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

Skip to content

Commit 34ca05d

Browse files
committed
fix: Remove ICEServer proxying from client to server
This made testing simple, but enabled insecure behavior. This allows the listener to fetch ICEServers from a remote location, which will likely be coderd.
1 parent 44d83e4 commit 34ca05d

11 files changed

+129
-514
lines changed

agent/agent_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ func TestAgent(t *testing.T) {
9595
func setup(t *testing.T) proto.DRPCPeerBrokerClient {
9696
client, server := provisionersdk.TransportPipe()
9797
closer := agent.New(func(ctx context.Context) (*peerbroker.Listener, error) {
98-
return peerbroker.Listen(server, &peer.ConnOptions{
98+
return peerbroker.Listen(server, nil, &peer.ConnOptions{
9999
Logger: slogtest.Make(t, nil),
100100
})
101101
}, &agent.Options{

go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ require (
3737
github.com/hashicorp/go-version v1.4.0
3838
github.com/hashicorp/terraform-config-inspect v0.0.0-20211115214459-90acf1ca460f
3939
github.com/hashicorp/terraform-exec v0.15.0
40+
github.com/hashicorp/terraform-json v0.13.0
4041
github.com/hashicorp/terraform-plugin-sdk/v2 v2.10.1
4142
github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87
4243
github.com/justinas/nosurf v1.1.1
@@ -109,7 +110,6 @@ require (
109110
github.com/hashicorp/hcl v1.0.0 // indirect
110111
github.com/hashicorp/hcl/v2 v2.11.1 // indirect
111112
github.com/hashicorp/logutils v1.0.0 // indirect
112-
github.com/hashicorp/terraform-json v0.13.0 // indirect
113113
github.com/hashicorp/terraform-plugin-go v0.5.0 // indirect
114114
github.com/hashicorp/terraform-plugin-log v0.2.0 // indirect
115115
github.com/hashicorp/terraform-registry-address v0.0.0-20210412075316-9b2996cce896 // indirect

peerbroker/dial.go

+8-38
Original file line numberDiff line numberDiff line change
@@ -12,36 +12,6 @@ import (
1212

1313
// Dial consumes the PeerBroker gRPC connection negotiation stream to produce a WebRTC peered connection.
1414
func Dial(stream proto.DRPCPeerBroker_NegotiateConnectionClient, iceServers []webrtc.ICEServer, opts *peer.ConnOptions) (*peer.Conn, error) {
15-
// Convert WebRTC ICE servers to the protobuf type.
16-
protoIceServers := make([]*proto.WebRTCICEServer, 0, len(iceServers))
17-
for _, iceServer := range iceServers {
18-
var credentialString string
19-
if value, ok := iceServer.Credential.(string); ok {
20-
credentialString = value
21-
}
22-
protoIceServers = append(protoIceServers, &proto.WebRTCICEServer{
23-
Urls: iceServer.URLs,
24-
Username: iceServer.Username,
25-
Credential: credentialString,
26-
CredentialType: int32(iceServer.CredentialType),
27-
})
28-
}
29-
if len(protoIceServers) > 0 {
30-
// Send ICE servers to connect with.
31-
// Client sends ICE servers so clients can determine the node
32-
// servers will meet at. eg. us-west1.coder.com could be a TURN server.
33-
err := stream.Send(&proto.NegotiateConnection_ClientToServer{
34-
Message: &proto.NegotiateConnection_ClientToServer_Servers{
35-
Servers: &proto.WebRTCICEServers{
36-
Servers: protoIceServers,
37-
},
38-
},
39-
})
40-
if err != nil {
41-
return nil, xerrors.Errorf("write ice servers: %w", err)
42-
}
43-
}
44-
4515
peerConn, err := peer.Client(iceServers, opts)
4616
if err != nil {
4717
return nil, xerrors.Errorf("create peer connection: %w", err)
@@ -54,9 +24,9 @@ func Dial(stream proto.DRPCPeerBroker_NegotiateConnectionClient, iceServers []we
5424
case <-peerConn.Closed():
5525
return
5626
case sessionDescription := <-peerConn.LocalSessionDescription():
57-
err = stream.Send(&proto.NegotiateConnection_ClientToServer{
58-
Message: &proto.NegotiateConnection_ClientToServer_Offer{
59-
Offer: &proto.WebRTCSessionDescription{
27+
err = stream.Send(&proto.Exchange{
28+
Message: &proto.Exchange_Sdp{
29+
Sdp: &proto.WebRTCSessionDescription{
6030
SdpType: int32(sessionDescription.Type),
6131
Sdp: sessionDescription.SDP,
6232
},
@@ -67,8 +37,8 @@ func Dial(stream proto.DRPCPeerBroker_NegotiateConnectionClient, iceServers []we
6737
return
6838
}
6939
case iceCandidate := <-peerConn.LocalCandidate():
70-
err = stream.Send(&proto.NegotiateConnection_ClientToServer{
71-
Message: &proto.NegotiateConnection_ClientToServer_IceCandidate{
40+
err = stream.Send(&proto.Exchange{
41+
Message: &proto.Exchange_IceCandidate{
7242
IceCandidate: iceCandidate.Candidate,
7343
},
7444
})
@@ -89,10 +59,10 @@ func Dial(stream proto.DRPCPeerBroker_NegotiateConnectionClient, iceServers []we
8959
}
9060

9161
switch {
92-
case serverToClientMessage.GetAnswer() != nil:
62+
case serverToClientMessage.GetSdp() != nil:
9363
peerConn.SetRemoteSessionDescription(webrtc.SessionDescription{
94-
Type: webrtc.SDPType(serverToClientMessage.GetAnswer().SdpType),
95-
SDP: serverToClientMessage.GetAnswer().Sdp,
64+
Type: webrtc.SDPType(serverToClientMessage.GetSdp().SdpType),
65+
SDP: serverToClientMessage.GetSdp().Sdp,
9666
})
9767
case serverToClientMessage.GetIceCandidate() != "":
9868
peerConn.AddRemoteCandidate(webrtc.ICECandidateInit{

peerbroker/dial_test.go

+14-3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package peerbroker_test
33
import (
44
"context"
55
"testing"
6+
"time"
67

78
"github.com/pion/webrtc/v3"
89
"github.com/stretchr/testify/require"
@@ -31,18 +32,28 @@ func TestDial(t *testing.T) {
3132
defer client.Close()
3233
defer server.Close()
3334

34-
listener, err := peerbroker.Listen(server, &peer.ConnOptions{
35-
Logger: slogtest.Make(t, nil).Named("server").Leveled(slog.LevelDebug),
35+
settingEngine := webrtc.SettingEngine{}
36+
// Ensures candidates are exchanging via the Google STUN server, not the host network.
37+
settingEngine.SetHostAcceptanceMinWait(time.Hour)
38+
listener, err := peerbroker.Listen(server, func(ctx context.Context) ([]webrtc.ICEServer, error) {
39+
return []webrtc.ICEServer{{
40+
URLs: []string{"stun:stun.l.google.com:19302"},
41+
}}, nil
42+
}, &peer.ConnOptions{
43+
Logger: slogtest.Make(t, nil).Named("server").Leveled(slog.LevelDebug),
44+
SettingEngine: settingEngine,
3645
})
3746
require.NoError(t, err)
3847

3948
api := proto.NewDRPCPeerBrokerClient(provisionersdk.Conn(client))
4049
stream, err := api.NegotiateConnection(ctx)
4150
require.NoError(t, err)
51+
4252
clientConn, err := peerbroker.Dial(stream, []webrtc.ICEServer{{
4353
URLs: []string{"stun:stun.l.google.com:19302"},
4454
}}, &peer.ConnOptions{
45-
Logger: slogtest.Make(t, nil).Named("client").Leveled(slog.LevelDebug),
55+
Logger: slogtest.Make(t, nil).Named("client").Leveled(slog.LevelDebug),
56+
SettingEngine: settingEngine,
4657
})
4758
require.NoError(t, err)
4859
defer clientConn.Close()

peerbroker/listen.go

+24-27
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,21 @@ import (
1717
"github.com/coder/coder/peerbroker/proto"
1818
)
1919

20+
// ICEServersFunc returns ICEServers when a new connection is requested.
21+
type ICEServersFunc func(ctx context.Context) ([]webrtc.ICEServer, error)
22+
2023
// Listen consumes the transport as the server-side of the PeerBroker dRPC service.
2124
// The Accept function must be serviced, or new connections will hang.
22-
func Listen(connListener net.Listener, opts *peer.ConnOptions) (*Listener, error) {
25+
func Listen(connListener net.Listener, iceServersFunc ICEServersFunc, opts *peer.ConnOptions) (*Listener, error) {
26+
if iceServersFunc == nil {
27+
iceServersFunc = func(ctx context.Context) ([]webrtc.ICEServer, error) {
28+
return []webrtc.ICEServer{}, nil
29+
}
30+
}
2331
ctx, cancelFunc := context.WithCancel(context.Background())
2432
listener := &Listener{
2533
connectionChannel: make(chan *peer.Conn),
34+
iceServersFunc: iceServersFunc,
2635

2736
closeFunc: cancelFunc,
2837
closed: make(chan struct{}),
@@ -48,6 +57,7 @@ func Listen(connListener net.Listener, opts *peer.ConnOptions) (*Listener, error
4857

4958
type Listener struct {
5059
connectionChannel chan *peer.Conn
60+
iceServersFunc ICEServersFunc
5161

5262
closeFunc context.CancelFunc
5363
closed chan struct{}
@@ -104,8 +114,12 @@ type peerBrokerService struct {
104114

105115
// NegotiateConnection negotiates a WebRTC connection.
106116
func (b *peerBrokerService) NegotiateConnection(stream proto.DRPCPeerBroker_NegotiateConnectionStream) error {
117+
iceServers, err := b.listener.iceServersFunc(stream.Context())
118+
if err != nil {
119+
return xerrors.Errorf("get ice servers: %w", err)
120+
}
107121
// Start with no ICE servers. They can be sent by the client if provided.
108-
peerConn, err := peer.Server([]webrtc.ICEServer{}, b.connOptions)
122+
peerConn, err := peer.Server(iceServers, b.connOptions)
109123
if err != nil {
110124
return xerrors.Errorf("create peer connection: %w", err)
111125
}
@@ -121,9 +135,9 @@ func (b *peerBrokerService) NegotiateConnection(stream proto.DRPCPeerBroker_Nego
121135
case <-peerConn.Closed():
122136
return
123137
case sessionDescription := <-peerConn.LocalSessionDescription():
124-
err = stream.Send(&proto.NegotiateConnection_ServerToClient{
125-
Message: &proto.NegotiateConnection_ServerToClient_Answer{
126-
Answer: &proto.WebRTCSessionDescription{
138+
err = stream.Send(&proto.Exchange{
139+
Message: &proto.Exchange_Sdp{
140+
Sdp: &proto.WebRTCSessionDescription{
127141
SdpType: int32(sessionDescription.Type),
128142
Sdp: sessionDescription.SDP,
129143
},
@@ -134,8 +148,8 @@ func (b *peerBrokerService) NegotiateConnection(stream proto.DRPCPeerBroker_Nego
134148
return
135149
}
136150
case iceCandidate := <-peerConn.LocalCandidate():
137-
err = stream.Send(&proto.NegotiateConnection_ServerToClient{
138-
Message: &proto.NegotiateConnection_ServerToClient_IceCandidate{
151+
err = stream.Send(&proto.Exchange{
152+
Message: &proto.Exchange_IceCandidate{
139153
IceCandidate: iceCandidate.Candidate,
140154
},
141155
})
@@ -156,28 +170,11 @@ func (b *peerBrokerService) NegotiateConnection(stream proto.DRPCPeerBroker_Nego
156170
}
157171

158172
switch {
159-
case clientToServerMessage.GetOffer() != nil:
173+
case clientToServerMessage.GetSdp() != nil:
160174
peerConn.SetRemoteSessionDescription(webrtc.SessionDescription{
161-
Type: webrtc.SDPType(clientToServerMessage.GetOffer().SdpType),
162-
SDP: clientToServerMessage.GetOffer().Sdp,
175+
Type: webrtc.SDPType(clientToServerMessage.GetSdp().SdpType),
176+
SDP: clientToServerMessage.GetSdp().Sdp,
163177
})
164-
case clientToServerMessage.GetServers() != nil:
165-
// Convert protobuf ICE servers to the WebRTC type.
166-
iceServers := make([]webrtc.ICEServer, 0, len(clientToServerMessage.GetServers().Servers))
167-
for _, iceServer := range clientToServerMessage.GetServers().Servers {
168-
iceServers = append(iceServers, webrtc.ICEServer{
169-
URLs: iceServer.Urls,
170-
Username: iceServer.Username,
171-
Credential: iceServer.Credential,
172-
CredentialType: webrtc.ICECredentialType(iceServer.CredentialType),
173-
})
174-
}
175-
err = peerConn.SetConfiguration(webrtc.Configuration{
176-
ICEServers: iceServers,
177-
})
178-
if err != nil {
179-
return peerConn.CloseWithError(xerrors.Errorf("set ice configuration: %w", err))
180-
}
181178
case clientToServerMessage.GetIceCandidate() != "":
182179
peerConn.AddRemoteCandidate(webrtc.ICECandidateInit{
183180
Candidate: clientToServerMessage.GetIceCandidate(),

peerbroker/listen_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ func TestListen(t *testing.T) {
2323
defer client.Close()
2424
defer server.Close()
2525

26-
listener, err := peerbroker.Listen(server, nil)
26+
listener, err := peerbroker.Listen(server, nil, nil)
2727
require.NoError(t, err)
2828

2929
api := proto.NewDRPCPeerBrokerClient(provisionersdk.Conn(client))
@@ -43,7 +43,7 @@ func TestListen(t *testing.T) {
4343
defer client.Close()
4444
defer server.Close()
4545

46-
listener, err := peerbroker.Listen(server, nil)
46+
listener, err := peerbroker.Listen(server, nil, nil)
4747
require.NoError(t, err)
4848
go listener.Close()
4949
_, err = listener.Accept()

0 commit comments

Comments
 (0)