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 }