1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel (at) haxx.se>, et al. 9 * 10 * This software is licensed as described in the file COPYING, which 11 * you should have received as part of this distribution. The terms 12 * are also available at https://curl.haxx.se/docs/copyright.html. 13 * 14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell 15 * copies of the Software, and permit persons to whom the Software is 16 * furnished to do so, under the terms of the COPYING file. 17 * 18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 * KIND, either express or implied. 20 * 21 ***************************************************************************/ 22 #include "server_setup.h" 23 24 /* Purpose 25 * 26 * 1. Accept a TCP connection on a custom port (IPv4 or IPv6), or connect 27 * to a given (localhost) port. 28 * 29 * 2. Get commands on STDIN. Pass data on to the TCP stream. 30 * Get data from TCP stream and pass on to STDOUT. 31 * 32 * This program is made to perform all the socket/stream/connection stuff for 33 * the test suite's (perl) FTP server. Previously the perl code did all of 34 * this by its own, but I decided to let this program do the socket layer 35 * because of several things: 36 * 37 * o We want the perl code to work with rather old perl installations, thus 38 * we cannot use recent perl modules or features. 39 * 40 * o We want IPv6 support for systems that provide it, and doing optional IPv6 41 * support in perl seems if not impossible so at least awkward. 42 * 43 * o We want FTP-SSL support, which means that a connection that starts with 44 * plain sockets needs to be able to "go SSL" in the midst. This would also 45 * require some nasty perl stuff I'd rather avoid. 46 * 47 * (Source originally based on sws.c) 48 */ 49 50 /* 51 * Signal handling notes for sockfilt 52 * ---------------------------------- 53 * 54 * This program is a single-threaded process. 55 * 56 * This program is intended to be highly portable and as such it must be kept 57 * as simple as possible, due to this the only signal handling mechanisms used 58 * will be those of ANSI C, and used only in the most basic form which is good 59 * enough for the purpose of this program. 60 * 61 * For the above reason and the specific needs of this program signals SIGHUP, 62 * SIGPIPE and SIGALRM will be simply ignored on systems where this can be 63 * done. If possible, signals SIGINT and SIGTERM will be handled by this 64 * program as an indication to cleanup and finish execution as soon as 65 * possible. This will be achieved with a single signal handler 66 * 'exit_signal_handler' for both signals. 67 * 68 * The 'exit_signal_handler' upon the first SIGINT or SIGTERM received signal 69 * will just set to one the global var 'got_exit_signal' storing in global var 70 * 'exit_signal' the signal that triggered this change. 71 * 72 * Nothing fancy that could introduce problems is used, the program at certain 73 * points in its normal flow checks if var 'got_exit_signal' is set and in 74 * case this is true it just makes its way out of loops and functions in 75 * structured and well behaved manner to achieve proper program cleanup and 76 * termination. 77 * 78 * Even with the above mechanism implemented it is worthwile to note that 79 * other signals might still be received, or that there might be systems on 80 * which it is not possible to trap and ignore some of the above signals. 81 * This implies that for increased portability and reliability the program 82 * must be coded as if no signal was being ignored or handled at all. Enjoy 83 * it! 84 */ 85 86 #ifdef HAVE_SIGNAL_H 87 #include <signal.h> 88 #endif 89 #ifdef HAVE_NETINET_IN_H 90 #include <netinet/in.h> 91 #endif 92 #ifdef HAVE_NETINET_IN6_H 93 #include <netinet/in6.h> 94 #endif 95 #ifdef HAVE_ARPA_INET_H 96 #include <arpa/inet.h> 97 #endif 98 #ifdef HAVE_NETDB_H 99 #include <netdb.h> 100 #endif 101 102 #define ENABLE_CURLX_PRINTF 103 /* make the curlx header define all printf() functions to use the curlx_* 104 versions instead */ 105 #include "curlx.h" /* from the private lib dir */ 106 #include "getpart.h" 107 #include "inet_pton.h" 108 #include "util.h" 109 #include "server_sockaddr.h" 110 #include "warnless.h" 111 112 /* include memdebug.h last */ 113 #include "memdebug.h" 114 115 #ifdef USE_WINSOCK 116 #undef EINTR 117 #define EINTR 4 /* errno.h value */ 118 #undef EAGAIN 119 #define EAGAIN 11 /* errno.h value */ 120 #undef ENOMEM 121 #define ENOMEM 12 /* errno.h value */ 122 #undef EINVAL 123 #define EINVAL 22 /* errno.h value */ 124 #endif 125 126 #define DEFAULT_PORT 8999 127 128 #ifndef DEFAULT_LOGFILE 129 #define DEFAULT_LOGFILE "log/sockfilt.log" 130 #endif 131 132 const char *serverlogfile = DEFAULT_LOGFILE; 133 134 static bool verbose = FALSE; 135 static bool bind_only = FALSE; 136 #ifdef ENABLE_IPV6 137 static bool use_ipv6 = FALSE; 138 #endif 139 static const char *ipv_inuse = "IPv4"; 140 static unsigned short port = DEFAULT_PORT; 141 static unsigned short connectport = 0; /* if non-zero, we activate this mode */ 142 143 enum sockmode { 144 PASSIVE_LISTEN, /* as a server waiting for connections */ 145 PASSIVE_CONNECT, /* as a server, connected to a client */ 146 ACTIVE, /* as a client, connected to a server */ 147 ACTIVE_DISCONNECT /* as a client, disconnected from server */ 148 }; 149 150 /* do-nothing macro replacement for systems which lack siginterrupt() */ 151 152 #ifndef HAVE_SIGINTERRUPT 153 #define siginterrupt(x,y) do {} while(0) 154 #endif 155 156 /* vars used to keep around previous signal handlers */ 157 158 typedef RETSIGTYPE (*SIGHANDLER_T)(int); 159 160 #ifdef SIGHUP 161 static SIGHANDLER_T old_sighup_handler = SIG_ERR; 162 #endif 163 164 #ifdef SIGPIPE 165 static SIGHANDLER_T old_sigpipe_handler = SIG_ERR; 166 #endif 167 168 #ifdef SIGALRM 169 static SIGHANDLER_T old_sigalrm_handler = SIG_ERR; 170 #endif 171 172 #ifdef SIGINT 173 static SIGHANDLER_T old_sigint_handler = SIG_ERR; 174 #endif 175 176 #ifdef SIGTERM 177 static SIGHANDLER_T old_sigterm_handler = SIG_ERR; 178 #endif 179 180 #if defined(SIGBREAK) && defined(WIN32) 181 static SIGHANDLER_T old_sigbreak_handler = SIG_ERR; 182 #endif 183 184 /* var which if set indicates that the program should finish execution */ 185 186 SIG_ATOMIC_T got_exit_signal = 0; 187 188 /* if next is set indicates the first signal handled in exit_signal_handler */ 189 190 static volatile int exit_signal = 0; 191 192 /* signal handler that will be triggered to indicate that the program 193 should finish its execution in a controlled manner as soon as possible. 194 The first time this is called it will set got_exit_signal to one and 195 store in exit_signal the signal that triggered its execution. */ 196 197 static RETSIGTYPE exit_signal_handler(int signum) 198 { 199 int old_errno = errno; 200 if(got_exit_signal == 0) { 201 got_exit_signal = 1; 202 exit_signal = signum; 203 } 204 (void)signal(signum, exit_signal_handler); 205 errno = old_errno; 206 } 207 208 static void install_signal_handlers(void) 209 { 210 #ifdef SIGHUP 211 /* ignore SIGHUP signal */ 212 old_sighup_handler = signal(SIGHUP, SIG_IGN); 213 if(old_sighup_handler == SIG_ERR) 214 logmsg("cannot install SIGHUP handler: %s", strerror(errno)); 215 #endif 216 #ifdef SIGPIPE 217 /* ignore SIGPIPE signal */ 218 old_sigpipe_handler = signal(SIGPIPE, SIG_IGN); 219 if(old_sigpipe_handler == SIG_ERR) 220 logmsg("cannot install SIGPIPE handler: %s", strerror(errno)); 221 #endif 222 #ifdef SIGALRM 223 /* ignore SIGALRM signal */ 224 old_sigalrm_handler = signal(SIGALRM, SIG_IGN); 225 if(old_sigalrm_handler == SIG_ERR) 226 logmsg("cannot install SIGALRM handler: %s", strerror(errno)); 227 #endif 228 #ifdef SIGINT 229 /* handle SIGINT signal with our exit_signal_handler */ 230 old_sigint_handler = signal(SIGINT, exit_signal_handler); 231 if(old_sigint_handler == SIG_ERR) 232 logmsg("cannot install SIGINT handler: %s", strerror(errno)); 233 else 234 siginterrupt(SIGINT, 1); 235 #endif 236 #ifdef SIGTERM 237 /* handle SIGTERM signal with our exit_signal_handler */ 238 old_sigterm_handler = signal(SIGTERM, exit_signal_handler); 239 if(old_sigterm_handler == SIG_ERR) 240 logmsg("cannot install SIGTERM handler: %s", strerror(errno)); 241 else 242 siginterrupt(SIGTERM, 1); 243 #endif 244 #if defined(SIGBREAK) && defined(WIN32) 245 /* handle SIGBREAK signal with our exit_signal_handler */ 246 old_sigbreak_handler = signal(SIGBREAK, exit_signal_handler); 247 if(old_sigbreak_handler == SIG_ERR) 248 logmsg("cannot install SIGBREAK handler: %s", strerror(errno)); 249 else 250 siginterrupt(SIGBREAK, 1); 251 #endif 252 } 253 254 static void restore_signal_handlers(void) 255 { 256 #ifdef SIGHUP 257 if(SIG_ERR != old_sighup_handler) 258 (void)signal(SIGHUP, old_sighup_handler); 259 #endif 260 #ifdef SIGPIPE 261 if(SIG_ERR != old_sigpipe_handler) 262 (void)signal(SIGPIPE, old_sigpipe_handler); 263 #endif 264 #ifdef SIGALRM 265 if(SIG_ERR != old_sigalrm_handler) 266 (void)signal(SIGALRM, old_sigalrm_handler); 267 #endif 268 #ifdef SIGINT 269 if(SIG_ERR != old_sigint_handler) 270 (void)signal(SIGINT, old_sigint_handler); 271 #endif 272 #ifdef SIGTERM 273 if(SIG_ERR != old_sigterm_handler) 274 (void)signal(SIGTERM, old_sigterm_handler); 275 #endif 276 #if defined(SIGBREAK) && defined(WIN32) 277 if(SIG_ERR != old_sigbreak_handler) 278 (void)signal(SIGBREAK, old_sigbreak_handler); 279 #endif 280 } 281 282 #ifdef WIN32 283 /* 284 * read-wrapper to support reading from stdin on Windows. 285 */ 286 static ssize_t read_wincon(int fd, void *buf, size_t count) 287 { 288 HANDLE handle = NULL; 289 DWORD mode, rcount = 0; 290 BOOL success; 291 292 if(fd == fileno(stdin)) { 293 handle = GetStdHandle(STD_INPUT_HANDLE); 294 } 295 else { 296 return read(fd, buf, count); 297 } 298 299 if(GetConsoleMode(handle, &mode)) { 300 success = ReadConsole(handle, buf, curlx_uztoul(count), &rcount, NULL); 301 } 302 else { 303 success = ReadFile(handle, buf, curlx_uztoul(count), &rcount, NULL); 304 } 305 if(success) { 306 return rcount; 307 } 308 309 errno = GetLastError(); 310 return -1; 311 } 312 #undef read 313 #define read(a,b,c) read_wincon(a,b,c) 314 315 /* 316 * write-wrapper to support writing to stdout and stderr on Windows. 317 */ 318 static ssize_t write_wincon(int fd, const void *buf, size_t count) 319 { 320 HANDLE handle = NULL; 321 DWORD mode, wcount = 0; 322 BOOL success; 323 324 if(fd == fileno(stdout)) { 325 handle = GetStdHandle(STD_OUTPUT_HANDLE); 326 } 327 else if(fd == fileno(stderr)) { 328 handle = GetStdHandle(STD_ERROR_HANDLE); 329 } 330 else { 331 return write(fd, buf, count); 332 } 333 334 if(GetConsoleMode(handle, &mode)) { 335 success = WriteConsole(handle, buf, curlx_uztoul(count), &wcount, NULL); 336 } 337 else { 338 success = WriteFile(handle, buf, curlx_uztoul(count), &wcount, NULL); 339 } 340 if(success) { 341 return wcount; 342 } 343 344 errno = GetLastError(); 345 return -1; 346 } 347 #undef write 348 #define write(a,b,c) write_wincon(a,b,c) 349 #endif 350 351 /* 352 * fullread is a wrapper around the read() function. This will repeat the call 353 * to read() until it actually has read the complete number of bytes indicated 354 * in nbytes or it fails with a condition that cannot be handled with a simple 355 * retry of the read call. 356 */ 357 358 static ssize_t fullread(int filedes, void *buffer, size_t nbytes) 359 { 360 int error; 361 ssize_t rc; 362 ssize_t nread = 0; 363 364 do { 365 rc = read(filedes, (unsigned char *)buffer + nread, nbytes - nread); 366 367 if(got_exit_signal) { 368 logmsg("signalled to die"); 369 return -1; 370 } 371 372 if(rc < 0) { 373 error = errno; 374 if((error == EINTR) || (error == EAGAIN)) 375 continue; 376 logmsg("reading from file descriptor: %d,", filedes); 377 logmsg("unrecoverable read() failure: (%d) %s", 378 error, strerror(error)); 379 return -1; 380 } 381 382 if(rc == 0) { 383 logmsg("got 0 reading from stdin"); 384 return 0; 385 } 386 387 nread += rc; 388 389 } while((size_t)nread < nbytes); 390 391 if(verbose) 392 logmsg("read %zd bytes", nread); 393 394 return nread; 395 } 396 397 /* 398 * fullwrite is a wrapper around the write() function. This will repeat the 399 * call to write() until it actually has written the complete number of bytes 400 * indicated in nbytes or it fails with a condition that cannot be handled 401 * with a simple retry of the write call. 402 */ 403 404 static ssize_t fullwrite(int filedes, const void *buffer, size_t nbytes) 405 { 406 int error; 407 ssize_t wc; 408 ssize_t nwrite = 0; 409 410 do { 411 wc = write(filedes, (const unsigned char *)buffer + nwrite, 412 nbytes - nwrite); 413 414 if(got_exit_signal) { 415 logmsg("signalled to die"); 416 return -1; 417 } 418 419 if(wc < 0) { 420 error = errno; 421 if((error == EINTR) || (error == EAGAIN)) 422 continue; 423 logmsg("writing to file descriptor: %d,", filedes); 424 logmsg("unrecoverable write() failure: (%d) %s", 425 error, strerror(error)); 426 return -1; 427 } 428 429 if(wc == 0) { 430 logmsg("put 0 writing to stdout"); 431 return 0; 432 } 433 434 nwrite += wc; 435 436 } while((size_t)nwrite < nbytes); 437 438 if(verbose) 439 logmsg("wrote %zd bytes", nwrite); 440 441 return nwrite; 442 } 443 444 /* 445 * read_stdin tries to read from stdin nbytes into the given buffer. This is a 446 * blocking function that will only return TRUE when nbytes have actually been 447 * read or FALSE when an unrecoverable error has been detected. Failure of this 448 * function is an indication that the sockfilt process should terminate. 449 */ 450 451 static bool read_stdin(void *buffer, size_t nbytes) 452 { 453 ssize_t nread = fullread(fileno(stdin), buffer, nbytes); 454 if(nread != (ssize_t)nbytes) { 455 logmsg("exiting..."); 456 return FALSE; 457 } 458 return TRUE; 459 } 460 461 /* 462 * write_stdout tries to write to stdio nbytes from the given buffer. This is a 463 * blocking function that will only return TRUE when nbytes have actually been 464 * written or FALSE when an unrecoverable error has been detected. Failure of 465 * this function is an indication that the sockfilt process should terminate. 466 */ 467 468 static bool write_stdout(const void *buffer, size_t nbytes) 469 { 470 ssize_t nwrite = fullwrite(fileno(stdout), buffer, nbytes); 471 if(nwrite != (ssize_t)nbytes) { 472 logmsg("exiting..."); 473 return FALSE; 474 } 475 return TRUE; 476 } 477 478 static void lograw(unsigned char *buffer, ssize_t len) 479 { 480 char data[120]; 481 ssize_t i; 482 unsigned char *ptr = buffer; 483 char *optr = data; 484 ssize_t width = 0; 485 int left = sizeof(data); 486 487 for(i = 0; i<len; i++) { 488 switch(ptr[i]) { 489 case '\n': 490 snprintf(optr, left, "\\n"); 491 width += 2; 492 optr += 2; 493 left -= 2; 494 break; 495 case '\r': 496 snprintf(optr, left, "\\r"); 497 width += 2; 498 optr += 2; 499 left -= 2; 500 break; 501 default: 502 snprintf(optr, left, "%c", (ISGRAPH(ptr[i]) || 503 ptr[i] == 0x20) ?ptr[i]:'.'); 504 width++; 505 optr++; 506 left--; 507 break; 508 } 509 510 if(width>60) { 511 logmsg("'%s'", data); 512 width = 0; 513 optr = data; 514 left = sizeof(data); 515 } 516 } 517 if(width) 518 logmsg("'%s'", data); 519 } 520 521 #ifdef USE_WINSOCK 522 /* 523 * WinSock select() does not support standard file descriptors, 524 * it can only check SOCKETs. The following function is an attempt 525 * to re-create a select() function with support for other handle types. 526 * 527 * select() function with support for WINSOCK2 sockets and all 528 * other handle types supported by WaitForMultipleObjectsEx() as 529 * well as disk files, anonymous and names pipes, and character input. 530 * 531 * https://msdn.microsoft.com/en-us/library/windows/desktop/ms687028.aspx 532 * https://msdn.microsoft.com/en-us/library/windows/desktop/ms741572.aspx 533 */ 534 struct select_ws_wait_data { 535 HANDLE handle; /* actual handle to wait for during select */ 536 HANDLE event; /* internal event to abort waiting thread */ 537 }; 538 static DWORD WINAPI select_ws_wait_thread(LPVOID lpParameter) 539 { 540 struct select_ws_wait_data *data; 541 HANDLE handle, handles[2]; 542 INPUT_RECORD inputrecord; 543 LARGE_INTEGER size, pos; 544 DWORD type, length; 545 546 /* retrieve handles from internal structure */ 547 data = (struct select_ws_wait_data *) lpParameter; 548 if(data) { 549 handle = data->handle; 550 handles[0] = data->event; 551 handles[1] = handle; 552 free(data); 553 } 554 else 555 return (DWORD)-1; 556 557 /* retrieve the type of file to wait on */ 558 type = GetFileType(handle); 559 switch(type) { 560 case FILE_TYPE_DISK: 561 /* The handle represents a file on disk, this means: 562 * - WaitForMultipleObjectsEx will always be signalled for it. 563 * - comparison of current position in file and total size of 564 * the file can be used to check if we reached the end yet. 565 * 566 * Approach: Loop till either the internal event is signalled 567 * or if the end of the file has already been reached. 568 */ 569 while(WaitForMultipleObjectsEx(1, handles, FALSE, 0, FALSE) 570 == WAIT_TIMEOUT) { 571 /* get total size of file */ 572 length = 0; 573 size.QuadPart = 0; 574 size.LowPart = GetFileSize(handle, &length); 575 if((size.LowPart != INVALID_FILE_SIZE) || 576 (GetLastError() == NO_ERROR)) { 577 size.HighPart = length; 578 /* get the current position within the file */ 579 pos.QuadPart = 0; 580 pos.LowPart = SetFilePointer(handle, 0, &pos.HighPart, 581 FILE_CURRENT); 582 if((pos.LowPart != INVALID_SET_FILE_POINTER) || 583 (GetLastError() == NO_ERROR)) { 584 /* compare position with size, abort if not equal */ 585 if(size.QuadPart == pos.QuadPart) { 586 /* sleep and continue waiting */ 587 SleepEx(0, FALSE); 588 continue; 589 } 590 } 591 } 592 /* there is some data available, stop waiting */ 593 break; 594 } 595 break; 596 597 case FILE_TYPE_CHAR: 598 /* The handle represents a character input, this means: 599 * - WaitForMultipleObjectsEx will be signalled on any kind of input, 600 * including mouse and window size events we do not care about. 601 * 602 * Approach: Loop till either the internal event is signalled 603 * or we get signalled for an actual key-event. 604 */ 605 while(WaitForMultipleObjectsEx(2, handles, FALSE, INFINITE, FALSE) 606 == WAIT_OBJECT_0 + 1) { 607 /* check if this is an actual console handle */ 608 length = 0; 609 if(GetConsoleMode(handle, &length)) { 610 /* retrieve an event from the console buffer */ 611 length = 0; 612 if(PeekConsoleInput(handle, &inputrecord, 1, &length)) { 613 /* check if the event is not an actual key-event */ 614 if(length == 1 && inputrecord.EventType != KEY_EVENT) { 615 /* purge the non-key-event and continue waiting */ 616 ReadConsoleInput(handle, &inputrecord, 1, &length); 617 continue; 618 } 619 } 620 } 621 /* there is some data available, stop waiting */ 622 break; 623 } 624 break; 625 626 case FILE_TYPE_PIPE: 627 /* The handle represents an anonymous or named pipe, this means: 628 * - WaitForMultipleObjectsEx will always be signalled for it. 629 * - peek into the pipe and retrieve the amount of data available. 630 * 631 * Approach: Loop till either the internal event is signalled 632 * or there is data in the pipe available for reading. 633 */ 634 while(WaitForMultipleObjectsEx(1, handles, FALSE, 0, FALSE) 635 == WAIT_TIMEOUT) { 636 /* peek into the pipe and retrieve the amount of data available */ 637 length = 0; 638 if(PeekNamedPipe(handle, NULL, 0, NULL, &length, NULL)) { 639 /* if there is no data available, sleep and continue waiting */ 640 if(length == 0) { 641 SleepEx(0, FALSE); 642 continue; 643 } 644 } 645 else { 646 /* if the pipe has been closed, sleep and continue waiting */ 647 if(GetLastError() == ERROR_BROKEN_PIPE) { 648 SleepEx(0, FALSE); 649 continue; 650 } 651 } 652 /* there is some data available, stop waiting */ 653 break; 654 } 655 break; 656 657 default: 658 /* The handle has an unknown type, try to wait on it */ 659 WaitForMultipleObjectsEx(2, handles, FALSE, INFINITE, FALSE); 660 break; 661 } 662 663 return 0; 664 } 665 static HANDLE select_ws_wait(HANDLE handle, HANDLE event) 666 { 667 struct select_ws_wait_data *data; 668 HANDLE thread = NULL; 669 670 /* allocate internal waiting data structure */ 671 data = malloc(sizeof(struct select_ws_wait_data)); 672 if(data) { 673 data->handle = handle; 674 data->event = event; 675 676 /* launch waiting thread */ 677 thread = CreateThread(NULL, 0, 678 &select_ws_wait_thread, 679 data, 0, NULL); 680 681 /* free data if thread failed to launch */ 682 if(!thread) { 683 free(data); 684 } 685 } 686 687 return thread; 688 } 689 struct select_ws_data { 690 curl_socket_t fd; /* the original input handle (indexed by fds) */ 691 curl_socket_t wsasock; /* the internal socket handle (indexed by wsa) */ 692 WSAEVENT wsaevent; /* the internal WINSOCK2 event (indexed by wsa) */ 693 HANDLE thread; /* the internal threads handle (indexed by thd) */ 694 }; 695 static int select_ws(int nfds, fd_set *readfds, fd_set *writefds, 696 fd_set *exceptfds, struct timeval *timeout) 697 { 698 DWORD milliseconds, wait, idx; 699 WSANETWORKEVENTS wsanetevents; 700 struct select_ws_data *data; 701 HANDLE handle, *handles; 702 curl_socket_t sock; 703 long networkevents; 704 WSAEVENT wsaevent; 705 int error, fds; 706 HANDLE waitevent = NULL; 707 DWORD nfd = 0, thd = 0, wsa = 0; 708 int ret = 0; 709 710 /* check if the input value is valid */ 711 if(nfds < 0) { 712 errno = EINVAL; 713 return -1; 714 } 715 716 /* check if we got descriptors, sleep in case we got none */ 717 if(!nfds) { 718 Sleep((timeout->tv_sec*1000)+(DWORD)(((double)timeout->tv_usec)/1000.0)); 719 return 0; 720 } 721 722 /* create internal event to signal waiting threads */ 723 waitevent = CreateEvent(NULL, TRUE, FALSE, NULL); 724 if(!waitevent) { 725 errno = ENOMEM; 726 return -1; 727 } 728 729 /* allocate internal array for the internal data */ 730 data = malloc(nfds * sizeof(struct select_ws_data)); 731 if(data == NULL) { 732 errno = ENOMEM; 733 return -1; 734 } 735 736 /* allocate internal array for the internal event handles */ 737 handles = malloc(nfds * sizeof(HANDLE)); 738 if(handles == NULL) { 739 free(data); 740 errno = ENOMEM; 741 return -1; 742 } 743 744 /* clear internal arrays */ 745 memset(data, 0, nfds * sizeof(struct select_ws_data)); 746 memset(handles, 0, nfds * sizeof(HANDLE)); 747 748 /* loop over the handles in the input descriptor sets */ 749 for(fds = 0; fds < nfds; fds++) { 750 networkevents = 0; 751 handles[nfd] = 0; 752 753 if(FD_ISSET(fds, readfds)) 754 networkevents |= FD_READ|FD_ACCEPT|FD_CLOSE; 755 756 if(FD_ISSET(fds, writefds)) 757 networkevents |= FD_WRITE|FD_CONNECT; 758 759 if(FD_ISSET(fds, exceptfds)) 760 networkevents |= FD_OOB|FD_CLOSE; 761 762 /* only wait for events for which we actually care */ 763 if(networkevents) { 764 data[nfd].fd = curlx_sitosk(fds); 765 if(fds == fileno(stdin)) { 766 handle = GetStdHandle(STD_INPUT_HANDLE); 767 handle = select_ws_wait(handle, waitevent); 768 handles[nfd] = handle; 769 data[thd].thread = handle; 770 thd++; 771 } 772 else if(fds == fileno(stdout)) { 773 handles[nfd] = GetStdHandle(STD_OUTPUT_HANDLE); 774 } 775 else if(fds == fileno(stderr)) { 776 handles[nfd] = GetStdHandle(STD_ERROR_HANDLE); 777 } 778 else { 779 wsaevent = WSACreateEvent(); 780 if(wsaevent != WSA_INVALID_EVENT) { 781 error = WSAEventSelect(fds, wsaevent, networkevents); 782 if(error != SOCKET_ERROR) { 783 handle = (HANDLE) wsaevent; 784 handles[nfd] = handle; 785 data[wsa].wsasock = curlx_sitosk(fds); 786 data[wsa].wsaevent = wsaevent; 787 wsa++; 788 } 789 else { 790 WSACloseEvent(wsaevent); 791 handle = (HANDLE) curlx_sitosk(fds); 792 handle = select_ws_wait(handle, waitevent); 793 handles[nfd] = handle; 794 data[thd].thread = handle; 795 thd++; 796 } 797 } 798 } 799 nfd++; 800 } 801 } 802 803 /* convert struct timeval to milliseconds */ 804 if(timeout) { 805 milliseconds = ((timeout->tv_sec * 1000) + (timeout->tv_usec / 1000)); 806 } 807 else { 808 milliseconds = INFINITE; 809 } 810 811 /* wait for one of the internal handles to trigger */ 812 wait = WaitForMultipleObjectsEx(nfd, handles, FALSE, milliseconds, FALSE); 813 814 /* signal the event handle for the waiting threads */ 815 SetEvent(waitevent); 816 817 /* loop over the internal handles returned in the descriptors */ 818 for(idx = 0; idx < nfd; idx++) { 819 handle = handles[idx]; 820 sock = data[idx].fd; 821 fds = curlx_sktosi(sock); 822 823 /* check if the current internal handle was triggered */ 824 if(wait != WAIT_FAILED && (wait - WAIT_OBJECT_0) <= idx && 825 WaitForSingleObjectEx(handle, 0, FALSE) == WAIT_OBJECT_0) { 826 /* first handle stdin, stdout and stderr */ 827 if(fds == fileno(stdin)) { 828 /* stdin is never ready for write or exceptional */ 829 FD_CLR(sock, writefds); 830 FD_CLR(sock, exceptfds); 831 } 832 else if(fds == fileno(stdout) || fds == fileno(stderr)) { 833 /* stdout and stderr are never ready for read or exceptional */ 834 FD_CLR(sock, readfds); 835 FD_CLR(sock, exceptfds); 836 } 837 else { 838 /* try to handle the event with the WINSOCK2 functions */ 839 wsanetevents.lNetworkEvents = 0; 840 error = WSAEnumNetworkEvents(fds, handle, &wsanetevents); 841 if(error != SOCKET_ERROR) { 842 /* remove from descriptor set if not ready for read/accept/close */ 843 if(!(wsanetevents.lNetworkEvents & (FD_READ|FD_ACCEPT|FD_CLOSE))) 844 FD_CLR(sock, readfds); 845 846 /* remove from descriptor set if not ready for write/connect */ 847 if(!(wsanetevents.lNetworkEvents & (FD_WRITE|FD_CONNECT))) 848 FD_CLR(sock, writefds); 849 850 /* HACK: 851 * use exceptfds together with readfds to signal 852 * that the connection was closed by the client. 853 * 854 * Reason: FD_CLOSE is only signaled once, sometimes 855 * at the same time as FD_READ with data being available. 856 * This means that recv/sread is not reliable to detect 857 * that the connection is closed. 858 */ 859 /* remove from descriptor set if not exceptional */ 860 if(!(wsanetevents.lNetworkEvents & (FD_OOB|FD_CLOSE))) 861 FD_CLR(sock, exceptfds); 862 } 863 } 864 865 /* check if the event has not been filtered using specific tests */ 866 if(FD_ISSET(sock, readfds) || FD_ISSET(sock, writefds) || 867 FD_ISSET(sock, exceptfds)) { 868 ret++; 869 } 870 } 871 else { 872 /* remove from all descriptor sets since this handle did not trigger */ 873 FD_CLR(sock, readfds); 874 FD_CLR(sock, writefds); 875 FD_CLR(sock, exceptfds); 876 } 877 } 878 879 for(fds = 0; fds < nfds; fds++) { 880 if(FD_ISSET(fds, readfds)) 881 logmsg("select_ws: %d is readable", fds); 882 883 if(FD_ISSET(fds, writefds)) 884 logmsg("select_ws: %d is writable", fds); 885 886 if(FD_ISSET(fds, exceptfds)) 887 logmsg("select_ws: %d is excepted", fds); 888 } 889 890 for(idx = 0; idx < wsa; idx++) { 891 WSAEventSelect(data[idx].wsasock, NULL, 0); 892 WSACloseEvent(data[idx].wsaevent); 893 } 894 895 for(idx = 0; idx < thd; idx++) { 896 WaitForSingleObject(data[idx].thread, INFINITE); 897 CloseHandle(data[idx].thread); 898 } 899 900 CloseHandle(waitevent); 901 902 free(handles); 903 free(data); 904 905 return ret; 906 } 907 #define select(a,b,c,d,e) select_ws(a,b,c,d,e) 908 #endif /* USE_WINSOCK */ 909 910 /* 911 sockfdp is a pointer to an established stream or CURL_SOCKET_BAD 912 913 if sockfd is CURL_SOCKET_BAD, listendfd is a listening socket we must 914 accept() 915 */ 916 static bool juggle(curl_socket_t *sockfdp, 917 curl_socket_t listenfd, 918 enum sockmode *mode) 919 { 920 struct timeval timeout; 921 fd_set fds_read; 922 fd_set fds_write; 923 fd_set fds_err; 924 curl_socket_t sockfd = CURL_SOCKET_BAD; 925 int maxfd = -99; 926 ssize_t rc; 927 ssize_t nread_socket; 928 ssize_t bytes_written; 929 ssize_t buffer_len; 930 int error = 0; 931 932 /* 'buffer' is this excessively large only to be able to support things like 933 test 1003 which tests exceedingly large server response lines */ 934 unsigned char buffer[17010]; 935 char data[16]; 936 937 if(got_exit_signal) { 938 logmsg("signalled to die, exiting..."); 939 return FALSE; 940 } 941 942 #ifdef HAVE_GETPPID 943 /* As a last resort, quit if sockfilt process becomes orphan. Just in case 944 parent ftpserver process has died without killing its sockfilt children */ 945 if(getppid() <= 1) { 946 logmsg("process becomes orphan, exiting"); 947 return FALSE; 948 } 949 #endif 950 951 timeout.tv_sec = 120; 952 timeout.tv_usec = 0; 953 954 FD_ZERO(&fds_read); 955 FD_ZERO(&fds_write); 956 FD_ZERO(&fds_err); 957 958 FD_SET((curl_socket_t)fileno(stdin), &fds_read); 959 960 switch(*mode) { 961 962 case PASSIVE_LISTEN: 963 964 /* server mode */ 965 sockfd = listenfd; 966 /* there's always a socket to wait for */ 967 FD_SET(sockfd, &fds_read); 968 maxfd = (int)sockfd; 969 break; 970 971 case PASSIVE_CONNECT: 972 973 sockfd = *sockfdp; 974 if(CURL_SOCKET_BAD == sockfd) { 975 /* eeek, we are supposedly connected and then this cannot be -1 ! */ 976 logmsg("socket is -1! on %s:%d", __FILE__, __LINE__); 977 maxfd = 0; /* stdin */ 978 } 979 else { 980 /* there's always a socket to wait for */ 981 FD_SET(sockfd, &fds_read); 982 #ifdef USE_WINSOCK 983 FD_SET(sockfd, &fds_err); 984 #endif 985 maxfd = (int)sockfd; 986 } 987 break; 988 989 case ACTIVE: 990 991 sockfd = *sockfdp; 992 /* sockfd turns CURL_SOCKET_BAD when our connection has been closed */ 993 if(CURL_SOCKET_BAD != sockfd) { 994 FD_SET(sockfd, &fds_read); 995 #ifdef USE_WINSOCK 996 FD_SET(sockfd, &fds_err); 997 #endif 998 maxfd = (int)sockfd; 999 } 1000 else { 1001 logmsg("No socket to read on"); 1002 maxfd = 0; 1003 } 1004 break; 1005 1006 case ACTIVE_DISCONNECT: 1007 1008 logmsg("disconnected, no socket to read on"); 1009 maxfd = 0; 1010 sockfd = CURL_SOCKET_BAD; 1011 break; 1012 1013 } /* switch(*mode) */ 1014 1015 1016 do { 1017 1018 /* select() blocking behavior call on blocking descriptors please */ 1019 1020 rc = select(maxfd + 1, &fds_read, &fds_write, &fds_err, &timeout); 1021 1022 if(got_exit_signal) { 1023 logmsg("signalled to die, exiting..."); 1024 return FALSE; 1025 } 1026 1027 } while((rc == -1) && ((error = errno) == EINTR)); 1028 1029 if(rc < 0) { 1030 logmsg("select() failed with error: (%d) %s", 1031 error, strerror(error)); 1032 return FALSE; 1033 } 1034 1035 if(rc == 0) 1036 /* timeout */ 1037 return TRUE; 1038 1039 1040 if(FD_ISSET(fileno(stdin), &fds_read)) { 1041 /* read from stdin, commands/data to be dealt with and possibly passed on 1042 to the socket 1043 1044 protocol: 1045 1046 4 letter command + LF [mandatory] 1047 1048 4-digit hexadecimal data length + LF [if the command takes data] 1049 data [the data being as long as set above] 1050 1051 Commands: 1052 1053 DATA - plain pass-thru data 1054 */ 1055 1056 if(!read_stdin(buffer, 5)) 1057 return FALSE; 1058 1059 logmsg("Received %c%c%c%c (on stdin)", 1060 buffer[0], buffer[1], buffer[2], buffer[3]); 1061 1062 if(!memcmp("PING", buffer, 4)) { 1063 /* send reply on stdout, just proving we are alive */ 1064 if(!write_stdout("PONG\n", 5)) 1065 return FALSE; 1066 } 1067 1068 else if(!memcmp("PORT", buffer, 4)) { 1069 /* Question asking us what PORT number we are listening to. 1070 Replies to PORT with "IPv[num]/[port]" */ 1071 snprintf((char *)buffer, sizeof(buffer), "%s/%hu\n", ipv_inuse, port); 1072 buffer_len = (ssize_t)strlen((char *)buffer); 1073 snprintf(data, sizeof(data), "PORT\n%04zx\n", buffer_len); 1074 if(!write_stdout(data, 10)) 1075 return FALSE; 1076 if(!write_stdout(buffer, buffer_len)) 1077 return FALSE; 1078 } 1079 else if(!memcmp("QUIT", buffer, 4)) { 1080 /* just die */ 1081 logmsg("quits"); 1082 return FALSE; 1083 } 1084 else if(!memcmp("DATA", buffer, 4)) { 1085 /* data IN => data OUT */ 1086 1087 if(!read_stdin(buffer, 5)) 1088 return FALSE; 1089 1090 buffer[5] = '\0'; 1091 1092 buffer_len = (ssize_t)strtol((char *)buffer, NULL, 16); 1093 if(buffer_len > (ssize_t)sizeof(buffer)) { 1094 logmsg("ERROR: Buffer size (%zu bytes) too small for data size " 1095 "(%zd bytes)", sizeof(buffer), buffer_len); 1096 return FALSE; 1097 } 1098 logmsg("> %zd bytes data, server => client", buffer_len); 1099 1100 if(!read_stdin(buffer, buffer_len)) 1101 return FALSE; 1102 1103 lograw(buffer, buffer_len); 1104 1105 if(*mode == PASSIVE_LISTEN) { 1106 logmsg("*** We are disconnected!"); 1107 if(!write_stdout("DISC\n", 5)) 1108 return FALSE; 1109 } 1110 else { 1111 /* send away on the socket */ 1112 bytes_written = swrite(sockfd, buffer, buffer_len); 1113 if(bytes_written != buffer_len) { 1114 logmsg("Not all data was sent. Bytes to send: %zd sent: %zd", 1115 buffer_len, bytes_written); 1116 } 1117 } 1118 } 1119 else if(!memcmp("DISC", buffer, 4)) { 1120 /* disconnect! */ 1121 if(!write_stdout("DISC\n", 5)) 1122 return FALSE; 1123 if(sockfd != CURL_SOCKET_BAD) { 1124 logmsg("====> Client forcibly disconnected"); 1125 sclose(sockfd); 1126 *sockfdp = CURL_SOCKET_BAD; 1127 if(*mode == PASSIVE_CONNECT) 1128 *mode = PASSIVE_LISTEN; 1129 else 1130 *mode = ACTIVE_DISCONNECT; 1131 } 1132 else 1133 logmsg("attempt to close already dead connection"); 1134 return TRUE; 1135 } 1136 } 1137 1138 1139 if((sockfd != CURL_SOCKET_BAD) && (FD_ISSET(sockfd, &fds_read)) ) { 1140 1141 curl_socket_t newfd = CURL_SOCKET_BAD; /* newly accepted socket */ 1142 1143 if(*mode == PASSIVE_LISTEN) { 1144 /* there's no stream set up yet, this is an indication that there's a 1145 client connecting. */ 1146 newfd = accept(sockfd, NULL, NULL); 1147 if(CURL_SOCKET_BAD == newfd) { 1148 error = SOCKERRNO; 1149 logmsg("accept(%d, NULL, NULL) failed with error: (%d) %s", 1150 sockfd, error, strerror(error)); 1151 } 1152 else { 1153 logmsg("====> Client connect"); 1154 if(!write_stdout("CNCT\n", 5)) 1155 return FALSE; 1156 *sockfdp = newfd; /* store the new socket */ 1157 *mode = PASSIVE_CONNECT; /* we have connected */ 1158 } 1159 return TRUE; 1160 } 1161 1162 /* read from socket, pass on data to stdout */ 1163 nread_socket = sread(sockfd, buffer, sizeof(buffer)); 1164 1165 if(nread_socket > 0) { 1166 snprintf(data, sizeof(data), "DATA\n%04zx\n", nread_socket); 1167 if(!write_stdout(data, 10)) 1168 return FALSE; 1169 if(!write_stdout(buffer, nread_socket)) 1170 return FALSE; 1171 1172 logmsg("< %zd bytes data, client => server", nread_socket); 1173 lograw(buffer, nread_socket); 1174 } 1175 1176 if(nread_socket <= 0 1177 #ifdef USE_WINSOCK 1178 || FD_ISSET(sockfd, &fds_err) 1179 #endif 1180 ) { 1181 logmsg("====> Client disconnect"); 1182 if(!write_stdout("DISC\n", 5)) 1183 return FALSE; 1184 sclose(sockfd); 1185 *sockfdp = CURL_SOCKET_BAD; 1186 if(*mode == PASSIVE_CONNECT) 1187 *mode = PASSIVE_LISTEN; 1188 else 1189 *mode = ACTIVE_DISCONNECT; 1190 return TRUE; 1191 } 1192 } 1193 1194 return TRUE; 1195 } 1196 1197 static curl_socket_t sockdaemon(curl_socket_t sock, 1198 unsigned short *listenport) 1199 { 1200 /* passive daemon style */ 1201 srvr_sockaddr_union_t listener; 1202 int flag; 1203 int rc; 1204 int totdelay = 0; 1205 int maxretr = 10; 1206 int delay = 20; 1207 int attempt = 0; 1208 int error = 0; 1209 1210 do { 1211 attempt++; 1212 flag = 1; 1213 rc = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, 1214 (void *)&flag, sizeof(flag)); 1215 if(rc) { 1216 error = SOCKERRNO; 1217 logmsg("setsockopt(SO_REUSEADDR) failed with error: (%d) %s", 1218 error, strerror(error)); 1219 if(maxretr) { 1220 rc = wait_ms(delay); 1221 if(rc) { 1222 /* should not happen */ 1223 error = errno; 1224 logmsg("wait_ms() failed with error: (%d) %s", 1225 error, strerror(error)); 1226 sclose(sock); 1227 return CURL_SOCKET_BAD; 1228 } 1229 if(got_exit_signal) { 1230 logmsg("signalled to die, exiting..."); 1231 sclose(sock); 1232 return CURL_SOCKET_BAD; 1233 } 1234 totdelay += delay; 1235 delay *= 2; /* double the sleep for next attempt */ 1236 } 1237 } 1238 } while(rc && maxretr--); 1239 1240 if(rc) { 1241 logmsg("setsockopt(SO_REUSEADDR) failed %d times in %d ms. Error: (%d) %s", 1242 attempt, totdelay, error, strerror(error)); 1243 logmsg("Continuing anyway..."); 1244 } 1245 1246 /* When the specified listener port is zero, it is actually a 1247 request to let the system choose a non-zero available port. */ 1248 1249 #ifdef ENABLE_IPV6 1250 if(!use_ipv6) { 1251 #endif 1252 memset(&listener.sa4, 0, sizeof(listener.sa4)); 1253 listener.sa4.sin_family = AF_INET; 1254 listener.sa4.sin_addr.s_addr = INADDR_ANY; 1255 listener.sa4.sin_port = htons(*listenport); 1256 rc = bind(sock, &listener.sa, sizeof(listener.sa4)); 1257 #ifdef ENABLE_IPV6 1258 } 1259 else { 1260 memset(&listener.sa6, 0, sizeof(listener.sa6)); 1261 listener.sa6.sin6_family = AF_INET6; 1262 listener.sa6.sin6_addr = in6addr_any; 1263 listener.sa6.sin6_port = htons(*listenport); 1264 rc = bind(sock, &listener.sa, sizeof(listener.sa6)); 1265 } 1266 #endif /* ENABLE_IPV6 */ 1267 if(rc) { 1268 error = SOCKERRNO; 1269 logmsg("Error binding socket on port %hu: (%d) %s", 1270 *listenport, error, strerror(error)); 1271 sclose(sock); 1272 return CURL_SOCKET_BAD; 1273 } 1274 1275 if(!*listenport) { 1276 /* The system was supposed to choose a port number, figure out which 1277 port we actually got and update the listener port value with it. */ 1278 curl_socklen_t la_size; 1279 srvr_sockaddr_union_t localaddr; 1280 #ifdef ENABLE_IPV6 1281 if(!use_ipv6) 1282 #endif 1283 la_size = sizeof(localaddr.sa4); 1284 #ifdef ENABLE_IPV6 1285 else 1286 la_size = sizeof(localaddr.sa6); 1287 #endif 1288 memset(&localaddr.sa, 0, (size_t)la_size); 1289 if(getsockname(sock, &localaddr.sa, &la_size) < 0) { 1290 error = SOCKERRNO; 1291 logmsg("getsockname() failed with error: (%d) %s", 1292 error, strerror(error)); 1293 sclose(sock); 1294 return CURL_SOCKET_BAD; 1295 } 1296 switch(localaddr.sa.sa_family) { 1297 case AF_INET: 1298 *listenport = ntohs(localaddr.sa4.sin_port); 1299 break; 1300 #ifdef ENABLE_IPV6 1301 case AF_INET6: 1302 *listenport = ntohs(localaddr.sa6.sin6_port); 1303 break; 1304 #endif 1305 default: 1306 break; 1307 } 1308 if(!*listenport) { 1309 /* Real failure, listener port shall not be zero beyond this point. */ 1310 logmsg("Apparently getsockname() succeeded, with listener port zero."); 1311 logmsg("A valid reason for this failure is a binary built without"); 1312 logmsg("proper network library linkage. This might not be the only"); 1313 logmsg("reason, but double check it before anything else."); 1314 sclose(sock); 1315 return CURL_SOCKET_BAD; 1316 } 1317 } 1318 1319 /* bindonly option forces no listening */ 1320 if(bind_only) { 1321 logmsg("instructed to bind port without listening"); 1322 return sock; 1323 } 1324 1325 /* start accepting connections */ 1326 rc = listen(sock, 5); 1327 if(0 != rc) { 1328 error = SOCKERRNO; 1329 logmsg("listen(%d, 5) failed with error: (%d) %s", 1330 sock, error, strerror(error)); 1331 sclose(sock); 1332 return CURL_SOCKET_BAD; 1333 } 1334 1335 return sock; 1336 } 1337 1338 1339 int main(int argc, char *argv[]) 1340 { 1341 srvr_sockaddr_union_t me; 1342 curl_socket_t sock = CURL_SOCKET_BAD; 1343 curl_socket_t msgsock = CURL_SOCKET_BAD; 1344 int wrotepidfile = 0; 1345 const char *pidname = ".sockfilt.pid"; 1346 bool juggle_again; 1347 int rc; 1348 int error; 1349 int arg = 1; 1350 enum sockmode mode = PASSIVE_LISTEN; /* default */ 1351 const char *addr = NULL; 1352 1353 while(argc>arg) { 1354 if(!strcmp("--version", argv[arg])) { 1355 printf("sockfilt IPv4%s\n", 1356 #ifdef ENABLE_IPV6 1357 "/IPv6" 1358 #else 1359 "" 1360 #endif 1361 ); 1362 return 0; 1363 } 1364 else if(!strcmp("--verbose", argv[arg])) { 1365 verbose = TRUE; 1366 arg++; 1367 } 1368 else if(!strcmp("--pidfile", argv[arg])) { 1369 arg++; 1370 if(argc>arg) 1371 pidname = argv[arg++]; 1372 } 1373 else if(!strcmp("--logfile", argv[arg])) { 1374 arg++; 1375 if(argc>arg) 1376 serverlogfile = argv[arg++]; 1377 } 1378 else if(!strcmp("--ipv6", argv[arg])) { 1379 #ifdef ENABLE_IPV6 1380 ipv_inuse = "IPv6"; 1381 use_ipv6 = TRUE; 1382 #endif 1383 arg++; 1384 } 1385 else if(!strcmp("--ipv4", argv[arg])) { 1386 /* for completeness, we support this option as well */ 1387 #ifdef ENABLE_IPV6 1388 ipv_inuse = "IPv4"; 1389 use_ipv6 = FALSE; 1390 #endif 1391 arg++; 1392 } 1393 else if(!strcmp("--bindonly", argv[arg])) { 1394 bind_only = TRUE; 1395 arg++; 1396 } 1397 else if(!strcmp("--port", argv[arg])) { 1398 arg++; 1399 if(argc>arg) { 1400 char *endptr; 1401 unsigned long ulnum = strtoul(argv[arg], &endptr, 10); 1402 if((endptr != argv[arg] + strlen(argv[arg])) || 1403 ((ulnum != 0UL) && ((ulnum < 1025UL) || (ulnum > 65535UL)))) { 1404 fprintf(stderr, "sockfilt: invalid --port argument (%s)\n", 1405 argv[arg]); 1406 return 0; 1407 } 1408 port = curlx_ultous(ulnum); 1409 arg++; 1410 } 1411 } 1412 else if(!strcmp("--connect", argv[arg])) { 1413 /* Asked to actively connect to the specified local port instead of 1414 doing a passive server-style listening. */ 1415 arg++; 1416 if(argc>arg) { 1417 char *endptr; 1418 unsigned long ulnum = strtoul(argv[arg], &endptr, 10); 1419 if((endptr != argv[arg] + strlen(argv[arg])) || 1420 (ulnum < 1025UL) || (ulnum > 65535UL)) { 1421 fprintf(stderr, "sockfilt: invalid --connect argument (%s)\n", 1422 argv[arg]); 1423 return 0; 1424 } 1425 connectport = curlx_ultous(ulnum); 1426 arg++; 1427 } 1428 } 1429 else if(!strcmp("--addr", argv[arg])) { 1430 /* Set an IP address to use with --connect; otherwise use localhost */ 1431 arg++; 1432 if(argc>arg) { 1433 addr = argv[arg]; 1434 arg++; 1435 } 1436 } 1437 else { 1438 puts("Usage: sockfilt [option]\n" 1439 " --version\n" 1440 " --verbose\n" 1441 " --logfile [file]\n" 1442 " --pidfile [file]\n" 1443 " --ipv4\n" 1444 " --ipv6\n" 1445 " --bindonly\n" 1446 " --port [port]\n" 1447 " --connect [port]\n" 1448 " --addr [address]"); 1449 return 0; 1450 } 1451 } 1452 1453 #ifdef WIN32 1454 win32_init(); 1455 atexit(win32_cleanup); 1456 1457 setmode(fileno(stdin), O_BINARY); 1458 setmode(fileno(stdout), O_BINARY); 1459 setmode(fileno(stderr), O_BINARY); 1460 #endif 1461 1462 install_signal_handlers(); 1463 1464 #ifdef ENABLE_IPV6 1465 if(!use_ipv6) 1466 #endif 1467 sock = socket(AF_INET, SOCK_STREAM, 0); 1468 #ifdef ENABLE_IPV6 1469 else 1470 sock = socket(AF_INET6, SOCK_STREAM, 0); 1471 #endif 1472 1473 if(CURL_SOCKET_BAD == sock) { 1474 error = SOCKERRNO; 1475 logmsg("Error creating socket: (%d) %s", 1476 error, strerror(error)); 1477 write_stdout("FAIL\n", 5); 1478 goto sockfilt_cleanup; 1479 } 1480 1481 if(connectport) { 1482 /* Active mode, we should connect to the given port number */ 1483 mode = ACTIVE; 1484 #ifdef ENABLE_IPV6 1485 if(!use_ipv6) { 1486 #endif 1487 memset(&me.sa4, 0, sizeof(me.sa4)); 1488 me.sa4.sin_family = AF_INET; 1489 me.sa4.sin_port = htons(connectport); 1490 me.sa4.sin_addr.s_addr = INADDR_ANY; 1491 if(!addr) 1492 addr = "127.0.0.1"; 1493 Curl_inet_pton(AF_INET, addr, &me.sa4.sin_addr); 1494 1495 rc = connect(sock, &me.sa, sizeof(me.sa4)); 1496 #ifdef ENABLE_IPV6 1497 } 1498 else { 1499 memset(&me.sa6, 0, sizeof(me.sa6)); 1500 me.sa6.sin6_family = AF_INET6; 1501 me.sa6.sin6_port = htons(connectport); 1502 if(!addr) 1503 addr = "::1"; 1504 Curl_inet_pton(AF_INET6, addr, &me.sa6.sin6_addr); 1505 1506 rc = connect(sock, &me.sa, sizeof(me.sa6)); 1507 } 1508 #endif /* ENABLE_IPV6 */ 1509 if(rc) { 1510 error = SOCKERRNO; 1511 logmsg("Error connecting to port %hu: (%d) %s", 1512 connectport, error, strerror(error)); 1513 write_stdout("FAIL\n", 5); 1514 goto sockfilt_cleanup; 1515 } 1516 logmsg("====> Client connect"); 1517 msgsock = sock; /* use this as stream */ 1518 } 1519 else { 1520 /* passive daemon style */ 1521 sock = sockdaemon(sock, &port); 1522 if(CURL_SOCKET_BAD == sock) { 1523 write_stdout("FAIL\n", 5); 1524 goto sockfilt_cleanup; 1525 } 1526 msgsock = CURL_SOCKET_BAD; /* no stream socket yet */ 1527 } 1528 1529 logmsg("Running %s version", ipv_inuse); 1530 1531 if(connectport) 1532 logmsg("Connected to port %hu", connectport); 1533 else if(bind_only) 1534 logmsg("Bound without listening on port %hu", port); 1535 else 1536 logmsg("Listening on port %hu", port); 1537 1538 wrotepidfile = write_pidfile(pidname); 1539 if(!wrotepidfile) { 1540 write_stdout("FAIL\n", 5); 1541 goto sockfilt_cleanup; 1542 } 1543 1544 do { 1545 juggle_again = juggle(&msgsock, sock, &mode); 1546 } while(juggle_again); 1547 1548 sockfilt_cleanup: 1549 1550 if((msgsock != sock) && (msgsock != CURL_SOCKET_BAD)) 1551 sclose(msgsock); 1552 1553 if(sock != CURL_SOCKET_BAD) 1554 sclose(sock); 1555 1556 if(wrotepidfile) 1557 unlink(pidname); 1558 1559 restore_signal_handlers(); 1560 1561 if(got_exit_signal) { 1562 logmsg("============> sockfilt exits with signal (%d)", exit_signal); 1563 /* 1564 * To properly set the return status of the process we 1565 * must raise the same signal SIGINT or SIGTERM that we 1566 * caught and let the old handler take care of it. 1567 */ 1568 raise(exit_signal); 1569 } 1570 1571 logmsg("============> sockfilt quits"); 1572 return 0; 1573 } 1574 1575