s_socket.c revision 337982
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); 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) (int s, int stype, unsigned char *context), 294 unsigned char *context, int naccept) 295{ 296 int sock; 297 int accept_socket = 0; 298 int i; 299 300 if (!init_server(&accept_socket, port, type)) 301 return (0); 302 303 if (ret != NULL) { 304 *ret = accept_socket; 305 /* return(1); */ 306 } 307 for (;;) { 308 if (type == SOCK_STREAM) { 309 if (do_accept(accept_socket, &sock) == 0) { 310 SHUTDOWN(accept_socket); 311 return (0); 312 } 313 } else 314 sock = accept_socket; 315 i = (*cb) (sock, type, context); 316 if (type == SOCK_STREAM) 317 SHUTDOWN2(sock); 318 if (naccept != -1) 319 naccept--; 320 if (i < 0 || naccept == 0) { 321 SHUTDOWN2(accept_socket); 322 return (i); 323 } 324 } 325} 326 327static int init_server_long(int *sock, int port, char *ip, int type) 328{ 329 int ret = 0; 330 struct sockaddr_in server; 331 int s = -1; 332 333 if (!ssl_sock_init()) 334 return (0); 335 336 memset((char *)&server, 0, sizeof(server)); 337 server.sin_family = AF_INET; 338 server.sin_port = htons((unsigned short)port); 339 if (ip == NULL) 340 server.sin_addr.s_addr = INADDR_ANY; 341 else 342/* Added for T3E, address-of fails on bit field (beckman@acl.lanl.gov) */ 343# ifndef BIT_FIELD_LIMITS 344 memcpy(&server.sin_addr.s_addr, ip, 4); 345# else 346 memcpy(&server.sin_addr, ip, 4); 347# endif 348 349 if (type == SOCK_STREAM) 350 s = socket(AF_INET, SOCK_STREAM, SOCKET_PROTOCOL); 351 else /* type == SOCK_DGRAM */ 352 s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 353 354 if (s == INVALID_SOCKET) 355 goto err; 356# if defined SOL_SOCKET && defined SO_REUSEADDR 357 { 358 int j = 1; 359 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void *)&j, sizeof(j)); 360 } 361# endif 362 if (bind(s, (struct sockaddr *)&server, sizeof(server)) == -1) { 363# ifndef OPENSSL_SYS_WINDOWS 364 perror("bind"); 365# endif 366 goto err; 367 } 368 /* Make it 128 for linux */ 369 if (type == SOCK_STREAM && listen(s, 128) == -1) 370 goto err; 371 *sock = s; 372 ret = 1; 373 err: 374 if ((ret == 0) && (s != -1)) { 375 SHUTDOWN(s); 376 } 377 return (ret); 378} 379 380static int init_server(int *sock, int port, int type) 381{ 382 return (init_server_long(sock, port, NULL, type)); 383} 384 385static int do_accept(int acc_sock, int *sock) 386{ 387 int ret; 388 389 if (!ssl_sock_init()) 390 return 0; 391 392# ifndef OPENSSL_SYS_WINDOWS 393 redoit: 394# endif 395 396 /* 397 * Note: under VMS with SOCKETSHR the fourth parameter is currently of 398 * type (int *) whereas under other systems it is (void *) if you don't 399 * have a cast it will choke the compiler: if you do have a cast then you 400 * can either go for (int *) or (void *). 401 */ 402 ret = accept(acc_sock, NULL, NULL); 403 if (ret == INVALID_SOCKET) { 404# if defined(OPENSSL_SYS_WINDOWS) || (defined(OPENSSL_SYS_NETWARE) && !defined(NETWARE_BSDSOCK)) 405 int i; 406 i = WSAGetLastError(); 407 BIO_printf(bio_err, "accept error %d\n", i); 408# else 409 if (errno == EINTR) { 410 /* 411 * check_timeout(); 412 */ 413 goto redoit; 414 } 415 fprintf(stderr, "errno=%d ", errno); 416 perror("accept"); 417# endif 418 return 0; 419 } 420 421 *sock = ret; 422 return 1; 423} 424 425int extract_host_port(char *str, char **host_ptr, unsigned char *ip, 426 short *port_ptr) 427{ 428 char *h, *p; 429 430 h = str; 431 p = strchr(str, ':'); 432 if (p == NULL) { 433 BIO_printf(bio_err, "no port defined\n"); 434 return (0); 435 } 436 *(p++) = '\0'; 437 438 if ((ip != NULL) && !host_ip(str, ip)) 439 goto err; 440 if (host_ptr != NULL) 441 *host_ptr = h; 442 443 if (!extract_port(p, port_ptr)) 444 goto err; 445 return (1); 446 err: 447 return (0); 448} 449 450static int host_ip(char *str, unsigned char ip[4]) 451{ 452 unsigned int in[4]; 453 int i; 454 455 if (sscanf(str, "%u.%u.%u.%u", &(in[0]), &(in[1]), &(in[2]), &(in[3])) == 456 4) { 457 for (i = 0; i < 4; i++) 458 if (in[i] > 255) { 459 BIO_printf(bio_err, "invalid IP address\n"); 460 goto err; 461 } 462 ip[0] = in[0]; 463 ip[1] = in[1]; 464 ip[2] = in[2]; 465 ip[3] = in[3]; 466 } else { /* do a gethostbyname */ 467 struct hostent *he; 468 469 if (!ssl_sock_init()) 470 return (0); 471 472 he = GetHostByName(str); 473 if (he == NULL) { 474 BIO_printf(bio_err, "gethostbyname failure\n"); 475 goto err; 476 } 477 /* cast to short because of win16 winsock definition */ 478 if ((short)he->h_addrtype != AF_INET) { 479 BIO_printf(bio_err, "gethostbyname addr is not AF_INET\n"); 480 return (0); 481 } 482 ip[0] = he->h_addr_list[0][0]; 483 ip[1] = he->h_addr_list[0][1]; 484 ip[2] = he->h_addr_list[0][2]; 485 ip[3] = he->h_addr_list[0][3]; 486 } 487 return (1); 488 err: 489 return (0); 490} 491 492int extract_port(char *str, short *port_ptr) 493{ 494 int i; 495 struct servent *s; 496 497 i = atoi(str); 498 if (i != 0) 499 *port_ptr = (unsigned short)i; 500 else { 501 s = getservbyname(str, "tcp"); 502 if (s == NULL) { 503 BIO_printf(bio_err, "getservbyname failure for %s\n", str); 504 return (0); 505 } 506 *port_ptr = ntohs((unsigned short)s->s_port); 507 } 508 return (1); 509} 510 511# define GHBN_NUM 4 512static struct ghbn_cache_st { 513 char name[128]; 514 struct hostent ent; 515 unsigned long order; 516} ghbn_cache[GHBN_NUM]; 517 518static unsigned long ghbn_hits = 0L; 519static unsigned long ghbn_miss = 0L; 520 521static struct hostent *GetHostByName(char *name) 522{ 523 struct hostent *ret; 524 int i, lowi = 0; 525 unsigned long low = (unsigned long)-1; 526 527 for (i = 0; i < GHBN_NUM; i++) { 528 if (low > ghbn_cache[i].order) { 529 low = ghbn_cache[i].order; 530 lowi = i; 531 } 532 if (ghbn_cache[i].order > 0) { 533 if (strncmp(name, ghbn_cache[i].name, 128) == 0) 534 break; 535 } 536 } 537 if (i == GHBN_NUM) { /* no hit */ 538 ghbn_miss++; 539 ret = gethostbyname(name); 540 if (ret == NULL) 541 return (NULL); 542 /* else add to cache */ 543 if (strlen(name) < sizeof(ghbn_cache[0].name)) { 544 strcpy(ghbn_cache[lowi].name, name); 545 memcpy((char *)&(ghbn_cache[lowi].ent), ret, 546 sizeof(struct hostent)); 547 ghbn_cache[lowi].order = ghbn_miss + ghbn_hits; 548 } 549 return (ret); 550 } else { 551 ghbn_hits++; 552 ret = &(ghbn_cache[i].ent); 553 ghbn_cache[i].order = ghbn_miss + ghbn_hits; 554 return (ret); 555 } 556} 557 558#endif 559