Move all low level calls into nl subpackage

This commit is contained in:
Vishvananda Ishaya 2014-09-18 19:04:48 -07:00
parent c84dba1b12
commit 1a26b9f251
19 changed files with 691 additions and 695 deletions

View File

@ -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
}

View File

@ -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]))
}
}

View File

@ -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

View File

@ -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)
}
}

48
nl/addr_linux.go Normal file
View File

@ -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
}

View File

@ -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
}

View File

@ -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)

View File

@ -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
}

34
nl/route_linux.go Normal file
View File

@ -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)))[:]
}

View File

@ -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
}

View File

@ -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;

View File

@ -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
}

120
nl/xfrm_policy_linux.go Normal file
View File

@ -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)))[:]
}

View File

@ -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
}

222
nl/xfrm_state_linux.go Normal file
View File

@ -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)))[:]
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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)

View File

@ -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()
}