Petr Pisar's privoxy-3.0.12-ipv6-3.diff.
authorFabian Keil <fk@fabiankeil.de>
Fri, 17 Apr 2009 11:27:49 +0000 (11:27 +0000)
committerFabian Keil <fk@fabiankeil.de>
Fri, 17 Apr 2009 11:27:49 +0000 (11:27 +0000)
configure.in
doc/source/p-config.sgml
doc/source/user-manual.sgml
filters.c
jbsockets.c
jcc.c
loadcfg.c
project.h
urlmatch.c

index b2c38fd..8c4fbac 100644 (file)
@@ -1,6 +1,6 @@
 dnl Process this file with autoconf to produce a configure script.
 dnl 
-dnl $Id: configure.in,v 1.126 2009/03/21 10:45:06 fabiankeil Exp $
+dnl $Id: configure.in,v 1.127 2009/03/25 17:26:31 fabiankeil Exp $
 dnl 
 dnl Written by and Copyright (C) 2001-2009 the
 dnl Privoxy team. http://www.privoxy.org/
@@ -28,6 +28,9 @@ dnl or write to the Free Software Foundation, Inc., 59
 dnl Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 dnl 
 dnl $Log: configure.in,v $
+dnl Revision 1.127  2009/03/25 17:26:31  fabiankeil
+dnl And they are running again. Bump version to 3.0.13 UNRELEASED.
+dnl
 dnl Revision 1.126  2009/03/21 10:45:06  fabiankeil
 dnl Declare the code stable.
 dnl
@@ -566,7 +569,7 @@ dnl =================================================================
 dnl AutoConf Initialization
 dnl =================================================================
 
-AC_REVISION($Revision: 1.126 $)
+AC_REVISION($Revision: 1.127 $)
 AC_INIT(jcc.c)
 
 if test ! -f config.h.in; then
@@ -1237,7 +1240,7 @@ AC_FUNC_SETPGRP
 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 =================================================================
index 2d8c181..9ed8f15 100644 (file)
@@ -3,7 +3,7 @@
 
  Purpose     :  Used with other docs and files only.
 
- $Id: p-config.sgml,v 2.42 2009/03/23 04:17:47 ler762 Exp $
+ $Id: p-config.sgml,v 2.43 2009/03/28 15:33:41 fabiankeil Exp $
 
  Copyright (C) 2001-2009 Privoxy Developers http://www.privoxy.org/
  See LICENSE.
@@ -95,7 +95,7 @@
  Sample Configuration File for Privoxy v&p-version;
 </title>
 <para>
- $Id: p-config.sgml,v 2.42 2009/03/23 04:17:47 ler762 Exp $
+ $Id: p-config.sgml,v 2.43 2009/03/28 15:33:41 fabiankeil Exp $
 </para>
 <para>
 Copyright (C) 2001-2009 Privoxy Developers http://www.privoxy.org/
@@ -1213,9 +1213,9 @@ actionsfile
   <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>
@@ -1230,6 +1230,9 @@ actionsfile
     serve requests from other machines (e.g. on your local network) as well, you
     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
@@ -1257,6 +1260,15 @@ actionsfile
    <para>
     <programlisting>
   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>
@@ -1611,23 +1623,41 @@ ACLs: permit-access and deny-access</title>
   <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/rfc3493">RFC 3493</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>
@@ -1676,6 +1706,13 @@ ACLs: permit-access and deny-access</title>
     like <quote>*.org</quote> or partial domain names. If a DNS name resolves to multiple
     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
@@ -1717,6 +1754,24 @@ ACLs: permit-access and deny-access</title>
   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 @@ ACLs: permit-access and deny-access</title>
     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>
@@ -1864,6 +1919,16 @@ ACLs: permit-access and deny-access</title>
     If <replaceable class="parameter">http_parent</replaceable> is <quote>.</quote>, then requests are not
     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/rfc3493">RFC 3493</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>
@@ -1891,6 +1956,24 @@ ACLs: permit-access and deny-access</title>
   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  &lt;[2-3][0-9a-f][0-9a-f][0-9a-f]:*&gt;   .
+</programlisting>
+   </para>
   </listitem>
  </varlistentry>
 </variablelist>
