A DNS-based hack, was Re: Squid is becoming slow with 3000 ACL's ...

From: Scott Lystig Fritchie <fritchie@dont-contact.us>
Date: Sun, 13 Sep 1998 23:33:34 -0500

Greetings --

I've only been following this thread distantly ... but I'm including a
diff below which helps solve at least one kind of lots-of-ACLs kind of
problem, and it might be used to address directly the problem that
H.J. Bekker first brought up.

Several months ago, at my previous place of employment, MRNet, I ran
into a situation where I'd have to have over 100 ACLs in order to
limit access to MRNet customers only. Furthermore, I wanted a "low
maintenance" solution where I could automate editing ACLs in
"squid.conf" files on each of my dispersed caches (or avoid the task
altogether, if possible). The solution I came up with was based on
how one of the anti-spam RBL techniques works.

If a client's source address is A.B.C.D, Squid checks to see if an A
record called D.C.B.A.custnets.mr.net exists. If so, the query is
permitted. Squid's own DNS cache caches the info, so subsequent
client requests don't have to consult a DNS server again.

Though my patch can't directly solve Henni's problem, a variation
could. Instead of checking the source IP address, the destination
hostname could be checked using the same technique: if the client asks
for something at www.bannedplace.com, a DNS query for
www.bannedplace.com.blacklist.yourdomain.com could be done. (You'd
have to include the IP address(es) for www.bannedplace.com in
blacklist.yourdomain.com, too ... but I guess you'd have to take that
into consideration when crafting your 3000 entry traditional ACL,
too.)

FWIW, liberal use of wildcards in the DNS server's zone files makes life
easier, e.g.

$ORIGIN 192.137.custnets.mr.net.
* in a 10.10.10.10
$ORIGIN 22.137.custnets.mr.net.
* in a 10.10.10.10

... though for various CIDR network blocks, the zone file has an awful
lot of:

$ORIGIN 9.32.209.custnets.mr.net.
* in a 10.10.10.10
$ORIGIN 90.32.209.custnets.mr.net.
* in a 10.10.10.10
$ORIGIN 91.32.209.custnets.mr.net.
* in a 10.10.10.10
$ORIGIN 92.32.209.custnets.mr.net.
* in a 10.10.10.10

When I first queried this list if such a hack were worthwhile, I got
mixed feedback ... so I went ahead and implemented it. At the time,
I'd pledged that I'd spread the patch around in case anyone else were
interested or if it ought to be rolled in to a production release.
Better late than never: the diff is below. It's against 1.1.21. I
have no idea how easy or painful it would be to apply to a 1.2
release. The code is brute force and ignorance. :-)

-Scott

---
Scott Lystig Fritchie                            HSA Corp.
<fritchie@mr.net>                                5401 - 10th Ave S
                                                 Minneapolis, MN  55417 USA
             "We're in the middle of another commercial-
              free decade."    -- Minnesota Public Radio
--- snip --- snip --- snip --- snip --- snip --- snip --- snip --- 
diff -crw ./lib/safe_inet_addr.c ../squid-1.1.21.scott/lib/safe_inet_addr.c
*** ./lib/safe_inet_addr.c	Wed May 14 12:19:50 1997
--- ../squid-1.1.21.scott/lib/safe_inet_addr.c	Thu Apr 16 15:55:46 1998
***************
*** 21,26 ****
--- 21,29 ----
  #if HAVE_ARPA_INET_H
  #include <arpa/inet.h>
  #endif
+ #if HAVE_CTYPE_H
+ #include <ctype.h>
+ #endif
  
  int
  safe_inet_addr(const char *buf, struct in_addr *addr)
***************
*** 28,33 ****
--- 31,38 ----
      static char addrbuf[32];
      int a1 = 0, a2 = 0, a3 = 0, a4 = 0;
      struct in_addr A;
+     char *p = buf;
+ 
      if (sscanf(buf, "%d.%d.%d.%d", &a1, &a2, &a3, &a4) != 4)
  	return 0;
      if (a1 < 0 || a1 > 255)
***************
*** 38,43 ****
--- 43,58 ----
  	return 0;
      if (a4 < 0 || a4 > 255)
  	return 0;
