mirror of
https://github.com/XTLS/Xray-core.git
synced 2025-08-23 10:06:48 +08:00
Compare commits
22 Commits
v1.5.0
...
features-l
Author | SHA1 | Date | |
---|---|---|---|
![]() |
e14a4dc10b | ||
![]() |
ab3b0f843d | ||
![]() |
98050aaf02 | ||
![]() |
7cf30d5101 | ||
![]() |
598e15aed2 | ||
![]() |
708ce026ca | ||
![]() |
217844cc37 | ||
![]() |
f20c445974 | ||
![]() |
6e902b24ae | ||
![]() |
70b63e21a5 | ||
![]() |
726a722019 | ||
![]() |
f4a048aa0c | ||
![]() |
90c81e8459 | ||
![]() |
364086c974 | ||
![]() |
7a778d74d0 | ||
![]() |
d3533abe3c | ||
![]() |
58daa2f788 | ||
![]() |
8382b29922 | ||
![]() |
41d3f31447 | ||
![]() |
9b93b90fa9 | ||
![]() |
b15fffaac6 | ||
![]() |
8884e948fe |
1
.github/build/friendly-filenames.json
vendored
1
.github/build/friendly-filenames.json
vendored
@@ -29,6 +29,5 @@
|
||||
"openbsd-arm7": { "friendlyName": "openbsd-arm32-v7a" },
|
||||
"windows-386": { "friendlyName": "windows-32" },
|
||||
"windows-amd64": { "friendlyName": "windows-64" },
|
||||
"windows-arm64": { "friendlyName": "windows-arm64-v8a" },
|
||||
"windows-arm7": { "friendlyName": "windows-arm32-v7a" }
|
||||
}
|
11
.github/dependabot.yml
vendored
11
.github/dependabot.yml
vendored
@@ -1,11 +0,0 @@
|
||||
# To get started with Dependabot version updates, you'll need to specify which
|
||||
# package ecosystems to update and where the package manifests are located.
|
||||
# Please see the documentation for all configuration options:
|
||||
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
||||
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "gomod"
|
||||
directory: "/" # Location of package manifests
|
||||
schedule:
|
||||
interval: "daily"
|
6
.github/workflows/release.yml
vendored
6
.github/workflows/release.yml
vendored
@@ -52,9 +52,7 @@ jobs:
|
||||
- goos: android
|
||||
goarch: arm64
|
||||
# END Android ARM 8
|
||||
# Windows ARM
|
||||
- goos: windows
|
||||
goarch: arm64
|
||||
# Windows ARM 7
|
||||
- goos: windows
|
||||
goarch: arm
|
||||
goarm: 7
|
||||
@@ -123,7 +121,7 @@ jobs:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ^1.17.2
|
||||
go-version: ^1.16
|
||||
|
||||
- name: Get project dependencies
|
||||
run: go mod download
|
||||
|
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
@@ -28,7 +28,7 @@ jobs:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ^1.17.2
|
||||
go-version: ^1.16
|
||||
- name: Checkout codebase
|
||||
uses: actions/checkout@v2
|
||||
|
||||
|
@@ -40,16 +40,13 @@
|
||||
- [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)
|
||||
- [Qv2ray](https://github.com/Qv2ray/Qv2ray) (This project had been archived and currently inactive)
|
||||
- [Qv2ray](https://github.com/Qv2ray/Qv2ray)
|
||||
- [Netch (NetFilter & TUN/TAP)](https://github.com/NetchX/Netch)
|
||||
- Android
|
||||
- [v2rayNG](https://github.com/2dust/v2rayNG)
|
||||
- [AnXray](https://github.com/XTLS/AnXray)
|
||||
- [Kitsunebi](https://github.com/rurirei/Kitsunebi/tree/release_xtls)
|
||||
- iOS & macOS (with M1 chip)
|
||||
- iOS / Mac
|
||||
- [Shadowrocket](https://apps.apple.com/app/shadowrocket/id932747118)
|
||||
- macOS (Intel chip & M1 chip)
|
||||
- [Qv2ray](https://github.com/Qv2ray/Qv2ray) (This project had been archived and currently inactive)
|
||||
|
||||
## Credits
|
||||
|
||||
|
@@ -1,12 +1,13 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.27.1
|
||||
// protoc v3.18.0
|
||||
// protoc-gen-go v1.25.0
|
||||
// protoc v3.14.0
|
||||
// source: app/commander/config.proto
|
||||
|
||||
package commander
|
||||
|
||||
import (
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
serial "github.com/xtls/xray-core/common/serial"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
@@ -21,6 +22,10 @@ const (
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||
// of the legacy proto package is being used.
|
||||
const _ = proto.ProtoPackageIsVersion4
|
||||
|
||||
// Config is the settings for Commander.
|
||||
type Config struct {
|
||||
state protoimpl.MessageState
|
||||
|
@@ -3,10 +3,9 @@ package commander
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/reflection"
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
)
|
||||
|
||||
// Service is a Commander service.
|
||||
|
@@ -1,12 +1,13 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.27.1
|
||||
// protoc v3.18.0
|
||||
// protoc-gen-go v1.25.0
|
||||
// protoc v3.14.0
|
||||
// source: app/dispatcher/config.proto
|
||||
|
||||
package dispatcher
|
||||
|
||||
import (
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
@@ -20,6 +21,10 @@ const (
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||
// of the legacy proto package is being used.
|
||||
const _ = proto.ProtoPackageIsVersion4
|
||||
|
||||
type SessionConfig struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
|
@@ -25,7 +25,9 @@ import (
|
||||
"github.com/xtls/xray-core/transport/pipe"
|
||||
)
|
||||
|
||||
var errSniffingTimeout = newError("timeout on sniffing")
|
||||
var (
|
||||
errSniffingTimeout = newError("timeout on sniffing")
|
||||
)
|
||||
|
||||
type cachedReader struct {
|
||||
sync.Mutex
|
||||
@@ -177,7 +179,7 @@ func (d *DefaultDispatcher) getLink(ctx context.Context) (*transport.Link, *tran
|
||||
func shouldOverride(ctx context.Context, result SniffResult, request session.SniffingRequest, destination net.Destination) bool {
|
||||
domain := result.Domain()
|
||||
for _, d := range request.ExcludeForDomain {
|
||||
if strings.ToLower(domain) == d {
|
||||
if domain == d {
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -193,15 +195,10 @@ func shouldOverride(ctx context.Context, result SniffResult, request session.Sni
|
||||
if strings.HasPrefix(protocolString, p) {
|
||||
return true
|
||||
}
|
||||
if fkr0, ok := fakeDNSEngine.(dns.FakeDNSEngineRev0); ok && protocolString != "bittorrent" && p == "fakedns" &&
|
||||
destination.Address.Family().IsIP() && fkr0.IsIPInIPPool(destination.Address) {
|
||||
newError("Using sniffer ", protocolString, " since the fake DNS missed").WriteToLog(session.ExportIDToError(ctx))
|
||||
return true
|
||||
}
|
||||
if resultSubset, ok := result.(SnifferIsProtoSubsetOf); ok {
|
||||
if resultSubset.IsProtoSubsetOf(p) {
|
||||
return true
|
||||
}
|
||||
if fakeDNSEngine != nil && protocolString != "bittorrent" && p == "fakedns" &&
|
||||
destination.Address.Family().IsIP() && fakeDNSEngine.GetFakeIPRange().Contains(destination.Address.IP()) {
|
||||
newError("Using sniffer ", protocolString, " since the fake DNS missed").WriteToLog(session.ExportIDToError(ctx))
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -312,14 +309,18 @@ func sniffer(ctx context.Context, cReader *cachedReader, metadataOnly bool) (Sni
|
||||
func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.Link, destination net.Destination) {
|
||||
var handler outbound.Handler
|
||||
|
||||
routingLink := routing_session.AsRoutingContext(ctx)
|
||||
inTag := routingLink.GetInboundTag()
|
||||
isPickRoute := false
|
||||
if d.router != nil {
|
||||
if route, err := d.router.PickRoute(routing_session.AsRoutingContext(ctx)); err == nil {
|
||||
tag := route.GetOutboundTag()
|
||||
if h := d.ohm.GetHandler(tag); h != nil {
|
||||
newError("taking detour [", tag, "] for [", destination, "]").WriteToLog(session.ExportIDToError(ctx))
|
||||
if route, err := d.router.PickRoute(routingLink); err == nil {
|
||||
outTag := route.GetOutboundTag()
|
||||
isPickRoute = true
|
||||
if h := d.ohm.GetHandler(outTag); h != nil {
|
||||
newError("taking detour [", outTag, "] for [", destination, "]").WriteToLog(session.ExportIDToError(ctx))
|
||||
handler = h
|
||||
} else {
|
||||
newError("non existing outTag: ", tag).AtWarning().WriteToLog(session.ExportIDToError(ctx))
|
||||
newError("non existing outTag: ", outTag).AtWarning().WriteToLog(session.ExportIDToError(ctx))
|
||||
}
|
||||
} else {
|
||||
newError("default route for ", destination).WriteToLog(session.ExportIDToError(ctx))
|
||||
@@ -339,7 +340,19 @@ func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.
|
||||
|
||||
if accessMessage := log.AccessMessageFromContext(ctx); accessMessage != nil {
|
||||
if tag := handler.Tag(); tag != "" {
|
||||
accessMessage.Detour = tag
|
||||
if isPickRoute {
|
||||
if inTag != "" {
|
||||
accessMessage.Detour = inTag + " -> " + tag
|
||||
} else {
|
||||
accessMessage.Detour = tag
|
||||
}
|
||||
} else {
|
||||
if inTag != "" {
|
||||
accessMessage.Detour = inTag + " >> " + tag
|
||||
} else {
|
||||
accessMessage.Detour = tag
|
||||
}
|
||||
}
|
||||
}
|
||||
log.Record(accessMessage)
|
||||
}
|
||||
|
@@ -2,7 +2,6 @@ package dispatcher
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
@@ -33,15 +32,6 @@ func newFakeDNSSniffer(ctx context.Context) (protocolSnifferWithMetadata, error)
|
||||
return &fakeDNSSniffResult{domainName: domainFromFakeDNS}, nil
|
||||
}
|
||||
}
|
||||
|
||||
if ipAddressInRangeValueI := ctx.Value(ipAddressInRange); ipAddressInRangeValueI != nil {
|
||||
ipAddressInRangeValue := ipAddressInRangeValueI.(*ipAddressInRangeOpt)
|
||||
if fkr0, ok := fakeDNSEngine.(dns.FakeDNSEngineRev0); ok {
|
||||
inPool := fkr0.IsIPInIPPool(Target.Address)
|
||||
ipAddressInRangeValue.addressInRange = &inPool
|
||||
}
|
||||
}
|
||||
|
||||
return nil, common.ErrNoClue
|
||||
}, metadataSniffer: true}, nil
|
||||
}
|
||||
@@ -57,61 +47,3 @@ func (fakeDNSSniffResult) Protocol() string {
|
||||
func (f fakeDNSSniffResult) Domain() string {
|
||||
return f.domainName
|
||||
}
|
||||
|
||||
type fakeDNSExtraOpts int
|
||||
|
||||
const ipAddressInRange fakeDNSExtraOpts = 1
|
||||
|
||||
type ipAddressInRangeOpt struct {
|
||||
addressInRange *bool
|
||||
}
|
||||
|
||||
type DNSThenOthersSniffResult struct {
|
||||
domainName string
|
||||
protocolOriginalName string
|
||||
}
|
||||
|
||||
func (f DNSThenOthersSniffResult) IsProtoSubsetOf(protocolName string) bool {
|
||||
return strings.HasPrefix(protocolName, f.protocolOriginalName)
|
||||
}
|
||||
|
||||
func (DNSThenOthersSniffResult) Protocol() string {
|
||||
return "fakedns+others"
|
||||
}
|
||||
|
||||
func (f DNSThenOthersSniffResult) Domain() string {
|
||||
return f.domainName
|
||||
}
|
||||
|
||||
func newFakeDNSThenOthers(ctx context.Context, fakeDNSSniffer protocolSnifferWithMetadata, others []protocolSnifferWithMetadata) (
|
||||
protocolSnifferWithMetadata, error) { // nolint: unparam
|
||||
// ctx may be used in the future
|
||||
_ = ctx
|
||||
return protocolSnifferWithMetadata{
|
||||
protocolSniffer: func(ctx context.Context, bytes []byte) (SniffResult, error) {
|
||||
ipAddressInRangeValue := &ipAddressInRangeOpt{}
|
||||
ctx = context.WithValue(ctx, ipAddressInRange, ipAddressInRangeValue)
|
||||
result, err := fakeDNSSniffer.protocolSniffer(ctx, bytes)
|
||||
if err == nil {
|
||||
return result, nil
|
||||
}
|
||||
if ipAddressInRangeValue.addressInRange != nil {
|
||||
if *ipAddressInRangeValue.addressInRange {
|
||||
for _, v := range others {
|
||||
if v.metadataSniffer || bytes != nil {
|
||||
if result, err := v.protocolSniffer(ctx, bytes); err == nil {
|
||||
return DNSThenOthersSniffResult{domainName: result.Domain(), protocolOriginalName: result.Protocol()}, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, common.ErrNoClue
|
||||
}
|
||||
newError("ip address not in fake dns range, return as is").AtDebug().WriteToLog()
|
||||
return nil, common.ErrNoClue
|
||||
}
|
||||
newError("fake dns sniffer did not set address in range option, assume false.").AtWarning().WriteToLog()
|
||||
return nil, common.ErrNoClue
|
||||
},
|
||||
metadataSniffer: false,
|
||||
}, nil
|
||||
}
|
||||
|
@@ -37,12 +37,7 @@ func NewSniffer(ctx context.Context) *Sniffer {
|
||||
},
|
||||
}
|
||||
if sniffer, err := newFakeDNSSniffer(ctx); err == nil {
|
||||
others := ret.sniffer
|
||||
ret.sniffer = append(ret.sniffer, sniffer)
|
||||
fakeDNSThenOthers, err := newFakeDNSThenOthers(ctx, sniffer, others)
|
||||
if err == nil {
|
||||
ret.sniffer = append([]protocolSnifferWithMetadata{fakeDNSThenOthers}, ret.sniffer...)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
@@ -126,7 +121,3 @@ func (c compositeResult) ProtocolForDomainResult() string {
|
||||
type SnifferResultComposite interface {
|
||||
ProtocolForDomainResult() string
|
||||
}
|
||||
|
||||
type SnifferIsProtoSubsetOf interface {
|
||||
IsProtoSubsetOf(protocolName string) bool
|
||||
}
|
||||
|
@@ -1,12 +1,13 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.27.1
|
||||
// protoc v3.18.0
|
||||
// protoc-gen-go v1.25.0
|
||||
// protoc v3.15.8
|
||||
// source: app/dns/config.proto
|
||||
|
||||
package dns
|
||||
|
||||
import (
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
router "github.com/xtls/xray-core/app/router"
|
||||
net "github.com/xtls/xray-core/common/net"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
@@ -22,6 +23,10 @@ const (
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||
// of the legacy proto package is being used.
|
||||
const _ = proto.ProtoPackageIsVersion4
|
||||
|
||||
type DomainMatchingType int32
|
||||
|
||||
const (
|
||||
@@ -123,6 +128,55 @@ func (QueryStrategy) EnumDescriptor() ([]byte, []int) {
|
||||
return file_app_dns_config_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
type CacheStrategy int32
|
||||
|
||||
const (
|
||||
CacheStrategy_Cache_ALL CacheStrategy = 0
|
||||
CacheStrategy_Cache_NOERROR CacheStrategy = 1
|
||||
CacheStrategy_Cache_DISABLE CacheStrategy = 2
|
||||
)
|
||||
|
||||
// Enum value maps for CacheStrategy.
|
||||
var (
|
||||
CacheStrategy_name = map[int32]string{
|
||||
0: "Cache_ALL",
|
||||
1: "Cache_NOERROR",
|
||||
2: "Cache_DISABLE",
|
||||
}
|
||||
CacheStrategy_value = map[string]int32{
|
||||
"Cache_ALL": 0,
|
||||
"Cache_NOERROR": 1,
|
||||
"Cache_DISABLE": 2,
|
||||
}
|
||||
)
|
||||
|
||||
func (x CacheStrategy) Enum() *CacheStrategy {
|
||||
p := new(CacheStrategy)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x CacheStrategy) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (CacheStrategy) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_app_dns_config_proto_enumTypes[2].Descriptor()
|
||||
}
|
||||
|
||||
func (CacheStrategy) Type() protoreflect.EnumType {
|
||||
return &file_app_dns_config_proto_enumTypes[2]
|
||||
}
|
||||
|
||||
func (x CacheStrategy) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use CacheStrategy.Descriptor instead.
|
||||
func (CacheStrategy) EnumDescriptor() ([]byte, []int) {
|
||||
return file_app_dns_config_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
type NameServer struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
@@ -235,10 +289,9 @@ type Config struct {
|
||||
// Tag is the inbound tag of DNS client.
|
||||
Tag string `protobuf:"bytes,6,opt,name=tag,proto3" json:"tag,omitempty"`
|
||||
// DisableCache disables DNS cache
|
||||
DisableCache bool `protobuf:"varint,8,opt,name=disableCache,proto3" json:"disableCache,omitempty"`
|
||||
QueryStrategy QueryStrategy `protobuf:"varint,9,opt,name=query_strategy,json=queryStrategy,proto3,enum=xray.app.dns.QueryStrategy" json:"query_strategy,omitempty"`
|
||||
DisableFallback bool `protobuf:"varint,10,opt,name=disableFallback,proto3" json:"disableFallback,omitempty"`
|
||||
DisableFallbackIfMatch bool `protobuf:"varint,11,opt,name=disableFallbackIfMatch,proto3" json:"disableFallbackIfMatch,omitempty"`
|
||||
CacheStrategy CacheStrategy `protobuf:"varint,8,opt,name=cache_strategy,json=cacheStrategy,proto3,enum=xray.app.dns.CacheStrategy" json:"cache_strategy,omitempty"`
|
||||
QueryStrategy QueryStrategy `protobuf:"varint,9,opt,name=query_strategy,json=queryStrategy,proto3,enum=xray.app.dns.QueryStrategy" json:"query_strategy,omitempty"`
|
||||
DisableFallback bool `protobuf:"varint,10,opt,name=disableFallback,proto3" json:"disableFallback,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Config) Reset() {
|
||||
@@ -317,11 +370,11 @@ func (x *Config) GetTag() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Config) GetDisableCache() bool {
|
||||
func (x *Config) GetCacheStrategy() CacheStrategy {
|
||||
if x != nil {
|
||||
return x.DisableCache
|
||||
return x.CacheStrategy
|
||||
}
|
||||
return false
|
||||
return CacheStrategy_Cache_ALL
|
||||
}
|
||||
|
||||
func (x *Config) GetQueryStrategy() QueryStrategy {
|
||||
@@ -338,13 +391,6 @@ func (x *Config) GetDisableFallback() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *Config) GetDisableFallbackIfMatch() bool {
|
||||
if x != nil {
|
||||
return x.DisableFallbackIfMatch
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type NameServer_PriorityDomain struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
@@ -569,7 +615,7 @@ var file_app_dns_config_proto_rawDesc = []byte{
|
||||
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,
|
||||
0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x22, 0xd7, 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,
|
||||
@@ -588,48 +634,51 @@ var file_app_dns_config_proto_rawDesc = []byte{
|
||||
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,
|
||||
0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x42, 0x0a, 0x0e,
|
||||
0x63, 0x61, 0x63, 0x68, 0x65, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x08,
|
||||
0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e,
|
||||
0x64, 0x6e, 0x73, 0x2e, 0x43, 0x61, 0x63, 0x68, 0x65, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67,
|
||||
0x79, 0x52, 0x0d, 0x63, 0x61, 0x63, 0x68, 0x65, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79,
|
||||
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,
|
||||
0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 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, 0x2a, 0x44,
|
||||
0x0a, 0x0d, 0x43, 0x61, 0x63, 0x68, 0x65, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12,
|
||||
0x0d, 0x0a, 0x09, 0x43, 0x61, 0x63, 0x68, 0x65, 0x5f, 0x41, 0x4c, 0x4c, 0x10, 0x00, 0x12, 0x11,
|
||||
0x0a, 0x0d, 0x43, 0x61, 0x63, 0x68, 0x65, 0x5f, 0x4e, 0x4f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10,
|
||||
0x01, 0x12, 0x11, 0x0a, 0x0d, 0x43, 0x61, 0x63, 0x68, 0x65, 0x5f, 0x44, 0x49, 0x53, 0x41, 0x42,
|
||||
0x4c, 0x45, 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 (
|
||||
@@ -644,39 +693,41 @@ func file_app_dns_config_proto_rawDescGZIP() []byte {
|
||||
return file_app_dns_config_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_app_dns_config_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
|
||||
var file_app_dns_config_proto_enumTypes = make([]protoimpl.EnumInfo, 3)
|
||||
var file_app_dns_config_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
|
||||
var file_app_dns_config_proto_goTypes = []interface{}{
|
||||
(DomainMatchingType)(0), // 0: xray.app.dns.DomainMatchingType
|
||||
(QueryStrategy)(0), // 1: xray.app.dns.QueryStrategy
|
||||
(*NameServer)(nil), // 2: xray.app.dns.NameServer
|
||||
(*Config)(nil), // 3: xray.app.dns.Config
|
||||
(*NameServer_PriorityDomain)(nil), // 4: xray.app.dns.NameServer.PriorityDomain
|
||||
(*NameServer_OriginalRule)(nil), // 5: xray.app.dns.NameServer.OriginalRule
|
||||
nil, // 6: xray.app.dns.Config.HostsEntry
|
||||
(*Config_HostMapping)(nil), // 7: xray.app.dns.Config.HostMapping
|
||||
(*net.Endpoint)(nil), // 8: xray.common.net.Endpoint
|
||||
(*router.GeoIP)(nil), // 9: xray.app.router.GeoIP
|
||||
(*net.IPOrDomain)(nil), // 10: xray.common.net.IPOrDomain
|
||||
(CacheStrategy)(0), // 2: xray.app.dns.CacheStrategy
|
||||
(*NameServer)(nil), // 3: xray.app.dns.NameServer
|
||||
(*Config)(nil), // 4: xray.app.dns.Config
|
||||
(*NameServer_PriorityDomain)(nil), // 5: xray.app.dns.NameServer.PriorityDomain
|
||||
(*NameServer_OriginalRule)(nil), // 6: xray.app.dns.NameServer.OriginalRule
|
||||
nil, // 7: xray.app.dns.Config.HostsEntry
|
||||
(*Config_HostMapping)(nil), // 8: xray.app.dns.Config.HostMapping
|
||||
(*net.Endpoint)(nil), // 9: xray.common.net.Endpoint
|
||||
(*router.GeoIP)(nil), // 10: xray.app.router.GeoIP
|
||||
(*net.IPOrDomain)(nil), // 11: xray.common.net.IPOrDomain
|
||||
}
|
||||
var file_app_dns_config_proto_depIdxs = []int32{
|
||||
8, // 0: xray.app.dns.NameServer.address:type_name -> xray.common.net.Endpoint
|
||||
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
|
||||
9, // 0: xray.app.dns.NameServer.address:type_name -> xray.common.net.Endpoint
|
||||
5, // 1: xray.app.dns.NameServer.prioritized_domain:type_name -> xray.app.dns.NameServer.PriorityDomain
|
||||
10, // 2: xray.app.dns.NameServer.geoip:type_name -> xray.app.router.GeoIP
|
||||
6, // 3: xray.app.dns.NameServer.original_rules:type_name -> xray.app.dns.NameServer.OriginalRule
|
||||
9, // 4: xray.app.dns.Config.NameServers:type_name -> xray.common.net.Endpoint
|
||||
3, // 5: xray.app.dns.Config.name_server:type_name -> xray.app.dns.NameServer
|
||||
7, // 6: xray.app.dns.Config.Hosts:type_name -> xray.app.dns.Config.HostsEntry
|
||||
8, // 7: xray.app.dns.Config.static_hosts:type_name -> xray.app.dns.Config.HostMapping
|
||||
2, // 8: xray.app.dns.Config.cache_strategy:type_name -> xray.app.dns.CacheStrategy
|
||||
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
|
||||
11, // 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() }
|
||||
@@ -751,7 +802,7 @@ func file_app_dns_config_proto_init() {
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_app_dns_config_proto_rawDesc,
|
||||
NumEnums: 2,
|
||||
NumEnums: 3,
|
||||
NumMessages: 6,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
|
@@ -43,6 +43,12 @@ enum QueryStrategy {
|
||||
USE_IP6 = 2;
|
||||
}
|
||||
|
||||
enum CacheStrategy {
|
||||
Cache_ALL = 0;
|
||||
Cache_NOERROR = 1;
|
||||
Cache_DISABLE = 2;
|
||||
}
|
||||
|
||||
message Config {
|
||||
// Nameservers used by this DNS. Only traditional UDP servers are support at
|
||||
// the moment. A special value 'localhost' as a domain address can be set to
|
||||
@@ -79,10 +85,9 @@ message Config {
|
||||
reserved 7;
|
||||
|
||||
// DisableCache disables DNS cache
|
||||
bool disableCache = 8;
|
||||
CacheStrategy cache_strategy = 8;
|
||||
|
||||
QueryStrategy query_strategy = 9;
|
||||
|
||||
bool disableFallback = 10;
|
||||
bool disableFallbackIfMatch = 11;
|
||||
}
|
||||
|
161
app/dns/dns.go
161
app/dns/dns.go
@@ -22,16 +22,15 @@ import (
|
||||
// DNS is a DNS rely server.
|
||||
type DNS struct {
|
||||
sync.Mutex
|
||||
tag string
|
||||
disableCache bool
|
||||
disableFallback bool
|
||||
disableFallbackIfMatch bool
|
||||
ipOption *dns.IPOption
|
||||
hosts *StaticHosts
|
||||
clients []*Client
|
||||
ctx context.Context
|
||||
domainMatcher strmatcher.IndexMatcher
|
||||
matcherInfos []*DomainMatcherInfo
|
||||
tag string
|
||||
cacheStrategy CacheStrategy
|
||||
disableFallback bool
|
||||
ipOption *dns.IPOption
|
||||
hosts *StaticHosts
|
||||
clients []*Client
|
||||
ctx context.Context
|
||||
domainMatcher strmatcher.IndexMatcher
|
||||
matcherInfos []DomainMatcherInfo
|
||||
}
|
||||
|
||||
// DomainMatcherInfo contains information attached to index returned by Server.domainMatcher
|
||||
@@ -91,7 +90,7 @@ func New(ctx context.Context, config *Config) (*DNS, error) {
|
||||
}
|
||||
|
||||
// MatcherInfos is ensured to cover the maximum index domainMatcher could return, where matcher's index starts from 1
|
||||
matcherInfos := make([]*DomainMatcherInfo, domainRuleCount+1)
|
||||
matcherInfos := make([]DomainMatcherInfo, domainRuleCount+1)
|
||||
domainMatcher := &strmatcher.MatcherGroup{}
|
||||
geoipContainer := router.GeoIPMatcherContainer{}
|
||||
|
||||
@@ -106,9 +105,9 @@ func New(ctx context.Context, config *Config) (*DNS, error) {
|
||||
|
||||
for _, ns := range config.NameServer {
|
||||
clientIdx := len(clients)
|
||||
updateDomain := func(domainRule strmatcher.Matcher, originalRuleIdx int, matcherInfos []*DomainMatcherInfo) error {
|
||||
updateDomain := func(domainRule strmatcher.Matcher, originalRuleIdx int, matcherInfos []DomainMatcherInfo) error {
|
||||
midx := domainMatcher.Add(domainRule)
|
||||
matcherInfos[midx] = &DomainMatcherInfo{
|
||||
matcherInfos[midx] = DomainMatcherInfo{
|
||||
clientIdx: uint16(clientIdx),
|
||||
domainRuleIdx: uint16(originalRuleIdx),
|
||||
}
|
||||
@@ -133,16 +132,15 @@ func New(ctx context.Context, config *Config) (*DNS, error) {
|
||||
}
|
||||
|
||||
return &DNS{
|
||||
tag: tag,
|
||||
hosts: hosts,
|
||||
ipOption: ipOption,
|
||||
clients: clients,
|
||||
ctx: ctx,
|
||||
domainMatcher: domainMatcher,
|
||||
matcherInfos: matcherInfos,
|
||||
disableCache: config.DisableCache,
|
||||
disableFallback: config.DisableFallback,
|
||||
disableFallbackIfMatch: config.DisableFallbackIfMatch,
|
||||
tag: tag,
|
||||
hosts: hosts,
|
||||
ipOption: ipOption,
|
||||
clients: clients,
|
||||
ctx: ctx,
|
||||
domainMatcher: domainMatcher,
|
||||
matcherInfos: matcherInfos,
|
||||
cacheStrategy: config.CacheStrategy,
|
||||
disableFallback: config.DisableFallback,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -168,16 +166,42 @@ func (s *DNS) IsOwnLink(ctx context.Context) bool {
|
||||
}
|
||||
|
||||
// LookupIP implements dns.Client.
|
||||
func (s *DNS) LookupIP(domain string, option dns.IPOption) ([]net.IP, error) {
|
||||
func (s *DNS) LookupIP(domain string) ([]net.IP, error) {
|
||||
return s.lookupIPInternal(domain, s.ipOption.Copy())
|
||||
}
|
||||
|
||||
// LookupOptions implements dns.Client.
|
||||
func (s *DNS) LookupOptions(domain string, opts ...dns.Option) ([]net.IP, error) {
|
||||
opt := s.ipOption.Copy()
|
||||
for _, o := range opts {
|
||||
if o != nil {
|
||||
o(opt)
|
||||
}
|
||||
}
|
||||
|
||||
return s.lookupIPInternal(domain, opt)
|
||||
}
|
||||
|
||||
// LookupIPv4 implements dns.IPv4Lookup.
|
||||
func (s *DNS) LookupIPv4(domain string) ([]net.IP, error) {
|
||||
return s.lookupIPInternal(domain, &dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
})
|
||||
}
|
||||
|
||||
// LookupIPv6 implements dns.IPv6Lookup.
|
||||
func (s *DNS) LookupIPv6(domain string) ([]net.IP, error) {
|
||||
return s.lookupIPInternal(domain, &dns.IPOption{
|
||||
IPv6Enable: true,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *DNS) lookupIPInternal(domain string, option *dns.IPOption) ([]net.IP, error) {
|
||||
if domain == "" {
|
||||
return nil, newError("empty domain name")
|
||||
}
|
||||
|
||||
option.IPv4Enable = option.IPv4Enable && s.ipOption.IPv4Enable
|
||||
option.IPv6Enable = option.IPv6Enable && s.ipOption.IPv6Enable
|
||||
|
||||
if !option.IPv4Enable && !option.IPv6Enable {
|
||||
return nil, dns.ErrEmptyResponse
|
||||
if isQuery(option) {
|
||||
return nil, newError("empty option: Impossible.").AtWarning()
|
||||
}
|
||||
|
||||
// Normalize the FQDN form query
|
||||
@@ -194,20 +218,20 @@ func (s *DNS) LookupIP(domain string, option dns.IPOption) ([]net.IP, error) {
|
||||
case len(addrs) == 1 && addrs[0].Family().IsDomain(): // Domain replacement
|
||||
newError("domain replaced: ", domain, " -> ", addrs[0].Domain()).WriteToLog()
|
||||
domain = addrs[0].Domain()
|
||||
default: // Successfully found ip records in static host
|
||||
newError("returning ", len(addrs), " IP(s) for domain ", domain, " -> ", addrs).WriteToLog()
|
||||
return toNetIP(addrs)
|
||||
default:
|
||||
// Successfully found ip records in static host.
|
||||
// Skip hosts mapping result in FakeDNS query.
|
||||
if isIPQuery(option) {
|
||||
newError("returning ", len(addrs), " IP(s) for domain ", domain, " -> ", addrs).WriteToLog()
|
||||
return toNetIP(addrs)
|
||||
}
|
||||
}
|
||||
|
||||
// Name servers lookup
|
||||
errs := []error{}
|
||||
ctx := session.ContextWithInbound(s.ctx, &session.Inbound{Tag: s.tag})
|
||||
for _, client := range s.sortClients(domain) {
|
||||
if !option.FakeEnable && strings.EqualFold(client.Name(), "FakeDNS") {
|
||||
newError("skip DNS resolution for domain ", domain, " at server ", client.Name()).AtDebug().WriteToLog()
|
||||
continue
|
||||
}
|
||||
ips, err := client.QueryIP(ctx, domain, option, s.disableCache)
|
||||
for _, client := range s.sortClients(domain, option) {
|
||||
ips, err := client.QueryIP(ctx, domain, *option, s.cacheStrategy)
|
||||
if len(ips) > 0 {
|
||||
return ips, nil
|
||||
}
|
||||
@@ -223,34 +247,35 @@ func (s *DNS) LookupIP(domain string, option dns.IPOption) ([]net.IP, error) {
|
||||
return nil, newError("returning nil for domain ", domain).Base(errors.Combine(errs...))
|
||||
}
|
||||
|
||||
// GetIPOption implements ClientWithIPOption.
|
||||
func (s *DNS) GetIPOption() *dns.IPOption {
|
||||
return s.ipOption
|
||||
}
|
||||
|
||||
// SetQueryOption implements ClientWithIPOption.
|
||||
func (s *DNS) SetQueryOption(isIPv4Enable, isIPv6Enable bool) {
|
||||
s.ipOption.IPv4Enable = isIPv4Enable
|
||||
s.ipOption.IPv6Enable = isIPv6Enable
|
||||
}
|
||||
|
||||
// SetFakeDNSOption implements ClientWithIPOption.
|
||||
func (s *DNS) SetFakeDNSOption(isFakeEnable bool) {
|
||||
s.ipOption.FakeEnable = isFakeEnable
|
||||
}
|
||||
|
||||
func (s *DNS) sortClients(domain string) []*Client {
|
||||
func (s *DNS) sortClients(domain string, option *dns.IPOption) []*Client {
|
||||
clients := make([]*Client, 0, len(s.clients))
|
||||
clientUsed := make([]bool, len(s.clients))
|
||||
clientNames := make([]string, 0, len(s.clients))
|
||||
domainRules := []string{}
|
||||
|
||||
defer func() {
|
||||
if len(domainRules) > 0 {
|
||||
newError("domain ", domain, " matches following rules: ", domainRules).AtDebug().WriteToLog()
|
||||
}
|
||||
if len(clientNames) > 0 {
|
||||
newError("domain ", domain, " will use DNS in order: ", clientNames).AtDebug().WriteToLog()
|
||||
}
|
||||
if len(clients) == 0 {
|
||||
clients = append(clients, s.clients[0])
|
||||
clientNames = append(clientNames, s.clients[0].Name())
|
||||
newError("domain ", domain, " will use the first DNS: ", clientNames).AtDebug().WriteToLog()
|
||||
}
|
||||
}()
|
||||
|
||||
// Priority domain matching
|
||||
hasMatch := false
|
||||
for _, match := range s.domainMatcher.Match(domain) {
|
||||
info := s.matcherInfos[match]
|
||||
client := s.clients[info.clientIdx]
|
||||
domainRule := client.domains[info.domainRuleIdx]
|
||||
if !canQueryOnClient(option, client) {
|
||||
newError("skipping the client " + client.Name()).AtDebug().WriteToLog()
|
||||
continue
|
||||
}
|
||||
domainRules = append(domainRules, fmt.Sprintf("%s(DNS idx:%d)", domainRule, info.clientIdx))
|
||||
if clientUsed[info.clientIdx] {
|
||||
continue
|
||||
@@ -258,34 +283,26 @@ func (s *DNS) sortClients(domain string) []*Client {
|
||||
clientUsed[info.clientIdx] = true
|
||||
clients = append(clients, client)
|
||||
clientNames = append(clientNames, client.Name())
|
||||
hasMatch = true
|
||||
}
|
||||
|
||||
if !(s.disableFallback || s.disableFallbackIfMatch && hasMatch) {
|
||||
if !s.disableFallback {
|
||||
// Default round-robin query
|
||||
for idx, client := range s.clients {
|
||||
if clientUsed[idx] || client.skipFallback {
|
||||
continue
|
||||
}
|
||||
|
||||
if !canQueryOnClient(option, client) {
|
||||
newError("skipping the client " + client.Name()).AtDebug().WriteToLog()
|
||||
continue
|
||||
}
|
||||
|
||||
clientUsed[idx] = true
|
||||
clients = append(clients, client)
|
||||
clientNames = append(clientNames, client.Name())
|
||||
}
|
||||
}
|
||||
|
||||
if len(domainRules) > 0 {
|
||||
newError("domain ", domain, " matches following rules: ", domainRules).AtDebug().WriteToLog()
|
||||
}
|
||||
if len(clientNames) > 0 {
|
||||
newError("domain ", domain, " will use DNS in order: ", clientNames).AtDebug().WriteToLog()
|
||||
}
|
||||
|
||||
if len(clients) == 0 {
|
||||
clients = append(clients, s.clients[0])
|
||||
clientNames = append(clientNames, s.clients[0].Name())
|
||||
newError("domain ", domain, " will use the first DNS: ", clientNames).AtDebug().WriteToLog()
|
||||
}
|
||||
|
||||
return clients
|
||||
}
|
||||
|
||||
|
@@ -6,6 +6,7 @@ import (
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/miekg/dns"
|
||||
|
||||
"github.com/xtls/xray-core/app/dispatcher"
|
||||
. "github.com/xtls/xray-core/app/dns"
|
||||
"github.com/xtls/xray-core/app/policy"
|
||||
@@ -21,7 +22,8 @@ import (
|
||||
"github.com/xtls/xray-core/testing/servers/udp"
|
||||
)
|
||||
|
||||
type staticHandler struct{}
|
||||
type staticHandler struct {
|
||||
}
|
||||
|
||||
func (*staticHandler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
|
||||
ans := new(dns.Msg)
|
||||
@@ -152,11 +154,7 @@ func TestUDPServerSubnet(t *testing.T) {
|
||||
|
||||
client := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)
|
||||
|
||||
ips, err := client.LookupIP("google.com", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
})
|
||||
ips, err := client.LookupIP("google.com")
|
||||
if err != nil {
|
||||
t.Fatal("unexpected error: ", err)
|
||||
}
|
||||
@@ -211,11 +209,7 @@ func TestUDPServer(t *testing.T) {
|
||||
client := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)
|
||||
|
||||
{
|
||||
ips, err := client.LookupIP("google.com", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
})
|
||||
ips, err := client.LookupIP("google.com")
|
||||
if err != nil {
|
||||
t.Fatal("unexpected error: ", err)
|
||||
}
|
||||
@@ -226,11 +220,7 @@ func TestUDPServer(t *testing.T) {
|
||||
}
|
||||
|
||||
{
|
||||
ips, err := client.LookupIP("facebook.com", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
})
|
||||
ips, err := client.LookupIP("facebook.com")
|
||||
if err != nil {
|
||||
t.Fatal("unexpected error: ", err)
|
||||
}
|
||||
@@ -241,11 +231,7 @@ func TestUDPServer(t *testing.T) {
|
||||
}
|
||||
|
||||
{
|
||||
_, err := client.LookupIP("notexist.google.com", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
})
|
||||
_, err := client.LookupIP("notexist.google.com")
|
||||
if err == nil {
|
||||
t.Fatal("nil error")
|
||||
}
|
||||
@@ -255,11 +241,8 @@ func TestUDPServer(t *testing.T) {
|
||||
}
|
||||
|
||||
{
|
||||
ips, err := client.LookupIP("ipv4only.google.com", feature_dns.IPOption{
|
||||
IPv4Enable: false,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
})
|
||||
clientv6 := client.(feature_dns.IPv6Lookup)
|
||||
ips, err := clientv6.LookupIPv6("ipv4only.google.com")
|
||||
if err != feature_dns.ErrEmptyResponse {
|
||||
t.Fatal("error: ", err)
|
||||
}
|
||||
@@ -271,11 +254,7 @@ func TestUDPServer(t *testing.T) {
|
||||
dnsServer.Shutdown()
|
||||
|
||||
{
|
||||
ips, err := client.LookupIP("google.com", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
})
|
||||
ips, err := client.LookupIP("google.com")
|
||||
if err != nil {
|
||||
t.Fatal("unexpected error: ", err)
|
||||
}
|
||||
@@ -352,11 +331,7 @@ func TestPrioritizedDomain(t *testing.T) {
|
||||
startTime := time.Now()
|
||||
|
||||
{
|
||||
ips, err := client.LookupIP("google.com", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
})
|
||||
ips, err := client.LookupIP("google.com")
|
||||
if err != nil {
|
||||
t.Fatal("unexpected error: ", err)
|
||||
}
|
||||
@@ -415,12 +390,9 @@ func TestUDPServerIPv6(t *testing.T) {
|
||||
common.Must(err)
|
||||
|
||||
client := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)
|
||||
client6 := client.(feature_dns.IPv6Lookup)
|
||||
{
|
||||
ips, err := client.LookupIP("ipv6.google.com", feature_dns.IPOption{
|
||||
IPv4Enable: false,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
})
|
||||
ips, err := client6.LookupIPv6("ipv6.google.com")
|
||||
if err != nil {
|
||||
t.Fatal("unexpected error: ", err)
|
||||
}
|
||||
@@ -483,11 +455,7 @@ func TestStaticHostDomain(t *testing.T) {
|
||||
client := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)
|
||||
|
||||
{
|
||||
ips, err := client.LookupIP("example.com", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
})
|
||||
ips, err := client.LookupIP("example.com")
|
||||
if err != nil {
|
||||
t.Fatal("unexpected error: ", err)
|
||||
}
|
||||
@@ -594,11 +562,7 @@ func TestIPMatch(t *testing.T) {
|
||||
startTime := time.Now()
|
||||
|
||||
{
|
||||
ips, err := client.LookupIP("google.com", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
})
|
||||
ips, err := client.LookupIP("google.com")
|
||||
if err != nil {
|
||||
t.Fatal("unexpected error: ", err)
|
||||
}
|
||||
@@ -717,11 +681,7 @@ func TestLocalDomain(t *testing.T) {
|
||||
startTime := time.Now()
|
||||
|
||||
{ // Will match dotless:
|
||||
ips, err := client.LookupIP("hostname", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
})
|
||||
ips, err := client.LookupIP("hostname")
|
||||
if err != nil {
|
||||
t.Fatal("unexpected error: ", err)
|
||||
}
|
||||
@@ -732,11 +692,7 @@ func TestLocalDomain(t *testing.T) {
|
||||
}
|
||||
|
||||
{ // Will match domain:local
|
||||
ips, err := client.LookupIP("hostname.local", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
})
|
||||
ips, err := client.LookupIP("hostname.local")
|
||||
if err != nil {
|
||||
t.Fatal("unexpected error: ", err)
|
||||
}
|
||||
@@ -747,11 +703,7 @@ func TestLocalDomain(t *testing.T) {
|
||||
}
|
||||
|
||||
{ // Will match static ip
|
||||
ips, err := client.LookupIP("hostnamestatic", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
})
|
||||
ips, err := client.LookupIP("hostnamestatic")
|
||||
if err != nil {
|
||||
t.Fatal("unexpected error: ", err)
|
||||
}
|
||||
@@ -762,11 +714,7 @@ func TestLocalDomain(t *testing.T) {
|
||||
}
|
||||
|
||||
{ // Will match domain replacing
|
||||
ips, err := client.LookupIP("hostnamealias", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
})
|
||||
ips, err := client.LookupIP("hostnamealias")
|
||||
if err != nil {
|
||||
t.Fatal("unexpected error: ", err)
|
||||
}
|
||||
@@ -777,11 +725,7 @@ func TestLocalDomain(t *testing.T) {
|
||||
}
|
||||
|
||||
{ // Will match dotless:localhost, but not expectIPs: 127.0.0.2, 127.0.0.3, then matches at dotless:
|
||||
ips, err := client.LookupIP("localhost", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
})
|
||||
ips, err := client.LookupIP("localhost")
|
||||
if err != nil {
|
||||
t.Fatal("unexpected error: ", err)
|
||||
}
|
||||
@@ -792,11 +736,7 @@ func TestLocalDomain(t *testing.T) {
|
||||
}
|
||||
|
||||
{ // Will match dotless:localhost, and expectIPs: 127.0.0.2, 127.0.0.3
|
||||
ips, err := client.LookupIP("localhost-a", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
})
|
||||
ips, err := client.LookupIP("localhost-a")
|
||||
if err != nil {
|
||||
t.Fatal("unexpected error: ", err)
|
||||
}
|
||||
@@ -807,11 +747,7 @@ func TestLocalDomain(t *testing.T) {
|
||||
}
|
||||
|
||||
{ // Will match dotless:localhost, and expectIPs: 127.0.0.2, 127.0.0.3
|
||||
ips, err := client.LookupIP("localhost-b", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
})
|
||||
ips, err := client.LookupIP("localhost-b")
|
||||
if err != nil {
|
||||
t.Fatal("unexpected error: ", err)
|
||||
}
|
||||
@@ -822,11 +758,7 @@ func TestLocalDomain(t *testing.T) {
|
||||
}
|
||||
|
||||
{ // Will match dotless:
|
||||
ips, err := client.LookupIP("Mijia Cloud", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
})
|
||||
ips, err := client.LookupIP("Mijia Cloud")
|
||||
if err != nil {
|
||||
t.Fatal("unexpected error: ", err)
|
||||
}
|
||||
@@ -988,11 +920,7 @@ func TestMultiMatchPrioritizedDomain(t *testing.T) {
|
||||
startTime := time.Now()
|
||||
|
||||
{ // Will match server 1,2 and server 1 returns expected ip
|
||||
ips, err := client.LookupIP("google.com", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
})
|
||||
ips, err := client.LookupIP("google.com")
|
||||
if err != nil {
|
||||
t.Fatal("unexpected error: ", err)
|
||||
}
|
||||
@@ -1003,11 +931,8 @@ func TestMultiMatchPrioritizedDomain(t *testing.T) {
|
||||
}
|
||||
|
||||
{ // Will match server 1,2 and server 1 returns unexpected ip, then server 2 returns expected one
|
||||
ips, err := client.LookupIP("ipv6.google.com", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: false,
|
||||
FakeEnable: false,
|
||||
})
|
||||
clientv4 := client.(feature_dns.IPv4Lookup)
|
||||
ips, err := clientv4.LookupIPv4("ipv6.google.com")
|
||||
if err != nil {
|
||||
t.Fatal("unexpected error: ", err)
|
||||
}
|
||||
@@ -1018,11 +943,7 @@ func TestMultiMatchPrioritizedDomain(t *testing.T) {
|
||||
}
|
||||
|
||||
{ // Will match server 3,1,2 and server 3 returns expected one
|
||||
ips, err := client.LookupIP("api.google.com", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
})
|
||||
ips, err := client.LookupIP("api.google.com")
|
||||
if err != nil {
|
||||
t.Fatal("unexpected error: ", err)
|
||||
}
|
||||
@@ -1033,11 +954,7 @@ func TestMultiMatchPrioritizedDomain(t *testing.T) {
|
||||
}
|
||||
|
||||
{ // Will match server 4,3,1,2 and server 4 returns expected one
|
||||
ips, err := client.LookupIP("v2.api.google.com", feature_dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
})
|
||||
ips, err := client.LookupIP("v2.api.google.com")
|
||||
if err != nil {
|
||||
t.Fatal("unexpected error: ", err)
|
||||
}
|
||||
|
@@ -5,12 +5,11 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/dns/dnsmessage"
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
dns_feature "github.com/xtls/xray-core/features/dns"
|
||||
"golang.org/x/net/dns/dnsmessage"
|
||||
)
|
||||
|
||||
// Fqdn normalize domain make sure it ends with '.'
|
||||
@@ -54,7 +53,9 @@ func isNewer(baseRec *IPRecord, newRec *IPRecord) bool {
|
||||
return baseRec.Expire.Before(newRec.Expire)
|
||||
}
|
||||
|
||||
var errRecordNotFound = errors.New("record not found")
|
||||
var (
|
||||
errRecordNotFound = errors.New("record not found")
|
||||
)
|
||||
|
||||
type dnsRequest struct {
|
||||
reqType dnsmessage.Type
|
||||
@@ -211,7 +212,7 @@ L:
|
||||
case dnsmessage.TypeAAAA:
|
||||
ans, err := parser.AAAAResource()
|
||||
if err != nil {
|
||||
newError("failed to parse AAAA record for domain: ", ah.Name).Base(err).WriteToLog()
|
||||
newError("failed to parse A record for domain: ", ah.Name).Base(err).WriteToLog()
|
||||
break L
|
||||
}
|
||||
ipRecord.IP = append(ipRecord.IP, net.IPAddress(ans.AAAA[:]))
|
||||
|
@@ -7,11 +7,10 @@ import (
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/miekg/dns"
|
||||
"golang.org/x/net/dns/dnsmessage"
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
dns_feature "github.com/xtls/xray-core/features/dns"
|
||||
"golang.org/x/net/dns/dnsmessage"
|
||||
)
|
||||
|
||||
func Test_parseResponse(t *testing.T) {
|
||||
@@ -50,28 +49,20 @@ func Test_parseResponse(t *testing.T) {
|
||||
want *IPRecord
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
"empty",
|
||||
{"empty",
|
||||
&IPRecord{0, []net.Address(nil), time.Time{}, dnsmessage.RCodeSuccess},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"error",
|
||||
{"error",
|
||||
nil,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"a record",
|
||||
&IPRecord{
|
||||
1,
|
||||
[]net.Address{net.ParseAddress("8.8.8.8"), net.ParseAddress("8.8.4.4")},
|
||||
time.Time{},
|
||||
dnsmessage.RCodeSuccess,
|
||||
},
|
||||
{"a record",
|
||||
&IPRecord{1, []net.Address{net.ParseAddress("8.8.8.8"), net.ParseAddress("8.8.4.4")},
|
||||
time.Time{}, dnsmessage.RCodeSuccess},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"aaaa record",
|
||||
{"aaaa record",
|
||||
&IPRecord{2, []net.Address{net.ParseAddress("2001::123:8888"), net.ParseAddress("2001::123:8844")}, time.Time{}, dnsmessage.RCodeSuccess},
|
||||
false,
|
||||
},
|
||||
|
@@ -20,30 +20,12 @@ type Holder struct {
|
||||
config *FakeDnsPool
|
||||
}
|
||||
|
||||
func (fkdns *Holder) IsIPInIPPool(ip net.Address) bool {
|
||||
if ip.Family().IsDomain() {
|
||||
return false
|
||||
}
|
||||
return fkdns.ipRange.Contains(ip.IP())
|
||||
}
|
||||
|
||||
func (fkdns *Holder) GetFakeIPForDomain3(domain string, ipv4, ipv6 bool) []net.Address {
|
||||
isIPv6 := fkdns.ipRange.IP.To4() == nil
|
||||
if (isIPv6 && ipv6) || (!isIPv6 && ipv4) {
|
||||
return fkdns.GetFakeIPForDomain(domain)
|
||||
}
|
||||
return []net.Address{}
|
||||
}
|
||||
|
||||
func (*Holder) Type() interface{} {
|
||||
return (*dns.FakeDNSEngine)(nil)
|
||||
}
|
||||
|
||||
func (fkdns *Holder) Start() error {
|
||||
if fkdns.config != nil && fkdns.config.IpPool != "" && fkdns.config.LruSize != 0 {
|
||||
return fkdns.initializeFromConfig()
|
||||
}
|
||||
return newError("invalid fakeDNS setting")
|
||||
return fkdns.initializeFromConfig()
|
||||
}
|
||||
|
||||
func (fkdns *Holder) Close() error {
|
||||
@@ -59,7 +41,7 @@ func NewFakeDNSHolder() (*Holder, error) {
|
||||
if fkdns, err = NewFakeDNSHolderConfigOnly(nil); err != nil {
|
||||
return nil, newError("Unable to create Fake Dns Engine").Base(err).AtError()
|
||||
}
|
||||
err = fkdns.initialize(dns.FakeIPv4Pool, 65535)
|
||||
err = fkdns.initialize(dns.FakeIPPool, 65535)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -97,13 +79,13 @@ func (fkdns *Holder) GetFakeIPForDomain(domain string) []net.Address {
|
||||
if v, ok := fkdns.domainToIP.Get(domain); ok {
|
||||
return []net.Address{v.(net.Address)}
|
||||
}
|
||||
currentTimeMillis := uint64(time.Now().UnixNano() / 1e6)
|
||||
var currentTimeMillis = uint64(time.Now().UnixNano() / 1e6)
|
||||
ones, bits := fkdns.ipRange.Mask.Size()
|
||||
rooms := bits - ones
|
||||
if rooms < 64 {
|
||||
currentTimeMillis %= (uint64(1) << rooms)
|
||||
}
|
||||
bigIntIP := big.NewInt(0).SetBytes(fkdns.ipRange.IP)
|
||||
var bigIntIP = big.NewInt(0).SetBytes(fkdns.ipRange.IP)
|
||||
bigIntIP = bigIntIP.Add(bigIntIP, new(big.Int).SetUint64(currentTimeMillis))
|
||||
var ip net.Address
|
||||
for {
|
||||
@@ -135,92 +117,9 @@ func (fkdns *Holder) GetDomainFromFakeDNS(ip net.Address) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
type HolderMulti struct {
|
||||
holders []*Holder
|
||||
|
||||
config *FakeDnsPoolMulti
|
||||
}
|
||||
|
||||
func (h *HolderMulti) IsIPInIPPool(ip net.Address) bool {
|
||||
if ip.Family().IsDomain() {
|
||||
return false
|
||||
}
|
||||
for _, v := range h.holders {
|
||||
if v.IsIPInIPPool(ip) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (h *HolderMulti) GetFakeIPForDomain3(domain string, ipv4, ipv6 bool) []net.Address {
|
||||
var ret []net.Address
|
||||
for _, v := range h.holders {
|
||||
ret = append(ret, v.GetFakeIPForDomain3(domain, ipv4, ipv6)...)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (h *HolderMulti) GetFakeIPForDomain(domain string) []net.Address {
|
||||
var ret []net.Address
|
||||
for _, v := range h.holders {
|
||||
ret = append(ret, v.GetFakeIPForDomain(domain)...)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (h *HolderMulti) GetDomainFromFakeDNS(ip net.Address) string {
|
||||
for _, v := range h.holders {
|
||||
if domain := v.GetDomainFromFakeDNS(ip); domain != "" {
|
||||
return domain
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (h *HolderMulti) Type() interface{} {
|
||||
return (*dns.FakeDNSEngine)(nil)
|
||||
}
|
||||
|
||||
func (h *HolderMulti) Start() error {
|
||||
for _, v := range h.holders {
|
||||
if v.config != nil && v.config.IpPool != "" && v.config.LruSize != 0 {
|
||||
if err := v.Start(); err != nil {
|
||||
return newError("Cannot start all fake dns pools").Base(err)
|
||||
}
|
||||
} else {
|
||||
return newError("invalid fakeDNS setting")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *HolderMulti) Close() error {
|
||||
for _, v := range h.holders {
|
||||
if err := v.Close(); err != nil {
|
||||
return newError("Cannot close all fake dns pools").Base(err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *HolderMulti) createHolderGroups() error {
|
||||
for _, v := range h.config.Pools {
|
||||
holder, err := NewFakeDNSHolderConfigOnly(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
h.holders = append(h.holders, holder)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewFakeDNSHolderMulti(conf *FakeDnsPoolMulti) (*HolderMulti, error) {
|
||||
holderMulti := &HolderMulti{nil, conf}
|
||||
if err := holderMulti.createHolderGroups(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return holderMulti, nil
|
||||
// GetFakeIPRange return fake IP range from configuration
|
||||
func (fkdns *Holder) GetFakeIPRange() *gonet.IPNet {
|
||||
return fkdns.ipRange
|
||||
}
|
||||
|
||||
func init() {
|
||||
@@ -232,13 +131,4 @@ func init() {
|
||||
}
|
||||
return f, nil
|
||||
}))
|
||||
|
||||
common.Must(common.RegisterConfig((*FakeDnsPoolMulti)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
|
||||
var f *HolderMulti
|
||||
var err error
|
||||
if f, err = NewFakeDNSHolderMulti(config.(*FakeDnsPoolMulti)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return f, nil
|
||||
}))
|
||||
}
|
||||
|
@@ -1,12 +1,13 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.27.1
|
||||
// protoc v3.18.0
|
||||
// protoc-gen-go v1.25.0
|
||||
// protoc v3.13.0
|
||||
// source: app/dns/fakedns/fakedns.proto
|
||||
|
||||
package fakedns
|
||||
|
||||
import (
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
@@ -20,6 +21,10 @@ const (
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||
// of the legacy proto package is being used.
|
||||
const _ = proto.ProtoPackageIsVersion4
|
||||
|
||||
type FakeDnsPool struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
@@ -75,75 +80,24 @@ func (x *FakeDnsPool) GetLruSize() int64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
type FakeDnsPoolMulti struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Pools []*FakeDnsPool `protobuf:"bytes,1,rep,name=pools,proto3" json:"pools,omitempty"`
|
||||
}
|
||||
|
||||
func (x *FakeDnsPoolMulti) Reset() {
|
||||
*x = FakeDnsPoolMulti{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_app_dns_fakedns_fakedns_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *FakeDnsPoolMulti) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*FakeDnsPoolMulti) ProtoMessage() {}
|
||||
|
||||
func (x *FakeDnsPoolMulti) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_app_dns_fakedns_fakedns_proto_msgTypes[1]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use FakeDnsPoolMulti.ProtoReflect.Descriptor instead.
|
||||
func (*FakeDnsPoolMulti) Descriptor() ([]byte, []int) {
|
||||
return file_app_dns_fakedns_fakedns_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *FakeDnsPoolMulti) GetPools() []*FakeDnsPool {
|
||||
if x != nil {
|
||||
return x.Pools
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_app_dns_fakedns_fakedns_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_app_dns_fakedns_fakedns_proto_rawDesc = []byte{
|
||||
0x0a, 0x1d, 0x61, 0x70, 0x70, 0x2f, 0x64, 0x6e, 0x73, 0x2f, 0x66, 0x61, 0x6b, 0x65, 0x64, 0x6e,
|
||||
0x73, 0x2f, 0x66, 0x61, 0x6b, 0x65, 0x64, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
|
||||
0x14, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x66, 0x61,
|
||||
0x6b, 0x65, 0x64, 0x6e, 0x73, 0x22, 0x40, 0x0a, 0x0b, 0x46, 0x61, 0x6b, 0x65, 0x44, 0x6e, 0x73,
|
||||
0x50, 0x6f, 0x6f, 0x6c, 0x12, 0x17, 0x0a, 0x07, 0x69, 0x70, 0x5f, 0x70, 0x6f, 0x6f, 0x6c, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x69, 0x70, 0x50, 0x6f, 0x6f, 0x6c, 0x12, 0x18, 0x0a,
|
||||
0x07, 0x6c, 0x72, 0x75, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07,
|
||||
0x6c, 0x72, 0x75, 0x53, 0x69, 0x7a, 0x65, 0x22, 0x4b, 0x0a, 0x10, 0x46, 0x61, 0x6b, 0x65, 0x44,
|
||||
0x6e, 0x73, 0x50, 0x6f, 0x6f, 0x6c, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x12, 0x37, 0x0a, 0x05, 0x70,
|
||||
0x6f, 0x6f, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x78, 0x72, 0x61,
|
||||
0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x66, 0x61, 0x6b, 0x65, 0x64, 0x6e,
|
||||
0x73, 0x2e, 0x46, 0x61, 0x6b, 0x65, 0x44, 0x6e, 0x73, 0x50, 0x6f, 0x6f, 0x6c, 0x52, 0x05, 0x70,
|
||||
0x6f, 0x6f, 0x6c, 0x73, 0x42, 0x5e, 0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
||||
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x66, 0x61, 0x6b, 0x65, 0x64, 0x6e, 0x73,
|
||||
0x50, 0x01, 0x5a, 0x29, 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, 0x2f, 0x66, 0x61, 0x6b, 0x65, 0x64, 0x6e, 0x73, 0xaa, 0x02, 0x14,
|
||||
0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x44, 0x6e, 0x73, 0x2e, 0x46, 0x61, 0x6b,
|
||||
0x65, 0x64, 0x6e, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x1a, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e,
|
||||
0x64, 0x6e, 0x73, 0x2e, 0x66, 0x61, 0x6b, 0x65, 0x64, 0x6e, 0x73, 0x22, 0x40, 0x0a, 0x0b, 0x46,
|
||||
0x61, 0x6b, 0x65, 0x44, 0x6e, 0x73, 0x50, 0x6f, 0x6f, 0x6c, 0x12, 0x17, 0x0a, 0x07, 0x69, 0x70,
|
||||
0x5f, 0x70, 0x6f, 0x6f, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x69, 0x70, 0x50,
|
||||
0x6f, 0x6f, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x6c, 0x72, 0x75, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x6c, 0x72, 0x75, 0x53, 0x69, 0x7a, 0x65, 0x42, 0x5f, 0x0a,
|
||||
0x1e, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,
|
||||
0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x66, 0x61, 0x6b, 0x65, 0x64, 0x6e, 0x73, 0x50,
|
||||
0x01, 0x5a, 0x1e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72,
|
||||
0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x64, 0x6e, 0x73, 0x2f, 0x66, 0x61, 0x6b, 0x65, 0x64, 0x6e,
|
||||
0x73, 0xaa, 0x02, 0x1a, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x41,
|
||||
0x70, 0x70, 0x2e, 0x44, 0x6e, 0x73, 0x2e, 0x46, 0x61, 0x6b, 0x65, 0x64, 0x6e, 0x73, 0x62, 0x06,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -158,18 +112,16 @@ func file_app_dns_fakedns_fakedns_proto_rawDescGZIP() []byte {
|
||||
return file_app_dns_fakedns_fakedns_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_app_dns_fakedns_fakedns_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
||||
var file_app_dns_fakedns_fakedns_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||
var file_app_dns_fakedns_fakedns_proto_goTypes = []interface{}{
|
||||
(*FakeDnsPool)(nil), // 0: xray.app.dns.fakedns.FakeDnsPool
|
||||
(*FakeDnsPoolMulti)(nil), // 1: xray.app.dns.fakedns.FakeDnsPoolMulti
|
||||
(*FakeDnsPool)(nil), // 0: xray.app.dns.fakedns.FakeDnsPool
|
||||
}
|
||||
var file_app_dns_fakedns_fakedns_proto_depIdxs = []int32{
|
||||
0, // 0: xray.app.dns.fakedns.FakeDnsPoolMulti.pools:type_name -> xray.app.dns.fakedns.FakeDnsPool
|
||||
1, // [1:1] is the sub-list for method output_type
|
||||
1, // [1:1] is the sub-list for method input_type
|
||||
1, // [1:1] is the sub-list for extension type_name
|
||||
1, // [1:1] is the sub-list for extension extendee
|
||||
0, // [0:1] is the sub-list for field type_name
|
||||
0, // [0:0] is the sub-list for method output_type
|
||||
0, // [0:0] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_app_dns_fakedns_fakedns_proto_init() }
|
||||
@@ -190,18 +142,6 @@ func file_app_dns_fakedns_fakedns_proto_init() {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_app_dns_fakedns_fakedns_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*FakeDnsPoolMulti); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
@@ -209,7 +149,7 @@ func file_app_dns_fakedns_fakedns_proto_init() {
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_app_dns_fakedns_fakedns_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 2,
|
||||
NumMessages: 1,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
|
@@ -10,7 +10,3 @@ message FakeDnsPool{
|
||||
string ip_pool = 1; //CIDR of IP pool used as fake DNS IP
|
||||
int64 lruSize = 2; //Size of Pool for remembering relationship between domain name and IP address
|
||||
}
|
||||
|
||||
message FakeDnsPoolMulti{
|
||||
repeated FakeDnsPool pools = 1;
|
||||
}
|
@@ -3,8 +3,6 @@ package fakedns
|
||||
import (
|
||||
"testing"
|
||||
|
||||
gonet "net"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
@@ -13,7 +11,9 @@ import (
|
||||
"github.com/xtls/xray-core/features/dns"
|
||||
)
|
||||
|
||||
var ipPrefix = "198.1"
|
||||
var (
|
||||
ipPrefix = "198.18."
|
||||
)
|
||||
|
||||
func TestNewFakeDnsHolder(_ *testing.T) {
|
||||
_, err := NewFakeDNSHolder()
|
||||
@@ -69,7 +69,7 @@ func TestFakeDnsHolderCreateMappingManySingleDomain(t *testing.T) {
|
||||
|
||||
func TestFakeDnsHolderCreateMappingAndRollOver(t *testing.T) {
|
||||
fkdns, err := NewFakeDNSHolderConfigOnly(&FakeDnsPool{
|
||||
IpPool: dns.FakeIPv4Pool,
|
||||
IpPool: dns.FakeIPPool,
|
||||
LruSize: 256,
|
||||
})
|
||||
common.Must(err)
|
||||
@@ -103,79 +103,3 @@ func TestFakeDnsHolderCreateMappingAndRollOver(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFakeDNSMulti(t *testing.T) {
|
||||
fakeMulti, err := NewFakeDNSHolderMulti(&FakeDnsPoolMulti{
|
||||
Pools: []*FakeDnsPool{{
|
||||
IpPool: "240.0.0.0/12",
|
||||
LruSize: 256,
|
||||
}, {
|
||||
IpPool: "fddd:c5b4:ff5f:f4f0::/64",
|
||||
LruSize: 256,
|
||||
}},
|
||||
},
|
||||
)
|
||||
common.Must(err)
|
||||
|
||||
err = fakeMulti.Start()
|
||||
|
||||
common.Must(err)
|
||||
|
||||
assert.Nil(t, err, "Should not throw error")
|
||||
_ = fakeMulti
|
||||
|
||||
t.Run("checkInRange", func(t *testing.T) {
|
||||
t.Run("ipv4", func(t *testing.T) {
|
||||
inPool := fakeMulti.IsIPInIPPool(net.IPAddress([]byte{240, 0, 0, 5}))
|
||||
assert.True(t, inPool)
|
||||
})
|
||||
t.Run("ipv6", func(t *testing.T) {
|
||||
ip, err := gonet.ResolveIPAddr("ip", "fddd:c5b4:ff5f:f4f0::5")
|
||||
assert.Nil(t, err)
|
||||
inPool := fakeMulti.IsIPInIPPool(net.IPAddress(ip.IP))
|
||||
assert.True(t, inPool)
|
||||
})
|
||||
t.Run("ipv4_inverse", func(t *testing.T) {
|
||||
inPool := fakeMulti.IsIPInIPPool(net.IPAddress([]byte{241, 0, 0, 5}))
|
||||
assert.False(t, inPool)
|
||||
})
|
||||
t.Run("ipv6_inverse", func(t *testing.T) {
|
||||
ip, err := gonet.ResolveIPAddr("ip", "fcdd:c5b4:ff5f:f4f0::5")
|
||||
assert.Nil(t, err)
|
||||
inPool := fakeMulti.IsIPInIPPool(net.IPAddress(ip.IP))
|
||||
assert.False(t, inPool)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("allocateTwoAddressForTwoPool", func(t *testing.T) {
|
||||
address := fakeMulti.GetFakeIPForDomain("fakednstest.v2fly.org")
|
||||
assert.Len(t, address, 2, "should be 2 address one for each pool")
|
||||
t.Run("eachOfThemShouldResolve:0", func(t *testing.T) {
|
||||
domain := fakeMulti.GetDomainFromFakeDNS(address[0])
|
||||
assert.Equal(t, "fakednstest.v2fly.org", domain)
|
||||
})
|
||||
t.Run("eachOfThemShouldResolve:1", func(t *testing.T) {
|
||||
domain := fakeMulti.GetDomainFromFakeDNS(address[1])
|
||||
assert.Equal(t, "fakednstest.v2fly.org", domain)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("understandIPTypeSelector", func(t *testing.T) {
|
||||
t.Run("ipv4", func(t *testing.T) {
|
||||
address := fakeMulti.GetFakeIPForDomain3("fakednstestipv4.v2fly.org", true, false)
|
||||
assert.Len(t, address, 1, "should be 1 address")
|
||||
assert.True(t, address[0].Family().IsIPv4())
|
||||
})
|
||||
t.Run("ipv6", func(t *testing.T) {
|
||||
address := fakeMulti.GetFakeIPForDomain3("fakednstestipv6.v2fly.org", false, true)
|
||||
assert.Len(t, address, 1, "should be 1 address")
|
||||
assert.True(t, address[0].Family().IsIPv6())
|
||||
})
|
||||
t.Run("ipv46", func(t *testing.T) {
|
||||
address := fakeMulti.GetFakeIPForDomain3("fakednstestipv46.v2fly.org", true, true)
|
||||
assert.Len(t, address, 2, "should be 2 address")
|
||||
assert.True(t, address[0].Family().IsIPv4())
|
||||
assert.True(t, address[1].Family().IsIPv6())
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@@ -49,6 +49,7 @@ func NewStaticHosts(hosts []*Config_HostMapping, legacy map[string]*net.IPOrDoma
|
||||
switch {
|
||||
case len(mapping.ProxiedDomain) > 0:
|
||||
ips = append(ips, net.DomainAddress(mapping.ProxiedDomain))
|
||||
|
||||
case len(mapping.Ip) > 0:
|
||||
for _, ip := range mapping.Ip {
|
||||
addr := net.IPAddress(ip)
|
||||
@@ -57,6 +58,7 @@ func NewStaticHosts(hosts []*Config_HostMapping, legacy map[string]*net.IPOrDoma
|
||||
}
|
||||
ips = append(ips, addr)
|
||||
}
|
||||
|
||||
default:
|
||||
return nil, newError("neither IP address nor proxied domain specified for domain: ", mapping.Domain).AtWarning()
|
||||
}
|
||||
@@ -67,7 +69,7 @@ func NewStaticHosts(hosts []*Config_HostMapping, legacy map[string]*net.IPOrDoma
|
||||
return sh, nil
|
||||
}
|
||||
|
||||
func filterIP(ips []net.Address, option dns.IPOption) []net.Address {
|
||||
func filterIP(ips []net.Address, option *dns.IPOption) []net.Address {
|
||||
filtered := make([]net.Address, 0, len(ips))
|
||||
for _, ip := range ips {
|
||||
if (ip.Family().IsIPv4() && option.IPv4Enable) || (ip.Family().IsIPv6() && option.IPv6Enable) {
|
||||
@@ -82,10 +84,13 @@ func (h *StaticHosts) lookupInternal(domain string) []net.Address {
|
||||
for _, id := range h.matchers.Match(domain) {
|
||||
ips = append(ips, h.ips[id]...)
|
||||
}
|
||||
if len(ips) == 1 && ips[0].Family().IsDomain() {
|
||||
return ips
|
||||
}
|
||||
return ips
|
||||
}
|
||||
|
||||
func (h *StaticHosts) lookup(domain string, option dns.IPOption, maxDepth int) []net.Address {
|
||||
func (h *StaticHosts) lookup(domain string, option *dns.IPOption, maxDepth int) []net.Address {
|
||||
switch addrs := h.lookupInternal(domain); {
|
||||
case len(addrs) == 0: // Not recorded in static hosts, return nil
|
||||
return nil
|
||||
@@ -104,6 +109,6 @@ func (h *StaticHosts) lookup(domain string, option dns.IPOption, maxDepth int) [
|
||||
}
|
||||
|
||||
// Lookup returns IP addresses or proxied domain for the given domain, if exists in this StaticHosts.
|
||||
func (h *StaticHosts) Lookup(domain string, option dns.IPOption) []net.Address {
|
||||
func (h *StaticHosts) Lookup(domain string, option *dns.IPOption) []net.Address {
|
||||
return h.lookup(domain, option, 5)
|
||||
}
|
||||
|
@@ -4,6 +4,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
|
||||
. "github.com/xtls/xray-core/app/dns"
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
@@ -21,17 +22,17 @@ func TestStaticHosts(t *testing.T) {
|
||||
},
|
||||
{
|
||||
Type: DomainMatchingType_Full,
|
||||
Domain: "proxy.xray.com",
|
||||
Domain: "proxy.example.com",
|
||||
Ip: [][]byte{
|
||||
{1, 2, 3, 4},
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
},
|
||||
ProxiedDomain: "another-proxy.xray.com",
|
||||
ProxiedDomain: "another-proxy.example.com",
|
||||
},
|
||||
{
|
||||
Type: DomainMatchingType_Full,
|
||||
Domain: "proxy2.xray.com",
|
||||
ProxiedDomain: "proxy.xray.com",
|
||||
Domain: "proxy2.example.com",
|
||||
ProxiedDomain: "proxy.example.com",
|
||||
},
|
||||
{
|
||||
Type: DomainMatchingType_Subdomain,
|
||||
@@ -54,7 +55,7 @@ func TestStaticHosts(t *testing.T) {
|
||||
common.Must(err)
|
||||
|
||||
{
|
||||
ips := hosts.Lookup("example.com", dns.IPOption{
|
||||
ips := hosts.Lookup("example.com", &dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
})
|
||||
@@ -67,33 +68,33 @@ func TestStaticHosts(t *testing.T) {
|
||||
}
|
||||
|
||||
{
|
||||
domain := hosts.Lookup("proxy.xray.com", dns.IPOption{
|
||||
domain := hosts.Lookup("proxy.example.com", &dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: false,
|
||||
})
|
||||
if len(domain) != 1 {
|
||||
t.Error("expect 1 domain, but got ", len(domain))
|
||||
}
|
||||
if diff := cmp.Diff(domain[0].Domain(), "another-proxy.xray.com"); diff != "" {
|
||||
if diff := cmp.Diff(domain[0].Domain(), "another-proxy.example.com"); diff != "" {
|
||||
t.Error(diff)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
domain := hosts.Lookup("proxy2.xray.com", dns.IPOption{
|
||||
domain := hosts.Lookup("proxy2.example.com", &dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: false,
|
||||
})
|
||||
if len(domain) != 1 {
|
||||
t.Error("expect 1 domain, but got ", len(domain))
|
||||
}
|
||||
if diff := cmp.Diff(domain[0].Domain(), "another-proxy.xray.com"); diff != "" {
|
||||
if diff := cmp.Diff(domain[0].Domain(), "another-proxy.example.com"); diff != "" {
|
||||
t.Error(diff)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
ips := hosts.Lookup("www.example.cn", dns.IPOption{
|
||||
ips := hosts.Lookup("www.example.cn", &dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
})
|
||||
@@ -106,7 +107,7 @@ func TestStaticHosts(t *testing.T) {
|
||||
}
|
||||
|
||||
{
|
||||
ips := hosts.Lookup("baidu.com", dns.IPOption{
|
||||
ips := hosts.Lookup("baidu.com", &dns.IPOption{
|
||||
IPv4Enable: false,
|
||||
IPv6Enable: true,
|
||||
})
|
||||
|
@@ -10,7 +10,7 @@ import (
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/strmatcher"
|
||||
"github.com/xtls/xray-core/core"
|
||||
core "github.com/xtls/xray-core/core"
|
||||
"github.com/xtls/xray-core/features/dns"
|
||||
"github.com/xtls/xray-core/features/routing"
|
||||
)
|
||||
@@ -20,7 +20,7 @@ type Server interface {
|
||||
// Name of the Client.
|
||||
Name() string
|
||||
// QueryIP sends IP queries to its configured server.
|
||||
QueryIP(ctx context.Context, domain string, clientIP net.IP, option dns.IPOption, disableCache bool) ([]net.IP, error)
|
||||
QueryIP(ctx context.Context, domain string, clientIP net.IP, option dns.IPOption, cs CacheStrategy) ([]net.IP, error)
|
||||
}
|
||||
|
||||
// Client is the interface for DNS client.
|
||||
@@ -50,10 +50,6 @@ func NewServer(dest net.Destination, dispatcher routing.Dispatcher) (Server, err
|
||||
return NewDoHLocalNameServer(u), nil
|
||||
case strings.EqualFold(u.Scheme, "quic+local"): // DNS-over-QUIC Local mode
|
||||
return NewQUICNameServer(u)
|
||||
case strings.EqualFold(u.Scheme, "tcp"): // DNS-over-TCP Remote mode
|
||||
return NewTCPNameServer(u, dispatcher)
|
||||
case strings.EqualFold(u.Scheme, "tcp+local"): // DNS-over-TCP Local mode
|
||||
return NewTCPLocalNameServer(u)
|
||||
case strings.EqualFold(u.String(), "fakedns"):
|
||||
return NewFakeDNSServer(), nil
|
||||
}
|
||||
@@ -68,7 +64,7 @@ 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 {
|
||||
@@ -86,11 +82,8 @@ func NewClient(ctx context.Context, ns *NameServer, clientIP net.IP, container r
|
||||
// Because the `localhost` DNS client will apend len(localTLDsAndDotlessDomains) rules into matcherInfos to match `geosite:private` default rule.
|
||||
// But `matcherInfos` has no enough length to add rules, which leads to core panics (rule index out of range).
|
||||
// To avoid this, the length of `matcherInfos` must be equal to the expected, so manually append it with Golang default zero value first for later modification.
|
||||
// Related issues:
|
||||
// https://github.com/v2fly/v2ray-core/issues/529
|
||||
// https://github.com/v2fly/v2ray-core/issues/719
|
||||
for i := 0; i < len(localTLDsAndDotlessDomains); i++ {
|
||||
*matcherInfos = append(*matcherInfos, &DomainMatcherInfo{
|
||||
*matcherInfos = append(*matcherInfos, DomainMatcherInfo{
|
||||
clientIdx: uint16(0),
|
||||
domainRuleIdx: uint16(0),
|
||||
})
|
||||
@@ -148,7 +141,6 @@ func NewClient(ctx context.Context, ns *NameServer, clientIP net.IP, container r
|
||||
|
||||
client.server = server
|
||||
client.clientIP = clientIP
|
||||
client.skipFallback = ns.SkipFallback
|
||||
client.domains = rules
|
||||
client.expectIPs = matchers
|
||||
return nil
|
||||
@@ -187,9 +179,9 @@ func (c *Client) Name() string {
|
||||
}
|
||||
|
||||
// QueryIP send DNS query to the name server with the client's IP.
|
||||
func (c *Client) QueryIP(ctx context.Context, domain string, option dns.IPOption, disableCache bool) ([]net.IP, error) {
|
||||
func (c *Client) QueryIP(ctx context.Context, domain string, option dns.IPOption, cs CacheStrategy) ([]net.IP, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, 4*time.Second)
|
||||
ips, err := c.server.QueryIP(ctx, domain, c.clientIP, option, disableCache)
|
||||
ips, err := c.server.QueryIP(ctx, domain, c.clientIP, option, cs)
|
||||
cancel()
|
||||
|
||||
if err != nil {
|
||||
|
@@ -5,14 +5,13 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/dns/dnsmessage"
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/log"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
@@ -24,6 +23,7 @@ import (
|
||||
dns_feature "github.com/xtls/xray-core/features/dns"
|
||||
"github.com/xtls/xray-core/features/routing"
|
||||
"github.com/xtls/xray-core/transport/internet"
|
||||
"golang.org/x/net/dns/dnsmessage"
|
||||
)
|
||||
|
||||
// DoHNameServer implemented DNS over HTTPS (RFC8484) Wire Format,
|
||||
@@ -32,16 +32,17 @@ import (
|
||||
type DoHNameServer struct {
|
||||
dispatcher routing.Dispatcher
|
||||
sync.RWMutex
|
||||
ips map[string]*record
|
||||
ips map[string]record
|
||||
pub *pubsub.Service
|
||||
cleanup *task.Periodic
|
||||
reqID uint32
|
||||
clientIP net.IP
|
||||
httpClient *http.Client
|
||||
dohURL string
|
||||
name string
|
||||
}
|
||||
|
||||
// NewDoHNameServer creates DOH server object for remote resolving.
|
||||
// NewDoHNameServer creates DOH server object for remote resolving
|
||||
func NewDoHNameServer(url *url.URL, dispatcher routing.Dispatcher) (*DoHNameServer, error) {
|
||||
newError("DNS: created Remote DOH client for ", url.String()).AtInfo().WriteToLog()
|
||||
s := baseDOHNameServer(url, "DOH")
|
||||
@@ -79,6 +80,12 @@ func NewDoHNameServer(url *url.URL, dispatcher routing.Dispatcher) (*DoHNameServ
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.Record(&log.AccessMessage{
|
||||
From: "DoH",
|
||||
To: s.dohURL,
|
||||
Status: log.AccessAccepted,
|
||||
Detour: "local",
|
||||
})
|
||||
|
||||
cc := common.ChainedClosable{}
|
||||
if cw, ok := link.Writer.(common.Closable); ok {
|
||||
@@ -137,7 +144,7 @@ func NewDoHLocalNameServer(url *url.URL) *DoHNameServer {
|
||||
|
||||
func baseDOHNameServer(url *url.URL, prefix string) *DoHNameServer {
|
||||
s := &DoHNameServer{
|
||||
ips: make(map[string]*record),
|
||||
ips: make(map[string]record),
|
||||
pub: pubsub.NewService(),
|
||||
name: prefix + "//" + url.Host,
|
||||
dohURL: url.String(),
|
||||
@@ -146,6 +153,7 @@ func baseDOHNameServer(url *url.URL, prefix string) *DoHNameServer {
|
||||
Interval: time.Minute,
|
||||
Execute: s.Cleanup,
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
@@ -181,7 +189,7 @@ func (s *DoHNameServer) Cleanup() error {
|
||||
}
|
||||
|
||||
if len(s.ips) == 0 {
|
||||
s.ips = make(map[string]*record)
|
||||
s.ips = make(map[string]record)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -191,10 +199,7 @@ func (s *DoHNameServer) updateIP(req *dnsRequest, ipRec *IPRecord) {
|
||||
elapsed := time.Since(req.start)
|
||||
|
||||
s.Lock()
|
||||
rec, found := s.ips[req.domain]
|
||||
if !found {
|
||||
rec = &record{}
|
||||
}
|
||||
rec := s.ips[req.domain]
|
||||
updated := false
|
||||
|
||||
switch req.reqType {
|
||||
@@ -204,7 +209,7 @@ func (s *DoHNameServer) updateIP(req *dnsRequest, ipRec *IPRecord) {
|
||||
updated = true
|
||||
}
|
||||
case dnsmessage.TypeAAAA:
|
||||
addr := make([]net.Address, 0, len(ipRec.IP))
|
||||
addr := make([]net.Address, 0)
|
||||
for _, ip := range ipRec.IP {
|
||||
if len(ip.IP()) == net.IPv6len {
|
||||
addr = append(addr, ip)
|
||||
@@ -256,7 +261,7 @@ func (s *DoHNameServer) sendQuery(ctx context.Context, domain string, clientIP n
|
||||
go func(r *dnsRequest) {
|
||||
// generate new context for each req, using same context
|
||||
// may cause reqs all aborted if any one encounter an error
|
||||
dnsCtx := ctx
|
||||
dnsCtx := context.Background()
|
||||
|
||||
// reserve internal dns server requested Inbound
|
||||
if inbound := session.InboundFromContext(ctx); inbound != nil {
|
||||
@@ -314,11 +319,11 @@ func (s *DoHNameServer) dohHTTPSContext(ctx context.Context, b []byte) ([]byte,
|
||||
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
io.Copy(io.Discard, resp.Body) // flush resp.Body so that the conn is reusable
|
||||
io.Copy(ioutil.Discard, resp.Body) // flush resp.Body so that the conn is reusable
|
||||
return nil, fmt.Errorf("DOH server returned code %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
return io.ReadAll(resp.Body)
|
||||
return ioutil.ReadAll(resp.Body)
|
||||
}
|
||||
|
||||
func (s *DoHNameServer) findIPsForDomain(domain string, option dns_feature.IPOption) ([]net.IP, error) {
|
||||
@@ -330,30 +335,30 @@ func (s *DoHNameServer) findIPsForDomain(domain string, option dns_feature.IPOpt
|
||||
return nil, errRecordNotFound
|
||||
}
|
||||
|
||||
var err4 error
|
||||
var err6 error
|
||||
var ips []net.Address
|
||||
var ip6 []net.Address
|
||||
|
||||
if option.IPv4Enable {
|
||||
ips, err4 = record.A.getIPs()
|
||||
var lastErr error
|
||||
if option.IPv6Enable && record.AAAA != nil && record.AAAA.RCode == dnsmessage.RCodeSuccess {
|
||||
aaaa, err := record.AAAA.getIPs()
|
||||
if err != nil {
|
||||
lastErr = err
|
||||
}
|
||||
ips = append(ips, aaaa...)
|
||||
}
|
||||
|
||||
if option.IPv6Enable {
|
||||
ip6, err6 = record.AAAA.getIPs()
|
||||
ips = append(ips, ip6...)
|
||||
if option.IPv4Enable && record.A != nil && record.A.RCode == dnsmessage.RCodeSuccess {
|
||||
a, err := record.A.getIPs()
|
||||
if err != nil {
|
||||
lastErr = err
|
||||
}
|
||||
ips = append(ips, a...)
|
||||
}
|
||||
|
||||
if len(ips) > 0 {
|
||||
return toNetIP(ips)
|
||||
}
|
||||
|
||||
if err4 != nil {
|
||||
return nil, err4
|
||||
}
|
||||
|
||||
if err6 != nil {
|
||||
return nil, err6
|
||||
if lastErr != nil {
|
||||
return nil, lastErr
|
||||
}
|
||||
|
||||
if (option.IPv4Enable && record.A != nil) || (option.IPv6Enable && record.AAAA != nil) {
|
||||
@@ -364,17 +369,19 @@ 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
|
||||
func (s *DoHNameServer) QueryIP(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption, cs CacheStrategy) ([]net.IP, error) { // nolint: dupl
|
||||
fqdn := Fqdn(domain)
|
||||
|
||||
if disableCache {
|
||||
if cs == CacheStrategy_Cache_DISABLE {
|
||||
newError("DNS cache is disabled. Querying IP for ", domain, " at ", s.name).AtDebug().WriteToLog()
|
||||
} else {
|
||||
ips, err := s.findIPsForDomain(fqdn, option)
|
||||
if err != errRecordNotFound {
|
||||
newError(s.name, " cache HIT ", domain, " -> ", ips).Base(err).AtDebug().WriteToLog()
|
||||
log.Record(&log.DNSLog{Server: s.name, Domain: domain, Result: ips, Status: log.DNSCacheHit, Elapsed: 0, Error: err})
|
||||
return ips, err
|
||||
if cs == CacheStrategy_Cache_NOERROR && err == nil {
|
||||
newError(s.name, " cache HIT ", domain, " -> ", ips).Base(err).AtDebug().WriteToLog()
|
||||
log.Record(&log.DNSLog{s.name, domain, ips, log.DNSCacheHit, 0, err})
|
||||
return ips, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -410,7 +417,7 @@ func (s *DoHNameServer) QueryIP(ctx context.Context, domain string, clientIP net
|
||||
for {
|
||||
ips, err := s.findIPsForDomain(fqdn, option)
|
||||
if err != errRecordNotFound {
|
||||
log.Record(&log.DNSLog{Server: s.name, Domain: domain, Result: ips, Status: log.DNSQueried, Elapsed: time.Since(start), Error: err})
|
||||
log.Record(&log.DNSLog{s.name, domain, ips, log.DNSQueried, time.Since(start), err})
|
||||
return ips, err
|
||||
}
|
||||
|
||||
|
@@ -23,7 +23,7 @@ func TestDOHNameServer(t *testing.T) {
|
||||
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
}, false)
|
||||
}, CacheStrategy_Cache_ALL)
|
||||
cancel()
|
||||
common.Must(err)
|
||||
if len(ips) == 0 {
|
||||
@@ -40,18 +40,18 @@ func TestDOHNameServerWithCache(t *testing.T) {
|
||||
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns_feature.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
}, false)
|
||||
}, CacheStrategy_Cache_ALL)
|
||||
cancel()
|
||||
common.Must(err)
|
||||
if len(ips) == 0 {
|
||||
t.Error("expect some ips, but got 0")
|
||||
}
|
||||
|
||||
ctx2, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||
ctx2, cancel := context.WithTimeout(context.Background(), time.Second*2)
|
||||
ips2, err := s.QueryIP(ctx2, "google.com", net.IP(nil), dns_feature.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
}, true)
|
||||
}, CacheStrategy_Cache_ALL)
|
||||
cancel()
|
||||
common.Must(err)
|
||||
if r := cmp.Diff(ips2, ips); r != "" {
|
||||
|
@@ -16,11 +16,13 @@ func NewFakeDNSServer() *FakeDNSServer {
|
||||
return &FakeDNSServer{}
|
||||
}
|
||||
|
||||
const FakeDNSName = "FakeDNS"
|
||||
|
||||
func (FakeDNSServer) Name() string {
|
||||
return "FakeDNS"
|
||||
return FakeDNSName
|
||||
}
|
||||
|
||||
func (f *FakeDNSServer) QueryIP(ctx context.Context, domain string, _ net.IP, opt dns.IPOption, _ bool) ([]net.IP, error) {
|
||||
func (f *FakeDNSServer) QueryIP(ctx context.Context, domain string, _ net.IP, _ dns.IPOption, _ CacheStrategy) ([]net.IP, error) {
|
||||
if f.fakeDNSEngine == nil {
|
||||
if err := core.RequireFeatures(ctx, func(fd dns.FakeDNSEngine) {
|
||||
f.fakeDNSEngine = fd
|
||||
@@ -28,12 +30,7 @@ func (f *FakeDNSServer) QueryIP(ctx context.Context, domain string, _ net.IP, op
|
||||
return nil, newError("Unable to locate a fake DNS Engine").Base(err).AtError()
|
||||
}
|
||||
}
|
||||
var ips []net.Address
|
||||
if fkr0, ok := f.fakeDNSEngine.(dns.FakeDNSEngineRev0); ok {
|
||||
ips = fkr0.GetFakeIPForDomain3(domain, opt.IPv4Enable, opt.IPv6Enable)
|
||||
} else {
|
||||
ips = f.fakeDNSEngine.GetFakeIPForDomain(domain)
|
||||
}
|
||||
ips := f.fakeDNSEngine.GetFakeIPForDomain(domain)
|
||||
|
||||
netIP, err := toNetIP(ips)
|
||||
if err != nil {
|
||||
@@ -42,8 +39,5 @@ func (f *FakeDNSServer) QueryIP(ctx context.Context, domain string, _ net.IP, op
|
||||
|
||||
newError(f.Name(), " got answer: ", domain, " -> ", ips).AtInfo().WriteToLog()
|
||||
|
||||
if len(netIP) > 0 {
|
||||
return netIP, nil
|
||||
}
|
||||
return nil, dns.ErrEmptyResponse
|
||||
return netIP, nil
|
||||
}
|
||||
|
@@ -2,11 +2,9 @@ package dns
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/xtls/xray-core/features/dns"
|
||||
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/features/dns"
|
||||
"github.com/xtls/xray-core/features/dns/localdns"
|
||||
)
|
||||
|
||||
@@ -15,21 +13,25 @@ type LocalNameServer struct {
|
||||
client *localdns.Client
|
||||
}
|
||||
|
||||
const errEmptyResponse = "No address associated with hostname"
|
||||
|
||||
// QueryIP implements Server.
|
||||
func (s *LocalNameServer) QueryIP(_ context.Context, domain string, _ net.IP, option dns.IPOption, _ bool) (ips []net.IP, err error) {
|
||||
ips, err = s.client.LookupIP(domain, option)
|
||||
func (s *LocalNameServer) QueryIP(_ context.Context, domain string, _ net.IP, option dns.IPOption, _ CacheStrategy) ([]net.IP, error) {
|
||||
var ips []net.IP
|
||||
var err error
|
||||
|
||||
if err != nil && strings.HasSuffix(err.Error(), errEmptyResponse) {
|
||||
err = dns.ErrEmptyResponse
|
||||
switch {
|
||||
case option.IPv4Enable && option.IPv6Enable:
|
||||
ips, err = s.client.LookupIP(domain)
|
||||
case option.IPv4Enable:
|
||||
ips, err = s.client.LookupIPv4(domain)
|
||||
case option.IPv6Enable:
|
||||
ips, err = s.client.LookupIPv6(domain)
|
||||
}
|
||||
|
||||
if len(ips) > 0 {
|
||||
newError("Localhost got answer: ", domain, " -> ", ips).AtInfo().WriteToLog()
|
||||
}
|
||||
|
||||
return
|
||||
return ips, err
|
||||
}
|
||||
|
||||
// Name implements Server.
|
||||
|
@@ -5,21 +5,19 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
|
||||
. "github.com/xtls/xray-core/app/dns"
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/features/dns"
|
||||
)
|
||||
|
||||
func TestLocalNameServer(t *testing.T) {
|
||||
s := NewLocalNameServer()
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||
ips, err := s.QueryIP(ctx, "google.com", net.IP{}, dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
}, false)
|
||||
}, CacheStrategy_Cache_ALL)
|
||||
cancel()
|
||||
common.Must(err)
|
||||
if len(ips) == 0 {
|
||||
|
@@ -8,8 +8,12 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/lucas-clemente/quic-go"
|
||||
"golang.org/x/net/dns/dnsmessage"
|
||||
"golang.org/x/net/http2"
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/buf"
|
||||
"github.com/xtls/xray-core/common/log"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/protocol/dns"
|
||||
"github.com/xtls/xray-core/common/session"
|
||||
@@ -17,25 +21,21 @@ import (
|
||||
"github.com/xtls/xray-core/common/task"
|
||||
dns_feature "github.com/xtls/xray-core/features/dns"
|
||||
"github.com/xtls/xray-core/transport/internet/tls"
|
||||
"golang.org/x/net/dns/dnsmessage"
|
||||
"golang.org/x/net/http2"
|
||||
)
|
||||
|
||||
// NextProtoDQ - During connection establishment, DNS/QUIC support is indicated
|
||||
// by selecting the ALPN token "dq" in the crypto handshake.
|
||||
const NextProtoDQ = "doq-i00"
|
||||
|
||||
const handshakeTimeout = time.Second * 8
|
||||
|
||||
// QUICNameServer implemented DNS over QUIC
|
||||
type QUICNameServer struct {
|
||||
sync.RWMutex
|
||||
ips map[string]*record
|
||||
ips map[string]record
|
||||
pub *pubsub.Service
|
||||
cleanup *task.Periodic
|
||||
reqID uint32
|
||||
name string
|
||||
destination *net.Destination
|
||||
destination net.Destination
|
||||
session quic.Session
|
||||
}
|
||||
|
||||
@@ -51,13 +51,13 @@ func NewQUICNameServer(url *url.URL) (*QUICNameServer, error) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
dest := net.UDPDestination(net.ParseAddress(url.Hostname()), port)
|
||||
dest := net.UDPDestination(net.DomainAddress(url.Hostname()), port)
|
||||
|
||||
s := &QUICNameServer{
|
||||
ips: make(map[string]*record),
|
||||
ips: make(map[string]record),
|
||||
pub: pubsub.NewService(),
|
||||
name: url.String(),
|
||||
destination: &dest,
|
||||
destination: dest,
|
||||
}
|
||||
s.cleanup = &task.Periodic{
|
||||
Interval: time.Minute,
|
||||
@@ -99,7 +99,7 @@ func (s *QUICNameServer) Cleanup() error {
|
||||
}
|
||||
|
||||
if len(s.ips) == 0 {
|
||||
s.ips = make(map[string]*record)
|
||||
s.ips = make(map[string]record)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -109,10 +109,7 @@ func (s *QUICNameServer) updateIP(req *dnsRequest, ipRec *IPRecord) {
|
||||
elapsed := time.Since(req.start)
|
||||
|
||||
s.Lock()
|
||||
rec, found := s.ips[req.domain]
|
||||
if !found {
|
||||
rec = &record{}
|
||||
}
|
||||
rec := s.ips[req.domain]
|
||||
updated := false
|
||||
|
||||
switch req.reqType {
|
||||
@@ -169,17 +166,22 @@ func (s *QUICNameServer) sendQuery(ctx context.Context, domain string, clientIP
|
||||
go func(r *dnsRequest) {
|
||||
// generate new context for each req, using same context
|
||||
// may cause reqs all aborted if any one encounter an error
|
||||
dnsCtx := ctx
|
||||
dnsCtx := context.Background()
|
||||
|
||||
// reserve internal dns server requested Inbound
|
||||
if inbound := session.InboundFromContext(ctx); inbound != nil {
|
||||
dnsCtx = session.ContextWithInbound(dnsCtx, inbound)
|
||||
}
|
||||
|
||||
dnsCtx = session.ContextWithContent(dnsCtx, &session.Content{
|
||||
Protocol: "quic",
|
||||
SkipDNSResolve: true,
|
||||
})
|
||||
dnsCtx = log.ContextWithAccessMessage(dnsCtx, &log.AccessMessage{
|
||||
From: "DoQ",
|
||||
To: s.name,
|
||||
Status: log.AccessAccepted,
|
||||
Reason: "",
|
||||
})
|
||||
|
||||
var cancel context.CancelFunc
|
||||
dnsCtx, cancel = context.WithDeadline(dnsCtx, deadline)
|
||||
@@ -232,30 +234,30 @@ func (s *QUICNameServer) findIPsForDomain(domain string, option dns_feature.IPOp
|
||||
return nil, errRecordNotFound
|
||||
}
|
||||
|
||||
var err4 error
|
||||
var err6 error
|
||||
var ips []net.Address
|
||||
var ip6 []net.Address
|
||||
|
||||
if option.IPv4Enable {
|
||||
ips, err4 = record.A.getIPs()
|
||||
var lastErr error
|
||||
if option.IPv6Enable && record.AAAA != nil && record.AAAA.RCode == dnsmessage.RCodeSuccess {
|
||||
aaaa, err := record.AAAA.getIPs()
|
||||
if err != nil {
|
||||
lastErr = err
|
||||
}
|
||||
ips = append(ips, aaaa...)
|
||||
}
|
||||
|
||||
if option.IPv6Enable {
|
||||
ip6, err6 = record.AAAA.getIPs()
|
||||
ips = append(ips, ip6...)
|
||||
if option.IPv4Enable && record.A != nil && record.A.RCode == dnsmessage.RCodeSuccess {
|
||||
a, err := record.A.getIPs()
|
||||
if err != nil {
|
||||
lastErr = err
|
||||
}
|
||||
ips = append(ips, a...)
|
||||
}
|
||||
|
||||
if len(ips) > 0 {
|
||||
return toNetIP(ips)
|
||||
}
|
||||
|
||||
if err4 != nil {
|
||||
return nil, err4
|
||||
}
|
||||
|
||||
if err6 != nil {
|
||||
return nil, err6
|
||||
if lastErr != nil {
|
||||
return nil, lastErr
|
||||
}
|
||||
|
||||
if (option.IPv4Enable && record.A != nil) || (option.IPv6Enable && record.AAAA != nil) {
|
||||
@@ -266,16 +268,19 @@ 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) {
|
||||
func (s *QUICNameServer) QueryIP(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption, cs CacheStrategy) ([]net.IP, error) {
|
||||
fqdn := Fqdn(domain)
|
||||
|
||||
if disableCache {
|
||||
if cs == CacheStrategy_Cache_DISABLE {
|
||||
newError("DNS cache is disabled. Querying IP for ", domain, " at ", s.name).AtDebug().WriteToLog()
|
||||
} else {
|
||||
ips, err := s.findIPsForDomain(fqdn, option)
|
||||
if err != errRecordNotFound {
|
||||
newError(s.name, " cache HIT ", domain, " -> ", ips).Base(err).AtDebug().WriteToLog()
|
||||
return ips, err
|
||||
if cs == CacheStrategy_Cache_NOERROR && err == nil {
|
||||
newError(s.name, " cache HIT ", domain, " -> ", ips).Base(err).AtDebug().WriteToLog()
|
||||
log.Record(&log.DNSLog{s.name, domain, ips, log.DNSCacheHit, 0, err})
|
||||
return ips, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,10 +311,12 @@ func (s *QUICNameServer) QueryIP(ctx context.Context, domain string, clientIP ne
|
||||
close(done)
|
||||
}()
|
||||
s.sendQuery(ctx, fqdn, clientIP, option)
|
||||
start := time.Now()
|
||||
|
||||
for {
|
||||
ips, err := s.findIPsForDomain(fqdn, option)
|
||||
if err != errRecordNotFound {
|
||||
log.Record(&log.DNSLog{s.name, domain, ips, log.DNSQueried, time.Since(start), err})
|
||||
return ips, err
|
||||
}
|
||||
|
||||
@@ -366,9 +373,7 @@ func (s *QUICNameServer) getSession() (quic.Session, error) {
|
||||
|
||||
func (s *QUICNameServer) openSession() (quic.Session, error) {
|
||||
tlsConfig := tls.Config{}
|
||||
quicConfig := &quic.Config{
|
||||
HandshakeIdleTimeout: handshakeTimeout,
|
||||
}
|
||||
quicConfig := &quic.Config{}
|
||||
|
||||
session, err := quic.DialAddrContext(context.Background(), s.destination.NetAddr(), tlsConfig.GetTLSConfig(tls.WithNextProto("http/1.1", http2.NextProtoTLS, NextProtoDQ)), quicConfig)
|
||||
if err != nil {
|
||||
|
@@ -6,13 +6,12 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/xtls/xray-core/features/dns"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
|
||||
. "github.com/xtls/xray-core/app/dns"
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
dns_feature "github.com/xtls/xray-core/features/dns"
|
||||
)
|
||||
|
||||
func TestQUICNameServer(t *testing.T) {
|
||||
@@ -20,11 +19,28 @@ func TestQUICNameServer(t *testing.T) {
|
||||
common.Must(err)
|
||||
s, err := NewQUICNameServer(url)
|
||||
common.Must(err)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
|
||||
ips, err := s.QueryIP(ctx, "google.com", net.IP(nil), dns.IPOption{
|
||||
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)
|
||||
}, CacheStrategy_Cache_ALL)
|
||||
cancel()
|
||||
common.Must(err)
|
||||
if len(ips) == 0 {
|
||||
t.Error("expect some ips, but got 0")
|
||||
}
|
||||
}
|
||||
|
||||
func TestQUICNameServerWithCache(t *testing.T) {
|
||||
url, err := url.Parse("quic://dns.adguard.com")
|
||||
common.Must(err)
|
||||
s, err := NewQUICNameServer(url)
|
||||
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,
|
||||
}, CacheStrategy_Cache_ALL)
|
||||
cancel()
|
||||
common.Must(err)
|
||||
if len(ips) == 0 {
|
||||
@@ -32,10 +48,10 @@ func TestQUICNameServer(t *testing.T) {
|
||||
}
|
||||
|
||||
ctx2, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||
ips2, err := s.QueryIP(ctx2, "google.com", net.IP(nil), dns.IPOption{
|
||||
ips2, err := s.QueryIP(ctx2, "google.com", net.IP(nil), dns_feature.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
}, true)
|
||||
}, CacheStrategy_Cache_ALL)
|
||||
cancel()
|
||||
common.Must(err)
|
||||
if r := cmp.Diff(ips2, ips); r != "" {
|
||||
|
@@ -1,362 +0,0 @@
|
||||
package dns
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"net/url"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/dns/dnsmessage"
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/buf"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/net/cnc"
|
||||
"github.com/xtls/xray-core/common/protocol/dns"
|
||||
"github.com/xtls/xray-core/common/session"
|
||||
"github.com/xtls/xray-core/common/signal/pubsub"
|
||||
"github.com/xtls/xray-core/common/task"
|
||||
dns_feature "github.com/xtls/xray-core/features/dns"
|
||||
"github.com/xtls/xray-core/features/routing"
|
||||
"github.com/xtls/xray-core/transport/internet"
|
||||
)
|
||||
|
||||
// TCPNameServer implemented DNS over TCP (RFC7766).
|
||||
type TCPNameServer struct {
|
||||
sync.RWMutex
|
||||
name string
|
||||
destination *net.Destination
|
||||
ips map[string]*record
|
||||
pub *pubsub.Service
|
||||
cleanup *task.Periodic
|
||||
reqID uint32
|
||||
dial func(context.Context) (net.Conn, error)
|
||||
}
|
||||
|
||||
// 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")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.dial = func(ctx context.Context) (net.Conn, error) {
|
||||
link, err := dispatcher.Dispatch(ctx, *s.destination)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return cnc.NewConnection(
|
||||
cnc.ConnectionInputMulti(link.Writer),
|
||||
cnc.ConnectionOutputMulti(link.Reader),
|
||||
), nil
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// NewTCPLocalNameServer creates DNS over TCP client object for local resolving
|
||||
func NewTCPLocalNameServer(url *url.URL) (*TCPNameServer, error) {
|
||||
s, err := baseTCPNameServer(url, "TCPL")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.dial = func(ctx context.Context) (net.Conn, error) {
|
||||
return internet.DialSystem(ctx, *s.destination, nil)
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func baseTCPNameServer(url *url.URL, prefix string) (*TCPNameServer, error) {
|
||||
var err error
|
||||
port := net.Port(53)
|
||||
if url.Port() != "" {
|
||||
port, err = net.PortFromString(url.Port())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
dest := net.TCPDestination(net.ParseAddress(url.Hostname()), port)
|
||||
|
||||
s := &TCPNameServer{
|
||||
destination: &dest,
|
||||
ips: make(map[string]*record),
|
||||
pub: pubsub.NewService(),
|
||||
name: prefix + "//" + dest.NetAddr(),
|
||||
}
|
||||
s.cleanup = &task.Periodic{
|
||||
Interval: time.Minute,
|
||||
Execute: s.Cleanup,
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// Name implements Server.
|
||||
func (s *TCPNameServer) Name() string {
|
||||
return s.name
|
||||
}
|
||||
|
||||
// Cleanup clears expired items from cache
|
||||
func (s *TCPNameServer) Cleanup() error {
|
||||
now := time.Now()
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
if len(s.ips) == 0 {
|
||||
return newError("nothing to do. stopping...")
|
||||
}
|
||||
|
||||
for domain, record := range s.ips {
|
||||
if record.A != nil && record.A.Expire.Before(now) {
|
||||
record.A = nil
|
||||
}
|
||||
if record.AAAA != nil && record.AAAA.Expire.Before(now) {
|
||||
record.AAAA = nil
|
||||
}
|
||||
|
||||
if record.A == nil && record.AAAA == nil {
|
||||
newError(s.name, " cleanup ", domain).AtDebug().WriteToLog()
|
||||
delete(s.ips, domain)
|
||||
} else {
|
||||
s.ips[domain] = record
|
||||
}
|
||||
}
|
||||
|
||||
if len(s.ips) == 0 {
|
||||
s.ips = make(map[string]*record)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *TCPNameServer) updateIP(req *dnsRequest, ipRec *IPRecord) {
|
||||
elapsed := time.Since(req.start)
|
||||
|
||||
s.Lock()
|
||||
rec, found := s.ips[req.domain]
|
||||
if !found {
|
||||
rec = &record{}
|
||||
}
|
||||
updated := false
|
||||
|
||||
switch req.reqType {
|
||||
case dnsmessage.TypeA:
|
||||
if isNewer(rec.A, ipRec) {
|
||||
rec.A = ipRec
|
||||
updated = true
|
||||
}
|
||||
case dnsmessage.TypeAAAA:
|
||||
addr := make([]net.Address, 0)
|
||||
for _, ip := range ipRec.IP {
|
||||
if len(ip.IP()) == net.IPv6len {
|
||||
addr = append(addr, ip)
|
||||
}
|
||||
}
|
||||
ipRec.IP = addr
|
||||
if isNewer(rec.AAAA, ipRec) {
|
||||
rec.AAAA = ipRec
|
||||
updated = true
|
||||
}
|
||||
}
|
||||
newError(s.name, " got answer: ", req.domain, " ", req.reqType, " -> ", ipRec.IP, " ", elapsed).AtInfo().WriteToLog()
|
||||
|
||||
if updated {
|
||||
s.ips[req.domain] = rec
|
||||
}
|
||||
switch req.reqType {
|
||||
case dnsmessage.TypeA:
|
||||
s.pub.Publish(req.domain+"4", nil)
|
||||
case dnsmessage.TypeAAAA:
|
||||
s.pub.Publish(req.domain+"6", nil)
|
||||
}
|
||||
s.Unlock()
|
||||
common.Must(s.cleanup.Start())
|
||||
}
|
||||
|
||||
func (s *TCPNameServer) newReqID() uint16 {
|
||||
return uint16(atomic.AddUint32(&s.reqID, 1))
|
||||
}
|
||||
|
||||
func (s *TCPNameServer) sendQuery(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption) {
|
||||
newError(s.name, " querying DNS for: ", domain).AtDebug().WriteToLog(session.ExportIDToError(ctx))
|
||||
|
||||
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(clientIP))
|
||||
|
||||
var deadline time.Time
|
||||
if d, ok := ctx.Deadline(); ok {
|
||||
deadline = d
|
||||
} else {
|
||||
deadline = time.Now().Add(time.Second * 5)
|
||||
}
|
||||
|
||||
for _, req := range reqs {
|
||||
go func(r *dnsRequest) {
|
||||
dnsCtx := ctx
|
||||
|
||||
if inbound := session.InboundFromContext(ctx); inbound != nil {
|
||||
dnsCtx = session.ContextWithInbound(dnsCtx, inbound)
|
||||
}
|
||||
|
||||
dnsCtx = session.ContextWithContent(dnsCtx, &session.Content{
|
||||
Protocol: "dns",
|
||||
SkipDNSResolve: true,
|
||||
})
|
||||
|
||||
var cancel context.CancelFunc
|
||||
dnsCtx, cancel = context.WithDeadline(dnsCtx, deadline)
|
||||
defer cancel()
|
||||
|
||||
b, err := dns.PackMessage(r.msg)
|
||||
if err != nil {
|
||||
newError("failed to pack dns query").Base(err).AtError().WriteToLog()
|
||||
return
|
||||
}
|
||||
|
||||
conn, err := s.dial(dnsCtx)
|
||||
if err != nil {
|
||||
newError("failed to dial namesever").Base(err).AtError().WriteToLog()
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
dnsReqBuf := buf.New()
|
||||
binary.Write(dnsReqBuf, binary.BigEndian, uint16(b.Len()))
|
||||
dnsReqBuf.Write(b.Bytes())
|
||||
b.Release()
|
||||
|
||||
_, err = conn.Write(dnsReqBuf.Bytes())
|
||||
if err != nil {
|
||||
newError("failed to send query").Base(err).AtError().WriteToLog()
|
||||
return
|
||||
}
|
||||
dnsReqBuf.Release()
|
||||
|
||||
respBuf := buf.New()
|
||||
defer respBuf.Release()
|
||||
n, err := respBuf.ReadFullFrom(conn, 2)
|
||||
if err != nil && n == 0 {
|
||||
newError("failed to read response length").Base(err).AtError().WriteToLog()
|
||||
return
|
||||
}
|
||||
var length int16
|
||||
err = binary.Read(bytes.NewReader(respBuf.Bytes()), binary.BigEndian, &length)
|
||||
if err != nil {
|
||||
newError("failed to parse response length").Base(err).AtError().WriteToLog()
|
||||
return
|
||||
}
|
||||
respBuf.Clear()
|
||||
n, err = respBuf.ReadFullFrom(conn, int32(length))
|
||||
if err != nil && n == 0 {
|
||||
newError("failed to read response length").Base(err).AtError().WriteToLog()
|
||||
return
|
||||
}
|
||||
|
||||
rec, err := parseResponse(respBuf.Bytes())
|
||||
if err != nil {
|
||||
newError("failed to parse DNS over TCP response").Base(err).AtError().WriteToLog()
|
||||
return
|
||||
}
|
||||
|
||||
s.updateIP(r, rec)
|
||||
}(req)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *TCPNameServer) findIPsForDomain(domain string, option dns_feature.IPOption) ([]net.IP, error) {
|
||||
s.RLock()
|
||||
record, found := s.ips[domain]
|
||||
s.RUnlock()
|
||||
|
||||
if !found {
|
||||
return nil, errRecordNotFound
|
||||
}
|
||||
|
||||
var err4 error
|
||||
var err6 error
|
||||
var ips []net.Address
|
||||
var ip6 []net.Address
|
||||
|
||||
if option.IPv4Enable {
|
||||
ips, err4 = record.A.getIPs()
|
||||
}
|
||||
|
||||
if option.IPv6Enable {
|
||||
ip6, err6 = record.AAAA.getIPs()
|
||||
ips = append(ips, ip6...)
|
||||
}
|
||||
|
||||
if len(ips) > 0 {
|
||||
return toNetIP(ips)
|
||||
}
|
||||
|
||||
if err4 != nil {
|
||||
return nil, err4
|
||||
}
|
||||
|
||||
if err6 != nil {
|
||||
return nil, err6
|
||||
}
|
||||
|
||||
return nil, dns_feature.ErrEmptyResponse
|
||||
}
|
||||
|
||||
// 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)
|
||||
|
||||
if disableCache {
|
||||
newError("DNS cache is disabled. Querying IP for ", domain, " at ", s.name).AtDebug().WriteToLog()
|
||||
} else {
|
||||
ips, err := s.findIPsForDomain(fqdn, option)
|
||||
if err != errRecordNotFound {
|
||||
newError(s.name, " cache HIT ", domain, " -> ", ips).Base(err).AtDebug().WriteToLog()
|
||||
return ips, err
|
||||
}
|
||||
}
|
||||
|
||||
// ipv4 and ipv6 belong to different subscription groups
|
||||
var sub4, sub6 *pubsub.Subscriber
|
||||
if option.IPv4Enable {
|
||||
sub4 = s.pub.Subscribe(fqdn + "4")
|
||||
defer sub4.Close()
|
||||
}
|
||||
if option.IPv6Enable {
|
||||
sub6 = s.pub.Subscribe(fqdn + "6")
|
||||
defer sub6.Close()
|
||||
}
|
||||
done := make(chan interface{})
|
||||
go func() {
|
||||
if sub4 != nil {
|
||||
select {
|
||||
case <-sub4.Wait():
|
||||
case <-ctx.Done():
|
||||
}
|
||||
}
|
||||
if sub6 != nil {
|
||||
select {
|
||||
case <-sub6.Wait():
|
||||
case <-ctx.Done():
|
||||
}
|
||||
}
|
||||
close(done)
|
||||
}()
|
||||
s.sendQuery(ctx, fqdn, clientIP, option)
|
||||
|
||||
for {
|
||||
ips, err := s.findIPsForDomain(fqdn, option)
|
||||
if err != errRecordNotFound {
|
||||
return ips, err
|
||||
}
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
case <-done:
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,60 +0,0 @@
|
||||
package dns_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/url"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
|
||||
. "github.com/xtls/xray-core/app/dns"
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
dns_feature "github.com/xtls/xray-core/features/dns"
|
||||
)
|
||||
|
||||
func TestTCPLocalNameServer(t *testing.T) {
|
||||
url, err := url.Parse("tcp+local://8.8.8.8")
|
||||
common.Must(err)
|
||||
s, err := NewTCPLocalNameServer(url)
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTCPLocalNameServerWithCache(t *testing.T) {
|
||||
url, err := url.Parse("tcp+local://8.8.8.8")
|
||||
common.Must(err)
|
||||
s, err := NewTCPLocalNameServer(url)
|
||||
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")
|
||||
}
|
||||
|
||||
ctx2, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||
ips2, err := s.QueryIP(ctx2, "google.com", net.IP(nil), dns_feature.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
}, true)
|
||||
cancel()
|
||||
common.Must(err)
|
||||
if r := cmp.Diff(ips2, ips); r != "" {
|
||||
t.Fatal(r)
|
||||
}
|
||||
}
|
@@ -7,8 +7,6 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/dns/dnsmessage"
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/log"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
@@ -20,15 +18,15 @@ import (
|
||||
dns_feature "github.com/xtls/xray-core/features/dns"
|
||||
"github.com/xtls/xray-core/features/routing"
|
||||
"github.com/xtls/xray-core/transport/internet/udp"
|
||||
"golang.org/x/net/dns/dnsmessage"
|
||||
)
|
||||
|
||||
// ClassicNameServer implemented traditional UDP DNS.
|
||||
type ClassicNameServer struct {
|
||||
sync.RWMutex
|
||||
name string
|
||||
address *net.Destination
|
||||
ips map[string]*record
|
||||
requests map[uint16]*dnsRequest
|
||||
address net.Destination
|
||||
ips map[string]record
|
||||
requests map[uint16]dnsRequest
|
||||
pub *pubsub.Service
|
||||
udpServer *udp.Dispatcher
|
||||
cleanup *task.Periodic
|
||||
@@ -43,9 +41,9 @@ func NewClassicNameServer(address net.Destination, dispatcher routing.Dispatcher
|
||||
}
|
||||
|
||||
s := &ClassicNameServer{
|
||||
address: &address,
|
||||
ips: make(map[string]*record),
|
||||
requests: make(map[uint16]*dnsRequest),
|
||||
address: address,
|
||||
ips: make(map[string]record),
|
||||
requests: make(map[uint16]dnsRequest),
|
||||
pub: pubsub.NewService(),
|
||||
name: strings.ToUpper(address.String()),
|
||||
}
|
||||
@@ -82,7 +80,6 @@ func (s *ClassicNameServer) Cleanup() error {
|
||||
}
|
||||
|
||||
if record.A == nil && record.AAAA == nil {
|
||||
newError(s.name, " cleanup ", domain).AtDebug().WriteToLog()
|
||||
delete(s.ips, domain)
|
||||
} else {
|
||||
s.ips[domain] = record
|
||||
@@ -90,7 +87,7 @@ func (s *ClassicNameServer) Cleanup() error {
|
||||
}
|
||||
|
||||
if len(s.ips) == 0 {
|
||||
s.ips = make(map[string]*record)
|
||||
s.ips = make(map[string]record)
|
||||
}
|
||||
|
||||
for id, req := range s.requests {
|
||||
@@ -100,7 +97,7 @@ func (s *ClassicNameServer) Cleanup() error {
|
||||
}
|
||||
|
||||
if len(s.requests) == 0 {
|
||||
s.requests = make(map[uint16]*dnsRequest)
|
||||
s.requests = make(map[uint16]dnsRequest)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -138,17 +135,15 @@ func (s *ClassicNameServer) HandleResponse(ctx context.Context, packet *udp_prot
|
||||
elapsed := time.Since(req.start)
|
||||
newError(s.name, " got answer: ", req.domain, " ", req.reqType, " -> ", ipRec.IP, " ", elapsed).AtInfo().WriteToLog()
|
||||
if len(req.domain) > 0 && (rec.A != nil || rec.AAAA != nil) {
|
||||
s.updateIP(req.domain, &rec)
|
||||
s.updateIP(req.domain, rec)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ClassicNameServer) updateIP(domain string, newRec *record) {
|
||||
func (s *ClassicNameServer) updateIP(domain string, newRec record) {
|
||||
s.Lock()
|
||||
|
||||
rec, found := s.ips[domain]
|
||||
if !found {
|
||||
rec = &record{}
|
||||
}
|
||||
newError(s.name, " updating IP records for domain:", domain).AtDebug().WriteToLog()
|
||||
rec := s.ips[domain]
|
||||
|
||||
updated := false
|
||||
if isNewer(rec.A, newRec.A) {
|
||||
@@ -161,7 +156,6 @@ func (s *ClassicNameServer) updateIP(domain string, newRec *record) {
|
||||
}
|
||||
|
||||
if updated {
|
||||
newError(s.name, " updating IP records for domain:", domain).AtDebug().WriteToLog()
|
||||
s.ips[domain] = rec
|
||||
}
|
||||
if newRec.A != nil {
|
||||
@@ -184,7 +178,7 @@ func (s *ClassicNameServer) addPendingRequest(req *dnsRequest) {
|
||||
|
||||
id := req.msg.ID
|
||||
req.expire = time.Now().Add(time.Second * 8)
|
||||
s.requests[id] = req
|
||||
s.requests[id] = *req
|
||||
}
|
||||
|
||||
func (s *ClassicNameServer) sendQuery(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption) {
|
||||
@@ -199,7 +193,6 @@ func (s *ClassicNameServer) sendQuery(ctx context.Context, domain string, client
|
||||
if inbound := session.InboundFromContext(ctx); inbound != nil {
|
||||
udpCtx = session.ContextWithInbound(udpCtx, inbound)
|
||||
}
|
||||
|
||||
udpCtx = session.ContextWithContent(udpCtx, &session.Content{
|
||||
Protocol: "dns",
|
||||
})
|
||||
@@ -209,7 +202,7 @@ func (s *ClassicNameServer) sendQuery(ctx context.Context, domain string, client
|
||||
Status: log.AccessAccepted,
|
||||
Reason: "",
|
||||
})
|
||||
s.udpServer.Dispatch(udpCtx, *s.address, b)
|
||||
s.udpServer.Dispatch(udpCtx, s.address, b)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,47 +215,49 @@ func (s *ClassicNameServer) findIPsForDomain(domain string, option dns_feature.I
|
||||
return nil, errRecordNotFound
|
||||
}
|
||||
|
||||
var err4 error
|
||||
var err6 error
|
||||
var ips []net.Address
|
||||
var ip6 []net.Address
|
||||
|
||||
var lastErr error
|
||||
if option.IPv4Enable {
|
||||
ips, err4 = record.A.getIPs()
|
||||
a, err := record.A.getIPs()
|
||||
if err != nil {
|
||||
lastErr = err
|
||||
}
|
||||
ips = append(ips, a...)
|
||||
}
|
||||
|
||||
if option.IPv6Enable {
|
||||
ip6, err6 = record.AAAA.getIPs()
|
||||
ips = append(ips, ip6...)
|
||||
aaaa, err := record.AAAA.getIPs()
|
||||
if err != nil {
|
||||
lastErr = err
|
||||
}
|
||||
ips = append(ips, aaaa...)
|
||||
}
|
||||
|
||||
if len(ips) > 0 {
|
||||
return toNetIP(ips)
|
||||
}
|
||||
|
||||
if err4 != nil {
|
||||
return nil, err4
|
||||
}
|
||||
|
||||
if err6 != nil {
|
||||
return nil, err6
|
||||
if lastErr != nil {
|
||||
return nil, lastErr
|
||||
}
|
||||
|
||||
return nil, dns_feature.ErrEmptyResponse
|
||||
}
|
||||
|
||||
// QueryIP implements Server.
|
||||
func (s *ClassicNameServer) QueryIP(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption, disableCache bool) ([]net.IP, error) {
|
||||
func (s *ClassicNameServer) QueryIP(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption, cs CacheStrategy) ([]net.IP, error) {
|
||||
fqdn := Fqdn(domain)
|
||||
|
||||
if disableCache {
|
||||
if cs == CacheStrategy_Cache_DISABLE {
|
||||
newError("DNS cache is disabled. Querying IP for ", domain, " at ", s.name).AtDebug().WriteToLog()
|
||||
} else {
|
||||
ips, err := s.findIPsForDomain(fqdn, option)
|
||||
if err != errRecordNotFound {
|
||||
newError(s.name, " cache HIT ", domain, " -> ", ips).Base(err).AtDebug().WriteToLog()
|
||||
log.Record(&log.DNSLog{Server: s.name, Domain: domain, Result: ips, Status: log.DNSCacheHit, Elapsed: 0, Error: err})
|
||||
return ips, err
|
||||
if cs == CacheStrategy_Cache_NOERROR && err == nil {
|
||||
newError(s.name, " cache HIT ", domain, " -> ", ips).Base(err).AtDebug().WriteToLog()
|
||||
log.Record(&log.DNSLog{s.name, domain, ips, log.DNSCacheHit, 0, err})
|
||||
return ips, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -298,7 +293,7 @@ func (s *ClassicNameServer) QueryIP(ctx context.Context, domain string, clientIP
|
||||
for {
|
||||
ips, err := s.findIPsForDomain(fqdn, option)
|
||||
if err != errRecordNotFound {
|
||||
log.Record(&log.DNSLog{Server: s.name, Domain: domain, Result: ips, Status: log.DNSQueried, Elapsed: time.Since(start), Error: err})
|
||||
log.Record(&log.DNSLog{s.name, domain, ips, log.DNSQueried, time.Since(start), err})
|
||||
return ips, err
|
||||
}
|
||||
|
||||
|
16
app/dns/options.go
Normal file
16
app/dns/options.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package dns
|
||||
|
||||
import "github.com/xtls/xray-core/features/dns"
|
||||
|
||||
func isIPQuery(o *dns.IPOption) bool {
|
||||
return o.IPv4Enable || o.IPv6Enable
|
||||
}
|
||||
|
||||
func canQueryOnClient(o *dns.IPOption, c *Client) bool {
|
||||
isIPClient := !(c.Name() == FakeDNSName)
|
||||
return isIPClient && isIPQuery(o)
|
||||
}
|
||||
|
||||
func isQuery(o *dns.IPOption) bool {
|
||||
return !(o.IPv4Enable || o.IPv6Enable || o.FakeEnable)
|
||||
}
|
@@ -1,12 +1,13 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.27.1
|
||||
// protoc v3.18.0
|
||||
// protoc-gen-go v1.25.0
|
||||
// protoc v3.14.0
|
||||
// source: app/log/command/config.proto
|
||||
|
||||
package command
|
||||
|
||||
import (
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
@@ -20,6 +21,10 @@ const (
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||
// of the legacy proto package is being used.
|
||||
const _ = proto.ProtoPackageIsVersion4
|
||||
|
||||
type Config struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
|
@@ -1,12 +1,13 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.27.1
|
||||
// protoc v3.18.0
|
||||
// protoc-gen-go v1.25.0
|
||||
// protoc v3.14.0
|
||||
// source: app/log/config.proto
|
||||
|
||||
package log
|
||||
|
||||
import (
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
log "github.com/xtls/xray-core/common/log"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
@@ -21,6 +22,10 @@ const (
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||
// of the legacy proto package is being used.
|
||||
const _ = proto.ProtoPackageIsVersion4
|
||||
|
||||
type LogType int32
|
||||
|
||||
const (
|
||||
@@ -129,7 +134,7 @@ func (x *Config) GetErrorLogLevel() log.Severity {
|
||||
if x != nil {
|
||||
return x.ErrorLogLevel
|
||||
}
|
||||
return log.Severity(0)
|
||||
return log.Severity_Unknown
|
||||
}
|
||||
|
||||
func (x *Config) GetErrorLogPath() string {
|
||||
|
@@ -11,7 +11,9 @@ type HandlerCreatorOptions struct {
|
||||
|
||||
type HandlerCreator func(LogType, HandlerCreatorOptions) (log.Handler, error)
|
||||
|
||||
var handlerCreatorMap = make(map[LogType]HandlerCreator)
|
||||
var (
|
||||
handlerCreatorMap = make(map[LogType]HandlerCreator)
|
||||
)
|
||||
|
||||
func RegisterHandlerCreator(logType LogType, f HandlerCreator) error {
|
||||
if f == nil {
|
||||
|
@@ -5,7 +5,6 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
|
||||
"github.com/xtls/xray-core/app/log"
|
||||
"github.com/xtls/xray-core/common"
|
||||
clog "github.com/xtls/xray-core/common/log"
|
||||
|
@@ -1,12 +1,13 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.27.1
|
||||
// protoc v3.18.0
|
||||
// protoc-gen-go v1.25.0
|
||||
// protoc v3.14.0
|
||||
// source: app/policy/config.proto
|
||||
|
||||
package policy
|
||||
|
||||
import (
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
@@ -20,6 +21,10 @@ const (
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||
// of the legacy proto package is being used.
|
||||
const _ = proto.ProtoPackageIsVersion4
|
||||
|
||||
type Second struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
|
@@ -1,12 +1,13 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.27.1
|
||||
// protoc v3.18.0
|
||||
// protoc-gen-go v1.25.0
|
||||
// protoc v3.14.0
|
||||
// source: app/proxyman/command/command.proto
|
||||
|
||||
package command
|
||||
|
||||
import (
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
protocol "github.com/xtls/xray-core/common/protocol"
|
||||
serial "github.com/xtls/xray-core/common/serial"
|
||||
core "github.com/xtls/xray-core/core"
|
||||
@@ -23,6 +24,10 @@ const (
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||
// of the legacy proto package is being used.
|
||||
const _ = proto.ProtoPackageIsVersion4
|
||||
|
||||
type AddUserOperation struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
|
@@ -1,12 +1,13 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.27.1
|
||||
// protoc v3.18.0
|
||||
// protoc-gen-go v1.25.0
|
||||
// protoc (unknown)
|
||||
// source: app/proxyman/config.proto
|
||||
|
||||
package proxyman
|
||||
|
||||
import (
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
net "github.com/xtls/xray-core/common/net"
|
||||
serial "github.com/xtls/xray-core/common/serial"
|
||||
internet "github.com/xtls/xray-core/transport/internet"
|
||||
@@ -23,6 +24,10 @@ const (
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||
// of the legacy proto package is being used.
|
||||
const _ = proto.ProtoPackageIsVersion4
|
||||
|
||||
type KnownProtocols int32
|
||||
|
||||
const (
|
||||
|
@@ -6,8 +6,6 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/xtls/xray-core/transport/internet/stat"
|
||||
|
||||
"github.com/xtls/xray-core/app/proxyman"
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/buf"
|
||||
@@ -56,7 +54,7 @@ func getTProxyType(s *internet.MemoryStreamConfig) internet.SocketConfig_TProxyM
|
||||
return s.SocketSettings.Tproxy
|
||||
}
|
||||
|
||||
func (w *tcpWorker) callback(conn stat.Connection) {
|
||||
func (w *tcpWorker) callback(conn internet.Connection) {
|
||||
ctx, cancel := context.WithCancel(w.ctx)
|
||||
sid := session.NewID()
|
||||
ctx = session.ContextWithID(ctx, sid)
|
||||
@@ -82,7 +80,7 @@ func (w *tcpWorker) callback(conn stat.Connection) {
|
||||
}
|
||||
|
||||
if w.uplinkCounter != nil || w.downlinkCounter != nil {
|
||||
conn = &stat.CounterConnection{
|
||||
conn = &internet.StatCouterConnection{
|
||||
Connection: conn,
|
||||
ReadCounter: w.uplinkCounter,
|
||||
WriteCounter: w.downlinkCounter,
|
||||
@@ -119,7 +117,7 @@ func (w *tcpWorker) Proxy() proxy.Inbound {
|
||||
|
||||
func (w *tcpWorker) Start() error {
|
||||
ctx := context.Background()
|
||||
hub, err := internet.ListenTCP(ctx, w.address, w.port, w.stream, func(conn stat.Connection) {
|
||||
hub, err := internet.ListenTCP(ctx, w.address, w.port, w.stream, func(conn internet.Connection) {
|
||||
go w.callback(conn)
|
||||
})
|
||||
if err != nil {
|
||||
@@ -438,13 +436,13 @@ type dsWorker struct {
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
func (w *dsWorker) callback(conn stat.Connection) {
|
||||
func (w *dsWorker) callback(conn internet.Connection) {
|
||||
ctx, cancel := context.WithCancel(w.ctx)
|
||||
sid := session.NewID()
|
||||
ctx = session.ContextWithID(ctx, sid)
|
||||
|
||||
if w.uplinkCounter != nil || w.downlinkCounter != nil {
|
||||
conn = &stat.CounterConnection{
|
||||
conn = &internet.StatCouterConnection{
|
||||
Connection: conn,
|
||||
ReadCounter: w.uplinkCounter,
|
||||
WriteCounter: w.downlinkCounter,
|
||||
@@ -482,10 +480,9 @@ func (w *dsWorker) Proxy() proxy.Inbound {
|
||||
func (w *dsWorker) Port() net.Port {
|
||||
return net.Port(0)
|
||||
}
|
||||
|
||||
func (w *dsWorker) Start() error {
|
||||
ctx := context.Background()
|
||||
hub, err := internet.ListenUnix(ctx, w.address, w.stream, func(conn stat.Connection) {
|
||||
hub, err := internet.ListenUnix(ctx, w.address, w.stream, func(conn internet.Connection) {
|
||||
go w.callback(conn)
|
||||
})
|
||||
if err != nil {
|
||||
|
@@ -3,8 +3,6 @@ package outbound
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/xtls/xray-core/transport/internet/stat"
|
||||
|
||||
"github.com/xtls/xray-core/app/proxyman"
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/mux"
|
||||
@@ -160,7 +158,7 @@ func (h *Handler) Address() net.Address {
|
||||
}
|
||||
|
||||
// Dial implements internet.Dialer.
|
||||
func (h *Handler) Dial(ctx context.Context, dest net.Destination) (stat.Connection, error) {
|
||||
func (h *Handler) Dial(ctx context.Context, dest net.Destination) (internet.Connection, error) {
|
||||
if h.senderSettings != nil {
|
||||
if h.senderSettings.ProxySettings.HasTag() {
|
||||
tag := h.senderSettings.ProxySettings.Tag
|
||||
@@ -203,9 +201,9 @@ func (h *Handler) Dial(ctx context.Context, dest net.Destination) (stat.Connecti
|
||||
return h.getStatCouterConnection(conn), err
|
||||
}
|
||||
|
||||
func (h *Handler) getStatCouterConnection(conn stat.Connection) stat.Connection {
|
||||
func (h *Handler) getStatCouterConnection(conn internet.Connection) internet.Connection {
|
||||
if h.uplinkCounter != nil || h.downlinkCounter != nil {
|
||||
return &stat.CounterConnection{
|
||||
return &internet.StatCouterConnection{
|
||||
Connection: conn,
|
||||
ReadCounter: h.downlinkCounter,
|
||||
WriteCounter: h.uplinkCounter,
|
||||
|
@@ -4,8 +4,6 @@ import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/xtls/xray-core/transport/internet/stat"
|
||||
|
||||
"github.com/xtls/xray-core/app/policy"
|
||||
. "github.com/xtls/xray-core/app/proxyman/outbound"
|
||||
"github.com/xtls/xray-core/app/stats"
|
||||
@@ -14,6 +12,7 @@ import (
|
||||
core "github.com/xtls/xray-core/core"
|
||||
"github.com/xtls/xray-core/features/outbound"
|
||||
"github.com/xtls/xray-core/proxy/freedom"
|
||||
"github.com/xtls/xray-core/transport/internet"
|
||||
)
|
||||
|
||||
func TestInterfaces(t *testing.T) {
|
||||
@@ -45,9 +44,9 @@ func TestOutboundWithoutStatCounter(t *testing.T) {
|
||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
|
||||
})
|
||||
conn, _ := h.(*Handler).Dial(ctx, net.TCPDestination(net.DomainAddress("localhost"), 13146))
|
||||
_, ok := conn.(*stat.CounterConnection)
|
||||
_, ok := conn.(*internet.StatCouterConnection)
|
||||
if ok {
|
||||
t.Errorf("Expected conn to not be CounterConnection")
|
||||
t.Errorf("Expected conn to not be StatCouterConnection")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,8 +73,8 @@ func TestOutboundWithStatCounter(t *testing.T) {
|
||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
|
||||
})
|
||||
conn, _ := h.(*Handler).Dial(ctx, net.TCPDestination(net.DomainAddress("localhost"), 13146))
|
||||
_, ok := conn.(*stat.CounterConnection)
|
||||
_, ok := conn.(*internet.StatCouterConnection)
|
||||
if !ok {
|
||||
t.Errorf("Expected conn to be CounterConnection")
|
||||
t.Errorf("Expected conn to be StatCouterConnection")
|
||||
}
|
||||
}
|
||||
|
@@ -5,7 +5,6 @@ import (
|
||||
"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"
|
||||
|
@@ -1,12 +1,13 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.27.1
|
||||
// protoc v3.18.0
|
||||
// protoc-gen-go v1.25.0
|
||||
// protoc v3.14.0
|
||||
// source: app/reverse/config.proto
|
||||
|
||||
package reverse
|
||||
|
||||
import (
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
@@ -20,6 +21,10 @@ const (
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||
// of the legacy proto package is being used.
|
||||
const _ = proto.ProtoPackageIsVersion4
|
||||
|
||||
type Control_State int32
|
||||
|
||||
const (
|
||||
|
@@ -6,7 +6,6 @@ import (
|
||||
"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"
|
||||
|
@@ -9,7 +9,8 @@ type BalancingStrategy interface {
|
||||
PickOutbound([]string) string
|
||||
}
|
||||
|
||||
type RandomStrategy struct{}
|
||||
type RandomStrategy struct {
|
||||
}
|
||||
|
||||
func (s *RandomStrategy) PickOutbound(tags []string) string {
|
||||
n := len(tags)
|
||||
|
@@ -1,12 +1,13 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.27.1
|
||||
// protoc v3.18.0
|
||||
// protoc-gen-go v1.25.0
|
||||
// protoc v3.14.0
|
||||
// source: app/router/command/command.proto
|
||||
|
||||
package command
|
||||
|
||||
import (
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
net "github.com/xtls/xray-core/common/net"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
@@ -21,6 +22,10 @@ const (
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||
// of the legacy proto package is being used.
|
||||
const _ = proto.ProtoPackageIsVersion4
|
||||
|
||||
// RoutingContext is the context with information relative to routing process.
|
||||
// It conforms to the structure of xray.features.routing.Context and
|
||||
// xray.features.routing.Route.
|
||||
@@ -86,7 +91,7 @@ func (x *RoutingContext) GetNetwork() net.Network {
|
||||
if x != nil {
|
||||
return x.Network
|
||||
}
|
||||
return net.Network(0)
|
||||
return net.Network_Unknown
|
||||
}
|
||||
|
||||
func (x *RoutingContext) GetSourceIPs() [][]byte {
|
||||
|
@@ -8,9 +8,6 @@ import (
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/test/bufconn"
|
||||
|
||||
"github.com/xtls/xray-core/app/router"
|
||||
. "github.com/xtls/xray-core/app/router/command"
|
||||
"github.com/xtls/xray-core/app/stats"
|
||||
@@ -18,6 +15,8 @@ import (
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/features/routing"
|
||||
"github.com/xtls/xray-core/testing/mocks"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/test/bufconn"
|
||||
)
|
||||
|
||||
func TestServiceSubscribeRoutingStats(t *testing.T) {
|
||||
@@ -45,6 +44,7 @@ func TestServiceSubscribeRoutingStats(t *testing.T) {
|
||||
{SourceIPs: [][]byte{{127, 0, 0, 1}}, Attributes: map[string]string{"attr": "value"}, OutboundTag: "out"},
|
||||
}
|
||||
errCh := make(chan error)
|
||||
nextPub := make(chan struct{})
|
||||
|
||||
// Server goroutine
|
||||
go func() {
|
||||
@@ -76,6 +76,13 @@ func TestServiceSubscribeRoutingStats(t *testing.T) {
|
||||
if err := publishTestCases(); err != nil {
|
||||
errCh <- err
|
||||
}
|
||||
|
||||
// Wait for next round of publishing
|
||||
<-nextPub
|
||||
|
||||
if err := publishTestCases(); err != nil {
|
||||
errCh <- err
|
||||
}
|
||||
}()
|
||||
|
||||
// Client goroutine
|
||||
@@ -137,92 +144,6 @@ func TestServiceSubscribeRoutingStats(t *testing.T) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := testRetrievingAllFields(); err != nil {
|
||||
errCh <- err
|
||||
}
|
||||
errCh <- nil // Client passed all tests successfully
|
||||
}()
|
||||
|
||||
// Wait for goroutines to complete
|
||||
select {
|
||||
case <-time.After(2 * time.Second):
|
||||
t.Fatal("Test timeout after 2s")
|
||||
case err := <-errCh:
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestServiceSubscribeSubsetOfFields(t *testing.T) {
|
||||
c := stats.NewChannel(&stats.ChannelConfig{
|
||||
SubscriberLimit: 1,
|
||||
BufferSize: 0,
|
||||
Blocking: true,
|
||||
})
|
||||
common.Must(c.Start())
|
||||
defer c.Close()
|
||||
|
||||
lis := bufconn.Listen(1024 * 1024)
|
||||
bufDialer := func(context.Context, string) (net.Conn, error) {
|
||||
return lis.Dial()
|
||||
}
|
||||
|
||||
testCases := []*RoutingContext{
|
||||
{InboundTag: "in", OutboundTag: "out"},
|
||||
{TargetIPs: [][]byte{{1, 2, 3, 4}}, TargetPort: 8080, OutboundTag: "out"},
|
||||
{TargetDomain: "example.com", TargetPort: 443, OutboundTag: "out"},
|
||||
{SourcePort: 9999, TargetPort: 9999, OutboundTag: "out"},
|
||||
{Network: net.Network_UDP, OutboundGroupTags: []string{"outergroup", "innergroup"}, OutboundTag: "out"},
|
||||
{Protocol: "bittorrent", OutboundTag: "blocked"},
|
||||
{User: "example@example.com", OutboundTag: "out"},
|
||||
{SourceIPs: [][]byte{{127, 0, 0, 1}}, Attributes: map[string]string{"attr": "value"}, OutboundTag: "out"},
|
||||
}
|
||||
errCh := make(chan error)
|
||||
|
||||
// Server goroutine
|
||||
go func() {
|
||||
server := grpc.NewServer()
|
||||
RegisterRoutingServiceServer(server, NewRoutingServer(nil, c))
|
||||
errCh <- server.Serve(lis)
|
||||
}()
|
||||
|
||||
// Publisher goroutine
|
||||
go func() {
|
||||
publishTestCases := func() error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
|
||||
defer cancel()
|
||||
for { // Wait until there's one subscriber in routing stats channel
|
||||
if len(c.Subscribers()) > 0 {
|
||||
break
|
||||
}
|
||||
if ctx.Err() != nil {
|
||||
return ctx.Err()
|
||||
}
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
c.Publish(context.Background(), AsRoutingRoute(tc))
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := publishTestCases(); err != nil {
|
||||
errCh <- err
|
||||
}
|
||||
}()
|
||||
|
||||
// Client goroutine
|
||||
go func() {
|
||||
defer lis.Close()
|
||||
conn, err := grpc.DialContext(context.Background(), "bufnet", grpc.WithContextDialer(bufDialer), grpc.WithInsecure())
|
||||
if err != nil {
|
||||
errCh <- err
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
client := NewRoutingServiceClient(conn)
|
||||
|
||||
// Test retrieving only a subset of fields
|
||||
testRetrievingSubsetOfFields := func() error {
|
||||
streamCtx, streamClose := context.WithCancel(context.Background())
|
||||
@@ -234,6 +155,9 @@ func TestServiceSubscribeSubsetOfFields(t *testing.T) {
|
||||
return err
|
||||
}
|
||||
|
||||
// Send nextPub signal to start next round of publishing
|
||||
close(nextPub)
|
||||
|
||||
for _, tc := range testCases {
|
||||
msg, err := stream.Recv()
|
||||
if err != nil {
|
||||
@@ -255,6 +179,10 @@ func TestServiceSubscribeSubsetOfFields(t *testing.T) {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := testRetrievingAllFields(); err != nil {
|
||||
errCh <- err
|
||||
}
|
||||
if err := testRetrievingSubsetOfFields(); err != nil {
|
||||
errCh <- err
|
||||
}
|
||||
|
@@ -30,7 +30,6 @@ func (c routingContext) GetTargetPort() net.Port {
|
||||
|
||||
// GetSkipDNSResolve is a mock implementation here to match the interface,
|
||||
// SkipDNSResolve is set from dns module, no use if coming from a protobuf object?
|
||||
// TODO: please confirm @Vigilans
|
||||
func (c routingContext) GetSkipDNSResolve() bool {
|
||||
return false
|
||||
}
|
||||
|
@@ -66,24 +66,6 @@ type DomainMatcher struct {
|
||||
matchers strmatcher.IndexMatcher
|
||||
}
|
||||
|
||||
func NewMphMatcherGroup(domains []*Domain) (*DomainMatcher, error) {
|
||||
g := strmatcher.NewMphMatcherGroup()
|
||||
for _, d := range domains {
|
||||
matcherType, f := matcherTypeMap[d.Type]
|
||||
if !f {
|
||||
return nil, newError("unsupported domain type", d.Type)
|
||||
}
|
||||
_, err := g.AddPattern(d.Value, matcherType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
g.Build()
|
||||
return &DomainMatcher{
|
||||
matchers: g,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func NewDomainMatcher(domains []*Domain) (*DomainMatcher, error) {
|
||||
g := new(strmatcher.MatcherGroup)
|
||||
for _, d := range domains {
|
||||
@@ -100,7 +82,7 @@ func NewDomainMatcher(domains []*Domain) (*DomainMatcher, error) {
|
||||
}
|
||||
|
||||
func (m *DomainMatcher) ApplyDomain(domain string) bool {
|
||||
return len(m.matchers.Match(strings.ToLower(domain))) > 0
|
||||
return len(m.matchers.Match(domain)) > 0
|
||||
}
|
||||
|
||||
// Apply implements Condition.
|
||||
@@ -109,7 +91,7 @@ func (m *DomainMatcher) Apply(ctx routing.Context) bool {
|
||||
if len(domain) == 0 {
|
||||
return false
|
||||
}
|
||||
return m.ApplyDomain(domain)
|
||||
return m.ApplyDomain(strings.ToLower(domain))
|
||||
}
|
||||
|
||||
type MultiGeoIPMatcher struct {
|
||||
|
@@ -186,4 +186,6 @@ func (c *GeoIPMatcherContainer) Add(geoip *GeoIP) (*GeoIPMatcher, error) {
|
||||
return m, nil
|
||||
}
|
||||
|
||||
var globalGeoIPContainer GeoIPMatcherContainer
|
||||
var (
|
||||
globalGeoIPContainer GeoIPMatcherContainer
|
||||
)
|
||||
|
@@ -6,7 +6,6 @@ import (
|
||||
"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"
|
||||
@@ -89,8 +88,7 @@ func TestGeoIPMatcher(t *testing.T) {
|
||||
{
|
||||
Input: "192.0.1.0",
|
||||
Output: false,
|
||||
},
|
||||
{
|
||||
}, {
|
||||
Input: "0.1.0.0",
|
||||
Output: true,
|
||||
},
|
||||
|
@@ -359,9 +359,6 @@ func TestChinaSites(t *testing.T) {
|
||||
matcher, err := NewDomainMatcher(domains)
|
||||
common.Must(err)
|
||||
|
||||
acMatcher, err := NewMphMatcherGroup(domains)
|
||||
common.Must(err)
|
||||
|
||||
type TestCase struct {
|
||||
Domain string
|
||||
Output bool
|
||||
@@ -390,96 +387,9 @@ func TestChinaSites(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
r1 := matcher.ApplyDomain(testCase.Domain)
|
||||
r2 := acMatcher.ApplyDomain(testCase.Domain)
|
||||
if r1 != testCase.Output {
|
||||
t.Error("DomainMatcher expected output ", testCase.Output, " for domain ", testCase.Domain, " but got ", r1)
|
||||
} else if r2 != testCase.Output {
|
||||
t.Error("ACDomainMatcher expected output ", testCase.Output, " for domain ", testCase.Domain, " but got ", r2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMphDomainMatcher(b *testing.B) {
|
||||
domains, err := loadGeoSite("CN")
|
||||
common.Must(err)
|
||||
|
||||
matcher, err := NewMphMatcherGroup(domains)
|
||||
common.Must(err)
|
||||
|
||||
type TestCase struct {
|
||||
Domain string
|
||||
Output bool
|
||||
}
|
||||
testCases := []TestCase{
|
||||
{
|
||||
Domain: "163.com",
|
||||
Output: true,
|
||||
},
|
||||
{
|
||||
Domain: "163.com",
|
||||
Output: true,
|
||||
},
|
||||
{
|
||||
Domain: "164.com",
|
||||
Output: false,
|
||||
},
|
||||
{
|
||||
Domain: "164.com",
|
||||
Output: false,
|
||||
},
|
||||
}
|
||||
|
||||
for i := 0; i < 1024; i++ {
|
||||
testCases = append(testCases, TestCase{Domain: strconv.Itoa(i) + ".not-exists.com", Output: false})
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
for _, testCase := range testCases {
|
||||
_ = matcher.ApplyDomain(testCase.Domain)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkDomainMatcher(b *testing.B) {
|
||||
domains, err := loadGeoSite("CN")
|
||||
common.Must(err)
|
||||
|
||||
matcher, err := NewDomainMatcher(domains)
|
||||
common.Must(err)
|
||||
|
||||
type TestCase struct {
|
||||
Domain string
|
||||
Output bool
|
||||
}
|
||||
testCases := []TestCase{
|
||||
{
|
||||
Domain: "163.com",
|
||||
Output: true,
|
||||
},
|
||||
{
|
||||
Domain: "163.com",
|
||||
Output: true,
|
||||
},
|
||||
{
|
||||
Domain: "164.com",
|
||||
Output: false,
|
||||
},
|
||||
{
|
||||
Domain: "164.com",
|
||||
Output: false,
|
||||
},
|
||||
}
|
||||
|
||||
for i := 0; i < 1024; i++ {
|
||||
testCases = append(testCases, TestCase{Domain: strconv.Itoa(i) + ".not-exists.com", Output: false})
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
for _, testCase := range testCases {
|
||||
_ = matcher.ApplyDomain(testCase.Domain)
|
||||
r := matcher.ApplyDomain(testCase.Domain)
|
||||
if r != testCase.Output {
|
||||
t.Error("expected output ", testCase.Output, " for domain ", testCase.Domain, " but got ", r)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -67,23 +67,11 @@ func (rr *RoutingRule) BuildCondition() (Condition, error) {
|
||||
conds := NewConditionChan()
|
||||
|
||||
if len(rr.Domain) > 0 {
|
||||
switch rr.DomainMatcher {
|
||||
case "linear":
|
||||
matcher, err := NewDomainMatcher(rr.Domain)
|
||||
if err != nil {
|
||||
return nil, newError("failed to build domain condition").Base(err)
|
||||
}
|
||||
conds.Add(matcher)
|
||||
case "mph", "hybrid":
|
||||
fallthrough
|
||||
default:
|
||||
matcher, err := NewMphMatcherGroup(rr.Domain)
|
||||
if err != nil {
|
||||
return nil, newError("failed to build domain condition with MphDomainMatcher").Base(err)
|
||||
}
|
||||
newError("MphDomainMatcher is enabled for ", len(rr.Domain), " domain rule(s)").AtDebug().WriteToLog()
|
||||
conds.Add(matcher)
|
||||
matcher, err := NewDomainMatcher(rr.Domain)
|
||||
if err != nil {
|
||||
return nil, newError("failed to build domain condition").Base(err)
|
||||
}
|
||||
conds.Add(matcher)
|
||||
}
|
||||
|
||||
if len(rr.UserEmail) > 0 {
|
||||
|
@@ -1,12 +1,13 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.27.1
|
||||
// protoc v3.18.0
|
||||
// protoc-gen-go v1.25.0
|
||||
// protoc v3.14.0
|
||||
// source: app/router/config.proto
|
||||
|
||||
package router
|
||||
|
||||
import (
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
net "github.com/xtls/xray-core/common/net"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
@@ -21,6 +22,10 @@ const (
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||
// of the legacy proto package is being used.
|
||||
const _ = proto.ProtoPackageIsVersion4
|
||||
|
||||
// Type of domain value.
|
||||
type Domain_Type int32
|
||||
|
||||
@@ -510,7 +515,6 @@ type RoutingRule struct {
|
||||
InboundTag []string `protobuf:"bytes,8,rep,name=inbound_tag,json=inboundTag,proto3" json:"inbound_tag,omitempty"`
|
||||
Protocol []string `protobuf:"bytes,9,rep,name=protocol,proto3" json:"protocol,omitempty"`
|
||||
Attributes string `protobuf:"bytes,15,opt,name=attributes,proto3" json:"attributes,omitempty"`
|
||||
DomainMatcher string `protobuf:"bytes,17,opt,name=domain_matcher,json=domainMatcher,proto3" json:"domain_matcher,omitempty"`
|
||||
}
|
||||
|
||||
func (x *RoutingRule) Reset() {
|
||||
@@ -668,13 +672,6 @@ func (x *RoutingRule) GetAttributes() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *RoutingRule) GetDomainMatcher() string {
|
||||
if x != nil {
|
||||
return x.DomainMatcher
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type isRoutingRule_TargetTag interface {
|
||||
isRoutingRule_TargetTag()
|
||||
}
|
||||
@@ -949,7 +946,7 @@ var file_app_router_config_proto_rawDesc = []byte{
|
||||
0x74, 0x12, 0x2e, 0x0a, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b,
|
||||
0x32, 0x18, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74,
|
||||
0x65, 0x72, 0x2e, 0x47, 0x65, 0x6f, 0x53, 0x69, 0x74, 0x65, 0x52, 0x05, 0x65, 0x6e, 0x74, 0x72,
|
||||
0x79, 0x22, 0xb5, 0x06, 0x0a, 0x0b, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c,
|
||||
0x79, 0x22, 0x8e, 0x06, 0x0a, 0x0b, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c,
|
||||
0x65, 0x12, 0x12, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00,
|
||||
0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x25, 0x0a, 0x0d, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69,
|
||||
0x6e, 0x67, 0x5f, 0x74, 0x61, 0x67, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0c,
|
||||
@@ -997,38 +994,36 @@ var file_app_router_config_proto_rawDesc = []byte{
|
||||
0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x09, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x1e, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74,
|
||||
0x65, 0x73, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62,
|
||||
0x75, 0x74, 0x65, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x6d,
|
||||
0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x64, 0x6f,
|
||||
0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x42, 0x0c, 0x0a, 0x0a, 0x74,
|
||||
0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x74, 0x61, 0x67, 0x22, 0x4e, 0x0a, 0x0d, 0x42, 0x61, 0x6c,
|
||||
0x61, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61,
|
||||
0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x2b, 0x0a, 0x11,
|
||||
0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f,
|
||||
0x72, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e,
|
||||
0x64, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x22, 0x9b, 0x02, 0x0a, 0x06, 0x43, 0x6f,
|
||||
0x6e, 0x66, 0x69, 0x67, 0x12, 0x4f, 0x0a, 0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x73,
|
||||
0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x26, 0x2e,
|
||||
0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e,
|
||||
0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72,
|
||||
0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72,
|
||||
0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x30, 0x0a, 0x04, 0x72, 0x75, 0x6c, 0x65, 0x18, 0x02, 0x20,
|
||||
0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72,
|
||||
0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c,
|
||||
0x65, 0x52, 0x04, 0x72, 0x75, 0x6c, 0x65, 0x12, 0x45, 0x0a, 0x0e, 0x62, 0x61, 0x6c, 0x61, 0x6e,
|
||||
0x63, 0x69, 0x6e, 0x67, 0x5f, 0x72, 0x75, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32,
|
||||
0x1e, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65,
|
||||
0x72, 0x2e, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x52,
|
||||
0x0d, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x22, 0x47,
|
||||
0x0a, 0x0e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79,
|
||||
0x12, 0x08, 0x0a, 0x04, 0x41, 0x73, 0x49, 0x73, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x55, 0x73,
|
||||
0x65, 0x49, 0x70, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x49, 0x70, 0x49, 0x66, 0x4e, 0x6f, 0x6e,
|
||||
0x4d, 0x61, 0x74, 0x63, 0x68, 0x10, 0x02, 0x12, 0x0e, 0x0a, 0x0a, 0x49, 0x70, 0x4f, 0x6e, 0x44,
|
||||
0x65, 0x6d, 0x61, 0x6e, 0x64, 0x10, 0x03, 0x42, 0x4f, 0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x2e, 0x78,
|
||||
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x50, 0x01,
|
||||
0x5a, 0x24, 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,
|
||||
0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0xaa, 0x02, 0x0f, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70,
|
||||
0x70, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x75, 0x74, 0x65, 0x73, 0x42, 0x0c, 0x0a, 0x0a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x74,
|
||||
0x61, 0x67, 0x22, 0x4e, 0x0a, 0x0d, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x52,
|
||||
0x75, 0x6c, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x2b, 0x0a, 0x11, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e,
|
||||
0x64, 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09,
|
||||
0x52, 0x10, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74,
|
||||
0x6f, 0x72, 0x22, 0x9b, 0x02, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x4f, 0x0a,
|
||||
0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x26, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
|
||||
0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e,
|
||||
0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0e,
|
||||
0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x30,
|
||||
0x0a, 0x04, 0x72, 0x75, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x78,
|
||||
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x52,
|
||||
0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x04, 0x72, 0x75, 0x6c, 0x65,
|
||||
0x12, 0x45, 0x0a, 0x0e, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x72, 0x75,
|
||||
0x6c, 0x65, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
|
||||
0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x42, 0x61, 0x6c, 0x61, 0x6e,
|
||||
0x63, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x0d, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63,
|
||||
0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x22, 0x47, 0x0a, 0x0e, 0x44, 0x6f, 0x6d, 0x61, 0x69,
|
||||
0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x08, 0x0a, 0x04, 0x41, 0x73, 0x49,
|
||||
0x73, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x55, 0x73, 0x65, 0x49, 0x70, 0x10, 0x01, 0x12, 0x10,
|
||||
0x0a, 0x0c, 0x49, 0x70, 0x49, 0x66, 0x4e, 0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x10, 0x02,
|
||||
0x12, 0x0e, 0x0a, 0x0a, 0x49, 0x70, 0x4f, 0x6e, 0x44, 0x65, 0x6d, 0x61, 0x6e, 0x64, 0x10, 0x03,
|
||||
0x42, 0x4f, 0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70,
|
||||
0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x50, 0x01, 0x5a, 0x24, 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, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0xaa,
|
||||
0x02, 0x0f, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65,
|
||||
0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
|
@@ -119,8 +119,6 @@ message RoutingRule {
|
||||
repeated string protocol = 9;
|
||||
|
||||
string attributes = 15;
|
||||
|
||||
string domain_matcher = 17;
|
||||
}
|
||||
|
||||
message BalancingRule {
|
||||
|
@@ -80,6 +80,7 @@ func (r *Router) PickRoute(ctx routing.Context) (routing.Route, error) {
|
||||
}
|
||||
|
||||
func (r *Router) pickRouteInternal(ctx routing.Context) (*Rule, routing.Context, error) {
|
||||
|
||||
// SkipDNSResolve is set from DNS module.
|
||||
// the DOH remote server maybe a domain name,
|
||||
// this prevents cycle resolving dead loop
|
||||
|
@@ -4,10 +4,7 @@ import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/xtls/xray-core/features/dns"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
|
||||
. "github.com/xtls/xray-core/app/router"
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
@@ -118,11 +115,7 @@ func TestIPOnDemand(t *testing.T) {
|
||||
defer mockCtl.Finish()
|
||||
|
||||
mockDNS := mocks.NewDNSClient(mockCtl)
|
||||
mockDNS.EXPECT().LookupIP(gomock.Eq("example.com"), dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
}).Return([]net.IP{{192, 168, 0, 1}}, nil).AnyTimes()
|
||||
mockDNS.EXPECT().LookupIP(gomock.Eq("example.com")).Return([]net.IP{{192, 168, 0, 1}}, nil).AnyTimes()
|
||||
|
||||
r := new(Router)
|
||||
common.Must(r.Init(config, mockDNS, nil))
|
||||
@@ -157,11 +150,7 @@ func TestIPIfNonMatchDomain(t *testing.T) {
|
||||
defer mockCtl.Finish()
|
||||
|
||||
mockDNS := mocks.NewDNSClient(mockCtl)
|
||||
mockDNS.EXPECT().LookupIP(gomock.Eq("example.com"), dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
}).Return([]net.IP{{192, 168, 0, 1}}, nil).AnyTimes()
|
||||
mockDNS.EXPECT().LookupIP(gomock.Eq("example.com")).Return([]net.IP{{192, 168, 0, 1}}, nil).AnyTimes()
|
||||
|
||||
r := new(Router)
|
||||
common.Must(r.Init(config, mockDNS, nil))
|
||||
|
@@ -1,12 +1,13 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.27.1
|
||||
// protoc v3.18.0
|
||||
// protoc-gen-go v1.25.0
|
||||
// protoc v3.14.0
|
||||
// source: app/stats/command/command.proto
|
||||
|
||||
package command
|
||||
|
||||
import (
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
@@ -20,6 +21,10 @@ const (
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||
// of the legacy proto package is being used.
|
||||
const _ = proto.ProtoPackageIsVersion4
|
||||
|
||||
type GetStatsRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
|
@@ -1,12 +1,13 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.27.1
|
||||
// protoc v3.18.0
|
||||
// protoc-gen-go v1.25.0
|
||||
// protoc v3.14.0
|
||||
// source: app/stats/config.proto
|
||||
|
||||
package stats
|
||||
|
||||
import (
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
@@ -20,6 +21,10 @@ const (
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||
// of the legacy proto package is being used.
|
||||
const _ = proto.ProtoPackageIsVersion4
|
||||
|
||||
type Config struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
|
@@ -24,17 +24,10 @@ type Buffer struct {
|
||||
UDP *net.Destination
|
||||
}
|
||||
|
||||
// New creates a Buffer with 0 length and 8K capacity.
|
||||
// New creates a Buffer with 0 length and 2K capacity.
|
||||
func New() *Buffer {
|
||||
buf := pool.Get().([]byte)
|
||||
if cap(buf) >= Size {
|
||||
buf = buf[:Size]
|
||||
} else {
|
||||
buf = make([]byte, Size)
|
||||
}
|
||||
|
||||
return &Buffer{
|
||||
v: buf,
|
||||
v: pool.Get().([]byte),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,15 +50,8 @@ func NewExisted(b []byte) *Buffer {
|
||||
// StackNew creates a new Buffer object on stack.
|
||||
// This method is for buffers that is released in the same function.
|
||||
func StackNew() Buffer {
|
||||
buf := pool.Get().([]byte)
|
||||
if cap(buf) >= Size {
|
||||
buf = buf[:Size]
|
||||
} else {
|
||||
buf = make([]byte, Size)
|
||||
}
|
||||
|
||||
return Buffer{
|
||||
v: buf,
|
||||
v: pool.Get().([]byte),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,10 +64,7 @@ func (b *Buffer) Release() {
|
||||
p := b.v
|
||||
b.v = nil
|
||||
b.Clear()
|
||||
|
||||
if cap(p) == Size {
|
||||
pool.Put(p)
|
||||
}
|
||||
pool.Put(p)
|
||||
b.UDP = nil
|
||||
}
|
||||
|
||||
|
@@ -6,7 +6,6 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
. "github.com/xtls/xray-core/common/buf"
|
||||
)
|
||||
@@ -78,7 +77,6 @@ func TestBufferByte(t *testing.T) {
|
||||
buffer.Release()
|
||||
}
|
||||
}
|
||||
|
||||
func TestBufferResize(t *testing.T) {
|
||||
buffer := New()
|
||||
defer buffer.Release()
|
||||
|
@@ -6,9 +6,6 @@ import (
|
||||
"os"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/xtls/xray-core/features/stats"
|
||||
"github.com/xtls/xray-core/transport/internet/stat"
|
||||
)
|
||||
|
||||
// Reader extends io.Reader with MultiBuffer.
|
||||
@@ -32,17 +29,9 @@ type Writer interface {
|
||||
}
|
||||
|
||||
// WriteAllBytes ensures all bytes are written into the given writer.
|
||||
func WriteAllBytes(writer io.Writer, payload []byte, c stats.Counter) error {
|
||||
wc := 0
|
||||
defer func() {
|
||||
if c != nil {
|
||||
c.Add(int64(wc))
|
||||
}
|
||||
}()
|
||||
|
||||
func WriteAllBytes(writer io.Writer, payload []byte) error {
|
||||
for len(payload) > 0 {
|
||||
n, err := writer.Write(payload)
|
||||
wc += n
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -76,13 +65,7 @@ func NewReader(reader io.Reader) Reader {
|
||||
if err != nil {
|
||||
newError("failed to get sysconn").Base(err).WriteToLog()
|
||||
} else {
|
||||
var counter stats.Counter
|
||||
|
||||
if statConn, ok := reader.(*stat.CounterConnection); ok {
|
||||
reader = statConn.Connection
|
||||
counter = statConn.ReadCounter
|
||||
}
|
||||
return NewReadVReader(reader, rawConn, counter)
|
||||
return NewReadVReader(reader, rawConn)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -121,24 +104,13 @@ func NewWriter(writer io.Writer) Writer {
|
||||
return mw
|
||||
}
|
||||
|
||||
iConn := writer
|
||||
if statConn, ok := writer.(*stat.CounterConnection); ok {
|
||||
iConn = statConn.Connection
|
||||
}
|
||||
|
||||
if isPacketWriter(iConn) {
|
||||
if isPacketWriter(writer) {
|
||||
return &SequentialWriter{
|
||||
Writer: writer,
|
||||
}
|
||||
}
|
||||
|
||||
var counter stats.Counter
|
||||
|
||||
if statConn, ok := writer.(*stat.CounterConnection); ok {
|
||||
counter = statConn.WriteCounter
|
||||
}
|
||||
return &BufferToBytesWriter{
|
||||
Writer: iConn,
|
||||
counter: counter,
|
||||
Writer: writer,
|
||||
}
|
||||
}
|
||||
|
@@ -4,11 +4,11 @@ import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
. "github.com/xtls/xray-core/common/buf"
|
||||
)
|
||||
@@ -119,7 +119,7 @@ func TestMultiBufferReadAllToByte(t *testing.T) {
|
||||
common.Must(err)
|
||||
f.Close()
|
||||
|
||||
cnt, err := os.ReadFile(dat)
|
||||
cnt, err := ioutil.ReadFile(dat)
|
||||
common.Must(err)
|
||||
|
||||
if d := cmp.Diff(buf2, cnt); d != "" {
|
||||
|
@@ -1,5 +1,6 @@
|
||||
//go:build !windows && !wasm && !illumos
|
||||
// +build !windows,!wasm,!illumos
|
||||
// +build !windows
|
||||
// +build !wasm
|
||||
// +build !illumos
|
||||
|
||||
package buf
|
||||
|
||||
|
@@ -1,14 +1,12 @@
|
||||
//go:build !wasm
|
||||
// +build !wasm
|
||||
|
||||
package buf
|
||||
|
||||
import (
|
||||
"io"
|
||||
"runtime"
|
||||
"syscall"
|
||||
|
||||
"github.com/xtls/xray-core/features/stats"
|
||||
|
||||
"github.com/xtls/xray-core/common/platform"
|
||||
)
|
||||
|
||||
@@ -56,19 +54,17 @@ type ReadVReader struct {
|
||||
rawConn syscall.RawConn
|
||||
mr multiReader
|
||||
alloc allocStrategy
|
||||
counter stats.Counter
|
||||
}
|
||||
|
||||
// NewReadVReader creates a new ReadVReader.
|
||||
func NewReadVReader(reader io.Reader, rawConn syscall.RawConn, counter stats.Counter) *ReadVReader {
|
||||
func NewReadVReader(reader io.Reader, rawConn syscall.RawConn) *ReadVReader {
|
||||
return &ReadVReader{
|
||||
Reader: reader,
|
||||
rawConn: rawConn,
|
||||
alloc: allocStrategy{
|
||||
current: 1,
|
||||
},
|
||||
mr: newMultiReader(),
|
||||
counter: counter,
|
||||
mr: newMultiReader(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,16 +123,10 @@ func (r *ReadVReader) ReadMultiBuffer() (MultiBuffer, error) {
|
||||
if b.IsFull() {
|
||||
r.alloc.Adjust(1)
|
||||
}
|
||||
if r.counter != nil && b != nil {
|
||||
r.counter.Add(int64(b.Len()))
|
||||
}
|
||||
return MultiBuffer{b}, err
|
||||
}
|
||||
|
||||
mb, err := r.readMulti()
|
||||
if r.counter != nil && mb != nil {
|
||||
r.counter.Add(int64(mb.Len()))
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -144,13 +134,17 @@ func (r *ReadVReader) ReadMultiBuffer() (MultiBuffer, error) {
|
||||
return mb, nil
|
||||
}
|
||||
|
||||
var useReadv bool
|
||||
var useReadv = true
|
||||
|
||||
func init() {
|
||||
const defaultFlagValue = "NOT_DEFINED_AT_ALL"
|
||||
value := platform.NewEnvFlag("xray.buf.readv").GetValue(func() string { return defaultFlagValue })
|
||||
switch value {
|
||||
case defaultFlagValue, "auto", "enable":
|
||||
case defaultFlagValue, "auto":
|
||||
if (runtime.GOARCH == "386" || runtime.GOARCH == "amd64" || runtime.GOARCH == "s390x") && (runtime.GOOS == "linux" || runtime.GOOS == "darwin" || runtime.GOOS == "windows") {
|
||||
useReadv = true
|
||||
}
|
||||
case "enable":
|
||||
useReadv = true
|
||||
}
|
||||
}
|
||||
|
@@ -1,4 +1,3 @@
|
||||
//go:build wasm
|
||||
// +build wasm
|
||||
|
||||
package buf
|
||||
|
@@ -1,4 +1,3 @@
|
||||
//go:build !wasm
|
||||
// +build !wasm
|
||||
|
||||
package buf_test
|
||||
@@ -10,11 +9,10 @@ import (
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
|
||||
"golang.org/x/sync/errgroup"
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
. "github.com/xtls/xray-core/common/buf"
|
||||
"github.com/xtls/xray-core/testing/servers/tcp"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
func TestReadvReader(t *testing.T) {
|
||||
@@ -52,7 +50,7 @@ func TestReadvReader(t *testing.T) {
|
||||
rawConn, err := conn.(*net.TCPConn).SyscallConn()
|
||||
common.Must(err)
|
||||
|
||||
reader := NewReadVReader(conn, rawConn, nil)
|
||||
reader := NewReadVReader(conn, rawConn)
|
||||
var rmb MultiBuffer
|
||||
for {
|
||||
mb, err := reader.ReadMultiBuffer()
|
||||
|
@@ -1,4 +1,3 @@
|
||||
//go:build illumos
|
||||
// +build illumos
|
||||
|
||||
package buf
|
||||
|
@@ -5,8 +5,6 @@ import (
|
||||
"net"
|
||||
"sync"
|
||||
|
||||
"github.com/xtls/xray-core/features/stats"
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
)
|
||||
@@ -15,8 +13,7 @@ import (
|
||||
type BufferToBytesWriter struct {
|
||||
io.Writer
|
||||
|
||||
counter stats.Counter
|
||||
cache [][]byte
|
||||
cache [][]byte
|
||||
}
|
||||
|
||||
// WriteMultiBuffer implements Writer. This method takes ownership of the given buffer.
|
||||
@@ -29,7 +26,7 @@ func (w *BufferToBytesWriter) WriteMultiBuffer(mb MultiBuffer) error {
|
||||
}
|
||||
|
||||
if len(mb) == 1 {
|
||||
return WriteAllBytes(w.Writer, mb[0].Bytes(), w.counter)
|
||||
return WriteAllBytes(w.Writer, mb[0].Bytes())
|
||||
}
|
||||
|
||||
if cap(w.cache) < len(mb) {
|
||||
@@ -48,15 +45,9 @@ func (w *BufferToBytesWriter) WriteMultiBuffer(mb MultiBuffer) error {
|
||||
}()
|
||||
|
||||
nb := net.Buffers(bs)
|
||||
wc := int64(0)
|
||||
defer func() {
|
||||
if w.counter != nil {
|
||||
w.counter.Add(wc)
|
||||
}
|
||||
}()
|
||||
|
||||
for size > 0 {
|
||||
n, err := nb.WriteTo(w.Writer)
|
||||
wc += n
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -182,7 +173,7 @@ func (w *BufferedWriter) flushInternal() error {
|
||||
w.buffer = nil
|
||||
|
||||
if writer, ok := w.writer.(io.Writer); ok {
|
||||
err := WriteAllBytes(writer, b.Bytes(), nil)
|
||||
err := WriteAllBytes(writer, b.Bytes())
|
||||
b.Release()
|
||||
return err
|
||||
}
|
||||
|
38
common/cache/lru.go
vendored
38
common/cache/lru.go
vendored
@@ -2,7 +2,7 @@ package cache
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
"sync"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
// Lru simple, fast lru cache implementation
|
||||
@@ -28,7 +28,7 @@ type lruElement struct {
|
||||
|
||||
// NewLru init a lru cache
|
||||
func NewLru(cap int) Lru {
|
||||
return &lru{
|
||||
return lru{
|
||||
capacity: cap,
|
||||
doubleLinkedlist: list.New(),
|
||||
keyToElement: new(sync.Map),
|
||||
@@ -37,53 +37,49 @@ func NewLru(cap int) Lru {
|
||||
}
|
||||
}
|
||||
|
||||
func (l *lru) Get(key interface{}) (value interface{}, ok bool) {
|
||||
l.mu.Lock()
|
||||
defer l.mu.Unlock()
|
||||
func (l lru) Get(key interface{}) (value interface{}, ok bool) {
|
||||
if v, ok := l.keyToElement.Load(key); ok {
|
||||
element := v.(*list.Element)
|
||||
l.doubleLinkedlist.MoveToFront(element)
|
||||
return element.Value.(*lruElement).value, true
|
||||
l.doubleLinkedlist.MoveBefore(element, l.doubleLinkedlist.Front())
|
||||
return element.Value.(lruElement).value, true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (l *lru) GetKeyFromValue(value interface{}) (key interface{}, ok bool) {
|
||||
l.mu.Lock()
|
||||
defer l.mu.Unlock()
|
||||
func (l lru) GetKeyFromValue(value interface{}) (key interface{}, ok bool) {
|
||||
if k, ok := l.valueToElement.Load(value); ok {
|
||||
element := k.(*list.Element)
|
||||
l.doubleLinkedlist.MoveToFront(element)
|
||||
return element.Value.(*lruElement).key, true
|
||||
l.doubleLinkedlist.MoveBefore(element, l.doubleLinkedlist.Front())
|
||||
return element.Value.(lruElement).key, true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (l *lru) PeekKeyFromValue(value interface{}) (key interface{}, ok bool) {
|
||||
func (l lru) PeekKeyFromValue(value interface{}) (key interface{}, ok bool) {
|
||||
if k, ok := l.valueToElement.Load(value); ok {
|
||||
element := k.(*list.Element)
|
||||
return element.Value.(*lruElement).key, true
|
||||
return element.Value.(lruElement).key, true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (l *lru) Put(key, value interface{}) {
|
||||
l.mu.Lock()
|
||||
e := &lruElement{key, value}
|
||||
func (l lru) Put(key, value interface{}) {
|
||||
e := lruElement{key, value}
|
||||
if v, ok := l.keyToElement.Load(key); ok {
|
||||
element := v.(*list.Element)
|
||||
element.Value = e
|
||||
l.doubleLinkedlist.MoveToFront(element)
|
||||
l.doubleLinkedlist.MoveBefore(element, l.doubleLinkedlist.Front())
|
||||
} else {
|
||||
l.mu.Lock()
|
||||
element := l.doubleLinkedlist.PushFront(e)
|
||||
l.keyToElement.Store(key, element)
|
||||
l.valueToElement.Store(value, element)
|
||||
if l.doubleLinkedlist.Len() > l.capacity {
|
||||
toBeRemove := l.doubleLinkedlist.Back()
|
||||
l.doubleLinkedlist.Remove(toBeRemove)
|
||||
l.keyToElement.Delete(toBeRemove.Value.(*lruElement).key)
|
||||
l.valueToElement.Delete(toBeRemove.Value.(*lruElement).value)
|
||||
l.keyToElement.Delete(toBeRemove.Value.(lruElement).key)
|
||||
l.valueToElement.Delete(toBeRemove.Value.(lruElement).value)
|
||||
}
|
||||
l.mu.Unlock()
|
||||
}
|
||||
l.mu.Unlock()
|
||||
}
|
||||
|
@@ -5,6 +5,7 @@ package common
|
||||
import (
|
||||
"fmt"
|
||||
"go/build"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
@@ -14,8 +15,10 @@ import (
|
||||
|
||||
//go:generate go run github.com/xtls/xray-core/common/errors/errorgen
|
||||
|
||||
// ErrNoClue is for the situation that existing information is not enough to make a decision. For example, Router may return this error when there is no suitable route.
|
||||
var ErrNoClue = errors.New("not enough information for making a decision")
|
||||
var (
|
||||
// ErrNoClue is for the situation that existing information is not enough to make a decision. For example, Router may return this error when there is no suitable route.
|
||||
ErrNoClue = errors.New("not enough information for making a decision")
|
||||
)
|
||||
|
||||
// Must panics if err is not nil.
|
||||
func Must(err error) {
|
||||
@@ -66,7 +69,7 @@ func GetRuntimeEnv(key string) (string, error) {
|
||||
}
|
||||
var data []byte
|
||||
var runtimeEnv string
|
||||
data, readErr := os.ReadFile(file)
|
||||
data, readErr := ioutil.ReadFile(file)
|
||||
if readErr != nil {
|
||||
return "", readErr
|
||||
}
|
||||
@@ -128,7 +131,7 @@ func GetModuleName(pathToProjectRoot string) (string, error) {
|
||||
for {
|
||||
if idx := strings.LastIndex(loopPath, string(filepath.Separator)); idx >= 0 {
|
||||
gomodPath := filepath.Join(loopPath, "go.mod")
|
||||
gomodBytes, err := os.ReadFile(gomodPath)
|
||||
gomodBytes, err := ioutil.ReadFile(gomodPath)
|
||||
if err != nil {
|
||||
loopPath = loopPath[:idx]
|
||||
continue
|
||||
|
@@ -290,6 +290,7 @@ func (w *AuthenticationWriter) writeStream(mb buf.MultiBuffer) error {
|
||||
mb = nb
|
||||
|
||||
eb, err := w.seal(rawBytes[:nBytes])
|
||||
|
||||
if err != nil {
|
||||
buf.ReleaseMulti(mb2Write)
|
||||
return err
|
||||
|
@@ -18,7 +18,7 @@ func mustDecodeHex(s string) []byte {
|
||||
}
|
||||
|
||||
func TestChaCha20Stream(t *testing.T) {
|
||||
cases := []struct {
|
||||
var cases = []struct {
|
||||
key []byte
|
||||
iv []byte
|
||||
output []byte
|
||||
|
@@ -3,7 +3,7 @@ package internal
|
||||
import "encoding/binary"
|
||||
|
||||
func ChaCha20Block(s *[16]uint32, out []byte, rounds int) {
|
||||
x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 := s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], s[8], s[9], s[10], s[11], s[12], s[13], s[14], s[15]
|
||||
var x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 = s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], s[8], s[9], s[10], s[11], s[12], s[13], s[14], s[15]
|
||||
for i := 0; i < rounds; i += 2 {
|
||||
var x uint32
|
||||
|
||||
|
@@ -1,4 +1,3 @@
|
||||
//go:build generate
|
||||
// +build generate
|
||||
|
||||
package main
|
||||
@@ -56,7 +55,7 @@ func ChaCha20Block(s *[16]uint32, out []byte, rounds int) {
|
||||
}
|
||||
|
||||
func main() {
|
||||
file, err := os.OpenFile("chacha_core.generated.go", os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0o644)
|
||||
file, err := os.OpenFile("chacha_core.generated.go", os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0644)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to generate chacha_core.go: %v", err)
|
||||
}
|
||||
|
@@ -27,7 +27,9 @@ func (r *CryptionReader) Read(data []byte) (int, error) {
|
||||
return nBytes, err
|
||||
}
|
||||
|
||||
var _ buf.Writer = (*CryptionWriter)(nil)
|
||||
var (
|
||||
_ buf.Writer = (*CryptionWriter)(nil)
|
||||
)
|
||||
|
||||
type CryptionWriter struct {
|
||||
stream cipher.Stream
|
||||
@@ -48,7 +50,7 @@ func NewCryptionWriter(stream cipher.Stream, writer io.Writer) *CryptionWriter {
|
||||
func (w *CryptionWriter) Write(data []byte) (int, error) {
|
||||
w.stream.XORKeyStream(data, data)
|
||||
|
||||
if err := buf.WriteAllBytes(w.writer, data, nil); err != nil {
|
||||
if err := buf.WriteAllBytes(w.writer, data); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return len(data), nil
|
||||
|
@@ -2,8 +2,11 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -17,21 +20,26 @@ func main() {
|
||||
pkg = "core"
|
||||
}
|
||||
|
||||
file, err := os.OpenFile("errors.generated.go", os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0o644)
|
||||
moduleName, gmnErr := common.GetModuleName(pwd)
|
||||
if gmnErr != nil {
|
||||
fmt.Println("can not get module path", gmnErr)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
file, err := os.OpenFile("errors.generated.go", os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0644)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to generate errors.generated.go: %v", err)
|
||||
log.Fatalf("Failed to generate errors.generated.go: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
fmt.Fprintf(file, `package %s
|
||||
|
||||
import "github.com/xtls/xray-core/common/errors"
|
||||
|
||||
type errPathObjHolder struct{}
|
||||
|
||||
func newError(values ...interface{}) *errors.Error {
|
||||
return errors.New(values...).WithPathObj(errPathObjHolder{})
|
||||
}
|
||||
`, pkg)
|
||||
fmt.Fprintln(file, "package", pkg)
|
||||
fmt.Fprintln(file, "")
|
||||
fmt.Fprintln(file, "import \""+moduleName+"/common/errors\"")
|
||||
fmt.Fprintln(file, "")
|
||||
fmt.Fprintln(file, "type errPathObjHolder struct{}")
|
||||
fmt.Fprintln(file, "")
|
||||
fmt.Fprintln(file, "func newError(values ...interface{}) *errors.Error {")
|
||||
fmt.Fprintln(file, " return errors.New(values...).WithPathObj(errPathObjHolder{})")
|
||||
fmt.Fprintln(file, "}")
|
||||
}
|
||||
|
@@ -32,7 +32,9 @@ func Record(msg Message) {
|
||||
logHandler.Handle(msg)
|
||||
}
|
||||
|
||||
var logHandler syncHandler
|
||||
var (
|
||||
logHandler syncHandler
|
||||
)
|
||||
|
||||
// RegisterHandler register a new handler as current log handler. Previous registered handler will be discarded.
|
||||
func RegisterHandler(handler Handler) {
|
||||
|
@@ -1,12 +1,13 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.27.1
|
||||
// protoc v3.18.0
|
||||
// protoc-gen-go v1.25.0
|
||||
// protoc v3.14.0
|
||||
// source: common/log/log.proto
|
||||
|
||||
package log
|
||||
|
||||
import (
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
@@ -20,6 +21,10 @@ const (
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||
// of the legacy proto package is being used.
|
||||
const _ = proto.ProtoPackageIsVersion4
|
||||
|
||||
type Severity int32
|
||||
|
||||
const (
|
||||
|
@@ -130,13 +130,13 @@ func CreateStderrLogWriter() WriterCreator {
|
||||
|
||||
// CreateFileLogWriter returns a LogWriterCreator that creates LogWriter for the given file.
|
||||
func CreateFileLogWriter(path string) (WriterCreator, error) {
|
||||
file, err := os.OpenFile(path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0o600)
|
||||
file, err := os.OpenFile(path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
file.Close()
|
||||
return func() Writer {
|
||||
file, err := os.OpenFile(path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0o600)
|
||||
file, err := os.OpenFile(path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package log_test
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -12,7 +13,7 @@ import (
|
||||
)
|
||||
|
||||
func TestFileLogger(t *testing.T) {
|
||||
f, err := os.CreateTemp("", "vtest")
|
||||
f, err := ioutil.TempFile("", "vtest")
|
||||
common.Must(err)
|
||||
path := f.Name()
|
||||
common.Must(f.Close())
|
||||
|
@@ -142,6 +142,7 @@ func (f *DialingWorkerFactory) Create() (*ClientWorker, error) {
|
||||
Reader: downlinkReader,
|
||||
Writer: upLinkWriter,
|
||||
}, f.Strategy)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -174,10 +175,8 @@ type ClientWorker struct {
|
||||
strategy ClientStrategy
|
||||
}
|
||||
|
||||
var (
|
||||
muxCoolAddress = net.DomainAddress("v1.mux.cool")
|
||||
muxCoolPort = net.Port(9527)
|
||||
)
|
||||
var muxCoolAddress = net.DomainAddress("v1.mux.cool")
|
||||
var muxCoolPort = net.Port(9527)
|
||||
|
||||
// NewClientWorker creates a new mux.Client.
|
||||
func NewClientWorker(stream transport.Link, s ClientStrategy) (*ClientWorker, error) {
|
||||
|
@@ -6,7 +6,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/mux"
|
||||
|
@@ -1,12 +1,13 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.27.1
|
||||
// protoc v3.18.0
|
||||
// protoc-gen-go v1.25.0
|
||||
// protoc v3.14.0
|
||||
// source: common/net/address.proto
|
||||
|
||||
package net
|
||||
|
||||
import (
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
@@ -20,6 +21,10 @@ const (
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||
// of the legacy proto package is being used.
|
||||
const _ = proto.ProtoPackageIsVersion4
|
||||
|
||||
// Address of a network host. It may be either an IP address or a domain
|
||||
// address.
|
||||
type IPOrDomain struct {
|
||||
|
@@ -1,12 +1,13 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.27.1
|
||||
// protoc v3.18.0
|
||||
// protoc-gen-go v1.25.0
|
||||
// protoc v3.14.0
|
||||
// source: common/net/destination.proto
|
||||
|
||||
package net
|
||||
|
||||
import (
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
@@ -20,6 +21,10 @@ const (
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||
// of the legacy proto package is being used.
|
||||
const _ = proto.ProtoPackageIsVersion4
|
||||
|
||||
// Endpoint of a network connection.
|
||||
type Endpoint struct {
|
||||
state protoimpl.MessageState
|
||||
|
@@ -1,12 +1,13 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.27.1
|
||||
// protoc v3.18.0
|
||||
// protoc-gen-go v1.25.0
|
||||
// protoc v3.14.0
|
||||
// source: common/net/network.proto
|
||||
|
||||
package net
|
||||
|
||||
import (
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
@@ -20,6 +21,10 @@ const (
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||
// of the legacy proto package is being used.
|
||||
const _ = proto.ProtoPackageIsVersion4
|
||||
|
||||
type Network int32
|
||||
|
||||
const (
|
||||
|
@@ -1,12 +1,13 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.27.1
|
||||
// protoc v3.18.0
|
||||
// protoc-gen-go v1.25.0
|
||||
// protoc v3.14.0
|
||||
// source: common/net/port.proto
|
||||
|
||||
package net
|
||||
|
||||
import (
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
@@ -20,6 +21,10 @@ const (
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||
// of the legacy proto package is being used.
|
||||
const _ = proto.ProtoPackageIsVersion4
|
||||
|
||||
// PortRange represents a range of ports.
|
||||
type PortRange struct {
|
||||
state protoimpl.MessageState
|
||||
|
@@ -3,21 +3,17 @@ package net
|
||||
import "net"
|
||||
|
||||
// DialTCP is an alias of net.DialTCP.
|
||||
var (
|
||||
DialTCP = net.DialTCP
|
||||
DialUDP = net.DialUDP
|
||||
DialUnix = net.DialUnix
|
||||
Dial = net.Dial
|
||||
)
|
||||
var DialTCP = net.DialTCP
|
||||
var DialUDP = net.DialUDP
|
||||
var DialUnix = net.DialUnix
|
||||
var Dial = net.Dial
|
||||
|
||||
type ListenConfig = net.ListenConfig
|
||||
|
||||
var (
|
||||
Listen = net.Listen
|
||||
ListenTCP = net.ListenTCP
|
||||
ListenUDP = net.ListenUDP
|
||||
ListenUnix = net.ListenUnix
|
||||
)
|
||||
var Listen = net.Listen
|
||||
var ListenTCP = net.ListenTCP
|
||||
var ListenUDP = net.ListenUDP
|
||||
var ListenUnix = net.ListenUnix
|
||||
|
||||
var LookupIP = net.LookupIP
|
||||
|
||||
@@ -30,54 +26,36 @@ var SplitHostPort = net.SplitHostPort
|
||||
|
||||
var CIDRMask = net.CIDRMask
|
||||
|
||||
type (
|
||||
Addr = net.Addr
|
||||
Conn = net.Conn
|
||||
PacketConn = net.PacketConn
|
||||
)
|
||||
type Addr = net.Addr
|
||||
type Conn = net.Conn
|
||||
type PacketConn = net.PacketConn
|
||||
|
||||
type (
|
||||
TCPAddr = net.TCPAddr
|
||||
TCPConn = net.TCPConn
|
||||
)
|
||||
type TCPAddr = net.TCPAddr
|
||||
type TCPConn = net.TCPConn
|
||||
|
||||
type (
|
||||
UDPAddr = net.UDPAddr
|
||||
UDPConn = net.UDPConn
|
||||
)
|
||||
type UDPAddr = net.UDPAddr
|
||||
type UDPConn = net.UDPConn
|
||||
|
||||
type (
|
||||
UnixAddr = net.UnixAddr
|
||||
UnixConn = net.UnixConn
|
||||
)
|
||||
type UnixAddr = net.UnixAddr
|
||||
type UnixConn = net.UnixConn
|
||||
|
||||
// IP is an alias for net.IP.
|
||||
type (
|
||||
IP = net.IP
|
||||
IPMask = net.IPMask
|
||||
IPNet = net.IPNet
|
||||
)
|
||||
type IP = net.IP
|
||||
type IPMask = net.IPMask
|
||||
type IPNet = net.IPNet
|
||||
|
||||
const (
|
||||
IPv4len = net.IPv4len
|
||||
IPv6len = net.IPv6len
|
||||
)
|
||||
const IPv4len = net.IPv4len
|
||||
const IPv6len = net.IPv6len
|
||||
|
||||
type (
|
||||
Error = net.Error
|
||||
AddrError = net.AddrError
|
||||
)
|
||||
type Error = net.Error
|
||||
type AddrError = net.AddrError
|
||||
|
||||
type (
|
||||
Dialer = net.Dialer
|
||||
Listener = net.Listener
|
||||
TCPListener = net.TCPListener
|
||||
UnixListener = net.UnixListener
|
||||
)
|
||||
type Dialer = net.Dialer
|
||||
type Listener = net.Listener
|
||||
type TCPListener = net.TCPListener
|
||||
type UnixListener = net.UnixListener
|
||||
|
||||
var (
|
||||
ResolveUnixAddr = net.ResolveUnixAddr
|
||||
ResolveUDPAddr = net.ResolveUDPAddr
|
||||
)
|
||||
var ResolveUnixAddr = net.ResolveUnixAddr
|
||||
var ResolveUDPAddr = net.ResolveUDPAddr
|
||||
|
||||
type Resolver = net.Resolver
|
||||
|
@@ -4,7 +4,7 @@ import (
|
||||
"bytes"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
@@ -56,6 +56,7 @@ func GetOCSPForCert(cert [][]byte) ([]byte, error) {
|
||||
pemBundle := bundle.Bytes()
|
||||
|
||||
certificates, err := parsePEMBundle(pemBundle)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -73,7 +74,7 @@ func GetOCSPForCert(cert [][]byte) ([]byte, error) {
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
issuerBytes, errC := io.ReadAll(resp.Body)
|
||||
issuerBytes, errC := ioutil.ReadAll(resp.Body)
|
||||
if errC != nil {
|
||||
return nil, newError(errC)
|
||||
}
|
||||
@@ -97,11 +98,13 @@ func GetOCSPForCert(cert [][]byte) ([]byte, error) {
|
||||
return nil, newError(err)
|
||||
}
|
||||
defer req.Body.Close()
|
||||
ocspResBytes, err := io.ReadAll(req.Body)
|
||||
ocspResBytes, err := ioutil.ReadAll(req.Body)
|
||||
|
||||
if err != nil {
|
||||
return nil, newError(err)
|
||||
}
|
||||
return ocspResBytes, nil
|
||||
|
||||
}
|
||||
|
||||
// parsePEMBundle parses a certificate bundle from top to bottom and returns
|
||||
|
@@ -1,4 +1,3 @@
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package ctlcmd
|
||||
|
@@ -1,4 +1,3 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package ctlcmd
|
||||
|
@@ -33,7 +33,7 @@ func CopyFile(dst string, src string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f, err := os.OpenFile(dst, os.O_CREATE|os.O_WRONLY, 0o644)
|
||||
f, err := os.OpenFile(dst, os.O_CREATE|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@@ -1,4 +1,3 @@
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package platform
|
||||
|
@@ -1,4 +1,3 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package platform
|
||||
|
@@ -6,7 +6,8 @@ import (
|
||||
"github.com/xtls/xray-core/common"
|
||||
)
|
||||
|
||||
type SniffHeader struct{}
|
||||
type SniffHeader struct {
|
||||
}
|
||||
|
||||
func (h *SniffHeader) Protocol() string {
|
||||
return "bittorrent"
|
||||
|
@@ -4,11 +4,10 @@ import (
|
||||
"encoding/binary"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/net/dns/dnsmessage"
|
||||
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/buf"
|
||||
"github.com/xtls/xray-core/common/serial"
|
||||
"golang.org/x/net/dns/dnsmessage"
|
||||
)
|
||||
|
||||
func PackMessage(msg *dnsmessage.Message) (*buf.Buffer, error) {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user