--- a/ip_list.c
+++ b/ip_list.c
@@ -106,76 +106,115 @@
 #  include <stdlib.h>
 #endif
 
-#include<netinet/in.h>
-#include<arpa/inet.h>
+#include <string.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
 
 #include "ip_list.h"
 #include "util.h"
 #include "log.h"
 
-static int ip_acl_match(struct in_addr c, const ip_acl *a);
-
-
-static int
-ip_acl_match(struct in_addr c, const ip_acl *a)
-{
-    static struct in_addr h;
-
-    h.s_addr = c.s_addr & a->mask.s_addr;
-    if (h.s_addr == a->addr.s_addr)
-	return 1;
-    else
-	return 0;
-}
-
 ip_access_type
-ip_access_check(struct in_addr address, const ip_acl *list)
+ip_access_check(int afamily, const void *address, const ip_acl *list)
 {
     const ip_acl *p = NULL;
-    /* address ... network byte-order IP addr */
-
+    struct in_addr h;
+    ip_access_type response=IP_DENY;
+    int i;
 #ifdef DEBUG
-    if (!list) {
-	mylog(DEBG, "ACL: denied %s\n", inet_ntoa(address));
-	return IP_DENY;
-    }
-    for (p = list; p; p = p->next) {
-	if (ip_acl_match(address, p)) {
-	    mylog(DEBG, "ACL: %s %s\n", p->access==IP_DENY ? "denied" : "allowed",
-		inet_ntoa(address));
-	    return p->access;
-	}
-    }
-    mylog(DEBG, "ACL: denied %s\n", inet_ntoa(address));
-    return IP_DENY;
-#else
-    if (!list)
-	return IP_DENY;
-    for (p = list; p; p = p->next) {
-	if (ip_acl_match(address, p))
-	    return p->access;
+    char addrbuffer[INET6_ADDRSTRLEN];
+
+    if (!inet_ntop(afamily,address,addrbuffer,sizeof(addrbuffer)))
+       addrbuffer[0]=0;
+#endif
+
+    if (list)
+    {
+       for (p = list; p; p = p->next)
+       {
+	  if (p->af!=afamily)
+	     continue;
+	  if (p->af==AF_INET)
+	  {
+	     h.s_addr = ((struct in_addr *)address)->s_addr & p->mask.s_addr;
+	     if (h.s_addr == p->addr.s_addr)
+	     {
+		response=p->access;
+		break;
+	     }
+	  }
+	  else if (p->af==AF_INET6)
+	  {
+	     int equal=1;
+	     /* apply mask and compare byte-wise*/
+	     for (i=0;i<sizeof(p->addr6.s6_addr);++i)
+	     {
+		if (p->addr6.s6_addr[i] !=
+		    (((struct in6_addr *)address)->s6_addr[i] & p->mask6.s6_addr[i]))
+		{
+		   equal=0;
+		   break;
+		}
+	     }
+	     if (equal)
+	     {
+		response=p->access;
+		break;
+	     }
+	  }
+       }
     }
-    return IP_DENY;
+#ifdef DEBUG
+    mylog(DEBG, "ACL: %s %s\n",
+	  response==IP_DENY ? "denied":"allowed",
+	  addrbuffer);
 #endif
+    return response;
 }
 
 void
 addToIPACL(ip_acl **list, const char *ip_str)
 {
     ip_acl *p, *q;
-    int a1, a2, a3, a4, m1;
-    struct in_addr lmask;
-    int inv = 0;
-    int c;
+    int inv=0, masklen;
+    char *masklenp;
+    int family,i;
 
     if (!ip_str) {
 	return;
     }
+
+    /* decode ip address */
+    if (*ip_str == '!') {
+        ip_str++;
+        inv++;
+    }
+    /* ipv6 or v4? */
+    family=strchr(ip_str,':')?AF_INET6:AF_INET;
+    /* where's the mask length? */
+    masklenp=strchr(ip_str,'/');
+    if (!masklenp)
+    {
+       mylog(ERROR, "Ignoring invalid IP acl line '%s': no mask len\n",ip_str);
+       return;
+    }
+    *masklenp=0;
+    masklen=atoi(++masklenp);
+    if (masklen<0 || (family==AF_INET6 && masklen>128)
+	|| (family==AF_INET && masklen>32))
+    {
+       mylog(ERROR, "Ignoring invalid IP acl line '%s': bad mask len\n",ip_str);
+       return;
+    }
+
+
     if (! (*list)) {
 	/* empty list */
 	*list = xcalloc(1, sizeof(ip_acl));
 	(*list)->next = NULL;
 	q = *list;
+	p=NULL;
     } else {
 	/* find end of list */
 	p = *list;
@@ -186,22 +225,44 @@ addToIPACL(ip_acl **list, const char *ip
 	p->next = q;
     }
 
-    /* decode ip address */
-    if (*ip_str == '!') {
-        ip_str++;
-        inv++;
-    }
-    a1 = a2 = a3 = a4 = 0;
-    c = sscanf(ip_str, "%d.%d.%d.%d/%d", &a1, &a2, &a3, &a4, &m1);
-    if (m1 < 0 || m1 > 32) {
-	mylog(ERROR, "addToIPACL: Ignoring invalid IP acl line '%s'\n",
-	      ip_str);
-	return;
+    q->af=family;
+    /* now parse the address */
+    if (!inet_pton(family,ip_str,(family==AF_INET?(void*)&q->addr.s_addr:
+				  (void*)&q->addr6.s6_addr)))
+    {
+       mylog(ERROR, "Ignoring invalid IP acl line '%s'\n",ip_str);
+       safe_free(q);
+       if (p)
+	  p->next=NULL;
+       else
+	  *list=NULL;
+       return;
     }
+    /* let's construct the mask and fill in the remaining bits */
     q->access = inv ? IP_DENY : IP_ALLOW;
-    q->addr.s_addr = htonl(a1 * 0x1000000 + a2 * 0x10000 + a3 * 0x100 + a4);
-    lmask.s_addr = m1 ? htonl(0xfffffffful << (32 - m1)) : 0;
-    q->mask.s_addr = lmask.s_addr;
+
+    if (family==AF_INET)
+    {
+       q->mask.s_addr= masklen ? htonl(0xfffffffful << (32 - masklen)) : 0;
+    }
+    else
+    {
+       for (i=0;i<sizeof(q->mask6.s6_addr);++i)
+       {
+	  if (i<masklen/8)
+	  {
+	     q->mask6.s6_addr[i]=0xff;
+	  }
+	  else if (i>masklen/8)
+	  {
+	     q->mask6.s6_addr[i]=0;
+	  }
+	  else
+	  {
+	     q->mask6.s6_addr[i]=  0xff&(0xff<<(8-masklen%8));
+	  }
+       }
+    }
 }
 
 void
--- a/ip_list.h
+++ b/ip_list.h
@@ -105,15 +105,17 @@ typedef enum {
 } ip_access_type;
 
 typedef struct _ip_acl {
-    struct in_addr addr;
-    struct in_addr mask;
-    ip_access_type access;
-    struct _ip_acl *next;
+   struct in_addr addr;
+   struct in_addr mask;
+   struct in6_addr addr6, mask6;
+   int af;			/* address family: AF_INET or AF_INET6 */
+   ip_access_type access;
+   struct _ip_acl *next;
 } ip_acl;
 
     
 extern void ip_acl_destroy(ip_acl **);
 extern void addToIPACL(ip_acl **, const char *);
-extern ip_access_type ip_access_check(struct in_addr, const ip_acl *);
+extern ip_access_type ip_access_check(int, const void *, const ip_acl *);
 
 #endif
--- a/rewrite.c
+++ b/rewrite.c
@@ -66,6 +66,8 @@ parse_buff(char *buff, char **url, char
 {
    int j;
    struct in_addr address;
+   struct in6_addr address6;
+   int family=AF_INET;
    char *token;
    char *next_token = buff;
    char *errorptr;
@@ -155,18 +157,26 @@ parse_buff(char *buff, char **url, char
        i.e. on 2.6  448K r-x + 40K rwx, but since it is a shared lib,
        it is already loaded, when squid runs - so not much waste of
        memory ;-) */
-    if ( (address.s_addr = inet_addr(*src_addr)) == -1 ) {
-	mylog(ERROR, "client IP address (%s) not valid\n",
-	    *src_addr ? *src_addr : "");
-	if ( token )
-	    *token = '/';
-	return 1;
+     if ( (address.s_addr = inet_addr(*src_addr)) == -1 )
+     {
+        /* not ipv6, test ipv6 now */
+        if (!inet_pton(AF_INET6,*src_addr,&address6.s6_addr))
+        {
+ 	  mylog(ERROR, "client IP address (%s) not valid\n",
+ 		*src_addr ? *src_addr : "");
+ 	  if ( token )
+ 	     *token = '/';
+ 	  return 1;
+        }
+        else
+ 	  family=AF_INET6;
     }
     if ( token )
 	*token = '/';
     
     /* make sure the IP source address matches that of the ones in our list */
-    if( ip_access_check(address, ip) == IP_DENY ) {
+    if( ip_access_check(family,(family==AF_INET?(void*)&address:
+				(void*)&address6),ip) == IP_DENY ) {
 #ifdef DEBUG
 	mylog(DEBG, "client IP address (%s) not matched\n", *src_addr);
 #endif  