+     /*
+     ** This is a bit odd, but we might be given something like
+     ** 4.2.192.137.in-addr.arpa or 4.2.192.137.some.other.domain.
+     */
+     while (*p) {
+ 	if (*p != '.' && !isdigit(*p))
+ 	    return 0;
+ 	p++;
+     }
+     /* We might still have 1.2.3.4.5.6.7.8, I suppose.  {sigh} */
      sprintf(addrbuf, "%d.%d.%d.%d", a1, a2, a3, a4);
      A.s_addr = inet_addr(addrbuf);
      if (addr)
diff -crw ./src/acl.c ../squid-1.1.21.scott/src/acl.c
*** ./src/acl.c	Mon Mar 16 18:57:30 1998
--- ../squid-1.1.21.scott/src/acl.c	Thu Apr 16 23:16:09 1998
***************
*** 153,158 ****
--- 153,160 ----
  	return ACL_DST_DOMAIN;
      if (!strcmp(s, "srcdomain"))
  	return ACL_SRC_DOMAIN;
+     if (!strcmp(s, "srcipmap"))
+ 	return ACL_SRC_IPMAP;
      if (!strcmp(s, "time"))
  	return ACL_TIME;
      if (!strcmp(s, "pattern"))
***************
*** 647,652 ****
--- 649,655 ----
  	break;
      case ACL_SRC_DOMAIN:
      case ACL_DST_DOMAIN:
+     case ACL_SRC_IPMAP:
  	aclParseDomainList(&A->data);
  	break;
      case ACL_TIME:
***************
*** 1072,1077 ****
--- 1075,1082 ----
      const char *fqdn = NULL;
      char *esc_buf;
      int k;
+     char *ipmapname = NULL;
+ 
      if (!acl)
  	return 0;
      debug(28, 3, "aclMatchAcl: checking '%s'\n", acl->cfgline);
***************
*** 1124,1129 ****
--- 1129,1154 ----
  	    return aclMatchDomainList(&acl->data, "none");
  	}
  	/* NOTREACHED */
+     case ACL_SRC_IPMAP:
+ 	if ((ipmapname = strrchr(acl->cfgline, ' ')) == NULL) {
+ 	    debug(28, 1, "aclMatchAcl: strchr() cannot find space in \"%\"",
+ 		  acl->cfgline);
+ 	    return 0;
+ 	}
+ 	ipmapname++;
+ 	fqdn = fqdncache_gethostbyaddripmap(checklist->src_addr,
+ 					    FQDN_LOOKUP_IF_MISS, ipmapname);
+ 	if (fqdn) {
+ 	    return aclMatchDomainList(&acl->data, fqdn);
+ 	} else if (checklist->state[ACL_SRC_DOMAIN] == ACL_LOOKUP_NONE) {
+ 	    debug(28, 3, "aclMatchAcl: Can't yet compare '%s' ACL for '%s'\n",
+ 		acl->name, inet_ntoa(checklist->src_addr));
+ 	    checklist->state[ACL_SRC_DOMAIN] = ACL_LOOKUP_NEED;
+ 	    return 0;
+ 	} else {
+ 	    return aclMatchDomainList(&acl->data, "none");
+ 	}
+ 	/* NOTREACHED */
      case ACL_TIME:
  	return aclMatchTime(acl->data, squid_curtime);
  	/* NOTREACHED */
***************
*** 1595,1597 ****
--- 1620,1623 ----
  }
  
  #endif /* USE_BIN_TREE */
+ 
diff -crw ./src/acl.h ../squid-1.1.21.scott/src/acl.h
*** ./src/acl.h	Thu Feb 20 15:03:10 1997
--- ../squid-1.1.21.scott/src/acl.h	Thu Apr 16 15:47:56 1998
***************
*** 44,50 ****
      ACL_PROTO,
      ACL_METHOD,
      ACL_BROWSER,
!     ACL_ENUM_MAX
  } squid_acl;
  
  #define ACL_SUNDAY	0x01
--- 44,51 ----
      ACL_PROTO,
      ACL_METHOD,
      ACL_BROWSER,
!     ACL_ENUM_MAX,
!     ACL_SRC_IPMAP
  } squid_acl;
  
  #define ACL_SUNDAY	0x01
***************
*** 127,132 ****
--- 128,134 ----
      char ident[ICP_IDENT_SZ];
      char browser[BROWSERNAMELEN];
      acl_lookup_state state[ACL_ENUM_MAX];
+     char ipmapname[SQUIDHOSTNAMELEN];
  };
  
  extern int aclCheck _PARAMS((const struct _acl_access *, aclCheck_t *));
