package syscall
import (
"runtime"
"unsafe"
)
var (
freebsdConfArch string
minRoutingSockaddrLen = rsaAlignOf (0 )
)
func rsaAlignOf (salen int ) int {
salign := sizeofPtr
if darwin64Bit {
salign = 4
} else if netbsd32Bit {
salign = 8
} else if runtime .GOOS == "freebsd" {
if freebsdConfArch == "amd64" {
salign = 8
}
}
if salen == 0 {
return salign
}
return (salen + salign - 1 ) & ^(salign - 1 )
}
func parseSockaddrLink (b []byte ) (*SockaddrDatalink , error ) {
if len (b ) < 8 {
return nil , EINVAL
}
sa , _ , err := parseLinkLayerAddr (b [4 :])
if err != nil {
return nil , err
}
rsa := (*RawSockaddrDatalink )(unsafe .Pointer (&b [0 ]))
sa .Len = rsa .Len
sa .Family = rsa .Family
sa .Index = rsa .Index
return sa , nil
}
func parseLinkLayerAddr (b []byte ) (*SockaddrDatalink , int , error ) {
type linkLayerAddr struct {
Type byte
Nlen byte
Alen byte
Slen byte
}
lla := (*linkLayerAddr )(unsafe .Pointer (&b [0 ]))
l := 4 + int (lla .Nlen ) + int (lla .Alen ) + int (lla .Slen )
if len (b ) < l {
return nil , 0 , EINVAL
}
b = b [4 :]
sa := &SockaddrDatalink {Type : lla .Type , Nlen : lla .Nlen , Alen : lla .Alen , Slen : lla .Slen }
for i := 0 ; len (sa .Data ) > i && i < l -4 ; i ++ {
sa .Data [i ] = int8 (b [i ])
}
return sa , rsaAlignOf (l ), nil
}
func parseSockaddrInet (b []byte , family byte ) (Sockaddr , error ) {
switch family {
case AF_INET :
if len (b ) < SizeofSockaddrInet4 {
return nil , EINVAL
}
rsa := (*RawSockaddrAny )(unsafe .Pointer (&b [0 ]))
return anyToSockaddr (rsa )
case AF_INET6 :
if len (b ) < SizeofSockaddrInet6 {
return nil , EINVAL
}
rsa := (*RawSockaddrAny )(unsafe .Pointer (&b [0 ]))
return anyToSockaddr (rsa )
default :
return nil , EINVAL
}
}
const (
offsetofInet4 = int (unsafe .Offsetof (RawSockaddrInet4 {}.Addr ))
offsetofInet6 = int (unsafe .Offsetof (RawSockaddrInet6 {}.Addr ))
)
func parseNetworkLayerAddr (b []byte , family byte ) (Sockaddr , error ) {
l := int (rsaAlignOf (int (b [0 ])))
if len (b ) < l {
return nil , EINVAL
}
switch {
case b [0 ] == SizeofSockaddrInet6 :
sa := &SockaddrInet6 {}
copy (sa .Addr [:], b [offsetofInet6 :])
return sa , nil
case family == AF_INET6 :
sa := &SockaddrInet6 {}
if l -1 < offsetofInet6 {
copy (sa .Addr [:], b [1 :l ])
} else {
copy (sa .Addr [:], b [l -offsetofInet6 :l ])
}
return sa , nil
case b [0 ] == SizeofSockaddrInet4 :
sa := &SockaddrInet4 {}
copy (sa .Addr [:], b [offsetofInet4 :])
return sa , nil
default :
sa := &SockaddrInet4 {}
if l -1 < offsetofInet4 {
copy (sa .Addr [:], b [1 :l ])
} else {
copy (sa .Addr [:], b [l -offsetofInet4 :l ])
}
return sa , nil
}
}
func RouteRIB (facility , param int ) ([]byte , error ) {
mib := []_C_int {CTL_NET , AF_ROUTE , 0 , 0 , _C_int (facility ), _C_int (param )}
n := uintptr (0 )
if err := sysctl (mib , nil , &n , nil , 0 ); err != nil {
return nil , err
}
if n == 0 {
return nil , nil
}
tab := make ([]byte , n )
if err := sysctl (mib , &tab [0 ], &n , nil , 0 ); err != nil {
return nil , err
}
return tab [:n ], nil
}
type RoutingMessage interface {
sockaddr () ([]Sockaddr , error )
}
const anyMessageLen = int (unsafe .Sizeof (anyMessage {}))
type anyMessage struct {
Msglen uint16
Version uint8
Type uint8
}
type RouteMessage struct {
Header RtMsghdr
Data []byte
}
func (m *RouteMessage ) sockaddr () ([]Sockaddr , error ) {
var sas [RTAX_MAX ]Sockaddr
b := m .Data [:]
family := uint8 (AF_UNSPEC )
for i := uint (0 ); i < RTAX_MAX && len (b ) >= minRoutingSockaddrLen ; i ++ {
if m .Header .Addrs &(1 <<i ) == 0 {
continue
}
rsa := (*RawSockaddr )(unsafe .Pointer (&b [0 ]))
switch rsa .Family {
case AF_LINK :
sa , err := parseSockaddrLink (b )
if err != nil {
return nil , err
}
sas [i ] = sa
b = b [rsaAlignOf (int (rsa .Len )):]
case AF_INET , AF_INET6 :
sa , err := parseSockaddrInet (b , rsa .Family )
if err != nil {
return nil , err
}
sas [i ] = sa
b = b [rsaAlignOf (int (rsa .Len )):]
family = rsa .Family
default :
sa , err := parseNetworkLayerAddr (b , family )
if err != nil {
return nil , err
}
sas [i ] = sa
b = b [rsaAlignOf (int (b [0 ])):]
}
}
return sas [:], nil
}
type InterfaceMessage struct {
Header IfMsghdr
Data []byte
}
func (m *InterfaceMessage ) sockaddr () ([]Sockaddr , error ) {
var sas [RTAX_MAX ]Sockaddr
if m .Header .Addrs &RTA_IFP == 0 {
return nil , nil
}
sa , err := parseSockaddrLink (m .Data [:])
if err != nil {
return nil , err
}
sas [RTAX_IFP ] = sa
return sas [:], nil
}
type InterfaceAddrMessage struct {
Header IfaMsghdr
Data []byte
}
func (m *InterfaceAddrMessage ) sockaddr () ([]Sockaddr , error ) {
var sas [RTAX_MAX ]Sockaddr
b := m .Data [:]
family := uint8 (AF_UNSPEC )
for i := uint (0 ); i < RTAX_MAX && len (b ) >= minRoutingSockaddrLen ; i ++ {
if m .Header .Addrs &(1 <<i ) == 0 {
continue
}
rsa := (*RawSockaddr )(unsafe .Pointer (&b [0 ]))
switch rsa .Family {
case AF_LINK :
sa , err := parseSockaddrLink (b )
if err != nil {
return nil , err
}
sas [i ] = sa
b = b [rsaAlignOf (int (rsa .Len )):]
case AF_INET , AF_INET6 :
sa , err := parseSockaddrInet (b , rsa .Family )
if err != nil {
return nil , err
}
sas [i ] = sa
b = b [rsaAlignOf (int (rsa .Len )):]
family = rsa .Family
default :
sa , err := parseNetworkLayerAddr (b , family )
if err != nil {
return nil , err
}
sas [i ] = sa
b = b [rsaAlignOf (int (b [0 ])):]
}
}
return sas [:], nil
}
func ParseRoutingMessage (b []byte ) (msgs []RoutingMessage , err error ) {
nmsgs , nskips := 0 , 0
for len (b ) >= anyMessageLen {
nmsgs ++
any := (*anyMessage )(unsafe .Pointer (&b [0 ]))
if any .Version != RTM_VERSION {
b = b [any .Msglen :]
continue
}
if m := any .toRoutingMessage (b ); m == nil {
nskips ++
} else {
msgs = append (msgs , m )
}
b = b [any .Msglen :]
}
if nmsgs != len (msgs )+nskips {
return nil , EINVAL
}
return msgs , nil
}
func ParseRoutingSockaddr (msg RoutingMessage ) ([]Sockaddr , error ) {
sas , err := msg .sockaddr ()
if err != nil {
return nil , err
}
return sas , nil
}
The pages are generated with Golds v0.3.6 . (GOOS=darwin 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 .