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