github.com/vishvananda/netlink@v1.3.1/xfrm_policy_linux.go (about)

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