Hi,

This diff changes the s_client and s_server apps to use getaddrinfo
for address parsing rather than manual IPv4 parsing and gethostbyname.

This allows specification of port by name:

openssl s_client -connect bugzilla.mindrot.org:https

But the main point is to support IPv6. You can now specify an IPv6
address explicitly (using '/' as a port separator to avoid ambiguity)
or use DNS names with IPv6 A records listed. s_client gets new -4 and
-6 options to force the issue when a host resolves to both IPv4 and
IPv6 addresses.

diff is against 0.9.8j, it has been in OpenBSD for a couple of years
now.

-d

Index: apps/s_apps.h
===================================================================
RCS file: /cvs/src/lib/libssl/src/apps/s_apps.h,v
retrieving revision 1.1.1.4
retrieving revision 1.8
diff -u -p -r1.1.1.4 -r1.8
--- apps/s_apps.h       6 Sep 2008 12:15:38 -0000       1.1.1.4
+++ apps/s_apps.h       6 Sep 2008 12:20:16 -0000       1.8
@@ -156,10 +156,10 @@ int MS_CALLBACK verify_callback(int ok, 
 int set_cert_stuff(SSL_CTX *ctx, char *cert_file, char *key_file);
 int set_cert_key_stuff(SSL_CTX *ctx, X509 *cert, EVP_PKEY *key);
 #endif
-int init_client(int *sock, char *server, int port, int type);
+int init_client(int *sock, char *server, char *port, int type, int af);
 int should_retry(int i);
 int extract_port(char *str, short *port_ptr);
-int extract_host_port(char *str,char **host_ptr,unsigned char *ip,short *p);
+int extract_host_port(char *str,char **host_ptr,unsigned char *ip,char **p);
 
 long MS_CALLBACK bio_dump_callback(BIO *bio, int cmd, const char *argp,
        int argi, long argl, long ret);
Index: apps/s_client.c
===================================================================
RCS file: /cvs/src/lib/libssl/src/apps/s_client.c,v
retrieving revision 1.1.1.8
diff -u -p -r1.1.1.8 s_client.c
--- apps/s_client.c     9 Jan 2009 12:13:49 -0000       1.1.1.8
+++ apps/s_client.c     30 Jan 2009 03:45:08 -0000
@@ -109,6 +109,8 @@
  *
  */
 
+#include <sys/types.h>
+#include <netinet/in.h>
 #include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -192,6 +194,8 @@ static void sc_usage(void)
        {
        BIO_printf(bio_err,"usage: s_client args\n");
        BIO_printf(bio_err,"\n");
+       BIO_printf(bio_err," -4            - Force IPv4\n");
+       BIO_printf(bio_err," -6            - Force IPv6\n");
        BIO_printf(bio_err," -host host     - use -connect instead\n");
        BIO_printf(bio_err," -port port     - use -connect instead\n");
        BIO_printf(bio_err," -connect host:port - who to connect to (default is 
%s:%s)\n",SSL_HOST_NAME,PORT_STR);
@@ -289,12 +293,12 @@ int MAIN(int argc, char **argv)
        int off=0;
        SSL *con=NULL,*con2=NULL;
        X509_STORE *store = NULL;
-       int s,k,width,state=0;
+       int s,k,width,state=0, af=AF_UNSPEC;
        char *cbuf=NULL,*sbuf=NULL,*mbuf=NULL;
        int cbuf_len,cbuf_off;
        int sbuf_len,sbuf_off;
        fd_set readfds,writefds;
-       short port=PORT;
+       char *port=PORT_STR;
        int full_log=1;
        char *host=SSL_HOST_NAME;
        char *cert_file=NULL,*key_file=NULL;
@@ -391,8 +395,8 @@ int MAIN(int argc, char **argv)
                else if (strcmp(*argv,"-port") == 0)
                        {
                        if (--argc < 1) goto bad;
-                       port=atoi(*(++argv));
-                       if (port == 0) goto bad;
+                       port= *(++argv);
+                       if (port == NULL || *port == '\0') goto bad;
                        }
                else if (strcmp(*argv,"-connect") == 0)
                        {
@@ -578,6 +582,8 @@ int MAIN(int argc, char **argv)
                        if (--argc < 1) goto bad;
                        inrand= *(++argv);
                        }
+               else if (strcmp(*argv,"-4") == 0) { af = AF_INET;}
+               else if (strcmp(*argv,"-6") == 0) { af = AF_INET6;}
 #ifndef OPENSSL_NO_TLSEXT
                else if (strcmp(*argv,"-servername") == 0)
                        {
@@ -795,7 +801,7 @@ bad:
 
 re_start:
 
-       if (init_client(&s,host,port,sock_type) == 0)
+       if (init_client(&s,host,port,sock_type,af) == 0)
                {
                
BIO_printf(bio_err,"connect:errno=%d\n",get_last_socket_error());
                SHUTDOWN(s);
Index: apps/s_socket.c
===================================================================
RCS file: /cvs/src/lib/libssl/src/apps/s_socket.c,v
retrieving revision 1.1.1.6
diff -u -p -r1.1.1.6 s_socket.c
--- apps/s_socket.c     6 Sep 2008 12:15:39 -0000       1.1.1.6
+++ apps/s_socket.c     30 Jan 2009 03:45:08 -0000
@@ -96,11 +96,9 @@ static struct hostent *GetHostByName(cha
 static void ssl_sock_cleanup(void);
 #endif
 static int ssl_sock_init(void);
-static int init_client_ip(int *sock,unsigned char ip[4], int port, int type);
 static int init_server(int *sock, int port, int type);
 static int init_server_long(int *sock, int port,char *ip, int type);
 static int do_accept(int acc_sock, int *sock, char **host);
-static int host_ip(char *str, unsigned char ip[4]);
 
 #ifdef OPENSSL_SYS_WIN16
 #define SOCKET_PROTOCOL        0 /* more microsoft stupidity */
@@ -228,44 +226,33 @@ static int ssl_sock_init(void)
        return(1);
        }
 
-int init_client(int *sock, char *host, int port, int type)
+int init_client(int *sock, char *host, char *port, int type, int af)
        {
-       unsigned char ip[4];
-       short p=0;
-
-       if (!host_ip(host,&(ip[0])))
-               {
-               return(0);
-               }
-       if (p != 0) port=p;
-       return(init_client_ip(sock,ip,port,type));
-       }
-
-static int init_client_ip(int *sock, unsigned char ip[4], int port, int type)
-       {
-       unsigned long addr;
-       struct sockaddr_in them;
-       int s,i;
+       struct addrinfo hints, *ai_top, *ai;
+       int i, s;
 
        if (!ssl_sock_init()) return(0);
 
-       memset((char *)&them,0,sizeof(them));
-       them.sin_family=AF_INET;
-       them.sin_port=htons((unsigned short)port);
-       addr=(unsigned long)
-               ((unsigned long)ip[0]<<24L)|
-               ((unsigned long)ip[1]<<16L)|
-               ((unsigned long)ip[2]<< 8L)|
-               ((unsigned long)ip[3]);
-       them.sin_addr.s_addr=htonl(addr);
+       memset(&hints, '\0', sizeof(hints));
+       hints.ai_family = af;
+       hints.ai_socktype = type;
 
-       if (type == SOCK_STREAM)
-               s=socket(AF_INET,SOCK_STREAM,SOCKET_PROTOCOL);
-       else /* ( type == SOCK_DGRAM) */
-               s=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
-                       
-       if (s == INVALID_SOCKET) { perror("socket"); return(0); }
+       if ((i = getaddrinfo(host, port, &hints, &ai_top)) != 0)
+               {
+               BIO_printf(bio_err,"getaddrinfo: %s\n", gai_strerror(i));
+               return (0);
+               }
+       if (ai_top == NULL || ai_top->ai_addr == NULL)
+               {
+               BIO_printf(bio_err,"getaddrinfo returned no addresses\n");
+               if (ai_top != NULL) { freeaddrinfo(ai_top); }
+               return (0);
+               }
 
+       for (ai = ai_top; ai != NULL; ai = ai->ai_next)
+               {
+               s=socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+               if (s == INVALID_SOCKET) { continue; }
 #ifndef OPENSSL_SYS_MPE
        if (type == SOCK_STREAM)
                {
@@ -274,11 +261,16 @@ static int init_client_ip(int *sock, uns
                if (i < 0) { perror("keepalive"); return(0); }
                }
 #endif
+               if ((i = connect(s, ai->ai_addr, ai->ai_addrlen)) == 0)
+                       { *sock=s; freeaddrinfo(ai_top); return (1); }
 
-       if (connect(s,(struct sockaddr *)&them,sizeof(them)) == -1)
-               { close(s); perror("connect"); return(0); }
-       *sock=s;
-       return(1);
+               close(s);
+               }
+
+       perror("connect");
+       close(s);
+       freeaddrinfo(ai_top);
+       return(0);
        }
 
 int do_server(int port, int type, int *ret, int (*cb)(char *hostname, int s, 
unsigned char *context), unsigned char *context)
@@ -470,12 +462,13 @@ end:
        }
 
 int extract_host_port(char *str, char **host_ptr, unsigned char *ip,
-            short *port_ptr)
+            char **port_ptr)
        {
        char *h,*p;
 
        h=str;
-       p=strchr(str,':');
+       p=strrchr(str,'/'); /* IPv6 host/port */
+       if (p == NULL) { p=strrchr(str,':'); }
        if (p == NULL)
                {
                BIO_printf(bio_err,"no port defined\n");
@@ -483,58 +476,11 @@ int extract_host_port(char *str, char **
                }
        *(p++)='\0';
 
-       if ((ip != NULL) && !host_ip(str,ip))
-               goto err;
        if (host_ptr != NULL) *host_ptr=h;
 
-       if (!extract_port(p,port_ptr))
-               goto err;
-       return(1);
-err:
-       return(0);
-       }
-
-static int host_ip(char *str, unsigned char ip[4])
-       {
-       unsigned int in[4]; 
-       int i;
-
-       if (sscanf(str,"%u.%u.%u.%u",&(in[0]),&(in[1]),&(in[2]),&(in[3])) == 4)
-               {
-               for (i=0; i<4; i++)
-                       if (in[i] > 255)
-                               {
-                               BIO_printf(bio_err,"invalid IP address\n");
-                               goto err;
-                               }
-               ip[0]=in[0];
-               ip[1]=in[1];
-               ip[2]=in[2];
-               ip[3]=in[3];
-               }
-       else
-               { /* do a gethostbyname */
-               struct hostent *he;
-
-               if (!ssl_sock_init()) return(0);
+       if (port_ptr != NULL && p != NULL && *p != '\0')
+               *port_ptr = p;
 
-               he=GetHostByName(str);
-               if (he == NULL)
-                       {
-                       BIO_printf(bio_err,"gethostbyname failure\n");
-                       goto err;
-                       }
-               /* cast to short because of win16 winsock definition */
-               if ((short)he->h_addrtype != AF_INET)
-                       {
-                       BIO_printf(bio_err,"gethostbyname addr is not 
AF_INET\n");
-                       return(0);
-                       }
-               ip[0]=he->h_addr_list[0][0];
-               ip[1]=he->h_addr_list[0][1];
-               ip[2]=he->h_addr_list[0][2];
-               ip[3]=he->h_addr_list[0][3];
-               }
        return(1);
 err:
        return(0);

______________________________________________________________________
OpenSSL Project                                 http://www.openssl.org
Development Mailing List                       openssl-dev@openssl.org
Automated List Manager                           majord...@openssl.org

Reply via email to