On Tue, Jul 18, 2006 at 02:06:12PM +0200, Richard Levitte via RT wrote:
>
> I'm taking a look at it. Don't worry about RT "stripping" the
> attachment, that's just for outgoing email. The patch is in the
> database, and I just downloaded it.
Richard,
I prepared new version of the patch.
Fixes:
- indentation -- I did the previous patch with -b, which was
not exactly clever;
- OPENSSL_free(*host_ptr) replaces OPENSSL_free(*port_ptr);
- freeaddrinfo(res0) is now in the err:;
- NI_MAXHOST instead of INET6_ADDRSTRLEN + 16.
Changes:
The patch also changes the logic in conn_state, to go back to
BIO_CONN_S_CREATE_SOCKET from later stages, provided there are some
more records in res left.
The patch also no longer adds those *_ipv6 functions, so that
changes to the ABI are minimal. Those two functions can always be
added any time later on.
I can also generate just an incremental patch from the previous
patch2, if you prefer.
Are you aware of any software which actually uses the BIO networking?
I'm affraid I did not test these code paths beyond compile.
Yours,
--
Jan Pazdziora
diff --git a/crypto/bio/b_sock.c b/crypto/bio/b_sock.c
index 4b3860b..aa6f0e1 100644
--- a/crypto/bio/b_sock.c
+++ b/crypto/bio/b_sock.c
@@ -64,6 +64,7 @@ #include "cryptlib.h"
#include <openssl/bio.h>
#if defined(OPENSSL_SYS_NETWARE) && defined(NETWARE_BSDSOCK)
#include "netdb.h"
+#include "bio_lcl.h"
#endif
#ifndef OPENSSL_NO_SOCK
@@ -99,6 +100,7 @@ static struct ghbn_cache_st
} ghbn_cache[GHBN_NUM];
#endif
+#ifndef OPENSSL_NO_DEPRECATED /* not needed since we have IPv6 support */
static int get_ip(const char *str,unsigned char *ip);
#if 0
static void ghbn_free(struct hostent *a);
@@ -216,6 +218,7 @@ #endif
}
return(1);
}
+#endif /* not needed since we have IPv6 support */
int BIO_sock_error(int sock)
{
@@ -355,6 +358,7 @@ static void ghbn_free(struct hostent *a)
#endif
+#ifndef OPENSSL_NO_DEPRECATED /* not needed since we have IPv6 support */
struct hostent *BIO_gethostbyname(const char *name)
{
#if 1
@@ -445,6 +449,56 @@ # endif
return(ret);
#endif
}
+#endif /* not needed since we have IPv6 support */
+
+/* Utility function to parse host and service (hostname and port)
+ information from a string. The hostname can also be an
+ IPv6 address in brackets. */
+int extract_host_port(char *str, char **host_ptr, char **port_ptr)
+ {
+ char *end, *port_start;
+
+ *host_ptr = *port_ptr = NULL;
+ end = NULL;
+ port_start = NULL;
+ if (*str == '[' && (end = strchr(str + 1, ']')))
+ {
+ *host_ptr = BUF_strndup(str + 1, end - str - 1);
+ end++;
+ if (*end == ':')
+ port_start = end + 1;
+ }
+ else
+ {
+ if ((end = strchr(str, ':')) != NULL)
+ {
+ *host_ptr = BUF_strndup(str, end - str);
+ port_start = end + 1;
+ }
+ else if ((end = strchr(str, '/')) != NULL)
+ {
+ *host_ptr = BUF_strndup(str, end - str);
+ }
+ else
+ *host_ptr = BUF_strdup(str);
+ }
+ if (*host_ptr == NULL)
+ return -1;
+ if (port_start != NULL)
+ {
+ if ((end = strchr(port_start, '/')) != NULL)
+ *port_ptr = BUF_strndup(port_start, end - port_start);
+ else
+ *port_ptr = BUF_strdup(port_start);
+ if (*port_ptr == NULL)
+ {
+ OPENSSL_free(*host_ptr);
+ *host_ptr = *port_ptr = NULL;
+ return -1;
+ }
+ }
+ return 0;
+ }
int BIO_sock_init(void)
@@ -541,6 +595,7 @@ #endif /* __DJGPP__ */
}
#endif /* __VMS_VER */
+#ifndef OPENSSL_NO_DEPRECATED /* not needed since we have IPv6 support */
/* The reason I have implemented this instead of using sscanf is because
* Visual C 1.52c gives an unresolved external when linking a DLL :-( */
static int get_ip(const char *str, unsigned char ip[4])
@@ -577,126 +632,151 @@ static int get_ip(const char *str, unsig
ip[3]=tmp[3];
return(1);
}
+#endif /* not needed since we have IPv6 support */
int BIO_get_accept_socket(char *host, int bind_mode)
{
int ret=0;
- struct sockaddr_in server,client;
- int s=INVALID_SOCKET,cs;
- unsigned char ip[4];
- unsigned short port;
- char *str=NULL,*e;
- const char *h,*p;
- unsigned long l;
+ struct addrinfo *res, *res0, hints;
+ int s;
+ char *h, *p;
+ int port_is_numeric;
+ int gai_e;
int err_num;
if (BIO_sock_init() != 1) return(INVALID_SOCKET);
- if ((str=BUF_strdup(host)) == NULL) return(INVALID_SOCKET);
+ if (extract_host_port(host, &h, &p) != 0)
+ return(INVALID_SOCKET);
- h=p=NULL;
- h=str;
- for (e=str; *e; e++)
+ memset(&hints, '\0', sizeof(hints));
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_ADDRCONFIG;
+ if (strcmp(h,"*") == 0)
{
- if (*e == ':')
- {
- p= &(e[1]);
- *e='\0';
- }
- else if (*e == '/')
- {
- *e='\0';
- break;
- }
+ hints.ai_flags |= AI_PASSIVE;
+ h = NULL;
}
+ port_is_numeric = 0;
- if (p == NULL)
+redo_with_numeric:
+ gai_e = getaddrinfo(h, p, &hints, &res);
+ if (gai_e)
{
- p=h;
- h="*";
- }
-
- if (!BIO_get_port(p,&port)) goto err;
-
- memset((char *)&server,0,sizeof(server));
- server.sin_family=AF_INET;
- server.sin_port=htons(port);
-
- if (strcmp(h,"*") == 0)
- server.sin_addr.s_addr=INADDR_ANY;
- else
- {
- if (!BIO_get_host_ip(h,&(ip[0]))) goto err;
- l=(unsigned long)
- ((unsigned long)ip[0]<<24L)|
- ((unsigned long)ip[1]<<16L)|
- ((unsigned long)ip[2]<< 8L)|
- ((unsigned long)ip[3]);
- server.sin_addr.s_addr=htonl(l);
+ if (! port_is_numeric)
+ {
+ port_is_numeric = 1;
+ if (strcmp(p,"http") == 0)
+ p = "80";
+ else if (strcmp(p,"telnet") == 0)
+ p = "23";
+ else if (strcmp(p,"socks") == 0)
+ p = "1080";
+ else if (strcmp(p,"https") == 0)
+ p = "443";
+ else if (strcmp(p,"ssl") == 0)
+ p = "443";
+ else if (strcmp(p,"ftp") == 0)
+ p = "21";
+ else if (strcmp(p,"gopher") == 0)
+ p = "70";
+#if 0
+ else if (strcmp(p,"wais") == 0)
+ p = "21";
+#endif
+ else
+ port_is_numeric = 0;
+ if (port_is_numeric)
+ goto redo_with_numeric;
}
-again:
- s=socket(AF_INET,SOCK_STREAM,SOCKET_PROTOCOL);
- if (s == INVALID_SOCKET)
- {
- SYSerr(SYS_F_SOCKET,get_last_socket_error());
- ERR_add_error_data(3,"port='",host,"'");
-
BIOerr(BIO_F_BIO_GET_ACCEPT_SOCKET,BIO_R_UNABLE_TO_CREATE_SOCKET);
+ ERR_add_error_data(3,"host='",host,"'");
+ ERR_add_error_data(2,"error=", gai_strerror(gai_e));
+ BIOerr(BIO_F_BIO_GET_ACCEPT_SOCKET,BIO_R_FAILED_TO_GETADDRINFO);
goto err;
}
-#ifdef SO_REUSEADDR
- if (bind_mode == BIO_BIND_REUSEADDR)
+ res0 = res;
+ s = INVALID_SOCKET;
+ while (res)
{
- int i=1;
+again:
+ s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+ if (s == INVALID_SOCKET)
+ {
+ if (res->ai_next)
+ goto nextres;
+ SYSerr(SYS_F_SOCKET,get_last_socket_error());
+ ERR_add_error_data(3,"port='",host,"'");
+
BIOerr(BIO_F_BIO_GET_ACCEPT_SOCKET,BIO_R_UNABLE_TO_CREATE_SOCKET);
+ goto err;
+ }
+#ifdef SO_REUSEADDR
+ if (bind_mode == BIO_BIND_REUSEADDR)
+ {
+ int i=1;
- ret=setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&i,sizeof(i));
- bind_mode=BIO_BIND_NORMAL;
- }
+ ret=setsockopt(s,SOL_SOCKET,SO_REUSEADDR,
+ (char *)&i,sizeof(i));
+ bind_mode=BIO_BIND_NORMAL;
+ }
#endif
- if (bind(s,(struct sockaddr *)&server,sizeof(server)) == -1)
- {
-#ifdef SO_REUSEADDR
- err_num=get_last_socket_error();
- if ((bind_mode == BIO_BIND_REUSEADDR_IF_UNUSED) &&
- (err_num == EADDRINUSE))
+ if (bind(s, res->ai_addr, res->ai_addrlen) == -1)
{
- memcpy((char *)&client,(char *)&server,sizeof(server));
- if (strcmp(h,"*") == 0)
- client.sin_addr.s_addr=htonl(0x7F000001);
- cs=socket(AF_INET,SOCK_STREAM,SOCKET_PROTOCOL);
- if (cs != INVALID_SOCKET)
+#ifdef SO_REUSEADDR
+ err_num=get_last_socket_error();
+ if ((bind_mode == BIO_BIND_REUSEADDR_IF_UNUSED) &&
+ (err_num == EADDRINUSE))
{
- int ii;
- ii=connect(cs,(struct sockaddr *)&client,
- sizeof(client));
- closesocket(cs);
- if (ii == INVALID_SOCKET)
+ int cs;
+ cs=socket(res->ai_family, res->ai_socktype,
res->ai_protocol);
+ if (cs != INVALID_SOCKET)
{
- bind_mode=BIO_BIND_REUSEADDR;
- closesocket(s);
- goto again;
+ int ii;
+ ii=connect(cs, res->ai_addr,
res->ai_addrlen);
+ closesocket(cs);
+ if (ii == INVALID_SOCKET)
+ {
+ bind_mode=BIO_BIND_REUSEADDR;
+ closesocket(s);
+ goto again;
+ }
+ /* else error */
}
/* else error */
}
- /* else error */
- }
#endif
- SYSerr(SYS_F_BIND,err_num);
- ERR_add_error_data(3,"port='",host,"'");
- BIOerr(BIO_F_BIO_GET_ACCEPT_SOCKET,BIO_R_UNABLE_TO_BIND_SOCKET);
- goto err;
- }
- if (listen(s,MAX_LISTEN) == -1)
- {
- SYSerr(SYS_F_BIND,get_last_socket_error());
- ERR_add_error_data(3,"port='",host,"'");
-
BIOerr(BIO_F_BIO_GET_ACCEPT_SOCKET,BIO_R_UNABLE_TO_LISTEN_SOCKET);
- goto err;
+ if (res->ai_next)
+ goto nextres;
+ SYSerr(SYS_F_BIND,err_num);
+ ERR_add_error_data(3,"port='",host,"'");
+
BIOerr(BIO_F_BIO_GET_ACCEPT_SOCKET,BIO_R_UNABLE_TO_BIND_SOCKET);
+ goto err;
+ }
+ if (listen(s,MAX_LISTEN) == -1)
+ {
+ if (res->ai_next)
+ goto nextres;
+ SYSerr(SYS_F_BIND,get_last_socket_error());
+ ERR_add_error_data(3,"port='",host,"'");
+
BIOerr(BIO_F_BIO_GET_ACCEPT_SOCKET,BIO_R_UNABLE_TO_LISTEN_SOCKET);
+ goto err;
+ }
+
+ ret = 1;
+ break;
+
+nextres:
+ if (s != INVALID_SOCKET)
+ closesocket(s);
+ res = res->ai_next;
}
- ret=1;
+
err:
- if (str != NULL) OPENSSL_free(str);
+ freeaddrinfo(res0);
+
+ if (h != NULL) OPENSSL_free(h);
+ if (p != NULL && !port_is_numeric) OPENSSL_free(p);
if ((ret == 0) && (s != INVALID_SOCKET))
{
closesocket(s);
@@ -708,20 +788,20 @@ err:
int BIO_accept(int sock, char **addr)
{
int ret=INVALID_SOCKET;
- static struct sockaddr_in from;
- unsigned long l;
- unsigned short port;
- int len;
- char *p;
+ static struct sockaddr_storage from;
+ int fromlen;
+ char address_name[NI_MAXHOST];
+ char port_name[NI_MAXSERV];
+ int outlen;
memset((char *)&from,0,sizeof(from));
- len=sizeof(from);
+ fromlen=sizeof(from);
/* Note: under VMS with SOCKETSHR the fourth parameter is currently
* of type (int *) whereas under other systems it is (void *) if
* you don't have a cast it will choke the compiler: if you do
* have a cast then you can either go for (int *) or (void *).
*/
- ret=accept(sock,(struct sockaddr *)&from,(void *)&len);
+ ret=accept(sock,(struct sockaddr *)&from,(void *)&fromlen);
if (ret == INVALID_SOCKET)
{
if(BIO_sock_should_retry(ret)) return -2;
@@ -732,23 +812,35 @@ int BIO_accept(int sock, char **addr)
if (addr == NULL) goto end;
- l=ntohl(from.sin_addr.s_addr);
- port=ntohs(from.sin_port);
+ if (*addr != NULL)
+ OPENSSL_free(*addr);
+ *addr = NULL;
+
+ if (! getnameinfo((struct sockaddr *)&from, fromlen,
+ address_name, sizeof(address_name),
+ port_name, sizeof(port_name),
+ NI_NUMERICHOST | NI_NUMERICSERV))
+ goto end;
+
+ outlen = strlen(address_name) + 1
+ + strlen(port_name) + 1;
+ if (from.ss_family == AF_INET6)
+ outlen += 2;
+ *addr = OPENSSL_malloc(outlen);
+
if (*addr == NULL)
{
- if ((p=OPENSSL_malloc(24)) == NULL)
- {
- BIOerr(BIO_F_BIO_ACCEPT,ERR_R_MALLOC_FAILURE);
- goto end;
- }
- *addr=p;
+ BIOerr(BIO_F_BIO_ACCEPT,ERR_R_MALLOC_FAILURE);
+ goto end;
}
- BIO_snprintf(*addr,24,"%d.%d.%d.%d:%d",
- (unsigned char)(l>>24L)&0xff,
- (unsigned char)(l>>16L)&0xff,
- (unsigned char)(l>> 8L)&0xff,
- (unsigned char)(l )&0xff,
- port);
+
+ snprintf(*addr, outlen, "%s%s%s:%s",
+ ( from.ss_family == AF_INET6 ? "[" : "" ),
+ address_name,
+ ( from.ss_family == AF_INET6 ? "]" : "" ),
+ ":",
+ port_name);
+
end:
return(ret);
}
diff --git a/crypto/bio/bio.h b/crypto/bio/bio.h
index 07333cf..0b2196d 100644
--- a/crypto/bio/bio.h
+++ b/crypto/bio/bio.h
@@ -175,12 +175,14 @@ #ifndef BIO_FLAGS_UPLINK
#define BIO_FLAGS_UPLINK 0
#endif
+#ifndef OPENSSL_NO_DEPRECATED /* not needed since we have IPv6 support */
/* Used in BIO_gethostbyname() */
#define BIO_GHBN_CTRL_HITS 1
#define BIO_GHBN_CTRL_MISSES 2
#define BIO_GHBN_CTRL_CACHE_SIZE 3
#define BIO_GHBN_CTRL_GET_ENTRY 4
#define BIO_GHBN_CTRL_FLUSH 5
+#endif /* not needed since we have IPv6 support */
/* Mostly used in the SSL BIO */
/* Not used anymore
@@ -335,6 +337,7 @@ #define BIO_CONN_S_CONNECT 5
#define BIO_CONN_S_OK 6
#define BIO_CONN_S_BLOCKED_CONNECT 7
#define BIO_CONN_S_NBIO 8
+#define BIO_CONN_S_GET_ADDRINFO 9
/*#define BIO_CONN_get_param_hostname BIO_ctrl */
#define BIO_C_SET_CONNECT 100
@@ -639,6 +642,7 @@ #ifndef OPENSSL_NO_FP_API
int BIO_dump_fp(FILE *fp, const char *s, int len);
int BIO_dump_indent_fp(FILE *fp, const char *s, int len, int indent);
#endif
+#ifndef OPENSSL_NO_DEPRECATED /* not needed since we have IPv6 support */
struct hostent *BIO_gethostbyname(const char *name);
/* We might want a thread-safe interface too:
* struct hostent *BIO_gethostbyname_r(const char *name,
@@ -648,11 +652,14 @@ struct hostent *BIO_gethostbyname(const
* substructures; if the buffer does not suffice, NULL is returned
* and an appropriate error code is set).
*/
+#endif /* not needed since we have IPv6 support */
int BIO_sock_error(int sock);
int BIO_socket_ioctl(int fd, long type, void *arg);
int BIO_socket_nbio(int fd,int mode);
+#ifndef OPENSSL_NO_DEPRECATED /* not needed since we have IPv6 support */
int BIO_get_port(const char *str, unsigned short *port_ptr);
int BIO_get_host_ip(const char *str, unsigned char *ip);
+#endif /* not needed since we have IPv6 support */
int BIO_get_accept_socket(char *host_port,int mode);
int BIO_accept(int sock,char **ip_port);
int BIO_sock_init(void );
@@ -763,6 +770,7 @@ #define BIO_R_UNINITIALIZED 120
#define BIO_R_UNSUPPORTED_METHOD 121
#define BIO_R_WRITE_TO_READ_ONLY_BIO 126
#define BIO_R_WSASTARTUP 122
+#define BIO_R_FAILED_TO_GETADDRINFO 132
#ifdef __cplusplus
}
diff --git a/crypto/bio/bio_lcl.h b/crypto/bio/bio_lcl.h
index dba2919..a730a49 100644
--- a/crypto/bio/bio_lcl.h
+++ b/crypto/bio/bio_lcl.h
@@ -26,3 +26,5 @@ #define UP_write write
#define UP_lseek lseek
#define UP_close close
#endif
+
+extern int extract_host_port(char *str, char **host_ptr, char **port_ptr);
diff --git a/crypto/bio/bss_conn.c b/crypto/bio/bss_conn.c
index c147278..20065c3 100644
--- a/crypto/bio/bss_conn.c
+++ b/crypto/bio/bss_conn.c
@@ -61,6 +61,7 @@ #include <errno.h>
#define USE_SOCKETS
#include "cryptlib.h"
#include <openssl/bio.h>
+#include "bio_lcl.h"
#ifndef OPENSSL_NO_SOCK
@@ -84,10 +85,9 @@ typedef struct bio_connect_st
char *param_port;
int nbio;
- unsigned char ip[4];
- unsigned short port;
-
- struct sockaddr_in them;
+ struct sockaddr_storage them_addr;
+ socklen_t them_addr_len;
+ int them_port;
/* int socket; this will be kept in bio->num so that it is
* compatible with the bss_sock bio */
@@ -128,88 +128,81 @@ static BIO_METHOD methods_connectp=
static int conn_state(BIO *b, BIO_CONNECT *c)
{
int ret= -1,i;
- unsigned long l;
- char *p,*q;
+ struct addrinfo *res, *res0, hints;
+ int gai_e;
+
int (*cb)(const BIO *,int,int)=NULL;
if (c->info_callback != NULL)
cb=c->info_callback;
+ res0 = res = NULL;
+
for (;;)
{
switch (c->state)
{
case BIO_CONN_S_BEFORE:
- p=c->param_hostname;
- if (p == NULL)
+ if (c->param_hostname == NULL)
{
BIOerr(BIO_F_CONN_STATE,BIO_R_NO_HOSTNAME_SPECIFIED);
goto exit_loop;
}
- for ( ; *p != '\0'; p++)
- {
- if ((*p == ':') || (*p == '/')) break;
- }
-
- i= *p;
- if ((i == ':') || (i == '/'))
- {
-
- *(p++)='\0';
- if (i == ':')
- {
- for (q=p; *q; q++)
- if (*q == '/')
- {
- *q='\0';
- break;
- }
- if (c->param_port != NULL)
- OPENSSL_free(c->param_port);
- c->param_port=BUF_strdup(p);
- }
- }
-
- if (c->param_port == NULL)
- {
-
BIOerr(BIO_F_CONN_STATE,BIO_R_NO_PORT_SPECIFIED);
- ERR_add_error_data(2,"host=",c->param_hostname);
- goto exit_loop;
- }
c->state=BIO_CONN_S_GET_IP;
break;
case BIO_CONN_S_GET_IP:
- if (BIO_get_host_ip(c->param_hostname,&(c->ip[0])) <= 0)
- goto exit_loop;
- c->state=BIO_CONN_S_GET_PORT;
- break;
-
case BIO_CONN_S_GET_PORT:
if (c->param_port == NULL)
{
/* abort(); */
goto exit_loop;
}
- else if (BIO_get_port(c->param_port,&c->port) <= 0)
+ c->state=BIO_CONN_S_GET_ADDRINFO;
+ break;
+
+ case BIO_CONN_S_GET_ADDRINFO:
+ memset(&hints, '\0', sizeof(hints));
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_ADDRCONFIG;
+ gai_e = getaddrinfo(c->param_hostname, c->param_port,
+ &hints, &res);
+ if (gai_e != 0)
+ {
+
BIOerr(BIO_F_CONN_STATE,BIO_R_FAILED_TO_GETADDRINFO);
+ ERR_add_error_data(1, gai_strerror(gai_e));
goto exit_loop;
+ }
+ res0 = res;
c->state=BIO_CONN_S_CREATE_SOCKET;
break;
case BIO_CONN_S_CREATE_SOCKET:
- /* now setup address */
- memset((char *)&c->them,0,sizeof(c->them));
- c->them.sin_family=AF_INET;
- c->them.sin_port=htons((unsigned short)c->port);
- l=(unsigned long)
- ((unsigned long)c->ip[0]<<24L)|
- ((unsigned long)c->ip[1]<<16L)|
- ((unsigned long)c->ip[2]<< 8L)|
- ((unsigned long)c->ip[3]);
- c->them.sin_addr.s_addr=htonl(l);
- c->state=BIO_CONN_S_CREATE_SOCKET;
+ while (res)
+ {
+ ret = INVALID_SOCKET;
+ ret = socket(res->ai_family,
+ res->ai_socktype, res->ai_protocol);
+ if (ret != INVALID_SOCKET)
+ {
+ memcpy((void*)&(c->them_addr),
res->ai_addr,
+ sizeof(c->them_addr));
+ c->them_addr_len = res->ai_addrlen;
+ if (res->ai_family == AF_INET)
+ c->them_port = ntohs(
+ ((struct sockaddr_in
*)(res->ai_addr))->sin_port
+ );
+ else if (res->ai_family == AF_INET6)
+ c->them_port = ntohs(
+ ((struct sockaddr_in6
*)(res->ai_addr))->sin6_port
+ );
+ else
+ c->them_port = 0;
+ break;
+ }
+ res = res->ai_next;
+ }
- ret=socket(AF_INET,SOCK_STREAM,SOCKET_PROTOCOL);
if (ret == INVALID_SOCKET)
{
SYSerr(SYS_F_SOCKET,get_last_socket_error());
@@ -218,6 +211,7 @@ static int conn_state(BIO *b, BIO_CONNEC
BIOerr(BIO_F_CONN_STATE,BIO_R_UNABLE_TO_CREATE_SOCKET);
goto exit_loop;
}
+
b->num=ret;
c->state=BIO_CONN_S_NBIO;
break;
@@ -227,9 +221,14 @@ static int conn_state(BIO *b, BIO_CONNEC
{
if (!BIO_socket_nbio(b->num,1))
{
+ closesocket(b->num);
+ if (res)
+ {
+
c->state=BIO_CONN_S_CREATE_SOCKET;
+ break;
+ }
BIOerr(BIO_F_CONN_STATE,BIO_R_ERROR_SETTING_NBIO);
- ERR_add_error_data(4,"host=",
- c->param_hostname,
+
ERR_add_error_data(4,"host=",c->param_hostname,
":",c->param_port);
goto exit_loop;
}
@@ -241,6 +240,12 @@ #if defined(SO_KEEPALIVE) && !defined(OP
i=setsockopt(b->num,SOL_SOCKET,SO_KEEPALIVE,(char
*)&i,sizeof(i));
if (i < 0)
{
+ closesocket(b->num);
+ if (res)
+ {
+ c->state=BIO_CONN_S_CREATE_SOCKET;
+ break;
+ }
SYSerr(SYS_F_SOCKET,get_last_socket_error());
ERR_add_error_data(4,"host=",c->param_hostname,
":",c->param_port);
@@ -253,8 +258,7 @@ #endif
case BIO_CONN_S_CONNECT:
BIO_clear_retry_flags(b);
ret=connect(b->num,
- (struct sockaddr *)&c->them,
- sizeof(c->them));
+ (struct sockaddr *)&(c->them_addr),
c->them_addr_len);
b->retry_reason=0;
if (ret < 0)
{
@@ -266,6 +270,12 @@ #endif
}
else
{
+ closesocket(b->num);
+ if (res)
+ {
+
c->state=BIO_CONN_S_CREATE_SOCKET;
+ break;
+ }
SYSerr(SYS_F_CONNECT,get_last_socket_error());
ERR_add_error_data(4,"host=",
c->param_hostname,
@@ -315,6 +325,7 @@ exit_loop:
if (cb != NULL)
ret=cb((BIO *)b,c->state,ret);
end:
+ freeaddrinfo(res0);
return(ret);
}
@@ -329,12 +340,8 @@ BIO_CONNECT *BIO_CONNECT_new(void)
ret->param_port=NULL;
ret->info_callback=NULL;
ret->nbio=0;
- ret->ip[0]=0;
- ret->ip[1]=0;
- ret->ip[2]=0;
- ret->ip[3]=0;
- ret->port=0;
- memset((char *)&ret->them,0,sizeof(ret->them));
+ ret->them_addr_len = 0;
+ ret->them_port = 0;
return(ret);
}
@@ -489,11 +496,17 @@ static long conn_ctrl(BIO *b, int cmd, l
}
else if (num == 2)
{
- *pptr= (char *)&(data->ip[0]);
+ if (data->them_addr_len == 0)
+ *pptr = "\0\0\0";
+ else if (data->them_addr.ss_family != AF_INET)
+ *pptr = NULL;
+ else
+ *pptr = (char *)&(((struct sockaddr_in
*)
+ &(data->them_addr))->sin_addr);
}
else if (num == 3)
{
- *((int *)ptr)=data->port;
+ *((int *)ptr)=data->them_port;
}
if ((!b->init) || (ptr == NULL))
*pptr="not initialized";
@@ -506,8 +519,20 @@ static long conn_ctrl(BIO *b, int cmd, l
b->init=1;
if (num == 0)
{
+ char *host, *port;
if (data->param_hostname != NULL)
OPENSSL_free(data->param_hostname);
+ if (extract_host_port((char *)ptr, &host,
&port) == 0)
+ {
+ data->param_hostname = host;
+ if (port)
+ {
+ if (data->param_port != NULL)
+
OPENSSL_free(data->param_port);
+ data->param_port = port;
+ }
+ }
+ else
data->param_hostname=BUF_strdup(ptr);
}
else if (num == 1)
@@ -520,13 +545,19 @@ static long conn_ctrl(BIO *b, int cmd, l
{
char buf[16];
unsigned char *p = ptr;
+ struct sockaddr_in *in_addr;
BIO_snprintf(buf,sizeof buf,"%d.%d.%d.%d",
p[0],p[1],p[2],p[3]);
if (data->param_hostname != NULL)
OPENSSL_free(data->param_hostname);
data->param_hostname=BUF_strdup(buf);
- memcpy(&(data->ip[0]),ptr,4);
+
+ data->them_addr_len = sizeof(struct
sockaddr_in);
+ in_addr = (struct sockaddr_in
*)&(data->them_addr);
+ in_addr->sin_family = AF_INET;
+ memcpy((void *)&(in_addr->sin_addr),ptr,4);
+ in_addr->sin_port = htons(data->them_port);
}
else if (num == 3)
{
@@ -536,7 +567,18 @@ static long conn_ctrl(BIO *b, int cmd, l
if (data->param_port != NULL)
OPENSSL_free(data->param_port);
data->param_port=BUF_strdup(buf);
- data->port= *(int *)ptr;
+ data->them_port= *(int *)ptr;
+ if (data->them_addr_len)
+ {
+ if (data->them_addr.ss_family ==
AF_INET)
+ ((struct sockaddr_in *)
+
&(data->them_addr))->sin_port
+ =
htons(data->them_port);
+ else if (data->them_addr.ss_family ==
AF_INET6)
+ ((struct sockaddr_in6 *)
+
&(data->them_addr))->sin6_port
+ =
htons(data->them_port);
+ }
}
}
break;
diff --git a/doc/crypto/BIO_s_connect.pod b/doc/crypto/BIO_s_connect.pod
index bcf7d8d..76fea04 100644
--- a/doc/crypto/BIO_s_connect.pod
+++ b/doc/crypto/BIO_s_connect.pod
@@ -59,16 +59,17 @@ type (int *).
BIO_set_conn_hostname() uses the string B<name> to set the hostname.
The hostname can be an IP address. The hostname can also include the
port in the form hostname:port . It is also acceptable to use the
-form "hostname/any/other/path" or "hostname:port/any/other/path".
+form "hostname/any/other/path", "hostname:port/any/other/path",
+"[IPv6 address]/any/other/path",
+or "[IPv6 address]:port/any/other/path".
BIO_set_conn_port() sets the port to B<port>. B<port> can be the
numerical form or a string such as "http". A string will be looked
-up first using getservbyname() on the host platform but if that
-fails a standard table of port names will be used. Currently the
-list is http, telnet, socks, https, ssl, ftp, gopher and wais.
+up using getaddrinfo() on the host platform.
-BIO_set_conn_ip() sets the IP address to B<ip> using binary form,
+BIO_set_conn_ip() sets the IPv4 address to B<ip> using binary form,
that is four bytes specifying the IP address in big-endian form.
+At the same time it sets the family to AF_INET.
BIO_set_conn_int_port() sets the port using B<port>. B<port> should
be of type (int *).
@@ -79,7 +80,7 @@ This return value is an internal pointer
BIO_get_conn_port() returns the port as a string.
-BIO_get_conn_ip() returns the IP address in binary form.
+BIO_get_conn_ip() returns the IPv4 address in binary form.
BIO_get_conn_int_port() returns the port as an int.
@@ -112,9 +113,9 @@ character in the passed hostname and eit
truncating the string at that point.
The values returned by BIO_get_conn_hostname(), BIO_get_conn_port(),
-BIO_get_conn_ip() and BIO_get_conn_int_port() are updated when a
-connection attempt is made. Before any connection attempt the values
-returned are those set by the application itself.
+BIO_get_conn_ip(), and BIO_get_conn_int_port() are
+updated when a connection attempt is made. Before any connection
+attempt the values returned are those set by the application itself.
Applications do not have to call BIO_do_connect() but may wish to do
so to separate the connection process from other I/O processing.
@@ -150,7 +151,8 @@ BIO_get_conn_port() returns a string rep
port or NULL if not set.
BIO_get_conn_ip() returns a pointer to the connected IP address in
-binary form or all zeros if not set.
+binary form or all zeros if not set. If the address set is not
+an IPv4 address, NULL is returned;
BIO_get_conn_int_port() returns the connected port or 0 if none was
set.