2014-09-01 03:27:34 +00:00
|
|
|
package netlink
|
|
|
|
|
|
|
|
import (
|
Add ErrDumpInterrupted
Add a specific error to report that a netlink response had
NLM_F_DUMP_INTR set, indicating that the set of results may be
incomplete or inconsistent.
unix.EINTR was previously returned (with no results) when the
NLM_F_DUMP_INTR flag was set. Now, errors.Is(err, unix.EINTR) will
still work. But, this will be a breaking change for any code that's
checking for equality with unix.EINTR.
Return results with ErrDumpInterrupted. Results may be incomplete
or inconsistent, but give the caller the option of using them.
Look for NLM_F_DUMP_INTR in more places:
- linkSubscribeAt, neighSubscribeAt, routeSubscribeAt
- can do an initial dump, which may report inconsistent results
-> if there's an error callback, call it with ErrDumpInterrupted
- socketDiagXDPExecutor
- makes an NLM_F_DUMP request, without using Execute()
-> give it the same behaviour as functions that do use Execute()
Signed-off-by: Rob Murray <rob.murray@docker.com>
2024-09-05 08:25:13 +00:00
|
|
|
"errors"
|
2023-10-24 17:45:29 +00:00
|
|
|
"fmt"
|
|
|
|
"net"
|
|
|
|
|
2014-09-19 02:04:48 +00:00
|
|
|
"github.com/vishvananda/netlink/nl"
|
2017-10-20 20:38:07 +00:00
|
|
|
"golang.org/x/sys/unix"
|
2014-09-01 03:27:34 +00:00
|
|
|
)
|
|
|
|
|
2023-10-24 17:45:29 +00:00
|
|
|
// Dir is an enum representing an ipsec template direction.
|
|
|
|
type Dir uint8
|
|
|
|
|
|
|
|
const (
|
|
|
|
XFRM_DIR_IN Dir = iota
|
|
|
|
XFRM_DIR_OUT
|
|
|
|
XFRM_DIR_FWD
|
|
|
|
XFRM_SOCKET_IN
|
|
|
|
XFRM_SOCKET_OUT
|
|
|
|
XFRM_SOCKET_FWD
|
|
|
|
)
|
|
|
|
|
|
|
|
func (d Dir) String() string {
|
|
|
|
switch d {
|
|
|
|
case XFRM_DIR_IN:
|
|
|
|
return "dir in"
|
|
|
|
case XFRM_DIR_OUT:
|
|
|
|
return "dir out"
|
|
|
|
case XFRM_DIR_FWD:
|
|
|
|
return "dir fwd"
|
|
|
|
case XFRM_SOCKET_IN:
|
|
|
|
return "socket in"
|
|
|
|
case XFRM_SOCKET_OUT:
|
|
|
|
return "socket out"
|
|
|
|
case XFRM_SOCKET_FWD:
|
|
|
|
return "socket fwd"
|
|
|
|
}
|
|
|
|
return fmt.Sprintf("socket %d", d-XFRM_SOCKET_IN)
|
|
|
|
}
|
|
|
|
|
|
|
|
// PolicyAction is an enum representing an ipsec policy action.
|
|
|
|
type PolicyAction uint8
|
|
|
|
|
|
|
|
const (
|
|
|
|
XFRM_POLICY_ALLOW PolicyAction = 0
|
|
|
|
XFRM_POLICY_BLOCK PolicyAction = 1
|
|
|
|
)
|
|
|
|
|
|
|
|
func (a PolicyAction) String() string {
|
|
|
|
switch a {
|
|
|
|
case XFRM_POLICY_ALLOW:
|
|
|
|
return "allow"
|
|
|
|
case XFRM_POLICY_BLOCK:
|
|
|
|
return "block"
|
|
|
|
default:
|
|
|
|
return fmt.Sprintf("action %d", a)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// XfrmPolicyTmpl encapsulates a rule for the base addresses of an ipsec
|
|
|
|
// policy. These rules are matched with XfrmState to determine encryption
|
|
|
|
// and authentication algorithms.
|
|
|
|
type XfrmPolicyTmpl struct {
|
|
|
|
Dst net.IP
|
|
|
|
Src net.IP
|
|
|
|
Proto Proto
|
|
|
|
Mode Mode
|
|
|
|
Spi int
|
|
|
|
Reqid int
|
|
|
|
Optional int
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t XfrmPolicyTmpl) String() string {
|
|
|
|
return fmt.Sprintf("{Dst: %v, Src: %v, Proto: %s, Mode: %s, Spi: 0x%x, Reqid: 0x%x}",
|
|
|
|
t.Dst, t.Src, t.Proto, t.Mode, t.Spi, t.Reqid)
|
|
|
|
}
|
|
|
|
|
|
|
|
// XfrmPolicy represents an ipsec policy. It represents the overlay network
|
|
|
|
// and has a list of XfrmPolicyTmpls representing the base addresses of
|
|
|
|
// the policy.
|
|
|
|
type XfrmPolicy struct {
|
|
|
|
Dst *net.IPNet
|
|
|
|
Src *net.IPNet
|
|
|
|
Proto Proto
|
|
|
|
DstPort int
|
|
|
|
SrcPort int
|
|
|
|
Dir Dir
|
|
|
|
Priority int
|
|
|
|
Index int
|
|
|
|
Action PolicyAction
|
|
|
|
Ifindex int
|
|
|
|
Ifid int
|
|
|
|
Mark *XfrmMark
|
|
|
|
Tmpls []XfrmPolicyTmpl
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p XfrmPolicy) String() string {
|
|
|
|
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}",
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2014-09-19 02:04:48 +00:00
|
|
|
func selFromPolicy(sel *nl.XfrmSelector, policy *XfrmPolicy) {
|
2016-05-12 17:52:20 +00:00
|
|
|
sel.Family = uint16(nl.FAMILY_V4)
|
|
|
|
if policy.Dst != nil {
|
|
|
|
sel.Family = uint16(nl.GetIPFamily(policy.Dst.IP))
|
|
|
|
sel.Daddr.FromIP(policy.Dst.IP)
|
|
|
|
prefixlenD, _ := policy.Dst.Mask.Size()
|
|
|
|
sel.PrefixlenD = uint8(prefixlenD)
|
|
|
|
}
|
|
|
|
if policy.Src != nil {
|
|
|
|
sel.Saddr.FromIP(policy.Src.IP)
|
|
|
|
prefixlenS, _ := policy.Src.Mask.Size()
|
|
|
|
sel.PrefixlenS = uint8(prefixlenS)
|
|
|
|
}
|
2016-05-09 16:19:18 +00:00
|
|
|
sel.Proto = uint8(policy.Proto)
|
|
|
|
sel.Dport = nl.Swap16(uint16(policy.DstPort))
|
|
|
|
sel.Sport = nl.Swap16(uint16(policy.SrcPort))
|
2016-05-25 18:10:01 +00:00
|
|
|
if sel.Dport != 0 {
|
|
|
|
sel.DportMask = ^uint16(0)
|
|
|
|
}
|
|
|
|
if sel.Sport != 0 {
|
|
|
|
sel.SportMask = ^uint16(0)
|
|
|
|
}
|
2018-08-10 15:18:51 +00:00
|
|
|
sel.Ifindex = int32(policy.Ifindex)
|
2014-09-01 03:27:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// XfrmPolicyAdd will add an xfrm policy to the system.
|
|
|
|
// Equivalent to: `ip xfrm policy add $policy`
|
|
|
|
func XfrmPolicyAdd(policy *XfrmPolicy) error {
|
2016-05-09 23:55:00 +00:00
|
|
|
return pkgHandle.XfrmPolicyAdd(policy)
|
2016-05-08 18:35:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// XfrmPolicyAdd will add an xfrm policy to the system.
|
|
|
|
// Equivalent to: `ip xfrm policy add $policy`
|
|
|
|
func (h *Handle) XfrmPolicyAdd(policy *XfrmPolicy) error {
|
|
|
|
return h.xfrmPolicyAddOrUpdate(policy, nl.XFRM_MSG_NEWPOLICY)
|
2016-05-04 05:52:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// XfrmPolicyUpdate will update an xfrm policy to the system.
|
|
|
|
// Equivalent to: `ip xfrm policy update $policy`
|
|
|
|
func XfrmPolicyUpdate(policy *XfrmPolicy) error {
|
2016-05-09 23:55:00 +00:00
|
|
|
return pkgHandle.XfrmPolicyUpdate(policy)
|
2016-05-04 05:52:55 +00:00
|
|
|
}
|
|
|
|
|
2016-05-08 18:35:49 +00:00
|
|
|
// XfrmPolicyUpdate will update an xfrm policy to the system.
|
|
|
|
// Equivalent to: `ip xfrm policy update $policy`
|
|
|
|
func (h *Handle) XfrmPolicyUpdate(policy *XfrmPolicy) error {
|
|
|
|
return h.xfrmPolicyAddOrUpdate(policy, nl.XFRM_MSG_UPDPOLICY)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (h *Handle) xfrmPolicyAddOrUpdate(policy *XfrmPolicy, nlProto int) error {
|
2017-10-20 20:38:07 +00:00
|
|
|
req := h.newNetlinkRequest(nlProto, unix.NLM_F_CREATE|unix.NLM_F_EXCL|unix.NLM_F_ACK)
|
2014-09-01 03:27:34 +00:00
|
|
|
|
2014-09-19 02:04:48 +00:00
|
|
|
msg := &nl.XfrmUserpolicyInfo{}
|
|
|
|
selFromPolicy(&msg.Sel, policy)
|
2014-09-01 03:27:34 +00:00
|
|
|
msg.Priority = uint32(policy.Priority)
|
|
|
|
msg.Index = uint32(policy.Index)
|
|
|
|
msg.Dir = uint8(policy.Dir)
|
2018-08-10 15:18:51 +00:00
|
|
|
msg.Action = uint8(policy.Action)
|
2014-09-19 02:04:48 +00:00
|
|
|
msg.Lft.SoftByteLimit = nl.XFRM_INF
|
|
|
|
msg.Lft.HardByteLimit = nl.XFRM_INF
|
|
|
|
msg.Lft.SoftPacketLimit = nl.XFRM_INF
|
|
|
|
msg.Lft.HardPacketLimit = nl.XFRM_INF
|
2014-09-01 03:27:34 +00:00
|
|
|
req.AddData(msg)
|
|
|
|
|
2014-09-19 02:04:48 +00:00
|
|
|
tmplData := make([]byte, nl.SizeofXfrmUserTmpl*len(policy.Tmpls))
|
2014-09-01 03:27:34 +00:00
|
|
|
for i, tmpl := range policy.Tmpls {
|
2014-09-19 02:04:48 +00:00
|
|
|
start := i * nl.SizeofXfrmUserTmpl
|
|
|
|
userTmpl := nl.DeserializeXfrmUserTmpl(tmplData[start : start+nl.SizeofXfrmUserTmpl])
|
2014-09-01 03:27:34 +00:00
|
|
|
userTmpl.XfrmId.Daddr.FromIP(tmpl.Dst)
|
|
|
|
userTmpl.Saddr.FromIP(tmpl.Src)
|
2022-10-05 03:23:15 +00:00
|
|
|
userTmpl.Family = uint16(nl.GetIPFamily(tmpl.Dst))
|
2014-09-01 03:27:34 +00:00
|
|
|
userTmpl.XfrmId.Proto = uint8(tmpl.Proto)
|
2016-05-25 18:10:56 +00:00
|
|
|
userTmpl.XfrmId.Spi = nl.Swap32(uint32(tmpl.Spi))
|
2014-09-01 03:27:34 +00:00
|
|
|
userTmpl.Mode = uint8(tmpl.Mode)
|
|
|
|
userTmpl.Reqid = uint32(tmpl.Reqid)
|
2021-02-23 00:51:33 +00:00
|
|
|
userTmpl.Optional = uint8(tmpl.Optional)
|
2014-09-15 01:51:44 +00:00
|
|
|
userTmpl.Aalgos = ^uint32(0)
|
|
|
|
userTmpl.Ealgos = ^uint32(0)
|
|
|
|
userTmpl.Calgos = ^uint32(0)
|
2014-09-01 03:27:34 +00:00
|
|
|
}
|
|
|
|
if len(tmplData) > 0 {
|
2014-09-19 02:04:48 +00:00
|
|
|
tmpls := nl.NewRtAttr(nl.XFRMA_TMPL, tmplData)
|
2014-09-01 03:27:34 +00:00
|
|
|
req.AddData(tmpls)
|
|
|
|
}
|
2016-05-01 03:31:59 +00:00
|
|
|
if policy.Mark != nil {
|
|
|
|
out := nl.NewRtAttr(nl.XFRMA_MARK, writeMark(policy.Mark))
|
|
|
|
req.AddData(out)
|
|
|
|
}
|
2014-09-01 03:27:34 +00:00
|
|
|
|
2022-01-17 18:36:17 +00:00
|
|
|
if policy.Ifid != 0 {
|
|
|
|
ifId := nl.NewRtAttr(nl.XFRMA_IF_ID, nl.Uint32Attr(uint32(policy.Ifid)))
|
|
|
|
req.AddData(ifId)
|
|
|
|
}
|
2019-01-02 22:56:57 +00:00
|
|
|
|
2017-10-20 20:38:07 +00:00
|
|
|
_, err := req.Execute(unix.NETLINK_XFRM, 0)
|
2014-09-01 03:27:34 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// XfrmPolicyDel will delete an xfrm policy from the system. Note that
|
|
|
|
// the Tmpls are ignored when matching the policy to delete.
|
|
|
|
// Equivalent to: `ip xfrm policy del $policy`
|
|
|
|
func XfrmPolicyDel(policy *XfrmPolicy) error {
|
2016-05-09 23:55:00 +00:00
|
|
|
return pkgHandle.XfrmPolicyDel(policy)
|
2016-05-08 18:35:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// XfrmPolicyDel will delete an xfrm policy from the system. Note that
|
|
|
|
// the Tmpls are ignored when matching the policy to delete.
|
|
|
|
// Equivalent to: `ip xfrm policy del $policy`
|
|
|
|
func (h *Handle) XfrmPolicyDel(policy *XfrmPolicy) error {
|
2016-05-12 20:16:26 +00:00
|
|
|
_, err := h.xfrmPolicyGetOrDelete(policy, nl.XFRM_MSG_DELPOLICY)
|
2014-09-01 03:27:34 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// XfrmPolicyList gets a list of xfrm policies in the system.
|
|
|
|
// Equivalent to: `ip xfrm policy show`.
|
|
|
|
// The list can be filtered by ip family.
|
Add ErrDumpInterrupted
Add a specific error to report that a netlink response had
NLM_F_DUMP_INTR set, indicating that the set of results may be
incomplete or inconsistent.
unix.EINTR was previously returned (with no results) when the
NLM_F_DUMP_INTR flag was set. Now, errors.Is(err, unix.EINTR) will
still work. But, this will be a breaking change for any code that's
checking for equality with unix.EINTR.
Return results with ErrDumpInterrupted. Results may be incomplete
or inconsistent, but give the caller the option of using them.
Look for NLM_F_DUMP_INTR in more places:
- linkSubscribeAt, neighSubscribeAt, routeSubscribeAt
- can do an initial dump, which may report inconsistent results
-> if there's an error callback, call it with ErrDumpInterrupted
- socketDiagXDPExecutor
- makes an NLM_F_DUMP request, without using Execute()
-> give it the same behaviour as functions that do use Execute()
Signed-off-by: Rob Murray <rob.murray@docker.com>
2024-09-05 08:25:13 +00:00
|
|
|
//
|
|
|
|
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
|
|
|
// or incomplete.
|
2014-09-01 03:27:34 +00:00
|
|
|
func XfrmPolicyList(family int) ([]XfrmPolicy, error) {
|
2016-05-09 23:55:00 +00:00
|
|
|
return pkgHandle.XfrmPolicyList(family)
|
2016-05-08 18:35:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// XfrmPolicyList gets a list of xfrm policies in the system.
|
|
|
|
// Equivalent to: `ip xfrm policy show`.
|
|
|
|
// The list can be filtered by ip family.
|
Add ErrDumpInterrupted
Add a specific error to report that a netlink response had
NLM_F_DUMP_INTR set, indicating that the set of results may be
incomplete or inconsistent.
unix.EINTR was previously returned (with no results) when the
NLM_F_DUMP_INTR flag was set. Now, errors.Is(err, unix.EINTR) will
still work. But, this will be a breaking change for any code that's
checking for equality with unix.EINTR.
Return results with ErrDumpInterrupted. Results may be incomplete
or inconsistent, but give the caller the option of using them.
Look for NLM_F_DUMP_INTR in more places:
- linkSubscribeAt, neighSubscribeAt, routeSubscribeAt
- can do an initial dump, which may report inconsistent results
-> if there's an error callback, call it with ErrDumpInterrupted
- socketDiagXDPExecutor
- makes an NLM_F_DUMP request, without using Execute()
-> give it the same behaviour as functions that do use Execute()
Signed-off-by: Rob Murray <rob.murray@docker.com>
2024-09-05 08:25:13 +00:00
|
|
|
//
|
|
|
|
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
|
|
|
// or incomplete.
|
2016-05-08 18:35:49 +00:00
|
|
|
func (h *Handle) XfrmPolicyList(family int) ([]XfrmPolicy, error) {
|
2017-10-20 20:38:07 +00:00
|
|
|
req := h.newNetlinkRequest(nl.XFRM_MSG_GETPOLICY, unix.NLM_F_DUMP)
|
2014-09-01 03:27:34 +00:00
|
|
|
|
2014-09-19 02:04:48 +00:00
|
|
|
msg := nl.NewIfInfomsg(family)
|
2014-09-01 03:27:34 +00:00
|
|
|
req.AddData(msg)
|
|
|
|
|
Add ErrDumpInterrupted
Add a specific error to report that a netlink response had
NLM_F_DUMP_INTR set, indicating that the set of results may be
incomplete or inconsistent.
unix.EINTR was previously returned (with no results) when the
NLM_F_DUMP_INTR flag was set. Now, errors.Is(err, unix.EINTR) will
still work. But, this will be a breaking change for any code that's
checking for equality with unix.EINTR.
Return results with ErrDumpInterrupted. Results may be incomplete
or inconsistent, but give the caller the option of using them.
Look for NLM_F_DUMP_INTR in more places:
- linkSubscribeAt, neighSubscribeAt, routeSubscribeAt
- can do an initial dump, which may report inconsistent results
-> if there's an error callback, call it with ErrDumpInterrupted
- socketDiagXDPExecutor
- makes an NLM_F_DUMP request, without using Execute()
-> give it the same behaviour as functions that do use Execute()
Signed-off-by: Rob Murray <rob.murray@docker.com>
2024-09-05 08:25:13 +00:00
|
|
|
msgs, executeErr := req.Execute(unix.NETLINK_XFRM, nl.XFRM_MSG_NEWPOLICY)
|
|
|
|
if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
|
|
|
|
return nil, executeErr
|
2014-09-01 03:27:34 +00:00
|
|
|
}
|
|
|
|
|
2015-06-19 00:41:46 +00:00
|
|
|
var res []XfrmPolicy
|
2014-09-01 03:27:34 +00:00
|
|
|
for _, m := range msgs {
|
2016-05-09 23:52:35 +00:00
|
|
|
if policy, err := parseXfrmPolicy(m, family); err == nil {
|
|
|
|
res = append(res, *policy)
|
|
|
|
} else if err == familyError {
|
2014-09-01 03:27:34 +00:00
|
|
|
continue
|
2016-05-09 23:52:35 +00:00
|
|
|
} else {
|
|
|
|
return nil, err
|
2014-09-01 03:27:34 +00:00
|
|
|
}
|
2016-05-09 23:52:35 +00:00
|
|
|
}
|
Add ErrDumpInterrupted
Add a specific error to report that a netlink response had
NLM_F_DUMP_INTR set, indicating that the set of results may be
incomplete or inconsistent.
unix.EINTR was previously returned (with no results) when the
NLM_F_DUMP_INTR flag was set. Now, errors.Is(err, unix.EINTR) will
still work. But, this will be a breaking change for any code that's
checking for equality with unix.EINTR.
Return results with ErrDumpInterrupted. Results may be incomplete
or inconsistent, but give the caller the option of using them.
Look for NLM_F_DUMP_INTR in more places:
- linkSubscribeAt, neighSubscribeAt, routeSubscribeAt
- can do an initial dump, which may report inconsistent results
-> if there's an error callback, call it with ErrDumpInterrupted
- socketDiagXDPExecutor
- makes an NLM_F_DUMP request, without using Execute()
-> give it the same behaviour as functions that do use Execute()
Signed-off-by: Rob Murray <rob.murray@docker.com>
2024-09-05 08:25:13 +00:00
|
|
|
return res, executeErr
|
2016-05-09 23:52:35 +00:00
|
|
|
}
|
2014-09-01 03:27:34 +00:00
|
|
|
|
2016-05-09 23:52:35 +00:00
|
|
|
// XfrmPolicyGet gets a the policy described by the index or selector, if found.
|
|
|
|
// Equivalent to: `ip xfrm policy get { SELECTOR | index INDEX } dir DIR [ctx CTX ] [ mark MARK [ mask MASK ] ] [ ptype PTYPE ]`.
|
|
|
|
func XfrmPolicyGet(policy *XfrmPolicy) (*XfrmPolicy, error) {
|
2016-05-12 20:16:26 +00:00
|
|
|
return pkgHandle.XfrmPolicyGet(policy)
|
2016-05-09 23:52:35 +00:00
|
|
|
}
|
2014-09-01 03:27:34 +00:00
|
|
|
|
2016-05-09 23:52:35 +00:00
|
|
|
// XfrmPolicyGet gets a the policy described by the index or selector, if found.
|
|
|
|
// Equivalent to: `ip xfrm policy get { SELECTOR | index INDEX } dir DIR [ctx CTX ] [ mark MARK [ mask MASK ] ] [ ptype PTYPE ]`.
|
|
|
|
func (h *Handle) XfrmPolicyGet(policy *XfrmPolicy) (*XfrmPolicy, error) {
|
2016-05-12 20:16:26 +00:00
|
|
|
return h.xfrmPolicyGetOrDelete(policy, nl.XFRM_MSG_GETPOLICY)
|
|
|
|
}
|
2014-09-01 03:27:34 +00:00
|
|
|
|
2016-05-13 23:42:24 +00:00
|
|
|
// XfrmPolicyFlush will flush the policies on the system.
|
|
|
|
// Equivalent to: `ip xfrm policy flush`
|
|
|
|
func XfrmPolicyFlush() error {
|
|
|
|
return pkgHandle.XfrmPolicyFlush()
|
|
|
|
}
|
|
|
|
|
|
|
|
// XfrmPolicyFlush will flush the policies on the system.
|
|
|
|
// Equivalent to: `ip xfrm policy flush`
|
|
|
|
func (h *Handle) XfrmPolicyFlush() error {
|
2017-10-20 20:38:07 +00:00
|
|
|
req := h.newNetlinkRequest(nl.XFRM_MSG_FLUSHPOLICY, unix.NLM_F_ACK)
|
|
|
|
_, err := req.Execute(unix.NETLINK_XFRM, 0)
|
2016-05-13 23:42:24 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2016-05-12 20:16:26 +00:00
|
|
|
func (h *Handle) xfrmPolicyGetOrDelete(policy *XfrmPolicy, nlProto int) (*XfrmPolicy, error) {
|
2017-10-20 20:38:07 +00:00
|
|
|
req := h.newNetlinkRequest(nlProto, unix.NLM_F_ACK)
|
2016-05-12 20:16:26 +00:00
|
|
|
|
|
|
|
msg := &nl.XfrmUserpolicyId{}
|
2016-05-09 23:52:35 +00:00
|
|
|
selFromPolicy(&msg.Sel, policy)
|
|
|
|
msg.Index = uint32(policy.Index)
|
|
|
|
msg.Dir = uint8(policy.Dir)
|
|
|
|
req.AddData(msg)
|
2014-09-01 03:27:34 +00:00
|
|
|
|
2016-05-12 20:16:26 +00:00
|
|
|
if policy.Mark != nil {
|
|
|
|
out := nl.NewRtAttr(nl.XFRMA_MARK, writeMark(policy.Mark))
|
|
|
|
req.AddData(out)
|
|
|
|
}
|
|
|
|
|
2022-01-17 18:36:17 +00:00
|
|
|
if policy.Ifid != 0 {
|
|
|
|
ifId := nl.NewRtAttr(nl.XFRMA_IF_ID, nl.Uint32Attr(uint32(policy.Ifid)))
|
|
|
|
req.AddData(ifId)
|
|
|
|
}
|
2019-01-02 22:56:57 +00:00
|
|
|
|
2016-05-12 20:16:26 +00:00
|
|
|
resType := nl.XFRM_MSG_NEWPOLICY
|
|
|
|
if nlProto == nl.XFRM_MSG_DELPOLICY {
|
|
|
|
resType = 0
|
|
|
|
}
|
|
|
|
|
2017-10-20 20:38:07 +00:00
|
|
|
msgs, err := req.Execute(unix.NETLINK_XFRM, uint16(resType))
|
2016-05-09 23:52:35 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2016-05-12 20:16:26 +00:00
|
|
|
if nlProto == nl.XFRM_MSG_DELPOLICY {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2018-09-30 20:42:25 +00:00
|
|
|
return parseXfrmPolicy(msgs[0], FAMILY_ALL)
|
2016-05-09 23:52:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func parseXfrmPolicy(m []byte, family int) (*XfrmPolicy, error) {
|
|
|
|
msg := nl.DeserializeXfrmUserpolicyInfo(m)
|
|
|
|
|
|
|
|
// This is mainly for the policy dump
|
|
|
|
if family != FAMILY_ALL && family != int(msg.Sel.Family) {
|
|
|
|
return nil, familyError
|
|
|
|
}
|
|
|
|
|
|
|
|
var policy XfrmPolicy
|
|
|
|
|
2022-10-05 03:23:15 +00:00
|
|
|
policy.Dst = msg.Sel.Daddr.ToIPNet(msg.Sel.PrefixlenD, uint16(family))
|
|
|
|
policy.Src = msg.Sel.Saddr.ToIPNet(msg.Sel.PrefixlenS, uint16(family))
|
2016-05-09 23:52:35 +00:00
|
|
|
policy.Proto = Proto(msg.Sel.Proto)
|
|
|
|
policy.DstPort = int(nl.Swap16(msg.Sel.Dport))
|
|
|
|
policy.SrcPort = int(nl.Swap16(msg.Sel.Sport))
|
2018-08-10 15:18:51 +00:00
|
|
|
policy.Ifindex = int(msg.Sel.Ifindex)
|
2016-05-09 23:52:35 +00:00
|
|
|
policy.Priority = int(msg.Priority)
|
|
|
|
policy.Index = int(msg.Index)
|
|
|
|
policy.Dir = Dir(msg.Dir)
|
2018-08-10 15:18:51 +00:00
|
|
|
policy.Action = PolicyAction(msg.Action)
|
2016-05-09 23:52:35 +00:00
|
|
|
|
|
|
|
attrs, err := nl.ParseRouteAttr(m[msg.Len():])
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, attr := range attrs {
|
|
|
|
switch attr.Attr.Type {
|
|
|
|
case nl.XFRMA_TMPL:
|
|
|
|
max := len(attr.Value)
|
|
|
|
for i := 0; i < max; i += nl.SizeofXfrmUserTmpl {
|
|
|
|
var resTmpl XfrmPolicyTmpl
|
|
|
|
tmpl := nl.DeserializeXfrmUserTmpl(attr.Value[i : i+nl.SizeofXfrmUserTmpl])
|
|
|
|
resTmpl.Dst = tmpl.XfrmId.Daddr.ToIP()
|
|
|
|
resTmpl.Src = tmpl.Saddr.ToIP()
|
|
|
|
resTmpl.Proto = Proto(tmpl.XfrmId.Proto)
|
|
|
|
resTmpl.Mode = Mode(tmpl.Mode)
|
2016-05-25 18:10:56 +00:00
|
|
|
resTmpl.Spi = int(nl.Swap32(tmpl.XfrmId.Spi))
|
2016-05-09 23:52:35 +00:00
|
|
|
resTmpl.Reqid = int(tmpl.Reqid)
|
2021-02-23 00:51:33 +00:00
|
|
|
resTmpl.Optional = int(tmpl.Optional)
|
2016-05-09 23:52:35 +00:00
|
|
|
policy.Tmpls = append(policy.Tmpls, resTmpl)
|
2014-09-01 03:27:34 +00:00
|
|
|
}
|
2016-05-09 23:52:35 +00:00
|
|
|
case nl.XFRMA_MARK:
|
|
|
|
mark := nl.DeserializeXfrmMark(attr.Value[:])
|
|
|
|
policy.Mark = new(XfrmMark)
|
|
|
|
policy.Mark.Value = mark.Value
|
|
|
|
policy.Mark.Mask = mark.Mask
|
2019-01-02 22:56:57 +00:00
|
|
|
case nl.XFRMA_IF_ID:
|
|
|
|
policy.Ifid = int(native.Uint32(attr.Value))
|
2014-09-01 03:27:34 +00:00
|
|
|
}
|
|
|
|
}
|
2016-05-09 23:52:35 +00:00
|
|
|
|
|
|
|
return &policy, nil
|
2014-09-01 03:27:34 +00:00
|
|
|
}
|