Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ toolchain go1.24.2
require (
github.com/gammazero/deque v1.0.0
github.com/livekit/protocol v1.38.1-0.20250511053429-f8ea8179871e
github.com/pion/ice/v4 v4.2.0
github.com/pion/ice/v4 v4.2.6
github.com/pion/interceptor v0.1.43
github.com/pion/logging v0.2.4
github.com/pion/rtcp v1.2.16
github.com/pion/rtp v1.10.0
github.com/pion/stun/v3 v3.1.1
github.com/pion/stun/v3 v3.1.2
github.com/pion/transport/v4 v4.0.1
github.com/pion/webrtc/v4 v4.2.3
github.com/pkg/errors v0.9.1
Expand All @@ -28,13 +28,13 @@ require (
github.com/google/uuid v1.6.0 // indirect
github.com/klauspost/cpuid/v2 v2.2.6 // indirect
github.com/pion/datachannel v1.6.0 // indirect
github.com/pion/dtls/v3 v3.0.10 // indirect
github.com/pion/dtls/v3 v3.1.2 // indirect
github.com/pion/mdns/v2 v2.1.0 // indirect
github.com/pion/randutil v0.1.0 // indirect
github.com/pion/sctp v1.9.2 // indirect
github.com/pion/sdp/v3 v3.0.17 // indirect
github.com/pion/srtp/v3 v3.0.10 // indirect
github.com/pion/turn/v4 v4.1.4 // indirect
github.com/pion/turn/v5 v5.0.4 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/puzpuzpuz/xsync/v3 v3.5.0 // indirect
github.com/wlynxg/anet v0.0.5 // indirect
Expand All @@ -44,7 +44,7 @@ require (
go.uber.org/zap/exp v0.3.0 // indirect
golang.org/x/crypto v0.47.0 // indirect
golang.org/x/net v0.49.0 // indirect
golang.org/x/sys v0.40.0 // indirect
golang.org/x/sys v0.41.0 // indirect
golang.org/x/time v0.14.0 // indirect
google.golang.org/protobuf v1.36.5 // indirect
)
18 changes: 10 additions & 8 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ github.com/livekit/protocol v1.38.1-0.20250511053429-f8ea8179871e h1:qa0NFwLRJy0
github.com/livekit/protocol v1.38.1-0.20250511053429-f8ea8179871e/go.mod h1:JpubNKJFmZuTksypbvFI0qmYxzTgR5+3sw3GM0JyYAA=
github.com/pion/datachannel v1.6.0 h1:XecBlj+cvsxhAMZWFfFcPyUaDZtd7IJvrXqlXD/53i0=
github.com/pion/datachannel v1.6.0/go.mod h1:ur+wzYF8mWdC+Mkis5Thosk+u/VOL287apDNEbFpsIk=
github.com/pion/dtls/v3 v3.0.10 h1:k9ekkq1kaZoxnNEbyLKI8DI37j/Nbk1HWmMuywpQJgg=
github.com/pion/dtls/v3 v3.0.10/go.mod h1:YEmmBYIoBsY3jmG56dsziTv/Lca9y4Om83370CXfqJ8=
github.com/pion/ice/v4 v4.2.0 h1:jJC8S+CvXCCvIQUgx+oNZnoUpt6zwc34FhjWwCU4nlw=
github.com/pion/ice/v4 v4.2.0/go.mod h1:EgjBGxDgmd8xB0OkYEVFlzQuEI7kWSCFu+mULqaisy4=
github.com/pion/dtls/v3 v3.1.2 h1:gqEdOUXLtCGW+afsBLO0LtDD8GnuBBjEy6HRtyofZTc=
github.com/pion/dtls/v3 v3.1.2/go.mod h1:Hw/igcX4pdY69z1Hgv5x7wJFrUkdgHwAn/Q/uo7YHRo=
github.com/pion/ice/v4 v4.2.6 h1:17SKPTupOmumCMAQ4ntf8rv6q6XEfVzuz1gSFrnhzPE=
github.com/pion/ice/v4 v4.2.6/go.mod h1:tmp90fBKpZhQDkHkp/QJb+Gn8vhMxuAcMq7PfhQWQHE=
github.com/pion/interceptor v0.1.43 h1:6hmRfnmjogSs300xfkR0JxYFZ9k5blTEvCD7wxEDuNQ=
github.com/pion/interceptor v0.1.43/go.mod h1:BSiC1qKIJt1XVr3l3xQ2GEmCFStk9tx8fwtCZxxgR7M=
github.com/pion/logging v0.2.4 h1:tTew+7cmQ+Mc1pTBLKH2puKsOvhm32dROumOZ655zB8=
Expand All @@ -40,14 +40,16 @@ github.com/pion/sdp/v3 v3.0.17 h1:9SfLAW/fF1XC8yRqQ3iWGzxkySxup4k4V7yN8Fs8nuo=
github.com/pion/sdp/v3 v3.0.17/go.mod h1:9tyKzznud3qiweZcD86kS0ff1pGYB3VX+Bcsmkx6IXo=
github.com/pion/srtp/v3 v3.0.10 h1:tFirkpBb3XccP5VEXLi50GqXhv5SKPxqrdlhDCJlZrQ=
github.com/pion/srtp/v3 v3.0.10/go.mod h1:3mOTIB0cq9qlbn59V4ozvv9ClW/BSEbRp4cY0VtaR7M=
github.com/pion/stun/v3 v3.1.1 h1:CkQxveJ4xGQjulGSROXbXq94TAWu8gIX2dT+ePhUkqw=
github.com/pion/stun/v3 v3.1.1/go.mod h1:qC1DfmcCTQjl9PBaMa5wSn3x9IPmKxSdcCsxBcDBndM=
github.com/pion/stun/v3 v3.1.2 h1:86IhD8wFn6IDW4b1/0QzoQS+f5PeA8OHHRn8UZW5ErY=
github.com/pion/stun/v3 v3.1.2/go.mod h1:H7gDic7nNwlUL05pbs6T1dtaBehh/KjupxfWw3ZI7cA=
github.com/pion/transport/v3 v3.1.1 h1:Tr684+fnnKlhPceU+ICdrw6KKkTms+5qHMgw6bIkYOM=
github.com/pion/transport/v3 v3.1.1/go.mod h1:+c2eewC5WJQHiAA46fkMMzoYZSuGzA/7E2FPrOYHctQ=
github.com/pion/transport/v4 v4.0.1 h1:sdROELU6BZ63Ab7FrOLn13M6YdJLY20wldXW2Cu2k8o=
github.com/pion/transport/v4 v4.0.1/go.mod h1:nEuEA4AD5lPdcIegQDpVLgNoDGreqM/YqmEx3ovP4jM=
github.com/pion/turn/v4 v4.1.4 h1:EU11yMXKIsK43FhcUnjLlrhE4nboHZq+TXBIi3QpcxQ=
github.com/pion/turn/v4 v4.1.4/go.mod h1:ES1DXVFKnOhuDkqn9hn5VJlSWmZPaRJLyBXoOeO/BmQ=
github.com/pion/turn/v5 v5.0.4 h1:xKAnP1b5eCnjFPd55OgxkqIVoyzbHKZa06SxZ3fopXQ=
github.com/pion/turn/v5 v5.0.4/go.mod h1:zbPsMp+fIVhKt5uWu2jcjk88FcoRbGMBSzVsaTuhcmM=
github.com/pion/webrtc/v4 v4.2.3 h1:RtdWDnkenNQGxUrZqWa5gSkTm5ncsLg5d+zu0M4cXt4=
github.com/pion/webrtc/v4 v4.2.3/go.mod h1:7vsyFzRzaKP5IELUnj8zLcglPyIT6wWwqTppBZ1k6Kc=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
Expand Down Expand Up @@ -81,8 +83,8 @@ golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c/go.mod h1:tujkw807nyEEAamNbD
golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o=
golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
Expand Down
30 changes: 16 additions & 14 deletions pkg/rtcconfig/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,20 +42,22 @@ var DefaultStunServers = []string{
}

type RTCConfig struct {
UDPPort PortRange `yaml:"udp_port,omitempty"`
TCPPort uint32 `yaml:"tcp_port,omitempty"`
ICEPortRangeStart uint32 `yaml:"port_range_start,omitempty"`
ICEPortRangeEnd uint32 `yaml:"port_range_end,omitempty"`
UseStunPortAsICE bool `yaml:"use_stun_port_as_ice,omitempty"`
NodeIP NodeIP `yaml:"node_ip,omitempty"`
NodeIPAutoGenerated bool `yaml:"-"`
STUNServers []string `yaml:"stun_servers,omitempty"`
UseExternalIP bool `yaml:"use_external_ip"`
UseICELite bool `yaml:"use_ice_lite,omitempty"`
Interfaces InterfacesConfig `yaml:"interfaces,omitempty"`
IPs IPsConfig `yaml:"ips,omitempty"`
EnableLoopbackCandidate bool `yaml:"enable_loopback_candidate"`
UseMDNS bool `yaml:"use_mdns,omitempty"`
UDPPort PortRange `yaml:"udp_port,omitempty"`
TCPPort uint32 `yaml:"tcp_port,omitempty"`
ICEPortRangeStart uint32 `yaml:"port_range_start,omitempty"`
ICEPortRangeEnd uint32 `yaml:"port_range_end,omitempty"`
UseStunPortAsICE bool `yaml:"use_stun_port_as_ice,omitempty"`
NodeIP NodeIP `yaml:"node_ip,omitempty"`
NodeIPAutoGenerated bool `yaml:"-"`
STUNServers []string `yaml:"stun_servers,omitempty"`
UseExternalIP bool `yaml:"use_external_ip"`
SkipExternalIPValidation bool `yaml:"skip_external_ip_validation,omitempty"`
AdvertiseInternalIP bool `yaml:"advertise_internal_ip,omitempty"`
UseICELite bool `yaml:"use_ice_lite,omitempty"`
Interfaces InterfacesConfig `yaml:"interfaces,omitempty"`
IPs IPsConfig `yaml:"ips,omitempty"`
EnableLoopbackCandidate bool `yaml:"enable_loopback_candidate"`
UseMDNS bool `yaml:"use_mdns,omitempty"`
// when UseExternalIP is true, only advertise the external IP to client
ExternalIPOnly bool `yaml:"external_ip_only,omitempty"`
BatchIO BatchIOConfig `yaml:"batch_io,omitempty"`
Expand Down
12 changes: 10 additions & 2 deletions pkg/rtcconfig/ip.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ func GetLocalIPAddresses(includeLoopback bool, includeV6 bool, ifFilter func(str
return nil, fmt.Errorf("could not find local IP address")
}

func findExternalIP(ctx context.Context, stunServer string, localAddr net.Addr) (string, error) {
func findExternalIP(ctx context.Context, stunServer string, localAddr net.Addr, validate bool) (string, error) {
ctx1, cancel1 := context.WithTimeout(ctx, stunPingTimeout)
defer cancel1()

Expand Down Expand Up @@ -213,13 +213,21 @@ func findExternalIP(ctx context.Context, stunServer string, localAddr net.Addr)
"localAddr", localAddr,
"stunServer", stunServer,
"externalIP", ipAddr,
"validateExternalIP", validate,
)
if !validate {
return ipAddr, nil
}
return ipAddr, validateExternalIP(ctx, ipAddr, localAddr)
}

// GetExternalIP return external IP for localAddr from stun server. If localAddr is nil, a local address is chosen automatically,
// else the address will be used to validate the external IP is accessible from the outside.
func GetExternalIP(ctx context.Context, stunServers []string, localAddr net.Addr) (string, error) {
return getExternalIP(ctx, stunServers, localAddr, true)
}

func getExternalIP(ctx context.Context, stunServers []string, localAddr net.Addr, validate bool) (string, error) {
if len(stunServers) == 0 {
return "", errors.New("STUN servers are required but not defined")
}
Expand All @@ -230,7 +238,7 @@ func GetExternalIP(ctx context.Context, stunServers []string, localAddr net.Addr
var err error
for _, ss := range stunServers {
var ipAddr string
ipAddr, err = findExternalIP(ctx1, ss, localAddr)
ipAddr, err = findExternalIP(ctx1, ss, localAddr, validate)
if err == nil {
return ipAddr, nil
}
Expand Down
22 changes: 13 additions & 9 deletions pkg/rtcconfig/webrtc_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,18 +98,18 @@ func NewWebRTCConfig(rtcConf *RTCConfig, development bool) (*WebRTCConfig, error
s.SetIPFilter(ipFilter)
if len(ips) == 0 {
logger.Infow("no external IPs found, using node IP for NAT1To1Ips", "ip", rtcConf.NodeIP)
if err := SetNAT1To1AddressRewriteRules(&s, rtcConf.NodeIP.ToStringSlice(), webrtc.ICECandidateTypeHost); err != nil {
if err := SetNAT1To1AddressRewriteRules(&s, rtcConf.NodeIP.ToStringSlice(), false); err != nil {
return nil, err
}
} else {
logger.Infow("using external IPs", "ips", ips)
if err := SetNAT1To1AddressRewriteRules(&s, ips, webrtc.ICECandidateTypeHost); err != nil {
logger.Infow("using external IPs", "ips", ips, "advertiseInternalIP", rtcConf.AdvertiseInternalIP)
if err := SetNAT1To1AddressRewriteRules(&s, ips, rtcConf.AdvertiseInternalIP); err != nil {
return nil, err
}
}
nat1to1IPs = ips
} else {
if err := SetNAT1To1AddressRewriteRules(&s, rtcConf.NodeIP.ToStringSlice(), webrtc.ICECandidateTypeHost); err != nil {
if err := SetNAT1To1AddressRewriteRules(&s, rtcConf.NodeIP.ToStringSlice(), false); err != nil {
return nil, err
}
}
Expand Down Expand Up @@ -236,26 +236,30 @@ func NewWebRTCConfig(rtcConf *RTCConfig, development bool) (*WebRTCConfig, error
}, nil
}

func SetNAT1To1AddressRewriteRules(s *webrtc.SettingEngine, ips []string, candidateType webrtc.ICECandidateType) error {
func SetNAT1To1AddressRewriteRules(s *webrtc.SettingEngine, ips []string, includeInternal bool) error {
rules := make([]webrtc.ICEAddressRewriteRule, 0, len(ips)+1)
catchAll := make([]string, 0, len(ips))

mode := webrtc.ICEAddressRewriteModeUnspecified
if includeInternal {
mode = webrtc.ICEAddressRewriteAppend
}
for _, ip := range ips {
if parts := strings.Split(ip, "/"); len(parts) == 2 {
rules = append(rules, webrtc.ICEAddressRewriteRule{
External: []string{parts[0]},
Local: parts[1],
AsCandidateType: candidateType,
AsCandidateType: webrtc.ICECandidateTypeHost,
Mode: mode,
})
catchAll = append(catchAll, parts[0])
} else {
catchAll = append(catchAll, ip)
}
}
if len(catchAll) > 0 {
rules = append(rules, webrtc.ICEAddressRewriteRule{
External: catchAll,
AsCandidateType: candidateType,
AsCandidateType: webrtc.ICECandidateTypeHost,
})
}

Expand Down Expand Up @@ -304,7 +308,7 @@ func getNAT1to1IPsForConf(rtcConf *RTCConfig, ifFilter func(string) bool, ipFilt
go func(localIP string) {
defer wg.Done()
for _, port := range udpPorts {
addr, err := GetExternalIP(ctx, stunServers, &net.UDPAddr{IP: net.ParseIP(localIP), Port: port})
addr, err := getExternalIP(ctx, stunServers, &net.UDPAddr{IP: net.ParseIP(localIP), Port: port}, !rtcConf.SkipExternalIPValidation)
if err != nil {
if strings.Contains(err.Error(), "address already in use") {
logger.Infow("failed to get external ip, address already in use", "local", localIP, "port", port)
Expand Down