* released 1.2.0
* the same as 1.1.27 + IPv6 support on the client side
diff --git a/CHANGELOG b/CHANGELOG
index c3c2046..b8ae2ac 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,9 @@
 ChangeLog :
 ===========
 
+2003/11/09 : 1.2.0
+  - the same as 1.1.27 + IPv6 support on the client side
+
 2003/10/27 : 1.1.27
   - the configurable HTTP health check introduced in 1.1.23 revealed a shameful
     bug : the code still assumed that HTTP requests were the same size as the
diff --git a/haproxy.c b/haproxy.c
index bdee43d..10bb3e0 100644
--- a/haproxy.c
+++ b/haproxy.c
@@ -53,8 +53,8 @@
 #include <linux/netfilter_ipv4.h>
 #endif
 
-#define HAPROXY_VERSION "1.1.27"
-#define HAPROXY_DATE	"2003/10/27"
+#define HAPROXY_VERSION "1.1.27-ipv6"
+#define HAPROXY_DATE	"2003/11/09"
 
 /* this is for libc5 for example */
 #ifndef TCP_NODELAY
@@ -389,7 +389,7 @@
     int flags;				/* some flags describing the session */
     struct buffer *req;			/* request buffer */
     struct buffer *rep;			/* response buffer */
-    struct sockaddr_in cli_addr;	/* the client address */
+    struct sockaddr_storage cli_addr;	/* the client address */
     struct sockaddr_in srv_addr;	/* the address to connect to */
     struct server *srv;			/* the server being used */
     struct {
@@ -409,9 +409,9 @@
 };
 
 struct listener {
-    int fd;			/* the listen socket */
-    struct sockaddr_in addr;	/* the address we listen to */
-    struct listener *next;	/* next address or NULL */
+    int fd;				/* the listen socket */
+    struct sockaddr_storage addr;	/* the address we listen to */
+    struct listener *next;		/* next address or NULL */
 };
     
     
@@ -776,13 +776,7 @@
     if (*str == '*' || *str == '\0') { /* INADDR_ANY */
 	sa.sin_addr.s_addr = INADDR_ANY;
     }
