Skip to content

Commit 5cec847

Browse files
committed
User-aware relay address generator
Resolves #420
1 parent 3ff9392 commit 5cec847

13 files changed

+462
-81
lines changed

internal/allocation/allocation_manager.go

+12-8
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ import (
1515
// ManagerConfig a bag of config params for Manager.
1616
type ManagerConfig struct {
1717
LeveledLogger logging.LeveledLogger
18-
AllocatePacketConn func(network string, requestedPort int) (net.PacketConn, net.Addr, error)
19-
AllocateConn func(network string, requestedPort int) (net.Conn, net.Addr, error)
18+
AllocatePacketConn func(network string, requestedPort int, username string) (net.PacketConn, net.Addr, error)
19+
AllocateConn func(network string, requestedPort int, username string) (net.Conn, net.Addr, error)
2020
PermissionHandler func(sourceAddr net.Addr, peerIP net.IP) bool
2121
}
2222

@@ -33,8 +33,8 @@ type Manager struct {
3333
allocations map[FiveTupleFingerprint]*Allocation
3434
reservations []*reservation
3535

36-
allocatePacketConn func(network string, requestedPort int) (net.PacketConn, net.Addr, error)
37-
allocateConn func(network string, requestedPort int) (net.Conn, net.Addr, error)
36+
allocatePacketConn func(network string, requestedPort int, username string) (net.PacketConn, net.Addr, error)
37+
allocateConn func(network string, requestedPort int, username string) (net.Conn, net.Addr, error)
3838
permissionHandler func(sourceAddr net.Addr, peerIP net.IP) bool
3939
}
4040

@@ -86,7 +86,7 @@ func (m *Manager) Close() error {
8686
}
8787

8888
// CreateAllocation creates a new allocation and starts relaying
89-
func (m *Manager) CreateAllocation(fiveTuple *FiveTuple, turnSocket net.PacketConn, requestedPort int, lifetime time.Duration) (*Allocation, error) {
89+
func (m *Manager) CreateAllocation(fiveTuple *FiveTuple, turnSocket net.PacketConn, requestedPort int, lifetime time.Duration, username string) (*Allocation, error) {
9090
switch {
9191
case fiveTuple == nil:
9292
return nil, errNilFiveTuple
@@ -105,7 +105,7 @@ func (m *Manager) CreateAllocation(fiveTuple *FiveTuple, turnSocket net.PacketCo
105105
}
106106
a := NewAllocation(turnSocket, fiveTuple, m.log)
107107

108-
conn, relayAddr, err := m.allocatePacketConn("udp4", requestedPort)
108+
conn, relayAddr, err := m.allocatePacketConn("udp4", requestedPort, username)
109109
if err != nil {
110110
return nil, err
111111
}
@@ -180,9 +180,13 @@ func (m *Manager) GetReservation(reservationToken string) (int, bool) {
180180
}
181181

182182
// GetRandomEvenPort returns a random un-allocated udp4 port
183-
func (m *Manager) GetRandomEvenPort() (int, error) {
183+
func (m *Manager) GetRandomEvenPort(username string) (int, error) {
184184
for i := 0; i < 128; i++ {
185-
conn, addr, err := m.allocatePacketConn("udp4", 0)
185+
conn, addr, err := m.allocatePacketConn("udp4", 0, username)
186+
if err != nil {
187+
return 0, err
188+
}
189+
186190
if err != nil {
187191
return 0, err
188192
}

internal/allocation/allocation_manager_test.go

+37-30
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
package allocation
88

99
import (
10+
"errors"
1011
"io"
1112
"math/rand"
1213
"net"
@@ -19,10 +20,12 @@ import (
1920
"github.com/stretchr/testify/assert"
2021
)
2122

23+
var errUnexpectedTestUsername = errors.New("unexpected user name")
24+
2225
func TestManager(t *testing.T) {
2326
tt := []struct {
2427
name string
25-
f func(*testing.T, net.PacketConn)
28+
f func(*testing.T, net.PacketConn, string)
2629
}{
2730
{"CreateInvalidAllocation", subTestCreateInvalidAllocation},
2831
{"CreateAllocation", subTestCreateAllocation},
@@ -42,34 +45,34 @@ func TestManager(t *testing.T) {
4245
for _, tc := range tt {
4346
f := tc.f
4447
t.Run(tc.name, func(t *testing.T) {
45-
f(t, turnSocket)
48+
f(t, turnSocket, "test_user_1")
4649
})
4750
}
4851
}
4952

5053
// Test invalid Allocation creations
51-
func subTestCreateInvalidAllocation(t *testing.T, turnSocket net.PacketConn) {
52-
m, err := newTestManager()
54+
func subTestCreateInvalidAllocation(t *testing.T, turnSocket net.PacketConn, username string) {
55+
m, err := newTestManager(username)
5356
assert.NoError(t, err)
5457

55-
if a, err := m.CreateAllocation(nil, turnSocket, 0, proto.DefaultLifetime); a != nil || err == nil {
58+
if a, err := m.CreateAllocation(nil, turnSocket, 0, proto.DefaultLifetime, username); a != nil || err == nil {
5659
t.Errorf("Illegally created allocation with nil FiveTuple")
5760
}
58-
if a, err := m.CreateAllocation(randomFiveTuple(), nil, 0, proto.DefaultLifetime); a != nil || err == nil {
61+
if a, err := m.CreateAllocation(randomFiveTuple(), nil, 0, proto.DefaultLifetime, username); a != nil || err == nil {
5962
t.Errorf("Illegally created allocation with nil turnSocket")
6063
}
61-
if a, err := m.CreateAllocation(randomFiveTuple(), turnSocket, 0, 0); a != nil || err == nil {
64+
if a, err := m.CreateAllocation(randomFiveTuple(), turnSocket, 0, 0, username); a != nil || err == nil {
6265
t.Errorf("Illegally created allocation with 0 lifetime")
6366
}
6467
}
6568

6669
// Test valid Allocation creations
67-
func subTestCreateAllocation(t *testing.T, turnSocket net.PacketConn) {
68-
m, err := newTestManager()
70+
func subTestCreateAllocation(t *testing.T, turnSocket net.PacketConn, username string) {
71+
m, err := newTestManager(username)
6972
assert.NoError(t, err)
7073

7174
fiveTuple := randomFiveTuple()
72-
if a, err := m.CreateAllocation(fiveTuple, turnSocket, 0, proto.DefaultLifetime); a == nil || err != nil {
75+
if a, err := m.CreateAllocation(fiveTuple, turnSocket, 0, proto.DefaultLifetime, username); a == nil || err != nil {
7376
t.Errorf("Failed to create allocation %v %v", a, err)
7477
}
7578

@@ -79,26 +82,26 @@ func subTestCreateAllocation(t *testing.T, turnSocket net.PacketConn) {
7982
}
8083

8184
// Test that two allocations can't be created with the same FiveTuple
82-
func subTestCreateAllocationDuplicateFiveTuple(t *testing.T, turnSocket net.PacketConn) {
83-
m, err := newTestManager()
85+
func subTestCreateAllocationDuplicateFiveTuple(t *testing.T, turnSocket net.PacketConn, username string) {
86+
m, err := newTestManager(username)
8487
assert.NoError(t, err)
8588

8689
fiveTuple := randomFiveTuple()
87-
if a, err := m.CreateAllocation(fiveTuple, turnSocket, 0, proto.DefaultLifetime); a == nil || err != nil {
90+
if a, err := m.CreateAllocation(fiveTuple, turnSocket, 0, proto.DefaultLifetime, username); a == nil || err != nil {
8891
t.Errorf("Failed to create allocation %v %v", a, err)
8992
}
9093

91-
if a, err := m.CreateAllocation(fiveTuple, turnSocket, 0, proto.DefaultLifetime); a != nil || err == nil {
94+
if a, err := m.CreateAllocation(fiveTuple, turnSocket, 0, proto.DefaultLifetime, username); a != nil || err == nil {
9295
t.Errorf("Was able to create allocation with same FiveTuple twice")
9396
}
9497
}
9598

96-
func subTestDeleteAllocation(t *testing.T, turnSocket net.PacketConn) {
97-
m, err := newTestManager()
99+
func subTestDeleteAllocation(t *testing.T, turnSocket net.PacketConn, username string) {
100+
m, err := newTestManager(username)
98101
assert.NoError(t, err)
99102

100103
fiveTuple := randomFiveTuple()
101-
if a, err := m.CreateAllocation(fiveTuple, turnSocket, 0, proto.DefaultLifetime); a == nil || err != nil {
104+
if a, err := m.CreateAllocation(fiveTuple, turnSocket, 0, proto.DefaultLifetime, username); a == nil || err != nil {
102105
t.Errorf("Failed to create allocation %v %v", a, err)
103106
}
104107

@@ -113,8 +116,8 @@ func subTestDeleteAllocation(t *testing.T, turnSocket net.PacketConn) {
113116
}
114117

115118
// Test that allocation should be closed if timeout
116-
func subTestAllocationTimeout(t *testing.T, turnSocket net.PacketConn) {
117-
m, err := newTestManager()
119+
func subTestAllocationTimeout(t *testing.T, turnSocket net.PacketConn, username string) {
120+
m, err := newTestManager(username)
118121
assert.NoError(t, err)
119122

120123
allocations := make([]*Allocation, 5)
@@ -123,7 +126,7 @@ func subTestAllocationTimeout(t *testing.T, turnSocket net.PacketConn) {
123126
for index := range allocations {
124127
fiveTuple := randomFiveTuple()
125128

126-
a, err := m.CreateAllocation(fiveTuple, turnSocket, 0, lifetime)
129+
a, err := m.CreateAllocation(fiveTuple, turnSocket, 0, lifetime, username)
127130
if err != nil {
128131
t.Errorf("Failed to create allocation with %v", fiveTuple)
129132
}
@@ -141,15 +144,15 @@ func subTestAllocationTimeout(t *testing.T, turnSocket net.PacketConn) {
141144
}
142145

143146
// Test for manager close
144-
func subTestManagerClose(t *testing.T, turnSocket net.PacketConn) {
145-
m, err := newTestManager()
147+
func subTestManagerClose(t *testing.T, turnSocket net.PacketConn, username string) {
148+
m, err := newTestManager(username)
146149
assert.NoError(t, err)
147150

148151
allocations := make([]*Allocation, 2)
149152

150-
a1, _ := m.CreateAllocation(randomFiveTuple(), turnSocket, 0, time.Second)
153+
a1, _ := m.CreateAllocation(randomFiveTuple(), turnSocket, 0, time.Second, username)
151154
allocations[0] = a1
152-
a2, _ := m.CreateAllocation(randomFiveTuple(), turnSocket, 0, time.Minute)
155+
a2, _ := m.CreateAllocation(randomFiveTuple(), turnSocket, 0, time.Minute, username)
153156
allocations[1] = a2
154157

155158
// Make a1 timeout
@@ -174,21 +177,25 @@ func randomFiveTuple() *FiveTuple {
174177
}
175178
}
176179

177-
func newTestManager() (*Manager, error) {
180+
func newTestManager(expectedUsername string) (*Manager, error) {
178181
loggerFactory := logging.NewDefaultLoggerFactory()
179182

180183
config := ManagerConfig{
181184
LeveledLogger: loggerFactory.NewLogger("test"),
182-
AllocatePacketConn: func(string, int) (net.PacketConn, net.Addr, error) {
185+
AllocatePacketConn: func(_ string, _ int, username string) (net.PacketConn, net.Addr, error) {
186+
if username != expectedUsername {
187+
return nil, nil, errUnexpectedTestUsername
188+
}
183189
conn, err := net.ListenPacket("udp4", "0.0.0.0:0")
184190
if err != nil {
185191
return nil, nil, err
186192
}
187193

188194
return conn, conn.LocalAddr(), nil
189195
},
190-
AllocateConn: func(string, int) (net.Conn, net.Addr, error) { return nil, nil, nil },
196+
AllocateConn: func(string, int, string) (net.Conn, net.Addr, error) { return nil, nil, nil },
191197
}
198+
192199
return NewManager(config)
193200
}
194201

@@ -197,11 +204,11 @@ func isClose(conn io.Closer) bool {
197204
return closeErr != nil && strings.Contains(closeErr.Error(), "use of closed network connection")
198205
}
199206

200-
func subTestGetRandomEvenPort(t *testing.T, _ net.PacketConn) {
201-
m, err := newTestManager()
207+
func subTestGetRandomEvenPort(t *testing.T, _ net.PacketConn, username string) {
208+
m, err := newTestManager(username)
202209
assert.NoError(t, err)
203210

204-
port, err := m.GetRandomEvenPort()
211+
port, err := m.GetRandomEvenPort(username)
205212
assert.NoError(t, err)
206213
assert.True(t, port > 0)
207214
assert.True(t, port%2 == 0)

internal/allocation/allocation_test.go

+6-3
Original file line numberDiff line numberDiff line change
@@ -259,9 +259,12 @@ func subTestAllocationClose(t *testing.T) {
259259
}
260260

261261
func subTestPacketHandler(t *testing.T) {
262-
network := "udp"
262+
const (
263+
network = "udp"
264+
testUsername = "test_user_2"
265+
)
263266

264-
m, _ := newTestManager()
267+
m, _ := newTestManager(testUsername)
265268

266269
// TURN server initialization
267270
turnSocket, err := net.ListenPacket(network, "127.0.0.1:0")
@@ -292,7 +295,7 @@ func subTestPacketHandler(t *testing.T) {
292295
a, err := m.CreateAllocation(&FiveTuple{
293296
SrcAddr: clientListener.LocalAddr(),
294297
DstAddr: turnSocket.LocalAddr(),
295-
}, turnSocket, 0, proto.DefaultLifetime)
298+
}, turnSocket, 0, proto.DefaultLifetime, testUsername)
296299

297300
assert.Nil(t, err, "should succeed")
298301

internal/server/turn.go

+16-15
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ func handleAllocateRequest(r Request, m *stun.Message) error {
2525
// mechanism of [https://tools.ietf.org/html/rfc5389#section-10.2.2]
2626
// unless the client and server agree to use another mechanism through
2727
// some procedure outside the scope of this document.
28-
messageIntegrity, hasAuth, err := authenticateRequest(r, m, stun.MethodAllocate)
29-
if !hasAuth {
28+
authResult, err := authenticateRequest(r, m, stun.MethodAllocate)
29+
if !authResult.hasAuth {
3030
return err
3131
}
3232

@@ -51,7 +51,7 @@ func handleAllocateRequest(r Request, m *stun.Message) error {
5151
return buildAndSendErr(r.Conn, r.SrcAddr, errRelayAlreadyAllocatedForFiveTuple, msg...)
5252
}
5353
// A retry allocation
54-
msg := buildMsg(m.TransactionID, stun.NewType(stun.MethodAllocate, stun.ClassSuccessResponse), append(attrs, messageIntegrity)...)
54+
msg := buildMsg(m.TransactionID, stun.NewType(stun.MethodAllocate, stun.ClassSuccessResponse), append(attrs, authResult.messageIntegrity)...)
5555
return buildAndSend(r.Conn, r.SrcAddr, msg...)
5656
}
5757

@@ -104,7 +104,7 @@ func handleAllocateRequest(r Request, m *stun.Message) error {
104104
var evenPort proto.EvenPort
105105
if err = evenPort.GetFrom(m); err == nil {
106106
var randomPort int
107-
randomPort, err = r.AllocationManager.GetRandomEvenPort()
107+
randomPort, err = r.AllocationManager.GetRandomEvenPort(authResult.username)
108108
if err != nil {
109109
return buildAndSendErr(r.Conn, r.SrcAddr, err, insufficientCapacityMsg...)
110110
}
@@ -131,7 +131,8 @@ func handleAllocateRequest(r Request, m *stun.Message) error {
131131
fiveTuple,
132132
r.Conn,
133133
requestedPort,
134-
lifetimeDuration)
134+
lifetimeDuration,
135+
authResult.username)
135136
if err != nil {
136137
return buildAndSendErr(r.Conn, r.SrcAddr, err, insufficientCapacityMsg...)
137138
}
@@ -177,16 +178,16 @@ func handleAllocateRequest(r Request, m *stun.Message) error {
177178
responseAttrs = append(responseAttrs, proto.ReservationToken([]byte(reservationToken)))
178179
}
179180

180-
msg := buildMsg(m.TransactionID, stun.NewType(stun.MethodAllocate, stun.ClassSuccessResponse), append(responseAttrs, messageIntegrity)...)
181+
msg := buildMsg(m.TransactionID, stun.NewType(stun.MethodAllocate, stun.ClassSuccessResponse), append(responseAttrs, authResult.messageIntegrity)...)
181182
a.SetResponseCache(m.TransactionID, responseAttrs)
182183
return buildAndSend(r.Conn, r.SrcAddr, msg...)
183184
}
184185

185186
func handleRefreshRequest(r Request, m *stun.Message) error {
186187
r.Log.Debugf("Received RefreshRequest from %s", r.SrcAddr)
187188

188-
messageIntegrity, hasAuth, err := authenticateRequest(r, m, stun.MethodRefresh)
189-
if !hasAuth {
189+
authResult, err := authenticateRequest(r, m, stun.MethodRefresh)
190+
if !authResult.hasAuth {
190191
return err
191192
}
192193

@@ -212,7 +213,7 @@ func handleRefreshRequest(r Request, m *stun.Message) error {
212213
&proto.Lifetime{
213214
Duration: lifetimeDuration,
214215
},
215-
messageIntegrity,
216+
authResult.messageIntegrity,
216217
}...)...)
217218
}
218219

@@ -228,8 +229,8 @@ func handleCreatePermissionRequest(r Request, m *stun.Message) error {
228229
return fmt.Errorf("%w %v:%v", errNoAllocationFound, r.SrcAddr, r.Conn.LocalAddr())
229230
}
230231

231-
messageIntegrity, hasAuth, err := authenticateRequest(r, m, stun.MethodCreatePermission)
232-
if !hasAuth {
232+
authResult, err := authenticateRequest(r, m, stun.MethodCreatePermission)
233+
if !authResult.hasAuth {
233234
return err
234235
}
235236

@@ -267,7 +268,7 @@ func handleCreatePermissionRequest(r Request, m *stun.Message) error {
267268
respClass = stun.ClassErrorResponse
268269
}
269270

270-
return buildAndSend(r.Conn, r.SrcAddr, buildMsg(m.TransactionID, stun.NewType(stun.MethodCreatePermission, respClass), []stun.Setter{messageIntegrity}...)...)
271+
return buildAndSend(r.Conn, r.SrcAddr, buildMsg(m.TransactionID, stun.NewType(stun.MethodCreatePermission, respClass), []stun.Setter{authResult.messageIntegrity}...)...)
271272
}
272273

273274
func handleSendIndication(r Request, m *stun.Message) error {
@@ -317,8 +318,8 @@ func handleChannelBindRequest(r Request, m *stun.Message) error {
317318

318319
badRequestMsg := buildMsg(m.TransactionID, stun.NewType(stun.MethodChannelBind, stun.ClassErrorResponse), &stun.ErrorCodeAttribute{Code: stun.CodeBadRequest})
319320

320-
messageIntegrity, hasAuth, err := authenticateRequest(r, m, stun.MethodChannelBind)
321-
if !hasAuth {
321+
authResult, err := authenticateRequest(r, m, stun.MethodChannelBind)
322+
if !authResult.hasAuth {
322323
return err
323324
}
324325

@@ -351,7 +352,7 @@ func handleChannelBindRequest(r Request, m *stun.Message) error {
351352
return buildAndSendErr(r.Conn, r.SrcAddr, err, badRequestMsg...)
352353
}
353354

354-
return buildAndSend(r.Conn, r.SrcAddr, buildMsg(m.TransactionID, stun.NewType(stun.MethodChannelBind, stun.ClassSuccessResponse), []stun.Setter{messageIntegrity}...)...)
355+
return buildAndSend(r.Conn, r.SrcAddr, buildMsg(m.TransactionID, stun.NewType(stun.MethodChannelBind, stun.ClassSuccessResponse), []stun.Setter{authResult.messageIntegrity}...)...)
355356
}
356357

357358
func handleChannelData(r Request, c *proto.ChannelData) error {

internal/server/turn_test.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -64,15 +64,15 @@ func TestAllocationLifeTime(t *testing.T) {
6464
logger := logging.NewDefaultLoggerFactory().NewLogger("turn")
6565

6666
allocationManager, err := allocation.NewManager(allocation.ManagerConfig{
67-
AllocatePacketConn: func(network string, _ int) (net.PacketConn, net.Addr, error) {
67+
AllocatePacketConn: func(network string, _ int, _ string) (net.PacketConn, net.Addr, error) {
6868
conn, listenErr := net.ListenPacket(network, "0.0.0.0:0")
6969
if err != nil {
7070
return nil, nil, listenErr
7171
}
7272

7373
return conn, conn.LocalAddr(), nil
7474
},
75-
AllocateConn: func(string, int) (net.Conn, net.Addr, error) {
75+
AllocateConn: func(string, int, string) (net.Conn, net.Addr, error) {
7676
return nil, nil, nil
7777
},
7878
LeveledLogger: logger,
@@ -97,7 +97,7 @@ func TestAllocationLifeTime(t *testing.T) {
9797

9898
fiveTuple := &allocation.FiveTuple{SrcAddr: r.SrcAddr, DstAddr: r.Conn.LocalAddr(), Protocol: allocation.UDP}
9999

100-
_, err = r.AllocationManager.CreateAllocation(fiveTuple, r.Conn, 0, time.Hour)
100+
_, err = r.AllocationManager.CreateAllocation(fiveTuple, r.Conn, 0, time.Hour, "")
101101
assert.NoError(t, err)
102102

103103
assert.NotNil(t, r.AllocationManager.GetAllocation(fiveTuple))

0 commit comments

Comments
 (0)