github.com/database64128/shadowsocks-go@v1.10.2-0.20240315062903-143a773533f1/conn/conn_darwinlinux.go (about) 1 //go:build darwin || linux 2 3 package conn 4 5 import ( 6 "fmt" 7 "net/netip" 8 "unsafe" 9 10 "golang.org/x/sys/unix" 11 ) 12 13 // SocketControlMessageBufferSize specifies the buffer size for receiving socket control messages. 14 const SocketControlMessageBufferSize = unix.SizeofCmsghdr + (unix.SizeofInet6Pktinfo+unix.SizeofPtr-1) & ^(unix.SizeofPtr-1) 15 16 // ParsePktinfoCmsg parses a single socket control message of type IP_PKTINFO or IPV6_PKTINFO, 17 // and returns the IP address and index of the network interface the packet was received from, 18 // or an error. 19 // 20 // This function is only implemented for Linux, macOS and Windows. On other platforms, this is a no-op. 21 func ParsePktinfoCmsg(cmsg []byte) (netip.Addr, uint32, error) { 22 if len(cmsg) < unix.SizeofCmsghdr { 23 return netip.Addr{}, 0, fmt.Errorf("control message length %d is shorter than cmsghdr length", len(cmsg)) 24 } 25 26 cmsghdr := (*unix.Cmsghdr)(unsafe.Pointer(&cmsg[0])) 27 28 switch { 29 case cmsghdr.Level == unix.IPPROTO_IP && cmsghdr.Type == unix.IP_PKTINFO && len(cmsg) >= unix.SizeofCmsghdr+unix.SizeofInet4Pktinfo: 30 pktinfo := (*unix.Inet4Pktinfo)(unsafe.Pointer(&cmsg[unix.SizeofCmsghdr])) 31 return netip.AddrFrom4(pktinfo.Spec_dst), uint32(pktinfo.Ifindex), nil 32 33 case cmsghdr.Level == unix.IPPROTO_IPV6 && cmsghdr.Type == unix.IPV6_PKTINFO && len(cmsg) >= unix.SizeofCmsghdr+unix.SizeofInet6Pktinfo: 34 pktinfo := (*unix.Inet6Pktinfo)(unsafe.Pointer(&cmsg[unix.SizeofCmsghdr])) 35 return netip.AddrFrom16(pktinfo.Addr), pktinfo.Ifindex, nil 36 37 default: 38 return netip.Addr{}, 0, fmt.Errorf("unknown control message level %d type %d", cmsghdr.Level, cmsghdr.Type) 39 } 40 }