stun-server.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. package stunserver
  2. import (
  3. "context"
  4. "fmt"
  5. "log"
  6. "net"
  7. "os"
  8. "os/signal"
  9. "strings"
  10. "sync"
  11. "syscall"
  12. "github.com/gravitl/netmaker/logger"
  13. "github.com/gravitl/netmaker/servercfg"
  14. "github.com/pkg/errors"
  15. "gortc.io/stun"
  16. )
  17. // Server is RFC 5389 basic server implementation.
  18. //
  19. // Current implementation is UDP only and not utilizes FINGERPRINT mechanism,
  20. // nor ALTERNATE-SERVER, nor credentials mechanisms. It does not support
  21. // backwards compatibility with RFC 3489.
  22. type Server struct {
  23. Addr string
  24. Ctx context.Context
  25. }
  26. var (
  27. software = stun.NewSoftware("netmaker-stun")
  28. errNotSTUNMessage = errors.New("not stun message")
  29. )
  30. func basicProcess(addr net.Addr, b []byte, req, res *stun.Message) error {
  31. if !stun.IsMessage(b) {
  32. return errNotSTUNMessage
  33. }
  34. if _, err := req.Write(b); err != nil {
  35. return errors.Wrap(err, "failed to read message")
  36. }
  37. var (
  38. ip net.IP
  39. port int
  40. )
  41. switch a := addr.(type) {
  42. case *net.UDPAddr:
  43. ip = a.IP
  44. port = a.Port
  45. default:
  46. panic(fmt.Sprintf("unknown addr: %v", addr))
  47. }
  48. return res.Build(req,
  49. stun.BindingSuccess,
  50. software,
  51. &stun.XORMappedAddress{
  52. IP: ip,
  53. Port: port,
  54. },
  55. stun.Fingerprint,
  56. )
  57. }
  58. func (s *Server) serveConn(c net.PacketConn, res, req *stun.Message) error {
  59. if c == nil {
  60. return nil
  61. }
  62. buf := make([]byte, 1024)
  63. n, addr, err := c.ReadFrom(buf)
  64. if err != nil {
  65. logger.Log(1, "ReadFrom: %v", err.Error())
  66. return nil
  67. }
  68. log.Printf("read %d bytes from %s\n", n, addr)
  69. if _, err = req.Write(buf[:n]); err != nil {
  70. logger.Log(1, "Write: %v", err.Error())
  71. return err
  72. }
  73. if err = basicProcess(addr, buf[:n], req, res); err != nil {
  74. if err == errNotSTUNMessage {
  75. return nil
  76. }
  77. logger.Log(1, "basicProcess: %v", err.Error())
  78. return nil
  79. }
  80. _, err = c.WriteTo(res.Raw, addr)
  81. if err != nil {
  82. logger.Log(1, "WriteTo: %v", err.Error())
  83. }
  84. return err
  85. }
  86. // Serve reads packets from connections and responds to BINDING requests.
  87. func (s *Server) serve(c net.PacketConn) error {
  88. var (
  89. res = new(stun.Message)
  90. req = new(stun.Message)
  91. )
  92. for {
  93. select {
  94. case <-s.Ctx.Done():
  95. logger.Log(0, "Shutting down stun server...")
  96. c.Close()
  97. return nil
  98. default:
  99. if err := s.serveConn(c, res, req); err != nil {
  100. logger.Log(1, "serve: %v", err.Error())
  101. continue
  102. }
  103. res.Reset()
  104. req.Reset()
  105. }
  106. }
  107. }
  108. // listenUDPAndServe listens on laddr and process incoming packets.
  109. func listenUDPAndServe(ctx context.Context, serverNet, laddr string) error {
  110. c, err := net.ListenPacket(serverNet, laddr)
  111. if err != nil {
  112. return err
  113. }
  114. s := &Server{
  115. Addr: laddr,
  116. Ctx: ctx,
  117. }
  118. return s.serve(c)
  119. }
  120. func normalize(address string) string {
  121. if len(address) == 0 {
  122. address = "0.0.0.0"
  123. }
  124. if !strings.Contains(address, ":") {
  125. address = fmt.Sprintf("%s:%d", address, stun.DefaultPort)
  126. }
  127. return address
  128. }
  129. // Start - starts the stun server
  130. func Start(wg *sync.WaitGroup) {
  131. ctx, cancel := context.WithCancel(context.Background())
  132. go func(wg *sync.WaitGroup) {
  133. defer wg.Done()
  134. quit := make(chan os.Signal, 1)
  135. signal.Notify(quit, syscall.SIGTERM, os.Interrupt)
  136. <-quit
  137. cancel()
  138. }(wg)
  139. normalized := normalize(fmt.Sprintf("0.0.0.0:%d", servercfg.GetStunPort()))
  140. logger.Log(0, "netmaker-stun listening on", normalized, "via udp")
  141. err := listenUDPAndServe(ctx, "udp", normalized)
  142. if err != nil {
  143. logger.Log(0, "failed to start stun server: ", err.Error())
  144. }
  145. }