--------------------- PatchSet 2105 Date: 2001/04/27 08:30:04 Author: rbcollins Branch: generic_modules Tag: (none) Log: arp acls as a module Members: src/modules/acl_arp/Makefile.in:1.1->1.1.2.1 src/modules/acl_arp/acl_arp.c:1.1->1.1.2.1 --- /dev/null Wed Feb 14 00:51:37 2007 +++ squid/src/modules/acl_arp/Makefile.in Wed Feb 14 00:52:45 2007 @@ -0,0 +1,70 @@ +# +# Makefile for the ntlm authentication scheme module for the Squid Object Cache server +# +# $Id$ +# + +MODULE = acl_arp + +#SUBDIRS = helpers + +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ + +CC = @CC@ +MAKEDEPEND = @MAKEDEPEND@ +AR_R = @AR_R@ +RANLIB = @RANLIB@ +AC_CFLAGS = @CFLAGS@ +SHELL = /bin/sh + +INCLUDE = -I../../../include -I$(top_srcdir)/include -I$(top_srcdir)/src/ +CFLAGS = $(AC_CFLAGS) $(INCLUDE) $(DEFINES) + +OUT = ../$(MODULE).a + +OBJS = \ + acl_arp.o + + +all install: $(OUT) + @for dir in $(SUBDIRS); do \ + if [ -f $$dir/Makefile ]; then \ + sh -c "cd $$dir && $(MAKE) $@" || exit 1; \ + fi; \ + done; + +$(OUT): $(OBJS) + @rm -f ../stamp + $(AR_R) $(OUT) $(OBJS) + $(RANLIB) $(OUT) + +$(OBJS): $(top_srcdir)/include/version.h ../../../include/autoconf.h + +.c.o: + @rm -f ../stamp + $(CC) $(CFLAGS) -c $< + +clean: + -rm -rf *.o *pure_* core ../$(MODULE).a + -for dir in *; do \ + if [ -f $$dir/Makefile ]; then \ + sh -c "cd $$dir && $(MAKE) clean"; \ + fi; \ + done + +distclean: clean + -rm -f Makefile + -rm -f Makefile.bak + -rm -f tags + -for dir in *; do \ + if [ -f $$dir/Makefile ]; then \ + sh -c "cd $$dir && $(MAKE) distclean"; \ + fi; \ + done + +tags: + ctags *.[ch] $(top_srcdir)/src/*.[ch] $(top_srcdir)/include/*.h $(top_srcdir)/lib/*.[ch] + +depend: + $(MAKEDEPEND) $(INCLUDE) -fMakefile *.c --- /dev/null Wed Feb 14 00:51:37 2007 +++ squid/src/modules/acl_arp/acl_arp.c Wed Feb 14 00:52:45 2007 @@ -0,0 +1,487 @@ + +/* + * $Id$ + * + * DEBUG: section 28 ACL + * AUTHOR: Several + * + * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from the + * Internet community. Development is led by Duane Wessels of the + * National Laboratory for Applied Network Research and funded by the + * National Science Foundation. Squid is Copyrighted (C) 1998 by + * the Regents of the University of California. Please see the + * COPYRIGHT file for full details. Squid incorporates software + * developed and/or copyrighted by other sources. Please 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. + * + */ + +#include "squid.h" +#include "squid_parser.h" +#include "acl.h" + +struct _acl_arp_data { + char eth[6]; +}; + + +static PARSER_PARSE aclParseArpList; +static PARSER_FREE aclDestroyArpList; +static PARSER_DUMP dump_ArpList; +static ACLMATCH aclMatchSrcArp; +static int decode_eth(const char *asc, char *eth); +static int aclMatchArp(void *dataptr, struct in_addr c); +static wordlist *aclDumpArpList(void *); +static SPLAYCMP aclArpCompare; +static SPLAYWALKEE aclDumpArpListWalkee; + +/* register as a module */ +void +mod_install_acl_arp (const char *namestr) +{ + parserRegisterType("arplist", aclParseArpList, aclDestroyArpList, dump_ArpList); + aclRegisterAclName("arp", parserTypeByName("arplist"), aclMatchSrcArp); + /* Register global configuration parameters */ +} + +/* deregister as a module */ +void +mod_uninstall_acl_arp(const char *namestr) { + /* Deregister global configurationparameters */ +//FIXME: aclDeregisterAclName("arp"); +//FIXME: parserDeregisterName("arplist"); + +} + + +/* ==== BEGIN ARP ACL 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 arp ... + * + * For example, + * + * acl students arp 00:00:21:55:ed:22 00:00:21:ff:55:38 + * + * NOTE: Linux code by David Luyer . + * Original (BSD-specific) code no longer works. + * Solaris code by R. Gancarz + */ + +#ifdef _SQUID_SOLARIS_ +#include +#else +#include +#endif +#ifdef _SQUID_LINUX_ +#include +#include +#else +#include +#endif +#include +#include +#if HAVE_NETINET_IF_ETHER_H +#include +#endif + +/* + * Decode an ascii representation (asc) of an ethernet adress, and place + * it in eth[6]. + */ +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) { + debug(28, 0) ("decode_eth: Invalid ethernet address '%s'\n", 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; +} + +static acl_arp_data * +aclParseArpData(const char *t) +{ + LOCAL_ARRAY(char, eth, 256); + acl_arp_data *q = xcalloc(1, sizeof(acl_arp_data)); + debug(28, 5) ("aclParseArpData: %s\n", t); + if (sscanf(t, "%[0-9a-fA-F:]", eth) != 1) { + debug(28, 0) ("aclParseArpData: Bad ethernet address: '%s'\n", t); + safe_free(q); + return NULL; + } + if (!decode_eth(eth, q->eth)) { + debug(28, 0) ("%s line %d: %s\n", + cfg_filename, config_lineno, config_input_line); + debug(28, 0) ("aclParseArpData: Ignoring invalid ARP acl entry: can't parse '%s'\n", eth); + safe_free(q); + return NULL; + } + return q; +} + + +/*******************/ +/* aclParseArpList */ +/*******************/ +static void +aclParseArpList(parserNameNode *parserName, void *curlist) +{ + char *t = NULL; + splayNode **Top = curlist; + acl_arp_data *q = NULL; + while ((t = strtokFile())) { + if ((q = aclParseArpData(t)) == NULL) + continue; + *Top = splay_insert(q, *Top, aclArpCompare); + } +} + +/***************/ +/* aclMatchArp */ +/***************/ +static int +aclMatchArp(void *dataptr, struct in_addr c) +{ +#if defined(_SQUID_LINUX_) + struct arpreq arpReq; + struct sockaddr_in ipAddr; + unsigned char ifbuffer[sizeof(struct ifreq) * 64]; + struct ifconf ifc; + struct ifreq *ifr; + int offset; + splayNode **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 + */ + /* + * Set up structures for ARP lookup with blank interface name + */ + ipAddr.sin_family = AF_INET; + ipAddr.sin_port = 0; + ipAddr.sin_addr = c; + memset(&arpReq, '\0', sizeof(arpReq)); + xmemcpy(&arpReq.arp_pa, &ipAddr, sizeof(struct sockaddr_in)); + /* Query ARP table */ + if (ioctl(HttpSockets[0], SIOCGARP, &arpReq) != -1) { + /* Skip non-ethernet interfaces */ + if (arpReq.arp_ha.sa_family != ARPHRD_ETHER) { + return 0; + } + debug(28, 4) ("Got address %02x:%02x:%02x:%02x:%02x:%02x\n", + arpReq.arp_ha.sa_data[0] & 0xff, arpReq.arp_ha.sa_data[1] & 0xff, + arpReq.arp_ha.sa_data[2] & 0xff, arpReq.arp_ha.sa_data[3] & 0xff, + arpReq.arp_ha.sa_data[4] & 0xff, arpReq.arp_ha.sa_data[5] & 0xff); + /* Do lookup */ + *Top = splay_splay(&arpReq.arp_ha.sa_data, *Top, aclArpCompare); + debug(28, 3) ("aclMatchArp: '%s' %s\n", + inet_ntoa(c), splayLastResult ? "NOT found" : "found"); + return (0 == splayLastResult); + } + /* lookup list of interface names */ + ifc.ifc_len = sizeof(ifbuffer); + ifc.ifc_buf = ifbuffer; + if (ioctl(HttpSockets[0], SIOCGIFCONF, &ifc) < 0) { + debug(28, 1) ("Attempt to retrieve interface list failed: %s\n", + xstrerror()); + return 0; + } + if (ifc.ifc_len > sizeof(ifbuffer)) { + debug(28, 1) ("Interface list too long - %d\n", 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; + debug(28, 4) ("Looking up ARP address for %s on %s\n", inet_ntoa(c), + ifr->ifr_name); + /* Set up structures for ARP lookup */ + ipAddr.sin_family = AF_INET; + ipAddr.sin_port = 0; + ipAddr.sin_addr = c; + memset(&arpReq, '\0', sizeof(arpReq)); + xmemcpy(&arpReq.arp_pa, &ipAddr, sizeof(struct sockaddr_in)); + 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 + debug(28, 1) ("ARP query failed: %s: %s\n", + ifr->ifr_name, xstrerror()); + continue; + } + /* Skip non-ethernet interfaces */ + if (arpReq.arp_ha.sa_family != ARPHRD_ETHER) + continue; + debug(28, 4) ("Got address %02x:%02x:%02x:%02x:%02x:%02x on %s\n", + arpReq.arp_ha.sa_data[0] & 0xff, + arpReq.arp_ha.sa_data[1] & 0xff, + arpReq.arp_ha.sa_data[2] & 0xff, + arpReq.arp_ha.sa_data[3] & 0xff, + arpReq.arp_ha.sa_data[4] & 0xff, + arpReq.arp_ha.sa_data[5] & 0xff, ifr->ifr_name); + /* Do lookup */ + *Top = splay_splay(&arpReq.arp_ha.sa_data, *Top, aclArpCompare); + /* Return if match, otherwise continue to other interfaces */ + if (0 == splayLastResult) { + debug(28, 3) ("aclMatchArp: %s found on %s\n", + inet_ntoa(c), ifr->ifr_name); + return 1; + } + /* + * Should we stop looking here? Can the same IP address + * exist on multiple interfaces? + */ + } +#elif defined(_SQUID_SOLARIS_) + struct arpreq arpReq; + struct sockaddr_in ipAddr; + unsigned char ifbuffer[sizeof(struct ifreq) * 64]; + struct ifconf ifc; + struct ifreq *ifr; + int offset; + splayNode **Top = dataptr; + /* + * Set up structures for ARP lookup with blank interface name + */ + ipAddr.sin_family = AF_INET; + ipAddr.sin_port = 0; + ipAddr.sin_addr = c; + memset(&arpReq, '\0', sizeof(arpReq)); + xmemcpy(&arpReq.arp_pa, &ipAddr, sizeof(struct sockaddr_in)); + /* 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; + debug(28, 4) ("Got address %02x:%02x:%02x:%02x:%02x:%02x\n", + arpReq.arp_ha.sa_data[0] & 0xff, arpReq.arp_ha.sa_data[1] & 0xff, + arpReq.arp_ha.sa_data[2] & 0xff, arpReq.arp_ha.sa_data[3] & 0xff, + arpReq.arp_ha.sa_data[4] & 0xff, arpReq.arp_ha.sa_data[5] & 0xff); + /* Do lookup */ + *Top = splay_splay(&arpReq.arp_ha.sa_data, *Top, aclArpCompare); + debug(28, 3) ("aclMatchArp: '%s' %s\n", + inet_ntoa(c), splayLastResult ? "NOT found" : "found"); + return (0 == splayLastResult); + } +#else + WRITE ME; +#endif + /* + * Address was not found on any interface + */ + debug(28, 3) ("aclMatchArp: %s NOT found\n", inet_ntoa(c)); + return 0; +} + +static int +aclMatchSrcArp(void **dataptr, aclCheck_t *checklist) +{ + return aclMatchArp(dataptr, checklist->src_addr); +} + + +static void +aclDestroyArpList(parserNameNode *parserName, void * data) +{ + acl ** head=(acl **)data; + acl *a=*head; + if (a) + splay_destroy(a->data, xfree); +} + +static void +dump_ArpList(StoreEntry * entry, const char *name, void const * const data) +{ + acl * ae=*(acl * *)data; + wordlist *w; + wordlist *v; + while (ae != NULL) { + debug(3, 3) ("dump_ArpList: %s %s\n", name, ae->name); + v = w = aclDumpArpList(ae->data); + while (v != NULL) { + debug(3, 3) ("dump_ArpList: %s %s %s\n", name, ae->name, v->key); + storeAppendPrintf(entry, "%s %s %s %s\n", + name, + ae->name, + aclTypeToStr(ae->type), + v->key); + v = v->next; + } + wordlistDestroy(&w); + ae = ae->next; + } +} + +static int +aclArpCompare(const void *a, const void *b) +{ +#if defined(_SQUID_LINUX_) + const unsigned short *d1 = a; + const unsigned short *d2 = b; + if (d1[0] != d2[0]) + return (d1[0] > d2[0]) ? 1 : -1; + if (d1[1] != d2[1]) + return (d1[1] > d2[1]) ? 1 : -1; + if (d1[2] != d2[2]) + return (d1[2] > d2[2]) ? 1 : -1; +#elif defined(_SQUID_SOLARIS_) + const unsigned char *d1 = a; + const unsigned char *d2 = b; + if (d1[0] != d2[0]) + return (d1[0] > d2[0]) ? 1 : -1; + if (d1[1] != d2[1]) + return (d1[1] > d2[1]) ? 1 : -1; + if (d1[2] != d2[2]) + return (d1[2] > d2[2]) ? 1 : -1; + if (d1[3] != d2[3]) + return (d1[3] > d2[3]) ? 1 : -1; + if (d1[4] != d2[4]) + return (d1[4] > d2[4]) ? 1 : -1; + if (d1[5] != d2[5]) + return (d1[5] > d2[5]) ? 1 : -1; +#else + WRITE ME; +#endif + return 0; +} + +#if UNUSED_CODE +/********************************************************************** +* This is from the pre-splay-tree code for BSD +* I suspect the Linux approach will work on most O/S and be much +* better - +*********************************************************************** +static int +checkARP(u_long ip, char *eth) +{ + int mib[6] = + {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO}; + size_t needed; + char *buf, *next, *lim; + struct rt_msghdr *rtm; + struct sockaddr_inarp *sin; + struct sockaddr_dl *sdl; + if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { + debug(28, 0) ("Can't estimate ARP table size!\n"); + return 0; + } + if ((buf = xmalloc(needed)) == NULL) { + debug(28, 0) ("Can't allocate temporary ARP table!\n"); + return 0; + } + if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { + debug(28, 0) ("Can't retrieve ARP table!\n"); + 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); + if (sin->sin_addr.s_addr == ip) { + if (sdl->sdl_alen) + if (!memcmp(LLADDR(sdl), eth, 6)) { + xfree(buf); + return 1; + } + break; + } + } + xfree(buf); + return 0; +} +**********************************************************************/ +#endif + +static void +aclDumpArpListWalkee(void *node, void *state) +{ + acl_arp_data *arp = node; + wordlist **W = state; + static char buf[24]; + while (*W != NULL) + W = &(*W)->next; + snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x", + arp->eth[0], arp->eth[1], arp->eth[2], arp->eth[3], + arp->eth[4], arp->eth[5]); + wordlistAdd(state, buf); +} + +static wordlist * +aclDumpArpList(void *data) +{ + wordlist *w = NULL; + splay_walk(data, aclDumpArpListWalkee, &w); + return w; +} + +/* ==== END ARP ACL SUPPORT =============================================== */ +