@@ -1962,6 +2045,18 @@ forward-socks4, forward-socks4a and forward-socks5</title>
    <para>
     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 clss="parameter">http_parent</replaceable> can be IPv6
+    numerical address (if
+    <ulink url="http://tools.ietf.org/html/rfc3493">RFC 3493</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
index 024d350..ac7ad28 100644 (file)
@@ -34,7 +34,7 @@
                 This file belongs into
                 ijbswa.sourceforge.net:/home/groups/i/ij/ijbswa/htdocs/
 
- $Id: user-manual.sgml,v 2.102 2009/03/15 19:31:36 fabiankeil Exp $
+ $Id: user-manual.sgml,v 2.103 2009/03/21 10:49:05 fabiankeil Exp $
 
  Copyright (C) 2001-2009 Privoxy Developers http://www.privoxy.org/
  See LICENSE.
@@ -60,7 +60,7 @@
  </subscript>
 </pubdate>
 
-<pubdate>$Id: user-manual.sgml,v 2.102 2009/03/15 19:31:36 fabiankeil Exp $</pubdate>
+<pubdate>$Id: user-manual.sgml,v 2.103 2009/03/21 10:49:05 fabiankeil Exp $</pubdate>
 
 <!--
 
@@ -2147,12 +2147,12 @@ for details.
  
 <para>
  Generally, an URL pattern has the form
- <literal>&lt;domain&gt;/&lt;path&gt;</literal>, where both the
- <literal>&lt;domain&gt;</literal> and <literal>&lt;path&gt;</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>&lt;domain&gt;&lt;port&gt;/&lt;path&gt;</literal>, where both the
+ <literal>&lt;domain&gt;</literal> and <literal>&lt;port&gt;</literal>
and <literal>&lt;path&gt;</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 @@ for details.
  <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>&lt;</literal>, <literal>&gt;</literal>).
+</para>
 
 <variablelist>
  <varlistentry>
@@ -2210,6 +2216,23 @@ for details.
    </para>
   </listitem>
  </varlistentry>
+ <varlistentry>
+  <term><literal>:8000/</literal></term>
+  <listitem>
+   <para>
+    Matches any URL pointing to TCP port 8000.
+   </para>
+  </listitem>
+ </varlistentry>
+ <varlistentry>
+  <term><literal>&lt;2001:db8::1&gt;/</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>
@@ -8453,6 +8476,9 @@ In file: user.action <guibutton>[ View ]</guibutton> <guibutton>[ Edit ]</guibut
  USA
 
  $Log: user-manual.sgml,v $
+ Revision 2.103  2009/03/21 10:49:05  fabiankeil
+ Merge updated ChangeLog.
+
  Revision 2.102  2009/03/15 19:31:36  fabiankeil
  Update "What's New in this Release" section.
 
index 18ef5b3..43b002f 100644 (file)
--- a/filters.c
+++ b/filters.c
@@ -1,4 +1,4 @@
-const char filters_rcs[] = "$Id: filters.c,v 1.112 2009/03/01 18:28:23 fabiankeil Exp $";
+const char filters_rcs[] = "$Id: filters.c,v 1.113 2009/03/08 14:19:23 fabiankeil Exp $";
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/filters.c,v $
@@ -40,6 +40,10 @@ const char filters_rcs[] = "$Id: filters.c,v 1.112 2009/03/01 18:28:23 fabiankei
  *
  * Revisions   :
  *    $Log: filters.c,v $
+ *    Revision 1.113  2009/03/08 14:19:23  fabiankeil
+ *    Fix justified (but harmless) compiler warnings
+ *    on platforms where sizeof(int) < sizeof(long).
+ *
  *    Revision 1.112  2009/03/01 18:28:23  fabiankeil
  *    Help clang understand that we aren't dereferencing
  *    NULL pointers here.
@@ -661,6 +665,11 @@ const char filters_rcs[] = "$Id: filters.c,v 1.112 2009/03/01 18:28:23 fabiankei
 #include <string.h>
 #include <assert.h>
 
+#ifdef HAVE_GETADDRINFO
+#include <netdb.h>
+#include <sys/socket.h>
+#endif /* def HAVE_GETADDRINFO */
+
 #ifndef _WIN32
 #ifndef __OS2__
 #include <unistd.h>
