diff --git a/pkg/config/config.go b/pkg/config/config.go index cf7814303..8b1182ea1 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -217,15 +217,16 @@ type LoggingConfig struct { } type TURNConfig struct { - Enabled bool `yaml:"enabled,omitempty"` - Domain string `yaml:"domain,omitempty"` - CertFile string `yaml:"cert_file,omitempty"` - KeyFile string `yaml:"key_file,omitempty"` - TLSPort int `yaml:"tls_port,omitempty"` - UDPPort int `yaml:"udp_port,omitempty"` - RelayPortRangeStart uint16 `yaml:"relay_range_start,omitempty"` - RelayPortRangeEnd uint16 `yaml:"relay_range_end,omitempty"` - ExternalTLS bool `yaml:"external_tls,omitempty"` + Enabled bool `yaml:"enabled,omitempty"` + Domain string `yaml:"domain,omitempty"` + CertFile string `yaml:"cert_file,omitempty"` + KeyFile string `yaml:"key_file,omitempty"` + TLSPort int `yaml:"tls_port,omitempty"` + UDPPort int `yaml:"udp_port,omitempty"` + RelayPortRangeStart uint16 `yaml:"relay_range_start,omitempty"` + RelayPortRangeEnd uint16 `yaml:"relay_range_end,omitempty"` + ExternalTLS bool `yaml:"external_tls,omitempty"` + BindAddresses []string `yaml:"bind_addresses,omitempty"` } type NodeSelectorConfig struct { @@ -418,7 +419,8 @@ var DefaultConfig = Config{ PionLevel: "error", }, TURN: TURNConfig{ - Enabled: false, + Enabled: false, + BindAddresses: []string{"0.0.0.0"}, }, NodeSelector: NodeSelectorConfig{ Kind: "any", diff --git a/pkg/service/turn.go b/pkg/service/turn.go index 1dca87040..a37091c4f 100644 --- a/pkg/service/turn.go +++ b/pkg/service/turn.go @@ -40,8 +40,6 @@ const ( LivekitRealm = "livekit" allocateRetries = 50 - turnMinPort = 1024 - turnMaxPort = 30000 ) func NewTurnServer(conf *config.Config, authHandler turn.AuthHandler, standalone bool) (*turn.Server, error) { @@ -52,32 +50,7 @@ func NewTurnServer(conf *config.Config, authHandler turn.AuthHandler, standalone if turnConf.TLSPort <= 0 && turnConf.UDPPort <= 0 { return nil, errors.New("invalid TURN ports") - } - if conf.RTC.NodeIP.V4 == "" { - return nil, errors.New("invalid node IPv4 for relay") - } - - serverConfig := turn.ServerConfig{ - Realm: LivekitRealm, - AuthHandler: authHandler, - LoggerFactory: pionlogger.NewLoggerFactory(logger.GetLogger()), - } - var relayAddrGen turn.RelayAddressGenerator = &turn.RelayAddressGeneratorPortRange{ - RelayAddress: net.ParseIP(conf.RTC.NodeIP.V4), - Address: "0.0.0.0", - MinPort: turnConf.RelayPortRangeStart, - MaxPort: turnConf.RelayPortRangeEnd, - MaxRetries: allocateRetries, - } - if standalone { - relayAddrGen = telemetry.NewRelayAddressGenerator(relayAddrGen) - } - var logValues []any - - logValues = append(logValues, "turn.relay_range_start", turnConf.RelayPortRangeStart) - logValues = append(logValues, "turn.relay_range_end", turnConf.RelayPortRangeEnd) - - if turnConf.TLSPort > 0 { + } else if turnConf.TLSPort > 0 { if turnConf.Domain == "" { return nil, errors.New("TURN domain required") } @@ -85,64 +58,92 @@ func NewTurnServer(conf *config.Config, authHandler turn.AuthHandler, standalone if !IsValidDomain(turnConf.Domain) { return nil, errors.New("TURN domain is not correct") } - - if !turnConf.ExternalTLS { - cert, err := tls.LoadX509KeyPair(turnConf.CertFile, turnConf.KeyFile) - if err != nil { - return nil, errors.Wrap(err, "TURN tls cert required") - } - - tlsListener, err := tls.Listen("tcp4", "0.0.0.0:"+strconv.Itoa(turnConf.TLSPort), - &tls.Config{ - MinVersion: tls.VersionTLS12, - Certificates: []tls.Certificate{cert}, - }) - if err != nil { - return nil, errors.Wrap(err, "could not listen on TURN TCP port") - } - if standalone { - tlsListener = telemetry.NewListener(tlsListener) - } - - listenerConfig := turn.ListenerConfig{ - Listener: tlsListener, - RelayAddressGenerator: relayAddrGen, - } - serverConfig.ListenerConfigs = append(serverConfig.ListenerConfigs, listenerConfig) - } else { - tcpListener, err := net.Listen("tcp4", "0.0.0.0:"+strconv.Itoa(turnConf.TLSPort)) - if err != nil { - return nil, errors.Wrap(err, "could not listen on TURN TCP port") - } - if standalone { - tcpListener = telemetry.NewListener(tcpListener) - } - - listenerConfig := turn.ListenerConfig{ - Listener: tcpListener, - RelayAddressGenerator: relayAddrGen, - } - serverConfig.ListenerConfigs = append(serverConfig.ListenerConfigs, listenerConfig) - } - logValues = append(logValues, "turn.portTLS", turnConf.TLSPort, "turn.externalTLS", turnConf.ExternalTLS) } - if turnConf.UDPPort > 0 { - udpListener, err := net.ListenPacket("udp4", "0.0.0.0:"+strconv.Itoa(turnConf.UDPPort)) - if err != nil { - return nil, errors.Wrap(err, "could not listen on TURN UDP port") + serverConfig := turn.ServerConfig{ + Realm: LivekitRealm, + AuthHandler: authHandler, + LoggerFactory: pionlogger.NewLoggerFactory(logger.GetLogger()), + } + + var logValues []any + logValues = append(logValues, "turn.relay_range_start", turnConf.RelayPortRangeStart) + logValues = append(logValues, "turn.relay_range_end", turnConf.RelayPortRangeEnd) + + for _, addr := range turnConf.BindAddresses { + var nodeIP string + if net.ParseIP(addr).To4() != nil { + nodeIP = conf.RTC.NodeIP.V4 + } else { + nodeIP = conf.RTC.NodeIP.V6 + } + if nodeIP == "" { + return nil, errors.New("no matching node IP for relay") } + var relayAddrGen turn.RelayAddressGenerator = &turn.RelayAddressGeneratorPortRange{ + RelayAddress: net.ParseIP(nodeIP), + Address: addr, + MinPort: turnConf.RelayPortRangeStart, + MaxPort: turnConf.RelayPortRangeEnd, + MaxRetries: allocateRetries, + } if standalone { - udpListener = telemetry.NewPacketConn(udpListener, prometheus.Incoming) + relayAddrGen = telemetry.NewRelayAddressGenerator(relayAddrGen) } - packetConfig := turn.PacketConnConfig{ - PacketConn: udpListener, - RelayAddressGenerator: relayAddrGen, + if turnConf.TLSPort > 0 { + var listener net.Listener + var listenerErr error + + if turnConf.ExternalTLS { + listener, listenerErr = net.Listen("tcp", net.JoinHostPort(addr, strconv.Itoa(turnConf.TLSPort))) + } else { + cert, err := tls.LoadX509KeyPair(turnConf.CertFile, turnConf.KeyFile) + if err != nil { + return nil, errors.Wrap(err, "TURN tls cert required") + } + + listener, listenerErr = tls.Listen("tcp", net.JoinHostPort(addr, strconv.Itoa(turnConf.TLSPort)), + &tls.Config{ + MinVersion: tls.VersionTLS12, + Certificates: []tls.Certificate{cert}, + }) + } + + if listenerErr != nil { + return nil, errors.Wrap(listenerErr, "could not listen on TURN TCP port") + } + if standalone { + listener = telemetry.NewListener(listener) + } + + listenerConfig := turn.ListenerConfig{ + Listener: listener, + RelayAddressGenerator: relayAddrGen, + } + serverConfig.ListenerConfigs = append(serverConfig.ListenerConfigs, listenerConfig) + + logValues = append(logValues, "turn.portTLS", turnConf.TLSPort, "turn.externalTLS", turnConf.ExternalTLS) + } + + if turnConf.UDPPort > 0 { + udpListener, err := net.ListenPacket("udp", net.JoinHostPort(addr, strconv.Itoa(turnConf.UDPPort))) + if err != nil { + return nil, errors.Wrap(err, "could not listen on TURN UDP port") + } + + if standalone { + udpListener = telemetry.NewPacketConn(udpListener, prometheus.Incoming) + } + + packetConfig := turn.PacketConnConfig{ + PacketConn: udpListener, + RelayAddressGenerator: relayAddrGen, + } + serverConfig.PacketConnConfigs = append(serverConfig.PacketConnConfigs, packetConfig) + logValues = append(logValues, "turn.portUDP", turnConf.UDPPort) } - serverConfig.PacketConnConfigs = append(serverConfig.PacketConnConfigs, packetConfig) - logValues = append(logValues, "turn.portUDP", turnConf.UDPPort) } logger.Infow("Starting TURN server", logValues...)