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

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