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>