sticky_linux.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. //go:build linux && !android
  2. // SPDX-License-Identifier: MIT
  3. //
  4. // Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved.
  5. package conn
  6. import (
  7. "net/netip"
  8. "unsafe"
  9. "golang.org/x/sys/unix"
  10. )
  11. // getSrcFromControl parses the control for PKTINFO and if found updates ep with
  12. // the source information found.
  13. func getSrcFromControl(control []byte, ep *StdNetEndpoint) {
  14. ep.ClearSrc()
  15. var (
  16. hdr unix.Cmsghdr
  17. data []byte
  18. rem []byte = control
  19. err error
  20. )
  21. for len(rem) > unix.SizeofCmsghdr {
  22. hdr, data, rem, err = unix.ParseOneSocketControlMessage(rem)
  23. if err != nil {
  24. return
  25. }
  26. if hdr.Level == unix.IPPROTO_IP &&
  27. hdr.Type == unix.IP_PKTINFO {
  28. info := pktInfoFromBuf[unix.Inet4Pktinfo](data)
  29. ep.src.Addr = netip.AddrFrom4(info.Spec_dst)
  30. ep.src.ifidx = info.Ifindex
  31. return
  32. }
  33. if hdr.Level == unix.IPPROTO_IPV6 &&
  34. hdr.Type == unix.IPV6_PKTINFO {
  35. info := pktInfoFromBuf[unix.Inet6Pktinfo](data)
  36. ep.src.Addr = netip.AddrFrom16(info.Addr)
  37. ep.src.ifidx = int32(info.Ifindex)
  38. return
  39. }
  40. }
  41. }
  42. // pktInfoFromBuf returns type T populated from the provided buf via copy(). It
  43. // panics if buf is of insufficient size.
  44. func pktInfoFromBuf[T unix.Inet4Pktinfo | unix.Inet6Pktinfo](buf []byte) (t T) {
  45. size := int(unsafe.Sizeof(t))
  46. if len(buf) < size {
  47. panic("pktInfoFromBuf: buffer too small")
  48. }
  49. copy(unsafe.Slice((*byte)(unsafe.Pointer(&t)), size), buf)
  50. return t
  51. }
  52. // setSrcControl sets an IP{V6}_PKTINFO in control based on the source address
  53. // and source ifindex found in ep. control's len will be set to 0 in the event
  54. // that ep is a default value.
  55. func setSrcControl(control *[]byte, ep *StdNetEndpoint) {
  56. *control = (*control)[:cap(*control)]
  57. if len(*control) < int(unsafe.Sizeof(unix.Cmsghdr{})) {
  58. *control = (*control)[:0]
  59. return
  60. }
  61. if ep.src.ifidx == 0 && !ep.SrcIP().IsValid() {
  62. *control = (*control)[:0]
  63. return
  64. }
  65. if len(*control) < srcControlSize {
  66. *control = (*control)[:0]
  67. return
  68. }
  69. hdr := (*unix.Cmsghdr)(unsafe.Pointer(&(*control)[0]))
  70. if ep.SrcIP().Is4() {
  71. hdr.Level = unix.IPPROTO_IP
  72. hdr.Type = unix.IP_PKTINFO
  73. hdr.SetLen(unix.CmsgLen(unix.SizeofInet4Pktinfo))
  74. info := (*unix.Inet4Pktinfo)(unsafe.Pointer(&(*control)[unix.SizeofCmsghdr]))
  75. info.Ifindex = ep.src.ifidx
  76. if ep.SrcIP().IsValid() {
  77. info.Spec_dst = ep.SrcIP().As4()
  78. }
  79. *control = (*control)[:unix.CmsgSpace(unix.SizeofInet4Pktinfo)]
  80. } else {
  81. hdr.Level = unix.IPPROTO_IPV6
  82. hdr.Type = unix.IPV6_PKTINFO
  83. hdr.SetLen(unix.CmsgLen(unix.SizeofInet6Pktinfo))
  84. info := (*unix.Inet6Pktinfo)(unsafe.Pointer(&(*control)[unix.SizeofCmsghdr]))
  85. info.Ifindex = uint32(ep.src.ifidx)
  86. if ep.SrcIP().IsValid() {
  87. info.Addr = ep.SrcIP().As16()
  88. }
  89. *control = (*control)[:unix.CmsgSpace(unix.SizeofInet6Pktinfo)]
  90. }
  91. }
  92. var srcControlSize = unix.CmsgSpace(unix.SizeofInet6Pktinfo)
  93. const StdNetSupportsStickySockets = true