Adapt to CVS version as of 2006-09-17 (incl. new IPv6 patch).
[privoxy.git] / debian / patches / 03_ipv6.dpatch
1 #! /bin/sh /usr/share/dpatch/dpatch-run
2 ## 03_ipv6.dpatch by Lionel Elie Mamane <lionel@mamane.lu>
3 ##
4 ## All lines beginning with `## DP:' are a description of the patch.
5 ## DP: privoxy_CVS_20030523_ipv6_5.patch.bz2 from
6 ## DP: ftp://ftp.deepspace6.net/pub/ds6/sources/privoxy/privoxy_CVS_20030523_ipv6_5.patch.bz2
7 ## DP: adapted to the 3.0 branch of privoxy by Roland Rosenfeld
8 ## DP: adapted to 3.0.4 by higuita, but i'm no programmer, so i hope i 
9 ## DP: didnt broke anything :)
10
11 @DPATCH@
12 diff -urNad privoxy~/GNUmakefile.in privoxy/GNUmakefile.in
13 --- privoxy~/GNUmakefile.in
14 +++ privoxy/GNUmakefile.in
15 @@ -187,7 +187,7 @@
16  C_SRC  = actions.c cgi.c cgiedit.c cgisimple.c deanimate.c encode.c \
17           errlog.c filters.c gateway.c jbsockets.c jcc.c killpopup.c \
18           list.c loadcfg.c loaders.c miscutil.c parsers.c ssplit.c \
19 -         urlmatch.c
20 +         urlmatch.c addrlist.c jb_socket_set.c
21  
22  C_OBJS = $(C_SRC:.c=.@OBJEXT@)
23  C_HDRS = $(C_SRC:.c=.h) project.h actionlist.h
24 @@ -241,7 +241,7 @@
25  SPECIAL_CFLAGS = @SPECIAL_CFLAGS@
26  
27  # Add your flags here 
28 -OTHER_CFLAGS =   
29 +OTHER_CFLAGS = -DINET6
30  
31  CFLAGS = @CFLAGS@ @CPPFLAGS@ $(OTHER_CFLAGS) $(SPECIAL_CFLAGS) -Wall \
32           @STATIC_PCRE_ONLY@ -Ipcre 
33 diff -urNad privoxy~/addrlist.c privoxy/addrlist.c
34 --- privoxy~/addrlist.c
35 +++ privoxy/addrlist.c
36 @@ -0,0 +1,198 @@
37 +const char addrlist_rcs[] = "$Id: $";
38 +/*********************************************************************
39 + *
40 + * File        :  $Source: $
41 + *
42 + * Purpose     :  Declares functions to handle lists of network addresses.
43 + *                Functions declared include:
44 + *                   `destroy_addr_list', head_addr_list and `tail_addr_list'
45 + *
46 + * Copyright   :  Written by and Copyright (C) 2002 Lionel Elie Mamane
47 + *                <lionel@mamane.lu>
48 + *
49 + *                This program is free software; you can redistribute it
50 + *                and/or modify it under the terms of the GNU General
51 + *                Public License as published by the Free Software
52 + *                Foundation; either version 2 of the License, or (at
53 + *                your option) any later version.
54 + *
55 + *                This program is distributed in the hope that it will
56 + *                be useful, but WITHOUT ANY WARRANTY; without even the
57 + *                implied warranty of MERCHANTABILITY or FITNESS FOR A
58 + *                PARTICULAR PURPOSE.  See the GNU General Public
59 + *                License for more details.
60 + *
61 + *                The GNU General Public License should be included with
62 + *                this file.  If not, you can view it at
63 + *                http://www.gnu.org/copyleft/gpl.html
64 + *                or write to the Free Software Foundation, Inc., 59
65 + *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
66 + *
67 + * Revisions   :
68 + *    $Log: addrlist.c,v $
69 + *
70 + *********************************************************************/
71 +
72 +#include "addrlist.h"
73 +#include <sys/types.h>
74 +#include <sys/socket.h>
75 +#include <netdb.h>
76 +#include <string.h>
77 +
78 +/*********************************************************************
79 + *
80 + * Function    :  acceptable
81 + *
82 + * Description :  Test wheter an address is acceptable for our use
83 + *                Currently, this means either an IPv4 or an IPv6 address
84 + *
85 + * Parameters  :
86 + *          0  :  addr = the address to test
87 + *
88 + * Returns     :  0             = false / no
89 + *                anything else = true / yes
90 + *
91 + *********************************************************************/
92 +static int acceptable (struct sockaddr_storage *addr)
93 +{
94 +   switch(addr->ss_family)
95 +   {
96 +   case AF_INET:
97 +#ifdef INET6
98 +   case AF_INET6:
99 +#endif
100 +      return !0;
101 +   default:
102 +      return 0;
103 +   }
104 +}
105 +
106 +/*********************************************************************
107 + *
108 + * Function    :  skim
109 + *
110 + * Description :  Get the first acceptable address in head position
111 + *                Assumes there is one
112 + *
113 + * Parameters  :
114 + *          0  :  l = the list to skim
115 + *
116 + * Returns     :  the skimmed list
117 + *
118 + *********************************************************************/
119 +static addr_list *skim (addr_list *l)
120 +{
121 +   if (acceptable((struct sockaddr_storage*)l->ai_addr))
122 +      return l;
123 +   return skim(l->ai_next);
124 +}
125 +
126 +/*********************************************************************
127 + *
128 + * Function    :  tail_addr_list
129 + *
130 + * Description :  Get the tail of an address list
131 + *
132 + * Parameters  :
133 + *          0  :  l = the list to get the tail of
134 + *
135 + * Returns     :  the tail of the list
136 + *                If the list has no tail (i.e. is nil), unspecified
137 + *                behaviour
138 + *
139 + *********************************************************************/
140 +addr_list *tail_addr_list(addr_list *l)
141 +{
142 +   return skim(l)->ai_next;
143 +}
144 +
145 +/*********************************************************************
146 + *
147 + * Function    :  head_addr_list
148 + *
149 + * Description :  Get the head of an address list
150 + *
151 + * Parameters  :
152 + *          0  :  l = the list to get the head of
153 + *
154 + * Returns     :  the head of the list
155 + *                If the list has no head (i.e. is nil), unspecified
156 + *                behaviour
157 + *
158 + *********************************************************************/
159 +struct sockaddr_storage *head_addr_list(addr_list *l)
160 +{
161 +   return (struct sockaddr_storage *)skim(l)->ai_addr;
162 +}
163 +
164 +/*********************************************************************
165 + *
166 + * Function    :  cpy_head_addr_list
167 + *
168 + * Description :  Copy the head of an address list to the given destination
169 + *
170 + * Parameters  :
171 + *          0  :  l = the list to get the head of
172 + *          1  :  r = where to put the result
173 + *
174 + * Returns     :  Nothing
175 + *                If the list has no head (i.e. is nil), unspecified
176 + *                behaviour
177 + *
178 + *********************************************************************/
179 +void cpy_head_addr_list(addr_list *l, struct sockaddr_storage *r, size_t *addrlen)
180 +{
181 +   addr_list *sl = skim(l);
182 +   memcpy(r, sl->ai_addr, sl->ai_addrlen);
183 +   *addrlen = sl->ai_addrlen;
184 +}
185 +
186 +/*********************************************************************
187 + *
188 + * Function    :  destroy_addr_list
189 + *
190 + * Description :  Unallocate memory allocated to an address list
191 + *
192 + * Parameters  :
193 + *          0  :  l = the list to unallocate
194 + *
195 + * Returns     :  nothing
196 + *
197 + *********************************************************************/
198 +void destroy_addr_list(addr_list *l)
199 +{
200 +   freeaddrinfo(l);
201 +}
202 +
203 +/*********************************************************************
204 + *
205 + * Function    :  is_nil_addr_list
206 + *
207 + * Description :  Test wheter a list is nil (empty)
208 + *
209 + * Parameters  :
210 + *          0  :  l = the list to test
211 + *
212 + * Returns     :  0             = false if list has a head,
213 + *                anything else = true if list is nil
214 + *
215 + *********************************************************************/
216 +int is_nil_addr_list(addr_list *l)
217 +{
218 +   /* We are searching for a witness of non-nilness (modulo acceptability)
219 +    * If none is found, the list is nil
220 +    */
221 +   if (l==NULL)
222 +      /* Empty list*/
223 +      return !0;
224 +   if (acceptable(head_addr_list(l)))
225 +      /* Witness found */
226 +      return 0;
227 +   return is_nil_addr_list(l->ai_next);
228 +}
229 +
230 +/*
231 +  Local Variables:
232 +  tab-width: 3
233 +  end:
234 +*/
235 diff -urNad privoxy~/addrlist.h privoxy/addrlist.h
236 --- privoxy~/addrlist.h
237 +++ privoxy/addrlist.h
238 @@ -0,0 +1,56 @@
239 +#ifndef ADDR_LIST_H_INCLUDED
240 +#define ADDR_LIST_H_INCLUDED
241 +#define ADDR_LIST_H_VERSION "$Id: $"
242 +/*********************************************************************
243 + *
244 + * File        :  $Source: $
245 + *
246 + * Purpose     :  Declares functions to handle lists of network addresses.
247 + *                Functions declared include:
248 + *                   `destroy_addr_list', head_addr_list and `tail_addr_list'
249 + *
250 + * Copyright   :  Written by and Copyright (C) 2002 Lionel Elie Mamane
251 + *                <lionel@mamane.lu>
252 + *
253 + *                This program is free software; you can redistribute it
254 + *                and/or modify it under the terms of the GNU General
255 + *                Public License as published by the Free Software
256 + *                Foundation; either version 2 of the License, or (at
257 + *                your option) any later version.
258 + *
259 + *                This program is distributed in the hope that it will
260 + *                be useful, but WITHOUT ANY WARRANTY; without even the
261 + *                implied warranty of MERCHANTABILITY or FITNESS FOR A
262 + *                PARTICULAR PURPOSE.  See the GNU General Public
263 + *                License for more details.
264 + *
265 + *                The GNU General Public License should be included with
266 + *                this file.  If not, you can view it at
267 + *                http://www.gnu.org/copyleft/gpl.html
268 + *                or write to the Free Software Foundation, Inc., 59
269 + *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
270 + *
271 + * Revisions   :
272 + *    $Log: addrlist.h,v $
273 + *
274 + *********************************************************************/
275 +
276 +#include <sys/socket.h>
277 +
278 +typedef struct addrinfo addr_list;
279 +
280 +addr_list *tail_addr_list(addr_list *l);
281 +struct sockaddr_storage *head_addr_list(addr_list *l);
282 +void cpy_head_addr_list(addr_list *l, struct sockaddr_storage *r, size_t *addrlen);
283 +void destroy_addr_list(addr_list *l);
284 +int is_nil_addr_list(addr_list *l);
285 +
286 +#define freez_addr_list(X)  { if(X) { destroy_addr_list(X); X = NULL ; } }
287 +
288 +#endif /* ndef LIST_H_INCLUDED */
289 +
290 +/*
291 +  Local Variables:
292 +  tab-width: 3
293 +  end:
294 +*/
295 diff -urNad privoxy~/cgi.c privoxy/cgi.c
296 --- privoxy~/cgi.c
297 +++ privoxy/cgi.c
298 @@ -14,6 +14,9 @@
299   * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
300   *                Privoxy team. http://www.privoxy.org/
301   *
302 + *                Modified by Lionel Elie Mamane <lionel@mamane.lu>
303 + *                for IPv6 support on 8 December 2002, 24 January 2003.
304 + *
305   *                Based on the Internet Junkbuster originally written
306   *                by and Copyright (C) 1997 Anonymous Coders and 
307   *                Junkbusters Corporation.  http://www.junkbusters.com
308 @@ -2221,7 +2224,6 @@
309   *********************************************************************/
310  struct map *default_exports(const struct client_state *csp, const char *caller)
311  {
312 -   char buf[20];
313     jb_err err;
314     struct map * exports;
315     int local_help_exists = 0;
316 @@ -2257,8 +2259,7 @@
317     if (!err) err = map_block_killer(exports, "can-toggle");
318  #endif
319  
320 -   snprintf(buf, 20, "%d", csp->config->hport);
321 -   if (!err) err = map(exports, "my-port", 1, buf, 1);
322 +       if (!err) err = map(exports, "my-port", 1, csp->my_port_str, 1);
323  
324     if(!strcmp(CODE_STATUS, "stable"))
325     {
326 diff -urNad privoxy~/errlog.c privoxy/errlog.c
327 --- privoxy~/errlog.c
328 +++ privoxy/errlog.c
329 @@ -739,6 +739,13 @@
330              break;
331           case 'E':
332              /* Non-standard: Print error code from errno */
333 +            /* TODO
334 +             * This is not only not standard, but clashes
335 +             * with the E modifier on the GNU (and possibly
336 +             * other systems): It means double (floating point)
337 +             * number in exponential notation, with capital E
338 +             * for mantiss / exponenent separator
339 +             */
340  #ifdef _WIN32
341              ival = WSAGetLastError();
342              sval = w32_socket_strerr(ival, tempbuf);
343 diff -urNad privoxy~/filters.c privoxy/filters.c
344 --- privoxy~/filters.c
345 +++ privoxy/filters.c
346 @@ -15,6 +15,9 @@
347   * Copyright   :  Written by and Copyright (C) 2001, 2004 the SourceForge
348   *                Privoxy team. http://www.privoxy.org/
349   *
350 + *                Modified by Lionel Elie Mamane <lionel@mamane.lu>
351 + *                for IPv6 support on 8 December 2002, 24 January 2003.
352 + *
353   *                Based on the Internet Junkbuster originally written
354   *                by and Copyright (C) 1997 Anonymous Coders and
355   *                Junkbusters Corporation.  http://www.junkbusters.com
356 @@ -465,6 +468,9 @@
357  #include <ctype.h>
358  #include <string.h>
359  #include <assert.h>
360 +#ifdef INET6
361 +#include <netdb.h>
362 +#endif
363  
364  #ifndef _WIN32
365  #ifndef __OS2__
366 @@ -499,17 +505,119 @@
367  
368  const char filters_h_rcs[] = FILTERS_H_VERSION;
369  
370 -/* Fix a problem with Solaris.  There should be no effect on other
371 - * platforms.
372 - * Solaris's isspace() is a macro which uses it's argument directly
373 - * as an array index.  Therefore we need to make sure that high-bit
374 - * characters generate +ve values, and ideally we also want to make
375 - * the argument match the declared parameter type of "int".
376 - */
377 -#define ijb_isdigit(__X) isdigit((int)(unsigned char)(__X))
378 +#ifdef FEATURE_ACL
379 +/*********************************************************************
380 + *
381 + * Function    :  addr_equal_under_mask
382 + *
383 + * Description :  Are these addresses equal modulo this mask?
384 + *                Assumes the second argument is already in
385 + *                mask-normal form
386 + *
387 + * Parameters  :
388 + *          0  :  addr1 = First address to compare
389 + *          1  :  addr2 = Second address to compare
390 + *                        MUST be in mask-normal form
391 + *          2  :  mask = for IPv4 addresses, a bitmask
392 + *                       for IPv6 addresses, a prefixlen in bits
393 + *
394 + * Returns     : 0 = FALSE (not equal) and non-zero = TRUE (equal)
395 + *
396 + *********************************************************************/
397 +static
398 +int
399 +addr_equal_under_mask(struct sockaddr_storage *addr1, struct sockaddr_storage *addr2, unsigned long  mask)
400 +{
401 +   if (!mask)
402 +       return 1;
403  
404 +   /* only identical families can be compared */
405 +   /* TODO: Should we code the special case of "IPv4 addresses as IPv6 addresses"? */
406 +   if (addr1->ss_family != addr2-> ss_family)
407 +     {
408 +       /*fprintf(stderr, "equal_under_mask: diff sa_family: %d %d\n",
409 +         sa1->sa_family, sa2-> sa_family); */
410 +       return 0;
411 +     }
412 +  
413 +   switch (addr1->ss_family)
414 +      {
415 +      case AF_INET:
416 +         {
417 +            /* IPv4 - mask is a bitmask */
418 +            struct sockaddr_in *sin1 = (struct sockaddr_in *)addr1;
419 +            struct sockaddr_in *sin2 = (struct sockaddr_in *)addr2;
420 +            
421 +            /*fprintf(stderr, "AF_INET: %08x %08x %08x\n", 
422 +              sin1->sin_addr.s_addr,
423 +              sin2->sin_addr.s_addr,
424 +              mask); */
425 +            return (sin1->sin_addr.s_addr & mask) == sin2->sin_addr.s_addr;
426 +         }
427 +         break;
428 +#ifdef INET6
429 +      case AF_INET6:
430 +         {
431 +            /* IPv6 - mask is a prefixlength in bits. */
432 +            struct sockaddr_in6 *sin1 = (struct sockaddr_in6 *)addr1;
433 +            struct sockaddr_in6 *sin2 = (struct sockaddr_in6 *)addr2;
434 +            char bitmask;
435 +            char *a1, *a2;
436 +            const int maskbytes = mask / 8;
437 +            static char m[] = { 0x00, 0x80, 0xC0, 0xE0,
438 +                                0xF0, 0xF8, 0xFC, 0xFE };
439 +/*             { */
440 +/*                int i; */
441 +/*                fprintf(stderr, "PF_INET6: "); */
442 +/*                for (i = 0; i < 16; i++) { */
443 +/*                   fprintf(stderr, "%02x ", sin1->sin6_addr.s6_addr[i]); */
444 +/*                } */
445 +/*                fprintf(stderr, "   "); */
446 +/*                for (i = 0; i < 16; i++) { */
447 +/*                   fprintf(stderr, "%02x ", sin2->sin6_addr.s6_addr[i]); */
448 +/*                } */
449 +/*                fprintf(stderr, "mask %d scopeids %x %x\n", mask, sin1->sin6_scope_id, sin2->sin6_scope_id); */
450 +/*             } */
451 +            /* should we compare scope ids and such too? */
452 +            /*
453 +             * LEM: I see no reason for this comparison
454 +             * Quite the contrary: A client coming to us with
455 +             * a small-scope address should be able to a bigger-scope
456 +             * address.
457 +             */
458 +/*             if (sin1->sin6_scope_id != sin2->sin6_scope_id) */
459 +/*                return 0; */
460 +
461 +            if (mask > 128ul)
462 +            {
463 +               log_error(LOG_LEVEL_ERROR, "%s%d", "Tried to compare IPv6 addresses with invalid prefixlen: ", mask);
464 +               return 0;
465 +            }
466 +
467 +            a1 = sin1->sin6_addr.s6_addr;
468 +            a2 = sin2->sin6_addr.s6_addr;
469 +
470 +            if (memcmp(a1, a2, maskbytes) != 0)
471 +               return 0;
472 +
473 +            mask %= 8;
474 +            /* This special case is necessary for when mask==128
475 +               else, we would go over the array size in a1/a2
476 +             */
477 +            if (mask==0)
478 +               return 1;
479 +
480 +            bitmask = m[mask];
481 +
482 +            return (a1[maskbytes] & bitmask) == a2[maskbytes];
483 +      }
484 +         break;
485 +#endif
486 +      default:
487 +         return 0;
488 +      }
489 +}
490  
491 -#ifdef FEATURE_ACL
492  /*********************************************************************
493   *
494   * Function    :  block_acl
495 @@ -539,7 +647,7 @@
496     /* search the list */
497     while (acl != NULL)
498     {
499 -      if ((csp->ip_addr_long & acl->src->mask) == acl->src->addr)
500 +      if (addr_equal_under_mask(&csp->ip_addr_addr, &acl->src->addr, acl->src->mask))
501        {
502           if (dst == NULL)
503           {
504 @@ -549,8 +657,8 @@
505                 return(0);
506              }
507           }
508 -         else if ( ((dst->addr & acl->dst->mask) == acl->dst->addr)
509 -           && ((dst->port == acl->dst->port) || (acl->dst->port == 0)))
510 +         else if ( addr_equal_under_mask(&dst->addr, &acl->dst->addr, acl->dst->mask)
511 +                   && ((dst->port == acl->dst->port) || (acl->dst->port == 0)))
512           {
513              if (acl->action == ACL_PERMIT)
514              {
515 @@ -569,81 +677,249 @@
516  
517  }
518  
519 -
520  /*********************************************************************
521   *
522 - * Function    :  acl_addr
523 + * Function    :  fill_acl_addr_mask
524   *
525 - * Description :  Called from `load_config' to parse an ACL address.
526 + * Description :  Fill in the mask-related members of a
527 + *                struct access_control_addr
528   *
529   * Parameters  :
530 - *          1  :  aspec = String specifying ACL address.
531 - *          2  :  aca = struct access_control_addr to fill in.
532 + *          0  :  aca = struct access_control_addr to fill in.
533 + *          1  :  masklength = mask length.
534   *
535 - * Returns     :  0 => Ok, everything else is an error.
536 + * Returns     :  nothing
537   *
538   *********************************************************************/
539 -int acl_addr(char *aspec, struct access_control_addr *aca)
540 +void fill_acl_addr_mask(struct access_control_addr *aca, int masklength)
541  {
542 -   int i, masklength, port;
543 -   char *p;
544 +   int pf;
545  
546 -   masklength = 32;
547 -   port       =  0;
548 +   pf = aca->addr.ss_family;
549  
550 -   if ((p = strchr(aspec, '/')) != NULL)
551 +   switch (pf)
552     {
553 -      *p++ = '\0';
554 -
555 -      if (ijb_isdigit(*p) == 0)
556 +   case PF_INET:
557 +      /* build the netmask */
558 +      if (masklength == -1)
559 +         masklength = 32;
560 +      aca->mask = 0;
561 +      for(pf=1; pf <= masklength ; ++pf)
562        {
563 -         return(-1);
564 +         aca->mask |= (1 << (32 - pf));
565        }
566 -      masklength = atoi(p);
567 -   }
568 +      aca->mask = htonl(aca->mask);
569 +      
570 +      /* now mask off the host portion of the ip address
571 +       * (i.e. save on the network portion of the address).
572 +       */
573 +      ((struct sockaddr_in*) &aca->addr)->sin_addr.s_addr &= aca->mask;
574 +      aca->port = ((struct sockaddr_in*) &aca->addr)->sin_port;
575 +      break;
576 +#ifdef INET6
577 +   case PF_INET6:
578 +      {
579 +         static char m[] = { 0x00, 0x80, 0xC0, 0xE0,
580 +                             0xF0, 0xF8, 0xFC, 0xFE };
581 +         int i;
582 +         struct sockaddr_in6 *sa6 = (struct sockaddr_in6*)&aca->addr;
583  
584 -   if ((masklength < 0) || (masklength > 32))
585 -   {
586 -      return(-1);
587 +         aca->mask = (masklength == -1) ? masklength : 128 ;
588 +         /* now mask off the host portion of the ip address
589 +          * (i.e. save on the network portion of the address).
590 +          */
591 +         i = aca->mask / 8;
592 +         if (i < 16)
593 +         {
594 +            sa6->sin6_addr.s6_addr[i] &= m[aca->mask % 8];
595 +            /* The following loop is not strictly necessary,
596 +               because of the way addr_equal_under_mask is
597 +               written. Better safe than sorry, though:
598 +               New code might make the full mask-normal
599 +               form assumption.
600 +             */
601 +            for(++i; i < 16 ; ++i)
602 +               sa6->sin6_addr.s6_addr[i] = 0;
603 +         }
604 +         aca -> port = sa6->sin6_port;
605 +         break;
606 +      }
607 +#endif
608 +   default:
609 +      /* FATAL because access_control_addr's are created only with adresses
610 +         deemed 'acceptable' by the addr_list stuff, thus currently IPv4 and
611 +         IPv6.
612 +       */
613 +      log_error(LOG_LEVEL_FATAL,"%s%d","Unknown address family in ACL address: ",pf);
614     }
615 +}
616  
617 -   if ((p = strchr(aspec, ':')) != NULL)
618 -   {
619 -      *p++ = '\0';
620 +/*********************************************************************
621 + *
622 + * Function    :  acl_addrs
623 + *
624 + * Description :  Parse an ACL address (adress + mask prefix)
625 + *                Resolve the parsed address
626 + *                Describe errors in *proxy_args.
627 + *
628 + * Parameters  :
629 + *          0  :  aspec = the string containing the ACL address/mask
630 + *          1  :  masklength = pointer used to return the mask
631 + *          2  :  proxy_args = Pointer to string to append description of errors to.
632 + *          3  :  type = type of ACL adress (source / destination).
633 + *                       Used for error reporting.
634 + *
635 + * Returns     :  the list of adresses the ACL address resolves to
636 + *
637 + *********************************************************************/
638 +static addr_list *acl_addrs(char *aspec, int *masklength, char**proxy_args, const char *type)
639 +{
640 +   char *host;
641 +   char *port;
642 +   int pf;
643  
644 -      if (ijb_isdigit(*p) == 0)
645 -      {
646 -         return(-1);
647 -      }
648 -      port = atoi(p);
649 +   pf = -1;
650 +   if (parse_pf_ip_netmask(aspec, &host, &port, &pf, masklength) != 0)
651 +   {
652 +      log_error(LOG_LEVEL_ERROR, "Invalid %s IP for (deny|permit)-access "
653 +                "directive in configuration file: \"%s\"", type, aspec);
654 +      string_append(proxy_args,"<br>\nWARNING: Invalid ");
655 +      string_append(proxy_args, type);
656 +      string_append(proxy_args," IP for (deny|permit)-access directive"
657 +                    " in configuration file: \"");
658 +      string_append(proxy_args, aspec);
659 +      string_append(proxy_args,"\"<br><br>\n");
660 +      return NULL;
661     }
662  
663 -   aca->port = port;
664 +   return resolve_hostname_to_ip(host, port, pf);
665 +}
666  
667 -   aca->addr = ntohl(resolve_hostname_to_ip(aspec));
668 +/*********************************************************************
669 + *
670 + * Function    :  add_one_to_acl_list
671 + *
672 + * Description :  Add one entry to an access_control_list.
673 + *
674 + * Parameters  :
675 + *          0  :  l = the list to add to
676 + *          1  :  action = ACL_DENY or ACL_PERMIT
677 + *          2  :  src_addrs = the head of this list will be used as source
678 + *                            in the ACL entry.
679 + *          3  :  dst_addrs = the head of this list will be used as destination
680 + *                            in the ACL entry.
681 + *                            NULL for none
682 + *          4  :  src_masklength = mask length for the source
683 + *          5  :  src_masklength = mask length for the destination
684 + *
685 + * Returns     :  the new list
686 + *
687 + *********************************************************************/
688 +struct access_control_list *add_one_to_acl_list(struct access_control_list *l, short action,
689 +                                                addr_list *src_addrs, addr_list *dst_addrs,
690 +                                                int src_masklength, int dst_masklength)
691 +{
692 +   struct access_control_list *cur_acl;
693 +   /* allocate a new node */
694 +   cur_acl = (struct access_control_list *) zalloc(sizeof(*cur_acl));
695  
696 -   if (aca->addr == INADDR_NONE)
697 +   if (cur_acl == NULL)
698     {
699 -      return(-1);
700 +      log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
701 +      /* Never get here - LOG_LEVEL_FATAL causes program exit */
702 +      return l;
703     }
704  
705 -   /* build the netmask */
706 -   aca->mask = 0;
707 -   for (i=1; i <= masklength ; i++)
708 +   cur_acl->action = action;
709 +
710 +   cpy_head_addr_list(src_addrs, &cur_acl->src->addr, &cur_acl->src->addrlen);
711 +   fill_acl_addr_mask(cur_acl->src, src_masklength);
712 +   if (dst_addrs != NULL)
713     {
714 -      aca->mask |= (1 << (32 - i));
715 +      cpy_head_addr_list(dst_addrs, &cur_acl->dst->addr, &cur_acl->dst->addrlen);
716 +      fill_acl_addr_mask(cur_acl->src, src_masklength);
717     }
718  
719 -   /* now mask off the host portion of the ip address
720 -    * (i.e. save on the network portion of the address).
721 +   /*
722 +    * Add it to the list.  Note we reverse the list to get the
723 +    * behaviour the user expects.  With both the ACL and
724 +    * actions file, the last match wins.  However, the internal
725 +    * implementations are different:  The actions file is stored
726 +    * in the same order as the file, and scanned completely.
727 +    * With the ACL, we reverse the order as we load it, then
728 +    * when we scan it we stop as soon as we get a match.
729      */
730 -   aca->addr = aca->addr & aca->mask;
731 +   cur_acl->next  = l;
732  
733 -   return(0);
734 +   return cur_acl;
735 +}
736 +
737 +/*********************************************************************
738 + *
739 + * Function    :  add_to_acl_list
740 + *
741 + * Description :  Add entries to an access_control_list.
742 + *                Describe errors in *proxy_args.
743 + *
744 + * Parameters  :
745 + *          0  :  l = the list to add to
746 + *          1  :  action = ACL_DENY or ACL_PERMIT
747 + *          2  :  src_spec = String giving the source of the acl entry
748 + *          3  :  dst_spec = String giving the destination of the acl entry,
749 + *                           or NULL
750 + *          4  :  proxy_args = Pointer to string to append description of errors to.
751 + *
752 + * Returns     :  the new list
753 + *
754 + *********************************************************************/
755 +struct access_control_list *add_to_acl_list(struct access_control_list *l,
756 +                                            short action,
757 +                                            char *src_spec,
758 +                                            char *dst_spec,
759 +                                            char **proxy_args)
760 +{
761 +   int src_masklength, dst_masklength;
762 +   addr_list *src_addrs, *dst_addrs;
763 +   addr_list *src_addrs_remaining, *dst_addrs_remaining;
764 +
765 +   src_addrs = acl_addrs(src_spec, &src_masklength, proxy_args, "source");
766 +   if (is_nil_addr_list(src_addrs))
767 +   {
768 +      log_error(LOG_LEVEL_ERROR, "Source of ACL resolves to no address",dst_spec);
769 +      return l;
770 +   }
771 +   if (dst_spec != NULL)
772 +   {
773 +      dst_addrs = acl_addrs(dst_spec, &dst_masklength, proxy_args, "destination");
774 +      if (is_nil_addr_list(dst_addrs))
775 +      {
776 +         log_error(LOG_LEVEL_ERROR, "Destination of ACL resolves to no address",dst_spec);
777 +         destroy_addr_list(src_addrs);
778 +         return l;
779 +      }
780 +   }
781 +   else
782 +      dst_addrs = NULL;
783 +
784 +   for(src_addrs_remaining = src_addrs;
785 +       is_nil_addr_list(src_addrs);
786 +       src_addrs_remaining=tail_addr_list(src_addrs_remaining))
787 +   {
788 +      if (dst_addrs == NULL)
789 +         l = add_one_to_acl_list(l, action, src_addrs_remaining, NULL, src_masklength,0);
790 +      else for(dst_addrs_remaining = dst_addrs;
791 +               is_nil_addr_list(dst_addrs);
792 +               dst_addrs_remaining=tail_addr_list(dst_addrs_remaining))
793 +         l = add_one_to_acl_list(l, action, src_addrs_remaining, dst_addrs_remaining,
794 +                                 src_masklength, dst_masklength);
795 +   }
796 +   destroy_addr_list(src_addrs);
797 +   destroy_addr_list(dst_addrs);
798  
799 +   return l;
800  }
801 -#endif /* def FEATURE_ACL */
802  
803 +#endif /* def FEATURE_ACL */
804  
805  /*********************************************************************
806   *
807 diff -urNad privoxy~/filters.h privoxy/filters.h
808 --- privoxy~/filters.h
809 +++ privoxy/filters.h
810 @@ -15,6 +15,9 @@
811   * Copyright   :  Written by and Copyright (C) 2001, 2004 the SourceForge
812   *                Privoxy team. http://www.privoxy.org/
813   *
814 + *                Modified by Lionel Elie Mamane <lionel@mamane.lu>
815 + *                for IPv6 support on 8 December 2002, 24 January 2003.
816 + *
817   *                Based on the Internet Junkbuster originally written
818   *                by and Copyright (C) 1997 Anonymous Coders and 
819   *                Junkbusters Corporation.  http://www.junkbusters.com
820 @@ -234,7 +237,11 @@
821   */
822  #ifdef FEATURE_ACL
823  extern int block_acl(struct access_control_addr *dst, struct client_state *csp);
824 -extern int acl_addr(char *aspec, struct access_control_addr *aca);
825 +extern struct access_control_list *add_to_acl_list(struct access_control_list *l,
826 +                                                   short action,
827 +                                                   char *src_spec,
828 +                                                   char *dst_spec,
829 +                                                   char **proxy_args);
830  #endif /* def FEATURE_ACL */
831  extern int match_portlist(const char *portlist, int port);
832  
833 diff -urNad privoxy~/gateway.c privoxy/gateway.c
834 --- privoxy~/gateway.c
835 +++ privoxy/gateway.c
836 @@ -10,6 +10,9 @@
837   * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
838   *                Privoxy team. http://www.privoxy.org/
839   *
840 + *                Modified by Lionel Elie Mamane <lionel@mamane.lu>
841 + *                for IPv6 support on 8 December 2002, 24 January 2003.
842 + *
843   *                Based on the Internet Junkbuster originally written
844   *                by and Copyright (C) 1997 Anonymous Coders and
845   *                Junkbusters Corporation.  http://www.junkbusters.com
846 @@ -203,12 +206,14 @@
847   * Returns     :  JB_INVALID_SOCKET => failure, else it is the socket file descriptor.
848   *
849   *********************************************************************/
850 -jb_socket forwarded_connect(const struct forward_spec * fwd,
851 +jb_socket forwarded_connect(const struct forward_spec *fwd,
852                              struct http_request *http,
853                              struct client_state *csp)
854  {
855     const char * dest_host;
856 -   int dest_port;
857 +   const char * dest_port_str;
858 +   unsigned long dest_port;
859 +   int dest_pf;
860  
861     /* Figure out if we need to connect to the web server or a HTTP proxy. */
862     if (fwd->forward_host)
863 @@ -216,19 +221,23 @@
864        /* HTTP proxy */
865        dest_host = fwd->forward_host;
866        dest_port = fwd->forward_port;
867 +      dest_port_str = fwd->forward_port_str;
868 +      dest_pf = fwd->forward_family;
869     }
870     else
871     {
872        /* Web server */
873        dest_host = http->host;
874        dest_port = http->port;
875 +      dest_port_str = http->port_str;
876 +      dest_pf = PF_UNSPEC;
877     }
878  
879     /* Connect, maybe using a SOCKS proxy */
880     switch (fwd->type)
881     {
882        case SOCKS_NONE:
883 -         return (connect_to(dest_host, dest_port, csp));
884 +         return (connect_to(dest_host, dest_port_str, dest_port, dest_pf, csp));
885  
886        case SOCKS_4:
887        case SOCKS_4A:
888 @@ -262,74 +271,19 @@
889   * Returns     :  JB_INVALID_SOCKET => failure, else a socket file descriptor.
890   *
891   *********************************************************************/
892 -static jb_socket socks4_connect(const struct forward_spec * fwd,
893 -                                const char * target_host,
894 -                                int target_port,
895 -                                struct client_state *csp)
896 +static jb_socket socks4_connect_one_ip(const struct forward_spec * fwd,
897 +                                       unsigned long web_server_addr,
898 +                                       int target_port,
899 +                                       struct client_state *csp,
900 +                                       size_t csiz,
901 +                                       char *cbuf)
902  {
903 -   int web_server_addr;
904 -   char cbuf[BUFFER_SIZE];
905     char sbuf[BUFFER_SIZE];
906 -   struct socks_op    *c = (struct socks_op    *)cbuf;
907     struct socks_reply *s = (struct socks_reply *)sbuf;
908 -   size_t n;
909 -   size_t csiz;
910 +   struct socks_reply *c = (struct socks_reply *)cbuf;
911     jb_socket sfd;
912 -   int err = 0;
913     char *errstr;
914  
915 -   if ((fwd->gateway_host == NULL) || (*fwd->gateway_host == '\0'))
916 -   {
917 -      log_error(LOG_LEVEL_CONNECT, "socks4_connect: NULL gateway host specified");
918 -      err = 1;
919 -   }
920 -
921 -   if (fwd->gateway_port <= 0)
922 -   {
923 -      log_error(LOG_LEVEL_CONNECT, "socks4_connect: invalid gateway port specified");
924 -      err = 1;
925 -   }
926 -
927 -   if (err)
928 -   {
929 -      errno = EINVAL;
930 -      return(JB_INVALID_SOCKET);
931 -   }
932 -
933 -   /* build a socks request for connection to the web server */
934 -
935 -   strcpy((char *)&(c->userid), socks_userid);
936 -
937 -   csiz = sizeof(*c) + sizeof(socks_userid) - 1;
938 -
939 -   switch (fwd->type)
940 -   {
941 -      case SOCKS_4:
942 -         web_server_addr = htonl(resolve_hostname_to_ip(target_host));
943 -         if (web_server_addr == INADDR_NONE)
944 -         {
945 -            log_error(LOG_LEVEL_CONNECT, "socks4_connect: could not resolve target host %s", target_host);
946 -            return(JB_INVALID_SOCKET);
947 -         }
948 -         break;
949 -      case SOCKS_4A:
950 -         web_server_addr = 0x00000001;
951 -         n = csiz + strlen(target_host) + 1;
952 -         if (n > sizeof(cbuf))
953 -         {
954 -            errno = EINVAL;
955 -            return(JB_INVALID_SOCKET);
956 -         }
957 -         strcpy(cbuf + csiz, target_host);
958 -         csiz = n;
959 -         break;
960 -      default:
961 -         /* Should never get here */
962 -         log_error(LOG_LEVEL_FATAL, "SOCKS4 impossible internal error - bad SOCKS type.");
963 -         errno = EINVAL;
964 -         return(JB_INVALID_SOCKET);
965 -   }
966 -
967     c->vn          = 4;
968     c->cd          = 1;
969     c->dstport[0]  = (target_port       >> 8  ) & 0xff;
970 @@ -340,7 +294,7 @@
971     c->dstip[3]    = (web_server_addr         ) & 0xff;
972  
973     /* pass the request to the socks server */
974 -   sfd = connect_to(fwd->gateway_host, fwd->gateway_port, csp);
975 +   sfd = connect_to(fwd->gateway_host, fwd->gateway_port_str, fwd->gateway_port, PF_INET ,csp);
976  
977     if (sfd == JB_INVALID_SOCKET)
978     {
979 @@ -395,6 +349,92 @@
980  
981  }
982  
983 +static jb_socket socks4_connect(const struct forward_spec * fwd,
984 +                                const char * target_host,
985 +                                int target_port,
986 +                                struct client_state *csp)
987 +{
988 +   char cbuf[BUFFER_SIZE];
989 +   struct socks_op    *c = (struct socks_op    *)cbuf;
990 +   size_t csiz;
991 +   int err = 0;
992 +
993 +   /**
994 +    * SOCKS4 is IPv4-specific. At least I think so.
995 +    */
996 +   if ((fwd->gateway_host == NULL) || (*fwd->gateway_host == '\0'))
997 +   {
998 +      log_error(LOG_LEVEL_CONNECT, "socks4_connect: NULL gateway host specified");
999 +      err = 1;
1000 +   }
1001 +
1002 +   if (fwd->gateway_port <= 0)
1003 +   {
1004 +      log_error(LOG_LEVEL_CONNECT, "socks4_connect: invalid gateway port specified");
1005 +      err = 1;
1006 +   }
1007 +
1008 +   if (err)
1009 +   {
1010 +      errno = EINVAL;
1011 +      return(JB_INVALID_SOCKET);
1012 +   }
1013 +
1014 +   /* build a socks request for connection to the web server */
1015 +
1016 +   strcpy((char *)&(c->userid), socks_userid);
1017 +
1018 +   csiz = sizeof(*c) + sizeof(socks_userid) - 1;
1019 +
1020 +   switch (fwd->type)
1021 +   {
1022 +      case SOCKS_4:
1023 +      {
1024 +         addr_list *web_server_addrs = resolve_hostname_to_ip(target_host,NULL,PF_INET);
1025 +         jb_socket return_value = JB_INVALID_SOCKET;
1026 +         if (is_nil_addr_list(web_server_addrs))
1027 +         {
1028 +            log_error(LOG_LEVEL_CONNECT, "socks4_connect: could not resolve target host %s", target_host);
1029 +         }
1030 +         else
1031 +         {
1032 +            addr_list *addrs_to_try;
1033 +            
1034 +            for(addrs_to_try = web_server_addrs;
1035 +                !is_nil_addr_list(addrs_to_try);
1036 +                addrs_to_try = tail_addr_list(addrs_to_try))
1037 +            {
1038 +               const unsigned long web_server_addr = ((struct sockaddr_in*) head_addr_list(addrs_to_try))->sin_addr.s_addr;
1039 +               return_value=socks4_connect_one_ip(fwd, web_server_addr, target_port, csp, csiz, cbuf);
1040 +               if(return_value != JB_INVALID_SOCKET)
1041 +                  break;
1042 +            }
1043 +         }
1044 +         destroy_addr_list(web_server_addrs);
1045 +         return return_value;
1046 +         break;
1047 +      }
1048 +      case SOCKS_4A:
1049 +      {
1050 +         size_t n;
1051 +         n = csiz + strlen(target_host) + 1;
1052 +         if (n > sizeof(cbuf))
1053 +         {
1054 +            errno = EINVAL;
1055 +            return(JB_INVALID_SOCKET);
1056 +         }
1057 +         strcpy(cbuf + csiz, target_host);
1058 +         csiz = n;
1059 +         return socks4_connect_one_ip(fwd, 0x00000001, target_port, csp, csiz, cbuf);
1060 +         break;
1061 +      }
1062 +      default:
1063 +         /* Should never get here */
1064 +         log_error(LOG_LEVEL_FATAL, "SOCKS4 impossible internal error - bad SOCKS type.");
1065 +         errno = EINVAL;
1066 +         return(JB_INVALID_SOCKET);
1067 +   }
1068 +}
1069  
1070  /*
1071    Local Variables:
1072 diff -urNad privoxy~/jb_socket_set.c privoxy/jb_socket_set.c
1073 --- privoxy~/jb_socket_set.c
1074 +++ privoxy/jb_socket_set.c
1075 @@ -0,0 +1,174 @@
1076 +const char jb_socket_set_rcs[] = "$Id: $";
1077 +/*********************************************************************
1078 + *
1079 + * File        :  $Source: $
1080 + *
1081 + * Purpose     :  Declares functions to handle sets of sockets
1082 + *
1083 + * Copyright   :  Written by and Copyright (C) 2002 Lionel Elie Mamane
1084 + *                <lionel@mamane.lu>
1085 + *
1086 + *                This program is free software; you can redistribute it
1087 + *                and/or modify it under the terms of the GNU General
1088 + *                Public License as published by the Free Software
1089 + *                Foundation; either version 2 of the License, or (at
1090 + *                your option) any later version.
1091 + *
1092 + *                This program is distributed in the hope that it will
1093 + *                be useful, but WITHOUT ANY WARRANTY; without even the
1094 + *                implied warranty of MERCHANTABILITY or FITNESS FOR A
1095 + *                PARTICULAR PURPOSE.  See the GNU General Public
1096 + *                License for more details.
1097 + *
1098 + *                The GNU General Public License should be included with
1099 + *                this file.  If not, you can view it at
1100 + *                http://www.gnu.org/copyleft/gpl.html
1101 + *                or write to the Free Software Foundation, Inc., 59
1102 + *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
1103 + *
1104 + * Revisions   :
1105 + *    $Log: jb_socket_set.c,v $
1106 + *
1107 + *********************************************************************/
1108 +
1109 +#include "jb_socket_set.h"
1110 +#include <sys/time.h>
1111 +#include <sys/types.h>
1112 +#include <unistd.h>
1113 +#include "project.h"
1114 +
1115 +/*********************************************************************
1116 + *
1117 + * Function    :  jb_socket_set_add
1118 + *
1119 + * Description :  Add a socket to the set
1120 + *
1121 + * Parameters  :
1122 + *          0  :  l = the set to add to
1123 + *          1  :  the elemen to add to the set
1124 + *
1125 + * Returns     :  0 on success
1126 + *                non-0 on failure
1127 + *
1128 + *********************************************************************/
1129 +
1130 +int jb_socket_set_add(jb_socket_set *l, jb_socket e)
1131 +{
1132 +   if (l->data==NULL)
1133 +   {
1134 +      l->size=2;
1135 +      l->data=malloc(l->size * sizeof(jb_socket));
1136 +      if (l->data==NULL)
1137 +      {
1138 +         l->size = 0;
1139 +         return -1;
1140 +      }
1141 +      l->occupied=0;
1142 +   }
1143 +   l->data[(l->occupied)++] = e;
1144 +   if (l->occupied == l->size)
1145 +   {
1146 +      jb_socket *new_data;
1147 +      l->size *= 2;
1148 +      new_data = realloc(l->data,l->size * sizeof(jb_socket));
1149 +      if (new_data == NULL)
1150 +      {
1151 +         /* Not enough memory to continue. Cancel changes. */
1152 +         l->data[--(l->occupied)] = JB_INVALID_SOCKET;
1153 +         l->size /= 2;
1154 +         return -1;
1155 +      }
1156 +      l->data = new_data;
1157 +   }
1158 +   l->data[l->occupied] = JB_INVALID_SOCKET;
1159 +   return 0;
1160 +}
1161 +
1162 +/*********************************************************************
1163 + *
1164 + * Function    :  destroy_jb_socket_set
1165 + *
1166 + * Description :  Unallocate memory allocated to a socket set
1167 + *
1168 + * Parameters  :
1169 + *          0  :  l = the set to unallocate
1170 + *
1171 + * Returns     :  nothing
1172 + *
1173 + *********************************************************************/
1174 +void destroy_jb_socket_set(jb_socket_set *l)
1175 +{
1176 +   free(l->data);
1177 +   init_jb_socket_set(l);
1178 +}
1179 +/*********************************************************************
1180 + *
1181 + * Function    :  is_empty_jb_socket_set
1182 + *
1183 + * Description :  Test wheter a set is empty
1184 + *
1185 + * Parameters  :
1186 + *          0  :  l = the set to test
1187 + *
1188 + * Returns     :  0             = false if set has a head,
1189 + *                anything else = true if set is nil
1190 + *
1191 + *********************************************************************/
1192 +int is_nil_jb_socket_set(jb_socket_set *l)
1193 +{
1194 +   return (l->occupied == 0);
1195 +}
1196 +
1197 +/*********************************************************************
1198 + *
1199 + * Function    :  init_jb_socket_set
1200 + *
1201 + * Description :  Init a set to empty
1202 + *
1203 + * Parameters  :
1204 + *          0  :  l = the set to init
1205 + *
1206 + *********************************************************************/
1207 +void init_jb_socket_set(jb_socket_set *l)
1208 +{
1209 +   l->data=NULL;
1210 +   l->size=0;
1211 +   l->occupied=0;
1212 +}
1213 +
1214 +/*********************************************************************
1215 + *
1216 + * Function    :  jb_socket_set_iteration_begin
1217 + *
1218 + * Description :  Return an iterator on the set
1219 + *
1220 + * Parameters  :
1221 + *          0  :  l = the set
1222 + *
1223 + *********************************************************************/
1224 +jb_socket_set_iterate_state jb_socket_set_iteration_begin(jb_socket_set *l)
1225 +{
1226 +   return l->data;
1227 +}
1228 +
1229 +/*********************************************************************
1230 + *
1231 + * Function    :  jb_socket_set_iteration_next
1232 + *
1233 + * Description :  Return value pointed to by iterator and step
1234 + *                iterator to next position
1235 + *
1236 + * Parameters  :
1237 + *          0  :  s = the iterator
1238 + *
1239 + *********************************************************************/
1240 +jb_socket jb_socket_set_iteration_next(jb_socket_set_iterate_state*s)
1241 +{
1242 +   return(*((*s)++));
1243 +}
1244 +
1245 +/*
1246 +  Local Variables:
1247 +  tab-width: 3
1248 +  end:
1249 +*/
1250 diff -urNad privoxy~/jb_socket_set.h privoxy/jb_socket_set.h
1251 --- privoxy~/jb_socket_set.h
1252 +++ privoxy/jb_socket_set.h
1253 @@ -0,0 +1,71 @@
1254 +#ifndef JB_SOCKET_SET_H_INCLUDED
1255 +#define JB_SOCKET_SET_H_INCLUDED
1256 +#define JB_SOCKET_SET_H_VERSION "$Id: $"
1257 +/*********************************************************************
1258 + *
1259 + * File        :  $Source: $
1260 + *
1261 + * Purpose     :  Declares functions to handle sets of sockets
1262 + *
1263 + * Copyright   :  Written by and Copyright (C) 2002 Lionel Elie Mamane
1264 + *                <lionel@mamane.lu>
1265 + *
1266 + *                This program is free software; you can redistribute it
1267 + *                and/or modify it under the terms of the GNU General
1268 + *                Public License as published by the Free Software
1269 + *                Foundation; either version 2 of the License, or (at
1270 + *                your option) any later version.
1271 + *
1272 + *                This program is distributed in the hope that it will
1273 + *                be useful, but WITHOUT ANY WARRANTY; without even the
1274 + *                implied warranty of MERCHANTABILITY or FITNESS FOR A
1275 + *                PARTICULAR PURPOSE.  See the GNU General Public
1276 + *                License for more details.
1277 + *
1278 + *                The GNU General Public License should be included with
1279 + *                this file.  If not, you can view it at
1280 + *                http://www.gnu.org/copyleft/gpl.html
1281 + *                or write to the Free Software Foundation, Inc., 59
1282 + *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
1283 + *
1284 + * Revisions   :
1285 + *    $Log: jb_socket_set.h,v $
1286 + *
1287 + *********************************************************************/
1288 +#include <sys/time.h>
1289 +#include <sys/types.h>
1290 +#include <unistd.h>
1291 +#include "project.h"
1292 +
1293 +struct jb_socket_set_struct
1294 +{
1295 +   unsigned int size; /* size allocated*/
1296 +   unsigned int occupied; /* size occupied - 1 == index of final JB_INVALID_SOCKET
1297 +                             == number of sockets in the set */
1298 +   jb_socket *data; /* Array containing the sockets, JB_INVALID_SOCKET-terminated */
1299 +};
1300 +
1301 +typedef struct jb_socket_set_struct jb_socket_set;
1302 +typedef const jb_socket* jb_socket_set_iterate_state;
1303 +
1304 +void init_jb_socket_set(jb_socket_set*);
1305 +
1306 +jb_socket_set_iterate_state jb_socket_set_iteration_begin(jb_socket_set *);
1307 +jb_socket jb_socket_set_iteration_next(jb_socket_set_iterate_state*);
1308 +
1309 +int jb_socket_set_add(jb_socket_set*, jb_socket);
1310 +
1311 +void destroy_jb_socket_set(jb_socket_set *l);
1312 +int is_empty_jb_socket_set(jb_socket_set *l);
1313 +
1314 +#define freez_jb_socket_set(X)  { if(X) { destroy_jb_socket_set(X); X = NULL ; } }
1315 +
1316 +int jb_select(jb_socket_set *readfds, jb_socket_set *writefds, jb_socket_set *exceptfds, struct timeval *timeout);
1317 +
1318 +#endif /* ndef JB_SOCKET_SET_H_INCLUDED */
1319 +
1320 +/*
1321 +  Local Variables:
1322 +  tab-width: 3
1323 +  end:
1324 +*/
1325 diff -urNad privoxy~/jbsockets.c privoxy/jbsockets.c
1326 --- privoxy~/jbsockets.c
1327 +++ privoxy/jbsockets.c
1328 @@ -11,6 +11,10 @@
1329   * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
1330   *                Privoxy team. http://www.privoxy.org/
1331   *
1332 + *                Modified by Lionel Elie Mamane <lionel@mamane.lu>
1333 + *                for IPv6 support on 8-9 December 2002, 24 January 2003,
1334 + *                13 February 2003.
1335 + *
1336   *                Based on the Internet Junkbuster originally written
1337   *                by and Copyright (C) 1997 Anonymous Coders and 
1338   *                Junkbusters Corporation.  http://www.junkbusters.com
1339 @@ -275,6 +279,7 @@
1340  #include "jbsockets.h"
1341  #include "filters.h"
1342  #include "errlog.h"
1343 +#include "addrlist.h"
1344  
1345  const char jbsockets_h_rcs[] = JBSOCKETS_H_VERSION;
1346  
1347 @@ -287,141 +292,194 @@
1348   *                that this is allowed according to ACL.
1349   *
1350   * Parameters  :
1351 - *          1  :  host = hostname to connect to
1352 - *          2  :  portnum = port to connent on
1353 + *          0  :  host = hostname to connect to
1354 + *          1  :  port = port to connect on, as string
1355 + *          2  :  portnum = port to connect on, as integer
1356   *          3  :  csp = Current client state (buffers, headers, etc...)
1357 - *                      Not modified, only used for source IP and ACL.
1358   *
1359   * Returns     :  JB_INVALID_SOCKET => failure, else it is the socket
1360   *                file descriptor.
1361   *
1362   *********************************************************************/
1363 -jb_socket connect_to(const char *host, int portnum, struct client_state *csp)
1364 +jb_socket connect_to_one_ip(struct sockaddr_storage *addr, size_t addrlen, const char *host, unsigned long portnum, struct client_state *csp)
1365  {
1366 -   struct sockaddr_in inaddr;
1367 -   jb_socket fd;
1368 -   int addr;
1369 -   fd_set wfds;
1370 -   struct timeval tv[1];
1371 -#if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA)
1372 -   int   flags;
1373 -#endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) */
1374 -
1375  #ifdef FEATURE_ACL
1376 -   struct access_control_addr dst[1];
1377 -#endif /* def FEATURE_ACL */
1378 -
1379 -   memset((char *)&inaddr, 0, sizeof inaddr);
1380 -
1381 -   if ((addr = resolve_hostname_to_ip(host)) == INADDR_NONE)
1382 +   if (csp)
1383     {
1384 -      csp->http->host_ip_addr_str = strdup("unknown");
1385 -      return(JB_INVALID_SOCKET);
1386 -   }
1387 +      struct access_control_addr dst[1];
1388 +      char hostname[NI_MAXHOST];
1389 +      char port[NI_MAXSERV];
1390 +      if (getnameinfo((struct sockaddr*)addr, addrlen, hostname, NI_MAXHOST,
1391 +                      port, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV) != 0)
1392 +      {
1393 +         log_error(LOG_LEVEL_ERROR, "connect: Could not get string address and port back from sockaddr because %E");
1394 +         strncpy(hostname,"unknown",NI_MAXHOST);
1395 +         strncpy(port,"unknown",NI_MAXSERV);
1396 +      }
1397  
1398 -#ifdef FEATURE_ACL
1399 -   dst->addr = ntohl((unsigned long) addr);
1400 -   dst->port = portnum;
1401 +      csp->http->host_ip_addr_str = strdup(hostname);
1402  
1403 -   if (block_acl(dst, csp))
1404 -   {
1405 +      dst->addr = *addr;
1406 +      dst->addrlen = addrlen;
1407 +      dst->port = portnum;
1408 +
1409 +      if (block_acl(dst, csp))
1410 +      {
1411  #ifdef __OS2__
1412 -      errno = SOCEPERM;
1413 +         errno = SOCEPERM;
1414  #else
1415 -      errno = EPERM;
1416 +         errno = EPERM;
1417  #endif
1418 -      return(JB_INVALID_SOCKET);
1419 -   }
1420 -#endif /* def FEATURE_ACL */
1421 +         return(JB_INVALID_SOCKET);
1422 +      }
1423  
1424 -   inaddr.sin_addr.s_addr = addr;
1425 -   inaddr.sin_family      = AF_INET;
1426 -   csp->http->host_ip_addr_str = strdup(inet_ntoa(inaddr.sin_addr));
1427  
1428 -#ifndef _WIN32
1429 -   if (sizeof(inaddr.sin_port) == sizeof(short))
1430 -#endif /* ndef _WIN32 */
1431 -   {
1432 -      inaddr.sin_port = htons((unsigned short) portnum);
1433     }
1434 -#ifndef _WIN32
1435 -   else
1436 +#endif /* def FEATURE_ACL */
1437 +
1438     {
1439 -      inaddr.sin_port = htonl((unsigned long)portnum);
1440 -   }
1441 -#endif /* ndef _WIN32 */
1442 +      jb_socket fd;
1443  
1444  #ifdef _WIN32
1445 -   if ((fd = socket(inaddr.sin_family, SOCK_STREAM, 0)) == JB_INVALID_SOCKET)
1446 +      if ((fd = socket(addr->ss_family, SOCK_STREAM, 0)) == JB_INVALID_SOCKET)
1447  #else
1448 -   if ((fd = socket(inaddr.sin_family, SOCK_STREAM, 0)) < 0)
1449 +      if ((fd = socket(addr->ss_family, SOCK_STREAM, 6)) < 0)
1450  #endif
1451 -   {
1452 -      return(JB_INVALID_SOCKET);
1453 -   }
1454 +      {
1455 +         return(JB_INVALID_SOCKET);
1456 +      }
1457  
1458  #ifdef TCP_NODELAY
1459 -   {  /* turn off TCP coalescence */
1460 -      int mi = 1;
1461 -      setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &mi, sizeof (int));
1462 -   }
1463 +      {  /* turn off TCP coalescence */
1464 +         int mi = 1;
1465 +         setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, (char *) &mi, sizeof (int));
1466 +      }
1467  #endif /* def TCP_NODELAY */
1468  
1469  #if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__)
1470 -   if ((flags = fcntl(fd, F_GETFL, 0)) != -1)
1471 -   {
1472 -      flags |= O_NDELAY;
1473 -      fcntl(fd, F_SETFL, flags);
1474 -   }
1475 +      {
1476 +         int flags;
1477 +
1478 +         if ((flags = fcntl(fd, F_GETFL, 0)) != -1)
1479 +         {
1480 +            flags |= O_NDELAY;
1481 +            fcntl(fd, F_SETFL, flags);
1482 +         }
1483 +      }
1484  #endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) */
1485  
1486 -   while (connect(fd, (struct sockaddr *) & inaddr, sizeof inaddr) == JB_INVALID_SOCKET)
1487 -   {
1488 +      while (connect(fd, (struct sockaddr *) addr, addrlen) == JB_INVALID_SOCKET)
1489 +      {
1490  #ifdef _WIN32
1491 -      if (errno == WSAEINPROGRESS)
1492 +         if (errno == WSAEINPROGRESS)
1493  #elif __OS2__ 
1494 -      if (sock_errno() == EINPROGRESS)
1495 +         if (sock_errno() == EINPROGRESS)
1496  #else /* ifndef _WIN32 */
1497 -      if (errno == EINPROGRESS)
1498 +         if (errno == EINPROGRESS)
1499  #endif /* ndef _WIN32 || __OS2__ */
1500 -      {
1501 -         break;
1502 -      }
1503 +         {
1504 +            break;
1505 +         }
1506  
1507  #ifdef __OS2__ 
1508 -      if (sock_errno() != EINTR)
1509 +         if (sock_errno() != EINTR)
1510  #else
1511 -      if (errno != EINTR)
1512 +         if (errno != EINTR)
1513  #endif /* __OS2__ */
1514 +         {
1515 +            close_socket(fd);
1516 +            return(JB_INVALID_SOCKET);
1517 +         }
1518 +      }
1519 +
1520 +#if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__)
1521        {
1522 -         close_socket(fd);
1523 -         return(JB_INVALID_SOCKET);
1524 +         int flags;
1525 +         if ((flags = fcntl(fd, F_GETFL, 0)) != -1)
1526 +         {
1527 +            flags &= ~O_NDELAY;
1528 +            fcntl(fd, F_SETFL, flags);
1529 +         }
1530        }
1531 -   }
1532 +#endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) */
1533  
1534 +      {
1535 +         fd_set wfds;
1536 +         struct timeval tv[1];
1537 +
1538 +         /* wait for connection to complete */
1539 +         FD_ZERO(&wfds);
1540 +         FD_SET(fd, &wfds);
1541 +
1542 +         tv->tv_sec  = 30;
1543 +         tv->tv_usec = 0;
1544 +
1545 +         /* MS Windows uses int, not SOCKET, for the 1st arg of select(). Wierd! */
1546 +         if (select((int)fd + 1, NULL, &wfds, NULL, tv) <= 0)
1547 +         {
1548 +            close_socket(fd);
1549 +            return(JB_INVALID_SOCKET);
1550 +         }
1551  #if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__)
1552 -   if (flags != -1)
1553 -   {
1554 -      flags &= ~O_NDELAY;
1555 -      fcntl(fd, F_SETFL, flags);
1556 -   }
1557 +         else
1558 +         {
1559 +            int connect_result;
1560 +            socklen_t connect_result_len = sizeof connect_result;
1561 +
1562 +            if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &connect_result, &connect_result_len) != 0)
1563 +            {
1564 +               log_error(LOG_LEVEL_ERROR, "Could not determine whether connection to %s port %d was successful because %E. Assuming failure.",
1565 +                         csp->http->host_ip_addr_str, portnum);
1566 +               close_socket(fd);
1567 +               return(JB_INVALID_SOCKET);
1568 +            }
1569 +            else if( connect_result != 0 )
1570 +            {
1571 +               log_error(LOG_LEVEL_CONNECT, "Connection to %s port %d failed because %s.",
1572 +                         csp->http->host_ip_addr_str, portnum, strerror(connect_result));
1573 +               close_socket(fd);
1574 +               return(JB_INVALID_SOCKET);
1575 +            }
1576 +         }
1577  #endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) */
1578 +      }
1579 +      return(fd);
1580 +   }
1581 +}
1582  
1583 -   /* wait for connection to complete */
1584 -   FD_ZERO(&wfds);
1585 -   FD_SET(fd, &wfds);
1586 +jb_socket connect_to(const char *host, const char *port, unsigned long portnum, int pf, struct client_state *csp)
1587 +{
1588 +   jb_socket fd = JB_INVALID_SOCKET;
1589 +   struct sockaddr_storage addr;
1590 +   addr_list *addrs, *addrs_to_try;
1591  
1592 -   tv->tv_sec  = 30;
1593 -   tv->tv_usec = 0;
1594 +   addrs = resolve_hostname_to_ip(host,port,pf);
1595  
1596 -   /* MS Windows uses int, not SOCKET, for the 1st arg of select(). Wierd! */
1597 -   if (select((int)fd + 1, NULL, &wfds, NULL, tv) <= 0)
1598 +   if (is_nil_addr_list(addrs))
1599     {
1600 -      close_socket(fd);
1601 -      return(JB_INVALID_SOCKET);
1602 +      errno = EINVAL;
1603 +      return fd;
1604 +   }
1605 +
1606 +   for(addrs_to_try=addrs;
1607 +       !is_nil_addr_list(addrs_to_try);
1608 +       addrs_to_try = tail_addr_list(addrs_to_try))
1609 +   {
1610 +      size_t addrlen;
1611 +      memset((char *)&addr, 0, sizeof addr);
1612 +      cpy_head_addr_list(addrs_to_try, &addr,&addrlen);
1613 +      fd = connect_to_one_ip(&addr, addrlen, host, portnum, csp);
1614 +      if (fd != JB_INVALID_SOCKET)
1615 +         break;
1616     }
1617 -   return(fd);
1618  
1619 +   if (fd == JB_INVALID_SOCKET)
1620 +   {
1621 +      csp->http->host_ip_addr_str = strdup("unknown");
1622 +   }
1623 +
1624 +   destroy_addr_list(addrs);
1625 +   return fd;
1626  }
1627  
1628  
1629 @@ -561,55 +619,30 @@
1630  
1631  /*********************************************************************
1632   *
1633 - * Function    :  bind_port
1634 + * Function    :  bind_port_one_ip
1635   *
1636   * Description :  Call socket, set socket options, and listen.
1637 - *                Called by listen_loop to "boot up" our proxy address.
1638   *
1639   * Parameters  :
1640 - *          1  :  hostnam = TCP/IP address to bind/listen to
1641 - *          2  :  portnum = port to listen on
1642 - *          3  :  pfd = pointer used to return file descriptor.
1643 + *          0  :  addr = TCP/IP address and port to bind/listen to
1644 + *          1  :  fds = jb_socket_set where the new socket should go
1645   *
1646 - * Returns     :  if success, returns 0 and sets *pfd.
1647 + * Returns     :  if success returns 0 and adds sockets to fds.
1648   *                if failure, returns -3 if address is in use,
1649 - *                                    -2 if address unresolvable,
1650 + *                                    -2 if memory error
1651   *                                    -1 otherwise
1652   *********************************************************************/
1653 -int bind_port(const char *hostnam, int portnum, jb_socket *pfd)
1654 +int bind_port_one_ip(struct sockaddr *addr, const socklen_t addr_len, jb_socket_set *fds)
1655  {
1656 -   struct sockaddr_in inaddr;
1657     jb_socket fd;
1658 +   int flags;
1659  #ifndef _WIN32
1660     int one = 1;
1661  #endif /* ndef _WIN32 */
1662  
1663 -   *pfd = JB_INVALID_SOCKET;
1664 -
1665 -   memset((char *)&inaddr, '\0', sizeof inaddr);
1666 -
1667 -   inaddr.sin_family      = AF_INET;
1668 -   inaddr.sin_addr.s_addr = resolve_hostname_to_ip(hostnam);
1669 -
1670 -   if (inaddr.sin_addr.s_addr == INADDR_NONE)
1671 -   {
1672 -      return(-2);
1673 -   }
1674 -
1675 -#ifndef _WIN32
1676 -   if (sizeof(inaddr.sin_port) == sizeof(short))
1677 -#endif /* ndef _WIN32 */
1678 -   {
1679 -      inaddr.sin_port = htons((unsigned short) portnum);
1680 -   }
1681 -#ifndef _WIN32
1682 -   else
1683 -   {
1684 -      inaddr.sin_port = htonl((unsigned long) portnum);
1685 -   }
1686 -#endif /* ndef _WIN32 */
1687 +   fd = JB_INVALID_SOCKET;
1688  
1689 -   fd = socket(AF_INET, SOCK_STREAM, 0);
1690 +   fd = socket(addr->sa_family, SOCK_STREAM, 6);
1691  
1692  #ifdef _WIN32
1693     if (fd == JB_INVALID_SOCKET)
1694 @@ -635,8 +668,17 @@
1695      */
1696     setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one));
1697  #endif /* ndef _WIN32 */
1698 -
1699 -   if (bind(fd, (struct sockaddr *)&inaddr, sizeof(inaddr)) < 0)
1700 +   /* As we are now listening on more than one socket,
1701 +    * this is important: The only way to be sure accept
1702 +    * won't block!!
1703 +    */
1704 +   if ((flags = fcntl(fd, F_GETFL, 0)) != -1)
1705 +   {
1706 +      flags |= O_NONBLOCK;
1707 +      fcntl(fd, F_SETFL, flags);
1708 +   }
1709 +   
1710 +   if (bind (fd, addr, addr_len) < 0)
1711     {
1712  #ifdef _WIN32
1713        errno = WSAGetLastError();
1714 @@ -655,7 +697,7 @@
1715        }
1716     }
1717  
1718 -   while (listen(fd, 5) == -1)
1719 +   while (listen(fd, 25) == -1)
1720     {
1721        if (errno != EINTR)
1722        {
1723 @@ -663,7 +705,11 @@
1724        }
1725     }
1726  
1727 -   *pfd = fd;
1728 +   if (jb_socket_set_add(fds,fd) != 0)
1729 +   {
1730 +      close_socket(fd);
1731 +      return -2;
1732 +   }
1733     return 0;
1734  
1735  }
1736 @@ -671,6 +717,91 @@
1737  
1738  /*********************************************************************
1739   *
1740 + * Function    :  bind_port
1741 + *
1742 + * Description :  Call bind_port_one_ip on all addresses host resolves to
1743 + *                Called by listen_loop to "boot up" our proxy address.
1744 + *
1745 + * Parameters  :
1746 + *          0  :  host = TCP/IP hostname to bind/listen to
1747 + *          1  :  port = port to listen to, as string
1748 + *          2  :  fds = socket set the sockets should be added to
1749 + *
1750 + * Returns     :  if success on at least one address resolving from hostnam,
1751 + *                 returns 0 and adds sockets to fds.
1752 + *                if failure, returns non-zero
1753 + *********************************************************************/
1754 +int bind_port(const char *host, const char *port, int pf, jb_socket_set *fds)
1755 +{
1756 +   int result;
1757 +   int failure = 1;
1758 +   struct sockaddr_storage addr;
1759 +   struct sockaddr * const addr_addr = (struct sockaddr *)&addr;
1760 +   addr_list *addrs, *addrs_to_try;
1761 +
1762 +   const char * const log_host = (host != NULL) ? host : "ADDR_ANY";
1763 +
1764 +   addrs = resolve_hostname_to_ip(host,port,pf);
1765 +
1766 +   if (is_nil_addr_list(addrs))
1767 +      log_error(LOG_LEVEL_ERROR, "can't bind to %s:%s: " 
1768 +                "Name resolution didn't give any address",
1769 +                log_host, port);
1770 +
1771 +   log_error(LOG_LEVEL_INFO, "Binding to %s:%s...",  log_host, port);
1772 +
1773 +   for(addrs_to_try=addrs;
1774 +       !is_nil_addr_list(addrs_to_try);
1775 +       addrs_to_try = tail_addr_list(addrs_to_try))
1776 +   {
1777 +      char numeric_hostname[NI_MAXHOST];
1778 +      char numeric_port[NI_MAXSERV];
1779 +      size_t addrlen;
1780 +      memset((char *)addr_addr, 0, sizeof addr);
1781 +      cpy_head_addr_list(addrs_to_try, &addr, &addrlen);
1782 +      result = getnameinfo(addr_addr, addrlen, numeric_hostname, NI_MAXHOST,
1783 +                           numeric_port, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV);
1784 +      if (result != 0)
1785 +      {
1786 +         log_error(LOG_LEVEL_ERROR, "bind: Could not get string address and port back from sockaddr because %E");
1787 +         strncpy(numeric_hostname,"unknown",NI_MAXHOST);
1788 +         strncpy(numeric_port,"unknown",NI_MAXSERV);
1789 +      }
1790 +      result = bind_port_one_ip(addr_addr, addrlen, fds);
1791 +      if( result == 0 )
1792 +      {
1793 +         failure = 0;
1794 +         log_error(LOG_LEVEL_INFO, "Successfully bound to %s:%s", numeric_hostname, numeric_port);
1795 +      }
1796 +      else
1797 +      {
1798 +         switch(result)
1799 +         {
1800 +         case -3 :
1801 +            log_error(LOG_LEVEL_ERROR, "can't bind to %s:%s (%s:%s): "
1802 +                      "There may be another Privoxy or some other "
1803 +                      "proxy running on port %s",
1804 +                      log_host, port, numeric_hostname, numeric_port, numeric_port);
1805 +                               break;
1806 +         case -2 :
1807 +            log_error(LOG_LEVEL_ERROR, "can't bind to %s:%s (%s:%s): "
1808 +                      "Out of memory",
1809 +                      log_host, port, numeric_hostname, numeric_port);
1810 +                               break;
1811 +         default :
1812 +            log_error(LOG_LEVEL_ERROR, "can't bind to %s:%s: because %E",
1813 +                      log_host, numeric_port);
1814 +         }
1815 +      }
1816 +   }
1817 +
1818 +   destroy_addr_list(addrs);
1819 +   return failure;
1820 +}
1821 +
1822 +
1823 +/*********************************************************************
1824 + *
1825   * Function    :  accept_connection
1826   *
1827   * Description :  Accepts a connection on a socket.  Socket must have
1828 @@ -687,8 +818,7 @@
1829   *********************************************************************/
1830  int accept_connection(struct client_state * csp, jb_socket fd)
1831  {
1832 -   struct sockaddr_in client, server;
1833 -   struct hostent *host = NULL;
1834 +   struct sockaddr_storage client, server;
1835     jb_socket afd;
1836  #if defined(_WIN32) || defined(__OS2__) || defined(__APPLE_CC__) || defined(AMIGA)
1837     /* Wierdness - fix a warning. */
1838 @@ -696,15 +826,7 @@
1839  #else
1840     socklen_t c_length, s_length;
1841  #endif
1842 -#if defined(HAVE_GETHOSTBYADDR_R_8_ARGS) ||  defined(HAVE_GETHOSTBYADDR_R_7_ARGS) || defined(HAVE_GETHOSTBYADDR_R_5_ARGS)
1843 -   struct hostent result;
1844 -#if defined(HAVE_GETHOSTBYADDR_R_5_ARGS)
1845 -   struct hostent_data hdata;
1846 -#else
1847 -   char hbuf[HOSTENT_BUFFER_SIZE];
1848 -   int thd_err;
1849 -#endif /* def HAVE_GETHOSTBYADDR_R_5_ARGS */
1850 -#endif /* def HAVE_GETHOSTBYADDR_R_(8|7|5)_ARGS */
1851 +   int flags;
1852  
1853     c_length = s_length = sizeof(client);
1854  
1855 @@ -724,6 +846,12 @@
1856        return 0;
1857     }
1858  #endif
1859 +   /* If we inherited O_NONBLOCK from the listening fd, unset it */
1860 +   if ((flags = fcntl(fd, F_GETFL, 0)) != -1)
1861 +   {
1862 +      flags &= ~O_NONBLOCK;
1863 +      fcntl(fd, F_SETFL, flags);
1864 +   }
1865  
1866     /* 
1867      * Determine the IP-Adress that the client used to reach us
1868 @@ -731,49 +859,50 @@
1869      */
1870     if (!getsockname(afd, (struct sockaddr *) &server, &s_length))
1871     {
1872 -      csp->my_ip_addr_str = strdup(inet_ntoa(server.sin_addr));
1873 -#if defined(HAVE_GETHOSTBYADDR_R_8_ARGS)
1874 -      gethostbyaddr_r((const char *)&server.sin_addr,
1875 -                      sizeof(server.sin_addr), AF_INET,
1876 -                      &result, hbuf, HOSTENT_BUFFER_SIZE,
1877 -                      &host, &thd_err);
1878 -#elif defined(HAVE_GETHOSTBYADDR_R_7_ARGS)
1879 -      host = gethostbyaddr_r((const char *)&server.sin_addr,
1880 -                      sizeof(server.sin_addr), AF_INET,
1881 -                      &result, hbuf, HOSTENT_BUFFER_SIZE, &thd_err);
1882 -#elif defined(HAVE_GETHOSTBYADDR_R_5_ARGS)
1883 -      if (0 == gethostbyaddr_r((const char *)&server.sin_addr,
1884 -                               sizeof(server.sin_addr), AF_INET,
1885 -                               &result, &hdata))
1886 +      char hostname[NI_MAXHOST];
1887 +      char port[NI_MAXSERV];
1888 +
1889 +      if (getnameinfo((struct sockaddr *)&server, s_length, hostname, NI_MAXHOST,
1890 +                      port, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV) != 0)
1891        {
1892 -         host = &result;
1893 +         log_error(LOG_LEVEL_ERROR, "accept: Could not get string address and port back from server sockaddr because %E");
1894 +         strncpy(hostname,"unknown IP",NI_MAXHOST);
1895 +         strncpy(port,"unknown port",NI_MAXSERV);
1896        }
1897 -      else
1898 +      csp->my_ip_addr_str = strdup(hostname);
1899 +      csp->my_port_str = strdup(port);
1900 +
1901 +      if (getnameinfo((struct sockaddr *)&server, s_length, hostname, NI_MAXHOST, NULL, 0, NI_NAMEREQD) != 0)
1902        {
1903 -         host = NULL;
1904 +         log_error(LOG_LEVEL_ERROR, "accept: Could not get my own hostname because %E");
1905 +         strncpy(hostname,"unknown host",NI_MAXHOST);
1906        }
1907 -#elif defined(OSX_DARWIN) || defined(__OpenBSD__)
1908 -      pthread_mutex_lock(&gethostbyaddr_mutex);
1909 -      host = gethostbyaddr((const char *)&server.sin_addr, 
1910 -                           sizeof(server.sin_addr), AF_INET);
1911 -      pthread_mutex_unlock(&gethostbyaddr_mutex);
1912 -#else
1913 -      host = gethostbyaddr((const char *)&server.sin_addr, 
1914 -                           sizeof(server.sin_addr), AF_INET);
1915 -#endif
1916 -      if (host == NULL)
1917 +      csp->my_hostname = strdup(hostname);
1918 +   }
1919 +   else
1920 +   {
1921 +      log_error(LOG_LEVEL_ERROR, "accept: Could not get sockaddr from socket fd because %E");
1922 +   }
1923 +
1924 +   csp->cfd    = afd;
1925 +   {
1926 +      char hostname[NI_MAXHOST];
1927 +
1928 +      if (getnameinfo((struct sockaddr *)&client, c_length, hostname, NI_MAXHOST, NULL, 0, NI_NUMERICHOST) != 0)
1929        {
1930 -         log_error(LOG_LEVEL_ERROR, "Unable to get my own hostname: %E\n");
1931 +         log_error(LOG_LEVEL_ERROR, "accept: Could not get client IP address string because %E");
1932 +         strncpy(hostname,"unknown IP",NI_MAXHOST);
1933        }
1934 -      else
1935 +      csp->my_ip_addr_str = strdup(hostname);
1936 +
1937 +      if (getnameinfo((struct sockaddr *)&server, s_length, hostname, NI_MAXHOST, NULL, 0, 0) != 0)
1938        {
1939 -         csp->my_hostname = strdup(host->h_name);
1940 +         log_error(LOG_LEVEL_ERROR, "accept: Could not get my own hostname because %E");
1941 +         strncpy(hostname,"unknown host",NI_MAXHOST);
1942        }
1943 +      csp->ip_addr_str = strdup(hostname);
1944     }
1945 -
1946 -   csp->cfd    = afd;
1947 -   csp->ip_addr_str  = strdup(inet_ntoa(client.sin_addr));
1948 -   csp->ip_addr_long = ntohl(client.sin_addr.s_addr);
1949 +   csp->ip_addr_addr = client;
1950  
1951     return 1;
1952  
1953 @@ -784,108 +913,42 @@
1954   *
1955   * Function    :  resolve_hostname_to_ip
1956   *
1957 - * Description :  Resolve a hostname to an internet tcp/ip address.
1958 - *                NULL or an empty string resolve to INADDR_ANY.
1959 + * Description :  Resolve a hostname to a list of internet tcp/ip addresses.
1960   *
1961   * Parameters  :
1962 - *          1  :  host = hostname to resolve
1963 + *          0  :  host = hostname to resolve
1964 + *          1  :  result = where to store the result
1965 + *          2  :  pf = preferred address family. PF_UNSPEC for no preference (recommended).
1966   *
1967 - * Returns     :  INADDR_NONE => failure, INADDR_ANY or tcp/ip address if succesful.
1968 + * Returns     :  A (possibly empty) list of adresses
1969   *
1970   *********************************************************************/
1971 -unsigned long resolve_hostname_to_ip(const char *host)
1972 -{
1973 -   struct sockaddr_in inaddr;
1974 -   struct hostent *hostp;
1975 -   unsigned int dns_retries = 0;
1976 -#if defined(HAVE_GETHOSTBYNAME_R_6_ARGS) || defined(HAVE_GETHOSTBYNAME_R_5_ARGS) || defined(HAVE_GETHOSTBYNAME_R_3_ARGS)
1977 -   struct hostent result;
1978 -#if defined(HAVE_GETHOSTBYNAME_R_6_ARGS) || defined(HAVE_GETHOSTBYNAME_R_5_ARGS)
1979 -   char hbuf[HOSTENT_BUFFER_SIZE];
1980 -   int thd_err;
1981 -#else /* defined(HAVE_GETHOSTBYNAME_R_3_ARGS) */
1982 -   struct hostent_data hdata;
1983 -#endif /* def HAVE_GETHOSTBYNAME_R_(6|5)_ARGS */
1984 -#endif /* def HAVE_GETHOSTBYNAME_R_(6|5|3)_ARGS */
1985 -
1986 -   if ((host == NULL) || (*host == '\0'))
1987 -   {
1988 -      return(INADDR_ANY);
1989 -   }
1990 -
1991 -   memset((char *) &inaddr, 0, sizeof inaddr);
1992 -
1993 -   if ((inaddr.sin_addr.s_addr = inet_addr(host)) == -1)
1994 -   {
1995 -#if defined(HAVE_GETHOSTBYNAME_R_6_ARGS)
1996 -       while ( gethostbyname_r(host, &result, hbuf,
1997 -                      HOSTENT_BUFFER_SIZE, &hostp, &thd_err)
1998 -               && (thd_err == TRY_AGAIN) && (dns_retries++ < 10) )
1999 -      {   
2000 -         log_error(LOG_LEVEL_ERROR, "Timeout #%u while trying to resolve %s. Trying again.",
2001 -                                                dns_retries, host);
2002 -      }
2003 -#elif defined(HAVE_GETHOSTBYNAME_R_5_ARGS)
2004 -      hostp = gethostbyname_r(host, &result, hbuf,
2005 -                      HOSTENT_BUFFER_SIZE, &thd_err);
2006 -#elif defined(HAVE_GETHOSTBYNAME_R_3_ARGS)
2007 -      if (0 == gethostbyname_r(host, &result, &hdata))
2008 -      {
2009 -         hostp = &result;
2010 -      }
2011 -      else
2012 -      {
2013 -         hostp = NULL;
2014 -      }
2015 -#elif defined(OSX_DARWIN) || defined(__OpenBSD__)
2016 -      pthread_mutex_lock(&gethostbyname_mutex);
2017 -      while ( NULL == (hostp = gethostbyname(host))
2018 -            && (h_errno == TRY_AGAIN) && (dns_retries++ < 10) )
2019 -      {   
2020 -         log_error(LOG_LEVEL_ERROR, "Timeout #%u while trying to resolve %s. Trying again.",
2021 -                                                dns_retries, host);
2022 -      }
2023 -      pthread_mutex_unlock(&gethostbyname_mutex);
2024 -#else
2025 -      while ( NULL == (hostp = gethostbyname(host))
2026 -            && (h_errno == TRY_AGAIN) && (dns_retries++ < 10) )
2027 -      {
2028 -         log_error(LOG_LEVEL_ERROR, "Timeout #%u while trying to resolve %s. Trying again.",
2029 -                                                dns_retries, host);
2030 -      }
2031 -#endif /* def HAVE_GETHOSTBYNAME_R_(6|5|3)_ARGS */
2032 -      /*
2033 -       * On Mac OSX, if a domain exists but doesn't have a type A
2034 -       * record associated with it, the h_addr member of the struct
2035 -       * hostent returned by gethostbyname is NULL, even if h_length
2036 -       * is 4. Therefore the second test below.
2037 -       */
2038 -      if (hostp == NULL || hostp->h_addr == NULL)
2039 -      {
2040 -         errno = EINVAL;
2041 -         log_error(LOG_LEVEL_ERROR, "could not resolve hostname %s", host);
2042 -         return(INADDR_NONE);
2043 -      }
2044 -      if (hostp->h_addrtype != AF_INET)
2045 -      {
2046 -#ifdef _WIN32
2047 -         errno = WSAEPROTOTYPE;
2048 -#else
2049 -         errno = EPROTOTYPE;
2050 -#endif 
2051 -         log_error(LOG_LEVEL_ERROR, "hostname %s resolves to unknown address type.", host);
2052 -         return(INADDR_NONE);
2053 -      }
2054 -      memcpy(
2055 -         (char *) &inaddr.sin_addr,
2056 -         (char *) hostp->h_addr,
2057 -         sizeof(inaddr.sin_addr)
2058 -      );
2059 -   }
2060 -   return(inaddr.sin_addr.s_addr);
2061 -
2062 -}
2063 -
2064 +addr_list *resolve_hostname_to_ip(const char *host, const char *port, int pf)
2065 + {
2066 +   /* TODO 
2067 +    * Do all supported platforms have "getaddrinfo"?
2068 +    */
2069 +    
2070 +   struct addrinfo hints, *res0;
2071 +   int result;
2072 +   memset(&hints, 0, sizeof(hints));
2073 +   hints.ai_family = pf;
2074 +   hints.ai_socktype = SOCK_STREAM;
2075 +  
2076 +   result = getaddrinfo(host, port, &hints, &res0);
2077 +   if ( result != 0 )
2078 +     {
2079 +      log_error(LOG_LEVEL_ERROR, "could not resolve hostname %s because %s", host,gai_strerror(result));
2080 +      if (result == EAI_SYSTEM)
2081 +         log_error(LOG_LEVEL_ERROR, "The system error is %E");
2082 +      return NULL;
2083 +     }
2084 +   else
2085 +      if (res0==0)
2086 +         log_error(LOG_LEVEL_ERROR, "Problem in resolving hostname %s: succeeded, but no information returned", host);
2087 +  
2088 +   return res0;
2089 + }
2090  
2091  /*
2092    Local Variables:
2093 diff -urNad privoxy~/jbsockets.h privoxy/jbsockets.h
2094 --- privoxy~/jbsockets.h
2095 +++ privoxy/jbsockets.h
2096 @@ -13,6 +13,9 @@
2097   * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
2098   *                Privoxy team. http://www.privoxy.org/
2099   *
2100 + *                Modified by Lionel Elie Mamane <lionel@mamane.lu>
2101 + *                for IPv6 support on 8 December 2002, 24 January 2003.
2102 + *
2103   *                Based on the Internet Junkbuster originally written
2104   *                by and Copyright (C) 1997 Anonymous Coders and 
2105   *                Junkbusters Corporation.  http://www.junkbusters.com
2106 @@ -104,9 +107,11 @@
2107  extern "C" {
2108  #endif
2109  
2110 +#include "addrlist.h"
2111 +
2112  struct client_state;
2113  
2114 -extern jb_socket connect_to(const char *host, int portnum, struct client_state *csp);
2115 +extern jb_socket connect_to(const char *host, const char *port, unsigned long portnum, int pf, struct client_state *csp);
2116  #ifdef AMIGA
2117  extern int write_socket(jb_socket fd, const char *buf, ssize_t n);
2118  #else
2119 @@ -115,10 +120,10 @@
2120  extern int read_socket(jb_socket fd, char *buf, int n);
2121  extern void close_socket(jb_socket fd);
2122  
2123 -extern int bind_port(const char *hostnam, int portnum, jb_socket *pfd);
2124 +extern int bind_port(const char *host, const char *port, int pf, jb_socket_set *fds);
2125  extern int accept_connection(struct client_state * csp, jb_socket fd);
2126  
2127 -extern unsigned long resolve_hostname_to_ip(const char *host);
2128 +extern addr_list *resolve_hostname_to_ip(const char *host, const char *port, int pf);
2129  
2130  /* Revision control strings from this header and associated .c file */
2131  extern const char jbsockets_rcs[];
2132 diff -urNad privoxy~/jcc.c privoxy/jcc.c
2133 --- privoxy~/jcc.c
2134 +++ privoxy/jcc.c
2135 @@ -744,6 +744,7 @@
2136  #include "cgi.h"
2137  #include "loadcfg.h"
2138  #include "urlmatch.h"
2139 +#include "jb_socket_set.h"
2140  
2141  const char jcc_h_rcs[] = JCC_H_VERSION;
2142  const char project_h_rcs[] = PROJECT_H_VERSION;
2143 @@ -2304,61 +2305,78 @@
2144   * Returns     :  Port that was opened.
2145   *
2146   *********************************************************************/
2147 -static jb_socket bind_port_helper(struct configuration_spec * config)
2148 +static void bind_port_helper(struct configuration_spec * config, jb_socket_set *bfds)
2149  {
2150     int result;
2151 -   jb_socket bfd;
2152 +   struct bind_spec *bs;
2153 +   unsigned int bs_index;
2154 +   int never_bound;
2155  
2156 -   if ( (config->haddr != NULL)
2157 -     && (config->haddr[0] == '1')
2158 -     && (config->haddr[1] == '2')
2159 -     && (config->haddr[2] == '7')
2160 -     && (config->haddr[3] == '.') )
2161 -   {
2162 -      log_error(LOG_LEVEL_INFO, "Listening on port %d for local connections only",
2163 -                config->hport);
2164 -   }
2165 -   else if (config->haddr == NULL)
2166 -   {
2167 -      log_error(LOG_LEVEL_INFO, "Listening on port %d on all IP addresses",
2168 -                config->hport);
2169 -   }
2170 -   else
2171 +   never_bound = 1;
2172 +   for (bs_index = 0; bs_index < config->hspecs_occupied;++bs_index)
2173     {
2174 -      log_error(LOG_LEVEL_INFO, "Listening on port %d on IP address %s",
2175 -                config->hport, config->haddr);
2176 -   }
2177 +      bs = &config->hspecs[bs_index];
2178 +      
2179 +      /* This check misses about a trillion zillion different manners to describe
2180 +         the local interface in IPv6. Who cares? */
2181 +      if ( (bs->haddr != NULL)
2182 +           && (((bs->haddr[0] == '1')
2183 +                && (bs->haddr[1] == '2')
2184 +                && (bs->haddr[2] == '7')
2185 +                && (bs->haddr[3] == '.'))
2186 +               || ((bs->haddr[0] == ':')
2187 +                   && (bs->haddr[1] == ':')
2188 +                   && (bs->haddr[2] == '1'))))
2189 +      {
2190 +         log_error(LOG_LEVEL_INFO, "Listening on port %s for local connections only",
2191 +                   bs->hport);
2192 +      }
2193 +      else if (bs->haddr == NULL || bs->haddr[0]=='\0')
2194 +      {
2195 +         log_error(LOG_LEVEL_INFO, "Listening on port %s on all IP addresses",
2196 +                   bs->hport);
2197 +      }
2198 +      else
2199 +      {
2200 +         log_error(LOG_LEVEL_INFO, "Listening on port %s on IP address %s",
2201 +                   bs->hport, bs->haddr);
2202 +      }
2203  
2204 -   result = bind_port(config->haddr, config->hport, &bfd);
2205 +      result = bind_port(bs->haddr, bs->hport, bs->pf, bfds);
2206  
2207 -   if (result < 0)
2208 -   {
2209 -      switch(result)
2210 +      if (result != 0)
2211        {
2212 +         switch(result)
2213 +         {
2214           case -3 :
2215 -            log_error(LOG_LEVEL_FATAL, "can't bind to %s:%d: "
2216 +            log_error(LOG_LEVEL_ERROR, "can't bind to %s:%s: "
2217                 "There may be another Privoxy or some other "
2218 -               "proxy running on port %d",
2219 -               (NULL != config->haddr) ? config->haddr : "INADDR_ANY",
2220 -                      config->hport, config->hport);
2221 +               "proxy running on port %s",
2222 +               (NULL != bs->haddr) ? bs->haddr : "INADDR_ANY",
2223 +                      bs->hport, bs->hport);
2224 +                               break;
2225  
2226           case -2 :
2227 -            log_error(LOG_LEVEL_FATAL, "can't bind to %s:%d: " 
2228 +            log_error(LOG_LEVEL_ERROR, "can't bind to %s:%s: " 
2229                 "The hostname is not resolvable",
2230 -               (NULL != config->haddr) ? config->haddr : "INADDR_ANY", config->hport);
2231 +               (NULL != bs->haddr) ? bs->haddr : "INADDR_ANY", bs->hport);
2232 +                               break;
2233  
2234           default :
2235 -            log_error(LOG_LEVEL_FATAL, "can't bind to %s:%d: because %E",
2236 -               (NULL != config->haddr) ? config->haddr : "INADDR_ANY", config->hport);
2237 +            log_error(LOG_LEVEL_ERROR, "can't bind to %s:%s: because %E",
2238 +               (NULL != bs->haddr) ? bs->haddr : "INADDR_ANY", bs->hport);
2239 +         }
2240        }
2241 +      else
2242 +         never_bound = 0;
2243 +   }
2244  
2245 +   if(never_bound)
2246 +   {
2247 +      log_error(LOG_LEVEL_FATAL, "Couldn't bind at all - bailing out");
2248        /* shouldn't get here */
2249 -      return JB_INVALID_SOCKET;
2250     }
2251 -
2252     config->need_bind = 0;
2253 -
2254 -   return bfd;
2255  }
2256  
2257  
2258 @@ -2387,12 +2405,18 @@
2259  static void listen_loop(void)
2260  {
2261     struct client_state *csp = NULL;
2262 -   jb_socket bfd;
2263 +   jb_socket_set bfds;
2264 +   fd_set bfds_fs;
2265 +   jb_socket_set_iterate_state bfds_iterate_state;
2266 +   jb_socket bfd_current;
2267     struct configuration_spec * config;
2268  
2269 +   init_jb_socket_set(&bfds);
2270 +
2271     config = load_config();
2272  
2273 -   bfd = bind_port_helper(config);
2274 +   bind_port_helper(config,&bfds);
2275 +   bfd_current=JB_INVALID_SOCKET;
2276  
2277  #ifdef FEATURE_GRACEFUL_TERMINATION
2278     while (!g_terminate)
2279 @@ -2466,14 +2490,55 @@
2280            * that this will hurt people's feelings.
2281            */
2282  
2283 -         close_socket(bfd);
2284 +         jb_socket_set_iterate_state s;
2285 +         jb_socket bfd;
2286 +         s=jb_socket_set_iteration_begin(&bfds);
2287 +         for(bfd=jb_socket_set_iteration_next(&s);bfd!=JB_INVALID_SOCKET;bfd=jb_socket_set_iteration_next(&s))
2288 +         {
2289 +            close_socket(bfd);
2290 +         }
2291 +         destroy_jb_socket_set(&bfds);
2292 +         bind_port_helper(config,&bfds);
2293 +         /* We have a new set of fd's to accept. Restart iteration over bfds. */
2294 +         bfd_current = JB_INVALID_SOCKET;
2295 +      }
2296  
2297 -         bfd = bind_port_helper(config);
2298 +      /* Here: select call on listening sockets: bfd=sockets */
2299 +      if (bfd_current == JB_INVALID_SOCKET)
2300 +      {
2301 +         jb_socket max;
2302 +         log_error(LOG_LEVEL_CONNECT, "select connections ... ");
2303 +         bfds_iterate_state=jb_socket_set_iteration_begin(&bfds);
2304 +         FD_ZERO(&bfds_fs);
2305 +         max = 0;
2306 +         for(bfd_current=jb_socket_set_iteration_next(&bfds_iterate_state);
2307 +             bfd_current!=JB_INVALID_SOCKET;
2308 +             bfd_current=jb_socket_set_iteration_next(&bfds_iterate_state))
2309 +         {
2310 +            FD_SET(bfd_current,&bfds_fs);
2311 +            if (bfd_current >= max)
2312 +               max = bfd_current + 1;
2313 +         }
2314 +         if(!select(max,&bfds_fs,NULL,NULL,NULL))
2315 +         {
2316 +            log_error(LOG_LEVEL_CONNECT, "select failed: %E");
2317 +            bfd_current=JB_INVALID_SOCKET;
2318 +            continue;
2319 +         }
2320 +         log_error(LOG_LEVEL_CONNECT, "OK");
2321 +         bfds_iterate_state=jb_socket_set_iteration_begin(&bfds);
2322 +         bfd_current=jb_socket_set_iteration_next(&bfds_iterate_state);
2323 +      }
2324 +      if (!FD_ISSET(bfd_current,&bfds_fs))
2325 +      {
2326 +         bfd_current=jb_socket_set_iteration_next(&bfds_iterate_state);
2327 +         freez(csp);
2328 +         continue;
2329        }
2330  
2331        log_error(LOG_LEVEL_CONNECT, "accept connection ... ");
2332  
2333 -      if (!accept_connection(csp, bfd))
2334 +      if (!accept_connection(csp, bfd_current))
2335        {
2336           log_error(LOG_LEVEL_CONNECT, "accept failed: %E");
2337  
2338 @@ -2491,6 +2556,8 @@
2339           log_error(LOG_LEVEL_CONNECT, "OK");
2340        }
2341  
2342 +      bfd_current=jb_socket_set_iteration_next(&bfds_iterate_state);
2343 +
2344  #ifdef FEATURE_TOGGLE
2345        if (global_toggle_state)
2346        {
2347 diff -urNad privoxy~/loadcfg.c privoxy/loadcfg.c
2348 --- privoxy~/loadcfg.c
2349 +++ privoxy/loadcfg.c
2350 @@ -11,6 +11,9 @@
2351   * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
2352   *                Privoxy team. http://www.privoxy.org/
2353   *
2354 + *                Modified by Lionel Elie Mamane <lionel@mamane.lu>
2355 + *                for IPv6 support on 8 December 2002, 24 January 2003.
2356 + *
2357   *                Based on the Internet Junkbuster originally written
2358   *                by and Copyright (C) 1997 Anonymous Coders and
2359   *                Junkbusters Corporation.  http://www.junkbusters.com
2360 @@ -402,6 +405,7 @@
2361  #include "encode.h"
2362  #include "urlmatch.h"
2363  #include "cgi.h"
2364 +#include "parsers.h"
2365  
2366  const char loadcfg_h_rcs[] = LOADCFG_H_VERSION;
2367  
2368 @@ -521,8 +525,8 @@
2369        struct forward_spec * next_fwd = cur_fwd->next;
2370        free_url_spec(cur_fwd->url);
2371  
2372 -      freez(cur_fwd->gateway_host);
2373 -      freez(cur_fwd->forward_host);
2374 +      freez(cur_fwd->gateway_malloc);
2375 +      freez(cur_fwd->forward_malloc);
2376        free(cur_fwd);
2377        cur_fwd = next_fwd;
2378     }
2379 @@ -539,7 +543,16 @@
2380     freez(config->confdir);
2381     freez(config->logdir);
2382  
2383 -   freez(config->haddr);
2384 +   if(config -> hspecs != NULL)
2385 +   {
2386 +      int i;
2387 +      for (i=0; i < config->hspecs_occupied; ++i)
2388 +      {
2389 +         freez(config->hspecs[i].haddr);
2390 +         freez(config->hspecs[i].hport);
2391 +      }
2392 +   }
2393 +   freez(config->hspecs);
2394     freez(config->logfile);
2395  
2396     for (i = 0; i < MAX_AF_FILES; i++)
2397 @@ -606,6 +619,28 @@
2398   * Returns     :  The configuration_spec, or NULL on error.
2399   *
2400   *********************************************************************/
2401 +static void fail_load_config_memory(struct file_list *fs, struct configuration_spec *config)
2402 +{
2403 +   freez(fs->filename);
2404 +   freez(fs);
2405 +   if (config != NULL)
2406 +   {
2407 +      if(config -> hspecs != NULL)
2408 +      {
2409 +         int i;
2410 +         for (i=0; i < config->hspecs_occupied; ++i)
2411 +         {
2412 +            freez(config->hspecs[i].haddr);
2413 +            freez(config->hspecs[i].hport);
2414 +         }
2415 +      }
2416 +      freez(config -> hspecs);
2417 +   }
2418 +   freez(config);
2419 +   log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
2420 +   /* Never get here - LOG_LEVEL_FATAL causes program exit */
2421 +}
2422 +
2423  struct configuration_spec * load_config(void)
2424  {
2425     char buf[BUFFER_SIZE];
2426 @@ -637,12 +672,7 @@
2427     fs->f = config = (struct configuration_spec *)zalloc(sizeof(*config));
2428  
2429     if (config==NULL)
2430 -   {
2431 -      freez(fs->filename);
2432 -      freez(fs);
2433 -      log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
2434 -      /* Never get here - LOG_LEVEL_FATAL causes program exit */
2435 -   }
2436 +      fail_load_config_memory(fs,config);
2437  
2438     /*
2439      * This is backwards from how it's usually done.
2440 @@ -659,7 +689,7 @@
2441      * Set to defaults
2442      */
2443     config->multi_threaded            = 1;
2444 -   config->hport                     = HADDR_PORT;
2445 +   config->hspecs                    = NULL;
2446     config->buffer_limit              = 4096 * 1024;
2447     config->usermanual                = strdup(USER_MANUAL_URL);
2448     config->proxy_args                = strdup("");
2449 @@ -678,9 +708,6 @@
2450        char cmd[BUFFER_SIZE];
2451        char arg[BUFFER_SIZE];
2452        char tmp[BUFFER_SIZE];
2453 -#ifdef FEATURE_ACL
2454 -      struct access_control_list *cur_acl;
2455 -#endif /* def FEATURE_ACL */
2456        struct forward_spec *cur_fwd;
2457        int vec_count;
2458        char *vec[3];
2459 @@ -791,74 +818,23 @@
2460   * *************************************************************************/
2461  #ifdef FEATURE_ACL
2462           case hash_deny_access:
2463 -            vec_count = ssplit(arg, " \t", vec, SZ(vec), 1, 1);
2464 -
2465 -            if ((vec_count != 1) && (vec_count != 2))
2466 -            {
2467 -               log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
2468 -                     "deny-access directive in configuration file.");
2469 -               string_append(&config->proxy_args,
2470 -                  "<br>\nWARNING: Wrong number of parameters for "
2471 -                  "deny-access directive in configuration file.<br><br>\n");
2472 -               continue;
2473 -            }
2474 -
2475 -            /* allocate a new node */
2476 -            cur_acl = (struct access_control_list *) zalloc(sizeof(*cur_acl));
2477 -
2478 -            if (cur_acl == NULL)
2479 -            {
2480 -               log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
2481 -               /* Never get here - LOG_LEVEL_FATAL causes program exit */
2482 -               continue;
2483 -            }
2484 -            cur_acl->action = ACL_DENY;
2485 -
2486 -            if (acl_addr(vec[0], cur_acl->src) < 0)
2487 -            {
2488 -               log_error(LOG_LEVEL_ERROR, "Invalid source IP for deny-access "
2489 -                     "directive in configuration file: \"%s\"", vec[0]);
2490 -               string_append(&config->proxy_args,
2491 -                  "<br>\nWARNING: Invalid source IP for deny-access directive"
2492 -                  " in configuration file: \"");
2493 -               string_append(&config->proxy_args,
2494 -                  vec[0]);
2495 -               string_append(&config->proxy_args,
2496 -                  "\"<br><br>\n");
2497 -               freez(cur_acl);
2498 -               continue;
2499 -            }
2500 -            if (vec_count == 2)
2501 +            switch (ssplit(arg, " \t", vec, SZ(vec), 1, 1))
2502              {
2503 -               if (acl_addr(vec[1], cur_acl->dst) < 0)
2504 -               {
2505 -                  log_error(LOG_LEVEL_ERROR, "Invalid destination IP for deny-access "
2506 -                        "directive in configuration file: \"%s\"", vec[0]);
2507 -                  string_append(&config->proxy_args,
2508 -                     "<br>\nWARNING: Invalid destination IP for deny-access directive"
2509 -                     " in configuration file: \"");
2510 -                  string_append(&config->proxy_args,
2511 -                     vec[0]);
2512 +               case 1:
2513 +                  config->acl = add_to_acl_list(config->acl, ACL_DENY, vec[0], NULL, &config->proxy_args);
2514 +                                               break;
2515 +               case 2:
2516 +                  config->acl = add_to_acl_list(config->acl, ACL_DENY, vec[0], vec[1], &config->proxy_args);
2517 +                                               break;
2518 +               default:
2519 +                  log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
2520 +                            "deny-access directive in configuration file.");
2521                    string_append(&config->proxy_args,
2522 -                     "\"<br><br>\n");
2523 -                  freez(cur_acl);
2524 -                  continue;
2525 -               }
2526 +                                "<br>\nWARNING: Wrong number of parameters for "
2527 +                                "deny-access directive in configuration file.<br><br>\n");
2528              }
2529 -
2530 -            /*
2531 -             * Add it to the list.  Note we reverse the list to get the
2532 -             * behaviour the user expects.  With both the ACL and
2533 -             * actions file, the last match wins.  However, the internal
2534 -             * implementations are different:  The actions file is stored
2535 -             * in the same order as the file, and scanned completely.
2536 -             * With the ACL, we reverse the order as we load it, then
2537 -             * when we scan it we stop as soon as we get a match.
2538 -             */
2539 -            cur_acl->next  = config->acl;
2540 -            config->acl = cur_acl;
2541 -
2542              continue;
2543 +
2544  #endif /* def FEATURE_ACL */
2545  
2546  /* *************************************************************************
2547 @@ -978,16 +954,18 @@
2548  
2549              if (strcmp(p, ".") != 0)
2550              {
2551 -               cur_fwd->forward_host = strdup(p);
2552 +               cur_fwd->forward_malloc = strdup(p);
2553 +               cur_fwd->forward_family = -1;
2554  
2555 -               if (NULL != (p = strchr(cur_fwd->forward_host, ':')))
2556 -               {
2557 -                  *p++ = '\0';
2558 -                  cur_fwd->forward_port = atoi(p);
2559 -               }
2560 +               parse_pf_ip(cur_fwd->forward_malloc,
2561 +                           &cur_fwd->forward_host,
2562 +                           &cur_fwd->forward_port_str,
2563 +                           &cur_fwd->forward_family);
2564 +               cur_fwd->forward_port = atoi(cur_fwd->forward_port_str);
2565  
2566                 if (cur_fwd->forward_port <= 0)
2567                 {
2568 +                  cur_fwd->forward_port_str = "8000";
2569                    cur_fwd->forward_port = 8000;
2570                 }
2571              }
2572 @@ -1041,15 +1019,27 @@
2573  
2574              if (strcmp(p, ".") != 0)
2575              {
2576 -               cur_fwd->gateway_host = strdup(p);
2577 +               /* SOCKS is IPv4-specific */
2578 +               int pf = PF_INET;
2579  
2580 -               if (NULL != (p = strchr(cur_fwd->gateway_host, ':')))
2581 +               cur_fwd->gateway_malloc = strdup(p);
2582 +               if (parse_pf_ip(cur_fwd->gateway_malloc,
2583 +                               &cur_fwd->gateway_host,
2584 +                               &cur_fwd->gateway_port_str,
2585 +                               &pf) != 0)
2586                 {
2587 -                  *p++ = '\0';
2588 -                  cur_fwd->gateway_port = atoi(p);
2589 +                 log_error(LOG_LEVEL_ERROR, "Could not parse forward-socks4 host: %s",p);
2590 +                 cur_fwd->gateway_host = NULL;
2591 +                 cur_fwd->gateway_port_str = NULL;
2592 +                 freez(cur_fwd->gateway_malloc);
2593 +                 continue;
2594                 }
2595 +
2596 +               cur_fwd->gateway_port = atoi(cur_fwd->gateway_port_str);
2597 +
2598                 if (cur_fwd->gateway_port <= 0)
2599                 {
2600 +                  cur_fwd->gateway_port_str = "1080";
2601                    cur_fwd->gateway_port = 1080;
2602                 }
2603              }
2604 @@ -1059,16 +1049,26 @@
2605  
2606              if (strcmp(p, ".") != 0)
2607              {
2608 -               cur_fwd->forward_host = strdup(p);
2609 +               cur_fwd->forward_malloc = strdup(p);
2610 +               cur_fwd->forward_family = -1;
2611  
2612 -               if (NULL != (p = strchr(cur_fwd->forward_host, ':')))
2613 +               parse_pf_ip(cur_fwd->forward_malloc,
2614 +                           &cur_fwd->forward_host,
2615 +                           &cur_fwd->forward_port_str,
2616 +                           &cur_fwd->forward_family);
2617 +               cur_fwd->forward_port = atoi(cur_fwd->forward_port_str);
2618 +
2619 +               if (cur_fwd->forward_port <= 0)
2620                 {
2621 -                  *p++ = '\0';
2622 -                  cur_fwd->forward_port = atoi(p);
2623 +                  cur_fwd->forward_port_str = "8000";
2624 +                  cur_fwd->forward_port = 8000;
2625                 }
2626  
2627 +               cur_fwd->forward_port = atoi(p);
2628 +
2629                 if (cur_fwd->forward_port <= 0)
2630                 {
2631 +                  cur_fwd->forward_port_str = "8000";
2632                    cur_fwd->forward_port = 8000;
2633                 }
2634              }
2635 @@ -1120,16 +1120,30 @@
2636              /* Parse the SOCKS proxy host[:port] */
2637              p = vec[1];
2638  
2639 -            cur_fwd->gateway_host = strdup(p);
2640 -
2641 -            if (NULL != (p = strchr(cur_fwd->gateway_host, ':')))
2642 -            {
2643 -               *p++ = '\0';
2644 -               cur_fwd->gateway_port = atoi(p);
2645 -            }
2646 -            if (cur_fwd->gateway_port <= 0)
2647              {
2648 -               cur_fwd->gateway_port = 1080;
2649 +               /* SOCKS is IPv4-specific */
2650 +               int pf = PF_INET;
2651 +
2652 +               cur_fwd->gateway_malloc = strdup(p);
2653 +               if (parse_pf_ip(cur_fwd->gateway_malloc,
2654 +                               &cur_fwd->gateway_host,
2655 +                               &cur_fwd->gateway_port_str,
2656 +                               &pf) != 0)
2657 +               {
2658 +                 log_error(LOG_LEVEL_ERROR, "Could not parse forward-socks4a host: %s",p);
2659 +                 cur_fwd->gateway_host = NULL;
2660 +                 cur_fwd->gateway_port_str = NULL;
2661 +                 freez(cur_fwd->gateway_malloc);
2662 +                 continue;
2663 +               }
2664 +
2665 +               cur_fwd->gateway_port = atoi(cur_fwd->gateway_port_str);
2666 +
2667 +               if (cur_fwd->gateway_port <= 0)
2668 +               {
2669 +                  cur_fwd->gateway_port_str = "1080";
2670 +                  cur_fwd->gateway_port = 1080;
2671 +               }
2672              }
2673  
2674              /* Parse the parent HTTP proxy host[:port] */
2675 @@ -1137,16 +1151,26 @@
2676  
2677              if (strcmp(p, ".") != 0)
2678              {
2679 -               cur_fwd->forward_host = strdup(p);
2680 +               cur_fwd->forward_malloc = strdup(p);
2681 +               cur_fwd->forward_family = -1;
2682  
2683 -               if (NULL != (p = strchr(cur_fwd->forward_host, ':')))
2684 +               parse_pf_ip(cur_fwd->forward_malloc,
2685 +                           &cur_fwd->forward_host,
2686 +                           &cur_fwd->forward_port_str,
2687 +                           &cur_fwd->forward_family);
2688 +               cur_fwd->forward_port = atoi(cur_fwd->forward_port_str);
2689 +
2690 +               if (cur_fwd->forward_port <= 0)
2691                 {
2692 -                  *p++ = '\0';
2693 -                  cur_fwd->forward_port = atoi(p);
2694 +                  cur_fwd->forward_port_str = "8000";
2695 +                  cur_fwd->forward_port = 8000;
2696                 }
2697  
2698 +               cur_fwd->forward_port = atoi(p);
2699 +
2700                 if (cur_fwd->forward_port <= 0)
2701                 {
2702 +                  cur_fwd->forward_port_str = "8000";
2703                    cur_fwd->forward_port = 8000;
2704                 }
2705              }
2706 @@ -1179,10 +1203,49 @@
2707   * listen-address [ip][:port]
2708   * *************************************************************************/
2709           case hash_listen_address :
2710 -            freez(config->haddr);
2711 -            config->haddr = strdup(arg);
2712 +         {
2713 +            struct bind_spec *bs;
2714 +            char *arg_cpy;
2715 +            if (config->hspecs == NULL)
2716 +            {
2717 +               /* This is the first we'll bind to */
2718 +               config->hspecs = calloc(2,sizeof(struct bind_spec));
2719 +               if (config->hspecs == NULL)
2720 +                  fail_load_config_memory(fs,config);
2721 +               config->hspecs_size = 2;
2722 +               config->hspecs_occupied = 0;
2723 +            }
2724 +            
2725 +            arg_cpy = strdup(arg);
2726 +            if (arg_cpy == NULL)
2727 +               fail_load_config_memory(fs,config);
2728 +            if (config->hspecs_occupied == config->hspecs_size)
2729 +              {
2730 +                struct bind_spec *new_hspecs;
2731 +                config->hspecs_size *= 2;
2732 +                new_hspecs = realloc(config->hspecs,config->hspecs_size * sizeof(struct bind_spec));
2733 +                if (new_hspecs == NULL)
2734 +                  {
2735 +                    /* Not enough memory to continue. Cancel changes. */
2736 +                    config->hspecs_size /= 2;
2737 +                    fail_load_config_memory(fs,config);
2738 +                  }
2739 +                config->hspecs = new_hspecs;
2740 +              }
2741 +            bs = &config->hspecs[(config->hspecs_occupied)++];
2742 +            bs->pf = -1;
2743 +            parse_pf_ip(arg,&bs->haddr,&bs->hport,&bs->pf);
2744 +            if (*bs->haddr == '\0')
2745 +            {
2746 +               bs->haddr = NULL;
2747 +            }
2748 +            else
2749 +            {
2750 +               (bs->haddr = strdup(bs->haddr));
2751 +            }
2752 +            bs->hport = strdup(bs->hport);
2753              continue;
2754 -
2755 +         }
2756  /* *************************************************************************
2757   * logdir directory-name
2758   * *************************************************************************/
2759 @@ -1205,75 +1268,21 @@
2760   * *************************************************************************/
2761  #ifdef FEATURE_ACL
2762           case hash_permit_access:
2763 -            vec_count = ssplit(arg, " \t", vec, SZ(vec), 1, 1);
2764 -
2765 -            if ((vec_count != 1) && (vec_count != 2))
2766 -            {
2767 -               log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
2768 -                     "permit-access directive in configuration file.");
2769 -               string_append(&config->proxy_args,
2770 -                  "<br>\nWARNING: Wrong number of parameters for "
2771 -                  "permit-access directive in configuration file.<br><br>\n");
2772 -
2773 -               continue;
2774 -            }
2775 -
2776 -            /* allocate a new node */
2777 -            cur_acl = (struct access_control_list *) zalloc(sizeof(*cur_acl));
2778 -
2779 -            if (cur_acl == NULL)
2780 -            {
2781 -               log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
2782 -               /* Never get here - LOG_LEVEL_FATAL causes program exit */
2783 -               continue;
2784 -            }
2785 -            cur_acl->action = ACL_PERMIT;
2786 -
2787 -            if (acl_addr(vec[0], cur_acl->src) < 0)
2788 -            {
2789 -               log_error(LOG_LEVEL_ERROR, "Invalid source IP for permit-access "
2790 -                     "directive in configuration file: \"%s\"", vec[0]);
2791 -               string_append(&config->proxy_args,
2792 -                  "<br>\nWARNING: Invalid source IP for permit-access directive"
2793 -                  " in configuration file: \"");
2794 -               string_append(&config->proxy_args,
2795 -                  vec[0]);
2796 -               string_append(&config->proxy_args,
2797 -                  "\"<br><br>\n");
2798 -               freez(cur_acl);
2799 -               continue;
2800 -            }
2801 -            if (vec_count == 2)
2802 +            switch (ssplit(arg, " \t", vec, SZ(vec), 1, 1))
2803              {
2804 -               if (acl_addr(vec[1], cur_acl->dst) < 0)
2805 -               {
2806 -                  log_error(LOG_LEVEL_ERROR, "Invalid destination IP for "
2807 -                        "permit-access directive in configuration file: \"%s\"",
2808 -                        vec[0]);
2809 -                  string_append(&config->proxy_args,
2810 -                     "<br>\nWARNING: Invalid destination IP for permit-access directive"
2811 -                     " in configuration file: \"");
2812 -                  string_append(&config->proxy_args,
2813 -                     vec[0]);
2814 +               case 1:
2815 +                  config->acl = add_to_acl_list(config->acl, ACL_PERMIT, vec[0], NULL, &config->proxy_args);
2816 +                                               break;
2817 +               case 2:
2818 +                  config->acl = add_to_acl_list(config->acl, ACL_PERMIT, vec[0], vec[1], &config->proxy_args);
2819 +                                               break;
2820 +               default:
2821 +                  log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
2822 +                            "permit-access directive in configuration file.");
2823                    string_append(&config->proxy_args,
2824 -                     "\"<br><br>\n");
2825 -                  freez(cur_acl);
2826 -                  continue;
2827 -               }
2828 +                                "<br>\nWARNING: Wrong number of parameters for "
2829 +                                "permit-access directive in configuration file.<br><br>\n");
2830              }
2831 -
2832 -            /*
2833 -             * Add it to the list.  Note we reverse the list to get the
2834 -             * behaviour the user expects.  With both the ACL and
2835 -             * actions file, the last match wins.  However, the internal
2836 -             * implementations are different:  The actions file is stored
2837 -             * in the same order as the file, and scanned completely.
2838 -             * With the ACL, we reverse the order as we load it, then
2839 -             * when we scan it we stop as soon as we get a match.
2840 -             */
2841 -            cur_acl->next  = config->acl;
2842 -            config->acl = cur_acl;
2843 -
2844              continue;
2845  #endif /* def FEATURE_ACL */
2846  
2847 @@ -1513,32 +1522,33 @@
2848     }
2849  #endif /* def FEATURE_COOKIE_JAR */
2850  
2851 -   if ( NULL == config->haddr )
2852 -   {
2853 -      config->haddr = strdup( HADDR_DEFAULT );
2854 -   }
2855 -
2856 -   if ( NULL != config->haddr )
2857 +   if ( config->hspecs == NULL )
2858     {
2859 -      if (NULL != (p = strchr(config->haddr, ':')))
2860 -      {
2861 -         *p++ = '\0';
2862 -         if (*p)
2863 -         {
2864 -            config->hport = atoi(p);
2865 -         }
2866 -      }
2867 -
2868 -      if (config->hport <= 0)
2869 -      {
2870 -         *--p = ':';
2871 -         log_error(LOG_LEVEL_FATAL, "invalid bind port spec %s", config->haddr);
2872 -         /* Never get here - LOG_LEVEL_FATAL causes program exit */
2873 -      }
2874 -      if (*config->haddr == '\0')
2875 -      {
2876 -         config->haddr = NULL;
2877 -      }
2878 +      /* No listen-address set. The default is localhost on port 8118, on IPv4
2879 +         and (if INET6 is defined) IPv6.
2880 +       */
2881 +      struct bind_spec *bs;
2882 +#ifdef INET6
2883 +      config->hspecs = calloc(2,sizeof(struct bind_spec));
2884 +      if (config->hspecs == NULL)
2885 +         fail_load_config_memory(fs,config);
2886 +      config->hspecs_size=2;
2887 +      config->hspecs_occupied=1;
2888 +      bs = &config->hspecs[0];
2889 +      bs->haddr = strdup("::1");
2890 +      bs->hport = strdup("8118");
2891 +      bs->pf = PF_UNSPEC;
2892 +#else
2893 +      config->hspecs = calloc(1,sizeof(struct bind_spec));
2894 +      if (config->hspecs == NULL)
2895 +         fail_load_config_memory(fs,config);
2896 +      config->hspecs_size=1;
2897 +      config->hspecs_occupied=0;
2898 +#endif
2899 +      bs = &config->hspecs[config->hspecs_occupied++];
2900 +      bs->haddr = strdup("127.0.0.1");
2901 +      bs->hport = strdup("8118");
2902 +      bs->pf = PF_UNSPEC;
2903     }
2904  
2905     /*
2906 @@ -1580,31 +1590,29 @@
2907        struct configuration_spec * oldcfg = (struct configuration_spec *)
2908                                             current_configfile->f;
2909        /*
2910 -       * Check if config->haddr,hport == oldcfg->haddr,hport
2911 -       *
2912 -       * The following could be written more compactly as a single,
2913 -       * (unreadably long) if statement.
2914 +       * Check if the listening addresses have changed
2915         */
2916        config->need_bind = 0;
2917 -      if (config->hport != oldcfg->hport)
2918 -      {
2919 -         config->need_bind = 1;
2920 -      }
2921 -      else if (config->haddr == NULL)
2922 +      if (config -> hspecs_occupied == oldcfg -> hspecs_occupied)
2923        {
2924 -         if (oldcfg->haddr != NULL)
2925 +         int bs_index;
2926 +         struct bind_spec *hspec;
2927 +         struct bind_spec *oldhspec;
2928 +         hspec = config -> hspecs;
2929 +         oldhspec = oldcfg -> hspecs;
2930 +         for(bs_index = 0; bs_index < oldcfg->hspecs_occupied; ++bs_index)
2931           {
2932 -            config->need_bind = 1;
2933 +           if (strcmp(hspec[bs_index].haddr,oldhspec[bs_index].haddr) != 0
2934 +               || strcmp(hspec[bs_index].hport,oldhspec[bs_index].hport) != 0
2935 +               || hspec[bs_index].pf != hspec[bs_index].pf)
2936 +           {
2937 +              config -> need_bind = 1;
2938 +              break;
2939 +           }
2940           }
2941        }
2942 -      else if (oldcfg->haddr == NULL)
2943 -      {
2944 -         config->need_bind = 1;
2945 -      }
2946 -      else if (0 != strcmp(config->haddr, oldcfg->haddr))
2947 -      {
2948 -         config->need_bind = 1;
2949 -      }
2950 +      else
2951 +         config-> need_bind = 1;
2952  
2953        current_configfile->unloader = unload_configfile;
2954     }
2955 diff -urNad privoxy~/loaders.c privoxy/loaders.c
2956 --- privoxy~/loaders.c
2957 +++ privoxy/loaders.c
2958 @@ -11,6 +11,9 @@
2959   * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
2960   *                Privoxy team. http://www.privoxy.org/
2961   *
2962 + *                Modified by Lionel Elie Mamane <lionel@mamane.lu>
2963 + *                for IPv6 support on 8 December 2002, 24 January 2003.
2964 + *
2965   *                Based on the Internet Junkbuster originally written
2966   *                by and Copyright (C) 1997 Anonymous Coders and
2967   *                Junkbusters Corporation.  http://www.junkbusters.com
2968 @@ -465,6 +468,7 @@
2969  
2970           freez(csp->ip_addr_str);
2971           freez(csp->my_ip_addr_str);
2972 +         freez(csp->my_port_str);
2973           freez(csp->my_hostname);
2974           freez(csp->x_forwarded);
2975           freez(csp->iob->buf);
2976 diff -urNad privoxy~/miscutil.h privoxy/miscutil.h
2977 --- privoxy~/miscutil.h
2978 +++ privoxy/miscutil.h
2979 @@ -162,6 +162,15 @@
2980  
2981  #include "project.h"
2982  
2983 +/* Fix a problem with Solaris.  There should be no effect on other
2984 + * platforms.
2985 + * Solaris's isspace() is a macro which uses it's argument directly
2986 + * as an array index.  Therefore we need to make sure that high-bit
2987 + * characters generate +ve values, and ideally we also want to make
2988 + * the argument match the declared parameter type of "int".
2989 + */
2990 +#define ijb_isdigit(__X) isdigit((int)(unsigned char)(__X))
2991 +
2992  #if defined(__cplusplus)
2993  extern "C" {
2994  #endif
2995 diff -urNad privoxy~/parsers.c privoxy/parsers.c
2996 --- privoxy~/parsers.c
2997 +++ privoxy/parsers.c
2998 @@ -16,6 +16,9 @@
2999   * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
3000   *                Privoxy team. http://www.privoxy.org/
3001   *
3002 + *                Modified by Lionel Elie Mamane <lionel@mamane.lu>
3003 + *                for IPv6 support on 24 January 2003.
3004 + *
3005   *                Based on the Internet Junkbuster originally written
3006   *                by and Copyright (C) 1997 Anonymous Coders and
3007   *                Junkbusters Corporation.  http://www.junkbusters.com
3008 @@ -1929,6 +1932,167 @@
3009     return JB_ERR_OK;
3010  }
3011  
3012 +/*********************************************************************
3013 + *
3014 + * Function    :  parse_pf_ip_netmask
3015 + *
3016 + * Description :  Parse an IPv{4,6} litteral or hostname
3017 + *                with optional port and optional explicit family
3018 + *                and optional netmask
3019 + *
3020 + * Parameters  :
3021 + *          0  :  string = the string to parse
3022 + *          1  :  host = Is set to point to the hostname or IP literal
3023 + *                       part
3024 + *          2  :  port = Is set to point to the port part,
3025 + *                       or NULL if no port in string
3026 + *          3  :  pf = pointer used to return the address family
3027 + *                     pf is a value-result argument:
3028 + *                     If it is set to -1, then parse_pf_ip will set it
3029 + *                      to the address family of the pf_ip string
3030 + *                     else, it won't touch it, and fail if the two
3031 + *                      cannot match
3032 + *          4  :  pointer used to return the mask length
3033 + *                Set to -1 if no mask
3034 + *
3035 + * Returns     :  0 on success
3036 + *
3037 + *********************************************************************/
3038 +int parse_pf_ip_netmask(char *string, char **host, char **port, int *pf, int *masklength)
3039 +{
3040 +   int i;
3041 +   char *p;
3042 +
3043 +   *masklength = -1;
3044 +
3045 +   if ((p = strchr(string, '/')) != NULL)
3046 +   {
3047 +      *p++ = '\0';
3048 +
3049 +      if (ijb_isdigit(*p) == 0)
3050 +      {
3051 +         return -1;
3052 +      }
3053 +      i = atoi(p);
3054 +      if ( i < 0 )
3055 +         return -1;
3056 +      *masklength = i;
3057 +   }
3058 +
3059 +   return parse_pf_ip(string, host, port, pf);
3060 +}
3061 +
3062 +/*********************************************************************
3063 + *
3064 + * Function    :  parse_pf_ip
3065 + *
3066 + * Description :  Parse an IPv{4,6} litteral or hostname
3067 + *                with optional port and optional explicit family
3068 + *
3069 + * Parameters  :
3070 + *          0  :  string = the string to parse
3071 + *          1  :  host = Is set to point to the hostname or IP literal
3072 + *                       part
3073 + *          2  :  port = Is set to point to the port part,
3074 + *                       or NULL if no port in string
3075 + *          3  :  pf = pointer used to return the address family
3076 + *                     pf is a value-result argument:
3077 + *                     If it is set to -1, then parse_pf_ip will set it
3078 + *                      to the address family of the pf_ip string
3079 + *                     else, it won't touch it, and fail if the two
3080 + *                      cannot match
3081 + *
3082 + * Returns     :  0 on success
3083 + *
3084 + *********************************************************************/
3085 +int parse_pf_ip(char *string, char **host, char **port, int *pf)
3086 +{
3087 +   if (pf != NULL && *pf == -1)
3088 +      *pf = PF_UNSPEC;
3089 +
3090 +   /* See if we want to override the default protocol family */
3091 +   if (strncmpic(string, "ipv4:", 5) == 0)
3092 +   {
3093 +      string += 5;
3094 +      if (pf!=NULL)
3095 +      {
3096 +         if(*pf==PF_INET || *pf==PF_UNSPEC)
3097 +            *pf = AF_INET;
3098 +         else
3099 +         {
3100 +            log_error(LOG_LEVEL_ERROR,"%s","IPv4 address found where other awaited");
3101 +            return -2;
3102 +         }
3103 +      }
3104 +   }
3105 +   else if (strncmpic(string, "ipv6:", 5) == 0)
3106 +   {
3107 +#ifdef INET6
3108 +      string += 5;
3109 +      if(*pf==PF_INET6 || *pf==PF_UNSPEC)
3110 +         *pf = AF_INET6;
3111 +      else
3112 +      {
3113 +        log_error(LOG_LEVEL_ERROR,"%s","IPv6 address found where other awaited");
3114 +        return -2;
3115 +      }
3116 +#else
3117 +      log_error(LOG_LEVEL_ERROR,"%s","This privoxy hasn't IPv6 support");
3118 +      return -1;
3119 +#endif
3120 +   }
3121 +   return parse_ip(string, host, port);
3122 +}
3123 +
3124 +/*********************************************************************
3125 + *
3126 + * Function    :  parse_ip
3127 + *
3128 + * Description :  Parse an IPv{4,6} litteral or hostname
3129 + *                with optional port
3130 + *
3131 + * Parameters  :
3132 + *          0  :  string = the string to parse
3133 + *          1  :  host = Is set to point to the hostname or IP literal
3134 + *                       part
3135 + *          2  :  port = Is set to point to the port part,
3136 + *                       or NULL if no port in string
3137 + * Returns     :  0 on success
3138 + *
3139 + *********************************************************************/
3140 +int parse_ip(char *string, char **host, char **port)
3141 +{
3142 +   char *p;
3143 +   int skip;
3144 +
3145 +   /* allow IPv6 address literal: [numbers:with:colons]:port/mask */
3146 +   if (string[0] == '[' && (p = strchr(string, ']')))
3147 +   {
3148 +      *p++ = '\0';
3149 +      skip = 1;
3150 +   }
3151 +   else
3152 +   {
3153 +      p = string;
3154 +      skip = 0;
3155 +   }
3156 +
3157 +   if (host != NULL)
3158 +      *host = string + skip;
3159 +
3160 +   for(;*p != '\0'; ++p)
3161 +   {
3162 +      if (*p == ':')
3163 +      {
3164 +         *p++ = '\0';
3165 +         break;
3166 +      }
3167 +   }
3168 +   if (port != NULL)
3169 +      *port = p;
3170 +   return 0;
3171 +}
3172 +
3173  
3174  /*********************************************************************
3175   *
3176 diff -urNad privoxy~/parsers.h privoxy/parsers.h
3177 --- privoxy~/parsers.h
3178 +++ privoxy/parsers.h
3179 @@ -19,6 +19,9 @@
3180   * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
3181   *                Privoxy team. http://www.privoxy.org/
3182   *
3183 + *                Modified by Lionel Elie Mamane <lionel@mamane.lu>
3184 + *                for IPv6 support on 24 January 2003.
3185 + *
3186   *                Based on the Internet Junkbuster originally written
3187   *                by and Copyright (C) 1997 Anonymous Coders and 
3188   *                Junkbusters Corporation.  http://www.junkbusters.com
3189 @@ -270,6 +273,10 @@
3190  extern jb_err server_last_modified   (struct client_state *csp, char **header);
3191  extern jb_err server_content_disposition(struct client_state *csp, char **header);
3192  
3193 +extern int parse_pf_ip_netmask(char *string, char **host, char **port, int *pf, int *masklength);
3194 +extern int parse_pf_ip(char *string, char ** host, char ** port, int *pf);
3195 +extern int parse_ip(char *string, char ** host, char** port);
3196 +
3197  #ifdef FEATURE_FORCE_LOAD
3198  extern int strclean(const char *string, const char *substring);
3199  #endif /* def FEATURE_FORCE_LOAD */
3200 diff -urNad privoxy~/project.h privoxy/project.h
3201 --- privoxy~/project.h
3202 +++ privoxy/project.h
3203 @@ -598,6 +598,20 @@
3204  
3205  #endif /* ndef _WIN32 */
3206  
3207 +#include "jb_socket_set.h"
3208 +
3209 +#ifdef INET6
3210 +/**
3211 + * Get from the operating system structures big enough
3212 + * to put a network address in, namely sockaddr_storage
3213 + */
3214 +#include <sys/socket.h> 
3215 +/**
3216 + * If no IPv6 support, just use the old sockaddr
3217 + */
3218 +#else
3219 +#define sockaddr_storage   sockaddr
3220 +#endif
3221  
3222  /**
3223   * A standard error code.  This should be JB_ERR_OK or one of the JB_ERR_xxx
3224 @@ -667,19 +681,6 @@
3225   */
3226  #define FOREVER 1
3227  
3228 -/**
3229 - * Default IP address to listen on, as a string.
3230 - * Set to "127.0.0.1".
3231 - */
3232 -#define HADDR_DEFAULT   "127.0.0.1"
3233 -
3234 -/**
3235 - * Default port to listen on, as a number.
3236 - * Set to 8118.
3237 - */
3238 -#define HADDR_PORT      8118
3239 -
3240 -
3241  /* Forward def for struct client_state */
3242  struct configuration_spec;
3243  
3244 @@ -758,13 +759,16 @@
3245     char *ver;      /**< Protocol version */
3246     int status;     /**< HTTP Status */
3247  
3248 +   char *host_port_malloc;     /**< malloc used for place wher host and port_str are */
3249     char *host;     /**< Host part of URL */
3250     int   port;     /**< Port of URL or 80 (default) */
3251 +   char *port_str; /**< Port of URL, as string */
3252     char *path;     /**< Path of URL */
3253     char *hostport; /**< host[:port] */
3254     int   ssl;      /**< Flag if protocol is https */
3255  
3256 -   char *host_ip_addr_str; /**< String with dotted decimal representation
3257 +   char *host_ip_addr_str; /**< String with dotted decimal representation (IPv4)
3258 +                                or hexadecimal colon-separated (IPv6)
3259                                  of host's IP. NULL before connect_to() */
3260  
3261     char  *dbuffer; /**< Buffer with '\0'-delimited domain name.           */
3262 @@ -1144,13 +1148,16 @@
3263         As a string. */
3264     char *ip_addr_str;
3265     /** Client PC's IP address, as reported by the accept() function.
3266 -       As a number. */
3267 -   long  ip_addr_long;
3268 +       As an address. */
3269 +   struct sockaddr_storage ip_addr_addr;
3270  
3271     /** Our IP address. I.e. the IP address that the client used to reach us,
3272         as a string. */
3273     char *my_ip_addr_str;
3274  
3275 +   /** Our  port. I.e. the port the client used to reach us */
3276 +   char *my_port_str;
3277 +
3278     /** Our hostname. I.e. the reverse DNS of the IP address that the client
3279         used to reach us, as a string. */
3280     char *my_hostname;
3281 @@ -1325,18 +1332,33 @@
3282     /** Connection type.  Must be SOCKS_NONE, SOCKS_4, or SOCKS_4A. */
3283     int   type;
3284  
3285 +   /** pointer returned by the malloc used for gateway_host and gateway_port_str */
3286 +   char *gateway_malloc;
3287 +
3288     /** SOCKS server hostname.  Only valid if "type" is SOCKS_4 or SOCKS_4A. */
3289     char *gateway_host;
3290  
3291     /** SOCKS server port. */
3292     int   gateway_port;
3293  
3294 +   /** SOCKS server port, as string. */
3295 +   char *gateway_port_str;
3296 +
3297 +   /** pointer returned by the malloc used for forward_host and forward_port_str */
3298 +   char *forward_malloc;
3299 +
3300 +   /** Parent HTTP proxy address family. */
3301 +   int forward_family;
3302 +
3303     /** Parent HTTP proxy hostname, or NULL for none. */
3304     char *forward_host;
3305  
3306     /** Parent HTTP proxy port. */
3307     int   forward_port;
3308  
3309 +   /** Parent HTTP proxy port as string. */
3310 +   char *forward_port_str;
3311 +
3312     /** Next entry in the linked list. */
3313     struct forward_spec *next;
3314  };
3315 @@ -1345,7 +1367,7 @@
3316  /**
3317   * Initializer for a static struct forward_spec.
3318   */
3319 -#define FORWARD_SPEC_INITIALIZER { { URL_SPEC_INITIALIZER }, 0, NULL, 0, NULL, 0, NULL }
3320 +#define FORWARD_SPEC_INITIALIZER { { URL_SPEC_INITIALIZER }, 0, NULL, NULL, 0, NULL, NULL, 0, NULL, 0, NULL, NULL}
3321  
3322  
3323  /**
3324 @@ -1374,7 +1396,8 @@
3325   */
3326  struct access_control_addr
3327  {
3328 -   unsigned long addr;  /**< The IP address as an integer. */
3329 +   struct sockaddr_storage addr; /**< The IP address. */
3330 +   size_t addrlen;
3331     unsigned long mask;  /**< The network mask as an integer. */
3332     unsigned long port;  /**< The port number. */
3333  };
3334 @@ -1409,6 +1432,17 @@
3335  /** configuration_spec::feature_flags: HTTP-header-based toggle. */
3336  #define RUNTIME_FEATURE_HTTP_TOGGLE       4
3337  
3338 +struct bind_spec
3339 +{
3340 +   /** IP address to bind to. */
3341 +   char *haddr;
3342 +
3343 +   /** Port to bind to. */
3344 +   char *hport;
3345 +
3346 +   /** Address family */
3347 +   int pf;
3348 +};
3349  /**
3350   * Data loaded from the configuration file.
3351   *
3352 @@ -1472,11 +1506,13 @@
3353  
3354  #endif /* def FEATURE_COOKIE_JAR */
3355  
3356 -   /** IP address to bind to.  Defaults to HADDR_DEFAULT == 127.0.0.1. */
3357 -   const char *haddr;
3358 -
3359 -   /** Port to bind to.  Defaults to HADDR_PORT == 8118. */
3360 -   int         hport;
3361 +   /* IP addresses and ports to bind to.
3362 +       Defaults to HSPECS_DEFAULT == {ipv4:127.0.0.1:8118, ipv6:[::1]:8118}. */
3363 +   struct bind_spec *hspecs;
3364 +   /* size allocated */
3365 +   unsigned int hspecs_size;
3366 +   /* number of entries */
3367 +   unsigned int hspecs_occupied;
3368  
3369     /** Size limit for IOB */
3370     size_t buffer_limit;
3371 diff -urNad privoxy~/urlmatch.c privoxy/urlmatch.c
3372 --- privoxy~/urlmatch.c
3373 +++ privoxy/urlmatch.c
3374 @@ -137,6 +137,7 @@
3375  #include "ssplit.h"
3376  #include "miscutil.h"
3377  #include "errlog.h"
3378 +#include "parsers.h"
3379  
3380  const char urlmatch_h_rcs[] = URLMATCH_H_VERSION;
3381  
3382 @@ -160,7 +161,7 @@
3383     freez(http->cmd);
3384     freez(http->ocmd);
3385     freez(http->gpc);
3386 -   freez(http->host);
3387 +   freez(http->host_port_malloc);
3388     freez(http->url);
3389     freez(http->hostport);
3390     freez(http->path);
3391 @@ -302,8 +303,6 @@
3392      */
3393     {
3394        char *buf;
3395 -      char *host;
3396 -      char *port;
3397  
3398        buf = strdup(http->hostport);
3399        if (buf == NULL)
3400 @@ -311,38 +310,34 @@
3401           return JB_ERR_MEMORY;
3402        }
3403  
3404 +               http->host_port_malloc = buf;
3405 +
3406        /* check if url contains username and/or password */
3407 -      host = strchr(buf, '@');
3408 -      if (host != NULL)
3409 +      buf = strchr(buf, '@');
3410 +      if (buf != NULL)
3411        {
3412           /* Contains username/password, skip it and the @ sign. */
3413 -         host++;
3414 +         buf++;
3415        }
3416        else
3417        {
3418           /* No username or password. */
3419 -         host = buf;
3420 +         buf = http->host_port_malloc;
3421        }
3422  
3423 -      /* check if url contains port */
3424 -      port = strchr(host, ':');
3425 -      if (port != NULL)
3426 +      parse_ip(buf,&http->host,&http->port_str);
3427 +
3428 +      if (*http->port_str != '\0')
3429        {
3430 -         /* Contains port */
3431 -         /* Terminate hostname and point to start of port string */
3432 -         *port++ = '\0';
3433 -         http->port = atoi(port);
3434 +         http->port = atoi(http->port_str);
3435        }