diff --git a/CHANGES b/CHANGES
index 9c338d6e370d437d66654b42d2c73eaacbb82f4e..fa03ea07300656a5771b46869112335b3a945f30 100644
--- a/CHANGES
+++ b/CHANGES
@@ -6,6 +6,12 @@
 
                                   Changelog
 
+Daniel Fandrich (9 Oct 2008)
+- Fixed the --interface option to work with IPv6 connections on glibc
+  systems supporting getifaddrs(). Also fixed a problem where an IPv6
+  address could be chosen instead of an IPv4 one for --interface when it
+  involved a name lookup.
+
 Daniel Fandrich (8 Oct 2008)
 - Added tests 1082 through 1085 to test symbolic --interface parameters
 
diff --git a/RELEASE-NOTES b/RELEASE-NOTES
index 4d8e21ec73fc62d8580c89b4e0e29b8a6c74f219..918be61b684e71a36e0160ad119aa38978e9e812 100644
--- a/RELEASE-NOTES
+++ b/RELEASE-NOTES
@@ -15,6 +15,7 @@ This release includes the following changes:
  o Better detect HTTP 1.0 servers and don't do HTTP 1.1 requests on them
  o configure --disable-proxy disables proxy
  o Added CURLOPT_USERNAME and CURLOPT_PASSWORD
+ o --interface now works with IPv6 connections on glibc systems
 
 This release includes the following bugfixes:
 
