Annotation of embedaddon/dnsmasq/src/arp.c, revision 1.1.1.3
1.1.1.3 ! misho 1: /* dnsmasq is Copyright (c) 2000-2022 Simon Kelley
1.1 misho 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];
1.1.1.2 misho 31: union all_addr addr;
1.1 misho 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: {
1.1.1.2 misho 55: if (arp->addr.addr4.s_addr != ((struct in_addr *)addrp)->s_addr)
1.1 misho 56: continue;
57: }
58: else
59: {
1.1.1.2 misho 60: if (!IN6_ARE_ADDR_EQUAL(&arp->addr.addr6, (struct in6_addr *)addrp))
1.1 misho 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)
1.1.1.2 misho 98: arp->addr.addr4.s_addr = ((struct in_addr *)addrp)->s_addr;
1.1 misho 99: else
1.1.1.2 misho 100: memcpy(&arp->addr.addr6, addrp, IN6ADDRSZ);
1.1 misho 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 &&
1.1.1.2 misho 127: arp->addr.addr4.s_addr != addr->in.sin_addr.s_addr)
1.1 misho 128: continue;
129:
130: if (arp->family == AF_INET6 &&
1.1.1.2 misho 131: !IN6_ARE_ADDR_EQUAL(&arp->addr.addr6, &addr->in6.sin6_addr))
1.1 misho 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)
1.1.1.2 misho 194: arp->addr.addr4.s_addr = addr->in.sin_addr.s_addr;
1.1 misho 195: else
1.1.1.2 misho 196: memcpy(&arp->addr.addr6, &addr->in6.sin6_addr, IN6ADDRSZ);
1.1 misho 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>