@@ -708,6 +717,151 @@ static jb_err remove_chunked_transfer_coding(char *buffer, size_t *size);
 static jb_err prepare_for_filtering(struct client_state *csp);
 
 #ifdef FEATURE_ACL
+#ifdef HAVE_GETADDRINFO
+/*********************************************************************
+ *
+ * Function    :  sockaddr_storage_to_ip
+ *
+ * Description :  Access internal structure of sockaddr_storage
+ *
+ * Parameters  :
+ *          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 = no errror; otherwise 
+ *
+ *********************************************************************/
+int sockaddr_storage_to_ip(const struct sockaddr_storage *addr, uint8_t **ip,
+      unsigned int *len, in_port_t **port)
+{
+   if (!addr)
+   {
+      return(-1);
+   }
+
+   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;
+
+      case AF_INET6:
+         if (len)
+         {
+            *len = 16;
+         }
+         if (ip)
+         {
+            *ip = ( (struct sockaddr_in6 *) addr)->sin6_addr.s6_addr;
+         }
+         if (port)
+         {
+            *port = &((struct sockaddr_in6 *) addr)->sin6_port;
+         }
+         break;
+
+      default:
+         /* Unsupported address family */
+         return(-1);
+   }
+
+   return(0);
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  match_sockaddr
+ *
+ * Description :  Check whether address matches network (IP address and port)
+ *
+ * Parameters  :
+ *          1  :  network = socket address of subnework
+ *          3  :  netmask = network mask as socket address 
+ *          2  :  address = checked socket address against given network
+ *
+ * Returns     :  0 = doesn't match; 1 = does match
+ *
+ *********************************************************************/
+int match_sockaddr(const struct sockaddr_storage *network,
+      const struct sockaddr_storage *netmask,
+      const struct sockaddr_storage *address)
+{
+   uint8_t *network_addr, *netmask_addr, *address_addr;
+   unsigned int addr_len;
+   in_port_t *network_port, *netmask_port, *address_port;
+   int i;
+
+   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;
+   }
+
+   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);
+
+   /* 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;
+   }
+
+   /* XXX: Port check is signaled in netmask */
+   if (*netmask_port && *network_port != *address_port)
+   {
+      return 0;
+   }
+
+   /* 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]) )
+      {
+         return 0;
+      }
+   }
+   
+   return 1;
+}
+#endif /* def HAVE_GETADDRINFO */
+
+
 /*********************************************************************
  *
  * Function    :  block_acl
@@ -737,7 +891,13 @@ int block_acl(const struct access_control_addr *dst, const struct client_state *
    /* search the list */
    while (acl != NULL)
    {
-      if ((csp->ip_addr_long & acl->src->mask) == acl->src->addr)
+      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)
          {
@@ -747,8 +907,23 @@ int block_acl(const struct access_control_addr *dst, const struct client_state *
                return(0);
             }
          }
