00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "server_setup.h"
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086 #ifdef HAVE_SIGNAL_H
00087 #include <signal.h>
00088 #endif
00089 #ifdef HAVE_NETINET_IN_H
00090 #include <netinet/in.h>
00091 #endif
00092 #ifdef HAVE_ARPA_INET_H
00093 #include <arpa/inet.h>
00094 #endif
00095 #ifdef HAVE_NETDB_H
00096 #include <netdb.h>
00097 #endif
00098
00099 #define ENABLE_CURLX_PRINTF
00100
00101
00102 #include "curlx.h"
00103 #include "getpart.h"
00104 #include "inet_pton.h"
00105 #include "util.h"
00106 #include "server_sockaddr.h"
00107 #include "warnless.h"
00108
00109
00110 #include "memdebug.h"
00111
00112 #ifdef USE_WINSOCK
00113 #undef EINTR
00114 #define EINTR 4
00115 #undef EAGAIN
00116 #define EAGAIN 11
00117 #undef ENOMEM
00118 #define ENOMEM 12
00119 #undef EINVAL
00120 #define EINVAL 22
00121 #endif
00122
00123 #define DEFAULT_PORT 8999
00124
00125 #ifndef DEFAULT_LOGFILE
00126 #define DEFAULT_LOGFILE "log/sockfilt.log"
00127 #endif
00128
00129 const char *serverlogfile = DEFAULT_LOGFILE;
00130
00131 static bool verbose = FALSE;
00132 static bool bind_only = FALSE;
00133 #ifdef ENABLE_IPV6
00134 static bool use_ipv6 = FALSE;
00135 #endif
00136 static const char *ipv_inuse = "IPv4";
00137 static unsigned short port = DEFAULT_PORT;
00138 static unsigned short connectport = 0;
00139
00140 enum sockmode {
00141 PASSIVE_LISTEN,
00142 PASSIVE_CONNECT,
00143 ACTIVE,
00144 ACTIVE_DISCONNECT
00145 };
00146
00147
00148
00149 #ifndef HAVE_SIGINTERRUPT
00150 #define siginterrupt(x,y) do {} while(0)
00151 #endif
00152
00153
00154
00155 typedef RETSIGTYPE (*SIGHANDLER_T)(int);
00156
00157 #ifdef SIGHUP
00158 static SIGHANDLER_T old_sighup_handler = SIG_ERR;
00159 #endif
00160
00161 #ifdef SIGPIPE
00162 static SIGHANDLER_T old_sigpipe_handler = SIG_ERR;
00163 #endif
00164
00165 #ifdef SIGALRM
00166 static SIGHANDLER_T old_sigalrm_handler = SIG_ERR;
00167 #endif
00168
00169 #ifdef SIGINT
00170 static SIGHANDLER_T old_sigint_handler = SIG_ERR;
00171 #endif
00172
00173 #ifdef SIGTERM
00174 static SIGHANDLER_T old_sigterm_handler = SIG_ERR;
00175 #endif
00176
00177 #if defined(SIGBREAK) && defined(WIN32)
00178 static SIGHANDLER_T old_sigbreak_handler = SIG_ERR;
00179 #endif
00180
00181
00182
00183 SIG_ATOMIC_T got_exit_signal = 0;
00184
00185
00186
00187 static volatile int exit_signal = 0;
00188
00189
00190
00191
00192
00193
00194 static RETSIGTYPE exit_signal_handler(int signum)
00195 {
00196 int old_errno = errno;
00197 if(got_exit_signal == 0) {
00198 got_exit_signal = 1;
00199 exit_signal = signum;
00200 }
00201 (void)signal(signum, exit_signal_handler);
00202 errno = old_errno;
00203 }
00204
00205 static void install_signal_handlers(void)
00206 {
00207 #ifdef SIGHUP
00208
00209 old_sighup_handler = signal(SIGHUP, SIG_IGN);
00210 if(old_sighup_handler == SIG_ERR)
00211 logmsg("cannot install SIGHUP handler: %s", strerror(errno));
00212 #endif
00213 #ifdef SIGPIPE
00214
00215 old_sigpipe_handler = signal(SIGPIPE, SIG_IGN);
00216 if(old_sigpipe_handler == SIG_ERR)
00217 logmsg("cannot install SIGPIPE handler: %s", strerror(errno));
00218 #endif
00219 #ifdef SIGALRM
00220
00221 old_sigalrm_handler = signal(SIGALRM, SIG_IGN);
00222 if(old_sigalrm_handler == SIG_ERR)
00223 logmsg("cannot install SIGALRM handler: %s", strerror(errno));
00224 #endif
00225 #ifdef SIGINT
00226
00227 old_sigint_handler = signal(SIGINT, exit_signal_handler);
00228 if(old_sigint_handler == SIG_ERR)
00229 logmsg("cannot install SIGINT handler: %s", strerror(errno));
00230 else
00231 siginterrupt(SIGINT, 1);
00232 #endif
00233 #ifdef SIGTERM
00234
00235 old_sigterm_handler = signal(SIGTERM, exit_signal_handler);
00236 if(old_sigterm_handler == SIG_ERR)
00237 logmsg("cannot install SIGTERM handler: %s", strerror(errno));
00238 else
00239 siginterrupt(SIGTERM, 1);
00240 #endif
00241 #if defined(SIGBREAK) && defined(WIN32)
00242
00243 old_sigbreak_handler = signal(SIGBREAK, exit_signal_handler);
00244 if(old_sigbreak_handler == SIG_ERR)
00245 logmsg("cannot install SIGBREAK handler: %s", strerror(errno));
00246 else
00247 siginterrupt(SIGBREAK, 1);
00248 #endif
00249 }
00250
00251 static void restore_signal_handlers(void)
00252 {
00253 #ifdef SIGHUP
00254 if(SIG_ERR != old_sighup_handler)
00255 (void)signal(SIGHUP, old_sighup_handler);
00256 #endif
00257 #ifdef SIGPIPE
00258 if(SIG_ERR != old_sigpipe_handler)
00259 (void)signal(SIGPIPE, old_sigpipe_handler);
00260 #endif
00261 #ifdef SIGALRM
00262 if(SIG_ERR != old_sigalrm_handler)
00263 (void)signal(SIGALRM, old_sigalrm_handler);
00264 #endif
00265 #ifdef SIGINT
00266 if(SIG_ERR != old_sigint_handler)
00267 (void)signal(SIGINT, old_sigint_handler);
00268 #endif
00269 #ifdef SIGTERM
00270 if(SIG_ERR != old_sigterm_handler)
00271 (void)signal(SIGTERM, old_sigterm_handler);
00272 #endif
00273 #if defined(SIGBREAK) && defined(WIN32)
00274 if(SIG_ERR != old_sigbreak_handler)
00275 (void)signal(SIGBREAK, old_sigbreak_handler);
00276 #endif
00277 }
00278
00279 #ifdef WIN32
00280
00281
00282
00283 static ssize_t read_wincon(int fd, void *buf, size_t count)
00284 {
00285 HANDLE handle = NULL;
00286 DWORD mode, rcount = 0;
00287 BOOL success;
00288
00289 if(fd == fileno(stdin)) {
00290 handle = GetStdHandle(STD_INPUT_HANDLE);
00291 }
00292 else {
00293 return read(fd, buf, count);
00294 }
00295
00296 if(GetConsoleMode(handle, &mode)) {
00297 success = ReadConsole(handle, buf, curlx_uztoul(count), &rcount, NULL);
00298 }
00299 else {
00300 success = ReadFile(handle, buf, curlx_uztoul(count), &rcount, NULL);
00301 }
00302 if(success) {
00303 return rcount;
00304 }
00305
00306 errno = GetLastError();
00307 return -1;
00308 }
00309 #undef read
00310 #define read(a,b,c) read_wincon(a,b,c)
00311
00312
00313
00314
00315 static ssize_t write_wincon(int fd, const void *buf, size_t count)
00316 {
00317 HANDLE handle = NULL;
00318 DWORD mode, wcount = 0;
00319 BOOL success;
00320
00321 if(fd == fileno(stdout)) {
00322 handle = GetStdHandle(STD_OUTPUT_HANDLE);
00323 }
00324 else if(fd == fileno(stderr)) {
00325 handle = GetStdHandle(STD_ERROR_HANDLE);
00326 }
00327 else {
00328 return write(fd, buf, count);
00329 }
00330
00331 if(GetConsoleMode(handle, &mode)) {
00332 success = WriteConsole(handle, buf, curlx_uztoul(count), &wcount, NULL);
00333 }
00334 else {
00335 success = WriteFile(handle, buf, curlx_uztoul(count), &wcount, NULL);
00336 }
00337 if(success) {
00338 return wcount;
00339 }
00340
00341 errno = GetLastError();
00342 return -1;
00343 }
00344 #undef write
00345 #define write(a,b,c) write_wincon(a,b,c)
00346 #endif
00347
00348
00349
00350
00351
00352
00353
00354
00355 static ssize_t fullread(int filedes, void *buffer, size_t nbytes)
00356 {
00357 int error;
00358 ssize_t rc;
00359 ssize_t nread = 0;
00360
00361 do {
00362 rc = read(filedes, (unsigned char *)buffer + nread, nbytes - nread);
00363
00364 if(got_exit_signal) {
00365 logmsg("signalled to die");
00366 return -1;
00367 }
00368
00369 if(rc < 0) {
00370 error = errno;
00371 if((error == EINTR) || (error == EAGAIN))
00372 continue;
00373 logmsg("reading from file descriptor: %d,", filedes);
00374 logmsg("unrecoverable read() failure: (%d) %s",
00375 error, strerror(error));
00376 return -1;
00377 }
00378
00379 if(rc == 0) {
00380 logmsg("got 0 reading from stdin");
00381 return 0;
00382 }
00383
00384 nread += rc;
00385
00386 } while((size_t)nread < nbytes);
00387
00388 if(verbose)
00389 logmsg("read %zd bytes", nread);
00390
00391 return nread;
00392 }
00393
00394
00395
00396
00397
00398
00399
00400
00401 static ssize_t fullwrite(int filedes, const void *buffer, size_t nbytes)
00402 {
00403 int error;
00404 ssize_t wc;
00405 ssize_t nwrite = 0;
00406
00407 do {
00408 wc = write(filedes, (unsigned char *)buffer + nwrite, nbytes - nwrite);
00409
00410 if(got_exit_signal) {
00411 logmsg("signalled to die");
00412 return -1;
00413 }
00414
00415 if(wc < 0) {
00416 error = errno;
00417 if((error == EINTR) || (error == EAGAIN))
00418 continue;
00419 logmsg("writing to file descriptor: %d,", filedes);
00420 logmsg("unrecoverable write() failure: (%d) %s",
00421 error, strerror(error));
00422 return -1;
00423 }
00424
00425 if(wc == 0) {
00426 logmsg("put 0 writing to stdout");
00427 return 0;
00428 }
00429
00430 nwrite += wc;
00431
00432 } while((size_t)nwrite < nbytes);
00433
00434 if(verbose)
00435 logmsg("wrote %zd bytes", nwrite);
00436
00437 return nwrite;
00438 }
00439
00440
00441
00442
00443
00444
00445
00446
00447 static bool read_stdin(void *buffer, size_t nbytes)
00448 {
00449 ssize_t nread = fullread(fileno(stdin), buffer, nbytes);
00450 if(nread != (ssize_t)nbytes) {
00451 logmsg("exiting...");
00452 return FALSE;
00453 }
00454 return TRUE;
00455 }
00456
00457
00458
00459
00460
00461
00462
00463
00464 static bool write_stdout(const void *buffer, size_t nbytes)
00465 {
00466 ssize_t nwrite = fullwrite(fileno(stdout), buffer, nbytes);
00467 if(nwrite != (ssize_t)nbytes) {
00468 logmsg("exiting...");
00469 return FALSE;
00470 }
00471 return TRUE;
00472 }
00473
00474 static void lograw(unsigned char *buffer, ssize_t len)
00475 {
00476 char data[120];
00477 ssize_t i;
00478 unsigned char *ptr = buffer;
00479 char *optr = data;
00480 ssize_t width=0;
00481 int left = sizeof(data);
00482
00483 for(i=0; i<len; i++) {
00484 switch(ptr[i]) {
00485 case '\n':
00486 snprintf(optr, left, "\\n");
00487 width += 2;
00488 optr += 2;
00489 left-=2;
00490 break;
00491 case '\r':
00492 snprintf(optr, left, "\\r");
00493 width += 2;
00494 optr += 2;
00495 left-=2;
00496 break;
00497 default:
00498 snprintf(optr, left, "%c", (ISGRAPH(ptr[i]) ||
00499 ptr[i]==0x20) ?ptr[i]:'.');
00500 width++;
00501 optr++;
00502 left--;
00503 break;
00504 }
00505
00506 if(width>60) {
00507 logmsg("'%s'", data);
00508 width = 0;
00509 optr = data;
00510 left = sizeof(data);
00511 }
00512 }
00513 if(width)
00514 logmsg("'%s'", data);
00515 }
00516
00517 #ifdef USE_WINSOCK
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530 struct select_ws_wait_data {
00531 HANDLE handle;
00532 HANDLE event;
00533 };
00534 static DWORD WINAPI select_ws_wait_thread(LPVOID lpParameter)
00535 {
00536 struct select_ws_wait_data *data;
00537 HANDLE handle, handles[2];
00538 INPUT_RECORD inputrecord;
00539 LARGE_INTEGER size, pos;
00540 DWORD type, length;
00541
00542
00543 data = (struct select_ws_wait_data *) lpParameter;
00544 if(data) {
00545 handle = data->handle;
00546 handles[0] = data->event;
00547 handles[1] = handle;
00548 free(data);
00549 }
00550 else
00551 return -1;
00552
00553
00554 type = GetFileType(handle);
00555 switch(type) {
00556 case FILE_TYPE_DISK:
00557
00558
00559
00560
00561
00562
00563
00564
00565 while(WaitForMultipleObjectsEx(1, handles, FALSE, 0, FALSE)
00566 == WAIT_TIMEOUT) {
00567
00568 length = 0;
00569 size.QuadPart = 0;
00570 size.LowPart = GetFileSize(handle, &length);
00571 if((size.LowPart != INVALID_FILE_SIZE) ||
00572 (GetLastError() == NO_ERROR)) {
00573 size.HighPart = length;
00574
00575 pos.QuadPart = 0;
00576 pos.LowPart = SetFilePointer(handle, 0, &pos.HighPart,
00577 FILE_CURRENT);
00578 if((pos.LowPart != INVALID_SET_FILE_POINTER) ||
00579 (GetLastError() == NO_ERROR)) {
00580
00581 if(size.QuadPart == pos.QuadPart) {
00582
00583 SleepEx(0, FALSE);
00584 continue;
00585 }
00586 }
00587 }
00588
00589 break;
00590 }
00591 break;
00592
00593 case FILE_TYPE_CHAR:
00594
00595
00596
00597
00598
00599
00600
00601 while(WaitForMultipleObjectsEx(2, handles, FALSE, INFINITE, FALSE)
00602 == WAIT_OBJECT_0 + 1) {
00603
00604 length = 0;
00605 if(GetConsoleMode(handle, &length)) {
00606
00607 length = 0;
00608 if(PeekConsoleInput(handle, &inputrecord, 1, &length)) {
00609
00610 if(length == 1 && inputrecord.EventType != KEY_EVENT) {
00611
00612 ReadConsoleInput(handle, &inputrecord, 1, &length);
00613 continue;
00614 }
00615 }
00616 }
00617
00618 break;
00619 }
00620 break;
00621
00622 case FILE_TYPE_PIPE:
00623
00624
00625
00626
00627
00628
00629
00630 while(WaitForMultipleObjectsEx(1, handles, FALSE, 0, FALSE)
00631 == WAIT_TIMEOUT) {
00632
00633 length = 0;
00634 if(PeekNamedPipe(handle, NULL, 0, NULL, &length, NULL)) {
00635
00636 if(length == 0) {
00637 SleepEx(0, FALSE);
00638 continue;
00639 }
00640 }
00641 else {
00642
00643 if(GetLastError() == ERROR_BROKEN_PIPE) {
00644 SleepEx(0, FALSE);
00645 continue;
00646 }
00647 }
00648
00649 break;
00650 }
00651 break;
00652
00653 default:
00654
00655 WaitForMultipleObjectsEx(2, handles, FALSE, INFINITE, FALSE);
00656 break;
00657 }
00658
00659 return 0;
00660 }
00661 static HANDLE select_ws_wait(HANDLE handle, HANDLE event)
00662 {
00663 struct select_ws_wait_data *data;
00664 HANDLE thread = NULL;
00665
00666
00667 data = malloc(sizeof(struct select_ws_wait_data));
00668 if(data) {
00669 data->handle = handle;
00670 data->event = event;
00671
00672
00673 thread = CreateThread(NULL, 0,
00674 &select_ws_wait_thread,
00675 data, 0, NULL);
00676
00677
00678 if(!thread) {
00679 free(data);
00680 }
00681 }
00682
00683 return thread;
00684 }
00685 struct select_ws_data {
00686 curl_socket_t fd;
00687 curl_socket_t wsasock;
00688 WSAEVENT wsaevent;
00689 HANDLE thread;
00690 };
00691 static int select_ws(int nfds, fd_set *readfds, fd_set *writefds,
00692 fd_set *exceptfds, struct timeval *timeout)
00693 {
00694 DWORD milliseconds, wait, idx;
00695 WSANETWORKEVENTS wsanetevents;
00696 struct select_ws_data *data;
00697 HANDLE handle, *handles;
00698 curl_socket_t sock;
00699 long networkevents;
00700 WSAEVENT wsaevent;
00701 int error, fds;
00702 HANDLE waitevent = NULL;
00703 DWORD nfd = 0, thd = 0, wsa = 0;
00704 int ret = 0;
00705
00706
00707 if(nfds < 0) {
00708 errno = EINVAL;
00709 return -1;
00710 }
00711
00712
00713 if(!nfds) {
00714 Sleep((timeout->tv_sec*1000)+(DWORD)(((double)timeout->tv_usec)/1000.0));
00715 return 0;
00716 }
00717
00718
00719 waitevent = CreateEvent(NULL, TRUE, FALSE, NULL);
00720 if(!waitevent) {
00721 errno = ENOMEM;
00722 return -1;
00723 }
00724
00725
00726 data = malloc(nfds * sizeof(struct select_ws_data));
00727 if(data == NULL) {
00728 errno = ENOMEM;
00729 return -1;
00730 }
00731
00732
00733 handles = malloc(nfds * sizeof(HANDLE));
00734 if(handles == NULL) {
00735 free(data);
00736 errno = ENOMEM;
00737 return -1;
00738 }
00739
00740
00741 memset(data, 0, nfds * sizeof(struct select_ws_data));
00742 memset(handles, 0, nfds * sizeof(HANDLE));
00743
00744
00745 for(fds = 0; fds < nfds; fds++) {
00746 networkevents = 0;
00747 handles[nfd] = 0;
00748
00749 if(FD_ISSET(fds, readfds))
00750 networkevents |= FD_READ|FD_ACCEPT|FD_CLOSE;
00751
00752 if(FD_ISSET(fds, writefds))
00753 networkevents |= FD_WRITE|FD_CONNECT;
00754
00755 if(FD_ISSET(fds, exceptfds))
00756 networkevents |= FD_OOB|FD_CLOSE;
00757
00758
00759 if(networkevents) {
00760 data[nfd].fd = curlx_sitosk(fds);
00761 if(fds == fileno(stdin)) {
00762 handle = GetStdHandle(STD_INPUT_HANDLE);
00763 handle = select_ws_wait(handle, waitevent);
00764 handles[nfd] = handle;
00765 data[thd].thread = handle;
00766 thd++;
00767 }
00768 else if(fds == fileno(stdout)) {
00769 handles[nfd] = GetStdHandle(STD_OUTPUT_HANDLE);
00770 }
00771 else if(fds == fileno(stderr)) {
00772 handles[nfd] = GetStdHandle(STD_ERROR_HANDLE);
00773 }
00774 else {
00775 wsaevent = WSACreateEvent();
00776 if(wsaevent != WSA_INVALID_EVENT) {
00777 error = WSAEventSelect(fds, wsaevent, networkevents);
00778 if(error != SOCKET_ERROR) {
00779 handle = (HANDLE) wsaevent;
00780 handles[nfd] = handle;
00781 data[wsa].wsasock = curlx_sitosk(fds);
00782 data[wsa].wsaevent = wsaevent;
00783 wsa++;
00784 }
00785 else {
00786 WSACloseEvent(wsaevent);
00787 handle = (HANDLE) curlx_sitosk(fds);
00788 handle = select_ws_wait(handle, waitevent);
00789 handles[nfd] = handle;
00790 data[thd].thread = handle;
00791 thd++;
00792 }
00793 }
00794 }
00795 nfd++;
00796 }
00797 }
00798
00799
00800 if(timeout) {
00801 milliseconds = ((timeout->tv_sec * 1000) + (timeout->tv_usec / 1000));
00802 }
00803 else {
00804 milliseconds = INFINITE;
00805 }
00806
00807
00808 wait = WaitForMultipleObjectsEx(nfd, handles, FALSE, milliseconds, FALSE);
00809
00810
00811 SetEvent(waitevent);
00812
00813
00814 for(idx = 0; idx < nfd; idx++) {
00815 handle = handles[idx];
00816 sock = data[idx].fd;
00817 fds = curlx_sktosi(sock);
00818
00819
00820 if(wait != WAIT_FAILED && (wait - WAIT_OBJECT_0) <= idx &&
00821 WaitForSingleObjectEx(handle, 0, FALSE) == WAIT_OBJECT_0) {
00822
00823 if(fds == fileno(stdin)) {
00824
00825 FD_CLR(sock, writefds);
00826 FD_CLR(sock, exceptfds);
00827 }
00828 else if(fds == fileno(stdout) || fds == fileno(stderr)) {
00829
00830 FD_CLR(sock, readfds);
00831 FD_CLR(sock, exceptfds);
00832 }
00833 else {
00834
00835 wsanetevents.lNetworkEvents = 0;
00836 error = WSAEnumNetworkEvents(fds, handle, &wsanetevents);
00837 if(error != SOCKET_ERROR) {
00838
00839 if(!(wsanetevents.lNetworkEvents & (FD_READ|FD_ACCEPT|FD_CLOSE)))
00840 FD_CLR(sock, readfds);
00841
00842
00843 if(!(wsanetevents.lNetworkEvents & (FD_WRITE|FD_CONNECT)))
00844 FD_CLR(sock, writefds);
00845
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856 if(!(wsanetevents.lNetworkEvents & (FD_OOB|FD_CLOSE)))
00857 FD_CLR(sock, exceptfds);
00858 }
00859 }
00860
00861
00862 if(FD_ISSET(sock, readfds) || FD_ISSET(sock, writefds) ||
00863 FD_ISSET(sock, exceptfds)) {
00864 ret++;
00865 }
00866 }
00867 else {
00868
00869 FD_CLR(sock, readfds);
00870 FD_CLR(sock, writefds);
00871 FD_CLR(sock, exceptfds);
00872 }
00873 }
00874
00875 for(fds = 0; fds < nfds; fds++) {
00876 if(FD_ISSET(fds, readfds))
00877 logmsg("select_ws: %d is readable", fds);
00878
00879 if(FD_ISSET(fds, writefds))
00880 logmsg("select_ws: %d is writable", fds);
00881
00882 if(FD_ISSET(fds, exceptfds))
00883 logmsg("select_ws: %d is excepted", fds);
00884 }
00885
00886 for(idx = 0; idx < wsa; idx++) {
00887 WSAEventSelect(data[idx].wsasock, NULL, 0);
00888 WSACloseEvent(data[idx].wsaevent);
00889 }
00890
00891 for(idx = 0; idx < thd; idx++) {
00892 WaitForSingleObject(data[idx].thread, INFINITE);
00893 CloseHandle(data[idx].thread);
00894 }
00895
00896 CloseHandle(waitevent);
00897
00898 free(handles);
00899 free(data);
00900
00901 return ret;
00902 }
00903 #define select(a,b,c,d,e) select_ws(a,b,c,d,e)
00904 #endif
00905
00906
00907
00908
00909
00910
00911
00912 static bool juggle(curl_socket_t *sockfdp,
00913 curl_socket_t listenfd,
00914 enum sockmode *mode)
00915 {
00916 struct timeval timeout;
00917 fd_set fds_read;
00918 fd_set fds_write;
00919 fd_set fds_err;
00920 curl_socket_t sockfd = CURL_SOCKET_BAD;
00921 int maxfd = -99;
00922 ssize_t rc;
00923 ssize_t nread_socket;
00924 ssize_t bytes_written;
00925 ssize_t buffer_len;
00926 int error = 0;
00927
00928
00929
00930 unsigned char buffer[17010];
00931 char data[16];
00932
00933 if(got_exit_signal) {
00934 logmsg("signalled to die, exiting...");
00935 return FALSE;
00936 }
00937
00938 #ifdef HAVE_GETPPID
00939
00940
00941 if(getppid() <= 1) {
00942 logmsg("process becomes orphan, exiting");
00943 return FALSE;
00944 }
00945 #endif
00946
00947 timeout.tv_sec = 120;
00948 timeout.tv_usec = 0;
00949
00950 FD_ZERO(&fds_read);
00951 FD_ZERO(&fds_write);
00952 FD_ZERO(&fds_err);
00953
00954 FD_SET((curl_socket_t)fileno(stdin), &fds_read);
00955
00956 switch(*mode) {
00957
00958 case PASSIVE_LISTEN:
00959
00960
00961 sockfd = listenfd;
00962
00963 FD_SET(sockfd, &fds_read);
00964 maxfd = (int)sockfd;
00965 break;
00966
00967 case PASSIVE_CONNECT:
00968
00969 sockfd = *sockfdp;
00970 if(CURL_SOCKET_BAD == sockfd) {
00971
00972 logmsg("socket is -1! on %s:%d", __FILE__, __LINE__);
00973 maxfd = 0;
00974 }
00975 else {
00976
00977 FD_SET(sockfd, &fds_read);
00978 #ifdef USE_WINSOCK
00979 FD_SET(sockfd, &fds_err);
00980 #endif
00981 maxfd = (int)sockfd;
00982 }
00983 break;
00984
00985 case ACTIVE:
00986
00987 sockfd = *sockfdp;
00988
00989 if(CURL_SOCKET_BAD != sockfd) {
00990 FD_SET(sockfd, &fds_read);
00991 #ifdef USE_WINSOCK
00992 FD_SET(sockfd, &fds_err);
00993 #endif
00994 maxfd = (int)sockfd;
00995 }
00996 else {
00997 logmsg("No socket to read on");
00998 maxfd = 0;
00999 }
01000 break;
01001
01002 case ACTIVE_DISCONNECT:
01003
01004 logmsg("disconnected, no socket to read on");
01005 maxfd = 0;
01006 sockfd = CURL_SOCKET_BAD;
01007 break;
01008
01009 }
01010
01011
01012 do {
01013
01014
01015
01016 rc = select(maxfd + 1, &fds_read, &fds_write, &fds_err, &timeout);
01017
01018 if(got_exit_signal) {
01019 logmsg("signalled to die, exiting...");
01020 return FALSE;
01021 }
01022
01023 } while((rc == -1) && ((error = errno) == EINTR));
01024
01025 if(rc < 0) {
01026 logmsg("select() failed with error: (%d) %s",
01027 error, strerror(error));
01028 return FALSE;
01029 }
01030
01031 if(rc == 0)
01032
01033 return TRUE;
01034
01035
01036 if(FD_ISSET(fileno(stdin), &fds_read)) {
01037
01038
01039
01040
01041
01042
01043
01044
01045
01046
01047
01048
01049
01050
01051
01052 if(!read_stdin(buffer, 5))
01053 return FALSE;
01054
01055 logmsg("Received %c%c%c%c (on stdin)",
01056 buffer[0], buffer[1], buffer[2], buffer[3]);
01057
01058 if(!memcmp("PING", buffer, 4)) {
01059
01060 if(!write_stdout("PONG\n", 5))
01061 return FALSE;
01062 }
01063
01064 else if(!memcmp("PORT", buffer, 4)) {
01065
01066
01067 snprintf((char *)buffer, sizeof(buffer), "%s/%hu\n", ipv_inuse, port);
01068 buffer_len = (ssize_t)strlen((char *)buffer);
01069 snprintf(data, sizeof(data), "PORT\n%04zx\n", buffer_len);
01070 if(!write_stdout(data, 10))
01071 return FALSE;
01072 if(!write_stdout(buffer, buffer_len))
01073 return FALSE;
01074 }
01075 else if(!memcmp("QUIT", buffer, 4)) {
01076
01077 logmsg("quits");
01078 return FALSE;
01079 }
01080 else if(!memcmp("DATA", buffer, 4)) {
01081
01082
01083 if(!read_stdin(buffer, 5))
01084 return FALSE;
01085
01086 buffer[5] = '\0';
01087
01088 buffer_len = (ssize_t)strtol((char *)buffer, NULL, 16);
01089 if(buffer_len > (ssize_t)sizeof(buffer)) {
01090 logmsg("ERROR: Buffer size (%zu bytes) too small for data size "
01091 "(%zd bytes)", sizeof(buffer), buffer_len);
01092 return FALSE;
01093 }
01094 logmsg("> %zd bytes data, server => client", buffer_len);
01095
01096 if(!read_stdin(buffer, buffer_len))
01097 return FALSE;
01098
01099 lograw(buffer, buffer_len);
01100
01101 if(*mode == PASSIVE_LISTEN) {
01102 logmsg("*** We are disconnected!");
01103 if(!write_stdout("DISC\n", 5))
01104 return FALSE;
01105 }
01106 else {
01107
01108 bytes_written = swrite(sockfd, buffer, buffer_len);
01109 if(bytes_written != buffer_len) {
01110 logmsg("Not all data was sent. Bytes to send: %zd sent: %zd",
01111 buffer_len, bytes_written);
01112 }
01113 }
01114 }
01115 else if(!memcmp("DISC", buffer, 4)) {
01116
01117 if(!write_stdout("DISC\n", 5))
01118 return FALSE;
01119 if(sockfd != CURL_SOCKET_BAD) {
01120 logmsg("====> Client forcibly disconnected");
01121 sclose(sockfd);
01122 *sockfdp = CURL_SOCKET_BAD;
01123 if(*mode == PASSIVE_CONNECT)
01124 *mode = PASSIVE_LISTEN;
01125 else
01126 *mode = ACTIVE_DISCONNECT;
01127 }
01128 else
01129 logmsg("attempt to close already dead connection");
01130 return TRUE;
01131 }
01132 }
01133
01134
01135 if((sockfd != CURL_SOCKET_BAD) && (FD_ISSET(sockfd, &fds_read)) ) {
01136
01137 curl_socket_t newfd = CURL_SOCKET_BAD;
01138
01139 if(*mode == PASSIVE_LISTEN) {
01140
01141
01142 newfd = accept(sockfd, NULL, NULL);
01143 if(CURL_SOCKET_BAD == newfd) {
01144 error = SOCKERRNO;
01145 logmsg("accept(%d, NULL, NULL) failed with error: (%d) %s",
01146 sockfd, error, strerror(error));
01147 }
01148 else {
01149 logmsg("====> Client connect");
01150 if(!write_stdout("CNCT\n", 5))
01151 return FALSE;
01152 *sockfdp = newfd;
01153 *mode = PASSIVE_CONNECT;
01154 }
01155 return TRUE;
01156 }
01157
01158
01159 nread_socket = sread(sockfd, buffer, sizeof(buffer));
01160
01161 if(nread_socket > 0) {
01162 snprintf(data, sizeof(data), "DATA\n%04zx\n", nread_socket);
01163 if(!write_stdout(data, 10))
01164 return FALSE;
01165 if(!write_stdout(buffer, nread_socket))
01166 return FALSE;
01167
01168 logmsg("< %zd bytes data, client => server", nread_socket);
01169 lograw(buffer, nread_socket);
01170 }
01171
01172 if(nread_socket <= 0
01173 #ifdef USE_WINSOCK
01174 || FD_ISSET(sockfd, &fds_err)
01175 #endif
01176 ) {
01177 logmsg("====> Client disconnect");
01178 if(!write_stdout("DISC\n", 5))
01179 return FALSE;
01180 sclose(sockfd);
01181 *sockfdp = CURL_SOCKET_BAD;
01182 if(*mode == PASSIVE_CONNECT)
01183 *mode = PASSIVE_LISTEN;
01184 else
01185 *mode = ACTIVE_DISCONNECT;
01186 return TRUE;
01187 }
01188 }
01189
01190 return TRUE;
01191 }
01192
01193 static curl_socket_t sockdaemon(curl_socket_t sock,
01194 unsigned short *listenport)
01195 {
01196
01197 srvr_sockaddr_union_t listener;
01198 int flag;
01199 int rc;
01200 int totdelay = 0;
01201 int maxretr = 10;
01202 int delay= 20;
01203 int attempt = 0;
01204 int error = 0;
01205
01206 do {
01207 attempt++;
01208 flag = 1;
01209 rc = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
01210 (void *)&flag, sizeof(flag));
01211 if(rc) {
01212 error = SOCKERRNO;
01213 logmsg("setsockopt(SO_REUSEADDR) failed with error: (%d) %s",
01214 error, strerror(error));
01215 if(maxretr) {
01216 rc = wait_ms(delay);
01217 if(rc) {
01218
01219 error = errno;
01220 logmsg("wait_ms() failed with error: (%d) %s",
01221 error, strerror(error));
01222 sclose(sock);
01223 return CURL_SOCKET_BAD;
01224 }
01225 if(got_exit_signal) {
01226 logmsg("signalled to die, exiting...");
01227 sclose(sock);
01228 return CURL_SOCKET_BAD;
01229 }
01230 totdelay += delay;
01231 delay *= 2;
01232 }
01233 }
01234 } while(rc && maxretr--);
01235
01236 if(rc) {
01237 logmsg("setsockopt(SO_REUSEADDR) failed %d times in %d ms. Error: (%d) %s",
01238 attempt, totdelay, error, strerror(error));
01239 logmsg("Continuing anyway...");
01240 }
01241
01242
01243
01244
01245 #ifdef ENABLE_IPV6
01246 if(!use_ipv6) {
01247 #endif
01248 memset(&listener.sa4, 0, sizeof(listener.sa4));
01249 listener.sa4.sin_family = AF_INET;
01250 listener.sa4.sin_addr.s_addr = INADDR_ANY;
01251 listener.sa4.sin_port = htons(*listenport);
01252 rc = bind(sock, &listener.sa, sizeof(listener.sa4));
01253 #ifdef ENABLE_IPV6
01254 }
01255 else {
01256 memset(&listener.sa6, 0, sizeof(listener.sa6));
01257 listener.sa6.sin6_family = AF_INET6;
01258 listener.sa6.sin6_addr = in6addr_any;
01259 listener.sa6.sin6_port = htons(*listenport);
01260 rc = bind(sock, &listener.sa, sizeof(listener.sa6));
01261 }
01262 #endif
01263 if(rc) {
01264 error = SOCKERRNO;
01265 logmsg("Error binding socket on port %hu: (%d) %s",
01266 *listenport, error, strerror(error));
01267 sclose(sock);
01268 return CURL_SOCKET_BAD;
01269 }
01270
01271 if(!*listenport) {
01272
01273
01274 curl_socklen_t la_size;
01275 srvr_sockaddr_union_t localaddr;
01276 #ifdef ENABLE_IPV6
01277 if(!use_ipv6)
01278 #endif
01279 la_size = sizeof(localaddr.sa4);
01280 #ifdef ENABLE_IPV6
01281 else
01282 la_size = sizeof(localaddr.sa6);
01283 #endif
01284 memset(&localaddr.sa, 0, (size_t)la_size);
01285 if(getsockname(sock, &localaddr.sa, &la_size) < 0) {
01286 error = SOCKERRNO;
01287 logmsg("getsockname() failed with error: (%d) %s",
01288 error, strerror(error));
01289 sclose(sock);
01290 return CURL_SOCKET_BAD;
01291 }
01292 switch(localaddr.sa.sa_family) {
01293 case AF_INET:
01294 *listenport = ntohs(localaddr.sa4.sin_port);
01295 break;
01296 #ifdef ENABLE_IPV6
01297 case AF_INET6:
01298 *listenport = ntohs(localaddr.sa6.sin6_port);
01299 break;
01300 #endif
01301 default:
01302 break;
01303 }
01304 if(!*listenport) {
01305
01306 logmsg("Apparently getsockname() succeeded, with listener port zero.");
01307 logmsg("A valid reason for this failure is a binary built without");
01308 logmsg("proper network library linkage. This might not be the only");
01309 logmsg("reason, but double check it before anything else.");
01310 sclose(sock);
01311 return CURL_SOCKET_BAD;
01312 }
01313 }
01314
01315
01316 if(bind_only) {
01317 logmsg("instructed to bind port without listening");
01318 return sock;
01319 }
01320
01321
01322 rc = listen(sock, 5);
01323 if(0 != rc) {
01324 error = SOCKERRNO;
01325 logmsg("listen(%d, 5) failed with error: (%d) %s",
01326 sock, error, strerror(error));
01327 sclose(sock);
01328 return CURL_SOCKET_BAD;
01329 }
01330
01331 return sock;
01332 }
01333
01334
01335 int main(int argc, char *argv[])
01336 {
01337 srvr_sockaddr_union_t me;
01338 curl_socket_t sock = CURL_SOCKET_BAD;
01339 curl_socket_t msgsock = CURL_SOCKET_BAD;
01340 int wrotepidfile = 0;
01341 char *pidname= (char *)".sockfilt.pid";
01342 bool juggle_again;
01343 int rc;
01344 int error;
01345 int arg=1;
01346 enum sockmode mode = PASSIVE_LISTEN;
01347 const char *addr = NULL;
01348
01349 while(argc>arg) {
01350 if(!strcmp("--version", argv[arg])) {
01351 printf("sockfilt IPv4%s\n",
01352 #ifdef ENABLE_IPV6
01353 "/IPv6"
01354 #else
01355 ""
01356 #endif
01357 );
01358 return 0;
01359 }
01360 else if(!strcmp("--verbose", argv[arg])) {
01361 verbose = TRUE;
01362 arg++;
01363 }
01364 else if(!strcmp("--pidfile", argv[arg])) {
01365 arg++;
01366 if(argc>arg)
01367 pidname = argv[arg++];
01368 }
01369 else if(!strcmp("--logfile", argv[arg])) {
01370 arg++;
01371 if(argc>arg)
01372 serverlogfile = argv[arg++];
01373 }
01374 else if(!strcmp("--ipv6", argv[arg])) {
01375 #ifdef ENABLE_IPV6
01376 ipv_inuse = "IPv6";
01377 use_ipv6 = TRUE;
01378 #endif
01379 arg++;
01380 }
01381 else if(!strcmp("--ipv4", argv[arg])) {
01382
01383 #ifdef ENABLE_IPV6
01384 ipv_inuse = "IPv4";
01385 use_ipv6 = FALSE;
01386 #endif
01387 arg++;
01388 }
01389 else if(!strcmp("--bindonly", argv[arg])) {
01390 bind_only = TRUE;
01391 arg++;
01392 }
01393 else if(!strcmp("--port", argv[arg])) {
01394 arg++;
01395 if(argc>arg) {
01396 char *endptr;
01397 unsigned long ulnum = strtoul(argv[arg], &endptr, 10);
01398 if((endptr != argv[arg] + strlen(argv[arg])) ||
01399 ((ulnum != 0UL) && ((ulnum < 1025UL) || (ulnum > 65535UL)))) {
01400 fprintf(stderr, "sockfilt: invalid --port argument (%s)\n",
01401 argv[arg]);
01402 return 0;
01403 }
01404 port = curlx_ultous(ulnum);
01405 arg++;
01406 }
01407 }
01408 else if(!strcmp("--connect", argv[arg])) {
01409
01410
01411 arg++;
01412 if(argc>arg) {
01413 char *endptr;
01414 unsigned long ulnum = strtoul(argv[arg], &endptr, 10);
01415 if((endptr != argv[arg] + strlen(argv[arg])) ||
01416 (ulnum < 1025UL) || (ulnum > 65535UL)) {
01417 fprintf(stderr, "sockfilt: invalid --connect argument (%s)\n",
01418 argv[arg]);
01419 return 0;
01420 }
01421 connectport = curlx_ultous(ulnum);
01422 arg++;
01423 }
01424 }
01425 else if(!strcmp("--addr", argv[arg])) {
01426
01427 arg++;
01428 if(argc>arg) {
01429 addr = argv[arg];
01430 arg++;
01431 }
01432 }
01433 else {
01434 puts("Usage: sockfilt [option]\n"
01435 " --version\n"
01436 " --verbose\n"
01437 " --logfile [file]\n"
01438 " --pidfile [file]\n"
01439 " --ipv4\n"
01440 " --ipv6\n"
01441 " --bindonly\n"
01442 " --port [port]\n"
01443 " --connect [port]\n"
01444 " --addr [address]");
01445 return 0;
01446 }
01447 }
01448
01449 #ifdef WIN32
01450 win32_init();
01451 atexit(win32_cleanup);
01452
01453 setmode(fileno(stdin), O_BINARY);
01454 setmode(fileno(stdout), O_BINARY);
01455 setmode(fileno(stderr), O_BINARY);
01456 #endif
01457
01458 install_signal_handlers();
01459
01460 #ifdef ENABLE_IPV6
01461 if(!use_ipv6)
01462 #endif
01463 sock = socket(AF_INET, SOCK_STREAM, 0);
01464 #ifdef ENABLE_IPV6
01465 else
01466 sock = socket(AF_INET6, SOCK_STREAM, 0);
01467 #endif
01468
01469 if(CURL_SOCKET_BAD == sock) {
01470 error = SOCKERRNO;
01471 logmsg("Error creating socket: (%d) %s",
01472 error, strerror(error));
01473 write_stdout("FAIL\n", 5);
01474 goto sockfilt_cleanup;
01475 }
01476
01477 if(connectport) {
01478
01479 mode = ACTIVE;
01480 #ifdef ENABLE_IPV6
01481 if(!use_ipv6) {
01482 #endif
01483 memset(&me.sa4, 0, sizeof(me.sa4));
01484 me.sa4.sin_family = AF_INET;
01485 me.sa4.sin_port = htons(connectport);
01486 me.sa4.sin_addr.s_addr = INADDR_ANY;
01487 if(!addr)
01488 addr = "127.0.0.1";
01489 Curl_inet_pton(AF_INET, addr, &me.sa4.sin_addr);
01490
01491 rc = connect(sock, &me.sa, sizeof(me.sa4));
01492 #ifdef ENABLE_IPV6
01493 }
01494 else {
01495 memset(&me.sa6, 0, sizeof(me.sa6));
01496 me.sa6.sin6_family = AF_INET6;
01497 me.sa6.sin6_port = htons(connectport);
01498 if(!addr)
01499 addr = "::1";
01500 Curl_inet_pton(AF_INET6, addr, &me.sa6.sin6_addr);
01501
01502 rc = connect(sock, &me.sa, sizeof(me.sa6));
01503 }
01504 #endif
01505 if(rc) {
01506 error = SOCKERRNO;
01507 logmsg("Error connecting to port %hu: (%d) %s",
01508 connectport, error, strerror(error));
01509 write_stdout("FAIL\n", 5);
01510 goto sockfilt_cleanup;
01511 }
01512 logmsg("====> Client connect");
01513 msgsock = sock;
01514 }
01515 else {
01516
01517 sock = sockdaemon(sock, &port);
01518 if(CURL_SOCKET_BAD == sock) {
01519 write_stdout("FAIL\n", 5);
01520 goto sockfilt_cleanup;
01521 }
01522 msgsock = CURL_SOCKET_BAD;
01523 }
01524
01525 logmsg("Running %s version", ipv_inuse);
01526
01527 if(connectport)
01528 logmsg("Connected to port %hu", connectport);
01529 else if(bind_only)
01530 logmsg("Bound without listening on port %hu", port);
01531 else
01532 logmsg("Listening on port %hu", port);
01533
01534 wrotepidfile = write_pidfile(pidname);
01535 if(!wrotepidfile) {
01536 write_stdout("FAIL\n", 5);
01537 goto sockfilt_cleanup;
01538 }
01539
01540 do {
01541 juggle_again = juggle(&msgsock, sock, &mode);
01542 } while(juggle_again);
01543
01544 sockfilt_cleanup:
01545
01546 if((msgsock != sock) && (msgsock != CURL_SOCKET_BAD))
01547 sclose(msgsock);
01548
01549 if(sock != CURL_SOCKET_BAD)
01550 sclose(sock);
01551
01552 if(wrotepidfile)
01553 unlink(pidname);
01554
01555 restore_signal_handlers();
01556
01557 if(got_exit_signal) {
01558 logmsg("============> sockfilt exits with signal (%d)", exit_signal);
01559
01560
01561
01562
01563
01564 raise(exit_signal);
01565 }
01566
01567 logmsg("============> sockfilt quits");
01568 return 0;
01569 }
01570