outside_test.go 18 KB

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