Skip to content
This repository was archived by the owner on Aug 30, 2024. It is now read-only.

feat: Use internal TURN server for proxying #322

Merged
merged 3 commits into from
Apr 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion agent/stream.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,11 @@ func (s *stream) processMessage(msg proto.Message) {
}

if msg.Offer != nil {
rtc, err := xwebrtc.NewPeerConnection()
if msg.Servers == nil {
s.fatal(fmt.Errorf("servers must be sent with offer"))
return
}
rtc, err := xwebrtc.NewPeerConnection(msg.Servers)
if err != nil {
s.fatal(fmt.Errorf("create connection: %w", err))
return
Expand Down
34 changes: 24 additions & 10 deletions internal/cmd/tunnel.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
"io"
"net"
"net/url"
"os"
"strconv"
"time"
Expand Down Expand Up @@ -57,7 +58,7 @@ coder tunnel my-dev 3000 3000
}
baseURL := sdk.BaseURL()

envs, err := sdk.Environments(ctx)
envs, err := getEnvs(ctx, sdk, coder.Me)
if err != nil {
return err
}
Expand All @@ -79,8 +80,8 @@ coder tunnel my-dev 3000 3000
localPort: uint16(localPort),
remotePort: uint16(remotePort),
ctx: context.Background(),
logger: log,
brokerAddr: baseURL.String(),
logger: log.Leveled(slog.LevelDebug),
brokerAddr: baseURL,
token: sdk.Token(),
}

Expand All @@ -98,7 +99,7 @@ coder tunnel my-dev 3000 3000

type client struct {
ctx context.Context
brokerAddr string
brokerAddr url.URL
token string
logger slog.Logger
id string
Expand All @@ -108,9 +109,13 @@ type client struct {
}

func (c *client) start() error {
url := fmt.Sprintf("%s%s%s%s%s", c.brokerAddr, "/api/private/envagent/", c.id, "/connect?session_token=", c.token)
c.logger.Info(c.ctx, "connecting to broker", slog.F("url", url))

url := fmt.Sprintf("%s%s%s%s%s", c.brokerAddr.String(), "/api/private/envagent/", c.id, "/connect?session_token=", c.token)
turnScheme := "turns"
if c.brokerAddr.Scheme == "http" {
turnScheme = "turn"
}
tcpProxy := fmt.Sprintf("%s:%s:5349?transport=tcp", turnScheme, c.brokerAddr.Host)
c.logger.Info(c.ctx, "connecting to broker", slog.F("url", url), slog.F("tcp-proxy", tcpProxy))
conn, resp, err := websocket.Dial(c.ctx, url, nil)
if err != nil && resp == nil {
return fmt.Errorf("dial: %w", err)
Expand All @@ -122,7 +127,15 @@ func (c *client) start() error {
}
nconn := websocket.NetConn(context.Background(), conn, websocket.MessageBinary)

rtc, err := xwebrtc.NewPeerConnection()
// Only enabled under a private feature flag for now,
// so insecure connections are entirely fine to allow.
servers := []webrtc.ICEServer{{
URLs: []string{tcpProxy},
Username: "insecure",
Credential: "pass",
CredentialType: webrtc.ICECredentialTypePassword,
}}
rtc, err := xwebrtc.NewPeerConnection(servers)
if err != nil {
return fmt.Errorf("create connection: %w", err)
}
Expand Down Expand Up @@ -150,16 +163,17 @@ func (c *client) start() error {
if err != nil {
return fmt.Errorf("set local desc: %w", err)
}
flushCandidates()

c.logger.Debug(context.Background(), "writing offer")
b, _ := json.Marshal(&proto.Message{
Offer: &localDesc,
Offer: &localDesc,
Servers: servers,
})
_, err = nconn.Write(b)
if err != nil {
return fmt.Errorf("write offer: %w", err)
}
flushCandidates()

go func() {
err = xwebrtc.WaitForDataChannelOpen(context.Background(), channel)
Expand Down
15 changes: 8 additions & 7 deletions internal/x/xwebrtc/conn.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
package xwebrtc

import "github.com/pion/webrtc/v3"
import (
"time"

"github.com/pion/webrtc/v3"
)

// NewPeerConnection creates a new peer connection.
// It uses the Google stun server by default.
func NewPeerConnection() (*webrtc.PeerConnection, error) {
func NewPeerConnection(servers []webrtc.ICEServer) (*webrtc.PeerConnection, error) {
se := webrtc.SettingEngine{}
se.DetachDataChannels()
se.SetICETimeouts(time.Second*5, time.Second*5, time.Second*2)
api := webrtc.NewAPI(webrtc.WithSettingEngine(se))

return api.NewPeerConnection(webrtc.Configuration{
ICEServers: []webrtc.ICEServer{
{
URLs: []string{"stun:stun.l.google.com:19302"},
},
},
ICEServers: servers,
})
}
1 change: 1 addition & 0 deletions pkg/proto/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ type Message struct {
Error string `json:"error"`
Candidate string `json:"candidate"`
Offer *webrtc.SessionDescription `json:"offer"`
Servers []webrtc.ICEServer `json:"servers"`
Answer *webrtc.SessionDescription `json:"answer"`
}

Expand Down