mirror of
https://github.com/XTLS/Xray-core.git
synced 2026-09-26 16:58:47 +03:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c84753dae6 | ||
|
|
d17906c2f1 | ||
|
|
52a412d9e2 | ||
|
|
18a1b5042a | ||
|
|
c26d2eda24 | ||
|
|
a1bf968be9 | ||
|
|
c037ccd98d | ||
|
|
37ceb8b4b6 | ||
|
|
fd2ca74822 | ||
|
|
47cfe9994a | ||
|
|
3e2f040cd8 | ||
|
|
c7245c0336 | ||
|
|
eef6e63bc1 | ||
|
|
6ce8dc53e7 | ||
|
|
01a034be53 | ||
|
|
de2caf3cef | ||
|
|
cecc88f43c | ||
|
|
cd4ce973e9 | ||
|
|
fc7b980636 | ||
|
|
8ee131cbbb | ||
|
|
2776ea6d74 |
@@ -67,9 +67,7 @@ jobs:
|
|||||||
check-latest: true
|
check-latest: true
|
||||||
cache: false
|
cache: false
|
||||||
- name: Check Format
|
- name: Check Format
|
||||||
run: |
|
run: go run ./infra/vformat/main.go -mode check -pwd ./
|
||||||
go install -v mvdan.cc/gofumpt@latest
|
|
||||||
go run ./infra/vformat/main.go -mode check -pwd ./
|
|
||||||
|
|
||||||
test:
|
test:
|
||||||
needs: check-assets
|
needs: check-assets
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ func newFakeDNSSniffer(ctx context.Context) (protocolSnifferWithMetadata, error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if fakeDNSEngine == nil {
|
if fakeDNSEngine == nil {
|
||||||
errNotInit := errors.New("FakeDNSEngine is not initialized, but such a sniffer is used").AtError()
|
errNotInit := errors.New("FakeDNSEngine is not initialized, but such a sniffer is used")
|
||||||
return protocolSnifferWithMetadata{}, errNotInit
|
return protocolSnifferWithMetadata{}, errNotInit
|
||||||
}
|
}
|
||||||
return protocolSnifferWithMetadata{protocolSniffer: func(ctx context.Context, bytes []byte) (SniffResult, error) {
|
return protocolSnifferWithMetadata{protocolSniffer: func(ctx context.Context, bytes []byte) (SniffResult, error) {
|
||||||
|
|||||||
+1
-1
@@ -28,7 +28,7 @@ func toNetIP(addrs []net.Address) ([]net.IP, error) {
|
|||||||
if addr.Family().IsIP() {
|
if addr.Family().IsIP() {
|
||||||
ips = append(ips, addr.IP())
|
ips = append(ips, addr.IP())
|
||||||
} else {
|
} else {
|
||||||
return nil, errors.New("Failed to convert address", addr, "to Net IP.").AtWarning()
|
return nil, errors.New("Failed to convert address", addr, "to Net IP.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ips, nil
|
return ips, nil
|
||||||
|
|||||||
@@ -188,10 +188,10 @@ func parseResponse(payload []byte) (*IPRecord, error) {
|
|||||||
var parser dnsmessage.Parser
|
var parser dnsmessage.Parser
|
||||||
h, err := parser.Start(payload)
|
h, err := parser.Start(payload)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("failed to parse DNS response").Base(err).AtWarning()
|
return nil, errors.New("failed to parse DNS response").Base(err)
|
||||||
}
|
}
|
||||||
if err := parser.SkipAllQuestions(); err != nil {
|
if err := parser.SkipAllQuestions(); err != nil {
|
||||||
return nil, errors.New("failed to skip questions in DNS response").Base(err).AtWarning()
|
return nil, errors.New("failed to skip questions in DNS response").Base(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ func NewFakeDNSHolder() (*Holder, error) {
|
|||||||
var err error
|
var err error
|
||||||
|
|
||||||
if fkdns, err = NewFakeDNSHolderConfigOnly(nil); err != nil {
|
if fkdns, err = NewFakeDNSHolderConfigOnly(nil); err != nil {
|
||||||
return nil, errors.New("Unable to create Fake Dns Engine").Base(err).AtError()
|
return nil, errors.New("Unable to create Fake Dns Engine").Base(err)
|
||||||
}
|
}
|
||||||
err = fkdns.initialize(dns.FakeIPv4Pool, 65535)
|
err = fkdns.initialize(dns.FakeIPv4Pool, 65535)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -80,13 +80,13 @@ func (fkdns *Holder) initialize(ipPoolCidr string, lruSize int) error {
|
|||||||
var err error
|
var err error
|
||||||
|
|
||||||
if _, ipRange, err = net.ParseCIDR(ipPoolCidr); err != nil {
|
if _, ipRange, err = net.ParseCIDR(ipPoolCidr); err != nil {
|
||||||
return errors.New("Unable to parse CIDR for Fake DNS IP assignment").Base(err).AtError()
|
return errors.New("Unable to parse CIDR for Fake DNS IP assignment").Base(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ones, bits := ipRange.Mask.Size()
|
ones, bits := ipRange.Mask.Size()
|
||||||
rooms := bits - ones
|
rooms := bits - ones
|
||||||
if math.Log2(float64(lruSize)) >= float64(rooms) {
|
if math.Log2(float64(lruSize)) >= float64(rooms) {
|
||||||
return errors.New("LRU size is bigger than subnet size").AtError()
|
return errors.New("LRU size is bigger than subnet size")
|
||||||
}
|
}
|
||||||
fkdns.domainToIP = cache.NewLru(lruSize)
|
fkdns.domainToIP = cache.NewLru(lruSize)
|
||||||
fkdns.ipRange = ipRange
|
fkdns.ipRange = ipRange
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ func NewServer(ctx context.Context, dest net.Destination, dispatcher routing.Dis
|
|||||||
if dest.Network == net.Network_UDP { // UDP classic DNS mode
|
if dest.Network == net.Network_UDP { // UDP classic DNS mode
|
||||||
return NewClassicNameServer(dest, dispatcher, disableCache, serveStale, serveExpiredTTL, clientIP), nil
|
return NewClassicNameServer(dest, dispatcher, disableCache, serveStale, serveExpiredTTL, clientIP), nil
|
||||||
}
|
}
|
||||||
return nil, errors.New("No available name server could be created from ", dest).AtWarning()
|
return nil, errors.New("No available name server could be created from ", dest)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewClient creates a DNS client managing a name server with client IP, domain rules and expected IPs.
|
// NewClient creates a DNS client managing a name server with client IP, domain rules and expected IPs.
|
||||||
@@ -102,7 +102,7 @@ func NewClient(
|
|||||||
// Create a new server for each client for now
|
// Create a new server for each client for now
|
||||||
server, err := NewServer(ctx, ns.Address.AsDestination(), dispatcher, disableCache, serveStale, serveExpiredTTL, clientIP)
|
server, err := NewServer(ctx, ns.Address.AsDestination(), dispatcher, disableCache, serveStale, serveExpiredTTL, clientIP)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to create nameserver").Base(err).AtWarning()
|
return errors.New("failed to create nameserver").Base(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, isLocalDNS := server.(*LocalNameServer)
|
_, isLocalDNS := server.(*LocalNameServer)
|
||||||
@@ -113,7 +113,7 @@ func NewClient(
|
|||||||
if len(ns.ExpectedIp) > 0 {
|
if len(ns.ExpectedIp) > 0 {
|
||||||
expectedMatcher, err = geodata.IPReg.BuildIPMatcher(ns.ExpectedIp)
|
expectedMatcher, err = geodata.IPReg.BuildIPMatcher(ns.ExpectedIp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to create expected ip matcher").Base(err).AtWarning()
|
return errors.New("failed to create expected ip matcher").Base(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,7 +122,7 @@ func NewClient(
|
|||||||
if len(ns.UnexpectedIp) > 0 {
|
if len(ns.UnexpectedIp) > 0 {
|
||||||
unexpectedMatcher, err = geodata.IPReg.BuildIPMatcher(ns.UnexpectedIp)
|
unexpectedMatcher, err = geodata.IPReg.BuildIPMatcher(ns.UnexpectedIp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to create unexpected ip matcher").Base(err).AtWarning()
|
return errors.New("failed to create unexpected ip matcher").Base(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ func (s *FakeDNSServer) IsDisableCache() bool {
|
|||||||
|
|
||||||
func (f *FakeDNSServer) QueryIP(ctx context.Context, domain string, opt dns.IPOption) ([]net.IP, uint32, error) {
|
func (f *FakeDNSServer) QueryIP(ctx context.Context, domain string, opt dns.IPOption) ([]net.IP, uint32, error) {
|
||||||
if f.fakeDNSEngine == nil {
|
if f.fakeDNSEngine == nil {
|
||||||
return nil, 0, errors.New("Unable to locate a fake DNS Engine").AtError()
|
return nil, 0, errors.New("Unable to locate a fake DNS Engine")
|
||||||
}
|
}
|
||||||
|
|
||||||
var ips []net.Address
|
var ips []net.Address
|
||||||
@@ -39,7 +39,7 @@ func (f *FakeDNSServer) QueryIP(ctx context.Context, domain string, opt dns.IPOp
|
|||||||
|
|
||||||
netIP, err := toNetIP(ips)
|
netIP, err := toNetIP(ips)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, errors.New("Unable to convert IP to net ip").Base(err).AtError()
|
return nil, 0, errors.New("Unable to convert IP to net ip").Base(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
errors.LogInfo(ctx, f.Name(), " got answer: ", domain, " -> ", ips)
|
errors.LogInfo(ctx, f.Name(), " got answer: ", domain, " -> ", ips)
|
||||||
|
|||||||
+6
-2
@@ -89,10 +89,10 @@ func (g *Instance) startInternal() error {
|
|||||||
g.active = true
|
g.active = true
|
||||||
|
|
||||||
if err := g.initAccessLogger(); err != nil {
|
if err := g.initAccessLogger(); err != nil {
|
||||||
return errors.New("failed to initialize access logger").Base(err).AtWarning()
|
return errors.New("failed to initialize access logger").Base(err)
|
||||||
}
|
}
|
||||||
if err := g.initErrorLogger(); err != nil {
|
if err := g.initErrorLogger(); err != nil {
|
||||||
return errors.New("failed to initialize error logger").Base(err).AtWarning()
|
return errors.New("failed to initialize error logger").Base(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -141,6 +141,10 @@ func (g *Instance) Handle(msg log.Message) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (g *Instance) Severity() log.Severity {
|
||||||
|
return g.config.ErrorLogLevel
|
||||||
|
}
|
||||||
|
|
||||||
// Close implements common.Closable.Close().
|
// Close implements common.Closable.Close().
|
||||||
func (g *Instance) Close() error {
|
func (g *Instance) Close() error {
|
||||||
errors.LogDebug(context.Background(), "Logger closing")
|
errors.LogDebug(context.Background(), "Logger closing")
|
||||||
|
|||||||
+11
-22
@@ -330,7 +330,6 @@ type SenderConfig struct {
|
|||||||
// Send traffic through the given IP. Only IP is allowed.
|
// Send traffic through the given IP. Only IP is allowed.
|
||||||
Via *net.IPOrDomain `protobuf:"bytes,1,opt,name=via,proto3" json:"via,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"`
|
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"`
|
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"`
|
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"`
|
TargetStrategy internet.DomainStrategy `protobuf:"varint,6,opt,name=target_strategy,json=targetStrategy,proto3,enum=xray.transport.internet.DomainStrategy" json:"target_strategy,omitempty"`
|
||||||
@@ -382,13 +381,6 @@ func (x *SenderConfig) GetStreamSettings() *internet.StreamConfig {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *SenderConfig) GetProxySettings() *internet.ProxyConfig {
|
|
||||||
if x != nil {
|
|
||||||
return x.ProxySettings
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *SenderConfig) GetMultiplexSettings() *MultiplexingConfig {
|
func (x *SenderConfig) GetMultiplexSettings() *MultiplexingConfig {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.MultiplexSettings
|
return x.MultiplexSettings
|
||||||
@@ -506,14 +498,13 @@ const file_app_proxyman_config_proto_rawDesc = "" +
|
|||||||
"\x03tag\x18\x01 \x01(\tR\x03tag\x12M\n" +
|
"\x03tag\x18\x01 \x01(\tR\x03tag\x12M\n" +
|
||||||
"\x11receiver_settings\x18\x02 \x01(\v2 .xray.common.serial.TypedMessageR\x10receiverSettings\x12G\n" +
|
"\x11receiver_settings\x18\x02 \x01(\v2 .xray.common.serial.TypedMessageR\x10receiverSettings\x12G\n" +
|
||||||
"\x0eproxy_settings\x18\x03 \x01(\v2 .xray.common.serial.TypedMessageR\rproxySettings\"\x10\n" +
|
"\x0eproxy_settings\x18\x03 \x01(\v2 .xray.common.serial.TypedMessageR\rproxySettings\"\x10\n" +
|
||||||
"\x0eOutboundConfig\"\x9d\x03\n" +
|
"\x0eOutboundConfig\"\xd6\x02\n" +
|
||||||
"\fSenderConfig\x12-\n" +
|
"\fSenderConfig\x12-\n" +
|
||||||
"\x03via\x18\x01 \x01(\v2\x1b.xray.common.net.IPOrDomainR\x03via\x12N\n" +
|
"\x03via\x18\x01 \x01(\v2\x1b.xray.common.net.IPOrDomainR\x03via\x12N\n" +
|
||||||
"\x0fstream_settings\x18\x02 \x01(\v2%.xray.transport.internet.StreamConfigR\x0estreamSettings\x12K\n" +
|
"\x0fstream_settings\x18\x02 \x01(\v2%.xray.transport.internet.StreamConfigR\x0estreamSettings\x12T\n" +
|
||||||
"\x0eproxy_settings\x18\x03 \x01(\v2$.xray.transport.internet.ProxyConfigR\rproxySettings\x12T\n" +
|
|
||||||
"\x12multiplex_settings\x18\x04 \x01(\v2%.xray.app.proxyman.MultiplexingConfigR\x11multiplexSettings\x12\x19\n" +
|
"\x12multiplex_settings\x18\x04 \x01(\v2%.xray.app.proxyman.MultiplexingConfigR\x11multiplexSettings\x12\x19\n" +
|
||||||
"\bvia_cidr\x18\x05 \x01(\tR\aviaCidr\x12P\n" +
|
"\bvia_cidr\x18\x05 \x01(\tR\aviaCidr\x12P\n" +
|
||||||
"\x0ftarget_strategy\x18\x06 \x01(\x0e2'.xray.transport.internet.DomainStrategyR\x0etargetStrategy\"\xa4\x01\n" +
|
"\x0ftarget_strategy\x18\x06 \x01(\x0e2'.xray.transport.internet.DomainStrategyR\x0etargetStrategyJ\x04\b\x03\x10\x04\"\xa4\x01\n" +
|
||||||
"\x12MultiplexingConfig\x12\x18\n" +
|
"\x12MultiplexingConfig\x12\x18\n" +
|
||||||
"\aenabled\x18\x01 \x01(\bR\aenabled\x12 \n" +
|
"\aenabled\x18\x01 \x01(\bR\aenabled\x12 \n" +
|
||||||
"\vconcurrency\x18\x02 \x01(\x05R\vconcurrency\x12(\n" +
|
"\vconcurrency\x18\x02 \x01(\x05R\vconcurrency\x12(\n" +
|
||||||
@@ -548,8 +539,7 @@ var file_app_proxyman_config_proto_goTypes = []any{
|
|||||||
(*net.IPOrDomain)(nil), // 10: xray.common.net.IPOrDomain
|
(*net.IPOrDomain)(nil), // 10: xray.common.net.IPOrDomain
|
||||||
(*internet.StreamConfig)(nil), // 11: xray.transport.internet.StreamConfig
|
(*internet.StreamConfig)(nil), // 11: xray.transport.internet.StreamConfig
|
||||||
(*serial.TypedMessage)(nil), // 12: xray.common.serial.TypedMessage
|
(*serial.TypedMessage)(nil), // 12: xray.common.serial.TypedMessage
|
||||||
(*internet.ProxyConfig)(nil), // 13: xray.transport.internet.ProxyConfig
|
(internet.DomainStrategy)(0), // 13: xray.transport.internet.DomainStrategy
|
||||||
(internet.DomainStrategy)(0), // 14: xray.transport.internet.DomainStrategy
|
|
||||||
}
|
}
|
||||||
var file_app_proxyman_config_proto_depIdxs = []int32{
|
var file_app_proxyman_config_proto_depIdxs = []int32{
|
||||||
7, // 0: xray.app.proxyman.SniffingConfig.domains_excluded:type_name -> xray.common.geodata.DomainRule
|
7, // 0: xray.app.proxyman.SniffingConfig.domains_excluded:type_name -> xray.common.geodata.DomainRule
|
||||||
@@ -562,14 +552,13 @@ var file_app_proxyman_config_proto_depIdxs = []int32{
|
|||||||
12, // 7: xray.app.proxyman.InboundHandlerConfig.proxy_settings:type_name -> xray.common.serial.TypedMessage
|
12, // 7: xray.app.proxyman.InboundHandlerConfig.proxy_settings:type_name -> xray.common.serial.TypedMessage
|
||||||
10, // 8: xray.app.proxyman.SenderConfig.via:type_name -> xray.common.net.IPOrDomain
|
10, // 8: xray.app.proxyman.SenderConfig.via:type_name -> xray.common.net.IPOrDomain
|
||||||
11, // 9: xray.app.proxyman.SenderConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig
|
11, // 9: xray.app.proxyman.SenderConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig
|
||||||
13, // 10: xray.app.proxyman.SenderConfig.proxy_settings:type_name -> xray.transport.internet.ProxyConfig
|
6, // 10: xray.app.proxyman.SenderConfig.multiplex_settings:type_name -> xray.app.proxyman.MultiplexingConfig
|
||||||
6, // 11: xray.app.proxyman.SenderConfig.multiplex_settings:type_name -> xray.app.proxyman.MultiplexingConfig
|
13, // 11: xray.app.proxyman.SenderConfig.target_strategy:type_name -> xray.transport.internet.DomainStrategy
|
||||||
14, // 12: xray.app.proxyman.SenderConfig.target_strategy:type_name -> xray.transport.internet.DomainStrategy
|
12, // [12:12] is the sub-list for method output_type
|
||||||
13, // [13:13] is the sub-list for method output_type
|
12, // [12:12] is the sub-list for method input_type
|
||||||
13, // [13:13] is the sub-list for method input_type
|
12, // [12:12] is the sub-list for extension type_name
|
||||||
13, // [13:13] is the sub-list for extension type_name
|
12, // [12:12] is the sub-list for extension extendee
|
||||||
13, // [13:13] is the sub-list for extension extendee
|
0, // [0:12] is the sub-list for field type_name
|
||||||
0, // [0:13] is the sub-list for field type_name
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { file_app_proxyman_config_proto_init() }
|
func init() { file_app_proxyman_config_proto_init() }
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ message SenderConfig {
|
|||||||
// Send traffic through the given IP. Only IP is allowed.
|
// Send traffic through the given IP. Only IP is allowed.
|
||||||
xray.common.net.IPOrDomain via = 1;
|
xray.common.net.IPOrDomain via = 1;
|
||||||
xray.transport.internet.StreamConfig stream_settings = 2;
|
xray.transport.internet.StreamConfig stream_settings = 2;
|
||||||
xray.transport.internet.ProxyConfig proxy_settings = 3;
|
reserved 3;
|
||||||
MultiplexingConfig multiplex_settings = 4;
|
MultiplexingConfig multiplex_settings = 4;
|
||||||
string via_cidr = 5;
|
string via_cidr = 5;
|
||||||
xray.transport.internet.DomainStrategy target_strategy = 6;
|
xray.transport.internet.DomainStrategy target_strategy = 6;
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *
|
|||||||
}
|
}
|
||||||
mss, err := internet.ToMemoryStreamConfig(receiverConfig.StreamSettings)
|
mss, err := internet.ToMemoryStreamConfig(receiverConfig.StreamSettings)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("failed to parse stream config").Base(err).AtWarning()
|
return nil, errors.New("failed to parse stream config").Base(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
newCtx := session.ContextWithInbound(ctx, &session.Inbound{Tag: tag, Source: src})
|
newCtx := session.ContextWithInbound(ctx, &session.Inbound{Tag: tag, Source: src})
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ func NewHandler(ctx context.Context, config *core.InboundHandlerConfig) (inbound
|
|||||||
|
|
||||||
receiverSettings, ok := rawReceiverSettings.(*proxyman.ReceiverConfig)
|
receiverSettings, ok := rawReceiverSettings.(*proxyman.ReceiverConfig)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("not a ReceiverConfig").AtError()
|
return nil, errors.New("not a ReceiverConfig")
|
||||||
}
|
}
|
||||||
|
|
||||||
streamSettings := receiverSettings.StreamSettings
|
streamSettings := receiverSettings.StreamSettings
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ func (w *tcpWorker) Start() error {
|
|||||||
go w.callback(conn)
|
go w.callback(conn)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to listen TCP on ", w.port).AtWarning().Base(err)
|
return errors.New("failed to listen TCP on ", w.port).Base(err)
|
||||||
}
|
}
|
||||||
w.hub = hub
|
w.hub = hub
|
||||||
return nil
|
return nil
|
||||||
@@ -528,7 +528,7 @@ func (w *dsWorker) Start() error {
|
|||||||
go w.callback(conn)
|
go w.callback(conn)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to listen Unix Domain Socket on ", w.address).AtWarning().Base(err)
|
return errors.New("failed to listen Unix Domain Socket on ", w.address).Base(err)
|
||||||
}
|
}
|
||||||
w.hub = hub
|
w.hub = hub
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import (
|
|||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
"github.com/xtls/xray-core/common/mux"
|
"github.com/xtls/xray-core/common/mux"
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/net/cnc"
|
|
||||||
"github.com/xtls/xray-core/common/serial"
|
"github.com/xtls/xray-core/common/serial"
|
||||||
"github.com/xtls/xray-core/common/session"
|
"github.com/xtls/xray-core/common/session"
|
||||||
"github.com/xtls/xray-core/core"
|
"github.com/xtls/xray-core/core"
|
||||||
@@ -26,8 +25,6 @@ import (
|
|||||||
"github.com/xtls/xray-core/transport"
|
"github.com/xtls/xray-core/transport"
|
||||||
"github.com/xtls/xray-core/transport/internet"
|
"github.com/xtls/xray-core/transport/internet"
|
||||||
"github.com/xtls/xray-core/transport/internet/stat"
|
"github.com/xtls/xray-core/transport/internet/stat"
|
||||||
"github.com/xtls/xray-core/transport/internet/tls"
|
|
||||||
"github.com/xtls/xray-core/transport/pipe"
|
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -63,7 +60,6 @@ type Handler struct {
|
|||||||
streamSettings *internet.MemoryStreamConfig
|
streamSettings *internet.MemoryStreamConfig
|
||||||
proxyConfig proto.Message
|
proxyConfig proto.Message
|
||||||
proxy proxy.Outbound
|
proxy proxy.Outbound
|
||||||
outboundManager outbound.Manager
|
|
||||||
mux *mux.ClientManager
|
mux *mux.ClientManager
|
||||||
xudp *mux.ClientManager
|
xudp *mux.ClientManager
|
||||||
udp443 string
|
udp443 string
|
||||||
@@ -77,7 +73,6 @@ func NewHandler(ctx context.Context, config *core.OutboundHandlerConfig) (outbou
|
|||||||
uplinkCounter, downlinkCounter := getStatCounter(v, config.Tag)
|
uplinkCounter, downlinkCounter := getStatCounter(v, config.Tag)
|
||||||
h := &Handler{
|
h := &Handler{
|
||||||
tag: config.Tag,
|
tag: config.Tag,
|
||||||
outboundManager: v.GetFeature(outbound.ManagerType()).(outbound.Manager),
|
|
||||||
uplinkCounter: uplinkCounter,
|
uplinkCounter: uplinkCounter,
|
||||||
downlinkCounter: downlinkCounter,
|
downlinkCounter: downlinkCounter,
|
||||||
}
|
}
|
||||||
@@ -92,7 +87,7 @@ func NewHandler(ctx context.Context, config *core.OutboundHandlerConfig) (outbou
|
|||||||
h.senderSettings = s
|
h.senderSettings = s
|
||||||
mss, err := internet.ToMemoryStreamConfig(s.StreamSettings)
|
mss, err := internet.ToMemoryStreamConfig(s.StreamSettings)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("failed to parse stream settings").Base(err).AtWarning()
|
return nil, errors.New("failed to parse stream settings").Base(err)
|
||||||
}
|
}
|
||||||
h.streamSettings = mss
|
h.streamSettings = mss
|
||||||
default:
|
default:
|
||||||
@@ -108,9 +103,11 @@ func NewHandler(ctx context.Context, config *core.OutboundHandlerConfig) (outbou
|
|||||||
|
|
||||||
ctx = session.ContextWithFullHandler(ctx, h)
|
ctx = session.ContextWithFullHandler(ctx, h)
|
||||||
|
|
||||||
newCtx := session.ContextWithStreamSettings(ctx, h.streamSettings)
|
if h.streamSettings != nil {
|
||||||
|
ctx = session.ContextWithStreamSettings(ctx, h.streamSettings)
|
||||||
|
}
|
||||||
|
|
||||||
rawProxyHandler, err := common.CreateObject(newCtx, proxyConfig)
|
rawProxyHandler, err := common.CreateObject(ctx, proxyConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -197,7 +194,6 @@ func (h *Handler) Dispatch(ctx context.Context, link *transport.Link) {
|
|||||||
common.Interrupt(link.Reader)
|
common.Interrupt(link.Reader)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
unchangedDomain := ob.Target.Address.Domain()
|
unchangedDomain := ob.Target.Address.Domain()
|
||||||
ob.Target.Address = net.IPAddress(ips[dice.Roll(len(ips))])
|
ob.Target.Address = net.IPAddress(ips[dice.Roll(len(ips))])
|
||||||
@@ -221,7 +217,7 @@ func (h *Handler) Dispatch(ctx context.Context, link *transport.Link) {
|
|||||||
if ob.Target.Network == net.Network_UDP && ob.Target.Port == 443 {
|
if ob.Target.Network == net.Network_UDP && ob.Target.Port == 443 {
|
||||||
switch h.udp443 {
|
switch h.udp443 {
|
||||||
case "reject":
|
case "reject":
|
||||||
test(errors.New("XUDP rejected UDP/443 traffic").AtInfo())
|
test(errors.New("XUDP rejected UDP/443 traffic"))
|
||||||
return
|
return
|
||||||
case "skip":
|
case "skip":
|
||||||
goto out
|
goto out
|
||||||
@@ -270,66 +266,26 @@ func (h *Handler) DestIpAddress() net.IP {
|
|||||||
|
|
||||||
// Dial implements internet.Dialer.
|
// Dial implements internet.Dialer.
|
||||||
func (h *Handler) Dial(ctx context.Context, dest net.Destination) (stat.Connection, error) {
|
func (h *Handler) Dial(ctx context.Context, dest net.Destination) (stat.Connection, error) {
|
||||||
if h.senderSettings != nil {
|
if h.senderSettings != nil && h.senderSettings.Via != nil {
|
||||||
|
outbounds := session.OutboundsFromContext(ctx)
|
||||||
if h.senderSettings.ProxySettings.HasTag() {
|
ob := outbounds[len(outbounds)-1]
|
||||||
|
h.SetOutboundGateway(ctx, ob)
|
||||||
tag := h.senderSettings.ProxySettings.Tag
|
|
||||||
handler := h.outboundManager.GetHandler(tag)
|
|
||||||
if handler != nil {
|
|
||||||
errors.LogDebug(ctx, "proxying to ", tag, " for dest ", dest)
|
|
||||||
outbounds := session.OutboundsFromContext(ctx)
|
|
||||||
ctx = session.ContextWithOutbounds(ctx, append(outbounds, &session.Outbound{
|
|
||||||
Target: dest,
|
|
||||||
Tag: tag,
|
|
||||||
})) // add another outbound in session ctx
|
|
||||||
opts := pipe.OptionsFromContext(ctx)
|
|
||||||
uplinkReader, uplinkWriter := pipe.New(opts...)
|
|
||||||
downlinkReader, downlinkWriter := pipe.New(opts...)
|
|
||||||
|
|
||||||
go handler.Dispatch(ctx, &transport.Link{Reader: uplinkReader, Writer: downlinkWriter})
|
|
||||||
conn := cnc.NewConnection(cnc.ConnectionInputMulti(uplinkWriter), cnc.ConnectionOutputMulti(downlinkReader))
|
|
||||||
|
|
||||||
if config := tls.ConfigFromStreamSettings(h.streamSettings); config != nil {
|
|
||||||
tlsConfig := config.GetTLSConfig(tls.WithDestination(dest))
|
|
||||||
conn = tls.Client(conn, tlsConfig)
|
|
||||||
}
|
|
||||||
|
|
||||||
return h.getStatCouterConnection(conn), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
errors.LogError(ctx, "failed to get outbound handler with tag: ", tag)
|
|
||||||
return nil, errors.New("failed to get outbound handler with tag: " + tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
if h.senderSettings.Via != nil {
|
|
||||||
outbounds := session.OutboundsFromContext(ctx)
|
|
||||||
ob := outbounds[len(outbounds)-1]
|
|
||||||
h.SetOutboundGateway(ctx, ob)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
conn, err := internet.Dial(ctx, dest, h.streamSettings)
|
conn, err := internet.Dial(ctx, dest, h.streamSettings)
|
||||||
conn = h.getStatCouterConnection(conn)
|
conn = h.getStatCouterConnection(conn)
|
||||||
outbounds := session.OutboundsFromContext(ctx)
|
|
||||||
if outbounds != nil {
|
|
||||||
ob := outbounds[len(outbounds)-1]
|
|
||||||
ob.Conn = conn
|
|
||||||
} else {
|
|
||||||
// for Vision's pre-connect
|
|
||||||
}
|
|
||||||
return conn, err
|
return conn, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) SetOutboundGateway(ctx context.Context, ob *session.Outbound) {
|
func (h *Handler) SetOutboundGateway(ctx context.Context, ob *session.Outbound) {
|
||||||
if ob.Gateway == nil && h.senderSettings != nil && h.senderSettings.Via != nil && !h.senderSettings.ProxySettings.HasTag() && (h.streamSettings.SocketSettings == nil || len(h.streamSettings.SocketSettings.DialerProxy) == 0) {
|
if ob.Gateway == nil && h.senderSettings != nil && h.senderSettings.Via != nil &&
|
||||||
|
(h.streamSettings.SocketSettings == nil || len(h.streamSettings.SocketSettings.DialerProxy) == 0) {
|
||||||
var domain string
|
var domain string
|
||||||
addr := h.senderSettings.Via.AsAddress()
|
addr := h.senderSettings.Via.AsAddress()
|
||||||
domain = h.senderSettings.Via.GetDomain()
|
domain = h.senderSettings.Via.GetDomain()
|
||||||
switch {
|
switch {
|
||||||
case h.senderSettings.ViaCidr != "":
|
case h.senderSettings.ViaCidr != "":
|
||||||
ob.Gateway = ParseRandomIP(addr, h.senderSettings.ViaCidr)
|
ob.Gateway = ParseRandomIP(addr, h.senderSettings.ViaCidr)
|
||||||
|
|
||||||
case domain == "origin":
|
case domain == "origin":
|
||||||
if inbound := session.InboundFromContext(ctx); inbound != nil {
|
if inbound := session.InboundFromContext(ctx); inbound != nil {
|
||||||
if inbound.Local.IsValid() && inbound.Local.Address.Family().IsIP() {
|
if inbound.Local.IsValid() && inbound.Local.Address.Family().IsIP() {
|
||||||
@@ -344,11 +300,9 @@ func (h *Handler) SetOutboundGateway(ctx context.Context, ob *session.Outbound)
|
|||||||
errors.LogDebug(ctx, "use inbound source ip as sendthrough: ", inbound.Source.Address.String())
|
errors.LogDebug(ctx, "use inbound source ip as sendthrough: ", inbound.Source.Address.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// case addr.Family().IsDomain():
|
default: // case addr.Family().IsDomain():
|
||||||
default:
|
|
||||||
ob.Gateway = addr
|
ob.Gateway = addr
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -68,13 +68,13 @@ func (p *Portal) HandleConnection(ctx context.Context, link *transport.Link) err
|
|||||||
outbounds := session.OutboundsFromContext(ctx)
|
outbounds := session.OutboundsFromContext(ctx)
|
||||||
ob := outbounds[len(outbounds)-1]
|
ob := outbounds[len(outbounds)-1]
|
||||||
if ob == nil {
|
if ob == nil {
|
||||||
return errors.New("outbound metadata not found").AtError()
|
return errors.New("outbound metadata not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
if isDomain(ob.Target, p.domain) {
|
if isDomain(ob.Target, p.domain) {
|
||||||
muxClient, err := mux.NewClientWorker(*link, mux.ClientStrategy{})
|
muxClient, err := mux.NewClientWorker(*link, mux.ClientStrategy{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to create mux client worker").Base(err).AtWarning()
|
return errors.New("failed to create mux client worker").Base(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
worker, err := NewPortalWorker(muxClient)
|
worker, err := NewPortalWorker(muxClient)
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ func (rr *RoutingRule) BuildCondition() (Condition, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if conds.Len() == 0 {
|
if conds.Len() == 0 {
|
||||||
return nil, errors.New("this rule has no effective fields").AtWarning()
|
return nil, errors.New("this rule has no effective fields")
|
||||||
}
|
}
|
||||||
|
|
||||||
return conds, nil
|
return conds, nil
|
||||||
@@ -145,7 +145,7 @@ func (br *BalancingRule) Build(ohm outbound.Manager, dispatcher routing.Dispatch
|
|||||||
}
|
}
|
||||||
s, ok := i.(*StrategyLeastLoadConfig)
|
s, ok := i.(*StrategyLeastLoadConfig)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("not a StrategyLeastLoadConfig").AtError()
|
return nil, errors.New("not a StrategyLeastLoadConfig")
|
||||||
}
|
}
|
||||||
leastLoadStrategy := NewLeastLoadStrategy(s)
|
leastLoadStrategy := NewLeastLoadStrategy(s)
|
||||||
return &Balancer{
|
return &Balancer{
|
||||||
|
|||||||
@@ -118,7 +118,9 @@ func (w *BufferedWriter) Write(b []byte) (int, error) {
|
|||||||
|
|
||||||
nBytes, err := w.buffer.Write(b)
|
nBytes, err := w.buffer.Write(b)
|
||||||
totalBytes += nBytes
|
totalBytes += nBytes
|
||||||
if err != nil {
|
|
||||||
|
// ErrBufferFull means a partial write, so flush below and continue
|
||||||
|
if err != nil && err != ErrBufferFull {
|
||||||
return totalBytes, err
|
return totalBytes, err
|
||||||
}
|
}
|
||||||
if !w.buffered || w.buffer.IsFull() {
|
if !w.buffered || w.buffer.IsFull() {
|
||||||
|
|||||||
@@ -10,12 +10,12 @@ import (
|
|||||||
|
|
||||||
// [,)
|
// [,)
|
||||||
func RandBetween(from int64, to int64) int64 {
|
func RandBetween(from int64, to int64) int64 {
|
||||||
if from == to {
|
|
||||||
return from
|
|
||||||
}
|
|
||||||
if from > to {
|
if from > to {
|
||||||
from, to = to, from
|
from, to = to, from
|
||||||
}
|
}
|
||||||
|
if d := to - from; d == 0 || d == 1 {
|
||||||
|
return from
|
||||||
|
}
|
||||||
bigInt, _ := rand.Int(rand.Reader, big.NewInt(to-from))
|
bigInt, _ := rand.Int(rand.Reader, big.NewInt(to-from))
|
||||||
return from + bigInt.Int64()
|
return from + bigInt.Int64()
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-65
@@ -18,17 +18,12 @@ type hasInnerError interface {
|
|||||||
Unwrap() error
|
Unwrap() error
|
||||||
}
|
}
|
||||||
|
|
||||||
type hasSeverity interface {
|
|
||||||
Severity() log.Severity
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error is an error object with underlying error.
|
// Error is an error object with underlying error.
|
||||||
type Error struct {
|
type Error struct {
|
||||||
prefix []interface{}
|
prefix []interface{}
|
||||||
message []interface{}
|
message []interface{}
|
||||||
caller string
|
caller string
|
||||||
inner error
|
inner error
|
||||||
severity log.Severity
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error implements error.Error().
|
// Error implements error.Error().
|
||||||
@@ -69,46 +64,6 @@ func (err *Error) Base(e error) *Error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (err *Error) atSeverity(s log.Severity) *Error {
|
|
||||||
err.severity = s
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (err *Error) Severity() log.Severity {
|
|
||||||
if err.inner == nil {
|
|
||||||
return err.severity
|
|
||||||
}
|
|
||||||
|
|
||||||
if s, ok := err.inner.(hasSeverity); ok {
|
|
||||||
as := s.Severity()
|
|
||||||
if as < err.severity {
|
|
||||||
return as
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return err.severity
|
|
||||||
}
|
|
||||||
|
|
||||||
// AtDebug sets the severity to debug.
|
|
||||||
func (err *Error) AtDebug() *Error {
|
|
||||||
return err.atSeverity(log.Severity_Debug)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AtInfo sets the severity to info.
|
|
||||||
func (err *Error) AtInfo() *Error {
|
|
||||||
return err.atSeverity(log.Severity_Info)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AtWarning sets the severity to warning.
|
|
||||||
func (err *Error) AtWarning() *Error {
|
|
||||||
return err.atSeverity(log.Severity_Warning)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AtError sets the severity to error.
|
|
||||||
func (err *Error) AtError() *Error {
|
|
||||||
return err.atSeverity(log.Severity_Error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns the string representation of this error.
|
// String returns the string representation of this error.
|
||||||
func (err *Error) String() string {
|
func (err *Error) String() string {
|
||||||
return err.Error()
|
return err.Error()
|
||||||
@@ -132,9 +87,8 @@ func New(msg ...interface{}) *Error {
|
|||||||
details = details[:i]
|
details = details[:i]
|
||||||
}
|
}
|
||||||
return &Error{
|
return &Error{
|
||||||
message: msg,
|
message: msg,
|
||||||
severity: log.Severity_Info,
|
caller: details,
|
||||||
caller: details,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,6 +125,9 @@ func LogErrorInner(ctx context.Context, inner error, msg ...interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func doLog(ctx context.Context, inner error, severity log.Severity, msg ...interface{}) {
|
func doLog(ctx context.Context, inner error, severity log.Severity, msg ...interface{}) {
|
||||||
|
if log.GetSeverity() < severity {
|
||||||
|
return
|
||||||
|
}
|
||||||
pc, _, _, _ := runtime.Caller(2)
|
pc, _, _, _ := runtime.Caller(2)
|
||||||
details := runtime.FuncForPC(pc).Name()
|
details := runtime.FuncForPC(pc).Name()
|
||||||
if len(details) >= trim {
|
if len(details) >= trim {
|
||||||
@@ -181,10 +138,9 @@ func doLog(ctx context.Context, inner error, severity log.Severity, msg ...inter
|
|||||||
details = details[:i]
|
details = details[:i]
|
||||||
}
|
}
|
||||||
err := &Error{
|
err := &Error{
|
||||||
message: msg,
|
message: msg,
|
||||||
severity: severity,
|
caller: details,
|
||||||
caller: details,
|
inner: inner,
|
||||||
inner: inner,
|
|
||||||
}
|
}
|
||||||
if ctx != nil && ctx != context.Background() {
|
if ctx != nil && ctx != context.Background() {
|
||||||
id := uint32(c.IDFromContext(ctx))
|
id := uint32(c.IDFromContext(ctx))
|
||||||
@@ -193,7 +149,7 @@ func doLog(ctx context.Context, inner error, severity log.Severity, msg ...inter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.Record(&log.GeneralMessage{
|
log.Record(&log.GeneralMessage{
|
||||||
Severity: GetSeverity(err),
|
Severity: severity,
|
||||||
Content: err,
|
Content: err,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -217,11 +173,3 @@ L:
|
|||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSeverity returns the actual severity of the error, including inner errors.
|
|
||||||
func GetSeverity(err error) log.Severity {
|
|
||||||
if s, ok := err.(hasSeverity); ok {
|
|
||||||
return s.Severity()
|
|
||||||
}
|
|
||||||
return log.Severity_Info
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -7,30 +7,21 @@ import (
|
|||||||
|
|
||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
. "github.com/xtls/xray-core/common/errors"
|
. "github.com/xtls/xray-core/common/errors"
|
||||||
"github.com/xtls/xray-core/common/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestError(t *testing.T) {
|
func TestError(t *testing.T) {
|
||||||
err := New("TestError")
|
err := New("TestError")
|
||||||
if v := GetSeverity(err); v != log.Severity_Info {
|
if v := err.Error(); !strings.Contains(v, "TestError") {
|
||||||
t.Error("severity: ", v)
|
t.Error("error: ", v)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = New("TestError2").Base(io.EOF)
|
err = New("TestError2").Base(io.EOF)
|
||||||
if v := GetSeverity(err); v != log.Severity_Info {
|
if v := err.Error(); !strings.Contains(v, "EOF") {
|
||||||
t.Error("severity: ", v)
|
t.Error("error: ", v)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = New("TestError3").Base(io.EOF).AtWarning()
|
err = New("TestError3").Base(io.EOF)
|
||||||
if v := GetSeverity(err); v != log.Severity_Warning {
|
err = New("TestError4").Base(err)
|
||||||
t.Error("severity: ", v)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = New("TestError4").Base(io.EOF).AtWarning()
|
|
||||||
err = New("TestError5").Base(err)
|
|
||||||
if v := GetSeverity(err); v != log.Severity_Warning {
|
|
||||||
t.Error("severity: ", v)
|
|
||||||
}
|
|
||||||
if v := err.Error(); !strings.Contains(v, "EOF") {
|
if v := err.Error(); !strings.Contains(v, "EOF") {
|
||||||
t.Error("error: ", v)
|
t.Error("error: ", v)
|
||||||
}
|
}
|
||||||
|
|||||||
+21
-25
@@ -1,7 +1,7 @@
|
|||||||
package log // import "github.com/xtls/xray-core/common/log"
|
package log // import "github.com/xtls/xray-core/common/log"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"sync"
|
"sync/atomic"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common/serial"
|
"github.com/xtls/xray-core/common/serial"
|
||||||
)
|
)
|
||||||
@@ -29,36 +29,32 @@ func (m *GeneralMessage) String() string {
|
|||||||
|
|
||||||
// Record writes a message into log stream.
|
// Record writes a message into log stream.
|
||||||
func Record(msg Message) {
|
func Record(msg Message) {
|
||||||
logHandler.Handle(msg)
|
if h := logHandler.Load(); h != nil {
|
||||||
|
(*h).Handle(msg)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var logHandler syncHandler
|
type SeverityLogger interface {
|
||||||
|
Handler
|
||||||
|
Severity() Severity
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetSeverity() Severity {
|
||||||
|
if h := logHandler.Load(); h != nil {
|
||||||
|
if sh, ok := (*h).(SeverityLogger); ok {
|
||||||
|
return sh.Severity()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// log everything by default
|
||||||
|
return Severity_Debug
|
||||||
|
}
|
||||||
|
|
||||||
|
var logHandler atomic.Pointer[Handler]
|
||||||
|
|
||||||
// RegisterHandler registers a new handler as current log handler. Previous registered handler will be discarded.
|
// RegisterHandler registers a new handler as current log handler. Previous registered handler will be discarded.
|
||||||
func RegisterHandler(handler Handler) {
|
func RegisterHandler(handler Handler) {
|
||||||
if handler == nil {
|
if handler == nil {
|
||||||
panic("Log handler is nil")
|
panic("Log handler is nil")
|
||||||
}
|
}
|
||||||
logHandler.Set(handler)
|
logHandler.Store(&handler)
|
||||||
}
|
|
||||||
|
|
||||||
type syncHandler struct {
|
|
||||||
sync.RWMutex
|
|
||||||
Handler
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *syncHandler) Handle(msg Message) {
|
|
||||||
h.RLock()
|
|
||||||
defer h.RUnlock()
|
|
||||||
|
|
||||||
if h.Handler != nil {
|
|
||||||
h.Handler.Handle(msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *syncHandler) Set(handler Handler) {
|
|
||||||
h.Lock()
|
|
||||||
defer h.Unlock()
|
|
||||||
|
|
||||||
h.Handler = handler
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,6 +68,10 @@ func (l *serverityLogger) Handle(msg Message) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l *serverityLogger) Severity() Severity {
|
||||||
|
return l.logLevel
|
||||||
|
}
|
||||||
|
|
||||||
func (l *generalLogger) run() {
|
func (l *generalLogger) run() {
|
||||||
defer l.access.Signal()
|
defer l.access.Signal()
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ func (m *ClientManager) Dispatch(ctx context.Context, link *transport.Link) erro
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return errors.New("unable to find an available mux client").AtWarning()
|
return errors.New("unable to find an available mux client")
|
||||||
}
|
}
|
||||||
|
|
||||||
type WorkerPicker interface {
|
type WorkerPicker interface {
|
||||||
|
|||||||
+1
-1
@@ -117,7 +117,7 @@ func (f *FrameMetadata) Unmarshal(reader io.Reader, readSourceAndLocal bool) err
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if metaLen > 512 {
|
if metaLen > 512 {
|
||||||
return errors.New("invalid metalen ", metaLen).AtError()
|
return errors.New("invalid metalen ", metaLen)
|
||||||
}
|
}
|
||||||
|
|
||||||
b := buf.New()
|
b := buf.New()
|
||||||
|
|||||||
@@ -351,7 +351,7 @@ func (w *ServerWorker) handleFrame(ctx context.Context, reader *buf.BufferedRead
|
|||||||
err = w.handleStatusKeep(&meta, reader)
|
err = w.handleStatusKeep(&meta, reader)
|
||||||
default:
|
default:
|
||||||
status := meta.SessionStatus
|
status := meta.SessionStatus
|
||||||
return errors.New("unknown status: ", status).AtError()
|
return errors.New("unknown status: ", status)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
|
|
||||||
func (u *User) GetTypedAccount() (Account, error) {
|
func (u *User) GetTypedAccount() (Account, error) {
|
||||||
if u.GetAccount() == nil {
|
if u.GetAccount() == nil {
|
||||||
return nil, errors.New("Account is missing").AtWarning()
|
return nil, errors.New("Account is missing")
|
||||||
}
|
}
|
||||||
|
|
||||||
rawAccount, err := u.Account.GetInstance()
|
rawAccount, err := u.Account.GetInstance()
|
||||||
|
|||||||
@@ -70,8 +70,6 @@ type Outbound struct {
|
|||||||
Tag string
|
Tag string
|
||||||
// Name of the outbound proxy that handles the connection.
|
// Name of the outbound proxy that handles the connection.
|
||||||
Name string
|
Name string
|
||||||
// Unused. Conn is actually internet.Connection. May be nil. It is currently nil for outbound with proxySettings
|
|
||||||
Conn net.Conn
|
|
||||||
// CanSpliceCopy is a property for this connection
|
// CanSpliceCopy is a property for this connection
|
||||||
// 1 = can, 2 = after processing protocol info should be able to, 3 = cannot
|
// 1 = can, 2 = after processing protocol info should be able to, 3 = cannot
|
||||||
CanSpliceCopy int
|
CanSpliceCopy int
|
||||||
|
|||||||
+2
-2
@@ -16,7 +16,7 @@ var typeCreatorRegistry = make(map[reflect.Type]ConfigCreator)
|
|||||||
func RegisterConfig(config interface{}, configCreator ConfigCreator) error {
|
func RegisterConfig(config interface{}, configCreator ConfigCreator) error {
|
||||||
configType := reflect.TypeOf(config)
|
configType := reflect.TypeOf(config)
|
||||||
if _, found := typeCreatorRegistry[configType]; found {
|
if _, found := typeCreatorRegistry[configType]; found {
|
||||||
return errors.New(configType.Name() + " is already registered").AtError()
|
return errors.New(configType.Name() + " is already registered")
|
||||||
}
|
}
|
||||||
typeCreatorRegistry[configType] = configCreator
|
typeCreatorRegistry[configType] = configCreator
|
||||||
return nil
|
return nil
|
||||||
@@ -27,7 +27,7 @@ func CreateObject(ctx context.Context, config interface{}) (interface{}, error)
|
|||||||
configType := reflect.TypeOf(config)
|
configType := reflect.TypeOf(config)
|
||||||
creator, found := typeCreatorRegistry[configType]
|
creator, found := typeCreatorRegistry[configType]
|
||||||
if !found {
|
if !found {
|
||||||
return nil, errors.New(configType.String() + " is not registered").AtError()
|
return nil, errors.New(configType.String() + " is not registered")
|
||||||
}
|
}
|
||||||
return creator(ctx, config)
|
return creator(ctx, config)
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -125,7 +125,7 @@ func LoadConfig(formatName string, input interface{}) (*Config, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if f == "" {
|
if f == "" {
|
||||||
return nil, errors.New("Failed to get format of ", file).AtWarning()
|
return nil, errors.New("Failed to get format of ", file)
|
||||||
}
|
}
|
||||||
|
|
||||||
if f == "protobuf" {
|
if f == "protobuf" {
|
||||||
@@ -142,7 +142,7 @@ func LoadConfig(formatName string, input interface{}) (*Config, error) {
|
|||||||
if len(v) == 1 {
|
if len(v) == 1 {
|
||||||
return configLoaderByName["protobuf"].Loader(v)
|
return configLoaderByName["protobuf"].Loader(v)
|
||||||
} else {
|
} else {
|
||||||
return nil, errors.New("Only one protobuf config file is allowed").AtWarning()
|
return nil, errors.New("Only one protobuf config file is allowed")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,11 +152,11 @@ func LoadConfig(formatName string, input interface{}) (*Config, error) {
|
|||||||
if f, found := configLoaderByName[formatName]; found {
|
if f, found := configLoaderByName[formatName]; found {
|
||||||
return f.Loader(v)
|
return f.Loader(v)
|
||||||
} else {
|
} else {
|
||||||
return nil, errors.New("Unable to load config in", formatName).AtWarning()
|
return nil, errors.New("Unable to load config in", formatName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, errors.New("Unable to load config").AtWarning()
|
return nil, errors.New("Unable to load config")
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadProtobufConfig(data []byte) (*Config, error) {
|
func loadProtobufConfig(data []byte) (*Config, error) {
|
||||||
|
|||||||
+2
-2
@@ -19,8 +19,8 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
Version_x byte = 26
|
Version_x byte = 26
|
||||||
Version_y byte = 7
|
Version_y byte = 9
|
||||||
Version_z byte = 28
|
Version_z byte = 9
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
module github.com/xtls/xray-core
|
module github.com/xtls/xray-core
|
||||||
|
|
||||||
go 1.26
|
go 1.27
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/apernet/quic-go v0.61.1-0.20260806010916-184d081eef3e
|
github.com/apernet/quic-go v0.61.1-0.20260806010916-184d081eef3e
|
||||||
@@ -22,7 +22,7 @@ require (
|
|||||||
github.com/sagernet/sing-shadowsocks v0.2.7
|
github.com/sagernet/sing-shadowsocks v0.2.7
|
||||||
github.com/stretchr/testify v1.12.1
|
github.com/stretchr/testify v1.12.1
|
||||||
github.com/vishvananda/netlink v1.3.1
|
github.com/vishvananda/netlink v1.3.1
|
||||||
github.com/xtls/reality v0.0.0-20260322125925-9234c772ba8f
|
github.com/xtls/reality v0.0.0-20260908062103-8cdf7bf9c7f0
|
||||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
|
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
|
||||||
golang.org/x/crypto v0.55.0
|
golang.org/x/crypto v0.55.0
|
||||||
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842
|
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842
|
||||||
@@ -32,11 +32,12 @@ require (
|
|||||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2
|
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2
|
||||||
golang.zx2c4.com/wireguard v0.0.0-20250521234502-f333402bd9cb
|
golang.zx2c4.com/wireguard v0.0.0-20250521234502-f333402bd9cb
|
||||||
golang.zx2c4.com/wireguard/windows v1.0.1
|
golang.zx2c4.com/wireguard/windows v1.0.1
|
||||||
google.golang.org/grpc v1.83.1
|
google.golang.org/grpc v1.83.2
|
||||||
google.golang.org/protobuf v1.36.12
|
google.golang.org/protobuf v1.36.12
|
||||||
gvisor.dev/gvisor v0.0.0-20260122175437-89a5d21be8f0
|
gvisor.dev/gvisor v0.0.0-20260122175437-89a5d21be8f0
|
||||||
h12.io/socks v1.0.3
|
h12.io/socks v1.0.3
|
||||||
lukechampine.com/blake3 v1.4.1
|
lukechampine.com/blake3 v1.4.1
|
||||||
|
mvdan.cc/gofumpt v0.12.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
@@ -48,7 +49,6 @@ require (
|
|||||||
github.com/juju/ratelimit v1.0.2 // indirect
|
github.com/juju/ratelimit v1.0.2 // indirect
|
||||||
github.com/klauspost/compress v1.17.4 // indirect
|
github.com/klauspost/compress v1.17.4 // indirect
|
||||||
github.com/koron/go-ssdp v0.0.4 // indirect
|
github.com/koron/go-ssdp v0.0.4 // indirect
|
||||||
github.com/kr/text v0.2.0 // indirect
|
|
||||||
github.com/libp2p/go-netroute v0.2.1 // indirect
|
github.com/libp2p/go-netroute v0.2.1 // indirect
|
||||||
github.com/pion/dtls/v3 v3.1.5 // indirect
|
github.com/pion/dtls/v3 v3.1.5 // indirect
|
||||||
github.com/pion/logging v0.2.4 // indirect
|
github.com/pion/logging v0.2.4 // indirect
|
||||||
@@ -59,6 +59,7 @@ require (
|
|||||||
go.yaml.in/yaml/v3 v3.0.5 // indirect
|
go.yaml.in/yaml/v3 v3.0.5 // indirect
|
||||||
golang.org/x/text v0.41.0 // indirect
|
golang.org/x/text v0.41.0 // indirect
|
||||||
golang.org/x/time v0.14.0 // indirect
|
golang.org/x/time v0.14.0 // indirect
|
||||||
|
golang.org/x/tools v0.49.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -6,13 +6,14 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF
|
|||||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/cloudflare/circl v1.6.5 h1:O64F26HEqNhznd/hrC5KZXVKYuKM2rx4deZDTc4ihQA=
|
github.com/cloudflare/circl v1.6.5 h1:O64F26HEqNhznd/hrC5KZXVKYuKM2rx4deZDTc4ihQA=
|
||||||
github.com/cloudflare/circl v1.6.5/go.mod h1:h5LNyxAc5nTue9DS5jT+48en2PSDYt3zdGnz5OstK6c=
|
github.com/cloudflare/circl v1.6.5/go.mod h1:h5LNyxAc5nTue9DS5jT+48en2PSDYt3zdGnz5OstK6c=
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
|
||||||
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344 h1:Arcl6UOIS/kgO2nW3A65HN+7CMjSDP/gofXL4CZt1V4=
|
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344 h1:Arcl6UOIS/kgO2nW3A65HN+7CMjSDP/gofXL4CZt1V4=
|
||||||
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I=
|
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I=
|
||||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||||
|
github.com/go-quicktest/qt v1.102.0 h1:HSQxCeh5YZH3EL3W39ixjtyaEhcWSXQHtHnMBzSs474=
|
||||||
|
github.com/go-quicktest/qt v1.102.0/go.mod h1:p4lGIVX+8Wa6ZPNDvqcxq36XpUDLh42FLetFU7odllI=
|
||||||
github.com/golang/mock v1.7.0-rc.1 h1:YojYx61/OLFsiv6Rw1Z96LpldJIy31o+UHmwAUMJ6/U=
|
github.com/golang/mock v1.7.0-rc.1 h1:YojYx61/OLFsiv6Rw1Z96LpldJIy31o+UHmwAUMJ6/U=
|
||||||
github.com/golang/mock v1.7.0-rc.1/go.mod h1:s42URUywIqd+OcERslBJvOjepvNymP31m3q8d/GkuRs=
|
github.com/golang/mock v1.7.0-rc.1/go.mod h1:s42URUywIqd+OcERslBJvOjepvNymP31m3q8d/GkuRs=
|
||||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||||
@@ -73,8 +74,8 @@ github.com/refraction-networking/utls v1.8.3-0.20260301010127-aa6edf4b11af h1:er
|
|||||||
github.com/refraction-networking/utls v1.8.3-0.20260301010127-aa6edf4b11af/go.mod h1:jkSOEkLqn+S/jtpEHPOsVv/4V4EVnelwbMQl4vCWXAM=
|
github.com/refraction-networking/utls v1.8.3-0.20260301010127-aa6edf4b11af/go.mod h1:jkSOEkLqn+S/jtpEHPOsVv/4V4EVnelwbMQl4vCWXAM=
|
||||||
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||||
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
github.com/rogpeppe/go-internal v1.16.0 h1:O9DK+vNMDVGLr2BeZqmpLeMjiMNkuXfcqntWbZV6S5g=
|
||||||
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
|
github.com/rogpeppe/go-internal v1.16.0/go.mod h1:DrUVZyrJU+txYW5/1kwtXQSMFio52ZOxX7yM1VHvnxs=
|
||||||
github.com/sagernet/sing v0.5.1 h1:mhL/MZVq0TjuvHcpYcFtmSD1BFOxZ/+8ofbNZcg1k1Y=
|
github.com/sagernet/sing v0.5.1 h1:mhL/MZVq0TjuvHcpYcFtmSD1BFOxZ/+8ofbNZcg1k1Y=
|
||||||
github.com/sagernet/sing v0.5.1/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
github.com/sagernet/sing v0.5.1/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||||
github.com/sagernet/sing-shadowsocks v0.2.7 h1:zaopR1tbHEw5Nk6FAkM05wCslV6ahVegEZaKMv9ipx8=
|
github.com/sagernet/sing-shadowsocks v0.2.7 h1:zaopR1tbHEw5Nk6FAkM05wCslV6ahVegEZaKMv9ipx8=
|
||||||
@@ -87,8 +88,8 @@ github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zd
|
|||||||
github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
||||||
github.com/wlynxg/anet v0.0.5 h1:J3VJGi1gvo0JwZ/P1/Yc/8p63SoW98B5dHkYDmpgvvU=
|
github.com/wlynxg/anet v0.0.5 h1:J3VJGi1gvo0JwZ/P1/Yc/8p63SoW98B5dHkYDmpgvvU=
|
||||||
github.com/wlynxg/anet v0.0.5/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA=
|
github.com/wlynxg/anet v0.0.5/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA=
|
||||||
github.com/xtls/reality v0.0.0-20260322125925-9234c772ba8f h1:iy2JRioxmUpoJ3SzbFPyTxHZMbR/rSHP7dOOgYaq1O8=
|
github.com/xtls/reality v0.0.0-20260908062103-8cdf7bf9c7f0 h1:rb+fKQFhz+5I2PPuQsNYxI5mUU840XWYtRF0ZBjvkws=
|
||||||
github.com/xtls/reality v0.0.0-20260322125925-9234c772ba8f/go.mod h1:DsJblcWDGt76+FVqBVwbwRhxyyNJsGV48gJLch0OOWI=
|
github.com/xtls/reality v0.0.0-20260908062103-8cdf7bf9c7f0/go.mod h1:DsJblcWDGt76+FVqBVwbwRhxyyNJsGV48gJLch0OOWI=
|
||||||
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||||
@@ -147,6 +148,8 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
|
|||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
||||||
|
golang.org/x/tools v0.49.0 h1:3NI7VXzL9+1WZD52Dx2ttoPwD5DWrFGpl9mFZDlmisI=
|
||||||
|
golang.org/x/tools v0.49.0/go.mod h1:SJNXV9DBKT0UbdttsQjbfJlAE/q+y36++zo3uL3N0Oo=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
@@ -160,8 +163,8 @@ gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
|
|||||||
gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
|
gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa h1:mZHHdPZl0dbGHCflZgAq/Q468DWVFcU2whhB2KAo8fk=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa h1:mZHHdPZl0dbGHCflZgAq/Q468DWVFcU2whhB2KAo8fk=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||||
google.golang.org/grpc v1.83.1 h1:HIO0+BEtBP6soyqvqC8sNUjZ7bTs+0hFQuFF+RAy++Y=
|
google.golang.org/grpc v1.83.2 h1:EManeRomTObA0BU7I8vXgg/78uE5MJ9M8B39EX2WscU=
|
||||||
google.golang.org/grpc v1.83.1/go.mod h1:kDyl6SKsiHKt0uylY5gtn5cEjkrIOhQOGDgIc4JGwzQ=
|
google.golang.org/grpc v1.83.2/go.mod h1:YPI1hK3kDked6iHvgX3tR0y+nX/qpMFKhPgFsokw1S8=
|
||||||
google.golang.org/protobuf v1.36.12 h1:pJOKDDOyeXErUroCihFAd5LQuwXBSpVnKGrj5o/fwxc=
|
google.golang.org/protobuf v1.36.12 h1:pJOKDDOyeXErUroCihFAd5LQuwXBSpVnKGrj5o/fwxc=
|
||||||
google.golang.org/protobuf v1.36.12/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
google.golang.org/protobuf v1.36.12/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
@@ -176,3 +179,5 @@ h12.io/socks v1.0.3 h1:Ka3qaQewws4j4/eDQnOdpr4wXsC//dXtWvftlIcCQUo=
|
|||||||
h12.io/socks v1.0.3/go.mod h1:AIhxy1jOId/XCz9BO+EIgNL2rQiPTBNnOfnVnQ+3Eck=
|
h12.io/socks v1.0.3/go.mod h1:AIhxy1jOId/XCz9BO+EIgNL2rQiPTBNnOfnVnQ+3Eck=
|
||||||
lukechampine.com/blake3 v1.4.1 h1:I3Smz7gso8w4/TunLKec6K2fn+kyKtDxr/xcQEN84Wg=
|
lukechampine.com/blake3 v1.4.1 h1:I3Smz7gso8w4/TunLKec6K2fn+kyKtDxr/xcQEN84Wg=
|
||||||
lukechampine.com/blake3 v1.4.1/go.mod h1:QFosUxmjB8mnrWFSNwKmvxHpfY72bmD2tQ0kBMM3kwo=
|
lukechampine.com/blake3 v1.4.1/go.mod h1:QFosUxmjB8mnrWFSNwKmvxHpfY72bmD2tQ0kBMM3kwo=
|
||||||
|
mvdan.cc/gofumpt v0.12.0 h1:1Lbudkz2kpM9Cjz2pL4M19u7q+GaEhCTNf7N9mfpcho=
|
||||||
|
mvdan.cc/gofumpt v0.12.0/go.mod h1:SmBHHrljiZu/uoypeKup3rFzP6eoC9UwCp2iH5E3jZA=
|
||||||
|
|||||||
+2
-2
@@ -97,7 +97,7 @@ func (v *HTTPClientConfig) Build() (proto.Message, error) {
|
|||||||
user.Email = v.Email
|
user.Email = v.Email
|
||||||
} else {
|
} else {
|
||||||
if err := json.Unmarshal(rawUser, user); err != nil {
|
if err := json.Unmarshal(rawUser, user); err != nil {
|
||||||
return nil, errors.New("failed to parse HTTP user").Base(err).AtError()
|
return nil, errors.New("failed to parse HTTP user").Base(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
account := new(HTTPAccount)
|
account := new(HTTPAccount)
|
||||||
@@ -106,7 +106,7 @@ func (v *HTTPClientConfig) Build() (proto.Message, error) {
|
|||||||
account.Password = v.Password
|
account.Password = v.Password
|
||||||
} else {
|
} else {
|
||||||
if err := json.Unmarshal(rawUser, account); err != nil {
|
if err := json.Unmarshal(rawUser, account); err != nil {
|
||||||
return nil, errors.New("failed to parse HTTP account").Base(err).AtError()
|
return nil, errors.New("failed to parse HTTP account").Base(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
user.Account = serial.ToTypedMessage(account.Build())
|
user.Account = serial.ToTypedMessage(account.Build())
|
||||||
|
|||||||
+1
-1
@@ -18,7 +18,7 @@ func RegisterConfigureFilePostProcessingStage(name string, stage ConfigureFilePo
|
|||||||
func PostProcessConfigureFile(conf *Config) error {
|
func PostProcessConfigureFile(conf *Config) error {
|
||||||
for k, v := range configureFilePostProcessingStages {
|
for k, v := range configureFilePostProcessingStages {
|
||||||
if err := v.Process(conf); err != nil {
|
if err := v.Process(conf); err != nil {
|
||||||
return errors.New("Rejected by Postprocessing Stage ", k).AtError().Base(err)
|
return errors.New("Rejected by Postprocessing Stage ", k).Base(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ type ConfigCreatorCache map[string]ConfigCreator
|
|||||||
|
|
||||||
func (v ConfigCreatorCache) RegisterCreator(id string, creator ConfigCreator) error {
|
func (v ConfigCreatorCache) RegisterCreator(id string, creator ConfigCreator) error {
|
||||||
if _, found := v[id]; found {
|
if _, found := v[id]; found {
|
||||||
return errors.New(id, " already registered.").AtError()
|
return errors.New(id, " already registered.")
|
||||||
}
|
}
|
||||||
|
|
||||||
v[id] = creator
|
v[id] = creator
|
||||||
@@ -61,7 +61,7 @@ func (v *JSONConfigLoader) Load(raw []byte) (interface{}, string, error) {
|
|||||||
}
|
}
|
||||||
rawID, found := obj[v.idKey]
|
rawID, found := obj[v.idKey]
|
||||||
if !found {
|
if !found {
|
||||||
return nil, "", errors.New(v.idKey, " not found in JSON context").AtError()
|
return nil, "", errors.New(v.idKey, " not found in JSON context")
|
||||||
}
|
}
|
||||||
var id string
|
var id string
|
||||||
if err := json.Unmarshal(rawID, &id); err != nil {
|
if err := json.Unmarshal(rawID, &id); err != nil {
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ func MergeConfigFromFiles(files []*core.ConfigSource) (string, error) {
|
|||||||
if j, ok := creflect.MarshalToJson(c, true); ok {
|
if j, ok := creflect.MarshalToJson(c, true); ok {
|
||||||
return j, nil
|
return j, nil
|
||||||
}
|
}
|
||||||
return "", errors.New("marshal to json failed.").AtError()
|
return "", errors.New("marshal to json failed.")
|
||||||
}
|
}
|
||||||
|
|
||||||
func mergeConfigs(files []*core.ConfigSource) (*conf.Config, error) {
|
func mergeConfigs(files []*core.ConfigSource) (*conf.Config, error) {
|
||||||
|
|||||||
+2
-3
@@ -44,7 +44,6 @@ func (v *SocksServerConfig) Build() (proto.Message, error) {
|
|||||||
case AuthMethodUserPass:
|
case AuthMethodUserPass:
|
||||||
config.AuthType = socks.AuthType_PASSWORD
|
config.AuthType = socks.AuthType_PASSWORD
|
||||||
default:
|
default:
|
||||||
// errors.New("unknown socks auth method: ", v.AuthMethod, ". Default to noauth.").AtWarning().WriteToLog()
|
|
||||||
config.AuthType = socks.AuthType_NO_AUTH
|
config.AuthType = socks.AuthType_NO_AUTH
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,7 +114,7 @@ func (v *SocksClientConfig) Build() (proto.Message, error) {
|
|||||||
user.Email = v.Email
|
user.Email = v.Email
|
||||||
} else {
|
} else {
|
||||||
if err := json.Unmarshal(rawUser, user); err != nil {
|
if err := json.Unmarshal(rawUser, user); err != nil {
|
||||||
return nil, errors.New("failed to parse Socks user").Base(err).AtError()
|
return nil, errors.New("failed to parse Socks user").Base(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
account := new(SocksAccount)
|
account := new(SocksAccount)
|
||||||
@@ -124,7 +123,7 @@ func (v *SocksClientConfig) Build() (proto.Message, error) {
|
|||||||
account.Password = v.Password
|
account.Password = v.Password
|
||||||
} else {
|
} else {
|
||||||
if err := json.Unmarshal(rawUser, account); err != nil {
|
if err := json.Unmarshal(rawUser, account); err != nil {
|
||||||
return nil, errors.New("failed to parse socks account").Base(err).AtError()
|
return nil, errors.New("failed to parse socks account").Base(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
user.Account = serial.ToTypedMessage(account.Build())
|
user.Account = serial.ToTypedMessage(account.Build())
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import (
|
|||||||
googleuuid "github.com/google/uuid"
|
googleuuid "github.com/google/uuid"
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
|
"github.com/xtls/xray-core/transport/internet"
|
||||||
"github.com/xtls/xray-core/transport/internet/finalmask/fragment"
|
"github.com/xtls/xray-core/transport/internet/finalmask/fragment"
|
||||||
"github.com/xtls/xray-core/transport/internet/finalmask/header/custom"
|
"github.com/xtls/xray-core/transport/internet/finalmask/header/custom"
|
||||||
"github.com/xtls/xray-core/transport/internet/finalmask/mkcp/aes128gcm"
|
"github.com/xtls/xray-core/transport/internet/finalmask/mkcp/aes128gcm"
|
||||||
@@ -23,6 +24,7 @@ import (
|
|||||||
"github.com/xtls/xray-core/transport/internet/finalmask/realm"
|
"github.com/xtls/xray-core/transport/internet/finalmask/realm"
|
||||||
"github.com/xtls/xray-core/transport/internet/finalmask/salamander"
|
"github.com/xtls/xray-core/transport/internet/finalmask/salamander"
|
||||||
"github.com/xtls/xray-core/transport/internet/finalmask/sudoku"
|
"github.com/xtls/xray-core/transport/internet/finalmask/sudoku"
|
||||||
|
"github.com/xtls/xray-core/transport/internet/finalmask/udphop"
|
||||||
"github.com/xtls/xray-core/transport/internet/finalmask/xdns"
|
"github.com/xtls/xray-core/transport/internet/finalmask/xdns"
|
||||||
"github.com/xtls/xray-core/transport/internet/finalmask/xicmp"
|
"github.com/xtls/xray-core/transport/internet/finalmask/xicmp"
|
||||||
"github.com/xtls/xray-core/transport/internet/finalmask/xmc"
|
"github.com/xtls/xray-core/transport/internet/finalmask/xmc"
|
||||||
@@ -83,6 +85,7 @@ var (
|
|||||||
"xdns": func() interface{} { return new(Xdns) },
|
"xdns": func() interface{} { return new(Xdns) },
|
||||||
"xicmp": func() interface{} { return new(Xicmp) },
|
"xicmp": func() interface{} { return new(Xicmp) },
|
||||||
"realm": func() interface{} { return new(Realm) },
|
"realm": func() interface{} { return new(Realm) },
|
||||||
|
"udphop": func() interface{} { return new(UDPHop) },
|
||||||
}, "type", "settings")
|
}, "type", "settings")
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -905,6 +908,62 @@ func (c *Realm) Build() (proto.Message, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UDPHop struct {
|
||||||
|
Sockopt *SocketConfig `json:"sockopt"`
|
||||||
|
Mode string `json:"mode"`
|
||||||
|
Interval Int32Range `json:"interval"`
|
||||||
|
RemotePorts PortList `json:"remotePorts"`
|
||||||
|
RemoteIPs []string `json:"remoteIPs"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *UDPHop) Build() (proto.Message, error) {
|
||||||
|
var sockopt *internet.SocketConfig
|
||||||
|
if c.Sockopt != nil {
|
||||||
|
var err error
|
||||||
|
sockopt, err = c.Sockopt.Build()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var local, remote, remoteOnce bool
|
||||||
|
for _, mode := range strings.Split(c.Mode, ",") {
|
||||||
|
switch strings.ToLower(mode) {
|
||||||
|
case "intervallocal":
|
||||||
|
local = true
|
||||||
|
case "intervalremote":
|
||||||
|
remote = true
|
||||||
|
case "perconnremote":
|
||||||
|
remoteOnce = true
|
||||||
|
default:
|
||||||
|
return nil, errors.New("invalid mode ", mode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var remoteIPs []string
|
||||||
|
for _, ip := range c.RemoteIPs {
|
||||||
|
prefix, err := netip.ParsePrefix(ip)
|
||||||
|
if err == nil {
|
||||||
|
remoteIPs = append(remoteIPs, prefix.String())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
addr, err := netip.ParseAddr(ip)
|
||||||
|
if err == nil {
|
||||||
|
remoteIPs = append(remoteIPs, netip.PrefixFrom(addr, addr.BitLen()).String())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return nil, errors.New("invalid ip ", ip)
|
||||||
|
}
|
||||||
|
return &udphop.Config{
|
||||||
|
Sockopt: sockopt,
|
||||||
|
Local: local,
|
||||||
|
Remote: remote,
|
||||||
|
RemoteOnce: remoteOnce,
|
||||||
|
IntervalMin: int64(c.Interval.From),
|
||||||
|
IntervalMax: int64(c.Interval.To),
|
||||||
|
RemotePorts: c.RemotePorts.Build().Ports(),
|
||||||
|
RemoteIPs: remoteIPs,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
type Mask struct {
|
type Mask struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Settings *json.RawMessage `json:"settings"`
|
Settings *json.RawMessage `json:"settings"`
|
||||||
@@ -938,7 +997,6 @@ type QuicParamsConfig struct {
|
|||||||
BrutalUp Bandwidth `json:"brutalUp"`
|
BrutalUp Bandwidth `json:"brutalUp"`
|
||||||
BrutalDown Bandwidth `json:"brutalDown"`
|
BrutalDown Bandwidth `json:"brutalDown"`
|
||||||
BrutalDisableLossCompensation bool `json:"brutalDisableLossCompensation"`
|
BrutalDisableLossCompensation bool `json:"brutalDisableLossCompensation"`
|
||||||
UdpHop UdpHop `json:"udpHop"`
|
|
||||||
InitStreamReceiveWindow uint64 `json:"initStreamReceiveWindow"`
|
InitStreamReceiveWindow uint64 `json:"initStreamReceiveWindow"`
|
||||||
MaxStreamReceiveWindow uint64 `json:"maxStreamReceiveWindow"`
|
MaxStreamReceiveWindow uint64 `json:"maxStreamReceiveWindow"`
|
||||||
InitConnectionReceiveWindow uint64 `json:"initConnectionReceiveWindow"`
|
InitConnectionReceiveWindow uint64 `json:"initConnectionReceiveWindow"`
|
||||||
|
|||||||
@@ -253,10 +253,6 @@ func (c *StreamConfig) Build() (*internet.StreamConfig, error) {
|
|||||||
return nil, errors.New("unknown congestion control: ", c.FinalMask.QuicParams.Congestion, ", valid values: reno, bbr, brutal, force-brutal")
|
return nil, errors.New("unknown congestion control: ", c.FinalMask.QuicParams.Congestion, ", valid values: reno, bbr, brutal, force-brutal")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c.FinalMask.QuicParams.UdpHop.Interval.From != 0 && c.FinalMask.QuicParams.UdpHop.Interval.From < 5) || (c.FinalMask.QuicParams.UdpHop.Interval.To != 0 && c.FinalMask.QuicParams.UdpHop.Interval.To < 5) {
|
|
||||||
return nil, errors.New("Interval must be at least 5")
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.FinalMask.QuicParams.InitStreamReceiveWindow > 0 && c.FinalMask.QuicParams.InitStreamReceiveWindow < 16384 {
|
if c.FinalMask.QuicParams.InitStreamReceiveWindow > 0 && c.FinalMask.QuicParams.InitStreamReceiveWindow < 16384 {
|
||||||
return nil, errors.New("InitStreamReceiveWindow must be at least 16384")
|
return nil, errors.New("InitStreamReceiveWindow must be at least 16384")
|
||||||
}
|
}
|
||||||
@@ -290,43 +286,20 @@ func (c *StreamConfig) Build() (*internet.StreamConfig, error) {
|
|||||||
BrutalUp: up,
|
BrutalUp: up,
|
||||||
BrutalDown: down,
|
BrutalDown: down,
|
||||||
BrutalDisableLossCompensation: c.FinalMask.QuicParams.BrutalDisableLossCompensation,
|
BrutalDisableLossCompensation: c.FinalMask.QuicParams.BrutalDisableLossCompensation,
|
||||||
UdpHop: &internet.UdpHop{
|
InitStreamReceiveWindow: c.FinalMask.QuicParams.InitStreamReceiveWindow,
|
||||||
Ports: c.FinalMask.QuicParams.UdpHop.PortList.Build().Ports(),
|
MaxStreamReceiveWindow: c.FinalMask.QuicParams.MaxStreamReceiveWindow,
|
||||||
IntervalMin: int64(c.FinalMask.QuicParams.UdpHop.Interval.From),
|
InitConnReceiveWindow: c.FinalMask.QuicParams.InitConnectionReceiveWindow,
|
||||||
IntervalMax: int64(c.FinalMask.QuicParams.UdpHop.Interval.To),
|
MaxConnReceiveWindow: c.FinalMask.QuicParams.MaxConnectionReceiveWindow,
|
||||||
},
|
MaxIdleTimeout: c.FinalMask.QuicParams.MaxIdleTimeout,
|
||||||
InitStreamReceiveWindow: c.FinalMask.QuicParams.InitStreamReceiveWindow,
|
KeepAlivePeriod: c.FinalMask.QuicParams.KeepAlivePeriod,
|
||||||
MaxStreamReceiveWindow: c.FinalMask.QuicParams.MaxStreamReceiveWindow,
|
DisablePathMtuDiscovery: c.FinalMask.QuicParams.DisablePathMTUDiscovery,
|
||||||
InitConnReceiveWindow: c.FinalMask.QuicParams.InitConnectionReceiveWindow,
|
DisableChromeParrot: c.FinalMask.QuicParams.DisableChromeParrot,
|
||||||
MaxConnReceiveWindow: c.FinalMask.QuicParams.MaxConnectionReceiveWindow,
|
DisableGSO: c.FinalMask.QuicParams.DisableGSO,
|
||||||
MaxIdleTimeout: c.FinalMask.QuicParams.MaxIdleTimeout,
|
MaxIncomingStreams: c.FinalMask.QuicParams.MaxIncomingStreams,
|
||||||
KeepAlivePeriod: c.FinalMask.QuicParams.KeepAlivePeriod,
|
DisableStatelessReset: c.FinalMask.QuicParams.DisableStatelessReset,
|
||||||
DisablePathMtuDiscovery: c.FinalMask.QuicParams.DisablePathMTUDiscovery,
|
|
||||||
DisableChromeParrot: c.FinalMask.QuicParams.DisableChromeParrot,
|
|
||||||
DisableGSO: c.FinalMask.QuicParams.DisableGSO,
|
|
||||||
MaxIncomingStreams: c.FinalMask.QuicParams.MaxIncomingStreams,
|
|
||||||
DisableStatelessReset: c.FinalMask.QuicParams.DisableStatelessReset,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return config, nil
|
return config, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProxyConfig struct {
|
|
||||||
Tag string `json:"tag"`
|
|
||||||
|
|
||||||
// TransportLayerProxy: For compatibility.
|
|
||||||
TransportLayerProxy bool `json:"transportLayer"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build implements Buildable.
|
|
||||||
func (v *ProxyConfig) Build() (*internet.ProxyConfig, error) {
|
|
||||||
if v.Tag == "" {
|
|
||||||
return nil, errors.New("Proxy tag is not set.")
|
|
||||||
}
|
|
||||||
return &internet.ProxyConfig{
|
|
||||||
Tag: v.Tag,
|
|
||||||
TransportLayerProxy: v.TransportLayerProxy,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package conf
|
package conf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"math/big"
|
"math/big"
|
||||||
"net/url"
|
"net/url"
|
||||||
@@ -122,7 +121,7 @@ func (v *AuthenticatorRequest) Build() (*http.RequestConfig, error) {
|
|||||||
for _, key := range headerNames {
|
for _, key := range headerNames {
|
||||||
value := v.Headers[key]
|
value := v.Headers[key]
|
||||||
if value == nil {
|
if value == nil {
|
||||||
return nil, errors.New("empty HTTP header value: " + key).AtError()
|
return nil, errors.New("empty HTTP header value: " + key)
|
||||||
}
|
}
|
||||||
config.Header = append(config.Header, &http.Header{
|
config.Header = append(config.Header, &http.Header{
|
||||||
Name: key,
|
Name: key,
|
||||||
@@ -190,7 +189,7 @@ func (v *AuthenticatorResponse) Build() (*http.ResponseConfig, error) {
|
|||||||
for _, key := range headerNames {
|
for _, key := range headerNames {
|
||||||
value := v.Headers[key]
|
value := v.Headers[key]
|
||||||
if value == nil {
|
if value == nil {
|
||||||
return nil, errors.New("empty HTTP header value: " + key).AtError()
|
return nil, errors.New("empty HTTP header value: " + key)
|
||||||
}
|
}
|
||||||
config.Header = append(config.Header, &http.Header{
|
config.Header = append(config.Header, &http.Header{
|
||||||
Name: key,
|
Name: key,
|
||||||
@@ -240,11 +239,11 @@ func (c *TCPConfig) Build() (proto.Message, error) {
|
|||||||
if len(c.HeaderConfig) > 0 {
|
if len(c.HeaderConfig) > 0 {
|
||||||
headerConfig, _, err := tcpHeaderLoader.Load(c.HeaderConfig)
|
headerConfig, _, err := tcpHeaderLoader.Load(c.HeaderConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("invalid TCP header config").Base(err).AtError()
|
return nil, errors.New("invalid TCP header config").Base(err)
|
||||||
}
|
}
|
||||||
ts, err := headerConfig.(Buildable).Build()
|
ts, err := headerConfig.(Buildable).Build()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("invalid TCP header config").Base(err).AtError()
|
return nil, errors.New("invalid TCP header config").Base(err)
|
||||||
}
|
}
|
||||||
config.HeaderSettings = serial.ToTypedMessage(ts)
|
config.HeaderSettings = serial.ToTypedMessage(ts)
|
||||||
}
|
}
|
||||||
@@ -534,10 +533,6 @@ type KCPConfig struct {
|
|||||||
|
|
||||||
// Build implements Buildable.
|
// Build implements Buildable.
|
||||||
func (c *KCPConfig) Build() (proto.Message, error) {
|
func (c *KCPConfig) Build() (proto.Message, error) {
|
||||||
if c.HeaderConfig != nil || c.Seed != nil {
|
|
||||||
return nil, errors.PrintRemovedFeatureError("mkcp header & seed", "finalmask/udp header-* & mkcp-original & mkcp-aes128gcm")
|
|
||||||
}
|
|
||||||
|
|
||||||
config := common.Must2(internet.CreateTransportConfig(kcp.ProtocolName)).(*kcp.Config)
|
config := common.Must2(internet.CreateTransportConfig(kcp.ProtocolName)).(*kcp.Config)
|
||||||
|
|
||||||
if c.Mtu != nil {
|
if c.Mtu != nil {
|
||||||
@@ -560,16 +555,16 @@ func (c *KCPConfig) Build() (proto.Message, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if config.Mtu < 21 {
|
if config.Mtu < 21 {
|
||||||
return nil, errors.New("Mtu must be at least 21").AtError()
|
return nil, errors.New("MTU must be at least 21")
|
||||||
}
|
}
|
||||||
if config.Tti < 10 || config.Tti > 1000 {
|
if config.Tti < 10 || config.Tti > 1000 {
|
||||||
return nil, errors.New("invalid mKCP TTI: ", c.Tti).AtError()
|
return nil, errors.New("TTI must be between 10 and 1000")
|
||||||
}
|
}
|
||||||
if config.CwndMultiplier < 1 {
|
if config.CwndMultiplier < 1 {
|
||||||
return nil, errors.New("CwndMultiplier must be at least 1").AtError()
|
return nil, errors.New("CwndMultiplier must be at least 1")
|
||||||
}
|
}
|
||||||
if config.GetSendingBufferSize() == 0 {
|
if config.GetSendingBufferSize() == 0 {
|
||||||
return nil, errors.New("MaxSendingWindow must be >= Mtu").AtError()
|
return nil, errors.New("MaxSendingWindow must be at least ", config.Mtu)
|
||||||
}
|
}
|
||||||
|
|
||||||
return config, nil
|
return config, nil
|
||||||
@@ -739,11 +734,6 @@ func (b Bandwidth) Bps() (uint64, error) {
|
|||||||
return uint64(val*float64(mul)) / 8, nil
|
return uint64(val*float64(mul)) / 8, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type UdpHop struct {
|
|
||||||
PortList PortList `json:"ports"`
|
|
||||||
Interval Int32Range `json:"interval"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Masquerade struct {
|
type Masquerade struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
|
|
||||||
@@ -760,14 +750,8 @@ type Masquerade struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type HysteriaConfig struct {
|
type HysteriaConfig struct {
|
||||||
Version int32 `json:"version"`
|
Version int32 `json:"version"`
|
||||||
Auth string `json:"auth"`
|
Auth string `json:"auth"`
|
||||||
|
|
||||||
Congestion *string `json:"congestion"`
|
|
||||||
Up *Bandwidth `json:"up"`
|
|
||||||
Down *Bandwidth `json:"down"`
|
|
||||||
UdpHop *UdpHop `json:"udphop"`
|
|
||||||
|
|
||||||
UdpIdleTimeout int64 `json:"udpIdleTimeout"`
|
UdpIdleTimeout int64 `json:"udpIdleTimeout"`
|
||||||
Masquerade Masquerade `json:"masquerade"`
|
Masquerade Masquerade `json:"masquerade"`
|
||||||
}
|
}
|
||||||
@@ -777,10 +761,6 @@ func (c *HysteriaConfig) Build() (proto.Message, error) {
|
|||||||
return nil, errors.New("version != 2")
|
return nil, errors.New("version != 2")
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.Congestion != nil || c.Up != nil || c.Down != nil || c.UdpHop != nil {
|
|
||||||
errors.LogWarning(context.Background(), "congestion & up & down & udphop move to finalmask/quicParams")
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.UdpIdleTimeout != 0 && (c.UdpIdleTimeout < 2 || c.UdpIdleTimeout > 600) {
|
if c.UdpIdleTimeout != 0 && (c.UdpIdleTimeout < 2 || c.UdpIdleTimeout > 600) {
|
||||||
return nil, errors.New("UdpIdleTimeout must be between 2 and 600")
|
return nil, errors.New("UdpIdleTimeout must be between 2 and 600")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,10 +113,10 @@ func (c *REALITYConfig) Build() (proto.Message, error) {
|
|||||||
config.MinClientVer[i] = byte(u)
|
config.MinClientVer[i] = byte(u)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
errors.LogWarning(context.Background(), `REALITY: Changing "minClientVer" will increase the likelihood of your server's IP being blocked by the GFW`)
|
// errors.LogWarning(context.Background(), `REALITY: Changing "minClientVer" will increase the likelihood of your server's IP being blocked by the GFW`)
|
||||||
} else {
|
} else {
|
||||||
config.MinClientVer = []byte{26, 3, 27} // change it at your own risk: https://github.com/XTLS/Xray-core/commit/af7eb68028732a8ee3c0e5d6ab2b8a657bb2e770
|
// config.MinClientVer = []byte{26, 3, 27} // change it at your own risk: https://github.com/XTLS/Xray-core/commit/af7eb68028732a8ee3c0e5d6ab2b8a657bb2e770
|
||||||
errors.LogWarning(context.Background(), `REALITY: The default minimal client version is Xray-core v26.3.27, other clients may be refused to connect`)
|
// errors.LogWarning(context.Background(), `REALITY: The default minimal client version is Xray-core v26.3.27, other clients may be refused to connect`)
|
||||||
}
|
}
|
||||||
if c.MaxClientVer != "" {
|
if c.MaxClientVer != "" {
|
||||||
config.MaxClientVer = make([]byte, 3)
|
config.MaxClientVer = make([]byte, 3)
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type CustomSockoptConfig struct {
|
type CustomSockoptConfig struct {
|
||||||
Syetem string `json:"system"`
|
System string `json:"system"`
|
||||||
Network string `json:"network"`
|
Network string `json:"network"`
|
||||||
Level string `json:"level"`
|
Level string `json:"level"`
|
||||||
Opt string `json:"opt"`
|
Opt string `json:"opt"`
|
||||||
@@ -124,7 +124,7 @@ func (c *SocketConfig) Build() (*internet.SocketConfig, error) {
|
|||||||
|
|
||||||
for _, copt := range c.CustomSockopt {
|
for _, copt := range c.CustomSockopt {
|
||||||
customSockopt := &internet.CustomSockopt{
|
customSockopt := &internet.CustomSockopt{
|
||||||
System: copt.Syetem,
|
System: copt.System,
|
||||||
Network: copt.Network,
|
Network: copt.Network,
|
||||||
Level: copt.Level,
|
Level: copt.Level,
|
||||||
Opt: copt.Opt,
|
Opt: copt.Opt,
|
||||||
|
|||||||
@@ -312,6 +312,9 @@ func (c *VLessOutboundConfig) Build() (proto.Message, error) {
|
|||||||
if err := json.Unmarshal(rawUser, account); err != nil {
|
if err := json.Unmarshal(rawUser, account); err != nil {
|
||||||
return nil, errors.New(`VLESS users: invalid user`).Base(err)
|
return nil, errors.New(`VLESS users: invalid user`).Base(err)
|
||||||
}
|
}
|
||||||
|
// validateOutboundTransportSecurity needs to see these
|
||||||
|
c.Encryption = account.Encryption
|
||||||
|
c.Address = rec.Address
|
||||||
if account.Reverse != nil { // may not be reached: error json unmarshal
|
if account.Reverse != nil { // may not be reached: error json unmarshal
|
||||||
return nil, errors.New(`VLESS users: please use simplified outbound's config style to use "reverse"`)
|
return nil, errors.New(`VLESS users: please use simplified outbound's config style to use "reverse"`)
|
||||||
}
|
}
|
||||||
|
|||||||
+32
-35
@@ -15,6 +15,7 @@ import (
|
|||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/serial"
|
"github.com/xtls/xray-core/common/serial"
|
||||||
core "github.com/xtls/xray-core/core"
|
core "github.com/xtls/xray-core/core"
|
||||||
|
"github.com/xtls/xray-core/proxy/freedom"
|
||||||
"github.com/xtls/xray-core/transport/internet"
|
"github.com/xtls/xray-core/transport/internet"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -216,21 +217,11 @@ type OutboundDetourConfig struct {
|
|||||||
Tag string `json:"tag"`
|
Tag string `json:"tag"`
|
||||||
Settings *json.RawMessage `json:"settings"`
|
Settings *json.RawMessage `json:"settings"`
|
||||||
StreamSetting *StreamConfig `json:"streamSettings"`
|
StreamSetting *StreamConfig `json:"streamSettings"`
|
||||||
ProxySettings *ProxyConfig `json:"proxySettings"`
|
ProxySettings *json.RawMessage `json:"proxySettings"`
|
||||||
MuxSettings *MuxConfig `json:"mux"`
|
MuxSettings *MuxConfig `json:"mux"`
|
||||||
TargetStrategy string `json:"targetStrategy"`
|
TargetStrategy string `json:"targetStrategy"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *OutboundDetourConfig) checkChainProxyConfig() error {
|
|
||||||
if c.StreamSetting == nil || c.ProxySettings == nil || c.StreamSetting.SocketSettings == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if len(c.ProxySettings.Tag) > 0 && len(c.StreamSetting.SocketSettings.DialerProxy) > 0 {
|
|
||||||
return errors.New("proxySettings.tag is conflicted with sockopt.dialerProxy").AtWarning()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func requiresTransportSecurity(address *Address) bool {
|
func requiresTransportSecurity(address *Address) bool {
|
||||||
if address == nil || address.Address == nil {
|
if address == nil || address.Address == nil {
|
||||||
return false
|
return false
|
||||||
@@ -251,7 +242,7 @@ func validateOutboundTransportSecurity(rawConfig interface{}, senderSettings *pr
|
|||||||
if vlessCfg.Encryption != "" && vlessCfg.Encryption != "none" {
|
if vlessCfg.Encryption != "" && vlessCfg.Encryption != "none" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if requiresTransportSecurity(vlessCfg.Vnext[0].Address) {
|
if requiresTransportSecurity(vlessCfg.Address) {
|
||||||
return errors.New("vless without TLS or other encryption is prohibited unless the server address is a private IP or domain")
|
return errors.New("vless without TLS or other encryption is prohibited unless the server address is a private IP or domain")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -267,6 +258,10 @@ func validateOutboundTransportSecurity(rawConfig interface{}, senderSettings *pr
|
|||||||
|
|
||||||
// Build implements Buildable.
|
// Build implements Buildable.
|
||||||
func (c *OutboundDetourConfig) Build() (*core.OutboundHandlerConfig, error) {
|
func (c *OutboundDetourConfig) Build() (*core.OutboundHandlerConfig, error) {
|
||||||
|
if c.ProxySettings != nil {
|
||||||
|
return nil, errors.PrintRemovedFeatureError(`outbound "proxySettings"`, `"streamSettings.sockopt.dialerProxy"`)
|
||||||
|
}
|
||||||
|
|
||||||
senderSettings := &proxyman.SenderConfig{}
|
senderSettings := &proxyman.SenderConfig{}
|
||||||
switch strings.ToLower(c.TargetStrategy) {
|
switch strings.ToLower(c.TargetStrategy) {
|
||||||
case "asis", "":
|
case "asis", "":
|
||||||
@@ -294,9 +289,6 @@ func (c *OutboundDetourConfig) Build() (*core.OutboundHandlerConfig, error) {
|
|||||||
default:
|
default:
|
||||||
return nil, errors.New("unsupported target domain strategy: ", c.TargetStrategy)
|
return nil, errors.New("unsupported target domain strategy: ", c.TargetStrategy)
|
||||||
}
|
}
|
||||||
if err := c.checkChainProxyConfig(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.SendThrough != nil {
|
if c.SendThrough != nil {
|
||||||
address := ParseSendThough(c.SendThrough)
|
address := ParseSendThough(c.SendThrough)
|
||||||
@@ -322,26 +314,6 @@ func (c *OutboundDetourConfig) Build() (*core.OutboundHandlerConfig, error) {
|
|||||||
senderSettings.StreamSettings = ss
|
senderSettings.StreamSettings = ss
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.ProxySettings != nil {
|
|
||||||
ps, err := c.ProxySettings.Build()
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("invalid outbound detour proxy settings").Base(err)
|
|
||||||
}
|
|
||||||
if ps.TransportLayerProxy {
|
|
||||||
if senderSettings.StreamSettings != nil {
|
|
||||||
if senderSettings.StreamSettings.SocketSettings != nil {
|
|
||||||
senderSettings.StreamSettings.SocketSettings.DialerProxy = ps.Tag
|
|
||||||
} else {
|
|
||||||
senderSettings.StreamSettings.SocketSettings = &internet.SocketConfig{DialerProxy: ps.Tag}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
senderSettings.StreamSettings = &internet.StreamConfig{SocketSettings: &internet.SocketConfig{DialerProxy: ps.Tag}}
|
|
||||||
}
|
|
||||||
ps = nil
|
|
||||||
}
|
|
||||||
senderSettings.ProxySettings = ps
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.MuxSettings != nil {
|
if c.MuxSettings != nil {
|
||||||
ms, err := c.MuxSettings.Build()
|
ms, err := c.MuxSettings.Build()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -366,6 +338,31 @@ func (c *OutboundDetourConfig) Build() (*core.OutboundHandlerConfig, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if fc, ok := ts.(*freedom.Config); ok {
|
||||||
|
if senderSettings.StreamSettings != nil &&
|
||||||
|
senderSettings.StreamSettings.SocketSettings != nil &&
|
||||||
|
senderSettings.StreamSettings.SocketSettings.AddressPortStrategy != internet.AddressPortStrategy_None {
|
||||||
|
return nil, errors.New(`freedom outbound does not support "sockopt.addressPortStrategy"`)
|
||||||
|
}
|
||||||
|
|
||||||
|
var strategy internet.DomainStrategy
|
||||||
|
if strategy = senderSettings.TargetStrategy; strategy != internet.DomainStrategy_AS_IS {
|
||||||
|
errors.LogWarning(context.Background(), `The "outbound.targetStrategy" setting is not supported directly by freedom and has been automatically migrated to "sockopt.domainStrategy" with no behavior change.`)
|
||||||
|
senderSettings.TargetStrategy = internet.DomainStrategy_AS_IS
|
||||||
|
} else if strategy = fc.DomainStrategy; strategy != internet.DomainStrategy_AS_IS {
|
||||||
|
errors.LogWarning(context.Background(), `The "freedom.domainStrategy" setting is deprecated and will be removed. For compatibility, its value has been automatically migrated to "sockopt.domainStrategy". Please update your config before removal.`)
|
||||||
|
}
|
||||||
|
if strategy != internet.DomainStrategy_AS_IS {
|
||||||
|
if senderSettings.StreamSettings == nil {
|
||||||
|
senderSettings.StreamSettings = &internet.StreamConfig{}
|
||||||
|
}
|
||||||
|
if senderSettings.StreamSettings.SocketSettings == nil {
|
||||||
|
senderSettings.StreamSettings.SocketSettings = &internet.SocketConfig{}
|
||||||
|
}
|
||||||
|
senderSettings.StreamSettings.SocketSettings.DomainStrategy = strategy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return &core.OutboundHandlerConfig{
|
return &core.OutboundHandlerConfig{
|
||||||
SenderSettings: serial.ToTypedMessage(senderSettings),
|
SenderSettings: serial.ToTypedMessage(senderSettings),
|
||||||
Tag: c.Tag,
|
Tag: c.Tag,
|
||||||
|
|||||||
+273
-139
@@ -1,15 +1,18 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"bytes"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"go/build"
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
|
||||||
|
"mvdan.cc/gofumpt/format"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -23,101 +26,27 @@ var (
|
|||||||
isFormat bool
|
isFormat bool
|
||||||
)
|
)
|
||||||
|
|
||||||
// envFile returns the name of the Go environment configuration file.
|
func getModuleInfo(pwd string) (modPath, langVersion string, err error) {
|
||||||
// Copy from https://github.com/golang/go/blob/c4f2a9788a7be04daf931ac54382fbe2cb754938/src/cmd/go/internal/cfg/cfg.go#L150-L166
|
data, err := os.ReadFile(filepath.Join(pwd, "go.mod"))
|
||||||
func envFile() (string, error) {
|
|
||||||
if file := os.Getenv("GOENV"); file != "" {
|
|
||||||
if file == "off" {
|
|
||||||
return "", errors.New("GOENV=off")
|
|
||||||
}
|
|
||||||
return file, nil
|
|
||||||
}
|
|
||||||
dir, err := os.UserConfigDir()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", "", err
|
||||||
}
|
}
|
||||||
if dir == "" {
|
for _, line := range strings.Split(string(data), "\n") {
|
||||||
return "", errors.New("missing user-config dir")
|
fields := strings.Fields(line)
|
||||||
}
|
if len(fields) >= 2 {
|
||||||
return filepath.Join(dir, "go", "env"), nil
|
switch fields[0] {
|
||||||
}
|
case "module":
|
||||||
|
modPath = fields[1]
|
||||||
// GetRuntimeEnv returns the value of runtime environment variable,
|
case "go":
|
||||||
// that is set by running following command: `go env -w key=value`.
|
langVersion = "go" + strings.TrimPrefix(fields[1], "go")
|
||||||
func GetRuntimeEnv(key string) (string, error) {
|
|
||||||
file, err := envFile()
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
if file == "" {
|
|
||||||
return "", errors.New("missing runtime env file")
|
|
||||||
}
|
|
||||||
var data []byte
|
|
||||||
var runtimeEnv string
|
|
||||||
data, readErr := os.ReadFile(file)
|
|
||||||
if readErr != nil {
|
|
||||||
return "", readErr
|
|
||||||
}
|
|
||||||
envStrings := strings.Split(string(data), "\n")
|
|
||||||
for _, envItem := range envStrings {
|
|
||||||
envItem = strings.TrimSuffix(envItem, "\r")
|
|
||||||
envKeyValue := strings.Split(envItem, "=")
|
|
||||||
if len(envKeyValue) == 2 && strings.TrimSpace(envKeyValue[0]) == key {
|
|
||||||
runtimeEnv = strings.TrimSpace(envKeyValue[1])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return runtimeEnv, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetGOBIN returns GOBIN environment variable as a string. It will NOT be empty.
|
|
||||||
func GetGOBIN() string {
|
|
||||||
// The one set by user explicitly by `export GOBIN=/path` or `env GOBIN=/path command`
|
|
||||||
GOBIN := os.Getenv("GOBIN")
|
|
||||||
if GOBIN == "" {
|
|
||||||
var err error
|
|
||||||
// The one set by user by running `go env -w GOBIN=/path`
|
|
||||||
GOBIN, err = GetRuntimeEnv("GOBIN")
|
|
||||||
if err != nil {
|
|
||||||
// The default one that Golang uses
|
|
||||||
return filepath.Join(build.Default.GOPATH, "bin")
|
|
||||||
}
|
|
||||||
if GOBIN == "" {
|
|
||||||
return filepath.Join(build.Default.GOPATH, "bin")
|
|
||||||
}
|
|
||||||
return GOBIN
|
|
||||||
}
|
|
||||||
return GOBIN
|
|
||||||
}
|
|
||||||
|
|
||||||
func Run(binary string, args []string) ([]byte, error) {
|
|
||||||
cmd := exec.Command(binary, args...)
|
|
||||||
cmd.Env = append(cmd.Env, os.Environ()...)
|
|
||||||
output, cmdErr := cmd.CombinedOutput()
|
|
||||||
if cmdErr != nil {
|
|
||||||
return nil, cmdErr
|
|
||||||
}
|
|
||||||
return output, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func RunMany(binary string, args, files []string) bool {
|
|
||||||
fmt.Println("Processing with", binary, args, "...")
|
|
||||||
|
|
||||||
formatRequired := false
|
|
||||||
maxTasks := make(chan struct{}, runtime.NumCPU())
|
|
||||||
for _, file := range files {
|
|
||||||
maxTasks <- struct{}{}
|
|
||||||
go func(file string) {
|
|
||||||
output, err := Run(binary, append(args, file))
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
} else if len(output) > 0 {
|
|
||||||
fmt.Println(string(output))
|
|
||||||
formatRequired = true
|
|
||||||
}
|
}
|
||||||
<-maxTasks
|
}
|
||||||
}(file)
|
|
||||||
}
|
}
|
||||||
return formatRequired
|
return modPath, langVersion, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func formatGoSource(src []byte, opts format.Options) ([]byte, error) {
|
||||||
|
return format.Source(src, opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@@ -150,26 +79,76 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pwd := *directory
|
pwd := *directory
|
||||||
GOBIN := GetGOBIN()
|
modPath, langVersion, modErr := getModuleInfo(pwd)
|
||||||
binPath := os.Getenv("PATH")
|
if modErr != nil {
|
||||||
pathSlice := []string{pwd, GOBIN, binPath}
|
fmt.Println("Error reading go.mod:", modErr)
|
||||||
binPath = strings.Join(pathSlice, string(os.PathListSeparator))
|
|
||||||
os.Setenv("PATH", binPath)
|
|
||||||
|
|
||||||
suffix := ""
|
|
||||||
if runtime.GOOS == "windows" {
|
|
||||||
suffix = ".exe"
|
|
||||||
}
|
|
||||||
gofmt := "gofumpt" + suffix
|
|
||||||
|
|
||||||
if gofmtPath, err := exec.LookPath(gofmt); err != nil {
|
|
||||||
fmt.Println("Can not find", gofmt, "in system path or current working directory.")
|
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
} else {
|
}
|
||||||
gofmt = gofmtPath
|
opts := format.Options{
|
||||||
|
LangVersion: langVersion,
|
||||||
|
ModulePath: modPath,
|
||||||
|
}
|
||||||
|
|
||||||
|
if isFormat {
|
||||||
|
fmt.Println("Formatting Go source files...")
|
||||||
|
} else if isCheck {
|
||||||
|
fmt.Println("Checking files thar are not properly formatted...")
|
||||||
|
}
|
||||||
|
|
||||||
|
jobs := make(chan string, runtime.NumCPU())
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
var formatRequired atomic.Bool
|
||||||
|
var hasErrors atomic.Bool
|
||||||
|
|
||||||
|
for i := 0; i < runtime.NumCPU(); i++ {
|
||||||
|
wg.Go(func() {
|
||||||
|
for path := range jobs {
|
||||||
|
src, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error reading %s: %v\n", path, err)
|
||||||
|
hasErrors.Store(true)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
formatted, err := formatGoSource(src, opts)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error formatting %s: %v\n", path, err)
|
||||||
|
hasErrors.Store(true)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if !bytes.Equal(src, formatted) {
|
||||||
|
var diffText []byte
|
||||||
|
if isDryrun {
|
||||||
|
newName := filepath.ToSlash(path)
|
||||||
|
oldName := newName + ".orig"
|
||||||
|
diffText = diff(oldName, src, newName, formatted)
|
||||||
|
}
|
||||||
|
if isFormat {
|
||||||
|
info, statErr := os.Stat(path)
|
||||||
|
if statErr != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error stating %s: %v\n", path, statErr)
|
||||||
|
hasErrors.Store(true)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if writeErr := os.WriteFile(path, formatted, info.Mode().Perm()); writeErr != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error writing %s: %v\n", path, writeErr)
|
||||||
|
hasErrors.Store(true)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
formatRequired.Store(true)
|
||||||
|
if isDryrun && len(diffText) > 0 {
|
||||||
|
fmt.Printf("%s\n%s", path, diffText)
|
||||||
|
} else {
|
||||||
|
fmt.Println(path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
rawFilesSlice := make([]string, 0, 1000)
|
|
||||||
walkErr := filepath.Walk(pwd, func(path string, info os.FileInfo, err error) error {
|
walkErr := filepath.Walk(pwd, func(path string, info os.FileInfo, err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
@@ -186,51 +165,206 @@ func main() {
|
|||||||
!strings.HasSuffix(filename, ".pb.go") &&
|
!strings.HasSuffix(filename, ".pb.go") &&
|
||||||
!strings.Contains(dir, filepath.Join("testing", "mocks")) &&
|
!strings.Contains(dir, filepath.Join("testing", "mocks")) &&
|
||||||
!strings.Contains(path, filepath.Join("main", "distro", "all", "all.go")) {
|
!strings.Contains(path, filepath.Join("main", "distro", "all", "all.go")) {
|
||||||
rawFilesSlice = append(rawFilesSlice, path)
|
jobs <- path
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
close(jobs)
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
if walkErr != nil {
|
if walkErr != nil {
|
||||||
fmt.Println(walkErr)
|
fmt.Println(walkErr)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if isFormat {
|
if hasErrors.Load() {
|
||||||
gofmtArgs := []string{
|
os.Exit(1)
|
||||||
"-l", "-e", "-w",
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println("Formatting Go source files...")
|
if isFormat {
|
||||||
RunMany(gofmt, gofmtArgs, rawFilesSlice)
|
if formatRequired.Load() {
|
||||||
fmt.Println("Do NOT forget to commit file changes.")
|
fmt.Println("Do NOT forget to commit file changes.")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if isCheck {
|
if isCheck {
|
||||||
gofmtListArgs := []string{
|
if formatRequired.Load() {
|
||||||
"-l", "-e",
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println("Checking files thar are not properly formatted...")
|
|
||||||
formatRequired := RunMany(gofmt, gofmtListArgs, rawFilesSlice)
|
|
||||||
if formatRequired {
|
|
||||||
fmt.Println("Format problem(s) found.")
|
fmt.Println("Format problem(s) found.")
|
||||||
}
|
fmt.Println("Please run 'go run ./infra/vformat/main.go' to format the Go source files.")
|
||||||
|
|
||||||
if isDryrun {
|
|
||||||
if formatRequired {
|
|
||||||
gofmtShowArgs := []string{
|
|
||||||
"-d", "-e",
|
|
||||||
}
|
|
||||||
RunMany(gofmt, gofmtShowArgs, rawFilesSlice)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if formatRequired {
|
|
||||||
fmt.Println("Please run 'go install -v mvdan.cc/gofumpt@latest', then run 'go run ./infra/vformat/main.go' to format the Go source files.")
|
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("All Go source file format check has been passed.")
|
fmt.Println("All Go source file format check has been passed.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// diff algorithm copied from mvdan.cc/gofumpt/internal/govendor/diff
|
||||||
|
type pair struct{ x, y int }
|
||||||
|
|
||||||
|
func diff(oldName string, old []byte, newName string, new []byte) []byte {
|
||||||
|
if bytes.Equal(old, new) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
x := diffLines(old)
|
||||||
|
y := diffLines(new)
|
||||||
|
|
||||||
|
var out bytes.Buffer
|
||||||
|
fmt.Fprintf(&out, "diff %s %s\n", oldName, newName)
|
||||||
|
fmt.Fprintf(&out, "--- %s\n", oldName)
|
||||||
|
fmt.Fprintf(&out, "+++ %s\n", newName)
|
||||||
|
|
||||||
|
var (
|
||||||
|
done pair
|
||||||
|
chunk pair
|
||||||
|
count pair
|
||||||
|
ctext []string
|
||||||
|
)
|
||||||
|
for _, m := range diffTgs(x, y) {
|
||||||
|
if m.x < done.x {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
start := m
|
||||||
|
for start.x > done.x && start.y > done.y && x[start.x-1] == y[start.y-1] {
|
||||||
|
start.x--
|
||||||
|
start.y--
|
||||||
|
}
|
||||||
|
end := m
|
||||||
|
for end.x < len(x) && end.y < len(y) && x[end.x] == y[end.y] {
|
||||||
|
end.x++
|
||||||
|
end.y++
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, s := range x[done.x:start.x] {
|
||||||
|
ctext = append(ctext, "-"+s)
|
||||||
|
count.x++
|
||||||
|
}
|
||||||
|
for _, s := range y[done.y:start.y] {
|
||||||
|
ctext = append(ctext, "+"+s)
|
||||||
|
count.y++
|
||||||
|
}
|
||||||
|
|
||||||
|
const C = 3
|
||||||
|
if (end.x < len(x) || end.y < len(y)) &&
|
||||||
|
(end.x-start.x < C || (len(ctext) > 0 && end.x-start.x < 2*C)) {
|
||||||
|
for _, s := range x[start.x:end.x] {
|
||||||
|
ctext = append(ctext, " "+s)
|
||||||
|
count.x++
|
||||||
|
count.y++
|
||||||
|
}
|
||||||
|
done = end
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(ctext) > 0 {
|
||||||
|
n := end.x - start.x
|
||||||
|
if n > C {
|
||||||
|
n = C
|
||||||
|
}
|
||||||
|
for _, s := range x[start.x : start.x+n] {
|
||||||
|
ctext = append(ctext, " "+s)
|
||||||
|
count.x++
|
||||||
|
count.y++
|
||||||
|
}
|
||||||
|
done = pair{start.x + n, start.y + n}
|
||||||
|
|
||||||
|
if count.x > 0 {
|
||||||
|
chunk.x++
|
||||||
|
}
|
||||||
|
if count.y > 0 {
|
||||||
|
chunk.y++
|
||||||
|
}
|
||||||
|
fmt.Fprintf(&out, "@@ -%d,%d +%d,%d @@\n", chunk.x, count.x, chunk.y, count.y)
|
||||||
|
for _, s := range ctext {
|
||||||
|
out.WriteString(s)
|
||||||
|
}
|
||||||
|
count.x = 0
|
||||||
|
count.y = 0
|
||||||
|
ctext = ctext[:0]
|
||||||
|
}
|
||||||
|
|
||||||
|
if end.x >= len(x) && end.y >= len(y) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
chunk = pair{end.x - C, end.y - C}
|
||||||
|
for _, s := range x[chunk.x:end.x] {
|
||||||
|
ctext = append(ctext, " "+s)
|
||||||
|
count.x++
|
||||||
|
count.y++
|
||||||
|
}
|
||||||
|
done = end
|
||||||
|
}
|
||||||
|
|
||||||
|
return out.Bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
func diffLines(x []byte) []string {
|
||||||
|
l := strings.SplitAfter(string(x), "\n")
|
||||||
|
if l[len(l)-1] == "" {
|
||||||
|
l = l[:len(l)-1]
|
||||||
|
} else {
|
||||||
|
l[len(l)-1] += "\n\\ No newline at end of file\n"
|
||||||
|
}
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
|
||||||
|
func diffTgs(x, y []string) []pair {
|
||||||
|
m := make(map[string]int)
|
||||||
|
for _, s := range x {
|
||||||
|
if c := m[s]; c > -2 {
|
||||||
|
m[s] = c - 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, s := range y {
|
||||||
|
if c := m[s]; c > -8 {
|
||||||
|
m[s] = c - 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var xi, yi, inv []int
|
||||||
|
for i, s := range y {
|
||||||
|
if m[s] == -5 {
|
||||||
|
m[s] = len(yi)
|
||||||
|
yi = append(yi, i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i, s := range x {
|
||||||
|
if j, ok := m[s]; ok && j >= 0 {
|
||||||
|
xi = append(xi, i)
|
||||||
|
inv = append(inv, j)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
J := inv
|
||||||
|
n := len(xi)
|
||||||
|
T := make([]int, n)
|
||||||
|
L := make([]int, n)
|
||||||
|
for i := range T {
|
||||||
|
T[i] = n + 1
|
||||||
|
}
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
k := sort.Search(n, func(k int) bool {
|
||||||
|
return T[k] >= J[i]
|
||||||
|
})
|
||||||
|
T[k] = J[i]
|
||||||
|
L[i] = k + 1
|
||||||
|
}
|
||||||
|
k := 0
|
||||||
|
for _, v := range L {
|
||||||
|
if k < v {
|
||||||
|
k = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
seq := make([]pair, 2+k)
|
||||||
|
seq[1+k] = pair{len(x), len(y)}
|
||||||
|
lastj := n
|
||||||
|
for i := n - 1; i >= 0; i-- {
|
||||||
|
if L[i] == k && J[i] < lastj {
|
||||||
|
seq[k] = pair{xi[i], yi[J[i]]}
|
||||||
|
k--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
seq[0] = pair{0, 0}
|
||||||
|
return seq
|
||||||
|
}
|
||||||
|
|||||||
+96
-102
@@ -53,6 +53,10 @@ func reloadEnvSettings() error {
|
|||||||
func init() {
|
func init() {
|
||||||
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
|
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
|
||||||
h := new(Handler)
|
h := new(Handler)
|
||||||
|
if streamSettings, ok := session.StreamSettingsFromContext(ctx).(*internet.MemoryStreamConfig); ok && streamSettings.SocketSettings != nil {
|
||||||
|
h.resolveStrategy = streamSettings.SocketSettings.DomainStrategy
|
||||||
|
h.usesDialerProxy = len(streamSettings.SocketSettings.DialerProxy) > 0
|
||||||
|
}
|
||||||
if err := core.RequireFeatures(ctx, func(pm policy.Manager) error {
|
if err := core.RequireFeatures(ctx, func(pm policy.Manager) error {
|
||||||
return h.Init(config.(*Config), pm)
|
return h.Init(config.(*Config), pm)
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
@@ -89,9 +93,11 @@ type FinalRule struct {
|
|||||||
|
|
||||||
// Handler handles Freedom connections.
|
// Handler handles Freedom connections.
|
||||||
type Handler struct {
|
type Handler struct {
|
||||||
policyManager policy.Manager
|
policyManager policy.Manager
|
||||||
config *Config
|
config *Config
|
||||||
finalRules []*FinalRule
|
finalRules []*FinalRule
|
||||||
|
resolveStrategy internet.DomainStrategy
|
||||||
|
usesDialerProxy bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildFinalRule(config *FinalRuleConfig) (*FinalRule, error) {
|
func buildFinalRule(config *FinalRuleConfig) (*FinalRule, error) {
|
||||||
@@ -168,22 +174,6 @@ func getDefaultFinalRule(inbound *session.Inbound) *FinalRule {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) shouldResolveDomainBeforeFinalRules(dialDest net.Destination, defaultRule *FinalRule) bool {
|
|
||||||
if !dialDest.Address.Family().IsDomain() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if len(h.finalRules) > 0 {
|
|
||||||
rule := h.finalRules[0]
|
|
||||||
if rule.action == RuleAction_Allow && rule.network[dialDest.Network] && len(rule.port) == 0 && rule.ip == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if defaultRule != nil || len(h.finalRules) > 0 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Handler) matchFinalRule(network net.Network, address net.Address, port net.Port, defaultRule *FinalRule) *FinalRule {
|
func (h *Handler) matchFinalRule(network net.Network, address net.Address, port net.Port, defaultRule *FinalRule) *FinalRule {
|
||||||
for _, rule := range h.finalRules {
|
for _, rule := range h.finalRules {
|
||||||
if rule.Apply(network, address, port) {
|
if rule.Apply(network, address, port) {
|
||||||
@@ -196,17 +186,16 @@ func (h *Handler) matchFinalRule(network net.Network, address net.Address, port
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) applyFinalRules(network net.Network, address net.Address, port net.Port, defaultRule *FinalRule) RuleAction {
|
|
||||||
if rule := h.matchFinalRule(network, address, port, defaultRule); rule != nil {
|
|
||||||
return rule.action
|
|
||||||
}
|
|
||||||
return RuleAction_Allow
|
|
||||||
}
|
|
||||||
|
|
||||||
// Init initializes the Handler with necessary parameters.
|
// Init initializes the Handler with necessary parameters.
|
||||||
func (h *Handler) Init(config *Config, pm policy.Manager) error {
|
func (h *Handler) Init(config *Config, pm policy.Manager) error {
|
||||||
h.config = config
|
h.config = config
|
||||||
h.policyManager = pm
|
h.policyManager = pm
|
||||||
|
if h.usesDialerProxy { // freedom is not the final outbound, final rules do not apply
|
||||||
|
if len(config.FinalRules) > 0 {
|
||||||
|
errors.LogWarning(context.Background(), `The "finalRules" setting is ignored when "sockopt.dialerProxy" is set, since freedom is not the final outbound.`)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
h.finalRules = make([]*FinalRule, 0, len(config.FinalRules))
|
h.finalRules = make([]*FinalRule, 0, len(config.FinalRules))
|
||||||
for _, rc := range config.FinalRules {
|
for _, rc := range config.FinalRules {
|
||||||
rule, err := buildFinalRule(rc)
|
rule, err := buildFinalRule(rc)
|
||||||
@@ -237,6 +226,20 @@ func (h *Handler) blockDelay(rule *FinalRule) time.Duration {
|
|||||||
return time.Duration(min+uint64(dice.Roll(int(span+1)))) * time.Second
|
return time.Duration(min+uint64(dice.Roll(int(span+1)))) * time.Second
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *Handler) blackhole(ctx context.Context, input buf.Reader, output buf.Writer, rule *FinalRule, dest *net.Destination) error {
|
||||||
|
delay := h.blockDelay(rule)
|
||||||
|
errors.LogInfo(ctx, "blocked target: ", *dest, ", blackholing connection for ", delay)
|
||||||
|
timer := time.AfterFunc(delay, func() {
|
||||||
|
common.Interrupt(input)
|
||||||
|
common.Interrupt(output)
|
||||||
|
errors.LogInfo(ctx, "closed blackholed connection to blocked target: ", *dest)
|
||||||
|
})
|
||||||
|
defer timer.Stop()
|
||||||
|
defer common.Close(output)
|
||||||
|
_ = buf.Copy(input, buf.Discard)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func isValidAddress(addr *net.IPOrDomain) bool {
|
func isValidAddress(addr *net.IPOrDomain) bool {
|
||||||
if addr == nil {
|
if addr == nil {
|
||||||
return false
|
return false
|
||||||
@@ -256,7 +259,10 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
ob.Name = "freedom"
|
ob.Name = "freedom"
|
||||||
ob.CanSpliceCopy = 1
|
ob.CanSpliceCopy = 1
|
||||||
inbound := session.InboundFromContext(ctx)
|
inbound := session.InboundFromContext(ctx)
|
||||||
defaultRule := getDefaultFinalRule(inbound)
|
var defaultRule *FinalRule
|
||||||
|
if !h.usesDialerProxy { // freedom is not the final outbound, final rules do not apply (and the domain is not resolved)
|
||||||
|
defaultRule = getDefaultFinalRule(inbound)
|
||||||
|
}
|
||||||
|
|
||||||
destination := ob.Target
|
destination := ob.Target
|
||||||
origTargetAddr := ob.OriginalTarget.Address
|
origTargetAddr := ob.OriginalTarget.Address
|
||||||
@@ -284,61 +290,53 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
var conn stat.Connection
|
var conn stat.Connection
|
||||||
var blockedDest *net.Destination
|
var blockedDest *net.Destination
|
||||||
var blockedRule *FinalRule
|
var blockedRule *FinalRule
|
||||||
firstResolve := true
|
|
||||||
err := retry.ExponentialBackoff(5, 100).On(func() error {
|
err := retry.ExponentialBackoff(5, 100).On(func() error {
|
||||||
dialDest := destination
|
if destination.Address.Family().IsDomain() {
|
||||||
if h.config.DomainStrategy.HasStrategy() && dialDest.Address.Family().IsDomain() {
|
if defaultRule != nil || len(h.finalRules) > 0 {
|
||||||
strategy := h.config.DomainStrategy
|
if strategy := h.resolveStrategy; strategy.HasStrategy() {
|
||||||
if destination.Network == net.Network_UDP && origTargetAddr != nil && outGateway == nil {
|
ips, err := internet.LookupForIP(destination.Address.Domain(), strategy, outGateway)
|
||||||
strategy = strategy.GetDynamicStrategy(origTargetAddr.Family())
|
if err != nil { // non-force may still dial with system DNS
|
||||||
}
|
errors.LogInfoInner(ctx, err, "failed to get IP address for domain ", destination.Address.Domain())
|
||||||
ips, err := internet.LookupForIP(dialDest.Address.Domain(), strategy, outGateway)
|
if strategy.ForceIP() {
|
||||||
if err != nil {
|
return err // retry
|
||||||
errors.LogInfoInner(ctx, err, "failed to get IP address for domain ", dialDest.Address.Domain())
|
}
|
||||||
if h.config.DomainStrategy.ForceIP() || h.shouldResolveDomainBeforeFinalRules(dialDest, defaultRule) {
|
}
|
||||||
return err
|
for _, ip := range ips {
|
||||||
|
if addr := net.IPAddress(ip); addr != nil {
|
||||||
|
if rule := h.matchFinalRule(destination.Network, addr, destination.Port, defaultRule); rule != nil && rule.action == RuleAction_Block {
|
||||||
|
blockedDest = &destination
|
||||||
|
blockedDest.Address = addr
|
||||||
|
blockedRule = rule
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
addrs, err := net.DefaultResolver.LookupIPAddr(ctx, destination.Address.Domain())
|
||||||
|
if err != nil { // dialer may retry DNS
|
||||||
|
errors.LogInfoInner(ctx, err, "failed to get IP address for domain ", destination.Address.Domain())
|
||||||
|
}
|
||||||
|
for _, addr := range addrs {
|
||||||
|
if ipAddr := net.IPAddress(addr.IP); ipAddr != nil {
|
||||||
|
if rule := h.matchFinalRule(destination.Network, ipAddr, destination.Port, defaultRule); rule != nil && rule.action == RuleAction_Block {
|
||||||
|
blockedDest = &destination
|
||||||
|
blockedDest.Address = ipAddr
|
||||||
|
blockedRule = rule
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
dialDest = net.Destination{
|
|
||||||
Network: dialDest.Network,
|
|
||||||
Address: net.IPAddress(ips[dice.Roll(len(ips))]),
|
|
||||||
Port: dialDest.Port,
|
|
||||||
}
|
|
||||||
errors.LogInfo(ctx, "dialing to ", dialDest)
|
|
||||||
}
|
}
|
||||||
} else if h.shouldResolveDomainBeforeFinalRules(dialDest, defaultRule) { // asis + domain + hasrules
|
} else {
|
||||||
domain := dialDest.Address.Domain()
|
if rule := h.matchFinalRule(destination.Network, destination.Address, destination.Port, defaultRule); rule != nil && rule.action == RuleAction_Block {
|
||||||
var ips []net.IP
|
blockedDest = &destination
|
||||||
if firstResolve {
|
blockedRule = rule
|
||||||
firstResolve = false
|
return nil
|
||||||
supportIPv4, supportIPv6 := utils.CheckRoutes()
|
|
||||||
if supportIPv4 {
|
|
||||||
ips, _ = net.DefaultResolver.LookupIP(ctx, "ip4", domain)
|
|
||||||
}
|
|
||||||
if len(ips) == 0 && supportIPv6 {
|
|
||||||
ips, _ = net.DefaultResolver.LookupIP(ctx, "ip6", domain)
|
|
||||||
}
|
|
||||||
if len(ips) == 0 {
|
|
||||||
return errors.New("failed to get IP address for domain ", domain)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ips, _ = net.DefaultResolver.LookupIP(ctx, "ip", domain)
|
|
||||||
}
|
}
|
||||||
if len(ips) == 0 { // SRV/TXT, lookup failed
|
|
||||||
return errors.New("failed to get IP address for domain ", domain)
|
|
||||||
}
|
|
||||||
if addr := net.IPAddress(ips[dice.Roll(len(ips))]); addr != nil {
|
|
||||||
dialDest.Address = addr
|
|
||||||
errors.LogInfo(ctx, "dialing to ", dialDest)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if rule := h.matchFinalRule(dialDest.Network, dialDest.Address, dialDest.Port, defaultRule); rule != nil && rule.action == RuleAction_Block {
|
|
||||||
blockedDest = &dialDest
|
|
||||||
blockedRule = rule
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rawConn, err := dialer.Dial(ctx, dialDest)
|
rawConn, err := dialer.Dial(ctx, destination)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -350,20 +348,17 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
return errors.New("failed to open connection to ", destination).Base(err)
|
return errors.New("failed to open connection to ", destination).Base(err)
|
||||||
}
|
}
|
||||||
if blockedDest != nil {
|
if blockedDest != nil {
|
||||||
delay := h.blockDelay(blockedRule)
|
return h.blackhole(ctx, input, output, blockedRule, blockedDest)
|
||||||
errors.LogInfo(ctx, "blocked target: ", *blockedDest, ", blackholing connection for ", delay)
|
|
||||||
timer := time.AfterFunc(delay, func() {
|
|
||||||
common.Interrupt(input)
|
|
||||||
common.Interrupt(output)
|
|
||||||
errors.LogInfo(ctx, "closed blackholed connection to blocked target: ", *blockedDest)
|
|
||||||
})
|
|
||||||
defer timer.Stop()
|
|
||||||
defer common.Close(output)
|
|
||||||
if err := buf.Copy(input, buf.Discard); err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
if destination.Address.Family().IsDomain() && (defaultRule != nil || len(h.finalRules) > 0) {
|
||||||
|
// pre-check may fail or dialer may select another IP
|
||||||
|
remoteDest := net.DestinationFromAddr(conn.RemoteAddr())
|
||||||
|
if rule := h.matchFinalRule(remoteDest.Network, remoteDest.Address, remoteDest.Port, defaultRule); rule != nil && rule.action == RuleAction_Block {
|
||||||
|
conn.Close()
|
||||||
|
return h.blackhole(ctx, input, output, rule, &remoteDest)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if h.config.ProxyProtocol > 0 && h.config.ProxyProtocol <= 2 {
|
if h.config.ProxyProtocol > 0 && h.config.ProxyProtocol <= 2 {
|
||||||
version := byte(h.config.ProxyProtocol)
|
version := byte(h.config.ProxyProtocol)
|
||||||
srcAddr := inbound.Source.RawNetAddr()
|
srcAddr := inbound.Source.RawNetAddr()
|
||||||
@@ -408,7 +403,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
writer = buf.NewWriter(conn)
|
writer = buf.NewWriter(conn)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
writer = NewPacketWriter(conn, h, defaultRule, UDPOverride, destination)
|
writer = NewPacketWriter(conn, h, defaultRule, UDPOverride, destination, outGateway)
|
||||||
if h.config.Noises != nil {
|
if h.config.Noises != nil {
|
||||||
errors.LogDebug(ctx, "NOISE", h.config.Noises)
|
errors.LogDebug(ctx, "NOISE", h.config.Noises)
|
||||||
writer = &NoisePacketWriter{
|
writer = &NoisePacketWriter{
|
||||||
@@ -512,7 +507,7 @@ func (r *PacketReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
|
|||||||
}
|
}
|
||||||
udpAddr := d.(*net.UDPAddr)
|
udpAddr := d.(*net.UDPAddr)
|
||||||
sourceAddr := net.IPAddress(udpAddr.IP)
|
sourceAddr := net.IPAddress(udpAddr.IP)
|
||||||
if r.Handler.applyFinalRules(net.Network_UDP, sourceAddr, net.Port(udpAddr.Port), r.DefaultRule) == RuleAction_Block {
|
if rule := r.Handler.matchFinalRule(net.Network_UDP, sourceAddr, net.Port(udpAddr.Port), r.DefaultRule); rule != nil && rule.action == RuleAction_Block {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
b.Resize(0, int32(n))
|
b.Resize(0, int32(n))
|
||||||
@@ -537,7 +532,7 @@ func (r *PacketReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DialDest means the dial target used in the dialer when creating conn
|
// DialDest means the dial target used in the dialer when creating conn
|
||||||
func NewPacketWriter(conn net.Conn, h *Handler, defaultRule *FinalRule, UDPOverride net.Destination, DialDest net.Destination) buf.Writer {
|
func NewPacketWriter(conn net.Conn, h *Handler, defaultRule *FinalRule, UDPOverride net.Destination, DialDest net.Destination, outGateway net.Address) buf.Writer {
|
||||||
iConn := conn
|
iConn := conn
|
||||||
statConn, ok := iConn.(*stat.CounterConnection)
|
statConn, ok := iConn.(*stat.CounterConnection)
|
||||||
if ok {
|
if ok {
|
||||||
@@ -561,9 +556,8 @@ func NewPacketWriter(conn net.Conn, h *Handler, defaultRule *FinalRule, UDPOverr
|
|||||||
DefaultRule: defaultRule,
|
DefaultRule: defaultRule,
|
||||||
UDPOverride: UDPOverride,
|
UDPOverride: UDPOverride,
|
||||||
ResolvedUDPAddr: resolvedUDPAddr,
|
ResolvedUDPAddr: resolvedUDPAddr,
|
||||||
LocalAddr: net.DestinationFromAddr(conn.LocalAddr()).Address,
|
OutGateway: outGateway,
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return &buf.SequentialWriter{Writer: conn}
|
return &buf.SequentialWriter{Writer: conn}
|
||||||
}
|
}
|
||||||
@@ -580,7 +574,7 @@ type PacketWriter struct {
|
|||||||
// Resulting in these packets being sent to many different IPs randomly
|
// Resulting in these packets being sent to many different IPs randomly
|
||||||
// So, cache and keep the resolve result
|
// So, cache and keep the resolve result
|
||||||
ResolvedUDPAddr *utils.TypedSyncMap[string, net.Address]
|
ResolvedUDPAddr *utils.TypedSyncMap[string, net.Address]
|
||||||
LocalAddr net.Address
|
OutGateway net.Address
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
||||||
@@ -603,21 +597,21 @@ func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
|||||||
if ip, ok := w.ResolvedUDPAddr.Load(b.UDP.Address.Domain()); ok {
|
if ip, ok := w.ResolvedUDPAddr.Load(b.UDP.Address.Domain()); ok {
|
||||||
b.UDP.Address = ip
|
b.UDP.Address = ip
|
||||||
} else {
|
} else {
|
||||||
ShouldUseSystemResolver := true
|
shouldUseSystemResolver := true
|
||||||
if w.Handler.config.DomainStrategy.HasStrategy() {
|
if strategy := w.Handler.resolveStrategy; strategy.HasStrategy() {
|
||||||
ips, err := internet.LookupForIP(b.UDP.Address.Domain(), w.Handler.config.DomainStrategy, w.LocalAddr)
|
ips, err := internet.LookupForIP(b.UDP.Address.Domain(), strategy, w.OutGateway)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// drop packet if resolve failed when forceIP
|
// drop packet if resolve failed when forceIP
|
||||||
if w.Handler.config.DomainStrategy.ForceIP() {
|
if strategy.ForceIP() {
|
||||||
b.Release()
|
b.Release()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ip = net.IPAddress(ips[dice.Roll(len(ips))])
|
ip = net.IPAddress(ips[dice.Roll(len(ips))])
|
||||||
ShouldUseSystemResolver = false
|
shouldUseSystemResolver = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ShouldUseSystemResolver {
|
if shouldUseSystemResolver {
|
||||||
udpAddr, err := net.ResolveUDPAddr("udp", b.UDP.NetAddr())
|
udpAddr, err := net.ResolveUDPAddr("udp", b.UDP.NetAddr())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Release()
|
b.Release()
|
||||||
@@ -631,7 +625,7 @@ func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if w.applyFinalRules(net.Network_UDP, b.UDP.Address, b.UDP.Port, w.DefaultRule) == RuleAction_Block {
|
if rule := w.matchFinalRule(net.Network_UDP, b.UDP.Address, b.UDP.Port, w.DefaultRule); rule != nil && rule.action == RuleAction_Block {
|
||||||
b.Release()
|
b.Release()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -115,11 +115,7 @@ Start:
|
|||||||
|
|
||||||
request, err := http.ReadRequest(reader)
|
request, err := http.ReadRequest(reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
trace := errors.New("failed to read http request").Base(err)
|
return errors.New("failed to read http request").Base(err)
|
||||||
if errors.Cause(err) != io.EOF && !isTimeout(errors.Cause(err)) {
|
|
||||||
trace.AtWarning()
|
|
||||||
}
|
|
||||||
return trace
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(s.config.Accounts) > 0 {
|
if len(s.config.Accounts) > 0 {
|
||||||
@@ -147,7 +143,7 @@ Start:
|
|||||||
}
|
}
|
||||||
dest, err := http_proto.ParseHost(host, defaultPort)
|
dest, err := http_proto.ParseHost(host, defaultPort)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("malformed proxy host: ", host).AtWarning().Base(err)
|
return errors.New("malformed proxy host: ", host).Base(err)
|
||||||
}
|
}
|
||||||
ctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{
|
ctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{
|
||||||
From: conn.RemoteAddr(),
|
From: conn.RemoteAddr(),
|
||||||
@@ -262,7 +258,7 @@ func (s *Server) handlePlainHTTP(ctx context.Context, request *http.Request, wri
|
|||||||
requestWriter := buf.NewBufferedWriter(link.Writer)
|
requestWriter := buf.NewBufferedWriter(link.Writer)
|
||||||
common.Must(requestWriter.SetBuffered(false))
|
common.Must(requestWriter.SetBuffered(false))
|
||||||
if err := request.Write(requestWriter); err != nil {
|
if err := request.Write(requestWriter); err != nil {
|
||||||
return errors.New("failed to write whole request").Base(err).AtWarning()
|
return errors.New("failed to write whole request").Base(err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -299,7 +295,7 @@ func (s *Server) handlePlainHTTP(ctx context.Context, request *http.Request, wri
|
|||||||
response.Header.Set("Proxy-Connection", "close")
|
response.Header.Set("Proxy-Connection", "close")
|
||||||
}
|
}
|
||||||
if err := response.Write(writer); err != nil {
|
if err := response.Write(writer); err != nil {
|
||||||
return errors.New("failed to write response").Base(err).AtWarning()
|
return errors.New("failed to write response").Base(err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -332,7 +328,7 @@ func readResponseAndHandle100Continue(r *bufio.Reader, req *http.Request, writer
|
|||||||
return nil, errors.New("failed to read http 1xx response").Base(err)
|
return nil, errors.New("failed to read http 1xx response").Base(err)
|
||||||
}
|
}
|
||||||
ResponseHeader1xx = append(ResponseHeader1xx, data...)
|
ResponseHeader1xx = append(ResponseHeader1xx, data...)
|
||||||
if bytes.Equal(ResponseHeader1xx[len(ResponseHeader1xx)-4:], []byte{'\r', '\n', '\r', '\n'}) {
|
if len(ResponseHeader1xx) >= 4 && bytes.Equal(ResponseHeader1xx[len(ResponseHeader1xx)-4:], []byte{'\r', '\n', '\r', '\n'}) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if len(ResponseHeader1xx) > 1024 {
|
if len(ResponseHeader1xx) > 1024 {
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package http
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A malformed upstream response containing a bare '\n' before the real
|
||||||
|
// status line used to crash readResponseAndHandle100Continue: the first
|
||||||
|
// ReadSlice('\n') returns fewer than 4 bytes, and slicing
|
||||||
|
// ResponseHeader1xx[len(ResponseHeader1xx)-4:] panicked with a negative
|
||||||
|
// index instead of returning an error.
|
||||||
|
func TestReadResponseAndHandle100ContinueDoesNotPanicOnEarlyNewline(t *testing.T) {
|
||||||
|
payload := "X\nHTTP/1.1 100 Continue\r\n\r\n" + strings.Repeat("A", 40)
|
||||||
|
r := bufio.NewReader(bytes.NewReader([]byte(payload)))
|
||||||
|
req, err := http.NewRequest("GET", "http://example.com/", nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must not panic; a parse error for the garbage trailing bytes is fine.
|
||||||
|
_, _ = readResponseAndHandle100Continue(r, req, io.Discard)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadResponseAndHandle100ContinueForwardsAndParsesFinalResponse(t *testing.T) {
|
||||||
|
payload := "HTTP/1.1 100 Continue\r\n\r\n" +
|
||||||
|
"HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\nhello"
|
||||||
|
r := bufio.NewReader(bytes.NewReader([]byte(payload)))
|
||||||
|
req, err := http.NewRequest("GET", "http://example.com/", nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var forwarded bytes.Buffer
|
||||||
|
resp, err := readResponseAndHandle100Continue(r, req, &forwarded)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if resp.StatusCode != 200 {
|
||||||
|
t.Fatalf("expected status 200, got %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
if !strings.Contains(forwarded.String(), "100 Continue") {
|
||||||
|
t.Fatalf("expected 1xx response to be forwarded, got %q", forwarded.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -62,7 +62,7 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
|
|||||||
|
|
||||||
conn, err := dialer.Dial(hysteria.ContextWithDatagram(ctx, target.Network == net.Network_UDP), c.server.Destination)
|
conn, err := dialer.Dial(hysteria.ContextWithDatagram(ctx, target.Network == net.Network_UDP), c.server.Destination)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to find an available destination").AtWarning().Base(err)
|
return errors.New("failed to find an available destination").Base(err)
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
errors.LogInfo(ctx, "tunneling request to ", target, " via ", target.Network, ":", c.server.Destination.NetAddr())
|
errors.LogInfo(ctx, "tunneling request to ", target, " via ", target.Network, ":", c.server.Destination.NetAddr())
|
||||||
|
|||||||
@@ -40,11 +40,11 @@ func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {
|
|||||||
for _, user := range config.Users {
|
for _, user := range config.Users {
|
||||||
u, err := user.ToMemoryUser()
|
u, err := user.ToMemoryUser()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("failed to get hysteria user").Base(err).AtError()
|
return nil, errors.New("failed to get hysteria user").Base(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validator.Add(u); err != nil {
|
if err := validator.Add(u); err != nil {
|
||||||
return nil, errors.New("failed to add user").Base(err).AtError()
|
return nil, errors.New("failed to add user").Base(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ func (l *Loopback) init(config *Config, dispatcherInstance routing.Dispatcher) e
|
|||||||
if config.Sniffing.GetEnabled() {
|
if config.Sniffing.GetEnabled() {
|
||||||
request, err := proxyman.BuildSniffingRequest(config.Sniffing)
|
request, err := proxyman.BuildSniffingRequest(config.Sniffing)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to build loopback sniffing request").Base(err).AtError()
|
return errors.New("failed to build loopback sniffing request").Base(err)
|
||||||
}
|
}
|
||||||
l.sniffingRequest = request
|
l.sniffingRequest = request
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to find an available destination").AtWarning().Base(err)
|
return errors.New("failed to find an available destination").Base(err)
|
||||||
}
|
}
|
||||||
errors.LogInfo(ctx, "tunneling request to ", destination, " via ", network, ":", server.Destination.NetAddr())
|
errors.LogInfo(ctx, "tunneling request to ", destination, " via ", network, ":", server.Destination.NetAddr())
|
||||||
|
|
||||||
@@ -124,7 +124,7 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err = buf.CopyOnceTimeout(link.Reader, bodyWriter, time.Millisecond*100); err != nil && err != buf.ErrNotTimeoutReader && err != buf.ErrReadTimeout {
|
if err = buf.CopyOnceTimeout(link.Reader, bodyWriter, time.Millisecond*100); err != nil && err != buf.ErrNotTimeoutReader && err != buf.ErrReadTimeout {
|
||||||
return errors.New("failed to write A request payload").Base(err).AtWarning()
|
return errors.New("failed to write A request payload").Base(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := bufferedWriter.SetBuffered(false); err != nil {
|
if err := bufferedWriter.SetBuffered(false); err != nil {
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ func ReadTCPSession(validator *Validator, reader io.Reader) (*protocol.RequestHe
|
|||||||
iv := append([]byte(nil), buffer.BytesTo(ivLen)...)
|
iv := append([]byte(nil), buffer.BytesTo(ivLen)...)
|
||||||
r, err = account.Cipher.NewDecryptionReader(account.Key, iv, reader)
|
r, err = account.Cipher.NewDecryptionReader(account.Key, iv, reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, drain.WithError(drainer, reader, errors.New("failed to initialize decoding stream").Base(err).AtError())
|
return nil, nil, drain.WithError(drainer, reader, errors.New("failed to initialize decoding stream").Base(err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -146,7 +146,7 @@ func WriteTCPRequest(request *protocol.RequestHeader, writer io.Writer) (buf.Wri
|
|||||||
|
|
||||||
w, err := account.Cipher.NewEncryptionWriter(account.Key, iv, writer)
|
w, err := account.Cipher.NewEncryptionWriter(account.Key, iv, writer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("failed to create encoding stream").Base(err).AtError()
|
return nil, errors.New("failed to create encoding stream").Base(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
header := buf.New()
|
header := buf.New()
|
||||||
|
|||||||
@@ -34,11 +34,11 @@ func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {
|
|||||||
for _, user := range config.Users {
|
for _, user := range config.Users {
|
||||||
u, err := user.ToMemoryUser()
|
u, err := user.ToMemoryUser()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("failed to get shadowsocks user").Base(err).AtError()
|
return nil, errors.New("failed to get shadowsocks user").Base(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validator.Add(u); err != nil {
|
if err := validator.Add(u); err != nil {
|
||||||
return nil, errors.New("failed to add user").Base(err).AtError()
|
return nil, errors.New("failed to add user").Base(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,7 +200,7 @@ func (s *Server) handleUDPPayload(ctx context.Context, conn stat.Connection, dis
|
|||||||
func (s *Server) handleConnection(ctx context.Context, conn stat.Connection, dispatcher routing.Dispatcher) error {
|
func (s *Server) handleConnection(ctx context.Context, conn stat.Connection, dispatcher routing.Dispatcher) error {
|
||||||
sessionPolicy := s.policyManager.ForLevel(0)
|
sessionPolicy := s.policyManager.ForLevel(0)
|
||||||
if err := conn.SetReadDeadline(time.Now().Add(sessionPolicy.Timeouts.Handshake)); err != nil {
|
if err := conn.SetReadDeadline(time.Now().Add(sessionPolicy.Timeouts.Handshake)); err != nil {
|
||||||
return errors.New("unable to set read deadline").Base(err).AtWarning()
|
return errors.New("unable to set read deadline").Base(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
bufferedReader := buf.BufferedReader{Reader: buf.NewReader(conn)}
|
bufferedReader := buf.BufferedReader{Reader: buf.NewReader(conn)}
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ func NewMultiServer(ctx context.Context, config *MultiUserServerConfig) (*MultiU
|
|||||||
}
|
}
|
||||||
u, err := user.ToMemoryUser()
|
u, err := user.ToMemoryUser()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("failed to get shadowsocks user").Base(err).AtError()
|
return nil, errors.New("failed to get shadowsocks user").Base(err)
|
||||||
}
|
}
|
||||||
memUsers = append(memUsers, u)
|
memUsers = append(memUsers, u)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,6 +82,7 @@ func (o *Outbound) Process(ctx context.Context, link *transport.Link, dialer int
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to connect to server").Base(err)
|
return errors.New("failed to connect to server").Base(err)
|
||||||
}
|
}
|
||||||
|
defer connection.Close()
|
||||||
|
|
||||||
if session.TimeoutOnlyFromContext(ctx) {
|
if session.TimeoutOnlyFromContext(ctx) {
|
||||||
ctx, _ = context.WithCancel(context.Background())
|
ctx, _ = context.WithCancel(context.Background())
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
|
|||||||
}
|
}
|
||||||
udpRequest, err := ClientHandshake(request, conn, conn)
|
udpRequest, err := ClientHandshake(request, conn, conn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to establish connection to server").AtWarning().Base(err)
|
return errors.New("failed to establish connection to server").Base(err)
|
||||||
}
|
}
|
||||||
if udpRequest != nil {
|
if udpRequest != nil {
|
||||||
if udpRequest.Address == net.AnyIP || udpRequest.Address == net.AnyIPv6 {
|
if udpRequest.Address == net.AnyIP || udpRequest.Address == net.AnyIPv6 {
|
||||||
|
|||||||
@@ -458,10 +458,10 @@ func ClientHandshake(request *protocol.RequestHeader, reader io.Reader, writer i
|
|||||||
}
|
}
|
||||||
|
|
||||||
if b.Byte(0) != socks5Version {
|
if b.Byte(0) != socks5Version {
|
||||||
return nil, errors.New("unexpected server version: ", b.Byte(0)).AtWarning()
|
return nil, errors.New("unexpected server version: ", b.Byte(0))
|
||||||
}
|
}
|
||||||
if b.Byte(1) != authByte {
|
if b.Byte(1) != authByte {
|
||||||
return nil, errors.New("auth method not supported.").AtWarning()
|
return nil, errors.New("auth method not supported.")
|
||||||
}
|
}
|
||||||
|
|
||||||
if authByte == authPassword {
|
if authByte == authPassword {
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to find an available destination").AtWarning().Base(err)
|
return errors.New("failed to find an available destination").Base(err)
|
||||||
}
|
}
|
||||||
errors.LogInfo(ctx, "tunneling request to ", destination, " via ", server.Destination.NetAddr())
|
errors.LogInfo(ctx, "tunneling request to ", destination, " via ", server.Destination.NetAddr())
|
||||||
|
|
||||||
@@ -116,21 +116,21 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
|
|||||||
|
|
||||||
// write some request payload to buffer
|
// write some request payload to buffer
|
||||||
if err = buf.CopyOnceTimeout(link.Reader, bodyWriter, time.Millisecond*100); err != nil && err != buf.ErrNotTimeoutReader && err != buf.ErrReadTimeout {
|
if err = buf.CopyOnceTimeout(link.Reader, bodyWriter, time.Millisecond*100); err != nil && err != buf.ErrNotTimeoutReader && err != buf.ErrReadTimeout {
|
||||||
return errors.New("failed to write A request payload").Base(err).AtWarning()
|
return errors.New("failed to write A request payload").Base(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flush; bufferWriter.WriteMultiBuffer now is bufferWriter.writer.WriteMultiBuffer
|
// Flush; bufferWriter.WriteMultiBuffer now is bufferWriter.writer.WriteMultiBuffer
|
||||||
if err = bufferWriter.SetBuffered(false); err != nil {
|
if err = bufferWriter.SetBuffered(false); err != nil {
|
||||||
return errors.New("failed to flush payload").Base(err).AtWarning()
|
return errors.New("failed to flush payload").Base(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send header if not sent yet
|
// Send header if not sent yet
|
||||||
if _, err = connWriter.Write([]byte{}); err != nil {
|
if _, err = connWriter.Write([]byte{}); err != nil {
|
||||||
return err.(*errors.Error).AtWarning()
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = buf.Copy(link.Reader, bodyWriter, buf.UpdateActivity(timer)); err != nil {
|
if err = buf.Copy(link.Reader, bodyWriter, buf.UpdateActivity(timer)); err != nil {
|
||||||
return errors.New("failed to transfer request payload").Base(err).AtInfo()
|
return errors.New("failed to transfer request payload").Base(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
+12
-12
@@ -47,11 +47,11 @@ func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {
|
|||||||
for _, user := range config.Users {
|
for _, user := range config.Users {
|
||||||
u, err := user.ToMemoryUser()
|
u, err := user.ToMemoryUser()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("failed to get trojan user").Base(err).AtError()
|
return nil, errors.New("failed to get trojan user").Base(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validator.Add(u); err != nil {
|
if err := validator.Add(u); err != nil {
|
||||||
return nil, errors.New("failed to add user").Base(err).AtError()
|
return nil, errors.New("failed to add user").Base(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,7 +151,7 @@ func (s *Server) Process(ctx context.Context, network net.Network, conn stat.Con
|
|||||||
|
|
||||||
sessionPolicy := s.policyManager.ForLevel(0)
|
sessionPolicy := s.policyManager.ForLevel(0)
|
||||||
if err := conn.SetReadDeadline(time.Now().Add(sessionPolicy.Timeouts.Handshake)); err != nil {
|
if err := conn.SetReadDeadline(time.Now().Add(sessionPolicy.Timeouts.Handshake)); err != nil {
|
||||||
return errors.New("unable to set read deadline").Base(err).AtWarning()
|
return errors.New("unable to set read deadline").Base(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
first := buf.FromBytes(make([]byte, buf.Size))
|
first := buf.FromBytes(make([]byte, buf.Size))
|
||||||
@@ -219,7 +219,7 @@ func (s *Server) Process(ctx context.Context, network net.Network, conn stat.Con
|
|||||||
|
|
||||||
destination := clientReader.Target
|
destination := clientReader.Target
|
||||||
if err := conn.SetReadDeadline(time.Time{}); err != nil {
|
if err := conn.SetReadDeadline(time.Time{}); err != nil {
|
||||||
return errors.New("unable to set read deadline").Base(err).AtWarning()
|
return errors.New("unable to set read deadline").Base(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
inbound := session.InboundFromContext(ctx)
|
inbound := session.InboundFromContext(ctx)
|
||||||
@@ -402,7 +402,7 @@ func (s *Server) fallback(ctx context.Context, err error, sessionPolicy policy.S
|
|||||||
}
|
}
|
||||||
apfb := napfb[name]
|
apfb := napfb[name]
|
||||||
if apfb == nil {
|
if apfb == nil {
|
||||||
return errors.New(`failed to find the default "name" config`).AtWarning()
|
return errors.New(`failed to find the default "name" config`)
|
||||||
}
|
}
|
||||||
|
|
||||||
if apfb[alpn] == nil {
|
if apfb[alpn] == nil {
|
||||||
@@ -410,7 +410,7 @@ func (s *Server) fallback(ctx context.Context, err error, sessionPolicy policy.S
|
|||||||
}
|
}
|
||||||
pfb := apfb[alpn]
|
pfb := apfb[alpn]
|
||||||
if pfb == nil {
|
if pfb == nil {
|
||||||
return errors.New(`failed to find the default "alpn" config`).AtWarning()
|
return errors.New(`failed to find the default "alpn" config`)
|
||||||
}
|
}
|
||||||
|
|
||||||
path := ""
|
path := ""
|
||||||
@@ -444,7 +444,7 @@ func (s *Server) fallback(ctx context.Context, err error, sessionPolicy policy.S
|
|||||||
}
|
}
|
||||||
fb := pfb[path]
|
fb := pfb[path]
|
||||||
if fb == nil {
|
if fb == nil {
|
||||||
return errors.New(`failed to find the default "path" config`).AtWarning()
|
return errors.New(`failed to find the default "path" config`)
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(ctx)
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
@@ -460,7 +460,7 @@ func (s *Server) fallback(ctx context.Context, err error, sessionPolicy policy.S
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return errors.New("failed to dial to " + fb.Dest).Base(err).AtWarning()
|
return errors.New("failed to dial to " + fb.Dest).Base(err)
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
@@ -520,11 +520,11 @@ func (s *Server) fallback(ctx context.Context, err error, sessionPolicy policy.S
|
|||||||
common.Must2(pro.Write([]byte{byte(p1 >> 8), byte(p1), byte(p2 >> 8), byte(p2)}))
|
common.Must2(pro.Write([]byte{byte(p1 >> 8), byte(p1), byte(p2 >> 8), byte(p2)}))
|
||||||
}
|
}
|
||||||
if err := serverWriter.WriteMultiBuffer(buf.MultiBuffer{pro}); err != nil {
|
if err := serverWriter.WriteMultiBuffer(buf.MultiBuffer{pro}); err != nil {
|
||||||
return errors.New("failed to set PROXY protocol v", fb.Xver).Base(err).AtWarning()
|
return errors.New("failed to set PROXY protocol v", fb.Xver).Base(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := buf.Copy(reader, serverWriter, buf.UpdateActivity(timer)); err != nil {
|
if err := buf.Copy(reader, serverWriter, buf.UpdateActivity(timer)); err != nil {
|
||||||
return errors.New("failed to fallback request payload").Base(err).AtInfo()
|
return errors.New("failed to fallback request payload").Base(err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -534,7 +534,7 @@ func (s *Server) fallback(ctx context.Context, err error, sessionPolicy policy.S
|
|||||||
getResponse := func() error {
|
getResponse := func() error {
|
||||||
defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)
|
defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)
|
||||||
if err := buf.Copy(serverReader, writer, buf.UpdateActivity(timer)); err != nil {
|
if err := buf.Copy(serverReader, writer, buf.UpdateActivity(timer)); err != nil {
|
||||||
return errors.New("failed to deliver response payload").Base(err).AtInfo()
|
return errors.New("failed to deliver response payload").Base(err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -542,7 +542,7 @@ func (s *Server) fallback(ctx context.Context, err error, sessionPolicy policy.S
|
|||||||
if err := task.Run(ctx, task.OnSuccess(postRequest, task.Close(serverWriter)), task.OnSuccess(getResponse, task.Close(writer))); err != nil {
|
if err := task.Run(ctx, task.OnSuccess(postRequest, task.Close(serverWriter)), task.OnSuccess(getResponse, task.Close(writer))); err != nil {
|
||||||
common.Must(common.Interrupt(serverReader))
|
common.Must(common.Interrupt(serverReader))
|
||||||
common.Must(common.Interrupt(serverWriter))
|
common.Must(common.Interrupt(serverWriter))
|
||||||
return errors.New("fallback ends").Base(err).AtInfo()
|
return errors.New("fallback ends").Base(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
+145
-137
@@ -3,14 +3,14 @@
|
|||||||
package tun
|
package tun
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
go_errors "errors"
|
go_errors "errors"
|
||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
@@ -31,13 +31,14 @@ func procyield(cycles uint32)
|
|||||||
type WindowsTun struct {
|
type WindowsTun struct {
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
|
|
||||||
options *Config
|
options *Config
|
||||||
adapter *wintun.Adapter
|
adapter *wintun.Adapter
|
||||||
session wintun.Session
|
session wintun.Session
|
||||||
readWait windows.Handle
|
readWait windows.Handle
|
||||||
luid winipcfg.LUID
|
luid winipcfg.LUID
|
||||||
changeCallback winipcfg.ChangeCallback
|
cbr winipcfg.ChangeCallback
|
||||||
closed bool
|
cbi winipcfg.ChangeCallback
|
||||||
|
closed bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// WindowsTun implements Tun
|
// WindowsTun implements Tun
|
||||||
@@ -85,23 +86,37 @@ func open(name, desc string) (*wintun.Adapter, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *WindowsTun) Start() error {
|
func (t *WindowsTun) Start() (err error) {
|
||||||
var has4, has6 bool
|
var address4, address6 bool
|
||||||
allowedIPs := make([]netip.Prefix, 0, len(t.options.AutoSystemRoutingTable))
|
addresses := make([]netip.Prefix, 0, len(t.options.Gateway))
|
||||||
for _, route := range t.options.AutoSystemRoutingTable {
|
for _, cidr := range t.options.Gateway {
|
||||||
allowedIPs = append(allowedIPs, netip.MustParsePrefix(route))
|
prefix := netip.MustParsePrefix(cidr)
|
||||||
|
if prefix.Addr().Is4() {
|
||||||
|
address4 = true
|
||||||
|
} else {
|
||||||
|
address6 = true
|
||||||
|
}
|
||||||
|
addresses = append(addresses, prefix)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dns := make([]netip.Addr, 0, len(t.options.DNS))
|
||||||
|
for _, ip := range t.options.DNS {
|
||||||
|
dns = append(dns, netip.MustParseAddr(ip))
|
||||||
|
}
|
||||||
|
|
||||||
|
var route4, route6 bool
|
||||||
routesMap := make(map[winipcfg.RouteData]struct{})
|
routesMap := make(map[winipcfg.RouteData]struct{})
|
||||||
for _, ip := range allowedIPs {
|
for _, cidr := range t.options.AutoSystemRoutingTable {
|
||||||
|
prefix := netip.MustParsePrefix(cidr)
|
||||||
route := winipcfg.RouteData{
|
route := winipcfg.RouteData{
|
||||||
Destination: ip.Masked(),
|
Destination: prefix.Masked(),
|
||||||
Metric: 0,
|
Metric: 0,
|
||||||
}
|
}
|
||||||
if ip.Addr().Is4() {
|
if prefix.Addr().Is4() {
|
||||||
has4 = true
|
route4 = true
|
||||||
route.NextHop = netip.IPv4Unspecified()
|
route.NextHop = netip.IPv4Unspecified()
|
||||||
} else {
|
} else {
|
||||||
has6 = true
|
route6 = true
|
||||||
route.NextHop = netip.IPv6Unspecified()
|
route.NextHop = netip.IPv6Unspecified()
|
||||||
}
|
}
|
||||||
routesMap[route] = struct{}{}
|
routesMap[route] = struct{}{}
|
||||||
@@ -111,24 +126,40 @@ func (t *WindowsTun) Start() error {
|
|||||||
r := route
|
r := route
|
||||||
routesData = append(routesData, &r)
|
routesData = append(routesData, &r)
|
||||||
}
|
}
|
||||||
err := t.luid.SetRoutes(routesData)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New("unable to set routes").Base(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(t.options.Gateway) > 0 {
|
var retryTimes int
|
||||||
addresses := make([]netip.Prefix, 0, len(t.options.Gateway))
|
var firstErr error
|
||||||
for _, address := range t.options.Gateway {
|
startOver:
|
||||||
addresses = append(addresses, netip.MustParsePrefix(address))
|
if retryTimes > 0 {
|
||||||
}
|
if retryTimes > 15 {
|
||||||
err := t.luid.SetIPAddresses(addresses)
|
return windows.ERROR_NOT_FOUND
|
||||||
if err != nil {
|
|
||||||
return errors.New("unable to set ips").Base(err)
|
|
||||||
}
|
}
|
||||||
|
errors.LogErrorInner(context.Background(), firstErr, "Interface configuration failed, retrying attempt ", retryTimes, "/15")
|
||||||
|
time.Sleep(time.Second)
|
||||||
}
|
}
|
||||||
|
retryTimes++
|
||||||
if has4 {
|
for _, family := range []winipcfg.AddressFamily{windows.AF_INET, windows.AF_INET6} {
|
||||||
ipif, err := t.luid.IPInterface(windows.AF_INET)
|
if family == windows.AF_INET && route4 || family == windows.AF_INET6 && route6 {
|
||||||
|
err = t.luid.SetRoutesForFamily(family, routesData)
|
||||||
|
if err != nil {
|
||||||
|
firstErr = errors.New("unable to set routes").Base(err)
|
||||||
|
if err == windows.ERROR_NOT_FOUND {
|
||||||
|
goto startOver
|
||||||
|
}
|
||||||
|
return firstErr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if family == windows.AF_INET && address4 || family == windows.AF_INET6 && address6 {
|
||||||
|
err = t.luid.SetIPAddressesForFamily(family, addresses)
|
||||||
|
if err != nil {
|
||||||
|
firstErr = errors.New("unable to set ips").Base(err)
|
||||||
|
if err == windows.ERROR_NOT_FOUND {
|
||||||
|
goto startOver
|
||||||
|
}
|
||||||
|
return firstErr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ipif, err := t.luid.IPInterface(family)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -136,56 +167,45 @@ func (t *WindowsTun) Start() error {
|
|||||||
ipif.DadTransmits = 0
|
ipif.DadTransmits = 0
|
||||||
ipif.ManagedAddressConfigurationSupported = false
|
ipif.ManagedAddressConfigurationSupported = false
|
||||||
ipif.OtherStatefulConfigurationSupported = false
|
ipif.OtherStatefulConfigurationSupported = false
|
||||||
ipif.NLMTU = t.options.MTU
|
if family == windows.AF_INET && (address4 || route4) || family == windows.AF_INET6 && (address6 || route6) {
|
||||||
ipif.UseAutomaticMetric = false
|
ipif.NLMTU = t.options.MTU
|
||||||
ipif.Metric = 0
|
}
|
||||||
|
if family == windows.AF_INET && route4 || family == windows.AF_INET6 && route6 {
|
||||||
|
ipif.UseAutomaticMetric = false
|
||||||
|
ipif.Metric = 0
|
||||||
|
}
|
||||||
err = ipif.Set()
|
err = ipif.Set()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
firstErr = errors.New("unable to set metric and MTU").Base(err)
|
||||||
|
if err == windows.ERROR_NOT_FOUND {
|
||||||
|
goto startOver
|
||||||
|
}
|
||||||
|
return firstErr
|
||||||
}
|
}
|
||||||
}
|
err = t.luid.SetDNS(family, dns, nil)
|
||||||
if has6 {
|
|
||||||
ipif, err := t.luid.IPInterface(windows.AF_INET6)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
firstErr = errors.New("unable to set DNS").Base(err)
|
||||||
}
|
if err == windows.ERROR_NOT_FOUND {
|
||||||
ipif.RouterDiscoveryBehavior = winipcfg.RouterDiscoveryDisabled
|
goto startOver
|
||||||
ipif.DadTransmits = 0
|
}
|
||||||
ipif.ManagedAddressConfigurationSupported = false
|
return firstErr
|
||||||
ipif.OtherStatefulConfigurationSupported = false
|
|
||||||
ipif.NLMTU = t.options.MTU
|
|
||||||
ipif.UseAutomaticMetric = false
|
|
||||||
ipif.Metric = 0
|
|
||||||
err = ipif.Set()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(t.options.DNS) > 0 {
|
|
||||||
dns := make([]netip.Addr, 0, len(t.options.DNS))
|
|
||||||
for _, ip := range t.options.DNS {
|
|
||||||
dns = append(dns, netip.MustParseAddr(ip))
|
|
||||||
}
|
|
||||||
err := t.luid.SetDNS(windows.AF_INET, dns, nil)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = t.luid.SetDNS(windows.AF_INET6, dns, nil)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if updater != nil {
|
if updater != nil {
|
||||||
t.changeCallback, err = winipcfg.RegisterInterfaceChangeCallback(func(notificationType winipcfg.MibNotificationType, iface *winipcfg.MibIPInterfaceRow) {
|
t.cbr, err = winipcfg.RegisterRouteChangeCallback(func(notificationType winipcfg.MibNotificationType, route *winipcfg.MibIPforwardRow2) {
|
||||||
|
updater.Update()
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
t.cbi, err = winipcfg.RegisterInterfaceChangeCallback(func(notificationType winipcfg.MibNotificationType, iface *winipcfg.MibIPInterfaceRow) {
|
||||||
updater.Update()
|
updater.Update()
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,12 +217,26 @@ func (t *WindowsTun) Close() error {
|
|||||||
}
|
}
|
||||||
t.closed = true
|
t.closed = true
|
||||||
|
|
||||||
if t.changeCallback != nil {
|
if t.cbr != nil {
|
||||||
t.changeCallback.Unregister()
|
t.cbr.Unregister()
|
||||||
|
}
|
||||||
|
if t.cbi != nil {
|
||||||
|
t.cbi.Unregister()
|
||||||
|
}
|
||||||
|
if t.luid != 0 {
|
||||||
|
t.luid.FlushRoutes(windows.AF_INET)
|
||||||
|
t.luid.FlushIPAddresses(windows.AF_INET)
|
||||||
|
t.luid.FlushDNS(windows.AF_INET)
|
||||||
|
t.luid.FlushRoutes(windows.AF_INET6)
|
||||||
|
t.luid.FlushIPAddresses(windows.AF_INET6)
|
||||||
|
t.luid.FlushDNS(windows.AF_INET6)
|
||||||
|
}
|
||||||
|
if t.session != (wintun.Session{}) {
|
||||||
|
t.session.End()
|
||||||
|
}
|
||||||
|
if t.adapter != nil {
|
||||||
|
t.adapter.Close()
|
||||||
}
|
}
|
||||||
t.session.End()
|
|
||||||
_ = t.adapter.Close()
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -311,75 +345,49 @@ func setinterface(network, address string, fd uintptr, iface *net.Interface) err
|
|||||||
}
|
}
|
||||||
|
|
||||||
func findOutboundInterface(tunIndex int, fixedName string) (*net.Interface, error) {
|
func findOutboundInterface(tunIndex int, fixedName string) (*net.Interface, error) {
|
||||||
interfaces, err := net.Interfaces()
|
if fixedName != "" {
|
||||||
|
return net.InterfaceByName(fixedName)
|
||||||
|
}
|
||||||
|
|
||||||
|
r, err := winipcfg.GetIPForwardTable2(windows.AF_UNSPEC)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
lowestMetric := ^uint32(0)
|
||||||
|
index := uint32(0)
|
||||||
|
lowestMetricWifi := ^uint32(0)
|
||||||
|
indexWifi := uint32(0)
|
||||||
|
for i := range r {
|
||||||
|
if r[i].DestinationPrefix.PrefixLength != 0 || r[i].InterfaceIndex == uint32(tunIndex) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ifrow, err := r[i].InterfaceLUID.Interface()
|
||||||
|
if err != nil || ifrow.OperStatus != winipcfg.IfOperStatusUp {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if fixedName != "" {
|
iface, err := r[i].InterfaceLUID.IPInterface(windows.AF_INET)
|
||||||
for _, iface := range interfaces {
|
if err != nil {
|
||||||
if iface.Index != tunIndex && iface.Name == fixedName {
|
iface, err = r[i].InterfaceLUID.IPInterface(windows.AF_INET6)
|
||||||
return &iface, nil
|
if err != nil {
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var candidates []struct {
|
if ifrow.Type == windows.IF_TYPE_IEEE80211 {
|
||||||
index int
|
if r[i].Metric+iface.Metric < lowestMetricWifi {
|
||||||
score int
|
lowestMetricWifi = r[i].Metric + iface.Metric
|
||||||
|
indexWifi = r[i].InterfaceIndex
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if r[i].Metric+iface.Metric < lowestMetric {
|
||||||
|
lowestMetric = r[i].Metric + iface.Metric
|
||||||
|
index = r[i].InterfaceIndex
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for i, iface := range interfaces {
|
if indexWifi != 0 {
|
||||||
if iface.Index == tunIndex {
|
index = indexWifi
|
||||||
continue
|
|
||||||
}
|
|
||||||
if strings.Contains(iface.Name, "vEthernet") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if iface.Flags&net.FlagUp == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if iface.Flags&net.FlagLoopback != 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
addrs, err := iface.Addrs()
|
|
||||||
if err != nil || len(addrs) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
candidates = append(candidates, struct {
|
|
||||||
index int
|
|
||||||
score int
|
|
||||||
}{i, scoreWindowsInterface(&iface, addrs)})
|
|
||||||
}
|
}
|
||||||
|
return net.InterfaceByIndex(int(index))
|
||||||
sort.Slice(candidates, func(i, j int) bool {
|
|
||||||
if candidates[i].score != candidates[j].score {
|
|
||||||
return candidates[i].score > candidates[j].score
|
|
||||||
}
|
|
||||||
return interfaces[candidates[i].index].Name < interfaces[candidates[j].index].Name
|
|
||||||
})
|
|
||||||
if len(candidates) == 0 {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
iface := interfaces[candidates[0].index]
|
|
||||||
return &iface, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func scoreWindowsInterface(iface *net.Interface, addrs []net.Addr) int {
|
|
||||||
score := 0
|
|
||||||
|
|
||||||
name := strings.ToLower(iface.Name)
|
|
||||||
if strings.Contains(name, "wlan") || strings.Contains(name, "wi-fi") {
|
|
||||||
score += 2
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, addr := range addrs {
|
|
||||||
if strings.HasPrefix(addr.String(), "192.168.") {
|
|
||||||
score++
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return score
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
func (a *Account) AsAccount() (protocol.Account, error) {
|
func (a *Account) AsAccount() (protocol.Account, error) {
|
||||||
id, err := uuid.ParseString(a.Id)
|
id, err := uuid.ParseString(a.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("failed to parse ID").Base(err).AtError()
|
return nil, errors.New("failed to parse ID").Base(err)
|
||||||
}
|
}
|
||||||
return &MemoryAccount{
|
return &MemoryAccount{
|
||||||
ID: protocol.NewID(id),
|
ID: protocol.NewID(id),
|
||||||
|
|||||||
@@ -61,10 +61,10 @@ func init() {
|
|||||||
for _, user := range c.Users {
|
for _, user := range c.Users {
|
||||||
u, err := user.ToMemoryUser()
|
u, err := user.ToMemoryUser()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("failed to get VLESS user").Base(err).AtError()
|
return nil, errors.New("failed to get VLESS user").Base(err)
|
||||||
}
|
}
|
||||||
if err := validator.Add(u); err != nil {
|
if err := validator.Add(u); err != nil {
|
||||||
return nil, errors.New("failed to initiate user").Base(err).AtError()
|
return nil, errors.New("failed to initiate user").Base(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,7 +110,7 @@ func New(ctx context.Context, config *Config, dc dns.Client, validator vless.Val
|
|||||||
}
|
}
|
||||||
handler.decryption = &encryption.ServerInstance{}
|
handler.decryption = &encryption.ServerInstance{}
|
||||||
if err := handler.decryption.Init(nfsSKeysBytes, config.XorMode, config.SecondsFrom, config.SecondsTo, config.Padding); err != nil {
|
if err := handler.decryption.Init(nfsSKeysBytes, config.XorMode, config.SecondsFrom, config.SecondsTo, config.Padding); err != nil {
|
||||||
return nil, errors.New("failed to use decryption").Base(err).AtError()
|
return nil, errors.New("failed to use decryption").Base(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,7 +128,7 @@ func New(ctx context.Context, config *Config, dc dns.Client, validator vless.Val
|
|||||||
/*
|
/*
|
||||||
if fb.Path != "" {
|
if fb.Path != "" {
|
||||||
if r, err := regexp.Compile(fb.Path); err != nil {
|
if r, err := regexp.Compile(fb.Path); err != nil {
|
||||||
return nil, errors.New("invalid path regexp").Base(err).AtError()
|
return nil, errors.New("invalid path regexp").Base(err)
|
||||||
} else {
|
} else {
|
||||||
handler.regexps[fb.Path] = r
|
handler.regexps[fb.Path] = r
|
||||||
}
|
}
|
||||||
@@ -274,13 +274,13 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||||||
if h.decryption != nil {
|
if h.decryption != nil {
|
||||||
var err error
|
var err error
|
||||||
if connection, err = h.decryption.Handshake(connection, nil); err != nil {
|
if connection, err = h.decryption.Handshake(connection, nil); err != nil {
|
||||||
return errors.New("ML-KEM-768 handshake failed").Base(err).AtInfo()
|
return errors.New("ML-KEM-768 handshake failed").Base(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sessionPolicy := h.policyManager.ForLevel(0)
|
sessionPolicy := h.policyManager.ForLevel(0)
|
||||||
if err := connection.SetReadDeadline(time.Now().Add(sessionPolicy.Timeouts.Handshake)); err != nil {
|
if err := connection.SetReadDeadline(time.Now().Add(sessionPolicy.Timeouts.Handshake)); err != nil {
|
||||||
return errors.New("unable to set read deadline").Base(err).AtWarning()
|
return errors.New("unable to set read deadline").Base(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
first := buf.FromBytes(make([]byte, buf.Size))
|
first := buf.FromBytes(make([]byte, buf.Size))
|
||||||
@@ -352,7 +352,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||||||
}
|
}
|
||||||
apfb := napfb[name]
|
apfb := napfb[name]
|
||||||
if apfb == nil {
|
if apfb == nil {
|
||||||
return errors.New(`failed to find the default "name" config`).AtWarning()
|
return errors.New(`failed to find the default "name" config`)
|
||||||
}
|
}
|
||||||
|
|
||||||
if apfb[alpn] == nil {
|
if apfb[alpn] == nil {
|
||||||
@@ -360,7 +360,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||||||
}
|
}
|
||||||
pfb := apfb[alpn]
|
pfb := apfb[alpn]
|
||||||
if pfb == nil {
|
if pfb == nil {
|
||||||
return errors.New(`failed to find the default "alpn" config`).AtWarning()
|
return errors.New(`failed to find the default "alpn" config`)
|
||||||
}
|
}
|
||||||
|
|
||||||
path := ""
|
path := ""
|
||||||
@@ -369,7 +369,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||||||
if lines := bytes.Split(firstBytes, []byte{'\r', '\n'}); len(lines) > 1 {
|
if lines := bytes.Split(firstBytes, []byte{'\r', '\n'}); len(lines) > 1 {
|
||||||
if s := bytes.Split(lines[0], []byte{' '}); len(s) == 3 {
|
if s := bytes.Split(lines[0], []byte{' '}); len(s) == 3 {
|
||||||
if len(s[0]) < 8 && len(s[1]) > 0 && len(s[2]) == 8 {
|
if len(s[0]) < 8 && len(s[1]) > 0 && len(s[2]) == 8 {
|
||||||
errors.New("realPath = " + string(s[1])).AtInfo().WriteToLog(sid)
|
errors.New("realPath = " + string(s[1])).WriteToLog(sid)
|
||||||
for _, fb := range pfb {
|
for _, fb := range pfb {
|
||||||
if fb.Path != "" && h.regexps[fb.Path].Match(s[1]) {
|
if fb.Path != "" && h.regexps[fb.Path].Match(s[1]) {
|
||||||
path = fb.Path
|
path = fb.Path
|
||||||
@@ -409,7 +409,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||||||
}
|
}
|
||||||
fb := pfb[path]
|
fb := pfb[path]
|
||||||
if fb == nil {
|
if fb == nil {
|
||||||
return errors.New(`failed to find the default "path" config`).AtWarning()
|
return errors.New(`failed to find the default "path" config`)
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(ctx)
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
@@ -425,7 +425,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return errors.New("failed to dial to " + fb.Dest).Base(err).AtWarning()
|
return errors.New("failed to dial to " + fb.Dest).Base(err)
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
@@ -485,11 +485,11 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||||||
pro.Write([]byte{byte(p1 >> 8), byte(p1), byte(p2 >> 8), byte(p2)})
|
pro.Write([]byte{byte(p1 >> 8), byte(p1), byte(p2 >> 8), byte(p2)})
|
||||||
}
|
}
|
||||||
if err := serverWriter.WriteMultiBuffer(buf.MultiBuffer{pro}); err != nil {
|
if err := serverWriter.WriteMultiBuffer(buf.MultiBuffer{pro}); err != nil {
|
||||||
return errors.New("failed to set PROXY protocol v", fb.Xver).Base(err).AtWarning()
|
return errors.New("failed to set PROXY protocol v", fb.Xver).Base(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := buf.Copy(reader, serverWriter, buf.UpdateActivity(timer)); err != nil {
|
if err := buf.Copy(reader, serverWriter, buf.UpdateActivity(timer)); err != nil {
|
||||||
return errors.New("failed to fallback request payload").Base(err).AtInfo()
|
return errors.New("failed to fallback request payload").Base(err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -499,7 +499,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||||||
getResponse := func() error {
|
getResponse := func() error {
|
||||||
defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)
|
defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)
|
||||||
if err := buf.Copy(serverReader, writer, buf.UpdateActivity(timer)); err != nil {
|
if err := buf.Copy(serverReader, writer, buf.UpdateActivity(timer)); err != nil {
|
||||||
return errors.New("failed to deliver response payload").Base(err).AtInfo()
|
return errors.New("failed to deliver response payload").Base(err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -507,7 +507,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||||||
if err := task.Run(ctx, task.OnSuccess(postRequest, task.Close(serverWriter)), task.OnSuccess(getResponse, task.Close(writer))); err != nil {
|
if err := task.Run(ctx, task.OnSuccess(postRequest, task.Close(serverWriter)), task.OnSuccess(getResponse, task.Close(writer))); err != nil {
|
||||||
common.Interrupt(serverReader)
|
common.Interrupt(serverReader)
|
||||||
common.Interrupt(serverWriter)
|
common.Interrupt(serverWriter)
|
||||||
return errors.New("fallback ends").Base(err).AtInfo()
|
return errors.New("fallback ends").Base(err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -519,7 +519,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||||||
Status: log.AccessRejected,
|
Status: log.AccessRejected,
|
||||||
Reason: err,
|
Reason: err,
|
||||||
})
|
})
|
||||||
err = errors.New("invalid request from ", connection.RemoteAddr()).Base(err).AtInfo()
|
err = errors.New("invalid request from ", connection.RemoteAddr()).Base(err)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -555,7 +555,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||||||
inbound.CanSpliceCopy = 2
|
inbound.CanSpliceCopy = 2
|
||||||
switch request.Command {
|
switch request.Command {
|
||||||
case protocol.RequestCommandUDP:
|
case protocol.RequestCommandUDP:
|
||||||
return errors.New(requestAddons.Flow + " doesn't support UDP").AtWarning()
|
return errors.New(requestAddons.Flow + " doesn't support UDP")
|
||||||
case protocol.RequestCommandMux, protocol.RequestCommandRvs:
|
case protocol.RequestCommandMux, protocol.RequestCommandRvs:
|
||||||
inbound.CanSpliceCopy = 3
|
inbound.CanSpliceCopy = 3
|
||||||
fallthrough // we will break Mux connections that contain TCP requests
|
fallthrough // we will break Mux connections that contain TCP requests
|
||||||
@@ -570,7 +570,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||||||
p = uintptr(unsafe.Pointer(commonConn))
|
p = uintptr(unsafe.Pointer(commonConn))
|
||||||
} else if tlsConn, ok := iConn.(*tls.Conn); ok {
|
} else if tlsConn, ok := iConn.(*tls.Conn); ok {
|
||||||
if tlsConn.ConnectionState().Version != gotls.VersionTLS13 {
|
if tlsConn.ConnectionState().Version != gotls.VersionTLS13 {
|
||||||
return errors.New(`failed to use `+requestAddons.Flow+`, found outer tls version `, tlsConn.ConnectionState().Version).AtWarning()
|
return errors.New(`failed to use `+requestAddons.Flow+`, found outer tls version `, tlsConn.ConnectionState().Version)
|
||||||
}
|
}
|
||||||
t = reflect.TypeOf(tlsConn.Conn).Elem()
|
t = reflect.TypeOf(tlsConn.Conn).Elem()
|
||||||
p = uintptr(unsafe.Pointer(tlsConn.Conn))
|
p = uintptr(unsafe.Pointer(tlsConn.Conn))
|
||||||
@@ -578,7 +578,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||||||
t = reflect.TypeOf(realityConn.Conn).Elem()
|
t = reflect.TypeOf(realityConn.Conn).Elem()
|
||||||
p = uintptr(unsafe.Pointer(realityConn.Conn))
|
p = uintptr(unsafe.Pointer(realityConn.Conn))
|
||||||
} else {
|
} else {
|
||||||
return errors.New("XTLS only supports TLS and REALITY directly for now.").AtWarning()
|
return errors.New("XTLS only supports TLS and REALITY directly for now.")
|
||||||
}
|
}
|
||||||
i, _ := t.FieldByName("input")
|
i, _ := t.FieldByName("input")
|
||||||
r, _ := t.FieldByName("rawInput")
|
r, _ := t.FieldByName("rawInput")
|
||||||
@@ -586,15 +586,15 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||||||
rawInput = (*bytes.Buffer)(unsafe.Pointer(p + r.Offset))
|
rawInput = (*bytes.Buffer)(unsafe.Pointer(p + r.Offset))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return errors.New("account " + account.ID.String() + " is not able to use the flow " + requestAddons.Flow).AtWarning()
|
return errors.New("account " + account.ID.String() + " is not able to use the flow " + requestAddons.Flow)
|
||||||
}
|
}
|
||||||
case "":
|
case "":
|
||||||
inbound.CanSpliceCopy = 3
|
inbound.CanSpliceCopy = 3
|
||||||
if account.Flow == vless.XRV && (request.Command == protocol.RequestCommandTCP || isMuxAndNotXUDP(request, first)) {
|
if account.Flow == vless.XRV && (request.Command == protocol.RequestCommandTCP || isMuxAndNotXUDP(request, first)) {
|
||||||
return errors.New("account " + account.ID.String() + " is rejected since the client flow is empty. Note that the pure TLS proxy has certain TLS in TLS characters.").AtWarning()
|
return errors.New("account " + account.ID.String() + " is rejected since the client flow is empty. Note that the pure TLS proxy has certain TLS in TLS characters.")
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return errors.New("unknown request flow " + requestAddons.Flow).AtWarning()
|
return errors.New("unknown request flow " + requestAddons.Flow)
|
||||||
}
|
}
|
||||||
|
|
||||||
if request.Command != protocol.RequestCommandMux {
|
if request.Command != protocol.RequestCommandMux {
|
||||||
@@ -617,7 +617,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||||||
|
|
||||||
bufferWriter := buf.NewBufferedWriter(buf.NewWriter(connection))
|
bufferWriter := buf.NewBufferedWriter(buf.NewWriter(connection))
|
||||||
if err := encoding.EncodeResponseHeader(bufferWriter, request, responseAddons); err != nil {
|
if err := encoding.EncodeResponseHeader(bufferWriter, request, responseAddons); err != nil {
|
||||||
return errors.New("failed to encode response header").Base(err).AtWarning()
|
return errors.New("failed to encode response header").Base(err)
|
||||||
}
|
}
|
||||||
clientWriter := encoding.EncodeBodyAddons(bufferWriter, request, requestAddons, trafficState, false, ctx, connection, nil)
|
clientWriter := encoding.EncodeBodyAddons(bufferWriter, request, requestAddons, trafficState, false, ctx, connection, nil)
|
||||||
bufferWriter.SetFlushNext()
|
bufferWriter.SetFlushNext()
|
||||||
@@ -654,11 +654,11 @@ func (r *Reverse) Tag() string {
|
|||||||
func (r *Reverse) NewMux(ctx context.Context, link *transport.Link, observer features.Feature) error {
|
func (r *Reverse) NewMux(ctx context.Context, link *transport.Link, observer features.Feature) error {
|
||||||
muxClient, err := mux.NewClientWorker(*link, mux.ClientStrategy{})
|
muxClient, err := mux.NewClientWorker(*link, mux.ClientStrategy{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to create mux client worker").Base(err).AtWarning()
|
return errors.New("failed to create mux client worker").Base(err)
|
||||||
}
|
}
|
||||||
worker, err := reverse.NewPortalWorker(muxClient)
|
worker, err := reverse.NewPortalWorker(muxClient)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to create portal worker").Base(err).AtWarning()
|
return errors.New("failed to create portal worker").Base(err)
|
||||||
}
|
}
|
||||||
r.picker.AddWorker(worker)
|
r.picker.AddWorker(worker)
|
||||||
if burstObs, ok := observer.(extension.BurstObservatory); ok {
|
if burstObs, ok := observer.(extension.BurstObservatory); ok {
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ func New(ctx context.Context, config *Config) (*Handler, error) {
|
|||||||
}
|
}
|
||||||
server, err := protocol.NewServerSpecFromPB(config.Vnext)
|
server, err := protocol.NewServerSpecFromPB(config.Vnext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("failed to get server spec").Base(err).AtError()
|
return nil, errors.New("failed to get server spec").Base(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
v := core.MustFromContext(ctx)
|
v := core.MustFromContext(ctx)
|
||||||
@@ -93,7 +93,7 @@ func New(ctx context.Context, config *Config) (*Handler, error) {
|
|||||||
}
|
}
|
||||||
handler.encryption = &encryption.ClientInstance{}
|
handler.encryption = &encryption.ClientInstance{}
|
||||||
if err := handler.encryption.Init(nfsPKeysBytes, a.XorMode, a.Seconds, a.Padding); err != nil {
|
if err := handler.encryption.Init(nfsPKeysBytes, a.XorMode, a.Seconds, a.Padding); err != nil {
|
||||||
return nil, errors.New("failed to use encryption").Base(err).AtError()
|
return nil, errors.New("failed to use encryption").Base(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,7 +106,7 @@ func New(ctx context.Context, config *Config) (*Handler, error) {
|
|||||||
if sc := a.Reverse.Sniffing; sc != nil && sc.Enabled {
|
if sc := a.Reverse.Sniffing; sc != nil && sc.Enabled {
|
||||||
request, err := proxymanConfig.BuildSniffingRequest(sc)
|
request, err := proxymanConfig.BuildSniffingRequest(sc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("failed to build reverse sniffing request").Base(err).AtError()
|
return nil, errors.New("failed to build reverse sniffing request").Base(err)
|
||||||
}
|
}
|
||||||
rvsCtx = session.ContextWithContent(rvsCtx, &session.Content{
|
rvsCtx = session.ContextWithContent(rvsCtx, &session.Content{
|
||||||
SniffingRequest: request,
|
SniffingRequest: request,
|
||||||
@@ -149,7 +149,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
outbounds := session.OutboundsFromContext(ctx)
|
outbounds := session.OutboundsFromContext(ctx)
|
||||||
ob := outbounds[len(outbounds)-1]
|
ob := outbounds[len(outbounds)-1]
|
||||||
if !ob.Target.IsValid() && ob.Target.Address.String() != "v1.rvs.cool" {
|
if !ob.Target.IsValid() && ob.Target.Address.String() != "v1.rvs.cool" {
|
||||||
return errors.New("target not specified").AtError()
|
return errors.New("target not specified")
|
||||||
}
|
}
|
||||||
ob.Name = "vless"
|
ob.Name = "vless"
|
||||||
|
|
||||||
@@ -178,7 +178,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
for {
|
for {
|
||||||
connTime := <-h.preConns
|
connTime := <-h.preConns
|
||||||
if connTime == nil {
|
if connTime == nil {
|
||||||
return errors.New("closed handler").AtWarning()
|
return errors.New("closed handler")
|
||||||
}
|
}
|
||||||
if time.Now().Before(connTime.Expire) {
|
if time.Now().Before(connTime.Expire) {
|
||||||
conn = connTime.Conn
|
conn = connTime.Conn
|
||||||
@@ -197,13 +197,11 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return errors.New("failed to find an available destination").Base(err).AtWarning()
|
return errors.New("failed to find an available destination").Base(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
ob.Conn = conn // for Vision's pre-connect
|
|
||||||
|
|
||||||
iConn := stat.TryUnwrapStatsConn(conn)
|
iConn := stat.TryUnwrapStatsConn(conn)
|
||||||
target := ob.Target
|
target := ob.Target
|
||||||
errors.LogInfo(ctx, "tunneling request to ", target, " via ", rec.Destination.NetAddr())
|
errors.LogInfo(ctx, "tunneling request to ", target, " via ", rec.Destination.NetAddr())
|
||||||
@@ -211,7 +209,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
if h.encryption != nil {
|
if h.encryption != nil {
|
||||||
var err error
|
var err error
|
||||||
if conn, err = h.encryption.Handshake(conn); err != nil {
|
if conn, err = h.encryption.Handshake(conn); err != nil {
|
||||||
return errors.New("ML-KEM-768 handshake failed").Base(err).AtInfo()
|
return errors.New("ML-KEM-768 handshake failed").Base(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,7 +223,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
command = protocol.RequestCommandMux
|
command = protocol.RequestCommandMux
|
||||||
case "v1.rvs.cool":
|
case "v1.rvs.cool":
|
||||||
if target.Network != net.Network_Unknown {
|
if target.Network != net.Network_Unknown {
|
||||||
return errors.New("nice try baby").AtError()
|
return errors.New("nice try baby")
|
||||||
}
|
}
|
||||||
command = protocol.RequestCommandRvs
|
command = protocol.RequestCommandRvs
|
||||||
}
|
}
|
||||||
@@ -258,7 +256,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
switch request.Command {
|
switch request.Command {
|
||||||
case protocol.RequestCommandUDP:
|
case protocol.RequestCommandUDP:
|
||||||
if !allowUDP443 && request.Port == 443 {
|
if !allowUDP443 && request.Port == 443 {
|
||||||
return errors.New("XTLS rejected UDP/443 traffic").AtInfo()
|
return errors.New("XTLS rejected UDP/443 traffic")
|
||||||
}
|
}
|
||||||
case protocol.RequestCommandMux:
|
case protocol.RequestCommandMux:
|
||||||
fallthrough // let server break Mux connections that contain TCP requests
|
fallthrough // let server break Mux connections that contain TCP requests
|
||||||
@@ -281,7 +279,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
t = reflect.TypeOf(realityConn.Conn).Elem()
|
t = reflect.TypeOf(realityConn.Conn).Elem()
|
||||||
p = uintptr(unsafe.Pointer(realityConn.Conn))
|
p = uintptr(unsafe.Pointer(realityConn.Conn))
|
||||||
} else {
|
} else {
|
||||||
return errors.New("XTLS only supports TLS and REALITY directly for now.").AtWarning()
|
return errors.New("XTLS only supports TLS and REALITY directly for now.")
|
||||||
}
|
}
|
||||||
i, _ := t.FieldByName("input")
|
i, _ := t.FieldByName("input")
|
||||||
r, _ := t.FieldByName("rawInput")
|
r, _ := t.FieldByName("rawInput")
|
||||||
@@ -323,7 +321,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
|
|
||||||
bufferWriter := buf.NewBufferedWriter(buf.NewWriter(conn))
|
bufferWriter := buf.NewBufferedWriter(buf.NewWriter(conn))
|
||||||
if err := encoding.EncodeRequestHeader(bufferWriter, request, requestAddons); err != nil {
|
if err := encoding.EncodeRequestHeader(bufferWriter, request, requestAddons); err != nil {
|
||||||
return errors.New("failed to encode request header").Base(err).AtWarning()
|
return errors.New("failed to encode request header").Base(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// default: serverWriter := bufferWriter
|
// default: serverWriter := bufferWriter
|
||||||
@@ -352,23 +350,23 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
}
|
}
|
||||||
// Flush; bufferWriter.WriteMultiBuffer now is bufferWriter.writer.WriteMultiBuffer
|
// Flush; bufferWriter.WriteMultiBuffer now is bufferWriter.writer.WriteMultiBuffer
|
||||||
if err := bufferWriter.SetBuffered(false); err != nil {
|
if err := bufferWriter.SetBuffered(false); err != nil {
|
||||||
return errors.New("failed to write A request payload").Base(err).AtWarning()
|
return errors.New("failed to write A request payload").Base(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if requestAddons.Flow == vless.XRV {
|
if requestAddons.Flow == vless.XRV {
|
||||||
if tlsConn, ok := iConn.(*tls.Conn); ok {
|
if tlsConn, ok := iConn.(*tls.Conn); ok {
|
||||||
if tlsConn.ConnectionState().Version != gotls.VersionTLS13 {
|
if tlsConn.ConnectionState().Version != gotls.VersionTLS13 {
|
||||||
return errors.New(`failed to use `+requestAddons.Flow+`, found outer tls version `, tlsConn.ConnectionState().Version).AtWarning()
|
return errors.New(`failed to use `+requestAddons.Flow+`, found outer tls version `, tlsConn.ConnectionState().Version)
|
||||||
}
|
}
|
||||||
} else if utlsConn, ok := iConn.(*tls.UConn); ok {
|
} else if utlsConn, ok := iConn.(*tls.UConn); ok {
|
||||||
if utlsConn.ConnectionState().Version != utls.VersionTLS13 {
|
if utlsConn.ConnectionState().Version != utls.VersionTLS13 {
|
||||||
return errors.New(`failed to use `+requestAddons.Flow+`, found outer tls version `, utlsConn.ConnectionState().Version).AtWarning()
|
return errors.New(`failed to use `+requestAddons.Flow+`, found outer tls version `, utlsConn.ConnectionState().Version)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err := buf.Copy(clientReader, serverWriter, buf.UpdateActivity(timer))
|
err := buf.Copy(clientReader, serverWriter, buf.UpdateActivity(timer))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to transfer request payload").Base(err).AtInfo()
|
return errors.New("failed to transfer request payload").Base(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Indicates the end of request payload.
|
// Indicates the end of request payload.
|
||||||
@@ -383,7 +381,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
|
|
||||||
responseAddons, err := encoding.DecodeResponseHeader(conn, request)
|
responseAddons, err := encoding.DecodeResponseHeader(conn, request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to decode response header").Base(err).AtInfo()
|
return errors.New("failed to decode response header").Base(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// default: serverReader := buf.NewReader(conn)
|
// default: serverReader := buf.NewReader(conn)
|
||||||
@@ -407,7 +405,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to transfer response payload").Base(err).AtInfo()
|
return errors.New("failed to transfer response payload").Base(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -418,7 +416,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := task.Run(ctx, postRequest, task.OnSuccess(getResponse, task.Close(clientWriter))); err != nil {
|
if err := task.Run(ctx, postRequest, task.OnSuccess(getResponse, task.Close(clientWriter))); err != nil {
|
||||||
return errors.New("connection ends").Base(err).AtInfo()
|
return errors.New("connection ends").Base(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ func (a *MemoryAccount) ToProto() proto.Message {
|
|||||||
func (a *Account) AsAccount() (protocol.Account, error) {
|
func (a *Account) AsAccount() (protocol.Account, error) {
|
||||||
id, err := uuid.ParseString(a.Id)
|
id, err := uuid.ParseString(a.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("failed to parse ID").Base(err).AtError()
|
return nil, errors.New("failed to parse ID").Base(err)
|
||||||
}
|
}
|
||||||
protoID := protocol.NewID(id)
|
protoID := protocol.NewID(id)
|
||||||
var AuthenticatedLength, NoTerminationSignal bool
|
var AuthenticatedLength, NoTerminationSignal bool
|
||||||
|
|||||||
@@ -209,7 +209,7 @@ func (c *ClientSession) DecodeResponseHeader(reader io.Reader) (*protocol.Respon
|
|||||||
defer buffer.Release()
|
defer buffer.Release()
|
||||||
|
|
||||||
if _, err := buffer.ReadFullFrom(c.responseReader, 4); err != nil {
|
if _, err := buffer.ReadFullFrom(c.responseReader, 4); err != nil {
|
||||||
return nil, errors.New("failed to read response header").Base(err).AtWarning()
|
return nil, errors.New("failed to read response header").Base(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if buffer.Byte(0) != c.responseHeader {
|
if buffer.Byte(0) != c.responseHeader {
|
||||||
|
|||||||
@@ -227,7 +227,7 @@ func transferResponse(timer signal.ActivityUpdater, session *encoding.ServerSess
|
|||||||
func (h *Handler) Process(ctx context.Context, network net.Network, connection stat.Connection, dispatcher routing.Dispatcher) error {
|
func (h *Handler) Process(ctx context.Context, network net.Network, connection stat.Connection, dispatcher routing.Dispatcher) error {
|
||||||
sessionPolicy := h.policyManager.ForLevel(0)
|
sessionPolicy := h.policyManager.ForLevel(0)
|
||||||
if err := connection.SetReadDeadline(time.Now().Add(sessionPolicy.Timeouts.Handshake)); err != nil {
|
if err := connection.SetReadDeadline(time.Now().Add(sessionPolicy.Timeouts.Handshake)); err != nil {
|
||||||
return errors.New("unable to set read deadline").Base(err).AtWarning()
|
return errors.New("unable to set read deadline").Base(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
iConn := stat.TryUnwrapStatsConn(connection)
|
iConn := stat.TryUnwrapStatsConn(connection)
|
||||||
@@ -247,7 +247,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||||||
Status: log.AccessRejected,
|
Status: log.AccessRejected,
|
||||||
Reason: err,
|
Reason: err,
|
||||||
})
|
})
|
||||||
err = errors.New("invalid request from ", connection.RemoteAddr()).Base(err).AtInfo()
|
err = errors.New("invalid request from ", connection.RemoteAddr()).Base(err)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
outbounds := session.OutboundsFromContext(ctx)
|
outbounds := session.OutboundsFromContext(ctx)
|
||||||
ob := outbounds[len(outbounds)-1]
|
ob := outbounds[len(outbounds)-1]
|
||||||
if !ob.Target.IsValid() {
|
if !ob.Target.IsValid() {
|
||||||
return errors.New("target not specified").AtError()
|
return errors.New("target not specified")
|
||||||
}
|
}
|
||||||
ob.Name = "vmess"
|
ob.Name = "vmess"
|
||||||
ob.CanSpliceCopy = 3
|
ob.CanSpliceCopy = 3
|
||||||
@@ -78,7 +78,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to find an available destination").Base(err).AtWarning()
|
return errors.New("failed to find an available destination").Base(err)
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
@@ -154,7 +154,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
|
|
||||||
writer := buf.NewBufferedWriter(buf.NewWriter(conn))
|
writer := buf.NewBufferedWriter(buf.NewWriter(conn))
|
||||||
if err := session.EncodeRequestHeader(request, writer); err != nil {
|
if err := session.EncodeRequestHeader(request, writer); err != nil {
|
||||||
return errors.New("failed to encode request").Base(err).AtWarning()
|
return errors.New("failed to encode request").Base(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
bodyWriter, err := session.EncodeRequestBody(request, writer)
|
bodyWriter, err := session.EncodeRequestBody(request, writer)
|
||||||
|
|||||||
@@ -82,9 +82,14 @@ func TestResolveIP(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
Tag: "direct",
|
Tag: "direct",
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{
|
||||||
DomainStrategy: internet.DomainStrategy_USE_IP,
|
StreamSettings: &internet.StreamConfig{
|
||||||
|
SocketSettings: &internet.SocketConfig{
|
||||||
|
DomainStrategy: internet.DomainStrategy_USE_IP,
|
||||||
|
},
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ func TestPassiveConnection(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestProxy(t *testing.T) {
|
func TestDialerProxy(t *testing.T) {
|
||||||
tcpServer := tcp.Server{
|
tcpServer := tcp.Server{
|
||||||
MsgProcessor: xor,
|
MsgProcessor: xor,
|
||||||
}
|
}
|
||||||
@@ -187,8 +187,10 @@ func TestProxy(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{
|
SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{
|
||||||
ProxySettings: &internet.ProxyConfig{
|
StreamSettings: &internet.StreamConfig{
|
||||||
Tag: "proxy",
|
SocketSettings: &internet.SocketConfig{
|
||||||
|
DialerProxy: "proxy",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
@@ -218,7 +220,7 @@ func TestProxy(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestProxyOverKCP(t *testing.T) {
|
func TestDialerProxyOverKCP(t *testing.T) {
|
||||||
tcpServer := tcp.Server{
|
tcpServer := tcp.Server{
|
||||||
MsgProcessor: xor,
|
MsgProcessor: xor,
|
||||||
}
|
}
|
||||||
@@ -321,11 +323,11 @@ func TestProxyOverKCP(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{
|
SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{
|
||||||
ProxySettings: &internet.ProxyConfig{
|
|
||||||
Tag: "proxy",
|
|
||||||
},
|
|
||||||
StreamSettings: &internet.StreamConfig{
|
StreamSettings: &internet.StreamConfig{
|
||||||
ProtocolName: "mkcp",
|
ProtocolName: "mkcp",
|
||||||
|
SocketSettings: &internet.SocketConfig{
|
||||||
|
DialerProxy: "proxy",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -509,7 +509,7 @@ func TestVlessXtlsVisionReality(t *testing.T) {
|
|||||||
|
|
||||||
// This testing test all known utls fingerprint in tls.PresetFingerprints that support reality (expect unsafe and random*)
|
// This testing test all known utls fingerprint in tls.PresetFingerprints that support reality (expect unsafe and random*)
|
||||||
// Beacuse figerprint support may be broken after utls/reality update
|
// Beacuse figerprint support may be broken after utls/reality update
|
||||||
// Known broken fingerprint: android, 360
|
// Known working fingerprint: chrome, firefox, safari
|
||||||
func TestVlessRealityFingerprints(t *testing.T) {
|
func TestVlessRealityFingerprints(t *testing.T) {
|
||||||
TestFingerprint := func(fingerprint string) error {
|
TestFingerprint := func(fingerprint string) error {
|
||||||
tcpServer := tcp.Server{
|
tcpServer := tcp.Server{
|
||||||
@@ -641,7 +641,7 @@ func TestVlessRealityFingerprints(t *testing.T) {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
fingerPrints := []string{"chrome", "firefox", "safari", "ios", "edge", "qq"}
|
fingerPrints := []string{"chrome", "firefox", "safari"}
|
||||||
wg := sync.WaitGroup{}
|
wg := sync.WaitGroup{}
|
||||||
wg.Add(len(fingerPrints))
|
wg.Add(len(fingerPrints))
|
||||||
for _, fp := range fingerPrints {
|
for _, fp := range fingerPrints {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ type ConfigCreator func() interface{}
|
|||||||
|
|
||||||
var globalTransportConfigCreatorCache = make(map[string]ConfigCreator)
|
var globalTransportConfigCreatorCache = make(map[string]ConfigCreator)
|
||||||
|
|
||||||
var strategy = [][]byte{
|
var strategy = [11][3]byte{
|
||||||
// name strategy, prefer, fallback
|
// name strategy, prefer, fallback
|
||||||
{0, 0, 0}, // AsIs none, /, /
|
{0, 0, 0}, // AsIs none, /, /
|
||||||
{1, 0, 0}, // UseIP use, both, none
|
{1, 0, 0}, // UseIP use, both, none
|
||||||
@@ -25,11 +25,9 @@ var strategy = [][]byte{
|
|||||||
{2, 6, 4}, // ForceIPv6v4 force, 6, 4
|
{2, 6, 4}, // ForceIPv6v4 force, 6, 4
|
||||||
}
|
}
|
||||||
|
|
||||||
const unknownProtocol = "unknown"
|
|
||||||
|
|
||||||
func RegisterProtocolConfigCreator(name string, creator ConfigCreator) error {
|
func RegisterProtocolConfigCreator(name string, creator ConfigCreator) error {
|
||||||
if _, found := globalTransportConfigCreatorCache[name]; found {
|
if _, found := globalTransportConfigCreatorCache[name]; found {
|
||||||
return errors.New("protocol ", name, " is already registered").AtError()
|
return errors.New("protocol ", name, " is already registered")
|
||||||
}
|
}
|
||||||
globalTransportConfigCreatorCache[name] = creator
|
globalTransportConfigCreatorCache[name] = creator
|
||||||
return nil
|
return nil
|
||||||
@@ -91,10 +89,6 @@ func (c *StreamConfig) HasSecuritySettings() bool {
|
|||||||
return len(c.SecuritySettings) > 0
|
return len(c.SecuritySettings) > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ProxyConfig) HasTag() bool {
|
|
||||||
return c != nil && len(c.Tag) > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m SocketConfig_TProxyMode) IsEnabled() bool {
|
func (m SocketConfig_TProxyMode) IsEnabled() bool {
|
||||||
return m != SocketConfig_Off
|
return m != SocketConfig_Off
|
||||||
}
|
}
|
||||||
|
|||||||
+63
-194
@@ -206,7 +206,7 @@ func (x SocketConfig_TProxyMode) Number() protoreflect.EnumNumber {
|
|||||||
|
|
||||||
// Deprecated: Use SocketConfig_TProxyMode.Descriptor instead.
|
// Deprecated: Use SocketConfig_TProxyMode.Descriptor instead.
|
||||||
func (SocketConfig_TProxyMode) EnumDescriptor() ([]byte, []int) {
|
func (SocketConfig_TProxyMode) EnumDescriptor() ([]byte, []int) {
|
||||||
return file_transport_internet_config_proto_rawDescGZIP(), []int{6, 0}
|
return file_transport_internet_config_proto_rawDescGZIP(), []int{4, 0}
|
||||||
}
|
}
|
||||||
|
|
||||||
type TransportConfig struct {
|
type TransportConfig struct {
|
||||||
@@ -382,66 +382,6 @@ func (x *StreamConfig) GetSocketSettings() *SocketConfig {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type UdpHop struct {
|
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
|
||||||
Ports []uint32 `protobuf:"varint,1,rep,packed,name=ports,proto3" json:"ports,omitempty"`
|
|
||||||
IntervalMin int64 `protobuf:"varint,2,opt,name=interval_min,json=intervalMin,proto3" json:"interval_min,omitempty"`
|
|
||||||
IntervalMax int64 `protobuf:"varint,3,opt,name=interval_max,json=intervalMax,proto3" json:"interval_max,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *UdpHop) Reset() {
|
|
||||||
*x = UdpHop{}
|
|
||||||
mi := &file_transport_internet_config_proto_msgTypes[2]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *UdpHop) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*UdpHop) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *UdpHop) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_transport_internet_config_proto_msgTypes[2]
|
|
||||||
if x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use UdpHop.ProtoReflect.Descriptor instead.
|
|
||||||
func (*UdpHop) Descriptor() ([]byte, []int) {
|
|
||||||
return file_transport_internet_config_proto_rawDescGZIP(), []int{2}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *UdpHop) GetPorts() []uint32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.Ports
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *UdpHop) GetIntervalMin() int64 {
|
|
||||||
if x != nil {
|
|
||||||
return x.IntervalMin
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *UdpHop) GetIntervalMax() int64 {
|
|
||||||
if x != nil {
|
|
||||||
return x.IntervalMax
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
type QuicParams struct {
|
type QuicParams struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
Congestion string `protobuf:"bytes,1,opt,name=congestion,proto3" json:"congestion,omitempty"`
|
Congestion string `protobuf:"bytes,1,opt,name=congestion,proto3" json:"congestion,omitempty"`
|
||||||
@@ -449,25 +389,24 @@ type QuicParams struct {
|
|||||||
BrutalUp uint64 `protobuf:"varint,3,opt,name=brutal_up,json=brutalUp,proto3" json:"brutal_up,omitempty"`
|
BrutalUp uint64 `protobuf:"varint,3,opt,name=brutal_up,json=brutalUp,proto3" json:"brutal_up,omitempty"`
|
||||||
BrutalDown uint64 `protobuf:"varint,4,opt,name=brutal_down,json=brutalDown,proto3" json:"brutal_down,omitempty"`
|
BrutalDown uint64 `protobuf:"varint,4,opt,name=brutal_down,json=brutalDown,proto3" json:"brutal_down,omitempty"`
|
||||||
BrutalDisableLossCompensation bool `protobuf:"varint,5,opt,name=brutal_disable_loss_compensation,json=brutalDisableLossCompensation,proto3" json:"brutal_disable_loss_compensation,omitempty"`
|
BrutalDisableLossCompensation bool `protobuf:"varint,5,opt,name=brutal_disable_loss_compensation,json=brutalDisableLossCompensation,proto3" json:"brutal_disable_loss_compensation,omitempty"`
|
||||||
UdpHop *UdpHop `protobuf:"bytes,6,opt,name=udp_hop,json=udpHop,proto3" json:"udp_hop,omitempty"`
|
InitStreamReceiveWindow uint64 `protobuf:"varint,6,opt,name=init_stream_receive_window,json=initStreamReceiveWindow,proto3" json:"init_stream_receive_window,omitempty"`
|
||||||
InitStreamReceiveWindow uint64 `protobuf:"varint,7,opt,name=init_stream_receive_window,json=initStreamReceiveWindow,proto3" json:"init_stream_receive_window,omitempty"`
|
MaxStreamReceiveWindow uint64 `protobuf:"varint,7,opt,name=max_stream_receive_window,json=maxStreamReceiveWindow,proto3" json:"max_stream_receive_window,omitempty"`
|
||||||
MaxStreamReceiveWindow uint64 `protobuf:"varint,8,opt,name=max_stream_receive_window,json=maxStreamReceiveWindow,proto3" json:"max_stream_receive_window,omitempty"`
|
InitConnReceiveWindow uint64 `protobuf:"varint,8,opt,name=init_conn_receive_window,json=initConnReceiveWindow,proto3" json:"init_conn_receive_window,omitempty"`
|
||||||
InitConnReceiveWindow uint64 `protobuf:"varint,9,opt,name=init_conn_receive_window,json=initConnReceiveWindow,proto3" json:"init_conn_receive_window,omitempty"`
|
MaxConnReceiveWindow uint64 `protobuf:"varint,9,opt,name=max_conn_receive_window,json=maxConnReceiveWindow,proto3" json:"max_conn_receive_window,omitempty"`
|
||||||
MaxConnReceiveWindow uint64 `protobuf:"varint,10,opt,name=max_conn_receive_window,json=maxConnReceiveWindow,proto3" json:"max_conn_receive_window,omitempty"`
|
MaxIdleTimeout int64 `protobuf:"varint,10,opt,name=max_idle_timeout,json=maxIdleTimeout,proto3" json:"max_idle_timeout,omitempty"`
|
||||||
MaxIdleTimeout int64 `protobuf:"varint,11,opt,name=max_idle_timeout,json=maxIdleTimeout,proto3" json:"max_idle_timeout,omitempty"`
|
KeepAlivePeriod int64 `protobuf:"varint,11,opt,name=keep_alive_period,json=keepAlivePeriod,proto3" json:"keep_alive_period,omitempty"`
|
||||||
KeepAlivePeriod int64 `protobuf:"varint,12,opt,name=keep_alive_period,json=keepAlivePeriod,proto3" json:"keep_alive_period,omitempty"`
|
DisablePathMtuDiscovery bool `protobuf:"varint,12,opt,name=disable_path_mtu_discovery,json=disablePathMtuDiscovery,proto3" json:"disable_path_mtu_discovery,omitempty"`
|
||||||
DisablePathMtuDiscovery bool `protobuf:"varint,13,opt,name=disable_path_mtu_discovery,json=disablePathMtuDiscovery,proto3" json:"disable_path_mtu_discovery,omitempty"`
|
DisableChromeParrot bool `protobuf:"varint,13,opt,name=disable_chrome_parrot,json=disableChromeParrot,proto3" json:"disable_chrome_parrot,omitempty"`
|
||||||
DisableChromeParrot bool `protobuf:"varint,14,opt,name=disable_chrome_parrot,json=disableChromeParrot,proto3" json:"disable_chrome_parrot,omitempty"`
|
DisableGSO bool `protobuf:"varint,14,opt,name=disableGSO,proto3" json:"disableGSO,omitempty"`
|
||||||
DisableGSO bool `protobuf:"varint,15,opt,name=disableGSO,proto3" json:"disableGSO,omitempty"`
|
MaxIncomingStreams int64 `protobuf:"varint,15,opt,name=max_incoming_streams,json=maxIncomingStreams,proto3" json:"max_incoming_streams,omitempty"`
|
||||||
MaxIncomingStreams int64 `protobuf:"varint,16,opt,name=max_incoming_streams,json=maxIncomingStreams,proto3" json:"max_incoming_streams,omitempty"`
|
DisableStatelessReset bool `protobuf:"varint,16,opt,name=disable_stateless_reset,json=disableStatelessReset,proto3" json:"disable_stateless_reset,omitempty"`
|
||||||
DisableStatelessReset bool `protobuf:"varint,17,opt,name=disable_stateless_reset,json=disableStatelessReset,proto3" json:"disable_stateless_reset,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *QuicParams) Reset() {
|
func (x *QuicParams) Reset() {
|
||||||
*x = QuicParams{}
|
*x = QuicParams{}
|
||||||
mi := &file_transport_internet_config_proto_msgTypes[3]
|
mi := &file_transport_internet_config_proto_msgTypes[2]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -479,7 +418,7 @@ func (x *QuicParams) String() string {
|
|||||||
func (*QuicParams) ProtoMessage() {}
|
func (*QuicParams) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *QuicParams) ProtoReflect() protoreflect.Message {
|
func (x *QuicParams) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_transport_internet_config_proto_msgTypes[3]
|
mi := &file_transport_internet_config_proto_msgTypes[2]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -492,7 +431,7 @@ func (x *QuicParams) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use QuicParams.ProtoReflect.Descriptor instead.
|
// Deprecated: Use QuicParams.ProtoReflect.Descriptor instead.
|
||||||
func (*QuicParams) Descriptor() ([]byte, []int) {
|
func (*QuicParams) Descriptor() ([]byte, []int) {
|
||||||
return file_transport_internet_config_proto_rawDescGZIP(), []int{3}
|
return file_transport_internet_config_proto_rawDescGZIP(), []int{2}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *QuicParams) GetCongestion() string {
|
func (x *QuicParams) GetCongestion() string {
|
||||||
@@ -530,13 +469,6 @@ func (x *QuicParams) GetBrutalDisableLossCompensation() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *QuicParams) GetUdpHop() *UdpHop {
|
|
||||||
if x != nil {
|
|
||||||
return x.UdpHop
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *QuicParams) GetInitStreamReceiveWindow() uint64 {
|
func (x *QuicParams) GetInitStreamReceiveWindow() uint64 {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.InitStreamReceiveWindow
|
return x.InitStreamReceiveWindow
|
||||||
@@ -614,58 +546,6 @@ func (x *QuicParams) GetDisableStatelessReset() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProxyConfig struct {
|
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
|
||||||
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
|
|
||||||
TransportLayerProxy bool `protobuf:"varint,2,opt,name=transportLayerProxy,proto3" json:"transportLayerProxy,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *ProxyConfig) Reset() {
|
|
||||||
*x = ProxyConfig{}
|
|
||||||
mi := &file_transport_internet_config_proto_msgTypes[4]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *ProxyConfig) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*ProxyConfig) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *ProxyConfig) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_transport_internet_config_proto_msgTypes[4]
|
|
||||||
if x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use ProxyConfig.ProtoReflect.Descriptor instead.
|
|
||||||
func (*ProxyConfig) Descriptor() ([]byte, []int) {
|
|
||||||
return file_transport_internet_config_proto_rawDescGZIP(), []int{4}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *ProxyConfig) GetTag() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Tag
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *ProxyConfig) GetTransportLayerProxy() bool {
|
|
||||||
if x != nil {
|
|
||||||
return x.TransportLayerProxy
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
type CustomSockopt struct {
|
type CustomSockopt struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
System string `protobuf:"bytes,1,opt,name=system,proto3" json:"system,omitempty"`
|
System string `protobuf:"bytes,1,opt,name=system,proto3" json:"system,omitempty"`
|
||||||
@@ -680,7 +560,7 @@ type CustomSockopt struct {
|
|||||||
|
|
||||||
func (x *CustomSockopt) Reset() {
|
func (x *CustomSockopt) Reset() {
|
||||||
*x = CustomSockopt{}
|
*x = CustomSockopt{}
|
||||||
mi := &file_transport_internet_config_proto_msgTypes[5]
|
mi := &file_transport_internet_config_proto_msgTypes[3]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -692,7 +572,7 @@ func (x *CustomSockopt) String() string {
|
|||||||
func (*CustomSockopt) ProtoMessage() {}
|
func (*CustomSockopt) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *CustomSockopt) ProtoReflect() protoreflect.Message {
|
func (x *CustomSockopt) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_transport_internet_config_proto_msgTypes[5]
|
mi := &file_transport_internet_config_proto_msgTypes[3]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -705,7 +585,7 @@ func (x *CustomSockopt) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use CustomSockopt.ProtoReflect.Descriptor instead.
|
// Deprecated: Use CustomSockopt.ProtoReflect.Descriptor instead.
|
||||||
func (*CustomSockopt) Descriptor() ([]byte, []int) {
|
func (*CustomSockopt) Descriptor() ([]byte, []int) {
|
||||||
return file_transport_internet_config_proto_rawDescGZIP(), []int{5}
|
return file_transport_internet_config_proto_rawDescGZIP(), []int{3}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *CustomSockopt) GetSystem() string {
|
func (x *CustomSockopt) GetSystem() string {
|
||||||
@@ -785,7 +665,7 @@ type SocketConfig struct {
|
|||||||
|
|
||||||
func (x *SocketConfig) Reset() {
|
func (x *SocketConfig) Reset() {
|
||||||
*x = SocketConfig{}
|
*x = SocketConfig{}
|
||||||
mi := &file_transport_internet_config_proto_msgTypes[6]
|
mi := &file_transport_internet_config_proto_msgTypes[4]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -797,7 +677,7 @@ func (x *SocketConfig) String() string {
|
|||||||
func (*SocketConfig) ProtoMessage() {}
|
func (*SocketConfig) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *SocketConfig) ProtoReflect() protoreflect.Message {
|
func (x *SocketConfig) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_transport_internet_config_proto_msgTypes[6]
|
mi := &file_transport_internet_config_proto_msgTypes[4]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -810,7 +690,7 @@ func (x *SocketConfig) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use SocketConfig.ProtoReflect.Descriptor instead.
|
// Deprecated: Use SocketConfig.ProtoReflect.Descriptor instead.
|
||||||
func (*SocketConfig) Descriptor() ([]byte, []int) {
|
func (*SocketConfig) Descriptor() ([]byte, []int) {
|
||||||
return file_transport_internet_config_proto_rawDescGZIP(), []int{6}
|
return file_transport_internet_config_proto_rawDescGZIP(), []int{4}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *SocketConfig) GetMark() int32 {
|
func (x *SocketConfig) GetMark() int32 {
|
||||||
@@ -972,7 +852,7 @@ type HappyEyeballsConfig struct {
|
|||||||
|
|
||||||
func (x *HappyEyeballsConfig) Reset() {
|
func (x *HappyEyeballsConfig) Reset() {
|
||||||
*x = HappyEyeballsConfig{}
|
*x = HappyEyeballsConfig{}
|
||||||
mi := &file_transport_internet_config_proto_msgTypes[7]
|
mi := &file_transport_internet_config_proto_msgTypes[5]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -984,7 +864,7 @@ func (x *HappyEyeballsConfig) String() string {
|
|||||||
func (*HappyEyeballsConfig) ProtoMessage() {}
|
func (*HappyEyeballsConfig) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *HappyEyeballsConfig) ProtoReflect() protoreflect.Message {
|
func (x *HappyEyeballsConfig) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_transport_internet_config_proto_msgTypes[7]
|
mi := &file_transport_internet_config_proto_msgTypes[5]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -997,7 +877,7 @@ func (x *HappyEyeballsConfig) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use HappyEyeballsConfig.ProtoReflect.Descriptor instead.
|
// Deprecated: Use HappyEyeballsConfig.ProtoReflect.Descriptor instead.
|
||||||
func (*HappyEyeballsConfig) Descriptor() ([]byte, []int) {
|
func (*HappyEyeballsConfig) Descriptor() ([]byte, []int) {
|
||||||
return file_transport_internet_config_proto_rawDescGZIP(), []int{7}
|
return file_transport_internet_config_proto_rawDescGZIP(), []int{5}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *HappyEyeballsConfig) GetPrioritizeIpv6() bool {
|
func (x *HappyEyeballsConfig) GetPrioritizeIpv6() bool {
|
||||||
@@ -1048,11 +928,7 @@ const file_transport_internet_config_proto_rawDesc = "" +
|
|||||||
"\btcpmasks\x18\v \x03(\v2 .xray.common.serial.TypedMessageR\btcpmasks\x12D\n" +
|
"\btcpmasks\x18\v \x03(\v2 .xray.common.serial.TypedMessageR\btcpmasks\x12D\n" +
|
||||||
"\vquic_params\x18\f \x01(\v2#.xray.transport.internet.QuicParamsR\n" +
|
"\vquic_params\x18\f \x01(\v2#.xray.transport.internet.QuicParamsR\n" +
|
||||||
"quicParams\x12N\n" +
|
"quicParams\x12N\n" +
|
||||||
"\x0fsocket_settings\x18\x06 \x01(\v2%.xray.transport.internet.SocketConfigR\x0esocketSettings\"d\n" +
|
"\x0fsocket_settings\x18\x06 \x01(\v2%.xray.transport.internet.SocketConfigR\x0esocketSettings\"\x8d\x06\n" +
|
||||||
"\x06UdpHop\x12\x14\n" +
|
|
||||||
"\x05ports\x18\x01 \x03(\rR\x05ports\x12!\n" +
|
|
||||||
"\finterval_min\x18\x02 \x01(\x03R\vintervalMin\x12!\n" +
|
|
||||||
"\finterval_max\x18\x03 \x01(\x03R\vintervalMax\"\xc7\x06\n" +
|
|
||||||
"\n" +
|
"\n" +
|
||||||
"QuicParams\x12\x1e\n" +
|
"QuicParams\x12\x1e\n" +
|
||||||
"\n" +
|
"\n" +
|
||||||
@@ -1063,25 +939,21 @@ const file_transport_internet_config_proto_rawDesc = "" +
|
|||||||
"\tbrutal_up\x18\x03 \x01(\x04R\bbrutalUp\x12\x1f\n" +
|
"\tbrutal_up\x18\x03 \x01(\x04R\bbrutalUp\x12\x1f\n" +
|
||||||
"\vbrutal_down\x18\x04 \x01(\x04R\n" +
|
"\vbrutal_down\x18\x04 \x01(\x04R\n" +
|
||||||
"brutalDown\x12G\n" +
|
"brutalDown\x12G\n" +
|
||||||
" brutal_disable_loss_compensation\x18\x05 \x01(\bR\x1dbrutalDisableLossCompensation\x128\n" +
|
" brutal_disable_loss_compensation\x18\x05 \x01(\bR\x1dbrutalDisableLossCompensation\x12;\n" +
|
||||||
"\audp_hop\x18\x06 \x01(\v2\x1f.xray.transport.internet.UdpHopR\x06udpHop\x12;\n" +
|
"\x1ainit_stream_receive_window\x18\x06 \x01(\x04R\x17initStreamReceiveWindow\x129\n" +
|
||||||
"\x1ainit_stream_receive_window\x18\a \x01(\x04R\x17initStreamReceiveWindow\x129\n" +
|
"\x19max_stream_receive_window\x18\a \x01(\x04R\x16maxStreamReceiveWindow\x127\n" +
|
||||||
"\x19max_stream_receive_window\x18\b \x01(\x04R\x16maxStreamReceiveWindow\x127\n" +
|
"\x18init_conn_receive_window\x18\b \x01(\x04R\x15initConnReceiveWindow\x125\n" +
|
||||||
"\x18init_conn_receive_window\x18\t \x01(\x04R\x15initConnReceiveWindow\x125\n" +
|
"\x17max_conn_receive_window\x18\t \x01(\x04R\x14maxConnReceiveWindow\x12(\n" +
|
||||||
"\x17max_conn_receive_window\x18\n" +
|
"\x10max_idle_timeout\x18\n" +
|
||||||
" \x01(\x04R\x14maxConnReceiveWindow\x12(\n" +
|
" \x01(\x03R\x0emaxIdleTimeout\x12*\n" +
|
||||||
"\x10max_idle_timeout\x18\v \x01(\x03R\x0emaxIdleTimeout\x12*\n" +
|
"\x11keep_alive_period\x18\v \x01(\x03R\x0fkeepAlivePeriod\x12;\n" +
|
||||||
"\x11keep_alive_period\x18\f \x01(\x03R\x0fkeepAlivePeriod\x12;\n" +
|
"\x1adisable_path_mtu_discovery\x18\f \x01(\bR\x17disablePathMtuDiscovery\x122\n" +
|
||||||
"\x1adisable_path_mtu_discovery\x18\r \x01(\bR\x17disablePathMtuDiscovery\x122\n" +
|
"\x15disable_chrome_parrot\x18\r \x01(\bR\x13disableChromeParrot\x12\x1e\n" +
|
||||||
"\x15disable_chrome_parrot\x18\x0e \x01(\bR\x13disableChromeParrot\x12\x1e\n" +
|
|
||||||
"\n" +
|
"\n" +
|
||||||
"disableGSO\x18\x0f \x01(\bR\n" +
|
"disableGSO\x18\x0e \x01(\bR\n" +
|
||||||
"disableGSO\x120\n" +
|
"disableGSO\x120\n" +
|
||||||
"\x14max_incoming_streams\x18\x10 \x01(\x03R\x12maxIncomingStreams\x126\n" +
|
"\x14max_incoming_streams\x18\x0f \x01(\x03R\x12maxIncomingStreams\x126\n" +
|
||||||
"\x17disable_stateless_reset\x18\x11 \x01(\bR\x15disableStatelessReset\"Q\n" +
|
"\x17disable_stateless_reset\x18\x10 \x01(\bR\x15disableStatelessReset\"\x93\x01\n" +
|
||||||
"\vProxyConfig\x12\x10\n" +
|
|
||||||
"\x03tag\x18\x01 \x01(\tR\x03tag\x120\n" +
|
|
||||||
"\x13transportLayerProxy\x18\x02 \x01(\bR\x13transportLayerProxy\"\x93\x01\n" +
|
|
||||||
"\rCustomSockopt\x12\x16\n" +
|
"\rCustomSockopt\x12\x16\n" +
|
||||||
"\x06system\x18\x01 \x01(\tR\x06system\x12\x18\n" +
|
"\x06system\x18\x01 \x01(\tR\x06system\x12\x18\n" +
|
||||||
"\anetwork\x18\x02 \x01(\tR\anetwork\x12\x14\n" +
|
"\anetwork\x18\x02 \x01(\tR\anetwork\x12\x14\n" +
|
||||||
@@ -1165,42 +1037,39 @@ func file_transport_internet_config_proto_rawDescGZIP() []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var file_transport_internet_config_proto_enumTypes = make([]protoimpl.EnumInfo, 3)
|
var file_transport_internet_config_proto_enumTypes = make([]protoimpl.EnumInfo, 3)
|
||||||
var file_transport_internet_config_proto_msgTypes = make([]protoimpl.MessageInfo, 8)
|
var file_transport_internet_config_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
|
||||||
var file_transport_internet_config_proto_goTypes = []any{
|
var file_transport_internet_config_proto_goTypes = []any{
|
||||||
(DomainStrategy)(0), // 0: xray.transport.internet.DomainStrategy
|
(DomainStrategy)(0), // 0: xray.transport.internet.DomainStrategy
|
||||||
(AddressPortStrategy)(0), // 1: xray.transport.internet.AddressPortStrategy
|
(AddressPortStrategy)(0), // 1: xray.transport.internet.AddressPortStrategy
|
||||||
(SocketConfig_TProxyMode)(0), // 2: xray.transport.internet.SocketConfig.TProxyMode
|
(SocketConfig_TProxyMode)(0), // 2: xray.transport.internet.SocketConfig.TProxyMode
|
||||||
(*TransportConfig)(nil), // 3: xray.transport.internet.TransportConfig
|
(*TransportConfig)(nil), // 3: xray.transport.internet.TransportConfig
|
||||||
(*StreamConfig)(nil), // 4: xray.transport.internet.StreamConfig
|
(*StreamConfig)(nil), // 4: xray.transport.internet.StreamConfig
|
||||||
(*UdpHop)(nil), // 5: xray.transport.internet.UdpHop
|
(*QuicParams)(nil), // 5: xray.transport.internet.QuicParams
|
||||||
(*QuicParams)(nil), // 6: xray.transport.internet.QuicParams
|
(*CustomSockopt)(nil), // 6: xray.transport.internet.CustomSockopt
|
||||||
(*ProxyConfig)(nil), // 7: xray.transport.internet.ProxyConfig
|
(*SocketConfig)(nil), // 7: xray.transport.internet.SocketConfig
|
||||||
(*CustomSockopt)(nil), // 8: xray.transport.internet.CustomSockopt
|
(*HappyEyeballsConfig)(nil), // 8: xray.transport.internet.HappyEyeballsConfig
|
||||||
(*SocketConfig)(nil), // 9: xray.transport.internet.SocketConfig
|
(*serial.TypedMessage)(nil), // 9: xray.common.serial.TypedMessage
|
||||||
(*HappyEyeballsConfig)(nil), // 10: xray.transport.internet.HappyEyeballsConfig
|
(*net.IPOrDomain)(nil), // 10: xray.common.net.IPOrDomain
|
||||||
(*serial.TypedMessage)(nil), // 11: xray.common.serial.TypedMessage
|
|
||||||
(*net.IPOrDomain)(nil), // 12: xray.common.net.IPOrDomain
|
|
||||||
}
|
}
|
||||||
var file_transport_internet_config_proto_depIdxs = []int32{
|
var file_transport_internet_config_proto_depIdxs = []int32{
|
||||||
11, // 0: xray.transport.internet.TransportConfig.settings:type_name -> xray.common.serial.TypedMessage
|
9, // 0: xray.transport.internet.TransportConfig.settings:type_name -> xray.common.serial.TypedMessage
|
||||||
12, // 1: xray.transport.internet.StreamConfig.address:type_name -> xray.common.net.IPOrDomain
|
10, // 1: xray.transport.internet.StreamConfig.address:type_name -> xray.common.net.IPOrDomain
|
||||||
3, // 2: xray.transport.internet.StreamConfig.transport_settings:type_name -> xray.transport.internet.TransportConfig
|
3, // 2: xray.transport.internet.StreamConfig.transport_settings:type_name -> xray.transport.internet.TransportConfig
|
||||||
11, // 3: xray.transport.internet.StreamConfig.security_settings:type_name -> xray.common.serial.TypedMessage
|
9, // 3: xray.transport.internet.StreamConfig.security_settings:type_name -> xray.common.serial.TypedMessage
|
||||||
11, // 4: xray.transport.internet.StreamConfig.udpmasks:type_name -> xray.common.serial.TypedMessage
|
9, // 4: xray.transport.internet.StreamConfig.udpmasks:type_name -> xray.common.serial.TypedMessage
|
||||||
11, // 5: xray.transport.internet.StreamConfig.tcpmasks:type_name -> xray.common.serial.TypedMessage
|
9, // 5: xray.transport.internet.StreamConfig.tcpmasks:type_name -> xray.common.serial.TypedMessage
|
||||||
6, // 6: xray.transport.internet.StreamConfig.quic_params:type_name -> xray.transport.internet.QuicParams
|
5, // 6: xray.transport.internet.StreamConfig.quic_params:type_name -> xray.transport.internet.QuicParams
|
||||||
9, // 7: xray.transport.internet.StreamConfig.socket_settings:type_name -> xray.transport.internet.SocketConfig
|
7, // 7: xray.transport.internet.StreamConfig.socket_settings:type_name -> xray.transport.internet.SocketConfig
|
||||||
5, // 8: xray.transport.internet.QuicParams.udp_hop:type_name -> xray.transport.internet.UdpHop
|
2, // 8: xray.transport.internet.SocketConfig.tproxy:type_name -> xray.transport.internet.SocketConfig.TProxyMode
|
||||||
2, // 9: xray.transport.internet.SocketConfig.tproxy:type_name -> xray.transport.internet.SocketConfig.TProxyMode
|
0, // 9: xray.transport.internet.SocketConfig.domain_strategy:type_name -> xray.transport.internet.DomainStrategy
|
||||||
0, // 10: xray.transport.internet.SocketConfig.domain_strategy:type_name -> xray.transport.internet.DomainStrategy
|
6, // 10: xray.transport.internet.SocketConfig.customSockopt:type_name -> xray.transport.internet.CustomSockopt
|
||||||
8, // 11: xray.transport.internet.SocketConfig.customSockopt:type_name -> xray.transport.internet.CustomSockopt
|
1, // 11: xray.transport.internet.SocketConfig.address_port_strategy:type_name -> xray.transport.internet.AddressPortStrategy
|
||||||
1, // 12: xray.transport.internet.SocketConfig.address_port_strategy:type_name -> xray.transport.internet.AddressPortStrategy
|
8, // 12: xray.transport.internet.SocketConfig.happy_eyeballs:type_name -> xray.transport.internet.HappyEyeballsConfig
|
||||||
10, // 13: xray.transport.internet.SocketConfig.happy_eyeballs:type_name -> xray.transport.internet.HappyEyeballsConfig
|
13, // [13:13] is the sub-list for method output_type
|
||||||
14, // [14:14] is the sub-list for method output_type
|
13, // [13:13] is the sub-list for method input_type
|
||||||
14, // [14:14] is the sub-list for method input_type
|
13, // [13:13] is the sub-list for extension type_name
|
||||||
14, // [14:14] is the sub-list for extension type_name
|
13, // [13:13] is the sub-list for extension extendee
|
||||||
14, // [14:14] is the sub-list for extension extendee
|
0, // [0:13] is the sub-list for field type_name
|
||||||
0, // [0:14] is the sub-list for field type_name
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { file_transport_internet_config_proto_init() }
|
func init() { file_transport_internet_config_proto_init() }
|
||||||
@@ -1214,7 +1083,7 @@ func file_transport_internet_config_proto_init() {
|
|||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_transport_internet_config_proto_rawDesc), len(file_transport_internet_config_proto_rawDesc)),
|
RawDescriptor: unsafe.Slice(unsafe.StringData(file_transport_internet_config_proto_rawDesc), len(file_transport_internet_config_proto_rawDesc)),
|
||||||
NumEnums: 3,
|
NumEnums: 3,
|
||||||
NumMessages: 8,
|
NumMessages: 6,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
NumServices: 0,
|
NumServices: 0,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -64,35 +64,23 @@ message StreamConfig {
|
|||||||
SocketConfig socket_settings = 6;
|
SocketConfig socket_settings = 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
message UdpHop {
|
|
||||||
repeated uint32 ports = 1;
|
|
||||||
int64 interval_min = 2;
|
|
||||||
int64 interval_max = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
message QuicParams {
|
message QuicParams {
|
||||||
string congestion = 1;
|
string congestion = 1;
|
||||||
string bbr_profile = 2;
|
string bbr_profile = 2;
|
||||||
uint64 brutal_up = 3;
|
uint64 brutal_up = 3;
|
||||||
uint64 brutal_down = 4;
|
uint64 brutal_down = 4;
|
||||||
bool brutal_disable_loss_compensation = 5;
|
bool brutal_disable_loss_compensation = 5;
|
||||||
UdpHop udp_hop = 6;
|
uint64 init_stream_receive_window = 6;
|
||||||
uint64 init_stream_receive_window = 7;
|
uint64 max_stream_receive_window = 7;
|
||||||
uint64 max_stream_receive_window = 8;
|
uint64 init_conn_receive_window = 8;
|
||||||
uint64 init_conn_receive_window = 9;
|
uint64 max_conn_receive_window = 9;
|
||||||
uint64 max_conn_receive_window = 10;
|
int64 max_idle_timeout = 10;
|
||||||
int64 max_idle_timeout = 11;
|
int64 keep_alive_period = 11;
|
||||||
int64 keep_alive_period = 12;
|
bool disable_path_mtu_discovery = 12;
|
||||||
bool disable_path_mtu_discovery = 13;
|
bool disable_chrome_parrot = 13;
|
||||||
bool disable_chrome_parrot = 14;
|
bool disableGSO = 14;
|
||||||
bool disableGSO = 15;
|
int64 max_incoming_streams = 15;
|
||||||
int64 max_incoming_streams = 16;
|
bool disable_stateless_reset = 16;
|
||||||
bool disable_stateless_reset = 17;
|
|
||||||
}
|
|
||||||
|
|
||||||
message ProxyConfig {
|
|
||||||
string tag = 1;
|
|
||||||
bool transportLayerProxy = 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message CustomSockopt {
|
message CustomSockopt {
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ var transportDialerCache = make(map[string]dialFunc)
|
|||||||
// RegisterTransportDialer registers a Dialer with given name.
|
// RegisterTransportDialer registers a Dialer with given name.
|
||||||
func RegisterTransportDialer(protocol string, dialer dialFunc) error {
|
func RegisterTransportDialer(protocol string, dialer dialFunc) error {
|
||||||
if _, found := transportDialerCache[protocol]; found {
|
if _, found := transportDialerCache[protocol]; found {
|
||||||
return errors.New(protocol, " dialer already registered").AtError()
|
return errors.New(protocol, " dialer already registered")
|
||||||
}
|
}
|
||||||
transportDialerCache[protocol] = dialer
|
transportDialerCache[protocol] = dialer
|
||||||
return nil
|
return nil
|
||||||
@@ -58,7 +58,7 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *MemoryStrea
|
|||||||
protocol := streamSettings.ProtocolName
|
protocol := streamSettings.ProtocolName
|
||||||
dialer := transportDialerCache[protocol]
|
dialer := transportDialerCache[protocol]
|
||||||
if dialer == nil {
|
if dialer == nil {
|
||||||
return nil, errors.New(protocol, " dialer not registered").AtError()
|
return nil, errors.New(protocol, " dialer not registered")
|
||||||
}
|
}
|
||||||
return dialer(ctx, dest, streamSettings)
|
return dialer(ctx, dest, streamSettings)
|
||||||
}
|
}
|
||||||
@@ -66,7 +66,7 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *MemoryStrea
|
|||||||
if dest.Network == net.Network_UDP {
|
if dest.Network == net.Network_UDP {
|
||||||
udpDialer := transportDialerCache["udp"]
|
udpDialer := transportDialerCache["udp"]
|
||||||
if udpDialer == nil {
|
if udpDialer == nil {
|
||||||
return nil, errors.New("UDP dialer not registered").AtError()
|
return nil, errors.New("UDP dialer not registered")
|
||||||
}
|
}
|
||||||
return udpDialer(ctx, dest, streamSettings)
|
return udpDialer(ctx, dest, streamSettings)
|
||||||
}
|
}
|
||||||
@@ -86,7 +86,7 @@ var (
|
|||||||
|
|
||||||
func LookupForIP(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 {
|
if dnsClient == nil {
|
||||||
return nil, errors.New("DNS client not initialized").AtError()
|
return nil, errors.New("DNS client not initialized")
|
||||||
}
|
}
|
||||||
|
|
||||||
ips, _, err := dnsClient.LookupIP(domain, dns.IPOption{
|
ips, _, err := dnsClient.LookupIP(domain, dns.IPOption{
|
||||||
@@ -269,11 +269,11 @@ func DialSystem(ctx context.Context, dest net.Destination, sockopt *SocketConfig
|
|||||||
|
|
||||||
if len(sockopt.DialerProxy) > 0 {
|
if len(sockopt.DialerProxy) > 0 {
|
||||||
if obm == nil {
|
if obm == nil {
|
||||||
return nil, errors.New("there is no outbound manager for dialerProxy").AtError()
|
return nil, errors.New("there is no outbound manager for dialerProxy")
|
||||||
}
|
}
|
||||||
h := obm.GetHandler(sockopt.DialerProxy)
|
h := obm.GetHandler(sockopt.DialerProxy)
|
||||||
if h == nil {
|
if h == nil {
|
||||||
return nil, errors.New("there is no outbound handler for dialerProxy").AtError()
|
return nil, errors.New("there is no outbound handler for dialerProxy")
|
||||||
}
|
}
|
||||||
return redirect(ctx, dest, sockopt.DialerProxy, h), nil
|
return redirect(ctx, dest, sockopt.DialerProxy, h), nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,8 +10,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Udpmask interface {
|
type Udpmask interface {
|
||||||
UDP()
|
|
||||||
|
|
||||||
WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error)
|
WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error)
|
||||||
WrapPacketConnServer(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error)
|
WrapPacketConnServer(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error)
|
||||||
}
|
}
|
||||||
@@ -21,15 +19,14 @@ type UdpmaskManager struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewUdpmaskManager(udpmasks []Udpmask) *UdpmaskManager {
|
func NewUdpmaskManager(udpmasks []Udpmask) *UdpmaskManager {
|
||||||
return &UdpmaskManager{
|
slices.Reverse(udpmasks)
|
||||||
udpmasks: udpmasks,
|
return &UdpmaskManager{udpmasks: udpmasks}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *UdpmaskManager) WrapPacketConnClient(raw net.PacketConn) (net.PacketConn, error) {
|
func (m *UdpmaskManager) WrapPacketConnClient(raw net.PacketConn) (net.PacketConn, error) {
|
||||||
var sizes []int
|
var sizes []int
|
||||||
var conns []net.PacketConn
|
var conns []net.PacketConn
|
||||||
for i, mask := range slices.Backward(m.udpmasks) {
|
for i, mask := range m.udpmasks {
|
||||||
if _, ok := mask.(headerConn); ok {
|
if _, ok := mask.(headerConn); ok {
|
||||||
conn, err := mask.WrapPacketConnClient(nil, i, len(m.udpmasks)-1)
|
conn, err := mask.WrapPacketConnClient(nil, i, len(m.udpmasks)-1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -62,7 +59,7 @@ func (m *UdpmaskManager) WrapPacketConnClient(raw net.PacketConn) (net.PacketCon
|
|||||||
func (m *UdpmaskManager) WrapPacketConnServer(raw net.PacketConn) (net.PacketConn, error) {
|
func (m *UdpmaskManager) WrapPacketConnServer(raw net.PacketConn) (net.PacketConn, error) {
|
||||||
var sizes []int
|
var sizes []int
|
||||||
var conns []net.PacketConn
|
var conns []net.PacketConn
|
||||||
for i, mask := range slices.Backward(m.udpmasks) {
|
for i, mask := range m.udpmasks {
|
||||||
if _, ok := mask.(headerConn); ok {
|
if _, ok := mask.(headerConn); ok {
|
||||||
conn, err := mask.WrapPacketConnServer(nil, i, len(m.udpmasks)-1)
|
conn, err := mask.WrapPacketConnServer(nil, i, len(m.udpmasks)-1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -195,8 +192,6 @@ func (c *headerManagerConn) WriteTo(p []byte, addr net.Addr) (n int, err error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Tcpmask interface {
|
type Tcpmask interface {
|
||||||
TCP()
|
|
||||||
|
|
||||||
WrapConnClient(net.Conn) (net.Conn, error)
|
WrapConnClient(net.Conn) (net.Conn, error)
|
||||||
WrapConnServer(net.Conn) (net.Conn, error)
|
WrapConnServer(net.Conn) (net.Conn, error)
|
||||||
}
|
}
|
||||||
@@ -206,14 +201,13 @@ type TcpmaskManager struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewTcpmaskManager(tcpmasks []Tcpmask) *TcpmaskManager {
|
func NewTcpmaskManager(tcpmasks []Tcpmask) *TcpmaskManager {
|
||||||
return &TcpmaskManager{
|
slices.Reverse(tcpmasks)
|
||||||
tcpmasks: tcpmasks,
|
return &TcpmaskManager{tcpmasks: tcpmasks}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *TcpmaskManager) WrapConnClient(raw net.Conn) (net.Conn, error) {
|
func (m *TcpmaskManager) WrapConnClient(raw net.Conn) (net.Conn, error) {
|
||||||
var err error
|
var err error
|
||||||
for _, mask := range slices.Backward(m.tcpmasks) {
|
for _, mask := range m.tcpmasks {
|
||||||
raw, err = mask.WrapConnClient(raw)
|
raw, err = mask.WrapConnClient(raw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -224,7 +218,7 @@ func (m *TcpmaskManager) WrapConnClient(raw net.Conn) (net.Conn, error) {
|
|||||||
|
|
||||||
func (m *TcpmaskManager) WrapConnServer(raw net.Conn) (net.Conn, error) {
|
func (m *TcpmaskManager) WrapConnServer(raw net.Conn) (net.Conn, error) {
|
||||||
var err error
|
var err error
|
||||||
for _, mask := range slices.Backward(m.tcpmasks) {
|
for _, mask := range m.tcpmasks {
|
||||||
raw, err = mask.WrapConnServer(raw)
|
raw, err = mask.WrapConnServer(raw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -2,9 +2,6 @@ package fragment
|
|||||||
|
|
||||||
import "net"
|
import "net"
|
||||||
|
|
||||||
func (c *Config) TCP() {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Config) WrapConnClient(raw net.Conn) (net.Conn, error) {
|
func (c *Config) WrapConnClient(raw net.Conn) (net.Conn, error) {
|
||||||
return NewConnClient(c, raw, false)
|
return NewConnClient(c, raw, false)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *TCPConfig) TCP() {}
|
|
||||||
|
|
||||||
func (c *TCPConfig) WrapConnClient(raw net.Conn) (net.Conn, error) {
|
func (c *TCPConfig) WrapConnClient(raw net.Conn) (net.Conn, error) {
|
||||||
return NewConnClientTCP(c, raw)
|
return NewConnClientTCP(c, raw)
|
||||||
}
|
}
|
||||||
@@ -14,8 +12,6 @@ func (c *TCPConfig) WrapConnServer(raw net.Conn) (net.Conn, error) {
|
|||||||
return NewConnServerTCP(c, raw)
|
return NewConnServerTCP(c, raw)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *UDPConfig) UDP() {}
|
|
||||||
|
|
||||||
func (c *UDPConfig) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
|
func (c *UDPConfig) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
|
||||||
return NewConnClientUDP(c, raw)
|
return NewConnClientUDP(c, raw)
|
||||||
}
|
}
|
||||||
@@ -24,8 +20,6 @@ func (c *UDPConfig) WrapPacketConnServer(raw net.PacketConn, level int, levelCou
|
|||||||
return NewConnServerUDP(c, raw)
|
return NewConnServerUDP(c, raw)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *UDPStandaloneConfig) UDP() {}
|
|
||||||
|
|
||||||
func (c *UDPStandaloneConfig) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
|
func (c *UDPStandaloneConfig) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
|
||||||
return NewConnClientUDPStandalone(c, raw)
|
return NewConnClientUDPStandalone(c, raw)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Config) UDP() {}
|
|
||||||
|
|
||||||
func (c *Config) HeaderConn() {}
|
func (c *Config) HeaderConn() {}
|
||||||
|
|
||||||
func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
|
func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Config) UDP() {}
|
|
||||||
|
|
||||||
func (c *Config) HeaderConn() {}
|
func (c *Config) HeaderConn() {}
|
||||||
|
|
||||||
func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
|
func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Config) UDP() {}
|
|
||||||
|
|
||||||
func (c *Config) HeaderConn() {}
|
func (c *Config) HeaderConn() {}
|
||||||
|
|
||||||
func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
|
func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
|
||||||
|
|||||||
@@ -2,9 +2,6 @@ package noise
|
|||||||
|
|
||||||
import "net"
|
import "net"
|
||||||
|
|
||||||
func (c *Config) UDP() {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
|
func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
|
||||||
return NewConnClient(c, raw)
|
return NewConnClient(c, raw)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,15 +5,11 @@ import (
|
|||||||
|
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
"github.com/xtls/xray-core/transport/internet"
|
"github.com/xtls/xray-core/transport/internet"
|
||||||
"github.com/xtls/xray-core/transport/internet/hysteria/udphop"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Config) UDP() {}
|
|
||||||
|
|
||||||
func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
|
func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
|
||||||
_, ok1 := raw.(*internet.FakePacketConn)
|
_, ok1 := raw.(*internet.FakePacketConn)
|
||||||
_, ok2 := raw.(*udphop.UdpHopPacketConn)
|
if level != 0 || ok1 {
|
||||||
if level != 0 || ok1 || ok2 {
|
|
||||||
return nil, errors.New("realm requires being at the outermost level")
|
return nil, errors.New("realm requires being at the outermost level")
|
||||||
}
|
}
|
||||||
return NewConnClient(c, raw)
|
return NewConnClient(c, raw)
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Config) UDP() {}
|
|
||||||
|
|
||||||
func (c *Config) HeaderConn() {}
|
func (c *Config) HeaderConn() {}
|
||||||
|
|
||||||
func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
|
func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
|
||||||
@@ -16,8 +14,6 @@ func (c *Config) WrapPacketConnServer(raw net.PacketConn, level int, levelCount
|
|||||||
return NewSalamanderConnServer(c, raw)
|
return NewSalamanderConnServer(c, raw)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *GeckoConfig) UDP() {}
|
|
||||||
|
|
||||||
func (c *GeckoConfig) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
|
func (c *GeckoConfig) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
|
||||||
return NewGeckoConnClient(c, raw)
|
return NewGeckoConnClient(c, raw)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,12 +6,6 @@ import (
|
|||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Config) TCP() {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Config) UDP() {
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sudoku in finalmask mode is a pure appearance transform with no standalone handshake.
|
// Sudoku in finalmask mode is a pure appearance transform with no standalone handshake.
|
||||||
// TCP always keeps classic sudoku on uplink and uses packed downlink optimization on server writes.
|
// TCP always keeps classic sudoku on uplink and uses packed downlink optimization on server writes.
|
||||||
func (c *Config) WrapConnClient(raw net.Conn) (net.Conn, error) {
|
func (c *Config) WrapConnClient(raw net.Conn) (net.Conn, error) {
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package udphop
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/xtls/xray-core/common/errors"
|
||||||
|
"github.com/xtls/xray-core/transport/internet"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
|
||||||
|
_, ok1 := raw.(*internet.FakePacketConn)
|
||||||
|
if level != 0 || ok1 {
|
||||||
|
return nil, errors.New("udphop requires being at the outermost level")
|
||||||
|
}
|
||||||
|
return NewUDPHopConn(c, raw)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) WrapPacketConnServer(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
|
||||||
|
return nil, errors.New("udphop: client only")
|
||||||
|
}
|
||||||
@@ -0,0 +1,190 @@
|
|||||||
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// protoc-gen-go v1.36.11
|
||||||
|
// protoc v6.33.5
|
||||||
|
// source: transport/internet/finalmask/udphop/config.proto
|
||||||
|
|
||||||
|
package udphop
|
||||||
|
|
||||||
|
import (
|
||||||
|
internet "github.com/xtls/xray-core/transport/internet"
|
||||||
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
|
reflect "reflect"
|
||||||
|
sync "sync"
|
||||||
|
unsafe "unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Verify that this generated code is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||||
|
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
Sockopt *internet.SocketConfig `protobuf:"bytes,1,opt,name=sockopt,proto3" json:"sockopt,omitempty"`
|
||||||
|
Local bool `protobuf:"varint,2,opt,name=local,proto3" json:"local,omitempty"`
|
||||||
|
Remote bool `protobuf:"varint,3,opt,name=remote,proto3" json:"remote,omitempty"`
|
||||||
|
RemoteOnce bool `protobuf:"varint,4,opt,name=remote_once,json=remoteOnce,proto3" json:"remote_once,omitempty"`
|
||||||
|
IntervalMin int64 `protobuf:"varint,5,opt,name=interval_min,json=intervalMin,proto3" json:"interval_min,omitempty"`
|
||||||
|
IntervalMax int64 `protobuf:"varint,6,opt,name=interval_max,json=intervalMax,proto3" json:"interval_max,omitempty"`
|
||||||
|
RemotePorts []uint32 `protobuf:"varint,7,rep,packed,name=remote_ports,json=remotePorts,proto3" json:"remote_ports,omitempty"`
|
||||||
|
RemoteIPs []string `protobuf:"bytes,8,rep,name=remoteIPs,proto3" json:"remoteIPs,omitempty"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Config) Reset() {
|
||||||
|
*x = Config{}
|
||||||
|
mi := &file_transport_internet_finalmask_udphop_config_proto_msgTypes[0]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Config) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*Config) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *Config) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_transport_internet_finalmask_udphop_config_proto_msgTypes[0]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
|
||||||
|
func (*Config) Descriptor() ([]byte, []int) {
|
||||||
|
return file_transport_internet_finalmask_udphop_config_proto_rawDescGZIP(), []int{0}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Config) GetSockopt() *internet.SocketConfig {
|
||||||
|
if x != nil {
|
||||||
|
return x.Sockopt
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Config) GetLocal() bool {
|
||||||
|
if x != nil {
|
||||||
|
return x.Local
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Config) GetRemote() bool {
|
||||||
|
if x != nil {
|
||||||
|
return x.Remote
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Config) GetRemoteOnce() bool {
|
||||||
|
if x != nil {
|
||||||
|
return x.RemoteOnce
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Config) GetIntervalMin() int64 {
|
||||||
|
if x != nil {
|
||||||
|
return x.IntervalMin
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Config) GetIntervalMax() int64 {
|
||||||
|
if x != nil {
|
||||||
|
return x.IntervalMax
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Config) GetRemotePorts() []uint32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.RemotePorts
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Config) GetRemoteIPs() []string {
|
||||||
|
if x != nil {
|
||||||
|
return x.RemoteIPs
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var File_transport_internet_finalmask_udphop_config_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
|
const file_transport_internet_finalmask_udphop_config_proto_rawDesc = "" +
|
||||||
|
"\n" +
|
||||||
|
"0transport/internet/finalmask/udphop/config.proto\x12(xray.transport.internet.finalmask.udphop\x1a\x1ftransport/internet/config.proto\"\x9f\x02\n" +
|
||||||
|
"\x06Config\x12?\n" +
|
||||||
|
"\asockopt\x18\x01 \x01(\v2%.xray.transport.internet.SocketConfigR\asockopt\x12\x14\n" +
|
||||||
|
"\x05local\x18\x02 \x01(\bR\x05local\x12\x16\n" +
|
||||||
|
"\x06remote\x18\x03 \x01(\bR\x06remote\x12\x1f\n" +
|
||||||
|
"\vremote_once\x18\x04 \x01(\bR\n" +
|
||||||
|
"remoteOnce\x12!\n" +
|
||||||
|
"\finterval_min\x18\x05 \x01(\x03R\vintervalMin\x12!\n" +
|
||||||
|
"\finterval_max\x18\x06 \x01(\x03R\vintervalMax\x12!\n" +
|
||||||
|
"\fremote_ports\x18\a \x03(\rR\vremotePorts\x12\x1c\n" +
|
||||||
|
"\tremoteIPs\x18\b \x03(\tR\tremoteIPsB\x9a\x01\n" +
|
||||||
|
",com.xray.transport.internet.finalmask.udphopP\x01Z=github.com/xtls/xray-core/transport/internet/finalmask/udphop\xaa\x02(Xray.Transport.Internet.Finalmask.Udphopb\x06proto3"
|
||||||
|
|
||||||
|
var (
|
||||||
|
file_transport_internet_finalmask_udphop_config_proto_rawDescOnce sync.Once
|
||||||
|
file_transport_internet_finalmask_udphop_config_proto_rawDescData []byte
|
||||||
|
)
|
||||||
|
|
||||||
|
func file_transport_internet_finalmask_udphop_config_proto_rawDescGZIP() []byte {
|
||||||
|
file_transport_internet_finalmask_udphop_config_proto_rawDescOnce.Do(func() {
|
||||||
|
file_transport_internet_finalmask_udphop_config_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_transport_internet_finalmask_udphop_config_proto_rawDesc), len(file_transport_internet_finalmask_udphop_config_proto_rawDesc)))
|
||||||
|
})
|
||||||
|
return file_transport_internet_finalmask_udphop_config_proto_rawDescData
|
||||||
|
}
|
||||||
|
|
||||||
|
var file_transport_internet_finalmask_udphop_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||||
|
var file_transport_internet_finalmask_udphop_config_proto_goTypes = []any{
|
||||||
|
(*Config)(nil), // 0: xray.transport.internet.finalmask.udphop.Config
|
||||||
|
(*internet.SocketConfig)(nil), // 1: xray.transport.internet.SocketConfig
|
||||||
|
}
|
||||||
|
var file_transport_internet_finalmask_udphop_config_proto_depIdxs = []int32{
|
||||||
|
1, // 0: xray.transport.internet.finalmask.udphop.Config.sockopt:type_name -> xray.transport.internet.SocketConfig
|
||||||
|
1, // [1:1] is the sub-list for method output_type
|
||||||
|
1, // [1:1] is the sub-list for method input_type
|
||||||
|
1, // [1:1] is the sub-list for extension type_name
|
||||||
|
1, // [1:1] is the sub-list for extension extendee
|
||||||
|
0, // [0:1] is the sub-list for field type_name
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() { file_transport_internet_finalmask_udphop_config_proto_init() }
|
||||||
|
func file_transport_internet_finalmask_udphop_config_proto_init() {
|
||||||
|
if File_transport_internet_finalmask_udphop_config_proto != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
type x struct{}
|
||||||
|
out := protoimpl.TypeBuilder{
|
||||||
|
File: protoimpl.DescBuilder{
|
||||||
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
|
RawDescriptor: unsafe.Slice(unsafe.StringData(file_transport_internet_finalmask_udphop_config_proto_rawDesc), len(file_transport_internet_finalmask_udphop_config_proto_rawDesc)),
|
||||||
|
NumEnums: 0,
|
||||||
|
NumMessages: 1,
|
||||||
|
NumExtensions: 0,
|
||||||
|
NumServices: 0,
|
||||||
|
},
|
||||||
|
GoTypes: file_transport_internet_finalmask_udphop_config_proto_goTypes,
|
||||||
|
DependencyIndexes: file_transport_internet_finalmask_udphop_config_proto_depIdxs,
|
||||||
|
MessageInfos: file_transport_internet_finalmask_udphop_config_proto_msgTypes,
|
||||||
|
}.Build()
|
||||||
|
File_transport_internet_finalmask_udphop_config_proto = out.File
|
||||||
|
file_transport_internet_finalmask_udphop_config_proto_goTypes = nil
|
||||||
|
file_transport_internet_finalmask_udphop_config_proto_depIdxs = nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package xray.transport.internet.finalmask.udphop;
|
||||||
|
option csharp_namespace = "Xray.Transport.Internet.Finalmask.Udphop";
|
||||||
|
option go_package = "github.com/xtls/xray-core/transport/internet/finalmask/udphop";
|
||||||
|
option java_package = "com.xray.transport.internet.finalmask.udphop";
|
||||||
|
option java_multiple_files = true;
|
||||||
|
|
||||||
|
import "transport/internet/config.proto";
|
||||||
|
|
||||||
|
message Config {
|
||||||
|
xray.transport.internet.SocketConfig sockopt = 1;
|
||||||
|
bool local = 2;
|
||||||
|
bool remote = 3;
|
||||||
|
bool remote_once = 4;
|
||||||
|
int64 interval_min = 5;
|
||||||
|
int64 interval_max = 6;
|
||||||
|
repeated uint32 remote_ports = 7;
|
||||||
|
repeated string remoteIPs = 8;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,305 @@
|
|||||||
|
package udphop
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/rand"
|
||||||
|
goerrors "errors"
|
||||||
|
"io"
|
||||||
|
mrand "math/rand"
|
||||||
|
gonet "net"
|
||||||
|
"net/netip"
|
||||||
|
"reflect"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/xtls/xray-core/common"
|
||||||
|
"github.com/xtls/xray-core/common/crypto"
|
||||||
|
"github.com/xtls/xray-core/common/errors"
|
||||||
|
"github.com/xtls/xray-core/common/net"
|
||||||
|
"github.com/xtls/xray-core/common/net/cnc"
|
||||||
|
"github.com/xtls/xray-core/transport/internet"
|
||||||
|
"github.com/xtls/xray-core/transport/internet/finalmask"
|
||||||
|
)
|
||||||
|
|
||||||
|
var pool = sync.Pool{
|
||||||
|
New: func() any {
|
||||||
|
return make([]byte, finalmask.UDPSize)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
type packet struct {
|
||||||
|
p []byte
|
||||||
|
addr net.Addr
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
type udpHopConn struct {
|
||||||
|
conn net.PacketConn
|
||||||
|
sockopt *internet.SocketConfig
|
||||||
|
local bool
|
||||||
|
remote bool
|
||||||
|
remoteOnce bool
|
||||||
|
|
||||||
|
intervalMin int64
|
||||||
|
intervalMax int64
|
||||||
|
remotePorts []uint32
|
||||||
|
remoteIPs []netip.Prefix
|
||||||
|
|
||||||
|
deadline time.Time
|
||||||
|
readDeadline time.Time
|
||||||
|
writeDeadline time.Time
|
||||||
|
|
||||||
|
pre net.PacketConn
|
||||||
|
cur net.PacketConn
|
||||||
|
addr *net.UDPAddr
|
||||||
|
readCh chan packet
|
||||||
|
closeCh chan struct{}
|
||||||
|
wg sync.WaitGroup
|
||||||
|
mu sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUDPHopConn(c *Config, raw net.PacketConn) (net.PacketConn, error) {
|
||||||
|
if c.IntervalMin < 5 || c.IntervalMax < 5 {
|
||||||
|
return nil, errors.New("invalid interval")
|
||||||
|
}
|
||||||
|
remoteIPs := make([]netip.Prefix, 0, len(c.RemoteIPs))
|
||||||
|
for _, ip := range c.RemoteIPs {
|
||||||
|
remoteIPs = append(remoteIPs, netip.MustParsePrefix(ip))
|
||||||
|
}
|
||||||
|
conn := &udpHopConn{
|
||||||
|
conn: raw,
|
||||||
|
sockopt: c.Sockopt,
|
||||||
|
local: c.Local,
|
||||||
|
remote: c.Remote,
|
||||||
|
remoteOnce: c.RemoteOnce,
|
||||||
|
|
||||||
|
intervalMin: c.IntervalMin,
|
||||||
|
intervalMax: c.IntervalMax,
|
||||||
|
remotePorts: c.RemotePorts,
|
||||||
|
remoteIPs: remoteIPs,
|
||||||
|
|
||||||
|
readCh: make(chan packet),
|
||||||
|
closeCh: make(chan struct{}),
|
||||||
|
}
|
||||||
|
return conn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *udpHopConn) closed() bool {
|
||||||
|
select {
|
||||||
|
case <-c.closeCh:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *udpHopConn) hop(addr *net.UDPAddr) {
|
||||||
|
if c.closed() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
newAddr := &net.UDPAddr{IP: addr.IP, Port: addr.Port}
|
||||||
|
newConn := c.conn
|
||||||
|
if c.remote || c.remoteOnce && c.addr == nil {
|
||||||
|
if len(c.remotePorts) > 0 {
|
||||||
|
newAddr.Port = int(c.remotePorts[mrand.Intn(len(c.remotePorts))])
|
||||||
|
}
|
||||||
|
if len(c.remoteIPs) > 0 {
|
||||||
|
newAddr.IP = randPrefix(c.remoteIPs[mrand.Intn(len(c.remoteIPs))])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if c.local {
|
||||||
|
raw, err := internet.DialSystem(context.Background(), net.UDPDestination(net.IPAddress(newAddr.IP), net.Port(newAddr.Port)), c.sockopt)
|
||||||
|
if err != nil {
|
||||||
|
errors.LogErrorInner(context.Background(), err, "hop err")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch c := raw.(type) {
|
||||||
|
case *internet.PacketConnWrapper:
|
||||||
|
newConn = c.PacketConn
|
||||||
|
case *cnc.Connection:
|
||||||
|
newConn = &internet.FakePacketConn{Conn: c}
|
||||||
|
default:
|
||||||
|
panic(reflect.TypeOf(c))
|
||||||
|
}
|
||||||
|
newConn.SetDeadline(c.deadline)
|
||||||
|
newConn.SetReadDeadline(c.readDeadline)
|
||||||
|
newConn.SetWriteDeadline(c.writeDeadline)
|
||||||
|
if c.pre != nil {
|
||||||
|
_ = c.pre.Close()
|
||||||
|
}
|
||||||
|
c.pre = c.cur
|
||||||
|
c.wg.Add(1)
|
||||||
|
go c.recv(newConn)
|
||||||
|
}
|
||||||
|
c.addr = newAddr
|
||||||
|
c.cur = newConn
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *udpHopConn) recv(conn net.PacketConn) {
|
||||||
|
defer c.wg.Done()
|
||||||
|
|
||||||
|
for {
|
||||||
|
if c.closed() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p := pool.Get().([]byte)
|
||||||
|
n, addr, err := conn.ReadFrom(p)
|
||||||
|
if err != nil {
|
||||||
|
pool.Put(p[:cap(p)])
|
||||||
|
if goerrors.Is(err, io.EOF) || goerrors.Is(err, io.ErrClosedPipe) || goerrors.Is(err, gonet.ErrClosed) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
var netErr net.Error
|
||||||
|
if goerrors.As(err, &netErr) && netErr.Timeout() {
|
||||||
|
select {
|
||||||
|
case c.readCh <- packet{err: err}:
|
||||||
|
case <-c.closeCh:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
errors.LogErrorInner(context.Background(), err, "recv err")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case c.readCh <- packet{p: p[:n], addr: addr}:
|
||||||
|
case <-c.closeCh:
|
||||||
|
pool.Put(p[:cap(p)])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *udpHopConn) hopLoop() {
|
||||||
|
ticker := time.NewTicker(time.Second * time.Duration(crypto.RandBetween(c.intervalMin, c.intervalMax+1)))
|
||||||
|
defer ticker.Stop()
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ticker.C:
|
||||||
|
ticker.Reset(time.Second * time.Duration(crypto.RandBetween(c.intervalMin, c.intervalMax+1)))
|
||||||
|
c.mu.Lock()
|
||||||
|
c.hop(c.addr)
|
||||||
|
c.mu.Unlock()
|
||||||
|
case <-c.closeCh:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *udpHopConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
|
||||||
|
packet, ok := <-c.readCh
|
||||||
|
if ok {
|
||||||
|
if packet.p != nil {
|
||||||
|
n = copy(p, packet.p)
|
||||||
|
pool.Put(packet.p[:cap(packet.p)])
|
||||||
|
}
|
||||||
|
return n, packet.addr, packet.err
|
||||||
|
}
|
||||||
|
return 0, nil, io.EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *udpHopConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
|
||||||
|
c.mu.Lock()
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
|
||||||
|
if c.cur == nil {
|
||||||
|
c.hop(addr.(*net.UDPAddr))
|
||||||
|
if c.cur == nil {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
go c.hopLoop()
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = c.cur.WriteTo(p, c.addr)
|
||||||
|
if err != nil {
|
||||||
|
errors.LogErrorInner(context.Background(), err, "send err")
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return len(p), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *udpHopConn) Close() error {
|
||||||
|
c.mu.Lock()
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
if c.closed() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
close(c.closeCh)
|
||||||
|
if c.pre != nil {
|
||||||
|
_ = c.pre.Close()
|
||||||
|
}
|
||||||
|
if c.cur != nil {
|
||||||
|
_ = c.cur.Close()
|
||||||
|
}
|
||||||
|
_ = c.conn.Close()
|
||||||
|
c.wg.Wait()
|
||||||
|
select {
|
||||||
|
case p := <-c.readCh:
|
||||||
|
if p.p != nil {
|
||||||
|
pool.Put(p.p[:cap(p.p)])
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
close(c.readCh)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *udpHopConn) LocalAddr() net.Addr {
|
||||||
|
return c.conn.LocalAddr()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *udpHopConn) SetDeadline(t time.Time) error {
|
||||||
|
c.mu.Lock()
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
c.deadline = t
|
||||||
|
if c.pre != nil {
|
||||||
|
_ = c.pre.SetDeadline(t)
|
||||||
|
}
|
||||||
|
if c.cur != nil {
|
||||||
|
_ = c.cur.SetDeadline(t)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *udpHopConn) SetReadDeadline(t time.Time) error {
|
||||||
|
c.mu.Lock()
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
c.readDeadline = t
|
||||||
|
if c.pre != nil {
|
||||||
|
_ = c.pre.SetReadDeadline(t)
|
||||||
|
}
|
||||||
|
if c.cur != nil {
|
||||||
|
_ = c.cur.SetReadDeadline(t)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *udpHopConn) SetWriteDeadline(t time.Time) error {
|
||||||
|
c.mu.Lock()
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
c.writeDeadline = t
|
||||||
|
if c.pre != nil {
|
||||||
|
_ = c.pre.SetWriteDeadline(t)
|
||||||
|
}
|
||||||
|
if c.cur != nil {
|
||||||
|
_ = c.cur.SetWriteDeadline(t)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func randPrefix(p netip.Prefix) []byte {
|
||||||
|
if p.IsSingleIP() {
|
||||||
|
return p.Addr().AsSlice()
|
||||||
|
}
|
||||||
|
b := p.Addr().AsSlice()
|
||||||
|
prefix := p.Bits()
|
||||||
|
var new [16]byte
|
||||||
|
common.Must2(rand.Read(new[:len(b)]))
|
||||||
|
i := prefix / 8
|
||||||
|
j := prefix % 8
|
||||||
|
if i+1 < len(b) {
|
||||||
|
copy(b[i+1:], new[i+1:])
|
||||||
|
}
|
||||||
|
mask := byte(0xff << (8 - j))
|
||||||
|
b[i] = (b[i] & mask) | (new[i] &^ mask)
|
||||||
|
return b
|
||||||
|
}
|
||||||
@@ -4,9 +4,6 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Config) UDP() {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
|
func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
|
||||||
// _, ok1 := raw.(*internet.FakePacketConn)
|
// _, ok1 := raw.(*internet.FakePacketConn)
|
||||||
// _, ok2 := raw.(*udphop.UdpHopPacketConn)
|
// _, ok2 := raw.(*udphop.UdpHopPacketConn)
|
||||||
|
|||||||
@@ -45,7 +45,8 @@ type xicmpConnClient struct {
|
|||||||
id int
|
id int
|
||||||
seq int
|
seq int
|
||||||
readCh chan packet
|
readCh chan packet
|
||||||
closedCh chan struct{}
|
closeCh chan struct{}
|
||||||
|
wg sync.WaitGroup
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,9 +82,10 @@ func NewConnClient(c *Config, raw net.PacketConn) (net.PacketConn, error) {
|
|||||||
id: mathrand.Intn(65536),
|
id: mathrand.Intn(65536),
|
||||||
seq: 1,
|
seq: 1,
|
||||||
readCh: make(chan packet),
|
readCh: make(chan packet),
|
||||||
closedCh: make(chan struct{}),
|
closeCh: make(chan struct{}),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
conn.wg.Add(2)
|
||||||
go conn.recv4()
|
go conn.recv4()
|
||||||
go conn.recv6()
|
go conn.recv6()
|
||||||
|
|
||||||
@@ -96,7 +98,7 @@ func (c *xicmpConnClient) ring(a, b uint16) uint16 {
|
|||||||
|
|
||||||
func (c *xicmpConnClient) closed() bool {
|
func (c *xicmpConnClient) closed() bool {
|
||||||
select {
|
select {
|
||||||
case <-c.closedCh:
|
case <-c.closeCh:
|
||||||
return true
|
return true
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
@@ -104,8 +106,9 @@ func (c *xicmpConnClient) closed() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *xicmpConnClient) recv4() {
|
func (c *xicmpConnClient) recv4() {
|
||||||
var b [finalmask.UDPSize]byte
|
defer c.wg.Done()
|
||||||
|
|
||||||
|
var b [finalmask.UDPSize]byte
|
||||||
for {
|
for {
|
||||||
if c.closed() {
|
if c.closed() {
|
||||||
return
|
return
|
||||||
@@ -119,10 +122,11 @@ func (c *xicmpConnClient) recv4() {
|
|||||||
case c.readCh <- packet{
|
case c.readCh <- packet{
|
||||||
err: err,
|
err: err,
|
||||||
}:
|
}:
|
||||||
case <-c.closedCh:
|
case <-c.closeCh:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
errors.LogErrorInner(context.Background(), err, "recv4 err")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,7 +170,7 @@ func (c *xicmpConnClient) recv4() {
|
|||||||
p: p,
|
p: p,
|
||||||
addr: addr,
|
addr: addr,
|
||||||
}:
|
}:
|
||||||
case <-c.closedCh:
|
case <-c.closeCh:
|
||||||
pool.Put(p)
|
pool.Put(p)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -174,11 +178,12 @@ func (c *xicmpConnClient) recv4() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *xicmpConnClient) recv6() {
|
func (c *xicmpConnClient) recv6() {
|
||||||
var b [finalmask.UDPSize]byte
|
defer c.wg.Done()
|
||||||
|
|
||||||
|
var b [finalmask.UDPSize]byte
|
||||||
for {
|
for {
|
||||||
if c.closed() {
|
if c.closed() {
|
||||||
break
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
n, addr, err := c.icmp6.ReadFrom(b[:])
|
n, addr, err := c.icmp6.ReadFrom(b[:])
|
||||||
@@ -189,10 +194,11 @@ func (c *xicmpConnClient) recv6() {
|
|||||||
case c.readCh <- packet{
|
case c.readCh <- packet{
|
||||||
err: err,
|
err: err,
|
||||||
}:
|
}:
|
||||||
case <-c.closedCh:
|
case <-c.closeCh:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
errors.LogErrorInner(context.Background(), err, "recv6 err")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,7 +242,7 @@ func (c *xicmpConnClient) recv6() {
|
|||||||
p: p,
|
p: p,
|
||||||
addr: addr,
|
addr: addr,
|
||||||
}:
|
}:
|
||||||
case <-c.closedCh:
|
case <-c.closeCh:
|
||||||
pool.Put(p)
|
pool.Put(p)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -244,16 +250,15 @@ func (c *xicmpConnClient) recv6() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *xicmpConnClient) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
|
func (c *xicmpConnClient) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
|
||||||
select {
|
packet, ok := <-c.readCh
|
||||||
case packet := <-c.readCh:
|
if ok {
|
||||||
if packet.p != nil {
|
if packet.p != nil {
|
||||||
n = copy(p, packet.p)
|
n = copy(p, packet.p)
|
||||||
pool.Put(packet.p)
|
pool.Put(packet.p)
|
||||||
}
|
}
|
||||||
return n, packet.addr, packet.err
|
return n, packet.addr, packet.err
|
||||||
case <-c.closedCh:
|
|
||||||
return 0, nil, io.EOF
|
|
||||||
}
|
}
|
||||||
|
return 0, nil, io.EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *xicmpConnClient) WriteTo(p []byte, addr net.Addr) (n int, err error) {
|
func (c *xicmpConnClient) WriteTo(p []byte, addr net.Addr) (n int, err error) {
|
||||||
@@ -294,10 +299,9 @@ func (c *xicmpConnClient) WriteTo(p []byte, addr net.Addr) (n int, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogErrorInner(context.Background(), err, "xicmp write")
|
errors.LogErrorInner(context.Background(), err, "send err")
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return len(p), nil
|
return len(p), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -307,10 +311,19 @@ func (c *xicmpConnClient) Close() error {
|
|||||||
if c.closed() {
|
if c.closed() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
close(c.closedCh)
|
close(c.closeCh)
|
||||||
_ = c.icmp4.Close()
|
_ = c.icmp4.Close()
|
||||||
_ = c.icmp6.Close()
|
_ = c.icmp6.Close()
|
||||||
_ = c.conn.Close()
|
_ = c.conn.Close()
|
||||||
|
c.wg.Wait()
|
||||||
|
select {
|
||||||
|
case p := <-c.readCh:
|
||||||
|
if p.p != nil {
|
||||||
|
pool.Put(p.p)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
close(c.readCh)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,16 +5,11 @@ import (
|
|||||||
|
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
"github.com/xtls/xray-core/transport/internet"
|
"github.com/xtls/xray-core/transport/internet"
|
||||||
"github.com/xtls/xray-core/transport/internet/hysteria/udphop"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Config) UDP() {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
|
func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
|
||||||
_, ok1 := raw.(*internet.FakePacketConn)
|
_, ok1 := raw.(*internet.FakePacketConn)
|
||||||
_, ok2 := raw.(*udphop.UdpHopPacketConn)
|
if level != 0 || ok1 {
|
||||||
if level != 0 || ok1 || ok2 {
|
|
||||||
return nil, errors.New("xicmp requires being at the outermost level")
|
return nil, errors.New("xicmp requires being at the outermost level")
|
||||||
}
|
}
|
||||||
return NewConnClient(c, raw)
|
return NewConnClient(c, raw)
|
||||||
|
|||||||
@@ -37,14 +37,15 @@ type record struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type xicmpConnServer struct {
|
type xicmpConnServer struct {
|
||||||
conn net.PacketConn
|
conn net.PacketConn
|
||||||
icmp4 *icmp.PacketConn
|
icmp4 *icmp.PacketConn
|
||||||
icmp6 *icmp.PacketConn
|
icmp6 *icmp.PacketConn
|
||||||
ips map[netip.Addr]struct{}
|
ips map[netip.Addr]struct{}
|
||||||
rec map[string]record
|
rec map[string]record
|
||||||
readCh chan packet
|
readCh chan packet
|
||||||
closedCh chan struct{}
|
closeCh chan struct{}
|
||||||
mu sync.Mutex
|
wg sync.WaitGroup
|
||||||
|
mu sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewConnServer(c *Config, raw net.PacketConn) (net.PacketConn, error) {
|
func NewConnServer(c *Config, raw net.PacketConn) (net.PacketConn, error) {
|
||||||
@@ -63,16 +64,17 @@ func NewConnServer(c *Config, raw net.PacketConn) (net.PacketConn, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
conn := &xicmpConnServer{
|
conn := &xicmpConnServer{
|
||||||
conn: raw,
|
conn: raw,
|
||||||
icmp4: icmp4,
|
icmp4: icmp4,
|
||||||
icmp6: icmp6,
|
icmp6: icmp6,
|
||||||
ips: ips,
|
ips: ips,
|
||||||
rec: make(map[string]record),
|
rec: make(map[string]record),
|
||||||
readCh: make(chan packet),
|
readCh: make(chan packet),
|
||||||
closedCh: make(chan struct{}),
|
closeCh: make(chan struct{}),
|
||||||
}
|
}
|
||||||
|
|
||||||
go conn.clean()
|
go conn.clean()
|
||||||
|
conn.wg.Add(2)
|
||||||
go conn.recv4()
|
go conn.recv4()
|
||||||
go conn.recv6()
|
go conn.recv6()
|
||||||
|
|
||||||
@@ -81,7 +83,7 @@ func NewConnServer(c *Config, raw net.PacketConn) (net.PacketConn, error) {
|
|||||||
|
|
||||||
func (c *xicmpConnServer) closed() bool {
|
func (c *xicmpConnServer) closed() bool {
|
||||||
select {
|
select {
|
||||||
case <-c.closedCh:
|
case <-c.closeCh:
|
||||||
return true
|
return true
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
@@ -102,15 +104,16 @@ func (c *xicmpConnServer) clean() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
c.mu.Unlock()
|
c.mu.Unlock()
|
||||||
case <-c.closedCh:
|
case <-c.closeCh:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *xicmpConnServer) recv4() {
|
func (c *xicmpConnServer) recv4() {
|
||||||
var b [finalmask.UDPSize]byte
|
defer c.wg.Done()
|
||||||
|
|
||||||
|
var b [finalmask.UDPSize]byte
|
||||||
for {
|
for {
|
||||||
if c.closed() {
|
if c.closed() {
|
||||||
return
|
return
|
||||||
@@ -124,10 +127,11 @@ func (c *xicmpConnServer) recv4() {
|
|||||||
case c.readCh <- packet{
|
case c.readCh <- packet{
|
||||||
err: err,
|
err: err,
|
||||||
}:
|
}:
|
||||||
case <-c.closedCh:
|
case <-c.closeCh:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
errors.LogErrorInner(context.Background(), err, "recv4 err")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,7 +183,7 @@ func (c *xicmpConnServer) recv4() {
|
|||||||
p: p,
|
p: p,
|
||||||
addr: cAddr,
|
addr: cAddr,
|
||||||
}:
|
}:
|
||||||
case <-c.closedCh:
|
case <-c.closeCh:
|
||||||
pool.Put(p)
|
pool.Put(p)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -187,8 +191,9 @@ func (c *xicmpConnServer) recv4() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *xicmpConnServer) recv6() {
|
func (c *xicmpConnServer) recv6() {
|
||||||
var b [finalmask.UDPSize]byte
|
defer c.wg.Done()
|
||||||
|
|
||||||
|
var b [finalmask.UDPSize]byte
|
||||||
for {
|
for {
|
||||||
if c.closed() {
|
if c.closed() {
|
||||||
return
|
return
|
||||||
@@ -202,10 +207,11 @@ func (c *xicmpConnServer) recv6() {
|
|||||||
case c.readCh <- packet{
|
case c.readCh <- packet{
|
||||||
err: err,
|
err: err,
|
||||||
}:
|
}:
|
||||||
case <-c.closedCh:
|
case <-c.closeCh:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
errors.LogErrorInner(context.Background(), err, "recv6 err")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,7 +263,7 @@ func (c *xicmpConnServer) recv6() {
|
|||||||
p: p,
|
p: p,
|
||||||
addr: cAddr,
|
addr: cAddr,
|
||||||
}:
|
}:
|
||||||
case <-c.closedCh:
|
case <-c.closeCh:
|
||||||
pool.Put(p)
|
pool.Put(p)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -265,16 +271,15 @@ func (c *xicmpConnServer) recv6() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *xicmpConnServer) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
|
func (c *xicmpConnServer) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
|
||||||
select {
|
packet, ok := <-c.readCh
|
||||||
case packet := <-c.readCh:
|
if ok {
|
||||||
if packet.p != nil {
|
if packet.p != nil {
|
||||||
n = copy(p, packet.p)
|
n = copy(p, packet.p)
|
||||||
pool.Put(packet.p)
|
pool.Put(packet.p)
|
||||||
}
|
}
|
||||||
return n, packet.addr, packet.err
|
return n, packet.addr, packet.err
|
||||||
case <-c.closedCh:
|
|
||||||
return 0, nil, io.EOF
|
|
||||||
}
|
}
|
||||||
|
return 0, nil, io.EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *xicmpConnServer) WriteTo(p []byte, addr net.Addr) (n int, err error) {
|
func (c *xicmpConnServer) WriteTo(p []byte, addr net.Addr) (n int, err error) {
|
||||||
@@ -310,10 +315,9 @@ func (c *xicmpConnServer) WriteTo(p []byte, addr net.Addr) (n int, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogErrorInner(context.Background(), err, "xicmp write")
|
errors.LogErrorInner(context.Background(), err, "send err")
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return len(p), nil
|
return len(p), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -323,10 +327,19 @@ func (c *xicmpConnServer) Close() error {
|
|||||||
if c.closed() {
|
if c.closed() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
close(c.closedCh)
|
close(c.closeCh)
|
||||||
_ = c.icmp4.Close()
|
_ = c.icmp4.Close()
|
||||||
_ = c.icmp6.Close()
|
_ = c.icmp6.Close()
|
||||||
_ = c.conn.Close()
|
_ = c.conn.Close()
|
||||||
|
c.wg.Wait()
|
||||||
|
select {
|
||||||
|
case p := <-c.readCh:
|
||||||
|
if p.p != nil {
|
||||||
|
pool.Put(p.p)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
close(c.readCh)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,16 +39,17 @@ type record struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type xicmpConnServer struct {
|
type xicmpConnServer struct {
|
||||||
conn net.PacketConn
|
conn net.PacketConn
|
||||||
icmp4 *icmp.PacketConn
|
icmp4 *icmp.PacketConn
|
||||||
icmp6 *icmp.PacketConn
|
icmp6 *icmp.PacketConn
|
||||||
ipv4PC *ipv4.PacketConn
|
ipv4PC *ipv4.PacketConn
|
||||||
ipv6PC *ipv6.PacketConn
|
ipv6PC *ipv6.PacketConn
|
||||||
ips map[netip.Addr]struct{}
|
ips map[netip.Addr]struct{}
|
||||||
rec map[string]record
|
rec map[string]record
|
||||||
readCh chan packet
|
readCh chan packet
|
||||||
closedCh chan struct{}
|
closeCh chan struct{}
|
||||||
mu sync.Mutex
|
wg sync.WaitGroup
|
||||||
|
mu sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewConnServer(c *Config, raw net.PacketConn) (net.PacketConn, error) {
|
func NewConnServer(c *Config, raw net.PacketConn) (net.PacketConn, error) {
|
||||||
@@ -67,21 +68,22 @@ func NewConnServer(c *Config, raw net.PacketConn) (net.PacketConn, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
conn := &xicmpConnServer{
|
conn := &xicmpConnServer{
|
||||||
conn: raw,
|
conn: raw,
|
||||||
icmp4: icmp4,
|
icmp4: icmp4,
|
||||||
icmp6: icmp6,
|
icmp6: icmp6,
|
||||||
ipv4PC: icmp4.IPv4PacketConn(),
|
ipv4PC: icmp4.IPv4PacketConn(),
|
||||||
ipv6PC: icmp6.IPv6PacketConn(),
|
ipv6PC: icmp6.IPv6PacketConn(),
|
||||||
ips: ips,
|
ips: ips,
|
||||||
rec: make(map[string]record),
|
rec: make(map[string]record),
|
||||||
readCh: make(chan packet),
|
readCh: make(chan packet),
|
||||||
closedCh: make(chan struct{}),
|
closeCh: make(chan struct{}),
|
||||||
}
|
}
|
||||||
|
|
||||||
common.Must(conn.ipv4PC.SetControlMessage(ipv4.FlagDst, true))
|
common.Must(conn.ipv4PC.SetControlMessage(ipv4.FlagDst, true))
|
||||||
common.Must(conn.ipv6PC.SetControlMessage(ipv6.FlagDst, true))
|
common.Must(conn.ipv6PC.SetControlMessage(ipv6.FlagDst, true))
|
||||||
|
|
||||||
go conn.clean()
|
go conn.clean()
|
||||||
|
conn.wg.Add(2)
|
||||||
go conn.recv4()
|
go conn.recv4()
|
||||||
go conn.recv6()
|
go conn.recv6()
|
||||||
|
|
||||||
@@ -90,7 +92,7 @@ func NewConnServer(c *Config, raw net.PacketConn) (net.PacketConn, error) {
|
|||||||
|
|
||||||
func (c *xicmpConnServer) closed() bool {
|
func (c *xicmpConnServer) closed() bool {
|
||||||
select {
|
select {
|
||||||
case <-c.closedCh:
|
case <-c.closeCh:
|
||||||
return true
|
return true
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
@@ -111,15 +113,16 @@ func (c *xicmpConnServer) clean() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
c.mu.Unlock()
|
c.mu.Unlock()
|
||||||
case <-c.closedCh:
|
case <-c.closeCh:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *xicmpConnServer) recv4() {
|
func (c *xicmpConnServer) recv4() {
|
||||||
var b [finalmask.UDPSize]byte
|
defer c.wg.Done()
|
||||||
|
|
||||||
|
var b [finalmask.UDPSize]byte
|
||||||
for {
|
for {
|
||||||
if c.closed() {
|
if c.closed() {
|
||||||
return
|
return
|
||||||
@@ -133,10 +136,11 @@ func (c *xicmpConnServer) recv4() {
|
|||||||
case c.readCh <- packet{
|
case c.readCh <- packet{
|
||||||
err: err,
|
err: err,
|
||||||
}:
|
}:
|
||||||
case <-c.closedCh:
|
case <-c.closeCh:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
errors.LogErrorInner(context.Background(), err, "recv4 err")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,7 +193,7 @@ func (c *xicmpConnServer) recv4() {
|
|||||||
p: p,
|
p: p,
|
||||||
addr: cAddr,
|
addr: cAddr,
|
||||||
}:
|
}:
|
||||||
case <-c.closedCh:
|
case <-c.closeCh:
|
||||||
pool.Put(p)
|
pool.Put(p)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -197,8 +201,9 @@ func (c *xicmpConnServer) recv4() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *xicmpConnServer) recv6() {
|
func (c *xicmpConnServer) recv6() {
|
||||||
var b [finalmask.UDPSize]byte
|
defer c.wg.Done()
|
||||||
|
|
||||||
|
var b [finalmask.UDPSize]byte
|
||||||
for {
|
for {
|
||||||
if c.closed() {
|
if c.closed() {
|
||||||
return
|
return
|
||||||
@@ -212,10 +217,11 @@ func (c *xicmpConnServer) recv6() {
|
|||||||
case c.readCh <- packet{
|
case c.readCh <- packet{
|
||||||
err: err,
|
err: err,
|
||||||
}:
|
}:
|
||||||
case <-c.closedCh:
|
case <-c.closeCh:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
errors.LogErrorInner(context.Background(), err, "recv6 err")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -268,7 +274,7 @@ func (c *xicmpConnServer) recv6() {
|
|||||||
p: p,
|
p: p,
|
||||||
addr: cAddr,
|
addr: cAddr,
|
||||||
}:
|
}:
|
||||||
case <-c.closedCh:
|
case <-c.closeCh:
|
||||||
pool.Put(p)
|
pool.Put(p)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -276,16 +282,15 @@ func (c *xicmpConnServer) recv6() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *xicmpConnServer) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
|
func (c *xicmpConnServer) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
|
||||||
select {
|
packet, ok := <-c.readCh
|
||||||
case packet := <-c.readCh:
|
if ok {
|
||||||
if packet.p != nil {
|
if packet.p != nil {
|
||||||
n = copy(p, packet.p)
|
n = copy(p, packet.p)
|
||||||
pool.Put(packet.p)
|
pool.Put(packet.p)
|
||||||
}
|
}
|
||||||
return n, packet.addr, packet.err
|
return n, packet.addr, packet.err
|
||||||
case <-c.closedCh:
|
|
||||||
return 0, nil, io.EOF
|
|
||||||
}
|
}
|
||||||
|
return 0, nil, io.EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *xicmpConnServer) WriteTo(p []byte, addr net.Addr) (n int, err error) {
|
func (c *xicmpConnServer) WriteTo(p []byte, addr net.Addr) (n int, err error) {
|
||||||
@@ -321,10 +326,9 @@ func (c *xicmpConnServer) WriteTo(p []byte, addr net.Addr) (n int, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogErrorInner(context.Background(), err, "xicmp write")
|
errors.LogErrorInner(context.Background(), err, "send err")
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return len(p), nil
|
return len(p), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -334,10 +338,19 @@ func (c *xicmpConnServer) Close() error {
|
|||||||
if c.closed() {
|
if c.closed() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
close(c.closedCh)
|
close(c.closeCh)
|
||||||
_ = c.icmp4.Close()
|
_ = c.icmp4.Close()
|
||||||
_ = c.icmp6.Close()
|
_ = c.icmp6.Close()
|
||||||
_ = c.conn.Close()
|
_ = c.conn.Close()
|
||||||
|
c.wg.Wait()
|
||||||
|
select {
|
||||||
|
case p := <-c.readCh:
|
||||||
|
if p.p != nil {
|
||||||
|
pool.Put(p.p)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
close(c.readCh)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,9 +5,6 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Config) TCP() {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Config) WrapConnClient(conn net.Conn) (net.Conn, error) {
|
func (c *Config) WrapConnClient(conn net.Conn) (net.Conn, error) {
|
||||||
profiles, err := profilesFromConfig(c.Profiles)
|
profiles, err := profilesFromConfig(c.Profiles)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -103,14 +103,11 @@ func (c *InterConn) Update() {
|
|||||||
|
|
||||||
func (c *InterConn) Read(p []byte) (int, error) {
|
func (c *InterConn) Read(p []byte) (int, error) {
|
||||||
b, ok := <-c.ch
|
b, ok := <-c.ch
|
||||||
if !ok {
|
if ok {
|
||||||
return 0, io.EOF
|
c.Update()
|
||||||
|
return copy(p, b), nil
|
||||||
}
|
}
|
||||||
if len(p) < len(b) {
|
return 0, io.EOF
|
||||||
return 0, io.ErrShortBuffer
|
|
||||||
}
|
|
||||||
c.Update()
|
|
||||||
return copy(p, b), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *InterConn) Write(p []byte) (int, error) {
|
func (c *InterConn) Write(p []byte) (int, error) {
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package hysteria
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
go_tls "crypto/tls"
|
go_tls "crypto/tls"
|
||||||
"math/rand"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"reflect"
|
"reflect"
|
||||||
@@ -22,7 +21,6 @@ import (
|
|||||||
"github.com/xtls/xray-core/transport/internet/finalmask"
|
"github.com/xtls/xray-core/transport/internet/finalmask"
|
||||||
"github.com/xtls/xray-core/transport/internet/hysteria/congestion"
|
"github.com/xtls/xray-core/transport/internet/hysteria/congestion"
|
||||||
"github.com/xtls/xray-core/transport/internet/hysteria/congestion/bbr"
|
"github.com/xtls/xray-core/transport/internet/hysteria/congestion/bbr"
|
||||||
"github.com/xtls/xray-core/transport/internet/hysteria/udphop"
|
|
||||||
"github.com/xtls/xray-core/transport/internet/stat"
|
"github.com/xtls/xray-core/transport/internet/stat"
|
||||||
"github.com/xtls/xray-core/transport/internet/tls"
|
"github.com/xtls/xray-core/transport/internet/tls"
|
||||||
)
|
)
|
||||||
@@ -78,7 +76,6 @@ func (c *client) dial(ctx context.Context) error {
|
|||||||
if quicParams == nil {
|
if quicParams == nil {
|
||||||
quicParams = &internet.QuicParams{
|
quicParams = &internet.QuicParams{
|
||||||
BbrProfile: string(bbr.ProfileStandard),
|
BbrProfile: string(bbr.ProfileStandard),
|
||||||
UdpHop: &internet.UdpHop{},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,35 +112,8 @@ func (c *client) dial(ctx context.Context) error {
|
|||||||
// quicConfig.KeepAlivePeriod = 10 * time.Second
|
// quicConfig.KeepAlivePeriod = 10 * time.Second
|
||||||
// }
|
// }
|
||||||
|
|
||||||
udpHopDialer := func(addr *net.UDPAddr) (net.PacketConn, error) {
|
|
||||||
conn, err := internet.DialSystem(ctx, net.UDPDestination(net.IPAddress(addr.IP), net.Port(addr.Port)), c.socketConfig)
|
|
||||||
if err != nil {
|
|
||||||
errors.LogInfoInner(context.Background(), err, "skip hop: failed to dial to dest")
|
|
||||||
return nil, errors.New("")
|
|
||||||
}
|
|
||||||
|
|
||||||
var pktConn net.PacketConn
|
|
||||||
|
|
||||||
switch c := conn.(type) {
|
|
||||||
case *internet.PacketConnWrapper:
|
|
||||||
pktConn = c.PacketConn
|
|
||||||
case *cnc.Connection:
|
|
||||||
pktConn = &internet.FakePacketConn{Conn: c}
|
|
||||||
default:
|
|
||||||
panic(reflect.TypeOf(c))
|
|
||||||
}
|
|
||||||
|
|
||||||
return pktConn, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var pktConn net.PacketConn
|
var pktConn net.PacketConn
|
||||||
var udpAddr *net.UDPAddr
|
var udpAddr *net.UDPAddr
|
||||||
var index int
|
|
||||||
|
|
||||||
if len(quicParams.UdpHop.Ports) > 0 {
|
|
||||||
index = rand.Intn(len(quicParams.UdpHop.Ports))
|
|
||||||
c.dest.Port = net.Port(quicParams.UdpHop.Ports[index])
|
|
||||||
}
|
|
||||||
|
|
||||||
raw, err := internet.DialSystem(ctx, c.dest, c.socketConfig)
|
raw, err := internet.DialSystem(ctx, c.dest, c.socketConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -160,10 +130,6 @@ func (c *client) dial(ctx context.Context) error {
|
|||||||
panic(reflect.TypeOf(c))
|
panic(reflect.TypeOf(c))
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(quicParams.UdpHop.Ports) > 0 {
|
|
||||||
pktConn = udphop.NewUDPHopPacketConn(udphop.ToAddrs(udpAddr.IP, quicParams.UdpHop.Ports), time.Duration(quicParams.UdpHop.IntervalMin)*time.Second, time.Duration(quicParams.UdpHop.IntervalMax)*time.Second, udpHopDialer, pktConn, index)
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.udpmaskManager != nil {
|
if c.udpmaskManager != nil {
|
||||||
newConn, err := c.udpmaskManager.WrapPacketConnClient(pktConn)
|
newConn, err := c.udpmaskManager.WrapPacketConnClient(pktConn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -231,8 +231,8 @@ func Listen(ctx context.Context, address net.Address, port net.Port, streamSetti
|
|||||||
transport.TLSClientConfig.InsecureSkipVerify = true
|
transport.TLSClientConfig.InsecureSkipVerify = true
|
||||||
}
|
}
|
||||||
case "", "unix":
|
case "", "unix":
|
||||||
u = &url.URL{Scheme: "http", Host: "localhost"}
|
|
||||||
path := u.Path
|
path := u.Path
|
||||||
|
u = &url.URL{Scheme: "http", Host: "localhost"}
|
||||||
dialer := &net.Dialer{Timeout: 30 * time.Second}
|
dialer := &net.Dialer{Timeout: 30 * time.Second}
|
||||||
transport = transport.Clone()
|
transport = transport.Clone()
|
||||||
transport.Proxy = nil
|
transport.Proxy = nil
|
||||||
@@ -281,7 +281,6 @@ func Listen(ctx context.Context, address net.Address, port net.Port, streamSetti
|
|||||||
if quicParams == nil {
|
if quicParams == nil {
|
||||||
quicParams = &internet.QuicParams{
|
quicParams = &internet.QuicParams{
|
||||||
BbrProfile: string(bbr.ProfileStandard),
|
BbrProfile: string(bbr.ProfileStandard),
|
||||||
UdpHop: &internet.UdpHop{},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,254 +0,0 @@
|
|||||||
package udphop
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"math/rand"
|
|
||||||
"net"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/xtls/xray-core/transport/internet/finalmask"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
packetQueueSize = 1024
|
|
||||||
udpBufferSize = finalmask.UDPSize
|
|
||||||
|
|
||||||
defaultHopInterval = 30 * time.Second
|
|
||||||
)
|
|
||||||
|
|
||||||
type UdpHopPacketConn struct {
|
|
||||||
Addrs []net.Addr
|
|
||||||
HopIntervalMin time.Duration
|
|
||||||
HopIntervalMax time.Duration
|
|
||||||
ListenUDPFunc func(addr *net.UDPAddr) (net.PacketConn, error)
|
|
||||||
|
|
||||||
connMutex sync.RWMutex
|
|
||||||
prevConn net.PacketConn
|
|
||||||
currentConn net.PacketConn
|
|
||||||
addrIndex int
|
|
||||||
|
|
||||||
deadline time.Time
|
|
||||||
readDeadline time.Time
|
|
||||||
writeDeadline time.Time
|
|
||||||
|
|
||||||
recvQueue chan *udpPacket
|
|
||||||
closeChan chan struct{}
|
|
||||||
closed bool
|
|
||||||
|
|
||||||
bufPool sync.Pool
|
|
||||||
}
|
|
||||||
|
|
||||||
type udpPacket struct {
|
|
||||||
Buf []byte
|
|
||||||
N int
|
|
||||||
Addr net.Addr
|
|
||||||
Err error
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewUDPHopPacketConn(addrs []net.Addr, hopIntervalMin time.Duration, hopIntervalMax time.Duration, listenUDPFunc func(addr *net.UDPAddr) (net.PacketConn, error), currentConn net.PacketConn, addrIndex int) net.PacketConn {
|
|
||||||
if len(addrs) == 0 {
|
|
||||||
panic("len(addrs) == 0")
|
|
||||||
}
|
|
||||||
if hopIntervalMin == 0 {
|
|
||||||
hopIntervalMin = defaultHopInterval
|
|
||||||
}
|
|
||||||
if hopIntervalMax == 0 {
|
|
||||||
hopIntervalMax = defaultHopInterval
|
|
||||||
}
|
|
||||||
if hopIntervalMin < 5*time.Second {
|
|
||||||
panic("hopIntervalMin < 5*time.Second")
|
|
||||||
}
|
|
||||||
if hopIntervalMax < 5*time.Second {
|
|
||||||
panic("hopIntervalMax < 5*time.Second")
|
|
||||||
}
|
|
||||||
if hopIntervalMax < hopIntervalMin {
|
|
||||||
panic("hopIntervalMax < hopIntervalMin")
|
|
||||||
}
|
|
||||||
if listenUDPFunc == nil {
|
|
||||||
panic("listenUDPFunc is nil")
|
|
||||||
}
|
|
||||||
hConn := &UdpHopPacketConn{
|
|
||||||
Addrs: addrs,
|
|
||||||
HopIntervalMin: hopIntervalMin,
|
|
||||||
HopIntervalMax: hopIntervalMax,
|
|
||||||
ListenUDPFunc: listenUDPFunc,
|
|
||||||
prevConn: nil,
|
|
||||||
currentConn: currentConn,
|
|
||||||
addrIndex: addrIndex,
|
|
||||||
recvQueue: make(chan *udpPacket, packetQueueSize),
|
|
||||||
closeChan: make(chan struct{}),
|
|
||||||
bufPool: sync.Pool{
|
|
||||||
New: func() interface{} {
|
|
||||||
return make([]byte, udpBufferSize)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
go hConn.recvLoop(hConn.currentConn)
|
|
||||||
go hConn.hopLoop()
|
|
||||||
return hConn
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *UdpHopPacketConn) recvLoop(conn net.PacketConn) {
|
|
||||||
for {
|
|
||||||
buf := u.bufPool.Get().([]byte)
|
|
||||||
n, addr, err := conn.ReadFrom(buf)
|
|
||||||
if err != nil {
|
|
||||||
u.bufPool.Put(buf)
|
|
||||||
var netErr net.Error
|
|
||||||
if errors.As(err, &netErr) && netErr.Timeout() {
|
|
||||||
u.recvQueue <- &udpPacket{nil, 0, nil, netErr}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
select {
|
|
||||||
case u.recvQueue <- &udpPacket{buf, n, addr, nil}:
|
|
||||||
default:
|
|
||||||
u.bufPool.Put(buf)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *UdpHopPacketConn) hopLoop() {
|
|
||||||
timer := time.NewTimer(u.nextHopInterval())
|
|
||||||
defer timer.Stop()
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-timer.C:
|
|
||||||
u.hop()
|
|
||||||
timer.Reset(u.nextHopInterval())
|
|
||||||
case <-u.closeChan:
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *UdpHopPacketConn) nextHopInterval() time.Duration {
|
|
||||||
if u.HopIntervalMin == u.HopIntervalMax {
|
|
||||||
return u.HopIntervalMin
|
|
||||||
}
|
|
||||||
return u.HopIntervalMin + time.Duration(rand.Int63n(int64(u.HopIntervalMax-u.HopIntervalMin)+1))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *UdpHopPacketConn) hop() {
|
|
||||||
u.connMutex.Lock()
|
|
||||||
defer u.connMutex.Unlock()
|
|
||||||
if u.closed {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
addrIndex := rand.Intn(len(u.Addrs))
|
|
||||||
newConn, err := u.ListenUDPFunc(u.Addrs[addrIndex].(*net.UDPAddr))
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if u.prevConn != nil {
|
|
||||||
_ = u.prevConn.Close()
|
|
||||||
}
|
|
||||||
u.prevConn = u.currentConn
|
|
||||||
u.addrIndex = addrIndex
|
|
||||||
u.currentConn = newConn
|
|
||||||
if !u.deadline.IsZero() {
|
|
||||||
_ = u.currentConn.SetDeadline(u.deadline)
|
|
||||||
}
|
|
||||||
if !u.readDeadline.IsZero() {
|
|
||||||
_ = u.currentConn.SetReadDeadline(u.readDeadline)
|
|
||||||
}
|
|
||||||
if !u.writeDeadline.IsZero() {
|
|
||||||
_ = u.currentConn.SetWriteDeadline(u.writeDeadline)
|
|
||||||
}
|
|
||||||
go u.recvLoop(newConn)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *UdpHopPacketConn) ReadFrom(b []byte) (n int, addr net.Addr, err error) {
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case p := <-u.recvQueue:
|
|
||||||
if p.Err != nil {
|
|
||||||
return 0, nil, p.Err
|
|
||||||
}
|
|
||||||
n := copy(b, p.Buf[:p.N])
|
|
||||||
u.bufPool.Put(p.Buf)
|
|
||||||
return n, p.Addr, nil
|
|
||||||
case <-u.closeChan:
|
|
||||||
return 0, nil, net.ErrClosed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *UdpHopPacketConn) WriteTo(b []byte, addr net.Addr) (n int, err error) {
|
|
||||||
u.connMutex.RLock()
|
|
||||||
defer u.connMutex.RUnlock()
|
|
||||||
if u.closed {
|
|
||||||
return 0, net.ErrClosed
|
|
||||||
}
|
|
||||||
return u.currentConn.WriteTo(b, u.Addrs[u.addrIndex])
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *UdpHopPacketConn) Close() error {
|
|
||||||
u.connMutex.Lock()
|
|
||||||
defer u.connMutex.Unlock()
|
|
||||||
if u.closed {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if u.prevConn != nil {
|
|
||||||
_ = u.prevConn.Close()
|
|
||||||
}
|
|
||||||
err := u.currentConn.Close()
|
|
||||||
close(u.closeChan)
|
|
||||||
u.closed = true
|
|
||||||
u.Addrs = nil
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *UdpHopPacketConn) LocalAddr() net.Addr {
|
|
||||||
u.connMutex.RLock()
|
|
||||||
defer u.connMutex.RUnlock()
|
|
||||||
return u.currentConn.LocalAddr()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *UdpHopPacketConn) SetDeadline(t time.Time) error {
|
|
||||||
u.connMutex.Lock()
|
|
||||||
defer u.connMutex.Unlock()
|
|
||||||
u.deadline = t
|
|
||||||
u.readDeadline = t
|
|
||||||
u.writeDeadline = t
|
|
||||||
if u.prevConn != nil {
|
|
||||||
_ = u.prevConn.SetDeadline(t)
|
|
||||||
}
|
|
||||||
return u.currentConn.SetDeadline(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *UdpHopPacketConn) SetReadDeadline(t time.Time) error {
|
|
||||||
u.connMutex.Lock()
|
|
||||||
defer u.connMutex.Unlock()
|
|
||||||
u.deadline = time.Time{}
|
|
||||||
u.readDeadline = t
|
|
||||||
if u.prevConn != nil {
|
|
||||||
_ = u.prevConn.SetReadDeadline(t)
|
|
||||||
}
|
|
||||||
return u.currentConn.SetReadDeadline(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *UdpHopPacketConn) SetWriteDeadline(t time.Time) error {
|
|
||||||
u.connMutex.Lock()
|
|
||||||
defer u.connMutex.Unlock()
|
|
||||||
u.deadline = time.Time{}
|
|
||||||
u.writeDeadline = t
|
|
||||||
if u.prevConn != nil {
|
|
||||||
_ = u.prevConn.SetWriteDeadline(t)
|
|
||||||
}
|
|
||||||
return u.currentConn.SetWriteDeadline(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func ToAddrs(ip net.IP, ports []uint32) []net.Addr {
|
|
||||||
var addrs []net.Addr
|
|
||||||
for _, port := range ports {
|
|
||||||
addr := &net.UDPAddr{
|
|
||||||
IP: ip,
|
|
||||||
Port: int(port),
|
|
||||||
}
|
|
||||||
addrs = append(addrs, addr)
|
|
||||||
}
|
|
||||||
return addrs
|
|
||||||
}
|
|
||||||
@@ -53,7 +53,7 @@ func DialKCP(ctx context.Context, dest net.Destination, streamSettings *internet
|
|||||||
|
|
||||||
conn, err := internet.DialSystem(ctx, dest, streamSettings.SocketSettings)
|
conn, err := internet.DialSystem(ctx, dest, streamSettings.SocketSettings)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("failed to dial to dest: ", err).AtWarning().Base(err)
|
return nil, errors.New("failed to dial to dest: ", err).Base(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if streamSettings.UdpmaskManager != nil {
|
if streamSettings.UdpmaskManager != nil {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user