snat.go 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. package nebula
  2. import (
  3. "encoding/binary"
  4. "net/netip"
  5. )
  6. func recalcIPv4Checksum(data []byte, oldSrcIP netip.Addr, newSrcIP netip.Addr) {
  7. oldChecksum := binary.BigEndian.Uint16(data[10:12])
  8. //because of how checksums work, we can re-use this function
  9. checksum := calcNewTransportChecksum(oldChecksum, oldSrcIP, 0, newSrcIP, 0)
  10. binary.BigEndian.PutUint16(data[10:12], checksum)
  11. }
  12. func calcNewTransportChecksum(oldChecksum uint16, oldSrcIP netip.Addr, oldSrcPort uint16, newSrcIP netip.Addr, newSrcPort uint16) uint16 {
  13. oldIP := binary.BigEndian.Uint32(oldSrcIP.AsSlice())
  14. newIP := binary.BigEndian.Uint32(newSrcIP.AsSlice())
  15. // Start with inverted checksum
  16. checksum := uint32(^oldChecksum)
  17. // Subtract old IP (as two 16-bit words)
  18. checksum += uint32(^uint16(oldIP >> 16))
  19. checksum += uint32(^uint16(oldIP & 0xFFFF))
  20. // Subtract old port
  21. checksum += uint32(^oldSrcPort)
  22. // Add new IP (as two 16-bit words)
  23. checksum += uint32(newIP >> 16)
  24. checksum += uint32(newIP & 0xFFFF)
  25. // Add new port
  26. checksum += uint32(newSrcPort)
  27. // Fold carries
  28. for checksum > 0xFFFF {
  29. checksum = (checksum & 0xFFFF) + (checksum >> 16)
  30. }
  31. // Return ones' complement
  32. return ^uint16(checksum)
  33. }
  34. func recalcV4TransportChecksum(offsetInsideHeader int, data []byte, oldSrcIP netip.AddrPort, newSrcIP netip.AddrPort) {
  35. ipHeaderOffset := int(data[0]&0x0F) * 4
  36. offset := ipHeaderOffset + offsetInsideHeader
  37. oldcsum := binary.BigEndian.Uint16(data[offset : offset+2])
  38. checksum := calcNewTransportChecksum(oldcsum, oldSrcIP.Addr(), oldSrcIP.Port(), newSrcIP.Addr(), newSrcIP.Port())
  39. binary.BigEndian.PutUint16(data[offset:offset+2], checksum)
  40. }
  41. func recalcUDPv4Checksum(data []byte, oldSrcIP netip.AddrPort, newSrcIP netip.AddrPort) {
  42. const offsetInsideHeader = 6
  43. recalcV4TransportChecksum(offsetInsideHeader, data, oldSrcIP, newSrcIP)
  44. }
  45. func recalcTCPv4Checksum(data []byte, oldSrcIP netip.AddrPort, newSrcIP netip.AddrPort) {
  46. const offsetInsideHeader = 16
  47. recalcV4TransportChecksum(offsetInsideHeader, data, oldSrcIP, newSrcIP)
  48. }
  49. func calcNewICMPChecksum(oldChecksum uint16, oldCode uint16, newCode uint16, oldID uint16, newID uint16) uint16 {
  50. // Start with inverted checksum
  51. checksum := uint32(^oldChecksum)
  52. // Subtract old stuff
  53. checksum += uint32(^oldCode)
  54. checksum += uint32(^oldID)
  55. // Add new stuff
  56. checksum += uint32(newCode)
  57. checksum += uint32(newID)
  58. // Fold carries
  59. for checksum > 0xFFFF {
  60. checksum = (checksum & 0xFFFF) + (checksum >> 16)
  61. }
  62. // Return ones' complement
  63. return ^uint16(checksum)
  64. }
  65. func recalcICMPv4Checksum(data []byte, oldCode uint16, newCode uint16, oldID uint16, newID uint16) {
  66. const offsetInsideHeader = 2
  67. ipHeaderOffset := int(data[0]&0x0F) * 4
  68. offset := ipHeaderOffset + offsetInsideHeader
  69. oldChecksum := binary.BigEndian.Uint16(data[offset : offset+2])
  70. checksum := calcNewICMPChecksum(oldChecksum, oldCode, newCode, oldID, newID)
  71. binary.BigEndian.PutUint16(data[offset:offset+2], checksum)
  72. }