bind_std.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513
  1. // SPDX-License-Identifier: MIT
  2. //
  3. // Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved.
  4. package conn
  5. import (
  6. "context"
  7. "errors"
  8. "net"
  9. "net/netip"
  10. "runtime"
  11. "strconv"
  12. "sync"
  13. "syscall"
  14. "golang.org/x/net/ipv4"
  15. "golang.org/x/net/ipv6"
  16. "golang.org/x/sys/unix"
  17. )
  18. var (
  19. _ Bind = (*StdNetBind)(nil)
  20. )
  21. // StdNetBind implements Bind for all platforms. While Windows has its own Bind
  22. // (see bind_windows.go), it may fall back to StdNetBind.
  23. // TODO: Remove usage of ipv{4,6}.PacketConn when net.UDPConn has comparable
  24. // methods for sending and receiving multiple datagrams per-syscall. See the
  25. // proposal in https://github.com/golang/go/issues/45886#issuecomment-1218301564.
  26. type StdNetBind struct {
  27. mu sync.Mutex // protects all fields except as specified
  28. ipv4 *net.UDPConn
  29. ipv6 *net.UDPConn
  30. ipv4PC *ipv4.PacketConn // will be nil on non-Linux
  31. ipv6PC *ipv6.PacketConn // will be nil on non-Linux
  32. // these three fields are not guarded by mu
  33. udpAddrPool sync.Pool
  34. ipv4MsgsPool sync.Pool
  35. ipv6MsgsPool sync.Pool
  36. blackhole4 bool
  37. blackhole6 bool
  38. listenAddr4 string
  39. listenAddr6 string
  40. bindV4 bool
  41. bindV6 bool
  42. reusePort bool
  43. }
  44. func newStdNetBind() *StdNetBind {
  45. return &StdNetBind{
  46. udpAddrPool: sync.Pool{
  47. New: func() any {
  48. return &net.UDPAddr{
  49. IP: make([]byte, 16),
  50. }
  51. },
  52. },
  53. ipv4MsgsPool: sync.Pool{
  54. New: func() any {
  55. msgs := make([]ipv4.Message, IdealBatchSize)
  56. for i := range msgs {
  57. msgs[i].Buffers = make(net.Buffers, 1)
  58. msgs[i].OOB = make([]byte, srcControlSize)
  59. }
  60. return &msgs
  61. },
  62. },
  63. ipv6MsgsPool: sync.Pool{
  64. New: func() any {
  65. msgs := make([]ipv6.Message, IdealBatchSize)
  66. for i := range msgs {
  67. msgs[i].Buffers = make(net.Buffers, 1)
  68. msgs[i].OOB = make([]byte, srcControlSize)
  69. }
  70. return &msgs
  71. },
  72. },
  73. bindV4: true,
  74. bindV6: true,
  75. reusePort: false,
  76. }
  77. }
  78. // NewStdNetBind creates a bind that listens on all interfaces.
  79. func NewStdNetBind() *StdNetBind {
  80. return newStdNetBind()
  81. }
  82. // NewStdNetBindForAddr creates a bind that listens on a specific address.
  83. // If addr is IPv4, only the IPv4 socket will be created. For IPv6, only the
  84. // IPv6 socket will be created.
  85. func NewStdNetBindForAddr(addr netip.Addr, reusePort bool) *StdNetBind {
  86. b := newStdNetBind()
  87. if addr.IsValid() {
  88. if addr.Is4() {
  89. b.listenAddr4 = addr.Unmap().String()
  90. b.bindV4 = true
  91. b.bindV6 = false
  92. } else {
  93. b.listenAddr6 = addr.Unmap().String()
  94. b.bindV6 = true
  95. b.bindV4 = false
  96. }
  97. }
  98. b.reusePort = reusePort
  99. return b
  100. }
  101. type StdNetEndpoint struct {
  102. // AddrPort is the endpoint destination.
  103. netip.AddrPort
  104. // src is the current sticky source address and interface index, if supported.
  105. src struct {
  106. netip.Addr
  107. ifidx int32
  108. }
  109. }
  110. var (
  111. _ Bind = (*StdNetBind)(nil)
  112. _ Endpoint = &StdNetEndpoint{}
  113. )
  114. func (*StdNetBind) ParseEndpoint(s string) (Endpoint, error) {
  115. e, err := netip.ParseAddrPort(s)
  116. if err != nil {
  117. return nil, err
  118. }
  119. return &StdNetEndpoint{
  120. AddrPort: e,
  121. }, nil
  122. }
  123. func (e *StdNetEndpoint) ClearSrc() {
  124. e.src.ifidx = 0
  125. e.src.Addr = netip.Addr{}
  126. }
  127. func (e *StdNetEndpoint) DstIP() netip.Addr {
  128. return e.AddrPort.Addr()
  129. }
  130. func (e *StdNetEndpoint) SrcIP() netip.Addr {
  131. return e.src.Addr
  132. }
  133. func (e *StdNetEndpoint) SrcIfidx() int32 {
  134. return e.src.ifidx
  135. }
  136. func (e *StdNetEndpoint) DstToBytes() []byte {
  137. b, _ := e.AddrPort.MarshalBinary()
  138. return b
  139. }
  140. func (e *StdNetEndpoint) DstToString() string {
  141. return e.AddrPort.String()
  142. }
  143. func (e *StdNetEndpoint) SrcToString() string {
  144. return e.src.Addr.String()
  145. }
  146. func (s *StdNetBind) listenNet(network string, host string, port int) (*net.UDPConn, int, error) {
  147. lc := listenConfig()
  148. if s.reusePort {
  149. base := lc.Control
  150. lc.Control = func(network, address string, c syscall.RawConn) error {
  151. if base != nil {
  152. if err := base(network, address, c); err != nil {
  153. return err
  154. }
  155. }
  156. return c.Control(func(fd uintptr) {
  157. _ = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEPORT, 1)
  158. })
  159. }
  160. }
  161. addr := ":" + strconv.Itoa(port)
  162. if host != "" {
  163. addr = net.JoinHostPort(host, strconv.Itoa(port))
  164. }
  165. conn, err := lc.ListenPacket(context.Background(), network, addr)
  166. if err != nil {
  167. return nil, 0, err
  168. }
  169. // Retrieve port.
  170. laddr := conn.LocalAddr()
  171. uaddr, err := net.ResolveUDPAddr(
  172. laddr.Network(),
  173. laddr.String(),
  174. )
  175. if err != nil {
  176. return nil, 0, err
  177. }
  178. return conn.(*net.UDPConn), uaddr.Port, nil
  179. }
  180. func (s *StdNetBind) openIPv4(port int) (*net.UDPConn, *ipv4.PacketConn, int, error) {
  181. if !s.bindV4 {
  182. return nil, nil, port, nil
  183. }
  184. host := s.listenAddr4
  185. conn, actualPort, err := s.listenNet("udp4", host, port)
  186. if err != nil {
  187. if errors.Is(err, syscall.EAFNOSUPPORT) {
  188. return nil, nil, port, nil
  189. }
  190. return nil, nil, port, err
  191. }
  192. if runtime.GOOS != "linux" {
  193. return conn, nil, actualPort, nil
  194. }
  195. pc := ipv4.NewPacketConn(conn)
  196. return conn, pc, actualPort, nil
  197. }
  198. func (s *StdNetBind) openIPv6(port int) (*net.UDPConn, *ipv6.PacketConn, int, error) {
  199. if !s.bindV6 {
  200. return nil, nil, port, nil
  201. }
  202. host := s.listenAddr6
  203. conn, actualPort, err := s.listenNet("udp6", host, port)
  204. if err != nil {
  205. if errors.Is(err, syscall.EAFNOSUPPORT) {
  206. return nil, nil, port, nil
  207. }
  208. return nil, nil, port, err
  209. }
  210. if runtime.GOOS != "linux" {
  211. return conn, nil, actualPort, nil
  212. }
  213. pc := ipv6.NewPacketConn(conn)
  214. return conn, pc, actualPort, nil
  215. }
  216. func (s *StdNetBind) Open(uport uint16) ([]ReceiveFunc, uint16, error) {
  217. s.mu.Lock()
  218. defer s.mu.Unlock()
  219. var err error
  220. var tries int
  221. if s.ipv4 != nil || s.ipv6 != nil {
  222. return nil, 0, ErrBindAlreadyOpen
  223. }
  224. // Attempt to open ipv4 and ipv6 listeners on the same port.
  225. // If uport is 0, we can retry on failure.
  226. again:
  227. port := int(uport)
  228. var v4conn *net.UDPConn
  229. var v6conn *net.UDPConn
  230. var v4pc *ipv4.PacketConn
  231. var v6pc *ipv6.PacketConn
  232. v4conn, v4pc, port, err = s.openIPv4(port)
  233. if err != nil {
  234. return nil, 0, err
  235. }
  236. // Listen on the same port as we're using for ipv4.
  237. v6conn, v6pc, port, err = s.openIPv6(port)
  238. if uport == 0 && errors.Is(err, syscall.EADDRINUSE) && tries < 100 {
  239. if v4conn != nil {
  240. v4conn.Close()
  241. }
  242. tries++
  243. goto again
  244. }
  245. if err != nil {
  246. if v4conn != nil {
  247. v4conn.Close()
  248. }
  249. return nil, 0, err
  250. }
  251. var fns []ReceiveFunc
  252. if v4conn != nil {
  253. s.ipv4 = v4conn
  254. if v4pc != nil {
  255. s.ipv4PC = v4pc
  256. }
  257. fns = append(fns, s.makeReceiveIPv4(v4pc, v4conn))
  258. }
  259. if v6conn != nil {
  260. s.ipv6 = v6conn
  261. if v6pc != nil {
  262. s.ipv6PC = v6pc
  263. }
  264. fns = append(fns, s.makeReceiveIPv6(v6pc, v6conn))
  265. }
  266. if len(fns) == 0 {
  267. return nil, 0, syscall.EAFNOSUPPORT
  268. }
  269. return fns, uint16(port), nil
  270. }
  271. func (s *StdNetBind) makeReceiveIPv4(pc *ipv4.PacketConn, conn *net.UDPConn) ReceiveFunc {
  272. return func(bufs [][]byte, sizes []int, eps []Endpoint) (n int, err error) {
  273. msgs := s.ipv4MsgsPool.Get().(*[]ipv4.Message)
  274. defer s.ipv4MsgsPool.Put(msgs)
  275. for i := range bufs {
  276. (*msgs)[i].Buffers[0] = bufs[i]
  277. }
  278. var numMsgs int
  279. if runtime.GOOS == "linux" && pc != nil {
  280. numMsgs, err = pc.ReadBatch(*msgs, 0)
  281. if err != nil {
  282. return 0, err
  283. }
  284. } else {
  285. msg := &(*msgs)[0]
  286. msg.N, msg.NN, _, msg.Addr, err = conn.ReadMsgUDP(msg.Buffers[0], msg.OOB)
  287. if err != nil {
  288. return 0, err
  289. }
  290. numMsgs = 1
  291. }
  292. for i := 0; i < numMsgs; i++ {
  293. msg := &(*msgs)[i]
  294. sizes[i] = msg.N
  295. addrPort := msg.Addr.(*net.UDPAddr).AddrPort()
  296. ep := &StdNetEndpoint{AddrPort: addrPort} // TODO: remove allocation
  297. getSrcFromControl(msg.OOB[:msg.NN], ep)
  298. eps[i] = ep
  299. }
  300. return numMsgs, nil
  301. }
  302. }
  303. func (s *StdNetBind) makeReceiveIPv6(pc *ipv6.PacketConn, conn *net.UDPConn) ReceiveFunc {
  304. return func(bufs [][]byte, sizes []int, eps []Endpoint) (n int, err error) {
  305. msgs := s.ipv6MsgsPool.Get().(*[]ipv6.Message)
  306. defer s.ipv6MsgsPool.Put(msgs)
  307. for i := range bufs {
  308. (*msgs)[i].Buffers[0] = bufs[i]
  309. }
  310. var numMsgs int
  311. if runtime.GOOS == "linux" && pc != nil {
  312. numMsgs, err = pc.ReadBatch(*msgs, 0)
  313. if err != nil {
  314. return 0, err
  315. }
  316. } else {
  317. msg := &(*msgs)[0]
  318. msg.N, msg.NN, _, msg.Addr, err = conn.ReadMsgUDP(msg.Buffers[0], msg.OOB)
  319. if err != nil {
  320. return 0, err
  321. }
  322. numMsgs = 1
  323. }
  324. for i := 0; i < numMsgs; i++ {
  325. msg := &(*msgs)[i]
  326. sizes[i] = msg.N
  327. addrPort := msg.Addr.(*net.UDPAddr).AddrPort()
  328. ep := &StdNetEndpoint{AddrPort: addrPort} // TODO: remove allocation
  329. getSrcFromControl(msg.OOB[:msg.NN], ep)
  330. eps[i] = ep
  331. }
  332. return numMsgs, nil
  333. }
  334. }
  335. // TODO: When all Binds handle IdealBatchSize, remove this dynamic function and
  336. // rename the IdealBatchSize constant to BatchSize.
  337. func (s *StdNetBind) BatchSize() int {
  338. if runtime.GOOS == "linux" {
  339. return IdealBatchSize
  340. }
  341. return 1
  342. }
  343. func (s *StdNetBind) Close() error {
  344. s.mu.Lock()
  345. defer s.mu.Unlock()
  346. var err1, err2 error
  347. if s.ipv4 != nil {
  348. err1 = s.ipv4.Close()
  349. s.ipv4 = nil
  350. s.ipv4PC = nil
  351. }
  352. if s.ipv6 != nil {
  353. err2 = s.ipv6.Close()
  354. s.ipv6 = nil
  355. s.ipv6PC = nil
  356. }
  357. s.blackhole4 = false
  358. s.blackhole6 = false
  359. if err1 != nil {
  360. return err1
  361. }
  362. return err2
  363. }
  364. func (s *StdNetBind) Send(bufs [][]byte, endpoint Endpoint) error {
  365. s.mu.Lock()
  366. blackhole := s.blackhole4
  367. conn := s.ipv4
  368. var (
  369. pc4 *ipv4.PacketConn
  370. pc6 *ipv6.PacketConn
  371. )
  372. is6 := false
  373. if endpoint.DstIP().Is6() {
  374. blackhole = s.blackhole6
  375. conn = s.ipv6
  376. pc6 = s.ipv6PC
  377. is6 = true
  378. } else {
  379. pc4 = s.ipv4PC
  380. }
  381. s.mu.Unlock()
  382. if blackhole {
  383. return nil
  384. }
  385. if conn == nil {
  386. return syscall.EAFNOSUPPORT
  387. }
  388. if is6 {
  389. return s.send6(conn, pc6, endpoint, bufs)
  390. } else {
  391. return s.send4(conn, pc4, endpoint, bufs)
  392. }
  393. }
  394. func (s *StdNetBind) send4(conn *net.UDPConn, pc *ipv4.PacketConn, ep Endpoint, bufs [][]byte) error {
  395. ua := s.udpAddrPool.Get().(*net.UDPAddr)
  396. as4 := ep.DstIP().As4()
  397. copy(ua.IP, as4[:])
  398. ua.IP = ua.IP[:4]
  399. ua.Port = int(ep.(*StdNetEndpoint).Port())
  400. msgs := s.ipv4MsgsPool.Get().(*[]ipv4.Message)
  401. for i, buf := range bufs {
  402. (*msgs)[i].Buffers[0] = buf
  403. (*msgs)[i].Addr = ua
  404. setSrcControl(&(*msgs)[i].OOB, ep.(*StdNetEndpoint))
  405. }
  406. var (
  407. n int
  408. err error
  409. start int
  410. )
  411. if runtime.GOOS == "linux" && pc != nil {
  412. for {
  413. n, err = pc.WriteBatch((*msgs)[start:len(bufs)], 0)
  414. if err != nil || n == len((*msgs)[start:len(bufs)]) {
  415. break
  416. }
  417. start += n
  418. }
  419. } else {
  420. for i, buf := range bufs {
  421. _, _, err = conn.WriteMsgUDP(buf, (*msgs)[i].OOB, ua)
  422. if err != nil {
  423. break
  424. }
  425. }
  426. }
  427. s.udpAddrPool.Put(ua)
  428. s.ipv4MsgsPool.Put(msgs)
  429. return err
  430. }
  431. func (s *StdNetBind) send6(conn *net.UDPConn, pc *ipv6.PacketConn, ep Endpoint, bufs [][]byte) error {
  432. ua := s.udpAddrPool.Get().(*net.UDPAddr)
  433. as16 := ep.DstIP().As16()
  434. copy(ua.IP, as16[:])
  435. ua.IP = ua.IP[:16]
  436. ua.Port = int(ep.(*StdNetEndpoint).Port())
  437. msgs := s.ipv6MsgsPool.Get().(*[]ipv6.Message)
  438. for i, buf := range bufs {
  439. (*msgs)[i].Buffers[0] = buf
  440. (*msgs)[i].Addr = ua
  441. setSrcControl(&(*msgs)[i].OOB, ep.(*StdNetEndpoint))
  442. }
  443. var (
  444. n int
  445. err error
  446. start int
  447. )
  448. if runtime.GOOS == "linux" && pc != nil {
  449. for {
  450. n, err = pc.WriteBatch((*msgs)[start:len(bufs)], 0)
  451. if err != nil || n == len((*msgs)[start:len(bufs)]) {
  452. break
  453. }
  454. start += n
  455. }
  456. } else {
  457. for i, buf := range bufs {
  458. _, _, err = conn.WriteMsgUDP(buf, (*msgs)[i].OOB, ua)
  459. if err != nil {
  460. break
  461. }
  462. }
  463. }
  464. s.udpAddrPool.Put(ua)
  465. s.ipv6MsgsPool.Put(msgs)
  466. return err
  467. }