packet_test.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522
  1. package iputil
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "net"
  6. "testing"
  7. "github.com/stretchr/testify/assert"
  8. "golang.org/x/net/ipv4"
  9. "golang.org/x/net/ipv6"
  10. )
  11. func Test_CreateRejectPacket(t *testing.T) {
  12. h := ipv4.Header{
  13. Len: 20,
  14. Src: net.IPv4(10, 0, 0, 1),
  15. Dst: net.IPv4(10, 0, 0, 2),
  16. Protocol: 1, // ICMP
  17. }
  18. b, err := h.Marshal()
  19. if err != nil {
  20. t.Fatalf("h.Marhshal: %v", err)
  21. }
  22. b = append(b, []byte{0, 3, 0, 4}...)
  23. expectedLen := ipv4.HeaderLen + 8 + h.Len + 4
  24. out := make([]byte, expectedLen)
  25. rejectPacket := CreateRejectPacket(b, out)
  26. assert.NotNil(t, rejectPacket)
  27. assert.Len(t, rejectPacket, expectedLen)
  28. // ICMP with max header len
  29. h = ipv4.Header{
  30. Len: 60,
  31. Src: net.IPv4(10, 0, 0, 1),
  32. Dst: net.IPv4(10, 0, 0, 2),
  33. Protocol: 1, // ICMP
  34. Options: make([]byte, 40),
  35. }
  36. b, err = h.Marshal()
  37. if err != nil {
  38. t.Fatalf("h.Marhshal: %v", err)
  39. }
  40. b = append(b, []byte{0, 3, 0, 4, 0, 0, 0, 0}...)
  41. expectedLen = maxIPv4RejectPacketSize
  42. out = make([]byte, MaxRejectPacketSize)
  43. rejectPacket = CreateRejectPacket(b, out)
  44. assert.NotNil(t, rejectPacket)
  45. assert.Len(t, rejectPacket, expectedLen)
  46. // TCP with max header len
  47. h = ipv4.Header{
  48. Len: 60,
  49. Src: net.IPv4(10, 0, 0, 1),
  50. Dst: net.IPv4(10, 0, 0, 2),
  51. Protocol: 6, // TCP
  52. Options: make([]byte, 40),
  53. }
  54. b, err = h.Marshal()
  55. if err != nil {
  56. t.Fatalf("h.Marhshal: %v", err)
  57. }
  58. b = append(b, []byte{0, 3, 0, 4}...)
  59. b = append(b, make([]byte, 16)...)
  60. expectedLen = ipv4.HeaderLen + 20
  61. out = make([]byte, expectedLen)
  62. rejectPacket = CreateRejectPacket(b, out)
  63. assert.NotNil(t, rejectPacket)
  64. assert.Len(t, rejectPacket, expectedLen)
  65. }
  66. func Test_CreateRejectPacket_NoFragment(t *testing.T) {
  67. out := make([]byte, MaxRejectPacketSize)
  68. // IPv4: non-zero fragment offset should not generate reject packet
  69. h := ipv4.Header{
  70. Len: 20,
  71. Src: net.IPv4(10, 0, 0, 1),
  72. Dst: net.IPv4(10, 0, 0, 2),
  73. Protocol: 17, // UDP
  74. }
  75. b, err := h.Marshal()
  76. if err != nil {
  77. t.Fatalf("h.Marshal: %v", err)
  78. }
  79. b = append(b, make([]byte, 8)...)
  80. // Set fragment offset to non-zero (byte 6-7, offset in 8-byte units)
  81. b[6] = 0x00
  82. b[7] = 0x01
  83. assert.Nil(t, CreateRejectPacket(b, out))
  84. // MF flag with zero offset (first fragment) should still generate reject
  85. b[6] = 0x20 // MF flag set
  86. b[7] = 0x00
  87. assert.NotNil(t, CreateRejectPacket(b, out))
  88. // Non-fragment should still generate reject packet
  89. b[6] = 0x00
  90. b[7] = 0x00
  91. assert.NotNil(t, CreateRejectPacket(b, out))
  92. // DF flag only (not a fragment) should still generate reject packet
  93. b[6] = 0x40
  94. b[7] = 0x00
  95. assert.NotNil(t, CreateRejectPacket(b, out))
  96. }
  97. func Test_CreateRejectPacketIPv6_NoFragment(t *testing.T) {
  98. src := net.ParseIP("fd00::1")
  99. dst := net.ParseIP("fd00::2")
  100. out := make([]byte, MaxRejectPacketSize)
  101. // IPv6 with Fragment header and non-zero offset should not generate reject
  102. fragHeader := []byte{
  103. 17, // next header: UDP
  104. 0, // reserved
  105. 0, 9, // fragment offset=1 (shifted left 3), M=1
  106. 0, 0, 0, 1, // identification
  107. }
  108. udpPayload := make([]byte, 8)
  109. payload := append(fragHeader, udpPayload...)
  110. packet := makeIPv6Packet(src, dst, 44, payload) // next header 44 = Fragment
  111. assert.Nil(t, CreateRejectPacket(packet, out))
  112. // Fragment header with zero offset (first fragment) should still generate reject
  113. fragHeader[2] = 0
  114. fragHeader[3] = 1 // offset=0, M=1
  115. payload = append(fragHeader, udpPayload...)
  116. packet = makeIPv6Packet(src, dst, 44, payload)
  117. assert.NotNil(t, CreateRejectPacket(packet, out))
  118. }
  119. func Test_CreateRejectPacket_NoICMPError(t *testing.T) {
  120. out := make([]byte, MaxRejectPacketSize)
  121. // ICMP error types should not generate reject packets
  122. icmpErrorTypes := []byte{3, 4, 5, 11, 12}
  123. for _, icmpType := range icmpErrorTypes {
  124. h := ipv4.Header{
  125. Len: 20,
  126. Src: net.IPv4(10, 0, 0, 1),
  127. Dst: net.IPv4(10, 0, 0, 2),
  128. Protocol: 1, // ICMP
  129. }
  130. b, err := h.Marshal()
  131. if err != nil {
  132. t.Fatalf("h.Marshal: %v", err)
  133. }
  134. b = append(b, icmpType, 0, 0, 0, 0, 0, 0, 0)
  135. rejectPacket := CreateRejectPacket(b, out)
  136. assert.Nil(t, rejectPacket, "ICMP type %d should not generate a reject packet", icmpType)
  137. }
  138. // ICMP non-error types should still generate reject packets
  139. icmpNonErrorTypes := []byte{0, 8, 13, 14}
  140. for _, icmpType := range icmpNonErrorTypes {
  141. h := ipv4.Header{
  142. Len: 20,
  143. Src: net.IPv4(10, 0, 0, 1),
  144. Dst: net.IPv4(10, 0, 0, 2),
  145. Protocol: 1, // ICMP
  146. }
  147. b, err := h.Marshal()
  148. if err != nil {
  149. t.Fatalf("h.Marshal: %v", err)
  150. }
  151. b = append(b, icmpType, 0, 0, 0, 0, 0, 0, 0)
  152. rejectPacket := CreateRejectPacket(b, out)
  153. assert.NotNil(t, rejectPacket, "ICMP type %d should generate a reject packet", icmpType)
  154. }
  155. }
  156. // Test_CreateRejectPacket_RespectsCap guards against H2: with UDP GRO the
  157. // scratch buffer reused to build a reject is a single coalesced segment inside
  158. // a shared recvmmsg row. Its length covers just that segment, but an uncapped
  159. // slice's capacity runs on into the next, not-yet-processed segment. Because
  160. // CreateRejectPacket honors cap, capping the borrowed segment to its own length
  161. // (cap==len) makes it physically impossible for an oversized ICMPv6 reject to
  162. // overwrite the neighbor segment's bytes.
  163. func Test_CreateRejectPacket_RespectsCap(t *testing.T) {
  164. src := net.ParseIP("fd00::1")
  165. dst := net.ParseIP("fd00::2")
  166. // Inner IPv6 UDP packet. An ICMPv6 reject copies the whole inner packet
  167. // plus a 48-byte header (40 IPv6 + 8 ICMPv6), so it needs 48 more bytes
  168. // than the inner packet length.
  169. inner := makeIPv6Packet(src, dst, 17, make([]byte, 20))
  170. // The ciphertext scratch reused as the reject buffer is the received
  171. // datagram: 16-byte Nebula header + inner + 16-byte AEAD tag. That is only
  172. // 32 bytes of slack, so a full ICMPv6 reject overruns it by 16 bytes.
  173. const nebulaOverhead = 32
  174. segLen := len(inner) + nebulaOverhead
  175. // Shared backing row laid out as [segment][neighbor's 16-byte Nebula header].
  176. const neighborHdr = 16
  177. sentinel := bytes.Repeat([]byte{0xAB}, neighborHdr)
  178. // Uncapped: the slice's capacity reaches into the neighbor, reproducing
  179. // the overrun that silently drops the neighbor packet.
  180. backing := make([]byte, segLen+neighborHdr)
  181. copy(backing[segLen:], sentinel)
  182. reject := CreateRejectPacket(inner, backing[:segLen])
  183. assert.NotNil(t, reject, "uncapped buffer reaches into the neighbor, so the reject is built")
  184. assert.NotEqual(t, sentinel, backing[segLen:segLen+neighborHdr],
  185. "without the cap the oversized reject overruns into the neighbor segment")
  186. // Capped (the fix): cap==len, so the builder cannot exceed the segment. The
  187. // reject does not fit, so it is refused rather than corrupting the neighbor.
  188. backing = make([]byte, segLen+neighborHdr)
  189. copy(backing[segLen:], sentinel)
  190. reject = CreateRejectPacket(inner, backing[:segLen:segLen])
  191. assert.Nil(t, reject, "capped segment is 16 bytes too small for a full ICMPv6 reject, so it is refused")
  192. assert.Equal(t, sentinel, backing[segLen:segLen+neighborHdr],
  193. "capped segment must leave the neighbor untouched")
  194. }
  195. func makeIPv6Packet(src, dst net.IP, nextHeader uint8, payload []byte) []byte {
  196. b := make([]byte, ipv6.HeaderLen+len(payload))
  197. b[0] = ipv6.Version << 4
  198. binary.BigEndian.PutUint16(b[4:], uint16(len(payload)))
  199. b[6] = nextHeader
  200. b[7] = 64
  201. copy(b[8:24], src.To16())
  202. copy(b[24:40], dst.To16())
  203. copy(b[ipv6.HeaderLen:], payload)
  204. return b
  205. }
  206. func Test_CreateRejectPacketIPv6_ICMP(t *testing.T) {
  207. src := net.ParseIP("fd00::1")
  208. dst := net.ParseIP("fd00::2")
  209. // Small UDP packet: entire original included in body
  210. udpPayload := make([]byte, 20)
  211. udpPayload[0] = 0x00 // src port high
  212. udpPayload[1] = 0x50 // src port low (80)
  213. udpPayload[2] = 0x01 // dst port high
  214. udpPayload[3] = 0xBB // dst port low (443)
  215. packet := makeIPv6Packet(src, dst, 17, udpPayload)
  216. out := make([]byte, MaxRejectPacketSize)
  217. rejectPacket := CreateRejectPacket(packet, out)
  218. assert.NotNil(t, rejectPacket)
  219. // Small packet fits entirely: 40 (ipv6 hdr) + 8 (icmpv6 hdr) + 60 (original)
  220. expectedLen := ipv6.HeaderLen + 8 + len(packet)
  221. assert.Len(t, rejectPacket, expectedLen)
  222. // Verify version
  223. assert.Equal(t, byte(ipv6.Version<<4), rejectPacket[0]&0xf0)
  224. // Verify next header is ICMPv6 (58)
  225. assert.Equal(t, byte(58), rejectPacket[6])
  226. // Verify src/dst are swapped
  227. assert.Equal(t, dst.To16(), net.IP(rejectPacket[8:24]))
  228. assert.Equal(t, src.To16(), net.IP(rejectPacket[24:40]))
  229. // Verify ICMPv6 type=1 (Dest Unreachable), code=1 (Administratively prohibited)
  230. assert.Equal(t, byte(1), rejectPacket[ipv6.HeaderLen])
  231. assert.Equal(t, byte(1), rejectPacket[ipv6.HeaderLen+1])
  232. // Verify entire original packet is included in body
  233. assert.Equal(t, packet, rejectPacket[ipv6.HeaderLen+8:])
  234. // Large packet: body is truncated to 1000 bytes
  235. largePkt := makeIPv6Packet(src, dst, 17, make([]byte, 1200))
  236. rejectPacket = CreateRejectPacket(largePkt, out)
  237. assert.NotNil(t, rejectPacket)
  238. assert.Len(t, rejectPacket, ipv6.HeaderLen+8+1000)
  239. assert.Equal(t, largePkt[:1000], rejectPacket[ipv6.HeaderLen+8:])
  240. }
  241. func Test_CreateRejectPacketIPv6_TCP(t *testing.T) {
  242. src := net.ParseIP("fd00::1")
  243. dst := net.ParseIP("fd00::2")
  244. // TCP SYN packet (next header 6)
  245. tcpPayload := make([]byte, 20)
  246. tcpPayload[0] = 0x00 // src port high
  247. tcpPayload[1] = 0x50 // src port low (80)
  248. tcpPayload[2] = 0x01 // dst port high
  249. tcpPayload[3] = 0xBB // dst port low (443)
  250. binary.BigEndian.PutUint32(tcpPayload[4:], 1000) // seq
  251. binary.BigEndian.PutUint32(tcpPayload[8:], 0) // ack seq
  252. tcpPayload[12] = (20 >> 2) << 4 // data offset
  253. tcpPayload[13] = 0b00000010 // SYN flag
  254. packet := makeIPv6Packet(src, dst, 6, tcpPayload)
  255. out := make([]byte, MaxRejectPacketSize)
  256. rejectPacket := CreateRejectPacket(packet, out)
  257. assert.NotNil(t, rejectPacket)
  258. // Expected: 40 (ipv6 hdr) + 20 (tcp RST)
  259. expectedLen := ipv6.HeaderLen + 20
  260. assert.Len(t, rejectPacket, expectedLen)
  261. // Verify version
  262. assert.Equal(t, byte(ipv6.Version<<4), rejectPacket[0]&0xf0)
  263. // Verify next header is TCP (6)
  264. assert.Equal(t, byte(6), rejectPacket[6])
  265. // Verify src/dst are swapped
  266. assert.Equal(t, dst.To16(), net.IP(rejectPacket[8:24]))
  267. assert.Equal(t, src.To16(), net.IP(rejectPacket[24:40]))
  268. // Verify ports are swapped
  269. tcpOut := rejectPacket[ipv6.HeaderLen:]
  270. assert.Equal(t, uint16(443), binary.BigEndian.Uint16(tcpOut[0:2]))
  271. assert.Equal(t, uint16(80), binary.BigEndian.Uint16(tcpOut[2:4]))
  272. // RST+ACK flags (since input was SYN without ACK)
  273. assert.Equal(t, byte(0b00010100), tcpOut[13])
  274. // ack_seq = original seq (1000) + SYN (1) + FIN (0) + segment data (0)
  275. assert.Equal(t, uint32(1001), binary.BigEndian.Uint32(tcpOut[8:]))
  276. }
  277. func Test_CreateRejectPacketIPv6_TCPWithACK(t *testing.T) {
  278. src := net.ParseIP("fd00::1")
  279. dst := net.ParseIP("fd00::2")
  280. // TCP packet with ACK set
  281. tcpPayload := make([]byte, 20)
  282. tcpPayload[0] = 0x00
  283. tcpPayload[1] = 0x50
  284. tcpPayload[2] = 0x01
  285. tcpPayload[3] = 0xBB
  286. binary.BigEndian.PutUint32(tcpPayload[4:], 1000) // seq
  287. binary.BigEndian.PutUint32(tcpPayload[8:], 2000) // ack seq
  288. tcpPayload[12] = (20 >> 2) << 4 // data offset
  289. tcpPayload[13] = 0b00010000 // ACK flag
  290. packet := makeIPv6Packet(src, dst, 6, tcpPayload)
  291. out := make([]byte, MaxRejectPacketSize)
  292. rejectPacket := CreateRejectPacket(packet, out)
  293. assert.NotNil(t, rejectPacket)
  294. tcpOut := rejectPacket[ipv6.HeaderLen:]
  295. // RST only (no ACK) since input had ACK
  296. assert.Equal(t, byte(0b00000100), tcpOut[13])
  297. // seq = original ack_seq
  298. assert.Equal(t, uint32(2000), binary.BigEndian.Uint32(tcpOut[4:]))
  299. }
  300. func Test_CreateRejectPacketIPv6_NoICMPError(t *testing.T) {
  301. src := net.ParseIP("fd00::1")
  302. dst := net.ParseIP("fd00::2")
  303. out := make([]byte, MaxRejectPacketSize)
  304. // ICMPv6 error types (1-4) should not generate reject packets
  305. for icmpType := byte(1); icmpType <= 4; icmpType++ {
  306. payload := make([]byte, 8)
  307. payload[0] = icmpType
  308. packet := makeIPv6Packet(src, dst, 58, payload)
  309. rejectPacket := CreateRejectPacket(packet, out)
  310. assert.Nil(t, rejectPacket, "ICMPv6 type %d should not generate a reject packet", icmpType)
  311. }
  312. // ICMPv6 non-error types should still generate reject packets
  313. nonErrorTypes := []byte{128, 129, 133, 134}
  314. for _, icmpType := range nonErrorTypes {
  315. payload := make([]byte, 8)
  316. payload[0] = icmpType
  317. packet := makeIPv6Packet(src, dst, 58, payload)
  318. rejectPacket := CreateRejectPacket(packet, out)
  319. assert.NotNil(t, rejectPacket, "ICMPv6 type %d should generate a reject packet", icmpType)
  320. }
  321. }
  322. func Test_CreateRejectPacketIPv6_TooShort(t *testing.T) {
  323. // Packet too short to be valid IPv6
  324. out := make([]byte, MaxRejectPacketSize)
  325. assert.Nil(t, CreateRejectPacket([]byte{0x60}, out))
  326. assert.Nil(t, CreateRejectPacket(make([]byte, 39), out))
  327. }
  328. func Test_CreateRejectPacketIPv6_ExtensionHeaders(t *testing.T) {
  329. src := net.ParseIP("fd00::1")
  330. dst := net.ParseIP("fd00::2")
  331. // IPv6 + Hop-by-Hop extension header + TCP
  332. hopByHop := []byte{
  333. 6, // next header: TCP
  334. 0, // length (8 bytes total)
  335. 0, 0, // padding
  336. 0, 0, 0, 0,
  337. }
  338. tcpPayload := make([]byte, 20)
  339. tcpPayload[0] = 0x00
  340. tcpPayload[1] = 0x50
  341. tcpPayload[2] = 0x01
  342. tcpPayload[3] = 0xBB
  343. binary.BigEndian.PutUint32(tcpPayload[4:], 1000)
  344. binary.BigEndian.PutUint32(tcpPayload[8:], 2000)
  345. tcpPayload[12] = (20 >> 2) << 4
  346. tcpPayload[13] = 0b00010000 // ACK
  347. payload := append(hopByHop, tcpPayload...)
  348. packet := makeIPv6Packet(src, dst, 0, payload) // next header 0 = Hop-by-Hop
  349. out := make([]byte, MaxRejectPacketSize)
  350. rejectPacket := CreateRejectPacket(packet, out)
  351. assert.NotNil(t, rejectPacket)
  352. // Should produce TCP RST
  353. expectedLen := ipv6.HeaderLen + 20
  354. assert.Len(t, rejectPacket, expectedLen)
  355. assert.Equal(t, byte(6), rejectPacket[6]) // next header is TCP
  356. tcpOut := rejectPacket[ipv6.HeaderLen:]
  357. assert.Equal(t, byte(0b00000100), tcpOut[13]) // RST only
  358. }
  359. func TestCreateICMPEchoResponse_IPv4(t *testing.T) {
  360. // Build a simple IPv4 ICMP Echo Request
  361. packet := make([]byte, 28)
  362. packet[0] = 0x45 // version 4, IHL 5
  363. binary.BigEndian.PutUint16(packet[2:], uint16(28)) // total length
  364. packet[8] = 64 // TTL
  365. packet[9] = 1 // protocol ICMP
  366. copy(packet[12:16], net.IPv4(10, 0, 0, 1).To4()) // src
  367. copy(packet[16:20], net.IPv4(10, 0, 0, 2).To4()) // dst
  368. packet[20] = 8 // ICMP Echo Request
  369. out := make([]byte, len(packet))
  370. result := CreateICMPEchoResponse(packet, out)
  371. assert.NotNil(t, result)
  372. assert.Equal(t, byte(0x45), result[0])
  373. // src/dst swapped
  374. assert.Equal(t, net.IPv4(10, 0, 0, 2).To4(), net.IP(result[12:16]))
  375. assert.Equal(t, net.IPv4(10, 0, 0, 1).To4(), net.IP(result[16:20]))
  376. // ICMP Echo Reply
  377. assert.Equal(t, byte(0), result[20])
  378. }
  379. func TestCreateICMPEchoResponse_IPv6(t *testing.T) {
  380. src := net.ParseIP("fd00::1").To16()
  381. dst := net.ParseIP("fd00::2").To16()
  382. // Build an IPv6 ICMPv6 Echo Request packet
  383. // IPv6 header (40 bytes) + ICMPv6 (8 bytes)
  384. packet := make([]byte, 48)
  385. packet[0] = 0x60 // version 6
  386. payloadLen := uint16(8) // ICMPv6 header only
  387. binary.BigEndian.PutUint16(packet[4:], payloadLen)
  388. packet[6] = 58 // Next Header: ICMPv6
  389. packet[7] = 64 // Hop Limit
  390. copy(packet[8:24], src) // src address
  391. copy(packet[24:40], dst) // dst address
  392. // ICMPv6 Echo Request
  393. icmp := packet[40:]
  394. icmp[0] = 128 // type: Echo Request
  395. icmp[1] = 0 // code
  396. binary.BigEndian.PutUint16(icmp[4:], 1) // identifier
  397. binary.BigEndian.PutUint16(icmp[6:], 1) // sequence number
  398. // Compute correct checksum for the request
  399. csum := ipv6PseudoheaderChecksum(src, dst, 58, uint32(payloadLen))
  400. binary.BigEndian.PutUint16(icmp[2:], tcpipChecksum(icmp, csum))
  401. out := make([]byte, len(packet))
  402. result := CreateICMPEchoResponse(packet, out)
  403. assert.NotNil(t, result)
  404. // Version should still be 6
  405. assert.Equal(t, byte(6), result[0]>>4)
  406. // src/dst swapped
  407. assert.Equal(t, dst, net.IP(result[8:24]))
  408. assert.Equal(t, src, net.IP(result[24:40]))
  409. // ICMPv6 Echo Reply type
  410. assert.Equal(t, byte(129), result[40])
  411. // Verify checksum is valid (tcpipChecksum returns 0 when data+checksum is correct)
  412. respIcmp := result[40:]
  413. verifyCsum := ipv6PseudoheaderChecksum(result[8:24], result[24:40], 58, uint32(payloadLen))
  414. assert.Equal(t, uint16(0), tcpipChecksum(respIcmp, verifyCsum))
  415. }
  416. func TestCreateICMPEchoResponse_IPv6_NotEchoRequest(t *testing.T) {
  417. src := net.ParseIP("fd00::1").To16()
  418. dst := net.ParseIP("fd00::2").To16()
  419. packet := make([]byte, 48)
  420. packet[0] = 0x60
  421. binary.BigEndian.PutUint16(packet[4:], 8)
  422. packet[6] = 58
  423. packet[7] = 64
  424. copy(packet[8:24], src)
  425. copy(packet[24:40], dst)
  426. // ICMPv6 type 1 (Destination Unreachable) - not Echo Request
  427. packet[40] = 1
  428. out := make([]byte, len(packet))
  429. result := CreateICMPEchoResponse(packet, out)
  430. assert.Nil(t, result)
  431. }
  432. func TestCreateICMPEchoResponse_IPv6_NotICMPv6(t *testing.T) {
  433. src := net.ParseIP("fd00::1").To16()
  434. dst := net.ParseIP("fd00::2").To16()
  435. packet := make([]byte, 48)
  436. packet[0] = 0x60
  437. binary.BigEndian.PutUint16(packet[4:], 8)
  438. packet[6] = 6 // TCP, not ICMPv6
  439. packet[7] = 64
  440. copy(packet[8:24], src)
  441. copy(packet[24:40], dst)
  442. out := make([]byte, len(packet))
  443. result := CreateICMPEchoResponse(packet, out)
  444. assert.Nil(t, result)
  445. }