1
0

bind_std.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573
  1. /* SPDX-License-Identifier: MIT
  2. *
  3. * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved.
  4. */
  5. package conn
  6. import (
  7. "context"
  8. "errors"
  9. "fmt"
  10. "net"
  11. "net/netip"
  12. "runtime"
  13. "strconv"
  14. "sync"
  15. "syscall"
  16. "golang.org/x/net/ipv4"
  17. "golang.org/x/net/ipv6"
  18. )
  19. var (
  20. _ Bind = (*StdNetBind)(nil)
  21. )
  22. // StdNetBind implements Bind for all platforms. While Windows has its own Bind
  23. // (see bind_windows.go), it may fall back to StdNetBind.
  24. // TODO: Remove usage of ipv{4,6}.PacketConn when net.UDPConn has comparable
  25. // methods for sending and receiving multiple datagrams per-syscall. See the
  26. // proposal in https://github.com/golang/go/issues/45886#issuecomment-1218301564.
  27. type StdNetBind struct {
  28. mu sync.Mutex // protects all fields except as specified
  29. ipv4 *net.UDPConn
  30. ipv6 *net.UDPConn
  31. ipv4PC *ipv4.PacketConn // will be nil on non-Linux
  32. ipv6PC *ipv6.PacketConn // will be nil on non-Linux
  33. ipv4TxOffload bool
  34. ipv4RxOffload bool
  35. ipv6TxOffload bool
  36. ipv6RxOffload bool
  37. // these two fields are not guarded by mu
  38. udpAddrPool sync.Pool
  39. msgsPool sync.Pool
  40. blackhole4 bool
  41. blackhole6 bool
  42. }
  43. // NewStdNetBind creates a bind that listens on all interfaces.
  44. func NewStdNetBind() *StdNetBind {
  45. return newStdNetBind().(*StdNetBind)
  46. }
  47. // NewStdNetBindForAddr creates a bind that listens on a specific address.
  48. // If addr is IPv4, only the IPv4 socket will be created. For IPv6, only the
  49. // IPv6 socket will be created.
  50. func NewStdNetBindForAddr(addr netip.Addr, reusePort bool) *StdNetBind {
  51. b := NewStdNetBind()
  52. //if addr.IsValid() {
  53. // if addr.IsUnspecified() {
  54. // // keep dual-stack defaults with empty listen addresses
  55. // } else if addr.Is4() {
  56. // b.listenAddr4 = addr.Unmap().String()
  57. // b.bindV4 = true
  58. // b.bindV6 = false
  59. // } else {
  60. // b.listenAddr6 = addr.Unmap().String()
  61. // b.bindV6 = true
  62. // b.bindV4 = false
  63. // }
  64. //}
  65. //b.reusePort = reusePort
  66. return b
  67. }
  68. func newStdNetBind() Bind {
  69. return &StdNetBind{
  70. udpAddrPool: sync.Pool{
  71. New: func() any {
  72. return &net.UDPAddr{
  73. IP: make([]byte, 16),
  74. }
  75. },
  76. },
  77. msgsPool: sync.Pool{
  78. New: func() any {
  79. // ipv6.Message and ipv4.Message are interchangeable as they are
  80. // both aliases for x/net/internal/socket.Message.
  81. msgs := make([]ipv6.Message, IdealBatchSize)
  82. for i := range msgs {
  83. msgs[i].Buffers = make(net.Buffers, 1)
  84. msgs[i].OOB = make([]byte, 0, stickyControlSize+gsoControlSize)
  85. }
  86. return &msgs
  87. },
  88. },
  89. }
  90. }
  91. type StdNetEndpoint struct {
  92. // AddrPort is the endpoint destination.
  93. netip.AddrPort
  94. // src is the current sticky source address and interface index, if
  95. // supported. Typically this is a PKTINFO structure from/for control
  96. // messages, see unix.PKTINFO for an example.
  97. src []byte
  98. }
  99. var (
  100. _ Bind = (*StdNetBind)(nil)
  101. _ Endpoint = &StdNetEndpoint{}
  102. )
  103. func (*StdNetBind) ParseEndpoint(s string) (Endpoint, error) {
  104. e, err := netip.ParseAddrPort(s)
  105. if err != nil {
  106. return nil, err
  107. }
  108. return &StdNetEndpoint{
  109. AddrPort: e,
  110. }, nil
  111. }
  112. func (e *StdNetEndpoint) ClearSrc() {
  113. if e.src != nil {
  114. // Truncate src, no need to reallocate.
  115. e.src = e.src[:0]
  116. }
  117. }
  118. func (e *StdNetEndpoint) DstIP() netip.Addr {
  119. return e.AddrPort.Addr()
  120. }
  121. // See control_default,linux, etc for implementations of SrcIP and SrcIfidx.
  122. func (e *StdNetEndpoint) DstToBytes() []byte {
  123. b, _ := e.AddrPort.MarshalBinary()
  124. return b
  125. }
  126. func (e *StdNetEndpoint) DstToString() string {
  127. return e.AddrPort.String()
  128. }
  129. func listenNet(network string, port int) (*net.UDPConn, int, error) {
  130. conn, err := listenConfig().ListenPacket(context.Background(), network, ":"+strconv.Itoa(port))
  131. if err != nil {
  132. return nil, 0, err
  133. }
  134. // Retrieve port.
  135. laddr := conn.LocalAddr()
  136. uaddr, err := net.ResolveUDPAddr(
  137. laddr.Network(),
  138. laddr.String(),
  139. )
  140. if err != nil {
  141. return nil, 0, err
  142. }
  143. return conn.(*net.UDPConn), uaddr.Port, nil
  144. }
  145. func (s *StdNetBind) Open(uport uint16) ([]ReceiveFunc, uint16, error) {
  146. s.mu.Lock()
  147. defer s.mu.Unlock()
  148. var err error
  149. var tries int
  150. if s.ipv4 != nil || s.ipv6 != nil {
  151. return nil, 0, ErrBindAlreadyOpen
  152. }
  153. // Attempt to open ipv4 and ipv6 listeners on the same port.
  154. // If uport is 0, we can retry on failure.
  155. again:
  156. port := int(uport)
  157. var v4conn, v6conn *net.UDPConn
  158. var v4pc *ipv4.PacketConn
  159. var v6pc *ipv6.PacketConn
  160. v4conn, port, err = listenNet("udp4", port)
  161. if err != nil && !errors.Is(err, syscall.EAFNOSUPPORT) {
  162. return nil, 0, err
  163. }
  164. // Listen on the same port as we're using for ipv4.
  165. v6conn, port, err = listenNet("udp6", port)
  166. if uport == 0 && errors.Is(err, syscall.EADDRINUSE) && tries < 100 {
  167. v4conn.Close()
  168. tries++
  169. goto again
  170. }
  171. if err != nil && !errors.Is(err, syscall.EAFNOSUPPORT) {
  172. v4conn.Close()
  173. return nil, 0, err
  174. }
  175. var fns []ReceiveFunc
  176. if v4conn != nil {
  177. s.ipv4TxOffload, s.ipv4RxOffload = supportsUDPOffload(v4conn)
  178. if runtime.GOOS == "linux" || runtime.GOOS == "android" {
  179. v4pc = ipv4.NewPacketConn(v4conn)
  180. s.ipv4PC = v4pc
  181. }
  182. fns = append(fns, s.makeReceiveIPv4(v4pc, v4conn, s.ipv4RxOffload))
  183. s.ipv4 = v4conn
  184. }
  185. if v6conn != nil {
  186. s.ipv6TxOffload, s.ipv6RxOffload = supportsUDPOffload(v6conn)
  187. if runtime.GOOS == "linux" || runtime.GOOS == "android" {
  188. v6pc = ipv6.NewPacketConn(v6conn)
  189. s.ipv6PC = v6pc
  190. }
  191. fns = append(fns, s.makeReceiveIPv6(v6pc, v6conn, s.ipv6RxOffload))
  192. s.ipv6 = v6conn
  193. }
  194. if len(fns) == 0 {
  195. return nil, 0, syscall.EAFNOSUPPORT
  196. }
  197. return fns, uint16(port), nil
  198. }
  199. func (s *StdNetBind) putMessages(msgs *[]ipv6.Message) {
  200. for i := range *msgs {
  201. (*msgs)[i].OOB = (*msgs)[i].OOB[:0]
  202. (*msgs)[i] = ipv6.Message{Buffers: (*msgs)[i].Buffers, OOB: (*msgs)[i].OOB}
  203. }
  204. s.msgsPool.Put(msgs)
  205. }
  206. func (s *StdNetBind) getMessages() *[]ipv6.Message {
  207. return s.msgsPool.Get().(*[]ipv6.Message)
  208. }
  209. var (
  210. // If compilation fails here these are no longer the same underlying type.
  211. _ ipv6.Message = ipv4.Message{}
  212. )
  213. type batchReader interface {
  214. ReadBatch([]ipv6.Message, int) (int, error)
  215. }
  216. type batchWriter interface {
  217. WriteBatch([]ipv6.Message, int) (int, error)
  218. }
  219. func (s *StdNetBind) receiveIP(
  220. br batchReader,
  221. conn *net.UDPConn,
  222. rxOffload bool,
  223. bufs [][]byte,
  224. sizes []int,
  225. eps []Endpoint,
  226. ) (n int, err error) {
  227. msgs := s.getMessages()
  228. for i := range bufs {
  229. (*msgs)[i].Buffers[0] = bufs[i]
  230. (*msgs)[i].OOB = (*msgs)[i].OOB[:cap((*msgs)[i].OOB)]
  231. }
  232. defer s.putMessages(msgs)
  233. var numMsgs int
  234. if runtime.GOOS == "linux" || runtime.GOOS == "android" {
  235. if rxOffload {
  236. readAt := len(*msgs) - (IdealBatchSize / udpSegmentMaxDatagrams)
  237. numMsgs, err = br.ReadBatch((*msgs)[readAt:], 0)
  238. if err != nil {
  239. return 0, err
  240. }
  241. numMsgs, err = splitCoalescedMessages(*msgs, readAt, getGSOSize)
  242. if err != nil {
  243. return 0, err
  244. }
  245. } else {
  246. numMsgs, err = br.ReadBatch(*msgs, 0)
  247. if err != nil {
  248. return 0, err
  249. }
  250. }
  251. } else {
  252. msg := &(*msgs)[0]
  253. msg.N, msg.NN, _, msg.Addr, err = conn.ReadMsgUDP(msg.Buffers[0], msg.OOB)
  254. if err != nil {
  255. return 0, err
  256. }
  257. numMsgs = 1
  258. }
  259. for i := 0; i < numMsgs; i++ {
  260. msg := &(*msgs)[i]
  261. sizes[i] = msg.N
  262. if sizes[i] == 0 {
  263. continue
  264. }
  265. addrPort := msg.Addr.(*net.UDPAddr).AddrPort()
  266. ep := &StdNetEndpoint{AddrPort: addrPort} // TODO: remove allocation
  267. getSrcFromControl(msg.OOB[:msg.NN], ep)
  268. eps[i] = ep
  269. }
  270. return numMsgs, nil
  271. }
  272. func (s *StdNetBind) makeReceiveIPv4(pc *ipv4.PacketConn, conn *net.UDPConn, rxOffload bool) ReceiveFunc {
  273. return func(bufs [][]byte, sizes []int, eps []Endpoint) (n int, err error) {
  274. return s.receiveIP(pc, conn, rxOffload, bufs, sizes, eps)
  275. }
  276. }
  277. func (s *StdNetBind) makeReceiveIPv6(pc *ipv6.PacketConn, conn *net.UDPConn, rxOffload bool) ReceiveFunc {
  278. return func(bufs [][]byte, sizes []int, eps []Endpoint) (n int, err error) {
  279. return s.receiveIP(pc, conn, rxOffload, bufs, sizes, eps)
  280. }
  281. }
  282. // TODO: When all Binds handle IdealBatchSize, remove this dynamic function and
  283. // rename the IdealBatchSize constant to BatchSize.
  284. func (s *StdNetBind) BatchSize() int {
  285. if runtime.GOOS == "linux" || runtime.GOOS == "android" {
  286. return IdealBatchSize
  287. }
  288. return 1
  289. }
  290. func (s *StdNetBind) Close() error {
  291. s.mu.Lock()
  292. defer s.mu.Unlock()
  293. var err1, err2 error
  294. if s.ipv4 != nil {
  295. err1 = s.ipv4.Close()
  296. s.ipv4 = nil
  297. s.ipv4PC = nil
  298. }
  299. if s.ipv6 != nil {
  300. err2 = s.ipv6.Close()
  301. s.ipv6 = nil
  302. s.ipv6PC = nil
  303. }
  304. s.blackhole4 = false
  305. s.blackhole6 = false
  306. s.ipv4TxOffload = false
  307. s.ipv4RxOffload = false
  308. s.ipv6TxOffload = false
  309. s.ipv6RxOffload = false
  310. if err1 != nil {
  311. return err1
  312. }
  313. return err2
  314. }
  315. type ErrUDPGSODisabled struct {
  316. onLaddr string
  317. RetryErr error
  318. }
  319. func (e ErrUDPGSODisabled) Error() string {
  320. return fmt.Sprintf("disabled UDP GSO on %s, NIC(s) may not support checksum offload", e.onLaddr)
  321. }
  322. func (e ErrUDPGSODisabled) Unwrap() error {
  323. return e.RetryErr
  324. }
  325. func (s *StdNetBind) Send(bufs [][]byte, endpoint Endpoint) error {
  326. s.mu.Lock()
  327. blackhole := s.blackhole4
  328. conn := s.ipv4
  329. offload := s.ipv4TxOffload
  330. br := batchWriter(s.ipv4PC)
  331. is6 := false
  332. if endpoint.DstIP().Is6() {
  333. blackhole = s.blackhole6
  334. conn = s.ipv6
  335. br = s.ipv6PC
  336. is6 = true
  337. offload = s.ipv6TxOffload
  338. }
  339. s.mu.Unlock()
  340. if blackhole {
  341. return nil
  342. }
  343. if conn == nil {
  344. return syscall.EAFNOSUPPORT
  345. }
  346. msgs := s.getMessages()
  347. defer s.putMessages(msgs)
  348. ua := s.udpAddrPool.Get().(*net.UDPAddr)
  349. defer s.udpAddrPool.Put(ua)
  350. if is6 {
  351. as16 := endpoint.DstIP().As16()
  352. copy(ua.IP, as16[:])
  353. ua.IP = ua.IP[:16]
  354. } else {
  355. as4 := endpoint.DstIP().As4()
  356. copy(ua.IP, as4[:])
  357. ua.IP = ua.IP[:4]
  358. }
  359. ua.Port = int(endpoint.(*StdNetEndpoint).Port())
  360. var (
  361. retried bool
  362. err error
  363. )
  364. retry:
  365. if offload {
  366. n := coalesceMessages(ua, endpoint.(*StdNetEndpoint), bufs, *msgs, setGSOSize)
  367. err = s.send(conn, br, (*msgs)[:n])
  368. if err != nil && offload && errShouldDisableUDPGSO(err) {
  369. offload = false
  370. s.mu.Lock()
  371. if is6 {
  372. s.ipv6TxOffload = false
  373. } else {
  374. s.ipv4TxOffload = false
  375. }
  376. s.mu.Unlock()
  377. retried = true
  378. goto retry
  379. }
  380. } else {
  381. for i := range bufs {
  382. (*msgs)[i].Addr = ua
  383. (*msgs)[i].Buffers[0] = bufs[i]
  384. setSrcControl(&(*msgs)[i].OOB, endpoint.(*StdNetEndpoint))
  385. }
  386. err = s.send(conn, br, (*msgs)[:len(bufs)])
  387. }
  388. if retried {
  389. return ErrUDPGSODisabled{onLaddr: conn.LocalAddr().String(), RetryErr: err}
  390. }
  391. return err
  392. }
  393. func (s *StdNetBind) send(conn *net.UDPConn, pc batchWriter, msgs []ipv6.Message) error {
  394. var (
  395. n int
  396. err error
  397. start int
  398. )
  399. if runtime.GOOS == "linux" || runtime.GOOS == "android" {
  400. for {
  401. n, err = pc.WriteBatch(msgs[start:], 0)
  402. if err != nil || n == len(msgs[start:]) {
  403. break
  404. }
  405. start += n
  406. }
  407. } else {
  408. for _, msg := range msgs {
  409. _, _, err = conn.WriteMsgUDP(msg.Buffers[0], msg.OOB, msg.Addr.(*net.UDPAddr))
  410. if err != nil {
  411. break
  412. }
  413. }
  414. }
  415. return err
  416. }
  417. const (
  418. // Exceeding these values results in EMSGSIZE. They account for layer3 and
  419. // layer4 headers. IPv6 does not need to account for itself as the payload
  420. // length field is self excluding.
  421. maxIPv4PayloadLen = 1<<16 - 1 - 20 - 8
  422. maxIPv6PayloadLen = 1<<16 - 1 - 8
  423. // This is a hard limit imposed by the kernel.
  424. udpSegmentMaxDatagrams = 64
  425. )
  426. type setGSOFunc func(control *[]byte, gsoSize uint16)
  427. func coalesceMessages(addr *net.UDPAddr, ep *StdNetEndpoint, bufs [][]byte, msgs []ipv6.Message, setGSO setGSOFunc) int {
  428. var (
  429. base = -1 // index of msg we are currently coalescing into
  430. gsoSize int // segmentation size of msgs[base]
  431. dgramCnt int // number of dgrams coalesced into msgs[base]
  432. endBatch bool // tracking flag to start a new batch on next iteration of bufs
  433. )
  434. maxPayloadLen := maxIPv4PayloadLen
  435. if ep.DstIP().Is6() {
  436. maxPayloadLen = maxIPv6PayloadLen
  437. }
  438. for i, buf := range bufs {
  439. if i > 0 {
  440. msgLen := len(buf)
  441. baseLenBefore := len(msgs[base].Buffers[0])
  442. freeBaseCap := cap(msgs[base].Buffers[0]) - baseLenBefore
  443. if msgLen+baseLenBefore <= maxPayloadLen &&
  444. msgLen <= gsoSize &&
  445. msgLen <= freeBaseCap &&
  446. dgramCnt < udpSegmentMaxDatagrams &&
  447. !endBatch {
  448. msgs[base].Buffers[0] = append(msgs[base].Buffers[0], buf...)
  449. if i == len(bufs)-1 {
  450. setGSO(&msgs[base].OOB, uint16(gsoSize))
  451. }
  452. dgramCnt++
  453. if msgLen < gsoSize {
  454. // A smaller than gsoSize packet on the tail is legal, but
  455. // it must end the batch.
  456. endBatch = true
  457. }
  458. continue
  459. }
  460. }
  461. if dgramCnt > 1 {
  462. setGSO(&msgs[base].OOB, uint16(gsoSize))
  463. }
  464. // Reset prior to incrementing base since we are preparing to start a
  465. // new potential batch.
  466. endBatch = false
  467. base++
  468. gsoSize = len(buf)
  469. setSrcControl(&msgs[base].OOB, ep)
  470. msgs[base].Buffers[0] = buf
  471. msgs[base].Addr = addr
  472. dgramCnt = 1
  473. }
  474. return base + 1
  475. }
  476. type getGSOFunc func(control []byte) (int, error)
  477. func splitCoalescedMessages(msgs []ipv6.Message, firstMsgAt int, getGSO getGSOFunc) (n int, err error) {
  478. for i := firstMsgAt; i < len(msgs); i++ {
  479. msg := &msgs[i]
  480. if msg.N == 0 {
  481. return n, err
  482. }
  483. var (
  484. gsoSize int
  485. start int
  486. end = msg.N
  487. numToSplit = 1
  488. )
  489. gsoSize, err = getGSO(msg.OOB[:msg.NN])
  490. if err != nil {
  491. return n, err
  492. }
  493. if gsoSize > 0 {
  494. numToSplit = (msg.N + gsoSize - 1) / gsoSize
  495. end = gsoSize
  496. }
  497. for j := 0; j < numToSplit; j++ {
  498. if n > i {
  499. return n, errors.New("splitting coalesced packet resulted in overflow")
  500. }
  501. copied := copy(msgs[n].Buffers[0], msg.Buffers[0][start:end])
  502. msgs[n].N = copied
  503. msgs[n].Addr = msg.Addr
  504. start = end
  505. end += gsoSize
  506. if end > msg.N {
  507. end = msg.N
  508. }
  509. n++
  510. }
  511. if i != n-1 {
  512. // It is legal for bytes to move within msg.Buffers[0] as a result
  513. // of splitting, so we only zero the source msg len when it is not
  514. // the destination of the last split operation above.
  515. msg.N = 0
  516. }
  517. }
  518. return n, nil
  519. }