]>
Commit | Line | Data |
---|---|---|
cc192b50 | 1 | |
48071869 | 2 | /* |
cc192b50 | 3 | * $Id: ACLARP.cc,v 1.25 2007/12/14 23:11:45 amosjeffries Exp $ |
48071869 | 4 | * |
5 | * DEBUG: section 28 Access Control | |
6 | * AUTHOR: Duane Wessels | |
7 | * | |
8 | * SQUID Web Proxy Cache http://www.squid-cache.org/ | |
9 | * ---------------------------------------------------------- | |
10 | * | |
11 | * Squid is the result of efforts by numerous individuals from | |
12 | * the Internet community; see the CONTRIBUTORS file for full | |
13 | * details. Many organizations have provided support for Squid's | |
14 | * development; see the SPONSORS file for full details. Squid is | |
15 | * Copyrighted (C) 2001 by the Regents of the University of | |
16 | * California; see the COPYRIGHT file for full details. Squid | |
17 | * incorporates software developed and/or copyrighted by other | |
18 | * sources; see the CREDITS file for full details. | |
19 | * | |
20 | * This program is free software; you can redistribute it and/or modify | |
21 | * it under the terms of the GNU General Public License as published by | |
22 | * the Free Software Foundation; either version 2 of the License, or | |
23 | * (at your option) any later version. | |
24 | * | |
25 | * This program is distributed in the hope that it will be useful, | |
26 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
27 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
28 | * GNU General Public License for more details. | |
29 | * | |
30 | * You should have received a copy of the GNU General Public License | |
31 | * along with this program; if not, write to the Free Software | |
32 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. | |
33 | * | |
34 | * | |
35 | * Copyright (c) 2003, Robert Collins <robertc@squid-cache.org> | |
36 | */ | |
37 | ||
6fc1da74 | 38 | #include "config.h" |
5700029a | 39 | #ifdef _SQUID_CYGWIN_ |
40 | #include <squid_windows.h> | |
41 | #endif | |
09f64260 | 42 | #include "squid.h" |
cc192b50 | 43 | #include "IPAddress.h" |
6fc1da74 | 44 | |
5700029a | 45 | #ifdef _SQUID_WIN32_ |
46 | ||
47 | struct arpreq | |
48 | { | |
49 | ||
cc192b50 | 50 | IPAddress arp_pa; /* protocol address */ |
5700029a | 51 | |
52 | struct sockaddr arp_ha; /* hardware address */ | |
53 | int arp_flags; /* flags */ | |
54 | }; | |
55 | ||
56 | #include <Iphlpapi.h> | |
57 | #else | |
58 | ||
6fc1da74 | 59 | #ifdef _SQUID_SOLARIS_ |
60 | #include <sys/sockio.h> | |
61 | #else | |
62 | #include <sys/sysctl.h> | |
63 | #endif | |
64 | #ifdef _SQUID_LINUX_ | |
65 | #include <net/if_arp.h> | |
66 | #include <sys/ioctl.h> | |
67 | #else | |
68 | #include <net/if_dl.h> | |
69 | #endif | |
70 | #include <net/route.h> | |
71 | #include <net/if.h> | |
680ec522 | 72 | #if defined(_SQUID_FREEBSD_) || defined(_SQUID_NETBSD_) || defined(_SQUID_OPENBSD_) |
9a2f1170 | 73 | #include <net/if_arp.h> |
74 | #endif | |
6fc1da74 | 75 | #if HAVE_NETINET_IF_ETHER_H |
76 | #include <netinet/if_ether.h> | |
77 | #endif | |
5700029a | 78 | #endif |
6fc1da74 | 79 | |
48071869 | 80 | #include "ACLARP.h" |
c913a563 | 81 | #include "wordlist.h" |
48071869 | 82 | |
83 | #if !USE_ARP_ACL | |
84 | #error USE_ARP_ACL Not defined | |
85 | #endif | |
86 | static void aclParseArpList(SplayNode<acl_arp_data *> **curlist); | |
87 | static int decode_eth(const char *asc, char *eth); | |
cc192b50 | 88 | static int aclMatchArp(SplayNode<acl_arp_data *> **dataptr, IPAddress &c); |
48071869 | 89 | static SplayNode<acl_arp_data *>::SPLAYCMP aclArpCompare; |
90 | static SplayNode<acl_arp_data *>::SPLAYWALKEE aclDumpArpListWalkee; | |
91 | ||
92 | ACL::Prototype ACLARP::RegistryProtoype(&ACLARP::RegistryEntry_, "arp"); | |
93 | ||
94 | ACLARP ACLARP::RegistryEntry_("arp"); | |
95 | ||
96 | ACL * | |
97 | ACLARP::clone() const | |
98 | { | |
99 | return new ACLARP(*this); | |
100 | } | |
101 | ||
102 | ACLARP::ACLARP (char const *theClass) : data (NULL), class_ (theClass) | |
103 | {} | |
104 | ||
105 | ACLARP::ACLARP (ACLARP const & old) : data (NULL), class_ (old.class_) | |
106 | { | |
107 | /* we don't have copy constructors for the data yet */ | |
108 | assert (!old.data); | |
109 | } | |
110 | ||
48071869 | 111 | ACLARP::~ACLARP() |
112 | { | |
113 | if (data) | |
114 | data->destroy(SplayNode<acl_arp_data*>::DefaultFree); | |
115 | } | |
116 | ||
117 | char const * | |
118 | ACLARP::typeString() const | |
119 | { | |
120 | return class_; | |
121 | } | |
122 | ||
123 | bool | |
4b0f5de8 | 124 | ACLARP::empty () const |
48071869 | 125 | { |
290eb6b9 | 126 | return data->empty(); |
48071869 | 127 | } |
128 | ||
129 | /* ==== BEGIN ARP ACL SUPPORT ============================================= */ | |
130 | ||
131 | /* | |
132 | * From: dale@server.ctam.bitmcnit.bryansk.su (Dale) | |
133 | * To: wessels@nlanr.net | |
134 | * Subject: Another Squid patch... :) | |
135 | * Date: Thu, 04 Dec 1997 19:55:01 +0300 | |
136 | * ============================================================================ | |
137 | * | |
138 | * Working on setting up a proper firewall for a network containing some | |
139 | * Win'95 computers at our Univ, I've discovered that some smart students | |
140 | * avoid the restrictions easily just changing their IP addresses in Win'95 | |
141 | * Contol Panel... It has been getting boring, so I took Squid-1.1.18 | |
142 | * sources and added a new acl type for hard-wired access control: | |
143 | * | |
144 | * acl <name> arp <Ethernet address> ... | |
145 | * | |
146 | * For example, | |
147 | * | |
148 | * acl students arp 00:00:21:55:ed:22 00:00:21:ff:55:38 | |
149 | * | |
150 | * NOTE: Linux code by David Luyer <luyer@ucs.uwa.edu.au>. | |
151 | * Original (BSD-specific) code no longer works. | |
152 | * Solaris code by R. Gancarz <radekg@solaris.elektrownia-lagisza.com.pl> | |
153 | */ | |
154 | ||
48071869 | 155 | /* |
156 | * Decode an ascii representation (asc) of an ethernet adress, and place | |
157 | * it in eth[6]. | |
158 | */ | |
159 | static int | |
160 | decode_eth(const char *asc, char *eth) | |
161 | { | |
162 | int a1 = 0, a2 = 0, a3 = 0, a4 = 0, a5 = 0, a6 = 0; | |
163 | ||
164 | if (sscanf(asc, "%x:%x:%x:%x:%x:%x", &a1, &a2, &a3, &a4, &a5, &a6) != 6) { | |
bf8fe701 | 165 | debugs(28, 0, "decode_eth: Invalid ethernet address '" << asc << "'"); |
48071869 | 166 | return 0; /* This is not valid address */ |
167 | } | |
168 | ||
169 | eth[0] = (u_char) a1; | |
170 | eth[1] = (u_char) a2; | |
171 | eth[2] = (u_char) a3; | |
172 | eth[3] = (u_char) a4; | |
173 | eth[4] = (u_char) a5; | |
174 | eth[5] = (u_char) a6; | |
175 | return 1; | |
176 | } | |
177 | ||
178 | acl_arp_data * | |
179 | aclParseArpData(const char *t) | |
180 | { | |
181 | LOCAL_ARRAY(char, eth, 256); | |
182 | acl_arp_data *q = new acl_arp_data; | |
bf8fe701 | 183 | debugs(28, 5, "aclParseArpData: " << t); |
48071869 | 184 | |
185 | if (sscanf(t, "%[0-9a-fA-F:]", eth) != 1) { | |
bf8fe701 | 186 | debugs(28, 0, "aclParseArpData: Bad ethernet address: '" << t << "'"); |
48071869 | 187 | safe_free(q); |
188 | return NULL; | |
189 | } | |
190 | ||
191 | if (!decode_eth(eth, q->eth)) { | |
bf8fe701 | 192 | debugs(28, 0, "" << cfg_filename << " line " << config_lineno << ": " << config_input_line); |
193 | debugs(28, 0, "aclParseArpData: Ignoring invalid ARP acl entry: can't parse '" << eth << "'"); | |
48071869 | 194 | safe_free(q); |
195 | return NULL; | |
196 | } | |
197 | ||
198 | return q; | |
199 | } | |
200 | ||
201 | ||
202 | /*******************/ | |
203 | /* aclParseArpList */ | |
204 | /*******************/ | |
205 | void | |
206 | ACLARP::parse() | |
207 | { | |
208 | aclParseArpList (&data); | |
209 | } | |
210 | ||
211 | void | |
212 | aclParseArpList(SplayNode<acl_arp_data *> **curlist) | |
213 | { | |
214 | char *t = NULL; | |
215 | SplayNode<acl_arp_data *> **Top = curlist; | |
216 | acl_arp_data *q = NULL; | |
217 | ||
218 | while ((t = strtokFile())) { | |
219 | if ((q = aclParseArpData(t)) == NULL) | |
220 | continue; | |
221 | ||
222 | *Top = (*Top)->insert(q, aclArpCompare); | |
223 | } | |
224 | } | |
225 | ||
226 | int | |
227 | ACLARP::match(ACLChecklist *checklist) | |
228 | { | |
cc192b50 | 229 | /* IPv6 does not do ARP */ |
230 | if(!checklist->src_addr.IsIPv4()) | |
231 | { | |
232 | debugs(14, 3, "ACLARP::match: IPv4 Required for ARP Lookups. Skipping " << checklist->src_addr ); | |
233 | return 0; | |
234 | } | |
235 | ||
48071869 | 236 | return aclMatchArp(&data, checklist->src_addr); |
237 | } | |
238 | ||
239 | /***************/ | |
240 | /* aclMatchArp */ | |
241 | /***************/ | |
242 | int | |
cc192b50 | 243 | aclMatchArp(SplayNode<acl_arp_data *> **dataptr, IPAddress &c) |
48071869 | 244 | { |
cc192b50 | 245 | char ntoabuf[MAX_IPSTRLEN]; |
48071869 | 246 | |
247 | struct arpreq arpReq; | |
248 | ||
cc192b50 | 249 | IPAddress ipAddr = c; |
250 | ||
251 | #if defined(_SQUID_LINUX_) | |
48071869 | 252 | |
253 | unsigned char ifbuffer[sizeof(struct ifreq) * 64]; | |
254 | ||
255 | struct ifconf ifc; | |
256 | ||
257 | struct ifreq *ifr; | |
258 | int offset; | |
259 | SplayNode<acl_arp_data*> **Top = dataptr; | |
260 | /* | |
261 | * The linux kernel 2.2 maintains per interface ARP caches and | |
262 | * thus requires an interface name when doing ARP queries. | |
263 | * | |
264 | * The older 2.0 kernels appear to use a unified ARP cache, | |
265 | * and require an empty interface name | |
266 | * | |
267 | * To support both, we attempt the lookup with a blank interface | |
268 | * name first. If that does not succeed, the try each interface | |
269 | * in turn | |
270 | */ | |
cc192b50 | 271 | |
48071869 | 272 | /* |
273 | * Set up structures for ARP lookup with blank interface name | |
274 | */ | |
48071869 | 275 | memset(&arpReq, '\0', sizeof(arpReq)); |
276 | ||
cc192b50 | 277 | ipAddr.GetSockAddr(arpReq.arp_pa); |
48071869 | 278 | /* Query ARP table */ |
279 | ||
280 | if (ioctl(HttpSockets[0], SIOCGARP, &arpReq) != -1) { | |
281 | /* Skip non-ethernet interfaces */ | |
282 | ||
283 | if (arpReq.arp_ha.sa_family != ARPHRD_ETHER) { | |
284 | return 0; | |
285 | } | |
286 | ||
bf8fe701 | 287 | debugs(28, 4, "Got address "<< std::setfill('0') << std::hex << |
288 | std::setw(2) << (arpReq.arp_ha.sa_data[0] & 0xff) << ":" << | |
289 | std::setw(2) << (arpReq.arp_ha.sa_data[1] & 0xff) << ":" << | |
290 | std::setw(2) << (arpReq.arp_ha.sa_data[2] & 0xff) << ":" << | |
291 | std::setw(2) << (arpReq.arp_ha.sa_data[3] & 0xff) << ":" << | |
292 | std::setw(2) << (arpReq.arp_ha.sa_data[4] & 0xff) << ":" << | |
293 | std::setw(2) << (arpReq.arp_ha.sa_data[5] & 0xff)); | |
294 | ||
48071869 | 295 | /* Do lookup */ |
296 | acl_arp_data X; | |
297 | memcpy (X.eth, arpReq.arp_ha.sa_data, 6); | |
298 | *Top = (*Top)->splay(&X, aclArpCompare); | |
cc192b50 | 299 | debugs(28, 3, "aclMatchArp: '" << c << "' " << (splayLastResult ? "NOT found" : "found")); |
48071869 | 300 | return (0 == splayLastResult); |
301 | } | |
302 | ||
303 | /* lookup list of interface names */ | |
304 | ifc.ifc_len = sizeof(ifbuffer); | |
305 | ||
306 | ifc.ifc_buf = (char *)ifbuffer; | |
307 | ||
308 | if (ioctl(HttpSockets[0], SIOCGIFCONF, &ifc) < 0) { | |
bf8fe701 | 309 | debugs(28, 1, "Attempt to retrieve interface list failed: " << xstrerror()); |
48071869 | 310 | return 0; |
311 | } | |
312 | ||
313 | if (ifc.ifc_len > (int)sizeof(ifbuffer)) { | |
bf8fe701 | 314 | debugs(28, 1, "Interface list too long - " << ifc.ifc_len); |
48071869 | 315 | return 0; |
316 | } | |
317 | ||
318 | /* Attempt ARP lookup on each interface */ | |
319 | offset = 0; | |
320 | ||
321 | while (offset < ifc.ifc_len) { | |
322 | ||
323 | ifr = (struct ifreq *) (ifbuffer + offset); | |
324 | offset += sizeof(*ifr); | |
325 | /* Skip loopback and aliased interfaces */ | |
326 | ||
327 | if (0 == strncmp(ifr->ifr_name, "lo", 2)) | |
328 | continue; | |
329 | ||
330 | if (NULL != strchr(ifr->ifr_name, ':')) | |
331 | continue; | |
332 | ||
cc192b50 | 333 | debugs(28, 4, "Looking up ARP address for " << c << " on " << ifr->ifr_name); |
48071869 | 334 | |
335 | /* Set up structures for ARP lookup */ | |
48071869 | 336 | |
337 | memset(&arpReq, '\0', sizeof(arpReq)); | |
338 | ||
cc192b50 | 339 | ipAddr.GetSockAddr(arpReq.arp_pa); |
48071869 | 340 | |
341 | strncpy(arpReq.arp_dev, ifr->ifr_name, sizeof(arpReq.arp_dev) - 1); | |
342 | ||
343 | arpReq.arp_dev[sizeof(arpReq.arp_dev) - 1] = '\0'; | |
344 | ||
345 | /* Query ARP table */ | |
346 | if (-1 == ioctl(HttpSockets[0], SIOCGARP, &arpReq)) { | |
347 | /* | |
348 | * Query failed. Do not log failed lookups or "device | |
349 | * not supported" | |
350 | */ | |
351 | ||
352 | if (ENXIO == errno) | |
353 | (void) 0; | |
354 | else if (ENODEV == errno) | |
355 | (void) 0; | |
356 | else | |
bf8fe701 | 357 | debugs(28, 1, "ARP query failed: " << ifr->ifr_name << ": " << xstrerror()); |
48071869 | 358 | |
359 | continue; | |
360 | } | |
361 | ||
362 | /* Skip non-ethernet interfaces */ | |
363 | if (arpReq.arp_ha.sa_family != ARPHRD_ETHER) | |
364 | continue; | |
365 | ||
bf8fe701 | 366 | debugs(28, 4, "Got address "<< std::setfill('0') << std::hex << |
367 | std::setw(2) << (arpReq.arp_ha.sa_data[0] & 0xff) << ":" << | |
368 | std::setw(2) << (arpReq.arp_ha.sa_data[1] & 0xff) << ":" << | |
369 | std::setw(2) << (arpReq.arp_ha.sa_data[2] & 0xff) << ":" << | |
370 | std::setw(2) << (arpReq.arp_ha.sa_data[3] & 0xff) << ":" << | |
371 | std::setw(2) << (arpReq.arp_ha.sa_data[4] & 0xff) << ":" << | |
372 | std::setw(2) << (arpReq.arp_ha.sa_data[5] & 0xff) << " on "<< | |
373 | std::setfill(' ') << ifr->ifr_name); | |
48071869 | 374 | |
375 | /* Do lookup */ | |
376 | acl_arp_data X; | |
377 | ||
378 | memcpy (X.eth, arpReq.arp_ha.sa_data, 6); | |
379 | ||
380 | *Top = (*Top)->splay(&X, aclArpCompare); | |
381 | ||
382 | /* Return if match, otherwise continue to other interfaces */ | |
383 | if (0 == splayLastResult) { | |
cc192b50 | 384 | debugs(28, 3, "aclMatchArp: " << c << " found on " << ifr->ifr_name); |
48071869 | 385 | return 1; |
386 | } | |
387 | ||
388 | /* | |
389 | * Should we stop looking here? Can the same IP address | |
390 | * exist on multiple interfaces? | |
391 | */ | |
392 | } | |
393 | ||
394 | #elif defined(_SQUID_SOLARIS_) | |
395 | ||
48071869 | 396 | SplayNode<acl_arp_data *> **Top = dataptr; |
397 | ||
398 | /* | |
399 | * Set up structures for ARP lookup with blank interface name | |
400 | */ | |
48071869 | 401 | |
402 | memset(&arpReq, '\0', sizeof(arpReq)); | |
403 | ||
cc192b50 | 404 | ipAddr.GetSockAddr(arpReq.arp_pa); |
48071869 | 405 | |
406 | /* Query ARP table */ | |
407 | if (ioctl(HttpSockets[0], SIOCGARP, &arpReq) != -1) { | |
408 | /* | |
409 | * Solaris (at least 2.6/x86) does not use arp_ha.sa_family - | |
410 | * it returns 00:00:00:00:00:00 for non-ethernet media | |
411 | */ | |
412 | ||
413 | if (arpReq.arp_ha.sa_data[0] == 0 && | |
414 | arpReq.arp_ha.sa_data[1] == 0 && | |
415 | arpReq.arp_ha.sa_data[2] == 0 && | |
416 | arpReq.arp_ha.sa_data[3] == 0 && | |
417 | arpReq.arp_ha.sa_data[4] == 0 && arpReq.arp_ha.sa_data[5] == 0) | |
418 | return 0; | |
419 | ||
bf8fe701 | 420 | debugs(28, 4, "Got address "<< std::setfill('0') << std::hex << |
421 | std::setw(2) << (arpReq.arp_ha.sa_data[0] & 0xff) << ":" << | |
422 | std::setw(2) << (arpReq.arp_ha.sa_data[1] & 0xff) << ":" << | |
423 | std::setw(2) << (arpReq.arp_ha.sa_data[2] & 0xff) << ":" << | |
424 | std::setw(2) << (arpReq.arp_ha.sa_data[3] & 0xff) << ":" << | |
425 | std::setw(2) << (arpReq.arp_ha.sa_data[4] & 0xff) << ":" << | |
426 | std::setw(2) << (arpReq.arp_ha.sa_data[5] & 0xff)); | |
48071869 | 427 | |
428 | /* Do lookup */ | |
09f64260 | 429 | *Top = (*Top)->splay((acl_arp_data *)&arpReq.arp_ha.sa_data, aclArpCompare); |
48071869 | 430 | |
cc192b50 | 431 | debugs(28, 3, "aclMatchArp: '" << c << "' " << (splayLastResult ? "NOT found" : "found")); |
48071869 | 432 | |
433 | return (0 == splayLastResult); | |
434 | } | |
435 | ||
680ec522 | 436 | #elif defined(_SQUID_FREEBSD_) || defined(_SQUID_NETBSD_) || defined(_SQUID_OPENBSD_) |
9a2f1170 | 437 | |
9a2f1170 | 438 | SplayNode<acl_arp_data *> **Top = dataptr; |
439 | ||
440 | int mib[6]; | |
441 | ||
442 | size_t needed; | |
443 | ||
444 | char *lim, *buf, *next; | |
445 | ||
446 | struct rt_msghdr *rtm; | |
447 | ||
448 | struct sockaddr_inarp *sin; | |
449 | ||
450 | struct sockaddr_dl *sdl; | |
451 | ||
452 | /* | |
453 | * Set up structures for ARP lookup with blank interface name | |
454 | */ | |
9a2f1170 | 455 | |
456 | memset(&arpReq, '\0', sizeof(arpReq)); | |
457 | ||
cc192b50 | 458 | ipAddr.GetSockAddr(arpReq.arp_pa); |
9a2f1170 | 459 | |
460 | /* Query ARP table */ | |
461 | mib[0] = CTL_NET; | |
462 | ||
463 | mib[1] = PF_ROUTE; | |
464 | ||
465 | mib[2] = 0; | |
466 | ||
467 | mib[3] = AF_INET; | |
468 | ||
469 | mib[4] = NET_RT_FLAGS; | |
470 | ||
471 | mib[5] = RTF_LLINFO; | |
472 | ||
473 | if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { | |
bf8fe701 | 474 | debugs(28, 0, "Can't estimate ARP table size!"); |
9a2f1170 | 475 | return 0; |
476 | } | |
477 | ||
09f64260 | 478 | if ((buf = (char *)xmalloc(needed)) == NULL) { |
bf8fe701 | 479 | debugs(28, 0, "Can't allocate temporary ARP table!"); |
9a2f1170 | 480 | return 0; |
481 | } | |
482 | ||
483 | if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { | |
bf8fe701 | 484 | debugs(28, 0, "Can't retrieve ARP table!"); |
9a2f1170 | 485 | xfree(buf); |
486 | return 0; | |
487 | } | |
488 | ||
489 | lim = buf + needed; | |
490 | ||
491 | for (next = buf; next < lim; next += rtm->rtm_msglen) { | |
492 | ||
493 | rtm = (struct rt_msghdr *) next; | |
494 | ||
495 | sin = (struct sockaddr_inarp *) (rtm + 1); | |
496 | /*sdl = (struct sockaddr_dl *) (sin + 1); */ | |
497 | ||
498 | #define ROUNDUP(a) \ | |
499 | ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) | |
500 | ||
b3bbddff | 501 | sdl = (struct sockaddr_dl *)((char *) sin + ROUNDUP(sin->sin_len)); |
9a2f1170 | 502 | |
cc192b50 | 503 | if (c == sin->sin_addr) { |
9a2f1170 | 504 | if (sdl->sdl_alen) { |
505 | ||
506 | arpReq.arp_ha.sa_len = sizeof(struct sockaddr); | |
507 | arpReq.arp_ha.sa_family = AF_UNSPEC; | |
508 | memcpy(arpReq.arp_ha.sa_data, LLADDR(sdl), sdl->sdl_alen); | |
509 | } | |
510 | } | |
511 | } | |
512 | ||
513 | xfree(buf); | |
514 | ||
515 | if (arpReq.arp_ha.sa_data[0] == 0 && arpReq.arp_ha.sa_data[1] == 0 && | |
516 | arpReq.arp_ha.sa_data[2] == 0 && arpReq.arp_ha.sa_data[3] == 0 && | |
517 | arpReq.arp_ha.sa_data[4] == 0 && arpReq.arp_ha.sa_data[5] == 0) | |
518 | return 0; | |
519 | ||
bf8fe701 | 520 | debugs(28, 4, "Got address "<< std::setfill('0') << std::hex << |
521 | std::setw(2) << (arpReq.arp_ha.sa_data[0] & 0xff) << ":" << | |
522 | std::setw(2) << (arpReq.arp_ha.sa_data[1] & 0xff) << ":" << | |
523 | std::setw(2) << (arpReq.arp_ha.sa_data[2] & 0xff) << ":" << | |
524 | std::setw(2) << (arpReq.arp_ha.sa_data[3] & 0xff) << ":" << | |
525 | std::setw(2) << (arpReq.arp_ha.sa_data[4] & 0xff) << ":" << | |
526 | std::setw(2) << (arpReq.arp_ha.sa_data[5] & 0xff)); | |
9a2f1170 | 527 | |
528 | /* Do lookup */ | |
09f64260 | 529 | *Top = (*Top)->splay((acl_arp_data *)&arpReq.arp_ha.sa_data, aclArpCompare); |
9a2f1170 | 530 | |
cc192b50 | 531 | debugs(28, 3, "aclMatchArp: '" << c << "' " << (splayLastResult ? "NOT found" : "found")); |
9a2f1170 | 532 | |
533 | return (0 == splayLastResult); | |
534 | ||
5700029a | 535 | #elif defined(_SQUID_WIN32_) |
536 | ||
537 | DWORD dwNetTable = 0; | |
538 | ||
539 | DWORD ipNetTableLen = 0; | |
540 | ||
541 | PMIB_IPNETTABLE NetTable = NULL; | |
542 | ||
543 | DWORD i; | |
544 | ||
545 | SplayNode<acl_arp_data *> **Top = dataptr; | |
546 | ||
922a8455 | 547 | memset(&arpReq, '\0', sizeof(arpReq)); |
548 | ||
5700029a | 549 | /* Get size of Windows ARP table */ |
550 | if (GetIpNetTable(NetTable, &ipNetTableLen, FALSE) != ERROR_INSUFFICIENT_BUFFER) { | |
bf8fe701 | 551 | debugs(28, 0, "Can't estimate ARP table size!"); |
5700029a | 552 | return 0; |
553 | } | |
554 | ||
555 | /* Allocate space for ARP table and assign pointers */ | |
556 | if ((NetTable = (PMIB_IPNETTABLE)xmalloc(ipNetTableLen)) == NULL) { | |
bf8fe701 | 557 | debugs(28, 0, "Can't allocate temporary ARP table!"); |
5700029a | 558 | return 0; |
559 | } | |
560 | ||
561 | /* Get actual ARP table */ | |
562 | if ((dwNetTable = GetIpNetTable(NetTable, &ipNetTableLen, FALSE)) != NO_ERROR) { | |
bf8fe701 | 563 | debugs(28, 0, "Can't retrieve ARP table!"); |
5700029a | 564 | xfree(NetTable); |
565 | return 0; | |
566 | } | |
567 | ||
568 | /* Find MAC address from net table */ | |
569 | for (i = 0 ; i < NetTable->dwNumEntries ; i++) { | |
cc192b50 | 570 | if ((c == (struct in_addr)NetTable->table[i].dwAddr) && (NetTable->table[i].dwType > 2)) { |
5700029a | 571 | arpReq.arp_ha.sa_family = AF_UNSPEC; |
922a8455 | 572 | memcpy(arpReq.arp_ha.sa_data, NetTable->table[i].bPhysAddr, NetTable->table[i].dwPhysAddrLen); |
5700029a | 573 | } |
574 | } | |
575 | ||
576 | xfree(NetTable); | |
577 | ||
578 | if (arpReq.arp_ha.sa_data[0] == 0 && arpReq.arp_ha.sa_data[1] == 0 && | |
579 | arpReq.arp_ha.sa_data[2] == 0 && arpReq.arp_ha.sa_data[3] == 0 && | |
580 | arpReq.arp_ha.sa_data[4] == 0 && arpReq.arp_ha.sa_data[5] == 0) | |
581 | return 0; | |
582 | ||
bf8fe701 | 583 | debugs(28, 4, "Got address "<< std::setfill('0') << std::hex << |
584 | std::setw(2) << (arpReq.arp_ha.sa_data[0] & 0xff) << ":" << | |
585 | std::setw(2) << (arpReq.arp_ha.sa_data[1] & 0xff) << ":" << | |
586 | std::setw(2) << (arpReq.arp_ha.sa_data[2] & 0xff) << ":" << | |
587 | std::setw(2) << (arpReq.arp_ha.sa_data[3] & 0xff) << ":" << | |
588 | std::setw(2) << (arpReq.arp_ha.sa_data[4] & 0xff) << ":" << | |
589 | std::setw(2) << (arpReq.arp_ha.sa_data[5] & 0xff)); | |
5700029a | 590 | |
591 | /* Do lookup */ | |
592 | *Top = (*Top)->splay((acl_arp_data *)&arpReq.arp_ha.sa_data, aclArpCompare); | |
593 | ||
cc192b50 | 594 | debugs(28, 3, "aclMatchArp: '" << c << "' " << (splayLastResult ? "NOT found" : "found")); |
5700029a | 595 | |
596 | return (0 == splayLastResult); | |
597 | ||
48071869 | 598 | #else |
9a2f1170 | 599 | |
6bf4f823 | 600 | #error "ARP type ACL not supported on this operating system." |
48071869 | 601 | |
602 | #endif | |
603 | /* | |
604 | * Address was not found on any interface | |
605 | */ | |
cc192b50 | 606 | debugs(28, 3, "aclMatchArp: " << c << " NOT found"); |
48071869 | 607 | |
608 | return 0; | |
609 | } | |
610 | ||
611 | static int | |
612 | aclArpCompare(acl_arp_data * const &a, acl_arp_data * const &b) | |
613 | { | |
614 | return memcmp(a->eth, b->eth, 6); | |
615 | } | |
616 | ||
48071869 | 617 | static void |
618 | aclDumpArpListWalkee(acl_arp_data * const &node, void *state) | |
619 | { | |
620 | acl_arp_data *arp = node; | |
621 | static char buf[24]; | |
622 | snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x", | |
5b807763 | 623 | arp->eth[0] & 0xff, arp->eth[1] & 0xff, |
624 | arp->eth[2] & 0xff, arp->eth[3] & 0xff, | |
625 | arp->eth[4] & 0xff, arp->eth[5] & 0xff); | |
48071869 | 626 | wordlistAdd((wordlist **)state, buf); |
627 | } | |
628 | ||
629 | wordlist * | |
630 | ACLARP::dump() const | |
631 | { | |
632 | wordlist *w = NULL; | |
633 | data->walk(aclDumpArpListWalkee, &w); | |
634 | return w; | |
635 | } | |
636 | ||
637 | /* ==== END ARP ACL SUPPORT =============================================== */ |