-         else if ( ((dst->addr & acl->dst->mask) == acl->dst->addr)
-           && ((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)
             {
@@ -784,12 +959,24 @@ int block_acl(const struct access_control_addr *dst, const struct client_state *
 int acl_addr(const char *aspec, struct access_control_addr *aca)
 {
    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
 
    /*
     * Use a temporary acl spec copy so we can log
@@ -813,13 +1000,53 @@ int acl_addr(const char *aspec, struct access_control_addr *aca)
       masklength = atoi(p);
    }
 
-   if ((masklength < 0) || (masklength > 32))
+   if ((masklength < 0) ||
+#ifdef HAVE_GETADDRINFO
+         (masklength > 128)
+#else
+         (masklength > 32)
+#endif
+         )
    {
       freez(acl_spec);
       return(-1);
    }
 
-   if ((p = strchr(acl_spec, ':')) != NULL)
+   if (*acl_spec == '[' && NULL != (p = strchr(acl_spec, ']')))
+   {
+      *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, result->ai_addrlen);
+   freeaddrinfo(result);
+#else
+   if (p != NULL)
    {
       char *endptr;
 
@@ -843,8 +1070,49 @@ int acl_addr(const char *aspec, struct access_control_addr *aca)
       /* XXX: This will be logged as parse error. */
       return(-1);
    }
+#endif /* def HAVE_GETADDRINFO */
 
    /* build the netmask */
+#ifdef HAVE_GETADDRINFO
+   /* Clip masklength according current family */
+   if (aca->addr.ss_family == AF_INET && masklength > 32)
+   {
+      masklength = 32;
+   }
+
+   aca->mask.ss_family = aca->addr.ss_family;
+   if (sockaddr_storage_to_ip(&aca->mask, &mask_data, &addr_len, &mask_port))
+   {
+      return(-1);
+   }
+
+   if (p)
+   {
+      /* Port number in ACL has been specified, check ports in future */
+      *mask_port = 1;
+   }
+
+   /* 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++)
+   {
+      if (masklength >= 8)
+      {
+         mask_data[i] = 0xFF;
+         masklength -= 8;
+      }
+      else
+      {
+         /* 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;
+      }
+   }
+
+#else
    aca->mask = 0;
    for (i=1; i <= masklength ; i++)
    {
@@ -855,6 +1123,7 @@ int acl_addr(const char *aspec, struct access_control_addr *aca)
     * (i.e. save on the network portion of the address).
     */
    aca->addr = aca->addr & aca->mask;
+#endif /* def HAVE_GETADDRINFO */
 
    return(0);
 
@@ -2702,4 +2971,6 @@ int content_filters_enabled(const struct current_action_spec *action)
   Local Variables:
   tab-width: 3
   end:
+
+  vim:softtabstop=3 shiftwidth=3
 */
index f7443ec..76f1cb8 100644 (file)
@@ -1,4 +1,4 @@
-const char jbsockets_rcs[] = "$Id: jbsockets.c,v 1.49 2008/11/10 17:03:57 fabiankeil Exp $";
+const char jbsockets_rcs[] = "$Id: jbsockets.c,v 1.50 2008/12/20 14:53:55 fabiankeil Exp $";
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/jbsockets.c,v $
@@ -35,6 +35,11 @@ const char jbsockets_rcs[] = "$Id: jbsockets.c,v 1.49 2008/11/10 17:03:57 fabian
  *
  * Revisions   :
  *    $Log: jbsockets.c,v $
+ *    Revision 1.50  2008/12/20 14:53:55  fabiankeil
+ *    Add config option socket-timeout to control the time
+ *    Privoxy waits for data to arrive on a socket. Useful
+ *    in case of stale ssh tunnels or when fuzz-testing.
+ *
  *    Revision 1.49  2008/11/10 17:03:57  fabiankeil
  *    Fix a gcc44 warning and remove a now-obsolete cast.
  *
@@ -350,6 +355,177 @@ const char jbsockets_h_rcs[] = JBSOCKETS_H_VERSION;
  *                file descriptor.
  *
  *********************************************************************/
+#ifdef HAVE_GETADDRINFO
+/* Getaddrinfo implementation */
+jb_socket connect_to(const char *host, int portnum, struct client_state *csp)
+{
+   struct addrinfo hints, *result, *rp;
+   char service[6];
+   int retval;
+   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;
+
+#ifdef FEATURE_ACL
+   struct access_control_addr dst[1];
+#endif /* def FEATURE_ACL */
+
+   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);
+   }
+
+   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);
+   }
+
+   for (rp = result; rp != NULL; rp = rp->ai_next)
+   {
+
+#ifdef FEATURE_ACL
+      memcpy(&dst->addr, rp->ai_addr, rp->ai_addrlen);
+
+      if (block_acl(dst, csp))
+      {
+#ifdef __OS2__
+         errno = SOCEPERM;
+#else
+         errno = EPERM;
+#endif
+         continue;
+      }
+#endif /* def FEATURE_ACL */
+
+      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)
+      {
+         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;
+      }
+
+#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;
+      }
+
+#ifdef TCP_NODELAY
+      {  /* 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);
+      }
+#endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) */
+
+      connect_failed = 0;
+      while (connect(fd, rp->ai_addr, rp->ai_addrlen) == JB_INVALID_SOCKET)
+      {
+#ifdef _WIN32
+         if (errno == WSAEINPROGRESS)
+#elif __OS2__ 
+         if (sock_errno() == EINPROGRESS)
+#else /* ifndef _WIN32 */
+         if (errno == EINPROGRESS)
+#endif /* ndef _WIN32 || __OS2__ */
+         {
+            break;
+         }
+
+#ifdef __OS2__ 
+         if (sock_errno() != EINTR)
+#else
+         if (errno != EINTR)
+#endif /* __OS2__ */
+         {
+            close_socket(fd);
+            connect_failed = 1;
+            break;
+         }
+      }
+      if (connect_failed)
+      {
+         continue;
+      }
+
+#if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__)
+      if (flags != -1)
+      {
+         flags &= ~O_NDELAY;
+         fcntl(fd, F_SETFL, flags);
+      }
+#endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) */
+
+      /* 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);
+         continue;
+      }
+      
+      break; /* for; Connection established; don't try other addresses */
+   }
+
+   freeaddrinfo(result);
+   if (!rp)
+   {
+      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);*/
+
+   return(fd);
+
+}
+
+# else /* ndef HAVE_GETADDRINFO */
+/* Pre-getaddrinfo implementation */
+
 jb_socket connect_to(const char *host, int portnum, struct client_state *csp)
 {
    struct sockaddr_in inaddr;
@@ -477,6 +653,7 @@ jb_socket connect_to(const char *host, int portnum, struct client_state *csp)
    return(fd);
 
 }
