github.com/vishvananda/netlink@v1.3.1/addr_linux.go (about)

     1  package netlink
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"net"
     7  	"syscall"
     8  
     9  	"github.com/vishvananda/netlink/nl"
    10  	"github.com/vishvananda/netns"
    11  	"golang.org/x/sys/unix"
    12  )
    13  
    14  // AddrAdd will add an IP address to a link device.
    15  //
    16  // Equivalent to: `ip addr add $addr dev $link`
    17  //
    18  // If `addr` is an IPv4 address and the broadcast address is not given, it
    19  // will be automatically computed based on the IP mask if /30 or larger.
    20  // If `net.IPv4zero` is given as the broadcast address, broadcast is disabled.
    21  func AddrAdd(link Link, addr *Addr) error {
    22  	return pkgHandle.AddrAdd(link, addr)
    23  }
    24  
    25  // AddrAdd will add an IP address to a link device.
    26  //
    27  // Equivalent to: `ip addr add $addr dev $link`
    28  //
    29  // If `addr` is an IPv4 address and the broadcast address is not given, it
    30  // will be automatically computed based on the IP mask if /30 or larger.
    31  // If `net.IPv4zero` is given as the broadcast address, broadcast is disabled.
    32  func (h *Handle) AddrAdd(link Link, addr *Addr) error {
    33  	req := h.newNetlinkRequest(unix.RTM_NEWADDR, unix.NLM_F_CREATE|unix.NLM_F_EXCL|unix.NLM_F_ACK)
    34  	return h.addrHandle(link, addr, req)
    35  }
    36  
    37  // AddrReplace will replace (or, if not present, add) an IP address on a link device.
    38  //
    39  // Equivalent to: `ip addr replace $addr dev $link`
    40  //
    41  // If `addr` is an IPv4 address and the broadcast address is not given, it
    42  // will be automatically computed based on the IP mask if /30 or larger.
    43  // If `net.IPv4zero` is given as the broadcast address, broadcast is disabled.
    44  func AddrReplace(link Link, addr *Addr) error {
    45  	return pkgHandle.AddrReplace(link, addr)
    46  }
    47  
    48  // AddrReplace will replace (or, if not present, add) an IP address on a link device.
    49  //
    50  // Equivalent to: `ip addr replace $addr dev $link`
    51  //
    52  // If `addr` is an IPv4 address and the broadcast address is not given, it
    53  // will be automatically computed based on the IP mask if /30 or larger.
    54  // If `net.IPv4zero` is given as the broadcast address, broadcast is disabled.
    55  func (h *Handle) AddrReplace(link Link, addr *Addr) error {
    56  	req := h.newNetlinkRequest(unix.RTM_NEWADDR, unix.NLM_F_CREATE|unix.NLM_F_REPLACE|unix.NLM_F_ACK)
    57  	return h.addrHandle(link, addr, req)
    58  }
    59  
    60  // AddrDel will delete an IP address from a link device.
    61  //
    62  // Equivalent to: `ip addr del $addr dev $link`
    63  func AddrDel(link Link, addr *Addr) error {
    64  	return pkgHandle.AddrDel(link, addr)
    65  }
    66  
    67  // AddrDel will delete an IP address from a link device.
    68  //
    69  // Equivalent to: `ip addr del $addr dev $link`
    70  func (h *Handle) AddrDel(link Link, addr *Addr) error {
    71  	req := h.newNetlinkRequest(unix.RTM_DELADDR, unix.NLM_F_ACK)
    72  	return h.addrHandle(link, addr, req)
    73  }
    74  
    75  func (h *Handle) addrHandle(link Link, addr *Addr, req *nl.NetlinkRequest) error {
    76  	family := nl.GetIPFamily(addr.IP)
    77  	msg := nl.NewIfAddrmsg(family)
    78  	msg.Scope = uint8(addr.Scope)
    79  	if link == nil {
    80  		msg.Index = uint32(addr.LinkIndex)
    81  	} else {
    82  		base := link.Attrs()
    83  		h.ensureIndex(base)
    84  		msg.Index = uint32(base.Index)
    85  	}
    86  	mask := addr.Mask
    87  	if addr.Peer != nil {
    88  		mask = addr.Peer.Mask
    89  	}
    90  	prefixlen, masklen := mask.Size()
    91  	msg.Prefixlen = uint8(prefixlen)
    92  	req.AddData(msg)
    93  
    94  	var localAddrData []byte
    95  	if family == FAMILY_V4 {
    96  		localAddrData = addr.IP.To4()
    97  	} else {
    98  		localAddrData = addr.IP.To16()
    99  	}
   100  
   101  	localData := nl.NewRtAttr(unix.IFA_LOCAL, localAddrData)
   102  	req.AddData(localData)
   103  	var peerAddrData []byte
   104  	if addr.Peer != nil {
   105  		if family == FAMILY_V4 {
   106  			peerAddrData = addr.Peer.IP.To4()
   107  		} else {
   108  			peerAddrData = addr.Peer.IP.To16()
   109  		}
   110  	} else {
   111  		peerAddrData = localAddrData
   112  	}
   113  
   114  	addressData := nl.NewRtAttr(unix.IFA_ADDRESS, peerAddrData)
   115  	req.AddData(addressData)
   116  
   117  	if addr.Flags != 0 {
   118  		if addr.Flags <= 0xff {
   119  			msg.IfAddrmsg.Flags = uint8(addr.Flags)
   120  		} else {
   121  			b := make([]byte, 4)
   122  			native.PutUint32(b, uint32(addr.Flags))
   123  			flagsData := nl.NewRtAttr(unix.IFA_FLAGS, b)
   124  			req.AddData(flagsData)
   125  		}
   126  	}
   127  
   128  	if family == FAMILY_V4 {
   129  		// Automatically set the broadcast address if it is unset and the
   130  		// subnet is large enough to sensibly have one (/30 or larger).
   131  		// See: RFC 3021
   132  		if addr.Broadcast == nil && prefixlen < 31 {
   133  			calcBroadcast := make(net.IP, masklen/8)
   134  			for i := range localAddrData {
   135  				calcBroadcast[i] = localAddrData[i] | ^mask[i]
   136  			}
   137  			addr.Broadcast = calcBroadcast
   138  		}
   139  
   140  		if net.IPv4zero.Equal(addr.Broadcast) {
   141  			addr.Broadcast = nil
   142  		}
   143  
   144  		if addr.Broadcast != nil {
   145  			req.AddData(nl.NewRtAttr(unix.IFA_BROADCAST, addr.Broadcast))
   146  		}
   147  
   148  		if addr.Label != "" {
   149  			labelData := nl.NewRtAttr(unix.IFA_LABEL, nl.ZeroTerminated(addr.Label))
   150  			req.AddData(labelData)
   151  		}
   152  	}
   153  
   154  	// 0 is the default value for these attributes. However, 0 means "expired", while the least-surprising default
   155  	// value should be "forever". To compensate for that, only add the attributes if at least one of the values is
   156  	// non-zero, which means the caller has explicitly set them
   157  	if addr.ValidLft > 0 || addr.PreferedLft > 0 {
   158  		cachedata := nl.IfaCacheInfo{unix.IfaCacheinfo{
   159  			Valid:    uint32(addr.ValidLft),
   160  			Prefered: uint32(addr.PreferedLft),
   161  		}}
   162  		req.AddData(nl.NewRtAttr(unix.IFA_CACHEINFO, cachedata.Serialize()))
   163  	}
   164  
   165  	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
   166  	return err
   167  }
   168  
   169  // AddrList gets a list of IP addresses in the system.
   170  // Equivalent to: `ip addr show`.
   171  // The list can be filtered by link and ip family.
   172  //
   173  // If the returned error is [ErrDumpInterrupted], results may be inconsistent
   174  // or incomplete.
   175  func AddrList(link Link, family int) ([]Addr, error) {
   176  	return pkgHandle.AddrList(link, family)
   177  }
   178  
   179  // AddrList gets a list of IP addresses in the system.
   180  // Equivalent to: `ip addr show`.
   181  // The list can be filtered by link and ip family.
   182  //
   183  // If the returned error is [ErrDumpInterrupted], results may be inconsistent
   184  // or incomplete.
   185  func (h *Handle) AddrList(link Link, family int) ([]Addr, error) {
   186  	req := h.newNetlinkRequest(unix.RTM_GETADDR, unix.NLM_F_DUMP)
   187  	msg := nl.NewIfAddrmsg(family)
   188  	req.AddData(msg)
   189  
   190  	msgs, executeErr := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWADDR)
   191  	if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
   192  		return nil, executeErr
   193  	}
   194  
   195  	indexFilter := 0
   196  	if link != nil {
   197  		base := link.Attrs()
   198  		h.ensureIndex(base)
   199  		indexFilter = base.Index
   200  	}
   201  
   202  	var res []Addr
   203  	for _, m := range msgs {
   204  		addr, msgFamily, err := parseAddr(m)
   205  		if err != nil {
   206  			return res, err
   207  		}
   208  
   209  		if link != nil && addr.LinkIndex != indexFilter {
   210  			// Ignore messages from other interfaces
   211  			continue
   212  		}
   213  
   214  		if family != FAMILY_ALL && msgFamily != family {
   215  			continue
   216  		}
   217  
   218  		res = append(res, addr)
   219  	}
   220  
   221  	return res, executeErr
   222  }
   223  
   224  func parseAddr(m []byte) (addr Addr, family int, err error) {
   225  	msg := nl.DeserializeIfAddrmsg(m)
   226  
   227  	family = -1
   228  	addr.LinkIndex = -1
   229  
   230  	attrs, err1 := nl.ParseRouteAttr(m[msg.Len():])
   231  	if err1 != nil {
   232  		err = err1
   233  		return
   234  	}
   235  
   236  	family = int(msg.Family)
   237  	addr.LinkIndex = int(msg.Index)
   238  
   239  	var local, dst *net.IPNet
   240  	for _, attr := range attrs {
   241  		switch attr.Attr.Type {
   242  		case unix.IFA_ADDRESS:
   243  			dst = &net.IPNet{
   244  				IP:   attr.Value,
   245  				Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
   246  			}
   247  		case unix.IFA_LOCAL:
   248  			// iproute2 manual:
   249  			// If a peer address is specified, the local address
   250  			// cannot have a prefix length. The network prefix is
   251  			// associated with the peer rather than with the local
   252  			// address.
   253  			n := 8 * len(attr.Value)
   254  			local = &net.IPNet{
   255  				IP:   attr.Value,
   256  				Mask: net.CIDRMask(n, n),
   257  			}
   258  		case unix.IFA_BROADCAST:
   259  			addr.Broadcast = attr.Value
   260  		case unix.IFA_LABEL:
   261  			addr.Label = string(attr.Value[:len(attr.Value)-1])
   262  		case unix.IFA_FLAGS:
   263  			addr.Flags = int(native.Uint32(attr.Value[0:4]))
   264  		case unix.IFA_CACHEINFO:
   265  			ci := nl.DeserializeIfaCacheInfo(attr.Value)
   266  			addr.PreferedLft = int(ci.Prefered)
   267  			addr.ValidLft = int(ci.Valid)
   268  		}
   269  	}
   270  
   271  	// libnl addr.c comment:
   272  	// IPv6 sends the local address as IFA_ADDRESS with no
   273  	// IFA_LOCAL, IPv4 sends both IFA_LOCAL and IFA_ADDRESS
   274  	// with IFA_ADDRESS being the peer address if they differ
   275  	//
   276  	// But obviously, as there are IPv6 PtP addresses, too,
   277  	// IFA_LOCAL should also be handled for IPv6.
   278  	if local != nil {
   279  		if family == FAMILY_V4 && dst != nil && local.IP.Equal(dst.IP) {
   280  			addr.IPNet = dst
   281  		} else {
   282  			addr.IPNet = local
   283  			addr.Peer = dst
   284  		}
   285  	} else {
   286  		addr.IPNet = dst
   287  	}
   288  
   289  	addr.Scope = int(msg.Scope)
   290  
   291  	return
   292  }
   293  
   294  type AddrUpdate struct {
   295  	LinkAddress net.IPNet
   296  	LinkIndex   int
   297  	Flags       int
   298  	Scope       int
   299  	PreferedLft int
   300  	ValidLft    int
   301  	NewAddr     bool // true=added false=deleted
   302  }
   303  
   304  // AddrSubscribe takes a chan down which notifications will be sent
   305  // when addresses change.  Close the 'done' chan to stop subscription.
   306  func AddrSubscribe(ch chan<- AddrUpdate, done <-chan struct{}) error {
   307  	return addrSubscribeAt(netns.None(), netns.None(), ch, done, nil, false, 0, nil, false)
   308  }
   309  
   310  // AddrSubscribeAt works like AddrSubscribe plus it allows the caller
   311  // to choose the network namespace in which to subscribe (ns).
   312  func AddrSubscribeAt(ns netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}) error {
   313  	return addrSubscribeAt(ns, netns.None(), ch, done, nil, false, 0, nil, false)
   314  }
   315  
   316  // AddrSubscribeOptions contains a set of options to use with
   317  // AddrSubscribeWithOptions.
   318  type AddrSubscribeOptions struct {
   319  	Namespace              *netns.NsHandle
   320  	ErrorCallback          func(error)
   321  	ListExisting           bool
   322  	ReceiveBufferSize      int
   323  	ReceiveBufferForceSize bool
   324  	ReceiveTimeout         *unix.Timeval
   325  }
   326  
   327  // AddrSubscribeWithOptions work like AddrSubscribe but enable to
   328  // provide additional options to modify the behavior. Currently, the
   329  // namespace can be provided as well as an error callback.
   330  func AddrSubscribeWithOptions(ch chan<- AddrUpdate, done <-chan struct{}, options AddrSubscribeOptions) error {
   331  	if options.Namespace == nil {
   332  		none := netns.None()
   333  		options.Namespace = &none
   334  	}
   335  	return addrSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback, options.ListExisting,
   336  		options.ReceiveBufferSize, options.ReceiveTimeout, options.ReceiveBufferForceSize)
   337  }
   338  
   339  func addrSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}, cberr func(error), listExisting bool,
   340  	rcvbuf int, rcvTimeout *unix.Timeval, rcvBufForce bool) error {
   341  	s, err := nl.SubscribeAt(newNs, curNs, unix.NETLINK_ROUTE, unix.RTNLGRP_IPV4_IFADDR, unix.RTNLGRP_IPV6_IFADDR)
   342  	if err != nil {
   343  		return err
   344  	}
   345  	if rcvTimeout != nil {
   346  		if err := s.SetReceiveTimeout(rcvTimeout); err != nil {
   347  			return err
   348  		}
   349  	}
   350  	if rcvbuf != 0 {
   351  		err = s.SetReceiveBufferSize(rcvbuf, rcvBufForce)
   352  		if err != nil {
   353  			return err
   354  		}
   355  	}
   356  	if done != nil {
   357  		go func() {
   358  			<-done
   359  			s.Close()
   360  		}()
   361  	}
   362  	if listExisting {
   363  		req := pkgHandle.newNetlinkRequest(unix.RTM_GETADDR,
   364  			unix.NLM_F_DUMP)
   365  		infmsg := nl.NewIfInfomsg(unix.AF_UNSPEC)
   366  		req.AddData(infmsg)
   367  		if err := s.Send(req); err != nil {
   368  			return err
   369  		}
   370  	}
   371  	go func() {
   372  		defer close(ch)
   373  		for {
   374  			msgs, from, err := s.Receive()
   375  			if err != nil {
   376  				if cberr != nil {
   377  					cberr(fmt.Errorf("Receive failed: %v",
   378  						err))
   379  				}
   380  				return
   381  			}
   382  			if from.Pid != nl.PidKernel {
   383  				if cberr != nil {
   384  					cberr(fmt.Errorf("Wrong sender portid %d, expected %d", from.Pid, nl.PidKernel))
   385  				}
   386  				continue
   387  			}
   388  			for _, m := range msgs {
   389  				if m.Header.Type == unix.NLMSG_DONE {
   390  					continue
   391  				}
   392  				if m.Header.Type == unix.NLMSG_ERROR {
   393  					error := int32(native.Uint32(m.Data[0:4]))
   394  					if error == 0 {
   395  						continue
   396  					}
   397  					if cberr != nil {
   398  						cberr(fmt.Errorf("error message: %v",
   399  							syscall.Errno(-error)))
   400  					}
   401  					continue
   402  				}
   403  				msgType := m.Header.Type
   404  				if msgType != unix.RTM_NEWADDR && msgType != unix.RTM_DELADDR {
   405  					if cberr != nil {
   406  						cberr(fmt.Errorf("bad message type: %d", msgType))
   407  					}
   408  					continue
   409  				}
   410  
   411  				addr, _, err := parseAddr(m.Data)
   412  				if err != nil {
   413  					if cberr != nil {
   414  						cberr(fmt.Errorf("could not parse address: %v", err))
   415  					}
   416  					continue
   417  				}
   418  
   419  				ch <- AddrUpdate{LinkAddress: *addr.IPNet,
   420  					LinkIndex:   addr.LinkIndex,
   421  					NewAddr:     msgType == unix.RTM_NEWADDR,
   422  					Flags:       addr.Flags,
   423  					Scope:       addr.Scope,
   424  					PreferedLft: addr.PreferedLft,
   425  					ValidLft:    addr.ValidLft}
   426  			}
   427  		}
   428  	}()
   429  
   430  	return nil
   431  }