-    else if (
-#ifndef SOLARIS
-	!inet_aton(str, &sa.sin_addr)
-#else
-	!inet_pton(AF_INET, str, &sa.sin_addr)
-#endif
-	) {
+    else if (!inet_pton(AF_INET, str, &sa.sin_addr)) {
 	struct hostent *he;
 
 	if ((he = gethostbyname(str)) == NULL) {
@@ -815,21 +809,49 @@
     int port, end;
 
     next = dupstr = strdup(str);
-    
     while (next && *next) {
+	struct sockaddr_storage ss;
+
 	str = next;
 	/* 1) look for the end of the first address */
 	if ((next = strrchr(str, ',')) != NULL) {
 	    *next++ = 0;
 	}
 
-	/* 2) look for the addr/port delimiter */
-	if ((range = strrchr(str, ':')) != NULL) {
-	    *range++ = 0;
+	/* 2) look for the addr/port delimiter, it's the last colon. */
+	if ((range = strrchr(str, ':')) == NULL) {
+	    Alert("Missing port number: '%s'\n", str);
+	}	    
+
+	*range++ = 0;
+
+	if (strrchr(str, ':') != NULL) {
+	    /* IPv6 address contains ':' */
+	    memset(&ss, 0, sizeof(ss));
+	    ss.ss_family = AF_INET6;
+
+	    if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in6 *)&ss)->sin6_addr)) {
+		Alert("Invalid server address: '%s'\n", str);
+	    }
 	}
 	else {
-		Alert("Missing port number: '%s'\n", str);
-	}	    
+	    memset(&ss, 0, sizeof(ss));
+	    ss.ss_family = AF_INET;
+
+	    if (*str == '*' || *str == '\0') { /* INADDR_ANY */
+		((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY;
+	    }
+	    else if (!inet_pton(ss.ss_family, str, &((struct sockaddr_in *)&ss)->sin_addr)) {
+		struct hostent *he;
+		
+		if ((he = gethostbyname(str)) == NULL) {
+		    Alert("Invalid server name: '%s'\n", str);
+		}
+		else
+		    ((struct sockaddr_in *)&ss)->sin_addr =
+			*(struct in_addr *) *(he->h_addr_list);
+	    }
+	}
 
 	/* 3) look for the port-end delimiter */
 	if ((c = strchr(range, '-')) != NULL) {
@@ -845,26 +867,12 @@
 	    l->next = tail;
 	    tail = l;
 
-	    if (*str == '*' || *str == '\0') { /* INADDR_ANY */
-		l->addr.sin_addr.s_addr = INADDR_ANY;
-	    }
-	    else if (
-#ifndef SOLARIS
-		     !inet_aton(str, &l->addr.sin_addr)
-#else
-		     !inet_pton(AF_INET, str, &l->addr.sin_addr)
-#endif
-		     ) {
-		struct hostent *he;
-		
-		if ((he = gethostbyname(str)) == NULL) {
-		    Alert("Invalid server name: '%s'\n", str);
-		}
-		else
-		    l->addr.sin_addr = *(struct in_addr *) *(he->h_addr_list);
-	    }
-	    l->addr.sin_port=htons(port);
-	    l->addr.sin_family=AF_INET;
+	    l->addr = ss;
+	    if (ss.ss_family == AF_INET6)
+		((struct sockaddr_in6 *)(&l->addr))->sin6_port = htons(port);
+	    else
+		((struct sockaddr_in *)(&l->addr))->sin_port = htons(port);
+
 	} /* end for(port) */
     } /* end while(next) */
     free(dupstr);
@@ -1943,7 +1951,7 @@
  * send a log for the session when we have enough info about it
  */
 void sess_log(struct session *s) {
-    unsigned char *pn;
+    char pn[INET6_ADDRSTRLEN + strlen(":65535")];
     struct proxy *p = s->proxy;
     int log;
     char *uri;
@@ -1959,9 +1967,14 @@
 
     log = p->to_log & ~s->logs.logwait;
 
-    pn = (log & LW_CLIP) ?
-	 (unsigned char *)&s->cli_addr.sin_addr :
-	 (unsigned char *)"\0\0\0\0";
+    if (s->cli_addr.ss_family == AF_INET)
+	inet_ntop(AF_INET,
+		  (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
+		  pn, sizeof(pn));
+    else
+	inet_ntop(AF_INET6,
+		  (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
+		  pn, sizeof(pn));
 
     uri = (log & LW_REQ) ? s->logs.uri ? s->logs.uri : "<BADREQ>" : "";
     pxid = p->id;
@@ -1969,8 +1982,11 @@
 
     tm = localtime(&s->logs.tv_accept.tv_sec);
     if (p->to_log & LW_REQ) {
-	send_log(p, LOG_INFO, "%d.%d.%d.%d:%d [%02d/%s/%04d:%02d:%02d:%02d] %s %s %d/%d/%d/%d %d %lld %s %s %c%c%c%c \"%s\"\n",
-		 pn[0], pn[1], pn[2], pn[3], ntohs(s->cli_addr.sin_port),
+	send_log(p, LOG_INFO, "%s:%d [%02d/%s/%04d:%02d:%02d:%02d] %s %s %d/%d/%d/%d %d %lld %s %s %c%c%c%c \"%s\"\n",
+		 pn,
+		 (s->cli_addr.ss_family == AF_INET) ?
+		   ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
+		   ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
 		 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
 		 tm->tm_hour, tm->tm_min, tm->tm_sec,
 		 pxid, srv,
@@ -1988,8 +2004,11 @@
 		 uri);
     }
     else {
-	send_log(p, LOG_INFO, "%d.%d.%d.%d:%d [%02d/%s/%04d:%02d:%02d:%02d] %s %s %d/%d %lld %c%c\n",
-		 pn[0], pn[1], pn[2], pn[3], ntohs(s->cli_addr.sin_port),
+	send_log(p, LOG_INFO, "%s:%d [%02d/%s/%04d:%02d:%02d:%02d] %s %s %d/%d %lld %c%c\n",
+		 pn,
+		 (s->cli_addr.ss_family == AF_INET) ?
+		   ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
+		   ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
 		 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
 		 tm->tm_hour, tm->tm_min, tm->tm_sec,
 		 pxid, srv,
@@ -2017,7 +2036,7 @@
     int one = 1;
 
     while (p->nbconn < p->maxconn) {
-	struct sockaddr_in addr;
+	struct sockaddr_storage addr;
 	int laddr = sizeof(addr);
 	if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1)
 	    return 0;	    /* nothing more to accept */
@@ -2092,15 +2111,13 @@
 
 	if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP)
 	    && (p->logfac1 >= 0 || p->logfac2 >= 0)) {
-	    struct sockaddr_in sockname;
-	    unsigned char *pn, *sn;
+	    struct sockaddr_storage sockname;
 	    int namelen;
 
 	    namelen = sizeof(sockname);
-	    if (get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
+	    if (addr.ss_family != AF_INET ||
+		get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
 		getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
-	    sn = (unsigned char *)&sockname.sin_addr;
-	    pn = (unsigned char *)&s->cli_addr.sin_addr;
 
 	    if (p->to_log) {
 		/* we have the client ip */
@@ -2108,28 +2125,62 @@
 		    if (!(s->logs.logwait &= ~LW_CLIP))
 			sess_log(s);
 	    }
-	    else
-		send_log(p, LOG_INFO, "Connect from %d.%d.%d.%d:%d to %d.%d.%d.%d:%d (%s/%s)\n",
-			 pn[0], pn[1], pn[2], pn[3], ntohs(s->cli_addr.sin_port),
-			 sn[0], sn[1], sn[2], sn[3], ntohs(sockname.sin_port),
-			 p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
+	    else if (s->cli_addr.ss_family == AF_INET) {
+		char pn[INET_ADDRSTRLEN], sn[INET_ADDRSTRLEN];
+		if (inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&sockname)->sin_addr,
+			      sn, sizeof(sn)) &&
+		    inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
+			      pn, sizeof(pn))) {
+		    send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
+			     pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port),
+			     sn, ntohs(((struct sockaddr_in *)&sockname)->sin_port),
+			     p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
+		}
+	    }
+	    else {
+		char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
+		if (inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&sockname)->sin6_addr,
+			      sn, sizeof(sn)) &&
+		    inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&s->cli_addr)->sin6_addr,
+			      pn, sizeof(pn))) {
+		    send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
+			     pn, ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
+			     sn, ntohs(((struct sockaddr_in6 *)&sockname)->sin6_port),
+			     p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
+		}
+	    }
 	}
 
 	if ((global.mode & MODE_DEBUG) && !(global.mode & MODE_QUIET)) {
 	    struct sockaddr_in sockname;
-	    unsigned char *pn, *sn;
 	    int namelen;
 	    int len;
-
 	    namelen = sizeof(sockname);
-	    if (get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
+	    if (addr.ss_family != AF_INET ||
+		get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1)
 		getsockname(cfd, (struct sockaddr *)&sockname, &namelen);
-	    sn = (unsigned char *)&sockname.sin_addr;
-	    pn = (unsigned char *)&s->cli_addr.sin_addr;
 
-	    len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%d.%d.%d.%d:%d]\n",
-			  s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
-			  pn[0], pn[1], pn[2], pn[3], ntohs(s->cli_addr.sin_port));
+	    if (s->cli_addr.ss_family == AF_INET) {
+		char pn[INET_ADDRSTRLEN];
+		inet_ntop(AF_INET,
+			  (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
+			  pn, sizeof(pn));
+
+		len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
+			      s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
+			      pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port));
+	    }
+	    else {
+		char pn[INET6_ADDRSTRLEN];
+		inet_ntop(AF_INET6,
+			  (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
+			  pn, sizeof(pn));
+
+		len = sprintf(trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
+			      s->uniq_id, p->id, (unsigned short)fd, (unsigned short)cfd,
+			      pn, ntohs(((struct sockaddr_in6 *)(&s->cli_addr))->sin6_port));
+	    }
+
 	    write(1, trash, len);
 	}
 
