rule_linux.go 5.2 KB

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