packet.go 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. package firewall
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. mathrand "math/rand"
  6. "net/netip"
  7. )
  8. type m = map[string]any
  9. const (
  10. ProtoAny = 0 // When we want to handle HOPOPT (0) we can change this, if ever
  11. ProtoTCP = 6
  12. ProtoUDP = 17
  13. ProtoICMP = 1
  14. ProtoICMPv6 = 58
  15. PortAny = 0 // Special value for matching `port: any`
  16. PortFragment = -1 // Special value for matching `port: fragment`
  17. )
  18. type Packet struct {
  19. LocalAddr netip.Addr
  20. RemoteAddr netip.Addr
  21. LocalPort uint16
  22. RemotePort uint16
  23. Protocol uint8
  24. Fragment bool
  25. }
  26. func (fp *Packet) Copy() *Packet {
  27. return &Packet{
  28. LocalAddr: fp.LocalAddr,
  29. RemoteAddr: fp.RemoteAddr,
  30. LocalPort: fp.LocalPort,
  31. RemotePort: fp.RemotePort,
  32. Protocol: fp.Protocol,
  33. Fragment: fp.Fragment,
  34. }
  35. }
  36. func (fp Packet) MarshalJSON() ([]byte, error) {
  37. var proto string
  38. switch fp.Protocol {
  39. case ProtoTCP:
  40. proto = "tcp"
  41. case ProtoICMP:
  42. proto = "icmp"
  43. case ProtoUDP:
  44. proto = "udp"
  45. default:
  46. proto = fmt.Sprintf("unknown %v", fp.Protocol)
  47. }
  48. return json.Marshal(m{
  49. "LocalAddr": fp.LocalAddr.String(),
  50. "RemoteAddr": fp.RemoteAddr.String(),
  51. "LocalPort": fp.LocalPort,
  52. "RemotePort": fp.RemotePort,
  53. "Protocol": proto,
  54. "Fragment": fp.Fragment,
  55. })
  56. }
  57. // UDPSendPort calculates the UDP port to send from when using multiport mode.
  58. // The result will be from [0, numBuckets)
  59. func (fp Packet) UDPSendPort(numBuckets int) uint16 {
  60. if numBuckets <= 1 {
  61. return 0
  62. }
  63. // If there is no port (like an ICMP packet), pick a random UDP send port
  64. if fp.LocalPort == 0 {
  65. return uint16(mathrand.Intn(numBuckets))
  66. }
  67. // A decent enough 32bit hash function
  68. // Prospecting for Hash Functions
  69. // - https://nullprogram.com/blog/2018/07/31/
  70. // - https://github.com/skeeto/hash-prospector
  71. // [16 21f0aaad 15 d35a2d97 15] = 0.10760229515479501
  72. x := (uint32(fp.LocalPort) << 16) | uint32(fp.RemotePort)
  73. x ^= x >> 16
  74. x *= 0x21f0aaad
  75. x ^= x >> 15
  76. x *= 0xd35a2d97
  77. x ^= x >> 15
  78. return uint16(x) % uint16(numBuckets)
  79. }