chap 21: ARP, address resolution protocol 21.1 introduction translate: ip to MAC 32 bit to 48 bit remember we cache the result, so we must look that up first. basic ARP functionality: send/recv/grat arp, etc. 21.2 arp and routing table Figure 21.1 arp and routing table/interface structures # arp -an ? (107.180.166.94) at 00:e0:d0:10:ad:9e on ed0 [ethernet] homebrew# netstat -rn Routing tables Internet: Destination Gateway Flags Refs Use Netif Expire default 107.180.166.94 UGSc 35 0 ed0 10 link#8 UC 0 0 wi0 127.0.0.1 127.0.0.1 UH 0 20 lo0 107.180.166.88/29 link#2 UC 1 0 ed0 107.180.166.94 00:e0:d0:10:ad:9e UHLW 36 0 ed0 789 *************************************************************************** L marks the arp table entry in the routing table. arp -an is just a "view" on the routing table. UC marks the clone route inserted at interface ifconfig ipaddress time. Figure 21.1 ifnet - ptr to interface list ifnet_addrs: ptr to interface addresses in_ifaddr ... ifaddr ptr list llinfo_arp: ptr to arp table entryies (routing table entries) note the UC flag and the UHL flags. UHL are arp entries. W means "was" as in "was cloned". When an arp message comes in with an IP address in the subnet ... a routing table lookup occurs that matches the clone ... a new "instance" is created automagically by the routing code. The mac address is filled in as the gateway. Note the gateway pointer ... in the routing table entry. 1. llinfo_arp ... arp timer processes this list every 5 minutes. 2. llinfo_arp entry pts to routing table entry. uses la_rt and rt_llinfo to pt to each other. 3. clone route ... 4. rtentry, rt_gateway points to sockaddr_dl which has MAC address note that sdl_alen is 6 (6 * 8) 5. rt_ifp points to associated interface, therefore we can state all arp cache entries are of the form (IP, MAC, if) 6. problem always exists with question of what to do about YOUR IP address, when it is not localhost. In this case it basically points to localhost with ifp. So not a problem ... 7. la_hold is mbuf chain pointer. this is where packet lives if arp has not resolved it. we don't throw it away ... for awhile. 8. rmx_expire. routing table entries have "xtra info" for various uses. This is the arp timer. 20 minutes by default. Design Question: this is simpler? 21.3 Code Introduction net/if_arp.h arphdr structure definition (arp on the wire), arpcom structure, old arp ioctl structure netinet/if_ether.h - misc cruft, another structure for arp, the includes arphdr plus the address fields. this is struct ether_arp. a socketaddr_inarp as well. MACROS ... e.g., ethernet/multicast which ain't arp, but is the multicast equivalent. netinet/if_ether.c arp functions Figure 21.3, ze big picture Figure 21.4 global variables llinfo_arp - the arp ptr list arpintrq - arp input queue 21.4 arp structures Figure 21.7 the ARP packet structure arphdr + ether_arp (which includes arphdr) make it up hardware means 48 bit mac protocol (arp_spa e.g.,) means IP address Figure 21.8 common arphdr figure 21.9 ether_arp structure Figure 21.10 llinfo_arp structure la_asked counts how many times ARP asked without answer ... when this counter reachs a limit, arp will give up, and won't work for awhile. if rt_timer value is 0, arp entry is considered permanent. 21.5 arpwhohas function 1. ether_output arpresolve arpwhohas 1. send broadcast arp when needed 2. at i/f address time, in_ifinit arpresolve 2. send grat. arp calls arprequest ! args are: 1. arpcom ptr. 2. source ip 3. target ip 4. our mac note: 1/3 are arpwhohas args if grat. arp, source and target are the same 21.6 arprequest function send a broadcast ARP request/query Figure 21.12 mbuf layout and socket addr structure note: if_output (ether_output) needs a packet chain, and a "dest" which is a mac address. Thus Figure 21.12. We need to build those two items. mbuf contains arp info. The sockaddr contains an ethernet header with the address all 1's (bcast). Normally this is an ip address (gateway), but we use AF_UNSPEC so that we have an ethernet header prefilled in instead. Thus ether_output does NOT call arpresolve again. Figure 21.13 arprequest function get mbuf form ptr to ether_arp form ptr (ea) to eh copy in all 1s as dst to sa set type note zero out of mbuf ... (this is why arp from BSD box has zeroes!) fill in ea structure ship it! figure 21.14 ethernet type fields Figure 21.15 arp op codes 21.7 arpintr function you got arp. ether_input with type ETHERTYPE_ARP schedules sw interrupt of priority NETISR_ARP. appends frame to arp input queue, arpintrq, returns. arpintr gets called. Figure 21.16 arpintr loop while frames exist dequeue if m len sane, etc. ... pass it to in_arpinput(m) to do the real work 21.8 in_arpinput function process 1 arp frame scenarios: 1. input could be request, send a reply. because we will probably send a packet back, we also pre-cache an arp cache entry for the other guy, thus avoiding an arp. 2. if reply to response sent by us, we fill in the arp entry. in addition: arp requests are normally broadcast ... 3. if host X sends request/reply with sender IP of host Y, we know there is a problem (or a hack in progress...) We log a message to syslog. 4. if we get request/reply from host X, and MAC X has changed, we change it. 5. we may be a proxy arp server, that means that for host IP A, (normally not us), we volunteer our MAC for it. The arp command is used with the "pub" sub-verb. Figure 21.17, part 1, in_arpinput. arpcom ptr setup forth ether_arp pointer to mbuf. get op copy source ip to isaddr copy dst ip to itaddr loop thru ifaddrs ... if interface matches if the target is us or the sender is us break 385: if maybe_ia is non-null (we located a recv. interface) but no IP address matched ... myaddr is set to the final IP address of the i/f Figure 21.18, next part - packet validation if sender hw same this interface hw, our send, ignore it if sender's hw addr is ethernet broadcast address, oops log an error if sender ip same as my addr somebody thinks they are me ... log an error Figure 21.19 arplookup - search arp cache for sender's ip address create it if this host is the target arg 3 is 0, meaning do not look for proxy arp entry returns: llinfo_arp structure OR NULL if arp cache found and there is a rt entry, and there is a socket (mac info) update existing entry or fill in new entry overwrite mac if X exists and log that copy sender's hw mac to gateway structure mac slot if timer set, update it make sure reject route flag is not set and asked is set to zero as a counter if we have a held packet send it reply: if op is not request (it's a reply), we are done Figure 21.20 rest of function deals with reply if the target is me ... send a reply! copy src hw to target hw copy arpcom mac (me) to source hw else check for proxy case lookup target in "arp table" if none, bail copy src hw to target hw copy gateway mac to source hw copy src ip to target ip copy target to source ip set op to REPLY set protocol type to IP setup ethernet header ... set mac dst to target call if output routine (ether_output) 21.9 arp timer functions 2 kinds of entries: dynamic: time out in 20 minutes permanent: do not time out published or not published by the way (proxy arp) rmx_expire is the arp timer, it contains the unix epoch time (in secs) Figure 21.21 arp timer, called every 5 minutes arp_rtrequest causes it to be called the 1st time sets up another 5 minute timer with timeout call walks llinfo ptr chain if expire set and less than now free the entry arptfree delete a single entry from the llinfo_arp list if refcnt > 0, it will cause arp to go off again alen = 0 does this ... invalidates the entry clear asked/and REJECT flag (anti-arp-flooding mechanism) else call rtrequest RTM_DELETE to delete the routing entry it also calls arp_rtrequest, which cleans up llinfo_arp 21.10 arpresolve ether_output calls arpresolve arpresolve returns: 1 - cached go ahead and call start routine 0 - not cached "yet" datagram held in la_hold, note that this is per dst arp cache must also "avoid arp flooding" -- sending arp at a high rate, when possibly you never get an answer Figure 21.23 dst - contains dst ip dsten - the answer, ethermet mac for dst ip if packet is bcast, just fill in all 1's and return 1 if packet is mcast, just map it and return 1 if we have a route ... form llinfo ptr else call arplookup, 2nd arg = 1 which means create it if you don't find it (clone route used) 3rd arg is 0, means not proxy arp case error check (shouldn't happen normally) Figure 21.24, 2nd half of arpresolve entry must be checked for validity. Valid if, 1. timer is 0 or (time is greater than now AND 2. family is AF_LINK for gateway AND 3. sld_alen is nonzero) if valid then copy gateway to desten and return question: why is this bad for NFS? if hold buffer, free it replace held buffer with this one if expire is set (this is not a permanent entry) turn off reject flag la_asked is counter and counts number of times unanswered arp is sent to a dst if 0 or expire time is not now (note latter condition disallows > 1 arp per sec) set time to now if asked still less than limit for retries (5) arpwhohas ... with arpcom, and dst else too many! set routing flag to reject set expire to "down" time, which will force waiting down time = 20 second wait set asked to 0 Figure 21.25 RTF_REJECT causes EHOSTDOWN to be returned. It might even be true. arpt_down is now controllable thru sysctl. net.link.ether.inet.host_down_time: 20 Arp aging timer is too: net.link.ether.inet.max_age: 1200 21.11 arplookup function calls rtalloc1 to look up arp entry called from: in_arpinput - to lookup and possibly create entry for recv. arp packet. in_arpinput - to see if proxy arp exists 3. from arpresolve to look up/create entry for ip dst about to be sent. three args: 1. ip address to search for 2. flag to incidate to create or not 3. flag to signal that proxy arp should be searched for and possibly created returns: llinfo_arp ptr Figure 21.26, sockaddr_inarp structure sin_other set to 1 to indicate proxy request (SIN_PROXY) Figure 21.27 rtalloc1 does match of dst ... if clone route exists it is cloned to have a new ip dst (host), and an empty link gateway ... interface ptr is retained arp undoes increment put in by route allocation gateway sanity check (must be RTF_LLINFO) (L flag) 21.12 Proxy ARP 2 kindza proxy always causes grat. arp to be issued 1. enter IP address for host on local net into arp cache, any mac address may be supplied. can do this for a box who cannot arp. 2. 2nd type is for host that already has routing table entry. we specify the proxy server MAC upon request, proxy server returns its MAC address for the host ip H Review figure 21.3. be sure and understand that #ifconfig ed0 10.0.0.1 ... netmask 255.0.0.0 creates clone route for net 10 with empty link gateway ... This route is cloned for arp table entries. 1. arplookup calls rtalloc1 to look up and possibly create routing entry (Link) 2. arptfree calls rtrequest with RTM_DELETE ... to decrement reference count and possibly free entry. arp(8) using routing socket (route (4)) to send and recv. routing messages using RTM_ADD, RTM_DELETE, and RTM_GET. Thus manipulates routing table/arp table view of routing table. Figure 21.28, arp_rtrequest, 1st part this code is really called from the routing code ... for arp and for managing both the llinfo_arp, and gateway part of the route. It does not allocate/delete the route itself. note how we form a pointer to a route's associated llinfo_arp 1st time called (1st interface with ip), we startup 5 minute arp timer. Note how this is done. Efficiency is not a big concern with this routine (... at least for a few statements) not a gateway ... direct route 3 cases, RTM_ADD, RTM_RESOLVE, RTM_DELETE add called either via arp(8) or ifconfig of i/f with ip fixup cloning bit for backwards compatibility if cloning is set rt_setgate allocates space for gateway LL sockaddr_dl (holds MAC) SDL init ... from interface time set to now clone routes don't have llinfo_arp, therefore they are not bothered by the arp timer. if ANNOUNCE flag set arp for self Figure 21.29 RTM_RESOLVE - lookup and possibly create rtalloc1 matches entry with RTF_CLONG flag set ... and 2nd arg is nonzero (create!) new llinfo_arp must be allocated make sure gateway is sane if la exists (some change in route but route exists) return malloc new llinfo_arp and set it up note 161, put in queue of llinfo (not really q) if the routing table key is the same as the interface, then force a host route thru localhost ... entry is permanent functional equivalent of route add 140.252.13.35 127.0.0.1 important routing table design principle: don't bury too much magic in it ... explicit is better. Figure 21.30 arp_rtrequest RTM_DELETE burn the "la" ... 21.14 arp and multicast called but really only invokes ETHER_MAP_IP_MULTICAST macro ... to map ip to IETF MAC. Summary arp flooding: classic example of "maybe you want it, and maybe you don't" ...