rule_linux.go 5.9 KB

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