Skip to content

Commit e39d582

Browse files
author
Ben Schwartz
committed
Add a unit test
1 parent 6447a85 commit e39d582

File tree

1 file changed

+88
-14
lines changed

1 file changed

+88
-14
lines changed

service/udp_test.go

Lines changed: 88 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,11 @@ import (
2222
"testing"
2323
"time"
2424

25+
onet "github.com/Jigsaw-Code/outline-ss-server/net"
26+
"github.com/Jigsaw-Code/outline-ss-server/service/metrics"
2527
ss "github.com/Jigsaw-Code/outline-ss-server/shadowsocks"
2628
logging "github.com/op/go-logging"
29+
"github.com/shadowsocks/go-shadowsocks2/socks"
2730
)
2831

2932
const timeout = 5 * time.Minute
@@ -86,6 +89,77 @@ func (conn *fakePacketConn) Close() error {
8689
return nil
8790
}
8891

92+
// Stub metrics implementation for testing NAT behaviors.
93+
type natTestMetrics struct {
94+
metrics.ShadowsocksMetrics
95+
natEntriesAdded int
96+
}
97+
98+
func (m *natTestMetrics) AddTCPProbe(clientLocation, status, drainResult string, port int, data metrics.ProxyMetrics) {
99+
}
100+
func (m *natTestMetrics) AddClosedTCPConnection(clientLocation, accessKey, status string, data metrics.ProxyMetrics, timeToCipher, duration time.Duration) {
101+
}
102+
func (m *natTestMetrics) GetLocation(net.Addr) (string, error) {
103+
return "", nil
104+
}
105+
func (m *natTestMetrics) SetNumAccessKeys(numKeys int, numPorts int) {
106+
}
107+
func (m *natTestMetrics) AddOpenTCPConnection(clientLocation string) {
108+
}
109+
func (m *natTestMetrics) AddUDPPacketFromClient(clientLocation, accessKey, status string, clientProxyBytes, proxyTargetBytes int, timeToCipher time.Duration) {
110+
}
111+
func (m *natTestMetrics) AddUDPPacketFromTarget(clientLocation, accessKey, status string, targetProxyBytes, proxyClientBytes int) {
112+
}
113+
func (m *natTestMetrics) AddUDPNatEntry() {
114+
m.natEntriesAdded++
115+
}
116+
func (m *natTestMetrics) RemoveUDPNatEntry() {}
117+
118+
func TestIPFilter(t *testing.T) {
119+
// Takes a validation policy, and returns the metrics it
120+
// generates when localhost access is attempted
121+
checkLocalhost := func(validator onet.TargetIPValidator) *natTestMetrics {
122+
ciphers, _ := MakeTestCiphers([]string{"asdf"})
123+
cipher := ciphers.SnapshotForClientIP(nil)[0].Value.(*CipherEntry).Cipher
124+
clientConn := makePacketConn()
125+
metrics := &natTestMetrics{}
126+
service := NewUDPService(timeout, ciphers, metrics)
127+
service.SetTargetIPValidator(validator)
128+
go service.Serve(clientConn)
129+
130+
// Send one packet to the "discard" port on localhost
131+
targetAddr := socks.ParseAddr("127.0.0.1:9")
132+
payload := []byte("payload")
133+
plaintext := append(targetAddr, payload...)
134+
ciphertext := make([]byte, cipher.SaltSize()+len(plaintext)+cipher.TagSize())
135+
ss.Pack(ciphertext, plaintext, cipher)
136+
clientConn.recv <- packet{
137+
addr: &net.UDPAddr{
138+
IP: net.ParseIP("192.0.2.1"),
139+
Port: 54321,
140+
},
141+
payload: ciphertext,
142+
}
143+
144+
service.GracefulStop()
145+
return metrics
146+
}
147+
148+
t.Run("Localhost allowed", func(t *testing.T) {
149+
metrics := checkLocalhost(allowAll)
150+
if metrics.natEntriesAdded != 1 {
151+
t.Errorf("Expected 1 NAT entry, not %d", metrics.natEntriesAdded)
152+
}
153+
})
154+
155+
t.Run("Localhost not allowed", func(t *testing.T) {
156+
metrics := checkLocalhost(onet.RequirePublicIP)
157+
if metrics.natEntriesAdded != 0 {
158+
t.Error("Unexpected NAT entry on rejected packet")
159+
}
160+
})
161+
}
162+
89163
func assertAlmostEqual(t *testing.T, a, b time.Time) {
90164
delta := a.Sub(b)
91165
limit := 100 * time.Millisecond
@@ -95,14 +169,14 @@ func assertAlmostEqual(t *testing.T, a, b time.Time) {
95169
}
96170

97171
func TestNATEmpty(t *testing.T) {
98-
nat := newNATmap(timeout, &probeTestMetrics{}, &sync.WaitGroup{})
172+
nat := newNATmap(timeout, &natTestMetrics{}, &sync.WaitGroup{})
99173
if nat.Get("foo") != nil {
100174
t.Error("Expected nil value from empty NAT map")
101175
}
102176
}
103177

104-
func setup() (*fakePacketConn, *fakePacketConn, *natconn) {
105-
nat := newNATmap(timeout, &probeTestMetrics{}, &sync.WaitGroup{})
178+
func setupNAT() (*fakePacketConn, *fakePacketConn, *natconn) {
179+
nat := newNATmap(timeout, &natTestMetrics{}, &sync.WaitGroup{})
106180
clientConn := makePacketConn()
107181
targetConn := makePacketConn()
108182
nat.Add(&clientAddr, clientConn, natCipher, targetConn, "ZZ", "key id")
@@ -111,7 +185,7 @@ func setup() (*fakePacketConn, *fakePacketConn, *natconn) {
111185
}
112186

113187
func TestNATGet(t *testing.T) {
114-
_, targetConn, entry := setup()
188+
_, targetConn, entry := setupNAT()
115189
if entry == nil {
116190
t.Fatal("Failed to find target conn")
117191
}
@@ -121,7 +195,7 @@ func TestNATGet(t *testing.T) {
121195
}
122196

123197
func TestNATWrite(t *testing.T) {
124-
_, targetConn, entry := setup()
198+
_, targetConn, entry := setupNAT()
125199

126200
// Simulate one generic packet being sent
127201
buf := []byte{1}
@@ -137,7 +211,7 @@ func TestNATWrite(t *testing.T) {
137211
}
138212

139213
func TestNATWriteDNS(t *testing.T) {
140-
_, targetConn, entry := setup()
214+
_, targetConn, entry := setupNAT()
141215

142216
// Simulate one DNS query being sent.
143217
buf := []byte{1}
@@ -154,7 +228,7 @@ func TestNATWriteDNS(t *testing.T) {
154228
}
155229

156230
func TestNATWriteDNSMultiple(t *testing.T) {
157-
_, targetConn, entry := setup()
231+
_, targetConn, entry := setupNAT()
158232

159233
// Simulate three DNS queries being sent.
160234
buf := []byte{1}
@@ -169,7 +243,7 @@ func TestNATWriteDNSMultiple(t *testing.T) {
169243
}
170244

171245
func TestNATWriteMixed(t *testing.T) {
172-
_, targetConn, entry := setup()
246+
_, targetConn, entry := setupNAT()
173247

174248
// Simulate both non-DNS and DNS packets being sent.
175249
buf := []byte{1}
@@ -182,7 +256,7 @@ func TestNATWriteMixed(t *testing.T) {
182256
}
183257

184258
func TestNATFastClose(t *testing.T) {
185-
clientConn, targetConn, entry := setup()
259+
clientConn, targetConn, entry := setupNAT()
186260

187261
// Send one DNS query.
188262
query := []byte{1}
@@ -208,7 +282,7 @@ func TestNATFastClose(t *testing.T) {
208282
}
209283

210284
func TestNATNoFastClose_NotDNS(t *testing.T) {
211-
clientConn, targetConn, entry := setup()
285+
clientConn, targetConn, entry := setupNAT()
212286

213287
// Send one non-DNS packet.
214288
query := []byte{1}
@@ -233,7 +307,7 @@ func TestNATNoFastClose_NotDNS(t *testing.T) {
233307
}
234308

235309
func TestNATNoFastClose_MultipleDNS(t *testing.T) {
236-
clientConn, targetConn, entry := setup()
310+
clientConn, targetConn, entry := setupNAT()
237311

238312
// Send two DNS packets.
239313
query1 := []byte{1}
@@ -267,7 +341,7 @@ func (e *fakeTimeoutError) Temporary() bool {
267341
}
268342

269343
func TestNATTimeout(t *testing.T) {
270-
_, targetConn, entry := setup()
344+
_, targetConn, entry := setupNAT()
271345

272346
// Simulate a non-DNS initial packet.
273347
entry.WriteTo([]byte{1}, &targetAddr)
@@ -365,7 +439,7 @@ func TestUDPDoubleServe(t *testing.T) {
365439
if err != nil {
366440
t.Fatal(err)
367441
}
368-
testMetrics := &probeTestMetrics{}
442+
testMetrics := &natTestMetrics{}
369443
const testTimeout = 200 * time.Millisecond
370444
s := NewUDPService(testTimeout, cipherList, testMetrics)
371445

@@ -399,7 +473,7 @@ func TestUDPEarlyStop(t *testing.T) {
399473
if err != nil {
400474
t.Fatal(err)
401475
}
402-
testMetrics := &probeTestMetrics{}
476+
testMetrics := &natTestMetrics{}
403477
const testTimeout = 200 * time.Millisecond
404478
s := NewUDPService(testTimeout, cipherList, testMetrics)
405479

0 commit comments

Comments
 (0)