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.
 
 
 

333 lines
8.0 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
  5. import (
  6. "fmt"
  7. "net"
  8. "reflect"
  9. "testing"
  10. "golang.org/x/net/internal/iana"
  11. "golang.org/x/net/ipv4"
  12. "golang.org/x/net/ipv6"
  13. )
  14. func TestMarshalAndParseExtension(t *testing.T) {
  15. fn := func(t *testing.T, proto int, typ Type, hdr, obj []byte, te Extension) error {
  16. b, err := te.Marshal(proto)
  17. if err != nil {
  18. return err
  19. }
  20. if !reflect.DeepEqual(b, obj) {
  21. return fmt.Errorf("got %#v; want %#v", b, obj)
  22. }
  23. switch typ {
  24. case ipv4.ICMPTypeExtendedEchoRequest, ipv6.ICMPTypeExtendedEchoRequest:
  25. exts, l, err := parseExtensions(typ, append(hdr, obj...), 0)
  26. if err != nil {
  27. return err
  28. }
  29. if l != 0 {
  30. return fmt.Errorf("got %d; want 0", l)
  31. }
  32. if !reflect.DeepEqual(exts, []Extension{te}) {
  33. return fmt.Errorf("got %#v; want %#v", exts[0], te)
  34. }
  35. default:
  36. for i, wire := range []struct {
  37. data []byte // original datagram
  38. inlattr int // length of padded original datagram, a hint
  39. outlattr int // length of padded original datagram, a want
  40. err error
  41. }{
  42. {nil, 0, -1, errNoExtension},
  43. {make([]byte, 127), 128, -1, errNoExtension},
  44. {make([]byte, 128), 127, -1, errNoExtension},
  45. {make([]byte, 128), 128, -1, errNoExtension},
  46. {make([]byte, 128), 129, -1, errNoExtension},
  47. {append(make([]byte, 128), append(hdr, obj...)...), 127, 128, nil},
  48. {append(make([]byte, 128), append(hdr, obj...)...), 128, 128, nil},
  49. {append(make([]byte, 128), append(hdr, obj...)...), 129, 128, nil},
  50. {append(make([]byte, 512), append(hdr, obj...)...), 511, -1, errNoExtension},
  51. {append(make([]byte, 512), append(hdr, obj...)...), 512, 512, nil},
  52. {append(make([]byte, 512), append(hdr, obj...)...), 513, -1, errNoExtension},
  53. } {
  54. exts, l, err := parseExtensions(typ, wire.data, wire.inlattr)
  55. if err != wire.err {
  56. return fmt.Errorf("#%d: got %v; want %v", i, err, wire.err)
  57. }
  58. if wire.err != nil {
  59. continue
  60. }
  61. if l != wire.outlattr {
  62. return fmt.Errorf("#%d: got %d; want %d", i, l, wire.outlattr)
  63. }
  64. if !reflect.DeepEqual(exts, []Extension{te}) {
  65. return fmt.Errorf("#%d: got %#v; want %#v", i, exts[0], te)
  66. }
  67. }
  68. }
  69. return nil
  70. }
  71. t.Run("MPLSLabelStack", func(t *testing.T) {
  72. for _, et := range []struct {
  73. proto int
  74. typ Type
  75. hdr []byte
  76. obj []byte
  77. ext Extension
  78. }{
  79. // MPLS label stack with no label
  80. {
  81. proto: iana.ProtocolICMP,
  82. typ: ipv4.ICMPTypeDestinationUnreachable,
  83. hdr: []byte{
  84. 0x20, 0x00, 0x00, 0x00,
  85. },
  86. obj: []byte{
  87. 0x00, 0x04, 0x01, 0x01,
  88. },
  89. ext: &MPLSLabelStack{
  90. Class: classMPLSLabelStack,
  91. Type: typeIncomingMPLSLabelStack,
  92. },
  93. },
  94. // MPLS label stack with a single label
  95. {
  96. proto: iana.ProtocolIPv6ICMP,
  97. typ: ipv6.ICMPTypeDestinationUnreachable,
  98. hdr: []byte{
  99. 0x20, 0x00, 0x00, 0x00,
  100. },
  101. obj: []byte{
  102. 0x00, 0x08, 0x01, 0x01,
  103. 0x03, 0xe8, 0xe9, 0xff,
  104. },
  105. ext: &MPLSLabelStack{
  106. Class: classMPLSLabelStack,
  107. Type: typeIncomingMPLSLabelStack,
  108. Labels: []MPLSLabel{
  109. {
  110. Label: 16014,
  111. TC: 0x4,
  112. S: true,
  113. TTL: 255,
  114. },
  115. },
  116. },
  117. },
  118. // MPLS label stack with multiple labels
  119. {
  120. proto: iana.ProtocolICMP,
  121. typ: ipv4.ICMPTypeDestinationUnreachable,
  122. hdr: []byte{
  123. 0x20, 0x00, 0x00, 0x00,
  124. },
  125. obj: []byte{
  126. 0x00, 0x0c, 0x01, 0x01,
  127. 0x03, 0xe8, 0xde, 0xfe,
  128. 0x03, 0xe8, 0xe1, 0xff,
  129. },
  130. ext: &MPLSLabelStack{
  131. Class: classMPLSLabelStack,
  132. Type: typeIncomingMPLSLabelStack,
  133. Labels: []MPLSLabel{
  134. {
  135. Label: 16013,
  136. TC: 0x7,
  137. S: false,
  138. TTL: 254,
  139. },
  140. {
  141. Label: 16014,
  142. TC: 0,
  143. S: true,
  144. TTL: 255,
  145. },
  146. },
  147. },
  148. },
  149. } {
  150. if err := fn(t, et.proto, et.typ, et.hdr, et.obj, et.ext); err != nil {
  151. t.Error(err)
  152. }
  153. }
  154. })
  155. t.Run("InterfaceInfo", func(t *testing.T) {
  156. for _, et := range []struct {
  157. proto int
  158. typ Type
  159. hdr []byte
  160. obj []byte
  161. ext Extension
  162. }{
  163. // Interface information with no attribute
  164. {
  165. proto: iana.ProtocolICMP,
  166. typ: ipv4.ICMPTypeDestinationUnreachable,
  167. hdr: []byte{
  168. 0x20, 0x00, 0x00, 0x00,
  169. },
  170. obj: []byte{
  171. 0x00, 0x04, 0x02, 0x00,
  172. },
  173. ext: &InterfaceInfo{
  174. Class: classInterfaceInfo,
  175. },
  176. },
  177. // Interface information with ifIndex and name
  178. {
  179. proto: iana.ProtocolICMP,
  180. typ: ipv4.ICMPTypeDestinationUnreachable,
  181. hdr: []byte{
  182. 0x20, 0x00, 0x00, 0x00,
  183. },
  184. obj: []byte{
  185. 0x00, 0x10, 0x02, 0x0a,
  186. 0x00, 0x00, 0x00, 0x10,
  187. 0x08, byte('e'), byte('n'), byte('1'),
  188. byte('0'), byte('1'), 0x00, 0x00,
  189. },
  190. ext: &InterfaceInfo{
  191. Class: classInterfaceInfo,
  192. Type: 0x0a,
  193. Interface: &net.Interface{
  194. Index: 16,
  195. Name: "en101",
  196. },
  197. },
  198. },
  199. // Interface information with ifIndex, IPAddr, name and MTU
  200. {
  201. proto: iana.ProtocolIPv6ICMP,
  202. typ: ipv6.ICMPTypeDestinationUnreachable,
  203. hdr: []byte{
  204. 0x20, 0x00, 0x00, 0x00,
  205. },
  206. obj: []byte{
  207. 0x00, 0x28, 0x02, 0x0f,
  208. 0x00, 0x00, 0x00, 0x0f,
  209. 0x00, 0x02, 0x00, 0x00,
  210. 0xfe, 0x80, 0x00, 0x00,
  211. 0x00, 0x00, 0x00, 0x00,
  212. 0x00, 0x00, 0x00, 0x00,
  213. 0x00, 0x00, 0x00, 0x01,
  214. 0x08, byte('e'), byte('n'), byte('1'),
  215. byte('0'), byte('1'), 0x00, 0x00,
  216. 0x00, 0x00, 0x20, 0x00,
  217. },
  218. ext: &InterfaceInfo{
  219. Class: classInterfaceInfo,
  220. Type: 0x0f,
  221. Interface: &net.Interface{
  222. Index: 15,
  223. Name: "en101",
  224. MTU: 8192,
  225. },
  226. Addr: &net.IPAddr{
  227. IP: net.ParseIP("fe80::1"),
  228. Zone: "en101",
  229. },
  230. },
  231. },
  232. } {
  233. if err := fn(t, et.proto, et.typ, et.hdr, et.obj, et.ext); err != nil {
  234. t.Error(err)
  235. }
  236. }
  237. })
  238. t.Run("InterfaceIdent", func(t *testing.T) {
  239. for _, et := range []struct {
  240. proto int
  241. typ Type
  242. hdr []byte
  243. obj []byte
  244. ext Extension
  245. }{
  246. // Interface identification by name
  247. {
  248. proto: iana.ProtocolICMP,
  249. typ: ipv4.ICMPTypeExtendedEchoRequest,
  250. hdr: []byte{
  251. 0x20, 0x00, 0x00, 0x00,
  252. },
  253. obj: []byte{
  254. 0x00, 0x0c, 0x03, 0x01,
  255. byte('e'), byte('n'), byte('1'), byte('0'),
  256. byte('1'), 0x00, 0x00, 0x00,
  257. },
  258. ext: &InterfaceIdent{
  259. Class: classInterfaceIdent,
  260. Type: typeInterfaceByName,
  261. Name: "en101",
  262. },
  263. },
  264. // Interface identification by index
  265. {
  266. proto: iana.ProtocolIPv6ICMP,
  267. typ: ipv6.ICMPTypeExtendedEchoRequest,
  268. hdr: []byte{
  269. 0x20, 0x00, 0x00, 0x00,
  270. },
  271. obj: []byte{
  272. 0x00, 0x08, 0x03, 0x02,
  273. 0x00, 0x00, 0x03, 0x8f,
  274. },
  275. ext: &InterfaceIdent{
  276. Class: classInterfaceIdent,
  277. Type: typeInterfaceByIndex,
  278. Index: 911,
  279. },
  280. },
  281. // Interface identification by address
  282. {
  283. proto: iana.ProtocolICMP,
  284. typ: ipv4.ICMPTypeExtendedEchoRequest,
  285. hdr: []byte{
  286. 0x20, 0x00, 0x00, 0x00,
  287. },
  288. obj: []byte{
  289. 0x00, 0x10, 0x03, 0x03,
  290. byte(iana.AddrFamily48bitMAC >> 8), byte(iana.AddrFamily48bitMAC & 0x0f), 0x06, 0x00,
  291. 0x01, 0x23, 0x45, 0x67,
  292. 0x89, 0xab, 0x00, 0x00,
  293. },
  294. ext: &InterfaceIdent{
  295. Class: classInterfaceIdent,
  296. Type: typeInterfaceByAddress,
  297. AFI: iana.AddrFamily48bitMAC,
  298. Addr: []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab},
  299. },
  300. },
  301. } {
  302. if err := fn(t, et.proto, et.typ, et.hdr, et.obj, et.ext); err != nil {
  303. t.Error(err)
  304. }
  305. }
  306. })
  307. }
  308. func TestParseInterfaceName(t *testing.T) {
  309. ifi := InterfaceInfo{Interface: &net.Interface{}}
  310. for i, tt := range []struct {
  311. b []byte
  312. error
  313. }{
  314. {[]byte{0, 'e', 'n', '0'}, errInvalidExtension},
  315. {[]byte{4, 'e', 'n', '0'}, nil},
  316. {[]byte{7, 'e', 'n', '0', 0xff, 0xff, 0xff, 0xff}, errInvalidExtension},
  317. {[]byte{8, 'e', 'n', '0', 0xff, 0xff, 0xff}, errMessageTooShort},
  318. } {
  319. if _, err := ifi.parseName(tt.b); err != tt.error {
  320. t.Errorf("#%d: got %v; want %v", i, err, tt.error)
  321. }
  322. }
  323. }