connsock_darwin.go 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803
  1. //go:build !e2e_testing
  2. package udp
  3. import (
  4. "context"
  5. "errors"
  6. "fmt"
  7. "log/slog"
  8. "maps"
  9. "net"
  10. "net/netip"
  11. "os"
  12. "slices"
  13. "strconv"
  14. "sync"
  15. "sync/atomic"
  16. "syscall"
  17. "time"
  18. "golang.org/x/sys/unix"
  19. )
  20. // A connected socket is a UDP socket connected to one busy peer, on the listener's port and bound to the source
  21. // address the listener's route to that peer picks, so the peer sees the same address and port from either. A send
  22. // on a connected socket skips the per-datagram address and MAC policy checks, and the EndpointSecurity send check
  23. // that xprotectd can hold every unconnected sendto on, and it is the only UDP send that reports the interface
  24. // queue's flow control, as ENOBUFS. A connected socket wins xnu's lookup for its peer's datagrams; it never sees
  25. // anyone else's.
  26. //
  27. // A connected socket sets SO_REUSEPORT and binds a specific address beside a wildcard listener, which sets
  28. // SO_REUSEPORT only for listen routines. xnu refuses a wildcard SO_REUSEPORT bind beside a holder without the
  29. // option, and refuses another uid's bind to an address a socket holds specifically, so no other user can join the
  30. // port while connected sockets open and close: uid nobody got EADDRINUSE on every bind against a root listener
  31. // with connected sockets in the 09-25 probes. A connected socket is closed, never disconnected, because xnu widens
  32. // a disconnected socket's local address to the wildcard.
  33. //
  34. // Only the current remote of an established tunnel may get one: Nebula names those with SetEstablishedPeer, so an
  35. // unauthenticated sender can't earn a connected socket by drawing replies such as recv_error or handshake
  36. // responses.
  37. type connSock struct {
  38. dst netip.AddrPort
  39. peer *connSockPeer
  40. conn *net.UDPConn
  41. rc syscall.RawConn
  42. // used is the monotonic time in nanoseconds of the connected socket's last send or receive.
  43. used atomic.Int64
  44. // stallAt is the monotonic time of the first ENOBUFS or EAGAIN since a send last went through, or 0, and
  45. // dropping is set once that stall has dropped a datagram, so each stall logs its drops once.
  46. stallAt atomic.Int64
  47. dropping atomic.Bool
  48. // parkMu serializes the writes that wait for a full send buffer, since the write deadline bounding each wait
  49. // is the descriptor's, not the writer's.
  50. parkMu sync.Mutex
  51. // sys writes one datagram on the descriptor: writeFd, or a stand-in for the interface in tests.
  52. sys func(fd int, b []byte) error
  53. }
  54. func writeFd(fd int, b []byte) error {
  55. _, err := syscall.Write(fd, b)
  56. return err
  57. }
  58. // errStallSpent is a write that found the connected socket's stall budget spent, so its datagram is dropped.
  59. var errStallSpent = errors.New("connected socket stall budget spent")
  60. // connSockWriter carries one write through RawConn.Write. They are pooled with fn bound once, since a closure
  61. // passed through the RawConn interface escapes and would allocate on every send.
  62. type connSockWriter struct {
  63. s *connSock
  64. b []byte
  65. park bool
  66. err error
  67. fn func(fd uintptr) bool
  68. }
  69. var connSockWriters = sync.Pool{New: func() any {
  70. w := &connSockWriter{}
  71. w.fn = w.write
  72. return w
  73. }}
  74. func (w *connSockWriter) write(fd uintptr) bool {
  75. for {
  76. w.err = w.s.sys(int(fd), w.b)
  77. switch {
  78. case w.err == syscall.EINTR:
  79. case w.err == syscall.EAGAIN && w.park:
  80. return false
  81. default:
  82. return true
  83. }
  84. }
  85. }
  86. // try writes b on s once and returns nil, the write's errno, os.ErrDeadlineExceeded, or net.ErrClosed. With park
  87. // set, EAGAIN waits in the netpoller until the socket is writable or the write deadline passes; without it, EAGAIN
  88. // is returned.
  89. func (s *connSock) try(b []byte, park bool) error {
  90. w := connSockWriters.Get().(*connSockWriter)
  91. w.s, w.b, w.park = s, b, park
  92. rerr := s.rc.Write(w.fn)
  93. err := w.err
  94. *w = connSockWriter{fn: w.fn}
  95. connSockWriters.Put(w)
  96. switch {
  97. case rerr == nil:
  98. return err
  99. case errors.Is(rerr, os.ErrDeadlineExceeded):
  100. return os.ErrDeadlineExceeded
  101. default:
  102. return net.ErrClosed
  103. }
  104. }
  105. // connSockConfig holds the knobs. connSockConfigFromEnv reads all but backoff and enobufsMax from the environment,
  106. // so one binary can be tuned without a rebuild.
  107. type connSockConfig struct {
  108. // max is how many connected sockets the listen routines may have open at once; 0 turns connected sockets off.
  109. max int
  110. // run is how many datagrams to one destination within one window earn it a connected socket. darwin's tun
  111. // hands over one packet per read, so a peer's sends arrive one WriteTo or one-datagram batch at a time and
  112. // busyness has to be counted across calls.
  113. run int
  114. window time.Duration
  115. // idle closes a connected socket after it has neither sent nor received for this long.
  116. idle time.Duration
  117. // backoff keeps a destination whose connected socket failed on the listener for this long.
  118. backoff time.Duration
  119. // openEvery is how often the open bucket earns back an open once max are spent, which bounds connected socket
  120. // churn however fast senders earn connected sockets and errors close them.
  121. openEvery time.Duration
  122. // enobufsMax is how long a connected socket's sends may wait out ENOBUFS without one going through before they
  123. // drop instead, so a suspended interface costs one write per datagram rather than stalling the tun reader.
  124. enobufsMax time.Duration
  125. }
  126. func connSockConfigFromEnv() connSockConfig {
  127. c := connSockConfig{
  128. max: 8,
  129. run: 64,
  130. window: time.Second,
  131. idle: 30 * time.Second,
  132. backoff: 30 * time.Second,
  133. openEvery: time.Second,
  134. enobufsMax: 10 * time.Millisecond,
  135. }
  136. if v, err := strconv.Atoi(os.Getenv("NEBULA_CONNSOCKS")); err == nil {
  137. c.max = v
  138. }
  139. if v, err := strconv.Atoi(os.Getenv("NEBULA_CONNSOCK_RUN")); err == nil && v > 0 {
  140. c.run = v
  141. }
  142. if v, err := time.ParseDuration(os.Getenv("NEBULA_CONNSOCK_WINDOW")); err == nil && v > 0 {
  143. c.window = v
  144. }
  145. if v, err := time.ParseDuration(os.Getenv("NEBULA_CONNSOCK_IDLE")); err == nil && v > 0 {
  146. c.idle = v
  147. }
  148. if v, err := time.ParseDuration(os.Getenv("NEBULA_CONNSOCK_OPEN_EVERY")); err == nil && v > 0 {
  149. c.openEvery = v
  150. }
  151. return c
  152. }
  153. // connSockGroups holds the connSocks that the listen routines bound to one address share, so the limits, the
  154. // connected sockets and Rebind cover every routine, and a peer has at most one connected socket.
  155. var connSockGroups = struct {
  156. sync.Mutex
  157. m map[netip.AddrPort]*connSocks
  158. }{m: map[netip.AddrPort]*connSocks{}}
  159. // joinConnSocks returns the connSocks u shares with the other listen routines bound to la, and makes it for the
  160. // first.
  161. func joinConnSocks(u *StdConn, la netip.AddrPort, s Settings) *connSocks {
  162. g := &connSockGroups
  163. g.Lock()
  164. defer g.Unlock()
  165. if cs := g.m[la]; s.Multi && cs != nil {
  166. cs.mu.Lock()
  167. cs.members = append(cs.members, u)
  168. cs.mu.Unlock()
  169. return cs
  170. }
  171. cs := &connSocks{cfg: connSockConfigFromEnv(), key: la, members: []*StdConn{u}, clock: monoNow, sleep: time.Sleep}
  172. if cs.cfg.max > 0 && !u.listenHost.IsUnspecified() && !s.Multi {
  173. // A connected socket on a specific listen.host binds the listener's own address, which xnu allows only when
  174. // both sockets set SO_REUSEPORT, and a listener with it lets another uid bind a dual-stack wildcard on the
  175. // port.
  176. cs.off.Store(true)
  177. u.l.Debug("connected sockets: off for a specific listen.host", "addr", s.Listen)
  178. }
  179. if s.Multi {
  180. g.m[la] = cs
  181. }
  182. return cs
  183. }
  184. type connSocks struct {
  185. cfg connSockConfig
  186. // key is the listeners' bound address, which connSockGroups files this under.
  187. key netip.AddrPort
  188. // off keeps connected sockets from opening, when the listener's address can't be shared with them.
  189. off atomic.Bool
  190. // table maps each destination that is the remote of an established tunnel, and that a connected socket could
  191. // reach, to its peer; it is nil when there are none, so a send with nothing to consider costs one load. Every
  192. // send reads it without a lock, and mu guards copying it. An open that holds mu and still finds its peer here
  193. // can't outlive the tunnel.
  194. table atomic.Pointer[map[netip.AddrPort]*connSockPeer]
  195. // reserved counts the connected sockets that are open, opening or closing, against cfg.max; mu guards changing it.
  196. reserved atomic.Int32
  197. mu sync.Mutex
  198. closed bool
  199. // members are the listen routines' listeners that share these connected sockets.
  200. members []*StdConn
  201. // pending holds each destination whose connected socket is opening or closing, and not on its peer. xnu
  202. // refuses to connect a 4-tuple that is still bound, so a destination in pending can't open another.
  203. pending map[netip.AddrPort]struct{}
  204. // rebinds counts Rebinds, so an open that copied the listener's interface before one is discarded.
  205. rebinds uint64
  206. // closers tracks the goroutines that close detached connected sockets.
  207. closers sync.WaitGroup
  208. // done stops the reaper; it is made when ListenOut starts the connected sockets.
  209. done chan struct{}
  210. // opens bounds connected socket opens to cfg.max at once and one per cfg.openEvery after.
  211. opens gcra
  212. // logs bounds connected socket log lines at info or warn; see connSockLogBurst.
  213. logs gcra
  214. // clock returns monotonic nanoseconds and sleep waits out ENOBUFS: monoNow and time.Sleep, or stand-ins in
  215. // tests.
  216. clock func() int64
  217. sleep func(time.Duration)
  218. // dialHook and closeHook, when set, run just before an open's dials and a close's Close, outside mu; tests
  219. // use them to hold an open or close in flight.
  220. dialHook, closeHook func(dst netip.AddrPort)
  221. }
  222. // connSockPeer is what connSocks keeps about an established tunnel's remote: its connected socket, how busy it is,
  223. // and how long a failed connected socket keeps it on the listener.
  224. type connSockPeer struct {
  225. sock atomic.Pointer[connSock]
  226. // windowMu guards start, the monotonic time the current window began, and n, the datagrams sent in it, so a
  227. // window's reset and its counts can't interleave with another sender's.
  228. windowMu sync.Mutex
  229. start int64
  230. n int
  231. // retryAt is the monotonic time before which a peer whose connected socket failed stays on the listener;
  232. // connSocks.mu guards it.
  233. retryAt int64
  234. }
  235. // busy counts n more datagrams to p and reports whether it has now sent cfg.run within one window. A busy peer's
  236. // count starts over, so a peer that can't get a connected socket retries at most once per cfg.run sends.
  237. func (p *connSockPeer) busy(now int64, n int, cfg *connSockConfig) bool {
  238. p.windowMu.Lock()
  239. defer p.windowMu.Unlock()
  240. if time.Duration(now-p.start) > cfg.window {
  241. p.start, p.n = now, 0
  242. }
  243. p.n += n
  244. if p.n < cfg.run {
  245. return false
  246. }
  247. p.n = 0
  248. return true
  249. }
  250. // connSockLogBurst and connSockLogEvery size the bucket that lets connected socket opens, closes and failures log
  251. // at info or warn; past it they log at debug, so churn can't flood the log.
  252. const (
  253. connSockLogBurst = 32
  254. connSockLogEvery = 10 * time.Second
  255. )
  256. var monoStart = time.Now()
  257. func monoNow() int64 { return int64(time.Since(monoStart)) }
  258. // gcra is a token bucket kept as the monotonic time it is next full (the generic cell rate algorithm), so it needs
  259. // no refill tick.
  260. type gcra struct{ tat int64 }
  261. // take spends a token from a bucket of burst that earns one back per every, and reports whether there was one to
  262. // spend.
  263. func (g *gcra) take(now int64, burst int, every time.Duration) bool {
  264. e := int64(every)
  265. tat := max(g.tat, now)
  266. if tat-now > int64(burst-1)*e {
  267. return false
  268. }
  269. g.tat = tat + e
  270. return true
  271. }
  272. // logLevelLocked returns level while the log bucket has a token, and debug once it is spent.
  273. func (cs *connSocks) logLevelLocked(level slog.Level) slog.Level {
  274. if cs.logs.take(cs.clock(), connSockLogBurst, connSockLogEvery) {
  275. return level
  276. }
  277. return slog.LevelDebug
  278. }
  279. // startConnSocks starts the idle reaper.
  280. func (u *StdConn) startConnSocks() {
  281. cs := u.socks
  282. cs.mu.Lock()
  283. defer cs.mu.Unlock()
  284. if cs.closed || cs.done != nil || cs.cfg.max <= 0 || cs.off.Load() {
  285. return
  286. }
  287. cs.done = make(chan struct{})
  288. go u.reapConnSocks(cs.done)
  289. }
  290. // stopConnSocks closes every connected socket and keeps new ones from opening, once any listen routine's listener
  291. // closes, as they do together at shutdown. It returns once their descriptors are closed.
  292. func (u *StdConn) stopConnSocks() {
  293. cs := u.socks
  294. cs.mu.Lock()
  295. cs.members = slices.DeleteFunc(cs.members, func(m *StdConn) bool { return m == u })
  296. if !cs.closed {
  297. cs.closed = true
  298. if cs.done != nil {
  299. close(cs.done)
  300. }
  301. u.detachAllLocked("close")
  302. }
  303. cs.mu.Unlock()
  304. connSockGroups.Lock()
  305. if connSockGroups.m[cs.key] == cs {
  306. delete(connSockGroups.m, cs.key)
  307. }
  308. connSockGroups.Unlock()
  309. cs.closers.Wait()
  310. }
  311. // siblings returns the other listen routines' listeners.
  312. func (cs *connSocks) siblings(u *StdConn) []*StdConn {
  313. cs.mu.Lock()
  314. defer cs.mu.Unlock()
  315. return slices.DeleteFunc(slices.Clone(cs.members), func(m *StdConn) bool { return m == u })
  316. }
  317. // connSockFor returns dst's connected socket, or nil.
  318. func (u *StdConn) connSockFor(dst netip.AddrPort) *connSock {
  319. if p := u.socks.peer(dst); p != nil {
  320. return p.sock.Load()
  321. }
  322. return nil
  323. }
  324. func (cs *connSocks) peer(dst netip.AddrPort) *connSockPeer {
  325. if t := cs.table.Load(); t != nil {
  326. return (*t)[dst]
  327. }
  328. return nil
  329. }
  330. // SetEstablishedPeer makes dst eligible for a connected socket while it is the remote of an established tunnel,
  331. // and closes the one it has once it no longer is. Nebula calls it for every listen routine under the hostmap's
  332. // write lock, so repeats are no-ops and it makes no syscalls: the descriptor is closed by another goroutine.
  333. func (u *StdConn) SetEstablishedPeer(dst netip.AddrPort, established bool) {
  334. cs := u.socks
  335. if cs.cfg.max <= 0 || cs.off.Load() || !u.connSockable(dst) {
  336. return
  337. }
  338. cs.mu.Lock()
  339. defer cs.mu.Unlock()
  340. t := cs.table.Load()
  341. p := cs.peer(dst)
  342. if cs.closed || (p != nil) == established {
  343. return
  344. }
  345. next := map[netip.AddrPort]*connSockPeer{}
  346. if t != nil {
  347. next = maps.Clone(*t)
  348. }
  349. if established {
  350. p = &connSockPeer{start: cs.clock()}
  351. next[dst] = p
  352. } else {
  353. delete(next, dst)
  354. if s := p.sock.Load(); s != nil {
  355. u.detachLocked(s, "tunnel gone", false)
  356. }
  357. }
  358. cs.storeTableLocked(next)
  359. }
  360. // storeTableLocked publishes t, or nil for an empty one.
  361. func (cs *connSocks) storeTableLocked(t map[netip.AddrPort]*connSockPeer) {
  362. if len(t) == 0 {
  363. cs.table.Store(nil)
  364. return
  365. }
  366. cs.table.Store(&t)
  367. }
  368. // connSockable reports whether a connected socket to dst could send what the listener would. A v4 listener can't
  369. // reach a v6 destination at all, and a connected socket bound to a specific listen.host must share its family.
  370. func (u *StdConn) connSockable(dst netip.AddrPort) bool {
  371. if !dst.IsValid() || dst.Port() == 0 {
  372. return false
  373. }
  374. if u.isV4 {
  375. return dst.Addr().Is4()
  376. }
  377. return u.listenHost.IsUnspecified() || u.listenHost.Unmap().Is4() == dst.Addr().Unmap().Is4()
  378. }
  379. // connSockRun sends bufs, all to p's destination, on p's connected socket, opening one if they make p busy. It
  380. // returns how many went out; when that is short of len(bufs), err is the failure of bufs[sent], or nil to leave
  381. // bufs[sent:] to the listener.
  382. func (u *StdConn) connSockRun(p *connSockPeer, dst netip.AddrPort, bufs [][]byte) (sent int, err error) {
  383. s := p.sock.Load()
  384. if s == nil {
  385. if s = u.maybeOpenConnSock(p, dst, len(bufs)); s == nil {
  386. return 0, nil
  387. }
  388. }
  389. sent, errno, closed := u.connSockWrite(s, bufs)
  390. switch {
  391. case sent == len(bufs):
  392. case connSockDead(errno):
  393. u.closeConnSock(s, errno.Error(), true)
  394. case !closed:
  395. return sent, &net.OpError{Op: "write", Err: errno}
  396. }
  397. return sent, nil
  398. }
  399. // maybeOpenConnSock counts n datagrams to p, and opens a connected socket to it once it is busy and nothing rules
  400. // one out.
  401. func (u *StdConn) maybeOpenConnSock(p *connSockPeer, dst netip.AddrPort, n int) *connSock {
  402. cs := u.socks
  403. if n <= 0 || u.reader.Load() == nil || int(cs.reserved.Load()) >= cs.cfg.max || !p.busy(cs.clock(), n, &cs.cfg) {
  404. return nil
  405. }
  406. cs.mu.Lock()
  407. if cs.closed || cs.peer(dst) != p {
  408. cs.mu.Unlock()
  409. return nil
  410. }
  411. if s := p.sock.Load(); s != nil {
  412. cs.mu.Unlock()
  413. return s
  414. }
  415. now := cs.clock()
  416. if _, ok := cs.pending[dst]; ok || int(cs.reserved.Load()) >= cs.cfg.max || now < p.retryAt ||
  417. !cs.opens.take(now, cs.cfg.max, cs.cfg.openEvery) {
  418. cs.mu.Unlock()
  419. return nil
  420. }
  421. if cs.pending == nil {
  422. cs.pending = map[netip.AddrPort]struct{}{}
  423. }
  424. cs.pending[dst] = struct{}{}
  425. cs.reserved.Add(1)
  426. rebinds := cs.rebinds
  427. cs.mu.Unlock()
  428. if cs.dialHook != nil {
  429. cs.dialHook(dst)
  430. }
  431. s, err := u.dialConnSock(p, dst)
  432. cs.mu.Lock()
  433. if err != nil {
  434. delete(cs.pending, dst)
  435. cs.reserved.Add(-1)
  436. p.retryAt = cs.clock() + int64(cs.cfg.backoff)
  437. level := cs.logLevelLocked(slog.LevelWarn)
  438. cs.mu.Unlock()
  439. u.l.Log(context.Background(), level, "connected socket: open failed, staying on the listener", "udpAddr", dst, "error", err)
  440. return nil
  441. }
  442. if cs.closed || cs.rebinds != rebinds || cs.peer(dst) != p {
  443. // The tunnel went away, or a Rebind or shutdown ran, while the socket was opening; it stays in pending until
  444. // it is closed.
  445. cs.mu.Unlock()
  446. u.finishClose(s)
  447. u.l.Debug("connected socket: discarded, its tunnel or route changed while it opened", "udpAddr", dst)
  448. return nil
  449. }
  450. delete(cs.pending, dst)
  451. p.sock.Store(s)
  452. go u.readConnSock(s)
  453. level := cs.logLevelLocked(slog.LevelInfo)
  454. cs.mu.Unlock()
  455. u.l.Log(context.Background(), level, "connected socket: opened", "udpAddr", dst, "local", s.conn.LocalAddr(), "open", cs.reserved.Load())
  456. return s
  457. }
  458. // dialConnSock opens a socket on the listener's port with SO_REUSEPORT, bound to the configured listen.host or,
  459. // for a wildcard listener, to the source address the route to dst picks, and connected to dst. It carries the
  460. // listener's IP_BOUND_IF, so both route the same way.
  461. func (u *StdConn) dialConnSock(p *connSockPeer, dst netip.AddrPort) (*connSock, error) {
  462. raddr := net.UDPAddrFromAddrPort(netip.AddrPortFrom(dst.Addr().Unmap(), dst.Port()))
  463. network := "udp6"
  464. if raddr.IP.To4() != nil {
  465. network = "udp4"
  466. }
  467. ifindex, err := u.boundIf()
  468. if err != nil {
  469. return nil, err
  470. }
  471. local := &net.UDPAddr{IP: u.listenHost.AsSlice(), Zone: u.listenHost.Zone()}
  472. if u.listenHost.IsUnspecified() {
  473. // A connected socket gets the source address xnu would pick for an unconnected send to dst.
  474. d := net.Dialer{Control: connSockControl(false, ifindex)}
  475. probe, err := d.Dial(network, raddr.String())
  476. if err != nil {
  477. return nil, err
  478. }
  479. local = probe.LocalAddr().(*net.UDPAddr)
  480. _ = probe.Close()
  481. }
  482. local.Port = int(u.port)
  483. d := net.Dialer{LocalAddr: local, Control: connSockControl(true, ifindex)}
  484. c, err := d.Dial(network, raddr.String())
  485. if err != nil {
  486. return nil, err
  487. }
  488. uc := c.(*net.UDPConn)
  489. rc, err := uc.SyscallConn()
  490. if err != nil {
  491. _ = uc.Close()
  492. return nil, err
  493. }
  494. s := &connSock{dst: dst, peer: p, conn: uc, rc: rc, sys: writeFd}
  495. s.used.Store(u.socks.clock())
  496. return s, nil
  497. }
  498. // connSockControl sets SO_REUSEPORT when reuse is set, and IP_BOUND_IF or IPV6_BOUND_IF when ifindex isn't 0,
  499. // before the socket binds.
  500. func connSockControl(reuse bool, ifindex int) func(network, address string, c syscall.RawConn) error {
  501. return func(network, _ string, c syscall.RawConn) error {
  502. var serr error
  503. err := c.Control(func(fd uintptr) {
  504. if reuse {
  505. serr = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEPORT, 1)
  506. }
  507. if serr == nil && ifindex != 0 {
  508. if network == "udp4" {
  509. serr = unix.SetsockoptInt(int(fd), unix.IPPROTO_IP, unix.IP_BOUND_IF, ifindex)
  510. } else {
  511. serr = unix.SetsockoptInt(int(fd), unix.IPPROTO_IPV6, unix.IPV6_BOUND_IF, ifindex)
  512. }
  513. }
  514. })
  515. if err != nil {
  516. return err
  517. }
  518. return serr
  519. }
  520. }
  521. // boundIf returns the interface index the listener is scoped to, or 0. An error keeps the peer on the listener,
  522. // since a connected socket opened without the listener's scope could route out an interface the listener can't.
  523. func (u *StdConn) boundIf() (int, error) {
  524. level, opt := unix.IPPROTO_IPV6, unix.IPV6_BOUND_IF
  525. if u.isV4 {
  526. level, opt = unix.IPPROTO_IP, unix.IP_BOUND_IF
  527. }
  528. v, err := unix.GetsockoptInt(int(u.sysFd), level, opt)
  529. if err != nil {
  530. return 0, fmt.Errorf("reading the listener's bound interface: %w", err)
  531. }
  532. return v, nil
  533. }
  534. // closeConnSock closes s if it is still open. With backoff set, the peer stays on the listener until the backoff
  535. // runs out.
  536. func (u *StdConn) closeConnSock(s *connSock, why string, backoff bool) {
  537. u.socks.mu.Lock()
  538. u.detachLocked(s, why, backoff)
  539. u.socks.mu.Unlock()
  540. }
  541. // detachLocked takes s off its peer, if it is still there, and closes it on another goroutine, since callers such
  542. // as SetEstablishedPeer hold locks that no socket syscall should run under. s.dst stays in pending until the close
  543. // completes.
  544. func (u *StdConn) detachLocked(s *connSock, why string, backoff bool) {
  545. cs := u.socks
  546. if !s.peer.sock.CompareAndSwap(s, nil) {
  547. return
  548. }
  549. if backoff {
  550. s.peer.retryAt = cs.clock() + int64(cs.cfg.backoff)
  551. }
  552. if cs.pending == nil {
  553. cs.pending = map[netip.AddrPort]struct{}{}
  554. }
  555. cs.pending[s.dst] = struct{}{}
  556. level := cs.logLevelLocked(slog.LevelInfo)
  557. cs.closers.Add(1)
  558. go func() {
  559. defer cs.closers.Done()
  560. open := u.finishClose(s)
  561. u.l.Log(context.Background(), level, "connected socket: closed", "udpAddr", s.dst, "reason", why, "open", open)
  562. }()
  563. }
  564. // finishClose closes s, whose destination is in pending, then lets the destination open again, and returns how
  565. // many connected sockets are left. Closing waits only for a write already in a syscall: a write parked on a full
  566. // buffer is woken, and one waiting out ENOBUFS holds no reference on the descriptor.
  567. func (u *StdConn) finishClose(s *connSock) int32 {
  568. cs := u.socks
  569. if cs.closeHook != nil {
  570. cs.closeHook(s.dst)
  571. }
  572. _ = s.conn.Close()
  573. cs.mu.Lock()
  574. defer cs.mu.Unlock()
  575. delete(cs.pending, s.dst)
  576. return cs.reserved.Add(-1)
  577. }
  578. // detachAllLocked detaches every connected socket, for a network change or shutdown.
  579. func (u *StdConn) detachAllLocked(why string) {
  580. if t := u.socks.table.Load(); t != nil {
  581. for _, p := range *t {
  582. if s := p.sock.Load(); s != nil {
  583. u.detachLocked(s, why, false)
  584. }
  585. }
  586. }
  587. }
  588. // closeConnSocks detaches every connected socket and discards the ones still opening, for a network change.
  589. func (u *StdConn) closeConnSocks(why string) {
  590. u.socks.mu.Lock()
  591. u.socks.rebinds++
  592. u.detachAllLocked(why)
  593. u.socks.mu.Unlock()
  594. }
  595. func (u *StdConn) reapConnSocks(done <-chan struct{}) {
  596. cs := u.socks
  597. idle := cs.cfg.idle
  598. tick := time.NewTicker(max(min(idle/4, 5*time.Second), time.Millisecond))
  599. defer tick.Stop()
  600. for {
  601. select {
  602. case <-done:
  603. return
  604. case <-tick.C:
  605. }
  606. t := cs.table.Load()
  607. if t == nil {
  608. continue
  609. }
  610. now := cs.clock()
  611. for _, p := range *t {
  612. if s := p.sock.Load(); s != nil && time.Duration(now-s.used.Load()) > idle {
  613. u.closeConnSock(s, "idle", false)
  614. }
  615. }
  616. }
  617. }
  618. // connSockDead reports whether a connected socket send or receive error means the connected path to the peer is
  619. // gone, so its traffic belongs back on the listener. A connected UDP socket reports a peer's ICMP unreachable as
  620. // ECONNREFUSED on its next call, which the unconnected listener never sees.
  621. func connSockDead(errno syscall.Errno) bool {
  622. switch errno {
  623. case unix.ECONNREFUSED, unix.EHOSTUNREACH, unix.EHOSTDOWN, unix.ENETUNREACH, unix.ENETDOWN,
  624. unix.EADDRNOTAVAIL, unix.EPIPE, unix.ENOTCONN, unix.EDESTADDRREQ:
  625. return true
  626. }
  627. return false
  628. }
  629. // enobufsWait is how long a connected socket send sleeps when the interface queue is flow controlled. The kernel
  630. // posts no wakeup when the advisory lifts, so this polls; 50us kept a gigabit link full without spinning a core in
  631. // the 09-25 probes.
  632. const enobufsWait = 50 * time.Microsecond
  633. // connSockWrite writes bufs on s, one datagram per write. A full socket buffer parks the caller in the netpoller
  634. // until the socket is writable, and a flow-controlled interface makes it wait out ENOBUFS, so a busy link slows
  635. // the tun reader instead of dropping. Once the connected socket has waited cfg.enobufsMax without a send going
  636. // through, either one drops the datagram instead, and a dropped datagram counts as sent, as the listener's
  637. // unreported interface drops do; it never falls back to the listener, which would reorder it. closed reports that
  638. // the connected socket was closed before bufs[sent] went out; any other error stops the run and is returned with
  639. // how many went out.
  640. func (u *StdConn) connSockWrite(s *connSock, bufs [][]byte) (sent int, errno syscall.Errno, closed bool) {
  641. cs := u.socks
  642. defer func() {
  643. if sent > 0 {
  644. s.used.Store(cs.clock())
  645. }
  646. }()
  647. for sent < len(bufs) {
  648. err := s.try(bufs[sent], false)
  649. if err == syscall.EAGAIN || err == os.ErrDeadlineExceeded {
  650. // os.ErrDeadlineExceeded here is another writer's parked deadline, passed but not yet cleared.
  651. err = u.parkedWrite(s, bufs[sent])
  652. }
  653. switch err {
  654. case nil:
  655. sent++
  656. if s.stallAt.Load() != 0 {
  657. s.stallAt.Store(0)
  658. s.dropping.Store(false)
  659. }
  660. continue
  661. case errStallSpent:
  662. u.dropStalled(s)
  663. sent++
  664. continue
  665. }
  666. errno, ok := err.(syscall.Errno)
  667. if !ok {
  668. return sent, 0, true
  669. }
  670. if errno != syscall.ENOBUFS {
  671. return sent, errno, false
  672. }
  673. // The wait holds no reference on the descriptor, so a close doesn't wait for it.
  674. if s.stalledFor(cs.clock()) < cs.cfg.enobufsMax {
  675. cs.sleep(enobufsWait)
  676. } else {
  677. u.dropStalled(s)
  678. sent++
  679. }
  680. }
  681. return sent, 0, false
  682. }
  683. // parkedWrite writes b after EAGAIN, parked in the netpoller for what is left of s's stall budget, and returns
  684. // errStallSpent once none is. golang/go#73919: a darwin UDP write parked on EAGAIN can wait forever for a
  685. // writability event that never comes, so the wait always has a deadline.
  686. func (u *StdConn) parkedWrite(s *connSock, b []byte) error {
  687. cs := u.socks
  688. s.parkMu.Lock()
  689. defer s.parkMu.Unlock()
  690. left := cs.cfg.enobufsMax - s.stalledFor(cs.clock())
  691. if left <= 0 {
  692. return errStallSpent
  693. }
  694. if err := s.conn.SetWriteDeadline(time.Now().Add(left)); err != nil {
  695. return net.ErrClosed
  696. }
  697. err := s.try(b, true)
  698. _ = s.conn.SetWriteDeadline(time.Time{})
  699. if err == os.ErrDeadlineExceeded {
  700. return errStallSpent
  701. }
  702. return err
  703. }
  704. // dropStalled logs the first datagram a stall drops.
  705. func (u *StdConn) dropStalled(s *connSock) {
  706. if !s.dropping.Swap(true) {
  707. u.l.Debug("connected socket: sends stalled, dropping datagrams until one goes through", "udpAddr", s.dst)
  708. }
  709. }
  710. // stalledFor records an ENOBUFS or EAGAIN on s at now and returns how long its sends have stalled: since the first
  711. // ENOBUFS or EAGAIN after a send last went through. Every writer measures from that one time, so concurrent writers
  712. // spend the budget no faster than one, and a send going through ends the stall for every writer, including one
  713. // asleep in it.
  714. func (s *connSock) stalledFor(now int64) time.Duration {
  715. if s.stallAt.CompareAndSwap(0, now) {
  716. return 0
  717. }
  718. at := s.stallAt.Load()
  719. if at == 0 {
  720. return 0
  721. }
  722. return time.Duration(now - at)
  723. }
  724. // readConnSock delivers a connected socket's datagrams through the listener's reader, serialized with ListenOut,
  725. // until the connected socket is closed. Any receive error closes it: a connected socket reports its peer's
  726. // unreachables here, and retrying an unexpected error could spin.
  727. func (u *StdConn) readConnSock(s *connSock) {
  728. rd := u.reader.Load()
  729. buf := make([]byte, MTU)
  730. for {
  731. n, from, err := s.conn.ReadFromUDPAddrPort(buf)
  732. if err != nil {
  733. if errors.Is(err, net.ErrClosed) {
  734. return
  735. }
  736. why := err.Error()
  737. var errno syscall.Errno
  738. if errors.As(err, &errno) && connSockDead(errno) {
  739. why = errno.Error()
  740. } else {
  741. u.l.Warn("connected socket: unexpected receive error", "udpAddr", s.dst, "error", err)
  742. }
  743. u.closeConnSock(s, why, true)
  744. return
  745. }
  746. s.used.Store(u.socks.clock())
  747. u.readMu.Lock()
  748. rd.r(netip.AddrPortFrom(from.Addr().Unmap(), from.Port()), buf[:n:n])
  749. rd.flush()
  750. u.readMu.Unlock()
  751. }
  752. }