route.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626
  1. package rtnetlink
  2. import (
  3. "encoding/binary"
  4. "errors"
  5. "fmt"
  6. "net"
  7. "unsafe"
  8. "github.com/jsimonetti/rtnetlink/internal/unix"
  9. "github.com/mdlayher/netlink"
  10. )
  11. var (
  12. // errInvalidRouteMessage is returned when a RouteMessage is malformed.
  13. errInvalidRouteMessage = errors.New("rtnetlink RouteMessage is invalid or too short")
  14. // errInvalidRouteMessageAttr is returned when link attributes are malformed.
  15. errInvalidRouteMessageAttr = errors.New("rtnetlink RouteMessage has a wrong attribute data length")
  16. )
  17. var _ Message = &RouteMessage{}
  18. type RouteMessage struct {
  19. Family uint8 // Address family (current unix.AF_INET or unix.AF_INET6)
  20. DstLength uint8 // Length of destination prefix
  21. SrcLength uint8 // Length of source prefix
  22. Tos uint8 // TOS filter
  23. Table uint8 // Routing table ID
  24. Protocol uint8 // Routing protocol
  25. Scope uint8 // Distance to the destination
  26. Type uint8 // Route type
  27. Flags uint32
  28. Attributes RouteAttributes
  29. }
  30. func (m *RouteMessage) MarshalBinary() ([]byte, error) {
  31. b := make([]byte, unix.SizeofRtMsg)
  32. b[0] = m.Family
  33. b[1] = m.DstLength
  34. b[2] = m.SrcLength
  35. b[3] = m.Tos
  36. b[4] = m.Table
  37. b[5] = m.Protocol
  38. b[6] = m.Scope
  39. b[7] = m.Type
  40. nativeEndian.PutUint32(b[8:12], m.Flags)
  41. ae := netlink.NewAttributeEncoder()
  42. err := m.Attributes.encode(ae)
  43. if err != nil {
  44. return nil, err
  45. }
  46. a, err := ae.Encode()
  47. if err != nil {
  48. return nil, err
  49. }
  50. return append(b, a...), nil
  51. }
  52. func (m *RouteMessage) UnmarshalBinary(b []byte) error {
  53. l := len(b)
  54. if l < unix.SizeofRtMsg {
  55. return errInvalidRouteMessage
  56. }
  57. m.Family = uint8(b[0])
  58. m.DstLength = uint8(b[1])
  59. m.SrcLength = uint8(b[2])
  60. m.Tos = uint8(b[3])
  61. m.Table = uint8(b[4])
  62. m.Protocol = uint8(b[5])
  63. m.Scope = uint8(b[6])
  64. m.Type = uint8(b[7])
  65. m.Flags = nativeEndian.Uint32(b[8:12])
  66. if l > unix.SizeofRtMsg {
  67. ad, err := netlink.NewAttributeDecoder(b[unix.SizeofRtMsg:])
  68. if err != nil {
  69. return err
  70. }
  71. var ra RouteAttributes
  72. if err := ra.decode(ad); err != nil {
  73. return err
  74. }
  75. // Must consume errors from decoder before returning.
  76. if err := ad.Err(); err != nil {
  77. return fmt.Errorf("invalid route message attributes: %v", err)
  78. }
  79. m.Attributes = ra
  80. }
  81. return nil
  82. }
  83. // rtMessage is an empty method to sattisfy the Message interface.
  84. func (*RouteMessage) rtMessage() {}
  85. type RouteService struct {
  86. c *Conn
  87. }
  88. func (r *RouteService) execute(m Message, family uint16, flags netlink.HeaderFlags) ([]RouteMessage, error) {
  89. msgs, err := r.c.Execute(m, family, flags)
  90. routes := make([]RouteMessage, len(msgs))
  91. for i := range msgs {
  92. routes[i] = *msgs[i].(*RouteMessage)
  93. }
  94. return routes, err
  95. }
  96. // Add new route
  97. func (r *RouteService) Add(req *RouteMessage) error {
  98. flags := netlink.Request | netlink.Create | netlink.Acknowledge | netlink.Excl
  99. _, err := r.c.Execute(req, unix.RTM_NEWROUTE, flags)
  100. return err
  101. }
  102. // Replace or add new route
  103. func (r *RouteService) Replace(req *RouteMessage) error {
  104. flags := netlink.Request | netlink.Create | netlink.Replace | netlink.Acknowledge
  105. _, err := r.c.Execute(req, unix.RTM_NEWROUTE, flags)
  106. return err
  107. }
  108. // Delete existing route
  109. func (r *RouteService) Delete(req *RouteMessage) error {
  110. flags := netlink.Request | netlink.Acknowledge
  111. _, err := r.c.Execute(req, unix.RTM_DELROUTE, flags)
  112. return err
  113. }
  114. // Get Route(s)
  115. func (r *RouteService) Get(req *RouteMessage) ([]RouteMessage, error) {
  116. flags := netlink.Request | netlink.DumpFiltered
  117. return r.execute(req, unix.RTM_GETROUTE, flags)
  118. }
  119. // List all routes
  120. func (r *RouteService) List() ([]RouteMessage, error) {
  121. flags := netlink.Request | netlink.Dump
  122. return r.execute(&RouteMessage{}, unix.RTM_GETROUTE, flags)
  123. }
  124. type RouteAttributes struct {
  125. Dst net.IP
  126. Src net.IP
  127. Gateway net.IP
  128. OutIface uint32
  129. Priority uint32
  130. Table uint32
  131. Mark uint32
  132. Pref *uint8
  133. Expires *uint32
  134. Metrics *RouteMetrics
  135. Multipath []NextHop
  136. }
  137. func (a *RouteAttributes) decode(ad *netlink.AttributeDecoder) error {
  138. for ad.Next() {
  139. switch ad.Type() {
  140. case unix.RTA_UNSPEC:
  141. // unused attribute
  142. case unix.RTA_DST:
  143. ad.Do(decodeIP(&a.Dst))
  144. case unix.RTA_PREFSRC:
  145. ad.Do(decodeIP(&a.Src))
  146. case unix.RTA_GATEWAY:
  147. ad.Do(decodeIP(&a.Gateway))
  148. case unix.RTA_OIF:
  149. a.OutIface = ad.Uint32()
  150. case unix.RTA_PRIORITY:
  151. a.Priority = ad.Uint32()
  152. case unix.RTA_TABLE:
  153. a.Table = ad.Uint32()
  154. case unix.RTA_MARK:
  155. a.Mark = ad.Uint32()
  156. case unix.RTA_EXPIRES:
  157. timeout := ad.Uint32()
  158. a.Expires = &timeout
  159. case unix.RTA_METRICS:
  160. a.Metrics = &RouteMetrics{}
  161. ad.Nested(a.Metrics.decode)
  162. case unix.RTA_MULTIPATH:
  163. ad.Do(a.parseMultipath)
  164. case unix.RTA_PREF:
  165. pref := ad.Uint8()
  166. a.Pref = &pref
  167. }
  168. }
  169. return nil
  170. }
  171. func (a *RouteAttributes) encode(ae *netlink.AttributeEncoder) error {
  172. if a.Dst != nil {
  173. ae.Do(unix.RTA_DST, encodeIP(a.Dst))
  174. }
  175. if a.Src != nil {
  176. ae.Do(unix.RTA_PREFSRC, encodeIP(a.Src))
  177. }
  178. if a.Gateway != nil {
  179. ae.Do(unix.RTA_GATEWAY, encodeIP(a.Gateway))
  180. }
  181. if a.OutIface != 0 {
  182. ae.Uint32(unix.RTA_OIF, a.OutIface)
  183. }
  184. if a.Priority != 0 {
  185. ae.Uint32(unix.RTA_PRIORITY, a.Priority)
  186. }
  187. if a.Table != 0 {
  188. ae.Uint32(unix.RTA_TABLE, a.Table)
  189. }
  190. if a.Mark != 0 {
  191. ae.Uint32(unix.RTA_MARK, a.Mark)
  192. }
  193. if a.Pref != nil {
  194. ae.Uint8(unix.RTA_PREF, *a.Pref)
  195. }
  196. if a.Expires != nil {
  197. ae.Uint32(unix.RTA_EXPIRES, *a.Expires)
  198. }
  199. if a.Metrics != nil {
  200. ae.Nested(unix.RTA_METRICS, a.Metrics.encode)
  201. }
  202. if len(a.Multipath) > 0 {
  203. ae.Do(unix.RTA_MULTIPATH, a.encodeMultipath)
  204. }
  205. return nil
  206. }
  207. // RouteMetrics holds some advanced metrics for a route
  208. type RouteMetrics struct {
  209. AdvMSS uint32
  210. Features uint32
  211. InitCwnd uint32
  212. InitRwnd uint32
  213. MTU uint32
  214. }
  215. func (rm *RouteMetrics) decode(ad *netlink.AttributeDecoder) error {
  216. for ad.Next() {
  217. switch ad.Type() {
  218. case unix.RTAX_ADVMSS:
  219. rm.AdvMSS = ad.Uint32()
  220. case unix.RTAX_FEATURES:
  221. rm.Features = ad.Uint32()
  222. case unix.RTAX_INITCWND:
  223. rm.InitCwnd = ad.Uint32()
  224. case unix.RTAX_INITRWND:
  225. rm.InitRwnd = ad.Uint32()
  226. case unix.RTAX_MTU:
  227. rm.MTU = ad.Uint32()
  228. }
  229. }
  230. // ad.Err call handled by Nested method in calling attribute decoder.
  231. return nil
  232. }
  233. func (rm *RouteMetrics) encode(ae *netlink.AttributeEncoder) error {
  234. if rm.AdvMSS != 0 {
  235. ae.Uint32(unix.RTAX_ADVMSS, rm.AdvMSS)
  236. }
  237. if rm.Features != 0 {
  238. ae.Uint32(unix.RTAX_FEATURES, rm.Features)
  239. }
  240. if rm.InitCwnd != 0 {
  241. ae.Uint32(unix.RTAX_INITCWND, rm.InitCwnd)
  242. }
  243. if rm.InitRwnd != 0 {
  244. ae.Uint32(unix.RTAX_INITRWND, rm.InitRwnd)
  245. }
  246. if rm.MTU != 0 {
  247. ae.Uint32(unix.RTAX_MTU, rm.MTU)
  248. }
  249. return nil
  250. }
  251. // TODO(mdlayher): probably eliminate Length field from the API to avoid the
  252. // caller possibly tampering with it since we can compute it.
  253. // RTNextHop represents the netlink rtnexthop struct (not an attribute)
  254. type RTNextHop struct {
  255. Length uint16 // length of this hop including nested values
  256. Flags uint8 // flags defined in rtnetlink.h line 311
  257. Hops uint8
  258. IfIndex uint32 // the interface index number
  259. }
  260. // NextHop wraps struct rtnexthop to provide access to nested attributes
  261. type NextHop struct {
  262. Hop RTNextHop // a rtnexthop struct
  263. Gateway net.IP // that struct's nested Gateway attribute
  264. MPLS []MPLSNextHop // Any MPLS next hops for a route.
  265. }
  266. func (a *RouteAttributes) encodeMultipath() ([]byte, error) {
  267. var b []byte
  268. for _, nh := range a.Multipath {
  269. // Encode the attributes first so their total length can be used to
  270. // compute the length of each (rtnexthop, attributes) pair.
  271. ae := netlink.NewAttributeEncoder()
  272. if nh.Gateway != nil {
  273. ae.Do(unix.RTA_GATEWAY, encodeIP(nh.Gateway))
  274. }
  275. if len(nh.MPLS) > 0 {
  276. // TODO(mdlayher): validation over different encapsulation types,
  277. // and ensure that only one can be set.
  278. ae.Uint16(unix.RTA_ENCAP_TYPE, unix.LWTUNNEL_ENCAP_MPLS)
  279. ae.Nested(unix.RTA_ENCAP, nh.encodeEncap)
  280. }
  281. ab, err := ae.Encode()
  282. if err != nil {
  283. return nil, err
  284. }
  285. // Assume the caller wants the length updated so they don't have to
  286. // keep track of it themselves when encoding attributes.
  287. nh.Hop.Length = unix.SizeofRtNexthop + uint16(len(ab))
  288. var nhb [unix.SizeofRtNexthop]byte
  289. copy(
  290. nhb[:],
  291. (*(*[unix.SizeofRtNexthop]byte)(unsafe.Pointer(&nh.Hop)))[:],
  292. )
  293. // rtnexthop first, then attributes.
  294. b = append(b, nhb[:]...)
  295. b = append(b, ab...)
  296. }
  297. return b, nil
  298. }
  299. // parseMultipath consumes RTA_MULTIPATH data into RouteAttributes.
  300. func (a *RouteAttributes) parseMultipath(b []byte) error {
  301. // We cannot retain b after the function returns, so make a copy of the
  302. // bytes up front for the multipathParser.
  303. buf := make([]byte, len(b))
  304. copy(buf, b)
  305. // Iterate until no more bytes remain in the buffer or an error occurs.
  306. mpp := &multipathParser{b: buf}
  307. for mpp.Next() {
  308. // Each iteration reads a fixed length RTNextHop structure immediately
  309. // followed by its associated netlink attributes with optional data.
  310. nh := NextHop{Hop: mpp.RTNextHop()}
  311. if err := nh.decode(mpp.AttributeDecoder()); err != nil {
  312. return err
  313. }
  314. // Stop iteration early if the data was malformed, or otherwise append
  315. // this NextHop to the Multipath field.
  316. if err := mpp.Err(); err != nil {
  317. return err
  318. }
  319. a.Multipath = append(a.Multipath, nh)
  320. }
  321. // Check the error when Next returns false.
  322. return mpp.Err()
  323. }
  324. // decode decodes netlink attribute values into a NextHop.
  325. func (nh *NextHop) decode(ad *netlink.AttributeDecoder) error {
  326. if ad == nil {
  327. // Invalid decoder, do nothing.
  328. return nil
  329. }
  330. // If encapsulation is present, we won't know how to deal with it until we
  331. // identify the right type and then later parse the nested attribute bytes.
  332. var (
  333. encapType uint16
  334. encapBuf []byte
  335. )
  336. for ad.Next() {
  337. switch ad.Type() {
  338. case unix.RTA_ENCAP:
  339. encapBuf = ad.Bytes()
  340. case unix.RTA_ENCAP_TYPE:
  341. encapType = ad.Uint16()
  342. case unix.RTA_GATEWAY:
  343. ad.Do(decodeIP(&nh.Gateway))
  344. }
  345. }
  346. if err := ad.Err(); err != nil {
  347. return err
  348. }
  349. if encapType != 0 && encapBuf != nil {
  350. // Found encapsulation, start decoding it from the buffer.
  351. return nh.decodeEncap(encapType, encapBuf)
  352. }
  353. return nil
  354. }
  355. // An MPLSNextHop is a route next hop using MPLS encapsulation.
  356. type MPLSNextHop struct {
  357. Label int
  358. TrafficClass int
  359. BottomOfStack bool
  360. TTL uint8
  361. }
  362. // TODO(mdlayher): MPLSNextHop TTL vs MPLS_IPTUNNEL_TTL. What's the difference?
  363. // encodeEncap encodes netlink attribute values related to encapsulation from
  364. // a NextHop.
  365. func (nh *NextHop) encodeEncap(ae *netlink.AttributeEncoder) error {
  366. // TODO: this only handles MPLS encapsulation as that is all we support.
  367. // Allocate enough space for an MPLS label stack.
  368. var (
  369. i int
  370. b = make([]byte, 4*len(nh.MPLS))
  371. )
  372. for _, mnh := range nh.MPLS {
  373. // Pack the following:
  374. // - label: 20 bits
  375. // - traffic class: 3 bits
  376. // - bottom-of-stack: 1 bit
  377. // - TTL: 8 bits
  378. binary.BigEndian.PutUint32(b[i:i+4], uint32(mnh.Label)<<12)
  379. b[i+2] |= byte(mnh.TrafficClass) << 1
  380. if mnh.BottomOfStack {
  381. b[i+2] |= 1
  382. }
  383. b[i+3] = mnh.TTL
  384. // Advance in the buffer to begin storing the next label.
  385. i += 4
  386. }
  387. // Finally store the output bytes.
  388. ae.Bytes(unix.MPLS_IPTUNNEL_DST, b)
  389. return nil
  390. }
  391. // decodeEncap decodes netlink attribute values related to encapsulation into a
  392. // NextHop.
  393. func (nh *NextHop) decodeEncap(typ uint16, b []byte) error {
  394. if typ != unix.LWTUNNEL_ENCAP_MPLS {
  395. // TODO: handle other encapsulation types as needed.
  396. return nil
  397. }
  398. // MPLS labels are stored as big endian bytes.
  399. ad, err := netlink.NewAttributeDecoder(b)
  400. if err != nil {
  401. return err
  402. }
  403. for ad.Next() {
  404. switch ad.Type() {
  405. case unix.MPLS_IPTUNNEL_DST:
  406. // Every 4 bytes stores another MPLS label, so make sure the stored
  407. // bytes are divisible by exactly 4.
  408. b := ad.Bytes()
  409. if len(b)%4 != 0 {
  410. return errInvalidRouteMessageAttr
  411. }
  412. for i := 0; i < len(b); i += 4 {
  413. n := binary.BigEndian.Uint32(b[i : i+4])
  414. // For reference, see:
  415. // https://en.wikipedia.org/wiki/Multiprotocol_Label_Switching#Operation
  416. nh.MPLS = append(nh.MPLS, MPLSNextHop{
  417. Label: int(n) >> 12,
  418. TrafficClass: int(n & 0xe00 >> 9),
  419. BottomOfStack: n&0x100 != 0,
  420. TTL: uint8(n & 0xff),
  421. })
  422. }
  423. }
  424. }
  425. return ad.Err()
  426. }
  427. // A multipathParser parses packed RTNextHop and netlink attributes into
  428. // multipath attributes for an rtnetlink route.
  429. type multipathParser struct {
  430. // Any errors which occurred during parsing.
  431. err error
  432. // The underlying buffer and a pointer to the reading position.
  433. b []byte
  434. i int
  435. // The length of the next set of netlink attributes.
  436. alen int
  437. }
  438. // Next continues iteration until an error occurs or no bytes remain.
  439. func (mpp *multipathParser) Next() bool {
  440. if mpp.err != nil {
  441. return false
  442. }
  443. // Are there enough bytes left for another RTNextHop, or 0 for EOF?
  444. n := len(mpp.b[mpp.i:])
  445. switch {
  446. case n == 0:
  447. // EOF.
  448. return false
  449. case n >= unix.SizeofRtNexthop:
  450. return true
  451. default:
  452. mpp.err = errInvalidRouteMessageAttr
  453. return false
  454. }
  455. }
  456. // Err returns any errors encountered while parsing.
  457. func (mpp *multipathParser) Err() error { return mpp.err }
  458. // RTNextHop parses the next RTNextHop structure from the buffer.
  459. func (mpp *multipathParser) RTNextHop() RTNextHop {
  460. if mpp.err != nil {
  461. return RTNextHop{}
  462. }
  463. if len(mpp.b)-mpp.i < unix.SizeofRtNexthop {
  464. // Out of bounds access, not enough data for a valid RTNextHop.
  465. mpp.err = errInvalidRouteMessageAttr
  466. return RTNextHop{}
  467. }
  468. // Consume an RTNextHop from the buffer by copying its bytes into an output
  469. // structure while also verifying that the size of each structure is equal
  470. // to avoid any out-of-bounds unsafe memory access.
  471. var rtnh RTNextHop
  472. next := mpp.b[mpp.i : mpp.i+unix.SizeofRtNexthop]
  473. if unix.SizeofRtNexthop != len(next) {
  474. panic("rtnetlink: invalid RTNextHop structure size, panicking to avoid out-of-bounds unsafe access")
  475. }
  476. copy(
  477. (*(*[unix.SizeofRtNexthop]byte)(unsafe.Pointer(&rtnh)))[:],
  478. (*(*[unix.SizeofRtNexthop]byte)(unsafe.Pointer(&next[0])))[:],
  479. )
  480. if rtnh.Length < unix.SizeofRtNexthop {
  481. // Length value is invalid.
  482. mpp.err = errInvalidRouteMessageAttr
  483. return RTNextHop{}
  484. }
  485. // Compute the length of the next set of attributes using the Length value
  486. // in the RTNextHop, minus the size of that fixed length structure itself.
  487. // Then, advance the pointer to be ready to read those attributes.
  488. mpp.alen = int(rtnh.Length) - unix.SizeofRtNexthop
  489. mpp.i += unix.SizeofRtNexthop
  490. return rtnh
  491. }
  492. // AttributeDecoder returns a netlink.AttributeDecoder pointed at the next set
  493. // of netlink attributes from the buffer.
  494. func (mpp *multipathParser) AttributeDecoder() *netlink.AttributeDecoder {
  495. if mpp.err != nil {
  496. return nil
  497. }
  498. // Ensure the attributes length value computed while parsing the rtnexthop
  499. // fits within the actual slice.
  500. if len(mpp.b[mpp.i:]) < mpp.alen {
  501. mpp.err = errInvalidRouteMessageAttr
  502. return nil
  503. }
  504. // Consume the next set of netlink attributes from the buffer and advance
  505. // the pointer to the next RTNextHop or EOF once that is complete.
  506. ad, err := netlink.NewAttributeDecoder(mpp.b[mpp.i : mpp.i+mpp.alen])
  507. if err != nil {
  508. mpp.err = err
  509. return nil
  510. }
  511. mpp.i += mpp.alen
  512. return ad
  513. }