From: Roland Rosenfeld Date: Sat, 9 Sep 2006 13:49:59 +0000 (+0000) Subject: - Add patches from Debian release 3.0.3-2-2 X-Git-Tag: v_3_0_5~59 X-Git-Url: http://www.privoxy.org/gitweb/?p=privoxy.git;a=commitdiff_plain;h=ffbf7b982b3446ab0d2ac6db5e244f785882db7e - Add patches from Debian release 3.0.3-2-2 - Adapt Debian patches to the upcoming 3.0.4 release --- diff --git a/debian/changelog b/debian/changelog index 804eefcd..8e0fdb03 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,8 +1,40 @@ +privoxy (3.0.4.cvs20060909-1) UNRELEASED; urgency=low + + * New upstream CVS snapshot as of 2006-09-09. + * Adapted all patches to this version. + * The following patches are incorporated upstream now, so they are no + longer needed: 01_local_usermanual.dpatch, 08_log_pthread.dpatch, + 09_no_identity.dpatch, 12_multiple-filters.dpatch, 13_memory.dpatch, + 18_dns_retry.dpatch. + * 20_makefile_fixup.dpatch: Fix a syntax error in the GNUmakefile.in. + + -- Roland Rosenfeld Sat, 9 Sep 2006 15:26:34 +0200 + +privoxy (3.0.3-2-2) unstable; urgency=low + + * Upgrade to Standards-Version 3.7.2 (no changes). + * 17_502_no_such_domain.dpatch: Changes the 404 HTTP status code of the + "No such Domain" template to 502 Bad Gateway, which seems to be more + correct according to http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html + (Closes: #380389). + * Disable filter{js-annoyances} and filter{unsolicited-popups} for + .cnrs.fr and blogs.msdn.com, because these sites consume very much CPU + time otherwise (Closes: #377843). + * 18_dns_retry.dpatch by Fabian Keil : 10 retries + before giving up DNS lookup. This hopefully Closes: #335660. + * 19_manpage_fixup.dpatch: + - Convert Latin-1 char á to groff eqivalent in man page. + - Quote minus signs to differenciate them from hyphens. + * Do not filter{banners-by-size} on .w3.org pages, because these often + contain validator icons (Closes: #319025). + + -- Roland Rosenfeld Sat, 5 Aug 2006 15:15:17 +0200 + privoxy (3.0.3-2-1) unstable; urgency=low * New upstream version 3.0.3-2. * Add debian/watch file. - * Remove parts of 13_memory.dpatch, which seem to be free too much + * Remove parts of 13_memory.dpatch, which seems to free too much memory (Closes: #353110, #354611). -- Roland Rosenfeld Mon, 27 Feb 2006 23:28:52 +0100 diff --git a/debian/control b/debian/control index cd43c6c7..f33f074a 100644 --- a/debian/control +++ b/debian/control @@ -3,7 +3,7 @@ Section: web Priority: optional Maintainer: Roland Rosenfeld Build-Depends: debhelper (>= 5.0.0), autoconf, autotools-dev, libpcre3-dev, jade, docbook-dsssl, w3m, sp, sgmlspl, groff, htmldoc (>= 1.8.25-1), man2html, dpatch -Standards-Version: 3.6.2 +Standards-Version: 3.7.2 Package: privoxy Architecture: any diff --git a/debian/patches/00list b/debian/patches/00list index 6c2fb3f7..c2254958 100644 --- a/debian/patches/00list +++ b/debian/patches/00list @@ -1,14 +1,21 @@ -01_local_usermanual.dpatch +# 01_local_usermanual.dpatch # now upstream 02_linkcolor.dpatch +# 03_ipv6.dpatch # incompatible with 18_dns_retry.dpatch 04_nomultiproxy.dpatch 05_defaut_action.dpatch 06_8bit_manual.dpatch 07_typos.dpatch -08_log_pthread.dpatch -09_no_identity.dpatch +# 08_log_pthread.dpatch # now upstream +# 09_no_identity.dpatch # now upstream 10_backup_doc.dpatch 11_backup_autotools.dpatch -12_multiple-filters.dpatch -13_memory.dpatch +# 12_multiple-filters.dpatch # now upstream +# 13_memory.dpatch # new upstream 14_config.dpatch 15_mansection8.dpatch +# 16_gzip.dpatch # still broken. +17_502_no_such_domain.dpatch +# 18_dns_retry.dpatch # now upstream +19_manpage_fixup.dpatch +20_makefile_fixup.dpatch +21_version_3.0.4.dpatch diff --git a/debian/patches/01_local_usermanual.dpatch b/debian/patches/01_local_usermanual.dpatch index a5c51fa6..faa57228 100644 --- a/debian/patches/01_local_usermanual.dpatch +++ b/debian/patches/01_local_usermanual.dpatch @@ -7,9 +7,9 @@ @DPATCH@ diff -urNad privoxy~/cgi.c privoxy/cgi.c ---- privoxy~/cgi.c 2006-02-11 23:44:26.000000000 +0100 -+++ privoxy/cgi.c 2006-02-11 23:44:34.000000000 +0100 -@@ -609,6 +609,9 @@ +--- privoxy~/cgi.c ++++ privoxy/cgi.c +@@ -616,6 +616,9 @@ { "t", cgi_transparent_image, NULL, TRUE /* Send a transparent image (short name) */ }, @@ -19,7 +19,7 @@ diff -urNad privoxy~/cgi.c privoxy/cgi.c { NULL, /* NULL Indicates end of list and default page */ cgi_error_404, NULL, TRUE /* Unknown CGI page */ } -@@ -821,21 +824,28 @@ +@@ -828,21 +831,28 @@ { return cgi_error_memory(); } @@ -57,7 +57,7 @@ diff -urNad privoxy~/cgi.c privoxy/cgi.c } /* -@@ -1597,7 +1607,13 @@ +@@ -1604,7 +1614,13 @@ if (!item) return NULL; result = strdup(""); -@@ -2171,7 +2187,11 @@ +@@ -2193,7 +2209,11 @@ if (!err) err = map(exports, "default-cgi", 1, html_encode(CGI_PREFIX), 0); if (!err) err = map(exports, "menu", 1, make_menu(caller), 0); if (!err) err = map(exports, "code-status", 1, CODE_STATUS, 1); @@ -86,9 +86,9 @@ diff -urNad privoxy~/cgi.c privoxy/cgi.c #ifdef FEATURE_TOGGLE if (!err) err = map_conditional(exports, "enabled-display", global_toggle_state); diff -urNad privoxy~/cgisimple.c privoxy/cgisimple.c ---- privoxy~/cgisimple.c 2006-02-11 23:44:26.000000000 +0100 -+++ privoxy/cgisimple.c 2006-02-11 23:44:34.000000000 +0100 -@@ -642,6 +642,89 @@ +--- privoxy~/cgisimple.c ++++ privoxy/cgisimple.c +@@ -660,6 +660,89 @@ return JB_ERR_OK; } @@ -179,9 +179,9 @@ diff -urNad privoxy~/cgisimple.c privoxy/cgisimple.c /********************************************************************* diff -urNad privoxy~/cgisimple.h privoxy/cgisimple.h ---- privoxy~/cgisimple.h 2006-02-11 23:44:26.000000000 +0100 -+++ privoxy/cgisimple.h 2006-02-11 23:44:34.000000000 +0100 -@@ -128,6 +128,9 @@ +--- privoxy~/cgisimple.h ++++ privoxy/cgisimple.h +@@ -132,6 +132,9 @@ extern jb_err cgi_send_stylesheet(struct client_state *csp, struct http_response *rsp, const struct map *parameters); @@ -192,9 +192,9 @@ diff -urNad privoxy~/cgisimple.h privoxy/cgisimple.h #ifdef FEATURE_GRACEFUL_TERMINATION extern jb_err cgi_die (struct client_state *csp, diff -urNad privoxy~/loadcfg.c privoxy/loadcfg.c ---- privoxy~/loadcfg.c 2006-02-11 23:44:26.000000000 +0100 -+++ privoxy/loadcfg.c 2006-02-11 23:44:34.000000000 +0100 -@@ -1579,7 +1579,13 @@ +--- privoxy~/loadcfg.c ++++ privoxy/loadcfg.c +@@ -1605,7 +1605,13 @@ * link to it's section in the user-manual */ buf = strdup("\n
+## +## All lines beginning with `## DP:' are a description of the patch. +## DP: privoxy_CVS_20030523_ipv6_5.patch.bz2 from +## DP: ftp://ftp.deepspace6.net/pub/ds6/sources/privoxy/privoxy_CVS_20030523_ipv6_5.patch.bz2 +## DP: adapted to the 3.0 branch of privoxy by Roland Rosenfeld + +@DPATCH@ +diff -urNad privoxy~/GNUmakefile.in privoxy/GNUmakefile.in +--- privoxy~/GNUmakefile.in ++++ privoxy/GNUmakefile.in +@@ -187,7 +187,7 @@ + C_SRC = actions.c cgi.c cgiedit.c cgisimple.c deanimate.c encode.c \ + errlog.c filters.c gateway.c jbsockets.c jcc.c killpopup.c \ + list.c loadcfg.c loaders.c miscutil.c parsers.c ssplit.c \ +- urlmatch.c ++ urlmatch.c addrlist.c jb_socket_set.c + + C_OBJS = $(C_SRC:.c=.@OBJEXT@) + C_HDRS = $(C_SRC:.c=.h) project.h actionlist.h +@@ -241,7 +241,7 @@ + SPECIAL_CFLAGS = @SPECIAL_CFLAGS@ + + # Add your flags here +-OTHER_CFLAGS = ++OTHER_CFLAGS = -DINET6 + + CFLAGS = @CFLAGS@ @CPPFLAGS@ $(OTHER_CFLAGS) $(SPECIAL_CFLAGS) -Wall \ + @STATIC_PCRE_ONLY@ -Ipcre +diff -urNad privoxy~/addrlist.c privoxy/addrlist.c +--- privoxy~/addrlist.c ++++ privoxy/addrlist.c +@@ -0,0 +1,198 @@ ++const char addrlist_rcs[] = "$Id: $"; ++/********************************************************************* ++ * ++ * File : $Source: $ ++ * ++ * Purpose : Declares functions to handle lists of network addresses. ++ * Functions declared include: ++ * `destroy_addr_list', head_addr_list and `tail_addr_list' ++ * ++ * Copyright : Written by and Copyright (C) 2002 Lionel Elie Mamane ++ * ++ * ++ * This program is free software; you can redistribute it ++ * and/or modify it under the terms of the GNU General ++ * Public License as published by the Free Software ++ * Foundation; either version 2 of the License, or (at ++ * your option) any later version. ++ * ++ * This program is distributed in the hope that it will ++ * be useful, but WITHOUT ANY WARRANTY; without even the ++ * implied warranty of MERCHANTABILITY or FITNESS FOR A ++ * PARTICULAR PURPOSE. See the GNU General Public ++ * License for more details. ++ * ++ * The GNU General Public License should be included with ++ * this file. If not, you can view it at ++ * http://www.gnu.org/copyleft/gpl.html ++ * or write to the Free Software Foundation, Inc., 59 ++ * Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * Revisions : ++ * $Log: addrlist.c,v $ ++ * ++ *********************************************************************/ ++ ++#include "addrlist.h" ++#include ++#include ++#include ++#include ++ ++/********************************************************************* ++ * ++ * Function : acceptable ++ * ++ * Description : Test wheter an address is acceptable for our use ++ * Currently, this means either an IPv4 or an IPv6 address ++ * ++ * Parameters : ++ * 0 : addr = the address to test ++ * ++ * Returns : 0 = false / no ++ * anything else = true / yes ++ * ++ *********************************************************************/ ++static int acceptable (struct sockaddr_storage *addr) ++{ ++ switch(addr->ss_family) ++ { ++ case AF_INET: ++#ifdef INET6 ++ case AF_INET6: ++#endif ++ return !0; ++ default: ++ return 0; ++ } ++} ++ ++/********************************************************************* ++ * ++ * Function : skim ++ * ++ * Description : Get the first acceptable address in head position ++ * Assumes there is one ++ * ++ * Parameters : ++ * 0 : l = the list to skim ++ * ++ * Returns : the skimmed list ++ * ++ *********************************************************************/ ++static addr_list *skim (addr_list *l) ++{ ++ if (acceptable((struct sockaddr_storage*)l->ai_addr)) ++ return l; ++ return skim(l->ai_next); ++} ++ ++/********************************************************************* ++ * ++ * Function : tail_addr_list ++ * ++ * Description : Get the tail of an address list ++ * ++ * Parameters : ++ * 0 : l = the list to get the tail of ++ * ++ * Returns : the tail of the list ++ * If the list has no tail (i.e. is nil), unspecified ++ * behaviour ++ * ++ *********************************************************************/ ++addr_list *tail_addr_list(addr_list *l) ++{ ++ return skim(l)->ai_next; ++} ++ ++/********************************************************************* ++ * ++ * Function : head_addr_list ++ * ++ * Description : Get the head of an address list ++ * ++ * Parameters : ++ * 0 : l = the list to get the head of ++ * ++ * Returns : the head of the list ++ * If the list has no head (i.e. is nil), unspecified ++ * behaviour ++ * ++ *********************************************************************/ ++struct sockaddr_storage *head_addr_list(addr_list *l) ++{ ++ return (struct sockaddr_storage *)skim(l)->ai_addr; ++} ++ ++/********************************************************************* ++ * ++ * Function : cpy_head_addr_list ++ * ++ * Description : Copy the head of an address list to the given destination ++ * ++ * Parameters : ++ * 0 : l = the list to get the head of ++ * 1 : r = where to put the result ++ * ++ * Returns : Nothing ++ * If the list has no head (i.e. is nil), unspecified ++ * behaviour ++ * ++ *********************************************************************/ ++void cpy_head_addr_list(addr_list *l, struct sockaddr_storage *r, size_t *addrlen) ++{ ++ addr_list *sl = skim(l); ++ memcpy(r, sl->ai_addr, sl->ai_addrlen); ++ *addrlen = sl->ai_addrlen; ++} ++ ++/********************************************************************* ++ * ++ * Function : destroy_addr_list ++ * ++ * Description : Unallocate memory allocated to an address list ++ * ++ * Parameters : ++ * 0 : l = the list to unallocate ++ * ++ * Returns : nothing ++ * ++ *********************************************************************/ ++void destroy_addr_list(addr_list *l) ++{ ++ freeaddrinfo(l); ++} ++ ++/********************************************************************* ++ * ++ * Function : is_nil_addr_list ++ * ++ * Description : Test wheter a list is nil (empty) ++ * ++ * Parameters : ++ * 0 : l = the list to test ++ * ++ * Returns : 0 = false if list has a head, ++ * anything else = true if list is nil ++ * ++ *********************************************************************/ ++int is_nil_addr_list(addr_list *l) ++{ ++ /* We are searching for a witness of non-nilness (modulo acceptability) ++ * If none is found, the list is nil ++ */ ++ if (l==NULL) ++ /* Empty list*/ ++ return !0; ++ if (acceptable(head_addr_list(l))) ++ /* Witness found */ ++ return 0; ++ return is_nil_addr_list(l->ai_next); ++} ++ ++/* ++ Local Variables: ++ tab-width: 3 ++ end: ++*/ +diff -urNad privoxy~/addrlist.h privoxy/addrlist.h +--- privoxy~/addrlist.h ++++ privoxy/addrlist.h +@@ -0,0 +1,56 @@ ++#ifndef ADDR_LIST_H_INCLUDED ++#define ADDR_LIST_H_INCLUDED ++#define ADDR_LIST_H_VERSION "$Id: $" ++/********************************************************************* ++ * ++ * File : $Source: $ ++ * ++ * Purpose : Declares functions to handle lists of network addresses. ++ * Functions declared include: ++ * `destroy_addr_list', head_addr_list and `tail_addr_list' ++ * ++ * Copyright : Written by and Copyright (C) 2002 Lionel Elie Mamane ++ * ++ * ++ * This program is free software; you can redistribute it ++ * and/or modify it under the terms of the GNU General ++ * Public License as published by the Free Software ++ * Foundation; either version 2 of the License, or (at ++ * your option) any later version. ++ * ++ * This program is distributed in the hope that it will ++ * be useful, but WITHOUT ANY WARRANTY; without even the ++ * implied warranty of MERCHANTABILITY or FITNESS FOR A ++ * PARTICULAR PURPOSE. See the GNU General Public ++ * License for more details. ++ * ++ * The GNU General Public License should be included with ++ * this file. If not, you can view it at ++ * http://www.gnu.org/copyleft/gpl.html ++ * or write to the Free Software Foundation, Inc., 59 ++ * Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * Revisions : ++ * $Log: addrlist.h,v $ ++ * ++ *********************************************************************/ ++ ++#include ++ ++typedef struct addrinfo addr_list; ++ ++addr_list *tail_addr_list(addr_list *l); ++struct sockaddr_storage *head_addr_list(addr_list *l); ++void cpy_head_addr_list(addr_list *l, struct sockaddr_storage *r, size_t *addrlen); ++void destroy_addr_list(addr_list *l); ++int is_nil_addr_list(addr_list *l); ++ ++#define freez_addr_list(X) { if(X) { destroy_addr_list(X); X = NULL ; } } ++ ++#endif /* ndef LIST_H_INCLUDED */ ++ ++/* ++ Local Variables: ++ tab-width: 3 ++ end: ++*/ +diff -urNad privoxy~/cgi.c privoxy/cgi.c +--- privoxy~/cgi.c ++++ privoxy/cgi.c +@@ -14,6 +14,9 @@ + * Copyright : Written by and Copyright (C) 2001 the SourceForge + * Privoxy team. http://www.privoxy.org/ + * ++ * Modified by Lionel Elie Mamane ++ * for IPv6 support on 8 December 2002, 24 January 2003. ++ * + * Based on the Internet Junkbuster originally written + * by and Copyright (C) 1997 Anonymous Coders and + * Junkbusters Corporation. http://www.junkbusters.com +@@ -2167,7 +2170,6 @@ + *********************************************************************/ + struct map *default_exports(const struct client_state *csp, const char *caller) + { +- char buf[20]; + jb_err err; + struct map * exports; + int local_help_exists = 0; +@@ -2199,8 +2201,7 @@ + if (!err) err = map_block_killer(exports, "can-toggle"); + #endif + +- snprintf(buf, 20, "%d", csp->config->hport); +- if (!err) err = map(exports, "my-port", 1, buf, 1); ++ if (!err) err = map(exports, "my-port", 1, csp->my_port_str, 1); + + if(!strcmp(CODE_STATUS, "stable")) + { +diff -urNad privoxy~/errlog.c privoxy/errlog.c +--- privoxy~/errlog.c ++++ privoxy/errlog.c +@@ -679,6 +679,13 @@ + break; + case 'E': + /* Non-standard: Print error code from errno */ ++ /* TODO ++ * This is not only not standard, but clashes ++ * with the E modifier on the GNU (and possibly ++ * other systems): It means double (floating point) ++ * number in exponential notation, with capital E ++ * for mantiss / exponenent separator ++ */ + #ifdef _WIN32 + ival = WSAGetLastError(); + sval = w32_socket_strerr(ival, tempbuf); +diff -urNad privoxy~/filters.c privoxy/filters.c +--- privoxy~/filters.c ++++ privoxy/filters.c +@@ -14,6 +14,9 @@ + * Copyright : Written by and Copyright (C) 2001 the SourceForge + * Privoxy team. http://www.privoxy.org/ + * ++ * Modified by Lionel Elie Mamane ++ * for IPv6 support on 8 December 2002, 24 January 2003. ++ * + * Based on the Internet Junkbuster originally written + * by and Copyright (C) 1997 Anonymous Coders and + * Junkbusters Corporation. http://www.junkbusters.com +@@ -427,6 +430,9 @@ + #include + #include + #include ++#ifdef INET6 ++#include ++#endif + + #ifndef _WIN32 + #ifndef __OS2__ +@@ -461,17 +467,119 @@ + + const char filters_h_rcs[] = FILTERS_H_VERSION; + +-/* Fix a problem with Solaris. There should be no effect on other +- * platforms. +- * Solaris's isspace() is a macro which uses it's argument directly +- * as an array index. Therefore we need to make sure that high-bit +- * characters generate +ve values, and ideally we also want to make +- * the argument match the declared parameter type of "int". +- */ +-#define ijb_isdigit(__X) isdigit((int)(unsigned char)(__X)) ++#ifdef FEATURE_ACL ++/********************************************************************* ++ * ++ * Function : addr_equal_under_mask ++ * ++ * Description : Are these addresses equal modulo this mask? ++ * Assumes the second argument is already in ++ * mask-normal form ++ * ++ * Parameters : ++ * 0 : addr1 = First address to compare ++ * 1 : addr2 = Second address to compare ++ * MUST be in mask-normal form ++ * 2 : mask = for IPv4 addresses, a bitmask ++ * for IPv6 addresses, a prefixlen in bits ++ * ++ * Returns : 0 = FALSE (not equal) and non-zero = TRUE (equal) ++ * ++ *********************************************************************/ ++static ++int ++addr_equal_under_mask(struct sockaddr_storage *addr1, struct sockaddr_storage *addr2, unsigned long mask) ++{ ++ if (!mask) ++ return 1; + ++ /* only identical families can be compared */ ++ /* TODO: Should we code the special case of "IPv4 addresses as IPv6 addresses"? */ ++ if (addr1->ss_family != addr2-> ss_family) ++ { ++ /*fprintf(stderr, "equal_under_mask: diff sa_family: %d %d\n", ++ sa1->sa_family, sa2-> sa_family); */ ++ return 0; ++ } ++ ++ switch (addr1->ss_family) ++ { ++ case AF_INET: ++ { ++ /* IPv4 - mask is a bitmask */ ++ struct sockaddr_in *sin1 = (struct sockaddr_in *)addr1; ++ struct sockaddr_in *sin2 = (struct sockaddr_in *)addr2; ++ ++ /*fprintf(stderr, "AF_INET: %08x %08x %08x\n", ++ sin1->sin_addr.s_addr, ++ sin2->sin_addr.s_addr, ++ mask); */ ++ return (sin1->sin_addr.s_addr & mask) == sin2->sin_addr.s_addr; ++ } ++ break; ++#ifdef INET6 ++ case AF_INET6: ++ { ++ /* IPv6 - mask is a prefixlength in bits. */ ++ struct sockaddr_in6 *sin1 = (struct sockaddr_in6 *)addr1; ++ struct sockaddr_in6 *sin2 = (struct sockaddr_in6 *)addr2; ++ char bitmask; ++ char *a1, *a2; ++ const int maskbytes = mask / 8; ++ static char m[] = { 0x00, 0x80, 0xC0, 0xE0, ++ 0xF0, 0xF8, 0xFC, 0xFE }; ++/* { */ ++/* int i; */ ++/* fprintf(stderr, "PF_INET6: "); */ ++/* for (i = 0; i < 16; i++) { */ ++/* fprintf(stderr, "%02x ", sin1->sin6_addr.s6_addr[i]); */ ++/* } */ ++/* fprintf(stderr, " "); */ ++/* for (i = 0; i < 16; i++) { */ ++/* fprintf(stderr, "%02x ", sin2->sin6_addr.s6_addr[i]); */ ++/* } */ ++/* fprintf(stderr, "mask %d scopeids %x %x\n", mask, sin1->sin6_scope_id, sin2->sin6_scope_id); */ ++/* } */ ++ /* should we compare scope ids and such too? */ ++ /* ++ * LEM: I see no reason for this comparison ++ * Quite the contrary: A client coming to us with ++ * a small-scope address should be able to a bigger-scope ++ * address. ++ */ ++/* if (sin1->sin6_scope_id != sin2->sin6_scope_id) */ ++/* return 0; */ ++ ++ if (mask > 128ul) ++ { ++ log_error(LOG_LEVEL_ERROR, "%s%d", "Tried to compare IPv6 addresses with invalid prefixlen: ", mask); ++ return 0; ++ } ++ ++ a1 = sin1->sin6_addr.s6_addr; ++ a2 = sin2->sin6_addr.s6_addr; ++ ++ if (memcmp(a1, a2, maskbytes) != 0) ++ return 0; ++ ++ mask %= 8; ++ /* This special case is necessary for when mask==128 ++ else, we would go over the array size in a1/a2 ++ */ ++ if (mask==0) ++ return 1; ++ ++ bitmask = m[mask]; ++ ++ return (a1[maskbytes] & bitmask) == a2[maskbytes]; ++ } ++ break; ++#endif ++ default: ++ return 0; ++ } ++} + +-#ifdef FEATURE_ACL + /********************************************************************* + * + * Function : block_acl +@@ -501,7 +609,7 @@ + /* search the list */ + while (acl != NULL) + { +- if ((csp->ip_addr_long & acl->src->mask) == acl->src->addr) ++ if (addr_equal_under_mask(&csp->ip_addr_addr, &acl->src->addr, acl->src->mask)) + { + if (dst == NULL) + { +@@ -511,8 +619,8 @@ + return(0); + } + } +- else if ( ((dst->addr & acl->dst->mask) == acl->dst->addr) +- && ((dst->port == acl->dst->port) || (acl->dst->port == 0))) ++ else if ( addr_equal_under_mask(&dst->addr, &acl->dst->addr, acl->dst->mask) ++ && ((dst->port == acl->dst->port) || (acl->dst->port == 0))) + { + if (acl->action == ACL_PERMIT) + { +@@ -531,81 +639,249 @@ + + } + +- + /********************************************************************* + * +- * Function : acl_addr ++ * Function : fill_acl_addr_mask + * +- * Description : Called from `load_config' to parse an ACL address. ++ * Description : Fill in the mask-related members of a ++ * struct access_control_addr + * + * Parameters : +- * 1 : aspec = String specifying ACL address. +- * 2 : aca = struct access_control_addr to fill in. ++ * 0 : aca = struct access_control_addr to fill in. ++ * 1 : masklength = mask length. + * +- * Returns : 0 => Ok, everything else is an error. ++ * Returns : nothing + * + *********************************************************************/ +-int acl_addr(char *aspec, struct access_control_addr *aca) ++void fill_acl_addr_mask(struct access_control_addr *aca, int masklength) + { +- int i, masklength, port; +- char *p; ++ int pf; + +- masklength = 32; +- port = 0; ++ pf = aca->addr.ss_family; + +- if ((p = strchr(aspec, '/')) != NULL) ++ switch (pf) + { +- *p++ = '\0'; +- +- if (ijb_isdigit(*p) == 0) ++ case PF_INET: ++ /* build the netmask */ ++ if (masklength == -1) ++ masklength = 32; ++ aca->mask = 0; ++ for(pf=1; pf <= masklength ; ++pf) + { +- return(-1); ++ aca->mask |= (1 << (32 - pf)); + } +- masklength = atoi(p); +- } ++ aca->mask = htonl(aca->mask); ++ ++ /* now mask off the host portion of the ip address ++ * (i.e. save on the network portion of the address). ++ */ ++ ((struct sockaddr_in*) &aca->addr)->sin_addr.s_addr &= aca->mask; ++ aca->port = ((struct sockaddr_in*) &aca->addr)->sin_port; ++ break; ++#ifdef INET6 ++ case PF_INET6: ++ { ++ static char m[] = { 0x00, 0x80, 0xC0, 0xE0, ++ 0xF0, 0xF8, 0xFC, 0xFE }; ++ int i; ++ struct sockaddr_in6 *sa6 = (struct sockaddr_in6*)&aca->addr; + +- if ((masklength < 0) || (masklength > 32)) +- { +- return(-1); ++ aca->mask = (masklength == -1) ? masklength : 128 ; ++ /* now mask off the host portion of the ip address ++ * (i.e. save on the network portion of the address). ++ */ ++ i = aca->mask / 8; ++ if (i < 16) ++ { ++ sa6->sin6_addr.s6_addr[i] &= m[aca->mask % 8]; ++ /* The following loop is not strictly necessary, ++ because of the way addr_equal_under_mask is ++ written. Better safe than sorry, though: ++ New code might make the full mask-normal ++ form assumption. ++ */ ++ for(++i; i < 16 ; ++i) ++ sa6->sin6_addr.s6_addr[i] = 0; ++ } ++ aca -> port = sa6->sin6_port; ++ break; ++ } ++#endif ++ default: ++ /* FATAL because access_control_addr's are created only with adresses ++ deemed 'acceptable' by the addr_list stuff, thus currently IPv4 and ++ IPv6. ++ */ ++ log_error(LOG_LEVEL_FATAL,"%s%d","Unknown address family in ACL address: ",pf); + } ++} + +- if ((p = strchr(aspec, ':')) != NULL) +- { +- *p++ = '\0'; ++/********************************************************************* ++ * ++ * Function : acl_addrs ++ * ++ * Description : Parse an ACL address (adress + mask prefix) ++ * Resolve the parsed address ++ * Describe errors in *proxy_args. ++ * ++ * Parameters : ++ * 0 : aspec = the string containing the ACL address/mask ++ * 1 : masklength = pointer used to return the mask ++ * 2 : proxy_args = Pointer to string to append description of errors to. ++ * 3 : type = type of ACL adress (source / destination). ++ * Used for error reporting. ++ * ++ * Returns : the list of adresses the ACL address resolves to ++ * ++ *********************************************************************/ ++static addr_list *acl_addrs(char *aspec, int *masklength, char**proxy_args, const char *type) ++{ ++ char *host; ++ char *port; ++ int pf; + +- if (ijb_isdigit(*p) == 0) +- { +- return(-1); +- } +- port = atoi(p); ++ pf = -1; ++ if (parse_pf_ip_netmask(aspec, &host, &port, &pf, masklength) != 0) ++ { ++ log_error(LOG_LEVEL_ERROR, "Invalid %s IP for (deny|permit)-access " ++ "directive in configuration file: \"%s\"", type, aspec); ++ string_append(proxy_args,"
\nWARNING: Invalid "); ++ string_append(proxy_args, type); ++ string_append(proxy_args," IP for (deny|permit)-access directive" ++ " in configuration file: \""); ++ string_append(proxy_args, aspec); ++ string_append(proxy_args,"\"

\n"); ++ return NULL; + } + +- aca->port = port; ++ return resolve_hostname_to_ip(host, port, pf); ++} + +- aca->addr = ntohl(resolve_hostname_to_ip(aspec)); ++/********************************************************************* ++ * ++ * Function : add_one_to_acl_list ++ * ++ * Description : Add one entry to an access_control_list. ++ * ++ * Parameters : ++ * 0 : l = the list to add to ++ * 1 : action = ACL_DENY or ACL_PERMIT ++ * 2 : src_addrs = the head of this list will be used as source ++ * in the ACL entry. ++ * 3 : dst_addrs = the head of this list will be used as destination ++ * in the ACL entry. ++ * NULL for none ++ * 4 : src_masklength = mask length for the source ++ * 5 : src_masklength = mask length for the destination ++ * ++ * Returns : the new list ++ * ++ *********************************************************************/ ++struct access_control_list *add_one_to_acl_list(struct access_control_list *l, short action, ++ addr_list *src_addrs, addr_list *dst_addrs, ++ int src_masklength, int dst_masklength) ++{ ++ struct access_control_list *cur_acl; ++ /* allocate a new node */ ++ cur_acl = (struct access_control_list *) zalloc(sizeof(*cur_acl)); + +- if (aca->addr == INADDR_NONE) ++ if (cur_acl == NULL) + { +- return(-1); ++ log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration"); ++ /* Never get here - LOG_LEVEL_FATAL causes program exit */ ++ return l; + } + +- /* build the netmask */ +- aca->mask = 0; +- for (i=1; i <= masklength ; i++) ++ cur_acl->action = action; ++ ++ cpy_head_addr_list(src_addrs, &cur_acl->src->addr, &cur_acl->src->addrlen); ++ fill_acl_addr_mask(cur_acl->src, src_masklength); ++ if (dst_addrs != NULL) + { +- aca->mask |= (1 << (32 - i)); ++ cpy_head_addr_list(dst_addrs, &cur_acl->dst->addr, &cur_acl->dst->addrlen); ++ fill_acl_addr_mask(cur_acl->src, src_masklength); + } + +- /* now mask off the host portion of the ip address +- * (i.e. save on the network portion of the address). ++ /* ++ * Add it to the list. Note we reverse the list to get the ++ * behaviour the user expects. With both the ACL and ++ * actions file, the last match wins. However, the internal ++ * implementations are different: The actions file is stored ++ * in the same order as the file, and scanned completely. ++ * With the ACL, we reverse the order as we load it, then ++ * when we scan it we stop as soon as we get a match. + */ +- aca->addr = aca->addr & aca->mask; ++ cur_acl->next = l; + +- return(0); ++ return cur_acl; ++} ++ ++/********************************************************************* ++ * ++ * Function : add_to_acl_list ++ * ++ * Description : Add entries to an access_control_list. ++ * Describe errors in *proxy_args. ++ * ++ * Parameters : ++ * 0 : l = the list to add to ++ * 1 : action = ACL_DENY or ACL_PERMIT ++ * 2 : src_spec = String giving the source of the acl entry ++ * 3 : dst_spec = String giving the destination of the acl entry, ++ * or NULL ++ * 4 : proxy_args = Pointer to string to append description of errors to. ++ * ++ * Returns : the new list ++ * ++ *********************************************************************/ ++struct access_control_list *add_to_acl_list(struct access_control_list *l, ++ short action, ++ char *src_spec, ++ char *dst_spec, ++ char **proxy_args) ++{ ++ int src_masklength, dst_masklength; ++ addr_list *src_addrs, *dst_addrs; ++ addr_list *src_addrs_remaining, *dst_addrs_remaining; ++ ++ src_addrs = acl_addrs(src_spec, &src_masklength, proxy_args, "source"); ++ if (is_nil_addr_list(src_addrs)) ++ { ++ log_error(LOG_LEVEL_ERROR, "Source of ACL resolves to no address",dst_spec); ++ return l; ++ } ++ if (dst_spec != NULL) ++ { ++ dst_addrs = acl_addrs(dst_spec, &dst_masklength, proxy_args, "destination"); ++ if (is_nil_addr_list(dst_addrs)) ++ { ++ log_error(LOG_LEVEL_ERROR, "Destination of ACL resolves to no address",dst_spec); ++ destroy_addr_list(src_addrs); ++ return l; ++ } ++ } ++ else ++ dst_addrs = NULL; ++ ++ for(src_addrs_remaining = src_addrs; ++ is_nil_addr_list(src_addrs); ++ src_addrs_remaining=tail_addr_list(src_addrs_remaining)) ++ { ++ if (dst_addrs == NULL) ++ l = add_one_to_acl_list(l, action, src_addrs_remaining, NULL, src_masklength,0); ++ else for(dst_addrs_remaining = dst_addrs; ++ is_nil_addr_list(dst_addrs); ++ dst_addrs_remaining=tail_addr_list(dst_addrs_remaining)) ++ l = add_one_to_acl_list(l, action, src_addrs_remaining, dst_addrs_remaining, ++ src_masklength, dst_masklength); ++ } ++ destroy_addr_list(src_addrs); ++ destroy_addr_list(dst_addrs); + ++ return l; + } +-#endif /* def FEATURE_ACL */ + ++#endif /* def FEATURE_ACL */ + + /********************************************************************* + * +@@ -1048,7 +1324,7 @@ + *********************************************************************/ + struct http_response *redirect_url(struct client_state *csp) + { +- char *p, *q; ++ const char *p, *q; + struct http_response *rsp; + + p = q = csp->http->path; +diff -urNad privoxy~/filters.h privoxy/filters.h +--- privoxy~/filters.h ++++ privoxy/filters.h +@@ -15,6 +15,9 @@ + * Copyright : Written by and Copyright (C) 2001 the SourceForge + * Privoxy team. http://www.privoxy.org/ + * ++ * Modified by Lionel Elie Mamane ++ * for IPv6 support on 8 December 2002, 24 January 2003. ++ * + * Based on the Internet Junkbuster originally written + * by and Copyright (C) 1997 Anonymous Coders and + * Junkbusters Corporation. http://www.junkbusters.com +@@ -221,7 +224,11 @@ + */ + #ifdef FEATURE_ACL + extern int block_acl(struct access_control_addr *dst, struct client_state *csp); +-extern int acl_addr(char *aspec, struct access_control_addr *aca); ++extern struct access_control_list *add_to_acl_list(struct access_control_list *l, ++ short action, ++ char *src_spec, ++ char *dst_spec, ++ char **proxy_args); + #endif /* def FEATURE_ACL */ + extern int match_portlist(const char *portlist, int port); + +diff -urNad privoxy~/gateway.c privoxy/gateway.c +--- privoxy~/gateway.c ++++ privoxy/gateway.c +@@ -10,6 +10,9 @@ + * Copyright : Written by and Copyright (C) 2001 the SourceForge + * Privoxy team. http://www.privoxy.org/ + * ++ * Modified by Lionel Elie Mamane ++ * for IPv6 support on 8 December 2002, 24 January 2003. ++ * + * Based on the Internet Junkbuster originally written + * by and Copyright (C) 1997 Anonymous Coders and + * Junkbusters Corporation. http://www.junkbusters.com +@@ -199,12 +202,14 @@ + * Returns : JB_INVALID_SOCKET => failure, else it is the socket file descriptor. + * + *********************************************************************/ +-jb_socket forwarded_connect(const struct forward_spec * fwd, ++jb_socket forwarded_connect(const struct forward_spec *fwd, + struct http_request *http, + struct client_state *csp) + { + const char * dest_host; +- int dest_port; ++ const char * dest_port_str; ++ unsigned long dest_port; ++ int dest_pf; + + /* Figure out if we need to connect to the web server or a HTTP proxy. */ + if (fwd->forward_host) +@@ -212,19 +217,23 @@ + /* HTTP proxy */ + dest_host = fwd->forward_host; + dest_port = fwd->forward_port; ++ dest_port_str = fwd->forward_port_str; ++ dest_pf = fwd->forward_family; + } + else + { + /* Web server */ + dest_host = http->host; + dest_port = http->port; ++ dest_port_str = http->port_str; ++ dest_pf = PF_UNSPEC; + } + + /* Connect, maybe using a SOCKS proxy */ + switch (fwd->type) + { + case SOCKS_NONE: +- return (connect_to(dest_host, dest_port, csp)); ++ return (connect_to(dest_host, dest_port_str, dest_port, dest_pf, csp)); + + case SOCKS_4: + case SOCKS_4A: +@@ -258,74 +267,19 @@ + * Returns : JB_INVALID_SOCKET => failure, else a socket file descriptor. + * + *********************************************************************/ +-static jb_socket socks4_connect(const struct forward_spec * fwd, +- const char * target_host, +- int target_port, +- struct client_state *csp) ++static jb_socket socks4_connect_one_ip(const struct forward_spec * fwd, ++ unsigned long web_server_addr, ++ int target_port, ++ struct client_state *csp, ++ size_t csiz, ++ char *cbuf) + { +- int web_server_addr; +- char cbuf[BUFFER_SIZE]; + char sbuf[BUFFER_SIZE]; +- struct socks_op *c = (struct socks_op *)cbuf; + struct socks_reply *s = (struct socks_reply *)sbuf; +- size_t n; +- size_t csiz; ++ struct socks_reply *c = (struct socks_reply *)cbuf; + jb_socket sfd; +- int err = 0; + char *errstr; + +- if ((fwd->gateway_host == NULL) || (*fwd->gateway_host == '\0')) +- { +- log_error(LOG_LEVEL_CONNECT, "socks4_connect: NULL gateway host specified"); +- err = 1; +- } +- +- if (fwd->gateway_port <= 0) +- { +- log_error(LOG_LEVEL_CONNECT, "socks4_connect: invalid gateway port specified"); +- err = 1; +- } +- +- if (err) +- { +- errno = EINVAL; +- return(JB_INVALID_SOCKET); +- } +- +- /* build a socks request for connection to the web server */ +- +- strcpy((char *)&(c->userid), socks_userid); +- +- csiz = sizeof(*c) + sizeof(socks_userid) - 1; +- +- switch (fwd->type) +- { +- case SOCKS_4: +- web_server_addr = htonl(resolve_hostname_to_ip(target_host)); +- if (web_server_addr == INADDR_NONE) +- { +- log_error(LOG_LEVEL_CONNECT, "socks4_connect: could not resolve target host %s", target_host); +- return(JB_INVALID_SOCKET); +- } +- break; +- case SOCKS_4A: +- web_server_addr = 0x00000001; +- n = csiz + strlen(target_host) + 1; +- if (n > sizeof(cbuf)) +- { +- errno = EINVAL; +- return(JB_INVALID_SOCKET); +- } +- strcpy(cbuf + csiz, target_host); +- csiz = n; +- break; +- default: +- /* Should never get here */ +- log_error(LOG_LEVEL_FATAL, "SOCKS4 impossible internal error - bad SOCKS type."); +- errno = EINVAL; +- return(JB_INVALID_SOCKET); +- } +- + c->vn = 4; + c->cd = 1; + c->dstport[0] = (target_port >> 8 ) & 0xff; +@@ -336,7 +290,7 @@ + c->dstip[3] = (web_server_addr ) & 0xff; + + /* pass the request to the socks server */ +- sfd = connect_to(fwd->gateway_host, fwd->gateway_port, csp); ++ sfd = connect_to(fwd->gateway_host, fwd->gateway_port_str, fwd->gateway_port, PF_INET ,csp); + + if (sfd == JB_INVALID_SOCKET) + { +@@ -391,6 +345,92 @@ + + } + ++static jb_socket socks4_connect(const struct forward_spec * fwd, ++ const char * target_host, ++ int target_port, ++ struct client_state *csp) ++{ ++ char cbuf[BUFFER_SIZE]; ++ struct socks_op *c = (struct socks_op *)cbuf; ++ size_t csiz; ++ int err = 0; ++ ++ /** ++ * SOCKS4 is IPv4-specific. At least I think so. ++ */ ++ if ((fwd->gateway_host == NULL) || (*fwd->gateway_host == '\0')) ++ { ++ log_error(LOG_LEVEL_CONNECT, "socks4_connect: NULL gateway host specified"); ++ err = 1; ++ } ++ ++ if (fwd->gateway_port <= 0) ++ { ++ log_error(LOG_LEVEL_CONNECT, "socks4_connect: invalid gateway port specified"); ++ err = 1; ++ } ++ ++ if (err) ++ { ++ errno = EINVAL; ++ return(JB_INVALID_SOCKET); ++ } ++ ++ /* build a socks request for connection to the web server */ ++ ++ strcpy((char *)&(c->userid), socks_userid); ++ ++ csiz = sizeof(*c) + sizeof(socks_userid) - 1; ++ ++ switch (fwd->type) ++ { ++ case SOCKS_4: ++ { ++ addr_list *web_server_addrs = resolve_hostname_to_ip(target_host,NULL,PF_INET); ++ jb_socket return_value = JB_INVALID_SOCKET; ++ if (is_nil_addr_list(web_server_addrs)) ++ { ++ log_error(LOG_LEVEL_CONNECT, "socks4_connect: could not resolve target host %s", target_host); ++ } ++ else ++ { ++ addr_list *addrs_to_try; ++ ++ for(addrs_to_try = web_server_addrs; ++ !is_nil_addr_list(addrs_to_try); ++ addrs_to_try = tail_addr_list(addrs_to_try)) ++ { ++ const unsigned long web_server_addr = ((struct sockaddr_in*) head_addr_list(addrs_to_try))->sin_addr.s_addr; ++ return_value=socks4_connect_one_ip(fwd, web_server_addr, target_port, csp, csiz, cbuf); ++ if(return_value != JB_INVALID_SOCKET) ++ break; ++ } ++ } ++ destroy_addr_list(web_server_addrs); ++ return return_value; ++ break; ++ } ++ case SOCKS_4A: ++ { ++ size_t n; ++ n = csiz + strlen(target_host) + 1; ++ if (n > sizeof(cbuf)) ++ { ++ errno = EINVAL; ++ return(JB_INVALID_SOCKET); ++ } ++ strcpy(cbuf + csiz, target_host); ++ csiz = n; ++ return socks4_connect_one_ip(fwd, 0x00000001, target_port, csp, csiz, cbuf); ++ break; ++ } ++ default: ++ /* Should never get here */ ++ log_error(LOG_LEVEL_FATAL, "SOCKS4 impossible internal error - bad SOCKS type."); ++ errno = EINVAL; ++ return(JB_INVALID_SOCKET); ++ } ++} + + /* + Local Variables: +diff -urNad privoxy~/jb_socket_set.c privoxy/jb_socket_set.c +--- privoxy~/jb_socket_set.c ++++ privoxy/jb_socket_set.c +@@ -0,0 +1,174 @@ ++const char jb_socket_set_rcs[] = "$Id: $"; ++/********************************************************************* ++ * ++ * File : $Source: $ ++ * ++ * Purpose : Declares functions to handle sets of sockets ++ * ++ * Copyright : Written by and Copyright (C) 2002 Lionel Elie Mamane ++ * ++ * ++ * This program is free software; you can redistribute it ++ * and/or modify it under the terms of the GNU General ++ * Public License as published by the Free Software ++ * Foundation; either version 2 of the License, or (at ++ * your option) any later version. ++ * ++ * This program is distributed in the hope that it will ++ * be useful, but WITHOUT ANY WARRANTY; without even the ++ * implied warranty of MERCHANTABILITY or FITNESS FOR A ++ * PARTICULAR PURPOSE. See the GNU General Public ++ * License for more details. ++ * ++ * The GNU General Public License should be included with ++ * this file. If not, you can view it at ++ * http://www.gnu.org/copyleft/gpl.html ++ * or write to the Free Software Foundation, Inc., 59 ++ * Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * Revisions : ++ * $Log: jb_socket_set.c,v $ ++ * ++ *********************************************************************/ ++ ++#include "jb_socket_set.h" ++#include ++#include ++#include ++#include "project.h" ++ ++/********************************************************************* ++ * ++ * Function : jb_socket_set_add ++ * ++ * Description : Add a socket to the set ++ * ++ * Parameters : ++ * 0 : l = the set to add to ++ * 1 : the elemen to add to the set ++ * ++ * Returns : 0 on success ++ * non-0 on failure ++ * ++ *********************************************************************/ ++ ++int jb_socket_set_add(jb_socket_set *l, jb_socket e) ++{ ++ if (l->data==NULL) ++ { ++ l->size=2; ++ l->data=malloc(l->size * sizeof(jb_socket)); ++ if (l->data==NULL) ++ { ++ l->size = 0; ++ return -1; ++ } ++ l->occupied=0; ++ } ++ l->data[(l->occupied)++] = e; ++ if (l->occupied == l->size) ++ { ++ jb_socket *new_data; ++ l->size *= 2; ++ new_data = realloc(l->data,l->size * sizeof(jb_socket)); ++ if (new_data == NULL) ++ { ++ /* Not enough memory to continue. Cancel changes. */ ++ l->data[--(l->occupied)] = JB_INVALID_SOCKET; ++ l->size /= 2; ++ return -1; ++ } ++ l->data = new_data; ++ } ++ l->data[l->occupied] = JB_INVALID_SOCKET; ++ return 0; ++} ++ ++/********************************************************************* ++ * ++ * Function : destroy_jb_socket_set ++ * ++ * Description : Unallocate memory allocated to a socket set ++ * ++ * Parameters : ++ * 0 : l = the set to unallocate ++ * ++ * Returns : nothing ++ * ++ *********************************************************************/ ++void destroy_jb_socket_set(jb_socket_set *l) ++{ ++ free(l->data); ++ init_jb_socket_set(l); ++} ++/********************************************************************* ++ * ++ * Function : is_empty_jb_socket_set ++ * ++ * Description : Test wheter a set is empty ++ * ++ * Parameters : ++ * 0 : l = the set to test ++ * ++ * Returns : 0 = false if set has a head, ++ * anything else = true if set is nil ++ * ++ *********************************************************************/ ++int is_nil_jb_socket_set(jb_socket_set *l) ++{ ++ return (l->occupied == 0); ++} ++ ++/********************************************************************* ++ * ++ * Function : init_jb_socket_set ++ * ++ * Description : Init a set to empty ++ * ++ * Parameters : ++ * 0 : l = the set to init ++ * ++ *********************************************************************/ ++void init_jb_socket_set(jb_socket_set *l) ++{ ++ l->data=NULL; ++ l->size=0; ++ l->occupied=0; ++} ++ ++/********************************************************************* ++ * ++ * Function : jb_socket_set_iteration_begin ++ * ++ * Description : Return an iterator on the set ++ * ++ * Parameters : ++ * 0 : l = the set ++ * ++ *********************************************************************/ ++jb_socket_set_iterate_state jb_socket_set_iteration_begin(jb_socket_set *l) ++{ ++ return l->data; ++} ++ ++/********************************************************************* ++ * ++ * Function : jb_socket_set_iteration_next ++ * ++ * Description : Return value pointed to by iterator and step ++ * iterator to next position ++ * ++ * Parameters : ++ * 0 : s = the iterator ++ * ++ *********************************************************************/ ++jb_socket jb_socket_set_iteration_next(jb_socket_set_iterate_state*s) ++{ ++ return(*((*s)++)); ++} ++ ++/* ++ Local Variables: ++ tab-width: 3 ++ end: ++*/ +diff -urNad privoxy~/jb_socket_set.h privoxy/jb_socket_set.h +--- privoxy~/jb_socket_set.h ++++ privoxy/jb_socket_set.h +@@ -0,0 +1,71 @@ ++#ifndef JB_SOCKET_SET_H_INCLUDED ++#define JB_SOCKET_SET_H_INCLUDED ++#define JB_SOCKET_SET_H_VERSION "$Id: $" ++/********************************************************************* ++ * ++ * File : $Source: $ ++ * ++ * Purpose : Declares functions to handle sets of sockets ++ * ++ * Copyright : Written by and Copyright (C) 2002 Lionel Elie Mamane ++ * ++ * ++ * This program is free software; you can redistribute it ++ * and/or modify it under the terms of the GNU General ++ * Public License as published by the Free Software ++ * Foundation; either version 2 of the License, or (at ++ * your option) any later version. ++ * ++ * This program is distributed in the hope that it will ++ * be useful, but WITHOUT ANY WARRANTY; without even the ++ * implied warranty of MERCHANTABILITY or FITNESS FOR A ++ * PARTICULAR PURPOSE. See the GNU General Public ++ * License for more details. ++ * ++ * The GNU General Public License should be included with ++ * this file. If not, you can view it at ++ * http://www.gnu.org/copyleft/gpl.html ++ * or write to the Free Software Foundation, Inc., 59 ++ * Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * Revisions : ++ * $Log: jb_socket_set.h,v $ ++ * ++ *********************************************************************/ ++#include ++#include ++#include ++#include "project.h" ++ ++struct jb_socket_set_struct ++{ ++ unsigned int size; /* size allocated*/ ++ unsigned int occupied; /* size occupied - 1 == index of final JB_INVALID_SOCKET ++ == number of sockets in the set */ ++ jb_socket *data; /* Array containing the sockets, JB_INVALID_SOCKET-terminated */ ++}; ++ ++typedef struct jb_socket_set_struct jb_socket_set; ++typedef const jb_socket* jb_socket_set_iterate_state; ++ ++void init_jb_socket_set(jb_socket_set*); ++ ++jb_socket_set_iterate_state jb_socket_set_iteration_begin(jb_socket_set *); ++jb_socket jb_socket_set_iteration_next(jb_socket_set_iterate_state*); ++ ++int jb_socket_set_add(jb_socket_set*, jb_socket); ++ ++void destroy_jb_socket_set(jb_socket_set *l); ++int is_empty_jb_socket_set(jb_socket_set *l); ++ ++#define freez_jb_socket_set(X) { if(X) { destroy_jb_socket_set(X); X = NULL ; } } ++ ++int jb_select(jb_socket_set *readfds, jb_socket_set *writefds, jb_socket_set *exceptfds, struct timeval *timeout); ++ ++#endif /* ndef JB_SOCKET_SET_H_INCLUDED */ ++ ++/* ++ Local Variables: ++ tab-width: 3 ++ end: ++*/ +diff -urNad privoxy~/jbsockets.c privoxy/jbsockets.c +--- privoxy~/jbsockets.c ++++ privoxy/jbsockets.c +@@ -11,6 +11,10 @@ + * Copyright : Written by and Copyright (C) 2001 the SourceForge + * Privoxy team. http://www.privoxy.org/ + * ++ * Modified by Lionel Elie Mamane ++ * for IPv6 support on 8-9 December 2002, 24 January 2003, ++ * 13 February 2003. ++ * + * Based on the Internet Junkbuster originally written + * by and Copyright (C) 1997 Anonymous Coders and + * Junkbusters Corporation. http://www.junkbusters.com +@@ -258,6 +262,7 @@ + #include "jbsockets.h" + #include "filters.h" + #include "errlog.h" ++#include "addrlist.h" + + const char jbsockets_h_rcs[] = JBSOCKETS_H_VERSION; + +@@ -270,141 +275,194 @@ + * that this is allowed according to ACL. + * + * Parameters : +- * 1 : host = hostname to connect to +- * 2 : portnum = port to connent on ++ * 0 : host = hostname to connect to ++ * 1 : port = port to connect on, as string ++ * 2 : portnum = port to connect on, as integer + * 3 : csp = Current client state (buffers, headers, etc...) +- * Not modified, only used for source IP and ACL. + * + * Returns : JB_INVALID_SOCKET => failure, else it is the socket + * file descriptor. + * + *********************************************************************/ +-jb_socket connect_to(const char *host, int portnum, struct client_state *csp) ++jb_socket connect_to_one_ip(struct sockaddr_storage *addr, size_t addrlen, const char *host, unsigned long portnum, struct client_state *csp) + { +- struct sockaddr_in inaddr; +- jb_socket fd; +- int addr; +- fd_set wfds; +- struct timeval tv[1]; +-#if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) +- int flags; +-#endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) */ +- + #ifdef FEATURE_ACL +- struct access_control_addr dst[1]; +-#endif /* def FEATURE_ACL */ +- +- memset((char *)&inaddr, 0, sizeof inaddr); +- +- if ((addr = resolve_hostname_to_ip(host)) == INADDR_NONE) ++ if (csp) + { +- csp->http->host_ip_addr_str = strdup("unknown"); +- return(JB_INVALID_SOCKET); +- } ++ struct access_control_addr dst[1]; ++ char hostname[NI_MAXHOST]; ++ char port[NI_MAXSERV]; ++ if (getnameinfo((struct sockaddr*)addr, addrlen, hostname, NI_MAXHOST, ++ port, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV) != 0) ++ { ++ log_error(LOG_LEVEL_ERROR, "connect: Could not get string address and port back from sockaddr because %E"); ++ strncpy(hostname,"unknown",NI_MAXHOST); ++ strncpy(port,"unknown",NI_MAXSERV); ++ } + +-#ifdef FEATURE_ACL +- dst->addr = ntohl((unsigned long) addr); +- dst->port = portnum; ++ csp->http->host_ip_addr_str = strdup(hostname); + +- if (block_acl(dst, csp)) +- { ++ dst->addr = *addr; ++ dst->addrlen = addrlen; ++ dst->port = portnum; ++ ++ if (block_acl(dst, csp)) ++ { + #ifdef __OS2__ +- errno = SOCEPERM; ++ errno = SOCEPERM; + #else +- errno = EPERM; ++ errno = EPERM; + #endif +- return(JB_INVALID_SOCKET); +- } +-#endif /* def FEATURE_ACL */ ++ return(JB_INVALID_SOCKET); ++ } + +- inaddr.sin_addr.s_addr = addr; +- inaddr.sin_family = AF_INET; +- csp->http->host_ip_addr_str = strdup(inet_ntoa(inaddr.sin_addr)); + +-#ifndef _WIN32 +- if (sizeof(inaddr.sin_port) == sizeof(short)) +-#endif /* ndef _WIN32 */ +- { +- inaddr.sin_port = htons((unsigned short) portnum); + } +-#ifndef _WIN32 +- else ++#endif /* def FEATURE_ACL */ ++ + { +- inaddr.sin_port = htonl((unsigned long)portnum); +- } +-#endif /* ndef _WIN32 */ ++ jb_socket fd; + + #ifdef _WIN32 +- if ((fd = socket(inaddr.sin_family, SOCK_STREAM, 0)) == JB_INVALID_SOCKET) ++ if ((fd = socket(addr->ss_family, SOCK_STREAM, 0)) == JB_INVALID_SOCKET) + #else +- if ((fd = socket(inaddr.sin_family, SOCK_STREAM, 0)) < 0) ++ if ((fd = socket(addr->ss_family, SOCK_STREAM, 6)) < 0) + #endif +- { +- return(JB_INVALID_SOCKET); +- } ++ { ++ return(JB_INVALID_SOCKET); ++ } + + #ifdef TCP_NODELAY +- { /* turn off TCP coalescence */ +- int mi = 1; +- setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &mi, sizeof (int)); +- } ++ { /* turn off TCP coalescence */ ++ int mi = 1; ++ setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, (char *) &mi, sizeof (int)); ++ } + #endif /* def TCP_NODELAY */ + + #if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) +- if ((flags = fcntl(fd, F_GETFL, 0)) != -1) +- { +- flags |= O_NDELAY; +- fcntl(fd, F_SETFL, flags); +- } ++ { ++ int flags; ++ ++ if ((flags = fcntl(fd, F_GETFL, 0)) != -1) ++ { ++ flags |= O_NDELAY; ++ fcntl(fd, F_SETFL, flags); ++ } ++ } + #endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) */ + +- while (connect(fd, (struct sockaddr *) & inaddr, sizeof inaddr) == JB_INVALID_SOCKET) +- { ++ while (connect(fd, (struct sockaddr *) addr, addrlen) == JB_INVALID_SOCKET) ++ { + #ifdef _WIN32 +- if (errno == WSAEINPROGRESS) ++ if (errno == WSAEINPROGRESS) + #elif __OS2__ +- if (sock_errno() == EINPROGRESS) ++ if (sock_errno() == EINPROGRESS) + #else /* ifndef _WIN32 */ +- if (errno == EINPROGRESS) ++ if (errno == EINPROGRESS) + #endif /* ndef _WIN32 || __OS2__ */ +- { +- break; +- } ++ { ++ break; ++ } + + #ifdef __OS2__ +- if (sock_errno() != EINTR) ++ if (sock_errno() != EINTR) + #else +- if (errno != EINTR) ++ if (errno != EINTR) + #endif /* __OS2__ */ ++ { ++ close_socket(fd); ++ return(JB_INVALID_SOCKET); ++ } ++ } ++ ++#if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) + { +- close_socket(fd); +- return(JB_INVALID_SOCKET); ++ int flags; ++ if ((flags = fcntl(fd, F_GETFL, 0)) != -1) ++ { ++ flags &= ~O_NDELAY; ++ fcntl(fd, F_SETFL, flags); ++ } + } +- } ++#endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) */ ++ ++ { ++ fd_set wfds; ++ struct timeval tv[1]; ++ ++ /* wait for connection to complete */ ++ FD_ZERO(&wfds); ++ FD_SET(fd, &wfds); + ++ tv->tv_sec = 30; ++ tv->tv_usec = 0; ++ ++ /* MS Windows uses int, not SOCKET, for the 1st arg of select(). Wierd! */ ++ if (select((int)fd + 1, NULL, &wfds, NULL, tv) <= 0) ++ { ++ close_socket(fd); ++ return(JB_INVALID_SOCKET); ++ } + #if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) +- if (flags != -1) +- { +- flags &= ~O_NDELAY; +- fcntl(fd, F_SETFL, flags); +- } ++ else ++ { ++ int connect_result; ++ socklen_t connect_result_len = sizeof connect_result; ++ ++ if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &connect_result, &connect_result_len) != 0) ++ { ++ log_error(LOG_LEVEL_ERROR, "Could not determine whether connection to %s port %d was successful because %E. Assuming failure.", ++ csp->http->host_ip_addr_str, portnum); ++ close_socket(fd); ++ return(JB_INVALID_SOCKET); ++ } ++ else if( connect_result != 0 ) ++ { ++ log_error(LOG_LEVEL_CONNECT, "Connection to %s port %d failed because %s.", ++ csp->http->host_ip_addr_str, portnum, strerror(connect_result)); ++ close_socket(fd); ++ return(JB_INVALID_SOCKET); ++ } ++ } + #endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) */ ++ } ++ return(fd); ++ } ++} + +- /* wait for connection to complete */ +- FD_ZERO(&wfds); +- FD_SET(fd, &wfds); ++jb_socket connect_to(const char *host, const char *port, unsigned long portnum, int pf, struct client_state *csp) ++{ ++ jb_socket fd = JB_INVALID_SOCKET; ++ struct sockaddr_storage addr; ++ addr_list *addrs, *addrs_to_try; + +- tv->tv_sec = 30; +- tv->tv_usec = 0; ++ addrs = resolve_hostname_to_ip(host,port,pf); + +- /* MS Windows uses int, not SOCKET, for the 1st arg of select(). Wierd! */ +- if (select((int)fd + 1, NULL, &wfds, NULL, tv) <= 0) ++ if (is_nil_addr_list(addrs)) + { +- close_socket(fd); +- return(JB_INVALID_SOCKET); ++ errno = EINVAL; ++ return fd; + } +- return(fd); + ++ for(addrs_to_try=addrs; ++ !is_nil_addr_list(addrs_to_try); ++ addrs_to_try = tail_addr_list(addrs_to_try)) ++ { ++ size_t addrlen; ++ memset((char *)&addr, 0, sizeof addr); ++ cpy_head_addr_list(addrs_to_try, &addr,&addrlen); ++ fd = connect_to_one_ip(&addr, addrlen, host, portnum, csp); ++ if (fd != JB_INVALID_SOCKET) ++ break; ++ } ++ ++ if (fd == JB_INVALID_SOCKET) ++ { ++ csp->http->host_ip_addr_str = strdup("unknown"); ++ } ++ ++ destroy_addr_list(addrs); ++ return fd; + } + + +@@ -544,55 +602,30 @@ + + /********************************************************************* + * +- * Function : bind_port ++ * Function : bind_port_one_ip + * + * Description : Call socket, set socket options, and listen. +- * Called by listen_loop to "boot up" our proxy address. + * + * Parameters : +- * 1 : hostnam = TCP/IP address to bind/listen to +- * 2 : portnum = port to listen on +- * 3 : pfd = pointer used to return file descriptor. ++ * 0 : addr = TCP/IP address and port to bind/listen to ++ * 1 : fds = jb_socket_set where the new socket should go + * +- * Returns : if success, returns 0 and sets *pfd. ++ * Returns : if success returns 0 and adds sockets to fds. + * if failure, returns -3 if address is in use, +- * -2 if address unresolvable, ++ * -2 if memory error + * -1 otherwise + *********************************************************************/ +-int bind_port(const char *hostnam, int portnum, jb_socket *pfd) ++int bind_port_one_ip(struct sockaddr *addr, const socklen_t addr_len, jb_socket_set *fds) + { +- struct sockaddr_in inaddr; + jb_socket fd; ++ int flags; + #ifndef _WIN32 + int one = 1; + #endif /* ndef _WIN32 */ + +- *pfd = JB_INVALID_SOCKET; +- +- memset((char *)&inaddr, '\0', sizeof inaddr); +- +- inaddr.sin_family = AF_INET; +- inaddr.sin_addr.s_addr = resolve_hostname_to_ip(hostnam); +- +- if (inaddr.sin_addr.s_addr == INADDR_NONE) +- { +- return(-2); +- } +- +-#ifndef _WIN32 +- if (sizeof(inaddr.sin_port) == sizeof(short)) +-#endif /* ndef _WIN32 */ +- { +- inaddr.sin_port = htons((unsigned short) portnum); +- } +-#ifndef _WIN32 +- else +- { +- inaddr.sin_port = htonl((unsigned long) portnum); +- } +-#endif /* ndef _WIN32 */ ++ fd = JB_INVALID_SOCKET; + +- fd = socket(AF_INET, SOCK_STREAM, 0); ++ fd = socket(addr->sa_family, SOCK_STREAM, 6); + + #ifdef _WIN32 + if (fd == JB_INVALID_SOCKET) +@@ -618,8 +651,17 @@ + */ + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one)); + #endif /* ndef _WIN32 */ +- +- if (bind(fd, (struct sockaddr *)&inaddr, sizeof(inaddr)) < 0) ++ /* As we are now listening on more than one socket, ++ * this is important: The only way to be sure accept ++ * won't block!! ++ */ ++ if ((flags = fcntl(fd, F_GETFL, 0)) != -1) ++ { ++ flags |= O_NONBLOCK; ++ fcntl(fd, F_SETFL, flags); ++ } ++ ++ if (bind (fd, addr, addr_len) < 0) + { + #ifdef _WIN32 + errno = WSAGetLastError(); +@@ -638,7 +680,7 @@ + } + } + +- while (listen(fd, 5) == -1) ++ while (listen(fd, 25) == -1) + { + if (errno != EINTR) + { +@@ -646,7 +688,11 @@ + } + } + +- *pfd = fd; ++ if (jb_socket_set_add(fds,fd) != 0) ++ { ++ close_socket(fd); ++ return -2; ++ } + return 0; + + } +@@ -654,6 +700,91 @@ + + /********************************************************************* + * ++ * Function : bind_port ++ * ++ * Description : Call bind_port_one_ip on all addresses host resolves to ++ * Called by listen_loop to "boot up" our proxy address. ++ * ++ * Parameters : ++ * 0 : host = TCP/IP hostname to bind/listen to ++ * 1 : port = port to listen to, as string ++ * 2 : fds = socket set the sockets should be added to ++ * ++ * Returns : if success on at least one address resolving from hostnam, ++ * returns 0 and adds sockets to fds. ++ * if failure, returns non-zero ++ *********************************************************************/ ++int bind_port(const char *host, const char *port, int pf, jb_socket_set *fds) ++{ ++ int result; ++ int failure = 1; ++ struct sockaddr_storage addr; ++ struct sockaddr * const addr_addr = (struct sockaddr *)&addr; ++ addr_list *addrs, *addrs_to_try; ++ ++ const char * const log_host = (host != NULL) ? host : "ADDR_ANY"; ++ ++ addrs = resolve_hostname_to_ip(host,port,pf); ++ ++ if (is_nil_addr_list(addrs)) ++ log_error(LOG_LEVEL_ERROR, "can't bind to %s:%s: " ++ "Name resolution didn't give any address", ++ log_host, port); ++ ++ log_error(LOG_LEVEL_INFO, "Binding to %s:%s...", log_host, port); ++ ++ for(addrs_to_try=addrs; ++ !is_nil_addr_list(addrs_to_try); ++ addrs_to_try = tail_addr_list(addrs_to_try)) ++ { ++ char numeric_hostname[NI_MAXHOST]; ++ char numeric_port[NI_MAXSERV]; ++ size_t addrlen; ++ memset((char *)addr_addr, 0, sizeof addr); ++ cpy_head_addr_list(addrs_to_try, &addr, &addrlen); ++ result = getnameinfo(addr_addr, addrlen, numeric_hostname, NI_MAXHOST, ++ numeric_port, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV); ++ if (result != 0) ++ { ++ log_error(LOG_LEVEL_ERROR, "bind: Could not get string address and port back from sockaddr because %E"); ++ strncpy(numeric_hostname,"unknown",NI_MAXHOST); ++ strncpy(numeric_port,"unknown",NI_MAXSERV); ++ } ++ result = bind_port_one_ip(addr_addr, addrlen, fds); ++ if( result == 0 ) ++ { ++ failure = 0; ++ log_error(LOG_LEVEL_INFO, "Successfully bound to %s:%s", numeric_hostname, numeric_port); ++ } ++ else ++ { ++ switch(result) ++ { ++ case -3 : ++ log_error(LOG_LEVEL_ERROR, "can't bind to %s:%s (%s:%s): " ++ "There may be another Privoxy or some other " ++ "proxy running on port %s", ++ log_host, port, numeric_hostname, numeric_port, numeric_port); ++ break; ++ case -2 : ++ log_error(LOG_LEVEL_ERROR, "can't bind to %s:%s (%s:%s): " ++ "Out of memory", ++ log_host, port, numeric_hostname, numeric_port); ++ break; ++ default : ++ log_error(LOG_LEVEL_ERROR, "can't bind to %s:%s: because %E", ++ log_host, numeric_port); ++ } ++ } ++ } ++ ++ destroy_addr_list(addrs); ++ return failure; ++} ++ ++ ++/********************************************************************* ++ * + * Function : accept_connection + * + * Description : Accepts a connection on a socket. Socket must have +@@ -670,8 +801,7 @@ + *********************************************************************/ + int accept_connection(struct client_state * csp, jb_socket fd) + { +- struct sockaddr_in client, server; +- struct hostent *host = NULL; ++ struct sockaddr_storage client, server; + jb_socket afd; + #if defined(_WIN32) || defined(__OS2__) || defined(__APPLE_CC__) || defined(AMIGA) + /* Wierdness - fix a warning. */ +@@ -679,15 +809,7 @@ + #else + socklen_t c_length, s_length; + #endif +-#if defined(HAVE_GETHOSTBYADDR_R_8_ARGS) || defined(HAVE_GETHOSTBYADDR_R_7_ARGS) || defined(HAVE_GETHOSTBYADDR_R_5_ARGS) +- struct hostent result; +-#if defined(HAVE_GETHOSTBYADDR_R_5_ARGS) +- struct hostent_data hdata; +-#else +- char hbuf[HOSTENT_BUFFER_SIZE]; +- int thd_err; +-#endif /* def HAVE_GETHOSTBYADDR_R_5_ARGS */ +-#endif /* def HAVE_GETHOSTBYADDR_R_(8|7|5)_ARGS */ ++ int flags; + + c_length = s_length = sizeof(client); + +@@ -707,6 +829,12 @@ + return 0; + } + #endif ++ /* If we inherited O_NONBLOCK from the listening fd, unset it */ ++ if ((flags = fcntl(fd, F_GETFL, 0)) != -1) ++ { ++ flags &= ~O_NONBLOCK; ++ fcntl(fd, F_SETFL, flags); ++ } + + /* + * Determine the IP-Adress that the client used to reach us +@@ -714,49 +842,50 @@ + */ + if (!getsockname(afd, (struct sockaddr *) &server, &s_length)) + { +- csp->my_ip_addr_str = strdup(inet_ntoa(server.sin_addr)); +-#if defined(HAVE_GETHOSTBYADDR_R_8_ARGS) +- gethostbyaddr_r((const char *)&server.sin_addr, +- sizeof(server.sin_addr), AF_INET, +- &result, hbuf, HOSTENT_BUFFER_SIZE, +- &host, &thd_err); +-#elif defined(HAVE_GETHOSTBYADDR_R_7_ARGS) +- host = gethostbyaddr_r((const char *)&server.sin_addr, +- sizeof(server.sin_addr), AF_INET, +- &result, hbuf, HOSTENT_BUFFER_SIZE, &thd_err); +-#elif defined(HAVE_GETHOSTBYADDR_R_5_ARGS) +- if (0 == gethostbyaddr_r((const char *)&server.sin_addr, +- sizeof(server.sin_addr), AF_INET, +- &result, &hdata)) ++ char hostname[NI_MAXHOST]; ++ char port[NI_MAXSERV]; ++ ++ if (getnameinfo((struct sockaddr *)&server, s_length, hostname, NI_MAXHOST, ++ port, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV) != 0) + { +- host = &result; ++ log_error(LOG_LEVEL_ERROR, "accept: Could not get string address and port back from server sockaddr because %E"); ++ strncpy(hostname,"unknown IP",NI_MAXHOST); ++ strncpy(port,"unknown port",NI_MAXSERV); + } +- else ++ csp->my_ip_addr_str = strdup(hostname); ++ csp->my_port_str = strdup(port); ++ ++ if (getnameinfo((struct sockaddr *)&server, s_length, hostname, NI_MAXHOST, NULL, 0, NI_NAMEREQD) != 0) + { +- host = NULL; ++ log_error(LOG_LEVEL_ERROR, "accept: Could not get my own hostname because %E"); ++ strncpy(hostname,"unknown host",NI_MAXHOST); + } +-#elif defined(OSX_DARWIN) +- pthread_mutex_lock(&gethostbyaddr_mutex); +- host = gethostbyaddr((const char *)&server.sin_addr, +- sizeof(server.sin_addr), AF_INET); +- pthread_mutex_unlock(&gethostbyaddr_mutex); +-#else +- host = gethostbyaddr((const char *)&server.sin_addr, +- sizeof(server.sin_addr), AF_INET); +-#endif +- if (host == NULL) ++ csp->my_hostname = strdup(hostname); ++ } ++ else ++ { ++ log_error(LOG_LEVEL_ERROR, "accept: Could not get sockaddr from socket fd because %E"); ++ } ++ ++ csp->cfd = afd; ++ { ++ char hostname[NI_MAXHOST]; ++ ++ if (getnameinfo((struct sockaddr *)&client, c_length, hostname, NI_MAXHOST, NULL, 0, NI_NUMERICHOST) != 0) + { +- log_error(LOG_LEVEL_ERROR, "Unable to get my own hostname: %E\n"); ++ log_error(LOG_LEVEL_ERROR, "accept: Could not get client IP address string because %E"); ++ strncpy(hostname,"unknown IP",NI_MAXHOST); + } +- else ++ csp->my_ip_addr_str = strdup(hostname); ++ ++ if (getnameinfo((struct sockaddr *)&server, s_length, hostname, NI_MAXHOST, NULL, 0, 0) != 0) + { +- csp->my_hostname = strdup(host->h_name); ++ log_error(LOG_LEVEL_ERROR, "accept: Could not get my own hostname because %E"); ++ strncpy(hostname,"unknown host",NI_MAXHOST); + } ++ csp->ip_addr_str = strdup(hostname); + } +- +- csp->cfd = afd; +- csp->ip_addr_str = strdup(inet_ntoa(client.sin_addr)); +- csp->ip_addr_long = ntohl(client.sin_addr.s_addr); ++ csp->ip_addr_addr = client; + + return 1; + +@@ -767,90 +896,41 @@ + * + * Function : resolve_hostname_to_ip + * +- * Description : Resolve a hostname to an internet tcp/ip address. +- * NULL or an empty string resolve to INADDR_ANY. ++ * Description : Resolve a hostname to a list of internet tcp/ip addresses. + * + * Parameters : +- * 1 : host = hostname to resolve ++ * 0 : host = hostname to resolve ++ * 1 : result = where to store the result ++ * 2 : pf = preferred address family. PF_UNSPEC for no preference (recommended). + * +- * Returns : INADDR_NONE => failure, INADDR_ANY or tcp/ip address if succesful. ++ * Returns : A (possibly empty) list of adresses + * + *********************************************************************/ +-unsigned long resolve_hostname_to_ip(const char *host) ++addr_list *resolve_hostname_to_ip(const char *host, const char *port, int pf) + { +- struct sockaddr_in inaddr; +- struct hostent *hostp; +-#if defined(HAVE_GETHOSTBYNAME_R_6_ARGS) || defined(HAVE_GETHOSTBYNAME_R_5_ARGS) || defined(HAVE_GETHOSTBYNAME_R_3_ARGS) +- struct hostent result; +-#if defined(HAVE_GETHOSTBYNAME_R_6_ARGS) || defined(HAVE_GETHOSTBYNAME_R_5_ARGS) +- char hbuf[HOSTENT_BUFFER_SIZE]; +- int thd_err; +-#else /* defined(HAVE_GETHOSTBYNAME_R_3_ARGS) */ +- struct hostent_data hdata; +-#endif /* def HAVE_GETHOSTBYNAME_R_(6|5)_ARGS */ +-#endif /* def HAVE_GETHOSTBYNAME_R_(6|5|3)_ARGS */ +- +- if ((host == NULL) || (*host == '\0')) +- { +- return(INADDR_ANY); +- } +- +- memset((char *) &inaddr, 0, sizeof inaddr); ++ /* TODO ++ * Do all supported platforms have "getaddrinfo"? ++ */ ++ ++ struct addrinfo hints, *res0; ++ int result; ++ memset(&hints, 0, sizeof(hints)); ++ hints.ai_family = pf; ++ hints.ai_socktype = SOCK_STREAM; + +- if ((inaddr.sin_addr.s_addr = inet_addr(host)) == -1) ++ result = getaddrinfo(host, port, &hints, &res0); ++ if ( result != 0 ) + { +-#if defined(HAVE_GETHOSTBYNAME_R_6_ARGS) +- gethostbyname_r(host, &result, hbuf, +- HOSTENT_BUFFER_SIZE, &hostp, &thd_err); +-#elif defined(HAVE_GETHOSTBYNAME_R_5_ARGS) +- hostp = gethostbyname_r(host, &result, hbuf, +- HOSTENT_BUFFER_SIZE, &thd_err); +-#elif defined(HAVE_GETHOSTBYNAME_R_3_ARGS) +- if (0 == gethostbyname_r(host, &result, &hdata)) +- { +- hostp = &result; +- } +- else +- { +- hostp = NULL; +- } +-#elif OSX_DARWIN +- pthread_mutex_lock(&gethostbyname_mutex); +- hostp = gethostbyname(host); +- pthread_mutex_unlock(&gethostbyname_mutex); +-#else +- hostp = gethostbyname(host); +-#endif /* def HAVE_GETHOSTBYNAME_R_(6|5|3)_ARGS */ +- /* +- * On Mac OSX, if a domain exists but doesn't have a type A +- * record associated with it, the h_addr member of the struct +- * hostent returned by gethostbyname is NULL, even if h_length +- * is 4. Therefore the second test below. +- */ +- if (hostp == NULL || hostp->h_addr == NULL) +- { +- errno = EINVAL; +- log_error(LOG_LEVEL_ERROR, "could not resolve hostname %s", host); +- return(INADDR_NONE); +- } +- if (hostp->h_addrtype != AF_INET) +- { +-#ifdef _WIN32 +- errno = WSAEPROTOTYPE; +-#else +- errno = EPROTOTYPE; +-#endif +- log_error(LOG_LEVEL_ERROR, "hostname %s resolves to unknown address type.", host); +- return(INADDR_NONE); +- } +- memcpy( +- (char *) &inaddr.sin_addr, +- (char *) hostp->h_addr, +- sizeof(inaddr.sin_addr) +- ); ++ log_error(LOG_LEVEL_ERROR, "could not resolve hostname %s because %s", host,gai_strerror(result)); ++ if (result == EAI_SYSTEM) ++ log_error(LOG_LEVEL_ERROR, "The system error is %E"); ++ return NULL; + } +- return(inaddr.sin_addr.s_addr); ++ else ++ if (res0==0) ++ log_error(LOG_LEVEL_ERROR, "Problem in resolving hostname %s: succeeded, but no information returned", host); + ++ return res0; + } + + +diff -urNad privoxy~/jbsockets.h privoxy/jbsockets.h +--- privoxy~/jbsockets.h ++++ privoxy/jbsockets.h +@@ -13,6 +13,9 @@ + * Copyright : Written by and Copyright (C) 2001 the SourceForge + * Privoxy team. http://www.privoxy.org/ + * ++ * Modified by Lionel Elie Mamane ++ * for IPv6 support on 8 December 2002, 24 January 2003. ++ * + * Based on the Internet Junkbuster originally written + * by and Copyright (C) 1997 Anonymous Coders and + * Junkbusters Corporation. http://www.junkbusters.com +@@ -100,9 +103,11 @@ + extern "C" { + #endif + ++#include "addrlist.h" ++ + struct client_state; + +-extern jb_socket connect_to(const char *host, int portnum, struct client_state *csp); ++extern jb_socket connect_to(const char *host, const char *port, unsigned long portnum, int pf, struct client_state *csp); + #ifdef AMIGA + extern int write_socket(jb_socket fd, const char *buf, ssize_t n); + #else +@@ -111,10 +116,10 @@ + extern int read_socket(jb_socket fd, char *buf, int n); + extern void close_socket(jb_socket fd); + +-extern int bind_port(const char *hostnam, int portnum, jb_socket *pfd); ++extern int bind_port(const char *host, const char *port, int pf, jb_socket_set *fds); + extern int accept_connection(struct client_state * csp, jb_socket fd); + +-extern unsigned long resolve_hostname_to_ip(const char *host); ++extern addr_list *resolve_hostname_to_ip(const char *host, const char *port, int pf); + + /* Revision control strings from this header and associated .c file */ + extern const char jbsockets_rcs[]; +diff -urNad privoxy~/jcc.c privoxy/jcc.c +--- privoxy~/jcc.c ++++ privoxy/jcc.c +@@ -676,6 +676,7 @@ + #include "cgi.h" + #include "loadcfg.h" + #include "urlmatch.h" ++#include "jb_socket_set.h" + + const char jcc_h_rcs[] = JCC_H_VERSION; + const char project_h_rcs[] = PROJECT_H_VERSION; +@@ -2112,61 +2113,78 @@ + * Returns : Port that was opened. + * + *********************************************************************/ +-static jb_socket bind_port_helper(struct configuration_spec * config) ++static void bind_port_helper(struct configuration_spec * config, jb_socket_set *bfds) + { + int result; +- jb_socket bfd; ++ struct bind_spec *bs; ++ unsigned int bs_index; ++ int never_bound; + +- if ( (config->haddr != NULL) +- && (config->haddr[0] == '1') +- && (config->haddr[1] == '2') +- && (config->haddr[2] == '7') +- && (config->haddr[3] == '.') ) +- { +- log_error(LOG_LEVEL_INFO, "Listening on port %d for local connections only", +- config->hport); +- } +- else if (config->haddr == NULL) +- { +- log_error(LOG_LEVEL_INFO, "Listening on port %d on all IP addresses", +- config->hport); +- } +- else ++ never_bound = 1; ++ for (bs_index = 0; bs_index < config->hspecs_occupied;++bs_index) + { +- log_error(LOG_LEVEL_INFO, "Listening on port %d on IP address %s", +- config->hport, config->haddr); +- } ++ bs = &config->hspecs[bs_index]; ++ ++ /* This check misses about a trillion zillion different manners to describe ++ the local interface in IPv6. Who cares? */ ++ if ( (bs->haddr != NULL) ++ && (((bs->haddr[0] == '1') ++ && (bs->haddr[1] == '2') ++ && (bs->haddr[2] == '7') ++ && (bs->haddr[3] == '.')) ++ || ((bs->haddr[0] == ':') ++ && (bs->haddr[1] == ':') ++ && (bs->haddr[2] == '1')))) ++ { ++ log_error(LOG_LEVEL_INFO, "Listening on port %s for local connections only", ++ bs->hport); ++ } ++ else if (bs->haddr == NULL || bs->haddr[0]=='\0') ++ { ++ log_error(LOG_LEVEL_INFO, "Listening on port %s on all IP addresses", ++ bs->hport); ++ } ++ else ++ { ++ log_error(LOG_LEVEL_INFO, "Listening on port %s on IP address %s", ++ bs->hport, bs->haddr); ++ } + +- result = bind_port(config->haddr, config->hport, &bfd); ++ result = bind_port(bs->haddr, bs->hport, bs->pf, bfds); + +- if (result < 0) +- { +- switch(result) ++ if (result != 0) + { ++ switch(result) ++ { + case -3 : +- log_error(LOG_LEVEL_FATAL, "can't bind to %s:%d: " ++ log_error(LOG_LEVEL_ERROR, "can't bind to %s:%s: " + "There may be another Privoxy or some other " +- "proxy running on port %d", +- (NULL != config->haddr) ? config->haddr : "INADDR_ANY", +- config->hport, config->hport); ++ "proxy running on port %s", ++ (NULL != bs->haddr) ? bs->haddr : "INADDR_ANY", ++ bs->hport, bs->hport); ++ break; + + case -2 : +- log_error(LOG_LEVEL_FATAL, "can't bind to %s:%d: " ++ log_error(LOG_LEVEL_ERROR, "can't bind to %s:%s: " + "The hostname is not resolvable", +- (NULL != config->haddr) ? config->haddr : "INADDR_ANY", config->hport); ++ (NULL != bs->haddr) ? bs->haddr : "INADDR_ANY", bs->hport); ++ break; + + default : +- log_error(LOG_LEVEL_FATAL, "can't bind to %s:%d: because %E", +- (NULL != config->haddr) ? config->haddr : "INADDR_ANY", config->hport); ++ log_error(LOG_LEVEL_ERROR, "can't bind to %s:%s: because %E", ++ (NULL != bs->haddr) ? bs->haddr : "INADDR_ANY", bs->hport); ++ } + } ++ else ++ never_bound = 0; ++ } + ++ if(never_bound) ++ { ++ log_error(LOG_LEVEL_FATAL, "Couldn't bind at all - bailing out"); + /* shouldn't get here */ +- return JB_INVALID_SOCKET; + } +- + config->need_bind = 0; +- +- return bfd; + } + + +@@ -2184,12 +2202,18 @@ + static void listen_loop(void) + { + struct client_state *csp = NULL; +- jb_socket bfd; ++ jb_socket_set bfds; ++ fd_set bfds_fs; ++ jb_socket_set_iterate_state bfds_iterate_state; ++ jb_socket bfd_current; + struct configuration_spec * config; + ++ init_jb_socket_set(&bfds); ++ + config = load_config(); + +- bfd = bind_port_helper(config); ++ bind_port_helper(config,&bfds); ++ bfd_current=JB_INVALID_SOCKET; + + #ifdef FEATURE_GRACEFUL_TERMINATION + while (!g_terminate) +@@ -2263,14 +2287,55 @@ + * that this will hurt people's feelings. + */ + +- close_socket(bfd); ++ jb_socket_set_iterate_state s; ++ jb_socket bfd; ++ s=jb_socket_set_iteration_begin(&bfds); ++ for(bfd=jb_socket_set_iteration_next(&s);bfd!=JB_INVALID_SOCKET;bfd=jb_socket_set_iteration_next(&s)) ++ { ++ close_socket(bfd); ++ } ++ destroy_jb_socket_set(&bfds); ++ bind_port_helper(config,&bfds); ++ /* We have a new set of fd's to accept. Restart iteration over bfds. */ ++ bfd_current = JB_INVALID_SOCKET; ++ } + +- bfd = bind_port_helper(config); ++ /* Here: select call on listening sockets: bfd=sockets */ ++ if (bfd_current == JB_INVALID_SOCKET) ++ { ++ jb_socket max; ++ log_error(LOG_LEVEL_CONNECT, "select connections ... "); ++ bfds_iterate_state=jb_socket_set_iteration_begin(&bfds); ++ FD_ZERO(&bfds_fs); ++ max = 0; ++ for(bfd_current=jb_socket_set_iteration_next(&bfds_iterate_state); ++ bfd_current!=JB_INVALID_SOCKET; ++ bfd_current=jb_socket_set_iteration_next(&bfds_iterate_state)) ++ { ++ FD_SET(bfd_current,&bfds_fs); ++ if (bfd_current >= max) ++ max = bfd_current + 1; ++ } ++ if(!select(max,&bfds_fs,NULL,NULL,NULL)) ++ { ++ log_error(LOG_LEVEL_CONNECT, "select failed: %E"); ++ bfd_current=JB_INVALID_SOCKET; ++ continue; ++ } ++ log_error(LOG_LEVEL_CONNECT, "OK"); ++ bfds_iterate_state=jb_socket_set_iteration_begin(&bfds); ++ bfd_current=jb_socket_set_iteration_next(&bfds_iterate_state); ++ } ++ if (!FD_ISSET(bfd_current,&bfds_fs)) ++ { ++ bfd_current=jb_socket_set_iteration_next(&bfds_iterate_state); ++ freez(csp); ++ continue; + } + + log_error(LOG_LEVEL_CONNECT, "accept connection ... "); + +- if (!accept_connection(csp, bfd)) ++ if (!accept_connection(csp, bfd_current)) + { + log_error(LOG_LEVEL_CONNECT, "accept failed: %E"); + +@@ -2288,6 +2353,8 @@ + log_error(LOG_LEVEL_CONNECT, "OK"); + } + ++ bfd_current=jb_socket_set_iteration_next(&bfds_iterate_state); ++ + #ifdef FEATURE_TOGGLE + if (global_toggle_state) + { +diff -urNad privoxy~/loadcfg.c privoxy/loadcfg.c +--- privoxy~/loadcfg.c ++++ privoxy/loadcfg.c +@@ -11,6 +11,9 @@ + * Copyright : Written by and Copyright (C) 2001 the SourceForge + * Privoxy team. http://www.privoxy.org/ + * ++ * Modified by Lionel Elie Mamane ++ * for IPv6 support on 8 December 2002, 24 January 2003. ++ * + * Based on the Internet Junkbuster originally written + * by and Copyright (C) 1997 Anonymous Coders and + * Junkbusters Corporation. http://www.junkbusters.com +@@ -372,6 +375,7 @@ + #include "encode.h" + #include "urlmatch.h" + #include "cgi.h" ++#include "parsers.h" + + const char loadcfg_h_rcs[] = LOADCFG_H_VERSION; + +@@ -489,8 +493,8 @@ + struct forward_spec * next_fwd = cur_fwd->next; + free_url_spec(cur_fwd->url); + +- freez(cur_fwd->gateway_host); +- freez(cur_fwd->forward_host); ++ freez(cur_fwd->gateway_malloc); ++ freez(cur_fwd->forward_malloc); + free(cur_fwd); + cur_fwd = next_fwd; + } +@@ -507,7 +511,16 @@ + freez(config->confdir); + freez(config->logdir); + +- freez(config->haddr); ++ if(config -> hspecs != NULL) ++ { ++ int i; ++ for (i=0; i < config->hspecs_occupied; ++i) ++ { ++ freez(config->hspecs[i].haddr); ++ freez(config->hspecs[i].hport); ++ } ++ } ++ freez(config->hspecs); + freez(config->logfile); + + for (i = 0; i < MAX_ACTION_FILES; i++) +@@ -570,6 +583,28 @@ + * Returns : The configuration_spec, or NULL on error. + * + *********************************************************************/ ++static void fail_load_config_memory(struct file_list *fs, struct configuration_spec *config) ++{ ++ freez(fs->filename); ++ freez(fs); ++ if (config != NULL) ++ { ++ if(config -> hspecs != NULL) ++ { ++ int i; ++ for (i=0; i < config->hspecs_occupied; ++i) ++ { ++ freez(config->hspecs[i].haddr); ++ freez(config->hspecs[i].hport); ++ } ++ } ++ freez(config -> hspecs); ++ } ++ freez(config); ++ log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration"); ++ /* Never get here - LOG_LEVEL_FATAL causes program exit */ ++} ++ + struct configuration_spec * load_config(void) + { + char buf[BUFFER_SIZE]; +@@ -601,12 +636,7 @@ + fs->f = config = (struct configuration_spec *)zalloc(sizeof(*config)); + + if (config==NULL) +- { +- freez(fs->filename); +- freez(fs); +- log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration"); +- /* Never get here - LOG_LEVEL_FATAL causes program exit */ +- } ++ fail_load_config_memory(fs,config); + + /* + * This is backwards from how it's usually done. +@@ -623,7 +653,7 @@ + * Set to defaults + */ + config->multi_threaded = 1; +- config->hport = HADDR_PORT; ++ config->hspecs = NULL; + config->buffer_limit = 4096 * 1024; + config->usermanual = strdup(USER_MANUAL_URL); + config->proxy_args = strdup(""); +@@ -640,9 +670,6 @@ + char cmd[BUFFER_SIZE]; + char arg[BUFFER_SIZE]; + char tmp[BUFFER_SIZE]; +-#ifdef FEATURE_ACL +- struct access_control_list *cur_acl; +-#endif /* def FEATURE_ACL */ + struct forward_spec *cur_fwd; + int vec_count; + char *vec[3]; +@@ -753,74 +780,23 @@ + * *************************************************************************/ + #ifdef FEATURE_ACL + case hash_deny_access: +- vec_count = ssplit(arg, " \t", vec, SZ(vec), 1, 1); +- +- if ((vec_count != 1) && (vec_count != 2)) +- { +- log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for " +- "deny-access directive in configuration file."); +- string_append(&config->proxy_args, +- "
\nWARNING: Wrong number of parameters for " +- "deny-access directive in configuration file.