+#endif /* ndef HAVE_GETADDRINFO */
 
 
 /*********************************************************************
@@ -672,7 +849,16 @@ void close_socket(jb_socket fd)
  *********************************************************************/
 int bind_port(const char *hostnam, int portnum, jb_socket *pfd)
 {
+#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;
@@ -680,6 +866,32 @@ int bind_port(const char *hostnam, int portnum, jb_socket *pfd)
 
    *pfd = JB_INVALID_SOCKET;
 
+#ifdef HAVE_GETADDRINFO
+   retval = snprintf(servnam, sizeof(servnam), "%d", portnum);
+   if (-1 == retval || sizeof(servnam) <= retval)
+   {
+      log_error(LOG_LEVEL_ERROR,
+            "Port number (%d) ASCII decimal representation doesn't fit into 6 bytes",
+            portnum);
+      return -1;
+   }
+
+   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 ((retval = getaddrinfo(hostnam, servnam, &hints, &result)))
+   {
+      log_error(LOG_LEVEL_ERROR,
+            "Can not resolve %s: %s", hostnam, gai_strerror(retval));
+      return -2;
+   }
+#else
    memset((char *)&inaddr, '\0', sizeof inaddr);
 
    inaddr.sin_family      = AF_INET;
@@ -702,8 +914,15 @@ int bind_port(const char *hostnam, int portnum, jb_socket *pfd)
       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)
+   {
+      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)
@@ -711,7 +930,11 @@ int bind_port(const char *hostnam, int portnum, jb_socket *pfd)
    if (fd < 0)
 #endif
    {
+#ifdef HAVE_GETADDRINFO
+      continue;
+#else
       return(-1);
+#endif
    }
 
 #ifndef _WIN32
@@ -730,7 +953,11 @@ int bind_port(const char *hostnam, int portnum, jb_socket *pfd)
    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();
@@ -739,15 +966,36 @@ int bind_port(const char *hostnam, int portnum, jb_socket *pfd)
       if (errno == EADDRINUSE)
 #endif
       {
+#ifdef HAVE_GETADDRINFO
+         freeaddrinfo(result);
+#endif
          close_socket(fd);
          return(-3);
       }
       else
       {
          close_socket(fd);
+#ifndef HAVE_GETADDRINFO
          return(-1);
       }
    }
