Compare commits

..

22 Commits

Author SHA1 Message Date
秋のかえで
e14a4dc10b chore: regenerate protobufs 2021-04-14 23:37:45 +08:00
秋のかえで
ab3b0f843d Merge branch 'dns' into features-looutbound 2021-04-14 23:24:22 +08:00
AkinoKaede
98050aaf02 feat: add loopback outbound
Co-authored-by: Shelikhoo <xiaokangwang@outlook.com>
2021-04-14 23:22:18 +08:00
秋のかえで
7cf30d5101 Feat: DNS hosts support multiple addresses 2021-04-12 00:05:26 +08:00
秋のかえで
598e15aed2 style: refine var name 2021-04-11 12:45:16 +08:00
秋のかえで
708ce026ca Refine the test of dns conf 2021-04-10 17:22:44 +08:00
JimhHan
217844cc37 Refine DNS Options 2021-04-10 11:36:58 +08:00
JimhHan
f20c445974 Fix typo 2021-04-10 00:33:55 +08:00
秋のかえで
6e902b24ae Feat: add disableFallback & skipFallback option for DNS client (#489) 2021-04-10 00:07:08 +08:00
JimhHan
70b63e21a5 Fix testing 2021-04-09 23:36:48 +08:00
JimhHan
726a722019 Refine DNS strategies 2021-04-09 23:36:36 +08:00
秋のかえで
f4a048aa0c Merge branch 'main' into dns 2021-04-07 23:15:45 +08:00
秋のかえで
90c81e8459 fix: fix clientIP config 2021-04-02 16:57:31 +08:00
秋のかえで
364086c974 fix: remove AA header flag in DNS query 2021-04-02 16:47:19 +08:00
秋のかえで
7a778d74d0 feat: change the handshake timeout of quic to default vaule 2021-03-31 22:55:28 +08:00
秋のかえで
d3533abe3c Merge branch 'main' into dns 2021-03-31 22:53:43 +08:00
AkinoKaede
58daa2f788 fix: DNS tests timeout due to network instability 2021-03-22 13:20:14 +08:00
AkinoKaede
8382b29922 feat: add queryStrategy option for DNS 2021-03-19 23:35:01 +08:00
JimhHan
41d3f31447 Fix: DNS query log 2021-03-19 22:01:39 +08:00
AkinoKaede
9b93b90fa9 feat: add DNS logs to DNS over QUIC 2021-03-19 13:19:43 +08:00
AkinoKaede
b15fffaac6 fix: fix tests 2021-03-18 23:52:00 +08:00
AkinoKaede
8884e948fe refactor: new dns app 2021-03-18 23:28:01 +08:00
372 changed files with 3881 additions and 8495 deletions

View File

@@ -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" }
}
}

View File

@@ -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"

View File

@@ -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

View File

@@ -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

28
.gitignore vendored
View File

@@ -1,28 +0,0 @@
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
# Test binary, built with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# Dependency directories (remove the comment below to include it)
# vendor/
*.DS_Store
.idea
*.zip
*.tar.gz
v2ray
v2ctl
mockgen
vprotogen
!infra/vprotogen/
errorgen
!common/errors/errorgen/
*.dat

View File

@@ -1,128 +0,0 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
https://t.me/projectXtls.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.

View File

@@ -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

View File

@@ -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

View File

@@ -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.

View File

@@ -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

View File

@@ -4,7 +4,6 @@ package dispatcher
import (
"context"
"github.com/xtls/xray-core/features/dns"
"strings"
"sync"
"time"
@@ -16,6 +15,7 @@ import (
"github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features/dns"
"github.com/xtls/xray-core/features/outbound"
"github.com/xtls/xray-core/features/policy"
"github.com/xtls/xray-core/features/routing"
@@ -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
@@ -92,14 +94,13 @@ type DefaultDispatcher struct {
router routing.Router
policy policy.Manager
stats stats.Manager
hosts dns.HostsLookup
}
func init() {
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
d := new(DefaultDispatcher)
if err := core.RequireFeatures(ctx, func(om outbound.Manager, router routing.Router, pm policy.Manager, sm stats.Manager, dc dns.Client) error {
return d.Init(config.(*Config), om, router, pm, sm, dc)
if err := core.RequireFeatures(ctx, func(om outbound.Manager, router routing.Router, pm policy.Manager, sm stats.Manager) error {
return d.Init(config.(*Config), om, router, pm, sm)
}); err != nil {
return nil, err
}
@@ -108,14 +109,11 @@ func init() {
}
// Init initializes DefaultDispatcher.
func (d *DefaultDispatcher) Init(config *Config, om outbound.Manager, router routing.Router, pm policy.Manager, sm stats.Manager, dc dns.Client) error {
func (d *DefaultDispatcher) Init(config *Config, om outbound.Manager, router routing.Router, pm policy.Manager, sm stats.Manager) error {
d.ohm = om
d.router = router
d.policy = pm
d.stats = sm
if hosts, ok := dc.(dns.HostsLookup); ok {
d.hosts = hosts
}
return nil
}
@@ -181,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
}
}
@@ -197,16 +195,11 @@ 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) {
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
}
if resultSubset, ok := result.(SnifferIsProtoSubsetOf); ok {
if resultSubset.IsProtoSubsetOf(p) {
return true
}
}
}
return false
@@ -241,11 +234,7 @@ func (d *DefaultDispatcher) Dispatch(ctx context.Context, destination net.Destin
domain := result.Domain()
newError("sniffed domain: ", domain).WriteToLog(session.ExportIDToError(ctx))
destination.Address = net.ParseAddress(domain)
if sniffingRequest.RouteOnly && result.Protocol() != "fakedns" {
ob.RouteTarget = destination
} else {
ob.Target = destination
}
ob.Target = destination
}
}
go d.routedDispatch(ctx, outbound, destination)
@@ -263,11 +252,7 @@ func (d *DefaultDispatcher) Dispatch(ctx context.Context, destination net.Destin
domain := result.Domain()
newError("sniffed domain: ", domain).WriteToLog(session.ExportIDToError(ctx))
destination.Address = net.ParseAddress(domain)
if sniffingRequest.RouteOnly && result.Protocol() != "fakedns" {
ob.RouteTarget = destination
} else {
ob.Target = destination
}
ob.Target = destination
}
d.routedDispatch(ctx, outbound, destination)
}()
@@ -275,67 +260,6 @@ func (d *DefaultDispatcher) Dispatch(ctx context.Context, destination net.Destin
return inbound, nil
}
// DispatchLink implements routing.Dispatcher.
func (d *DefaultDispatcher) DispatchLink(ctx context.Context, destination net.Destination, outbound *transport.Link) error {
if !destination.IsValid() {
return newError("Dispatcher: Invalid destination.")
}
ob := &session.Outbound{
Target: destination,
}
ctx = session.ContextWithOutbound(ctx, ob)
content := session.ContentFromContext(ctx)
if content == nil {
content = new(session.Content)
ctx = session.ContextWithContent(ctx, content)
}
sniffingRequest := content.SniffingRequest
switch {
case !sniffingRequest.Enabled:
go d.routedDispatch(ctx, outbound, destination)
case destination.Network != net.Network_TCP:
// Only metadata sniff will be used for non tcp connection
result, err := sniffer(ctx, nil, true)
if err == nil {
content.Protocol = result.Protocol()
if shouldOverride(ctx, result, sniffingRequest, destination) {
domain := result.Domain()
newError("sniffed domain: ", domain).WriteToLog(session.ExportIDToError(ctx))
destination.Address = net.ParseAddress(domain)
if sniffingRequest.RouteOnly && result.Protocol() != "fakedns" {
ob.RouteTarget = destination
} else {
ob.Target = destination
}
}
}
go d.routedDispatch(ctx, outbound, destination)
default:
go func() {
cReader := &cachedReader{
reader: outbound.Reader.(*pipe.Reader),
}
outbound.Reader = cReader
result, err := sniffer(ctx, cReader, sniffingRequest.MetadataOnly)
if err == nil {
content.Protocol = result.Protocol()
}
if err == nil && shouldOverride(ctx, result, sniffingRequest, destination) {
domain := result.Domain()
newError("sniffed domain: ", domain).WriteToLog(session.ExportIDToError(ctx))
destination.Address = net.ParseAddress(domain)
if sniffingRequest.RouteOnly && result.Protocol() != "fakedns" {
ob.RouteTarget = destination
} else {
ob.Target = destination
}
}
d.routedDispatch(ctx, outbound, destination)
}()
}
return nil
}
func sniffer(ctx context.Context, cReader *cachedReader, metadataOnly bool) (SniffResult, error) {
payload := buf.New()
defer payload.Release()
@@ -383,41 +307,20 @@ func sniffer(ctx context.Context, cReader *cachedReader, metadataOnly bool) (Sni
}
func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.Link, destination net.Destination) {
ob := session.OutboundFromContext(ctx)
if d.hosts != nil && destination.Address.Family().IsDomain() {
proxied := d.hosts.LookupHosts(ob.Target.String())
if proxied != nil {
ro := ob.RouteTarget == destination
destination.Address = *proxied
if ro {
ob.RouteTarget = destination
} else {
ob.Target = destination
}
}
}
var handler outbound.Handler
if forcedOutboundTag := session.GetForcedOutboundTagFromContext(ctx); forcedOutboundTag != "" {
ctx = session.SetForcedOutboundTagToContext(ctx, "")
if h := d.ohm.GetHandler(forcedOutboundTag); h != nil {
newError("taking platform initialized detour [", forcedOutboundTag, "] for [", destination, "]").WriteToLog(session.ExportIDToError(ctx))
handler = h
} else {
newError("non existing tag for platform initialized detour: ", forcedOutboundTag).AtError().WriteToLog(session.ExportIDToError(ctx))
common.Close(link.Writer)
common.Interrupt(link.Reader)
return
}
} else 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))
routingLink := routing_session.AsRoutingContext(ctx)
inTag := routingLink.GetInboundTag()
isPickRoute := false
if d.router != nil {
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))
@@ -437,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)
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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,

View File

@@ -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;
}

View File

@@ -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,50 +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...))
}
// LookupHosts implements dns.HostsLookup.
func (s *DNS) LookupHosts(domain string) *net.Address {
domain = strings.TrimSuffix(domain, ".")
if domain == "" {
return nil
}
// Normalize the FQDN form query
addrs := s.hosts.Lookup(domain, *s.ipOption)
if len(addrs) > 0 {
newError("domain replaced: ", domain, " -> ", addrs[0].String()).AtInfo().WriteToLog()
return &addrs[0]
}
return nil
}
// 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
@@ -274,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
}

View File

@@ -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)
}

View File

@@ -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
@@ -178,7 +179,7 @@ func parseResponse(payload []byte) (*IPRecord, error) {
ipRecord := &IPRecord{
ReqID: h.ID,
RCode: h.RCode,
Expire: now.Add(time.Minute * 30),
Expire: now.Add(time.Second * 600),
}
L:
@@ -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[:]))

View File

@@ -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,
},

View File

@@ -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
}))
}

View File

@@ -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,
},

View File

@@ -9,8 +9,4 @@ option java_multiple_files = true;
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;
}

View File

@@ -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())
})
})
}

View File

@@ -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)
}

View File

@@ -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,
})

View File

@@ -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 {

View File

@@ -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 {
@@ -114,7 +121,7 @@ func NewDoHLocalNameServer(url *url.URL) *DoHNameServer {
if err != nil {
return nil, err
}
conn, err := internet.DialSystemDNS(ctx, dest, nil)
conn, err := internet.DialSystem(ctx, dest, nil)
log.Record(&log.AccessMessage{
From: "DoH",
To: s.dohURL,
@@ -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
}

View File

@@ -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 != "" {

View File

@@ -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
}

View File

@@ -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.

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 != "" {

View File

@@ -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:
}
}
}

View File

@@ -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)
}
}

