]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
SourceLayout: pull ARP operations into libeui
authorAmos Jeffries <squid3@treenet.co.nz>
Thu, 15 Oct 2009 10:12:38 +0000 (23:12 +1300)
committerAmos Jeffries <squid3@treenet.co.nz>
Thu, 15 Oct 2009 10:12:38 +0000 (23:12 +1300)
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.

configure.in
doc/release-notes/release-3.2.sgml
src/Makefile.am
src/acl/Arp.cc
src/acl/Arp.h
src/acl/Makefile.am
src/eui/Eui48.cc [new file with mode: 0644]
src/eui/Eui48.h [new file with mode: 0644]
src/eui/Makefile.am [new file with mode: 0644]
test-suite/buildtests/layer-02-maximus.opts

index 655dfaf3ad1fa98b1343d7ad88ef27a92aa29478..5c8171efa959e5604eb31a0002fccf8699d1861d 100644 (file)
@@ -1075,11 +1075,11 @@ AC_ARG_ENABLE(cachemgr-hostname,
    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-*)
            ;;
@@ -1092,18 +1092,29 @@ AC_ARG_ENABLE(arp-acl,
        *-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
 ])
 
@@ -4099,6 +4110,7 @@ AC_CONFIG_FILES([\
        src/adaptation/icap/Makefile \
        src/adaptation/ecap/Makefile \
        src/esi/Makefile \
+       src/eui/Makefile \
        src/icmp/Makefile \
        src/ident/Makefile \
        src/ip/Makefile \
index f6b81967e326a56b14804d0644c339349fb81eb7..dcc71782c2cc90b704db6bf5d0f0f40c6ad11e0c 100644 (file)
@@ -350,6 +350,10 @@ This section gives an account of those changes in three categories:
 <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.
@@ -370,8 +374,8 @@ This section gives an account of those changes in three categories:
 <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>
 
index 0840610fd6787664a0a28cb418ce7f95c83f5177..96195df96ddb24fd37b4c625e7c43d4bf06ff52e 100644 (file)
@@ -34,7 +34,7 @@ LOADABLE_MODULES_SOURCES = \
        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
@@ -161,6 +161,7 @@ COMMON_LIBS = \
        auth/libacls.la \
        ident/libident.la \
        acl/libacls.la \
+       eui/libeui.la \
        acl/libstate.la \
        auth/libauth.la \
        acl/libapi.la \
index 49eaade5c39b576617ae0bc2d0136ed7157482d3..8827d6186440c4849af391c1abbf3505a4a51298 100644 (file)
  * 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 *
@@ -106,7 +66,7 @@ ACLARP::ACLARP (ACLARP const & old) : data (NULL), class_ (old.class_)
 ACLARP::~ACLARP()
 {
     if (data)
-        data->destroy(SplayNode<acl_arp_data*>::DefaultFree);
+        data->destroy(SplayNode<Eui48*>::DefaultFree);
 }
 
 char const *
@@ -147,49 +107,22 @@ ACLARP::empty () 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;
     }
@@ -204,15 +137,15 @@ aclParseArpData(const char *t)
 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)
@@ -240,397 +173,36 @@ ACLARP::match(ACLChecklist *cl)
 /* 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);
 }
 
@@ -643,3 +215,5 @@ ACLARP::dump() const
 }
 
 /* ==== END ARP ACL SUPPORT =============================================== */
+
+#endif /* USE_SQUID_EUI */
index 962c5a360352c66bb30594982cab5ea49c214371..a676a37b9318b97c7b38ec5fff8c2ccf3ed25777 100644 (file)
 #include "acl/Checklist.h"
 #include "splay.h"
 
-/// \ingroup ACLAPI
-struct acl_arp_data {
-    char eth[6];
-};
+class Eui48;
 
 /// \ingroup ACLAPI
 class ACLARP : public ACL
@@ -66,7 +63,7 @@ public:
 protected:
     static Prototype RegistryProtoype;
     static ACLARP RegistryEntry_;
-    SplayNode<acl_arp_data *> *data;
+    SplayNode<Eui48 *> *data;
     char const *class_;
 };
 
index f1aa28869737b1b754290b3912de5e0bca6003e9..46658cb72f5da3c7954a24fe28e33d2687c89723 100644 (file)
@@ -130,7 +130,7 @@ EXTRA_libacls_la_SOURCES += $(SSL_ACLS)
 
 ARP_ACLS = Arp.cc Arp.h
 
-if ENABLE_ARP_ACL
+if USE_SQUID_EUI
 libacls_la_SOURCES += $(ARP_ACLS)
 endif
 
diff --git a/src/eui/Eui48.cc b/src/eui/Eui48.cc
new file mode 100644 (file)
index 0000000..3c2777f
--- /dev/null
@@ -0,0 +1,516 @@
+/*
+ * 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 */
diff --git a/src/eui/Eui48.h b/src/eui/Eui48.h
new file mode 100644 (file)
index 0000000..09cf2d4
--- /dev/null
@@ -0,0 +1,64 @@
+#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 */
diff --git a/src/eui/Makefile.am b/src/eui/Makefile.am
new file mode 100644 (file)
index 0000000..2d3fd07
--- /dev/null
@@ -0,0 +1,10 @@
+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@
index 61667b9ba154b78de6ce7287d88fedea3c4977bd..2fc580582128fb6a8aca77d7ddc5ddb9fe3f790d 100644 (file)
@@ -60,7 +60,7 @@ OPTS=" \
        --enable-kill-parent-hack \
        --enable-snmp \
        --enable-cachemgr-hostname \
-       --enable-arp-acl \
+       --enable-eui \
        --enable-htcp \
        --enable-ssl \
        --enable-forw-via-db \
@@ -112,5 +112,3 @@ OPTS=" \
 
 # Fix the distclean testing.
 export DISTCHECK_CONFIGURE_FLAGS="${OPTS}"
-
-