diff -crw ./src/client_side.c ../squid-1.1.21.scott/src/client_side.c
*** ./src/client_side.c	Fri Mar  6 12:33:10 1998
--- ../squid-1.1.21.scott/src/client_side.c	Thu Apr 16 21:35:00 1998
***************
*** 35,40 ****
--- 35,41 ----
  static void icpHandleIMSReply _PARAMS((int fd, StoreEntry * entry, void *data));
  static void clientLookupDstIPDone _PARAMS((int fd, const ipcache_addrs *, void *data));
  static void clientLookupSrcFQDNDone _PARAMS((int fd, const char *fqdn, void *data));
+ static void clientLookupSrcIPMapFQDNDone _PARAMS((int fd, const char *fqdn, void *data));
  static void clientLookupDstFQDNDone _PARAMS((int fd, const char *fqdn, void *data));
  static int clientGetsOldEntry _PARAMS((StoreEntry * new, StoreEntry * old, request_t * request));
  static int checkAccelOnly _PARAMS((icpStateData * icpState));
***************
*** 71,76 ****
--- 72,89 ----
  }
  
  static void
+ clientLookupSrcIPMapFQDNDone(int fd, const char *fqdn, void *data)
+ {
+     icpStateData *icpState = data;
+     debug(33, 5, "clientLookupSrcIPMapFQDNDone: FD %d, '%s', FQDN %s\n",
+ 	fd,
+ 	icpState->url,
+ 	fqdn ? fqdn : "NULL");
+     icpState->aclChecklist->state[ACL_SRC_IPMAP] = ACL_LOOKUP_DONE;
+     clientAccessCheck(icpState, icpState->aclHandler);
+ }
+ 
+ static void
  clientLookupDstFQDNDone(int fd, const char *fqdn, void *data)
  {
      icpStateData *icpState = data;
***************
*** 204,209 ****
--- 217,231 ----
  		icpState->fd,
  		clientLookupSrcFQDNDone,
  		icpState);
+ 	    return;
+ 	} else if (ch->state[ACL_SRC_IPMAP] == ACL_LOOKUP_NEED) {
+ 	    ch->state[ACL_SRC_IPMAP] = ACL_LOOKUP_PENDING;	/* first */
+ 	    debug(33, 1,
+ 		  "XXX Hey, bug here!  ch->ipmapname is not set.  Fix me.");
+ 	    fqdncache_nbgethostbyaddripmap(icpState->peer.sin_addr,
+ 		icpState->fd,
+ 		clientLookupSrcIPMapFQDNDone,
+ 		icpState, ch->ipmapname);
  	    return;
  	} else if (ch->state[ACL_DST_DOMAIN] == ACL_LOOKUP_NEED) {
  	    ch->state[ACL_DST_DOMAIN] = ACL_LOOKUP_PENDING;	/* first */
diff -crw ./src/errorpage.c ../squid-1.1.21.scott/src/errorpage.c
*** ./src/errorpage.c	Fri Mar  6 12:33:12 1998
--- ../squid-1.1.21.scott/src/errorpage.c	Fri Apr 17 16:22:21 1998
***************
*** 272,280 ****
  	"<P>\n"
  	"Sorry, you are not currently allowed to request:\n"
  	"<PRE>    %s</PRE>\n"
! 	"from this cache.  Please check with the\n"
! 	"<A HREF=\"mailto:%s\">cache administrator</A>\n"
! 	"if you believe this is incorrect.\n"
  	"<P>\n"
  	"%s\n"
  	"<HR>\n"
--- 272,287 ----
  	"<P>\n"
  	"Sorry, you are not currently allowed to request:\n"
  	"<PRE>%s</PRE>\n"
! 	"from this cache.\n"
! 	"<p> Too many people have abused this free service to continue to allow "
! 	"unrestricted access.  As a result of a number of Web server security breaches, "
! 	"use of this cache has been restricted to MRNet customers only.  "
! 	"If you are an MRNet customer, please contact the "
! 	"<A HREF=\"mailto:%s\">MRNet cache administrator</A>\n"
! 	"with the IP network address(es) which you believe should have acccess "
! 	"to this caching proxy.\n"
! 	"<p> If you are not an MRNet customer but wish to set up a 'sibling' "
! 	"cache arrangement, please contact the email address above.\n"
  	"<P>\n"
  	"%s\n"
  	"<HR>\n"
diff -crw ./src/fqdncache.c ../squid-1.1.21.scott/src/fqdncache.c
*** ./src/fqdncache.c	Mon Mar 16 21:05:01 1998
--- ../squid-1.1.21.scott/src/fqdncache.c	Wed Apr 22 22:44:56 1998
***************
*** 108,114 ****
  
  #define MAX_LINELEN (4096)
  
! #define MAX_FQDN		 1024	/* Maximum cached FQDN */
  #define FQDN_LOW_WATER       90
  #define FQDN_HIGH_WATER      95
  
--- 108,114 ----
  
  #define MAX_LINELEN (4096)
  
! #define MAX_FQDN		 4096	/* Maximum cached FQDN */
  #define FQDN_LOW_WATER       90
  #define FQDN_HIGH_WATER      95
  
***************
*** 673,678 ****
--- 673,767 ----
      fqdncache_call_pending(f);
  }
  
