diff --git a/config/config.sample.toml b/config/config.sample.toml index c736b36..6be3a82 100644 --- a/config/config.sample.toml +++ b/config/config.sample.toml @@ -52,6 +52,16 @@ enable_ipv6 = false # For more advanced usage this value can also be a comma separated list of # NAT mappings in the form of "external IP / internal IP" pairs, e.g. "8.8.8.8/10.0.2.2,8.8.4.4/10.0.2.1". ice_host_override = "" + +# An optional port number to be used as an override for host candidates in +# place of the one used to listen on (ice_port_udp/ice_port_tcp). +# This can be useful in case there are additional network components (e.g. NLBs) +# in front of this service that may route the traffic through a different port. +# +# Note: this port will apply to both UDP and TCP host candidates. +# +# ice_host_port_override = 30443 + # A list of ICE servers (STUN/TURN) to be used by the service. It supports # advanced configurations. # Example diff --git a/docs/env_config.md b/docs/env_config.md index d20372e..04032a3 100644 --- a/docs/env_config.md +++ b/docs/env_config.md @@ -15,6 +15,7 @@ RTCD_RTC_ICEPORTUDP Integer RTCD_RTC_ICEADDRESSTCP String RTCD_RTC_ICEPORTTCP Integer RTCD_RTC_ICEHOSTOVERRIDE String +RTCD_RTC_ICEHOSTPORTOVERRIDE Integer RTCD_RTC_ICESERVERS Comma-separated list of RTCD_RTC_TURNCONFIG_STATICAUTHSECRET String RTCD_RTC_TURNCONFIG_CREDENTIALSEXPIRATIONMINUTES Integer diff --git a/service/rtc/config.go b/service/rtc/config.go index ca3be09..599a4e6 100644 --- a/service/rtc/config.go +++ b/service/rtc/config.go @@ -22,6 +22,9 @@ type ServerConfig struct { // ICEHostOverride optionally specifies an IP address (or hostname) // to be used as the main host ICE candidate. ICEHostOverride string `toml:"ice_host_override"` + // ICEHostPortOverride optionally specifies a port number to override the one + // used to listen on when sharing host candidates. + ICEHostPortOverride int `toml:"ice_host_port_override"` // A list of ICE server (STUN/TURN) configurations to use. ICEServers ICEServers `toml:"ice_servers"` TURNConfig TURNConfig `toml:"turn"` @@ -54,6 +57,10 @@ func (c ServerConfig) IsValid() error { return fmt.Errorf("invalid TURNConfig: %w", err) } + if c.ICEHostPortOverride != 0 && (c.ICEHostPortOverride < 80 || c.ICEHostPortOverride > 49151) { + return fmt.Errorf("invalid ICEHostPortOverride value: %d is not in allowed range [80, 49151]", c.ICEHostPortOverride) + } + return nil } diff --git a/service/rtc/config_test.go b/service/rtc/config_test.go index 5f47a20..d8722e4 100644 --- a/service/rtc/config_test.go +++ b/service/rtc/config_test.go @@ -69,6 +69,20 @@ func TestServerConfigIsValid(t *testing.T) { require.Equal(t, "invalid TURNConfig: invalid CredentialsExpirationMinutes value: should be less than 1 week", err.Error()) }) + t.Run("invalid ICEHostPortOverride", func(t *testing.T) { + var cfg ServerConfig + cfg.ICEPortUDP = 8443 + cfg.ICEPortTCP = 8443 + cfg.ICEHostPortOverride = 45 + err := cfg.IsValid() + require.Error(t, err) + require.Equal(t, "invalid ICEHostPortOverride value: 45 is not in allowed range [80, 49151]", err.Error()) + cfg.ICEHostPortOverride = 65000 + err = cfg.IsValid() + require.Error(t, err) + require.Equal(t, "invalid ICEHostPortOverride value: 65000 is not in allowed range [80, 49151]", err.Error()) + }) + t.Run("valid", func(t *testing.T) { var cfg ServerConfig cfg.ICEAddressUDP = "127.0.0.1" diff --git a/service/rtc/sfu.go b/service/rtc/sfu.go index 3a6604e..2080c24 100644 --- a/service/rtc/sfu.go +++ b/service/rtc/sfu.go @@ -249,6 +249,17 @@ func (s *Server) InitSession(cfg SessionConfig, closeCb func() error) error { if candidate == nil { return } + + if s.cfg.ICEHostPortOverride != 0 && candidate.Typ == webrtc.ICECandidateTypeHost { + s.log.Debug("overriding host candidate port", + mlog.String("sessionID", cfg.SessionID), + mlog.Uint("port", candidate.Port), + mlog.Int("override", s.cfg.ICEHostPortOverride), + mlog.String("addr", candidate.Address), + mlog.Int("protocol", candidate.Protocol)) + candidate.Port = uint16(s.cfg.ICEHostPortOverride) + } + msg, err := newICEMessage(us, candidate) if err != nil { s.log.Error("failed to create ICE message", mlog.Err(err), mlog.String("sessionID", cfg.SessionID))