]> The Tcpdump Group git mirrors - libpcap/blob - rpcapd/rpcapd.c
d35940819a88bcbcf97fb2f357f6a61861aa6a23
[libpcap] / rpcapd / rpcapd.c
1 /*
2 * Copyright (c) 2002 - 2003
3 * NetGroup, Politecnico di Torino (Italy)
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the Politecnico di Torino nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 *
31 */
32
33 #ifdef HAVE_CONFIG_H
34 #include <config.h>
35 #endif
36
37 #include "ftmacros.h"
38
39 #include <errno.h> // for the errno variable
40 #include <string.h> // for strtok, etc
41 #include <stdlib.h> // for malloc(), free(), ...
42 #include <pcap.h> // for PCAP_ERRBUF_SIZE
43 #include <signal.h> // for signal()
44
45 #include "fmtutils.h"
46 #include "sockutils.h" // for socket calls
47 #include "portability.h"
48 #include "rpcapd.h"
49 #include "fileconf.h" // for the configuration file management
50 #include "rpcap-protocol.h"
51 #include "daemon.h" // the true main() method of this daemon
52 #include "log.h"
53
54 #ifdef _WIN32
55 #include <process.h> // for thread stuff
56 #include "win32-svc.h" // for Win32 service stuff
57 #include "getopt.h" // for getopt()-for-Windows
58 #else
59 #include <unistd.h> // for exit()
60 #include <sys/wait.h> // waitpid()
61 #endif
62
63
64 // Global variables
65 char hostlist[MAX_HOST_LIST + 1]; //!< Keeps the list of the hosts that are allowed to connect to this server
66 struct active_pars activelist[MAX_ACTIVE_LIST]; //!< Keeps the list of the hosts (host, port) on which I want to connect to (active mode)
67 int nullAuthAllowed; //!< '1' if we permit NULL authentication, '0' otherwise
68 static SOCKET sockmain; //!< keeps the main socket identifier
69 char loadfile[MAX_LINE + 1]; //!< Name of the file from which we have to load the configuration
70 int passivemode = 1; //!< '1' if we want to run in passive mode as well
71 struct addrinfo mainhints; //!< temporary struct to keep settings needed to open the new socket
72 char address[MAX_LINE + 1]; //!< keeps the network address (either numeric or literal) to bind to
73 char port[MAX_LINE + 1]; //!< keeps the network port to bind to
74
75 extern char *optarg; // for getopt()
76
77 // Function definition
78 #ifdef _WIN32
79 static unsigned __stdcall main_passive(void *ptr);
80 static unsigned __stdcall main_active(void *ptr);
81 #else
82 static void *main_passive(void *ptr);
83 static void *main_active(void *ptr);
84 #endif
85
86 static void main_terminate(int sign);
87 #ifdef _WIN32
88 static void main_abort(int sign);
89 #else
90 static void main_reap_children(int sign);
91 #endif
92
93 #define RPCAP_ACTIVE_WAIT 30 /* Waiting time between two attempts to open a connection, in active mode (default: 30 sec) */
94
95 /*!
96 \brief Prints the usage screen if it is launched in console mode.
97 */
98 static void printusage(void)
99 {
100 char *usagetext =
101 "USAGE:"
102 " " PROGRAM_NAME " [-b <address>] [-p <port>] [-4] [-l <host_list>] [-a <host,port>]\n"
103 " [-n] [-v] [-d] [-s <file>] [-f <file>]\n\n"
104 " -b <address> the address to bind to (either numeric or literal).\n"
105 " Default: binds to all local IPv4 and IPv6 addresses\n\n"
106 " -p <port> the port to bind to.\n"
107 " Default: binds to port " RPCAP_DEFAULT_NETPORT "\n\n"
108 " -4 use only IPv4.\n"
109 " Default: use both IPv4 and IPv6 waiting sockets\n\n"
110 " -l <host_list> a file that contains a list of hosts that are allowed\n"
111 " to connect to this server (if more than one, list them one per line).\n"
112 " We suggest to use literal names (instead of numeric ones) in\n"
113 " order to avoid problems with different address families.\n\n"
114 " -n permit NULL authentication (usually used with '-l')\n\n"
115 " -a <host,port> run in active mode when connecting to 'host' on port 'port'\n"
116 " In case 'port' is omitted, the default port (" RPCAP_DEFAULT_NETPORT_ACTIVE ") is used\n\n"
117 " -v run in active mode only (default: if '-a' is specified, it accepts\n"
118 " passive connections as well\n\n"
119 " -d run in daemon mode (UNIX only) or as a service (Win32 only)\n"
120 " Warning (Win32): this switch is provided automatically when the service\n"
121 " is started from the control panel\n\n"
122 " -s <file> save the current configuration to file\n\n"
123 " -f <file> load the current configuration from file; all switches\n"
124 " specified from the command line are ignored\n\n"
125 " -h print this help screen\n\n";
126
127 (void)fprintf(stderr, "RPCAPD, a remote packet capture daemon.\n"
128 "Compiled with %s\n\n", pcap_lib_version());
129 printf("%s", usagetext);
130 }
131
132
133
134 //! Program main
135 int main(int argc, char *argv[], char *envp[])
136 {
137 char savefile[MAX_LINE + 1]; // name of the file on which we have to save the configuration
138 int isdaemon = 0; // Not null if the user wants to run this program as a daemon
139 int retval; // keeps the returning value from several functions
140 char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed
141
142 savefile[0] = 0;
143 loadfile[0] = 0;
144 hostlist[0] = 0;
145
146 // Initialize errbuf
147 memset(errbuf, 0, sizeof(errbuf));
148
149 if (sock_init(errbuf, PCAP_ERRBUF_SIZE) == -1)
150 {
151 SOCK_ASSERT(errbuf, 1);
152 exit(-1);
153 }
154
155 strncpy(address, RPCAP_DEFAULT_NETADDR, MAX_LINE);
156 strncpy(port, RPCAP_DEFAULT_NETPORT, MAX_LINE);
157
158 // Prepare to open a new server socket
159 memset(&mainhints, 0, sizeof(struct addrinfo));
160
161 mainhints.ai_family = PF_UNSPEC;
162 mainhints.ai_flags = AI_PASSIVE; // Ready to a bind() socket
163 mainhints.ai_socktype = SOCK_STREAM;
164
165 // Getting the proper command line options
166 while ((retval = getopt(argc, argv, "b:dhp:4l:na:s:f:v")) != -1)
167 {
168 switch (retval)
169 {
170 case 'b':
171 strncpy(address, optarg, MAX_LINE);
172 break;
173 case 'p':
174 strncpy(port, optarg, MAX_LINE);
175 break;
176 case '4':
177 mainhints.ai_family = PF_INET; // IPv4 server only
178 break;
179 case 'd':
180 isdaemon = 1;
181 break;
182 case 'n':
183 nullAuthAllowed = 1;
184 break;
185 case 'v':
186 passivemode = 0;
187 break;
188 case 'l':
189 {
190 strncpy(hostlist, optarg, sizeof(hostlist));
191 break;
192 }
193 case 'a':
194 {
195 char *tmpaddress, *tmpport;
196 char *lasts;
197 int i = 0;
198
199 tmpaddress = pcap_strtok_r(optarg, RPCAP_HOSTLIST_SEP, &lasts);
200
201 while ((tmpaddress != NULL) && (i < MAX_ACTIVE_LIST))
202 {
203 tmpport = pcap_strtok_r(NULL, RPCAP_HOSTLIST_SEP, &lasts);
204
205 strlcpy(activelist[i].address, tmpaddress, MAX_LINE);
206
207 if ((tmpport == NULL) || (strcmp(tmpport, "DEFAULT") == 0)) // the user choose a custom port
208 strlcpy(activelist[i].port, RPCAP_DEFAULT_NETPORT_ACTIVE, MAX_LINE);
209 else
210 strlcpy(activelist[i].port, tmpport, MAX_LINE);
211
212 tmpaddress = pcap_strtok_r(NULL, RPCAP_HOSTLIST_SEP, &lasts);
213
214 i++;
215 }
216
217 if (i > MAX_ACTIVE_LIST)
218 SOCK_ASSERT("Only MAX_ACTIVE_LIST active connections are currently supported.", 1);
219
220 // I don't initialize the remaining part of the structure, since
221 // it is already zeroed (it is a global var)
222 break;
223 }
224 case 'f':
225 strlcpy(loadfile, optarg, MAX_LINE);
226 break;
227 case 's':
228 strlcpy(savefile, optarg, MAX_LINE);
229 break;
230 case 'h':
231 printusage();
232 exit(0);
233 default:
234 break;
235 }
236 }
237
238 if (savefile[0])
239 {
240 if (fileconf_save(savefile))
241 SOCK_ASSERT("Error when saving the configuration to file", 1);
242 }
243
244 // If the file does not exist, it keeps the settings provided by the command line
245 if (loadfile[0])
246 fileconf_read(0);
247
248 #ifndef _WIN32
249 // SIGTERM (i.e. kill -15) is not generated in Win32, although it is included for ANSI compatibility
250 signal(SIGTERM, main_terminate);
251 signal(SIGCHLD, main_reap_children);
252 // Ignore SIGPIPE - we'll get EPIPE when trying to write to a closed
253 // connection, we don't want to get killed by a signal in that case
254 signal(SIGPIPE, SIG_IGN);
255 #endif
256
257 // forking a daemon, if it is needed
258 if (isdaemon)
259 {
260 #ifndef _WIN32
261 int pid;
262
263 // Unix Network Programming, pg 336
264 if ((pid = fork()) != 0)
265 exit(0); // Parent terminates
266
267 // First child continues
268 // Set daemon mode
269 setsid();
270
271 // generated under unix with 'kill -HUP', needed to reload the configuration
272 signal(SIGHUP, fileconf_read);
273
274 if ((pid = fork()) != 0)
275 exit(0); // First child terminates
276
277 // LINUX WARNING: the current linux implementation of pthreads requires a management thread
278 // to handle some hidden stuff. So, as soon as you create the first thread, two threads are
279 // created. Fom this point on, the number of threads active are always one more compared
280 // to the number you're expecting
281
282 // Second child continues
283 // umask(0);
284 // chdir("/");
285 #else
286 // We use the SIGABRT signal to kill the Win32 service
287 signal(SIGABRT, main_abort);
288
289 // If this call succeeds, it is blocking on Win32
290 if (svc_start() != 1)
291 SOCK_ASSERT("Unable to start the service", 1);
292
293 // When the previous call returns, the entire application has to be stopped.
294 exit(0);
295 #endif
296 }
297 else // Console mode
298 {
299 // Enable the catching of Ctrl+C
300 signal(SIGINT, main_terminate);
301
302 #ifndef _WIN32
303 // generated under unix with 'kill -HUP', needed to reload the configuration
304 // We do not have this kind of signal in Win32
305 signal(SIGHUP, fileconf_read);
306 #endif
307
308 printf("Press CTRL + C to stop the server...\n");
309 }
310
311 // If we're a Win32 service, we have already called this function in the service_main
312 main_startup();
313
314 // The code should never arrive here (since the main_startup is blocking)
315 // however this avoids a compiler warning
316 exit(0);
317 }
318
319 void main_startup(void)
320 {
321 char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed
322 struct addrinfo *addrinfo; // keeps the addrinfo chain; required to open a new socket
323 int i;
324 #ifdef _WIN32
325 HANDLE threadId; // handle for the subthread
326 #else
327 pid_t pid;
328 #endif
329
330 i = 0;
331 addrinfo = NULL;
332 memset(errbuf, 0, sizeof(errbuf));
333
334 // Starts all the active threads
335 while ((i < MAX_ACTIVE_LIST) && (activelist[i].address[0] != 0))
336 {
337 activelist[i].ai_family = mainhints.ai_family;
338
339 #ifdef _WIN32
340 threadId = (HANDLE)_beginthreadex(NULL, 0, main_active,
341 (void *)&activelist[i], 0, NULL);
342 if (threadId == 0)
343 {
344 SOCK_ASSERT("Error creating the active child threads", 1);
345 continue;
346 }
347 CloseHandle(threadId);
348 #else
349 if ((pid = fork()) == 0) // I am the child
350 {
351 main_active((void *) &activelist[i]);
352 exit(0);
353 }
354 #endif
355 i++;
356 }
357
358 /*
359 * The code that manages the active connections is not blocking;
360 * the code that manages the passive connection is blocking.
361 * So, if the user does not want to run in passive mode, we have
362 * to block the main thread here, otherwise the program ends and
363 * all threads are stopped.
364 *
365 * WARNING: this means that in case we have only active mode,
366 * the program does not terminate even if all the child thread
367 * terminates. The user has always to press Ctrl+C (or send a
368 * SIGTERM) to terminate the program.
369 */
370 if (passivemode)
371 {
372 struct addrinfo *tempaddrinfo;
373
374 // Do the work
375 if (sock_initaddress((address[0]) ? address : NULL, port, &mainhints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1)
376 {
377 SOCK_ASSERT(errbuf, 1);
378 return;
379 }
380
381 tempaddrinfo = addrinfo;
382
383 while (tempaddrinfo)
384 {
385 SOCKET *socktemp;
386
387 if ((sockmain = sock_open(tempaddrinfo, SOCKOPEN_SERVER, SOCKET_MAXCONN, errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET)
388 {
389 SOCK_ASSERT(errbuf, 1);
390 tempaddrinfo = tempaddrinfo->ai_next;
391 continue;
392 }
393
394 //
395 // This trick is needed in order to allow the child
396 // thread to save the 'sockmain' variable without
397 // getting it overwritten by the sock_open, in case
398 // we want to open more than one waiting socket.
399 //
400 // For instance, the rpcapd_thread_create() will
401 // accept the socktemp variable, and it will
402 // immediately deallocate that variable.
403 //
404 // XXX - this shouldn't be necessary if we're
405 // using subprocesses rather than threads, as
406 // the use and overwrite would be done in
407 // separate processes; we should be able to
408 // pass a pointer to sockmain in the child
409 // process.
410 //
411 socktemp = (SOCKET *) malloc (sizeof (SOCKET));
412 if (socktemp == NULL)
413 exit(0);
414
415 *socktemp = sockmain;
416
417 #ifdef _WIN32
418 threadId = (HANDLE)_beginthreadex(NULL, 0, main_passive,
419 (void *) socktemp, 0, NULL);
420 if (threadId == 0)
421 {
422 SOCK_ASSERT("Error creating the passive child thread", 1);
423 free(socktemp);
424 continue;
425 }
426 CloseHandle(threadId);
427 #else
428 if ((pid = fork()) == 0) // I am the child
429 {
430 freeaddrinfo(addrinfo);
431 main_passive((void *) socktemp);
432 return;
433 }
434 free(socktemp);
435 #endif
436 tempaddrinfo = tempaddrinfo->ai_next;
437 }
438
439 freeaddrinfo(addrinfo);
440 }
441
442 // All the previous calls are no blocking, so the main line of execution goes here
443 // and I have to avoid that the program terminates
444 for (;;)
445 {
446 #ifdef _WIN32
447 Sleep(INFINITE);
448 #else
449 pause();
450 #endif
451 }
452 }
453
454
455 /*
456 \brief Closes gracefully (more or less) the program.
457
458 This function is called:
459 - when we're running in console and are terminated with ^C;
460 - on UN*X, when we're terminated with SIGTERM.
461 */
462 static void main_terminate(int sign)
463 {
464 SOCK_ASSERT(PROGRAM_NAME " is closing.\n", 1);
465
466 #ifndef _WIN32
467 //
468 // Sends a KILL signal to all the processes in this process's
469 // process group; i.e., it kills all the child processes
470 // we've created.
471 //
472 // XXX - that also includes us, so we will be killed as well;
473 // that may cause a message to be printed or logged.
474 //
475 kill(0, SIGKILL);
476 #endif
477
478 //
479 // Just leave. We shouldn't need to clean up sockets or
480 // anything else, and if we try to do so, we'll could end
481 // up closing sockets, or shutting Winsock down, out from
482 // under service loops, causing all sorts of noisy error
483 // messages.
484 //
485 // We shouldn't need to worry about cleaning up any resources
486 // such as handles, sockets, threads, etc. - exit() should
487 // terminate the process, causing all those resources to be
488 // cleaned up.
489 //
490 // Note that, on Windows, this will happen only for ^C, and
491 // thus will happen on a thread created to run the ^C handler,
492 // which is how it manages to cause the aforementioned service
493 // loop issues in service loops in other threads.
494 //
495 exit(0);
496 }
497
498 #ifdef _WIN32
499 static void main_abort(int sign)
500 {
501 SOCK_ASSERT(PROGRAM_NAME " is closing due to a SIGABRT.\n", 1);
502
503 //
504 // XXX - there should be a way to poke the main thread to get
505 // it to shut down the service.
506 //
507
508 // FULVIO (bug)
509 // Here we close only the latest 'sockmain' created; if we opened more than one waiting sockets,
510 // only the latest one is closed correctly.
511 if (sockmain)
512 closesocket(sockmain);
513 sock_cleanup();
514
515 /*
516 * This is a Win32 service, so we're a child thread, and we want
517 * just to terminate ourself. This is because the exit(0) will
518 * be invoked by the main thread, which is blocked waiting that
519 * all childs terminates. We are forced to call exit from the
520 * main thread, otherwise the Win32 service control manager
521 * (SCM) does not work well.
522 */
523 }
524 #endif
525
526 #ifndef _WIN32
527 static void main_reap_children(int sign)
528 {
529 pid_t pid;
530 int exitstat;
531
532 // Reap all child processes that have exited.
533 // For reference, Stevens, pg 128
534
535 while ((pid = waitpid(-1, &exitstat, WNOHANG)) > 0)
536 SOCK_ASSERT("Child terminated", 1);
537
538 return;
539 }
540 #endif
541
542 /*!
543 \brief 'true' main of the program.
544
545 It must be in a separate function because:
546 - if we're in 'console' mode, we have to put the main thread waiting for a Ctrl+C
547 (in order to be able to stop everything)
548 - if we're in daemon mode, the main program must terminate and a new child must be
549 created in order to create the daemon
550
551 \param ptr: it keeps the main socket handler (what's called
552 'sockmain' in the main()), that represents the socket used in
553 the main connection. It is a 'void *' just because the thread
554 APIs want this format.
555 */
556 #ifdef _WIN32
557 static unsigned __stdcall
558 #else
559 static void *
560 #endif
561 main_passive(void *ptr)
562 {
563 char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed
564 SOCKET sockctrl; // keeps the socket ID for this control connection
565 struct sockaddr_storage from; // generic sockaddr_storage variable
566 socklen_t fromlen; // keeps the length of the sockaddr_storage variable
567 SOCKET sockmain;
568
569 #ifndef _WIN32
570 pid_t pid;
571 #endif
572
573 sockmain = *((SOCKET *) ptr);
574
575 // Delete the pointer (which has been allocated in the main)
576 free(ptr);
577
578 // Initialize errbuf
579 memset(errbuf, 0, sizeof(errbuf));
580
581 // main thread loop
582 for (;;)
583 {
584 #ifdef _WIN32
585 HANDLE threadId; // handle for the subthread
586 #endif
587 struct daemon_slpars *pars; // parameters needed by the daemon_serviceloop()
588
589 // Connection creation
590 fromlen = sizeof(struct sockaddr_storage);
591
592 sockctrl = accept(sockmain, (struct sockaddr *) &from, &fromlen);
593
594 if (sockctrl == INVALID_SOCKET)
595 {
596 // The accept() call can return this error when a signal is catched
597 // In this case, we have simply to ignore this error code
598 // Stevens, pg 124
599 #ifdef _WIN32
600 if (WSAGetLastError() == WSAEINTR)
601 #else
602 if (errno == EINTR)
603 #endif
604 continue;
605
606 // Don't check for errors here, since the error can be due to the fact that the thread
607 // has been killed
608 sock_geterror("accept(): ", errbuf, PCAP_ERRBUF_SIZE);
609 rpcapd_log(LOGPRIO_ERROR, "Accept of control connection from client failed: %s",
610 errbuf);
611 continue;
612 }
613
614 // checks if the connecting host is among the ones allowed
615 if (sock_check_hostlist(hostlist, RPCAP_HOSTLIST_SEP, &from, errbuf, PCAP_ERRBUF_SIZE) < 0)
616 {
617 rpcap_senderror(sockctrl, 0, PCAP_ERR_HOSTNOAUTH, errbuf, NULL);
618 sock_close(sockctrl, NULL, 0);
619 continue;
620 }
621
622
623 #ifdef _WIN32
624 // in case of passive mode, this variable is deallocated by the daemon_serviceloop()
625 pars = (struct daemon_slpars *) malloc (sizeof(struct daemon_slpars));
626 if (pars == NULL)
627 {
628 pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
629 errno, "malloc() failed");
630 rpcap_senderror(sockctrl, 0, PCAP_ERR_OPEN, errbuf, NULL);
631 sock_close(sockctrl, NULL, 0);
632 continue;
633 }
634
635 pars->sockctrl = sockctrl;
636 pars->activeclose = 0; // useless in passive mode
637 pars->isactive = 0;
638 pars->nullAuthAllowed = nullAuthAllowed;
639
640 threadId = (HANDLE)_beginthreadex(NULL, 0, daemon_serviceloop,
641 (void *) pars, 0, NULL);
642 if (threadId == 0)
643 {
644 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error creating the child thread");
645 rpcap_senderror(sockctrl, 0, PCAP_ERR_OPEN, errbuf, NULL);
646 sock_close(sockctrl, NULL, 0);
647 continue;
648 }
649 CloseHandle(threadId);
650 #else
651 if ((pid = fork()) == 0) // I am the child
652 {
653 // in case of passive mode, this variable is deallocated by the daemon_serviceloop()
654 pars = (struct daemon_slpars *) malloc (sizeof(struct daemon_slpars));
655 if (pars == NULL)
656 {
657 pcap_fmt_errmsg_for_errno(errbuf,
658 PCAP_ERRBUF_SIZE, errno, "malloc() failed");
659 exit(0);
660 }
661
662 pars->sockctrl = sockctrl;
663 pars->activeclose = 0; // useless in passive mode
664 pars->isactive = 0;
665 pars->nullAuthAllowed = nullAuthAllowed;
666
667 // Close the main socket (must be open only in the parent)
668 closesocket(sockmain);
669
670 daemon_serviceloop((void *) pars);
671 exit(0);
672 }
673
674 // I am the parent
675 // Close the childsocket (must be open only in the child)
676 closesocket(sockctrl);
677 #endif
678
679 // loop forever, until interrupted
680 }
681 return 0;
682 }
683
684 /*!
685 \brief 'true' main of the program in case the active mode is turned on.
686
687 This function loops forever trying to connect to the remote host, until the
688 daemon is turned down.
689
690 \param ptr: it keeps the 'activepars' parameters. It is a 'void *'
691 just because the thread APIs want this format.
692 */
693 #ifdef _WIN32
694 static unsigned __stdcall
695 #else
696 static void *
697 #endif
698 main_active(void *ptr)
699 {
700 char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed
701 SOCKET sockctrl; // keeps the socket ID for this control connection
702 struct addrinfo hints; // temporary struct to keep settings needed to open the new socket
703 struct addrinfo *addrinfo; // keeps the addrinfo chain; required to open a new socket
704 struct active_pars *activepars;
705 struct daemon_slpars *pars; // parameters needed by the daemon_serviceloop()
706
707 activepars = (struct active_pars *) ptr;
708
709 // Prepare to open a new server socket
710 memset(&hints, 0, sizeof(struct addrinfo));
711 // WARNING Currently it supports only ONE socket family among IPv4 and IPv6
712 hints.ai_family = AF_INET; // PF_UNSPEC to have both IPv4 and IPv6 server
713 hints.ai_socktype = SOCK_STREAM;
714 hints.ai_family = activepars->ai_family;
715
716 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Connecting to host %s, port %s, using protocol %s",
717 activepars->address, activepars->port, (hints.ai_family == AF_INET) ? "IPv4":
718 (hints.ai_family == AF_INET6) ? "IPv6" : "Unspecified");
719 SOCK_ASSERT(errbuf, 1);
720
721 // Initialize errbuf
722 memset(errbuf, 0, sizeof(errbuf));
723
724 // Do the work
725 if (sock_initaddress(activepars->address, activepars->port, &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1)
726 {
727 SOCK_ASSERT(errbuf, 1);
728 return 0;
729 }
730
731 for (;;)
732 {
733 int activeclose;
734
735 if ((sockctrl = sock_open(addrinfo, SOCKOPEN_CLIENT, 0, errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET)
736 {
737 SOCK_ASSERT(errbuf, 1);
738
739 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error connecting to host %s, port %s, using protocol %s",
740 activepars->address, activepars->port, (hints.ai_family == AF_INET) ? "IPv4":
741 (hints.ai_family == AF_INET6) ? "IPv6" : "Unspecified");
742
743 SOCK_ASSERT(errbuf, 1);
744
745 sleep_secs(RPCAP_ACTIVE_WAIT);
746
747 continue;
748 }
749
750 pars = (struct daemon_slpars *) malloc (sizeof(struct daemon_slpars));
751 if (pars == NULL)
752 {
753 pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
754 errno, "malloc() failed");
755 continue;
756 }
757
758 pars->sockctrl = sockctrl;
759 pars->activeclose = 0;
760 pars->isactive = 1;
761 pars->nullAuthAllowed = nullAuthAllowed;
762
763 daemon_serviceloop((void *) pars);
764
765 activeclose = pars->activeclose;
766
767 free(pars);
768
769 // If the connection is closed by the user explicitely, don't try to connect to it again
770 // just exit the program
771 if (activeclose == 1)
772 break;
773 }
774
775 freeaddrinfo(addrinfo);
776 return 0;
777 }