mirror of
https://github.com/XTLS/Xray-core.git
synced 2025-08-24 02:26:48 +08:00
Compare commits
4 Commits
836b6487e4
...
f557bf7da4
Author | SHA1 | Date | |
---|---|---|---|
![]() |
f557bf7da4 | ||
![]() |
6fc0a40c2a | ||
![]() |
f3cdcad541 | ||
![]() |
5a8e9c25a4 |
@@ -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:
|
||||
|
@@ -13,6 +13,8 @@ const (
|
||||
Size = 8192
|
||||
)
|
||||
|
||||
var ErrBufferFull = errors.New("buffer is full")
|
||||
|
||||
var zero = [Size * 10]byte{0}
|
||||
|
||||
var pool = bytespool.GetPool(Size)
|
||||
@@ -244,6 +246,14 @@ func (b *Buffer) Cap() int32 {
|
||||
return int32(len(b.v))
|
||||
}
|
||||
|
||||
// Available returns the available capacity of the buffer content.
|
||||
func (b *Buffer) Available() int32 {
|
||||
if b == nil {
|
||||
return 0
|
||||
}
|
||||
return int32(len(b.v)) - b.end
|
||||
}
|
||||
|
||||
// IsEmpty returns true if the buffer is empty.
|
||||
func (b *Buffer) IsEmpty() bool {
|
||||
return b.Len() == 0
|
||||
@@ -258,13 +268,16 @@ func (b *Buffer) IsFull() bool {
|
||||
func (b *Buffer) Write(data []byte) (int, error) {
|
||||
nBytes := copy(b.v[b.end:], data)
|
||||
b.end += int32(nBytes)
|
||||
if nBytes < len(data) {
|
||||
return nBytes, ErrBufferFull
|
||||
}
|
||||
return nBytes, nil
|
||||
}
|
||||
|
||||
// WriteByte writes a single byte into the buffer.
|
||||
func (b *Buffer) WriteByte(v byte) error {
|
||||
if b.IsFull() {
|
||||
return errors.New("buffer full")
|
||||
return ErrBufferFull
|
||||
}
|
||||
b.v[b.end] = v
|
||||
b.end++
|
||||
|
@@ -144,7 +144,7 @@ func Compact(mb MultiBuffer) MultiBuffer {
|
||||
|
||||
for i := 1; i < len(mb); i++ {
|
||||
curr := mb[i]
|
||||
if last.Len()+curr.Len() > Size {
|
||||
if curr.Len() > last.Available() {
|
||||
mb2 = append(mb2, last)
|
||||
last = curr
|
||||
} else {
|
||||
|
@@ -175,6 +175,29 @@ func TestCompact(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCompactWithConsumed(t *testing.T) {
|
||||
// make a consumed buffer (a.Start != 0)
|
||||
a := New()
|
||||
for range 8192 {
|
||||
common.Must2(a.WriteString("a"))
|
||||
}
|
||||
a.Read(make([]byte, 2))
|
||||
|
||||
b := New()
|
||||
for range 2 {
|
||||
common.Must2(b.WriteString("b"))
|
||||
}
|
||||
|
||||
mb := MultiBuffer{a, b}
|
||||
cmb := Compact(mb)
|
||||
mbc := &MultiBufferContainer{mb}
|
||||
mbc.Read(make([]byte, 8190))
|
||||
|
||||
if w := cmb.String(); w != "bb" {
|
||||
t.Error("unexpected Compact result ", w)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSplitBytes(b *testing.B) {
|
||||
var mb MultiBuffer
|
||||
raw := make([]byte, Size)
|
||||
|
2
go.mod
2
go.mod
@@ -1,6 +1,6 @@
|
||||
module github.com/xtls/xray-core
|
||||
|
||||
go 1.24
|
||||
go 1.25
|
||||
|
||||
require (
|
||||
github.com/cloudflare/circl v1.6.1
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -6,9 +6,7 @@ import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"net"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"unsafe"
|
||||
|
||||
"github.com/xtls/xray-core/main/commands/base"
|
||||
. "github.com/xtls/xray-core/transport/internet/tls"
|
||||
@@ -139,14 +137,15 @@ func printCertificates(certs []*x509.Certificate) {
|
||||
}
|
||||
|
||||
func printTLSConnDetail(tlsConn *gotls.Conn) {
|
||||
connectionState := tlsConn.ConnectionState()
|
||||
var tlsVersion string
|
||||
if tlsConn.ConnectionState().Version == gotls.VersionTLS13 {
|
||||
if connectionState.Version == gotls.VersionTLS13 {
|
||||
tlsVersion = "TLS 1.3"
|
||||
} else if tlsConn.ConnectionState().Version == gotls.VersionTLS12 {
|
||||
} else if connectionState.Version == gotls.VersionTLS12 {
|
||||
tlsVersion = "TLS 1.2"
|
||||
}
|
||||
fmt.Println("TLS Version: ", tlsVersion)
|
||||
curveID := *(*gotls.CurveID)(unsafe.Pointer(reflect.ValueOf(tlsConn).Elem().FieldByName("curveID").UnsafeAddr()))
|
||||
curveID := connectionState.CurveID
|
||||
if curveID != 0 {
|
||||
PostQuantum := (curveID == gotls.X25519MLKEM768)
|
||||
fmt.Println("TLS Post-Quantum key exchange: ", PostQuantum, "("+curveID.String()+")")
|
||||
|
@@ -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()
|
||||
|
@@ -489,15 +489,16 @@ func (w uploadWriter) Write(b []byte) (int, error) {
|
||||
}
|
||||
*/
|
||||
|
||||
buffer := buf.New()
|
||||
n, err := buffer.Write(b)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
buffer := buf.MultiBufferContainer{}
|
||||
common.Must2(buffer.Write(b))
|
||||
|
||||
err = w.WriteMultiBuffer([]*buf.Buffer{buffer})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
var writed int
|
||||
for _, buff := range buffer.MultiBuffer {
|
||||
err := w.WriteMultiBuffer(buf.MultiBuffer{buff})
|
||||
if err != nil {
|
||||
return writed, err
|
||||
}
|
||||
writed += int(buff.Len())
|
||||
}
|
||||
return n, nil
|
||||
return writed, nil
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package splithttp_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
@@ -421,18 +422,12 @@ func Test_maxUpload(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
var uploadSize int
|
||||
uploadReceived := make([]byte, 10001)
|
||||
listen, err := ListenXH(context.Background(), net.LocalHostIP, listenPort, streamSettings, func(conn stat.Connection) {
|
||||
go func(c stat.Connection) {
|
||||
defer c.Close()
|
||||
var b [10240]byte
|
||||
c.SetReadDeadline(time.Now().Add(2 * time.Second))
|
||||
n, err := c.Read(b[:])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
uploadSize = n
|
||||
io.ReadFull(c, uploadReceived)
|
||||
|
||||
common.Must2(c.Write([]byte("Response")))
|
||||
}(conn)
|
||||
@@ -441,10 +436,12 @@ func Test_maxUpload(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
conn, err := Dial(ctx, net.TCPDestination(net.DomainAddress("localhost"), listenPort), streamSettings)
|
||||
common.Must(err)
|
||||
|
||||
// send a slightly too large upload
|
||||
var upload [10001]byte
|
||||
_, err = conn.Write(upload[:])
|
||||
upload := make([]byte, 10001)
|
||||
rand.Read(upload)
|
||||
_, err = conn.Write(upload)
|
||||
common.Must(err)
|
||||
|
||||
var b [10240]byte
|
||||
@@ -455,8 +452,8 @@ func Test_maxUpload(t *testing.T) {
|
||||
}
|
||||
common.Must(conn.Close())
|
||||
|
||||
if uploadSize > 10000 || uploadSize == 0 {
|
||||
t.Error("incorrect upload size: ", uploadSize)
|
||||
if !bytes.Equal(upload, uploadReceived) {
|
||||
t.Error("incorrect upload", upload, uploadReceived)
|
||||
}
|
||||
|
||||
common.Must(listen.Close())
|
||||
|
Reference in New Issue
Block a user