diff --git a/app/webrtc/subsystem.go b/app/webrtc/subsystem.go index 69bdc88..9c7e34e 100644 --- a/app/webrtc/subsystem.go +++ b/app/webrtc/subsystem.go @@ -67,14 +67,23 @@ func New(dataCfg config.DataWebRTC, logger log.Logger) (*Subsystem, error) { coreCfg.Enabled = dataCfg.Enable coreCfg.PublicIP = dataCfg.PublicIP - // If the operator configured multiple NAT1To1 IPs (e.g., dual - // LAN/public), they take precedence over PublicIP. Wire them - // through via PublicIP as the first entry; core/webrtc currently - // reads a single PublicIP, so M2 joins the list with the first - // entry winning. (Multi-IP NAT1To1 is an M3 enhancement.) - if len(dataCfg.NAT1To1IPs) > 0 && coreCfg.PublicIP == "" { - coreCfg.PublicIP = dataCfg.NAT1To1IPs[0] + // Build the NAT1To1IPs list that Pion will use for host candidates. + // Strategy: merge PublicIP and NAT1To1IPs, deduplicating. + // - If PublicIP is set it comes first. + // - Any entries in NAT1To1IPs that differ from PublicIP are appended. + // This replaces the old single-IP workaround and allows dual-homed + // servers (e.g., a LAN IP + a public IP) to advertise host candidates + // on all interfaces simultaneously. + nat1to1IPs := make([]string, 0, len(dataCfg.NAT1To1IPs)+1) + if dataCfg.PublicIP != "" { + nat1to1IPs = append(nat1to1IPs, dataCfg.PublicIP) } + for _, ip := range dataCfg.NAT1To1IPs { + if ip != dataCfg.PublicIP { + nat1to1IPs = append(nat1to1IPs, ip) + } + } + coreCfg.NAT1To1IPs = nat1to1IPs factory, err := corewebrtc.NewPeerFactory(coreCfg) if err != nil {