* https://www.openssl.org/source/license.html
*/
+#include <assert.h>
#include <string.h>
#include "bio_lcl.h"
#ifndef OPENSSL_NO_SOCK
#include <openssl/err.h>
#include <openssl/buffer.h>
+#include <internal/thread_once.h>
#include <ctype.h>
CRYPTO_RWLOCK *bio_lookup_lock;
unsigned short port,
BIO_ADDRINFO **bai)
{
- OPENSSL_assert(bai != NULL);
+ if (bai == NULL)
+ return 0;
*bai = OPENSSL_zalloc(sizeof(**bai));
if (*bai == NULL)
return 1;
}
-static void do_bio_lookup_init(void)
+DEFINE_RUN_ONCE_STATIC(do_bio_lookup_init)
{
+ OPENSSL_init_crypto(0, NULL);
bio_lookup_lock = CRYPTO_THREAD_lock_new();
+ return bio_lookup_lock != NULL;
+}
+
+int BIO_lookup(const char *host, const char *service,
+ enum BIO_lookup_type lookup_type,
+ int family, int socktype, BIO_ADDRINFO **res)
+{
+ return BIO_lookup_ex(host, service, lookup_type, family, socktype, 0, res);
}
/*-
- * BIO_lookup - look up the node and service you want to connect to.
+ * BIO_lookup_ex - look up the node and service you want to connect to.
* @node: the node you want to connect to.
* @service: the service you want to connect to.
* @lookup_type: declare intent with the result, client or server.
* AF_INET, AF_INET6 or AF_UNIX.
* @socktype: The socket type you want to use. Can be SOCK_STREAM, SOCK_DGRAM
* or 0 for all.
+ * @protocol: The protocol to use, e.g. IPPROTO_TCP or IPPROTO_UDP or 0 for all.
+ * Note that some platforms may not return IPPROTO_SCTP without
+ * explicitly requesting it (i.e. IPPROTO_SCTP may not be returned
+ * with 0 for the protocol)
* @res: Storage place for the resulting list of returned addresses
*
* This will do a lookup of the node and service that you want to connect to.
*
* The return value is 1 on success or 0 in case of error.
*/
-int BIO_lookup(const char *host, const char *service,
- enum BIO_lookup_type lookup_type,
- int family, int socktype, BIO_ADDRINFO **res)
+int BIO_lookup_ex(const char *host, const char *service, int lookup_type,
+ int family, int socktype, int protocol, BIO_ADDRINFO **res)
{
int ret = 0; /* Assume failure */
#endif
break;
default:
- BIOerr(BIO_F_BIO_LOOKUP, BIO_R_UNSUPPORTED_PROTOCOL_FAMILY);
+ BIOerr(BIO_F_BIO_LOOKUP_EX, BIO_R_UNSUPPORTED_PROTOCOL_FAMILY);
return 0;
}
if (addrinfo_wrap(family, socktype, host, strlen(host), 0, res))
return 1;
else
- BIOerr(BIO_F_BIO_LOOKUP, ERR_R_MALLOC_FAILURE);
+ BIOerr(BIO_F_BIO_LOOKUP_EX, ERR_R_MALLOC_FAILURE);
return 0;
}
#endif
return 0;
if (1) {
- int gai_ret = 0;
#ifdef AI_PASSIVE
+ int gai_ret = 0;
struct addrinfo hints;
+
memset(&hints, 0, sizeof hints);
-# ifdef AI_ADDRCONFIG
- hints.ai_flags = AI_ADDRCONFIG;
-# endif
hints.ai_family = family;
hints.ai_socktype = socktype;
+ hints.ai_protocol = protocol;
if (lookup_type == BIO_LOOKUP_SERVER)
hints.ai_flags |= AI_PASSIVE;
# ifdef EAI_SYSTEM
case EAI_SYSTEM:
SYSerr(SYS_F_GETADDRINFO, get_last_socket_error());
- BIOerr(BIO_F_BIO_LOOKUP, ERR_R_SYS_LIB);
+ BIOerr(BIO_F_BIO_LOOKUP_EX, ERR_R_SYS_LIB);
break;
# endif
case 0:
ret = 1; /* Success */
break;
default:
- BIOerr(BIO_F_BIO_LOOKUP, ERR_R_SYS_LIB);
+ BIOerr(BIO_F_BIO_LOOKUP_EX, ERR_R_SYS_LIB);
ERR_add_error_data(1, gai_strerror(gai_ret));
break;
}
struct servent se_fallback = { NULL, NULL, 0, NULL };
#endif
- CRYPTO_THREAD_run_once(&bio_lookup_init, do_bio_lookup_init);
+ if (!RUN_ONCE(&bio_lookup_init, do_bio_lookup_init)) {
+ BIOerr(BIO_F_BIO_LOOKUP_EX, ERR_R_MALLOC_FAILURE);
+ ret = 0;
+ goto err;
+ }
CRYPTO_THREAD_write_lock(bio_lookup_lock);
he_fallback_address = INADDR_ANY;
he_fallback_address = INADDR_ANY;
break;
default:
- OPENSSL_assert(("We forgot to handle a lookup type!" == 0));
- break;
+ /* We forgot to handle a lookup type! */
+ assert("We forgot to handle a lookup type!" == NULL);
+ BIOerr(BIO_F_BIO_LOOKUP_EX, ERR_R_INTERNAL_ERROR);
+ ret = 0;
+ goto err;
}
} else {
he = gethostbyname(host);
if (he == NULL) {
#ifndef OPENSSL_SYS_WINDOWS
- BIOerr(BIO_F_BIO_LOOKUP, ERR_R_SYS_LIB);
- ERR_add_error_data(1, hstrerror(h_errno));
+ /*
+ * This might be misleading, because h_errno is used as if
+ * it was errno. To minimize mixup add 1000. Underlying
+ * reason for this is that hstrerror is declared obsolete,
+ * not to mention that a) h_errno is not always guaranteed
+ * to be meaningless; b) hstrerror can reside in yet another
+ * library, linking for sake of hstrerror is an overkill;
+ * c) this path is not executed on contemporary systems
+ * anyway [above getaddrinfo/gai_strerror is]. We just let
+ * system administrator figure this out...
+ */
+ SYSerr(SYS_F_GETHOSTBYNAME, 1000 + h_errno);
#else
SYSerr(SYS_F_GETHOSTBYNAME, WSAGetLastError());
#endif
if (se == NULL) {
#ifndef OPENSSL_SYS_WINDOWS
- BIOerr(BIO_F_BIO_LOOKUP, ERR_R_SYS_LIB);
- ERR_add_error_data(1, hstrerror(h_errno));
+ SYSerr(SYS_F_GETSERVBYNAME, errno);
#else
SYSerr(SYS_F_GETSERVBYNAME, WSAGetLastError());
#endif
goto err;
}
} else {
- BIOerr(BIO_F_BIO_LOOKUP, BIO_R_MALFORMED_HOST_OR_SERVICE);
+ BIOerr(BIO_F_BIO_LOOKUP_EX, BIO_R_MALFORMED_HOST_OR_SERVICE);
goto err;
}
}
addrinfo_malloc_err:
BIO_ADDRINFO_free(*res);
*res = NULL;
- BIOerr(BIO_F_BIO_LOOKUP, ERR_R_MALLOC_FAILURE);
+ BIOerr(BIO_F_BIO_LOOKUP_EX, ERR_R_MALLOC_FAILURE);
ret = 0;
goto err;
}