stunserver.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. // Package stunserver implements a STUN server. The package publishes a number of stats
  4. // to expvar under the top level label "stun". Logs are sent to the standard log package.
  5. package stunserver
  6. import (
  7. "context"
  8. "errors"
  9. "io"
  10. "log"
  11. "net"
  12. "net/netip"
  13. "time"
  14. "tailscale.com/metrics"
  15. "tailscale.com/net/stun"
  16. )
  17. var (
  18. stats = metrics.NewSet("stun")
  19. stunDisposition = stats.NewLabelMap("counter_requests", "disposition")
  20. stunAddrFamily = stats.NewLabelMap("counter_addrfamily", "family")
  21. stunReadError = stunDisposition.Get("read_error")
  22. stunNotSTUN = stunDisposition.Get("not_stun")
  23. stunWriteError = stunDisposition.Get("write_error")
  24. stunSuccess = stunDisposition.Get("success")
  25. stunIPv4 = stunAddrFamily.Get("ipv4")
  26. stunIPv6 = stunAddrFamily.Get("ipv6")
  27. )
  28. type STUNServer struct {
  29. ctx context.Context // ctx signals service shutdown
  30. pc *net.UDPConn // pc is the UDP listener
  31. }
  32. // New creates a new STUN server. The server is shutdown when ctx is done.
  33. func New(ctx context.Context) *STUNServer {
  34. return &STUNServer{ctx: ctx}
  35. }
  36. // Listen binds the listen socket for the server at listenAddr.
  37. func (s *STUNServer) Listen(listenAddr string) error {
  38. uaddr, err := net.ResolveUDPAddr("udp", listenAddr)
  39. if err != nil {
  40. return err
  41. }
  42. s.pc, err = net.ListenUDP("udp", uaddr)
  43. if err != nil {
  44. return err
  45. }
  46. log.Printf("STUN server listening on %v", s.LocalAddr())
  47. // close the listener on shutdown in order to break out of the read loop
  48. go func() {
  49. <-s.ctx.Done()
  50. s.pc.Close()
  51. }()
  52. return nil
  53. }
  54. // Serve starts serving responses to STUN requests. Listen must be called before Serve.
  55. func (s *STUNServer) Serve() error {
  56. var buf [64 << 10]byte
  57. var (
  58. n int
  59. ua *net.UDPAddr
  60. err error
  61. )
  62. for {
  63. n, ua, err = s.pc.ReadFromUDP(buf[:])
  64. if err != nil {
  65. if errors.Is(err, io.EOF) || errors.Is(err, net.ErrClosed) {
  66. return nil
  67. }
  68. log.Printf("STUN ReadFrom: %v", err)
  69. time.Sleep(time.Second)
  70. stunReadError.Add(1)
  71. continue
  72. }
  73. pkt := buf[:n]
  74. if !stun.Is(pkt) {
  75. stunNotSTUN.Add(1)
  76. continue
  77. }
  78. txid, err := stun.ParseBindingRequest(pkt)
  79. if err != nil {
  80. stunNotSTUN.Add(1)
  81. continue
  82. }
  83. if ua.IP.To4() != nil {
  84. stunIPv4.Add(1)
  85. } else {
  86. stunIPv6.Add(1)
  87. }
  88. addr, _ := netip.AddrFromSlice(ua.IP)
  89. res := stun.Response(txid, netip.AddrPortFrom(addr, uint16(ua.Port)))
  90. _, err = s.pc.WriteTo(res, ua)
  91. if err != nil {
  92. stunWriteError.Add(1)
  93. } else {
  94. stunSuccess.Add(1)
  95. }
  96. }
  97. }
  98. // ListenAndServe starts the STUN server on listenAddr.
  99. func (s *STUNServer) ListenAndServe(listenAddr string) error {
  100. if err := s.Listen(listenAddr); err != nil {
  101. return err
  102. }
  103. return s.Serve()
  104. }
  105. // LocalAddr returns the local address of the STUN server. It must not be called before ListenAndServe.
  106. func (s *STUNServer) LocalAddr() net.Addr {
  107. return s.pc.LocalAddr()
  108. }