View File

@@ -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
View 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)
}

View File

@@ -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

View File

@@ -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 {

View File

@@ -1,8 +1,6 @@
package log
import (
"sync"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/log"
)
@@ -13,26 +11,20 @@ type HandlerCreatorOptions struct {
type HandlerCreator func(LogType, HandlerCreatorOptions) (log.Handler, error)
var handlerCreatorMap = make(map[LogType]HandlerCreator)
var handlerCreatorMapLock = &sync.RWMutex{}
var (
handlerCreatorMap = make(map[LogType]HandlerCreator)
)
func RegisterHandlerCreator(logType LogType, f HandlerCreator) error {
if f == nil {
return newError("nil HandlerCreator")
}
handlerCreatorMapLock.Lock()
defer handlerCreatorMapLock.Unlock()
handlerCreatorMap[logType] = f
return nil
}
func createHandler(logType LogType, options HandlerCreatorOptions) (log.Handler, error) {
handlerCreatorMapLock.RLock()
defer handlerCreatorMapLock.RUnlock()
creator, found := handlerCreatorMap[logType]
if !found {
return nil, newError("unable to create log handler for ", logType)

View File

@@ -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"

View File

@@ -1,530 +0,0 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.27.1
// protoc v3.18.0
// source: app/observatory/config.proto
package observatory
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type ObservationResult struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Status []*OutboundStatus `protobuf:"bytes,1,rep,name=status,proto3" json:"status,omitempty"`
}
func (x *ObservationResult) Reset() {
*x = ObservationResult{}
if protoimpl.UnsafeEnabled {
mi := &file_app_observatory_config_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ObservationResult) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ObservationResult) ProtoMessage() {}
func (x *ObservationResult) ProtoReflect() protoreflect.Message {
mi := &file_app_observatory_config_proto_msgTypes[0]
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 ObservationResult.ProtoReflect.Descriptor instead.
func (*ObservationResult) Descriptor() ([]byte, []int) {
return file_app_observatory_config_proto_rawDescGZIP(), []int{0}
}
func (x *ObservationResult) GetStatus() []*OutboundStatus {
if x != nil {
return x.Status
}
return nil
}
type OutboundStatus struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// @Document Whether this outbound is usable
//@Restriction ReadOnlyForUser
Alive bool `protobuf:"varint,1,opt,name=alive,proto3" json:"alive,omitempty"`
// @Document The time for probe request to finish.
//@Type time.ms
//@Restriction ReadOnlyForUser
Delay int64 `protobuf:"varint,2,opt,name=delay,proto3" json:"delay,omitempty"`
// @Document The last error caused this outbound failed to relay probe request
//@Restriction NotMachineReadable
LastErrorReason string `protobuf:"bytes,3,opt,name=last_error_reason,json=lastErrorReason,proto3" json:"last_error_reason,omitempty"`
// @Document The outbound tag for this Server
//@Type id.outboundTag
OutboundTag string `protobuf:"bytes,4,opt,name=outbound_tag,json=outboundTag,proto3" json:"outbound_tag,omitempty"`
// @Document The time this outbound is known to be alive
//@Type id.outboundTag
LastSeenTime int64 `protobuf:"varint,5,opt,name=last_seen_time,json=lastSeenTime,proto3" json:"last_seen_time,omitempty"`
// @Document The time this outbound is tried
//@Type id.outboundTag
LastTryTime int64 `protobuf:"varint,6,opt,name=last_try_time,json=lastTryTime,proto3" json:"last_try_time,omitempty"`
}
func (x *OutboundStatus) Reset() {
*x = OutboundStatus{}
if protoimpl.UnsafeEnabled {
mi := &file_app_observatory_config_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *OutboundStatus) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*OutboundStatus) ProtoMessage() {}
func (x *OutboundStatus) ProtoReflect() protoreflect.Message {
mi := &file_app_observatory_config_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 OutboundStatus.ProtoReflect.Descriptor instead.
func (*OutboundStatus) Descriptor() ([]byte, []int) {
return file_app_observatory_config_proto_rawDescGZIP(), []int{1}
}
func (x *OutboundStatus) GetAlive() bool {
if x != nil {
return x.Alive
}
return false
}
func (x *OutboundStatus) GetDelay() int64 {
if x != nil {
return x.Delay
}
return 0
}
func (x *OutboundStatus) GetLastErrorReason() string {
if x != nil {
return x.LastErrorReason
}
return ""
}
func (x *OutboundStatus) GetOutboundTag() string {
if x != nil {
return x.OutboundTag
}
return ""
}
func (x *OutboundStatus) GetLastSeenTime() int64 {
if x != nil {
return x.LastSeenTime
}
return 0
}
func (x *OutboundStatus) GetLastTryTime() int64 {
if x != nil {
return x.LastTryTime
}
return 0
}
type ProbeResult struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// @Document Whether this outbound is usable
//@Restriction ReadOnlyForUser
Alive bool `protobuf:"varint,1,opt,name=alive,proto3" json:"alive,omitempty"`
// @Document The time for probe request to finish.
//@Type time.ms
//@Restriction ReadOnlyForUser
Delay int64 `protobuf:"varint,2,opt,name=delay,proto3" json:"delay,omitempty"`
// @Document The error caused this outbound failed to relay probe request
//@Restriction NotMachineReadable
LastErrorReason string `protobuf:"bytes,3,opt,name=last_error_reason,json=lastErrorReason,proto3" json:"last_error_reason,omitempty"`
}
func (x *ProbeResult) Reset() {
*x = ProbeResult{}
if protoimpl.UnsafeEnabled {
mi := &file_app_observatory_config_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ProbeResult) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ProbeResult) ProtoMessage() {}
func (x *ProbeResult) ProtoReflect() protoreflect.Message {
mi := &file_app_observatory_config_proto_msgTypes[2]
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 ProbeResult.ProtoReflect.Descriptor instead.
func (*ProbeResult) Descriptor() ([]byte, []int) {
return file_app_observatory_config_proto_rawDescGZIP(), []int{2}
}
func (x *ProbeResult) GetAlive() bool {
if x != nil {
return x.Alive
}
return false
}
func (x *ProbeResult) GetDelay() int64 {
if x != nil {
return x.Delay
}
return 0
}
func (x *ProbeResult) GetLastErrorReason() string {
if x != nil {
return x.LastErrorReason
}
return ""
}
type Intensity struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// @Document The time interval for a probe request in ms.
//@Type time.ms
ProbeInterval uint32 `protobuf:"varint,1,opt,name=probe_interval,json=probeInterval,proto3" json:"probe_interval,omitempty"`
}
func (x *Intensity) Reset() {
*x = Intensity{}
if protoimpl.UnsafeEnabled {
mi := &file_app_observatory_config_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Intensity) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Intensity) ProtoMessage() {}
func (x *Intensity) ProtoReflect() protoreflect.Message {
mi := &file_app_observatory_config_proto_msgTypes[3]
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 Intensity.ProtoReflect.Descriptor instead.
func (*Intensity) Descriptor() ([]byte, []int) {
return file_app_observatory_config_proto_rawDescGZIP(), []int{3}
}
func (x *Intensity) GetProbeInterval() uint32 {
if x != nil {
return x.ProbeInterval
}
return 0
}
type Config struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// @Document The selectors for outbound under observation
SubjectSelector []string `protobuf:"bytes,2,rep,name=subject_selector,json=subjectSelector,proto3" json:"subject_selector,omitempty"`
ProbeUrl string `protobuf:"bytes,3,opt,name=probe_url,json=probeUrl,proto3" json:"probe_url,omitempty"`
ProbeInterval int64 `protobuf:"varint,4,opt,name=probe_interval,json=probeInterval,proto3" json:"probe_interval,omitempty"`
EnableConcurrency bool `protobuf:"varint,5,opt,name=enable_concurrency,json=enableConcurrency,proto3" json:"enable_concurrency,omitempty"`
}
func (x *Config) Reset() {
*x = Config{}
if protoimpl.UnsafeEnabled {
mi := &file_app_observatory_config_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Config) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Config) ProtoMessage() {}
func (x *Config) ProtoReflect() protoreflect.Message {
mi := &file_app_observatory_config_proto_msgTypes[4]
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 Config.ProtoReflect.Descriptor instead.
func (*Config) Descriptor() ([]byte, []int) {
return file_app_observatory_config_proto_rawDescGZIP(), []int{4}
}
func (x *Config) GetSubjectSelector() []string {
if x != nil {
return x.SubjectSelector
}
return nil
}
func (x *Config) GetProbeUrl() string {
if x != nil {
return x.ProbeUrl
}
return ""
}
func (x *Config) GetProbeInterval() int64 {
if x != nil {
return x.ProbeInterval
}
return 0
}
func (x *Config) GetEnableConcurrency() bool {
if x != nil {
return x.EnableConcurrency
}
return false
}
var File_app_observatory_config_proto protoreflect.FileDescriptor
var file_app_observatory_config_proto_rawDesc = []byte{
0x0a, 0x1c, 0x61, 0x70, 0x70, 0x2f, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72,
0x79, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x19,
0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6f, 0x62,
0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x22, 0x56, 0x0a, 0x11, 0x4f, 0x62, 0x73,
0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x41,
0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29,
0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6f,
0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x4f, 0x75, 0x74, 0x62, 0x6f,
0x75, 0x6e, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75,
0x73, 0x22, 0xd5, 0x01, 0x0a, 0x0e, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x53, 0x74,
0x61, 0x74, 0x75, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x18, 0x01, 0x20,
0x01, 0x28, 0x08, 0x52, 0x05, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x64, 0x65,
0x6c, 0x61, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x64, 0x65, 0x6c, 0x61, 0x79,
0x12, 0x2a, 0x0a, 0x11, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x72,
0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x6c, 0x61, 0x73,
0x74, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x21, 0x0a, 0x0c,
0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x74, 0x61, 0x67, 0x18, 0x04, 0x20, 0x01,
0x28, 0x09, 0x52, 0x0b, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x61, 0x67, 0x12,
0x24, 0x0a, 0x0e, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x65, 0x6e, 0x5f, 0x74, 0x69, 0x6d,
0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x6c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x65,
0x6e, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x22, 0x0a, 0x0d, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x74, 0x72,
0x79, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x6c, 0x61,
0x73, 0x74, 0x54, 0x72, 0x79, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x65, 0x0a, 0x0b, 0x50, 0x72, 0x6f,
0x62, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x6c, 0x69, 0x76,
0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x12, 0x14,
0x0a, 0x05, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x64,
0x65, 0x6c, 0x61, 0x79, 0x12, 0x2a, 0x0a, 0x11, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x65, 0x72, 0x72,
0x6f, 0x72, 0x5f, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
0x0f, 0x6c, 0x61, 0x73, 0x74, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e,
0x22, 0x32, 0x0a, 0x09, 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x79, 0x12, 0x25, 0x0a,
0x0e, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18,
0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x49, 0x6e, 0x74, 0x65,
0x72, 0x76, 0x61, 0x6c, 0x22, 0xa6, 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,
0x29, 0x0a, 0x10, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63,
0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x75, 0x62, 0x6a, 0x65,
0x63, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x72,
0x6f, 0x62, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70,
0x72, 0x6f, 0x62, 0x65, 0x55, 0x72, 0x6c, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x62, 0x65,
0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52,
0x0d, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x2d,
0x0a, 0x12, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72,
0x65, 0x6e, 0x63, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x65, 0x6e, 0x61, 0x62,
0x6c, 0x65, 0x43, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x42, 0x5e, 0x0a,
0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6f, 0x62,
0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 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, 0x6f, 0x62, 0x73, 0x65, 0x72,
0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0xaa, 0x02, 0x14, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x41, 0x70,
0x70, 0x2e, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x62, 0x06, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_app_observatory_config_proto_rawDescOnce sync.Once
file_app_observatory_config_proto_rawDescData = file_app_observatory_config_proto_rawDesc
)
func file_app_observatory_config_proto_rawDescGZIP() []byte {
file_app_observatory_config_proto_rawDescOnce.Do(func() {
file_app_observatory_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_observatory_config_proto_rawDescData)
})
return file_app_observatory_config_proto_rawDescData
}
var file_app_observatory_config_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
var file_app_observatory_config_proto_goTypes = []interface{}{
(*ObservationResult)(nil), // 0: xray.core.app.observatory.ObservationResult
(*OutboundStatus)(nil), // 1: xray.core.app.observatory.OutboundStatus
(*ProbeResult)(nil), // 2: xray.core.app.observatory.ProbeResult
(*Intensity)(nil), // 3: xray.core.app.observatory.Intensity
(*Config)(nil), // 4: xray.core.app.observatory.Config
}
var file_app_observatory_config_proto_depIdxs = []int32{
1, // 0: xray.core.app.observatory.ObservationResult.status:type_name -> xray.core.app.observatory.OutboundStatus
1, // [1:1] is the sub-list for method output_type
1, // [1:1] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension type_name
1, // [1:1] is the sub-list for extension extendee
0, // [0:1] is the sub-list for field type_name
}
func init() { file_app_observatory_config_proto_init() }
func file_app_observatory_config_proto_init() {
if File_app_observatory_config_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_app_observatory_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ObservationResult); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_observatory_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*OutboundStatus); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_observatory_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ProbeResult); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_observatory_config_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Intensity); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_app_observatory_config_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Config); 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{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_app_observatory_config_proto_rawDesc,
NumEnums: 0,
NumMessages: 5,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_app_observatory_config_proto_goTypes,
DependencyIndexes: file_app_observatory_config_proto_depIdxs,
MessageInfos: file_app_observatory_config_proto_msgTypes,
}.Build()
File_app_observatory_config_proto = out.File
file_app_observatory_config_proto_rawDesc = nil
file_app_observatory_config_proto_goTypes = nil
file_app_observatory_config_proto_depIdxs = nil
}