+ void
+ fqdncache_nbgethostbyaddripmap(struct in_addr addr, int fd, FQDNH handler,
+ 	void *handlerData, char *ipmapname)
+ {
+     fqdncache_entry *f = NULL;
+     dnsserver_t *dnsData = NULL;
+     struct in_addr reversedaddr;
+     char *reversedoctets = NULL, *name = NULL;
+     char array[4], tmp;
+ 
+     if (!handler)
+ 	fatal_dump("fqdncache_nbgethostbyaddripmap: NULL handler");
+ 
+     /* First we need to flip the octets of 'addr' to reverse order.  */
+     memcpy(array, &addr, sizeof(addr));
+     tmp = array[3];
+     array[3] = array[0];
+     array[0] = tmp;
+     tmp = array[1];
+     array[1] = array[2];
+     array[2] = tmp;
+     memcpy(&reversedaddr, array, sizeof(reversedaddr));
+     reversedoctets = inet_ntoa(reversedaddr);
+     name = xmalloc(strlen(reversedoctets) + strlen(ipmapname) + 2);
+     sprintf(name, "%s.%s", reversedoctets, ipmapname);
+ 
+     debug(35, 4, "fqdncache_nbgethostbyaddripmap: FD %d: Name '%s'.\n", fd, name);
+     FqdncacheStats.requests++;
+ 
+     if (name == NULL || name[0] == '\0') {
+ 	debug(35, 4, "fqdncache_nbgethostbyaddripmap: Invalid name!\n");
+ 	handler(fd, NULL, handlerData);
+ 	if (name != NULL)
+ 	    xfree(name);
+ 	return;
+     }
+     if ((f = fqdncache_get(name))) {
+ 	if (fqdncacheExpiredEntry(f)) {
+ 	    fqdncache_release(f);
+ 	    f = NULL;
+ 	}
+     }
+     if (f == NULL) {
+ 	/* MISS: No entry, create the new one */
+ 	debug(35, 5, "fqdncache_nbgethostbyaddripmap: MISS for '%s'\n", name);
+ 	FqdncacheStats.misses++;
+ 	f = fqdncacheAddNew(name, NULL, FQDN_PENDING);
+ 	fqdncacheAddPending(f, fd, handler, handlerData);
+     } else if (f->status == FQDN_CACHED || f->status == FQDN_NEGATIVE_CACHED) {
+ 	/* HIT */
+ 	debug(35, 4, "fqdncache_nbgethostbyaddripmap: HIT for '%s'\n", name);
+ 	if (f->status == FQDN_NEGATIVE_CACHED)
+ 	    FqdncacheStats.negative_hits++;
+ 	else
+ 	    FqdncacheStats.hits++;
+ 	fqdncacheAddPending(f, fd, handler, handlerData);
+ 	fqdncache_call_pending(f);
+ 	xfree(name);
+ 	return;
+     } else if (f->status == FQDN_PENDING || f->status == FQDN_DISPATCHED) {
+ 	debug(35, 4, "fqdncache_nbgethostbyaddripmap: PENDING for '%s'\n", name);
+ 	FqdncacheStats.pending_hits++;
+ 	fqdncacheAddPending(f, fd, handler, handlerData);
+ 	if (squid_curtime - f->expires > 600) {
+ 	    debug(14, 0, "fqdncache_nbgethostbyname: '%s' PENDING for %d seconds, aborting\n", name, squid_curtime + Config.negativeDnsTtl - f->expires);
+ 	    fqdncacheChangeKey(f);
+ 	    fqdncache_call_pending(f);
+ 	}
+ 	xfree(name);
+ 	return;
+     } else {
+ 	fatal_dump("fqdncache_nbgethostbyaddripmap: BAD fqdncache_entry status");
+     }
+ 
+     /* for HIT, PENDING, DISPATCHED we've returned.  For MISS we continue */
+ 
+     xfree(name);	/* We don't use if from this point forward */
+     if ((dnsData = dnsGetFirstAvailable())) {
+ 	fqdncache_dnsDispatch(dnsData, f);
+ 	return;
+     }
+     if (NDnsServersAlloc > 0) {
+ 	fqdncacheEnqueue(f);
+ 	return;
+     }
+     fqdncache_gethostbyaddr(addr, FQDN_BLOCKING_LOOKUP);
+     fqdncache_call_pending(f);
+ }
+ 
  static void
  fqdncache_dnsDispatch(dnsserver_t * dns, fqdncache_entry * f)
  {
***************
*** 823,828 ****
--- 912,1012 ----
      }
      if (flags & FQDN_LOOKUP_IF_MISS)
  	fqdncache_nbgethostbyaddr(addr, -1, dummy_handler, NULL);
