rule_linux.go 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. package netlink
  2. import (
  3. "bytes"
  4. "fmt"
  5. "net"
  6. "github.com/vishvananda/netlink/nl"
  7. "golang.org/x/sys/unix"
  8. )
  9. const FibRuleInvert = 0x2
  10. // RuleAdd adds a rule to the system.
  11. // Equivalent to: ip rule add
  12. func RuleAdd(rule *Rule) error {
  13. return pkgHandle.RuleAdd(rule)
  14. }
  15. // RuleAdd adds a rule to the system.
  16. // Equivalent to: ip rule add
  17. func (h *Handle) RuleAdd(rule *Rule) error {
  18. req := h.newNetlinkRequest(unix.RTM_NEWRULE, unix.NLM_F_CREATE|unix.NLM_F_EXCL|unix.NLM_F_ACK)
  19. return ruleHandle(rule, req)
  20. }
  21. // RuleDel deletes a rule from the system.
  22. // Equivalent to: ip rule del
  23. func RuleDel(rule *Rule) error {
  24. return pkgHandle.RuleDel(rule)
  25. }
  26. // RuleDel deletes a rule from the system.
  27. // Equivalent to: ip rule del
  28. func (h *Handle) RuleDel(rule *Rule) error {
  29. req := h.newNetlinkRequest(unix.RTM_DELRULE, unix.NLM_F_ACK)
  30. return ruleHandle(rule, req)
  31. }
  32. func ruleHandle(rule *Rule, req *nl.NetlinkRequest) error {
  33. msg := nl.NewRtMsg()
  34. msg.Family = unix.AF_INET
  35. msg.Protocol = unix.RTPROT_BOOT
  36. msg.Scope = unix.RT_SCOPE_UNIVERSE
  37. msg.Table = unix.RT_TABLE_UNSPEC
  38. msg.Type = unix.RTN_UNSPEC
  39. if req.NlMsghdr.Flags&unix.NLM_F_CREATE > 0 {
  40. msg.Type = unix.RTN_UNICAST
  41. }
  42. if rule.Invert {
  43. msg.Flags |= FibRuleInvert
  44. }
  45. if rule.Family != 0 {
  46. msg.Family = uint8(rule.Family)
  47. }
  48. if rule.Table >= 0 && rule.Table < 256 {
  49. msg.Table = uint8(rule.Table)
  50. }
  51. if rule.Tos != 0 {
  52. msg.Tos = uint8(rule.Tos)
  53. }
  54. var dstFamily uint8
  55. var rtAttrs []*nl.RtAttr
  56. if rule.Dst != nil && rule.Dst.IP != nil {
  57. dstLen, _ := rule.Dst.Mask.Size()
  58. msg.Dst_len = uint8(dstLen)
  59. msg.Family = uint8(nl.GetIPFamily(rule.Dst.IP))
  60. dstFamily = msg.Family
  61. var dstData []byte
  62. if msg.Family == unix.AF_INET {
  63. dstData = rule.Dst.IP.To4()
  64. } else {
  65. dstData = rule.Dst.IP.To16()
  66. }
  67. rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_DST, dstData))
  68. }
  69. if rule.Src != nil && rule.Src.IP != nil {
  70. msg.Family = uint8(nl.GetIPFamily(rule.Src.IP))
  71. if dstFamily != 0 && dstFamily != msg.Family {
  72. return fmt.Errorf("source and destination ip are not the same IP family")
  73. }
  74. srcLen, _ := rule.Src.Mask.Size()
  75. msg.Src_len = uint8(srcLen)
  76. var srcData []byte
  77. if msg.Family == unix.AF_INET {
  78. srcData = rule.Src.IP.To4()
  79. } else {
  80. srcData = rule.Src.IP.To16()
  81. }
  82. rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_SRC, srcData))
  83. }
  84. req.AddData(msg)
  85. for i := range rtAttrs {
  86. req.AddData(rtAttrs[i])
  87. }
  88. if rule.Priority >= 0 {
  89. b := make([]byte, 4)
  90. native.PutUint32(b, uint32(rule.Priority))
  91. req.AddData(nl.NewRtAttr(nl.FRA_PRIORITY, b))
  92. }
  93. if rule.Mark >= 0 {
  94. b := make([]byte, 4)
  95. native.PutUint32(b, uint32(rule.Mark))
  96. req.AddData(nl.NewRtAttr(nl.FRA_FWMARK, b))
  97. }
  98. if rule.Mask >= 0 {
  99. b := make([]byte, 4)
  100. native.PutUint32(b, uint32(rule.Mask))
  101. req.AddData(nl.NewRtAttr(nl.FRA_FWMASK, b))
  102. }
  103. if rule.Flow >= 0 {
  104. b := make([]byte, 4)
  105. native.PutUint32(b, uint32(rule.Flow))
  106. req.AddData(nl.NewRtAttr(nl.FRA_FLOW, b))
  107. }
  108. if rule.TunID > 0 {
  109. b := make([]byte, 4)
  110. native.PutUint32(b, uint32(rule.TunID))
  111. req.AddData(nl.NewRtAttr(nl.FRA_TUN_ID, b))
  112. }
  113. if rule.Table >= 256 {
  114. b := make([]byte, 4)
  115. native.PutUint32(b, uint32(rule.Table))
  116. req.AddData(nl.NewRtAttr(nl.FRA_TABLE, b))
  117. }
  118. if msg.Table > 0 {
  119. if rule.SuppressPrefixlen >= 0 {
  120. b := make([]byte, 4)
  121. native.PutUint32(b, uint32(rule.SuppressPrefixlen))
  122. req.AddData(nl.NewRtAttr(nl.FRA_SUPPRESS_PREFIXLEN, b))
  123. }
  124. if rule.SuppressIfgroup >= 0 {
  125. b := make([]byte, 4)
  126. native.PutUint32(b, uint32(rule.SuppressIfgroup))
  127. req.AddData(nl.NewRtAttr(nl.FRA_SUPPRESS_IFGROUP, b))
  128. }
  129. }
  130. if rule.IifName != "" {
  131. req.AddData(nl.NewRtAttr(nl.FRA_IIFNAME, []byte(rule.IifName+"\x00")))
  132. }
  133. if rule.OifName != "" {
  134. req.AddData(nl.NewRtAttr(nl.FRA_OIFNAME, []byte(rule.OifName+"\x00")))
  135. }
  136. if rule.Goto >= 0 {
  137. msg.Type = nl.FR_ACT_GOTO
  138. b := make([]byte, 4)
  139. native.PutUint32(b, uint32(rule.Goto))
  140. req.AddData(nl.NewRtAttr(nl.FRA_GOTO, b))
  141. }
  142. if rule.IPProto > 0 {
  143. b := make([]byte, 4)
  144. native.PutUint32(b, uint32(rule.IPProto))
  145. req.AddData(nl.NewRtAttr(nl.FRA_IP_PROTO, b))
  146. }
  147. if rule.Dport != nil {
  148. b := rule.Dport.toRtAttrData()
  149. req.AddData(nl.NewRtAttr(nl.FRA_DPORT_RANGE, b))
  150. }
  151. if rule.Sport != nil {
  152. b := rule.Sport.toRtAttrData()
  153. req.AddData(nl.NewRtAttr(nl.FRA_SPORT_RANGE, b))
  154. }
  155. _, err := req.Execute(unix.NETLINK_ROUTE, 0)
  156. return err
  157. }
  158. // RuleList lists rules in the system.
  159. // Equivalent to: ip rule list
  160. func RuleList(family int) ([]Rule, error) {
  161. return pkgHandle.RuleList(family)
  162. }
  163. // RuleList lists rules in the system.
  164. // Equivalent to: ip rule list
  165. func (h *Handle) RuleList(family int) ([]Rule, error) {
  166. return h.RuleListFiltered(family, nil, 0)
  167. }
  168. // RuleListFiltered gets a list of rules in the system filtered by the
  169. // specified rule template `filter`.
  170. // Equivalent to: ip rule list
  171. func RuleListFiltered(family int, filter *Rule, filterMask uint64) ([]Rule, error) {
  172. return pkgHandle.RuleListFiltered(family, filter, filterMask)
  173. }
  174. // RuleListFiltered lists rules in the system.
  175. // Equivalent to: ip rule list
  176. func (h *Handle) RuleListFiltered(family int, filter *Rule, filterMask uint64) ([]Rule, error) {
  177. req := h.newNetlinkRequest(unix.RTM_GETRULE, unix.NLM_F_DUMP|unix.NLM_F_REQUEST)
  178. msg := nl.NewIfInfomsg(family)
  179. req.AddData(msg)
  180. msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWRULE)
  181. if err != nil {
  182. return nil, err
  183. }
  184. var res = make([]Rule, 0)
  185. for i := range msgs {
  186. msg := nl.DeserializeRtMsg(msgs[i])
  187. attrs, err := nl.ParseRouteAttr(msgs[i][msg.Len():])
  188. if err != nil {
  189. return nil, err
  190. }
  191. rule := NewRule()
  192. rule.Invert = msg.Flags&FibRuleInvert > 0
  193. rule.Tos = uint(msg.Tos)
  194. for j := range attrs {
  195. switch attrs[j].Attr.Type {
  196. case unix.RTA_TABLE:
  197. rule.Table = int(native.Uint32(attrs[j].Value[0:4]))
  198. case nl.FRA_SRC:
  199. rule.Src = &net.IPNet{
  200. IP: attrs[j].Value,
  201. Mask: net.CIDRMask(int(msg.Src_len), 8*len(attrs[j].Value)),
  202. }
  203. case nl.FRA_DST:
  204. rule.Dst = &net.IPNet{
  205. IP: attrs[j].Value,
  206. Mask: net.CIDRMask(int(msg.Dst_len), 8*len(attrs[j].Value)),
  207. }
  208. case nl.FRA_FWMARK:
  209. rule.Mark = int(native.Uint32(attrs[j].Value[0:4]))
  210. case nl.FRA_FWMASK:
  211. rule.Mask = int(native.Uint32(attrs[j].Value[0:4]))
  212. case nl.FRA_TUN_ID:
  213. rule.TunID = uint(native.Uint64(attrs[j].Value[0:8]))
  214. case nl.FRA_IIFNAME:
  215. rule.IifName = string(attrs[j].Value[:len(attrs[j].Value)-1])
  216. case nl.FRA_OIFNAME:
  217. rule.OifName = string(attrs[j].Value[:len(attrs[j].Value)-1])
  218. case nl.FRA_SUPPRESS_PREFIXLEN:
  219. i := native.Uint32(attrs[j].Value[0:4])
  220. if i != 0xffffffff {
  221. rule.SuppressPrefixlen = int(i)
  222. }
  223. case nl.FRA_SUPPRESS_IFGROUP:
  224. i := native.Uint32(attrs[j].Value[0:4])
  225. if i != 0xffffffff {
  226. rule.SuppressIfgroup = int(i)
  227. }
  228. case nl.FRA_FLOW:
  229. rule.Flow = int(native.Uint32(attrs[j].Value[0:4]))
  230. case nl.FRA_GOTO:
  231. rule.Goto = int(native.Uint32(attrs[j].Value[0:4]))
  232. case nl.FRA_PRIORITY:
  233. rule.Priority = int(native.Uint32(attrs[j].Value[0:4]))
  234. case nl.FRA_IP_PROTO:
  235. rule.IPProto = int(native.Uint32(attrs[j].Value[0:4]))
  236. case nl.FRA_DPORT_RANGE:
  237. rule.Dport = NewRulePortRange(native.Uint16(attrs[j].Value[0:2]), native.Uint16(attrs[j].Value[2:4]))
  238. case nl.FRA_SPORT_RANGE:
  239. rule.Sport = NewRulePortRange(native.Uint16(attrs[j].Value[0:2]), native.Uint16(attrs[j].Value[2:4]))
  240. }
  241. }
  242. if filter != nil {
  243. switch {
  244. case filterMask&RT_FILTER_SRC != 0 &&
  245. (rule.Src == nil || rule.Src.String() != filter.Src.String()):
  246. continue
  247. case filterMask&RT_FILTER_DST != 0 &&
  248. (rule.Dst == nil || rule.Dst.String() != filter.Dst.String()):
  249. continue
  250. case filterMask&RT_FILTER_TABLE != 0 &&
  251. filter.Table != unix.RT_TABLE_UNSPEC && rule.Table != filter.Table:
  252. continue
  253. case filterMask&RT_FILTER_TOS != 0 && rule.Tos != filter.Tos:
  254. continue
  255. case filterMask&RT_FILTER_PRIORITY != 0 && rule.Priority != filter.Priority:
  256. continue
  257. case filterMask&RT_FILTER_MARK != 0 && rule.Mark != filter.Mark:
  258. continue
  259. case filterMask&RT_FILTER_MASK != 0 && rule.Mask != filter.Mask:
  260. continue
  261. }
  262. }
  263. res = append(res, *rule)
  264. }
  265. return res, nil
  266. }
  267. func (pr *RulePortRange) toRtAttrData() []byte {
  268. b := [][]byte{make([]byte, 2), make([]byte, 2)}
  269. native.PutUint16(b[0], pr.Start)
  270. native.PutUint16(b[1], pr.End)
  271. return bytes.Join(b, []byte{})
  272. }