package route
import "runtime"
type Addr interface {
Family () int
}
type LinkAddr struct {
Index int
Name string
Addr []byte
}
func (a *LinkAddr ) Family () int { return sysAF_LINK }
func (a *LinkAddr ) lenAndSpace () (int , int ) {
l := 8 + len (a .Name ) + len (a .Addr )
return l , roundup (l )
}
func (a *LinkAddr ) marshal (b []byte ) (int , error ) {
l , ll := a .lenAndSpace ()
if len (b ) < ll {
return 0 , errShortBuffer
}
nlen , alen := len (a .Name ), len (a .Addr )
if nlen > 255 || alen > 255 {
return 0 , errInvalidAddr
}
b [0 ] = byte (l )
b [1 ] = sysAF_LINK
if a .Index > 0 {
nativeEndian .PutUint16 (b [2 :4 ], uint16 (a .Index ))
}
data := b [8 :]
if nlen > 0 {
b [5 ] = byte (nlen )
copy (data [:nlen ], a .Name )
data = data [nlen :]
}
if alen > 0 {
b [6 ] = byte (alen )
copy (data [:alen ], a .Addr )
data = data [alen :]
}
return ll , nil
}
func parseLinkAddr (b []byte ) (Addr , error ) {
if len (b ) < 8 {
return nil , errInvalidAddr
}
_ , a , err := parseKernelLinkAddr (sysAF_LINK , b [4 :])
if err != nil {
return nil , err
}
a .(*LinkAddr ).Index = int (nativeEndian .Uint16 (b [2 :4 ]))
return a , nil
}
func parseKernelLinkAddr (_ int , b []byte ) (int , Addr , error ) {
nlen , alen , slen := int (b [1 ]), int (b [2 ]), int (b [3 ])
if nlen == 0xff {
nlen = 0
}
if alen == 0xff {
alen = 0
}
if slen == 0xff {
slen = 0
}
l := 4 + nlen + alen + slen
if len (b ) < l {
return 0 , nil , errInvalidAddr
}
data := b [4 :]
var name string
var addr []byte
if nlen > 0 {
name = string (data [:nlen ])
data = data [nlen :]
}
if alen > 0 {
addr = data [:alen ]
data = data [alen :]
}
return l , &LinkAddr {Name : name , Addr : addr }, nil
}
type Inet4Addr struct {
IP [4 ]byte
}
func (a *Inet4Addr ) Family () int { return sysAF_INET }
func (a *Inet4Addr ) lenAndSpace () (int , int ) {
return sizeofSockaddrInet , roundup (sizeofSockaddrInet )
}
func (a *Inet4Addr ) marshal (b []byte ) (int , error ) {
l , ll := a .lenAndSpace ()
if len (b ) < ll {
return 0 , errShortBuffer
}
b [0 ] = byte (l )
b [1 ] = sysAF_INET
copy (b [4 :8 ], a .IP [:])
return ll , nil
}
type Inet6Addr struct {
IP [16 ]byte
ZoneID int
}
func (a *Inet6Addr ) Family () int { return sysAF_INET6 }
func (a *Inet6Addr ) lenAndSpace () (int , int ) {
return sizeofSockaddrInet6 , roundup (sizeofSockaddrInet6 )
}
func (a *Inet6Addr ) marshal (b []byte ) (int , error ) {
l , ll := a .lenAndSpace ()
if len (b ) < ll {
return 0 , errShortBuffer
}
b [0 ] = byte (l )
b [1 ] = sysAF_INET6
copy (b [8 :24 ], a .IP [:])
if a .ZoneID > 0 {
nativeEndian .PutUint32 (b [24 :28 ], uint32 (a .ZoneID ))
}
return ll , nil
}
func parseInetAddr (af int , b []byte ) (Addr , error ) {
switch af {
case sysAF_INET :
if len (b ) < sizeofSockaddrInet {
return nil , errInvalidAddr
}
a := &Inet4Addr {}
copy (a .IP [:], b [4 :8 ])
return a , nil
case sysAF_INET6 :
if len (b ) < sizeofSockaddrInet6 {
return nil , errInvalidAddr
}
a := &Inet6Addr {ZoneID : int (nativeEndian .Uint32 (b [24 :28 ]))}
copy (a .IP [:], b [8 :24 ])
if a .IP [0 ] == 0xfe && a .IP [1 ]&0xc0 == 0x80 || a .IP [0 ] == 0xff && (a .IP [1 ]&0x0f == 0x01 || a .IP [1 ]&0x0f == 0x02 ) {
id := int (bigEndian .Uint16 (a .IP [2 :4 ]))
if id != 0 {
a .ZoneID = id
a .IP [2 ], a .IP [3 ] = 0 , 0
}
}
return a , nil
default :
return nil , errInvalidAddr
}
}
func parseKernelInetAddr (af int , b []byte ) (int , Addr , error ) {
l := int (b [0 ])
if runtime .GOOS == "darwin" || runtime .GOOS == "ios" {
if l == 0 || len (b ) > roundup (l ) {
l = roundup (l )
}
} else {
l = roundup (l )
}
if len (b ) < l {
return 0 , nil , errInvalidAddr
}
const (
off4 = 4
off6 = 8
)
switch {
case b [0 ] == sizeofSockaddrInet6 :
a := &Inet6Addr {}
copy (a .IP [:], b [off6 :off6 +16 ])
return int (b [0 ]), a , nil
case af == sysAF_INET6 :
a := &Inet6Addr {}
if l -1 < off6 {
copy (a .IP [:], b [1 :l ])
} else {
copy (a .IP [:], b [l -off6 :l ])
}
return int (b [0 ]), a , nil
case b [0 ] == sizeofSockaddrInet :
a := &Inet4Addr {}
copy (a .IP [:], b [off4 :off4 +4 ])
return int (b [0 ]), a , nil
default :
a := &Inet4Addr {}
if l -1 < off4 {
copy (a .IP [:], b [1 :l ])
} else {
copy (a .IP [:], b [l -off4 :l ])
}
return int (b [0 ]), a , nil
}
}
type DefaultAddr struct {
af int
Raw []byte
}
func (a *DefaultAddr ) Family () int { return a .af }
func (a *DefaultAddr ) lenAndSpace () (int , int ) {
l := len (a .Raw )
return l , roundup (l )
}
func (a *DefaultAddr ) marshal (b []byte ) (int , error ) {
l , ll := a .lenAndSpace ()
if len (b ) < ll {
return 0 , errShortBuffer
}
if l > 255 {
return 0 , errInvalidAddr
}
b [1 ] = byte (l )
copy (b [:l ], a .Raw )
return ll , nil
}
func parseDefaultAddr (b []byte ) (Addr , error ) {
if len (b ) < 2 || len (b ) < int (b [0 ]) {
return nil , errInvalidAddr
}
a := &DefaultAddr {af : int (b [1 ]), Raw : b [:b [0 ]]}
return a , nil
}
func addrsSpace (as []Addr ) int {
var l int
for _ , a := range as {
switch a := a .(type ) {
case *LinkAddr :
_ , ll := a .lenAndSpace ()
l += ll
case *Inet4Addr :
_ , ll := a .lenAndSpace ()
l += ll
case *Inet6Addr :
_ , ll := a .lenAndSpace ()
l += ll
case *DefaultAddr :
_ , ll := a .lenAndSpace ()
l += ll
}
}
return l
}
func marshalAddrs (b []byte , as []Addr ) (uint , error ) {
var attrs uint
for i , a := range as {
switch a := a .(type ) {
case *LinkAddr :
l , err := a .marshal (b )
if err != nil {
return 0 , err
}
b = b [l :]
attrs |= 1 << uint (i )
case *Inet4Addr :
l , err := a .marshal (b )
if err != nil {
return 0 , err
}
b = b [l :]
attrs |= 1 << uint (i )
case *Inet6Addr :
l , err := a .marshal (b )
if err != nil {
return 0 , err
}
b = b [l :]
attrs |= 1 << uint (i )
case *DefaultAddr :
l , err := a .marshal (b )
if err != nil {
return 0 , err
}
b = b [l :]
attrs |= 1 << uint (i )
}
}
return attrs , nil
}
func parseAddrs (attrs uint , fn func (int , []byte ) (int , Addr , error ), b []byte ) ([]Addr , error ) {
var as [sysRTAX_MAX ]Addr
af := int (sysAF_UNSPEC )
for i := uint (0 ); i < sysRTAX_MAX && len (b ) >= roundup (0 ); i ++ {
if attrs &(1 <<i ) == 0 {
continue
}
if i <= sysRTAX_BRD {
switch b [1 ] {
case sysAF_LINK :
a , err := parseLinkAddr (b )
if err != nil {
return nil , err
}
as [i ] = a
l := roundup (int (b [0 ]))
if len (b ) < l {
return nil , errMessageTooShort
}
b = b [l :]
case sysAF_INET , sysAF_INET6 :
af = int (b [1 ])
a , err := parseInetAddr (af , b )
if err != nil {
return nil , err
}
as [i ] = a
l := roundup (int (b [0 ]))
if len (b ) < l {
return nil , errMessageTooShort
}
b = b [l :]
default :
l , a , err := fn (af , b )
if err != nil {
return nil , err
}
as [i ] = a
ll := roundup (l )
if len (b ) < ll {
b = b [l :]
} else {
b = b [ll :]
}
}
} else {
a , err := parseDefaultAddr (b )
if err != nil {
return nil , err
}
as [i ] = a
l := roundup (int (b [0 ]))
if len (b ) < l {
return nil , errMessageTooShort
}
b = b [l :]
}
}
return as [:], 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 .