filter.go 1.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. // Copyright (C) 2019 The Syncthing Authors.
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  5. // You can obtain one at https://mozilla.org/MPL/2.0/.
  6. package stun
  7. import (
  8. "bytes"
  9. "net"
  10. "sync"
  11. "time"
  12. )
  13. const (
  14. stunFilterPriority = 10
  15. otherDataPriority = 100
  16. )
  17. type stunFilter struct {
  18. ids map[string]time.Time
  19. mut sync.Mutex
  20. }
  21. func (f *stunFilter) Outgoing(out []byte, addr net.Addr) {
  22. if !f.isStunPayload(out) {
  23. panic("not a stun payload")
  24. }
  25. f.mut.Lock()
  26. f.ids[string(out[8:20])] = time.Now().Add(time.Minute)
  27. f.reap()
  28. f.mut.Unlock()
  29. }
  30. func (f *stunFilter) ClaimIncoming(in []byte, addr net.Addr) bool {
  31. if f.isStunPayload(in) {
  32. f.mut.Lock()
  33. _, ok := f.ids[string(in[8:20])]
  34. f.reap()
  35. f.mut.Unlock()
  36. return ok
  37. }
  38. return false
  39. }
  40. func (f *stunFilter) isStunPayload(data []byte) bool {
  41. // Need at least 20 bytes
  42. if len(data) < 20 {
  43. return false
  44. }
  45. // First two bits always unset, and should always send magic cookie.
  46. return data[0]&0xc0 == 0 && bytes.Equal(data[4:8], []byte{0x21, 0x12, 0xA4, 0x42})
  47. }
  48. func (f *stunFilter) reap() {
  49. now := time.Now()
  50. for id, timeout := range f.ids {
  51. if timeout.Before(now) {
  52. delete(f.ids, id)
  53. }
  54. }
  55. }