s_socket.c revision 331638
1/* 2 * apps/s_socket.c - socket-related functions used by s_client and s_server 3 */ 4/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 5 * All rights reserved. 6 * 7 * This package is an SSL implementation written 8 * by Eric Young (eay@cryptsoft.com). 9 * The implementation was written so as to conform with Netscapes SSL. 10 * 11 * This library is free for commercial and non-commercial use as long as 12 * the following conditions are aheared to. The following conditions 13 * apply to all code found in this distribution, be it the RC4, RSA, 14 * lhash, DES, etc., code; not just the SSL code. The SSL documentation 15 * included with this distribution is covered by the same copyright terms 16 * except that the holder is Tim Hudson (tjh@cryptsoft.com). 17 * 18 * Copyright remains Eric Young's, and as such any Copyright notices in 19 * the code are not to be removed. 20 * If this package is used in a product, Eric Young should be given attribution 21 * as the author of the parts of the library used. 22 * This can be in the form of a textual message at program startup or 23 * in documentation (online or textual) provided with the package. 24 * 25 * Redistribution and use in source and binary forms, with or without 26 * modification, are permitted provided that the following conditions 27 * are met: 28 * 1. Redistributions of source code must retain the copyright 29 * notice, this list of conditions and the following disclaimer. 30 * 2. Redistributions in binary form must reproduce the above copyright 31 * notice, this list of conditions and the following disclaimer in the 32 * documentation and/or other materials provided with the distribution. 33 * 3. All advertising materials mentioning features or use of this software 34 * must display the following acknowledgement: 35 * "This product includes cryptographic software written by 36 * Eric Young (eay@cryptsoft.com)" 37 * The word 'cryptographic' can be left out if the rouines from the library 38 * being used are not cryptographic related :-). 39 * 4. If you include any Windows specific code (or a derivative thereof) from 40 * the apps directory (application code) you must include an acknowledgement: 41 * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 42 * 43 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 44 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 45 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 46 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 47 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 48 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 49 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 50 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 51 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 52 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 53 * SUCH DAMAGE. 54 * 55 * The licence and distribution terms for any publically available version or 56 * derivative of this code cannot be changed. i.e. this code cannot simply be 57 * copied and put under another distribution licence 58 * [including the GNU Public Licence.] 59 */ 60 61#include <stdio.h> 62#include <stdlib.h> 63#include <string.h> 64#include <errno.h> 65#include <signal.h> 66 67#ifdef FLAT_INC 68# include "e_os2.h" 69#else 70# include "../e_os2.h" 71#endif 72 73/* 74 * With IPv6, it looks like Digital has mixed up the proper order of 75 * recursive header file inclusion, resulting in the compiler complaining 76 * that u_int isn't defined, but only if _POSIX_C_SOURCE is defined, which is 77 * needed to have fileno() declared correctly... So let's define u_int 78 */ 79#if defined(OPENSSL_SYS_VMS_DECC) && !defined(__U_INT) 80# define __U_INT 81typedef unsigned int u_int; 82#endif 83 84#define USE_SOCKETS 85#define NON_MAIN 86#include "apps.h" 87#undef USE_SOCKETS 88#undef NON_MAIN 89#include "s_apps.h" 90#include <openssl/ssl.h> 91 92#ifdef FLAT_INC 93# include "e_os.h" 94#else 95# include "../e_os.h" 96#endif 97 98#ifndef OPENSSL_NO_SOCK 99 100# if defined(OPENSSL_SYS_NETWARE) && defined(NETWARE_BSDSOCK) 101# include "netdb.h" 102# endif 103 104static struct hostent *GetHostByName(char *name); 105# if defined(OPENSSL_SYS_WINDOWS) || (defined(OPENSSL_SYS_NETWARE) && !defined(NETWARE_BSDSOCK)) 106static void ssl_sock_cleanup(void); 107# endif 108static int ssl_sock_init(void); 109static int init_client_ip(int *sock, unsigned char ip[4], int port, int type); 110static int init_server(int *sock, int port, int type); 111static int init_server_long(int *sock, int port, char *ip, int type); 112static int do_accept(int acc_sock, int *sock, char **host); 113static int host_ip(char *str, unsigned char ip[4]); 114 115# ifdef OPENSSL_SYS_WIN16 116# define SOCKET_PROTOCOL 0 /* more microsoft stupidity */ 117# else 118# define SOCKET_PROTOCOL IPPROTO_TCP 119# endif 120 121# if defined(OPENSSL_SYS_NETWARE) && !defined(NETWARE_BSDSOCK) 122static int wsa_init_done = 0; 123# endif 124 125# ifdef OPENSSL_SYS_WINDOWS 126static struct WSAData wsa_state; 127static int wsa_init_done = 0; 128 129# ifdef OPENSSL_SYS_WIN16 130static HWND topWnd = 0; 131static FARPROC lpTopWndProc = NULL; 132static FARPROC lpTopHookProc = NULL; 133extern HINSTANCE _hInstance; /* nice global CRT provides */ 134 135static LONG FAR PASCAL topHookProc(HWND hwnd, UINT message, WPARAM wParam, 136 LPARAM lParam) 137{ 138 if (hwnd == topWnd) { 139 switch (message) { 140 case WM_DESTROY: 141 case WM_CLOSE: 142 SetWindowLong(topWnd, GWL_WNDPROC, (LONG) lpTopWndProc); 143 ssl_sock_cleanup(); 144 break; 145 } 146 } 147 return CallWindowProc(lpTopWndProc, hwnd, message, wParam, lParam); 148} 149 150static BOOL CALLBACK enumproc(HWND hwnd, LPARAM lParam) 151{ 152 topWnd = hwnd; 153 return (FALSE); 154} 155 156# endif /* OPENSSL_SYS_WIN32 */ 157# endif /* OPENSSL_SYS_WINDOWS */ 158 159# ifdef OPENSSL_SYS_WINDOWS 160static void ssl_sock_cleanup(void) 161{ 162 if (wsa_init_done) { 163 wsa_init_done = 0; 164# ifndef OPENSSL_SYS_WINCE 165 WSACancelBlockingCall(); 166# endif 167 WSACleanup(); 168 } 169} 170# elif defined(OPENSSL_SYS_NETWARE) && !defined(NETWARE_BSDSOCK) 171static void sock_cleanup(void) 172{ 173 if (wsa_init_done) { 174 wsa_init_done = 0; 175 WSACleanup(); 176 } 177} 178# endif 179 180static int ssl_sock_init(void) 181{ 182# ifdef WATT32 183 extern int _watt_do_exit; 184 _watt_do_exit = 0; 185 if (sock_init()) 186 return (0); 187# elif defined(OPENSSL_SYS_WINDOWS) 188 if (!wsa_init_done) { 189 int err; 190 191# ifdef SIGINT 192 signal(SIGINT, (void (*)(int))ssl_sock_cleanup); 193# endif 194 wsa_init_done = 1; 195 memset(&wsa_state, 0, sizeof(wsa_state)); 196 if (WSAStartup(0x0101, &wsa_state) != 0) { 197 err = WSAGetLastError(); 198 BIO_printf(bio_err, "unable to start WINSOCK, error code=%d\n", 199 err); 200 return (0); 201 } 202# ifdef OPENSSL_SYS_WIN16 203 EnumTaskWindows(GetCurrentTask(), enumproc, 0L); 204 lpTopWndProc = (FARPROC) GetWindowLong(topWnd, GWL_WNDPROC); 205 lpTopHookProc = MakeProcInstance((FARPROC) topHookProc, _hInstance); 206 207 SetWindowLong(topWnd, GWL_WNDPROC, (LONG) lpTopHookProc); 208# endif /* OPENSSL_SYS_WIN16 */ 209 } 210# elif defined(OPENSSL_SYS_NETWARE) && !defined(NETWARE_BSDSOCK) 211 WORD wVerReq; 212 WSADATA wsaData; 213 int err; 214 215 if (!wsa_init_done) { 216 217# ifdef SIGINT 218 signal(SIGINT, (void (*)(int))sock_cleanup); 219# endif 220 221 wsa_init_done = 1; 222 wVerReq = MAKEWORD(2, 0); 223 err = WSAStartup(wVerReq, &wsaData); 224 if (err != 0) { 225 BIO_printf(bio_err, "unable to start WINSOCK2, error code=%d\n", 226 err); 227 return (0); 228 } 229 } 230# endif /* OPENSSL_SYS_WINDOWS */ 231 return (1); 232} 233 234int init_client(int *sock, char *host, int port, int type) 235{ 236 unsigned char ip[4]; 237 238 memset(ip, '\0', sizeof(ip)); 239 if (!host_ip(host, &(ip[0]))) 240 return 0; 241 return init_client_ip(sock, ip, port, type); 242} 243 244static int init_client_ip(int *sock, unsigned char ip[4], int port, int type) 245{ 246 unsigned long addr; 247 struct sockaddr_in them; 248 int s, i; 249 250 if (!ssl_sock_init()) 251 return (0); 252 253 memset((char *)&them, 0, sizeof(them)); 254 them.sin_family = AF_INET; 255 them.sin_port = htons((unsigned short)port); 256 addr = (unsigned long) 257 ((unsigned long)ip[0] << 24L) | 258 ((unsigned long)ip[1] << 16L) | 259 ((unsigned long)ip[2] << 8L) | ((unsigned long)ip[3]); 260 them.sin_addr.s_addr = htonl(addr); 261 262 if (type == SOCK_STREAM) 263 s = socket(AF_INET, SOCK_STREAM, SOCKET_PROTOCOL); 264 else /* ( type == SOCK_DGRAM) */ 265 s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 266 267 if (s == INVALID_SOCKET) { 268 perror("socket"); 269 return (0); 270 } 271# if defined(SO_KEEPALIVE) && !defined(OPENSSL_SYS_MPE) 272 if (type == SOCK_STREAM) { 273 i = 0; 274 i = setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char *)&i, sizeof(i)); 275 if (i < 0) { 276 closesocket(s); 277 perror("keepalive"); 278 return (0); 279 } 280 } 281# endif 282 283 if (connect(s, (struct sockaddr *)&them, sizeof(them)) == -1) { 284 closesocket(s); 285 perror("connect"); 286 return (0); 287 } 288 *sock = s; 289 return (1); 290} 291 292int do_server(int port, int type, int *ret, 293 int (*cb) (char *hostname, int s, int stype, 294 unsigned char *context), unsigned char *context, 295 int naccept) 296{ 297 int sock; 298 char *name = NULL; 299 int accept_socket = 0; 300 int i; 301 302 if (!init_server(&accept_socket, port, type)) 303 return (0); 304 305 if (ret != NULL) { 306 *ret = accept_socket; 307 /* return(1); */ 308 } 309 for (;;) { 310 if (type == SOCK_STREAM) { 311 if (do_accept(accept_socket, &sock, &name) == 0) { 312 SHUTDOWN(accept_socket); 313 return (0); 314 } 315 } else 316 sock = accept_socket; 317 i = (*cb) (name, sock, type, context); 318 if (name != NULL) 319 OPENSSL_free(name); 320 if (type == SOCK_STREAM) 321 SHUTDOWN2(sock); 322 if (naccept != -1) 323 naccept--; 324 if (i < 0 || naccept == 0) { 325 SHUTDOWN2(accept_socket); 326 return (i); 327 } 328 } 329} 330 331static int init_server_long(int *sock, int port, char *ip, int type) 332{ 333 int ret = 0; 334 struct sockaddr_in server; 335 int s = -1; 336 337 if (!ssl_sock_init()) 338 return (0); 339 340 memset((char *)&server, 0, sizeof(server)); 341 server.sin_family = AF_INET; 342 server.sin_port = htons((unsigned short)port); 343 if (ip == NULL) 344 server.sin_addr.s_addr = INADDR_ANY; 345 else 346/* Added for T3E, address-of fails on bit field (beckman@acl.lanl.gov) */ 347# ifndef BIT_FIELD_LIMITS 348 memcpy(&server.sin_addr.s_addr, ip, 4); 349# else 350 memcpy(&server.sin_addr, ip, 4); 351# endif 352 353 if (type == SOCK_STREAM) 354 s = socket(AF_INET, SOCK_STREAM, SOCKET_PROTOCOL); 355 else /* type == SOCK_DGRAM */ 356 s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 357 358 if (s == INVALID_SOCKET) 359 goto err; 360# if defined SOL_SOCKET && defined SO_REUSEADDR 361 { 362 int j = 1; 363 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void *)&j, sizeof(j)); 364 } 365# endif 366 if (bind(s, (struct sockaddr *)&server, sizeof(server)) == -1) { 367# ifndef OPENSSL_SYS_WINDOWS 368 perror("bind"); 369# endif 370 goto err; 371 } 372 /* Make it 128 for linux */ 373 if (type == SOCK_STREAM && listen(s, 128) == -1) 374 goto err; 375 *sock = s; 376 ret = 1; 377 err: 378 if ((ret == 0) && (s != -1)) { 379 SHUTDOWN(s); 380 } 381 return (ret); 382} 383 384static int init_server(int *sock, int port, int type) 385{ 386 return (init_server_long(sock, port, NULL, type)); 387} 388 389static int do_accept(int acc_sock, int *sock, char **host) 390{ 391 int ret; 392 struct hostent *h1, *h2; 393 static struct sockaddr_in from; 394 int len; 395/* struct linger ling; */ 396 397 if (!ssl_sock_init()) 398 return (0); 399 400# ifndef OPENSSL_SYS_WINDOWS 401 redoit: 402# endif 403 404 memset((char *)&from, 0, sizeof(from)); 405 len = sizeof(from); 406 /* 407 * Note: under VMS with SOCKETSHR the fourth parameter is currently of 408 * type (int *) whereas under other systems it is (void *) if you don't 409 * have a cast it will choke the compiler: if you do have a cast then you 410 * can either go for (int *) or (void *). 411 */ 412 ret = accept(acc_sock, (struct sockaddr *)&from, (void *)&len); 413 if (ret == INVALID_SOCKET) { 414# if defined(OPENSSL_SYS_WINDOWS) || (defined(OPENSSL_SYS_NETWARE) && !defined(NETWARE_BSDSOCK)) 415 int i; 416 i = WSAGetLastError(); 417 BIO_printf(bio_err, "accept error %d\n", i); 418# else 419 if (errno == EINTR) { 420 /* 421 * check_timeout(); 422 */ 423 goto redoit; 424 } 425 fprintf(stderr, "errno=%d ", errno); 426 perror("accept"); 427# endif 428 return (0); 429 } 430 431/*- 432 ling.l_onoff=1; 433 ling.l_linger=0; 434 i=setsockopt(ret,SOL_SOCKET,SO_LINGER,(char *)&ling,sizeof(ling)); 435 if (i < 0) { perror("linger"); return(0); } 436 i=0; 437 i=setsockopt(ret,SOL_SOCKET,SO_KEEPALIVE,(char *)&i,sizeof(i)); 438 if (i < 0) { perror("keepalive"); return(0); } 439*/ 440 441 if (host == NULL) 442 goto end; 443# ifndef BIT_FIELD_LIMITS 444 /* I should use WSAAsyncGetHostByName() under windows */ 445 h1 = gethostbyaddr((char *)&from.sin_addr.s_addr, 446 sizeof(from.sin_addr.s_addr), AF_INET); 447# else 448 h1 = gethostbyaddr((char *)&from.sin_addr, 449 sizeof(struct in_addr), AF_INET); 450# endif 451 if (h1 == NULL) { 452 BIO_printf(bio_err, "bad gethostbyaddr\n"); 453 *host = NULL; 454 /* return(0); */ 455 } else { 456 if ((*host = (char *)OPENSSL_malloc(strlen(h1->h_name) + 1)) == NULL) { 457 perror("OPENSSL_malloc"); 458 closesocket(ret); 459 return (0); 460 } 461 BUF_strlcpy(*host, h1->h_name, strlen(h1->h_name) + 1); 462 463 h2 = GetHostByName(*host); 464 if (h2 == NULL) { 465 BIO_printf(bio_err, "gethostbyname failure\n"); 466 closesocket(ret); 467 return (0); 468 } 469 if (h2->h_addrtype != AF_INET) { 470 BIO_printf(bio_err, "gethostbyname addr is not AF_INET\n"); 471 closesocket(ret); 472 return (0); 473 } 474 } 475 end: 476 *sock = ret; 477 return (1); 478} 479 480int extract_host_port(char *str, char **host_ptr, unsigned char *ip, 481 short *port_ptr) 482{ 483 char *h, *p; 484 485 h = str; 486 p = strchr(str, ':'); 487 if (p == NULL) { 488 BIO_printf(bio_err, "no port defined\n"); 489 return (0); 490 } 491 *(p++) = '\0'; 492 493 if ((ip != NULL) && !host_ip(str, ip)) 494 goto err; 495 if (host_ptr != NULL) 496 *host_ptr = h; 497 498 if (!extract_port(p, port_ptr)) 499 goto err; 500 return (1); 501 err: 502 return (0); 503} 504 505static int host_ip(char *str, unsigned char ip[4]) 506{ 507 unsigned int in[4]; 508 int i; 509 510 if (sscanf(str, "%u.%u.%u.%u", &(in[0]), &(in[1]), &(in[2]), &(in[3])) == 511 4) { 512 for (i = 0; i < 4; i++) 513 if (in[i] > 255) { 514 BIO_printf(bio_err, "invalid IP address\n"); 515 goto err; 516 } 517 ip[0] = in[0]; 518 ip[1] = in[1]; 519 ip[2] = in[2]; 520 ip[3] = in[3]; 521 } else { /* do a gethostbyname */ 522 struct hostent *he; 523 524 if (!ssl_sock_init()) 525 return (0); 526 527 he = GetHostByName(str); 528 if (he == NULL) { 529 BIO_printf(bio_err, "gethostbyname failure\n"); 530 goto err; 531 } 532 /* cast to short because of win16 winsock definition */ 533 if ((short)he->h_addrtype != AF_INET) { 534 BIO_printf(bio_err, "gethostbyname addr is not AF_INET\n"); 535 return (0); 536 } 537 ip[0] = he->h_addr_list[0][0]; 538 ip[1] = he->h_addr_list[0][1]; 539 ip[2] = he->h_addr_list[0][2]; 540 ip[3] = he->h_addr_list[0][3]; 541 } 542 return (1); 543 err: 544 return (0); 545} 546 547int extract_port(char *str, short *port_ptr) 548{ 549 int i; 550 struct servent *s; 551 552 i = atoi(str); 553 if (i != 0) 554 *port_ptr = (unsigned short)i; 555 else { 556 s = getservbyname(str, "tcp"); 557 if (s == NULL) { 558 BIO_printf(bio_err, "getservbyname failure for %s\n", str); 559 return (0); 560 } 561 *port_ptr = ntohs((unsigned short)s->s_port); 562 } 563 return (1); 564} 565 566# define GHBN_NUM 4 567static struct ghbn_cache_st { 568 char name[128]; 569 struct hostent ent; 570 unsigned long order; 571} ghbn_cache[GHBN_NUM]; 572 573static unsigned long ghbn_hits = 0L; 574static unsigned long ghbn_miss = 0L; 575 576static struct hostent *GetHostByName(char *name) 577{ 578 struct hostent *ret; 579 int i, lowi = 0; 580 unsigned long low = (unsigned long)-1; 581 582 for (i = 0; i < GHBN_NUM; i++) { 583 if (low > ghbn_cache[i].order) { 584 low = ghbn_cache[i].order; 585 lowi = i; 586 } 587 if (ghbn_cache[i].order > 0) { 588 if (strncmp(name, ghbn_cache[i].name, 128) == 0) 589 break; 590 } 591 } 592 if (i == GHBN_NUM) { /* no hit */ 593 ghbn_miss++; 594 ret = gethostbyname(name); 595 if (ret == NULL) 596 return (NULL); 597 /* else add to cache */ 598 if (strlen(name) < sizeof(ghbn_cache[0].name)) { 599 strcpy(ghbn_cache[lowi].name, name); 600 memcpy((char *)&(ghbn_cache[lowi].ent), ret, 601 sizeof(struct hostent)); 602 ghbn_cache[lowi].order = ghbn_miss + ghbn_hits; 603 } 604 return (ret); 605 } else { 606 ghbn_hits++; 607 ret = &(ghbn_cache[i].ent); 608 ghbn_cache[i].order = ghbn_miss + ghbn_hits; 609 return (ret); 610 } 611} 612 613#endif 614