00001 /* 00002 * Copyright (c) 2002 - 2003 00003 * NetGroup, Politecnico di Torino (Italy) 00004 * All rights reserved. 00005 * 00006 * Redistribution and use in source and binary forms, with or without 00007 * modification, are permitted provided that the following conditions 00008 * are met: 00009 * 00010 * 1. Redistributions of source code must retain the above copyright 00011 * notice, this list of conditions and the following disclaimer. 00012 * 2. Redistributions in binary form must reproduce the above copyright 00013 * notice, this list of conditions and the following disclaimer in the 00014 * documentation and/or other materials provided with the distribution. 00015 * 3. Neither the name of the Politecnico di Torino nor the names of its 00016 * contributors may be used to endorse or promote products derived from 00017 * this software without specific prior written permission. 00018 * 00019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00020 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00021 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 00022 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 00023 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 00024 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 00025 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 00026 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 00027 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00028 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 00029 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00030 * 00031 */ 00032 00033 00034 00035 00036 00037 #include <errno.h> // for the errno variable 00038 #include <string.h> // for strtok, etc 00039 #include <stdlib.h> // for malloc(), free(), ... 00040 #include <pcap.h> // for PCAP_ERRBUF_SIZE 00041 #include <signal.h> // for signal() 00042 #include <pthread.h> 00043 #include "rpcapd.h" 00044 #include "fileconf.h" // for the configuration file management 00045 #include "pcap-remote.h" 00046 #include "daemon.h" // the true main() method of this daemon 00047 #include "utils.h" // Missing calls and such 00048 #include "sockutils.h" // for socket calls 00049 00050 #ifndef WIN32 00051 #include <unistd.h> // for exit() 00052 #include <sys/wait.h> // waitpid() 00053 #else 00054 #include "win32-svc.h" // for Win32 service stuff 00055 #endif 00056 00057 00058 // Global variables 00059 char hostlist[MAX_HOST_LIST + 1]; 00060 struct active_pars activelist[MAX_ACTIVE_LIST]; 00061 int nullAuthAllowed; 00062 SOCKET sockmain; 00063 char loadfile[MAX_LINE + 1]; 00064 int passivemode= 1; 00065 struct addrinfo mainhints; 00066 char address[MAX_LINE + 1]; 00067 char port[MAX_LINE + 1]; 00068 00069 extern char *optarg; // for getopt() 00070 00071 00072 00073 // Function definition 00074 void main_passive(void *ptr); 00075 void main_active(void *ptr); 00076 00077 00078 #ifndef WIN32 00079 void main_cleanup_childs(int sign); 00080 #endif 00081 00082 00086 void printusage() 00087 { 00088 char *usagetext = 00089 "USAGE:\n" 00090 " " PROGRAM_NAME " [-b <address>] [-p <port>] [-6] [-l <host_list>] [-a <host,port>]\n" 00091 " [-n] [-v] [-d] [-s <file>] [-f <file>]\n" 00092 " -b <address>: the address to bind to (either numeric or literal).\n" 00093 " Default: it binds to all local IPv4 addresses\n" 00094 " -p <port>: the port to bind to. Default: it binds to port " RPCAP_DEFAULT_NETPORT "\n" 00095 " -4: use only IPv4 (default both IPv4 and IPv6 waiting sockets are used)\n" 00096 " -l <host_list>: a file that keeps the list of the hosts which\n" 00097 " are allowed to connect to this server (if more than one,\n" 00098 " list them one per line). We suggest to use \n" 00099 " literal names (instead of numeric ones) in order to avoid\n" 00100 " problems with different address families\n" 00101 " -n: permit NULL authentication (usually used with '-l')\n" 00102 " -a <host, port>: run in active mode when connecting to 'host' on port 'port'\n" 00103 " -v: run in active mode only (default: if '-a' is specified, it accepts passive\n" 00104 " connections as well\n" 00105 " -d: run in daemon mode (UNIX only) or as a service (Win32 only)\n" 00106 " Warning (Win32): this switch is provided automatically when the service\n" 00107 " is started from the control panel\n" 00108 " -s <file>: save the current configuration to file\n" 00109 " -f <file>: load the current configuration from file; all the switches\n" 00110 " specified from the command line are ignored\n" 00111 " -h: print this help screen\n\n"; 00112 00113 printf(usagetext); 00114 } 00115 00116 00117 00119 int main(int argc, char *argv[], char *envp[]) 00120 { 00121 char savefile[MAX_LINE + 1]; // name of the file on which we have to save the configuration 00122 int isdaemon= 0; // Not null if the user wants to run this program as a daemon 00123 int retval; // keeps the returning value from several functions 00124 char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed 00125 00126 00127 savefile[0]= 0; 00128 loadfile[0]= 0; 00129 hostlist[0]= 0; 00130 00131 // Initialize errbuf 00132 memset(errbuf, 0, sizeof(errbuf) ); 00133 00134 if (sock_init(errbuf) == -1) 00135 { 00136 SOCK_ASSERT(errbuf, 1); 00137 exit(-1); 00138 } 00139 00140 strncpy(address, RPCAP_DEFAULT_NETADDR, MAX_LINE); 00141 strncpy(port, RPCAP_DEFAULT_NETPORT, MAX_LINE); 00142 00143 // Prepare to open a new server socket 00144 memset(&mainhints, 0, sizeof(struct addrinfo)); 00145 00146 mainhints.ai_family = PF_UNSPEC; 00147 mainhints.ai_flags = AI_PASSIVE; // Ready to a bind() socket 00148 mainhints.ai_socktype = SOCK_STREAM; 00149 00150 // Getting the proper command line options 00151 while ((retval = getopt(argc, argv, "b:dhp:4l:na:s:f:v")) != -1) 00152 { 00153 switch (retval) 00154 { 00155 case 'b': 00156 strncpy(address, optarg, MAX_LINE); 00157 break; 00158 case 'p': 00159 strncpy(port, optarg, MAX_LINE); 00160 break; 00161 case '4': 00162 mainhints.ai_family = PF_INET; // IPv4 server only 00163 break; 00164 case 'd': 00165 isdaemon= 1; 00166 break; 00167 case 'n': 00168 nullAuthAllowed= 1; 00169 break; 00170 case 'v': 00171 passivemode= 0; 00172 break; 00173 case 'l': 00174 { 00175 strncpy(hostlist, optarg, sizeof(hostlist) ); 00176 break; 00177 } 00178 case 'a': 00179 { 00180 char *tmpaddress, *tmpport; 00181 int i= 0; 00182 00183 tmpaddress= strtok(optarg, RPCAP_HOSTLIST_SEP); 00184 00185 while ( (tmpaddress != NULL) && (i < MAX_ACTIVE_LIST) ) 00186 { 00187 tmpport= strtok(NULL, RPCAP_HOSTLIST_SEP); 00188 00189 snprintf(activelist[i].address, MAX_LINE, tmpaddress); 00190 00191 if ( (tmpport == NULL) || (strcmp(tmpport, "DEFAULT") == 0) ) // the user choose a custom port 00192 snprintf(activelist[i].port, MAX_LINE, RPCAP_DEFAULT_NETPORT_ACTIVE); 00193 else 00194 snprintf(activelist[i].port, MAX_LINE, tmpport); 00195 00196 tmpaddress = strtok(NULL, RPCAP_HOSTLIST_SEP); 00197 00198 i++; 00199 } 00200 00201 if (i > MAX_ACTIVE_LIST) 00202 SOCK_ASSERT("Only MAX_ACTIVE_LIST active connections are currently supported.", 1); 00203 00204 // I don't initialize the remaining part of the structure, since 00205 // it is already zeroed (it is a global var) 00206 break; 00207 } 00208 case 'f': 00209 strncpy(loadfile, optarg, MAX_LINE); 00210 break; 00211 case 's': 00212 strncpy(savefile, optarg, MAX_LINE); 00213 break; 00214 case 'h': 00215 printusage(); 00216 exit(0); 00217 default: 00218 break; 00219 } 00220 } 00221 00222 if (savefile[0]) 00223 { 00224 if (fileconf_save(savefile) ) 00225 SOCK_ASSERT("Error when saving the configuration to file", 1); 00226 } 00227 00228 // If the file does not exist, it keeps the settings provided by the command line 00229 if (loadfile[0]) 00230 fileconf_read(0); 00231 00232 #ifdef linux 00233 // SIGTERM (i.e. kill -15) is not generated in WIN32, although it is included for ANSI compatibility 00234 signal(SIGTERM, main_cleanup); 00235 signal(SIGCHLD, main_cleanup_childs); 00236 #endif 00237 00238 // forking a daemon, if it is needed 00239 if (isdaemon) 00240 { 00241 #ifndef WIN32 00242 int pid; 00243 00244 // Unix Network Programming, pg 336 00245 if ( (pid = fork() ) != 0) 00246 exit(0); // Parent terminates 00247 00248 // First child continues 00249 // Set daemon mode 00250 setsid(); 00251 00252 // generated under unix with 'kill -HUP' 00253 signal(SIGHUP, fileconf_read); 00254 00255 if ( (pid = fork() ) != 0) 00256 exit(0); // First child terminates 00257 00258 // LINUX WARNING: the current linux implementation of pthreads requires a management thread 00259 // to handle some hidden stuff. So, as soon as you create the first thread, two threads are 00260 // created. Fom this point on, the number of threads active are always one more compared 00261 // to the number you're expecting 00262 00263 // Second child continues 00264 // umask(0); 00265 // chdir("/"); 00266 #else 00267 // We use the SIGABRT signal to kill the Win32 service 00268 signal(SIGABRT, main_cleanup); 00269 00270 // If this call succeeds, it is blocking on Win32 00271 if ( svc_start() != 1) 00272 SOCK_ASSERT(1, "Unable to start the service"); 00273 00274 // When the previous call returns, the entire application has to be stopped. 00275 exit(0); 00276 #endif 00277 } 00278 else // Console mode 00279 { 00280 // Enable the catching of Ctrl+C 00281 signal(SIGINT, main_cleanup); 00282 00283 printf("Press CTRL + C to stop the server...\n"); 00284 } 00285 00286 // If we're a Win32 service, we have already called this function in the service_main 00287 main_startup(); 00288 00289 // The code should never arrive here (since the main_startup is blocking) 00290 // however this avoids a compiler warning 00291 exit(0); 00292 } 00293 00294 00295 00296 void main_startup(void) 00297 { 00298 char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed 00299 struct addrinfo *addrinfo; // keeps the addrinfo chain; required to open a new socket 00300 int i; 00301 #ifdef WIN32 00302 pthread_t threadId; // Pthread variable that keeps the thread structures 00303 #else 00304 pid_t pid; 00305 #endif 00306 00307 i= 0; 00308 addrinfo= NULL; 00309 memset(errbuf, 0, sizeof(errbuf) ); 00310 00311 // Starts all the active threads 00312 while ( (activelist[i].address[0] != 0) && (i < MAX_ACTIVE_LIST) ) 00313 { 00314 activelist[i].ai_family= mainhints.ai_family; 00315 00316 #ifdef WIN32 00317 if ( pthread_create( &threadId, NULL, (void *) &main_active, (void *) &activelist[i]) ) 00318 { 00319 SOCK_ASSERT("Error creating the active child thread", 1); 00320 continue; 00321 } 00322 #else 00323 if ( (pid= fork() ) == 0) // I am the child 00324 { 00325 main_active( (void *) &activelist[i]); 00326 exit(0); 00327 } 00328 #endif 00329 i++; 00330 } 00331 00332 /* 00333 The code that manages the active connections is not blocking; 00334 vice versa, the code that manages the passive connection is blocking. 00335 So, if the user do not want to run in passive mode, we have to block 00336 the main thread here, otherwise the program ends and all threads 00337 are stopped. 00338 00339 WARNING: this means that in case we have only active mode, the program does 00340 not terminate even if all the child thread terminates. The user has always to 00341 press Ctrl+C (or send a SIGTERM) to terminate the program. 00342 */ 00343 00344 if (passivemode) 00345 { 00346 struct addrinfo *tempaddrinfo; 00347 00348 // Do the work 00349 if (sock_validaddr((address[0]) ? address : NULL, port, &mainhints, &addrinfo, errbuf) == -1) 00350 { 00351 SOCK_ASSERT(errbuf, 1); 00352 return; 00353 } 00354 00355 tempaddrinfo= addrinfo; 00356 00357 while (tempaddrinfo) 00358 { 00359 if ( (sockmain= sock_open(tempaddrinfo, SOCKOPEN_SERVER, SOCKET_MAXCONN, errbuf)) == -1) 00360 { 00361 SOCK_ASSERT(errbuf, 1); 00362 tempaddrinfo= tempaddrinfo->ai_next; 00363 continue; 00364 } 00365 00366 #ifdef WIN32 00367 if ( pthread_create( &threadId, NULL, (void *) &main_passive, (void *) &sockmain ) ) 00368 { 00369 SOCK_ASSERT("Error creating the passive child thread", 1); 00370 continue; 00371 } 00372 #else 00373 if ( (pid= fork() ) == 0) // I am the child 00374 { 00375 main_passive( (void *) &sockmain); 00376 return; 00377 // exit(0); 00378 } 00379 #endif 00380 // main_passive(sockmain); 00381 tempaddrinfo= tempaddrinfo->ai_next; 00382 } 00383 00384 freeaddrinfo(addrinfo); 00385 } 00386 00387 // All the previous calls are no blocking, so the main line of execution goes here 00388 // and I have to avoid that the program terminates 00389 while (1) 00390 pthread_suspend(10*60*1000); // it wakes up every 10 minutes; it seems to me reasonable 00391 } 00392 00393 00394 /* 00395 \brief Closes gracefully (more or less) the program. 00396 00397 This function is called: 00398 - when we're running in console 00399 - when we're running as a Win32 service (in case we press STOP) 00400 00401 It is not called when we are running as a daemon on UNIX, since 00402 we do not define a signal in order to terminate gracefully the daemon. 00403 00404 This function makes a fast cleanup (it does not clean everything, as 00405 you can see from the fact that it uses kill() on UNIX), closes 00406 the main socket, free winsock resources (on Win32) and exits the 00407 program. 00408 */ 00409 void main_cleanup(int sign) 00410 { 00411 #ifndef WIN32 00412 // Sends a KILL signal to all the processes 00413 // that share the same process group (i.e. kills all the childs) 00414 kill(0, SIGKILL); 00415 #endif 00416 00417 SOCK_ASSERT(PROGRAM_NAME " is closing.\n", 1); 00418 00419 if (sockmain) 00420 closesocket(sockmain); 00421 sock_cleanup(); 00422 00423 /* 00424 This code is executed under the following conditions: 00425 - SIGTERM: we're under UNIX, and the user kills us with 'kill -15' 00426 (no matter is we're a daemon or in a console mode) 00427 - SIGINT: we're in console mode and the user sends us a Ctrl+C 00428 (SIGINT signal), no matter if we're UNIX or Win32 00429 00430 In all these cases, we have to terminate the program. 00431 The case that still remains is if we're a Win32 service: in this case, 00432 we're a child thread, and we want just to terminate ourself. This is because 00433 the exit(0) will be invoked by the main thread, which is blocked waiting that 00434 all childs terminates. We are forced to call exit from the main thread otherwise 00435 the Win32 service control manager (SCM) does not work well. 00436 */ 00437 if ( (sign == SIGTERM) || (sign == SIGINT) ) 00438 exit(0); 00439 else 00440 return; 00441 } 00442 00443 00444 00445 #ifdef linux 00446 00447 void main_cleanup_childs(int sign) 00448 { 00449 pid_t pid; 00450 int stat; 00451 00452 // For reference, Stevens, pg 128 00453 00454 while ( (pid= waitpid(-1, &stat, WNOHANG) ) > 0) 00455 SOCK_ASSERT("Child terminated", 1); 00456 00457 return; 00458 } 00459 00460 #endif 00461 00462 00463 00464 00465 00478 void main_passive(void *ptr) 00479 { 00480 char fakeerrbuf[PCAP_ERRBUF_SIZE + 1]; // needed to keep the message due to an error that we want to discard. 00481 char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed 00482 SOCKET sockctrl; // keeps the socket ID for this control connection 00483 struct sockaddr_storage from; // generic sockaddr_storage variable 00484 socklen_t fromlen; // keeps the length of the sockaddr_storage variable 00485 SOCKET sockmain; 00486 00487 #ifdef linux 00488 pid_t pid; 00489 #endif 00490 00491 sockmain= *((SOCKET *) ptr); 00492 // Initialize errbuf 00493 memset(errbuf, 0, sizeof(errbuf) ); 00494 00495 // main thread loop 00496 while (1) 00497 { 00498 pthread_t threadId; // Pthread variable that keeps the thread structures 00499 struct daemon_slpars *pars; // parameters needed by the daemon_serviceloop() 00500 00501 // Connection creation 00502 fromlen = sizeof(struct sockaddr_storage); 00503 00504 sockctrl= accept(sockmain, (struct sockaddr *) &from, &fromlen); 00505 00506 if (sockctrl == -1) 00507 { 00508 // The accept() call can return this error when a signal is catched 00509 // In this case, we have simply to ignore this error code 00510 // Stevens, pg 124 00511 #ifdef WIN32 00512 if (WSAGetLastError() == WSAEINTR) 00513 #else 00514 if (errno == EINTR) 00515 #endif 00516 continue; 00517 00518 // Don't check for errors here, since the error can be due to the fact that the thread 00519 // has been killed 00520 sock_geterror("accept(): ", errbuf, PCAP_ERRBUF_SIZE); 00521 SOCK_ASSERT(errbuf, 1); 00522 continue; 00523 } 00524 00525 // checks if the connecting host is among the ones allowed 00526 if (sock_check_hostlist(hostlist, RPCAP_HOSTLIST_SEP, &from, errbuf) ) 00527 { 00528 rpcap_senderror(sockctrl, errbuf, PCAP_ERR_HOSTNOAUTH, fakeerrbuf); 00529 sock_close(sockctrl, fakeerrbuf); 00530 continue; 00531 } 00532 00533 00534 #ifdef WIN32 00535 // in case of passive mode, this variable is deallocated by the daemon_serviceloop() 00536 pars= (struct daemon_slpars *) malloc ( sizeof(struct daemon_slpars) ); 00537 if (pars == NULL) 00538 { 00539 snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno)); 00540 continue; 00541 } 00542 00543 pars->sockctrl= sockctrl; 00544 pars->activeclose= 0; // useless in passive mode 00545 pars->isactive= 0; 00546 pars->nullAuthAllowed= nullAuthAllowed; 00547 00548 if ( pthread_create( &threadId, NULL, (void *) &daemon_serviceloop, (void *) pars) ) 00549 { 00550 SOCK_ASSERT("Error creating the child thread", 1); 00551 continue; 00552 } 00553 00554 #else 00555 if ( (pid= fork() ) == 0) // I am the child 00556 { 00557 // in case of passive mode, this variable is deallocated by the daemon_serviceloop() 00558 pars= (struct daemon_slpars *) malloc ( sizeof(struct daemon_slpars) ); 00559 if (pars == NULL) 00560 { 00561 snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno)); 00562 exit(0); 00563 } 00564 00565 pars->sockctrl= sockctrl; 00566 pars->activeclose= 0; // useless in passive mode 00567 pars->isactive= 0; 00568 pars->nullAuthAllowed= nullAuthAllowed; 00569 00570 // Close the main socket (must be open only in the parent) 00571 closesocket(sockmain); 00572 00573 daemon_serviceloop( (void *) pars); 00574 exit(0); 00575 } 00576 00577 // I am the parent 00578 // Close the childsocket (must be open only in the child) 00579 closesocket(sockctrl); 00580 #endif 00581 00582 // loop forever, until interrupted 00583 } 00584 } 00585 00586 00587 00588 00596 void main_active(void *ptr) 00597 { 00598 char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed 00599 SOCKET sockctrl; // keeps the socket ID for this control connection 00600 struct addrinfo hints; // temporary struct to keep settings needed to open the new socket 00601 struct addrinfo *addrinfo; // keeps the addrinfo chain; required to open a new socket 00602 struct active_pars *activepars; 00603 struct daemon_slpars *pars; // parameters needed by the daemon_serviceloop() 00604 00605 00606 activepars= (struct active_pars *) ptr; 00607 00608 // Prepare to open a new server socket 00609 memset(&hints, 0, sizeof(struct addrinfo)); 00610 // WARNING Currently it supports only ONE socket family among IPv4 and IPv6 00611 hints.ai_family = AF_INET; // PF_UNSPEC to have both IPv4 and IPv6 server 00612 hints.ai_socktype = SOCK_STREAM; 00613 hints.ai_family= activepars->ai_family; 00614 00615 snprintf(errbuf, PCAP_ERRBUF_SIZE, "Connecting to host %s, port %s, using protocol %s", 00616 activepars->address, activepars->port, (hints.ai_family == AF_INET) ? "IPv4": "IPv6" ); 00617 SOCK_ASSERT(errbuf, 1); 00618 00619 // Initialize errbuf 00620 memset(errbuf, 0, sizeof(errbuf) ); 00621 00622 // Do the work 00623 if (sock_validaddr(activepars->address, activepars->port, &hints, &addrinfo, errbuf) == -1) 00624 { 00625 SOCK_ASSERT(errbuf, 1); 00626 return; 00627 } 00628 00629 while (1) 00630 { 00631 int activeclose; 00632 00633 if ( (sockctrl= sock_open(addrinfo, SOCKOPEN_CLIENT, 0, errbuf)) == -1) 00634 { 00635 SOCK_ASSERT(errbuf, 1); 00636 snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error connecting to host %s, port %s, using protocol %s", 00637 activepars->address, activepars->port, (hints.ai_family == AF_INET) ? "IPv4": "IPv6" ); 00638 SOCK_ASSERT(errbuf, 1); 00639 pthread_suspend(RPCAP_ACTIVE_WAIT * 1000); 00640 continue; 00641 } 00642 00643 pars= (struct daemon_slpars *) malloc ( sizeof(struct daemon_slpars) ); 00644 if (pars == NULL) 00645 { 00646 snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno)); 00647 continue; 00648 } 00649 00650 pars->sockctrl= sockctrl; 00651 pars->activeclose= 0; 00652 pars->isactive= 1; 00653 pars->nullAuthAllowed= nullAuthAllowed; 00654 00655 daemon_serviceloop( (void *) pars); 00656 00657 activeclose= pars->activeclose; 00658 00659 free(pars); 00660 // If the connection is closed by the user explicitely, don't try to connect to it again 00661 // just exit the program 00662 if (activeclose == 1) 00663 break; 00664 } 00665 } 00666
documentation. Copyright (c) 2002-2003 Politecnico di Torino. All rights reserved.