\n"); +- continue; +- } +- +- /* allocate a new node */ +- cur_acl = (struct access_control_list *) zalloc(sizeof(*cur_acl)); +- +- if (cur_acl == NULL) +- { +- log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration"); +- /* Never get here - LOG_LEVEL_FATAL causes program exit */ +- continue; +- } +- cur_acl->action = ACL_DENY; +- +- if (acl_addr(vec[0], cur_acl->src) < 0) +- { +- log_error(LOG_LEVEL_ERROR, "Invalid source IP for deny-access " +- "directive in configuration file: \"%s\"", vec[0]); +- string_append(&config->proxy_args, +- "
\nWARNING: Invalid source IP for deny-access directive" +- " in configuration file: \""); +- string_append(&config->proxy_args, +- vec[0]); +- string_append(&config->proxy_args, +- "\"

\n"); +- freez(cur_acl); +- continue; +- } +- if (vec_count == 2) ++ switch (ssplit(arg, " \t", vec, SZ(vec), 1, 1)) + { +- if (acl_addr(vec[1], cur_acl->dst) < 0) +- { +- log_error(LOG_LEVEL_ERROR, "Invalid destination IP for deny-access " +- "directive in configuration file: \"%s\"", vec[0]); +- string_append(&config->proxy_args, +- "
\nWARNING: Invalid destination IP for deny-access directive" +- " in configuration file: \""); +- string_append(&config->proxy_args, +- vec[0]); ++ case 1: ++ config->acl = add_to_acl_list(config->acl, ACL_DENY, vec[0], NULL, &config->proxy_args); ++ break; ++ case 2: ++ config->acl = add_to_acl_list(config->acl, ACL_DENY, vec[0], vec[1], &config->proxy_args); ++ break; ++ default: ++ log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for " ++ "deny-access directive in configuration file."); + string_append(&config->proxy_args, +- "\"

\n"); +- freez(cur_acl); +- continue; +- } ++ "
\nWARNING: Wrong number of parameters for " ++ "deny-access directive in configuration file.

\n"); + } +- +- /* +- * Add it to the list. Note we reverse the list to get the +- * behaviour the user expects. With both the ACL and +- * actions file, the last match wins. However, the internal +- * implementations are different: The actions file is stored +- * in the same order as the file, and scanned completely. +- * With the ACL, we reverse the order as we load it, then +- * when we scan it we stop as soon as we get a match. +- */ +- cur_acl->next = config->acl; +- config->acl = cur_acl; +- + continue; ++ + #endif /* def FEATURE_ACL */ + + /* ************************************************************************* +@@ -914,16 +890,18 @@ + + if (strcmp(p, ".") != 0) + { +- cur_fwd->forward_host = strdup(p); ++ cur_fwd->forward_malloc = strdup(p); ++ cur_fwd->forward_family = -1; + +- if (NULL != (p = strchr(cur_fwd->forward_host, ':'))) +- { +- *p++ = '\0'; +- cur_fwd->forward_port = atoi(p); +- } ++ parse_pf_ip(cur_fwd->forward_malloc, ++ &cur_fwd->forward_host, ++ &cur_fwd->forward_port_str, ++ &cur_fwd->forward_family); ++ cur_fwd->forward_port = atoi(cur_fwd->forward_port_str); + + if (cur_fwd->forward_port <= 0) + { ++ cur_fwd->forward_port_str = "8000"; + cur_fwd->forward_port = 8000; + } + } +@@ -977,15 +955,27 @@ + + if (strcmp(p, ".") != 0) + { +- cur_fwd->gateway_host = strdup(p); ++ /* SOCKS is IPv4-specific */ ++ int pf = PF_INET; + +- if (NULL != (p = strchr(cur_fwd->gateway_host, ':'))) ++ cur_fwd->gateway_malloc = strdup(p); ++ if (parse_pf_ip(cur_fwd->gateway_malloc, ++ &cur_fwd->gateway_host, ++ &cur_fwd->gateway_port_str, ++ &pf) != 0) + { +- *p++ = '\0'; +- cur_fwd->gateway_port = atoi(p); ++ log_error(LOG_LEVEL_ERROR, "Could not parse forward-socks4 host: %s",p); ++ cur_fwd->gateway_host = NULL; ++ cur_fwd->gateway_port_str = NULL; ++ freez(cur_fwd->gateway_malloc); ++ continue; + } ++ ++ cur_fwd->gateway_port = atoi(cur_fwd->gateway_port_str); ++ + if (cur_fwd->gateway_port <= 0) + { ++ cur_fwd->gateway_port_str = "1080"; + cur_fwd->gateway_port = 1080; + } + } +@@ -995,16 +985,26 @@ + + if (strcmp(p, ".") != 0) + { +- cur_fwd->forward_host = strdup(p); ++ cur_fwd->forward_malloc = strdup(p); ++ cur_fwd->forward_family = -1; + +- if (NULL != (p = strchr(cur_fwd->forward_host, ':'))) ++ parse_pf_ip(cur_fwd->forward_malloc, ++ &cur_fwd->forward_host, ++ &cur_fwd->forward_port_str, ++ &cur_fwd->forward_family); ++ cur_fwd->forward_port = atoi(cur_fwd->forward_port_str); ++ ++ if (cur_fwd->forward_port <= 0) + { +- *p++ = '\0'; +- cur_fwd->forward_port = atoi(p); ++ cur_fwd->forward_port_str = "8000"; ++ cur_fwd->forward_port = 8000; + } + ++ cur_fwd->forward_port = atoi(p); ++ + if (cur_fwd->forward_port <= 0) + { ++ cur_fwd->forward_port_str = "8000"; + cur_fwd->forward_port = 8000; + } + } +@@ -1056,16 +1056,30 @@ + /* Parse the SOCKS proxy host[:port] */ + p = vec[1]; + +- cur_fwd->gateway_host = strdup(p); +- +- if (NULL != (p = strchr(cur_fwd->gateway_host, ':'))) +- { +- *p++ = '\0'; +- cur_fwd->gateway_port = atoi(p); +- } +- if (cur_fwd->gateway_port <= 0) + { +- cur_fwd->gateway_port = 1080; ++ /* SOCKS is IPv4-specific */ ++ int pf = PF_INET; ++ ++ cur_fwd->gateway_malloc = strdup(p); ++ if (parse_pf_ip(cur_fwd->gateway_malloc, ++ &cur_fwd->gateway_host, ++ &cur_fwd->gateway_port_str, ++ &pf) != 0) ++ { ++ log_error(LOG_LEVEL_ERROR, "Could not parse forward-socks4a host: %s",p); ++ cur_fwd->gateway_host = NULL; ++ cur_fwd->gateway_port_str = NULL; ++ freez(cur_fwd->gateway_malloc); ++ continue; ++ } ++ ++ cur_fwd->gateway_port = atoi(cur_fwd->gateway_port_str); ++ ++ if (cur_fwd->gateway_port <= 0) ++ { ++ cur_fwd->gateway_port_str = "1080"; ++ cur_fwd->gateway_port = 1080; ++ } + } + + /* Parse the parent HTTP proxy host[:port] */ +@@ -1073,16 +1087,26 @@ + + if (strcmp(p, ".") != 0) + { +- cur_fwd->forward_host = strdup(p); ++ cur_fwd->forward_malloc = strdup(p); ++ cur_fwd->forward_family = -1; + +- if (NULL != (p = strchr(cur_fwd->forward_host, ':'))) ++ parse_pf_ip(cur_fwd->forward_malloc, ++ &cur_fwd->forward_host, ++ &cur_fwd->forward_port_str, ++ &cur_fwd->forward_family); ++ cur_fwd->forward_port = atoi(cur_fwd->forward_port_str); ++ ++ if (cur_fwd->forward_port <= 0) + { +- *p++ = '\0'; +- cur_fwd->forward_port = atoi(p); ++ cur_fwd->forward_port_str = "8000"; ++ cur_fwd->forward_port = 8000; + } + ++ cur_fwd->forward_port = atoi(p); ++ + if (cur_fwd->forward_port <= 0) + { ++ cur_fwd->forward_port_str = "8000"; + cur_fwd->forward_port = 8000; + } + } +@@ -1108,10 +1132,49 @@ + * listen-address [ip][:port] + * *************************************************************************/ + case hash_listen_address : +- freez(config->haddr); +- config->haddr = strdup(arg); ++ { ++ struct bind_spec *bs; ++ char *arg_cpy; ++ if (config->hspecs == NULL) ++ { ++ /* This is the first we'll bind to */ ++ config->hspecs = calloc(2,sizeof(struct bind_spec)); ++ if (config->hspecs == NULL) ++ fail_load_config_memory(fs,config); ++ config->hspecs_size = 2; ++ config->hspecs_occupied = 0; ++ } ++ ++ arg_cpy = strdup(arg); ++ if (arg_cpy == NULL) ++ fail_load_config_memory(fs,config); ++ if (config->hspecs_occupied == config->hspecs_size) ++ { ++ struct bind_spec *new_hspecs; ++ config->hspecs_size *= 2; ++ new_hspecs = realloc(config->hspecs,config->hspecs_size * sizeof(struct bind_spec)); ++ if (new_hspecs == NULL) ++ { ++ /* Not enough memory to continue. Cancel changes. */ ++ config->hspecs_size /= 2; ++ fail_load_config_memory(fs,config); ++ } ++ config->hspecs = new_hspecs; ++ } ++ bs = &config->hspecs[(config->hspecs_occupied)++]; ++ bs->pf = -1; ++ parse_pf_ip(arg,&bs->haddr,&bs->hport,&bs->pf); ++ if (*bs->haddr == '\0') ++ { ++ bs->haddr = NULL; ++ } ++ else ++ { ++ (bs->haddr = strdup(bs->haddr)); ++ } ++ bs->hport = strdup(bs->hport); + continue; +- ++ } + /* ************************************************************************* + * logdir directory-name + * *************************************************************************/ +@@ -1134,75 +1197,21 @@ + * *************************************************************************/ + #ifdef FEATURE_ACL + case hash_permit_access: +- vec_count = ssplit(arg, " \t", vec, SZ(vec), 1, 1); +- +- if ((vec_count != 1) && (vec_count != 2)) +- { +- log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for " +- "permit-access directive in configuration file."); +- string_append(&config->proxy_args, +- "
\nWARNING: Wrong number of parameters for " +- "permit-access directive in configuration file.

\n"); +- +- continue; +- } +- +- /* allocate a new node */ +- cur_acl = (struct access_control_list *) zalloc(sizeof(*cur_acl)); +- +- if (cur_acl == NULL) +- { +- log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration"); +- /* Never get here - LOG_LEVEL_FATAL causes program exit */ +- continue; +- } +- cur_acl->action = ACL_PERMIT; +- +- if (acl_addr(vec[0], cur_acl->src) < 0) +- { +- log_error(LOG_LEVEL_ERROR, "Invalid source IP for permit-access " +- "directive in configuration file: \"%s\"", vec[0]); +- string_append(&config->proxy_args, +- "
\nWARNING: Invalid source IP for permit-access directive" +- " in configuration file: \""); +- string_append(&config->proxy_args, +- vec[0]); +- string_append(&config->proxy_args, +- "\"

\n"); +- freez(cur_acl); +- continue; +- } +- if (vec_count == 2) ++ switch (ssplit(arg, " \t", vec, SZ(vec), 1, 1)) + { +- if (acl_addr(vec[1], cur_acl->dst) < 0) +- { +- log_error(LOG_LEVEL_ERROR, "Invalid destination IP for " +- "permit-access directive in configuration file: \"%s\"", +- vec[0]); +- string_append(&config->proxy_args, +- "
\nWARNING: Invalid destination IP for permit-access directive" +- " in configuration file: \""); +- string_append(&config->proxy_args, +- vec[0]); ++ case 1: ++ config->acl = add_to_acl_list(config->acl, ACL_PERMIT, vec[0], NULL, &config->proxy_args); ++ break; ++ case 2: ++ config->acl = add_to_acl_list(config->acl, ACL_PERMIT, vec[0], vec[1], &config->proxy_args); ++ break; ++ default: ++ log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for " ++ "permit-access directive in configuration file."); + string_append(&config->proxy_args, +- "\"

\n"); +- freez(cur_acl); +- continue; +- } ++ "
\nWARNING: Wrong number of parameters for " ++ "permit-access directive in configuration file.

\n"); + } +- +- /* +- * Add it to the list. Note we reverse the list to get the +- * behaviour the user expects. With both the ACL and +- * actions file, the last match wins. However, the internal +- * implementations are different: The actions file is stored +- * in the same order as the file, and scanned completely. +- * With the ACL, we reverse the order as we load it, then +- * when we scan it we stop as soon as we get a match. +- */ +- cur_acl->next = config->acl; +- config->acl = cur_acl; +- + continue; + #endif /* def FEATURE_ACL */ + +@@ -1442,32 +1451,33 @@ + } + #endif /* def FEATURE_COOKIE_JAR */ + +- if ( NULL == config->haddr ) +- { +- config->haddr = strdup( HADDR_DEFAULT ); +- } +- +- if ( NULL != config->haddr ) ++ if ( config->hspecs == NULL ) + { +- if (NULL != (p = strchr(config->haddr, ':'))) +- { +- *p++ = '\0'; +- if (*p) +- { +- config->hport = atoi(p); +- } +- } +- +- if (config->hport <= 0) +- { +- *--p = ':'; +- log_error(LOG_LEVEL_FATAL, "invalid bind port spec %s", config->haddr); +- /* Never get here - LOG_LEVEL_FATAL causes program exit */ +- } +- if (*config->haddr == '\0') +- { +- config->haddr = NULL; +- } ++ /* No listen-address set. The default is localhost on port 8118, on IPv4 ++ and (if INET6 is defined) IPv6. ++ */ ++ struct bind_spec *bs; ++#ifdef INET6 ++ config->hspecs = calloc(2,sizeof(struct bind_spec)); ++ if (config->hspecs == NULL) ++ fail_load_config_memory(fs,config); ++ config->hspecs_size=2; ++ config->hspecs_occupied=1; ++ bs = &config->hspecs[0]; ++ bs->haddr = strdup("::1"); ++ bs->hport = strdup("8118"); ++ bs->pf = PF_UNSPEC; ++#else ++ config->hspecs = calloc(1,sizeof(struct bind_spec)); ++ if (config->hspecs == NULL) ++ fail_load_config_memory(fs,config); ++ config->hspecs_size=1; ++ config->hspecs_occupied=0; ++#endif ++ bs = &config->hspecs[config->hspecs_occupied++]; ++ bs->haddr = strdup("127.0.0.1"); ++ bs->hport = strdup("8118"); ++ bs->pf = PF_UNSPEC; + } + + /* +@@ -1509,31 +1519,29 @@ + struct configuration_spec * oldcfg = (struct configuration_spec *) + current_configfile->f; + /* +- * Check if config->haddr,hport == oldcfg->haddr,hport +- * +- * The following could be written more compactly as a single, +- * (unreadably long) if statement. ++ * Check if the listening addresses have changed + */ + config->need_bind = 0; +- if (config->hport != oldcfg->hport) +- { +- config->need_bind = 1; +- } +- else if (config->haddr == NULL) ++ if (config -> hspecs_occupied == oldcfg -> hspecs_occupied) + { +- if (oldcfg->haddr != NULL) ++ int bs_index; ++ struct bind_spec *hspec; ++ struct bind_spec *oldhspec; ++ hspec = config -> hspecs; ++ oldhspec = oldcfg -> hspecs; ++ for(bs_index = 0; bs_index < oldcfg->hspecs_occupied; ++bs_index) + { +- config->need_bind = 1; ++ if (strcmp(hspec[bs_index].haddr,oldhspec[bs_index].haddr) != 0 ++ || strcmp(hspec[bs_index].hport,oldhspec[bs_index].hport) != 0 ++ || hspec[bs_index].pf != hspec[bs_index].pf) ++ { ++ config -> need_bind = 1; ++ break; ++ } + } + } +- else if (oldcfg->haddr == NULL) +- { +- config->need_bind = 1; +- } +- else if (0 != strcmp(config->haddr, oldcfg->haddr)) +- { +- config->need_bind = 1; +- } ++ else ++ config-> need_bind = 1; + + current_configfile->unloader = unload_configfile; + } +diff -urNad privoxy~/loaders.c privoxy/loaders.c +--- privoxy~/loaders.c ++++ privoxy/loaders.c +@@ -11,6 +11,9 @@ + * Copyright : Written by and Copyright (C) 2001 the SourceForge + * Privoxy team. http://www.privoxy.org/ + * ++ * Modified by Lionel Elie Mamane ++ * for IPv6 support on 8 December 2002, 24 January 2003. ++ * + * Based on the Internet Junkbuster originally written + * by and Copyright (C) 1997 Anonymous Coders and + * Junkbusters Corporation. http://www.junkbusters.com +@@ -427,6 +430,7 @@ + + freez(csp->ip_addr_str); + freez(csp->my_ip_addr_str); ++ freez(csp->my_port_str); + freez(csp->my_hostname); + freez(csp->x_forwarded); + freez(csp->iob->buf); +diff -urNad privoxy~/miscutil.h privoxy/miscutil.h +--- privoxy~/miscutil.h ++++ privoxy/miscutil.h +@@ -142,6 +142,15 @@ + + #include "project.h" + ++/* Fix a problem with Solaris. There should be no effect on other ++ * platforms. ++ * Solaris's isspace() is a macro which uses it's argument directly ++ * as an array index. Therefore we need to make sure that high-bit ++ * characters generate +ve values, and ideally we also want to make ++ * the argument match the declared parameter type of "int". ++ */ ++#define ijb_isdigit(__X) isdigit((int)(unsigned char)(__X)) ++ + #if defined(__cplusplus) + extern "C" { + #endif +diff -urNad privoxy~/parsers.c privoxy/parsers.c +--- privoxy~/parsers.c ++++ privoxy/parsers.c +@@ -16,6 +16,9 @@ + * Copyright : Written by and Copyright (C) 2001 the SourceForge + * Privoxy team. http://www.privoxy.org/ + * ++ * Modified by Lionel Elie Mamane ++ * for IPv6 support on 24 January 2003. ++ * + * Based on the Internet Junkbuster originally written + * by and Copyright (C) 1997 Anonymous Coders and + * Junkbusters Corporation. http://www.junkbusters.com +@@ -1953,6 +1956,167 @@ + } + #endif /* def FEATURE_FORCE_LOAD */ + ++/********************************************************************* ++ * ++ * Function : parse_pf_ip_netmask ++ * ++ * Description : Parse an IPv{4,6} litteral or hostname ++ * with optional port and optional explicit family ++ * and optional netmask ++ * ++ * Parameters : ++ * 0 : string = the string to parse ++ * 1 : host = Is set to point to the hostname or IP literal ++ * part ++ * 2 : port = Is set to point to the port part, ++ * or NULL if no port in string ++ * 3 : pf = pointer used to return the address family ++ * pf is a value-result argument: ++ * If it is set to -1, then parse_pf_ip will set it ++ * to the address family of the pf_ip string ++ * else, it won't touch it, and fail if the two ++ * cannot match ++ * 4 : pointer used to return the mask length ++ * Set to -1 if no mask ++ * ++ * Returns : 0 on success ++ * ++ *********************************************************************/ ++int parse_pf_ip_netmask(char *string, char **host, char **port, int *pf, int *masklength) ++{ ++ int i; ++ char *p; ++ ++ *masklength = -1; ++ ++ if ((p = strchr(string, '/')) != NULL) ++ { ++ *p++ = '\0'; ++ ++ if (ijb_isdigit(*p) == 0) ++ { ++ return -1; ++ } ++ i = atoi(p); ++ if ( i < 0 ) ++ return -1; ++ *masklength = i; ++ } ++ ++ return parse_pf_ip(string, host, port, pf); ++} ++ ++/********************************************************************* ++ * ++ * Function : parse_pf_ip ++ * ++ * Description : Parse an IPv{4,6} litteral or hostname ++ * with optional port and optional explicit family ++ * ++ * Parameters : ++ * 0 : string = the string to parse ++ * 1 : host = Is set to point to the hostname or IP literal ++ * part ++ * 2 : port = Is set to point to the port part, ++ * or NULL if no port in string ++ * 3 : pf = pointer used to return the address family ++ * pf is a value-result argument: ++ * If it is set to -1, then parse_pf_ip will set it ++ * to the address family of the pf_ip string ++ * else, it won't touch it, and fail if the two ++ * cannot match ++ * ++ * Returns : 0 on success ++ * ++ *********************************************************************/ ++int parse_pf_ip(char *string, char **host, char **port, int *pf) ++{ ++ if (pf != NULL && *pf == -1) ++ *pf = PF_UNSPEC; ++ ++ /* See if we want to override the default protocol family */ ++ if (strncmpic(string, "ipv4:", 5) == 0) ++ { ++ string += 5; ++ if (pf!=NULL) ++ { ++ if(*pf==PF_INET || *pf==PF_UNSPEC) ++ *pf = AF_INET; ++ else ++ { ++ log_error(LOG_LEVEL_ERROR,"%s","IPv4 address found where other awaited"); ++ return -2; ++ } ++ } ++ } ++ else if (strncmpic(string, "ipv6:", 5) == 0) ++ { ++#ifdef INET6 ++ string += 5; ++ if(*pf==PF_INET6 || *pf==PF_UNSPEC) ++ *pf = AF_INET6; ++ else ++ { ++ log_error(LOG_LEVEL_ERROR,"%s","IPv6 address found where other awaited"); ++ return -2; ++ } ++#else ++ log_error(LOG_LEVEL_ERROR,"%s","This privoxy hasn't IPv6 support"); ++ return -1; ++#endif ++ } ++ return parse_ip(string, host, port); ++} ++ ++/********************************************************************* ++ * ++ * Function : parse_ip ++ * ++ * Description : Parse an IPv{4,6} litteral or hostname ++ * with optional port ++ * ++ * Parameters : ++ * 0 : string = the string to parse ++ * 1 : host = Is set to point to the hostname or IP literal ++ * part ++ * 2 : port = Is set to point to the port part, ++ * or NULL if no port in string ++ * Returns : 0 on success ++ * ++ *********************************************************************/ ++int parse_ip(char *string, char **host, char **port) ++{ ++ char *p; ++ int skip; ++ ++ /* allow IPv6 address literal: [numbers:with:colons]:port/mask */ ++ if (string[0] == '[' && (p = strchr(string, ']'))) ++ { ++ *p++ = '\0'; ++ skip = 1; ++ } ++ else ++ { ++ p = string; ++ skip = 0; ++ } ++ ++ if (host != NULL) ++ *host = string + skip; ++ ++ for(;*p != '\0'; ++p) ++ { ++ if (*p == ':') ++ { ++ *p++ = '\0'; ++ break; ++ } ++ } ++ if (port != NULL) ++ *port = p; ++ return 0; ++} ++ + + /* + Local Variables: +diff -urNad privoxy~/parsers.h privoxy/parsers.h +--- privoxy~/parsers.h ++++ privoxy/parsers.h +@@ -19,6 +19,9 @@ + * Copyright : Written by and Copyright (C) 2001 the SourceForge + * Privoxy team. http://www.privoxy.org/ + * ++ * Modified by Lionel Elie Mamane ++ * for IPv6 support on 24 January 2003. ++ * + * Based on the Internet Junkbuster originally written + * by and Copyright (C) 1997 Anonymous Coders and + * Junkbusters Corporation. http://www.junkbusters.com +@@ -227,6 +230,10 @@ + extern jb_err server_transfer_coding (struct client_state *csp, char **header); + extern jb_err server_http (struct client_state *csp, char **header); + ++extern int parse_pf_ip_netmask(char *string, char **host, char **port, int *pf, int *masklength); ++extern int parse_pf_ip(char *string, char ** host, char ** port, int *pf); ++extern int parse_ip(char *string, char ** host, char** port); ++ + #ifdef FEATURE_FORCE_LOAD + extern int strclean(const char *string, const char *substring); + #endif /* def FEATURE_FORCE_LOAD */ +diff -urNad privoxy~/project.h privoxy/project.h +--- privoxy~/project.h ++++ privoxy/project.h +@@ -549,6 +549,20 @@ + + #endif /* ndef _WIN32 */ + ++#include "jb_socket_set.h" ++ ++#ifdef INET6 ++/** ++ * Get from the operating system structures big enough ++ * to put a network address in, namely sockaddr_storage ++ */ ++#include ++/** ++ * If no IPv6 support, just use the old sockaddr ++ */ ++#else ++#define sockaddr_storage sockaddr ++#endif + + /** + * A standard error code. This should be JB_ERR_OK or one of the JB_ERR_xxx +@@ -618,19 +632,6 @@ + */ + #define FOREVER 1 + +-/** +- * Default IP address to listen on, as a string. +- * Set to "127.0.0.1". +- */ +-#define HADDR_DEFAULT "127.0.0.1" +- +-/** +- * Default port to listen on, as a number. +- * Set to 8118. +- */ +-#define HADDR_PORT 8118 +- +- + /* Forward def for struct client_state */ + struct configuration_spec; + +@@ -709,13 +710,16 @@ + char *ver; /**< Protocol version */ + int status; /**< HTTP Status */ + ++ char *host_port_malloc; /**< malloc used for place wher host and port_str are */ + char *host; /**< Host part of URL */ + int port; /**< Port of URL or 80 (default) */ ++ char *port_str; /**< Port of URL, as string */ + char *path; /**< Path of URL */ + char *hostport; /**< host[:port] */ + int ssl; /**< Flag if protocol is https */ + +- char *host_ip_addr_str; /**< String with dotted decimal representation ++ char *host_ip_addr_str; /**< String with dotted decimal representation (IPv4) ++ or hexadecimal colon-separated (IPv6) + of host's IP. NULL before connect_to() */ + + char *dbuffer; /**< Buffer with '\0'-delimited domain name. */ +@@ -1039,13 +1043,16 @@ + As a string. */ + char *ip_addr_str; + /** Client PC's IP address, as reported by the accept() function. +- As a number. */ +- long ip_addr_long; ++ As an address. */ ++ struct sockaddr_storage ip_addr_addr; + + /** Our IP address. I.e. the IP address that the client used to reach us, + as a string. */ + char *my_ip_addr_str; + ++ /** Our port. I.e. the port the client used to reach us */ ++ char *my_port_str; ++ + /** Our hostname. I.e. the reverse DNS of the IP address that the client + used to reach us, as a string. */ + char *my_hostname; +@@ -1214,18 +1221,33 @@ + /** Connection type. Must be SOCKS_NONE, SOCKS_4, or SOCKS_4A. */ + int type; + ++ /** pointer returned by the malloc used for gateway_host and gateway_port_str */ ++ char *gateway_malloc; ++ + /** SOCKS server hostname. Only valid if "type" is SOCKS_4 or SOCKS_4A. */ + char *gateway_host; + + /** SOCKS server port. */ + int gateway_port; + ++ /** SOCKS server port, as string. */ ++ char *gateway_port_str; ++ ++ /** pointer returned by the malloc used for forward_host and forward_port_str */ ++ char *forward_malloc; ++ ++ /** Parent HTTP proxy address family. */ ++ int forward_family; ++ + /** Parent HTTP proxy hostname, or NULL for none. */ + char *forward_host; + + /** Parent HTTP proxy port. */ + int forward_port; + ++ /** Parent HTTP proxy port as string. */ ++ char *forward_port_str; ++ + /** Next entry in the linked list. */ + struct forward_spec *next; + }; +@@ -1234,7 +1256,7 @@ + /** + * Initializer for a static struct forward_spec. + */ +-#define FORWARD_SPEC_INITIALIZER { { URL_SPEC_INITIALIZER }, 0, NULL, 0, NULL, 0, NULL } ++#define FORWARD_SPEC_INITIALIZER { { URL_SPEC_INITIALIZER }, 0, NULL, NULL, 0, NULL, NULL, 0, NULL, 0, NULL, NULL} + + + /** +@@ -1263,7 +1285,8 @@ + */ + struct access_control_addr + { +- unsigned long addr; /**< The IP address as an integer. */ ++ struct sockaddr_storage addr; /**< The IP address. */ ++ size_t addrlen; + unsigned long mask; /**< The network mask as an integer. */ + unsigned long port; /**< The port number. */ + }; +@@ -1295,6 +1318,17 @@ + /** configuration_spec::feature_flags: Web-based toggle. */ + #define RUNTIME_FEATURE_CGI_TOGGLE 2 + ++struct bind_spec ++{ ++ /** IP address to bind to. */ ++ char *haddr; ++ ++ /** Port to bind to. */ ++ char *hport; ++ ++ /** Address family */ ++ int pf; ++}; + + /** + * Data loaded from the configuration file. +@@ -1355,11 +1389,13 @@ + + #endif /* def FEATURE_COOKIE_JAR */ + +- /** IP address to bind to. Defaults to HADDR_DEFAULT == 127.0.0.1. */ +- const char *haddr; +- +- /** Port to bind to. Defaults to HADDR_PORT == 8118. */ +- int hport; ++ /* IP addresses and ports to bind to. ++ Defaults to HSPECS_DEFAULT == {ipv4:127.0.0.1:8118, ipv6:[::1]:8118}. */ ++ struct bind_spec *hspecs; ++ /* size allocated */ ++ unsigned int hspecs_size; ++ /* number of entries */ ++ unsigned int hspecs_occupied; + + /** Size limit for IOB */ + size_t buffer_limit; +diff -urNad privoxy~/urlmatch.c privoxy/urlmatch.c +--- privoxy~/urlmatch.c ++++ privoxy/urlmatch.c +@@ -133,6 +133,7 @@ + #include "ssplit.h" + #include "miscutil.h" + #include "errlog.h" ++#include "parsers.h" + + const char urlmatch_h_rcs[] = URLMATCH_H_VERSION; + +@@ -156,7 +157,7 @@ + freez(http->cmd); + freez(http->ocmd); + freez(http->gpc); +- freez(http->host); ++ freez(http->host_port_malloc); + freez(http->url); + freez(http->hostport); + freez(http->path); +@@ -298,8 +299,6 @@ + */ + { + char *buf; +- char *host; +- char *port; + + buf = strdup(http->hostport); + if (buf == NULL) +@@ -307,38 +306,34 @@ + return JB_ERR_MEMORY; + } + ++ http->host_port_malloc = buf; ++ + /* check if url contains username and/or password */ +- host = strchr(buf, '@'); +- if (host != NULL) ++ buf = strchr(buf, '@'); ++ if (buf != NULL) + { + /* Contains username/password, skip it and the @ sign. */ +- host++; ++ buf++; + } + else + { + /* No username or password. */ +- host = buf; ++ buf = http->host_port_malloc; + } + +- /* check if url contains port */ +- port = strchr(host, ':'); +- if (port != NULL) ++ parse_ip(buf,&http->host,&http->port_str); ++ ++ if (*http->port_str != '\0') + { +- /* Contains port */ +- /* Terminate hostname and point to start of port string */ +- *port++ = '\0'; +- http->port = atoi(port); ++ http->port = atoi(http->port_str); + } + else + { + /* No port specified. */ +- http->port = (http->ssl ? 443 : 80); ++ http->port_str = (http->ssl ? "143" : "80"); ++ http->port = (http->ssl ? 443 : 80); + } + +- http->host = strdup(host); +- +- free(buf); +- + if (http->host == NULL) + { + return JB_ERR_MEMORY; +@@ -662,9 +657,8 @@ + * written to system log) + * + *********************************************************************/ +-jb_err create_url_spec(struct url_spec * url, const char * buf) ++jb_err create_url_spec(struct url_spec * url, char * buf) + { +- char *p; + + assert(url); + assert(buf); +@@ -681,22 +675,25 @@ + { + return JB_ERR_MEMORY; + } +- +- if ((p = strchr(buf, '/')) != NULL) + { +- if (NULL == (url->path = strdup(p))) ++ char *p; ++ ++ if ((p = strchr(buf, '/')) != NULL) + { +- freez(url->spec); +- return JB_ERR_MEMORY; ++ if (NULL == (url->path = strdup(p))) ++ { ++ freez(url->spec); ++ return JB_ERR_MEMORY; ++ } ++ url->pathlen = strlen(url->path); ++ *p = '\0'; + } +- url->pathlen = strlen(url->path); +- *p = '\0'; +- } +- else +- { +- url->path = NULL; +- url->pathlen = 0; +- } ++ else ++ { ++ url->path = NULL; ++ url->pathlen = 0; ++ } ++ } + if (url->path) + { + int errcode; +@@ -735,15 +732,12 @@ + return JB_ERR_PARSE; + } + } +- if ((p = strchr(buf, ':')) == NULL) +- { +- url->port = 0; +- } +- else ++ + { +- *p++ = '\0'; +- url->port = atoi(p); +- } ++ char *p; ++ parse_ip(buf,&buf,&p); ++ url->port = atoi(p); ++ } + + if (buf[0] != '\0') + { +@@ -775,12 +769,13 @@ + return JB_ERR_MEMORY; + } + +- /* +- * Map to lower case +- */ +- for (p = url->dbuffer; *p ; p++) + { +- *p = tolower((int)(unsigned char)*p); ++ char* p; ++ /* map to lower case */ ++ for (p = url->dbuffer; *p ; p++) ++ { ++ *p = tolower((int)(unsigned char)*p); ++ } + } + + /* +diff -urNad privoxy~/urlmatch.h privoxy/urlmatch.h +--- privoxy~/urlmatch.h ++++ privoxy/urlmatch.h +@@ -79,7 +79,7 @@ + extern int url_match(const struct url_spec *pattern, + const struct http_request *url); + +-extern jb_err create_url_spec(struct url_spec * url, const char * buf); ++extern jb_err create_url_spec(struct url_spec * url, char * buf); + extern void free_url_spec(struct url_spec *url); + + diff --git a/debian/patches/04_nomultiproxy.dpatch b/debian/patches/04_nomultiproxy.dpatch index 2a451a18..5f7fd28d 100644 --- a/debian/patches/04_nomultiproxy.dpatch +++ b/debian/patches/04_nomultiproxy.dpatch @@ -7,9 +7,9 @@ @DPATCH@ diff -urNad privoxy~/config privoxy/config ---- privoxy~/config 2006-02-05 16:23:12.000000000 +0100 -+++ privoxy/config 2006-02-05 16:25:45.000000000 +0100 -@@ -889,11 +889,10 @@ +--- privoxy~/config ++++ privoxy/config +@@ -931,11 +931,10 @@ # This feature allows routing of HTTP requests through a chain # of multiple proxies. It can be used to better protect privacy # and confidentiality when accessing specific domains by routing @@ -18,34 +18,17 @@ diff -urNad privoxy~/config privoxy/config -# proxy to speed up browsing. Or chaining to a parent proxy may be -# necessary because the machine that Privoxy runs on has no direct -# Internet access. -+# requests to those domains through an anonymous public proxy -+# or to use a caching proxy to speed up browsing. Or chaining to -+# a parent proxy may be necessary because the machine that Privoxy -+# runs on has no direct Internet access. - # ++# requests to those domains through an anonymous public proxy or ++# use a caching proxy to speed up browsing. Or chaining to a parent ++# proxy may be necessary because the machine that Privoxy runs on has ++# no direct Internet access. + # # Also specified here are SOCKS proxies. Privoxy supports the SOCKS # 4 and SOCKS 4A protocols. -diff -urNad privoxy~/doc/source/faq.sgml privoxy/doc/source/faq.sgml ---- privoxy~/doc/source/faq.sgml 2006-02-05 16:23:12.000000000 +0100 -+++ privoxy/doc/source/faq.sgml 2006-02-05 16:25:45.000000000 +0100 -@@ -1255,13 +1255,6 @@ - on (those suspicious) people with a more than average preference for privacy. - - -- You can find a list of anonymous public proxies at multiproxy.org and many -- more through Google. A particularly interesting project is the JAP service -- offered by the Technical University of Dresden (http://anon.inf.tu-dresden.de/index_en.html). -- -- - There is, however, even in the single-machine case the possibility to make the - server believe that your machine is in fact a shared proxy serving a whole big - LAN, and we are looking into that. diff -urNad privoxy~/doc/source/p-config.sgml privoxy/doc/source/p-config.sgml ---- privoxy~/doc/source/p-config.sgml 2006-02-05 16:23:12.000000000 +0100 -+++ privoxy/doc/source/p-config.sgml 2006-02-05 16:25:45.000000000 +0100 -@@ -1519,9 +1519,8 @@ +--- privoxy~/doc/source/p-config.sgml ++++ privoxy/doc/source/p-config.sgml +@@ -1606,9 +1606,8 @@ multiple proxies. It can be used to better protect privacy and confidentiality when accessing specific domains by routing requests to those domains diff --git a/debian/patches/05_defaut_action.dpatch b/debian/patches/05_defaut_action.dpatch index cf779e0b..716d81c6 100644 --- a/debian/patches/05_defaut_action.dpatch +++ b/debian/patches/05_defaut_action.dpatch @@ -6,32 +6,38 @@ @DPATCH@ diff -urNad privoxy~/default.action.master privoxy/default.action.master ---- privoxy~/default.action.master 2006-02-05 16:23:12.000000000 +0100 -+++ privoxy/default.action.master 2006-02-05 16:25:47.000000000 +0100 -@@ -1444,6 +1444,8 @@ - .microsoft.com - #MASTER# PROBLEM-URL: http://javabog.dk/ijk/ - javabog.dk/ijk/ -+#MASTER# PROBLEM-URL: http://validator.w3.org/ -+/valid- - - #---------------------------------------------------------------------------- - # These don't work without the referrer information: -@@ -1464,6 +1466,8 @@ - #MASTER# PROBLEM-URL: http://www.mandrakelinux.com/en/ftp.php3 - #MASTER# REMARKS: Link to download page breaks +--- privoxy~/default.action.master ++++ privoxy/default.action.master +@@ -1593,6 +1593,8 @@ www.mandrakelinux.com/en/ftp.php3 + #MASTER# REMARKS: Actions Tracker 1313157 + validator.w3.org/check\?uri=referer +#MASTER# PROBLEM-URL: http://www.petitiononline.com/mod_perl/signed.cgi?eldred&2901 +www.petitiononline.com/mod_perl/signed.cgi #---------------------------------------------------------------------------- # These animated gifs are either useful or nice: -@@ -1601,6 +1605,8 @@ +@@ -1714,6 +1716,10 @@ + #MASTER# PROBLEM-URL: http://www.nasa.gov + #MASTER# REMARKS: No progress past main page without js-annoyances + .nasa.gov ++#MASTER# PROBLEM-URL: http://www2.cnrs.fr/presse/communique/900.htm ++.cnrs.fr ++#MASTER# PROBLEM-URL: http://blogs.msdn.com/wga/archive/2006/07/16/667063.aspx ++blogs.msdn.com + + {-filter{unsolicited-popups}} + #MASTER# DONT-VERIFY +@@ -1733,6 +1739,12 @@ cf.nbc4.com/ #MASTER# PROBLEM-URL: http://www.hh.schule.de/ak/nt/ www.hh.schule.de/ak/nt/ +#MASTER# PROBLEM-URL: http://www.perl.com/language/newdocs/pod/perlop.html#Regexp_Quote_Like_Operators +www.perl.com/language/newdocs/pod/ ++#MASTER# PROBLEM-URL: http://www2.cnrs.fr/presse/communique/900.htm ++.cnrs.fr ++#MASTER# PROBLEM-URL: http://blogs.msdn.com/wga/archive/2006/07/16/667063.aspx ++blogs.msdn.com - {+fast-redirects -block} + {+fast-redirects{check-decoded-url} -block} #MASTER# PROBLEM-URL: http://isbn.nu/0596001088/price/2.html diff --git a/debian/patches/06_8bit_manual.dpatch b/debian/patches/06_8bit_manual.dpatch index 3ddc5869..e3ac205f 100644 --- a/debian/patches/06_8bit_manual.dpatch +++ b/debian/patches/06_8bit_manual.dpatch @@ -5,32 +5,32 @@ ## DP: Stop converting 8bit chars in the documentation (#203697) @DPATCH@ -diff -urNad privoxy-dpatch~/doc/source/ldp.dsl.in privoxy-dpatch/doc/source/ldp.dsl.in ---- privoxy-dpatch~/doc/source/ldp.dsl.in 2006-02-05 16:17:43.000000000 +0100 -+++ privoxy-dpatch/doc/source/ldp.dsl.in 2006-02-05 16:17:46.000000000 +0100 +diff -urNad privoxy~/doc/source/ldp.dsl.in privoxy/doc/source/ldp.dsl.in +--- privoxy~/doc/source/ldp.dsl.in ++++ privoxy/doc/source/ldp.dsl.in @@ -47,9 +47,9 @@ - - ;; this is necessary because right now jadetex does not understand - ;; symbolic entities, whereas things work well with numeric entities. --(declare-characteristic preserve-sdata? -- "UNREGISTERED::James Clark//Characteristic::preserve-sdata?" -- #f) -+;(declare-characteristic preserve-sdata? -+; "UNREGISTERED::James Clark//Characteristic::preserve-sdata?" -+; #f) - - ;; put the legal notice in a separate file - (define %generate-legalnotice-link% + + ;; this is necessary because right now jadetex does not understand + ;; symbolic entities, whereas things work well with numeric entities. +-(declare-characteristic preserve-sdata? +- "UNREGISTERED::James Clark//Characteristic::preserve-sdata?" +- #f) ++;(declare-characteristic preserve-sdata? ++; "UNREGISTERED::James Clark//Characteristic::preserve-sdata?" ++; #f) + + ;; put the legal notice in a separate file + (define %generate-legalnotice-link% @@ -257,9 +257,9 @@ - - ;; this is necessary because right now jadetex does not understand - ;; symbolic entities, whereas things work well with numeric entities. --(declare-characteristic preserve-sdata? -- "UNREGISTERED::James Clark//Characteristic::preserve-sdata?" -- #f) -+;(declare-characteristic preserve-sdata? -+; "UNREGISTERED::James Clark//Characteristic::preserve-sdata?" -+; #f) - - ;; put the legal notice in a separate file - (define %generate-legalnotice-link% + + ;; this is necessary because right now jadetex does not understand + ;; symbolic entities, whereas things work well with numeric entities. +-(declare-characteristic preserve-sdata? +- "UNREGISTERED::James Clark//Characteristic::preserve-sdata?" +- #f) ++;(declare-characteristic preserve-sdata? ++; "UNREGISTERED::James Clark//Characteristic::preserve-sdata?" ++; #f) + + ;; put the legal notice in a separate file + (define %generate-legalnotice-link% diff --git a/debian/patches/07_typos.dpatch b/debian/patches/07_typos.dpatch index 32669d15..7b534107 100644 --- a/debian/patches/07_typos.dpatch +++ b/debian/patches/07_typos.dpatch @@ -7,9 +7,9 @@ @DPATCH@ diff -urNad privoxy~/doc/source/privoxy-man-page.sgml privoxy/doc/source/privoxy-man-page.sgml ---- privoxy~/doc/source/privoxy-man-page.sgml 2006-02-05 22:03:58.000000000 +0100 -+++ privoxy/doc/source/privoxy-man-page.sgml 2006-02-11 18:32:40.000000000 +0100 -@@ -333,7 +333,7 @@ +--- privoxy~/doc/source/privoxy-man-page.sgml ++++ privoxy/doc/source/privoxy-man-page.sgml +@@ -367,7 +367,7 @@ # Set personal exceptions to the policies in default.action ####### @@ -18,33 +18,3 @@ diff -urNad privoxy~/doc/source/privoxy-man-page.sgml privoxy/doc/source/privoxy {-crunch-cookies -session-cookies-only} .redhat.com .sun.com -diff -urNad privoxy~/doc/source/user-manual.sgml privoxy/doc/source/user-manual.sgml ---- privoxy~/doc/source/user-manual.sgml 2004-01-31 10:49:48.000000000 +0100 -+++ privoxy/doc/source/user-manual.sgml 2006-02-11 18:34:24.000000000 +0100 -@@ -368,7 +368,7 @@ - - - -- In order not to loose your personal changes and adjustments when updating -+ In order not to lose your personal changes and adjustments when updating - to the latest default.action file we strongly - recommend that you use user.action for your - customization of Privoxy. See the - To determine which actions apply to a request, the URL of the request is -- compared to all patterns in each action file file. Every time it matches, the list of -+ compared to all patterns in each action file file. Every time it matches, the list of - applicable actions for the URL is incrementally updated, using the heading - of the section in which the pattern is located. If multiple matches for - the same URL set the same action differently, the last match wins. If not, -@@ -5251,7 +5251,7 @@ - blocks of HTML code disappear when a specific symbol is set. We use this - for many purposes, one of them being to include the beta warning in all - our user interface (CGI) pages when Privoxy -- in in an alpha or beta development stage: -+ is in an alpha or beta development stage: - - - diff --git a/debian/patches/09_no_identity.dpatch b/debian/patches/09_no_identity.dpatch index 95129c7f..b3458fdb 100644 --- a/debian/patches/09_no_identity.dpatch +++ b/debian/patches/09_no_identity.dpatch @@ -7,9 +7,9 @@ @DPATCH@ diff -urNad privoxy~/parsers.c privoxy/parsers.c ---- privoxy~/parsers.c 2006-02-05 16:23:12.000000000 +0100 -+++ privoxy/parsers.c 2006-02-05 16:25:49.000000000 +0100 -@@ -871,8 +871,7 @@ +--- privoxy~/parsers.c ++++ privoxy/parsers.c +@@ -1248,8 +1248,7 @@ * * Description : - Prohibit filtering (CT_TABOO) if transfer coding compresses * - Raise the CSP_FLAG_CHUNKED flag if coding is "chunked" @@ -19,7 +19,7 @@ diff -urNad privoxy~/parsers.c privoxy/parsers.c * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) -@@ -904,13 +903,13 @@ +@@ -1281,14 +1280,13 @@ /* * If the body was modified, it has been @@ -32,6 +32,7 @@ diff -urNad privoxy~/parsers.c privoxy/parsers.c { freez(*header); - *header = strdup("Transfer-Encoding: identity"); +- log_error(LOG_LEVEL_HEADER, "Set: %s", *header); - return (header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK; } } diff --git a/debian/patches/14_config.dpatch b/debian/patches/14_config.dpatch index b1b9695f..8390de2c 100644 --- a/debian/patches/14_config.dpatch +++ b/debian/patches/14_config.dpatch @@ -6,67 +6,67 @@ @DPATCH@ diff -urNad privoxy~/config privoxy/config ---- privoxy~/config 2006-02-11 20:29:59.000000000 +0100 -+++ privoxy/config 2006-02-11 20:30:28.000000000 +0100 +--- privoxy~/config ++++ privoxy/config @@ -1,4 +1,4 @@ --# Sample Configuration File for Privoxy v3.0.x +-# Sample Configuration File for Privoxy v3.0.4 +# Sample Configuration File for Privoxy - # - # Copyright (C) 2001-2004 Privoxy Developers http://privoxy.org - # -@@ -104,7 +104,7 @@ - # flat, except for confdir/templates, where the HTML templates - # for CGI output reside (e.g. Privoxy's 404 error page). - # --confdir . -+confdir /etc/privoxy - - # - # 1.2. logdir -@@ -131,7 +131,7 @@ - # - # No trailing "/", please - # --logdir . -+logdir /var/log/privoxy - - # - # 1.3. actionsfile -@@ -406,7 +406,7 @@ + # + # $Id: config,v 1.53 2006/09/07 02:02:56 hal9 Exp $ + # +@@ -123,7 +123,7 @@ # If set, this option should be the first option in the config # file, because it is used while the config file is being read. - # + # -#user-manual http://www.privoxy.org/user-manual/ +user-manual /usr/share/doc/privoxy/user-manual - # - # 2.2. trust-info-url -@@ -442,8 +442,8 @@ + # + # 1.2. trust-info-url +@@ -159,8 +159,8 @@ # don't end up locked out from the information on why they were # locked out in the first place! - # + # -trust-info-url http://www.example.com/why_we_block.html -trust-info-url http://www.example.com/what_we_allow.html +#trust-info-url http://www.example.com/why_we_block.html +#trust-info-url http://www.example.com/what_we_allow.html - # - # 2.3. admin-address -@@ -730,7 +730,7 @@ + # + # 1.3. admin-address +@@ -266,7 +266,7 @@ + # flat, except for confdir/templates, where the HTML templates + # for CGI output reside (e.g. Privoxy's 404 error page). + # +-confdir . ++confdir /etc/privoxy + + # + # 2.2. logdir +@@ -293,7 +293,7 @@ + # + # No trailing "/", please + # +-logdir . ++logdir /var/log/privoxy + + # + # 2.3. actionsfile +@@ -735,7 +735,7 @@ # Note that you must have compiled Privoxy with support for this # feature, otherwise this option has no effect. - # + # -enable-remote-toggle 1 +enable-remote-toggle 0 - # - # 4.4. enable-edit-actions -@@ -763,7 +763,7 @@ + # + # 4.4. enable-remote-http-toggle +@@ -803,7 +803,7 @@ # Note that you must have compiled Privoxy with support for this # feature, otherwise this option has no effect. - # + # -enable-edit-actions 1 +enable-edit-actions 0 - # - # 4.5. ACLs: permit-access and deny-access + # + # 4.6. ACLs: permit-access and deny-access diff --git a/debian/patches/15_mansection8.dpatch b/debian/patches/15_mansection8.dpatch index 8311c667..79e00817 100644 --- a/debian/patches/15_mansection8.dpatch +++ b/debian/patches/15_mansection8.dpatch @@ -5,21 +5,9 @@ ## DP: Move man page from man section 1 to man section 8. @DPATCH@ -diff -urNad privoxy~/doc/source/privoxy-man-page.sgml privoxy/doc/source/privoxy-man-page.sgml ---- privoxy~/doc/source/privoxy-man-page.sgml 2006-02-11 23:44:40.000000000 +0100 -+++ privoxy/doc/source/privoxy-man-page.sgml 2006-02-11 23:44:40.000000000 +0100 -@@ -57,7 +57,7 @@ - - - privoxy -- 1 -+ 8 - - Privoxy &p-version; - diff -urNad privoxy~/GNUmakefile.in privoxy/GNUmakefile.in ---- privoxy~/GNUmakefile.in 2006-02-11 23:44:25.000000000 +0100 -+++ privoxy/GNUmakefile.in 2006-02-11 23:44:40.000000000 +0100 +--- privoxy~/GNUmakefile.in ++++ privoxy/GNUmakefile.in @@ -177,7 +177,7 @@ `find doc/text/ -type f | grep -v "CVS" | grep -v "\.\#" | grep -v ".*~" | grep -v ".cvsignore" | grep -v "TAGS"` \ `find doc/webserver/ -name "*.html" | grep -v "\(webserver\|team\)\/index\.html"` \ @@ -29,7 +17,7 @@ diff -urNad privoxy~/GNUmakefile.in privoxy/GNUmakefile.in doc/pdf/*.pdf ############################################################################# -@@ -520,7 +520,7 @@ +@@ -521,7 +521,7 @@ $(RM) /etc/init.d/privoxy $(RM) /usr/sbin/privoxy $(RM) /usr/sbin/rcprivoxy @@ -38,7 +26,7 @@ diff -urNad privoxy~/GNUmakefile.in privoxy/GNUmakefile.in ############################################################################# # generic distribution -@@ -692,7 +692,7 @@ +@@ -697,7 +697,7 @@ $(RM) doc/man/* doc/webserver/man-page/*.html ifneq ($(MAN2HTML),false) $(ECHO) "Privoxy Man page

