mirror of
https://github.com/XTLS/Xray-core.git
synced 2024-06-30 23:19:20 +03:00
Merge remote-tracking branch 'upstream/main'
This commit is contained in:
commit
67f4f2e4c1
|
@ -22,6 +22,7 @@
|
|||
"linux-ppc64le": { "friendlyName": "linux-ppc64le" },
|
||||
"linux-ppc64": { "friendlyName": "linux-ppc64" },
|
||||
"linux-riscv64": { "friendlyName": "linux-riscv64" },
|
||||
"linux-loong64": { "friendlyName": "linux-loong64" },
|
||||
"linux-s390x": { "friendlyName": "linux-s390x" },
|
||||
"openbsd-386": { "friendlyName": "openbsd-32" },
|
||||
"openbsd-amd64": { "friendlyName": "openbsd-64" },
|
||||
|
|
|
@ -11,10 +11,10 @@ jobs:
|
|||
permissions:
|
||||
packages: write
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Docker metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v4
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ghcr.io/${{ github.repository_owner }}/xray-core
|
||||
flavor: latest=true
|
||||
|
@ -23,7 +23,7 @@ jobs:
|
|||
type=ref,event=pr
|
||||
type=semver,pattern={{version}}
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
|
@ -31,11 +31,11 @@ jobs:
|
|||
- # Add support for more platforms with QEMU (optional)
|
||||
# https://github.com/docker/setup-qemu-action
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
uses: docker/setup-qemu-action@v3
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
uses: docker/setup-buildx-action@v3
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v4
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64
|
||||
|
|
|
@ -105,12 +105,14 @@ jobs:
|
|||
goarch: arm
|
||||
goarm: 7
|
||||
# BEGIN Other architectures
|
||||
# BEGIN riscv64 & ARM64
|
||||
# BEGIN riscv64 & ARM64 & LOONG64
|
||||
- goos: linux
|
||||
goarch: arm64
|
||||
- goos: linux
|
||||
goarch: riscv64
|
||||
# END riscv64 & ARM64
|
||||
- goos: linux
|
||||
goarch: loong64
|
||||
# END riscv64 & ARM64 & LOONG64
|
||||
# BEGIN MIPS
|
||||
- goos: linux
|
||||
goarch: mips64
|
||||
|
@ -156,7 +158,7 @@ jobs:
|
|||
CGO_ENABLED: 0
|
||||
steps:
|
||||
- name: Checkout codebase
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Show workflow information
|
||||
run: |
|
||||
|
@ -167,7 +169,7 @@ jobs:
|
|||
- name: Set up Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '1.20'
|
||||
go-version: '1.21'
|
||||
check-latest: true
|
||||
|
||||
- name: Get project dependencies
|
||||
|
|
|
@ -30,10 +30,10 @@ jobs:
|
|||
- name: Set up Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '1.20'
|
||||
go-version: '1.21'
|
||||
check-latest: true
|
||||
- name: Checkout codebase
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: Restore Cache
|
||||
uses: actions/cache/restore@v3
|
||||
with:
|
||||
|
|
10
README.md
10
README.md
|
@ -23,6 +23,7 @@
|
|||
- Linux Script
|
||||
- [XTLS/Xray-install](https://github.com/XTLS/Xray-install)
|
||||
- Docker
|
||||
- [iamybj/docker-xray](https://hub.docker.com/r/iamybj/docker-xray)
|
||||
- [teddysun/xray](https://hub.docker.com/r/teddysun/xray)
|
||||
- Web Panel
|
||||
- [X-UI](https://github.com/FranzKafkaYu/x-ui), [X-UI-English](https://github.com/NidukaAkalanka/x-ui-english), [3X-UI](https://github.com/MHSanaei/3x-ui), [X-UI](https://github.com/alireza0/x-ui), [X-UI](https://github.com/diditra/x-ui)
|
||||
|
@ -54,6 +55,7 @@
|
|||
- [XTLS Vision](https://github.com/chika0801/Xray-install)
|
||||
- [REALITY (English)](https://cscot.pages.dev/2023/03/02/Xray-REALITY-tutorial/)
|
||||
- [XTLS-Iran-Reality (English)](https://github.com/SasukeFreestyle/XTLS-Iran-Reality)
|
||||
- [Xray REALITY with 'steal oneself' (English)](https://computerscot.github.io/vless-xtls-utls-reality-steal-oneself.html)
|
||||
|
||||
## GUI Clients
|
||||
|
||||
|
@ -63,6 +65,8 @@
|
|||
- [luci-app-xray](https://github.com/yichya/luci-app-xray) ([openwrt-xray](https://github.com/yichya/openwrt-xray))
|
||||
- Windows
|
||||
- [v2rayN](https://github.com/2dust/v2rayN)
|
||||
- [NekoRay](https://github.com/Matsuridayo/nekoray)
|
||||
- [Furious](https://github.com/LorenEteval/Furious)
|
||||
- [HiddifyN](https://github.com/hiddify/HiddifyN)
|
||||
- [Invisible Man - Xray](https://github.com/InvisibleManVPN/InvisibleMan-XRayClient)
|
||||
- Android
|
||||
|
@ -72,11 +76,16 @@
|
|||
- iOS & macOS arm64
|
||||
- [Mango](https://github.com/arror/Mango)
|
||||
- [FoXray](https://apps.apple.com/app/foxray/id6448898396)
|
||||
- [Streisand](https://apps.apple.com/app/streisand/id6450534064)
|
||||
- macOS arm64 & x64
|
||||
- [V2rayU](https://github.com/yanue/V2rayU)
|
||||
- [V2RayXS](https://github.com/tzmax/V2RayXS)
|
||||
- [Furious](https://github.com/LorenEteval/Furious)
|
||||
- [FoXray](https://apps.apple.com/app/foxray/id6448898396)
|
||||
- Linux
|
||||
- [v2rayA](https://github.com/v2rayA/v2rayA)
|
||||
- [NekoRay](https://github.com/Matsuridayo/nekoray)
|
||||
- [Furious](https://github.com/LorenEteval/Furious)
|
||||
|
||||
## Others that support VLESS, XTLS, REALITY, XUDP, PLUX...
|
||||
|
||||
|
@ -87,6 +96,7 @@
|
|||
- [xtlsapi](https://github.com/hiddify/xtlsapi)
|
||||
- [AndroidLibXrayLite](https://github.com/2dust/AndroidLibXrayLite)
|
||||
- [XrayKit](https://github.com/arror/XrayKit)
|
||||
- [Xray-core-python](https://github.com/LorenEteval/Xray-core-python)
|
||||
- [XrayR](https://github.com/XrayR-project/XrayR)
|
||||
- [XrayR-release](https://github.com/XrayR-project/XrayR-release)
|
||||
- [XrayR-V2Board](https://github.com/missuo/XrayR-V2Board)
|
||||
|
|
|
@ -4,7 +4,6 @@ package dispatcher
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
@ -135,77 +134,10 @@ func (*DefaultDispatcher) Start() error {
|
|||
// Close implements common.Closable.
|
||||
func (*DefaultDispatcher) Close() error { return nil }
|
||||
|
||||
func (d *DefaultDispatcher) getLink(ctx context.Context, network net.Network, sniffing session.SniffingRequest) (*transport.Link, *transport.Link) {
|
||||
downOpt := pipe.OptionsFromContext(ctx)
|
||||
upOpt := downOpt
|
||||
|
||||
if network == net.Network_UDP {
|
||||
var ip2domain *sync.Map // net.IP.String() => domain, this map is used by server side when client turn on fakedns
|
||||
// Client will send domain address in the buffer.UDP.Address, server record all possible target IP addrs.
|
||||
// When target replies, server will restore the domain and send back to client.
|
||||
// Note: this map is not global but per connection context
|
||||
upOpt = append(upOpt, pipe.OnTransmission(func(mb buf.MultiBuffer) buf.MultiBuffer {
|
||||
for i, buffer := range mb {
|
||||
if buffer.UDP == nil {
|
||||
continue
|
||||
}
|
||||
addr := buffer.UDP.Address
|
||||
if addr.Family().IsIP() {
|
||||
if fkr0, ok := d.fdns.(dns.FakeDNSEngineRev0); ok && fkr0.IsIPInIPPool(addr) && sniffing.Enabled {
|
||||
domain := fkr0.GetDomainFromFakeDNS(addr)
|
||||
if len(domain) > 0 {
|
||||
buffer.UDP.Address = net.DomainAddress(domain)
|
||||
newError("[fakedns client] override with domain: ", domain, " for xUDP buffer at ", i).WriteToLog(session.ExportIDToError(ctx))
|
||||
} else {
|
||||
newError("[fakedns client] failed to find domain! :", addr.String(), " for xUDP buffer at ", i).AtWarning().WriteToLog(session.ExportIDToError(ctx))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ip2domain == nil {
|
||||
ip2domain = new(sync.Map)
|
||||
newError("[fakedns client] create a new map").WriteToLog(session.ExportIDToError(ctx))
|
||||
}
|
||||
domain := addr.Domain()
|
||||
ips, err := d.dns.LookupIP(domain, dns.IPOption{true, true, false})
|
||||
if err == nil {
|
||||
for _, ip := range ips {
|
||||
ip2domain.Store(ip.String(), domain)
|
||||
}
|
||||
newError("[fakedns client] candidate ip: "+fmt.Sprintf("%v", ips), " for xUDP buffer at ", i).WriteToLog(session.ExportIDToError(ctx))
|
||||
} else {
|
||||
newError("[fakedns client] failed to look up IP for ", domain, " for xUDP buffer at ", i).Base(err).WriteToLog(session.ExportIDToError(ctx))
|
||||
}
|
||||
}
|
||||
}
|
||||
return mb
|
||||
}))
|
||||
downOpt = append(downOpt, pipe.OnTransmission(func(mb buf.MultiBuffer) buf.MultiBuffer {
|
||||
for i, buffer := range mb {
|
||||
if buffer.UDP == nil {
|
||||
continue
|
||||
}
|
||||
addr := buffer.UDP.Address
|
||||
if addr.Family().IsIP() {
|
||||
if ip2domain == nil {
|
||||
continue
|
||||
}
|
||||
if domain, found := ip2domain.Load(addr.IP().String()); found {
|
||||
buffer.UDP.Address = net.DomainAddress(domain.(string))
|
||||
newError("[fakedns client] restore domain: ", domain.(string), " for xUDP buffer at ", i).WriteToLog(session.ExportIDToError(ctx))
|
||||
}
|
||||
} else {
|
||||
if fkr0, ok := d.fdns.(dns.FakeDNSEngineRev0); ok {
|
||||
fakeIp := fkr0.GetFakeIPForDomain(addr.Domain())
|
||||
buffer.UDP.Address = fakeIp[0]
|
||||
newError("[fakedns client] restore FakeIP: ", buffer.UDP, fmt.Sprintf("%v", fakeIp), " for xUDP buffer at ", i).WriteToLog(session.ExportIDToError(ctx))
|
||||
}
|
||||
}
|
||||
}
|
||||
return mb
|
||||
}))
|
||||
}
|
||||
uplinkReader, uplinkWriter := pipe.New(upOpt...)
|
||||
downlinkReader, downlinkWriter := pipe.New(downOpt...)
|
||||
func (d *DefaultDispatcher) getLink(ctx context.Context) (*transport.Link, *transport.Link) {
|
||||
opt := pipe.OptionsFromContext(ctx)
|
||||
uplinkReader, uplinkWriter := pipe.New(opt...)
|
||||
downlinkReader, downlinkWriter := pipe.New(opt...)
|
||||
|
||||
inboundLink := &transport.Link{
|
||||
Reader: downlinkReader,
|
||||
|
@ -263,7 +195,7 @@ func (d *DefaultDispatcher) shouldOverride(ctx context.Context, result SniffResu
|
|||
protocolString = resComp.ProtocolForDomainResult()
|
||||
}
|
||||
for _, p := range request.OverrideDestinationForProtocol {
|
||||
if strings.HasPrefix(protocolString, p) {
|
||||
if strings.HasPrefix(protocolString, p) || strings.HasPrefix(p, protocolString) {
|
||||
return true
|
||||
}
|
||||
if fkr0, ok := d.fdns.(dns.FakeDNSEngineRev0); ok && protocolString != "bittorrent" && p == "fakedns" &&
|
||||
|
@ -286,18 +218,20 @@ func (d *DefaultDispatcher) Dispatch(ctx context.Context, destination net.Destin
|
|||
if !destination.IsValid() {
|
||||
panic("Dispatcher: Invalid destination.")
|
||||
}
|
||||
ob := &session.Outbound{
|
||||
Target: destination,
|
||||
}
|
||||
ob := session.OutboundFromContext(ctx)
|
||||
if ob == nil {
|
||||
ob = &session.Outbound{}
|
||||
ctx = session.ContextWithOutbound(ctx, ob)
|
||||
}
|
||||
ob.OriginalTarget = destination
|
||||
ob.Target = destination
|
||||
content := session.ContentFromContext(ctx)
|
||||
if content == nil {
|
||||
content = new(session.Content)
|
||||
ctx = session.ContextWithContent(ctx, content)
|
||||
}
|
||||
|
||||
sniffingRequest := content.SniffingRequest
|
||||
inbound, outbound := d.getLink(ctx, destination.Network, sniffingRequest)
|
||||
inbound, outbound := d.getLink(ctx)
|
||||
if !sniffingRequest.Enabled {
|
||||
go d.routedDispatch(ctx, outbound, destination)
|
||||
} else {
|
||||
|
@ -314,7 +248,15 @@ func (d *DefaultDispatcher) Dispatch(ctx context.Context, destination net.Destin
|
|||
domain := result.Domain()
|
||||
newError("sniffed domain: ", domain).WriteToLog(session.ExportIDToError(ctx))
|
||||
destination.Address = net.ParseAddress(domain)
|
||||
if sniffingRequest.RouteOnly && result.Protocol() != "fakedns" {
|
||||
protocol := result.Protocol()
|
||||
if resComp, ok := result.(SnifferResultComposite); ok {
|
||||
protocol = resComp.ProtocolForDomainResult()
|
||||
}
|
||||
isFakeIP := false
|
||||
if fkr0, ok := d.fdns.(dns.FakeDNSEngineRev0); ok && ob.Target.Address.Family().IsIP() && fkr0.IsIPInIPPool(ob.Target.Address) {
|
||||
isFakeIP = true
|
||||
}
|
||||
if sniffingRequest.RouteOnly && protocol != "fakedns" && protocol != "fakedns+others" && !isFakeIP {
|
||||
ob.RouteTarget = destination
|
||||
} else {
|
||||
ob.Target = destination
|
||||
|
@ -331,10 +273,13 @@ func (d *DefaultDispatcher) DispatchLink(ctx context.Context, destination net.De
|
|||
if !destination.IsValid() {
|
||||
return newError("Dispatcher: Invalid destination.")
|
||||
}
|
||||
ob := &session.Outbound{
|
||||
Target: destination,
|
||||
}
|
||||
ob := session.OutboundFromContext(ctx)
|
||||
if ob == nil {
|
||||
ob = &session.Outbound{}
|
||||
ctx = session.ContextWithOutbound(ctx, ob)
|
||||
}
|
||||
ob.OriginalTarget = destination
|
||||
ob.Target = destination
|
||||
content := session.ContentFromContext(ctx)
|
||||
if content == nil {
|
||||
content = new(session.Content)
|
||||
|
@ -356,7 +301,15 @@ func (d *DefaultDispatcher) DispatchLink(ctx context.Context, destination net.De
|
|||
domain := result.Domain()
|
||||
newError("sniffed domain: ", domain).WriteToLog(session.ExportIDToError(ctx))
|
||||
destination.Address = net.ParseAddress(domain)
|
||||
if sniffingRequest.RouteOnly && result.Protocol() != "fakedns" {
|
||||
protocol := result.Protocol()
|
||||
if resComp, ok := result.(SnifferResultComposite); ok {
|
||||
protocol = resComp.ProtocolForDomainResult()
|
||||
}
|
||||
isFakeIP := false
|
||||
if fkr0, ok := d.fdns.(dns.FakeDNSEngineRev0); ok && ob.Target.Address.Family().IsIP() && fkr0.IsIPInIPPool(ob.Target.Address) {
|
||||
isFakeIP = true
|
||||
}
|
||||
if sniffingRequest.RouteOnly && protocol != "fakedns" && protocol != "fakedns+others" && !isFakeIP {
|
||||
ob.RouteTarget = destination
|
||||
} else {
|
||||
ob.Target = destination
|
||||
|
|
|
@ -134,6 +134,7 @@ type NameServer struct {
|
|||
PrioritizedDomain []*NameServer_PriorityDomain `protobuf:"bytes,2,rep,name=prioritized_domain,json=prioritizedDomain,proto3" json:"prioritized_domain,omitempty"`
|
||||
Geoip []*router.GeoIP `protobuf:"bytes,3,rep,name=geoip,proto3" json:"geoip,omitempty"`
|
||||
OriginalRules []*NameServer_OriginalRule `protobuf:"bytes,4,rep,name=original_rules,json=originalRules,proto3" json:"original_rules,omitempty"`
|
||||
QueryStrategy QueryStrategy `protobuf:"varint,7,opt,name=query_strategy,json=queryStrategy,proto3,enum=xray.app.dns.QueryStrategy" json:"query_strategy,omitempty"`
|
||||
}
|
||||
|
||||
func (x *NameServer) Reset() {
|
||||
|
@ -210,6 +211,13 @@ func (x *NameServer) GetOriginalRules() []*NameServer_OriginalRule {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (x *NameServer) GetQueryStrategy() QueryStrategy {
|
||||
if x != nil {
|
||||
return x.QueryStrategy
|
||||
}
|
||||
return QueryStrategy_USE_IP
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
|
@ -538,7 +546,7 @@ var file_app_dns_config_proto_rawDesc = []byte{
|
|||
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x64, 0x65, 0x73, 0x74, 0x69,
|
||||
0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x17, 0x61, 0x70,
|
||||
0x70, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xee, 0x03, 0x0a, 0x0a, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb2, 0x04, 0x0a, 0x0a, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65,
|
||||
0x72, 0x76, 0x65, 0x72, 0x12, 0x33, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d,
|
||||
0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74,
|
||||
|
@ -559,77 +567,81 @@ var file_app_dns_config_proto_rawDesc = []byte{
|
|||
0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
||||
0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76,
|
||||
0x65, 0x72, 0x2e, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65, 0x52,
|
||||
0x0d, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x1a, 0x5e,
|
||||
0x0a, 0x0e, 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
|
||||
0x12, 0x34, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20,
|
||||
0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x44, 0x6f,
|
||||
0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x54, 0x79, 0x70, 0x65,
|
||||
0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
|
||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x1a, 0x36,
|
||||
0x0a, 0x0c, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x12,
|
||||
0x0a, 0x04, 0x72, 0x75, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x75,
|
||||
0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d,
|
||||
0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x22, 0xef, 0x05, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69,
|
||||
0x67, 0x12, 0x3f, 0x0a, 0x0b, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73,
|
||||
0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,
|
||||
0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e,
|
||||
0x74, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0b, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65,
|
||||
0x72, 0x73, 0x12, 0x39, 0x0a, 0x0b, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65,
|
||||
0x72, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61,
|
||||
0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65,
|
||||
0x72, 0x52, 0x0a, 0x6e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x39, 0x0a,
|
||||
0x05, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x78,
|
||||
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x66,
|
||||
0x69, 0x67, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x42, 0x02, 0x18,
|
||||
0x01, 0x52, 0x05, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65,
|
||||
0x6e, 0x74, 0x5f, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x63, 0x6c, 0x69,
|
||||
0x65, 0x6e, 0x74, 0x49, 0x70, 0x12, 0x43, 0x0a, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5f,
|
||||
0x68, 0x6f, 0x73, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72,
|
||||
0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69,
|
||||
0x67, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x52, 0x0b, 0x73,
|
||||
0x74, 0x61, 0x74, 0x69, 0x63, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61,
|
||||
0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x22, 0x0a, 0x0c,
|
||||
0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x18, 0x08, 0x20, 0x01,
|
||||
0x28, 0x08, 0x52, 0x0c, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65,
|
||||
0x12, 0x42, 0x0a, 0x0e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65,
|
||||
0x67, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
||||
0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x72,
|
||||
0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0d, 0x71, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x72, 0x61,
|
||||
0x74, 0x65, 0x67, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46,
|
||||
0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x64,
|
||||
0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x12, 0x36,
|
||||
0x0a, 0x16, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63,
|
||||
0x6b, 0x49, 0x66, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16,
|
||||
0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x49,
|
||||
0x66, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x1a, 0x55, 0x0a, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x45,
|
||||
0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x31, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18,
|
||||
0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d,
|
||||
0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61,
|
||||
0x69, 0x6e, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x92, 0x01,
|
||||
0x0a, 0x0b, 0x48, 0x6f, 0x73, 0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x34, 0x0a,
|
||||
0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x78, 0x72,
|
||||
0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69,
|
||||
0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74,
|
||||
0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69,
|
||||
0x70, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x70, 0x12, 0x25, 0x0a, 0x0e, 0x70,
|
||||
0x72, 0x6f, 0x78, 0x69, 0x65, 0x64, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x04, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x69, 0x65, 0x64, 0x44, 0x6f, 0x6d, 0x61,
|
||||
0x69, 0x6e, 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08, 0x2a, 0x45, 0x0a, 0x12, 0x44, 0x6f, 0x6d, 0x61,
|
||||
0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x54, 0x79, 0x70, 0x65, 0x12, 0x08,
|
||||
0x0a, 0x04, 0x46, 0x75, 0x6c, 0x6c, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x53, 0x75, 0x62, 0x64,
|
||||
0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x4b, 0x65, 0x79, 0x77, 0x6f,
|
||||
0x72, 0x64, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x52, 0x65, 0x67, 0x65, 0x78, 0x10, 0x03, 0x2a,
|
||||
0x35, 0x0a, 0x0d, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79,
|
||||
0x12, 0x0a, 0x0a, 0x06, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07,
|
||||
0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45,
|
||||
0x5f, 0x49, 0x50, 0x36, 0x10, 0x02, 0x42, 0x46, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72,
|
||||
0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x50, 0x01, 0x5a, 0x21, 0x67, 0x69,
|
||||
0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72,
|
||||
0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x64, 0x6e, 0x73, 0xaa,
|
||||
0x02, 0x0c, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x44, 0x6e, 0x73, 0x62, 0x06,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x0d, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x42,
|
||||
0x0a, 0x0e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79,
|
||||
0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
|
||||
0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x72, 0x61, 0x74,
|
||||
0x65, 0x67, 0x79, 0x52, 0x0d, 0x71, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65,
|
||||
0x67, 0x79, 0x1a, 0x5e, 0x0a, 0x0e, 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f,
|
||||
0x6d, 0x61, 0x69, 0x6e, 0x12, 0x34, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x0e, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e,
|
||||
0x73, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67,
|
||||
0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f,
|
||||
0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61,
|
||||
0x69, 0x6e, 0x1a, 0x36, 0x0a, 0x0c, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x75,
|
||||
0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x75, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x04, 0x72, 0x75, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x22, 0xef, 0x05, 0x0a, 0x06, 0x43,
|
||||
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3f, 0x0a, 0x0b, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72,
|
||||
0x76, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72, 0x61,
|
||||
0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x45, 0x6e, 0x64,
|
||||
0x70, 0x6f, 0x69, 0x6e, 0x74, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0b, 0x4e, 0x61, 0x6d, 0x65, 0x53,
|
||||
0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x12, 0x39, 0x0a, 0x0b, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x73,
|
||||
0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x78, 0x72,
|
||||
0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x53,
|
||||
0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x0a, 0x6e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65,
|
||||
0x72, 0x12, 0x39, 0x0a, 0x05, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b,
|
||||
0x32, 0x1f, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e,
|
||||
0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72,
|
||||
0x79, 0x42, 0x02, 0x18, 0x01, 0x52, 0x05, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x1b, 0x0a, 0x09,
|
||||
0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52,
|
||||
0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x70, 0x12, 0x43, 0x0a, 0x0c, 0x73, 0x74, 0x61,
|
||||
0x74, 0x69, 0x63, 0x5f, 0x68, 0x6f, 0x73, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32,
|
||||
0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x43,
|
||||
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e,
|
||||
0x67, 0x52, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x10,
|
||||
0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67,
|
||||
0x12, 0x22, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65,
|
||||
0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x43,
|
||||
0x61, 0x63, 0x68, 0x65, 0x12, 0x42, 0x0a, 0x0e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x73, 0x74,
|
||||
0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x78,
|
||||
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x51, 0x75, 0x65, 0x72,
|
||||
0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0d, 0x71, 0x75, 0x65, 0x72, 0x79,
|
||||
0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x64, 0x69, 0x73, 0x61,
|
||||
0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x18, 0x0a, 0x20, 0x01, 0x28,
|
||||
0x08, 0x52, 0x0f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61,
|
||||
0x63, 0x6b, 0x12, 0x36, 0x0a, 0x16, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c,
|
||||
0x6c, 0x62, 0x61, 0x63, 0x6b, 0x49, 0x66, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x0b, 0x20, 0x01,
|
||||
0x28, 0x08, 0x52, 0x16, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62,
|
||||
0x61, 0x63, 0x6b, 0x49, 0x66, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x1a, 0x55, 0x0a, 0x0a, 0x48, 0x6f,
|
||||
0x73, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x31, 0x0a, 0x05, 0x76, 0x61,
|
||||
0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
||||
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72,
|
||||
0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38,
|
||||
0x01, 0x1a, 0x92, 0x01, 0x0a, 0x0b, 0x48, 0x6f, 0x73, 0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e,
|
||||
0x67, 0x12, 0x34, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32,
|
||||
0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x44,
|
||||
0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x54, 0x79, 0x70,
|
||||
0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69,
|
||||
0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12,
|
||||
0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x70, 0x12,
|
||||
0x25, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78, 0x69, 0x65, 0x64, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69,
|
||||
0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x69, 0x65, 0x64,
|
||||
0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08, 0x2a, 0x45, 0x0a, 0x12,
|
||||
0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x54, 0x79,
|
||||
0x70, 0x65, 0x12, 0x08, 0x0a, 0x04, 0x46, 0x75, 0x6c, 0x6c, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09,
|
||||
0x53, 0x75, 0x62, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x4b,
|
||||
0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x52, 0x65, 0x67, 0x65,
|
||||
0x78, 0x10, 0x03, 0x2a, 0x35, 0x0a, 0x0d, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x74, 0x72, 0x61,
|
||||
0x74, 0x65, 0x67, 0x79, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x10, 0x00,
|
||||
0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x10, 0x01, 0x12, 0x0b, 0x0a,
|
||||
0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x10, 0x02, 0x42, 0x46, 0x0a, 0x10, 0x63, 0x6f,
|
||||
0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x50, 0x01,
|
||||
0x5a, 0x21, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c,
|
||||
0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f,
|
||||
0x64, 0x6e, 0x73, 0xaa, 0x02, 0x0c, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x44,
|
||||
0x6e, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
|
@ -664,19 +676,20 @@ var file_app_dns_config_proto_depIdxs = []int32{
|
|||
4, // 1: xray.app.dns.NameServer.prioritized_domain:type_name -> xray.app.dns.NameServer.PriorityDomain
|
||||
9, // 2: xray.app.dns.NameServer.geoip:type_name -> xray.app.router.GeoIP
|
||||
5, // 3: xray.app.dns.NameServer.original_rules:type_name -> xray.app.dns.NameServer.OriginalRule
|
||||
8, // 4: xray.app.dns.Config.NameServers:type_name -> xray.common.net.Endpoint
|
||||
2, // 5: xray.app.dns.Config.name_server:type_name -> xray.app.dns.NameServer
|
||||
6, // 6: xray.app.dns.Config.Hosts:type_name -> xray.app.dns.Config.HostsEntry
|
||||
7, // 7: xray.app.dns.Config.static_hosts:type_name -> xray.app.dns.Config.HostMapping
|
||||
1, // 8: xray.app.dns.Config.query_strategy:type_name -> xray.app.dns.QueryStrategy
|
||||
0, // 9: xray.app.dns.NameServer.PriorityDomain.type:type_name -> xray.app.dns.DomainMatchingType
|
||||
10, // 10: xray.app.dns.Config.HostsEntry.value:type_name -> xray.common.net.IPOrDomain
|
||||
0, // 11: xray.app.dns.Config.HostMapping.type:type_name -> xray.app.dns.DomainMatchingType
|
||||
12, // [12:12] is the sub-list for method output_type
|
||||
12, // [12:12] is the sub-list for method input_type
|
||||
12, // [12:12] is the sub-list for extension type_name
|
||||
12, // [12:12] is the sub-list for extension extendee
|
||||
0, // [0:12] is the sub-list for field type_name
|
||||
1, // 4: xray.app.dns.NameServer.query_strategy:type_name -> xray.app.dns.QueryStrategy
|
||||
8, // 5: xray.app.dns.Config.NameServers:type_name -> xray.common.net.Endpoint
|
||||
2, // 6: xray.app.dns.Config.name_server:type_name -> xray.app.dns.NameServer
|
||||
6, // 7: xray.app.dns.Config.Hosts:type_name -> xray.app.dns.Config.HostsEntry
|
||||
7, // 8: xray.app.dns.Config.static_hosts:type_name -> xray.app.dns.Config.HostMapping
|
||||
1, // 9: xray.app.dns.Config.query_strategy:type_name -> xray.app.dns.QueryStrategy
|
||||
0, // 10: xray.app.dns.NameServer.PriorityDomain.type:type_name -> xray.app.dns.DomainMatchingType
|
||||
10, // 11: xray.app.dns.Config.HostsEntry.value:type_name -> xray.common.net.IPOrDomain
|
||||
0, // 12: xray.app.dns.Config.HostMapping.type:type_name -> xray.app.dns.DomainMatchingType
|
||||
13, // [13:13] is the sub-list for method output_type
|
||||
13, // [13:13] is the sub-list for method input_type
|
||||
13, // [13:13] is the sub-list for extension type_name
|
||||
13, // [13:13] is the sub-list for extension extendee
|
||||
0, // [0:13] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_app_dns_config_proto_init() }
|
||||
|
|
|
@ -28,6 +28,7 @@ message NameServer {
|
|||
repeated PriorityDomain prioritized_domain = 2;
|
||||
repeated xray.app.router.GeoIP geoip = 3;
|
||||
repeated OriginalRule original_rules = 4;
|
||||
QueryStrategy query_strategy = 7;
|
||||
}
|
||||
|
||||
enum DomainMatchingType {
|
||||
|
|
|
@ -35,7 +35,7 @@ type Client struct {
|
|||
var errExpectedIPNonMatch = errors.New("expectIPs not match")
|
||||
|
||||
// NewServer creates a name server object according to the network destination url.
|
||||
func NewServer(dest net.Destination, dispatcher routing.Dispatcher) (Server, error) {
|
||||
func NewServer(dest net.Destination, dispatcher routing.Dispatcher, queryStrategy QueryStrategy) (Server, error) {
|
||||
if address := dest.Address; address.Family().IsDomain() {
|
||||
u, err := url.Parse(address.Domain())
|
||||
if err != nil {
|
||||
|
@ -45,15 +45,15 @@ func NewServer(dest net.Destination, dispatcher routing.Dispatcher) (Server, err
|
|||
case strings.EqualFold(u.String(), "localhost"):
|
||||
return NewLocalNameServer(), nil
|
||||
case strings.EqualFold(u.Scheme, "https"): // DOH Remote mode
|
||||
return NewDoHNameServer(u, dispatcher)
|
||||
return NewDoHNameServer(u, dispatcher, queryStrategy)
|
||||
case strings.EqualFold(u.Scheme, "https+local"): // DOH Local mode
|
||||
return NewDoHLocalNameServer(u), nil
|
||||
return NewDoHLocalNameServer(u, queryStrategy), nil
|
||||
case strings.EqualFold(u.Scheme, "quic+local"): // DNS-over-QUIC Local mode
|
||||
return NewQUICNameServer(u)
|
||||
return NewQUICNameServer(u, queryStrategy)
|
||||
case strings.EqualFold(u.Scheme, "tcp"): // DNS-over-TCP Remote mode
|
||||
return NewTCPNameServer(u, dispatcher)
|
||||
return NewTCPNameServer(u, dispatcher, queryStrategy)
|
||||
case strings.EqualFold(u.Scheme, "tcp+local"): // DNS-over-TCP Local mode
|
||||
return NewTCPLocalNameServer(u)
|
||||
return NewTCPLocalNameServer(u, queryStrategy)
|
||||
case strings.EqualFold(u.String(), "fakedns"):
|
||||
return NewFakeDNSServer(), nil
|
||||
}
|
||||
|
@ -68,12 +68,19 @@ func NewServer(dest net.Destination, dispatcher routing.Dispatcher) (Server, err
|
|||
}
|
||||
|
||||
// NewClient creates a DNS client managing a name server with client IP, domain rules and expected IPs.
|
||||
func NewClient(ctx context.Context, ns *NameServer, clientIP net.IP, container router.GeoIPMatcherContainer, matcherInfos *[]*DomainMatcherInfo, updateDomainRule func(strmatcher.Matcher, int, []*DomainMatcherInfo) error) (*Client, error) {
|
||||
func NewClient(
|
||||
ctx context.Context,
|
||||
ns *NameServer,
|
||||
clientIP net.IP,
|
||||
container router.GeoIPMatcherContainer,
|
||||
matcherInfos *[]*DomainMatcherInfo,
|
||||
updateDomainRule func(strmatcher.Matcher, int, []*DomainMatcherInfo) error,
|
||||
) (*Client, error) {
|
||||
client := &Client{}
|
||||
|
||||
err := core.RequireFeatures(ctx, func(dispatcher routing.Dispatcher) error {
|
||||
// Create a new server for each client for now
|
||||
server, err := NewServer(ns.Address.AsDestination(), dispatcher)
|
||||
server, err := NewServer(ns.Address.AsDestination(), dispatcher, ns.GetQueryStrategy())
|
||||
if err != nil {
|
||||
return newError("failed to create nameserver").Base(err).AtWarning()
|
||||
}
|
||||
|
@ -160,7 +167,7 @@ func NewClient(ctx context.Context, ns *NameServer, clientIP net.IP, container r
|
|||
func NewSimpleClient(ctx context.Context, endpoint *net.Endpoint, clientIP net.IP) (*Client, error) {
|
||||
client := &Client{}
|
||||
err := core.RequireFeatures(ctx, func(dispatcher routing.Dispatcher) error {
|
||||
server, err := NewServer(endpoint.AsDestination(), dispatcher)
|
||||
server, err := NewServer(endpoint.AsDestination(), dispatcher, QueryStrategy_USE_IP)
|
||||
if err != nil {
|
||||
return newError("failed to create nameserver").Base(err).AtWarning()
|
||||
}
|
||||
|
@ -218,3 +225,24 @@ func (c *Client) MatchExpectedIPs(domain string, ips []net.IP) ([]net.IP, error)
|
|||
newError("domain ", domain, " expectIPs ", newIps, " matched at server ", c.Name()).AtDebug().WriteToLog()
|
||||
return newIps, nil
|
||||
}
|
||||
|
||||
func ResolveIpOptionOverride(queryStrategy QueryStrategy, ipOption dns.IPOption) dns.IPOption {
|
||||
switch queryStrategy {
|
||||
case QueryStrategy_USE_IP:
|
||||
return ipOption
|
||||
case QueryStrategy_USE_IP4:
|
||||
return dns.IPOption{
|
||||
IPv4Enable: ipOption.IPv4Enable,
|
||||
IPv6Enable: false,
|
||||
FakeEnable: false,
|
||||
}
|
||||
case QueryStrategy_USE_IP6:
|
||||
return dns.IPOption{
|
||||
IPv4Enable: false,
|
||||
IPv6Enable: ipOption.IPv6Enable,
|
||||
FakeEnable: false,
|
||||
}
|
||||
default:
|
||||
return ipOption
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,12 +38,13 @@ type DoHNameServer struct {
|
|||
httpClient *http.Client
|
||||
dohURL string
|
||||
name string
|
||||
queryStrategy QueryStrategy
|
||||
}
|
||||
|
||||
// NewDoHNameServer creates DOH server object for remote resolving.
|
||||
func NewDoHNameServer(url *url.URL, dispatcher routing.Dispatcher) (*DoHNameServer, error) {
|
||||
func NewDoHNameServer(url *url.URL, dispatcher routing.Dispatcher, queryStrategy QueryStrategy) (*DoHNameServer, error) {
|
||||
newError("DNS: created Remote DOH client for ", url.String()).AtInfo().WriteToLog()
|
||||
s := baseDOHNameServer(url, "DOH")
|
||||
s := baseDOHNameServer(url, "DOH", queryStrategy)
|
||||
|
||||
s.dispatcher = dispatcher
|
||||
tr := &http.Transport{
|
||||
|
@ -90,9 +91,9 @@ func NewDoHNameServer(url *url.URL, dispatcher routing.Dispatcher) (*DoHNameServ
|
|||
}
|
||||
|
||||
// NewDoHLocalNameServer creates DOH client object for local resolving
|
||||
func NewDoHLocalNameServer(url *url.URL) *DoHNameServer {
|
||||
func NewDoHLocalNameServer(url *url.URL, queryStrategy QueryStrategy) *DoHNameServer {
|
||||
url.Scheme = "https"
|
||||
s := baseDOHNameServer(url, "DOHL")
|
||||
s := baseDOHNameServer(url, "DOHL", queryStrategy)
|
||||
tr := &http.Transport{
|
||||
IdleConnTimeout: 90 * time.Second,
|
||||
ForceAttemptHTTP2: true,
|
||||
|
@ -122,12 +123,13 @@ func NewDoHLocalNameServer(url *url.URL) *DoHNameServer {
|
|||
return s
|
||||
}
|
||||
|
||||
func baseDOHNameServer(url *url.URL, prefix string) *DoHNameServer {
|
||||
func baseDOHNameServer(url *url.URL, prefix string, queryStrategy QueryStrategy) *DoHNameServer {
|
||||
s := &DoHNameServer{
|
||||
ips: make(map[string]*record),
|
||||
pub: pubsub.NewService(),
|
||||
name: prefix + "//" + url.Host,
|
||||
dohURL: url.String(),
|
||||
queryStrategy: queryStrategy,
|
||||
}
|
||||
s.cleanup = &task.Periodic{
|
||||
Interval: time.Minute,
|
||||
|
@ -353,6 +355,10 @@ func (s *DoHNameServer) findIPsForDomain(domain string, option dns_feature.IPOpt
|
|||
// QueryIP implements Server.
|
||||
func (s *DoHNameServer) QueryIP(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption, disableCache bool) ([]net.IP, error) { // nolint: dupl
|
||||
fqdn := Fqdn(domain)
|
||||
option = ResolveIpOptionOverride(s.queryStrategy, option)
|
||||
if !option.IPv4Enable && !option.IPv6Enable {
|
||||
return nil, dns_feature.ErrEmptyResponse
|
||||
}
|
||||
|
||||
if disableCache {
|
||||
newError("DNS cache is disabled. Querying IP for ", domain, " at ", s.name).AtDebug().WriteToLog()
|
||||
|
|
|
@ -17,7 +17,7 @@ func TestDOHNameServer(t *testing.T) {
|
|||
url, err := url.Parse("https+local://1.1.1.1/dns-query")
|
||||
common.Must(err)
|
||||
|
||||
s := NewDoHLocalNameServer(url)
|
||||
s := NewDoHLocalNameServer(url, QueryStrategy_USE_IP)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
|
||||
IPv4Enable: true,
|
||||
|
@ -34,7 +34,7 @@ func TestDOHNameServerWithCache(t *testing.T) {
|
|||
url, err := url.Parse("https+local://1.1.1.1/dns-query")
|
||||
common.Must(err)
|
||||
|
||||
s := NewDoHLocalNameServer(url)
|
||||
s := NewDoHLocalNameServer(url, QueryStrategy_USE_IP)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
|
||||
IPv4Enable: true,
|
||||
|
@ -57,3 +57,49 @@ func TestDOHNameServerWithCache(t *testing.T) {
|
|||
t.Fatal(r)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDOHNameServerWithIPv4Override(t *testing.T) {
|
||||
url, err := url.Parse("https+local://1.1.1.1/dns-query")
|
||||
common.Must(err)
|
||||
|
||||
s := NewDoHLocalNameServer(url, QueryStrategy_USE_IP4)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
}, false)
|
||||
cancel()
|
||||
common.Must(err)
|
||||
if len(ips) == 0 {
|
||||
t.Error("expect some ips, but got 0")
|
||||
}
|
||||
|
||||
for _, ip := range ips {
|
||||
if len(ip) != net.IPv4len {
|
||||
t.Error("expect only IPv4 response from DNS query")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDOHNameServerWithIPv6Override(t *testing.T) {
|
||||
url, err := url.Parse("https+local://1.1.1.1/dns-query")
|
||||
common.Must(err)
|
||||
|
||||
s := NewDoHLocalNameServer(url, QueryStrategy_USE_IP6)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
}, false)
|
||||
cancel()
|
||||
common.Must(err)
|
||||
if len(ips) == 0 {
|
||||
t.Error("expect some ips, but got 0")
|
||||
}
|
||||
|
||||
for _, ip := range ips {
|
||||
if len(ip) != net.IPv6len {
|
||||
t.Error("expect only IPv6 response from DNS query")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,10 +38,11 @@ type QUICNameServer struct {
|
|||
name string
|
||||
destination *net.Destination
|
||||
connection quic.Connection
|
||||
queryStrategy QueryStrategy
|
||||
}
|
||||
|
||||
// NewQUICNameServer creates DNS-over-QUIC client object for local resolving
|
||||
func NewQUICNameServer(url *url.URL) (*QUICNameServer, error) {
|
||||
func NewQUICNameServer(url *url.URL, queryStrategy QueryStrategy) (*QUICNameServer, error) {
|
||||
newError("DNS: created Local DNS-over-QUIC client for ", url.String()).AtInfo().WriteToLog()
|
||||
|
||||
var err error
|
||||
|
@ -59,6 +60,7 @@ func NewQUICNameServer(url *url.URL) (*QUICNameServer, error) {
|
|||
pub: pubsub.NewService(),
|
||||
name: url.String(),
|
||||
destination: &dest,
|
||||
queryStrategy: queryStrategy,
|
||||
}
|
||||
s.cleanup = &task.Periodic{
|
||||
Interval: time.Minute,
|
||||
|
@ -269,6 +271,10 @@ func (s *QUICNameServer) findIPsForDomain(domain string, option dns_feature.IPOp
|
|||
// QueryIP is called from dns.Server->queryIPTimeout
|
||||
func (s *QUICNameServer) QueryIP(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption, disableCache bool) ([]net.IP, error) {
|
||||
fqdn := Fqdn(domain)
|
||||
option = ResolveIpOptionOverride(s.queryStrategy, option)
|
||||
if !option.IPv4Enable && !option.IPv6Enable {
|
||||
return nil, dns_feature.ErrEmptyResponse
|
||||
}
|
||||
|
||||
if disableCache {
|
||||
newError("DNS cache is disabled. Querying IP for ", domain, " at ", s.name).AtDebug().WriteToLog()
|
||||
|
|
|
@ -16,7 +16,7 @@ import (
|
|||
func TestQUICNameServer(t *testing.T) {
|
||||
url, err := url.Parse("quic://dns.adguard.com")
|
||||
common.Must(err)
|
||||
s, err := NewQUICNameServer(url)
|
||||
s, err := NewQUICNameServer(url, QueryStrategy_USE_IP)
|
||||
common.Must(err)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
|
||||
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns.IPOption{
|
||||
|
@ -40,3 +40,49 @@ func TestQUICNameServer(t *testing.T) {
|
|||
t.Fatal(r)
|
||||
}
|
||||
}
|
||||
|
||||
func TestQUICNameServerWithIPv4Override(t *testing.T) {
|
||||
url, err := url.Parse("quic://dns.adguard.com")
|
||||
common.Must(err)
|
||||
s, err := NewQUICNameServer(url, QueryStrategy_USE_IP4)
|
||||
common.Must(err)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
|
||||
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
}, false)
|
||||
cancel()
|
||||
common.Must(err)
|
||||
if len(ips) == 0 {
|
||||
t.Error("expect some ips, but got 0")
|
||||
}
|
||||
|
||||
for _, ip := range ips {
|
||||
if len(ip) != net.IPv4len {
|
||||
t.Error("expect only IPv4 response from DNS query")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestQUICNameServerWithIPv6Override(t *testing.T) {
|
||||
url, err := url.Parse("quic://dns.adguard.com")
|
||||
common.Must(err)
|
||||
s, err := NewQUICNameServer(url, QueryStrategy_USE_IP6)
|
||||
common.Must(err)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
|
||||
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
}, false)
|
||||
cancel()
|
||||
common.Must(err)
|
||||
if len(ips) == 0 {
|
||||
t.Error("expect some ips, but got 0")
|
||||
}
|
||||
|
||||
for _, ip := range ips {
|
||||
if len(ip) != net.IPv6len {
|
||||
t.Error("expect only IPv6 response from DNS query")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,11 +34,16 @@ type TCPNameServer struct {
|
|||
cleanup *task.Periodic
|
||||
reqID uint32
|
||||
dial func(context.Context) (net.Conn, error)
|
||||
queryStrategy QueryStrategy
|
||||
}
|
||||
|
||||
// NewTCPNameServer creates DNS over TCP server object for remote resolving.
|
||||
func NewTCPNameServer(url *url.URL, dispatcher routing.Dispatcher) (*TCPNameServer, error) {
|
||||
s, err := baseTCPNameServer(url, "TCP")
|
||||
func NewTCPNameServer(
|
||||
url *url.URL,
|
||||
dispatcher routing.Dispatcher,
|
||||
queryStrategy QueryStrategy,
|
||||
) (*TCPNameServer, error) {
|
||||
s, err := baseTCPNameServer(url, "TCP", queryStrategy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -59,8 +64,8 @@ func NewTCPNameServer(url *url.URL, dispatcher routing.Dispatcher) (*TCPNameServ
|
|||
}
|
||||
|
||||
// NewTCPLocalNameServer creates DNS over TCP client object for local resolving
|
||||
func NewTCPLocalNameServer(url *url.URL) (*TCPNameServer, error) {
|
||||
s, err := baseTCPNameServer(url, "TCPL")
|
||||
func NewTCPLocalNameServer(url *url.URL, queryStrategy QueryStrategy) (*TCPNameServer, error) {
|
||||
s, err := baseTCPNameServer(url, "TCPL", queryStrategy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -72,12 +77,11 @@ func NewTCPLocalNameServer(url *url.URL) (*TCPNameServer, error) {
|
|||
return s, nil
|
||||
}
|
||||
|
||||
func baseTCPNameServer(url *url.URL, prefix string) (*TCPNameServer, error) {
|
||||
var err error
|
||||
func baseTCPNameServer(url *url.URL, prefix string, queryStrategy QueryStrategy) (*TCPNameServer, error) {
|
||||
port := net.Port(53)
|
||||
if url.Port() != "" {
|
||||
port, err = net.PortFromString(url.Port())
|
||||
if err != nil {
|
||||
var err error
|
||||
if port, err = net.PortFromString(url.Port()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
@ -88,6 +92,7 @@ func baseTCPNameServer(url *url.URL, prefix string) (*TCPNameServer, error) {
|
|||
ips: make(map[string]*record),
|
||||
pub: pubsub.NewService(),
|
||||
name: prefix + "//" + dest.NetAddr(),
|
||||
queryStrategy: queryStrategy,
|
||||
}
|
||||
s.cleanup = &task.Periodic{
|
||||
Interval: time.Minute,
|
||||
|
@ -308,6 +313,10 @@ func (s *TCPNameServer) findIPsForDomain(domain string, option dns_feature.IPOpt
|
|||
// QueryIP implements Server.
|
||||
func (s *TCPNameServer) QueryIP(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption, disableCache bool) ([]net.IP, error) {
|
||||
fqdn := Fqdn(domain)
|
||||
option = ResolveIpOptionOverride(s.queryStrategy, option)
|
||||
if !option.IPv4Enable && !option.IPv6Enable {
|
||||
return nil, dns_feature.ErrEmptyResponse
|
||||
}
|
||||
|
||||
if disableCache {
|
||||
newError("DNS cache is disabled. Querying IP for ", domain, " at ", s.name).AtDebug().WriteToLog()
|
||||
|
|
|
@ -16,7 +16,7 @@ import (
|
|||
func TestTCPLocalNameServer(t *testing.T) {
|
||||
url, err := url.Parse("tcp+local://8.8.8.8")
|
||||
common.Must(err)
|
||||
s, err := NewTCPLocalNameServer(url)
|
||||
s, err := NewTCPLocalNameServer(url, QueryStrategy_USE_IP)
|
||||
common.Must(err)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
|
||||
|
@ -33,7 +33,7 @@ func TestTCPLocalNameServer(t *testing.T) {
|
|||
func TestTCPLocalNameServerWithCache(t *testing.T) {
|
||||
url, err := url.Parse("tcp+local://8.8.8.8")
|
||||
common.Must(err)
|
||||
s, err := NewTCPLocalNameServer(url)
|
||||
s, err := NewTCPLocalNameServer(url, QueryStrategy_USE_IP)
|
||||
common.Must(err)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
|
||||
|
@ -57,3 +57,51 @@ func TestTCPLocalNameServerWithCache(t *testing.T) {
|
|||
t.Fatal(r)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTCPLocalNameServerWithIPv4Override(t *testing.T) {
|
||||
url, err := url.Parse("tcp+local://8.8.8.8")
|
||||
common.Must(err)
|
||||
s, err := NewTCPLocalNameServer(url, QueryStrategy_USE_IP4)
|
||||
common.Must(err)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
}, false)
|
||||
cancel()
|
||||
common.Must(err)
|
||||
|
||||
if len(ips) == 0 {
|
||||
t.Error("expect some ips, but got 0")
|
||||
}
|
||||
|
||||
for _, ip := range ips {
|
||||
if len(ip) != net.IPv4len {
|
||||
t.Error("expect only IPv4 response from DNS query")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTCPLocalNameServerWithIPv6Override(t *testing.T) {
|
||||
url, err := url.Parse("tcp+local://8.8.8.8")
|
||||
common.Must(err)
|
||||
s, err := NewTCPLocalNameServer(url, QueryStrategy_USE_IP6)
|
||||
common.Must(err)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
}, false)
|
||||
cancel()
|
||||
common.Must(err)
|
||||
|
||||
if len(ips) == 0 {
|
||||
t.Error("expect some ips, but got 0")
|
||||
}
|
||||
|
||||
for _, ip := range ips {
|
||||
if len(ip) != net.IPv6len {
|
||||
t.Error("expect only IPv6 response from DNS query")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/xtls/xray-core/common"
|
||||
v2net "github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/session"
|
||||
|
@ -19,6 +18,7 @@ import (
|
|||
"github.com/xtls/xray-core/features/extension"
|
||||
"github.com/xtls/xray-core/features/outbound"
|
||||
"github.com/xtls/xray-core/transport/internet/tagged"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type Observer struct {
|
||||
|
|
|
@ -61,6 +61,7 @@ func (w *tcpWorker) callback(conn stat.Connection) {
|
|||
sid := session.NewID()
|
||||
ctx = session.ContextWithID(ctx, sid)
|
||||
|
||||
var outbound = &session.Outbound{}
|
||||
if w.recvOrigDest {
|
||||
var dest net.Destination
|
||||
switch getTProxyType(w.stream) {
|
||||
|
@ -75,11 +76,10 @@ func (w *tcpWorker) callback(conn stat.Connection) {
|
|||
dest = net.DestinationFromAddr(conn.LocalAddr())
|
||||
}
|
||||
if dest.IsValid() {
|
||||
ctx = session.ContextWithOutbound(ctx, &session.Outbound{
|
||||
Target: dest,
|
||||
})
|
||||
outbound.Target = dest
|
||||
}
|
||||
}
|
||||
ctx = session.ContextWithOutbound(ctx, outbound)
|
||||
|
||||
if w.uplinkCounter != nil || w.downlinkCounter != nil {
|
||||
conn = &stat.CounterConnection{
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
|
||||
"github.com/xtls/xray-core/app/proxyman"
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/buf"
|
||||
"github.com/xtls/xray-core/common/mux"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/net/cnc"
|
||||
|
@ -166,6 +167,11 @@ func (h *Handler) Tag() string {
|
|||
|
||||
// Dispatch implements proxy.Outbound.Dispatch.
|
||||
func (h *Handler) Dispatch(ctx context.Context, link *transport.Link) {
|
||||
outbound := session.OutboundFromContext(ctx)
|
||||
if outbound.Target.Network == net.Network_UDP && outbound.OriginalTarget.Address != nil && outbound.OriginalTarget.Address != outbound.Target.Address {
|
||||
link.Reader = &buf.EndpointOverrideReader{Reader: link.Reader, Dest: outbound.Target.Address, OriginalDest: outbound.OriginalTarget.Address}
|
||||
link.Writer = &buf.EndpointOverrideWriter{Writer: link.Writer, Dest: outbound.Target.Address, OriginalDest: outbound.OriginalTarget.Address}
|
||||
}
|
||||
if h.mux != nil {
|
||||
test := func(err error) {
|
||||
if err != nil {
|
||||
|
@ -175,7 +181,6 @@ func (h *Handler) Dispatch(ctx context.Context, link *transport.Link) {
|
|||
common.Interrupt(link.Writer)
|
||||
}
|
||||
}
|
||||
outbound := session.OutboundFromContext(ctx)
|
||||
if outbound.Target.Network == net.Network_UDP && outbound.Target.Port == 443 {
|
||||
switch h.udp443 {
|
||||
case "reject":
|
||||
|
@ -269,7 +274,12 @@ func (h *Handler) Dial(ctx context.Context, dest net.Destination) (stat.Connecti
|
|||
}
|
||||
|
||||
conn, err := internet.Dial(ctx, dest, h.streamSettings)
|
||||
return h.getStatCouterConnection(conn), err
|
||||
conn = h.getStatCouterConnection(conn)
|
||||
outbound := session.OutboundFromContext(ctx)
|
||||
if outbound != nil {
|
||||
outbound.Conn = conn
|
||||
}
|
||||
return conn, err
|
||||
}
|
||||
|
||||
func (h *Handler) getStatCouterConnection(conn stat.Connection) stat.Connection {
|
||||
|
|
|
@ -11,6 +11,9 @@ import (
|
|||
)
|
||||
|
||||
func (h *Handler) getUoTConnection(ctx context.Context, dest net.Destination) (stat.Connection, error) {
|
||||
if dest.Address == nil {
|
||||
return nil, newError("nil destination address")
|
||||
}
|
||||
if !dest.Address.Family().IsDomain() {
|
||||
return nil, os.ErrInvalid
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ import (
|
|||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/xtls/xray-core/common/mux"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/session"
|
||||
|
@ -12,6 +11,7 @@ import (
|
|||
"github.com/xtls/xray-core/features/routing"
|
||||
"github.com/xtls/xray-core/transport"
|
||||
"github.com/xtls/xray-core/transport/pipe"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// Bridge is a component in reverse proxy, that relays connections from Portal to local address.
|
||||
|
|
|
@ -5,7 +5,6 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/buf"
|
||||
"github.com/xtls/xray-core/common/mux"
|
||||
|
@ -15,6 +14,7 @@ import (
|
|||
"github.com/xtls/xray-core/features/outbound"
|
||||
"github.com/xtls/xray-core/transport"
|
||||
"github.com/xtls/xray-core/transport/pipe"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type Portal struct {
|
||||
|
|
|
@ -1,81 +1,49 @@
|
|||
package router
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"sort"
|
||||
"net/netip"
|
||||
"strconv"
|
||||
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"go4.org/netipx"
|
||||
)
|
||||
|
||||
type ipv6 struct {
|
||||
a uint64
|
||||
b uint64
|
||||
}
|
||||
|
||||
type GeoIPMatcher struct {
|
||||
countryCode string
|
||||
reverseMatch bool
|
||||
ip4 []uint32
|
||||
prefix4 []uint8
|
||||
ip6 []ipv6
|
||||
prefix6 []uint8
|
||||
}
|
||||
|
||||
func normalize4(ip uint32, prefix uint8) uint32 {
|
||||
return (ip >> (32 - prefix)) << (32 - prefix)
|
||||
}
|
||||
|
||||
func normalize6(ip ipv6, prefix uint8) ipv6 {
|
||||
if prefix <= 64 {
|
||||
ip.a = (ip.a >> (64 - prefix)) << (64 - prefix)
|
||||
ip.b = 0
|
||||
} else {
|
||||
ip.b = (ip.b >> (128 - prefix)) << (128 - prefix)
|
||||
}
|
||||
return ip
|
||||
ip4 *netipx.IPSet
|
||||
ip6 *netipx.IPSet
|
||||
}
|
||||
|
||||
func (m *GeoIPMatcher) Init(cidrs []*CIDR) error {
|
||||
ip4Count := 0
|
||||
ip6Count := 0
|
||||
var builder4, builder6 netipx.IPSetBuilder
|
||||
|
||||
for _, cidr := range cidrs {
|
||||
ip := cidr.Ip
|
||||
ip := net.IP(cidr.GetIp())
|
||||
ipPrefixString := ip.String() + "/" + strconv.Itoa(int(cidr.GetPrefix()))
|
||||
ipPrefix, err := netip.ParsePrefix(ipPrefixString)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch len(ip) {
|
||||
case 4:
|
||||
ip4Count++
|
||||
case 16:
|
||||
ip6Count++
|
||||
default:
|
||||
return newError("unexpect ip length: ", len(ip))
|
||||
case net.IPv4len:
|
||||
builder4.AddPrefix(ipPrefix)
|
||||
case net.IPv6len:
|
||||
builder6.AddPrefix(ipPrefix)
|
||||
}
|
||||
}
|
||||
|
||||
cidrList := CIDRList(cidrs)
|
||||
sort.Sort(&cidrList)
|
||||
|
||||
m.ip4 = make([]uint32, 0, ip4Count)
|
||||
m.prefix4 = make([]uint8, 0, ip4Count)
|
||||
m.ip6 = make([]ipv6, 0, ip6Count)
|
||||
m.prefix6 = make([]uint8, 0, ip6Count)
|
||||
|
||||
for _, cidr := range cidrList {
|
||||
ip := cidr.Ip
|
||||
prefix := uint8(cidr.Prefix)
|
||||
switch len(ip) {
|
||||
case 4:
|
||||
m.ip4 = append(m.ip4, normalize4(binary.BigEndian.Uint32(ip), prefix))
|
||||
m.prefix4 = append(m.prefix4, prefix)
|
||||
case 16:
|
||||
ip6 := ipv6{
|
||||
a: binary.BigEndian.Uint64(ip[0:8]),
|
||||
b: binary.BigEndian.Uint64(ip[8:16]),
|
||||
if ip4, err := builder4.IPSet(); err != nil {
|
||||
return err
|
||||
} else {
|
||||
m.ip4 = ip4
|
||||
}
|
||||
ip6 = normalize6(ip6, prefix)
|
||||
|
||||
m.ip6 = append(m.ip6, ip6)
|
||||
m.prefix6 = append(m.prefix6, prefix)
|
||||
}
|
||||
if ip6, err := builder6.IPSet(); err != nil {
|
||||
return err
|
||||
} else {
|
||||
m.ip6 = ip6
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -85,91 +53,37 @@ func (m *GeoIPMatcher) SetReverseMatch(isReverseMatch bool) {
|
|||
m.reverseMatch = isReverseMatch
|
||||
}
|
||||
|
||||
func (m *GeoIPMatcher) match4(ip uint32) bool {
|
||||
if len(m.ip4) == 0 {
|
||||
func (m *GeoIPMatcher) match4(ip net.IP) bool {
|
||||
nip, ok := netipx.FromStdIP(ip)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
if ip < m.ip4[0] {
|
||||
return false
|
||||
}
|
||||
|
||||
size := uint32(len(m.ip4))
|
||||
l := uint32(0)
|
||||
r := size
|
||||
for l < r {
|
||||
x := ((l + r) >> 1)
|
||||
if ip < m.ip4[x] {
|
||||
r = x
|
||||
continue
|
||||
}
|
||||
|
||||
nip := normalize4(ip, m.prefix4[x])
|
||||
if nip == m.ip4[x] {
|
||||
return true
|
||||
}
|
||||
|
||||
l = x + 1
|
||||
}
|
||||
|
||||
return l > 0 && normalize4(ip, m.prefix4[l-1]) == m.ip4[l-1]
|
||||
return m.ip4.Contains(nip)
|
||||
}
|
||||
|
||||
func less6(a ipv6, b ipv6) bool {
|
||||
return a.a < b.a || (a.a == b.a && a.b < b.b)
|
||||
}
|
||||
|
||||
func (m *GeoIPMatcher) match6(ip ipv6) bool {
|
||||
if len(m.ip6) == 0 {
|
||||
func (m *GeoIPMatcher) match6(ip net.IP) bool {
|
||||
nip, ok := netipx.FromStdIP(ip)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
if less6(ip, m.ip6[0]) {
|
||||
return false
|
||||
}
|
||||
|
||||
size := uint32(len(m.ip6))
|
||||
l := uint32(0)
|
||||
r := size
|
||||
for l < r {
|
||||
x := (l + r) / 2
|
||||
if less6(ip, m.ip6[x]) {
|
||||
r = x
|
||||
continue
|
||||
}
|
||||
|
||||
if normalize6(ip, m.prefix6[x]) == m.ip6[x] {
|
||||
return true
|
||||
}
|
||||
|
||||
l = x + 1
|
||||
}
|
||||
|
||||
return l > 0 && normalize6(ip, m.prefix6[l-1]) == m.ip6[l-1]
|
||||
return m.ip6.Contains(nip)
|
||||
}
|
||||
|
||||
// Match returns true if the given ip is included by the GeoIP.
|
||||
func (m *GeoIPMatcher) Match(ip net.IP) bool {
|
||||
isMatched := false
|
||||
switch len(ip) {
|
||||
case 4:
|
||||
case net.IPv4len:
|
||||
isMatched = m.match4(ip)
|
||||
case net.IPv6len:
|
||||
isMatched = m.match6(ip)
|
||||
}
|
||||
if m.reverseMatch {
|
||||
return !m.match4(binary.BigEndian.Uint32(ip))
|
||||
}
|
||||
return m.match4(binary.BigEndian.Uint32(ip))
|
||||
case 16:
|
||||
if m.reverseMatch {
|
||||
return !m.match6(ipv6{
|
||||
a: binary.BigEndian.Uint64(ip[0:8]),
|
||||
b: binary.BigEndian.Uint64(ip[8:16]),
|
||||
})
|
||||
}
|
||||
return m.match6(ipv6{
|
||||
a: binary.BigEndian.Uint64(ip[0:8]),
|
||||
b: binary.BigEndian.Uint64(ip[8:16]),
|
||||
})
|
||||
default:
|
||||
return false
|
||||
return !isMatched
|
||||
}
|
||||
return isMatched
|
||||
}
|
||||
|
||||
// GeoIPMatcherContainer is a container for GeoIPMatchers. It keeps unique copies of GeoIPMatcher by country code.
|
||||
|
|
|
@ -5,12 +5,12 @@ import (
|
|||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/xtls/xray-core/app/router"
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/platform"
|
||||
"github.com/xtls/xray-core/common/platform/filesystem"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -53,7 +53,7 @@ func TestGeoIPMatcherContainer(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestGeoIPMatcher(t *testing.T) {
|
||||
cidrList := router.CIDRList{
|
||||
cidrList := []*router.CIDR{
|
||||
{Ip: []byte{0, 0, 0, 0}, Prefix: 8},
|
||||
{Ip: []byte{10, 0, 0, 0}, Prefix: 8},
|
||||
{Ip: []byte{100, 64, 0, 0}, Prefix: 10},
|
||||
|
@ -124,8 +124,40 @@ func TestGeoIPMatcher(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestGeoIPMatcherRegression(t *testing.T) {
|
||||
cidrList := []*router.CIDR{
|
||||
{Ip: []byte{98, 108, 20, 0}, Prefix: 22},
|
||||
{Ip: []byte{98, 108, 20, 0}, Prefix: 23},
|
||||
}
|
||||
|
||||
matcher := &router.GeoIPMatcher{}
|
||||
common.Must(matcher.Init(cidrList))
|
||||
|
||||
testCases := []struct {
|
||||
Input string
|
||||
Output bool
|
||||
}{
|
||||
{
|
||||
Input: "98.108.22.11",
|
||||
Output: true,
|
||||
},
|
||||
{
|
||||
Input: "98.108.25.0",
|
||||
Output: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
ip := net.ParseAddress(testCase.Input).IP()
|
||||
actual := matcher.Match(ip)
|
||||
if actual != testCase.Output {
|
||||
t.Error("expect input", testCase.Input, "to be", testCase.Output, ", but actually", actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGeoIPReverseMatcher(t *testing.T) {
|
||||
cidrList := router.CIDRList{
|
||||
cidrList := []*router.CIDR{
|
||||
{Ip: []byte{8, 8, 8, 8}, Prefix: 32},
|
||||
{Ip: []byte{91, 108, 4, 0}, Prefix: 16},
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ import (
|
|||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
. "github.com/xtls/xray-core/app/router"
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
|
@ -18,6 +17,7 @@ import (
|
|||
"github.com/xtls/xray-core/common/session"
|
||||
"github.com/xtls/xray-core/features/routing"
|
||||
routing_session "github.com/xtls/xray-core/features/routing/session"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
|
|
@ -9,45 +9,6 @@ import (
|
|||
"github.com/xtls/xray-core/features/routing"
|
||||
)
|
||||
|
||||
// CIDRList is an alias of []*CIDR to provide sort.Interface.
|
||||
type CIDRList []*CIDR
|
||||
|
||||
// Len implements sort.Interface.
|
||||
func (l *CIDRList) Len() int {
|
||||
return len(*l)
|
||||
}
|
||||
|
||||
// Less implements sort.Interface.
|
||||
func (l *CIDRList) Less(i int, j int) bool {
|
||||
ci := (*l)[i]
|
||||
cj := (*l)[j]
|
||||
|
||||
if len(ci.Ip) < len(cj.Ip) {
|
||||
return true
|
||||
}
|
||||
|
||||
if len(ci.Ip) > len(cj.Ip) {
|
||||
return false
|
||||
}
|
||||
|
||||
for k := 0; k < len(ci.Ip); k++ {
|
||||
if ci.Ip[k] < cj.Ip[k] {
|
||||
return true
|
||||
}
|
||||
|
||||
if ci.Ip[k] > cj.Ip[k] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return ci.Prefix < cj.Prefix
|
||||
}
|
||||
|
||||
// Swap implements sort.Interface.
|
||||
func (l *CIDRList) Swap(i int, j int) {
|
||||
(*l)[i], (*l)[j] = (*l)[j], (*l)[i]
|
||||
}
|
||||
|
||||
type Rule struct {
|
||||
Tag string
|
||||
Balancer *Balancer
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/signal"
|
||||
"github.com/xtls/xray-core/features/stats"
|
||||
)
|
||||
|
||||
type dataHandler func(MultiBuffer)
|
||||
|
@ -40,6 +41,17 @@ func CountSize(sc *SizeCounter) CopyOption {
|
|||
}
|
||||
}
|
||||
|
||||
// AddToStatCounter a CopyOption add to stat counter
|
||||
func AddToStatCounter(sc stats.Counter) CopyOption {
|
||||
return func(handler *copyHandler) {
|
||||
handler.onData = append(handler.onData, func(b MultiBuffer) {
|
||||
if sc != nil {
|
||||
sc.Add(int64(b.Len()))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type readError struct {
|
||||
error
|
||||
}
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
package buf
|
||||
|
||||
import (
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
)
|
||||
|
||||
type EndpointOverrideReader struct {
|
||||
Reader
|
||||
Dest net.Address
|
||||
OriginalDest net.Address
|
||||
}
|
||||
|
||||
func (r *EndpointOverrideReader) ReadMultiBuffer() (MultiBuffer, error) {
|
||||
mb, err := r.Reader.ReadMultiBuffer()
|
||||
if err == nil {
|
||||
for _, b := range mb {
|
||||
if b.UDP != nil && b.UDP.Address == r.OriginalDest {
|
||||
b.UDP.Address = r.Dest
|
||||
}
|
||||
}
|
||||
}
|
||||
return mb, err
|
||||
}
|
||||
|
||||
type EndpointOverrideWriter struct {
|
||||
Writer
|
||||
Dest net.Address
|
||||
OriginalDest net.Address
|
||||
}
|
||||
|
||||
func (w *EndpointOverrideWriter) WriteMultiBuffer(mb MultiBuffer) error {
|
||||
for _, b := range mb {
|
||||
if b.UDP != nil && b.UDP.Address == w.Dest {
|
||||
b.UDP.Address = w.OriginalDest
|
||||
}
|
||||
}
|
||||
return w.Writer.WriteMultiBuffer(mb)
|
||||
}
|
|
@ -1,10 +1,9 @@
|
|||
package serial
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/reflect/protoreflect"
|
||||
"google.golang.org/protobuf/reflect/protoregistry"
|
||||
)
|
||||
|
||||
// ToTypedMessage converts a proto Message into TypedMessage.
|
||||
|
@ -21,16 +20,17 @@ func ToTypedMessage(message proto.Message) *TypedMessage {
|
|||
|
||||
// GetMessageType returns the name of this proto Message.
|
||||
func GetMessageType(message proto.Message) string {
|
||||
return proto.MessageName(message)
|
||||
return string(message.ProtoReflect().Descriptor().FullName())
|
||||
}
|
||||
|
||||
// GetInstance creates a new instance of the message with messageType.
|
||||
func GetInstance(messageType string) (interface{}, error) {
|
||||
mType := proto.MessageType(messageType)
|
||||
if mType == nil || mType.Elem() == nil {
|
||||
return nil, errors.New("Serial: Unknown type: " + messageType)
|
||||
messageTypeDescriptor := protoreflect.FullName(messageType)
|
||||
mType, err := protoregistry.GlobalTypes.FindMessageByName(messageTypeDescriptor)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return reflect.New(mType.Elem()).Interface(), nil
|
||||
return mType.New().Interface(), nil
|
||||
}
|
||||
|
||||
// GetInstance converts current TypedMessage into a proto Message.
|
||||
|
|
|
@ -50,15 +50,30 @@ type Inbound struct {
|
|||
Conn net.Conn
|
||||
// Timer of the inbound buf copier. May be nil.
|
||||
Timer *signal.ActivityTimer
|
||||
// CanSpliceCopy is a property for this connection, set by both inbound and outbound
|
||||
// 1 = can, 2 = after processing protocol info should be able to, 3 = cannot
|
||||
CanSpliceCopy int
|
||||
}
|
||||
|
||||
func(i *Inbound) SetCanSpliceCopy(canSpliceCopy int) int {
|
||||
if canSpliceCopy > i.CanSpliceCopy {
|
||||
i.CanSpliceCopy = canSpliceCopy
|
||||
}
|
||||
return i.CanSpliceCopy
|
||||
}
|
||||
|
||||
// Outbound is the metadata of an outbound connection.
|
||||
type Outbound struct {
|
||||
// Target address of the outbound connection.
|
||||
OriginalTarget net.Destination
|
||||
Target net.Destination
|
||||
RouteTarget net.Destination
|
||||
// Gateway address
|
||||
Gateway net.Address
|
||||
// Name of the outbound proxy that handles the connection.
|
||||
Name string
|
||||
// Conn is actually internet.Connection. May be nil. It is currently nil for outbound with proxySettings
|
||||
Conn net.Conn
|
||||
}
|
||||
|
||||
// SniffingRequest controls the behavior of content sniffing.
|
||||
|
|
|
@ -18,19 +18,25 @@ func ToNetwork(network string) net.Network {
|
|||
}
|
||||
|
||||
func ToDestination(socksaddr M.Socksaddr, network net.Network) net.Destination {
|
||||
// IsFqdn() implicitly checks if the domain name is valid
|
||||
if socksaddr.IsFqdn() {
|
||||
return net.Destination{
|
||||
Network: network,
|
||||
Address: net.DomainAddress(socksaddr.Fqdn),
|
||||
Port: net.Port(socksaddr.Port),
|
||||
}
|
||||
} else {
|
||||
}
|
||||
|
||||
// IsIP() implicitly checks if the IP address is valid
|
||||
if socksaddr.IsIP() {
|
||||
return net.Destination{
|
||||
Network: network,
|
||||
Address: net.IPAddress(socksaddr.Addr.AsSlice()),
|
||||
Port: net.Port(socksaddr.Port),
|
||||
}
|
||||
}
|
||||
|
||||
return net.Destination{}
|
||||
}
|
||||
|
||||
func ToSocksaddr(destination net.Destination) M.Socksaddr {
|
||||
|
|
|
@ -225,7 +225,11 @@ func (ac *ACAutomaton) Match(s string) bool {
|
|||
// 2. the match string is through a fail edge. NOT FULL MATCH
|
||||
// 2.1 Through a fail edge, but there exists a valid node. SUBSTR
|
||||
for i := len(s) - 1; i >= 0; i-- {
|
||||
idx := char2Index[s[i]]
|
||||
chr := int(s[i])
|
||||
if chr >= len(char2Index) {
|
||||
return false
|
||||
}
|
||||
idx := char2Index[chr]
|
||||
fullMatch = fullMatch && ac.trie[node][idx].edgeType
|
||||
node = ac.trie[node][idx].nextNode
|
||||
switch ac.exists[node].matchType {
|
||||
|
|
|
@ -217,6 +217,10 @@ func TestACAutomaton(t *testing.T) {
|
|||
pattern: "vvgoogle.com",
|
||||
res: true,
|
||||
},
|
||||
{
|
||||
pattern: "½",
|
||||
res: false,
|
||||
},
|
||||
}
|
||||
for _, test := range cases2Output {
|
||||
if m := ac.Match(test.pattern); m != test.res {
|
||||
|
@ -224,7 +228,6 @@ func TestACAutomaton(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
cases3Input := []struct {
|
||||
pattern string
|
||||
|
|
|
@ -4,11 +4,11 @@ import (
|
|||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/buf"
|
||||
"github.com/xtls/xray-core/common/cmdarg"
|
||||
"github.com/xtls/xray-core/main/confloader"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// ConfigFormat is a configurable format of Xray config file.
|
||||
|
@ -57,7 +57,7 @@ func GetFormatByExtension(ext string) string {
|
|||
return "yaml"
|
||||
case "toml":
|
||||
return "toml"
|
||||
case "json":
|
||||
case "json", "jsonc":
|
||||
return "json"
|
||||
default:
|
||||
return ""
|
||||
|
|
|
@ -21,7 +21,7 @@ import (
|
|||
var (
|
||||
Version_x byte = 1
|
||||
Version_y byte = 8
|
||||
Version_z byte = 3
|
||||
Version_z byte = 4
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
@ -7,7 +7,6 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/xtls/xray-core/app/dispatcher"
|
||||
"github.com/xtls/xray-core/app/proxyman"
|
||||
|
@ -18,6 +17,7 @@ import (
|
|||
"github.com/xtls/xray-core/proxy/freedom"
|
||||
"github.com/xtls/xray-core/testing/servers/tcp"
|
||||
"github.com/xtls/xray-core/testing/servers/udp"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
func xor(b []byte) []byte {
|
||||
|
|
|
@ -3,7 +3,6 @@ package core_test
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/xtls/xray-core/app/dispatcher"
|
||||
"github.com/xtls/xray-core/app/proxyman"
|
||||
"github.com/xtls/xray-core/common"
|
||||
|
@ -19,6 +18,7 @@ import (
|
|||
"github.com/xtls/xray-core/proxy/vmess"
|
||||
"github.com/xtls/xray-core/proxy/vmess/outbound"
|
||||
"github.com/xtls/xray-core/testing/servers/tcp"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
func TestXrayDependency(t *testing.T) {
|
||||
|
|
|
@ -3,8 +3,8 @@ package extension
|
|||
import (
|
||||
"context"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/xtls/xray-core/features"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type Observatory interface {
|
||||
|
|
50
go.mod
50
go.mod
|
@ -1,59 +1,61 @@
|
|||
module github.com/xtls/xray-core
|
||||
|
||||
go 1.20
|
||||
go 1.21
|
||||
|
||||
require (
|
||||
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344
|
||||
github.com/golang/mock v1.6.0
|
||||
github.com/golang/protobuf v1.5.3
|
||||
github.com/google/go-cmp v0.5.9
|
||||
github.com/gorilla/websocket v1.5.0
|
||||
github.com/miekg/dns v1.1.55
|
||||
github.com/miekg/dns v1.1.56
|
||||
github.com/pelletier/go-toml v1.9.5
|
||||
github.com/pires/go-proxyproto v0.7.0
|
||||
github.com/quic-go/quic-go v0.36.0
|
||||
github.com/refraction-networking/utls v1.3.2
|
||||
github.com/sagernet/sing v0.2.7
|
||||
github.com/sagernet/sing-shadowsocks v0.2.2
|
||||
github.com/quic-go/quic-go v0.39.0
|
||||
github.com/refraction-networking/utls v1.5.3
|
||||
github.com/sagernet/sing v0.2.12
|
||||
github.com/sagernet/sing-shadowsocks v0.2.5
|
||||
github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c
|
||||
github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb
|
||||
github.com/stretchr/testify v1.8.4
|
||||
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e
|
||||
github.com/xtls/reality v0.0.0-20230613075828-e07c3b04b983
|
||||
golang.org/x/crypto v0.10.0
|
||||
golang.org/x/net v0.11.0
|
||||
github.com/xtls/reality v0.0.0-20230828171259-e426190d57f6
|
||||
go4.org/netipx v0.0.0-20230824141953-6213f710f925
|
||||
golang.org/x/crypto v0.13.0
|
||||
golang.org/x/net v0.15.0
|
||||
golang.org/x/sync v0.3.0
|
||||
golang.org/x/sys v0.9.0
|
||||
google.golang.org/grpc v1.56.1
|
||||
golang.org/x/sys v0.12.0
|
||||
google.golang.org/grpc v1.58.2
|
||||
google.golang.org/protobuf v1.31.0
|
||||
gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c
|
||||
gvisor.dev/gvisor v0.0.0-20230822212503-5bf4e5f98744
|
||||
h12.io/socks v1.0.3
|
||||
lukechampine.com/blake3 v1.2.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/andybalholm/brotli v1.0.5 // indirect
|
||||
github.com/cloudflare/circl v1.3.3 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 // indirect
|
||||
github.com/francoispqt/gojay v1.2.13 // indirect
|
||||
github.com/gaukas/godicttls v0.0.3 // indirect
|
||||
github.com/gaukas/godicttls v0.0.4 // indirect
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/google/btree v1.1.2 // indirect
|
||||
github.com/google/pprof v0.0.0-20230602150820-91b7bce49751 // indirect
|
||||
github.com/klauspost/compress v1.16.6 // indirect
|
||||
github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98 // indirect
|
||||
github.com/klauspost/compress v1.17.0 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.11.0 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.12.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/quic-go/qtls-go1-19 v0.3.2 // indirect
|
||||
github.com/quic-go/qtls-go1-20 v0.2.2 // indirect
|
||||
github.com/quic-go/qtls-go1-20 v0.3.4 // indirect
|
||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
|
||||
go.uber.org/atomic v1.11.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect
|
||||
golang.org/x/mod v0.11.0 // indirect
|
||||
golang.org/x/text v0.10.0 // indirect
|
||||
go.uber.org/mock v0.3.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
|
||||
golang.org/x/mod v0.12.0 // indirect
|
||||
golang.org/x/text v0.13.0 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
golang.org/x/tools v0.10.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc // indirect
|
||||
golang.org/x/tools v0.13.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
|
97
go.sum
97
go.sum
|
@ -15,6 +15,8 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24
|
|||
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
|
||||
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs=
|
||||
github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
|
||||
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
|
@ -27,14 +29,15 @@ github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI
|
|||
github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk=
|
||||
github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/gaukas/godicttls v0.0.3 h1:YNDIf0d9adcxOijiLrEzpfZGAkNwLRzPaG6OjU7EITk=
|
||||
github.com/gaukas/godicttls v0.0.3/go.mod h1:l6EenT4TLWgTdwslVb4sEMOCf7Bv0JAK67deKr9/NCI=
|
||||
github.com/gaukas/godicttls v0.0.4 h1:NlRaXb3J6hAnTmWdsEKb9bcSBD6BvcIjdGdeb0zfXbk=
|
||||
github.com/gaukas/godicttls v0.0.4/go.mod h1:l6EenT4TLWgTdwslVb4sEMOCf7Bv0JAK67deKr9/NCI=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
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/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
|
||||
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
|
@ -60,8 +63,8 @@ github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+u
|
|||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20230602150820-91b7bce49751 h1:hR7/MlvK23p6+lIw9SN1TigNLn9ZnF3W4SYRKq2gAHs=
|
||||
github.com/google/pprof v0.0.0-20230602150820-91b7bce49751/go.mod h1:Jh3hGz2jkYak8qXPD19ryItVnUgpgeqzdkY/D0EaeuA=
|
||||
github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98 h1:pUa4ghanp6q4IJHwE9RwLgmVFfReJN+KbQ8ExNEUUoQ=
|
||||
github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
|
||||
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
|
||||
github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
|
@ -75,8 +78,8 @@ github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0
|
|||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.16.6 h1:91SKEy4K37vkp255cJ8QesJhjyRO0hn9i9G0GoUwLsk=
|
||||
github.com/klauspost/compress v1.16.6/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||
github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM=
|
||||
github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||
github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg=
|
||||
github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
|
@ -89,15 +92,16 @@ github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm
|
|||
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
|
||||
github.com/miekg/dns v1.1.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo=
|
||||
github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY=
|
||||
github.com/miekg/dns v1.1.56 h1:5imZaSeoRNvpM9SzWNhEcP9QliKiz20/dA2QabIGVnE=
|
||||
github.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
|
||||
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
|
||||
github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU=
|
||||
github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM=
|
||||
github.com/onsi/gomega v1.27.8 h1:gegWiwZjBsf2DgiSbf5hpokZ98JVDMcWkUiigk6/KXc=
|
||||
github.com/onsi/ginkgo/v2 v2.12.1 h1:uHNEO1RP2SpuZApSkel9nEh1/Mu+hmQe7Q+Pepg5OYA=
|
||||
github.com/onsi/ginkgo/v2 v2.12.1/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o=
|
||||
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
|
||||
github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
|
||||
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
|
||||
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
|
||||
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||
|
@ -112,21 +116,19 @@ github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP
|
|||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/quic-go/qtls-go1-19 v0.3.2 h1:tFxjCFcTQzK+oMxG6Zcvp4Dq8dx4yD3dDiIiyc86Z5U=
|
||||
github.com/quic-go/qtls-go1-19 v0.3.2/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI=
|
||||
github.com/quic-go/qtls-go1-20 v0.2.2 h1:WLOPx6OY/hxtTxKV1Zrq20FtXtDEkeY00CGQm8GEa3E=
|
||||
github.com/quic-go/qtls-go1-20 v0.2.2/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM=
|
||||
github.com/quic-go/quic-go v0.36.0 h1:JIrO7p7Ug6hssFcARjWDiqS2RAKJHCiwPxBAA989rbI=
|
||||
github.com/quic-go/quic-go v0.36.0/go.mod h1:zPetvwDlILVxt15n3hr3Gf/I3mDf7LpLKPhR4Ez0AZQ=
|
||||
github.com/refraction-networking/utls v1.3.2 h1:o+AkWB57mkcoW36ET7uJ002CpBWHu0KPxi6vzxvPnv8=
|
||||
github.com/refraction-networking/utls v1.3.2/go.mod h1:fmoaOww2bxzzEpIKOebIsnBvjQpqP7L2vcm/9KUfm/E=
|
||||
github.com/quic-go/qtls-go1-20 v0.3.4 h1:MfFAPULvst4yoMgY9QmtpYmfij/em7O8UUi+bNVm7Cg=
|
||||
github.com/quic-go/qtls-go1-20 v0.3.4/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
|
||||
github.com/quic-go/quic-go v0.39.0 h1:AgP40iThFMY0bj8jGxROhw3S0FMGa8ryqsmi9tBH3So=
|
||||
github.com/quic-go/quic-go v0.39.0/go.mod h1:T09QsDQWjLiQ74ZmacDfqZmhY/NLnw5BC40MANNNZ1Q=
|
||||
github.com/refraction-networking/utls v1.5.3 h1:Ds5Ocg1+MC1ahNx5iBEcHe0jHeLaA/fLey61EENm7ro=
|
||||
github.com/refraction-networking/utls v1.5.3/go.mod h1:SPuDbBmgLGp8s+HLNc83FuavwZCFoMmExj+ltUHiHUw=
|
||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg=
|
||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3/go.mod h1:HgjTstvQsPGkxUsCd2KWxErBblirPizecHcpD3ffK+s=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/sagernet/sing v0.2.7 h1:cOy0FfPS8q7m0aJ51wS7LRQAGc9wF+fWhHtBDj99wy8=
|
||||
github.com/sagernet/sing v0.2.7/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.2 h1:ezSdVhrmIcwDXmCZF3bOJVMuVtTQWpda+1Op+Ie2TA4=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.2/go.mod h1:JIBWG6a7orB2HxBxYElViQFLUQxFVG7DuqIj8gD7uCQ=
|
||||
github.com/sagernet/sing v0.2.12 h1:wwdLm3c4qvU4hW8tNtadh60V5z2FGlDZSYYGRzHhD74=
|
||||
github.com/sagernet/sing v0.2.12/go.mod h1:GQ673iPfUnkbK/dIPkfd1Xh1MjOGo36gkl/mkiHY7Jg=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.5 h1:qxIttos4xu6ii7MTVJYA8EFQR7Q3KG6xMqmLJIFtBaY=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.5/go.mod h1:MGWGkcU2xW2G2mfArT9/QqpVLOGU+dBaahZCtPHdt7A=
|
||||
github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c h1:vK2wyt9aWYHHvNLWniwijBu/n4pySypiKRhN32u/JGo=
|
||||
github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c/go.mod h1:euOmN6O5kk9dQmgSS8Df4psAl3TCjxOz0NW60EWkSaI=
|
||||
github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb h1:XfLJSPIOUX+osiMraVgIrMR27uMXnRJWGm1+GL8/63U=
|
||||
|
@ -166,29 +168,33 @@ github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e h1:5QefA066A1tF
|
|||
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e/go.mod h1:5t19P9LBIrNamL6AcMQOncg/r10y3Pc01AbHeMhwlpU=
|
||||
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
|
||||
github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
|
||||
github.com/xtls/reality v0.0.0-20230613075828-e07c3b04b983 h1:AMyzgjkh54WocjQSlCnT1LhDc/BKiUqtNOv40AkpURs=
|
||||
github.com/xtls/reality v0.0.0-20230613075828-e07c3b04b983/go.mod h1:rkuAY1S9F8eI8gDiPDYvACE8e2uwkyg8qoOTuwWov7Y=
|
||||
github.com/xtls/reality v0.0.0-20230828171259-e426190d57f6 h1:T+YCYGfFdzyaKTDCdZn/hEiKvsw6yUfd+e4hze0rCUw=
|
||||
github.com/xtls/reality v0.0.0-20230828171259-e426190d57f6/go.mod h1:rkuAY1S9F8eI8gDiPDYvACE8e2uwkyg8qoOTuwWov7Y=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
|
||||
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
|
||||
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||
go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo=
|
||||
go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
|
||||
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
|
||||
go4.org/netipx v0.0.0-20230824141953-6213f710f925 h1:eeQDDVKFkx0g4Hyy8pHgmZaK0EqB4SD6rvKbUdN3ziQ=
|
||||
go4.org/netipx v0.0.0-20230824141953-6213f710f925/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
|
||||
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
|
||||
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM=
|
||||
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
|
||||
golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
|
||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc=
|
||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
|
||||
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU=
|
||||
golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
|
@ -200,8 +206,8 @@ golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn
|
|||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.11.0 h1:Gi2tvZIJyBtO9SDr1q9h5hEQCp/4L2RQ+ar0qjx2oNU=
|
||||
golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=
|
||||
golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8=
|
||||
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
|
@ -225,14 +231,14 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
|
||||
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58=
|
||||
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
||||
|
@ -244,8 +250,8 @@ golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGm
|
|||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.10.0 h1:tvDr/iQoUqNdohiYm0LmmKcBk+q86lb9EprIUFhHHGg=
|
||||
golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM=
|
||||
golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
|
||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||
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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
@ -262,20 +268,21 @@ google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoA
|
|||
google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg=
|
||||
google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc h1:XSJ8Vk1SWuNr8S18z1NZSziL0CPIXLCCMDOEFtHBOFc=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13 h1:N3bU/SQDCDyD6R528GJ/PwW9KjYcJA3dgyH+MovAkIM=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13/go.mod h1:KSqppvjFjtoCI+KGd4PELB0qLNxdJHRGqRI09mB6pQA=
|
||||
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
|
||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.56.1 h1:z0dNfjIl0VpaZ9iSVjA6daGatAYwPGstTjt5vkRMFkQ=
|
||||
google.golang.org/grpc v1.56.1/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s=
|
||||
google.golang.org/grpc v1.58.2 h1:SXUpjxeVF3FKrTYQI4f4KvbGD5u2xccdYdurwowix5I=
|
||||
google.golang.org/grpc v1.58.2/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
|
@ -286,8 +293,8 @@ gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C
|
|||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
|
||||
gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c h1:m5lcgWnL3OElQNVyp3qcncItJ2c0sQlSGjYK2+nJTA4=
|
||||
gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c/go.mod h1:TIvkJD0sxe8pIob3p6T8IzxXunlp6yfgktvTNp+DGNM=
|
||||
gvisor.dev/gvisor v0.0.0-20230822212503-5bf4e5f98744 h1:tE44CyJgxEGzoPtHs9GI7ddKdgEGCREQBP54AmaVM+I=
|
||||
gvisor.dev/gvisor v0.0.0-20230822212503-5bf4e5f98744/go.mod h1:lYEMhXbxgudVhALYsMQrBaUAjM3NMinh8mKL1CJv7rc=
|
||||
h12.io/socks v1.0.3 h1:Ka3qaQewws4j4/eDQnOdpr4wXsC//dXtWvftlIcCQUo=
|
||||
h12.io/socks v1.0.3/go.mod h1:AIhxy1jOId/XCz9BO+EIgNL2rQiPTBNnOfnVnQ+3Eck=
|
||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
|
|
@ -3,9 +3,9 @@ package conf
|
|||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/xtls/xray-core/common/serial"
|
||||
"github.com/xtls/xray-core/proxy/blackhole"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type NoneResponse struct{}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package conf
|
||||
|
||||
import "github.com/golang/protobuf/proto"
|
||||
import "google.golang.org/protobuf/proto"
|
||||
|
||||
type Buildable interface {
|
||||
Build() (proto.Message, error)
|
||||
|
|
|
@ -17,6 +17,7 @@ type NameServerConfig struct {
|
|||
SkipFallback bool
|
||||
Domains []string
|
||||
ExpectIPs StringList
|
||||
QueryStrategy string
|
||||
}
|
||||
|
||||
func (c *NameServerConfig) UnmarshalJSON(data []byte) error {
|
||||
|
@ -33,6 +34,7 @@ func (c *NameServerConfig) UnmarshalJSON(data []byte) error {
|
|||
SkipFallback bool `json:"skipFallback"`
|
||||
Domains []string `json:"domains"`
|
||||
ExpectIPs StringList `json:"expectIps"`
|
||||
QueryStrategy string `json:"queryStrategy"`
|
||||
}
|
||||
if err := json.Unmarshal(data, &advanced); err == nil {
|
||||
c.Address = advanced.Address
|
||||
|
@ -41,6 +43,7 @@ func (c *NameServerConfig) UnmarshalJSON(data []byte) error {
|
|||
c.SkipFallback = advanced.SkipFallback
|
||||
c.Domains = advanced.Domains
|
||||
c.ExpectIPs = advanced.ExpectIPs
|
||||
c.QueryStrategy = advanced.QueryStrategy
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -112,6 +115,7 @@ func (c *NameServerConfig) Build() (*dns.NameServer, error) {
|
|||
PrioritizedDomain: domains,
|
||||
Geoip: geoipList,
|
||||
OriginalRules: originalRules,
|
||||
QueryStrategy: resolveQueryStrategy(c.QueryStrategy),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -311,6 +315,7 @@ func (c *DNSConfig) Build() (*dns.Config, error) {
|
|||
DisableCache: c.DisableCache,
|
||||
DisableFallback: c.DisableFallback,
|
||||
DisableFallbackIfMatch: c.DisableFallbackIfMatch,
|
||||
QueryStrategy: resolveQueryStrategy(c.QueryStrategy),
|
||||
}
|
||||
|
||||
if c.ClientIP != nil {
|
||||
|
@ -320,16 +325,6 @@ func (c *DNSConfig) Build() (*dns.Config, error) {
|
|||
config.ClientIp = []byte(c.ClientIP.IP())
|
||||
}
|
||||
|
||||
config.QueryStrategy = dns.QueryStrategy_USE_IP
|
||||
switch strings.ToLower(c.QueryStrategy) {
|
||||
case "useip", "use_ip", "use-ip":
|
||||
config.QueryStrategy = dns.QueryStrategy_USE_IP
|
||||
case "useip4", "useipv4", "use_ip4", "use_ipv4", "use_ip_v4", "use-ip4", "use-ipv4", "use-ip-v4":
|
||||
config.QueryStrategy = dns.QueryStrategy_USE_IP4
|
||||
case "useip6", "useipv6", "use_ip6", "use_ipv6", "use_ip_v6", "use-ip6", "use-ipv6", "use-ip-v6":
|
||||
config.QueryStrategy = dns.QueryStrategy_USE_IP6
|
||||
}
|
||||
|
||||
for _, server := range c.Servers {
|
||||
ns, err := server.Build()
|
||||
if err != nil {
|
||||
|
@ -348,3 +343,16 @@ func (c *DNSConfig) Build() (*dns.Config, error) {
|
|||
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func resolveQueryStrategy(queryStrategy string) dns.QueryStrategy {
|
||||
switch strings.ToLower(queryStrategy) {
|
||||
case "useip", "use_ip", "use-ip":
|
||||
return dns.QueryStrategy_USE_IP
|
||||
case "useip4", "useipv4", "use_ip4", "use_ipv4", "use_ip_v4", "use-ip4", "use-ipv4", "use-ip-v4":
|
||||
return dns.QueryStrategy_USE_IP4
|
||||
case "useip6", "useipv6", "use_ip6", "use_ipv6", "use_ip_v6", "use-ip6", "use-ipv6", "use-ip-v6":
|
||||
return dns.QueryStrategy_USE_IP6
|
||||
default:
|
||||
return dns.QueryStrategy_USE_IP
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package conf
|
||||
|
||||
import (
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/proxy/dns"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type DNSOutboundConfig struct {
|
||||
|
|
|
@ -6,7 +6,6 @@ import (
|
|||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/xtls/xray-core/app/dns"
|
||||
"github.com/xtls/xray-core/app/router"
|
||||
"github.com/xtls/xray-core/common"
|
||||
|
@ -14,6 +13,7 @@ import (
|
|||
"github.com/xtls/xray-core/common/platform"
|
||||
"github.com/xtls/xray-core/common/platform/filesystem"
|
||||
. "github.com/xtls/xray-core/infra/conf"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package conf
|
||||
|
||||
import (
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/xtls/xray-core/proxy/dokodemo"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type DokodemoConfig struct {
|
||||
|
|
|
@ -5,10 +5,10 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
v2net "github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/protocol"
|
||||
"github.com/xtls/xray-core/proxy/freedom"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type FreedomConfig struct {
|
||||
|
@ -39,91 +39,89 @@ func (c *FreedomConfig) Build() (proto.Message, error) {
|
|||
}
|
||||
|
||||
if c.Fragment != nil {
|
||||
if len(c.Fragment.Interval) == 0 || len(c.Fragment.Length) == 0 {
|
||||
return nil, newError("Invalid interval or length")
|
||||
}
|
||||
intervalMinMax := strings.Split(c.Fragment.Interval, "-")
|
||||
var minInterval, maxInterval int64
|
||||
config.Fragment = new(freedom.Fragment)
|
||||
var err, err2 error
|
||||
if len(intervalMinMax) == 2 {
|
||||
minInterval, err = strconv.ParseInt(intervalMinMax[0], 10, 64)
|
||||
maxInterval, err2 = strconv.ParseInt(intervalMinMax[1], 10, 64)
|
||||
} else {
|
||||
minInterval, err = strconv.ParseInt(intervalMinMax[0], 10, 64)
|
||||
maxInterval = minInterval
|
||||
}
|
||||
if err != nil {
|
||||
return nil, newError("Invalid minimum interval: ", err).Base(err)
|
||||
}
|
||||
if err2 != nil {
|
||||
return nil, newError("Invalid maximum interval: ", err2).Base(err2)
|
||||
}
|
||||
|
||||
lengthMinMax := strings.Split(c.Fragment.Length, "-")
|
||||
var minLength, maxLength int64
|
||||
if len(lengthMinMax) == 2 {
|
||||
minLength, err = strconv.ParseInt(lengthMinMax[0], 10, 64)
|
||||
maxLength, err2 = strconv.ParseInt(lengthMinMax[1], 10, 64)
|
||||
|
||||
} else {
|
||||
minLength, err = strconv.ParseInt(lengthMinMax[0], 10, 64)
|
||||
maxLength = minLength
|
||||
}
|
||||
if err != nil {
|
||||
return nil, newError("Invalid minimum length: ", err).Base(err)
|
||||
}
|
||||
if err2 != nil {
|
||||
return nil, newError("Invalid maximum length: ", err2).Base(err2)
|
||||
}
|
||||
|
||||
if minInterval > maxInterval {
|
||||
minInterval, maxInterval = maxInterval, minInterval
|
||||
}
|
||||
if minLength > maxLength {
|
||||
minLength, maxLength = maxLength, minLength
|
||||
}
|
||||
|
||||
config.Fragment = &freedom.Fragment{
|
||||
MinInterval: int32(minInterval),
|
||||
MaxInterval: int32(maxInterval),
|
||||
MinLength: int32(minLength),
|
||||
MaxLength: int32(maxLength),
|
||||
}
|
||||
|
||||
switch strings.ToLower(c.Fragment.Packets) {
|
||||
case "tlshello":
|
||||
// TLS Hello Fragmentation (into multiple handshake messages)
|
||||
config.Fragment.StartPacket = 0
|
||||
config.Fragment.EndPacket = 1
|
||||
config.Fragment.PacketsFrom = 0
|
||||
config.Fragment.PacketsTo = 1
|
||||
case "":
|
||||
// TCP Segmentation (all packets)
|
||||
config.Fragment.StartPacket = 0
|
||||
config.Fragment.EndPacket = 0
|
||||
config.Fragment.PacketsFrom = 0
|
||||
config.Fragment.PacketsTo = 0
|
||||
default:
|
||||
// TCP Segmentation (range)
|
||||
packetRange := strings.Split(c.Fragment.Packets, "-")
|
||||
var startPacket, endPacket int64
|
||||
if len(packetRange) == 2 {
|
||||
startPacket, err = strconv.ParseInt(packetRange[0], 10, 64)
|
||||
endPacket, err2 = strconv.ParseInt(packetRange[1], 10, 64)
|
||||
packetsFromTo := strings.Split(c.Fragment.Packets, "-")
|
||||
if len(packetsFromTo) == 2 {
|
||||
config.Fragment.PacketsFrom, err = strconv.ParseUint(packetsFromTo[0], 10, 64)
|
||||
config.Fragment.PacketsTo, err2 = strconv.ParseUint(packetsFromTo[1], 10, 64)
|
||||
} else {
|
||||
startPacket, err = strconv.ParseInt(packetRange[0], 10, 64)
|
||||
endPacket = startPacket
|
||||
config.Fragment.PacketsFrom, err = strconv.ParseUint(packetsFromTo[0], 10, 64)
|
||||
config.Fragment.PacketsTo = config.Fragment.PacketsFrom
|
||||
}
|
||||
if err != nil {
|
||||
return nil, newError("Invalid start packet: ", err).Base(err)
|
||||
return nil, newError("Invalid PacketsFrom").Base(err)
|
||||
}
|
||||
if err2 != nil {
|
||||
return nil, newError("Invalid end packet: ", err2).Base(err2)
|
||||
return nil, newError("Invalid PacketsTo").Base(err2)
|
||||
}
|
||||
if startPacket > endPacket {
|
||||
return nil, newError("Invalid packet range: ", c.Fragment.Packets)
|
||||
if config.Fragment.PacketsFrom > config.Fragment.PacketsTo {
|
||||
config.Fragment.PacketsFrom, config.Fragment.PacketsTo = config.Fragment.PacketsTo, config.Fragment.PacketsFrom
|
||||
}
|
||||
if startPacket < 1 {
|
||||
return nil, newError("Cannot start from packet 0")
|
||||
if config.Fragment.PacketsFrom == 0 {
|
||||
return nil, newError("PacketsFrom can't be 0")
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
if c.Fragment.Length == "" {
|
||||
return nil, newError("Length can't be empty")
|
||||
}
|
||||
lengthMinMax := strings.Split(c.Fragment.Length, "-")
|
||||
if len(lengthMinMax) == 2 {
|
||||
config.Fragment.LengthMin, err = strconv.ParseUint(lengthMinMax[0], 10, 64)
|
||||
config.Fragment.LengthMax, err2 = strconv.ParseUint(lengthMinMax[1], 10, 64)
|
||||
} else {
|
||||
config.Fragment.LengthMin, err = strconv.ParseUint(lengthMinMax[0], 10, 64)
|
||||
config.Fragment.LengthMax = config.Fragment.LengthMin
|
||||
}
|
||||
if err != nil {
|
||||
return nil, newError("Invalid LengthMin").Base(err)
|
||||
}
|
||||
if err2 != nil {
|
||||
return nil, newError("Invalid LengthMax").Base(err2)
|
||||
}
|
||||
if config.Fragment.LengthMin > config.Fragment.LengthMax {
|
||||
config.Fragment.LengthMin, config.Fragment.LengthMax = config.Fragment.LengthMax, config.Fragment.LengthMin
|
||||
}
|
||||
if config.Fragment.LengthMin == 0 {
|
||||
return nil, newError("LengthMin can't be 0")
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
if c.Fragment.Interval == "" {
|
||||
return nil, newError("Interval can't be empty")
|
||||
}
|
||||
intervalMinMax := strings.Split(c.Fragment.Interval, "-")
|
||||
if len(intervalMinMax) == 2 {
|
||||
config.Fragment.IntervalMin, err = strconv.ParseUint(intervalMinMax[0], 10, 64)
|
||||
config.Fragment.IntervalMax, err2 = strconv.ParseUint(intervalMinMax[1], 10, 64)
|
||||
} else {
|
||||
config.Fragment.IntervalMin, err = strconv.ParseUint(intervalMinMax[0], 10, 64)
|
||||
config.Fragment.IntervalMax = config.Fragment.IntervalMin
|
||||
}
|
||||
if err != nil {
|
||||
return nil, newError("Invalid IntervalMin").Base(err)
|
||||
}
|
||||
if err2 != nil {
|
||||
return nil, newError("Invalid IntervalMax").Base(err2)
|
||||
}
|
||||
if config.Fragment.IntervalMin > config.Fragment.IntervalMax {
|
||||
config.Fragment.IntervalMin, config.Fragment.IntervalMax = config.Fragment.IntervalMax, config.Fragment.IntervalMin
|
||||
}
|
||||
config.Fragment.StartPacket = int32(startPacket)
|
||||
config.Fragment.EndPacket = int32(endPacket)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,9 +4,9 @@ import (
|
|||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/xtls/xray-core/common"
|
||||
. "github.com/xtls/xray-core/infra/conf"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
func loadJSON(creator func() Buildable) func(string) (proto.Message, error) {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package conf
|
||||
|
||||
import (
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/xtls/xray-core/transport/internet/grpc"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type GRPCConfig struct {
|
||||
|
|
|
@ -3,10 +3,10 @@ package conf
|
|||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/xtls/xray-core/common/protocol"
|
||||
"github.com/xtls/xray-core/common/serial"
|
||||
"github.com/xtls/xray-core/proxy/http"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type HTTPAccount struct {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package conf
|
||||
|
||||
import (
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/xtls/xray-core/proxy/loopback"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type LoopbackConfig struct {
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package conf
|
||||
|
||||
import (
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/xtls/xray-core/app/observatory"
|
||||
"github.com/xtls/xray-core/infra/conf/cfgcommon/duration"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type ObservatoryConfig struct {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package conf
|
||||
|
||||
import (
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/xtls/xray-core/app/reverse"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type BridgeConfig struct {
|
||||
|
|
|
@ -6,10 +6,10 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/xtls/xray-core/app/router"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/platform/filesystem"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type RouterRulesConfig struct {
|
||||
|
@ -245,6 +245,23 @@ func loadSite(file, code string) ([]*router.Domain, error) {
|
|||
return SiteCache[index].Domain, nil
|
||||
}
|
||||
|
||||
func DecodeVarint(buf []byte) (x uint64, n int) {
|
||||
for shift := uint(0); shift < 64; shift += 7 {
|
||||
if n >= len(buf) {
|
||||
return 0, 0
|
||||
}
|
||||
b := uint64(buf[n])
|
||||
n++
|
||||
x |= (b & 0x7F) << shift
|
||||
if (b & 0x80) == 0 {
|
||||
return x, n
|
||||
}
|
||||
}
|
||||
|
||||
// The number is too large to represent in a 64-bit value.
|
||||
return 0, 0
|
||||
}
|
||||
|
||||
func find(data, code []byte) []byte {
|
||||
codeL := len(code)
|
||||
if codeL == 0 {
|
||||
|
@ -255,7 +272,7 @@ func find(data, code []byte) []byte {
|
|||
if dataL < 2 {
|
||||
return nil
|
||||
}
|
||||
x, y := proto.DecodeVarint(data[1:])
|
||||
x, y := DecodeVarint(data[1:])
|
||||
if x == 0 && y == 0 {
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -7,13 +7,13 @@ import (
|
|||
"testing"
|
||||
_ "unsafe"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/xtls/xray-core/app/router"
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/platform"
|
||||
"github.com/xtls/xray-core/common/platform/filesystem"
|
||||
. "github.com/xtls/xray-core/infra/conf"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
|
|
@ -3,13 +3,13 @@ package conf
|
|||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/sagernet/sing-shadowsocks/shadowaead_2022"
|
||||
C "github.com/sagernet/sing/common"
|
||||
"github.com/xtls/xray-core/common/protocol"
|
||||
"github.com/xtls/xray-core/common/serial"
|
||||
"github.com/xtls/xray-core/proxy/shadowsocks"
|
||||
"github.com/xtls/xray-core/proxy/shadowsocks_2022"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
func cipherFromString(c string) shadowsocks.CipherType {
|
||||
|
|
|
@ -4,10 +4,10 @@ import (
|
|||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/xtls/xray-core/common/protocol"
|
||||
"github.com/xtls/xray-core/common/serial"
|
||||
"github.com/xtls/xray-core/proxy/socks"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type SocksAccount struct {
|
||||
|
|
|
@ -3,7 +3,6 @@ package conf
|
|||
import (
|
||||
"sort"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/xtls/xray-core/transport/internet/headers/dns"
|
||||
"github.com/xtls/xray-core/transport/internet/headers/http"
|
||||
"github.com/xtls/xray-core/transport/internet/headers/noop"
|
||||
|
@ -12,6 +11,7 @@ import (
|
|||
"github.com/xtls/xray-core/transport/internet/headers/utp"
|
||||
"github.com/xtls/xray-core/transport/internet/headers/wechat"
|
||||
"github.com/xtls/xray-core/transport/internet/headers/wireguard"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type NoOpAuthenticator struct{}
|
||||
|
|
|
@ -11,7 +11,6 @@ import (
|
|||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/platform/filesystem"
|
||||
"github.com/xtls/xray-core/common/protocol"
|
||||
|
@ -26,6 +25,7 @@ import (
|
|||
"github.com/xtls/xray-core/transport/internet/tcp"
|
||||
"github.com/xtls/xray-core/transport/internet/tls"
|
||||
"github.com/xtls/xray-core/transport/internet/websocket"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -622,6 +622,7 @@ type SocketConfig struct {
|
|||
TCPUserTimeout int32 `json:"tcpUserTimeout"`
|
||||
V6only bool `json:"v6only"`
|
||||
Interface string `json:"interface"`
|
||||
TcpMptcp bool `json:"tcpMptcp"`
|
||||
}
|
||||
|
||||
// Build implements Buildable.
|
||||
|
@ -677,6 +678,7 @@ func (c *SocketConfig) Build() (*internet.SocketConfig, error) {
|
|||
TcpUserTimeout: c.TCPUserTimeout,
|
||||
V6Only: c.V6only,
|
||||
Interface: c.Interface,
|
||||
TcpMptcp: c.TcpMptcp,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@ import (
|
|||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/xtls/xray-core/common/protocol"
|
||||
"github.com/xtls/xray-core/common/serial"
|
||||
. "github.com/xtls/xray-core/infra/conf"
|
||||
|
@ -18,6 +17,7 @@ import (
|
|||
"github.com/xtls/xray-core/transport/internet/quic"
|
||||
"github.com/xtls/xray-core/transport/internet/tcp"
|
||||
"github.com/xtls/xray-core/transport/internet/websocket"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
func TestSocketConfig(t *testing.T) {
|
||||
|
|
|
@ -6,11 +6,11 @@ import (
|
|||
"strconv"
|
||||
"syscall"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/protocol"
|
||||
"github.com/xtls/xray-core/common/serial"
|
||||
"github.com/xtls/xray-core/proxy/trojan"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// TrojanServerTarget is configuration of a single trojan server
|
||||
|
@ -30,13 +30,14 @@ type TrojanClientConfig struct {
|
|||
|
||||
// Build implements Buildable
|
||||
func (c *TrojanClientConfig) Build() (proto.Message, error) {
|
||||
config := new(trojan.ClientConfig)
|
||||
|
||||
if len(c.Servers) == 0 {
|
||||
return nil, newError("0 Trojan server configured.")
|
||||
}
|
||||
|
||||
serverSpecs := make([]*protocol.ServerEndpoint, len(c.Servers))
|
||||
config := &trojan.ClientConfig{
|
||||
Server: make([]*protocol.ServerEndpoint, len(c.Servers)),
|
||||
}
|
||||
|
||||
for idx, rec := range c.Servers {
|
||||
if rec.Address == nil {
|
||||
return nil, newError("Trojan server address is not set.")
|
||||
|
@ -47,34 +48,25 @@ func (c *TrojanClientConfig) Build() (proto.Message, error) {
|
|||
if rec.Password == "" {
|
||||
return nil, newError("Trojan password is not specified.")
|
||||
}
|
||||
account := &trojan.Account{
|
||||
Password: rec.Password,
|
||||
Flow: rec.Flow,
|
||||
if rec.Flow != "" {
|
||||
return nil, newError(`Trojan doesn't support "flow" anymore.`)
|
||||
}
|
||||
|
||||
switch account.Flow {
|
||||
case "":
|
||||
default:
|
||||
return nil, newError(`Trojan servers: "flow" doesn't support "` + account.Flow + `" in this version`)
|
||||
}
|
||||
|
||||
trojan := &protocol.ServerEndpoint{
|
||||
config.Server[idx] = &protocol.ServerEndpoint{
|
||||
Address: rec.Address.Build(),
|
||||
Port: uint32(rec.Port),
|
||||
User: []*protocol.User{
|
||||
{
|
||||
Level: uint32(rec.Level),
|
||||
Email: rec.Email,
|
||||
Account: serial.ToTypedMessage(account),
|
||||
Account: serial.ToTypedMessage(&trojan.Account{
|
||||
Password: rec.Password,
|
||||
}),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
serverSpecs[idx] = trojan
|
||||
}
|
||||
|
||||
config.Server = serverSpecs
|
||||
|
||||
return config, nil
|
||||
}
|
||||
|
||||
|
@ -105,25 +97,22 @@ type TrojanServerConfig struct {
|
|||
|
||||
// Build implements Buildable
|
||||
func (c *TrojanServerConfig) Build() (proto.Message, error) {
|
||||
config := new(trojan.ServerConfig)
|
||||
config.Users = make([]*protocol.User, len(c.Clients))
|
||||
config := &trojan.ServerConfig{
|
||||
Users: make([]*protocol.User, len(c.Clients)),
|
||||
}
|
||||
|
||||
for idx, rawUser := range c.Clients {
|
||||
user := new(protocol.User)
|
||||
account := &trojan.Account{
|
||||
if rawUser.Flow != "" {
|
||||
return nil, newError(`Trojan doesn't support "flow" anymore.`)
|
||||
}
|
||||
|
||||
config.Users[idx] = &protocol.User{
|
||||
Level: uint32(rawUser.Level),
|
||||
Email: rawUser.Email,
|
||||
Account: serial.ToTypedMessage(&trojan.Account{
|
||||
Password: rawUser.Password,
|
||||
Flow: rawUser.Flow,
|
||||
}),
|
||||
}
|
||||
|
||||
switch account.Flow {
|
||||
case "":
|
||||
default:
|
||||
return nil, newError(`Trojan clients: "flow" doesn't support "` + account.Flow + `" in this version`)
|
||||
}
|
||||
|
||||
user.Email = rawUser.Email
|
||||
user.Level = uint32(rawUser.Level)
|
||||
user.Account = serial.ToTypedMessage(account)
|
||||
config.Users[idx] = user
|
||||
}
|
||||
|
||||
if c.Fallback != nil {
|
||||
|
|
|
@ -6,7 +6,6 @@ import (
|
|||
"strconv"
|
||||
"syscall"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/protocol"
|
||||
"github.com/xtls/xray-core/common/serial"
|
||||
|
@ -14,6 +13,7 @@ import (
|
|||
"github.com/xtls/xray-core/proxy/vless"
|
||||
"github.com/xtls/xray-core/proxy/vless/inbound"
|
||||
"github.com/xtls/xray-core/proxy/vless/outbound"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type VLessInboundFallback struct {
|
||||
|
|
|
@ -4,13 +4,13 @@ import (
|
|||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/xtls/xray-core/common/protocol"
|
||||
"github.com/xtls/xray-core/common/serial"
|
||||
"github.com/xtls/xray-core/common/uuid"
|
||||
"github.com/xtls/xray-core/proxy/vmess"
|
||||
"github.com/xtls/xray-core/proxy/vmess/inbound"
|
||||
"github.com/xtls/xray-core/proxy/vmess/outbound"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type VMessAccount struct {
|
||||
|
|
|
@ -4,8 +4,8 @@ import (
|
|||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/xtls/xray-core/proxy/wireguard"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type WireGuardPeerConfig struct {
|
||||
|
|
|
@ -5,7 +5,6 @@ import (
|
|||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/xtls/xray-core/app/dispatcher"
|
||||
"github.com/xtls/xray-core/app/log"
|
||||
|
@ -27,6 +26,7 @@ import (
|
|||
"github.com/xtls/xray-core/transport/internet/http"
|
||||
"github.com/xtls/xray-core/transport/internet/tls"
|
||||
"github.com/xtls/xray-core/transport/internet/websocket"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
func TestXrayConfig(t *testing.T) {
|
||||
|
|
|
@ -113,13 +113,13 @@ func dirExists(file string) bool {
|
|||
func getRegepxByFormat() string {
|
||||
switch strings.ToLower(*format) {
|
||||
case "json":
|
||||
return `^.+\.json$`
|
||||
return `^.+\.(json|jsonc)$`
|
||||
case "toml":
|
||||
return `^.+\.toml$`
|
||||
case "yaml", "yml":
|
||||
return `^.+\.(yaml|yml)$`
|
||||
default:
|
||||
return `^.+\.(json|toml|yaml|yml)$`
|
||||
return `^.+\.(json|jsonc|toml|yaml|yml)$`
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/session"
|
||||
"github.com/xtls/xray-core/transport"
|
||||
"github.com/xtls/xray-core/transport/internet"
|
||||
)
|
||||
|
@ -30,6 +31,11 @@ func New(ctx context.Context, config *Config) (*Handler, error) {
|
|||
|
||||
// Process implements OutboundHandler.Dispatch().
|
||||
func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error {
|
||||
outbound := session.OutboundFromContext(ctx)
|
||||
if outbound != nil {
|
||||
outbound.Name = "blackhole"
|
||||
}
|
||||
|
||||
nBytes := h.response.WriteTo(link.Writer)
|
||||
if nBytes > 0 {
|
||||
// Sleep a little here to make sure the response is sent to client.
|
||||
|
|
|
@ -96,6 +96,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, d internet.
|
|||
if outbound == nil || !outbound.Target.IsValid() {
|
||||
return newError("invalid outbound")
|
||||
}
|
||||
outbound.Name = "dns"
|
||||
|
||||
srcNetwork := outbound.Target.Network
|
||||
|
||||
|
|
|
@ -102,12 +102,11 @@ func (d *DokodemoDoor) Process(ctx context.Context, network net.Network, conn st
|
|||
}
|
||||
|
||||
inbound := session.InboundFromContext(ctx)
|
||||
if inbound != nil {
|
||||
inbound.Name = "dokodemo-door"
|
||||
inbound.SetCanSpliceCopy(1)
|
||||
inbound.User = &protocol.MemoryUser{
|
||||
Level: d.config.UserLevel,
|
||||
}
|
||||
}
|
||||
|
||||
ctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{
|
||||
From: conn.RemoteAddr(),
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
package proxy
|
||||
|
||||
import "github.com/xtls/xray-core/common/errors"
|
||||
|
||||
type errPathObjHolder struct{}
|
||||
|
||||
func newError(values ...interface{}) *errors.Error {
|
||||
return errors.New(values...).WithPathObj(errPathObjHolder{})
|
||||
}
|
|
@ -125,12 +125,12 @@ type Fragment struct {
|
|||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
MinInterval int32 `protobuf:"varint,1,opt,name=min_interval,json=minInterval,proto3" json:"min_interval,omitempty"`
|
||||
MaxInterval int32 `protobuf:"varint,2,opt,name=max_interval,json=maxInterval,proto3" json:"max_interval,omitempty"`
|
||||
MinLength int32 `protobuf:"varint,3,opt,name=min_length,json=minLength,proto3" json:"min_length,omitempty"`
|
||||
MaxLength int32 `protobuf:"varint,4,opt,name=max_length,json=maxLength,proto3" json:"max_length,omitempty"`
|
||||
StartPacket int32 `protobuf:"varint,5,opt,name=start_packet,json=startPacket,proto3" json:"start_packet,omitempty"`
|
||||
EndPacket int32 `protobuf:"varint,6,opt,name=end_packet,json=endPacket,proto3" json:"end_packet,omitempty"`
|
||||
PacketsFrom uint64 `protobuf:"varint,1,opt,name=packets_from,json=packetsFrom,proto3" json:"packets_from,omitempty"`
|
||||
PacketsTo uint64 `protobuf:"varint,2,opt,name=packets_to,json=packetsTo,proto3" json:"packets_to,omitempty"`
|
||||
LengthMin uint64 `protobuf:"varint,3,opt,name=length_min,json=lengthMin,proto3" json:"length_min,omitempty"`
|
||||
LengthMax uint64 `protobuf:"varint,4,opt,name=length_max,json=lengthMax,proto3" json:"length_max,omitempty"`
|
||||
IntervalMin uint64 `protobuf:"varint,5,opt,name=interval_min,json=intervalMin,proto3" json:"interval_min,omitempty"`
|
||||
IntervalMax uint64 `protobuf:"varint,6,opt,name=interval_max,json=intervalMax,proto3" json:"interval_max,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Fragment) Reset() {
|
||||
|
@ -165,44 +165,44 @@ func (*Fragment) Descriptor() ([]byte, []int) {
|
|||
return file_proxy_freedom_config_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *Fragment) GetMinInterval() int32 {
|
||||
func (x *Fragment) GetPacketsFrom() uint64 {
|
||||
if x != nil {
|
||||
return x.MinInterval
|
||||
return x.PacketsFrom
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *Fragment) GetMaxInterval() int32 {
|
||||
func (x *Fragment) GetPacketsTo() uint64 {
|
||||
if x != nil {
|
||||
return x.MaxInterval
|
||||
return x.PacketsTo
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *Fragment) GetMinLength() int32 {
|
||||
func (x *Fragment) GetLengthMin() uint64 {
|
||||
if x != nil {
|
||||
return x.MinLength
|
||||
return x.LengthMin
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *Fragment) GetMaxLength() int32 {
|
||||
func (x *Fragment) GetLengthMax() uint64 {
|
||||
if x != nil {
|
||||
return x.MaxLength
|
||||
return x.LengthMax
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *Fragment) GetStartPacket() int32 {
|
||||
func (x *Fragment) GetIntervalMin() uint64 {
|
||||
if x != nil {
|
||||
return x.StartPacket
|
||||
return x.IntervalMin
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *Fragment) GetEndPacket() int32 {
|
||||
func (x *Fragment) GetIntervalMax() uint64 {
|
||||
if x != nil {
|
||||
return x.EndPacket
|
||||
return x.IntervalMax
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
@ -302,19 +302,19 @@ var file_proxy_freedom_config_proto_rawDesc = []byte{
|
|||
0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,
|
||||
0x6c, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74,
|
||||
0x52, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x22, 0xd0, 0x01, 0x0a, 0x08, 0x46, 0x72, 0x61,
|
||||
0x67, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x6d, 0x69, 0x6e, 0x5f, 0x69, 0x6e, 0x74,
|
||||
0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x6d, 0x69, 0x6e,
|
||||
0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x21, 0x0a, 0x0c, 0x6d, 0x61, 0x78, 0x5f,
|
||||
0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b,
|
||||
0x6d, 0x61, 0x78, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x1d, 0x0a, 0x0a, 0x6d,
|
||||
0x69, 0x6e, 0x5f, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52,
|
||||
0x09, 0x6d, 0x69, 0x6e, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x61,
|
||||
0x78, 0x5f, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09,
|
||||
0x6d, 0x61, 0x78, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x74, 0x61,
|
||||
0x72, 0x74, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52,
|
||||
0x0b, 0x73, 0x74, 0x61, 0x72, 0x74, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x1d, 0x0a, 0x0a,
|
||||
0x65, 0x6e, 0x64, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05,
|
||||
0x52, 0x09, 0x65, 0x6e, 0x64, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x22, 0xf2, 0x02, 0x0a, 0x06,
|
||||
0x67, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73,
|
||||
0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x70, 0x61, 0x63,
|
||||
0x6b, 0x65, 0x74, 0x73, 0x46, 0x72, 0x6f, 0x6d, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x63, 0x6b,
|
||||
0x65, 0x74, 0x73, 0x5f, 0x74, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x70, 0x61,
|
||||
0x63, 0x6b, 0x65, 0x74, 0x73, 0x54, 0x6f, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x65, 0x6e, 0x67, 0x74,
|
||||
0x68, 0x5f, 0x6d, 0x69, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x6c, 0x65, 0x6e,
|
||||
0x67, 0x74, 0x68, 0x4d, 0x69, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68,
|
||||
0x5f, 0x6d, 0x61, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x6c, 0x65, 0x6e, 0x67,
|
||||
0x74, 0x68, 0x4d, 0x61, 0x78, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61,
|
||||
0x6c, 0x5f, 0x6d, 0x69, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x69, 0x6e, 0x74,
|
||||
0x65, 0x72, 0x76, 0x61, 0x6c, 0x4d, 0x69, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x6e, 0x74, 0x65,
|
||||
0x72, 0x76, 0x61, 0x6c, 0x5f, 0x6d, 0x61, 0x78, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b,
|
||||
0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x4d, 0x61, 0x78, 0x22, 0xf2, 0x02, 0x0a, 0x06,
|
||||
0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x52, 0x0a, 0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
|
||||
0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32,
|
||||
0x29, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x66, 0x72, 0x65,
|
||||
|
|
|
@ -13,12 +13,12 @@ message DestinationOverride {
|
|||
}
|
||||
|
||||
message Fragment {
|
||||
int32 min_interval = 1;
|
||||
int32 max_interval = 2;
|
||||
int32 min_length = 3;
|
||||
int32 max_length = 4;
|
||||
int32 start_packet = 5;
|
||||
int32 end_packet = 6;
|
||||
uint64 packets_from = 1;
|
||||
uint64 packets_to = 2;
|
||||
uint64 length_min = 3;
|
||||
uint64 length_max = 4;
|
||||
uint64 interval_min = 5;
|
||||
uint64 interval_max = 6;
|
||||
}
|
||||
|
||||
message Config {
|
||||
|
|
|
@ -5,7 +5,6 @@ package freedom
|
|||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"io"
|
||||
"math/big"
|
||||
"time"
|
||||
|
@ -13,8 +12,8 @@ import (
|
|||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/buf"
|
||||
"github.com/xtls/xray-core/common/dice"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/platform"
|
||||
"github.com/xtls/xray-core/common/retry"
|
||||
"github.com/xtls/xray-core/common/session"
|
||||
"github.com/xtls/xray-core/common/signal"
|
||||
|
@ -23,11 +22,14 @@ import (
|
|||
"github.com/xtls/xray-core/features/dns"
|
||||
"github.com/xtls/xray-core/features/policy"
|
||||
"github.com/xtls/xray-core/features/stats"
|
||||
"github.com/xtls/xray-core/proxy"
|
||||
"github.com/xtls/xray-core/transport"
|
||||
"github.com/xtls/xray-core/transport/internet"
|
||||
"github.com/xtls/xray-core/transport/internet/stat"
|
||||
)
|
||||
|
||||
var useSplice bool
|
||||
|
||||
func init() {
|
||||
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
|
||||
h := new(Handler)
|
||||
|
@ -38,6 +40,12 @@ func init() {
|
|||
}
|
||||
return h, nil
|
||||
}))
|
||||
const defaultFlagValue = "NOT_DEFINED_AT_ALL"
|
||||
value := platform.NewEnvFlag("xray.buf.splice").GetValue(func() string { return defaultFlagValue })
|
||||
switch value {
|
||||
case "auto", "enable":
|
||||
useSplice = true
|
||||
}
|
||||
}
|
||||
|
||||
// Handler handles Freedom connections.
|
||||
|
@ -109,6 +117,11 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||
if outbound == nil || !outbound.Target.IsValid() {
|
||||
return newError("target not specified.")
|
||||
}
|
||||
outbound.Name = "freedom"
|
||||
inbound := session.InboundFromContext(ctx)
|
||||
if inbound != nil {
|
||||
inbound.SetCanSpliceCopy(1)
|
||||
}
|
||||
destination := outbound.Target
|
||||
UDPOverride := net.UDPDestination(nil, 0)
|
||||
if h.config.DestinationOverride != nil {
|
||||
|
@ -175,28 +188,12 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||
var writer buf.Writer
|
||||
if destination.Network == net.Network_TCP {
|
||||
if h.config.Fragment != nil {
|
||||
if h.config.Fragment.StartPacket == 0 && h.config.Fragment.EndPacket == 1 {
|
||||
newError("FRAGMENT", int(h.config.Fragment.MaxLength)).WriteToLog(session.ExportIDToError(ctx))
|
||||
writer = buf.NewWriter(
|
||||
&FragmentedClientHelloConn{
|
||||
Conn: conn,
|
||||
maxLength: int(h.config.Fragment.MaxLength),
|
||||
minInterval: time.Duration(h.config.Fragment.MinInterval) * time.Millisecond,
|
||||
maxInterval: time.Duration(h.config.Fragment.MaxInterval) * time.Millisecond,
|
||||
newError("FRAGMENT", h.config.Fragment.PacketsFrom, h.config.Fragment.PacketsTo, h.config.Fragment.LengthMin, h.config.Fragment.LengthMax,
|
||||
h.config.Fragment.IntervalMin, h.config.Fragment.IntervalMax).AtDebug().WriteToLog(session.ExportIDToError(ctx))
|
||||
writer = buf.NewWriter(&FragmentWriter{
|
||||
fragment: h.config.Fragment,
|
||||
writer: conn,
|
||||
})
|
||||
} else {
|
||||
writer = buf.NewWriter(
|
||||
&FragmentWriter{
|
||||
Writer: conn,
|
||||
minLength: int(h.config.Fragment.MinLength),
|
||||
maxLength: int(h.config.Fragment.MaxLength),
|
||||
minInterval: time.Duration(h.config.Fragment.MinInterval) * time.Millisecond,
|
||||
maxInterval: time.Duration(h.config.Fragment.MaxInterval) * time.Millisecond,
|
||||
startPacket: int(h.config.Fragment.StartPacket),
|
||||
endPacket: int(h.config.Fragment.EndPacket),
|
||||
PacketCount: 0,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
writer = buf.NewWriter(conn)
|
||||
}
|
||||
|
@ -213,17 +210,17 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||
|
||||
responseDone := func() error {
|
||||
defer timer.SetTimeout(plcy.Timeouts.UplinkOnly)
|
||||
|
||||
var reader buf.Reader
|
||||
if destination.Network == net.Network_TCP {
|
||||
reader = buf.NewReader(conn)
|
||||
} else {
|
||||
reader = NewPacketReader(conn, UDPOverride)
|
||||
var writeConn net.Conn
|
||||
if inbound := session.InboundFromContext(ctx); inbound != nil && inbound.Conn != nil && useSplice {
|
||||
writeConn = inbound.Conn
|
||||
}
|
||||
return proxy.CopyRawConnIfExist(ctx, conn, writeConn, link.Writer, timer)
|
||||
}
|
||||
reader := NewPacketReader(conn, UDPOverride)
|
||||
if err := buf.Copy(reader, output, buf.UpdateActivity(timer)); err != nil {
|
||||
return newError("failed to process response").Base(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -356,40 +353,66 @@ func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
|||
}
|
||||
|
||||
type FragmentWriter struct {
|
||||
io.Writer
|
||||
minLength int
|
||||
maxLength int
|
||||
minInterval time.Duration
|
||||
maxInterval time.Duration
|
||||
startPacket int
|
||||
endPacket int
|
||||
PacketCount int
|
||||
fragment *Fragment
|
||||
writer io.Writer
|
||||
count uint64
|
||||
}
|
||||
|
||||
func (w *FragmentWriter) Write(buf []byte) (int, error) {
|
||||
w.PacketCount += 1
|
||||
if (w.startPacket != 0 && (w.PacketCount < w.startPacket || w.PacketCount > w.endPacket)) || len(buf) <= w.minLength {
|
||||
return w.Writer.Write(buf)
|
||||
}
|
||||
func (f *FragmentWriter) Write(b []byte) (int, error) {
|
||||
f.count++
|
||||
|
||||
nTotal := 0
|
||||
for {
|
||||
randomBytesTo := int(randBetween(int64(w.minLength), int64(w.maxLength))) + nTotal
|
||||
if randomBytesTo > len(buf) {
|
||||
randomBytesTo = len(buf)
|
||||
if f.fragment.PacketsFrom == 0 && f.fragment.PacketsTo == 1 {
|
||||
if f.count != 1 || len(b) <= 5 || b[0] != 22 {
|
||||
return f.writer.Write(b)
|
||||
}
|
||||
n, err := w.Writer.Write(buf[nTotal:randomBytesTo])
|
||||
recordLen := 5 + ((int(b[3]) << 8) | int(b[4]))
|
||||
data := b[5:recordLen]
|
||||
buf := make([]byte, 1024)
|
||||
for from := 0; ; {
|
||||
to := from + int(randBetween(int64(f.fragment.LengthMin), int64(f.fragment.LengthMax)))
|
||||
if to > len(data) {
|
||||
to = len(data)
|
||||
}
|
||||
copy(buf[:3], b)
|
||||
copy(buf[5:], data[from:to])
|
||||
l := to - from
|
||||
from = to
|
||||
buf[3] = byte(l >> 8)
|
||||
buf[4] = byte(l)
|
||||
_, err := f.writer.Write(buf[:5+l])
|
||||
time.Sleep(time.Duration(randBetween(int64(f.fragment.IntervalMin), int64(f.fragment.IntervalMax))) * time.Millisecond)
|
||||
if err != nil {
|
||||
return nTotal + n, err
|
||||
return 0, err
|
||||
}
|
||||
if from == len(data) {
|
||||
if len(b) > recordLen {
|
||||
n, err := f.writer.Write(b[recordLen:])
|
||||
if err != nil {
|
||||
return recordLen + n, err
|
||||
}
|
||||
}
|
||||
return len(b), nil
|
||||
}
|
||||
}
|
||||
nTotal += n
|
||||
|
||||
if nTotal >= len(buf) {
|
||||
return nTotal, nil
|
||||
}
|
||||
|
||||
randomInterval := randBetween(int64(w.minInterval), int64(w.maxInterval))
|
||||
time.Sleep(time.Duration(randomInterval))
|
||||
if f.fragment.PacketsFrom != 0 && (f.count < f.fragment.PacketsFrom || f.count > f.fragment.PacketsTo) {
|
||||
return f.writer.Write(b)
|
||||
}
|
||||
for from := 0; ; {
|
||||
to := from + int(randBetween(int64(f.fragment.LengthMin), int64(f.fragment.LengthMax)))
|
||||
if to > len(b) {
|
||||
to = len(b)
|
||||
}
|
||||
n, err := f.writer.Write(b[from:to])
|
||||
from += n
|
||||
time.Sleep(time.Duration(randBetween(int64(f.fragment.IntervalMin), int64(f.fragment.IntervalMax))) * time.Millisecond)
|
||||
if err != nil {
|
||||
return from, err
|
||||
}
|
||||
if from >= len(b) {
|
||||
return from, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -401,66 +424,3 @@ func randBetween(left int64, right int64) int64 {
|
|||
bigInt, _ := rand.Int(rand.Reader, big.NewInt(right-left))
|
||||
return left + bigInt.Int64()
|
||||
}
|
||||
|
||||
type FragmentedClientHelloConn struct {
|
||||
net.Conn
|
||||
PacketCount int
|
||||
minLength int
|
||||
maxLength int
|
||||
minInterval time.Duration
|
||||
maxInterval time.Duration
|
||||
}
|
||||
|
||||
func (c *FragmentedClientHelloConn) Write(b []byte) (n int, err error) {
|
||||
if len(b) >= 5 && b[0] == 22 && c.PacketCount == 0 {
|
||||
n, err = sendFragmentedClientHello(c, b, c.minLength, c.maxLength)
|
||||
|
||||
if err == nil {
|
||||
c.PacketCount++
|
||||
return n, err
|
||||
}
|
||||
}
|
||||
|
||||
return c.Conn.Write(b)
|
||||
}
|
||||
|
||||
func sendFragmentedClientHello(conn *FragmentedClientHelloConn, clientHello []byte, minFragmentSize, maxFragmentSize int) (n int, err error) {
|
||||
if len(clientHello) < 5 || clientHello[0] != 22 {
|
||||
return 0, errors.New("not a valid TLS ClientHello message")
|
||||
}
|
||||
|
||||
clientHelloLen := (int(clientHello[3]) << 8) | int(clientHello[4])
|
||||
|
||||
clientHelloData := clientHello[5:]
|
||||
for i := 0; i < clientHelloLen; {
|
||||
fragmentEnd := i + int(randBetween(int64(minFragmentSize), int64(maxFragmentSize)))
|
||||
if fragmentEnd > clientHelloLen {
|
||||
fragmentEnd = clientHelloLen
|
||||
}
|
||||
|
||||
fragment := clientHelloData[i:fragmentEnd]
|
||||
i = fragmentEnd
|
||||
|
||||
err = writeFragmentedRecord(conn, 22, fragment, clientHello)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
|
||||
return len(clientHello), nil
|
||||
}
|
||||
|
||||
func writeFragmentedRecord(c *FragmentedClientHelloConn, contentType uint8, data []byte, clientHello []byte) error {
|
||||
header := make([]byte, 5)
|
||||
header[0] = byte(clientHello[0])
|
||||
|
||||
tlsVersion := (int(clientHello[1]) << 8) | int(clientHello[2])
|
||||
binary.BigEndian.PutUint16(header[1:], uint16(tlsVersion))
|
||||
|
||||
binary.BigEndian.PutUint16(header[3:], uint16(len(data)))
|
||||
_, err := c.Conn.Write(append(header, data...))
|
||||
randomInterval := randBetween(int64(c.minInterval), int64(c.maxInterval))
|
||||
time.Sleep(time.Duration(randomInterval))
|
||||
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -73,6 +73,11 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
|
|||
if outbound == nil || !outbound.Target.IsValid() {
|
||||
return newError("target not specified.")
|
||||
}
|
||||
outbound.Name = "http"
|
||||
inbound := session.InboundFromContext(ctx)
|
||||
if inbound != nil {
|
||||
inbound.SetCanSpliceCopy(2)
|
||||
}
|
||||
target := outbound.Target
|
||||
targetAddr := target.NetAddr()
|
||||
|
||||
|
@ -172,6 +177,10 @@ func fillRequestHeader(ctx context.Context, header []*Header) ([]*Header, error)
|
|||
inbound := session.InboundFromContext(ctx)
|
||||
outbound := session.OutboundFromContext(ctx)
|
||||
|
||||
if inbound == nil || outbound == nil {
|
||||
return nil, newError("missing inbound or outbound metadata from context")
|
||||
}
|
||||
|
||||
data := struct {
|
||||
Source net.Destination
|
||||
Target net.Destination
|
||||
|
|
|
@ -84,12 +84,11 @@ type readerOnly struct {
|
|||
|
||||
func (s *Server) Process(ctx context.Context, network net.Network, conn stat.Connection, dispatcher routing.Dispatcher) error {
|
||||
inbound := session.InboundFromContext(ctx)
|
||||
if inbound != nil {
|
||||
inbound.Name = "http"
|
||||
inbound.SetCanSpliceCopy(2)
|
||||
inbound.User = &protocol.MemoryUser{
|
||||
Level: s.config.UserLevel,
|
||||
}
|
||||
}
|
||||
|
||||
reader := bufio.NewReaderSize(readerOnly{conn}, buf.Size)
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ func (l *Loopback) Process(ctx context.Context, link *transport.Link, _ internet
|
|||
if outbound == nil || !outbound.Target.IsValid() {
|
||||
return newError("target not specified.")
|
||||
}
|
||||
outbound.Name = "loopback"
|
||||
destination := outbound.Target
|
||||
|
||||
newError("opening connection to ", destination).WriteToLog(session.ExportIDToError(ctx))
|
||||
|
|
464
proxy/proxy.go
464
proxy/proxy.go
|
@ -6,15 +6,52 @@
|
|||
package proxy
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"io"
|
||||
"math/big"
|
||||
"runtime"
|
||||
"strconv"
|
||||
|
||||
"github.com/pires/go-proxyproto"
|
||||
"github.com/xtls/xray-core/common/buf"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/protocol"
|
||||
"github.com/xtls/xray-core/common/session"
|
||||
"github.com/xtls/xray-core/common/signal"
|
||||
"github.com/xtls/xray-core/features/routing"
|
||||
"github.com/xtls/xray-core/features/stats"
|
||||
"github.com/xtls/xray-core/transport"
|
||||
"github.com/xtls/xray-core/transport/internet"
|
||||
"github.com/xtls/xray-core/transport/internet/reality"
|
||||
"github.com/xtls/xray-core/transport/internet/stat"
|
||||
"github.com/xtls/xray-core/transport/internet/tls"
|
||||
)
|
||||
|
||||
var (
|
||||
Tls13SupportedVersions = []byte{0x00, 0x2b, 0x00, 0x02, 0x03, 0x04}
|
||||
TlsClientHandShakeStart = []byte{0x16, 0x03}
|
||||
TlsServerHandShakeStart = []byte{0x16, 0x03, 0x03}
|
||||
TlsApplicationDataStart = []byte{0x17, 0x03, 0x03}
|
||||
|
||||
Tls13CipherSuiteDic = map[uint16]string{
|
||||
0x1301: "TLS_AES_128_GCM_SHA256",
|
||||
0x1302: "TLS_AES_256_GCM_SHA384",
|
||||
0x1303: "TLS_CHACHA20_POLY1305_SHA256",
|
||||
0x1304: "TLS_AES_128_CCM_SHA256",
|
||||
0x1305: "TLS_AES_128_CCM_8_SHA256",
|
||||
}
|
||||
)
|
||||
|
||||
const (
|
||||
TlsHandshakeTypeClientHello byte = 0x01
|
||||
TlsHandshakeTypeServerHello byte = 0x02
|
||||
|
||||
CommandPaddingContinue byte = 0x00
|
||||
CommandPaddingEnd byte = 0x01
|
||||
CommandPaddingDirect byte = 0x02
|
||||
)
|
||||
|
||||
// An Inbound processes inbound connections.
|
||||
|
@ -48,3 +85,430 @@ type GetInbound interface {
|
|||
type GetOutbound interface {
|
||||
GetOutbound() Outbound
|
||||
}
|
||||
|
||||
// TrafficState is used to track uplink and downlink of one connection
|
||||
// It is used by XTLS to determine if switch to raw copy mode, It is used by Vision to calculate padding
|
||||
type TrafficState struct {
|
||||
UserUUID []byte
|
||||
NumberOfPacketToFilter int
|
||||
EnableXtls bool
|
||||
IsTLS12orAbove bool
|
||||
IsTLS bool
|
||||
Cipher uint16
|
||||
RemainingServerHello int32
|
||||
|
||||
// reader link state
|
||||
WithinPaddingBuffers bool
|
||||
ReaderSwitchToDirectCopy bool
|
||||
RemainingCommand int32
|
||||
RemainingContent int32
|
||||
RemainingPadding int32
|
||||
CurrentCommand int
|
||||
|
||||
// write link state
|
||||
IsPadding bool
|
||||
WriterSwitchToDirectCopy bool
|
||||
}
|
||||
|
||||
func NewTrafficState(userUUID []byte) *TrafficState {
|
||||
return &TrafficState{
|
||||
UserUUID: userUUID,
|
||||
NumberOfPacketToFilter: 8,
|
||||
EnableXtls: false,
|
||||
IsTLS12orAbove: false,
|
||||
IsTLS: false,
|
||||
Cipher: 0,
|
||||
RemainingServerHello: -1,
|
||||
WithinPaddingBuffers: true,
|
||||
ReaderSwitchToDirectCopy: false,
|
||||
RemainingCommand: -1,
|
||||
RemainingContent: -1,
|
||||
RemainingPadding: -1,
|
||||
CurrentCommand: 0,
|
||||
IsPadding: true,
|
||||
WriterSwitchToDirectCopy: false,
|
||||
}
|
||||
}
|
||||
|
||||
// VisionReader is used to read xtls vision protocol
|
||||
// Note Vision probably only make sense as the inner most layer of reader, since it need assess traffic state from origin proxy traffic
|
||||
type VisionReader struct {
|
||||
buf.Reader
|
||||
trafficState *TrafficState
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
func NewVisionReader(reader buf.Reader, state *TrafficState, context context.Context) *VisionReader {
|
||||
return &VisionReader{
|
||||
Reader: reader,
|
||||
trafficState: state,
|
||||
ctx: context,
|
||||
}
|
||||
}
|
||||
|
||||
func (w *VisionReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
|
||||
buffer, err := w.Reader.ReadMultiBuffer()
|
||||
if !buffer.IsEmpty() {
|
||||
if w.trafficState.WithinPaddingBuffers || w.trafficState.NumberOfPacketToFilter > 0 {
|
||||
mb2 := make(buf.MultiBuffer, 0, len(buffer))
|
||||
for _, b := range buffer {
|
||||
newbuffer := XtlsUnpadding(b, w.trafficState, w.ctx)
|
||||
if newbuffer.Len() > 0 {
|
||||
mb2 = append(mb2, newbuffer)
|
||||
}
|
||||
}
|
||||
buffer = mb2
|
||||
if w.trafficState.RemainingContent > 0 || w.trafficState.RemainingPadding > 0 || w.trafficState.CurrentCommand == 0 {
|
||||
w.trafficState.WithinPaddingBuffers = true
|
||||
} else if w.trafficState.CurrentCommand == 1 {
|
||||
w.trafficState.WithinPaddingBuffers = false
|
||||
} else if w.trafficState.CurrentCommand == 2 {
|
||||
w.trafficState.WithinPaddingBuffers = false
|
||||
w.trafficState.ReaderSwitchToDirectCopy = true
|
||||
} else {
|
||||
newError("XtlsRead unknown command ", w.trafficState.CurrentCommand, buffer.Len()).WriteToLog(session.ExportIDToError(w.ctx))
|
||||
}
|
||||
}
|
||||
if w.trafficState.NumberOfPacketToFilter > 0 {
|
||||
XtlsFilterTls(buffer, w.trafficState, w.ctx)
|
||||
}
|
||||
}
|
||||
return buffer, err
|
||||
}
|
||||
|
||||
// VisionWriter is used to write xtls vision protocol
|
||||
// Note Vision probably only make sense as the inner most layer of writer, since it need assess traffic state from origin proxy traffic
|
||||
type VisionWriter struct {
|
||||
buf.Writer
|
||||
trafficState *TrafficState
|
||||
ctx context.Context
|
||||
writeOnceUserUUID []byte
|
||||
}
|
||||
|
||||
func NewVisionWriter(writer buf.Writer, state *TrafficState, context context.Context) *VisionWriter {
|
||||
w := make([]byte, len(state.UserUUID))
|
||||
copy(w, state.UserUUID)
|
||||
return &VisionWriter{
|
||||
Writer: writer,
|
||||
trafficState: state,
|
||||
ctx: context,
|
||||
writeOnceUserUUID: w,
|
||||
}
|
||||
}
|
||||
|
||||
func (w *VisionWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
||||
if w.trafficState.NumberOfPacketToFilter > 0 {
|
||||
XtlsFilterTls(mb, w.trafficState, w.ctx)
|
||||
}
|
||||
if w.trafficState.IsPadding {
|
||||
if len(mb) == 1 && mb[0] == nil {
|
||||
mb[0] = XtlsPadding(nil, CommandPaddingContinue, &w.writeOnceUserUUID, true, w.ctx) // we do a long padding to hide vless header
|
||||
return w.Writer.WriteMultiBuffer(mb)
|
||||
}
|
||||
mb = ReshapeMultiBuffer(w.ctx, mb)
|
||||
longPadding := w.trafficState.IsTLS
|
||||
for i, b := range mb {
|
||||
if w.trafficState.IsTLS && b.Len() >= 6 && bytes.Equal(TlsApplicationDataStart, b.BytesTo(3)) {
|
||||
if w.trafficState.EnableXtls {
|
||||
w.trafficState.WriterSwitchToDirectCopy = true
|
||||
}
|
||||
var command byte = CommandPaddingContinue
|
||||
if i == len(mb) - 1 {
|
||||
command = CommandPaddingEnd
|
||||
if w.trafficState.EnableXtls {
|
||||
command = CommandPaddingDirect
|
||||
}
|
||||
}
|
||||
mb[i] = XtlsPadding(b, command, &w.writeOnceUserUUID, true, w.ctx)
|
||||
w.trafficState.IsPadding = false // padding going to end
|
||||
longPadding = false
|
||||
continue
|
||||
} else if !w.trafficState.IsTLS12orAbove && w.trafficState.NumberOfPacketToFilter <= 1 { // For compatibility with earlier vision receiver, we finish padding 1 packet early
|
||||
w.trafficState.IsPadding = false
|
||||
mb[i] = XtlsPadding(b, CommandPaddingEnd, &w.writeOnceUserUUID, longPadding, w.ctx)
|
||||
break
|
||||
}
|
||||
var command byte = CommandPaddingContinue
|
||||
if i == len(mb) - 1 && !w.trafficState.IsPadding {
|
||||
command = CommandPaddingEnd
|
||||
if w.trafficState.EnableXtls {
|
||||
command = CommandPaddingDirect
|
||||
}
|
||||
}
|
||||
mb[i] = XtlsPadding(b, command, &w.writeOnceUserUUID, longPadding, w.ctx)
|
||||
}
|
||||
}
|
||||
return w.Writer.WriteMultiBuffer(mb)
|
||||
}
|
||||
|
||||
// ReshapeMultiBuffer prepare multi buffer for padding stucture (max 21 bytes)
|
||||
func ReshapeMultiBuffer(ctx context.Context, buffer buf.MultiBuffer) buf.MultiBuffer {
|
||||
needReshape := 0
|
||||
for _, b := range buffer {
|
||||
if b.Len() >= buf.Size-21 {
|
||||
needReshape += 1
|
||||
}
|
||||
}
|
||||
if needReshape == 0 {
|
||||
return buffer
|
||||
}
|
||||
mb2 := make(buf.MultiBuffer, 0, len(buffer)+needReshape)
|
||||
toPrint := ""
|
||||
for i, buffer1 := range buffer {
|
||||
if buffer1.Len() >= buf.Size-21 {
|
||||
index := int32(bytes.LastIndex(buffer1.Bytes(), TlsApplicationDataStart))
|
||||
if index <= 0 || index > buf.Size-21 {
|
||||
index = buf.Size / 2
|
||||
}
|
||||
buffer2 := buf.New()
|
||||
buffer2.Write(buffer1.BytesFrom(index))
|
||||
buffer1.Resize(0, index)
|
||||
mb2 = append(mb2, buffer1, buffer2)
|
||||
toPrint += " " + strconv.Itoa(int(buffer1.Len())) + " " + strconv.Itoa(int(buffer2.Len()))
|
||||
} else {
|
||||
mb2 = append(mb2, buffer1)
|
||||
toPrint += " " + strconv.Itoa(int(buffer1.Len()))
|
||||
}
|
||||
buffer[i] = nil
|
||||
}
|
||||
buffer = buffer[:0]
|
||||
newError("ReshapeMultiBuffer ", toPrint).WriteToLog(session.ExportIDToError(ctx))
|
||||
return mb2
|
||||
}
|
||||
|
||||
// XtlsPadding add padding to eliminate length siganature during tls handshake
|
||||
func XtlsPadding(b *buf.Buffer, command byte, userUUID *[]byte, longPadding bool, ctx context.Context) *buf.Buffer {
|
||||
var contentLen int32 = 0
|
||||
var paddingLen int32 = 0
|
||||
if b != nil {
|
||||
contentLen = b.Len()
|
||||
}
|
||||
if contentLen < 900 && longPadding {
|
||||
l, err := rand.Int(rand.Reader, big.NewInt(500))
|
||||
if err != nil {
|
||||
newError("failed to generate padding").Base(err).WriteToLog(session.ExportIDToError(ctx))
|
||||
}
|
||||
paddingLen = int32(l.Int64()) + 900 - contentLen
|
||||
} else {
|
||||
l, err := rand.Int(rand.Reader, big.NewInt(256))
|
||||
if err != nil {
|
||||
newError("failed to generate padding").Base(err).WriteToLog(session.ExportIDToError(ctx))
|
||||
}
|
||||
paddingLen = int32(l.Int64())
|
||||
}
|
||||
if paddingLen > buf.Size-21-contentLen {
|
||||
paddingLen = buf.Size - 21 - contentLen
|
||||
}
|
||||
newbuffer := buf.New()
|
||||
if userUUID != nil {
|
||||
newbuffer.Write(*userUUID)
|
||||
*userUUID = nil
|
||||
}
|
||||
newbuffer.Write([]byte{command, byte(contentLen >> 8), byte(contentLen), byte(paddingLen >> 8), byte(paddingLen)})
|
||||
if b != nil {
|
||||
newbuffer.Write(b.Bytes())
|
||||
b.Release()
|
||||
b = nil
|
||||
}
|
||||
newbuffer.Extend(paddingLen)
|
||||
newError("XtlsPadding ", contentLen, " ", paddingLen, " ", command).WriteToLog(session.ExportIDToError(ctx))
|
||||
return newbuffer
|
||||
}
|
||||
|
||||
// XtlsUnpadding remove padding and parse command
|
||||
func XtlsUnpadding(b *buf.Buffer, s *TrafficState, ctx context.Context) *buf.Buffer {
|
||||
if s.RemainingCommand == -1 && s.RemainingContent == -1 && s.RemainingPadding == -1 { // inital state
|
||||
if b.Len() >= 21 && bytes.Equal(s.UserUUID, b.BytesTo(16)) {
|
||||
b.Advance(16)
|
||||
s.RemainingCommand = 5
|
||||
} else {
|
||||
return b
|
||||
}
|
||||
}
|
||||
newbuffer := buf.New()
|
||||
for b.Len() > 0 {
|
||||
if s.RemainingCommand > 0 {
|
||||
data, err := b.ReadByte()
|
||||
if err != nil {
|
||||
return newbuffer
|
||||
}
|
||||
switch s.RemainingCommand {
|
||||
case 5:
|
||||
s.CurrentCommand = int(data)
|
||||
case 4:
|
||||
s.RemainingContent = int32(data)<<8
|
||||
case 3:
|
||||
s.RemainingContent = s.RemainingContent | int32(data)
|
||||
case 2:
|
||||
s.RemainingPadding = int32(data)<<8
|
||||
case 1:
|
||||
s.RemainingPadding = s.RemainingPadding | int32(data)
|
||||
newError("Xtls Unpadding new block, content ", s.RemainingContent, " padding ", s.RemainingPadding, " command ", s.CurrentCommand).WriteToLog(session.ExportIDToError(ctx))
|
||||
}
|
||||
s.RemainingCommand--
|
||||
} else if s.RemainingContent > 0 {
|
||||
len := s.RemainingContent
|
||||
if b.Len() < len {
|
||||
len = b.Len()
|
||||
}
|
||||
data, err := b.ReadBytes(len)
|
||||
if err != nil {
|
||||
return newbuffer
|
||||
}
|
||||
newbuffer.Write(data)
|
||||
s.RemainingContent -= len
|
||||
} else { // remainingPadding > 0
|
||||
len := s.RemainingPadding
|
||||
if b.Len() < len {
|
||||
len = b.Len()
|
||||
}
|
||||
b.Advance(len)
|
||||
s.RemainingPadding -= len
|
||||
}
|
||||
if s.RemainingCommand <= 0 && s.RemainingContent <= 0 && s.RemainingPadding <= 0 { // this block done
|
||||
if s.CurrentCommand == 0 {
|
||||
s.RemainingCommand = 5
|
||||
} else {
|
||||
s.RemainingCommand = -1 // set to initial state
|
||||
s.RemainingContent = -1
|
||||
s.RemainingPadding = -1
|
||||
if b.Len() > 0 { // shouldn't happen
|
||||
newbuffer.Write(b.Bytes())
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
b.Release()
|
||||
b = nil
|
||||
return newbuffer
|
||||
}
|
||||
|
||||
// XtlsFilterTls filter and recognize tls 1.3 and other info
|
||||
func XtlsFilterTls(buffer buf.MultiBuffer, trafficState *TrafficState, ctx context.Context) {
|
||||
for _, b := range buffer {
|
||||
if b == nil {
|
||||
continue
|
||||
}
|
||||
trafficState.NumberOfPacketToFilter--
|
||||
if b.Len() >= 6 {
|
||||
startsBytes := b.BytesTo(6)
|
||||
if bytes.Equal(TlsServerHandShakeStart, startsBytes[:3]) && startsBytes[5] == TlsHandshakeTypeServerHello {
|
||||
trafficState.RemainingServerHello = (int32(startsBytes[3])<<8 | int32(startsBytes[4])) + 5
|
||||
trafficState.IsTLS12orAbove = true
|
||||
trafficState.IsTLS = true
|
||||
if b.Len() >= 79 && trafficState.RemainingServerHello >= 79 {
|
||||
sessionIdLen := int32(b.Byte(43))
|
||||
cipherSuite := b.BytesRange(43+sessionIdLen+1, 43+sessionIdLen+3)
|
||||
trafficState.Cipher = uint16(cipherSuite[0])<<8 | uint16(cipherSuite[1])
|
||||
} else {
|
||||
newError("XtlsFilterTls short server hello, tls 1.2 or older? ", b.Len(), " ", trafficState.RemainingServerHello).WriteToLog(session.ExportIDToError(ctx))
|
||||
}
|
||||
} else if bytes.Equal(TlsClientHandShakeStart, startsBytes[:2]) && startsBytes[5] == TlsHandshakeTypeClientHello {
|
||||
trafficState.IsTLS = true
|
||||
newError("XtlsFilterTls found tls client hello! ", buffer.Len()).WriteToLog(session.ExportIDToError(ctx))
|
||||
}
|
||||
}
|
||||
if trafficState.RemainingServerHello > 0 {
|
||||
end := trafficState.RemainingServerHello
|
||||
if end > b.Len() {
|
||||
end = b.Len()
|
||||
}
|
||||
trafficState.RemainingServerHello -= b.Len()
|
||||
if bytes.Contains(b.BytesTo(end), Tls13SupportedVersions) {
|
||||
v, ok := Tls13CipherSuiteDic[trafficState.Cipher]
|
||||
if !ok {
|
||||
v = "Old cipher: " + strconv.FormatUint(uint64(trafficState.Cipher), 16)
|
||||
} else if v != "TLS_AES_128_CCM_8_SHA256" {
|
||||
trafficState.EnableXtls = true
|
||||
}
|
||||
newError("XtlsFilterTls found tls 1.3! ", b.Len(), " ", v).WriteToLog(session.ExportIDToError(ctx))
|
||||
trafficState.NumberOfPacketToFilter = 0
|
||||
return
|
||||
} else if trafficState.RemainingServerHello <= 0 {
|
||||
newError("XtlsFilterTls found tls 1.2! ", b.Len()).WriteToLog(session.ExportIDToError(ctx))
|
||||
trafficState.NumberOfPacketToFilter = 0
|
||||
return
|
||||
}
|
||||
newError("XtlsFilterTls inconclusive server hello ", b.Len(), " ", trafficState.RemainingServerHello).WriteToLog(session.ExportIDToError(ctx))
|
||||
}
|
||||
if trafficState.NumberOfPacketToFilter <= 0 {
|
||||
newError("XtlsFilterTls stop filtering", buffer.Len()).WriteToLog(session.ExportIDToError(ctx))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// UnwrapRawConn support unwrap stats, tls, utls, reality and proxyproto conn and get raw tcp conn from it
|
||||
func UnwrapRawConn(conn net.Conn) (net.Conn, stats.Counter, stats.Counter) {
|
||||
var readCounter, writerCounter stats.Counter
|
||||
if conn != nil {
|
||||
statConn, ok := conn.(*stat.CounterConnection)
|
||||
if ok {
|
||||
conn = statConn.Connection
|
||||
readCounter = statConn.ReadCounter
|
||||
writerCounter = statConn.WriteCounter
|
||||
}
|
||||
if xc, ok := conn.(*tls.Conn); ok {
|
||||
conn = xc.NetConn()
|
||||
} else if utlsConn, ok := conn.(*tls.UConn); ok {
|
||||
conn = utlsConn.NetConn()
|
||||
} else if realityConn, ok := conn.(*reality.Conn); ok {
|
||||
conn = realityConn.NetConn()
|
||||
} else if realityUConn, ok := conn.(*reality.UConn); ok {
|
||||
conn = realityUConn.NetConn()
|
||||
}
|
||||
if pc, ok := conn.(*proxyproto.Conn); ok {
|
||||
conn = pc.Raw()
|
||||
// 8192 > 4096, there is no need to process pc's bufReader
|
||||
}
|
||||
}
|
||||
return conn, readCounter, writerCounter
|
||||
}
|
||||
|
||||
// CopyRawConnIfExist use the most efficient copy method.
|
||||
// - If caller don't want to turn on splice, do not pass in both reader conn and writer conn
|
||||
// - writer are from *transport.Link
|
||||
func CopyRawConnIfExist(ctx context.Context, readerConn net.Conn, writerConn net.Conn, writer buf.Writer, timer signal.ActivityUpdater) error {
|
||||
readerConn, readCounter, _ := UnwrapRawConn(readerConn)
|
||||
writerConn, _, writeCounter := UnwrapRawConn(writerConn)
|
||||
reader := buf.NewReader(readerConn)
|
||||
if inbound := session.InboundFromContext(ctx); inbound != nil {
|
||||
if tc, ok := writerConn.(*net.TCPConn); ok && readerConn != nil && writerConn != nil && (runtime.GOOS == "linux" || runtime.GOOS == "android") {
|
||||
for inbound.CanSpliceCopy != 3 {
|
||||
if inbound.CanSpliceCopy == 1 {
|
||||
newError("CopyRawConn splice").WriteToLog(session.ExportIDToError(ctx))
|
||||
runtime.Gosched() // necessary
|
||||
w, err := tc.ReadFrom(readerConn)
|
||||
if readCounter != nil {
|
||||
readCounter.Add(w)
|
||||
}
|
||||
if writeCounter != nil {
|
||||
writeCounter.Add(w)
|
||||
}
|
||||
if err != nil && errors.Cause(err) != io.EOF {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
buffer, err := reader.ReadMultiBuffer()
|
||||
if !buffer.IsEmpty() {
|
||||
if readCounter != nil {
|
||||
readCounter.Add(int64(buffer.Len()))
|
||||
}
|
||||
timer.Update()
|
||||
if werr := writer.WriteMultiBuffer(buffer); werr != nil {
|
||||
return werr
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
newError("CopyRawConn readv").WriteToLog(session.ExportIDToError(ctx))
|
||||
if err := buf.Copy(reader, writer, buf.UpdateActivity(timer), buf.AddToStatCounter(readCounter)); err != nil {
|
||||
return newError("failed to process response").Base(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -53,6 +53,11 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
|
|||
if outbound == nil || !outbound.Target.IsValid() {
|
||||
return newError("target not specified")
|
||||
}
|
||||
outbound.Name = "shadowsocks"
|
||||
inbound := session.InboundFromContext(ctx)
|
||||
if inbound != nil {
|
||||
inbound.SetCanSpliceCopy(3)
|
||||
}
|
||||
destination := outbound.Target
|
||||
network := destination.Network
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"crypto/hmac"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
"hash/crc32"
|
||||
"io"
|
||||
|
||||
|
@ -236,19 +237,26 @@ func EncodeUDPPacket(request *protocol.RequestHeader, payload []byte) (*buf.Buff
|
|||
}
|
||||
|
||||
func DecodeUDPPacket(validator *Validator, payload *buf.Buffer) (*protocol.RequestHeader, *buf.Buffer, error) {
|
||||
bs := payload.Bytes()
|
||||
if len(bs) <= 32 {
|
||||
return nil, nil, newError("len(bs) <= 32")
|
||||
rawPayload := payload.Bytes()
|
||||
user, _, d, _, err := validator.Get(rawPayload, protocol.RequestCommandUDP)
|
||||
|
||||
if errors.Is(err, ErrIVNotUnique) {
|
||||
return nil, nil, newError("failed iv check").Base(err)
|
||||
}
|
||||
|
||||
user, _, d, _, err := validator.Get(bs, protocol.RequestCommandUDP)
|
||||
switch err {
|
||||
case ErrIVNotUnique:
|
||||
return nil, nil, newError("failed iv check").Base(err)
|
||||
case ErrNotFound:
|
||||
if errors.Is(err, ErrNotFound) {
|
||||
return nil, nil, newError("failed to match an user").Base(err)
|
||||
default:
|
||||
account := user.Account.(*MemoryAccount)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, newError("unexpected error").Base(err)
|
||||
}
|
||||
|
||||
account, ok := user.Account.(*MemoryAccount)
|
||||
if !ok {
|
||||
return nil, nil, newError("expected MemoryAccount returned from validator")
|
||||
}
|
||||
|
||||
if account.Cipher.IsAEAD() {
|
||||
payload.Clear()
|
||||
payload.Write(d)
|
||||
|
@ -261,13 +269,6 @@ func DecodeUDPPacket(validator *Validator, payload *buf.Buffer) (*protocol.Reque
|
|||
return nil, nil, newError("failed to decrypt UDP payload").Base(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
request := &protocol.RequestHeader{
|
||||
Version: Version,
|
||||
User: user,
|
||||
Command: protocol.RequestCommandUDP,
|
||||
}
|
||||
|
||||
payload.SetByte(0, payload.Byte(0)&0x0F)
|
||||
|
||||
|
@ -276,8 +277,13 @@ func DecodeUDPPacket(validator *Validator, payload *buf.Buffer) (*protocol.Reque
|
|||
return nil, nil, newError("failed to parse address").Base(err)
|
||||
}
|
||||
|
||||
request.Address = addr
|
||||
request.Port = port
|
||||
request := &protocol.RequestHeader{
|
||||
Version: Version,
|
||||
User: user,
|
||||
Command: protocol.RequestCommandUDP,
|
||||
Address: addr,
|
||||
Port: port,
|
||||
}
|
||||
|
||||
return request, payload, nil
|
||||
}
|
||||
|
|
|
@ -23,8 +23,9 @@ func equalRequestHeader(x, y *protocol.RequestHeader) bool {
|
|||
}))
|
||||
}
|
||||
|
||||
func TestUDPEncoding(t *testing.T) {
|
||||
request := &protocol.RequestHeader{
|
||||
func TestUDPEncodingDecoding(t *testing.T) {
|
||||
testRequests := []protocol.RequestHeader{
|
||||
{
|
||||
Version: Version,
|
||||
Command: protocol.RequestCommandUDP,
|
||||
Address: net.LocalHostIP,
|
||||
|
@ -36,11 +37,26 @@ func TestUDPEncoding(t *testing.T) {
|
|||
CipherType: CipherType_AES_128_GCM,
|
||||
}),
|
||||
},
|
||||
},
|
||||
{
|
||||
Version: Version,
|
||||
Command: protocol.RequestCommandUDP,
|
||||
Address: net.LocalHostIP,
|
||||
Port: 1234,
|
||||
User: &protocol.MemoryUser{
|
||||
Email: "love@example.com",
|
||||
Account: toAccount(&Account{
|
||||
Password: "123",
|
||||
CipherType: CipherType_NONE,
|
||||
}),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, request := range testRequests {
|
||||
data := buf.New()
|
||||
common.Must2(data.WriteString("test string"))
|
||||
encodedData, err := EncodeUDPPacket(request, data.Bytes())
|
||||
encodedData, err := EncodeUDPPacket(&request, data.Bytes())
|
||||
common.Must(err)
|
||||
|
||||
validator := new(Validator)
|
||||
|
@ -52,9 +68,36 @@ func TestUDPEncoding(t *testing.T) {
|
|||
t.Error("data: ", r)
|
||||
}
|
||||
|
||||
if equalRequestHeader(decodedRequest, request) == false {
|
||||
if equalRequestHeader(decodedRequest, &request) == false {
|
||||
t.Error("different request")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestUDPDecodingWithPayloadTooShort(t *testing.T) {
|
||||
testAccounts := []protocol.Account{
|
||||
toAccount(&Account{
|
||||
Password: "password",
|
||||
CipherType: CipherType_AES_128_GCM,
|
||||
}),
|
||||
toAccount(&Account{
|
||||
Password: "password",
|
||||
CipherType: CipherType_NONE,
|
||||
}),
|
||||
}
|
||||
|
||||
for _, account := range testAccounts {
|
||||
data := buf.New()
|
||||
data.WriteString("short payload")
|
||||
validator := new(Validator)
|
||||
validator.Add(&protocol.MemoryUser{
|
||||
Account: account,
|
||||
})
|
||||
_, _, err := DecodeUDPPacket(validator, data)
|
||||
if err == nil {
|
||||
t.Fatal("expected error")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTCPRequest(t *testing.T) {
|
||||
|
|
|
@ -71,6 +71,10 @@ func (s *Server) Network() []net.Network {
|
|||
}
|
||||
|
||||
func (s *Server) Process(ctx context.Context, network net.Network, conn stat.Connection, dispatcher routing.Dispatcher) error {
|
||||
inbound := session.InboundFromContext(ctx)
|
||||
inbound.Name = "shadowsocks"
|
||||
inbound.SetCanSpliceCopy(3)
|
||||
|
||||
switch network {
|
||||
case net.Network_TCP:
|
||||
return s.handleConnection(ctx, conn, dispatcher)
|
||||
|
@ -110,13 +114,7 @@ func (s *Server) handleUDPPayload(ctx context.Context, conn stat.Connection, dis
|
|||
})
|
||||
|
||||
inbound := session.InboundFromContext(ctx)
|
||||
if inbound == nil {
|
||||
panic("no inbound metadata")
|
||||
}
|
||||
inbound.Name = "shadowsocks"
|
||||
|
||||
var dest *net.Destination
|
||||
|
||||
reader := buf.NewPacketReader(conn)
|
||||
for {
|
||||
mpayload, err := reader.ReadMultiBuffer()
|
||||
|
|
|
@ -80,6 +80,11 @@ func (v *Validator) Get(bs []byte, command protocol.RequestCommand) (u *protocol
|
|||
|
||||
for _, user := range v.users {
|
||||
if account := user.Account.(*MemoryAccount); account.Cipher.IsAEAD() {
|
||||
// AEAD payload decoding requires the payload to be over 32 bytes
|
||||
if len(bs) < 32 {
|
||||
continue
|
||||
}
|
||||
|
||||
aeadCipher := account.Cipher.(*AEADCipher)
|
||||
ivLen = aeadCipher.IVSize()
|
||||
iv := bs[:ivLen]
|
||||
|
|
|
@ -66,6 +66,7 @@ func (i *Inbound) Network() []net.Network {
|
|||
func (i *Inbound) Process(ctx context.Context, network net.Network, connection stat.Connection, dispatcher routing.Dispatcher) error {
|
||||
inbound := session.InboundFromContext(ctx)
|
||||
inbound.Name = "shadowsocks-2022"
|
||||
inbound.SetCanSpliceCopy(3)
|
||||
|
||||
var metadata M.Metadata
|
||||
if inbound.Source.IsValid() {
|
||||
|
|
|
@ -155,6 +155,7 @@ func (i *MultiUserInbound) Network() []net.Network {
|
|||
func (i *MultiUserInbound) Process(ctx context.Context, network net.Network, connection stat.Connection, dispatcher routing.Dispatcher) error {
|
||||
inbound := session.InboundFromContext(ctx)
|
||||
inbound.Name = "shadowsocks-2022-multi"
|
||||
inbound.SetCanSpliceCopy(3)
|
||||
|
||||
var metadata M.Metadata
|
||||
if inbound.Source.IsValid() {
|
||||
|
@ -204,7 +205,12 @@ func (i *MultiUserInbound) NewConnection(ctx context.Context, conn net.Conn, met
|
|||
})
|
||||
newError("tunnelling request to tcp:", metadata.Destination).WriteToLog(session.ExportIDToError(ctx))
|
||||
dispatcher := session.DispatcherFromContext(ctx)
|
||||
link, err := dispatcher.Dispatch(ctx, singbridge.ToDestination(metadata.Destination, net.Network_TCP))
|
||||
destination := singbridge.ToDestination(metadata.Destination, net.Network_TCP)
|
||||
if !destination.IsValid() {
|
||||
return newError("invalid destination")
|
||||
}
|
||||
|
||||
link, err := dispatcher.Dispatch(ctx, destination)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -87,6 +87,7 @@ func (i *RelayInbound) Network() []net.Network {
|
|||
func (i *RelayInbound) Process(ctx context.Context, network net.Network, connection stat.Connection, dispatcher routing.Dispatcher) error {
|
||||
inbound := session.InboundFromContext(ctx)
|
||||
inbound.Name = "shadowsocks-2022-relay"
|
||||
inbound.SetCanSpliceCopy(3)
|
||||
|
||||
var metadata M.Metadata
|
||||
if inbound.Source.IsValid() {
|
||||
|
|
|
@ -66,12 +66,14 @@ func (o *Outbound) Process(ctx context.Context, link *transport.Link, dialer int
|
|||
inbound := session.InboundFromContext(ctx)
|
||||
if inbound != nil {
|
||||
inboundConn = inbound.Conn
|
||||
inbound.SetCanSpliceCopy(3)
|
||||
}
|
||||
|
||||
outbound := session.OutboundFromContext(ctx)
|
||||
if outbound == nil || !outbound.Target.IsValid() {
|
||||
return newError("target not specified")
|
||||
}
|
||||
outbound.Name = "shadowsocks-2022"
|
||||
destination := outbound.Target
|
||||
network := destination.Network
|
||||
|
||||
|
|
|
@ -61,6 +61,11 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
|
|||
if outbound == nil || !outbound.Target.IsValid() {
|
||||
return newError("target not specified.")
|
||||
}
|
||||
outbound.Name = "socks"
|
||||
inbound := session.InboundFromContext(ctx)
|
||||
if inbound != nil {
|
||||
inbound.SetCanSpliceCopy(2)
|
||||
}
|
||||
// Destination of the inner request.
|
||||
destination := outbound.Target
|
||||
|
||||
|
|
|
@ -63,12 +63,12 @@ func (s *Server) Network() []net.Network {
|
|||
|
||||
// Process implements proxy.Inbound.
|
||||
func (s *Server) Process(ctx context.Context, network net.Network, conn stat.Connection, dispatcher routing.Dispatcher) error {
|
||||
if inbound := session.InboundFromContext(ctx); inbound != nil {
|
||||
inbound := session.InboundFromContext(ctx)
|
||||
inbound.Name = "socks"
|
||||
inbound.SetCanSpliceCopy(2)
|
||||
inbound.User = &protocol.MemoryUser{
|
||||
Level: s.config.UserLevel,
|
||||
}
|
||||
}
|
||||
|
||||
switch network {
|
||||
case net.Network_TCP:
|
||||
|
|
|
@ -54,6 +54,11 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
|
|||
if outbound == nil || !outbound.Target.IsValid() {
|
||||
return newError("target not specified")
|
||||
}
|
||||
outbound.Name = "trojan"
|
||||
inbound := session.InboundFromContext(ctx)
|
||||
if inbound != nil {
|
||||
inbound.SetCanSpliceCopy(3)
|
||||
}
|
||||
destination := outbound.Target
|
||||
network := destination.Network
|
||||
|
||||
|
@ -77,22 +82,12 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
|
|||
|
||||
defer conn.Close()
|
||||
|
||||
iConn := conn
|
||||
statConn, ok := iConn.(*stat.CounterConnection)
|
||||
if ok {
|
||||
iConn = statConn.Connection
|
||||
}
|
||||
|
||||
user := server.PickUser()
|
||||
account, ok := user.Account.(*MemoryAccount)
|
||||
if !ok {
|
||||
return newError("user account is not valid")
|
||||
}
|
||||
|
||||
connWriter := &ConnWriter{
|
||||
Flow: account.Flow,
|
||||
}
|
||||
|
||||
var newCtx context.Context
|
||||
var newCancel context.CancelFunc
|
||||
if session.TimeoutOnlyFromContext(ctx) {
|
||||
|
@ -113,9 +108,11 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
|
|||
|
||||
bufferWriter := buf.NewBufferedWriter(buf.NewWriter(conn))
|
||||
|
||||
connWriter.Writer = bufferWriter
|
||||
connWriter.Target = destination
|
||||
connWriter.Account = account
|
||||
connWriter := &ConnWriter{
|
||||
Writer: bufferWriter,
|
||||
Target: destination,
|
||||
Account: account,
|
||||
}
|
||||
|
||||
var bodyWriter buf.Writer
|
||||
if destination.Network == net.Network_UDP {
|
||||
|
|
|
@ -13,7 +13,6 @@ import (
|
|||
type MemoryAccount struct {
|
||||
Password string
|
||||
Key []byte
|
||||
Flow string
|
||||
}
|
||||
|
||||
// AsAccount implements protocol.AsAccount.
|
||||
|
@ -23,7 +22,6 @@ func (a *Account) AsAccount() (protocol.Account, error) {
|
|||
return &MemoryAccount{
|
||||
Password: password,
|
||||
Key: key,
|
||||
Flow: a.Flow,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,6 @@ type Account struct {
|
|||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Password string `protobuf:"bytes,1,opt,name=password,proto3" json:"password,omitempty"`
|
||||
Flow string `protobuf:"bytes,2,opt,name=flow,proto3" json:"flow,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Account) Reset() {
|
||||
|
@ -69,13 +68,6 @@ func (x *Account) GetPassword() string {
|
|||
return ""
|
||||
}
|
||||
|
||||
func (x *Account) GetFlow() string {
|
||||
if x != nil {
|
||||
return x.Flow
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type Fallback struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
|
@ -216,7 +208,7 @@ type ServerConfig struct {
|
|||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Users []*protocol.User `protobuf:"bytes,1,rep,name=users,proto3" json:"users,omitempty"`
|
||||
Fallbacks []*Fallback `protobuf:"bytes,3,rep,name=fallbacks,proto3" json:"fallbacks,omitempty"`
|
||||
Fallbacks []*Fallback `protobuf:"bytes,2,rep,name=fallbacks,proto3" json:"fallbacks,omitempty"`
|
||||
}
|
||||
|
||||
func (x *ServerConfig) Reset() {
|
||||
|
@ -274,38 +266,37 @@ var file_proxy_trojan_config_proto_rawDesc = []byte{
|
|||
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f,
|
||||
0x75, 0x73, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d,
|
||||
0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x73, 0x65, 0x72, 0x76,
|
||||
0x65, 0x72, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x39, 0x0a,
|
||||
0x65, 0x72, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x25, 0x0a,
|
||||
0x07, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73,
|
||||
0x77, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73,
|
||||
0x77, 0x6f, 0x72, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x6c, 0x6f, 0x77, 0x18, 0x02, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x04, 0x66, 0x6c, 0x6f, 0x77, 0x22, 0x82, 0x01, 0x0a, 0x08, 0x46, 0x61, 0x6c,
|
||||
0x6c, 0x62, 0x61, 0x63, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x6c, 0x70,
|
||||
0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x61, 0x6c, 0x70, 0x6e, 0x12, 0x12, 0x0a,
|
||||
0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74,
|
||||
0x68, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x65, 0x73, 0x74, 0x18, 0x05, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x78, 0x76, 0x65,
|
||||
0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x78, 0x76, 0x65, 0x72, 0x22, 0x4c, 0x0a,
|
||||
0x0c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3c, 0x0a,
|
||||
0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e,
|
||||
0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f,
|
||||
0x69, 0x6e, 0x74, 0x52, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x22, 0x7b, 0x0a, 0x0c, 0x53,
|
||||
0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x30, 0x0a, 0x05, 0x75,
|
||||
0x73, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x78, 0x72, 0x61,
|
||||
0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,
|
||||
0x6c, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x12, 0x39, 0x0a,
|
||||
0x09, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b,
|
||||
0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x74, 0x72,
|
||||
0x6f, 0x6a, 0x61, 0x6e, 0x2e, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x09, 0x66,
|
||||
0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x73, 0x42, 0x55, 0x0a, 0x15, 0x63, 0x6f, 0x6d, 0x2e,
|
||||
0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x74, 0x72, 0x6f, 0x6a, 0x61,
|
||||
0x6e, 0x50, 0x01, 0x5a, 0x26, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
|
||||
0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70,
|
||||
0x72, 0x6f, 0x78, 0x79, 0x2f, 0x74, 0x72, 0x6f, 0x6a, 0x61, 0x6e, 0xaa, 0x02, 0x11, 0x58, 0x72,
|
||||
0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x54, 0x72, 0x6f, 0x6a, 0x61, 0x6e, 0x62,
|
||||
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x77, 0x6f, 0x72, 0x64, 0x22, 0x82, 0x01, 0x0a, 0x08, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63,
|
||||
0x6b, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x6c, 0x70, 0x6e, 0x18, 0x02, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x04, 0x61, 0x6c, 0x70, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74,
|
||||
0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x12, 0x0a,
|
||||
0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70,
|
||||
0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x65, 0x73, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x04, 0x64, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x78, 0x76, 0x65, 0x72, 0x18, 0x06, 0x20,
|
||||
0x01, 0x28, 0x04, 0x52, 0x04, 0x78, 0x76, 0x65, 0x72, 0x22, 0x4c, 0x0a, 0x0c, 0x43, 0x6c, 0x69,
|
||||
0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3c, 0x0a, 0x06, 0x73, 0x65, 0x72,
|
||||
0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
||||
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c,
|
||||
0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52,
|
||||
0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x22, 0x7b, 0x0a, 0x0c, 0x53, 0x65, 0x72, 0x76, 0x65,
|
||||
0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x30, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73,
|
||||
0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,
|
||||
0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x55, 0x73,
|
||||
0x65, 0x72, 0x52, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x12, 0x39, 0x0a, 0x09, 0x66, 0x61, 0x6c,
|
||||
0x6c, 0x62, 0x61, 0x63, 0x6b, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x78,
|
||||
0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x74, 0x72, 0x6f, 0x6a, 0x61, 0x6e,
|
||||
0x2e, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x09, 0x66, 0x61, 0x6c, 0x6c, 0x62,
|
||||
0x61, 0x63, 0x6b, 0x73, 0x42, 0x55, 0x0a, 0x15, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
||||
0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x74, 0x72, 0x6f, 0x6a, 0x61, 0x6e, 0x50, 0x01, 0x5a,
|
||||
0x26, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73,
|
||||
0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79,
|
||||
0x2f, 0x74, 0x72, 0x6f, 0x6a, 0x61, 0x6e, 0xaa, 0x02, 0x11, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x50,
|
||||
0x72, 0x6f, 0x78, 0x79, 0x2e, 0x54, 0x72, 0x6f, 0x6a, 0x61, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
|
|
|
@ -11,7 +11,6 @@ import "common/protocol/server_spec.proto";
|
|||
|
||||
message Account {
|
||||
string password = 1;
|
||||
string flow = 2;
|
||||
}
|
||||
|
||||
message Fallback {
|
||||
|
@ -29,5 +28,5 @@ message ClientConfig {
|
|||
|
||||
message ServerConfig {
|
||||
repeated xray.common.protocol.User users = 1;
|
||||
repeated Fallback fallbacks = 3;
|
||||
repeated Fallback fallbacks = 2;
|
||||
}
|
||||
|
|
|
@ -31,7 +31,6 @@ type ConnWriter struct {
|
|||
io.Writer
|
||||
Target net.Destination
|
||||
Account *MemoryAccount
|
||||
Flow string
|
||||
headerSent bool
|
||||
}
|
||||
|
||||
|
|
|
@ -217,10 +217,8 @@ func (s *Server) Process(ctx context.Context, network net.Network, conn stat.Con
|
|||
}
|
||||
|
||||
inbound := session.InboundFromContext(ctx)
|
||||
if inbound == nil {
|
||||
panic("no inbound metadata")
|
||||
}
|
||||
inbound.Name = "trojan"
|
||||
inbound.SetCanSpliceCopy(3)
|
||||
inbound.User = user
|
||||
sessionPolicy = s.policyManager.ForLevel(user.Level)
|
||||
|
||||
|
@ -260,7 +258,7 @@ func (s *Server) Process(ctx context.Context, network net.Network, conn stat.Con
|
|||
})
|
||||
|
||||
newError("received request for ", destination).WriteToLog(sid)
|
||||
return s.handleConnection(ctx, sessionPolicy, destination, clientReader, buf.NewWriter(conn), dispatcher, iConn, statConn)
|
||||
return s.handleConnection(ctx, sessionPolicy, destination, clientReader, buf.NewWriter(conn), dispatcher)
|
||||
}
|
||||
|
||||
func (s *Server) handleUDPPayload(ctx context.Context, clientReader *PacketReader, clientWriter *PacketWriter, dispatcher routing.Dispatcher) error {
|
||||
|
@ -326,7 +324,7 @@ func (s *Server) handleUDPPayload(ctx context.Context, clientReader *PacketReade
|
|||
func (s *Server) handleConnection(ctx context.Context, sessionPolicy policy.Session,
|
||||
destination net.Destination,
|
||||
clientReader buf.Reader,
|
||||
clientWriter buf.Writer, dispatcher routing.Dispatcher, iConn stat.Connection, statConn *stat.CounterConnection,
|
||||
clientWriter buf.Writer, dispatcher routing.Dispatcher,
|
||||
) error {
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
package trojan
|
||||
|
||||
const (
|
||||
muxCoolAddress = "v1.mux.cool"
|
||||
)
|
||||
//go:generate go run github.com/xtls/xray-core/common/errors/errorgen
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
package encoding
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/xtls/xray-core/common/buf"
|
||||
"github.com/xtls/xray-core/common/protocol"
|
||||
"github.com/xtls/xray-core/proxy"
|
||||
"github.com/xtls/xray-core/proxy/vless"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
func EncodeHeaderAddons(buffer *buf.Buffer, addons *Addons) error {
|
||||
|
@ -58,14 +60,19 @@ func DecodeHeaderAddons(buffer *buf.Buffer, reader io.Reader) (*Addons, error) {
|
|||
}
|
||||
|
||||
// EncodeBodyAddons returns a Writer that auto-encrypt content written by caller.
|
||||
func EncodeBodyAddons(writer io.Writer, request *protocol.RequestHeader, addons *Addons) buf.Writer {
|
||||
switch addons.Flow {
|
||||
default:
|
||||
func EncodeBodyAddons(writer io.Writer, request *protocol.RequestHeader, requestAddons *Addons, state *proxy.TrafficState, context context.Context) buf.Writer {
|
||||
if request.Command == protocol.RequestCommandUDP {
|
||||
return NewMultiLengthPacketWriter(writer.(buf.Writer))
|
||||
w := writer.(buf.Writer)
|
||||
if requestAddons.Flow == vless.XRV {
|
||||
w = proxy.NewVisionWriter(w, state, context)
|
||||
}
|
||||
return NewMultiLengthPacketWriter(w)
|
||||
}
|
||||
return buf.NewWriter(writer)
|
||||
w := buf.NewWriter(writer)
|
||||
if requestAddons.Flow == vless.XRV {
|
||||
w = proxy.NewVisionWriter(w, state, context)
|
||||
}
|
||||
return w
|
||||
}
|
||||
|
||||
// DecodeBodyAddons returns a Reader from which caller can fetch decrypted body.
|
||||
|
|
|
@ -5,13 +5,7 @@ package encoding
|
|||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"io"
|
||||
"math/big"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/xtls/xray-core/common/buf"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
|
@ -20,40 +14,14 @@ import (
|
|||
"github.com/xtls/xray-core/common/session"
|
||||
"github.com/xtls/xray-core/common/signal"
|
||||
"github.com/xtls/xray-core/features/stats"
|
||||
"github.com/xtls/xray-core/proxy"
|
||||
"github.com/xtls/xray-core/proxy/vless"
|
||||
"github.com/xtls/xray-core/transport/internet/reality"
|
||||
"github.com/xtls/xray-core/transport/internet/stat"
|
||||
"github.com/xtls/xray-core/transport/internet/tls"
|
||||
)
|
||||
|
||||
const (
|
||||
Version = byte(0)
|
||||
)
|
||||
|
||||
var (
|
||||
tls13SupportedVersions = []byte{0x00, 0x2b, 0x00, 0x02, 0x03, 0x04}
|
||||
tlsClientHandShakeStart = []byte{0x16, 0x03}
|
||||
tlsServerHandShakeStart = []byte{0x16, 0x03, 0x03}
|
||||
tlsApplicationDataStart = []byte{0x17, 0x03, 0x03}
|
||||
|
||||
Tls13CipherSuiteDic = map[uint16]string{
|
||||
0x1301: "TLS_AES_128_GCM_SHA256",
|
||||
0x1302: "TLS_AES_256_GCM_SHA384",
|
||||
0x1303: "TLS_CHACHA20_POLY1305_SHA256",
|
||||
0x1304: "TLS_AES_128_CCM_SHA256",
|
||||
0x1305: "TLS_AES_128_CCM_8_SHA256",
|
||||
}
|
||||
)
|
||||
|
||||
const (
|
||||
tlsHandshakeTypeClientHello byte = 0x01
|
||||
tlsHandshakeTypeServerHello byte = 0x02
|
||||
|
||||
CommandPaddingContinue byte = 0x00
|
||||
CommandPaddingEnd byte = 0x01
|
||||
CommandPaddingDirect byte = 0x02
|
||||
)
|
||||
|
||||
var addrParser = protocol.NewAddressParser(
|
||||
protocol.AddressFamilyByte(byte(protocol.AddressTypeIPv4), net.AddressFamilyIPv4),
|
||||
protocol.AddressFamilyByte(byte(protocol.AddressTypeDomain), net.AddressFamilyDomain),
|
||||
|
@ -206,67 +174,24 @@ func DecodeResponseHeader(reader io.Reader, request *protocol.RequestHeader) (*A
|
|||
}
|
||||
|
||||
// XtlsRead filter and read xtls protocol
|
||||
func XtlsRead(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater, conn net.Conn, rawConn syscall.RawConn,
|
||||
input *bytes.Reader, rawInput *bytes.Buffer,
|
||||
counter stats.Counter, ctx context.Context, userUUID []byte, numberOfPacketToFilter *int, enableXtls *bool,
|
||||
isTLS12orAbove *bool, isTLS *bool, cipher *uint16, remainingServerHello *int32,
|
||||
) error {
|
||||
func XtlsRead(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater, conn net.Conn, input *bytes.Reader, rawInput *bytes.Buffer, trafficState *proxy.TrafficState, ctx context.Context) error {
|
||||
err := func() error {
|
||||
var ct stats.Counter
|
||||
withinPaddingBuffers := true
|
||||
shouldSwitchToDirectCopy := false
|
||||
var remainingContent int32 = -1
|
||||
var remainingPadding int32 = -1
|
||||
currentCommand := 0
|
||||
visionReader := proxy.NewVisionReader(reader, trafficState, ctx)
|
||||
for {
|
||||
if shouldSwitchToDirectCopy {
|
||||
shouldSwitchToDirectCopy = false
|
||||
if inbound := session.InboundFromContext(ctx); inbound != nil && inbound.Conn != nil && (runtime.GOOS == "linux" || runtime.GOOS == "android") {
|
||||
if _, ok := inbound.User.Account.(*vless.MemoryAccount); inbound.User.Account == nil || ok {
|
||||
iConn := inbound.Conn
|
||||
statConn, ok := iConn.(*stat.CounterConnection)
|
||||
if ok {
|
||||
iConn = statConn.Connection
|
||||
}
|
||||
if tlsConn, ok := iConn.(*tls.Conn); ok {
|
||||
iConn = tlsConn.NetConn()
|
||||
} else if realityConn, ok := iConn.(*reality.Conn); ok {
|
||||
iConn = realityConn.NetConn()
|
||||
}
|
||||
if tc, ok := iConn.(*net.TCPConn); ok {
|
||||
newError("XtlsRead splice").WriteToLog(session.ExportIDToError(ctx))
|
||||
runtime.Gosched() // necessary
|
||||
w, err := tc.ReadFrom(conn)
|
||||
if counter != nil {
|
||||
counter.Add(w)
|
||||
}
|
||||
if statConn != nil && statConn.WriteCounter != nil {
|
||||
statConn.WriteCounter.Add(w)
|
||||
}
|
||||
return err
|
||||
if trafficState.ReaderSwitchToDirectCopy {
|
||||
var writerConn net.Conn
|
||||
if inbound := session.InboundFromContext(ctx); inbound != nil && inbound.Conn != nil {
|
||||
writerConn = inbound.Conn
|
||||
if inbound.CanSpliceCopy == 2 {
|
||||
inbound.CanSpliceCopy = 1 // force the value to 1, don't use setter
|
||||
}
|
||||
}
|
||||
return proxy.CopyRawConnIfExist(ctx, conn, writerConn, writer, timer)
|
||||
}
|
||||
if rawConn != nil {
|
||||
reader = buf.NewReadVReader(conn, rawConn, nil)
|
||||
} else {
|
||||
reader = buf.NewReader(conn)
|
||||
}
|
||||
ct = counter
|
||||
newError("XtlsRead readV").WriteToLog(session.ExportIDToError(ctx))
|
||||
}
|
||||
buffer, err := reader.ReadMultiBuffer()
|
||||
buffer, err := visionReader.ReadMultiBuffer()
|
||||
if !buffer.IsEmpty() {
|
||||
if withinPaddingBuffers || *numberOfPacketToFilter > 0 {
|
||||
buffer = XtlsUnpadding(ctx, buffer, userUUID, &remainingContent, &remainingPadding, ¤tCommand)
|
||||
if remainingContent == 0 && remainingPadding == 0 {
|
||||
if currentCommand == 1 {
|
||||
withinPaddingBuffers = false
|
||||
remainingContent = -1
|
||||
remainingPadding = -1 // set to initial state to parse the next padding
|
||||
} else if currentCommand == 2 {
|
||||
withinPaddingBuffers = false
|
||||
shouldSwitchToDirectCopy = true
|
||||
timer.Update()
|
||||
if trafficState.ReaderSwitchToDirectCopy {
|
||||
// XTLS Vision processes struct TLS Conn's input and rawInput
|
||||
if inputBuffer, err := buf.ReadFrom(input); err == nil {
|
||||
if !inputBuffer.IsEmpty() {
|
||||
|
@ -278,24 +203,7 @@ func XtlsRead(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater
|
|||
buffer, _ = buf.MergeMulti(buffer, rawInputBuffer)
|
||||
}
|
||||
}
|
||||
} else if currentCommand == 0 {
|
||||
withinPaddingBuffers = true
|
||||
} else {
|
||||
newError("XtlsRead unknown command ", currentCommand, buffer.Len()).WriteToLog(session.ExportIDToError(ctx))
|
||||
}
|
||||
} else if remainingContent > 0 || remainingPadding > 0 {
|
||||
withinPaddingBuffers = true
|
||||
} else {
|
||||
withinPaddingBuffers = false
|
||||
}
|
||||
}
|
||||
if *numberOfPacketToFilter > 0 {
|
||||
XtlsFilterTls(buffer, numberOfPacketToFilter, enableXtls, isTLS12orAbove, isTLS, cipher, remainingServerHello, ctx)
|
||||
}
|
||||
if ct != nil {
|
||||
ct.Add(int64(buffer.Len()))
|
||||
}
|
||||
timer.Update()
|
||||
if werr := writer.WriteMultiBuffer(buffer); werr != nil {
|
||||
return werr
|
||||
}
|
||||
|
@ -312,56 +220,19 @@ func XtlsRead(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater
|
|||
}
|
||||
|
||||
// XtlsWrite filter and write xtls protocol
|
||||
func XtlsWrite(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater, conn net.Conn, counter stats.Counter,
|
||||
ctx context.Context, numberOfPacketToFilter *int, enableXtls *bool, isTLS12orAbove *bool, isTLS *bool,
|
||||
cipher *uint16, remainingServerHello *int32,
|
||||
) error {
|
||||
func XtlsWrite(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater, conn net.Conn, trafficState *proxy.TrafficState, ctx context.Context) error {
|
||||
err := func() error {
|
||||
var ct stats.Counter
|
||||
isPadding := true
|
||||
shouldSwitchToDirectCopy := false
|
||||
for {
|
||||
buffer, err := reader.ReadMultiBuffer()
|
||||
if !buffer.IsEmpty() {
|
||||
if *numberOfPacketToFilter > 0 {
|
||||
XtlsFilterTls(buffer, numberOfPacketToFilter, enableXtls, isTLS12orAbove, isTLS, cipher, remainingServerHello, ctx)
|
||||
}
|
||||
if isPadding {
|
||||
buffer = ReshapeMultiBuffer(ctx, buffer)
|
||||
var xtlsSpecIndex int
|
||||
for i, b := range buffer {
|
||||
if *isTLS && b.Len() >= 6 && bytes.Equal(tlsApplicationDataStart, b.BytesTo(3)) {
|
||||
var command byte = CommandPaddingEnd
|
||||
if *enableXtls {
|
||||
shouldSwitchToDirectCopy = true
|
||||
xtlsSpecIndex = i
|
||||
command = CommandPaddingDirect
|
||||
}
|
||||
isPadding = false
|
||||
buffer[i] = XtlsPadding(b, command, nil, *isTLS, ctx)
|
||||
break
|
||||
} else if !*isTLS12orAbove && *numberOfPacketToFilter <= 1 { // For compatibility with earlier vision receiver, we finish padding 1 packet early
|
||||
isPadding = false
|
||||
buffer[i] = XtlsPadding(b, CommandPaddingEnd, nil, *isTLS, ctx)
|
||||
break
|
||||
}
|
||||
buffer[i] = XtlsPadding(b, CommandPaddingContinue, nil, *isTLS, ctx)
|
||||
}
|
||||
if shouldSwitchToDirectCopy {
|
||||
encryptBuffer, directBuffer := buf.SplitMulti(buffer, xtlsSpecIndex+1)
|
||||
length := encryptBuffer.Len()
|
||||
if !encryptBuffer.IsEmpty() {
|
||||
timer.Update()
|
||||
if werr := writer.WriteMultiBuffer(encryptBuffer); werr != nil {
|
||||
return werr
|
||||
}
|
||||
}
|
||||
buffer = directBuffer
|
||||
writer = buf.NewWriter(conn)
|
||||
ct = counter
|
||||
newError("XtlsWrite writeV ", xtlsSpecIndex, " ", length, " ", buffer.Len()).WriteToLog(session.ExportIDToError(ctx))
|
||||
time.Sleep(5 * time.Millisecond) // for some device, the first xtls direct packet fails without this delay
|
||||
if trafficState.WriterSwitchToDirectCopy {
|
||||
if inbound := session.InboundFromContext(ctx); inbound != nil && inbound.CanSpliceCopy == 2 {
|
||||
inbound.CanSpliceCopy = 1 // force the value to 1, don't use setter
|
||||
}
|
||||
rawConn, _, writerCounter := proxy.UnwrapRawConn(conn)
|
||||
writer = buf.NewWriter(rawConn)
|
||||
ct = writerCounter
|
||||
trafficState.WriterSwitchToDirectCopy = false
|
||||
}
|
||||
if !buffer.IsEmpty() {
|
||||
if ct != nil {
|
||||
|
@ -372,7 +243,6 @@ func XtlsWrite(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdate
|
|||
return werr
|
||||
}
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -383,201 +253,3 @@ func XtlsWrite(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdate
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// XtlsFilterTls filter and recognize tls 1.3 and other info
|
||||
func XtlsFilterTls(buffer buf.MultiBuffer, numberOfPacketToFilter *int, enableXtls *bool, isTLS12orAbove *bool, isTLS *bool,
|
||||
cipher *uint16, remainingServerHello *int32, ctx context.Context,
|
||||
) {
|
||||
for _, b := range buffer {
|
||||
*numberOfPacketToFilter--
|
||||
if b.Len() >= 6 {
|
||||
startsBytes := b.BytesTo(6)
|
||||
if bytes.Equal(tlsServerHandShakeStart, startsBytes[:3]) && startsBytes[5] == tlsHandshakeTypeServerHello {
|
||||
*remainingServerHello = (int32(startsBytes[3])<<8 | int32(startsBytes[4])) + 5
|
||||
*isTLS12orAbove = true
|
||||
*isTLS = true
|
||||
if b.Len() >= 79 && *remainingServerHello >= 79 {
|
||||
sessionIdLen := int32(b.Byte(43))
|
||||
cipherSuite := b.BytesRange(43+sessionIdLen+1, 43+sessionIdLen+3)
|
||||
*cipher = uint16(cipherSuite[0])<<8 | uint16(cipherSuite[1])
|
||||
} else {
|
||||
newError("XtlsFilterTls short server hello, tls 1.2 or older? ", b.Len(), " ", *remainingServerHello).WriteToLog(session.ExportIDToError(ctx))
|
||||
}
|
||||
} else if bytes.Equal(tlsClientHandShakeStart, startsBytes[:2]) && startsBytes[5] == tlsHandshakeTypeClientHello {
|
||||
*isTLS = true
|
||||
newError("XtlsFilterTls found tls client hello! ", buffer.Len()).WriteToLog(session.ExportIDToError(ctx))
|
||||
}
|
||||
}
|
||||
if *remainingServerHello > 0 {
|
||||
end := *remainingServerHello
|
||||
if end > b.Len() {
|
||||
end = b.Len()
|
||||
}
|
||||
*remainingServerHello -= b.Len()
|
||||
if bytes.Contains(b.BytesTo(end), tls13SupportedVersions) {
|
||||
v, ok := Tls13CipherSuiteDic[*cipher]
|
||||
if !ok {
|
||||
v = "Old cipher: " + strconv.FormatUint(uint64(*cipher), 16)
|
||||
} else if v != "TLS_AES_128_CCM_8_SHA256" {
|
||||
*enableXtls = true
|
||||
}
|
||||
newError("XtlsFilterTls found tls 1.3! ", b.Len(), " ", v).WriteToLog(session.ExportIDToError(ctx))
|
||||
*numberOfPacketToFilter = 0
|
||||
return
|
||||
} else if *remainingServerHello <= 0 {
|
||||
newError("XtlsFilterTls found tls 1.2! ", b.Len()).WriteToLog(session.ExportIDToError(ctx))
|
||||
*numberOfPacketToFilter = 0
|
||||
return
|
||||
}
|
||||
newError("XtlsFilterTls inconclusive server hello ", b.Len(), " ", *remainingServerHello).WriteToLog(session.ExportIDToError(ctx))
|
||||
}
|
||||
if *numberOfPacketToFilter <= 0 {
|
||||
newError("XtlsFilterTls stop filtering", buffer.Len()).WriteToLog(session.ExportIDToError(ctx))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ReshapeMultiBuffer prepare multi buffer for padding stucture (max 21 bytes)
|
||||
func ReshapeMultiBuffer(ctx context.Context, buffer buf.MultiBuffer) buf.MultiBuffer {
|
||||
needReshape := 0
|
||||
for _, b := range buffer {
|
||||
if b.Len() >= buf.Size-21 {
|
||||
needReshape += 1
|
||||
}
|
||||
}
|
||||
if needReshape == 0 {
|
||||
return buffer
|
||||
}
|
||||
mb2 := make(buf.MultiBuffer, 0, len(buffer)+needReshape)
|
||||
toPrint := ""
|
||||
for i, buffer1 := range buffer {
|
||||
if buffer1.Len() >= buf.Size-21 {
|
||||
index := int32(bytes.LastIndex(buffer1.Bytes(), tlsApplicationDataStart))
|
||||
if index <= 0 || index > buf.Size-21 {
|
||||
index = buf.Size / 2
|
||||
}
|
||||
buffer2 := buf.New()
|
||||
buffer2.Write(buffer1.BytesFrom(index))
|
||||
buffer1.Resize(0, index)
|
||||
mb2 = append(mb2, buffer1, buffer2)
|
||||
toPrint += " " + strconv.Itoa(int(buffer1.Len())) + " " + strconv.Itoa(int(buffer2.Len()))
|
||||
} else {
|
||||
mb2 = append(mb2, buffer1)
|
||||
toPrint += " " + strconv.Itoa(int(buffer1.Len()))
|
||||
}
|
||||
buffer[i] = nil
|
||||
}
|
||||
buffer = buffer[:0]
|
||||
newError("ReshapeMultiBuffer ", toPrint).WriteToLog(session.ExportIDToError(ctx))
|
||||
return mb2
|
||||
}
|
||||
|
||||
// XtlsPadding add padding to eliminate length siganature during tls handshake
|
||||
func XtlsPadding(b *buf.Buffer, command byte, userUUID *[]byte, longPadding bool, ctx context.Context) *buf.Buffer {
|
||||
var contentLen int32 = 0
|
||||
var paddingLen int32 = 0
|
||||
if b != nil {
|
||||
contentLen = b.Len()
|
||||
}
|
||||
if contentLen < 900 && longPadding {
|
||||
l, err := rand.Int(rand.Reader, big.NewInt(500))
|
||||
if err != nil {
|
||||
newError("failed to generate padding").Base(err).WriteToLog(session.ExportIDToError(ctx))
|
||||
}
|
||||
paddingLen = int32(l.Int64()) + 900 - contentLen
|
||||
} else {
|
||||
l, err := rand.Int(rand.Reader, big.NewInt(256))
|
||||
if err != nil {
|
||||
newError("failed to generate padding").Base(err).WriteToLog(session.ExportIDToError(ctx))
|
||||
}
|
||||
paddingLen = int32(l.Int64())
|
||||
}
|
||||
if paddingLen > buf.Size-21-contentLen {
|
||||
paddingLen = buf.Size - 21 - contentLen
|
||||
}
|
||||
newbuffer := buf.New()
|
||||
if userUUID != nil {
|
||||
newbuffer.Write(*userUUID)
|
||||
*userUUID = nil
|
||||
}
|
||||
newbuffer.Write([]byte{command, byte(contentLen >> 8), byte(contentLen), byte(paddingLen >> 8), byte(paddingLen)})
|
||||
if b != nil {
|
||||
newbuffer.Write(b.Bytes())
|
||||
b.Release()
|
||||
b = nil
|
||||
}
|
||||
newbuffer.Extend(paddingLen)
|
||||
newError("XtlsPadding ", contentLen, " ", paddingLen, " ", command).WriteToLog(session.ExportIDToError(ctx))
|
||||
return newbuffer
|
||||
}
|
||||
|
||||
// XtlsUnpadding remove padding and parse command
|
||||
func XtlsUnpadding(ctx context.Context, buffer buf.MultiBuffer, userUUID []byte, remainingContent *int32, remainingPadding *int32, currentCommand *int) buf.MultiBuffer {
|
||||
posindex := 0
|
||||
var posByte int32 = 0
|
||||
if *remainingContent == -1 && *remainingPadding == -1 {
|
||||
for i, b := range buffer {
|
||||
if b.Len() >= 21 && bytes.Equal(userUUID, b.BytesTo(16)) {
|
||||
posindex = i
|
||||
posByte = 16
|
||||
*remainingContent = 0
|
||||
*remainingPadding = 0
|
||||
*currentCommand = 0
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if *remainingContent == -1 && *remainingPadding == -1 {
|
||||
return buffer
|
||||
}
|
||||
mb2 := make(buf.MultiBuffer, 0, len(buffer))
|
||||
for i := 0; i < posindex; i++ {
|
||||
newbuffer := buf.New()
|
||||
newbuffer.Write(buffer[i].Bytes())
|
||||
mb2 = append(mb2, newbuffer)
|
||||
}
|
||||
for i := posindex; i < len(buffer); i++ {
|
||||
b := buffer[i]
|
||||
for posByte < b.Len() {
|
||||
if *remainingContent <= 0 && *remainingPadding <= 0 {
|
||||
if *currentCommand == 1 { // possible buffer after padding, no need to worry about xtls (command 2)
|
||||
len := b.Len() - posByte
|
||||
newbuffer := buf.New()
|
||||
newbuffer.Write(b.BytesRange(posByte, posByte+len))
|
||||
mb2 = append(mb2, newbuffer)
|
||||
posByte += len
|
||||
} else {
|
||||
paddingInfo := b.BytesRange(posByte, posByte+5)
|
||||
*currentCommand = int(paddingInfo[0])
|
||||
*remainingContent = int32(paddingInfo[1])<<8 | int32(paddingInfo[2])
|
||||
*remainingPadding = int32(paddingInfo[3])<<8 | int32(paddingInfo[4])
|
||||
newError("Xtls Unpadding new block", i, " ", posByte, " content ", *remainingContent, " padding ", *remainingPadding, " ", paddingInfo[0]).WriteToLog(session.ExportIDToError(ctx))
|
||||
posByte += 5
|
||||
}
|
||||
} else if *remainingContent > 0 {
|
||||
len := *remainingContent
|
||||
if b.Len() < posByte+*remainingContent {
|
||||
len = b.Len() - posByte
|
||||
}
|
||||
newbuffer := buf.New()
|
||||
newbuffer.Write(b.BytesRange(posByte, posByte+len))
|
||||
mb2 = append(mb2, newbuffer)
|
||||
*remainingContent -= len
|
||||
posByte += len
|
||||
} else { // remainingPadding > 0
|
||||
len := *remainingPadding
|
||||
if b.Len() < posByte+*remainingPadding {
|
||||
len = b.Len() - posByte
|
||||
}
|
||||
*remainingPadding -= len
|
||||
posByte += len
|
||||
}
|
||||
if posByte == b.Len() {
|
||||
posByte = 0
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
buf.ReleaseMulti(buffer)
|
||||
return mb2
|
||||
}
|
||||
|
|
|
@ -11,11 +11,9 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/pires/go-proxyproto"
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/buf"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
|
@ -31,7 +29,7 @@ import (
|
|||
feature_inbound "github.com/xtls/xray-core/features/inbound"
|
||||
"github.com/xtls/xray-core/features/policy"
|
||||
"github.com/xtls/xray-core/features/routing"
|
||||
"github.com/xtls/xray-core/features/stats"
|
||||
"github.com/xtls/xray-core/proxy"
|
||||
"github.com/xtls/xray-core/proxy/vless"
|
||||
"github.com/xtls/xray-core/proxy/vless/encoding"
|
||||
"github.com/xtls/xray-core/transport/internet/reality"
|
||||
|
@ -185,8 +183,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||
sid := session.ExportIDToError(ctx)
|
||||
|
||||
iConn := connection
|
||||
statConn, ok := iConn.(*stat.CounterConnection)
|
||||
if ok {
|
||||
if statConn, ok := iConn.(*stat.CounterConnection); ok {
|
||||
iConn = statConn.Connection
|
||||
}
|
||||
|
||||
|
@ -473,14 +470,35 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||
connIp.Time = time.Now().Unix()
|
||||
}
|
||||
|
||||
var netConn net.Conn
|
||||
var rawConn syscall.RawConn
|
||||
if (request.User.IpLimit > 0) {
|
||||
addr := connection.RemoteAddr().(*net.TCPAddr)
|
||||
|
||||
uniqueIps := make(map[string]bool)
|
||||
|
||||
h.Lock()
|
||||
// Iterate through the connections and find unique used IP addresses withing last 30 seconds.
|
||||
for _, conn := range *usrIpRstrct {
|
||||
if conn.User == request.User.Email && !conn.IpAddress.Equal(addr.IP) && ((time.Now().Unix() - conn.Time) < 30) {
|
||||
uniqueIps[conn.IpAddress.String()] = true
|
||||
}
|
||||
}
|
||||
h.Unlock()
|
||||
|
||||
if (len(uniqueIps) >= int(request.User.IpLimit)) {
|
||||
return newError("User ", request.User.Email, " has exceeded their allowed IPs.").AtWarning()
|
||||
}
|
||||
|
||||
connIp.IpAddress = addr.IP
|
||||
connIp.User = request.User.Email
|
||||
connIp.Time = time.Now().Unix()
|
||||
}
|
||||
|
||||
var input *bytes.Reader
|
||||
var rawInput *bytes.Buffer
|
||||
|
||||
switch requestAddons.Flow {
|
||||
case vless.XRV:
|
||||
if account.Flow == requestAddons.Flow {
|
||||
inbound.SetCanSpliceCopy(2)
|
||||
switch request.Command {
|
||||
case protocol.RequestCommandUDP:
|
||||
return newError(requestAddons.Flow + " doesn't support UDP").AtWarning()
|
||||
|
@ -493,23 +511,14 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||
if tlsConn.ConnectionState().Version != gotls.VersionTLS13 {
|
||||
return newError(`failed to use `+requestAddons.Flow+`, found outer tls version `, tlsConn.ConnectionState().Version).AtWarning()
|
||||
}
|
||||
netConn = tlsConn.NetConn()
|
||||
t = reflect.TypeOf(tlsConn.Conn).Elem()
|
||||
p = uintptr(unsafe.Pointer(tlsConn.Conn))
|
||||
} else if realityConn, ok := iConn.(*reality.Conn); ok {
|
||||
netConn = realityConn.NetConn()
|
||||
t = reflect.TypeOf(realityConn.Conn).Elem()
|
||||
p = uintptr(unsafe.Pointer(realityConn.Conn))
|
||||
} else {
|
||||
return newError("XTLS only supports TLS and REALITY directly for now.").AtWarning()
|
||||
}
|
||||
if pc, ok := netConn.(*proxyproto.Conn); ok {
|
||||
netConn = pc.Raw()
|
||||
// 8192 > 4096, there is no need to process pc's bufReader
|
||||
}
|
||||
if sc, ok := netConn.(syscall.Conn); ok {
|
||||
rawConn, _ = sc.SyscallConn()
|
||||
}
|
||||
i, _ := t.FieldByName("input")
|
||||
r, _ := t.FieldByName("rawInput")
|
||||
input = (*bytes.Reader)(unsafe.Pointer(p + i.Offset))
|
||||
|
@ -519,6 +528,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||
return newError(account.ID.String() + " is not able to use " + requestAddons.Flow).AtWarning()
|
||||
}
|
||||
case "":
|
||||
inbound.SetCanSpliceCopy(3)
|
||||
if account.Flow == vless.XRV && (request.Command == protocol.RequestCommandTCP || isMuxAndNotXUDP(request, first)) {
|
||||
return newError(account.ID.String() + " is not able to use \"\". Note that the pure TLS proxy has certain TLS in TLS characters.").AtWarning()
|
||||
}
|
||||
|
@ -550,13 +560,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||
|
||||
serverReader := link.Reader // .(*pipe.Reader)
|
||||
serverWriter := link.Writer // .(*pipe.Writer)
|
||||
enableXtls := false
|
||||
isTLS12orAbove := false
|
||||
isTLS := false
|
||||
var cipher uint16 = 0
|
||||
var remainingServerHello int32 = -1
|
||||
numberOfPacketToFilter := 8
|
||||
|
||||
trafficState := proxy.NewTrafficState(account.ID.Bytes())
|
||||
postRequest := func() error {
|
||||
defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
|
||||
|
||||
|
@ -566,14 +570,8 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||
var err error
|
||||
|
||||
if requestAddons.Flow == vless.XRV {
|
||||
var counter stats.Counter
|
||||
if statConn != nil {
|
||||
counter = statConn.ReadCounter
|
||||
}
|
||||
// TODO enable splice
|
||||
ctx = session.ContextWithInbound(ctx, nil)
|
||||
err = encoding.XtlsRead(clientReader, serverWriter, timer, netConn, rawConn, input, rawInput, counter, ctx, account.ID.Bytes(),
|
||||
&numberOfPacketToFilter, &enableXtls, &isTLS12orAbove, &isTLS, &cipher, &remainingServerHello)
|
||||
ctx1 := session.ContextWithInbound(ctx, nil) // TODO enable splice
|
||||
err = encoding.XtlsRead(clientReader, serverWriter, timer, connection, input, rawInput, trafficState, ctx1)
|
||||
} else {
|
||||
// from clientReader.ReadMultiBuffer to serverWriter.WriteMultiBufer
|
||||
err = buf.Copy(clientReader, serverWriter, buf.UpdateActivity(timer))
|
||||
|
@ -595,19 +593,11 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||
}
|
||||
|
||||
// default: clientWriter := bufferWriter
|
||||
clientWriter := encoding.EncodeBodyAddons(bufferWriter, request, responseAddons)
|
||||
userUUID := account.ID.Bytes()
|
||||
clientWriter := encoding.EncodeBodyAddons(bufferWriter, request, requestAddons, trafficState, ctx)
|
||||
multiBuffer, err1 := serverReader.ReadMultiBuffer()
|
||||
if err1 != nil {
|
||||
return err1 // ...
|
||||
}
|
||||
if requestAddons.Flow == vless.XRV {
|
||||
encoding.XtlsFilterTls(multiBuffer, &numberOfPacketToFilter, &enableXtls, &isTLS12orAbove, &isTLS, &cipher, &remainingServerHello, ctx)
|
||||
multiBuffer = encoding.ReshapeMultiBuffer(ctx, multiBuffer)
|
||||
for i, b := range multiBuffer {
|
||||
multiBuffer[i] = encoding.XtlsPadding(b, encoding.CommandPaddingContinue, &userUUID, isTLS, ctx)
|
||||
}
|
||||
}
|
||||
if err := clientWriter.WriteMultiBuffer(multiBuffer); err != nil {
|
||||
return err // ...
|
||||
}
|
||||
|
@ -618,12 +608,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||
|
||||
var err error
|
||||
if requestAddons.Flow == vless.XRV {
|
||||
var counter stats.Counter
|
||||
if statConn != nil {
|
||||
counter = statConn.WriteCounter
|
||||
}
|
||||
err = encoding.XtlsWrite(serverReader, clientWriter, timer, netConn, counter, ctx, &numberOfPacketToFilter,
|
||||
&enableXtls, &isTLS12orAbove, &isTLS, &cipher, &remainingServerHello)
|
||||
err = encoding.XtlsWrite(serverReader, clientWriter, timer, connection, trafficState, ctx)
|
||||
} else {
|
||||
// from serverReader.ReadMultiBuffer to clientWriter.WriteMultiBufer
|
||||
err = buf.Copy(serverReader, clientWriter, buf.UpdateActivity(timer))
|
||||
|
|
|
@ -7,7 +7,6 @@ import (
|
|||
"context"
|
||||
gotls "crypto/tls"
|
||||
"reflect"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
|
@ -23,7 +22,7 @@ import (
|
|||
"github.com/xtls/xray-core/common/xudp"
|
||||
"github.com/xtls/xray-core/core"
|
||||
"github.com/xtls/xray-core/features/policy"
|
||||
"github.com/xtls/xray-core/features/stats"
|
||||
"github.com/xtls/xray-core/proxy"
|
||||
"github.com/xtls/xray-core/proxy/vless"
|
||||
"github.com/xtls/xray-core/proxy/vless/encoding"
|
||||
"github.com/xtls/xray-core/transport"
|
||||
|
@ -71,9 +70,15 @@ func New(ctx context.Context, config *Config) (*Handler, error) {
|
|||
|
||||
// Process implements proxy.Outbound.Process().
|
||||
func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error {
|
||||
outbound := session.OutboundFromContext(ctx)
|
||||
if outbound == nil || !outbound.Target.IsValid() {
|
||||
return newError("target not specified").AtError()
|
||||
}
|
||||
outbound.Name = "vless"
|
||||
inbound := session.InboundFromContext(ctx)
|
||||
|
||||
var rec *protocol.ServerSpec
|
||||
var conn stat.Connection
|
||||
|
||||
if err := retry.ExponentialBackoff(5, 200).On(func() error {
|
||||
rec = h.serverPicker.PickServer()
|
||||
var err error
|
||||
|
@ -88,16 +93,9 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||
defer conn.Close()
|
||||
|
||||
iConn := conn
|
||||
statConn, ok := iConn.(*stat.CounterConnection)
|
||||
if ok {
|
||||
if statConn, ok := iConn.(*stat.CounterConnection); ok {
|
||||
iConn = statConn.Connection
|
||||
}
|
||||
|
||||
outbound := session.OutboundFromContext(ctx)
|
||||
if outbound == nil || !outbound.Target.IsValid() {
|
||||
return newError("target not specified").AtError()
|
||||
}
|
||||
|
||||
target := outbound.Target
|
||||
newError("tunneling request to ", target, " via ", rec.Destination().NetAddr()).AtInfo().WriteToLog(session.ExportIDToError(ctx))
|
||||
|
||||
|
@ -123,8 +121,6 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||
Flow: account.Flow,
|
||||
}
|
||||
|
||||
var netConn net.Conn
|
||||
var rawConn syscall.RawConn
|
||||
var input *bytes.Reader
|
||||
var rawInput *bytes.Buffer
|
||||
allowUDP443 := false
|
||||
|
@ -134,6 +130,9 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||
requestAddons.Flow = requestAddons.Flow[:16]
|
||||
fallthrough
|
||||
case vless.XRV:
|
||||
if inbound != nil {
|
||||
inbound.SetCanSpliceCopy(2)
|
||||
}
|
||||
switch request.Command {
|
||||
case protocol.RequestCommandUDP:
|
||||
if !allowUDP443 && request.Port == 443 {
|
||||
|
@ -146,28 +145,26 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||
var t reflect.Type
|
||||
var p uintptr
|
||||
if tlsConn, ok := iConn.(*tls.Conn); ok {
|
||||
netConn = tlsConn.NetConn()
|
||||
t = reflect.TypeOf(tlsConn.Conn).Elem()
|
||||
p = uintptr(unsafe.Pointer(tlsConn.Conn))
|
||||
} else if utlsConn, ok := iConn.(*tls.UConn); ok {
|
||||
netConn = utlsConn.NetConn()
|
||||
t = reflect.TypeOf(utlsConn.Conn).Elem()
|
||||
p = uintptr(unsafe.Pointer(utlsConn.Conn))
|
||||
} else if realityConn, ok := iConn.(*reality.UConn); ok {
|
||||
netConn = realityConn.NetConn()
|
||||
t = reflect.TypeOf(realityConn.Conn).Elem()
|
||||
p = uintptr(unsafe.Pointer(realityConn.Conn))
|
||||
} else {
|
||||
return newError("XTLS only supports TLS and REALITY directly for now.").AtWarning()
|
||||
}
|
||||
if sc, ok := netConn.(syscall.Conn); ok {
|
||||
rawConn, _ = sc.SyscallConn()
|
||||
}
|
||||
i, _ := t.FieldByName("input")
|
||||
r, _ := t.FieldByName("rawInput")
|
||||
input = (*bytes.Reader)(unsafe.Pointer(p + i.Offset))
|
||||
rawInput = (*bytes.Buffer)(unsafe.Pointer(p + r.Offset))
|
||||
}
|
||||
default:
|
||||
if inbound != nil {
|
||||
inbound.SetCanSpliceCopy(3)
|
||||
}
|
||||
}
|
||||
|
||||
var newCtx context.Context
|
||||
|
@ -187,13 +184,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||
|
||||
clientReader := link.Reader // .(*pipe.Reader)
|
||||
clientWriter := link.Writer // .(*pipe.Writer)
|
||||
enableXtls := false
|
||||
isTLS12orAbove := false
|
||||
isTLS := false
|
||||
var cipher uint16 = 0
|
||||
var remainingServerHello int32 = -1
|
||||
numberOfPacketToFilter := 8
|
||||
|
||||
trafficState := proxy.NewTrafficState(account.ID.Bytes())
|
||||
if request.Command == protocol.RequestCommandUDP && h.cone && request.Port != 53 && request.Port != 443 {
|
||||
request.Command = protocol.RequestCommandMux
|
||||
request.Address = net.DomainAddress("v1.mux.cool")
|
||||
|
@ -209,22 +200,14 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||
}
|
||||
|
||||
// default: serverWriter := bufferWriter
|
||||
serverWriter := encoding.EncodeBodyAddons(bufferWriter, request, requestAddons)
|
||||
serverWriter := encoding.EncodeBodyAddons(bufferWriter, request, requestAddons, trafficState, ctx)
|
||||
if request.Command == protocol.RequestCommandMux && request.Port == 666 {
|
||||
serverWriter = xudp.NewPacketWriter(serverWriter, target, xudp.GetGlobalID(ctx))
|
||||
}
|
||||
userUUID := account.ID.Bytes()
|
||||
timeoutReader, ok := clientReader.(buf.TimeoutReader)
|
||||
if ok {
|
||||
multiBuffer, err1 := timeoutReader.ReadMultiBufferTimeout(time.Millisecond * 500)
|
||||
if err1 == nil {
|
||||
if requestAddons.Flow == vless.XRV {
|
||||
encoding.XtlsFilterTls(multiBuffer, &numberOfPacketToFilter, &enableXtls, &isTLS12orAbove, &isTLS, &cipher, &remainingServerHello, ctx)
|
||||
multiBuffer = encoding.ReshapeMultiBuffer(ctx, multiBuffer)
|
||||
for i, b := range multiBuffer {
|
||||
multiBuffer[i] = encoding.XtlsPadding(b, encoding.CommandPaddingContinue, &userUUID, isTLS, ctx)
|
||||
}
|
||||
}
|
||||
if err := serverWriter.WriteMultiBuffer(multiBuffer); err != nil {
|
||||
return err // ...
|
||||
}
|
||||
|
@ -232,10 +215,9 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||
return err1
|
||||
} else if requestAddons.Flow == vless.XRV {
|
||||
mb := make(buf.MultiBuffer, 1)
|
||||
mb[0] = encoding.XtlsPadding(nil, encoding.CommandPaddingContinue, &userUUID, true, ctx) // we do a long padding to hide vless header
|
||||
newError("Insert padding with empty content to camouflage VLESS header ", mb.Len()).WriteToLog(session.ExportIDToError(ctx))
|
||||
if err := serverWriter.WriteMultiBuffer(mb); err != nil {
|
||||
return err
|
||||
return err // ...
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -257,12 +239,8 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||
return newError(`failed to use `+requestAddons.Flow+`, found outer tls version `, utlsConn.ConnectionState().Version).AtWarning()
|
||||
}
|
||||
}
|
||||
var counter stats.Counter
|
||||
if statConn != nil {
|
||||
counter = statConn.WriteCounter
|
||||
}
|
||||
err = encoding.XtlsWrite(clientReader, serverWriter, timer, netConn, counter, ctx, &numberOfPacketToFilter,
|
||||
&enableXtls, &isTLS12orAbove, &isTLS, &cipher, &remainingServerHello)
|
||||
ctx1 := session.ContextWithOutbound(ctx, nil) // TODO enable splice
|
||||
err = encoding.XtlsWrite(clientReader, serverWriter, timer, conn, trafficState, ctx1)
|
||||
} else {
|
||||
// from clientReader.ReadMultiBuffer to serverWriter.WriteMultiBufer
|
||||
err = buf.Copy(clientReader, serverWriter, buf.UpdateActivity(timer))
|
||||
|
@ -293,12 +271,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||
}
|
||||
|
||||
if requestAddons.Flow == vless.XRV {
|
||||
var counter stats.Counter
|
||||
if statConn != nil {
|
||||
counter = statConn.ReadCounter
|
||||
}
|
||||
err = encoding.XtlsRead(serverReader, clientWriter, timer, netConn, rawConn, input, rawInput, counter, ctx, account.ID.Bytes(),
|
||||
&numberOfPacketToFilter, &enableXtls, &isTLS12orAbove, &isTLS, &cipher, &remainingServerHello)
|
||||
err = encoding.XtlsRead(serverReader, clientWriter, timer, conn, input, rawInput, trafficState, ctx)
|
||||
} else {
|
||||
// from serverReader.ReadMultiBuffer to clientWriter.WriteMultiBufer
|
||||
err = buf.Copy(serverReader, clientWriter, buf.UpdateActivity(timer))
|
||||
|
|
|
@ -258,10 +258,8 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||
}
|
||||
|
||||
inbound := session.InboundFromContext(ctx)
|
||||
if inbound == nil {
|
||||
panic("no inbound metadata")
|
||||
}
|
||||
inbound.Name = "vmess"
|
||||
inbound.SetCanSpliceCopy(3)
|
||||
inbound.User = request.User
|
||||
|
||||
sessionPolicy = h.policyManager.ForLevel(request.User.Level)
|
||||
|
|
|
@ -60,9 +60,18 @@ func New(ctx context.Context, config *Config) (*Handler, error) {
|
|||
|
||||
// Process implements proxy.Outbound.Process().
|
||||
func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error {
|
||||
outbound := session.OutboundFromContext(ctx)
|
||||
if outbound == nil || !outbound.Target.IsValid() {
|
||||
return newError("target not specified").AtError()
|
||||
}
|
||||
outbound.Name = "vmess"
|
||||
inbound := session.InboundFromContext(ctx)
|
||||
if inbound != nil {
|
||||
inbound.SetCanSpliceCopy(3)
|
||||
}
|
||||
|
||||
var rec *protocol.ServerSpec
|
||||
var conn stat.Connection
|
||||
|
||||
err := retry.ExponentialBackoff(5, 200).On(func() error {
|
||||
rec = h.serverPicker.PickServer()
|
||||
rawConn, err := dialer.Dial(ctx, rec.Destination())
|
||||
|
@ -78,11 +87,6 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||
}
|
||||
defer conn.Close()
|
||||
|
||||
outbound := session.OutboundFromContext(ctx)
|
||||
if outbound == nil || !outbound.Target.IsValid() {
|
||||
return newError("target not specified").AtError()
|
||||
}
|
||||
|
||||
target := outbound.Target
|
||||
newError("tunneling request to ", target, " via ", rec.Destination().NetAddr()).WriteToLog(session.ExportIDToError(ctx))
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue