sockopt_freebsd.go 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. package internet
  2. import (
  3. "encoding/binary"
  4. "net"
  5. "os"
  6. "syscall"
  7. "unsafe"
  8. "golang.org/x/sys/unix"
  9. )
  10. const (
  11. sysPFINOUT = 0x0
  12. sysPFIN = 0x1
  13. sysPFOUT = 0x2
  14. sysPFFWD = 0x3
  15. sysDIOCNATLOOK = 0xc04c4417
  16. )
  17. type pfiocNatlook struct {
  18. Saddr [16]byte /* pf_addr */
  19. Daddr [16]byte /* pf_addr */
  20. Rsaddr [16]byte /* pf_addr */
  21. Rdaddr [16]byte /* pf_addr */
  22. Sport uint16
  23. Dport uint16
  24. Rsport uint16
  25. Rdport uint16
  26. Af uint8
  27. Proto uint8
  28. Direction uint8
  29. Pad [1]byte
  30. }
  31. const (
  32. sizeofPfiocNatlook = 0x4c
  33. soReUsePortLB = 0x00010000
  34. )
  35. func ioctl(s uintptr, ioc int, b []byte) error {
  36. if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, s, uintptr(ioc), uintptr(unsafe.Pointer(&b[0]))); errno != 0 {
  37. return error(errno)
  38. }
  39. return nil
  40. }
  41. func (nl *pfiocNatlook) rdPort() int {
  42. return int(binary.BigEndian.Uint16((*[2]byte)(unsafe.Pointer(&nl.Rdport))[:]))
  43. }
  44. func (nl *pfiocNatlook) setPort(remote, local int) {
  45. binary.BigEndian.PutUint16((*[2]byte)(unsafe.Pointer(&nl.Sport))[:], uint16(remote))
  46. binary.BigEndian.PutUint16((*[2]byte)(unsafe.Pointer(&nl.Dport))[:], uint16(local))
  47. }
  48. // OriginalDst uses ioctl to read original destination from /dev/pf
  49. func OriginalDst(la, ra net.Addr) (net.IP, int, error) {
  50. f, err := os.Open("/dev/pf")
  51. if err != nil {
  52. return net.IP{}, -1, newError("failed to open device /dev/pf").Base(err)
  53. }
  54. defer f.Close()
  55. fd := f.Fd()
  56. b := make([]byte, sizeofPfiocNatlook)
  57. nl := (*pfiocNatlook)(unsafe.Pointer(&b[0]))
  58. var raIP, laIP net.IP
  59. var raPort, laPort int
  60. switch la.(type) {
  61. case *net.TCPAddr:
  62. raIP = ra.(*net.TCPAddr).IP
  63. laIP = la.(*net.TCPAddr).IP
  64. raPort = ra.(*net.TCPAddr).Port
  65. laPort = la.(*net.TCPAddr).Port
  66. nl.Proto = syscall.IPPROTO_TCP
  67. case *net.UDPAddr:
  68. raIP = ra.(*net.UDPAddr).IP
  69. laIP = la.(*net.UDPAddr).IP
  70. raPort = ra.(*net.UDPAddr).Port
  71. laPort = la.(*net.UDPAddr).Port
  72. nl.Proto = syscall.IPPROTO_UDP
  73. }
  74. if raIP.To4() != nil {
  75. if laIP.IsUnspecified() {
  76. laIP = net.ParseIP("127.0.0.1")
  77. }
  78. copy(nl.Saddr[:net.IPv4len], raIP.To4())
  79. copy(nl.Daddr[:net.IPv4len], laIP.To4())
  80. nl.Af = syscall.AF_INET
  81. }
  82. if raIP.To16() != nil && raIP.To4() == nil {
  83. if laIP.IsUnspecified() {
  84. laIP = net.ParseIP("::1")
  85. }
  86. copy(nl.Saddr[:], raIP)
  87. copy(nl.Daddr[:], laIP)
  88. nl.Af = syscall.AF_INET6
  89. }
  90. nl.setPort(raPort, laPort)
  91. ioc := uintptr(sysDIOCNATLOOK)
  92. for _, dir := range []byte{sysPFOUT, sysPFIN} {
  93. nl.Direction = dir
  94. err = ioctl(fd, int(ioc), b)
  95. if err == nil || err != syscall.ENOENT {
  96. break
  97. }
  98. }
  99. if err != nil {
  100. return net.IP{}, -1, os.NewSyscallError("ioctl", err)
  101. }
  102. odPort := nl.rdPort()
  103. var odIP net.IP
  104. switch nl.Af {
  105. case syscall.AF_INET:
  106. odIP = make(net.IP, net.IPv4len)
  107. copy(odIP, nl.Rdaddr[:net.IPv4len])
  108. case syscall.AF_INET6:
  109. odIP = make(net.IP, net.IPv6len)
  110. copy(odIP, nl.Rdaddr[:])
  111. }
  112. return odIP, odPort, nil
  113. }
  114. func applyOutboundSocketOptions(network string, address string, fd uintptr, config *SocketConfig) error {
  115. if config.Mark != 0 {
  116. if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_USER_COOKIE, int(config.Mark)); err != nil {
  117. return newError("failed to set SO_USER_COOKIE").Base(err)
  118. }
  119. }
  120. if isTCPSocket(network) {
  121. switch config.Tfo {
  122. case SocketConfig_Enable:
  123. if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_FASTOPEN, 1); err != nil {
  124. return newError("failed to set TCP_FASTOPEN_CONNECT=1").Base(err)
  125. }
  126. case SocketConfig_Disable:
  127. if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_FASTOPEN, 0); err != nil {
  128. return newError("failed to set TCP_FASTOPEN_CONNECT=0").Base(err)
  129. }
  130. }
  131. }
  132. if config.Tproxy.IsEnabled() {
  133. ip, _, _ := net.SplitHostPort(address)
  134. if net.ParseIP(ip).To4() != nil {
  135. if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_BINDANY, 1); err != nil {
  136. return newError("failed to set outbound IP_BINDANY").Base(err)
  137. }
  138. } else {
  139. if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IPV6, syscall.IPV6_BINDANY, 1); err != nil {
  140. return newError("failed to set outbound IPV6_BINDANY").Base(err)
  141. }
  142. }
  143. }
  144. return nil
  145. }
  146. func applyInboundSocketOptions(network string, fd uintptr, config *SocketConfig) error {
  147. if config.Mark != 0 {
  148. if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_USER_COOKIE, int(config.Mark)); err != nil {
  149. return newError("failed to set SO_USER_COOKIE").Base(err)
  150. }
  151. }
  152. if isTCPSocket(network) {
  153. switch config.Tfo {
  154. case SocketConfig_Enable:
  155. if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_FASTOPEN, 1); err != nil {
  156. return newError("failed to set TCP_FASTOPEN=1").Base(err)
  157. }
  158. case SocketConfig_Disable:
  159. if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_FASTOPEN, 0); err != nil {
  160. return newError("failed to set TCP_FASTOPEN=0").Base(err)
  161. }
  162. }
  163. }
  164. if config.Tproxy.IsEnabled() {
  165. if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IPV6, syscall.IPV6_BINDANY, 1); err != nil {
  166. if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_BINDANY, 1); err != nil {
  167. return newError("failed to set inbound IP_BINDANY").Base(err)
  168. }
  169. }
  170. }
  171. return nil
  172. }
  173. func bindAddr(fd uintptr, ip []byte, port uint32) error {
  174. if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1); err != nil {
  175. return newError("failed to set resuse_addr").Base(err).AtWarning()
  176. }
  177. if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, soReUsePortLB, 1); err != nil {
  178. return newError("failed to set resuse_port").Base(err).AtWarning()
  179. }
  180. var sockaddr syscall.Sockaddr
  181. switch len(ip) {
  182. case net.IPv4len:
  183. a4 := &syscall.SockaddrInet4{
  184. Port: int(port),
  185. }
  186. copy(a4.Addr[:], ip)
  187. sockaddr = a4
  188. case net.IPv6len:
  189. a6 := &syscall.SockaddrInet6{
  190. Port: int(port),
  191. }
  192. copy(a6.Addr[:], ip)
  193. sockaddr = a6
  194. default:
  195. return newError("unexpected length of ip")
  196. }
  197. return syscall.Bind(int(fd), sockaddr)
  198. }