diff --git a/configure.ac b/configure.ac
index bf86bf038ef072b415d6d665fd05149ca34de62e..25572cd7a83a774108aa0d7f78267cf0ec81020f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2061,6 +2061,7 @@ AC_CHECK_FUNCS([basename \
   fork \
   geteuid \
   gethostbyaddr \
+  getifaddrs \
   getpass_r \
   getppid \
   getprotobyname \
diff --git a/lib/connect.c b/lib/connect.c
index 3773b8280bc71da74ce129e15826dc8aacbb1f91..07d5f388715a0c6a02c55f79c7aa4d3d13c6579d 100644
--- a/lib/connect.c
+++ b/lib/connect.c
@@ -284,15 +284,16 @@ int waitconnect(curl_socket_t sockfd, /* socket */
 }
 
 static CURLcode bindlocal(struct connectdata *conn,
-                          curl_socket_t sockfd)
+                          curl_socket_t sockfd, int af)
 {
-#ifdef ENABLE_IPV6
-  char ipv6_addr[16];
-#endif
   struct SessionHandle *data = conn->data;
   struct sockaddr_in me;
+#ifdef ENABLE_IPV6
+  struct sockaddr_in6 me6;
+#endif
   struct sockaddr *sock = NULL;  /* bind to this address */
-  socklen_t socksize; /* size of the data sock points to */
+  socklen_t socksize = 0; /* size of the data sock points to */
+  struct Curl_dns_entry *h=NULL;
   unsigned short port = data->set.localport; /* use this port number, 0 for
                                                 "random" */
   /* how many port numbers to try to bind to, increasing one at a time */
@@ -303,20 +304,13 @@ static CURLcode bindlocal(struct connectdata *conn,
    * Select device to bind socket to
    *************************************************************/
   if(dev && (strlen(dev)<255) ) {
-    struct Curl_dns_entry *h=NULL;
     char myhost[256] = "";
-    in_addr_t in;
     int rc;
     bool was_iface = FALSE;
-    int in6 = -1;
 
-    /* First check if the given name is an IP address */
-    in=inet_addr((char *) dev);
-
-    if((in == CURL_INADDR_NONE) &&
-       Curl_if2ip(dev, myhost, sizeof(myhost))) {
+    if(Curl_if2ip(af, dev, myhost, sizeof(myhost))) {
       /*
-       * We now have the numerical IPv4-style x.y.z.w in the 'myhost' buffer
+       * We now have the numerical IP address in the 'myhost' buffer
        */
       rc = Curl_resolv(conn, myhost, 0, &h);
       if(rc == CURLRESOLV_PENDING)
@@ -324,7 +318,6 @@ static CURLcode bindlocal(struct connectdata *conn,
 
       if(h) {
         was_iface = TRUE;
-        Curl_resolv_unlock(data, h);
       }
     }
 
@@ -333,22 +326,30 @@ static CURLcode bindlocal(struct connectdata *conn,
        * This was not an interface, resolve the name as a host name
        * or IP number
        */
+
+      /*
+       * Temporarily force name resolution to use only the address type
+       * of the connection. The resolve functions should really be changed
+       * to take a type parameter instead.
+       */
+      long ipver = data->set.ip_version;
+      if (af == AF_INET)
+        data->set.ip_version = CURL_IPRESOLVE_V4;
+      else if (af == AF_INET6)
+        data->set.ip_version = CURL_IPRESOLVE_V6;
+
       rc = Curl_resolv(conn, dev, 0, &h);
       if(rc == CURLRESOLV_PENDING)
         (void)Curl_wait_for_resolv(conn, &h);
+      data->set.ip_version = ipver;
 
       if(h) {
-        if(in == CURL_INADDR_NONE)
-          /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */
-          Curl_printable_address(h->addr, myhost, sizeof myhost);
-        else
-          /* we know data->set.device is shorter than the myhost array */
-          strcpy(myhost, dev);
-        Curl_resolv_unlock(data, h);
+        /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */
+        Curl_printable_address(h->addr, myhost, sizeof myhost);
       }
     }
 
-    if(! *myhost) {
+    if(!*myhost || !h) {
       /* need to fix this
          h=Curl_gethost(data,
          getmyhost(*myhost,sizeof(myhost)),
@@ -356,11 +357,16 @@ static CURLcode bindlocal(struct connectdata *conn,
          sizeof(hostent_buf));
       */
       failf(data, "Couldn't bind to '%s'", dev);
+      if(h)
+        Curl_resolv_unlock(data, h);
       return CURLE_INTERFACE_FAILED;
     }
 
     infof(data, "Bind local address to %s\n", myhost);
 
+    sock = h->addr->ai_addr;
+    socksize = h->addr->ai_addrlen;
+
 #ifdef SO_BINDTODEVICE
     /* I am not sure any other OSs than Linux that provide this feature, and
      * at the least I cannot test. --Ben
@@ -378,42 +384,37 @@ static CURLcode bindlocal(struct connectdata *conn,
                      dev, strlen(dev)+1) != 0) {
         /* printf("Failed to BINDTODEVICE, socket: %d  device: %s error: %s\n",
            sockfd, dev, Curl_strerror(SOCKERRNO)); */
-        infof(data, "SO_BINDTODEVICE %s failed\n", dev);
+        int error = ERRNO;
+        infof(data, "SO_BINDTODEVICE %s failed with errno %d: %s; will do regular bind\n",
+              dev, error, Curl_strerror(conn, error));
         /* This is typically "errno 1, error: Operation not permitted" if
            you're not running as root or another suitable privileged user */
       }
     }
 #endif
-
-    in=inet_addr(myhost);
-
-#ifdef ENABLE_IPV6
-    in6 = Curl_inet_pton (AF_INET6, myhost, (void *)&ipv6_addr);
-#endif
-    if(CURL_INADDR_NONE == in && -1 == in6) {
-      failf(data,"couldn't find my own IP address (%s)", myhost);
-      return CURLE_INTERFACE_FAILED;
-    } /* end of inet_addr */
-
-    if( h ) {
-      Curl_addrinfo *addr = h->addr;
-      sock = addr->ai_addr;
-      socksize = addr->ai_addrlen;
-    }
-    else
-      return CURLE_INTERFACE_FAILED;
-
   }
   else if(port) {
     /* if a local port number is requested but no local IP, extract the
        address from the socket */
-    memset(&me, 0, sizeof(struct sockaddr));
-    me.sin_family = AF_INET;
-    me.sin_addr.s_addr = INADDR_ANY;
+    if(af == AF_INET) {
+      memset(&me, 0, sizeof(struct sockaddr));
+      me.sin_family = AF_INET;
+      me.sin_addr.s_addr = INADDR_ANY;
 
-    sock = (struct sockaddr *)&me;
-    socksize = sizeof(struct sockaddr);
+      sock = (struct sockaddr *)&me;
+      socksize = sizeof(struct sockaddr);
 
+    }
+#ifdef ENABLE_IPV6
+    else { /* AF_INET6 */
+      memset(&me6, 0, sizeof(struct sockaddr));
+      me6.sin6_family = AF_INET6;
+      me6.sin6_addr = in6addr_any;
+
+      sock = (struct sockaddr *)&me6;
+      socksize = sizeof(struct sockaddr);
+    }
+#endif
   }
   else
     /* no local kind of binding was requested */
@@ -432,11 +433,11 @@ static CURLcode bindlocal(struct connectdata *conn,
     if( bind(sockfd, sock, socksize) >= 0) {
       /* we succeeded to bind */
       struct Curl_sockaddr_storage add;
-      socklen_t size;
-
-      size = sizeof(add);
+      socklen_t size = sizeof(add);
       if(getsockname(sockfd, (struct sockaddr *) &add, &size) < 0) {
         failf(data, "getsockname() failed");
+	if(h)
+	  Curl_resolv_unlock(data, h);
         return CURLE_INTERFACE_FAILED;
       }
       /* We re-use/clobber the port variable here below */
@@ -448,6 +449,8 @@ static CURLcode bindlocal(struct connectdata *conn,
 #endif
       infof(data, "Local port: %d\n", port);
       conn->bits.bound = TRUE;
+      if(h)
+	Curl_resolv_unlock(data, h);
       return CURLE_OK;
     }
     if(--portnum > 0) {
@@ -461,8 +464,10 @@ static CURLcode bindlocal(struct connectdata *conn,
   data->state.os_errno = SOCKERRNO;
   failf(data, "bind failure: %s",
         Curl_strerror(conn, data->state.os_errno));
-  return CURLE_INTERFACE_FAILED;
+  if(h)
+    Curl_resolv_unlock(data, h);
 
+  return CURLE_INTERFACE_FAILED;
 }
 
 /*
@@ -822,7 +827,7 @@ singleipconnect(struct connectdata *conn,
   }
 
   /* possibly bind the local end to an IP, interface or port */
-  res = bindlocal(conn, sockfd);
+  res = bindlocal(conn, sockfd, addr->family);
   if(res) {
     sclose(sockfd); /* close socket and bail out */
     return CURL_SOCKET_BAD;
diff --git a/lib/ftp.c b/lib/ftp.c
index 8409fdc15dfc5242afc1116797407e092cee7536..3d116b543148650627f11abc20bddcd91107ae36 100644
--- a/lib/ftp.c
+++ b/lib/ftp.c
@@ -892,7 +892,8 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
   if(data->set.str[STRING_FTPPORT] &&
      (strlen(data->set.str[STRING_FTPPORT]) > 1)) {
     /* attempt to get the address of the given interface name */
-    if(!Curl_if2ip(data->set.str[STRING_FTPPORT], hbuf, sizeof(hbuf)))
+    if(!Curl_if2ip(conn->ip_addr->ai_family, data->set.str[STRING_FTPPORT],
+                   hbuf, sizeof(hbuf)))
       /* not an interface, use the given string as host name instead */
       host = data->set.str[STRING_FTPPORT];
     else
@@ -964,8 +965,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
 
     /* It failed. Bind the address used for the control connection instead */
     sslen = sizeof(ss);
-    if(getsockname(conn->sock[FIRSTSOCKET],
-                    (struct sockaddr *)sa, &sslen)) {
+    if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
       failf(data, "getsockname() failed: %s",
           Curl_strerror(conn, SOCKERRNO) );
       sclose(portsock);
@@ -973,7 +973,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
     }
 
     /* set port number to zero to make bind() pick "any" */
-    if(((struct sockaddr *)sa)->sa_family == AF_INET)
+    if(sa->sa_family == AF_INET)
       ((struct sockaddr_in *)sa)->sin_port=0;
     else
       ((struct sockaddr_in6 *)sa)->sin6_port =0;
@@ -981,7 +981,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
     if(sslen > (socklen_t)sizeof(ss))
       sslen = sizeof(ss);
 
-    if(bind(portsock, (struct sockaddr *)sa, sslen)) {
+    if(bind(portsock, sa, sslen)) {
       failf(data, "bind failed: %s", Curl_strerror(conn, SOCKERRNO));
       sclose(portsock);
       return CURLE_FTP_PORT_FAILED;
@@ -1112,7 +1112,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
       /* this is an IPv4 address */
       addr = Curl_ip2addr(in, ftpportstr, 0);
     else {
-      if(Curl_if2ip(ftpportstr, myhost, sizeof(myhost))) {
+      if(Curl_if2ip(AF_INET, ftpportstr, myhost, sizeof(myhost))) {
         /* The interface to IP conversion provided a dotted address */
         in=inet_addr(myhost);
         addr = Curl_ip2addr(in, myhost, 0);
diff --git a/lib/if2ip.c b/lib/if2ip.c
index 94a09c11e53fd91e2adfa1f25373701520bedbd3..a540500402146f0783525b080667d633f568031a 100644
--- a/lib/if2ip.c
+++ b/lib/if2ip.c
@@ -42,6 +42,60 @@
     !defined(__AMIGA__) && !defined(__minix) && !defined(__SYMBIAN32__) && \
     !defined(__WATCOMC__)
 
+#if defined(HAVE_GETIFADDRS)
+
+/*
+ * glibc provides getifaddrs() to provide a list of all interfaces and their
+ * addresses.
+ */
+
+#include <ifaddrs.h>
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#include "inet_ntop.h"
+#include "strequal.h"
+
+char *Curl_if2ip(int af, const char *interface, char *buf, int buf_size)
+{
+  struct ifaddrs *iface, *head;
+  char *ip=NULL;
+
+  if (getifaddrs(&head) >= 0) {
+    for (iface=head; iface != NULL; iface=iface->ifa_next) {
+      if ((iface->ifa_addr->sa_family == af) &&
+          curl_strequal(iface->ifa_name, interface)) {
+        void *addr;
+	char scope[12]="";
+        if (af == AF_INET6) {
+          unsigned int scopeid;
+          addr = &((struct sockaddr_in6 *)iface->ifa_addr)->sin6_addr;
+	  /* Include the scope of this interface as part of the address */
+          scopeid = ((struct sockaddr_in6 *)iface->ifa_addr)->sin6_scope_id;
+          if (scopeid)
+	    snprintf(scope, sizeof(scope), "%%%u", scopeid);
+	} else
+          addr = &((struct sockaddr_in *)iface->ifa_addr)->sin_addr;
+        ip = (char *) Curl_inet_ntop(af, addr, buf, buf_size);
+	Curl_strlcat(buf, scope, buf_size);
+	break;
+      }
+    }
+    freeifaddrs(head);
+  }
+  return ip;
+}
+
+#else
+
 #ifdef HAVE_SYS_SOCKET_H
 #include <sys/socket.h>
 #endif
@@ -83,12 +137,12 @@
 
 #define SYS_ERROR -1
 
-char *Curl_if2ip(const char *interface, char *buf, int buf_size)
+char *Curl_if2ip(int af, const char *interface, char *buf, int buf_size)
 {
   int dummy;
   char *ip=NULL;
 
-  if(!interface)
+  if(!interface || (af != AF_INET))
     return NULL;
 
   dummy = socket(AF_INET, SOCK_STREAM, 0);
@@ -124,11 +178,13 @@ char *Curl_if2ip(const char *interface, char *buf, int buf_size)
   }
   return ip;
 }
+#endif
 
 /* -- end of if2ip() -- */
 #else
-char *Curl_if2ip(const char *interf, char *buf, int buf_size)
+char *Curl_if2ip(int af, const char *interf, char *buf, int buf_size)
 {
+    (void) af;
     (void) interf;
     (void) buf;
     (void) buf_size;
diff --git a/lib/if2ip.h b/lib/if2ip.h
index 4e86e2b27d496b1e90a25ba2139b5a00b91bbd05..6888a4cb8e10562c1e256409c3dd60237003a5cd 100644
--- a/lib/if2ip.h
+++ b/lib/if2ip.h
@@ -24,7 +24,7 @@
  ***************************************************************************/
 #include "setup.h"
 
-extern char *Curl_if2ip(const char *interf, char *buf, int buf_size);
+extern char *Curl_if2ip(int af, const char *interf, char *buf, int buf_size);
 
 #ifdef __INTERIX
 #include <sys/socket.h>