route_linux.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. package netlink
  2. import (
  3. "fmt"
  4. "net"
  5. "syscall"
  6. "github.com/vishvananda/netlink/nl"
  7. "github.com/vishvananda/netns"
  8. )
  9. // RtAttr is shared so it is in netlink_linux.go
  10. const (
  11. SCOPE_UNIVERSE Scope = syscall.RT_SCOPE_UNIVERSE
  12. SCOPE_SITE Scope = syscall.RT_SCOPE_SITE
  13. SCOPE_LINK Scope = syscall.RT_SCOPE_LINK
  14. SCOPE_HOST Scope = syscall.RT_SCOPE_HOST
  15. SCOPE_NOWHERE Scope = syscall.RT_SCOPE_NOWHERE
  16. )
  17. const (
  18. RT_FILTER_PROTOCOL uint64 = 1 << (1 + iota)
  19. RT_FILTER_SCOPE
  20. RT_FILTER_TYPE
  21. RT_FILTER_TOS
  22. RT_FILTER_IIF
  23. RT_FILTER_OIF
  24. RT_FILTER_DST
  25. RT_FILTER_SRC
  26. RT_FILTER_GW
  27. RT_FILTER_TABLE
  28. )
  29. const (
  30. FLAG_ONLINK NextHopFlag = syscall.RTNH_F_ONLINK
  31. FLAG_PERVASIVE NextHopFlag = syscall.RTNH_F_PERVASIVE
  32. )
  33. var testFlags = []flagString{
  34. {f: FLAG_ONLINK, s: "onlink"},
  35. {f: FLAG_PERVASIVE, s: "pervasive"},
  36. }
  37. func (r *Route) ListFlags() []string {
  38. var flags []string
  39. for _, tf := range testFlags {
  40. if r.Flags&int(tf.f) != 0 {
  41. flags = append(flags, tf.s)
  42. }
  43. }
  44. return flags
  45. }
  46. // RouteAdd will add a route to the system.
  47. // Equivalent to: `ip route add $route`
  48. func RouteAdd(route *Route) error {
  49. return pkgHandle.RouteAdd(route)
  50. }
  51. // RouteAdd will add a route to the system.
  52. // Equivalent to: `ip route add $route`
  53. func (h *Handle) RouteAdd(route *Route) error {
  54. req := h.newNetlinkRequest(syscall.RTM_NEWROUTE, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
  55. return h.routeHandle(route, req, nl.NewRtMsg())
  56. }
  57. // RouteDel will delete a route from the system.
  58. // Equivalent to: `ip route del $route`
  59. func RouteDel(route *Route) error {
  60. return pkgHandle.RouteDel(route)
  61. }
  62. // RouteDel will delete a route from the system.
  63. // Equivalent to: `ip route del $route`
  64. func (h *Handle) RouteDel(route *Route) error {
  65. req := h.newNetlinkRequest(syscall.RTM_DELROUTE, syscall.NLM_F_ACK)
  66. return h.routeHandle(route, req, nl.NewRtDelMsg())
  67. }
  68. func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg) error {
  69. if (route.Dst == nil || route.Dst.IP == nil) && route.Src == nil && route.Gw == nil {
  70. return fmt.Errorf("one of Dst.IP, Src, or Gw must not be nil")
  71. }
  72. family := -1
  73. var rtAttrs []*nl.RtAttr
  74. if route.Dst != nil && route.Dst.IP != nil {
  75. dstLen, _ := route.Dst.Mask.Size()
  76. msg.Dst_len = uint8(dstLen)
  77. dstFamily := nl.GetIPFamily(route.Dst.IP)
  78. family = dstFamily
  79. var dstData []byte
  80. if dstFamily == FAMILY_V4 {
  81. dstData = route.Dst.IP.To4()
  82. } else {
  83. dstData = route.Dst.IP.To16()
  84. }
  85. rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_DST, dstData))
  86. }
  87. if route.Src != nil {
  88. srcFamily := nl.GetIPFamily(route.Src)
  89. if family != -1 && family != srcFamily {
  90. return fmt.Errorf("source and destination ip are not the same IP family")
  91. }
  92. family = srcFamily
  93. var srcData []byte
  94. if srcFamily == FAMILY_V4 {
  95. srcData = route.Src.To4()
  96. } else {
  97. srcData = route.Src.To16()
  98. }
  99. // The commonly used src ip for routes is actually PREFSRC
  100. rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_PREFSRC, srcData))
  101. }
  102. if route.Gw != nil {
  103. gwFamily := nl.GetIPFamily(route.Gw)
  104. if family != -1 && family != gwFamily {
  105. return fmt.Errorf("gateway, source, and destination ip are not the same IP family")
  106. }
  107. family = gwFamily
  108. var gwData []byte
  109. if gwFamily == FAMILY_V4 {
  110. gwData = route.Gw.To4()
  111. } else {
  112. gwData = route.Gw.To16()
  113. }
  114. rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_GATEWAY, gwData))
  115. }
  116. if len(route.MultiPath) > 0 {
  117. buf := []byte{}
  118. for _, nh := range route.MultiPath {
  119. rtnh := &nl.RtNexthop{
  120. RtNexthop: syscall.RtNexthop{
  121. Hops: uint8(nh.Hops),
  122. Ifindex: int32(nh.LinkIndex),
  123. Len: uint16(syscall.SizeofRtNexthop),
  124. },
  125. }
  126. var gwData []byte
  127. if nh.Gw != nil {
  128. gwFamily := nl.GetIPFamily(nh.Gw)
  129. if family != -1 && family != gwFamily {
  130. return fmt.Errorf("gateway, source, and destination ip are not the same IP family")
  131. }
  132. var gw *nl.RtAttr
  133. if gwFamily == FAMILY_V4 {
  134. gw = nl.NewRtAttr(syscall.RTA_GATEWAY, []byte(nh.Gw.To4()))
  135. } else {
  136. gw = nl.NewRtAttr(syscall.RTA_GATEWAY, []byte(nh.Gw.To16()))
  137. }
  138. gwData := gw.Serialize()
  139. rtnh.Len += uint16(len(gwData))
  140. }
  141. buf = append(buf, rtnh.Serialize()...)
  142. buf = append(buf, gwData...)
  143. }
  144. rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_MULTIPATH, buf))
  145. }
  146. if route.Table > 0 {
  147. if route.Table >= 256 {
  148. msg.Table = syscall.RT_TABLE_UNSPEC
  149. b := make([]byte, 4)
  150. native.PutUint32(b, uint32(route.Table))
  151. rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_TABLE, b))
  152. } else {
  153. msg.Table = uint8(route.Table)
  154. }
  155. }
  156. if route.Priority > 0 {
  157. b := make([]byte, 4)
  158. native.PutUint32(b, uint32(route.Priority))
  159. rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_PRIORITY, b))
  160. }
  161. if route.Tos > 0 {
  162. msg.Tos = uint8(route.Tos)
  163. }
  164. if route.Protocol > 0 {
  165. msg.Protocol = uint8(route.Protocol)
  166. }
  167. if route.Type > 0 {
  168. msg.Type = uint8(route.Type)
  169. }
  170. msg.Flags = uint32(route.Flags)
  171. msg.Scope = uint8(route.Scope)
  172. msg.Family = uint8(family)
  173. req.AddData(msg)
  174. for _, attr := range rtAttrs {
  175. req.AddData(attr)
  176. }
  177. var (
  178. b = make([]byte, 4)
  179. native = nl.NativeEndian()
  180. )
  181. native.PutUint32(b, uint32(route.LinkIndex))
  182. req.AddData(nl.NewRtAttr(syscall.RTA_OIF, b))
  183. _, err := req.Execute(syscall.NETLINK_ROUTE, 0)
  184. return err
  185. }
  186. // RouteList gets a list of routes in the system.
  187. // Equivalent to: `ip route show`.
  188. // The list can be filtered by link and ip family.
  189. func RouteList(link Link, family int) ([]Route, error) {
  190. return pkgHandle.RouteList(link, family)
  191. }
  192. // RouteList gets a list of routes in the system.
  193. // Equivalent to: `ip route show`.
  194. // The list can be filtered by link and ip family.
  195. func (h *Handle) RouteList(link Link, family int) ([]Route, error) {
  196. var routeFilter *Route
  197. if link != nil {
  198. routeFilter = &Route{
  199. LinkIndex: link.Attrs().Index,
  200. }
  201. }
  202. return h.RouteListFiltered(family, routeFilter, RT_FILTER_OIF)
  203. }
  204. // RouteListFiltered gets a list of routes in the system filtered with specified rules.
  205. // All rules must be defined in RouteFilter struct
  206. func RouteListFiltered(family int, filter *Route, filterMask uint64) ([]Route, error) {
  207. return pkgHandle.RouteListFiltered(family, filter, filterMask)
  208. }
  209. // RouteListFiltered gets a list of routes in the system filtered with specified rules.
  210. // All rules must be defined in RouteFilter struct
  211. func (h *Handle) RouteListFiltered(family int, filter *Route, filterMask uint64) ([]Route, error) {
  212. req := h.newNetlinkRequest(syscall.RTM_GETROUTE, syscall.NLM_F_DUMP)
  213. infmsg := nl.NewIfInfomsg(family)
  214. req.AddData(infmsg)
  215. msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWROUTE)
  216. if err != nil {
  217. return nil, err
  218. }
  219. var res []Route
  220. for _, m := range msgs {
  221. msg := nl.DeserializeRtMsg(m)
  222. if msg.Flags&syscall.RTM_F_CLONED != 0 {
  223. // Ignore cloned routes
  224. continue
  225. }
  226. if msg.Table != syscall.RT_TABLE_MAIN {
  227. if filter == nil || filter != nil && filterMask&RT_FILTER_TABLE == 0 {
  228. // Ignore non-main tables
  229. continue
  230. }
  231. }
  232. route, err := deserializeRoute(m)
  233. if err != nil {
  234. return nil, err
  235. }
  236. if filter != nil {
  237. switch {
  238. case filterMask&RT_FILTER_TABLE != 0 && route.Table != filter.Table:
  239. continue
  240. case filterMask&RT_FILTER_PROTOCOL != 0 && route.Protocol != filter.Protocol:
  241. continue
  242. case filterMask&RT_FILTER_SCOPE != 0 && route.Scope != filter.Scope:
  243. continue
  244. case filterMask&RT_FILTER_TYPE != 0 && route.Type != filter.Type:
  245. continue
  246. case filterMask&RT_FILTER_TOS != 0 && route.Tos != filter.Tos:
  247. continue
  248. case filterMask&RT_FILTER_OIF != 0 && route.LinkIndex != filter.LinkIndex:
  249. continue
  250. case filterMask&RT_FILTER_IIF != 0 && route.ILinkIndex != filter.ILinkIndex:
  251. continue
  252. case filterMask&RT_FILTER_GW != 0 && !route.Gw.Equal(filter.Gw):
  253. continue
  254. case filterMask&RT_FILTER_SRC != 0 && !route.Src.Equal(filter.Src):
  255. continue
  256. case filterMask&RT_FILTER_DST != 0 && filter.Dst != nil:
  257. if route.Dst == nil {
  258. continue
  259. }
  260. aMaskLen, aMaskBits := route.Dst.Mask.Size()
  261. bMaskLen, bMaskBits := filter.Dst.Mask.Size()
  262. if !(route.Dst.IP.Equal(filter.Dst.IP) && aMaskLen == bMaskLen && aMaskBits == bMaskBits) {
  263. continue
  264. }
  265. }
  266. }
  267. res = append(res, route)
  268. }
  269. return res, nil
  270. }
  271. // deserializeRoute decodes a binary netlink message into a Route struct
  272. func deserializeRoute(m []byte) (Route, error) {
  273. msg := nl.DeserializeRtMsg(m)
  274. attrs, err := nl.ParseRouteAttr(m[msg.Len():])
  275. if err != nil {
  276. return Route{}, err
  277. }
  278. route := Route{
  279. Scope: Scope(msg.Scope),
  280. Protocol: int(msg.Protocol),
  281. Table: int(msg.Table),
  282. Type: int(msg.Type),
  283. Tos: int(msg.Tos),
  284. Flags: int(msg.Flags),
  285. }
  286. native := nl.NativeEndian()
  287. for _, attr := range attrs {
  288. switch attr.Attr.Type {
  289. case syscall.RTA_GATEWAY:
  290. route.Gw = net.IP(attr.Value)
  291. case syscall.RTA_PREFSRC:
  292. route.Src = net.IP(attr.Value)
  293. case syscall.RTA_DST:
  294. route.Dst = &net.IPNet{
  295. IP: attr.Value,
  296. Mask: net.CIDRMask(int(msg.Dst_len), 8*len(attr.Value)),
  297. }
  298. case syscall.RTA_OIF:
  299. route.LinkIndex = int(native.Uint32(attr.Value[0:4]))
  300. case syscall.RTA_IIF:
  301. route.ILinkIndex = int(native.Uint32(attr.Value[0:4]))
  302. case syscall.RTA_PRIORITY:
  303. route.Priority = int(native.Uint32(attr.Value[0:4]))
  304. case syscall.RTA_TABLE:
  305. route.Table = int(native.Uint32(attr.Value[0:4]))
  306. case syscall.RTA_MULTIPATH:
  307. parseRtNexthop := func(value []byte) (*NexthopInfo, []byte, error) {
  308. if len(value) < syscall.SizeofRtNexthop {
  309. return nil, nil, fmt.Errorf("Lack of bytes")
  310. }
  311. nh := nl.DeserializeRtNexthop(value)
  312. if len(value) < int(nh.RtNexthop.Len) {
  313. return nil, nil, fmt.Errorf("Lack of bytes")
  314. }
  315. info := &NexthopInfo{
  316. LinkIndex: int(nh.RtNexthop.Ifindex),
  317. Hops: int(nh.RtNexthop.Hops),
  318. }
  319. attrs, err := nl.ParseRouteAttr(value[syscall.SizeofRtNexthop:int(nh.RtNexthop.Len)])
  320. if err != nil {
  321. return nil, nil, err
  322. }
  323. for _, attr := range attrs {
  324. switch attr.Attr.Type {
  325. case syscall.RTA_GATEWAY:
  326. info.Gw = net.IP(attr.Value)
  327. }
  328. }
  329. return info, value[int(nh.RtNexthop.Len):], nil
  330. }
  331. rest := attr.Value
  332. for len(rest) > 0 {
  333. info, buf, err := parseRtNexthop(rest)
  334. if err != nil {
  335. return route, err
  336. }
  337. route.MultiPath = append(route.MultiPath, info)
  338. rest = buf
  339. }
  340. }
  341. }
  342. return route, nil
  343. }
  344. // RouteGet gets a route to a specific destination from the host system.
  345. // Equivalent to: 'ip route get'.
  346. func RouteGet(destination net.IP) ([]Route, error) {
  347. return pkgHandle.RouteGet(destination)
  348. }
  349. // RouteGet gets a route to a specific destination from the host system.
  350. // Equivalent to: 'ip route get'.
  351. func (h *Handle) RouteGet(destination net.IP) ([]Route, error) {
  352. req := h.newNetlinkRequest(syscall.RTM_GETROUTE, syscall.NLM_F_REQUEST)
  353. family := nl.GetIPFamily(destination)
  354. var destinationData []byte
  355. var bitlen uint8
  356. if family == FAMILY_V4 {
  357. destinationData = destination.To4()
  358. bitlen = 32
  359. } else {
  360. destinationData = destination.To16()
  361. bitlen = 128
  362. }
  363. msg := &nl.RtMsg{}
  364. msg.Family = uint8(family)
  365. msg.Dst_len = bitlen
  366. req.AddData(msg)
  367. rtaDst := nl.NewRtAttr(syscall.RTA_DST, destinationData)
  368. req.AddData(rtaDst)
  369. msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWROUTE)
  370. if err != nil {
  371. return nil, err
  372. }
  373. var res []Route
  374. for _, m := range msgs {
  375. route, err := deserializeRoute(m)
  376. if err != nil {
  377. return nil, err
  378. }
  379. res = append(res, route)
  380. }
  381. return res, nil
  382. }
  383. // RouteSubscribe takes a chan down which notifications will be sent
  384. // when routes are added or deleted. Close the 'done' chan to stop subscription.
  385. func RouteSubscribe(ch chan<- RouteUpdate, done <-chan struct{}) error {
  386. return routeSubscribeAt(netns.None(), netns.None(), ch, done)
  387. }
  388. // RouteSubscribeAt works like RouteSubscribe plus it allows the caller
  389. // to choose the network namespace in which to subscribe (ns).
  390. func RouteSubscribeAt(ns netns.NsHandle, ch chan<- RouteUpdate, done <-chan struct{}) error {
  391. return routeSubscribeAt(ns, netns.None(), ch, done)
  392. }
  393. func routeSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- RouteUpdate, done <-chan struct{}) error {
  394. s, err := nl.SubscribeAt(newNs, curNs, syscall.NETLINK_ROUTE, syscall.RTNLGRP_IPV4_ROUTE, syscall.RTNLGRP_IPV6_ROUTE)
  395. if err != nil {
  396. return err
  397. }
  398. if done != nil {
  399. go func() {
  400. <-done
  401. s.Close()
  402. }()
  403. }
  404. go func() {
  405. defer close(ch)
  406. for {
  407. msgs, err := s.Receive()
  408. if err != nil {
  409. return
  410. }
  411. for _, m := range msgs {
  412. route, err := deserializeRoute(m.Data)
  413. if err != nil {
  414. return
  415. }
  416. ch <- RouteUpdate{Type: m.Header.Type, Route: route}
  417. }
  418. }
  419. }()
  420. return nil
  421. }