messages.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package icmp6
  15. import (
  16. "fmt"
  17. "net"
  18. "github.com/google/gopacket"
  19. "github.com/google/gopacket/layers"
  20. "yunion.io/x/pkg/errors"
  21. )
  22. type TPreference int
  23. const (
  24. PreferenceLow TPreference = 0
  25. PreferenceMedium TPreference = 1
  26. PreferenceHigh TPreference = 2
  27. )
  28. func (pref TPreference) String() string {
  29. switch pref {
  30. case PreferenceLow:
  31. return "low"
  32. case PreferenceMedium:
  33. return "medium"
  34. case PreferenceHigh:
  35. return "high"
  36. }
  37. return "unknown"
  38. }
  39. type SBaseICMP6Message struct {
  40. SrcMac net.HardwareAddr
  41. SrcIP net.IP
  42. DstMac net.HardwareAddr
  43. DstIP net.IP
  44. Vlan uint16
  45. }
  46. func (msg SBaseICMP6Message) String() string {
  47. var vlanStr string
  48. if msg.Vlan > 1 {
  49. vlanStr += fmt.Sprintf("(vlan %d)", msg.Vlan)
  50. }
  51. return fmt.Sprintf("%s[%s]->%s[%s]%s", msg.SrcIP.String(), msg.SrcMac.String(), msg.DstIP.String(), msg.DstMac.String(), vlanStr)
  52. }
  53. type IICMP6Message interface {
  54. fmt.Stringer
  55. Payload() gopacket.SerializableLayer
  56. ICMP6TypeCode() layers.ICMPv6TypeCode
  57. SourceMac() net.HardwareAddr
  58. SourceIP() net.IP
  59. DestinationMac() net.HardwareAddr
  60. DestinationIP() net.IP
  61. VlanId() uint16
  62. }
  63. func (msg SBaseICMP6Message) SourceIP() net.IP {
  64. return msg.SrcIP
  65. }
  66. func (msg SBaseICMP6Message) SourceMac() net.HardwareAddr {
  67. return msg.SrcMac
  68. }
  69. func (msg SBaseICMP6Message) DestinationIP() net.IP {
  70. return msg.DstIP
  71. }
  72. func (msg SBaseICMP6Message) DestinationMac() net.HardwareAddr {
  73. return msg.DstMac
  74. }
  75. func (msg SBaseICMP6Message) VlanId() uint16 {
  76. return msg.Vlan
  77. }
  78. type SRouterSolicitation struct {
  79. SBaseICMP6Message
  80. }
  81. type SPrefixInfoOption struct {
  82. IsOnlink bool
  83. IsAutoconf bool
  84. Prefix net.IP
  85. PrefixLen uint8
  86. ValidLifetime uint32
  87. PreferredLifetime uint32
  88. }
  89. func (opt SPrefixInfoOption) String() string {
  90. return fmt.Sprintf("%s/%d (IsOnlink: %t, IsAutoconf: %t) ValidLifetime: %d, PreferredLifetime: %d", opt.Prefix.String(), opt.PrefixLen, opt.IsOnlink, opt.IsAutoconf, opt.ValidLifetime, opt.PreferredLifetime)
  91. }
  92. type SRouteInfoOption struct {
  93. RouteLifetime uint32
  94. Prefix net.IP
  95. PrefixLen uint8
  96. Preference TPreference
  97. }
  98. func (opt SRouteInfoOption) String() string {
  99. return fmt.Sprintf("%s/%d (Pref: %s) RouteLifetime: %d", opt.Prefix.String(), opt.PrefixLen, opt.Preference.String(), opt.RouteLifetime)
  100. }
  101. type SRouterAdvertisement struct {
  102. SBaseICMP6Message
  103. CurHopLimit uint8
  104. IsManaged bool
  105. IsOther bool
  106. IsHomeAgent bool
  107. Preference TPreference
  108. RouterLifetime uint16
  109. ReachableTime uint32
  110. RetransTimer uint32
  111. MTU uint32
  112. PrefixInfo []SPrefixInfoOption
  113. RouteInfo []SRouteInfoOption
  114. }
  115. type SNeighborSolicitation struct {
  116. SBaseICMP6Message
  117. /*
  118. The IP address of the target of the solicitation.
  119. It MUST NOT be a multicast address.
  120. */
  121. TargetAddr net.IP
  122. }
  123. type SNeighborAdvertisement struct {
  124. SBaseICMP6Message
  125. /*
  126. For solicited advertisements, the Target Address
  127. field in the Neighbor Solicitation message that
  128. prompted this advertisement. For an unsolicited
  129. advertisement, the address whose link-layer address
  130. has changed. The Target Address MUST NOT be a
  131. multicast address.
  132. */
  133. TargetAddr net.IP
  134. IsRouter bool
  135. IsSolicited bool
  136. }
  137. func (msg SNeighborSolicitation) ICMP6TypeCode() layers.ICMPv6TypeCode {
  138. return layers.CreateICMPv6TypeCode(layers.ICMPv6TypeNeighborSolicitation, 0)
  139. }
  140. func (msg SNeighborSolicitation) Payload() gopacket.SerializableLayer {
  141. pkt := layers.ICMPv6NeighborSolicitation{}
  142. pkt.TargetAddress = msg.TargetAddr
  143. pkt.Options = layers.ICMPv6Options{
  144. layers.ICMPv6Option{
  145. Type: layers.ICMPv6OptSourceAddress,
  146. Data: NewIcmpv6OptSourceTargetAddress(msg.SrcMac).Bytes(),
  147. },
  148. }
  149. return &pkt
  150. }
  151. func (msg *SNeighborSolicitation) Unmarshal(data *layers.ICMPv6NeighborSolicitation) error {
  152. msg.TargetAddr = data.TargetAddress
  153. return nil
  154. }
  155. func (msg SNeighborSolicitation) String() string {
  156. return fmt.Sprintf("NeighborSolicitation %s target %s", msg.SBaseICMP6Message.String(), msg.TargetAddr.String())
  157. }
  158. func (msg SNeighborAdvertisement) ICMP6TypeCode() layers.ICMPv6TypeCode {
  159. return layers.CreateICMPv6TypeCode(layers.ICMPv6TypeNeighborAdvertisement, 0)
  160. }
  161. func (msg SNeighborAdvertisement) Payload() gopacket.SerializableLayer {
  162. pkt := layers.ICMPv6NeighborAdvertisement{}
  163. pkt.TargetAddress = msg.TargetAddr
  164. pkt.Flags = 0x00
  165. if msg.IsRouter {
  166. pkt.Flags |= 0x80
  167. }
  168. if msg.IsSolicited {
  169. pkt.Flags |= 0x40
  170. }
  171. pkt.Options = layers.ICMPv6Options{
  172. layers.ICMPv6Option{
  173. Type: layers.ICMPv6OptSourceAddress,
  174. Data: NewIcmpv6OptSourceTargetAddress(msg.SrcMac).Bytes(),
  175. },
  176. }
  177. return &pkt
  178. }
  179. func (msg *SNeighborAdvertisement) Unmarshal(data *layers.ICMPv6NeighborAdvertisement) error {
  180. msg.TargetAddr = data.TargetAddress
  181. msg.IsRouter = data.Flags&0x80 != 0
  182. msg.IsSolicited = data.Flags&0x40 != 0
  183. return nil
  184. }
  185. func (msg SNeighborAdvertisement) String() string {
  186. return fmt.Sprintf("NeighborAdvertisement %s target %s", msg.SBaseICMP6Message.String(), msg.TargetAddr.String())
  187. }
  188. func (msg SRouterSolicitation) ICMP6TypeCode() layers.ICMPv6TypeCode {
  189. return layers.CreateICMPv6TypeCode(layers.ICMPv6TypeRouterSolicitation, 0)
  190. }
  191. func (msg SRouterSolicitation) Payload() gopacket.SerializableLayer {
  192. pkt := layers.ICMPv6RouterSolicitation{}
  193. pkt.Options = layers.ICMPv6Options{
  194. layers.ICMPv6Option{
  195. Type: layers.ICMPv6OptSourceAddress,
  196. Data: NewIcmpv6OptSourceTargetAddress(msg.SrcMac).Bytes(),
  197. },
  198. }
  199. return &pkt
  200. }
  201. func (msg *SRouterSolicitation) Unmarshal(data *layers.ICMPv6RouterSolicitation) error {
  202. return nil
  203. }
  204. func (msg SRouterSolicitation) String() string {
  205. return fmt.Sprintf("RouterSolicitation %s", msg.SBaseICMP6Message.String())
  206. }
  207. func (msg SRouterAdvertisement) ICMP6TypeCode() layers.ICMPv6TypeCode {
  208. return layers.CreateICMPv6TypeCode(layers.ICMPv6TypeRouterAdvertisement, 0)
  209. }
  210. func (msg SRouterAdvertisement) Payload() gopacket.SerializableLayer {
  211. pkt := layers.ICMPv6RouterAdvertisement{}
  212. // https://datatracker.ietf.org/doc/html/rfc4861#section-4.2
  213. // https://datatracker.ietf.org/doc/html/rfc4191
  214. pkt.Flags = 0x00 // M=1, O=1, stateful DHCPv6, pref=00
  215. if msg.IsManaged {
  216. pkt.Flags |= 0x80
  217. }
  218. if msg.IsOther {
  219. pkt.Flags |= 0x40
  220. }
  221. if msg.IsHomeAgent {
  222. pkt.Flags |= 0x20
  223. }
  224. switch msg.Preference {
  225. case PreferenceLow:
  226. pkt.Flags |= 0x18
  227. case PreferenceMedium:
  228. // do nothing
  229. case PreferenceHigh:
  230. pkt.Flags |= 0x08
  231. }
  232. pkt.HopLimit = msg.CurHopLimit
  233. pkt.RouterLifetime = msg.RouterLifetime
  234. pkt.ReachableTime = msg.ReachableTime
  235. pkt.RetransTimer = msg.RetransTimer
  236. pkt.Options = layers.ICMPv6Options{}
  237. for i := range msg.PrefixInfo {
  238. pref := msg.PrefixInfo[i]
  239. pkt.Options = append(pkt.Options, layers.ICMPv6Option{
  240. Type: layers.ICMPv6OptPrefixInfo,
  241. Data: NewIcmpv6OptPrefixInfo(pref).Bytes(),
  242. })
  243. }
  244. for i := range msg.RouteInfo {
  245. rt := msg.RouteInfo[i]
  246. pkt.Options = append(pkt.Options, layers.ICMPv6Option{
  247. Type: 24,
  248. Data: NewIcmpv6OptRouteInfo(rt).Bytes(),
  249. })
  250. }
  251. if msg.MTU > 0 {
  252. pkt.Options = append(pkt.Options, layers.ICMPv6Option{
  253. Type: layers.ICMPv6OptMTU,
  254. Data: NewIcmpV6OptMtu(msg.MTU).Bytes(),
  255. })
  256. }
  257. pkt.Options = append(pkt.Options, layers.ICMPv6Option{
  258. Type: layers.ICMPv6OptSourceAddress,
  259. Data: NewIcmpv6OptSourceTargetAddress(msg.SrcMac).Bytes(),
  260. })
  261. return &pkt
  262. }
  263. func (msg *SRouterAdvertisement) Unmarshal(data *layers.ICMPv6RouterAdvertisement) error {
  264. msg.CurHopLimit = data.HopLimit
  265. msg.IsManaged = data.Flags&0x80 != 0
  266. msg.IsOther = data.Flags&0x40 != 0
  267. msg.IsHomeAgent = data.Flags&0x20 != 0
  268. switch data.Flags & 0x18 {
  269. case 0x18:
  270. msg.Preference = PreferenceLow
  271. case 0x08:
  272. msg.Preference = PreferenceHigh
  273. default:
  274. msg.Preference = PreferenceMedium
  275. }
  276. msg.RouterLifetime = data.RouterLifetime
  277. for i := range data.Options {
  278. opt := data.Options[i]
  279. switch opt.Type {
  280. case layers.ICMPv6OptMTU:
  281. msg.MTU = DecodeIcmpV6OptMtu(opt.Data)
  282. case layers.ICMPv6OptPrefixInfo:
  283. prefix := DecodeIcmpv6OptPrefixInfo(opt.Data)
  284. msg.PrefixInfo = append(msg.PrefixInfo, prefix)
  285. case 24:
  286. route := DecodeIcmpv6OptRouteInfo(opt.Data)
  287. msg.RouteInfo = append(msg.RouteInfo, route)
  288. }
  289. }
  290. return nil
  291. }
  292. func (msg SRouterAdvertisement) String() string {
  293. return fmt.Sprintf(`RouterAdvertisement %s
  294. CurHopLimit: %d, IsManaged: %t, IsOther: %t, IsHomeAgent: %t, Preference: %s, RouterLifetime: %d, ReachableTime: %d, RetransTimer: %d
  295. MTU: %d
  296. PrefixInfo: %v
  297. RouteInfo: %v)`,
  298. msg.SBaseICMP6Message.String(),
  299. msg.CurHopLimit, msg.IsManaged, msg.IsOther, msg.IsHomeAgent, msg.Preference.String(), msg.RouterLifetime, msg.ReachableTime, msg.RetransTimer,
  300. msg.MTU, msg.PrefixInfo, msg.RouteInfo)
  301. }
  302. func EncodePacket(msg IICMP6Message) ([]byte, error) {
  303. var pktLayers []gopacket.SerializableLayer
  304. var eth = &layers.Ethernet{
  305. EthernetType: layers.EthernetTypeIPv6,
  306. SrcMAC: msg.SourceMac(),
  307. DstMAC: msg.DestinationMac(),
  308. }
  309. pktLayers = append(pktLayers, eth)
  310. if msg.VlanId() > 1 {
  311. eth.EthernetType = layers.EthernetTypeDot1Q
  312. dot1Q := &layers.Dot1Q{
  313. VLANIdentifier: msg.VlanId(),
  314. Priority: 6,
  315. Type: layers.EthernetTypeIPv6,
  316. }
  317. pktLayers = append(pktLayers, dot1Q)
  318. }
  319. var ip = &layers.IPv6{
  320. Version: 6,
  321. HopLimit: 0xff,
  322. TrafficClass: 0xc0,
  323. SrcIP: msg.SourceIP(),
  324. DstIP: msg.DestinationIP(),
  325. NextHeader: layers.IPProtocolICMPv6,
  326. }
  327. pktLayers = append(pktLayers, ip)
  328. var icmp6 = &layers.ICMPv6{
  329. TypeCode: msg.ICMP6TypeCode(),
  330. }
  331. icmp6.SetNetworkLayerForChecksum(ip)
  332. pktLayers = append(pktLayers, icmp6)
  333. pktLayers = append(pktLayers, msg.Payload())
  334. var (
  335. buf = gopacket.NewSerializeBuffer()
  336. opts = gopacket.SerializeOptions{ComputeChecksums: true, FixLengths: true}
  337. )
  338. if err := gopacket.SerializeLayers(buf, opts, pktLayers...); err != nil {
  339. return nil, errors.Wrap(err, "SerializeLayers error")
  340. }
  341. return buf.Bytes(), nil
  342. }
  343. func DecodePacket(data []byte) (IICMP6Message, error) {
  344. packet := gopacket.NewPacket(data, layers.LayerTypeEthernet, gopacket.Default)
  345. if packet.ErrorLayer() != nil {
  346. return nil, errors.Wrap(packet.ErrorLayer().Error(), "DecodePacket error")
  347. }
  348. var baseMsg SBaseICMP6Message
  349. {
  350. ethLayer := packet.Layer(layers.LayerTypeEthernet)
  351. if ethLayer != nil {
  352. eth := ethLayer.(*layers.Ethernet)
  353. baseMsg.SrcMac = eth.SrcMAC
  354. baseMsg.DstMac = eth.DstMAC
  355. } else {
  356. return nil, errors.Wrap(packet.ErrorLayer().Error(), "Expect Ethernet layer")
  357. }
  358. }
  359. {
  360. // optional vlan layer
  361. dot1qLayer := packet.Layer(layers.LayerTypeDot1Q)
  362. if dot1qLayer != nil {
  363. dot1q := dot1qLayer.(*layers.Dot1Q)
  364. baseMsg.Vlan = dot1q.VLANIdentifier
  365. }
  366. }
  367. {
  368. ipLayer := packet.Layer(layers.LayerTypeIPv6)
  369. if ipLayer != nil {
  370. // ipv6
  371. ip6 := ipLayer.(*layers.IPv6)
  372. baseMsg.SrcIP = ip6.SrcIP
  373. baseMsg.DstIP = ip6.DstIP
  374. } else {
  375. return nil, errors.Wrap(packet.ErrorLayer().Error(), "Expect IPv6 packet")
  376. }
  377. }
  378. {
  379. icmpLayer := packet.Layer(layers.LayerTypeICMPv6)
  380. if icmpLayer != nil {
  381. icmp6 := icmpLayer.(*layers.ICMPv6)
  382. if icmp6 == nil {
  383. return nil, errors.Wrap(packet.ErrorLayer().Error(), "Expect IPv6 packet")
  384. }
  385. switch icmp6.TypeCode.Type() {
  386. case 133:
  387. payload := packet.Layer(layers.LayerTypeICMPv6RouterSolicitation)
  388. if payload != nil {
  389. msg := &SRouterSolicitation{
  390. SBaseICMP6Message: baseMsg,
  391. }
  392. err := msg.Unmarshal(payload.(*layers.ICMPv6RouterSolicitation))
  393. if err != nil {
  394. return nil, errors.Wrap(err, "Unmarshal Router Solicitation packet")
  395. }
  396. return msg, nil
  397. } else {
  398. return nil, errors.Wrap(packet.ErrorLayer().Error(), "Expect ICMPv6 Router Solicitation packet")
  399. }
  400. case 134:
  401. payload := packet.Layer(layers.LayerTypeICMPv6RouterAdvertisement)
  402. if payload != nil {
  403. msg := &SRouterAdvertisement{
  404. SBaseICMP6Message: baseMsg,
  405. }
  406. err := msg.Unmarshal(payload.(*layers.ICMPv6RouterAdvertisement))
  407. if err != nil {
  408. return nil, errors.Wrap(err, "Unmarshal Router Advertisement packet")
  409. }
  410. return msg, nil
  411. } else {
  412. return nil, errors.Wrap(packet.ErrorLayer().Error(), "Expect ICMPv6 Router Advertisement packet")
  413. }
  414. case 135:
  415. payload := packet.Layer(layers.LayerTypeICMPv6NeighborSolicitation)
  416. if payload != nil {
  417. msg := &SNeighborSolicitation{
  418. SBaseICMP6Message: baseMsg,
  419. }
  420. err := msg.Unmarshal(payload.(*layers.ICMPv6NeighborSolicitation))
  421. if err != nil {
  422. return nil, errors.Wrap(err, "Unmarshal Neighbor Solicitation packet")
  423. }
  424. return msg, nil
  425. } else {
  426. return nil, errors.Wrap(packet.ErrorLayer().Error(), "Expect ICMPv6 Neighbor Solicitation packet")
  427. }
  428. case 136:
  429. payload := packet.Layer(layers.LayerTypeICMPv6NeighborAdvertisement)
  430. if payload != nil {
  431. msg := &SNeighborAdvertisement{
  432. SBaseICMP6Message: baseMsg,
  433. }
  434. err := msg.Unmarshal(payload.(*layers.ICMPv6NeighborAdvertisement))
  435. if err != nil {
  436. return nil, errors.Wrap(err, "Unmarshal Neighbor Advertisement packet")
  437. }
  438. return msg, nil
  439. } else {
  440. return nil, errors.Wrap(packet.ErrorLayer().Error(), "Expect ICMPv6 Neighbor Advertisement packet")
  441. }
  442. default:
  443. return nil, errors.Wrap(packet.ErrorLayer().Error(), "Expect ICMPv6 packet")
  444. }
  445. } else {
  446. return nil, errors.Wrap(packet.ErrorLayer().Error(), "Expect IPv6 packet")
  447. }
  448. }
  449. }