Merge branch 'master' into v5

This commit is contained in:
loyalsoldier
2021-02-24 17:26:17 +08:00
45 changed files with 8142 additions and 7905 deletions
+1 -1
View File
@@ -15,7 +15,7 @@ jobs:
- name: Set up Go 1.x
uses: actions/setup-go@v2
with:
go-version: ^1.15
go-version: ^1.16
- name: Checkout codebase
uses: actions/checkout@v2
+5 -3
View File
@@ -7,10 +7,12 @@ on:
- v*
paths:
- "**/*.go"
- ".github/workflows/linter.yml"
pull_request:
types: [opened, synchronize, reopened]
paths:
- "**/*.go"
- ".github/workflows/linter.yml"
jobs:
lint:
@@ -19,14 +21,14 @@ jobs:
- name: Set up Go 1.x
uses: actions/setup-go@v2
with:
go-version: ^1.15
go-version: ^1.16
- name: Checkout codebase
uses: actions/checkout@v2
- name: golangci-lint
uses: golangci/golangci-lint-action@v2.4.0
uses: golangci/golangci-lint-action@v2.5.1
with:
version: v1.31
version: latest
args: --config=.github/linters/.golangci.yml
only-new-issues: true
+5 -2
View File
@@ -51,6 +51,8 @@ jobs:
goarch: arm
goarm: 7
# BEGIN Other architectures
- goos: darwin
goarch: arm64
- goos: linux
goarch: arm64
- goos: linux
@@ -96,7 +98,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: ^1.15
go-version: ^1.16
- name: Get project dependencies
run: go mod download
@@ -152,7 +154,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: ^1.15
go-version: ^1.16
- uses: actions/download-artifact@v2
with:
@@ -160,6 +162,7 @@ jobs:
- name: Generate shasum
run: |
go get -v github.com/v2fly/V2BuildAssist/v2buildutil
cd build_artifacts || exit 1
mkdir .temp
mv ./*/*.zip ./.temp
+1 -1
View File
@@ -8,7 +8,7 @@ jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v3.0.16
- uses: actions/stale@v3.0.17
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: "This issue is stale because it has been open 120 days with no activity. Remove stale label or comment or this will be closed in 5 days"
+1 -1
View File
@@ -27,7 +27,7 @@ jobs:
- name: Set up Go 1.x
uses: actions/setup-go@v2
with:
go-version: ^1.15
go-version: ^1.16
- name: Checkout codebase
uses: actions/checkout@v2
+2
View File
@@ -20,3 +20,5 @@
*.tar.gz
v2ray
v2ctl
mockgen
vprotogen
+39 -28
View File
@@ -182,6 +182,8 @@ type Config struct {
StaticHosts []*Config_HostMapping `protobuf:"bytes,4,rep,name=static_hosts,json=staticHosts,proto3" json:"static_hosts,omitempty"`
// Tag is the inbound tag of DNS client.
Tag string `protobuf:"bytes,6,opt,name=tag,proto3" json:"tag,omitempty"`
// DisableCache Disable DNS cache
DisableCache bool `protobuf:"varint,8,opt,name=disableCache,proto3" json:"disableCache,omitempty"`
}
func (x *Config) Reset() {
@@ -260,6 +262,13 @@ func (x *Config) GetTag() string {
return ""
}
func (x *Config) GetDisableCache() bool {
if x != nil {
return x.DisableCache
}
return false
}
type NameServer_PriorityDomain struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -485,7 +494,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, 0xc9, 0x04, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69,
0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x22, 0xed, 0x04, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69,
0x67, 0x12, 0x45, 0x0a, 0x0b, 0x4e, 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73,
0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,
0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x45,
@@ -506,33 +515,35 @@ var file_app_dns_config_proto_rawDesc = []byte{
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, 0x1a, 0x5b, 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, 0x37, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,
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, 0x98, 0x01, 0x0a, 0x0b, 0x48, 0x6f, 0x73, 0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e,
0x67, 0x12, 0x3a, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32,
0x26, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 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, 0x42, 0x57, 0x0a, 0x16, 0x63, 0x6f, 0x6d,
0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e,
0x64, 0x6e, 0x73, 0x50, 0x01, 0x5a, 0x26, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
0x6d, 0x2f, 0x76, 0x32, 0x66, 0x6c, 0x79, 0x2f, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f,
0x72, 0x65, 0x2f, 0x76, 0x34, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x64, 0x6e, 0x73, 0xaa, 0x02, 0x12,
0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x44,
0x6e, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
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, 0x1a, 0x5b, 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, 0x37, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75,
0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e,
0x63, 0x6f, 0x72, 0x65, 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, 0x98, 0x01, 0x0a, 0x0b, 0x48, 0x6f, 0x73, 0x74, 0x4d, 0x61,
0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x3a, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20,
0x01, 0x28, 0x0e, 0x32, 0x26, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,
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, 0x42, 0x57, 0x0a,
0x16, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,
0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x50, 0x01, 0x5a, 0x26, 0x67, 0x69, 0x74, 0x68, 0x75,
0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x76, 0x32, 0x66, 0x6c, 0x79, 0x2f, 0x76, 0x32, 0x72, 0x61,
0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x76, 0x34, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x64, 0x6e,
0x73, 0xaa, 0x02, 0x12, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x41,
0x70, 0x70, 0x2e, 0x44, 0x6e, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
+3
View File
@@ -71,4 +71,7 @@ message Config {
string tag = 6;
reserved 7;
// DisableCache Disable DNS cache
bool disableCache = 8;
}
+11 -26
View File
@@ -6,6 +6,7 @@ package dns
import (
"context"
"fmt"
"strings"
"sync"
"github.com/v2fly/v2ray-core/v4/app/router"
@@ -22,6 +23,7 @@ import (
type DNS struct {
sync.Mutex
tag string
disableCache bool
hosts *StaticHosts
clients []*Client
ctx context.Context
@@ -103,6 +105,7 @@ func New(ctx context.Context, config *Config) (*DNS, error) {
clients = append(clients, client)
}
// If there is no DNS client in config, add a `localhost` DNS client
if len(clients) == 0 {
clients = append(clients, NewLocalDNSClient())
}
@@ -114,6 +117,7 @@ func New(ctx context.Context, config *Config) (*DNS, error) {
ctx: ctx,
domainMatcher: domainMatcher,
matcherInfos: matcherInfos,
disableCache: config.DisableCache,
}, nil
}
@@ -139,36 +143,13 @@ func (s *DNS) IsOwnLink(ctx context.Context) bool {
}
// LookupIP implements dns.Client.
func (s *DNS) LookupIP(domain string) ([]net.IP, error) {
return s.lookupIPInternal(domain, IPOption{
IPv4Enable: true,
IPv6Enable: true,
})
}
// LookupIPv4 implements dns.IPv4Lookup.
func (s *DNS) LookupIPv4(domain string) ([]net.IP, error) {
return s.lookupIPInternal(domain, IPOption{
IPv4Enable: true,
IPv6Enable: false,
})
}
// LookupIPv6 implements dns.IPv6Lookup.
func (s *DNS) LookupIPv6(domain string) ([]net.IP, error) {
return s.lookupIPInternal(domain, IPOption{
IPv4Enable: false,
IPv6Enable: true,
})
}
func (s *DNS) lookupIPInternal(domain string, option IPOption) ([]net.IP, error) {
func (s *DNS) LookupIP(domain string, option dns.IPOption) ([]net.IP, error) {
if domain == "" {
return nil, newError("empty domain name")
}
// Normalize the FQDN form query
if domain[len(domain)-1] == '.' {
if strings.HasSuffix(domain, ".") {
domain = domain[:len(domain)-1]
}
@@ -190,7 +171,11 @@ func (s *DNS) lookupIPInternal(domain string, option IPOption) ([]net.IP, error)
errs := []error{}
ctx := session.ContextWithInbound(s.ctx, &session.Inbound{Tag: s.tag})
for _, client := range s.sortClients(domain) {
ips, err := client.QueryIP(ctx, domain, option)
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)
if len(ips) > 0 {
return ips, nil
}
+110 -26
View File
@@ -154,7 +154,11 @@ func TestUDPServerSubnet(t *testing.T) {
client := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)
ips, err := client.LookupIP("google.com")
ips, err := client.LookupIP("google.com", feature_dns.IPOption{
IPv4Enable: true,
IPv6Enable: true,
FakeEnable: false,
})
if err != nil {
t.Fatal("unexpected error: ", err)
}
@@ -209,7 +213,11 @@ func TestUDPServer(t *testing.T) {
client := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)
{
ips, err := client.LookupIP("google.com")
ips, err := client.LookupIP("google.com", feature_dns.IPOption{
IPv4Enable: true,
IPv6Enable: true,
FakeEnable: false,
})
if err != nil {
t.Fatal("unexpected error: ", err)
}
@@ -220,7 +228,11 @@ func TestUDPServer(t *testing.T) {
}
{
ips, err := client.LookupIP("facebook.com")
ips, err := client.LookupIP("facebook.com", feature_dns.IPOption{
IPv4Enable: true,
IPv6Enable: true,
FakeEnable: false,
})
if err != nil {
t.Fatal("unexpected error: ", err)
}
@@ -231,7 +243,11 @@ func TestUDPServer(t *testing.T) {
}
{
_, err := client.LookupIP("notexist.google.com")
_, err := client.LookupIP("notexist.google.com", feature_dns.IPOption{
IPv4Enable: true,
IPv6Enable: true,
FakeEnable: false,
})
if err == nil {
t.Fatal("nil error")
}
@@ -241,8 +257,11 @@ func TestUDPServer(t *testing.T) {
}
{
clientv6 := client.(feature_dns.IPv6Lookup)
ips, err := clientv6.LookupIPv6("ipv4only.google.com")
ips, err := client.LookupIP("ipv4only.google.com", feature_dns.IPOption{
IPv4Enable: false,
IPv6Enable: true,
FakeEnable: false,
})
if err != feature_dns.ErrEmptyResponse {
t.Fatal("error: ", err)
}
@@ -254,7 +273,11 @@ func TestUDPServer(t *testing.T) {
dnsServer.Shutdown()
{
ips, err := client.LookupIP("google.com")
ips, err := client.LookupIP("google.com", feature_dns.IPOption{
IPv4Enable: true,
IPv6Enable: true,
FakeEnable: false,
})
if err != nil {
t.Fatal("unexpected error: ", err)
}
@@ -331,7 +354,11 @@ func TestPrioritizedDomain(t *testing.T) {
startTime := time.Now()
{
ips, err := client.LookupIP("google.com")
ips, err := client.LookupIP("google.com", feature_dns.IPOption{
IPv4Enable: true,
IPv6Enable: true,
FakeEnable: false,
})
if err != nil {
t.Fatal("unexpected error: ", err)
}
@@ -390,10 +417,12 @@ func TestUDPServerIPv6(t *testing.T) {
common.Must(err)
client := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)
client6 := client.(feature_dns.IPv6Lookup)
{
ips, err := client6.LookupIPv6("ipv6.google.com")
ips, err := client.LookupIP("ipv6.google.com", feature_dns.IPOption{
IPv4Enable: false,
IPv6Enable: true,
FakeEnable: false,
})
if err != nil {
t.Fatal("unexpected error: ", err)
}
@@ -456,7 +485,11 @@ func TestStaticHostDomain(t *testing.T) {
client := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)
{
ips, err := client.LookupIP("example.com")
ips, err := client.LookupIP("example.com", feature_dns.IPOption{
IPv4Enable: true,
IPv6Enable: true,
FakeEnable: false,
})
if err != nil {
t.Fatal("unexpected error: ", err)
}
@@ -563,7 +596,11 @@ func TestIPMatch(t *testing.T) {
startTime := time.Now()
{
ips, err := client.LookupIP("google.com")
ips, err := client.LookupIP("google.com", feature_dns.IPOption{
IPv4Enable: true,
IPv6Enable: true,
FakeEnable: false,
})
if err != nil {
t.Fatal("unexpected error: ", err)
}
@@ -682,7 +719,11 @@ func TestLocalDomain(t *testing.T) {
startTime := time.Now()
{ // Will match dotless:
ips, err := client.LookupIP("hostname")
ips, err := client.LookupIP("hostname", feature_dns.IPOption{
IPv4Enable: true,
IPv6Enable: true,
FakeEnable: false,
})
if err != nil {
t.Fatal("unexpected error: ", err)
}
@@ -693,7 +734,11 @@ func TestLocalDomain(t *testing.T) {
}
{ // Will match domain:local
ips, err := client.LookupIP("hostname.local")
ips, err := client.LookupIP("hostname.local", feature_dns.IPOption{
IPv4Enable: true,
IPv6Enable: true,
FakeEnable: false,
})
if err != nil {
t.Fatal("unexpected error: ", err)
}
@@ -704,7 +749,11 @@ func TestLocalDomain(t *testing.T) {
}
{ // Will match static ip
ips, err := client.LookupIP("hostnamestatic")
ips, err := client.LookupIP("hostnamestatic", feature_dns.IPOption{
IPv4Enable: true,
IPv6Enable: true,
FakeEnable: false,
})
if err != nil {
t.Fatal("unexpected error: ", err)
}
@@ -715,7 +764,11 @@ func TestLocalDomain(t *testing.T) {
}
{ // Will match domain replacing
ips, err := client.LookupIP("hostnamealias")
ips, err := client.LookupIP("hostnamealias", feature_dns.IPOption{
IPv4Enable: true,
IPv6Enable: true,
FakeEnable: false,
})
if err != nil {
t.Fatal("unexpected error: ", err)
}
@@ -726,7 +779,11 @@ 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")
ips, err := client.LookupIP("localhost", feature_dns.IPOption{
IPv4Enable: true,
IPv6Enable: true,
FakeEnable: false,
})
if err != nil {
t.Fatal("unexpected error: ", err)
}
@@ -737,7 +794,11 @@ 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")
ips, err := client.LookupIP("localhost-a", feature_dns.IPOption{
IPv4Enable: true,
IPv6Enable: true,
FakeEnable: false,
})
if err != nil {
t.Fatal("unexpected error: ", err)
}
@@ -748,7 +809,11 @@ 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")
ips, err := client.LookupIP("localhost-b", feature_dns.IPOption{
IPv4Enable: true,
IPv6Enable: true,
FakeEnable: false,
})
if err != nil {
t.Fatal("unexpected error: ", err)
}
@@ -759,7 +824,11 @@ func TestLocalDomain(t *testing.T) {
}
{ // Will match dotless:
ips, err := client.LookupIP("Mijia Cloud")
ips, err := client.LookupIP("Mijia Cloud", feature_dns.IPOption{
IPv4Enable: true,
IPv6Enable: true,
FakeEnable: false,
})
if err != nil {
t.Fatal("unexpected error: ", err)
}
@@ -921,7 +990,11 @@ 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")
ips, err := client.LookupIP("google.com", feature_dns.IPOption{
IPv4Enable: true,
IPv6Enable: true,
FakeEnable: false,
})
if err != nil {
t.Fatal("unexpected error: ", err)
}
@@ -932,8 +1005,11 @@ func TestMultiMatchPrioritizedDomain(t *testing.T) {
}
{ // Will match server 1,2 and server 1 returns unexpected ip, then server 2 returns expected one
clientv4 := client.(feature_dns.IPv4Lookup)
ips, err := clientv4.LookupIPv4("ipv6.google.com")
ips, err := client.LookupIP("ipv6.google.com", feature_dns.IPOption{
IPv4Enable: true,
IPv6Enable: false,
FakeEnable: false,
})
if err != nil {
t.Fatal("unexpected error: ", err)
}
@@ -944,7 +1020,11 @@ func TestMultiMatchPrioritizedDomain(t *testing.T) {
}
{ // Will match server 3,1,2 and server 3 returns expected one
ips, err := client.LookupIP("api.google.com")
ips, err := client.LookupIP("api.google.com", feature_dns.IPOption{
IPv4Enable: true,
IPv6Enable: true,
FakeEnable: false,
})
if err != nil {
t.Fatal("unexpected error: ", err)
}
@@ -955,7 +1035,11 @@ 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")
ips, err := client.LookupIP("v2.api.google.com", feature_dns.IPOption{
IPv4Enable: true,
IPv6Enable: true,
FakeEnable: false,
})
if err != nil {
t.Fatal("unexpected error: ", err)
}
+3 -2
View File
@@ -2,6 +2,7 @@ package dns
import (
"encoding/binary"
"strings"
"time"
"golang.org/x/net/dns/dnsmessage"
@@ -14,7 +15,7 @@ import (
// Fqdn normalize domain make sure it ends with '.'
func Fqdn(domain string) string {
if len(domain) > 0 && domain[len(domain)-1] == '.' {
if len(domain) > 0 && strings.HasSuffix(domain, ".") {
return domain
}
return domain + "."
@@ -113,7 +114,7 @@ func genEDNS0Options(clientIP net.IP) *dnsmessage.Resource {
return opt
}
func buildReqMsgs(domain string, option IPOption, reqIDGen func() uint16, reqOpts *dnsmessage.Resource) []*dnsRequest {
func buildReqMsgs(domain string, option dns_feature.IPOption, reqIDGen func() uint16, reqOpts *dnsmessage.Resource) []*dnsRequest {
qA := dnsmessage.Question{
Name: dnsmessage.MustNewName(domain),
Type: dnsmessage.TypeA,
+22 -5
View File
@@ -11,6 +11,7 @@ import (
"github.com/v2fly/v2ray-core/v4/common"
"github.com/v2fly/v2ray-core/v4/common/net"
dns_feature "github.com/v2fly/v2ray-core/v4/features/dns"
)
func Test_parseResponse(t *testing.T) {
@@ -93,7 +94,7 @@ func Test_buildReqMsgs(t *testing.T) {
}
type args struct {
domain string
option IPOption
option dns_feature.IPOption
reqOpts *dnsmessage.Resource
}
tests := []struct {
@@ -101,10 +102,26 @@ func Test_buildReqMsgs(t *testing.T) {
args args
want int
}{
{"dual stack", args{"test.com", IPOption{true, true}, nil}, 2},
{"ipv4 only", args{"test.com", IPOption{true, false}, nil}, 1},
{"ipv6 only", args{"test.com", IPOption{false, true}, nil}, 1},
{"none/error", args{"test.com", IPOption{false, false}, nil}, 0},
{"dual stack", args{"test.com", dns_feature.IPOption{
IPv4Enable: true,
IPv6Enable: true,
FakeEnable: false,
}, nil}, 2},
{"ipv4 only", args{"test.com", dns_feature.IPOption{
IPv4Enable: true,
IPv6Enable: false,
FakeEnable: false,
}, nil}, 1},
{"ipv6 only", args{"test.com", dns_feature.IPOption{
IPv4Enable: false,
IPv6Enable: true,
FakeEnable: false,
}, nil}, 1},
{"none/error", args{"test.com", dns_feature.IPOption{
IPv4Enable: false,
IPv6Enable: false,
FakeEnable: false,
}, nil}, 0},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
+4 -3
View File
@@ -5,6 +5,7 @@ import (
"github.com/v2fly/v2ray-core/v4/common/net"
"github.com/v2fly/v2ray-core/v4/common/strmatcher"
"github.com/v2fly/v2ray-core/v4/features"
"github.com/v2fly/v2ray-core/v4/features/dns"
)
// StaticHosts represents static domain-ip mapping in DNS server.
@@ -73,7 +74,7 @@ func NewStaticHosts(hosts []*Config_HostMapping, legacy map[string]*net.IPOrDoma
return sh, nil
}
func filterIP(ips []net.Address, option 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) {
@@ -91,7 +92,7 @@ func (h *StaticHosts) lookupInternal(domain string) []net.Address {
return ips
}
func (h *StaticHosts) lookup(domain string, option 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
@@ -109,6 +110,6 @@ func (h *StaticHosts) lookup(domain string, option IPOption, maxDepth int) []net
}
// Lookup returns IP addresses or proxied domain for the given domain, if exists in this StaticHosts.
func (h *StaticHosts) Lookup(domain string, option IPOption) []net.Address {
func (h *StaticHosts) Lookup(domain string, option dns.IPOption) []net.Address {
return h.lookup(domain, option, 5)
}
+4 -3
View File
@@ -8,6 +8,7 @@ import (
. "github.com/v2fly/v2ray-core/v4/app/dns"
"github.com/v2fly/v2ray-core/v4/common"
"github.com/v2fly/v2ray-core/v4/common/net"
"github.com/v2fly/v2ray-core/v4/features/dns"
)
func TestStaticHosts(t *testing.T) {
@@ -39,7 +40,7 @@ func TestStaticHosts(t *testing.T) {
common.Must(err)
{
ips := hosts.Lookup("v2fly.org", IPOption{
ips := hosts.Lookup("v2fly.org", dns.IPOption{
IPv4Enable: true,
IPv6Enable: true,
})
@@ -52,7 +53,7 @@ func TestStaticHosts(t *testing.T) {
}
{
ips := hosts.Lookup("www.v2ray.cn", IPOption{
ips := hosts.Lookup("www.v2ray.cn", dns.IPOption{
IPv4Enable: true,
IPv6Enable: true,
})
@@ -65,7 +66,7 @@ func TestStaticHosts(t *testing.T) {
}
{
ips := hosts.Lookup("baidu.com", IPOption{
ips := hosts.Lookup("baidu.com", dns.IPOption{
IPv4Enable: false,
IPv6Enable: true,
})
+10 -14
View File
@@ -3,6 +3,7 @@ package dns
import (
"context"
"net/url"
"strings"
"time"
core "github.com/v2fly/v2ray-core/v4"
@@ -10,21 +11,16 @@ import (
"github.com/v2fly/v2ray-core/v4/common/errors"
"github.com/v2fly/v2ray-core/v4/common/net"
"github.com/v2fly/v2ray-core/v4/common/strmatcher"
"github.com/v2fly/v2ray-core/v4/features/dns"
"github.com/v2fly/v2ray-core/v4/features/routing"
)
// IPOption is an object for IP query options.
type IPOption struct {
IPv4Enable bool
IPv6Enable bool
}
// Server is the interface for Name Server.
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 IPOption) ([]net.IP, error)
QueryIP(ctx context.Context, domain string, clientIP net.IP, option dns.IPOption, disableCache bool) ([]net.IP, error)
}
// Client is the interface for DNS client.
@@ -45,15 +41,15 @@ func NewServer(dest net.Destination, dispatcher routing.Dispatcher) (Server, err
return nil, err
}
switch {
case u.String() == "localhost":
case strings.EqualFold(u.String(), "localhost"):
return NewLocalNameServer(), nil
case u.Scheme == "https": // DOH Remote mode
case strings.EqualFold(u.Scheme, "https"): // DOH Remote mode
return NewDoHNameServer(u, dispatcher)
case u.Scheme == "https+local": // DOH Local mode
case strings.EqualFold(u.Scheme, "https+local"): // DOH Local mode
return NewDoHLocalNameServer(u), nil
case u.Scheme == "quic+local": // DNS-over-QUIC Local mode
case strings.EqualFold(u.Scheme, "quic+local"): // DNS-over-QUIC Local mode
return NewQUICNameServer(u)
case u.String() == "fakedns":
case strings.EqualFold(u.String(), "fakedns"):
return NewFakeDNSServer(), nil
}
}
@@ -171,9 +167,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 IPOption) ([]net.IP, error) {
func (c *Client) QueryIP(ctx context.Context, domain string, option dns.IPOption, disableCache bool) ([]net.IP, error) {
ctx, cancel := context.WithTimeout(ctx, 4*time.Second)
ips, err := c.server.QueryIP(ctx, domain, c.clientIP, option)
ips, err := c.server.QueryIP(ctx, domain, c.clientIP, option, disableCache)
cancel()
if err != nil {
+11 -7
View File
@@ -205,7 +205,7 @@ func (s *DoHNameServer) newReqID() uint16 {
return uint16(atomic.AddUint32(&s.reqID, 1))
}
func (s *DoHNameServer) sendQuery(ctx context.Context, domain string, clientIP net.IP, option IPOption) {
func (s *DoHNameServer) sendQuery(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption) {
newError(s.name, " querying: ", domain).AtInfo().WriteToLog(session.ExportIDToError(ctx))
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(clientIP))
@@ -284,7 +284,7 @@ func (s *DoHNameServer) dohHTTPSContext(ctx context.Context, b []byte) ([]byte,
return ioutil.ReadAll(resp.Body)
}
func (s *DoHNameServer) findIPsForDomain(domain string, option IPOption) ([]net.IP, error) {
func (s *DoHNameServer) findIPsForDomain(domain string, option dns_feature.IPOption) ([]net.IP, error) {
s.RLock()
record, found := s.ips[domain]
s.RUnlock()
@@ -327,13 +327,17 @@ func (s *DoHNameServer) findIPsForDomain(domain string, option IPOption) ([]net.
}
// QueryIP implements Server.
func (s *DoHNameServer) QueryIP(ctx context.Context, domain string, clientIP net.IP, option IPOption) ([]net.IP, error) { // nolint: dupl
func (s *DoHNameServer) QueryIP(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption, disableCache bool) ([]net.IP, error) { // nolint: dupl
fqdn := Fqdn(domain)
ips, err := s.findIPsForDomain(fqdn, option)
if err != errRecordNotFound {
newError(s.name, " cache HIT ", domain, " -> ", ips).Base(err).AtDebug().WriteToLog()
return ips, err
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
+60
View File
@@ -0,0 +1,60 @@
package dns_test
import (
"context"
"net/url"
"testing"
"time"
"github.com/google/go-cmp/cmp"
. "github.com/v2fly/v2ray-core/v4/app/dns"
"github.com/v2fly/v2ray-core/v4/common"
"github.com/v2fly/v2ray-core/v4/common/net"
dns_feature "github.com/v2fly/v2ray-core/v4/features/dns"
)
func TestDoHLocalNameServer(t *testing.T) {
url, err := url.Parse("https+local://1.1.1.1/dns-query")
common.Must(err)
s := NewDoHLocalNameServer(url)
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 TestDoHLocalNameServerWithCache(t *testing.T) {
url, err := url.Parse("https+local://1.1.1.1/dns-query")
common.Must(err)
s := NewDoHLocalNameServer(url)
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*2)
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)
}
}
+3 -1
View File
@@ -20,7 +20,7 @@ func (FakeDNSServer) Name() string {
return "FakeDNS"
}
func (f *FakeDNSServer) QueryIP(ctx context.Context, domain string, _ net.IP, _ IPOption) ([]net.IP, error) {
func (f *FakeDNSServer) QueryIP(ctx context.Context, domain string, _ net.IP, _ dns.IPOption, _ bool) ([]net.IP, error) {
if f.fakeDNSEngine == nil {
if err := core.RequireFeatures(ctx, func(fd dns.FakeDNSEngine) {
f.fakeDNSEngine = fd
@@ -35,5 +35,7 @@ func (f *FakeDNSServer) QueryIP(ctx context.Context, domain string, _ net.IP, _
return nil, newError("Unable to convert IP to net ip").Base(err).AtError()
}
newError(f.Name(), " got answer: ", domain, " -> ", ips).AtInfo().WriteToLog()
return netIP, nil
}
+4 -11
View File
@@ -4,6 +4,7 @@ import (
"context"
"github.com/v2fly/v2ray-core/v4/common/net"
"github.com/v2fly/v2ray-core/v4/features/dns"
"github.com/v2fly/v2ray-core/v4/features/dns/localdns"
)
@@ -13,17 +14,9 @@ type LocalNameServer struct {
}
// QueryIP implements Server.
func (s *LocalNameServer) QueryIP(ctx context.Context, domain string, clientIP net.IP, option IPOption) ([]net.IP, error) {
if option.IPv4Enable && option.IPv6Enable {
return s.client.LookupIP(domain)
}
if option.IPv4Enable {
return s.client.LookupIPv4(domain)
}
if option.IPv6Enable {
return s.client.LookupIPv6(domain)
func (s *LocalNameServer) QueryIP(_ context.Context, domain string, _ net.IP, option dns.IPOption, _ bool) ([]net.IP, error) {
if option.IPv4Enable || option.IPv6Enable {
return s.client.LookupIP(domain, option)
}
return nil, newError("neither IPv4 nor IPv6 is enabled")
+3 -2
View File
@@ -8,15 +8,16 @@ import (
. "github.com/v2fly/v2ray-core/v4/app/dns"
"github.com/v2fly/v2ray-core/v4/common"
"github.com/v2fly/v2ray-core/v4/common/net"
"github.com/v2fly/v2ray-core/v4/features/dns"
)
func TestLocalNameServer(t *testing.T) {
s := NewLocalNameServer()
ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
ips, err := s.QueryIP(ctx, "google.com", net.IP{}, IPOption{
ips, err := s.QueryIP(ctx, "google.com", net.IP{}, dns.IPOption{
IPv4Enable: true,
IPv6Enable: true,
})
}, false)
cancel()
common.Must(err)
if len(ips) == 0 {
+11 -7
View File
@@ -151,7 +151,7 @@ func (s *QUICNameServer) newReqID() uint16 {
return uint16(atomic.AddUint32(&s.reqID, 1))
}
func (s *QUICNameServer) sendQuery(ctx context.Context, domain string, clientIP net.IP, option IPOption) {
func (s *QUICNameServer) sendQuery(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption) {
newError(s.name, " querying: ", domain).AtInfo().WriteToLog(session.ExportIDToError(ctx))
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(clientIP))
@@ -221,7 +221,7 @@ func (s *QUICNameServer) sendQuery(ctx context.Context, domain string, clientIP
}
}
func (s *QUICNameServer) findIPsForDomain(domain string, option IPOption) ([]net.IP, error) {
func (s *QUICNameServer) findIPsForDomain(domain string, option dns_feature.IPOption) ([]net.IP, error) {
s.RLock()
record, found := s.ips[domain]
s.RUnlock()
@@ -264,13 +264,17 @@ func (s *QUICNameServer) findIPsForDomain(domain string, option IPOption) ([]net
}
// QueryIP is called from dns.Server->queryIPTimeout
func (s *QUICNameServer) QueryIP(ctx context.Context, domain string, clientIP net.IP, option IPOption) ([]net.IP, error) {
func (s *QUICNameServer) QueryIP(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption, disableCache bool) ([]net.IP, error) {
fqdn := Fqdn(domain)
ips, err := s.findIPsForDomain(fqdn, option)
if err != errRecordNotFound {
newError(s.name, " cache HIT ", domain, " -> ", ips).Base(err).AtDebug().WriteToLog()
return ips, err
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
+33 -2
View File
@@ -6,9 +6,12 @@ import (
"testing"
"time"
"github.com/google/go-cmp/cmp"
. "github.com/v2fly/v2ray-core/v4/app/dns"
"github.com/v2fly/v2ray-core/v4/common"
"github.com/v2fly/v2ray-core/v4/common/net"
dns_feature "github.com/v2fly/v2ray-core/v4/features/dns"
)
func TestQUICNameServer(t *testing.T) {
@@ -17,13 +20,41 @@ func TestQUICNameServer(t *testing.T) {
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), IPOption{
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 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*2)
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*2)
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)
}
}
+12 -8
View File
@@ -53,7 +53,7 @@ func NewClassicNameServer(address net.Destination, dispatcher routing.Dispatcher
Execute: s.Cleanup,
}
s.udpServer = udp.NewDispatcher(dispatcher, s.HandleResponse)
newError("DNS: created UDP client inited for ", address.NetAddr()).AtInfo().WriteToLog()
newError("DNS: created UDP client initialized for ", address.NetAddr()).AtInfo().WriteToLog()
return s
}
@@ -182,7 +182,7 @@ func (s *ClassicNameServer) addPendingRequest(req *dnsRequest) {
s.requests[id] = *req
}
func (s *ClassicNameServer) sendQuery(ctx context.Context, domain string, clientIP net.IP, option IPOption) {
func (s *ClassicNameServer) 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))
@@ -201,7 +201,7 @@ func (s *ClassicNameServer) sendQuery(ctx context.Context, domain string, client
}
}
func (s *ClassicNameServer) findIPsForDomain(domain string, option IPOption) ([]net.IP, error) {
func (s *ClassicNameServer) findIPsForDomain(domain string, option dns_feature.IPOption) ([]net.IP, error) {
s.RLock()
record, found := s.ips[domain]
s.RUnlock()
@@ -240,13 +240,17 @@ func (s *ClassicNameServer) findIPsForDomain(domain string, option IPOption) ([]
}
// QueryIP implements Server.
func (s *ClassicNameServer) QueryIP(ctx context.Context, domain string, clientIP net.IP, option IPOption) ([]net.IP, error) {
func (s *ClassicNameServer) QueryIP(ctx context.Context, domain string, clientIP net.IP, option dns_feature.IPOption, disableCache bool) ([]net.IP, error) {
fqdn := Fqdn(domain)
ips, err := s.findIPsForDomain(fqdn, option)
if err != errRecordNotFound {
newError(s.name, " cache HIT ", domain, " -> ", ips).Base(err).AtDebug().WriteToLog()
return ips, err
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
+11 -2
View File
@@ -11,6 +11,7 @@ import (
"github.com/v2fly/v2ray-core/v4/common/net"
serial "github.com/v2fly/v2ray-core/v4/common/serial"
"github.com/v2fly/v2ray-core/v4/common/session"
"github.com/v2fly/v2ray-core/v4/features/dns"
"github.com/v2fly/v2ray-core/v4/features/outbound"
routing_session "github.com/v2fly/v2ray-core/v4/features/routing/session"
"github.com/v2fly/v2ray-core/v4/testing/mocks"
@@ -163,7 +164,11 @@ func TestIPOnDemand(t *testing.T) {
defer mockCtl.Finish()
mockDNS := mocks.NewDNSClient(mockCtl)
mockDNS.EXPECT().LookupIP(gomock.Eq("v2fly.org")).Return([]net.IP{{192, 168, 0, 1}}, nil).AnyTimes()
mockDNS.EXPECT().LookupIP(gomock.Eq("v2fly.org"), dns.IPOption{
IPv4Enable: true,
IPv6Enable: true,
FakeEnable: false,
}).Return([]net.IP{{192, 168, 0, 1}}, nil).AnyTimes()
r := new(Router)
common.Must(r.Init(config, mockDNS, nil, nil))
@@ -198,7 +203,11 @@ func TestIPIfNonMatchDomain(t *testing.T) {
defer mockCtl.Finish()
mockDNS := mocks.NewDNSClient(mockCtl)
mockDNS.EXPECT().LookupIP(gomock.Eq("v2fly.org")).Return([]net.IP{{192, 168, 0, 1}}, nil).AnyTimes()
mockDNS.EXPECT().LookupIP(gomock.Eq("v2fly.org"), dns.IPOption{
IPv4Enable: true,
IPv6Enable: true,
FakeEnable: false,
}).Return([]net.IP{{192, 168, 0, 1}}, nil).AnyTimes()
r := new(Router)
common.Must(r.Init(config, mockDNS, nil, nil))
+8 -15
View File
@@ -7,6 +7,13 @@ import (
"github.com/v2fly/v2ray-core/v4/features"
)
// IPOption is an object for IP query options.
type IPOption struct {
IPv4Enable bool
IPv6Enable bool
FakeEnable bool
}
// Client is a V2Ray feature for querying DNS information.
//
// v2ray:api:stable
@@ -14,21 +21,7 @@ type Client interface {
features.Feature
// LookupIP returns IP address for the given domain. IPs may contain IPv4 and/or IPv6 addresses.
LookupIP(domain string) ([]net.IP, error)
}
// IPv4Lookup is an optional feature for querying IPv4 addresses only.
//
// v2ray:api:beta
type IPv4Lookup interface {
LookupIPv4(domain string) ([]net.IP, error)
}
// IPv6Lookup is an optional feature for querying IPv6 addresses only.
//
// v2ray:api:beta
type IPv6Lookup interface {
LookupIPv6(domain string) ([]net.IP, error)
LookupIP(domain string, option IPOption) ([]net.IP, error)
}
// ClientType returns the type of Client interface. Can be used for implementing common.HasType.
+17 -34
View File
@@ -20,58 +20,41 @@ func (*Client) Start() error { return nil }
func (*Client) Close() error { return nil }
// LookupIP implements Client.
func (*Client) LookupIP(host string) ([]net.IP, error) {
func (*Client) LookupIP(host string, option dns.IPOption) ([]net.IP, error) {
ips, err := net.LookupIP(host)
if err != nil {
return nil, err
}
parsedIPs := make([]net.IP, 0, len(ips))
ipv4 := make([]net.IP, 0, len(ips))
ipv6 := make([]net.IP, 0, len(ips))
for _, ip := range ips {
parsed := net.IPAddress(ip)
if parsed != nil {
parsedIPs = append(parsedIPs, parsed.IP())
}
}
if len(parsedIPs) == 0 {
return nil, dns.ErrEmptyResponse
}
return parsedIPs, nil
}
// LookupIPv4 implements IPv4Lookup.
func (c *Client) LookupIPv4(host string) ([]net.IP, error) {
ips, err := c.LookupIP(host)
if err != nil {
return nil, err
}
ipv4 := make([]net.IP, 0, len(ips))
for _, ip := range ips {
if len(ip) == net.IPv4len {
ipv4 = append(ipv4, ip)
}
}
if len(ipv4) == 0 {
return nil, dns.ErrEmptyResponse
}
return ipv4, nil
}
// LookupIPv6 implements IPv6Lookup.
func (c *Client) LookupIPv6(host string) ([]net.IP, error) {
ips, err := c.LookupIP(host)
if err != nil {
return nil, err
}
ipv6 := make([]net.IP, 0, len(ips))
for _, ip := range ips {
if len(ip) == net.IPv6len {
ipv6 = append(ipv6, ip)
}
}
if len(ipv6) == 0 {
return nil, dns.ErrEmptyResponse
switch {
case option.IPv4Enable && option.IPv6Enable:
if len(parsedIPs) > 0 {
return parsedIPs, nil
}
case option.IPv4Enable:
if len(ipv4) > 0 {
return ipv4, nil
}
case option.IPv6Enable:
if len(ipv6) > 0 {
return ipv6, nil
}
}
return ipv6, nil
return nil, dns.ErrEmptyResponse
}
// New create a new dns.Client that queries localhost for DNS.
+5 -1
View File
@@ -26,7 +26,11 @@ func (ctx *ResolvableContext) GetTargetIPs() []net.IP {
}
if domain := ctx.GetTargetDomain(); len(domain) != 0 {
ips, err := ctx.dnsClient.LookupIP(domain)
ips, err := ctx.dnsClient.LookupIP(domain, dns.IPOption{
IPv4Enable: true,
IPv6Enable: true,
FakeEnable: false,
})
if err == nil {
ctx.resolvedIPs = ips
return ips
+9 -9
View File
@@ -1,26 +1,26 @@
module github.com/v2fly/v2ray-core/v4
go 1.15
go 1.16
require (
github.com/golang/mock v1.4.4
github.com/golang/mock v1.5.0
github.com/golang/protobuf v1.4.3
github.com/google/go-cmp v0.5.4
github.com/gorilla/websocket v1.4.2
github.com/lucas-clemente/quic-go v0.19.3
github.com/miekg/dns v1.1.38
github.com/miekg/dns v1.1.39
github.com/pelletier/go-toml v1.8.1
github.com/pires/go-proxyproto v0.4.2
github.com/seiflotfy/cuckoofilter v0.0.0-20201222105146-bc6005554a0c
github.com/stretchr/testify v1.7.0
github.com/v2fly/VSign v0.0.0-20201108000810-e2adc24bf848
go.starlark.net v0.0.0-20210212215732-ebe61bd709bf
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad
golang.org/x/net v0.0.0-20210119194325-5f4716e94777
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a
golang.org/x/sys v0.0.0-20210216224549-f992740a1bac
go.starlark.net v0.0.0-20210223155950-e043a3d3c984
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83
golang.org/x/net v0.0.0-20210224082022-3d97a244fca7
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
golang.org/x/sys v0.0.0-20210223212115-eede4237b368
google.golang.org/grpc v1.35.0
google.golang.org/protobuf v1.25.0
gopkg.in/yaml.v2 v2.3.0
gopkg.in/yaml.v2 v2.4.0
h12.io/socks v1.0.2
)
+19 -14
View File
@@ -49,8 +49,9 @@ github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200j
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/mock v1.5.0 h1:jlYHihg//f7RRwuPfptm04yp4s7O6Kw8EZiVYIGcH0g=
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -108,8 +109,8 @@ github.com/marten-seemann/qtls-go1-15 v0.1.1 h1:LIH6K34bPVttyXnUWixk0bzH6/N07Vxb
github.com/marten-seemann/qtls-go1-15 v0.1.1/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
github.com/miekg/dns v1.1.38 h1:MtIY+fmHUVVgv1AXzmKMWcwdCYxTRPG1EDjpqF4RCEw=
github.com/miekg/dns v1.1.38/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
github.com/miekg/dns v1.1.39 h1:6dRfDGnHiXOMmTZkwWANy7bBXXlKls5Qu+pn+Ue0TLo=
github.com/miekg/dns v1.1.39/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
@@ -180,8 +181,8 @@ github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49u
github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.starlark.net v0.0.0-20210212215732-ebe61bd709bf h1:8b1dxl/E/KcBT0eST8oMb6H06zAtsUCfNNoNVkP7Z2U=
go.starlark.net v0.0.0-20210212215732-ebe61bd709bf/go.mod h1:t3mmBBPzAVvK0L0n1drDmrQsJ8FoIx4INCqVMTr/Zo0=
go.starlark.net v0.0.0-20210223155950-e043a3d3c984 h1:xwwDQW5We85NaTk2APgoN9202w/l0DVGp+GZMfsrh7s=
go.starlark.net v0.0.0-20210223155950-e043a3d3c984/go.mod h1:t3mmBBPzAVvK0L0n1drDmrQsJ8FoIx4INCqVMTr/Zo0=
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
@@ -190,14 +191,15 @@ golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY=
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -212,8 +214,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210224082022-3d97a244fca7 h1:OgUuv8lsRpBibGNbSizVwKWlysjaNzmC9gYMhPVfqFM=
golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -225,8 +227,8 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a h1:DcqTD9SDLc+1P/r1EmRBwnVsrOwW+kk2vWf9n+1sGhs=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -244,8 +246,8 @@ golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210216224549-f992740a1bac h1:9glrpwtNjBYgRpb67AZJKHfzj1stG/8BL5H7In2oTC4=
golang.org/x/sys v0.0.0-20210216224549-f992740a1bac/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210223212115-eede4237b368 h1:fDE3p0qf2V1co1vfj3/o87Ps8Hq6QTGNxJ5Xe7xSp80=
golang.org/x/sys v0.0.0-20210223212115-eede4237b368/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -264,7 +266,9 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
@@ -315,8 +319,9 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWD
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c h1:grhR+C34yXImVGp7EzNk+DTIk+323eIUWOmEevy6bDo=
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+7 -5
View File
@@ -120,10 +120,11 @@ var typeMap = map[router.Domain_Type]dns.DomainMatchingType{
// DNSConfig is a JSON serializable object for dns.Config.
type DNSConfig struct {
Servers []*NameServerConfig `json:"servers"`
Hosts map[string]*Address `json:"hosts"`
ClientIP *Address `json:"clientIp"`
Tag string `json:"tag"`
Servers []*NameServerConfig `json:"servers"`
Hosts map[string]*Address `json:"hosts"`
ClientIP *Address `json:"clientIp"`
Tag string `json:"tag"`
DisableCache bool `json:"disableCache"`
}
func getHostMapping(addr *Address) *dns.Config_HostMapping {
@@ -140,7 +141,8 @@ func getHostMapping(addr *Address) *dns.Config_HostMapping {
// Build implements Buildable
func (c *DNSConfig) Build() (*dns.Config, error) {
config := &dns.Config{
Tag: c.Tag,
Tag: c.Tag,
DisableCache: c.DisableCache,
}
if c.ClientIP != nil {
+7 -6
View File
@@ -1,8 +1,9 @@
package core
//go:generate go run github.com/golang/mock/mockgen -package mocks -destination testing/mocks/io.go -mock_names Reader=Reader,Writer=Writer io Reader,Writer
//go:generate go run github.com/golang/mock/mockgen -package mocks -destination testing/mocks/log.go -mock_names Handler=LogHandler github.com/v2fly/v2ray-core/v4/common/log Handler
//go:generate go run github.com/golang/mock/mockgen -package mocks -destination testing/mocks/mux.go -mock_names ClientWorkerFactory=MuxClientWorkerFactory github.com/v2fly/v2ray-core/v4/common/mux ClientWorkerFactory
//go:generate go run github.com/golang/mock/mockgen -package mocks -destination testing/mocks/dns.go -mock_names Client=DNSClient github.com/v2fly/v2ray-core/v4/features/dns Client
//go:generate go run github.com/golang/mock/mockgen -package mocks -destination testing/mocks/outbound.go -mock_names Manager=OutboundManager,HandlerSelector=OutboundHandlerSelector github.com/v2fly/v2ray-core/v4/features/outbound Manager,HandlerSelector
//go:generate go run github.com/golang/mock/mockgen -package mocks -destination testing/mocks/proxy.go -mock_names Inbound=ProxyInbound,Outbound=ProxyOutbound github.com/v2fly/v2ray-core/v4/proxy Inbound,Outbound
//go:generate env GOBIN=$PWD go install -v github.com/golang/mock/mockgen@latest
//go:generate ./mockgen -package mocks -destination testing/mocks/io.go -mock_names Reader=Reader,Writer=Writer io Reader,Writer
//go:generate ./mockgen -package mocks -destination testing/mocks/log.go -mock_names Handler=LogHandler github.com/v2fly/v2ray-core/v4/common/log Handler
//go:generate ./mockgen -package mocks -destination testing/mocks/mux.go -mock_names ClientWorkerFactory=MuxClientWorkerFactory github.com/v2fly/v2ray-core/v4/common/mux ClientWorkerFactory
//go:generate ./mockgen -package mocks -destination testing/mocks/dns.go -mock_names Client=DNSClient github.com/v2fly/v2ray-core/v4/features/dns Client
//go:generate ./mockgen -package mocks -destination testing/mocks/outbound.go -mock_names Manager=OutboundManager,HandlerSelector=OutboundHandlerSelector github.com/v2fly/v2ray-core/v4/features/outbound Manager,HandlerSelector
//go:generate ./mockgen -package mocks -destination testing/mocks/proxy.go -mock_names Inbound=ProxyInbound,Outbound=ProxyOutbound github.com/v2fly/v2ray-core/v4/proxy Inbound,Outbound
+2 -2
View File
@@ -1,5 +1,5 @@
package core
//go:generate go install -v google.golang.org/protobuf/cmd/protoc-gen-go
//go:generate go install -v google.golang.org/grpc/cmd/protoc-gen-go-grpc
//go:generate go install -v google.golang.org/protobuf/cmd/protoc-gen-go@latest
//go:generate go install -v google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
//go:generate go run ./infra/vprotogen/
+10 -16
View File
@@ -37,26 +37,12 @@ type ownLinkVerifier interface {
type Handler struct {
client dns.Client
ipv4Lookup dns.IPv4Lookup
ipv6Lookup dns.IPv6Lookup
ownLinkVerifier ownLinkVerifier
server net.Destination
}
func (h *Handler) Init(config *Config, dnsClient dns.Client) error {
h.client = dnsClient
ipv4lookup, ok := dnsClient.(dns.IPv4Lookup)
if !ok {
return newError("dns.Client doesn't implement IPv4Lookup")
}
h.ipv4Lookup = ipv4lookup
ipv6lookup, ok := dnsClient.(dns.IPv6Lookup)
if !ok {
return newError("dns.Client doesn't implement IPv6Lookup")
}
h.ipv6Lookup = ipv6lookup
if v, ok := dnsClient.(ownLinkVerifier); ok {
h.ownLinkVerifier = v
}
@@ -215,9 +201,17 @@ func (h *Handler) handleIPQuery(id uint16, qType dnsmessage.Type, domain string,
switch qType {
case dnsmessage.TypeA:
ips, err = h.ipv4Lookup.LookupIPv4(domain)
ips, err = h.client.LookupIP(domain, dns.IPOption{
IPv4Enable: true,
IPv6Enable: false,
FakeEnable: true,
})
case dnsmessage.TypeAAAA:
ips, err = h.ipv6Lookup.LookupIPv6(domain)
ips, err = h.client.LookupIP(domain, dns.IPOption{
IPv4Enable: false,
IPv6Enable: true,
FakeEnable: true,
})
}
rcode := dns.RCodeFromError(err)
+15 -8
View File
@@ -58,19 +58,26 @@ func (h *Handler) policy() policy.Session {
}
func (h *Handler) resolveIP(ctx context.Context, domain string, localAddr net.Address) net.Address {
var lookupFunc func(string) ([]net.IP, error) = h.dns.LookupIP
var option dns.IPOption = dns.IPOption{
IPv4Enable: true,
IPv6Enable: true,
FakeEnable: false,
}
if h.config.DomainStrategy == Config_USE_IP4 || (localAddr != nil && localAddr.Family().IsIPv4()) {
if lookupIPv4, ok := h.dns.(dns.IPv4Lookup); ok {
lookupFunc = lookupIPv4.LookupIPv4
option = dns.IPOption{
IPv4Enable: true,
IPv6Enable: false,
FakeEnable: false,
}
} else if h.config.DomainStrategy == Config_USE_IP6 || (localAddr != nil && localAddr.Family().IsIPv6()) {
if lookupIPv6, ok := h.dns.(dns.IPv6Lookup); ok {
lookupFunc = lookupIPv6.LookupIPv6
option = dns.IPOption{
IPv4Enable: false,
IPv6Enable: true,
FakeEnable: false,
}
}
ips, err := lookupFunc(domain)
ips, err := h.dns.LookupIP(domain, option)
if err != nil {
newError("failed to get IP address for domain ", domain).Base(err).WriteToLog(session.ExportIDToError(ctx))
}
@@ -121,7 +128,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
Address: ip,
Port: dialDest.Port,
}
newError("dialing to to ", dialDest).WriteToLog(session.ExportIDToError(ctx))
newError("dialing to ", dialDest).WriteToLog(session.ExportIDToError(ctx))
}
}
+15 -5
View File
@@ -7,17 +7,27 @@ import (
)
func KDF(key []byte, path ...string) []byte {
hmacf := hmac.New(sha256.New, []byte(KDFSaltConstVMessAEADKDF))
hmacCreator := &hMacCreator{value: []byte(KDFSaltConstVMessAEADKDF)}
for _, v := range path {
hmacf = hmac.New(func() hash.Hash {
return hmacf
}, []byte(v))
hmacCreator = &hMacCreator{value: []byte(v), parent: hmacCreator}
}
hmacf := hmacCreator.Create()
hmacf.Write(key)
return hmacf.Sum(nil)
}
type hMacCreator struct {
parent *hMacCreator
value []byte
}
func (h *hMacCreator) Create() hash.Hash {
if h.parent == nil {
return hmac.New(sha256.New, h.value)
}
return hmac.New(h.parent.Create, h.value)
}
func KDF16(key []byte, path ...string) []byte {
r := KDF(key, path...)
return r[:16]
+15
View File
@@ -0,0 +1,15 @@
package aead
import (
"encoding/hex"
"fmt"
"testing"
"github.com/stretchr/testify/assert"
)
func TestKDFValue(t *testing.T) {
GeneratedKey := KDF([]byte("Demo Key for KDF Value Test"), "Demo Path for KDF Value Test", "Demo Path for KDF Value Test2", "Demo Path for KDF Value Test3")
fmt.Println(hex.EncodeToString(GeneratedKey))
assert.Equal(t, "53e9d7e1bd7bd25022b71ead07d8a596efc8a845c7888652fd684b4903dc8892", hex.EncodeToString(GeneratedKey), "Should generate expected KDF Value")
}
Binary file not shown.
+7552 -7551
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -1,5 +1,6 @@
{
"darwin-amd64": { "friendlyName": "macos-64" },
"darwin-arm64": { "friendlyName": "macos-arm64-v8a" },
"dragonfly-amd64": { "friendlyName": "dragonfly-64" },
"freebsd-386": { "friendlyName": "freebsd-32" },
"freebsd-amd64": { "friendlyName": "freebsd-64" },
+19 -17
View File
@@ -5,35 +5,37 @@
package mocks
import (
gomock "github.com/golang/mock/gomock"
net "net"
reflect "reflect"
gomock "github.com/golang/mock/gomock"
dns "github.com/v2fly/v2ray-core/v4/features/dns"
)
// DNSClient is a mock of Client interface
// DNSClient is a mock of Client interface.
type DNSClient struct {
ctrl *gomock.Controller
recorder *DNSClientMockRecorder
}
// DNSClientMockRecorder is the mock recorder for DNSClient
// DNSClientMockRecorder is the mock recorder for DNSClient.
type DNSClientMockRecorder struct {
mock *DNSClient
}
// NewDNSClient creates a new mock instance
// NewDNSClient creates a new mock instance.
func NewDNSClient(ctrl *gomock.Controller) *DNSClient {
mock := &DNSClient{ctrl: ctrl}
mock.recorder = &DNSClientMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *DNSClient) EXPECT() *DNSClientMockRecorder {
return m.recorder
}
// Close mocks base method
// Close mocks base method.
func (m *DNSClient) Close() error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Close")
@@ -41,28 +43,28 @@ func (m *DNSClient) Close() error {
return ret0
}
// Close indicates an expected call of Close
// Close indicates an expected call of Close.
func (mr *DNSClientMockRecorder) Close() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*DNSClient)(nil).Close))
}
// LookupIP mocks base method
func (m *DNSClient) LookupIP(arg0 string) ([]net.IP, error) {
// LookupIP mocks base method.
func (m *DNSClient) LookupIP(arg0 string, arg1 dns.IPOption) ([]net.IP, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "LookupIP", arg0)
ret := m.ctrl.Call(m, "LookupIP", arg0, arg1)
ret0, _ := ret[0].([]net.IP)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// LookupIP indicates an expected call of LookupIP
func (mr *DNSClientMockRecorder) LookupIP(arg0 interface{}) *gomock.Call {
// LookupIP indicates an expected call of LookupIP.
func (mr *DNSClientMockRecorder) LookupIP(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LookupIP", reflect.TypeOf((*DNSClient)(nil).LookupIP), arg0)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LookupIP", reflect.TypeOf((*DNSClient)(nil).LookupIP), arg0, arg1)
}
// Start mocks base method
// Start mocks base method.
func (m *DNSClient) Start() error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Start")
@@ -70,13 +72,13 @@ func (m *DNSClient) Start() error {
return ret0
}
// Start indicates an expected call of Start
// Start indicates an expected call of Start.
func (mr *DNSClientMockRecorder) Start() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Start", reflect.TypeOf((*DNSClient)(nil).Start))
}
// Type mocks base method
// Type mocks base method.
func (m *DNSClient) Type() interface{} {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Type")
@@ -84,7 +86,7 @@ func (m *DNSClient) Type() interface{} {
return ret0
}
// Type indicates an expected call of Type
// Type indicates an expected call of Type.
func (mr *DNSClientMockRecorder) Type() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Type", reflect.TypeOf((*DNSClient)(nil).Type))
+14 -13
View File
@@ -5,34 +5,35 @@
package mocks
import (
gomock "github.com/golang/mock/gomock"
reflect "reflect"
gomock "github.com/golang/mock/gomock"
)
// Reader is a mock of Reader interface
// Reader is a mock of Reader interface.
type Reader struct {
ctrl *gomock.Controller
recorder *ReaderMockRecorder
}
// ReaderMockRecorder is the mock recorder for Reader
// ReaderMockRecorder is the mock recorder for Reader.
type ReaderMockRecorder struct {
mock *Reader
}
// NewReader creates a new mock instance
// NewReader creates a new mock instance.
func NewReader(ctrl *gomock.Controller) *Reader {
mock := &Reader{ctrl: ctrl}
mock.recorder = &ReaderMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *Reader) EXPECT() *ReaderMockRecorder {
return m.recorder
}
// Read mocks base method
// Read mocks base method.
func (m *Reader) Read(arg0 []byte) (int, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Read", arg0)
@@ -41,36 +42,36 @@ func (m *Reader) Read(arg0 []byte) (int, error) {
return ret0, ret1
}
// Read indicates an expected call of Read
// Read indicates an expected call of Read.
func (mr *ReaderMockRecorder) Read(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Read", reflect.TypeOf((*Reader)(nil).Read), arg0)
}
// Writer is a mock of Writer interface
// Writer is a mock of Writer interface.
type Writer struct {
ctrl *gomock.Controller
recorder *WriterMockRecorder
}
// WriterMockRecorder is the mock recorder for Writer
// WriterMockRecorder is the mock recorder for Writer.
type WriterMockRecorder struct {
mock *Writer
}
// NewWriter creates a new mock instance
// NewWriter creates a new mock instance.
func NewWriter(ctrl *gomock.Controller) *Writer {
mock := &Writer{ctrl: ctrl}
mock.recorder = &WriterMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *Writer) EXPECT() *WriterMockRecorder {
return m.recorder
}
// Write mocks base method
// Write mocks base method.
func (m *Writer) Write(arg0 []byte) (int, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Write", arg0)
@@ -79,7 +80,7 @@ func (m *Writer) Write(arg0 []byte) (int, error) {
return ret0, ret1
}
// Write indicates an expected call of Write
// Write indicates an expected call of Write.
func (mr *WriterMockRecorder) Write(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Write", reflect.TypeOf((*Writer)(nil).Write), arg0)
+8 -7
View File
@@ -5,41 +5,42 @@
package mocks
import (
reflect "reflect"
gomock "github.com/golang/mock/gomock"
log "github.com/v2fly/v2ray-core/v4/common/log"
reflect "reflect"
)
// LogHandler is a mock of Handler interface
// LogHandler is a mock of Handler interface.
type LogHandler struct {
ctrl *gomock.Controller
recorder *LogHandlerMockRecorder
}
// LogHandlerMockRecorder is the mock recorder for LogHandler
// LogHandlerMockRecorder is the mock recorder for LogHandler.
type LogHandlerMockRecorder struct {
mock *LogHandler
}
// NewLogHandler creates a new mock instance
// NewLogHandler creates a new mock instance.
func NewLogHandler(ctrl *gomock.Controller) *LogHandler {
mock := &LogHandler{ctrl: ctrl}
mock.recorder = &LogHandlerMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *LogHandler) EXPECT() *LogHandlerMockRecorder {
return m.recorder
}
// Handle mocks base method
// Handle mocks base method.
func (m *LogHandler) Handle(arg0 log.Message) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "Handle", arg0)
}
// Handle indicates an expected call of Handle
// Handle indicates an expected call of Handle.
func (mr *LogHandlerMockRecorder) Handle(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Handle", reflect.TypeOf((*LogHandler)(nil).Handle), arg0)
+8 -7
View File
@@ -5,35 +5,36 @@
package mocks
import (
reflect "reflect"
gomock "github.com/golang/mock/gomock"
mux "github.com/v2fly/v2ray-core/v4/common/mux"
reflect "reflect"
)
// MuxClientWorkerFactory is a mock of ClientWorkerFactory interface
// MuxClientWorkerFactory is a mock of ClientWorkerFactory interface.
type MuxClientWorkerFactory struct {
ctrl *gomock.Controller
recorder *MuxClientWorkerFactoryMockRecorder
}
// MuxClientWorkerFactoryMockRecorder is the mock recorder for MuxClientWorkerFactory
// MuxClientWorkerFactoryMockRecorder is the mock recorder for MuxClientWorkerFactory.
type MuxClientWorkerFactoryMockRecorder struct {
mock *MuxClientWorkerFactory
}
// NewMuxClientWorkerFactory creates a new mock instance
// NewMuxClientWorkerFactory creates a new mock instance.
func NewMuxClientWorkerFactory(ctrl *gomock.Controller) *MuxClientWorkerFactory {
mock := &MuxClientWorkerFactory{ctrl: ctrl}
mock.recorder = &MuxClientWorkerFactoryMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MuxClientWorkerFactory) EXPECT() *MuxClientWorkerFactoryMockRecorder {
return m.recorder
}
// Create mocks base method
// Create mocks base method.
func (m *MuxClientWorkerFactory) Create() (*mux.ClientWorker, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Create")
@@ -42,7 +43,7 @@ func (m *MuxClientWorkerFactory) Create() (*mux.ClientWorker, error) {
return ret0, ret1
}
// Create indicates an expected call of Create
// Create indicates an expected call of Create.
func (mr *MuxClientWorkerFactoryMockRecorder) Create() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MuxClientWorkerFactory)(nil).Create))
+26 -25
View File
@@ -6,35 +6,36 @@ package mocks
import (
context "context"
reflect "reflect"
gomock "github.com/golang/mock/gomock"
outbound "github.com/v2fly/v2ray-core/v4/features/outbound"
reflect "reflect"
)
// OutboundManager is a mock of Manager interface
// OutboundManager is a mock of Manager interface.
type OutboundManager struct {
ctrl *gomock.Controller
recorder *OutboundManagerMockRecorder
}
// OutboundManagerMockRecorder is the mock recorder for OutboundManager
// OutboundManagerMockRecorder is the mock recorder for OutboundManager.
type OutboundManagerMockRecorder struct {
mock *OutboundManager
}
// NewOutboundManager creates a new mock instance
// NewOutboundManager creates a new mock instance.
func NewOutboundManager(ctrl *gomock.Controller) *OutboundManager {
mock := &OutboundManager{ctrl: ctrl}
mock.recorder = &OutboundManagerMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *OutboundManager) EXPECT() *OutboundManagerMockRecorder {
return m.recorder
}
// AddHandler mocks base method
// AddHandler mocks base method.
func (m *OutboundManager) AddHandler(arg0 context.Context, arg1 outbound.Handler) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "AddHandler", arg0, arg1)
@@ -42,13 +43,13 @@ func (m *OutboundManager) AddHandler(arg0 context.Context, arg1 outbound.Handler
return ret0
}
// AddHandler indicates an expected call of AddHandler
// AddHandler indicates an expected call of AddHandler.
func (mr *OutboundManagerMockRecorder) AddHandler(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddHandler", reflect.TypeOf((*OutboundManager)(nil).AddHandler), arg0, arg1)
}
// Close mocks base method
// Close mocks base method.
func (m *OutboundManager) Close() error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Close")
@@ -56,13 +57,13 @@ func (m *OutboundManager) Close() error {
return ret0
}
// Close indicates an expected call of Close
// Close indicates an expected call of Close.
func (mr *OutboundManagerMockRecorder) Close() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*OutboundManager)(nil).Close))
}
// GetDefaultHandler mocks base method
// GetDefaultHandler mocks base method.
func (m *OutboundManager) GetDefaultHandler() outbound.Handler {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetDefaultHandler")
@@ -70,13 +71,13 @@ func (m *OutboundManager) GetDefaultHandler() outbound.Handler {
return ret0
}
// GetDefaultHandler indicates an expected call of GetDefaultHandler
// GetDefaultHandler indicates an expected call of GetDefaultHandler.
func (mr *OutboundManagerMockRecorder) GetDefaultHandler() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDefaultHandler", reflect.TypeOf((*OutboundManager)(nil).GetDefaultHandler))
}
// GetHandler mocks base method
// GetHandler mocks base method.
func (m *OutboundManager) GetHandler(arg0 string) outbound.Handler {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetHandler", arg0)
@@ -84,13 +85,13 @@ func (m *OutboundManager) GetHandler(arg0 string) outbound.Handler {
return ret0
}
// GetHandler indicates an expected call of GetHandler
// GetHandler indicates an expected call of GetHandler.
func (mr *OutboundManagerMockRecorder) GetHandler(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetHandler", reflect.TypeOf((*OutboundManager)(nil).GetHandler), arg0)
}
// RemoveHandler mocks base method
// RemoveHandler mocks base method.
func (m *OutboundManager) RemoveHandler(arg0 context.Context, arg1 string) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "RemoveHandler", arg0, arg1)
@@ -98,13 +99,13 @@ func (m *OutboundManager) RemoveHandler(arg0 context.Context, arg1 string) error
return ret0
}
// RemoveHandler indicates an expected call of RemoveHandler
// RemoveHandler indicates an expected call of RemoveHandler.
func (mr *OutboundManagerMockRecorder) RemoveHandler(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveHandler", reflect.TypeOf((*OutboundManager)(nil).RemoveHandler), arg0, arg1)
}
// Start mocks base method
// Start mocks base method.
func (m *OutboundManager) Start() error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Start")
@@ -112,13 +113,13 @@ func (m *OutboundManager) Start() error {
return ret0
}
// Start indicates an expected call of Start
// Start indicates an expected call of Start.
func (mr *OutboundManagerMockRecorder) Start() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Start", reflect.TypeOf((*OutboundManager)(nil).Start))
}
// Type mocks base method
// Type mocks base method.
func (m *OutboundManager) Type() interface{} {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Type")
@@ -126,36 +127,36 @@ func (m *OutboundManager) Type() interface{} {
return ret0
}
// Type indicates an expected call of Type
// Type indicates an expected call of Type.
func (mr *OutboundManagerMockRecorder) Type() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Type", reflect.TypeOf((*OutboundManager)(nil).Type))
}
// OutboundHandlerSelector is a mock of HandlerSelector interface
// OutboundHandlerSelector is a mock of HandlerSelector interface.
type OutboundHandlerSelector struct {
ctrl *gomock.Controller
recorder *OutboundHandlerSelectorMockRecorder
}
// OutboundHandlerSelectorMockRecorder is the mock recorder for OutboundHandlerSelector
// OutboundHandlerSelectorMockRecorder is the mock recorder for OutboundHandlerSelector.
type OutboundHandlerSelectorMockRecorder struct {
mock *OutboundHandlerSelector
}
// NewOutboundHandlerSelector creates a new mock instance
// NewOutboundHandlerSelector creates a new mock instance.
func NewOutboundHandlerSelector(ctrl *gomock.Controller) *OutboundHandlerSelector {
mock := &OutboundHandlerSelector{ctrl: ctrl}
mock.recorder = &OutboundHandlerSelectorMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *OutboundHandlerSelector) EXPECT() *OutboundHandlerSelectorMockRecorder {
return m.recorder
}
// Select mocks base method
// Select mocks base method.
func (m *OutboundHandlerSelector) Select(arg0 []string) []string {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Select", arg0)
@@ -163,7 +164,7 @@ func (m *OutboundHandlerSelector) Select(arg0 []string) []string {
return ret0
}
// Select indicates an expected call of Select
// Select indicates an expected call of Select.
func (mr *OutboundHandlerSelectorMockRecorder) Select(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Select", reflect.TypeOf((*OutboundHandlerSelector)(nil).Select), arg0)
+16 -15
View File
@@ -6,38 +6,39 @@ package mocks
import (
context "context"
reflect "reflect"
gomock "github.com/golang/mock/gomock"
net "github.com/v2fly/v2ray-core/v4/common/net"
routing "github.com/v2fly/v2ray-core/v4/features/routing"
transport "github.com/v2fly/v2ray-core/v4/transport"
internet "github.com/v2fly/v2ray-core/v4/transport/internet"
reflect "reflect"
)
// ProxyInbound is a mock of Inbound interface
// ProxyInbound is a mock of Inbound interface.
type ProxyInbound struct {
ctrl *gomock.Controller
recorder *ProxyInboundMockRecorder
}
// ProxyInboundMockRecorder is the mock recorder for ProxyInbound
// ProxyInboundMockRecorder is the mock recorder for ProxyInbound.
type ProxyInboundMockRecorder struct {
mock *ProxyInbound
}
// NewProxyInbound creates a new mock instance
// NewProxyInbound creates a new mock instance.
func NewProxyInbound(ctrl *gomock.Controller) *ProxyInbound {
mock := &ProxyInbound{ctrl: ctrl}
mock.recorder = &ProxyInboundMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *ProxyInbound) EXPECT() *ProxyInboundMockRecorder {
return m.recorder
}
// Network mocks base method
// Network mocks base method.
func (m *ProxyInbound) Network() []net.Network {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Network")
@@ -45,13 +46,13 @@ func (m *ProxyInbound) Network() []net.Network {
return ret0
}
// Network indicates an expected call of Network
// Network indicates an expected call of Network.
func (mr *ProxyInboundMockRecorder) Network() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Network", reflect.TypeOf((*ProxyInbound)(nil).Network))
}
// Process mocks base method
// Process mocks base method.
func (m *ProxyInbound) Process(arg0 context.Context, arg1 net.Network, arg2 internet.Connection, arg3 routing.Dispatcher) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Process", arg0, arg1, arg2, arg3)
@@ -59,36 +60,36 @@ func (m *ProxyInbound) Process(arg0 context.Context, arg1 net.Network, arg2 inte
return ret0
}
// Process indicates an expected call of Process
// Process indicates an expected call of Process.
func (mr *ProxyInboundMockRecorder) Process(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Process", reflect.TypeOf((*ProxyInbound)(nil).Process), arg0, arg1, arg2, arg3)
}
// ProxyOutbound is a mock of Outbound interface
// ProxyOutbound is a mock of Outbound interface.
type ProxyOutbound struct {
ctrl *gomock.Controller
recorder *ProxyOutboundMockRecorder
}
// ProxyOutboundMockRecorder is the mock recorder for ProxyOutbound
// ProxyOutboundMockRecorder is the mock recorder for ProxyOutbound.
type ProxyOutboundMockRecorder struct {
mock *ProxyOutbound
}
// NewProxyOutbound creates a new mock instance
// NewProxyOutbound creates a new mock instance.
func NewProxyOutbound(ctrl *gomock.Controller) *ProxyOutbound {
mock := &ProxyOutbound{ctrl: ctrl}
mock.recorder = &ProxyOutboundMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *ProxyOutbound) EXPECT() *ProxyOutboundMockRecorder {
return m.recorder
}
// Process mocks base method
// Process mocks base method.
func (m *ProxyOutbound) Process(arg0 context.Context, arg1 *transport.Link, arg2 internet.Dialer) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Process", arg0, arg1, arg2)
@@ -96,7 +97,7 @@ func (m *ProxyOutbound) Process(arg0 context.Context, arg1 *transport.Link, arg2
return ret0
}
// Process indicates an expected call of Process
// Process indicates an expected call of Process.
func (mr *ProxyOutboundMockRecorder) Process(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Process", reflect.TypeOf((*ProxyOutbound)(nil).Process), arg0, arg1, arg2)