outside_test.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642
  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. err = nil
  133. // A good ICMP packet
  134. ip = layers.IPv6{
  135. Version: 6,
  136. NextHeader: layers.IPProtocolICMPv6,
  137. HopLimit: 128,
  138. SrcIP: net.IPv6linklocalallrouters,
  139. DstIP: net.IPv6linklocalallnodes,
  140. }
  141. icmp := layers.ICMPv6{
  142. TypeCode: layers.ICMPv6TypeEchoRequest,
  143. Checksum: 0x1234,
  144. }
  145. buffer.Clear()
  146. require.NoError(t, gopacket.SerializeLayers(buffer, opt, &ip, &icmp))
  147. require.Error(t, newPacket(buffer.Bytes(), true, p))
  148. buffer.Clear()
  149. echo := layers.ICMPv6Echo{
  150. Identifier: 0xabcd,
  151. SeqNumber: 1234,
  152. }
  153. require.NoError(t, gopacket.SerializeLayers(buffer, opt, &ip, &icmp, &echo))
  154. require.NoError(t, newPacket(buffer.Bytes(), true, p))
  155. assert.Equal(t, uint8(layers.IPProtocolICMPv6), p.Protocol)
  156. assert.Equal(t, netip.MustParseAddr("ff02::2"), p.RemoteAddr)
  157. assert.Equal(t, netip.MustParseAddr("ff02::1"), p.LocalAddr)
  158. assert.Equal(t, uint16(0xabcd), p.RemotePort)
  159. assert.Equal(t, uint16(0), p.LocalPort)
  160. assert.False(t, p.Fragment)
  161. // A good ESP packet
  162. b := buffer.Bytes()
  163. b[6] = byte(layers.IPProtocolESP)
  164. err = newPacket(b, true, p)
  165. require.NoError(t, err)
  166. assert.Equal(t, uint8(layers.IPProtocolESP), p.Protocol)
  167. assert.Equal(t, netip.MustParseAddr("ff02::2"), p.RemoteAddr)
  168. assert.Equal(t, netip.MustParseAddr("ff02::1"), p.LocalAddr)
  169. assert.Equal(t, uint16(0), p.RemotePort)
  170. assert.Equal(t, uint16(0), p.LocalPort)
  171. assert.False(t, p.Fragment)
  172. // A good None packet
  173. b = buffer.Bytes()
  174. b[6] = byte(layers.IPProtocolNoNextHeader)
  175. err = newPacket(b, true, p)
  176. require.NoError(t, err)
  177. assert.Equal(t, uint8(layers.IPProtocolNoNextHeader), p.Protocol)
  178. assert.Equal(t, netip.MustParseAddr("ff02::2"), p.RemoteAddr)
  179. assert.Equal(t, netip.MustParseAddr("ff02::1"), p.LocalAddr)
  180. assert.Equal(t, uint16(0), p.RemotePort)
  181. assert.Equal(t, uint16(0), p.LocalPort)
  182. assert.False(t, p.Fragment)
  183. // An unknown protocol packet
  184. b = buffer.Bytes()
  185. b[6] = 255 // 255 is a reserved protocol number
  186. err = newPacket(b, true, p)
  187. require.ErrorIs(t, err, ErrIPv6CouldNotFindPayload)
  188. // A good UDP packet
  189. ip = layers.IPv6{
  190. Version: 6,
  191. NextHeader: firewall.ProtoUDP,
  192. HopLimit: 128,
  193. SrcIP: net.IPv6linklocalallrouters,
  194. DstIP: net.IPv6linklocalallnodes,
  195. }
  196. udp := layers.UDP{
  197. SrcPort: layers.UDPPort(36123),
  198. DstPort: layers.UDPPort(22),
  199. }
  200. err = udp.SetNetworkLayerForChecksum(&ip)
  201. require.NoError(t, err)
  202. buffer.Clear()
  203. err = gopacket.SerializeLayers(buffer, opt, &ip, &udp, gopacket.Payload([]byte{0xde, 0xad, 0xbe, 0xef}))
  204. if err != nil {
  205. panic(err)
  206. }
  207. b = buffer.Bytes()
  208. // incoming
  209. err = newPacket(b, true, p)
  210. require.NoError(t, err)
  211. assert.Equal(t, uint8(firewall.ProtoUDP), p.Protocol)
  212. assert.Equal(t, netip.MustParseAddr("ff02::2"), p.RemoteAddr)
  213. assert.Equal(t, netip.MustParseAddr("ff02::1"), p.LocalAddr)
  214. assert.Equal(t, uint16(36123), p.RemotePort)
  215. assert.Equal(t, uint16(22), p.LocalPort)
  216. assert.False(t, p.Fragment)
  217. // outgoing
  218. err = newPacket(b, false, p)
  219. require.NoError(t, err)
  220. assert.Equal(t, uint8(firewall.ProtoUDP), p.Protocol)
  221. assert.Equal(t, netip.MustParseAddr("ff02::2"), p.LocalAddr)
  222. assert.Equal(t, netip.MustParseAddr("ff02::1"), p.RemoteAddr)
  223. assert.Equal(t, uint16(36123), p.LocalPort)
  224. assert.Equal(t, uint16(22), p.RemotePort)
  225. assert.False(t, p.Fragment)
  226. // Too short UDP packet
  227. err = newPacket(b[:len(b)-10], false, p) // pull off the last 10 bytes
  228. require.ErrorIs(t, err, ErrIPv6PacketTooShort)
  229. // A good TCP packet
  230. b[6] = byte(layers.IPProtocolTCP)
  231. // incoming
  232. err = newPacket(b, true, p)
  233. require.NoError(t, err)
  234. assert.Equal(t, uint8(firewall.ProtoTCP), p.Protocol)
  235. assert.Equal(t, netip.MustParseAddr("ff02::2"), p.RemoteAddr)
  236. assert.Equal(t, netip.MustParseAddr("ff02::1"), p.LocalAddr)
  237. assert.Equal(t, uint16(36123), p.RemotePort)
  238. assert.Equal(t, uint16(22), p.LocalPort)
  239. assert.False(t, p.Fragment)
  240. // outgoing
  241. err = newPacket(b, false, p)
  242. require.NoError(t, err)
  243. assert.Equal(t, uint8(firewall.ProtoTCP), p.Protocol)
  244. assert.Equal(t, netip.MustParseAddr("ff02::2"), p.LocalAddr)
  245. assert.Equal(t, netip.MustParseAddr("ff02::1"), p.RemoteAddr)
  246. assert.Equal(t, uint16(36123), p.LocalPort)
  247. assert.Equal(t, uint16(22), p.RemotePort)
  248. assert.False(t, p.Fragment)
  249. // Too short TCP packet
  250. err = newPacket(b[:len(b)-10], false, p) // pull off the last 10 bytes
  251. require.ErrorIs(t, err, ErrIPv6PacketTooShort)
  252. // A good UDP packet with an AH header
  253. ip = layers.IPv6{
  254. Version: 6,
  255. NextHeader: layers.IPProtocolAH,
  256. HopLimit: 128,
  257. SrcIP: net.IPv6linklocalallrouters,
  258. DstIP: net.IPv6linklocalallnodes,
  259. }
  260. ah := layers.IPSecAH{
  261. AuthenticationData: []byte{0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef},
  262. }
  263. ah.NextHeader = layers.IPProtocolUDP
  264. udpHeader := []byte{
  265. 0x8d, 0x1b, // Source port 36123
  266. 0x00, 0x16, // Destination port 22
  267. 0x00, 0x00, // Length
  268. 0x00, 0x00, // Checksum
  269. }
  270. buffer.Clear()
  271. err = ip.SerializeTo(buffer, opt)
  272. if err != nil {
  273. panic(err)
  274. }
  275. b = buffer.Bytes()
  276. ahb := serializeAH(&ah)
  277. b = append(b, ahb...)
  278. b = append(b, udpHeader...)
  279. err = newPacket(b, true, p)
  280. require.NoError(t, err)
  281. assert.Equal(t, uint8(firewall.ProtoUDP), p.Protocol)
  282. assert.Equal(t, netip.MustParseAddr("ff02::2"), p.RemoteAddr)
  283. assert.Equal(t, netip.MustParseAddr("ff02::1"), p.LocalAddr)
  284. assert.Equal(t, uint16(36123), p.RemotePort)
  285. assert.Equal(t, uint16(22), p.LocalPort)
  286. assert.False(t, p.Fragment)
  287. // Ensure buffer bounds checking during processing
  288. err = newPacket(b[:41], true, p)
  289. require.ErrorIs(t, err, ErrIPv6PacketTooShort)
  290. // Invalid AH header
  291. b = buffer.Bytes()
  292. err = newPacket(b, true, p)
  293. require.ErrorIs(t, err, ErrIPv6CouldNotFindPayload)
  294. }
  295. func Test_newPacket_ipv6Fragment(t *testing.T) {
  296. p := &firewall.Packet{}
  297. ip := &layers.IPv6{
  298. Version: 6,
  299. NextHeader: layers.IPProtocolIPv6Fragment,
  300. HopLimit: 64,
  301. SrcIP: net.IPv6linklocalallrouters,
  302. DstIP: net.IPv6linklocalallnodes,
  303. }
  304. // First fragment
  305. fragHeader1 := []byte{
  306. uint8(layers.IPProtocolUDP), // Next Header (UDP)
  307. 0x00, // Reserved
  308. 0x00, // Fragment Offset high byte (0)
  309. 0x01, // Fragment Offset low byte & flags (M=1)
  310. 0x00, 0x00, 0x00, 0x01, // Identification
  311. }
  312. udpHeader := []byte{
  313. 0x8d, 0x1b, // Source port 36123
  314. 0x00, 0x16, // Destination port 22
  315. 0x00, 0x00, // Length
  316. 0x00, 0x00, // Checksum
  317. }
  318. buffer := gopacket.NewSerializeBuffer()
  319. opts := gopacket.SerializeOptions{
  320. ComputeChecksums: true,
  321. FixLengths: true,
  322. }
  323. err := ip.SerializeTo(buffer, opts)
  324. if err != nil {
  325. t.Fatal(err)
  326. }
  327. firstFrag := buffer.Bytes()
  328. firstFrag = append(firstFrag, fragHeader1...)
  329. firstFrag = append(firstFrag, udpHeader...)
  330. firstFrag = append(firstFrag, []byte{0xde, 0xad, 0xbe, 0xef}...)
  331. // Test first fragment incoming
  332. err = newPacket(firstFrag, true, p)
  333. require.NoError(t, err)
  334. assert.Equal(t, netip.MustParseAddr("ff02::2"), p.RemoteAddr)
  335. assert.Equal(t, netip.MustParseAddr("ff02::1"), p.LocalAddr)
  336. assert.Equal(t, uint8(layers.IPProtocolUDP), p.Protocol)
  337. assert.Equal(t, uint16(36123), p.RemotePort)
  338. assert.Equal(t, uint16(22), p.LocalPort)
  339. assert.False(t, p.Fragment)
  340. // Test first fragment outgoing
  341. err = newPacket(firstFrag, false, p)
  342. require.NoError(t, err)
  343. assert.Equal(t, netip.MustParseAddr("ff02::2"), p.LocalAddr)
  344. assert.Equal(t, netip.MustParseAddr("ff02::1"), p.RemoteAddr)
  345. assert.Equal(t, uint8(layers.IPProtocolUDP), p.Protocol)
  346. assert.Equal(t, uint16(36123), p.LocalPort)
  347. assert.Equal(t, uint16(22), p.RemotePort)
  348. assert.False(t, p.Fragment)
  349. // Second fragment
  350. fragHeader2 := []byte{
  351. uint8(layers.IPProtocolUDP), // Next Header (UDP)
  352. 0x00, // Reserved
  353. 0xb9, // Fragment Offset high byte (185)
  354. 0x01, // Fragment Offset low byte & flags (M=1)
  355. 0x00, 0x00, 0x00, 0x01, // Identification
  356. }
  357. buffer.Clear()
  358. err = ip.SerializeTo(buffer, opts)
  359. if err != nil {
  360. t.Fatal(err)
  361. }
  362. secondFrag := buffer.Bytes()
  363. secondFrag = append(secondFrag, fragHeader2...)
  364. secondFrag = append(secondFrag, []byte{0xde, 0xad, 0xbe, 0xef}...)
  365. // Test second fragment incoming
  366. err = newPacket(secondFrag, true, p)
  367. require.NoError(t, err)
  368. assert.Equal(t, netip.MustParseAddr("ff02::2"), p.RemoteAddr)
  369. assert.Equal(t, netip.MustParseAddr("ff02::1"), p.LocalAddr)
  370. assert.Equal(t, uint8(layers.IPProtocolUDP), p.Protocol)
  371. assert.Equal(t, uint16(0), p.RemotePort)
  372. assert.Equal(t, uint16(0), p.LocalPort)
  373. assert.True(t, p.Fragment)
  374. // Test second fragment outgoing
  375. err = newPacket(secondFrag, false, p)
  376. require.NoError(t, err)
  377. assert.Equal(t, netip.MustParseAddr("ff02::2"), p.LocalAddr)
  378. assert.Equal(t, netip.MustParseAddr("ff02::1"), p.RemoteAddr)
  379. assert.Equal(t, uint8(layers.IPProtocolUDP), p.Protocol)
  380. assert.Equal(t, uint16(0), p.LocalPort)
  381. assert.Equal(t, uint16(0), p.RemotePort)
  382. assert.True(t, p.Fragment)
  383. // Too short of a fragment packet
  384. err = newPacket(secondFrag[:len(secondFrag)-10], false, p)
  385. require.ErrorIs(t, err, ErrIPv6PacketTooShort)
  386. }
  387. func BenchmarkParseV6(b *testing.B) {
  388. // Regular UDP packet
  389. ip := &layers.IPv6{
  390. Version: 6,
  391. NextHeader: layers.IPProtocolUDP,
  392. HopLimit: 64,
  393. SrcIP: net.IPv6linklocalallrouters,
  394. DstIP: net.IPv6linklocalallnodes,
  395. }
  396. udp := &layers.UDP{
  397. SrcPort: layers.UDPPort(36123),
  398. DstPort: layers.UDPPort(22),
  399. }
  400. buffer := gopacket.NewSerializeBuffer()
  401. opts := gopacket.SerializeOptions{
  402. ComputeChecksums: false,
  403. FixLengths: true,
  404. }
  405. err := gopacket.SerializeLayers(buffer, opts, ip, udp)
  406. if err != nil {
  407. b.Fatal(err)
  408. }
  409. normalPacket := buffer.Bytes()
  410. // First Fragment packet
  411. ipFrag := &layers.IPv6{
  412. Version: 6,
  413. NextHeader: layers.IPProtocolIPv6Fragment,
  414. HopLimit: 64,
  415. SrcIP: net.IPv6linklocalallrouters,
  416. DstIP: net.IPv6linklocalallnodes,
  417. }
  418. fragHeader := []byte{
  419. uint8(layers.IPProtocolUDP), // Next Header (UDP)
  420. 0x00, // Reserved
  421. 0x00, // Fragment Offset high byte (0)
  422. 0x01, // Fragment Offset low byte & flags (M=1)
  423. 0x00, 0x00, 0x00, 0x01, // Identification
  424. }
  425. udpHeader := []byte{
  426. 0x8d, 0x7b, // Source port 36123
  427. 0x00, 0x16, // Destination port 22
  428. 0x00, 0x00, // Length
  429. 0x00, 0x00, // Checksum
  430. }
  431. buffer.Clear()
  432. err = ipFrag.SerializeTo(buffer, opts)
  433. if err != nil {
  434. b.Fatal(err)
  435. }
  436. firstFrag := buffer.Bytes()
  437. firstFrag = append(firstFrag, fragHeader...)
  438. firstFrag = append(firstFrag, udpHeader...)
  439. firstFrag = append(firstFrag, []byte{0xde, 0xad, 0xbe, 0xef}...)
  440. // Second Fragment packet
  441. fragHeader[2] = 0xb9 // offset 185
  442. buffer.Clear()
  443. err = ipFrag.SerializeTo(buffer, opts)
  444. if err != nil {
  445. b.Fatal(err)
  446. }
  447. secondFrag := buffer.Bytes()
  448. secondFrag = append(secondFrag, fragHeader...)
  449. secondFrag = append(secondFrag, []byte{0xde, 0xad, 0xbe, 0xef}...)
  450. fp := &firewall.Packet{}
  451. b.Run("Normal", func(b *testing.B) {
  452. for i := 0; i < b.N; i++ {
  453. if err = parseV6(normalPacket, true, fp); err != nil {
  454. b.Fatal(err)
  455. }
  456. }
  457. })
  458. b.Run("FirstFragment", func(b *testing.B) {
  459. for i := 0; i < b.N; i++ {
  460. if err = parseV6(firstFrag, true, fp); err != nil {
  461. b.Fatal(err)
  462. }
  463. }
  464. })
  465. b.Run("SecondFragment", func(b *testing.B) {
  466. for i := 0; i < b.N; i++ {
  467. if err = parseV6(secondFrag, true, fp); err != nil {
  468. b.Fatal(err)
  469. }
  470. }
  471. })
  472. // Evil packet
  473. evilPacket := &layers.IPv6{
  474. Version: 6,
  475. NextHeader: layers.IPProtocolIPv6HopByHop,
  476. HopLimit: 64,
  477. SrcIP: net.IPv6linklocalallrouters,
  478. DstIP: net.IPv6linklocalallnodes,
  479. }
  480. hopHeader := []byte{
  481. uint8(layers.IPProtocolIPv6HopByHop), // Next Header (HopByHop)
  482. 0x00, // Length
  483. 0x00, 0x00, // Options and padding
  484. 0x00, 0x00, 0x00, 0x00, // More options and padding
  485. }
  486. lastHopHeader := []byte{
  487. uint8(layers.IPProtocolUDP), // Next Header (UDP)
  488. 0x00, // Length
  489. 0x00, 0x00, // Options and padding
  490. 0x00, 0x00, 0x00, 0x00, // More options and padding
  491. }
  492. buffer.Clear()
  493. err = evilPacket.SerializeTo(buffer, opts)
  494. if err != nil {
  495. b.Fatal(err)
  496. }
  497. evilBytes := buffer.Bytes()
  498. for range 200 {
  499. evilBytes = append(evilBytes, hopHeader...)
  500. }
  501. evilBytes = append(evilBytes, lastHopHeader...)
  502. evilBytes = append(evilBytes, udpHeader...)
  503. evilBytes = append(evilBytes, []byte{0xde, 0xad, 0xbe, 0xef}...)
  504. b.Run("200 HopByHop headers", func(b *testing.B) {
  505. for i := 0; i < b.N; i++ {
  506. if err = parseV6(evilBytes, false, fp); err != nil {
  507. b.Fatal(err)
  508. }
  509. }
  510. })
  511. }
  512. // Ensure authentication data is a multiple of 8 bytes by padding if necessary
  513. func padAuthData(authData []byte) []byte {
  514. // Length of Authentication Data must be a multiple of 8 bytes
  515. paddingLength := (8 - (len(authData) % 8)) % 8 // Only pad if necessary
  516. if paddingLength > 0 {
  517. authData = append(authData, make([]byte, paddingLength)...)
  518. }
  519. return authData
  520. }
  521. // Custom function to manually serialize IPSecAH for both IPv4 and IPv6
  522. func serializeAH(ah *layers.IPSecAH) []byte {
  523. buf := new(bytes.Buffer)
  524. // Ensure Authentication Data is a multiple of 8 bytes
  525. ah.AuthenticationData = padAuthData(ah.AuthenticationData)
  526. // Calculate Payload Length (in 32-bit words, minus 2)
  527. payloadLen := uint8((12+len(ah.AuthenticationData))/4) - 2
  528. // Serialize fields
  529. if err := binary.Write(buf, binary.BigEndian, ah.NextHeader); err != nil {
  530. panic(err)
  531. }
  532. if err := binary.Write(buf, binary.BigEndian, payloadLen); err != nil {
  533. panic(err)
  534. }
  535. if err := binary.Write(buf, binary.BigEndian, ah.Reserved); err != nil {
  536. panic(err)
  537. }
  538. if err := binary.Write(buf, binary.BigEndian, ah.SPI); err != nil {
  539. panic(err)
  540. }
  541. if err := binary.Write(buf, binary.BigEndian, ah.Seq); err != nil {
  542. panic(err)
  543. }
  544. if len(ah.AuthenticationData) > 0 {
  545. if err := binary.Write(buf, binary.BigEndian, ah.AuthenticationData); err != nil {
  546. panic(err)
  547. }
  548. }
  549. return buf.Bytes()
  550. }