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