1 #! /bin/sh /usr/share/dpatch/dpatch-run
2 ## 03_ipv6.dpatch by Lionel Elie Mamane <lionel@mamane.lu>
4 ## All lines beginning with `## DP:' are a description of the patch.
5 ## DP: privoxy_CVS_20030523_ipv6_5.patch.bz2 from
6 ## DP: ftp://ftp.deepspace6.net/pub/ds6/sources/privoxy/privoxy_CVS_20030523_ipv6_5.patch.bz2
7 ## DP: adapted to the 3.0 branch of privoxy by Roland Rosenfeld
8 ## DP: adapted to 3.0.4 by higuita, but i'm no programmer, so i hope i
9 ## DP: didnt broke anything :)
12 diff -urNad privoxy~/GNUmakefile.in privoxy/GNUmakefile.in
13 --- privoxy~/GNUmakefile.in
14 +++ privoxy/GNUmakefile.in
16 C_SRC = actions.c cgi.c cgiedit.c cgisimple.c deanimate.c encode.c \
17 errlog.c filters.c gateway.c jbsockets.c jcc.c killpopup.c \
18 list.c loadcfg.c loaders.c miscutil.c parsers.c ssplit.c \
20 + urlmatch.c addrlist.c jb_socket_set.c
22 C_OBJS = $(C_SRC:.c=.@OBJEXT@)
23 C_HDRS = $(C_SRC:.c=.h) project.h actionlist.h
25 SPECIAL_CFLAGS = @SPECIAL_CFLAGS@
29 +OTHER_CFLAGS = -DINET6
31 CFLAGS = @CFLAGS@ @CPPFLAGS@ $(OTHER_CFLAGS) $(SPECIAL_CFLAGS) -Wall \
32 @STATIC_PCRE_ONLY@ -Ipcre
33 diff -urNad privoxy~/addrlist.c privoxy/addrlist.c
34 --- privoxy~/addrlist.c
35 +++ privoxy/addrlist.c
37 +const char addrlist_rcs[] = "$Id: $";
38 +/*********************************************************************
42 + * Purpose : Declares functions to handle lists of network addresses.
43 + * Functions declared include:
44 + * `destroy_addr_list', head_addr_list and `tail_addr_list'
46 + * Copyright : Written by and Copyright (C) 2002 Lionel Elie Mamane
47 + * <lionel@mamane.lu>
49 + * This program is free software; you can redistribute it
50 + * and/or modify it under the terms of the GNU General
51 + * Public License as published by the Free Software
52 + * Foundation; either version 2 of the License, or (at
53 + * your option) any later version.
55 + * This program is distributed in the hope that it will
56 + * be useful, but WITHOUT ANY WARRANTY; without even the
57 + * implied warranty of MERCHANTABILITY or FITNESS FOR A
58 + * PARTICULAR PURPOSE. See the GNU General Public
59 + * License for more details.
61 + * The GNU General Public License should be included with
62 + * this file. If not, you can view it at
63 + * http://www.gnu.org/copyleft/gpl.html
64 + * or write to the Free Software Foundation, Inc., 59
65 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
68 + * $Log: addrlist.c,v $
70 + *********************************************************************/
72 +#include "addrlist.h"
73 +#include <sys/types.h>
74 +#include <sys/socket.h>
78 +/*********************************************************************
80 + * Function : acceptable
82 + * Description : Test wheter an address is acceptable for our use
83 + * Currently, this means either an IPv4 or an IPv6 address
86 + * 0 : addr = the address to test
88 + * Returns : 0 = false / no
89 + * anything else = true / yes
91 + *********************************************************************/
92 +static int acceptable (struct sockaddr_storage *addr)
94 + switch(addr->ss_family)
106 +/*********************************************************************
110 + * Description : Get the first acceptable address in head position
111 + * Assumes there is one
114 + * 0 : l = the list to skim
116 + * Returns : the skimmed list
118 + *********************************************************************/
119 +static addr_list *skim (addr_list *l)
121 + if (acceptable((struct sockaddr_storage*)l->ai_addr))
123 + return skim(l->ai_next);
126 +/*********************************************************************
128 + * Function : tail_addr_list
130 + * Description : Get the tail of an address list
133 + * 0 : l = the list to get the tail of
135 + * Returns : the tail of the list
136 + * If the list has no tail (i.e. is nil), unspecified
139 + *********************************************************************/
140 +addr_list *tail_addr_list(addr_list *l)
142 + return skim(l)->ai_next;
145 +/*********************************************************************
147 + * Function : head_addr_list
149 + * Description : Get the head of an address list
152 + * 0 : l = the list to get the head of
154 + * Returns : the head of the list
155 + * If the list has no head (i.e. is nil), unspecified
158 + *********************************************************************/
159 +struct sockaddr_storage *head_addr_list(addr_list *l)
161 + return (struct sockaddr_storage *)skim(l)->ai_addr;
164 +/*********************************************************************
166 + * Function : cpy_head_addr_list
168 + * Description : Copy the head of an address list to the given destination
171 + * 0 : l = the list to get the head of
172 + * 1 : r = where to put the result
174 + * Returns : Nothing
175 + * If the list has no head (i.e. is nil), unspecified
178 + *********************************************************************/
179 +void cpy_head_addr_list(addr_list *l, struct sockaddr_storage *r, size_t *addrlen)
181 + addr_list *sl = skim(l);
182 + memcpy(r, sl->ai_addr, sl->ai_addrlen);
183 + *addrlen = sl->ai_addrlen;
186 +/*********************************************************************
188 + * Function : destroy_addr_list
190 + * Description : Unallocate memory allocated to an address list
193 + * 0 : l = the list to unallocate
195 + * Returns : nothing
197 + *********************************************************************/
198 +void destroy_addr_list(addr_list *l)
203 +/*********************************************************************
205 + * Function : is_nil_addr_list
207 + * Description : Test wheter a list is nil (empty)
210 + * 0 : l = the list to test
212 + * Returns : 0 = false if list has a head,
213 + * anything else = true if list is nil
215 + *********************************************************************/
216 +int is_nil_addr_list(addr_list *l)
218 + /* We are searching for a witness of non-nilness (modulo acceptability)
219 + * If none is found, the list is nil
224 + if (acceptable(head_addr_list(l)))
225 + /* Witness found */
227 + return is_nil_addr_list(l->ai_next);
235 diff -urNad privoxy~/addrlist.h privoxy/addrlist.h
236 --- privoxy~/addrlist.h
237 +++ privoxy/addrlist.h
239 +#ifndef ADDR_LIST_H_INCLUDED
240 +#define ADDR_LIST_H_INCLUDED
241 +#define ADDR_LIST_H_VERSION "$Id: $"
242 +/*********************************************************************
244 + * File : $Source: $
246 + * Purpose : Declares functions to handle lists of network addresses.
247 + * Functions declared include:
248 + * `destroy_addr_list', head_addr_list and `tail_addr_list'
250 + * Copyright : Written by and Copyright (C) 2002 Lionel Elie Mamane
251 + * <lionel@mamane.lu>
253 + * This program is free software; you can redistribute it
254 + * and/or modify it under the terms of the GNU General
255 + * Public License as published by the Free Software
256 + * Foundation; either version 2 of the License, or (at
257 + * your option) any later version.
259 + * This program is distributed in the hope that it will
260 + * be useful, but WITHOUT ANY WARRANTY; without even the
261 + * implied warranty of MERCHANTABILITY or FITNESS FOR A
262 + * PARTICULAR PURPOSE. See the GNU General Public
263 + * License for more details.
265 + * The GNU General Public License should be included with
266 + * this file. If not, you can view it at
267 + * http://www.gnu.org/copyleft/gpl.html
268 + * or write to the Free Software Foundation, Inc., 59
269 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
272 + * $Log: addrlist.h,v $
274 + *********************************************************************/
276 +#include <sys/socket.h>
278 +typedef struct addrinfo addr_list;
280 +addr_list *tail_addr_list(addr_list *l);
281 +struct sockaddr_storage *head_addr_list(addr_list *l);
282 +void cpy_head_addr_list(addr_list *l, struct sockaddr_storage *r, size_t *addrlen);
283 +void destroy_addr_list(addr_list *l);
284 +int is_nil_addr_list(addr_list *l);
286 +#define freez_addr_list(X) { if(X) { destroy_addr_list(X); X = NULL ; } }
288 +#endif /* ndef LIST_H_INCLUDED */
295 diff -urNad privoxy~/cgi.c privoxy/cgi.c
299 * Copyright : Written by and Copyright (C) 2001 the SourceForge
300 * Privoxy team. http://www.privoxy.org/
302 + * Modified by Lionel Elie Mamane <lionel@mamane.lu>
303 + * for IPv6 support on 8 December 2002, 24 January 2003.
305 * Based on the Internet Junkbuster originally written
306 * by and Copyright (C) 1997 Anonymous Coders and
307 * Junkbusters Corporation. http://www.junkbusters.com
308 @@ -2250,7 +2253,6 @@
309 *********************************************************************/
310 struct map *default_exports(const struct client_state *csp, const char *caller)
314 struct map * exports;
315 int local_help_exists = 0;
316 @@ -2286,8 +2288,7 @@
317 if (!err) err = map_block_killer(exports, "can-toggle");
320 - snprintf(buf, 20, "%d", csp->config->hport);
321 - if (!err) err = map(exports, "my-port", 1, buf, 1);
322 + if (!err) err = map(exports, "my-port", 1, csp->my_port_str, 1);
324 if(!strcmp(CODE_STATUS, "stable"))
326 diff -urNad privoxy~/errlog.c privoxy/errlog.c
327 --- privoxy~/errlog.c
332 /* Non-standard: Print error code from errno */
334 + * This is not only not standard, but clashes
335 + * with the E modifier on the GNU (and possibly
336 + * other systems): It means double (floating point)
337 + * number in exponential notation, with capital E
338 + * for mantiss / exponenent separator
341 ival = WSAGetLastError();
342 sval = w32_socket_strerr(ival, tempbuf);
343 diff -urNad privoxy~/filters.c privoxy/filters.c
344 --- privoxy~/filters.c
345 +++ privoxy/filters.c
347 * Copyright : Written by and Copyright (C) 2001, 2004 the SourceForge
348 * Privoxy team. http://www.privoxy.org/
350 + * Modified by Lionel Elie Mamane <lionel@mamane.lu>
351 + * for IPv6 support on 8 December 2002, 24 January 2003.
353 * Based on the Internet Junkbuster originally written
354 * by and Copyright (C) 1997 Anonymous Coders and
355 * Junkbusters Corporation. http://www.junkbusters.com
366 @@ -502,17 +508,119 @@
368 const char filters_h_rcs[] = FILTERS_H_VERSION;
370 -/* Fix a problem with Solaris. There should be no effect on other
372 - * Solaris's isspace() is a macro which uses it's argument directly
373 - * as an array index. Therefore we need to make sure that high-bit
374 - * characters generate +ve values, and ideally we also want to make
375 - * the argument match the declared parameter type of "int".
377 -#define ijb_isdigit(__X) isdigit((int)(unsigned char)(__X))
379 +/*********************************************************************
381 + * Function : addr_equal_under_mask
383 + * Description : Are these addresses equal modulo this mask?
384 + * Assumes the second argument is already in
388 + * 0 : addr1 = First address to compare
389 + * 1 : addr2 = Second address to compare
390 + * MUST be in mask-normal form
391 + * 2 : mask = for IPv4 addresses, a bitmask
392 + * for IPv6 addresses, a prefixlen in bits
394 + * Returns : 0 = FALSE (not equal) and non-zero = TRUE (equal)
396 + *********************************************************************/
399 +addr_equal_under_mask(struct sockaddr_storage *addr1, struct sockaddr_storage *addr2, unsigned long mask)
404 + /* only identical families can be compared */
405 + /* TODO: Should we code the special case of "IPv4 addresses as IPv6 addresses"? */
406 + if (addr1->ss_family != addr2-> ss_family)
408 + /*fprintf(stderr, "equal_under_mask: diff sa_family: %d %d\n",
409 + sa1->sa_family, sa2-> sa_family); */
413 + switch (addr1->ss_family)
417 + /* IPv4 - mask is a bitmask */
418 + struct sockaddr_in *sin1 = (struct sockaddr_in *)addr1;
419 + struct sockaddr_in *sin2 = (struct sockaddr_in *)addr2;
421 + /*fprintf(stderr, "AF_INET: %08x %08x %08x\n",
422 + sin1->sin_addr.s_addr,
423 + sin2->sin_addr.s_addr,
425 + return (sin1->sin_addr.s_addr & mask) == sin2->sin_addr.s_addr;
431 + /* IPv6 - mask is a prefixlength in bits. */
432 + struct sockaddr_in6 *sin1 = (struct sockaddr_in6 *)addr1;
433 + struct sockaddr_in6 *sin2 = (struct sockaddr_in6 *)addr2;
436 + const int maskbytes = mask / 8;
437 + static char m[] = { 0x00, 0x80, 0xC0, 0xE0,
438 + 0xF0, 0xF8, 0xFC, 0xFE };
441 +/* fprintf(stderr, "PF_INET6: "); */
442 +/* for (i = 0; i < 16; i++) { */
443 +/* fprintf(stderr, "%02x ", sin1->sin6_addr.s6_addr[i]); */
445 +/* fprintf(stderr, " "); */
446 +/* for (i = 0; i < 16; i++) { */
447 +/* fprintf(stderr, "%02x ", sin2->sin6_addr.s6_addr[i]); */
449 +/* fprintf(stderr, "mask %d scopeids %x %x\n", mask, sin1->sin6_scope_id, sin2->sin6_scope_id); */
451 + /* should we compare scope ids and such too? */
453 + * LEM: I see no reason for this comparison
454 + * Quite the contrary: A client coming to us with
455 + * a small-scope address should be able to a bigger-scope
458 +/* if (sin1->sin6_scope_id != sin2->sin6_scope_id) */
463 + log_error(LOG_LEVEL_ERROR, "%s%d", "Tried to compare IPv6 addresses with invalid prefixlen: ", mask);
467 + a1 = sin1->sin6_addr.s6_addr;
468 + a2 = sin2->sin6_addr.s6_addr;
470 + if (memcmp(a1, a2, maskbytes) != 0)
474 + /* This special case is necessary for when mask==128
475 + else, we would go over the array size in a1/a2
482 + return (a1[maskbytes] & bitmask) == a2[maskbytes];
492 /*********************************************************************
494 * Function : block_acl
496 /* search the list */
499 - if ((csp->ip_addr_long & acl->src->mask) == acl->src->addr)
500 + if (addr_equal_under_mask(&csp->ip_addr_addr, &acl->src->addr, acl->src->mask))
508 - else if ( ((dst->addr & acl->dst->mask) == acl->dst->addr)
509 - && ((dst->port == acl->dst->port) || (acl->dst->port == 0)))
510 + else if ( addr_equal_under_mask(&dst->addr, &acl->dst->addr, acl->dst->mask)
511 + && ((dst->port == acl->dst->port) || (acl->dst->port == 0)))
513 if (acl->action == ACL_PERMIT)
515 @@ -572,81 +680,249 @@
520 /*********************************************************************
522 - * Function : acl_addr
523 + * Function : fill_acl_addr_mask
525 - * Description : Called from `load_config' to parse an ACL address.
526 + * Description : Fill in the mask-related members of a
527 + * struct access_control_addr
530 - * 1 : aspec = String specifying ACL address.
531 - * 2 : aca = struct access_control_addr to fill in.
532 + * 0 : aca = struct access_control_addr to fill in.
533 + * 1 : masklength = mask length.
535 - * Returns : 0 => Ok, everything else is an error.
536 + * Returns : nothing
538 *********************************************************************/
539 -int acl_addr(char *aspec, struct access_control_addr *aca)
540 +void fill_acl_addr_mask(struct access_control_addr *aca, int masklength)
542 - int i, masklength, port;
548 + pf = aca->addr.ss_family;
550 - if ((p = strchr(aspec, '/')) != NULL)
555 - if (ijb_isdigit(*p) == 0)
557 + /* build the netmask */
558 + if (masklength == -1)
561 + for(pf=1; pf <= masklength ; ++pf)
564 + aca->mask |= (1 << (32 - pf));
566 - masklength = atoi(p);
568 + aca->mask = htonl(aca->mask);
570 + /* now mask off the host portion of the ip address
571 + * (i.e. save on the network portion of the address).
573 + ((struct sockaddr_in*) &aca->addr)->sin_addr.s_addr &= aca->mask;
574 + aca->port = ((struct sockaddr_in*) &aca->addr)->sin_port;
579 + static char m[] = { 0x00, 0x80, 0xC0, 0xE0,
580 + 0xF0, 0xF8, 0xFC, 0xFE };
582 + struct sockaddr_in6 *sa6 = (struct sockaddr_in6*)&aca->addr;
584 - if ((masklength < 0) || (masklength > 32))
587 + aca->mask = (masklength == -1) ? masklength : 128 ;
588 + /* now mask off the host portion of the ip address
589 + * (i.e. save on the network portion of the address).
594 + sa6->sin6_addr.s6_addr[i] &= m[aca->mask % 8];
595 + /* The following loop is not strictly necessary,
596 + because of the way addr_equal_under_mask is
597 + written. Better safe than sorry, though:
598 + New code might make the full mask-normal
601 + for(++i; i < 16 ; ++i)
602 + sa6->sin6_addr.s6_addr[i] = 0;
604 + aca -> port = sa6->sin6_port;
609 + /* FATAL because access_control_addr's are created only with adresses
610 + deemed 'acceptable' by the addr_list stuff, thus currently IPv4 and
613 + log_error(LOG_LEVEL_FATAL,"%s%d","Unknown address family in ACL address: ",pf);
617 - if ((p = strchr(aspec, ':')) != NULL)
620 +/*********************************************************************
622 + * Function : acl_addrs
624 + * Description : Parse an ACL address (adress + mask prefix)
625 + * Resolve the parsed address
626 + * Describe errors in *proxy_args.
629 + * 0 : aspec = the string containing the ACL address/mask
630 + * 1 : masklength = pointer used to return the mask
631 + * 2 : proxy_args = Pointer to string to append description of errors to.
632 + * 3 : type = type of ACL adress (source / destination).
633 + * Used for error reporting.
635 + * Returns : the list of adresses the ACL address resolves to
637 + *********************************************************************/
638 +static addr_list *acl_addrs(char *aspec, int *masklength, char**proxy_args, const char *type)
644 - if (ijb_isdigit(*p) == 0)
650 + if (parse_pf_ip_netmask(aspec, &host, &port, &pf, masklength) != 0)
652 + log_error(LOG_LEVEL_ERROR, "Invalid %s IP for (deny|permit)-access "
653 + "directive in configuration file: \"%s\"", type, aspec);
654 + string_append(proxy_args,"<br>\nWARNING: Invalid ");
655 + string_append(proxy_args, type);
656 + string_append(proxy_args," IP for (deny|permit)-access directive"
657 + " in configuration file: \"");
658 + string_append(proxy_args, aspec);
659 + string_append(proxy_args,"\"<br><br>\n");
664 + return resolve_hostname_to_ip(host, port, pf);
667 - aca->addr = ntohl(resolve_hostname_to_ip(aspec));
668 +/*********************************************************************
670 + * Function : add_one_to_acl_list
672 + * Description : Add one entry to an access_control_list.
675 + * 0 : l = the list to add to
676 + * 1 : action = ACL_DENY or ACL_PERMIT
677 + * 2 : src_addrs = the head of this list will be used as source
678 + * in the ACL entry.
679 + * 3 : dst_addrs = the head of this list will be used as destination
680 + * in the ACL entry.
682 + * 4 : src_masklength = mask length for the source
683 + * 5 : src_masklength = mask length for the destination
685 + * Returns : the new list
687 + *********************************************************************/
688 +struct access_control_list *add_one_to_acl_list(struct access_control_list *l, short action,
689 + addr_list *src_addrs, addr_list *dst_addrs,
690 + int src_masklength, int dst_masklength)
692 + struct access_control_list *cur_acl;
693 + /* allocate a new node */
694 + cur_acl = (struct access_control_list *) zalloc(sizeof(*cur_acl));
696 - if (aca->addr == INADDR_NONE)
697 + if (cur_acl == NULL)
700 + log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
701 + /* Never get here - LOG_LEVEL_FATAL causes program exit */
705 - /* build the netmask */
707 - for (i=1; i <= masklength ; i++)
708 + cur_acl->action = action;
710 + cpy_head_addr_list(src_addrs, &cur_acl->src->addr, &cur_acl->src->addrlen);
711 + fill_acl_addr_mask(cur_acl->src, src_masklength);
712 + if (dst_addrs != NULL)
714 - aca->mask |= (1 << (32 - i));
715 + cpy_head_addr_list(dst_addrs, &cur_acl->dst->addr, &cur_acl->dst->addrlen);
716 + fill_acl_addr_mask(cur_acl->src, src_masklength);
719 - /* now mask off the host portion of the ip address
720 - * (i.e. save on the network portion of the address).
722 + * Add it to the list. Note we reverse the list to get the
723 + * behaviour the user expects. With both the ACL and
724 + * actions file, the last match wins. However, the internal
725 + * implementations are different: The actions file is stored
726 + * in the same order as the file, and scanned completely.
727 + * With the ACL, we reverse the order as we load it, then
728 + * when we scan it we stop as soon as we get a match.
730 - aca->addr = aca->addr & aca->mask;
737 +/*********************************************************************
739 + * Function : add_to_acl_list
741 + * Description : Add entries to an access_control_list.
742 + * Describe errors in *proxy_args.
745 + * 0 : l = the list to add to
746 + * 1 : action = ACL_DENY or ACL_PERMIT
747 + * 2 : src_spec = String giving the source of the acl entry
748 + * 3 : dst_spec = String giving the destination of the acl entry,
750 + * 4 : proxy_args = Pointer to string to append description of errors to.
752 + * Returns : the new list
754 + *********************************************************************/
755 +struct access_control_list *add_to_acl_list(struct access_control_list *l,
761 + int src_masklength, dst_masklength;
762 + addr_list *src_addrs, *dst_addrs;
763 + addr_list *src_addrs_remaining, *dst_addrs_remaining;
765 + src_addrs = acl_addrs(src_spec, &src_masklength, proxy_args, "source");
766 + if (is_nil_addr_list(src_addrs))
768 + log_error(LOG_LEVEL_ERROR, "Source of ACL resolves to no address",dst_spec);
771 + if (dst_spec != NULL)
773 + dst_addrs = acl_addrs(dst_spec, &dst_masklength, proxy_args, "destination");
774 + if (is_nil_addr_list(dst_addrs))
776 + log_error(LOG_LEVEL_ERROR, "Destination of ACL resolves to no address",dst_spec);
777 + destroy_addr_list(src_addrs);
784 + for(src_addrs_remaining = src_addrs;
785 + is_nil_addr_list(src_addrs);
786 + src_addrs_remaining=tail_addr_list(src_addrs_remaining))
788 + if (dst_addrs == NULL)
789 + l = add_one_to_acl_list(l, action, src_addrs_remaining, NULL, src_masklength,0);
790 + else for(dst_addrs_remaining = dst_addrs;
791 + is_nil_addr_list(dst_addrs);
792 + dst_addrs_remaining=tail_addr_list(dst_addrs_remaining))
793 + l = add_one_to_acl_list(l, action, src_addrs_remaining, dst_addrs_remaining,
794 + src_masklength, dst_masklength);
796 + destroy_addr_list(src_addrs);
797 + destroy_addr_list(dst_addrs);
801 -#endif /* def FEATURE_ACL */
803 +#endif /* def FEATURE_ACL */
805 /*********************************************************************
807 diff -urNad privoxy~/filters.h privoxy/filters.h
808 --- privoxy~/filters.h
809 +++ privoxy/filters.h
811 * Copyright : Written by and Copyright (C) 2001, 2004 the SourceForge
812 * Privoxy team. http://www.privoxy.org/
814 + * Modified by Lionel Elie Mamane <lionel@mamane.lu>
815 + * for IPv6 support on 8 December 2002, 24 January 2003.
817 * Based on the Internet Junkbuster originally written
818 * by and Copyright (C) 1997 Anonymous Coders and
819 * Junkbusters Corporation. http://www.junkbusters.com
823 extern int block_acl(struct access_control_addr *dst, struct client_state *csp);
824 -extern int acl_addr(char *aspec, struct access_control_addr *aca);
825 +extern struct access_control_list *add_to_acl_list(struct access_control_list *l,
829 + char **proxy_args);
830 #endif /* def FEATURE_ACL */
831 extern int match_portlist(const char *portlist, int port);
833 diff -urNad privoxy~/gateway.c privoxy/gateway.c
834 --- privoxy~/gateway.c
835 +++ privoxy/gateway.c
837 * Copyright : Written by and Copyright (C) 2001 the SourceForge
838 * Privoxy team. http://www.privoxy.org/
840 + * Modified by Lionel Elie Mamane <lionel@mamane.lu>
841 + * for IPv6 support on 8 December 2002, 24 January 2003.
843 * Based on the Internet Junkbuster originally written
844 * by and Copyright (C) 1997 Anonymous Coders and
845 * Junkbusters Corporation. http://www.junkbusters.com
846 @@ -203,12 +206,14 @@
847 * Returns : JB_INVALID_SOCKET => failure, else it is the socket file descriptor.
849 *********************************************************************/
850 -jb_socket forwarded_connect(const struct forward_spec * fwd,
851 +jb_socket forwarded_connect(const struct forward_spec *fwd,
852 struct http_request *http,
853 struct client_state *csp)
855 const char * dest_host;
857 + const char * dest_port_str;
858 + unsigned long dest_port;
861 /* Figure out if we need to connect to the web server or a HTTP proxy. */
862 if (fwd->forward_host)
863 @@ -216,19 +221,23 @@
865 dest_host = fwd->forward_host;
866 dest_port = fwd->forward_port;
867 + dest_port_str = fwd->forward_port_str;
868 + dest_pf = fwd->forward_family;
873 dest_host = http->host;
874 dest_port = http->port;
875 + dest_port_str = http->port_str;
876 + dest_pf = PF_UNSPEC;
879 /* Connect, maybe using a SOCKS proxy */
883 - return (connect_to(dest_host, dest_port, csp));
884 + return (connect_to(dest_host, dest_port_str, dest_port, dest_pf, csp));
888 @@ -262,74 +271,19 @@
889 * Returns : JB_INVALID_SOCKET => failure, else a socket file descriptor.
891 *********************************************************************/
892 -static jb_socket socks4_connect(const struct forward_spec * fwd,
893 - const char * target_host,
895 - struct client_state *csp)
896 +static jb_socket socks4_connect_one_ip(const struct forward_spec * fwd,
897 + unsigned long web_server_addr,
899 + struct client_state *csp,
903 - int web_server_addr;
904 - char cbuf[BUFFER_SIZE];
905 char sbuf[BUFFER_SIZE];
906 - struct socks_op *c = (struct socks_op *)cbuf;
907 struct socks_reply *s = (struct socks_reply *)sbuf;
910 + struct socks_reply *c = (struct socks_reply *)cbuf;
915 - if ((fwd->gateway_host == NULL) || (*fwd->gateway_host == '\0'))
917 - log_error(LOG_LEVEL_CONNECT, "socks4_connect: NULL gateway host specified");
921 - if (fwd->gateway_port <= 0)
923 - log_error(LOG_LEVEL_CONNECT, "socks4_connect: invalid gateway port specified");
930 - return(JB_INVALID_SOCKET);
933 - /* build a socks request for connection to the web server */
935 - strcpy((char *)&(c->userid), socks_userid);
937 - csiz = sizeof(*c) + sizeof(socks_userid) - 1;
942 - web_server_addr = htonl(resolve_hostname_to_ip(target_host));
943 - if (web_server_addr == INADDR_NONE)
945 - log_error(LOG_LEVEL_CONNECT, "socks4_connect: could not resolve target host %s", target_host);
946 - return(JB_INVALID_SOCKET);
950 - web_server_addr = 0x00000001;
951 - n = csiz + strlen(target_host) + 1;
952 - if (n > sizeof(cbuf))
955 - return(JB_INVALID_SOCKET);
957 - strcpy(cbuf + csiz, target_host);
961 - /* Should never get here */
962 - log_error(LOG_LEVEL_FATAL, "SOCKS4 impossible internal error - bad SOCKS type.");
964 - return(JB_INVALID_SOCKET);
969 c->dstport[0] = (target_port >> 8 ) & 0xff;
971 c->dstip[3] = (web_server_addr ) & 0xff;
973 /* pass the request to the socks server */
974 - sfd = connect_to(fwd->gateway_host, fwd->gateway_port, csp);
975 + sfd = connect_to(fwd->gateway_host, fwd->gateway_port_str, fwd->gateway_port, PF_INET ,csp);
977 if (sfd == JB_INVALID_SOCKET)
983 +static jb_socket socks4_connect(const struct forward_spec * fwd,
984 + const char * target_host,
986 + struct client_state *csp)
988 + char cbuf[BUFFER_SIZE];
989 + struct socks_op *c = (struct socks_op *)cbuf;
994 + * SOCKS4 is IPv4-specific. At least I think so.
996 + if ((fwd->gateway_host == NULL) || (*fwd->gateway_host == '\0'))
998 + log_error(LOG_LEVEL_CONNECT, "socks4_connect: NULL gateway host specified");
1002 + if (fwd->gateway_port <= 0)
1004 + log_error(LOG_LEVEL_CONNECT, "socks4_connect: invalid gateway port specified");
1011 + return(JB_INVALID_SOCKET);
1014 + /* build a socks request for connection to the web server */
1016 + strcpy((char *)&(c->userid), socks_userid);
1018 + csiz = sizeof(*c) + sizeof(socks_userid) - 1;
1020 + switch (fwd->type)
1024 + addr_list *web_server_addrs = resolve_hostname_to_ip(target_host,NULL,PF_INET);
1025 + jb_socket return_value = JB_INVALID_SOCKET;
1026 + if (is_nil_addr_list(web_server_addrs))
1028 + log_error(LOG_LEVEL_CONNECT, "socks4_connect: could not resolve target host %s", target_host);
1032 + addr_list *addrs_to_try;
1034 + for(addrs_to_try = web_server_addrs;
1035 + !is_nil_addr_list(addrs_to_try);
1036 + addrs_to_try = tail_addr_list(addrs_to_try))
1038 + const unsigned long web_server_addr = ((struct sockaddr_in*) head_addr_list(addrs_to_try))->sin_addr.s_addr;
1039 + return_value=socks4_connect_one_ip(fwd, web_server_addr, target_port, csp, csiz, cbuf);
1040 + if(return_value != JB_INVALID_SOCKET)
1044 + destroy_addr_list(web_server_addrs);
1045 + return return_value;
1051 + n = csiz + strlen(target_host) + 1;
1052 + if (n > sizeof(cbuf))
1055 + return(JB_INVALID_SOCKET);
1057 + strcpy(cbuf + csiz, target_host);
1059 + return socks4_connect_one_ip(fwd, 0x00000001, target_port, csp, csiz, cbuf);
1063 + /* Should never get here */
1064 + log_error(LOG_LEVEL_FATAL, "SOCKS4 impossible internal error - bad SOCKS type.");
1066 + return(JB_INVALID_SOCKET);
1072 diff -urNad privoxy~/jb_socket_set.c privoxy/jb_socket_set.c
1073 --- privoxy~/jb_socket_set.c
1074 +++ privoxy/jb_socket_set.c
1076 +const char jb_socket_set_rcs[] = "$Id: $";
1077 +/*********************************************************************
1079 + * File : $Source: $
1081 + * Purpose : Declares functions to handle sets of sockets
1083 + * Copyright : Written by and Copyright (C) 2002 Lionel Elie Mamane
1084 + * <lionel@mamane.lu>
1086 + * This program is free software; you can redistribute it
1087 + * and/or modify it under the terms of the GNU General
1088 + * Public License as published by the Free Software
1089 + * Foundation; either version 2 of the License, or (at
1090 + * your option) any later version.
1092 + * This program is distributed in the hope that it will
1093 + * be useful, but WITHOUT ANY WARRANTY; without even the
1094 + * implied warranty of MERCHANTABILITY or FITNESS FOR A
1095 + * PARTICULAR PURPOSE. See the GNU General Public
1096 + * License for more details.
1098 + * The GNU General Public License should be included with
1099 + * this file. If not, you can view it at
1100 + * http://www.gnu.org/copyleft/gpl.html
1101 + * or write to the Free Software Foundation, Inc., 59
1102 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1105 + * $Log: jb_socket_set.c,v $
1107 + *********************************************************************/
1109 +#include "jb_socket_set.h"
1110 +#include <sys/time.h>
1111 +#include <sys/types.h>
1112 +#include <unistd.h>
1113 +#include "project.h"
1115 +/*********************************************************************
1117 + * Function : jb_socket_set_add
1119 + * Description : Add a socket to the set
1122 + * 0 : l = the set to add to
1123 + * 1 : the elemen to add to the set
1125 + * Returns : 0 on success
1126 + * non-0 on failure
1128 + *********************************************************************/
1130 +int jb_socket_set_add(jb_socket_set *l, jb_socket e)
1132 + if (l->data==NULL)
1135 + l->data=malloc(l->size * sizeof(jb_socket));
1136 + if (l->data==NULL)
1143 + l->data[(l->occupied)++] = e;
1144 + if (l->occupied == l->size)
1146 + jb_socket *new_data;
1148 + new_data = realloc(l->data,l->size * sizeof(jb_socket));
1149 + if (new_data == NULL)
1151 + /* Not enough memory to continue. Cancel changes. */
1152 + l->data[--(l->occupied)] = JB_INVALID_SOCKET;
1156 + l->data = new_data;
1158 + l->data[l->occupied] = JB_INVALID_SOCKET;
1162 +/*********************************************************************
1164 + * Function : destroy_jb_socket_set
1166 + * Description : Unallocate memory allocated to a socket set
1169 + * 0 : l = the set to unallocate
1171 + * Returns : nothing
1173 + *********************************************************************/
1174 +void destroy_jb_socket_set(jb_socket_set *l)
1177 + init_jb_socket_set(l);
1179 +/*********************************************************************
1181 + * Function : is_empty_jb_socket_set
1183 + * Description : Test wheter a set is empty
1186 + * 0 : l = the set to test
1188 + * Returns : 0 = false if set has a head,
1189 + * anything else = true if set is nil
1191 + *********************************************************************/
1192 +int is_nil_jb_socket_set(jb_socket_set *l)
1194 + return (l->occupied == 0);
1197 +/*********************************************************************
1199 + * Function : init_jb_socket_set
1201 + * Description : Init a set to empty
1204 + * 0 : l = the set to init
1206 + *********************************************************************/
1207 +void init_jb_socket_set(jb_socket_set *l)
1214 +/*********************************************************************
1216 + * Function : jb_socket_set_iteration_begin
1218 + * Description : Return an iterator on the set
1223 + *********************************************************************/
1224 +jb_socket_set_iterate_state jb_socket_set_iteration_begin(jb_socket_set *l)
1229 +/*********************************************************************
1231 + * Function : jb_socket_set_iteration_next
1233 + * Description : Return value pointed to by iterator and step
1234 + * iterator to next position
1237 + * 0 : s = the iterator
1239 + *********************************************************************/
1240 +jb_socket jb_socket_set_iteration_next(jb_socket_set_iterate_state*s)
1242 + return(*((*s)++));
1250 diff -urNad privoxy~/jb_socket_set.h privoxy/jb_socket_set.h
1251 --- privoxy~/jb_socket_set.h
1252 +++ privoxy/jb_socket_set.h
1254 +#ifndef JB_SOCKET_SET_H_INCLUDED
1255 +#define JB_SOCKET_SET_H_INCLUDED
1256 +#define JB_SOCKET_SET_H_VERSION "$Id: $"
1257 +/*********************************************************************
1259 + * File : $Source: $
1261 + * Purpose : Declares functions to handle sets of sockets
1263 + * Copyright : Written by and Copyright (C) 2002 Lionel Elie Mamane
1264 + * <lionel@mamane.lu>
1266 + * This program is free software; you can redistribute it
1267 + * and/or modify it under the terms of the GNU General
1268 + * Public License as published by the Free Software
1269 + * Foundation; either version 2 of the License, or (at
1270 + * your option) any later version.
1272 + * This program is distributed in the hope that it will
1273 + * be useful, but WITHOUT ANY WARRANTY; without even the
1274 + * implied warranty of MERCHANTABILITY or FITNESS FOR A
1275 + * PARTICULAR PURPOSE. See the GNU General Public
1276 + * License for more details.
1278 + * The GNU General Public License should be included with
1279 + * this file. If not, you can view it at
1280 + * http://www.gnu.org/copyleft/gpl.html
1281 + * or write to the Free Software Foundation, Inc., 59
1282 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1285 + * $Log: jb_socket_set.h,v $
1287 + *********************************************************************/
1288 +#include <sys/time.h>
1289 +#include <sys/types.h>
1290 +#include <unistd.h>
1291 +#include "project.h"
1293 +struct jb_socket_set_struct
1295 + unsigned int size; /* size allocated*/
1296 + unsigned int occupied; /* size occupied - 1 == index of final JB_INVALID_SOCKET
1297 + == number of sockets in the set */
1298 + jb_socket *data; /* Array containing the sockets, JB_INVALID_SOCKET-terminated */
1301 +typedef struct jb_socket_set_struct jb_socket_set;
1302 +typedef const jb_socket* jb_socket_set_iterate_state;
1304 +void init_jb_socket_set(jb_socket_set*);
1306 +jb_socket_set_iterate_state jb_socket_set_iteration_begin(jb_socket_set *);
1307 +jb_socket jb_socket_set_iteration_next(jb_socket_set_iterate_state*);
1309 +int jb_socket_set_add(jb_socket_set*, jb_socket);
1311 +void destroy_jb_socket_set(jb_socket_set *l);
1312 +int is_empty_jb_socket_set(jb_socket_set *l);
1314 +#define freez_jb_socket_set(X) { if(X) { destroy_jb_socket_set(X); X = NULL ; } }
1316 +int jb_select(jb_socket_set *readfds, jb_socket_set *writefds, jb_socket_set *exceptfds, struct timeval *timeout);
1318 +#endif /* ndef JB_SOCKET_SET_H_INCLUDED */
1325 diff -urNad privoxy~/jbsockets.c privoxy/jbsockets.c
1326 --- privoxy~/jbsockets.c
1327 +++ privoxy/jbsockets.c
1329 * Copyright : Written by and Copyright (C) 2001 the SourceForge
1330 * Privoxy team. http://www.privoxy.org/
1332 + * Modified by Lionel Elie Mamane <lionel@mamane.lu>
1333 + * for IPv6 support on 8-9 December 2002, 24 January 2003,
1334 + * 13 February 2003.
1336 * Based on the Internet Junkbuster originally written
1337 * by and Copyright (C) 1997 Anonymous Coders and
1338 * Junkbusters Corporation. http://www.junkbusters.com
1340 #include "jbsockets.h"
1341 #include "filters.h"
1343 +#include "addrlist.h"
1345 const char jbsockets_h_rcs[] = JBSOCKETS_H_VERSION;
1347 @@ -287,141 +292,194 @@
1348 * that this is allowed according to ACL.
1351 - * 1 : host = hostname to connect to
1352 - * 2 : portnum = port to connent on
1353 + * 0 : host = hostname to connect to
1354 + * 1 : port = port to connect on, as string
1355 + * 2 : portnum = port to connect on, as integer
1356 * 3 : csp = Current client state (buffers, headers, etc...)
1357 - * Not modified, only used for source IP and ACL.
1359 * Returns : JB_INVALID_SOCKET => failure, else it is the socket
1362 *********************************************************************/
1363 -jb_socket connect_to(const char *host, int portnum, struct client_state *csp)
1364 +jb_socket connect_to_one_ip(struct sockaddr_storage *addr, size_t addrlen, const char *host, unsigned long portnum, struct client_state *csp)
1366 - struct sockaddr_in inaddr;
1370 - struct timeval tv[1];
1371 -#if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA)
1373 -#endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) */
1376 - struct access_control_addr dst[1];
1377 -#endif /* def FEATURE_ACL */
1379 - memset((char *)&inaddr, 0, sizeof inaddr);
1381 - if ((addr = resolve_hostname_to_ip(host)) == INADDR_NONE)
1384 - csp->http->host_ip_addr_str = strdup("unknown");
1385 - return(JB_INVALID_SOCKET);
1387 + struct access_control_addr dst[1];
1388 + char hostname[NI_MAXHOST];
1389 + char port[NI_MAXSERV];
1390 + if (getnameinfo((struct sockaddr*)addr, addrlen, hostname, NI_MAXHOST,
1391 + port, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV) != 0)
1393 + log_error(LOG_LEVEL_ERROR, "connect: Could not get string address and port back from sockaddr because %E");
1394 + strncpy(hostname,"unknown",NI_MAXHOST);
1395 + strncpy(port,"unknown",NI_MAXSERV);
1399 - dst->addr = ntohl((unsigned long) addr);
1400 - dst->port = portnum;
1401 + csp->http->host_ip_addr_str = strdup(hostname);
1403 - if (block_acl(dst, csp))
1405 + dst->addr = *addr;
1406 + dst->addrlen = addrlen;
1407 + dst->port = portnum;
1409 + if (block_acl(dst, csp))
1418 - return(JB_INVALID_SOCKET);
1420 -#endif /* def FEATURE_ACL */
1421 + return(JB_INVALID_SOCKET);
1424 - inaddr.sin_addr.s_addr = addr;
1425 - inaddr.sin_family = AF_INET;
1426 - csp->http->host_ip_addr_str = strdup(inet_ntoa(inaddr.sin_addr));
1429 - if (sizeof(inaddr.sin_port) == sizeof(short))
1430 -#endif /* ndef _WIN32 */
1432 - inaddr.sin_port = htons((unsigned short) portnum);
1436 +#endif /* def FEATURE_ACL */
1439 - inaddr.sin_port = htonl((unsigned long)portnum);
1441 -#endif /* ndef _WIN32 */
1445 - if ((fd = socket(inaddr.sin_family, SOCK_STREAM, 0)) == JB_INVALID_SOCKET)
1446 + if ((fd = socket(addr->ss_family, SOCK_STREAM, 0)) == JB_INVALID_SOCKET)
1448 - if ((fd = socket(inaddr.sin_family, SOCK_STREAM, 0)) < 0)
1449 + if ((fd = socket(addr->ss_family, SOCK_STREAM, 6)) < 0)
1452 - return(JB_INVALID_SOCKET);
1455 + return(JB_INVALID_SOCKET);
1459 - { /* turn off TCP coalescence */
1461 - setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &mi, sizeof (int));
1463 + { /* turn off TCP coalescence */
1465 + setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, (char *) &mi, sizeof (int));
1467 #endif /* def TCP_NODELAY */
1469 #if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__)
1470 - if ((flags = fcntl(fd, F_GETFL, 0)) != -1)
1472 - flags |= O_NDELAY;
1473 - fcntl(fd, F_SETFL, flags);
1478 + if ((flags = fcntl(fd, F_GETFL, 0)) != -1)
1480 + flags |= O_NDELAY;
1481 + fcntl(fd, F_SETFL, flags);
1484 #endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) */
1486 - while (connect(fd, (struct sockaddr *) & inaddr, sizeof inaddr) == JB_INVALID_SOCKET)
1488 + while (connect(fd, (struct sockaddr *) addr, addrlen) == JB_INVALID_SOCKET)
1491 - if (errno == WSAEINPROGRESS)
1492 + if (errno == WSAEINPROGRESS)
1494 - if (sock_errno() == EINPROGRESS)
1495 + if (sock_errno() == EINPROGRESS)
1496 #else /* ifndef _WIN32 */
1497 - if (errno == EINPROGRESS)
1498 + if (errno == EINPROGRESS)
1499 #endif /* ndef _WIN32 || __OS2__ */
1508 - if (sock_errno() != EINTR)
1509 + if (sock_errno() != EINTR)
1511 - if (errno != EINTR)
1512 + if (errno != EINTR)
1513 #endif /* __OS2__ */
1516 + return(JB_INVALID_SOCKET);
1520 +#if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__)
1523 - return(JB_INVALID_SOCKET);
1525 + if ((flags = fcntl(fd, F_GETFL, 0)) != -1)
1527 + flags &= ~O_NDELAY;
1528 + fcntl(fd, F_SETFL, flags);
1532 +#endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) */
1536 + struct timeval tv[1];
1538 + /* wait for connection to complete */
1540 + FD_SET(fd, &wfds);
1545 + /* MS Windows uses int, not SOCKET, for the 1st arg of select(). Wierd! */
1546 + if (select((int)fd + 1, NULL, &wfds, NULL, tv) <= 0)
1549 + return(JB_INVALID_SOCKET);
1551 #if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__)
1554 - flags &= ~O_NDELAY;
1555 - fcntl(fd, F_SETFL, flags);
1559 + int connect_result;
1560 + socklen_t connect_result_len = sizeof connect_result;
1562 + if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &connect_result, &connect_result_len) != 0)
1564 + log_error(LOG_LEVEL_ERROR, "Could not determine whether connection to %s port %d was successful because %E. Assuming failure.",
1565 + csp->http->host_ip_addr_str, portnum);
1567 + return(JB_INVALID_SOCKET);
1569 + else if( connect_result != 0 )
1571 + log_error(LOG_LEVEL_CONNECT, "Connection to %s port %d failed because %s.",
1572 + csp->http->host_ip_addr_str, portnum, strerror(connect_result));
1574 + return(JB_INVALID_SOCKET);
1577 #endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) */
1583 - /* wait for connection to complete */
1585 - FD_SET(fd, &wfds);
1586 +jb_socket connect_to(const char *host, const char *port, unsigned long portnum, int pf, struct client_state *csp)
1588 + jb_socket fd = JB_INVALID_SOCKET;
1589 + struct sockaddr_storage addr;
1590 + addr_list *addrs, *addrs_to_try;
1594 + addrs = resolve_hostname_to_ip(host,port,pf);
1596 - /* MS Windows uses int, not SOCKET, for the 1st arg of select(). Wierd! */
1597 - if (select((int)fd + 1, NULL, &wfds, NULL, tv) <= 0)
1598 + if (is_nil_addr_list(addrs))
1601 - return(JB_INVALID_SOCKET);
1606 + for(addrs_to_try=addrs;
1607 + !is_nil_addr_list(addrs_to_try);
1608 + addrs_to_try = tail_addr_list(addrs_to_try))
1611 + memset((char *)&addr, 0, sizeof addr);
1612 + cpy_head_addr_list(addrs_to_try, &addr,&addrlen);
1613 + fd = connect_to_one_ip(&addr, addrlen, host, portnum, csp);
1614 + if (fd != JB_INVALID_SOCKET)
1619 + if (fd == JB_INVALID_SOCKET)
1621 + csp->http->host_ip_addr_str = strdup("unknown");
1624 + destroy_addr_list(addrs);
1629 @@ -561,55 +619,30 @@
1631 /*********************************************************************
1633 - * Function : bind_port
1634 + * Function : bind_port_one_ip
1636 * Description : Call socket, set socket options, and listen.
1637 - * Called by listen_loop to "boot up" our proxy address.
1640 - * 1 : hostnam = TCP/IP address to bind/listen to
1641 - * 2 : portnum = port to listen on
1642 - * 3 : pfd = pointer used to return file descriptor.
1643 + * 0 : addr = TCP/IP address and port to bind/listen to
1644 + * 1 : fds = jb_socket_set where the new socket should go
1646 - * Returns : if success, returns 0 and sets *pfd.
1647 + * Returns : if success returns 0 and adds sockets to fds.
1648 * if failure, returns -3 if address is in use,
1649 - * -2 if address unresolvable,
1650 + * -2 if memory error
1652 *********************************************************************/
1653 -int bind_port(const char *hostnam, int portnum, jb_socket *pfd)
1654 +int bind_port_one_ip(struct sockaddr *addr, const socklen_t addr_len, jb_socket_set *fds)
1656 - struct sockaddr_in inaddr;
1661 #endif /* ndef _WIN32 */
1663 - *pfd = JB_INVALID_SOCKET;
1665 - memset((char *)&inaddr, '\0', sizeof inaddr);
1667 - inaddr.sin_family = AF_INET;
1668 - inaddr.sin_addr.s_addr = resolve_hostname_to_ip(hostnam);
1670 - if (inaddr.sin_addr.s_addr == INADDR_NONE)
1676 - if (sizeof(inaddr.sin_port) == sizeof(short))
1677 -#endif /* ndef _WIN32 */
1679 - inaddr.sin_port = htons((unsigned short) portnum);
1684 - inaddr.sin_port = htonl((unsigned long) portnum);
1686 -#endif /* ndef _WIN32 */
1687 + fd = JB_INVALID_SOCKET;
1689 - fd = socket(AF_INET, SOCK_STREAM, 0);
1690 + fd = socket(addr->sa_family, SOCK_STREAM, 6);
1693 if (fd == JB_INVALID_SOCKET)
1694 @@ -635,8 +668,17 @@
1696 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one));
1697 #endif /* ndef _WIN32 */
1699 - if (bind(fd, (struct sockaddr *)&inaddr, sizeof(inaddr)) < 0)
1700 + /* As we are now listening on more than one socket,
1701 + * this is important: The only way to be sure accept
1704 + if ((flags = fcntl(fd, F_GETFL, 0)) != -1)
1706 + flags |= O_NONBLOCK;
1707 + fcntl(fd, F_SETFL, flags);
1710 + if (bind (fd, addr, addr_len) < 0)
1713 errno = WSAGetLastError();
1718 - while (listen(fd, 5) == -1)
1719 + while (listen(fd, 25) == -1)
1723 @@ -663,7 +705,11 @@
1728 + if (jb_socket_set_add(fds,fd) != 0)
1736 @@ -671,6 +717,91 @@
1738 /*********************************************************************
1740 + * Function : bind_port
1742 + * Description : Call bind_port_one_ip on all addresses host resolves to
1743 + * Called by listen_loop to "boot up" our proxy address.
1746 + * 0 : host = TCP/IP hostname to bind/listen to
1747 + * 1 : port = port to listen to, as string
1748 + * 2 : fds = socket set the sockets should be added to
1750 + * Returns : if success on at least one address resolving from hostnam,
1751 + * returns 0 and adds sockets to fds.
1752 + * if failure, returns non-zero
1753 + *********************************************************************/
1754 +int bind_port(const char *host, const char *port, int pf, jb_socket_set *fds)
1758 + struct sockaddr_storage addr;
1759 + struct sockaddr * const addr_addr = (struct sockaddr *)&addr;
1760 + addr_list *addrs, *addrs_to_try;
1762 + const char * const log_host = (host != NULL) ? host : "ADDR_ANY";
1764 + addrs = resolve_hostname_to_ip(host,port,pf);
1766 + if (is_nil_addr_list(addrs))
1767 + log_error(LOG_LEVEL_ERROR, "can't bind to %s:%s: "
1768 + "Name resolution didn't give any address",
1771 + log_error(LOG_LEVEL_INFO, "Binding to %s:%s...", log_host, port);
1773 + for(addrs_to_try=addrs;
1774 + !is_nil_addr_list(addrs_to_try);
1775 + addrs_to_try = tail_addr_list(addrs_to_try))
1777 + char numeric_hostname[NI_MAXHOST];
1778 + char numeric_port[NI_MAXSERV];
1780 + memset((char *)addr_addr, 0, sizeof addr);
1781 + cpy_head_addr_list(addrs_to_try, &addr, &addrlen);
1782 + result = getnameinfo(addr_addr, addrlen, numeric_hostname, NI_MAXHOST,
1783 + numeric_port, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV);
1786 + log_error(LOG_LEVEL_ERROR, "bind: Could not get string address and port back from sockaddr because %E");
1787 + strncpy(numeric_hostname,"unknown",NI_MAXHOST);
1788 + strncpy(numeric_port,"unknown",NI_MAXSERV);
1790 + result = bind_port_one_ip(addr_addr, addrlen, fds);
1794 + log_error(LOG_LEVEL_INFO, "Successfully bound to %s:%s", numeric_hostname, numeric_port);
1801 + log_error(LOG_LEVEL_ERROR, "can't bind to %s:%s (%s:%s): "
1802 + "There may be another Privoxy or some other "
1803 + "proxy running on port %s",
1804 + log_host, port, numeric_hostname, numeric_port, numeric_port);
1807 + log_error(LOG_LEVEL_ERROR, "can't bind to %s:%s (%s:%s): "
1809 + log_host, port, numeric_hostname, numeric_port);
1812 + log_error(LOG_LEVEL_ERROR, "can't bind to %s:%s: because %E",
1813 + log_host, numeric_port);
1818 + destroy_addr_list(addrs);
1823 +/*********************************************************************
1825 * Function : accept_connection
1827 * Description : Accepts a connection on a socket. Socket must have
1829 *********************************************************************/
1830 int accept_connection(struct client_state * csp, jb_socket fd)
1832 - struct sockaddr_in client, server;
1833 - struct hostent *host = NULL;
1834 + struct sockaddr_storage client, server;
1836 #if defined(_WIN32) || defined(__OS2__) || defined(__APPLE_CC__) || defined(AMIGA)
1837 /* Wierdness - fix a warning. */
1838 @@ -696,15 +826,7 @@
1840 socklen_t c_length, s_length;
1842 -#if defined(HAVE_GETHOSTBYADDR_R_8_ARGS) || defined(HAVE_GETHOSTBYADDR_R_7_ARGS) || defined(HAVE_GETHOSTBYADDR_R_5_ARGS)
1843 - struct hostent result;
1844 -#if defined(HAVE_GETHOSTBYADDR_R_5_ARGS)
1845 - struct hostent_data hdata;
1847 - char hbuf[HOSTENT_BUFFER_SIZE];
1849 -#endif /* def HAVE_GETHOSTBYADDR_R_5_ARGS */
1850 -#endif /* def HAVE_GETHOSTBYADDR_R_(8|7|5)_ARGS */
1853 c_length = s_length = sizeof(client);
1855 @@ -724,6 +846,12 @@
1859 + /* If we inherited O_NONBLOCK from the listening fd, unset it */
1860 + if ((flags = fcntl(fd, F_GETFL, 0)) != -1)
1862 + flags &= ~O_NONBLOCK;
1863 + fcntl(fd, F_SETFL, flags);
1867 * Determine the IP-Adress that the client used to reach us
1868 @@ -731,49 +859,50 @@
1870 if (!getsockname(afd, (struct sockaddr *) &server, &s_length))
1872 - csp->my_ip_addr_str = strdup(inet_ntoa(server.sin_addr));
1873 -#if defined(HAVE_GETHOSTBYADDR_R_8_ARGS)
1874 - gethostbyaddr_r((const char *)&server.sin_addr,
1875 - sizeof(server.sin_addr), AF_INET,
1876 - &result, hbuf, HOSTENT_BUFFER_SIZE,
1878 -#elif defined(HAVE_GETHOSTBYADDR_R_7_ARGS)
1879 - host = gethostbyaddr_r((const char *)&server.sin_addr,
1880 - sizeof(server.sin_addr), AF_INET,
1881 - &result, hbuf, HOSTENT_BUFFER_SIZE, &thd_err);
1882 -#elif defined(HAVE_GETHOSTBYADDR_R_5_ARGS)
1883 - if (0 == gethostbyaddr_r((const char *)&server.sin_addr,
1884 - sizeof(server.sin_addr), AF_INET,
1886 + char hostname[NI_MAXHOST];
1887 + char port[NI_MAXSERV];
1889 + if (getnameinfo((struct sockaddr *)&server, s_length, hostname, NI_MAXHOST,
1890 + port, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV) != 0)
1893 + log_error(LOG_LEVEL_ERROR, "accept: Could not get string address and port back from server sockaddr because %E");
1894 + strncpy(hostname,"unknown IP",NI_MAXHOST);
1895 + strncpy(port,"unknown port",NI_MAXSERV);
1898 + csp->my_ip_addr_str = strdup(hostname);
1899 + csp->my_port_str = strdup(port);
1901 + if (getnameinfo((struct sockaddr *)&server, s_length, hostname, NI_MAXHOST, NULL, 0, NI_NAMEREQD) != 0)
1904 + log_error(LOG_LEVEL_ERROR, "accept: Could not get my own hostname because %E");
1905 + strncpy(hostname,"unknown host",NI_MAXHOST);
1907 -#elif defined(OSX_DARWIN) || defined(__OpenBSD__)
1908 - pthread_mutex_lock(&gethostbyaddr_mutex);
1909 - host = gethostbyaddr((const char *)&server.sin_addr,
1910 - sizeof(server.sin_addr), AF_INET);
1911 - pthread_mutex_unlock(&gethostbyaddr_mutex);
1913 - host = gethostbyaddr((const char *)&server.sin_addr,
1914 - sizeof(server.sin_addr), AF_INET);
1917 + csp->my_hostname = strdup(hostname);
1921 + log_error(LOG_LEVEL_ERROR, "accept: Could not get sockaddr from socket fd because %E");
1926 + char hostname[NI_MAXHOST];
1928 + if (getnameinfo((struct sockaddr *)&client, c_length, hostname, NI_MAXHOST, NULL, 0, NI_NUMERICHOST) != 0)
1930 - log_error(LOG_LEVEL_ERROR, "Unable to get my own hostname: %E\n");
1931 + log_error(LOG_LEVEL_ERROR, "accept: Could not get client IP address string because %E");
1932 + strncpy(hostname,"unknown IP",NI_MAXHOST);
1935 + csp->my_ip_addr_str = strdup(hostname);
1937 + if (getnameinfo((struct sockaddr *)&server, s_length, hostname, NI_MAXHOST, NULL, 0, 0) != 0)
1939 - csp->my_hostname = strdup(host->h_name);
1940 + log_error(LOG_LEVEL_ERROR, "accept: Could not get my own hostname because %E");
1941 + strncpy(hostname,"unknown host",NI_MAXHOST);
1943 + csp->ip_addr_str = strdup(hostname);
1947 - csp->ip_addr_str = strdup(inet_ntoa(client.sin_addr));
1948 - csp->ip_addr_long = ntohl(client.sin_addr.s_addr);
1949 + csp->ip_addr_addr = client;
1953 @@ -784,108 +913,42 @@
1955 * Function : resolve_hostname_to_ip
1957 - * Description : Resolve a hostname to an internet tcp/ip address.
1958 - * NULL or an empty string resolve to INADDR_ANY.
1959 + * Description : Resolve a hostname to a list of internet tcp/ip addresses.
1962 - * 1 : host = hostname to resolve
1963 + * 0 : host = hostname to resolve
1964 + * 1 : result = where to store the result
1965 + * 2 : pf = preferred address family. PF_UNSPEC for no preference (recommended).
1967 - * Returns : INADDR_NONE => failure, INADDR_ANY or tcp/ip address if succesful.
1968 + * Returns : A (possibly empty) list of adresses
1970 *********************************************************************/
1971 -unsigned long resolve_hostname_to_ip(const char *host)
1973 - struct sockaddr_in inaddr;
1974 - struct hostent *hostp;
1975 - unsigned int dns_retries = 0;
1976 -#if defined(HAVE_GETHOSTBYNAME_R_6_ARGS) || defined(HAVE_GETHOSTBYNAME_R_5_ARGS) || defined(HAVE_GETHOSTBYNAME_R_3_ARGS)
1977 - struct hostent result;
1978 -#if defined(HAVE_GETHOSTBYNAME_R_6_ARGS) || defined(HAVE_GETHOSTBYNAME_R_5_ARGS)
1979 - char hbuf[HOSTENT_BUFFER_SIZE];
1981 -#else /* defined(HAVE_GETHOSTBYNAME_R_3_ARGS) */
1982 - struct hostent_data hdata;
1983 -#endif /* def HAVE_GETHOSTBYNAME_R_(6|5)_ARGS */
1984 -#endif /* def HAVE_GETHOSTBYNAME_R_(6|5|3)_ARGS */
1986 - if ((host == NULL) || (*host == '\0'))
1988 - return(INADDR_ANY);
1991 - memset((char *) &inaddr, 0, sizeof inaddr);
1993 - if ((inaddr.sin_addr.s_addr = inet_addr(host)) == -1)
1995 -#if defined(HAVE_GETHOSTBYNAME_R_6_ARGS)
1996 - while ( gethostbyname_r(host, &result, hbuf,
1997 - HOSTENT_BUFFER_SIZE, &hostp, &thd_err)
1998 - && (thd_err == TRY_AGAIN) && (dns_retries++ < 10) )
2000 - log_error(LOG_LEVEL_ERROR, "Timeout #%u while trying to resolve %s. Trying again.",
2001 - dns_retries, host);
2003 -#elif defined(HAVE_GETHOSTBYNAME_R_5_ARGS)
2004 - hostp = gethostbyname_r(host, &result, hbuf,
2005 - HOSTENT_BUFFER_SIZE, &thd_err);
2006 -#elif defined(HAVE_GETHOSTBYNAME_R_3_ARGS)
2007 - if (0 == gethostbyname_r(host, &result, &hdata))
2015 -#elif defined(OSX_DARWIN) || defined(__OpenBSD__)
2016 - pthread_mutex_lock(&gethostbyname_mutex);
2017 - while ( NULL == (hostp = gethostbyname(host))
2018 - && (h_errno == TRY_AGAIN) && (dns_retries++ < 10) )
2020 - log_error(LOG_LEVEL_ERROR, "Timeout #%u while trying to resolve %s. Trying again.",
2021 - dns_retries, host);
2023 - pthread_mutex_unlock(&gethostbyname_mutex);
2025 - while ( NULL == (hostp = gethostbyname(host))
2026 - && (h_errno == TRY_AGAIN) && (dns_retries++ < 10) )
2028 - log_error(LOG_LEVEL_ERROR, "Timeout #%u while trying to resolve %s. Trying again.",
2029 - dns_retries, host);
2031 -#endif /* def HAVE_GETHOSTBYNAME_R_(6|5|3)_ARGS */
2033 - * On Mac OSX, if a domain exists but doesn't have a type A
2034 - * record associated with it, the h_addr member of the struct
2035 - * hostent returned by gethostbyname is NULL, even if h_length
2036 - * is 4. Therefore the second test below.
2038 - if (hostp == NULL || hostp->h_addr == NULL)
2041 - log_error(LOG_LEVEL_ERROR, "could not resolve hostname %s", host);
2042 - return(INADDR_NONE);
2044 - if (hostp->h_addrtype != AF_INET)
2047 - errno = WSAEPROTOTYPE;
2049 - errno = EPROTOTYPE;
2051 - log_error(LOG_LEVEL_ERROR, "hostname %s resolves to unknown address type.", host);
2052 - return(INADDR_NONE);
2055 - (char *) &inaddr.sin_addr,
2056 - (char *) hostp->h_addr,
2057 - sizeof(inaddr.sin_addr)
2060 - return(inaddr.sin_addr.s_addr);
2064 +addr_list *resolve_hostname_to_ip(const char *host, const char *port, int pf)
2067 + * Do all supported platforms have "getaddrinfo"?
2070 + struct addrinfo hints, *res0;
2072 + memset(&hints, 0, sizeof(hints));
2073 + hints.ai_family = pf;
2074 + hints.ai_socktype = SOCK_STREAM;
2076 + result = getaddrinfo(host, port, &hints, &res0);
2077 + if ( result != 0 )
2079 + log_error(LOG_LEVEL_ERROR, "could not resolve hostname %s because %s", host,gai_strerror(result));
2080 + if (result == EAI_SYSTEM)
2081 + log_error(LOG_LEVEL_ERROR, "The system error is %E");
2086 + log_error(LOG_LEVEL_ERROR, "Problem in resolving hostname %s: succeeded, but no information returned", host);
2093 diff -urNad privoxy~/jbsockets.h privoxy/jbsockets.h
2094 --- privoxy~/jbsockets.h
2095 +++ privoxy/jbsockets.h
2097 * Copyright : Written by and Copyright (C) 2001 the SourceForge
2098 * Privoxy team. http://www.privoxy.org/
2100 + * Modified by Lionel Elie Mamane <lionel@mamane.lu>
2101 + * for IPv6 support on 8 December 2002, 24 January 2003.
2103 * Based on the Internet Junkbuster originally written
2104 * by and Copyright (C) 1997 Anonymous Coders and
2105 * Junkbusters Corporation. http://www.junkbusters.com
2106 @@ -104,9 +107,11 @@
2110 +#include "addrlist.h"
2112 struct client_state;
2114 -extern jb_socket connect_to(const char *host, int portnum, struct client_state *csp);
2115 +extern jb_socket connect_to(const char *host, const char *port, unsigned long portnum, int pf, struct client_state *csp);
2117 extern int write_socket(jb_socket fd, const char *buf, ssize_t n);
2119 @@ -115,10 +120,10 @@
2120 extern int read_socket(jb_socket fd, char *buf, int n);
2121 extern void close_socket(jb_socket fd);
2123 -extern int bind_port(const char *hostnam, int portnum, jb_socket *pfd);
2124 +extern int bind_port(const char *host, const char *port, int pf, jb_socket_set *fds);
2125 extern int accept_connection(struct client_state * csp, jb_socket fd);
2127 -extern unsigned long resolve_hostname_to_ip(const char *host);
2128 +extern addr_list *resolve_hostname_to_ip(const char *host, const char *port, int pf);
2130 /* Revision control strings from this header and associated .c file */
2131 extern const char jbsockets_rcs[];
2132 diff -urNad privoxy~/jcc.c privoxy/jcc.c
2137 #include "loadcfg.h"
2138 #include "urlmatch.h"
2139 +#include "jb_socket_set.h"
2141 const char jcc_h_rcs[] = JCC_H_VERSION;
2142 const char project_h_rcs[] = PROJECT_H_VERSION;
2143 @@ -2306,61 +2307,78 @@
2144 * Returns : Port that was opened.
2146 *********************************************************************/
2147 -static jb_socket bind_port_helper(struct configuration_spec * config)
2148 +static void bind_port_helper(struct configuration_spec * config, jb_socket_set *bfds)
2152 + struct bind_spec *bs;
2153 + unsigned int bs_index;
2156 - if ( (config->haddr != NULL)
2157 - && (config->haddr[0] == '1')
2158 - && (config->haddr[1] == '2')
2159 - && (config->haddr[2] == '7')
2160 - && (config->haddr[3] == '.') )
2162 - log_error(LOG_LEVEL_INFO, "Listening on port %d for local connections only",
2165 - else if (config->haddr == NULL)
2167 - log_error(LOG_LEVEL_INFO, "Listening on port %d on all IP addresses",
2172 + for (bs_index = 0; bs_index < config->hspecs_occupied;++bs_index)
2174 - log_error(LOG_LEVEL_INFO, "Listening on port %d on IP address %s",
2175 - config->hport, config->haddr);
2177 + bs = &config->hspecs[bs_index];
2179 + /* This check misses about a trillion zillion different manners to describe
2180 + the local interface in IPv6. Who cares? */
2181 + if ( (bs->haddr != NULL)
2182 + && (((bs->haddr[0] == '1')
2183 + && (bs->haddr[1] == '2')
2184 + && (bs->haddr[2] == '7')
2185 + && (bs->haddr[3] == '.'))
2186 + || ((bs->haddr[0] == ':')
2187 + && (bs->haddr[1] == ':')
2188 + && (bs->haddr[2] == '1'))))
2190 + log_error(LOG_LEVEL_INFO, "Listening on port %s for local connections only",
2193 + else if (bs->haddr == NULL || bs->haddr[0]=='\0')
2195 + log_error(LOG_LEVEL_INFO, "Listening on port %s on all IP addresses",
2200 + log_error(LOG_LEVEL_INFO, "Listening on port %s on IP address %s",
2201 + bs->hport, bs->haddr);
2204 - result = bind_port(config->haddr, config->hport, &bfd);
2205 + result = bind_port(bs->haddr, bs->hport, bs->pf, bfds);
2215 - log_error(LOG_LEVEL_FATAL, "can't bind to %s:%d: "
2216 + log_error(LOG_LEVEL_ERROR, "can't bind to %s:%s: "
2217 "There may be another Privoxy or some other "
2218 - "proxy running on port %d",
2219 - (NULL != config->haddr) ? config->haddr : "INADDR_ANY",
2220 - config->hport, config->hport);
2221 + "proxy running on port %s",
2222 + (NULL != bs->haddr) ? bs->haddr : "INADDR_ANY",
2223 + bs->hport, bs->hport);
2227 - log_error(LOG_LEVEL_FATAL, "can't bind to %s:%d: "
2228 + log_error(LOG_LEVEL_ERROR, "can't bind to %s:%s: "
2229 "The hostname is not resolvable",
2230 - (NULL != config->haddr) ? config->haddr : "INADDR_ANY", config->hport);
2231 + (NULL != bs->haddr) ? bs->haddr : "INADDR_ANY", bs->hport);
2235 - log_error(LOG_LEVEL_FATAL, "can't bind to %s:%d: because %E",
2236 - (NULL != config->haddr) ? config->haddr : "INADDR_ANY", config->hport);
2237 + log_error(LOG_LEVEL_ERROR, "can't bind to %s:%s: because %E",
2238 + (NULL != bs->haddr) ? bs->haddr : "INADDR_ANY", bs->hport);
2247 + log_error(LOG_LEVEL_FATAL, "Couldn't bind at all - bailing out");
2248 /* shouldn't get here */
2249 - return JB_INVALID_SOCKET;
2252 config->need_bind = 0;
2258 @@ -2389,12 +2407,18 @@
2259 static void listen_loop(void)
2261 struct client_state *csp = NULL;
2263 + jb_socket_set bfds;
2265 + jb_socket_set_iterate_state bfds_iterate_state;
2266 + jb_socket bfd_current;
2267 struct configuration_spec * config;
2269 + init_jb_socket_set(&bfds);
2271 config = load_config();
2273 - bfd = bind_port_helper(config);
2274 + bind_port_helper(config,&bfds);
2275 + bfd_current=JB_INVALID_SOCKET;
2277 #ifdef FEATURE_GRACEFUL_TERMINATION
2278 while (!g_terminate)
2279 @@ -2468,14 +2492,55 @@
2280 * that this will hurt people's feelings.
2283 - close_socket(bfd);
2284 + jb_socket_set_iterate_state s;
2286 + s=jb_socket_set_iteration_begin(&bfds);
2287 + for(bfd=jb_socket_set_iteration_next(&s);bfd!=JB_INVALID_SOCKET;bfd=jb_socket_set_iteration_next(&s))
2289 + close_socket(bfd);
2291 + destroy_jb_socket_set(&bfds);
2292 + bind_port_helper(config,&bfds);
2293 + /* We have a new set of fd's to accept. Restart iteration over bfds. */
2294 + bfd_current = JB_INVALID_SOCKET;
2297 - bfd = bind_port_helper(config);
2298 + /* Here: select call on listening sockets: bfd=sockets */
2299 + if (bfd_current == JB_INVALID_SOCKET)
2302 + log_error(LOG_LEVEL_CONNECT, "select connections ... ");
2303 + bfds_iterate_state=jb_socket_set_iteration_begin(&bfds);
2304 + FD_ZERO(&bfds_fs);
2306 + for(bfd_current=jb_socket_set_iteration_next(&bfds_iterate_state);
2307 + bfd_current!=JB_INVALID_SOCKET;
2308 + bfd_current=jb_socket_set_iteration_next(&bfds_iterate_state))
2310 + FD_SET(bfd_current,&bfds_fs);
2311 + if (bfd_current >= max)
2312 + max = bfd_current + 1;
2314 + if(!select(max,&bfds_fs,NULL,NULL,NULL))
2316 + log_error(LOG_LEVEL_CONNECT, "select failed: %E");
2317 + bfd_current=JB_INVALID_SOCKET;
2320 + log_error(LOG_LEVEL_CONNECT, "OK");
2321 + bfds_iterate_state=jb_socket_set_iteration_begin(&bfds);
2322 + bfd_current=jb_socket_set_iteration_next(&bfds_iterate_state);
2324 + if (!FD_ISSET(bfd_current,&bfds_fs))
2326 + bfd_current=jb_socket_set_iteration_next(&bfds_iterate_state);
2331 log_error(LOG_LEVEL_CONNECT, "accept connection ... ");
2333 - if (!accept_connection(csp, bfd))
2334 + if (!accept_connection(csp, bfd_current))
2336 log_error(LOG_LEVEL_CONNECT, "accept failed: %E");
2338 @@ -2493,6 +2558,8 @@
2339 log_error(LOG_LEVEL_CONNECT, "OK");
2342 + bfd_current=jb_socket_set_iteration_next(&bfds_iterate_state);
2344 #ifdef FEATURE_TOGGLE
2345 if (global_toggle_state)
2347 diff -urNad privoxy~/loadcfg.c privoxy/loadcfg.c
2348 --- privoxy~/loadcfg.c
2349 +++ privoxy/loadcfg.c
2351 * Copyright : Written by and Copyright (C) 2001 the SourceForge
2352 * Privoxy team. http://www.privoxy.org/
2354 + * Modified by Lionel Elie Mamane <lionel@mamane.lu>
2355 + * for IPv6 support on 8 December 2002, 24 January 2003.
2357 * Based on the Internet Junkbuster originally written
2358 * by and Copyright (C) 1997 Anonymous Coders and
2359 * Junkbusters Corporation. http://www.junkbusters.com
2362 #include "urlmatch.h"
2364 +#include "parsers.h"
2366 const char loadcfg_h_rcs[] = LOADCFG_H_VERSION;
2369 struct forward_spec * next_fwd = cur_fwd->next;
2370 free_url_spec(cur_fwd->url);
2372 - freez(cur_fwd->gateway_host);
2373 - freez(cur_fwd->forward_host);
2374 + freez(cur_fwd->gateway_malloc);
2375 + freez(cur_fwd->forward_malloc);
2379 @@ -539,7 +543,16 @@
2380 freez(config->confdir);
2381 freez(config->logdir);
2383 - freez(config->haddr);
2384 + if(config -> hspecs != NULL)
2387 + for (i=0; i < config->hspecs_occupied; ++i)
2389 + freez(config->hspecs[i].haddr);
2390 + freez(config->hspecs[i].hport);
2393 + freez(config->hspecs);
2394 freez(config->logfile);
2396 for (i = 0; i < MAX_AF_FILES; i++)
2397 @@ -606,6 +619,28 @@
2398 * Returns : The configuration_spec, or NULL on error.
2400 *********************************************************************/
2401 +static void fail_load_config_memory(struct file_list *fs, struct configuration_spec *config)
2403 + freez(fs->filename);
2405 + if (config != NULL)
2407 + if(config -> hspecs != NULL)
2410 + for (i=0; i < config->hspecs_occupied; ++i)
2412 + freez(config->hspecs[i].haddr);
2413 + freez(config->hspecs[i].hport);
2416 + freez(config -> hspecs);
2419 + log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
2420 + /* Never get here - LOG_LEVEL_FATAL causes program exit */
2423 struct configuration_spec * load_config(void)
2425 char buf[BUFFER_SIZE];
2426 @@ -637,12 +672,7 @@
2427 fs->f = config = (struct configuration_spec *)zalloc(sizeof(*config));
2431 - freez(fs->filename);
2433 - log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
2434 - /* Never get here - LOG_LEVEL_FATAL causes program exit */
2436 + fail_load_config_memory(fs,config);
2439 * This is backwards from how it's usually done.
2443 config->multi_threaded = 1;
2444 - config->hport = HADDR_PORT;
2445 + config->hspecs = NULL;
2446 config->buffer_limit = 4096 * 1024;
2447 config->usermanual = strdup(USER_MANUAL_URL);
2448 config->proxy_args = strdup("");
2450 char cmd[BUFFER_SIZE];
2451 char arg[BUFFER_SIZE];
2452 char tmp[BUFFER_SIZE];
2454 - struct access_control_list *cur_acl;
2455 -#endif /* def FEATURE_ACL */
2456 struct forward_spec *cur_fwd;
2459 @@ -791,74 +818,23 @@
2460 * *************************************************************************/
2462 case hash_deny_access:
2463 - vec_count = ssplit(arg, " \t", vec, SZ(vec), 1, 1);
2465 - if ((vec_count != 1) && (vec_count != 2))
2467 - log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
2468 - "deny-access directive in configuration file.");
2469 - string_append(&config->proxy_args,
2470 - "<br>\nWARNING: Wrong number of parameters for "
2471 - "deny-access directive in configuration file.<br><br>\n");
2475 - /* allocate a new node */
2476 - cur_acl = (struct access_control_list *) zalloc(sizeof(*cur_acl));
2478 - if (cur_acl == NULL)
2480 - log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
2481 - /* Never get here - LOG_LEVEL_FATAL causes program exit */
2484 - cur_acl->action = ACL_DENY;
2486 - if (acl_addr(vec[0], cur_acl->src) < 0)
2488 - log_error(LOG_LEVEL_ERROR, "Invalid source IP for deny-access "
2489 - "directive in configuration file: \"%s\"", vec[0]);
2490 - string_append(&config->proxy_args,
2491 - "<br>\nWARNING: Invalid source IP for deny-access directive"
2492 - " in configuration file: \"");
2493 - string_append(&config->proxy_args,
2495 - string_append(&config->proxy_args,
2500 - if (vec_count == 2)
2501 + switch (ssplit(arg, " \t", vec, SZ(vec), 1, 1))
2503 - if (acl_addr(vec[1], cur_acl->dst) < 0)
2505 - log_error(LOG_LEVEL_ERROR, "Invalid destination IP for deny-access "
2506 - "directive in configuration file: \"%s\"", vec[0]);
2507 - string_append(&config->proxy_args,
2508 - "<br>\nWARNING: Invalid destination IP for deny-access directive"
2509 - " in configuration file: \"");
2510 - string_append(&config->proxy_args,
2513 + config->acl = add_to_acl_list(config->acl, ACL_DENY, vec[0], NULL, &config->proxy_args);
2516 + config->acl = add_to_acl_list(config->acl, ACL_DENY, vec[0], vec[1], &config->proxy_args);
2519 + log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
2520 + "deny-access directive in configuration file.");
2521 string_append(&config->proxy_args,
2526 + "<br>\nWARNING: Wrong number of parameters for "
2527 + "deny-access directive in configuration file.<br><br>\n");
2531 - * Add it to the list. Note we reverse the list to get the
2532 - * behaviour the user expects. With both the ACL and
2533 - * actions file, the last match wins. However, the internal
2534 - * implementations are different: The actions file is stored
2535 - * in the same order as the file, and scanned completely.
2536 - * With the ACL, we reverse the order as we load it, then
2537 - * when we scan it we stop as soon as we get a match.
2539 - cur_acl->next = config->acl;
2540 - config->acl = cur_acl;
2544 #endif /* def FEATURE_ACL */
2546 /* *************************************************************************
2547 @@ -978,16 +954,18 @@
2549 if (strcmp(p, ".") != 0)
2551 - cur_fwd->forward_host = strdup(p);
2552 + cur_fwd->forward_malloc = strdup(p);
2553 + cur_fwd->forward_family = -1;
2555 - if (NULL != (p = strchr(cur_fwd->forward_host, ':')))
2558 - cur_fwd->forward_port = atoi(p);
2560 + parse_pf_ip(cur_fwd->forward_malloc,
2561 + &cur_fwd->forward_host,
2562 + &cur_fwd->forward_port_str,
2563 + &cur_fwd->forward_family);
2564 + cur_fwd->forward_port = atoi(cur_fwd->forward_port_str);
2566 if (cur_fwd->forward_port <= 0)
2568 + cur_fwd->forward_port_str = "8000";
2569 cur_fwd->forward_port = 8000;
2572 @@ -1041,15 +1019,27 @@
2574 if (strcmp(p, ".") != 0)
2576 - cur_fwd->gateway_host = strdup(p);
2577 + /* SOCKS is IPv4-specific */
2580 - if (NULL != (p = strchr(cur_fwd->gateway_host, ':')))
2581 + cur_fwd->gateway_malloc = strdup(p);
2582 + if (parse_pf_ip(cur_fwd->gateway_malloc,
2583 + &cur_fwd->gateway_host,
2584 + &cur_fwd->gateway_port_str,
2588 - cur_fwd->gateway_port = atoi(p);
2589 + log_error(LOG_LEVEL_ERROR, "Could not parse forward-socks4 host: %s",p);
2590 + cur_fwd->gateway_host = NULL;
2591 + cur_fwd->gateway_port_str = NULL;
2592 + freez(cur_fwd->gateway_malloc);
2596 + cur_fwd->gateway_port = atoi(cur_fwd->gateway_port_str);
2598 if (cur_fwd->gateway_port <= 0)
2600 + cur_fwd->gateway_port_str = "1080";
2601 cur_fwd->gateway_port = 1080;
2604 @@ -1059,16 +1049,26 @@
2606 if (strcmp(p, ".") != 0)
2608 - cur_fwd->forward_host = strdup(p);
2609 + cur_fwd->forward_malloc = strdup(p);
2610 + cur_fwd->forward_family = -1;
2612 - if (NULL != (p = strchr(cur_fwd->forward_host, ':')))
2613 + parse_pf_ip(cur_fwd->forward_malloc,
2614 + &cur_fwd->forward_host,
2615 + &cur_fwd->forward_port_str,
2616 + &cur_fwd->forward_family);
2617 + cur_fwd->forward_port = atoi(cur_fwd->forward_port_str);
2619 + if (cur_fwd->forward_port <= 0)
2622 - cur_fwd->forward_port = atoi(p);
2623 + cur_fwd->forward_port_str = "8000";
2624 + cur_fwd->forward_port = 8000;
2627 + cur_fwd->forward_port = atoi(p);
2629 if (cur_fwd->forward_port <= 0)
2631 + cur_fwd->forward_port_str = "8000";
2632 cur_fwd->forward_port = 8000;
2635 @@ -1120,16 +1120,30 @@
2636 /* Parse the SOCKS proxy host[:port] */
2639 - cur_fwd->gateway_host = strdup(p);
2641 - if (NULL != (p = strchr(cur_fwd->gateway_host, ':')))
2644 - cur_fwd->gateway_port = atoi(p);
2646 - if (cur_fwd->gateway_port <= 0)
2648 - cur_fwd->gateway_port = 1080;
2649 + /* SOCKS is IPv4-specific */
2652 + cur_fwd->gateway_malloc = strdup(p);
2653 + if (parse_pf_ip(cur_fwd->gateway_malloc,
2654 + &cur_fwd->gateway_host,
2655 + &cur_fwd->gateway_port_str,
2658 + log_error(LOG_LEVEL_ERROR, "Could not parse forward-socks4a host: %s",p);
2659 + cur_fwd->gateway_host = NULL;
2660 + cur_fwd->gateway_port_str = NULL;
2661 + freez(cur_fwd->gateway_malloc);
2665 + cur_fwd->gateway_port = atoi(cur_fwd->gateway_port_str);
2667 + if (cur_fwd->gateway_port <= 0)
2669 + cur_fwd->gateway_port_str = "1080";
2670 + cur_fwd->gateway_port = 1080;
2674 /* Parse the parent HTTP proxy host[:port] */
2675 @@ -1137,16 +1151,26 @@
2677 if (strcmp(p, ".") != 0)
2679 - cur_fwd->forward_host = strdup(p);
2680 + cur_fwd->forward_malloc = strdup(p);
2681 + cur_fwd->forward_family = -1;
2683 - if (NULL != (p = strchr(cur_fwd->forward_host, ':')))
2684 + parse_pf_ip(cur_fwd->forward_malloc,
2685 + &cur_fwd->forward_host,
2686 + &cur_fwd->forward_port_str,
2687 + &cur_fwd->forward_family);
2688 + cur_fwd->forward_port = atoi(cur_fwd->forward_port_str);
2690 + if (cur_fwd->forward_port <= 0)
2693 - cur_fwd->forward_port = atoi(p);
2694 + cur_fwd->forward_port_str = "8000";
2695 + cur_fwd->forward_port = 8000;
2698 + cur_fwd->forward_port = atoi(p);
2700 if (cur_fwd->forward_port <= 0)
2702 + cur_fwd->forward_port_str = "8000";
2703 cur_fwd->forward_port = 8000;
2706 @@ -1179,10 +1203,49 @@
2707 * listen-address [ip][:port]
2708 * *************************************************************************/
2709 case hash_listen_address :
2710 - freez(config->haddr);
2711 - config->haddr = strdup(arg);
2713 + struct bind_spec *bs;
2715 + if (config->hspecs == NULL)
2717 + /* This is the first we'll bind to */
2718 + config->hspecs = calloc(2,sizeof(struct bind_spec));
2719 + if (config->hspecs == NULL)
2720 + fail_load_config_memory(fs,config);
2721 + config->hspecs_size = 2;
2722 + config->hspecs_occupied = 0;
2725 + arg_cpy = strdup(arg);
2726 + if (arg_cpy == NULL)
2727 + fail_load_config_memory(fs,config);
2728 + if (config->hspecs_occupied == config->hspecs_size)
2730 + struct bind_spec *new_hspecs;
2731 + config->hspecs_size *= 2;
2732 + new_hspecs = realloc(config->hspecs,config->hspecs_size * sizeof(struct bind_spec));
2733 + if (new_hspecs == NULL)
2735 + /* Not enough memory to continue. Cancel changes. */
2736 + config->hspecs_size /= 2;
2737 + fail_load_config_memory(fs,config);
2739 + config->hspecs = new_hspecs;
2741 + bs = &config->hspecs[(config->hspecs_occupied)++];
2743 + parse_pf_ip(arg,&bs->haddr,&bs->hport,&bs->pf);
2744 + if (*bs->haddr == '\0')
2750 + (bs->haddr = strdup(bs->haddr));
2752 + bs->hport = strdup(bs->hport);
2756 /* *************************************************************************
2757 * logdir directory-name
2758 * *************************************************************************/
2759 @@ -1205,75 +1268,21 @@
2760 * *************************************************************************/
2762 case hash_permit_access:
2763 - vec_count = ssplit(arg, " \t", vec, SZ(vec), 1, 1);
2765 - if ((vec_count != 1) && (vec_count != 2))
2767 - log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
2768 - "permit-access directive in configuration file.");
2769 - string_append(&config->proxy_args,
2770 - "<br>\nWARNING: Wrong number of parameters for "
2771 - "permit-access directive in configuration file.<br><br>\n");
2776 - /* allocate a new node */
2777 - cur_acl = (struct access_control_list *) zalloc(sizeof(*cur_acl));
2779 - if (cur_acl == NULL)
2781 - log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
2782 - /* Never get here - LOG_LEVEL_FATAL causes program exit */
2785 - cur_acl->action = ACL_PERMIT;
2787 - if (acl_addr(vec[0], cur_acl->src) < 0)
2789 - log_error(LOG_LEVEL_ERROR, "Invalid source IP for permit-access "
2790 - "directive in configuration file: \"%s\"", vec[0]);
2791 - string_append(&config->proxy_args,
2792 - "<br>\nWARNING: Invalid source IP for permit-access directive"
2793 - " in configuration file: \"");
2794 - string_append(&config->proxy_args,
2796 - string_append(&config->proxy_args,
2801 - if (vec_count == 2)
2802 + switch (ssplit(arg, " \t", vec, SZ(vec), 1, 1))
2804 - if (acl_addr(vec[1], cur_acl->dst) < 0)
2806 - log_error(LOG_LEVEL_ERROR, "Invalid destination IP for "
2807 - "permit-access directive in configuration file: \"%s\"",
2809 - string_append(&config->proxy_args,
2810 - "<br>\nWARNING: Invalid destination IP for permit-access directive"
2811 - " in configuration file: \"");
2812 - string_append(&config->proxy_args,
2815 + config->acl = add_to_acl_list(config->acl, ACL_PERMIT, vec[0], NULL, &config->proxy_args);
2818 + config->acl = add_to_acl_list(config->acl, ACL_PERMIT, vec[0], vec[1], &config->proxy_args);
2821 + log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
2822 + "permit-access directive in configuration file.");
2823 string_append(&config->proxy_args,
2828 + "<br>\nWARNING: Wrong number of parameters for "
2829 + "permit-access directive in configuration file.<br><br>\n");
2833 - * Add it to the list. Note we reverse the list to get the
2834 - * behaviour the user expects. With both the ACL and
2835 - * actions file, the last match wins. However, the internal
2836 - * implementations are different: The actions file is stored
2837 - * in the same order as the file, and scanned completely.
2838 - * With the ACL, we reverse the order as we load it, then
2839 - * when we scan it we stop as soon as we get a match.
2841 - cur_acl->next = config->acl;
2842 - config->acl = cur_acl;
2845 #endif /* def FEATURE_ACL */
2847 @@ -1513,32 +1522,33 @@
2849 #endif /* def FEATURE_COOKIE_JAR */
2851 - if ( NULL == config->haddr )
2853 - config->haddr = strdup( HADDR_DEFAULT );
2856 - if ( NULL != config->haddr )
2857 + if ( config->hspecs == NULL )
2859 - if (NULL != (p = strchr(config->haddr, ':')))
2864 - config->hport = atoi(p);
2868 - if (config->hport <= 0)
2871 - log_error(LOG_LEVEL_FATAL, "invalid bind port spec %s", config->haddr);
2872 - /* Never get here - LOG_LEVEL_FATAL causes program exit */
2874 - if (*config->haddr == '\0')
2876 - config->haddr = NULL;
2878 + /* No listen-address set. The default is localhost on port 8118, on IPv4
2879 + and (if INET6 is defined) IPv6.
2881 + struct bind_spec *bs;
2883 + config->hspecs = calloc(2,sizeof(struct bind_spec));
2884 + if (config->hspecs == NULL)
2885 + fail_load_config_memory(fs,config);
2886 + config->hspecs_size=2;
2887 + config->hspecs_occupied=1;
2888 + bs = &config->hspecs[0];
2889 + bs->haddr = strdup("::1");
2890 + bs->hport = strdup("8118");
2891 + bs->pf = PF_UNSPEC;
2893 + config->hspecs = calloc(1,sizeof(struct bind_spec));
2894 + if (config->hspecs == NULL)
2895 + fail_load_config_memory(fs,config);
2896 + config->hspecs_size=1;
2897 + config->hspecs_occupied=0;
2899 + bs = &config->hspecs[config->hspecs_occupied++];
2900 + bs->haddr = strdup("127.0.0.1");
2901 + bs->hport = strdup("8118");
2902 + bs->pf = PF_UNSPEC;
2906 @@ -1580,31 +1590,29 @@
2907 struct configuration_spec * oldcfg = (struct configuration_spec *)
2908 current_configfile->f;
2910 - * Check if config->haddr,hport == oldcfg->haddr,hport
2912 - * The following could be written more compactly as a single,
2913 - * (unreadably long) if statement.
2914 + * Check if the listening addresses have changed
2916 config->need_bind = 0;
2917 - if (config->hport != oldcfg->hport)
2919 - config->need_bind = 1;
2921 - else if (config->haddr == NULL)
2922 + if (config -> hspecs_occupied == oldcfg -> hspecs_occupied)
2924 - if (oldcfg->haddr != NULL)
2926 + struct bind_spec *hspec;
2927 + struct bind_spec *oldhspec;
2928 + hspec = config -> hspecs;
2929 + oldhspec = oldcfg -> hspecs;
2930 + for(bs_index = 0; bs_index < oldcfg->hspecs_occupied; ++bs_index)
2932 - config->need_bind = 1;
2933 + if (strcmp(hspec[bs_index].haddr,oldhspec[bs_index].haddr) != 0
2934 + || strcmp(hspec[bs_index].hport,oldhspec[bs_index].hport) != 0
2935 + || hspec[bs_index].pf != hspec[bs_index].pf)
2937 + config -> need_bind = 1;
2942 - else if (oldcfg->haddr == NULL)
2944 - config->need_bind = 1;
2946 - else if (0 != strcmp(config->haddr, oldcfg->haddr))
2948 - config->need_bind = 1;
2951 + config-> need_bind = 1;
2953 current_configfile->unloader = unload_configfile;
2955 diff -urNad privoxy~/loaders.c privoxy/loaders.c
2956 --- privoxy~/loaders.c
2957 +++ privoxy/loaders.c
2959 * Copyright : Written by and Copyright (C) 2001 the SourceForge
2960 * Privoxy team. http://www.privoxy.org/
2962 + * Modified by Lionel Elie Mamane <lionel@mamane.lu>
2963 + * for IPv6 support on 8 December 2002, 24 January 2003.
2965 * Based on the Internet Junkbuster originally written
2966 * by and Copyright (C) 1997 Anonymous Coders and
2967 * Junkbusters Corporation. http://www.junkbusters.com
2970 freez(csp->ip_addr_str);
2971 freez(csp->my_ip_addr_str);
2972 + freez(csp->my_port_str);
2973 freez(csp->my_hostname);
2974 freez(csp->x_forwarded);
2975 freez(csp->iob->buf);
2976 diff -urNad privoxy~/miscutil.h privoxy/miscutil.h
2977 --- privoxy~/miscutil.h
2978 +++ privoxy/miscutil.h
2979 @@ -162,6 +162,15 @@
2981 #include "project.h"
2983 +/* Fix a problem with Solaris. There should be no effect on other
2985 + * Solaris's isspace() is a macro which uses it's argument directly
2986 + * as an array index. Therefore we need to make sure that high-bit
2987 + * characters generate +ve values, and ideally we also want to make
2988 + * the argument match the declared parameter type of "int".
2990 +#define ijb_isdigit(__X) isdigit((int)(unsigned char)(__X))
2992 #if defined(__cplusplus)
2995 diff -urNad privoxy~/parsers.c privoxy/parsers.c
2996 --- privoxy~/parsers.c
2997 +++ privoxy/parsers.c
2999 * Copyright : Written by and Copyright (C) 2001 the SourceForge
3000 * Privoxy team. http://www.privoxy.org/
3002 + * Modified by Lionel Elie Mamane <lionel@mamane.lu>
3003 + * for IPv6 support on 24 January 2003.
3005 * Based on the Internet Junkbuster originally written
3006 * by and Copyright (C) 1997 Anonymous Coders and
3007 * Junkbusters Corporation. http://www.junkbusters.com
3008 @@ -1932,6 +1935,167 @@
3012 +/*********************************************************************
3014 + * Function : parse_pf_ip_netmask
3016 + * Description : Parse an IPv{4,6} litteral or hostname
3017 + * with optional port and optional explicit family
3018 + * and optional netmask
3021 + * 0 : string = the string to parse
3022 + * 1 : host = Is set to point to the hostname or IP literal
3024 + * 2 : port = Is set to point to the port part,
3025 + * or NULL if no port in string
3026 + * 3 : pf = pointer used to return the address family
3027 + * pf is a value-result argument:
3028 + * If it is set to -1, then parse_pf_ip will set it
3029 + * to the address family of the pf_ip string
3030 + * else, it won't touch it, and fail if the two
3032 + * 4 : pointer used to return the mask length
3033 + * Set to -1 if no mask
3035 + * Returns : 0 on success
3037 + *********************************************************************/
3038 +int parse_pf_ip_netmask(char *string, char **host, char **port, int *pf, int *masklength)
3045 + if ((p = strchr(string, '/')) != NULL)
3049 + if (ijb_isdigit(*p) == 0)
3059 + return parse_pf_ip(string, host, port, pf);
3062 +/*********************************************************************
3064 + * Function : parse_pf_ip
3066 + * Description : Parse an IPv{4,6} litteral or hostname
3067 + * with optional port and optional explicit family
3070 + * 0 : string = the string to parse
3071 + * 1 : host = Is set to point to the hostname or IP literal
3073 + * 2 : port = Is set to point to the port part,
3074 + * or NULL if no port in string
3075 + * 3 : pf = pointer used to return the address family
3076 + * pf is a value-result argument:
3077 + * If it is set to -1, then parse_pf_ip will set it
3078 + * to the address family of the pf_ip string
3079 + * else, it won't touch it, and fail if the two
3082 + * Returns : 0 on success
3084 + *********************************************************************/
3085 +int parse_pf_ip(char *string, char **host, char **port, int *pf)
3087 + if (pf != NULL && *pf == -1)
3090 + /* See if we want to override the default protocol family */
3091 + if (strncmpic(string, "ipv4:", 5) == 0)
3096 + if(*pf==PF_INET || *pf==PF_UNSPEC)
3100 + log_error(LOG_LEVEL_ERROR,"%s","IPv4 address found where other awaited");
3105 + else if (strncmpic(string, "ipv6:", 5) == 0)
3109 + if(*pf==PF_INET6 || *pf==PF_UNSPEC)
3113 + log_error(LOG_LEVEL_ERROR,"%s","IPv6 address found where other awaited");
3117 + log_error(LOG_LEVEL_ERROR,"%s","This privoxy hasn't IPv6 support");
3121 + return parse_ip(string, host, port);
3124 +/*********************************************************************
3126 + * Function : parse_ip
3128 + * Description : Parse an IPv{4,6} litteral or hostname
3129 + * with optional port
3132 + * 0 : string = the string to parse
3133 + * 1 : host = Is set to point to the hostname or IP literal
3135 + * 2 : port = Is set to point to the port part,
3136 + * or NULL if no port in string
3137 + * Returns : 0 on success
3139 + *********************************************************************/
3140 +int parse_ip(char *string, char **host, char **port)
3145 + /* allow IPv6 address literal: [numbers:with:colons]:port/mask */
3146 + if (string[0] == '[' && (p = strchr(string, ']')))
3158 + *host = string + skip;
3160 + for(;*p != '\0'; ++p)
3174 /*********************************************************************
3176 diff -urNad privoxy~/parsers.h privoxy/parsers.h
3177 --- privoxy~/parsers.h
3178 +++ privoxy/parsers.h
3180 * Copyright : Written by and Copyright (C) 2001 the SourceForge
3181 * Privoxy team. http://www.privoxy.org/
3183 + * Modified by Lionel Elie Mamane <lionel@mamane.lu>
3184 + * for IPv6 support on 24 January 2003.
3186 * Based on the Internet Junkbuster originally written
3187 * by and Copyright (C) 1997 Anonymous Coders and
3188 * Junkbusters Corporation. http://www.junkbusters.com
3189 @@ -270,6 +273,10 @@
3190 extern jb_err server_last_modified (struct client_state *csp, char **header);
3191 extern jb_err server_content_disposition(struct client_state *csp, char **header);
3193 +extern int parse_pf_ip_netmask(char *string, char **host, char **port, int *pf, int *masklength);
3194 +extern int parse_pf_ip(char *string, char ** host, char ** port, int *pf);
3195 +extern int parse_ip(char *string, char ** host, char** port);
3197 #ifdef FEATURE_FORCE_LOAD
3198 extern int strclean(const char *string, const char *substring);
3199 #endif /* def FEATURE_FORCE_LOAD */
3200 diff -urNad privoxy~/project.h privoxy/project.h
3201 --- privoxy~/project.h
3202 +++ privoxy/project.h
3203 @@ -607,6 +607,20 @@
3205 #endif /* ndef _WIN32 */
3207 +#include "jb_socket_set.h"
3211 + * Get from the operating system structures big enough
3212 + * to put a network address in, namely sockaddr_storage
3214 +#include <sys/socket.h>
3216 + * If no IPv6 support, just use the old sockaddr
3219 +#define sockaddr_storage sockaddr
3223 * A standard error code. This should be JB_ERR_OK or one of the JB_ERR_xxx
3224 @@ -681,19 +695,6 @@
3229 - * Default IP address to listen on, as a string.
3230 - * Set to "127.0.0.1".
3232 -#define HADDR_DEFAULT "127.0.0.1"
3235 - * Default port to listen on, as a number.
3238 -#define HADDR_PORT 8118
3241 /* Forward def for struct client_state */
3242 struct configuration_spec;
3244 @@ -772,13 +773,16 @@
3245 char *ver; /**< Protocol version */
3246 int status; /**< HTTP Status */
3248 + char *host_port_malloc; /**< malloc used for place wher host and port_str are */
3249 char *host; /**< Host part of URL */
3250 int port; /**< Port of URL or 80 (default) */
3251 + char *port_str; /**< Port of URL, as string */
3252 char *path; /**< Path of URL */
3253 char *hostport; /**< host[:port] */
3254 int ssl; /**< Flag if protocol is https */
3256 - char *host_ip_addr_str; /**< String with dotted decimal representation
3257 + char *host_ip_addr_str; /**< String with dotted decimal representation (IPv4)
3258 + or hexadecimal colon-separated (IPv6)
3259 of host's IP. NULL before connect_to() */
3261 char *dbuffer; /**< Buffer with '\0'-delimited domain name. */
3262 @@ -1158,13 +1162,16 @@
3265 /** Client PC's IP address, as reported by the accept() function.
3267 - long ip_addr_long;
3269 + struct sockaddr_storage ip_addr_addr;
3271 /** Our IP address. I.e. the IP address that the client used to reach us,
3273 char *my_ip_addr_str;
3275 + /** Our port. I.e. the port the client used to reach us */
3276 + char *my_port_str;
3278 /** Our hostname. I.e. the reverse DNS of the IP address that the client
3279 used to reach us, as a string. */
3281 @@ -1339,18 +1346,33 @@
3282 /** Connection type. Must be SOCKS_NONE, SOCKS_4, or SOCKS_4A. */
3285 + /** pointer returned by the malloc used for gateway_host and gateway_port_str */
3286 + char *gateway_malloc;
3288 /** SOCKS server hostname. Only valid if "type" is SOCKS_4 or SOCKS_4A. */
3291 /** SOCKS server port. */
3294 + /** SOCKS server port, as string. */
3295 + char *gateway_port_str;
3297 + /** pointer returned by the malloc used for forward_host and forward_port_str */
3298 + char *forward_malloc;
3300 + /** Parent HTTP proxy address family. */
3301 + int forward_family;
3303 /** Parent HTTP proxy hostname, or NULL for none. */
3306 /** Parent HTTP proxy port. */
3309 + /** Parent HTTP proxy port as string. */
3310 + char *forward_port_str;
3312 /** Next entry in the linked list. */
3313 struct forward_spec *next;
3315 @@ -1359,7 +1381,7 @@
3317 * Initializer for a static struct forward_spec.
3319 -#define FORWARD_SPEC_INITIALIZER { { URL_SPEC_INITIALIZER }, 0, NULL, 0, NULL, 0, NULL }
3320 +#define FORWARD_SPEC_INITIALIZER { { URL_SPEC_INITIALIZER }, 0, NULL, NULL, 0, NULL, NULL, 0, NULL, 0, NULL, NULL}
3324 @@ -1388,7 +1410,8 @@
3326 struct access_control_addr
3328 - unsigned long addr; /**< The IP address as an integer. */
3329 + struct sockaddr_storage addr; /**< The IP address. */
3331 unsigned long mask; /**< The network mask as an integer. */
3332 unsigned long port; /**< The port number. */
3334 @@ -1423,6 +1446,17 @@
3335 /** configuration_spec::feature_flags: HTTP-header-based toggle. */
3336 #define RUNTIME_FEATURE_HTTP_TOGGLE 4
3340 + /** IP address to bind to. */
3343 + /** Port to bind to. */
3346 + /** Address family */
3350 * Data loaded from the configuration file.
3352 @@ -1486,11 +1520,13 @@
3354 #endif /* def FEATURE_COOKIE_JAR */
3356 - /** IP address to bind to. Defaults to HADDR_DEFAULT == 127.0.0.1. */
3357 - const char *haddr;
3359 - /** Port to bind to. Defaults to HADDR_PORT == 8118. */
3361 + /* IP addresses and ports to bind to.
3362 + Defaults to HSPECS_DEFAULT == {ipv4:127.0.0.1:8118, ipv6:[::1]:8118}. */
3363 + struct bind_spec *hspecs;
3364 + /* size allocated */
3365 + unsigned int hspecs_size;
3366 + /* number of entries */
3367 + unsigned int hspecs_occupied;
3369 /** Size limit for IOB */
3370 size_t buffer_limit;
3371 diff -urNad privoxy~/urlmatch.c privoxy/urlmatch.c
3372 --- privoxy~/urlmatch.c
3373 +++ privoxy/urlmatch.c
3376 #include "miscutil.h"
3378 +#include "parsers.h"
3380 const char urlmatch_h_rcs[] = URLMATCH_H_VERSION;
3386 - freez(http->host);
3387 + freez(http->host_port_malloc);
3389 freez(http->hostport);
3398 buf = strdup(http->hostport);
3400 @@ -311,38 +310,34 @@
3401 return JB_ERR_MEMORY;
3404 + http->host_port_malloc = buf;
3406 /* check if url contains username and/or password */
3407 - host = strchr(buf, '@');
3409 + buf = strchr(buf, '@');
3412 /* Contains username/password, skip it and the @ sign. */
3418 /* No username or password. */
3420 + buf = http->host_port_malloc;
3423 - /* check if url contains port */
3424 - port = strchr(host, ':');
3426 + parse_ip(buf,&http->host,&http->port_str);
3428 + if (*http->port_str != '\0')
3430 - /* Contains port */
3431 - /* Terminate hostname and point to start of port string */
3433 - http->port = atoi(port);
3434 + http->port = atoi(http->port_str);
3438 /* No port specified. */
3439 - http->port = (http->ssl ? 443 : 80);
3440 + http->port_str = (http->ssl ? "143" : "80");
3441 + http->port = (http->ssl ? 443 : 80);
3444 - http->host = strdup(host);
3448 if (http->host == NULL)
3450 return JB_ERR_MEMORY;
3452 * written to system log)
3454 *********************************************************************/
3455 -jb_err create_url_spec(struct url_spec * url, const char * buf)
3456 +jb_err create_url_spec(struct url_spec * url, char * buf)
3462 @@ -685,22 +679,25 @@
3464 return JB_ERR_MEMORY;
3467 - if ((p = strchr(buf, '/')) != NULL)
3469 - if (NULL == (url->path = strdup(p)))
3472 + if ((p = strchr(buf, '/')) != NULL)
3475 - return JB_ERR_MEMORY;
3476 + if (NULL == (url->path = strdup(p)))
3479 + return JB_ERR_MEMORY;
3481 + url->pathlen = strlen(url->path);
3484 - url->pathlen = strlen(url->path);
3501 @@ -739,15 +736,12 @@
3502 return JB_ERR_PARSE;
3505 - if ((p = strchr(buf, ':')) == NULL)
3513 - url->port = atoi(p);
3516 + parse_ip(buf,&buf,&p);
3517 + url->port = atoi(p);
3522 @@ -779,12 +773,13 @@
3523 return JB_ERR_MEMORY;
3527 - * Map to lower case
3529 - for (p = url->dbuffer; *p ; p++)
3531 - *p = tolower((int)(unsigned char)*p);
3533 + /* map to lower case */
3534 + for (p = url->dbuffer; *p ; p++)
3536 + *p = tolower((int)(unsigned char)*p);
3541 diff -urNad privoxy~/urlmatch.h privoxy/urlmatch.h
3542 --- privoxy~/urlmatch.h
3543 +++ privoxy/urlmatch.h
3545 extern int url_match(const struct url_spec *pattern,
3546 const struct http_request *url);
3548 -extern jb_err create_url_spec(struct url_spec * url, const char * buf);
3549 +extern jb_err create_url_spec(struct url_spec * url, char * buf);
3550 extern void free_url_spec(struct url_spec *url);