github.com/sagernet/wireguard-go@v0.0.0-20231215174105-89dec3b2f3e8/conn/sticky_linux.go (about)

     1  //go:build linux && !android
     2  
     3  /* SPDX-License-Identifier: MIT
     4   *
     5   * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved.
     6   */
     7  
     8  package conn
     9  
    10  import (
    11  	"net/netip"
    12  	"unsafe"
    13  
    14  	"golang.org/x/sys/unix"
    15  )
    16  
    17  func (e *StdNetEndpoint) SrcIP() netip.Addr {
    18  	switch len(e.src) {
    19  	case unix.CmsgSpace(unix.SizeofInet4Pktinfo):
    20  		info := (*unix.Inet4Pktinfo)(unsafe.Pointer(&e.src[unix.CmsgLen(0)]))
    21  		return netip.AddrFrom4(info.Spec_dst)
    22  	case unix.CmsgSpace(unix.SizeofInet6Pktinfo):
    23  		info := (*unix.Inet6Pktinfo)(unsafe.Pointer(&e.src[unix.CmsgLen(0)]))
    24  		// TODO: set zone. in order to do so we need to check if the address is
    25  		// link local, and if it is perform a syscall to turn the ifindex into a
    26  		// zone string because netip uses string zones.
    27  		return netip.AddrFrom16(info.Addr)
    28  	}
    29  	return netip.Addr{}
    30  }
    31  
    32  func (e *StdNetEndpoint) SrcIfidx() int32 {
    33  	switch len(e.src) {
    34  	case unix.CmsgSpace(unix.SizeofInet4Pktinfo):
    35  		info := (*unix.Inet4Pktinfo)(unsafe.Pointer(&e.src[unix.CmsgLen(0)]))
    36  		return info.Ifindex
    37  	case unix.CmsgSpace(unix.SizeofInet6Pktinfo):
    38  		info := (*unix.Inet6Pktinfo)(unsafe.Pointer(&e.src[unix.CmsgLen(0)]))
    39  		return int32(info.Ifindex)
    40  	}
    41  	return 0
    42  }
    43  
    44  func (e *StdNetEndpoint) SrcToString() string {
    45  	return e.SrcIP().String()
    46  }
    47  
    48  // getSrcFromControl parses the control for PKTINFO and if found updates ep with
    49  // the source information found.
    50  func getSrcFromControl(control []byte, ep *StdNetEndpoint) {
    51  	ep.ClearSrc()
    52  
    53  	var (
    54  		hdr  unix.Cmsghdr
    55  		data []byte
    56  		rem  []byte = control
    57  		err  error
    58  	)
    59  
    60  	for len(rem) > unix.SizeofCmsghdr {
    61  		hdr, data, rem, err = unix.ParseOneSocketControlMessage(rem)
    62  		if err != nil {
    63  			return
    64  		}
    65  
    66  		if hdr.Level == unix.IPPROTO_IP &&
    67  			hdr.Type == unix.IP_PKTINFO {
    68  
    69  			if ep.src == nil || cap(ep.src) < unix.CmsgSpace(unix.SizeofInet4Pktinfo) {
    70  				ep.src = make([]byte, 0, unix.CmsgSpace(unix.SizeofInet4Pktinfo))
    71  			}
    72  			ep.src = ep.src[:unix.CmsgSpace(unix.SizeofInet4Pktinfo)]
    73  
    74  			hdrBuf := unsafe.Slice((*byte)(unsafe.Pointer(&hdr)), unix.SizeofCmsghdr)
    75  			copy(ep.src, hdrBuf)
    76  			copy(ep.src[unix.CmsgLen(0):], data)
    77  			return
    78  		}
    79  
    80  		if hdr.Level == unix.IPPROTO_IPV6 &&
    81  			hdr.Type == unix.IPV6_PKTINFO {
    82  
    83  			if ep.src == nil || cap(ep.src) < unix.CmsgSpace(unix.SizeofInet6Pktinfo) {
    84  				ep.src = make([]byte, 0, unix.CmsgSpace(unix.SizeofInet6Pktinfo))
    85  			}
    86  
    87  			ep.src = ep.src[:unix.CmsgSpace(unix.SizeofInet6Pktinfo)]
    88  
    89  			hdrBuf := unsafe.Slice((*byte)(unsafe.Pointer(&hdr)), unix.SizeofCmsghdr)
    90  			copy(ep.src, hdrBuf)
    91  			copy(ep.src[unix.CmsgLen(0):], data)
    92  			return
    93  		}
    94  	}
    95  }
    96  
    97  // setSrcControl sets an IP{V6}_PKTINFO in control based on the source address
    98  // and source ifindex found in ep. control's len will be set to 0 in the event
    99  // that ep is a default value.
   100  func setSrcControl(control *[]byte, ep *StdNetEndpoint) {
   101  	if cap(*control) < len(ep.src) {
   102  		return
   103  	}
   104  	*control = (*control)[:0]
   105  	*control = append(*control, ep.src...)
   106  }
   107  
   108  // stickyControlSize returns the recommended buffer size for pooling sticky
   109  // offloading control data.
   110  var stickyControlSize = unix.CmsgSpace(unix.SizeofInet6Pktinfo)
   111  
   112  const StdNetSupportsStickySockets = true