NAME

" > doc/webserver/man-page/privoxy-man-page.html @@ -47,7 +35,7 @@ diff -urNad privoxy~/GNUmakefile.in privoxy/GNUmakefile.in $(ECHO) "" >> doc/webserver/man-page/privoxy-man-page.html else $(MAKE) groff2html -@@ -704,14 +704,14 @@ +@@ -709,14 +709,14 @@ man: dok-release mkdir -p doc/source/temp && cd doc/source/temp && $(RM) * ;\ nsgmls ../privoxy-man-page.sgml | sgmlspl ../../../utils/docbook2man/docbook2man-spec.pl &&\ @@ -65,7 +53,7 @@ diff -urNad privoxy~/GNUmakefile.in privoxy/GNUmakefile.in $(PERL) -pi.bak -e 's/
//; s//man2html/' tmp.html $(PERL) -pi.bak -e 's/(<\/HEAD>)/<\/HEAD>/' tmp.html # Twice because my version of man2html is pulling in commas and periods in URLs. -@@ -726,7 +726,7 @@ +@@ -731,7 +731,7 @@ # Otherwise we get plain groff conversion. groff2html: @@ -74,8 +62,8 @@ diff -urNad privoxy~/GNUmakefile.in privoxy/GNUmakefile.in # readme page and INSTALL file -@@ -1122,8 +1122,8 @@ - $(INSTALL) $(INSTALL_T) $(DOK_WEB)/p_doc.css $$DOC;\ +@@ -1129,8 +1129,8 @@ + $(INSTALL) $(INSTALL_T) $(DOK_WEB)/p_doc.css $$DOC/user-manual;\ fi @# Not all platforms support gzipped man pages. - @$(ECHO) Installing man page to $(MAN_DEST)/privoxy.1 @@ -85,7 +73,7 @@ diff -urNad privoxy~/GNUmakefile.in privoxy/GNUmakefile.in @# Change the config file default directories according to the configured ones @$(ECHO) Rewriting config for this installation -@@ -1273,7 +1273,7 @@ +@@ -1286,7 +1286,7 @@ @# man page and docs @$(ECHO) Removing $(PROGRAM) docs @@ -94,3 +82,15 @@ diff -urNad privoxy~/GNUmakefile.in privoxy/GNUmakefile.in -$(RM) -r $(DOC_DEST) || $(RM) -r $(prefix)/doc/privoxy @# Log and jarfile and pidfile +diff -urNad privoxy~/doc/source/privoxy-man-page.sgml privoxy/doc/source/privoxy-man-page.sgml +--- privoxy~/doc/source/privoxy-man-page.sgml ++++ privoxy/doc/source/privoxy-man-page.sgml +@@ -57,7 +57,7 @@ + + + privoxy +- 1 ++ 8 + + Privoxy &p-version; + diff --git a/debian/patches/16_gzip.dpatch b/debian/patches/16_gzip.dpatch new file mode 100755 index 00000000..9d6cc722 --- /dev/null +++ b/debian/patches/16_gzip.dpatch @@ -0,0 +1,527 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 16_gzip.dpatch by Wil Mahan +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: Add deflate-filter support to privoxy, see sf bug id 895531 +## DP: Adapted from privoxy 3.1 to 3.0.x by Roland Rosenfeld. +## DP: This requires --enable-zlib as configure option in debian/rules +## DP: and a build dependeny on zlib1g-dev. + +@DPATCH@ +diff -urNad privoxy~/actionlist.h privoxy/actionlist.h +--- privoxy~/actionlist.h ++++ privoxy/actionlist.h +@@ -116,6 +116,7 @@ + DEFINE_ACTION_STRING ("deanimate-gifs", ACTION_DEANIMATE, ACTION_STRING_DEANIMATE) + DEFINE_CGI_PARAM_RADIO ("deanimate-gifs", ACTION_DEANIMATE, ACTION_STRING_DEANIMATE, "first", 0) + DEFINE_CGI_PARAM_RADIO ("deanimate-gifs", ACTION_DEANIMATE, ACTION_STRING_DEANIMATE, "last", 1) ++DEFINE_ACTION_BOOL ("decompress-from-server", ACTION_DECOMPRESS_IN) + DEFINE_ACTION_BOOL ("downgrade-http-version", ACTION_DOWNGRADE) + DEFINE_ACTION_BOOL ("fast-redirects", ACTION_FAST_REDIRECTS) + DEFINE_ACTION_MULTI ("filter", ACTION_MULTI_FILTER) +diff -urNad privoxy~/configure.in privoxy/configure.in +--- privoxy~/configure.in ++++ privoxy/configure.in +@@ -1234,6 +1234,20 @@ + libpcrs is available], + [ if test $enableval = "no"; then have_pcrs=no; fi ]) + ++AC_ARG_ENABLE(zlib, ++[ --enable-zlib Use the zlib library to allow compressing or ++ decompressing data on the fly.], ++[enableval2=$enableval], ++[enableval2=no]) ++if test $enableval2 = yes; then ++ AC_CHECK_LIB(z, zlibVersion, , [ ++ AC_MSG_ERROR([Unable to find a copy of zlib. The zlib library ++is necessary to enable compresion support. ]) ++ ]) ++ AC_DEFINE(FEATURE_ZLIB,1, ++ [ Define to 1 to use compression through the zlib library. ]) ++fi ++ + + # If we have libpcre and either we also have pcreposix or + # we don't need pcreposix, then link pcre dynamically; else +diff -urNad privoxy~/default.action.master privoxy/default.action.master +--- privoxy~/default.action.master ++++ privoxy/default.action.master +@@ -452,7 +452,7 @@ + -hide-user-agent \ + -kill-popups \ + -limit-connect \ +-+prevent-compression \ ++-prevent-compression \ + -send-vanilla-wafer \ + -send-wafer \ + +session-cookies-only \ +diff -urNad privoxy~/filters.c privoxy/filters.c +--- privoxy~/filters.c ++++ privoxy/filters.c +@@ -1325,6 +1325,38 @@ + return(NULL); + } + ++#ifdef FEATURE_ZLIB ++ /* If the body has a compressed transfer-encoding, uncompress ++ * it first, adjusting size and iob->eod. Note that ++ * decompression occurs after de-chunking. ++ */ ++ if (csp->content_type & CT_GZIP || csp->content_type & CT_DEFLATE) ++ { ++ /* Notice that we at least tried to decompress. */ ++ if (JB_ERR_OK != decompress_iob(csp)) ++ { ++ /* We failed to decompress the data; there's no point ++ * in continuing since we can't filter. This is ++ * slightly tricky because we need to remember not to ++ * modify the Content-Encoding header later; using ++ * CT_TABOO flag is a kludge for this purpose. ++ */ ++ csp->content_type |= CT_TABOO; ++ return(NULL); ++ } ++ log_error(LOG_LEVEL_RE_FILTER, "Decompressing successful"); ++ ++ /* Decompression gives us a completely new iob, so we ++ * need to update. ++ */ ++ size = csp->iob->eod - csp->iob->cur; ++ old = csp->iob->cur; ++ ++ csp->flags |= CSP_FLAG_MODIFIED; ++ } ++#endif ++ ++ + /* + * If the body has a "chunked" transfer-encoding, + * get rid of it first, adjusting size and iob->eod +diff -urNad privoxy~/jcc.c privoxy/jcc.c +--- privoxy~/jcc.c ++++ privoxy/jcc.c +@@ -659,6 +659,10 @@ + # include + # endif + ++#ifdef FEATURE_ZLIB ++#include ++#endif ++ + #endif + + #include "project.h" +@@ -1609,6 +1613,8 @@ + + if ((csp->content_type & CT_TEXT) && /* It's a text / * MIME-Type */ + !http->ssl && /* We talk plaintext */ ++ !(csp->content_type & CT_GZIP) && ++ !(csp->content_type & CT_DEFLATE) && + block_popups) /* Policy allows */ + { + block_popups_now = 1; +diff -urNad privoxy~/parsers.c privoxy/parsers.c +--- privoxy~/parsers.c ++++ privoxy/parsers.c +@@ -433,6 +433,10 @@ + #include + #include + ++#ifdef FEATURE_ZLIB ++#include ++#endif ++ + #if !defined(_WIN32) && !defined(__OS2__) + #include + #endif +@@ -632,6 +636,281 @@ + } + + ++#ifdef FEATURE_ZLIB ++/********************************************************************* ++ * ++ * Function : decompress_iob ++ * ++ * Description : Decompress buffered page, expanding the ++ * buffer as necessary. csp->iob->cur ++ * should point to the the beginning of the ++ * compressed data block. ++ * ++ * Parameters : ++ * 1 : csp = Current client state (buffers, headers, etc...) ++ * ++ * Returns : JB_ERR_OK on success, JB_ERR_MEMORY if out-of-memory ++ * limit reached, JB_ERR_COMPRESS if error decompressing ++ * buffer. ++ * ++ *********************************************************************/ ++jb_err decompress_iob(struct client_state *csp) ++{ ++ char *buf; /* new, uncompressed buffer */ ++ int bufsize = csp->iob->size; /* allocated size of the new buffer */ ++ /* Number of bytes at the beginning ++ * of the iob that we should NOT ++ * decompress. ++ */ ++ int skip_size = csp->iob->cur - csp->iob->buf; ++ int status; /* return status of the inflate() call */ ++ z_stream zstr; /* used by calls to zlib */ ++ ++ /* This is to protect the parsing of gzipped data, but it should(?) ++ * be valid for deflated data also. ++ */ ++ if (bufsize < 10) ++ { ++ log_error (LOG_LEVEL_ERROR, "Buffer too small decompressing iob"); ++ return JB_ERR_COMPRESS; ++ } ++ ++ if (csp->content_type & CT_GZIP) ++ { ++ /* Our task is slightly complicated by the facts that data ++ * compressed by gzip does not include a zlib header, and ++ * that there is no easily accessible interface in zlib to ++ * handle a gzip header. We strip off the gzip header by ++ * hand, and later inform zlib not to expect a header. ++ */ ++ ++ /* Strip off the gzip header. Please see RFC 1952 for more ++ * explanation of the appropriate fields. ++ */ ++ if ((*csp->iob->cur++ != (char)0x1f) ++ || (*csp->iob->cur++ != (char)0x8b) ++ || (*csp->iob->cur++ != Z_DEFLATED)) ++ { ++ log_error (LOG_LEVEL_ERROR, ++ "Invalid gzip header when decompressing"); ++ return JB_ERR_COMPRESS; ++ } ++ else { ++ int flags = *csp->iob->cur++; ++ if (flags & 0xe0) ++ { ++ /* The gzip header has reserved bits set; bail out. */ ++ log_error (LOG_LEVEL_ERROR, ++ "Invalid gzip header when decompressing"); ++ return JB_ERR_COMPRESS; ++ } ++ csp->iob->cur += 6; ++ ++ /* Skip extra fields if necessary. */ ++ if (flags & 0x04) ++ { ++ /* Skip a given number of bytes, specified as a 16-bit ++ * little-endian value. ++ */ ++ csp->iob->cur += *csp->iob->cur++ + (*csp->iob->cur++ << 8); ++ } ++ ++ /* Skip the filename if necessary. */ ++ if (flags & 0x08) ++ { ++ /* A null-terminated string follows. */ ++ while (*csp->iob->cur++); ++ } ++ ++ /* Skip the comment if necessary. */ ++ if (flags & 0x10) ++ { ++ while (*csp->iob->cur++); ++ } ++ ++ /* Skip the CRC if necessary. */ ++ if (flags & 0x02) ++ { ++ csp->iob->cur += 2; ++ } ++ } ++ } ++ else if (csp->content_type & CT_DEFLATE) ++ { ++ log_error (LOG_LEVEL_INFO, "Decompressing deflated iob: %d", *csp->iob->cur); ++ /* In theory (that is, according to RFC 1950), deflate-compressed ++ * data should begin with a two-byte zlib header and have an ++ * adler32 checksum at the end. It seems that in practice the ++ * only the raw compressed data is sent. Note that this means that ++ * we are not RFC 1950-compliant here, but the advantage is that ++ * this actually works. :) ++ * ++ * We add a dummy null byte to tell zlib where the data ends, ++ * and later inform it not to expect a header. ++ * ++ * Fortunately, add_to_iob() has thoughtfully null-terminated ++ * the buffer; we can just increment the end pointer to include ++ * the dummy byte. ++ */ ++ csp->iob->eod++; ++ } ++ else ++ { ++ log_error (LOG_LEVEL_ERROR, ++ "Unable to determine compression format for decompression"); ++ return JB_ERR_COMPRESS; ++ } ++ ++ /* Set up the fields required by zlib. */ ++ zstr.next_in = csp->iob->cur; ++ zstr.avail_in = csp->iob->eod - csp->iob->cur; ++ zstr.zalloc = Z_NULL; ++ zstr.zfree = Z_NULL; ++ zstr.opaque = Z_NULL; ++ ++ /* Passing -MAX_WBITS to inflateInit2 tells the library ++ * that there is no zlib header. ++ */ ++ if (inflateInit2 (&zstr, -MAX_WBITS) != Z_OK) ++ { ++ log_error (LOG_LEVEL_ERROR, ++ "Error initializing decompression"); ++ return JB_ERR_COMPRESS; ++ } ++ ++ /* Next, we allocate new storage for the inflated data. ++ * We don't modify the existing iob yet, so in case there ++ * is error in decompression we can recover gracefully. ++ */ ++ buf = zalloc (bufsize); ++ if (NULL == buf) ++ { ++ log_error (LOG_LEVEL_ERROR, ++ "Out of memory decompressing iob"); ++ return JB_ERR_MEMORY; ++ } ++ ++ assert(bufsize >= skip_size); ++ memcpy(buf, csp->iob->buf, skip_size); ++ zstr.avail_out = bufsize - skip_size; ++ zstr.next_out = buf + skip_size; ++ ++ /* Try to decompress the whole stream in one shot. */ ++ while (Z_BUF_ERROR == (status = inflate(&zstr, Z_FINISH))) ++ { ++ /* We need to allocate more memory for the output buffer. */ ++ ++ char *tmpbuf; /* used for realloc'ing the buffer */ ++ int oldbufsize = bufsize; /* keep track of the old bufsize */ ++ ++ /* If zlib wants more data then there's a problem, because ++ * the complete compressed file should have been buffered. ++ */ ++ if (0 == zstr.avail_in) ++ { ++ log_error(LOG_LEVEL_ERROR, ++ "Unexpected end of compressed iob"); ++ return JB_ERR_COMPRESS; ++ } ++ ++ /* If we tried the limit and still didn't have enough ++ * memory, just give up. ++ */ ++ if (bufsize == csp->config->buffer_limit) ++ { ++ log_error(LOG_LEVEL_ERROR, "Out of memory decompressing iob"); ++ return JB_ERR_MEMORY; ++ } ++ ++ /* Try doubling the buffer size each time. */ ++ bufsize *= 2; ++ ++ /* Don't exceed the buffer limit. */ ++ if (bufsize > csp->config->buffer_limit) ++ { ++ bufsize = csp->config->buffer_limit; ++ } ++ ++ /* Try to allocate the new buffer. */ ++ tmpbuf = realloc(buf, bufsize); ++ if (NULL == tmpbuf) ++ { ++ log_error(LOG_LEVEL_ERROR, "Out of memory decompressing iob"); ++ freez(buf); ++ return JB_ERR_MEMORY; ++ } ++ else ++ { ++ char *oldnext_out = zstr.next_out; ++ ++ /* Update the fields for inflate() to use the new ++ * buffer, which may be in a different location from ++ * the old one. ++ */ ++ zstr.avail_out += bufsize - oldbufsize; ++ zstr.next_out = tmpbuf + bufsize - zstr.avail_out; ++ ++ /* Compare with an uglier method of calculating these values ++ * that doesn't require the extra oldbufsize variable. ++ */ ++ assert(zstr.avail_out == ++ tmpbuf + bufsize - (char *)zstr.next_out); ++ assert((char *)zstr.next_out == ++ tmpbuf + ((char *)oldnext_out - buf)); ++ assert(zstr.avail_out > 0); ++ ++ buf = tmpbuf; ++ } ++ } ++ ++ inflateEnd(&zstr); ++ if (status != Z_STREAM_END) ++ { ++ /* We failed to decompress the stream. */ ++ log_error(LOG_LEVEL_ERROR, ++ "Error in decompressing to the buffer (iob): %s", ++ zstr.msg); ++ return JB_ERR_COMPRESS; ++ } ++ ++ /* Finally, we can actually update the iob, since the ++ * decompression was successful. First, free the old ++ * buffer. ++ */ ++ freez(csp->iob->buf); ++ ++ /* Now, update the iob to use the new buffer. */ ++ csp->iob->buf = buf; ++ csp->iob->cur = csp->iob->buf + skip_size; ++ csp->iob->eod = zstr.next_out; ++ csp->iob->size = bufsize; ++ ++ /* Make sure the new uncompressed iob obeys some minimal ++ * consistency conditions. ++ */ ++ if ((csp->iob->buf < csp->iob->cur) ++ && (csp->iob->cur <= csp->iob->eod) ++ && (csp->iob->eod <= csp->iob->buf + csp->iob->size)) ++ { ++ char t = csp->iob->cur[100]; ++ csp->iob->cur[100] = 0; ++ log_error(LOG_LEVEL_INFO, ++ "Sucessfully decompressed: %s", csp->iob->cur); ++ csp->iob->cur[100] = t; ++ return JB_ERR_OK; ++ } ++ else ++ { ++ /* It seems that zlib did something weird. */ ++ log_error(LOG_LEVEL_ERROR, ++ "Unexpected error decompressing the buffer (iob): %d==%d, %d>%d, %d<%d", csp->iob->cur, csp->iob->buf + skip_size, csp->iob->eod, csp->iob->buf, csp->iob->eod, csp->iob->buf + csp->iob->size); ++ return JB_ERR_COMPRESS; ++ } ++ ++} ++#endif /* defined(FEATURE_ZLIB) */ ++ ++ + /********************************************************************* + * + * Function : get_header +@@ -936,13 +1215,59 @@ + *********************************************************************/ + jb_err server_content_encoding(struct client_state *csp, char **header) + { ++#ifdef FEATURE_ZLIB ++ if (strstr(*header, "gzip")) ++ { ++ /* ++ * If the body was modified, we have tried to ++ * decompress it, so adjust the header if necessary. ++ */ ++ if ((csp->flags & CSP_FLAG_MODIFIED) /* we attempted to decompress */ ++ && !(csp->content_type & CT_TABOO)) /* decompression was successful */ ++ { ++ freez(*header); ++ *header = strdup("Content-Encoding: identity"); ++ return (header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK; ++ } ++ else ++ { ++ csp->content_type |= CT_GZIP; ++ } ++ } ++ else if (strstr(*header, "deflate")) ++ { ++ /* ++ * If the body was modified, we have tried to ++ * decompress it, so adjust the header if necessary. ++ */ ++ if ((csp->flags & CSP_FLAG_MODIFIED) /* we attempted to decompress */ ++ && !(csp->content_type & CT_TABOO)) /* decompression was successful */ ++ { ++ freez(*header); ++ *header = strdup("Content-Encoding: identity"); ++ return (header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK; ++ } ++ else ++ { ++ csp->content_type |= CT_DEFLATE; ++ } ++ } ++ else if (strstr(*header, "compress")) ++ { ++ /* We can't decompress this; therefore we can't filter ++ * it either. ++ */ ++ csp->content_type |= CT_TABOO; ++ } ++#else /* !defined(FEATURE_GZIP) */ + /* + * Turn off pcrs and gif filtering if body compressed + */ + if (strstr(*header, "gzip") || strstr(*header, "compress") || strstr(*header, "deflate")) + { +- csp->content_type = CT_TABOO; ++ csp->content_type |= CT_TABOO; + } ++#endif /* !defined(FEATURE_GZIP) */ + + return JB_ERR_OK; + +diff -urNad privoxy~/parsers.h privoxy/parsers.h +--- privoxy~/parsers.h ++++ privoxy/parsers.h +@@ -194,6 +194,7 @@ + + extern int flush_socket(jb_socket fd, struct client_state *csp); + extern jb_err add_to_iob(struct client_state *csp, char *buf, int n); ++extern jb_err decompress_iob(struct client_state *csp); + extern char *get_header(struct client_state *csp); + extern char *get_header_value(const struct list *header_list, const char *header_name); + extern char *sed(const struct parsers pats[], const add_header_func_ptr more_headers[], struct client_state *csp); +diff -urNad privoxy~/project.h privoxy/project.h +--- privoxy~/project.h ++++ privoxy/project.h +@@ -563,7 +563,7 @@ + #define JB_ERR_PARSE 4 /**< Error parsing file */ + #define JB_ERR_MODIFIED 5 /**< File has been modified outside of the + CGI actions editor. */ +- ++#define JB_ERR_COMPRESS 6 /**< Error on decompression */ + + /** + * This macro is used to free a pointer that may be NULL. +@@ -818,6 +818,15 @@ + #define CT_TABOO 4 /**< csp->content_type bitmask: + DO NOT filter, irrespective of other flags. */ + ++/* Although these are not, strictly speaking, content types ++ * (they are content encodings), it is simple to handle ++ * them as such. ++ */ ++#define CT_GZIP 8 /**< csp->content_type bitmask: ++ gzip-compressed data. */ ++#define CT_DEFLATE 16 /**< csp->content_type bitmask: ++ zlib-compressed data. */ ++ + /** + * The mask which includes all actions. + */ +@@ -862,6 +871,8 @@ + #define ACTION_VANILLA_WAFER 0x00008000UL + /** Action bitmap: Limit CONNECT requests to safe ports. */ + #define ACTION_LIMIT_CONNECT 0x00010000UL ++/** Action bitmap: Uncompress incoming text for filtering. */ ++#define ACTION_DECOMPRESS_IN 0x00020000UL + + /** Action string index: How to deanimate GIFs */ + #define ACTION_STRING_DEANIMATE 0 diff --git a/debian/patches/17_502_no_such_domain.dpatch b/debian/patches/17_502_no_such_domain.dpatch new file mode 100755 index 00000000..6eafee79 --- /dev/null +++ b/debian/patches/17_502_no_such_domain.dpatch @@ -0,0 +1,30 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 17_502_no_such_domain.dpatch by Roland Rosenfeld +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: Changes the 404 HTTP status code of the "No such Domain" template +## DP: to 502 Bad Gateway, which seems to be more correct according to +## DP: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html + +@DPATCH@ +diff -urNad privoxy~/templates/no-such-domain privoxy/templates/no-such-domain +--- privoxy~/templates/no-such-domain ++++ privoxy/templates/no-such-domain +@@ -79,7 +79,7 @@ + + + +- 404 - No such Domain (Privoxy@@my-hostname@) ++ 502 - Bad Gateway (Privoxy@@my-hostname@) + + + +@@ -92,7 +92,7 @@ + + + +
+- 404 ++ 502 + + diff --git a/debian/patches/18_dns_retry.dpatch b/debian/patches/18_dns_retry.dpatch new file mode 100755 index 00000000..cff2cbbe --- /dev/null +++ b/debian/patches/18_dns_retry.dpatch @@ -0,0 +1,58 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 18_dns_retry.dpatch by Fabian Keil +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: Retries DNS queries 10 times before giving up. +## DP: Extracted from http://www.fabiankeil.de/sourcecode/privoxy/ + +@DPATCH@ +diff -urNad privoxy~/jbsockets.c privoxy/jbsockets.c +--- privoxy~/jbsockets.c ++++ privoxy/jbsockets.c +@@ -780,6 +780,7 @@ + { + struct sockaddr_in inaddr; + struct hostent *hostp; ++ unsigned int dns_retries = 0; + #if defined(HAVE_GETHOSTBYNAME_R_6_ARGS) || defined(HAVE_GETHOSTBYNAME_R_5_ARGS) || defined(HAVE_GETHOSTBYNAME_R_3_ARGS) + struct hostent result; + #if defined(HAVE_GETHOSTBYNAME_R_6_ARGS) || defined(HAVE_GETHOSTBYNAME_R_5_ARGS) +@@ -800,8 +801,13 @@ + if ((inaddr.sin_addr.s_addr = inet_addr(host)) == -1) + { + #if defined(HAVE_GETHOSTBYNAME_R_6_ARGS) +- gethostbyname_r(host, &result, hbuf, +- HOSTENT_BUFFER_SIZE, &hostp, &thd_err); ++ while ( gethostbyname_r(host, &result, hbuf, ++ HOSTENT_BUFFER_SIZE, &hostp, &thd_err) ++ && (thd_err == TRY_AGAIN) && (dns_retries++ < 10) ) ++ { ++ log_error(LOG_LEVEL_ERROR, "Timeout #%u while trying to resolve %s. Trying again.", ++ dns_retries, host); ++ } + #elif defined(HAVE_GETHOSTBYNAME_R_5_ARGS) + hostp = gethostbyname_r(host, &result, hbuf, + HOSTENT_BUFFER_SIZE, &thd_err); +@@ -816,10 +822,20 @@ + } + #elif OSX_DARWIN + pthread_mutex_lock(&gethostbyname_mutex); +- hostp = gethostbyname(host); ++ while ( NULL == (hostp = gethostbyname(host)) ++ && (h_errno == TRY_AGAIN) && (dns_retries++ < 10) ) ++ { ++ log_error(LOG_LEVEL_ERROR, "Timeout #%u while trying to resolve %s. Trying again.", ++ dns_retries, host); ++ } + pthread_mutex_unlock(&gethostbyname_mutex); + #else +- hostp = gethostbyname(host); ++ while ( NULL == (hostp = gethostbyname(host)) ++ && (h_errno == TRY_AGAIN) && (dns_retries++ < 10) ) ++ { ++ log_error(LOG_LEVEL_ERROR, "%u. timeout while trying to resolve %s. Trying again.", ++ dns_retries, host); ++ } + #endif /* def HAVE_GETHOSTBYNAME_R_(6|5|3)_ARGS */ + /* + * On Mac OSX, if a domain exists but doesn't have a type A diff --git a/debian/patches/19_manpage_fixup.dpatch b/debian/patches/19_manpage_fixup.dpatch new file mode 100755 index 00000000..bdb3c118 --- /dev/null +++ b/debian/patches/19_manpage_fixup.dpatch @@ -0,0 +1,30 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 19_manpage_fixup.dpatch by Roland Rosenfeld +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: Convert Latin-1 char á to groff eqivalent in man page. +## DP: Quote minus signs to differenciate them from hyphens. + +@DPATCH@ +diff -urNad privoxy~/GNUmakefile.in privoxy/GNUmakefile.in +--- privoxy~/GNUmakefile.in ++++ privoxy/GNUmakefile.in +@@ -710,6 +710,10 @@ + mkdir -p doc/source/temp && cd doc/source/temp && $(RM) * ;\ + nsgmls ../privoxy-man-page.sgml | sgmlspl ../../../utils/docbook2man/docbook2man-spec.pl &&\ + perl -pi.bak -e 's/ //; s/\[ /\[/g' privoxy.8 ;\ ++ perl -pi.bak -e "s/\[ /\[/g;s/á/\\\\['a]/g" privoxy.8; \ ++ perl -pi.bak -e 's/([ {])-([a-z])/$$1\\-$$2/g' privoxy.8; \ ++ perl -pi.bak -e 's/ --([a-z])/ \\-\\-$$1/g' privoxy.8; \ ++ perl -pi.bak -e 's/\\fB--/\\fB\\-\\-/g' privoxy.8; \ + $(DB) ../privoxy-man-page.sgml && $(MV) -f privoxy.8 ../../../privoxy.8 + + # For those with man2html ala RH7s. +@@ -722,6 +726,7 @@ + # Twice because my version of man2html is pulling in commas and periods in URLs. + $(PERL) -pi.bak -e 's/()/$$1$$2/g' tmp.html + $(PERL) -pi.bak -e 's,\.">,">,g' tmp.html ++ $(PERL) -pi.bak -e "s/\['a\]/\á/g" tmp.html + # Get rid of spurious  from conversion. (How to do this with perl?) + $(SED) -e 's///g' tmp.html > doc/webserver/man-page/privoxy-man-page.html && $(RM) tmp.* + else diff --git a/debian/patches/20_makefile_fixup.dpatch b/debian/patches/20_makefile_fixup.dpatch new file mode 100755 index 00000000..2717bb9c --- /dev/null +++ b/debian/patches/20_makefile_fixup.dpatch @@ -0,0 +1,23 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 20_makefile_fixup.dpatch by Roland Rosenfeld +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: Fix syntax error in GNUmakefile.in + +@DPATCH@ +diff -urNad privoxy~/GNUmakefile.in privoxy/GNUmakefile.in +--- privoxy~/GNUmakefile.in ++++ privoxy/GNUmakefile.in +@@ -678,9 +678,9 @@ + $(RM) -r doc/source/user-manual/ + mkdir -p doc/text doc/source/user-manual + cd doc/source/user-manual && $(DB) -iuser-man ../user-manual.sgml && cd .. && cp user-manual/*.html ../webserver/user-manual/ +- @#FIXME: temp fix so same stylesheet gets in more than one place so it works \ +- @# for all doc set-ups, including the 'user manual' config option in local \ +- @#system where it MUST be in same directory as html. ++ #FIXME: temp fix so same stylesheet gets in more than one place so it works \ ++ # for all doc set-ups, including the 'user manual' config option in local \ ++ #system where it MUST be in same directory as html. + $(PERL) -pi.bak -e 's/<\/head/\n\n<\/head/i' doc/webserver/user-manual/*html + cd doc/source && $(DB) -iuser-man -V nochunks user-manual.sgml > tmp.html && $(WDUMP) tmp.html > ../text/user-manual.txt && $(RM) -r tmp.html user-manual + diff --git a/debian/patches/21_version_3.0.4.dpatch b/debian/patches/21_version_3.0.4.dpatch new file mode 100755 index 00000000..821f5ef3 --- /dev/null +++ b/debian/patches/21_version_3.0.4.dpatch @@ -0,0 +1,22 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 21_version_3.0.4.dpatch by Roland Rosenfeld +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: Bump version to 3.0.4 otherwise privoxy complains in the version check. + +@DPATCH@ +diff -urNad privoxy~/configure.in privoxy/configure.in +--- privoxy~/configure.in ++++ privoxy/configure.in +@@ -488,9 +488,9 @@ + dnl Application version number + dnl ================================================================= + +-VERSION_MAJOR=0 ++VERSION_MAJOR=3 + VERSION_MINOR=0 +-VERSION_POINT=0 ++VERSION_POINT=4 + CODE_STATUS="UNRELEASED" + + dnl CODE_STATUS can be "alpha", "beta", or "stable", and will be