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