golang.org/x/net@v0.25.1-0.20240516223405-c87a5b62e243/ipv4/sys_asmreq.go (about)

     1  // Copyright 2012 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  //go:build aix || darwin || dragonfly || freebsd || netbsd || openbsd || solaris || windows
     6  
     7  package ipv4
     8  
     9  import (
    10  	"errors"
    11  	"net"
    12  	"unsafe"
    13  
    14  	"golang.org/x/net/internal/socket"
    15  )
    16  
    17  var errNoSuchInterface = errors.New("no such interface")
    18  
    19  func (so *sockOpt) setIPMreq(c *socket.Conn, ifi *net.Interface, grp net.IP) error {
    20  	mreq := ipMreq{Multiaddr: [4]byte{grp[0], grp[1], grp[2], grp[3]}}
    21  	if err := setIPMreqInterface(&mreq, ifi); err != nil {
    22  		return err
    23  	}
    24  	b := (*[sizeofIPMreq]byte)(unsafe.Pointer(&mreq))[:sizeofIPMreq]
    25  	return so.Set(c, b)
    26  }
    27  
    28  func (so *sockOpt) getMulticastIf(c *socket.Conn) (*net.Interface, error) {
    29  	var b [4]byte
    30  	if _, err := so.Get(c, b[:]); err != nil {
    31  		return nil, err
    32  	}
    33  	ifi, err := netIP4ToInterface(net.IPv4(b[0], b[1], b[2], b[3]))
    34  	if err != nil {
    35  		return nil, err
    36  	}
    37  	return ifi, nil
    38  }
    39  
    40  func (so *sockOpt) setMulticastIf(c *socket.Conn, ifi *net.Interface) error {
    41  	ip, err := netInterfaceToIP4(ifi)
    42  	if err != nil {
    43  		return err
    44  	}
    45  	var b [4]byte
    46  	copy(b[:], ip)
    47  	return so.Set(c, b[:])
    48  }
    49  
    50  func setIPMreqInterface(mreq *ipMreq, ifi *net.Interface) error {
    51  	if ifi == nil {
    52  		return nil
    53  	}
    54  	ifat, err := ifi.Addrs()
    55  	if err != nil {
    56  		return err
    57  	}
    58  	for _, ifa := range ifat {
    59  		switch ifa := ifa.(type) {
    60  		case *net.IPAddr:
    61  			if ip := ifa.IP.To4(); ip != nil {
    62  				copy(mreq.Interface[:], ip)
    63  				return nil
    64  			}
    65  		case *net.IPNet:
    66  			if ip := ifa.IP.To4(); ip != nil {
    67  				copy(mreq.Interface[:], ip)
    68  				return nil
    69  			}
    70  		}
    71  	}
    72  	return errNoSuchInterface
    73  }
    74  
    75  func netIP4ToInterface(ip net.IP) (*net.Interface, error) {
    76  	ift, err := net.Interfaces()
    77  	if err != nil {
    78  		return nil, err
    79  	}
    80  	for _, ifi := range ift {
    81  		ifat, err := ifi.Addrs()
    82  		if err != nil {
    83  			return nil, err
    84  		}
    85  		for _, ifa := range ifat {
    86  			switch ifa := ifa.(type) {
    87  			case *net.IPAddr:
    88  				if ip.Equal(ifa.IP) {
    89  					return &ifi, nil
    90  				}
    91  			case *net.IPNet:
    92  				if ip.Equal(ifa.IP) {
    93  					return &ifi, nil
    94  				}
    95  			}
    96  		}
    97  	}
    98  	return nil, errNoSuchInterface
    99  }
   100  
   101  func netInterfaceToIP4(ifi *net.Interface) (net.IP, error) {
   102  	if ifi == nil {
   103  		return net.IPv4zero.To4(), nil
   104  	}
   105  	ifat, err := ifi.Addrs()
   106  	if err != nil {
   107  		return nil, err
   108  	}
   109  	for _, ifa := range ifat {
   110  		switch ifa := ifa.(type) {
   111  		case *net.IPAddr:
   112  			if ip := ifa.IP.To4(); ip != nil {
   113  				return ip, nil
   114  			}
   115  		case *net.IPNet:
   116  			if ip := ifa.IP.To4(); ip != nil {
   117  				return ip, nil
   118  			}
   119  		}
   120  	}
   121  	return nil, errNoSuchInterface
   122  }