multipart_test.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  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 proto {
  23. case iana.ProtocolICMP:
  24. if b[5] != 32 {
  25. return fmt.Errorf("got %d; want 32", b[5])
  26. }
  27. case iana.ProtocolIPv6ICMP:
  28. if b[4] != 16 {
  29. return fmt.Errorf("got %d; want 16", b[4])
  30. }
  31. default:
  32. return fmt.Errorf("unknown protocol: %d", proto)
  33. }
  34. m, err := icmp.ParseMessage(proto, b)
  35. if err != nil {
  36. return err
  37. }
  38. if m.Type != tm.Type || m.Code != tm.Code {
  39. return fmt.Errorf("got %v; want %v", m, &tm)
  40. }
  41. switch m.Type {
  42. case ipv4.ICMPTypeDestinationUnreachable:
  43. got, want := m.Body.(*icmp.DstUnreach), tm.Body.(*icmp.DstUnreach)
  44. if !reflect.DeepEqual(got.Extensions, want.Extensions) {
  45. return errors.New(dumpExtensions(got.Extensions, want.Extensions))
  46. }
  47. if len(got.Data) != 128 {
  48. return fmt.Errorf("got %d; want 128", len(got.Data))
  49. }
  50. case ipv4.ICMPTypeTimeExceeded:
  51. got, want := m.Body.(*icmp.TimeExceeded), tm.Body.(*icmp.TimeExceeded)
  52. if !reflect.DeepEqual(got.Extensions, want.Extensions) {
  53. return errors.New(dumpExtensions(got.Extensions, want.Extensions))
  54. }
  55. if len(got.Data) != 128 {
  56. return fmt.Errorf("got %d; want 128", len(got.Data))
  57. }
  58. case ipv4.ICMPTypeParameterProblem:
  59. got, want := m.Body.(*icmp.ParamProb), tm.Body.(*icmp.ParamProb)
  60. if !reflect.DeepEqual(got.Extensions, want.Extensions) {
  61. return errors.New(dumpExtensions(got.Extensions, want.Extensions))
  62. }
  63. if len(got.Data) != 128 {
  64. return fmt.Errorf("got %d; want 128", len(got.Data))
  65. }
  66. case ipv6.ICMPTypeDestinationUnreachable:
  67. got, want := m.Body.(*icmp.DstUnreach), tm.Body.(*icmp.DstUnreach)
  68. if !reflect.DeepEqual(got.Extensions, want.Extensions) {
  69. return errors.New(dumpExtensions(got.Extensions, want.Extensions))
  70. }
  71. if len(got.Data) != 128 {
  72. return fmt.Errorf("got %d; want 128", len(got.Data))
  73. }
  74. case ipv6.ICMPTypeTimeExceeded:
  75. got, want := m.Body.(*icmp.TimeExceeded), tm.Body.(*icmp.TimeExceeded)
  76. if !reflect.DeepEqual(got.Extensions, want.Extensions) {
  77. return errors.New(dumpExtensions(got.Extensions, want.Extensions))
  78. }
  79. if len(got.Data) != 128 {
  80. return fmt.Errorf("got %d; want 128", len(got.Data))
  81. }
  82. default:
  83. return fmt.Errorf("unknown message type: %v", m.Type)
  84. }
  85. return nil
  86. }
  87. t.Run("IPv4", func(t *testing.T) {
  88. for i, tm := range []icmp.Message{
  89. {
  90. Type: ipv4.ICMPTypeDestinationUnreachable, Code: 15,
  91. Body: &icmp.DstUnreach{
  92. Data: []byte("ERROR-INVOKING-PACKET"),
  93. Extensions: []icmp.Extension{
  94. &icmp.MPLSLabelStack{
  95. Class: 1,
  96. Type: 1,
  97. Labels: []icmp.MPLSLabel{
  98. {
  99. Label: 16014,
  100. TC: 0x4,
  101. S: true,
  102. TTL: 255,
  103. },
  104. },
  105. },
  106. &icmp.InterfaceInfo{
  107. Class: 2,
  108. Type: 0x0f,
  109. Interface: &net.Interface{
  110. Index: 15,
  111. Name: "en101",
  112. MTU: 8192,
  113. },
  114. Addr: &net.IPAddr{
  115. IP: net.IPv4(192, 168, 0, 1).To4(),
  116. },
  117. },
  118. },
  119. },
  120. },
  121. {
  122. Type: ipv4.ICMPTypeTimeExceeded, Code: 1,
  123. Body: &icmp.TimeExceeded{
  124. Data: []byte("ERROR-INVOKING-PACKET"),
  125. Extensions: []icmp.Extension{
  126. &icmp.InterfaceInfo{
  127. Class: 2,
  128. Type: 0x0f,
  129. Interface: &net.Interface{
  130. Index: 15,
  131. Name: "en101",
  132. MTU: 8192,
  133. },
  134. Addr: &net.IPAddr{
  135. IP: net.IPv4(192, 168, 0, 1).To4(),
  136. },
  137. },
  138. &icmp.MPLSLabelStack{
  139. Class: 1,
  140. Type: 1,
  141. Labels: []icmp.MPLSLabel{
  142. {
  143. Label: 16014,
  144. TC: 0x4,
  145. S: true,
  146. TTL: 255,
  147. },
  148. },
  149. },
  150. },
  151. },
  152. },
  153. {
  154. Type: ipv4.ICMPTypeParameterProblem, Code: 2,
  155. Body: &icmp.ParamProb{
  156. Pointer: 8,
  157. Data: []byte("ERROR-INVOKING-PACKET"),
  158. Extensions: []icmp.Extension{
  159. &icmp.MPLSLabelStack{
  160. Class: 1,
  161. Type: 1,
  162. Labels: []icmp.MPLSLabel{
  163. {
  164. Label: 16014,
  165. TC: 0x4,
  166. S: true,
  167. TTL: 255,
  168. },
  169. },
  170. },
  171. &icmp.InterfaceInfo{
  172. Class: 2,
  173. Type: 0x0f,
  174. Interface: &net.Interface{
  175. Index: 15,
  176. Name: "en101",
  177. MTU: 8192,
  178. },
  179. Addr: &net.IPAddr{
  180. IP: net.IPv4(192, 168, 0, 1).To4(),
  181. },
  182. },
  183. &icmp.InterfaceInfo{
  184. Class: 2,
  185. Type: 0x2f,
  186. Interface: &net.Interface{
  187. Index: 16,
  188. Name: "en102",
  189. MTU: 8192,
  190. },
  191. Addr: &net.IPAddr{
  192. IP: net.IPv4(192, 168, 0, 2).To4(),
  193. },
  194. },
  195. },
  196. },
  197. },
  198. } {
  199. if err := fn(t, iana.ProtocolICMP, tm); err != nil {
  200. t.Errorf("#%d: %v", i, err)
  201. }
  202. }
  203. })
  204. t.Run("IPv6", func(t *testing.T) {
  205. for i, tm := range []icmp.Message{
  206. {
  207. Type: ipv6.ICMPTypeDestinationUnreachable, Code: 6,
  208. Body: &icmp.DstUnreach{
  209. Data: []byte("ERROR-INVOKING-PACKET"),
  210. Extensions: []icmp.Extension{
  211. &icmp.MPLSLabelStack{
  212. Class: 1,
  213. Type: 1,
  214. Labels: []icmp.MPLSLabel{
  215. {
  216. Label: 16014,
  217. TC: 0x4,
  218. S: true,
  219. TTL: 255,
  220. },
  221. },
  222. },
  223. &icmp.InterfaceInfo{
  224. Class: 2,
  225. Type: 0x0f,
  226. Interface: &net.Interface{
  227. Index: 15,
  228. Name: "en101",
  229. MTU: 8192,
  230. },
  231. Addr: &net.IPAddr{
  232. IP: net.ParseIP("fe80::1"),
  233. Zone: "en101",
  234. },
  235. },
  236. },
  237. },
  238. },
  239. {
  240. Type: ipv6.ICMPTypeTimeExceeded, Code: 1,
  241. Body: &icmp.TimeExceeded{
  242. Data: []byte("ERROR-INVOKING-PACKET"),
  243. Extensions: []icmp.Extension{
  244. &icmp.InterfaceInfo{
  245. Class: 2,
  246. Type: 0x0f,
  247. Interface: &net.Interface{
  248. Index: 15,
  249. Name: "en101",
  250. MTU: 8192,
  251. },
  252. Addr: &net.IPAddr{
  253. IP: net.ParseIP("fe80::1"),
  254. Zone: "en101",
  255. },
  256. },
  257. &icmp.MPLSLabelStack{
  258. Class: 1,
  259. Type: 1,
  260. Labels: []icmp.MPLSLabel{
  261. {
  262. Label: 16014,
  263. TC: 0x4,
  264. S: true,
  265. TTL: 255,
  266. },
  267. },
  268. },
  269. &icmp.InterfaceInfo{
  270. Class: 2,
  271. Type: 0x2f,
  272. Interface: &net.Interface{
  273. Index: 16,
  274. Name: "en102",
  275. MTU: 8192,
  276. },
  277. Addr: &net.IPAddr{
  278. IP: net.ParseIP("fe80::1"),
  279. Zone: "en102",
  280. },
  281. },
  282. },
  283. },
  284. },
  285. } {
  286. if err := fn(t, iana.ProtocolIPv6ICMP, tm); err != nil {
  287. t.Errorf("#%d: %v", i, err)
  288. }
  289. }
  290. })
  291. }
  292. func dumpExtensions(gotExts, wantExts []icmp.Extension) string {
  293. var s string
  294. for i, got := range gotExts {
  295. switch got := got.(type) {
  296. case *icmp.MPLSLabelStack:
  297. want := wantExts[i].(*icmp.MPLSLabelStack)
  298. if !reflect.DeepEqual(got, want) {
  299. s += fmt.Sprintf("#%d: got %#v; want %#v\n", i, got, want)
  300. }
  301. case *icmp.InterfaceInfo:
  302. want := wantExts[i].(*icmp.InterfaceInfo)
  303. if !reflect.DeepEqual(got, want) {
  304. s += fmt.Sprintf("#%d: got %#v, %#v, %#v; want %#v, %#v, %#v\n", i, got, got.Interface, got.Addr, want, want.Interface, want.Addr)
  305. }
  306. }
  307. }
  308. if len(s) == 0 {
  309. return "<nil>"
  310. }
  311. return s[:len(s)-1]
  312. }
  313. func TestMultipartMessageBodyLen(t *testing.T) {
  314. for i, tt := range []struct {
  315. proto int
  316. in icmp.MessageBody
  317. out int
  318. }{
  319. {
  320. iana.ProtocolICMP,
  321. &icmp.DstUnreach{
  322. Data: make([]byte, ipv4.HeaderLen),
  323. },
  324. 4 + ipv4.HeaderLen, // unused and original datagram
  325. },
  326. {
  327. iana.ProtocolICMP,
  328. &icmp.TimeExceeded{
  329. Data: make([]byte, ipv4.HeaderLen),
  330. },
  331. 4 + ipv4.HeaderLen, // unused and original datagram
  332. },
  333. {
  334. iana.ProtocolICMP,
  335. &icmp.ParamProb{
  336. Data: make([]byte, ipv4.HeaderLen),
  337. },
  338. 4 + ipv4.HeaderLen, // [pointer, unused] and original datagram
  339. },
  340. {
  341. iana.ProtocolICMP,
  342. &icmp.ParamProb{
  343. Data: make([]byte, ipv4.HeaderLen),
  344. Extensions: []icmp.Extension{
  345. &icmp.MPLSLabelStack{},
  346. },
  347. },
  348. 4 + 4 + 4 + 0 + 128, // [pointer, length, unused], extension header, object header, object payload, original datagram
  349. },
  350. {
  351. iana.ProtocolICMP,
  352. &icmp.ParamProb{
  353. Data: make([]byte, 128),
  354. Extensions: []icmp.Extension{
  355. &icmp.MPLSLabelStack{},
  356. },
  357. },
  358. 4 + 4 + 4 + 0 + 128, // [pointer, length, unused], extension header, object header, object payload and original datagram
  359. },
  360. {
  361. iana.ProtocolICMP,
  362. &icmp.ParamProb{
  363. Data: make([]byte, 129),
  364. Extensions: []icmp.Extension{
  365. &icmp.MPLSLabelStack{},
  366. },
  367. },
  368. 4 + 4 + 4 + 0 + 132, // [pointer, length, unused], extension header, object header, object payload and original datagram
  369. },
  370. {
  371. iana.ProtocolIPv6ICMP,
  372. &icmp.DstUnreach{
  373. Data: make([]byte, ipv6.HeaderLen),
  374. },
  375. 4 + ipv6.HeaderLen, // unused and original datagram
  376. },
  377. {
  378. iana.ProtocolIPv6ICMP,
  379. &icmp.PacketTooBig{
  380. Data: make([]byte, ipv6.HeaderLen),
  381. },
  382. 4 + ipv6.HeaderLen, // mtu and original datagram
  383. },
  384. {
  385. iana.ProtocolIPv6ICMP,
  386. &icmp.TimeExceeded{
  387. Data: make([]byte, ipv6.HeaderLen),
  388. },
  389. 4 + ipv6.HeaderLen, // unused and original datagram
  390. },
  391. {
  392. iana.ProtocolIPv6ICMP,
  393. &icmp.ParamProb{
  394. Data: make([]byte, ipv6.HeaderLen),
  395. },
  396. 4 + ipv6.HeaderLen, // pointer and original datagram
  397. },
  398. {
  399. iana.ProtocolIPv6ICMP,
  400. &icmp.DstUnreach{
  401. Data: make([]byte, 127),
  402. Extensions: []icmp.Extension{
  403. &icmp.MPLSLabelStack{},
  404. },
  405. },
  406. 4 + 4 + 4 + 0 + 128, // [length, unused], extension header, object header, object payload and original datagram
  407. },
  408. {
  409. iana.ProtocolIPv6ICMP,
  410. &icmp.DstUnreach{
  411. Data: make([]byte, 128),
  412. Extensions: []icmp.Extension{
  413. &icmp.MPLSLabelStack{},
  414. },
  415. },
  416. 4 + 4 + 4 + 0 + 128, // [length, unused], extension header, object header, object payload and original datagram
  417. },
  418. {
  419. iana.ProtocolIPv6ICMP,
  420. &icmp.DstUnreach{
  421. Data: make([]byte, 129),
  422. Extensions: []icmp.Extension{
  423. &icmp.MPLSLabelStack{},
  424. },
  425. },
  426. 4 + 4 + 4 + 0 + 136, // [length, unused], extension header, object header, object payload and original datagram
  427. },
  428. } {
  429. if out := tt.in.Len(tt.proto); out != tt.out {
  430. t.Errorf("#%d: got %d; want %d", i, out, tt.out)
  431. }
  432. }
  433. }