From: Geoff Thorpe Date: Sat, 26 Apr 2014 05:22:54 +0000 (-0400) Subject: s_client/s_server: support unix domain sockets X-Git-Tag: master-post-reformat~826 X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff_plain;h=a935132099af20a8a742d30f8edcb613e73a368d s_client/s_server: support unix domain sockets The "-unix " argument allows s_server and s_client to use a unix domain socket in the filesystem instead of IPv4 ("-connect", "-port", "-accept", etc). If s_server exits gracefully, such as when "-naccept" is used and the requested number of SSL/TLS connections have occurred, then the domain socket file is removed. On ctrl-C, it is likely that the stale socket file will be left over, such that s_server would normally fail to restart with the same arguments. For this reason, s_server also supports an "-unlink" option, which will clean up any stale socket file before starting. If you have any reason to want encrypted IPC within an O/S instance, this concept might come in handy. Otherwise it just demonstrates that there is nothing about SSL/TLS that limits it to TCP/IP in any way. (There might also be benchmarking and profiling use in this path, as unix domain sockets are much lower overhead than connecting over local IP addresses). Signed-off-by: Geoff Thorpe --- diff --git a/apps/s_apps.h b/apps/s_apps.h index 3b9f9a0cb7..9d16e45978 100644 --- a/apps/s_apps.h +++ b/apps/s_apps.h @@ -148,7 +148,14 @@ typedef fd_mask fd_set; #define PORT_STR "4433" #define PROTOCOL "tcp" -int do_server(int port, int type, int *ret, int (*cb) (char *hostname, int s, int stype, unsigned char *context), unsigned char *context, int naccept); +int do_server(int port, int type, int *ret, + int (*cb)(char *hostname, int s, int stype, unsigned char *context), + unsigned char *context, int naccept); +#ifndef NO_SYS_UN_H +int do_server_unix(const char *path, int *ret, + int (*cb)(char *hostname, int s, int stype, unsigned char *context), + unsigned char *context, int naccept); +#endif #ifdef HEADER_X509_H int MS_CALLBACK verify_callback(int ok, X509_STORE_CTX *ctx); #endif @@ -162,6 +169,9 @@ int ssl_print_curves(BIO *out, SSL *s, int noshared); #endif int ssl_print_tmp_key(BIO *out, SSL *s); int init_client(int *sock, const char *server, int port, int type); +#ifndef NO_SYS_UN_H +int init_client_unix(int *sock, const char *server); +#endif int should_retry(int i); int extract_port(const char *str, short *port_ptr); int extract_host_port(char *str,char **host_ptr,unsigned char *ip,short *p); diff --git a/apps/s_client.c b/apps/s_client.c index f8c059a25a..eee0e2e779 100644 --- a/apps/s_client.c +++ b/apps/s_client.c @@ -323,7 +323,8 @@ static void sc_usage(void) BIO_printf(bio_err,"\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); + BIO_printf(bio_err," -connect host:port - connect over TCP/IP (default is %s:%s)\n",SSL_HOST_NAME,PORT_STR); + BIO_printf(bio_err," -unix path - connect over unix domain sockets\n"); BIO_printf(bio_err," -verify arg - turn on peer certificate verification\n"); BIO_printf(bio_err," -cert arg - certificate file to use, PEM format assumed\n"); BIO_printf(bio_err," -certform arg - certificate format (PEM or DER) PEM default\n"); @@ -627,6 +628,7 @@ int MAIN(int argc, char **argv) short port=PORT; int full_log=1; char *host=SSL_HOST_NAME; + const char *unix_path = NULL; char *xmpphost = NULL; char *cert_file=NULL,*key_file=NULL,*chain_file=NULL; int cert_format = FORMAT_PEM, key_format = FORMAT_PEM; @@ -760,6 +762,11 @@ static char *jpake_secret = NULL; if (!extract_host_port(*(++argv),&host,NULL,&port)) goto bad; } + else if (strcmp(*argv,"-unix") == 0) + { + if (--argc < 1) goto bad; + unix_path = *(++argv); + } else if (strcmp(*argv,"-xmpphost") == 0) { if (--argc < 1) goto bad; @@ -1155,6 +1162,11 @@ bad: goto end; } + if (unix_path && (socket_type != SOCK_STREAM)) + { + BIO_printf(bio_err, "Can't use unix sockets and datagrams together\n"); + goto end; + } #if !defined(OPENSSL_NO_JPAKE) && !defined(OPENSSL_NO_PSK) if (jpake_secret) { @@ -1499,7 +1511,8 @@ bad: re_start: - if (init_client(&s,host,port,socket_type) == 0) + if ((!unix_path && (init_client(&s,host,port,socket_type) == 0)) || + (unix_path && (init_client_unix(&s,unix_path) == 0))) { BIO_printf(bio_err,"connect:errno=%d\n",get_last_socket_error()); SHUTDOWN(s); diff --git a/apps/s_server.c b/apps/s_server.c index 05ffc351f7..7c4f7bc7d7 100644 --- a/apps/s_server.c +++ b/apps/s_server.c @@ -479,7 +479,9 @@ static void sv_usage(void) { BIO_printf(bio_err,"usage: s_server [args ...]\n"); BIO_printf(bio_err,"\n"); - BIO_printf(bio_err," -accept arg - port to accept on (default is %d)\n",PORT); + BIO_printf(bio_err," -accept port - TCP/IP port to accept on (default is %d)\n",PORT); + BIO_printf(bio_err," -unix path - unix domain socket to accept on\n"); + BIO_printf(bio_err," -unlink - for -unix, unlink existing socket first\n"); BIO_printf(bio_err," -context arg - set session ID context\n"); BIO_printf(bio_err," -verify arg - turn on peer certificate verification\n"); BIO_printf(bio_err," -Verify arg - turn on peer certificate verification, must have a cert.\n"); @@ -1008,6 +1010,9 @@ int MAIN(int argc, char *argv[]) X509_VERIFY_PARAM *vpm = NULL; int badarg = 0; short port=PORT; + const char *unix_path=NULL; + int unlink_unix_path=0; + int (*server_cb)(char *hostname, int s, int stype, unsigned char *context); char *CApath=NULL,*CAfile=NULL; char *chCApath=NULL,*chCAfile=NULL; char *vfyCApath=NULL,*vfyCAfile=NULL; @@ -1100,6 +1105,25 @@ int MAIN(int argc, char *argv[]) if (!extract_port(*(++argv),&port)) goto bad; } + else if (strcmp(*argv,"-unix") == 0) + { +#ifdef NO_SYS_UN_H + BIO_printf(bio_err, "unix domain sockets unsupported\n"); + goto bad; +#else + if (--argc < 1) goto bad; + unix_path = *(++argv); +#endif + } + else if (strcmp(*argv,"-unlink") == 0) + { +#ifdef NO_SYS_UN_H + BIO_printf(bio_err, "unix domain sockets unsupported\n"); + goto bad; +#else + unlink_unix_path = 1; +#endif + } else if (strcmp(*argv,"-naccept") == 0) { if (--argc < 1) goto bad; @@ -1544,6 +1568,11 @@ bad: goto end; } + if (unix_path && (socket_type != SOCK_STREAM)) + { + BIO_printf(bio_err, "Can't use unix sockets and datagrams together\n"); + goto end; + } #if !defined(OPENSSL_NO_JPAKE) && !defined(OPENSSL_NO_PSK) if (jpake_secret) { @@ -2106,11 +2135,19 @@ bad: BIO_printf(bio_s_out,"ACCEPT\n"); (void)BIO_flush(bio_s_out); if (rev) - do_server(port,socket_type,&accept_socket,rev_body, context, naccept); + server_cb = rev_body; else if (www) - do_server(port,socket_type,&accept_socket,www_body, context, naccept); + server_cb = www_body; + else + server_cb = sv_body; + if (unix_path) + { + if (unlink_unix_path) + unlink(unix_path); + do_server_unix(unix_path,&accept_socket,server_cb, context, naccept); + } else - do_server(port,socket_type,&accept_socket,sv_body, context, naccept); + do_server(port,socket_type,&accept_socket,server_cb, context, naccept); print_stats(bio_s_out,ctx); ret=0; end: diff --git a/apps/s_socket.c b/apps/s_socket.c index 65003fb6f0..e83baf4e70 100644 --- a/apps/s_socket.c +++ b/apps/s_socket.c @@ -102,6 +102,10 @@ 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(const char *str, unsigned char ip[4]); +#ifndef NO_SYS_UN_H +static int init_server_unix(int *sock, const char *path); +static int do_accept_unix(int acc_sock, int *sock); +#endif #ifdef OPENSSL_SYS_WIN16 #define SOCKET_PROTOCOL 0 /* more microsoft stupidity */ @@ -280,7 +284,32 @@ static int init_client_ip(int *sock, const unsigned char ip[4], int port, return(1); } -int do_server(int port, int type, int *ret, int (*cb)(char *hostname, int s, int stype, unsigned char *context), unsigned char *context, int naccept) +#ifndef NO_SYS_UN_H +int init_client_unix(int *sock, const char *server) + { + struct sockaddr_un them; + int s; + + if (strlen(server) > (UNIX_PATH_MAX + 1)) return(0); + if (!ssl_sock_init()) return(0); + + s=socket(AF_UNIX, SOCK_STREAM, 0); + if (s == INVALID_SOCKET) { perror("socket"); return(0); } + + memset((char *)&them,0,sizeof(them)); + them.sun_family=AF_UNIX; + strcpy(them.sun_path, server); + + if (connect(s, (struct sockaddr *)&them, sizeof(them)) == -1) + { closesocket(s); perror("connect"); return(0); } + *sock=s; + return(1); + } +#endif + +int do_server(int port, int type, int *ret, + int (*cb)(char *hostname, int s, int stype, unsigned char *context), + unsigned char *context, int naccept) { int sock; char *name = NULL; @@ -324,6 +353,43 @@ int do_server(int port, int type, int *ret, int (*cb)(char *hostname, int s, int } } +#ifndef NO_SYS_UN_H +int do_server_unix(const char *path, int *ret, + int (*cb)(char *hostname, int s, int stype, unsigned char *context), + unsigned char *context, int naccept) + { + int sock; + int accept_socket = 0; + int i; + + if (!init_server_unix(&accept_socket, path)) return(0); + + if (ret != NULL) + *ret=accept_socket; + for (;;) + { + if (do_accept_unix(accept_socket, &sock) == 0) + { + SHUTDOWN(accept_socket); + i = 0; + goto out; + } + i=(*cb)(NULL, sock, 0, context); + SHUTDOWN2(sock); + if (naccept != -1) + naccept--; + if (i < 0 || naccept == 0) + { + SHUTDOWN2(accept_socket); + goto out; + } + } +out: + unlink(path); + return(i); + } +#endif + static int init_server_long(int *sock, int port, char *ip, int type) { int ret=0; @@ -382,6 +448,50 @@ static int init_server(int *sock, int port, int type) return(init_server_long(sock, port, NULL, type)); } +#ifndef NO_SYS_UN_H +static int init_server_unix(int *sock, const char *path) + { + int ret = 0; + struct sockaddr_un server; + int s = -1; + + if (strlen(path) > (UNIX_PATH_MAX + 1)) return(0); + if (!ssl_sock_init()) return(0); + + s=socket(AF_UNIX, SOCK_STREAM, 0); + if (s == INVALID_SOCKET) goto err; + + memset((char *)&server,0,sizeof(server)); + server.sun_family=AF_UNIX; + strcpy(server.sun_path, path); + + if (bind(s, (struct sockaddr *)&server, sizeof(server)) == -1) + { +#ifndef OPENSSL_SYS_WINDOWS + perror("bind"); +#endif + goto err; + } + /* Make it 128 for linux */ + if (listen(s,128) == -1) + { +#ifndef OPENSSL_SYS_WINDOWS + perror("listen"); +#endif + unlink(path); + goto err; + } + *sock=s; + ret=1; +err: + if ((ret == 0) && (s != -1)) + { + SHUTDOWN(s); + } + return(ret); + } +#endif + static int do_accept(int acc_sock, int *sock, char **host) { int ret; @@ -476,6 +586,32 @@ end: return(1); } +#ifndef NO_SYS_UN_H +static int do_accept_unix(int acc_sock, int *sock) + { + int ret; + + if (!ssl_sock_init()) return(0); + +redoit: + ret=accept(acc_sock, NULL, NULL); + if (ret == INVALID_SOCKET) + { + if (errno == EINTR) + { + /*check_timeout(); */ + goto redoit; + } + fprintf(stderr,"errno=%d ",errno); + perror("accept"); + return(0); + } + + *sock=ret; + return(1); + } +#endif + int extract_host_port(char *str, char **host_ptr, unsigned char *ip, short *port_ptr) { diff --git a/e_os.h b/e_os.h index c5ed54f3b2..4440ac28d7 100644 --- a/e_os.h +++ b/e_os.h @@ -579,6 +579,16 @@ static unsigned int _strlen31(const char *str) # include # else # include +# ifndef NO_SYS_UN_H +# ifdef OPENSSL_SYS_VXWORKS +# include +# else +# include +# endif +# ifndef UNIX_PATH_MAX +# define UNIX_PATH_MAX sizeof(((struct sockaddr_un *)NULL)->sun_path) +# endif +# endif # ifdef FILIO_H # include /* Added for FIONBIO under unixware */ # endif