sticky_linux.go 2.9 KB

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