File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dnsmasq / src / arp.c
Revision 1.1: download - view: text, annotated - select for diffs - revision graph
Wed Nov 2 09:57:01 2016 UTC (7 years, 8 months ago) by misho
CVS tags: MAIN, HEAD
Initial revision

    1: /* dnsmasq is Copyright (c) 2000-2016 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:   struct 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: #ifndef HAVE_IPV6
   48:   if (family != AF_INET)
   49:     return 1;
   50: #endif
   51: 
   52:   /* Look for existing entry */
   53:   for (arp = arps; arp; arp = arp->next)
   54:     {
   55:       if (family != arp->family || arp->status == ARP_NEW)
   56: 	continue;
   57:       
   58:       if (family == AF_INET)
   59: 	{
   60: 	  if (arp->addr.addr.addr4.s_addr != ((struct in_addr *)addrp)->s_addr)
   61: 	    continue;
   62: 	}
   63: #ifdef HAVE_IPV6
   64:       else
   65: 	{
   66: 	  if (!IN6_ARE_ADDR_EQUAL(&arp->addr.addr.addr6, (struct in6_addr *)addrp))
   67: 	    continue;
   68: 	}
   69: #endif
   70: 
   71:       if (arp->status == ARP_EMPTY)
   72: 	{
   73: 	  /* existing address, was negative. */
   74: 	  arp->status = ARP_NEW;
   75: 	  arp->hwlen = maclen;
   76: 	  memcpy(arp->hwaddr, mac, maclen);
   77: 	}
   78:       else if (arp->hwlen == maclen && memcmp(arp->hwaddr, mac, maclen) == 0)
   79: 	/* Existing entry matches - confirm. */
   80: 	arp->status = ARP_FOUND;
   81:       else
   82: 	continue;
   83:       
   84:       break;
   85:     }
   86: 
   87:   if (!arp)
   88:     {
   89:       /* New entry */
   90:       if (freelist)
   91: 	{
   92: 	  arp = freelist;
   93: 	  freelist = freelist->next;
   94: 	}
   95:       else if (!(arp = whine_malloc(sizeof(struct arp_record))))
   96: 	return 1;
   97:       
   98:       arp->next = arps;
   99:       arps = arp;
  100:       arp->status = ARP_NEW;
  101:       arp->hwlen = maclen;
  102:       arp->family = family;
  103:       memcpy(arp->hwaddr, mac, maclen);
  104:       if (family == AF_INET)
  105: 	arp->addr.addr.addr4.s_addr = ((struct in_addr *)addrp)->s_addr;
  106: #ifdef HAVE_IPV6
  107:       else
  108: 	memcpy(&arp->addr.addr.addr6, addrp, IN6ADDRSZ);
  109: #endif
  110:     }
  111:   
  112:   return 1;
  113: }
  114: 
  115: /* If in lazy mode, we cache absence of ARP entries. */
  116: int find_mac(union mysockaddr *addr, unsigned char *mac, int lazy, time_t now)
  117: {
  118:   struct arp_record *arp, *tmp, **up;
  119:   int updated = 0;
  120: 
  121:  again:
  122:   
  123:   /* If the database is less then INTERVAL old, look in there */
  124:   if (difftime(now, last) < INTERVAL)
  125:     {
  126:       /* addr == NULL -> just make cache up-to-date */
  127:       if (!addr)
  128: 	return 0;
  129: 
  130:       for (arp = arps; arp; arp = arp->next)
  131: 	{
  132: 	  if (addr->sa.sa_family != arp->family)
  133: 	    continue;
  134: 	    
  135: 	  if (arp->family == AF_INET &&
  136: 	      arp->addr.addr.addr4.s_addr != addr->in.sin_addr.s_addr)
  137: 	    continue;
  138: 	    
  139: #ifdef HAVE_IPV6
  140: 	  if (arp->family == AF_INET6 && 
  141: 	      !IN6_ARE_ADDR_EQUAL(&arp->addr.addr.addr6, &addr->in6.sin6_addr))
  142: 	    continue;
  143: #endif
  144: 	  
  145: 	  /* Only accept positive entries unless in lazy mode. */
  146: 	  if (arp->status != ARP_EMPTY || lazy || updated)
  147: 	    {
  148: 	      if (mac && arp->hwlen != 0)
  149: 		memcpy(mac, arp->hwaddr, arp->hwlen);
  150: 	      return arp->hwlen;
  151: 	    }
  152: 	}
  153:     }
  154: 
  155:   /* Not found, try the kernel */
  156:   if (!updated)
  157:      {
  158:        updated = 1;
  159:        last = now;
  160: 
  161:        /* Mark all non-negative entries */
  162:        for (arp = arps; arp; arp = arp->next)
  163: 	 if (arp->status != ARP_EMPTY)
  164: 	   arp->status = ARP_MARK;
  165:        
  166:        iface_enumerate(AF_UNSPEC, NULL, filter_mac);
  167:        
  168:        /* Remove all unconfirmed entries to old list. */
  169:        for (arp = arps, up = &arps; arp; arp = tmp)
  170: 	 {
  171: 	   tmp = arp->next;
  172: 	   
  173: 	   if (arp->status == ARP_MARK)
  174: 	     {
  175: 	       *up = arp->next;
  176: 	       arp->next = old;
  177: 	       old = arp;
  178: 	     }
  179: 	   else
  180: 	     up = &arp->next;
  181: 	 }
  182: 
  183:        goto again;
  184:      }
  185: 
  186:   /* record failure, so we don't consult the kernel each time
  187:      we're asked for this address */
  188:   if (freelist)
  189:     {
  190:       arp = freelist;
  191:       freelist = freelist->next;
  192:     }
  193:   else
  194:     arp = whine_malloc(sizeof(struct arp_record));
  195:   
  196:   if (arp)
  197:     {      
  198:       arp->next = arps;
  199:       arps = arp;
  200:       arp->status = ARP_EMPTY;
  201:       arp->family = addr->sa.sa_family;
  202:       arp->hwlen = 0;
  203: 
  204:       if (addr->sa.sa_family == AF_INET)
  205: 	arp->addr.addr.addr4.s_addr = addr->in.sin_addr.s_addr;
  206: #ifdef HAVE_IPV6
  207:       else
  208: 	memcpy(&arp->addr.addr.addr6, &addr->in6.sin6_addr, IN6ADDRSZ);
  209: #endif
  210:     }
  211: 	  
  212:    return 0;
  213: }
  214: 
  215: int do_arp_script_run(void)
  216: {
  217:   struct arp_record *arp;
  218:   
  219:   /* Notify any which went, then move to free list */
  220:   if (old)
  221:     {
  222: #ifdef HAVE_SCRIPT
  223:       if (option_bool(OPT_SCRIPT_ARP))
  224: 	queue_arp(ACTION_ARP_DEL, old->hwaddr, old->hwlen, old->family, &old->addr);
  225: #endif
  226:       arp = old;
  227:       old = arp->next;
  228:       arp->next = freelist;
  229:       freelist = arp;
  230:       return 1;
  231:     }
  232: 
  233:   for (arp = arps; arp; arp = arp->next)
  234:     if (arp->status == ARP_NEW)
  235:       {
  236: #ifdef HAVE_SCRIPT
  237: 	if (option_bool(OPT_SCRIPT_ARP))
  238: 	  queue_arp(ACTION_ARP, arp->hwaddr, arp->hwlen, arp->family, &arp->addr);
  239: #endif
  240: 	arp->status = ARP_FOUND;
  241: 	return 1;
  242:       }
  243: 
  244:   return 0;
  245: }
  246: 
  247: 

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