This separates the current code for ARP lookup and encode/decode.
Also makes the code buildable without fatal build errors on
non-supporting systems. A loud run-time error is generated if related
features are attempt use on non-supporting systems.
FUTURE WORK:
* unit-tests
* on-demand lookups and logging of MAC/EUI-48 for a client
similar to how ident is done.
* on-demand passing MAC/EUI-48 to external_acl_type helpers
* EUI-64 for IPv6 support.
* Increased ARP support on other OS.
esac
])
-AM_CONDITIONAL(ENABLE_ARP_ACL, false)
-AC_ARG_ENABLE(arp-acl,
- AS_HELP_STRING([--enable-arp-acl],[Enable use of ARP ACL lists (ether address)]),
+AM_CONDITIONAL(USE_SQUID_EUI, false)
+AC_ARG_ENABLE(eui,
+ AS_HELP_STRING([--enable-eui],[Enable use of ARP / MAC/ EUI (ether address)]),
[ if test "$enableval" = "yes" ; then
- AC_MSG_NOTICE([ARP ACL lists enabled (ether address)])
+ AC_MSG_NOTICE([EUI controls enabled (ether address)])
case "$host" in
*-linux-*)
;;
*-netbsd*)
;;
*-cygwin*)
- LIBS="$LIBS -liphlpapi"
+ EUILIB="-liphlpapi"
;;
*-mingw*)
- LIBS="$LIBS -liphlpapi"
+ EUILIB="-liphlpapi"
;;
*)
- AC_MSG_WARN([ARP ACL support probably won't work on $host.])
+ AC_MSG_WARN([EUI support probably won't work on $host.])
sleep 10
;;
esac
- AC_DEFINE(USE_ARP_ACL,1,[Define this to include code which lets you specify access control elements based on ethernet hardware addresses. This code uses functions found in 4.4 BSD derviations (e.g. FreeBSD, ?).])
- AM_CONDITIONAL(ENABLE_ARP_ACL, true)
+ AC_CHECK_HEADERS( \
+ Iphlpapi.h \
+ net/if.h \
+ net/if_arp.h \
+ net/if_dl.h \
+ net/route.h \
+ netinet/if_ether.h \
+ sys/sockio.h \
+ sys/sysctl.h \
+ sys/ioctl.h \
+ )
+ AC_DEFINE(USE_SQUID_EUI,1,[Define this to include code which lets you use ethernet hardware addresses. This code uses functions found in 4.4 BSD derviations (e.g. FreeBSD, ?).])
+ AM_CONDITIONAL(USE_SQUID_EUI, true)
fi
])
src/adaptation/icap/Makefile \
src/adaptation/ecap/Makefile \
src/esi/Makefile \
+ src/eui/Makefile \
src/icmp/Makefile \
src/ident/Makefile \
src/ip/Makefile \
<sect1>New options<label id="newoptions">
<p>
<descrip>
+ <tag>--enable-eui</tag>
+ <p>Enable Support for handling EUI operations.
+ This includes ARP lookups for MAC (EUI-48) addresses and the ACL arp type tests.
+
<tag>--enable-url-rewrite-helpers</tag>
<p>Build helpers for some basic URL-rewrite actions. For use by url_rewrite_program.
If omitted or set to =all then all bundled helpers that are able to build will be built.
<sect1>Removed options<label id="removedoptions">
<p>
<descrip>
- <tag>???alphabetical list within group ordered: enable, disable, with, without) ???</tag>
- <p> ???explain??
+ <tag>--enable-arp-acl</tag>
+ <p>Replaced by --enable-eui
</descrip>
LoadableModules.h \
LoadableModules.cc
-SUBDIRS = base acl fs repl auth ip icmp ident
+SUBDIRS = base eui acl fs repl auth ip icmp ident
if USE_ADAPTATION
SUBDIRS += adaptation
auth/libacls.la \
ident/libident.la \
acl/libacls.la \
+ eui/libeui.la \
acl/libstate.la \
auth/libauth.la \
acl/libapi.la \
* Copyright (c) 2003, Robert Collins <robertc@squid-cache.org>
*/
-#include "config.h"
-#ifdef _SQUID_CYGWIN_
-#include <squid_windows.h>
-#endif
#include "squid.h"
-#include "ip/IpAddress.h"
-#ifdef _SQUID_WIN32_
-
-struct arpreq {
-
- IpAddress arp_pa; /* protocol address */
-
- struct sockaddr arp_ha; /* hardware address */
- int arp_flags; /* flags */
-};
-
-#include <Iphlpapi.h>
-#else
-
-#ifdef _SQUID_SOLARIS_
-#include <sys/sockio.h>
-#else
-#include <sys/sysctl.h>
-#endif
-#ifdef _SQUID_LINUX_
-#include <net/if_arp.h>
-#include <sys/ioctl.h>
-#else
-#include <net/if_dl.h>
-#endif
-#include <net/route.h>
-#include <net/if.h>
-#if defined(_SQUID_FREEBSD_) || defined(_SQUID_NETBSD_) || defined(_SQUID_OPENBSD_) || defined(_SQUID_DRAGONFLY_)
-#include <net/if_arp.h>
-#endif
-#if HAVE_NETINET_IF_ETHER_H
-#include <netinet/if_ether.h>
-#endif
-#endif
+#if USE_SQUID_EUI
#include "acl/Arp.h"
#include "acl/FilledChecklist.h"
+#include "eui/Eui48.h"
+#include "ip/IpAddress.h"
#include "wordlist.h"
-#if !USE_ARP_ACL
-#error USE_ARP_ACL Not defined
-#endif
-static void aclParseArpList(SplayNode<acl_arp_data *> **curlist);
-static int decode_eth(const char *asc, char *eth);
-static int aclMatchArp(SplayNode<acl_arp_data *> **dataptr, IpAddress &c);
-static SplayNode<acl_arp_data *>::SPLAYCMP aclArpCompare;
-static SplayNode<acl_arp_data *>::SPLAYWALKEE aclDumpArpListWalkee;
-
+static void aclParseArpList(SplayNode<Eui48 *> **curlist);
+static int aclMatchArp(SplayNode<Eui48 *> **dataptr, IpAddress &c);
+static SplayNode<Eui48 *>::SPLAYCMP aclArpCompare;
+static SplayNode<Eui48 *>::SPLAYWALKEE aclDumpArpListWalkee;
ACL *
ACLARP::~ACLARP()
{
if (data)
- data->destroy(SplayNode<acl_arp_data*>::DefaultFree);
+ data->destroy(SplayNode<Eui48*>::DefaultFree);
}
char const *
* Solaris code by R. Gancarz <radekg@solaris.elektrownia-lagisza.com.pl>
*/
-/**
- * Decode an ascii representation (asc) of an ethernet address.
- *
- * \param asc ASCII representation of an ethernet (MAC) address
- * \param eth Binary representation of the ethernet address
- * \retval 0 Conversion to binary failed. Invalid address
- * \retval 1 Conversion completed successfully
- */
-static int
-decode_eth(const char *asc, char *eth)
-{
- int a1 = 0, a2 = 0, a3 = 0, a4 = 0, a5 = 0, a6 = 0;
-
- if (sscanf(asc, "%x:%x:%x:%x:%x:%x", &a1, &a2, &a3, &a4, &a5, &a6) != 6) {
- debugs(28, 0, "decode_eth: Invalid ethernet address '" << asc << "'");
- return 0; /* This is not valid address */
- }
-
- eth[0] = (u_char) a1;
- eth[1] = (u_char) a2;
- eth[2] = (u_char) a3;
- eth[3] = (u_char) a4;
- eth[4] = (u_char) a5;
- eth[5] = (u_char) a6;
- return 1;
-}
-
-acl_arp_data *
+Eui48 *
aclParseArpData(const char *t)
{
- LOCAL_ARRAY(char, eth, 256);
- acl_arp_data *q = new acl_arp_data;
+ char buf[256];
+ Eui48 *q = new Eui48;
debugs(28, 5, "aclParseArpData: " << t);
- if (sscanf(t, "%[0-9a-fA-F:]", eth) != 1) {
+ if (sscanf(t, "%[0-9a-fA-F:]", buf) != 1) {
debugs(28, 0, "aclParseArpData: Bad ethernet address: '" << t << "'");
safe_free(q);
return NULL;
}
- if (!decode_eth(eth, q->eth)) {
+ if (!q->decode(buf)) {
debugs(28, 0, "" << cfg_filename << " line " << config_lineno << ": " << config_input_line);
- debugs(28, 0, "aclParseArpData: Ignoring invalid ARP acl entry: can't parse '" << eth << "'");
+ debugs(28, 0, "aclParseArpData: Ignoring invalid ARP acl entry: can't parse '" << buf << "'");
safe_free(q);
return NULL;
}
void
ACLARP::parse()
{
- aclParseArpList (&data);
+ aclParseArpList(&data);
}
void
-aclParseArpList(SplayNode<acl_arp_data *> **curlist)
+aclParseArpList(SplayNode<Eui48 *> **curlist)
{
char *t = NULL;
- SplayNode<acl_arp_data *> **Top = curlist;
- acl_arp_data *q = NULL;
+ SplayNode<Eui48*> **Top = curlist;
+ Eui48 *q = NULL;
while ((t = strtokFile())) {
if ((q = aclParseArpData(t)) == NULL)
/* aclMatchArp */
/***************/
int
-aclMatchArp(SplayNode<acl_arp_data *> **dataptr, IpAddress &c)
+aclMatchArp(SplayNode<Eui48 *> **dataptr, IpAddress &c)
{
- struct arpreq arpReq;
-#if !defined(_SQUID_WIN32_)
- struct sockaddr_in *sa = NULL;
-#endif
-
- IpAddress ipAddr = c;
- ipAddr.SetPort(0); // ARP will fail if the port is included in the match.
-
-#if defined(_SQUID_LINUX_)
-
- unsigned char ifbuffer[sizeof(struct ifreq) * 64];
- struct ifconf ifc;
-
- struct ifreq *ifr;
- int offset;
-
- SplayNode<acl_arp_data*> **Top = dataptr;
- /*
- * The linux kernel 2.2 maintains per interface ARP caches and
- * thus requires an interface name when doing ARP queries.
- *
- * The older 2.0 kernels appear to use a unified ARP cache,
- * and require an empty interface name
- *
- * To support both, we attempt the lookup with a blank interface
- * name first. If that does not succeed, the try each interface
- * in turn
- */
+ Eui48 result;
+ SplayNode<Eui48 *> **Top = dataptr;
- /*
- * Set up structures for ARP lookup with blank interface name
- */
- memset(&arpReq, '\0', sizeof(arpReq));
-
- sa = (sockaddr_in*)&arpReq.arp_pa;
- ipAddr.GetSockAddr(*sa);
- /* Query ARP table */
-
- if (ioctl(HttpSockets[0], SIOCGARP, &arpReq) != -1) {
- /* Skip non-ethernet interfaces */
-
- if (arpReq.arp_ha.sa_family != ARPHRD_ETHER) {
- return 0;
- }
-
- debugs(28, 4, "Got address "<< std::setfill('0') << std::hex <<
- std::setw(2) << (arpReq.arp_ha.sa_data[0] & 0xff) << ":" <<
- std::setw(2) << (arpReq.arp_ha.sa_data[1] & 0xff) << ":" <<
- std::setw(2) << (arpReq.arp_ha.sa_data[2] & 0xff) << ":" <<
- std::setw(2) << (arpReq.arp_ha.sa_data[3] & 0xff) << ":" <<
- std::setw(2) << (arpReq.arp_ha.sa_data[4] & 0xff) << ":" <<
- std::setw(2) << (arpReq.arp_ha.sa_data[5] & 0xff));
-
- /* Do lookup */
- acl_arp_data X;
- memcpy (X.eth, arpReq.arp_ha.sa_data, 6);
- *Top = (*Top)->splay(&X, aclArpCompare);
- debugs(28, 3, "aclMatchArp: '" << ipAddr << "' " << (splayLastResult ? "NOT found" : "found"));
+ if (result.lookup(c)) {
+ /* Do ACL match lookup */
+ *Top = (*Top)->splay(&result, aclArpCompare);
+ debugs(28, 3, "aclMatchArp: '" << c << "' " << (splayLastResult ? "NOT found" : "found"));
return (0 == splayLastResult);
}
- /* lookup list of interface names */
- ifc.ifc_len = sizeof(ifbuffer);
-
- ifc.ifc_buf = (char *)ifbuffer;
-
- if (ioctl(HttpSockets[0], SIOCGIFCONF, &ifc) < 0) {
- debugs(28, 1, "Attempt to retrieve interface list failed: " << xstrerror());
- return 0;
- }
-
- if (ifc.ifc_len > (int)sizeof(ifbuffer)) {
- debugs(28, 1, "Interface list too long - " << ifc.ifc_len);
- return 0;
- }
-
- /* Attempt ARP lookup on each interface */
- offset = 0;
-
- while (offset < ifc.ifc_len) {
-
- ifr = (struct ifreq *) (ifbuffer + offset);
- offset += sizeof(*ifr);
- /* Skip loopback and aliased interfaces */
-
- if (0 == strncmp(ifr->ifr_name, "lo", 2))
- continue;
-
- if (NULL != strchr(ifr->ifr_name, ':'))
- continue;
-
- debugs(28, 4, "Looking up ARP address for " << ipAddr << " on " << ifr->ifr_name);
-
- /* Set up structures for ARP lookup */
-
- memset(&arpReq, '\0', sizeof(arpReq));
-
- sa = (sockaddr_in*)&arpReq.arp_pa;
- ipAddr.GetSockAddr(*sa);
-
- strncpy(arpReq.arp_dev, ifr->ifr_name, sizeof(arpReq.arp_dev) - 1);
-
- arpReq.arp_dev[sizeof(arpReq.arp_dev) - 1] = '\0';
-
- /* Query ARP table */
- if (-1 == ioctl(HttpSockets[0], SIOCGARP, &arpReq)) {
- /*
- * Query failed. Do not log failed lookups or "device
- * not supported"
- */
-
- if (ENXIO == errno)
- (void) 0;
- else if (ENODEV == errno)
- (void) 0;
- else
- debugs(28, 1, "ARP query failed: " << ifr->ifr_name << ": " << xstrerror());
-
- continue;
- }
-
- /* Skip non-ethernet interfaces */
- if (arpReq.arp_ha.sa_family != ARPHRD_ETHER)
- continue;
-
- debugs(28, 4, "Got address "<< std::setfill('0') << std::hex <<
- std::setw(2) << (arpReq.arp_ha.sa_data[0] & 0xff) << ":" <<
- std::setw(2) << (arpReq.arp_ha.sa_data[1] & 0xff) << ":" <<
- std::setw(2) << (arpReq.arp_ha.sa_data[2] & 0xff) << ":" <<
- std::setw(2) << (arpReq.arp_ha.sa_data[3] & 0xff) << ":" <<
- std::setw(2) << (arpReq.arp_ha.sa_data[4] & 0xff) << ":" <<
- std::setw(2) << (arpReq.arp_ha.sa_data[5] & 0xff) << " on "<<
- std::setfill(' ') << ifr->ifr_name);
-
- /* Do lookup */
- acl_arp_data X;
-
- memcpy (X.eth, arpReq.arp_ha.sa_data, 6);
-
- *Top = (*Top)->splay(&X, aclArpCompare);
-
- /* Return if match, otherwise continue to other interfaces */
- if (0 == splayLastResult) {
- debugs(28, 3, "aclMatchArp: " << ipAddr << " found on " << ifr->ifr_name);
- return 1;
- }
-
- /*
- * Should we stop looking here? Can the same IP address
- * exist on multiple interfaces?
- */
- }
-
-#elif defined(_SQUID_SOLARIS_)
-
- SplayNode<acl_arp_data *> **Top = dataptr;
-
- /*
- * Set up structures for ARP lookup with blank interface name
- */
-
- memset(&arpReq, '\0', sizeof(arpReq));
-
- sa = (sockaddr_in*)&arpReq.arp_pa;
- ipAddr.GetSockAddr(*sa);
-
- /* Query ARP table */
- if (ioctl(HttpSockets[0], SIOCGARP, &arpReq) != -1) {
- /*
- * Solaris (at least 2.6/x86) does not use arp_ha.sa_family -
- * it returns 00:00:00:00:00:00 for non-ethernet media
- */
-
- if (arpReq.arp_ha.sa_data[0] == 0 &&
- arpReq.arp_ha.sa_data[1] == 0 &&
- arpReq.arp_ha.sa_data[2] == 0 &&
- arpReq.arp_ha.sa_data[3] == 0 &&
- arpReq.arp_ha.sa_data[4] == 0 && arpReq.arp_ha.sa_data[5] == 0)
- return 0;
-
- debugs(28, 4, "Got address "<< std::setfill('0') << std::hex <<
- std::setw(2) << (arpReq.arp_ha.sa_data[0] & 0xff) << ":" <<
- std::setw(2) << (arpReq.arp_ha.sa_data[1] & 0xff) << ":" <<
- std::setw(2) << (arpReq.arp_ha.sa_data[2] & 0xff) << ":" <<
- std::setw(2) << (arpReq.arp_ha.sa_data[3] & 0xff) << ":" <<
- std::setw(2) << (arpReq.arp_ha.sa_data[4] & 0xff) << ":" <<
- std::setw(2) << (arpReq.arp_ha.sa_data[5] & 0xff));
-
- /* Do lookup */
- *Top = (*Top)->splay((acl_arp_data *)&arpReq.arp_ha.sa_data, aclArpCompare);
-
- debugs(28, 3, "aclMatchArp: '" << ipAddr << "' " << (splayLastResult ? "NOT found" : "found"));
-
- return (0 == splayLastResult);
- }
-
-#elif defined(_SQUID_FREEBSD_) || defined(_SQUID_NETBSD_) || defined(_SQUID_OPENBSD_) || defined(_SQUID_DRAGONFLY_) || defined(_SQUID_KFREEBSD_)
-
- SplayNode<acl_arp_data *> **Top = dataptr;
-
- int mib[6];
-
- size_t needed;
-
- char *lim, *buf, *next;
-
- struct rt_msghdr *rtm;
-
- struct sockaddr_inarp *sin;
-
- struct sockaddr_dl *sdl;
-
- /*
- * Set up structures for ARP lookup with blank interface name
- */
-
- memset(&arpReq, '\0', sizeof(arpReq));
-
- sa = (struct sockaddr_in*) &arpReq.arp_pa;
- ipAddr.GetSockAddr(*sa);
-
- /* Query ARP table */
- mib[0] = CTL_NET;
-
- mib[1] = PF_ROUTE;
-
- mib[2] = 0;
-
- mib[3] = AF_INET;
-
- mib[4] = NET_RT_FLAGS;
-
- mib[5] = RTF_LLINFO;
-
- if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
- debugs(28, 0, "Can't estimate ARP table size!");
- return 0;
- }
-
- if ((buf = (char *)xmalloc(needed)) == NULL) {
- debugs(28, 0, "Can't allocate temporary ARP table!");
- return 0;
- }
-
- if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
- debugs(28, 0, "Can't retrieve ARP table!");
- xfree(buf);
- return 0;
- }
-
- lim = buf + needed;
-
- for (next = buf; next < lim; next += rtm->rtm_msglen) {
-
- rtm = (struct rt_msghdr *) next;
-
- sin = (struct sockaddr_inarp *) (rtm + 1);
- /*sdl = (struct sockaddr_dl *) (sin + 1); */
-
-#define ROUNDUP(a) \
- ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
-
- sdl = (struct sockaddr_dl *)((char *) sin + ROUNDUP(sin->sin_len));
-
- if (c == sin->sin_addr) {
- if (sdl->sdl_alen) {
-
- arpReq.arp_ha.sa_len = sizeof(struct sockaddr);
- arpReq.arp_ha.sa_family = AF_UNSPEC;
- memcpy(arpReq.arp_ha.sa_data, LLADDR(sdl), sdl->sdl_alen);
- }
- }
- }
-
- xfree(buf);
-
- if (arpReq.arp_ha.sa_data[0] == 0 && arpReq.arp_ha.sa_data[1] == 0 &&
- arpReq.arp_ha.sa_data[2] == 0 && arpReq.arp_ha.sa_data[3] == 0 &&
- arpReq.arp_ha.sa_data[4] == 0 && arpReq.arp_ha.sa_data[5] == 0)
- return 0;
-
- debugs(28, 4, "Got address "<< std::setfill('0') << std::hex <<
- std::setw(2) << (arpReq.arp_ha.sa_data[0] & 0xff) << ":" <<
- std::setw(2) << (arpReq.arp_ha.sa_data[1] & 0xff) << ":" <<
- std::setw(2) << (arpReq.arp_ha.sa_data[2] & 0xff) << ":" <<
- std::setw(2) << (arpReq.arp_ha.sa_data[3] & 0xff) << ":" <<
- std::setw(2) << (arpReq.arp_ha.sa_data[4] & 0xff) << ":" <<
- std::setw(2) << (arpReq.arp_ha.sa_data[5] & 0xff));
-
- /* Do lookup */
- *Top = (*Top)->splay((acl_arp_data *)&arpReq.arp_ha.sa_data, aclArpCompare);
-
- debugs(28, 3, "aclMatchArp: '" << ipAddr << "' " << (splayLastResult ? "NOT found" : "found"));
-
- return (0 == splayLastResult);
-
-#elif defined(_SQUID_WIN32_)
-
- DWORD dwNetTable = 0;
-
- DWORD ipNetTableLen = 0;
-
- PMIB_IPNETTABLE NetTable = NULL;
-
- DWORD i;
-
- SplayNode<acl_arp_data *> **Top = dataptr;
-
- memset(&arpReq, '\0', sizeof(arpReq));
-
- /* Get size of Windows ARP table */
- if (GetIpNetTable(NetTable, &ipNetTableLen, FALSE) != ERROR_INSUFFICIENT_BUFFER) {
- debugs(28, 0, "Can't estimate ARP table size!");
- return 0;
- }
-
- /* Allocate space for ARP table and assign pointers */
- if ((NetTable = (PMIB_IPNETTABLE)xmalloc(ipNetTableLen)) == NULL) {
- debugs(28, 0, "Can't allocate temporary ARP table!");
- return 0;
- }
-
- /* Get actual ARP table */
- if ((dwNetTable = GetIpNetTable(NetTable, &ipNetTableLen, FALSE)) != NO_ERROR) {
- debugs(28, 0, "Can't retrieve ARP table!");
- xfree(NetTable);
- return 0;
- }
-
- /* Find MAC address from net table */
- for (i = 0 ; i < NetTable->dwNumEntries ; i++) {
- in_addr a;
- a.s_addr = NetTable->table[i].dwAddr;
- if (c == a && (NetTable->table[i].dwType > 2)) {
- arpReq.arp_ha.sa_family = AF_UNSPEC;
- memcpy(arpReq.arp_ha.sa_data, NetTable->table[i].bPhysAddr, NetTable->table[i].dwPhysAddrLen);
- }
- }
-
- xfree(NetTable);
-
- if (arpReq.arp_ha.sa_data[0] == 0 && arpReq.arp_ha.sa_data[1] == 0 &&
- arpReq.arp_ha.sa_data[2] == 0 && arpReq.arp_ha.sa_data[3] == 0 &&
- arpReq.arp_ha.sa_data[4] == 0 && arpReq.arp_ha.sa_data[5] == 0)
- return 0;
-
- debugs(28, 4, "Got address "<< std::setfill('0') << std::hex <<
- std::setw(2) << (arpReq.arp_ha.sa_data[0] & 0xff) << ":" <<
- std::setw(2) << (arpReq.arp_ha.sa_data[1] & 0xff) << ":" <<
- std::setw(2) << (arpReq.arp_ha.sa_data[2] & 0xff) << ":" <<
- std::setw(2) << (arpReq.arp_ha.sa_data[3] & 0xff) << ":" <<
- std::setw(2) << (arpReq.arp_ha.sa_data[4] & 0xff) << ":" <<
- std::setw(2) << (arpReq.arp_ha.sa_data[5] & 0xff));
-
- /* Do lookup */
- *Top = (*Top)->splay((acl_arp_data *)&arpReq.arp_ha.sa_data, aclArpCompare);
-
- debugs(28, 3, "aclMatchArp: '" << ipAddr << "' " << (splayLastResult ? "NOT found" : "found"));
-
- return (0 == splayLastResult);
-
-#else
-
-#error "ARP type ACL not supported on this operating system."
-
-#endif
/*
* Address was not found on any interface
*/
- debugs(28, 3, "aclMatchArp: " << ipAddr << " NOT found");
-
+ debugs(28, 3, "aclMatchArp: " << c << " NOT found");
return 0;
}
static int
-aclArpCompare(acl_arp_data * const &a, acl_arp_data * const &b)
+aclArpCompare(Eui48 * const &a, Eui48 * const &b)
{
- return memcmp(a->eth, b->eth, 6);
+ return memcmp(a, b, sizeof(Eui48));
}
static void
-aclDumpArpListWalkee(acl_arp_data * const &node, void *state)
+aclDumpArpListWalkee(Eui48 * const &node, void *state)
{
- acl_arp_data *arp = node;
- static char buf[24];
- snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x",
- arp->eth[0] & 0xff, arp->eth[1] & 0xff,
- arp->eth[2] & 0xff, arp->eth[3] & 0xff,
- arp->eth[4] & 0xff, arp->eth[5] & 0xff);
+ static char buf[48];
+ node->encode(buf, 48);
wordlistAdd((wordlist **)state, buf);
}
}
/* ==== END ARP ACL SUPPORT =============================================== */
+
+#endif /* USE_SQUID_EUI */
#include "acl/Checklist.h"
#include "splay.h"
-/// \ingroup ACLAPI
-struct acl_arp_data {
- char eth[6];
-};
+class Eui48;
/// \ingroup ACLAPI
class ACLARP : public ACL
protected:
static Prototype RegistryProtoype;
static ACLARP RegistryEntry_;
- SplayNode<acl_arp_data *> *data;
+ SplayNode<Eui48 *> *data;
char const *class_;
};
ARP_ACLS = Arp.cc Arp.h
-if ENABLE_ARP_ACL
+if USE_SQUID_EUI
libacls_la_SOURCES += $(ARP_ACLS)
endif
--- /dev/null
+/*
+ * DEBUG: section ?? EUI Lookup
+ * AUTHOR: Duane Wessels
+ *
+ * SQUID Web Proxy Cache http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ * Squid is the result of efforts by numerous individuals from
+ * the Internet community; see the CONTRIBUTORS file for full
+ * details. Many organizations have provided support for Squid's
+ * development; see the SPONSORS file for full details. Squid is
+ * Copyrighted (C) 2001 by the Regents of the University of
+ * California; see the COPYRIGHT file for full details. Squid
+ * incorporates software developed and/or copyrighted by other
+ * sources; see the CREDITS file for full details.
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ *
+ * Copyright (c) 2003, Robert Collins <robertc@squid-cache.org>
+ */
+
+#include "config.h"
+
+#if USE_SQUID_EUI
+
+#include "Debug.h"
+#include "eui/Eui48.h"
+#include "globals.h"
+#include "ip/IpAddress.h"
+
+
+#if defined(_SQUID_CYGWIN_)
+#include <squid_windows.h>
+#endif
+
+/* START Legacy includes pattern */
+/* TODO: clean this up so we dont have per-OS requirements.
+ The files are checked for existence individually
+ and can be wrapped
+ */
+
+#if defined(_SQUID_WIN32_)
+
+struct arpreq {
+
+ IpAddress arp_pa; /* protocol address */
+
+ struct sockaddr arp_ha; /* hardware address */
+ int arp_flags; /* flags */
+};
+
+#include <Iphlpapi.h>
+#endif
+
+
+#if HAVE_SYS_SOCKIO_H
+/* required by Solaris */
+#include <sys/sockio.h>
+#endif
+#if HAVE_SYS_SYSCTL_H
+#include <sys/sysctl.h>
+#endif
+#if HAVE_NET_ROUTE_H
+#include <net/route.h>
+#endif
+#if HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+#if HAVE_NET_IF_ARP_H
+#include <net/if_arp.h>
+#endif
+#if HAVE_NET_IF_DL_H
+#include <net/if_dl.h>
+#endif
+#if HAVE_NETINET_IF_ETHER_H
+#include <netinet/if_ether.h>
+#endif
+#if HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+/* ==== BEGIN EUI LOOKUP SUPPORT ============================================= */
+
+/*
+ * From: dale@server.ctam.bitmcnit.bryansk.su (Dale)
+ * To: wessels@nlanr.net
+ * Subject: Another Squid patch... :)
+ * Date: Thu, 04 Dec 1997 19:55:01 +0300
+ * ============================================================================
+ *
+ * Working on setting up a proper firewall for a network containing some
+ * Win'95 computers at our Univ, I've discovered that some smart students
+ * avoid the restrictions easily just changing their IP addresses in Win'95
+ * Contol Panel... It has been getting boring, so I took Squid-1.1.18
+ * sources and added a new acl type for hard-wired access control:
+ *
+ * acl <name> arp <Ethernet address> ...
+ *
+ * For example,
+ *
+ * acl students arp 00:00:21:55:ed:22 00:00:21:ff:55:38
+ *
+ * NOTE: Linux code by David Luyer <luyer@ucs.uwa.edu.au>.
+ * Original (BSD-specific) code no longer works.
+ * Solaris code by R. Gancarz <radekg@solaris.elektrownia-lagisza.com.pl>
+ */
+
+bool
+Eui48::decode(const char *asc)
+{
+ int a1 = 0, a2 = 0, a3 = 0, a4 = 0, a5 = 0, a6 = 0;
+
+ if (sscanf(asc, "%x:%x:%x:%x:%x:%x", &a1, &a2, &a3, &a4, &a5, &a6) != 6) {
+ debugs(28, 0, "Decode EUI-48: Invalid ethernet address '" << asc << "'");
+ clear();
+ return false; /* This is not valid address */
+ }
+
+ eui[0] = (u_char) a1;
+ eui[1] = (u_char) a2;
+ eui[2] = (u_char) a3;
+ eui[3] = (u_char) a4;
+ eui[4] = (u_char) a5;
+ eui[5] = (u_char) a6;
+ return true;
+}
+
+bool
+Eui48::encode(char *buf, const int len)
+{
+ if (len < SZ_EUI48_BUF) return false;
+
+ snprintf(buf, len, "%02x:%02x:%02x:%02x:%02x:%02x",
+ eui[0] & 0xff, eui[1] & 0xff,
+ eui[2] & 0xff, eui[3] & 0xff,
+ eui[4] & 0xff, eui[5] & 0xff);
+ return true;
+}
+
+// return binary representation of the EUI
+bool
+Eui48::lookup(IpAddress &c)
+{
+ struct arpreq arpReq;
+#if !defined(_SQUID_WIN32_)
+ struct sockaddr_in *sa = NULL;
+#endif
+
+ IpAddress ipAddr = c;
+ ipAddr.SetPort(0);
+
+#if defined(_SQUID_LINUX_)
+
+ unsigned char ifbuffer[sizeof(struct ifreq) * 64];
+ struct ifconf ifc;
+
+ struct ifreq *ifr;
+ int offset;
+
+ /*
+ * The linux kernel 2.2 maintains per interface ARP caches and
+ * thus requires an interface name when doing ARP queries.
+ *
+ * The older 2.0 kernels appear to use a unified ARP cache,
+ * and require an empty interface name
+ *
+ * To support both, we attempt the lookup with a blank interface
+ * name first. If that does not succeed, the try each interface
+ * in turn
+ */
+
+ /*
+ * Set up structures for ARP lookup with blank interface name
+ */
+ memset(&arpReq, '\0', sizeof(arpReq));
+
+ sa = (sockaddr_in*)&arpReq.arp_pa;
+ ipAddr.GetSockAddr(*sa);
+
+ /* Query ARP table */
+ if (ioctl(HttpSockets[0], SIOCGARP, &arpReq) != -1) {
+ /* Skip non-ethernet interfaces */
+
+ if (arpReq.arp_ha.sa_family != ARPHRD_ETHER) {
+ clear();
+ return false;
+ }
+
+ debugs(28, 4, "Got address "<< std::setfill('0') << std::hex <<
+ std::setw(2) << (arpReq.arp_ha.sa_data[0] & 0xff) << ":" <<
+ std::setw(2) << (arpReq.arp_ha.sa_data[1] & 0xff) << ":" <<
+ std::setw(2) << (arpReq.arp_ha.sa_data[2] & 0xff) << ":" <<
+ std::setw(2) << (arpReq.arp_ha.sa_data[3] & 0xff) << ":" <<
+ std::setw(2) << (arpReq.arp_ha.sa_data[4] & 0xff) << ":" <<
+ std::setw(2) << (arpReq.arp_ha.sa_data[5] & 0xff));
+
+ set(arpReq.arp_ha.sa_data, 6);
+ return true;
+ }
+
+ /* lookup list of interface names */
+ ifc.ifc_len = sizeof(ifbuffer);
+
+ ifc.ifc_buf = (char *)ifbuffer;
+
+ if (ioctl(HttpSockets[0], SIOCGIFCONF, &ifc) < 0) {
+ debugs(28, 1, "Attempt to retrieve interface list failed: " << xstrerror());
+ clear();
+ return false;
+ }
+
+ if (ifc.ifc_len > (int)sizeof(ifbuffer)) {
+ debugs(28, 1, "Interface list too long - " << ifc.ifc_len);
+ clear();
+ return false;
+ }
+
+ /* Attempt ARP lookup on each interface */
+ offset = 0;
+
+ while (offset < ifc.ifc_len) {
+
+ ifr = (struct ifreq *) (ifbuffer + offset);
+ offset += sizeof(*ifr);
+ /* Skip loopback and aliased interfaces */
+
+ if (0 == strncmp(ifr->ifr_name, "lo", 2))
+ continue;
+
+ if (NULL != strchr(ifr->ifr_name, ':'))
+ continue;
+
+ debugs(28, 4, "Looking up ARP address for " << ipAddr << " on " << ifr->ifr_name);
+
+ /* Set up structures for ARP lookup */
+
+ memset(&arpReq, '\0', sizeof(arpReq));
+
+ sa = (sockaddr_in*)&arpReq.arp_pa;
+ ipAddr.GetSockAddr(*sa);
+
+ strncpy(arpReq.arp_dev, ifr->ifr_name, sizeof(arpReq.arp_dev) - 1);
+
+ arpReq.arp_dev[sizeof(arpReq.arp_dev) - 1] = '\0';
+
+ /* Query ARP table */
+ if (-1 == ioctl(HttpSockets[0], SIOCGARP, &arpReq)) {
+ /*
+ * Query failed. Do not log failed lookups or "device
+ * not supported"
+ */
+
+ if (ENXIO == errno)
+ (void) 0;
+ else if (ENODEV == errno)
+ (void) 0;
+ else
+ debugs(28, 1, "ARP query failed: " << ifr->ifr_name << ": " << xstrerror());
+
+ continue;
+ }
+
+ /* Skip non-ethernet interfaces */
+ if (arpReq.arp_ha.sa_family != ARPHRD_ETHER)
+ continue;
+
+ debugs(28, 4, "Got address "<< std::setfill('0') << std::hex <<
+ std::setw(2) << (arpReq.arp_ha.sa_data[0] & 0xff) << ":" <<
+ std::setw(2) << (arpReq.arp_ha.sa_data[1] & 0xff) << ":" <<
+ std::setw(2) << (arpReq.arp_ha.sa_data[2] & 0xff) << ":" <<
+ std::setw(2) << (arpReq.arp_ha.sa_data[3] & 0xff) << ":" <<
+ std::setw(2) << (arpReq.arp_ha.sa_data[4] & 0xff) << ":" <<
+ std::setw(2) << (arpReq.arp_ha.sa_data[5] & 0xff) << " on "<<
+ std::setfill(' ') << ifr->ifr_name);
+
+ set(arpReq.arp_ha.sa_data, 6);
+
+ /*
+ * Should we stop looking here? Can the same IP address
+ * exist on multiple interfaces?
+ */
+
+ /* AYJ: 2009-10-06: for now we have to. We can only store one EUI at a time. */
+ return true;
+ }
+
+#elif defined(_SQUID_SOLARIS_)
+
+ /* Set up structures for ARP lookup with blank interface name */
+
+ memset(&arpReq, '\0', sizeof(arpReq));
+
+ sa = (sockaddr_in*)&arpReq.arp_pa;
+ ipAddr.GetSockAddr(*sa);
+
+ /* Query ARP table */
+ if (ioctl(HttpSockets[0], SIOCGARP, &arpReq) != -1) {
+ /*
+ * Solaris (at least 2.6/x86) does not use arp_ha.sa_family -
+ * it returns 00:00:00:00:00:00 for non-ethernet media
+ */
+
+ if (arpReq.arp_ha.sa_data[0] == 0 &&
+ arpReq.arp_ha.sa_data[1] == 0 &&
+ arpReq.arp_ha.sa_data[2] == 0 &&
+ arpReq.arp_ha.sa_data[3] == 0 &&
+ arpReq.arp_ha.sa_data[4] == 0 && arpReq.arp_ha.sa_data[5] == 0) {
+ clear();
+ return false;
+ }
+
+ debugs(28, 4, "Got address "<< std::setfill('0') << std::hex <<
+ std::setw(2) << (arpReq.arp_ha.sa_data[0] & 0xff) << ":" <<
+ std::setw(2) << (arpReq.arp_ha.sa_data[1] & 0xff) << ":" <<
+ std::setw(2) << (arpReq.arp_ha.sa_data[2] & 0xff) << ":" <<
+ std::setw(2) << (arpReq.arp_ha.sa_data[3] & 0xff) << ":" <<
+ std::setw(2) << (arpReq.arp_ha.sa_data[4] & 0xff) << ":" <<
+ std::setw(2) << (arpReq.arp_ha.sa_data[5] & 0xff));
+
+ set(arpReq.arp_ha.sa_data, 6);
+ return true;
+ }
+
+#elif defined(_SQUID_FREEBSD_) || defined(_SQUID_NETBSD_) || defined(_SQUID_OPENBSD_) || defined(_SQUID_DRAGONFLY_) || defined(_SQUID_KFREEBSD_)
+
+ int mib[6];
+
+ size_t needed;
+
+ char *lim, *buf, *next;
+
+ struct rt_msghdr *rtm;
+
+ struct sockaddr_inarp *sin;
+
+ struct sockaddr_dl *sdl;
+
+ /*
+ * Set up structures for ARP lookup with blank interface name
+ */
+
+ memset(&arpReq, '\0', sizeof(arpReq));
+
+ sa = (struct sockaddr_in*) &arpReq.arp_pa;
+ ipAddr.GetSockAddr(*sa);
+
+ /* Query ARP table */
+ mib[0] = CTL_NET;
+
+ mib[1] = PF_ROUTE;
+
+ mib[2] = 0;
+
+ mib[3] = AF_INET;
+
+ mib[4] = NET_RT_FLAGS;
+
+ mib[5] = RTF_LLINFO;
+
+ if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
+ debugs(28, 0, "Can't estimate ARP table size!");
+ clear();
+ return false;
+ }
+
+ if ((buf = (char *)xmalloc(needed)) == NULL) {
+ debugs(28, 0, "Can't allocate temporary ARP table!");
+ clear();
+ return false;
+ }
+
+ if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
+ debugs(28, 0, "Can't retrieve ARP table!");
+ xfree(buf);
+ clear();
+ return false;
+ }
+
+ lim = buf + needed;
+
+ for (next = buf; next < lim; next += rtm->rtm_msglen) {
+
+ rtm = (struct rt_msghdr *) next;
+
+ sin = (struct sockaddr_inarp *) (rtm + 1);
+ /*sdl = (struct sockaddr_dl *) (sin + 1); */
+
+#define ROUNDUP(a) \
+ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
+
+ sdl = (struct sockaddr_dl *)((char *) sin + ROUNDUP(sin->sin_len));
+
+ if (ipAddr == sin->sin_addr) {
+ if (sdl->sdl_alen) {
+
+ arpReq.arp_ha.sa_len = sizeof(struct sockaddr);
+ arpReq.arp_ha.sa_family = AF_UNSPEC;
+ memcpy(arpReq.arp_ha.sa_data, LLADDR(sdl), sdl->sdl_alen);
+ }
+ }
+ }
+
+ xfree(buf);
+
+ if (arpReq.arp_ha.sa_data[0] == 0 && arpReq.arp_ha.sa_data[1] == 0 &&
+ arpReq.arp_ha.sa_data[2] == 0 && arpReq.arp_ha.sa_data[3] == 0 &&
+ arpReq.arp_ha.sa_data[4] == 0 && arpReq.arp_ha.sa_data[5] == 0) {
+ clear();
+ return false;
+ }
+
+ debugs(28, 4, "Got address "<< std::setfill('0') << std::hex <<
+ std::setw(2) << (arpReq.arp_ha.sa_data[0] & 0xff) << ":" <<
+ std::setw(2) << (arpReq.arp_ha.sa_data[1] & 0xff) << ":" <<
+ std::setw(2) << (arpReq.arp_ha.sa_data[2] & 0xff) << ":" <<
+ std::setw(2) << (arpReq.arp_ha.sa_data[3] & 0xff) << ":" <<
+ std::setw(2) << (arpReq.arp_ha.sa_data[4] & 0xff) << ":" <<
+ std::setw(2) << (arpReq.arp_ha.sa_data[5] & 0xff));
+
+ set(arpReq.arp_ha.sa_data, 6);
+ return true;
+
+#elif defined(_SQUID_WIN32_)
+
+ DWORD dwNetTable = 0;
+
+ DWORD ipNetTableLen = 0;
+
+ PMIB_IPNETTABLE NetTable = NULL;
+
+ DWORD i;
+
+ memset(&arpReq, '\0', sizeof(arpReq));
+
+ /* Get size of Windows ARP table */
+ if (GetIpNetTable(NetTable, &ipNetTableLen, FALSE) != ERROR_INSUFFICIENT_BUFFER) {
+ debugs(28, 0, "Can't estimate ARP table size!");
+ clear();
+ return false;
+ }
+
+ /* Allocate space for ARP table and assign pointers */
+ if ((NetTable = (PMIB_IPNETTABLE)xmalloc(ipNetTableLen)) == NULL) {
+ debugs(28, 0, "Can't allocate temporary ARP table!");
+ clear();
+ return false;
+ }
+
+ /* Get actual ARP table */
+ if ((dwNetTable = GetIpNetTable(NetTable, &ipNetTableLen, FALSE)) != NO_ERROR) {
+ debugs(28, 0, "Can't retrieve ARP table!");
+ xfree(NetTable);
+ clear();
+ return false;
+ }
+
+ /* Find MAC address from net table */
+ for (i = 0 ; i < NetTable->dwNumEntries ; i++) {
+ in_addr a;
+ a.s_addr = NetTable->table[i].dwAddr;
+ if (c == a && (NetTable->table[i].dwType > 2)) {
+ arpReq.arp_ha.sa_family = AF_UNSPEC;
+ memcpy(arpReq.arp_ha.sa_data, NetTable->table[i].bPhysAddr, NetTable->table[i].dwPhysAddrLen);
+ }
+ }
+
+ xfree(NetTable);
+
+ if (arpReq.arp_ha.sa_data[0] == 0 && arpReq.arp_ha.sa_data[1] == 0 &&
+ arpReq.arp_ha.sa_data[2] == 0 && arpReq.arp_ha.sa_data[3] == 0 &&
+ arpReq.arp_ha.sa_data[4] == 0 && arpReq.arp_ha.sa_data[5] == 0) {
+ clear();
+ return false;
+ }
+
+ debugs(28, 4, "Got address "<< std::setfill('0') << std::hex <<
+ std::setw(2) << (arpReq.arp_ha.sa_data[0] & 0xff) << ":" <<
+ std::setw(2) << (arpReq.arp_ha.sa_data[1] & 0xff) << ":" <<
+ std::setw(2) << (arpReq.arp_ha.sa_data[2] & 0xff) << ":" <<
+ std::setw(2) << (arpReq.arp_ha.sa_data[3] & 0xff) << ":" <<
+ std::setw(2) << (arpReq.arp_ha.sa_data[4] & 0xff) << ":" <<
+ std::setw(2) << (arpReq.arp_ha.sa_data[5] & 0xff));
+
+ set(arpReq.arp_ha.sa_data, 6);
+ return true;
+
+#else
+
+ debugs(28, 0, "ERROR: ARP / MAC / EUI-* operations not supported on this operating system.");
+
+#endif
+ /*
+ * Address was not found on any interface
+ */
+ debugs(28, 3, HERE << ipAddr << " NOT found");
+
+ clear();
+ return false;
+}
+
+/* ==== END EUI LOOKUP SUPPORT =============================================== */
+
+#endif /* USE_SQUID_EUI */
--- /dev/null
+#ifndef _SQUID_EUI_EUI48_H
+#define _SQUID_EUI_EUI48_H
+
+#include "config.h"
+
+#if USE_SQUID_EUI
+
+/* EUI-48 is 6 bytes. */
+#define SZ_EUI48_BUF 6
+
+class IpAddress;
+
+#if HAVE_CSTRING
+#include <cstring>
+#endif
+
+class Eui48 {
+
+public:
+ Eui48() { clear(); };
+ Eui48(const Eui48 &t) { memcpy(this, &t, sizeof(Eui48)); };
+ ~Eui48() {};
+
+ const unsigned char *get(void);
+
+ bool set(const char *src, const int len) {
+ if (len > SZ_EUI48_BUF) return false;
+ if (len < SZ_EUI48_BUF) clear();
+ memcpy(eui, src, len);
+ return true;
+ };
+
+ void clear() { memset(eui, NULL, SZ_EUI48_BUF); };
+
+ /**
+ * Decode an ascii representation of an EUI-48 ethernet address.
+ *
+ * \param asc ASCII representation of an ethernet (MAC) address
+ * \param eth Binary representation of the ethernet address
+ * \retval false Conversion to binary failed. Invalid address
+ * \retval true Conversion completed successfully
+ */
+ bool decode(const char *asc);
+
+ /**
+ * Encode an ascii representation (asc) of an EUI-48 ethernet address.
+ *
+ * \param buf Buffer to receive ASCII representation of an ethernet (MAC) address
+ * \param len Length of the buffer space available. Must be >= SZ_EUI48_BUF bytes or the encode will fail.
+ * \param eui Binary representation of the ethernet address
+ * \retval false Conversion to ASCII failed.
+ * \retval true Conversion completed successfully.
+ */
+ bool encode(char *buf, const int len);
+
+ // lookup an EUI-48 / MAC address via ARP
+ bool lookup(IpAddress &c);
+
+private:
+ unsigned char eui[SZ_EUI48_BUF];
+};
+
+#endif /* USE_SQUID_EUI */
+#endif /* _SQUID_EUI_EUI48_H */
--- /dev/null
+include $(top_srcdir)/src/Common.am
+include $(top_srcdir)/src/TestHeaders.am
+
+noinst_LTLIBRARIES = libeui.la
+
+libeui_la_SOURCES = \
+ Eui48.h \
+ Eui48.cc
+
+libeui_la_LIBADD = @EUILIB@
--enable-kill-parent-hack \
--enable-snmp \
--enable-cachemgr-hostname \
- --enable-arp-acl \
+ --enable-eui \
--enable-htcp \
--enable-ssl \
--enable-forw-via-db \
# Fix the distclean testing.
export DISTCHECK_CONFIGURE_FLAGS="${OPTS}"
-
-