outside_test.go 16 KB

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