outside_test.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635
  1. package nebula
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "net"
  6. "net/netip"
  7. "testing"
  8. "github.com/google/gopacket"
  9. "github.com/google/gopacket/layers"
  10. "github.com/slackhq/nebula/firewall"
  11. "github.com/stretchr/testify/assert"
  12. "github.com/stretchr/testify/require"
  13. "golang.org/x/net/ipv4"
  14. )
  15. func Test_newPacket(t *testing.T) {
  16. p := &firewall.Packet{}
  17. // length fails
  18. err := newPacket([]byte{}, true, p)
  19. require.ErrorIs(t, err, ErrPacketTooShort)
  20. err = newPacket([]byte{0x40}, true, p)
  21. require.ErrorIs(t, err, ErrIPv4PacketTooShort)
  22. err = newPacket([]byte{0x60}, true, p)
  23. require.ErrorIs(t, err, ErrIPv6PacketTooShort)
  24. // length fail with ip options
  25. h := ipv4.Header{
  26. Version: 1,
  27. Len: 100,
  28. Src: net.IPv4(10, 0, 0, 1),
  29. Dst: net.IPv4(10, 0, 0, 2),
  30. Options: []byte{0, 1, 0, 2},
  31. }
  32. b, _ := h.Marshal()
  33. err = newPacket(b, true, p)
  34. require.ErrorIs(t, err, ErrIPv4InvalidHeaderLength)
  35. // not an ipv4 packet
  36. err = newPacket([]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, true, p)
  37. require.ErrorIs(t, err, ErrUnknownIPVersion)
  38. // invalid ihl
  39. err = newPacket([]byte{4<<4 | (8 >> 2 & 0x0f), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, true, p)
  40. require.ErrorIs(t, err, ErrIPv4InvalidHeaderLength)
  41. // account for variable ip header length - incoming
  42. h = ipv4.Header{
  43. Version: 1,
  44. Len: 100,
  45. Src: net.IPv4(10, 0, 0, 1),
  46. Dst: net.IPv4(10, 0, 0, 2),
  47. Options: []byte{0, 1, 0, 2},
  48. Protocol: firewall.ProtoTCP,
  49. }
  50. b, _ = h.Marshal()
  51. b = append(b, []byte{0, 3, 0, 4}...)
  52. err = newPacket(b, true, p)
  53. require.NoError(t, err)
  54. assert.Equal(t, uint8(firewall.ProtoTCP), p.Protocol)
  55. assert.Equal(t, netip.MustParseAddr("10.0.0.2"), p.LocalAddr)
  56. assert.Equal(t, netip.MustParseAddr("10.0.0.1"), p.RemoteAddr)
  57. assert.Equal(t, uint16(3), p.RemotePort)
  58. assert.Equal(t, uint16(4), p.LocalPort)
  59. assert.False(t, p.Fragment)
  60. // account for variable ip header length - outgoing
  61. h = ipv4.Header{
  62. Version: 1,
  63. Protocol: 2,
  64. Len: 100,
  65. Src: net.IPv4(10, 0, 0, 1),
  66. Dst: net.IPv4(10, 0, 0, 2),
  67. Options: []byte{0, 1, 0, 2},
  68. }
  69. b, _ = h.Marshal()
  70. b = append(b, []byte{0, 5, 0, 6}...)
  71. err = newPacket(b, false, p)
  72. require.NoError(t, err)
  73. assert.Equal(t, uint8(2), p.Protocol)
  74. assert.Equal(t, netip.MustParseAddr("10.0.0.1"), p.LocalAddr)
  75. assert.Equal(t, netip.MustParseAddr("10.0.0.2"), p.RemoteAddr)
  76. assert.Equal(t, uint16(6), p.RemotePort)
  77. assert.Equal(t, uint16(5), p.LocalPort)
  78. assert.False(t, p.Fragment)
  79. }
  80. func Test_newPacket_v6(t *testing.T) {
  81. p := &firewall.Packet{}
  82. // invalid ipv6
  83. ip := layers.IPv6{
  84. Version: 6,
  85. HopLimit: 128,
  86. SrcIP: net.IPv6linklocalallrouters,
  87. DstIP: net.IPv6linklocalallnodes,
  88. }
  89. buffer := gopacket.NewSerializeBuffer()
  90. opt := gopacket.SerializeOptions{
  91. ComputeChecksums: false,
  92. FixLengths: false,
  93. }
  94. err := gopacket.SerializeLayers(buffer, opt, &ip)
  95. require.NoError(t, err)
  96. err = newPacket(buffer.Bytes(), true, p)
  97. require.ErrorIs(t, err, ErrIPv6CouldNotFindPayload)
  98. // A v6 packet with a hop-by-hop extension
  99. // ICMPv6 Payload (Echo Request)
  100. icmpLayer := layers.ICMPv6{
  101. TypeCode: layers.ICMPv6TypeEchoRequest,
  102. }
  103. // Hop-by-Hop Extension Header
  104. hopOption := layers.IPv6HopByHopOption{}
  105. hopOption.OptionData = []byte{0, 0, 0, 0}
  106. hopByHop := layers.IPv6HopByHop{}
  107. hopByHop.Options = append(hopByHop.Options, &hopOption)
  108. ip = layers.IPv6{
  109. Version: 6,
  110. HopLimit: 128,
  111. NextHeader: layers.IPProtocolIPv6Destination,
  112. SrcIP: net.IPv6linklocalallrouters,
  113. DstIP: net.IPv6linklocalallnodes,
  114. }
  115. buffer.Clear()
  116. err = gopacket.SerializeLayers(buffer, gopacket.SerializeOptions{
  117. ComputeChecksums: false,
  118. FixLengths: true,
  119. }, &ip, &hopByHop, &icmpLayer)
  120. if err != nil {
  121. panic(err)
  122. }
  123. // Ensure buffer length checks during parsing with the next 2 tests.
  124. // A full IPv6 header and 1 byte in the first extension, but missing
  125. // the length byte.
  126. err = newPacket(buffer.Bytes()[:41], true, p)
  127. require.ErrorIs(t, err, ErrIPv6CouldNotFindPayload)
  128. // A full IPv6 header plus 1 full extension, but only 1 byte of the
  129. // next layer, missing length byte
  130. err = newPacket(buffer.Bytes()[:49], true, p)
  131. require.ErrorIs(t, err, ErrIPv6CouldNotFindPayload)
  132. // A good ICMP packet
  133. ip = layers.IPv6{
  134. Version: 6,
  135. NextHeader: layers.IPProtocolICMPv6,
  136. HopLimit: 128,
  137. SrcIP: net.IPv6linklocalallrouters,
  138. DstIP: net.IPv6linklocalallnodes,
  139. }
  140. icmp := layers.ICMPv6{}
  141. buffer.Clear()
  142. err = gopacket.SerializeLayers(buffer, opt, &ip, &icmp)
  143. if err != nil {
  144. panic(err)
  145. }
  146. err = newPacket(buffer.Bytes(), true, p)
  147. require.NoError(t, err)
  148. assert.Equal(t, uint8(layers.IPProtocolICMPv6), p.Protocol)
  149. assert.Equal(t, netip.MustParseAddr("ff02::2"), p.RemoteAddr)
  150. assert.Equal(t, netip.MustParseAddr("ff02::1"), p.LocalAddr)
  151. assert.Equal(t, uint16(0), p.RemotePort)
  152. assert.Equal(t, uint16(0), p.LocalPort)
  153. assert.False(t, p.Fragment)
  154. // A good ESP packet
  155. b := buffer.Bytes()
  156. b[6] = byte(layers.IPProtocolESP)
  157. err = newPacket(b, true, p)
  158. require.NoError(t, err)
  159. assert.Equal(t, uint8(layers.IPProtocolESP), p.Protocol)
  160. assert.Equal(t, netip.MustParseAddr("ff02::2"), p.RemoteAddr)
  161. assert.Equal(t, netip.MustParseAddr("ff02::1"), p.LocalAddr)
  162. assert.Equal(t, uint16(0), p.RemotePort)
  163. assert.Equal(t, uint16(0), p.LocalPort)
  164. assert.False(t, p.Fragment)
  165. // A good None packet
  166. b = buffer.Bytes()
  167. b[6] = byte(layers.IPProtocolNoNextHeader)
  168. err = newPacket(b, true, p)
  169. require.NoError(t, err)
  170. assert.Equal(t, uint8(layers.IPProtocolNoNextHeader), p.Protocol)
  171. assert.Equal(t, netip.MustParseAddr("ff02::2"), p.RemoteAddr)
  172. assert.Equal(t, netip.MustParseAddr("ff02::1"), p.LocalAddr)
  173. assert.Equal(t, uint16(0), p.RemotePort)
  174. assert.Equal(t, uint16(0), p.LocalPort)
  175. assert.False(t, p.Fragment)
  176. // An unknown protocol packet
  177. b = buffer.Bytes()
  178. b[6] = 255 // 255 is a reserved protocol number
  179. err = newPacket(b, true, p)
  180. require.ErrorIs(t, err, ErrIPv6CouldNotFindPayload)
  181. // A good UDP packet
  182. ip = layers.IPv6{
  183. Version: 6,
  184. NextHeader: firewall.ProtoUDP,
  185. HopLimit: 128,
  186. SrcIP: net.IPv6linklocalallrouters,
  187. DstIP: net.IPv6linklocalallnodes,
  188. }
  189. udp := layers.UDP{
  190. SrcPort: layers.UDPPort(36123),
  191. DstPort: layers.UDPPort(22),
  192. }
  193. err = udp.SetNetworkLayerForChecksum(&ip)
  194. require.NoError(t, err)
  195. buffer.Clear()
  196. err = gopacket.SerializeLayers(buffer, opt, &ip, &udp, gopacket.Payload([]byte{0xde, 0xad, 0xbe, 0xef}))
  197. if err != nil {
  198. panic(err)
  199. }
  200. b = buffer.Bytes()
  201. // incoming
  202. err = newPacket(b, true, p)
  203. require.NoError(t, err)
  204. assert.Equal(t, uint8(firewall.ProtoUDP), p.Protocol)
  205. assert.Equal(t, netip.MustParseAddr("ff02::2"), p.RemoteAddr)
  206. assert.Equal(t, netip.MustParseAddr("ff02::1"), p.LocalAddr)
  207. assert.Equal(t, uint16(36123), p.RemotePort)
  208. assert.Equal(t, uint16(22), p.LocalPort)
  209. assert.False(t, p.Fragment)
  210. // outgoing
  211. err = newPacket(b, false, p)
  212. require.NoError(t, err)
  213. assert.Equal(t, uint8(firewall.ProtoUDP), p.Protocol)
  214. assert.Equal(t, netip.MustParseAddr("ff02::2"), p.LocalAddr)
  215. assert.Equal(t, netip.MustParseAddr("ff02::1"), p.RemoteAddr)
  216. assert.Equal(t, uint16(36123), p.LocalPort)
  217. assert.Equal(t, uint16(22), p.RemotePort)
  218. assert.False(t, p.Fragment)
  219. // Too short UDP packet
  220. err = newPacket(b[:len(b)-10], false, p) // pull off the last 10 bytes
  221. require.ErrorIs(t, err, ErrIPv6PacketTooShort)
  222. // A good TCP packet
  223. b[6] = byte(layers.IPProtocolTCP)
  224. // incoming
  225. err = newPacket(b, true, p)
  226. require.NoError(t, err)
  227. assert.Equal(t, uint8(firewall.ProtoTCP), p.Protocol)
  228. assert.Equal(t, netip.MustParseAddr("ff02::2"), p.RemoteAddr)
  229. assert.Equal(t, netip.MustParseAddr("ff02::1"), p.LocalAddr)
  230. assert.Equal(t, uint16(36123), p.RemotePort)
  231. assert.Equal(t, uint16(22), p.LocalPort)
  232. assert.False(t, p.Fragment)
  233. // outgoing
  234. err = newPacket(b, false, p)
  235. require.NoError(t, err)
  236. assert.Equal(t, uint8(firewall.ProtoTCP), p.Protocol)
  237. assert.Equal(t, netip.MustParseAddr("ff02::2"), p.LocalAddr)
  238. assert.Equal(t, netip.MustParseAddr("ff02::1"), p.RemoteAddr)
  239. assert.Equal(t, uint16(36123), p.LocalPort)
  240. assert.Equal(t, uint16(22), p.RemotePort)
  241. assert.False(t, p.Fragment)
  242. // Too short TCP packet
  243. err = newPacket(b[:len(b)-10], false, p) // pull off the last 10 bytes
  244. require.ErrorIs(t, err, ErrIPv6PacketTooShort)
  245. // A good UDP packet with an AH header
  246. ip = layers.IPv6{
  247. Version: 6,
  248. NextHeader: layers.IPProtocolAH,
  249. HopLimit: 128,
  250. SrcIP: net.IPv6linklocalallrouters,
  251. DstIP: net.IPv6linklocalallnodes,
  252. }
  253. ah := layers.IPSecAH{
  254. AuthenticationData: []byte{0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef},
  255. }
  256. ah.NextHeader = layers.IPProtocolUDP
  257. udpHeader := []byte{
  258. 0x8d, 0x1b, // Source port 36123
  259. 0x00, 0x16, // Destination port 22
  260. 0x00, 0x00, // Length
  261. 0x00, 0x00, // Checksum
  262. }
  263. buffer.Clear()
  264. err = ip.SerializeTo(buffer, opt)
  265. if err != nil {
  266. panic(err)
  267. }
  268. b = buffer.Bytes()
  269. ahb := serializeAH(&ah)
  270. b = append(b, ahb...)
  271. b = append(b, udpHeader...)
  272. err = newPacket(b, true, p)
  273. require.NoError(t, err)
  274. assert.Equal(t, uint8(firewall.ProtoUDP), p.Protocol)
  275. assert.Equal(t, netip.MustParseAddr("ff02::2"), p.RemoteAddr)
  276. assert.Equal(t, netip.MustParseAddr("ff02::1"), p.LocalAddr)
  277. assert.Equal(t, uint16(36123), p.RemotePort)
  278. assert.Equal(t, uint16(22), p.LocalPort)
  279. assert.False(t, p.Fragment)
  280. // Ensure buffer bounds checking during processing
  281. err = newPacket(b[:41], true, p)
  282. require.ErrorIs(t, err, ErrIPv6PacketTooShort)
  283. // Invalid AH header
  284. b = buffer.Bytes()
  285. err = newPacket(b, true, p)
  286. require.ErrorIs(t, err, ErrIPv6CouldNotFindPayload)
  287. }
  288. func Test_newPacket_ipv6Fragment(t *testing.T) {
  289. p := &firewall.Packet{}
  290. ip := &layers.IPv6{
  291. Version: 6,
  292. NextHeader: layers.IPProtocolIPv6Fragment,
  293. HopLimit: 64,
  294. SrcIP: net.IPv6linklocalallrouters,
  295. DstIP: net.IPv6linklocalallnodes,
  296. }
  297. // First fragment
  298. fragHeader1 := []byte{
  299. uint8(layers.IPProtocolUDP), // Next Header (UDP)
  300. 0x00, // Reserved
  301. 0x00, // Fragment Offset high byte (0)
  302. 0x01, // Fragment Offset low byte & flags (M=1)
  303. 0x00, 0x00, 0x00, 0x01, // Identification
  304. }
  305. udpHeader := []byte{
  306. 0x8d, 0x1b, // Source port 36123
  307. 0x00, 0x16, // Destination port 22
  308. 0x00, 0x00, // Length
  309. 0x00, 0x00, // Checksum
  310. }
  311. buffer := gopacket.NewSerializeBuffer()
  312. opts := gopacket.SerializeOptions{
  313. ComputeChecksums: true,
  314. FixLengths: true,
  315. }
  316. err := ip.SerializeTo(buffer, opts)
  317. if err != nil {
  318. t.Fatal(err)
  319. }
  320. firstFrag := buffer.Bytes()
  321. firstFrag = append(firstFrag, fragHeader1...)
  322. firstFrag = append(firstFrag, udpHeader...)
  323. firstFrag = append(firstFrag, []byte{0xde, 0xad, 0xbe, 0xef}...)
  324. // Test first fragment incoming
  325. err = newPacket(firstFrag, true, p)
  326. require.NoError(t, err)
  327. assert.Equal(t, netip.MustParseAddr("ff02::2"), p.RemoteAddr)
  328. assert.Equal(t, netip.MustParseAddr("ff02::1"), p.LocalAddr)
  329. assert.Equal(t, uint8(layers.IPProtocolUDP), p.Protocol)
  330. assert.Equal(t, uint16(36123), p.RemotePort)
  331. assert.Equal(t, uint16(22), p.LocalPort)
  332. assert.False(t, p.Fragment)
  333. // Test first fragment outgoing
  334. err = newPacket(firstFrag, false, p)
  335. require.NoError(t, err)
  336. assert.Equal(t, netip.MustParseAddr("ff02::2"), p.LocalAddr)
  337. assert.Equal(t, netip.MustParseAddr("ff02::1"), p.RemoteAddr)
  338. assert.Equal(t, uint8(layers.IPProtocolUDP), p.Protocol)
  339. assert.Equal(t, uint16(36123), p.LocalPort)
  340. assert.Equal(t, uint16(22), p.RemotePort)
  341. assert.False(t, p.Fragment)
  342. // Second fragment
  343. fragHeader2 := []byte{
  344. uint8(layers.IPProtocolUDP), // Next Header (UDP)
  345. 0x00, // Reserved
  346. 0xb9, // Fragment Offset high byte (185)
  347. 0x01, // Fragment Offset low byte & flags (M=1)
  348. 0x00, 0x00, 0x00, 0x01, // Identification
  349. }
  350. buffer.Clear()
  351. err = ip.SerializeTo(buffer, opts)
  352. if err != nil {
  353. t.Fatal(err)
  354. }
  355. secondFrag := buffer.Bytes()
  356. secondFrag = append(secondFrag, fragHeader2...)
  357. secondFrag = append(secondFrag, []byte{0xde, 0xad, 0xbe, 0xef}...)
  358. // Test second fragment incoming
  359. err = newPacket(secondFrag, true, p)
  360. require.NoError(t, err)
  361. assert.Equal(t, netip.MustParseAddr("ff02::2"), p.RemoteAddr)
  362. assert.Equal(t, netip.MustParseAddr("ff02::1"), p.LocalAddr)
  363. assert.Equal(t, uint8(layers.IPProtocolUDP), p.Protocol)
  364. assert.Equal(t, uint16(0), p.RemotePort)
  365. assert.Equal(t, uint16(0), p.LocalPort)
  366. assert.True(t, p.Fragment)
  367. // Test second fragment outgoing
  368. err = newPacket(secondFrag, false, p)
  369. require.NoError(t, err)
  370. assert.Equal(t, netip.MustParseAddr("ff02::2"), p.LocalAddr)
  371. assert.Equal(t, netip.MustParseAddr("ff02::1"), p.RemoteAddr)
  372. assert.Equal(t, uint8(layers.IPProtocolUDP), p.Protocol)
  373. assert.Equal(t, uint16(0), p.LocalPort)
  374. assert.Equal(t, uint16(0), p.RemotePort)
  375. assert.True(t, p.Fragment)
  376. // Too short of a fragment packet
  377. err = newPacket(secondFrag[:len(secondFrag)-10], false, p)
  378. require.ErrorIs(t, err, ErrIPv6PacketTooShort)
  379. }
  380. func BenchmarkParseV6(b *testing.B) {
  381. // Regular UDP packet
  382. ip := &layers.IPv6{
  383. Version: 6,
  384. NextHeader: layers.IPProtocolUDP,
  385. HopLimit: 64,
  386. SrcIP: net.IPv6linklocalallrouters,
  387. DstIP: net.IPv6linklocalallnodes,
  388. }
  389. udp := &layers.UDP{
  390. SrcPort: layers.UDPPort(36123),
  391. DstPort: layers.UDPPort(22),
  392. }
  393. buffer := gopacket.NewSerializeBuffer()
  394. opts := gopacket.SerializeOptions{
  395. ComputeChecksums: false,
  396. FixLengths: true,
  397. }
  398. err := gopacket.SerializeLayers(buffer, opts, ip, udp)
  399. if err != nil {
  400. b.Fatal(err)
  401. }
  402. normalPacket := buffer.Bytes()
  403. // First Fragment packet
  404. ipFrag := &layers.IPv6{
  405. Version: 6,
  406. NextHeader: layers.IPProtocolIPv6Fragment,
  407. HopLimit: 64,
  408. SrcIP: net.IPv6linklocalallrouters,
  409. DstIP: net.IPv6linklocalallnodes,
  410. }
  411. fragHeader := []byte{
  412. uint8(layers.IPProtocolUDP), // Next Header (UDP)
  413. 0x00, // Reserved
  414. 0x00, // Fragment Offset high byte (0)
  415. 0x01, // Fragment Offset low byte & flags (M=1)
  416. 0x00, 0x00, 0x00, 0x01, // Identification
  417. }
  418. udpHeader := []byte{
  419. 0x8d, 0x7b, // Source port 36123
  420. 0x00, 0x16, // Destination port 22
  421. 0x00, 0x00, // Length
  422. 0x00, 0x00, // Checksum
  423. }
  424. buffer.Clear()
  425. err = ipFrag.SerializeTo(buffer, opts)
  426. if err != nil {
  427. b.Fatal(err)
  428. }
  429. firstFrag := buffer.Bytes()
  430. firstFrag = append(firstFrag, fragHeader...)
  431. firstFrag = append(firstFrag, udpHeader...)
  432. firstFrag = append(firstFrag, []byte{0xde, 0xad, 0xbe, 0xef}...)
  433. // Second Fragment packet
  434. fragHeader[2] = 0xb9 // offset 185
  435. buffer.Clear()
  436. err = ipFrag.SerializeTo(buffer, opts)
  437. if err != nil {
  438. b.Fatal(err)
  439. }
  440. secondFrag := buffer.Bytes()
  441. secondFrag = append(secondFrag, fragHeader...)
  442. secondFrag = append(secondFrag, []byte{0xde, 0xad, 0xbe, 0xef}...)
  443. fp := &firewall.Packet{}
  444. b.Run("Normal", func(b *testing.B) {
  445. for i := 0; i < b.N; i++ {
  446. if err = parseV6(normalPacket, true, fp); err != nil {
  447. b.Fatal(err)
  448. }
  449. }
  450. })
  451. b.Run("FirstFragment", func(b *testing.B) {
  452. for i := 0; i < b.N; i++ {
  453. if err = parseV6(firstFrag, true, fp); err != nil {
  454. b.Fatal(err)
  455. }
  456. }
  457. })
  458. b.Run("SecondFragment", func(b *testing.B) {
  459. for i := 0; i < b.N; i++ {
  460. if err = parseV6(secondFrag, true, fp); err != nil {
  461. b.Fatal(err)
  462. }
  463. }
  464. })
  465. // Evil packet
  466. evilPacket := &layers.IPv6{
  467. Version: 6,
  468. NextHeader: layers.IPProtocolIPv6HopByHop,
  469. HopLimit: 64,
  470. SrcIP: net.IPv6linklocalallrouters,
  471. DstIP: net.IPv6linklocalallnodes,
  472. }
  473. hopHeader := []byte{
  474. uint8(layers.IPProtocolIPv6HopByHop), // Next Header (HopByHop)
  475. 0x00, // Length
  476. 0x00, 0x00, // Options and padding
  477. 0x00, 0x00, 0x00, 0x00, // More options and padding
  478. }
  479. lastHopHeader := []byte{
  480. uint8(layers.IPProtocolUDP), // Next Header (UDP)
  481. 0x00, // Length
  482. 0x00, 0x00, // Options and padding
  483. 0x00, 0x00, 0x00, 0x00, // More options and padding
  484. }
  485. buffer.Clear()
  486. err = evilPacket.SerializeTo(buffer, opts)
  487. if err != nil {
  488. b.Fatal(err)
  489. }
  490. evilBytes := buffer.Bytes()
  491. for i := 0; i < 200; i++ {
  492. evilBytes = append(evilBytes, hopHeader...)
  493. }
  494. evilBytes = append(evilBytes, lastHopHeader...)
  495. evilBytes = append(evilBytes, udpHeader...)
  496. evilBytes = append(evilBytes, []byte{0xde, 0xad, 0xbe, 0xef}...)
  497. b.Run("200 HopByHop headers", func(b *testing.B) {
  498. for i := 0; i < b.N; i++ {
  499. if err = parseV6(evilBytes, false, fp); err != nil {
  500. b.Fatal(err)
  501. }
  502. }
  503. })
  504. }
  505. // Ensure authentication data is a multiple of 8 bytes by padding if necessary
  506. func padAuthData(authData []byte) []byte {
  507. // Length of Authentication Data must be a multiple of 8 bytes
  508. paddingLength := (8 - (len(authData) % 8)) % 8 // Only pad if necessary
  509. if paddingLength > 0 {
  510. authData = append(authData, make([]byte, paddingLength)...)
  511. }
  512. return authData
  513. }
  514. // Custom function to manually serialize IPSecAH for both IPv4 and IPv6
  515. func serializeAH(ah *layers.IPSecAH) []byte {
  516. buf := new(bytes.Buffer)
  517. // Ensure Authentication Data is a multiple of 8 bytes
  518. ah.AuthenticationData = padAuthData(ah.AuthenticationData)
  519. // Calculate Payload Length (in 32-bit words, minus 2)
  520. payloadLen := uint8((12+len(ah.AuthenticationData))/4) - 2
  521. // Serialize fields
  522. if err := binary.Write(buf, binary.BigEndian, ah.NextHeader); err != nil {
  523. panic(err)
  524. }
  525. if err := binary.Write(buf, binary.BigEndian, payloadLen); err != nil {
  526. panic(err)
  527. }
  528. if err := binary.Write(buf, binary.BigEndian, ah.Reserved); err != nil {
  529. panic(err)
  530. }
  531. if err := binary.Write(buf, binary.BigEndian, ah.SPI); err != nil {
  532. panic(err)
  533. }
  534. if err := binary.Write(buf, binary.BigEndian, ah.Seq); err != nil {
  535. panic(err)
  536. }
  537. if len(ah.AuthenticationData) > 0 {
  538. if err := binary.Write(buf, binary.BigEndian, ah.AuthenticationData); err != nil {
  539. panic(err)
  540. }
  541. }
  542. return buf.Bytes()
  543. }