sockopt_freebsd.go 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  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. soReUsePort = 0x00000200
  34. soReUsePortLB = 0x00010000
  35. )
  36. func ioctl(s uintptr, ioc int, b []byte) error {
  37. if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, s, uintptr(ioc), uintptr(unsafe.Pointer(&b[0]))); errno != 0 {
  38. return error(errno)
  39. }
  40. return nil
  41. }
  42. func (nl *pfiocNatlook) rdPort() int {
  43. return int(binary.BigEndian.Uint16((*[2]byte)(unsafe.Pointer(&nl.Rdport))[:]))
  44. }
  45. func (nl *pfiocNatlook) setPort(remote, local int) {
  46. binary.BigEndian.PutUint16((*[2]byte)(unsafe.Pointer(&nl.Sport))[:], uint16(remote))
  47. binary.BigEndian.PutUint16((*[2]byte)(unsafe.Pointer(&nl.Dport))[:], uint16(local))
  48. }
  49. // OriginalDst uses ioctl to read original destination from /dev/pf
  50. func OriginalDst(la, ra net.Addr) (net.IP, int, error) {
  51. f, err := os.Open("/dev/pf")
  52. if err != nil {
  53. return net.IP{}, -1, newError("failed to open device /dev/pf").Base(err)
  54. }
  55. defer f.Close()
  56. fd := f.Fd()
  57. b := make([]byte, sizeofPfiocNatlook)
  58. nl := (*pfiocNatlook)(unsafe.Pointer(&b[0]))
  59. var raIP, laIP net.IP
  60. var raPort, laPort int
  61. switch la.(type) {
  62. case *net.TCPAddr:
  63. raIP = ra.(*net.TCPAddr).IP
  64. laIP = la.(*net.TCPAddr).IP
  65. raPort = ra.(*net.TCPAddr).Port
  66. laPort = la.(*net.TCPAddr).Port
  67. nl.Proto = syscall.IPPROTO_TCP
  68. case *net.UDPAddr:
  69. raIP = ra.(*net.UDPAddr).IP
  70. laIP = la.(*net.UDPAddr).IP
  71. raPort = ra.(*net.UDPAddr).Port
  72. laPort = la.(*net.UDPAddr).Port
  73. nl.Proto = syscall.IPPROTO_UDP
  74. }
  75. if raIP.To4() != nil {
  76. if laIP.IsUnspecified() {
  77. laIP = net.ParseIP("127.0.0.1")
  78. }
  79. copy(nl.Saddr[:net.IPv4len], raIP.To4())
  80. copy(nl.Daddr[:net.IPv4len], laIP.To4())
  81. nl.Af = syscall.AF_INET
  82. }
  83. if raIP.To16() != nil && raIP.To4() == nil {
  84. if laIP.IsUnspecified() {
  85. laIP = net.ParseIP("::1")
  86. }
  87. copy(nl.Saddr[:], raIP)
  88. copy(nl.Daddr[:], laIP)
  89. nl.Af = syscall.AF_INET6
  90. }
  91. nl.setPort(raPort, laPort)
  92. ioc := uintptr(sysDIOCNATLOOK)
  93. for _, dir := range []byte{sysPFOUT, sysPFIN} {
  94. nl.Direction = dir
  95. err = ioctl(fd, int(ioc), b)
  96. if err == nil || err != syscall.ENOENT {
  97. break
  98. }
  99. }
  100. if err != nil {
  101. return net.IP{}, -1, os.NewSyscallError("ioctl", err)
  102. }
  103. odPort := nl.rdPort()
  104. var odIP net.IP
  105. switch nl.Af {
  106. case syscall.AF_INET:
  107. odIP = make(net.IP, net.IPv4len)
  108. copy(odIP, nl.Rdaddr[:net.IPv4len])
  109. case syscall.AF_INET6:
  110. odIP = make(net.IP, net.IPv6len)
  111. copy(odIP, nl.Rdaddr[:])
  112. }
  113. return odIP, odPort, nil
  114. }
  115. func applyOutboundSocketOptions(network string, address string, fd uintptr, config *SocketConfig) error {
  116. if config.Mark != 0 {
  117. if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_USER_COOKIE, int(config.Mark)); err != nil {
  118. return newError("failed to set SO_USER_COOKIE").Base(err)
  119. }
  120. }
  121. if isTCPSocket(network) {
  122. switch config.Tfo {
  123. case SocketConfig_Enable:
  124. if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_FASTOPEN, 1); err != nil {
  125. return newError("failed to set TCP_FASTOPEN_CONNECT=1").Base(err)
  126. }
  127. case SocketConfig_Disable:
  128. if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_FASTOPEN, 0); err != nil {
  129. return newError("failed to set TCP_FASTOPEN_CONNECT=0").Base(err)
  130. }
  131. }
  132. if config.TcpKeepAliveIdle > 0 || config.TcpKeepAliveInterval > 0 {
  133. if config.TcpKeepAliveIdle > 0 {
  134. if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_KEEPIDLE, int(config.TcpKeepAliveIdle)); err != nil {
  135. return newError("failed to set TCP_KEEPIDLE").Base(err)
  136. }
  137. }
  138. if config.TcpKeepAliveInterval > 0 {
  139. if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, int(config.TcpKeepAliveInterval)); err != nil {
  140. return newError("failed to set TCP_KEEPINTVL").Base(err)
  141. }
  142. }
  143. if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, 1); err != nil {
  144. return newError("failed to set SO_KEEPALIVE").Base(err)
  145. }
  146. }
  147. }
  148. if config.Tproxy.IsEnabled() {
  149. ip, _, _ := net.SplitHostPort(address)
  150. if net.ParseIP(ip).To4() != nil {
  151. if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_BINDANY, 1); err != nil {
  152. return newError("failed to set outbound IP_BINDANY").Base(err)
  153. }
  154. } else {
  155. if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IPV6, syscall.IPV6_BINDANY, 1); err != nil {
  156. return newError("failed to set outbound IPV6_BINDANY").Base(err)
  157. }
  158. }
  159. }
  160. if config.SocketTxBufSize != 0 {
  161. if err := unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_SNDBUF, int(config.SocketTxBufSize)); err != nil {
  162. return newError("failed to set SO_SNDBUF/SO_SNDBUFFORCE").Base(err)
  163. }
  164. }
  165. if config.SocketRxBufSize != 0 {
  166. if err := unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_RCVBUF, int(config.SocketRxBufSize)); err != nil {
  167. return newError("failed to set SO_RCVBUF/SO_RCVBUFFORCE").Base(err)
  168. }
  169. }
  170. return nil
  171. }
  172. func applyInboundSocketOptions(network string, fd uintptr, config *SocketConfig) error {
  173. if config.Mark != 0 {
  174. if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_USER_COOKIE, int(config.Mark)); err != nil {
  175. return newError("failed to set SO_USER_COOKIE").Base(err)
  176. }
  177. }
  178. if isTCPSocket(network) {
  179. switch config.Tfo {
  180. case SocketConfig_Enable:
  181. if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_FASTOPEN, 1); err != nil {
  182. return newError("failed to set TCP_FASTOPEN=1").Base(err)
  183. }
  184. case SocketConfig_Disable:
  185. if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_FASTOPEN, 0); err != nil {
  186. return newError("failed to set TCP_FASTOPEN=0").Base(err)
  187. }
  188. }
  189. if config.TcpKeepAliveIdle > 0 || config.TcpKeepAliveInterval > 0 {
  190. if config.TcpKeepAliveIdle > 0 {
  191. if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_KEEPIDLE, int(config.TcpKeepAliveIdle)); err != nil {
  192. return newError("failed to set TCP_KEEPIDLE").Base(err)
  193. }
  194. }
  195. if config.TcpKeepAliveInterval > 0 {
  196. if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, int(config.TcpKeepAliveInterval)); err != nil {
  197. return newError("failed to set TCP_KEEPINTVL").Base(err)
  198. }
  199. }
  200. if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, 1); err != nil {
  201. return newError("failed to set SO_KEEPALIVE").Base(err)
  202. }
  203. }
  204. }
  205. if config.Tproxy.IsEnabled() {
  206. if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IPV6, syscall.IPV6_BINDANY, 1); err != nil {
  207. if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_BINDANY, 1); err != nil {
  208. return newError("failed to set inbound IP_BINDANY").Base(err)
  209. }
  210. }
  211. }
  212. if config.SocketTxBufSize != 0 {
  213. if err := unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_SNDBUF, int(config.SocketTxBufSize)); err != nil {
  214. return newError("failed to set SO_SNDBUF/SO_SNDBUFFORCE").Base(err)
  215. }
  216. }
  217. if config.SocketRxBufSize != 0 {
  218. if err := unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_RCVBUF, int(config.SocketRxBufSize)); err != nil {
  219. return newError("failed to set SO_RCVBUF/SO_RCVBUFFORCE").Base(err)
  220. }
  221. }
  222. return nil
  223. }
  224. func bindAddr(fd uintptr, ip []byte, port uint32) error {
  225. setReuseAddr(fd)
  226. setReusePort(fd)
  227. var sockaddr syscall.Sockaddr
  228. switch len(ip) {
  229. case net.IPv4len:
  230. a4 := &syscall.SockaddrInet4{
  231. Port: int(port),
  232. }
  233. copy(a4.Addr[:], ip)
  234. sockaddr = a4
  235. case net.IPv6len:
  236. a6 := &syscall.SockaddrInet6{
  237. Port: int(port),
  238. }
  239. copy(a6.Addr[:], ip)
  240. sockaddr = a6
  241. default:
  242. return newError("unexpected length of ip")
  243. }
  244. return syscall.Bind(int(fd), sockaddr)
  245. }
  246. func setReuseAddr(fd uintptr) error {
  247. if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1); err != nil {
  248. return newError("failed to set SO_REUSEADDR").Base(err).AtWarning()
  249. }
  250. return nil
  251. }
  252. func setReusePort(fd uintptr) error {
  253. if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, soReUsePortLB, 1); err != nil {
  254. if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, soReUsePort, 1); err != nil {
  255. return newError("failed to set SO_REUSEPORT").Base(err).AtWarning()
  256. }
  257. }
  258. return nil
  259. }