xfrm_policy_linux.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. package netlink
  2. import (
  3. "errors"
  4. "fmt"
  5. "net"
  6. "github.com/vishvananda/netlink/nl"
  7. "golang.org/x/sys/unix"
  8. )
  9. // Dir is an enum representing an ipsec template direction.
  10. type Dir uint8
  11. const (
  12. XFRM_DIR_IN Dir = iota
  13. XFRM_DIR_OUT
  14. XFRM_DIR_FWD
  15. XFRM_SOCKET_IN
  16. XFRM_SOCKET_OUT
  17. XFRM_SOCKET_FWD
  18. )
  19. func (d Dir) String() string {
  20. switch d {
  21. case XFRM_DIR_IN:
  22. return "dir in"
  23. case XFRM_DIR_OUT:
  24. return "dir out"
  25. case XFRM_DIR_FWD:
  26. return "dir fwd"
  27. case XFRM_SOCKET_IN:
  28. return "socket in"
  29. case XFRM_SOCKET_OUT:
  30. return "socket out"
  31. case XFRM_SOCKET_FWD:
  32. return "socket fwd"
  33. }
  34. return fmt.Sprintf("socket %d", d-XFRM_SOCKET_IN)
  35. }
  36. // PolicyAction is an enum representing an ipsec policy action.
  37. type PolicyAction uint8
  38. const (
  39. XFRM_POLICY_ALLOW PolicyAction = 0
  40. XFRM_POLICY_BLOCK PolicyAction = 1
  41. )
  42. func (a PolicyAction) String() string {
  43. switch a {
  44. case XFRM_POLICY_ALLOW:
  45. return "allow"
  46. case XFRM_POLICY_BLOCK:
  47. return "block"
  48. default:
  49. return fmt.Sprintf("action %d", a)
  50. }
  51. }
  52. // XfrmPolicyTmpl encapsulates a rule for the base addresses of an ipsec
  53. // policy. These rules are matched with XfrmState to determine encryption
  54. // and authentication algorithms.
  55. type XfrmPolicyTmpl struct {
  56. Dst net.IP
  57. Src net.IP
  58. Proto Proto
  59. Mode Mode
  60. Spi int
  61. Reqid int
  62. Optional int
  63. }
  64. func (t XfrmPolicyTmpl) String() string {
  65. return fmt.Sprintf("{Dst: %v, Src: %v, Proto: %s, Mode: %s, Spi: 0x%x, Reqid: 0x%x}",
  66. t.Dst, t.Src, t.Proto, t.Mode, t.Spi, t.Reqid)
  67. }
  68. // XfrmPolicy represents an ipsec policy. It represents the overlay network
  69. // and has a list of XfrmPolicyTmpls representing the base addresses of
  70. // the policy.
  71. type XfrmPolicy struct {
  72. Dst *net.IPNet
  73. Src *net.IPNet
  74. Proto Proto
  75. DstPort int
  76. SrcPort int
  77. Dir Dir
  78. Priority int
  79. Index int
  80. Action PolicyAction
  81. Ifindex int
  82. Ifid int
  83. Mark *XfrmMark
  84. Tmpls []XfrmPolicyTmpl
  85. }
  86. func (p XfrmPolicy) String() string {
  87. return fmt.Sprintf("{Dst: %v, Src: %v, Proto: %s, DstPort: %d, SrcPort: %d, Dir: %s, Priority: %d, Index: %d, Action: %s, Ifindex: %d, Ifid: %d, Mark: %s, Tmpls: %s}",
  88. p.Dst, p.Src, p.Proto, p.DstPort, p.SrcPort, p.Dir, p.Priority, p.Index, p.Action, p.Ifindex, p.Ifid, p.Mark, p.Tmpls)
  89. }
  90. func selFromPolicy(sel *nl.XfrmSelector, policy *XfrmPolicy) {
  91. sel.Family = uint16(nl.FAMILY_V4)
  92. if policy.Dst != nil {
  93. sel.Family = uint16(nl.GetIPFamily(policy.Dst.IP))
  94. sel.Daddr.FromIP(policy.Dst.IP)
  95. prefixlenD, _ := policy.Dst.Mask.Size()
  96. sel.PrefixlenD = uint8(prefixlenD)
  97. }
  98. if policy.Src != nil {
  99. sel.Saddr.FromIP(policy.Src.IP)
  100. prefixlenS, _ := policy.Src.Mask.Size()
  101. sel.PrefixlenS = uint8(prefixlenS)
  102. }
  103. sel.Proto = uint8(policy.Proto)
  104. sel.Dport = nl.Swap16(uint16(policy.DstPort))
  105. sel.Sport = nl.Swap16(uint16(policy.SrcPort))
  106. if sel.Dport != 0 {
  107. sel.DportMask = ^uint16(0)
  108. }
  109. if sel.Sport != 0 {
  110. sel.SportMask = ^uint16(0)
  111. }
  112. sel.Ifindex = int32(policy.Ifindex)
  113. }
  114. // XfrmPolicyAdd will add an xfrm policy to the system.
  115. // Equivalent to: `ip xfrm policy add $policy`
  116. func XfrmPolicyAdd(policy *XfrmPolicy) error {
  117. return pkgHandle.XfrmPolicyAdd(policy)
  118. }
  119. // XfrmPolicyAdd will add an xfrm policy to the system.
  120. // Equivalent to: `ip xfrm policy add $policy`
  121. func (h *Handle) XfrmPolicyAdd(policy *XfrmPolicy) error {
  122. return h.xfrmPolicyAddOrUpdate(policy, nl.XFRM_MSG_NEWPOLICY)
  123. }
  124. // XfrmPolicyUpdate will update an xfrm policy to the system.
  125. // Equivalent to: `ip xfrm policy update $policy`
  126. func XfrmPolicyUpdate(policy *XfrmPolicy) error {
  127. return pkgHandle.XfrmPolicyUpdate(policy)
  128. }
  129. // XfrmPolicyUpdate will update an xfrm policy to the system.
  130. // Equivalent to: `ip xfrm policy update $policy`
  131. func (h *Handle) XfrmPolicyUpdate(policy *XfrmPolicy) error {
  132. return h.xfrmPolicyAddOrUpdate(policy, nl.XFRM_MSG_UPDPOLICY)
  133. }
  134. func (h *Handle) xfrmPolicyAddOrUpdate(policy *XfrmPolicy, nlProto int) error {
  135. req := h.newNetlinkRequest(nlProto, unix.NLM_F_CREATE|unix.NLM_F_EXCL|unix.NLM_F_ACK)
  136. msg := &nl.XfrmUserpolicyInfo{}
  137. selFromPolicy(&msg.Sel, policy)
  138. msg.Priority = uint32(policy.Priority)
  139. msg.Index = uint32(policy.Index)
  140. msg.Dir = uint8(policy.Dir)
  141. msg.Action = uint8(policy.Action)
  142. msg.Lft.SoftByteLimit = nl.XFRM_INF
  143. msg.Lft.HardByteLimit = nl.XFRM_INF
  144. msg.Lft.SoftPacketLimit = nl.XFRM_INF
  145. msg.Lft.HardPacketLimit = nl.XFRM_INF
  146. req.AddData(msg)
  147. tmplData := make([]byte, nl.SizeofXfrmUserTmpl*len(policy.Tmpls))
  148. for i, tmpl := range policy.Tmpls {
  149. start := i * nl.SizeofXfrmUserTmpl
  150. userTmpl := nl.DeserializeXfrmUserTmpl(tmplData[start : start+nl.SizeofXfrmUserTmpl])
  151. userTmpl.XfrmId.Daddr.FromIP(tmpl.Dst)
  152. userTmpl.Saddr.FromIP(tmpl.Src)
  153. userTmpl.Family = uint16(nl.GetIPFamily(tmpl.Dst))
  154. userTmpl.XfrmId.Proto = uint8(tmpl.Proto)
  155. userTmpl.XfrmId.Spi = nl.Swap32(uint32(tmpl.Spi))
  156. userTmpl.Mode = uint8(tmpl.Mode)
  157. userTmpl.Reqid = uint32(tmpl.Reqid)
  158. userTmpl.Optional = uint8(tmpl.Optional)
  159. userTmpl.Aalgos = ^uint32(0)
  160. userTmpl.Ealgos = ^uint32(0)
  161. userTmpl.Calgos = ^uint32(0)
  162. }
  163. if len(tmplData) > 0 {
  164. tmpls := nl.NewRtAttr(nl.XFRMA_TMPL, tmplData)
  165. req.AddData(tmpls)
  166. }
  167. if policy.Mark != nil {
  168. out := nl.NewRtAttr(nl.XFRMA_MARK, writeMark(policy.Mark))
  169. req.AddData(out)
  170. }
  171. if policy.Ifid != 0 {
  172. ifId := nl.NewRtAttr(nl.XFRMA_IF_ID, nl.Uint32Attr(uint32(policy.Ifid)))
  173. req.AddData(ifId)
  174. }
  175. _, err := req.Execute(unix.NETLINK_XFRM, 0)
  176. return err
  177. }
  178. // XfrmPolicyDel will delete an xfrm policy from the system. Note that
  179. // the Tmpls are ignored when matching the policy to delete.
  180. // Equivalent to: `ip xfrm policy del $policy`
  181. func XfrmPolicyDel(policy *XfrmPolicy) error {
  182. return pkgHandle.XfrmPolicyDel(policy)
  183. }
  184. // XfrmPolicyDel will delete an xfrm policy from the system. Note that
  185. // the Tmpls are ignored when matching the policy to delete.
  186. // Equivalent to: `ip xfrm policy del $policy`
  187. func (h *Handle) XfrmPolicyDel(policy *XfrmPolicy) error {
  188. _, err := h.xfrmPolicyGetOrDelete(policy, nl.XFRM_MSG_DELPOLICY)
  189. return err
  190. }
  191. // XfrmPolicyList gets a list of xfrm policies in the system.
  192. // Equivalent to: `ip xfrm policy show`.
  193. // The list can be filtered by ip family.
  194. //
  195. // If the returned error is [ErrDumpInterrupted], results may be inconsistent
  196. // or incomplete.
  197. func XfrmPolicyList(family int) ([]XfrmPolicy, error) {
  198. return pkgHandle.XfrmPolicyList(family)
  199. }
  200. // XfrmPolicyList gets a list of xfrm policies in the system.
  201. // Equivalent to: `ip xfrm policy show`.
  202. // The list can be filtered by ip family.
  203. //
  204. // If the returned error is [ErrDumpInterrupted], results may be inconsistent
  205. // or incomplete.
  206. func (h *Handle) XfrmPolicyList(family int) ([]XfrmPolicy, error) {
  207. req := h.newNetlinkRequest(nl.XFRM_MSG_GETPOLICY, unix.NLM_F_DUMP)
  208. msg := nl.NewIfInfomsg(family)
  209. req.AddData(msg)
  210. msgs, executeErr := req.Execute(unix.NETLINK_XFRM, nl.XFRM_MSG_NEWPOLICY)
  211. if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
  212. return nil, executeErr
  213. }
  214. var res []XfrmPolicy
  215. for _, m := range msgs {
  216. if policy, err := parseXfrmPolicy(m, family); err == nil {
  217. res = append(res, *policy)
  218. } else if err == familyError {
  219. continue
  220. } else {
  221. return nil, err
  222. }
  223. }
  224. return res, executeErr
  225. }
  226. // XfrmPolicyGet gets a the policy described by the index or selector, if found.
  227. // Equivalent to: `ip xfrm policy get { SELECTOR | index INDEX } dir DIR [ctx CTX ] [ mark MARK [ mask MASK ] ] [ ptype PTYPE ]`.
  228. func XfrmPolicyGet(policy *XfrmPolicy) (*XfrmPolicy, error) {
  229. return pkgHandle.XfrmPolicyGet(policy)
  230. }
  231. // XfrmPolicyGet gets a the policy described by the index or selector, if found.
  232. // Equivalent to: `ip xfrm policy get { SELECTOR | index INDEX } dir DIR [ctx CTX ] [ mark MARK [ mask MASK ] ] [ ptype PTYPE ]`.
  233. func (h *Handle) XfrmPolicyGet(policy *XfrmPolicy) (*XfrmPolicy, error) {
  234. return h.xfrmPolicyGetOrDelete(policy, nl.XFRM_MSG_GETPOLICY)
  235. }
  236. // XfrmPolicyFlush will flush the policies on the system.
  237. // Equivalent to: `ip xfrm policy flush`
  238. func XfrmPolicyFlush() error {
  239. return pkgHandle.XfrmPolicyFlush()
  240. }
  241. // XfrmPolicyFlush will flush the policies on the system.
  242. // Equivalent to: `ip xfrm policy flush`
  243. func (h *Handle) XfrmPolicyFlush() error {
  244. req := h.newNetlinkRequest(nl.XFRM_MSG_FLUSHPOLICY, unix.NLM_F_ACK)
  245. _, err := req.Execute(unix.NETLINK_XFRM, 0)
  246. return err
  247. }
  248. func (h *Handle) xfrmPolicyGetOrDelete(policy *XfrmPolicy, nlProto int) (*XfrmPolicy, error) {
  249. req := h.newNetlinkRequest(nlProto, unix.NLM_F_ACK)
  250. msg := &nl.XfrmUserpolicyId{}
  251. selFromPolicy(&msg.Sel, policy)
  252. msg.Index = uint32(policy.Index)
  253. msg.Dir = uint8(policy.Dir)
  254. req.AddData(msg)
  255. if policy.Mark != nil {
  256. out := nl.NewRtAttr(nl.XFRMA_MARK, writeMark(policy.Mark))
  257. req.AddData(out)
  258. }
  259. if policy.Ifid != 0 {
  260. ifId := nl.NewRtAttr(nl.XFRMA_IF_ID, nl.Uint32Attr(uint32(policy.Ifid)))
  261. req.AddData(ifId)
  262. }
  263. resType := nl.XFRM_MSG_NEWPOLICY
  264. if nlProto == nl.XFRM_MSG_DELPOLICY {
  265. resType = 0
  266. }
  267. msgs, err := req.Execute(unix.NETLINK_XFRM, uint16(resType))
  268. if err != nil {
  269. return nil, err
  270. }
  271. if nlProto == nl.XFRM_MSG_DELPOLICY {
  272. return nil, err
  273. }
  274. return parseXfrmPolicy(msgs[0], FAMILY_ALL)
  275. }
  276. func parseXfrmPolicy(m []byte, family int) (*XfrmPolicy, error) {
  277. msg := nl.DeserializeXfrmUserpolicyInfo(m)
  278. // This is mainly for the policy dump
  279. if family != FAMILY_ALL && family != int(msg.Sel.Family) {
  280. return nil, familyError
  281. }
  282. var policy XfrmPolicy
  283. policy.Dst = msg.Sel.Daddr.ToIPNet(msg.Sel.PrefixlenD, uint16(family))
  284. policy.Src = msg.Sel.Saddr.ToIPNet(msg.Sel.PrefixlenS, uint16(family))
  285. policy.Proto = Proto(msg.Sel.Proto)
  286. policy.DstPort = int(nl.Swap16(msg.Sel.Dport))
  287. policy.SrcPort = int(nl.Swap16(msg.Sel.Sport))
  288. policy.Ifindex = int(msg.Sel.Ifindex)
  289. policy.Priority = int(msg.Priority)
  290. policy.Index = int(msg.Index)
  291. policy.Dir = Dir(msg.Dir)
  292. policy.Action = PolicyAction(msg.Action)
  293. attrs, err := nl.ParseRouteAttr(m[msg.Len():])
  294. if err != nil {
  295. return nil, err
  296. }
  297. for _, attr := range attrs {
  298. switch attr.Attr.Type {
  299. case nl.XFRMA_TMPL:
  300. max := len(attr.Value)
  301. for i := 0; i < max; i += nl.SizeofXfrmUserTmpl {
  302. var resTmpl XfrmPolicyTmpl
  303. tmpl := nl.DeserializeXfrmUserTmpl(attr.Value[i : i+nl.SizeofXfrmUserTmpl])
  304. resTmpl.Dst = tmpl.XfrmId.Daddr.ToIP()
  305. resTmpl.Src = tmpl.Saddr.ToIP()
  306. resTmpl.Proto = Proto(tmpl.XfrmId.Proto)
  307. resTmpl.Mode = Mode(tmpl.Mode)
  308. resTmpl.Spi = int(nl.Swap32(tmpl.XfrmId.Spi))
  309. resTmpl.Reqid = int(tmpl.Reqid)
  310. resTmpl.Optional = int(tmpl.Optional)
  311. policy.Tmpls = append(policy.Tmpls, resTmpl)
  312. }
  313. case nl.XFRMA_MARK:
  314. mark := nl.DeserializeXfrmMark(attr.Value[:])
  315. policy.Mark = new(XfrmMark)
  316. policy.Mark.Value = mark.Value
  317. policy.Mark.Mask = mark.Mask
  318. case nl.XFRMA_IF_ID:
  319. policy.Ifid = int(native.Uint32(attr.Value))
  320. }
  321. }
  322. return &policy, nil
  323. }