diff --git a/cmd/server/commands.go b/cmd/server/commands.go index bcfcdde54..73ff60f61 100644 --- a/cmd/server/commands.go +++ b/cmd/server/commands.go @@ -3,7 +3,6 @@ package main import ( "fmt" "os" - "strconv" "time" "github.com/livekit/protocol/auth" @@ -40,7 +39,12 @@ func printPorts(c *cli.Context) error { } if conf.TURN.Enabled { - tcpPorts = append(tcpPorts, strconv.Itoa(conf.TURN.TLSPort)) + if conf.TURN.TLSPort > 0 { + tcpPorts = append(tcpPorts, fmt.Sprintf("%d - TURN/TLS", conf.TURN.TLSPort)) + } + if conf.TURN.UDPPort > 0 { + udpPorts = append(udpPorts, fmt.Sprintf("%d - TURN/UDP", conf.TURN.UDPPort)) + } } fmt.Println("TCP Ports") diff --git a/config-sample.yaml b/config-sample.yaml index 17337d0cc..7b1ed90d5 100644 --- a/config-sample.yaml +++ b/config-sample.yaml @@ -95,10 +95,12 @@ keys: # # - using cert_file and key_file below # # defaults to false # enabled: false -# # needs to match tls cert domain -# domain: turn.myhost.com +# # defaults to 3478 - recommended to 443 if not running HTTP3/QUIC server +# udp_port: 3478 # # defaults to 3478 - if not using a load balancer, this must be set to 443 # tls_port: 3478 +# # needs to match tls cert domain +# domain: turn.myhost.com # # optional # # cert_file: /path/to/cert.pem # # key_file: /path/to/key.pem diff --git a/pkg/config/config.go b/pkg/config/config.go index 8bdb86959..881fdbdbe 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -91,6 +91,7 @@ type TURNConfig struct { CertFile string `yaml:"cert_file"` KeyFile string `yaml:"key_file"` TLSPort int `yaml:"tls_port"` + UDPPort int `yaml:"udp_port"` } func NewConfig(confString string, c *cli.Context) (*Config, error) { @@ -135,6 +136,7 @@ func NewConfig(confString string, c *cli.Context) (*Config, error) { TURN: TURNConfig{ Enabled: false, TLSPort: 3478, + UDPPort: 3478, }, Keys: map[string]string{}, } diff --git a/pkg/config/ip.go b/pkg/config/ip.go index 4102a21ac..c95f80a00 100644 --- a/pkg/config/ip.go +++ b/pkg/config/ip.go @@ -41,12 +41,15 @@ func GetLocalIPAddress() (string, error) { var ip net.IP switch v := addr.(type) { case *net.IPNet: - ip = v.IP + ip = v.IP.To4() case *net.IPAddr: - ip = v.IP + ip = v.IP.To4() default: continue } + if ip == nil { + continue + } if ip.IsLoopback() { loopBack = ip.String() } else { diff --git a/pkg/service/roommanager.go b/pkg/service/roommanager.go index ce5c1cd0b..cf94d3c26 100644 --- a/pkg/service/roommanager.go +++ b/pkg/service/roommanager.go @@ -513,11 +513,20 @@ func (r *RoomManager) iceServersForRoom(ri *livekit.Room) []*livekit.ICEServer { }) } if r.config.TURN.Enabled { - iceServers = append(iceServers, &livekit.ICEServer{ - Urls: []string{fmt.Sprintf("turns:%s:443?transport=tcp", r.config.TURN.Domain)}, - Username: ri.Name, - Credential: ri.TurnPassword, - }) + var urls []string + if r.config.TURN.UDPPort > 0 { + urls = append(urls, fmt.Sprintf("turn:%s:%d?transport=udp", r.config.RTC.NodeIP, r.config.TURN.UDPPort)) + } + if r.config.TURN.TLSPort > 0 { + urls = append(urls, fmt.Sprintf("turns:%s:443?transport=tcp", r.config.TURN.Domain)) + } + if len(urls) > 0 { + iceServers = append(iceServers, &livekit.ICEServer{ + Urls: urls, + Username: ri.Name, + Credential: ri.TurnPassword, + }) + } } return iceServers } diff --git a/pkg/service/turn.go b/pkg/service/turn.go index 2bea3b548..28a38e905 100644 --- a/pkg/service/turn.go +++ b/pkg/service/turn.go @@ -25,46 +25,67 @@ func NewTurnServer(conf *config.Config, roomStore RoomStore, node routing.LocalN if !turnConf.Enabled { return nil, nil } - if turnConf.Domain == "" { - return nil, errors.New("TURN domain required") - } - if turnConf.TLSPort == 0 { - return nil, errors.New("invalid TURN tcp port") - } - 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 turnConf.TLSPort == 0 && turnConf.UDPPort == 0 { + return nil, errors.New("invalid TURN ports") } serverConfig := turn.ServerConfig{ Realm: livekitRealm, AuthHandler: newTurnAuthHandler(roomStore), LoggerFactory: logger.LoggerFactory(), - ListenerConfigs: []turn.ListenerConfig{ - { - Listener: tlsListener, - RelayAddressGenerator: &turn.RelayAddressGeneratorPortRange{ - RelayAddress: net.ParseIP(node.Ip), - Address: "0.0.0.0", - MinPort: turnMinPort, - MaxPort: turnMaxPort, - MaxRetries: allocateRetries, - }, - }, - }, + } + relayAddrGen := &turn.RelayAddressGeneratorPortRange{ + RelayAddress: net.ParseIP(node.Ip), + Address: "0.0.0.0", + MinPort: turnMinPort, + MaxPort: turnMaxPort, + MaxRetries: allocateRetries, + } + var logValues []interface{} + + if turnConf.TLSPort > 0 { + if turnConf.Domain == "" { + return nil, errors.New("TURN domain required") + } + + 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") + } + + listenerConfig := turn.ListenerConfig{ + Listener: tlsListener, + RelayAddressGenerator: relayAddrGen, + } + serverConfig.ListenerConfigs = append(serverConfig.ListenerConfigs, listenerConfig) + logValues = append(logValues, "turn.portTLS", turnConf.TLSPort) } - logger.Infow("Starting TURN server", - "TLS port", turnConf.TLSPort) + 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") + } + + packetConfig := turn.PacketConnConfig{ + PacketConn: udpListener, + RelayAddressGenerator: relayAddrGen, + } + serverConfig.PacketConnConfigs = append(serverConfig.PacketConnConfigs, packetConfig) + logValues = append(logValues, "turn.portUDP", turnConf.UDPPort) + } + + logger.Infow("Starting TURN server", logValues...) return turn.NewServer(serverConfig) }