gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/tcpip/network/arp/arp.go (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package arp implements the ARP network protocol. It is used to resolve
    16  // IPv4 addresses into link-local MAC addresses, and advertises IPv4
    17  // addresses of its stack with the local network.
    18  package arp
    19  
    20  import (
    21  	"fmt"
    22  	"reflect"
    23  
    24  	"gvisor.dev/gvisor/pkg/atomicbitops"
    25  	"gvisor.dev/gvisor/pkg/sync"
    26  	"gvisor.dev/gvisor/pkg/tcpip"
    27  	"gvisor.dev/gvisor/pkg/tcpip/header"
    28  	"gvisor.dev/gvisor/pkg/tcpip/header/parse"
    29  	"gvisor.dev/gvisor/pkg/tcpip/network/internal/ip"
    30  	"gvisor.dev/gvisor/pkg/tcpip/stack"
    31  )
    32  
    33  const (
    34  	// ProtocolNumber is the ARP protocol number.
    35  	ProtocolNumber = header.ARPProtocolNumber
    36  )
    37  
    38  var _ stack.DuplicateAddressDetector = (*endpoint)(nil)
    39  var _ stack.LinkAddressResolver = (*endpoint)(nil)
    40  var _ ip.DADProtocol = (*endpoint)(nil)
    41  
    42  // ARP endpoints need to implement stack.NetworkEndpoint because the stack
    43  // considers the layer above the link-layer a network layer; the only
    44  // facility provided by the stack to deliver packets to a layer above
    45  // the link-layer is via stack.NetworkEndpoint.HandlePacket.
    46  var _ stack.NetworkEndpoint = (*endpoint)(nil)
    47  
    48  type endpoint struct {
    49  	protocol *protocol
    50  
    51  	// enabled is set to 1 when the NIC is enabled and 0 when it is disabled.
    52  	enabled atomicbitops.Uint32
    53  
    54  	nic   stack.NetworkInterface
    55  	stats sharedStats
    56  
    57  	// mu protects annotated fields below.
    58  	mu sync.Mutex
    59  
    60  	// +checklocks:mu
    61  	dad ip.DAD
    62  }
    63  
    64  // CheckDuplicateAddress implements stack.DuplicateAddressDetector.
    65  func (e *endpoint) CheckDuplicateAddress(addr tcpip.Address, h stack.DADCompletionHandler) stack.DADCheckAddressDisposition {
    66  	e.mu.Lock()
    67  	defer e.mu.Unlock()
    68  	return e.dad.CheckDuplicateAddressLocked(addr, h)
    69  }
    70  
    71  // SetDADConfigurations implements stack.DuplicateAddressDetector.
    72  func (e *endpoint) SetDADConfigurations(c stack.DADConfigurations) {
    73  	e.mu.Lock()
    74  	defer e.mu.Unlock()
    75  	e.dad.SetConfigsLocked(c)
    76  }
    77  
    78  // DuplicateAddressProtocol implements stack.DuplicateAddressDetector.
    79  func (*endpoint) DuplicateAddressProtocol() tcpip.NetworkProtocolNumber {
    80  	return header.IPv4ProtocolNumber
    81  }
    82  
    83  // SendDADMessage implements ip.DADProtocol.
    84  func (e *endpoint) SendDADMessage(addr tcpip.Address, _ []byte) tcpip.Error {
    85  	return e.sendARPRequest(header.IPv4Any, addr, header.EthernetBroadcastAddress)
    86  }
    87  
    88  func (e *endpoint) Enable() tcpip.Error {
    89  	if !e.nic.Enabled() {
    90  		return &tcpip.ErrNotPermitted{}
    91  	}
    92  
    93  	e.setEnabled(true)
    94  	return nil
    95  }
    96  
    97  func (e *endpoint) Enabled() bool {
    98  	return e.nic.Enabled() && e.isEnabled()
    99  }
   100  
   101  // isEnabled returns true if the endpoint is enabled, regardless of the
   102  // enabled status of the NIC.
   103  func (e *endpoint) isEnabled() bool {
   104  	return e.enabled.Load() == 1
   105  }
   106  
   107  // setEnabled sets the enabled status for the endpoint.
   108  func (e *endpoint) setEnabled(v bool) {
   109  	if v {
   110  		e.enabled.Store(1)
   111  	} else {
   112  		e.enabled.Store(0)
   113  	}
   114  }
   115  
   116  func (e *endpoint) Disable() {
   117  	e.setEnabled(false)
   118  }
   119  
   120  // DefaultTTL is unused for ARP. It implements stack.NetworkEndpoint.
   121  func (*endpoint) DefaultTTL() uint8 {
   122  	return 0
   123  }
   124  
   125  func (e *endpoint) MTU() uint32 {
   126  	lmtu := e.nic.MTU()
   127  	return lmtu - uint32(e.MaxHeaderLength())
   128  }
   129  
   130  func (e *endpoint) MaxHeaderLength() uint16 {
   131  	return e.nic.MaxHeaderLength() + header.ARPSize
   132  }
   133  
   134  func (*endpoint) Close() {}
   135  
   136  func (*endpoint) WritePacket(*stack.Route, stack.NetworkHeaderParams, *stack.PacketBuffer) tcpip.Error {
   137  	return &tcpip.ErrNotSupported{}
   138  }
   139  
   140  // NetworkProtocolNumber implements stack.NetworkEndpoint.NetworkProtocolNumber.
   141  func (*endpoint) NetworkProtocolNumber() tcpip.NetworkProtocolNumber {
   142  	return ProtocolNumber
   143  }
   144  
   145  func (*endpoint) WriteHeaderIncludedPacket(*stack.Route, *stack.PacketBuffer) tcpip.Error {
   146  	return &tcpip.ErrNotSupported{}
   147  }
   148  
   149  func (e *endpoint) HandlePacket(pkt *stack.PacketBuffer) {
   150  	stats := e.stats.arp
   151  	stats.packetsReceived.Increment()
   152  
   153  	if !e.isEnabled() {
   154  		stats.disabledPacketsReceived.Increment()
   155  		return
   156  	}
   157  
   158  	if _, _, ok := e.protocol.Parse(pkt); !ok {
   159  		stats.malformedPacketsReceived.Increment()
   160  		return
   161  	}
   162  
   163  	h := header.ARP(pkt.NetworkHeader().Slice())
   164  	if !h.IsValid() {
   165  		stats.malformedPacketsReceived.Increment()
   166  		return
   167  	}
   168  
   169  	switch h.Op() {
   170  	case header.ARPRequest:
   171  		stats.requestsReceived.Increment()
   172  		localAddr := tcpip.AddrFrom4Slice(h.ProtocolAddressTarget())
   173  
   174  		if !e.nic.CheckLocalAddress(header.IPv4ProtocolNumber, localAddr) {
   175  			stats.requestsReceivedUnknownTargetAddress.Increment()
   176  			return // we have no useful answer, ignore the request
   177  		}
   178  
   179  		remoteAddr := tcpip.AddrFrom4Slice(h.ProtocolAddressSender())
   180  		remoteLinkAddr := tcpip.LinkAddress(h.HardwareAddressSender())
   181  
   182  		switch err := e.nic.HandleNeighborProbe(header.IPv4ProtocolNumber, remoteAddr, remoteLinkAddr); err.(type) {
   183  		case nil:
   184  		case *tcpip.ErrNotSupported:
   185  			// The stack may support ARP but the NIC may not need link resolution.
   186  		default:
   187  			panic(fmt.Sprintf("unexpected error when informing NIC of neighbor probe message: %s", err))
   188  		}
   189  
   190  		respPkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
   191  			ReserveHeaderBytes: int(e.nic.MaxHeaderLength()) + header.ARPSize,
   192  		})
   193  		defer respPkt.DecRef()
   194  		packet := header.ARP(respPkt.NetworkHeader().Push(header.ARPSize))
   195  		respPkt.NetworkProtocolNumber = ProtocolNumber
   196  		packet.SetIPv4OverEthernet()
   197  		packet.SetOp(header.ARPReply)
   198  		// TODO(gvisor.dev/issue/4582): check copied length once TAP devices have a
   199  		// link address.
   200  		_ = copy(packet.HardwareAddressSender(), e.nic.LinkAddress())
   201  		if n := copy(packet.ProtocolAddressSender(), h.ProtocolAddressTarget()); n != header.IPv4AddressSize {
   202  			panic(fmt.Sprintf("copied %d bytes, expected %d bytes", n, header.IPv4AddressSize))
   203  		}
   204  		origSender := h.HardwareAddressSender()
   205  		if n := copy(packet.HardwareAddressTarget(), origSender); n != header.EthernetAddressSize {
   206  			panic(fmt.Sprintf("copied %d bytes, expected %d bytes", n, header.EthernetAddressSize))
   207  		}
   208  		if n := copy(packet.ProtocolAddressTarget(), h.ProtocolAddressSender()); n != header.IPv4AddressSize {
   209  			panic(fmt.Sprintf("copied %d bytes, expected %d bytes", n, header.IPv4AddressSize))
   210  		}
   211  
   212  		// As per RFC 826, under Packet Reception:
   213  		//   Swap hardware and protocol fields, putting the local hardware and
   214  		//   protocol addresses in the sender fields.
   215  		//
   216  		//   Send the packet to the (new) target hardware address on the same
   217  		//   hardware on which the request was received.
   218  		if err := e.nic.WritePacketToRemote(tcpip.LinkAddress(origSender), respPkt); err != nil {
   219  			stats.outgoingRepliesDropped.Increment()
   220  		} else {
   221  			stats.outgoingRepliesSent.Increment()
   222  		}
   223  
   224  	case header.ARPReply:
   225  		stats.repliesReceived.Increment()
   226  		addr := tcpip.AddrFrom4Slice(h.ProtocolAddressSender())
   227  		linkAddr := tcpip.LinkAddress(h.HardwareAddressSender())
   228  
   229  		e.mu.Lock()
   230  		e.dad.StopLocked(addr, &stack.DADDupAddrDetected{HolderLinkAddress: linkAddr})
   231  		e.mu.Unlock()
   232  
   233  		switch err := e.nic.HandleNeighborConfirmation(header.IPv4ProtocolNumber, addr, linkAddr, stack.ReachabilityConfirmationFlags{
   234  			// Only unicast ARP replies are considered solicited. Broadcast replies
   235  			// are gratuitous ARP replies and should not move neighbor entries to the
   236  			// reachable state.
   237  			Solicited: pkt.PktType == tcpip.PacketHost,
   238  			// If a different link address is received than the one cached, the entry
   239  			// should always go to Stale.
   240  			Override: false,
   241  			// ARP does not distinguish between router and non-router hosts.
   242  			IsRouter: false,
   243  		}); err.(type) {
   244  		case nil:
   245  		case *tcpip.ErrNotSupported:
   246  		// The stack may support ARP but the NIC may not need link resolution.
   247  		default:
   248  			panic(fmt.Sprintf("unexpected error when informing NIC of neighbor confirmation message: %s", err))
   249  		}
   250  	}
   251  }
   252  
   253  // Stats implements stack.NetworkEndpoint.
   254  func (e *endpoint) Stats() stack.NetworkEndpointStats {
   255  	return &e.stats.localStats
   256  }
   257  
   258  var _ stack.NetworkProtocol = (*protocol)(nil)
   259  
   260  type protocol struct {
   261  	stack   *stack.Stack
   262  	options Options
   263  }
   264  
   265  func (p *protocol) Number() tcpip.NetworkProtocolNumber { return ProtocolNumber }
   266  func (p *protocol) MinimumPacketSize() int              { return header.ARPSize }
   267  
   268  func (*protocol) ParseAddresses([]byte) (src, dst tcpip.Address) {
   269  	return tcpip.Address{}, tcpip.Address{}
   270  }
   271  
   272  func (p *protocol) NewEndpoint(nic stack.NetworkInterface, _ stack.TransportDispatcher) stack.NetworkEndpoint {
   273  	e := &endpoint{
   274  		protocol: p,
   275  		nic:      nic,
   276  	}
   277  
   278  	e.mu.Lock()
   279  	e.dad.Init(&e.mu, p.options.DADConfigs, ip.DADOptions{
   280  		Clock:     p.stack.Clock(),
   281  		SecureRNG: p.stack.SecureRNG().Reader,
   282  		// ARP does not support sending nonce values.
   283  		NonceSize: 0,
   284  		Protocol:  e,
   285  		NICID:     nic.ID(),
   286  	})
   287  	e.mu.Unlock()
   288  
   289  	tcpip.InitStatCounters(reflect.ValueOf(&e.stats.localStats).Elem())
   290  
   291  	stackStats := p.stack.Stats()
   292  	e.stats.arp.init(&e.stats.localStats.ARP, &stackStats.ARP)
   293  
   294  	return e
   295  }
   296  
   297  // LinkAddressProtocol implements stack.LinkAddressResolver.LinkAddressProtocol.
   298  func (*endpoint) LinkAddressProtocol() tcpip.NetworkProtocolNumber {
   299  	return header.IPv4ProtocolNumber
   300  }
   301  
   302  // LinkAddressRequest implements stack.LinkAddressResolver.LinkAddressRequest.
   303  func (e *endpoint) LinkAddressRequest(targetAddr, localAddr tcpip.Address, remoteLinkAddr tcpip.LinkAddress) tcpip.Error {
   304  	stats := e.stats.arp
   305  
   306  	if len(remoteLinkAddr) == 0 {
   307  		remoteLinkAddr = header.EthernetBroadcastAddress
   308  	}
   309  
   310  	if localAddr.BitLen() == 0 {
   311  		addr, err := e.nic.PrimaryAddress(header.IPv4ProtocolNumber)
   312  		if err != nil {
   313  			return err
   314  		}
   315  
   316  		if addr.Address.BitLen() == 0 {
   317  			stats.outgoingRequestInterfaceHasNoLocalAddressErrors.Increment()
   318  			return &tcpip.ErrNetworkUnreachable{}
   319  		}
   320  
   321  		localAddr = addr.Address
   322  	} else if !e.nic.CheckLocalAddress(header.IPv4ProtocolNumber, localAddr) {
   323  		stats.outgoingRequestBadLocalAddressErrors.Increment()
   324  		return &tcpip.ErrBadLocalAddress{}
   325  	}
   326  
   327  	return e.sendARPRequest(localAddr, targetAddr, remoteLinkAddr)
   328  }
   329  
   330  func (e *endpoint) sendARPRequest(localAddr, targetAddr tcpip.Address, remoteLinkAddr tcpip.LinkAddress) tcpip.Error {
   331  	pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
   332  		ReserveHeaderBytes: int(e.MaxHeaderLength()),
   333  	})
   334  	defer pkt.DecRef()
   335  	h := header.ARP(pkt.NetworkHeader().Push(header.ARPSize))
   336  	pkt.NetworkProtocolNumber = ProtocolNumber
   337  	h.SetIPv4OverEthernet()
   338  	h.SetOp(header.ARPRequest)
   339  	// TODO(gvisor.dev/issue/4582): check copied length once TAP devices have a
   340  	// link address.
   341  	_ = copy(h.HardwareAddressSender(), e.nic.LinkAddress())
   342  	if n := copy(h.ProtocolAddressSender(), localAddr.AsSlice()); n != header.IPv4AddressSize {
   343  		panic(fmt.Sprintf("copied %d bytes, expected %d bytes", n, header.IPv4AddressSize))
   344  	}
   345  	if n := copy(h.ProtocolAddressTarget(), targetAddr.AsSlice()); n != header.IPv4AddressSize {
   346  		panic(fmt.Sprintf("copied %d bytes, expected %d bytes", n, header.IPv4AddressSize))
   347  	}
   348  
   349  	stats := e.stats.arp
   350  	if err := e.nic.WritePacketToRemote(remoteLinkAddr, pkt); err != nil {
   351  		stats.outgoingRequestsDropped.Increment()
   352  		return err
   353  	}
   354  	stats.outgoingRequestsSent.Increment()
   355  	return nil
   356  }
   357  
   358  // ResolveStaticAddress implements stack.LinkAddressResolver.ResolveStaticAddress.
   359  func (*endpoint) ResolveStaticAddress(addr tcpip.Address) (tcpip.LinkAddress, bool) {
   360  	if addr == header.IPv4Broadcast {
   361  		return header.EthernetBroadcastAddress, true
   362  	}
   363  	if header.IsV4MulticastAddress(addr) {
   364  		return header.EthernetAddressFromMulticastIPv4Address(addr), true
   365  	}
   366  	return tcpip.LinkAddress([]byte(nil)), false
   367  }
   368  
   369  // SetOption implements stack.NetworkProtocol.SetOption.
   370  func (*protocol) SetOption(tcpip.SettableNetworkProtocolOption) tcpip.Error {
   371  	return &tcpip.ErrUnknownProtocolOption{}
   372  }
   373  
   374  // Option implements stack.NetworkProtocol.Option.
   375  func (*protocol) Option(tcpip.GettableNetworkProtocolOption) tcpip.Error {
   376  	return &tcpip.ErrUnknownProtocolOption{}
   377  }
   378  
   379  // Close implements stack.TransportProtocol.Close.
   380  func (*protocol) Close() {}
   381  
   382  // Wait implements stack.TransportProtocol.Wait.
   383  func (*protocol) Wait() {}
   384  
   385  // Parse implements stack.NetworkProtocol.Parse.
   386  func (*protocol) Parse(pkt *stack.PacketBuffer) (proto tcpip.TransportProtocolNumber, hasTransportHdr bool, ok bool) {
   387  	return 0, false, parse.ARP(pkt)
   388  }
   389  
   390  // Options holds options to configure a protocol.
   391  type Options struct {
   392  	// DADConfigs is the default DAD configurations used by ARP endpoints.
   393  	DADConfigs stack.DADConfigurations
   394  }
   395  
   396  // NewProtocolWithOptions returns an ARP network protocol factory that
   397  // will return an ARP network protocol with the provided options.
   398  func NewProtocolWithOptions(opts Options) stack.NetworkProtocolFactory {
   399  	return func(s *stack.Stack) stack.NetworkProtocol {
   400  		return &protocol{
   401  			stack:   s,
   402  			options: opts,
   403  		}
   404  	}
   405  }
   406  
   407  // NewProtocol returns an ARP network protocol.
   408  func NewProtocol(s *stack.Stack) stack.NetworkProtocol {
   409  	return NewProtocolWithOptions(Options{})(s)
   410  }