Files
dnsmasq/src/arp.c
T
Matthias Andree d578da0665 Fix FTBFS when using -pedantic compiler flag.
I am attaching an incremental git-am ready patch to go on top your Git HEAD,
to fix all sorts of issues and make this conforming C99 with default
options set,
and fix another load of warnings you receive when setting the compiler
to pick the nits,
-pedantic-errors -std=c99 (or c11, c18, c2x).
It changes many void * to uint8_t * to make the "increment by bytes"
explicit.
You can't do:

void *foo;
// ...
foo += 2.
2024-12-24 11:18:42 +00:00

233 lines
5.4 KiB
C

/* dnsmasq is Copyright (c) 2000-2024 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 dated June, 1991, or
(at your option) version 3 dated 29 June, 2007.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "dnsmasq.h"
/* Time between forced re-loads from kernel. */
#define INTERVAL 90
#define ARP_MARK 0
#define ARP_FOUND 1 /* Confirmed */
#define ARP_NEW 2 /* Newly created */
#define ARP_EMPTY 3 /* No MAC addr */
struct arp_record {
unsigned short hwlen, status;
int family;
unsigned char hwaddr[DHCP_CHADDR_MAX];
union all_addr addr;
struct arp_record *next;
};
static struct arp_record *arps = NULL, *old = NULL, *freelist = NULL;
static time_t last = 0;
static int filter_mac(int family, void *addrp, char *mac, size_t maclen, void *parmv)
{
struct arp_record *arp;
(void)parmv;
if (maclen > DHCP_CHADDR_MAX)
return 1;
/* Look for existing entry */
for (arp = arps; arp; arp = arp->next)
{
if (family != arp->family || arp->status == ARP_NEW)
continue;
if (family == AF_INET)
{
if (arp->addr.addr4.s_addr != ((struct in_addr *)addrp)->s_addr)
continue;
}
else
{
if (!IN6_ARE_ADDR_EQUAL(&arp->addr.addr6, (struct in6_addr *)addrp))
continue;
}
if (arp->status == ARP_EMPTY)
{
/* existing address, was negative. */
arp->status = ARP_NEW;
arp->hwlen = maclen;
memcpy(arp->hwaddr, mac, maclen);
}
else if (arp->hwlen == maclen && memcmp(arp->hwaddr, mac, maclen) == 0)
/* Existing entry matches - confirm. */
arp->status = ARP_FOUND;
else
continue;
break;
}
if (!arp)
{
/* New entry */
if (freelist)
{
arp = freelist;
freelist = freelist->next;
}
else if (!(arp = whine_malloc(sizeof(struct arp_record))))
return 1;
arp->next = arps;
arps = arp;
arp->status = ARP_NEW;
arp->hwlen = maclen;
arp->family = family;
memcpy(arp->hwaddr, mac, maclen);
if (family == AF_INET)
arp->addr.addr4.s_addr = ((struct in_addr *)addrp)->s_addr;
else
memcpy(&arp->addr.addr6, addrp, IN6ADDRSZ);
}
return 1;
}
/* If in lazy mode, we cache absence of ARP entries. */
int find_mac(union mysockaddr *addr, unsigned char *mac, int lazy, time_t now)
{
struct arp_record *arp, *tmp, **up;
int updated = 0;
again:
/* If the database is less then INTERVAL old, look in there */
if (difftime(now, last) < INTERVAL)
{
/* addr == NULL -> just make cache up-to-date */
if (!addr)
return 0;
for (arp = arps; arp; arp = arp->next)
{
if (addr->sa.sa_family != arp->family)
continue;
if (arp->family == AF_INET &&
arp->addr.addr4.s_addr != addr->in.sin_addr.s_addr)
continue;
if (arp->family == AF_INET6 &&
!IN6_ARE_ADDR_EQUAL(&arp->addr.addr6, &addr->in6.sin6_addr))
continue;
/* Only accept positive entries unless in lazy mode. */
if (arp->status != ARP_EMPTY || lazy || updated)
{
if (mac && arp->hwlen != 0)
memcpy(mac, arp->hwaddr, arp->hwlen);
return arp->hwlen;
}
}
}
/* Not found, try the kernel */
if (!updated)
{
updated = 1;
last = now;
/* Mark all non-negative entries */
for (arp = arps; arp; arp = arp->next)
if (arp->status != ARP_EMPTY)
arp->status = ARP_MARK;
iface_enumerate(AF_UNSPEC, NULL, (callback_t){.af_unspec=filter_mac});
/* Remove all unconfirmed entries to old list. */
for (arp = arps, up = &arps; arp; arp = tmp)
{
tmp = arp->next;
if (arp->status == ARP_MARK)
{
*up = arp->next;
arp->next = old;
old = arp;
}
else
up = &arp->next;
}
goto again;
}
/* record failure, so we don't consult the kernel each time
we're asked for this address */
if (freelist)
{
arp = freelist;
freelist = freelist->next;
}
else
arp = whine_malloc(sizeof(struct arp_record));
if (arp)
{
arp->next = arps;
arps = arp;
arp->status = ARP_EMPTY;
arp->family = addr->sa.sa_family;
arp->hwlen = 0;
if (addr->sa.sa_family == AF_INET)
arp->addr.addr4.s_addr = addr->in.sin_addr.s_addr;
else
memcpy(&arp->addr.addr6, &addr->in6.sin6_addr, IN6ADDRSZ);
}
return 0;
}
int do_arp_script_run(void)
{
struct arp_record *arp;
/* Notify any which went, then move to free list */
if (old)
{
#ifdef HAVE_SCRIPT
if (option_bool(OPT_SCRIPT_ARP))
queue_arp(ACTION_ARP_DEL, old->hwaddr, old->hwlen, old->family, &old->addr);
#endif
arp = old;
old = arp->next;
arp->next = freelist;
freelist = arp;
return 1;
}
for (arp = arps; arp; arp = arp->next)
if (arp->status == ARP_NEW)
{
#ifdef HAVE_SCRIPT
if (option_bool(OPT_SCRIPT_ARP))
queue_arp(ACTION_ARP, arp->hwaddr, arp->hwlen, arp->family, &arp->addr);
#endif
arp->status = ARP_FOUND;
return 1;
}
return 0;
}