+     return NULL;
+ }
+ 
+ /*
+ ** The body of this function was borrowed/stolen from
+ ** fqdncache_gethostbyaddr() and tweaked just enough "to get it to work".
+ ** I doubt that all of the flow control paths through this function would
+ ** actually function correctly ... Caveat coder.
+ ** -SLF, <fritchie@mr.net> 4/22/98
+ */
+ 
+ const char *
+ fqdncache_gethostbyaddripmap(struct in_addr addr, int flags, char *ipmapname)
+ {
+     fqdncache_entry *f = NULL;
+     const struct hostent *hp = NULL;
+     struct in_addr ip;
+     static char *static_name = NULL;
+     struct in_addr reversedaddr;
+     char *reversedoctets = NULL, *name = NULL;
+     char array[4], tmp;
+ 
+     /* First we need to flip the octets of 'addr' to reverse order.  */
+     memcpy(array, &addr, sizeof(addr));
+     tmp = array[3];
+     array[3] = array[0];
+     array[0] = tmp;
+     tmp = array[1];
+     array[1] = array[2];
+     array[2] = tmp;
+     memcpy(&reversedaddr, array, sizeof(reversedaddr));
+     reversedoctets = inet_ntoa(reversedaddr);
+     name = xmalloc(strlen(reversedoctets) + strlen(ipmapname) + 2);
+     sprintf(name, "%s.%s", reversedoctets, ipmapname);
+ 
+     if (!name)
+ 	fatal_dump("fqdncache_gethostbyaddripmap: NULL name");
+     debug(35, 4, "fqdncache_gethostbyaddripmap: Name '%s'.\n", name);
+ 
+     FqdncacheStats.requests++;
+     if ((f = fqdncache_get(name))) {
+ 	if (fqdncacheExpiredEntry(f)) {
+ 	    fqdncache_release(f);
+ 	    f = NULL;
+ 	}
+     }
+     if (f) {
+ 	if (f->status == FQDN_PENDING || f->status == FQDN_DISPATCHED) {
+ 	    if (!BIT_TEST(flags, IP_BLOCKING_LOOKUP)) {
+ 		/*
+ 		** I don't know what the deal is, but it's a symptom
+ 		** of a damn rare bug.  Under Solaris, we very occasionally
+ 		** find ourself here when doing a nonblocking lookup.
+ 		** I suspect it's a subtle select()/poll() bug; you'd think
+ 		** that Sun would finally fix those !@#$! bugs.  Anyhow,
+ 		** as far as my limited understanding tells me, we should
+ 		** still have FQDN_PENDING status at this point.  So, if
+ 		** we are, it's a bug.  Since this happens very rarely,
+ 		** I'll cope with it by issuing a false positive.  Why?
+ 		** Because if you're using the 'srcipmap' method to
+ 		** restrict access to a limited set of clients, a false
+ 		** positive will very rarely grant access to a client
+ 		** outside of that set, and their very next request will
+ 		** almost certainly fail.  If you issue a false negative to
+ 		** a legitimate user, you'll probably end up with a few
+ 		** rare users who run into this and get damn confused,
+ 		** particularly if they (or you) can't reproduce the problem.
+ 		** Or if they call your Tech Support division for help.
+ 		*/
+ 		FqdncacheStats.pending_hits++;
+ 		debug(35, 1, "fqdncache_gethostbyaddripmap: XXX This should never happen but is mostly harmless: PENDING HIT: %s\n",
+ 		      name);
+ 		/* Return ipmapname to fake a positive result */
+ 		return ipmapname;
+ 	    }
+ 	} else if (f->status == FQDN_NEGATIVE_CACHED) {
+ 	    FqdncacheStats.negative_hits++;
+ 	    debug(35, 4, "fqdncache_gethostbyaddripmap: NEGATIVE HIT: %s\n",
+ 		  name);
+ 	    dns_error_message = f->error_message;
+ 	    return NULL;
+ 	} else {
+ 	    FqdncacheStats.hits++;
+ 	    debug(35, 4, "fqdncache_gethostbyaddripmap: HIT: %s\n", name);
+ 	    f->lastref = squid_curtime;
+ 	    return f->names[0];
+ 	}
+     }
+     /* check if it's already a FQDN address in text form. */
+     if (!safe_inet_addr(name, &ip) && !strstr(name, ipmapname))
+ 	return name;
+     FqdncacheStats.misses++;
+     if (flags & FQDN_LOOKUP_IF_MISS)
+ 	fqdncache_nbgethostbyaddripmap(addr, -1, dummy_handler, NULL,
+ 				       ipmapname);
      return NULL;
  }
  
