mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-18 08:16:39 +00:00
Handle IPv6 candidates in userspace bind
This commit is contained in:
153
client/iface/bind/dual_stack_conn.go
Normal file
153
client/iface/bind/dual_stack_conn.go
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
package bind
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"net"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/hashicorp/go-multierror"
|
||||||
|
|
||||||
|
nberrors "github.com/netbirdio/netbird/client/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
errNoIPv4Conn = errors.New("no IPv4 connection available")
|
||||||
|
errNoIPv6Conn = errors.New("no IPv6 connection available")
|
||||||
|
errInvalidAddr = errors.New("invalid address type")
|
||||||
|
)
|
||||||
|
|
||||||
|
// DualStackPacketConn is a composite PacketConn that can handle both IPv4 and IPv6
|
||||||
|
type DualStackPacketConn struct {
|
||||||
|
ipv4Conn net.PacketConn
|
||||||
|
ipv6Conn net.PacketConn
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDualStackPacketConn creates a new dual-stack packet connection
|
||||||
|
func NewDualStackPacketConn(ipv4Conn, ipv6Conn net.PacketConn) *DualStackPacketConn {
|
||||||
|
return &DualStackPacketConn{
|
||||||
|
ipv4Conn: ipv4Conn,
|
||||||
|
ipv6Conn: ipv6Conn,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadFrom reads from both IPv4 and IPv6 connections
|
||||||
|
func (d *DualStackPacketConn) ReadFrom(b []byte) (n int, addr net.Addr, err error) {
|
||||||
|
// Prefer IPv4 if available
|
||||||
|
if d.ipv4Conn != nil {
|
||||||
|
return d.ipv4Conn.ReadFrom(b)
|
||||||
|
}
|
||||||
|
if d.ipv6Conn != nil {
|
||||||
|
return d.ipv6Conn.ReadFrom(b)
|
||||||
|
}
|
||||||
|
return 0, nil, net.ErrClosed
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteTo writes to the appropriate connection based on the address type
|
||||||
|
func (d *DualStackPacketConn) WriteTo(b []byte, addr net.Addr) (n int, err error) {
|
||||||
|
udpAddr, ok := addr.(*net.UDPAddr)
|
||||||
|
if !ok {
|
||||||
|
return 0, &net.OpError{
|
||||||
|
Op: "write",
|
||||||
|
Net: "udp",
|
||||||
|
Addr: addr,
|
||||||
|
Err: errInvalidAddr,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if udpAddr.IP.To4() == nil {
|
||||||
|
if d.ipv6Conn != nil {
|
||||||
|
return d.ipv6Conn.WriteTo(b, addr)
|
||||||
|
}
|
||||||
|
return 0, &net.OpError{
|
||||||
|
Op: "write",
|
||||||
|
Net: "udp6",
|
||||||
|
Addr: addr,
|
||||||
|
Err: errNoIPv6Conn,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.ipv4Conn != nil {
|
||||||
|
return d.ipv4Conn.WriteTo(b, addr)
|
||||||
|
}
|
||||||
|
return 0, &net.OpError{
|
||||||
|
Op: "write",
|
||||||
|
Net: "udp4",
|
||||||
|
Addr: addr,
|
||||||
|
Err: errNoIPv4Conn,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close closes both connections
|
||||||
|
func (d *DualStackPacketConn) Close() error {
|
||||||
|
var result *multierror.Error
|
||||||
|
if d.ipv4Conn != nil {
|
||||||
|
if err := d.ipv4Conn.Close(); err != nil {
|
||||||
|
result = multierror.Append(result, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if d.ipv6Conn != nil {
|
||||||
|
if err := d.ipv6Conn.Close(); err != nil {
|
||||||
|
result = multierror.Append(result, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nberrors.FormatErrorOrNil(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LocalAddr returns the local address of the IPv4 connection (for compatibility)
|
||||||
|
func (d *DualStackPacketConn) LocalAddr() net.Addr {
|
||||||
|
if d.ipv4Conn != nil {
|
||||||
|
return d.ipv4Conn.LocalAddr()
|
||||||
|
}
|
||||||
|
if d.ipv6Conn != nil {
|
||||||
|
return d.ipv6Conn.LocalAddr()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetDeadline sets the deadline for both connections
|
||||||
|
func (d *DualStackPacketConn) SetDeadline(t time.Time) error {
|
||||||
|
var result *multierror.Error
|
||||||
|
if d.ipv4Conn != nil {
|
||||||
|
if err := d.ipv4Conn.SetDeadline(t); err != nil {
|
||||||
|
result = multierror.Append(result, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if d.ipv6Conn != nil {
|
||||||
|
if err := d.ipv6Conn.SetDeadline(t); err != nil {
|
||||||
|
result = multierror.Append(result, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nberrors.FormatErrorOrNil(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetReadDeadline sets the read deadline for both connections
|
||||||
|
func (d *DualStackPacketConn) SetReadDeadline(t time.Time) error {
|
||||||
|
var result *multierror.Error
|
||||||
|
if d.ipv4Conn != nil {
|
||||||
|
if err := d.ipv4Conn.SetReadDeadline(t); err != nil {
|
||||||
|
result = multierror.Append(result, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if d.ipv6Conn != nil {
|
||||||
|
if err := d.ipv6Conn.SetReadDeadline(t); err != nil {
|
||||||
|
result = multierror.Append(result, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nberrors.FormatErrorOrNil(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetWriteDeadline sets the write deadline for both connections
|
||||||
|
func (d *DualStackPacketConn) SetWriteDeadline(t time.Time) error {
|
||||||
|
var result *multierror.Error
|
||||||
|
if d.ipv4Conn != nil {
|
||||||
|
if err := d.ipv4Conn.SetWriteDeadline(t); err != nil {
|
||||||
|
result = multierror.Append(result, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if d.ipv6Conn != nil {
|
||||||
|
if err := d.ipv6Conn.SetWriteDeadline(t); err != nil {
|
||||||
|
result = multierror.Append(result, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nberrors.FormatErrorOrNil(result)
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@ package bind
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"errors"
|
||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"runtime"
|
"runtime"
|
||||||
@@ -26,7 +26,7 @@ type receiverCreator struct {
|
|||||||
iceBind *ICEBind
|
iceBind *ICEBind
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rc receiverCreator) CreateReceiverFn(pc wgConn.PacketReader, conn *net.UDPConn, rxOffload bool, msgPool *sync.Pool) wgConn.ReceiveFunc {
|
func (rc receiverCreator) CreateReceiverFn(pc wgConn.BatchReader, conn *net.UDPConn, rxOffload bool, msgPool *sync.Pool) wgConn.ReceiveFunc {
|
||||||
return rc.iceBind.createReceiverFn(pc, conn, rxOffload, msgPool)
|
return rc.iceBind.createReceiverFn(pc, conn, rxOffload, msgPool)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,6 +53,8 @@ type ICEBind struct {
|
|||||||
|
|
||||||
muUDPMux sync.Mutex
|
muUDPMux sync.Mutex
|
||||||
udpMux *UniversalUDPMuxDefault
|
udpMux *UniversalUDPMuxDefault
|
||||||
|
ipv4Conn *net.UDPConn
|
||||||
|
ipv6Conn *net.UDPConn
|
||||||
address wgaddr.Address
|
address wgaddr.Address
|
||||||
activityRecorder *ActivityRecorder
|
activityRecorder *ActivityRecorder
|
||||||
}
|
}
|
||||||
@@ -110,11 +112,11 @@ func (s *ICEBind) ActivityRecorder() *ActivityRecorder {
|
|||||||
func (s *ICEBind) GetICEMux() (*UniversalUDPMuxDefault, error) {
|
func (s *ICEBind) GetICEMux() (*UniversalUDPMuxDefault, error) {
|
||||||
s.muUDPMux.Lock()
|
s.muUDPMux.Lock()
|
||||||
defer s.muUDPMux.Unlock()
|
defer s.muUDPMux.Unlock()
|
||||||
if s.udpMux == nil {
|
|
||||||
return nil, fmt.Errorf("ICEBind has not been initialized yet")
|
|
||||||
}
|
|
||||||
|
|
||||||
return s.udpMux, nil
|
if s.udpMux != nil {
|
||||||
|
return s.udpMux, nil
|
||||||
|
}
|
||||||
|
return nil, errors.New("ICEBind has not been initialized yet")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *ICEBind) SetEndpoint(fakeIP netip.Addr, conn net.Conn) {
|
func (b *ICEBind) SetEndpoint(fakeIP netip.Addr, conn net.Conn) {
|
||||||
@@ -146,14 +148,40 @@ func (b *ICEBind) Send(bufs [][]byte, ep wgConn.Endpoint) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ICEBind) createReceiverFn(pc wgConn.PacketReader, conn *net.UDPConn, rxOffload bool, msgsPool *sync.Pool) wgConn.ReceiveFunc {
|
func (s *ICEBind) createReceiverFn(pc wgConn.BatchReader, conn *net.UDPConn, rxOffload bool, msgsPool *sync.Pool) wgConn.ReceiveFunc {
|
||||||
s.muUDPMux.Lock()
|
s.muUDPMux.Lock()
|
||||||
defer s.muUDPMux.Unlock()
|
defer s.muUDPMux.Unlock()
|
||||||
|
|
||||||
if s.udpMux == nil {
|
localAddr, ok := conn.LocalAddr().(*net.UDPAddr)
|
||||||
|
if !ok {
|
||||||
|
log.Errorf("ICEBind: unexpected address type: %T", conn.LocalAddr())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
isIPv6 := localAddr.IP.To4() == nil
|
||||||
|
|
||||||
|
if isIPv6 {
|
||||||
|
s.ipv6Conn = conn
|
||||||
|
} else {
|
||||||
|
s.ipv4Conn = conn
|
||||||
|
}
|
||||||
|
|
||||||
|
needsNewMux := s.udpMux == nil && (s.ipv4Conn != nil || s.ipv6Conn != nil)
|
||||||
|
needsUpgrade := s.udpMux != nil && s.ipv4Conn != nil && s.ipv6Conn != nil
|
||||||
|
|
||||||
|
if needsNewMux || needsUpgrade {
|
||||||
|
var iceMuxConn net.PacketConn
|
||||||
|
switch {
|
||||||
|
case s.ipv4Conn != nil && s.ipv6Conn != nil:
|
||||||
|
iceMuxConn = NewDualStackPacketConn(s.ipv4Conn, s.ipv6Conn)
|
||||||
|
case s.ipv4Conn != nil:
|
||||||
|
iceMuxConn = s.ipv4Conn
|
||||||
|
default:
|
||||||
|
iceMuxConn = s.ipv6Conn
|
||||||
|
}
|
||||||
|
|
||||||
s.udpMux = NewUniversalUDPMuxDefault(
|
s.udpMux = NewUniversalUDPMuxDefault(
|
||||||
UniversalUDPMuxParams{
|
UniversalUDPMuxParams{
|
||||||
UDPConn: conn,
|
UDPConn: iceMuxConn,
|
||||||
Net: s.transportNet,
|
Net: s.transportNet,
|
||||||
FilterFn: s.filterFn,
|
FilterFn: s.filterFn,
|
||||||
WGAddress: s.address,
|
WGAddress: s.address,
|
||||||
@@ -198,7 +226,7 @@ func (s *ICEBind) createReceiverFn(pc wgConn.PacketReader, conn *net.UDPConn, rx
|
|||||||
msg := &(*msgs)[i]
|
msg := &(*msgs)[i]
|
||||||
|
|
||||||
// todo: handle err
|
// todo: handle err
|
||||||
ok, _ := s.filterOutStunMessages(msg.Buffers, msg.N, msg.Addr)
|
ok, _ := s.filterOutStunMessages(msg.Buffers, msg.N, msg.Addr, isIPv6)
|
||||||
if ok {
|
if ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -206,7 +234,12 @@ func (s *ICEBind) createReceiverFn(pc wgConn.PacketReader, conn *net.UDPConn, rx
|
|||||||
if sizes[i] == 0 {
|
if sizes[i] == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
addrPort := msg.Addr.(*net.UDPAddr).AddrPort()
|
udpAddr, ok := msg.Addr.(*net.UDPAddr)
|
||||||
|
if !ok {
|
||||||
|
log.Errorf("ICEBind: unexpected address type: %T", msg.Addr)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
addrPort := udpAddr.AddrPort()
|
||||||
|
|
||||||
if isTransportPkg(msg.Buffers, msg.N) {
|
if isTransportPkg(msg.Buffers, msg.N) {
|
||||||
s.activityRecorder.record(addrPort)
|
s.activityRecorder.record(addrPort)
|
||||||
@@ -220,7 +253,7 @@ func (s *ICEBind) createReceiverFn(pc wgConn.PacketReader, conn *net.UDPConn, rx
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ICEBind) filterOutStunMessages(buffers [][]byte, n int, addr net.Addr) (bool, error) {
|
func (s *ICEBind) filterOutStunMessages(buffers [][]byte, n int, addr net.Addr, isIPv6 bool) (bool, error) {
|
||||||
for i := range buffers {
|
for i := range buffers {
|
||||||
if !stun.IsMessage(buffers[i]) {
|
if !stun.IsMessage(buffers[i]) {
|
||||||
continue
|
continue
|
||||||
@@ -232,9 +265,10 @@ func (s *ICEBind) filterOutStunMessages(buffers [][]byte, n int, addr net.Addr)
|
|||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
muxErr := s.udpMux.HandleSTUNMessage(msg, addr)
|
if s.udpMux != nil {
|
||||||
if muxErr != nil {
|
if err := s.udpMux.HandleSTUNMessage(msg, addr); err != nil {
|
||||||
log.Warnf("failed to handle STUN packet")
|
log.Warnf("failed to handle STUN packet: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buffers[i] = []byte{}
|
buffers[i] = []byte{}
|
||||||
|
|||||||
@@ -342,6 +342,9 @@ func (m *UDPMuxDefault) Close() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *UDPMuxDefault) writeTo(buf []byte, rAddr net.Addr) (n int, err error) {
|
func (m *UDPMuxDefault) writeTo(buf []byte, rAddr net.Addr) (n int, err error) {
|
||||||
|
if dualStackConn, ok := m.params.UDPConn.(*DualStackPacketConn); ok {
|
||||||
|
return dualStackConn.WriteTo(buf, rAddr)
|
||||||
|
}
|
||||||
return m.params.UDPConn.WriteTo(buf, rAddr)
|
return m.params.UDPConn.WriteTo(buf, rAddr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -126,6 +126,11 @@ type udpConn struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *udpConn) WriteTo(b []byte, addr net.Addr) (int, error) {
|
func (u *udpConn) WriteTo(b []byte, addr net.Addr) (int, error) {
|
||||||
|
// Check if this is a dual-stack connection and handle IPv6 addresses properly
|
||||||
|
if dualStackConn, ok := u.PacketConn.(*DualStackPacketConn); ok {
|
||||||
|
return dualStackConn.WriteTo(b, addr)
|
||||||
|
}
|
||||||
|
|
||||||
if u.filterFn == nil {
|
if u.filterFn == nil {
|
||||||
return u.PacketConn.WriteTo(b, addr)
|
return u.PacketConn.WriteTo(b, addr)
|
||||||
}
|
}
|
||||||
@@ -141,6 +146,11 @@ func (u *udpConn) handleCachedAddress(isRouted bool, b []byte, addr net.Addr) (i
|
|||||||
if isRouted {
|
if isRouted {
|
||||||
return 0, fmt.Errorf("address %s is part of a routed network, refusing to write", addr)
|
return 0, fmt.Errorf("address %s is part of a routed network, refusing to write", addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if dualStackConn, ok := u.PacketConn.(*DualStackPacketConn); ok {
|
||||||
|
return dualStackConn.WriteTo(b, addr)
|
||||||
|
}
|
||||||
|
|
||||||
return u.PacketConn.WriteTo(b, addr)
|
return u.PacketConn.WriteTo(b, addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,6 +158,11 @@ func (u *udpConn) handleUncachedAddress(b []byte, addr net.Addr) (int, error) {
|
|||||||
if err := u.performFilterCheck(addr); err != nil {
|
if err := u.performFilterCheck(addr); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if dualStackConn, ok := u.PacketConn.(*DualStackPacketConn); ok {
|
||||||
|
return dualStackConn.WriteTo(b, addr)
|
||||||
|
}
|
||||||
|
|
||||||
return u.PacketConn.WriteTo(b, addr)
|
return u.PacketConn.WriteTo(b, addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -146,8 +146,8 @@ func (w *WorkerICE) OnNewOffer(remoteOfferAnswer *OfferAnswer) {
|
|||||||
RosenpassAddr: remoteOfferAnswer.RosenpassAddr,
|
RosenpassAddr: remoteOfferAnswer.RosenpassAddr,
|
||||||
LocalIceCandidateType: pair.Local.Type().String(),
|
LocalIceCandidateType: pair.Local.Type().String(),
|
||||||
RemoteIceCandidateType: pair.Remote.Type().String(),
|
RemoteIceCandidateType: pair.Remote.Type().String(),
|
||||||
LocalIceCandidateEndpoint: fmt.Sprintf("%s:%d", pair.Local.Address(), pair.Local.Port()),
|
LocalIceCandidateEndpoint: formatEndpoint(pair.Local.Address(), pair.Local.Port()),
|
||||||
RemoteIceCandidateEndpoint: fmt.Sprintf("%s:%d", pair.Remote.Address(), pair.Remote.Port()),
|
RemoteIceCandidateEndpoint: formatEndpoint(pair.Remote.Address(), pair.Remote.Port()),
|
||||||
Relayed: isRelayed(pair),
|
Relayed: isRelayed(pair),
|
||||||
RelayedOnLocal: isRelayCandidate(pair.Local),
|
RelayedOnLocal: isRelayCandidate(pair.Local),
|
||||||
}
|
}
|
||||||
@@ -405,3 +405,12 @@ func selectedPriority(pair *ice.CandidatePair) conntype.ConnPriority {
|
|||||||
return conntype.ICEP2P
|
return conntype.ICEP2P
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// formatEndpoint formats an IP address and port for display, adding brackets around IPv6 addresses
|
||||||
|
func formatEndpoint(addr string, port int) string {
|
||||||
|
parsed, err := netip.ParseAddr(addr)
|
||||||
|
if err == nil && parsed.Is6() {
|
||||||
|
return fmt.Sprintf("[%s]:%d", addr, port)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s:%d", addr, port)
|
||||||
|
}
|
||||||
|
|||||||
2
go.mod
2
go.mod
@@ -253,7 +253,7 @@ replace github.com/kardianos/service => github.com/netbirdio/service v0.0.0-2024
|
|||||||
|
|
||||||
replace github.com/getlantern/systray => github.com/netbirdio/systray v0.0.0-20231030152038-ef1ed2a27949
|
replace github.com/getlantern/systray => github.com/netbirdio/systray v0.0.0-20231030152038-ef1ed2a27949
|
||||||
|
|
||||||
replace golang.zx2c4.com/wireguard => github.com/netbirdio/wireguard-go v0.0.0-20241230120307-6a676aebaaf6
|
replace golang.zx2c4.com/wireguard => github.com/netbirdio/wireguard-go v0.0.0-20250709101833-3247b6066880
|
||||||
|
|
||||||
replace github.com/cloudflare/circl => github.com/cunicu/circl v0.0.0-20230801113412-fec58fc7b5f6
|
replace github.com/cloudflare/circl => github.com/cunicu/circl v0.0.0-20230801113412-fec58fc7b5f6
|
||||||
|
|
||||||
|
|||||||
4
go.sum
4
go.sum
@@ -509,8 +509,8 @@ github.com/netbirdio/service v0.0.0-20240911161631-f62744f42502 h1:3tHlFmhTdX9ax
|
|||||||
github.com/netbirdio/service v0.0.0-20240911161631-f62744f42502/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM=
|
github.com/netbirdio/service v0.0.0-20240911161631-f62744f42502/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM=
|
||||||
github.com/netbirdio/signal-dispatcher/dispatcher v0.0.0-20250514131221-a464fd5f30cb h1:Cr6age+ePALqlSvtp7wc6lYY97XN7rkD1K4XEDmY+TU=
|
github.com/netbirdio/signal-dispatcher/dispatcher v0.0.0-20250514131221-a464fd5f30cb h1:Cr6age+ePALqlSvtp7wc6lYY97XN7rkD1K4XEDmY+TU=
|
||||||
github.com/netbirdio/signal-dispatcher/dispatcher v0.0.0-20250514131221-a464fd5f30cb/go.mod h1:5/sjFmLb8O96B5737VCqhHyGRzNFIaN/Bu7ZodXc3qQ=
|
github.com/netbirdio/signal-dispatcher/dispatcher v0.0.0-20250514131221-a464fd5f30cb/go.mod h1:5/sjFmLb8O96B5737VCqhHyGRzNFIaN/Bu7ZodXc3qQ=
|
||||||
github.com/netbirdio/wireguard-go v0.0.0-20241230120307-6a676aebaaf6 h1:X5h5QgP7uHAv78FWgHV8+WYLjHxK9v3ilkVXT1cpCrQ=
|
github.com/netbirdio/wireguard-go v0.0.0-20250709101833-3247b6066880 h1:s4y7B+jGbOSCnBAyh+APS8QSe8Liq+akU4enLHs8Efo=
|
||||||
github.com/netbirdio/wireguard-go v0.0.0-20241230120307-6a676aebaaf6/go.mod h1:tkCQ4FQXmpAgYVh++1cq16/dH4QJtmvpRv19DWGAHSA=
|
github.com/netbirdio/wireguard-go v0.0.0-20250709101833-3247b6066880/go.mod h1:tkCQ4FQXmpAgYVh++1cq16/dH4QJtmvpRv19DWGAHSA=
|
||||||
github.com/nicksnyder/go-i18n/v2 v2.4.0 h1:3IcvPOAvnCKwNm0TB0dLDTuawWEj+ax/RERNC+diLMM=
|
github.com/nicksnyder/go-i18n/v2 v2.4.0 h1:3IcvPOAvnCKwNm0TB0dLDTuawWEj+ax/RERNC+diLMM=
|
||||||
github.com/nicksnyder/go-i18n/v2 v2.4.0/go.mod h1:nxYSZE9M0bf3Y70gPQjN9ha7XNHX7gMc814+6wVyEI4=
|
github.com/nicksnyder/go-i18n/v2 v2.4.0/go.mod h1:nxYSZE9M0bf3Y70gPQjN9ha7XNHX7gMc814+6wVyEI4=
|
||||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||||
|
|||||||
@@ -146,9 +146,26 @@ func (s *SharedSocket) updateRouter() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// LocalAddr returns an IPv4 address using the supplied port
|
// LocalAddr returns the local address that can handle both IPv4 and IPv6 connections
|
||||||
func (s *SharedSocket) LocalAddr() net.Addr {
|
func (s *SharedSocket) LocalAddr() net.Addr {
|
||||||
// todo check impact on ipv6 discovery
|
if s.conn4 != nil && s.conn6 != nil {
|
||||||
|
return &net.UDPAddr{
|
||||||
|
IP: net.IPv6unspecified,
|
||||||
|
Port: s.port,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if s.conn4 != nil {
|
||||||
|
return &net.UDPAddr{
|
||||||
|
IP: net.IPv4zero,
|
||||||
|
Port: s.port,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if s.conn6 != nil {
|
||||||
|
return &net.UDPAddr{
|
||||||
|
IP: net.IPv6zero,
|
||||||
|
Port: s.port,
|
||||||
|
}
|
||||||
|
}
|
||||||
return &net.UDPAddr{
|
return &net.UDPAddr{
|
||||||
IP: net.IPv4zero,
|
IP: net.IPv4zero,
|
||||||
Port: s.port,
|
Port: s.port,
|
||||||
|
|||||||
Reference in New Issue
Block a user