You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

568 lines
14 KiB

  1. // Copyright 2015 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package icmp_test
  5. import (
  6. "errors"
  7. "fmt"
  8. "net"
  9. "reflect"
  10. "testing"
  11. "golang.org/x/net/icmp"
  12. "golang.org/x/net/internal/iana"
  13. "golang.org/x/net/ipv4"
  14. "golang.org/x/net/ipv6"
  15. )
  16. func TestMarshalAndParseMultipartMessage(t *testing.T) {
  17. fn := func(t *testing.T, proto int, tm icmp.Message) error {
  18. b, err := tm.Marshal(nil)
  19. if err != nil {
  20. return err
  21. }
  22. switch tm.Type {
  23. case ipv4.ICMPTypeExtendedEchoRequest, ipv6.ICMPTypeExtendedEchoRequest:
  24. default:
  25. switch proto {
  26. case iana.ProtocolICMP:
  27. if b[5] != 32 {
  28. return fmt.Errorf("got %d; want 32", b[5])
  29. }
  30. case iana.ProtocolIPv6ICMP:
  31. if b[4] != 16 {
  32. return fmt.Errorf("got %d; want 16", b[4])
  33. }
  34. default:
  35. return fmt.Errorf("unknown protocol: %d", proto)
  36. }
  37. }
  38. m, err := icmp.ParseMessage(proto, b)
  39. if err != nil {
  40. return err
  41. }
  42. if m.Type != tm.Type || m.Code != tm.Code {
  43. return fmt.Errorf("got %v; want %v", m, &tm)
  44. }
  45. switch m.Type {
  46. case ipv4.ICMPTypeExtendedEchoRequest, ipv6.ICMPTypeExtendedEchoRequest:
  47. got, want := m.Body.(*icmp.ExtendedEchoRequest), tm.Body.(*icmp.ExtendedEchoRequest)
  48. if !reflect.DeepEqual(got.Extensions, want.Extensions) {
  49. return errors.New(dumpExtensions(got.Extensions, want.Extensions))
  50. }
  51. case ipv4.ICMPTypeDestinationUnreachable:
  52. got, want := m.Body.(*icmp.DstUnreach), tm.Body.(*icmp.DstUnreach)
  53. if !reflect.DeepEqual(got.Extensions, want.Extensions) {
  54. return errors.New(dumpExtensions(got.Extensions, want.Extensions))
  55. }
  56. if len(got.Data) != 128 {
  57. return fmt.Errorf("got %d; want 128", len(got.Data))
  58. }
  59. case ipv4.ICMPTypeTimeExceeded:
  60. got, want := m.Body.(*icmp.TimeExceeded), tm.Body.(*icmp.TimeExceeded)
  61. if !reflect.DeepEqual(got.Extensions, want.Extensions) {
  62. return errors.New(dumpExtensions(got.Extensions, want.Extensions))
  63. }
  64. if len(got.Data) != 128 {
  65. return fmt.Errorf("got %d; want 128", len(got.Data))
  66. }
  67. case ipv4.ICMPTypeParameterProblem:
  68. got, want := m.Body.(*icmp.ParamProb), tm.Body.(*icmp.ParamProb)
  69. if !reflect.DeepEqual(got.Extensions, want.Extensions) {
  70. return errors.New(dumpExtensions(got.Extensions, want.Extensions))
  71. }
  72. if len(got.Data) != 128 {
  73. return fmt.Errorf("got %d; want 128", len(got.Data))
  74. }
  75. case ipv6.ICMPTypeDestinationUnreachable:
  76. got, want := m.Body.(*icmp.DstUnreach), tm.Body.(*icmp.DstUnreach)
  77. if !reflect.DeepEqual(got.Extensions, want.Extensions) {
  78. return errors.New(dumpExtensions(got.Extensions, want.Extensions))
  79. }
  80. if len(got.Data) != 128 {
  81. return fmt.Errorf("got %d; want 128", len(got.Data))
  82. }
  83. case ipv6.ICMPTypeTimeExceeded:
  84. got, want := m.Body.(*icmp.TimeExceeded), tm.Body.(*icmp.TimeExceeded)
  85. if !reflect.DeepEqual(got.Extensions, want.Extensions) {
  86. return errors.New(dumpExtensions(got.Extensions, want.Extensions))
  87. }
  88. if len(got.Data) != 128 {
  89. return fmt.Errorf("got %d; want 128", len(got.Data))
  90. }
  91. default:
  92. return fmt.Errorf("unknown message type: %v", m.Type)
  93. }
  94. return nil
  95. }
  96. t.Run("IPv4", func(t *testing.T) {
  97. for i, tm := range []icmp.Message{
  98. {
  99. Type: ipv4.ICMPTypeDestinationUnreachable, Code: 15,
  100. Body: &icmp.DstUnreach{
  101. Data: []byte("ERROR-INVOKING-PACKET"),
  102. Extensions: []icmp.Extension{
  103. &icmp.MPLSLabelStack{
  104. Class: 1,
  105. Type: 1,
  106. Labels: []icmp.MPLSLabel{
  107. {
  108. Label: 16014,
  109. TC: 0x4,
  110. S: true,
  111. TTL: 255,
  112. },
  113. },
  114. },
  115. &icmp.InterfaceInfo{
  116. Class: 2,
  117. Type: 0x0f,
  118. Interface: &net.Interface{
  119. Index: 15,
  120. Name: "en101",
  121. MTU: 8192,
  122. },
  123. Addr: &net.IPAddr{
  124. IP: net.IPv4(192, 168, 0, 1).To4(),
  125. },
  126. },
  127. },
  128. },
  129. },
  130. {
  131. Type: ipv4.ICMPTypeTimeExceeded, Code: 1,
  132. Body: &icmp.TimeExceeded{
  133. Data: []byte("ERROR-INVOKING-PACKET"),
  134. Extensions: []icmp.Extension{
  135. &icmp.InterfaceInfo{
  136. Class: 2,
  137. Type: 0x0f,
  138. Interface: &net.Interface{
  139. Index: 15,
  140. Name: "en101",
  141. MTU: 8192,
  142. },
  143. Addr: &net.IPAddr{
  144. IP: net.IPv4(192, 168, 0, 1).To4(),
  145. },
  146. },
  147. &icmp.MPLSLabelStack{
  148. Class: 1,
  149. Type: 1,
  150. Labels: []icmp.MPLSLabel{
  151. {
  152. Label: 16014,
  153. TC: 0x4,
  154. S: true,
  155. TTL: 255,
  156. },
  157. },
  158. },
  159. },
  160. },
  161. },
  162. {
  163. Type: ipv4.ICMPTypeParameterProblem, Code: 2,
  164. Body: &icmp.ParamProb{
  165. Pointer: 8,
  166. Data: []byte("ERROR-INVOKING-PACKET"),
  167. Extensions: []icmp.Extension{
  168. &icmp.MPLSLabelStack{
  169. Class: 1,
  170. Type: 1,
  171. Labels: []icmp.MPLSLabel{
  172. {
  173. Label: 16014,
  174. TC: 0x4,
  175. S: true,
  176. TTL: 255,
  177. },
  178. },
  179. },
  180. &icmp.InterfaceInfo{
  181. Class: 2,
  182. Type: 0x0f,
  183. Interface: &net.Interface{
  184. Index: 15,
  185. Name: "en101",
  186. MTU: 8192,
  187. },
  188. Addr: &net.IPAddr{
  189. IP: net.IPv4(192, 168, 0, 1).To4(),
  190. },
  191. },
  192. &icmp.InterfaceInfo{
  193. Class: 2,
  194. Type: 0x2f,
  195. Interface: &net.Interface{
  196. Index: 16,
  197. Name: "en102",
  198. MTU: 8192,
  199. },
  200. Addr: &net.IPAddr{
  201. IP: net.IPv4(192, 168, 0, 2).To4(),
  202. },
  203. },
  204. },
  205. },
  206. },
  207. {
  208. Type: ipv4.ICMPTypeExtendedEchoRequest, Code: 0,
  209. Body: &icmp.ExtendedEchoRequest{
  210. ID: 1, Seq: 2, Local: true,
  211. Extensions: []icmp.Extension{
  212. &icmp.InterfaceIdent{
  213. Class: 3,
  214. Type: 1,
  215. Name: "en101",
  216. },
  217. },
  218. },
  219. },
  220. {
  221. Type: ipv4.ICMPTypeExtendedEchoRequest, Code: 0,
  222. Body: &icmp.ExtendedEchoRequest{
  223. ID: 1, Seq: 2, Local: true,
  224. Extensions: []icmp.Extension{
  225. &icmp.InterfaceIdent{
  226. Class: 3,
  227. Type: 2,
  228. Index: 911,
  229. },
  230. },
  231. },
  232. },
  233. {
  234. Type: ipv4.ICMPTypeExtendedEchoRequest, Code: 0,
  235. Body: &icmp.ExtendedEchoRequest{
  236. ID: 1, Seq: 2,
  237. Extensions: []icmp.Extension{
  238. &icmp.InterfaceIdent{
  239. Class: 3,
  240. Type: 3,
  241. AFI: iana.AddrFamily48bitMAC,
  242. Addr: []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab},
  243. },
  244. },
  245. },
  246. },
  247. } {
  248. if err := fn(t, iana.ProtocolICMP, tm); err != nil {
  249. t.Errorf("#%d: %v", i, err)
  250. }
  251. }
  252. })
  253. t.Run("IPv6", func(t *testing.T) {
  254. for i, tm := range []icmp.Message{
  255. {
  256. Type: ipv6.ICMPTypeDestinationUnreachable, Code: 6,
  257. Body: &icmp.DstUnreach{
  258. Data: []byte("ERROR-INVOKING-PACKET"),
  259. Extensions: []icmp.Extension{
  260. &icmp.MPLSLabelStack{
  261. Class: 1,
  262. Type: 1,
  263. Labels: []icmp.MPLSLabel{
  264. {
  265. Label: 16014,
  266. TC: 0x4,
  267. S: true,
  268. TTL: 255,
  269. },
  270. },
  271. },
  272. &icmp.InterfaceInfo{
  273. Class: 2,
  274. Type: 0x0f,
  275. Interface: &net.Interface{
  276. Index: 15,
  277. Name: "en101",
  278. MTU: 8192,
  279. },
  280. Addr: &net.IPAddr{
  281. IP: net.ParseIP("fe80::1"),
  282. Zone: "en101",
  283. },
  284. },
  285. },
  286. },
  287. },
  288. {
  289. Type: ipv6.ICMPTypeTimeExceeded, Code: 1,
  290. Body: &icmp.TimeExceeded{
  291. Data: []byte("ERROR-INVOKING-PACKET"),
  292. Extensions: []icmp.Extension{
  293. &icmp.InterfaceInfo{
  294. Class: 2,
  295. Type: 0x0f,
  296. Interface: &net.Interface{
  297. Index: 15,
  298. Name: "en101",
  299. MTU: 8192,
  300. },
  301. Addr: &net.IPAddr{
  302. IP: net.ParseIP("fe80::1"),
  303. Zone: "en101",
  304. },
  305. },
  306. &icmp.MPLSLabelStack{
  307. Class: 1,
  308. Type: 1,
  309. Labels: []icmp.MPLSLabel{
  310. {
  311. Label: 16014,
  312. TC: 0x4,
  313. S: true,
  314. TTL: 255,
  315. },
  316. },
  317. },
  318. &icmp.InterfaceInfo{
  319. Class: 2,
  320. Type: 0x2f,
  321. Interface: &net.Interface{
  322. Index: 16,
  323. Name: "en102",
  324. MTU: 8192,
  325. },
  326. Addr: &net.IPAddr{
  327. IP: net.ParseIP("fe80::1"),
  328. Zone: "en102",
  329. },
  330. },
  331. },
  332. },
  333. },
  334. {
  335. Type: ipv6.ICMPTypeExtendedEchoRequest, Code: 0,
  336. Body: &icmp.ExtendedEchoRequest{
  337. ID: 1, Seq: 2, Local: true,
  338. Extensions: []icmp.Extension{
  339. &icmp.InterfaceIdent{
  340. Class: 3,
  341. Type: 1,
  342. Name: "en101",
  343. },
  344. },
  345. },
  346. },
  347. {
  348. Type: ipv6.ICMPTypeExtendedEchoRequest, Code: 0,
  349. Body: &icmp.ExtendedEchoRequest{
  350. ID: 1, Seq: 2, Local: true,
  351. Extensions: []icmp.Extension{
  352. &icmp.InterfaceIdent{
  353. Class: 3,
  354. Type: 2,
  355. Index: 911,
  356. },
  357. },
  358. },
  359. },
  360. {
  361. Type: ipv6.ICMPTypeExtendedEchoRequest, Code: 0,
  362. Body: &icmp.ExtendedEchoRequest{
  363. ID: 1, Seq: 2,
  364. Extensions: []icmp.Extension{
  365. &icmp.InterfaceIdent{
  366. Class: 3,
  367. Type: 3,
  368. AFI: iana.AddrFamilyIPv4,
  369. Addr: []byte{192, 0, 2, 1},
  370. },
  371. },
  372. },
  373. },
  374. } {
  375. if err := fn(t, iana.ProtocolIPv6ICMP, tm); err != nil {
  376. t.Errorf("#%d: %v", i, err)
  377. }
  378. }
  379. })
  380. }
  381. func dumpExtensions(gotExts, wantExts []icmp.Extension) string {
  382. var s string
  383. for i, got := range gotExts {
  384. switch got := got.(type) {
  385. case *icmp.MPLSLabelStack:
  386. want := wantExts[i].(*icmp.MPLSLabelStack)
  387. if !reflect.DeepEqual(got, want) {
  388. s += fmt.Sprintf("#%d: got %#v; want %#v\n", i, got, want)
  389. }
  390. case *icmp.InterfaceInfo:
  391. want := wantExts[i].(*icmp.InterfaceInfo)
  392. if !reflect.DeepEqual(got, want) {
  393. s += fmt.Sprintf("#%d: got %#v, %#v, %#v; want %#v, %#v, %#v\n", i, got, got.Interface, got.Addr, want, want.Interface, want.Addr)
  394. }
  395. case *icmp.InterfaceIdent:
  396. want := wantExts[i].(*icmp.InterfaceIdent)
  397. if !reflect.DeepEqual(got, want) {
  398. s += fmt.Sprintf("#%d: got %#v; want %#v\n", i, got, want)
  399. }
  400. case *icmp.RawExtension:
  401. s += fmt.Sprintf("#%d: raw extension\n", i)
  402. }
  403. }
  404. if len(s) == 0 {
  405. s += "empty extension"
  406. }
  407. return s[:len(s)-1]
  408. }
  409. func TestMultipartMessageBodyLen(t *testing.T) {
  410. for i, tt := range []struct {
  411. proto int
  412. in icmp.MessageBody
  413. out int
  414. }{
  415. {
  416. iana.ProtocolICMP,
  417. &icmp.DstUnreach{
  418. Data: make([]byte, ipv4.HeaderLen),
  419. },
  420. 4 + ipv4.HeaderLen, // unused and original datagram
  421. },
  422. {
  423. iana.ProtocolICMP,
  424. &icmp.TimeExceeded{
  425. Data: make([]byte, ipv4.HeaderLen),
  426. },
  427. 4 + ipv4.HeaderLen, // unused and original datagram
  428. },
  429. {
  430. iana.ProtocolICMP,
  431. &icmp.ParamProb{
  432. Data: make([]byte, ipv4.HeaderLen),
  433. },
  434. 4 + ipv4.HeaderLen, // [pointer, unused] and original datagram
  435. },
  436. {
  437. iana.ProtocolICMP,
  438. &icmp.ParamProb{
  439. Data: make([]byte, ipv4.HeaderLen),
  440. Extensions: []icmp.Extension{
  441. &icmp.MPLSLabelStack{},
  442. },
  443. },
  444. 4 + 4 + 4 + 0 + 128, // [pointer, length, unused], extension header, object header, object payload, original datagram
  445. },
  446. {
  447. iana.ProtocolICMP,
  448. &icmp.ParamProb{
  449. Data: make([]byte, 128),
  450. Extensions: []icmp.Extension{
  451. &icmp.MPLSLabelStack{},
  452. },
  453. },
  454. 4 + 4 + 4 + 0 + 128, // [pointer, length, unused], extension header, object header, object payload and original datagram
  455. },
  456. {
  457. iana.ProtocolICMP,
  458. &icmp.ParamProb{
  459. Data: make([]byte, 129),
  460. Extensions: []icmp.Extension{
  461. &icmp.MPLSLabelStack{},
  462. },
  463. },
  464. 4 + 4 + 4 + 0 + 132, // [pointer, length, unused], extension header, object header, object payload and original datagram
  465. },
  466. {
  467. iana.ProtocolIPv6ICMP,
  468. &icmp.DstUnreach{
  469. Data: make([]byte, ipv6.HeaderLen),
  470. },
  471. 4 + ipv6.HeaderLen, // unused and original datagram
  472. },
  473. {
  474. iana.ProtocolIPv6ICMP,
  475. &icmp.PacketTooBig{
  476. Data: make([]byte, ipv6.HeaderLen),
  477. },
  478. 4 + ipv6.HeaderLen, // mtu and original datagram
  479. },
  480. {
  481. iana.ProtocolIPv6ICMP,
  482. &icmp.TimeExceeded{
  483. Data: make([]byte, ipv6.HeaderLen),
  484. },
  485. 4 + ipv6.HeaderLen, // unused and original datagram
  486. },
  487. {
  488. iana.ProtocolIPv6ICMP,
  489. &icmp.ParamProb{
  490. Data: make([]byte, ipv6.HeaderLen),
  491. },
  492. 4 + ipv6.HeaderLen, // pointer and original datagram
  493. },
  494. {
  495. iana.ProtocolIPv6ICMP,
  496. &icmp.DstUnreach{
  497. Data: make([]byte, 127),
  498. Extensions: []icmp.Extension{
  499. &icmp.MPLSLabelStack{},
  500. },
  501. },
  502. 4 + 4 + 4 + 0 + 128, // [length, unused], extension header, object header, object payload and original datagram
  503. },
  504. {
  505. iana.ProtocolIPv6ICMP,
  506. &icmp.DstUnreach{
  507. Data: make([]byte, 128),
  508. Extensions: []icmp.Extension{
  509. &icmp.MPLSLabelStack{},
  510. },
  511. },
  512. 4 + 4 + 4 + 0 + 128, // [length, unused], extension header, object header, object payload and original datagram
  513. },
  514. {
  515. iana.ProtocolIPv6ICMP,
  516. &icmp.DstUnreach{
  517. Data: make([]byte, 129),
  518. Extensions: []icmp.Extension{
  519. &icmp.MPLSLabelStack{},
  520. },
  521. },
  522. 4 + 4 + 4 + 0 + 136, // [length, unused], extension header, object header, object payload and original datagram
  523. },
  524. {
  525. iana.ProtocolICMP,
  526. &icmp.ExtendedEchoRequest{},
  527. 4, // [id, seq, l-bit]
  528. },
  529. {
  530. iana.ProtocolICMP,
  531. &icmp.ExtendedEchoRequest{
  532. Extensions: []icmp.Extension{
  533. &icmp.InterfaceIdent{},
  534. },
  535. },
  536. 4 + 4 + 4, // [id, seq, l-bit], extension header, object header
  537. },
  538. {
  539. iana.ProtocolIPv6ICMP,
  540. &icmp.ExtendedEchoRequest{
  541. Extensions: []icmp.Extension{
  542. &icmp.InterfaceIdent{
  543. Type: 3,
  544. AFI: iana.AddrFamilyNSAP,
  545. Addr: []byte{0x49, 0x00, 0x01, 0xaa, 0xaa, 0xbb, 0xbb, 0xcc, 0xcc, 0x00},
  546. },
  547. },
  548. },
  549. 4 + 4 + 4 + 16, // [id, seq, l-bit], extension header, object header, object payload
  550. },
  551. } {
  552. if out := tt.in.Len(tt.proto); out != tt.out {
  553. t.Errorf("#%d: got %d; want %d", i, out, tt.out)
  554. }
  555. }
  556. }