From: Fabian Keil <fk@fabiankeil.de> Date: Fri, 17 Apr 2009 11:27:49 +0000 (+0000) Subject: Petr Pisar's privoxy-3.0.12-ipv6-3.diff. X-Git-Tag: v_3_0_13~129 X-Git-Url: http://www.privoxy.org/gitweb/%22https:/@default-cgi@/faq/user-manual/@default-cgi@toggle?a=commitdiff_plain;h=df9616f1dacac74ba9469d6c334d0105a6effe15;p=privoxy.git Petr Pisar's privoxy-3.0.12-ipv6-3.diff. --- diff --git a/configure.in b/configure.in index b2c38fd4..8c4fbac4 100644 --- a/configure.in +++ b/configure.in @@ -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 ================================================================= diff --git a/doc/source/p-config.sgml b/doc/source/p-config.sgml index 2d8c1817..9ed8f15c 100644 --- a/doc/source/p-config.sgml +++ b/doc/source/p-config.sgml @@ -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 <[2-3][0-9a-f][0-9a-f][0-9a-f]:*> . +</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 diff --git a/doc/source/user-manual.sgml b/doc/source/user-manual.sgml index 024d350e..ac7ad28f 100644 --- a/doc/source/user-manual.sgml +++ b/doc/source/user-manual.sgml @@ -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><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 @@ 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><</literal>, <literal>></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><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> @@ -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. diff --git a/filters.c b/filters.c index 18ef5b35..43b002f2 100644 --- 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 */ diff --git a/jbsockets.c b/jbsockets.c index f7443ec9..76f1cb8c 100644 --- a/jbsockets.c +++ b/jbsockets.c @@ -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 69b21f2b..c8e9ea75 100644 --- 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 */ diff --git a/loadcfg.c b/loadcfg.c index 6282b314..76363eb7 100644 --- 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 */ diff --git a/project.h b/project.h index b0e969b3..19f7523c 100644 --- 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 @@ -707,6 +710,12 @@ /* 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 */ diff --git a/urlmatch.c b/urlmatch.c index ce12ecc8..fa11f204 100644 --- a/urlmatch.c +++ b/urlmatch.c @@ -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 */