From 43948793f6d3a2c029b5bd3399d70904b910d668 Mon Sep 17 00:00:00 2001 From: Martynas Pumputis Date: Mon, 30 Jan 2017 11:36:23 +0000 Subject: [PATCH] Add support of ESN --- nl/xfrm_state_linux.go | 55 +++++++++++++++++++++++++++++++++++------- xfrm_state.go | 5 ++-- xfrm_state_linux.go | 29 ++++++++++++++++++++++ 3 files changed, 78 insertions(+), 11 deletions(-) diff --git a/nl/xfrm_state_linux.go b/nl/xfrm_state_linux.go index e5b9a09..b6290fd 100644 --- a/nl/xfrm_state_linux.go +++ b/nl/xfrm_state_linux.go @@ -5,15 +5,27 @@ import ( ) const ( - SizeofXfrmUsersaId = 0x18 - SizeofXfrmStats = 0x0c - SizeofXfrmUsersaInfo = 0xe0 - SizeofXfrmUserSpiInfo = 0xe8 - SizeofXfrmAlgo = 0x44 - SizeofXfrmAlgoAuth = 0x48 - SizeofXfrmAlgoAEAD = 0x48 - SizeofXfrmEncapTmpl = 0x18 - SizeofXfrmUsersaFlush = 0x8 + SizeofXfrmUsersaId = 0x18 + SizeofXfrmStats = 0x0c + SizeofXfrmUsersaInfo = 0xe0 + SizeofXfrmUserSpiInfo = 0xe8 + SizeofXfrmAlgo = 0x44 + SizeofXfrmAlgoAuth = 0x48 + SizeofXfrmAlgoAEAD = 0x48 + SizeofXfrmEncapTmpl = 0x18 + SizeofXfrmUsersaFlush = 0x8 + SizeofXfrmReplayStateEsn = 0x18 +) + +const ( + XFRM_STATE_NOECN = 1 + XFRM_STATE_DECAP_DSCP = 2 + XFRM_STATE_NOPMTUDISC = 4 + XFRM_STATE_WILDRECV = 8 + XFRM_STATE_ICMP = 16 + XFRM_STATE_AF_UNSPEC = 32 + XFRM_STATE_ALIGN4 = 64 + XFRM_STATE_ESN = 128 ) // struct xfrm_usersa_id { @@ -295,3 +307,28 @@ func DeserializeXfrmUsersaFlush(b []byte) *XfrmUsersaFlush { func (msg *XfrmUsersaFlush) Serialize() []byte { return (*(*[SizeofXfrmUsersaFlush]byte)(unsafe.Pointer(msg)))[:] } + +// struct xfrm_replay_state_esn { +// unsigned int bmp_len; +// __u32 oseq; +// __u32 seq; +// __u32 oseq_hi; +// __u32 seq_hi; +// __u32 replay_window; +// __u32 bmp[0]; +// }; + +type XfrmReplayStateEsn struct { + BmpLen uint32 + OSeq uint32 + Seq uint32 + OSeqHi uint32 + SeqHi uint32 + ReplayWindow uint32 + Bmp []uint32 +} + +func (msg *XfrmReplayStateEsn) Serialize() []byte { + // We deliberately do not pass Bmp, as it gets set by the kernel. + return (*(*[SizeofXfrmReplayStateEsn]byte)(unsafe.Pointer(msg)))[:] +} diff --git a/xfrm_state.go b/xfrm_state.go index e25cde2..368a9b9 100644 --- a/xfrm_state.go +++ b/xfrm_state.go @@ -83,11 +83,12 @@ type XfrmState struct { Crypt *XfrmStateAlgo Aead *XfrmStateAlgo Encap *XfrmStateEncap + ESN bool } func (sa XfrmState) String() string { - return fmt.Sprintf("Dst: %v, Src: %v, Proto: %s, Mode: %s, SPI: 0x%x, ReqID: 0x%x, ReplayWindow: %d, Mark: %v, Auth: %v, Crypt: %v, Aead: %v,Encap: %v", - sa.Dst, sa.Src, sa.Proto, sa.Mode, sa.Spi, sa.Reqid, sa.ReplayWindow, sa.Mark, sa.Auth, sa.Crypt, sa.Aead, sa.Encap) + return fmt.Sprintf("Dst: %v, Src: %v, Proto: %s, Mode: %s, SPI: 0x%x, ReqID: 0x%x, ReplayWindow: %d, Mark: %v, Auth: %v, Crypt: %v, Aead: %v, Encap: %v, ESN: %t", + sa.Dst, sa.Src, sa.Proto, sa.Mode, sa.Spi, sa.Reqid, sa.ReplayWindow, sa.Mark, sa.Auth, sa.Crypt, sa.Aead, sa.Encap, sa.ESN) } func (sa XfrmState) Print(stats bool) string { if !stats { diff --git a/xfrm_state_linux.go b/xfrm_state_linux.go index dda4970..6a7bc0d 100644 --- a/xfrm_state_linux.go +++ b/xfrm_state_linux.go @@ -60,6 +60,21 @@ func writeMark(m *XfrmMark) []byte { return mark.Serialize() } +func writeReplayEsn(replayWindow int) []byte { + replayEsn := &nl.XfrmReplayStateEsn{ + OSeq: 0, + Seq: 0, + OSeqHi: 0, + SeqHi: 0, + ReplayWindow: uint32(replayWindow), + } + + // taken from iproute2/ip/xfrm_state.c: + replayEsn.BmpLen = uint32((replayWindow + (4 * 8) - 1) / (4 * 8)) + + return replayEsn.Serialize() +} + // XfrmStateAdd will add an xfrm state to the system. // Equivalent to: `ip xfrm state add $state` func XfrmStateAdd(state *XfrmState) error { @@ -91,6 +106,7 @@ func (h *Handle) XfrmStateUpdate(state *XfrmState) error { } func (h *Handle) xfrmStateAddOrUpdate(state *XfrmState, nlProto int) error { + // A state with spi 0 can't be deleted so don't allow it to be set if state.Spi == 0 { return fmt.Errorf("Spi must be set when adding xfrm state.") @@ -98,6 +114,15 @@ func (h *Handle) xfrmStateAddOrUpdate(state *XfrmState, nlProto int) error { req := h.newNetlinkRequest(nlProto, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) msg := xfrmUsersaInfoFromXfrmState(state) + + if state.ESN { + if state.ReplayWindow == 0 { + return fmt.Errorf("ESN flag set without ReplayWindow") + } + msg.Flags |= nl.XFRM_STATE_ESN + msg.ReplayWindow = 0 + } + limitsToLft(state.Limits, &msg.Lft) req.AddData(msg) @@ -127,6 +152,10 @@ func (h *Handle) xfrmStateAddOrUpdate(state *XfrmState, nlProto int) error { out := nl.NewRtAttr(nl.XFRMA_MARK, writeMark(state.Mark)) req.AddData(out) } + if state.ESN { + out := nl.NewRtAttr(nl.XFRMA_REPLAY_ESN_VAL, writeReplayEsn(state.ReplayWindow)) + req.AddData(out) + } _, err := req.Execute(syscall.NETLINK_XFRM, 0) return err