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