+#else
+      }
+   }
+   else
+      /* 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;
+   }
+
+   freeaddrinfo(result);
+   if (rp == NULL)
+   {
+      /* All bind()s failed */
+      return(-1);
+   }
+#endif /* ndef HAVE_GETADDRINFO */
 
    while (listen(fd, MAX_LISTEN_BACKLOG) == -1)
    {
@@ -787,14 +1035,20 @@ int bind_port(const char *hostnam, int portnum, jb_socket *pfd)
  *********************************************************************/
 void get_host_information(jb_socket afd, char **ip_address, char **hostname)
 {
+#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)
@@ -804,7 +1058,8 @@ void get_host_information(jb_socket afd, char **ip_address, char **hostname)
    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)
    {
@@ -814,8 +1069,23 @@ void get_host_information(jb_socket afd, char **ip_address, char **hostname)
 
    if (!getsockname(afd, (struct sockaddr *) &server, &s_length))
    {
+      if (s_length > s_length_provided)
+      {
+         log_error(LOG_LEVEL_ERROR, "getsockname() truncated server address");
+         return;
+      }
+#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
       *ip_address = strdup(inet_ntoa(server.sin_addr));
-
+#endif /* HAVE_GETNAMEINFO */
       if (NULL == hostname)
       {
          /*
@@ -824,6 +1094,16 @@ void get_host_information(jb_socket afd, char **ip_address, char **hostname)
           */
          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);
+      }
+#else
 #if defined(HAVE_GETHOSTBYADDR_R_8_ARGS)
       gethostbyaddr_r((const char *)&server.sin_addr,
                       sizeof(server.sin_addr), AF_INET,
@@ -861,6 +1141,7 @@ void get_host_information(jb_socket afd, char **ip_address, char **hostname)
       {
          *hostname = strdup(host->h_name);
       }
+#endif /* else def HAVE_GETNAMEINFO */
    }
 
    return;
@@ -885,7 +1166,13 @@ void get_host_information(jb_socket afd, char **ip_address, char **hostname)
  *********************************************************************/
 int accept_connection(struct client_state * csp, jb_socket fd)
 {
+#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. */
@@ -914,8 +1201,21 @@ int accept_connection(struct client_state * csp, jb_socket fd)
 #endif
 
    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 */
 
    return 1;
 
@@ -1046,4 +1346,6 @@ unsigned long resolve_hostname_to_ip(const char *host)
   Local Variables:
   tab-width: 3
   end:
+
+  vim:softtabstop=3 shiftwidth=3
 */
diff --git a/jcc.c b/jcc.c
index 69b21f2..c8e9ea7 100644 (file)
--- a/jcc.c
+++ b/jcc.c
@@ -1,4 +1,4 @@
-const char jcc_rcs[] = "$Id: jcc.c,v 1.241 2009/04/11 10:37:23 fabiankeil Exp $";
+const char jcc_rcs[] = "$Id: jcc.c,v 1.242 2009/04/11 10:44:47 fabiankeil Exp $";
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/jcc.c,v $
@@ -33,6 +33,9 @@ const char jcc_rcs[] = "$Id: jcc.c,v 1.241 2009/04/11 10:37:23 fabiankeil Exp $"
  *
  * Revisions   :
  *    $Log: jcc.c,v $
+ *    Revision 1.242  2009/04/11 10:44:47  fabiankeil
+ *    Update a comment. We're not in Kansas anymore.
+ *
  *    Revision 1.241  2009/04/11 10:37:23  fabiankeil
  *    When dropping connections due to ACL, don't leak csp->ip_addr_str.
  *
@@ -2744,7 +2747,7 @@ static void chat(struct client_state *csp)
 
    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
@@ -4533,4 +4536,6 @@ static void listen_loop(void)
   Local Variables:
   tab-width: 3
   end:
+
+  vim:softtabstop=3 shiftwidth=3
 */
index 6282b31..76363eb 100644 (file)
--- a/loadcfg.c
+++ b/loadcfg.c
@@ -1,4 +1,4 @@
-const char loadcfg_rcs[] = "$Id: loadcfg.c,v 1.92 2009/03/18 20:43:19 fabiankeil Exp $";
+const char loadcfg_rcs[] = "$Id: loadcfg.c,v 1.93 2009/03/18 21:46:26 fabiankeil Exp $";
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/loadcfg.c,v $
@@ -35,6 +35,9 @@ const char loadcfg_rcs[] = "$Id: loadcfg.c,v 1.92 2009/03/18 20:43:19 fabiankeil
  *
  * Revisions   :
  *    $Log: loadcfg.c,v $
+ *    Revision 1.93  2009/03/18 21:46:26  fabiankeil
+ *    Revert the last commit as there's a better way.
+ *
  *    Revision 1.92  2009/03/18 20:43:19  fabiankeil
  *    Don't enable LOG_LEVEL_INFO by default and don't apply the user's
  *    debug settings until the logfile has been opened (if there is one).
@@ -832,7 +835,6 @@ struct configuration_spec * load_config(void)
     * Set to defaults
     */
    config->multi_threaded            = 1;
-   config->hport                     = HADDR_PORT;
    config->buffer_limit              = 4096 * 1024;
    config->usermanual                = strdup(USER_MANUAL_URL);
    config->proxy_args                = strdup("");
@@ -1041,6 +1043,12 @@ struct configuration_spec * load_config(void)
                   break;
                }
             }
+#ifdef HAVE_GETADDRINFO
+            else
+            {
+               cur_acl->wildcard_dst = 1;
+            }
+#endif /* def HAVE_GETADDRINFO */
 
             /*
              * Add it to the list.  Note we reverse the list to get the
@@ -1190,7 +1198,18 @@ struct configuration_spec * load_config(void)
             {
                cur_fwd->forward_host = strdup(p);
 
-               if (NULL != (p = strchr(cur_fwd->forward_host, ':')))
+               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);
@@ -1254,11 +1273,23 @@ struct configuration_spec * load_config(void)
             {
                cur_fwd->gateway_host = strdup(p);
 
-               if (NULL != (p = strchr(cur_fwd->gateway_host, ':')))
+               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);
                }
+
                if (cur_fwd->gateway_port <= 0)
                {
                   cur_fwd->gateway_port = 1080;
@@ -1272,7 +1303,18 @@ struct configuration_spec * load_config(void)
             {
                cur_fwd->forward_host = strdup(p);
 
-               if (NULL != (p = strchr(cur_fwd->forward_host, ':')))
+               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);
@@ -1342,11 +1384,23 @@ struct configuration_spec * load_config(void)
 
             cur_fwd->gateway_host = strdup(p);
 
-            if (NULL != (p = strchr(cur_fwd->gateway_host, ':')))
+            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);
             }
+
             if (cur_fwd->gateway_port <= 0)
             {
                cur_fwd->gateway_port = 1080;
@@ -1359,7 +1413,18 @@ struct configuration_spec * load_config(void)
             {
                cur_fwd->forward_host = strdup(p);
 
-               if (NULL != (p = strchr(cur_fwd->forward_host, ':')))
+               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);
@@ -1509,6 +1574,12 @@ struct configuration_spec * load_config(void)
                   break;
                }
             }
+#ifdef HAVE_GETADDRINFO
+            else
+            {
+               cur_acl->wildcard_dst = 1;
+            }
+#endif /* def HAVE_GETADDRINFO */
 
             /*
              * Add it to the list.  Note we reverse the list to get the
@@ -1848,18 +1919,20 @@ struct configuration_spec * load_config(void)
 
    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)
+      else if (NULL != (p = strchr(config->haddr, ':')) &&
+            0 < (config->hport = atoi(p + 1)))
+      {
+         *p = '\0';
+      }
+      else 
       {
-         *--p = ':';
          log_error(LOG_LEVEL_FATAL, "invalid bind port spec %s", config->haddr);
          /* Never get here - LOG_LEVEL_FATAL causes program exit */
       }
