ip4.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. package packet
  4. import (
  5. "encoding/binary"
  6. "errors"
  7. "net/netip"
  8. "tailscale.com/types/ipproto"
  9. )
  10. // ip4HeaderLength is the length of an IPv4 header with no IP options.
  11. const ip4HeaderLength = 20
  12. // IP4Header represents an IPv4 packet header.
  13. type IP4Header struct {
  14. IPProto ipproto.Proto
  15. IPID uint16
  16. Src netip.Addr
  17. Dst netip.Addr
  18. }
  19. // Len implements Header.
  20. func (h IP4Header) Len() int {
  21. return ip4HeaderLength
  22. }
  23. var errWrongFamily = errors.New("wrong address family for src/dst IP")
  24. // Marshal implements Header.
  25. func (h IP4Header) Marshal(buf []byte) error {
  26. if len(buf) < h.Len() {
  27. return errSmallBuffer
  28. }
  29. if len(buf) > maxPacketLength {
  30. return errLargePacket
  31. }
  32. if !h.Src.Is4() || !h.Dst.Is4() {
  33. return errWrongFamily
  34. }
  35. buf[0] = 0x40 | (byte(h.Len() >> 2)) // IPv4 + IHL
  36. buf[1] = 0x00 // DSCP + ECN
  37. binary.BigEndian.PutUint16(buf[2:4], uint16(len(buf))) // Total length
  38. binary.BigEndian.PutUint16(buf[4:6], h.IPID) // ID
  39. binary.BigEndian.PutUint16(buf[6:8], 0) // Flags + fragment offset
  40. buf[8] = 64 // TTL
  41. buf[9] = uint8(h.IPProto) // Inner protocol
  42. // Blank checksum. This is necessary even though we overwrite
  43. // it later, because the checksum computation runs over these
  44. // bytes and expects them to be zero.
  45. binary.BigEndian.PutUint16(buf[10:12], 0)
  46. src := h.Src.As4()
  47. dst := h.Dst.As4()
  48. copy(buf[12:16], src[:])
  49. copy(buf[16:20], dst[:])
  50. binary.BigEndian.PutUint16(buf[10:12], ip4Checksum(buf[0:20])) // Checksum
  51. return nil
  52. }
  53. // ToResponse implements Header.
  54. func (h *IP4Header) ToResponse() {
  55. h.Src, h.Dst = h.Dst, h.Src
  56. // Flip the bits in the IPID. If incoming IPIDs are distinct, so are these.
  57. h.IPID = ^h.IPID
  58. }
  59. // ip4Checksum computes an IPv4 checksum, as specified in
  60. // https://tools.ietf.org/html/rfc1071
  61. func ip4Checksum(b []byte) uint16 {
  62. var ac uint32
  63. i := 0
  64. n := len(b)
  65. for n >= 2 {
  66. ac += uint32(binary.BigEndian.Uint16(b[i : i+2]))
  67. n -= 2
  68. i += 2
  69. }
  70. if n == 1 {
  71. ac += uint32(b[i]) << 8
  72. }
  73. for (ac >> 16) > 0 {
  74. ac = (ac >> 16) + (ac & 0xffff)
  75. }
  76. return uint16(^ac)
  77. }
  78. // ip4PseudoHeaderOffset is the number of bytes by which the IPv4 UDP
  79. // pseudo-header is smaller than the real IPv4 header.
  80. const ip4PseudoHeaderOffset = 8
  81. // marshalPseudo serializes h into buf in the "pseudo-header" form
  82. // required when calculating UDP checksums. The pseudo-header starts
  83. // at buf[ip4PseudoHeaderOffset] so as to abut the following UDP
  84. // header, while leaving enough space in buf for a full IPv4 header.
  85. func (h IP4Header) marshalPseudo(buf []byte) error {
  86. if len(buf) < h.Len() {
  87. return errSmallBuffer
  88. }
  89. if len(buf) > maxPacketLength {
  90. return errLargePacket
  91. }
  92. length := len(buf) - h.Len()
  93. src, dst := h.Src.As4(), h.Dst.As4()
  94. copy(buf[8:12], src[:])
  95. copy(buf[12:16], dst[:])
  96. buf[16] = 0x0
  97. buf[17] = uint8(h.IPProto)
  98. binary.BigEndian.PutUint16(buf[18:20], uint16(length))
  99. return nil
  100. }