From 1a26b9f2515ffdb6270fb1c5b125179c950ec7dd Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Thu, 18 Sep 2014 19:04:48 -0700 Subject: [PATCH] Move all low level calls into nl subpackage --- addr_linux.go | 68 +--- link_linux.go | 137 +++----- netlink.go | 26 +- netlink_test.go | 22 -- nl/addr_linux.go | 48 +++ addr_linux_test.go => nl/addr_linux_test.go | 6 +- netlink_linux.go => nl/nl_linux.go | 55 +++- netlink_linux_test.go => nl/nl_linux_test.go | 26 +- nl/route_linux.go | 34 ++ route_linux_test.go => nl/route_linux_test.go | 6 +- xfrm_linux.go => nl/xfrm_linux.go | 22 +- xfrm_linux_test.go => nl/xfrm_linux_test.go | 20 +- nl/xfrm_policy_linux.go | 120 +++++++ .../xfrm_policy_linux_test.go | 14 +- nl/xfrm_state_linux.go | 222 +++++++++++++ .../xfrm_state_linux_test.go | 28 +- route_linux.go | 66 ++-- xfrm_policy_linux.go | 167 ++-------- xfrm_state_linux.go | 299 +++--------------- 19 files changed, 691 insertions(+), 695 deletions(-) create mode 100644 nl/addr_linux.go rename addr_linux_test.go => nl/addr_linux_test.go (87%) rename netlink_linux.go => nl/nl_linux.go (85%) rename netlink_linux_test.go => nl/nl_linux_test.go (56%) create mode 100644 nl/route_linux.go rename route_linux_test.go => nl/route_linux_test.go (87%) rename xfrm_linux.go => nl/xfrm_linux.go (90%) rename xfrm_linux_test.go => nl/xfrm_linux_test.go (90%) create mode 100644 nl/xfrm_policy_linux.go rename xfrm_policy_linux_test.go => nl/xfrm_policy_linux_test.go (91%) create mode 100644 nl/xfrm_state_linux.go rename xfrm_state_linux_test.go => nl/xfrm_state_linux_test.go (89%) diff --git a/addr_linux.go b/addr_linux.go index cbd061b..0333d25 100644 --- a/addr_linux.go +++ b/addr_linux.go @@ -5,74 +5,34 @@ import ( "net" "strings" "syscall" - "unsafe" + + "github.com/vishvananda/netlink/nl" ) -type IfAddrmsg struct { - syscall.IfAddrmsg -} - -func newIfAddrmsg(family int) *IfAddrmsg { - return &IfAddrmsg{ - IfAddrmsg: syscall.IfAddrmsg{ - Family: uint8(family), - }, - } -} - -// struct ifaddrmsg { -// __u8 ifa_family; -// __u8 ifa_prefixlen; /* The prefix length */ -// __u8 ifa_flags; /* Flags */ -// __u8 ifa_scope; /* Address scope */ -// __u32 ifa_index; /* Link index */ -// }; - -// type IfAddrmsg struct { -// Family uint8 -// Prefixlen uint8 -// Flags uint8 -// Scope uint8 -// Index uint32 -// } -// SizeofIfAddrmsg = 0x8 - -func DeserializeIfAddrmsg(b []byte) *IfAddrmsg { - return (*IfAddrmsg)(unsafe.Pointer(&b[0:syscall.SizeofIfAddrmsg][0])) -} - -func (msg *IfAddrmsg) Serialize() []byte { - return (*(*[syscall.SizeofIfAddrmsg]byte)(unsafe.Pointer(msg)))[:] -} - -func (msg *IfAddrmsg) Len() int { - return syscall.SizeofIfAddrmsg -} - // AddrAdd will add an IP address to a link device. // Equivalent to: `ip addr del $addr dev $link` func AddrAdd(link *Link, addr *Addr) error { - req := newNetlinkRequest(syscall.RTM_NEWADDR, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) + req := nl.NewNetlinkRequest(syscall.RTM_NEWADDR, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) return addrHandle(link, addr, req) } // AddrDel will delete an IP address from a link device. // Equivalent to: `ip addr del $addr dev $link` func AddrDel(link *Link, addr *Addr) error { - req := newNetlinkRequest(syscall.RTM_DELADDR, syscall.NLM_F_ACK) + req := nl.NewNetlinkRequest(syscall.RTM_DELADDR, syscall.NLM_F_ACK) return addrHandle(link, addr, req) } -func addrHandle(link *Link, addr *Addr, req *NetlinkRequest) error { +func addrHandle(link *Link, addr *Addr, req *nl.NetlinkRequest) error { if addr.Label != "" && !strings.HasPrefix(addr.Label, link.Name) { return fmt.Errorf("label must begin with interface name") } ensureIndex(link) - family := GetIPFamily(addr.IP) + family := nl.GetIPFamily(addr.IP) - msg := newIfAddrmsg(family) + msg := nl.NewIfAddrmsg(family) msg.Index = uint32(link.Index) prefixlen, _ := addr.Mask.Size() msg.Prefixlen = uint8(prefixlen) @@ -85,14 +45,14 @@ func addrHandle(link *Link, addr *Addr, req *NetlinkRequest) error { addrData = addr.IP.To16() } - localData := newRtAttr(syscall.IFA_LOCAL, addrData) + localData := nl.NewRtAttr(syscall.IFA_LOCAL, addrData) req.AddData(localData) - addressData := newRtAttr(syscall.IFA_ADDRESS, addrData) + addressData := nl.NewRtAttr(syscall.IFA_ADDRESS, addrData) req.AddData(addressData) if addr.Label != "" { - labelData := newRtAttr(syscall.IFA_LABEL, zeroTerminated(addr.Label)) + labelData := nl.NewRtAttr(syscall.IFA_LABEL, nl.ZeroTerminated(addr.Label)) req.AddData(labelData) } @@ -104,8 +64,8 @@ func addrHandle(link *Link, addr *Addr, req *NetlinkRequest) error { // Equivalent to: `ip addr show`. // The list can be filtered by link and ip family. func AddrList(link *Link, family int) ([]Addr, error) { - req := newNetlinkRequest(syscall.RTM_GETADDR, syscall.NLM_F_DUMP) - msg := newIfInfomsg(family) + req := nl.NewNetlinkRequest(syscall.RTM_GETADDR, syscall.NLM_F_DUMP) + msg := nl.NewIfInfomsg(family) req.AddData(msg) msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWADDR) @@ -117,14 +77,14 @@ func AddrList(link *Link, family int) ([]Addr, error) { res := make([]Addr, 0) for _, m := range msgs { - msg := DeserializeIfAddrmsg(m) + msg := nl.DeserializeIfAddrmsg(m) if link != nil && msg.Index != uint32(link.Index) { // Ignore messages from other interfaces continue } - attrs, err := parseRouteAttr(m[msg.Len():]) + attrs, err := nl.ParseRouteAttr(m[msg.Len():]) if err != nil { return nil, err } diff --git a/link_linux.go b/link_linux.go index dc3dcff..30859b6 100644 --- a/link_linux.go +++ b/link_linux.go @@ -5,39 +5,8 @@ import ( "fmt" "net" "syscall" -) -const ( - DEFAULT_CHANGE = 0xFFFFFFFF -) - -const ( - IFLA_INFO_UNSPEC = iota - IFLA_INFO_KIND = iota - IFLA_INFO_DATA = iota - IFLA_INFO_XSTATS = iota - IFLA_INFO_MAX = IFLA_INFO_XSTATS -) - -const ( - IFLA_VLAN_UNSPEC = iota - IFLA_VLAN_ID = iota - IFLA_VLAN_FLAGS = iota - IFLA_VLAN_EGRESS_QOS = iota - IFLA_VLAN_INGRESS_QOS = iota - IFLA_VLAN_PROTOCOL = iota - IFLA_VLAN_MAX = IFLA_VLAN_PROTOCOL -) - -const ( - VETH_INFO_UNSPEC = iota - VETH_INFO_PEER = iota - VETH_INFO_MAX = VETH_INFO_PEER -) - -const ( - // not defined in syscall - IFLA_NET_NS_FD = 28 + "github.com/vishvananda/netlink/nl" ) func ensureIndex(link *Link) { @@ -53,9 +22,9 @@ func ensureIndex(link *Link) { // Equivalent to: `ip link set $link up` func LinkSetUp(link *Link) error { ensureIndex(link) - req := newNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_ACK) + req := nl.NewNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_ACK) - msg := newIfInfomsg(syscall.AF_UNSPEC) + msg := nl.NewIfInfomsg(syscall.AF_UNSPEC) msg.Change = syscall.IFF_UP msg.Flags = syscall.IFF_UP msg.Index = int32(link.Index) @@ -69,9 +38,9 @@ func LinkSetUp(link *Link) error { // Equivalent to: `ip link set $link down` func LinkSetDown(link *Link) error { ensureIndex(link) - req := newNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_ACK) + req := nl.NewNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_ACK) - msg := newIfInfomsg(syscall.AF_UNSPEC) + msg := nl.NewIfInfomsg(syscall.AF_UNSPEC) msg.Change = syscall.IFF_UP msg.Flags = 0 & ^syscall.IFF_UP msg.Index = int32(link.Index) @@ -85,22 +54,22 @@ func LinkSetDown(link *Link) error { // Equivalent to: `ip link set $link mtu $mtu` func LinkSetMTU(link *Link, mtu int) error { ensureIndex(link) - req := newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK) + req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK) - msg := newIfInfomsg(syscall.AF_UNSPEC) + msg := nl.NewIfInfomsg(syscall.AF_UNSPEC) msg.Type = syscall.RTM_SETLINK msg.Flags = syscall.NLM_F_REQUEST msg.Index = int32(link.Index) - msg.Change = DEFAULT_CHANGE + msg.Change = nl.DEFAULT_CHANGE req.AddData(msg) var ( b = make([]byte, 4) - native = nativeEndian() + native = nl.NativeEndian() ) native.PutUint32(b, uint32(mtu)) - data := newRtAttr(syscall.IFLA_MTU, b) + data := nl.NewRtAttr(syscall.IFLA_MTU, b) req.AddData(data) _, err := req.Execute(syscall.NETLINK_ROUTE, 0) @@ -113,18 +82,18 @@ func LinkSetMTU(link *Link, mtu int) error { func LinkSetMaster(link *Link, master *Link) error { ensureIndex(link) ensureIndex(master) - req := newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK) + req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK) - msg := newIfInfomsg(syscall.AF_UNSPEC) + msg := nl.NewIfInfomsg(syscall.AF_UNSPEC) msg.Type = syscall.RTM_SETLINK msg.Flags = syscall.NLM_F_REQUEST msg.Index = int32(link.Index) - msg.Change = DEFAULT_CHANGE + msg.Change = nl.DEFAULT_CHANGE req.AddData(msg) var ( b = make([]byte, 4) - native = nativeEndian() + native = nl.NativeEndian() index = 0 ) @@ -134,7 +103,7 @@ func LinkSetMaster(link *Link, master *Link) error { native.PutUint32(b, uint32(index)) - data := newRtAttr(syscall.IFLA_MASTER, b) + data := nl.NewRtAttr(syscall.IFLA_MASTER, b) req.AddData(data) _, err := req.Execute(syscall.NETLINK_ROUTE, 0) @@ -145,22 +114,22 @@ func LinkSetMaster(link *Link, master *Link) error { // pid must be a pid of a running process. // Equivalent to: `ip link set $link netns $pid` func LinkSetNsPid(link *Link, nspid int) error { - req := newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK) + req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK) - msg := newIfInfomsg(syscall.AF_UNSPEC) + msg := nl.NewIfInfomsg(syscall.AF_UNSPEC) msg.Type = syscall.RTM_SETLINK msg.Flags = syscall.NLM_F_REQUEST msg.Index = int32(link.Index) - msg.Change = DEFAULT_CHANGE + msg.Change = nl.DEFAULT_CHANGE req.AddData(msg) var ( b = make([]byte, 4) - native = nativeEndian() + native = nl.NativeEndian() ) native.PutUint32(b, uint32(nspid)) - data := newRtAttr(syscall.IFLA_NET_NS_PID, b) + data := nl.NewRtAttr(syscall.IFLA_NET_NS_PID, b) req.AddData(data) _, err := req.Execute(syscall.NETLINK_ROUTE, 0) @@ -171,34 +140,28 @@ func LinkSetNsPid(link *Link, nspid int) error { // fd must be an open file descriptor to a network namespace. // Similar to: `ip link set $link netns $ns` func LinkSetNsFd(link *Link, fd int) error { - req := newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK) + req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK) - msg := newIfInfomsg(syscall.AF_UNSPEC) + msg := nl.NewIfInfomsg(syscall.AF_UNSPEC) msg.Type = syscall.RTM_SETLINK msg.Flags = syscall.NLM_F_REQUEST msg.Index = int32(link.Index) - msg.Change = DEFAULT_CHANGE + msg.Change = nl.DEFAULT_CHANGE req.AddData(msg) var ( b = make([]byte, 4) - native = nativeEndian() + native = nl.NativeEndian() ) native.PutUint32(b, uint32(fd)) - data := newRtAttr(IFLA_NET_NS_FD, b) + data := nl.NewRtAttr(nl.IFLA_NET_NS_FD, b) req.AddData(data) _, err := req.Execute(syscall.NETLINK_ROUTE, 0) return err } -func newIfInfomsgChild(parent *RtAttr, family int) *IfInfomsg { - msg := newIfInfomsg(family) - parent.children = append(parent.children, msg) - return msg -} - // LinkAdd adds a new link device. The type and features of the device // are taken fromt the parameters in the link object. // Equivalent to: `ip link add $link` @@ -210,37 +173,37 @@ func LinkAdd(link *Link) error { return fmt.Errorf("Neither link.Name nor link.Type can be empty!") } - req := newNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) + req := nl.NewNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) - msg := newIfInfomsg(syscall.AF_UNSPEC) + msg := nl.NewIfInfomsg(syscall.AF_UNSPEC) req.AddData(msg) - native := nativeEndian() + native := nl.NativeEndian() if link.Parent != nil { ensureIndex(link.Parent) b := make([]byte, 4) native.PutUint32(b, uint32(link.Parent.Index)) - data := newRtAttr(syscall.IFLA_LINK, b) + data := nl.NewRtAttr(syscall.IFLA_LINK, b) req.AddData(data) } - nameData := newRtAttr(syscall.IFLA_IFNAME, zeroTerminated(link.Name)) + nameData := nl.NewRtAttr(syscall.IFLA_IFNAME, nl.ZeroTerminated(link.Name)) req.AddData(nameData) - linkInfo := newRtAttr(syscall.IFLA_LINKINFO, nil) - newRtAttrChild(linkInfo, IFLA_INFO_KIND, nonZeroTerminated(link.Type)) + linkInfo := nl.NewRtAttr(syscall.IFLA_LINKINFO, nil) + nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_KIND, nl.NonZeroTerminated(link.Type)) if link.Type == "vlan" { b := make([]byte, 2) native.PutUint16(b, uint16(link.VlanId)) - data := newRtAttrChild(linkInfo, IFLA_INFO_DATA, nil) - newRtAttrChild(data, IFLA_VLAN_ID, b) + data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil) + nl.NewRtAttrChild(data, nl.IFLA_VLAN_ID, b) } else if link.Type == "veth" { - data := newRtAttrChild(linkInfo, IFLA_INFO_DATA, nil) - peer := newRtAttrChild(data, VETH_INFO_PEER, nil) - newIfInfomsgChild(peer, syscall.AF_UNSPEC) - newRtAttrChild(peer, syscall.IFLA_IFNAME, zeroTerminated(link.PeerName)) + data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil) + peer := nl.NewRtAttrChild(data, nl.VETH_INFO_PEER, nil) + nl.NewIfInfomsgChild(peer, syscall.AF_UNSPEC) + nl.NewRtAttrChild(peer, syscall.IFLA_IFNAME, nl.ZeroTerminated(link.PeerName)) } req.AddData(linkInfo) @@ -263,9 +226,9 @@ func LinkAdd(link *Link) error { func LinkDel(link *Link) error { ensureIndex(link) - req := newNetlinkRequest(syscall.RTM_DELLINK, syscall.NLM_F_ACK) + req := nl.NewNetlinkRequest(syscall.RTM_DELLINK, syscall.NLM_F_ACK) - msg := newIfInfomsg(syscall.AF_UNSPEC) + msg := nl.NewIfInfomsg(syscall.AF_UNSPEC) msg.Index = int32(link.Index) req.AddData(msg) @@ -306,9 +269,9 @@ func LinkByIndex(index int) (*Link, error) { func LinkList() ([]Link, error) { // NOTE(vish): This duplicates functionality in net/iface_linux.go, but we need // to get the message ourselves to parse link type. - req := newNetlinkRequest(syscall.RTM_GETLINK, syscall.NLM_F_DUMP) + req := nl.NewNetlinkRequest(syscall.RTM_GETLINK, syscall.NLM_F_DUMP) - msg := newIfInfomsg(syscall.AF_UNSPEC) + msg := nl.NewIfInfomsg(syscall.AF_UNSPEC) req.AddData(msg) msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWLINK) @@ -316,13 +279,13 @@ func LinkList() ([]Link, error) { return nil, err } - native := nativeEndian() + native := nl.NativeEndian() res := make([]Link, 0) for _, m := range msgs { - msg := DeserializeIfInfomsg(m) + msg := nl.DeserializeIfInfomsg(m) - attrs, err := parseRouteAttr(m[msg.Len():]) + attrs, err := nl.ParseRouteAttr(m[msg.Len():]) if err != nil { return nil, err } @@ -331,16 +294,16 @@ func LinkList() ([]Link, error) { for _, attr := range attrs { switch attr.Attr.Type { case syscall.IFLA_LINKINFO: - infos, err := parseRouteAttr(attr.Value) + infos, err := nl.ParseRouteAttr(attr.Value) if err != nil { return nil, err } for _, info := range infos { switch info.Attr.Type { - case IFLA_INFO_KIND: + case nl.IFLA_INFO_KIND: link.Type = string(info.Value[:len(info.Value)-1]) - case IFLA_INFO_DATA: - data, err := parseRouteAttr(info.Value) + case nl.IFLA_INFO_DATA: + data, err := nl.ParseRouteAttr(info.Value) if err != nil { return nil, err } @@ -379,7 +342,7 @@ func LinkList() ([]Link, error) { func parseVlanData(link *Link, data []syscall.NetlinkRouteAttr, native binary.ByteOrder) { for _, datum := range data { switch datum.Attr.Type { - case IFLA_VLAN_ID: + case nl.IFLA_VLAN_ID: link.VlanId = int(native.Uint16(datum.Value[0:2])) } } diff --git a/netlink.go b/netlink.go index 842d8fa..3ff7935 100644 --- a/netlink.go +++ b/netlink.go @@ -3,34 +3,24 @@ // the kernel. It can be used to add and remove interfaces, set up ip // addresses and routes, and confiugre ipsec. Netlink communication // requires elevated privileges, so in most cases this code needs to -// be run as root. In addition to dealing with netlink primitives, the -// library attempts to provide an high-level interface that is loosly -// modeled on the iproute2 command line interface. +// be run as root. The low level primitives for netlink are contained +// in the nl subpackage. This package attempts to provide a high-level +// interface that is loosly modeled on the iproute2 cli. package netlink import ( "net" - "syscall" + + "github.com/vishvananda/netlink/nl" ) const ( // Family type definitions - FAMILY_ALL = syscall.AF_UNSPEC - FAMILY_V4 = syscall.AF_INET - FAMILY_V6 = syscall.AF_INET6 + FAMILY_ALL = nl.FAMILY_ALL + FAMILY_V4 = nl.FAMILY_V4 + FAMILY_V6 = nl.FAMILY_V6 ) -// GetIPFamily returns the family type of a net.IP. -func GetIPFamily(ip net.IP) int { - if len(ip) <= net.IPv4len { - return FAMILY_V4 - } - if ip.To4() != nil { - return FAMILY_V4 - } - return FAMILY_V6 -} - // ParseIPNet parses a string in ip/net format and returns a net.IPNet. // This is valuable because addresses in netlink are often IPNets and // ParseCIDR returns an IPNet with the IP part set to the base IP of the diff --git a/netlink_test.go b/netlink_test.go index cc1111d..718448b 100644 --- a/netlink_test.go +++ b/netlink_test.go @@ -1,11 +1,9 @@ package netlink import ( - "bytes" "github.com/vishvananda/netns" "log" "os" - "reflect" "runtime" "testing" ) @@ -33,23 +31,3 @@ func setUpNetlinkTest(t *testing.T) tearDownNetlinkTest { runtime.UnlockOSThread() } } - -type testSerializer interface { - serializeSafe() []byte - Serialize() []byte -} - -func testDeserializeSerialize(t *testing.T, orig []byte, safemsg testSerializer, msg testSerializer) { - if !reflect.DeepEqual(safemsg, msg) { - t.Fatal("Deserialization failed.\n", safemsg, "\n", msg) - } - safe := msg.serializeSafe() - if !bytes.Equal(safe, orig) { - t.Fatal("Safe serialization failed.\n", safe, "\n", orig) - } - b := msg.Serialize() - if !bytes.Equal(b, safe) { - t.Fatal("Serialization failed.\n", b, "\n", safe) - } - -} diff --git a/nl/addr_linux.go b/nl/addr_linux.go new file mode 100644 index 0000000..1287042 --- /dev/null +++ b/nl/addr_linux.go @@ -0,0 +1,48 @@ +package nl + +import ( + "syscall" + "unsafe" +) + +type IfAddrmsg struct { + syscall.IfAddrmsg +} + +func NewIfAddrmsg(family int) *IfAddrmsg { + return &IfAddrmsg{ + IfAddrmsg: syscall.IfAddrmsg{ + Family: uint8(family), + }, + } +} + +// struct ifaddrmsg { +// __u8 ifa_family; +// __u8 ifa_prefixlen; /* The prefix length */ +// __u8 ifa_flags; /* Flags */ +// __u8 ifa_scope; /* Address scope */ +// __u32 ifa_index; /* Link index */ +// }; + +// type IfAddrmsg struct { +// Family uint8 +// Prefixlen uint8 +// Flags uint8 +// Scope uint8 +// Index uint32 +// } +// SizeofIfAddrmsg = 0x8 + +func DeserializeIfAddrmsg(b []byte) *IfAddrmsg { + return (*IfAddrmsg)(unsafe.Pointer(&b[0:syscall.SizeofIfAddrmsg][0])) +} + +func (msg *IfAddrmsg) Serialize() []byte { + return (*(*[syscall.SizeofIfAddrmsg]byte)(unsafe.Pointer(msg)))[:] +} + +func (msg *IfAddrmsg) Len() int { + return syscall.SizeofIfAddrmsg +} + diff --git a/addr_linux_test.go b/nl/addr_linux_test.go similarity index 87% rename from addr_linux_test.go rename to nl/addr_linux_test.go index fc9f117..98c3b21 100644 --- a/addr_linux_test.go +++ b/nl/addr_linux_test.go @@ -1,4 +1,4 @@ -package netlink +package nl import ( "bytes" @@ -9,7 +9,7 @@ import ( ) func (msg *IfAddrmsg) write(b []byte) { - native := nativeEndian() + native := NativeEndian() b[0] = msg.Family b[1] = msg.Prefixlen b[2] = msg.Flags @@ -26,7 +26,7 @@ func (msg *IfAddrmsg) serializeSafe() []byte { func deserializeIfAddrmsgSafe(b []byte) *IfAddrmsg { var msg = IfAddrmsg{} - binary.Read(bytes.NewReader(b[0:syscall.SizeofIfAddrmsg]), nativeEndian(), &msg) + binary.Read(bytes.NewReader(b[0:syscall.SizeofIfAddrmsg]), NativeEndian(), &msg) return &msg } diff --git a/netlink_linux.go b/nl/nl_linux.go similarity index 85% rename from netlink_linux.go rename to nl/nl_linux.go index 9e9fd66..b933906 100644 --- a/netlink_linux.go +++ b/nl/nl_linux.go @@ -1,18 +1,37 @@ -package netlink +// Package nl has low level primitives for making Netlink calls. +package nl import ( "bytes" "encoding/binary" + "net" "fmt" "sync/atomic" "syscall" "unsafe" ) +const ( + // Family type definitions + FAMILY_ALL = syscall.AF_UNSPEC + FAMILY_V4 = syscall.AF_INET + FAMILY_V6 = syscall.AF_INET6 +) + var nextSeqNr uint32 +// GetIPFamily returns the family type of a net.IP. +func GetIPFamily(ip net.IP) int { + if len(ip) <= net.IPv4len { + return FAMILY_V4 + } + if ip.To4() != nil { + return FAMILY_V4 + } + return FAMILY_V6 +} // Get native endianness for the system -func nativeEndian() binary.ByteOrder { +func NativeEndian() binary.ByteOrder { var x uint32 = 0x01020304 if *(*byte)(unsafe.Pointer(&x)) == 0x01 { return binary.BigEndian @@ -21,12 +40,12 @@ func nativeEndian() binary.ByteOrder { } // Byte swap a 16 bit value in place -func swap16(i uint16) uint16 { +func Swap16(i uint16) uint16 { return (i&0xff00)>>8 | (i&0xff)<<8 } // Byte swap a 32 bit value in place -func swap32(i uint32) uint32 { +func Swap32(i uint32) uint32 { return (i&0xff000000)>>24 | (i&0xff0000)>>8 | (i&0xff00)<<8 | (i&0xff)<<24 } @@ -41,7 +60,7 @@ type IfInfomsg struct { } // Create an IfInfomsg with family specified -func newIfInfomsg(family int) *IfInfomsg { +func NewIfInfomsg(family int) *IfInfomsg { return &IfInfomsg{ IfInfomsg: syscall.IfInfomsg{ Family: uint8(family), @@ -65,6 +84,12 @@ func rtaAlignOf(attrlen int) int { return (attrlen + syscall.RTA_ALIGNTO - 1) & ^(syscall.RTA_ALIGNTO - 1) } +func NewIfInfomsgChild(parent *RtAttr, family int) *IfInfomsg { + msg := NewIfInfomsg(family) + parent.children = append(parent.children, msg) + return msg +} + // Extend RtAttr to handle data and children type RtAttr struct { syscall.RtAttr @@ -73,7 +98,7 @@ type RtAttr struct { } // Create a new Extended RtAttr object -func newRtAttr(attrType int, data []byte) *RtAttr { +func NewRtAttr(attrType int, data []byte) *RtAttr { return &RtAttr{ RtAttr: syscall.RtAttr{ Type: uint16(attrType), @@ -84,8 +109,8 @@ func newRtAttr(attrType int, data []byte) *RtAttr { } // Create a new RtAttr obj anc add it as a child of an existing object -func newRtAttrChild(parent *RtAttr, attrType int, data []byte) *RtAttr { - attr := newRtAttr(attrType, data) +func NewRtAttrChild(parent *RtAttr, attrType int, data []byte) *RtAttr { + attr := NewRtAttr(attrType, data) parent.children = append(parent.children, attr) return attr } @@ -106,7 +131,7 @@ func (a *RtAttr) Len() int { // Serialize the RtAttr into a byte array // This can't ust unsafe.cast because it must iterate through children. func (a *RtAttr) Serialize() []byte { - native := nativeEndian() + native := NativeEndian() length := a.Len() buf := make([]byte, rtaAlignOf(length)) @@ -200,7 +225,7 @@ done: break done } if m.Header.Type == syscall.NLMSG_ERROR { - native := nativeEndian() + native := NativeEndian() error := int32(native.Uint32(m.Data[0:4])) if error == 0 { break done @@ -219,7 +244,7 @@ done: // Create a new netlink request from proto and flags // Note the Len value will be inaccurate once data is added until // the message is serialized -func newNetlinkRequest(proto, flags int) *NetlinkRequest { +func NewNetlinkRequest(proto, flags int) *NetlinkRequest { return &NetlinkRequest{ NlMsghdr: syscall.NlMsghdr{ Len: uint32(syscall.SizeofNlMsghdr), @@ -288,7 +313,7 @@ func (s *NetlinkSocket) GetPid() (uint32, error) { return 0, fmt.Errorf("Wrong socket type") } -func zeroTerminated(s string) []byte { +func ZeroTerminated(s string) []byte { bytes := make([]byte, len(s)+1) for i := 0; i < len(s); i++ { bytes[i] = s[i] @@ -297,7 +322,7 @@ func zeroTerminated(s string) []byte { return bytes } -func nonZeroTerminated(s string) []byte { +func NonZeroTerminated(s string) []byte { bytes := make([]byte, len(s)) for i := 0; i < len(s); i++ { bytes[i] = s[i] @@ -305,12 +330,12 @@ func nonZeroTerminated(s string) []byte { return bytes } -func bytesToString(b []byte) string { +func BytesToString(b []byte) string { n := bytes.Index(b, []byte{0}) return string(b[:n]) } -func parseRouteAttr(b []byte) ([]syscall.NetlinkRouteAttr, error) { +func ParseRouteAttr(b []byte) ([]syscall.NetlinkRouteAttr, error) { var attrs []syscall.NetlinkRouteAttr for len(b) >= syscall.SizeofRtAttr { a, vbuf, alen, err := netlinkRouteAttrAndValue(b) diff --git a/netlink_linux_test.go b/nl/nl_linux_test.go similarity index 56% rename from netlink_linux_test.go rename to nl/nl_linux_test.go index aeebf2b..4672684 100644 --- a/netlink_linux_test.go +++ b/nl/nl_linux_test.go @@ -1,15 +1,35 @@ -package netlink +package nl import ( "bytes" "crypto/rand" "encoding/binary" + "reflect" "syscall" "testing" ) +type testSerializer interface { + serializeSafe() []byte + Serialize() []byte +} + +func testDeserializeSerialize(t *testing.T, orig []byte, safemsg testSerializer, msg testSerializer) { + if !reflect.DeepEqual(safemsg, msg) { + t.Fatal("Deserialization failed.\n", safemsg, "\n", msg) + } + safe := msg.serializeSafe() + if !bytes.Equal(safe, orig) { + t.Fatal("Safe serialization failed.\n", safe, "\n", orig) + } + b := msg.Serialize() + if !bytes.Equal(b, safe) { + t.Fatal("Serialization failed.\n", b, "\n", safe) + } +} + func (msg *IfInfomsg) write(b []byte) { - native := nativeEndian() + native := NativeEndian() b[0] = msg.Family b[1] = msg.X__ifi_pad native.PutUint16(b[2:4], msg.Type) @@ -27,7 +47,7 @@ func (msg *IfInfomsg) serializeSafe() []byte { func deserializeIfInfomsgSafe(b []byte) *IfInfomsg { var msg = IfInfomsg{} - binary.Read(bytes.NewReader(b[0:syscall.SizeofIfInfomsg]), nativeEndian(), &msg) + binary.Read(bytes.NewReader(b[0:syscall.SizeofIfInfomsg]), NativeEndian(), &msg) return &msg } diff --git a/nl/route_linux.go b/nl/route_linux.go new file mode 100644 index 0000000..de54609 --- /dev/null +++ b/nl/route_linux.go @@ -0,0 +1,34 @@ +package nl + +import ( + "syscall" + "unsafe" +) + +type RtMsg struct { + syscall.RtMsg +} + +func NewRtMsg() *RtMsg { + return &RtMsg{ + RtMsg: syscall.RtMsg{ + Table: syscall.RT_TABLE_MAIN, + Scope: syscall.RT_SCOPE_UNIVERSE, + Protocol: syscall.RTPROT_BOOT, + Type: syscall.RTN_UNICAST, + }, + } +} + +func (msg *RtMsg) Len() int { + return syscall.SizeofRtMsg +} + +func DeserializeRtMsg(b []byte) *RtMsg { + return (*RtMsg)(unsafe.Pointer(&b[0:syscall.SizeofRtMsg][0])) +} + +func (msg *RtMsg) Serialize() []byte { + return (*(*[syscall.SizeofRtMsg]byte)(unsafe.Pointer(msg)))[:] +} + diff --git a/route_linux_test.go b/nl/route_linux_test.go similarity index 87% rename from route_linux_test.go rename to nl/route_linux_test.go index 059a729..ba9c410 100644 --- a/route_linux_test.go +++ b/nl/route_linux_test.go @@ -1,4 +1,4 @@ -package netlink +package nl import ( "bytes" @@ -9,7 +9,7 @@ import ( ) func (msg *RtMsg) write(b []byte) { - native := nativeEndian() + native := NativeEndian() b[0] = msg.Family b[1] = msg.Dst_len b[2] = msg.Src_len @@ -30,7 +30,7 @@ func (msg *RtMsg) serializeSafe() []byte { func deserializeRtMsgSafe(b []byte) *RtMsg { var msg = RtMsg{} - binary.Read(bytes.NewReader(b[0:syscall.SizeofRtMsg]), nativeEndian(), &msg) + binary.Read(bytes.NewReader(b[0:syscall.SizeofRtMsg]), NativeEndian(), &msg) return &msg } diff --git a/xfrm_linux.go b/nl/xfrm_linux.go similarity index 90% rename from xfrm_linux.go rename to nl/xfrm_linux.go index 5b39060..59f4607 100644 --- a/xfrm_linux.go +++ b/nl/xfrm_linux.go @@ -1,4 +1,4 @@ -package netlink +package nl import ( "bytes" @@ -172,26 +172,6 @@ func (msg *XfrmSelector) Serialize() []byte { return (*(*[SizeofXfrmSelector]byte)(unsafe.Pointer(msg)))[:] } -func (sel *XfrmSelector) FromPolicy(policy *XfrmPolicy) { - sel.Family = uint16(GetIPFamily(policy.Dst.IP)) - sel.Daddr.FromIP(policy.Dst.IP) - sel.Saddr.FromIP(policy.Src.IP) - prefixlenD, _ := policy.Dst.Mask.Size() - sel.PrefixlenD = uint8(prefixlenD) - prefixlenS, _ := policy.Src.Mask.Size() - sel.PrefixlenS = uint8(prefixlenS) -} - -func (sel *XfrmSelector) FromState(state *XfrmPolicy) { - sel.Family = uint16(GetIPFamily(state.Dst.IP)) - sel.Daddr.FromIP(state.Dst.IP) - sel.Saddr.FromIP(state.Src.IP) - prefixlenD, _ := state.Dst.Mask.Size() - sel.PrefixlenD = uint8(prefixlenD) - prefixlenS, _ := state.Src.Mask.Size() - sel.PrefixlenS = uint8(prefixlenS) -} - // struct xfrm_lifetime_cfg { // __u64 soft_byte_limit; // __u64 hard_byte_limit; diff --git a/xfrm_linux_test.go b/nl/xfrm_linux_test.go similarity index 90% rename from xfrm_linux_test.go rename to nl/xfrm_linux_test.go index adf6981..04404d7 100644 --- a/xfrm_linux_test.go +++ b/nl/xfrm_linux_test.go @@ -1,4 +1,4 @@ -package netlink +package nl import ( "bytes" @@ -19,7 +19,7 @@ func (msg *XfrmAddress) serializeSafe() []byte { func deserializeXfrmAddressSafe(b []byte) *XfrmAddress { var msg = XfrmAddress{} - binary.Read(bytes.NewReader(b[0:SizeofXfrmAddress]), nativeEndian(), &msg) + binary.Read(bytes.NewReader(b[0:SizeofXfrmAddress]), NativeEndian(), &msg) return &msg } @@ -33,7 +33,7 @@ func TestXfrmAddressDeserializeSerialize(t *testing.T) { func (msg *XfrmSelector) write(b []byte) { const AddrEnd = SizeofXfrmAddress * 2 - native := nativeEndian() + native := NativeEndian() msg.Daddr.write(b[0:SizeofXfrmAddress]) msg.Saddr.write(b[SizeofXfrmAddress:AddrEnd]) native.PutUint16(b[AddrEnd:AddrEnd+2], msg.Dport) @@ -58,7 +58,7 @@ func (msg *XfrmSelector) serializeSafe() []byte { func deserializeXfrmSelectorSafe(b []byte) *XfrmSelector { var msg = XfrmSelector{} - binary.Read(bytes.NewReader(b[0:SizeofXfrmSelector]), nativeEndian(), &msg) + binary.Read(bytes.NewReader(b[0:SizeofXfrmSelector]), NativeEndian(), &msg) return &msg } @@ -71,7 +71,7 @@ func TestXfrmSelectorDeserializeSerialize(t *testing.T) { } func (msg *XfrmLifetimeCfg) write(b []byte) { - native := nativeEndian() + native := NativeEndian() native.PutUint64(b[0:8], msg.SoftByteLimit) native.PutUint64(b[8:16], msg.HardByteLimit) native.PutUint64(b[16:24], msg.SoftPacketLimit) @@ -91,7 +91,7 @@ func (msg *XfrmLifetimeCfg) serializeSafe() []byte { func deserializeXfrmLifetimeCfgSafe(b []byte) *XfrmLifetimeCfg { var msg = XfrmLifetimeCfg{} - binary.Read(bytes.NewReader(b[0:SizeofXfrmLifetimeCfg]), nativeEndian(), &msg) + binary.Read(bytes.NewReader(b[0:SizeofXfrmLifetimeCfg]), NativeEndian(), &msg) return &msg } @@ -104,7 +104,7 @@ func TestXfrmLifetimeCfgDeserializeSerialize(t *testing.T) { } func (msg *XfrmLifetimeCur) write(b []byte) { - native := nativeEndian() + native := NativeEndian() native.PutUint64(b[0:8], msg.Bytes) native.PutUint64(b[8:16], msg.Packets) native.PutUint64(b[16:24], msg.AddTime) @@ -120,7 +120,7 @@ func (msg *XfrmLifetimeCur) serializeSafe() []byte { func deserializeXfrmLifetimeCurSafe(b []byte) *XfrmLifetimeCur { var msg = XfrmLifetimeCur{} - binary.Read(bytes.NewReader(b[0:SizeofXfrmLifetimeCur]), nativeEndian(), &msg) + binary.Read(bytes.NewReader(b[0:SizeofXfrmLifetimeCur]), NativeEndian(), &msg) return &msg } @@ -133,7 +133,7 @@ func TestXfrmLifetimeCurDeserializeSerialize(t *testing.T) { } func (msg *XfrmId) write(b []byte) { - native := nativeEndian() + native := NativeEndian() msg.Daddr.write(b[0:SizeofXfrmAddress]) native.PutUint32(b[SizeofXfrmAddress:SizeofXfrmAddress+4], msg.Spi) b[SizeofXfrmAddress+4] = msg.Proto @@ -148,7 +148,7 @@ func (msg *XfrmId) serializeSafe() []byte { func deserializeXfrmIdSafe(b []byte) *XfrmId { var msg = XfrmId{} - binary.Read(bytes.NewReader(b[0:SizeofXfrmId]), nativeEndian(), &msg) + binary.Read(bytes.NewReader(b[0:SizeofXfrmId]), NativeEndian(), &msg) return &msg } diff --git a/nl/xfrm_policy_linux.go b/nl/xfrm_policy_linux.go new file mode 100644 index 0000000..e1d186b --- /dev/null +++ b/nl/xfrm_policy_linux.go @@ -0,0 +1,120 @@ +package nl + +import ( + "unsafe" +) + +const ( + SizeofXfrmUserpolicyId = 0x40 + SizeofXfrmUserpolicyInfo = 0xa8 + SizeofXfrmUserTmpl = 0x40 +) + +// struct xfrm_userpolicy_id { +// struct xfrm_selector sel; +// __u32 index; +// __u8 dir; +// }; +// + +type XfrmUserpolicyId struct { + Sel XfrmSelector + Index uint32 + Dir uint8 + Pad [3]byte +} + +func (msg *XfrmUserpolicyId) Len() int { + return SizeofXfrmUserpolicyId +} + +func DeserializeXfrmUserpolicyId(b []byte) *XfrmUserpolicyId { + return (*XfrmUserpolicyId)(unsafe.Pointer(&b[0:SizeofXfrmUserpolicyId][0])) +} + +func (msg *XfrmUserpolicyId) Serialize() []byte { + return (*(*[SizeofXfrmUserpolicyId]byte)(unsafe.Pointer(msg)))[:] +} + +// struct xfrm_userpolicy_info { +// struct xfrm_selector sel; +// struct xfrm_lifetime_cfg lft; +// struct xfrm_lifetime_cur curlft; +// __u32 priority; +// __u32 index; +// __u8 dir; +// __u8 action; +// #define XFRM_POLICY_ALLOW 0 +// #define XFRM_POLICY_BLOCK 1 +// __u8 flags; +// #define XFRM_POLICY_LOCALOK 1 /* Allow user to override global policy */ +// /* Automatically expand selector to include matching ICMP payloads. */ +// #define XFRM_POLICY_ICMP 2 +// __u8 share; +// }; + +type XfrmUserpolicyInfo struct { + Sel XfrmSelector + Lft XfrmLifetimeCfg + Curlft XfrmLifetimeCur + Priority uint32 + Index uint32 + Dir uint8 + Action uint8 + Flags uint8 + Share uint8 + Pad [4]byte +} + +func (msg *XfrmUserpolicyInfo) Len() int { + return SizeofXfrmUserpolicyInfo +} + +func DeserializeXfrmUserpolicyInfo(b []byte) *XfrmUserpolicyInfo { + return (*XfrmUserpolicyInfo)(unsafe.Pointer(&b[0:SizeofXfrmUserpolicyInfo][0])) +} + +func (msg *XfrmUserpolicyInfo) Serialize() []byte { + return (*(*[SizeofXfrmUserpolicyInfo]byte)(unsafe.Pointer(msg)))[:] +} + +// struct xfrm_user_tmpl { +// struct xfrm_id id; +// __u16 family; +// xfrm_address_t saddr; +// __u32 reqid; +// __u8 mode; +// __u8 share; +// __u8 optional; +// __u32 aalgos; +// __u32 ealgos; +// __u32 calgos; +// } + +type XfrmUserTmpl struct { + XfrmId XfrmId + Family uint16 + Pad1 [2]byte + Saddr XfrmAddress + Reqid uint32 + Mode uint8 + Share uint8 + Optional uint8 + Pad2 byte + Aalgos uint32 + Ealgos uint32 + Calgos uint32 +} + +func (msg *XfrmUserTmpl) Len() int { + return SizeofXfrmUserTmpl +} + +func DeserializeXfrmUserTmpl(b []byte) *XfrmUserTmpl { + return (*XfrmUserTmpl)(unsafe.Pointer(&b[0:SizeofXfrmUserTmpl][0])) +} + +func (msg *XfrmUserTmpl) Serialize() []byte { + return (*(*[SizeofXfrmUserTmpl]byte)(unsafe.Pointer(msg)))[:] +} + diff --git a/xfrm_policy_linux_test.go b/nl/xfrm_policy_linux_test.go similarity index 91% rename from xfrm_policy_linux_test.go rename to nl/xfrm_policy_linux_test.go index 5c4cf91..08a604b 100644 --- a/xfrm_policy_linux_test.go +++ b/nl/xfrm_policy_linux_test.go @@ -1,4 +1,4 @@ -package netlink +package nl import ( "bytes" @@ -8,7 +8,7 @@ import ( ) func (msg *XfrmUserpolicyId) write(b []byte) { - native := nativeEndian() + native := NativeEndian() msg.Sel.write(b[0:SizeofXfrmSelector]) native.PutUint32(b[SizeofXfrmSelector:SizeofXfrmSelector+4], msg.Index) b[SizeofXfrmSelector+4] = msg.Dir @@ -23,7 +23,7 @@ func (msg *XfrmUserpolicyId) serializeSafe() []byte { func deserializeXfrmUserpolicyIdSafe(b []byte) *XfrmUserpolicyId { var msg = XfrmUserpolicyId{} - binary.Read(bytes.NewReader(b[0:SizeofXfrmUserpolicyId]), nativeEndian(), &msg) + binary.Read(bytes.NewReader(b[0:SizeofXfrmUserpolicyId]), NativeEndian(), &msg) return &msg } @@ -38,7 +38,7 @@ func TestXfrmUserpolicyIdDeserializeSerialize(t *testing.T) { func (msg *XfrmUserpolicyInfo) write(b []byte) { const CfgEnd = SizeofXfrmSelector + SizeofXfrmLifetimeCfg const CurEnd = CfgEnd + SizeofXfrmLifetimeCur - native := nativeEndian() + native := NativeEndian() msg.Sel.write(b[0:SizeofXfrmSelector]) msg.Lft.write(b[SizeofXfrmSelector:CfgEnd]) msg.Curlft.write(b[CfgEnd:CurEnd]) @@ -59,7 +59,7 @@ func (msg *XfrmUserpolicyInfo) serializeSafe() []byte { func deserializeXfrmUserpolicyInfoSafe(b []byte) *XfrmUserpolicyInfo { var msg = XfrmUserpolicyInfo{} - binary.Read(bytes.NewReader(b[0:SizeofXfrmUserpolicyInfo]), nativeEndian(), &msg) + binary.Read(bytes.NewReader(b[0:SizeofXfrmUserpolicyInfo]), NativeEndian(), &msg) return &msg } @@ -73,7 +73,7 @@ func TestXfrmUserpolicyInfoDeserializeSerialize(t *testing.T) { func (msg *XfrmUserTmpl) write(b []byte) { const AddrEnd = SizeofXfrmId + 4 + SizeofXfrmAddress - native := nativeEndian() + native := NativeEndian() msg.XfrmId.write(b[0:SizeofXfrmId]) native.PutUint16(b[SizeofXfrmId:SizeofXfrmId+2], msg.Family) copy(b[SizeofXfrmId+2:SizeofXfrmId+4], msg.Pad1[:]) @@ -96,7 +96,7 @@ func (msg *XfrmUserTmpl) serializeSafe() []byte { func deserializeXfrmUserTmplSafe(b []byte) *XfrmUserTmpl { var msg = XfrmUserTmpl{} - binary.Read(bytes.NewReader(b[0:SizeofXfrmUserTmpl]), nativeEndian(), &msg) + binary.Read(bytes.NewReader(b[0:SizeofXfrmUserTmpl]), NativeEndian(), &msg) return &msg } diff --git a/nl/xfrm_state_linux.go b/nl/xfrm_state_linux.go new file mode 100644 index 0000000..74da332 --- /dev/null +++ b/nl/xfrm_state_linux.go @@ -0,0 +1,222 @@ +package nl + +import ( + "unsafe" +) + +const ( + SizeofXfrmUsersaId = 0x18 + SizeofXfrmStats = 0x0c + SizeofXfrmUsersaInfo = 0xe0 + SizeofXfrmAlgo = 0x44 + SizeofXfrmAlgoAuth = 0x48 + SizeofXfrmEncapTmpl = 0x18 +) + +// struct xfrm_usersa_id { +// xfrm_address_t daddr; +// __be32 spi; +// __u16 family; +// __u8 proto; +// }; + +type XfrmUsersaId struct { + Daddr XfrmAddress + Spi uint32 // big endian + Family uint16 + Proto uint8 + Pad byte +} + +func (msg *XfrmUsersaId) Len() int { + return SizeofXfrmUsersaId +} + +func DeserializeXfrmUsersaId(b []byte) *XfrmUsersaId { + return (*XfrmUsersaId)(unsafe.Pointer(&b[0:SizeofXfrmUsersaId][0])) +} + +func (msg *XfrmUsersaId) Serialize() []byte { + return (*(*[SizeofXfrmUsersaId]byte)(unsafe.Pointer(msg)))[:] +} + +// struct xfrm_stats { +// __u32 replay_window; +// __u32 replay; +// __u32 integrity_failed; +// }; + +type XfrmStats struct { + ReplayWindow uint32 + Replay uint32 + IntegrityFailed uint32 +} + +func (msg *XfrmStats) Len() int { + return SizeofXfrmStats +} + +func DeserializeXfrmStats(b []byte) *XfrmStats { + return (*XfrmStats)(unsafe.Pointer(&b[0:SizeofXfrmStats][0])) +} + +func (msg *XfrmStats) Serialize() []byte { + return (*(*[SizeofXfrmStats]byte)(unsafe.Pointer(msg)))[:] +} + +// struct xfrm_usersa_info { +// struct xfrm_selector sel; +// struct xfrm_id id; +// xfrm_address_t saddr; +// struct xfrm_lifetime_cfg lft; +// struct xfrm_lifetime_cur curlft; +// struct xfrm_stats stats; +// __u32 seq; +// __u32 reqid; +// __u16 family; +// __u8 mode; /* XFRM_MODE_xxx */ +// __u8 replay_window; +// __u8 flags; +// #define XFRM_STATE_NOECN 1 +// #define XFRM_STATE_DECAP_DSCP 2 +// #define XFRM_STATE_NOPMTUDISC 4 +// #define XFRM_STATE_WILDRECV 8 +// #define XFRM_STATE_ICMP 16 +// #define XFRM_STATE_AF_UNSPEC 32 +// #define XFRM_STATE_ALIGN4 64 +// #define XFRM_STATE_ESN 128 +// }; +// +// #define XFRM_SA_XFLAG_DONT_ENCAP_DSCP 1 +// + +type XfrmUsersaInfo struct { + Sel XfrmSelector + Id XfrmId + Saddr XfrmAddress + Lft XfrmLifetimeCfg + Curlft XfrmLifetimeCur + Stats XfrmStats + Seq uint32 + Reqid uint32 + Family uint16 + Mode uint8 + ReplayWindow uint8 + Flags uint8 + Pad [7]byte +} + +func (msg *XfrmUsersaInfo) Len() int { + return SizeofXfrmUsersaInfo +} + +func DeserializeXfrmUsersaInfo(b []byte) *XfrmUsersaInfo { + return (*XfrmUsersaInfo)(unsafe.Pointer(&b[0:SizeofXfrmUsersaInfo][0])) +} + +func (msg *XfrmUsersaInfo) Serialize() []byte { + return (*(*[SizeofXfrmUsersaInfo]byte)(unsafe.Pointer(msg)))[:] +} + +// struct xfrm_algo { +// char alg_name[64]; +// unsigned int alg_key_len; /* in bits */ +// char alg_key[0]; +// }; + +type XfrmAlgo struct { + AlgName [64]byte + AlgKeyLen uint32 + AlgKey []byte +} + +func (msg *XfrmAlgo) Len() int { + return SizeofXfrmAlgo + int(msg.AlgKeyLen/8) +} + +func DeserializeXfrmAlgo(b []byte) *XfrmAlgo { + ret := XfrmAlgo{} + copy(ret.AlgName[:], b[0:64]) + ret.AlgKeyLen = *(*uint32)(unsafe.Pointer(&b[64])) + ret.AlgKey = b[68:ret.Len()] + return &ret +} + +func (msg *XfrmAlgo) Serialize() []byte { + b := make([]byte, msg.Len()) + copy(b[0:64], msg.AlgName[:]) + copy(b[64:68], (*(*[4]byte)(unsafe.Pointer(&msg.AlgKeyLen)))[:]) + copy(b[68:msg.Len()], msg.AlgKey[:]) + return b +} + +// struct xfrm_algo_auth { +// char alg_name[64]; +// unsigned int alg_key_len; /* in bits */ +// unsigned int alg_trunc_len; /* in bits */ +// char alg_key[0]; +// }; + +type XfrmAlgoAuth struct { + AlgName [64]byte + AlgKeyLen uint32 + AlgTruncLen uint32 + AlgKey []byte +} + +func (msg *XfrmAlgoAuth) Len() int { + return SizeofXfrmAlgoAuth + int(msg.AlgKeyLen/8) +} + +func DeserializeXfrmAlgoAuth(b []byte) *XfrmAlgoAuth { + ret := XfrmAlgoAuth{} + copy(ret.AlgName[:], b[0:64]) + ret.AlgKeyLen = *(*uint32)(unsafe.Pointer(&b[64])) + ret.AlgTruncLen = *(*uint32)(unsafe.Pointer(&b[68])) + ret.AlgKey = b[72:ret.Len()] + return &ret +} + +func (msg *XfrmAlgoAuth) Serialize() []byte { + b := make([]byte, msg.Len()) + copy(b[0:64], msg.AlgName[:]) + copy(b[64:68], (*(*[4]byte)(unsafe.Pointer(&msg.AlgKeyLen)))[:]) + copy(b[68:72], (*(*[4]byte)(unsafe.Pointer(&msg.AlgTruncLen)))[:]) + copy(b[72:msg.Len()], msg.AlgKey[:]) + return b +} + +// struct xfrm_algo_aead { +// char alg_name[64]; +// unsigned int alg_key_len; /* in bits */ +// unsigned int alg_icv_len; /* in bits */ +// char alg_key[0]; +// } + +// struct xfrm_encap_tmpl { +// __u16 encap_type; +// __be16 encap_sport; +// __be16 encap_dport; +// xfrm_address_t encap_oa; +// }; + +type XfrmEncapTmpl struct { + EncapType uint16 + EncapSport uint16 // big endian + EncapDport uint16 // big endian + Pad [2]byte + EncapOa XfrmAddress +} + +func (msg *XfrmEncapTmpl) Len() int { + return SizeofXfrmEncapTmpl +} + +func DeserializeXfrmEncapTmpl(b []byte) *XfrmEncapTmpl { + return (*XfrmEncapTmpl)(unsafe.Pointer(&b[0:SizeofXfrmEncapTmpl][0])) +} + +func (msg *XfrmEncapTmpl) Serialize() []byte { + return (*(*[SizeofXfrmEncapTmpl]byte)(unsafe.Pointer(msg)))[:] +} + diff --git a/xfrm_state_linux_test.go b/nl/xfrm_state_linux_test.go similarity index 89% rename from xfrm_state_linux_test.go rename to nl/xfrm_state_linux_test.go index b8e8fa8..d5281e9 100644 --- a/xfrm_state_linux_test.go +++ b/nl/xfrm_state_linux_test.go @@ -1,4 +1,4 @@ -package netlink +package nl import ( "bytes" @@ -8,7 +8,7 @@ import ( ) func (msg *XfrmUsersaId) write(b []byte) { - native := nativeEndian() + native := NativeEndian() msg.Daddr.write(b[0:SizeofXfrmAddress]) native.PutUint32(b[SizeofXfrmAddress:SizeofXfrmAddress+4], msg.Spi) native.PutUint16(b[SizeofXfrmAddress+4:SizeofXfrmAddress+6], msg.Family) @@ -24,7 +24,7 @@ func (msg *XfrmUsersaId) serializeSafe() []byte { func deserializeXfrmUsersaIdSafe(b []byte) *XfrmUsersaId { var msg = XfrmUsersaId{} - binary.Read(bytes.NewReader(b[0:SizeofXfrmUsersaId]), nativeEndian(), &msg) + binary.Read(bytes.NewReader(b[0:SizeofXfrmUsersaId]), NativeEndian(), &msg) return &msg } @@ -37,7 +37,7 @@ func TestXfrmUsersaIdDeserializeSerialize(t *testing.T) { } func (msg *XfrmStats) write(b []byte) { - native := nativeEndian() + native := NativeEndian() native.PutUint32(b[0:4], msg.ReplayWindow) native.PutUint32(b[4:8], msg.Replay) native.PutUint32(b[8:12], msg.IntegrityFailed) @@ -51,7 +51,7 @@ func (msg *XfrmStats) serializeSafe() []byte { func deserializeXfrmStatsSafe(b []byte) *XfrmStats { var msg = XfrmStats{} - binary.Read(bytes.NewReader(b[0:SizeofXfrmStats]), nativeEndian(), &msg) + binary.Read(bytes.NewReader(b[0:SizeofXfrmStats]), NativeEndian(), &msg) return &msg } @@ -69,7 +69,7 @@ func (msg *XfrmUsersaInfo) write(b []byte) { const CfgEnd = AddressEnd + SizeofXfrmLifetimeCfg const CurEnd = CfgEnd + SizeofXfrmLifetimeCur const StatsEnd = CurEnd + SizeofXfrmStats - native := nativeEndian() + native := NativeEndian() msg.Sel.write(b[0:SizeofXfrmSelector]) msg.Id.write(b[SizeofXfrmSelector:IdEnd]) msg.Saddr.write(b[IdEnd:AddressEnd]) @@ -93,7 +93,7 @@ func (msg *XfrmUsersaInfo) serializeSafe() []byte { func deserializeXfrmUsersaInfoSafe(b []byte) *XfrmUsersaInfo { var msg = XfrmUsersaInfo{} - binary.Read(bytes.NewReader(b[0:SizeofXfrmUsersaInfo]), nativeEndian(), &msg) + binary.Read(bytes.NewReader(b[0:SizeofXfrmUsersaInfo]), NativeEndian(), &msg) return &msg } @@ -106,7 +106,7 @@ func TestXfrmUsersaInfoDeserializeSerialize(t *testing.T) { } func (msg *XfrmAlgo) write(b []byte) { - native := nativeEndian() + native := NativeEndian() copy(b[0:64], msg.AlgName[:]) native.PutUint32(b[64:68], msg.AlgKeyLen) copy(b[68:msg.Len()], msg.AlgKey[:]) @@ -121,7 +121,7 @@ func (msg *XfrmAlgo) serializeSafe() []byte { func deserializeXfrmAlgoSafe(b []byte) *XfrmAlgo { var msg = XfrmAlgo{} copy(msg.AlgName[:], b[0:64]) - binary.Read(bytes.NewReader(b[64:68]), nativeEndian(), &msg.AlgKeyLen) + binary.Read(bytes.NewReader(b[64:68]), NativeEndian(), &msg.AlgKeyLen) msg.AlgKey = b[68:msg.Len()] return &msg } @@ -141,7 +141,7 @@ func TestXfrmAlgoDeserializeSerialize(t *testing.T) { } func (msg *XfrmAlgoAuth) write(b []byte) { - native := nativeEndian() + native := NativeEndian() copy(b[0:64], msg.AlgName[:]) native.PutUint32(b[64:68], msg.AlgKeyLen) native.PutUint32(b[68:72], msg.AlgTruncLen) @@ -157,8 +157,8 @@ func (msg *XfrmAlgoAuth) serializeSafe() []byte { func deserializeXfrmAlgoAuthSafe(b []byte) *XfrmAlgoAuth { var msg = XfrmAlgoAuth{} copy(msg.AlgName[:], b[0:64]) - binary.Read(bytes.NewReader(b[64:68]), nativeEndian(), &msg.AlgKeyLen) - binary.Read(bytes.NewReader(b[68:72]), nativeEndian(), &msg.AlgTruncLen) + binary.Read(bytes.NewReader(b[64:68]), NativeEndian(), &msg.AlgKeyLen) + binary.Read(bytes.NewReader(b[68:72]), NativeEndian(), &msg.AlgTruncLen) msg.AlgKey = b[72:msg.Len()] return &msg } @@ -178,7 +178,7 @@ func TestXfrmAlgoAuthDeserializeSerialize(t *testing.T) { } func (msg *XfrmEncapTmpl) write(b []byte) { - native := nativeEndian() + native := NativeEndian() native.PutUint16(b[0:2], msg.EncapType) native.PutUint16(b[2:4], msg.EncapSport) native.PutUint16(b[4:6], msg.EncapDport) @@ -194,7 +194,7 @@ func (msg *XfrmEncapTmpl) serializeSafe() []byte { func deserializeXfrmEncapTmplSafe(b []byte) *XfrmEncapTmpl { var msg = XfrmEncapTmpl{} - binary.Read(bytes.NewReader(b[0:SizeofXfrmEncapTmpl]), nativeEndian(), &msg) + binary.Read(bytes.NewReader(b[0:SizeofXfrmEncapTmpl]), NativeEndian(), &msg) return &msg } diff --git a/route_linux.go b/route_linux.go index 1bf5741..5af6dd6 100644 --- a/route_linux.go +++ b/route_linux.go @@ -4,66 +4,40 @@ import ( "fmt" "net" "syscall" - "unsafe" + + "github.com/vishvananda/netlink/nl" ) -type RtMsg struct { - syscall.RtMsg -} - -func newRtMsg() *RtMsg { - return &RtMsg{ - RtMsg: syscall.RtMsg{ - Table: syscall.RT_TABLE_MAIN, - Scope: syscall.RT_SCOPE_UNIVERSE, - Protocol: syscall.RTPROT_BOOT, - Type: syscall.RTN_UNICAST, - }, - } -} - -func (msg *RtMsg) Len() int { - return syscall.SizeofRtMsg -} - -func DeserializeRtMsg(b []byte) *RtMsg { - return (*RtMsg)(unsafe.Pointer(&b[0:syscall.SizeofRtMsg][0])) -} - -func (msg *RtMsg) Serialize() []byte { - return (*(*[syscall.SizeofRtMsg]byte)(unsafe.Pointer(msg)))[:] -} - // RtAttr is shared so it is in netlink_linux.go // RouteAdd will add a route to the system. // Equivalent to: `ip route add $route` func RouteAdd(route *Route) error { - req := newNetlinkRequest(syscall.RTM_NEWROUTE, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) + req := nl.NewNetlinkRequest(syscall.RTM_NEWROUTE, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) return routeHandle(route, req) } // RouteAdd will delete a route from the system. // Equivalent to: `ip route del $route` func RouteDel(route *Route) error { - req := newNetlinkRequest(syscall.RTM_DELROUTE, syscall.NLM_F_ACK) + req := nl.NewNetlinkRequest(syscall.RTM_DELROUTE, syscall.NLM_F_ACK) return routeHandle(route, req) } -func routeHandle(route *Route, req *NetlinkRequest) error { +func routeHandle(route *Route, req *nl.NetlinkRequest) error { if route.Dst.IP == nil && route.Src == nil && route.Gw == nil { return fmt.Errorf("one of Dst.IP, Src, or Gw must not be nil") } - msg := newRtMsg() + msg := nl.NewRtMsg() msg.Scope = uint8(route.Scope) family := -1 - var rtAttrs []*RtAttr + var rtAttrs []*nl.RtAttr if route.Dst.IP != nil { dstLen, _ := route.Dst.Mask.Size() msg.Dst_len = uint8(dstLen) - dstFamily := GetIPFamily(route.Dst.IP) + dstFamily := nl.GetIPFamily(route.Dst.IP) family = dstFamily var dstData []byte if dstFamily == FAMILY_V4 { @@ -71,11 +45,11 @@ func routeHandle(route *Route, req *NetlinkRequest) error { } else { dstData = route.Dst.IP.To16() } - rtAttrs = append(rtAttrs, newRtAttr(syscall.RTA_DST, dstData)) + rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_DST, dstData)) } if route.Src != nil { - srcFamily := GetIPFamily(route.Src) + srcFamily := nl.GetIPFamily(route.Src) if family != -1 && family != srcFamily { return fmt.Errorf("source and destination ip are not the same IP family") } @@ -87,11 +61,11 @@ func routeHandle(route *Route, req *NetlinkRequest) error { srcData = route.Src.To16() } // The commonly used src ip for routes is actually PREFSRC - rtAttrs = append(rtAttrs, newRtAttr(syscall.RTA_PREFSRC, srcData)) + rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_PREFSRC, srcData)) } if route.Gw != nil { - gwFamily := GetIPFamily(route.Gw) + gwFamily := nl.GetIPFamily(route.Gw) if family != -1 && family != gwFamily { return fmt.Errorf("gateway, source, and destination ip are not the same IP family") } @@ -102,7 +76,7 @@ func routeHandle(route *Route, req *NetlinkRequest) error { } else { gwData = route.Gw.To16() } - rtAttrs = append(rtAttrs, newRtAttr(syscall.RTA_GATEWAY, gwData)) + rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_GATEWAY, gwData)) } msg.Family = uint8(family) @@ -114,11 +88,11 @@ func routeHandle(route *Route, req *NetlinkRequest) error { var ( b = make([]byte, 4) - native = nativeEndian() + native = nl.NativeEndian() ) native.PutUint32(b, uint32(route.Link.Index)) - req.AddData(newRtAttr(syscall.RTA_OIF, b)) + req.AddData(nl.NewRtAttr(syscall.RTA_OIF, b)) _, err := req.Execute(syscall.NETLINK_ROUTE, 0) return err @@ -128,8 +102,8 @@ func routeHandle(route *Route, req *NetlinkRequest) error { // Equivalent to: `ip route show`. // The list can be filtered by link and ip family. func RouteList(link *Link, family int) ([]Route, error) { - req := newNetlinkRequest(syscall.RTM_GETROUTE, syscall.NLM_F_DUMP) - msg := newIfInfomsg(family) + req := nl.NewNetlinkRequest(syscall.RTM_GETROUTE, syscall.NLM_F_DUMP) + msg := nl.NewIfInfomsg(family) req.AddData(msg) msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWROUTE) @@ -137,10 +111,10 @@ func RouteList(link *Link, family int) ([]Route, error) { return nil, err } - native := nativeEndian() + native := nl.NativeEndian() res := make([]Route, 0) for _, m := range msgs { - msg := DeserializeRtMsg(m) + msg := nl.DeserializeRtMsg(m) if msg.Flags&syscall.RTM_F_CLONED != 0 { // Ignore cloned routes @@ -152,7 +126,7 @@ func RouteList(link *Link, family int) ([]Route, error) { continue } - attrs, err := parseRouteAttr(m[msg.Len():]) + attrs, err := nl.ParseRouteAttr(m[msg.Len():]) if err != nil { return nil, err } diff --git a/xfrm_policy_linux.go b/xfrm_policy_linux.go index 090a0b1..6fe1b63 100644 --- a/xfrm_policy_linux.go +++ b/xfrm_policy_linux.go @@ -2,143 +2,40 @@ package netlink import ( "syscall" - "unsafe" + + "github.com/vishvananda/netlink/nl" ) -const ( - SizeofXfrmUserpolicyId = 0x40 - SizeofXfrmUserpolicyInfo = 0xa8 - SizeofXfrmUserTmpl = 0x40 -) - -// struct xfrm_userpolicy_id { -// struct xfrm_selector sel; -// __u32 index; -// __u8 dir; -// }; -// - -type XfrmUserpolicyId struct { - Sel XfrmSelector - Index uint32 - Dir uint8 - Pad [3]byte -} - -func (msg *XfrmUserpolicyId) Len() int { - return SizeofXfrmUserpolicyId -} - -func DeserializeXfrmUserpolicyId(b []byte) *XfrmUserpolicyId { - return (*XfrmUserpolicyId)(unsafe.Pointer(&b[0:SizeofXfrmUserpolicyId][0])) -} - -func (msg *XfrmUserpolicyId) Serialize() []byte { - return (*(*[SizeofXfrmUserpolicyId]byte)(unsafe.Pointer(msg)))[:] -} - -// struct xfrm_userpolicy_info { -// struct xfrm_selector sel; -// struct xfrm_lifetime_cfg lft; -// struct xfrm_lifetime_cur curlft; -// __u32 priority; -// __u32 index; -// __u8 dir; -// __u8 action; -// #define XFRM_POLICY_ALLOW 0 -// #define XFRM_POLICY_BLOCK 1 -// __u8 flags; -// #define XFRM_POLICY_LOCALOK 1 /* Allow user to override global policy */ -// /* Automatically expand selector to include matching ICMP payloads. */ -// #define XFRM_POLICY_ICMP 2 -// __u8 share; -// }; - -type XfrmUserpolicyInfo struct { - Sel XfrmSelector - Lft XfrmLifetimeCfg - Curlft XfrmLifetimeCur - Priority uint32 - Index uint32 - Dir uint8 - Action uint8 - Flags uint8 - Share uint8 - Pad [4]byte -} - -func (msg *XfrmUserpolicyInfo) Len() int { - return SizeofXfrmUserpolicyInfo -} - -func DeserializeXfrmUserpolicyInfo(b []byte) *XfrmUserpolicyInfo { - return (*XfrmUserpolicyInfo)(unsafe.Pointer(&b[0:SizeofXfrmUserpolicyInfo][0])) -} - -func (msg *XfrmUserpolicyInfo) Serialize() []byte { - return (*(*[SizeofXfrmUserpolicyInfo]byte)(unsafe.Pointer(msg)))[:] -} - -// struct xfrm_user_tmpl { -// struct xfrm_id id; -// __u16 family; -// xfrm_address_t saddr; -// __u32 reqid; -// __u8 mode; -// __u8 share; -// __u8 optional; -// __u32 aalgos; -// __u32 ealgos; -// __u32 calgos; -// } - -type XfrmUserTmpl struct { - XfrmId XfrmId - Family uint16 - Pad1 [2]byte - Saddr XfrmAddress - Reqid uint32 - Mode uint8 - Share uint8 - Optional uint8 - Pad2 byte - Aalgos uint32 - Ealgos uint32 - Calgos uint32 -} - -func (msg *XfrmUserTmpl) Len() int { - return SizeofXfrmUserTmpl -} - -func DeserializeXfrmUserTmpl(b []byte) *XfrmUserTmpl { - return (*XfrmUserTmpl)(unsafe.Pointer(&b[0:SizeofXfrmUserTmpl][0])) -} - -func (msg *XfrmUserTmpl) Serialize() []byte { - return (*(*[SizeofXfrmUserTmpl]byte)(unsafe.Pointer(msg)))[:] +func selFromPolicy(sel *nl.XfrmSelector, policy *XfrmPolicy) { + sel.Family = uint16(nl.GetIPFamily(policy.Dst.IP)) + sel.Daddr.FromIP(policy.Dst.IP) + sel.Saddr.FromIP(policy.Src.IP) + prefixlenD, _ := policy.Dst.Mask.Size() + sel.PrefixlenD = uint8(prefixlenD) + prefixlenS, _ := policy.Src.Mask.Size() + sel.PrefixlenS = uint8(prefixlenS) } // XfrmPolicyAdd will add an xfrm policy to the system. // Equivalent to: `ip xfrm policy add $policy` func XfrmPolicyAdd(policy *XfrmPolicy) error { - req := newNetlinkRequest(XFRM_MSG_NEWPOLICY, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) + req := nl.NewNetlinkRequest(nl.XFRM_MSG_NEWPOLICY, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) - msg := &XfrmUserpolicyInfo{} - msg.Sel.FromPolicy(policy) + msg := &nl.XfrmUserpolicyInfo{} + selFromPolicy(&msg.Sel, policy) msg.Priority = uint32(policy.Priority) msg.Index = uint32(policy.Index) msg.Dir = uint8(policy.Dir) - msg.Lft.SoftByteLimit = XFRM_INF - msg.Lft.HardByteLimit = XFRM_INF - msg.Lft.SoftPacketLimit = XFRM_INF - msg.Lft.HardPacketLimit = XFRM_INF + msg.Lft.SoftByteLimit = nl.XFRM_INF + msg.Lft.HardByteLimit = nl.XFRM_INF + msg.Lft.SoftPacketLimit = nl.XFRM_INF + msg.Lft.HardPacketLimit = nl.XFRM_INF req.AddData(msg) - tmplData := make([]byte, SizeofXfrmUserTmpl*len(policy.Tmpls)) + tmplData := make([]byte, nl.SizeofXfrmUserTmpl*len(policy.Tmpls)) for i, tmpl := range policy.Tmpls { - start := i * SizeofXfrmUserTmpl - userTmpl := DeserializeXfrmUserTmpl(tmplData[start : start+SizeofXfrmUserTmpl]) + start := i * nl.SizeofXfrmUserTmpl + userTmpl := nl.DeserializeXfrmUserTmpl(tmplData[start : start+nl.SizeofXfrmUserTmpl]) userTmpl.XfrmId.Daddr.FromIP(tmpl.Dst) userTmpl.Saddr.FromIP(tmpl.Src) userTmpl.XfrmId.Proto = uint8(tmpl.Proto) @@ -149,7 +46,7 @@ func XfrmPolicyAdd(policy *XfrmPolicy) error { userTmpl.Calgos = ^uint32(0) } if len(tmplData) > 0 { - tmpls := newRtAttr(XFRMA_TMPL, tmplData) + tmpls := nl.NewRtAttr(nl.XFRMA_TMPL, tmplData) req.AddData(tmpls) } @@ -161,10 +58,10 @@ func XfrmPolicyAdd(policy *XfrmPolicy) error { // the Tmpls are ignored when matching the policy to delete. // Equivalent to: `ip xfrm policy del $policy` func XfrmPolicyDel(policy *XfrmPolicy) error { - req := newNetlinkRequest(XFRM_MSG_DELPOLICY, syscall.NLM_F_ACK) + req := nl.NewNetlinkRequest(nl.XFRM_MSG_DELPOLICY, syscall.NLM_F_ACK) - msg := &XfrmUserpolicyId{} - msg.Sel.FromPolicy(policy) + msg := &nl.XfrmUserpolicyId{} + selFromPolicy(&msg.Sel, policy) msg.Index = uint32(policy.Index) msg.Dir = uint8(policy.Dir) req.AddData(msg) @@ -177,19 +74,19 @@ func XfrmPolicyDel(policy *XfrmPolicy) error { // Equivalent to: `ip xfrm policy show`. // The list can be filtered by ip family. func XfrmPolicyList(family int) ([]XfrmPolicy, error) { - req := newNetlinkRequest(XFRM_MSG_GETPOLICY, syscall.NLM_F_DUMP) + req := nl.NewNetlinkRequest(nl.XFRM_MSG_GETPOLICY, syscall.NLM_F_DUMP) - msg := newIfInfomsg(family) + msg := nl.NewIfInfomsg(family) req.AddData(msg) - msgs, err := req.Execute(syscall.NETLINK_XFRM, XFRM_MSG_NEWPOLICY) + msgs, err := req.Execute(syscall.NETLINK_XFRM, nl.XFRM_MSG_NEWPOLICY) if err != nil { return nil, err } res := make([]XfrmPolicy, 0) for _, m := range msgs { - msg := DeserializeXfrmUserpolicyInfo(m) + msg := nl.DeserializeXfrmUserpolicyInfo(m) if family != FAMILY_ALL && family != int(msg.Sel.Family) { continue @@ -203,18 +100,18 @@ func XfrmPolicyList(family int) ([]XfrmPolicy, error) { policy.Index = int(msg.Index) policy.Dir = Dir(msg.Dir) - attrs, err := parseRouteAttr(m[msg.Len():]) + attrs, err := nl.ParseRouteAttr(m[msg.Len():]) if err != nil { return nil, err } for _, attr := range attrs { switch attr.Attr.Type { - case XFRMA_TMPL: + case nl.XFRMA_TMPL: max := len(attr.Value) - for i := 0; i < max; i += SizeofXfrmUserTmpl { + for i := 0; i < max; i += nl.SizeofXfrmUserTmpl { var resTmpl XfrmPolicyTmpl - tmpl := DeserializeXfrmUserTmpl(attr.Value[i : i+SizeofXfrmUserTmpl]) + tmpl := nl.DeserializeXfrmUserTmpl(attr.Value[i : i+nl.SizeofXfrmUserTmpl]) resTmpl.Dst = tmpl.XfrmId.Daddr.ToIP() resTmpl.Src = tmpl.Saddr.ToIP() resTmpl.Proto = Proto(tmpl.XfrmId.Proto) diff --git a/xfrm_state_linux.go b/xfrm_state_linux.go index c93d690..0f1fbd0 100644 --- a/xfrm_state_linux.go +++ b/xfrm_state_linux.go @@ -3,227 +3,12 @@ package netlink import ( "fmt" "syscall" - "unsafe" + + "github.com/vishvananda/netlink/nl" ) -const ( - SizeofXfrmUsersaId = 0x18 - SizeofXfrmStats = 0x0c - SizeofXfrmUsersaInfo = 0xe0 - SizeofXfrmAlgo = 0x44 - SizeofXfrmAlgoAuth = 0x48 - SizeofXfrmEncapTmpl = 0x18 -) - -// struct xfrm_usersa_id { -// xfrm_address_t daddr; -// __be32 spi; -// __u16 family; -// __u8 proto; -// }; - -type XfrmUsersaId struct { - Daddr XfrmAddress - Spi uint32 // big endian - Family uint16 - Proto uint8 - Pad byte -} - -func (msg *XfrmUsersaId) Len() int { - return SizeofXfrmUsersaId -} - -func DeserializeXfrmUsersaId(b []byte) *XfrmUsersaId { - return (*XfrmUsersaId)(unsafe.Pointer(&b[0:SizeofXfrmUsersaId][0])) -} - -func (msg *XfrmUsersaId) Serialize() []byte { - return (*(*[SizeofXfrmUsersaId]byte)(unsafe.Pointer(msg)))[:] -} - -// struct xfrm_stats { -// __u32 replay_window; -// __u32 replay; -// __u32 integrity_failed; -// }; - -type XfrmStats struct { - ReplayWindow uint32 - Replay uint32 - IntegrityFailed uint32 -} - -func (msg *XfrmStats) Len() int { - return SizeofXfrmStats -} - -func DeserializeXfrmStats(b []byte) *XfrmStats { - return (*XfrmStats)(unsafe.Pointer(&b[0:SizeofXfrmStats][0])) -} - -func (msg *XfrmStats) Serialize() []byte { - return (*(*[SizeofXfrmStats]byte)(unsafe.Pointer(msg)))[:] -} - -// struct xfrm_usersa_info { -// struct xfrm_selector sel; -// struct xfrm_id id; -// xfrm_address_t saddr; -// struct xfrm_lifetime_cfg lft; -// struct xfrm_lifetime_cur curlft; -// struct xfrm_stats stats; -// __u32 seq; -// __u32 reqid; -// __u16 family; -// __u8 mode; /* XFRM_MODE_xxx */ -// __u8 replay_window; -// __u8 flags; -// #define XFRM_STATE_NOECN 1 -// #define XFRM_STATE_DECAP_DSCP 2 -// #define XFRM_STATE_NOPMTUDISC 4 -// #define XFRM_STATE_WILDRECV 8 -// #define XFRM_STATE_ICMP 16 -// #define XFRM_STATE_AF_UNSPEC 32 -// #define XFRM_STATE_ALIGN4 64 -// #define XFRM_STATE_ESN 128 -// }; -// -// #define XFRM_SA_XFLAG_DONT_ENCAP_DSCP 1 -// - -type XfrmUsersaInfo struct { - Sel XfrmSelector - Id XfrmId - Saddr XfrmAddress - Lft XfrmLifetimeCfg - Curlft XfrmLifetimeCur - Stats XfrmStats - Seq uint32 - Reqid uint32 - Family uint16 - Mode uint8 - ReplayWindow uint8 - Flags uint8 // TODO: investigate enum - Pad [7]byte -} - -func (msg *XfrmUsersaInfo) Len() int { - return SizeofXfrmUsersaInfo -} - -func DeserializeXfrmUsersaInfo(b []byte) *XfrmUsersaInfo { - return (*XfrmUsersaInfo)(unsafe.Pointer(&b[0:SizeofXfrmUsersaInfo][0])) -} - -func (msg *XfrmUsersaInfo) Serialize() []byte { - return (*(*[SizeofXfrmUsersaInfo]byte)(unsafe.Pointer(msg)))[:] -} - -// struct xfrm_algo { -// char alg_name[64]; -// unsigned int alg_key_len; /* in bits */ -// char alg_key[0]; -// }; - -type XfrmAlgo struct { - AlgName [64]byte - AlgKeyLen uint32 - AlgKey []byte -} - -func (msg *XfrmAlgo) Len() int { - return SizeofXfrmAlgo + int(msg.AlgKeyLen/8) -} - -func DeserializeXfrmAlgo(b []byte) *XfrmAlgo { - ret := XfrmAlgo{} - copy(ret.AlgName[:], b[0:64]) - ret.AlgKeyLen = *(*uint32)(unsafe.Pointer(&b[64])) - ret.AlgKey = b[68:ret.Len()] - return &ret -} - -func (msg *XfrmAlgo) Serialize() []byte { - b := make([]byte, msg.Len()) - copy(b[0:64], msg.AlgName[:]) - copy(b[64:68], (*(*[4]byte)(unsafe.Pointer(&msg.AlgKeyLen)))[:]) - copy(b[68:msg.Len()], msg.AlgKey[:]) - return b -} - -// struct xfrm_algo_auth { -// char alg_name[64]; -// unsigned int alg_key_len; /* in bits */ -// unsigned int alg_trunc_len; /* in bits */ -// char alg_key[0]; -// }; - -type XfrmAlgoAuth struct { - AlgName [64]byte - AlgKeyLen uint32 - AlgTruncLen uint32 - AlgKey []byte -} - -func (msg *XfrmAlgoAuth) Len() int { - return SizeofXfrmAlgoAuth + int(msg.AlgKeyLen/8) -} - -func DeserializeXfrmAlgoAuth(b []byte) *XfrmAlgoAuth { - ret := XfrmAlgoAuth{} - copy(ret.AlgName[:], b[0:64]) - ret.AlgKeyLen = *(*uint32)(unsafe.Pointer(&b[64])) - ret.AlgTruncLen = *(*uint32)(unsafe.Pointer(&b[68])) - ret.AlgKey = b[72:ret.Len()] - return &ret -} - -func (msg *XfrmAlgoAuth) Serialize() []byte { - b := make([]byte, msg.Len()) - copy(b[0:64], msg.AlgName[:]) - copy(b[64:68], (*(*[4]byte)(unsafe.Pointer(&msg.AlgKeyLen)))[:]) - copy(b[68:72], (*(*[4]byte)(unsafe.Pointer(&msg.AlgTruncLen)))[:]) - copy(b[72:msg.Len()], msg.AlgKey[:]) - return b -} - -// struct xfrm_algo_aead { -// char alg_name[64]; -// unsigned int alg_key_len; /* in bits */ -// unsigned int alg_icv_len; /* in bits */ -// char alg_key[0]; -// } - -// struct xfrm_encap_tmpl { -// __u16 encap_type; -// __be16 encap_sport; -// __be16 encap_dport; -// xfrm_address_t encap_oa; -// }; - -type XfrmEncapTmpl struct { - EncapType uint16 - EncapSport uint16 // big endian - EncapDport uint16 // big endian - Pad [2]byte - EncapOa XfrmAddress -} - -func (msg *XfrmEncapTmpl) Len() int { - return SizeofXfrmEncapTmpl -} - -func DeserializeXfrmEncapTmpl(b []byte) *XfrmEncapTmpl { - return (*XfrmEncapTmpl)(unsafe.Pointer(&b[0:SizeofXfrmEncapTmpl][0])) -} - -func (msg *XfrmEncapTmpl) Serialize() []byte { - return (*(*[SizeofXfrmEncapTmpl]byte)(unsafe.Pointer(msg)))[:] -} - func writeStateAlgo(a *XfrmStateAlgo) []byte { - algo := XfrmAlgo{ + algo := nl.XfrmAlgo{ AlgKeyLen: uint32(len(a.Key) * 8), AlgKey: a.Key, } @@ -236,7 +21,7 @@ func writeStateAlgo(a *XfrmStateAlgo) []byte { } func writeStateAlgoAuth(a *XfrmStateAlgo) []byte { - algo := XfrmAlgoAuth{ + algo := nl.XfrmAlgoAuth{ AlgKeyLen: uint32(len(a.Key) * 8), AlgTruncLen: uint32(a.TruncateLen), AlgKey: a.Key, @@ -256,39 +41,39 @@ func XfrmStateAdd(state *XfrmState) error { if state.Spi == 0 { return fmt.Errorf("Spi must be set when adding xfrm state.") } - req := newNetlinkRequest(XFRM_MSG_NEWSA, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) + req := nl.NewNetlinkRequest(nl.XFRM_MSG_NEWSA, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) - msg := &XfrmUsersaInfo{} - msg.Family = uint16(GetIPFamily(state.Dst)) + msg := &nl.XfrmUsersaInfo{} + msg.Family = uint16(nl.GetIPFamily(state.Dst)) msg.Id.Daddr.FromIP(state.Dst) msg.Saddr.FromIP(state.Src) msg.Id.Proto = uint8(state.Proto) msg.Mode = uint8(state.Mode) - msg.Id.Spi = swap32(uint32(state.Spi)) + msg.Id.Spi = nl.Swap32(uint32(state.Spi)) msg.Reqid = uint32(state.Reqid) msg.ReplayWindow = uint8(state.ReplayWindow) - msg.Lft.SoftByteLimit = XFRM_INF - msg.Lft.HardByteLimit = XFRM_INF - msg.Lft.SoftPacketLimit = XFRM_INF - msg.Lft.HardPacketLimit = XFRM_INF + msg.Lft.SoftByteLimit = nl.XFRM_INF + msg.Lft.HardByteLimit = nl.XFRM_INF + msg.Lft.SoftPacketLimit = nl.XFRM_INF + msg.Lft.HardPacketLimit = nl.XFRM_INF req.AddData(msg) if state.Auth != nil { - out := newRtAttr(XFRMA_ALG_AUTH_TRUNC, writeStateAlgoAuth(state.Auth)) + out := nl.NewRtAttr(nl.XFRMA_ALG_AUTH_TRUNC, writeStateAlgoAuth(state.Auth)) req.AddData(out) } if state.Crypt != nil { - out := newRtAttr(XFRMA_ALG_CRYPT, writeStateAlgo(state.Crypt)) + out := nl.NewRtAttr(nl.XFRMA_ALG_CRYPT, writeStateAlgo(state.Crypt)) req.AddData(out) } if state.Encap != nil { - encapData := make([]byte, SizeofXfrmEncapTmpl) - encap := DeserializeXfrmEncapTmpl(encapData) + encapData := make([]byte, nl.SizeofXfrmEncapTmpl) + encap := nl.DeserializeXfrmEncapTmpl(encapData) encap.EncapType = uint16(state.Encap.Type) - encap.EncapSport = swap16(uint16(state.Encap.SrcPort)) - encap.EncapDport = swap16(uint16(state.Encap.DstPort)) + encap.EncapSport = nl.Swap16(uint16(state.Encap.SrcPort)) + encap.EncapDport = nl.Swap16(uint16(state.Encap.DstPort)) encap.EncapOa.FromIP(state.Encap.OriginalAddress) - out := newRtAttr(XFRMA_ENCAP, encapData) + out := nl.NewRtAttr(nl.XFRMA_ENCAP, encapData) req.AddData(out) } @@ -300,18 +85,18 @@ func XfrmStateAdd(state *XfrmState) error { // the Algos are ignored when matching the state to delete. // Equivalent to: `ip xfrm state del $state` func XfrmStateDel(state *XfrmState) error { - req := newNetlinkRequest(XFRM_MSG_DELSA, syscall.NLM_F_ACK) + req := nl.NewNetlinkRequest(nl.XFRM_MSG_DELSA, syscall.NLM_F_ACK) - msg := &XfrmUsersaId{} + msg := &nl.XfrmUsersaId{} msg.Daddr.FromIP(state.Dst) - msg.Family = uint16(GetIPFamily(state.Dst)) + msg.Family = uint16(nl.GetIPFamily(state.Dst)) msg.Proto = uint8(state.Proto) - msg.Spi = swap32(uint32(state.Spi)) + msg.Spi = nl.Swap32(uint32(state.Spi)) req.AddData(msg) - saddr := XfrmAddress{} + saddr := nl.XfrmAddress{} saddr.FromIP(state.Src) - srcdata := newRtAttr(XFRMA_SRCADDR, saddr.Serialize()) + srcdata := nl.NewRtAttr(nl.XFRMA_SRCADDR, saddr.Serialize()) req.AddData(srcdata) @@ -323,19 +108,19 @@ func XfrmStateDel(state *XfrmState) error { // Equivalent to: `ip xfrm state show`. // The list can be filtered by ip family. func XfrmStateList(family int) ([]XfrmState, error) { - req := newNetlinkRequest(XFRM_MSG_GETSA, syscall.NLM_F_DUMP) + req := nl.NewNetlinkRequest(nl.XFRM_MSG_GETSA, syscall.NLM_F_DUMP) - msg := newIfInfomsg(family) + msg := nl.NewIfInfomsg(family) req.AddData(msg) - msgs, err := req.Execute(syscall.NETLINK_XFRM, XFRM_MSG_NEWSA) + msgs, err := req.Execute(syscall.NETLINK_XFRM, nl.XFRM_MSG_NEWSA) if err != nil { return nil, err } res := make([]XfrmState, 0) for _, m := range msgs { - msg := DeserializeXfrmUsersaInfo(m) + msg := nl.DeserializeXfrmUsersaInfo(m) if family != FAMILY_ALL && family != int(msg.Family) { continue @@ -347,20 +132,20 @@ func XfrmStateList(family int) ([]XfrmState, error) { state.Src = msg.Saddr.ToIP() state.Proto = Proto(msg.Id.Proto) state.Mode = Mode(msg.Mode) - state.Spi = int(swap32(msg.Id.Spi)) + state.Spi = int(nl.Swap32(msg.Id.Spi)) state.Reqid = int(msg.Reqid) state.ReplayWindow = int(msg.ReplayWindow) - attrs, err := parseRouteAttr(m[msg.Len():]) + attrs, err := nl.ParseRouteAttr(m[msg.Len():]) if err != nil { return nil, err } for _, attr := range attrs { switch attr.Attr.Type { - case XFRMA_ALG_AUTH, XFRMA_ALG_CRYPT: + case nl.XFRMA_ALG_AUTH, nl.XFRMA_ALG_CRYPT: var resAlgo *XfrmStateAlgo - if attr.Attr.Type == XFRMA_ALG_AUTH { + if attr.Attr.Type == nl.XFRMA_ALG_AUTH { if state.Auth == nil { state.Auth = new(XfrmStateAlgo) } @@ -369,23 +154,23 @@ func XfrmStateList(family int) ([]XfrmState, error) { state.Crypt = new(XfrmStateAlgo) resAlgo = state.Crypt } - algo := DeserializeXfrmAlgo(attr.Value[:]) - (*resAlgo).Name = bytesToString(algo.AlgName[:]) + algo := nl.DeserializeXfrmAlgo(attr.Value[:]) + (*resAlgo).Name = nl.BytesToString(algo.AlgName[:]) (*resAlgo).Key = algo.AlgKey - case XFRMA_ALG_AUTH_TRUNC: + case nl.XFRMA_ALG_AUTH_TRUNC: if state.Auth == nil { state.Auth = new(XfrmStateAlgo) } - algo := DeserializeXfrmAlgoAuth(attr.Value[:]) - state.Auth.Name = bytesToString(algo.AlgName[:]) + algo := nl.DeserializeXfrmAlgoAuth(attr.Value[:]) + state.Auth.Name = nl.BytesToString(algo.AlgName[:]) state.Auth.Key = algo.AlgKey state.Auth.TruncateLen = int(algo.AlgTruncLen) - case XFRMA_ENCAP: - encap := DeserializeXfrmEncapTmpl(attr.Value[:]) + case nl.XFRMA_ENCAP: + encap := nl.DeserializeXfrmEncapTmpl(attr.Value[:]) state.Encap = new(XfrmStateEncap) state.Encap.Type = EncapType(encap.EncapType) - state.Encap.SrcPort = int(swap16(encap.EncapSport)) - state.Encap.DstPort = int(swap16(encap.EncapDport)) + state.Encap.SrcPort = int(nl.Swap16(encap.EncapSport)) + state.Encap.DstPort = int(nl.Swap16(encap.EncapDport)) state.Encap.OriginalAddress = encap.EncapOa.ToIP() }