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 :)
10 ## DP: adapted to 3.0.6 by Petr Písa?? petrp@users.sf.net found on
11 ## DP: http://xpisar.wz.cz/privoxy-ipv6/ Use privoxy-3.0.6-stable-ipv6.diff.bz2
15 diff -urNad privoxy~/GNUmakefile.in privoxy/GNUmakefile.in
16 --- privoxy~/GNUmakefile.in
17 +++ privoxy/GNUmakefile.in
19 C_SRC = actions.c cgi.c cgiedit.c cgisimple.c deanimate.c encode.c \
20 errlog.c filters.c gateway.c jbsockets.c jcc.c killpopup.c \
21 list.c loadcfg.c loaders.c miscutil.c parsers.c ssplit.c \
23 + urlmatch.c addrlist.c jb_socket_set.c
25 C_OBJS = $(C_SRC:.c=.@OBJEXT@)
26 C_HDRS = $(C_SRC:.c=.h) project.h actionlist.h
28 SPECIAL_CFLAGS = @SPECIAL_CFLAGS@
32 +OTHER_CFLAGS = -DINET6
34 CFLAGS = @CFLAGS@ @CPPFLAGS@ $(OTHER_CFLAGS) $(SPECIAL_CFLAGS) -Wall \
35 @STATIC_PCRE_ONLY@ -Ipcre
36 diff -urNad privoxy~/addrlist.c privoxy/addrlist.c
37 --- privoxy~/addrlist.c
38 +++ privoxy/addrlist.c
40 +const char addrlist_rcs[] = "$Id: $";
41 +/*********************************************************************
45 + * Purpose : Declares functions to handle lists of network addresses.
46 + * Functions declared include:
47 + * `destroy_addr_list', head_addr_list and `tail_addr_list'
49 + * Copyright : Written by and Copyright (C) 2002 Lionel Elie Mamane
50 + * <lionel@mamane.lu>
52 + * This program is free software; you can redistribute it
53 + * and/or modify it under the terms of the GNU General
54 + * Public License as published by the Free Software
55 + * Foundation; either version 2 of the License, or (at
56 + * your option) any later version.
58 + * This program is distributed in the hope that it will
59 + * be useful, but WITHOUT ANY WARRANTY; without even the
60 + * implied warranty of MERCHANTABILITY or FITNESS FOR A
61 + * PARTICULAR PURPOSE. See the GNU General Public
62 + * License for more details.
64 + * The GNU General Public License should be included with
65 + * this file. If not, you can view it at
66 + * http://www.gnu.org/copyleft/gpl.html
67 + * or write to the Free Software Foundation, Inc., 59
68 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
71 + * $Log: addrlist.c,v $
73 + *********************************************************************/
75 +#include "addrlist.h"
76 +#include <sys/types.h>
77 +#include <sys/socket.h>
81 +/*********************************************************************
83 + * Function : acceptable
85 + * Description : Test wheter an address is acceptable for our use
86 + * Currently, this means either an IPv4 or an IPv6 address
89 + * 0 : addr = the address to test
91 + * Returns : 0 = false / no
92 + * anything else = true / yes
94 + *********************************************************************/
95 +static int acceptable (struct sockaddr_storage *addr)
97 + switch(addr->ss_family)
109 +/*********************************************************************
113 + * Description : Get the first acceptable address in head position
114 + * Assumes there is one
117 + * 0 : l = the list to skim
119 + * Returns : the skimmed list
121 + *********************************************************************/
122 +static addr_list *skim (addr_list *l)
124 + if (acceptable((struct sockaddr_storage*)l->ai_addr))
126 + return skim(l->ai_next);
129 +/*********************************************************************
131 + * Function : tail_addr_list
133 + * Description : Get the tail of an address list
136 + * 0 : l = the list to get the tail of
138 + * Returns : the tail of the list
139 + * If the list has no tail (i.e. is nil), unspecified
142 + *********************************************************************/
143 +addr_list *tail_addr_list(addr_list *l)
145 + return skim(l)->ai_next;
148 +/*********************************************************************
150 + * Function : head_addr_list
152 + * Description : Get the head of an address list
155 + * 0 : l = the list to get the head of
157 + * Returns : the head of the list
158 + * If the list has no head (i.e. is nil), unspecified
161 + *********************************************************************/
162 +struct sockaddr_storage *head_addr_list(addr_list *l)
164 + return (struct sockaddr_storage *)skim(l)->ai_addr;
167 +/*********************************************************************
169 + * Function : cpy_head_addr_list
171 + * Description : Copy the head of an address list to the given destination
174 + * 0 : l = the list to get the head of
175 + * 1 : r = where to put the result
177 + * Returns : Nothing
178 + * If the list has no head (i.e. is nil), unspecified
181 + *********************************************************************/
182 +void cpy_head_addr_list(addr_list *l, struct sockaddr_storage *r, size_t *addrlen)
184 + addr_list *sl = skim(l);
185 + memcpy(r, sl->ai_addr, sl->ai_addrlen);
186 + *addrlen = sl->ai_addrlen;
189 +/*********************************************************************
191 + * Function : destroy_addr_list
193 + * Description : Unallocate memory allocated to an address list
196 + * 0 : l = the list to unallocate
198 + * Returns : nothing
200 + *********************************************************************/
201 +void destroy_addr_list(addr_list *l)
206 +/*********************************************************************
208 + * Function : is_nil_addr_list
210 + * Description : Test wheter a list is nil (empty)
213 + * 0 : l = the list to test
215 + * Returns : 0 = false if list has a head,
216 + * anything else = true if list is nil
218 + *********************************************************************/
219 +int is_nil_addr_list(addr_list *l)
221 + /* We are searching for a witness of non-nilness (modulo acceptability)
222 + * If none is found, the list is nil
227 + if (acceptable(head_addr_list(l)))
228 + /* Witness found */
230 + return is_nil_addr_list(l->ai_next);
238 diff -urNad privoxy~/addrlist.h privoxy/addrlist.h
239 --- privoxy~/addrlist.h
240 +++ privoxy/addrlist.h
242 +#ifndef ADDR_LIST_H_INCLUDED
243 +#define ADDR_LIST_H_INCLUDED
244 +#define ADDR_LIST_H_VERSION "$Id: $"
245 +/*********************************************************************
247 + * File : $Source: $
249 + * Purpose : Declares functions to handle lists of network addresses.
250 + * Functions declared include:
251 + * `destroy_addr_list', head_addr_list and `tail_addr_list'
253 + * Copyright : Written by and Copyright (C) 2002 Lionel Elie Mamane
254 + * <lionel@mamane.lu>
256 + * This program is free software; you can redistribute it
257 + * and/or modify it under the terms of the GNU General
258 + * Public License as published by the Free Software
259 + * Foundation; either version 2 of the License, or (at
260 + * your option) any later version.
262 + * This program is distributed in the hope that it will
263 + * be useful, but WITHOUT ANY WARRANTY; without even the
264 + * implied warranty of MERCHANTABILITY or FITNESS FOR A
265 + * PARTICULAR PURPOSE. See the GNU General Public
266 + * License for more details.
268 + * The GNU General Public License should be included with
269 + * this file. If not, you can view it at
270 + * http://www.gnu.org/copyleft/gpl.html
271 + * or write to the Free Software Foundation, Inc., 59
272 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
275 + * $Log: addrlist.h,v $
277 + *********************************************************************/
279 +#include <sys/socket.h>
281 +typedef struct addrinfo addr_list;
283 +addr_list *tail_addr_list(addr_list *l);
284 +struct sockaddr_storage *head_addr_list(addr_list *l);
285 +void cpy_head_addr_list(addr_list *l, struct sockaddr_storage *r, size_t *addrlen);
286 +void destroy_addr_list(addr_list *l);
287 +int is_nil_addr_list(addr_list *l);
289 +#define freez_addr_list(X) { if(X) { destroy_addr_list(X); X = NULL ; } }
291 +#endif /* ndef LIST_H_INCLUDED */
298 diff -urNad privoxy~/cgi.c privoxy/cgi.c
302 * Copyright : Written by and Copyright (C) 2001 the SourceForge
303 * Privoxy team. http://www.privoxy.org/
305 + * Modified by Lionel Elie Mamane <lionel@mamane.lu>
306 + * for IPv6 support on 8 December 2002, 24 January 2003.
308 * Based on the Internet Junkbuster originally written
309 * by and Copyright (C) 1997 Anonymous Coders and
310 * Junkbusters Corporation. http://www.junkbusters.com
311 @@ -2259,7 +2262,6 @@
312 *********************************************************************/
313 struct map *default_exports(const struct client_state *csp, const char *caller)
317 struct map * exports;
318 int local_help_exists = 0;
319 @@ -2295,8 +2297,7 @@
320 if (!err) err = map_block_killer(exports, "can-toggle");
323 - snprintf(buf, 20, "%d", csp->config->hport);
324 - if (!err) err = map(exports, "my-port", 1, buf, 1);
325 + if (!err) err = map(exports, "my-port", 1, csp->my_port_str, 1);
327 if(!strcmp(CODE_STATUS, "stable"))
329 diff -urNad privoxy~/errlog.c privoxy/errlog.c
330 --- privoxy~/errlog.c
335 /* Non-standard: Print error code from errno */
337 + * This is not only not standard, but clashes
338 + * with the E modifier on the GNU (and possibly
339 + * other systems): It means double (floating point)
340 + * number in exponential notation, with capital E
341 + * for mantiss / exponenent separator
344 ival = WSAGetLastError();
345 sval = w32_socket_strerr(ival, tempbuf);
346 diff -urNad privoxy~/filters.c privoxy/filters.c
347 --- privoxy~/filters.c
348 +++ privoxy/filters.c
350 * Copyright : Written by and Copyright (C) 2001, 2004 the SourceForge
351 * Privoxy team. http://www.privoxy.org/
353 + * Modified by Lionel Elie Mamane <lionel@mamane.lu>
354 + * for IPv6 support on 8 December 2002, 24 January 2003.
356 * Based on the Internet Junkbuster originally written
357 * by and Copyright (C) 1997 Anonymous Coders and
358 * Junkbusters Corporation. http://www.junkbusters.com
369 @@ -505,17 +511,119 @@
371 const char filters_h_rcs[] = FILTERS_H_VERSION;
373 -/* Fix a problem with Solaris. There should be no effect on other
375 - * Solaris's isspace() is a macro which uses it's argument directly
376 - * as an array index. Therefore we need to make sure that high-bit
377 - * characters generate +ve values, and ideally we also want to make
378 - * the argument match the declared parameter type of "int".
380 -#define ijb_isdigit(__X) isdigit((int)(unsigned char)(__X))
382 +/*********************************************************************
384 + * Function : addr_equal_under_mask
386 + * Description : Are these addresses equal modulo this mask?
387 + * Assumes the second argument is already in
391 + * 0 : addr1 = First address to compare
392 + * 1 : addr2 = Second address to compare
393 + * MUST be in mask-normal form
394 + * 2 : mask = for IPv4 addresses, a bitmask
395 + * for IPv6 addresses, a prefixlen in bits
397 + * Returns : 0 = FALSE (not equal) and non-zero = TRUE (equal)
399 + *********************************************************************/
402 +addr_equal_under_mask(struct sockaddr_storage *addr1, struct sockaddr_storage *addr2, unsigned long mask)
407 + /* only identical families can be compared */
408 + /* TODO: Should we code the special case of "IPv4 addresses as IPv6 addresses"? */
409 + if (addr1->ss_family != addr2-> ss_family)
411 + /*fprintf(stderr, "equal_under_mask: diff sa_family: %d %d\n",
412 + sa1->sa_family, sa2-> sa_family); */
416 + switch (addr1->ss_family)
420 + /* IPv4 - mask is a bitmask */
421 + struct sockaddr_in *sin1 = (struct sockaddr_in *)addr1;
422 + struct sockaddr_in *sin2 = (struct sockaddr_in *)addr2;
424 + /*fprintf(stderr, "AF_INET: %08x %08x %08x\n",
425 + sin1->sin_addr.s_addr,
426 + sin2->sin_addr.s_addr,
428 + return (sin1->sin_addr.s_addr & mask) == sin2->sin_addr.s_addr;
434 + /* IPv6 - mask is a prefixlength in bits. */
435 + struct sockaddr_in6 *sin1 = (struct sockaddr_in6 *)addr1;
436 + struct sockaddr_in6 *sin2 = (struct sockaddr_in6 *)addr2;
439 + const int maskbytes = mask / 8;
440 + static char m[] = { 0x00, 0x80, 0xC0, 0xE0,
441 + 0xF0, 0xF8, 0xFC, 0xFE };
444 +/* fprintf(stderr, "PF_INET6: "); */
445 +/* for (i = 0; i < 16; i++) { */
446 +/* fprintf(stderr, "%02x ", sin1->sin6_addr.s6_addr[i]); */
448 +/* fprintf(stderr, " "); */
449 +/* for (i = 0; i < 16; i++) { */
450 +/* fprintf(stderr, "%02x ", sin2->sin6_addr.s6_addr[i]); */
452 +/* fprintf(stderr, "mask %d scopeids %x %x\n", mask, sin1->sin6_scope_id, sin2->sin6_scope_id); */
454 + /* should we compare scope ids and such too? */
456 + * LEM: I see no reason for this comparison
457 + * Quite the contrary: A client coming to us with
458 + * a small-scope address should be able to a bigger-scope
461 +/* if (sin1->sin6_scope_id != sin2->sin6_scope_id) */
466 + log_error(LOG_LEVEL_ERROR, "%s%d", "Tried to compare IPv6 addresses with invalid prefixlen: ", mask);
470 + a1 = sin1->sin6_addr.s6_addr;
471 + a2 = sin2->sin6_addr.s6_addr;
473 + if (memcmp(a1, a2, maskbytes) != 0)
477 + /* This special case is necessary for when mask==128
478 + else, we would go over the array size in a1/a2
485 + return (a1[maskbytes] & bitmask) == a2[maskbytes];
495 /*********************************************************************
497 * Function : block_acl
499 /* search the list */
502 - if ((csp->ip_addr_long & acl->src->mask) == acl->src->addr)
503 + if (addr_equal_under_mask(&csp->ip_addr_addr, &acl->src->addr, acl->src->mask))
511 - else if ( ((dst->addr & acl->dst->mask) == acl->dst->addr)
512 - && ((dst->port == acl->dst->port) || (acl->dst->port == 0)))
513 + else if ( addr_equal_under_mask(&dst->addr, &acl->dst->addr, acl->dst->mask)
514 + && ((dst->port == acl->dst->port) || (acl->dst->port == 0)))
516 if (acl->action == ACL_PERMIT)
518 @@ -575,81 +683,249 @@
523 /*********************************************************************
525 - * Function : acl_addr
526 + * Function : fill_acl_addr_mask
528 - * Description : Called from `load_config' to parse an ACL address.
529 + * Description : Fill in the mask-related members of a
530 + * struct access_control_addr
533 - * 1 : aspec = String specifying ACL address.
534 - * 2 : aca = struct access_control_addr to fill in.
535 + * 0 : aca = struct access_control_addr to fill in.
536 + * 1 : masklength = mask length.
538 - * Returns : 0 => Ok, everything else is an error.
539 + * Returns : nothing
541 *********************************************************************/
542 -int acl_addr(char *aspec, struct access_control_addr *aca)
543 +void fill_acl_addr_mask(struct access_control_addr *aca, int masklength)
545 - int i, masklength, port;
551 + pf = aca->addr.ss_family;
553 - if ((p = strchr(aspec, '/')) != NULL)
558 - if (ijb_isdigit(*p) == 0)
560 + /* build the netmask */
561 + if (masklength == -1)
564 + for(pf=1; pf <= masklength ; ++pf)
567 + aca->mask |= (1 << (32 - pf));
569 - masklength = atoi(p);
571 + aca->mask = htonl(aca->mask);
573 + /* now mask off the host portion of the ip address
574 + * (i.e. save on the network portion of the address).
576 + ((struct sockaddr_in*) &aca->addr)->sin_addr.s_addr &= aca->mask;
577 + aca->port = ((struct sockaddr_in*) &aca->addr)->sin_port;
582 + static char m[] = { 0x00, 0x80, 0xC0, 0xE0,
583 + 0xF0, 0xF8, 0xFC, 0xFE };
585 + struct sockaddr_in6 *sa6 = (struct sockaddr_in6*)&aca->addr;
587 - if ((masklength < 0) || (masklength > 32))
590 + aca->mask = (masklength == -1) ? masklength : 128 ;
591 + /* now mask off the host portion of the ip address
592 + * (i.e. save on the network portion of the address).
597 + sa6->sin6_addr.s6_addr[i] &= m[aca->mask % 8];
598 + /* The following loop is not strictly necessary,
599 + because of the way addr_equal_under_mask is
600 + written. Better safe than sorry, though:
601 + New code might make the full mask-normal
604 + for(++i; i < 16 ; ++i)
605 + sa6->sin6_addr.s6_addr[i] = 0;
607 + aca -> port = sa6->sin6_port;
612 + /* FATAL because access_control_addr's are created only with adresses
613 + deemed 'acceptable' by the addr_list stuff, thus currently IPv4 and
616 + log_error(LOG_LEVEL_FATAL,"%s%d","Unknown address family in ACL address: ",pf);
620 - if ((p = strchr(aspec, ':')) != NULL)
623 +/*********************************************************************
625 + * Function : acl_addrs
627 + * Description : Parse an ACL address (adress + mask prefix)
628 + * Resolve the parsed address
629 + * Describe errors in *proxy_args.
632 + * 0 : aspec = the string containing the ACL address/mask
633 + * 1 : masklength = pointer used to return the mask
634 + * 2 : proxy_args = Pointer to string to append description of errors to.
635 + * 3 : type = type of ACL adress (source / destination).
636 + * Used for error reporting.
638 + * Returns : the list of adresses the ACL address resolves to
640 + *********************************************************************/
641 +static addr_list *acl_addrs(char *aspec, int *masklength, char**proxy_args, const char *type)
647 - if (ijb_isdigit(*p) == 0)
653 + if (parse_pf_ip_netmask(aspec, &host, &port, &pf, masklength) != 0)
655 + log_error(LOG_LEVEL_ERROR, "Invalid %s IP for (deny|permit)-access "
656 + "directive in configuration file: \"%s\"", type, aspec);
657 + string_append(proxy_args,"<br>\nWARNING: Invalid ");
658 + string_append(proxy_args, type);
659 + string_append(proxy_args," IP for (deny|permit)-access directive"
660 + " in configuration file: \"");
661 + string_append(proxy_args, aspec);
662 + string_append(proxy_args,"\"<br><br>\n");
667 + return resolve_hostname_to_ip(host, port, pf);
670 - aca->addr = ntohl(resolve_hostname_to_ip(aspec));
671 +/*********************************************************************
673 + * Function : add_one_to_acl_list
675 + * Description : Add one entry to an access_control_list.
678 + * 0 : l = the list to add to
679 + * 1 : action = ACL_DENY or ACL_PERMIT
680 + * 2 : src_addrs = the head of this list will be used as source
681 + * in the ACL entry.
682 + * 3 : dst_addrs = the head of this list will be used as destination
683 + * in the ACL entry.
685 + * 4 : src_masklength = mask length for the source
686 + * 5 : src_masklength = mask length for the destination
688 + * Returns : the new list
690 + *********************************************************************/
691 +struct access_control_list *add_one_to_acl_list(struct access_control_list *l, short action,
692 + addr_list *src_addrs, addr_list *dst_addrs,
693 + int src_masklength, int dst_masklength)
695 + struct access_control_list *cur_acl;
696 + /* allocate a new node */
697 + cur_acl = (struct access_control_list *) zalloc(sizeof(*cur_acl));
699 - if (aca->addr == INADDR_NONE)
700 + if (cur_acl == NULL)
703 + log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
704 + /* Never get here - LOG_LEVEL_FATAL causes program exit */
708 - /* build the netmask */
710 - for (i=1; i <= masklength ; i++)
711 + cur_acl->action = action;
713 + cpy_head_addr_list(src_addrs, &cur_acl->src->addr, &cur_acl->src->addrlen);
714 + fill_acl_addr_mask(cur_acl->src, src_masklength);
715 + if (dst_addrs != NULL)
717 - aca->mask |= (1 << (32 - i));
718 + cpy_head_addr_list(dst_addrs, &cur_acl->dst->addr, &cur_acl->dst->addrlen);
719 + fill_acl_addr_mask(cur_acl->src, src_masklength);
722 - /* now mask off the host portion of the ip address
723 - * (i.e. save on the network portion of the address).
725 + * Add it to the list. Note we reverse the list to get the
726 + * behaviour the user expects. With both the ACL and
727 + * actions file, the last match wins. However, the internal
728 + * implementations are different: The actions file is stored
729 + * in the same order as the file, and scanned completely.
730 + * With the ACL, we reverse the order as we load it, then
731 + * when we scan it we stop as soon as we get a match.
733 - aca->addr = aca->addr & aca->mask;
740 +/*********************************************************************
742 + * Function : add_to_acl_list
744 + * Description : Add entries to an access_control_list.
745 + * Describe errors in *proxy_args.
748 + * 0 : l = the list to add to
749 + * 1 : action = ACL_DENY or ACL_PERMIT
750 + * 2 : src_spec = String giving the source of the acl entry
751 + * 3 : dst_spec = String giving the destination of the acl entry,
753 + * 4 : proxy_args = Pointer to string to append description of errors to.
755 + * Returns : the new list
757 + *********************************************************************/
758 +struct access_control_list *add_to_acl_list(struct access_control_list *l,
764 + int src_masklength, dst_masklength;
765 + addr_list *src_addrs, *dst_addrs;
766 + addr_list *src_addrs_remaining, *dst_addrs_remaining;
768 + src_addrs = acl_addrs(src_spec, &src_masklength, proxy_args, "source");
769 + if (is_nil_addr_list(src_addrs))
771 + log_error(LOG_LEVEL_ERROR, "Source of ACL resolves to no address",dst_spec);
774 + if (dst_spec != NULL)
776 + dst_addrs = acl_addrs(dst_spec, &dst_masklength, proxy_args, "destination");
777 + if (is_nil_addr_list(dst_addrs))
779 + log_error(LOG_LEVEL_ERROR, "Destination of ACL resolves to no address",dst_spec);
780 + destroy_addr_list(src_addrs);
787 + for(src_addrs_remaining = src_addrs;
788 + is_nil_addr_list(src_addrs);
789 + src_addrs_remaining=tail_addr_list(src_addrs_remaining))
791 + if (dst_addrs == NULL)
792 + l = add_one_to_acl_list(l, action, src_addrs_remaining, NULL, src_masklength,0);
793 + else for(dst_addrs_remaining = dst_addrs;
794 + is_nil_addr_list(dst_addrs);
795 + dst_addrs_remaining=tail_addr_list(dst_addrs_remaining))
796 + l = add_one_to_acl_list(l, action, src_addrs_remaining, dst_addrs_remaining,
797 + src_masklength, dst_masklength);
799 + destroy_addr_list(src_addrs);
800 + destroy_addr_list(dst_addrs);
804 -#endif /* def FEATURE_ACL */
806 +#endif /* def FEATURE_ACL */
808 /*********************************************************************
810 diff -urNad privoxy~/filters.h privoxy/filters.h
811 --- privoxy~/filters.h
812 +++ privoxy/filters.h
814 * Copyright : Written by and Copyright (C) 2001, 2004 the SourceForge
815 * Privoxy team. http://www.privoxy.org/
817 + * Modified by Lionel Elie Mamane <lionel@mamane.lu>
818 + * for IPv6 support on 8 December 2002, 24 January 2003.
820 * Based on the Internet Junkbuster originally written
821 * by and Copyright (C) 1997 Anonymous Coders and
822 * Junkbusters Corporation. http://www.junkbusters.com
826 extern int block_acl(struct access_control_addr *dst, struct client_state *csp);
827 -extern int acl_addr(char *aspec, struct access_control_addr *aca);
828 +extern struct access_control_list *add_to_acl_list(struct access_control_list *l,
832 + char **proxy_args);
833 #endif /* def FEATURE_ACL */
834 extern int match_portlist(const char *portlist, int port);
836 diff -urNad privoxy~/gateway.c privoxy/gateway.c
837 --- privoxy~/gateway.c
838 +++ privoxy/gateway.c
840 * Copyright : Written by and Copyright (C) 2001 the SourceForge
841 * Privoxy team. http://www.privoxy.org/
843 + * Modified by Lionel Elie Mamane <lionel@mamane.lu>
844 + * for IPv6 support on 8 December 2002, 24 January 2003.
846 * Based on the Internet Junkbuster originally written
847 * by and Copyright (C) 1997 Anonymous Coders and
848 * Junkbusters Corporation. http://www.junkbusters.com
849 @@ -203,12 +206,14 @@
850 * Returns : JB_INVALID_SOCKET => failure, else it is the socket file descriptor.
852 *********************************************************************/
853 -jb_socket forwarded_connect(const struct forward_spec * fwd,
854 +jb_socket forwarded_connect(const struct forward_spec *fwd,
855 struct http_request *http,
856 struct client_state *csp)
858 const char * dest_host;
860 + const char * dest_port_str;
861 + unsigned long dest_port;
864 /* Figure out if we need to connect to the web server or a HTTP proxy. */
865 if (fwd->forward_host)
866 @@ -216,19 +221,23 @@
868 dest_host = fwd->forward_host;
869 dest_port = fwd->forward_port;
870 + dest_port_str = fwd->forward_port_str;
871 + dest_pf = fwd->forward_family;
876 dest_host = http->host;
877 dest_port = http->port;
878 + dest_port_str = http->port_str;
879 + dest_pf = PF_UNSPEC;
882 /* Connect, maybe using a SOCKS proxy */
886 - return (connect_to(dest_host, dest_port, csp));
887 + return (connect_to(dest_host, dest_port_str, dest_port, dest_pf, csp));
891 @@ -262,74 +271,19 @@
892 * Returns : JB_INVALID_SOCKET => failure, else a socket file descriptor.
894 *********************************************************************/
895 -static jb_socket socks4_connect(const struct forward_spec * fwd,
896 - const char * target_host,
898 - struct client_state *csp)
899 +static jb_socket socks4_connect_one_ip(const struct forward_spec * fwd,
900 + unsigned long web_server_addr,
902 + struct client_state *csp,
906 - int web_server_addr;
907 - char cbuf[BUFFER_SIZE];
908 char sbuf[BUFFER_SIZE];
909 - struct socks_op *c = (struct socks_op *)cbuf;
910 struct socks_reply *s = (struct socks_reply *)sbuf;
913 + struct socks_reply *c = (struct socks_reply *)cbuf;
918 - if ((fwd->gateway_host == NULL) || (*fwd->gateway_host == '\0'))
920 - log_error(LOG_LEVEL_CONNECT, "socks4_connect: NULL gateway host specified");
924 - if (fwd->gateway_port <= 0)
926 - log_error(LOG_LEVEL_CONNECT, "socks4_connect: invalid gateway port specified");
933 - return(JB_INVALID_SOCKET);
936 - /* build a socks request for connection to the web server */
938 - strcpy((char *)&(c->userid), socks_userid);
940 - csiz = sizeof(*c) + sizeof(socks_userid) - 1;
945 - web_server_addr = htonl(resolve_hostname_to_ip(target_host));
946 - if (web_server_addr == INADDR_NONE)
948 - log_error(LOG_LEVEL_CONNECT, "socks4_connect: could not resolve target host %s", target_host);
949 - return(JB_INVALID_SOCKET);
953 - web_server_addr = 0x00000001;
954 - n = csiz + strlen(target_host) + 1;
955 - if (n > sizeof(cbuf))
958 - return(JB_INVALID_SOCKET);
960 - strcpy(cbuf + csiz, target_host);
964 - /* Should never get here */
965 - log_error(LOG_LEVEL_FATAL, "SOCKS4 impossible internal error - bad SOCKS type.");
967 - return(JB_INVALID_SOCKET);
972 c->dstport[0] = (target_port >> 8 ) & 0xff;
974 c->dstip[3] = (web_server_addr ) & 0xff;
976 /* pass the request to the socks server */
977 - sfd = connect_to(fwd->gateway_host, fwd->gateway_port, csp);
978 + sfd = connect_to(fwd->gateway_host, fwd->gateway_port_str, fwd->gateway_port, PF_INET ,csp);
980 if (sfd == JB_INVALID_SOCKET)
986 +static jb_socket socks4_connect(const struct forward_spec * fwd,
987 + const char * target_host,
989 + struct client_state *csp)
991 + char cbuf[BUFFER_SIZE];
992 + struct socks_op *c = (struct socks_op *)cbuf;
997 + * SOCKS4 is IPv4-specific. At least I think so.
999 + if ((fwd->gateway_host == NULL) || (*fwd->gateway_host == '\0'))
1001 + log_error(LOG_LEVEL_CONNECT, "socks4_connect: NULL gateway host specified");
1005 + if (fwd->gateway_port <= 0)
1007 + log_error(LOG_LEVEL_CONNECT, "socks4_connect: invalid gateway port specified");
1014 + return(JB_INVALID_SOCKET);
1017 + /* build a socks request for connection to the web server */
1019 + strcpy((char *)&(c->userid), socks_userid);
1021 + csiz = sizeof(*c) + sizeof(socks_userid) - 1;
1023 + switch (fwd->type)
1027 + addr_list *web_server_addrs = resolve_hostname_to_ip(target_host,NULL,PF_INET);
1028 + jb_socket return_value = JB_INVALID_SOCKET;
1029 + if (is_nil_addr_list(web_server_addrs))
1031 + log_error(LOG_LEVEL_CONNECT, "socks4_connect: could not resolve target host %s", target_host);
1035 + addr_list *addrs_to_try;
1037 + for(addrs_to_try = web_server_addrs;
1038 + !is_nil_addr_list(addrs_to_try);
1039 + addrs_to_try = tail_addr_list(addrs_to_try))
1041 + const unsigned long web_server_addr = ((struct sockaddr_in*) head_addr_list(addrs_to_try))->sin_addr.s_addr;
1042 + return_value=socks4_connect_one_ip(fwd, web_server_addr, target_port, csp, csiz, cbuf);
1043 + if(return_value != JB_INVALID_SOCKET)
1047 + destroy_addr_list(web_server_addrs);
1048 + return return_value;
1054 + n = csiz + strlen(target_host) + 1;
1055 + if (n > sizeof(cbuf))
1058 + return(JB_INVALID_SOCKET);
1060 + strcpy(cbuf + csiz, target_host);
1062 + return socks4_connect_one_ip(fwd, 0x00000001, target_port, csp, csiz, cbuf);
1066 + /* Should never get here */
1067 + log_error(LOG_LEVEL_FATAL, "SOCKS4 impossible internal error - bad SOCKS type.");
1069 + return(JB_INVALID_SOCKET);
1075 diff -urNad privoxy~/jb_socket_set.c privoxy/jb_socket_set.c
1076 --- privoxy~/jb_socket_set.c
1077 +++ privoxy/jb_socket_set.c
1079 +const char jb_socket_set_rcs[] = "$Id: $";
1080 +/*********************************************************************
1082 + * File : $Source: $
1084 + * Purpose : Declares functions to handle sets of sockets
1086 + * Copyright : Written by and Copyright (C) 2002 Lionel Elie Mamane
1087 + * <lionel@mamane.lu>
1089 + * This program is free software; you can redistribute it
1090 + * and/or modify it under the terms of the GNU General
1091 + * Public License as published by the Free Software
1092 + * Foundation; either version 2 of the License, or (at
1093 + * your option) any later version.
1095 + * This program is distributed in the hope that it will
1096 + * be useful, but WITHOUT ANY WARRANTY; without even the
1097 + * implied warranty of MERCHANTABILITY or FITNESS FOR A
1098 + * PARTICULAR PURPOSE. See the GNU General Public
1099 + * License for more details.
1101 + * The GNU General Public License should be included with
1102 + * this file. If not, you can view it at
1103 + * http://www.gnu.org/copyleft/gpl.html
1104 + * or write to the Free Software Foundation, Inc., 59
1105 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1108 + * $Log: jb_socket_set.c,v $
1110 + *********************************************************************/
1112 +#include "jb_socket_set.h"
1113 +#include <sys/time.h>
1114 +#include <sys/types.h>
1115 +#include <unistd.h>
1116 +#include "project.h"
1118 +/*********************************************************************
1120 + * Function : jb_socket_set_add
1122 + * Description : Add a socket to the set
1125 + * 0 : l = the set to add to
1126 + * 1 : the elemen to add to the set
1128 + * Returns : 0 on success
1129 + * non-0 on failure
1131 + *********************************************************************/
1133 +int jb_socket_set_add(jb_socket_set *l, jb_socket e)
1135 + if (l->data==NULL)
1138 + l->data=malloc(l->size * sizeof(jb_socket));
1139 + if (l->data==NULL)
1146 + l->data[(l->occupied)++] = e;
1147 + if (l->occupied == l->size)
1149 + jb_socket *new_data;
1151 + new_data = realloc(l->data,l->size * sizeof(jb_socket));
1152 + if (new_data == NULL)
1154 + /* Not enough memory to continue. Cancel changes. */
1155 + l->data[--(l->occupied)] = JB_INVALID_SOCKET;
1159 + l->data = new_data;
1161 + l->data[l->occupied] = JB_INVALID_SOCKET;
1165 +/*********************************************************************
1167 + * Function : destroy_jb_socket_set
1169 + * Description : Unallocate memory allocated to a socket set
1172 + * 0 : l = the set to unallocate
1174 + * Returns : nothing
1176 + *********************************************************************/
1177 +void destroy_jb_socket_set(jb_socket_set *l)
1180 + init_jb_socket_set(l);
1182 +/*********************************************************************
1184 + * Function : is_empty_jb_socket_set
1186 + * Description : Test wheter a set is empty
1189 + * 0 : l = the set to test
1191 + * Returns : 0 = false if set has a head,
1192 + * anything else = true if set is nil
1194 + *********************************************************************/
1195 +int is_nil_jb_socket_set(jb_socket_set *l)
1197 + return (l->occupied == 0);
1200 +/*********************************************************************
1202 + * Function : init_jb_socket_set
1204 + * Description : Init a set to empty
1207 + * 0 : l = the set to init
1209 + *********************************************************************/
1210 +void init_jb_socket_set(jb_socket_set *l)
1217 +/*********************************************************************
1219 + * Function : jb_socket_set_iteration_begin
1221 + * Description : Return an iterator on the set
1226 + *********************************************************************/
1227 +jb_socket_set_iterate_state jb_socket_set_iteration_begin(jb_socket_set *l)
1232 +/*********************************************************************
1234 + * Function : jb_socket_set_iteration_next
1236 + * Description : Return value pointed to by iterator and step
1237 + * iterator to next position
1240 + * 0 : s = the iterator
1242 + *********************************************************************/
1243 +jb_socket jb_socket_set_iteration_next(jb_socket_set_iterate_state*s)
1245 + return(*((*s)++));
1253 diff -urNad privoxy~/jb_socket_set.h privoxy/jb_socket_set.h
1254 --- privoxy~/jb_socket_set.h
1255 +++ privoxy/jb_socket_set.h
1257 +#ifndef JB_SOCKET_SET_H_INCLUDED
1258 +#define JB_SOCKET_SET_H_INCLUDED
1259 +#define JB_SOCKET_SET_H_VERSION "$Id: $"
1260 +/*********************************************************************
1262 + * File : $Source: $
1264 + * Purpose : Declares functions to handle sets of sockets
1266 + * Copyright : Written by and Copyright (C) 2002 Lionel Elie Mamane
1267 + * <lionel@mamane.lu>
1269 + * This program is free software; you can redistribute it
1270 + * and/or modify it under the terms of the GNU General
1271 + * Public License as published by the Free Software
1272 + * Foundation; either version 2 of the License, or (at
1273 + * your option) any later version.
1275 + * This program is distributed in the hope that it will
1276 + * be useful, but WITHOUT ANY WARRANTY; without even the
1277 + * implied warranty of MERCHANTABILITY or FITNESS FOR A
1278 + * PARTICULAR PURPOSE. See the GNU General Public
1279 + * License for more details.
1281 + * The GNU General Public License should be included with
1282 + * this file. If not, you can view it at
1283 + * http://www.gnu.org/copyleft/gpl.html
1284 + * or write to the Free Software Foundation, Inc., 59
1285 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1288 + * $Log: jb_socket_set.h,v $
1290 + *********************************************************************/
1291 +#include <sys/time.h>
1292 +#include <sys/types.h>
1293 +#include <unistd.h>
1294 +#include "project.h"
1296 +struct jb_socket_set_struct
1298 + unsigned int size; /* size allocated*/
1299 + unsigned int occupied; /* size occupied - 1 == index of final JB_INVALID_SOCKET
1300 + == number of sockets in the set */
1301 + jb_socket *data; /* Array containing the sockets, JB_INVALID_SOCKET-terminated */
1304 +typedef struct jb_socket_set_struct jb_socket_set;
1305 +typedef const jb_socket* jb_socket_set_iterate_state;
1307 +void init_jb_socket_set(jb_socket_set*);
1309 +jb_socket_set_iterate_state jb_socket_set_iteration_begin(jb_socket_set *);
1310 +jb_socket jb_socket_set_iteration_next(jb_socket_set_iterate_state*);
1312 +int jb_socket_set_add(jb_socket_set*, jb_socket);
1314 +void destroy_jb_socket_set(jb_socket_set *l);
1315 +int is_empty_jb_socket_set(jb_socket_set *l);
1317 +#define freez_jb_socket_set(X) { if(X) { destroy_jb_socket_set(X); X = NULL ; } }
1319 +int jb_select(jb_socket_set *readfds, jb_socket_set *writefds, jb_socket_set *exceptfds, struct timeval *timeout);
1321 +#endif /* ndef JB_SOCKET_SET_H_INCLUDED */
1328 diff -urNad privoxy~/jbsockets.c privoxy/jbsockets.c
1329 --- privoxy~/jbsockets.c
1330 +++ privoxy/jbsockets.c
1332 * Copyright : Written by and Copyright (C) 2001 the SourceForge
1333 * Privoxy team. http://www.privoxy.org/
1335 + * Modified by Lionel Elie Mamane <lionel@mamane.lu>
1336 + * for IPv6 support on 8-9 December 2002, 24 January 2003,
1337 + * 13 February 2003.
1339 * Based on the Internet Junkbuster originally written
1340 * by and Copyright (C) 1997 Anonymous Coders and
1341 * Junkbusters Corporation. http://www.junkbusters.com
1343 #include "jbsockets.h"
1344 #include "filters.h"
1346 +#include "addrlist.h"
1348 const char jbsockets_h_rcs[] = JBSOCKETS_H_VERSION;
1350 @@ -297,141 +302,194 @@
1351 * that this is allowed according to ACL.
1354 - * 1 : host = hostname to connect to
1355 - * 2 : portnum = port to connent on
1356 + * 0 : host = hostname to connect to
1357 + * 1 : port = port to connect on, as string
1358 + * 2 : portnum = port to connect on, as integer
1359 * 3 : csp = Current client state (buffers, headers, etc...)
1360 - * Not modified, only used for source IP and ACL.
1362 * Returns : JB_INVALID_SOCKET => failure, else it is the socket
1365 *********************************************************************/
1366 -jb_socket connect_to(const char *host, int portnum, struct client_state *csp)
1367 +jb_socket connect_to_one_ip(struct sockaddr_storage *addr, size_t addrlen, const char *host, unsigned long portnum, struct client_state *csp)
1369 - struct sockaddr_in inaddr;
1373 - struct timeval tv[1];
1374 -#if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA)
1376 -#endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) */
1379 - struct access_control_addr dst[1];
1380 -#endif /* def FEATURE_ACL */
1382 - memset((char *)&inaddr, 0, sizeof inaddr);
1384 - if ((addr = resolve_hostname_to_ip(host)) == INADDR_NONE)
1387 - csp->http->host_ip_addr_str = strdup("unknown");
1388 - return(JB_INVALID_SOCKET);
1390 + struct access_control_addr dst[1];
1391 + char hostname[NI_MAXHOST];
1392 + char port[NI_MAXSERV];
1393 + if (getnameinfo((struct sockaddr*)addr, addrlen, hostname, NI_MAXHOST,
1394 + port, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV) != 0)
1396 + log_error(LOG_LEVEL_ERROR, "connect: Could not get string address and port back from sockaddr because %E");
1397 + strncpy(hostname,"unknown",NI_MAXHOST);
1398 + strncpy(port,"unknown",NI_MAXSERV);
1402 - dst->addr = ntohl((unsigned long) addr);
1403 - dst->port = portnum;
1404 + csp->http->host_ip_addr_str = strdup(hostname);
1406 - if (block_acl(dst, csp))
1408 + dst->addr = *addr;
1409 + dst->addrlen = addrlen;
1410 + dst->port = portnum;
1412 + if (block_acl(dst, csp))
1421 - return(JB_INVALID_SOCKET);
1423 -#endif /* def FEATURE_ACL */
1424 + return(JB_INVALID_SOCKET);
1427 - inaddr.sin_addr.s_addr = addr;
1428 - inaddr.sin_family = AF_INET;
1429 - csp->http->host_ip_addr_str = strdup(inet_ntoa(inaddr.sin_addr));
1432 - if (sizeof(inaddr.sin_port) == sizeof(short))
1433 -#endif /* ndef _WIN32 */
1435 - inaddr.sin_port = htons((unsigned short) portnum);
1439 +#endif /* def FEATURE_ACL */
1442 - inaddr.sin_port = htonl((unsigned long)portnum);
1444 -#endif /* ndef _WIN32 */
1448 - if ((fd = socket(inaddr.sin_family, SOCK_STREAM, 0)) == JB_INVALID_SOCKET)
1449 + if ((fd = socket(addr->ss_family, SOCK_STREAM, 0)) == JB_INVALID_SOCKET)
1451 - if ((fd = socket(inaddr.sin_family, SOCK_STREAM, 0)) < 0)
1452 + if ((fd = socket(addr->ss_family, SOCK_STREAM, 6)) < 0)
1455 - return(JB_INVALID_SOCKET);
1458 + return(JB_INVALID_SOCKET);
1462 - { /* turn off TCP coalescence */
1464 - setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &mi, sizeof (int));
1466 + { /* turn off TCP coalescence */
1468 + setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, (char *) &mi, sizeof (int));
1470 #endif /* def TCP_NODELAY */
1472 #if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__)
1473 - if ((flags = fcntl(fd, F_GETFL, 0)) != -1)
1475 - flags |= O_NDELAY;
1476 - fcntl(fd, F_SETFL, flags);
1481 + if ((flags = fcntl(fd, F_GETFL, 0)) != -1)
1483 + flags |= O_NDELAY;
1484 + fcntl(fd, F_SETFL, flags);
1487 #endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) */
1489 - while (connect(fd, (struct sockaddr *) & inaddr, sizeof inaddr) == JB_INVALID_SOCKET)
1491 + while (connect(fd, (struct sockaddr *) addr, addrlen) == JB_INVALID_SOCKET)
1494 - if (errno == WSAEINPROGRESS)
1495 + if (errno == WSAEINPROGRESS)
1497 - if (sock_errno() == EINPROGRESS)
1498 + if (sock_errno() == EINPROGRESS)
1499 #else /* ifndef _WIN32 */
1500 - if (errno == EINPROGRESS)
1501 + if (errno == EINPROGRESS)
1502 #endif /* ndef _WIN32 || __OS2__ */
1511 - if (sock_errno() != EINTR)
1512 + if (sock_errno() != EINTR)
1514 - if (errno != EINTR)
1515 + if (errno != EINTR)
1516 #endif /* __OS2__ */
1519 + return(JB_INVALID_SOCKET);
1523 +#if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__)
1526 - return(JB_INVALID_SOCKET);
1528 + if ((flags = fcntl(fd, F_GETFL, 0)) != -1)
1530 + flags &= ~O_NDELAY;
1531 + fcntl(fd, F_SETFL, flags);
1535 +#endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) */
1539 + struct timeval tv[1];
1541 + /* wait for connection to complete */
1543 + FD_SET(fd, &wfds);
1548 + /* MS Windows uses int, not SOCKET, for the 1st arg of select(). Wierd! */
1549 + if (select((int)fd + 1, NULL, &wfds, NULL, tv) <= 0)
1552 + return(JB_INVALID_SOCKET);
1554 #if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__)
1557 - flags &= ~O_NDELAY;
1558 - fcntl(fd, F_SETFL, flags);
1562 + int connect_result;
1563 + socklen_t connect_result_len = sizeof connect_result;
1565 + if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &connect_result, &connect_result_len) != 0)
1567 + log_error(LOG_LEVEL_ERROR, "Could not determine whether connection to %s port %d was successful because %E. Assuming failure.",
1568 + csp->http->host_ip_addr_str, portnum);
1570 + return(JB_INVALID_SOCKET);
1572 + else if( connect_result != 0 )
1574 + log_error(LOG_LEVEL_CONNECT, "Connection to %s port %d failed because %s.",
1575 + csp->http->host_ip_addr_str, portnum, strerror(connect_result));
1577 + return(JB_INVALID_SOCKET);
1580 #endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) */
1586 - /* wait for connection to complete */
1588 - FD_SET(fd, &wfds);
1589 +jb_socket connect_to(const char *host, const char *port, unsigned long portnum, int pf, struct client_state *csp)
1591 + jb_socket fd = JB_INVALID_SOCKET;
1592 + struct sockaddr_storage addr;
1593 + addr_list *addrs, *addrs_to_try;
1597 + addrs = resolve_hostname_to_ip(host,port,pf);
1599 - /* MS Windows uses int, not SOCKET, for the 1st arg of select(). Wierd! */
1600 - if (select((int)fd + 1, NULL, &wfds, NULL, tv) <= 0)
1601 + if (is_nil_addr_list(addrs))
1604 - return(JB_INVALID_SOCKET);
1609 + for(addrs_to_try=addrs;
1610 + !is_nil_addr_list(addrs_to_try);
1611 + addrs_to_try = tail_addr_list(addrs_to_try))
1614 + memset((char *)&addr, 0, sizeof addr);
1615 + cpy_head_addr_list(addrs_to_try, &addr,&addrlen);
1616 + fd = connect_to_one_ip(&addr, addrlen, host, portnum, csp);
1617 + if (fd != JB_INVALID_SOCKET)
1622 + if (fd == JB_INVALID_SOCKET)
1624 + csp->http->host_ip_addr_str = strdup("unknown");
1627 + destroy_addr_list(addrs);
1632 @@ -571,55 +629,30 @@
1634 /*********************************************************************
1636 - * Function : bind_port
1637 + * Function : bind_port_one_ip
1639 * Description : Call socket, set socket options, and listen.
1640 - * Called by listen_loop to "boot up" our proxy address.
1643 - * 1 : hostnam = TCP/IP address to bind/listen to
1644 - * 2 : portnum = port to listen on
1645 - * 3 : pfd = pointer used to return file descriptor.
1646 + * 0 : addr = TCP/IP address and port to bind/listen to
1647 + * 1 : fds = jb_socket_set where the new socket should go
1649 - * Returns : if success, returns 0 and sets *pfd.
1650 + * Returns : if success returns 0 and adds sockets to fds.
1651 * if failure, returns -3 if address is in use,
1652 - * -2 if address unresolvable,
1653 + * -2 if memory error
1655 *********************************************************************/
1656 -int bind_port(const char *hostnam, int portnum, jb_socket *pfd)
1657 +int bind_port_one_ip(struct sockaddr *addr, const socklen_t addr_len, jb_socket_set *fds)
1659 - struct sockaddr_in inaddr;
1664 #endif /* ndef _WIN32 */
1666 - *pfd = JB_INVALID_SOCKET;
1668 - memset((char *)&inaddr, '\0', sizeof inaddr);
1670 - inaddr.sin_family = AF_INET;
1671 - inaddr.sin_addr.s_addr = resolve_hostname_to_ip(hostnam);
1673 - if (inaddr.sin_addr.s_addr == INADDR_NONE)
1679 - if (sizeof(inaddr.sin_port) == sizeof(short))
1680 -#endif /* ndef _WIN32 */
1682 - inaddr.sin_port = htons((unsigned short) portnum);
1687 - inaddr.sin_port = htonl((unsigned long) portnum);
1689 -#endif /* ndef _WIN32 */
1690 + fd = JB_INVALID_SOCKET;
1692 - fd = socket(AF_INET, SOCK_STREAM, 0);
1693 + fd = socket(addr->sa_family, SOCK_STREAM, 6);
1696 if (fd == JB_INVALID_SOCKET)
1697 @@ -645,8 +678,17 @@
1699 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one));
1700 #endif /* ndef _WIN32 */
1702 - if (bind(fd, (struct sockaddr *)&inaddr, sizeof(inaddr)) < 0)
1703 + /* As we are now listening on more than one socket,
1704 + * this is important: The only way to be sure accept
1707 + if ((flags = fcntl(fd, F_GETFL, 0)) != -1)
1709 + flags |= O_NONBLOCK;
1710 + fcntl(fd, F_SETFL, flags);
1713 + if (bind (fd, addr, addr_len) < 0)
1716 errno = WSAGetLastError();
1721 - while (listen(fd, 5) == -1)
1722 + while (listen(fd, 25) == -1)
1726 @@ -673,7 +715,11 @@
1731 + if (jb_socket_set_add(fds,fd) != 0)
1739 @@ -681,6 +727,91 @@
1741 /*********************************************************************
1743 + * Function : bind_port
1745 + * Description : Call bind_port_one_ip on all addresses host resolves to
1746 + * Called by listen_loop to "boot up" our proxy address.
1749 + * 0 : host = TCP/IP hostname to bind/listen to
1750 + * 1 : port = port to listen to, as string
1751 + * 2 : fds = socket set the sockets should be added to
1753 + * Returns : if success on at least one address resolving from hostnam,
1754 + * returns 0 and adds sockets to fds.
1755 + * if failure, returns non-zero
1756 + *********************************************************************/
1757 +int bind_port(const char *host, const char *port, int pf, jb_socket_set *fds)
1761 + struct sockaddr_storage addr;
1762 + struct sockaddr * const addr_addr = (struct sockaddr *)&addr;
1763 + addr_list *addrs, *addrs_to_try;
1765 + const char * const log_host = (host != NULL) ? host : "ADDR_ANY";
1767 + addrs = resolve_hostname_to_ip(host,port,pf);
1769 + if (is_nil_addr_list(addrs))
1770 + log_error(LOG_LEVEL_ERROR, "can't bind to %s:%s: "
1771 + "Name resolution didn't give any address",
1774 + log_error(LOG_LEVEL_INFO, "Binding to %s:%s...", log_host, port);
1776 + for(addrs_to_try=addrs;
1777 + !is_nil_addr_list(addrs_to_try);
1778 + addrs_to_try = tail_addr_list(addrs_to_try))
1780 + char numeric_hostname[NI_MAXHOST];
1781 + char numeric_port[NI_MAXSERV];
1783 + memset((char *)addr_addr, 0, sizeof addr);
1784 + cpy_head_addr_list(addrs_to_try, &addr, &addrlen);
1785 + result = getnameinfo(addr_addr, addrlen, numeric_hostname, NI_MAXHOST,
1786 + numeric_port, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV);
1789 + log_error(LOG_LEVEL_ERROR, "bind: Could not get string address and port back from sockaddr because %E");
1790 + strncpy(numeric_hostname,"unknown",NI_MAXHOST);
1791 + strncpy(numeric_port,"unknown",NI_MAXSERV);
1793 + result = bind_port_one_ip(addr_addr, addrlen, fds);
1797 + log_error(LOG_LEVEL_INFO, "Successfully bound to %s:%s", numeric_hostname, numeric_port);
1804 + log_error(LOG_LEVEL_ERROR, "can't bind to %s:%s (%s:%s): "
1805 + "There may be another Privoxy or some other "
1806 + "proxy running on port %s",
1807 + log_host, port, numeric_hostname, numeric_port, numeric_port);
1810 + log_error(LOG_LEVEL_ERROR, "can't bind to %s:%s (%s:%s): "
1812 + log_host, port, numeric_hostname, numeric_port);
1815 + log_error(LOG_LEVEL_ERROR, "can't bind to %s:%s: because %E",
1816 + log_host, numeric_port);
1821 + destroy_addr_list(addrs);
1826 +/*********************************************************************
1828 * Function : accept_connection
1830 * Description : Accepts a connection on a socket. Socket must have
1832 *********************************************************************/
1833 int accept_connection(struct client_state * csp, jb_socket fd)
1835 - struct sockaddr_in client, server;
1836 - struct hostent *host = NULL;
1837 + struct sockaddr_storage client, server;
1839 #if defined(_WIN32) || defined(__OS2__) || defined(__APPLE_CC__) || defined(AMIGA)
1840 /* Wierdness - fix a warning. */
1841 @@ -706,15 +836,7 @@
1843 socklen_t c_length, s_length;
1845 -#if defined(HAVE_GETHOSTBYADDR_R_8_ARGS) || defined(HAVE_GETHOSTBYADDR_R_7_ARGS) || defined(HAVE_GETHOSTBYADDR_R_5_ARGS)
1846 - struct hostent result;
1847 -#if defined(HAVE_GETHOSTBYADDR_R_5_ARGS)
1848 - struct hostent_data hdata;
1850 - char hbuf[HOSTENT_BUFFER_SIZE];
1852 -#endif /* def HAVE_GETHOSTBYADDR_R_5_ARGS */
1853 -#endif /* def HAVE_GETHOSTBYADDR_R_(8|7|5)_ARGS */
1856 c_length = s_length = sizeof(client);
1858 @@ -734,6 +856,12 @@
1862 + /* If we inherited O_NONBLOCK from the listening fd, unset it */
1863 + if ((flags = fcntl(fd, F_GETFL, 0)) != -1)
1865 + flags &= ~O_NONBLOCK;
1866 + fcntl(fd, F_SETFL, flags);
1870 * Determine the IP-Adress that the client used to reach us
1871 @@ -741,49 +869,50 @@
1873 if (!getsockname(afd, (struct sockaddr *) &server, &s_length))
1875 - csp->my_ip_addr_str = strdup(inet_ntoa(server.sin_addr));
1876 -#if defined(HAVE_GETHOSTBYADDR_R_8_ARGS)
1877 - gethostbyaddr_r((const char *)&server.sin_addr,
1878 - sizeof(server.sin_addr), AF_INET,
1879 - &result, hbuf, HOSTENT_BUFFER_SIZE,
1881 -#elif defined(HAVE_GETHOSTBYADDR_R_7_ARGS)
1882 - host = gethostbyaddr_r((const char *)&server.sin_addr,
1883 - sizeof(server.sin_addr), AF_INET,
1884 - &result, hbuf, HOSTENT_BUFFER_SIZE, &thd_err);
1885 -#elif defined(HAVE_GETHOSTBYADDR_R_5_ARGS)
1886 - if (0 == gethostbyaddr_r((const char *)&server.sin_addr,
1887 - sizeof(server.sin_addr), AF_INET,
1889 + char hostname[NI_MAXHOST];
1890 + char port[NI_MAXSERV];
1892 + if (getnameinfo((struct sockaddr *)&server, s_length, hostname, NI_MAXHOST,
1893 + port, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV) != 0)
1896 + log_error(LOG_LEVEL_ERROR, "accept: Could not get string address and port back from server sockaddr because %E");
1897 + strncpy(hostname,"unknown IP",NI_MAXHOST);
1898 + strncpy(port,"unknown port",NI_MAXSERV);
1901 + csp->my_ip_addr_str = strdup(hostname);
1902 + csp->my_port_str = strdup(port);
1904 + if (getnameinfo((struct sockaddr *)&server, s_length, hostname, NI_MAXHOST, NULL, 0, NI_NAMEREQD) != 0)
1907 + log_error(LOG_LEVEL_ERROR, "accept: Could not get my own hostname because %E");
1908 + strncpy(hostname,"unknown host",NI_MAXHOST);
1910 -#elif FEATURE_PTHREAD
1911 - pthread_mutex_lock(&gethostbyaddr_mutex);
1912 - host = gethostbyaddr((const char *)&server.sin_addr,
1913 - sizeof(server.sin_addr), AF_INET);
1914 - pthread_mutex_unlock(&gethostbyaddr_mutex);
1916 - host = gethostbyaddr((const char *)&server.sin_addr,
1917 - sizeof(server.sin_addr), AF_INET);
1920 + csp->my_hostname = strdup(hostname);
1924 + log_error(LOG_LEVEL_ERROR, "accept: Could not get sockaddr from socket fd because %E");
1929 + char hostname[NI_MAXHOST];
1931 + if (getnameinfo((struct sockaddr *)&client, c_length, hostname, NI_MAXHOST, NULL, 0, NI_NUMERICHOST) != 0)
1933 - log_error(LOG_LEVEL_ERROR, "Unable to get my own hostname: %E\n");
1934 + log_error(LOG_LEVEL_ERROR, "accept: Could not get client IP address string because %E");
1935 + strncpy(hostname,"unknown IP",NI_MAXHOST);
1938 + csp->my_ip_addr_str = strdup(hostname);
1940 + if (getnameinfo((struct sockaddr *)&server, s_length, hostname, NI_MAXHOST, NULL, 0, 0) != 0)
1942 - csp->my_hostname = strdup(host->h_name);
1943 + log_error(LOG_LEVEL_ERROR, "accept: Could not get my own hostname because %E");
1944 + strncpy(hostname,"unknown host",NI_MAXHOST);
1946 + csp->ip_addr_str = strdup(hostname);
1950 - csp->ip_addr_str = strdup(inet_ntoa(client.sin_addr));
1951 - csp->ip_addr_long = ntohl(client.sin_addr.s_addr);
1952 + csp->ip_addr_addr = client;
1956 @@ -794,108 +923,48 @@
1958 * Function : resolve_hostname_to_ip
1960 - * Description : Resolve a hostname to an internet tcp/ip address.
1961 - * NULL or an empty string resolve to INADDR_ANY.
1962 + * Description : Resolve a hostname to a list of internet tcp/ip addresses.
1965 - * 1 : host = hostname to resolve
1966 + * 0 : host = hostname to resolve
1967 + * 1 : result = where to store the result
1968 + * 2 : pf = preferred address family. PF_UNSPEC for no preference (recommended).
1970 - * Returns : INADDR_NONE => failure, INADDR_ANY or tcp/ip address if succesful.
1971 + * Returns : A (possibly empty) list of adresses
1973 *********************************************************************/
1974 -unsigned long resolve_hostname_to_ip(const char *host)
1976 - struct sockaddr_in inaddr;
1977 - struct hostent *hostp;
1978 +addr_list *resolve_hostname_to_ip(const char *host, const char *port, int pf)
1981 + * Do all supported platforms have "getaddrinfo"?
1984 + struct addrinfo hints, *res0;
1986 unsigned int dns_retries = 0;
1987 -#if defined(HAVE_GETHOSTBYNAME_R_6_ARGS) || defined(HAVE_GETHOSTBYNAME_R_5_ARGS) || defined(HAVE_GETHOSTBYNAME_R_3_ARGS)
1988 - struct hostent result;
1989 -#if defined(HAVE_GETHOSTBYNAME_R_6_ARGS) || defined(HAVE_GETHOSTBYNAME_R_5_ARGS)
1990 - char hbuf[HOSTENT_BUFFER_SIZE];
1992 -#else /* defined(HAVE_GETHOSTBYNAME_R_3_ARGS) */
1993 - struct hostent_data hdata;
1994 -#endif /* def HAVE_GETHOSTBYNAME_R_(6|5)_ARGS */
1995 -#endif /* def HAVE_GETHOSTBYNAME_R_(6|5|3)_ARGS */
1997 - if ((host == NULL) || (*host == '\0'))
1999 - return(INADDR_ANY);
2002 - memset((char *) &inaddr, 0, sizeof inaddr);
2004 - if ((inaddr.sin_addr.s_addr = inet_addr(host)) == -1)
2006 -#if defined(HAVE_GETHOSTBYNAME_R_6_ARGS)
2007 - while ( gethostbyname_r(host, &result, hbuf,
2008 - HOSTENT_BUFFER_SIZE, &hostp, &thd_err)
2009 - && (thd_err == TRY_AGAIN) && (dns_retries++ < 10) )
2011 - log_error(LOG_LEVEL_ERROR, "Timeout #%u while trying to resolve %s. Trying again.",
2012 - dns_retries, host);
2014 -#elif defined(HAVE_GETHOSTBYNAME_R_5_ARGS)
2015 - hostp = gethostbyname_r(host, &result, hbuf,
2016 - HOSTENT_BUFFER_SIZE, &thd_err);
2017 -#elif defined(HAVE_GETHOSTBYNAME_R_3_ARGS)
2018 - if (0 == gethostbyname_r(host, &result, &hdata))
2026 -#elif FEATURE_PTHREAD
2027 - pthread_mutex_lock(&gethostbyname_mutex);
2028 - while ( NULL == (hostp = gethostbyname(host))
2029 - && (h_errno == TRY_AGAIN) && (dns_retries++ < 10) )
2031 - log_error(LOG_LEVEL_ERROR, "Timeout #%u while trying to resolve %s. Trying again.",
2032 - dns_retries, host);
2034 - pthread_mutex_unlock(&gethostbyname_mutex);
2036 - while ( NULL == (hostp = gethostbyname(host))
2037 - && (h_errno == TRY_AGAIN) && (dns_retries++ < 10) )
2039 - log_error(LOG_LEVEL_ERROR, "Timeout #%u while trying to resolve %s. Trying again.",
2040 - dns_retries, host);
2042 -#endif /* def HAVE_GETHOSTBYNAME_R_(6|5|3)_ARGS */
2044 - * On Mac OSX, if a domain exists but doesn't have a type A
2045 - * record associated with it, the h_addr member of the struct
2046 - * hostent returned by gethostbyname is NULL, even if h_length
2047 - * is 4. Therefore the second test below.
2049 - if (hostp == NULL || hostp->h_addr == NULL)
2052 - log_error(LOG_LEVEL_ERROR, "could not resolve hostname %s", host);
2053 - return(INADDR_NONE);
2055 - if (hostp->h_addrtype != AF_INET)
2058 - errno = WSAEPROTOTYPE;
2060 - errno = EPROTOTYPE;
2062 - log_error(LOG_LEVEL_ERROR, "hostname %s resolves to unknown address type.", host);
2063 - return(INADDR_NONE);
2066 - (char *) &inaddr.sin_addr,
2067 - (char *) hostp->h_addr,
2068 - sizeof(inaddr.sin_addr)
2070 + memset(&hints, 0, sizeof(hints));
2071 + hints.ai_family = pf;
2072 + hints.ai_socktype = SOCK_STREAM;
2074 + while ((result = getaddrinfo(host, port, &hints, &res0))
2075 + && (result == EAI_AGAIN) && (dns_retries++ < 10)) {
2076 + log_error(LOG_LEVEL_ERROR, "Timeout #%u while trying to resolve %s. Trying again.",
2077 + dns_retries, host);
2079 - return(inaddr.sin_addr.s_addr);
2083 + if ( result != 0 )
2085 + log_error(LOG_LEVEL_ERROR, "could not resolve hostname %s because %s", host,gai_strerror(result));
2086 + if (result == EAI_SYSTEM)
2087 + log_error(LOG_LEVEL_ERROR, "The system error is %E");
2092 + log_error(LOG_LEVEL_ERROR, "Problem in resolving hostname %s: succeeded, but no information returned", host);
2099 diff -urNad privoxy~/jbsockets.h privoxy/jbsockets.h
2100 --- privoxy~/jbsockets.h
2101 +++ privoxy/jbsockets.h
2103 * Copyright : Written by and Copyright (C) 2001 the SourceForge
2104 * Privoxy team. http://www.privoxy.org/
2106 + * Modified by Lionel Elie Mamane <lionel@mamane.lu>
2107 + * for IPv6 support on 8 December 2002, 24 January 2003.
2109 * Based on the Internet Junkbuster originally written
2110 * by and Copyright (C) 1997 Anonymous Coders and
2111 * Junkbusters Corporation. http://www.junkbusters.com
2112 @@ -104,9 +107,11 @@
2116 +#include "addrlist.h"
2118 struct client_state;
2120 -extern jb_socket connect_to(const char *host, int portnum, struct client_state *csp);
2121 +extern jb_socket connect_to(const char *host, const char *port, unsigned long portnum, int pf, struct client_state *csp);
2123 extern int write_socket(jb_socket fd, const char *buf, ssize_t n);
2125 @@ -115,10 +120,10 @@
2126 extern int read_socket(jb_socket fd, char *buf, int n);
2127 extern void close_socket(jb_socket fd);
2129 -extern int bind_port(const char *hostnam, int portnum, jb_socket *pfd);
2130 +extern int bind_port(const char *host, const char *port, int pf, jb_socket_set *fds);
2131 extern int accept_connection(struct client_state * csp, jb_socket fd);
2133 -extern unsigned long resolve_hostname_to_ip(const char *host);
2134 +extern addr_list *resolve_hostname_to_ip(const char *host, const char *port, int pf);
2136 /* Revision control strings from this header and associated .c file */
2137 extern const char jbsockets_rcs[];
2138 diff -urNad privoxy~/jcc.c privoxy/jcc.c
2143 #include "loadcfg.h"
2144 #include "urlmatch.h"
2145 +#include "jb_socket_set.h"
2147 const char jcc_h_rcs[] = JCC_H_VERSION;
2148 const char project_h_rcs[] = PROJECT_H_VERSION;
2149 @@ -2338,61 +2339,78 @@
2150 * Returns : Port that was opened.
2152 *********************************************************************/
2153 -static jb_socket bind_port_helper(struct configuration_spec * config)
2154 +static void bind_port_helper(struct configuration_spec * config, jb_socket_set *bfds)
2158 + struct bind_spec *bs;
2159 + unsigned int bs_index;
2162 - if ( (config->haddr != NULL)
2163 - && (config->haddr[0] == '1')
2164 - && (config->haddr[1] == '2')
2165 - && (config->haddr[2] == '7')
2166 - && (config->haddr[3] == '.') )
2168 - log_error(LOG_LEVEL_INFO, "Listening on port %d for local connections only",
2171 - else if (config->haddr == NULL)
2173 - log_error(LOG_LEVEL_INFO, "Listening on port %d on all IP addresses",
2178 + for (bs_index = 0; bs_index < config->hspecs_occupied;++bs_index)
2180 - log_error(LOG_LEVEL_INFO, "Listening on port %d on IP address %s",
2181 - config->hport, config->haddr);
2183 + bs = &config->hspecs[bs_index];
2185 + /* This check misses about a trillion zillion different manners to describe
2186 + the local interface in IPv6. Who cares? */
2187 + if ( (bs->haddr != NULL)
2188 + && (((bs->haddr[0] == '1')
2189 + && (bs->haddr[1] == '2')
2190 + && (bs->haddr[2] == '7')
2191 + && (bs->haddr[3] == '.'))
2192 + || ((bs->haddr[0] == ':')
2193 + && (bs->haddr[1] == ':')
2194 + && (bs->haddr[2] == '1'))))
2196 + log_error(LOG_LEVEL_INFO, "Listening on port %s for local connections only",
2199 + else if (bs->haddr == NULL || bs->haddr[0]=='\0')
2201 + log_error(LOG_LEVEL_INFO, "Listening on port %s on all IP addresses",
2206 + log_error(LOG_LEVEL_INFO, "Listening on port %s on IP address %s",
2207 + bs->hport, bs->haddr);
2210 - result = bind_port(config->haddr, config->hport, &bfd);
2211 + result = bind_port(bs->haddr, bs->hport, bs->pf, bfds);
2221 - log_error(LOG_LEVEL_FATAL, "can't bind to %s:%d: "
2222 + log_error(LOG_LEVEL_ERROR, "can't bind to %s:%s: "
2223 "There may be another Privoxy or some other "
2224 - "proxy running on port %d",
2225 - (NULL != config->haddr) ? config->haddr : "INADDR_ANY",
2226 - config->hport, config->hport);
2227 + "proxy running on port %s",
2228 + (NULL != bs->haddr) ? bs->haddr : "INADDR_ANY",
2229 + bs->hport, bs->hport);
2233 - log_error(LOG_LEVEL_FATAL, "can't bind to %s:%d: "
2234 + log_error(LOG_LEVEL_ERROR, "can't bind to %s:%s: "
2235 "The hostname is not resolvable",
2236 - (NULL != config->haddr) ? config->haddr : "INADDR_ANY", config->hport);
2237 + (NULL != bs->haddr) ? bs->haddr : "INADDR_ANY", bs->hport);
2241 - log_error(LOG_LEVEL_FATAL, "can't bind to %s:%d: because %E",
2242 - (NULL != config->haddr) ? config->haddr : "INADDR_ANY", config->hport);
2243 + log_error(LOG_LEVEL_ERROR, "can't bind to %s:%s: because %E",
2244 + (NULL != bs->haddr) ? bs->haddr : "INADDR_ANY", bs->hport);
2253 + log_error(LOG_LEVEL_FATAL, "Couldn't bind at all - bailing out");
2254 /* shouldn't get here */
2255 - return JB_INVALID_SOCKET;
2258 config->need_bind = 0;
2264 @@ -2421,12 +2439,18 @@
2265 static void listen_loop(void)
2267 struct client_state *csp = NULL;
2269 + jb_socket_set bfds;
2271 + jb_socket_set_iterate_state bfds_iterate_state;
2272 + jb_socket bfd_current;
2273 struct configuration_spec * config;
2275 + init_jb_socket_set(&bfds);
2277 config = load_config();
2279 - bfd = bind_port_helper(config);
2280 + bind_port_helper(config,&bfds);
2281 + bfd_current=JB_INVALID_SOCKET;
2283 #ifdef FEATURE_GRACEFUL_TERMINATION
2284 while (!g_terminate)
2285 @@ -2500,14 +2524,55 @@
2286 * that this will hurt people's feelings.
2289 - close_socket(bfd);
2290 + jb_socket_set_iterate_state s;
2292 + s=jb_socket_set_iteration_begin(&bfds);
2293 + for(bfd=jb_socket_set_iteration_next(&s);bfd!=JB_INVALID_SOCKET;bfd=jb_socket_set_iteration_next(&s))
2295 + close_socket(bfd);
2297 + destroy_jb_socket_set(&bfds);
2298 + bind_port_helper(config,&bfds);
2299 + /* We have a new set of fd's to accept. Restart iteration over bfds. */
2300 + bfd_current = JB_INVALID_SOCKET;
2303 - bfd = bind_port_helper(config);
2304 + /* Here: select call on listening sockets: bfd=sockets */
2305 + if (bfd_current == JB_INVALID_SOCKET)
2308 + log_error(LOG_LEVEL_CONNECT, "select connections ... ");
2309 + bfds_iterate_state=jb_socket_set_iteration_begin(&bfds);
2310 + FD_ZERO(&bfds_fs);
2312 + for(bfd_current=jb_socket_set_iteration_next(&bfds_iterate_state);
2313 + bfd_current!=JB_INVALID_SOCKET;
2314 + bfd_current=jb_socket_set_iteration_next(&bfds_iterate_state))
2316 + FD_SET(bfd_current,&bfds_fs);
2317 + if (bfd_current >= max)
2318 + max = bfd_current + 1;
2320 + if(!select(max,&bfds_fs,NULL,NULL,NULL))
2322 + log_error(LOG_LEVEL_CONNECT, "select failed: %E");
2323 + bfd_current=JB_INVALID_SOCKET;
2326 + log_error(LOG_LEVEL_CONNECT, "OK");
2327 + bfds_iterate_state=jb_socket_set_iteration_begin(&bfds);
2328 + bfd_current=jb_socket_set_iteration_next(&bfds_iterate_state);
2330 + if (!FD_ISSET(bfd_current,&bfds_fs))
2332 + bfd_current=jb_socket_set_iteration_next(&bfds_iterate_state);
2337 log_error(LOG_LEVEL_CONNECT, "accept connection ... ");
2339 - if (!accept_connection(csp, bfd))
2340 + if (!accept_connection(csp, bfd_current))
2342 log_error(LOG_LEVEL_CONNECT, "accept failed: %E");
2344 @@ -2525,6 +2590,8 @@
2345 log_error(LOG_LEVEL_CONNECT, "OK");
2348 + bfd_current=jb_socket_set_iteration_next(&bfds_iterate_state);
2350 #ifdef FEATURE_TOGGLE
2351 if (global_toggle_state)
2353 diff -urNad privoxy~/loadcfg.c privoxy/loadcfg.c
2354 --- privoxy~/loadcfg.c
2355 +++ privoxy/loadcfg.c
2357 * Copyright : Written by and Copyright (C) 2001 the SourceForge
2358 * Privoxy team. http://www.privoxy.org/
2360 + * Modified by Lionel Elie Mamane <lionel@mamane.lu>
2361 + * for IPv6 support on 8 December 2002, 24 January 2003.
2363 * Based on the Internet Junkbuster originally written
2364 * by and Copyright (C) 1997 Anonymous Coders and
2365 * Junkbusters Corporation. http://www.junkbusters.com
2368 #include "urlmatch.h"
2370 +#include "parsers.h"
2372 const char loadcfg_h_rcs[] = LOADCFG_H_VERSION;
2375 struct forward_spec * next_fwd = cur_fwd->next;
2376 free_url_spec(cur_fwd->url);
2378 - freez(cur_fwd->gateway_host);
2379 - freez(cur_fwd->forward_host);
2380 + freez(cur_fwd->gateway_malloc);
2381 + freez(cur_fwd->forward_malloc);
2385 @@ -545,7 +549,16 @@
2386 freez(config->confdir);
2387 freez(config->logdir);
2389 - freez(config->haddr);
2390 + if(config -> hspecs != NULL)
2393 + for (i=0; i < config->hspecs_occupied; ++i)
2395 + freez(config->hspecs[i].haddr);
2396 + freez(config->hspecs[i].hport);
2399 + freez(config->hspecs);
2400 freez(config->logfile);
2402 for (i = 0; i < MAX_AF_FILES; i++)
2403 @@ -612,6 +625,28 @@
2404 * Returns : The configuration_spec, or NULL on error.
2406 *********************************************************************/
2407 +static void fail_load_config_memory(struct file_list *fs, struct configuration_spec *config)
2409 + freez(fs->filename);
2411 + if (config != NULL)
2413 + if(config -> hspecs != NULL)
2416 + for (i=0; i < config->hspecs_occupied; ++i)
2418 + freez(config->hspecs[i].haddr);
2419 + freez(config->hspecs[i].hport);
2422 + freez(config -> hspecs);
2425 + log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
2426 + /* Never get here - LOG_LEVEL_FATAL causes program exit */
2429 struct configuration_spec * load_config(void)
2431 char buf[BUFFER_SIZE];
2432 @@ -643,12 +678,7 @@
2433 fs->f = config = (struct configuration_spec *)zalloc(sizeof(*config));
2437 - freez(fs->filename);
2439 - log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
2440 - /* Never get here - LOG_LEVEL_FATAL causes program exit */
2442 + fail_load_config_memory(fs,config);
2445 * This is backwards from how it's usually done.
2449 config->multi_threaded = 1;
2450 - config->hport = HADDR_PORT;
2451 + config->hspecs = NULL;
2452 config->buffer_limit = 4096 * 1024;
2453 config->usermanual = strdup(USER_MANUAL_URL);
2454 config->proxy_args = strdup("");
2456 char cmd[BUFFER_SIZE];
2457 char arg[BUFFER_SIZE];
2458 char tmp[BUFFER_SIZE];
2460 - struct access_control_list *cur_acl;
2461 -#endif /* def FEATURE_ACL */
2462 struct forward_spec *cur_fwd;
2465 @@ -797,74 +824,23 @@
2466 * *************************************************************************/
2468 case hash_deny_access:
2469 - vec_count = ssplit(arg, " \t", vec, SZ(vec), 1, 1);
2471 - if ((vec_count != 1) && (vec_count != 2))
2473 - log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
2474 - "deny-access directive in configuration file.");
2475 - string_append(&config->proxy_args,
2476 - "<br>\nWARNING: Wrong number of parameters for "
2477 - "deny-access directive in configuration file.<br><br>\n");
2481 - /* allocate a new node */
2482 - cur_acl = (struct access_control_list *) zalloc(sizeof(*cur_acl));
2484 - if (cur_acl == NULL)
2486 - log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
2487 - /* Never get here - LOG_LEVEL_FATAL causes program exit */
2490 - cur_acl->action = ACL_DENY;
2492 - if (acl_addr(vec[0], cur_acl->src) < 0)
2494 - log_error(LOG_LEVEL_ERROR, "Invalid source IP for deny-access "
2495 - "directive in configuration file: \"%s\"", vec[0]);
2496 - string_append(&config->proxy_args,
2497 - "<br>\nWARNING: Invalid source IP for deny-access directive"
2498 - " in configuration file: \"");
2499 - string_append(&config->proxy_args,
2501 - string_append(&config->proxy_args,
2506 - if (vec_count == 2)
2507 + switch (ssplit(arg, " \t", vec, SZ(vec), 1, 1))
2509 - if (acl_addr(vec[1], cur_acl->dst) < 0)
2511 - log_error(LOG_LEVEL_ERROR, "Invalid destination IP for deny-access "
2512 - "directive in configuration file: \"%s\"", vec[0]);
2513 - string_append(&config->proxy_args,
2514 - "<br>\nWARNING: Invalid destination IP for deny-access directive"
2515 - " in configuration file: \"");
2516 - string_append(&config->proxy_args,
2519 + config->acl = add_to_acl_list(config->acl, ACL_DENY, vec[0], NULL, &config->proxy_args);
2522 + config->acl = add_to_acl_list(config->acl, ACL_DENY, vec[0], vec[1], &config->proxy_args);
2525 + log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
2526 + "deny-access directive in configuration file.");
2527 string_append(&config->proxy_args,
2532 + "<br>\nWARNING: Wrong number of parameters for "
2533 + "deny-access directive in configuration file.<br><br>\n");
2537 - * Add it to the list. Note we reverse the list to get the
2538 - * behaviour the user expects. With both the ACL and
2539 - * actions file, the last match wins. However, the internal
2540 - * implementations are different: The actions file is stored
2541 - * in the same order as the file, and scanned completely.
2542 - * With the ACL, we reverse the order as we load it, then
2543 - * when we scan it we stop as soon as we get a match.
2545 - cur_acl->next = config->acl;
2546 - config->acl = cur_acl;
2550 #endif /* def FEATURE_ACL */
2552 /* *************************************************************************
2553 @@ -984,16 +960,18 @@
2555 if (strcmp(p, ".") != 0)
2557 - cur_fwd->forward_host = strdup(p);
2558 + cur_fwd->forward_malloc = strdup(p);
2559 + cur_fwd->forward_family = -1;
2561 - if (NULL != (p = strchr(cur_fwd->forward_host, ':')))
2564 - cur_fwd->forward_port = atoi(p);
2566 + parse_pf_ip(cur_fwd->forward_malloc,
2567 + &cur_fwd->forward_host,
2568 + &cur_fwd->forward_port_str,
2569 + &cur_fwd->forward_family);
2570 + cur_fwd->forward_port = atoi(cur_fwd->forward_port_str);
2572 if (cur_fwd->forward_port <= 0)
2574 + cur_fwd->forward_port_str = "8000";
2575 cur_fwd->forward_port = 8000;
2578 @@ -1047,15 +1025,27 @@
2580 if (strcmp(p, ".") != 0)
2582 - cur_fwd->gateway_host = strdup(p);
2583 + /* SOCKS is IPv4-specific */
2586 - if (NULL != (p = strchr(cur_fwd->gateway_host, ':')))
2587 + cur_fwd->gateway_malloc = strdup(p);
2588 + if (parse_pf_ip(cur_fwd->gateway_malloc,
2589 + &cur_fwd->gateway_host,
2590 + &cur_fwd->gateway_port_str,
2594 - cur_fwd->gateway_port = atoi(p);
2595 + log_error(LOG_LEVEL_ERROR, "Could not parse forward-socks4 host: %s",p);
2596 + cur_fwd->gateway_host = NULL;
2597 + cur_fwd->gateway_port_str = NULL;
2598 + freez(cur_fwd->gateway_malloc);
2602 + cur_fwd->gateway_port = atoi(cur_fwd->gateway_port_str);
2604 if (cur_fwd->gateway_port <= 0)
2606 + cur_fwd->gateway_port_str = "1080";
2607 cur_fwd->gateway_port = 1080;
2610 @@ -1065,16 +1055,26 @@
2612 if (strcmp(p, ".") != 0)
2614 - cur_fwd->forward_host = strdup(p);
2615 + cur_fwd->forward_malloc = strdup(p);
2616 + cur_fwd->forward_family = -1;
2618 - if (NULL != (p = strchr(cur_fwd->forward_host, ':')))
2619 + parse_pf_ip(cur_fwd->forward_malloc,
2620 + &cur_fwd->forward_host,
2621 + &cur_fwd->forward_port_str,
2622 + &cur_fwd->forward_family);
2623 + cur_fwd->forward_port = atoi(cur_fwd->forward_port_str);
2625 + if (cur_fwd->forward_port <= 0)
2628 - cur_fwd->forward_port = atoi(p);
2629 + cur_fwd->forward_port_str = "8000";
2630 + cur_fwd->forward_port = 8000;
2633 + cur_fwd->forward_port = atoi(p);
2635 if (cur_fwd->forward_port <= 0)
2637 + cur_fwd->forward_port_str = "8000";
2638 cur_fwd->forward_port = 8000;
2641 @@ -1126,16 +1126,30 @@
2642 /* Parse the SOCKS proxy host[:port] */
2645 - cur_fwd->gateway_host = strdup(p);
2647 - if (NULL != (p = strchr(cur_fwd->gateway_host, ':')))
2650 - cur_fwd->gateway_port = atoi(p);
2652 - if (cur_fwd->gateway_port <= 0)
2654 - cur_fwd->gateway_port = 1080;
2655 + /* SOCKS is IPv4-specific */
2658 + cur_fwd->gateway_malloc = strdup(p);
2659 + if (parse_pf_ip(cur_fwd->gateway_malloc,
2660 + &cur_fwd->gateway_host,
2661 + &cur_fwd->gateway_port_str,
2664 + log_error(LOG_LEVEL_ERROR, "Could not parse forward-socks4a host: %s",p);
2665 + cur_fwd->gateway_host = NULL;
2666 + cur_fwd->gateway_port_str = NULL;
2667 + freez(cur_fwd->gateway_malloc);
2671 + cur_fwd->gateway_port = atoi(cur_fwd->gateway_port_str);
2673 + if (cur_fwd->gateway_port <= 0)
2675 + cur_fwd->gateway_port_str = "1080";
2676 + cur_fwd->gateway_port = 1080;
2680 /* Parse the parent HTTP proxy host[:port] */
2681 @@ -1143,16 +1157,26 @@
2683 if (strcmp(p, ".") != 0)
2685 - cur_fwd->forward_host = strdup(p);
2686 + cur_fwd->forward_malloc = strdup(p);
2687 + cur_fwd->forward_family = -1;
2689 - if (NULL != (p = strchr(cur_fwd->forward_host, ':')))
2690 + parse_pf_ip(cur_fwd->forward_malloc,
2691 + &cur_fwd->forward_host,
2692 + &cur_fwd->forward_port_str,
2693 + &cur_fwd->forward_family);
2694 + cur_fwd->forward_port = atoi(cur_fwd->forward_port_str);
2696 + if (cur_fwd->forward_port <= 0)
2699 - cur_fwd->forward_port = atoi(p);
2700 + cur_fwd->forward_port_str = "8000";
2701 + cur_fwd->forward_port = 8000;
2704 + cur_fwd->forward_port = atoi(p);
2706 if (cur_fwd->forward_port <= 0)
2708 + cur_fwd->forward_port_str = "8000";
2709 cur_fwd->forward_port = 8000;
2712 @@ -1185,10 +1209,49 @@
2713 * listen-address [ip][:port]
2714 * *************************************************************************/
2715 case hash_listen_address :
2716 - freez(config->haddr);
2717 - config->haddr = strdup(arg);
2719 + struct bind_spec *bs;
2721 + if (config->hspecs == NULL)
2723 + /* This is the first we'll bind to */
2724 + config->hspecs = calloc(2,sizeof(struct bind_spec));
2725 + if (config->hspecs == NULL)
2726 + fail_load_config_memory(fs,config);
2727 + config->hspecs_size = 2;
2728 + config->hspecs_occupied = 0;
2731 + arg_cpy = strdup(arg);
2732 + if (arg_cpy == NULL)
2733 + fail_load_config_memory(fs,config);
2734 + if (config->hspecs_occupied == config->hspecs_size)
2736 + struct bind_spec *new_hspecs;
2737 + config->hspecs_size *= 2;
2738 + new_hspecs = realloc(config->hspecs,config->hspecs_size * sizeof(struct bind_spec));
2739 + if (new_hspecs == NULL)
2741 + /* Not enough memory to continue. Cancel changes. */
2742 + config->hspecs_size /= 2;
2743 + fail_load_config_memory(fs,config);
2745 + config->hspecs = new_hspecs;
2747 + bs = &config->hspecs[(config->hspecs_occupied)++];
2749 + parse_pf_ip(arg,&bs->haddr,&bs->hport,&bs->pf);
2750 + if (*bs->haddr == '\0')
2756 + (bs->haddr = strdup(bs->haddr));
2758 + bs->hport = strdup(bs->hport);
2762 /* *************************************************************************
2763 * logdir directory-name
2764 * *************************************************************************/
2765 @@ -1211,75 +1274,21 @@
2766 * *************************************************************************/
2768 case hash_permit_access:
2769 - vec_count = ssplit(arg, " \t", vec, SZ(vec), 1, 1);
2771 - if ((vec_count != 1) && (vec_count != 2))
2773 - log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
2774 - "permit-access directive in configuration file.");
2775 - string_append(&config->proxy_args,
2776 - "<br>\nWARNING: Wrong number of parameters for "
2777 - "permit-access directive in configuration file.<br><br>\n");
2782 - /* allocate a new node */
2783 - cur_acl = (struct access_control_list *) zalloc(sizeof(*cur_acl));
2785 - if (cur_acl == NULL)
2787 - log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
2788 - /* Never get here - LOG_LEVEL_FATAL causes program exit */
2791 - cur_acl->action = ACL_PERMIT;
2793 - if (acl_addr(vec[0], cur_acl->src) < 0)
2795 - log_error(LOG_LEVEL_ERROR, "Invalid source IP for permit-access "
2796 - "directive in configuration file: \"%s\"", vec[0]);
2797 - string_append(&config->proxy_args,
2798 - "<br>\nWARNING: Invalid source IP for permit-access directive"
2799 - " in configuration file: \"");
2800 - string_append(&config->proxy_args,
2802 - string_append(&config->proxy_args,
2807 - if (vec_count == 2)
2808 + switch (ssplit(arg, " \t", vec, SZ(vec), 1, 1))
2810 - if (acl_addr(vec[1], cur_acl->dst) < 0)
2812 - log_error(LOG_LEVEL_ERROR, "Invalid destination IP for "
2813 - "permit-access directive in configuration file: \"%s\"",
2815 - string_append(&config->proxy_args,
2816 - "<br>\nWARNING: Invalid destination IP for permit-access directive"
2817 - " in configuration file: \"");
2818 - string_append(&config->proxy_args,
2821 + config->acl = add_to_acl_list(config->acl, ACL_PERMIT, vec[0], NULL, &config->proxy_args);
2824 + config->acl = add_to_acl_list(config->acl, ACL_PERMIT, vec[0], vec[1], &config->proxy_args);
2827 + log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
2828 + "permit-access directive in configuration file.");
2829 string_append(&config->proxy_args,
2834 + "<br>\nWARNING: Wrong number of parameters for "
2835 + "permit-access directive in configuration file.<br><br>\n");
2839 - * Add it to the list. Note we reverse the list to get the
2840 - * behaviour the user expects. With both the ACL and
2841 - * actions file, the last match wins. However, the internal
2842 - * implementations are different: The actions file is stored
2843 - * in the same order as the file, and scanned completely.
2844 - * With the ACL, we reverse the order as we load it, then
2845 - * when we scan it we stop as soon as we get a match.
2847 - cur_acl->next = config->acl;
2848 - config->acl = cur_acl;
2851 #endif /* def FEATURE_ACL */
2853 @@ -1519,32 +1528,33 @@
2855 #endif /* def FEATURE_COOKIE_JAR */
2857 - if ( NULL == config->haddr )
2859 - config->haddr = strdup( HADDR_DEFAULT );
2862 - if ( NULL != config->haddr )
2863 + if ( config->hspecs == NULL )
2865 - if (NULL != (p = strchr(config->haddr, ':')))
2870 - config->hport = atoi(p);
2874 - if (config->hport <= 0)
2877 - log_error(LOG_LEVEL_FATAL, "invalid bind port spec %s", config->haddr);
2878 - /* Never get here - LOG_LEVEL_FATAL causes program exit */
2880 - if (*config->haddr == '\0')
2882 - config->haddr = NULL;
2884 + /* No listen-address set. The default is localhost on port 8118, on IPv4
2885 + and (if INET6 is defined) IPv6.
2887 + struct bind_spec *bs;
2889 + config->hspecs = calloc(2,sizeof(struct bind_spec));
2890 + if (config->hspecs == NULL)
2891 + fail_load_config_memory(fs,config);
2892 + config->hspecs_size=2;
2893 + config->hspecs_occupied=1;
2894 + bs = &config->hspecs[0];
2895 + bs->haddr = strdup("::1");
2896 + bs->hport = strdup("8118");
2897 + bs->pf = PF_UNSPEC;
2899 + config->hspecs = calloc(1,sizeof(struct bind_spec));
2900 + if (config->hspecs == NULL)
2901 + fail_load_config_memory(fs,config);
2902 + config->hspecs_size=1;
2903 + config->hspecs_occupied=0;
2905 + bs = &config->hspecs[config->hspecs_occupied++];
2906 + bs->haddr = strdup("127.0.0.1");
2907 + bs->hport = strdup("8118");
2908 + bs->pf = PF_UNSPEC;
2912 @@ -1586,31 +1596,29 @@
2913 struct configuration_spec * oldcfg = (struct configuration_spec *)
2914 current_configfile->f;
2916 - * Check if config->haddr,hport == oldcfg->haddr,hport
2918 - * The following could be written more compactly as a single,
2919 - * (unreadably long) if statement.
2920 + * Check if the listening addresses have changed
2922 config->need_bind = 0;
2923 - if (config->hport != oldcfg->hport)
2925 - config->need_bind = 1;
2927 - else if (config->haddr == NULL)
2928 + if (config -> hspecs_occupied == oldcfg -> hspecs_occupied)
2930 - if (oldcfg->haddr != NULL)
2932 + struct bind_spec *hspec;
2933 + struct bind_spec *oldhspec;
2934 + hspec = config -> hspecs;
2935 + oldhspec = oldcfg -> hspecs;
2936 + for(bs_index = 0; bs_index < oldcfg->hspecs_occupied; ++bs_index)
2938 - config->need_bind = 1;
2939 + if (strcmp(hspec[bs_index].haddr,oldhspec[bs_index].haddr) != 0
2940 + || strcmp(hspec[bs_index].hport,oldhspec[bs_index].hport) != 0
2941 + || hspec[bs_index].pf != hspec[bs_index].pf)
2943 + config -> need_bind = 1;
2948 - else if (oldcfg->haddr == NULL)
2950 - config->need_bind = 1;
2952 - else if (0 != strcmp(config->haddr, oldcfg->haddr))
2954 - config->need_bind = 1;
2957 + config-> need_bind = 1;
2959 current_configfile->unloader = unload_configfile;
2961 diff -urNad privoxy~/loaders.c privoxy/loaders.c
2962 --- privoxy~/loaders.c
2963 +++ privoxy/loaders.c
2965 * Copyright : Written by and Copyright (C) 2001 the SourceForge
2966 * Privoxy team. http://www.privoxy.org/
2968 + * Modified by Lionel Elie Mamane <lionel@mamane.lu>
2969 + * for IPv6 support on 8 December 2002, 24 January 2003.
2971 * Based on the Internet Junkbuster originally written
2972 * by and Copyright (C) 1997 Anonymous Coders and
2973 * Junkbusters Corporation. http://www.junkbusters.com
2976 freez(csp->ip_addr_str);
2977 freez(csp->my_ip_addr_str);
2978 + freez(csp->my_port_str);
2979 freez(csp->my_hostname);
2980 freez(csp->x_forwarded);
2981 freez(csp->iob->buf);
2982 diff -urNad privoxy~/miscutil.h privoxy/miscutil.h
2983 --- privoxy~/miscutil.h
2984 +++ privoxy/miscutil.h
2985 @@ -162,6 +162,15 @@
2987 #include "project.h"
2989 +/* Fix a problem with Solaris. There should be no effect on other
2991 + * Solaris's isspace() is a macro which uses it's argument directly
2992 + * as an array index. Therefore we need to make sure that high-bit
2993 + * characters generate +ve values, and ideally we also want to make
2994 + * the argument match the declared parameter type of "int".
2996 +#define ijb_isdigit(__X) isdigit((int)(unsigned char)(__X))
2998 #if defined(__cplusplus)
3001 diff -urNad privoxy~/parsers.c privoxy/parsers.c
3002 --- privoxy~/parsers.c
3003 +++ privoxy/parsers.c
3005 * Copyright : Written by and Copyright (C) 2001 the SourceForge
3006 * Privoxy team. http://www.privoxy.org/
3008 + * Modified by Lionel Elie Mamane <lionel@mamane.lu>
3009 + * for IPv6 support on 24 January 2003.
3011 * Based on the Internet Junkbuster originally written
3012 * by and Copyright (C) 1997 Anonymous Coders and
3013 * Junkbusters Corporation. http://www.junkbusters.com
3014 @@ -1951,6 +1954,167 @@
3018 +/*********************************************************************
3020 + * Function : parse_pf_ip_netmask
3022 + * Description : Parse an IPv{4,6} litteral or hostname
3023 + * with optional port and optional explicit family
3024 + * and optional netmask
3027 + * 0 : string = the string to parse
3028 + * 1 : host = Is set to point to the hostname or IP literal
3030 + * 2 : port = Is set to point to the port part,
3031 + * or NULL if no port in string
3032 + * 3 : pf = pointer used to return the address family
3033 + * pf is a value-result argument:
3034 + * If it is set to -1, then parse_pf_ip will set it
3035 + * to the address family of the pf_ip string
3036 + * else, it won't touch it, and fail if the two
3038 + * 4 : pointer used to return the mask length
3039 + * Set to -1 if no mask
3041 + * Returns : 0 on success
3043 + *********************************************************************/
3044 +int parse_pf_ip_netmask(char *string, char **host, char **port, int *pf, int *masklength)
3051 + if ((p = strchr(string, '/')) != NULL)
3055 + if (ijb_isdigit(*p) == 0)
3065 + return parse_pf_ip(string, host, port, pf);
3068 +/*********************************************************************
3070 + * Function : parse_pf_ip
3072 + * Description : Parse an IPv{4,6} litteral or hostname
3073 + * with optional port and optional explicit family
3076 + * 0 : string = the string to parse
3077 + * 1 : host = Is set to point to the hostname or IP literal
3079 + * 2 : port = Is set to point to the port part,
3080 + * or NULL if no port in string
3081 + * 3 : pf = pointer used to return the address family
3082 + * pf is a value-result argument:
3083 + * If it is set to -1, then parse_pf_ip will set it
3084 + * to the address family of the pf_ip string
3085 + * else, it won't touch it, and fail if the two
3088 + * Returns : 0 on success
3090 + *********************************************************************/
3091 +int parse_pf_ip(char *string, char **host, char **port, int *pf)
3093 + if (pf != NULL && *pf == -1)
3096 + /* See if we want to override the default protocol family */
3097 + if (strncmpic(string, "ipv4:", 5) == 0)
3102 + if(*pf==PF_INET || *pf==PF_UNSPEC)
3106 + log_error(LOG_LEVEL_ERROR,"%s","IPv4 address found where other awaited");
3111 + else if (strncmpic(string, "ipv6:", 5) == 0)
3115 + if(*pf==PF_INET6 || *pf==PF_UNSPEC)
3119 + log_error(LOG_LEVEL_ERROR,"%s","IPv6 address found where other awaited");
3123 + log_error(LOG_LEVEL_ERROR,"%s","This privoxy hasn't IPv6 support");
3127 + return parse_ip(string, host, port);
3130 +/*********************************************************************
3132 + * Function : parse_ip
3134 + * Description : Parse an IPv{4,6} litteral or hostname
3135 + * with optional port
3138 + * 0 : string = the string to parse
3139 + * 1 : host = Is set to point to the hostname or IP literal
3141 + * 2 : port = Is set to point to the port part,
3142 + * or NULL if no port in string
3143 + * Returns : 0 on success
3145 + *********************************************************************/
3146 +int parse_ip(char *string, char **host, char **port)
3151 + /* allow IPv6 address literal: [numbers:with:colons]:port/mask */
3152 + if (string[0] == '[' && (p = strchr(string, ']')))
3164 + *host = string + skip;
3166 + for(;*p != '\0'; ++p)
3180 /*********************************************************************
3182 diff -urNad privoxy~/parsers.h privoxy/parsers.h
3183 --- privoxy~/parsers.h
3184 +++ privoxy/parsers.h
3186 * Copyright : Written by and Copyright (C) 2001 the SourceForge
3187 * Privoxy team. http://www.privoxy.org/
3189 + * Modified by Lionel Elie Mamane <lionel@mamane.lu>
3190 + * for IPv6 support on 24 January 2003.
3192 * Based on the Internet Junkbuster originally written
3193 * by and Copyright (C) 1997 Anonymous Coders and
3194 * Junkbusters Corporation. http://www.junkbusters.com
3195 @@ -270,6 +273,10 @@
3196 extern jb_err server_last_modified (struct client_state *csp, char **header);
3197 extern jb_err server_content_disposition(struct client_state *csp, char **header);
3199 +extern int parse_pf_ip_netmask(char *string, char **host, char **port, int *pf, int *masklength);
3200 +extern int parse_pf_ip(char *string, char ** host, char ** port, int *pf);
3201 +extern int parse_ip(char *string, char ** host, char** port);
3203 #ifdef FEATURE_FORCE_LOAD
3204 extern int strclean(const char *string, const char *substring);
3205 #endif /* def FEATURE_FORCE_LOAD */
3206 diff -urNad privoxy~/project.h privoxy/project.h
3207 --- privoxy~/project.h
3208 +++ privoxy/project.h
3209 @@ -607,6 +607,20 @@
3211 #endif /* ndef _WIN32 */
3213 +#include "jb_socket_set.h"
3217 + * Get from the operating system structures big enough
3218 + * to put a network address in, namely sockaddr_storage
3220 +#include <sys/socket.h>
3222 + * If no IPv6 support, just use the old sockaddr
3225 +#define sockaddr_storage sockaddr
3229 * A standard error code. This should be JB_ERR_OK or one of the JB_ERR_xxx
3230 @@ -681,19 +695,6 @@
3235 - * Default IP address to listen on, as a string.
3236 - * Set to "127.0.0.1".
3238 -#define HADDR_DEFAULT "127.0.0.1"
3241 - * Default port to listen on, as a number.
3244 -#define HADDR_PORT 8118
3247 /* Forward def for struct client_state */
3248 struct configuration_spec;
3250 @@ -772,13 +773,16 @@
3251 char *ver; /**< Protocol version */
3252 int status; /**< HTTP Status */
3254 + char *host_port_malloc; /**< malloc used for place wher host and port_str are */
3255 char *host; /**< Host part of URL */
3256 int port; /**< Port of URL or 80 (default) */
3257 + char *port_str; /**< Port of URL, as string */
3258 char *path; /**< Path of URL */
3259 char *hostport; /**< host[:port] */
3260 int ssl; /**< Flag if protocol is https */
3262 - char *host_ip_addr_str; /**< String with dotted decimal representation
3263 + char *host_ip_addr_str; /**< String with dotted decimal representation (IPv4)
3264 + or hexadecimal colon-separated (IPv6)
3265 of host's IP. NULL before connect_to() */
3267 char *dbuffer; /**< Buffer with '\0'-delimited domain name. */
3268 @@ -1158,13 +1162,16 @@
3271 /** Client PC's IP address, as reported by the accept() function.
3273 - long ip_addr_long;
3275 + struct sockaddr_storage ip_addr_addr;
3277 /** Our IP address. I.e. the IP address that the client used to reach us,
3279 char *my_ip_addr_str;
3281 + /** Our port. I.e. the port the client used to reach us */
3282 + char *my_port_str;
3284 /** Our hostname. I.e. the reverse DNS of the IP address that the client
3285 used to reach us, as a string. */
3287 @@ -1339,18 +1346,33 @@
3288 /** Connection type. Must be SOCKS_NONE, SOCKS_4, or SOCKS_4A. */
3291 + /** pointer returned by the malloc used for gateway_host and gateway_port_str */
3292 + char *gateway_malloc;
3294 /** SOCKS server hostname. Only valid if "type" is SOCKS_4 or SOCKS_4A. */
3297 /** SOCKS server port. */
3300 + /** SOCKS server port, as string. */
3301 + char *gateway_port_str;
3303 + /** pointer returned by the malloc used for forward_host and forward_port_str */
3304 + char *forward_malloc;
3306 + /** Parent HTTP proxy address family. */
3307 + int forward_family;
3309 /** Parent HTTP proxy hostname, or NULL for none. */
3312 /** Parent HTTP proxy port. */
3315 + /** Parent HTTP proxy port as string. */
3316 + char *forward_port_str;
3318 /** Next entry in the linked list. */
3319 struct forward_spec *next;
3321 @@ -1359,7 +1381,7 @@
3323 * Initializer for a static struct forward_spec.
3325 -#define FORWARD_SPEC_INITIALIZER { { URL_SPEC_INITIALIZER }, 0, NULL, 0, NULL, 0, NULL }
3326 +#define FORWARD_SPEC_INITIALIZER { { URL_SPEC_INITIALIZER }, 0, NULL, NULL, 0, NULL, NULL, 0, NULL, 0, NULL, NULL}
3330 @@ -1388,7 +1410,8 @@
3332 struct access_control_addr
3334 - unsigned long addr; /**< The IP address as an integer. */
3335 + struct sockaddr_storage addr; /**< The IP address. */
3337 unsigned long mask; /**< The network mask as an integer. */
3338 unsigned long port; /**< The port number. */
3340 @@ -1423,6 +1446,17 @@
3341 /** configuration_spec::feature_flags: HTTP-header-based toggle. */
3342 #define RUNTIME_FEATURE_HTTP_TOGGLE 4
3346 + /** IP address to bind to. */
3349 + /** Port to bind to. */
3352 + /** Address family */
3356 * Data loaded from the configuration file.
3358 @@ -1486,11 +1520,13 @@
3360 #endif /* def FEATURE_COOKIE_JAR */
3362 - /** IP address to bind to. Defaults to HADDR_DEFAULT == 127.0.0.1. */
3363 - const char *haddr;
3365 - /** Port to bind to. Defaults to HADDR_PORT == 8118. */
3367 + /* IP addresses and ports to bind to.
3368 + Defaults to HSPECS_DEFAULT == {ipv4:127.0.0.1:8118, ipv6:[::1]:8118}. */
3369 + struct bind_spec *hspecs;
3370 + /* size allocated */
3371 + unsigned int hspecs_size;
3372 + /* number of entries */
3373 + unsigned int hspecs_occupied;
3375 /** Size limit for IOB */
3376 size_t buffer_limit;
3377 diff -urNad privoxy~/urlmatch.c privoxy/urlmatch.c
3378 --- privoxy~/urlmatch.c
3379 +++ privoxy/urlmatch.c
3382 #include "miscutil.h"
3384 +#include "parsers.h"
3386 const char urlmatch_h_rcs[] = URLMATCH_H_VERSION;
3392 - freez(http->host);
3393 + freez(http->host_port_malloc);
3395 freez(http->hostport);
3404 buf = strdup(http->hostport);
3406 @@ -311,38 +310,34 @@
3407 return JB_ERR_MEMORY;
3410 + http->host_port_malloc = buf;
3412 /* check if url contains username and/or password */
3413 - host = strchr(buf, '@');
3415 + buf = strchr(buf, '@');
3418 /* Contains username/password, skip it and the @ sign. */
3424 /* No username or password. */
3426 + buf = http->host_port_malloc;
3429 - /* check if url contains port */
3430 - port = strchr(host, ':');
3432 + parse_ip(buf,&http->host,&http->port_str);
3434 + if (*http->port_str != '\0')
3436 - /* Contains port */
3437 - /* Terminate hostname and point to start of port string */
3439 - http->port = atoi(port);
3440 + http->port = atoi(http->port_str);
3444 /* No port specified. */
3445 + http->port_str = (http->ssl ? "143" : "80");
3446 http->port = (http->ssl ? 443 : 80);
3449 - http->host = strdup(host);
3453 if (http->host == NULL)
3455 return JB_ERR_MEMORY;
3457 * written to system log)
3459 *********************************************************************/
3460 -jb_err create_url_spec(struct url_spec * url, const char * buf)
3461 +jb_err create_url_spec(struct url_spec * url, char * buf)
3467 @@ -685,21 +679,24 @@
3469 return JB_ERR_MEMORY;
3472 - if ((p = strchr(buf, '/')) != NULL)
3474 - if (NULL == (url->path = strdup(p)))
3477 + if ((p = strchr(buf, '/')) != NULL)
3480 - return JB_ERR_MEMORY;
3481 + if (NULL == (url->path = strdup(p)))
3484 + return JB_ERR_MEMORY;
3486 + url->pathlen = strlen(url->path);
3494 - url->pathlen = strlen(url->path);
3504 @@ -739,14 +736,11 @@
3505 return JB_ERR_PARSE;
3508 - if ((p = strchr(buf, ':')) == NULL)
3516 - url->port = atoi(p);
3518 + parse_ip(buf,&buf,&p);
3519 + url->port = atoi(p);
3523 @@ -779,12 +773,13 @@
3524 return JB_ERR_MEMORY;
3528 - * Map to lower case
3530 - for (p = url->dbuffer; *p ; p++)
3532 - *p = tolower((int)(unsigned char)*p);
3534 + /* map to lower case */
3535 + for (p = url->dbuffer; *p ; p++)
3537 + *p = tolower((int)(unsigned char)*p);
3542 diff -urNad privoxy~/urlmatch.h privoxy/urlmatch.h
3543 --- privoxy~/urlmatch.h
3544 +++ privoxy/urlmatch.h
3546 extern int url_match(const struct url_spec *pattern,
3547 const struct http_request *url);
3549 -extern jb_err create_url_spec(struct url_spec * url, const char * buf);
3550 +extern jb_err create_url_spec(struct url_spec * url, char * buf);
3551 extern void free_url_spec(struct url_spec *url);