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
10 diff -urNad privoxy~/GNUmakefile.in privoxy/GNUmakefile.in
11 --- privoxy~/GNUmakefile.in
12 +++ privoxy/GNUmakefile.in
14 C_SRC = actions.c cgi.c cgiedit.c cgisimple.c deanimate.c encode.c \
15 errlog.c filters.c gateway.c jbsockets.c jcc.c killpopup.c \
16 list.c loadcfg.c loaders.c miscutil.c parsers.c ssplit.c \
18 + urlmatch.c addrlist.c jb_socket_set.c
20 C_OBJS = $(C_SRC:.c=.@OBJEXT@)
21 C_HDRS = $(C_SRC:.c=.h) project.h actionlist.h
23 SPECIAL_CFLAGS = @SPECIAL_CFLAGS@
27 +OTHER_CFLAGS = -DINET6
29 CFLAGS = @CFLAGS@ @CPPFLAGS@ $(OTHER_CFLAGS) $(SPECIAL_CFLAGS) -Wall \
30 @STATIC_PCRE_ONLY@ -Ipcre
31 diff -urNad privoxy~/addrlist.c privoxy/addrlist.c
32 --- privoxy~/addrlist.c
33 +++ privoxy/addrlist.c
35 +const char addrlist_rcs[] = "$Id: $";
36 +/*********************************************************************
40 + * Purpose : Declares functions to handle lists of network addresses.
41 + * Functions declared include:
42 + * `destroy_addr_list', head_addr_list and `tail_addr_list'
44 + * Copyright : Written by and Copyright (C) 2002 Lionel Elie Mamane
45 + * <lionel@mamane.lu>
47 + * This program is free software; you can redistribute it
48 + * and/or modify it under the terms of the GNU General
49 + * Public License as published by the Free Software
50 + * Foundation; either version 2 of the License, or (at
51 + * your option) any later version.
53 + * This program is distributed in the hope that it will
54 + * be useful, but WITHOUT ANY WARRANTY; without even the
55 + * implied warranty of MERCHANTABILITY or FITNESS FOR A
56 + * PARTICULAR PURPOSE. See the GNU General Public
57 + * License for more details.
59 + * The GNU General Public License should be included with
60 + * this file. If not, you can view it at
61 + * http://www.gnu.org/copyleft/gpl.html
62 + * or write to the Free Software Foundation, Inc., 59
63 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
66 + * $Log: addrlist.c,v $
68 + *********************************************************************/
70 +#include "addrlist.h"
71 +#include <sys/types.h>
72 +#include <sys/socket.h>
76 +/*********************************************************************
78 + * Function : acceptable
80 + * Description : Test wheter an address is acceptable for our use
81 + * Currently, this means either an IPv4 or an IPv6 address
84 + * 0 : addr = the address to test
86 + * Returns : 0 = false / no
87 + * anything else = true / yes
89 + *********************************************************************/
90 +static int acceptable (struct sockaddr_storage *addr)
92 + switch(addr->ss_family)
104 +/*********************************************************************
108 + * Description : Get the first acceptable address in head position
109 + * Assumes there is one
112 + * 0 : l = the list to skim
114 + * Returns : the skimmed list
116 + *********************************************************************/
117 +static addr_list *skim (addr_list *l)
119 + if (acceptable((struct sockaddr_storage*)l->ai_addr))
121 + return skim(l->ai_next);
124 +/*********************************************************************
126 + * Function : tail_addr_list
128 + * Description : Get the tail of an address list
131 + * 0 : l = the list to get the tail of
133 + * Returns : the tail of the list
134 + * If the list has no tail (i.e. is nil), unspecified
137 + *********************************************************************/
138 +addr_list *tail_addr_list(addr_list *l)
140 + return skim(l)->ai_next;
143 +/*********************************************************************
145 + * Function : head_addr_list
147 + * Description : Get the head of an address list
150 + * 0 : l = the list to get the head of
152 + * Returns : the head of the list
153 + * If the list has no head (i.e. is nil), unspecified
156 + *********************************************************************/
157 +struct sockaddr_storage *head_addr_list(addr_list *l)
159 + return (struct sockaddr_storage *)skim(l)->ai_addr;
162 +/*********************************************************************
164 + * Function : cpy_head_addr_list
166 + * Description : Copy the head of an address list to the given destination
169 + * 0 : l = the list to get the head of
170 + * 1 : r = where to put the result
172 + * Returns : Nothing
173 + * If the list has no head (i.e. is nil), unspecified
176 + *********************************************************************/
177 +void cpy_head_addr_list(addr_list *l, struct sockaddr_storage *r, size_t *addrlen)
179 + addr_list *sl = skim(l);
180 + memcpy(r, sl->ai_addr, sl->ai_addrlen);
181 + *addrlen = sl->ai_addrlen;
184 +/*********************************************************************
186 + * Function : destroy_addr_list
188 + * Description : Unallocate memory allocated to an address list
191 + * 0 : l = the list to unallocate
193 + * Returns : nothing
195 + *********************************************************************/
196 +void destroy_addr_list(addr_list *l)
201 +/*********************************************************************
203 + * Function : is_nil_addr_list
205 + * Description : Test wheter a list is nil (empty)
208 + * 0 : l = the list to test
210 + * Returns : 0 = false if list has a head,
211 + * anything else = true if list is nil
213 + *********************************************************************/
214 +int is_nil_addr_list(addr_list *l)
216 + /* We are searching for a witness of non-nilness (modulo acceptability)
217 + * If none is found, the list is nil
222 + if (acceptable(head_addr_list(l)))
223 + /* Witness found */
225 + return is_nil_addr_list(l->ai_next);
233 diff -urNad privoxy~/addrlist.h privoxy/addrlist.h
234 --- privoxy~/addrlist.h
235 +++ privoxy/addrlist.h
237 +#ifndef ADDR_LIST_H_INCLUDED
238 +#define ADDR_LIST_H_INCLUDED
239 +#define ADDR_LIST_H_VERSION "$Id: $"
240 +/*********************************************************************
242 + * File : $Source: $
244 + * Purpose : Declares functions to handle lists of network addresses.
245 + * Functions declared include:
246 + * `destroy_addr_list', head_addr_list and `tail_addr_list'
248 + * Copyright : Written by and Copyright (C) 2002 Lionel Elie Mamane
249 + * <lionel@mamane.lu>
251 + * This program is free software; you can redistribute it
252 + * and/or modify it under the terms of the GNU General
253 + * Public License as published by the Free Software
254 + * Foundation; either version 2 of the License, or (at
255 + * your option) any later version.
257 + * This program is distributed in the hope that it will
258 + * be useful, but WITHOUT ANY WARRANTY; without even the
259 + * implied warranty of MERCHANTABILITY or FITNESS FOR A
260 + * PARTICULAR PURPOSE. See the GNU General Public
261 + * License for more details.
263 + * The GNU General Public License should be included with
264 + * this file. If not, you can view it at
265 + * http://www.gnu.org/copyleft/gpl.html
266 + * or write to the Free Software Foundation, Inc., 59
267 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
270 + * $Log: addrlist.h,v $
272 + *********************************************************************/
274 +#include <sys/socket.h>
276 +typedef struct addrinfo addr_list;
278 +addr_list *tail_addr_list(addr_list *l);
279 +struct sockaddr_storage *head_addr_list(addr_list *l);
280 +void cpy_head_addr_list(addr_list *l, struct sockaddr_storage *r, size_t *addrlen);
281 +void destroy_addr_list(addr_list *l);
282 +int is_nil_addr_list(addr_list *l);
284 +#define freez_addr_list(X) { if(X) { destroy_addr_list(X); X = NULL ; } }
286 +#endif /* ndef LIST_H_INCLUDED */
293 diff -urNad privoxy~/cgi.c privoxy/cgi.c
297 * Copyright : Written by and Copyright (C) 2001 the SourceForge
298 * Privoxy team. http://www.privoxy.org/
300 + * Modified by Lionel Elie Mamane <lionel@mamane.lu>
301 + * for IPv6 support on 8 December 2002, 24 January 2003.
303 * Based on the Internet Junkbuster originally written
304 * by and Copyright (C) 1997 Anonymous Coders and
305 * Junkbusters Corporation. http://www.junkbusters.com
306 @@ -2167,7 +2170,6 @@
307 *********************************************************************/
308 struct map *default_exports(const struct client_state *csp, const char *caller)
312 struct map * exports;
313 int local_help_exists = 0;
314 @@ -2199,8 +2201,7 @@
315 if (!err) err = map_block_killer(exports, "can-toggle");
318 - snprintf(buf, 20, "%d", csp->config->hport);
319 - if (!err) err = map(exports, "my-port", 1, buf, 1);
320 + if (!err) err = map(exports, "my-port", 1, csp->my_port_str, 1);
322 if(!strcmp(CODE_STATUS, "stable"))
324 diff -urNad privoxy~/errlog.c privoxy/errlog.c
325 --- privoxy~/errlog.c
330 /* Non-standard: Print error code from errno */
332 + * This is not only not standard, but clashes
333 + * with the E modifier on the GNU (and possibly
334 + * other systems): It means double (floating point)
335 + * number in exponential notation, with capital E
336 + * for mantiss / exponenent separator
339 ival = WSAGetLastError();
340 sval = w32_socket_strerr(ival, tempbuf);
341 diff -urNad privoxy~/filters.c privoxy/filters.c
342 --- privoxy~/filters.c
343 +++ privoxy/filters.c
345 * Copyright : Written by and Copyright (C) 2001 the SourceForge
346 * Privoxy team. http://www.privoxy.org/
348 + * Modified by Lionel Elie Mamane <lionel@mamane.lu>
349 + * for IPv6 support on 8 December 2002, 24 January 2003.
351 * Based on the Internet Junkbuster originally written
352 * by and Copyright (C) 1997 Anonymous Coders and
353 * Junkbusters Corporation. http://www.junkbusters.com
364 @@ -461,17 +467,119 @@
366 const char filters_h_rcs[] = FILTERS_H_VERSION;
368 -/* Fix a problem with Solaris. There should be no effect on other
370 - * Solaris's isspace() is a macro which uses it's argument directly
371 - * as an array index. Therefore we need to make sure that high-bit
372 - * characters generate +ve values, and ideally we also want to make
373 - * the argument match the declared parameter type of "int".
375 -#define ijb_isdigit(__X) isdigit((int)(unsigned char)(__X))
377 +/*********************************************************************
379 + * Function : addr_equal_under_mask
381 + * Description : Are these addresses equal modulo this mask?
382 + * Assumes the second argument is already in
386 + * 0 : addr1 = First address to compare
387 + * 1 : addr2 = Second address to compare
388 + * MUST be in mask-normal form
389 + * 2 : mask = for IPv4 addresses, a bitmask
390 + * for IPv6 addresses, a prefixlen in bits
392 + * Returns : 0 = FALSE (not equal) and non-zero = TRUE (equal)
394 + *********************************************************************/
397 +addr_equal_under_mask(struct sockaddr_storage *addr1, struct sockaddr_storage *addr2, unsigned long mask)
402 + /* only identical families can be compared */
403 + /* TODO: Should we code the special case of "IPv4 addresses as IPv6 addresses"? */
404 + if (addr1->ss_family != addr2-> ss_family)
406 + /*fprintf(stderr, "equal_under_mask: diff sa_family: %d %d\n",
407 + sa1->sa_family, sa2-> sa_family); */
411 + switch (addr1->ss_family)
415 + /* IPv4 - mask is a bitmask */
416 + struct sockaddr_in *sin1 = (struct sockaddr_in *)addr1;
417 + struct sockaddr_in *sin2 = (struct sockaddr_in *)addr2;
419 + /*fprintf(stderr, "AF_INET: %08x %08x %08x\n",
420 + sin1->sin_addr.s_addr,
421 + sin2->sin_addr.s_addr,
423 + return (sin1->sin_addr.s_addr & mask) == sin2->sin_addr.s_addr;
429 + /* IPv6 - mask is a prefixlength in bits. */
430 + struct sockaddr_in6 *sin1 = (struct sockaddr_in6 *)addr1;
431 + struct sockaddr_in6 *sin2 = (struct sockaddr_in6 *)addr2;
434 + const int maskbytes = mask / 8;
435 + static char m[] = { 0x00, 0x80, 0xC0, 0xE0,
436 + 0xF0, 0xF8, 0xFC, 0xFE };
439 +/* fprintf(stderr, "PF_INET6: "); */
440 +/* for (i = 0; i < 16; i++) { */
441 +/* fprintf(stderr, "%02x ", sin1->sin6_addr.s6_addr[i]); */
443 +/* fprintf(stderr, " "); */
444 +/* for (i = 0; i < 16; i++) { */
445 +/* fprintf(stderr, "%02x ", sin2->sin6_addr.s6_addr[i]); */
447 +/* fprintf(stderr, "mask %d scopeids %x %x\n", mask, sin1->sin6_scope_id, sin2->sin6_scope_id); */
449 + /* should we compare scope ids and such too? */
451 + * LEM: I see no reason for this comparison
452 + * Quite the contrary: A client coming to us with
453 + * a small-scope address should be able to a bigger-scope
456 +/* if (sin1->sin6_scope_id != sin2->sin6_scope_id) */
461 + log_error(LOG_LEVEL_ERROR, "%s%d", "Tried to compare IPv6 addresses with invalid prefixlen: ", mask);
465 + a1 = sin1->sin6_addr.s6_addr;
466 + a2 = sin2->sin6_addr.s6_addr;
468 + if (memcmp(a1, a2, maskbytes) != 0)
472 + /* This special case is necessary for when mask==128
473 + else, we would go over the array size in a1/a2
480 + return (a1[maskbytes] & bitmask) == a2[maskbytes];
490 /*********************************************************************
492 * Function : block_acl
494 /* search the list */
497 - if ((csp->ip_addr_long & acl->src->mask) == acl->src->addr)
498 + if (addr_equal_under_mask(&csp->ip_addr_addr, &acl->src->addr, acl->src->mask))
506 - else if ( ((dst->addr & acl->dst->mask) == acl->dst->addr)
507 - && ((dst->port == acl->dst->port) || (acl->dst->port == 0)))
508 + else if ( addr_equal_under_mask(&dst->addr, &acl->dst->addr, acl->dst->mask)
509 + && ((dst->port == acl->dst->port) || (acl->dst->port == 0)))
511 if (acl->action == ACL_PERMIT)
513 @@ -531,81 +639,249 @@
518 /*********************************************************************
520 - * Function : acl_addr
521 + * Function : fill_acl_addr_mask
523 - * Description : Called from `load_config' to parse an ACL address.
524 + * Description : Fill in the mask-related members of a
525 + * struct access_control_addr
528 - * 1 : aspec = String specifying ACL address.
529 - * 2 : aca = struct access_control_addr to fill in.
530 + * 0 : aca = struct access_control_addr to fill in.
531 + * 1 : masklength = mask length.
533 - * Returns : 0 => Ok, everything else is an error.
534 + * Returns : nothing
536 *********************************************************************/
537 -int acl_addr(char *aspec, struct access_control_addr *aca)
538 +void fill_acl_addr_mask(struct access_control_addr *aca, int masklength)
540 - int i, masklength, port;
546 + pf = aca->addr.ss_family;
548 - if ((p = strchr(aspec, '/')) != NULL)
553 - if (ijb_isdigit(*p) == 0)
555 + /* build the netmask */
556 + if (masklength == -1)
559 + for(pf=1; pf <= masklength ; ++pf)
562 + aca->mask |= (1 << (32 - pf));
564 - masklength = atoi(p);
566 + aca->mask = htonl(aca->mask);
568 + /* now mask off the host portion of the ip address
569 + * (i.e. save on the network portion of the address).
571 + ((struct sockaddr_in*) &aca->addr)->sin_addr.s_addr &= aca->mask;
572 + aca->port = ((struct sockaddr_in*) &aca->addr)->sin_port;
577 + static char m[] = { 0x00, 0x80, 0xC0, 0xE0,
578 + 0xF0, 0xF8, 0xFC, 0xFE };
580 + struct sockaddr_in6 *sa6 = (struct sockaddr_in6*)&aca->addr;
582 - if ((masklength < 0) || (masklength > 32))
585 + aca->mask = (masklength == -1) ? masklength : 128 ;
586 + /* now mask off the host portion of the ip address
587 + * (i.e. save on the network portion of the address).
592 + sa6->sin6_addr.s6_addr[i] &= m[aca->mask % 8];
593 + /* The following loop is not strictly necessary,
594 + because of the way addr_equal_under_mask is
595 + written. Better safe than sorry, though:
596 + New code might make the full mask-normal
599 + for(++i; i < 16 ; ++i)
600 + sa6->sin6_addr.s6_addr[i] = 0;
602 + aca -> port = sa6->sin6_port;
607 + /* FATAL because access_control_addr's are created only with adresses
608 + deemed 'acceptable' by the addr_list stuff, thus currently IPv4 and
611 + log_error(LOG_LEVEL_FATAL,"%s%d","Unknown address family in ACL address: ",pf);
615 - if ((p = strchr(aspec, ':')) != NULL)
618 +/*********************************************************************
620 + * Function : acl_addrs
622 + * Description : Parse an ACL address (adress + mask prefix)
623 + * Resolve the parsed address
624 + * Describe errors in *proxy_args.
627 + * 0 : aspec = the string containing the ACL address/mask
628 + * 1 : masklength = pointer used to return the mask
629 + * 2 : proxy_args = Pointer to string to append description of errors to.
630 + * 3 : type = type of ACL adress (source / destination).
631 + * Used for error reporting.
633 + * Returns : the list of adresses the ACL address resolves to
635 + *********************************************************************/
636 +static addr_list *acl_addrs(char *aspec, int *masklength, char**proxy_args, const char *type)
642 - if (ijb_isdigit(*p) == 0)
648 + if (parse_pf_ip_netmask(aspec, &host, &port, &pf, masklength) != 0)
650 + log_error(LOG_LEVEL_ERROR, "Invalid %s IP for (deny|permit)-access "
651 + "directive in configuration file: \"%s\"", type, aspec);
652 + string_append(proxy_args,"<br>\nWARNING: Invalid ");
653 + string_append(proxy_args, type);
654 + string_append(proxy_args," IP for (deny|permit)-access directive"
655 + " in configuration file: \"");
656 + string_append(proxy_args, aspec);
657 + string_append(proxy_args,"\"<br><br>\n");
662 + return resolve_hostname_to_ip(host, port, pf);
665 - aca->addr = ntohl(resolve_hostname_to_ip(aspec));
666 +/*********************************************************************
668 + * Function : add_one_to_acl_list
670 + * Description : Add one entry to an access_control_list.
673 + * 0 : l = the list to add to
674 + * 1 : action = ACL_DENY or ACL_PERMIT
675 + * 2 : src_addrs = the head of this list will be used as source
676 + * in the ACL entry.
677 + * 3 : dst_addrs = the head of this list will be used as destination
678 + * in the ACL entry.
680 + * 4 : src_masklength = mask length for the source
681 + * 5 : src_masklength = mask length for the destination
683 + * Returns : the new list
685 + *********************************************************************/
686 +struct access_control_list *add_one_to_acl_list(struct access_control_list *l, short action,
687 + addr_list *src_addrs, addr_list *dst_addrs,
688 + int src_masklength, int dst_masklength)
690 + struct access_control_list *cur_acl;
691 + /* allocate a new node */
692 + cur_acl = (struct access_control_list *) zalloc(sizeof(*cur_acl));
694 - if (aca->addr == INADDR_NONE)
695 + if (cur_acl == NULL)
698 + log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
699 + /* Never get here - LOG_LEVEL_FATAL causes program exit */
703 - /* build the netmask */
705 - for (i=1; i <= masklength ; i++)
706 + cur_acl->action = action;
708 + cpy_head_addr_list(src_addrs, &cur_acl->src->addr, &cur_acl->src->addrlen);
709 + fill_acl_addr_mask(cur_acl->src, src_masklength);
710 + if (dst_addrs != NULL)
712 - aca->mask |= (1 << (32 - i));
713 + cpy_head_addr_list(dst_addrs, &cur_acl->dst->addr, &cur_acl->dst->addrlen);
714 + fill_acl_addr_mask(cur_acl->src, src_masklength);
717 - /* now mask off the host portion of the ip address
718 - * (i.e. save on the network portion of the address).
720 + * Add it to the list. Note we reverse the list to get the
721 + * behaviour the user expects. With both the ACL and
722 + * actions file, the last match wins. However, the internal
723 + * implementations are different: The actions file is stored
724 + * in the same order as the file, and scanned completely.
725 + * With the ACL, we reverse the order as we load it, then
726 + * when we scan it we stop as soon as we get a match.
728 - aca->addr = aca->addr & aca->mask;
735 +/*********************************************************************
737 + * Function : add_to_acl_list
739 + * Description : Add entries to an access_control_list.
740 + * Describe errors in *proxy_args.
743 + * 0 : l = the list to add to
744 + * 1 : action = ACL_DENY or ACL_PERMIT
745 + * 2 : src_spec = String giving the source of the acl entry
746 + * 3 : dst_spec = String giving the destination of the acl entry,
748 + * 4 : proxy_args = Pointer to string to append description of errors to.
750 + * Returns : the new list
752 + *********************************************************************/
753 +struct access_control_list *add_to_acl_list(struct access_control_list *l,
759 + int src_masklength, dst_masklength;
760 + addr_list *src_addrs, *dst_addrs;
761 + addr_list *src_addrs_remaining, *dst_addrs_remaining;
763 + src_addrs = acl_addrs(src_spec, &src_masklength, proxy_args, "source");
764 + if (is_nil_addr_list(src_addrs))
766 + log_error(LOG_LEVEL_ERROR, "Source of ACL resolves to no address",dst_spec);
769 + if (dst_spec != NULL)
771 + dst_addrs = acl_addrs(dst_spec, &dst_masklength, proxy_args, "destination");
772 + if (is_nil_addr_list(dst_addrs))
774 + log_error(LOG_LEVEL_ERROR, "Destination of ACL resolves to no address",dst_spec);
775 + destroy_addr_list(src_addrs);
782 + for(src_addrs_remaining = src_addrs;
783 + is_nil_addr_list(src_addrs);
784 + src_addrs_remaining=tail_addr_list(src_addrs_remaining))
786 + if (dst_addrs == NULL)
787 + l = add_one_to_acl_list(l, action, src_addrs_remaining, NULL, src_masklength,0);
788 + else for(dst_addrs_remaining = dst_addrs;
789 + is_nil_addr_list(dst_addrs);
790 + dst_addrs_remaining=tail_addr_list(dst_addrs_remaining))
791 + l = add_one_to_acl_list(l, action, src_addrs_remaining, dst_addrs_remaining,
792 + src_masklength, dst_masklength);
794 + destroy_addr_list(src_addrs);
795 + destroy_addr_list(dst_addrs);
799 -#endif /* def FEATURE_ACL */
801 +#endif /* def FEATURE_ACL */
803 /*********************************************************************
805 @@ -1048,7 +1324,7 @@
806 *********************************************************************/
807 struct http_response *redirect_url(struct client_state *csp)
811 struct http_response *rsp;
813 p = q = csp->http->path;
814 diff -urNad privoxy~/filters.h privoxy/filters.h
815 --- privoxy~/filters.h
816 +++ privoxy/filters.h
818 * Copyright : Written by and Copyright (C) 2001 the SourceForge
819 * Privoxy team. http://www.privoxy.org/
821 + * Modified by Lionel Elie Mamane <lionel@mamane.lu>
822 + * for IPv6 support on 8 December 2002, 24 January 2003.
824 * Based on the Internet Junkbuster originally written
825 * by and Copyright (C) 1997 Anonymous Coders and
826 * Junkbusters Corporation. http://www.junkbusters.com
830 extern int block_acl(struct access_control_addr *dst, struct client_state *csp);
831 -extern int acl_addr(char *aspec, struct access_control_addr *aca);
832 +extern struct access_control_list *add_to_acl_list(struct access_control_list *l,
836 + char **proxy_args);
837 #endif /* def FEATURE_ACL */
838 extern int match_portlist(const char *portlist, int port);
840 diff -urNad privoxy~/gateway.c privoxy/gateway.c
841 --- privoxy~/gateway.c
842 +++ privoxy/gateway.c
844 * Copyright : Written by and Copyright (C) 2001 the SourceForge
845 * Privoxy team. http://www.privoxy.org/
847 + * Modified by Lionel Elie Mamane <lionel@mamane.lu>
848 + * for IPv6 support on 8 December 2002, 24 January 2003.
850 * Based on the Internet Junkbuster originally written
851 * by and Copyright (C) 1997 Anonymous Coders and
852 * Junkbusters Corporation. http://www.junkbusters.com
853 @@ -199,12 +202,14 @@
854 * Returns : JB_INVALID_SOCKET => failure, else it is the socket file descriptor.
856 *********************************************************************/
857 -jb_socket forwarded_connect(const struct forward_spec * fwd,
858 +jb_socket forwarded_connect(const struct forward_spec *fwd,
859 struct http_request *http,
860 struct client_state *csp)
862 const char * dest_host;
864 + const char * dest_port_str;
865 + unsigned long dest_port;
868 /* Figure out if we need to connect to the web server or a HTTP proxy. */
869 if (fwd->forward_host)
870 @@ -212,19 +217,23 @@
872 dest_host = fwd->forward_host;
873 dest_port = fwd->forward_port;
874 + dest_port_str = fwd->forward_port_str;
875 + dest_pf = fwd->forward_family;
880 dest_host = http->host;
881 dest_port = http->port;
882 + dest_port_str = http->port_str;
883 + dest_pf = PF_UNSPEC;
886 /* Connect, maybe using a SOCKS proxy */
890 - return (connect_to(dest_host, dest_port, csp));
891 + return (connect_to(dest_host, dest_port_str, dest_port, dest_pf, csp));
895 @@ -258,74 +267,19 @@
896 * Returns : JB_INVALID_SOCKET => failure, else a socket file descriptor.
898 *********************************************************************/
899 -static jb_socket socks4_connect(const struct forward_spec * fwd,
900 - const char * target_host,
902 - struct client_state *csp)
903 +static jb_socket socks4_connect_one_ip(const struct forward_spec * fwd,
904 + unsigned long web_server_addr,
906 + struct client_state *csp,
910 - int web_server_addr;
911 - char cbuf[BUFFER_SIZE];
912 char sbuf[BUFFER_SIZE];
913 - struct socks_op *c = (struct socks_op *)cbuf;
914 struct socks_reply *s = (struct socks_reply *)sbuf;
917 + struct socks_reply *c = (struct socks_reply *)cbuf;
922 - if ((fwd->gateway_host == NULL) || (*fwd->gateway_host == '\0'))
924 - log_error(LOG_LEVEL_CONNECT, "socks4_connect: NULL gateway host specified");
928 - if (fwd->gateway_port <= 0)
930 - log_error(LOG_LEVEL_CONNECT, "socks4_connect: invalid gateway port specified");
937 - return(JB_INVALID_SOCKET);
940 - /* build a socks request for connection to the web server */
942 - strcpy((char *)&(c->userid), socks_userid);
944 - csiz = sizeof(*c) + sizeof(socks_userid) - 1;
949 - web_server_addr = htonl(resolve_hostname_to_ip(target_host));
950 - if (web_server_addr == INADDR_NONE)
952 - log_error(LOG_LEVEL_CONNECT, "socks4_connect: could not resolve target host %s", target_host);
953 - return(JB_INVALID_SOCKET);
957 - web_server_addr = 0x00000001;
958 - n = csiz + strlen(target_host) + 1;
959 - if (n > sizeof(cbuf))
962 - return(JB_INVALID_SOCKET);
964 - strcpy(cbuf + csiz, target_host);
968 - /* Should never get here */
969 - log_error(LOG_LEVEL_FATAL, "SOCKS4 impossible internal error - bad SOCKS type.");
971 - return(JB_INVALID_SOCKET);
976 c->dstport[0] = (target_port >> 8 ) & 0xff;
978 c->dstip[3] = (web_server_addr ) & 0xff;
980 /* pass the request to the socks server */
981 - sfd = connect_to(fwd->gateway_host, fwd->gateway_port, csp);
982 + sfd = connect_to(fwd->gateway_host, fwd->gateway_port_str, fwd->gateway_port, PF_INET ,csp);
984 if (sfd == JB_INVALID_SOCKET)
990 +static jb_socket socks4_connect(const struct forward_spec * fwd,
991 + const char * target_host,
993 + struct client_state *csp)
995 + char cbuf[BUFFER_SIZE];
996 + struct socks_op *c = (struct socks_op *)cbuf;
1001 + * SOCKS4 is IPv4-specific. At least I think so.
1003 + if ((fwd->gateway_host == NULL) || (*fwd->gateway_host == '\0'))
1005 + log_error(LOG_LEVEL_CONNECT, "socks4_connect: NULL gateway host specified");
1009 + if (fwd->gateway_port <= 0)
1011 + log_error(LOG_LEVEL_CONNECT, "socks4_connect: invalid gateway port specified");
1018 + return(JB_INVALID_SOCKET);
1021 + /* build a socks request for connection to the web server */
1023 + strcpy((char *)&(c->userid), socks_userid);
1025 + csiz = sizeof(*c) + sizeof(socks_userid) - 1;
1027 + switch (fwd->type)
1031 + addr_list *web_server_addrs = resolve_hostname_to_ip(target_host,NULL,PF_INET);
1032 + jb_socket return_value = JB_INVALID_SOCKET;
1033 + if (is_nil_addr_list(web_server_addrs))
1035 + log_error(LOG_LEVEL_CONNECT, "socks4_connect: could not resolve target host %s", target_host);
1039 + addr_list *addrs_to_try;
1041 + for(addrs_to_try = web_server_addrs;
1042 + !is_nil_addr_list(addrs_to_try);
1043 + addrs_to_try = tail_addr_list(addrs_to_try))
1045 + const unsigned long web_server_addr = ((struct sockaddr_in*) head_addr_list(addrs_to_try))->sin_addr.s_addr;
1046 + return_value=socks4_connect_one_ip(fwd, web_server_addr, target_port, csp, csiz, cbuf);
1047 + if(return_value != JB_INVALID_SOCKET)
1051 + destroy_addr_list(web_server_addrs);
1052 + return return_value;
1058 + n = csiz + strlen(target_host) + 1;
1059 + if (n > sizeof(cbuf))
1062 + return(JB_INVALID_SOCKET);
1064 + strcpy(cbuf + csiz, target_host);
1066 + return socks4_connect_one_ip(fwd, 0x00000001, target_port, csp, csiz, cbuf);
1070 + /* Should never get here */
1071 + log_error(LOG_LEVEL_FATAL, "SOCKS4 impossible internal error - bad SOCKS type.");
1073 + return(JB_INVALID_SOCKET);
1079 diff -urNad privoxy~/jb_socket_set.c privoxy/jb_socket_set.c
1080 --- privoxy~/jb_socket_set.c
1081 +++ privoxy/jb_socket_set.c
1083 +const char jb_socket_set_rcs[] = "$Id: $";
1084 +/*********************************************************************
1086 + * File : $Source: $
1088 + * Purpose : Declares functions to handle sets of sockets
1090 + * Copyright : Written by and Copyright (C) 2002 Lionel Elie Mamane
1091 + * <lionel@mamane.lu>
1093 + * This program is free software; you can redistribute it
1094 + * and/or modify it under the terms of the GNU General
1095 + * Public License as published by the Free Software
1096 + * Foundation; either version 2 of the License, or (at
1097 + * your option) any later version.
1099 + * This program is distributed in the hope that it will
1100 + * be useful, but WITHOUT ANY WARRANTY; without even the
1101 + * implied warranty of MERCHANTABILITY or FITNESS FOR A
1102 + * PARTICULAR PURPOSE. See the GNU General Public
1103 + * License for more details.
1105 + * The GNU General Public License should be included with
1106 + * this file. If not, you can view it at
1107 + * http://www.gnu.org/copyleft/gpl.html
1108 + * or write to the Free Software Foundation, Inc., 59
1109 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1112 + * $Log: jb_socket_set.c,v $
1114 + *********************************************************************/
1116 +#include "jb_socket_set.h"
1117 +#include <sys/time.h>
1118 +#include <sys/types.h>
1119 +#include <unistd.h>
1120 +#include "project.h"
1122 +/*********************************************************************
1124 + * Function : jb_socket_set_add
1126 + * Description : Add a socket to the set
1129 + * 0 : l = the set to add to
1130 + * 1 : the elemen to add to the set
1132 + * Returns : 0 on success
1133 + * non-0 on failure
1135 + *********************************************************************/
1137 +int jb_socket_set_add(jb_socket_set *l, jb_socket e)
1139 + if (l->data==NULL)
1142 + l->data=malloc(l->size * sizeof(jb_socket));
1143 + if (l->data==NULL)
1150 + l->data[(l->occupied)++] = e;
1151 + if (l->occupied == l->size)
1153 + jb_socket *new_data;
1155 + new_data = realloc(l->data,l->size * sizeof(jb_socket));
1156 + if (new_data == NULL)
1158 + /* Not enough memory to continue. Cancel changes. */
1159 + l->data[--(l->occupied)] = JB_INVALID_SOCKET;
1163 + l->data = new_data;
1165 + l->data[l->occupied] = JB_INVALID_SOCKET;
1169 +/*********************************************************************
1171 + * Function : destroy_jb_socket_set
1173 + * Description : Unallocate memory allocated to a socket set
1176 + * 0 : l = the set to unallocate
1178 + * Returns : nothing
1180 + *********************************************************************/
1181 +void destroy_jb_socket_set(jb_socket_set *l)
1184 + init_jb_socket_set(l);
1186 +/*********************************************************************
1188 + * Function : is_empty_jb_socket_set
1190 + * Description : Test wheter a set is empty
1193 + * 0 : l = the set to test
1195 + * Returns : 0 = false if set has a head,
1196 + * anything else = true if set is nil
1198 + *********************************************************************/
1199 +int is_nil_jb_socket_set(jb_socket_set *l)
1201 + return (l->occupied == 0);
1204 +/*********************************************************************
1206 + * Function : init_jb_socket_set
1208 + * Description : Init a set to empty
1211 + * 0 : l = the set to init
1213 + *********************************************************************/
1214 +void init_jb_socket_set(jb_socket_set *l)
1221 +/*********************************************************************
1223 + * Function : jb_socket_set_iteration_begin
1225 + * Description : Return an iterator on the set
1230 + *********************************************************************/
1231 +jb_socket_set_iterate_state jb_socket_set_iteration_begin(jb_socket_set *l)
1236 +/*********************************************************************
1238 + * Function : jb_socket_set_iteration_next
1240 + * Description : Return value pointed to by iterator and step
1241 + * iterator to next position
1244 + * 0 : s = the iterator
1246 + *********************************************************************/
1247 +jb_socket jb_socket_set_iteration_next(jb_socket_set_iterate_state*s)
1249 + return(*((*s)++));
1257 diff -urNad privoxy~/jb_socket_set.h privoxy/jb_socket_set.h
1258 --- privoxy~/jb_socket_set.h
1259 +++ privoxy/jb_socket_set.h
1261 +#ifndef JB_SOCKET_SET_H_INCLUDED
1262 +#define JB_SOCKET_SET_H_INCLUDED
1263 +#define JB_SOCKET_SET_H_VERSION "$Id: $"
1264 +/*********************************************************************
1266 + * File : $Source: $
1268 + * Purpose : Declares functions to handle sets of sockets
1270 + * Copyright : Written by and Copyright (C) 2002 Lionel Elie Mamane
1271 + * <lionel@mamane.lu>
1273 + * This program is free software; you can redistribute it
1274 + * and/or modify it under the terms of the GNU General
1275 + * Public License as published by the Free Software
1276 + * Foundation; either version 2 of the License, or (at
1277 + * your option) any later version.
1279 + * This program is distributed in the hope that it will
1280 + * be useful, but WITHOUT ANY WARRANTY; without even the
1281 + * implied warranty of MERCHANTABILITY or FITNESS FOR A
1282 + * PARTICULAR PURPOSE. See the GNU General Public
1283 + * License for more details.
1285 + * The GNU General Public License should be included with
1286 + * this file. If not, you can view it at
1287 + * http://www.gnu.org/copyleft/gpl.html
1288 + * or write to the Free Software Foundation, Inc., 59
1289 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1292 + * $Log: jb_socket_set.h,v $
1294 + *********************************************************************/
1295 +#include <sys/time.h>
1296 +#include <sys/types.h>
1297 +#include <unistd.h>
1298 +#include "project.h"
1300 +struct jb_socket_set_struct
1302 + unsigned int size; /* size allocated*/
1303 + unsigned int occupied; /* size occupied - 1 == index of final JB_INVALID_SOCKET
1304 + == number of sockets in the set */
1305 + jb_socket *data; /* Array containing the sockets, JB_INVALID_SOCKET-terminated */
1308 +typedef struct jb_socket_set_struct jb_socket_set;
1309 +typedef const jb_socket* jb_socket_set_iterate_state;
1311 +void init_jb_socket_set(jb_socket_set*);
1313 +jb_socket_set_iterate_state jb_socket_set_iteration_begin(jb_socket_set *);
1314 +jb_socket jb_socket_set_iteration_next(jb_socket_set_iterate_state*);
1316 +int jb_socket_set_add(jb_socket_set*, jb_socket);
1318 +void destroy_jb_socket_set(jb_socket_set *l);
1319 +int is_empty_jb_socket_set(jb_socket_set *l);
1321 +#define freez_jb_socket_set(X) { if(X) { destroy_jb_socket_set(X); X = NULL ; } }
1323 +int jb_select(jb_socket_set *readfds, jb_socket_set *writefds, jb_socket_set *exceptfds, struct timeval *timeout);
1325 +#endif /* ndef JB_SOCKET_SET_H_INCLUDED */
1332 diff -urNad privoxy~/jbsockets.c privoxy/jbsockets.c
1333 --- privoxy~/jbsockets.c
1334 +++ privoxy/jbsockets.c
1336 * Copyright : Written by and Copyright (C) 2001 the SourceForge
1337 * Privoxy team. http://www.privoxy.org/
1339 + * Modified by Lionel Elie Mamane <lionel@mamane.lu>
1340 + * for IPv6 support on 8-9 December 2002, 24 January 2003,
1341 + * 13 February 2003.
1343 * Based on the Internet Junkbuster originally written
1344 * by and Copyright (C) 1997 Anonymous Coders and
1345 * Junkbusters Corporation. http://www.junkbusters.com
1347 #include "jbsockets.h"
1348 #include "filters.h"
1350 +#include "addrlist.h"
1352 const char jbsockets_h_rcs[] = JBSOCKETS_H_VERSION;
1354 @@ -270,141 +275,194 @@
1355 * that this is allowed according to ACL.
1358 - * 1 : host = hostname to connect to
1359 - * 2 : portnum = port to connent on
1360 + * 0 : host = hostname to connect to
1361 + * 1 : port = port to connect on, as string
1362 + * 2 : portnum = port to connect on, as integer
1363 * 3 : csp = Current client state (buffers, headers, etc...)
1364 - * Not modified, only used for source IP and ACL.
1366 * Returns : JB_INVALID_SOCKET => failure, else it is the socket
1369 *********************************************************************/
1370 -jb_socket connect_to(const char *host, int portnum, struct client_state *csp)
1371 +jb_socket connect_to_one_ip(struct sockaddr_storage *addr, size_t addrlen, const char *host, unsigned long portnum, struct client_state *csp)
1373 - struct sockaddr_in inaddr;
1377 - struct timeval tv[1];
1378 -#if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA)
1380 -#endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) */
1383 - struct access_control_addr dst[1];
1384 -#endif /* def FEATURE_ACL */
1386 - memset((char *)&inaddr, 0, sizeof inaddr);
1388 - if ((addr = resolve_hostname_to_ip(host)) == INADDR_NONE)
1391 - csp->http->host_ip_addr_str = strdup("unknown");
1392 - return(JB_INVALID_SOCKET);
1394 + struct access_control_addr dst[1];
1395 + char hostname[NI_MAXHOST];
1396 + char port[NI_MAXSERV];
1397 + if (getnameinfo((struct sockaddr*)addr, addrlen, hostname, NI_MAXHOST,
1398 + port, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV) != 0)
1400 + log_error(LOG_LEVEL_ERROR, "connect: Could not get string address and port back from sockaddr because %E");
1401 + strncpy(hostname,"unknown",NI_MAXHOST);
1402 + strncpy(port,"unknown",NI_MAXSERV);
1406 - dst->addr = ntohl((unsigned long) addr);
1407 - dst->port = portnum;
1408 + csp->http->host_ip_addr_str = strdup(hostname);
1410 - if (block_acl(dst, csp))
1412 + dst->addr = *addr;
1413 + dst->addrlen = addrlen;
1414 + dst->port = portnum;
1416 + if (block_acl(dst, csp))
1425 - return(JB_INVALID_SOCKET);
1427 -#endif /* def FEATURE_ACL */
1428 + return(JB_INVALID_SOCKET);
1431 - inaddr.sin_addr.s_addr = addr;
1432 - inaddr.sin_family = AF_INET;
1433 - csp->http->host_ip_addr_str = strdup(inet_ntoa(inaddr.sin_addr));
1436 - if (sizeof(inaddr.sin_port) == sizeof(short))
1437 -#endif /* ndef _WIN32 */
1439 - inaddr.sin_port = htons((unsigned short) portnum);
1443 +#endif /* def FEATURE_ACL */
1446 - inaddr.sin_port = htonl((unsigned long)portnum);
1448 -#endif /* ndef _WIN32 */
1452 - if ((fd = socket(inaddr.sin_family, SOCK_STREAM, 0)) == JB_INVALID_SOCKET)
1453 + if ((fd = socket(addr->ss_family, SOCK_STREAM, 0)) == JB_INVALID_SOCKET)
1455 - if ((fd = socket(inaddr.sin_family, SOCK_STREAM, 0)) < 0)
1456 + if ((fd = socket(addr->ss_family, SOCK_STREAM, 6)) < 0)
1459 - return(JB_INVALID_SOCKET);
1462 + return(JB_INVALID_SOCKET);
1466 - { /* turn off TCP coalescence */
1468 - setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &mi, sizeof (int));
1470 + { /* turn off TCP coalescence */
1472 + setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, (char *) &mi, sizeof (int));
1474 #endif /* def TCP_NODELAY */
1476 #if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__)
1477 - if ((flags = fcntl(fd, F_GETFL, 0)) != -1)
1479 - flags |= O_NDELAY;
1480 - fcntl(fd, F_SETFL, flags);
1485 + if ((flags = fcntl(fd, F_GETFL, 0)) != -1)
1487 + flags |= O_NDELAY;
1488 + fcntl(fd, F_SETFL, flags);
1491 #endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) */
1493 - while (connect(fd, (struct sockaddr *) & inaddr, sizeof inaddr) == JB_INVALID_SOCKET)
1495 + while (connect(fd, (struct sockaddr *) addr, addrlen) == JB_INVALID_SOCKET)
1498 - if (errno == WSAEINPROGRESS)
1499 + if (errno == WSAEINPROGRESS)
1501 - if (sock_errno() == EINPROGRESS)
1502 + if (sock_errno() == EINPROGRESS)
1503 #else /* ifndef _WIN32 */
1504 - if (errno == EINPROGRESS)
1505 + if (errno == EINPROGRESS)
1506 #endif /* ndef _WIN32 || __OS2__ */
1515 - if (sock_errno() != EINTR)
1516 + if (sock_errno() != EINTR)
1518 - if (errno != EINTR)
1519 + if (errno != EINTR)
1520 #endif /* __OS2__ */
1523 + return(JB_INVALID_SOCKET);
1527 +#if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__)
1530 - return(JB_INVALID_SOCKET);
1532 + if ((flags = fcntl(fd, F_GETFL, 0)) != -1)
1534 + flags &= ~O_NDELAY;
1535 + fcntl(fd, F_SETFL, flags);
1539 +#endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) */
1543 + struct timeval tv[1];
1545 + /* wait for connection to complete */
1547 + FD_SET(fd, &wfds);
1552 + /* MS Windows uses int, not SOCKET, for the 1st arg of select(). Wierd! */
1553 + if (select((int)fd + 1, NULL, &wfds, NULL, tv) <= 0)
1556 + return(JB_INVALID_SOCKET);
1558 #if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__)
1561 - flags &= ~O_NDELAY;
1562 - fcntl(fd, F_SETFL, flags);
1566 + int connect_result;
1567 + socklen_t connect_result_len = sizeof connect_result;
1569 + if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &connect_result, &connect_result_len) != 0)
1571 + log_error(LOG_LEVEL_ERROR, "Could not determine whether connection to %s port %d was successful because %E. Assuming failure.",
1572 + csp->http->host_ip_addr_str, portnum);
1574 + return(JB_INVALID_SOCKET);
1576 + else if( connect_result != 0 )
1578 + log_error(LOG_LEVEL_CONNECT, "Connection to %s port %d failed because %s.",
1579 + csp->http->host_ip_addr_str, portnum, strerror(connect_result));
1581 + return(JB_INVALID_SOCKET);
1584 #endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) */
1590 - /* wait for connection to complete */
1592 - FD_SET(fd, &wfds);
1593 +jb_socket connect_to(const char *host, const char *port, unsigned long portnum, int pf, struct client_state *csp)
1595 + jb_socket fd = JB_INVALID_SOCKET;
1596 + struct sockaddr_storage addr;
1597 + addr_list *addrs, *addrs_to_try;
1601 + addrs = resolve_hostname_to_ip(host,port,pf);
1603 - /* MS Windows uses int, not SOCKET, for the 1st arg of select(). Wierd! */
1604 - if (select((int)fd + 1, NULL, &wfds, NULL, tv) <= 0)
1605 + if (is_nil_addr_list(addrs))
1608 - return(JB_INVALID_SOCKET);
1614 + for(addrs_to_try=addrs;
1615 + !is_nil_addr_list(addrs_to_try);
1616 + addrs_to_try = tail_addr_list(addrs_to_try))
1619 + memset((char *)&addr, 0, sizeof addr);
1620 + cpy_head_addr_list(addrs_to_try, &addr,&addrlen);
1621 + fd = connect_to_one_ip(&addr, addrlen, host, portnum, csp);
1622 + if (fd != JB_INVALID_SOCKET)
1626 + if (fd == JB_INVALID_SOCKET)
1628 + csp->http->host_ip_addr_str = strdup("unknown");
1631 + destroy_addr_list(addrs);
1636 @@ -544,55 +602,30 @@
1638 /*********************************************************************
1640 - * Function : bind_port
1641 + * Function : bind_port_one_ip
1643 * Description : Call socket, set socket options, and listen.
1644 - * Called by listen_loop to "boot up" our proxy address.
1647 - * 1 : hostnam = TCP/IP address to bind/listen to
1648 - * 2 : portnum = port to listen on
1649 - * 3 : pfd = pointer used to return file descriptor.
1650 + * 0 : addr = TCP/IP address and port to bind/listen to
1651 + * 1 : fds = jb_socket_set where the new socket should go
1653 - * Returns : if success, returns 0 and sets *pfd.
1654 + * Returns : if success returns 0 and adds sockets to fds.
1655 * if failure, returns -3 if address is in use,
1656 - * -2 if address unresolvable,
1657 + * -2 if memory error
1659 *********************************************************************/
1660 -int bind_port(const char *hostnam, int portnum, jb_socket *pfd)
1661 +int bind_port_one_ip(struct sockaddr *addr, const socklen_t addr_len, jb_socket_set *fds)
1663 - struct sockaddr_in inaddr;
1668 #endif /* ndef _WIN32 */
1670 - *pfd = JB_INVALID_SOCKET;
1672 - memset((char *)&inaddr, '\0', sizeof inaddr);
1674 - inaddr.sin_family = AF_INET;
1675 - inaddr.sin_addr.s_addr = resolve_hostname_to_ip(hostnam);
1677 - if (inaddr.sin_addr.s_addr == INADDR_NONE)
1683 - if (sizeof(inaddr.sin_port) == sizeof(short))
1684 -#endif /* ndef _WIN32 */
1686 - inaddr.sin_port = htons((unsigned short) portnum);
1691 - inaddr.sin_port = htonl((unsigned long) portnum);
1693 -#endif /* ndef _WIN32 */
1694 + fd = JB_INVALID_SOCKET;
1696 - fd = socket(AF_INET, SOCK_STREAM, 0);
1697 + fd = socket(addr->sa_family, SOCK_STREAM, 6);
1700 if (fd == JB_INVALID_SOCKET)
1701 @@ -618,8 +651,17 @@
1703 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one));
1704 #endif /* ndef _WIN32 */
1706 - if (bind(fd, (struct sockaddr *)&inaddr, sizeof(inaddr)) < 0)
1707 + /* As we are now listening on more than one socket,
1708 + * this is important: The only way to be sure accept
1711 + if ((flags = fcntl(fd, F_GETFL, 0)) != -1)
1713 + flags |= O_NONBLOCK;
1714 + fcntl(fd, F_SETFL, flags);
1717 + if (bind (fd, addr, addr_len) < 0)
1720 errno = WSAGetLastError();
1725 - while (listen(fd, 5) == -1)
1726 + while (listen(fd, 25) == -1)
1730 @@ -646,7 +688,11 @@
1735 + if (jb_socket_set_add(fds,fd) != 0)
1743 @@ -654,6 +700,91 @@
1745 /*********************************************************************
1747 + * Function : bind_port
1749 + * Description : Call bind_port_one_ip on all addresses host resolves to
1750 + * Called by listen_loop to "boot up" our proxy address.
1753 + * 0 : host = TCP/IP hostname to bind/listen to
1754 + * 1 : port = port to listen to, as string
1755 + * 2 : fds = socket set the sockets should be added to
1757 + * Returns : if success on at least one address resolving from hostnam,
1758 + * returns 0 and adds sockets to fds.
1759 + * if failure, returns non-zero
1760 + *********************************************************************/
1761 +int bind_port(const char *host, const char *port, int pf, jb_socket_set *fds)
1765 + struct sockaddr_storage addr;
1766 + struct sockaddr * const addr_addr = (struct sockaddr *)&addr;
1767 + addr_list *addrs, *addrs_to_try;
1769 + const char * const log_host = (host != NULL) ? host : "ADDR_ANY";
1771 + addrs = resolve_hostname_to_ip(host,port,pf);
1773 + if (is_nil_addr_list(addrs))
1774 + log_error(LOG_LEVEL_ERROR, "can't bind to %s:%s: "
1775 + "Name resolution didn't give any address",
1778 + log_error(LOG_LEVEL_INFO, "Binding to %s:%s...", log_host, port);
1780 + for(addrs_to_try=addrs;
1781 + !is_nil_addr_list(addrs_to_try);
1782 + addrs_to_try = tail_addr_list(addrs_to_try))
1784 + char numeric_hostname[NI_MAXHOST];
1785 + char numeric_port[NI_MAXSERV];
1787 + memset((char *)addr_addr, 0, sizeof addr);
1788 + cpy_head_addr_list(addrs_to_try, &addr, &addrlen);
1789 + result = getnameinfo(addr_addr, addrlen, numeric_hostname, NI_MAXHOST,
1790 + numeric_port, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV);
1793 + log_error(LOG_LEVEL_ERROR, "bind: Could not get string address and port back from sockaddr because %E");
1794 + strncpy(numeric_hostname,"unknown",NI_MAXHOST);
1795 + strncpy(numeric_port,"unknown",NI_MAXSERV);
1797 + result = bind_port_one_ip(addr_addr, addrlen, fds);
1801 + log_error(LOG_LEVEL_INFO, "Successfully bound to %s:%s", numeric_hostname, numeric_port);
1808 + log_error(LOG_LEVEL_ERROR, "can't bind to %s:%s (%s:%s): "
1809 + "There may be another Privoxy or some other "
1810 + "proxy running on port %s",
1811 + log_host, port, numeric_hostname, numeric_port, numeric_port);
1814 + log_error(LOG_LEVEL_ERROR, "can't bind to %s:%s (%s:%s): "
1816 + log_host, port, numeric_hostname, numeric_port);
1819 + log_error(LOG_LEVEL_ERROR, "can't bind to %s:%s: because %E",
1820 + log_host, numeric_port);
1825 + destroy_addr_list(addrs);
1830 +/*********************************************************************
1832 * Function : accept_connection
1834 * Description : Accepts a connection on a socket. Socket must have
1836 *********************************************************************/
1837 int accept_connection(struct client_state * csp, jb_socket fd)
1839 - struct sockaddr_in client, server;
1840 - struct hostent *host = NULL;
1841 + struct sockaddr_storage client, server;
1843 #if defined(_WIN32) || defined(__OS2__) || defined(__APPLE_CC__) || defined(AMIGA)
1844 /* Wierdness - fix a warning. */
1845 @@ -679,15 +809,7 @@
1847 socklen_t c_length, s_length;
1849 -#if defined(HAVE_GETHOSTBYADDR_R_8_ARGS) || defined(HAVE_GETHOSTBYADDR_R_7_ARGS) || defined(HAVE_GETHOSTBYADDR_R_5_ARGS)
1850 - struct hostent result;
1851 -#if defined(HAVE_GETHOSTBYADDR_R_5_ARGS)
1852 - struct hostent_data hdata;
1854 - char hbuf[HOSTENT_BUFFER_SIZE];
1856 -#endif /* def HAVE_GETHOSTBYADDR_R_5_ARGS */
1857 -#endif /* def HAVE_GETHOSTBYADDR_R_(8|7|5)_ARGS */
1860 c_length = s_length = sizeof(client);
1862 @@ -707,6 +829,12 @@
1866 + /* If we inherited O_NONBLOCK from the listening fd, unset it */
1867 + if ((flags = fcntl(fd, F_GETFL, 0)) != -1)
1869 + flags &= ~O_NONBLOCK;
1870 + fcntl(fd, F_SETFL, flags);
1874 * Determine the IP-Adress that the client used to reach us
1875 @@ -714,49 +842,50 @@
1877 if (!getsockname(afd, (struct sockaddr *) &server, &s_length))
1879 - csp->my_ip_addr_str = strdup(inet_ntoa(server.sin_addr));
1880 -#if defined(HAVE_GETHOSTBYADDR_R_8_ARGS)
1881 - gethostbyaddr_r((const char *)&server.sin_addr,
1882 - sizeof(server.sin_addr), AF_INET,
1883 - &result, hbuf, HOSTENT_BUFFER_SIZE,
1885 -#elif defined(HAVE_GETHOSTBYADDR_R_7_ARGS)
1886 - host = gethostbyaddr_r((const char *)&server.sin_addr,
1887 - sizeof(server.sin_addr), AF_INET,
1888 - &result, hbuf, HOSTENT_BUFFER_SIZE, &thd_err);
1889 -#elif defined(HAVE_GETHOSTBYADDR_R_5_ARGS)
1890 - if (0 == gethostbyaddr_r((const char *)&server.sin_addr,
1891 - sizeof(server.sin_addr), AF_INET,
1893 + char hostname[NI_MAXHOST];
1894 + char port[NI_MAXSERV];
1896 + if (getnameinfo((struct sockaddr *)&server, s_length, hostname, NI_MAXHOST,
1897 + port, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV) != 0)
1900 + log_error(LOG_LEVEL_ERROR, "accept: Could not get string address and port back from server sockaddr because %E");
1901 + strncpy(hostname,"unknown IP",NI_MAXHOST);
1902 + strncpy(port,"unknown port",NI_MAXSERV);
1905 + csp->my_ip_addr_str = strdup(hostname);
1906 + csp->my_port_str = strdup(port);
1908 + if (getnameinfo((struct sockaddr *)&server, s_length, hostname, NI_MAXHOST, NULL, 0, NI_NAMEREQD) != 0)
1911 + log_error(LOG_LEVEL_ERROR, "accept: Could not get my own hostname because %E");
1912 + strncpy(hostname,"unknown host",NI_MAXHOST);
1914 -#elif defined(OSX_DARWIN)
1915 - pthread_mutex_lock(&gethostbyaddr_mutex);
1916 - host = gethostbyaddr((const char *)&server.sin_addr,
1917 - sizeof(server.sin_addr), AF_INET);
1918 - pthread_mutex_unlock(&gethostbyaddr_mutex);
1920 - host = gethostbyaddr((const char *)&server.sin_addr,
1921 - sizeof(server.sin_addr), AF_INET);
1924 + csp->my_hostname = strdup(hostname);
1928 + log_error(LOG_LEVEL_ERROR, "accept: Could not get sockaddr from socket fd because %E");
1933 + char hostname[NI_MAXHOST];
1935 + if (getnameinfo((struct sockaddr *)&client, c_length, hostname, NI_MAXHOST, NULL, 0, NI_NUMERICHOST) != 0)
1937 - log_error(LOG_LEVEL_ERROR, "Unable to get my own hostname: %E\n");
1938 + log_error(LOG_LEVEL_ERROR, "accept: Could not get client IP address string because %E");
1939 + strncpy(hostname,"unknown IP",NI_MAXHOST);
1942 + csp->my_ip_addr_str = strdup(hostname);
1944 + if (getnameinfo((struct sockaddr *)&server, s_length, hostname, NI_MAXHOST, NULL, 0, 0) != 0)
1946 - csp->my_hostname = strdup(host->h_name);
1947 + log_error(LOG_LEVEL_ERROR, "accept: Could not get my own hostname because %E");
1948 + strncpy(hostname,"unknown host",NI_MAXHOST);
1950 + csp->ip_addr_str = strdup(hostname);
1954 - csp->ip_addr_str = strdup(inet_ntoa(client.sin_addr));
1955 - csp->ip_addr_long = ntohl(client.sin_addr.s_addr);
1956 + csp->ip_addr_addr = client;
1960 @@ -767,90 +896,41 @@
1962 * Function : resolve_hostname_to_ip
1964 - * Description : Resolve a hostname to an internet tcp/ip address.
1965 - * NULL or an empty string resolve to INADDR_ANY.
1966 + * Description : Resolve a hostname to a list of internet tcp/ip addresses.
1969 - * 1 : host = hostname to resolve
1970 + * 0 : host = hostname to resolve
1971 + * 1 : result = where to store the result
1972 + * 2 : pf = preferred address family. PF_UNSPEC for no preference (recommended).
1974 - * Returns : INADDR_NONE => failure, INADDR_ANY or tcp/ip address if succesful.
1975 + * Returns : A (possibly empty) list of adresses
1977 *********************************************************************/
1978 -unsigned long resolve_hostname_to_ip(const char *host)
1979 +addr_list *resolve_hostname_to_ip(const char *host, const char *port, int pf)
1981 - struct sockaddr_in inaddr;
1982 - struct hostent *hostp;
1983 -#if defined(HAVE_GETHOSTBYNAME_R_6_ARGS) || defined(HAVE_GETHOSTBYNAME_R_5_ARGS) || defined(HAVE_GETHOSTBYNAME_R_3_ARGS)
1984 - struct hostent result;
1985 -#if defined(HAVE_GETHOSTBYNAME_R_6_ARGS) || defined(HAVE_GETHOSTBYNAME_R_5_ARGS)
1986 - char hbuf[HOSTENT_BUFFER_SIZE];
1988 -#else /* defined(HAVE_GETHOSTBYNAME_R_3_ARGS) */
1989 - struct hostent_data hdata;
1990 -#endif /* def HAVE_GETHOSTBYNAME_R_(6|5)_ARGS */
1991 -#endif /* def HAVE_GETHOSTBYNAME_R_(6|5|3)_ARGS */
1993 - if ((host == NULL) || (*host == '\0'))
1995 - return(INADDR_ANY);
1998 - memset((char *) &inaddr, 0, sizeof inaddr);
2000 + * Do all supported platforms have "getaddrinfo"?
2003 + struct addrinfo hints, *res0;
2005 + memset(&hints, 0, sizeof(hints));
2006 + hints.ai_family = pf;
2007 + hints.ai_socktype = SOCK_STREAM;
2009 - if ((inaddr.sin_addr.s_addr = inet_addr(host)) == -1)
2010 + result = getaddrinfo(host, port, &hints, &res0);
2011 + if ( result != 0 )
2013 -#if defined(HAVE_GETHOSTBYNAME_R_6_ARGS)
2014 - gethostbyname_r(host, &result, hbuf,
2015 - HOSTENT_BUFFER_SIZE, &hostp, &thd_err);
2016 -#elif defined(HAVE_GETHOSTBYNAME_R_5_ARGS)
2017 - hostp = gethostbyname_r(host, &result, hbuf,
2018 - HOSTENT_BUFFER_SIZE, &thd_err);
2019 -#elif defined(HAVE_GETHOSTBYNAME_R_3_ARGS)
2020 - if (0 == gethostbyname_r(host, &result, &hdata))
2029 - pthread_mutex_lock(&gethostbyname_mutex);
2030 - hostp = gethostbyname(host);
2031 - pthread_mutex_unlock(&gethostbyname_mutex);
2033 - hostp = gethostbyname(host);
2034 -#endif /* def HAVE_GETHOSTBYNAME_R_(6|5|3)_ARGS */
2036 - * On Mac OSX, if a domain exists but doesn't have a type A
2037 - * record associated with it, the h_addr member of the struct
2038 - * hostent returned by gethostbyname is NULL, even if h_length
2039 - * is 4. Therefore the second test below.
2041 - if (hostp == NULL || hostp->h_addr == NULL)
2044 - log_error(LOG_LEVEL_ERROR, "could not resolve hostname %s", host);
2045 - return(INADDR_NONE);
2047 - if (hostp->h_addrtype != AF_INET)
2050 - errno = WSAEPROTOTYPE;
2052 - errno = EPROTOTYPE;
2054 - log_error(LOG_LEVEL_ERROR, "hostname %s resolves to unknown address type.", host);
2055 - return(INADDR_NONE);
2058 - (char *) &inaddr.sin_addr,
2059 - (char *) hostp->h_addr,
2060 - sizeof(inaddr.sin_addr)
2062 + log_error(LOG_LEVEL_ERROR, "could not resolve hostname %s because %s", host,gai_strerror(result));
2063 + if (result == EAI_SYSTEM)
2064 + log_error(LOG_LEVEL_ERROR, "The system error is %E");
2067 - return(inaddr.sin_addr.s_addr);
2070 + log_error(LOG_LEVEL_ERROR, "Problem in resolving hostname %s: succeeded, but no information returned", host);
2076 diff -urNad privoxy~/jbsockets.h privoxy/jbsockets.h
2077 --- privoxy~/jbsockets.h
2078 +++ privoxy/jbsockets.h
2080 * Copyright : Written by and Copyright (C) 2001 the SourceForge
2081 * Privoxy team. http://www.privoxy.org/
2083 + * Modified by Lionel Elie Mamane <lionel@mamane.lu>
2084 + * for IPv6 support on 8 December 2002, 24 January 2003.
2086 * Based on the Internet Junkbuster originally written
2087 * by and Copyright (C) 1997 Anonymous Coders and
2088 * Junkbusters Corporation. http://www.junkbusters.com
2089 @@ -100,9 +103,11 @@
2093 +#include "addrlist.h"
2095 struct client_state;
2097 -extern jb_socket connect_to(const char *host, int portnum, struct client_state *csp);
2098 +extern jb_socket connect_to(const char *host, const char *port, unsigned long portnum, int pf, struct client_state *csp);
2100 extern int write_socket(jb_socket fd, const char *buf, ssize_t n);
2102 @@ -111,10 +116,10 @@
2103 extern int read_socket(jb_socket fd, char *buf, int n);
2104 extern void close_socket(jb_socket fd);
2106 -extern int bind_port(const char *hostnam, int portnum, jb_socket *pfd);
2107 +extern int bind_port(const char *host, const char *port, int pf, jb_socket_set *fds);
2108 extern int accept_connection(struct client_state * csp, jb_socket fd);
2110 -extern unsigned long resolve_hostname_to_ip(const char *host);
2111 +extern addr_list *resolve_hostname_to_ip(const char *host, const char *port, int pf);
2113 /* Revision control strings from this header and associated .c file */
2114 extern const char jbsockets_rcs[];
2115 diff -urNad privoxy~/jcc.c privoxy/jcc.c
2120 #include "loadcfg.h"
2121 #include "urlmatch.h"
2122 +#include "jb_socket_set.h"
2124 const char jcc_h_rcs[] = JCC_H_VERSION;
2125 const char project_h_rcs[] = PROJECT_H_VERSION;
2126 @@ -2112,61 +2113,78 @@
2127 * Returns : Port that was opened.
2129 *********************************************************************/
2130 -static jb_socket bind_port_helper(struct configuration_spec * config)
2131 +static void bind_port_helper(struct configuration_spec * config, jb_socket_set *bfds)
2135 + struct bind_spec *bs;
2136 + unsigned int bs_index;
2139 - if ( (config->haddr != NULL)
2140 - && (config->haddr[0] == '1')
2141 - && (config->haddr[1] == '2')
2142 - && (config->haddr[2] == '7')
2143 - && (config->haddr[3] == '.') )
2145 - log_error(LOG_LEVEL_INFO, "Listening on port %d for local connections only",
2148 - else if (config->haddr == NULL)
2150 - log_error(LOG_LEVEL_INFO, "Listening on port %d on all IP addresses",
2155 + for (bs_index = 0; bs_index < config->hspecs_occupied;++bs_index)
2157 - log_error(LOG_LEVEL_INFO, "Listening on port %d on IP address %s",
2158 - config->hport, config->haddr);
2160 + bs = &config->hspecs[bs_index];
2162 + /* This check misses about a trillion zillion different manners to describe
2163 + the local interface in IPv6. Who cares? */
2164 + if ( (bs->haddr != NULL)
2165 + && (((bs->haddr[0] == '1')
2166 + && (bs->haddr[1] == '2')
2167 + && (bs->haddr[2] == '7')
2168 + && (bs->haddr[3] == '.'))
2169 + || ((bs->haddr[0] == ':')
2170 + && (bs->haddr[1] == ':')
2171 + && (bs->haddr[2] == '1'))))
2173 + log_error(LOG_LEVEL_INFO, "Listening on port %s for local connections only",
2176 + else if (bs->haddr == NULL || bs->haddr[0]=='\0')
2178 + log_error(LOG_LEVEL_INFO, "Listening on port %s on all IP addresses",
2183 + log_error(LOG_LEVEL_INFO, "Listening on port %s on IP address %s",
2184 + bs->hport, bs->haddr);
2187 - result = bind_port(config->haddr, config->hport, &bfd);
2188 + result = bind_port(bs->haddr, bs->hport, bs->pf, bfds);
2198 - log_error(LOG_LEVEL_FATAL, "can't bind to %s:%d: "
2199 + log_error(LOG_LEVEL_ERROR, "can't bind to %s:%s: "
2200 "There may be another Privoxy or some other "
2201 - "proxy running on port %d",
2202 - (NULL != config->haddr) ? config->haddr : "INADDR_ANY",
2203 - config->hport, config->hport);
2204 + "proxy running on port %s",
2205 + (NULL != bs->haddr) ? bs->haddr : "INADDR_ANY",
2206 + bs->hport, bs->hport);
2210 - log_error(LOG_LEVEL_FATAL, "can't bind to %s:%d: "
2211 + log_error(LOG_LEVEL_ERROR, "can't bind to %s:%s: "
2212 "The hostname is not resolvable",
2213 - (NULL != config->haddr) ? config->haddr : "INADDR_ANY", config->hport);
2214 + (NULL != bs->haddr) ? bs->haddr : "INADDR_ANY", bs->hport);
2218 - log_error(LOG_LEVEL_FATAL, "can't bind to %s:%d: because %E",
2219 - (NULL != config->haddr) ? config->haddr : "INADDR_ANY", config->hport);
2220 + log_error(LOG_LEVEL_ERROR, "can't bind to %s:%s: because %E",
2221 + (NULL != bs->haddr) ? bs->haddr : "INADDR_ANY", bs->hport);
2230 + log_error(LOG_LEVEL_FATAL, "Couldn't bind at all - bailing out");
2231 /* shouldn't get here */
2232 - return JB_INVALID_SOCKET;
2235 config->need_bind = 0;
2241 @@ -2184,12 +2202,18 @@
2242 static void listen_loop(void)
2244 struct client_state *csp = NULL;
2246 + jb_socket_set bfds;
2248 + jb_socket_set_iterate_state bfds_iterate_state;
2249 + jb_socket bfd_current;
2250 struct configuration_spec * config;
2252 + init_jb_socket_set(&bfds);
2254 config = load_config();
2256 - bfd = bind_port_helper(config);
2257 + bind_port_helper(config,&bfds);
2258 + bfd_current=JB_INVALID_SOCKET;
2260 #ifdef FEATURE_GRACEFUL_TERMINATION
2261 while (!g_terminate)
2262 @@ -2263,14 +2287,55 @@
2263 * that this will hurt people's feelings.
2266 - close_socket(bfd);
2267 + jb_socket_set_iterate_state s;
2269 + s=jb_socket_set_iteration_begin(&bfds);
2270 + for(bfd=jb_socket_set_iteration_next(&s);bfd!=JB_INVALID_SOCKET;bfd=jb_socket_set_iteration_next(&s))
2272 + close_socket(bfd);
2274 + destroy_jb_socket_set(&bfds);
2275 + bind_port_helper(config,&bfds);
2276 + /* We have a new set of fd's to accept. Restart iteration over bfds. */
2277 + bfd_current = JB_INVALID_SOCKET;
2280 - bfd = bind_port_helper(config);
2281 + /* Here: select call on listening sockets: bfd=sockets */
2282 + if (bfd_current == JB_INVALID_SOCKET)
2285 + log_error(LOG_LEVEL_CONNECT, "select connections ... ");
2286 + bfds_iterate_state=jb_socket_set_iteration_begin(&bfds);
2287 + FD_ZERO(&bfds_fs);
2289 + for(bfd_current=jb_socket_set_iteration_next(&bfds_iterate_state);
2290 + bfd_current!=JB_INVALID_SOCKET;
2291 + bfd_current=jb_socket_set_iteration_next(&bfds_iterate_state))
2293 + FD_SET(bfd_current,&bfds_fs);
2294 + if (bfd_current >= max)
2295 + max = bfd_current + 1;
2297 + if(!select(max,&bfds_fs,NULL,NULL,NULL))
2299 + log_error(LOG_LEVEL_CONNECT, "select failed: %E");
2300 + bfd_current=JB_INVALID_SOCKET;
2303 + log_error(LOG_LEVEL_CONNECT, "OK");
2304 + bfds_iterate_state=jb_socket_set_iteration_begin(&bfds);
2305 + bfd_current=jb_socket_set_iteration_next(&bfds_iterate_state);
2307 + if (!FD_ISSET(bfd_current,&bfds_fs))
2309 + bfd_current=jb_socket_set_iteration_next(&bfds_iterate_state);
2314 log_error(LOG_LEVEL_CONNECT, "accept connection ... ");
2316 - if (!accept_connection(csp, bfd))
2317 + if (!accept_connection(csp, bfd_current))
2319 log_error(LOG_LEVEL_CONNECT, "accept failed: %E");
2321 @@ -2288,6 +2353,8 @@
2322 log_error(LOG_LEVEL_CONNECT, "OK");
2325 + bfd_current=jb_socket_set_iteration_next(&bfds_iterate_state);
2327 #ifdef FEATURE_TOGGLE
2328 if (global_toggle_state)
2330 diff -urNad privoxy~/loadcfg.c privoxy/loadcfg.c
2331 --- privoxy~/loadcfg.c
2332 +++ privoxy/loadcfg.c
2334 * Copyright : Written by and Copyright (C) 2001 the SourceForge
2335 * Privoxy team. http://www.privoxy.org/
2337 + * Modified by Lionel Elie Mamane <lionel@mamane.lu>
2338 + * for IPv6 support on 8 December 2002, 24 January 2003.
2340 * Based on the Internet Junkbuster originally written
2341 * by and Copyright (C) 1997 Anonymous Coders and
2342 * Junkbusters Corporation. http://www.junkbusters.com
2345 #include "urlmatch.h"
2347 +#include "parsers.h"
2349 const char loadcfg_h_rcs[] = LOADCFG_H_VERSION;
2352 struct forward_spec * next_fwd = cur_fwd->next;
2353 free_url_spec(cur_fwd->url);
2355 - freez(cur_fwd->gateway_host);
2356 - freez(cur_fwd->forward_host);
2357 + freez(cur_fwd->gateway_malloc);
2358 + freez(cur_fwd->forward_malloc);
2362 @@ -507,7 +511,16 @@
2363 freez(config->confdir);
2364 freez(config->logdir);
2366 - freez(config->haddr);
2367 + if(config -> hspecs != NULL)
2370 + for (i=0; i < config->hspecs_occupied; ++i)
2372 + freez(config->hspecs[i].haddr);
2373 + freez(config->hspecs[i].hport);
2376 + freez(config->hspecs);
2377 freez(config->logfile);
2379 for (i = 0; i < MAX_ACTION_FILES; i++)
2380 @@ -570,6 +583,28 @@
2381 * Returns : The configuration_spec, or NULL on error.
2383 *********************************************************************/
2384 +static void fail_load_config_memory(struct file_list *fs, struct configuration_spec *config)
2386 + freez(fs->filename);
2388 + if (config != NULL)
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);
2402 + log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
2403 + /* Never get here - LOG_LEVEL_FATAL causes program exit */
2406 struct configuration_spec * load_config(void)
2408 char buf[BUFFER_SIZE];
2409 @@ -601,12 +636,7 @@
2410 fs->f = config = (struct configuration_spec *)zalloc(sizeof(*config));
2414 - freez(fs->filename);
2416 - log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
2417 - /* Never get here - LOG_LEVEL_FATAL causes program exit */
2419 + fail_load_config_memory(fs,config);
2422 * This is backwards from how it's usually done.
2426 config->multi_threaded = 1;
2427 - config->hport = HADDR_PORT;
2428 + config->hspecs = NULL;
2429 config->buffer_limit = 4096 * 1024;
2430 config->usermanual = strdup(USER_MANUAL_URL);
2431 config->proxy_args = strdup("");
2433 char cmd[BUFFER_SIZE];
2434 char arg[BUFFER_SIZE];
2435 char tmp[BUFFER_SIZE];
2437 - struct access_control_list *cur_acl;
2438 -#endif /* def FEATURE_ACL */
2439 struct forward_spec *cur_fwd;
2442 @@ -753,74 +780,23 @@
2443 * *************************************************************************/
2445 case hash_deny_access:
2446 - vec_count = ssplit(arg, " \t", vec, SZ(vec), 1, 1);
2448 - if ((vec_count != 1) && (vec_count != 2))
2450 - log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
2451 - "deny-access directive in configuration file.");
2452 - string_append(&config->proxy_args,
2453 - "<br>\nWARNING: Wrong number of parameters for "
2454 - "deny-access directive in configuration file.<br><br>\n");
2458 - /* allocate a new node */
2459 - cur_acl = (struct access_control_list *) zalloc(sizeof(*cur_acl));
2461 - if (cur_acl == NULL)
2463 - log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
2464 - /* Never get here - LOG_LEVEL_FATAL causes program exit */
2467 - cur_acl->action = ACL_DENY;
2469 - if (acl_addr(vec[0], cur_acl->src) < 0)
2471 - log_error(LOG_LEVEL_ERROR, "Invalid source IP for deny-access "
2472 - "directive in configuration file: \"%s\"", vec[0]);
2473 - string_append(&config->proxy_args,
2474 - "<br>\nWARNING: Invalid source IP for deny-access directive"
2475 - " in configuration file: \"");
2476 - string_append(&config->proxy_args,
2478 - string_append(&config->proxy_args,
2483 - if (vec_count == 2)
2484 + switch (ssplit(arg, " \t", vec, SZ(vec), 1, 1))
2486 - if (acl_addr(vec[1], cur_acl->dst) < 0)
2488 - log_error(LOG_LEVEL_ERROR, "Invalid destination IP for deny-access "
2489 - "directive in configuration file: \"%s\"", vec[0]);
2490 - string_append(&config->proxy_args,
2491 - "<br>\nWARNING: Invalid destination IP for deny-access directive"
2492 - " in configuration file: \"");
2493 - string_append(&config->proxy_args,
2496 + config->acl = add_to_acl_list(config->acl, ACL_DENY, vec[0], NULL, &config->proxy_args);
2499 + config->acl = add_to_acl_list(config->acl, ACL_DENY, vec[0], vec[1], &config->proxy_args);
2502 + log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
2503 + "deny-access directive in configuration file.");
2504 string_append(&config->proxy_args,
2509 + "<br>\nWARNING: Wrong number of parameters for "
2510 + "deny-access directive in configuration file.<br><br>\n");
2514 - * Add it to the list. Note we reverse the list to get the
2515 - * behaviour the user expects. With both the ACL and
2516 - * actions file, the last match wins. However, the internal
2517 - * implementations are different: The actions file is stored
2518 - * in the same order as the file, and scanned completely.
2519 - * With the ACL, we reverse the order as we load it, then
2520 - * when we scan it we stop as soon as we get a match.
2522 - cur_acl->next = config->acl;
2523 - config->acl = cur_acl;
2527 #endif /* def FEATURE_ACL */
2529 /* *************************************************************************
2530 @@ -914,16 +890,18 @@
2532 if (strcmp(p, ".") != 0)
2534 - cur_fwd->forward_host = strdup(p);
2535 + cur_fwd->forward_malloc = strdup(p);
2536 + cur_fwd->forward_family = -1;
2538 - if (NULL != (p = strchr(cur_fwd->forward_host, ':')))
2541 - cur_fwd->forward_port = atoi(p);
2543 + parse_pf_ip(cur_fwd->forward_malloc,
2544 + &cur_fwd->forward_host,
2545 + &cur_fwd->forward_port_str,
2546 + &cur_fwd->forward_family);
2547 + cur_fwd->forward_port = atoi(cur_fwd->forward_port_str);
2549 if (cur_fwd->forward_port <= 0)
2551 + cur_fwd->forward_port_str = "8000";
2552 cur_fwd->forward_port = 8000;
2555 @@ -977,15 +955,27 @@
2557 if (strcmp(p, ".") != 0)
2559 - cur_fwd->gateway_host = strdup(p);
2560 + /* SOCKS is IPv4-specific */
2563 - if (NULL != (p = strchr(cur_fwd->gateway_host, ':')))
2564 + cur_fwd->gateway_malloc = strdup(p);
2565 + if (parse_pf_ip(cur_fwd->gateway_malloc,
2566 + &cur_fwd->gateway_host,
2567 + &cur_fwd->gateway_port_str,
2571 - cur_fwd->gateway_port = atoi(p);
2572 + log_error(LOG_LEVEL_ERROR, "Could not parse forward-socks4 host: %s",p);
2573 + cur_fwd->gateway_host = NULL;
2574 + cur_fwd->gateway_port_str = NULL;
2575 + freez(cur_fwd->gateway_malloc);
2579 + cur_fwd->gateway_port = atoi(cur_fwd->gateway_port_str);
2581 if (cur_fwd->gateway_port <= 0)
2583 + cur_fwd->gateway_port_str = "1080";
2584 cur_fwd->gateway_port = 1080;
2587 @@ -995,16 +985,26 @@
2589 if (strcmp(p, ".") != 0)
2591 - cur_fwd->forward_host = strdup(p);
2592 + cur_fwd->forward_malloc = strdup(p);
2593 + cur_fwd->forward_family = -1;
2595 - if (NULL != (p = strchr(cur_fwd->forward_host, ':')))
2596 + parse_pf_ip(cur_fwd->forward_malloc,
2597 + &cur_fwd->forward_host,
2598 + &cur_fwd->forward_port_str,
2599 + &cur_fwd->forward_family);
2600 + cur_fwd->forward_port = atoi(cur_fwd->forward_port_str);
2602 + if (cur_fwd->forward_port <= 0)
2605 - cur_fwd->forward_port = atoi(p);
2606 + cur_fwd->forward_port_str = "8000";
2607 + cur_fwd->forward_port = 8000;
2610 + cur_fwd->forward_port = atoi(p);
2612 if (cur_fwd->forward_port <= 0)
2614 + cur_fwd->forward_port_str = "8000";
2615 cur_fwd->forward_port = 8000;
2618 @@ -1056,16 +1056,30 @@
2619 /* Parse the SOCKS proxy host[:port] */
2622 - cur_fwd->gateway_host = strdup(p);
2624 - if (NULL != (p = strchr(cur_fwd->gateway_host, ':')))
2627 - cur_fwd->gateway_port = atoi(p);
2629 - if (cur_fwd->gateway_port <= 0)
2631 - cur_fwd->gateway_port = 1080;
2632 + /* SOCKS is IPv4-specific */
2635 + cur_fwd->gateway_malloc = strdup(p);
2636 + if (parse_pf_ip(cur_fwd->gateway_malloc,
2637 + &cur_fwd->gateway_host,
2638 + &cur_fwd->gateway_port_str,
2641 + log_error(LOG_LEVEL_ERROR, "Could not parse forward-socks4a host: %s",p);
2642 + cur_fwd->gateway_host = NULL;
2643 + cur_fwd->gateway_port_str = NULL;
2644 + freez(cur_fwd->gateway_malloc);
2648 + cur_fwd->gateway_port = atoi(cur_fwd->gateway_port_str);
2650 + if (cur_fwd->gateway_port <= 0)
2652 + cur_fwd->gateway_port_str = "1080";
2653 + cur_fwd->gateway_port = 1080;
2657 /* Parse the parent HTTP proxy host[:port] */
2658 @@ -1073,16 +1087,26 @@
2660 if (strcmp(p, ".") != 0)
2662 - cur_fwd->forward_host = strdup(p);
2663 + cur_fwd->forward_malloc = strdup(p);
2664 + cur_fwd->forward_family = -1;
2666 - if (NULL != (p = strchr(cur_fwd->forward_host, ':')))
2667 + parse_pf_ip(cur_fwd->forward_malloc,
2668 + &cur_fwd->forward_host,
2669 + &cur_fwd->forward_port_str,
2670 + &cur_fwd->forward_family);
2671 + cur_fwd->forward_port = atoi(cur_fwd->forward_port_str);
2673 + if (cur_fwd->forward_port <= 0)
2676 - cur_fwd->forward_port = atoi(p);
2677 + cur_fwd->forward_port_str = "8000";
2678 + cur_fwd->forward_port = 8000;
2681 + cur_fwd->forward_port = atoi(p);
2683 if (cur_fwd->forward_port <= 0)
2685 + cur_fwd->forward_port_str = "8000";
2686 cur_fwd->forward_port = 8000;
2689 @@ -1108,10 +1132,49 @@
2690 * listen-address [ip][:port]
2691 * *************************************************************************/
2692 case hash_listen_address :
2693 - freez(config->haddr);
2694 - config->haddr = strdup(arg);
2696 + struct bind_spec *bs;
2698 + if (config->hspecs == NULL)
2700 + /* This is the first we'll bind to */
2701 + config->hspecs = calloc(2,sizeof(struct bind_spec));
2702 + if (config->hspecs == NULL)
2703 + fail_load_config_memory(fs,config);
2704 + config->hspecs_size = 2;
2705 + config->hspecs_occupied = 0;
2708 + arg_cpy = strdup(arg);
2709 + if (arg_cpy == NULL)
2710 + fail_load_config_memory(fs,config);
2711 + if (config->hspecs_occupied == config->hspecs_size)
2713 + struct bind_spec *new_hspecs;
2714 + config->hspecs_size *= 2;
2715 + new_hspecs = realloc(config->hspecs,config->hspecs_size * sizeof(struct bind_spec));
2716 + if (new_hspecs == NULL)
2718 + /* Not enough memory to continue. Cancel changes. */
2719 + config->hspecs_size /= 2;
2720 + fail_load_config_memory(fs,config);
2722 + config->hspecs = new_hspecs;
2724 + bs = &config->hspecs[(config->hspecs_occupied)++];
2726 + parse_pf_ip(arg,&bs->haddr,&bs->hport,&bs->pf);
2727 + if (*bs->haddr == '\0')
2733 + (bs->haddr = strdup(bs->haddr));
2735 + bs->hport = strdup(bs->hport);
2739 /* *************************************************************************
2740 * logdir directory-name
2741 * *************************************************************************/
2742 @@ -1134,75 +1197,21 @@
2743 * *************************************************************************/
2745 case hash_permit_access:
2746 - vec_count = ssplit(arg, " \t", vec, SZ(vec), 1, 1);
2748 - if ((vec_count != 1) && (vec_count != 2))
2750 - log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
2751 - "permit-access directive in configuration file.");
2752 - string_append(&config->proxy_args,
2753 - "<br>\nWARNING: Wrong number of parameters for "
2754 - "permit-access directive in configuration file.<br><br>\n");
2759 - /* allocate a new node */
2760 - cur_acl = (struct access_control_list *) zalloc(sizeof(*cur_acl));
2762 - if (cur_acl == NULL)
2764 - log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
2765 - /* Never get here - LOG_LEVEL_FATAL causes program exit */
2768 - cur_acl->action = ACL_PERMIT;
2770 - if (acl_addr(vec[0], cur_acl->src) < 0)
2772 - log_error(LOG_LEVEL_ERROR, "Invalid source IP for permit-access "
2773 - "directive in configuration file: \"%s\"", vec[0]);
2774 - string_append(&config->proxy_args,
2775 - "<br>\nWARNING: Invalid source IP for permit-access directive"
2776 - " in configuration file: \"");
2777 - string_append(&config->proxy_args,
2779 - string_append(&config->proxy_args,
2784 - if (vec_count == 2)
2785 + switch (ssplit(arg, " \t", vec, SZ(vec), 1, 1))
2787 - if (acl_addr(vec[1], cur_acl->dst) < 0)
2789 - log_error(LOG_LEVEL_ERROR, "Invalid destination IP for "
2790 - "permit-access directive in configuration file: \"%s\"",
2792 - string_append(&config->proxy_args,
2793 - "<br>\nWARNING: Invalid destination IP for permit-access directive"
2794 - " in configuration file: \"");
2795 - string_append(&config->proxy_args,
2798 + config->acl = add_to_acl_list(config->acl, ACL_PERMIT, vec[0], NULL, &config->proxy_args);
2801 + config->acl = add_to_acl_list(config->acl, ACL_PERMIT, vec[0], vec[1], &config->proxy_args);
2804 + log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
2805 + "permit-access directive in configuration file.");
2806 string_append(&config->proxy_args,
2811 + "<br>\nWARNING: Wrong number of parameters for "
2812 + "permit-access directive in configuration file.<br><br>\n");
2816 - * Add it to the list. Note we reverse the list to get the
2817 - * behaviour the user expects. With both the ACL and
2818 - * actions file, the last match wins. However, the internal
2819 - * implementations are different: The actions file is stored
2820 - * in the same order as the file, and scanned completely.
2821 - * With the ACL, we reverse the order as we load it, then
2822 - * when we scan it we stop as soon as we get a match.
2824 - cur_acl->next = config->acl;
2825 - config->acl = cur_acl;
2828 #endif /* def FEATURE_ACL */
2830 @@ -1442,32 +1451,33 @@
2832 #endif /* def FEATURE_COOKIE_JAR */
2834 - if ( NULL == config->haddr )
2836 - config->haddr = strdup( HADDR_DEFAULT );
2839 - if ( NULL != config->haddr )
2840 + if ( config->hspecs == NULL )
2842 - if (NULL != (p = strchr(config->haddr, ':')))
2847 - config->hport = atoi(p);
2851 - if (config->hport <= 0)
2854 - log_error(LOG_LEVEL_FATAL, "invalid bind port spec %s", config->haddr);
2855 - /* Never get here - LOG_LEVEL_FATAL causes program exit */
2857 - if (*config->haddr == '\0')
2859 - config->haddr = NULL;
2861 + /* No listen-address set. The default is localhost on port 8118, on IPv4
2862 + and (if INET6 is defined) IPv6.
2864 + struct bind_spec *bs;
2866 + config->hspecs = calloc(2,sizeof(struct bind_spec));
2867 + if (config->hspecs == NULL)
2868 + fail_load_config_memory(fs,config);
2869 + config->hspecs_size=2;
2870 + config->hspecs_occupied=1;
2871 + bs = &config->hspecs[0];
2872 + bs->haddr = strdup("::1");
2873 + bs->hport = strdup("8118");
2874 + bs->pf = PF_UNSPEC;
2876 + config->hspecs = calloc(1,sizeof(struct bind_spec));
2877 + if (config->hspecs == NULL)
2878 + fail_load_config_memory(fs,config);
2879 + config->hspecs_size=1;
2880 + config->hspecs_occupied=0;
2882 + bs = &config->hspecs[config->hspecs_occupied++];
2883 + bs->haddr = strdup("127.0.0.1");
2884 + bs->hport = strdup("8118");
2885 + bs->pf = PF_UNSPEC;
2889 @@ -1509,31 +1519,29 @@
2890 struct configuration_spec * oldcfg = (struct configuration_spec *)
2891 current_configfile->f;
2893 - * Check if config->haddr,hport == oldcfg->haddr,hport
2895 - * The following could be written more compactly as a single,
2896 - * (unreadably long) if statement.
2897 + * Check if the listening addresses have changed
2899 config->need_bind = 0;
2900 - if (config->hport != oldcfg->hport)
2902 - config->need_bind = 1;
2904 - else if (config->haddr == NULL)
2905 + if (config -> hspecs_occupied == oldcfg -> hspecs_occupied)
2907 - if (oldcfg->haddr != NULL)
2909 + struct bind_spec *hspec;
2910 + struct bind_spec *oldhspec;
2911 + hspec = config -> hspecs;
2912 + oldhspec = oldcfg -> hspecs;
2913 + for(bs_index = 0; bs_index < oldcfg->hspecs_occupied; ++bs_index)
2915 - config->need_bind = 1;
2916 + if (strcmp(hspec[bs_index].haddr,oldhspec[bs_index].haddr) != 0
2917 + || strcmp(hspec[bs_index].hport,oldhspec[bs_index].hport) != 0
2918 + || hspec[bs_index].pf != hspec[bs_index].pf)
2920 + config -> need_bind = 1;
2925 - else if (oldcfg->haddr == NULL)
2927 - config->need_bind = 1;
2929 - else if (0 != strcmp(config->haddr, oldcfg->haddr))
2931 - config->need_bind = 1;
2934 + config-> need_bind = 1;
2936 current_configfile->unloader = unload_configfile;
2938 diff -urNad privoxy~/loaders.c privoxy/loaders.c
2939 --- privoxy~/loaders.c
2940 +++ privoxy/loaders.c
2942 * Copyright : Written by and Copyright (C) 2001 the SourceForge
2943 * Privoxy team. http://www.privoxy.org/
2945 + * Modified by Lionel Elie Mamane <lionel@mamane.lu>
2946 + * for IPv6 support on 8 December 2002, 24 January 2003.
2948 * Based on the Internet Junkbuster originally written
2949 * by and Copyright (C) 1997 Anonymous Coders and
2950 * Junkbusters Corporation. http://www.junkbusters.com
2953 freez(csp->ip_addr_str);
2954 freez(csp->my_ip_addr_str);
2955 + freez(csp->my_port_str);
2956 freez(csp->my_hostname);
2957 freez(csp->x_forwarded);
2958 freez(csp->iob->buf);
2959 diff -urNad privoxy~/miscutil.h privoxy/miscutil.h
2960 --- privoxy~/miscutil.h
2961 +++ privoxy/miscutil.h
2962 @@ -142,6 +142,15 @@
2964 #include "project.h"
2966 +/* Fix a problem with Solaris. There should be no effect on other
2968 + * Solaris's isspace() is a macro which uses it's argument directly
2969 + * as an array index. Therefore we need to make sure that high-bit
2970 + * characters generate +ve values, and ideally we also want to make
2971 + * the argument match the declared parameter type of "int".
2973 +#define ijb_isdigit(__X) isdigit((int)(unsigned char)(__X))
2975 #if defined(__cplusplus)
2978 diff -urNad privoxy~/parsers.c privoxy/parsers.c
2979 --- privoxy~/parsers.c
2980 +++ privoxy/parsers.c
2982 * Copyright : Written by and Copyright (C) 2001 the SourceForge
2983 * Privoxy team. http://www.privoxy.org/
2985 + * Modified by Lionel Elie Mamane <lionel@mamane.lu>
2986 + * for IPv6 support on 24 January 2003.
2988 * Based on the Internet Junkbuster originally written
2989 * by and Copyright (C) 1997 Anonymous Coders and
2990 * Junkbusters Corporation. http://www.junkbusters.com
2991 @@ -1953,6 +1956,167 @@
2993 #endif /* def FEATURE_FORCE_LOAD */
2995 +/*********************************************************************
2997 + * Function : parse_pf_ip_netmask
2999 + * Description : Parse an IPv{4,6} litteral or hostname
3000 + * with optional port and optional explicit family
3001 + * and optional netmask
3004 + * 0 : string = the string to parse
3005 + * 1 : host = Is set to point to the hostname or IP literal
3007 + * 2 : port = Is set to point to the port part,
3008 + * or NULL if no port in string
3009 + * 3 : pf = pointer used to return the address family
3010 + * pf is a value-result argument:
3011 + * If it is set to -1, then parse_pf_ip will set it
3012 + * to the address family of the pf_ip string
3013 + * else, it won't touch it, and fail if the two
3015 + * 4 : pointer used to return the mask length
3016 + * Set to -1 if no mask
3018 + * Returns : 0 on success
3020 + *********************************************************************/
3021 +int parse_pf_ip_netmask(char *string, char **host, char **port, int *pf, int *masklength)
3028 + if ((p = strchr(string, '/')) != NULL)
3032 + if (ijb_isdigit(*p) == 0)
3042 + return parse_pf_ip(string, host, port, pf);
3045 +/*********************************************************************
3047 + * Function : parse_pf_ip
3049 + * Description : Parse an IPv{4,6} litteral or hostname
3050 + * with optional port and optional explicit family
3053 + * 0 : string = the string to parse
3054 + * 1 : host = Is set to point to the hostname or IP literal
3056 + * 2 : port = Is set to point to the port part,
3057 + * or NULL if no port in string
3058 + * 3 : pf = pointer used to return the address family
3059 + * pf is a value-result argument:
3060 + * If it is set to -1, then parse_pf_ip will set it
3061 + * to the address family of the pf_ip string
3062 + * else, it won't touch it, and fail if the two
3065 + * Returns : 0 on success
3067 + *********************************************************************/
3068 +int parse_pf_ip(char *string, char **host, char **port, int *pf)
3070 + if (pf != NULL && *pf == -1)
3073 + /* See if we want to override the default protocol family */
3074 + if (strncmpic(string, "ipv4:", 5) == 0)
3079 + if(*pf==PF_INET || *pf==PF_UNSPEC)
3083 + log_error(LOG_LEVEL_ERROR,"%s","IPv4 address found where other awaited");
3088 + else if (strncmpic(string, "ipv6:", 5) == 0)
3092 + if(*pf==PF_INET6 || *pf==PF_UNSPEC)
3096 + log_error(LOG_LEVEL_ERROR,"%s","IPv6 address found where other awaited");
3100 + log_error(LOG_LEVEL_ERROR,"%s","This privoxy hasn't IPv6 support");
3104 + return parse_ip(string, host, port);
3107 +/*********************************************************************
3109 + * Function : parse_ip
3111 + * Description : Parse an IPv{4,6} litteral or hostname
3112 + * with optional port
3115 + * 0 : string = the string to parse
3116 + * 1 : host = Is set to point to the hostname or IP literal
3118 + * 2 : port = Is set to point to the port part,
3119 + * or NULL if no port in string
3120 + * Returns : 0 on success
3122 + *********************************************************************/
3123 +int parse_ip(char *string, char **host, char **port)
3128 + /* allow IPv6 address literal: [numbers:with:colons]:port/mask */
3129 + if (string[0] == '[' && (p = strchr(string, ']')))
3141 + *host = string + skip;
3143 + for(;*p != '\0'; ++p)
3159 diff -urNad privoxy~/parsers.h privoxy/parsers.h
3160 --- privoxy~/parsers.h
3161 +++ privoxy/parsers.h
3163 * Copyright : Written by and Copyright (C) 2001 the SourceForge
3164 * Privoxy team. http://www.privoxy.org/
3166 + * Modified by Lionel Elie Mamane <lionel@mamane.lu>
3167 + * for IPv6 support on 24 January 2003.
3169 * Based on the Internet Junkbuster originally written
3170 * by and Copyright (C) 1997 Anonymous Coders and
3171 * Junkbusters Corporation. http://www.junkbusters.com
3172 @@ -227,6 +230,10 @@
3173 extern jb_err server_transfer_coding (struct client_state *csp, char **header);
3174 extern jb_err server_http (struct client_state *csp, char **header);
3176 +extern int parse_pf_ip_netmask(char *string, char **host, char **port, int *pf, int *masklength);
3177 +extern int parse_pf_ip(char *string, char ** host, char ** port, int *pf);
3178 +extern int parse_ip(char *string, char ** host, char** port);
3180 #ifdef FEATURE_FORCE_LOAD
3181 extern int strclean(const char *string, const char *substring);
3182 #endif /* def FEATURE_FORCE_LOAD */
3183 diff -urNad privoxy~/project.h privoxy/project.h
3184 --- privoxy~/project.h
3185 +++ privoxy/project.h
3186 @@ -549,6 +549,20 @@
3188 #endif /* ndef _WIN32 */
3190 +#include "jb_socket_set.h"
3194 + * Get from the operating system structures big enough
3195 + * to put a network address in, namely sockaddr_storage
3197 +#include <sys/socket.h>
3199 + * If no IPv6 support, just use the old sockaddr
3202 +#define sockaddr_storage sockaddr
3206 * A standard error code. This should be JB_ERR_OK or one of the JB_ERR_xxx
3207 @@ -618,19 +632,6 @@
3212 - * Default IP address to listen on, as a string.
3213 - * Set to "127.0.0.1".
3215 -#define HADDR_DEFAULT "127.0.0.1"
3218 - * Default port to listen on, as a number.
3221 -#define HADDR_PORT 8118
3224 /* Forward def for struct client_state */
3225 struct configuration_spec;
3227 @@ -709,13 +710,16 @@
3228 char *ver; /**< Protocol version */
3229 int status; /**< HTTP Status */
3231 + char *host_port_malloc; /**< malloc used for place wher host and port_str are */
3232 char *host; /**< Host part of URL */
3233 int port; /**< Port of URL or 80 (default) */
3234 + char *port_str; /**< Port of URL, as string */
3235 char *path; /**< Path of URL */
3236 char *hostport; /**< host[:port] */
3237 int ssl; /**< Flag if protocol is https */
3239 - char *host_ip_addr_str; /**< String with dotted decimal representation
3240 + char *host_ip_addr_str; /**< String with dotted decimal representation (IPv4)
3241 + or hexadecimal colon-separated (IPv6)
3242 of host's IP. NULL before connect_to() */
3244 char *dbuffer; /**< Buffer with '\0'-delimited domain name. */
3245 @@ -1039,13 +1043,16 @@
3248 /** Client PC's IP address, as reported by the accept() function.
3250 - long ip_addr_long;
3252 + struct sockaddr_storage ip_addr_addr;
3254 /** Our IP address. I.e. the IP address that the client used to reach us,
3256 char *my_ip_addr_str;
3258 + /** Our port. I.e. the port the client used to reach us */
3259 + char *my_port_str;
3261 /** Our hostname. I.e. the reverse DNS of the IP address that the client
3262 used to reach us, as a string. */
3264 @@ -1214,18 +1221,33 @@
3265 /** Connection type. Must be SOCKS_NONE, SOCKS_4, or SOCKS_4A. */
3268 + /** pointer returned by the malloc used for gateway_host and gateway_port_str */
3269 + char *gateway_malloc;
3271 /** SOCKS server hostname. Only valid if "type" is SOCKS_4 or SOCKS_4A. */
3274 /** SOCKS server port. */
3277 + /** SOCKS server port, as string. */
3278 + char *gateway_port_str;
3280 + /** pointer returned by the malloc used for forward_host and forward_port_str */
3281 + char *forward_malloc;
3283 + /** Parent HTTP proxy address family. */
3284 + int forward_family;
3286 /** Parent HTTP proxy hostname, or NULL for none. */
3289 /** Parent HTTP proxy port. */
3292 + /** Parent HTTP proxy port as string. */
3293 + char *forward_port_str;
3295 /** Next entry in the linked list. */
3296 struct forward_spec *next;
3298 @@ -1234,7 +1256,7 @@
3300 * Initializer for a static struct forward_spec.
3302 -#define FORWARD_SPEC_INITIALIZER { { URL_SPEC_INITIALIZER }, 0, NULL, 0, NULL, 0, NULL }
3303 +#define FORWARD_SPEC_INITIALIZER { { URL_SPEC_INITIALIZER }, 0, NULL, NULL, 0, NULL, NULL, 0, NULL, 0, NULL, NULL}
3307 @@ -1263,7 +1285,8 @@
3309 struct access_control_addr
3311 - unsigned long addr; /**< The IP address as an integer. */
3312 + struct sockaddr_storage addr; /**< The IP address. */
3314 unsigned long mask; /**< The network mask as an integer. */
3315 unsigned long port; /**< The port number. */
3317 @@ -1295,6 +1318,17 @@
3318 /** configuration_spec::feature_flags: Web-based toggle. */
3319 #define RUNTIME_FEATURE_CGI_TOGGLE 2
3323 + /** IP address to bind to. */
3326 + /** Port to bind to. */
3329 + /** Address family */
3334 * Data loaded from the configuration file.
3335 @@ -1355,11 +1389,13 @@
3337 #endif /* def FEATURE_COOKIE_JAR */
3339 - /** IP address to bind to. Defaults to HADDR_DEFAULT == 127.0.0.1. */
3340 - const char *haddr;
3342 - /** Port to bind to. Defaults to HADDR_PORT == 8118. */
3344 + /* IP addresses and ports to bind to.
3345 + Defaults to HSPECS_DEFAULT == {ipv4:127.0.0.1:8118, ipv6:[::1]:8118}. */
3346 + struct bind_spec *hspecs;
3347 + /* size allocated */
3348 + unsigned int hspecs_size;
3349 + /* number of entries */
3350 + unsigned int hspecs_occupied;
3352 /** Size limit for IOB */
3353 size_t buffer_limit;
3354 diff -urNad privoxy~/urlmatch.c privoxy/urlmatch.c
3355 --- privoxy~/urlmatch.c
3356 +++ privoxy/urlmatch.c
3359 #include "miscutil.h"
3361 +#include "parsers.h"
3363 const char urlmatch_h_rcs[] = URLMATCH_H_VERSION;
3369 - freez(http->host);
3370 + freez(http->host_port_malloc);
3372 freez(http->hostport);
3381 buf = strdup(http->hostport);
3383 @@ -307,38 +306,34 @@
3384 return JB_ERR_MEMORY;
3387 + http->host_port_malloc = buf;
3389 /* check if url contains username and/or password */
3390 - host = strchr(buf, '@');
3392 + buf = strchr(buf, '@');
3395 /* Contains username/password, skip it and the @ sign. */
3401 /* No username or password. */
3403 + buf = http->host_port_malloc;
3406 - /* check if url contains port */
3407 - port = strchr(host, ':');
3409 + parse_ip(buf,&http->host,&http->port_str);
3411 + if (*http->port_str != '\0')
3413 - /* Contains port */
3414 - /* Terminate hostname and point to start of port string */
3416 - http->port = atoi(port);
3417 + http->port = atoi(http->port_str);
3421 /* No port specified. */
3422 - http->port = (http->ssl ? 443 : 80);
3423 + http->port_str = (http->ssl ? "143" : "80");
3424 + http->port = (http->ssl ? 443 : 80);
3427 - http->host = strdup(host);
3431 if (http->host == NULL)
3433 return JB_ERR_MEMORY;
3435 * written to system log)
3437 *********************************************************************/
3438 -jb_err create_url_spec(struct url_spec * url, const char * buf)
3439 +jb_err create_url_spec(struct url_spec * url, char * buf)
3445 @@ -681,22 +675,25 @@
3447 return JB_ERR_MEMORY;
3450 - if ((p = strchr(buf, '/')) != NULL)
3452 - if (NULL == (url->path = strdup(p)))
3455 + if ((p = strchr(buf, '/')) != NULL)
3458 - return JB_ERR_MEMORY;
3459 + if (NULL == (url->path = strdup(p)))
3462 + return JB_ERR_MEMORY;
3464 + url->pathlen = strlen(url->path);
3467 - url->pathlen = strlen(url->path);
3484 @@ -735,15 +732,12 @@
3485 return JB_ERR_PARSE;
3488 - if ((p = strchr(buf, ':')) == NULL)
3496 - url->port = atoi(p);
3499 + parse_ip(buf,&buf,&p);
3500 + url->port = atoi(p);
3505 @@ -775,12 +769,13 @@
3506 return JB_ERR_MEMORY;
3510 - * Map to lower case
3512 - for (p = url->dbuffer; *p ; p++)
3514 - *p = tolower((int)(unsigned char)*p);
3516 + /* map to lower case */
3517 + for (p = url->dbuffer; *p ; p++)
3519 + *p = tolower((int)(unsigned char)*p);
3524 diff -urNad privoxy~/urlmatch.h privoxy/urlmatch.h
3525 --- privoxy~/urlmatch.h
3526 +++ privoxy/urlmatch.h
3528 extern int url_match(const struct url_spec *pattern,
3529 const struct http_request *url);
3531 -extern jb_err create_url_spec(struct url_spec * url, const char * buf);
3532 +extern jb_err create_url_spec(struct url_spec * url, char * buf);
3533 extern void free_url_spec(struct url_spec *url);