Annotation of embedaddon/dnsmasq/src/arp.c, revision 1.1
1.1 ! misho 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>