View File

@@ -1,73 +0,0 @@
syntax = "proto3";
package xray.core.app.observatory;
option csharp_namespace = "Xray.App.Observatory";
option go_package = "github.com/xtls/xray-core/app/observatory";
option java_package = "com.xray.app.observatory";
option java_multiple_files = true;
message ObservationResult {
repeated OutboundStatus status = 1;
}
message OutboundStatus{
/* @Document Whether this outbound is usable
@Restriction ReadOnlyForUser
*/
bool alive = 1;
/* @Document The time for probe request to finish.
@Type time.ms
@Restriction ReadOnlyForUser
*/
int64 delay = 2;
/* @Document The last error caused this outbound failed to relay probe request
@Restriction NotMachineReadable
*/
string last_error_reason = 3;
/* @Document The outbound tag for this Server
@Type id.outboundTag
*/
string outbound_tag = 4;
/* @Document The time this outbound is known to be alive
@Type id.outboundTag
*/
int64 last_seen_time = 5;
/* @Document The time this outbound is tried
@Type id.outboundTag
*/
int64 last_try_time = 6;
}
message ProbeResult{
/* @Document Whether this outbound is usable
@Restriction ReadOnlyForUser
*/
bool alive = 1;
/* @Document The time for probe request to finish.
@Type time.ms
@Restriction ReadOnlyForUser
*/
int64 delay = 2;
/* @Document The error caused this outbound failed to relay probe request
@Restriction NotMachineReadable
*/
string last_error_reason = 3;
}
message Intensity{
/* @Document The time interval for a probe request in ms.
@Type time.ms
*/
uint32 probe_interval = 1;
}
message Config {
/* @Document The selectors for outbound under observation
*/
repeated string subject_selector = 2;
string probe_url = 3;
int64 probe_interval = 4;
bool enable_concurrency = 5;
}

View File

@@ -1,26 +0,0 @@
package observatory
import "github.com/xtls/xray-core/common/errors"
type errorCollector struct {
errors *errors.Error
}
func (e *errorCollector) SubmitError(err error) {
if e.errors == nil {
e.errors = newError("underlying connection error").Base(err)
return
}
e.errors = e.errors.Base(newError("underlying connection error").Base(err))
}
func newErrorCollector() *errorCollector {
return &errorCollector{}
}
func (e *errorCollector) UnderlyingError() error {
if e.errors == nil {
return newError("failed to produce report")
}
return e.errors
}

View File

@@ -1,3 +0,0 @@
package observatory
//go:generate go run github.com/xtls/xray-core/common/errors/errorgen

View File

@@ -1,222 +0,0 @@
package observatory
import (
"context"
"github.com/xtls/xray-core/core"
"net"
"net/http"
"net/url"
"sort"
"sync"
"time"
"github.com/golang/protobuf/proto"
"github.com/xtls/xray-core/common"
v2net "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/common/signal/done"
"github.com/xtls/xray-core/common/task"
"github.com/xtls/xray-core/features/extension"
"github.com/xtls/xray-core/features/outbound"
"github.com/xtls/xray-core/transport/internet/tagged"
)
type Observer struct {
config *Config
ctx context.Context
statusLock sync.Mutex
status []*OutboundStatus
finished *done.Instance
ohm outbound.Manager
StatusUpdate func(result *OutboundStatus)
}
func (o *Observer) GetObservation(ctx context.Context) (proto.Message, error) {
return &ObservationResult{Status: o.status}, nil
}
func (o *Observer) Type() interface{} {
return extension.ObservatoryType()
}
func (o *Observer) Start() error {
if o.config != nil && len(o.config.SubjectSelector) != 0 {
o.finished = done.New()
go o.background()
}
return nil
}
func (o *Observer) Close() error {
if o.finished != nil {
return o.finished.Close()
}
return nil
}
func (o *Observer) background() {
for !o.finished.Done() {
hs, ok := o.ohm.(outbound.HandlerSelector)
if !ok {
newError("outbound.Manager is not a HandlerSelector").WriteToLog()
return
}
outbounds := hs.Select(o.config.SubjectSelector)
sort.Strings(outbounds)
o.updateStatus(outbounds)
for _, v := range outbounds {
result := o.probe(v)
o.updateStatusForResult(v, &result)
if o.finished.Done() {
return
}
sleepTime := time.Second * 10
if o.config.ProbeInterval != 0 {
sleepTime = time.Duration(o.config.ProbeInterval)
}
time.Sleep(sleepTime)
}
}
}
func (o *Observer) updateStatus(outbounds []string) {
o.statusLock.Lock()
defer o.statusLock.Unlock()
// TODO should remove old inbound that is removed
_ = outbounds
}
func (o *Observer) probe(outbound string) ProbeResult {
errorCollectorForRequest := newErrorCollector()
httpTransport := http.Transport{
Proxy: func(*http.Request) (*url.URL, error) {
return nil, nil
},
DialContext: func(ctx context.Context, network string, addr string) (net.Conn, error) {
var connection net.Conn
taskErr := task.Run(ctx, func() error {
// MUST use V2Fly's built in context system
dest, err := v2net.ParseDestination(network + ":" + addr)
if err != nil {
return newError("cannot understand address").Base(err)
}
trackedCtx := session.TrackedConnectionError(o.ctx, errorCollectorForRequest)
conn, err := tagged.Dialer(trackedCtx, dest, outbound)
if err != nil {
return newError("cannot dial remote address ", dest).Base(err)
}
connection = conn
return nil
})
if taskErr != nil {
return nil, newError("cannot finish connection").Base(taskErr)
}
return connection, nil
},
TLSHandshakeTimeout: time.Second * 5,
}
httpClient := &http.Client{
Transport: &httpTransport,
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
},
Jar: nil,
Timeout: time.Second * 5,
}
var GETTime time.Duration
err := task.Run(o.ctx, func() error {
startTime := time.Now()
probeURL := "https://api.v2fly.org/checkConnection.svgz"
if o.config.ProbeUrl != "" {
probeURL = o.config.ProbeUrl
}
response, err := httpClient.Get(probeURL)
if err != nil {
return newError("outbound failed to relay connection").Base(err)
}
if response.Body != nil {
response.Body.Close()
}
endTime := time.Now()
GETTime = endTime.Sub(startTime)
return nil
})
if err != nil {
fullerr := newError("underlying connection failed").Base(errorCollectorForRequest.UnderlyingError())
fullerr = newError("with outbound handler report").Base(fullerr)
fullerr = newError("GET request failed:", err).Base(fullerr)
fullerr = newError("the outbound ", outbound, " is dead:").Base(fullerr)
fullerr = fullerr.AtInfo()
fullerr.WriteToLog()
return ProbeResult{Alive: false, LastErrorReason: fullerr.Error()}
}
newError("the outbound ", outbound, " is alive:", GETTime.Seconds()).AtInfo().WriteToLog()
return ProbeResult{Alive: true, Delay: GETTime.Milliseconds()}
}
func (o *Observer) updateStatusForResult(outbound string, result *ProbeResult) {
o.statusLock.Lock()
defer o.statusLock.Unlock()
var status *OutboundStatus
if location := o.findStatusLocationLockHolderOnly(outbound); location != -1 {
status = o.status[location]
} else {
status = &OutboundStatus{}
o.status = append(o.status, status)
}
status.LastTryTime = time.Now().Unix()
status.OutboundTag = outbound
status.Alive = result.Alive
if result.Alive {
status.Delay = result.Delay
status.LastSeenTime = status.LastTryTime
status.LastErrorReason = ""
} else {
status.LastErrorReason = result.LastErrorReason
status.Delay = 99999999
}
if o.StatusUpdate != nil {
o.StatusUpdate(status)
}
}
func (o *Observer) findStatusLocationLockHolderOnly(outbound string) int {
for i, v := range o.status {
if v.OutboundTag == outbound {
return i
}
}
return -1
}
func New(ctx context.Context, config *Config) (*Observer, error) {
var outboundManager outbound.Manager
err := core.RequireFeatures(ctx, func(om outbound.Manager) {
outboundManager = om
})
if err != nil {
return nil, newError("Cannot get depended features").Base(err)
}
return &Observer{
config: config,
ctx: ctx,
ohm: outboundManager,
}, nil
}
func init() {
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return New(ctx, config.(*Config))
}))
}

View File

