Skip to content

Commit

Permalink
Add TURN port range
Browse files Browse the repository at this point in the history
See #27
  • Loading branch information
jmattheis committed Oct 14, 2020
1 parent 8892186 commit 798edeb
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 21 deletions.
46 changes: 46 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ package config

import (
"crypto/rand"
"errors"
"fmt"
"net"
"os"
"path/filepath"
"regexp"
"strconv"
"strings"

"github.com/joho/godotenv"
Expand Down Expand Up @@ -44,6 +46,7 @@ type Config struct {

TurnAddress string `default:"0.0.0.0:3478" required:"true" split_words:"true"`
TurnStrictAuth bool `default:"true" split_words:"true"`
TurnPortRange string `split_words:"true"`

TrustProxyHeaders bool `split_words:"true"`
AuthMode string `default:"turn" split_words:"true"`
Expand All @@ -54,6 +57,34 @@ type Config struct {
CheckOrigin func(string) bool `ignored:"true" json:"-"`
}

func (c Config) parsePortRange() (uint16, uint16, error) {
if c.TurnPortRange == "" {
return 0, 0, nil
}

parts := strings.Split(c.TurnPortRange, ":")
if len(parts) != 2 {
return 0, 0, errors.New("must include one colon")
}
stringMin := parts[0]
stringMax := parts[1]
min64, err := strconv.ParseUint(stringMin, 10, 16)
if err != nil {
return 0, 0, fmt.Errorf("invalid min: %s", err)
}
max64, err := strconv.ParseUint(stringMax, 10, 16)
if err != nil {
return 0, 0, fmt.Errorf("invalid max: %s", err)
}

return uint16(min64), uint16(max64), nil
}

func (c Config) PortRange() (uint16, uint16, bool) {
min, max, _ := c.parsePortRange()
return min, max, min != 0 && max != 0
}

// Get loads the application config.
func Get() (Config, []FutureLog) {
var logs []FutureLog
Expand Down Expand Up @@ -143,6 +174,21 @@ func Get() (Config, []FutureLog) {
logs = append(logs, futureFatal(fmt.Sprintf("invalid SCREEGO_EXTERNAL_IP: %s", config.ExternalIP)))
}

min, max, err := config.parsePortRange()
if err != nil {
logs = append(logs, futureFatal(fmt.Sprintf("invalid SCREEGO_TURN_PORT_RANGE: %s", err)))
} else if min == 0 && max == 0 {
// valid; no port range
} else if min == 0 || max == 0 {
logs = append(logs, futureFatal("invalid SCREEGO_TURN_PORT_RANGE: min or max port is 0"))
} else if min > max {
logs = append(logs, futureFatal(fmt.Sprintf("invalid SCREEGO_TURN_PORT_RANGE: min port (%d) is higher than max port (%d)", min, max)))
} else if (max - min) < 40 {
logs = append(logs, FutureLog{
Level: zerolog.WarnLevel,
Msg: "Less than 40 ports are available for turn. When using multiple TURN connections this may not be enough"})
}

return config, logs
}

Expand Down
3 changes: 1 addition & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ require (
github.com/kr/pretty v0.2.0 // indirect
github.com/magiconair/properties v1.8.1
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2
github.com/pion/transport v0.10.1 // indirect
github.com/pion/turn/v2 v2.0.4
github.com/pion/turn/v2 v2.0.5
github.com/prometheus/client_golang v1.7.1
github.com/rs/xid v1.2.1
github.com/rs/zerolog v1.19.0
Expand Down
9 changes: 4 additions & 5 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -108,13 +108,14 @@ github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoU
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms=
github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA=
github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8=
github.com/pion/stun v0.3.5 h1:uLUCBCkQby4S1cf6CGuR9QrVOKcvUwFeemaC865QHDg=
github.com/pion/stun v0.3.5/go.mod h1:gDMim+47EeEtfWogA37n6qXZS88L5V6LqFcf+DZA2UA=
github.com/pion/transport v0.10.0/go.mod h1:BnHnUipd0rZQyTVB2SBGojFHT9CBt5C5TcsJSQGkvSE=
github.com/pion/transport v0.10.1 h1:2W+yJT+0mOQ160ThZYUx5Zp2skzshiNgxrNE9GUfhJM=
github.com/pion/transport v0.10.1/go.mod h1:PBis1stIILMiis0PewDw91WJeLJkyIMcEk+DwKOzf4A=
github.com/pion/turn/v2 v2.0.4 h1:oDguhEv2L/4rxwbL9clGLgtzQPjtuZwCdoM7Te8vQVk=
github.com/pion/turn/v2 v2.0.4/go.mod h1:1812p4DcGVbYVBTiraUmP50XoKye++AMkbfp+N27mog=
github.com/pion/turn/v2 v2.0.5 h1:iwMHqDfPEDEOFzwWKT56eFmh6DYC6o/+xnLAEzgISbA=
github.com/pion/turn/v2 v2.0.5/go.mod h1:APg43CFyt/14Uy7heYUOGWdkem/Wu4PhCO/bjyrTqMw=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
Expand Down Expand Up @@ -158,7 +159,6 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw=
Expand All @@ -172,7 +172,6 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
Expand Down
6 changes: 6 additions & 0 deletions screego.config.example
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ SCREEGO_SERVER_ADDRESS=0.0.0.0:5050
# The address the TURN server will listen on.
SCREEGO_TURN_ADDRESS=0.0.0.0:3478

# Limit the ports that TURN will use for data relaying.
# Format: min:max
# Example:
# 50000:55000
SCREEGO_TURN_PORT_RANGE=

# If reverse proxy headers should be trusted.
# Screego uses ip whitelisting for authentication
# of TURN connections. When behind a proxy the ip is always the proxy server.
Expand Down
47 changes: 33 additions & 14 deletions turn/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,18 @@ type Entry struct {

const Realm = "screego"

type LoggedGenerator struct {
turn.RelayAddressGenerator
}

func (r *LoggedGenerator) AllocatePacketConn(network string, requestedPort int) (net.PacketConn, net.Addr, error) {
conn, addr, err := r.RelayAddressGenerator.AllocatePacketConn(network, requestedPort)
if err == nil {
log.Debug().Str("addr", addr.String()).Str("network", network).Msg("TURN allocated")
}
return conn, addr, err
}

func Start(conf config.Config) (*Server, error) {
udpListener, err := net.ListenPacket("udp4", conf.TurnAddress)
if err != nil {
Expand All @@ -44,26 +56,16 @@ func Start(conf config.Config) (*Server, error) {
strictIPCheck: conf.TurnStrictAuth,
}

loggedGenerator := &LoggedGenerator{RelayAddressGenerator: generator(conf)}

_, err = turn.NewServer(turn.ServerConfig{
Realm: Realm,
AuthHandler: svr.authenticate,
ListenerConfigs: []turn.ListenerConfig{
{
Listener: tcpListener,
RelayAddressGenerator: &turn.RelayAddressGeneratorStatic{
RelayAddress: net.ParseIP(conf.ExternalIP),
Address: "0.0.0.0",
},
},
{Listener: tcpListener, RelayAddressGenerator: loggedGenerator},
},
PacketConnConfigs: []turn.PacketConnConfig{
{
PacketConn: udpListener,
RelayAddressGenerator: &turn.RelayAddressGeneratorStatic{
RelayAddress: net.ParseIP(conf.ExternalIP),
Address: "0.0.0.0",
},
},
{PacketConn: udpListener, RelayAddressGenerator: loggedGenerator},
},
})
if err != nil {
Expand All @@ -74,6 +76,23 @@ func Start(conf config.Config) (*Server, error) {
return svr, nil
}

func generator(conf config.Config) turn.RelayAddressGenerator {
min, max, useRange := conf.PortRange()
if useRange {
log.Debug().Uint16("min", min).Uint16("max", max).Msg("Using Port Range")
return &turn.RelayAddressGeneratorPortRange{
RelayAddress: net.ParseIP(conf.ExternalIP),
Address: "0.0.0.0",
MinPort: min,
MaxPort: max,
}
}
return &turn.RelayAddressGeneratorStatic{
RelayAddress: net.ParseIP(conf.ExternalIP),
Address: "0.0.0.0",
}
}

func (a *Server) Allow(username, password string, addr net.IP) {
a.lock.Lock()
defer a.lock.Unlock()
Expand Down

0 comments on commit 798edeb

Please sign in to comment.