From 02f6e0770900a138dc8d0a882cd0321bd90a8884 Mon Sep 17 00:00:00 2001 From: Dirk Date: Tue, 29 Mar 2016 19:46:44 +0200 Subject: [PATCH] - ipv6 changes (tested with 1.0.2h) --- bin/Readme.md | 4 +- bin/fedora-dirk-ipv6.diff | 531 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 534 insertions(+), 1 deletion(-) create mode 100644 bin/fedora-dirk-ipv6.diff diff --git a/bin/Readme.md b/bin/Readme.md index a70f1a7..9b6c6be 100644 --- a/bin/Readme.md +++ b/bin/Readme.md @@ -86,7 +86,9 @@ If you want to compile OpenSSL yourself, here are the instructions: enable-seed enable-camellia enable-idea enable-rfc3779 no-ec_nistp_64_gcc_128 \ -static experimental-jpake -DOPENSSL_USE_BUILD_DATE -(IPv6 would need additionally ``-DOPENSSL_USE_IPV6`` and the tree https://github.com/PeterMosmans/openssl/tree/ipv6.) +(IPv6 would need additionally ``-DOPENSSL_USE_IPV6`` and the patch from ``fedora-dirk-ipv6.diff`` +-- this doesn't give you the option of an IPv6 enabled proxy -- yet.) + Four GOST [1][2] ciphers come via engine support automagically with this setup. Two additional GOST ciphers can be compiled in (``GOST-GOST94``, ``GOST-MD5``) with ``-DTEMP_GOST_TLS`` but as of now they make problems under rare circumstances, so unless you desperately need those ciphers I would stay away from ``-DTEMP_GOST_TLS``. diff --git a/bin/fedora-dirk-ipv6.diff b/bin/fedora-dirk-ipv6.diff new file mode 100644 index 0000000..9e4ee24 --- /dev/null +++ b/bin/fedora-dirk-ipv6.diff @@ -0,0 +1,531 @@ +--- a/apps/s_apps.h ++++ b/apps/s_apps.h +@@ -151,7 +151,7 @@ typedef fd_mask fd_set; + #define PORT_STR "4433" + #define PROTOCOL "tcp" + +-int do_server(int port, int type, int *ret, ++int do_server(char *port, int type, int *ret, + int (*cb) (char *hostname, int s, int stype, + unsigned char *context), unsigned char *context, + int naccept); +@@ -167,11 +167,10 @@ int ssl_print_point_formats(BIO *out, SSL *s); + 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, char *server, int port, int type); ++int init_client(int *sock, char *server, char *port, int type); + 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, char **port_ptr); + + long MS_CALLBACK bio_dump_callback(BIO *bio, int cmd, const char *argp, + int argi, long argl, long ret); + +--- a/apps/s_client.c ++++ b/apps/s_client.c +@@ -678,7 +678,7 @@ int MAIN(int argc, char **argv) + int cbuf_len, cbuf_off; + int sbuf_len, sbuf_off; + fd_set readfds, writefds; +- short port = PORT; ++ char *port_str = PORT_STR; + char *http_proxy_str = NULL, *connect_str = NULL; + int full_log = 1; + char *host = SSL_HOST_NAME; +@@ -803,9 +803,7 @@ 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_str = *(++argv); + } else if (strcmp(*argv, "-connect") == 0) { + if (--argc < 1) + goto bad; +@@ -1156,10 +1154,10 @@ int MAIN(int argc, char **argv) + } + + if (http_proxy_str) { +- if (!extract_host_port(http_proxy_str, &host, NULL, &port)) ++ if (!extract_host_port(http_proxy_str, &host, &port_str)) + goto bad; + } else if (connect_str) { +- if (!extract_host_port(connect_str, &host, NULL, &port)) ++ if (!extract_host_port(connect_str, &host, &port_str)) + goto bad; + } + +@@ -1456,7 +1454,7 @@ int MAIN(int argc, char **argv) + + re_start: + +- if (init_client(&s, host, port, socket_type) == 0) { ++ if (init_client(&s, host, port_str, socket_type) == 0) { + BIO_printf(bio_err, "connect:errno=%d\n", get_last_socket_error()); + SHUTDOWN(s); + goto end; + +--- a/apps/s_server.c ++++ b/apps/s_server.c +@@ -1093,7 +1093,7 @@ int MAIN(int argc, char *argv[]) + { + X509_VERIFY_PARAM *vpm = NULL; + int badarg = 0; +- short port = PORT; ++ char *port_str = PORT_STR; + char *CApath = NULL, *CAfile = NULL; + char *chCApath = NULL, *chCAfile = NULL; + char *vfyCApath = NULL, *vfyCAfile = NULL; +@@ -1180,7 +1180,8 @@ int MAIN(int argc, char *argv[]) + if ((strcmp(*argv, "-port") == 0) || (strcmp(*argv, "-accept") == 0)) { + if (--argc < 1) + goto bad; +- if (!extract_port(*(++argv), &port)) ++ port_str = *(++argv); ++ if (port_str == NULL || *port_str == '\0') + goto bad; + } else if (strcmp(*argv, "-naccept") == 0) { + if (--argc < 1) +@@ -2056,13 +2057,13 @@ int MAIN(int argc, char *argv[]) + 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, ++ do_server(port_str, socket_type, &accept_socket, rev_body, context, + naccept); + else if (www) +- do_server(port, socket_type, &accept_socket, www_body, context, ++ do_server(port_str, socket_type, &accept_socket, www_body, context, + naccept); + else +- do_server(port, socket_type, &accept_socket, sv_body, context, ++ do_server(port_str, socket_type, &accept_socket, sv_body, context, + naccept); + print_stats(bio_s_out, ctx); + ret = 0; + +--- a/apps/s_socket.c ++++ b/apps/s_socket.c +@@ -106,9 +106,7 @@ static struct hostent *GetHostByName(char *name); + 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 init_server(int *sock, char *port, int type); + static int do_accept(int acc_sock, int *sock, char **host); + static int host_ip(char *str, unsigned char ip[4]); + +@@ -231,65 +229,66 @@ 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) + { +- unsigned char ip[4]; +- +- memset(ip, '\0', sizeof ip); +- if (!host_ip(host, &(ip[0]))) +- return 0; +- 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 *res, *res0, hints; ++ char *failed_call = NULL; ++ int s; ++ int e; + + 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); +- +- if (type == SOCK_STREAM) +- s = socket(AF_INET, SOCK_STREAM, SOCKET_PROTOCOL); +- else /* ( type == SOCK_DGRAM) */ +- s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); ++ memset(&hints, '\0', sizeof(hints)); ++ hints.ai_socktype = type; ++ hints.ai_flags = AI_ADDRCONFIG; + +- if (s == INVALID_SOCKET) { +- perror("socket"); ++ e = getaddrinfo(host, port, &hints, &res); ++ if (e) { ++ fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(e)); ++ if (e == EAI_SYSTEM) ++ perror("getaddrinfo"); + return (0); + } ++ ++ res0 = res; ++ while (res) { ++ s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); ++ if (s == INVALID_SOCKET) { ++ failed_call = "socket"; ++ goto nextres; ++ } + # if defined(SO_KEEPALIVE) && !defined(OPENSSL_SYS_MPE) +- if (type == SOCK_STREAM) { +- i = 0; +- i = setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char *)&i, sizeof(i)); +- if (i < 0) { +- closesocket(s); +- perror("keepalive"); +- return (0); ++ if (type == SOCK_STREAM) { ++ int i = 0; ++ i = setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, ++ (char *)&i, sizeof(i)); ++ if (i < 0) { ++ failed_call = "keepalive"; ++ goto nextres; ++ } + } +- } + # endif ++ if (connect(s, (struct sockaddr *)res->ai_addr, res->ai_addrlen) == 0) { ++ freeaddrinfo(res0); ++ *sock = s; ++ return (1); ++ } + +- if (connect(s, (struct sockaddr *)&them, sizeof(them)) == -1) { +- closesocket(s); +- perror("connect"); +- return (0); ++ failed_call = "socket"; ++ nextres: ++ if (s != INVALID_SOCKET) ++ close(s); ++ res = res->ai_next; + } +- *sock = s; +- return (1); ++ freeaddrinfo(res0); ++ closesocket(s); ++ ++ perror(failed_call); ++ return (0); + } + +-int do_server(int port, int type, int *ret, ++int do_server(char *port, int type, int *ret, + int (*cb) (char *hostname, int s, int stype, + unsigned char *context), unsigned char *context, + int naccept) +@@ -328,69 +327,89 @@ int do_server(int port, int type, int *ret, + } + } + +-static int init_server_long(int *sock, int port, char *ip, int type) ++static int init_server(int *sock, char *port, int type) + { +- int ret = 0; +- struct sockaddr_in server; +- int s = -1; ++ struct addrinfo *res, *res0 = NULL, hints; ++ char *failed_call = NULL; ++ int s = INVALID_SOCKET; ++ int e; + + if (!ssl_sock_init()) + return (0); + +- memset((char *)&server, 0, sizeof(server)); +- server.sin_family = AF_INET; +- server.sin_port = htons((unsigned short)port); +- if (ip == NULL) +- server.sin_addr.s_addr = INADDR_ANY; +- else +-/* Added for T3E, address-of fails on bit field (beckman@acl.lanl.gov) */ +-# ifndef BIT_FIELD_LIMITS +- memcpy(&server.sin_addr.s_addr, ip, 4); +-# else +- memcpy(&server.sin_addr, ip, 4); +-# endif +- +- if (type == SOCK_STREAM) +- s = socket(AF_INET, SOCK_STREAM, SOCKET_PROTOCOL); +- else /* type == SOCK_DGRAM */ +- s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); ++ memset(&hints, '\0', sizeof(hints)); ++ hints.ai_family = AF_INET6; ++ tryipv4: ++ hints.ai_socktype = type; ++ hints.ai_flags = AI_PASSIVE; ++ ++ e = getaddrinfo(NULL, port, &hints, &res); ++ if (e) { ++ if (hints.ai_family == AF_INET) { ++ fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(e)); ++ if (e == EAI_SYSTEM) ++ perror("getaddrinfo"); ++ return (0); ++ } else ++ res = NULL; ++ } + +- if (s == INVALID_SOCKET) +- goto err; ++ res0 = res; ++ while (res) { ++ s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); ++ if (s == INVALID_SOCKET) { ++ failed_call = "socket"; ++ goto nextres; ++ } ++ if (hints.ai_family == AF_INET6) { ++ int j = 0; ++ setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&j, sizeof j); ++ } + # if defined SOL_SOCKET && defined SO_REUSEADDR +- { +- int j = 1; +- setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void *)&j, sizeof j); +- } +-# endif +- if (bind(s, (struct sockaddr *)&server, sizeof(server)) == -1) { +-# ifndef OPENSSL_SYS_WINDOWS +- perror("bind"); ++ { ++ int j = 1; ++ setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void *)&j, sizeof j); ++ } + # endif +- goto err; ++ ++ if (bind(s, (struct sockaddr *)res->ai_addr, res->ai_addrlen) == -1) { ++ failed_call = "bind"; ++ goto nextres; ++ } ++ if (type == SOCK_STREAM && listen(s, 128) == -1) { ++ failed_call = "listen"; ++ goto nextres; ++ } ++ ++ *sock = s; ++ return (1); ++ ++ nextres: ++ if (s != INVALID_SOCKET) ++ close(s); ++ res = res->ai_next; + } +- /* Make it 128 for linux */ +- if (type == SOCK_STREAM && listen(s, 128) == -1) +- goto err; +- *sock = s; +- ret = 1; +- err: +- if ((ret == 0) && (s != -1)) { +- SHUTDOWN(s); ++ if (res0) ++ freeaddrinfo(res0); ++ ++ if (s == INVALID_SOCKET) { ++ if (hints.ai_family == AF_INET6) { ++ hints.ai_family = AF_INET; ++ goto tryipv4; ++ } ++ perror("socket"); ++ return (0); + } +- return (ret); +-} + +-static int init_server(int *sock, int port, int type) +-{ +- return (init_server_long(sock, port, NULL, type)); ++ perror(failed_call); ++ return (0); + } + + static int do_accept(int acc_sock, int *sock, char **host) + { ++ static struct sockaddr_storage from; ++ char buffer[NI_MAXHOST]; + int ret; +- struct hostent *h1, *h2; +- static struct sockaddr_in from; + int len; + /* struct linger ling; */ + +@@ -432,134 +451,60 @@ static int do_accept(int acc_sock, int *sock, char **host) + ling.l_onoff=1; + ling.l_linger=0; + i=setsockopt(ret,SOL_SOCKET,SO_LINGER,(char *)&ling,sizeof(ling)); +- if (i < 0) { perror("linger"); return(0); } ++ if (i < 0) { closesocket(ret); perror("linger"); return(0); } + i=0; + i=setsockopt(ret,SOL_SOCKET,SO_KEEPALIVE,(char *)&i,sizeof(i)); +- if (i < 0) { perror("keepalive"); return(0); } ++ if (i < 0) { closesocket(ret); perror("keepalive"); return(0); } + */ + + if (host == NULL) + goto end; +-# ifndef BIT_FIELD_LIMITS +- /* I should use WSAAsyncGetHostByName() under windows */ +- h1 = gethostbyaddr((char *)&from.sin_addr.s_addr, +- sizeof(from.sin_addr.s_addr), AF_INET); +-# else +- h1 = gethostbyaddr((char *)&from.sin_addr, +- sizeof(struct in_addr), AF_INET); +-# endif +- if (h1 == NULL) { +- BIO_printf(bio_err, "bad gethostbyaddr\n"); ++ ++ if (getnameinfo((struct sockaddr *)&from, sizeof(from), ++ buffer, sizeof(buffer), NULL, 0, 0)) { ++ BIO_printf(bio_err, "getnameinfo failed\n"); + *host = NULL; + /* return(0); */ + } else { +- if ((*host = (char *)OPENSSL_malloc(strlen(h1->h_name) + 1)) == NULL) { ++ if ((*host = (char *)OPENSSL_malloc(strlen(buffer) + 1)) == NULL) { + perror("OPENSSL_malloc"); + closesocket(ret); + return (0); + } +- BUF_strlcpy(*host, h1->h_name, strlen(h1->h_name) + 1); +- +- h2 = GetHostByName(*host); +- if (h2 == NULL) { +- BIO_printf(bio_err, "gethostbyname failure\n"); +- closesocket(ret); +- return (0); +- } +- if (h2->h_addrtype != AF_INET) { +- BIO_printf(bio_err, "gethostbyname addr is not AF_INET\n"); +- closesocket(ret); +- return (0); +- } ++ strcpy(*host, buffer); + } + end: + *sock = ret; + return (1); + } + +-int extract_host_port(char *str, char **host_ptr, unsigned char *ip, +- short *port_ptr) ++int extract_host_port(char *str, char **host_ptr, char **port_ptr) + { +- char *h, *p; +- +- h = str; +- p = strchr(str, ':'); ++ char *h, *p, *x; ++ ++ x = h = str; ++ if (*h == '[') { ++ h++; ++ p = strchr(h, ']'); ++ if (p == NULL) { ++ BIO_printf(bio_err, "no ending bracket for IPv6 address\n"); ++ return (0); ++ } ++ *(p++) = '\0'; ++ x = p; ++ } ++ p = strchr(x, ':'); + if (p == NULL) { + BIO_printf(bio_err, "no port defined\n"); + return (0); + } + *(p++) = '\0'; + +- if ((ip != NULL) && !host_ip(str, ip)) +- goto err; + if (host_ptr != NULL) + *host_ptr = h; ++ if (port_ptr != NULL) ++ *port_ptr = p; + +- 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); +- +- 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); +-} +- +-int extract_port(char *str, short *port_ptr) +-{ +- int i; +- struct servent *s; +- +- i = atoi(str); +- if (i != 0) +- *port_ptr = (unsigned short)i; +- else { +- s = getservbyname(str, "tcp"); +- if (s == NULL) { +- BIO_printf(bio_err, "getservbyname failure for %s\n", str); +- return (0); +- } +- *port_ptr = ntohs((unsigned short)s->s_port); +- } + return (1); + } +