Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b081562

Browse files
committed
Log TURN remote address
1 parent 859ec70 commit b081562

File tree

6 files changed

+79
-49
lines changed

6 files changed

+79
-49
lines changed

.github/workflows/coder.yaml

-4
Original file line numberDiff line numberDiff line change
@@ -163,10 +163,6 @@ jobs:
163163
terraform_version: 1.1.2
164164
terraform_wrapper: false
165165

166-
- name: Install socat
167-
if: runner.os == 'Linux'
168-
run: sudo apt-get install -y socat
169-
170166
- name: Test with Mock Database
171167
shell: bash
172168
env:

coderd/turnconn/turnconn.go

+62-36
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,20 @@ import (
1313
)
1414

1515
var (
16-
reservedHost = "coder"
17-
credential = "coder"
16+
// reservedAddress is a magic address that's used exclusively
17+
// for proxying via Coder. We don't proxy all TURN connections,
18+
// because that'd exclude the possibility of a customer using
19+
// their own TURN server.
20+
reservedAddress = "127.0.0.1:12345"
21+
credential = "coder"
22+
localhost = &net.TCPAddr{
23+
IP: net.IPv4(127, 0, 0, 1),
24+
}
1825

1926
// Proxy is a an ICE Server that uses a special hostname
2027
// to indicate traffic should be proxied.
2128
Proxy = webrtc.ICEServer{
22-
URLs: []string{"turns:" + reservedHost},
29+
URLs: []string{"turns:" + reservedAddress},
2330
Username: "coder",
2431
Credential: credential,
2532
}
@@ -29,14 +36,32 @@ var (
2936
// The relay address is used to broadcast the location of an accepted connection.
3037
func New(relayAddress *turn.RelayAddressGeneratorStatic) (*Server, error) {
3138
if relayAddress == nil {
32-
// Default to localhost.
39+
ip := "127.0.0.1"
40+
addrs, err := net.InterfaceAddrs()
41+
if err != nil {
42+
return nil, xerrors.Errorf("find interface addrs: %w", err)
43+
}
44+
// Try to find the localhost IP address.
45+
// It will generally be 127.0.0.1, but
46+
// search to be sure!
47+
for _, address := range addrs {
48+
ipNet, ok := address.(*net.IPNet)
49+
if !ok {
50+
continue
51+
}
52+
if !ipNet.IP.IsLoopback() {
53+
continue
54+
}
55+
ip = ipNet.IP.String()
56+
break
57+
}
3358
relayAddress = &turn.RelayAddressGeneratorStatic{
34-
RelayAddress: net.IP{127, 0, 0, 1},
35-
Address: "127.0.0.1",
59+
RelayAddress: net.ParseIP(ip),
60+
Address: ip,
3661
}
3762
}
3863
logger := logging.NewDefaultLoggerFactory()
39-
logger.DefaultLogLevel = logging.LogLevelDisabled
64+
logger.DefaultLogLevel = logging.LogLevelDebug
4065
server := &Server{
4166
conns: make(chan net.Conn, 1),
4267
closed: make(chan struct{}),
@@ -47,6 +72,8 @@ func New(relayAddress *turn.RelayAddressGeneratorStatic) (*Server, error) {
4772
var err error
4873
server.turn, err = turn.NewServer(turn.ServerConfig{
4974
AuthHandler: func(username, realm string, srcAddr net.Addr) (key []byte, ok bool) {
75+
// TURN connections require credentials. It's not important
76+
// for our use-case, because our listener is entirely in-memory.
5077
return turn.GenerateAuthKey(Proxy.Username, "", credential), true
5178
},
5279
ListenerConfigs: []turn.ListenerConfig{{
@@ -62,33 +89,6 @@ func New(relayAddress *turn.RelayAddressGeneratorStatic) (*Server, error) {
6289
return server, nil
6390
}
6491

65-
// ProxyDialer accepts a proxy function that's called when the connection
66-
// address matches the reserved host in the "Proxy" ICE server.
67-
//
68-
// This should be passed to WebRTC connections as an ICE dialer.
69-
func ProxyDialer(proxyFunc func() (c net.Conn, err error)) proxy.Dialer {
70-
return dialer(func(network, addr string) (net.Conn, error) {
71-
host, _, err := net.SplitHostPort(addr)
72-
if err != nil {
73-
return nil, err
74-
}
75-
if host != reservedHost {
76-
return proxy.Direct.Dial(network, addr)
77-
}
78-
netConn, err := proxyFunc()
79-
if err != nil {
80-
return nil, err
81-
}
82-
return &Conn{
83-
localAddress: &net.TCPAddr{
84-
IP: net.IPv4(127, 0, 0, 1),
85-
},
86-
closed: make(chan struct{}),
87-
Conn: netConn,
88-
}, nil
89-
})
90-
}
91-
9292
// Server accepts and connects TURN allocations.
9393
//
9494
// This is a thin wrapper around pion/turn that pipes
@@ -105,10 +105,14 @@ type Server struct {
105105
// Accept consumes a new connection into the TURN server.
106106
// A unique remote address must exist per-connection.
107107
// pion/turn indexes allocations based on the address.
108-
func (s *Server) Accept(nc net.Conn, remoteAddress *net.TCPAddr) *Conn {
108+
func (s *Server) Accept(nc net.Conn, remoteAddress, localAddress *net.TCPAddr) *Conn {
109+
if localAddress == nil {
110+
localAddress = localhost
111+
}
109112
conn := &Conn{
110113
Conn: nc,
111114
remoteAddress: remoteAddress,
115+
localAddress: localAddress,
112116
closed: make(chan struct{}),
113117
}
114118
s.conns <- conn
@@ -181,16 +185,38 @@ func (c *Conn) Closed() <-chan struct{} {
181185
}
182186

183187
func (c *Conn) Close() error {
188+
err := c.Conn.Close()
184189
select {
185190
case <-c.closed:
186191
default:
187192
close(c.closed)
188193
}
189-
return c.Conn.Close()
194+
return err
190195
}
191196

192197
type dialer func(network, addr string) (c net.Conn, err error)
193198

194199
func (d dialer) Dial(network, addr string) (c net.Conn, err error) {
195200
return d(network, addr)
196201
}
202+
203+
// ProxyDialer accepts a proxy function that's called when the connection
204+
// address matches the reserved host in the "Proxy" ICE server.
205+
//
206+
// This should be passed to WebRTC connections as an ICE dialer.
207+
func ProxyDialer(proxyFunc func() (c net.Conn, err error)) proxy.Dialer {
208+
return dialer(func(network, addr string) (net.Conn, error) {
209+
if addr != reservedAddress {
210+
return proxy.Direct.Dial(network, addr)
211+
}
212+
netConn, err := proxyFunc()
213+
if err != nil {
214+
return nil, err
215+
}
216+
return &Conn{
217+
localAddress: localhost,
218+
closed: make(chan struct{}),
219+
Conn: netConn,
220+
}, nil
221+
})
222+
}

coderd/turnconn/turnconn_test.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ func TestTURNConn(t *testing.T) {
3030
clientDialer, clientTURN := net.Pipe()
3131
turnServer.Accept(clientTURN, &net.TCPAddr{
3232
IP: net.IPv4(127, 0, 0, 1),
33-
Port: 1,
34-
})
33+
Port: 16000,
34+
}, nil)
3535
require.NoError(t, err)
3636
clientSettings := webrtc.SettingEngine{}
3737
clientSettings.SetNetworkTypes([]webrtc.NetworkType{webrtc.NetworkTypeTCP4, webrtc.NetworkTypeTCP6})
@@ -48,8 +48,8 @@ func TestTURNConn(t *testing.T) {
4848
serverDialer, serverTURN := net.Pipe()
4949
turnServer.Accept(serverTURN, &net.TCPAddr{
5050
IP: net.IPv4(127, 0, 0, 1),
51-
Port: 2,
52-
})
51+
Port: 16001,
52+
}, nil)
5353
require.NoError(t, err)
5454
serverSettings := webrtc.SettingEngine{}
5555
serverSettings.SetNetworkTypes([]webrtc.NetworkType{webrtc.NetworkTypeTCP4, webrtc.NetworkTypeTCP6})

coderd/workspaceagents.go

+7-1
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ func (api *api) workspaceAgentTurn(rw http.ResponseWriter, r *http.Request) {
232232
api.websocketWaitMutex.Unlock()
233233
defer api.websocketWaitGroup.Done()
234234

235+
localAddress, _ := r.Context().Value(http.LocalAddrContextKey).(*net.TCPAddr)
235236
remoteAddress := &net.TCPAddr{
236237
IP: net.ParseIP(r.RemoteAddr),
237238
}
@@ -261,11 +262,16 @@ func (api *api) workspaceAgentTurn(rw http.ResponseWriter, r *http.Request) {
261262
})
262263
return
263264
}
265+
defer func() {
266+
_ = wsConn.Close(websocket.StatusNormalClosure, "")
267+
}()
264268
netConn := websocket.NetConn(r.Context(), wsConn, websocket.MessageBinary)
269+
api.Logger.Debug(r.Context(), "accepting turn connection", slog.F("remote-address", r.RemoteAddr), slog.F("local-address", localAddress))
265270
select {
266-
case <-api.TURNServer.Accept(netConn, remoteAddress).Closed():
271+
case <-api.TURNServer.Accept(netConn, remoteAddress, localAddress).Closed():
267272
case <-r.Context().Done():
268273
}
274+
api.Logger.Debug(r.Context(), "completed turn connection", slog.F("remote-address", r.RemoteAddr), slog.F("local-address", localAddress))
269275
}
270276

271277
func convertWorkspaceAgent(dbAgent database.WorkspaceAgent, agentUpdateFrequency time.Duration) (codersdk.WorkspaceAgent, error) {

coderd/workspaceagents_test.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,9 @@ func TestWorkspaceAgentTURN(t *testing.T) {
143143
_ = agentCloser.Close()
144144
})
145145
resources := coderdtest.AwaitWorkspaceAgents(t, client, workspace.LatestBuild.ID)
146-
opts := &peer.ConnOptions{}
146+
opts := &peer.ConnOptions{
147+
Logger: slogtest.Make(t, nil).Named("client"),
148+
}
147149
// Force a TURN connection!
148150
opts.SettingEngine.SetNetworkTypes([]webrtc.NetworkType{webrtc.NetworkTypeTCP4})
149151
conn, err := client.DialWorkspaceAgent(context.Background(), resources[0].Agents[0].ID, opts)

peer/conn.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@ func newWithClientOrServer(servers []webrtc.ICEServer, client bool, opts *ConnOp
5050
}
5151

5252
opts.SettingEngine.DetachDataChannels()
53-
factory := logging.NewDefaultLoggerFactory()
54-
factory.DefaultLogLevel = logging.LogLevelDisabled
55-
opts.SettingEngine.LoggerFactory = factory
53+
logger := logging.NewDefaultLoggerFactory()
54+
logger.DefaultLogLevel = logging.LogLevelDisabled
55+
opts.SettingEngine.LoggerFactory = logger
5656
api := webrtc.NewAPI(webrtc.WithSettingEngine(opts.SettingEngine))
5757
rtc, err := api.NewPeerConnection(webrtc.Configuration{
5858
ICEServers: servers,

0 commit comments

Comments
 (0)