1 /* $OpenBSD: b_sock.c,v 1.40 2014/06/22 15:38:28 jsing Exp $ */ 2 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 3 * All rights reserved. 4 * 5 * This package is an SSL implementation written 6 * by Eric Young (eay@cryptsoft.com). 7 * The implementation was written so as to conform with Netscapes SSL. 8 * 9 * This library is free for commercial and non-commercial use as long as 10 * the following conditions are aheared to. The following conditions 11 * apply to all code found in this distribution, be it the RC4, RSA, 12 * lhash, DES, etc., code; not just the SSL code. The SSL documentation 13 * included with this distribution is covered by the same copyright terms 14 * except that the holder is Tim Hudson (tjh@cryptsoft.com). 15 * 16 * Copyright remains Eric Young's, and as such any Copyright notices in 17 * the code are not to be removed. 18 * If this package is used in a product, Eric Young should be given attribution 19 * as the author of the parts of the library used. 20 * This can be in the form of a textual message at program startup or 21 * in documentation (online or textual) provided with the package. 22 * 23 * Redistribution and use in source and binary forms, with or without 24 * modification, are permitted provided that the following conditions 25 * are met: 26 * 1. Redistributions of source code must retain the copyright 27 * notice, this list of conditions and the following disclaimer. 28 * 2. Redistributions in binary form must reproduce the above copyright 29 * notice, this list of conditions and the following disclaimer in the 30 * documentation and/or other materials provided with the distribution. 31 * 3. All advertising materials mentioning features or use of this software 32 * must display the following acknowledgement: 33 * "This product includes cryptographic software written by 34 * Eric Young (eay@cryptsoft.com)" 35 * The word 'cryptographic' can be left out if the rouines from the library 36 * being used are not cryptographic related :-). 37 * 4. If you include any Windows specific code (or a derivative thereof) from 38 * the apps directory (application code) you must include an acknowledgement: 39 * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 40 * 41 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 45 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 51 * SUCH DAMAGE. 52 * 53 * The licence and distribution terms for any publically available version or 54 * derivative of this code cannot be changed. i.e. this code cannot simply be 55 * copied and put under another distribution licence 56 * [including the GNU Public Licence.] 57 */ 58 59 #include <sys/ioctl.h> 60 #include <sys/socket.h> 61 62 #include <netinet/in.h> 63 64 #include <errno.h> 65 #include <netdb.h> 66 #include <stdio.h> 67 #include <stdlib.h> 68 #include <unistd.h> 69 70 #include <openssl/bio.h> 71 72 #include "cryptlib.h" 73 74 static int get_ip(const char *str, unsigned char *ip); 75 76 int 77 BIO_get_host_ip(const char *str, unsigned char *ip) 78 { 79 int i; 80 int err = 1; 81 int locked = 0; 82 struct hostent *he; 83 84 i = get_ip(str, ip); 85 if (i < 0) { 86 BIOerr(BIO_F_BIO_GET_HOST_IP, BIO_R_INVALID_IP_ADDRESS); 87 goto err; 88 } 89 90 /* At this point, we have something that is most probably correct 91 in some way, so let's init the socket. */ 92 if (BIO_sock_init() != 1) 93 return 0; /* don't generate another error code here */ 94 95 /* If the string actually contained an IP address, we need not do 96 anything more */ 97 if (i > 0) 98 return (1); 99 100 /* do a gethostbyname */ 101 CRYPTO_w_lock(CRYPTO_LOCK_GETHOSTBYNAME); 102 locked = 1; 103 he = BIO_gethostbyname(str); 104 if (he == NULL) { 105 BIOerr(BIO_F_BIO_GET_HOST_IP, BIO_R_BAD_HOSTNAME_LOOKUP); 106 goto err; 107 } 108 109 /* cast to short because of win16 winsock definition */ 110 if ((short)he->h_addrtype != AF_INET) { 111 BIOerr(BIO_F_BIO_GET_HOST_IP, BIO_R_GETHOSTBYNAME_ADDR_IS_NOT_AF_INET); 112 goto err; 113 } 114 for (i = 0; i < 4; i++) 115 ip[i] = he->h_addr_list[0][i]; 116 err = 0; 117 118 err: 119 if (locked) 120 CRYPTO_w_unlock(CRYPTO_LOCK_GETHOSTBYNAME); 121 if (err) { 122 ERR_asprintf_error_data("host=%s", str); 123 return 0; 124 } else 125 return 1; 126 } 127 128 int 129 BIO_get_port(const char *str, unsigned short *port_ptr) 130 { 131 struct servent *s; 132 long port; 133 char *ep; 134 135 if (str == NULL) { 136 BIOerr(BIO_F_BIO_GET_PORT, BIO_R_NO_PORT_SPECIFIED); 137 return (0); 138 } 139 140 errno = 0; 141 port = strtol(str, &ep, 10); 142 if (str[0] != '\0' && *ep == '\0') { 143 if (errno == ERANGE && (port == LONG_MAX || port == LONG_MIN)) { 144 BIOerr(BIO_F_BIO_GET_PORT, BIO_R_INVALID_PORT_NUMBER); 145 return (0); 146 } 147 if (port < 0 || port > 65535) { 148 BIOerr(BIO_F_BIO_GET_PORT, BIO_R_INVALID_PORT_NUMBER); 149 return (0); 150 } 151 152 *port_ptr = (unsigned short)port; 153 return (1); 154 } 155 156 CRYPTO_w_lock(CRYPTO_LOCK_GETSERVBYNAME); 157 s = getservbyname(str, "tcp"); 158 if (s != NULL) 159 *port_ptr = ntohs((unsigned short)s->s_port); 160 CRYPTO_w_unlock(CRYPTO_LOCK_GETSERVBYNAME); 161 162 if (s == NULL) { 163 if (strcmp(str, "http") == 0) 164 *port_ptr = 80; 165 else if (strcmp(str, "telnet") == 0) 166 *port_ptr = 23; 167 else if (strcmp(str, "socks") == 0) 168 *port_ptr = 1080; 169 else if (strcmp(str, "https") == 0) 170 *port_ptr = 443; 171 else if (strcmp(str, "ssl") == 0) 172 *port_ptr = 443; 173 else if (strcmp(str, "ftp") == 0) 174 *port_ptr = 21; 175 else if (strcmp(str, "gopher") == 0) 176 *port_ptr = 70; 177 else { 178 SYSerr(SYS_F_GETSERVBYNAME, errno); 179 ERR_asprintf_error_data("service='%s'", str); 180 return (0); 181 } 182 } 183 return (1); 184 } 185 186 int 187 BIO_sock_error(int sock) 188 { 189 int j, i; 190 int size; 191 192 size = sizeof(int); 193 /* Note: under Windows the third parameter is of type (char *) 194 * whereas under other systems it is (void *) if you don't have 195 * a cast it will choke the compiler: if you do have a cast then 196 * you can either go for (char *) or (void *). 197 */ 198 i = getsockopt(sock, SOL_SOCKET, SO_ERROR, (void *)&j, (void *)&size); 199 if (i < 0) 200 return (1); 201 else 202 return (j); 203 } 204 205 struct hostent * 206 BIO_gethostbyname(const char *name) 207 { 208 return gethostbyname(name); 209 } 210 211 212 int 213 BIO_sock_init(void) 214 { 215 return (1); 216 } 217 218 void 219 BIO_sock_cleanup(void) 220 { 221 } 222 223 int 224 BIO_socket_ioctl(int fd, long type, void *arg) 225 { 226 int i; 227 228 # define ARG arg 229 230 i = ioctl(fd, type, ARG); 231 if (i < 0) 232 SYSerr(SYS_F_IOCTLSOCKET, errno); 233 return (i); 234 } 235 236 /* The reason I have implemented this instead of using sscanf is because 237 * Visual C 1.52c gives an unresolved external when linking a DLL :-( */ 238 static int 239 get_ip(const char *str, unsigned char ip[4]) 240 { 241 unsigned int tmp[4]; 242 int num = 0, c, ok = 0; 243 244 tmp[0] = tmp[1] = tmp[2] = tmp[3] = 0; 245 246 for (;;) { 247 c= *(str++); 248 if ((c >= '0') && (c <= '9')) { 249 ok = 1; 250 tmp[num] = tmp[num]*10 + c-'0'; 251 if (tmp[num] > 255) 252 return (0); 253 } else if (c == '.') { 254 if (!ok) 255 return (-1); 256 if (num == 3) 257 return (0); 258 num++; 259 ok = 0; 260 } else if (c == '\0' && (num == 3) && ok) 261 break; 262 else 263 return (0); 264 } 265 ip[0] = tmp[0]; 266 ip[1] = tmp[1]; 267 ip[2] = tmp[2]; 268 ip[3] = tmp[3]; 269 return (1); 270 } 271 272 int 273 BIO_get_accept_socket(char *host, int bind_mode) 274 { 275 int ret = 0; 276 union { 277 struct sockaddr sa; 278 struct sockaddr_in sa_in; 279 struct sockaddr_in6 sa_in6; 280 } server, client; 281 int s = -1, cs, addrlen; 282 unsigned char ip[4]; 283 unsigned short port; 284 char *str = NULL, *e; 285 char *h, *p; 286 unsigned long l; 287 int err_num; 288 289 if (BIO_sock_init() != 1) 290 return (-1); 291 292 if ((str = BUF_strdup(host)) == NULL) 293 return (-1); 294 295 h = p = NULL; 296 h = str; 297 for (e = str; *e; e++) { 298 if (*e == ':') { 299 p = e; 300 } else if (*e == '/') { 301 *e = '\0'; 302 break; 303 } 304 } 305 if (p) 306 *p++='\0'; /* points at last ':', '::port' is special [see below] */ 307 else 308 p = h, h = NULL; 309 310 #ifdef EAI_FAMILY 311 do { 312 struct addrinfo *res, hint; 313 314 /* '::port' enforces IPv6 wildcard listener. Some OSes, 315 * e.g. Solaris, default to IPv6 without any hint. Also 316 * note that commonly IPv6 wildchard socket can service 317 * IPv4 connections just as well... */ 318 memset(&hint, 0, sizeof(hint)); 319 hint.ai_flags = AI_PASSIVE; 320 if (h) { 321 if (strchr(h, ':')) { 322 if (h[1] == '\0') 323 h = NULL; 324 hint.ai_family = AF_INET6; 325 } else if (h[0] == '*' && h[1] == '\0') { 326 hint.ai_family = AF_INET; 327 h = NULL; 328 } 329 } 330 331 if (getaddrinfo(h, p, &hint, &res)) 332 break; 333 334 addrlen = res->ai_addrlen <= sizeof(server) ? 335 res->ai_addrlen : sizeof(server); 336 memcpy(&server, res->ai_addr, addrlen); 337 338 freeaddrinfo(res); 339 goto again; 340 } while (0); 341 #endif 342 343 if (!BIO_get_port(p, &port)) 344 goto err; 345 346 memset((char *)&server, 0, sizeof(server)); 347 server.sa_in.sin_family = AF_INET; 348 server.sa_in.sin_port = htons(port); 349 addrlen = sizeof(server.sa_in); 350 351 if (h == NULL || strcmp(h, "*") == 0) 352 server.sa_in.sin_addr.s_addr = INADDR_ANY; 353 else { 354 if (!BIO_get_host_ip(h, &(ip[0]))) 355 goto err; 356 l = (unsigned long)((unsigned long)ip[0]<<24L)| 357 ((unsigned long)ip[1]<<16L)| 358 ((unsigned long)ip[2]<< 8L)| 359 ((unsigned long)ip[3]); 360 server.sa_in.sin_addr.s_addr = htonl(l); 361 } 362 363 again: 364 s = socket(server.sa.sa_family, SOCK_STREAM, IPPROTO_TCP); 365 if (s == -1) { 366 SYSerr(SYS_F_SOCKET, errno); 367 ERR_asprintf_error_data("port='%s'", host); 368 BIOerr(BIO_F_BIO_GET_ACCEPT_SOCKET, BIO_R_UNABLE_TO_CREATE_SOCKET); 369 goto err; 370 } 371 372 #ifdef SO_REUSEADDR 373 if (bind_mode == BIO_BIND_REUSEADDR) { 374 int i = 1; 375 376 ret = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&i, sizeof(i)); 377 bind_mode = BIO_BIND_NORMAL; 378 } 379 #endif 380 if (bind(s, &server.sa, addrlen) == -1) { 381 #ifdef SO_REUSEADDR 382 err_num = errno; 383 if ((bind_mode == BIO_BIND_REUSEADDR_IF_UNUSED) && 384 (err_num == EADDRINUSE)) { 385 client = server; 386 if (h == NULL || strcmp(h, "*") == 0) { 387 if (client.sa.sa_family == AF_INET6) { 388 memset(&client.sa_in6.sin6_addr, 0, sizeof(client.sa_in6.sin6_addr)); 389 client.sa_in6.sin6_addr.s6_addr[15] = 1; 390 } else if (client.sa.sa_family == AF_INET) { 391 client.sa_in.sin_addr.s_addr = htonl(0x7F000001); 392 } else 393 goto err; 394 } 395 cs = socket(client.sa.sa_family, SOCK_STREAM, IPPROTO_TCP); 396 if (cs != -1) { 397 int ii; 398 ii = connect(cs, &client.sa, addrlen); 399 close(cs); 400 if (ii == -1) { 401 bind_mode = BIO_BIND_REUSEADDR; 402 close(s); 403 goto again; 404 } 405 /* else error */ 406 } 407 /* else error */ 408 } 409 #endif 410 SYSerr(SYS_F_BIND, err_num); 411 ERR_asprintf_error_data("port='%s'", host); 412 BIOerr(BIO_F_BIO_GET_ACCEPT_SOCKET, BIO_R_UNABLE_TO_BIND_SOCKET); 413 goto err; 414 } 415 if (listen(s, SOMAXCONN) == -1) { 416 SYSerr(SYS_F_BIND, errno); 417 ERR_asprintf_error_data("port='%s'", host); 418 BIOerr(BIO_F_BIO_GET_ACCEPT_SOCKET, BIO_R_UNABLE_TO_LISTEN_SOCKET); 419 goto err; 420 } 421 ret = 1; 422 err: 423 free(str); 424 if ((ret == 0) && (s != -1)) { 425 close(s); 426 s = -1; 427 } 428 return (s); 429 } 430 431 int 432 BIO_accept(int sock, char **addr) 433 { 434 int ret = -1; 435 unsigned long l; 436 unsigned short port; 437 char *p, *tmp; 438 439 struct { 440 socklen_t len; 441 union { 442 struct sockaddr sa; 443 struct sockaddr_in sa_in; 444 struct sockaddr_in6 sa_in6; 445 } from; 446 } sa; 447 448 sa.len = sizeof(sa.from); 449 memset(&sa.from, 0, sizeof(sa.from)); 450 ret = accept(sock, &sa.from.sa, &sa.len); 451 if (ret == -1) { 452 if (BIO_sock_should_retry(ret)) 453 return -2; 454 SYSerr(SYS_F_ACCEPT, errno); 455 BIOerr(BIO_F_BIO_ACCEPT, BIO_R_ACCEPT_ERROR); 456 goto end; 457 } 458 459 if (addr == NULL) 460 goto end; 461 462 #ifdef EAI_FAMILY 463 do { 464 char h[NI_MAXHOST], s[NI_MAXSERV]; 465 size_t nl; 466 467 if (getnameinfo(&sa.from.sa, sa.len, h, sizeof(h), 468 s, sizeof(s), NI_NUMERICHOST|NI_NUMERICSERV)) 469 break; 470 nl = strlen(h) + strlen(s) + 2; 471 p = *addr; 472 if (p) { 473 *p = '\0'; 474 if (!(tmp = realloc(p, nl))) { 475 close(ret); 476 ret = -1; 477 free(p); 478 *addr = NULL; 479 BIOerr(BIO_F_BIO_ACCEPT, ERR_R_MALLOC_FAILURE); 480 goto end; 481 } 482 p = tmp; 483 } else { 484 p = malloc(nl); 485 } 486 if (p == NULL) { 487 close(ret); 488 ret = -1; 489 BIOerr(BIO_F_BIO_ACCEPT, ERR_R_MALLOC_FAILURE); 490 goto end; 491 } 492 *addr = p; 493 snprintf(*addr, nl, "%s:%s", h, s); 494 goto end; 495 } while (0); 496 #endif 497 if (sa.from.sa.sa_family != AF_INET) 498 goto end; 499 l = ntohl(sa.from.sa_in.sin_addr.s_addr); 500 port = ntohs(sa.from.sa_in.sin_port); 501 if (*addr == NULL) { 502 if ((p = malloc(24)) == NULL) { 503 close(ret); 504 ret = -1; 505 BIOerr(BIO_F_BIO_ACCEPT, ERR_R_MALLOC_FAILURE); 506 goto end; 507 } 508 *addr = p; 509 } 510 snprintf(*addr, 24, "%d.%d.%d.%d:%d", 511 (unsigned char)(l >> 24L) & 0xff, (unsigned char)(l >> 16L) & 0xff, 512 (unsigned char)(l >> 8L) & 0xff, (unsigned char)(l) & 0xff, port); 513 514 end: 515 return (ret); 516 } 517 518 int 519 BIO_set_tcp_ndelay(int s, int on) 520 { 521 int ret = 0; 522 #if defined(TCP_NODELAY) && (defined(IPPROTO_TCP) || defined(SOL_TCP)) 523 int opt; 524 525 #ifdef SOL_TCP 526 opt = SOL_TCP; 527 #else 528 #ifdef IPPROTO_TCP 529 opt = IPPROTO_TCP; 530 #endif 531 #endif 532 533 ret = setsockopt(s, opt, TCP_NODELAY, (char *)&on, sizeof(on)); 534 #endif 535 return (ret == 0); 536 } 537 538 int 539 BIO_socket_nbio(int s, int mode) 540 { 541 int ret = -1; 542 int l; 543 544 l = mode; 545 ret = BIO_socket_ioctl(s, FIONBIO, &l); 546 547 return (ret == 0); 548 } 549