@@ -2359,7 +2410,7 @@
 		num = *str - '0';
 		str++;
 
-		if (matches[num].rm_so > -1) {
+		if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
 		    len = matches[num].rm_eo - matches[num].rm_so;
 		    memcpy(dst, src + matches[num].rm_so, len);
 		    dst += len;
@@ -2439,12 +2490,21 @@
 		}
 
 		if (t->proxy->options & PR_O_FWDFOR) {
-		    /* insert an X-Forwarded-For header */
-		    unsigned char *pn;
-		    pn = (unsigned char *)&t->cli_addr.sin_addr;
-		    len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
-				  pn[0], pn[1], pn[2], pn[3]);
-		    buffer_replace2(req, req->h, req->h, trash, len);
+		    if (t->cli_addr.ss_family == AF_INET) {
+			unsigned char *pn;
+			pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
+			len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
+				      pn[0], pn[1], pn[2], pn[3]);
+			buffer_replace2(req, req->h, req->h, trash, len);
+		    }
+		    else if (t->cli_addr.ss_family == AF_INET6) {
+			char pn[INET6_ADDRSTRLEN];
+			inet_ntop(AF_INET6,
+				  (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
+				  pn, sizeof(pn));
+			len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
+			buffer_replace2(req, req->h, req->h, trash, len);
+		    }
 		}
 
 		if (!memcmp(req->data, "POST ", 5))
@@ -5763,7 +5823,7 @@
 
 	for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
 	    if ((fd = listener->fd =
-		 socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
+		 socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
 		Alert("cannot create listening socket for proxy %s. Aborting.\n",
 		      curproxy->id);
 		return -1;
@@ -5792,7 +5852,9 @@
 	
 	    if (bind(fd,
 		     (struct sockaddr *)&listener->addr,
-		     sizeof(listener->addr)) == -1) {
+		     listener->addr.ss_family == AF_INET6 ?
+		     sizeof(struct sockaddr_in6) :
+		     sizeof(struct sockaddr_in)) == -1) {
 		Alert("cannot bind socket for proxy %s. Aborting.\n",
 		      curproxy->id);
 		close(fd);