multipart_test.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575
  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. &icmp.InterfaceIdent{
  231. Class: 3,
  232. Type: 1,
  233. Name: "en101",
  234. },
  235. },
  236. },
  237. },
  238. {
  239. Type: ipv4.ICMPTypeExtendedEchoRequest, Code: 0,
  240. Body: &icmp.ExtendedEchoRequest{
  241. ID: 1, Seq: 2,
  242. Extensions: []icmp.Extension{
  243. &icmp.InterfaceIdent{
  244. Class: 3,
  245. Type: 3,
  246. AFI: iana.AddrFamily48bitMAC,
  247. Addr: []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab},
  248. },
  249. },
  250. },
  251. },
  252. } {
  253. if err := fn(t, iana.ProtocolICMP, tm); err != nil {
  254. t.Errorf("#%d: %v", i, err)
  255. }
  256. }
  257. })
  258. t.Run("IPv6", func(t *testing.T) {
  259. for i, tm := range []icmp.Message{
  260. {
  261. Type: ipv6.ICMPTypeDestinationUnreachable, Code: 6,
  262. Body: &icmp.DstUnreach{
  263. Data: []byte("ERROR-INVOKING-PACKET"),
  264. Extensions: []icmp.Extension{
  265. &icmp.MPLSLabelStack{
  266. Class: 1,
  267. Type: 1,
  268. Labels: []icmp.MPLSLabel{
  269. {
  270. Label: 16014,
  271. TC: 0x4,
  272. S: true,
  273. TTL: 255,
  274. },
  275. },
  276. },
  277. &icmp.InterfaceInfo{
  278. Class: 2,
  279. Type: 0x0f,
  280. Interface: &net.Interface{
  281. Index: 15,
  282. Name: "en101",
  283. MTU: 8192,
  284. },
  285. Addr: &net.IPAddr{
  286. IP: net.ParseIP("fe80::1"),
  287. Zone: "en101",
  288. },
  289. },
  290. },
  291. },
  292. },
  293. {
  294. Type: ipv6.ICMPTypeTimeExceeded, Code: 1,
  295. Body: &icmp.TimeExceeded{
  296. Data: []byte("ERROR-INVOKING-PACKET"),
  297. Extensions: []icmp.Extension{
  298. &icmp.InterfaceInfo{
  299. Class: 2,
  300. Type: 0x0f,
  301. Interface: &net.Interface{
  302. Index: 15,
  303. Name: "en101",
  304. MTU: 8192,
  305. },
  306. Addr: &net.IPAddr{
  307. IP: net.ParseIP("fe80::1"),
  308. Zone: "en101",
  309. },
  310. },
  311. &icmp.MPLSLabelStack{
  312. Class: 1,
  313. Type: 1,
  314. Labels: []icmp.MPLSLabel{
  315. {
  316. Label: 16014,
  317. TC: 0x4,
  318. S: true,
  319. TTL: 255,
  320. },
  321. },
  322. },
  323. &icmp.InterfaceInfo{
  324. Class: 2,
  325. Type: 0x2f,
  326. Interface: &net.Interface{
  327. Index: 16,
  328. Name: "en102",
  329. MTU: 8192,
  330. },
  331. Addr: &net.IPAddr{
  332. IP: net.ParseIP("fe80::1"),
  333. Zone: "en102",
  334. },
  335. },
  336. },
  337. },
  338. },
  339. {
  340. Type: ipv6.ICMPTypeExtendedEchoRequest, Code: 0,
  341. Body: &icmp.ExtendedEchoRequest{
  342. ID: 1, Seq: 2, Local: true,
  343. Extensions: []icmp.Extension{
  344. &icmp.InterfaceIdent{
  345. Class: 3,
  346. Type: 1,
  347. Name: "en101",
  348. },
  349. },
  350. },
  351. },
  352. {
  353. Type: ipv6.ICMPTypeExtendedEchoRequest, Code: 0,
  354. Body: &icmp.ExtendedEchoRequest{
  355. ID: 1, Seq: 2, Local: true,
  356. Extensions: []icmp.Extension{
  357. &icmp.InterfaceIdent{
  358. Class: 3,
  359. Type: 1,
  360. Name: "en101",
  361. },
  362. &icmp.InterfaceIdent{
  363. Class: 3,
  364. Type: 2,
  365. Index: 911,
  366. },
  367. },
  368. },
  369. },
  370. {
  371. Type: ipv6.ICMPTypeExtendedEchoRequest, Code: 0,
  372. Body: &icmp.ExtendedEchoRequest{
  373. ID: 1, Seq: 2,
  374. Extensions: []icmp.Extension{
  375. &icmp.InterfaceIdent{
  376. Class: 3,
  377. Type: 3,
  378. AFI: iana.AddrFamilyIPv4,
  379. Addr: []byte{192, 0, 2, 1},
  380. },
  381. },
  382. },
  383. },
  384. } {
  385. if err := fn(t, iana.ProtocolIPv6ICMP, tm); err != nil {
  386. t.Errorf("#%d: %v", i, err)
  387. }
  388. }
  389. })
  390. }
  391. func dumpExtensions(gotExts, wantExts []icmp.Extension) string {
  392. var s string
  393. for i, got := range gotExts {
  394. switch got := got.(type) {
  395. case *icmp.MPLSLabelStack:
  396. want := wantExts[i].(*icmp.MPLSLabelStack)
  397. if !reflect.DeepEqual(got, want) {
  398. s += fmt.Sprintf("#%d: got %#v; want %#v\n", i, got, want)
  399. }
  400. case *icmp.InterfaceInfo:
  401. want := wantExts[i].(*icmp.InterfaceInfo)
  402. if !reflect.DeepEqual(got, want) {
  403. s += fmt.Sprintf("#%d: got %#v, %#v, %#v; want %#v, %#v, %#v\n", i, got, got.Interface, got.Addr, want, want.Interface, want.Addr)
  404. }
  405. case *icmp.InterfaceIdent:
  406. want := wantExts[i].(*icmp.InterfaceIdent)
  407. if !reflect.DeepEqual(got, want) {
  408. s += fmt.Sprintf("#%d: got %#v; want %#v\n", i, got, want)
  409. }
  410. }
  411. }
  412. if len(s) == 0 {
  413. return "<nil>"
  414. }
  415. return s[:len(s)-1]
  416. }
  417. func TestMultipartMessageBodyLen(t *testing.T) {
  418. for i, tt := range []struct {
  419. proto int
  420. in icmp.MessageBody
  421. out int
  422. }{
  423. {
  424. iana.ProtocolICMP,
  425. &icmp.DstUnreach{
  426. Data: make([]byte, ipv4.HeaderLen),
  427. },
  428. 4 + ipv4.HeaderLen, // unused and original datagram
  429. },
  430. {
  431. iana.ProtocolICMP,
  432. &icmp.TimeExceeded{
  433. Data: make([]byte, ipv4.HeaderLen),
  434. },
  435. 4 + ipv4.HeaderLen, // unused and original datagram
  436. },
  437. {
  438. iana.ProtocolICMP,
  439. &icmp.ParamProb{
  440. Data: make([]byte, ipv4.HeaderLen),
  441. },
  442. 4 + ipv4.HeaderLen, // [pointer, unused] and original datagram
  443. },
  444. {
  445. iana.ProtocolICMP,
  446. &icmp.ParamProb{
  447. Data: make([]byte, ipv4.HeaderLen),
  448. Extensions: []icmp.Extension{
  449. &icmp.MPLSLabelStack{},
  450. },
  451. },
  452. 4 + 4 + 4 + 0 + 128, // [pointer, length, unused], extension header, object header, object payload, original datagram
  453. },
  454. {
  455. iana.ProtocolICMP,
  456. &icmp.ParamProb{
  457. Data: make([]byte, 128),
  458. Extensions: []icmp.Extension{
  459. &icmp.MPLSLabelStack{},
  460. },
  461. },
  462. 4 + 4 + 4 + 0 + 128, // [pointer, length, unused], extension header, object header, object payload and original datagram
  463. },
  464. {
  465. iana.ProtocolICMP,
  466. &icmp.ParamProb{
  467. Data: make([]byte, 129),
  468. Extensions: []icmp.Extension{
  469. &icmp.MPLSLabelStack{},
  470. },
  471. },
  472. 4 + 4 + 4 + 0 + 132, // [pointer, length, unused], extension header, object header, object payload and original datagram
  473. },
  474. {
  475. iana.ProtocolIPv6ICMP,
  476. &icmp.DstUnreach{
  477. Data: make([]byte, ipv6.HeaderLen),
  478. },
  479. 4 + ipv6.HeaderLen, // unused and original datagram
  480. },
  481. {
  482. iana.ProtocolIPv6ICMP,
  483. &icmp.PacketTooBig{
  484. Data: make([]byte, ipv6.HeaderLen),
  485. },
  486. 4 + ipv6.HeaderLen, // mtu and original datagram
  487. },
  488. {
  489. iana.ProtocolIPv6ICMP,
  490. &icmp.TimeExceeded{
  491. Data: make([]byte, ipv6.HeaderLen),
  492. },
  493. 4 + ipv6.HeaderLen, // unused and original datagram
  494. },
  495. {
  496. iana.ProtocolIPv6ICMP,
  497. &icmp.ParamProb{
  498. Data: make([]byte, ipv6.HeaderLen),
  499. },
  500. 4 + ipv6.HeaderLen, // pointer and original datagram
  501. },
  502. {
  503. iana.ProtocolIPv6ICMP,
  504. &icmp.DstUnreach{
  505. Data: make([]byte, 127),
  506. Extensions: []icmp.Extension{
  507. &icmp.MPLSLabelStack{},
  508. },
  509. },
  510. 4 + 4 + 4 + 0 + 128, // [length, unused], extension header, object header, object payload and original datagram
  511. },
  512. {
  513. iana.ProtocolIPv6ICMP,
  514. &icmp.DstUnreach{
  515. Data: make([]byte, 128),
  516. Extensions: []icmp.Extension{
  517. &icmp.MPLSLabelStack{},
  518. },
  519. },
  520. 4 + 4 + 4 + 0 + 128, // [length, unused], extension header, object header, object payload and original datagram
  521. },
  522. {
  523. iana.ProtocolIPv6ICMP,
  524. &icmp.DstUnreach{
  525. Data: make([]byte, 129),
  526. Extensions: []icmp.Extension{
  527. &icmp.MPLSLabelStack{},
  528. },
  529. },
  530. 4 + 4 + 4 + 0 + 136, // [length, unused], extension header, object header, object payload and original datagram
  531. },
  532. {
  533. iana.ProtocolICMP,
  534. &icmp.ExtendedEchoRequest{},
  535. 4, // [id, seq, l-bit]
  536. },
  537. {
  538. iana.ProtocolICMP,
  539. &icmp.ExtendedEchoRequest{
  540. Extensions: []icmp.Extension{
  541. &icmp.InterfaceIdent{},
  542. },
  543. },
  544. 4 + 4 + 4, // [id, seq, l-bit], extension header, object header
  545. },
  546. {
  547. iana.ProtocolIPv6ICMP,
  548. &icmp.ExtendedEchoRequest{
  549. Extensions: []icmp.Extension{
  550. &icmp.InterfaceIdent{
  551. Type: 3,
  552. AFI: iana.AddrFamilyNSAP,
  553. Addr: []byte{0x49, 0x00, 0x01, 0xaa, 0xaa, 0xbb, 0xbb, 0xcc, 0xcc, 0x00},
  554. },
  555. },
  556. },
  557. 4 + 4 + 4 + 16, // [id, seq, l-bit], extension header, object header, object payload
  558. },
  559. } {
  560. if out := tt.in.Len(tt.proto); out != tt.out {
  561. t.Errorf("#%d: got %d; want %d", i, out, tt.out)
  562. }
  563. }
  564. }