diff --git a/config/config.go b/config/config.go index 2d7e4e05..134743b8 100644 --- a/config/config.go +++ b/config/config.go @@ -4,6 +4,7 @@ import ( "crypto/rand" "errors" "fmt" + "net" "os" "path/filepath" "regexp" @@ -63,6 +64,9 @@ type Config struct { TurnIPProvider ipdns.Provider `ignored:"true"` TurnPort string `ignored:"true"` + TurnDenyPeers []string `default:"0.0.0.0/8,127.0.0.1/8,::/128,::1/128,fe80::/10" split_words:"true"` + TurnDenyPeersParsed []*net.IPNet `ignored:"true"` + CloseRoomWhenOwnerLeaves bool `default:"true" split_words:"true"` } @@ -218,6 +222,22 @@ func Get() (Config, []FutureLog) { } logs = append(logs, logDeprecated()...) + for _, cidrString := range config.TurnDenyPeers { + _, cidr, err := net.ParseCIDR(cidrString) + if err != nil { + logs = append(logs, FutureLog{ + Level: zerolog.FatalLevel, + Msg: fmt.Sprintf("Invalid SCREEGO_TURN_DENY_PEERS %q: %s", cidrString, err), + }) + } else { + config.TurnDenyPeersParsed = append(config.TurnDenyPeersParsed, cidr) + } + } + logs = append(logs, FutureLog{ + Level: zerolog.InfoLevel, + Msg: fmt.Sprintf("Deny turn peers within %q", config.TurnDenyPeersParsed), + }) + return config, logs } diff --git a/screego.config.development b/screego.config.development index b49c8c56..9c5a9d4e 100644 --- a/screego.config.development +++ b/screego.config.development @@ -2,3 +2,4 @@ SCREEGO_SECRET=secure SCREEGO_LOG_LEVEL=debug SCREEGO_CORS_ALLOWED_ORIGINS=http://localhost:3000 SCREEGO_USERS_FILE=./users +SCREEGO_TURN_DENY_PEERS= diff --git a/screego.config.example b/screego.config.example index 136580ba..4040bf4e 100644 --- a/screego.config.example +++ b/screego.config.example @@ -60,6 +60,16 @@ SCREEGO_TURN_EXTERNAL_PORT=3478 # Authentication secret for the external TURN server. SCREEGO_TURN_EXTERNAL_SECRET= +# Deny/ban peers within specific CIDRs to prevent TURN server users from +# accessing machines reachable by the TURN server but not from the internet, +# useful when the server is behind a NAT. +# +# Disallow internal ip addresses: https://en.wikipedia.org/wiki/Reserved_IP_addresses +# SCREEGO_TURN_DENY_PEERS=0.0.0.0/8,10.0.0.0/8,100.64.0.0/10,127.0.0.1/8,169.254.0.0/16,172.16.0.0/12,192.0.0.0/24,192.0.2.0/24,192.88.99.0/24,192.168.0.0/16,198.18.0.0/15,198.51.100.0/24,203.0.113.0/24,224.0.0.0/4,239.0.0.0/8,255.255.255.255/32,::/128,::1/128,64:ff9b:1::/48,100::/64,2001::/32,2002::/16,fc00::/7,fe80::/10 +# +# By default denies local addresses. +SCREEGO_TURN_DENY_PEERS=0.0.0.0/8,127.0.0.1/8,::/128,::1/128,fe80::/10 + # 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. diff --git a/turn/server.go b/turn/server.go index 3edbfc6d..9d78e2a9 100644 --- a/turn/server.go +++ b/turn/server.go @@ -98,14 +98,24 @@ func newInternalServer(conf config.Config) (Server, error) { IPProvider: conf.TurnIPProvider, } + var permissions turn.PermissionHandler = func(clientAddr net.Addr, peerIP net.IP) bool { + for _, cidr := range conf.TurnDenyPeersParsed { + if cidr.Contains(peerIP) { + return false + } + } + + return true + } + _, err = turn.NewServer(turn.ServerConfig{ Realm: Realm, AuthHandler: svr.authenticate, ListenerConfigs: []turn.ListenerConfig{ - {Listener: tcpListener, RelayAddressGenerator: gen}, + {Listener: tcpListener, RelayAddressGenerator: gen, PermissionHandler: permissions}, }, PacketConnConfigs: []turn.PacketConnConfig{ - {PacketConn: udpListener, RelayAddressGenerator: gen}, + {PacketConn: udpListener, RelayAddressGenerator: gen, PermissionHandler: permissions}, }, }) if err != nil {