sockopt_linux.go 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. package internet
  2. import (
  3. "context"
  4. "net"
  5. "runtime"
  6. "strconv"
  7. "strings"
  8. "syscall"
  9. "github.com/xtls/xray-core/common/errors"
  10. "golang.org/x/sys/unix"
  11. )
  12. func bindAddr(fd uintptr, ip []byte, port uint32) error {
  13. setReuseAddr(fd)
  14. setReusePort(fd)
  15. var sockaddr syscall.Sockaddr
  16. switch len(ip) {
  17. case net.IPv4len:
  18. a4 := &syscall.SockaddrInet4{
  19. Port: int(port),
  20. }
  21. copy(a4.Addr[:], ip)
  22. sockaddr = a4
  23. case net.IPv6len:
  24. a6 := &syscall.SockaddrInet6{
  25. Port: int(port),
  26. }
  27. copy(a6.Addr[:], ip)
  28. sockaddr = a6
  29. default:
  30. return errors.New("unexpected length of ip")
  31. }
  32. return syscall.Bind(int(fd), sockaddr)
  33. }
  34. // applyOutboundSocketOptions applies socket options for outbound connection.
  35. // note that unlike other part of Xray, this function needs network with speified network stack(tcp4/tcp6/udp4/udp6)
  36. func applyOutboundSocketOptions(network string, address string, fd uintptr, config *SocketConfig) error {
  37. if config.Mark != 0 {
  38. if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_MARK, int(config.Mark)); err != nil {
  39. return errors.New("failed to set SO_MARK").Base(err)
  40. }
  41. }
  42. if config.Interface != "" {
  43. if err := syscall.BindToDevice(int(fd), config.Interface); err != nil {
  44. return errors.New("failed to set Interface").Base(err)
  45. }
  46. }
  47. if isTCPSocket(network) {
  48. tfo := config.ParseTFOValue()
  49. if tfo > 0 {
  50. tfo = 1
  51. }
  52. if tfo >= 0 {
  53. if err := syscall.SetsockoptInt(int(fd), syscall.SOL_TCP, unix.TCP_FASTOPEN_CONNECT, tfo); err != nil {
  54. return errors.New("failed to set TCP_FASTOPEN_CONNECT", tfo).Base(err)
  55. }
  56. }
  57. if config.TcpCongestion != "" {
  58. if err := syscall.SetsockoptString(int(fd), syscall.SOL_TCP, syscall.TCP_CONGESTION, config.TcpCongestion); err != nil {
  59. return errors.New("failed to set TCP_CONGESTION", err)
  60. }
  61. }
  62. if config.TcpWindowClamp > 0 {
  63. if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_WINDOW_CLAMP, int(config.TcpWindowClamp)); err != nil {
  64. return errors.New("failed to set TCP_WINDOW_CLAMP", err)
  65. }
  66. }
  67. if config.TcpUserTimeout > 0 {
  68. if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_USER_TIMEOUT, int(config.TcpUserTimeout)); err != nil {
  69. return errors.New("failed to set TCP_USER_TIMEOUT", err)
  70. }
  71. }
  72. if config.TcpMaxSeg > 0 {
  73. if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_MAXSEG, int(config.TcpMaxSeg)); err != nil {
  74. return errors.New("failed to set TCP_MAXSEG", err)
  75. }
  76. }
  77. }
  78. if len(config.CustomSockopt) > 0 {
  79. for _, custom := range config.CustomSockopt {
  80. if custom.System != "" && custom.System != runtime.GOOS {
  81. errors.LogDebug(context.Background(), "CustomSockopt system not match: ", "want ", custom.System, " got ", runtime.GOOS)
  82. continue
  83. }
  84. // Skip unwanted network type
  85. // network might be tcp4 or tcp6
  86. // use HasPrefix so that "tcp" can match tcp4/6 with "tcp" if user want to control all tcp (udp is also the same)
  87. // if it is empty, strings.HasPrefix will always return true to make it apply for all networks
  88. if !strings.HasPrefix(network, custom.Network) {
  89. continue
  90. }
  91. var level = 0x6 // default TCP
  92. var opt int
  93. if len(custom.Opt) == 0 {
  94. return errors.New("No opt!")
  95. } else {
  96. opt, _ = strconv.Atoi(custom.Opt)
  97. }
  98. if custom.Level != "" {
  99. level, _ = strconv.Atoi(custom.Level)
  100. }
  101. if custom.Type == "int" {
  102. value, _ := strconv.Atoi(custom.Value)
  103. if err := syscall.SetsockoptInt(int(fd), level, opt, value); err != nil {
  104. return errors.New("failed to set CustomSockoptInt", opt, value, err)
  105. }
  106. } else if custom.Type == "str" {
  107. if err := syscall.SetsockoptString(int(fd), level, opt, custom.Value); err != nil {
  108. return errors.New("failed to set CustomSockoptString", opt, custom.Value, err)
  109. }
  110. } else {
  111. return errors.New("unknown CustomSockopt type:", custom.Type)
  112. }
  113. }
  114. }
  115. if config.Tproxy.IsEnabled() {
  116. if err := syscall.SetsockoptInt(int(fd), syscall.SOL_IP, syscall.IP_TRANSPARENT, 1); err != nil {
  117. return errors.New("failed to set IP_TRANSPARENT").Base(err)
  118. }
  119. }
  120. return nil
  121. }
  122. // applyInboundSocketOptions applies socket options for inbound listener.
  123. // note that unlike other part of Xray, this function needs network with speified network stack(tcp4/tcp6/udp4/udp6)
  124. func applyInboundSocketOptions(network string, fd uintptr, config *SocketConfig) error {
  125. if config.Mark != 0 {
  126. if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_MARK, int(config.Mark)); err != nil {
  127. return errors.New("failed to set SO_MARK").Base(err)
  128. }
  129. }
  130. if isTCPSocket(network) {
  131. tfo := config.ParseTFOValue()
  132. if tfo >= 0 {
  133. if err := syscall.SetsockoptInt(int(fd), syscall.SOL_TCP, unix.TCP_FASTOPEN, tfo); err != nil {
  134. return errors.New("failed to set TCP_FASTOPEN", tfo).Base(err)
  135. }
  136. }
  137. if config.TcpKeepAliveInterval > 0 || config.TcpKeepAliveIdle > 0 {
  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 errors.New("failed to set TCP_KEEPINTVL", err)
  141. }
  142. }
  143. if config.TcpKeepAliveIdle > 0 {
  144. if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_KEEPIDLE, int(config.TcpKeepAliveIdle)); err != nil {
  145. return errors.New("failed to set TCP_KEEPIDLE", err)
  146. }
  147. }
  148. if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, 1); err != nil {
  149. return errors.New("failed to set SO_KEEPALIVE", err)
  150. }
  151. } else if config.TcpKeepAliveInterval < 0 || config.TcpKeepAliveIdle < 0 {
  152. if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, 0); err != nil {
  153. return errors.New("failed to unset SO_KEEPALIVE", err)
  154. }
  155. }
  156. if config.TcpCongestion != "" {
  157. if err := syscall.SetsockoptString(int(fd), syscall.SOL_TCP, syscall.TCP_CONGESTION, config.TcpCongestion); err != nil {
  158. return errors.New("failed to set TCP_CONGESTION", err)
  159. }
  160. }
  161. if config.TcpWindowClamp > 0 {
  162. if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_WINDOW_CLAMP, int(config.TcpWindowClamp)); err != nil {
  163. return errors.New("failed to set TCP_WINDOW_CLAMP", err)
  164. }
  165. }
  166. if config.TcpUserTimeout > 0 {
  167. if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_USER_TIMEOUT, int(config.TcpUserTimeout)); err != nil {
  168. return errors.New("failed to set TCP_USER_TIMEOUT", err)
  169. }
  170. }
  171. if config.TcpMaxSeg > 0 {
  172. if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_MAXSEG, int(config.TcpMaxSeg)); err != nil {
  173. return errors.New("failed to set TCP_MAXSEG", err)
  174. }
  175. }
  176. if len(config.CustomSockopt) > 0 {
  177. for _, custom := range config.CustomSockopt {
  178. if custom.System != "" && custom.System != runtime.GOOS {
  179. errors.LogDebug(context.Background(), "CustomSockopt system not match: ", "want ", custom.System, " got ", runtime.GOOS)
  180. continue
  181. }
  182. // Skip unwanted network type
  183. // network might be tcp4 or tcp6
  184. // use HasPrefix so that "tcp" can match tcp4/6 with "tcp" if user want to control all tcp (udp is also the same)
  185. // if it is empty, strings.HasPrefix will always return true to make it apply for all networks
  186. if !strings.HasPrefix(network, custom.Network) {
  187. continue
  188. }
  189. var level = 0x6 // default TCP
  190. var opt int
  191. if len(custom.Opt) == 0 {
  192. return errors.New("No opt!")
  193. } else {
  194. opt, _ = strconv.Atoi(custom.Opt)
  195. }
  196. if custom.Level != "" {
  197. level, _ = strconv.Atoi(custom.Level)
  198. }
  199. if custom.Type == "int" {
  200. value, _ := strconv.Atoi(custom.Value)
  201. if err := syscall.SetsockoptInt(int(fd), level, opt, value); err != nil {
  202. return errors.New("failed to set CustomSockoptInt", opt, value, err)
  203. }
  204. } else if custom.Type == "str" {
  205. if err := syscall.SetsockoptString(int(fd), level, opt, custom.Value); err != nil {
  206. return errors.New("failed to set CustomSockoptString", opt, custom.Value, err)
  207. }
  208. } else {
  209. return errors.New("unknown CustomSockopt type:", custom.Type)
  210. }
  211. }
  212. }
  213. }
  214. if config.Tproxy.IsEnabled() {
  215. if err := syscall.SetsockoptInt(int(fd), syscall.SOL_IP, syscall.IP_TRANSPARENT, 1); err != nil {
  216. return errors.New("failed to set IP_TRANSPARENT").Base(err)
  217. }
  218. }
  219. if config.ReceiveOriginalDestAddress && isUDPSocket(network) {
  220. err1 := syscall.SetsockoptInt(int(fd), syscall.SOL_IPV6, unix.IPV6_RECVORIGDSTADDR, 1)
  221. err2 := syscall.SetsockoptInt(int(fd), syscall.SOL_IP, syscall.IP_RECVORIGDSTADDR, 1)
  222. if err1 != nil && err2 != nil {
  223. return err1
  224. }
  225. }
  226. if config.V6Only {
  227. if err := syscall.SetsockoptInt(int(fd), syscall.SOL_IPV6, syscall.IPV6_V6ONLY, 1); err != nil {
  228. return errors.New("failed to set IPV6_V6ONLY", err)
  229. }
  230. }
  231. return nil
  232. }
  233. func setReuseAddr(fd uintptr) error {
  234. if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1); err != nil {
  235. return errors.New("failed to set SO_REUSEADDR").Base(err).AtWarning()
  236. }
  237. return nil
  238. }
  239. func setReusePort(fd uintptr) error {
  240. if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, unix.SO_REUSEPORT, 1); err != nil {
  241. return errors.New("failed to set SO_REUSEPORT").Base(err).AtWarning()
  242. }
  243. return nil
  244. }