Hi,
if you are interested. The patch will bind squid to all A/AAAA
DNS records when a hostname is specified in the http_port directive.
Also does the patch allows to use IPv6 address/port syntax as suggested
in RFC2732 in the http_port directive.
Please see attachment for the patch.
Regards,
Oliver
diff -urNad /home/racon/squid/squid_2.5.3ipv6.20030616-4/src/cache_cf.c
squid_2.5.3ipv6.20030616-4/src/cache_cf.c
--- /home/racon/squid/squid_2.5.3ipv6.20030616-4/src/cache_cf.c 2003-06-22
22:50:35.000000000 -0300
+++ squid_2.5.3ipv6.20030616-4/src/cache_cf.c 2003-06-22 23:04:57.000000000 -0300
@@ -2203,43 +2203,151 @@
return PEER_SIBLING;
}
+static int
+get_address_list(const char* host, const unsigned int port,
+ sockaddr_in_list** head, int af)
+{
+ int i = 0;
+ struct IN_ADDR addr;
+ int c = 0;
+ struct hostent* hp;
+
+ /* do the query */
+ if((hp = gethostbyname2(host, af)) != NULL)
+ {
+ /* iterate through results */
+ while(hp->h_addr_list[i] != NULL)
+ {
+ c++;
+#ifdef INET6
+ /* if h_addrtype is AF_INET convert into AF_INET6 */
+ if(hp->h_addrtype == AF_INET)
+ {
+ addr.s6_addr32[0] = 0;
+ addr.s6_addr32[1] = 0;
+ addr.s6_addr32[2] = htonl(0xffff);
+ addr.s6_addr32[3] =
+ *((uint32_t*)(hp->h_addr_list[i]));
+ }
+ else
+#endif
+ addr = *((struct IN_ADDR*)hp->h_addr_list[i]);
+
+ sockaddr_in_list* sa_li;
+ sa_li = xcalloc(1, sizeof(sockaddr_in_list));
+ xmemcpy(&ADDR_FROM_SA(sa_li->s),
+ &addr, sizeof(struct IN_ADDR));
+ PORT_FROM_SA(sa_li->s) = htons(port);
+
+ /* do not need to check for duplicates here since
+ * DNS does not delivers duplicates and squid handles sockets
+ * which cannot be opened gracefully. */
+ while (*head)
+ head = &(*head)->next;
+
+ *head = sa_li;
+ i++;
+ }
+ }
+ return c;
+}
+
static void
parse_sockaddr_in_list(sockaddr_in_list ** head)
{
char *token;
char *t;
char *host;
- const struct hostent *hp;
unsigned short port;
- sockaddr_in_list *s;
while ((token = strtok(NULL, w_space))) {
host = NULL;
port = 0;
- if ((t = strchr(token, ':'))) {
+ /* If token starts with an opening bracket, the part in brackets is
+ * an IPv6 address, which must be followed by a colon and a port
+ * number. If token does not start with bracket, the part before
+ * the colon will be used as either address of hostname. */
+ if (token[0] == '[') {
+ /* [IPv6 addr]:port */
+ if ((t = strchr(token, ']')) && *(t + 1) == ':') {
+ /* copy IPv6 address to host */
+ *t = '\0';
+ host = xstrdup(&token[1]);
+ /* t + 1 and t + 2 should be safe since if ']' is not in
+ * the string (t + 1) is not evaluated, if it is the last
+ * character in the string *(t + 1) == '\0' in the worse
+ * case which does not evaluate (t + 2). If (t + 1) != '\0'
+ * *(t + 2) would be '\0' in the worse case which is an
+ * empty string. */
+ port = (unsigned short) atoi(t + 2);
+ if (0 == port) {
+ xfree(host);
+ self_destruct();
+ }
+ }
+ else
+ self_destruct();
+ }
+ else if ((t = strchr(token, ':'))) {
/* host:port */
- host = token;
*t = '\0';
+ host = xstrdup(token);
port = (unsigned short) atoi(t + 1);
if (0 == port)
+ {
+ xfree(host);
self_destruct();
+ }
} else if ((port = atoi(token)) > 0) {
/* port */
} else {
self_destruct();
}
- s = xcalloc(1, sizeof(*s));
- PORT_FROM_SA(s->s) = htons(port);
- if (NULL == host)
- ADDR_FROM_SA(s->s) = INADDR_ANY_ASSIGN;
- else if (1 == SAFE_INET_ADDR(host, &ADDR_FROM_SA(s->s)))
- (void) 0;
- else if ((hp = GETHOSTBYNAME(host))) /* dont use ipcache */
- ADDR_FROM_SA(s->s) = inaddrFromHostent(hp);
- else
- self_destruct();
- while (*head)
- head = &(*head)->next;
- *head = s;
+
+ if (NULL == host) {
+ /* only port was specified, so listen on any local address */
+ sockaddr_in_list* sa_li;
+ sa_li = xcalloc(1, sizeof(sockaddr_in_list));
+ PORT_FROM_SA(sa_li->s) = htons(port);
+ ADDR_FROM_SA(sa_li->s) = INADDR_ANY_ASSIGN;
+ /* append to list */
+ while (*head)
+ head = &(*head)->next;
+ *head = sa_li;
+ }
+ else {
+ /* host is either IPv4/IPv6 address or hostname */
+ struct IN_ADDR addr;
+
+ /* try IP address */
+ if (1 == SAFE_INET_ADDR(host, &addr)) {
+ /* ok host was an IPv4 or IPv6 address set the port and
+ * done*/
+ sockaddr_in_list* sa_li;
+ sa_li = xcalloc(1, sizeof(sockaddr_in_list));
+
+ ADDR_FROM_SA(sa_li->s) = addr;
+ PORT_FROM_SA(sa_li->s) = htons(port);
+
+ /* append to list */
+ while (*head)
+ head = &(*head)->next;
+ *head = sa_li;
+ }
+ /* no IP address so it should be hostname */
+ /* make an list entry for each address that was found */
+ else
+ {
+ int ret = 0;
+ ret += get_address_list(host, port, head, AF_INET6);
+ ret += get_address_list(host, port, head, AF_INET);
+ if(!ret)
+ {
+ xfree(host);
+ self_destruct();
+ }
+ }
+ xfree(host);
+ }
}
}
diff -urNad /home/racon/squid/squid_2.5.3ipv6.20030616-4/src/cf.data.pre
squid_2.5.3ipv6.20030616-4/src/cf.data.pre
--- /home/racon/squid/squid_2.5.3ipv6.20030616-4/src/cf.data.pre 2003-06-22
23:04:57.000000000 -0300
+++ squid_2.5.3ipv6.20030616-4/src/cf.data.pre 2003-06-22 23:04:57.000000000 -0300
@@ -62,15 +62,22 @@
Usage: port
hostname:port
1.2.3.4:port
+ [aaaa:bbbb:ccc:1::abcd]:port
+ [::ffff:1.2.3.4]:port
The socket addresses where Squid will listen for HTTP client
- requests. You may specify multiple socket addresses.
- There are three forms: port alone, hostname with port, and
- IP address with port. If you specify a hostname or IP
- address, then Squid binds the socket to that specific
- address. This replaces the old 'tcp_incoming_address'
- option. Most likely, you do not need to bind to a specific
- address, so you can use the port number alone.
+ requests. You may specify multiple socket addresses.
+ There are four forms: port alone, hostname with port, IPv4
+ style address with port and IPv6 style address with port. The
+ IPv6 style address must appear in brackets as suggested in RFC 2732.
+ If you specify an IP address, then Squid binds the socket to that
+ specific address. You can also specify IPv6 mapped IPv4 addresses.
+ If you specify a hostname Squid tries to bind to all addresses
+ associated with this hostname. Therefor Squid will query for AAAA
+ as well as for A records.
+ This option replaces the old 'tcp_incoming_address' option. Most
+ likely, you do not need to bind to a specific address, so you can
+ use the port number alone.
The default port number is 3128.