mirror of https://github.com/XTLS/Xray-core
Outbound: Add `targetStrategy`; Fix mux does not close `link.Reader`; Fix `origin` does not work on UDP; Add logs (#5006)
parent
6fc0a40c2a
commit
f557bf7da4
|
@ -42,12 +42,15 @@ func (r *IPRecord) getIPs() ([]net.IP, uint32, error) {
|
|||
if r == nil {
|
||||
return nil, 0, errRecordNotFound
|
||||
}
|
||||
untilExpire := time.Until(r.Expire)
|
||||
untilExpire := time.Until(r.Expire).Seconds()
|
||||
if untilExpire <= 0 {
|
||||
return nil, 0, errRecordNotFound
|
||||
}
|
||||
|
||||
ttl := uint32(untilExpire/time.Second) + uint32(1)
|
||||
ttl := uint32(untilExpire) + 1
|
||||
if ttl == 1 {
|
||||
r.Expire = time.Now().Add(time.Second) // To ensure that two consecutive requests get the same result
|
||||
}
|
||||
if r.RCode != dnsmessage.RCodeSuccess {
|
||||
return nil, ttl, dns_feature.RCodeError(r.RCode)
|
||||
}
|
||||
|
|
|
@ -449,11 +449,12 @@ type SenderConfig struct {
|
|||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// Send traffic through the given IP. Only IP is allowed.
|
||||
Via *net.IPOrDomain `protobuf:"bytes,1,opt,name=via,proto3" json:"via,omitempty"`
|
||||
StreamSettings *internet.StreamConfig `protobuf:"bytes,2,opt,name=stream_settings,json=streamSettings,proto3" json:"stream_settings,omitempty"`
|
||||
ProxySettings *internet.ProxyConfig `protobuf:"bytes,3,opt,name=proxy_settings,json=proxySettings,proto3" json:"proxy_settings,omitempty"`
|
||||
MultiplexSettings *MultiplexingConfig `protobuf:"bytes,4,opt,name=multiplex_settings,json=multiplexSettings,proto3" json:"multiplex_settings,omitempty"`
|
||||
ViaCidr string `protobuf:"bytes,5,opt,name=via_cidr,json=viaCidr,proto3" json:"via_cidr,omitempty"`
|
||||
Via *net.IPOrDomain `protobuf:"bytes,1,opt,name=via,proto3" json:"via,omitempty"`
|
||||
StreamSettings *internet.StreamConfig `protobuf:"bytes,2,opt,name=stream_settings,json=streamSettings,proto3" json:"stream_settings,omitempty"`
|
||||
ProxySettings *internet.ProxyConfig `protobuf:"bytes,3,opt,name=proxy_settings,json=proxySettings,proto3" json:"proxy_settings,omitempty"`
|
||||
MultiplexSettings *MultiplexingConfig `protobuf:"bytes,4,opt,name=multiplex_settings,json=multiplexSettings,proto3" json:"multiplex_settings,omitempty"`
|
||||
ViaCidr string `protobuf:"bytes,5,opt,name=via_cidr,json=viaCidr,proto3" json:"via_cidr,omitempty"`
|
||||
TargetStrategy internet.DomainStrategy `protobuf:"varint,6,opt,name=target_strategy,json=targetStrategy,proto3,enum=xray.transport.internet.DomainStrategy" json:"target_strategy,omitempty"`
|
||||
}
|
||||
|
||||
func (x *SenderConfig) Reset() {
|
||||
|
@ -521,6 +522,13 @@ func (x *SenderConfig) GetViaCidr() string {
|
|||
return ""
|
||||
}
|
||||
|
||||
func (x *SenderConfig) GetTargetStrategy() internet.DomainStrategy {
|
||||
if x != nil {
|
||||
return x.TargetStrategy
|
||||
}
|
||||
return internet.DomainStrategy(0)
|
||||
}
|
||||
|
||||
type MultiplexingConfig struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
|
@ -779,7 +787,7 @@ var file_app_proxyman_config_proto_rawDesc = []byte{
|
|||
0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65,
|
||||
0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x53,
|
||||
0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x10, 0x0a, 0x0e, 0x4f, 0x75, 0x74, 0x62, 0x6f,
|
||||
0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0xcb, 0x02, 0x0a, 0x0c, 0x53, 0x65,
|
||||
0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x9d, 0x03, 0x0a, 0x0c, 0x53, 0x65,
|
||||
0x6e, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2d, 0x0a, 0x03, 0x76, 0x69,
|
||||
0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63,
|
||||
0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f,
|
||||
|
@ -800,23 +808,28 @@ var file_app_proxyman_config_proto_rawDesc = []byte{
|
|||
0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x11, 0x6d, 0x75, 0x6c, 0x74, 0x69,
|
||||
0x70, 0x6c, 0x65, 0x78, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x19, 0x0a, 0x08,
|
||||
0x76, 0x69, 0x61, 0x5f, 0x63, 0x69, 0x64, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07,
|
||||
0x76, 0x69, 0x61, 0x43, 0x69, 0x64, 0x72, 0x22, 0xa4, 0x01, 0x0a, 0x12, 0x4d, 0x75, 0x6c, 0x74,
|
||||
0x69, 0x70, 0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18,
|
||||
0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52,
|
||||
0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x63,
|
||||
0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x63,
|
||||
0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x78, 0x75,
|
||||
0x64, 0x70, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x03, 0x20,
|
||||
0x01, 0x28, 0x05, 0x52, 0x0f, 0x78, 0x75, 0x64, 0x70, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72,
|
||||
0x65, 0x6e, 0x63, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x78, 0x75, 0x64, 0x70, 0x50, 0x72, 0x6f, 0x78,
|
||||
0x79, 0x55, 0x44, 0x50, 0x34, 0x34, 0x33, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x78,
|
||||
0x75, 0x64, 0x70, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x55, 0x44, 0x50, 0x34, 0x34, 0x33, 0x42, 0x55,
|
||||
0x0a, 0x15, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70,
|
||||
0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x50, 0x01, 0x5a, 0x26, 0x67, 0x69, 0x74, 0x68, 0x75,
|
||||
0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d,
|
||||
0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61,
|
||||
0x6e, 0xaa, 0x02, 0x11, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x50, 0x72, 0x6f,
|
||||
0x78, 0x79, 0x6d, 0x61, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x76, 0x69, 0x61, 0x43, 0x69, 0x64, 0x72, 0x12, 0x50, 0x0a, 0x0f, 0x74, 0x61, 0x72, 0x67, 0x65,
|
||||
0x74, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e,
|
||||
0x32, 0x27, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72,
|
||||
0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69,
|
||||
0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65,
|
||||
0x74, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x22, 0xa4, 0x01, 0x0a, 0x12, 0x4d, 0x75,
|
||||
0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
||||
0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f,
|
||||
0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52,
|
||||
0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x28, 0x0a, 0x0f,
|
||||
0x78, 0x75, 0x64, 0x70, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18,
|
||||
0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x78, 0x75, 0x64, 0x70, 0x43, 0x6f, 0x6e, 0x63, 0x75,
|
||||
0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x78, 0x75, 0x64, 0x70, 0x50, 0x72,
|
||||
0x6f, 0x78, 0x79, 0x55, 0x44, 0x50, 0x34, 0x34, 0x33, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x0f, 0x78, 0x75, 0x64, 0x70, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x55, 0x44, 0x50, 0x34, 0x34, 0x33,
|
||||
0x42, 0x55, 0x0a, 0x15, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70,
|
||||
0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x50, 0x01, 0x5a, 0x26, 0x67, 0x69, 0x74,
|
||||
0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61,
|
||||
0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79,
|
||||
0x6d, 0x61, 0x6e, 0xaa, 0x02, 0x11, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x50,
|
||||
0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
|
@ -850,6 +863,7 @@ var file_app_proxyman_config_proto_goTypes = []any{
|
|||
(*internet.StreamConfig)(nil), // 13: xray.transport.internet.StreamConfig
|
||||
(*serial.TypedMessage)(nil), // 14: xray.common.serial.TypedMessage
|
||||
(*internet.ProxyConfig)(nil), // 15: xray.transport.internet.ProxyConfig
|
||||
(internet.DomainStrategy)(0), // 16: xray.transport.internet.DomainStrategy
|
||||
}
|
||||
var file_app_proxyman_config_proto_depIdxs = []int32{
|
||||
0, // 0: xray.app.proxyman.AllocationStrategy.type:type_name -> xray.app.proxyman.AllocationStrategy.Type
|
||||
|
@ -866,11 +880,12 @@ var file_app_proxyman_config_proto_depIdxs = []int32{
|
|||
13, // 11: xray.app.proxyman.SenderConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig
|
||||
15, // 12: xray.app.proxyman.SenderConfig.proxy_settings:type_name -> xray.transport.internet.ProxyConfig
|
||||
8, // 13: xray.app.proxyman.SenderConfig.multiplex_settings:type_name -> xray.app.proxyman.MultiplexingConfig
|
||||
14, // [14:14] is the sub-list for method output_type
|
||||
14, // [14:14] is the sub-list for method input_type
|
||||
14, // [14:14] is the sub-list for extension type_name
|
||||
14, // [14:14] is the sub-list for extension extendee
|
||||
0, // [0:14] is the sub-list for field type_name
|
||||
16, // 14: xray.app.proxyman.SenderConfig.target_strategy:type_name -> xray.transport.internet.DomainStrategy
|
||||
15, // [15:15] is the sub-list for method output_type
|
||||
15, // [15:15] is the sub-list for method input_type
|
||||
15, // [15:15] is the sub-list for extension type_name
|
||||
15, // [15:15] is the sub-list for extension extendee
|
||||
0, // [0:15] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_app_proxyman_config_proto_init() }
|
||||
|
|
|
@ -84,6 +84,7 @@ message SenderConfig {
|
|||
xray.transport.internet.ProxyConfig proxy_settings = 3;
|
||||
MultiplexingConfig multiplex_settings = 4;
|
||||
string via_cidr = 5;
|
||||
xray.transport.internet.DomainStrategy target_strategy = 6;
|
||||
}
|
||||
|
||||
message MultiplexingConfig {
|
||||
|
|
|
@ -325,7 +325,7 @@ func (w *udpWorker) callback(b *buf.Buffer, source net.Destination, originalDest
|
|||
|
||||
ctx = session.ContextWithInbound(ctx, &session.Inbound{
|
||||
Source: source,
|
||||
Local: net.DestinationFromAddr(w.hub.Addr()),
|
||||
Local: net.DestinationFromAddr(w.hub.Addr()), // Due to some limitations, in UDP connections, localIP is always equal to listen interface IP
|
||||
Gateway: net.UDPDestination(w.address, w.port),
|
||||
Tag: w.tag,
|
||||
})
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"crypto/rand"
|
||||
goerrors "errors"
|
||||
"github.com/xtls/xray-core/common/dice"
|
||||
"io"
|
||||
"math/big"
|
||||
gonet "net"
|
||||
|
@ -177,6 +178,25 @@ func (h *Handler) Tag() string {
|
|||
func (h *Handler) Dispatch(ctx context.Context, link *transport.Link) {
|
||||
outbounds := session.OutboundsFromContext(ctx)
|
||||
ob := outbounds[len(outbounds)-1]
|
||||
content := session.ContentFromContext(ctx)
|
||||
if h.senderSettings != nil && h.senderSettings.TargetStrategy.HasStrategy() && ob.Target.Address.Family().IsDomain() && (content == nil || !content.SkipDNSResolve) {
|
||||
ips, err := internet.LookupForIP(ob.Target.Address.Domain(), h.senderSettings.TargetStrategy, nil)
|
||||
if err != nil {
|
||||
errors.LogInfoInner(ctx, err, "failed to resolve ip for target ", ob.Target.Address.Domain())
|
||||
if h.senderSettings.TargetStrategy.ForceIP() {
|
||||
err := errors.New("failed to resolve ip for target ", ob.Target.Address.Domain()).Base(err)
|
||||
session.SubmitOutboundErrorToOriginator(ctx, err)
|
||||
common.Interrupt(link.Writer)
|
||||
common.Interrupt(link.Reader)
|
||||
return
|
||||
}
|
||||
|
||||
} else {
|
||||
unchangedDomain := ob.Target.Address.Domain()
|
||||
ob.Target.Address = net.IPAddress(ips[dice.Roll(len(ips))])
|
||||
errors.LogInfo(ctx, "target: ", unchangedDomain, " resolved to: ", ob.Target.Address.String())
|
||||
}
|
||||
}
|
||||
if ob.Target.Network == net.Network_UDP && ob.OriginalTarget.Address != nil && ob.OriginalTarget.Address != ob.Target.Address {
|
||||
link.Reader = &buf.EndpointOverrideReader{Reader: link.Reader, Dest: ob.Target.Address, OriginalDest: ob.OriginalTarget.Address}
|
||||
link.Writer = &buf.EndpointOverrideWriter{Writer: link.Writer, Dest: ob.Target.Address, OriginalDest: ob.OriginalTarget.Address}
|
||||
|
@ -188,6 +208,7 @@ func (h *Handler) Dispatch(ctx context.Context, link *transport.Link) {
|
|||
session.SubmitOutboundErrorToOriginator(ctx, err)
|
||||
errors.LogInfo(ctx, err.Error())
|
||||
common.Interrupt(link.Writer)
|
||||
common.Interrupt(link.Reader)
|
||||
}
|
||||
}
|
||||
if ob.Target.Network == net.Network_UDP && ob.Target.Port == 443 {
|
||||
|
@ -287,26 +308,18 @@ func (h *Handler) Dial(ctx context.Context, dest net.Destination) (stat.Connecti
|
|||
ob.Gateway = ParseRandomIP(addr, h.senderSettings.ViaCidr)
|
||||
|
||||
case domain == "origin":
|
||||
|
||||
if inbound := session.InboundFromContext(ctx); inbound != nil {
|
||||
if inbound.Conn != nil {
|
||||
origin, _, err := net.SplitHostPort(inbound.Conn.LocalAddr().String())
|
||||
if err == nil {
|
||||
ob.Gateway = net.ParseAddress(origin)
|
||||
errors.LogDebug(ctx, "use receive package ip as snedthrough: ", origin)
|
||||
}
|
||||
if inbound.Local.IsValid() && inbound.Local.Address.Family().IsIP() {
|
||||
ob.Gateway = inbound.Local.Address
|
||||
errors.LogDebug(ctx, "use inbound local ip as sendthrough: ", inbound.Local.Address.String())
|
||||
}
|
||||
}
|
||||
case domain == "srcip":
|
||||
if inbound := session.InboundFromContext(ctx); inbound != nil {
|
||||
if inbound.Conn != nil {
|
||||
clientaddr, _, err := net.SplitHostPort(inbound.Conn.RemoteAddr().String())
|
||||
if err == nil {
|
||||
ob.Gateway = net.ParseAddress(clientaddr)
|
||||
errors.LogDebug(ctx, "use client src ip as snedthrough: ", clientaddr)
|
||||
}
|
||||
if inbound.Source.IsValid() && inbound.Source.Address.Family().IsIP() {
|
||||
ob.Gateway = inbound.Source.Address
|
||||
errors.LogDebug(ctx, "use inbound source ip as sendthrough: ", inbound.Source.Address.String())
|
||||
}
|
||||
|
||||
}
|
||||
//case addr.Family().IsDomain():
|
||||
default:
|
||||
|
|
|
@ -260,13 +260,14 @@ func (c *InboundDetourConfig) Build() (*core.InboundHandlerConfig, error) {
|
|||
}
|
||||
|
||||
type OutboundDetourConfig struct {
|
||||
Protocol string `json:"protocol"`
|
||||
SendThrough *string `json:"sendThrough"`
|
||||
Tag string `json:"tag"`
|
||||
Settings *json.RawMessage `json:"settings"`
|
||||
StreamSetting *StreamConfig `json:"streamSettings"`
|
||||
ProxySettings *ProxyConfig `json:"proxySettings"`
|
||||
MuxSettings *MuxConfig `json:"mux"`
|
||||
Protocol string `json:"protocol"`
|
||||
SendThrough *string `json:"sendThrough"`
|
||||
Tag string `json:"tag"`
|
||||
Settings *json.RawMessage `json:"settings"`
|
||||
StreamSetting *StreamConfig `json:"streamSettings"`
|
||||
ProxySettings *ProxyConfig `json:"proxySettings"`
|
||||
MuxSettings *MuxConfig `json:"mux"`
|
||||
TargetStrategy string `json:"targetStrategy"`
|
||||
}
|
||||
|
||||
func (c *OutboundDetourConfig) checkChainProxyConfig() error {
|
||||
|
@ -282,6 +283,32 @@ func (c *OutboundDetourConfig) checkChainProxyConfig() error {
|
|||
// Build implements Buildable.
|
||||
func (c *OutboundDetourConfig) Build() (*core.OutboundHandlerConfig, error) {
|
||||
senderSettings := &proxyman.SenderConfig{}
|
||||
switch strings.ToLower(c.TargetStrategy) {
|
||||
case "asis", "":
|
||||
senderSettings.TargetStrategy = internet.DomainStrategy_AS_IS
|
||||
case "useip":
|
||||
senderSettings.TargetStrategy = internet.DomainStrategy_USE_IP
|
||||
case "useipv4":
|
||||
senderSettings.TargetStrategy = internet.DomainStrategy_USE_IP4
|
||||
case "useipv6":
|
||||
senderSettings.TargetStrategy = internet.DomainStrategy_USE_IP6
|
||||
case "useipv4v6":
|
||||
senderSettings.TargetStrategy = internet.DomainStrategy_USE_IP46
|
||||
case "useipv6v4":
|
||||
senderSettings.TargetStrategy = internet.DomainStrategy_USE_IP64
|
||||
case "forceip":
|
||||
senderSettings.TargetStrategy = internet.DomainStrategy_FORCE_IP
|
||||
case "forceipv4":
|
||||
senderSettings.TargetStrategy = internet.DomainStrategy_FORCE_IP4
|
||||
case "forceipv6":
|
||||
senderSettings.TargetStrategy = internet.DomainStrategy_FORCE_IP6
|
||||
case "forceipv4v6":
|
||||
senderSettings.TargetStrategy = internet.DomainStrategy_FORCE_IP46
|
||||
case "forceipv6v4":
|
||||
senderSettings.TargetStrategy = internet.DomainStrategy_FORCE_IP64
|
||||
default:
|
||||
return nil, errors.New("unsupported target domain strategy: ", c.TargetStrategy)
|
||||
}
|
||||
if err := c.checkChainProxyConfig(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -100,30 +100,30 @@ func (m SocketConfig_TProxyMode) IsEnabled() bool {
|
|||
return m != SocketConfig_Off
|
||||
}
|
||||
|
||||
func (s DomainStrategy) hasStrategy() bool {
|
||||
func (s DomainStrategy) HasStrategy() bool {
|
||||
return strategy[s][0] != 0
|
||||
}
|
||||
|
||||
func (s DomainStrategy) forceIP() bool {
|
||||
func (s DomainStrategy) ForceIP() bool {
|
||||
return strategy[s][0] == 2
|
||||
}
|
||||
|
||||
func (s DomainStrategy) preferIP4() bool {
|
||||
func (s DomainStrategy) PreferIP4() bool {
|
||||
return strategy[s][1] == 4 || strategy[s][1] == 0
|
||||
}
|
||||
|
||||
func (s DomainStrategy) preferIP6() bool {
|
||||
func (s DomainStrategy) PreferIP6() bool {
|
||||
return strategy[s][1] == 6 || strategy[s][1] == 0
|
||||
}
|
||||
|
||||
func (s DomainStrategy) hasFallback() bool {
|
||||
func (s DomainStrategy) HasFallback() bool {
|
||||
return strategy[s][2] != 0
|
||||
}
|
||||
|
||||
func (s DomainStrategy) fallbackIP4() bool {
|
||||
func (s DomainStrategy) FallbackIP4() bool {
|
||||
return strategy[s][2] == 4
|
||||
}
|
||||
|
||||
func (s DomainStrategy) fallbackIP6() bool {
|
||||
func (s DomainStrategy) FallbackIP6() bool {
|
||||
return strategy[s][2] == 6
|
||||
}
|
||||
|
|
|
@ -85,20 +85,20 @@ var (
|
|||
obm outbound.Manager
|
||||
)
|
||||
|
||||
func lookupIP(domain string, strategy DomainStrategy, localAddr net.Address) ([]net.IP, error) {
|
||||
func LookupForIP(domain string, strategy DomainStrategy, localAddr net.Address) ([]net.IP, error) {
|
||||
if dnsClient == nil {
|
||||
return nil, errors.New("DNS client not initialized").AtError()
|
||||
}
|
||||
|
||||
ips, _, err := dnsClient.LookupIP(domain, dns.IPOption{
|
||||
IPv4Enable: (localAddr == nil || localAddr.Family().IsIPv4()) && strategy.preferIP4(),
|
||||
IPv6Enable: (localAddr == nil || localAddr.Family().IsIPv6()) && strategy.preferIP6(),
|
||||
IPv4Enable: (localAddr == nil || localAddr.Family().IsIPv4()) && strategy.PreferIP4(),
|
||||
IPv6Enable: (localAddr == nil || localAddr.Family().IsIPv6()) && strategy.PreferIP6(),
|
||||
})
|
||||
{ // Resolve fallback
|
||||
if (len(ips) == 0 || err != nil) && strategy.hasFallback() && localAddr == nil {
|
||||
if (len(ips) == 0 || err != nil) && strategy.HasFallback() && localAddr == nil {
|
||||
ips, _, err = dnsClient.LookupIP(domain, dns.IPOption{
|
||||
IPv4Enable: strategy.fallbackIP4(),
|
||||
IPv6Enable: strategy.fallbackIP6(),
|
||||
IPv4Enable: strategy.FallbackIP4(),
|
||||
IPv6Enable: strategy.FallbackIP6(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -113,7 +113,7 @@ func canLookupIP(dst net.Destination, sockopt *SocketConfig) bool {
|
|||
if dst.Address.Family().IsIP() {
|
||||
return false
|
||||
}
|
||||
return sockopt.DomainStrategy.hasStrategy()
|
||||
return sockopt.DomainStrategy.HasStrategy()
|
||||
}
|
||||
|
||||
func redirect(ctx context.Context, dst net.Destination, obt string, h outbound.Handler) net.Conn {
|
||||
|
@ -249,17 +249,17 @@ func DialSystem(ctx context.Context, dest net.Destination, sockopt *SocketConfig
|
|||
}
|
||||
|
||||
if canLookupIP(dest, sockopt) {
|
||||
ips, err := lookupIP(dest.Address.String(), sockopt.DomainStrategy, src)
|
||||
ips, err := LookupForIP(dest.Address.String(), sockopt.DomainStrategy, src)
|
||||
if err != nil {
|
||||
errors.LogErrorInner(ctx, err, "failed to resolve ip")
|
||||
if sockopt.DomainStrategy.forceIP() {
|
||||
if sockopt.DomainStrategy.ForceIP() {
|
||||
return nil, err
|
||||
}
|
||||
} else if sockopt.HappyEyeballs == nil || sockopt.HappyEyeballs.TryDelayMs == 0 || sockopt.HappyEyeballs.MaxConcurrentTry == 0 || len(ips) < 2 || len(sockopt.DialerProxy) > 0 || dest.Network != net.Network_TCP {
|
||||
dest.Address = net.IPAddress(ips[dice.Roll(len(ips))])
|
||||
errors.LogInfo(ctx, "replace destination with "+dest.String())
|
||||
} else {
|
||||
return TcpRaceDial(ctx, src, ips, dest.Port, sockopt)
|
||||
return TcpRaceDial(ctx, src, ips, dest.Port, sockopt, dest.Address.String())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ package internet
|
|||
|
||||
import (
|
||||
"context"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"time"
|
||||
)
|
||||
|
@ -12,7 +13,7 @@ type result struct {
|
|||
index int
|
||||
}
|
||||
|
||||
func TcpRaceDial(ctx context.Context, src net.Address, ips []net.IP, port net.Port, sockopt *SocketConfig) (net.Conn, error) {
|
||||
func TcpRaceDial(ctx context.Context, src net.Address, ips []net.IP, port net.Port, sockopt *SocketConfig, domain string) (net.Conn, error) {
|
||||
if len(ips) < 2 {
|
||||
panic("at least 2 ips is required to race dial")
|
||||
}
|
||||
|
@ -30,6 +31,7 @@ func TcpRaceDial(ctx context.Context, src net.Address, ips []net.IP, port net.Po
|
|||
activeNum := uint32(0)
|
||||
timer := time.NewTimer(0)
|
||||
var winConn net.Conn
|
||||
errors.LogDebug(ctx, "happy eyeballs racing dial for ", domain, " with IPs ", ips)
|
||||
for {
|
||||
select {
|
||||
case r := <-resultCh:
|
||||
|
@ -54,6 +56,7 @@ func TcpRaceDial(ctx context.Context, src net.Address, ips []net.IP, port net.Po
|
|||
timer.Stop()
|
||||
if winConn == nil {
|
||||
winConn = r.conn
|
||||
errors.LogDebug(ctx, "happy eyeballs established connection for ", domain, " with IP ", ips[r.index])
|
||||
} else {
|
||||
r.conn.Close()
|
||||
}
|
||||
|
@ -69,6 +72,7 @@ func TcpRaceDial(ctx context.Context, src net.Address, ips []net.IP, port net.Po
|
|||
continue
|
||||
}
|
||||
if activeNum == 0 {
|
||||
errors.LogDebugInner(ctx, r.err, "happy eyeballs no connection established for ", domain)
|
||||
return nil, r.err
|
||||
}
|
||||
timer.Stop()
|
||||
|
|
Loading…
Reference in New Issue