rule_linux.go 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. package netlink
  2. import (
  3. "fmt"
  4. "net"
  5. "github.com/vishvananda/netlink/nl"
  6. "golang.org/x/sys/unix"
  7. )
  8. const FibRuleInvert = 0x2
  9. // RuleAdd adds a rule to the system.
  10. // Equivalent to: ip rule add
  11. func RuleAdd(rule *Rule) error {
  12. return pkgHandle.RuleAdd(rule)
  13. }
  14. // RuleAdd adds a rule to the system.
  15. // Equivalent to: ip rule add
  16. func (h *Handle) RuleAdd(rule *Rule) error {
  17. req := h.newNetlinkRequest(unix.RTM_NEWRULE, unix.NLM_F_CREATE|unix.NLM_F_EXCL|unix.NLM_F_ACK)
  18. return ruleHandle(rule, req)
  19. }
  20. // RuleDel deletes a rule from the system.
  21. // Equivalent to: ip rule del
  22. func RuleDel(rule *Rule) error {
  23. return pkgHandle.RuleDel(rule)
  24. }
  25. // RuleDel deletes a rule from the system.
  26. // Equivalent to: ip rule del
  27. func (h *Handle) RuleDel(rule *Rule) error {
  28. req := h.newNetlinkRequest(unix.RTM_DELRULE, unix.NLM_F_ACK)
  29. return ruleHandle(rule, req)
  30. }
  31. func ruleHandle(rule *Rule, req *nl.NetlinkRequest) error {
  32. msg := nl.NewRtMsg()
  33. msg.Family = unix.AF_INET
  34. msg.Protocol = unix.RTPROT_BOOT
  35. msg.Scope = unix.RT_SCOPE_UNIVERSE
  36. msg.Table = unix.RT_TABLE_UNSPEC
  37. msg.Type = unix.RTN_UNSPEC
  38. if req.NlMsghdr.Flags&unix.NLM_F_CREATE > 0 {
  39. msg.Type = unix.RTN_UNICAST
  40. }
  41. if rule.Invert {
  42. msg.Flags |= FibRuleInvert
  43. }
  44. if rule.Family != 0 {
  45. msg.Family = uint8(rule.Family)
  46. }
  47. if rule.Table >= 0 && rule.Table < 256 {
  48. msg.Table = uint8(rule.Table)
  49. }
  50. var dstFamily uint8
  51. var rtAttrs []*nl.RtAttr
  52. if rule.Dst != nil && rule.Dst.IP != nil {
  53. dstLen, _ := rule.Dst.Mask.Size()
  54. msg.Dst_len = uint8(dstLen)
  55. msg.Family = uint8(nl.GetIPFamily(rule.Dst.IP))
  56. dstFamily = msg.Family
  57. var dstData []byte
  58. if msg.Family == unix.AF_INET {
  59. dstData = rule.Dst.IP.To4()
  60. } else {
  61. dstData = rule.Dst.IP.To16()
  62. }
  63. rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_DST, dstData))
  64. }
  65. if rule.Src != nil && rule.Src.IP != nil {
  66. msg.Family = uint8(nl.GetIPFamily(rule.Src.IP))
  67. if dstFamily != 0 && dstFamily != msg.Family {
  68. return fmt.Errorf("source and destination ip are not the same IP family")
  69. }
  70. srcLen, _ := rule.Src.Mask.Size()
  71. msg.Src_len = uint8(srcLen)
  72. var srcData []byte
  73. if msg.Family == unix.AF_INET {
  74. srcData = rule.Src.IP.To4()
  75. } else {
  76. srcData = rule.Src.IP.To16()
  77. }
  78. rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_SRC, srcData))
  79. }
  80. req.AddData(msg)
  81. for i := range rtAttrs {
  82. req.AddData(rtAttrs[i])
  83. }
  84. native := nl.NativeEndian()
  85. if rule.Priority >= 0 {
  86. b := make([]byte, 4)
  87. native.PutUint32(b, uint32(rule.Priority))
  88. req.AddData(nl.NewRtAttr(nl.FRA_PRIORITY, b))
  89. }
  90. if rule.Mark >= 0 {
  91. b := make([]byte, 4)
  92. native.PutUint32(b, uint32(rule.Mark))
  93. req.AddData(nl.NewRtAttr(nl.FRA_FWMARK, b))
  94. }
  95. if rule.Mask >= 0 {
  96. b := make([]byte, 4)
  97. native.PutUint32(b, uint32(rule.Mask))
  98. req.AddData(nl.NewRtAttr(nl.FRA_FWMASK, b))
  99. }
  100. if rule.Flow >= 0 {
  101. b := make([]byte, 4)
  102. native.PutUint32(b, uint32(rule.Flow))
  103. req.AddData(nl.NewRtAttr(nl.FRA_FLOW, b))
  104. }
  105. if rule.TunID > 0 {
  106. b := make([]byte, 4)
  107. native.PutUint32(b, uint32(rule.TunID))
  108. req.AddData(nl.NewRtAttr(nl.FRA_TUN_ID, b))
  109. }
  110. if rule.Table >= 256 {
  111. b := make([]byte, 4)
  112. native.PutUint32(b, uint32(rule.Table))
  113. req.AddData(nl.NewRtAttr(nl.FRA_TABLE, b))
  114. }
  115. if msg.Table > 0 {
  116. if rule.SuppressPrefixlen >= 0 {
  117. b := make([]byte, 4)
  118. native.PutUint32(b, uint32(rule.SuppressPrefixlen))
  119. req.AddData(nl.NewRtAttr(nl.FRA_SUPPRESS_PREFIXLEN, b))
  120. }
  121. if rule.SuppressIfgroup >= 0 {
  122. b := make([]byte, 4)
  123. native.PutUint32(b, uint32(rule.SuppressIfgroup))
  124. req.AddData(nl.NewRtAttr(nl.FRA_SUPPRESS_IFGROUP, b))
  125. }
  126. }
  127. if rule.IifName != "" {
  128. req.AddData(nl.NewRtAttr(nl.FRA_IIFNAME, []byte(rule.IifName)))
  129. }
  130. if rule.OifName != "" {
  131. req.AddData(nl.NewRtAttr(nl.FRA_OIFNAME, []byte(rule.OifName)))
  132. }
  133. if rule.Goto >= 0 {
  134. msg.Type = nl.FR_ACT_NOP
  135. b := make([]byte, 4)
  136. native.PutUint32(b, uint32(rule.Goto))
  137. req.AddData(nl.NewRtAttr(nl.FRA_GOTO, b))
  138. }
  139. _, err := req.Execute(unix.NETLINK_ROUTE, 0)
  140. return err
  141. }
  142. // RuleList lists rules in the system.
  143. // Equivalent to: ip rule list
  144. func RuleList(family int) ([]Rule, error) {
  145. return pkgHandle.RuleList(family)
  146. }
  147. // RuleList lists rules in the system.
  148. // Equivalent to: ip rule list
  149. func (h *Handle) RuleList(family int) ([]Rule, error) {
  150. req := h.newNetlinkRequest(unix.RTM_GETRULE, unix.NLM_F_DUMP|unix.NLM_F_REQUEST)
  151. msg := nl.NewIfInfomsg(family)
  152. req.AddData(msg)
  153. msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWRULE)
  154. if err != nil {
  155. return nil, err
  156. }
  157. native := nl.NativeEndian()
  158. var res = make([]Rule, 0)
  159. for i := range msgs {
  160. msg := nl.DeserializeRtMsg(msgs[i])
  161. attrs, err := nl.ParseRouteAttr(msgs[i][msg.Len():])
  162. if err != nil {
  163. return nil, err
  164. }
  165. rule := NewRule()
  166. rule.Invert = msg.Flags&FibRuleInvert > 0
  167. for j := range attrs {
  168. switch attrs[j].Attr.Type {
  169. case unix.RTA_TABLE:
  170. rule.Table = int(native.Uint32(attrs[j].Value[0:4]))
  171. case nl.FRA_SRC:
  172. rule.Src = &net.IPNet{
  173. IP: attrs[j].Value,
  174. Mask: net.CIDRMask(int(msg.Src_len), 8*len(attrs[j].Value)),
  175. }
  176. case nl.FRA_DST:
  177. rule.Dst = &net.IPNet{
  178. IP: attrs[j].Value,
  179. Mask: net.CIDRMask(int(msg.Dst_len), 8*len(attrs[j].Value)),
  180. }
  181. case nl.FRA_FWMARK:
  182. rule.Mark = int(native.Uint32(attrs[j].Value[0:4]))
  183. case nl.FRA_FWMASK:
  184. rule.Mask = int(native.Uint32(attrs[j].Value[0:4]))
  185. case nl.FRA_TUN_ID:
  186. rule.TunID = uint(native.Uint64(attrs[j].Value[0:4]))
  187. case nl.FRA_IIFNAME:
  188. rule.IifName = string(attrs[j].Value[:len(attrs[j].Value)-1])
  189. case nl.FRA_OIFNAME:
  190. rule.OifName = string(attrs[j].Value[:len(attrs[j].Value)-1])
  191. case nl.FRA_SUPPRESS_PREFIXLEN:
  192. i := native.Uint32(attrs[j].Value[0:4])
  193. if i != 0xffffffff {
  194. rule.SuppressPrefixlen = int(i)
  195. }
  196. case nl.FRA_SUPPRESS_IFGROUP:
  197. i := native.Uint32(attrs[j].Value[0:4])
  198. if i != 0xffffffff {
  199. rule.SuppressIfgroup = int(i)
  200. }
  201. case nl.FRA_FLOW:
  202. rule.Flow = int(native.Uint32(attrs[j].Value[0:4]))
  203. case nl.FRA_GOTO:
  204. rule.Goto = int(native.Uint32(attrs[j].Value[0:4]))
  205. case nl.FRA_PRIORITY:
  206. rule.Priority = int(native.Uint32(attrs[j].Value[0:4]))
  207. }
  208. }
  209. res = append(res, *rule)
  210. }
  211. return res, nil
  212. }