File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dnsmasq / src / arp.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Sep 27 11:02:07 2023 UTC (9 months, 1 week ago) by misho
Branches: dnsmasq, MAIN
CVS tags: v8_2p1, HEAD
Version 8.2p1

    1: /* dnsmasq is Copyright (c) 2000-2022 Simon Kelley
    2: 
    3:    This program is free software; you can redistribute it and/or modify
    4:    it under the terms of the GNU General Public License as published by
    5:    the Free Software Foundation; version 2 dated June, 1991, or
    6:    (at your option) version 3 dated 29 June, 2007.
    7:  
    8:    This program is distributed in the hope that it will be useful,
    9:    but WITHOUT ANY WARRANTY; without even the implied warranty of
   10:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   11:    GNU General Public License for more details.
   12:      
   13:    You should have received a copy of the GNU General Public License
   14:    along with this program.  If not, see <http://www.gnu.org/licenses/>.
   15: */
   16: 
   17: #include "dnsmasq.h"
   18: 
   19: /* Time between forced re-loads from kernel. */
   20: #define INTERVAL 90
   21: 
   22: #define ARP_MARK  0
   23: #define ARP_FOUND 1  /* Confirmed */
   24: #define ARP_NEW   2  /* Newly created */
   25: #define ARP_EMPTY 3  /* No MAC addr */
   26: 
   27: struct arp_record {
   28:   unsigned short hwlen, status;
   29:   int family;
   30:   unsigned char hwaddr[DHCP_CHADDR_MAX]; 
   31:   union all_addr addr;
   32:   struct arp_record *next;
   33: };
   34: 
   35: static struct arp_record *arps = NULL, *old = NULL, *freelist = NULL;
   36: static time_t last = 0;
   37: 
   38: static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv)
   39: {
   40:   struct arp_record *arp;
   41: 
   42:   (void)parmv;
   43: 
   44:   if (maclen > DHCP_CHADDR_MAX)
   45:     return 1;
   46: 
   47:   /* Look for existing entry */
   48:   for (arp = arps; arp; arp = arp->next)
   49:     {
   50:       if (family != arp->family || arp->status == ARP_NEW)
   51: 	continue;
   52:       
   53:       if (family == AF_INET)
   54: 	{
   55: 	  if (arp->addr.addr4.s_addr != ((struct in_addr *)addrp)->s_addr)
   56: 	    continue;
   57: 	}
   58:       else
   59: 	{
   60: 	  if (!IN6_ARE_ADDR_EQUAL(&arp->addr.addr6, (struct in6_addr *)addrp))
   61: 	    continue;
   62: 	}
   63: 
   64:       if (arp->status == ARP_EMPTY)
   65: 	{
   66: 	  /* existing address, was negative. */
   67: 	  arp->status = ARP_NEW;
   68: 	  arp->hwlen = maclen;
   69: 	  memcpy(arp->hwaddr, mac, maclen);
   70: 	}
   71:       else if (arp->hwlen == maclen && memcmp(arp->hwaddr, mac, maclen) == 0)
   72: 	/* Existing entry matches - confirm. */
   73: 	arp->status = ARP_FOUND;
   74:       else
   75: 	continue;
   76:       
   77:       break;
   78:     }
   79: 
   80:   if (!arp)
   81:     {
   82:       /* New entry */
   83:       if (freelist)
   84: 	{
   85: 	  arp = freelist;
   86: 	  freelist = freelist->next;
   87: 	}
   88:       else if (!(arp = whine_malloc(sizeof(struct arp_record))))
   89: 	return 1;
   90:       
   91:       arp->next = arps;
   92:       arps = arp;
   93:       arp->status = ARP_NEW;
   94:       arp->hwlen = maclen;
   95:       arp->family = family;
   96:       memcpy(arp->hwaddr, mac, maclen);
   97:       if (family == AF_INET)
   98: 	arp->addr.addr4.s_addr = ((struct in_addr *)addrp)->s_addr;
   99:       else
  100: 	memcpy(&arp->addr.addr6, addrp, IN6ADDRSZ);
  101:     }
  102:   
  103:   return 1;
  104: }
  105: 
  106: /* If in lazy mode, we cache absence of ARP entries. */
  107: int find_mac(union mysockaddr *addr, unsigned char *mac, int lazy, time_t now)
  108: {
  109:   struct arp_record *arp, *tmp, **up;
  110:   int updated = 0;
  111: 
  112:  again:
  113:   
  114:   /* If the database is less then INTERVAL old, look in there */
  115:   if (difftime(now, last) < INTERVAL)
  116:     {
  117:       /* addr == NULL -> just make cache up-to-date */
  118:       if (!addr)
  119: 	return 0;
  120: 
  121:       for (arp = arps; arp; arp = arp->next)
  122: 	{
  123: 	  if (addr->sa.sa_family != arp->family)
  124: 	    continue;
  125: 	    
  126: 	  if (arp->family == AF_INET &&
  127: 	      arp->addr.addr4.s_addr != addr->in.sin_addr.s_addr)
  128: 	    continue;
  129: 	    
  130: 	  if (arp->family == AF_INET6 && 
  131: 	      !IN6_ARE_ADDR_EQUAL(&arp->addr.addr6, &addr->in6.sin6_addr))
  132: 	    continue;
  133: 	  
  134: 	  /* Only accept positive entries unless in lazy mode. */
  135: 	  if (arp->status != ARP_EMPTY || lazy || updated)
  136: 	    {
  137: 	      if (mac && arp->hwlen != 0)
  138: 		memcpy(mac, arp->hwaddr, arp->hwlen);
  139: 	      return arp->hwlen;
  140: 	    }
  141: 	}
  142:     }
  143: 
  144:   /* Not found, try the kernel */
  145:   if (!updated)
  146:      {
  147:        updated = 1;
  148:        last = now;
  149: 
  150:        /* Mark all non-negative entries */
  151:        for (arp = arps; arp; arp = arp->next)
  152: 	 if (arp->status != ARP_EMPTY)
  153: 	   arp->status = ARP_MARK;
  154:        
  155:        iface_enumerate(AF_UNSPEC, NULL, filter_mac);
  156:        
  157:        /* Remove all unconfirmed entries to old list. */
  158:        for (arp = arps, up = &arps; arp; arp = tmp)
  159: 	 {
  160: 	   tmp = arp->next;
  161: 	   
  162: 	   if (arp->status == ARP_MARK)
  163: 	     {
  164: 	       *up = arp->next;
  165: 	       arp->next = old;
  166: 	       old = arp;
  167: 	     }
  168: 	   else
  169: 	     up = &arp->next;
  170: 	 }
  171: 
  172:        goto again;
  173:      }
  174: 
  175:   /* record failure, so we don't consult the kernel each time
  176:      we're asked for this address */
  177:   if (freelist)
  178:     {
  179:       arp = freelist;
  180:       freelist = freelist->next;
  181:     }
  182:   else
  183:     arp = whine_malloc(sizeof(struct arp_record));
  184:   
  185:   if (arp)
  186:     {      
  187:       arp->next = arps;
  188:       arps = arp;
  189:       arp->status = ARP_EMPTY;
  190:       arp->family = addr->sa.sa_family;
  191:       arp->hwlen = 0;
  192: 
  193:       if (addr->sa.sa_family == AF_INET)
  194: 	arp->addr.addr4.s_addr = addr->in.sin_addr.s_addr;
  195:       else
  196: 	memcpy(&arp->addr.addr6, &addr->in6.sin6_addr, IN6ADDRSZ);
  197:     }
  198: 	  
  199:    return 0;
  200: }
  201: 
  202: int do_arp_script_run(void)
  203: {
  204:   struct arp_record *arp;
  205:   
  206:   /* Notify any which went, then move to free list */
  207:   if (old)
  208:     {
  209: #ifdef HAVE_SCRIPT
  210:       if (option_bool(OPT_SCRIPT_ARP))
  211: 	queue_arp(ACTION_ARP_DEL, old->hwaddr, old->hwlen, old->family, &old->addr);
  212: #endif
  213:       arp = old;
  214:       old = arp->next;
  215:       arp->next = freelist;
  216:       freelist = arp;
  217:       return 1;
  218:     }
  219: 
  220:   for (arp = arps; arp; arp = arp->next)
  221:     if (arp->status == ARP_NEW)
  222:       {
  223: #ifdef HAVE_SCRIPT
  224: 	if (option_bool(OPT_SCRIPT_ARP))
  225: 	  queue_arp(ACTION_ARP, arp->hwaddr, arp->hwlen, arp->family, &arp->addr);
  226: #endif
  227: 	arp->status = ARP_FOUND;
  228: 	return 1;
  229:       }
  230: 
  231:   return 0;
  232: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>