packet.go 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. package packet
  2. import (
  3. "encoding/binary"
  4. "fmt"
  5. "net/netip"
  6. "github.com/google/gopacket"
  7. "github.com/google/gopacket/layers"
  8. "golang.org/x/net/icmp"
  9. "golang.org/x/net/ipv4"
  10. "golang.org/x/net/ipv6"
  11. )
  12. const (
  13. ipv4MinHeaderLen = 20
  14. ipv6HeaderLen = 40
  15. ipv4MinMTU = 576
  16. ipv6MinMTU = 1280
  17. icmpHeaderLen = 8
  18. // https://www.rfc-editor.org/rfc/rfc792 and https://datatracker.ietf.org/doc/html/rfc4443#section-3.3 define 2 codes.
  19. // 0 = ttl exceed in transit, 1 = fragment reassembly time exceeded
  20. icmpTTLExceedInTransitCode = 0
  21. DefaultTTL uint8 = 255
  22. pseudoHeaderLen = 40
  23. )
  24. // Packet represents an IP packet or a packet that is encapsulated by IP
  25. type Packet interface {
  26. // IPLayer returns the IP of the packet
  27. IPLayer() *IP
  28. // EncodeLayers returns the layers that make up this packet. They can be passed to an Encoder to serialize into RawPacket
  29. EncodeLayers() ([]gopacket.SerializableLayer, error)
  30. }
  31. // IP represents a generic IP packet. It can be embedded in more specific IP protocols
  32. type IP struct {
  33. Src netip.Addr
  34. Dst netip.Addr
  35. Protocol layers.IPProtocol
  36. TTL uint8
  37. }
  38. func newIPv4(ipLayer *layers.IPv4) (*IP, error) {
  39. src, ok := netip.AddrFromSlice(ipLayer.SrcIP)
  40. if !ok {
  41. return nil, fmt.Errorf("cannot convert source IP %s to netip.Addr", ipLayer.SrcIP)
  42. }
  43. dst, ok := netip.AddrFromSlice(ipLayer.DstIP)
  44. if !ok {
  45. return nil, fmt.Errorf("cannot convert source IP %s to netip.Addr", ipLayer.DstIP)
  46. }
  47. return &IP{
  48. Src: src,
  49. Dst: dst,
  50. Protocol: ipLayer.Protocol,
  51. TTL: ipLayer.TTL,
  52. }, nil
  53. }
  54. func newIPv6(ipLayer *layers.IPv6) (*IP, error) {
  55. src, ok := netip.AddrFromSlice(ipLayer.SrcIP)
  56. if !ok {
  57. return nil, fmt.Errorf("cannot convert source IP %s to netip.Addr", ipLayer.SrcIP)
  58. }
  59. dst, ok := netip.AddrFromSlice(ipLayer.DstIP)
  60. if !ok {
  61. return nil, fmt.Errorf("cannot convert source IP %s to netip.Addr", ipLayer.DstIP)
  62. }
  63. return &IP{
  64. Src: src,
  65. Dst: dst,
  66. Protocol: ipLayer.NextHeader,
  67. TTL: ipLayer.HopLimit,
  68. }, nil
  69. }
  70. func (ip *IP) IPLayer() *IP {
  71. return ip
  72. }
  73. func (ip *IP) isIPv4() bool {
  74. return ip.Src.Is4()
  75. }
  76. func (ip *IP) EncodeLayers() ([]gopacket.SerializableLayer, error) {
  77. if ip.isIPv4() {
  78. return []gopacket.SerializableLayer{
  79. &layers.IPv4{
  80. Version: 4,
  81. SrcIP: ip.Src.AsSlice(),
  82. DstIP: ip.Dst.AsSlice(),
  83. Protocol: layers.IPProtocol(ip.Protocol),
  84. TTL: ip.TTL,
  85. },
  86. }, nil
  87. } else {
  88. return []gopacket.SerializableLayer{
  89. &layers.IPv6{
  90. Version: 6,
  91. SrcIP: ip.Src.AsSlice(),
  92. DstIP: ip.Dst.AsSlice(),
  93. NextHeader: layers.IPProtocol(ip.Protocol),
  94. HopLimit: ip.TTL,
  95. },
  96. }, nil
  97. }
  98. }
  99. // ICMP represents is an IP packet + ICMP message
  100. type ICMP struct {
  101. *IP
  102. *icmp.Message
  103. }
  104. func (i *ICMP) EncodeLayers() ([]gopacket.SerializableLayer, error) {
  105. ipLayers, err := i.IP.EncodeLayers()
  106. if err != nil {
  107. return nil, err
  108. }
  109. var serializedPsh []byte = nil
  110. if i.Protocol == layers.IPProtocolICMPv6 {
  111. psh := &PseudoHeader{
  112. SrcIP: i.Src.As16(),
  113. DstIP: i.Dst.As16(),
  114. // i.Marshal re-calculates the UpperLayerPacketLength
  115. UpperLayerPacketLength: 0,
  116. NextHeader: uint8(i.Protocol),
  117. }
  118. serializedPsh = psh.Marshal()
  119. }
  120. msg, err := i.Marshal(serializedPsh)
  121. if err != nil {
  122. return nil, err
  123. }
  124. icmpLayer := gopacket.Payload(msg)
  125. return append(ipLayers, icmpLayer), nil
  126. }
  127. // https://www.rfc-editor.org/rfc/rfc2460#section-8.1
  128. type PseudoHeader struct {
  129. SrcIP [16]byte
  130. DstIP [16]byte
  131. UpperLayerPacketLength uint32
  132. zero [3]byte
  133. NextHeader uint8
  134. }
  135. func (ph *PseudoHeader) Marshal() []byte {
  136. buf := make([]byte, pseudoHeaderLen)
  137. index := 0
  138. copy(buf, ph.SrcIP[:])
  139. index += 16
  140. copy(buf[index:], ph.DstIP[:])
  141. index += 16
  142. binary.BigEndian.PutUint32(buf[index:], ph.UpperLayerPacketLength)
  143. index += 4
  144. copy(buf[index:], ph.zero[:])
  145. buf[pseudoHeaderLen-1] = ph.NextHeader
  146. return buf
  147. }
  148. func NewICMPTTLExceedPacket(originalIP *IP, originalPacket RawPacket, routerIP netip.Addr) *ICMP {
  149. var (
  150. protocol layers.IPProtocol
  151. icmpType icmp.Type
  152. )
  153. if originalIP.Dst.Is4() {
  154. protocol = layers.IPProtocolICMPv4
  155. icmpType = ipv4.ICMPTypeTimeExceeded
  156. } else {
  157. protocol = layers.IPProtocolICMPv6
  158. icmpType = ipv6.ICMPTypeTimeExceeded
  159. }
  160. return &ICMP{
  161. IP: &IP{
  162. Src: routerIP,
  163. Dst: originalIP.Src,
  164. Protocol: protocol,
  165. TTL: DefaultTTL,
  166. },
  167. Message: &icmp.Message{
  168. Type: icmpType,
  169. Code: icmpTTLExceedInTransitCode,
  170. Body: &icmp.TimeExceeded{
  171. Data: originalDatagram(originalPacket, originalIP.Dst.Is4()),
  172. },
  173. },
  174. }
  175. }
  176. // originalDatagram returns a slice of the original datagram for ICMP error messages
  177. // https://www.rfc-editor.org/rfc/rfc1812#section-4.3.2.3 suggests to copy as much without exceeding 576 bytes.
  178. // https://datatracker.ietf.org/doc/html/rfc4443#section-3.3 suggests to copy as much without exceeding 1280 bytes
  179. func originalDatagram(originalPacket RawPacket, isIPv4 bool) []byte {
  180. var upperBound int
  181. if isIPv4 {
  182. upperBound = ipv4MinMTU - ipv4MinHeaderLen - icmpHeaderLen
  183. if upperBound > len(originalPacket.Data) {
  184. upperBound = len(originalPacket.Data)
  185. }
  186. } else {
  187. upperBound = ipv6MinMTU - ipv6HeaderLen - icmpHeaderLen
  188. if upperBound > len(originalPacket.Data) {
  189. upperBound = len(originalPacket.Data)
  190. }
  191. }
  192. return originalPacket.Data[:upperBound]
  193. }