int BIO_get_host_ip(const char *str, unsigned char *ip) { BIO_ADDRINFO *res = NULL; int ret = 0; if (BIO_sock_init() != 1) return 0; /* don't generate another error code here */ if (BIO_lookup(str, NULL, BIO_LOOKUP_CLIENT, AF_INET, SOCK_STREAM, &res)) { size_t l; if (BIO_ADDRINFO_family(res) != AF_INET) { BIOerr(BIO_F_BIO_GET_HOST_IP, BIO_R_GETHOSTBYNAME_ADDR_IS_NOT_AF_INET); } else { BIO_ADDR_rawaddress(BIO_ADDRINFO_address(res), NULL, &l); /* Because only AF_INET addresses will reach this far, we can assert that l should be 4 */ OPENSSL_assert(l == 4); BIO_ADDR_rawaddress(BIO_ADDRINFO_address(res), ip, &l); ret = 1; } BIO_ADDRINFO_free(res); } else { ERR_add_error_data(2, "host=", str); } return ret; }
int BIO_get_accept_socket(char *host, int bind_mode) { int s = INVALID_SOCKET; char *h = NULL, *p = NULL; BIO_ADDRINFO *res = NULL; if (!BIO_parse_hostserv(host, &h, &p, BIO_PARSE_PRIO_SERV)) return INVALID_SOCKET; if (BIO_sock_init() != 1) return INVALID_SOCKET; if (BIO_lookup(h, p, BIO_LOOKUP_SERVER, AF_UNSPEC, SOCK_STREAM, &res) != 0) goto err; if ((s = BIO_socket(BIO_ADDRINFO_family(res), BIO_ADDRINFO_socktype(res), BIO_ADDRINFO_protocol(res), 0)) == INVALID_SOCKET) { s = INVALID_SOCKET; goto err; } if (!BIO_listen(s, BIO_ADDRINFO_address(res), bind_mode ? BIO_SOCK_REUSEADDR : 0)) { BIO_closesocket(s); s = INVALID_SOCKET; } err: BIO_ADDRINFO_free(res); OPENSSL_free(h); OPENSSL_free(p); return s; }
int BIO_get_port(const char *str, unsigned short *port_ptr) { BIO_ADDRINFO *res = NULL; int ret = 0; if (str == NULL) { BIOerr(BIO_F_BIO_GET_PORT, BIO_R_NO_PORT_DEFINED); return (0); } if (BIO_sock_init() != 1) return 0; /* don't generate another error code here */ if (BIO_lookup(NULL, str, BIO_LOOKUP_CLIENT, AF_INET, SOCK_STREAM, &res)) { if (BIO_ADDRINFO_family(res) != AF_INET) { BIOerr(BIO_F_BIO_GET_PORT, BIO_R_ADDRINFO_ADDR_IS_NOT_AF_INET); } else { *port_ptr = ntohs(BIO_ADDR_rawport(BIO_ADDRINFO_address(res))); ret = 1; } BIO_ADDRINFO_free(res); } else { ERR_add_error_data(2, "host=", str); } return ret; }
static void BIO_ACCEPT_free(BIO_ACCEPT *a) { if (a == NULL) return; OPENSSL_free(a->param_addr); OPENSSL_free(a->param_serv); BIO_ADDRINFO_free(a->addr_first); OPENSSL_free(a->cache_accepting_name); OPENSSL_free(a->cache_accepting_serv); OPENSSL_free(a->cache_peer_name); OPENSSL_free(a->cache_peer_serv); BIO_free(a->bio_chain); OPENSSL_free(a); }
/* addrinfo_wrap is used to build our own addrinfo "chain". * (it has only one entry, so calling it a chain may be a stretch) * It should ONLY be called when getaddrinfo() and friends * aren't available, OR when dealing with a non IP protocol * family, such as AF_UNIX * * the return value is 1 on success, or 0 on failure, which * only happens if a memory allocation error occurred. */ static int addrinfo_wrap(int family, int socktype, const void *where, size_t wherelen, unsigned short port, BIO_ADDRINFO **bai) { OPENSSL_assert(bai != NULL); *bai = OPENSSL_zalloc(sizeof(**bai)); if (*bai == NULL) return 0; (*bai)->bai_family = family; (*bai)->bai_socktype = socktype; if (socktype == SOCK_STREAM) (*bai)->bai_protocol = IPPROTO_TCP; if (socktype == SOCK_DGRAM) (*bai)->bai_protocol = IPPROTO_UDP; #ifdef AF_UNIX if (family == AF_UNIX) (*bai)->bai_protocol = 0; #endif { /* Magic: We know that BIO_ADDR_sockaddr_noconst is really just an advanced cast of BIO_ADDR* to struct sockaddr * by the power of union, so while it may seem that we're creating a memory leak here, we are not. It will be all right. */ BIO_ADDR *addr = BIO_ADDR_new(); if (addr != NULL) { BIO_ADDR_rawmake(addr, family, where, wherelen, port); (*bai)->bai_addr = BIO_ADDR_sockaddr_noconst(addr); } } (*bai)->bai_next = NULL; if ((*bai)->bai_addr == NULL) { BIO_ADDRINFO_free(*bai); *bai = NULL; return 0; } return 1; }
/*- * BIO_lookup - 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. * @family: the address family you want to use. Use AF_UNSPEC for any, or * 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. * @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. * It returns a linked list of different addresses you can try to connect to. * * When no longer needed you should call BIO_ADDRINFO_free() to free the result. * * 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 ret = 0; /* Assume failure */ switch(family) { case AF_INET: #ifdef AF_INET6 case AF_INET6: #endif #ifdef AF_UNIX case AF_UNIX: #endif #ifdef AF_UNSPEC case AF_UNSPEC: #endif break; default: BIOerr(BIO_F_BIO_LOOKUP, BIO_R_UNSUPPORTED_PROTOCOL_FAMILY); return 0; } #ifdef AF_UNIX if (family == AF_UNIX) { if (addrinfo_wrap(family, socktype, host, strlen(host), 0, res)) return 1; else BIOerr(BIO_F_BIO_LOOKUP, ERR_R_MALLOC_FAILURE); return 0; } #endif if (BIO_sock_init() != 1) return 0; if (1) { int gai_ret = 0; #ifdef AI_PASSIVE struct addrinfo hints; memset(&hints, 0, sizeof hints); hints.ai_family = family; hints.ai_socktype = socktype; if (lookup_type == BIO_LOOKUP_SERVER) hints.ai_flags |= AI_PASSIVE; /* Note that |res| SHOULD be a 'struct addrinfo **' thanks to * macro magic in bio_lcl.h */ switch ((gai_ret = getaddrinfo(host, service, &hints, res))) { # ifdef EAI_SYSTEM case EAI_SYSTEM: SYSerr(SYS_F_GETADDRINFO, get_last_socket_error()); BIOerr(BIO_F_BIO_LOOKUP, ERR_R_SYS_LIB); break; # endif case 0: ret = 1; /* Success */ break; default: BIOerr(BIO_F_BIO_LOOKUP, ERR_R_SYS_LIB); ERR_add_error_data(1, gai_strerror(gai_ret)); break; } } else { #endif const struct hostent *he; /* * Because struct hostent is defined for 32-bit pointers only with * VMS C, we need to make sure that '&he_fallback_address' and * '&he_fallback_addresses' are 32-bit pointers */ #if defined(OPENSSL_SYS_VMS) && defined(__DECC) # pragma pointer_size save # pragma pointer_size 32 #endif /* Windows doesn't seem to have in_addr_t */ #ifdef OPENSSL_SYS_WINDOWS static uint32_t he_fallback_address; static const char *he_fallback_addresses[] = { (char *)&he_fallback_address, NULL }; #else static in_addr_t he_fallback_address; static const char *he_fallback_addresses[] = { (char *)&he_fallback_address, NULL }; #endif static const struct hostent he_fallback = { NULL, NULL, AF_INET, sizeof(he_fallback_address), (char **)&he_fallback_addresses }; #if defined(OPENSSL_SYS_VMS) && defined(__DECC) # pragma pointer_size restore #endif struct servent *se; /* Apparently, on WIN64, s_proto and s_port have traded places... */ #ifdef _WIN64 struct servent se_fallback = { NULL, NULL, NULL, 0 }; #else struct servent se_fallback = { NULL, NULL, 0, NULL }; #endif if (!RUN_ONCE(&bio_lookup_init, do_bio_lookup_init)) { BIOerr(BIO_F_BIO_LOOKUP, ERR_R_MALLOC_FAILURE); ret = 0; goto err; } CRYPTO_THREAD_write_lock(bio_lookup_lock); he_fallback_address = INADDR_ANY; if (host == NULL) { he = &he_fallback; switch(lookup_type) { case BIO_LOOKUP_CLIENT: he_fallback_address = INADDR_LOOPBACK; break; case BIO_LOOKUP_SERVER: he_fallback_address = INADDR_ANY; break; default: OPENSSL_assert(("We forgot to handle a lookup type!" == 0)); break; } } 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)); #else SYSerr(SYS_F_GETHOSTBYNAME, WSAGetLastError()); #endif ret = 0; goto err; } } if (service == NULL) { se_fallback.s_port = 0; se_fallback.s_proto = NULL; se = &se_fallback; } else { char *endp = NULL; long portnum = strtol(service, &endp, 10); /* * Because struct servent is defined for 32-bit pointers only with * VMS C, we need to make sure that 'proto' is a 32-bit pointer. */ #if defined(OPENSSL_SYS_VMS) && defined(__DECC) # pragma pointer_size save # pragma pointer_size 32 #endif char *proto = NULL; #if defined(OPENSSL_SYS_VMS) && defined(__DECC) # pragma pointer_size restore #endif switch (socktype) { case SOCK_STREAM: proto = "tcp"; break; case SOCK_DGRAM: proto = "udp"; break; } if (endp != service && *endp == '\0' && portnum > 0 && portnum < 65536) { se_fallback.s_port = htons(portnum); se_fallback.s_proto = proto; se = &se_fallback; } else if (endp == service) { se = getservbyname(service, proto); if (se == NULL) { #ifndef OPENSSL_SYS_WINDOWS BIOerr(BIO_F_BIO_LOOKUP, ERR_R_SYS_LIB); ERR_add_error_data(1, hstrerror(h_errno)); #else SYSerr(SYS_F_GETSERVBYNAME, WSAGetLastError()); #endif goto err; } } else { BIOerr(BIO_F_BIO_LOOKUP, BIO_R_MALFORMED_HOST_OR_SERVICE); goto err; } } *res = NULL; { /* * Because hostent::h_addr_list is an array of 32-bit pointers with VMS C, * we must make sure our iterator designates the same element type, hence * the pointer size dance. */ #if defined(OPENSSL_SYS_VMS) && defined(__DECC) # pragma pointer_size save # pragma pointer_size 32 #endif char **addrlistp; #if defined(OPENSSL_SYS_VMS) && defined(__DECC) # pragma pointer_size restore #endif size_t addresses; BIO_ADDRINFO *tmp_bai = NULL; /* The easiest way to create a linked list from an array is to start from the back */ for(addrlistp = he->h_addr_list; *addrlistp != NULL; addrlistp++) ; for(addresses = addrlistp - he->h_addr_list; addrlistp--, addresses-- > 0; ) { if (!addrinfo_wrap(he->h_addrtype, socktype, *addrlistp, he->h_length, se->s_port, &tmp_bai)) goto addrinfo_malloc_err; tmp_bai->bai_next = *res; *res = tmp_bai; continue; addrinfo_malloc_err: BIO_ADDRINFO_free(*res); *res = NULL; BIOerr(BIO_F_BIO_LOOKUP, ERR_R_MALLOC_FAILURE); ret = 0; goto err; } ret = 1; } err: CRYPTO_THREAD_unlock(bio_lookup_lock); } return ret; }
static long acpt_ctrl(BIO *b, int cmd, long num, void *ptr) { int *ip; long ret = 1; BIO_ACCEPT *data; char **pp; data = (BIO_ACCEPT *)b->ptr; switch (cmd) { case BIO_CTRL_RESET: ret = 0; data->state = ACPT_S_BEFORE; acpt_close_socket(b); BIO_ADDRINFO_free(data->addr_first); data->addr_first = NULL; b->flags = 0; break; case BIO_C_DO_STATE_MACHINE: /* use this one to start the connection */ ret = (long)acpt_state(b, data); break; case BIO_C_SET_ACCEPT: if (ptr != NULL) { if (num == 0) { char *hold_serv = data->param_serv; /* We affect the hostname regardless. However, the input * string might contain a host:service spec, so we must * parse it, which might or might not affect the service */ OPENSSL_free(data->param_addr); data->param_addr = NULL; ret = BIO_parse_hostserv(ptr, &data->param_addr, &data->param_serv, BIO_PARSE_PRIO_SERV); if (hold_serv != data->param_serv) OPENSSL_free(hold_serv); b->init = 1; } else if (num == 1) { OPENSSL_free(data->param_serv); data->param_serv = BUF_strdup(ptr); b->init = 1; } else if (num == 2) { data->bind_mode |= BIO_SOCK_NONBLOCK; } else if (num == 3) { BIO_free(data->bio_chain); data->bio_chain = (BIO *)ptr; } else if (num == 4) { data->accept_family = *(int *)ptr; } } else { if (num == 2) { data->bind_mode &= ~BIO_SOCK_NONBLOCK; } } break; case BIO_C_SET_NBIO: if (num != 0) data->accepted_mode |= BIO_SOCK_NONBLOCK; else data->accepted_mode &= ~BIO_SOCK_NONBLOCK; break; case BIO_C_SET_FD: b->init = 1; b->num = *((int *)ptr); data->accept_sock = b->num; data->state = ACPT_S_ACCEPT; b->shutdown = (int)num; b->init = 1; break; case BIO_C_GET_FD: if (b->init) { ip = (int *)ptr; if (ip != NULL) *ip = data->accept_sock; ret = data->accept_sock; } else ret = -1; break; case BIO_C_GET_ACCEPT: if (b->init) { if (num == 0 && ptr != NULL) { pp = (char **)ptr; *pp = data->cache_accepting_name; } else if (num == 1 && ptr != NULL) { pp = (char **)ptr; *pp = data->cache_accepting_serv; } else if (num == 2 && ptr != NULL) { pp = (char **)ptr; *pp = data->cache_peer_name; } else if (num == 3 && ptr != NULL) { pp = (char **)ptr; *pp = data->cache_peer_serv; } else if (num == 4) { switch (BIO_ADDRINFO_family(data->addr_iter)) { #ifdef AF_INET6 case AF_INET6: ret = BIO_FAMILY_IPV6; break; #endif case AF_INET: ret = BIO_FAMILY_IPV4; break; case 0: ret = data->accept_family; break; default: ret = -1; break; } } else ret = -1; } else ret = -1; break; case BIO_CTRL_GET_CLOSE: ret = b->shutdown; break; case BIO_CTRL_SET_CLOSE: b->shutdown = (int)num; break; case BIO_CTRL_PENDING: case BIO_CTRL_WPENDING: ret = 0; break; case BIO_CTRL_FLUSH: break; case BIO_C_SET_BIND_MODE: data->bind_mode = (int)num; break; case BIO_C_GET_BIND_MODE: ret = (long)data->bind_mode; break; case BIO_CTRL_DUP: /*- dbio=(BIO *)ptr; if (data->param_port) EAY EAY BIO_set_port(dbio,data->param_port); if (data->param_hostname) BIO_set_hostname(dbio,data->param_hostname); BIO_set_nbio(dbio,data->nbio); */ break; default: ret = 0; break; } return (ret); }