mirror of https://github.com/vishvananda/netlink
Add XfrmMonitor
The implementation subscribes only to XFRMNLGRP_EXPIRE.
This commit is contained in:
parent
ebdfb74020
commit
9a7970b3b6
|
@ -11,34 +11,40 @@ const (
|
|||
XFRM_INF = ^uint64(0)
|
||||
)
|
||||
|
||||
type XfrmMsgType uint8
|
||||
|
||||
type XfrmMsg interface {
|
||||
Type() XfrmMsgType
|
||||
}
|
||||
|
||||
// Message Types
|
||||
const (
|
||||
XFRM_MSG_BASE = 0x10
|
||||
XFRM_MSG_NEWSA = 0x10
|
||||
XFRM_MSG_DELSA = 0x11
|
||||
XFRM_MSG_GETSA = 0x12
|
||||
XFRM_MSG_NEWPOLICY = 0x13
|
||||
XFRM_MSG_DELPOLICY = 0x14
|
||||
XFRM_MSG_GETPOLICY = 0x15
|
||||
XFRM_MSG_ALLOCSPI = 0x16
|
||||
XFRM_MSG_ACQUIRE = 0x17
|
||||
XFRM_MSG_EXPIRE = 0x18
|
||||
XFRM_MSG_UPDPOLICY = 0x19
|
||||
XFRM_MSG_UPDSA = 0x1a
|
||||
XFRM_MSG_POLEXPIRE = 0x1b
|
||||
XFRM_MSG_FLUSHSA = 0x1c
|
||||
XFRM_MSG_FLUSHPOLICY = 0x1d
|
||||
XFRM_MSG_NEWAE = 0x1e
|
||||
XFRM_MSG_GETAE = 0x1f
|
||||
XFRM_MSG_REPORT = 0x20
|
||||
XFRM_MSG_MIGRATE = 0x21
|
||||
XFRM_MSG_NEWSADINFO = 0x22
|
||||
XFRM_MSG_GETSADINFO = 0x23
|
||||
XFRM_MSG_NEWSPDINFO = 0x24
|
||||
XFRM_MSG_GETSPDINFO = 0x25
|
||||
XFRM_MSG_MAPPING = 0x26
|
||||
XFRM_MSG_MAX = 0x26
|
||||
XFRM_NR_MSGTYPES = 0x17
|
||||
XFRM_MSG_BASE XfrmMsgType = 0x10
|
||||
XFRM_MSG_NEWSA = 0x10
|
||||
XFRM_MSG_DELSA = 0x11
|
||||
XFRM_MSG_GETSA = 0x12
|
||||
XFRM_MSG_NEWPOLICY = 0x13
|
||||
XFRM_MSG_DELPOLICY = 0x14
|
||||
XFRM_MSG_GETPOLICY = 0x15
|
||||
XFRM_MSG_ALLOCSPI = 0x16
|
||||
XFRM_MSG_ACQUIRE = 0x17
|
||||
XFRM_MSG_EXPIRE = 0x18
|
||||
XFRM_MSG_UPDPOLICY = 0x19
|
||||
XFRM_MSG_UPDSA = 0x1a
|
||||
XFRM_MSG_POLEXPIRE = 0x1b
|
||||
XFRM_MSG_FLUSHSA = 0x1c
|
||||
XFRM_MSG_FLUSHPOLICY = 0x1d
|
||||
XFRM_MSG_NEWAE = 0x1e
|
||||
XFRM_MSG_GETAE = 0x1f
|
||||
XFRM_MSG_REPORT = 0x20
|
||||
XFRM_MSG_MIGRATE = 0x21
|
||||
XFRM_MSG_NEWSADINFO = 0x22
|
||||
XFRM_MSG_GETSADINFO = 0x23
|
||||
XFRM_MSG_NEWSPDINFO = 0x24
|
||||
XFRM_MSG_GETSPDINFO = 0x25
|
||||
XFRM_MSG_MAPPING = 0x26
|
||||
XFRM_MSG_MAX = 0x26
|
||||
XFRM_NR_MSGTYPES = 0x17
|
||||
)
|
||||
|
||||
// Attribute types
|
||||
|
@ -81,6 +87,20 @@ const (
|
|||
SizeofXfrmMark = 0x08
|
||||
)
|
||||
|
||||
// Netlink groups
|
||||
const (
|
||||
XFRMNLGRP_NONE = 0x0
|
||||
XFRMNLGRP_ACQUIRE = 0x1
|
||||
XFRMNLGRP_EXPIRE = 0x2
|
||||
XFRMNLGRP_SA = 0x3
|
||||
XFRMNLGRP_POLICY = 0x4
|
||||
XFRMNLGRP_AEVENTS = 0x5
|
||||
XFRMNLGRP_REPORT = 0x6
|
||||
XFRMNLGRP_MIGRATE = 0x7
|
||||
XFRMNLGRP_MAPPING = 0x8
|
||||
__XFRMNLGRP_MAX = 0x9
|
||||
)
|
||||
|
||||
// typedef union {
|
||||
// __be32 a4;
|
||||
// __be32 a6[4];
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
package nl
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
SizeofXfrmUserExpire = 0xe8
|
||||
)
|
||||
|
||||
// struct xfrm_user_expire {
|
||||
// struct xfrm_usersa_info state;
|
||||
// __u8 hard;
|
||||
// };
|
||||
|
||||
type XfrmUserExpire struct {
|
||||
XfrmUsersaInfo XfrmUsersaInfo
|
||||
Hard uint8
|
||||
Pad [7]byte
|
||||
}
|
||||
|
||||
func (msg *XfrmUserExpire) Len() int {
|
||||
return SizeofXfrmUserExpire
|
||||
}
|
||||
|
||||
func DeserializeXfrmUserExpire(b []byte) *XfrmUserExpire {
|
||||
return (*XfrmUserExpire)(unsafe.Pointer(&b[0:SizeofXfrmUserExpire][0]))
|
||||
}
|
||||
|
||||
func (msg *XfrmUserExpire) Serialize() []byte {
|
||||
return (*(*[SizeofXfrmUserExpire]byte)(unsafe.Pointer(msg)))[:]
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package nl
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func (msg *XfrmUserExpire) write(b []byte) {
|
||||
msg.XfrmUsersaInfo.write(b[0:SizeofXfrmUsersaInfo])
|
||||
b[SizeofXfrmUsersaInfo] = msg.Hard
|
||||
copy(b[SizeofXfrmUsersaInfo+1:SizeofXfrmUserExpire], msg.Pad[:])
|
||||
}
|
||||
|
||||
func (msg *XfrmUserExpire) serializeSafe() []byte {
|
||||
b := make([]byte, SizeofXfrmUserExpire)
|
||||
msg.write(b)
|
||||
return b
|
||||
}
|
||||
|
||||
func deserializeXfrmUserExpireSafe(b []byte) *XfrmUserExpire {
|
||||
var msg = XfrmUserExpire{}
|
||||
binary.Read(bytes.NewReader(b[0:SizeofXfrmUserExpire]), NativeEndian(), &msg)
|
||||
return &msg
|
||||
}
|
||||
|
||||
func TestXfrmUserExpireDeserializeSerialize(t *testing.T) {
|
||||
var orig = make([]byte, SizeofXfrmUserExpire)
|
||||
rand.Read(orig)
|
||||
safemsg := deserializeXfrmUserExpireSafe(orig)
|
||||
msg := DeserializeXfrmUserExpire(orig)
|
||||
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
package netlink
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"syscall"
|
||||
|
||||
"github.com/vishvananda/netns"
|
||||
|
||||
"github.com/vishvananda/netlink/nl"
|
||||
)
|
||||
|
||||
type XfrmMsg interface {
|
||||
Type() nl.XfrmMsgType
|
||||
}
|
||||
|
||||
type XfrmMsgExpire struct {
|
||||
XfrmState *XfrmState
|
||||
Hard bool
|
||||
}
|
||||
|
||||
func (ue *XfrmMsgExpire) Type() nl.XfrmMsgType {
|
||||
return nl.XFRM_MSG_EXPIRE
|
||||
}
|
||||
|
||||
func parseXfrmMsgExpire(b []byte) *XfrmMsgExpire {
|
||||
var e XfrmMsgExpire
|
||||
|
||||
msg := nl.DeserializeXfrmUserExpire(b)
|
||||
e.XfrmState = xfrmStateFromXfrmUsersaInfo(&msg.XfrmUsersaInfo)
|
||||
e.Hard = msg.Hard == 1
|
||||
|
||||
return &e
|
||||
}
|
||||
|
||||
func XfrmMonitor(ch chan<- XfrmMsg, done <-chan struct{}, errorChan chan<- error,
|
||||
types ...nl.XfrmMsgType) error {
|
||||
|
||||
groups, err := xfrmMcastGroups(types)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
s, err := nl.SubscribeAt(netns.None(), netns.None(), syscall.NETLINK_XFRM, groups...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if done != nil {
|
||||
go func() {
|
||||
<-done
|
||||
s.Close()
|
||||
}()
|
||||
|
||||
}
|
||||
|
||||
go func() {
|
||||
defer close(ch)
|
||||
for {
|
||||
msgs, err := s.Receive()
|
||||
if err != nil {
|
||||
errorChan <- err
|
||||
return
|
||||
}
|
||||
for _, m := range msgs {
|
||||
switch m.Header.Type {
|
||||
case nl.XFRM_MSG_EXPIRE:
|
||||
ch <- parseXfrmMsgExpire(m.Data)
|
||||
default:
|
||||
errorChan <- fmt.Errorf("unsupported msg type: %x", m.Header.Type)
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func xfrmMcastGroups(types []nl.XfrmMsgType) ([]uint, error) {
|
||||
groups := make([]uint, 0)
|
||||
|
||||
if len(types) == 0 {
|
||||
return nil, fmt.Errorf("no xfrm msg type specified")
|
||||
}
|
||||
|
||||
for _, t := range types {
|
||||
var group uint
|
||||
|
||||
switch t {
|
||||
case nl.XFRM_MSG_EXPIRE:
|
||||
group = nl.XFRMNLGRP_EXPIRE
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported group: %x", t)
|
||||
}
|
||||
|
||||
groups = append(groups, group)
|
||||
}
|
||||
|
||||
return groups, nil
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package netlink
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/vishvananda/netlink/nl"
|
||||
)
|
||||
|
||||
func TestXfrmMonitorExpire(t *testing.T) {
|
||||
setUpNetlinkTest(t)()
|
||||
|
||||
ch := make(chan XfrmMsg)
|
||||
done := make(chan struct{})
|
||||
defer close(done)
|
||||
errChan := make(chan error)
|
||||
if err := XfrmMonitor(ch, nil, errChan, nl.XFRM_MSG_EXPIRE); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Program state with limits
|
||||
state := getBaseState()
|
||||
state.Limits.TimeHard = 2
|
||||
state.Limits.TimeSoft = 1
|
||||
if err := XfrmStateAdd(state); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
msg := (<-ch).(*XfrmMsgExpire)
|
||||
if msg.XfrmState.Spi != state.Spi || msg.Hard {
|
||||
t.Fatal("Received unexpected msg")
|
||||
}
|
||||
|
||||
msg = (<-ch).(*XfrmMsgExpire)
|
||||
if msg.XfrmState.Spi != state.Spi || !msg.Hard {
|
||||
t.Fatal("Received unexpected msg")
|
||||
}
|
||||
}
|
|
@ -241,14 +241,7 @@ func (h *Handle) xfrmStateGetOrDelete(state *XfrmState, nlProto int) (*XfrmState
|
|||
|
||||
var familyError = fmt.Errorf("family error")
|
||||
|
||||
func parseXfrmState(m []byte, family int) (*XfrmState, error) {
|
||||
msg := nl.DeserializeXfrmUsersaInfo(m)
|
||||
|
||||
// This is mainly for the state dump
|
||||
if family != FAMILY_ALL && family != int(msg.Family) {
|
||||
return nil, familyError
|
||||
}
|
||||
|
||||
func xfrmStateFromXfrmUsersaInfo(msg *nl.XfrmUsersaInfo) *XfrmState {
|
||||
var state XfrmState
|
||||
|
||||
state.Dst = msg.Id.Daddr.ToIP()
|
||||
|
@ -260,6 +253,19 @@ func parseXfrmState(m []byte, family int) (*XfrmState, error) {
|
|||
state.ReplayWindow = int(msg.ReplayWindow)
|
||||
lftToLimits(&msg.Lft, &state.Limits)
|
||||
|
||||
return &state
|
||||
}
|
||||
|
||||
func parseXfrmState(m []byte, family int) (*XfrmState, error) {
|
||||
msg := nl.DeserializeXfrmUsersaInfo(m)
|
||||
|
||||
// This is mainly for the state dump
|
||||
if family != FAMILY_ALL && family != int(msg.Family) {
|
||||
return nil, familyError
|
||||
}
|
||||
|
||||
state := xfrmStateFromXfrmUsersaInfo(msg)
|
||||
|
||||
attrs, err := nl.ParseRouteAttr(m[nl.SizeofXfrmUsersaInfo:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -310,7 +316,7 @@ func parseXfrmState(m []byte, family int) (*XfrmState, error) {
|
|||
}
|
||||
}
|
||||
|
||||
return &state, nil
|
||||
return state, nil
|
||||
}
|
||||
|
||||
// XfrmStateFlush will flush the xfrm state on the system.
|
||||
|
|
Loading…
Reference in New Issue