ceabc4d61e524f853ceadc2f4e5719205616c230
[privoxy.git] / debian / patches / 03_ipv6.dpatch
1 #! /bin/sh /usr/share/dpatch/dpatch-run
2 ## 03_ipv6.dpatch by Petr Písař <petrp@users.sf.net>
3 ##
4 ## All lines beginning with `## DP:' are a description of the patch.
5 ## DP: IPv6 support for privoxy.
6 ## DP: http://xpisar.wz.cz/privoxy-ipv6/privoxy-3.0.10-ipv6-all-6.diff
7 ## DP: Former versions by Lionel Elie Mamane <lionel@mamane.lu>
8
9 @DPATCH@
10 diff -urNad privoxy~/configure.in privoxy/configure.in
11 --- privoxy~/configure.in
12 +++ privoxy/configure.in
13 @@ -1237,7 +1237,7 @@
14  AC_TYPE_SIGNAL
15  dnl uncommenting does not work for swa. suse linux
16  dnl AC_FUNC_STAT
17 -AC_CHECK_FUNCS([access atexit getcwd gethostbyaddr gethostbyaddr_r gethostbyname gethostbyname_r gettimeofday inet_ntoa localtime_r memchr memmove memset poll putenv random regcomp select setlocale snprintf socket strchr strdup strerror strftime strlcat strlcpy strptime strstr strtoul timegm tzset])
18 +AC_CHECK_FUNCS([access atexit getaddrinfo getcwd gethostbyaddr gethostbyaddr_r gethostbyname gethostbyname_r getnameinfo gettimeofday inet_ntoa localtime_r memchr memmove memset poll putenv random regcomp select setlocale snprintf socket strchr strdup strerror strftime strlcat strlcpy strptime strstr strtoul timegm tzset])
19  
20  
21  dnl =================================================================
22 diff -urNad privoxy~/doc/source/p-config.sgml privoxy/doc/source/p-config.sgml
23 --- privoxy~/doc/source/p-config.sgml
24 +++ privoxy/doc/source/p-config.sgml
25 @@ -1213,9 +1213,9 @@
26    <term>Effect if unset:</term>
27    <listitem>
28     <para>
29 -    Bind to 127.0.0.1 (localhost), port 8118. This is suitable and recommended for
30 -    home users who run <application>Privoxy</application> on the same machine as
31 -    their browser.
32 +    Bind to 127.0.0.1 (IPv4 localhost), port 8118. This is suitable and
33 +    recommended for home users who run <application>Privoxy</application> on
34 +    the same machine as their browser.
35     </para>
36    </listitem>
37   </varlistentry>
38 @@ -1231,6 +1231,9 @@
39      will need to override the default.
40     </para>
41     <para>
42 +    IPv6 address containing colons has to be quoted by brackets.
43 +   </para>
44 +   <para>
45      If you leave out the IP address, <application>Privoxy</application> will
46      bind to all interfaces (addresses) on your machine and may become reachable
47      from the Internet. In that case, consider using <link
48 @@ -1259,6 +1262,15 @@
49    listen-address  192.168.0.1:8118
50  </programlisting>
51     </para>
52 +   <para>
53 +    Suppose you are running <application>Privoxy</application> on IPv6 capable
54 +    machine and you want to listen on IPv6 loopback device:
55 +   </para>
56 +   <para>
57 +    <programlisting>
58 +  listen-address [::1]:8118
59 +</programlisting>
60 +   </para>
61    </listitem>
62   </varlistentry>
63  </variablelist>
64 @@ -1611,23 +1623,41 @@
65    <term>Type of value:</term>
66    <listitem>
67     <para>
68 -    <replaceable class="parameter">src_addr</replaceable>[/<replaceable class="parameter">src_masklen</replaceable>]
69 -    [<replaceable class="parameter">dst_addr</replaceable>[/<replaceable class="parameter">dst_masklen</replaceable>]]
70 +    <replaceable class="parameter">src_addr</replaceable>[:<replaceable class="parameter">port</replaceable>][/<replaceable class="parameter">src_masklen</replaceable>]
71 +    [<replaceable class="parameter">dst_addr</replaceable>[:<replaceable class="parameter">port</replaceable>][/<replaceable class="parameter">dst_masklen</replaceable>]]
72     </para>
73     <para>
74      Where <replaceable class="parameter">src_addr</replaceable> and 
75 -   <replaceable class="parameter">dst_addr</replaceable> are IP addresses in dotted decimal notation or valid
76 -    DNS names, and <replaceable class="parameter">src_masklen</replaceable> and
77 +   <replaceable class="parameter">dst_addr</replaceable> are IPv4 addresses in dotted decimal notation or valid
78 +    DNS names, <replaceable class="parameter">port</replaceable> is port
79 +    number, and <replaceable class="parameter">src_masklen</replaceable> and
80      <replaceable class="parameter">dst_masklen</replaceable> are subnet masks in CIDR notation, i.e. integer
81      values from 2 to 30 representing the length (in bits) of the network address. The masks and the whole
82      destination part are optional.
83     </para>
84 +   <para>
85 +    If your system implements
86 +    <ulink url="http://tools.ietf.org/html/rfc2553">RFC 2553</ulink>, then
87 +    <replaceable class="parameter">src_addr</replaceable> and <replaceable
88 +    class="parameter">dst_addr</replaceable> can be IPv6 addresses delimeted by
89 +    brackets, <replaceable class="parameter">port</replaceable> can be number
90 +    or service name, and
91 +    <replaceable class="parameter">src_masklen</replaceable> and
92 +    <replaceable class="parameter">dst_masklen</replaceable> can be number
93 +    from 0 to 128.
94 +   </para>
95    </listitem>
96   </varlistentry>
97   <varlistentry>
98    <term>Default value:</term>
99    <listitem>
100     <para><emphasis>Unset</emphasis></para>
101 +   <para>
102 +    No <replaceable class="parameter">port</replaceable> means match any port
103 +    and no <replaceable class="parameter">src_masklen</replaceable> or
104 +    no <replaceable class="parameter">src_masklen</replaceable> means exactly
105 +    given IP address (i.e. 32 for IPv4 and 128 for IPv6).
106 +   </para>
107    </listitem>
108   </varlistentry>
109   <varlistentry>
110 @@ -1677,6 +1707,13 @@
111      IP addresses, only the first one is used.
112     </para>
113     <para>
114 +     Some systems allows IPv4 client to connect to IPv6 server socket.
115 +     Then the client's IPv4 address will be translated by system into
116 +     IPv6 address space with special prefix ::ffff/96 (so called IPv4
117 +     mapped IPv6 address). <application>Privoxy</application> can handle it
118 +     and maps such ACL addresses automatically.
119 +   </para>
120 +   <para>
121      Denying access to particular sites by ACL may have undesired side effects
122      if the site in question is hosted on a machine which also hosts other sites
123      (most sites are).
124 @@ -1717,6 +1754,24 @@
125    deny-access    192.168.45.73    www.dirty-stuff.example.com
126  </screen>
127     </para>
128 +   <para>
129 +     Allow access from IPv4 network 192.0.2.0/24 even if listening on
130 +     IPv6 wild card address (where supported by operating system):
131 +   </para>
132 +   <para>
133 +    <programlisting>
134 +  permit-access  192.0.2.0/24
135 +</programlisting>
136 +   </para>
137 +   <para>
138 +     This is equivalent to the following line even if listening on IPv4
139 +     address (where supported by operating system):
140 +   </para>
141 +   <para>
142 +    <programlisting>
143 +  permit-access  [::ffff:192.0.2.0]/120
144 +</programlisting>
145 +   </para>
146    </listitem>
147   </varlistentry>
148  </variablelist>
149 @@ -1838,7 +1893,7 @@
150      denote <quote>all URLs</quote>.
151      <replaceable class="parameter">http_parent</replaceable>[:<replaceable class="parameter">port</replaceable>]
152      is the DNS name or IP address of the parent HTTP proxy through which the requests should be forwarded,
153 -    optionally followed by its listening port (default: 8080).
154 +    optionally followed by its listening port (default: 8000).
155      Use a single dot (<literal>.</literal>) to denote <quote>no forwarding</quote>.
156     </para>
157    </listitem>
158 @@ -1865,6 +1920,16 @@
159      forwarded to another HTTP proxy but are made directly to the web servers.
160     </para>
161     <para>
162 +    <replaceable class="parameter">http_parent</replaceable> can be IPv6
163 +    numerical address (if
164 +    <ulink url="http://tools.ietf.org/html/rfc2553">RFC 2553</ulink> is
165 +    implemented). However not to clash with port delimiter, quote
166 +    whole IP address with brackets. On the other hand <replaceable
167 +    class="parameter">target_pattern</replaceable> containing IPv6 address
168 +    must be delimited by angle brackets (normal brackets are reserved for
169 +    regular expression already).
170 +   </para>
171 +   <para>
172      Multiple lines are OK, they are checked in sequence, and the last match wins.
173     </para>
174    </listitem>
175 @@ -1891,6 +1956,24 @@
176    forward   .isp.example.net   .
177  </screen>
178     </para>
179 +   <para>
180 +    Parent proxy specified by IPv6 address:
181 +   </para>
182 +   <para>
183 +    <programlisting>
184 +  foward   /                   [2001:DB8::1]:8000
185 +</programlisting>
186 +   </para>
187 +   <para>
188 +    Suppose your parent proxy doesn't support IPv6:
189 +   </para>
190 +   <para>
191 +    <programlisting>
192 +  forward  /                        parent-proxy.example.org:8000 
193 +  forward  ipv6-server.example.org  .
194 +  forward  &lt;[2-3][0-9a-f][0-9a-f][0-9a-f]:*&gt;   .
195 +</programlisting>
196 +   </para>
197    </listitem>
198   </varlistentry>
199  </variablelist>
200 @@ -1963,6 +2046,18 @@
201      With <literal>forward-socks5</literal> the DNS resolution will happen on the remote server as well.
202     </para>
203     <para>
204 +    <replaceable class="parameter">socks_proxy</replaceable> and
205 +    <replaceable class="parameter">http_parent</replaceable> can be IPv6
206 +    numerical address (if
207 +    <ulink url="http://tools.ietf.org/html/rfc2553">RFC 2553</ulink> is
208 +    implemented). However not to clash with port
209 +    delimiter, quote whole IP address with brackets. On the other
210 +    hand <replaceable class="parameter">target_pattern</replaceable> containing
211 +    IPv6 address must be delimited by angle brackets (normal brackets are
212 +    reserved for regular expression already). The only exception is SOCKS 4
213 +    version where only IPv4 is suppored. 
214 +   </para>
215 +   <para>
216      If <replaceable class="parameter">http_parent</replaceable> is <quote>.</quote>, then requests are not
217      forwarded to another HTTP proxy but are made (HTTP-wise) directly to the web servers, albeit through
218      a SOCKS proxy.
219 diff -urNad privoxy~/doc/source/user-manual.sgml privoxy/doc/source/user-manual.sgml
220 --- privoxy~/doc/source/user-manual.sgml
221 +++ privoxy/doc/source/user-manual.sgml
222 @@ -2147,12 +2147,12 @@
223   
224  <para>
225   Generally, an URL pattern has the form
226 - <literal>&lt;domain&gt;/&lt;path&gt;</literal>, where both the
227 - <literal>&lt;domain&gt;</literal> and <literal>&lt;path&gt;</literal> are
228 - optional. (This is why the special <literal>/</literal> pattern matches all
229 - URLs). Note that the protocol portion of the URL pattern (e.g.
230 - <literal>http://</literal>) should <emphasis>not</emphasis> be included in
231 - the pattern. This is assumed already!
232 + <literal>&lt;domain&gt;&lt;port&gt;/&lt;path&gt;</literal>, where both the
233 + <literal>&lt;domain&gt;</literal> and <literal>&lt;port&gt;</literal>
234 + and <literal>&lt;path&gt;</literal> are optional. (This is why the special
235 + <literal>/</literal> pattern matches all URLs). Note that the protocol
236 + portion of the URL pattern (e.g. <literal>http://</literal>) should
237 + <emphasis>not</emphasis> be included in the pattern. This is assumed already!
238  </para>
239  <para>
240   The pattern matching syntax is different for the domain and path parts of
241 @@ -2161,6 +2161,12 @@
242   <ulink url="http://en.wikipedia.org/wiki/Regular_expressions"><quote>Regular
243    Expressions</quote></ulink> (POSIX 1003.2).
244  </para>
245 +<para>
246 + The port part of pattern is decimal port number preceeded by a colon
247 + (<literal>:</literal>). If domain part contains numeric IPv6 address, you
248 + will need to quote the domain part by angle brackets
249 + (<literal>&lt;</literal>, <literal>&gt;</literal>).
250 +</para>
251  
252  <variablelist>
253   <varlistentry>
254 @@ -2211,6 +2217,23 @@
255    </listitem>
256   </varlistentry>
257   <varlistentry>
258 +  <term><literal>:8000/</literal></term>
259 +  <listitem>
260 +   <para>
261 +    Matches any URL pointing to TCP port 8000.
262 +   </para>
263 +  </listitem>
264 + </varlistentry>
265 + <varlistentry>
266 +  <term><literal>&lt;2001:db8::1&gt;/</literal></term>
267 +  <listitem>
268 +   <para>
269 +    Matches any URL having <literal>2001:db8::1</literal> as a domain.
270 +    (Note that real URL uses plain brackets, not an angle brackets.)
271 +   </para>
272 +  </listitem>
273 + </varlistentry>
274 + <varlistentry>
275    <term><literal>index.html</literal></term>
276    <listitem>
277     <para>
278 diff -urNad privoxy~/filters.c privoxy/filters.c
279 --- privoxy~/filters.c
280 +++ privoxy/filters.c
281 @@ -665,6 +665,11 @@
282  #include <string.h>
283  #include <assert.h>
284  
285 +#ifdef HAVE_GETADDRINFO
286 +#include <netdb.h>
287 +#include <sys/socket.h>
288 +#endif /* def HAVE_GETADDRINFO */
289 +
290  #ifndef _WIN32
291  #ifndef __OS2__
292  #include <unistd.h>
293 @@ -712,6 +717,152 @@
294  static jb_err prepare_for_filtering(struct client_state *csp);
295  
296  #ifdef FEATURE_ACL
297 +#ifdef HAVE_GETADDRINFO
298 +/*********************************************************************
299 + *
300 + * Function    :  sockaddr_storage_to_ip
301 + *
302 + * Description :  Access internal structure of sockaddr_storage
303 + *
304 + * Parameters  :
305 + *          1  :  addr = socket address
306 + *          2  :  ip   = IP address as array of octets in network order
307 + *                       (it points into addr)
308 + *          3  :  len  = length of IP address in octets
309 + *          4  :  port = port number in network order;
310 + *
311 + * Returns     :  0 = no errror; otherwise 
312 + *
313 + *********************************************************************/
314 +int sockaddr_storage_to_ip(const struct sockaddr_storage *addr, uint8_t **ip,
315 +      unsigned int *len, in_port_t **port)
316 +{
317 +   if (!addr)
318 +   {
319 +      return(-1);
320 +   }
321 +
322 +   switch (addr->ss_family)
323 +   {
324 +      case AF_INET:
325 +         if (len)
326 +         {
327 +            *len = 4;
328 +         }
329 +         if (ip)
330 +         {
331 +            *ip = (uint8_t *)
332 +               &(( (struct sockaddr_in *) addr)->sin_addr.s_addr);
333 +         }
334 +         if (port)
335 +         {
336 +            *port = &((struct sockaddr_in *) addr)->sin_port;
337 +         }
338 +         break;
339 +
340 +      case AF_INET6:
341 +         if (len)
342 +         {
343 +            *len = 16;
344 +         }
345 +         if (ip)
346 +         {
347 +            *ip = (uint8_t *)
348 +               &(( (struct sockaddr_in6 *) addr)->sin6_addr.s6_addr);
349 +         }
350 +         if (port)
351 +         {
352 +            *port = &((struct sockaddr_in6 *) addr)->sin6_port;
353 +         }
354 +         break;
355 +
356 +      default:
357 +         /* Unsupported address family */
358 +         return(-1);
359 +   }
360 +
361 +   return(0);
362 +}
363 +
364 +
365 +/*********************************************************************
366 + *
367 + * Function    :  match_sockaddr
368 + *
369 + * Description :  Check whether address matches network (IP address and port)
370 + *
371 + * Parameters  :
372 + *          1  :  network = socket address of subnework
373 + *          3  :  netmask = network mask as socket address 
374 + *          2  :  address = checked socket address against given network
375 + *
376 + * Returns     :  0 = doesn't match; 1 = does match
377 + *
378 + *********************************************************************/
379 +int match_sockaddr(const struct sockaddr_storage *network,
380 +      const struct sockaddr_storage *netmask,
381 +      const struct sockaddr_storage *address)
382 +{
383 +   uint8_t *network_addr, *netmask_addr, *address_addr;
384 +   unsigned int addr_len;
385 +   in_port_t *network_port, *netmask_port, *address_port;
386 +   int i;
387 +
388 +   if (network->ss_family != netmask->ss_family) 
389 +   {
390 +      /* This should never happen */
391 +      log_error(LOG_LEVEL_ERROR,
392 +            "Internal error at %s:%llu: network and netmask differ in family",
393 +            __FILE__, __LINE__);
394 +      return 0;
395 +   }
396 +
397 +   sockaddr_storage_to_ip(network, &network_addr, &addr_len, &network_port);
398 +   sockaddr_storage_to_ip(netmask, &netmask_addr, NULL, &netmask_port);
399 +   sockaddr_storage_to_ip(address, &address_addr, NULL, &address_port);
400 +
401 +   /* Check for family */
402 +   if (network->ss_family == AF_INET && address->ss_family == AF_INET6 &&
403 +         IN6_IS_ADDR_V4MAPPED(address_addr))
404 +   {
405 +      /* Map AF_INET6 V4MAPPED address into AF_INET */
406 +      address_addr += 12;
407 +      addr_len = 4;
408 +   }
409 +   else if (network->ss_family == AF_INET6 && address->ss_family == AF_INET &&
410 +         IN6_IS_ADDR_V4MAPPED(network_addr))
411 +   {
412 +      /* Map AF_INET6 V4MAPPED network into AF_INET */
413 +      network_addr += 12;
414 +      netmask_addr += 12;
415 +      addr_len = 4;
416 +   }
417 +   else if (network->ss_family != address->ss_family)
418 +   {
419 +      return 0;
420 +   }
421 +
422 +   /* XXX: Port check is signaled in netmask */
423 +   if (*netmask_port && *network_port != *address_port)
424 +   {
425 +      return 0;
426 +   }
427 +
428 +   /* TODO: Optimize by checking by words insted of octets */
429 +   for (i=0; i < addr_len && netmask_addr[i]; i++)
430 +   {
431 +      if ( (network_addr[i] & netmask_addr[i]) !=
432 +           (address_addr[i] & netmask_addr[i]) )
433 +      {
434 +         return 0;
435 +      }
436 +   }
437 +   
438 +   return 1;
439 +}
440 +#endif /* def HAVE_GETADDRINFO */
441 +
442 +
443  /*********************************************************************
444   *
445   * Function    :  block_acl
446 @@ -741,7 +892,13 @@
447     /* search the list */
448     while (acl != NULL)
449     {
450 -      if ((csp->ip_addr_long & acl->src->mask) == acl->src->addr)
451 +      if (
452 +#ifdef HAVE_GETADDRINFO
453 +            match_sockaddr(&acl->src->addr, &acl->src->mask, &csp->tcp_addr) 
454 +#else
455 +            (csp->ip_addr_long & acl->src->mask) == acl->src->addr
456 +#endif
457 +            )
458        {
459           if (dst == NULL)
460           {
461 @@ -751,8 +908,23 @@
462                 return(0);
463              }
464           }
465 -         else if ( ((dst->addr & acl->dst->mask) == acl->dst->addr)
466 -           && ((dst->port == acl->dst->port) || (acl->dst->port == 0)))
467 +         else if (
468 +#ifdef HAVE_GETADDRINFO
469 +               /* XXX: Undefined acl->dst is full of zeros and should be
470 +                * considered as wildcard address.
471 +                * sockaddr_storage_to_ip() failes on such dst because of
472 +                * uknown sa_familly on glibc. However this test is not
473 +                * portable.
474 +                *
475 +                * So, we signal the acl->dst is wildcard in wildcard_dst.
476 +                */
477 +               acl->wildcard_dst ||
478 +                  match_sockaddr(&acl->dst->addr, &acl->dst->mask, &dst->addr)
479 +#else
480 +               ((dst->addr & acl->dst->mask) == acl->dst->addr)
481 +           && ((dst->port == acl->dst->port) || (acl->dst->port == 0))
482 +#endif
483 +           )
484           {
485              if (acl->action == ACL_PERMIT)
486              {
487 @@ -788,12 +960,24 @@
488  int acl_addr(const char *aspec, struct access_control_addr *aca)
489  {
490     int i, masklength;
491 +#ifdef HAVE_GETADDRINFO
492 +   struct addrinfo hints, *result;
493 +   uint8_t *mask_data;
494 +   in_port_t *mask_port;
495 +   unsigned int addr_len;
496 +#else
497     long port;
498 +#endif /* def HAVE_GETADDRINFO */
499     char *p;
500     char *acl_spec = NULL;
501  
502 +#ifdef HAVE_GETADDRINFO
503 +   /* FIXME: Depend on ai_family */
504 +   masklength = 128;
505 +#else
506     masklength = 32;
507     port       =  0;
508 +#endif
509  
510     /*
511      * Use a temporary acl spec copy so we can log
512 @@ -817,13 +1001,53 @@
513        masklength = atoi(p);
514     }
515  
516 -   if ((masklength < 0) || (masklength > 32))
517 +   if ((masklength < 0) ||
518 +#ifdef HAVE_GETADDRINFO
519 +         (masklength > 128)
520 +#else
521 +         (masklength > 32)
522 +#endif
523 +         )
524     {
525        freez(acl_spec);
526        return(-1);
527     }
528  
529 -   if ((p = strchr(acl_spec, ':')) != NULL)
530 +   if (*acl_spec == '[' && NULL != (p = strchr(acl_spec, ']')))
531 +   {
532 +      *p = '\0';
533 +      memmove(acl_spec, acl_spec + 1, (size_t) (p - acl_spec));
534 +
535 +      if (*++p != ':')
536 +      {
537 +         p = NULL;
538 +      }
539 +   }
540 +   else
541 +   {
542 +      p = strchr(acl_spec, ':');
543 +   }
544 +
545 +#ifdef HAVE_GETADDRINFO
546 +   memset(&hints, 0, sizeof(struct addrinfo));
547 +   hints.ai_family = AF_UNSPEC;
548 +   hints.ai_socktype = SOCK_STREAM;
549 +
550 +   i = getaddrinfo(acl_spec, (p) ? ++p : NULL, &hints, &result);
551 +   freez(acl_spec);
552 +
553 +   if (i != 0)
554 +   {
555 +      log_error(LOG_LEVEL_ERROR, "Can not resolve [%s]:%s: %s", acl_spec, p,
556 +            gai_strerror(i));
557 +      return(-1);
558 +   }
559 +
560 +   /* TODO: Allow multihomed hostnames */
561 +   memcpy(&(aca->addr), result->ai_addr, sizeof(aca->addr));
562 +   freeaddrinfo(result);
563 +#else
564 +   if (p != NULL)
565     {
566        char *endptr;
567  
568 @@ -847,8 +1071,49 @@
569        /* XXX: This will be logged as parse error. */
570        return(-1);
571     }
572 +#endif /* def HAVE_GETADDRINFO */
573  
574     /* build the netmask */
575 +#ifdef HAVE_GETADDRINFO
576 +   /* Clip masklength according current family */
577 +   if (aca->addr.ss_family == AF_INET && masklength > 32)
578 +   {
579 +      masklength = 32;
580 +   }
581 +
582 +   aca->mask.ss_family = aca->addr.ss_family;
583 +   if (sockaddr_storage_to_ip(&aca->mask, &mask_data, &addr_len, &mask_port))
584 +   {
585 +      return(-1);
586 +   }
587 +
588 +   if (p)
589 +   {
590 +      /* Port number in ACL has been specified, check ports in future */
591 +      *mask_port = 1;
592 +   }
593 +
594 +   /* XXX: This could be optimized to operate on whole words instead of octets
595 +    * (128-bit CPU could do it in one iteration). */
596 +   /* Octets after prefix can be ommitted because of previous initialization
597 +    * to zeros. */
598 +   for (i=0; i < addr_len && masklength; i++)
599 +   {
600 +      if (masklength >= 8)
601 +      {
602 +         mask_data[i] = 0xFF;
603 +         masklength -= 8;
604 +      }
605 +      else
606 +      {
607 +         /* XXX: This assumes MSB of octet is on the left site. This should be
608 +          * true for all architectures or solved on link layer of OSI model. */
609 +         mask_data[i] = ~((1 << (8 - masklength)) - 1);
610 +         masklength = 0;
611 +      }
612 +   }
613 +
614 +#else
615     aca->mask = 0;
616     for (i=1; i <= masklength ; i++)
617     {
618 @@ -859,6 +1124,7 @@
619      * (i.e. save on the network portion of the address).
620      */
621     aca->addr = aca->addr & aca->mask;
622 +#endif /* def HAVE_GETADDRINFO */
623  
624     return(0);
625  
626 @@ -2706,4 +2972,6 @@
627    Local Variables:
628    tab-width: 3
629    end:
630 +
631 +  vim:softtabstop=3 shiftwidth=3
632  */
633 diff -urNad privoxy~/jbsockets.c privoxy/jbsockets.c
634 --- privoxy~/jbsockets.c
635 +++ privoxy/jbsockets.c
636 @@ -357,19 +357,52 @@
637   *********************************************************************/
638  jb_socket connect_to(const char *host, int portnum, struct client_state *csp)
639  {
640 +#ifdef HAVE_GETADDRINFO
641 +   struct addrinfo hints, *result, *rp;
642 +   char service[6];
643 +   int retval;
644 +#else
645     struct sockaddr_in inaddr;
646 -   jb_socket fd;
647     unsigned int addr;
648 +#endif /* def HAVE_GETADDRINFO */
649 +   jb_socket fd;
650     fd_set wfds;
651     struct timeval tv[1];
652  #if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA)
653     int   flags;
654  #endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) */
655 +   int connect_failed;
656  
657  #ifdef FEATURE_ACL
658     struct access_control_addr dst[1];
659  #endif /* def FEATURE_ACL */
660  
661 +#ifdef HAVE_GETADDRINFO
662 +   retval = snprintf(service, sizeof(service), "%d", portnum);
663 +   if (-1 == retval || sizeof(service) <= retval)
664 +   {
665 +      log_error(LOG_LEVEL_ERROR,
666 +            "Port number (%d) ASCII decimal representation doesn't fit into 6 bytes",
667 +            portnum);
668 +      csp->http->host_ip_addr_str = strdup("unknown");
669 +      return(JB_INVALID_SOCKET);
670 +   }
671 +
672 +   memset((char *)&hints, 0, sizeof hints);
673 +   hints.ai_family = AF_UNSPEC;
674 +   hints.ai_socktype = SOCK_STREAM;
675 +   hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV; /* avoid service look-up */
676 +   if ((retval = getaddrinfo(host, service, &hints, &result)))
677 +   {
678 +      log_error(LOG_LEVEL_INFO,
679 +            "Can not resolve %s: %s", host, gai_strerror(retval));
680 +      csp->http->host_ip_addr_str = strdup("unknown");
681 +      return(JB_INVALID_SOCKET);
682 +   }
683 +
684 +   for (rp = result; rp != NULL; rp = rp->ai_next)
685 +   {
686 +#else
687     memset((char *)&inaddr, 0, sizeof inaddr);
688  
689     if ((addr = resolve_hostname_to_ip(host)) == INADDR_NONE)
690 @@ -377,10 +410,15 @@
691        csp->http->host_ip_addr_str = strdup("unknown");
692        return(JB_INVALID_SOCKET);
693     }
694 +#endif /* def HAVE_GETADDRINFO */
695  
696  #ifdef FEATURE_ACL
697 +#ifdef HAVE_GETADDRINFO
698 +   memcpy(&dst->addr, rp->ai_addr, sizeof(dst->addr));
699 +#else
700     dst->addr = ntohl(addr);
701     dst->port = portnum;
702 +#endif /* def HAVE_GETADDRINFO */
703  
704     if (block_acl(dst, csp))
705     {
706 @@ -389,14 +427,43 @@
707  #else
708        errno = EPERM;
709  #endif
710 +#ifdef HAVE_GETADDRINFO
711 +      continue;
712 +#else
713        return(JB_INVALID_SOCKET);
714 +#endif /* def HAVE_GETADDRINFO */
715     }
716  #endif /* def FEATURE_ACL */
717  
718 +#ifdef HAVE_GETNAMEINFO
719 +   csp->http->host_ip_addr_str = malloc(NI_MAXHOST);
720 +   retval = getnameinfo(rp->ai_addr, rp->ai_addrlen,
721 +         csp->http->host_ip_addr_str, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
722 +   if (!csp->http->host_ip_addr_str || retval)
723 +   {
724 +      log_error(LOG_LEVEL_ERROR, "Can not save csp->http->host_ip_addr_str: %s",
725 +            (csp->http->host_ip_addr_str) ? gai_strerror(retval) :
726 +            "Insufficient memory");
727 +      freez(csp->http->host_ip_addr_str);
728 +      continue;
729 +   }
730 +#else
731     inaddr.sin_addr.s_addr = addr;
732     inaddr.sin_family      = AF_INET;
733     csp->http->host_ip_addr_str = strdup(inet_ntoa(inaddr.sin_addr));
734 +#endif /* def HAVE_GETNAMERINFO */
735  
736 +#ifdef HAVE_GETADDRINFO
737 +#ifdef _WIN32
738 +   if ((fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) ==
739 +         JB_INVALID_SOCKET)
740 +#else
741 +   if ((fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) < 0)
742 +#endif
743 +   {
744 +      continue;
745 +   }
746 +#else
747  #ifndef _WIN32
748     if (sizeof(inaddr.sin_port) == sizeof(short))
749  #endif /* ndef _WIN32 */
750 @@ -418,6 +485,7 @@
751     {
752        return(JB_INVALID_SOCKET);
753     }
754 +#endif /* HAVE_GETADDRINFO */
755  
756  #ifdef TCP_NODELAY
757     {  /* turn off TCP coalescence */
758 @@ -434,7 +502,12 @@
759     }
760  #endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) */
761  
762 +   connect_failed = 0;
763 +#ifdef HAVE_GETADDRINFO
764 +   while (connect(fd, rp->ai_addr, rp->ai_addrlen) == JB_INVALID_SOCKET)
765 +#else
766     while (connect(fd, (struct sockaddr *) & inaddr, sizeof inaddr) == JB_INVALID_SOCKET)
767 +#endif /* HAVE_GETADDRINFO */
768     {
769  #ifdef _WIN32
770        if (errno == WSAEINPROGRESS)
771 @@ -454,9 +527,18 @@
772  #endif /* __OS2__ */
773        {
774           close_socket(fd);
775 -         return(JB_INVALID_SOCKET);
776 +         connect_failed = 1;
777 +         break;
778        }
779     }
780 +   if (connect_failed)
781 +   {
782 +#ifdef HAVE_GETADDRINFO
783 +         continue;
784 +#else
785 +         return(JB_INVALID_SOCKET);
786 +#endif
787 +   }
788  
789  #if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__)
790     if (flags != -1)
791 @@ -477,8 +559,32 @@
792     if (select((int)fd + 1, NULL, &wfds, NULL, tv) <= 0)
793     {
794        close_socket(fd);
795 +#ifdef HAVE_GETADDRINFO
796 +      continue;
797 +#else
798        return(JB_INVALID_SOCKET);
799 +#endif
800     }
801 +   
802 +#ifdef HAVE_GETADDRINFO
803 +   break; /* for */
804 +   }
805 +
806 +   freeaddrinfo(result);
807 +   if (!rp)
808 +   {
809 +      log_error(LOG_LEVEL_INFO, "Could not connect to TCP/[%s]:%s", host, service);
810 +      return(JB_INVALID_SOCKET);
811 +   }
812 +   /* XXX: Current connection verification (EINPROGRESS && select() for
813 +    * writing) is not sufficient. E.g. on my Linux-2.6.27 with glibc-2.6
814 +    * select returns socket ready for writing, however subsequential write(2)
815 +    * fails with ENOCONNECT. Read Linux connect(2) man page about non-blocking
816 +    * sockets.
817 +    * Thus we can not log here the socket is connected. */
818 +   /*log_error(LOG_LEVEL_INFO, "Connected to TCP/[%s]:%s", host, service);*/
819 +#endif
820 +
821     return(fd);
822  
823  }
824 @@ -677,7 +783,16 @@
825   *********************************************************************/
826  int bind_port(const char *hostnam, int portnum, jb_socket *pfd)
827  {
828 +#ifdef HAVE_GETADDRINFO
829 +   struct addrinfo hints;
830 +   struct addrinfo *result, *rp;
831 +   /* TODO: portnum shuld be string to allow symbolic service names in
832 +    * configuration and to avoid following int2string */
833 +   char servnam[6];
834 +   int retval;
835 +#else
836     struct sockaddr_in inaddr;
837 +#endif /* def HAVE_GETADDRINFO */
838     jb_socket fd;
839  #ifndef _WIN32
840     int one = 1;
841 @@ -685,6 +800,32 @@
842  
843     *pfd = JB_INVALID_SOCKET;
844  
845 +#ifdef HAVE_GETADDRINFO
846 +   retval = snprintf(servnam, sizeof(servnam), "%d", portnum);
847 +   if (-1 == retval || sizeof(servnam) <= retval)
848 +   {
849 +      log_error(LOG_LEVEL_ERROR,
850 +            "Port number (%d) ASCII decimal representation doesn't fit into 6 bytes",
851 +            portnum);
852 +      return -1;
853 +   }
854 +
855 +   memset(&hints, 0, sizeof(struct addrinfo));
856 +   hints.ai_family=AF_UNSPEC;
857 +   hints.ai_socktype=SOCK_STREAM;
858 +   hints.ai_flags=AI_PASSIVE|AI_ADDRCONFIG;
859 +   hints.ai_protocol=0; /* Realy any stream protocol or TCP only */
860 +   hints.ai_canonname=NULL;
861 +   hints.ai_addr=NULL;
862 +   hints.ai_next=NULL;
863 +
864 +   if ((retval = getaddrinfo(hostnam, servnam, &hints, &result)))
865 +   {
866 +      log_error(LOG_LEVEL_ERROR,
867 +            "Can not resolve %s: %s", hostnam, gai_strerror(retval));
868 +      return -2;
869 +   }
870 +#else
871     memset((char *)&inaddr, '\0', sizeof inaddr);
872  
873     inaddr.sin_family      = AF_INET;
874 @@ -707,8 +848,15 @@
875        inaddr.sin_port = htonl((unsigned long) portnum);
876     }
877  #endif /* ndef _WIN32 */
878 +#endif /* def HAVE_GETADDRINFO */
879  
880 +#ifdef HAVE_GETADDRINFO
881 +   for (rp = result; rp != NULL; rp = rp->ai_next)
882 +   {
883 +      fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
884 +#else
885     fd = socket(AF_INET, SOCK_STREAM, 0);
886 +#endif /* def HAVE_GETADDRINFO */
887  
888  #ifdef _WIN32
889     if (fd == JB_INVALID_SOCKET)
890 @@ -716,7 +864,11 @@
891     if (fd < 0)
892  #endif
893     {
894 +#ifdef HAVE_GETADDRINFO
895 +      continue;
896 +#else
897        return(-1);
898 +#endif
899     }
900  
901  #ifndef _WIN32
902 @@ -735,7 +887,11 @@
903     setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one));
904  #endif /* ndef _WIN32 */
905  
906 +#ifdef HAVE_GETADDRINFO
907 +   if (bind(fd, rp->ai_addr, rp->ai_addrlen) < 0)
908 +#else
909     if (bind(fd, (struct sockaddr *)&inaddr, sizeof(inaddr)) < 0)
910 +#endif
911     {
912  #ifdef _WIN32
913        errno = WSAGetLastError();
914 @@ -744,15 +900,36 @@
915        if (errno == EADDRINUSE)
916  #endif
917        {
918 +#ifdef HAVE_GETADDRINFO
919 +         freeaddrinfo(result);
920 +#endif
921           close_socket(fd);
922           return(-3);
923        }
924        else
925        {
926           close_socket(fd);
927 +#ifndef HAVE_GETADDRINFO
928           return(-1);
929        }
930     }
931 +#else
932 +      }
933 +   }
934 +   else
935 +      /* bind() succeeded, escape from for-loop */
936 +      /* TODO: Support multiple listening sockets (e.g. localhost resolves to
937 +       * AF_INET and AF_INET6, but only fist address is used */
938 +      break;
939 +   }
940 +
941 +   freeaddrinfo(result);
942 +   if (rp == NULL)
943 +   {
944 +      /* All bind()s failed */
945 +      return(-1);
946 +   }
947 +#endif /* ndef HAVE_GETADDRINFO */
948  
949     while (listen(fd, MAX_LISTEN_BACKLOG) == -1)
950     {
951 @@ -792,14 +969,20 @@
952   *********************************************************************/
953  void get_host_information(jb_socket afd, char **ip_address, char **hostname)
954  {
955 +#ifdef HAVE_GETNAMEINFO
956 +   struct sockaddr_storage server;
957 +   int retval;
958 +#else
959     struct sockaddr_in server;
960     struct hostent *host = NULL;
961 +#endif /* HAVE_GETNAMEINFO */
962  #if defined(_WIN32) || defined(__OS2__) || defined(__APPLE_CC__) || defined(AMIGA)
963     /* according to accept_connection() this fixes a warning. */
964 -   int s_length;
965 +   int s_length, s_length_provided;
966  #else
967 -   socklen_t s_length;
968 +   socklen_t s_length, s_length_provided;
969  #endif
970 +#ifndef HAVE_GETNAMEINFO
971  #if defined(HAVE_GETHOSTBYADDR_R_8_ARGS) ||  defined(HAVE_GETHOSTBYADDR_R_7_ARGS) || defined(HAVE_GETHOSTBYADDR_R_5_ARGS)
972     struct hostent result;
973  #if defined(HAVE_GETHOSTBYADDR_R_5_ARGS)
974 @@ -809,7 +992,8 @@
975     int thd_err;
976  #endif /* def HAVE_GETHOSTBYADDR_R_5_ARGS */
977  #endif /* def HAVE_GETHOSTBYADDR_R_(8|7|5)_ARGS */
978 -   s_length = sizeof(server);
979 +#endif /* ifndef HAVE_GETNAMEINFO */
980 +   s_length = s_length_provided = sizeof(server);
981  
982     if (NULL != hostname)
983     {
984 @@ -819,8 +1003,23 @@
985  
986     if (!getsockname(afd, (struct sockaddr *) &server, &s_length))
987     {
988 +      if (s_length > s_length_provided)
989 +      {
990 +         log_error(LOG_LEVEL_ERROR, "getsockname() truncated server address");
991 +         return;
992 +      }
993 +#ifdef HAVE_GETNAMEINFO
994 +      *ip_address = malloc(NI_MAXHOST);
995 +      if ((retval = getnameinfo((struct sockaddr *) &server, s_length,
996 +                  *ip_address, NI_MAXHOST, NULL, 0, NI_NUMERICHOST))) {
997 +         log_error(LOG_LEVEL_ERROR, "Unable to print my own IP address: %s",
998 +               gai_strerror(retval));
999 +         freez(*ip_address);
1000 +         return;
1001 +      }
1002 +#else
1003        *ip_address = strdup(inet_ntoa(server.sin_addr));
1004 -
1005 +#endif /* HAVE_GETNAMEINFO */
1006        if (NULL == hostname)
1007        {
1008           /*
1009 @@ -829,6 +1028,16 @@
1010            */
1011           return;
1012        }
1013 +
1014 +#ifdef HAVE_GETNAMEINFO
1015 +      *hostname = malloc(NI_MAXHOST);
1016 +      if ((retval = getnameinfo((struct sockaddr *) &server, s_length,
1017 +                  *hostname, NI_MAXHOST, NULL, 0, NI_NAMEREQD))) {
1018 +         log_error(LOG_LEVEL_ERROR, "Unable to resolve my own IP address: %s",
1019 +               gai_strerror(retval));
1020 +         freez(*hostname);
1021 +      }
1022 +#else
1023  #if defined(HAVE_GETHOSTBYADDR_R_8_ARGS)
1024        gethostbyaddr_r((const char *)&server.sin_addr,
1025                        sizeof(server.sin_addr), AF_INET,
1026 @@ -866,6 +1075,7 @@
1027        {
1028           *hostname = strdup(host->h_name);
1029        }
1030 +#endif /* else def HAVE_GETNAMEINFO */
1031     }
1032  
1033     return;
1034 @@ -890,7 +1100,13 @@
1035   *********************************************************************/
1036  int accept_connection(struct client_state * csp, jb_socket fd)
1037  {
1038 +#ifdef HAVE_GETNAMEINFO
1039 +   /* XXX: client is stored directly into csp->tcp_addr */
1040 +#define client (csp->tcp_addr)
1041 +   int retval;
1042 +#else
1043     struct sockaddr_in client;
1044 +#endif
1045     jb_socket afd;
1046  #if defined(_WIN32) || defined(__OS2__) || defined(__APPLE_CC__) || defined(AMIGA)
1047     /* Wierdness - fix a warning. */
1048 @@ -919,8 +1135,21 @@
1049  #endif
1050  
1051     csp->cfd = afd;
1052 +#ifdef HAVE_GETNAMEINFO
1053 +   csp->ip_addr_str = malloc(NI_MAXHOST);
1054 +   retval = getnameinfo((struct sockaddr *) &client, c_length,
1055 +         csp->ip_addr_str, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
1056 +   if (!csp->ip_addr_str || retval)
1057 +   {
1058 +      log_error(LOG_LEVEL_ERROR, "Can not save csp->ip_addr_str: %s",
1059 +            (csp->ip_addr_str) ? gai_strerror(retval) : "Insuffcient memory");
1060 +      freez(csp->ip_addr_str);
1061 +   }
1062 +#undef client
1063 +#else
1064     csp->ip_addr_str  = strdup(inet_ntoa(client.sin_addr));
1065     csp->ip_addr_long = ntohl(client.sin_addr.s_addr);
1066 +#endif /* def HAVE_GETNAMEINFO */
1067  
1068     return 1;
1069  
1070 @@ -1051,4 +1280,6 @@
1071    Local Variables:
1072    tab-width: 3
1073    end:
1074 +
1075 +  vim:softtabstop=3 shiftwidth=3
1076  */
1077 diff -urNad privoxy~/jcc.c privoxy/jcc.c
1078 --- privoxy~/jcc.c
1079 +++ privoxy/jcc.c
1080 @@ -2710,7 +2710,7 @@
1081  
1082     if (fwd->forward_host)
1083     {
1084 -      log_error(LOG_LEVEL_CONNECT, "via %s:%d to: %s",
1085 +      log_error(LOG_LEVEL_CONNECT, "via [%s]:%d to: %s",
1086           fwd->forward_host, fwd->forward_port, http->hostport);
1087     }
1088     else
1089 @@ -4483,4 +4483,6 @@
1090    Local Variables:
1091    tab-width: 3
1092    end:
1093 +
1094 +  vim:softtabstop=3 shiftwidth=3
1095  */
1096 diff -urNad privoxy~/loadcfg.c privoxy/loadcfg.c
1097 --- privoxy~/loadcfg.c
1098 +++ privoxy/loadcfg.c
1099 @@ -835,7 +835,6 @@
1100      * Set to defaults
1101      */
1102     config->multi_threaded            = 1;
1103 -   config->hport                     = HADDR_PORT;
1104     config->buffer_limit              = 4096 * 1024;
1105     config->usermanual                = strdup(USER_MANUAL_URL);
1106     config->proxy_args                = strdup("");
1107 @@ -1044,6 +1043,12 @@
1108                    break;
1109                 }
1110              }
1111 +#ifdef HAVE_GETADDRINFO
1112 +            else
1113 +            {
1114 +               cur_acl->wildcard_dst = 1;
1115 +            }
1116 +#endif /* def HAVE_GETADDRINFO */
1117  
1118              /*
1119               * Add it to the list.  Note we reverse the list to get the
1120 @@ -1193,7 +1198,18 @@
1121              {
1122                 cur_fwd->forward_host = strdup(p);
1123  
1124 -               if (NULL != (p = strchr(cur_fwd->forward_host, ':')))
1125 +               if (*cur_fwd->forward_host == '[' && 
1126 +                     NULL != (p = strchr(cur_fwd->forward_host, ']')))
1127 +               {
1128 +                  *p++ = '\0';
1129 +                  memmove(cur_fwd->forward_host, cur_fwd->forward_host + 1,
1130 +                        (size_t) (p - cur_fwd->forward_host));
1131 +                  if (*p == ':')
1132 +                  {
1133 +                     cur_fwd->forward_port = atoi(++p);
1134 +                  }
1135 +               }
1136 +               else if (NULL != (p = strchr(cur_fwd->forward_host, ':')))
1137                 {
1138                    *p++ = '\0';
1139                    cur_fwd->forward_port = atoi(p);
1140 @@ -1257,11 +1273,23 @@
1141              {
1142                 cur_fwd->gateway_host = strdup(p);
1143  
1144 -               if (NULL != (p = strchr(cur_fwd->gateway_host, ':')))
1145 +               if (*cur_fwd->gateway_host == '[' && 
1146 +                     NULL != (p = strchr(cur_fwd->gateway_host, ']')))
1147 +               {
1148 +                  *p++ = '\0';
1149 +                  memmove(cur_fwd->gateway_host, cur_fwd->gateway_host + 1,
1150 +                        (size_t) (p - cur_fwd->gateway_host));
1151 +                  if (*p == ':')
1152 +                  {
1153 +                     cur_fwd->gateway_port = atoi(++p);
1154 +                  }
1155 +               }
1156 +               else if (NULL != (p = strchr(cur_fwd->gateway_host, ':')))
1157                 {
1158                    *p++ = '\0';
1159                    cur_fwd->gateway_port = atoi(p);
1160                 }
1161 +
1162                 if (cur_fwd->gateway_port <= 0)
1163                 {
1164                    cur_fwd->gateway_port = 1080;
1165 @@ -1275,7 +1303,18 @@
1166              {
1167                 cur_fwd->forward_host = strdup(p);
1168  
1169 -               if (NULL != (p = strchr(cur_fwd->forward_host, ':')))
1170 +               if (*cur_fwd->forward_host == '[' && 
1171 +                     NULL != (p = strchr(cur_fwd->forward_host, ']')))
1172 +               {
1173 +                  *p++ = '\0';
1174 +                  memmove(cur_fwd->forward_host, cur_fwd->forward_host + 1,
1175 +                        (size_t) (p - cur_fwd->forward_host));
1176 +                  if (*p == ':')
1177 +                  {
1178 +                     cur_fwd->forward_port = atoi(++p);
1179 +                  }
1180 +               }
1181 +               else if (NULL != (p = strchr(cur_fwd->forward_host, ':')))
1182                 {
1183                    *p++ = '\0';
1184                    cur_fwd->forward_port = atoi(p);
1185 @@ -1345,11 +1384,23 @@
1186  
1187              cur_fwd->gateway_host = strdup(p);
1188  
1189 -            if (NULL != (p = strchr(cur_fwd->gateway_host, ':')))
1190 +            if (*cur_fwd->gateway_host == '[' && 
1191 +                  NULL != (p = strchr(cur_fwd->gateway_host, ']')))
1192 +            {
1193 +               *p++ = '\0';
1194 +               memmove(cur_fwd->gateway_host, cur_fwd->gateway_host + 1,
1195 +                     (size_t) (p - cur_fwd->gateway_host));
1196 +               if (*p == ':')
1197 +               {
1198 +                  cur_fwd->gateway_port = atoi(++p);
1199 +               }
1200 +            }
1201 +            else if (NULL != (p = strchr(cur_fwd->gateway_host, ':')))
1202              {
1203                 *p++ = '\0';
1204                 cur_fwd->gateway_port = atoi(p);
1205              }
1206 +
1207              if (cur_fwd->gateway_port <= 0)
1208              {
1209                 cur_fwd->gateway_port = 1080;
1210 @@ -1362,7 +1413,18 @@
1211              {
1212                 cur_fwd->forward_host = strdup(p);
1213  
1214 -               if (NULL != (p = strchr(cur_fwd->forward_host, ':')))
1215 +               if (*cur_fwd->forward_host == '[' && 
1216 +                     NULL != (p = strchr(cur_fwd->forward_host, ']')))
1217 +               {
1218 +                  *p++ = '\0';
1219 +                  memmove(cur_fwd->forward_host, cur_fwd->forward_host + 1,
1220 +                        (size_t) (p - cur_fwd->forward_host));
1221 +                  if (*p == ':')
1222 +                  {
1223 +                     cur_fwd->forward_port = atoi(++p);
1224 +                  }
1225 +               }
1226 +               else if (NULL != (p = strchr(cur_fwd->forward_host, ':')))
1227                 {
1228                    *p++ = '\0';
1229                    cur_fwd->forward_port = atoi(p);
1230 @@ -1512,6 +1574,12 @@
1231                    break;
1232                 }
1233              }
1234 +#ifdef HAVE_GETADDRINFO
1235 +            else
1236 +            {
1237 +               cur_acl->wildcard_dst = 1;
1238 +            }
1239 +#endif /* def HAVE_GETADDRINFO */
1240  
1241              /*
1242               * Add it to the list.  Note we reverse the list to get the
1243 @@ -1851,18 +1919,20 @@
1244  
1245     if ( NULL != config->haddr )
1246     {
1247 -      if (NULL != (p = strchr(config->haddr, ':')))
1248 +      if (*config->haddr == '[' && NULL != (p = strchr(config->haddr, ']')) &&
1249 +            p[1] == ':' && 0 < (config->hport = atoi(p + 2)))
1250        {
1251 -         *p++ = '\0';
1252 -         if (*p)
1253 -         {
1254 -            config->hport = atoi(p);
1255 -         }
1256 +         *p='\0';
1257 +         memmove((void *) config->haddr, config->haddr + 1,
1258 +               (size_t) (p - config->haddr));
1259        }
1260 -
1261 -      if (config->hport <= 0)
1262 +      else if (NULL != (p = strchr(config->haddr, ':')) &&
1263 +            0 < (config->hport = atoi(p + 1)))
1264 +      {
1265 +         *p = '\0';
1266 +      }
1267 +      else 
1268        {
1269 -         *--p = ':';
1270           log_error(LOG_LEVEL_FATAL, "invalid bind port spec %s", config->haddr);
1271           /* Never get here - LOG_LEVEL_FATAL causes program exit */
1272        }
1273 @@ -2038,4 +2108,6 @@
1274    Local Variables:
1275    tab-width: 3
1276    end:
1277 +
1278 +  vim:softtabstop=3 shiftwidth=3
1279  */
1280 diff -urNad privoxy~/project.h privoxy/project.h
1281 --- privoxy~/project.h
1282 +++ privoxy/project.h
1283 @@ -710,6 +710,12 @@
1284  /* Needed for pcre choice */
1285  #include "config.h"
1286  
1287 +#ifdef HAVE_GETADDRINFO
1288 +/* Need for struct sockaddr_storage */
1289 +#include <sys/socket.h>
1290 +#endif
1291 +
1292 +
1293  /*
1294   * Include appropriate regular expression libraries.
1295   * Note that pcrs and pcre (native) are needed for cgi
1296 @@ -861,16 +867,10 @@
1297  #define FOREVER 1
1298  
1299  /**
1300 - * Default IP address to listen on, as a string.
1301 - * Set to "127.0.0.1".
1302 - */
1303 -#define HADDR_DEFAULT   "127.0.0.1"
1304 -
1305 -/**
1306 - * Default port to listen on, as a number.
1307 - * Set to 8118.
1308 + * Default TCP/IP address to listen on, as a string.
1309 + * Set to "127.0.0.1:8118".
1310   */
1311 -#define HADDR_PORT      8118
1312 +#define HADDR_DEFAULT   "127.0.0.1:8118"
1313  
1314  
1315  /* Forward def for struct client_state */
1316 @@ -1424,9 +1424,15 @@
1317     /** Client PC's IP address, as reported by the accept() function.
1318         As a string. */
1319     char *ip_addr_str;
1320 +#ifdef HAVE_GETADDRINFO
1321 +   /** Client PC's TCP address, as reported by the accept() function.
1322 +       As a sockaddr. */
1323 +   struct sockaddr_storage tcp_addr;
1324 +#else
1325     /** Client PC's IP address, as reported by the accept() function.
1326         As a number. */
1327     unsigned long ip_addr_long;
1328 +#endif /* def HAVE_GETADDRINFO */
1329  
1330     /** The URL that was requested */
1331     struct http_request http[1];
1332 @@ -1660,9 +1666,14 @@
1333   */
1334  struct access_control_addr
1335  {
1336 +#ifdef HAVE_GETADDRINFO
1337 +   struct sockaddr_storage addr; /* <The TCP address in network order. */
1338 +   struct sockaddr_storage mask; /* <The TCP mask in network order. */
1339 +#else
1340     unsigned long addr;  /**< The IP address as an integer. */
1341     unsigned long mask;  /**< The network mask as an integer. */
1342     unsigned long port;  /**< The port number. */
1343 +#endif /* HAVE_GETADDRINFO */
1344  };
1345  
1346  /**
1347 @@ -1674,6 +1685,9 @@
1348  {
1349     struct access_control_addr src[1];  /**< Client IP address */
1350     struct access_control_addr dst[1];  /**< Website or parent proxy IP address */
1351 +#ifdef HAVE_GETADDRINFO
1352 +   int wildcard_dst;                   /** < dst address is wildcard */
1353 +#endif
1354  
1355     short action;                       /**< ACL_PERMIT or ACL_DENY */
1356     struct access_control_list *next;   /**< The next entry in the ACL. */
1357 @@ -1882,4 +1896,6 @@
1358    Local Variables:
1359    tab-width: 3
1360    end:
1361 +
1362 +  vim:softtabstop=3 shiftwidth=3
1363  */
1364 diff -urNad privoxy~/urlmatch.c privoxy/urlmatch.c
1365 --- privoxy~/urlmatch.c
1366 +++ privoxy/urlmatch.c
1367 @@ -540,8 +540,40 @@
1368           host = buf;
1369        }
1370  
1371 +      /* Move after hostname before port number */
1372 +      if (*host == '[')
1373 +      {
1374 +         /* Numeric IPv6 address delimited by brackets */
1375 +         host++;
1376 +         port = strchr(host, ']');
1377 +
1378 +         if (port == NULL)
1379 +         {
1380 +            /* Missing closing bracket */
1381 +            freez(buf);
1382 +            return JB_ERR_PARSE;
1383 +         }
1384 +
1385 +         *port++='\0';
1386 +         
1387 +         if (*port == '\0')
1388 +         {
1389 +            port = NULL;
1390 +         }
1391 +         else if (*port != ':')
1392 +         {
1393 +            /* Garbage after closing bracket */
1394 +            freez(buf);
1395 +            return JB_ERR_PARSE;
1396 +         }
1397 +      }
1398 +      else
1399 +      {
1400 +         /* Plain non-escaped hostname */ 
1401 +         port = strchr(host, ':');
1402 +      }
1403 +
1404        /* check if url contains port */
1405 -      port = strchr(host, ':');
1406        if (port != NULL)
1407        {
1408           /* Contains port */
1409 @@ -844,7 +876,31 @@
1410        *p = '\0';
1411     }
1412  
1413 -   p = strchr(buf, ':');
1414 +   /* XXX: IPv6 numeric hostname contains colons, thus we need to delimit the
1415 +    * hostname before real port separator. Because brackets are used in
1416 +    * hostname matching on lower layer, we can't use it. I decided to use
1417 +    * angle brackets '<' '>' instead. */
1418 +   if (buf[0] == '<' && NULL != (p = strchr(buf + 1, '>')))
1419 +   {
1420 +      *p++ = '\0';
1421 +      buf++;
1422 +
1423 +      if (*p == '\0')
1424 +      {
1425 +         /* Only IPv6 address without port number */
1426 +         p = NULL;
1427 +      }
1428 +      else if (*p != ':')
1429 +      {
1430 +         /* Garbage after address delimiter */
1431 +         return JB_ERR_PARSE;
1432 +      }
1433 +   }
1434 +   else
1435 +   {
1436 +      p = strchr(buf, ':');
1437 +   }
1438 +
1439     if (NULL != p)
1440     {
1441        *p++ = '\0';
1442 @@ -1449,4 +1505,6 @@
1443    Local Variables:
1444    tab-width: 3
1445    end:
1446 +
1447 +  vim:softtabstop=3 shiftwidth=3
1448  */