| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269 |
- package rtnetlink
- import (
- "errors"
- "fmt"
- "net"
- "github.com/jsimonetti/rtnetlink/internal/unix"
- "github.com/mdlayher/netlink"
- )
- var (
- // errInvalidaddressMessage is returned when a AddressMessage is malformed.
- errInvalidAddressMessage = errors.New("rtnetlink AddressMessage is invalid or too short")
- )
- var _ Message = &AddressMessage{}
- // A AddressMessage is a route netlink address message.
- type AddressMessage struct {
- // Address family (current unix.AF_INET or unix.AF_INET6)
- Family uint8
- // Prefix length
- PrefixLength uint8
- // Contains address flags
- Flags uint8
- // Address Scope
- Scope uint8
- // Interface index
- Index uint32
- // Optional attributes which are appended when not nil.
- Attributes *AddressAttributes
- }
- // MarshalBinary marshals a AddressMessage into a byte slice.
- func (m *AddressMessage) MarshalBinary() ([]byte, error) {
- b := make([]byte, unix.SizeofIfAddrmsg)
- b[0] = m.Family
- b[1] = m.PrefixLength
- b[2] = m.Flags
- b[3] = m.Scope
- nativeEndian.PutUint32(b[4:8], m.Index)
- if m.Attributes == nil {
- // No attributes to encode.
- return b, nil
- }
- ae := netlink.NewAttributeEncoder()
- err := m.Attributes.encode(ae)
- if err != nil {
- return nil, err
- }
- a, err := ae.Encode()
- if err != nil {
- return nil, err
- }
- return append(b, a...), nil
- }
- // UnmarshalBinary unmarshals the contents of a byte slice into a AddressMessage.
- func (m *AddressMessage) UnmarshalBinary(b []byte) error {
- l := len(b)
- if l < unix.SizeofIfAddrmsg {
- return errInvalidAddressMessage
- }
- m.Family = uint8(b[0])
- m.PrefixLength = uint8(b[1])
- m.Flags = uint8(b[2])
- m.Scope = uint8(b[3])
- m.Index = nativeEndian.Uint32(b[4:8])
- if l > unix.SizeofIfAddrmsg {
- ad, err := netlink.NewAttributeDecoder(b[unix.SizeofIfAddrmsg:])
- if err != nil {
- return err
- }
- var aa AddressAttributes
- if err := aa.decode(ad); err != nil {
- return err
- }
- // Must consume errors from decoder before returning.
- if err := ad.Err(); err != nil {
- return fmt.Errorf("invalid address message attributes: %v", err)
- }
- m.Attributes = &aa
- }
- return nil
- }
- // rtMessage is an empty method to sattisfy the Message interface.
- func (*AddressMessage) rtMessage() {}
- // AddressService is used to retrieve rtnetlink family information.
- type AddressService struct {
- c *Conn
- }
- // New creates a new address using the AddressMessage information.
- func (a *AddressService) New(req *AddressMessage) error {
- flags := netlink.Request | netlink.Create | netlink.Acknowledge | netlink.Excl
- _, err := a.c.Execute(req, unix.RTM_NEWADDR, flags)
- if err != nil {
- return err
- }
- return nil
- }
- // Delete removes an address using the AddressMessage information.
- func (a *AddressService) Delete(req *AddressMessage) error {
- flags := netlink.Request | netlink.Acknowledge
- _, err := a.c.Execute(req, unix.RTM_DELADDR, flags)
- if err != nil {
- return err
- }
- return nil
- }
- // List retrieves all addresses.
- func (a *AddressService) List() ([]AddressMessage, error) {
- req := AddressMessage{}
- flags := netlink.Request | netlink.Dump
- msgs, err := a.c.Execute(&req, unix.RTM_GETADDR, flags)
- if err != nil {
- return nil, err
- }
- addresses := make([]AddressMessage, len(msgs))
- for i := range msgs {
- addresses[i] = *msgs[i].(*AddressMessage)
- }
- return addresses, nil
- }
- // AddressAttributes contains all attributes for an interface.
- type AddressAttributes struct {
- Address net.IP // Interface Ip address
- Local net.IP // Local Ip address
- Label string
- Broadcast net.IP // Broadcast Ip address
- Anycast net.IP // Anycast Ip address
- CacheInfo CacheInfo // Address information
- Multicast net.IP // Multicast Ip address
- Flags uint32 // Address flags
- }
- func (a *AddressAttributes) decode(ad *netlink.AttributeDecoder) error {
- for ad.Next() {
- switch ad.Type() {
- case unix.IFA_UNSPEC:
- // unused attribute
- case unix.IFA_ADDRESS:
- ad.Do(decodeIP(&a.Address))
- case unix.IFA_LOCAL:
- ad.Do(decodeIP(&a.Local))
- case unix.IFA_LABEL:
- a.Label = ad.String()
- case unix.IFA_BROADCAST:
- ad.Do(decodeIP(&a.Broadcast))
- case unix.IFA_ANYCAST:
- ad.Do(decodeIP(&a.Anycast))
- case unix.IFA_CACHEINFO:
- ad.Do(a.CacheInfo.decode)
- case unix.IFA_MULTICAST:
- ad.Do(decodeIP(&a.Multicast))
- case unix.IFA_FLAGS:
- a.Flags = ad.Uint32()
- }
- }
- return nil
- }
- func (a *AddressAttributes) encode(ae *netlink.AttributeEncoder) error {
- ae.Uint16(unix.IFA_UNSPEC, 0)
- ae.Do(unix.IFA_ADDRESS, encodeIP(a.Address))
- if a.Local != nil {
- ae.Do(unix.IFA_LOCAL, encodeIP(a.Local))
- }
- if a.Broadcast != nil {
- ae.Do(unix.IFA_BROADCAST, encodeIP(a.Broadcast))
- }
- if a.Anycast != nil {
- ae.Do(unix.IFA_ANYCAST, encodeIP(a.Anycast))
- }
- if a.Multicast != nil {
- ae.Do(unix.IFA_MULTICAST, encodeIP(a.Multicast))
- }
- if a.Label != "" {
- ae.String(unix.IFA_LABEL, a.Label)
- }
- ae.Uint32(unix.IFA_FLAGS, a.Flags)
- return nil
- }
- // CacheInfo contains address information
- type CacheInfo struct {
- Prefered uint32
- Valid uint32
- Created uint32
- Updated uint32
- }
- // decode decodes raw bytes into a CacheInfo's fields.
- func (c *CacheInfo) decode(b []byte) error {
- if len(b) != 16 {
- return fmt.Errorf("rtnetlink: incorrect CacheInfo size, want: 16, got: %d", len(b))
- }
- c.Prefered = nativeEndian.Uint32(b[0:4])
- c.Valid = nativeEndian.Uint32(b[4:8])
- c.Created = nativeEndian.Uint32(b[8:12])
- c.Updated = nativeEndian.Uint32(b[12:16])
- return nil
- }
- // encodeIP is a helper for validating and encoding IPv4 and IPv6 addresses as
- // appropriate for the specified netlink attribute type. It should be used
- // with (*netlink.AttributeEncoder).Do.
- func encodeIP(ip net.IP) func() ([]byte, error) {
- return func() ([]byte, error) {
- // Don't allow nil or non 4/16-byte addresses.
- if ip == nil || ip.To16() == nil {
- return nil, fmt.Errorf("rtnetlink: cannot encode invalid IP address: %s", ip)
- }
- if ip4 := ip.To4(); ip4 != nil {
- // IPv4 address.
- return ip4, nil
- }
- // IPv6 address.
- return ip, nil
- }
- }
- // decodeIP is a helper for validating and decoding IPv4 and IPv6 addresses as
- // appropriate for the specified netlink attribute type. It should be used with
- // (*netlink.AttributeDecoder).Do.
- func decodeIP(ip *net.IP) func(b []byte) error {
- return func(b []byte) error {
- if l := len(b); l != 4 && l != 16 {
- return fmt.Errorf("rtnetlink: invalid IP address length: %d", l)
- }
- // We cannot retain b outside the closure, so make a copy into ip.
- *ip = make(net.IP, len(b))
- copy(*ip, b)
- return nil
- }
- }
|