@@ -1,12 +0,0 @@
package observatory
func (o *Observer) UpdateStatus(result *OutboundStatus) {
o.statusLock.Lock()
defer o.statusLock.Unlock()
if location := o.findStatusLocationLockHolderOnly(result.OutboundTag); location != -1 {
o.status[location] = result
} else {
o.status = append(o.status, result)
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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 (
@@ -69,64 +74,6 @@ func (KnownProtocols) EnumDescriptor() ([]byte, []int) {
return file_app_proxyman_config_proto_rawDescGZIP(), []int{0}
}
type DomainStrategy int32
const (
DomainStrategy_AS_IS DomainStrategy = 0
DomainStrategy_USE_IP DomainStrategy = 1
DomainStrategy_USE_IP4 DomainStrategy = 2
DomainStrategy_USE_IP6 DomainStrategy = 3
DomainStrategy_PREFER_IP4 DomainStrategy = 4
DomainStrategy_PREFER_IP6 DomainStrategy = 5
)
// Enum value maps for DomainStrategy.
var (
DomainStrategy_name = map[int32]string{
0: "AS_IS",
1: "USE_IP",
2: "USE_IP4",
3: "USE_IP6",
4: "PREFER_IP4",
5: "PREFER_IP6",
}
DomainStrategy_value = map[string]int32{
"AS_IS": 0,
"USE_IP": 1,
"USE_IP4": 2,
"USE_IP6": 3,
"PREFER_IP4": 4,
"PREFER_IP6": 5,
}
)
func (x DomainStrategy) Enum() *DomainStrategy {
p := new(DomainStrategy)
*p = x
return p
}
func (x DomainStrategy) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (DomainStrategy) Descriptor() protoreflect.EnumDescriptor {
return file_app_proxyman_config_proto_enumTypes[1].Descriptor()
}
func (DomainStrategy) Type() protoreflect.EnumType {
return &file_app_proxyman_config_proto_enumTypes[1]
}
func (x DomainStrategy) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use DomainStrategy.Descriptor instead.
func (DomainStrategy) EnumDescriptor() ([]byte, []int) {
return file_app_proxyman_config_proto_rawDescGZIP(), []int{1}
}
type AllocationStrategy_Type int32
const (
@@ -163,11 +110,11 @@ func (x AllocationStrategy_Type) String() string {
}
func (AllocationStrategy_Type) Descriptor() protoreflect.EnumDescriptor {
return file_app_proxyman_config_proto_enumTypes[2].Descriptor()
return file_app_proxyman_config_proto_enumTypes[1].Descriptor()
}
func (AllocationStrategy_Type) Type() protoreflect.EnumType {
return &file_app_proxyman_config_proto_enumTypes[2]
return &file_app_proxyman_config_proto_enumTypes[1]
}
func (x AllocationStrategy_Type) Number() protoreflect.EnumNumber {
@@ -298,7 +245,6 @@ type SniffingConfig struct {
// Whether should only try to sniff metadata without waiting for client input.
// Can be used to support SMTP like protocol where server send the first message.
MetadataOnly bool `protobuf:"varint,4,opt,name=metadata_only,json=metadataOnly,proto3" json:"metadata_only,omitempty"`
RouteOnly bool `protobuf:"varint,5,opt,name=route_only,json=routeOnly,proto3" json:"route_only,omitempty"`
}
func (x *SniffingConfig) Reset() {
@@ -361,13 +307,6 @@ func (x *SniffingConfig) GetMetadataOnly() bool {
return false
}
func (x *SniffingConfig) GetRouteOnly() bool {
if x != nil {
return x.RouteOnly
}
return false
}
type ReceiverConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -581,7 +520,6 @@ type SenderConfig struct {
StreamSettings *internet.StreamConfig `protobuf:"bytes,2,opt,name=stream_settings,json=streamSettings,proto3" json:"stream_settings,omitempty"`
ProxySettings *internet.ProxyConfig `protobuf:"bytes,3,opt,name=proxy_settings,json=proxySettings,proto3" json:"proxy_settings,omitempty"`
MultiplexSettings *MultiplexingConfig `protobuf:"bytes,4,opt,name=multiplex_settings,json=multiplexSettings,proto3" json:"multiplex_settings,omitempty"`
DomainStrategy DomainStrategy `protobuf:"varint,5,opt,name=domain_strategy,json=domainStrategy,proto3,enum=xray.app.proxyman.DomainStrategy" json:"domain_strategy,omitempty"`
}
func (x *SenderConfig) Reset() {
@@ -644,13 +582,6 @@ func (x *SenderConfig) GetMultiplexSettings() *MultiplexingConfig {
return nil
}
func (x *SenderConfig) GetDomainStrategy() DomainStrategy {
if x != nil {
return x.DomainStrategy
}
return DomainStrategy_AS_IS
}
type MultiplexingConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -843,7 +774,7 @@ var file_app_proxyman_config_proto_rawDesc = []byte{
0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x2c, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12,
0x0a, 0x0a, 0x06, 0x41, 0x6c, 0x77, 0x61, 0x79, 0x73, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x52,
0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x45, 0x78, 0x74, 0x65, 0x72,
0x6e, 0x61, 0x6c, 0x10, 0x02, 0x22, 0xcc, 0x01, 0x0a, 0x0e, 0x53, 0x6e, 0x69, 0x66, 0x66, 0x69,
0x6e, 0x61, 0x6c, 0x10, 0x02, 0x22, 0xad, 0x01, 0x0a, 0x0e, 0x53, 0x6e, 0x69, 0x66, 0x66, 0x69,
0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62,
0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c,
0x65, 0x64, 0x12, 0x31, 0x0a, 0x14, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f,
@@ -854,99 +785,86 @@ var file_app_proxyman_config_proto_rawDesc = []byte{
0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x45, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64,
0x12, 0x23, 0x0a, 0x0d, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x6f, 0x6e, 0x6c,
0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
0x61, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x6f,
0x6e, 0x6c, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x72, 0x6f, 0x75, 0x74, 0x65,
0x4f, 0x6e, 0x6c, 0x79, 0x22, 0x90, 0x04, 0x0a, 0x0e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65,
0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x39, 0x0a, 0x0a, 0x70, 0x6f, 0x72, 0x74, 0x5f,
0x72, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x78, 0x72,
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x6f,
0x72, 0x74, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x61, 0x6e,
0x67, 0x65, 0x12, 0x33, 0x0a, 0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 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,
0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x12, 0x56, 0x0a, 0x13, 0x61, 0x6c, 0x6c, 0x6f, 0x63,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x03,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e,
0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x12, 0x61, 0x6c, 0x6c,
0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12,
0x4e, 0x0a, 0x0f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e,
0x67, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e,
0x65, 0x74, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52,
0x0e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12,
0x40, 0x0a, 0x1c, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x5f, 0x6f, 0x72, 0x69, 0x67, 0x69,
0x6e, 0x61, 0x6c, 0x5f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18,
0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1a, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x4f, 0x72,
0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x12, 0x4e, 0x0a, 0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x6f, 0x76, 0x65, 0x72,
0x72, 0x69, 0x64, 0x65, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x21, 0x2e, 0x78, 0x72, 0x61,
0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x4b,
0x6e, 0x6f, 0x77, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x73, 0x42, 0x02, 0x18,
0x01, 0x52, 0x0e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64,
0x65, 0x12, 0x4e, 0x0a, 0x11, 0x73, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x65,
0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x78,
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e,
0x2e, 0x53, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52,
0x10, 0x73, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67,
0x73, 0x4a, 0x04, 0x08, 0x06, 0x10, 0x07, 0x22, 0xc0, 0x01, 0x0a, 0x14, 0x49, 0x6e, 0x62, 0x6f,
0x75, 0x6e, 0x64, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74,
0x61, 0x67, 0x12, 0x4d, 0x0a, 0x11, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x5f, 0x73,
0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e,
0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69,
0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52,
0x10, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67,
0x73, 0x12, 0x47, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69,
0x6e, 0x67, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79,
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54,
0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0d, 0x70, 0x72, 0x6f,
0x78, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x10, 0x0a, 0x0e, 0x4f, 0x75,
0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0xfc, 0x02, 0x0a,
0x0c, 0x53, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2d, 0x0a,
0x03, 0x76, 0x69, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61,
0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f,
0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x03, 0x76, 0x69, 0x61, 0x12, 0x4e, 0x0a, 0x0f,
0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18,
0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61,
0x61, 0x4f, 0x6e, 0x6c, 0x79, 0x22, 0x90, 0x04, 0x0a, 0x0e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76,
0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x39, 0x0a, 0x0a, 0x70, 0x6f, 0x72, 0x74,
0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x78,
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x50,
0x6f, 0x72, 0x74, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x61,
0x6e, 0x67, 0x65, 0x12, 0x33, 0x0a, 0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 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, 0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x12, 0x56, 0x0a, 0x13, 0x61, 0x6c, 0x6c, 0x6f,
0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18,
0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70,
0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x12, 0x61, 0x6c,
0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79,
0x12, 0x4e, 0x0a, 0x0f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69,
0x6e, 0x67, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79,
0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72,
0x6e, 0x65, 0x74, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
0x52, 0x0e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73,
0x12, 0x40, 0x0a, 0x1c, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x5f, 0x6f, 0x72, 0x69, 0x67,
0x69, 0x6e, 0x61, 0x6c, 0x5f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1a, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x4f,
0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x12, 0x4e, 0x0a, 0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x6f, 0x76, 0x65,
0x72, 0x72, 0x69, 0x64, 0x65, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x21, 0x2e, 0x78, 0x72,
0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e,
0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x73, 0x42, 0x02,
0x18, 0x01, 0x52, 0x0e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69,
0x64, 0x65, 0x12, 0x4e, 0x0a, 0x11, 0x73, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x5f, 0x73,
0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e,
0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61,
0x6e, 0x2e, 0x53, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
0x52, 0x10, 0x73, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e,
0x67, 0x73, 0x4a, 0x04, 0x08, 0x06, 0x10, 0x07, 0x22, 0xc0, 0x01, 0x0a, 0x14, 0x49, 0x6e, 0x62,
0x6f, 0x75, 0x6e, 0x64, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69,
0x67, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
0x74, 0x61, 0x67, 0x12, 0x4d, 0x0a, 0x11, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x5f,
0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20,
0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72,
0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
0x52, 0x10, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e,
0x67, 0x73, 0x12, 0x47, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74,
0x69, 0x6e, 0x67, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61,
0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e,
0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0d, 0x70, 0x72,
0x6f, 0x78, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x10, 0x0a, 0x0e, 0x4f,
0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0xb0, 0x02,
0x0a, 0x0c, 0x53, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2d,
0x0a, 0x03, 0x76, 0x69, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x78, 0x72,
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50,
0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x03, 0x76, 0x69, 0x61, 0x12, 0x4e, 0x0a,
0x0f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73,
0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72,
0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74,
0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x73,
0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x4b, 0x0a,
0x0e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18,
0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61,
0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e,
0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x73, 0x74,
0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x4b, 0x0a, 0x0e,
0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x03,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e,
0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x50,
0x72, 0x6f, 0x78, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78,
0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x54, 0x0a, 0x12, 0x6d, 0x75, 0x6c,
0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18,
0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70,
0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70,
0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x11, 0x6d, 0x75,
0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12,
0x4a, 0x0a, 0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65,
0x67, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x21, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 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, 0x22, 0x50, 0x0a, 0x12, 0x4d,
0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69,
0x67, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01,
0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x63,
0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d,
0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x2a, 0x23, 0x0a,
0x0e, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x73, 0x12,
0x08, 0x0a, 0x04, 0x48, 0x54, 0x54, 0x50, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x54, 0x4c, 0x53,
0x10, 0x01, 0x2a, 0x61, 0x0a, 0x0e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74, 0x72, 0x61,
0x74, 0x65, 0x67, 0x79, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x53, 0x5f, 0x49, 0x53, 0x10, 0x00, 0x12,
0x0a, 0x0a, 0x06, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x55,
0x53, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f,
0x49, 0x50, 0x36, 0x10, 0x03, 0x12, 0x0e, 0x0a, 0x0a, 0x50, 0x52, 0x45, 0x46, 0x45, 0x52, 0x5f,
0x49, 0x50, 0x34, 0x10, 0x04, 0x12, 0x0e, 0x0a, 0x0a, 0x50, 0x52, 0x45, 0x46, 0x45, 0x52, 0x5f,
0x49, 0x50, 0x36, 0x10, 0x05, 0x42, 0x55, 0x0a, 0x15, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61,
0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x50, 0x01,
0x5a, 0x26, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c,
0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f,
0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0xaa, 0x02, 0x11, 0x58, 0x72, 0x61, 0x79, 0x2e,
0x41, 0x70, 0x70, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x62, 0x06, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x33,
0x50, 0x72, 0x6f, 0x78, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0d, 0x70, 0x72, 0x6f,
0x78, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x54, 0x0a, 0x12, 0x6d, 0x75,
0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73,
0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x4d, 0x75, 0x6c, 0x74, 0x69,
0x70, 0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x11, 0x6d,
0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73,
0x22, 0x50, 0x0a, 0x12, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67,
0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65,
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64,
0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18,
0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e,
0x63, 0x79, 0x2a, 0x23, 0x0a, 0x0e, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f,
0x63, 0x6f, 0x6c, 0x73, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x54, 0x54, 0x50, 0x10, 0x00, 0x12, 0x07,
0x0a, 0x03, 0x54, 0x4c, 0x53, 0x10, 0x01, 0x42, 0x55, 0x0a, 0x15, 0x63, 0x6f, 0x6d, 0x2e, 0x78,
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e,
0x50, 0x01, 0x5a, 0x26, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78,
0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70,
0x70, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0xaa, 0x02, 0x11, 0x58, 0x72, 0x61,
0x79, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x62, 0x06,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@@ -961,50 +879,48 @@ func file_app_proxyman_config_proto_rawDescGZIP() []byte {
return file_app_proxyman_config_proto_rawDescData
}
var file_app_proxyman_config_proto_enumTypes = make([]protoimpl.EnumInfo, 3)
var file_app_proxyman_config_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
var file_app_proxyman_config_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
var file_app_proxyman_config_proto_goTypes = []interface{}{
(KnownProtocols)(0), // 0: xray.app.proxyman.KnownProtocols
(DomainStrategy)(0), // 1: xray.app.proxyman.DomainStrategy
(AllocationStrategy_Type)(0), // 2: xray.app.proxyman.AllocationStrategy.Type
(*InboundConfig)(nil), // 3: xray.app.proxyman.InboundConfig
(*AllocationStrategy)(nil), // 4: xray.app.proxyman.AllocationStrategy
(*SniffingConfig)(nil), // 5: xray.app.proxyman.SniffingConfig
(*ReceiverConfig)(nil), // 6: xray.app.proxyman.ReceiverConfig
(*InboundHandlerConfig)(nil), // 7: xray.app.proxyman.InboundHandlerConfig
(*OutboundConfig)(nil), // 8: xray.app.proxyman.OutboundConfig
(*SenderConfig)(nil), // 9: xray.app.proxyman.SenderConfig
(*MultiplexingConfig)(nil), // 10: xray.app.proxyman.MultiplexingConfig
(*AllocationStrategy_AllocationStrategyConcurrency)(nil), // 11: xray.app.proxyman.AllocationStrategy.AllocationStrategyConcurrency
(*AllocationStrategy_AllocationStrategyRefresh)(nil), // 12: xray.app.proxyman.AllocationStrategy.AllocationStrategyRefresh
(*net.PortRange)(nil), // 13: xray.common.net.PortRange
(*net.IPOrDomain)(nil), // 14: xray.common.net.IPOrDomain
(*internet.StreamConfig)(nil), // 15: xray.transport.internet.StreamConfig
(*serial.TypedMessage)(nil), // 16: xray.common.serial.TypedMessage
(*internet.ProxyConfig)(nil), // 17: xray.transport.internet.ProxyConfig
(AllocationStrategy_Type)(0), // 1: xray.app.proxyman.AllocationStrategy.Type
(*InboundConfig)(nil), // 2: xray.app.proxyman.InboundConfig
(*AllocationStrategy)(nil), // 3: xray.app.proxyman.AllocationStrategy
(*SniffingConfig)(nil), // 4: xray.app.proxyman.SniffingConfig
(*ReceiverConfig)(nil), // 5: xray.app.proxyman.ReceiverConfig
(*InboundHandlerConfig)(nil), // 6: xray.app.proxyman.InboundHandlerConfig
(*OutboundConfig)(nil), // 7: xray.app.proxyman.OutboundConfig
(*SenderConfig)(nil), // 8: xray.app.proxyman.SenderConfig
(*MultiplexingConfig)(nil), // 9: xray.app.proxyman.MultiplexingConfig
(*AllocationStrategy_AllocationStrategyConcurrency)(nil), // 10: xray.app.proxyman.AllocationStrategy.AllocationStrategyConcurrency
(*AllocationStrategy_AllocationStrategyRefresh)(nil), // 11: xray.app.proxyman.AllocationStrategy.AllocationStrategyRefresh
(*net.PortRange)(nil), // 12: xray.common.net.PortRange
(*net.IPOrDomain)(nil), // 13: xray.common.net.IPOrDomain
(*internet.StreamConfig)(nil), // 14: xray.transport.internet.StreamConfig
(*serial.TypedMessage)(nil), // 15: xray.common.serial.TypedMessage
(*internet.ProxyConfig)(nil), // 16: xray.transport.internet.ProxyConfig
}
var file_app_proxyman_config_proto_depIdxs = []int32{
2, // 0: xray.app.proxyman.AllocationStrategy.type:type_name -> xray.app.proxyman.AllocationStrategy.Type
11, // 1: xray.app.proxyman.AllocationStrategy.concurrency:type_name -> xray.app.proxyman.AllocationStrategy.AllocationStrategyConcurrency
12, // 2: xray.app.proxyman.AllocationStrategy.refresh:type_name -> xray.app.proxyman.AllocationStrategy.AllocationStrategyRefresh
13, // 3: xray.app.proxyman.ReceiverConfig.port_range:type_name -> xray.common.net.PortRange
14, // 4: xray.app.proxyman.ReceiverConfig.listen:type_name -> xray.common.net.IPOrDomain
4, // 5: xray.app.proxyman.ReceiverConfig.allocation_strategy:type_name -> xray.app.proxyman.AllocationStrategy
15, // 6: xray.app.proxyman.ReceiverConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig
1, // 0: xray.app.proxyman.AllocationStrategy.type:type_name -> xray.app.proxyman.AllocationStrategy.Type
10, // 1: xray.app.proxyman.AllocationStrategy.concurrency:type_name -> xray.app.proxyman.AllocationStrategy.AllocationStrategyConcurrency
11, // 2: xray.app.proxyman.AllocationStrategy.refresh:type_name -> xray.app.proxyman.AllocationStrategy.AllocationStrategyRefresh
12, // 3: xray.app.proxyman.ReceiverConfig.port_range:type_name -> xray.common.net.PortRange
13, // 4: xray.app.proxyman.ReceiverConfig.listen:type_name -> xray.common.net.IPOrDomain
3, // 5: xray.app.proxyman.ReceiverConfig.allocation_strategy:type_name -> xray.app.proxyman.AllocationStrategy
14, // 6: xray.app.proxyman.ReceiverConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig
0, // 7: xray.app.proxyman.ReceiverConfig.domain_override:type_name -> xray.app.proxyman.KnownProtocols
5, // 8: xray.app.proxyman.ReceiverConfig.sniffing_settings:type_name -> xray.app.proxyman.SniffingConfig
16, // 9: xray.app.proxyman.InboundHandlerConfig.receiver_settings:type_name -> xray.common.serial.TypedMessage
16, // 10: xray.app.proxyman.InboundHandlerConfig.proxy_settings:type_name -> xray.common.serial.TypedMessage
14, // 11: xray.app.proxyman.SenderConfig.via:type_name -> xray.common.net.IPOrDomain
15, // 12: xray.app.proxyman.SenderConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig
17, // 13: xray.app.proxyman.SenderConfig.proxy_settings:type_name -> xray.transport.internet.ProxyConfig
10, // 14: xray.app.proxyman.SenderConfig.multiplex_settings:type_name -> xray.app.proxyman.MultiplexingConfig
1, // 15: xray.app.proxyman.SenderConfig.domain_strategy:type_name -> xray.app.proxyman.DomainStrategy
16, // [16:16] is the sub-list for method output_type
16, // [16:16] is the sub-list for method input_type
16, // [16:16] is the sub-list for extension type_name
16, // [16:16] is the sub-list for extension extendee
0, // [0:16] is the sub-list for field type_name
4, // 8: xray.app.proxyman.ReceiverConfig.sniffing_settings:type_name -> xray.app.proxyman.SniffingConfig
15, // 9: xray.app.proxyman.InboundHandlerConfig.receiver_settings:type_name -> xray.common.serial.TypedMessage
15, // 10: xray.app.proxyman.InboundHandlerConfig.proxy_settings:type_name -> xray.common.serial.TypedMessage
13, // 11: xray.app.proxyman.SenderConfig.via:type_name -> xray.common.net.IPOrDomain
14, // 12: xray.app.proxyman.SenderConfig.stream_settings:type_name -> xray.transport.internet.StreamConfig
16, // 13: xray.app.proxyman.SenderConfig.proxy_settings:type_name -> xray.transport.internet.ProxyConfig
9, // 14: xray.app.proxyman.SenderConfig.multiplex_settings:type_name -> xray.app.proxyman.MultiplexingConfig
15, // [15:15] is the sub-list for method output_type
15, // [15:15] is the sub-list for method input_type
15, // [15:15] is the sub-list for extension type_name
15, // [15:15] is the sub-list for extension extendee
0, // [0:15] is the sub-list for field type_name
}
func init() { file_app_proxyman_config_proto_init() }
@@ -1139,7 +1055,7 @@ func file_app_proxyman_config_proto_init() {
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_app_proxyman_config_proto_rawDesc,
NumEnums: 3,
NumEnums: 2,
NumMessages: 10,
NumExtensions: 0,
NumServices: 0,

View File

@@ -57,12 +57,10 @@ message SniffingConfig {
// Supported values are "http", "tls", "fakedns".
repeated string destination_override = 2;
repeated string domains_excluded = 3;
// Whether should only try to sniff metadata without waiting for client input.
// Can be used to support SMTP like protocol where server send the first message.
bool metadata_only = 4;
bool route_only = 5;
}
message ReceiverConfig {
@@ -88,22 +86,12 @@ message InboundHandlerConfig {
message OutboundConfig {}
enum DomainStrategy {
AS_IS = 0;
USE_IP = 1;
USE_IP4 = 2;
USE_IP6 = 3;
PREFER_IP4 = 4;
PREFER_IP6 = 5;
}
message SenderConfig {
// Send traffic through the given IP. Only IP is allowed.
xray.common.net.IPOrDomain via = 1;
xray.transport.internet.StreamConfig stream_settings = 2;
xray.transport.internet.ProxyConfig proxy_settings = 3;
MultiplexingConfig multiplex_settings = 4;
DomainStrategy domain_strategy = 5;
}
message MultiplexingConfig {

View File

@@ -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,
@@ -101,7 +99,6 @@ func (w *tcpWorker) callback(conn stat.Connection) {
content.SniffingRequest.OverrideDestinationForProtocol = w.sniffingConfig.DestinationOverride
content.SniffingRequest.ExcludeForDomain = w.sniffingConfig.DomainsExcluded
content.SniffingRequest.MetadataOnly = w.sniffingConfig.MetadataOnly
content.SniffingRequest.RouteOnly = w.sniffingConfig.RouteOnly
}
ctx = session.ContextWithContent(ctx, content)
@@ -120,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 {
@@ -161,11 +158,6 @@ type udpConn struct {
done *done.Instance
uplink stats.Counter
downlink stats.Counter
inactive bool
}
func (c *udpConn) setInactive() {
c.inactive = true
}
func (c *udpConn) updateActivity() {
@@ -326,18 +318,13 @@ func (w *udpWorker) callback(b *buf.Buffer, source net.Destination, originalDest
content.SniffingRequest.Enabled = w.sniffingConfig.Enabled
content.SniffingRequest.OverrideDestinationForProtocol = w.sniffingConfig.DestinationOverride
content.SniffingRequest.MetadataOnly = w.sniffingConfig.MetadataOnly
content.SniffingRequest.RouteOnly = w.sniffingConfig.RouteOnly
}
ctx = session.ContextWithContent(ctx, content)
if err := w.proxy.Process(ctx, net.Network_UDP, conn, w.dispatcher); err != nil {
newError("connection ends").Base(err).WriteToLog(session.ExportIDToError(ctx))
}
conn.Close()
// conn not removed by checker TODO may be lock worker here is better
if !conn.inactive {
conn.setInactive()
w.removeConn(id)
}
w.removeConn(id)
}()
}
}
@@ -365,11 +352,8 @@ func (w *udpWorker) clean() error {
}
for addr, conn := range w.activeConn {
if nowSec-atomic.LoadInt64(&conn.lastActivityTime) > 5*60 { // TODO Timeout too small
if !conn.inactive {
conn.setInactive()
delete(w.activeConn, addr)
}
if nowSec-atomic.LoadInt64(&conn.lastActivityTime) > 300 {
delete(w.activeConn, addr)
conn.Close()
}
}
@@ -452,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,
@@ -477,7 +461,6 @@ func (w *dsWorker) callback(conn stat.Connection) {
content.SniffingRequest.OverrideDestinationForProtocol = w.sniffingConfig.DestinationOverride
content.SniffingRequest.ExcludeForDomain = w.sniffingConfig.DomainsExcluded
content.SniffingRequest.MetadataOnly = w.sniffingConfig.MetadataOnly
content.SniffingRequest.RouteOnly = w.sniffingConfig.RouteOnly
}
ctx = session.ContextWithContent(ctx, content)
@@ -497,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 {

View File

@@ -2,8 +2,6 @@ package outbound
import (
"context"
"github.com/xtls/xray-core/features/dns"
"github.com/xtls/xray-core/transport/internet/stat"
"github.com/xtls/xray-core/app/proxyman"
"github.com/xtls/xray-core/common"
@@ -54,7 +52,6 @@ type Handler struct {
streamSettings *internet.MemoryStreamConfig
proxy proxy.Outbound
outboundManager outbound.Manager
dnsClient dns.Client
mux *mux.ClientManager
uplinkCounter stats.Counter
downlinkCounter stats.Counter
@@ -67,7 +64,6 @@ func NewHandler(ctx context.Context, config *core.OutboundHandlerConfig) (outbou
h := &Handler{
tag: config.Tag,
outboundManager: v.GetFeature(outbound.ManagerType()).(outbound.Manager),
dnsClient: v.GetFeature(dns.ClientType()).(dns.Client),
uplinkCounter: uplinkCounter,
downlinkCounter: downlinkCounter,
}
@@ -142,47 +138,7 @@ func (h *Handler) Dispatch(ctx context.Context, link *transport.Link) {
common.Interrupt(link.Writer)
}
} else {
outbound := session.OutboundFromContext(ctx)
destination := outbound.Target
var domainString string
if destination.Address.Family().IsDomain() {
domainString = destination.Address.Domain()
} else if outbound.RouteTarget.Address != nil && outbound.RouteTarget.Address.Family().IsDomain() {
domainString = outbound.RouteTarget.Address.Domain()
} else {
domainString = ""
}
if h.senderSettings != nil && h.senderSettings.DomainStrategy != proxyman.DomainStrategy_AS_IS && domainString != "" {
var ips []net.IP
var err error
option := dns.IPOption{
IPv4Enable: true,
IPv6Enable: true,
FakeEnable: false,
}
switch h.senderSettings.DomainStrategy {
case proxyman.DomainStrategy_USE_IP4:
option.IPv6Enable = false
case proxyman.DomainStrategy_USE_IP6:
option.IPv4Enable = false
}
ips, err = h.dnsClient.LookupIP(domainString, option)
if err == nil {
switch h.senderSettings.DomainStrategy {
case proxyman.DomainStrategy_PREFER_IP4:
ips = reorderAddresses(ips, false)
case proxyman.DomainStrategy_PREFER_IP6:
ips = reorderAddresses(ips, true)
}
destination.Address = net.IPAddress(ips[0])
outbound.Target = destination
}
}
err := h.proxy.Process(ctx, link, h)
if err != nil {
if err := h.proxy.Process(ctx, link, h); err != nil {
// Ensure outbound ray is properly closed.
newError("failed to process outbound traffic").Base(err).WriteToLog(session.ExportIDToError(ctx))
common.Interrupt(link.Writer)
@@ -193,18 +149,6 @@ func (h *Handler) Dispatch(ctx context.Context, link *transport.Link) {
}
}
func reorderAddresses(ips []net.IP, preferIPv6 bool) []net.IP {
var result []net.IP
for i := 0; i < 2; i++ {
for _, ip := range ips {
if (preferIPv6 == (i == 0)) == (ip.To4() == nil) {
result = append(result, ip)
}
}
}
return result
}
// Address implements internet.Dialer.
func (h *Handler) Address() net.Address {
if h.senderSettings == nil || h.senderSettings.Via == nil {
@@ -214,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
@@ -257,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,

View File

@@ -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")
}
}

View File

@@ -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"
@@ -147,7 +146,7 @@ func (w *BridgeWorker) Connections() uint32 {
return w.worker.ActiveConnections()
}
func (w *BridgeWorker) handleInternalConn(link *transport.Link) {
func (w *BridgeWorker) handleInternalConn(link transport.Link) {
go func() {
reader := link.Reader
for {
@@ -181,7 +180,7 @@ func (w *BridgeWorker) Dispatch(ctx context.Context, dest net.Destination) (*tra
uplinkReader, uplinkWriter := pipe.New(opt...)
downlinkReader, downlinkWriter := pipe.New(opt...)
w.handleInternalConn(&transport.Link{
w.handleInternalConn(transport.Link{
Reader: downlinkReader,
Writer: uplinkWriter,
})
@@ -191,16 +190,3 @@ func (w *BridgeWorker) Dispatch(ctx context.Context, dest net.Destination) (*tra
Writer: downlinkWriter,
}, nil
}
func (w *BridgeWorker) DispatchLink(ctx context.Context, dest net.Destination, link *transport.Link) error {
if !isInternalDomain(dest) {
ctx = session.ContextWithInbound(ctx, &session.Inbound{
Tag: w.tag,
})
return w.dispatcher.DispatchLink(ctx, dest, link)
}
w.handleInternalConn(link)
return nil
}

View File

@@ -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 (

View File

@@ -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"

View File

@@ -1,10 +1,7 @@
package router
import (
"context"
"github.com/xtls/xray-core/common/dice"
"github.com/xtls/xray-core/features/extension"
"github.com/xtls/xray-core/features/outbound"
)
@@ -12,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)
@@ -44,8 +42,3 @@ func (b *Balancer) PickOutbound() (string, error) {
}
return tag, nil
}
func (b *Balancer) InjectContext(ctx context.Context) {
if contextReceiver, ok := b.strategy.(extension.ContextReceiver); ok {
contextReceiver.InjectContext(ctx)
}
}

View File

@@ -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 {

View File

@@ -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
}

View File

@@ -28,17 +28,8 @@ func (c routingContext) GetTargetPort() net.Port {
return net.Port(c.RoutingContext.GetTargetPort())
}
func (c routingContext) GetUid() uint32 {
return 0
}
func (c routingContext) GetAppStatus() []string {
return nil
}
// 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
}

View File

@@ -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 {
@@ -333,49 +315,3 @@ func (m *AttributeMatcher) Apply(ctx routing.Context) bool {
}
return m.Match(attributes)
}
type UidMatcher struct {
uidList map[uint32]bool
}
func NewUidMatcher(list *net.UidList) *UidMatcher {
m := UidMatcher{uidList: map[uint32]bool{}}
for _, uid := range list.Uid {
m.uidList[uid] = true
}
return &m
}
func (u UidMatcher) Apply(ctx routing.Context) bool {
return u.uidList[ctx.GetUid()]
}
type AppStatusMatcher struct {
appStatus map[string]bool
}
func NewAppStatusMatcher(appStatus []string) *AppStatusMatcher {
m := &AppStatusMatcher{
appStatus: map[string]bool{},
}
for _, status := range appStatus {
m.appStatus[status] = true
}
return m
}
// Apply implements Condition.
func (m *AppStatusMatcher) Apply(ctx routing.Context) bool {
status := ctx.GetAppStatus()
if len(status) == 0 {
return false
}
for _, s := range status {
if !m.appStatus[s] {
return false
}
}
return true
}

View File

@@ -13,12 +13,11 @@ type ipv6 struct {
}
type GeoIPMatcher struct {
countryCode string
reverseMatch bool
ip4 []uint32
prefix4 []uint8
ip6 []ipv6
prefix6 []uint8
countryCode string
ip4 []uint32
prefix4 []uint8
ip6 []ipv6
prefix6 []uint8
}
func normalize4(ip uint32, prefix uint8) uint32 {
@@ -59,7 +58,7 @@ func (m *GeoIPMatcher) Init(cidrs []*CIDR) error {
m.ip6 = make([]ipv6, 0, ip6Count)
m.prefix6 = make([]uint8, 0, ip6Count)
for _, cidr := range cidrList {
for _, cidr := range cidrs {
ip := cidr.Ip
prefix := uint8(cidr.Prefix)
switch len(ip) {
@@ -81,10 +80,6 @@ func (m *GeoIPMatcher) Init(cidrs []*CIDR) error {
return nil
}
func (m *GeoIPMatcher) SetReverseMatch(isReverseMatch bool) {
m.reverseMatch = isReverseMatch
}
func (m *GeoIPMatcher) match4(ip uint32) bool {
if len(m.ip4) == 0 {
return false
@@ -152,17 +147,8 @@ func (m *GeoIPMatcher) match6(ip ipv6) bool {
func (m *GeoIPMatcher) Match(ip net.IP) bool {
switch len(ip) {
case 4:
if m.reverseMatch {
return !m.match4(binary.BigEndian.Uint32(ip))
}
return m.match4(binary.BigEndian.Uint32(ip))
case 16:
if m.reverseMatch {
return !m.match6(ipv6{
a: binary.BigEndian.Uint64(ip[0:8]),
b: binary.BigEndian.Uint64(ip[8:16]),
})
}
return m.match6(ipv6{
a: binary.BigEndian.Uint64(ip[0:8]),
b: binary.BigEndian.Uint64(ip[8:16]),
@@ -182,15 +168,14 @@ type GeoIPMatcherContainer struct {
func (c *GeoIPMatcherContainer) Add(geoip *GeoIP) (*GeoIPMatcher, error) {
if len(geoip.CountryCode) > 0 {
for _, m := range c.matchers {
if m.countryCode == geoip.CountryCode && m.reverseMatch == geoip.ReverseMatch {
if m.countryCode == geoip.CountryCode {
return m, nil
}
}
}
m := &GeoIPMatcher{
countryCode: geoip.CountryCode,
reverseMatch: geoip.ReverseMatch,
countryCode: geoip.CountryCode,
}
if err := m.Init(geoip.Cidr); err != nil {
return nil, err
@@ -201,4 +186,6 @@ func (c *GeoIPMatcherContainer) Add(geoip *GeoIP) (*GeoIPMatcher, error) {
return m, nil
}
var globalGeoIPContainer GeoIPMatcherContainer
var (
globalGeoIPContainer GeoIPMatcherContainer
)

View File

@@ -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,
},
@@ -125,42 +123,6 @@ func TestGeoIPMatcher(t *testing.T) {
}
}
func TestGeoIPReverseMatcher(t *testing.T) {
cidrList := router.CIDRList{
{Ip: []byte{8, 8, 8, 8}, Prefix: 32},
{Ip: []byte{91, 108, 4, 0}, Prefix: 16},
}
matcher := &router.GeoIPMatcher{}
matcher.SetReverseMatch(true) // Reverse match
common.Must(matcher.Init(cidrList))
testCases := []struct {
Input string
Output bool
}{
{
Input: "8.8.8.8",
Output: false,
},
{
Input: "2001:cdba::3257:9652",
Output: true,
},
{
Input: "91.108.255.254",
Output: false,
},
}
for _, testCase := range testCases {
ip := net.ParseAddress(testCase.Input).IP()
actual := matcher.Match(ip)
if actual != testCase.Output {
t.Error("expect input", testCase.Input, "to be", testCase.Output, ", but actually", actual)
}
}
}
func TestGeoIPMatcher4CN(t *testing.T) {
ips, err := loadGeoIP("CN")
common.Must(err)

View File

@@ -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)
}
}
}

View File

@@ -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 {
@@ -150,14 +138,6 @@ func (rr *RoutingRule) BuildCondition() (Condition, error) {
conds.Add(cond)
}
if rr.UidList != nil && len(rr.UidList.Uid) > 0 {
conds.Add(NewUidMatcher(rr.UidList))
}
if len(rr.AppStatus) > 0 {
conds.Add(NewAppStatusMatcher(rr.AppStatus))
}
if conds.Len() == 0 {
return nil, newError("this rule has no effective fields").AtWarning()
}

View File

@@ -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
@@ -264,9 +269,8 @@ type GeoIP struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
CountryCode string `protobuf:"bytes,1,opt,name=country_code,json=countryCode,proto3" json:"country_code,omitempty"`
Cidr []*CIDR `protobuf:"bytes,2,rep,name=cidr,proto3" json:"cidr,omitempty"`
ReverseMatch bool `protobuf:"varint,3,opt,name=reverse_match,json=reverseMatch,proto3" json:"reverse_match,omitempty"`
CountryCode string `protobuf:"bytes,1,opt,name=country_code,json=countryCode,proto3" json:"country_code,omitempty"`
Cidr []*CIDR `protobuf:"bytes,2,rep,name=cidr,proto3" json:"cidr,omitempty"`
}
func (x *GeoIP) Reset() {
@@ -315,13 +319,6 @@ func (x *GeoIP) GetCidr() []*CIDR {
return nil
}
func (x *GeoIP) GetReverseMatch() bool {
if x != nil {
return x.ReverseMatch
}
return false
}
type GeoIPList struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -518,9 +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"`
UidList *net.UidList `protobuf:"bytes,18,opt,name=uid_list,json=uidList,proto3" json:"uid_list,omitempty"`
AppStatus []string `protobuf:"bytes,19,rep,name=app_status,json=appStatus,proto3" json:"app_status,omitempty"`
}
func (x *RoutingRule) Reset() {
@@ -678,27 +672,6 @@ func (x *RoutingRule) GetAttributes() string {
return ""
}
func (x *RoutingRule) GetDomainMatcher() string {
if x != nil {
return x.DomainMatcher
}
return ""
}
func (x *RoutingRule) GetUidList() *net.UidList {
if x != nil {
return x.UidList
}
return nil
}
func (x *RoutingRule) GetAppStatus() []string {
if x != nil {
return x.AppStatus
}
return nil
}
type isRoutingRule_TargetTag interface {
isRoutingRule_TargetTag()
}
@@ -724,7 +697,6 @@ type BalancingRule struct {
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
OutboundSelector []string `protobuf:"bytes,2,rep,name=outbound_selector,json=outboundSelector,proto3" json:"outbound_selector,omitempty"`
Strategy string `protobuf:"bytes,3,opt,name=strategy,proto3" json:"strategy,omitempty"`
}
func (x *BalancingRule) Reset() {
@@ -773,13 +745,6 @@ func (x *BalancingRule) GetOutboundSelector() []string {
return nil
}
func (x *BalancingRule) GetStrategy() string {
if x != nil {
return x.Strategy
}
return ""
}
type Config struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -939,139 +904,126 @@ var file_app_router_config_proto_rawDesc = []byte{
0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x1a, 0x15, 0x63, 0x6f, 0x6d, 0x6d,
0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x1a, 0x18, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x6e, 0x65,
0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x14, 0x63, 0x6f, 0x6d,
0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x75, 0x69, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x22, 0xb3, 0x02, 0x0a, 0x06, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x30, 0x0a, 0x04,
0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x78, 0x72, 0x61,
0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x44, 0x6f, 0x6d,
0x61, 0x69, 0x6e, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14,
0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76,
0x61, 0x6c, 0x75, 0x65, 0x12, 0x3f, 0x0a, 0x09, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74,
0x65, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61,
0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x52, 0x09, 0x61, 0x74, 0x74, 0x72,
0x69, 0x62, 0x75, 0x74, 0x65, 0x1a, 0x6c, 0x0a, 0x09, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75,
0x74, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x03, 0x6b, 0x65, 0x79, 0x12, 0x1f, 0x0a, 0x0a, 0x62, 0x6f, 0x6f, 0x6c, 0x5f, 0x76, 0x61, 0x6c,
0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x09, 0x62, 0x6f, 0x6f, 0x6c,
0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x1d, 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x5f, 0x76, 0x61, 0x6c,
0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x08, 0x69, 0x6e, 0x74, 0x56,
0x61, 0x6c, 0x75, 0x65, 0x42, 0x0d, 0x0a, 0x0b, 0x74, 0x79, 0x70, 0x65, 0x64, 0x5f, 0x76, 0x61,
0x6c, 0x75, 0x65, 0x22, 0x32, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x09, 0x0a, 0x05, 0x50,
0x6c, 0x61, 0x69, 0x6e, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x52, 0x65, 0x67, 0x65, 0x78, 0x10,
0x01, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x10, 0x02, 0x12, 0x08, 0x0a,
0x04, 0x46, 0x75, 0x6c, 0x6c, 0x10, 0x03, 0x22, 0x2e, 0x0a, 0x04, 0x43, 0x49, 0x44, 0x52, 0x12,
0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x70, 0x12,
0x16, 0x0a, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52,
0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x22, 0x7a, 0x0a, 0x05, 0x47, 0x65, 0x6f, 0x49, 0x50,
0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x64, 0x65,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x43,
0x6f, 0x64, 0x65, 0x12, 0x29, 0x0a, 0x04, 0x63, 0x69, 0x64, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28,
0x0b, 0x32, 0x15, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75,
0x74, 0x65, 0x72, 0x2e, 0x43, 0x49, 0x44, 0x52, 0x52, 0x04, 0x63, 0x69, 0x64, 0x72, 0x12, 0x23,
0x0a, 0x0d, 0x72, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x18,
0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x72, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x4d, 0x61,
0x74, 0x63, 0x68, 0x22, 0x39, 0x0a, 0x09, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x4c, 0x69, 0x73, 0x74,
0x12, 0x2c, 0x0a, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32,
0x16, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65,
0x72, 0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x52, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x22, 0x5d,
0x0a, 0x07, 0x47, 0x65, 0x6f, 0x53, 0x69, 0x74, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x75,
0x6e, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x0b, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x2f, 0x0a, 0x06,
0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb3, 0x02, 0x0a, 0x06,
0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x30, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01,
0x20, 0x01, 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e,
0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x54, 0x79,
0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75,
0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x3f,
0x0a, 0x09, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x18, 0x03, 0x20, 0x03, 0x28,
0x0b, 0x32, 0x21, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75,
0x74, 0x65, 0x72, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69,
0x62, 0x75, 0x74, 0x65, 0x52, 0x09, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x1a,
0x6c, 0x0a, 0x09, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x12, 0x10, 0x0a, 0x03,
0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x1f,
0x0a, 0x0a, 0x62, 0x6f, 0x6f, 0x6c, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01,
0x28, 0x08, 0x48, 0x00, 0x52, 0x09, 0x62, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12,
0x1d, 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01,
0x28, 0x03, 0x48, 0x00, 0x52, 0x08, 0x69, 0x6e, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x0d,
0x0a, 0x0b, 0x74, 0x79, 0x70, 0x65, 0x64, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x32, 0x0a,
0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x09, 0x0a, 0x05, 0x50, 0x6c, 0x61, 0x69, 0x6e, 0x10, 0x00,
0x12, 0x09, 0x0a, 0x05, 0x52, 0x65, 0x67, 0x65, 0x78, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x44,
0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x46, 0x75, 0x6c, 0x6c, 0x10,
0x03, 0x22, 0x2e, 0x0a, 0x04, 0x43, 0x49, 0x44, 0x52, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18,
0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x72, 0x65,
0x66, 0x69, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69,
0x78, 0x22, 0x55, 0x0a, 0x05, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f,
0x75, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x52, 0x0b, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x29, 0x0a,
0x04, 0x63, 0x69, 0x64, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x78, 0x72,
0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x43, 0x49,
0x44, 0x52, 0x52, 0x04, 0x63, 0x69, 0x64, 0x72, 0x22, 0x39, 0x0a, 0x09, 0x47, 0x65, 0x6f, 0x49,
0x50, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x2c, 0x0a, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01,
0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e,
0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x52, 0x05, 0x65, 0x6e,
0x74, 0x72, 0x79, 0x22, 0x5d, 0x0a, 0x07, 0x47, 0x65, 0x6f, 0x53, 0x69, 0x74, 0x65, 0x12, 0x21,
0x0a, 0x0c, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x43, 0x6f, 0x64,
0x65, 0x12, 0x2f, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x03, 0x28,
0x0b, 0x32, 0x17, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75,
0x74, 0x65, 0x72, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61,
0x69, 0x6e, 0x22, 0x3d, 0x0a, 0x0b, 0x47, 0x65, 0x6f, 0x53, 0x69, 0x74, 0x65, 0x4c, 0x69, 0x73,
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, 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,
0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x67, 0x12, 0x2f, 0x0a, 0x06,
0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x78,
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x44,
0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x22, 0x3d, 0x0a,
0x0b, 0x47, 0x65, 0x6f, 0x53, 0x69, 0x74, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x05,
0x65, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x78, 0x72,
0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x2d, 0x0a,
0x04, 0x63, 0x69, 0x64, 0x72, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x78, 0x72,
0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x43, 0x49,
0x44, 0x52, 0x42, 0x02, 0x18, 0x01, 0x52, 0x04, 0x63, 0x69, 0x64, 0x72, 0x12, 0x2c, 0x0a, 0x05,
0x67, 0x65, 0x6f, 0x69, 0x70, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 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, 0x89, 0x07, 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, 0x62, 0x61, 0x6c, 0x61, 0x6e,
0x63, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x67, 0x12, 0x2f, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69,
0x6e, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61,
0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x2d, 0x0a, 0x04, 0x63, 0x69, 0x64, 0x72,
0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x43, 0x49, 0x44, 0x52, 0x42, 0x02, 0x18,
0x01, 0x52, 0x04, 0x63, 0x69, 0x64, 0x72, 0x12, 0x2c, 0x0a, 0x05, 0x67, 0x65, 0x6f, 0x69, 0x70,
0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70,
0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x52, 0x05,
0x67, 0x65, 0x6f, 0x69, 0x70, 0x12, 0x3d, 0x0a, 0x0a, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x72, 0x61,
0x6e, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x78, 0x72, 0x61, 0x79,
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x6f, 0x72, 0x74,
0x52, 0x61, 0x6e, 0x67, 0x65, 0x42, 0x02, 0x18, 0x01, 0x52, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x52,
0x61, 0x6e, 0x67, 0x65, 0x12, 0x36, 0x0a, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x6c, 0x69, 0x73,
0x74, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63,
0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x4c, 0x69,
0x73, 0x74, 0x52, 0x08, 0x70, 0x6f, 0x72, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x43, 0x0a, 0x0c,
0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x05, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x4c, 0x69, 0x73, 0x74,
0x42, 0x02, 0x18, 0x01, 0x52, 0x0b, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x4c, 0x69, 0x73,
0x74, 0x12, 0x34, 0x0a, 0x08, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x18, 0x0d, 0x20,
0x03, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f,
0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x08, 0x6e,
0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x12, 0x3a, 0x0a, 0x0b, 0x73, 0x6f, 0x75, 0x72, 0x63,
0x65, 0x5f, 0x63, 0x69, 0x64, 0x72, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x78,
0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x43,
0x49, 0x44, 0x52, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0a, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43,
0x69, 0x64, 0x72, 0x12, 0x39, 0x0a, 0x0c, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x67, 0x65,
0x6f, 0x69, 0x70, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x78, 0x72, 0x61, 0x79,
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x6f, 0x49,
0x50, 0x52, 0x0b, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, 0x65, 0x6f, 0x69, 0x70, 0x12, 0x43,
0x0a, 0x10, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x6c, 0x69,
0x73, 0x74, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x4c,
0x69, 0x73, 0x74, 0x52, 0x0e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x4c,
0x69, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x65, 0x6d, 0x61, 0x69,
0x6c, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x45, 0x6d, 0x61,
0x69, 0x6c, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x74, 0x61,
0x67, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64,
0x54, 0x61, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, 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, 0x12, 0x33, 0x0a, 0x08, 0x75, 0x69, 0x64, 0x5f, 0x6c, 0x69,
0x73, 0x74, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x55, 0x69, 0x64, 0x4c, 0x69,
0x73, 0x74, 0x52, 0x07, 0x75, 0x69, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x61,
0x70, 0x70, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x13, 0x20, 0x03, 0x28, 0x09, 0x52,
0x09, 0x61, 0x70, 0x70, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x42, 0x0c, 0x0a, 0x0a, 0x74, 0x61,
0x72, 0x67, 0x65, 0x74, 0x5f, 0x74, 0x61, 0x67, 0x22, 0x6a, 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, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x74, 0x72, 0x61,
0x74, 0x65, 0x67, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x74, 0x72, 0x61,
0x74, 0x65, 0x67, 0x79, 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,
0x6f, 0x49, 0x50, 0x52, 0x05, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x12, 0x3d, 0x0a, 0x0a, 0x70, 0x6f,
0x72, 0x74, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a,
0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74,
0x2e, 0x50, 0x6f, 0x72, 0x74, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x42, 0x02, 0x18, 0x01, 0x52, 0x09,
0x70, 0x6f, 0x72, 0x74, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x36, 0x0a, 0x09, 0x70, 0x6f, 0x72,
0x74, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78,
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x50,
0x6f, 0x72, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x08, 0x70, 0x6f, 0x72, 0x74, 0x4c, 0x69, 0x73,
0x74, 0x12, 0x43, 0x0a, 0x0c, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x6c, 0x69, 0x73,
0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63,
0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72,
0x6b, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0b, 0x6e, 0x65, 0x74, 0x77, 0x6f,
0x72, 0x6b, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x34, 0x0a, 0x08, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72,
0x6b, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f,
0x72, 0x6b, 0x52, 0x08, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x12, 0x3a, 0x0a, 0x0b,
0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x63, 0x69, 0x64, 0x72, 0x18, 0x06, 0x20, 0x03, 0x28,
0x0b, 0x32, 0x15, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x72, 0x6f, 0x75,
0x74, 0x65, 0x72, 0x2e, 0x43, 0x49, 0x44, 0x52, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0a, 0x73, 0x6f,
0x75, 0x72, 0x63, 0x65, 0x43, 0x69, 0x64, 0x72, 0x12, 0x39, 0x0a, 0x0c, 0x73, 0x6f, 0x75, 0x72,
0x63, 0x65, 0x5f, 0x67, 0x65, 0x6f, 0x69, 0x70, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16,
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,
0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x52, 0x0b, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, 0x65,
0x6f, 0x69, 0x70, 0x12, 0x43, 0x0a, 0x10, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x70, 0x6f,
0x72, 0x74, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e,
0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e,
0x50, 0x6f, 0x72, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x0e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
0x50, 0x6f, 0x72, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x73, 0x65, 0x72,
0x5f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x75, 0x73,
0x65, 0x72, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x62, 0x6f, 0x75,
0x6e, 0x64, 0x5f, 0x74, 0x61, 0x67, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e,
0x62, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x61, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74,
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, 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 (
@@ -1105,7 +1057,6 @@ var file_app_router_config_proto_goTypes = []interface{}{
(*net.PortList)(nil), // 13: xray.common.net.PortList
(*net.NetworkList)(nil), // 14: xray.common.net.NetworkList
(net.Network)(0), // 15: xray.common.net.Network
(*net.UidList)(nil), // 16: xray.common.net.UidList
}
var file_app_router_config_proto_depIdxs = []int32{
0, // 0: xray.app.router.Domain.type:type_name -> xray.app.router.Domain.Type
@@ -1124,15 +1075,14 @@ var file_app_router_config_proto_depIdxs = []int32{
3, // 13: xray.app.router.RoutingRule.source_cidr:type_name -> xray.app.router.CIDR
4, // 14: xray.app.router.RoutingRule.source_geoip:type_name -> xray.app.router.GeoIP
13, // 15: xray.app.router.RoutingRule.source_port_list:type_name -> xray.common.net.PortList
16, // 16: xray.app.router.RoutingRule.uid_list:type_name -> xray.common.net.UidList
1, // 17: xray.app.router.Config.domain_strategy:type_name -> xray.app.router.Config.DomainStrategy
8, // 18: xray.app.router.Config.rule:type_name -> xray.app.router.RoutingRule
9, // 19: xray.app.router.Config.balancing_rule:type_name -> xray.app.router.BalancingRule
20, // [20:20] is the sub-list for method output_type
20, // [20:20] is the sub-list for method input_type
20, // [20:20] is the sub-list for extension type_name
20, // [20:20] is the sub-list for extension extendee
0, // [0:20] is the sub-list for field type_name
1, // 16: xray.app.router.Config.domain_strategy:type_name -> xray.app.router.Config.DomainStrategy
8, // 17: xray.app.router.Config.rule:type_name -> xray.app.router.RoutingRule
9, // 18: xray.app.router.Config.balancing_rule:type_name -> xray.app.router.BalancingRule
19, // [19:19] is the sub-list for method output_type
19, // [19:19] is the sub-list for method input_type
19, // [19:19] is the sub-list for extension type_name
19, // [19:19] is the sub-list for extension extendee
0, // [0:19] is the sub-list for field type_name
}
func init() { file_app_router_config_proto_init() }

View File

@@ -8,7 +8,6 @@ option java_multiple_files = true;
import "common/net/port.proto";
import "common/net/network.proto";
import "common/net/uid.proto";
// Domain for routing decision.
message Domain {
@@ -55,7 +54,6 @@ message CIDR {
message GeoIP {
string country_code = 1;
repeated CIDR cidr = 2;
bool reverse_match = 3;
}
message GeoIPList {
@@ -121,18 +119,11 @@ message RoutingRule {
repeated string protocol = 9;
string attributes = 15;
string domain_matcher = 17;
xray.common.net.UidList uid_list = 18;
repeated string app_status = 19;
}
message BalancingRule {
string tag = 1;
repeated string outbound_selector = 2;
string strategy = 3;
}
message Config {

View File

@@ -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

View File

@@ -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))

View File

@@ -1,57 +0,0 @@
package router
import (
"context"
"github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/app/observatory"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/features/extension"
)
type LeastPingStrategy struct {
ctx context.Context
observatory extension.Observatory
}
func (l *LeastPingStrategy) InjectContext(ctx context.Context) {
common.Must(core.RequireFeatures(ctx, func(observatory extension.Observatory) error {
l.observatory = observatory
return nil
}))
l.ctx = ctx
}
func (l *LeastPingStrategy) PickOutbound(strings []string) string {
observeReport, err := l.observatory.GetObservation(l.ctx)
if err != nil {
newError("cannot get observe report").Base(err).WriteToLog()
return ""
}
outboundsList := outboundList(strings)
if result, ok := observeReport.(*observatory.ObservationResult); ok {
status := result.Status
leastPing := int64(99999999)
selectedOutboundName := ""
for _, v := range status {
if outboundsList.contains(v.OutboundTag) && v.Alive && v.Delay < leastPing {
selectedOutboundName = v.OutboundTag
}
}
return selectedOutboundName
}
//No way to understand observeReport
return ""
}
type outboundList []string
func (o outboundList) contains(name string) bool {
for _, v := range o {
if v == name {
return true
}
}
return false
}

View File

@@ -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

View File

@@ -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

View File

@@ -1,6 +0,0 @@
package antireplay
type GeneralizedReplayFilter interface {
Interval() int64
Check(sum []byte) bool
}

View File

@@ -1,36 +0,0 @@
package antireplay
import (
"sync"
ss_bloomring "github.com/v2fly/ss-bloomring"
)
type BloomRing struct {
*ss_bloomring.BloomRing
lock *sync.Mutex
}
func (b BloomRing) Interval() int64 {
return 9999999
}
func (b BloomRing) Check(sum []byte) bool {
b.lock.Lock()
defer b.lock.Unlock()
if b.Test(sum) {
return false
}
b.Add(sum)
return true
}
func NewBloomRing() BloomRing {
const (
DefaultSFCapacity = 1e6
// FalsePositiveRate
DefaultSFFPR = 1e-6
DefaultSFSlot = 10
)
return BloomRing{ss_bloomring.NewBloomRing(DefaultSFSlot, DefaultSFCapacity, DefaultSFFPR), &sync.Mutex{}}
}

View File

@@ -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
}

View File

@@ -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()

View File

@@ -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,
}
}

View File

@@ -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 != "" {

View File

@@ -1,5 +1,6 @@
//go:build !windows && !wasm && !illumos
// +build !windows,!wasm,!illumos
// +build !windows
// +build !wasm
// +build !illumos
package buf

View File

@@ -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
}
}

View File

@@ -1,4 +1,3 @@
//go:build wasm
// +build wasm
package buf

View File

@@ -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()

View File

@@ -1,4 +1,3 @@
//go:build illumos
// +build illumos
package buf

View File

@@ -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
View File

@@ -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()
}

View File

@@ -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

View File

@@ -43,14 +43,6 @@ func GenerateInitialAEADNonce() BytesGenerator {
return GenerateIncreasingNonce([]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF})
}
func GenerateAEADNonceWithSize(nonceSize int) BytesGenerator {
c := make([]byte, nonceSize)
for i := 0; i < nonceSize; i++ {
c[i] = 0xFF
}
return GenerateIncreasingNonce(c)
}
type Authenticator interface {
NonceSize() int
Overhead() int
@@ -298,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

View File

@@ -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

View File

@@ -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

View File

@@ -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)
}

View File

@@ -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

View File

@@ -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, "}")
}

View 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) {

View File

@@ -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 (

View File

@@ -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
}

View File

@@ -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())

View File

@@ -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) {

View File

@@ -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"

View File

@@ -56,15 +56,6 @@ func (s *Server) Dispatch(ctx context.Context, dest net.Destination) (*transport
return &transport.Link{Reader: downlinkReader, Writer: uplinkWriter}, nil
}
// DispatchLink implements routing.Dispatcher
func (s *Server) DispatchLink(ctx context.Context, dest net.Destination, link *transport.Link) error {
if dest.Address != muxCoolAddress {
return s.dispatcher.DispatchLink(ctx, dest, link)
}
_, err := NewServerWorker(ctx, s.dispatcher, link)
return err
}
// Start implements common.Runnable.
func (s *Server) Start() error {
return nil

Some files were not shown because too many files have changed in this diff Show More