Subversion Repositories

?revision_form?Rev ?revision_input??revision_submit??revision_endform?

Rev 28 | Blame | Compare with Previous | Last modification | View Log | RSS feed

Description: IPv6 support.
 No -4 or -6 options initially. Literal IPv6 addresses can be specified using [].
Bug-Debian: https://bugs.debian.org/633085

--- a/sockets.c
+++ b/sockets.c
@@ -99,42 +99,66 @@ WriteExact(int sock, char *buf, int n)
  */
 
 int
-ConnectToTcpAddr(unsigned int host, int port)
+ConnectToTcpAddr(const char *hostname, int port)
 {
-  int sock;
-  struct sockaddr_in addr;
+  int sock = -1;
   int one = 1;
   
-  addr.sin_family = AF_INET;
-  addr.sin_port = htons(port);
-  addr.sin_addr.s_addr = host;
-  
+  struct addrinfo hints;
+  memset(&hints, 0, sizeof(struct addrinfo));
+  hints.ai_socktype = SOCK_STREAM;
+  hints.ai_flags = AI_NUMERICSERV;
+
+  char portstr[3*sizeof(int)+1];
   if(useSSHTunnel)
   {
-    char *remote, *gateway;
+    const char *remote, *gateway;
     if(useSSHGateway)
     {
       gateway=useSSHGateway;
-      remote=inet_ntoa(addr.sin_addr);
+      remote=hostname;
     }else{
-      gateway=inet_ntoa(addr.sin_addr);
-      remote="127.0.0.1";
+      gateway=hostname;
+      remote="localhost";
     }
-    addr.sin_port=htons(tunnel(gateway, remote, port));
-    inet_aton("127.0.0.1",& addr.sin_addr);
+    sprintf(portstr, "%i", tunnel(gateway, remote, port));
+    hostname = 0; /* Request loopback address from getaddrinfo() */
+  } else {
+    sprintf(portstr, "%i", port);
   }
-  
-  sock = socket(AF_INET, SOCK_STREAM, 0);
-  if (sock < 0) {
-    fprintf(stderr,"%s",programName);
-    perror(": ConnectToTcpAddr: socket");
-    return -1;
+
+  struct addrinfo *res;
+  int eai = getaddrinfo(hostname, portstr, &hints, &res);
+  if (eai) {
+      if (eai == EAI_SYSTEM) {
+         fprintf(stderr,"%s",programName);
+         perror(": ConnectToTcpAddr: getaddrinfo");
+      } else {
+         fprintf(stderr, "%s: ConnectToTcpAddr: getaddrinfo: %s\n", programName, gai_strerror(eai));
+         return -1;
+      }
   }
+  struct addrinfo *ai;
+  for (ai = res; ai; ai = ai->ai_next) {
+    sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+    if (sock < 0) {
+      fprintf(stderr,"%s",programName);
+      perror(": ConnectToTcpAddr: socket");
+      continue;
+    }
   
-  if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
-    fprintf(stderr,"%s",programName);
-    perror(": ConnectToTcpAddr: connect");
-    close(sock);
+    if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
+       fprintf(stderr,"%s",programName);
+       perror(": ConnectToTcpAddr: connect");
+       close(sock);
+       sock = -1;
+    } else {
+       break;
+    }
+  }
+  freeaddrinfo(res);
+  if (sock < 0) {
+    fprintf(stderr,"%s: Could not connect to any address\n", programName);
     return -1;
   }
   
@@ -157,41 +181,64 @@ ConnectToTcpAddr(unsigned int host, int
 int
 ListenAtTcpPort(int port)
 {
-    int sock;
-    struct sockaddr_in addr;
-    int one = 1;
-
-    addr.sin_family = AF_INET;
-    addr.sin_port = htons(port);
-    addr.sin_addr.s_addr = INADDR_ANY;
-
-    sock = socket(AF_INET, SOCK_STREAM, 0);
-    if (sock < 0) {
-       fprintf(stderr,"%s",programName);
-       perror(": ListenAtTcpPort: socket");
-       return -1;
-    }
+    int sock = -1;
+    int one = 1, zero = 0;
+    
+    struct sockaddr_storage addr;
+    socklen_t addrlen;
 
-    if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
-                  (const char *)&one, sizeof(one)) < 0) {
-       fprintf(stderr,"%s",programName);
-       perror(": ListenAtTcpPort: setsockopt");
-       close(sock);
-       return -1;
-    }
+    for (addr.ss_family = AF_INET6; sock < 0 && addr.ss_family;
+        addr.ss_family = (addr.ss_family == AF_INET6 ? AF_INET : 0)) {
 
-    if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
-       fprintf(stderr,"%s",programName);
-       perror(": ListenAtTcpPort: bind");
-       close(sock);
-       return -1;
-    }
-
-    if (listen(sock, 5) < 0) {
-       fprintf(stderr,"%s",programName);
-       perror(": ListenAtTcpPort: listen");
-       close(sock);
-       return -1;
+       sock = socket(addr.ss_family, SOCK_STREAM, 0);
+       if (sock < 0) {
+           fprintf(stderr,"%s",programName);
+           perror(": ListenAtTcpPort: socket");
+           continue;
+       }
+
+       if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
+                      (const char *)&one, sizeof(one)) < 0) {
+           fprintf(stderr,"%s",programName);
+           perror(": ListenAtTcpPort: setsockopt");
+           close(sock); sock = -1;
+           continue;
+       }
+
+       if (addr.ss_family == AF_INET6) {
+           struct sockaddr_in6 *addr6 = (struct sockaddr_in6*)&addr;
+           addr6->sin6_port = htons(port);
+           memcpy(addr6->sin6_addr.s6_addr, &in6addr_any, sizeof(in6addr_any));
+           addrlen = sizeof(struct sockaddr_in6);
+           if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
+                          &zero, sizeof(zero)) < 0) {
+               fprintf(stderr,"%s",programName);
+               perror(": Warning: ListenAtTcpPort: setsockopt");
+           }
+       } else {
+           struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr;
+           addr4->sin_port = htons(port);
+           addr4->sin_addr.s_addr = INADDR_ANY;
+           addrlen = sizeof(struct sockaddr_in);
+       }
+
+       if (bind(sock, (struct sockaddr *)&addr, addrlen) < 0
+           && (addr.ss_family != AF_INET6
+               || setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
+                             &one, sizeof(one)) < 0
+               || bind(sock, (struct sockaddr *)&addr, addrlen) < 0)) {
+           fprintf(stderr,"%s",programName);
+           perror(": ListenAtTcpPort: bind");
+           close(sock); sock = -1;
+           continue;
+       }
+
+       if (listen(sock, 5) < 0) {
+           fprintf(stderr,"%s",programName);
+           perror(": ListenAtTcpPort: listen");
+           close(sock); sock = -1;
+           continue;
+       }
     }
 
     return sock;