diff -crw ./src/fqdncache.h ../squid-1.1.21.scott/src/fqdncache.h
*** ./src/fqdncache.h	Thu Feb  5 16:21:07 1998
--- ../squid-1.1.21.scott/src/fqdncache.h	Thu Apr 16 20:04:36 1998
***************
*** 138,145 ****
--- 138,147 ----
  } fqdncache_entry;
  
  extern void fqdncache_nbgethostbyaddr _PARAMS((struct in_addr, int fd, FQDNH handler, void *handlerData));
+ extern void fqdncache_nbgethostbyaddripmap _PARAMS((struct in_addr, int fd, FQDNH handler, void *handlerData, char *));
  extern int fqdncacheUnregister _PARAMS((struct in_addr, int));
  extern const char *fqdncache_gethostbyaddr _PARAMS((struct in_addr, int flags));
+ extern const char *fqdncache_gethostbyaddripmap _PARAMS((struct in_addr, int flags, char *));
  extern void fqdncache_init _PARAMS((void));
  extern void fqdnStats _PARAMS((StoreEntry *));
  extern void fqdncacheShutdownServers _PARAMS((void));
diff -cwr ./src/squid.conf.pre ../squid-1.1.21.scott/src/squid.conf.pre
*** ./src/squid.conf.pre	Thu Apr 16 23:13:11 1998
--- ../squid-1.1.21.scott/src/squid.conf.pre	Thu Apr 16 15:47:57 1998
***************
*** 751,762 ****
  #
  # when using "file", the file should contain one item per line
  #
! # acltype is one of src dst srcdomain dstdomain url_pattern urlpath_pattern
  #	            time port proto method browser user
  #
  # acl aclname src      ip-address/netmask ... (clients IP address)
  # acl aclname src      addr1-addr2/netmask ... (range of addresses)
  # acl aclname dst      ip-address/netmask ... (URL host's IP address)
  # acl aclname srcdomain   foo.com ... (taken from reverse DNS lookup)
  # acl aclname dstdomain   foo.com ... (taken from the URL)
  # acl aclname time     [day-abbrevs]  [h1:m1-h2:m2]
--- 751,765 ----
  #
  # when using "file", the file should contain one item per line
  #
! # acltype is one of src dst srcipmap srcdomain dstdomain url_pattern urlpath_pattern
  #	            time port proto method browser user
  #
  # acl aclname src      ip-address/netmask ... (clients IP address)
  # acl aclname src      addr1-addr2/netmask ... (range of addresses)
  # acl aclname dst      ip-address/netmask ... (URL host's IP address)
+ # acl aclname srcipmap map.foo.com ... if src IP is A.B.C.D, lookup
+ #					D.C.B.A.map.foo.com.  If it exists,
+ #					permit the access.
  # acl aclname srcdomain   foo.com ... (taken from reverse DNS lookup)
  # acl aclname dstdomain   foo.com ... (taken from the URL)
  # acl aclname time     [day-abbrevs]  [h1:m1-h2:m2]
Received on Sun Sep 13 1998 - 21:43:47 MDT

This archive was generated by hypermail pre-2.1.9 : Tue Dec 09 2003 - 16:42:01 MST