util.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. package server
  2. import (
  3. "crypto/md5" //nolint:gosec,gci
  4. "fmt"
  5. "io"
  6. "math/rand"
  7. "net"
  8. "strconv"
  9. "time"
  10. "github.com/pion/stun"
  11. "github.com/pion/turn/v2/internal/proto"
  12. )
  13. const (
  14. maximumAllocationLifetime = time.Hour // https://tools.ietf.org/html/rfc5766#section-6.2 defines 3600 seconds recommendation
  15. nonceLifetime = time.Hour // https://tools.ietf.org/html/rfc5766#section-4
  16. )
  17. func randSeq(n int) string {
  18. letters := []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
  19. b := make([]rune, n)
  20. for i := range b {
  21. b[i] = letters[rand.Intn(len(letters))] //nolint:gosec
  22. }
  23. return string(b)
  24. }
  25. func buildNonce() (string, error) {
  26. /* #nosec */
  27. h := md5.New()
  28. if _, err := io.WriteString(h, strconv.FormatInt(time.Now().Unix(), 10)); err != nil {
  29. return "", fmt.Errorf("%w: %v", errFailedToGenerateNonce, err)
  30. }
  31. if _, err := io.WriteString(h, strconv.FormatInt(rand.Int63(), 10)); err != nil { //nolint:gosec
  32. return "", fmt.Errorf("%w: %v", errFailedToGenerateNonce, err)
  33. }
  34. return fmt.Sprintf("%x", h.Sum(nil)), nil
  35. }
  36. func buildAndSend(conn net.PacketConn, dst net.Addr, attrs ...stun.Setter) error {
  37. msg, err := stun.Build(attrs...)
  38. if err != nil {
  39. return err
  40. }
  41. _, err = conn.WriteTo(msg.Raw, dst)
  42. return err
  43. }
  44. // Send a STUN packet and return the original error to the caller
  45. func buildAndSendErr(conn net.PacketConn, dst net.Addr, err error, attrs ...stun.Setter) error {
  46. if sendErr := buildAndSend(conn, dst, attrs...); sendErr != nil {
  47. err = fmt.Errorf("%w %v %v", errFailedToSendError, sendErr, err)
  48. }
  49. return err
  50. }
  51. func buildMsg(transactionID [stun.TransactionIDSize]byte, msgType stun.MessageType, additional ...stun.Setter) []stun.Setter {
  52. return append([]stun.Setter{&stun.Message{TransactionID: transactionID}, msgType}, additional...)
  53. }
  54. func authenticateRequest(r Request, m *stun.Message, callingMethod stun.Method) (stun.MessageIntegrity, bool, error) {
  55. respondWithNonce := func(responseCode stun.ErrorCode) (stun.MessageIntegrity, bool, error) {
  56. nonce, err := buildNonce()
  57. if err != nil {
  58. return nil, false, err
  59. }
  60. // Nonce has already been taken
  61. if _, keyCollision := r.Nonces.LoadOrStore(nonce, time.Now()); keyCollision {
  62. return nil, false, errDuplicatedNonce
  63. }
  64. return nil, false, buildAndSend(r.Conn, r.SrcAddr, buildMsg(m.TransactionID,
  65. stun.NewType(callingMethod, stun.ClassErrorResponse),
  66. &stun.ErrorCodeAttribute{Code: responseCode},
  67. stun.NewNonce(nonce),
  68. stun.NewRealm(r.Realm),
  69. )...)
  70. }
  71. if !m.Contains(stun.AttrMessageIntegrity) {
  72. return respondWithNonce(stun.CodeUnauthorized)
  73. }
  74. nonceAttr := &stun.Nonce{}
  75. usernameAttr := &stun.Username{}
  76. realmAttr := &stun.Realm{}
  77. badRequestMsg := buildMsg(m.TransactionID, stun.NewType(callingMethod, stun.ClassErrorResponse), &stun.ErrorCodeAttribute{Code: stun.CodeBadRequest})
  78. if err := nonceAttr.GetFrom(m); err != nil {
  79. return nil, false, buildAndSendErr(r.Conn, r.SrcAddr, err, badRequestMsg...)
  80. }
  81. // Assert Nonce exists and is not expired
  82. nonceCreationTime, ok := r.Nonces.Load(string(*nonceAttr))
  83. if !ok || time.Since(nonceCreationTime.(time.Time)) >= nonceLifetime {
  84. r.Nonces.Delete(nonceAttr)
  85. return respondWithNonce(stun.CodeStaleNonce)
  86. }
  87. if err := realmAttr.GetFrom(m); err != nil {
  88. return nil, false, buildAndSendErr(r.Conn, r.SrcAddr, err, badRequestMsg...)
  89. } else if err := usernameAttr.GetFrom(m); err != nil {
  90. return nil, false, buildAndSendErr(r.Conn, r.SrcAddr, err, badRequestMsg...)
  91. }
  92. ourKey, ok := r.AuthHandler(usernameAttr.String(), realmAttr.String(), r.SrcAddr)
  93. if !ok {
  94. return nil, false, buildAndSendErr(r.Conn, r.SrcAddr, fmt.Errorf("%w %s", errNoSuchUser, usernameAttr.String()), badRequestMsg...)
  95. }
  96. if err := stun.MessageIntegrity(ourKey).Check(m); err != nil {
  97. return nil, false, buildAndSendErr(r.Conn, r.SrcAddr, err, badRequestMsg...)
  98. }
  99. return stun.MessageIntegrity(ourKey), true, nil
  100. }
  101. func allocationLifeTime(m *stun.Message) time.Duration {
  102. lifetimeDuration := proto.DefaultLifetime
  103. var lifetime proto.Lifetime
  104. if err := lifetime.GetFrom(m); err == nil {
  105. if lifetime.Duration < maximumAllocationLifetime {
  106. lifetimeDuration = lifetime.Duration
  107. }
  108. }
  109. return lifetimeDuration
  110. }