Skip to content

Commit

Permalink
Add support for action and ifindex in XFRM policy
Browse files Browse the repository at this point in the history
The action and ifindex fields aren't represented in the XfrmPolicy type
although they exist in the the linux equivalent data structures.   They
are represented in the serialized versions of those datatypes.  So this
patch simply exposes those fields to the user-consumable side of the
API.  This patch makes the policy's action a specific type in the same
style as the Dir field in XfrmPolicy.

Update the existing unit tests to compare Ifindex and Action fields in
the XFRM structure.  Verify that the default policy returns an action of
ALLOW and an ifindex of 0.  Add a unit test to add and read back a
policy to the loopback interface (ifindex 1) with action "block".

Signed-off-by: Chris Telfer <ctelfer@docker.com>
  • Loading branch information
ctelfer authored and aboch committed Aug 14, 2018
1 parent 9eab419 commit 8aa85bf
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 2 deletions.
25 changes: 23 additions & 2 deletions xfrm_policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,25 @@ func (d Dir) String() string {
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.
Expand Down Expand Up @@ -64,11 +83,13 @@ type XfrmPolicy struct {
Dir Dir
Priority int
Index int
Action PolicyAction
Ifindex 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, Mark: %s, Tmpls: %s}",
p.Dst, p.Src, p.Proto, p.DstPort, p.SrcPort, p.Dir, p.Priority, p.Index, p.Mark, p.Tmpls)
return fmt.Sprintf("{Dst: %v, Src: %v, Proto: %s, DstPort: %d, SrcPort: %d, Dir: %s, Priority: %d, Index: %d, Action: %s, Ifindex: %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.Mark, p.Tmpls)
}
4 changes: 4 additions & 0 deletions xfrm_policy_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ func selFromPolicy(sel *nl.XfrmSelector, policy *XfrmPolicy) {
if sel.Sport != 0 {
sel.SportMask = ^uint16(0)
}
sel.Ifindex = int32(policy.Ifindex)
}

// XfrmPolicyAdd will add an xfrm policy to the system.
Expand Down Expand Up @@ -61,6 +62,7 @@ func (h *Handle) xfrmPolicyAddOrUpdate(policy *XfrmPolicy, nlProto int) error {
msg.Priority = uint32(policy.Priority)
msg.Index = uint32(policy.Index)
msg.Dir = uint8(policy.Dir)
msg.Action = uint8(policy.Action)
msg.Lft.SoftByteLimit = nl.XFRM_INF
msg.Lft.HardByteLimit = nl.XFRM_INF
msg.Lft.SoftPacketLimit = nl.XFRM_INF
Expand Down Expand Up @@ -220,9 +222,11 @@ func parseXfrmPolicy(m []byte, family int) (*XfrmPolicy, error) {
policy.Proto = Proto(msg.Sel.Proto)
policy.DstPort = int(nl.Swap16(msg.Sel.Dport))
policy.SrcPort = int(nl.Swap16(msg.Sel.Sport))
policy.Ifindex = int(msg.Sel.Ifindex)
policy.Priority = int(msg.Priority)
policy.Index = int(msg.Index)
policy.Dir = Dir(msg.Dir)
policy.Action = PolicyAction(msg.Action)

attrs, err := nl.ParseRouteAttr(m[msg.Len():])
if err != nil {
Expand Down
33 changes: 33 additions & 0 deletions xfrm_policy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ func TestXfrmPolicyAddUpdateDel(t *testing.T) {
t.Fatalf("unexpected policy returned.\nExpected: %v.\nGot %v", policy, policies[0])
}

if policies[0].Ifindex != 0 {
t.Fatalf("default policy has a non-zero interface index.\nGot %d", policies[0].Ifindex)
}

if policies[0].Action != XFRM_POLICY_ALLOW {
t.Fatalf("default policy has non-allow action.\nGot %s", policies[0].Action)
}

// Look for a specific policy
sp, err := XfrmPolicyGet(policy)
if err != nil {
Expand Down Expand Up @@ -129,6 +137,30 @@ func TestXfrmPolicyFlush(t *testing.T) {

}

func TestXfrmPolicyBlockWithIfindex(t *testing.T) {
defer setUpNetlinkTest(t)()

pBlock := getPolicy()
pBlock.Action = XFRM_POLICY_BLOCK
pBlock.Ifindex = 1 // loopback interface
if err := XfrmPolicyAdd(pBlock); err != nil {
t.Fatal(err)
}
policies, err := XfrmPolicyList(FAMILY_ALL)
if err != nil {
t.Fatal(err)
}
if len(policies) != 1 {
t.Fatalf("unexpected number of policies: %d", len(policies))
}
if !comparePolicies(pBlock, &policies[0]) {
t.Fatalf("unexpected policy returned.\nExpected: %v.\nGot %v", pBlock, policies[0])
}
if err = XfrmPolicyDel(pBlock); err != nil {
t.Fatal(err)
}
}

func comparePolicies(a, b *XfrmPolicy) bool {
if a == b {
return true
Expand All @@ -139,6 +171,7 @@ func comparePolicies(a, b *XfrmPolicy) bool {
// Do not check Index which is assigned by kernel
return a.Dir == b.Dir && a.Priority == b.Priority &&
compareIPNet(a.Src, b.Src) && compareIPNet(a.Dst, b.Dst) &&
a.Action == b.Action && a.Ifindex == b.Ifindex &&
a.Mark.Value == b.Mark.Value && a.Mark.Mask == b.Mark.Mask &&
compareTemplates(a.Tmpls, b.Tmpls)
}
Expand Down

0 comments on commit 8aa85bf

Please sign in to comment.