@@ -208,22 +255,39 @@ int getFreePort(void)
   for(x=0;x<100;x++)
   {
     int port = 5500 + last % 100;
+    char portstr[3*sizeof(int)+1];
+    sprintf(portstr, "%i", port);
     last+=4711;
-  
-    addr.sin_family = AF_INET;
-    addr.sin_port = htons(port);
-    addr.sin_addr.s_addr = INADDR_ANY;
-    
-    sock = socket(AF_INET, SOCK_STREAM, 0);
-    if (sock < 0 ||
-        setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
-                   (const char *)&one, sizeof(one)) < 0 ||
-        bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
-    {
-      close(sock);
-    }else{
-      close(sock);
-      return port;
+
+    struct addrinfo *res = 0;
+    struct addrinfo hints;
+    memset(&hints, 0, sizeof(struct addrinfo));
+    hints.ai_socktype = SOCK_STREAM;
+  
+    int eai = getaddrinfo(0, portstr, &hints, &res);
+    if (eai) {
+       fprintf(stderr, "%s: getaddrinfo() failed when finding a free port: %s\n",
+               programName, gai_strerror(eai));
+       return -1;
+    }
+    for (struct addrinfo *ai = res; ai; ai = ai->ai_next) {
+       sock = socket(ai->ai_family, SOCK_STREAM, 0);
+       if (sock < 0 ||
+           setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
+                      &one, sizeof(one)) < 0 ||
+           (ai->ai_family == AF_INET6 && setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
+                                                    &one, sizeof(one)) < 0) ||
+           bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
+           close(sock);
+           sock = -1;
+           freeaddrinfo(res);
+           break;
+       } else {
+           close(sock);
+       }
+    }
+    if (sock > 0) {
+       return port;
     }
   }
   return -1;
@@ -238,7 +302,7 @@ int
 AcceptTcpConnection(int listenSock)
 {
     int sock;
-    struct sockaddr_in addr;
+    struct sockaddr_storage addr;
     int addrlen = sizeof(addr);
     int one = 1;
 
--- a/rfbproto.c
+++ b/rfbproto.c
@@ -60,15 +60,8 @@ static char buffer[BUFFER_SIZE];
 Bool
 ConnectToRFBServer(const char *hostname, int port)
 {
-    unsigned int host;
 
-    if (!StringToIPAddr(hostname, &host)) {
-       fprintf(stderr,"%s: couldn't convert '%s' to host address\n",
-               programName,hostname);
-       return False;
-    }
-
-    rfbsock = ConnectToTcpAddr(host, port);
+    rfbsock = ConnectToTcpAddr(hostname, port);
 
     if (rfbsock < 0) {
        fprintf(stderr,"%s: unable to connect to VNC server\n",
--- a/x2vnc.h
+++ b/x2vnc.h
@@ -140,7 +140,7 @@ extern Bool ReadExact(int sock, char *bu
 extern Bool WriteExact(int sock, char *buf, int n);
 extern int ListenAtTcpPort(int port);
 extern int getFreePort();
-extern int ConnectToTcpAddr(unsigned int host, int port);
+extern int ConnectToTcpAddr(const char *host, int port);
 extern int AcceptTcpConnection(int listenSock);
 extern int StringToIPAddr(const char *str, unsigned int *addr);
 extern Bool SameMachine(int sock);
--- a/args.c
+++ b/args.c
@@ -251,7 +251,8 @@ void processArgs(int argc, char **argv)
       
       argumentSpecified = True;
       
-      if (sscanf(argv[i], "%[^:]:%d", hostname, &port) != 2) usage();
+      if (sscanf(argv[i], "[%255[0-9a-f:]]:%d", hostname, &port) != 2
+         && sscanf(argv[i], "%255[^:]:%d", hostname, &port) != 2) usage();
       
       if (port < 100)
        port += SERVERPORT;