2 * DEBUG: section 28 Access Control
3 * AUTHOR: Duane Wessels
5 * SQUID Web Proxy Cache http://www.squid-cache.org/
6 * ----------------------------------------------------------
8 * Squid is the result of efforts by numerous individuals from
9 * the Internet community; see the CONTRIBUTORS file for full
10 * details. Many organizations have provided support for Squid's
11 * development; see the SPONSORS file for full details. Squid is
12 * Copyrighted (C) 2001 by the Regents of the University of
13 * California; see the COPYRIGHT file for full details. Squid
14 * incorporates software developed and/or copyrighted by other
15 * sources; see the CREDITS file for full details.
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
32 * Copyright (c) 2003, Robert Collins <robertc@squid-cache.org>
37 #include <squid_windows.h>
40 #include "ip/IpAddress.h"
46 IpAddress arp_pa
; /* protocol address */
48 struct sockaddr arp_ha
; /* hardware address */
49 int arp_flags
; /* flags */
55 #ifdef _SQUID_SOLARIS_
56 #include <sys/sockio.h>
58 #include <sys/sysctl.h>
61 #include <net/if_arp.h>
62 #include <sys/ioctl.h>
64 #include <net/if_dl.h>
66 #include <net/route.h>
68 #if defined(_SQUID_FREEBSD_) || defined(_SQUID_NETBSD_) || defined(_SQUID_OPENBSD_) || defined(_SQUID_DRAGONFLY_)
69 #include <net/if_arp.h>
71 #if HAVE_NETINET_IF_ETHER_H
72 #include <netinet/if_ether.h>
77 #include "acl/FilledChecklist.h"
81 #error USE_ARP_ACL Not defined
83 static void aclParseArpList(SplayNode
<acl_arp_data
*> **curlist
);
84 static int decode_eth(const char *asc
, char *eth
);
85 static int aclMatchArp(SplayNode
<acl_arp_data
*> **dataptr
, IpAddress
&c
);
86 static SplayNode
<acl_arp_data
*>::SPLAYCMP aclArpCompare
;
87 static SplayNode
<acl_arp_data
*>::SPLAYWALKEE aclDumpArpListWalkee
;
89 ACL::Prototype
ACLARP::RegistryProtoype(&ACLARP::RegistryEntry_
, "arp");
91 ACLARP
ACLARP::RegistryEntry_("arp");
96 return new ACLARP(*this);
99 ACLARP::ACLARP (char const *theClass
) : data (NULL
), class_ (theClass
)
102 ACLARP::ACLARP (ACLARP
const & old
) : data (NULL
), class_ (old
.class_
)
104 /* we don't have copy constructors for the data yet */
111 data
->destroy(SplayNode
<acl_arp_data
*>::DefaultFree
);
115 ACLARP::typeString() const
121 ACLARP::empty () const
123 return data
->empty();
126 /* ==== BEGIN ARP ACL SUPPORT ============================================= */
129 * From: dale@server.ctam.bitmcnit.bryansk.su (Dale)
130 * To: wessels@nlanr.net
131 * Subject: Another Squid patch... :)
132 * Date: Thu, 04 Dec 1997 19:55:01 +0300
133 * ============================================================================
135 * Working on setting up a proper firewall for a network containing some
136 * Win'95 computers at our Univ, I've discovered that some smart students
137 * avoid the restrictions easily just changing their IP addresses in Win'95
138 * Contol Panel... It has been getting boring, so I took Squid-1.1.18
139 * sources and added a new acl type for hard-wired access control:
141 * acl <name> arp <Ethernet address> ...
145 * acl students arp 00:00:21:55:ed:22 00:00:21:ff:55:38
147 * NOTE: Linux code by David Luyer <luyer@ucs.uwa.edu.au>.
148 * Original (BSD-specific) code no longer works.
149 * Solaris code by R. Gancarz <radekg@solaris.elektrownia-lagisza.com.pl>
153 * Decode an ascii representation (asc) of an ethernet adress.
155 \param asc[in] ASCII representation of an ethernet (MAC) address
156 \param eth[out] Binary representation of the ethernet address
157 \retval 0 Conversion to binary failed. Invalid address
158 \retval 1 Conversion completed successfully
161 decode_eth(const char *asc
, char *eth
)
163 int a1
= 0, a2
= 0, a3
= 0, a4
= 0, a5
= 0, a6
= 0;
165 if (sscanf(asc
, "%x:%x:%x:%x:%x:%x", &a1
, &a2
, &a3
, &a4
, &a5
, &a6
) != 6) {
166 debugs(28, 0, "decode_eth: Invalid ethernet address '" << asc
<< "'");
167 return 0; /* This is not valid address */
170 eth
[0] = (u_char
) a1
;
171 eth
[1] = (u_char
) a2
;
172 eth
[2] = (u_char
) a3
;
173 eth
[3] = (u_char
) a4
;
174 eth
[4] = (u_char
) a5
;
175 eth
[5] = (u_char
) a6
;
180 aclParseArpData(const char *t
)
182 LOCAL_ARRAY(char, eth
, 256);
183 acl_arp_data
*q
= new acl_arp_data
;
184 debugs(28, 5, "aclParseArpData: " << t
);
186 if (sscanf(t
, "%[0-9a-fA-F:]", eth
) != 1) {
187 debugs(28, 0, "aclParseArpData: Bad ethernet address: '" << t
<< "'");
192 if (!decode_eth(eth
, q
->eth
)) {
193 debugs(28, 0, "" << cfg_filename
<< " line " << config_lineno
<< ": " << config_input_line
);
194 debugs(28, 0, "aclParseArpData: Ignoring invalid ARP acl entry: can't parse '" << eth
<< "'");
203 /*******************/
204 /* aclParseArpList */
205 /*******************/
209 aclParseArpList (&data
);
213 aclParseArpList(SplayNode
<acl_arp_data
*> **curlist
)
216 SplayNode
<acl_arp_data
*> **Top
= curlist
;
217 acl_arp_data
*q
= NULL
;
219 while ((t
= strtokFile())) {
220 if ((q
= aclParseArpData(t
)) == NULL
)
223 *Top
= (*Top
)->insert(q
, aclArpCompare
);
228 ACLARP::match(ACLChecklist
*cl
)
230 ACLFilledChecklist
*checklist
= Filled(cl
);
232 /* IPv6 does not do ARP */
233 if (!checklist
->src_addr
.IsIPv4()) {
234 debugs(14, 3, "ACLARP::match: IPv4 Required for ARP Lookups. Skipping " << checklist
->src_addr
);
238 return aclMatchArp(&data
, checklist
->src_addr
);
245 aclMatchArp(SplayNode
<acl_arp_data
*> **dataptr
, IpAddress
&c
)
247 struct arpreq arpReq
;
248 struct sockaddr_in
*sa
= NULL
;
250 IpAddress ipAddr
= c
;
252 #if defined(_SQUID_LINUX_)
254 unsigned char ifbuffer
[sizeof(struct ifreq
) * 64];
260 SplayNode
<acl_arp_data
*> **Top
= dataptr
;
262 * The linux kernel 2.2 maintains per interface ARP caches and
263 * thus requires an interface name when doing ARP queries.
265 * The older 2.0 kernels appear to use a unified ARP cache,
266 * and require an empty interface name
268 * To support both, we attempt the lookup with a blank interface
269 * name first. If that does not succeed, the try each interface
274 * Set up structures for ARP lookup with blank interface name
276 memset(&arpReq
, '\0', sizeof(arpReq
));
278 sa
= (sockaddr_in
*)&arpReq
.arp_pa
;
279 ipAddr
.GetSockAddr(*sa
);
280 /* Query ARP table */
282 if (ioctl(HttpSockets
[0], SIOCGARP
, &arpReq
) != -1) {
283 /* Skip non-ethernet interfaces */
285 if (arpReq
.arp_ha
.sa_family
!= ARPHRD_ETHER
) {
289 debugs(28, 4, "Got address "<< std::setfill('0') << std::hex
<<
290 std::setw(2) << (arpReq
.arp_ha
.sa_data
[0] & 0xff) << ":" <<
291 std::setw(2) << (arpReq
.arp_ha
.sa_data
[1] & 0xff) << ":" <<
292 std::setw(2) << (arpReq
.arp_ha
.sa_data
[2] & 0xff) << ":" <<
293 std::setw(2) << (arpReq
.arp_ha
.sa_data
[3] & 0xff) << ":" <<
294 std::setw(2) << (arpReq
.arp_ha
.sa_data
[4] & 0xff) << ":" <<
295 std::setw(2) << (arpReq
.arp_ha
.sa_data
[5] & 0xff));
299 memcpy (X
.eth
, arpReq
.arp_ha
.sa_data
, 6);
300 *Top
= (*Top
)->splay(&X
, aclArpCompare
);
301 debugs(28, 3, "aclMatchArp: '" << c
<< "' " << (splayLastResult
? "NOT found" : "found"));
302 return (0 == splayLastResult
);
305 /* lookup list of interface names */
306 ifc
.ifc_len
= sizeof(ifbuffer
);
308 ifc
.ifc_buf
= (char *)ifbuffer
;
310 if (ioctl(HttpSockets
[0], SIOCGIFCONF
, &ifc
) < 0) {
311 debugs(28, 1, "Attempt to retrieve interface list failed: " << xstrerror());
315 if (ifc
.ifc_len
> (int)sizeof(ifbuffer
)) {
316 debugs(28, 1, "Interface list too long - " << ifc
.ifc_len
);
320 /* Attempt ARP lookup on each interface */
323 while (offset
< ifc
.ifc_len
) {
325 ifr
= (struct ifreq
*) (ifbuffer
+ offset
);
326 offset
+= sizeof(*ifr
);
327 /* Skip loopback and aliased interfaces */
329 if (0 == strncmp(ifr
->ifr_name
, "lo", 2))
332 if (NULL
!= strchr(ifr
->ifr_name
, ':'))
335 debugs(28, 4, "Looking up ARP address for " << c
<< " on " << ifr
->ifr_name
);
337 /* Set up structures for ARP lookup */
339 memset(&arpReq
, '\0', sizeof(arpReq
));
341 sa
= (sockaddr_in
*)&arpReq
.arp_pa
;
342 ipAddr
.GetSockAddr(*sa
);
344 strncpy(arpReq
.arp_dev
, ifr
->ifr_name
, sizeof(arpReq
.arp_dev
) - 1);
346 arpReq
.arp_dev
[sizeof(arpReq
.arp_dev
) - 1] = '\0';
348 /* Query ARP table */
349 if (-1 == ioctl(HttpSockets
[0], SIOCGARP
, &arpReq
)) {
351 * Query failed. Do not log failed lookups or "device
357 else if (ENODEV
== errno
)
360 debugs(28, 1, "ARP query failed: " << ifr
->ifr_name
<< ": " << xstrerror());
365 /* Skip non-ethernet interfaces */
366 if (arpReq
.arp_ha
.sa_family
!= ARPHRD_ETHER
)
369 debugs(28, 4, "Got address "<< std::setfill('0') << std::hex
<<
370 std::setw(2) << (arpReq
.arp_ha
.sa_data
[0] & 0xff) << ":" <<
371 std::setw(2) << (arpReq
.arp_ha
.sa_data
[1] & 0xff) << ":" <<
372 std::setw(2) << (arpReq
.arp_ha
.sa_data
[2] & 0xff) << ":" <<
373 std::setw(2) << (arpReq
.arp_ha
.sa_data
[3] & 0xff) << ":" <<
374 std::setw(2) << (arpReq
.arp_ha
.sa_data
[4] & 0xff) << ":" <<
375 std::setw(2) << (arpReq
.arp_ha
.sa_data
[5] & 0xff) << " on "<<
376 std::setfill(' ') << ifr
->ifr_name
);
381 memcpy (X
.eth
, arpReq
.arp_ha
.sa_data
, 6);
383 *Top
= (*Top
)->splay(&X
, aclArpCompare
);
385 /* Return if match, otherwise continue to other interfaces */
386 if (0 == splayLastResult
) {
387 debugs(28, 3, "aclMatchArp: " << c
<< " found on " << ifr
->ifr_name
);
392 * Should we stop looking here? Can the same IP address
393 * exist on multiple interfaces?
397 #elif defined(_SQUID_SOLARIS_)
399 SplayNode
<acl_arp_data
*> **Top
= dataptr
;
402 * Set up structures for ARP lookup with blank interface name
405 memset(&arpReq
, '\0', sizeof(arpReq
));
407 sa
= (sockaddr_in
*)&arpReq
.arp_pa
;
408 ipAddr
.GetSockAddr(*sa
);
410 /* Query ARP table */
411 if (ioctl(HttpSockets
[0], SIOCGARP
, &arpReq
) != -1) {
413 * Solaris (at least 2.6/x86) does not use arp_ha.sa_family -
414 * it returns 00:00:00:00:00:00 for non-ethernet media
417 if (arpReq
.arp_ha
.sa_data
[0] == 0 &&
418 arpReq
.arp_ha
.sa_data
[1] == 0 &&
419 arpReq
.arp_ha
.sa_data
[2] == 0 &&
420 arpReq
.arp_ha
.sa_data
[3] == 0 &&
421 arpReq
.arp_ha
.sa_data
[4] == 0 && arpReq
.arp_ha
.sa_data
[5] == 0)
424 debugs(28, 4, "Got address "<< std::setfill('0') << std::hex
<<
425 std::setw(2) << (arpReq
.arp_ha
.sa_data
[0] & 0xff) << ":" <<
426 std::setw(2) << (arpReq
.arp_ha
.sa_data
[1] & 0xff) << ":" <<
427 std::setw(2) << (arpReq
.arp_ha
.sa_data
[2] & 0xff) << ":" <<
428 std::setw(2) << (arpReq
.arp_ha
.sa_data
[3] & 0xff) << ":" <<
429 std::setw(2) << (arpReq
.arp_ha
.sa_data
[4] & 0xff) << ":" <<
430 std::setw(2) << (arpReq
.arp_ha
.sa_data
[5] & 0xff));
433 *Top
= (*Top
)->splay((acl_arp_data
*)&arpReq
.arp_ha
.sa_data
, aclArpCompare
);
435 debugs(28, 3, "aclMatchArp: '" << c
<< "' " << (splayLastResult
? "NOT found" : "found"));
437 return (0 == splayLastResult
);
440 #elif defined(_SQUID_FREEBSD_) || defined(_SQUID_NETBSD_) || defined(_SQUID_OPENBSD_) || defined(_SQUID_DRAGONFLY_)
442 SplayNode
<acl_arp_data
*> **Top
= dataptr
;
448 char *lim
, *buf
, *next
;
450 struct rt_msghdr
*rtm
;
452 struct sockaddr_inarp
*sin
;
454 struct sockaddr_dl
*sdl
;
457 * Set up structures for ARP lookup with blank interface name
460 memset(&arpReq
, '\0', sizeof(arpReq
));
462 sa
= (struct sockaddr_in
*) &arpReq
.arp_pa
;
463 ipAddr
.GetSockAddr(*sa
);
465 /* Query ARP table */
474 mib
[4] = NET_RT_FLAGS
;
478 if (sysctl(mib
, 6, NULL
, &needed
, NULL
, 0) < 0) {
479 debugs(28, 0, "Can't estimate ARP table size!");
483 if ((buf
= (char *)xmalloc(needed
)) == NULL
) {
484 debugs(28, 0, "Can't allocate temporary ARP table!");
488 if (sysctl(mib
, 6, buf
, &needed
, NULL
, 0) < 0) {
489 debugs(28, 0, "Can't retrieve ARP table!");
496 for (next
= buf
; next
< lim
; next
+= rtm
->rtm_msglen
) {
498 rtm
= (struct rt_msghdr
*) next
;
500 sin
= (struct sockaddr_inarp
*) (rtm
+ 1);
501 /*sdl = (struct sockaddr_dl *) (sin + 1); */
504 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
506 sdl
= (struct sockaddr_dl
*)((char *) sin
+ ROUNDUP(sin
->sin_len
));
508 if (c
== sin
->sin_addr
) {
511 arpReq
.arp_ha
.sa_len
= sizeof(struct sockaddr
);
512 arpReq
.arp_ha
.sa_family
= AF_UNSPEC
;
513 memcpy(arpReq
.arp_ha
.sa_data
, LLADDR(sdl
), sdl
->sdl_alen
);
520 if (arpReq
.arp_ha
.sa_data
[0] == 0 && arpReq
.arp_ha
.sa_data
[1] == 0 &&
521 arpReq
.arp_ha
.sa_data
[2] == 0 && arpReq
.arp_ha
.sa_data
[3] == 0 &&
522 arpReq
.arp_ha
.sa_data
[4] == 0 && arpReq
.arp_ha
.sa_data
[5] == 0)
525 debugs(28, 4, "Got address "<< std::setfill('0') << std::hex
<<
526 std::setw(2) << (arpReq
.arp_ha
.sa_data
[0] & 0xff) << ":" <<
527 std::setw(2) << (arpReq
.arp_ha
.sa_data
[1] & 0xff) << ":" <<
528 std::setw(2) << (arpReq
.arp_ha
.sa_data
[2] & 0xff) << ":" <<
529 std::setw(2) << (arpReq
.arp_ha
.sa_data
[3] & 0xff) << ":" <<
530 std::setw(2) << (arpReq
.arp_ha
.sa_data
[4] & 0xff) << ":" <<
531 std::setw(2) << (arpReq
.arp_ha
.sa_data
[5] & 0xff));
534 *Top
= (*Top
)->splay((acl_arp_data
*)&arpReq
.arp_ha
.sa_data
, aclArpCompare
);
536 debugs(28, 3, "aclMatchArp: '" << c
<< "' " << (splayLastResult
? "NOT found" : "found"));
538 return (0 == splayLastResult
);
540 #elif defined(_SQUID_WIN32_)
542 DWORD dwNetTable
= 0;
544 DWORD ipNetTableLen
= 0;
546 PMIB_IPNETTABLE NetTable
= NULL
;
550 SplayNode
<acl_arp_data
*> **Top
= dataptr
;
552 memset(&arpReq
, '\0', sizeof(arpReq
));
554 /* Get size of Windows ARP table */
555 if (GetIpNetTable(NetTable
, &ipNetTableLen
, FALSE
) != ERROR_INSUFFICIENT_BUFFER
) {
556 debugs(28, 0, "Can't estimate ARP table size!");
560 /* Allocate space for ARP table and assign pointers */
561 if ((NetTable
= (PMIB_IPNETTABLE
)xmalloc(ipNetTableLen
)) == NULL
) {
562 debugs(28, 0, "Can't allocate temporary ARP table!");
566 /* Get actual ARP table */
567 if ((dwNetTable
= GetIpNetTable(NetTable
, &ipNetTableLen
, FALSE
)) != NO_ERROR
) {
568 debugs(28, 0, "Can't retrieve ARP table!");
573 /* Find MAC address from net table */
574 for (i
= 0 ; i
< NetTable
->dwNumEntries
; i
++) {
576 a
.s_addr
= NetTable
->table
[i
].dwAddr
;
577 if (c
== a
&& (NetTable
->table
[i
].dwType
> 2)) {
578 arpReq
.arp_ha
.sa_family
= AF_UNSPEC
;
579 memcpy(arpReq
.arp_ha
.sa_data
, NetTable
->table
[i
].bPhysAddr
, NetTable
->table
[i
].dwPhysAddrLen
);
585 if (arpReq
.arp_ha
.sa_data
[0] == 0 && arpReq
.arp_ha
.sa_data
[1] == 0 &&
586 arpReq
.arp_ha
.sa_data
[2] == 0 && arpReq
.arp_ha
.sa_data
[3] == 0 &&
587 arpReq
.arp_ha
.sa_data
[4] == 0 && arpReq
.arp_ha
.sa_data
[5] == 0)
590 debugs(28, 4, "Got address "<< std::setfill('0') << std::hex
<<
591 std::setw(2) << (arpReq
.arp_ha
.sa_data
[0] & 0xff) << ":" <<
592 std::setw(2) << (arpReq
.arp_ha
.sa_data
[1] & 0xff) << ":" <<
593 std::setw(2) << (arpReq
.arp_ha
.sa_data
[2] & 0xff) << ":" <<
594 std::setw(2) << (arpReq
.arp_ha
.sa_data
[3] & 0xff) << ":" <<
595 std::setw(2) << (arpReq
.arp_ha
.sa_data
[4] & 0xff) << ":" <<
596 std::setw(2) << (arpReq
.arp_ha
.sa_data
[5] & 0xff));
599 *Top
= (*Top
)->splay((acl_arp_data
*)&arpReq
.arp_ha
.sa_data
, aclArpCompare
);
601 debugs(28, 3, "aclMatchArp: '" << c
<< "' " << (splayLastResult
? "NOT found" : "found"));
603 return (0 == splayLastResult
);
607 #error "ARP type ACL not supported on this operating system."
611 * Address was not found on any interface
613 debugs(28, 3, "aclMatchArp: " << c
<< " NOT found");
619 aclArpCompare(acl_arp_data
* const &a
, acl_arp_data
* const &b
)
621 return memcmp(a
->eth
, b
->eth
, 6);
625 aclDumpArpListWalkee(acl_arp_data
* const &node
, void *state
)
627 acl_arp_data
*arp
= node
;
629 snprintf(buf
, sizeof(buf
), "%02x:%02x:%02x:%02x:%02x:%02x",
630 arp
->eth
[0] & 0xff, arp
->eth
[1] & 0xff,
631 arp
->eth
[2] & 0xff, arp
->eth
[3] & 0xff,
632 arp
->eth
[4] & 0xff, arp
->eth
[5] & 0xff);
633 wordlistAdd((wordlist
**)state
, buf
);
640 data
->walk(aclDumpArpListWalkee
, &w
);
644 /* ==== END ARP ACL SUPPORT =============================================== */