#! /bin/sh /usr/share/dpatch/dpatch-run
-## 03_ipv6.dpatch by Lionel Elie Mamane <lionel@mamane.lu>
+## 03_ipv6.dpatch by Petr Písař <petrp@users.sf.net>
##
## All lines beginning with `## DP:' are a description of the patch.
-## DP: privoxy_CVS_20030523_ipv6_5.patch.bz2 from
-## DP: ftp://ftp.deepspace6.net/pub/ds6/sources/privoxy/privoxy_CVS_20030523_ipv6_5.patch.bz2
-## DP: adapted to the 3.0 branch of privoxy by Roland Rosenfeld
-## DP: adapted to 3.0.4 by higuita, but i'm no programmer, so i hope i
-## DP: didnt broke anything :)
-## DP: adapted to 3.0.6 by Petr Písa?? petrp@users.sf.net found on
-## DP: http://xpisar.wz.cz/privoxy-ipv6/ Use privoxy-3.0.6-stable-ipv6.diff.bz2
-## DP: and stripped
+## DP: IPv6 support for privoxy.
+## DP: http://xpisar.wz.cz/privoxy-ipv6/privoxy-3.0.10-ipv6-all-6.diff
+## DP: Former versions by Lionel Elie Mamane <lionel@mamane.lu>
@DPATCH@
-diff -urNad privoxy~/GNUmakefile.in privoxy/GNUmakefile.in
---- privoxy~/GNUmakefile.in
-+++ privoxy/GNUmakefile.in
-@@ -187,7 +187,7 @@
- C_SRC = actions.c cgi.c cgiedit.c cgisimple.c deanimate.c encode.c \
- errlog.c filters.c gateway.c jbsockets.c jcc.c killpopup.c \
- list.c loadcfg.c loaders.c miscutil.c parsers.c ssplit.c \
-- urlmatch.c
-+ urlmatch.c addrlist.c jb_socket_set.c
-
- C_OBJS = $(C_SRC:.c=.@OBJEXT@)
- C_HDRS = $(C_SRC:.c=.h) project.h actionlist.h
-@@ -241,7 +241,7 @@
- SPECIAL_CFLAGS = @SPECIAL_CFLAGS@
-
- # Add your flags here
--OTHER_CFLAGS =
-+OTHER_CFLAGS = -DINET6
+diff -urNad privoxy~/configure.in privoxy/configure.in
+--- privoxy~/configure.in
++++ privoxy/configure.in
+@@ -1237,7 +1237,7 @@
+ AC_TYPE_SIGNAL
+ dnl uncommenting does not work for swa. suse linux
+ dnl AC_FUNC_STAT
+-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])
++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])
+
+
+ dnl =================================================================
+diff -urNad privoxy~/doc/source/p-config.sgml privoxy/doc/source/p-config.sgml
+--- privoxy~/doc/source/p-config.sgml
++++ privoxy/doc/source/p-config.sgml
+@@ -1213,9 +1213,9 @@
+ <term>Effect if unset:</term>
+ <listitem>
+ <para>
+- Bind to 127.0.0.1 (localhost), port 8118. This is suitable and recommended for
+- home users who run <application>Privoxy</application> on the same machine as
+- their browser.
++ Bind to 127.0.0.1 (IPv4 localhost), port 8118. This is suitable and
++ recommended for home users who run <application>Privoxy</application> on
++ the same machine as their browser.
+ </para>
+ </listitem>
+ </varlistentry>
+@@ -1231,6 +1231,9 @@
+ will need to override the default.
+ </para>
+ <para>
++ IPv6 address containing colons has to be quoted by brackets.
++ </para>
++ <para>
+ If you leave out the IP address, <application>Privoxy</application> will
+ bind to all interfaces (addresses) on your machine and may become reachable
+ from the Internet. In that case, consider using <link
+@@ -1259,6 +1262,15 @@
+ listen-address 192.168.0.1:8118
+ </programlisting>
+ </para>
++ <para>
++ Suppose you are running <application>Privoxy</application> on IPv6 capable
++ machine and you want to listen on IPv6 loopback device:
++ </para>
++ <para>
++ <programlisting>
++ listen-address [::1]:8118
++</programlisting>
++ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+@@ -1611,23 +1623,41 @@
+ <term>Type of value:</term>
+ <listitem>
+ <para>
+- <replaceable class="parameter">src_addr</replaceable>[/<replaceable class="parameter">src_masklen</replaceable>]
+- [<replaceable class="parameter">dst_addr</replaceable>[/<replaceable class="parameter">dst_masklen</replaceable>]]
++ <replaceable class="parameter">src_addr</replaceable>[:<replaceable class="parameter">port</replaceable>][/<replaceable class="parameter">src_masklen</replaceable>]
++ [<replaceable class="parameter">dst_addr</replaceable>[:<replaceable class="parameter">port</replaceable>][/<replaceable class="parameter">dst_masklen</replaceable>]]
+ </para>
+ <para>
+ Where <replaceable class="parameter">src_addr</replaceable> and
+- <replaceable class="parameter">dst_addr</replaceable> are IP addresses in dotted decimal notation or valid
+- DNS names, and <replaceable class="parameter">src_masklen</replaceable> and
++ <replaceable class="parameter">dst_addr</replaceable> are IPv4 addresses in dotted decimal notation or valid
++ DNS names, <replaceable class="parameter">port</replaceable> is port
++ number, and <replaceable class="parameter">src_masklen</replaceable> and
+ <replaceable class="parameter">dst_masklen</replaceable> are subnet masks in CIDR notation, i.e. integer
+ values from 2 to 30 representing the length (in bits) of the network address. The masks and the whole
+ destination part are optional.
+ </para>
++ <para>
++ If your system implements
++ <ulink url="http://tools.ietf.org/html/rfc2553">RFC 2553</ulink>, then
++ <replaceable class="parameter">src_addr</replaceable> and <replaceable
++ class="parameter">dst_addr</replaceable> can be IPv6 addresses delimeted by
++ brackets, <replaceable class="parameter">port</replaceable> can be number
++ or service name, and
++ <replaceable class="parameter">src_masklen</replaceable> and
++ <replaceable class="parameter">dst_masklen</replaceable> can be number
++ from 0 to 128.
++ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Default value:</term>
+ <listitem>
+ <para><emphasis>Unset</emphasis></para>
++ <para>
++ No <replaceable class="parameter">port</replaceable> means match any port
++ and no <replaceable class="parameter">src_masklen</replaceable> or
++ no <replaceable class="parameter">src_masklen</replaceable> means exactly
++ given IP address (i.e. 32 for IPv4 and 128 for IPv6).
++ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+@@ -1677,6 +1707,13 @@
+ IP addresses, only the first one is used.
+ </para>
+ <para>
++ Some systems allows IPv4 client to connect to IPv6 server socket.
++ Then the client's IPv4 address will be translated by system into
++ IPv6 address space with special prefix ::ffff/96 (so called IPv4
++ mapped IPv6 address). <application>Privoxy</application> can handle it
++ and maps such ACL addresses automatically.
++ </para>
++ <para>
+ Denying access to particular sites by ACL may have undesired side effects
+ if the site in question is hosted on a machine which also hosts other sites
+ (most sites are).
+@@ -1717,6 +1754,24 @@
+ deny-access 192.168.45.73 www.dirty-stuff.example.com
+ </screen>
+ </para>
++ <para>
++ Allow access from IPv4 network 192.0.2.0/24 even if listening on
++ IPv6 wild card address (where supported by operating system):
++ </para>
++ <para>
++ <programlisting>
++ permit-access 192.0.2.0/24
++</programlisting>
++ </para>
++ <para>
++ This is equivalent to the following line even if listening on IPv4
++ address (where supported by operating system):
++ </para>
++ <para>
++ <programlisting>
++ permit-access [::ffff:192.0.2.0]/120
++</programlisting>
++ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+@@ -1838,7 +1893,7 @@
+ denote <quote>all URLs</quote>.
+ <replaceable class="parameter">http_parent</replaceable>[:<replaceable class="parameter">port</replaceable>]
+ is the DNS name or IP address of the parent HTTP proxy through which the requests should be forwarded,
+- optionally followed by its listening port (default: 8080).
++ optionally followed by its listening port (default: 8000).
+ Use a single dot (<literal>.</literal>) to denote <quote>no forwarding</quote>.
+ </para>
+ </listitem>
+@@ -1865,6 +1920,16 @@
+ forwarded to another HTTP proxy but are made directly to the web servers.
+ </para>
+ <para>
++ <replaceable class="parameter">http_parent</replaceable> can be IPv6
++ numerical address (if
++ <ulink url="http://tools.ietf.org/html/rfc2553">RFC 2553</ulink> is
++ implemented). However not to clash with port delimiter, quote
++ whole IP address with brackets. On the other hand <replaceable
++ class="parameter">target_pattern</replaceable> containing IPv6 address
++ must be delimited by angle brackets (normal brackets are reserved for
++ regular expression already).
++ </para>
++ <para>
+ Multiple lines are OK, they are checked in sequence, and the last match wins.
+ </para>
+ </listitem>
+@@ -1891,6 +1956,24 @@
+ forward .isp.example.net .
+ </screen>
+ </para>
++ <para>
++ Parent proxy specified by IPv6 address:
++ </para>
++ <para>
++ <programlisting>
++ foward / [2001:DB8::1]:8000
++</programlisting>
++ </para>
++ <para>
++ Suppose your parent proxy doesn't support IPv6:
++ </para>
++ <para>
++ <programlisting>
++ forward / parent-proxy.example.org:8000
++ forward ipv6-server.example.org .
++ forward <[2-3][0-9a-f][0-9a-f][0-9a-f]:*> .
++</programlisting>
++ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+@@ -1963,6 +2046,18 @@
+ With <literal>forward-socks5</literal> the DNS resolution will happen on the remote server as well.
+ </para>
+ <para>
++ <replaceable class="parameter">socks_proxy</replaceable> and
++ <replaceable class="parameter">http_parent</replaceable> can be IPv6
++ numerical address (if
++ <ulink url="http://tools.ietf.org/html/rfc2553">RFC 2553</ulink> is
++ implemented). However not to clash with port
++ delimiter, quote whole IP address with brackets. On the other
++ hand <replaceable class="parameter">target_pattern</replaceable> containing
++ IPv6 address must be delimited by angle brackets (normal brackets are
++ reserved for regular expression already). The only exception is SOCKS 4
++ version where only IPv4 is suppored.
++ </para>
++ <para>
+ If <replaceable class="parameter">http_parent</replaceable> is <quote>.</quote>, then requests are not
+ forwarded to another HTTP proxy but are made (HTTP-wise) directly to the web servers, albeit through
+ a SOCKS proxy.
+diff -urNad privoxy~/doc/source/user-manual.sgml privoxy/doc/source/user-manual.sgml
+--- privoxy~/doc/source/user-manual.sgml
++++ privoxy/doc/source/user-manual.sgml
+@@ -2147,12 +2147,12 @@
+
+ <para>
+ Generally, an URL pattern has the form
+- <literal><domain>/<path></literal>, where both the
+- <literal><domain></literal> and <literal><path></literal> are
+- optional. (This is why the special <literal>/</literal> pattern matches all
+- URLs). Note that the protocol portion of the URL pattern (e.g.
+- <literal>http://</literal>) should <emphasis>not</emphasis> be included in
+- the pattern. This is assumed already!
++ <literal><domain><port>/<path></literal>, where both the
++ <literal><domain></literal> and <literal><port></literal>
++ and <literal><path></literal> are optional. (This is why the special
++ <literal>/</literal> pattern matches all URLs). Note that the protocol
++ portion of the URL pattern (e.g. <literal>http://</literal>) should
++ <emphasis>not</emphasis> be included in the pattern. This is assumed already!
+ </para>
+ <para>
+ The pattern matching syntax is different for the domain and path parts of
+@@ -2161,6 +2161,12 @@
+ <ulink url="http://en.wikipedia.org/wiki/Regular_expressions"><quote>Regular
+ Expressions</quote></ulink> (POSIX 1003.2).
+ </para>
++<para>
++ The port part of pattern is decimal port number preceeded by a colon
++ (<literal>:</literal>). If domain part contains numeric IPv6 address, you
++ will need to quote the domain part by angle brackets
++ (<literal><</literal>, <literal>></literal>).
++</para>
+
+ <variablelist>
+ <varlistentry>
+@@ -2211,6 +2217,23 @@
+ </listitem>
+ </varlistentry>
+ <varlistentry>
++ <term><literal>:8000/</literal></term>
++ <listitem>
++ <para>
++ Matches any URL pointing to TCP port 8000.
++ </para>
++ </listitem>
++ </varlistentry>
++ <varlistentry>
++ <term><literal><2001:db8::1>/</literal></term>
++ <listitem>
++ <para>
++ Matches any URL having <literal>2001:db8::1</literal> as a domain.
++ (Note that real URL uses plain brackets, not an angle brackets.)
++ </para>
++ </listitem>
++ </varlistentry>
++ <varlistentry>
+ <term><literal>index.html</literal></term>
+ <listitem>
+ <para>
+diff -urNad privoxy~/filters.c privoxy/filters.c
+--- privoxy~/filters.c
++++ privoxy/filters.c
+@@ -665,6 +665,11 @@
+ #include <string.h>
+ #include <assert.h>
- CFLAGS = @CFLAGS@ @CPPFLAGS@ $(OTHER_CFLAGS) $(SPECIAL_CFLAGS) -Wall \
- @STATIC_PCRE_ONLY@ -Ipcre
-diff -urNad privoxy~/addrlist.c privoxy/addrlist.c
---- privoxy~/addrlist.c
-+++ privoxy/addrlist.c
-@@ -0,0 +1,198 @@
-+const char addrlist_rcs[] = "$Id: $";
-+/*********************************************************************
-+ *
-+ * File : $Source: $
-+ *
-+ * Purpose : Declares functions to handle lists of network addresses.
-+ * Functions declared include:
-+ * `destroy_addr_list', head_addr_list and `tail_addr_list'
-+ *
-+ * Copyright : Written by and Copyright (C) 2002 Lionel Elie Mamane
-+ * <lionel@mamane.lu>
-+ *
-+ * This program is free software; you can redistribute it
-+ * and/or modify it under the terms of the GNU General
-+ * Public License as published by the Free Software
-+ * Foundation; either version 2 of the License, or (at
-+ * your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will
-+ * be useful, but WITHOUT ANY WARRANTY; without even the
-+ * implied warranty of MERCHANTABILITY or FITNESS FOR A
-+ * PARTICULAR PURPOSE. See the GNU General Public
-+ * License for more details.
-+ *
-+ * The GNU General Public License should be included with
-+ * this file. If not, you can view it at
-+ * http://www.gnu.org/copyleft/gpl.html
-+ * or write to the Free Software Foundation, Inc., 59
-+ * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-+ *
-+ * Revisions :
-+ * $Log: addrlist.c,v $
-+ *
-+ *********************************************************************/
-+
-+#include "addrlist.h"
-+#include <sys/types.h>
-+#include <sys/socket.h>
++#ifdef HAVE_GETADDRINFO
+#include <netdb.h>
-+#include <string.h>
++#include <sys/socket.h>
++#endif /* def HAVE_GETADDRINFO */
+
+ #ifndef _WIN32
+ #ifndef __OS2__
+ #include <unistd.h>
+@@ -712,6 +717,152 @@
+ static jb_err prepare_for_filtering(struct client_state *csp);
+
+ #ifdef FEATURE_ACL
++#ifdef HAVE_GETADDRINFO
+/*********************************************************************
+ *
-+ * Function : acceptable
++ * Function : sockaddr_storage_to_ip
+ *
-+ * Description : Test wheter an address is acceptable for our use
-+ * Currently, this means either an IPv4 or an IPv6 address
++ * Description : Access internal structure of sockaddr_storage
+ *
+ * Parameters :
-+ * 0 : addr = the address to test
++ * 1 : addr = socket address
++ * 2 : ip = IP address as array of octets in network order
++ * (it points into addr)
++ * 3 : len = length of IP address in octets
++ * 4 : port = port number in network order;
+ *
-+ * Returns : 0 = false / no
-+ * anything else = true / yes
++ * Returns : 0 = no errror; otherwise
+ *
+ *********************************************************************/
-+static int acceptable (struct sockaddr_storage *addr)
++int sockaddr_storage_to_ip(const struct sockaddr_storage *addr, uint8_t **ip,
++ unsigned int *len, in_port_t **port)
+{
-+ switch(addr->ss_family)
++ if (!addr)
+ {
-+ case AF_INET:
-+#ifdef INET6
-+ case AF_INET6:
-+#endif
-+ return !0;
-+ default:
-+ return 0;
++ return(-1);
+ }
-+}
+
-+/*********************************************************************
-+ *
-+ * Function : skim
-+ *
-+ * Description : Get the first acceptable address in head position
-+ * Assumes there is one
-+ *
-+ * Parameters :
-+ * 0 : l = the list to skim
-+ *
-+ * Returns : the skimmed list
-+ *
-+ *********************************************************************/
-+static addr_list *skim (addr_list *l)
-+{
-+ if (acceptable((struct sockaddr_storage*)l->ai_addr))
-+ return l;
-+ return skim(l->ai_next);
-+}
++ switch (addr->ss_family)
++ {
++ case AF_INET:
++ if (len)
++ {
++ *len = 4;
++ }
++ if (ip)
++ {
++ *ip = (uint8_t *)
++ &(( (struct sockaddr_in *) addr)->sin_addr.s_addr);
++ }
++ if (port)
++ {
++ *port = &((struct sockaddr_in *) addr)->sin_port;
++ }
++ break;
+
-+/*********************************************************************
-+ *
-+ * Function : tail_addr_list
-+ *
-+ * Description : Get the tail of an address list
-+ *
-+ * Parameters :
-+ * 0 : l = the list to get the tail of
-+ *
-+ * Returns : the tail of the list
-+ * If the list has no tail (i.e. is nil), unspecified
-+ * behaviour
-+ *
-+ *********************************************************************/
-+addr_list *tail_addr_list(addr_list *l)
-+{
-+ return skim(l)->ai_next;
-+}
++ case AF_INET6:
++ if (len)
++ {
++ *len = 16;
++ }
++ if (ip)
++ {
++ *ip = (uint8_t *)
++ &(( (struct sockaddr_in6 *) addr)->sin6_addr.s6_addr);
++ }
++ if (port)
++ {
++ *port = &((struct sockaddr_in6 *) addr)->sin6_port;
++ }
++ break;
+
-+/*********************************************************************
-+ *
-+ * Function : head_addr_list
-+ *
-+ * Description : Get the head of an address list
-+ *
-+ * Parameters :
-+ * 0 : l = the list to get the head of
-+ *
-+ * Returns : the head of the list
-+ * If the list has no head (i.e. is nil), unspecified
-+ * behaviour
-+ *
-+ *********************************************************************/
-+struct sockaddr_storage *head_addr_list(addr_list *l)
-+{
-+ return (struct sockaddr_storage *)skim(l)->ai_addr;
-+}
++ default:
++ /* Unsupported address family */
++ return(-1);
++ }
+
-+/*********************************************************************
-+ *
-+ * Function : cpy_head_addr_list
-+ *
-+ * Description : Copy the head of an address list to the given destination
-+ *
-+ * Parameters :
-+ * 0 : l = the list to get the head of
-+ * 1 : r = where to put the result
-+ *
-+ * Returns : Nothing
-+ * If the list has no head (i.e. is nil), unspecified
-+ * behaviour
-+ *
-+ *********************************************************************/
-+void cpy_head_addr_list(addr_list *l, struct sockaddr_storage *r, size_t *addrlen)
-+{
-+ addr_list *sl = skim(l);
-+ memcpy(r, sl->ai_addr, sl->ai_addrlen);
-+ *addrlen = sl->ai_addrlen;
++ return(0);
+}
+
-+/*********************************************************************
-+ *
-+ * Function : destroy_addr_list
-+ *
-+ * Description : Unallocate memory allocated to an address list
-+ *
-+ * Parameters :
-+ * 0 : l = the list to unallocate
-+ *
-+ * Returns : nothing
-+ *
-+ *********************************************************************/
-+void destroy_addr_list(addr_list *l)
-+{
-+ freeaddrinfo(l);
-+}
+
+/*********************************************************************
+ *
-+ * Function : is_nil_addr_list
++ * Function : match_sockaddr
+ *
-+ * Description : Test wheter a list is nil (empty)
++ * Description : Check whether address matches network (IP address and port)
+ *
+ * Parameters :
-+ * 0 : l = the list to test
++ * 1 : network = socket address of subnework
++ * 3 : netmask = network mask as socket address
++ * 2 : address = checked socket address against given network
+ *
-+ * Returns : 0 = false if list has a head,
-+ * anything else = true if list is nil
++ * Returns : 0 = doesn't match; 1 = does match
+ *
+ *********************************************************************/
-+int is_nil_addr_list(addr_list *l)
++int match_sockaddr(const struct sockaddr_storage *network,
++ const struct sockaddr_storage *netmask,
++ const struct sockaddr_storage *address)
+{
-+ /* We are searching for a witness of non-nilness (modulo acceptability)
-+ * If none is found, the list is nil
-+ */
-+ if (l==NULL)
-+ /* Empty list*/
-+ return !0;
-+ if (acceptable(head_addr_list(l)))
-+ /* Witness found */
-+ return 0;
-+ return is_nil_addr_list(l->ai_next);
-+}
-+
-+/*
-+ Local Variables:
-+ tab-width: 3
-+ end:
-+*/
-diff -urNad privoxy~/addrlist.h privoxy/addrlist.h
---- privoxy~/addrlist.h
-+++ privoxy/addrlist.h
-@@ -0,0 +1,56 @@
-+#ifndef ADDR_LIST_H_INCLUDED
-+#define ADDR_LIST_H_INCLUDED
-+#define ADDR_LIST_H_VERSION "$Id: $"
-+/*********************************************************************
-+ *
-+ * File : $Source: $
-+ *
-+ * Purpose : Declares functions to handle lists of network addresses.
-+ * Functions declared include:
-+ * `destroy_addr_list', head_addr_list and `tail_addr_list'
-+ *
-+ * Copyright : Written by and Copyright (C) 2002 Lionel Elie Mamane
-+ * <lionel@mamane.lu>
-+ *
-+ * This program is free software; you can redistribute it
-+ * and/or modify it under the terms of the GNU General
-+ * Public License as published by the Free Software
-+ * Foundation; either version 2 of the License, or (at
-+ * your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will
-+ * be useful, but WITHOUT ANY WARRANTY; without even the
-+ * implied warranty of MERCHANTABILITY or FITNESS FOR A
-+ * PARTICULAR PURPOSE. See the GNU General Public
-+ * License for more details.
-+ *
-+ * The GNU General Public License should be included with
-+ * this file. If not, you can view it at
-+ * http://www.gnu.org/copyleft/gpl.html
-+ * or write to the Free Software Foundation, Inc., 59
-+ * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-+ *
-+ * Revisions :
-+ * $Log: addrlist.h,v $
-+ *
-+ *********************************************************************/
-+
-+#include <sys/socket.h>
++ uint8_t *network_addr, *netmask_addr, *address_addr;
++ unsigned int addr_len;
++ in_port_t *network_port, *netmask_port, *address_port;
++ int i;
+
-+typedef struct addrinfo addr_list;
++ if (network->ss_family != netmask->ss_family)
++ {
++ /* This should never happen */
++ log_error(LOG_LEVEL_ERROR,
++ "Internal error at %s:%llu: network and netmask differ in family",
++ __FILE__, __LINE__);
++ return 0;
++ }
+
-+addr_list *tail_addr_list(addr_list *l);
-+struct sockaddr_storage *head_addr_list(addr_list *l);
-+void cpy_head_addr_list(addr_list *l, struct sockaddr_storage *r, size_t *addrlen);
-+void destroy_addr_list(addr_list *l);
-+int is_nil_addr_list(addr_list *l);
++ sockaddr_storage_to_ip(network, &network_addr, &addr_len, &network_port);
++ sockaddr_storage_to_ip(netmask, &netmask_addr, NULL, &netmask_port);
++ sockaddr_storage_to_ip(address, &address_addr, NULL, &address_port);
+
-+#define freez_addr_list(X) { if(X) { destroy_addr_list(X); X = NULL ; } }
++ /* Check for family */
++ if (network->ss_family == AF_INET && address->ss_family == AF_INET6 &&
++ IN6_IS_ADDR_V4MAPPED(address_addr))
++ {
++ /* Map AF_INET6 V4MAPPED address into AF_INET */
++ address_addr += 12;
++ addr_len = 4;
++ }
++ else if (network->ss_family == AF_INET6 && address->ss_family == AF_INET &&
++ IN6_IS_ADDR_V4MAPPED(network_addr))
++ {
++ /* Map AF_INET6 V4MAPPED network into AF_INET */
++ network_addr += 12;
++ netmask_addr += 12;
++ addr_len = 4;
++ }
++ else if (network->ss_family != address->ss_family)
++ {
++ return 0;
++ }
+
-+#endif /* ndef LIST_H_INCLUDED */
++ /* XXX: Port check is signaled in netmask */
++ if (*netmask_port && *network_port != *address_port)
++ {
++ return 0;
++ }
+
-+/*
-+ Local Variables:
-+ tab-width: 3
-+ end:
-+*/
-diff -urNad privoxy~/cgi.c privoxy/cgi.c
---- privoxy~/cgi.c
-+++ privoxy/cgi.c
-@@ -14,6 +14,9 @@
- * Copyright : Written by and Copyright (C) 2001 the SourceForge
- * Privoxy team. http://www.privoxy.org/
- *
-+ * Modified by Lionel Elie Mamane <lionel@mamane.lu>
-+ * for IPv6 support on 8 December 2002, 24 January 2003.
-+ *
- * Based on the Internet Junkbuster originally written
- * by and Copyright (C) 1997 Anonymous Coders and
- * Junkbusters Corporation. http://www.junkbusters.com
-@@ -2259,7 +2262,6 @@
- *********************************************************************/
- struct map *default_exports(const struct client_state *csp, const char *caller)
- {
-- char buf[20];
- jb_err err;
- struct map * exports;
- int local_help_exists = 0;
-@@ -2295,8 +2297,7 @@
- if (!err) err = map_block_killer(exports, "can-toggle");
- #endif
-
-- snprintf(buf, 20, "%d", csp->config->hport);
-- if (!err) err = map(exports, "my-port", 1, buf, 1);
-+ if (!err) err = map(exports, "my-port", 1, csp->my_port_str, 1);
-
- if(!strcmp(CODE_STATUS, "stable"))
- {
-diff -urNad privoxy~/errlog.c privoxy/errlog.c
---- privoxy~/errlog.c
-+++ privoxy/errlog.c
-@@ -746,6 +746,13 @@
- break;
- case 'E':
- /* Non-standard: Print error code from errno */
-+ /* TODO
-+ * This is not only not standard, but clashes
-+ * with the E modifier on the GNU (and possibly
-+ * other systems): It means double (floating point)
-+ * number in exponential notation, with capital E
-+ * for mantiss / exponenent separator
-+ */
- #ifdef _WIN32
- ival = WSAGetLastError();
- sval = w32_socket_strerr(ival, tempbuf);
-diff -urNad privoxy~/filters.c privoxy/filters.c
---- privoxy~/filters.c
-+++ privoxy/filters.c
-@@ -15,6 +15,9 @@
- * Copyright : Written by and Copyright (C) 2001, 2004 the SourceForge
- * Privoxy team. http://www.privoxy.org/
- *
-+ * Modified by Lionel Elie Mamane <lionel@mamane.lu>
-+ * for IPv6 support on 8 December 2002, 24 January 2003.
-+ *
- * Based on the Internet Junkbuster originally written
- * by and Copyright (C) 1997 Anonymous Coders and
- * Junkbusters Corporation. http://www.junkbusters.com
-@@ -471,6 +474,9 @@
- #include <ctype.h>
- #include <string.h>
- #include <assert.h>
-+#ifdef INET6
-+#include <netdb.h>
-+#endif
-
- #ifndef _WIN32
- #ifndef __OS2__
-@@ -505,17 +511,119 @@
-
- const char filters_h_rcs[] = FILTERS_H_VERSION;
-
--/* Fix a problem with Solaris. There should be no effect on other
-- * platforms.
-- * Solaris's isspace() is a macro which uses it's argument directly
-- * as an array index. Therefore we need to make sure that high-bit
-- * characters generate +ve values, and ideally we also want to make
-- * the argument match the declared parameter type of "int".
-- */
--#define ijb_isdigit(__X) isdigit((int)(unsigned char)(__X))
-+#ifdef FEATURE_ACL
-+/*********************************************************************
-+ *
-+ * Function : addr_equal_under_mask
-+ *
-+ * Description : Are these addresses equal modulo this mask?
-+ * Assumes the second argument is already in
-+ * mask-normal form
-+ *
-+ * Parameters :
-+ * 0 : addr1 = First address to compare
-+ * 1 : addr2 = Second address to compare
-+ * MUST be in mask-normal form
-+ * 2 : mask = for IPv4 addresses, a bitmask
-+ * for IPv6 addresses, a prefixlen in bits
-+ *
-+ * Returns : 0 = FALSE (not equal) and non-zero = TRUE (equal)
-+ *
-+ *********************************************************************/
-+static
-+int
-+addr_equal_under_mask(struct sockaddr_storage *addr1, struct sockaddr_storage *addr2, unsigned long mask)
-+{
-+ if (!mask)
-+ return 1;
-
-+ /* only identical families can be compared */
-+ /* TODO: Should we code the special case of "IPv4 addresses as IPv6 addresses"? */
-+ if (addr1->ss_family != addr2-> ss_family)
-+ {
-+ /*fprintf(stderr, "equal_under_mask: diff sa_family: %d %d\n",
-+ sa1->sa_family, sa2-> sa_family); */
-+ return 0;
-+ }
-+
-+ switch (addr1->ss_family)
++ /* TODO: Optimize by checking by words insted of octets */
++ for (i=0; i < addr_len && netmask_addr[i]; i++)
++ {
++ if ( (network_addr[i] & netmask_addr[i]) !=
++ (address_addr[i] & netmask_addr[i]) )
+ {
-+ case AF_INET:
-+ {
-+ /* IPv4 - mask is a bitmask */
-+ struct sockaddr_in *sin1 = (struct sockaddr_in *)addr1;
-+ struct sockaddr_in *sin2 = (struct sockaddr_in *)addr2;
-+
-+ /*fprintf(stderr, "AF_INET: %08x %08x %08x\n",
-+ sin1->sin_addr.s_addr,
-+ sin2->sin_addr.s_addr,
-+ mask); */
-+ return (sin1->sin_addr.s_addr & mask) == sin2->sin_addr.s_addr;
-+ }
-+ break;
-+#ifdef INET6
-+ case AF_INET6:
-+ {
-+ /* IPv6 - mask is a prefixlength in bits. */
-+ struct sockaddr_in6 *sin1 = (struct sockaddr_in6 *)addr1;
-+ struct sockaddr_in6 *sin2 = (struct sockaddr_in6 *)addr2;
-+ char bitmask;
-+ char *a1, *a2;
-+ const int maskbytes = mask / 8;
-+ static char m[] = { 0x00, 0x80, 0xC0, 0xE0,
-+ 0xF0, 0xF8, 0xFC, 0xFE };
-+/* { */
-+/* int i; */
-+/* fprintf(stderr, "PF_INET6: "); */
-+/* for (i = 0; i < 16; i++) { */
-+/* fprintf(stderr, "%02x ", sin1->sin6_addr.s6_addr[i]); */
-+/* } */
-+/* fprintf(stderr, " "); */
-+/* for (i = 0; i < 16; i++) { */
-+/* fprintf(stderr, "%02x ", sin2->sin6_addr.s6_addr[i]); */
-+/* } */
-+/* fprintf(stderr, "mask %d scopeids %x %x\n", mask, sin1->sin6_scope_id, sin2->sin6_scope_id); */
-+/* } */
-+ /* should we compare scope ids and such too? */
-+ /*
-+ * LEM: I see no reason for this comparison
-+ * Quite the contrary: A client coming to us with
-+ * a small-scope address should be able to a bigger-scope
-+ * address.
-+ */
-+/* if (sin1->sin6_scope_id != sin2->sin6_scope_id) */
-+/* return 0; */
-+
-+ if (mask > 128ul)
-+ {
-+ log_error(LOG_LEVEL_ERROR, "%s%d", "Tried to compare IPv6 addresses with invalid prefixlen: ", mask);
-+ return 0;
-+ }
-+
-+ a1 = sin1->sin6_addr.s6_addr;
-+ a2 = sin2->sin6_addr.s6_addr;
-+
-+ if (memcmp(a1, a2, maskbytes) != 0)
-+ return 0;
-+
-+ mask %= 8;
-+ /* This special case is necessary for when mask==128
-+ else, we would go over the array size in a1/a2
-+ */
-+ if (mask==0)
-+ return 1;
-+
-+ bitmask = m[mask];
-+
-+ return (a1[maskbytes] & bitmask) == a2[maskbytes];
-+ }
-+ break;
-+#endif
-+ default:
+ return 0;
+ }
++ }
++
++ return 1;
+}
-
--#ifdef FEATURE_ACL
++#endif /* def HAVE_GETADDRINFO */
++
++
/*********************************************************************
*
* Function : block_acl
-@@ -545,7 +653,7 @@
+@@ -741,7 +892,13 @@
/* search the list */
while (acl != NULL)
{
- if ((csp->ip_addr_long & acl->src->mask) == acl->src->addr)
-+ if (addr_equal_under_mask(&csp->ip_addr_addr, &acl->src->addr, acl->src->mask))
++ if (
++#ifdef HAVE_GETADDRINFO
++ match_sockaddr(&acl->src->addr, &acl->src->mask, &csp->tcp_addr)
++#else
++ (csp->ip_addr_long & acl->src->mask) == acl->src->addr
++#endif
++ )
{
if (dst == NULL)
{
-@@ -555,8 +663,8 @@
+@@ -751,8 +908,23 @@
return(0);
}
}
- else if ( ((dst->addr & acl->dst->mask) == acl->dst->addr)
- && ((dst->port == acl->dst->port) || (acl->dst->port == 0)))
-+ else if ( addr_equal_under_mask(&dst->addr, &acl->dst->addr, acl->dst->mask)
-+ && ((dst->port == acl->dst->port) || (acl->dst->port == 0)))
++ else if (
++#ifdef HAVE_GETADDRINFO
++ /* XXX: Undefined acl->dst is full of zeros and should be
++ * considered as wildcard address.
++ * sockaddr_storage_to_ip() failes on such dst because of
++ * uknown sa_familly on glibc. However this test is not
++ * portable.
++ *
++ * So, we signal the acl->dst is wildcard in wildcard_dst.
++ */
++ acl->wildcard_dst ||
++ match_sockaddr(&acl->dst->addr, &acl->dst->mask, &dst->addr)
++#else
++ ((dst->addr & acl->dst->mask) == acl->dst->addr)
++ && ((dst->port == acl->dst->port) || (acl->dst->port == 0))
++#endif
++ )
{
if (acl->action == ACL_PERMIT)
{
-@@ -575,81 +683,249 @@
-
- }
-
--
- /*********************************************************************
- *
-- * Function : acl_addr
-+ * Function : fill_acl_addr_mask
- *
-- * Description : Called from `load_config' to parse an ACL address.
-+ * Description : Fill in the mask-related members of a
-+ * struct access_control_addr
- *
- * Parameters :
-- * 1 : aspec = String specifying ACL address.
-- * 2 : aca = struct access_control_addr to fill in.
-+ * 0 : aca = struct access_control_addr to fill in.
-+ * 1 : masklength = mask length.
- *
-- * Returns : 0 => Ok, everything else is an error.
-+ * Returns : nothing
- *
- *********************************************************************/
--int acl_addr(char *aspec, struct access_control_addr *aca)
-+void fill_acl_addr_mask(struct access_control_addr *aca, int masklength)
+@@ -788,12 +960,24 @@
+ int acl_addr(const char *aspec, struct access_control_addr *aca)
{
-- int i, masklength, port;
-- char *p;
-+ int pf;
-
-- masklength = 32;
-- port = 0;
-+ pf = aca->addr.ss_family;
+ int i, masklength;
++#ifdef HAVE_GETADDRINFO
++ struct addrinfo hints, *result;
++ uint8_t *mask_data;
++ in_port_t *mask_port;
++ unsigned int addr_len;
++#else
+ long port;
++#endif /* def HAVE_GETADDRINFO */
+ char *p;
+ char *acl_spec = NULL;
+
++#ifdef HAVE_GETADDRINFO
++ /* FIXME: Depend on ai_family */
++ masklength = 128;
++#else
+ masklength = 32;
+ port = 0;
++#endif
-- if ((p = strchr(aspec, '/')) != NULL)
-+ switch (pf)
- {
-- *p++ = '\0';
--
-- if (ijb_isdigit(*p) == 0)
-+ case PF_INET:
-+ /* build the netmask */
-+ if (masklength == -1)
-+ masklength = 32;
-+ aca->mask = 0;
-+ for(pf=1; pf <= masklength ; ++pf)
- {
-- return(-1);
-+ aca->mask |= (1 << (32 - pf));
- }
-- masklength = atoi(p);
-- }
-+ aca->mask = htonl(aca->mask);
-+
-+ /* now mask off the host portion of the ip address
-+ * (i.e. save on the network portion of the address).
-+ */
-+ ((struct sockaddr_in*) &aca->addr)->sin_addr.s_addr &= aca->mask;
-+ aca->port = ((struct sockaddr_in*) &aca->addr)->sin_port;
-+ break;
-+#ifdef INET6
-+ case PF_INET6:
-+ {
-+ static char m[] = { 0x00, 0x80, 0xC0, 0xE0,
-+ 0xF0, 0xF8, 0xFC, 0xFE };
-+ int i;
-+ struct sockaddr_in6 *sa6 = (struct sockaddr_in6*)&aca->addr;
+ /*
+ * Use a temporary acl spec copy so we can log
+@@ -817,13 +1001,53 @@
+ masklength = atoi(p);
+ }
- if ((masklength < 0) || (masklength > 32))
-- {
-- return(-1);
-+ aca->mask = (masklength == -1) ? masklength : 128 ;
-+ /* now mask off the host portion of the ip address
-+ * (i.e. save on the network portion of the address).
-+ */
-+ i = aca->mask / 8;
-+ if (i < 16)
-+ {
-+ sa6->sin6_addr.s6_addr[i] &= m[aca->mask % 8];
-+ /* The following loop is not strictly necessary,
-+ because of the way addr_equal_under_mask is
-+ written. Better safe than sorry, though:
-+ New code might make the full mask-normal
-+ form assumption.
-+ */
-+ for(++i; i < 16 ; ++i)
-+ sa6->sin6_addr.s6_addr[i] = 0;
-+ }
-+ aca -> port = sa6->sin6_port;
-+ break;
-+ }
++ if ((masklength < 0) ||
++#ifdef HAVE_GETADDRINFO
++ (masklength > 128)
++#else
++ (masklength > 32)
+#endif
-+ default:
-+ /* FATAL because access_control_addr's are created only with adresses
-+ deemed 'acceptable' by the addr_list stuff, thus currently IPv4 and
-+ IPv6.
-+ */
-+ log_error(LOG_LEVEL_FATAL,"%s%d","Unknown address family in ACL address: ",pf);
++ )
+ {
+ freez(acl_spec);
+ return(-1);
}
-+}
-
-- if ((p = strchr(aspec, ':')) != NULL)
-- {
-- *p++ = '\0';
-+/*********************************************************************
-+ *
-+ * Function : acl_addrs
-+ *
-+ * Description : Parse an ACL address (adress + mask prefix)
-+ * Resolve the parsed address
-+ * Describe errors in *proxy_args.
-+ *
-+ * Parameters :
-+ * 0 : aspec = the string containing the ACL address/mask
-+ * 1 : masklength = pointer used to return the mask
-+ * 2 : proxy_args = Pointer to string to append description of errors to.
-+ * 3 : type = type of ACL adress (source / destination).
-+ * Used for error reporting.
-+ *
-+ * Returns : the list of adresses the ACL address resolves to
-+ *
-+ *********************************************************************/
-+static addr_list *acl_addrs(char *aspec, int *masklength, char**proxy_args, const char *type)
-+{
-+ char *host;
-+ char *port;
-+ int pf;
-- if (ijb_isdigit(*p) == 0)
-- {
-- return(-1);
-- }
-- port = atoi(p);
-+ pf = -1;
-+ if (parse_pf_ip_netmask(aspec, &host, &port, &pf, masklength) != 0)
+- if ((p = strchr(acl_spec, ':')) != NULL)
++ if (*acl_spec == '[' && NULL != (p = strchr(acl_spec, ']')))
+ {
-+ log_error(LOG_LEVEL_ERROR, "Invalid %s IP for (deny|permit)-access "
-+ "directive in configuration file: \"%s\"", type, aspec);
-+ string_append(proxy_args,"<br>\nWARNING: Invalid ");
-+ string_append(proxy_args, type);
-+ string_append(proxy_args," IP for (deny|permit)-access directive"
-+ " in configuration file: \"");
-+ string_append(proxy_args, aspec);
-+ string_append(proxy_args,"\"<br><br>\n");
-+ return NULL;
- }
-
-- aca->port = port;
-+ return resolve_hostname_to_ip(host, port, pf);
-+}
-
-- aca->addr = ntohl(resolve_hostname_to_ip(aspec));
-+/*********************************************************************
-+ *
-+ * Function : add_one_to_acl_list
-+ *
-+ * Description : Add one entry to an access_control_list.
-+ *
-+ * Parameters :
-+ * 0 : l = the list to add to
-+ * 1 : action = ACL_DENY or ACL_PERMIT
-+ * 2 : src_addrs = the head of this list will be used as source
-+ * in the ACL entry.
-+ * 3 : dst_addrs = the head of this list will be used as destination
-+ * in the ACL entry.
-+ * NULL for none
-+ * 4 : src_masklength = mask length for the source
-+ * 5 : src_masklength = mask length for the destination
-+ *
-+ * Returns : the new list
-+ *
-+ *********************************************************************/
-+struct access_control_list *add_one_to_acl_list(struct access_control_list *l, short action,
-+ addr_list *src_addrs, addr_list *dst_addrs,
-+ int src_masklength, int dst_masklength)
-+{
-+ struct access_control_list *cur_acl;
-+ /* allocate a new node */
-+ cur_acl = (struct access_control_list *) zalloc(sizeof(*cur_acl));
-
-- if (aca->addr == INADDR_NONE)
-+ if (cur_acl == NULL)
++ *p = '\0';
++ memmove(acl_spec, acl_spec + 1, (size_t) (p - acl_spec));
++
++ if (*++p != ':')
++ {
++ p = NULL;
++ }
++ }
++ else
++ {
++ p = strchr(acl_spec, ':');
++ }
++
++#ifdef HAVE_GETADDRINFO
++ memset(&hints, 0, sizeof(struct addrinfo));
++ hints.ai_family = AF_UNSPEC;
++ hints.ai_socktype = SOCK_STREAM;
++
++ i = getaddrinfo(acl_spec, (p) ? ++p : NULL, &hints, &result);
++ freez(acl_spec);
++
++ if (i != 0)
++ {
++ log_error(LOG_LEVEL_ERROR, "Can not resolve [%s]:%s: %s", acl_spec, p,
++ gai_strerror(i));
++ return(-1);
++ }
++
++ /* TODO: Allow multihomed hostnames */
++ memcpy(&(aca->addr), result->ai_addr, sizeof(aca->addr));
++ freeaddrinfo(result);
++#else
++ if (p != NULL)
{
-- return(-1);
-+ log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
-+ /* Never get here - LOG_LEVEL_FATAL causes program exit */
-+ return l;
+ char *endptr;
+
+@@ -847,8 +1071,49 @@
+ /* XXX: This will be logged as parse error. */
+ return(-1);
}
++#endif /* def HAVE_GETADDRINFO */
-- /* build the netmask */
-- aca->mask = 0;
-- for (i=1; i <= masklength ; i++)
-+ cur_acl->action = action;
-+
-+ cpy_head_addr_list(src_addrs, &cur_acl->src->addr, &cur_acl->src->addrlen);
-+ fill_acl_addr_mask(cur_acl->src, src_masklength);
-+ if (dst_addrs != NULL)
- {
-- aca->mask |= (1 << (32 - i));
-+ cpy_head_addr_list(dst_addrs, &cur_acl->dst->addr, &cur_acl->dst->addrlen);
-+ fill_acl_addr_mask(cur_acl->src, src_masklength);
- }
-
-- /* now mask off the host portion of the ip address
-- * (i.e. save on the network portion of the address).
-+ /*
-+ * Add it to the list. Note we reverse the list to get the
-+ * behaviour the user expects. With both the ACL and
-+ * actions file, the last match wins. However, the internal
-+ * implementations are different: The actions file is stored
-+ * in the same order as the file, and scanned completely.
-+ * With the ACL, we reverse the order as we load it, then
-+ * when we scan it we stop as soon as we get a match.
- */
-- aca->addr = aca->addr & aca->mask;
-+ cur_acl->next = l;
-
-- return(0);
-+ return cur_acl;
-+}
-+
-+/*********************************************************************
-+ *
-+ * Function : add_to_acl_list
-+ *
-+ * Description : Add entries to an access_control_list.
-+ * Describe errors in *proxy_args.
-+ *
-+ * Parameters :
-+ * 0 : l = the list to add to
-+ * 1 : action = ACL_DENY or ACL_PERMIT
-+ * 2 : src_spec = String giving the source of the acl entry
-+ * 3 : dst_spec = String giving the destination of the acl entry,
-+ * or NULL
-+ * 4 : proxy_args = Pointer to string to append description of errors to.
-+ *
-+ * Returns : the new list
-+ *
-+ *********************************************************************/
-+struct access_control_list *add_to_acl_list(struct access_control_list *l,
-+ short action,
-+ char *src_spec,
-+ char *dst_spec,
-+ char **proxy_args)
-+{
-+ int src_masklength, dst_masklength;
-+ addr_list *src_addrs, *dst_addrs;
-+ addr_list *src_addrs_remaining, *dst_addrs_remaining;
-+
-+ src_addrs = acl_addrs(src_spec, &src_masklength, proxy_args, "source");
-+ if (is_nil_addr_list(src_addrs))
+ /* build the netmask */
++#ifdef HAVE_GETADDRINFO
++ /* Clip masklength according current family */
++ if (aca->addr.ss_family == AF_INET && masklength > 32)
+ {
-+ log_error(LOG_LEVEL_ERROR, "Source of ACL resolves to no address",dst_spec);
-+ return l;
++ masklength = 32;
+ }
-+ if (dst_spec != NULL)
-+ {
-+ dst_addrs = acl_addrs(dst_spec, &dst_masklength, proxy_args, "destination");
-+ if (is_nil_addr_list(dst_addrs))
-+ {
-+ log_error(LOG_LEVEL_ERROR, "Destination of ACL resolves to no address",dst_spec);
-+ destroy_addr_list(src_addrs);
-+ return l;
-+ }
-+ }
-+ else
-+ dst_addrs = NULL;
+
-+ for(src_addrs_remaining = src_addrs;
-+ is_nil_addr_list(src_addrs);
-+ src_addrs_remaining=tail_addr_list(src_addrs_remaining))
++ aca->mask.ss_family = aca->addr.ss_family;
++ if (sockaddr_storage_to_ip(&aca->mask, &mask_data, &addr_len, &mask_port))
+ {
-+ if (dst_addrs == NULL)
-+ l = add_one_to_acl_list(l, action, src_addrs_remaining, NULL, src_masklength,0);
-+ else for(dst_addrs_remaining = dst_addrs;
-+ is_nil_addr_list(dst_addrs);
-+ dst_addrs_remaining=tail_addr_list(dst_addrs_remaining))
-+ l = add_one_to_acl_list(l, action, src_addrs_remaining, dst_addrs_remaining,
-+ src_masklength, dst_masklength);
-+ }
-+ destroy_addr_list(src_addrs);
-+ destroy_addr_list(dst_addrs);
-
-+ return l;
- }
--#endif /* def FEATURE_ACL */
-
-+#endif /* def FEATURE_ACL */
-
- /*********************************************************************
- *
-diff -urNad privoxy~/filters.h privoxy/filters.h
---- privoxy~/filters.h
-+++ privoxy/filters.h
-@@ -15,6 +15,9 @@
- * Copyright : Written by and Copyright (C) 2001, 2004 the SourceForge
- * Privoxy team. http://www.privoxy.org/
- *
-+ * Modified by Lionel Elie Mamane <lionel@mamane.lu>
-+ * for IPv6 support on 8 December 2002, 24 January 2003.
-+ *
- * Based on the Internet Junkbuster originally written
- * by and Copyright (C) 1997 Anonymous Coders and
- * Junkbusters Corporation. http://www.junkbusters.com
-@@ -234,7 +237,11 @@
- */
- #ifdef FEATURE_ACL
- extern int block_acl(struct access_control_addr *dst, struct client_state *csp);
--extern int acl_addr(char *aspec, struct access_control_addr *aca);
-+extern struct access_control_list *add_to_acl_list(struct access_control_list *l,
-+ short action,
-+ char *src_spec,
-+ char *dst_spec,
-+ char **proxy_args);
- #endif /* def FEATURE_ACL */
- extern int match_portlist(const char *portlist, int port);
-
-diff -urNad privoxy~/gateway.c privoxy/gateway.c
---- privoxy~/gateway.c
-+++ privoxy/gateway.c
-@@ -10,6 +10,9 @@
- * Copyright : Written by and Copyright (C) 2001 the SourceForge
- * Privoxy team. http://www.privoxy.org/
- *
-+ * Modified by Lionel Elie Mamane <lionel@mamane.lu>
-+ * for IPv6 support on 8 December 2002, 24 January 2003.
-+ *
- * Based on the Internet Junkbuster originally written
- * by and Copyright (C) 1997 Anonymous Coders and
- * Junkbusters Corporation. http://www.junkbusters.com
-@@ -203,12 +206,14 @@
- * Returns : JB_INVALID_SOCKET => failure, else it is the socket file descriptor.
- *
- *********************************************************************/
--jb_socket forwarded_connect(const struct forward_spec * fwd,
-+jb_socket forwarded_connect(const struct forward_spec *fwd,
- struct http_request *http,
- struct client_state *csp)
- {
- const char * dest_host;
-- int dest_port;
-+ const char * dest_port_str;
-+ unsigned long dest_port;
-+ int dest_pf;
-
- /* Figure out if we need to connect to the web server or a HTTP proxy. */
- if (fwd->forward_host)
-@@ -216,19 +221,23 @@
- /* HTTP proxy */
- dest_host = fwd->forward_host;
- dest_port = fwd->forward_port;
-+ dest_port_str = fwd->forward_port_str;
-+ dest_pf = fwd->forward_family;
- }
- else
- {
- /* Web server */
- dest_host = http->host;
- dest_port = http->port;
-+ dest_port_str = http->port_str;
-+ dest_pf = PF_UNSPEC;
- }
-
- /* Connect, maybe using a SOCKS proxy */
- switch (fwd->type)
- {
- case SOCKS_NONE:
-- return (connect_to(dest_host, dest_port, csp));
-+ return (connect_to(dest_host, dest_port_str, dest_port, dest_pf, csp));
-
- case SOCKS_4:
- case SOCKS_4A:
-@@ -262,74 +271,19 @@
- * Returns : JB_INVALID_SOCKET => failure, else a socket file descriptor.
- *
- *********************************************************************/
--static jb_socket socks4_connect(const struct forward_spec * fwd,
-- const char * target_host,
-- int target_port,
-- struct client_state *csp)
-+static jb_socket socks4_connect_one_ip(const struct forward_spec * fwd,
-+ unsigned long web_server_addr,
-+ int target_port,
-+ struct client_state *csp,
-+ size_t csiz,
-+ char *cbuf)
- {
-- int web_server_addr;
-- char cbuf[BUFFER_SIZE];
- char sbuf[BUFFER_SIZE];
-- struct socks_op *c = (struct socks_op *)cbuf;
- struct socks_reply *s = (struct socks_reply *)sbuf;
-- size_t n;
-- size_t csiz;
-+ struct socks_reply *c = (struct socks_reply *)cbuf;
- jb_socket sfd;
-- int err = 0;
- char *errstr;
-
-- if ((fwd->gateway_host == NULL) || (*fwd->gateway_host == '\0'))
-- {
-- log_error(LOG_LEVEL_CONNECT, "socks4_connect: NULL gateway host specified");
-- err = 1;
-- }
--
-- if (fwd->gateway_port <= 0)
-- {
-- log_error(LOG_LEVEL_CONNECT, "socks4_connect: invalid gateway port specified");
-- err = 1;
-- }
--
-- if (err)
-- {
-- errno = EINVAL;
-- return(JB_INVALID_SOCKET);
-- }
--
-- /* build a socks request for connection to the web server */
--
-- strcpy((char *)&(c->userid), socks_userid);
--
-- csiz = sizeof(*c) + sizeof(socks_userid) - 1;
--
-- switch (fwd->type)
-- {
-- case SOCKS_4:
-- web_server_addr = htonl(resolve_hostname_to_ip(target_host));
-- if (web_server_addr == INADDR_NONE)
-- {
-- log_error(LOG_LEVEL_CONNECT, "socks4_connect: could not resolve target host %s", target_host);
-- return(JB_INVALID_SOCKET);
-- }
-- break;
-- case SOCKS_4A:
-- web_server_addr = 0x00000001;
-- n = csiz + strlen(target_host) + 1;
-- if (n > sizeof(cbuf))
-- {
-- errno = EINVAL;
-- return(JB_INVALID_SOCKET);
-- }
-- strcpy(cbuf + csiz, target_host);
-- csiz = n;
-- break;
-- default:
-- /* Should never get here */
-- log_error(LOG_LEVEL_FATAL, "SOCKS4 impossible internal error - bad SOCKS type.");
-- errno = EINVAL;
-- return(JB_INVALID_SOCKET);
-- }
--
- c->vn = 4;
- c->cd = 1;
- c->dstport[0] = (target_port >> 8 ) & 0xff;
-@@ -340,7 +294,7 @@
- c->dstip[3] = (web_server_addr ) & 0xff;
-
- /* pass the request to the socks server */
-- sfd = connect_to(fwd->gateway_host, fwd->gateway_port, csp);
-+ sfd = connect_to(fwd->gateway_host, fwd->gateway_port_str, fwd->gateway_port, PF_INET ,csp);
-
- if (sfd == JB_INVALID_SOCKET)
- {
-@@ -395,6 +349,92 @@
-
- }
-
-+static jb_socket socks4_connect(const struct forward_spec * fwd,
-+ const char * target_host,
-+ int target_port,
-+ struct client_state *csp)
-+{
-+ char cbuf[BUFFER_SIZE];
-+ struct socks_op *c = (struct socks_op *)cbuf;
-+ size_t csiz;
-+ int err = 0;
-+
-+ /**
-+ * SOCKS4 is IPv4-specific. At least I think so.
-+ */
-+ if ((fwd->gateway_host == NULL) || (*fwd->gateway_host == '\0'))
-+ {
-+ log_error(LOG_LEVEL_CONNECT, "socks4_connect: NULL gateway host specified");
-+ err = 1;
-+ }
-+
-+ if (fwd->gateway_port <= 0)
-+ {
-+ log_error(LOG_LEVEL_CONNECT, "socks4_connect: invalid gateway port specified");
-+ err = 1;
++ return(-1);
+ }
+
-+ if (err)
++ if (p)
+ {
-+ errno = EINVAL;
-+ return(JB_INVALID_SOCKET);
++ /* Port number in ACL has been specified, check ports in future */
++ *mask_port = 1;
+ }
+
-+ /* build a socks request for connection to the web server */
-+
-+ strcpy((char *)&(c->userid), socks_userid);
-+
-+ csiz = sizeof(*c) + sizeof(socks_userid) - 1;
-+
-+ switch (fwd->type)
++ /* XXX: This could be optimized to operate on whole words instead of octets
++ * (128-bit CPU could do it in one iteration). */
++ /* Octets after prefix can be ommitted because of previous initialization
++ * to zeros. */
++ for (i=0; i < addr_len && masklength; i++)
+ {
-+ case SOCKS_4:
++ if (masklength >= 8)
+ {
-+ addr_list *web_server_addrs = resolve_hostname_to_ip(target_host,NULL,PF_INET);
-+ jb_socket return_value = JB_INVALID_SOCKET;
-+ if (is_nil_addr_list(web_server_addrs))
-+ {
-+ log_error(LOG_LEVEL_CONNECT, "socks4_connect: could not resolve target host %s", target_host);
-+ }
-+ else
-+ {
-+ addr_list *addrs_to_try;
-+
-+ for(addrs_to_try = web_server_addrs;
-+ !is_nil_addr_list(addrs_to_try);
-+ addrs_to_try = tail_addr_list(addrs_to_try))
-+ {
-+ const unsigned long web_server_addr = ((struct sockaddr_in*) head_addr_list(addrs_to_try))->sin_addr.s_addr;
-+ return_value=socks4_connect_one_ip(fwd, web_server_addr, target_port, csp, csiz, cbuf);
-+ if(return_value != JB_INVALID_SOCKET)
-+ break;
-+ }
-+ }
-+ destroy_addr_list(web_server_addrs);
-+ return return_value;
-+ break;
++ mask_data[i] = 0xFF;
++ masklength -= 8;
+ }
-+ case SOCKS_4A:
++ else
+ {
-+ size_t n;
-+ n = csiz + strlen(target_host) + 1;
-+ if (n > sizeof(cbuf))
-+ {
-+ errno = EINVAL;
-+ return(JB_INVALID_SOCKET);
-+ }
-+ strcpy(cbuf + csiz, target_host);
-+ csiz = n;
-+ return socks4_connect_one_ip(fwd, 0x00000001, target_port, csp, csiz, cbuf);
-+ break;
++ /* XXX: This assumes MSB of octet is on the left site. This should be
++ * true for all architectures or solved on link layer of OSI model. */
++ mask_data[i] = ~((1 << (8 - masklength)) - 1);
++ masklength = 0;
+ }
-+ default:
-+ /* Should never get here */
-+ log_error(LOG_LEVEL_FATAL, "SOCKS4 impossible internal error - bad SOCKS type.");
-+ errno = EINVAL;
-+ return(JB_INVALID_SOCKET);
+ }
-+}
++
++#else
+ aca->mask = 0;
+ for (i=1; i <= masklength ; i++)
+ {
+@@ -859,6 +1124,7 @@
+ * (i.e. save on the network portion of the address).
+ */
+ aca->addr = aca->addr & aca->mask;
++#endif /* def HAVE_GETADDRINFO */
- /*
+ return(0);
+
+@@ -2706,4 +2972,6 @@
Local Variables:
-diff -urNad privoxy~/jb_socket_set.c privoxy/jb_socket_set.c
---- privoxy~/jb_socket_set.c
-+++ privoxy/jb_socket_set.c
-@@ -0,0 +1,174 @@
-+const char jb_socket_set_rcs[] = "$Id: $";
-+/*********************************************************************
-+ *
-+ * File : $Source: $
-+ *
-+ * Purpose : Declares functions to handle sets of sockets
-+ *
-+ * Copyright : Written by and Copyright (C) 2002 Lionel Elie Mamane
-+ * <lionel@mamane.lu>
-+ *
-+ * This program is free software; you can redistribute it
-+ * and/or modify it under the terms of the GNU General
-+ * Public License as published by the Free Software
-+ * Foundation; either version 2 of the License, or (at
-+ * your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will
-+ * be useful, but WITHOUT ANY WARRANTY; without even the
-+ * implied warranty of MERCHANTABILITY or FITNESS FOR A
-+ * PARTICULAR PURPOSE. See the GNU General Public
-+ * License for more details.
-+ *
-+ * The GNU General Public License should be included with
-+ * this file. If not, you can view it at
-+ * http://www.gnu.org/copyleft/gpl.html
-+ * or write to the Free Software Foundation, Inc., 59
-+ * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-+ *
-+ * Revisions :
-+ * $Log: jb_socket_set.c,v $
-+ *
-+ *********************************************************************/
-+
-+#include "jb_socket_set.h"
-+#include <sys/time.h>
-+#include <sys/types.h>
-+#include <unistd.h>
-+#include "project.h"
-+
-+/*********************************************************************
-+ *
-+ * Function : jb_socket_set_add
-+ *
-+ * Description : Add a socket to the set
-+ *
-+ * Parameters :
-+ * 0 : l = the set to add to
-+ * 1 : the elemen to add to the set
-+ *
-+ * Returns : 0 on success
-+ * non-0 on failure
-+ *
-+ *********************************************************************/
-+
-+int jb_socket_set_add(jb_socket_set *l, jb_socket e)
-+{
-+ if (l->data==NULL)
-+ {
-+ l->size=2;
-+ l->data=malloc(l->size * sizeof(jb_socket));
-+ if (l->data==NULL)
-+ {
-+ l->size = 0;
-+ return -1;
-+ }
-+ l->occupied=0;
-+ }
-+ l->data[(l->occupied)++] = e;
-+ if (l->occupied == l->size)
-+ {
-+ jb_socket *new_data;
-+ l->size *= 2;
-+ new_data = realloc(l->data,l->size * sizeof(jb_socket));
-+ if (new_data == NULL)
-+ {
-+ /* Not enough memory to continue. Cancel changes. */
-+ l->data[--(l->occupied)] = JB_INVALID_SOCKET;
-+ l->size /= 2;
-+ return -1;
-+ }
-+ l->data = new_data;
-+ }
-+ l->data[l->occupied] = JB_INVALID_SOCKET;
-+ return 0;
-+}
-+
-+/*********************************************************************
-+ *
-+ * Function : destroy_jb_socket_set
-+ *
-+ * Description : Unallocate memory allocated to a socket set
-+ *
-+ * Parameters :
-+ * 0 : l = the set to unallocate
-+ *
-+ * Returns : nothing
-+ *
-+ *********************************************************************/
-+void destroy_jb_socket_set(jb_socket_set *l)
-+{
-+ free(l->data);
-+ init_jb_socket_set(l);
-+}
-+/*********************************************************************
-+ *
-+ * Function : is_empty_jb_socket_set
-+ *
-+ * Description : Test wheter a set is empty
-+ *
-+ * Parameters :
-+ * 0 : l = the set to test
-+ *
-+ * Returns : 0 = false if set has a head,
-+ * anything else = true if set is nil
-+ *
-+ *********************************************************************/
-+int is_nil_jb_socket_set(jb_socket_set *l)
-+{
-+ return (l->occupied == 0);
-+}
-+
-+/*********************************************************************
-+ *
-+ * Function : init_jb_socket_set
-+ *
-+ * Description : Init a set to empty
-+ *
-+ * Parameters :
-+ * 0 : l = the set to init
-+ *
-+ *********************************************************************/
-+void init_jb_socket_set(jb_socket_set *l)
-+{
-+ l->data=NULL;
-+ l->size=0;
-+ l->occupied=0;
-+}
-+
-+/*********************************************************************
-+ *
-+ * Function : jb_socket_set_iteration_begin
-+ *
-+ * Description : Return an iterator on the set
-+ *
-+ * Parameters :
-+ * 0 : l = the set
-+ *
-+ *********************************************************************/
-+jb_socket_set_iterate_state jb_socket_set_iteration_begin(jb_socket_set *l)
-+{
-+ return l->data;
-+}
-+
-+/*********************************************************************
-+ *
-+ * Function : jb_socket_set_iteration_next
-+ *
-+ * Description : Return value pointed to by iterator and step
-+ * iterator to next position
-+ *
-+ * Parameters :
-+ * 0 : s = the iterator
-+ *
-+ *********************************************************************/
-+jb_socket jb_socket_set_iteration_next(jb_socket_set_iterate_state*s)
-+{
-+ return(*((*s)++));
-+}
-+
-+/*
-+ Local Variables:
-+ tab-width: 3
-+ end:
-+*/
-diff -urNad privoxy~/jb_socket_set.h privoxy/jb_socket_set.h
---- privoxy~/jb_socket_set.h
-+++ privoxy/jb_socket_set.h
-@@ -0,0 +1,71 @@
-+#ifndef JB_SOCKET_SET_H_INCLUDED
-+#define JB_SOCKET_SET_H_INCLUDED
-+#define JB_SOCKET_SET_H_VERSION "$Id: $"
-+/*********************************************************************
-+ *
-+ * File : $Source: $
-+ *
-+ * Purpose : Declares functions to handle sets of sockets
-+ *
-+ * Copyright : Written by and Copyright (C) 2002 Lionel Elie Mamane
-+ * <lionel@mamane.lu>
-+ *
-+ * This program is free software; you can redistribute it
-+ * and/or modify it under the terms of the GNU General
-+ * Public License as published by the Free Software
-+ * Foundation; either version 2 of the License, or (at
-+ * your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will
-+ * be useful, but WITHOUT ANY WARRANTY; without even the
-+ * implied warranty of MERCHANTABILITY or FITNESS FOR A
-+ * PARTICULAR PURPOSE. See the GNU General Public
-+ * License for more details.
-+ *
-+ * The GNU General Public License should be included with
-+ * this file. If not, you can view it at
-+ * http://www.gnu.org/copyleft/gpl.html
-+ * or write to the Free Software Foundation, Inc., 59
-+ * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-+ *
-+ * Revisions :
-+ * $Log: jb_socket_set.h,v $
-+ *
-+ *********************************************************************/
-+#include <sys/time.h>
-+#include <sys/types.h>
-+#include <unistd.h>
-+#include "project.h"
-+
-+struct jb_socket_set_struct
-+{
-+ unsigned int size; /* size allocated*/
-+ unsigned int occupied; /* size occupied - 1 == index of final JB_INVALID_SOCKET
-+ == number of sockets in the set */
-+ jb_socket *data; /* Array containing the sockets, JB_INVALID_SOCKET-terminated */
-+};
-+
-+typedef struct jb_socket_set_struct jb_socket_set;
-+typedef const jb_socket* jb_socket_set_iterate_state;
-+
-+void init_jb_socket_set(jb_socket_set*);
-+
-+jb_socket_set_iterate_state jb_socket_set_iteration_begin(jb_socket_set *);
-+jb_socket jb_socket_set_iteration_next(jb_socket_set_iterate_state*);
-+
-+int jb_socket_set_add(jb_socket_set*, jb_socket);
-+
-+void destroy_jb_socket_set(jb_socket_set *l);
-+int is_empty_jb_socket_set(jb_socket_set *l);
+ tab-width: 3
+ end:
+
-+#define freez_jb_socket_set(X) { if(X) { destroy_jb_socket_set(X); X = NULL ; } }
-+
-+int jb_select(jb_socket_set *readfds, jb_socket_set *writefds, jb_socket_set *exceptfds, struct timeval *timeout);
-+
-+#endif /* ndef JB_SOCKET_SET_H_INCLUDED */
-+
-+/*
-+ Local Variables:
-+ tab-width: 3
-+ end:
-+*/
++ vim:softtabstop=3 shiftwidth=3
+ */
diff -urNad privoxy~/jbsockets.c privoxy/jbsockets.c
--- privoxy~/jbsockets.c
+++ privoxy/jbsockets.c
-@@ -11,6 +11,10 @@
- * Copyright : Written by and Copyright (C) 2001 the SourceForge
- * Privoxy team. http://www.privoxy.org/
- *
-+ * Modified by Lionel Elie Mamane <lionel@mamane.lu>
-+ * for IPv6 support on 8-9 December 2002, 24 January 2003,
-+ * 13 February 2003.
-+ *
- * Based on the Internet Junkbuster originally written
- * by and Copyright (C) 1997 Anonymous Coders and
- * Junkbusters Corporation. http://www.junkbusters.com
-@@ -285,6 +289,7 @@
- #include "jbsockets.h"
- #include "filters.h"
- #include "errlog.h"
-+#include "addrlist.h"
-
- const char jbsockets_h_rcs[] = JBSOCKETS_H_VERSION;
-
-@@ -297,141 +302,194 @@
- * that this is allowed according to ACL.
- *
- * Parameters :
-- * 1 : host = hostname to connect to
-- * 2 : portnum = port to connent on
-+ * 0 : host = hostname to connect to
-+ * 1 : port = port to connect on, as string
-+ * 2 : portnum = port to connect on, as integer
- * 3 : csp = Current client state (buffers, headers, etc...)
-- * Not modified, only used for source IP and ACL.
- *
- * Returns : JB_INVALID_SOCKET => failure, else it is the socket
- * file descriptor.
- *
+@@ -357,19 +357,52 @@
*********************************************************************/
--jb_socket connect_to(const char *host, int portnum, struct client_state *csp)
-+jb_socket connect_to_one_ip(struct sockaddr_storage *addr, size_t addrlen, const char *host, unsigned long portnum, struct client_state *csp)
+ jb_socket connect_to(const char *host, int portnum, struct client_state *csp)
{
-- struct sockaddr_in inaddr;
++#ifdef HAVE_GETADDRINFO
++ struct addrinfo hints, *result, *rp;
++ char service[6];
++ int retval;
++#else
+ struct sockaddr_in inaddr;
- jb_socket fd;
-- int addr;
-- fd_set wfds;
-- struct timeval tv[1];
--#if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA)
-- int flags;
--#endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) */
--
- #ifdef FEATURE_ACL
-- struct access_control_addr dst[1];
--#endif /* def FEATURE_ACL */
--
-- memset((char *)&inaddr, 0, sizeof inaddr);
--
-- if ((addr = resolve_hostname_to_ip(host)) == INADDR_NONE)
-+ if (csp)
- {
-- csp->http->host_ip_addr_str = strdup("unknown");
-- return(JB_INVALID_SOCKET);
-- }
-+ struct access_control_addr dst[1];
-+ char hostname[NI_MAXHOST];
-+ char port[NI_MAXSERV];
-+ if (getnameinfo((struct sockaddr*)addr, addrlen, hostname, NI_MAXHOST,
-+ port, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV) != 0)
-+ {
-+ log_error(LOG_LEVEL_ERROR, "connect: Could not get string address and port back from sockaddr because %E");
-+ strncpy(hostname,"unknown",NI_MAXHOST);
-+ strncpy(port,"unknown",NI_MAXSERV);
-+ }
-
--#ifdef FEATURE_ACL
-- dst->addr = ntohl((unsigned long) addr);
-- dst->port = portnum;
-+ csp->http->host_ip_addr_str = strdup(hostname);
-
-- if (block_acl(dst, csp))
-- {
-+ dst->addr = *addr;
-+ dst->addrlen = addrlen;
-+ dst->port = portnum;
-+
-+ if (block_acl(dst, csp))
-+ {
- #ifdef __OS2__
-- errno = SOCEPERM;
-+ errno = SOCEPERM;
- #else
-- errno = EPERM;
-+ errno = EPERM;
- #endif
-- return(JB_INVALID_SOCKET);
-- }
--#endif /* def FEATURE_ACL */
-+ return(JB_INVALID_SOCKET);
-+ }
+ unsigned int addr;
++#endif /* def HAVE_GETADDRINFO */
++ jb_socket fd;
+ fd_set wfds;
+ struct timeval tv[1];
+ #if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA)
+ int flags;
+ #endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) */
++ int connect_failed;
-- inaddr.sin_addr.s_addr = addr;
-- inaddr.sin_family = AF_INET;
-- csp->http->host_ip_addr_str = strdup(inet_ntoa(inaddr.sin_addr));
-
--#ifndef _WIN32
-- if (sizeof(inaddr.sin_port) == sizeof(short))
--#endif /* ndef _WIN32 */
-- {
-- inaddr.sin_port = htons((unsigned short) portnum);
- }
--#ifndef _WIN32
-- else
-+#endif /* def FEATURE_ACL */
-+
- {
-- inaddr.sin_port = htonl((unsigned long)portnum);
-- }
--#endif /* ndef _WIN32 */
-+ jb_socket fd;
-
- #ifdef _WIN32
-- if ((fd = socket(inaddr.sin_family, SOCK_STREAM, 0)) == JB_INVALID_SOCKET)
-+ if ((fd = socket(addr->ss_family, SOCK_STREAM, 0)) == JB_INVALID_SOCKET)
- #else
-- if ((fd = socket(inaddr.sin_family, SOCK_STREAM, 0)) < 0)
-+ if ((fd = socket(addr->ss_family, SOCK_STREAM, 6)) < 0)
- #endif
-- {
-- return(JB_INVALID_SOCKET);
-- }
-+ {
-+ return(JB_INVALID_SOCKET);
-+ }
-
- #ifdef TCP_NODELAY
-- { /* turn off TCP coalescence */
-- int mi = 1;
-- setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &mi, sizeof (int));
-- }
-+ { /* turn off TCP coalescence */
-+ int mi = 1;
-+ setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, (char *) &mi, sizeof (int));
-+ }
- #endif /* def TCP_NODELAY */
-
- #if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__)
-- if ((flags = fcntl(fd, F_GETFL, 0)) != -1)
-- {
-- flags |= O_NDELAY;
-- fcntl(fd, F_SETFL, flags);
-- }
-+ {
-+ int flags;
-+
-+ if ((flags = fcntl(fd, F_GETFL, 0)) != -1)
-+ {
-+ flags |= O_NDELAY;
-+ fcntl(fd, F_SETFL, flags);
-+ }
-+ }
- #endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) */
-
-- while (connect(fd, (struct sockaddr *) & inaddr, sizeof inaddr) == JB_INVALID_SOCKET)
-- {
-+ while (connect(fd, (struct sockaddr *) addr, addrlen) == JB_INVALID_SOCKET)
-+ {
- #ifdef _WIN32
-- if (errno == WSAEINPROGRESS)
-+ if (errno == WSAEINPROGRESS)
- #elif __OS2__
-- if (sock_errno() == EINPROGRESS)
-+ if (sock_errno() == EINPROGRESS)
- #else /* ifndef _WIN32 */
-- if (errno == EINPROGRESS)
-+ if (errno == EINPROGRESS)
- #endif /* ndef _WIN32 || __OS2__ */
-- {
-- break;
-- }
-+ {
-+ break;
-+ }
-
- #ifdef __OS2__
-- if (sock_errno() != EINTR)
-+ if (sock_errno() != EINTR)
- #else
-- if (errno != EINTR)
-+ if (errno != EINTR)
- #endif /* __OS2__ */
-+ {
-+ close_socket(fd);
-+ return(JB_INVALID_SOCKET);
-+ }
-+ }
-+
-+#if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__)
- {
-- close_socket(fd);
-- return(JB_INVALID_SOCKET);
-+ int flags;
-+ if ((flags = fcntl(fd, F_GETFL, 0)) != -1)
-+ {
-+ flags &= ~O_NDELAY;
-+ fcntl(fd, F_SETFL, flags);
-+ }
- }
-- }
-+#endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) */
-
-+ {
-+ fd_set wfds;
-+ struct timeval tv[1];
-+
-+ /* wait for connection to complete */
-+ FD_ZERO(&wfds);
-+ FD_SET(fd, &wfds);
-+
-+ tv->tv_sec = 30;
-+ tv->tv_usec = 0;
-+
-+ /* MS Windows uses int, not SOCKET, for the 1st arg of select(). Wierd! */
-+ if (select((int)fd + 1, NULL, &wfds, NULL, tv) <= 0)
-+ {
-+ close_socket(fd);
-+ return(JB_INVALID_SOCKET);
-+ }
- #if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__)
-- if (flags != -1)
-- {
-- flags &= ~O_NDELAY;
-- fcntl(fd, F_SETFL, flags);
-- }
-+ else
-+ {
-+ int connect_result;
-+ socklen_t connect_result_len = sizeof connect_result;
-+
-+ if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &connect_result, &connect_result_len) != 0)
-+ {
-+ log_error(LOG_LEVEL_ERROR, "Could not determine whether connection to %s port %d was successful because %E. Assuming failure.",
-+ csp->http->host_ip_addr_str, portnum);
-+ close_socket(fd);
-+ return(JB_INVALID_SOCKET);
-+ }
-+ else if( connect_result != 0 )
-+ {
-+ log_error(LOG_LEVEL_CONNECT, "Connection to %s port %d failed because %s.",
-+ csp->http->host_ip_addr_str, portnum, strerror(connect_result));
-+ close_socket(fd);
-+ return(JB_INVALID_SOCKET);
-+ }
-+ }
- #endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) */
-+ }
-+ return(fd);
-+ }
-+}
-
-- /* wait for connection to complete */
-- FD_ZERO(&wfds);
-- FD_SET(fd, &wfds);
-+jb_socket connect_to(const char *host, const char *port, unsigned long portnum, int pf, struct client_state *csp)
-+{
-+ jb_socket fd = JB_INVALID_SOCKET;
-+ struct sockaddr_storage addr;
-+ addr_list *addrs, *addrs_to_try;
-
-- tv->tv_sec = 30;
-- tv->tv_usec = 0;
-+ addrs = resolve_hostname_to_ip(host,port,pf);
+ #ifdef FEATURE_ACL
+ struct access_control_addr dst[1];
+ #endif /* def FEATURE_ACL */
-- /* MS Windows uses int, not SOCKET, for the 1st arg of select(). Wierd! */
-- if (select((int)fd + 1, NULL, &wfds, NULL, tv) <= 0)
-+ if (is_nil_addr_list(addrs))
- {
-- close_socket(fd);
-- return(JB_INVALID_SOCKET);
-+ errno = EINVAL;
-+ return fd;
++#ifdef HAVE_GETADDRINFO
++ retval = snprintf(service, sizeof(service), "%d", portnum);
++ if (-1 == retval || sizeof(service) <= retval)
++ {
++ log_error(LOG_LEVEL_ERROR,
++ "Port number (%d) ASCII decimal representation doesn't fit into 6 bytes",
++ portnum);
++ csp->http->host_ip_addr_str = strdup("unknown");
++ return(JB_INVALID_SOCKET);
+ }
+
-+ for(addrs_to_try=addrs;
-+ !is_nil_addr_list(addrs_to_try);
-+ addrs_to_try = tail_addr_list(addrs_to_try))
-+ {
-+ size_t addrlen;
-+ memset((char *)&addr, 0, sizeof addr);
-+ cpy_head_addr_list(addrs_to_try, &addr,&addrlen);
-+ fd = connect_to_one_ip(&addr, addrlen, host, portnum, csp);
-+ if (fd != JB_INVALID_SOCKET)
-+ break;
- }
-- return(fd);
-
-+ if (fd == JB_INVALID_SOCKET)
++ memset((char *)&hints, 0, sizeof hints);
++ hints.ai_family = AF_UNSPEC;
++ hints.ai_socktype = SOCK_STREAM;
++ hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV; /* avoid service look-up */
++ if ((retval = getaddrinfo(host, service, &hints, &result)))
+ {
++ log_error(LOG_LEVEL_INFO,
++ "Can not resolve %s: %s", host, gai_strerror(retval));
+ csp->http->host_ip_addr_str = strdup("unknown");
++ return(JB_INVALID_SOCKET);
+ }
+
-+ destroy_addr_list(addrs);
-+ return fd;
- }
-
-
-@@ -571,55 +629,30 @@
++ for (rp = result; rp != NULL; rp = rp->ai_next)
++ {
++#else
+ memset((char *)&inaddr, 0, sizeof inaddr);
- /*********************************************************************
- *
-- * Function : bind_port
-+ * Function : bind_port_one_ip
- *
- * Description : Call socket, set socket options, and listen.
-- * Called by listen_loop to "boot up" our proxy address.
- *
- * Parameters :
-- * 1 : hostnam = TCP/IP address to bind/listen to
-- * 2 : portnum = port to listen on
-- * 3 : pfd = pointer used to return file descriptor.
-+ * 0 : addr = TCP/IP address and port to bind/listen to
-+ * 1 : fds = jb_socket_set where the new socket should go
- *
-- * Returns : if success, returns 0 and sets *pfd.
-+ * Returns : if success returns 0 and adds sockets to fds.
- * if failure, returns -3 if address is in use,
-- * -2 if address unresolvable,
-+ * -2 if memory error
- * -1 otherwise
- *********************************************************************/
--int bind_port(const char *hostnam, int portnum, jb_socket *pfd)
-+int bind_port_one_ip(struct sockaddr *addr, const socklen_t addr_len, jb_socket_set *fds)
- {
-- struct sockaddr_in inaddr;
- jb_socket fd;
-+ int flags;
- #ifndef _WIN32
- int one = 1;
- #endif /* ndef _WIN32 */
+ if ((addr = resolve_hostname_to_ip(host)) == INADDR_NONE)
+@@ -377,10 +410,15 @@
+ csp->http->host_ip_addr_str = strdup("unknown");
+ return(JB_INVALID_SOCKET);
+ }
++#endif /* def HAVE_GETADDRINFO */
-- *pfd = JB_INVALID_SOCKET;
--
-- memset((char *)&inaddr, '\0', sizeof inaddr);
--
-- inaddr.sin_family = AF_INET;
-- inaddr.sin_addr.s_addr = resolve_hostname_to_ip(hostnam);
--
-- if (inaddr.sin_addr.s_addr == INADDR_NONE)
-- {
-- return(-2);
-- }
--
--#ifndef _WIN32
-- if (sizeof(inaddr.sin_port) == sizeof(short))
--#endif /* ndef _WIN32 */
-- {
-- inaddr.sin_port = htons((unsigned short) portnum);
-- }
--#ifndef _WIN32
-- else
-- {
-- inaddr.sin_port = htonl((unsigned long) portnum);
-- }
--#endif /* ndef _WIN32 */
-+ fd = JB_INVALID_SOCKET;
+ #ifdef FEATURE_ACL
++#ifdef HAVE_GETADDRINFO
++ memcpy(&dst->addr, rp->ai_addr, sizeof(dst->addr));
++#else
+ dst->addr = ntohl(addr);
+ dst->port = portnum;
++#endif /* def HAVE_GETADDRINFO */
-- fd = socket(AF_INET, SOCK_STREAM, 0);
-+ fd = socket(addr->sa_family, SOCK_STREAM, 6);
+ if (block_acl(dst, csp))
+ {
+@@ -389,14 +427,43 @@
+ #else
+ errno = EPERM;
+ #endif
++#ifdef HAVE_GETADDRINFO
++ continue;
++#else
+ return(JB_INVALID_SOCKET);
++#endif /* def HAVE_GETADDRINFO */
+ }
+ #endif /* def FEATURE_ACL */
- #ifdef _WIN32
- if (fd == JB_INVALID_SOCKET)
-@@ -645,8 +678,17 @@
- */
- setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one));
- #endif /* ndef _WIN32 */
--
-- if (bind(fd, (struct sockaddr *)&inaddr, sizeof(inaddr)) < 0)
-+ /* As we are now listening on more than one socket,
-+ * this is important: The only way to be sure accept
-+ * won't block!!
-+ */
-+ if ((flags = fcntl(fd, F_GETFL, 0)) != -1)
++#ifdef HAVE_GETNAMEINFO
++ csp->http->host_ip_addr_str = malloc(NI_MAXHOST);
++ retval = getnameinfo(rp->ai_addr, rp->ai_addrlen,
++ csp->http->host_ip_addr_str, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
++ if (!csp->http->host_ip_addr_str || retval)
+ {
-+ flags |= O_NONBLOCK;
-+ fcntl(fd, F_SETFL, flags);
++ log_error(LOG_LEVEL_ERROR, "Can not save csp->http->host_ip_addr_str: %s",
++ (csp->http->host_ip_addr_str) ? gai_strerror(retval) :
++ "Insufficient memory");
++ freez(csp->http->host_ip_addr_str);
++ continue;
+ }
-+
-+ if (bind (fd, addr, addr_len) < 0)
++#else
+ inaddr.sin_addr.s_addr = addr;
+ inaddr.sin_family = AF_INET;
+ csp->http->host_ip_addr_str = strdup(inet_ntoa(inaddr.sin_addr));
++#endif /* def HAVE_GETNAMERINFO */
+
++#ifdef HAVE_GETADDRINFO
++#ifdef _WIN32
++ if ((fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) ==
++ JB_INVALID_SOCKET)
++#else
++ if ((fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) < 0)
++#endif
++ {
++ continue;
++ }
++#else
+ #ifndef _WIN32
+ if (sizeof(inaddr.sin_port) == sizeof(short))
+ #endif /* ndef _WIN32 */
+@@ -418,6 +485,7 @@
{
- #ifdef _WIN32
- errno = WSAGetLastError();
-@@ -665,7 +707,7 @@
- }
+ return(JB_INVALID_SOCKET);
+ }
++#endif /* HAVE_GETADDRINFO */
+
+ #ifdef TCP_NODELAY
+ { /* turn off TCP coalescence */
+@@ -434,7 +502,12 @@
}
+ #endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) */
-- while (listen(fd, 5) == -1)
-+ while (listen(fd, 25) == -1)
++ connect_failed = 0;
++#ifdef HAVE_GETADDRINFO
++ while (connect(fd, rp->ai_addr, rp->ai_addrlen) == JB_INVALID_SOCKET)
++#else
+ while (connect(fd, (struct sockaddr *) & inaddr, sizeof inaddr) == JB_INVALID_SOCKET)
++#endif /* HAVE_GETADDRINFO */
{
- if (errno != EINTR)
+ #ifdef _WIN32
+ if (errno == WSAEINPROGRESS)
+@@ -454,9 +527,18 @@
+ #endif /* __OS2__ */
{
-@@ -673,7 +715,11 @@
+ close_socket(fd);
+- return(JB_INVALID_SOCKET);
++ connect_failed = 1;
++ break;
}
}
-
-- *pfd = fd;
-+ if (jb_socket_set_add(fds,fd) != 0)
++ if (connect_failed)
+ {
-+ close_socket(fd);
-+ return -2;
++#ifdef HAVE_GETADDRINFO
++ continue;
++#else
++ return(JB_INVALID_SOCKET);
++#endif
+ }
- return 0;
- }
-@@ -681,6 +727,91 @@
-
- /*********************************************************************
- *
-+ * Function : bind_port
-+ *
-+ * Description : Call bind_port_one_ip on all addresses host resolves to
-+ * Called by listen_loop to "boot up" our proxy address.
-+ *
-+ * Parameters :
-+ * 0 : host = TCP/IP hostname to bind/listen to
-+ * 1 : port = port to listen to, as string
-+ * 2 : fds = socket set the sockets should be added to
-+ *
-+ * Returns : if success on at least one address resolving from hostnam,
-+ * returns 0 and adds sockets to fds.
-+ * if failure, returns non-zero
-+ *********************************************************************/
-+int bind_port(const char *host, const char *port, int pf, jb_socket_set *fds)
-+{
-+ int result;
-+ int failure = 1;
-+ struct sockaddr_storage addr;
-+ struct sockaddr * const addr_addr = (struct sockaddr *)&addr;
-+ addr_list *addrs, *addrs_to_try;
-+
-+ const char * const log_host = (host != NULL) ? host : "ADDR_ANY";
-+
-+ addrs = resolve_hostname_to_ip(host,port,pf);
-+
-+ if (is_nil_addr_list(addrs))
-+ log_error(LOG_LEVEL_ERROR, "can't bind to %s:%s: "
-+ "Name resolution didn't give any address",
-+ log_host, port);
-+
-+ log_error(LOG_LEVEL_INFO, "Binding to %s:%s...", log_host, port);
+ #if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__)
+ if (flags != -1)
+@@ -477,8 +559,32 @@
+ if (select((int)fd + 1, NULL, &wfds, NULL, tv) <= 0)
+ {
+ close_socket(fd);
++#ifdef HAVE_GETADDRINFO
++ continue;
++#else
+ return(JB_INVALID_SOCKET);
++#endif
+ }
++
++#ifdef HAVE_GETADDRINFO
++ break; /* for */
++ }
+
-+ for(addrs_to_try=addrs;
-+ !is_nil_addr_list(addrs_to_try);
-+ addrs_to_try = tail_addr_list(addrs_to_try))
++ freeaddrinfo(result);
++ if (!rp)
+ {
-+ char numeric_hostname[NI_MAXHOST];
-+ char numeric_port[NI_MAXSERV];
-+ size_t addrlen;
-+ memset((char *)addr_addr, 0, sizeof addr);
-+ cpy_head_addr_list(addrs_to_try, &addr, &addrlen);
-+ result = getnameinfo(addr_addr, addrlen, numeric_hostname, NI_MAXHOST,
-+ numeric_port, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV);
-+ if (result != 0)
-+ {
-+ log_error(LOG_LEVEL_ERROR, "bind: Could not get string address and port back from sockaddr because %E");
-+ strncpy(numeric_hostname,"unknown",NI_MAXHOST);
-+ strncpy(numeric_port,"unknown",NI_MAXSERV);
-+ }
-+ result = bind_port_one_ip(addr_addr, addrlen, fds);
-+ if( result == 0 )
-+ {
-+ failure = 0;
-+ log_error(LOG_LEVEL_INFO, "Successfully bound to %s:%s", numeric_hostname, numeric_port);
-+ }
-+ else
-+ {
-+ switch(result)
-+ {
-+ case -3 :
-+ log_error(LOG_LEVEL_ERROR, "can't bind to %s:%s (%s:%s): "
-+ "There may be another Privoxy or some other "
-+ "proxy running on port %s",
-+ log_host, port, numeric_hostname, numeric_port, numeric_port);
-+ break;
-+ case -2 :
-+ log_error(LOG_LEVEL_ERROR, "can't bind to %s:%s (%s:%s): "
-+ "Out of memory",
-+ log_host, port, numeric_hostname, numeric_port);
-+ break;
-+ default :
-+ log_error(LOG_LEVEL_ERROR, "can't bind to %s:%s: because %E",
-+ log_host, numeric_port);
-+ }
-+ }
++ log_error(LOG_LEVEL_INFO, "Could not connect to TCP/[%s]:%s", host, service);
++ return(JB_INVALID_SOCKET);
+ }
++ /* XXX: Current connection verification (EINPROGRESS && select() for
++ * writing) is not sufficient. E.g. on my Linux-2.6.27 with glibc-2.6
++ * select returns socket ready for writing, however subsequential write(2)
++ * fails with ENOCONNECT. Read Linux connect(2) man page about non-blocking
++ * sockets.
++ * Thus we can not log here the socket is connected. */
++ /*log_error(LOG_LEVEL_INFO, "Connected to TCP/[%s]:%s", host, service);*/
++#endif
+
-+ destroy_addr_list(addrs);
-+ return failure;
-+}
-+
-+
-+/*********************************************************************
-+ *
- * Function : accept_connection
- *
- * Description : Accepts a connection on a socket. Socket must have
-@@ -697,8 +828,7 @@
+ return(fd);
+
+ }
+@@ -677,7 +783,16 @@
*********************************************************************/
- int accept_connection(struct client_state * csp, jb_socket fd)
+ int bind_port(const char *hostnam, int portnum, jb_socket *pfd)
{
-- struct sockaddr_in client, server;
-- struct hostent *host = NULL;
-+ struct sockaddr_storage client, server;
- jb_socket afd;
- #if defined(_WIN32) || defined(__OS2__) || defined(__APPLE_CC__) || defined(AMIGA)
- /* Wierdness - fix a warning. */
-@@ -706,15 +836,7 @@
- #else
- socklen_t c_length, s_length;
- #endif
--#if defined(HAVE_GETHOSTBYADDR_R_8_ARGS) || defined(HAVE_GETHOSTBYADDR_R_7_ARGS) || defined(HAVE_GETHOSTBYADDR_R_5_ARGS)
-- struct hostent result;
--#if defined(HAVE_GETHOSTBYADDR_R_5_ARGS)
-- struct hostent_data hdata;
--#else
-- char hbuf[HOSTENT_BUFFER_SIZE];
-- int thd_err;
--#endif /* def HAVE_GETHOSTBYADDR_R_5_ARGS */
--#endif /* def HAVE_GETHOSTBYADDR_R_(8|7|5)_ARGS */
-+ int flags;
++#ifdef HAVE_GETADDRINFO
++ struct addrinfo hints;
++ struct addrinfo *result, *rp;
++ /* TODO: portnum shuld be string to allow symbolic service names in
++ * configuration and to avoid following int2string */
++ char servnam[6];
++ int retval;
++#else
+ struct sockaddr_in inaddr;
++#endif /* def HAVE_GETADDRINFO */
+ jb_socket fd;
+ #ifndef _WIN32
+ int one = 1;
+@@ -685,6 +800,32 @@
- c_length = s_length = sizeof(client);
+ *pfd = JB_INVALID_SOCKET;
-@@ -734,6 +856,12 @@
- return 0;
- }
- #endif
-+ /* If we inherited O_NONBLOCK from the listening fd, unset it */
-+ if ((flags = fcntl(fd, F_GETFL, 0)) != -1)
++#ifdef HAVE_GETADDRINFO
++ retval = snprintf(servnam, sizeof(servnam), "%d", portnum);
++ if (-1 == retval || sizeof(servnam) <= retval)
+ {
-+ flags &= ~O_NONBLOCK;
-+ fcntl(fd, F_SETFL, flags);
++ log_error(LOG_LEVEL_ERROR,
++ "Port number (%d) ASCII decimal representation doesn't fit into 6 bytes",
++ portnum);
++ return -1;
+ }
-
- /*
- * Determine the IP-Adress that the client used to reach us
-@@ -741,49 +869,50 @@
- */
- if (!getsockname(afd, (struct sockaddr *) &server, &s_length))
- {
-- csp->my_ip_addr_str = strdup(inet_ntoa(server.sin_addr));
--#if defined(HAVE_GETHOSTBYADDR_R_8_ARGS)
-- gethostbyaddr_r((const char *)&server.sin_addr,
-- sizeof(server.sin_addr), AF_INET,
-- &result, hbuf, HOSTENT_BUFFER_SIZE,
-- &host, &thd_err);
--#elif defined(HAVE_GETHOSTBYADDR_R_7_ARGS)
-- host = gethostbyaddr_r((const char *)&server.sin_addr,
-- sizeof(server.sin_addr), AF_INET,
-- &result, hbuf, HOSTENT_BUFFER_SIZE, &thd_err);
--#elif defined(HAVE_GETHOSTBYADDR_R_5_ARGS)
-- if (0 == gethostbyaddr_r((const char *)&server.sin_addr,
-- sizeof(server.sin_addr), AF_INET,
-- &result, &hdata))
-+ char hostname[NI_MAXHOST];
-+ char port[NI_MAXSERV];
+
-+ if (getnameinfo((struct sockaddr *)&server, s_length, hostname, NI_MAXHOST,
-+ port, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV) != 0)
- {
-- host = &result;
-+ log_error(LOG_LEVEL_ERROR, "accept: Could not get string address and port back from server sockaddr because %E");
-+ strncpy(hostname,"unknown IP",NI_MAXHOST);
-+ strncpy(port,"unknown port",NI_MAXSERV);
- }
-- else
-+ csp->my_ip_addr_str = strdup(hostname);
-+ csp->my_port_str = strdup(port);
++ memset(&hints, 0, sizeof(struct addrinfo));
++ hints.ai_family=AF_UNSPEC;
++ hints.ai_socktype=SOCK_STREAM;
++ hints.ai_flags=AI_PASSIVE|AI_ADDRCONFIG;
++ hints.ai_protocol=0; /* Realy any stream protocol or TCP only */
++ hints.ai_canonname=NULL;
++ hints.ai_addr=NULL;
++ hints.ai_next=NULL;
+
-+ if (getnameinfo((struct sockaddr *)&server, s_length, hostname, NI_MAXHOST, NULL, 0, NI_NAMEREQD) != 0)
- {
-- host = NULL;
-+ log_error(LOG_LEVEL_ERROR, "accept: Could not get my own hostname because %E");
-+ strncpy(hostname,"unknown host",NI_MAXHOST);
- }
--#elif FEATURE_PTHREAD
-- pthread_mutex_lock(&gethostbyaddr_mutex);
-- host = gethostbyaddr((const char *)&server.sin_addr,
-- sizeof(server.sin_addr), AF_INET);
-- pthread_mutex_unlock(&gethostbyaddr_mutex);
--#else
-- host = gethostbyaddr((const char *)&server.sin_addr,
-- sizeof(server.sin_addr), AF_INET);
--#endif
-- if (host == NULL)
-+ csp->my_hostname = strdup(hostname);
-+ }
-+ else
++ if ((retval = getaddrinfo(hostnam, servnam, &hints, &result)))
+ {
-+ log_error(LOG_LEVEL_ERROR, "accept: Could not get sockaddr from socket fd because %E");
++ log_error(LOG_LEVEL_ERROR,
++ "Can not resolve %s: %s", hostnam, gai_strerror(retval));
++ return -2;
+ }
-+
-+ csp->cfd = afd;
++#else
+ memset((char *)&inaddr, '\0', sizeof inaddr);
+
+ inaddr.sin_family = AF_INET;
+@@ -707,8 +848,15 @@
+ inaddr.sin_port = htonl((unsigned long) portnum);
+ }
+ #endif /* ndef _WIN32 */
++#endif /* def HAVE_GETADDRINFO */
+
++#ifdef HAVE_GETADDRINFO
++ for (rp = result; rp != NULL; rp = rp->ai_next)
+ {
-+ char hostname[NI_MAXHOST];
-+
-+ if (getnameinfo((struct sockaddr *)&client, c_length, hostname, NI_MAXHOST, NULL, 0, NI_NUMERICHOST) != 0)
++ fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
++#else
+ fd = socket(AF_INET, SOCK_STREAM, 0);
++#endif /* def HAVE_GETADDRINFO */
+
+ #ifdef _WIN32
+ if (fd == JB_INVALID_SOCKET)
+@@ -716,7 +864,11 @@
+ if (fd < 0)
+ #endif
+ {
++#ifdef HAVE_GETADDRINFO
++ continue;
++#else
+ return(-1);
++#endif
+ }
+
+ #ifndef _WIN32
+@@ -735,7 +887,11 @@
+ setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one));
+ #endif /* ndef _WIN32 */
+
++#ifdef HAVE_GETADDRINFO
++ if (bind(fd, rp->ai_addr, rp->ai_addrlen) < 0)
++#else
+ if (bind(fd, (struct sockaddr *)&inaddr, sizeof(inaddr)) < 0)
++#endif
+ {
+ #ifdef _WIN32
+ errno = WSAGetLastError();
+@@ -744,15 +900,36 @@
+ if (errno == EADDRINUSE)
+ #endif
{
-- log_error(LOG_LEVEL_ERROR, "Unable to get my own hostname: %E\n");
-+ log_error(LOG_LEVEL_ERROR, "accept: Could not get client IP address string because %E");
-+ strncpy(hostname,"unknown IP",NI_MAXHOST);
++#ifdef HAVE_GETADDRINFO
++ freeaddrinfo(result);
++#endif
+ close_socket(fd);
+ return(-3);
}
-- else
-+ csp->my_ip_addr_str = strdup(hostname);
-+
-+ if (getnameinfo((struct sockaddr *)&server, s_length, hostname, NI_MAXHOST, NULL, 0, 0) != 0)
+ else
{
-- csp->my_hostname = strdup(host->h_name);
-+ log_error(LOG_LEVEL_ERROR, "accept: Could not get my own hostname because %E");
-+ strncpy(hostname,"unknown host",NI_MAXHOST);
+ close_socket(fd);
++#ifndef HAVE_GETADDRINFO
+ return(-1);
}
-+ csp->ip_addr_str = strdup(hostname);
- }
--
-- csp->cfd = afd;
-- csp->ip_addr_str = strdup(inet_ntoa(client.sin_addr));
-- csp->ip_addr_long = ntohl(client.sin_addr.s_addr);
-+ csp->ip_addr_addr = client;
-
- return 1;
-
-@@ -794,108 +923,48 @@
- *
- * Function : resolve_hostname_to_ip
- *
-- * Description : Resolve a hostname to an internet tcp/ip address.
-- * NULL or an empty string resolve to INADDR_ANY.
-+ * Description : Resolve a hostname to a list of internet tcp/ip addresses.
- *
- * Parameters :
-- * 1 : host = hostname to resolve
-+ * 0 : host = hostname to resolve
-+ * 1 : result = where to store the result
-+ * 2 : pf = preferred address family. PF_UNSPEC for no preference (recommended).
- *
-- * Returns : INADDR_NONE => failure, INADDR_ANY or tcp/ip address if succesful.
-+ * Returns : A (possibly empty) list of adresses
- *
- *********************************************************************/
--unsigned long resolve_hostname_to_ip(const char *host)
--{
-- struct sockaddr_in inaddr;
-- struct hostent *hostp;
-+addr_list *resolve_hostname_to_ip(const char *host, const char *port, int pf)
-+ {
-+ /* TODO
-+ * Do all supported platforms have "getaddrinfo"?
-+ */
-+
-+ struct addrinfo hints, *res0;
-+ int result;
- unsigned int dns_retries = 0;
--#if defined(HAVE_GETHOSTBYNAME_R_6_ARGS) || defined(HAVE_GETHOSTBYNAME_R_5_ARGS) || defined(HAVE_GETHOSTBYNAME_R_3_ARGS)
-- struct hostent result;
--#if defined(HAVE_GETHOSTBYNAME_R_6_ARGS) || defined(HAVE_GETHOSTBYNAME_R_5_ARGS)
-- char hbuf[HOSTENT_BUFFER_SIZE];
-- int thd_err;
--#else /* defined(HAVE_GETHOSTBYNAME_R_3_ARGS) */
-- struct hostent_data hdata;
--#endif /* def HAVE_GETHOSTBYNAME_R_(6|5)_ARGS */
--#endif /* def HAVE_GETHOSTBYNAME_R_(6|5|3)_ARGS */
-
-- if ((host == NULL) || (*host == '\0'))
-- {
-- return(INADDR_ANY);
-- }
--
-- memset((char *) &inaddr, 0, sizeof inaddr);
--
-- if ((inaddr.sin_addr.s_addr = inet_addr(host)) == -1)
-- {
--#if defined(HAVE_GETHOSTBYNAME_R_6_ARGS)
-- while ( gethostbyname_r(host, &result, hbuf,
-- HOSTENT_BUFFER_SIZE, &hostp, &thd_err)
-- && (thd_err == TRY_AGAIN) && (dns_retries++ < 10) )
-- {
-- log_error(LOG_LEVEL_ERROR, "Timeout #%u while trying to resolve %s. Trying again.",
-- dns_retries, host);
-- }
--#elif defined(HAVE_GETHOSTBYNAME_R_5_ARGS)
-- hostp = gethostbyname_r(host, &result, hbuf,
-- HOSTENT_BUFFER_SIZE, &thd_err);
--#elif defined(HAVE_GETHOSTBYNAME_R_3_ARGS)
-- if (0 == gethostbyname_r(host, &result, &hdata))
-- {
-- hostp = &result;
-- }
-- else
-- {
-- hostp = NULL;
-- }
--#elif FEATURE_PTHREAD
-- pthread_mutex_lock(&gethostbyname_mutex);
-- while ( NULL == (hostp = gethostbyname(host))
-- && (h_errno == TRY_AGAIN) && (dns_retries++ < 10) )
-- {
-- log_error(LOG_LEVEL_ERROR, "Timeout #%u while trying to resolve %s. Trying again.",
-- dns_retries, host);
-- }
-- pthread_mutex_unlock(&gethostbyname_mutex);
--#else
-- while ( NULL == (hostp = gethostbyname(host))
-- && (h_errno == TRY_AGAIN) && (dns_retries++ < 10) )
-- {
-- log_error(LOG_LEVEL_ERROR, "Timeout #%u while trying to resolve %s. Trying again.",
-- dns_retries, host);
-- }
--#endif /* def HAVE_GETHOSTBYNAME_R_(6|5|3)_ARGS */
-- /*
-- * On Mac OSX, if a domain exists but doesn't have a type A
-- * record associated with it, the h_addr member of the struct
-- * hostent returned by gethostbyname is NULL, even if h_length
-- * is 4. Therefore the second test below.
-- */
-- if (hostp == NULL || hostp->h_addr == NULL)
-- {
-- errno = EINVAL;
-- log_error(LOG_LEVEL_ERROR, "could not resolve hostname %s", host);
-- return(INADDR_NONE);
-- }
-- if (hostp->h_addrtype != AF_INET)
-- {
--#ifdef _WIN32
-- errno = WSAEPROTOTYPE;
--#else
-- errno = EPROTOTYPE;
--#endif
-- log_error(LOG_LEVEL_ERROR, "hostname %s resolves to unknown address type.", host);
-- return(INADDR_NONE);
-- }
-- memcpy(
-- (char *) &inaddr.sin_addr,
-- (char *) hostp->h_addr,
-- sizeof(inaddr.sin_addr)
-- );
-+ memset(&hints, 0, sizeof(hints));
-+ hints.ai_family = pf;
-+ hints.ai_socktype = SOCK_STREAM;
-+
-+ while ((result = getaddrinfo(host, port, &hints, &res0))
-+ && (result == EAI_AGAIN) && (dns_retries++ < 10)) {
-+ log_error(LOG_LEVEL_ERROR, "Timeout #%u while trying to resolve %s. Trying again.",
-+ dns_retries, host);
}
-- return(inaddr.sin_addr.s_addr);
--
--}
--
-+ if ( result != 0 )
-+ {
-+ log_error(LOG_LEVEL_ERROR, "could not resolve hostname %s because %s", host,gai_strerror(result));
-+ if (result == EAI_SYSTEM)
-+ log_error(LOG_LEVEL_ERROR, "The system error is %E");
-+ return NULL;
-+ }
++#else
++ }
++ }
+ else
-+ if (res0==0)
-+ log_error(LOG_LEVEL_ERROR, "Problem in resolving hostname %s: succeeded, but no information returned", host);
-+
-+ return res0;
-+ }
-
- /*
- Local Variables:
-diff -urNad privoxy~/jbsockets.h privoxy/jbsockets.h
---- privoxy~/jbsockets.h
-+++ privoxy/jbsockets.h
-@@ -13,6 +13,9 @@
- * Copyright : Written by and Copyright (C) 2001 the SourceForge
- * Privoxy team. http://www.privoxy.org/
- *
-+ * Modified by Lionel Elie Mamane <lionel@mamane.lu>
-+ * for IPv6 support on 8 December 2002, 24 January 2003.
-+ *
- * Based on the Internet Junkbuster originally written
- * by and Copyright (C) 1997 Anonymous Coders and
- * Junkbusters Corporation. http://www.junkbusters.com
-@@ -104,9 +107,11 @@
- extern "C" {
- #endif
-
-+#include "addrlist.h"
++ /* bind() succeeded, escape from for-loop */
++ /* TODO: Support multiple listening sockets (e.g. localhost resolves to
++ * AF_INET and AF_INET6, but only fist address is used */
++ break;
++ }
+
- struct client_state;
-
--extern jb_socket connect_to(const char *host, int portnum, struct client_state *csp);
-+extern jb_socket connect_to(const char *host, const char *port, unsigned long portnum, int pf, struct client_state *csp);
- #ifdef AMIGA
- extern int write_socket(jb_socket fd, const char *buf, ssize_t n);
- #else
-@@ -115,10 +120,10 @@
- extern int read_socket(jb_socket fd, char *buf, int n);
- extern void close_socket(jb_socket fd);
-
--extern int bind_port(const char *hostnam, int portnum, jb_socket *pfd);
-+extern int bind_port(const char *host, const char *port, int pf, jb_socket_set *fds);
- extern int accept_connection(struct client_state * csp, jb_socket fd);
-
--extern unsigned long resolve_hostname_to_ip(const char *host);
-+extern addr_list *resolve_hostname_to_ip(const char *host, const char *port, int pf);
-
- /* Revision control strings from this header and associated .c file */
- extern const char jbsockets_rcs[];
-diff -urNad privoxy~/jcc.c privoxy/jcc.c
---- privoxy~/jcc.c
-+++ privoxy/jcc.c
-@@ -767,6 +767,7 @@
- #include "cgi.h"
- #include "loadcfg.h"
- #include "urlmatch.h"
-+#include "jb_socket_set.h"
++ freeaddrinfo(result);
++ if (rp == NULL)
++ {
++ /* All bind()s failed */
++ return(-1);
++ }
++#endif /* ndef HAVE_GETADDRINFO */
- const char jcc_h_rcs[] = JCC_H_VERSION;
- const char project_h_rcs[] = PROJECT_H_VERSION;
-@@ -2338,61 +2339,78 @@
- * Returns : Port that was opened.
- *
+ while (listen(fd, MAX_LISTEN_BACKLOG) == -1)
+ {
+@@ -792,14 +969,20 @@
*********************************************************************/
--static jb_socket bind_port_helper(struct configuration_spec * config)
-+static void bind_port_helper(struct configuration_spec * config, jb_socket_set *bfds)
+ void get_host_information(jb_socket afd, char **ip_address, char **hostname)
{
- int result;
-- jb_socket bfd;
-+ struct bind_spec *bs;
-+ unsigned int bs_index;
-+ int never_bound;
++#ifdef HAVE_GETNAMEINFO
++ struct sockaddr_storage server;
++ int retval;
++#else
+ struct sockaddr_in server;
+ struct hostent *host = NULL;
++#endif /* HAVE_GETNAMEINFO */
+ #if defined(_WIN32) || defined(__OS2__) || defined(__APPLE_CC__) || defined(AMIGA)
+ /* according to accept_connection() this fixes a warning. */
+- int s_length;
++ int s_length, s_length_provided;
+ #else
+- socklen_t s_length;
++ socklen_t s_length, s_length_provided;
+ #endif
++#ifndef HAVE_GETNAMEINFO
+ #if defined(HAVE_GETHOSTBYADDR_R_8_ARGS) || defined(HAVE_GETHOSTBYADDR_R_7_ARGS) || defined(HAVE_GETHOSTBYADDR_R_5_ARGS)
+ struct hostent result;
+ #if defined(HAVE_GETHOSTBYADDR_R_5_ARGS)
+@@ -809,7 +992,8 @@
+ int thd_err;
+ #endif /* def HAVE_GETHOSTBYADDR_R_5_ARGS */
+ #endif /* def HAVE_GETHOSTBYADDR_R_(8|7|5)_ARGS */
+- s_length = sizeof(server);
++#endif /* ifndef HAVE_GETNAMEINFO */
++ s_length = s_length_provided = sizeof(server);
+
+ if (NULL != hostname)
+ {
+@@ -819,8 +1003,23 @@
-- if ( (config->haddr != NULL)
-- && (config->haddr[0] == '1')
-- && (config->haddr[1] == '2')
-- && (config->haddr[2] == '7')
-- && (config->haddr[3] == '.') )
-- {
-- log_error(LOG_LEVEL_INFO, "Listening on port %d for local connections only",
-- config->hport);
-- }
-- else if (config->haddr == NULL)
-- {
-- log_error(LOG_LEVEL_INFO, "Listening on port %d on all IP addresses",
-- config->hport);
-- }
-- else
-+ never_bound = 1;
-+ for (bs_index = 0; bs_index < config->hspecs_occupied;++bs_index)
+ if (!getsockname(afd, (struct sockaddr *) &server, &s_length))
{
-- log_error(LOG_LEVEL_INFO, "Listening on port %d on IP address %s",
-- config->hport, config->haddr);
-- }
-+ bs = &config->hspecs[bs_index];
-+
-+ /* This check misses about a trillion zillion different manners to describe
-+ the local interface in IPv6. Who cares? */
-+ if ( (bs->haddr != NULL)
-+ && (((bs->haddr[0] == '1')
-+ && (bs->haddr[1] == '2')
-+ && (bs->haddr[2] == '7')
-+ && (bs->haddr[3] == '.'))
-+ || ((bs->haddr[0] == ':')
-+ && (bs->haddr[1] == ':')
-+ && (bs->haddr[2] == '1'))))
++ if (s_length > s_length_provided)
+ {
-+ log_error(LOG_LEVEL_INFO, "Listening on port %s for local connections only",
-+ bs->hport);
++ log_error(LOG_LEVEL_ERROR, "getsockname() truncated server address");
++ return;
+ }
-+ else if (bs->haddr == NULL || bs->haddr[0]=='\0')
-+ {
-+ log_error(LOG_LEVEL_INFO, "Listening on port %s on all IP addresses",
-+ bs->hport);
++#ifdef HAVE_GETNAMEINFO
++ *ip_address = malloc(NI_MAXHOST);
++ if ((retval = getnameinfo((struct sockaddr *) &server, s_length,
++ *ip_address, NI_MAXHOST, NULL, 0, NI_NUMERICHOST))) {
++ log_error(LOG_LEVEL_ERROR, "Unable to print my own IP address: %s",
++ gai_strerror(retval));
++ freez(*ip_address);
++ return;
+ }
-+ else
-+ {
-+ log_error(LOG_LEVEL_INFO, "Listening on port %s on IP address %s",
-+ bs->hport, bs->haddr);
++#else
+ *ip_address = strdup(inet_ntoa(server.sin_addr));
+-
++#endif /* HAVE_GETNAMEINFO */
+ if (NULL == hostname)
+ {
+ /*
+@@ -829,6 +1028,16 @@
+ */
+ return;
+ }
++
++#ifdef HAVE_GETNAMEINFO
++ *hostname = malloc(NI_MAXHOST);
++ if ((retval = getnameinfo((struct sockaddr *) &server, s_length,
++ *hostname, NI_MAXHOST, NULL, 0, NI_NAMEREQD))) {
++ log_error(LOG_LEVEL_ERROR, "Unable to resolve my own IP address: %s",
++ gai_strerror(retval));
++ freez(*hostname);
+ }
-
-- result = bind_port(config->haddr, config->hport, &bfd);
-+ result = bind_port(bs->haddr, bs->hport, bs->pf, bfds);
-
-- if (result < 0)
-- {
-- switch(result)
-+ if (result != 0)
++#else
+ #if defined(HAVE_GETHOSTBYADDR_R_8_ARGS)
+ gethostbyaddr_r((const char *)&server.sin_addr,
+ sizeof(server.sin_addr), AF_INET,
+@@ -866,6 +1075,7 @@
{
-+ switch(result)
-+ {
- case -3 :
-- log_error(LOG_LEVEL_FATAL, "can't bind to %s:%d: "
-+ log_error(LOG_LEVEL_ERROR, "can't bind to %s:%s: "
- "There may be another Privoxy or some other "
-- "proxy running on port %d",
-- (NULL != config->haddr) ? config->haddr : "INADDR_ANY",
-- config->hport, config->hport);
-+ "proxy running on port %s",
-+ (NULL != bs->haddr) ? bs->haddr : "INADDR_ANY",
-+ bs->hport, bs->hport);
-+ break;
-
- case -2 :
-- log_error(LOG_LEVEL_FATAL, "can't bind to %s:%d: "
-+ log_error(LOG_LEVEL_ERROR, "can't bind to %s:%s: "
- "The hostname is not resolvable",
-- (NULL != config->haddr) ? config->haddr : "INADDR_ANY", config->hport);
-+ (NULL != bs->haddr) ? bs->haddr : "INADDR_ANY", bs->hport);
-+ break;
-
- default :
-- log_error(LOG_LEVEL_FATAL, "can't bind to %s:%d: because %E",
-- (NULL != config->haddr) ? config->haddr : "INADDR_ANY", config->hport);
-+ log_error(LOG_LEVEL_ERROR, "can't bind to %s:%s: because %E",
-+ (NULL != bs->haddr) ? bs->haddr : "INADDR_ANY", bs->hport);
-+ }
+ *hostname = strdup(host->h_name);
}
-+ else
-+ never_bound = 0;
-+ }
-
-+ if(never_bound)
-+ {
-+ log_error(LOG_LEVEL_FATAL, "Couldn't bind at all - bailing out");
- /* shouldn't get here */
-- return JB_INVALID_SOCKET;
++#endif /* else def HAVE_GETNAMEINFO */
}
--
- config->need_bind = 0;
--
-- return bfd;
- }
-
-@@ -2421,12 +2439,18 @@
- static void listen_loop(void)
+ return;
+@@ -890,7 +1100,13 @@
+ *********************************************************************/
+ int accept_connection(struct client_state * csp, jb_socket fd)
{
- struct client_state *csp = NULL;
-- jb_socket bfd;
-+ jb_socket_set bfds;
-+ fd_set bfds_fs;
-+ jb_socket_set_iterate_state bfds_iterate_state;
-+ jb_socket bfd_current;
- struct configuration_spec * config;
-
-+ init_jb_socket_set(&bfds);
-+
- config = load_config();
-
-- bfd = bind_port_helper(config);
-+ bind_port_helper(config,&bfds);
-+ bfd_current=JB_INVALID_SOCKET;
-
- #ifdef FEATURE_GRACEFUL_TERMINATION
- while (!g_terminate)
-@@ -2500,14 +2524,55 @@
- * that this will hurt people's feelings.
- */
-
-- close_socket(bfd);
-+ jb_socket_set_iterate_state s;
-+ jb_socket bfd;
-+ s=jb_socket_set_iteration_begin(&bfds);
-+ for(bfd=jb_socket_set_iteration_next(&s);bfd!=JB_INVALID_SOCKET;bfd=jb_socket_set_iteration_next(&s))
-+ {
-+ close_socket(bfd);
-+ }
-+ destroy_jb_socket_set(&bfds);
-+ bind_port_helper(config,&bfds);
-+ /* We have a new set of fd's to accept. Restart iteration over bfds. */
-+ bfd_current = JB_INVALID_SOCKET;
-+ }
-
-- bfd = bind_port_helper(config);
-+ /* Here: select call on listening sockets: bfd=sockets */
-+ if (bfd_current == JB_INVALID_SOCKET)
-+ {
-+ jb_socket max;
-+ log_error(LOG_LEVEL_CONNECT, "select connections ... ");
-+ bfds_iterate_state=jb_socket_set_iteration_begin(&bfds);
-+ FD_ZERO(&bfds_fs);
-+ max = 0;
-+ for(bfd_current=jb_socket_set_iteration_next(&bfds_iterate_state);
-+ bfd_current!=JB_INVALID_SOCKET;
-+ bfd_current=jb_socket_set_iteration_next(&bfds_iterate_state))
-+ {
-+ FD_SET(bfd_current,&bfds_fs);
-+ if (bfd_current >= max)
-+ max = bfd_current + 1;
-+ }
-+ if(!select(max,&bfds_fs,NULL,NULL,NULL))
-+ {
-+ log_error(LOG_LEVEL_CONNECT, "select failed: %E");
-+ bfd_current=JB_INVALID_SOCKET;
-+ continue;
-+ }
-+ log_error(LOG_LEVEL_CONNECT, "OK");
-+ bfds_iterate_state=jb_socket_set_iteration_begin(&bfds);
-+ bfd_current=jb_socket_set_iteration_next(&bfds_iterate_state);
-+ }
-+ if (!FD_ISSET(bfd_current,&bfds_fs))
-+ {
-+ bfd_current=jb_socket_set_iteration_next(&bfds_iterate_state);
-+ freez(csp);
-+ continue;
- }
++#ifdef HAVE_GETNAMEINFO
++ /* XXX: client is stored directly into csp->tcp_addr */
++#define client (csp->tcp_addr)
++ int retval;
++#else
+ struct sockaddr_in client;
++#endif
+ jb_socket afd;
+ #if defined(_WIN32) || defined(__OS2__) || defined(__APPLE_CC__) || defined(AMIGA)
+ /* Wierdness - fix a warning. */
+@@ -919,8 +1135,21 @@
+ #endif
- log_error(LOG_LEVEL_CONNECT, "accept connection ... ");
+ csp->cfd = afd;
++#ifdef HAVE_GETNAMEINFO
++ csp->ip_addr_str = malloc(NI_MAXHOST);
++ retval = getnameinfo((struct sockaddr *) &client, c_length,
++ csp->ip_addr_str, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
++ if (!csp->ip_addr_str || retval)
++ {
++ log_error(LOG_LEVEL_ERROR, "Can not save csp->ip_addr_str: %s",
++ (csp->ip_addr_str) ? gai_strerror(retval) : "Insuffcient memory");
++ freez(csp->ip_addr_str);
++ }
++#undef client
++#else
+ csp->ip_addr_str = strdup(inet_ntoa(client.sin_addr));
+ csp->ip_addr_long = ntohl(client.sin_addr.s_addr);
++#endif /* def HAVE_GETNAMEINFO */
-- if (!accept_connection(csp, bfd))
-+ if (!accept_connection(csp, bfd_current))
- {
- log_error(LOG_LEVEL_CONNECT, "accept failed: %E");
+ return 1;
-@@ -2525,6 +2590,8 @@
- log_error(LOG_LEVEL_CONNECT, "OK");
- }
+@@ -1051,4 +1280,6 @@
+ Local Variables:
+ tab-width: 3
+ end:
++
++ vim:softtabstop=3 shiftwidth=3
+ */
+diff -urNad privoxy~/jcc.c privoxy/jcc.c
+--- privoxy~/jcc.c
++++ privoxy/jcc.c
+@@ -2710,7 +2710,7 @@
-+ bfd_current=jb_socket_set_iteration_next(&bfds_iterate_state);
+ if (fwd->forward_host)
+ {
+- log_error(LOG_LEVEL_CONNECT, "via %s:%d to: %s",
++ log_error(LOG_LEVEL_CONNECT, "via [%s]:%d to: %s",
+ fwd->forward_host, fwd->forward_port, http->hostport);
+ }
+ else
+@@ -4483,4 +4483,6 @@
+ Local Variables:
+ tab-width: 3
+ end:
+
- #ifdef FEATURE_TOGGLE
- if (global_toggle_state)
- {
++ vim:softtabstop=3 shiftwidth=3
+ */
diff -urNad privoxy~/loadcfg.c privoxy/loadcfg.c
--- privoxy~/loadcfg.c
+++ privoxy/loadcfg.c
-@@ -11,6 +11,9 @@
- * Copyright : Written by and Copyright (C) 2001 the SourceForge
- * Privoxy team. http://www.privoxy.org/
- *
-+ * Modified by Lionel Elie Mamane <lionel@mamane.lu>
-+ * for IPv6 support on 8 December 2002, 24 January 2003.
-+ *
- * Based on the Internet Junkbuster originally written
- * by and Copyright (C) 1997 Anonymous Coders and
- * Junkbusters Corporation. http://www.junkbusters.com
-@@ -408,6 +411,7 @@
- #include "encode.h"
- #include "urlmatch.h"
- #include "cgi.h"
-+#include "parsers.h"
-
- const char loadcfg_h_rcs[] = LOADCFG_H_VERSION;
-
-@@ -527,8 +531,8 @@
- struct forward_spec * next_fwd = cur_fwd->next;
- free_url_spec(cur_fwd->url);
-
-- freez(cur_fwd->gateway_host);
-- freez(cur_fwd->forward_host);
-+ freez(cur_fwd->gateway_malloc);
-+ freez(cur_fwd->forward_malloc);
- free(cur_fwd);
- cur_fwd = next_fwd;
- }
-@@ -545,7 +549,16 @@
- freez(config->confdir);
- freez(config->logdir);
-
-- freez(config->haddr);
-+ if(config -> hspecs != NULL)
-+ {
-+ int i;
-+ for (i=0; i < config->hspecs_occupied; ++i)
-+ {
-+ freez(config->hspecs[i].haddr);
-+ freez(config->hspecs[i].hport);
-+ }
-+ }
-+ freez(config->hspecs);
- freez(config->logfile);
-
- for (i = 0; i < MAX_AF_FILES; i++)
-@@ -612,6 +625,28 @@
- * Returns : The configuration_spec, or NULL on error.
- *
- *********************************************************************/
-+static void fail_load_config_memory(struct file_list *fs, struct configuration_spec *config)
-+{
-+ freez(fs->filename);
-+ freez(fs);
-+ if (config != NULL)
-+ {
-+ if(config -> hspecs != NULL)
-+ {
-+ int i;
-+ for (i=0; i < config->hspecs_occupied; ++i)
-+ {
-+ freez(config->hspecs[i].haddr);
-+ freez(config->hspecs[i].hport);
-+ }
-+ }
-+ freez(config -> hspecs);
-+ }
-+ freez(config);
-+ log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
-+ /* Never get here - LOG_LEVEL_FATAL causes program exit */
-+}
-+
- struct configuration_spec * load_config(void)
- {
- char buf[BUFFER_SIZE];
-@@ -643,12 +678,7 @@
- fs->f = config = (struct configuration_spec *)zalloc(sizeof(*config));
-
- if (config==NULL)
-- {
-- freez(fs->filename);
-- freez(fs);
-- log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
-- /* Never get here - LOG_LEVEL_FATAL causes program exit */
-- }
-+ fail_load_config_memory(fs,config);
-
- /*
- * This is backwards from how it's usually done.
-@@ -665,7 +695,7 @@
+@@ -835,7 +835,6 @@
* Set to defaults
*/
config->multi_threaded = 1;
- config->hport = HADDR_PORT;
-+ config->hspecs = NULL;
config->buffer_limit = 4096 * 1024;
config->usermanual = strdup(USER_MANUAL_URL);
config->proxy_args = strdup("");
-@@ -684,9 +714,6 @@
- char cmd[BUFFER_SIZE];
- char arg[BUFFER_SIZE];
- char tmp[BUFFER_SIZE];
--#ifdef FEATURE_ACL
-- struct access_control_list *cur_acl;
--#endif /* def FEATURE_ACL */
- struct forward_spec *cur_fwd;
- int vec_count;
- char *vec[3];
-@@ -797,74 +824,23 @@
- * *************************************************************************/
- #ifdef FEATURE_ACL
- case hash_deny_access:
-- vec_count = ssplit(arg, " \t", vec, SZ(vec), 1, 1);
--
-- if ((vec_count != 1) && (vec_count != 2))
-- {
-- log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
-- "deny-access directive in configuration file.");
-- string_append(&config->proxy_args,
-- "<br>\nWARNING: Wrong number of parameters for "
-- "deny-access directive in configuration file.<br><br>\n");
-- continue;
-- }
--
-- /* allocate a new node */
-- cur_acl = (struct access_control_list *) zalloc(sizeof(*cur_acl));
--
-- if (cur_acl == NULL)
-- {
-- log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
-- /* Never get here - LOG_LEVEL_FATAL causes program exit */
-- continue;
-- }
-- cur_acl->action = ACL_DENY;
--
-- if (acl_addr(vec[0], cur_acl->src) < 0)
-- {
-- log_error(LOG_LEVEL_ERROR, "Invalid source IP for deny-access "
-- "directive in configuration file: \"%s\"", vec[0]);
-- string_append(&config->proxy_args,
-- "<br>\nWARNING: Invalid source IP for deny-access directive"
-- " in configuration file: \"");
-- string_append(&config->proxy_args,
-- vec[0]);
-- string_append(&config->proxy_args,
-- "\"<br><br>\n");
-- freez(cur_acl);
-- continue;
-- }
-- if (vec_count == 2)
-+ switch (ssplit(arg, " \t", vec, SZ(vec), 1, 1))
- {
-- if (acl_addr(vec[1], cur_acl->dst) < 0)
-- {
-- log_error(LOG_LEVEL_ERROR, "Invalid destination IP for deny-access "
-- "directive in configuration file: \"%s\"", vec[0]);
-- string_append(&config->proxy_args,
-- "<br>\nWARNING: Invalid destination IP for deny-access directive"
-- " in configuration file: \"");
-- string_append(&config->proxy_args,
-- vec[0]);
-+ case 1:
-+ config->acl = add_to_acl_list(config->acl, ACL_DENY, vec[0], NULL, &config->proxy_args);
-+ break;
-+ case 2:
-+ config->acl = add_to_acl_list(config->acl, ACL_DENY, vec[0], vec[1], &config->proxy_args);
-+ break;
-+ default:
-+ log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
-+ "deny-access directive in configuration file.");
- string_append(&config->proxy_args,
-- "\"<br><br>\n");
-- freez(cur_acl);
-- continue;
-- }
-+ "<br>\nWARNING: Wrong number of parameters for "
-+ "deny-access directive in configuration file.<br><br>\n");
+@@ -1044,6 +1043,12 @@
+ break;
+ }
}
--
-- /*
-- * Add it to the list. Note we reverse the list to get the
-- * behaviour the user expects. With both the ACL and
-- * actions file, the last match wins. However, the internal
-- * implementations are different: The actions file is stored
-- * in the same order as the file, and scanned completely.
-- * With the ACL, we reverse the order as we load it, then
-- * when we scan it we stop as soon as we get a match.
-- */
-- cur_acl->next = config->acl;
-- config->acl = cur_acl;
--
- continue;
-+
- #endif /* def FEATURE_ACL */
-
- /* *************************************************************************
-@@ -984,16 +960,18 @@
++#ifdef HAVE_GETADDRINFO
++ else
++ {
++ cur_acl->wildcard_dst = 1;
++ }
++#endif /* def HAVE_GETADDRINFO */
- if (strcmp(p, ".") != 0)
+ /*
+ * Add it to the list. Note we reverse the list to get the
+@@ -1193,7 +1198,18 @@
{
-- cur_fwd->forward_host = strdup(p);
-+ cur_fwd->forward_malloc = strdup(p);
-+ cur_fwd->forward_family = -1;
+ cur_fwd->forward_host = strdup(p);
- if (NULL != (p = strchr(cur_fwd->forward_host, ':')))
-- {
-- *p++ = '\0';
-- cur_fwd->forward_port = atoi(p);
-- }
-+ parse_pf_ip(cur_fwd->forward_malloc,
-+ &cur_fwd->forward_host,
-+ &cur_fwd->forward_port_str,
-+ &cur_fwd->forward_family);
-+ cur_fwd->forward_port = atoi(cur_fwd->forward_port_str);
-
- if (cur_fwd->forward_port <= 0)
++ if (*cur_fwd->forward_host == '[' &&
++ NULL != (p = strchr(cur_fwd->forward_host, ']')))
++ {
++ *p++ = '\0';
++ memmove(cur_fwd->forward_host, cur_fwd->forward_host + 1,
++ (size_t) (p - cur_fwd->forward_host));
++ if (*p == ':')
++ {
++ cur_fwd->forward_port = atoi(++p);
++ }
++ }
++ else if (NULL != (p = strchr(cur_fwd->forward_host, ':')))
{
-+ cur_fwd->forward_port_str = "8000";
- cur_fwd->forward_port = 8000;
- }
- }
-@@ -1047,15 +1025,27 @@
-
- if (strcmp(p, ".") != 0)
+ *p++ = '\0';
+ cur_fwd->forward_port = atoi(p);
+@@ -1257,11 +1273,23 @@
{
-- cur_fwd->gateway_host = strdup(p);
-+ /* SOCKS is IPv4-specific */
-+ int pf = PF_INET;
+ cur_fwd->gateway_host = strdup(p);
- if (NULL != (p = strchr(cur_fwd->gateway_host, ':')))
-+ cur_fwd->gateway_malloc = strdup(p);
-+ if (parse_pf_ip(cur_fwd->gateway_malloc,
-+ &cur_fwd->gateway_host,
-+ &cur_fwd->gateway_port_str,
-+ &pf) != 0)
++ if (*cur_fwd->gateway_host == '[' &&
++ NULL != (p = strchr(cur_fwd->gateway_host, ']')))
++ {
++ *p++ = '\0';
++ memmove(cur_fwd->gateway_host, cur_fwd->gateway_host + 1,
++ (size_t) (p - cur_fwd->gateway_host));
++ if (*p == ':')
++ {
++ cur_fwd->gateway_port = atoi(++p);
++ }
++ }
++ else if (NULL != (p = strchr(cur_fwd->gateway_host, ':')))
{
-- *p++ = '\0';
-- cur_fwd->gateway_port = atoi(p);
-+ log_error(LOG_LEVEL_ERROR, "Could not parse forward-socks4 host: %s",p);
-+ cur_fwd->gateway_host = NULL;
-+ cur_fwd->gateway_port_str = NULL;
-+ freez(cur_fwd->gateway_malloc);
-+ continue;
+ *p++ = '\0';
+ cur_fwd->gateway_port = atoi(p);
}
-+
-+ cur_fwd->gateway_port = atoi(cur_fwd->gateway_port_str);
+
if (cur_fwd->gateway_port <= 0)
{
-+ cur_fwd->gateway_port_str = "1080";
cur_fwd->gateway_port = 1080;
- }
- }
-@@ -1065,16 +1055,26 @@
-
- if (strcmp(p, ".") != 0)
+@@ -1275,7 +1303,18 @@
{
-- cur_fwd->forward_host = strdup(p);
-+ cur_fwd->forward_malloc = strdup(p);
-+ cur_fwd->forward_family = -1;
+ cur_fwd->forward_host = strdup(p);
- if (NULL != (p = strchr(cur_fwd->forward_host, ':')))
-+ parse_pf_ip(cur_fwd->forward_malloc,
-+ &cur_fwd->forward_host,
-+ &cur_fwd->forward_port_str,
-+ &cur_fwd->forward_family);
-+ cur_fwd->forward_port = atoi(cur_fwd->forward_port_str);
-+
-+ if (cur_fwd->forward_port <= 0)
++ if (*cur_fwd->forward_host == '[' &&
++ NULL != (p = strchr(cur_fwd->forward_host, ']')))
++ {
++ *p++ = '\0';
++ memmove(cur_fwd->forward_host, cur_fwd->forward_host + 1,
++ (size_t) (p - cur_fwd->forward_host));
++ if (*p == ':')
++ {
++ cur_fwd->forward_port = atoi(++p);
++ }
++ }
++ else if (NULL != (p = strchr(cur_fwd->forward_host, ':')))
{
-- *p++ = '\0';
-- cur_fwd->forward_port = atoi(p);
-+ cur_fwd->forward_port_str = "8000";
-+ cur_fwd->forward_port = 8000;
- }
+ *p++ = '\0';
+ cur_fwd->forward_port = atoi(p);
+@@ -1345,11 +1384,23 @@
-+ cur_fwd->forward_port = atoi(p);
-+
- if (cur_fwd->forward_port <= 0)
- {
-+ cur_fwd->forward_port_str = "8000";
- cur_fwd->forward_port = 8000;
- }
- }
-@@ -1126,16 +1126,30 @@
- /* Parse the SOCKS proxy host[:port] */
- p = vec[1];
+ cur_fwd->gateway_host = strdup(p);
-- cur_fwd->gateway_host = strdup(p);
--
- if (NULL != (p = strchr(cur_fwd->gateway_host, ':')))
-- {
-- *p++ = '\0';
-- cur_fwd->gateway_port = atoi(p);
-- }
-- if (cur_fwd->gateway_port <= 0)
- {
-- cur_fwd->gateway_port = 1080;
-+ /* SOCKS is IPv4-specific */
-+ int pf = PF_INET;
-+
-+ cur_fwd->gateway_malloc = strdup(p);
-+ if (parse_pf_ip(cur_fwd->gateway_malloc,
-+ &cur_fwd->gateway_host,
-+ &cur_fwd->gateway_port_str,
-+ &pf) != 0)
-+ {
-+ log_error(LOG_LEVEL_ERROR, "Could not parse forward-socks4a host: %s",p);
-+ cur_fwd->gateway_host = NULL;
-+ cur_fwd->gateway_port_str = NULL;
-+ freez(cur_fwd->gateway_malloc);
-+ continue;
-+ }
-+
-+ cur_fwd->gateway_port = atoi(cur_fwd->gateway_port_str);
-+
-+ if (cur_fwd->gateway_port <= 0)
++ if (*cur_fwd->gateway_host == '[' &&
++ NULL != (p = strchr(cur_fwd->gateway_host, ']')))
++ {
++ *p++ = '\0';
++ memmove(cur_fwd->gateway_host, cur_fwd->gateway_host + 1,
++ (size_t) (p - cur_fwd->gateway_host));
++ if (*p == ':')
+ {
-+ cur_fwd->gateway_port_str = "1080";
-+ cur_fwd->gateway_port = 1080;
++ cur_fwd->gateway_port = atoi(++p);
+ }
++ }
++ else if (NULL != (p = strchr(cur_fwd->gateway_host, ':')))
+ {
+ *p++ = '\0';
+ cur_fwd->gateway_port = atoi(p);
}
-
- /* Parse the parent HTTP proxy host[:port] */
-@@ -1143,16 +1157,26 @@
-
- if (strcmp(p, ".") != 0)
++
+ if (cur_fwd->gateway_port <= 0)
{
-- cur_fwd->forward_host = strdup(p);
-+ cur_fwd->forward_malloc = strdup(p);
-+ cur_fwd->forward_family = -1;
+ cur_fwd->gateway_port = 1080;
+@@ -1362,7 +1413,18 @@
+ {
+ cur_fwd->forward_host = strdup(p);
- if (NULL != (p = strchr(cur_fwd->forward_host, ':')))
-+ parse_pf_ip(cur_fwd->forward_malloc,
-+ &cur_fwd->forward_host,
-+ &cur_fwd->forward_port_str,
-+ &cur_fwd->forward_family);
-+ cur_fwd->forward_port = atoi(cur_fwd->forward_port_str);
-+
-+ if (cur_fwd->forward_port <= 0)
- {
-- *p++ = '\0';
-- cur_fwd->forward_port = atoi(p);
-+ cur_fwd->forward_port_str = "8000";
-+ cur_fwd->forward_port = 8000;
- }
-
-+ cur_fwd->forward_port = atoi(p);
-+
- if (cur_fwd->forward_port <= 0)
++ if (*cur_fwd->forward_host == '[' &&
++ NULL != (p = strchr(cur_fwd->forward_host, ']')))
++ {
++ *p++ = '\0';
++ memmove(cur_fwd->forward_host, cur_fwd->forward_host + 1,
++ (size_t) (p - cur_fwd->forward_host));
++ if (*p == ':')
++ {
++ cur_fwd->forward_port = atoi(++p);
++ }
++ }
++ else if (NULL != (p = strchr(cur_fwd->forward_host, ':')))
{
-+ cur_fwd->forward_port_str = "8000";
- cur_fwd->forward_port = 8000;
+ *p++ = '\0';
+ cur_fwd->forward_port = atoi(p);
+@@ -1512,6 +1574,12 @@
+ break;
}
}
-@@ -1185,10 +1209,49 @@
- * listen-address [ip][:port]
- * *************************************************************************/
- case hash_listen_address :
-- freez(config->haddr);
-- config->haddr = strdup(arg);
-+ {
-+ struct bind_spec *bs;
-+ char *arg_cpy;
-+ if (config->hspecs == NULL)
-+ {
-+ /* This is the first we'll bind to */
-+ config->hspecs = calloc(2,sizeof(struct bind_spec));
-+ if (config->hspecs == NULL)
-+ fail_load_config_memory(fs,config);
-+ config->hspecs_size = 2;
-+ config->hspecs_occupied = 0;
-+ }
-+
-+ arg_cpy = strdup(arg);
-+ if (arg_cpy == NULL)
-+ fail_load_config_memory(fs,config);
-+ if (config->hspecs_occupied == config->hspecs_size)
-+ {
-+ struct bind_spec *new_hspecs;
-+ config->hspecs_size *= 2;
-+ new_hspecs = realloc(config->hspecs,config->hspecs_size * sizeof(struct bind_spec));
-+ if (new_hspecs == NULL)
-+ {
-+ /* Not enough memory to continue. Cancel changes. */
-+ config->hspecs_size /= 2;
-+ fail_load_config_memory(fs,config);
-+ }
-+ config->hspecs = new_hspecs;
-+ }
-+ bs = &config->hspecs[(config->hspecs_occupied)++];
-+ bs->pf = -1;
-+ parse_pf_ip(arg,&bs->haddr,&bs->hport,&bs->pf);
-+ if (*bs->haddr == '\0')
-+ {
-+ bs->haddr = NULL;
-+ }
++#ifdef HAVE_GETADDRINFO
+ else
+ {
-+ (bs->haddr = strdup(bs->haddr));
++ cur_acl->wildcard_dst = 1;
+ }
-+ bs->hport = strdup(bs->hport);
- continue;
--
-+ }
- /* *************************************************************************
- * logdir directory-name
- * *************************************************************************/
-@@ -1211,75 +1274,21 @@
- * *************************************************************************/
- #ifdef FEATURE_ACL
- case hash_permit_access:
-- vec_count = ssplit(arg, " \t", vec, SZ(vec), 1, 1);
--
-- if ((vec_count != 1) && (vec_count != 2))
-- {
-- log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
-- "permit-access directive in configuration file.");
-- string_append(&config->proxy_args,
-- "<br>\nWARNING: Wrong number of parameters for "
-- "permit-access directive in configuration file.<br><br>\n");
--
-- continue;
-- }
--
-- /* allocate a new node */
-- cur_acl = (struct access_control_list *) zalloc(sizeof(*cur_acl));
--
-- if (cur_acl == NULL)
-- {
-- log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
-- /* Never get here - LOG_LEVEL_FATAL causes program exit */
-- continue;
-- }
-- cur_acl->action = ACL_PERMIT;
--
-- if (acl_addr(vec[0], cur_acl->src) < 0)
-- {
-- log_error(LOG_LEVEL_ERROR, "Invalid source IP for permit-access "
-- "directive in configuration file: \"%s\"", vec[0]);
-- string_append(&config->proxy_args,
-- "<br>\nWARNING: Invalid source IP for permit-access directive"
-- " in configuration file: \"");
-- string_append(&config->proxy_args,
-- vec[0]);
-- string_append(&config->proxy_args,
-- "\"<br><br>\n");
-- freez(cur_acl);
-- continue;
-- }
-- if (vec_count == 2)
-+ switch (ssplit(arg, " \t", vec, SZ(vec), 1, 1))
- {
-- if (acl_addr(vec[1], cur_acl->dst) < 0)
-- {
-- log_error(LOG_LEVEL_ERROR, "Invalid destination IP for "
-- "permit-access directive in configuration file: \"%s\"",
-- vec[0]);
-- string_append(&config->proxy_args,
-- "<br>\nWARNING: Invalid destination IP for permit-access directive"
-- " in configuration file: \"");
-- string_append(&config->proxy_args,
-- vec[0]);
-+ case 1:
-+ config->acl = add_to_acl_list(config->acl, ACL_PERMIT, vec[0], NULL, &config->proxy_args);
-+ break;
-+ case 2:
-+ config->acl = add_to_acl_list(config->acl, ACL_PERMIT, vec[0], vec[1], &config->proxy_args);
-+ break;
-+ default:
-+ log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
-+ "permit-access directive in configuration file.");
- string_append(&config->proxy_args,
-- "\"<br><br>\n");
-- freez(cur_acl);
-- continue;
-- }
-+ "<br>\nWARNING: Wrong number of parameters for "
-+ "permit-access directive in configuration file.<br><br>\n");
- }
--
-- /*
-- * Add it to the list. Note we reverse the list to get the
-- * behaviour the user expects. With both the ACL and
-- * actions file, the last match wins. However, the internal
-- * implementations are different: The actions file is stored
-- * in the same order as the file, and scanned completely.
-- * With the ACL, we reverse the order as we load it, then
-- * when we scan it we stop as soon as we get a match.
-- */
-- cur_acl->next = config->acl;
-- config->acl = cur_acl;
--
- continue;
- #endif /* def FEATURE_ACL */
++#endif /* def HAVE_GETADDRINFO */
-@@ -1519,32 +1528,33 @@
- }
- #endif /* def FEATURE_COOKIE_JAR */
+ /*
+ * Add it to the list. Note we reverse the list to get the
+@@ -1851,18 +1919,20 @@
-- if ( NULL == config->haddr )
-- {
-- config->haddr = strdup( HADDR_DEFAULT );
-- }
--
-- if ( NULL != config->haddr )
-+ if ( config->hspecs == NULL )
+ if ( NULL != config->haddr )
{
- if (NULL != (p = strchr(config->haddr, ':')))
-- {
++ if (*config->haddr == '[' && NULL != (p = strchr(config->haddr, ']')) &&
++ p[1] == ':' && 0 < (config->hport = atoi(p + 2)))
+ {
- *p++ = '\0';
- if (*p)
- {
- config->hport = atoi(p);
- }
-- }
++ *p='\0';
++ memmove((void *) config->haddr, config->haddr + 1,
++ (size_t) (p - config->haddr));
+ }
-
- if (config->hport <= 0)
-- {
-- *--p = ':';
-- log_error(LOG_LEVEL_FATAL, "invalid bind port spec %s", config->haddr);
-- /* Never get here - LOG_LEVEL_FATAL causes program exit */
-- }
-- if (*config->haddr == '\0')
-- {
-- config->haddr = NULL;
-- }
-+ /* No listen-address set. The default is localhost on port 8118, on IPv4
-+ and (if INET6 is defined) IPv6.
-+ */
-+ struct bind_spec *bs;
-+#ifdef INET6
-+ config->hspecs = calloc(2,sizeof(struct bind_spec));
-+ if (config->hspecs == NULL)
-+ fail_load_config_memory(fs,config);
-+ config->hspecs_size=2;
-+ config->hspecs_occupied=1;
-+ bs = &config->hspecs[0];
-+ bs->haddr = strdup("::1");
-+ bs->hport = strdup("8118");
-+ bs->pf = PF_UNSPEC;
-+#else
-+ config->hspecs = calloc(1,sizeof(struct bind_spec));
-+ if (config->hspecs == NULL)
-+ fail_load_config_memory(fs,config);
-+ config->hspecs_size=1;
-+ config->hspecs_occupied=0;
-+#endif
-+ bs = &config->hspecs[config->hspecs_occupied++];
-+ bs->haddr = strdup("127.0.0.1");
-+ bs->hport = strdup("8118");
-+ bs->pf = PF_UNSPEC;
- }
-
- /*
-@@ -1586,31 +1596,29 @@
- struct configuration_spec * oldcfg = (struct configuration_spec *)
- current_configfile->f;
- /*
-- * Check if config->haddr,hport == oldcfg->haddr,hport
-- *
-- * The following could be written more compactly as a single,
-- * (unreadably long) if statement.
-+ * Check if the listening addresses have changed
- */
- config->need_bind = 0;
-- if (config->hport != oldcfg->hport)
-- {
-- config->need_bind = 1;
-- }
-- else if (config->haddr == NULL)
-+ if (config -> hspecs_occupied == oldcfg -> hspecs_occupied)
- {
-- if (oldcfg->haddr != NULL)
-+ int bs_index;
-+ struct bind_spec *hspec;
-+ struct bind_spec *oldhspec;
-+ hspec = config -> hspecs;
-+ oldhspec = oldcfg -> hspecs;
-+ for(bs_index = 0; bs_index < oldcfg->hspecs_occupied; ++bs_index)
- {
-- config->need_bind = 1;
-+ if (strcmp(hspec[bs_index].haddr,oldhspec[bs_index].haddr) != 0
-+ || strcmp(hspec[bs_index].hport,oldhspec[bs_index].hport) != 0
-+ || hspec[bs_index].pf != hspec[bs_index].pf)
-+ {
-+ config -> need_bind = 1;
-+ break;
-+ }
- }
- }
-- else if (oldcfg->haddr == NULL)
-- {
-- config->need_bind = 1;
-- }
-- else if (0 != strcmp(config->haddr, oldcfg->haddr))
-- {
-- config->need_bind = 1;
-- }
-+ else
-+ config-> need_bind = 1;
-
- current_configfile->unloader = unload_configfile;
- }
-diff -urNad privoxy~/loaders.c privoxy/loaders.c
---- privoxy~/loaders.c
-+++ privoxy/loaders.c
-@@ -11,6 +11,9 @@
- * Copyright : Written by and Copyright (C) 2001 the SourceForge
- * Privoxy team. http://www.privoxy.org/
- *
-+ * Modified by Lionel Elie Mamane <lionel@mamane.lu>
-+ * for IPv6 support on 8 December 2002, 24 January 2003.
-+ *
- * Based on the Internet Junkbuster originally written
- * by and Copyright (C) 1997 Anonymous Coders and
- * Junkbusters Corporation. http://www.junkbusters.com
-@@ -465,6 +468,7 @@
-
- freez(csp->ip_addr_str);
- freez(csp->my_ip_addr_str);
-+ freez(csp->my_port_str);
- freez(csp->my_hostname);
- freez(csp->x_forwarded);
- freez(csp->iob->buf);
-diff -urNad privoxy~/miscutil.h privoxy/miscutil.h
---- privoxy~/miscutil.h
-+++ privoxy/miscutil.h
-@@ -162,6 +162,15 @@
-
- #include "project.h"
-
-+/* Fix a problem with Solaris. There should be no effect on other
-+ * platforms.
-+ * Solaris's isspace() is a macro which uses it's argument directly
-+ * as an array index. Therefore we need to make sure that high-bit
-+ * characters generate +ve values, and ideally we also want to make
-+ * the argument match the declared parameter type of "int".
-+ */
-+#define ijb_isdigit(__X) isdigit((int)(unsigned char)(__X))
-+
- #if defined(__cplusplus)
- extern "C" {
- #endif
-diff -urNad privoxy~/parsers.c privoxy/parsers.c
---- privoxy~/parsers.c
-+++ privoxy/parsers.c
-@@ -16,6 +16,9 @@
- * Copyright : Written by and Copyright (C) 2001 the SourceForge
- * Privoxy team. http://www.privoxy.org/
- *
-+ * Modified by Lionel Elie Mamane <lionel@mamane.lu>
-+ * for IPv6 support on 24 January 2003.
-+ *
- * Based on the Internet Junkbuster originally written
- * by and Copyright (C) 1997 Anonymous Coders and
- * Junkbusters Corporation. http://www.junkbusters.com
-@@ -1951,6 +1954,167 @@
- return JB_ERR_OK;
- }
-
-+/*********************************************************************
-+ *
-+ * Function : parse_pf_ip_netmask
-+ *
-+ * Description : Parse an IPv{4,6} litteral or hostname
-+ * with optional port and optional explicit family
-+ * and optional netmask
-+ *
-+ * Parameters :
-+ * 0 : string = the string to parse
-+ * 1 : host = Is set to point to the hostname or IP literal
-+ * part
-+ * 2 : port = Is set to point to the port part,
-+ * or NULL if no port in string
-+ * 3 : pf = pointer used to return the address family
-+ * pf is a value-result argument:
-+ * If it is set to -1, then parse_pf_ip will set it
-+ * to the address family of the pf_ip string
-+ * else, it won't touch it, and fail if the two
-+ * cannot match
-+ * 4 : pointer used to return the mask length
-+ * Set to -1 if no mask
-+ *
-+ * Returns : 0 on success
-+ *
-+ *********************************************************************/
-+int parse_pf_ip_netmask(char *string, char **host, char **port, int *pf, int *masklength)
-+{
-+ int i;
-+ char *p;
-+
-+ *masklength = -1;
-+
-+ if ((p = strchr(string, '/')) != NULL)
-+ {
-+ *p++ = '\0';
-+
-+ if (ijb_isdigit(*p) == 0)
-+ {
-+ return -1;
-+ }
-+ i = atoi(p);
-+ if ( i < 0 )
-+ return -1;
-+ *masklength = i;
-+ }
-+
-+ return parse_pf_ip(string, host, port, pf);
-+}
-+
-+/*********************************************************************
-+ *
-+ * Function : parse_pf_ip
-+ *
-+ * Description : Parse an IPv{4,6} litteral or hostname
-+ * with optional port and optional explicit family
-+ *
-+ * Parameters :
-+ * 0 : string = the string to parse
-+ * 1 : host = Is set to point to the hostname or IP literal
-+ * part
-+ * 2 : port = Is set to point to the port part,
-+ * or NULL if no port in string
-+ * 3 : pf = pointer used to return the address family
-+ * pf is a value-result argument:
-+ * If it is set to -1, then parse_pf_ip will set it
-+ * to the address family of the pf_ip string
-+ * else, it won't touch it, and fail if the two
-+ * cannot match
-+ *
-+ * Returns : 0 on success
-+ *
-+ *********************************************************************/
-+int parse_pf_ip(char *string, char **host, char **port, int *pf)
-+{
-+ if (pf != NULL && *pf == -1)
-+ *pf = PF_UNSPEC;
-+
-+ /* See if we want to override the default protocol family */
-+ if (strncmpic(string, "ipv4:", 5) == 0)
-+ {
-+ string += 5;
-+ if (pf!=NULL)
-+ {
-+ if(*pf==PF_INET || *pf==PF_UNSPEC)
-+ *pf = AF_INET;
-+ else
-+ {
-+ log_error(LOG_LEVEL_ERROR,"%s","IPv4 address found where other awaited");
-+ return -2;
-+ }
-+ }
-+ }
-+ else if (strncmpic(string, "ipv6:", 5) == 0)
-+ {
-+#ifdef INET6
-+ string += 5;
-+ if(*pf==PF_INET6 || *pf==PF_UNSPEC)
-+ *pf = AF_INET6;
-+ else
-+ {
-+ log_error(LOG_LEVEL_ERROR,"%s","IPv6 address found where other awaited");
-+ return -2;
-+ }
-+#else
-+ log_error(LOG_LEVEL_ERROR,"%s","This privoxy hasn't IPv6 support");
-+ return -1;
-+#endif
-+ }
-+ return parse_ip(string, host, port);
-+}
-+
-+/*********************************************************************
-+ *
-+ * Function : parse_ip
-+ *
-+ * Description : Parse an IPv{4,6} litteral or hostname
-+ * with optional port
-+ *
-+ * Parameters :
-+ * 0 : string = the string to parse
-+ * 1 : host = Is set to point to the hostname or IP literal
-+ * part
-+ * 2 : port = Is set to point to the port part,
-+ * or NULL if no port in string
-+ * Returns : 0 on success
-+ *
-+ *********************************************************************/
-+int parse_ip(char *string, char **host, char **port)
-+{
-+ char *p;
-+ int skip;
-+
-+ /* allow IPv6 address literal: [numbers:with:colons]:port/mask */
-+ if (string[0] == '[' && (p = strchr(string, ']')))
-+ {
-+ *p++ = '\0';
-+ skip = 1;
-+ }
-+ else
-+ {
-+ p = string;
-+ skip = 0;
-+ }
-+
-+ if (host != NULL)
-+ *host = string + skip;
-+
-+ for(;*p != '\0'; ++p)
-+ {
-+ if (*p == ':')
++ else if (NULL != (p = strchr(config->haddr, ':')) &&
++ 0 < (config->hport = atoi(p + 1)))
+ {
-+ *p++ = '\0';
-+ break;
++ *p = '\0';
+ }
-+ }
-+ if (port != NULL)
-+ *port = p;
-+ return 0;
-+}
-+
-
- /*********************************************************************
- *
-diff -urNad privoxy~/parsers.h privoxy/parsers.h
---- privoxy~/parsers.h
-+++ privoxy/parsers.h
-@@ -19,6 +19,9 @@
- * Copyright : Written by and Copyright (C) 2001 the SourceForge
- * Privoxy team. http://www.privoxy.org/
- *
-+ * Modified by Lionel Elie Mamane <lionel@mamane.lu>
-+ * for IPv6 support on 24 January 2003.
-+ *
- * Based on the Internet Junkbuster originally written
- * by and Copyright (C) 1997 Anonymous Coders and
- * Junkbusters Corporation. http://www.junkbusters.com
-@@ -270,6 +273,10 @@
- extern jb_err server_last_modified (struct client_state *csp, char **header);
- extern jb_err server_content_disposition(struct client_state *csp, char **header);
-
-+extern int parse_pf_ip_netmask(char *string, char **host, char **port, int *pf, int *masklength);
-+extern int parse_pf_ip(char *string, char ** host, char ** port, int *pf);
-+extern int parse_ip(char *string, char ** host, char** port);
++ else
+ {
+- *--p = ':';
+ log_error(LOG_LEVEL_FATAL, "invalid bind port spec %s", config->haddr);
+ /* Never get here - LOG_LEVEL_FATAL causes program exit */
+ }
+@@ -2038,4 +2108,6 @@
+ Local Variables:
+ tab-width: 3
+ end:
+
- #ifdef FEATURE_FORCE_LOAD
- extern int strclean(const char *string, const char *substring);
- #endif /* def FEATURE_FORCE_LOAD */
++ vim:softtabstop=3 shiftwidth=3
+ */
diff -urNad privoxy~/project.h privoxy/project.h
--- privoxy~/project.h
+++ privoxy/project.h
-@@ -607,6 +607,20 @@
+@@ -710,6 +710,12 @@
+ /* Needed for pcre choice */
+ #include "config.h"
- #endif /* ndef _WIN32 */
-
-+#include "jb_socket_set.h"
-+
-+#ifdef INET6
-+/**
-+ * Get from the operating system structures big enough
-+ * to put a network address in, namely sockaddr_storage
-+ */
-+#include <sys/socket.h>
-+/**
-+ * If no IPv6 support, just use the old sockaddr
-+ */
-+#else
-+#define sockaddr_storage sockaddr
++#ifdef HAVE_GETADDRINFO
++/* Need for struct sockaddr_storage */
++#include <sys/socket.h>
+#endif
-
- /**
- * A standard error code. This should be JB_ERR_OK or one of the JB_ERR_xxx
-@@ -681,19 +695,6 @@
- */
++
++
+ /*
+ * Include appropriate regular expression libraries.
+ * Note that pcrs and pcre (native) are needed for cgi
+@@ -861,16 +867,10 @@
#define FOREVER 1
--/**
+ /**
- * Default IP address to listen on, as a string.
- * Set to "127.0.0.1".
- */
-/**
- * Default port to listen on, as a number.
- * Set to 8118.
-- */
++ * Default TCP/IP address to listen on, as a string.
++ * Set to "127.0.0.1:8118".
+ */
-#define HADDR_PORT 8118
--
--
- /* Forward def for struct client_state */
- struct configuration_spec;
-
-@@ -772,13 +773,16 @@
- char *ver; /**< Protocol version */
- int status; /**< HTTP Status */
-
-+ char *host_port_malloc; /**< malloc used for place wher host and port_str are */
- char *host; /**< Host part of URL */
- int port; /**< Port of URL or 80 (default) */
-+ char *port_str; /**< Port of URL, as string */
- char *path; /**< Path of URL */
- char *hostport; /**< host[:port] */
- int ssl; /**< Flag if protocol is https */
++#define HADDR_DEFAULT "127.0.0.1:8118"
-- char *host_ip_addr_str; /**< String with dotted decimal representation
-+ char *host_ip_addr_str; /**< String with dotted decimal representation (IPv4)
-+ or hexadecimal colon-separated (IPv6)
- of host's IP. NULL before connect_to() */
- char *dbuffer; /**< Buffer with '\0'-delimited domain name. */
-@@ -1158,13 +1162,16 @@
+ /* Forward def for struct client_state */
+@@ -1424,9 +1424,15 @@
+ /** Client PC's IP address, as reported by the accept() function.
As a string. */
char *ip_addr_str;
++#ifdef HAVE_GETADDRINFO
++ /** Client PC's TCP address, as reported by the accept() function.
++ As a sockaddr. */
++ struct sockaddr_storage tcp_addr;
++#else
/** Client PC's IP address, as reported by the accept() function.
-- As a number. */
-- long ip_addr_long;
-+ As an address. */
-+ struct sockaddr_storage ip_addr_addr;
-
- /** Our IP address. I.e. the IP address that the client used to reach us,
- as a string. */
- char *my_ip_addr_str;
-
-+ /** Our port. I.e. the port the client used to reach us */
-+ char *my_port_str;
-+
- /** Our hostname. I.e. the reverse DNS of the IP address that the client
- used to reach us, as a string. */
- char *my_hostname;
-@@ -1339,18 +1346,33 @@
- /** Connection type. Must be SOCKS_NONE, SOCKS_4, or SOCKS_4A. */
- int type;
-
-+ /** pointer returned by the malloc used for gateway_host and gateway_port_str */
-+ char *gateway_malloc;
-+
- /** SOCKS server hostname. Only valid if "type" is SOCKS_4 or SOCKS_4A. */
- char *gateway_host;
+ As a number. */
+ unsigned long ip_addr_long;
++#endif /* def HAVE_GETADDRINFO */
- /** SOCKS server port. */
- int gateway_port;
-
-+ /** SOCKS server port, as string. */
-+ char *gateway_port_str;
-+
-+ /** pointer returned by the malloc used for forward_host and forward_port_str */
-+ char *forward_malloc;
-+
-+ /** Parent HTTP proxy address family. */
-+ int forward_family;
-+
- /** Parent HTTP proxy hostname, or NULL for none. */
- char *forward_host;
-
- /** Parent HTTP proxy port. */
- int forward_port;
-
-+ /** Parent HTTP proxy port as string. */
-+ char *forward_port_str;
-+
- /** Next entry in the linked list. */
- struct forward_spec *next;
- };
-@@ -1359,7 +1381,7 @@
- /**
- * Initializer for a static struct forward_spec.
- */
--#define FORWARD_SPEC_INITIALIZER { { URL_SPEC_INITIALIZER }, 0, NULL, 0, NULL, 0, NULL }
-+#define FORWARD_SPEC_INITIALIZER { { URL_SPEC_INITIALIZER }, 0, NULL, NULL, 0, NULL, NULL, 0, NULL, 0, NULL, NULL}
-
-
- /**
-@@ -1388,7 +1410,8 @@
+ /** The URL that was requested */
+ struct http_request http[1];
+@@ -1660,9 +1666,14 @@
*/
struct access_control_addr
{
-- unsigned long addr; /**< The IP address as an integer. */
-+ struct sockaddr_storage addr; /**< The IP address. */
-+ size_t addrlen;
++#ifdef HAVE_GETADDRINFO
++ struct sockaddr_storage addr; /* <The TCP address in network order. */
++ struct sockaddr_storage mask; /* <The TCP mask in network order. */
++#else
+ unsigned long addr; /**< The IP address as an integer. */
unsigned long mask; /**< The network mask as an integer. */
unsigned long port; /**< The port number. */
++#endif /* HAVE_GETADDRINFO */
};
-@@ -1423,6 +1446,17 @@
- /** configuration_spec::feature_flags: HTTP-header-based toggle. */
- #define RUNTIME_FEATURE_HTTP_TOGGLE 4
-+struct bind_spec
-+{
-+ /** IP address to bind to. */
-+ char *haddr;
-+
-+ /** Port to bind to. */
-+ char *hport;
-+
-+ /** Address family */
-+ int pf;
-+};
/**
- * Data loaded from the configuration file.
- *
-@@ -1486,11 +1520,13 @@
-
- #endif /* def FEATURE_COOKIE_JAR */
-
-- /** IP address to bind to. Defaults to HADDR_DEFAULT == 127.0.0.1. */
-- const char *haddr;
--
-- /** Port to bind to. Defaults to HADDR_PORT == 8118. */
-- int hport;
-+ /* IP addresses and ports to bind to.
-+ Defaults to HSPECS_DEFAULT == {ipv4:127.0.0.1:8118, ipv6:[::1]:8118}. */
-+ struct bind_spec *hspecs;
-+ /* size allocated */
-+ unsigned int hspecs_size;
-+ /* number of entries */
-+ unsigned int hspecs_occupied;
+@@ -1674,6 +1685,9 @@
+ {
+ struct access_control_addr src[1]; /**< Client IP address */
+ struct access_control_addr dst[1]; /**< Website or parent proxy IP address */
++#ifdef HAVE_GETADDRINFO
++ int wildcard_dst; /** < dst address is wildcard */
++#endif
- /** Size limit for IOB */
- size_t buffer_limit;
+ short action; /**< ACL_PERMIT or ACL_DENY */
+ struct access_control_list *next; /**< The next entry in the ACL. */
+@@ -1882,4 +1896,6 @@
+ Local Variables:
+ tab-width: 3
+ end:
++
++ vim:softtabstop=3 shiftwidth=3
+ */
diff -urNad privoxy~/urlmatch.c privoxy/urlmatch.c
--- privoxy~/urlmatch.c
+++ privoxy/urlmatch.c
-@@ -137,6 +137,7 @@
- #include "ssplit.h"
- #include "miscutil.h"
- #include "errlog.h"
-+#include "parsers.h"
-
- const char urlmatch_h_rcs[] = URLMATCH_H_VERSION;
-
-@@ -160,7 +161,7 @@
- freez(http->cmd);
- freez(http->ocmd);
- freez(http->gpc);
-- freez(http->host);
-+ freez(http->host_port_malloc);
- freez(http->url);
- freez(http->hostport);
- freez(http->path);
-@@ -302,8 +303,6 @@
- */
- {
- char *buf;
-- char *host;
-- char *port;
-
- buf = strdup(http->hostport);
- if (buf == NULL)
-@@ -311,38 +310,34 @@
- return JB_ERR_MEMORY;
- }
-
-+ http->host_port_malloc = buf;
-+
- /* check if url contains username and/or password */
-- host = strchr(buf, '@');
-- if (host != NULL)
-+ buf = strchr(buf, '@');
-+ if (buf != NULL)
- {
- /* Contains username/password, skip it and the @ sign. */
-- host++;
-+ buf++;
- }
- else
- {
- /* No username or password. */
-- host = buf;
-+ buf = http->host_port_malloc;
+@@ -540,8 +540,40 @@
+ host = buf;
}
-- /* check if url contains port */
-- port = strchr(host, ':');
-- if (port != NULL)
-+ parse_ip(buf,&http->host,&http->port_str);
++ /* Move after hostname before port number */
++ if (*host == '[')
++ {
++ /* Numeric IPv6 address delimited by brackets */
++ host++;
++ port = strchr(host, ']');
+
-+ if (*http->port_str != '\0')
- {
-- /* Contains port */
-- /* Terminate hostname and point to start of port string */
-- *port++ = '\0';
-- http->port = atoi(port);
-+ http->port = atoi(http->port_str);
- }
- else
- {
- /* No port specified. */
-+ http->port_str = (http->ssl ? "143" : "80");
- http->port = (http->ssl ? 443 : 80);
- }
-
-- http->host = strdup(host);
--
-- free(buf);
--
- if (http->host == NULL)
- {
- return JB_ERR_MEMORY;
-@@ -666,9 +661,8 @@
- * written to system log)
- *
- *********************************************************************/
--jb_err create_url_spec(struct url_spec * url, const char * buf)
-+jb_err create_url_spec(struct url_spec * url, char * buf)
- {
-- char *p;
-
- assert(url);
- assert(buf);
-@@ -685,21 +679,24 @@
- {
- return JB_ERR_MEMORY;
- }
--
-- if ((p = strchr(buf, '/')) != NULL)
- {
-- if (NULL == (url->path = strdup(p)))
-+ char *p;
++ if (port == NULL)
++ {
++ /* Missing closing bracket */
++ freez(buf);
++ return JB_ERR_PARSE;
++ }
+
-+ if ((p = strchr(buf, '/')) != NULL)
- {
-- freez(url->spec);
-- return JB_ERR_MEMORY;
-+ if (NULL == (url->path = strdup(p)))
++ *port++='\0';
++
++ if (*port == '\0')
+ {
-+ freez(url->spec);
-+ return JB_ERR_MEMORY;
++ port = NULL;
++ }
++ else if (*port != ':')
++ {
++ /* Garbage after closing bracket */
++ freez(buf);
++ return JB_ERR_PARSE;
+ }
-+ url->pathlen = strlen(url->path);
-+ *p = '\0';
+ }
+ else
+ {
-+ url->path = NULL;
-+ url->pathlen = 0;
- }
-- url->pathlen = strlen(url->path);
-- *p = '\0';
-- }
-- else
-- {
-- url->path = NULL;
-- url->pathlen = 0;
- }
- if (url->path)
- {
-@@ -739,14 +736,11 @@
- return JB_ERR_PARSE;
- }
- }
-- if ((p = strchr(buf, ':')) == NULL)
-- {
-- url->port = 0;
-- }
-- else
++ /* Plain non-escaped hostname */
++ port = strchr(host, ':');
++ }
+
- {
-- *p++ = '\0';
-- url->port = atoi(p);
-+ char *p;
-+ parse_ip(buf,&buf,&p);
-+ url->port = atoi(p);
- }
-
- if (buf[0] != '\0')
-@@ -779,12 +773,13 @@
- return JB_ERR_MEMORY;
- }
-
-- /*
-- * Map to lower case
-- */
-- for (p = url->dbuffer; *p ; p++)
+ /* check if url contains port */
+- port = strchr(host, ':');
+ if (port != NULL)
{
-- *p = tolower((int)(unsigned char)*p);
-+ char* p;
-+ /* map to lower case */
-+ for (p = url->dbuffer; *p ; p++)
-+ {
-+ *p = tolower((int)(unsigned char)*p);
-+ }
- }
-
- /*
-diff -urNad privoxy~/urlmatch.h privoxy/urlmatch.h
---- privoxy~/urlmatch.h
-+++ privoxy/urlmatch.h
-@@ -83,7 +83,7 @@
- extern int url_match(const struct url_spec *pattern,
- const struct http_request *url);
-
--extern jb_err create_url_spec(struct url_spec * url, const char * buf);
-+extern jb_err create_url_spec(struct url_spec * url, char * buf);
- extern void free_url_spec(struct url_spec *url);
-
+ /* Contains port */
+@@ -844,7 +876,31 @@
+ *p = '\0';
+ }
+- p = strchr(buf, ':');
++ /* XXX: IPv6 numeric hostname contains colons, thus we need to delimit the
++ * hostname before real port separator. Because brackets are used in
++ * hostname matching on lower layer, we can't use it. I decided to use
++ * angle brackets '<' '>' instead. */
++ if (buf[0] == '<' && NULL != (p = strchr(buf + 1, '>')))
++ {
++ *p++ = '\0';
++ buf++;
++
++ if (*p == '\0')
++ {
++ /* Only IPv6 address without port number */
++ p = NULL;
++ }
++ else if (*p != ':')
++ {
++ /* Garbage after address delimiter */
++ return JB_ERR_PARSE;
++ }
++ }
++ else
++ {
++ p = strchr(buf, ':');
++ }
++
+ if (NULL != p)
+ {
+ *p++ = '\0';
+@@ -1449,4 +1505,6 @@
+ Local Variables:
+ tab-width: 3
+ end:
++
++ vim:softtabstop=3 shiftwidth=3
+ */