1 #! /bin/sh /usr/share/dpatch/dpatch-run
2 ## 03_ipv6.dpatch by Petr Písař <petrp@users.sf.net>
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>
10 diff -urNad privoxy~/configure.in privoxy/configure.in
11 --- privoxy~/configure.in
12 +++ privoxy/configure.in
15 dnl uncommenting does not work for swa. suse linux
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])
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
26 <term>Effect if unset:</term>
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
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.
39 will need to override the default.
42 + IPv6 address containing colons has to be quoted by brackets.
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
53 + Suppose you are running <application>Privoxy</application> on IPv6 capable
54 + machine and you want to listen on IPv6 loopback device:
58 + listen-address [::1]:8118
64 @@ -1611,23 +1623,41 @@
65 <term>Type of value:</term>
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>]]
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.
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
98 <term>Default value:</term>
100 <para><emphasis>Unset</emphasis></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).
110 @@ -1677,6 +1707,13 @@
111 IP addresses, only the first one is used.
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.
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
124 @@ -1717,6 +1754,24 @@
125 deny-access 192.168.45.73 www.dirty-stuff.example.com
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):
134 + permit-access 192.0.2.0/24
138 + This is equivalent to the following line even if listening on IPv4
139 + address (where supported by operating system):
143 + permit-access [::ffff:192.0.2.0]/120
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>.
158 @@ -1865,6 +1920,16 @@
159 forwarded to another HTTP proxy but are made directly to the web servers.
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).
172 Multiple lines are OK, they are checked in sequence, and the last match wins.
175 @@ -1891,6 +1956,24 @@
176 forward .isp.example.net .
180 + Parent proxy specified by IPv6 address:
184 + foward / [2001:DB8::1]:8000
188 + Suppose your parent proxy doesn't support IPv6:
192 + forward / parent-proxy.example.org:8000
193 + forward ipv6-server.example.org .
194 + forward <[2-3][0-9a-f][0-9a-f][0-9a-f]:*> .
200 @@ -1963,6 +2046,18 @@
201 With <literal>forward-socks5</literal> the DNS resolution will happen on the remote server as well.
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.
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
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 @@
225 Generally, an URL pattern has the form
226 - <literal><domain>/<path></literal>, where both the
227 - <literal><domain></literal> and <literal><path></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><domain><port>/<path></literal>, where both the
233 + <literal><domain></literal> and <literal><port></literal>
234 + and <literal><path></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!
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).
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><</literal>, <literal>></literal>).
254 @@ -2211,6 +2217,23 @@
258 + <term><literal>:8000/</literal></term>
261 + Matches any URL pointing to TCP port 8000.
266 + <term><literal><2001:db8::1>/</literal></term>
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.)
275 <term><literal>index.html</literal></term>
278 diff -urNad privoxy~/filters.c privoxy/filters.c
279 --- privoxy~/filters.c
280 +++ privoxy/filters.c
285 +#ifdef HAVE_GETADDRINFO
287 +#include <sys/socket.h>
288 +#endif /* def HAVE_GETADDRINFO */
293 @@ -712,6 +717,152 @@
294 static jb_err prepare_for_filtering(struct client_state *csp);
297 +#ifdef HAVE_GETADDRINFO
298 +/*********************************************************************
300 + * Function : sockaddr_storage_to_ip
302 + * Description : Access internal structure of sockaddr_storage
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;
311 + * Returns : 0 = no errror; otherwise
313 + *********************************************************************/
314 +int sockaddr_storage_to_ip(const struct sockaddr_storage *addr, uint8_t **ip,
315 + unsigned int *len, in_port_t **port)
322 + switch (addr->ss_family)
332 + &(( (struct sockaddr_in *) addr)->sin_addr.s_addr);
336 + *port = &((struct sockaddr_in *) addr)->sin_port;
348 + &(( (struct sockaddr_in6 *) addr)->sin6_addr.s6_addr);
352 + *port = &((struct sockaddr_in6 *) addr)->sin6_port;
357 + /* Unsupported address family */
365 +/*********************************************************************
367 + * Function : match_sockaddr
369 + * Description : Check whether address matches network (IP address and port)
372 + * 1 : network = socket address of subnework
373 + * 3 : netmask = network mask as socket address
374 + * 2 : address = checked socket address against given network
376 + * Returns : 0 = doesn't match; 1 = does match
378 + *********************************************************************/
379 +int match_sockaddr(const struct sockaddr_storage *network,
380 + const struct sockaddr_storage *netmask,
381 + const struct sockaddr_storage *address)
383 + uint8_t *network_addr, *netmask_addr, *address_addr;
384 + unsigned int addr_len;
385 + in_port_t *network_port, *netmask_port, *address_port;
388 + if (network->ss_family != netmask->ss_family)
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__);
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);
401 + /* Check for family */
402 + if (network->ss_family == AF_INET && address->ss_family == AF_INET6 &&
403 + IN6_IS_ADDR_V4MAPPED(address_addr))
405 + /* Map AF_INET6 V4MAPPED address into AF_INET */
406 + address_addr += 12;
409 + else if (network->ss_family == AF_INET6 && address->ss_family == AF_INET &&
410 + IN6_IS_ADDR_V4MAPPED(network_addr))
412 + /* Map AF_INET6 V4MAPPED network into AF_INET */
413 + network_addr += 12;
414 + netmask_addr += 12;
417 + else if (network->ss_family != address->ss_family)
422 + /* XXX: Port check is signaled in netmask */
423 + if (*netmask_port && *network_port != *address_port)
428 + /* TODO: Optimize by checking by words insted of octets */
429 + for (i=0; i < addr_len && netmask_addr[i]; i++)
431 + if ( (network_addr[i] & netmask_addr[i]) !=
432 + (address_addr[i] & netmask_addr[i]) )
440 +#endif /* def HAVE_GETADDRINFO */
443 /*********************************************************************
445 * Function : block_acl
447 /* search the list */
450 - if ((csp->ip_addr_long & acl->src->mask) == acl->src->addr)
452 +#ifdef HAVE_GETADDRINFO
453 + match_sockaddr(&acl->src->addr, &acl->src->mask, &csp->tcp_addr)
455 + (csp->ip_addr_long & acl->src->mask) == acl->src->addr
465 - else if ( ((dst->addr & acl->dst->mask) == acl->dst->addr)
466 - && ((dst->port == acl->dst->port) || (acl->dst->port == 0)))
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
475 + * So, we signal the acl->dst is wildcard in wildcard_dst.
477 + acl->wildcard_dst ||
478 + match_sockaddr(&acl->dst->addr, &acl->dst->mask, &dst->addr)
480 + ((dst->addr & acl->dst->mask) == acl->dst->addr)
481 + && ((dst->port == acl->dst->port) || (acl->dst->port == 0))
485 if (acl->action == ACL_PERMIT)
487 @@ -788,12 +960,24 @@
488 int acl_addr(const char *aspec, struct access_control_addr *aca)
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;
498 +#endif /* def HAVE_GETADDRINFO */
500 char *acl_spec = NULL;
502 +#ifdef HAVE_GETADDRINFO
503 + /* FIXME: Depend on ai_family */
511 * Use a temporary acl spec copy so we can log
512 @@ -817,13 +1001,53 @@
513 masklength = atoi(p);
516 - if ((masklength < 0) || (masklength > 32))
517 + if ((masklength < 0) ||
518 +#ifdef HAVE_GETADDRINFO
529 - if ((p = strchr(acl_spec, ':')) != NULL)
530 + if (*acl_spec == '[' && NULL != (p = strchr(acl_spec, ']')))
533 + memmove(acl_spec, acl_spec + 1, (size_t) (p - acl_spec));
542 + p = strchr(acl_spec, ':');
545 +#ifdef HAVE_GETADDRINFO
546 + memset(&hints, 0, sizeof(struct addrinfo));
547 + hints.ai_family = AF_UNSPEC;
548 + hints.ai_socktype = SOCK_STREAM;
550 + i = getaddrinfo(acl_spec, (p) ? ++p : NULL, &hints, &result);
555 + log_error(LOG_LEVEL_ERROR, "Can not resolve [%s]:%s: %s", acl_spec, p,
560 + /* TODO: Allow multihomed hostnames */
561 + memcpy(&(aca->addr), result->ai_addr, sizeof(aca->addr));
562 + freeaddrinfo(result);
568 @@ -847,8 +1071,49 @@
569 /* XXX: This will be logged as parse error. */
572 +#endif /* def HAVE_GETADDRINFO */
574 /* build the netmask */
575 +#ifdef HAVE_GETADDRINFO
576 + /* Clip masklength according current family */
577 + if (aca->addr.ss_family == AF_INET && masklength > 32)
582 + aca->mask.ss_family = aca->addr.ss_family;
583 + if (sockaddr_storage_to_ip(&aca->mask, &mask_data, &addr_len, &mask_port))
590 + /* Port number in ACL has been specified, check ports in future */
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
598 + for (i=0; i < addr_len && masklength; i++)
600 + if (masklength >= 8)
602 + mask_data[i] = 0xFF;
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);
616 for (i=1; i <= masklength ; i++)
619 * (i.e. save on the network portion of the address).
621 aca->addr = aca->addr & aca->mask;
622 +#endif /* def HAVE_GETADDRINFO */
626 @@ -2706,4 +2972,6 @@
631 + vim:softtabstop=3 shiftwidth=3
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)
640 +#ifdef HAVE_GETADDRINFO
641 + struct addrinfo hints, *result, *rp;
645 struct sockaddr_in inaddr;
648 +#endif /* def HAVE_GETADDRINFO */
651 struct timeval tv[1];
652 #if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA)
654 #endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) */
655 + int connect_failed;
658 struct access_control_addr dst[1];
659 #endif /* def FEATURE_ACL */
661 +#ifdef HAVE_GETADDRINFO
662 + retval = snprintf(service, sizeof(service), "%d", portnum);
663 + if (-1 == retval || sizeof(service) <= retval)
665 + log_error(LOG_LEVEL_ERROR,
666 + "Port number (%d) ASCII decimal representation doesn't fit into 6 bytes",
668 + csp->http->host_ip_addr_str = strdup("unknown");
669 + return(JB_INVALID_SOCKET);
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)))
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);
684 + for (rp = result; rp != NULL; rp = rp->ai_next)
687 memset((char *)&inaddr, 0, sizeof inaddr);
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);
694 +#endif /* def HAVE_GETADDRINFO */
697 +#ifdef HAVE_GETADDRINFO
698 + memcpy(&dst->addr, rp->ai_addr, sizeof(dst->addr));
700 dst->addr = ntohl(addr);
702 +#endif /* def HAVE_GETADDRINFO */
704 if (block_acl(dst, csp))
706 @@ -389,14 +427,43 @@
710 +#ifdef HAVE_GETADDRINFO
713 return(JB_INVALID_SOCKET);
714 +#endif /* def HAVE_GETADDRINFO */
716 #endif /* def FEATURE_ACL */
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)
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);
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 */
736 +#ifdef HAVE_GETADDRINFO
738 + if ((fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) ==
741 + if ((fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) < 0)
748 if (sizeof(inaddr.sin_port) == sizeof(short))
749 #endif /* ndef _WIN32 */
752 return(JB_INVALID_SOCKET);
754 +#endif /* HAVE_GETADDRINFO */
757 { /* turn off TCP coalescence */
760 #endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) */
762 + connect_failed = 0;
763 +#ifdef HAVE_GETADDRINFO
764 + while (connect(fd, rp->ai_addr, rp->ai_addrlen) == JB_INVALID_SOCKET)
766 while (connect(fd, (struct sockaddr *) & inaddr, sizeof inaddr) == JB_INVALID_SOCKET)
767 +#endif /* HAVE_GETADDRINFO */
770 if (errno == WSAEINPROGRESS)
775 - return(JB_INVALID_SOCKET);
776 + connect_failed = 1;
780 + if (connect_failed)
782 +#ifdef HAVE_GETADDRINFO
785 + return(JB_INVALID_SOCKET);
789 #if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__)
792 if (select((int)fd + 1, NULL, &wfds, NULL, tv) <= 0)
795 +#ifdef HAVE_GETADDRINFO
798 return(JB_INVALID_SOCKET);
802 +#ifdef HAVE_GETADDRINFO
806 + freeaddrinfo(result);
809 + log_error(LOG_LEVEL_INFO, "Could not connect to TCP/[%s]:%s", host, service);
810 + return(JB_INVALID_SOCKET);
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
817 + * Thus we can not log here the socket is connected. */
818 + /*log_error(LOG_LEVEL_INFO, "Connected to TCP/[%s]:%s", host, service);*/
825 *********************************************************************/
826 int bind_port(const char *hostnam, int portnum, jb_socket *pfd)
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 */
836 struct sockaddr_in inaddr;
837 +#endif /* def HAVE_GETADDRINFO */
843 *pfd = JB_INVALID_SOCKET;
845 +#ifdef HAVE_GETADDRINFO
846 + retval = snprintf(servnam, sizeof(servnam), "%d", portnum);
847 + if (-1 == retval || sizeof(servnam) <= retval)
849 + log_error(LOG_LEVEL_ERROR,
850 + "Port number (%d) ASCII decimal representation doesn't fit into 6 bytes",
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;
864 + if ((retval = getaddrinfo(hostnam, servnam, &hints, &result)))
866 + log_error(LOG_LEVEL_ERROR,
867 + "Can not resolve %s: %s", hostnam, gai_strerror(retval));
871 memset((char *)&inaddr, '\0', sizeof inaddr);
873 inaddr.sin_family = AF_INET;
875 inaddr.sin_port = htonl((unsigned long) portnum);
877 #endif /* ndef _WIN32 */
878 +#endif /* def HAVE_GETADDRINFO */
880 +#ifdef HAVE_GETADDRINFO
881 + for (rp = result; rp != NULL; rp = rp->ai_next)
883 + fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
885 fd = socket(AF_INET, SOCK_STREAM, 0);
886 +#endif /* def HAVE_GETADDRINFO */
889 if (fd == JB_INVALID_SOCKET)
894 +#ifdef HAVE_GETADDRINFO
903 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one));
904 #endif /* ndef _WIN32 */
906 +#ifdef HAVE_GETADDRINFO
907 + if (bind(fd, rp->ai_addr, rp->ai_addrlen) < 0)
909 if (bind(fd, (struct sockaddr *)&inaddr, sizeof(inaddr)) < 0)
913 errno = WSAGetLastError();
914 @@ -744,15 +900,36 @@
915 if (errno == EADDRINUSE)
918 +#ifdef HAVE_GETADDRINFO
919 + freeaddrinfo(result);
927 +#ifndef HAVE_GETADDRINFO
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 */
941 + freeaddrinfo(result);
944 + /* All bind()s failed */
947 +#endif /* ndef HAVE_GETADDRINFO */
949 while (listen(fd, MAX_LISTEN_BACKLOG) == -1)
951 @@ -792,14 +969,20 @@
952 *********************************************************************/
953 void get_host_information(jb_socket afd, char **ip_address, char **hostname)
955 +#ifdef HAVE_GETNAMEINFO
956 + struct sockaddr_storage server;
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. */
965 + int s_length, s_length_provided;
967 - socklen_t s_length;
968 + socklen_t s_length, s_length_provided;
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)
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);
982 if (NULL != hostname)
984 @@ -819,8 +1003,23 @@
986 if (!getsockname(afd, (struct sockaddr *) &server, &s_length))
988 + if (s_length > s_length_provided)
990 + log_error(LOG_LEVEL_ERROR, "getsockname() truncated server address");
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);
1003 *ip_address = strdup(inet_ntoa(server.sin_addr));
1005 +#endif /* HAVE_GETNAMEINFO */
1006 if (NULL == hostname)
1009 @@ -829,6 +1028,16 @@
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));
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 @@
1028 *hostname = strdup(host->h_name);
1030 +#endif /* else def HAVE_GETNAMEINFO */
1034 @@ -890,7 +1100,13 @@
1035 *********************************************************************/
1036 int accept_connection(struct client_state * csp, jb_socket fd)
1038 +#ifdef HAVE_GETNAMEINFO
1039 + /* XXX: client is stored directly into csp->tcp_addr */
1040 +#define client (csp->tcp_addr)
1043 struct sockaddr_in client;
1046 #if defined(_WIN32) || defined(__OS2__) || defined(__APPLE_CC__) || defined(AMIGA)
1047 /* Wierdness - fix a warning. */
1048 @@ -919,8 +1135,21 @@
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)
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);
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 */
1070 @@ -1051,4 +1280,6 @@
1075 + vim:softtabstop=3 shiftwidth=3
1077 diff -urNad privoxy~/jcc.c privoxy/jcc.c
1080 @@ -2710,7 +2710,7 @@
1082 if (fwd->forward_host)
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);
1089 @@ -4483,4 +4483,6 @@
1094 + vim:softtabstop=3 shiftwidth=3
1096 diff -urNad privoxy~/loadcfg.c privoxy/loadcfg.c
1097 --- privoxy~/loadcfg.c
1098 +++ privoxy/loadcfg.c
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 @@
1111 +#ifdef HAVE_GETADDRINFO
1114 + cur_acl->wildcard_dst = 1;
1116 +#endif /* def HAVE_GETADDRINFO */
1119 * Add it to the list. Note we reverse the list to get the
1120 @@ -1193,7 +1198,18 @@
1122 cur_fwd->forward_host = strdup(p);
1124 - if (NULL != (p = strchr(cur_fwd->forward_host, ':')))
1125 + if (*cur_fwd->forward_host == '[' &&
1126 + NULL != (p = strchr(cur_fwd->forward_host, ']')))
1129 + memmove(cur_fwd->forward_host, cur_fwd->forward_host + 1,
1130 + (size_t) (p - cur_fwd->forward_host));
1133 + cur_fwd->forward_port = atoi(++p);
1136 + else if (NULL != (p = strchr(cur_fwd->forward_host, ':')))
1139 cur_fwd->forward_port = atoi(p);
1140 @@ -1257,11 +1273,23 @@
1142 cur_fwd->gateway_host = strdup(p);
1144 - if (NULL != (p = strchr(cur_fwd->gateway_host, ':')))
1145 + if (*cur_fwd->gateway_host == '[' &&
1146 + NULL != (p = strchr(cur_fwd->gateway_host, ']')))
1149 + memmove(cur_fwd->gateway_host, cur_fwd->gateway_host + 1,
1150 + (size_t) (p - cur_fwd->gateway_host));
1153 + cur_fwd->gateway_port = atoi(++p);
1156 + else if (NULL != (p = strchr(cur_fwd->gateway_host, ':')))
1159 cur_fwd->gateway_port = atoi(p);
1162 if (cur_fwd->gateway_port <= 0)
1164 cur_fwd->gateway_port = 1080;
1165 @@ -1275,7 +1303,18 @@
1167 cur_fwd->forward_host = strdup(p);
1169 - if (NULL != (p = strchr(cur_fwd->forward_host, ':')))
1170 + if (*cur_fwd->forward_host == '[' &&
1171 + NULL != (p = strchr(cur_fwd->forward_host, ']')))
1174 + memmove(cur_fwd->forward_host, cur_fwd->forward_host + 1,
1175 + (size_t) (p - cur_fwd->forward_host));
1178 + cur_fwd->forward_port = atoi(++p);
1181 + else if (NULL != (p = strchr(cur_fwd->forward_host, ':')))
1184 cur_fwd->forward_port = atoi(p);
1185 @@ -1345,11 +1384,23 @@
1187 cur_fwd->gateway_host = strdup(p);
1189 - if (NULL != (p = strchr(cur_fwd->gateway_host, ':')))
1190 + if (*cur_fwd->gateway_host == '[' &&
1191 + NULL != (p = strchr(cur_fwd->gateway_host, ']')))
1194 + memmove(cur_fwd->gateway_host, cur_fwd->gateway_host + 1,
1195 + (size_t) (p - cur_fwd->gateway_host));
1198 + cur_fwd->gateway_port = atoi(++p);
1201 + else if (NULL != (p = strchr(cur_fwd->gateway_host, ':')))
1204 cur_fwd->gateway_port = atoi(p);
1207 if (cur_fwd->gateway_port <= 0)
1209 cur_fwd->gateway_port = 1080;
1210 @@ -1362,7 +1413,18 @@
1212 cur_fwd->forward_host = strdup(p);
1214 - if (NULL != (p = strchr(cur_fwd->forward_host, ':')))
1215 + if (*cur_fwd->forward_host == '[' &&
1216 + NULL != (p = strchr(cur_fwd->forward_host, ']')))
1219 + memmove(cur_fwd->forward_host, cur_fwd->forward_host + 1,
1220 + (size_t) (p - cur_fwd->forward_host));
1223 + cur_fwd->forward_port = atoi(++p);
1226 + else if (NULL != (p = strchr(cur_fwd->forward_host, ':')))
1229 cur_fwd->forward_port = atoi(p);
1230 @@ -1512,6 +1574,12 @@
1234 +#ifdef HAVE_GETADDRINFO
1237 + cur_acl->wildcard_dst = 1;
1239 +#endif /* def HAVE_GETADDRINFO */
1242 * Add it to the list. Note we reverse the list to get the
1243 @@ -1851,18 +1919,20 @@
1245 if ( NULL != config->haddr )
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)))
1254 - config->hport = atoi(p);
1257 + memmove((void *) config->haddr, config->haddr + 1,
1258 + (size_t) (p - config->haddr));
1261 - if (config->hport <= 0)
1262 + else if (NULL != (p = strchr(config->haddr, ':')) &&
1263 + 0 < (config->hport = atoi(p + 1)))
1270 log_error(LOG_LEVEL_FATAL, "invalid bind port spec %s", config->haddr);
1271 /* Never get here - LOG_LEVEL_FATAL causes program exit */
1273 @@ -2038,4 +2108,6 @@
1278 + vim:softtabstop=3 shiftwidth=3
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 */
1287 +#ifdef HAVE_GETADDRINFO
1288 +/* Need for struct sockaddr_storage */
1289 +#include <sys/socket.h>
1294 * Include appropriate regular expression libraries.
1295 * Note that pcrs and pcre (native) are needed for cgi
1296 @@ -861,16 +867,10 @@
1300 - * Default IP address to listen on, as a string.
1301 - * Set to "127.0.0.1".
1303 -#define HADDR_DEFAULT "127.0.0.1"
1306 - * Default port to listen on, as a number.
1308 + * Default TCP/IP address to listen on, as a string.
1309 + * Set to "127.0.0.1:8118".
1311 -#define HADDR_PORT 8118
1312 +#define HADDR_DEFAULT "127.0.0.1:8118"
1315 /* Forward def for struct client_state */
1316 @@ -1424,9 +1424,15 @@
1317 /** Client PC's IP address, as reported by the accept() function.
1320 +#ifdef HAVE_GETADDRINFO
1321 + /** Client PC's TCP address, as reported by the accept() function.
1323 + struct sockaddr_storage tcp_addr;
1325 /** Client PC's IP address, as reported by the accept() function.
1327 unsigned long ip_addr_long;
1328 +#endif /* def HAVE_GETADDRINFO */
1330 /** The URL that was requested */
1331 struct http_request http[1];
1332 @@ -1660,9 +1666,14 @@
1334 struct access_control_addr
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. */
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 */
1347 @@ -1674,6 +1685,9 @@
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 */
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 @@
1362 + vim:softtabstop=3 shiftwidth=3
1364 diff -urNad privoxy~/urlmatch.c privoxy/urlmatch.c
1365 --- privoxy~/urlmatch.c
1366 +++ privoxy/urlmatch.c
1367 @@ -540,8 +540,40 @@
1371 + /* Move after hostname before port number */
1374 + /* Numeric IPv6 address delimited by brackets */
1376 + port = strchr(host, ']');
1380 + /* Missing closing bracket */
1382 + return JB_ERR_PARSE;
1387 + if (*port == '\0')
1391 + else if (*port != ':')
1393 + /* Garbage after closing bracket */
1395 + return JB_ERR_PARSE;
1400 + /* Plain non-escaped hostname */
1401 + port = strchr(host, ':');
1404 /* check if url contains port */
1405 - port = strchr(host, ':');
1409 @@ -844,7 +876,31 @@
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, '>')))
1425 + /* Only IPv6 address without port number */
1428 + else if (*p != ':')
1430 + /* Garbage after address delimiter */
1431 + return JB_ERR_PARSE;
1436 + p = strchr(buf, ':');
1442 @@ -1449,4 +1505,6 @@
1447 + vim:softtabstop=3 shiftwidth=3