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