message_test.go 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. // Copyright 2014 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. "bytes"
  7. "net"
  8. "reflect"
  9. "testing"
  10. "golang.org/x/net/icmp"
  11. "golang.org/x/net/internal/iana"
  12. "golang.org/x/net/ipv4"
  13. "golang.org/x/net/ipv6"
  14. )
  15. func TestMarshalAndParseMessage(t *testing.T) {
  16. fn := func(t *testing.T, proto int, tms []icmp.Message) {
  17. var pshs [][]byte
  18. switch proto {
  19. case iana.ProtocolICMP:
  20. pshs = [][]byte{nil}
  21. case iana.ProtocolIPv6ICMP:
  22. pshs = [][]byte{
  23. icmp.IPv6PseudoHeader(net.ParseIP("fe80::1"), net.ParseIP("ff02::1")),
  24. nil,
  25. }
  26. }
  27. for i, tm := range tms {
  28. for _, psh := range pshs {
  29. b, err := tm.Marshal(psh)
  30. if err != nil {
  31. t.Fatalf("#%d: %v", i, err)
  32. }
  33. m, err := icmp.ParseMessage(proto, b)
  34. if err != nil {
  35. t.Fatalf("#%d: %v", i, err)
  36. }
  37. if m.Type != tm.Type || m.Code != tm.Code {
  38. t.Errorf("#%d: got %#v; want %#v", i, m, &tm)
  39. continue
  40. }
  41. if !reflect.DeepEqual(m.Body, tm.Body) {
  42. t.Errorf("#%d: got %#v; want %#v", i, m.Body, tm.Body)
  43. continue
  44. }
  45. }
  46. }
  47. }
  48. t.Run("IPv4", func(t *testing.T) {
  49. fn(t, iana.ProtocolICMP,
  50. []icmp.Message{
  51. {
  52. Type: ipv4.ICMPTypeDestinationUnreachable, Code: 15,
  53. Body: &icmp.DstUnreach{
  54. Data: []byte("ERROR-INVOKING-PACKET"),
  55. },
  56. },
  57. {
  58. Type: ipv4.ICMPTypeTimeExceeded, Code: 1,
  59. Body: &icmp.TimeExceeded{
  60. Data: []byte("ERROR-INVOKING-PACKET"),
  61. },
  62. },
  63. {
  64. Type: ipv4.ICMPTypeParameterProblem, Code: 2,
  65. Body: &icmp.ParamProb{
  66. Pointer: 8,
  67. Data: []byte("ERROR-INVOKING-PACKET"),
  68. },
  69. },
  70. {
  71. Type: ipv4.ICMPTypeEcho, Code: 0,
  72. Body: &icmp.Echo{
  73. ID: 1, Seq: 2,
  74. Data: []byte("HELLO-R-U-THERE"),
  75. },
  76. },
  77. {
  78. Type: ipv4.ICMPTypeExtendedEchoRequest, Code: 0,
  79. Body: &icmp.ExtendedEchoRequest{
  80. ID: 1, Seq: 2,
  81. Extensions: []icmp.Extension{
  82. &icmp.InterfaceIdent{
  83. Class: 3,
  84. Type: 1,
  85. Name: "en101",
  86. },
  87. },
  88. },
  89. },
  90. {
  91. Type: ipv4.ICMPTypeExtendedEchoReply, Code: 0,
  92. Body: &icmp.ExtendedEchoReply{
  93. State: 4 /* Delay */, Active: true, IPv4: true,
  94. },
  95. },
  96. })
  97. })
  98. t.Run("IPv6", func(t *testing.T) {
  99. fn(t, iana.ProtocolIPv6ICMP,
  100. []icmp.Message{
  101. {
  102. Type: ipv6.ICMPTypeDestinationUnreachable, Code: 6,
  103. Body: &icmp.DstUnreach{
  104. Data: []byte("ERROR-INVOKING-PACKET"),
  105. },
  106. },
  107. {
  108. Type: ipv6.ICMPTypePacketTooBig, Code: 0,
  109. Body: &icmp.PacketTooBig{
  110. MTU: 1<<16 - 1,
  111. Data: []byte("ERROR-INVOKING-PACKET"),
  112. },
  113. },
  114. {
  115. Type: ipv6.ICMPTypeTimeExceeded, Code: 1,
  116. Body: &icmp.TimeExceeded{
  117. Data: []byte("ERROR-INVOKING-PACKET"),
  118. },
  119. },
  120. {
  121. Type: ipv6.ICMPTypeParameterProblem, Code: 2,
  122. Body: &icmp.ParamProb{
  123. Pointer: 8,
  124. Data: []byte("ERROR-INVOKING-PACKET"),
  125. },
  126. },
  127. {
  128. Type: ipv6.ICMPTypeEchoRequest, Code: 0,
  129. Body: &icmp.Echo{
  130. ID: 1, Seq: 2,
  131. Data: []byte("HELLO-R-U-THERE"),
  132. },
  133. },
  134. {
  135. Type: ipv6.ICMPTypeExtendedEchoRequest, Code: 0,
  136. Body: &icmp.ExtendedEchoRequest{
  137. ID: 1, Seq: 2,
  138. Extensions: []icmp.Extension{
  139. &icmp.InterfaceIdent{
  140. Class: 3,
  141. Type: 2,
  142. Index: 911,
  143. },
  144. },
  145. },
  146. },
  147. {
  148. Type: ipv6.ICMPTypeExtendedEchoReply, Code: 0,
  149. Body: &icmp.ExtendedEchoReply{
  150. State: 5 /* Probe */, Active: true, IPv6: true,
  151. },
  152. },
  153. })
  154. })
  155. }
  156. func TestMarshalAndParseRawMessage(t *testing.T) {
  157. t.Run("RawBody", func(t *testing.T) {
  158. for i, tt := range []struct {
  159. m icmp.Message
  160. wire []byte
  161. parseShouldFail bool
  162. }{
  163. { // Nil body
  164. m: icmp.Message{
  165. Type: ipv4.ICMPTypeDestinationUnreachable, Code: 127,
  166. },
  167. wire: []byte{
  168. 0x03, 0x7f, 0xfc, 0x80,
  169. },
  170. parseShouldFail: true,
  171. },
  172. { // Empty body
  173. m: icmp.Message{
  174. Type: ipv6.ICMPTypeDestinationUnreachable, Code: 128,
  175. Body: &icmp.RawBody{},
  176. },
  177. wire: []byte{
  178. 0x01, 0x80, 0x00, 0x00,
  179. },
  180. parseShouldFail: true,
  181. },
  182. { // Crafted body
  183. m: icmp.Message{
  184. Type: ipv6.ICMPTypeDuplicateAddressConfirmation, Code: 129,
  185. Body: &icmp.RawBody{
  186. Data: []byte{0xca, 0xfe},
  187. },
  188. },
  189. wire: []byte{
  190. 0x9e, 0x81, 0x00, 0x00,
  191. 0xca, 0xfe,
  192. },
  193. parseShouldFail: false,
  194. },
  195. } {
  196. b, err := tt.m.Marshal(nil)
  197. if err != nil {
  198. t.Errorf("#%d: %v", i, err)
  199. continue
  200. }
  201. if !bytes.Equal(b, tt.wire) {
  202. t.Errorf("#%d: got %#v; want %#v", i, b, tt.wire)
  203. continue
  204. }
  205. m, err := icmp.ParseMessage(tt.m.Type.Protocol(), b)
  206. if err != nil != tt.parseShouldFail {
  207. t.Errorf("#%d: got %v, %v", i, m, err)
  208. continue
  209. }
  210. if tt.parseShouldFail {
  211. continue
  212. }
  213. if m.Type != tt.m.Type || m.Code != tt.m.Code {
  214. t.Errorf("#%d: got %v; want %v", i, m, tt.m)
  215. continue
  216. }
  217. if !bytes.Equal(m.Body.(*icmp.RawBody).Data, tt.m.Body.(*icmp.RawBody).Data) {
  218. t.Errorf("#%d: got %#v; want %#v", i, m.Body, tt.m.Body)
  219. continue
  220. }
  221. }
  222. })
  223. t.Run("RawExtension", func(t *testing.T) {
  224. for i, tt := range []struct {
  225. m icmp.Message
  226. wire []byte
  227. }{
  228. { // Unaligned data and nil extension
  229. m: icmp.Message{
  230. Type: ipv6.ICMPTypeDestinationUnreachable, Code: 130,
  231. Body: &icmp.DstUnreach{
  232. Data: []byte("ERROR-INVOKING-PACKET"),
  233. },
  234. },
  235. wire: []byte{
  236. 0x01, 0x82, 0x00, 0x00,
  237. 0x00, 0x00, 0x00, 0x00,
  238. 'E', 'R', 'R', 'O',
  239. 'R', '-', 'I', 'N',
  240. 'V', 'O', 'K', 'I',
  241. 'N', 'G', '-', 'P',
  242. 'A', 'C', 'K', 'E',
  243. 'T',
  244. },
  245. },
  246. { // Unaligned data and empty extension
  247. m: icmp.Message{
  248. Type: ipv6.ICMPTypeDestinationUnreachable, Code: 131,
  249. Body: &icmp.DstUnreach{
  250. Data: []byte("ERROR-INVOKING-PACKET"),
  251. Extensions: []icmp.Extension{
  252. &icmp.RawExtension{},
  253. },
  254. },
  255. },
  256. wire: []byte{
  257. 0x01, 0x83, 0x00, 0x00,
  258. 0x02, 0x00, 0x00, 0x00,
  259. 'E', 'R', 'R', 'O',
  260. 'R', '-', 'I', 'N',
  261. 'V', 'O', 'K', 'I',
  262. 'N', 'G', '-', 'P',
  263. 'A', 'C', 'K', 'E',
  264. 'T',
  265. 0x20, 0x00, 0xdf, 0xff,
  266. },
  267. },
  268. { // Nil extension
  269. m: icmp.Message{
  270. Type: ipv6.ICMPTypeExtendedEchoRequest, Code: 132,
  271. Body: &icmp.ExtendedEchoRequest{
  272. ID: 1, Seq: 2, Local: true,
  273. },
  274. },
  275. wire: []byte{
  276. 0xa0, 0x84, 0x00, 0x00,
  277. 0x00, 0x01, 0x02, 0x01,
  278. },
  279. },
  280. { // Empty extension
  281. m: icmp.Message{
  282. Type: ipv6.ICMPTypeExtendedEchoRequest, Code: 133,
  283. Body: &icmp.ExtendedEchoRequest{
  284. ID: 1, Seq: 2, Local: true,
  285. Extensions: []icmp.Extension{
  286. &icmp.RawExtension{},
  287. },
  288. },
  289. },
  290. wire: []byte{
  291. 0xa0, 0x85, 0x00, 0x00,
  292. 0x00, 0x01, 0x02, 0x01,
  293. 0x20, 0x00, 0xdf, 0xff,
  294. },
  295. },
  296. { // Crafted extension
  297. m: icmp.Message{
  298. Type: ipv6.ICMPTypeExtendedEchoRequest, Code: 134,
  299. Body: &icmp.ExtendedEchoRequest{
  300. ID: 1, Seq: 2, Local: true,
  301. Extensions: []icmp.Extension{
  302. &icmp.RawExtension{
  303. Data: []byte("CRAFTED"),
  304. },
  305. },
  306. },
  307. },
  308. wire: []byte{
  309. 0xa0, 0x86, 0x00, 0x00,
  310. 0x00, 0x01, 0x02, 0x01,
  311. 0x20, 0x00, 0xc3, 0x21,
  312. 'C', 'R', 'A', 'F',
  313. 'T', 'E', 'D',
  314. },
  315. },
  316. } {
  317. b, err := tt.m.Marshal(nil)
  318. if err != nil {
  319. t.Errorf("#%d: %v", i, err)
  320. continue
  321. }
  322. if !bytes.Equal(b, tt.wire) {
  323. t.Errorf("#%d: got %#v; want %#v", i, b, tt.wire)
  324. continue
  325. }
  326. m, err := icmp.ParseMessage(tt.m.Type.Protocol(), b)
  327. if err != nil {
  328. t.Errorf("#%d: %v", i, err)
  329. continue
  330. }
  331. if m.Type != tt.m.Type || m.Code != tt.m.Code {
  332. t.Errorf("#%d: got %v; want %v", i, m, tt.m)
  333. continue
  334. }
  335. }
  336. })
  337. }