@@ -2035,4 +2108,6 @@ static void savearg(char *command, char *argument, struct configuration_spec * c
   Local Variables:
   tab-width: 3
   end:
+
+  vim:softtabstop=3 shiftwidth=3
 */
index b0e969b..19f7523 100644 (file)
--- a/project.h
+++ b/project.h
@@ -1,7 +1,7 @@
 #ifndef PROJECT_H_INCLUDED
 #define PROJECT_H_INCLUDED
 /** Version string. */
-#define PROJECT_H_VERSION "$Id: project.h,v 1.128 2009/03/07 13:09:17 fabiankeil Exp $"
+#define PROJECT_H_VERSION "$Id: project.h,v 1.129 2009/03/08 14:12:51 fabiankeil Exp $"
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/project.h,v $
@@ -37,6 +37,9 @@
  *
  * Revisions   :
  *    $Log: project.h,v $
+ *    Revision 1.129  2009/03/08 14:12:51  fabiankeil
+ *    All the CSP_FLAG_FOO bit masks should be unsigned ints.
+ *
  *    Revision 1.128  2009/03/07 13:09:17  fabiankeil
  *    Change csp->expected_content and_csp->expected_content_length from
  *    size_t to unsigned long long to reduce the likelihood of integer
 /* Needed for pcre choice */
 #include "config.h"
 
+#ifdef HAVE_GETADDRINFO
+/* Need for struct sockaddr_storage */
+#include <sys/socket.h>
+#endif
+
+
 /*
  * Include appropriate regular expression libraries.
  * Note that pcrs and pcre (native) are needed for cgi
@@ -858,16 +867,10 @@ typedef int jb_err;
 #define FOREVER 1
 
 /**
- * Default IP address to listen on, as a string.
- * Set to "127.0.0.1".
+ * Default TCP/IP address to listen on, as a string.
+ * Set to "127.0.0.1:8118".
  */
-#define HADDR_DEFAULT   "127.0.0.1"
-
-/**
- * Default port to listen on, as a number.
- * Set to 8118.
- */
-#define HADDR_PORT      8118
+#define HADDR_DEFAULT   "127.0.0.1:8118"
 
 
 /* Forward def for struct client_state */
@@ -1421,9 +1424,15 @@ struct client_state
    /** 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. */
    unsigned long ip_addr_long;
+#endif /* def HAVE_GETADDRINFO */
 
    /** The URL that was requested */
    struct http_request http[1];
@@ -1657,9 +1666,14 @@ struct re_filterfile_spec
  */
 struct access_control_addr
 {
+#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 */
 };
 
 /**
@@ -1671,6 +1685,9 @@ struct access_control_list
 {
    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
 
    short action;                       /**< ACL_PERMIT or ACL_DENY */
    struct access_control_list *next;   /**< The next entry in the ACL. */
@@ -1879,4 +1896,6 @@ struct configuration_spec
   Local Variables:
   tab-width: 3
   end:
+
+  vim:softtabstop=3 shiftwidth=3
 */
index ce12ecc..fa11f20 100644 (file)
@@ -1,4 +1,4 @@
-const char urlmatch_rcs[] = "$Id: urlmatch.c,v 1.46 2009/02/11 19:31:32 fabiankeil Exp $";
+const char urlmatch_rcs[] = "$Id: urlmatch.c,v 1.47 2009/03/02 19:18:10 fabiankeil Exp $";
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/urlmatch.c,v $
@@ -33,6 +33,10 @@ const char urlmatch_rcs[] = "$Id: urlmatch.c,v 1.46 2009/02/11 19:31:32 fabianke
  *
  * Revisions   :
  *    $Log: urlmatch.c,v $
+ *    Revision 1.47  2009/03/02 19:18:10  fabiankeil
+ *    Streamline parse_http_request()'s prototype. As
+ *    cparser pointed out it doesn't actually use csp.
+ *
  *    Revision 1.46  2009/02/11 19:31:32  fabiankeil
  *    Reject request lines that end with neither HTTP/1.0 nor HTTP/1.1.
  *
@@ -536,8 +540,40 @@ jb_err parse_http_url(const char *url, struct http_request *http, int require_pr
          host = buf;
       }
 
+      /* Move after hostname before port number */
+      if (*host == '[')
+      {
+         /* Numeric IPv6 address delimited by brackets */
+         host++;
+         port = strchr(host, ']');
+
+         if (port == NULL)
+         {
+            /* Missing closing bracket */
+            freez(buf);
+            return JB_ERR_PARSE;
+         }
+
+         *port++='\0';
+         
+         if (*port == '\0')
+         {
+            port = NULL;
+         }
+         else if (*port != ':')
+         {
+            /* Garbage after closing bracket */
+            freez(buf);
+            return JB_ERR_PARSE;
+         }
+      }
+      else
+      {
+         /* Plain non-escaped hostname */ 
+         port = strchr(host, ':');
+      }
+
       /* check if url contains port */
-      port = strchr(host, ':');
       if (port != NULL)
       {
          /* Contains port */
@@ -840,7 +876,31 @@ static jb_err compile_url_pattern(struct url_spec *url, char *buf)
       *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';
@@ -1445,4 +1505,6 @@ int match_portlist(const char *portlist, int port)
   Local Variables:
   tab-width: 3
   end:
+
+  vim:softtabstop=3 shiftwidth=3
 */