package syscall
import (
"sync"
"unsafe"
)
func nlmAlignOf (msglen int ) int {
return (msglen + NLMSG_ALIGNTO - 1 ) & ^(NLMSG_ALIGNTO - 1 )
}
func rtaAlignOf (attrlen int ) int {
return (attrlen + RTA_ALIGNTO - 1 ) & ^(RTA_ALIGNTO - 1 )
}
type NetlinkRouteRequest struct {
Header NlMsghdr
Data RtGenmsg
}
func (rr *NetlinkRouteRequest ) toWireFormat () []byte {
b := make ([]byte , rr .Header .Len )
*(*uint32 )(unsafe .Pointer (&b [0 :4 ][0 ])) = rr .Header .Len
*(*uint16 )(unsafe .Pointer (&b [4 :6 ][0 ])) = rr .Header .Type
*(*uint16 )(unsafe .Pointer (&b [6 :8 ][0 ])) = rr .Header .Flags
*(*uint32 )(unsafe .Pointer (&b [8 :12 ][0 ])) = rr .Header .Seq
*(*uint32 )(unsafe .Pointer (&b [12 :16 ][0 ])) = rr .Header .Pid
b [16 ] = byte (rr .Data .Family )
return b
}
func newNetlinkRouteRequest (proto , seq , family int ) []byte {
rr := &NetlinkRouteRequest {}
rr .Header .Len = uint32 (NLMSG_HDRLEN + SizeofRtGenmsg )
rr .Header .Type = uint16 (proto )
rr .Header .Flags = NLM_F_DUMP | NLM_F_REQUEST
rr .Header .Seq = uint32 (seq )
rr .Data .Family = uint8 (family )
return rr .toWireFormat ()
}
var pageBufPool = &sync .Pool {New : func () any {
b := make ([]byte , Getpagesize ())
return &b
}}
func NetlinkRIB (proto , family int ) ([]byte , error ) {
s , err := Socket (AF_NETLINK , SOCK_RAW |SOCK_CLOEXEC , NETLINK_ROUTE )
if err != nil {
return nil , err
}
defer Close (s )
sa := &SockaddrNetlink {Family : AF_NETLINK }
if err := Bind (s , sa ); err != nil {
return nil , err
}
wb := newNetlinkRouteRequest (proto , 1 , family )
if err := Sendto (s , wb , 0 , sa ); err != nil {
return nil , err
}
lsa , err := Getsockname (s )
if err != nil {
return nil , err
}
lsanl , ok := lsa .(*SockaddrNetlink )
if !ok {
return nil , EINVAL
}
var tab []byte
rbNew := pageBufPool .Get ().(*[]byte )
defer pageBufPool .Put (rbNew )
done :
for {
rb := *rbNew
nr , _ , err := Recvfrom (s , rb , 0 )
if err != nil {
return nil , err
}
if nr < NLMSG_HDRLEN {
return nil , EINVAL
}
rb = rb [:nr ]
tab = append (tab , rb ...)
msgs , err := ParseNetlinkMessage (rb )
if err != nil {
return nil , err
}
for _ , m := range msgs {
if m .Header .Seq != 1 || m .Header .Pid != lsanl .Pid {
return nil , EINVAL
}
if m .Header .Type == NLMSG_DONE {
break done
}
if m .Header .Type == NLMSG_ERROR {
return nil , EINVAL
}
}
}
return tab , nil
}
type NetlinkMessage struct {
Header NlMsghdr
Data []byte
}
func ParseNetlinkMessage (b []byte ) ([]NetlinkMessage , error ) {
var msgs []NetlinkMessage
for len (b ) >= NLMSG_HDRLEN {
h , dbuf , dlen , err := netlinkMessageHeaderAndData (b )
if err != nil {
return nil , err
}
m := NetlinkMessage {Header : *h , Data : dbuf [:int (h .Len )-NLMSG_HDRLEN ]}
msgs = append (msgs , m )
b = b [dlen :]
}
return msgs , nil
}
func netlinkMessageHeaderAndData (b []byte ) (*NlMsghdr , []byte , int , error ) {
h := (*NlMsghdr )(unsafe .Pointer (&b [0 ]))
l := nlmAlignOf (int (h .Len ))
if int (h .Len ) < NLMSG_HDRLEN || l > len (b ) {
return nil , nil , 0 , EINVAL
}
return h , b [NLMSG_HDRLEN :], l , nil
}
type NetlinkRouteAttr struct {
Attr RtAttr
Value []byte
}
func ParseNetlinkRouteAttr (m *NetlinkMessage ) ([]NetlinkRouteAttr , error ) {
var b []byte
switch m .Header .Type {
case RTM_NEWLINK , RTM_DELLINK :
b = m .Data [SizeofIfInfomsg :]
case RTM_NEWADDR , RTM_DELADDR :
b = m .Data [SizeofIfAddrmsg :]
case RTM_NEWROUTE , RTM_DELROUTE :
b = m .Data [SizeofRtMsg :]
default :
return nil , EINVAL
}
var attrs []NetlinkRouteAttr
for len (b ) >= SizeofRtAttr {
a , vbuf , alen , err := netlinkRouteAttrAndValue (b )
if err != nil {
return nil , err
}
ra := NetlinkRouteAttr {Attr : *a , Value : vbuf [:int (a .Len )-SizeofRtAttr ]}
attrs = append (attrs , ra )
b = b [alen :]
}
return attrs , nil
}
func netlinkRouteAttrAndValue (b []byte ) (*RtAttr , []byte , int , error ) {
a := (*RtAttr )(unsafe .Pointer (&b [0 ]))
if int (a .Len ) < SizeofRtAttr || int (a .Len ) > len (b ) {
return nil , nil , 0 , EINVAL
}
return a , b [SizeofRtAttr :], rtaAlignOf (int (a .Len )), nil
}
The pages are generated with Golds v0.6.7 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds .