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