ntp.go 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  1. package sniff
  2. import (
  3. "context"
  4. "encoding/binary"
  5. "os"
  6. "github.com/sagernet/sing-box/adapter"
  7. C "github.com/sagernet/sing-box/constant"
  8. )
  9. func NTP(ctx context.Context, metadata *adapter.InboundContext, packet []byte) error {
  10. // NTP packets must be at least 48 bytes long (standard NTP header size).
  11. pLen := len(packet)
  12. if pLen < 48 {
  13. return os.ErrInvalid
  14. }
  15. // Check the LI (Leap Indicator) and Version Number (VN) in the first byte.
  16. // We'll primarily focus on ensuring the version is valid for NTP.
  17. // Many NTP versions are used, but let's check for generally accepted ones (3 & 4 for IPv4, plus potential extensions/customizations)
  18. firstByte := packet[0]
  19. li := (firstByte >> 6) & 0x03 // Extract LI
  20. vn := (firstByte >> 3) & 0x07 // Extract VN
  21. mode := firstByte & 0x07 // Extract Mode
  22. // Leap Indicator should be a valid value (0-3).
  23. if li > 3 {
  24. return os.ErrInvalid
  25. }
  26. // Version Check (common NTP versions are 3 and 4)
  27. if vn != 3 && vn != 4 {
  28. return os.ErrInvalid
  29. }
  30. // Check the Mode field for a client request (Mode 3). This validates it *is* a request.
  31. if mode != 3 {
  32. return os.ErrInvalid
  33. }
  34. // Check Root Delay and Root Dispersion. While not strictly *required* for a request,
  35. // we can check if they appear to be reasonable values (not excessively large).
  36. rootDelay := binary.BigEndian.Uint32(packet[4:8])
  37. rootDispersion := binary.BigEndian.Uint32(packet[8:12])
  38. // Check for unreasonably large root delay and dispersion. NTP RFC specifies max values of approximately 16 seconds.
  39. // Convert to milliseconds for easy comparison. Each unit is 1/2^16 seconds.
  40. if float64(rootDelay)/65536.0 > 16.0 {
  41. return os.ErrInvalid
  42. }
  43. if float64(rootDispersion)/65536.0 > 16.0 {
  44. return os.ErrInvalid
  45. }
  46. metadata.Protocol = C.ProtocolNTP
  47. return nil
  48. }