-
Notifications
You must be signed in to change notification settings - Fork 401
Expand file tree
/
Copy pathrouter_test.go
More file actions
154 lines (136 loc) · 3.77 KB
/
Copy pathrouter_test.go
File metadata and controls
154 lines (136 loc) · 3.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package wireproxy
import (
"regexp"
"testing"
)
func mustCompile(t *testing.T, patterns ...string) []*regexp.Regexp {
t.Helper()
out := make([]*regexp.Regexp, 0, len(patterns))
for _, p := range patterns {
re, err := regexp.Compile(p)
if err != nil {
t.Fatalf("compile %q: %v", p, err)
}
out = append(out, re)
}
return out
}
func TestDomainRouterShouldTunnel(t *testing.T) {
patterns := mustCompile(t, `^(.*\.)?example\.com$`, `^ipinfo\.io$`)
cases := []struct {
name string
host string
want bool
}{
{"exact match", "example.com", true},
{"subdomain match", "www.example.com", true},
{"deep subdomain match", "a.b.example.com", true},
{"second pattern exact", "ipinfo.io", true},
{"trailing dot stripped", "example.com.", true},
{"uppercase normalised", "WWW.EXAMPLE.COM", true},
{"no match", "other.net", false},
{"partial no match (suffix guard)", "notexample.com", false},
{"ip literal no match", "93.184.216.34", false},
}
router := NewDomainRouter(patterns, false)
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
if got := router.route(c.host); got != c.want {
t.Fatalf("route(%q) = %v, want %v", c.host, got, c.want)
}
})
}
}
func TestDomainRouterEmptyTunnelsEverything(t *testing.T) {
router := NewDomainRouter(nil, false)
for _, host := range []string{"anything.example", "1.2.3.4", ""} {
if !router.route(host) {
t.Fatalf("empty whitelist should tunnel %q", host)
}
}
// A nil router must also default to tunnelling (legacy behaviour).
var nilRouter *DomainRouter
if !nilRouter.route("example.com") {
t.Fatal("nil router should tunnel everything")
}
}
func TestHostFromAddr(t *testing.T) {
cases := map[string]string{
"example.com:443": "example.com",
"example.com": "example.com",
"1.2.3.4:80": "1.2.3.4",
"[::1]:443": "::1",
}
for in, want := range cases {
if got := hostFromAddr(in); got != want {
t.Fatalf("hostFromAddr(%q) = %q, want %q", in, got, want)
}
}
}
func TestParseRegexListMultiLine(t *testing.T) {
// Multiple TunnelDomains lines each parse as one full regex; commas inside a
// quantifier must survive (no comma-splitting).
const config = `
[Socks5]
BindAddress = 127.0.0.1:25344
TunnelDomains = ^(.*\.)?example\.com$
TunnelDomains = ^cache[0-9]{2,4}\.cdn\.net$
LogDomains = true`
iniData, err := loadIniConfig(config)
if err != nil {
t.Fatal(err)
}
section := iniData.Section("Socks5")
spawner, err := parseSocks5Config(section)
if err != nil {
t.Fatal(err)
}
cfg := spawner.(*Socks5Config)
if len(cfg.TunnelDomains) != 2 {
t.Fatalf("expected 2 patterns, got %d", len(cfg.TunnelDomains))
}
if !cfg.LogDomains {
t.Fatal("expected LogDomains=true")
}
router := NewDomainRouter(cfg.TunnelDomains, cfg.LogDomains)
if !router.route("www.example.com") {
t.Fatal("www.example.com should tunnel")
}
if !router.route("cache123.cdn.net") {
t.Fatal("cache123.cdn.net should tunnel (quantifier with comma)")
}
if router.route("evil.net") {
t.Fatal("evil.net should be direct")
}
}
func TestParseRegexListInvalidRejected(t *testing.T) {
const config = `
[http]
BindAddress = 127.0.0.1:25345
TunnelDomains = ^(unclosed`
iniData, err := loadIniConfig(config)
if err != nil {
t.Fatal(err)
}
section := iniData.Section("http")
if _, err := parseHTTPConfig(section); err == nil {
t.Fatal("expected invalid regex to be rejected")
}
}
func TestParseConfigDefaultsNoRouting(t *testing.T) {
const config = `
[SNI]
BindAddress = 0.0.0.0:443`
iniData, err := loadIniConfig(config)
if err != nil {
t.Fatal(err)
}
spawner, err := parseSNIConfig(iniData.Section("SNI"))
if err != nil {
t.Fatal(err)
}
cfg := spawner.(*SNIConfig)
if len(cfg.TunnelDomains) != 0 || cfg.LogDomains {
t.Fatal("defaults should be empty TunnelDomains and LogDomains=false")
}
}