s_socket.c revision 296465
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 short p = 0; 238 239 if (!host_ip(host, &(ip[0]))) { 240 return (0); 241 } 242 if (p != 0) 243 port = p; 244 return (init_client_ip(sock, ip, port, type)); 245} 246 247static int init_client_ip(int *sock, unsigned char ip[4], int port, int type) 248{ 249 unsigned long addr; 250 struct sockaddr_in them; 251 int s, i; 252 253 if (!ssl_sock_init()) 254 return (0); 255 256 memset((char *)&them, 0, sizeof(them)); 257 them.sin_family = AF_INET; 258 them.sin_port = htons((unsigned short)port); 259 addr = (unsigned long) 260 ((unsigned long)ip[0] << 24L) | 261 ((unsigned long)ip[1] << 16L) | 262 ((unsigned long)ip[2] << 8L) | ((unsigned long)ip[3]); 263 them.sin_addr.s_addr = htonl(addr); 264 265 if (type == SOCK_STREAM) 266 s = socket(AF_INET, SOCK_STREAM, SOCKET_PROTOCOL); 267 else /* ( type == SOCK_DGRAM) */ 268 s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 269 270 if (s == INVALID_SOCKET) { 271 perror("socket"); 272 return (0); 273 } 274# ifndef OPENSSL_SYS_MPE 275 if (type == SOCK_STREAM) { 276 i = 0; 277 i = setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char *)&i, sizeof(i)); 278 if (i < 0) { 279 perror("keepalive"); 280 return (0); 281 } 282 } 283# endif 284 285 if (connect(s, (struct sockaddr *)&them, sizeof(them)) == -1) { 286 close(s); 287 perror("connect"); 288 return (0); 289 } 290 *sock = s; 291 return (1); 292} 293 294int do_server(int port, int type, int *ret, 295 int (*cb) (char *hostname, int s, unsigned char *context), 296 unsigned char *context) 297{ 298 int sock; 299 char *name = NULL; 300 int accept_socket; 301 int i; 302 303 if (!init_server(&accept_socket, port, type)) 304 return (0); 305 306 if (ret != NULL) { 307 *ret = accept_socket; 308 /* return(1); */ 309 } 310 for (;;) { 311 if (type == SOCK_STREAM) { 312 if (do_accept(accept_socket, &sock, &name) == 0) { 313 SHUTDOWN(accept_socket); 314 return (0); 315 } 316 } else 317 sock = accept_socket; 318 i = (*cb) (name, sock, context); 319 if (name != NULL) 320 OPENSSL_free(name); 321 if (type == SOCK_STREAM) 322 SHUTDOWN2(sock); 323 if (i < 0) { 324 SHUTDOWN2(accept_socket); 325 return (i); 326 } 327 } 328} 329 330static int init_server_long(int *sock, int port, char *ip, int type) 331{ 332 int ret = 0; 333 struct sockaddr_in server; 334 int s = -1; 335 336 if (!ssl_sock_init()) 337 return (0); 338 339 memset((char *)&server, 0, sizeof(server)); 340 server.sin_family = AF_INET; 341 server.sin_port = htons((unsigned short)port); 342 if (ip == NULL) 343 server.sin_addr.s_addr = INADDR_ANY; 344 else 345/* Added for T3E, address-of fails on bit field (beckman@acl.lanl.gov) */ 346# ifndef BIT_FIELD_LIMITS 347 memcpy(&server.sin_addr.s_addr, ip, 4); 348# else 349 memcpy(&server.sin_addr, ip, 4); 350# endif 351 352 if (type == SOCK_STREAM) 353 s = socket(AF_INET, SOCK_STREAM, SOCKET_PROTOCOL); 354 else /* type == SOCK_DGRAM */ 355 s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 356 357 if (s == INVALID_SOCKET) 358 goto err; 359# if defined SOL_SOCKET && defined SO_REUSEADDR 360 { 361 int j = 1; 362 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void *)&j, sizeof j); 363 } 364# endif 365 if (bind(s, (struct sockaddr *)&server, sizeof(server)) == -1) { 366# ifndef OPENSSL_SYS_WINDOWS 367 perror("bind"); 368# endif 369 goto err; 370 } 371 /* Make it 128 for linux */ 372 if (type == SOCK_STREAM && listen(s, 128) == -1) 373 goto err; 374 *sock = s; 375 ret = 1; 376 err: 377 if ((ret == 0) && (s != -1)) { 378 SHUTDOWN(s); 379 } 380 return (ret); 381} 382 383static int init_server(int *sock, int port, int type) 384{ 385 return (init_server_long(sock, port, NULL, type)); 386} 387 388static int do_accept(int acc_sock, int *sock, char **host) 389{ 390 int ret; 391 struct hostent *h1, *h2; 392 static struct sockaddr_in from; 393 int len; 394/* struct linger ling; */ 395 396 if (!ssl_sock_init()) 397 return (0); 398 399# ifndef OPENSSL_SYS_WINDOWS 400 redoit: 401# endif 402 403 memset((char *)&from, 0, sizeof(from)); 404 len = sizeof(from); 405 /* 406 * Note: under VMS with SOCKETSHR the fourth parameter is currently of 407 * type (int *) whereas under other systems it is (void *) if you don't 408 * have a cast it will choke the compiler: if you do have a cast then you 409 * can either go for (int *) or (void *). 410 */ 411 ret = accept(acc_sock, (struct sockaddr *)&from, (void *)&len); 412 if (ret == INVALID_SOCKET) { 413# if defined(OPENSSL_SYS_WINDOWS) || (defined(OPENSSL_SYS_NETWARE) && !defined(NETWARE_BSDSOCK)) 414 int i; 415 i = WSAGetLastError(); 416 BIO_printf(bio_err, "accept error %d\n", i); 417# else 418 if (errno == EINTR) { 419 /* 420 * check_timeout(); 421 */ 422 goto redoit; 423 } 424 fprintf(stderr, "errno=%d ", errno); 425 perror("accept"); 426# endif 427 return (0); 428 } 429 430/*- 431 ling.l_onoff=1; 432 ling.l_linger=0; 433 i=setsockopt(ret,SOL_SOCKET,SO_LINGER,(char *)&ling,sizeof(ling)); 434 if (i < 0) { perror("linger"); return(0); } 435 i=0; 436 i=setsockopt(ret,SOL_SOCKET,SO_KEEPALIVE,(char *)&i,sizeof(i)); 437 if (i < 0) { perror("keepalive"); return(0); } 438*/ 439 440 if (host == NULL) 441 goto end; 442# ifndef BIT_FIELD_LIMITS 443 /* I should use WSAAsyncGetHostByName() under windows */ 444 h1 = gethostbyaddr((char *)&from.sin_addr.s_addr, 445 sizeof(from.sin_addr.s_addr), AF_INET); 446# else 447 h1 = gethostbyaddr((char *)&from.sin_addr, 448 sizeof(struct in_addr), AF_INET); 449# endif 450 if (h1 == NULL) { 451 BIO_printf(bio_err, "bad gethostbyaddr\n"); 452 *host = NULL; 453 /* return(0); */ 454 } else { 455 if ((*host = (char *)OPENSSL_malloc(strlen(h1->h_name) + 1)) == NULL) { 456 perror("OPENSSL_malloc"); 457 return (0); 458 } 459 BUF_strlcpy(*host, h1->h_name, strlen(h1->h_name) + 1); 460 461 h2 = GetHostByName(*host); 462 if (h2 == NULL) { 463 BIO_printf(bio_err, "gethostbyname failure\n"); 464 return (0); 465 } 466 if (h2->h_addrtype != AF_INET) { 467 BIO_printf(bio_err, "gethostbyname addr is not AF_INET\n"); 468 return (0); 469 } 470 } 471 end: 472 *sock = ret; 473 return (1); 474} 475 476int extract_host_port(char *str, char **host_ptr, unsigned char *ip, 477 short *port_ptr) 478{ 479 char *h, *p; 480 481 h = str; 482 p = strchr(str, ':'); 483 if (p == NULL) { 484 BIO_printf(bio_err, "no port defined\n"); 485 return (0); 486 } 487 *(p++) = '\0'; 488 489 if ((ip != NULL) && !host_ip(str, ip)) 490 goto err; 491 if (host_ptr != NULL) 492 *host_ptr = h; 493 494 if (!extract_port(p, port_ptr)) 495 goto err; 496 return (1); 497 err: 498 return (0); 499} 500 501static int host_ip(char *str, unsigned char ip[4]) 502{ 503 unsigned int in[4]; 504 int i; 505 506 if (sscanf(str, "%u.%u.%u.%u", &(in[0]), &(in[1]), &(in[2]), &(in[3])) == 507 4) { 508 for (i = 0; i < 4; i++) 509 if (in[i] > 255) { 510 BIO_printf(bio_err, "invalid IP address\n"); 511 goto err; 512 } 513 ip[0] = in[0]; 514 ip[1] = in[1]; 515 ip[2] = in[2]; 516 ip[3] = in[3]; 517 } else { /* do a gethostbyname */ 518 struct hostent *he; 519 520 if (!ssl_sock_init()) 521 return (0); 522 523 he = GetHostByName(str); 524 if (he == NULL) { 525 BIO_printf(bio_err, "gethostbyname failure\n"); 526 goto err; 527 } 528 /* cast to short because of win16 winsock definition */ 529 if ((short)he->h_addrtype != AF_INET) { 530 BIO_printf(bio_err, "gethostbyname addr is not AF_INET\n"); 531 return (0); 532 } 533 ip[0] = he->h_addr_list[0][0]; 534 ip[1] = he->h_addr_list[0][1]; 535 ip[2] = he->h_addr_list[0][2]; 536 ip[3] = he->h_addr_list[0][3]; 537 } 538 return (1); 539 err: 540 return (0); 541} 542 543int extract_port(char *str, short *port_ptr) 544{ 545 int i; 546 struct servent *s; 547 548 i = atoi(str); 549 if (i != 0) 550 *port_ptr = (unsigned short)i; 551 else { 552 s = getservbyname(str, "tcp"); 553 if (s == NULL) { 554 BIO_printf(bio_err, "getservbyname failure for %s\n", str); 555 return (0); 556 } 557 *port_ptr = ntohs((unsigned short)s->s_port); 558 } 559 return (1); 560} 561 562# define GHBN_NUM 4 563static struct ghbn_cache_st { 564 char name[128]; 565 struct hostent ent; 566 unsigned long order; 567} ghbn_cache[GHBN_NUM]; 568 569static unsigned long ghbn_hits = 0L; 570static unsigned long ghbn_miss = 0L; 571 572static struct hostent *GetHostByName(char *name) 573{ 574 struct hostent *ret; 575 int i, lowi = 0; 576 unsigned long low = (unsigned long)-1; 577 578 for (i = 0; i < GHBN_NUM; i++) { 579 if (low > ghbn_cache[i].order) { 580 low = ghbn_cache[i].order; 581 lowi = i; 582 } 583 if (ghbn_cache[i].order > 0) { 584 if (strncmp(name, ghbn_cache[i].name, 128) == 0) 585 break; 586 } 587 } 588 if (i == GHBN_NUM) { /* no hit */ 589 ghbn_miss++; 590 ret = gethostbyname(name); 591 if (ret == NULL) 592 return (NULL); 593 /* else add to cache */ 594 if (strlen(name) < sizeof ghbn_cache[0].name) { 595 strcpy(ghbn_cache[lowi].name, name); 596 memcpy((char *)&(ghbn_cache[lowi].ent), ret, 597 sizeof(struct hostent)); 598 ghbn_cache[lowi].order = ghbn_miss + ghbn_hits; 599 } 600 return (ret); 601 } else { 602 ghbn_hits++; 603 ret = &(ghbn_cache[i].ent); 604 ghbn_cache[i].order = ghbn_miss + ghbn_hits; 605 return (ret); 606 } 607} 608 609#endif 610