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 #include <config.h>
34
35 #include "ftmacros.h"
36 #include "diag-control.h"
37
38 #include <errno.h> // for the errno variable
39 #include <string.h> // for strtok, etc
40 #include <stdlib.h> // for malloc(), free(), ...
41 #include <stdio.h> // for fprintf(), stderr, FILE etc
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 "varattrs.h" // for _U_
48 #include "portability.h"
49 #include "rpcapd.h"
50 #include "config_params.h" // configuration file parameters
51 #include "fileconf.h" // for the configuration file management
52 #include "rpcap-protocol.h"
53 #include "daemon.h" // the true main() method of this daemon
54 #include "log.h"
55
56 #ifdef HAVE_OPENSSL
57 #include "sslutils.h"
58 #endif
59
60 #ifdef _WIN32
61 #include <process.h> // for thread stuff
62 #include "win32-svc.h" // for Win32 service stuff
63 #include "getopt.h" // for getopt()-for-Windows
64 #else
65 #include <fcntl.h> // for open()
66 #include <unistd.h> // for exit()
67 #include <sys/wait.h> // waitpid()
68 #endif
69
70 //
71 // Element in list of sockets on which we're listening for connections.
72 //
73 struct listen_sock {
74 struct listen_sock *next;
75 PCAP_SOCKET sock;
76 };
77
78 // Global variables
79 char hostlist[MAX_HOST_LIST + 1]; //!< Keeps the list of the hosts that are allowed to connect to this server
80 struct active_pars activelist[MAX_ACTIVE_LIST]; //!< Keeps the list of the hosts (host, port) on which I want to connect to (active mode)
81 int nullAuthAllowed; //!< '1' if we permit NULL authentication, '0' otherwise
82 static struct listen_sock *listen_socks; //!< sockets on which we listen
83 char loadfile[MAX_LINE + 1]; //!< Name of the file from which we have to load the configuration
84 static int passivemode = 1; //!< '1' if we want to run in passive mode as well
85 static struct addrinfo mainhints; //!< temporary struct to keep settings needed to open the new socket
86 static char address[MAX_LINE + 1]; //!< keeps the network address (either numeric or literal) to bind to
87 static char port[MAX_LINE + 1]; //!< keeps the network port to bind to
88 #ifdef _WIN32
89 static HANDLE state_change_event; //!< event to signal that a state change should take place
90 static volatile long shutdown_server; //!< '1' if the server is to shut down
91 static volatile long reread_config; //!< '1' if the server is to re-read its configuration
92 #else
93 static volatile sig_atomic_t shutdown_server; //!< '1' if the server is to shut down
94 static volatile sig_atomic_t reread_config; //!< '1' if the server is to re-read its configuration
95 #endif
96 static int uses_ssl; //!< '1' to use TLS over TCP
97
98 extern char *optarg; // for getopt()
99
100 // Function definition
101 #ifdef _WIN32
102 static unsigned __stdcall main_active(void *ptr);
103 static BOOL WINAPI main_ctrl_event(DWORD);
104 #else
105 static void *main_active(void *ptr);
106 static void main_terminate(int sign);
107 static void main_reread_config(int sign);
108 #endif
109 static void accept_connections(void);
110 static void accept_connection(PCAP_SOCKET listen_sock);
111 #ifndef _WIN32
112 static void main_reap_children(int sign);
113 #endif
114 #ifdef _WIN32
115 static unsigned __stdcall main_passive_serviceloop_thread(void *ptr);
116 #endif
117
118 #define RPCAP_ACTIVE_WAIT 30 /* Waiting time between two attempts to open a connection, in active mode (default: 30 sec) */
119
120 /*!
121 \brief Prints the usage screen if it is launched in console mode.
122 */
printusage(FILE * f)123 static void printusage(FILE * f)
124 {
125 const char *usagetext =
126 "USAGE:"
127 " " PROGRAM_NAME " [-b <address>] [-p <port>] [-4] [-l <host_list>] [-a <host,port>]\n"
128 " [-n] [-v] [-d] "
129 #ifndef _WIN32
130 "[-i] "
131 #endif
132 "[-D] [-s <config_file>] [-f <config_file>]\n\n"
133 " -b <address> the address to bind to (either numeric or literal).\n"
134 " Default: binds to all local IPv4 and IPv6 addresses\n\n"
135 " -p <port> the port to bind to.\n"
136 " Default: binds to port " RPCAP_DEFAULT_NETPORT "\n\n"
137 " -4 use only IPv4.\n"
138 " Default: use both IPv4 and IPv6 waiting sockets\n\n"
139 " -l <host_list> a file that contains a list of hosts that are allowed\n"
140 " to connect to this server (if more than one, list them one\n"
141 " per line).\n"
142 " We suggest to use literal names (instead of numeric ones)\n"
143 " in order to avoid problems with different address families.\n\n"
144 " -n permit NULL authentication (usually used with '-l')\n\n"
145 " -a <host,port> run in active mode when connecting to 'host' on port 'port'\n"
146 " In case 'port' is omitted, the default port (" RPCAP_DEFAULT_NETPORT_ACTIVE ") is used\n\n"
147 " -v run in active mode only (default: if '-a' is specified, it\n"
148 " accepts passive connections as well)\n\n"
149 " -d run in daemon mode (UNIX only) or as a service (Win32 only)\n"
150 " Warning (Win32): this switch is provided automatically when\n"
151 " the service is started from the control panel\n\n"
152 #ifndef _WIN32
153 " -i run in inetd mode (UNIX only)\n\n"
154 #endif
155 " -D log debugging messages\n\n"
156 #ifdef HAVE_OPENSSL
157 " -S encrypt all communication with SSL (implements rpcaps://)\n"
158 " -C enable compression\n"
159 " -K <pem_file> uses the SSL private key in this file (default: key.pem)\n"
160 " -X <pem_file> uses the certificate from this file (default: cert.pem)\n"
161 #endif
162 " -s <config_file> save the current configuration to file\n\n"
163 " -f <config_file> load the current configuration from file; all switches\n"
164 " specified from the command line are ignored\n\n"
165 " -h print this help screen\n\n";
166
167 (void)fprintf(f, "RPCAPD, a remote packet capture daemon.\n"
168 "Compiled with %s\n", pcap_lib_version());
169 #if defined(HAVE_OPENSSL) && defined(SSLEAY_VERSION)
170 (void)fprintf(f, "Compiled with %s\n", SSLeay_version(SSLEAY_VERSION));
171 #endif
172 (void)fprintf(f, "\n%s", usagetext);
173 }
174
175
176
177 //! Program main
main(int argc,char * argv[])178 int main(int argc, char *argv[])
179 {
180 char savefile[MAX_LINE + 1]; // name of the file on which we have to save the configuration
181 int log_to_systemlog = 0; // Non-zero if we should log to the "system log" rather than the standard error
182 int isdaemon = 0; // Non-zero if the user wants to run this program as a daemon
183 #ifndef _WIN32
184 int isrunbyinetd = 0; // Non-zero if this is being run by inetd or something inetd-like
185 #endif
186 int log_debug_messages = 0; // Non-zero if the user wants debug messages logged
187 int retval; // keeps the returning value from several functions
188 char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed
189 #ifndef _WIN32
190 struct sigaction action;
191 #endif
192 #ifdef HAVE_OPENSSL
193 int enable_compression = 0;
194 #endif
195
196 savefile[0] = 0;
197 loadfile[0] = 0;
198 hostlist[0] = 0;
199
200 // Initialize errbuf
201 memset(errbuf, 0, sizeof(errbuf));
202
203 pcapint_strlcpy(address, RPCAP_DEFAULT_NETADDR, sizeof (address));
204 pcapint_strlcpy(port, RPCAP_DEFAULT_NETPORT, sizeof (port));
205
206 // Prepare to open a new server socket
207 memset(&mainhints, 0, sizeof(struct addrinfo));
208
209 mainhints.ai_family = PF_UNSPEC;
210 mainhints.ai_flags = AI_PASSIVE; // Ready to a bind() socket
211 mainhints.ai_socktype = SOCK_STREAM;
212
213 // Getting the proper command line options
214 # ifdef HAVE_OPENSSL
215 # define SSL_CLOPTS "SK:X:C"
216 # else
217 # define SSL_CLOPTS ""
218 # endif
219
220 # define CLOPTS "b:dDhip:4l:na:s:f:v" SSL_CLOPTS
221
222 while ((retval = getopt(argc, argv, CLOPTS)) != -1)
223 {
224 switch (retval)
225 {
226 case 'D':
227 log_debug_messages = 1;
228 rpcapd_log_set(log_to_systemlog, log_debug_messages);
229 break;
230 case 'b':
231 pcapint_strlcpy(address, optarg, sizeof (address));
232 break;
233 case 'p':
234 pcapint_strlcpy(port, optarg, sizeof (port));
235 break;
236 case '4':
237 mainhints.ai_family = PF_INET; // IPv4 server only
238 break;
239 case 'd':
240 isdaemon = 1;
241 log_to_systemlog = 1;
242 rpcapd_log_set(log_to_systemlog, log_debug_messages);
243 break;
244 case 'i':
245 #ifdef _WIN32
246 printusage(stderr);
247 exit(1);
248 #else
249 isrunbyinetd = 1;
250 log_to_systemlog = 1;
251 rpcapd_log_set(log_to_systemlog, log_debug_messages);
252 #endif
253 break;
254 case 'n':
255 nullAuthAllowed = 1;
256 break;
257 case 'v':
258 passivemode = 0;
259 break;
260 case 'l':
261 {
262 pcapint_strlcpy(hostlist, optarg, sizeof(hostlist));
263 break;
264 }
265 case 'a':
266 {
267 char *tmpaddress, *tmpport;
268 char *lasts;
269 int i = 0;
270
271 tmpaddress = pcapint_strtok_r(optarg, RPCAP_HOSTLIST_SEP, &lasts);
272
273 while ((tmpaddress != NULL) && (i < MAX_ACTIVE_LIST))
274 {
275 tmpport = pcapint_strtok_r(NULL, RPCAP_HOSTLIST_SEP, &lasts);
276
277 pcapint_strlcpy(activelist[i].address, tmpaddress, sizeof (activelist[i].address));
278
279 if ((tmpport == NULL) || (strcmp(tmpport, "DEFAULT") == 0)) // the user choose a custom port
280 pcapint_strlcpy(activelist[i].port, RPCAP_DEFAULT_NETPORT_ACTIVE, sizeof (activelist[i].port));
281 else
282 pcapint_strlcpy(activelist[i].port, tmpport, sizeof (activelist[i].port));
283
284 tmpaddress = pcapint_strtok_r(NULL, RPCAP_HOSTLIST_SEP, &lasts);
285
286 i++;
287 }
288
289 if (i > MAX_ACTIVE_LIST)
290 rpcapd_log(LOGPRIO_ERROR, "Only MAX_ACTIVE_LIST active connections are currently supported.");
291
292 // I don't initialize the remaining part of the structure, since
293 // it is already zeroed (it is a global var)
294 break;
295 }
296 case 'f':
297 pcapint_strlcpy(loadfile, optarg, sizeof (loadfile));
298 break;
299 case 's':
300 pcapint_strlcpy(savefile, optarg, sizeof (savefile));
301 break;
302 #ifdef HAVE_OPENSSL
303 case 'S':
304 uses_ssl = 1;
305 break;
306 case 'C':
307 enable_compression = 1;
308 break;
309 case 'K':
310 ssl_set_keyfile(optarg);
311 break;
312 case 'X':
313 ssl_set_certfile(optarg);
314 break;
315 #endif
316 case 'h':
317 printusage(stdout);
318 exit(0);
319 /*NOTREACHED*/
320 default:
321 exit(1);
322 /*NOTREACHED*/
323 }
324 }
325
326 #ifndef _WIN32
327 if (isdaemon && isrunbyinetd)
328 {
329 rpcapd_log(LOGPRIO_ERROR, "rpcapd: -d and -i can't be used together");
330 exit(1);
331 }
332 #endif
333
334 //
335 // We want UTF-8 error messages.
336 //
337 if (pcap_init(PCAP_CHAR_ENC_UTF_8, errbuf) == -1)
338 {
339 rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
340 exit(-1);
341 }
342 pcapint_fmt_set_encoding(PCAP_CHAR_ENC_UTF_8);
343
344 if (sock_init(errbuf, PCAP_ERRBUF_SIZE) == -1)
345 {
346 rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
347 exit(-1);
348 }
349
350 if (savefile[0] && fileconf_save(savefile))
351 rpcapd_log(LOGPRIO_DEBUG, "Error when saving the configuration to file");
352
353 // If the file does not exist, it keeps the settings provided by the command line
354 if (loadfile[0])
355 fileconf_read();
356
357 #ifdef _WIN32
358 //
359 // Create a handle to signal the main loop to tell it to do
360 // something.
361 //
362 state_change_event = CreateEvent(NULL, FALSE, FALSE, NULL);
363 if (state_change_event == NULL)
364 {
365 sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE,
366 "Can't create state change event");
367 rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
368 exit(2);
369 }
370
371 //
372 // Catch control signals.
373 //
374 if (!SetConsoleCtrlHandler(main_ctrl_event, TRUE))
375 {
376 sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE,
377 "Can't set control handler");
378 rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
379 exit(2);
380 }
381 #else
382 memset(&action, 0, sizeof (action));
383 action.sa_handler = main_terminate;
384 action.sa_flags = 0;
385 sigemptyset(&action.sa_mask);
386 sigaction(SIGTERM, &action, NULL);
387 memset(&action, 0, sizeof (action));
388 action.sa_handler = main_reap_children;
389 action.sa_flags = 0;
390 sigemptyset(&action.sa_mask);
391 sigaction(SIGCHLD, &action, NULL);
392 // Ignore SIGPIPE - we'll get EPIPE when trying to write to a closed
393 // connection, we don't want to get killed by a signal in that case
394 #ifdef __illumos__
395 DIAG_OFF_STRICT_PROTOTYPES
396 #endif /* __illumos__ */
397 signal(SIGPIPE, SIG_IGN);
398 #ifdef __illumos__
399 DIAG_ON_STRICT_PROTOTYPES
400 #endif /* __illumos__ */
401 #endif
402
403 # ifdef HAVE_OPENSSL
404 if (uses_ssl) {
405 if (ssl_init_once(1, enable_compression, errbuf, PCAP_ERRBUF_SIZE) < 0)
406 {
407 rpcapd_log(LOGPRIO_ERROR, "Can't initialize SSL: %s",
408 errbuf);
409 exit(2);
410 }
411 }
412 # endif
413
414 #ifndef _WIN32
415 if (isrunbyinetd)
416 {
417 //
418 // -i was specified, indicating that this is being run
419 // by inetd or something that can run network daemons
420 // as if it were inetd (xinetd, launchd, systemd, etc.).
421 //
422 // We assume that the program that launched us just
423 // duplicated a single socket for the connection
424 // to our standard input, output, and error, so we
425 // can just use the standard input as our control
426 // socket.
427 //
428 int sockctrl;
429 int devnull_fd;
430
431 //
432 // Duplicate the standard input as the control socket.
433 //
434 sockctrl = dup(0);
435 if (sockctrl == -1)
436 {
437 sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE,
438 "Can't dup standard input");
439 rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
440 exit(2);
441 }
442
443 //
444 // Try to set the standard input, output, and error
445 // to /dev/null.
446 //
447 devnull_fd = open("/dev/null", O_RDWR);
448 if (devnull_fd != -1)
449 {
450 //
451 // If this fails, just drive on.
452 //
453 (void)dup2(devnull_fd, 0);
454 (void)dup2(devnull_fd, 1);
455 (void)dup2(devnull_fd, 2);
456 close(devnull_fd);
457 }
458
459 //
460 // Handle this client.
461 // This is passive mode, so we don't care whether we were
462 // told by the client to close.
463 //
464 char *hostlist_copy = strdup(hostlist);
465 if (hostlist_copy == NULL)
466 {
467 rpcapd_log(LOGPRIO_ERROR, "Out of memory copying the host/port list");
468 exit(0);
469 }
470 (void)daemon_serviceloop(sockctrl, 0, hostlist_copy,
471 nullAuthAllowed, uses_ssl);
472
473 //
474 // Nothing more to do.
475 //
476 exit(0);
477 }
478 #endif
479
480 if (isdaemon)
481 {
482 //
483 // This is being run as a daemon.
484 // On UN*X, it might be manually run, or run from an
485 // rc file.
486 //
487 #ifndef _WIN32
488 int pid;
489
490 //
491 // Daemonize ourselves.
492 //
493 // Unix Network Programming, pg 336
494 //
495 if ((pid = fork()) != 0)
496 exit(0); // Parent terminates
497
498 // First child continues
499 // Set daemon mode
500 setsid();
501
502 // generated under unix with 'kill -HUP', needed to reload the configuration
503 memset(&action, 0, sizeof (action));
504 action.sa_handler = main_reread_config;
505 action.sa_flags = 0;
506 sigemptyset(&action.sa_mask);
507 sigaction(SIGHUP, &action, NULL);
508
509 if ((pid = fork()) != 0)
510 exit(0); // First child terminates
511
512 // LINUX WARNING: the current linux implementation of pthreads requires a management thread
513 // to handle some hidden stuff. So, as soon as you create the first thread, two threads are
514 // created. From this point on, the number of threads active are always one more compared
515 // to the number you're expecting
516
517 // Second child continues
518 // umask(0);
519 // chdir("/");
520 #else
521 //
522 // This is being run as a service on Windows.
523 //
524 // If this call succeeds, it is blocking on Win32
525 //
526 if (!svc_start())
527 rpcapd_log(LOGPRIO_DEBUG, "Unable to start the service");
528
529 // When the previous call returns, the entire application has to be stopped.
530 exit(0);
531 #endif
532 }
533 else // Console mode
534 {
535 #ifndef _WIN32
536 // Enable the catching of Ctrl+C
537 memset(&action, 0, sizeof (action));
538 action.sa_handler = main_terminate;
539 action.sa_flags = 0;
540 sigemptyset(&action.sa_mask);
541 sigaction(SIGINT, &action, NULL);
542
543 // generated under unix with 'kill -HUP', needed to reload the configuration
544 // We do not have this kind of signal in Win32
545 memset(&action, 0, sizeof (action));
546 action.sa_handler = main_reread_config;
547 action.sa_flags = 0;
548 sigemptyset(&action.sa_mask);
549 sigaction(SIGHUP, &action, NULL);
550 #endif
551
552 printf("Press CTRL + C to stop the server...\n");
553 }
554
555 // If we're a Win32 service, we have already called this function in the service_main
556 main_startup();
557
558 // The code should never arrive here (since the main_startup is blocking)
559 // however this avoids a compiler warning
560 exit(0);
561 }
562
main_startup(void)563 void main_startup(void)
564 {
565 char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed
566 struct addrinfo *addrinfo; // keeps the addrinfo chain; required to open a new socket
567 int i;
568 #ifdef _WIN32
569 HANDLE threadId; // handle for the subthread
570 #else
571 pid_t pid;
572 #endif
573
574 i = 0;
575 addrinfo = NULL;
576 memset(errbuf, 0, sizeof(errbuf));
577
578 // Starts all the active threads
579 while ((i < MAX_ACTIVE_LIST) && (activelist[i].address[0] != 0))
580 {
581 activelist[i].ai_family = mainhints.ai_family;
582
583 #ifdef _WIN32
584 threadId = (HANDLE)_beginthreadex(NULL, 0, main_active,
585 (void *)&activelist[i], 0, NULL);
586 if (threadId == 0)
587 {
588 rpcapd_log(LOGPRIO_DEBUG, "Error creating the active child threads");
589 continue;
590 }
591 CloseHandle(threadId);
592 #else
593 if ((pid = fork()) == 0) // I am the child
594 {
595 main_active((void *) &activelist[i]);
596 exit(0);
597 }
598 #endif
599 i++;
600 }
601
602 /*
603 * The code that manages the active connections is not blocking;
604 * the code that manages the passive connection is blocking.
605 * So, if the user does not want to run in passive mode, we have
606 * to block the main thread here, otherwise the program ends and
607 * all threads are stopped.
608 *
609 * WARNING: this means that in case we have only active mode,
610 * the program does not terminate even if all the child thread
611 * terminates. The user has always to press Ctrl+C (or send a
612 * SIGTERM) to terminate the program.
613 */
614 if (passivemode)
615 {
616 struct addrinfo *tempaddrinfo;
617
618 //
619 // Get a list of sockets on which to listen.
620 //
621 addrinfo = sock_initaddress((address[0]) ? address : NULL,
622 port, &mainhints, errbuf, PCAP_ERRBUF_SIZE);
623 if (addrinfo == NULL)
624 {
625 rpcapd_log(LOGPRIO_DEBUG, "%s", errbuf);
626 return;
627 }
628
629 for (tempaddrinfo = addrinfo; tempaddrinfo;
630 tempaddrinfo = tempaddrinfo->ai_next)
631 {
632 PCAP_SOCKET sock;
633 struct listen_sock *sock_info;
634
635 if ((sock = sock_open(NULL, tempaddrinfo, SOCKOPEN_SERVER, SOCKET_MAXCONN, errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET)
636 {
637 switch (tempaddrinfo->ai_family)
638 {
639 case AF_INET:
640 {
641 struct sockaddr_in *in;
642 char addrbuf[INET_ADDRSTRLEN];
643
644 in = (struct sockaddr_in *)tempaddrinfo->ai_addr;
645 rpcapd_log(LOGPRIO_WARNING, "Can't listen on socket for %s:%u: %s",
646 inet_ntop(AF_INET, &in->sin_addr,
647 addrbuf, sizeof (addrbuf)),
648 ntohs(in->sin_port),
649 errbuf);
650 break;
651 }
652
653 case AF_INET6:
654 {
655 struct sockaddr_in6 *in6;
656 char addrbuf[INET6_ADDRSTRLEN];
657
658 in6 = (struct sockaddr_in6 *)tempaddrinfo->ai_addr;
659 rpcapd_log(LOGPRIO_WARNING, "Can't listen on socket for %s:%u: %s",
660 inet_ntop(AF_INET6, &in6->sin6_addr,
661 addrbuf, sizeof (addrbuf)),
662 ntohs(in6->sin6_port),
663 errbuf);
664 break;
665 }
666
667 default:
668 rpcapd_log(LOGPRIO_WARNING, "Can't listen on socket for address family %u: %s",
669 tempaddrinfo->ai_family,
670 errbuf);
671 break;
672 }
673 continue;
674 }
675
676 sock_info = (struct listen_sock *) malloc(sizeof (struct listen_sock));
677 if (sock_info == NULL)
678 {
679 rpcapd_log(LOGPRIO_ERROR, "Can't allocate structure for listen socket");
680 exit(2);
681 }
682 sock_info->sock = sock;
683 sock_info->next = listen_socks;
684 listen_socks = sock_info;
685 }
686
687 freeaddrinfo(addrinfo);
688
689 if (listen_socks == NULL)
690 {
691 rpcapd_log(LOGPRIO_ERROR, "Can't listen on any address");
692 exit(2);
693 }
694
695 //
696 // Now listen on all of them, waiting for connections.
697 //
698 accept_connections();
699 }
700
701 //
702 // We're done; exit.
703 //
704 rpcapd_log(LOGPRIO_DEBUG, PROGRAM_NAME " is closing.\n");
705
706 #ifndef _WIN32
707 //
708 // Sends a KILL signal to all the processes in this process's
709 // process group; i.e., it kills all the child processes
710 // we've created.
711 //
712 // XXX - that also includes us, so we will be killed as well;
713 // that may cause a message to be printed or logged.
714 //
715 kill(0, SIGKILL);
716 #endif
717
718 //
719 // Just leave. We shouldn't need to clean up sockets or
720 // anything else, and if we try to do so, we'll could end
721 // up closing sockets, or shutting Winsock down, out from
722 // under service loops, causing all sorts of noisy error
723 // messages.
724 //
725 // We shouldn't need to worry about cleaning up any resources
726 // such as handles, sockets, threads, etc. - exit() should
727 // terminate the process, causing all those resources to be
728 // cleaned up (including the threads; Microsoft claims in the
729 // ExitProcess() documentation that, if ExitProcess() is called,
730 // "If a thread is waiting on a kernel object, it will not be
731 // terminated until the wait has completed.", but claims in the
732 // _beginthread()/_beginthreadex() documentation that "All threads
733 // are terminated if any thread calls abort, exit, _exit, or
734 // ExitProcess." - the latter appears to be the case, even for
735 // threads waiting on the event for a pcap_t).
736 //
737 exit(0);
738 }
739
740 #ifdef _WIN32
741 static void
send_state_change_event(void)742 send_state_change_event(void)
743 {
744 char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed
745
746 if (!SetEvent(state_change_event))
747 {
748 sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE,
749 "SetEvent on shutdown event failed");
750 rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
751 }
752 }
753
754 void
send_shutdown_notification(void)755 send_shutdown_notification(void)
756 {
757 //
758 // Indicate that the server should shut down.
759 //
760 _InterlockedExchange(&shutdown_server, 1);
761
762 //
763 // Send a state change event, to wake up WSAWaitForMultipleEvents().
764 //
765 send_state_change_event();
766 }
767
768 void
send_reread_configuration_notification(void)769 send_reread_configuration_notification(void)
770 {
771 //
772 // Indicate that the server should re-read its configuration file.
773 //
774 _InterlockedExchange(&reread_config, 1);
775
776 //
777 // Send a state change event, to wake up WSAWaitForMultipleEvents().
778 //
779 send_state_change_event();
780 }
781
main_ctrl_event(DWORD ctrltype)782 static BOOL WINAPI main_ctrl_event(DWORD ctrltype)
783 {
784 //
785 // ctrltype is one of:
786 //
787 // CTRL_C_EVENT - we got a ^C; this is like SIGINT
788 // CTRL_BREAK_EVENT - we got Ctrl+Break
789 // CTRL_CLOSE_EVENT - the console was closed; this is like SIGHUP
790 // CTRL_LOGOFF_EVENT - a user is logging off; this is received
791 // only by services
792 // CTRL_SHUTDOWN_EVENT - the system is shutting down; this is
793 // received only by services
794 //
795 // For now, we treat all but CTRL_LOGOFF_EVENT as indications
796 // that we should shut down.
797 //
798 switch (ctrltype)
799 {
800 case CTRL_C_EVENT:
801 case CTRL_BREAK_EVENT:
802 case CTRL_CLOSE_EVENT:
803 case CTRL_SHUTDOWN_EVENT:
804 //
805 // Set a shutdown notification.
806 //
807 send_shutdown_notification();
808 break;
809
810 default:
811 break;
812 }
813
814 //
815 // We handled this.
816 //
817 return TRUE;
818 }
819 #else
main_terminate(int sign _U_)820 static void main_terminate(int sign _U_)
821 {
822 //
823 // Note that the server should shut down.
824 // select() should get an EINTR error when we return,
825 // so it will wake up and know it needs to check the flag.
826 //
827 shutdown_server = 1;
828 }
829
main_reread_config(int sign _U_)830 static void main_reread_config(int sign _U_)
831 {
832 //
833 // Note that the server should re-read its configuration file.
834 // select() should get an EINTR error when we return,
835 // so it will wake up and know it needs to check the flag.
836 //
837 reread_config = 1;
838 }
839
main_reap_children(int sign _U_)840 static void main_reap_children(int sign _U_)
841 {
842 pid_t pid;
843 int exitstat;
844
845 // Reap all child processes that have exited.
846 // For reference, Stevens, pg 128
847
848 while ((pid = waitpid(-1, &exitstat, WNOHANG)) > 0)
849 rpcapd_log(LOGPRIO_DEBUG, "Child terminated");
850
851 return;
852 }
853 #endif
854
855 //
856 // Loop waiting for incoming connections and accepting them.
857 //
858 static void
accept_connections(void)859 accept_connections(void)
860 {
861 #ifdef _WIN32
862 struct listen_sock *sock_info;
863 DWORD num_events;
864 WSAEVENT *events;
865 int i;
866 char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed
867
868 //
869 // How big does the set of events need to be?
870 // One for the shutdown event, plus one for every socket on which
871 // we'll be listening.
872 //
873 num_events = 1; // shutdown event
874 for (sock_info = listen_socks; sock_info;
875 sock_info = sock_info->next)
876 {
877 if (num_events == WSA_MAXIMUM_WAIT_EVENTS)
878 {
879 //
880 // WSAWaitForMultipleEvents() doesn't support
881 // more than WSA_MAXIMUM_WAIT_EVENTS events
882 // on which to wait.
883 //
884 rpcapd_log(LOGPRIO_ERROR, "Too many sockets on which to listen");
885 exit(2);
886 }
887 num_events++;
888 }
889
890 //
891 // Allocate the array of events.
892 //
893 events = (WSAEVENT *) malloc(num_events * sizeof (WSAEVENT));
894 if (events == NULL)
895 {
896 rpcapd_log(LOGPRIO_ERROR, "Can't allocate array of events which to listen");
897 exit(2);
898 }
899
900 //
901 // Fill it in.
902 //
903 events[0] = state_change_event; // state change event first
904 for (sock_info = listen_socks, i = 1; sock_info;
905 sock_info = sock_info->next, i++)
906 {
907 WSAEVENT event;
908
909 //
910 // Create an event that is signaled if there's a connection
911 // to accept on the socket in question.
912 //
913 event = WSACreateEvent();
914 if (event == WSA_INVALID_EVENT)
915 {
916 sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE,
917 "Can't create socket event");
918 rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
919 exit(2);
920 }
921 if (WSAEventSelect(sock_info->sock, event, FD_ACCEPT) == SOCKET_ERROR)
922 {
923 sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE,
924 "Can't setup socket event");
925 rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
926 exit(2);
927 }
928 events[i] = event;
929 }
930
931 for (;;)
932 {
933 //
934 // Wait for incoming connections.
935 //
936 DWORD ret;
937
938 ret = WSAWaitForMultipleEvents(num_events, events, FALSE,
939 WSA_INFINITE, FALSE);
940 if (ret == WSA_WAIT_FAILED)
941 {
942 sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE,
943 "WSAWaitForMultipleEvents failed");
944 rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
945 exit(2);
946 }
947
948 if (ret == WSA_WAIT_EVENT_0)
949 {
950 //
951 // The state change event was set.
952 //
953 if (_InterlockedExchange(&shutdown_server, 0))
954 {
955 //
956 // Time to quit. Exit the loop.
957 //
958 break;
959 }
960 if (_InterlockedExchange(&reread_config, 0))
961 {
962 //
963 // We should re-read the configuration
964 // file.
965 //
966 fileconf_read();
967 }
968 }
969
970 //
971 // Check each socket.
972 //
973 for (sock_info = listen_socks, i = 1; sock_info;
974 sock_info = sock_info->next, i++)
975 {
976 WSANETWORKEVENTS network_events;
977
978 if (WSAEnumNetworkEvents(sock_info->sock,
979 events[i], &network_events) == SOCKET_ERROR)
980 {
981 sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE,
982 "WSAEnumNetworkEvents failed");
983 rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
984 exit(2);
985 }
986 if (network_events.lNetworkEvents & FD_ACCEPT)
987 {
988 //
989 // Did an error occur?
990 //
991 if (network_events.iErrorCode[FD_ACCEPT_BIT] != 0)
992 {
993 //
994 // Yes - report it and keep going.
995 //
996 sock_fmterrmsg(errbuf,
997 PCAP_ERRBUF_SIZE,
998 network_events.iErrorCode[FD_ACCEPT_BIT],
999 "Socket error");
1000 rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
1001 continue;
1002 }
1003
1004 //
1005 // Accept the connection.
1006 //
1007 accept_connection(sock_info->sock);
1008 }
1009 }
1010 }
1011 #else
1012 struct listen_sock *sock_info;
1013 int num_sock_fds;
1014
1015 //
1016 // How big does the bitset of sockets on which to select() have
1017 // to be?
1018 //
1019 num_sock_fds = 0;
1020 for (sock_info = listen_socks; sock_info; sock_info = sock_info->next)
1021 {
1022 if (sock_info->sock + 1 > num_sock_fds)
1023 {
1024 if ((unsigned int)(sock_info->sock + 1) >
1025 (unsigned int)FD_SETSIZE)
1026 {
1027 rpcapd_log(LOGPRIO_ERROR, "Socket FD is too bit for an fd_set");
1028 exit(2);
1029 }
1030 num_sock_fds = sock_info->sock + 1;
1031 }
1032 }
1033
1034 for (;;)
1035 {
1036 fd_set sock_fds;
1037 int ret;
1038
1039 //
1040 // Set up an fd_set for all the sockets on which we're
1041 // listening.
1042 //
1043 // This set is modified by select(), so we have to
1044 // construct it anew each time.
1045 //
1046 FD_ZERO(&sock_fds);
1047 for (sock_info = listen_socks; sock_info;
1048 sock_info = sock_info->next)
1049 {
1050 FD_SET(sock_info->sock, &sock_fds);
1051 }
1052
1053 //
1054 // Wait for incoming connections.
1055 //
1056 ret = select(num_sock_fds, &sock_fds, NULL, NULL, NULL);
1057 if (ret == -1)
1058 {
1059 if (errno == EINTR)
1060 {
1061 //
1062 // If this is a "terminate the
1063 // server" signal, exit the loop,
1064 // otherwise just keep trying.
1065 //
1066 if (shutdown_server)
1067 {
1068 //
1069 // Time to quit. Exit the loop.
1070 //
1071 break;
1072 }
1073 if (reread_config)
1074 {
1075 //
1076 // We should re-read the configuration
1077 // file.
1078 //
1079 reread_config = 0; // clear the indicator
1080 fileconf_read();
1081 }
1082
1083 //
1084 // Go back and wait again.
1085 //
1086 continue;
1087 }
1088 else
1089 {
1090 rpcapd_log(LOGPRIO_ERROR, "select failed: %s",
1091 strerror(errno));
1092 exit(2);
1093 }
1094 }
1095
1096 //
1097 // Check each socket.
1098 //
1099 for (sock_info = listen_socks; sock_info;
1100 sock_info = sock_info->next)
1101 {
1102 if (FD_ISSET(sock_info->sock, &sock_fds))
1103 {
1104 //
1105 // Accept the connection.
1106 //
1107 accept_connection(sock_info->sock);
1108 }
1109 }
1110 }
1111 #endif
1112
1113 //
1114 // Close all the listen sockets.
1115 //
1116 for (sock_info = listen_socks; sock_info; sock_info = sock_info->next)
1117 {
1118 closesocket(sock_info->sock);
1119 }
1120 sock_cleanup();
1121 }
1122
1123 #ifdef _WIN32
1124 //
1125 // A structure to hold the parameters to the daemon service loop
1126 // thread on Windows.
1127 //
1128 // (On UN*X, there is no need for this explicit copy since the
1129 // fork "inherits" the parent stack.)
1130 //
1131 struct params_copy {
1132 PCAP_SOCKET sockctrl;
1133 char *hostlist;
1134 };
1135 #endif
1136
1137 //
1138 // Accept a connection and start a worker thread, on Windows, or a
1139 // worker process, on UN*X, to handle the connection.
1140 //
1141 static void
accept_connection(PCAP_SOCKET listen_sock)1142 accept_connection(PCAP_SOCKET listen_sock)
1143 {
1144 char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed
1145 PCAP_SOCKET sockctrl; // keeps the socket ID for this control connection
1146 struct sockaddr_storage from; // generic sockaddr_storage variable
1147 socklen_t fromlen; // keeps the length of the sockaddr_storage variable
1148
1149 #ifdef _WIN32
1150 HANDLE threadId; // handle for the subthread
1151 u_long off = 0;
1152 struct params_copy *params_copy = NULL;
1153 #else
1154 pid_t pid;
1155 #endif
1156
1157 // Initialize errbuf
1158 memset(errbuf, 0, sizeof(errbuf));
1159
1160 for (;;)
1161 {
1162 // Accept the connection
1163 fromlen = sizeof(struct sockaddr_storage);
1164
1165 sockctrl = accept(listen_sock, (struct sockaddr *) &from, &fromlen);
1166
1167 if (sockctrl != INVALID_SOCKET)
1168 {
1169 // Success.
1170 break;
1171 }
1172
1173 // The accept() call can return this error when a signal is caught
1174 // In this case, we have simply to ignore this error code
1175 // Stevens, pg 124
1176 #ifdef _WIN32
1177 if (WSAGetLastError() == WSAEINTR)
1178 #else
1179 if (errno == EINTR)
1180 #endif
1181 continue;
1182
1183 // Don't check for errors here, since the error can be due to the fact that the thread
1184 // has been killed
1185 sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE, "accept() failed");
1186 rpcapd_log(LOGPRIO_ERROR, "Accept of control connection from client failed: %s",
1187 errbuf);
1188 return;
1189 }
1190
1191 #ifdef _WIN32
1192 //
1193 // Put the socket back into blocking mode; doing WSAEventSelect()
1194 // on the listen socket makes that socket non-blocking, and it
1195 // appears that sockets returned from an accept() on that socket
1196 // are also non-blocking.
1197 //
1198 // First, we have to un-WSAEventSelect() this socket, and then
1199 // we can turn non-blocking mode off.
1200 //
1201 // If this fails, we aren't guaranteed that, for example, any
1202 // of the error message will be sent - if it can't be put in
1203 // the socket queue, the send will just fail.
1204 //
1205 // So we just log the message and close the connection.
1206 //
1207 if (WSAEventSelect(sockctrl, NULL, 0) == SOCKET_ERROR)
1208 {
1209 sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE,
1210 "WSAEventSelect() failed");
1211 rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
1212 sock_close(sockctrl, NULL, 0);
1213 return;
1214 }
1215 if (ioctlsocket(sockctrl, FIONBIO, &off) == SOCKET_ERROR)
1216 {
1217 sock_geterrmsg(errbuf, PCAP_ERRBUF_SIZE,
1218 "ioctlsocket(FIONBIO) failed");
1219 rpcapd_log(LOGPRIO_ERROR, "%s", errbuf);
1220 sock_close(sockctrl, NULL, 0);
1221 return;
1222 }
1223
1224 //
1225 // Make a copy of the host list to pass to the new thread, so that
1226 // if we update it in the main thread, it won't catch us in the
1227 // middle of updating it.
1228 //
1229 // daemon_serviceloop() will free it once it's done with it.
1230 //
1231 char *hostlist_copy = strdup(hostlist);
1232 if (hostlist_copy == NULL)
1233 {
1234 rpcapd_log(LOGPRIO_ERROR, "Out of memory copying the host/port list");
1235 sock_close(sockctrl, NULL, 0);
1236 return;
1237 }
1238
1239 //
1240 // Allocate a location to hold the values of sockctrl.
1241 // It will be freed in the newly-created thread once it's
1242 // finished with it.
1243 //
1244 params_copy = malloc(sizeof(*params_copy));
1245 if (params_copy == NULL)
1246 {
1247 rpcapd_log(LOGPRIO_ERROR, "Out of memory allocating the parameter copy structure");
1248 free(hostlist_copy);
1249 sock_close(sockctrl, NULL, 0);
1250 return;
1251 }
1252 params_copy->sockctrl = sockctrl;
1253 params_copy->hostlist = hostlist_copy;
1254
1255 threadId = (HANDLE)_beginthreadex(NULL, 0,
1256 main_passive_serviceloop_thread, (void *) params_copy, 0, NULL);
1257 if (threadId == 0)
1258 {
1259 rpcapd_log(LOGPRIO_ERROR, "Error creating the child thread");
1260 free(params_copy);
1261 free(hostlist_copy);
1262 sock_close(sockctrl, NULL, 0);
1263 return;
1264 }
1265 CloseHandle(threadId);
1266 #else /* _WIN32 */
1267 pid = fork();
1268 if (pid == -1)
1269 {
1270 rpcapd_log(LOGPRIO_ERROR, "Error creating the child process: %s",
1271 strerror(errno));
1272 sock_close(sockctrl, NULL, 0);
1273 return;
1274 }
1275 if (pid == 0)
1276 {
1277 //
1278 // Child process.
1279 //
1280 // Close the socket on which we're listening (must
1281 // be open only in the parent).
1282 //
1283 closesocket(listen_sock);
1284
1285 #if 0
1286 //
1287 // Modify thread params so that it can be killed at any time
1288 // XXX - is this necessary? This is the main and, currently,
1289 // only thread in the child process, and nobody tries to
1290 // cancel us, although *we* may cancel the thread that's
1291 // handling the capture loop.
1292 //
1293 if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL))
1294 goto end;
1295 if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL))
1296 goto end;
1297 #endif
1298
1299 //
1300 // Run the service loop.
1301 // This is passive mode, so we don't care whether we were
1302 // told by the client to close.
1303 //
1304 char *hostlist_copy = strdup(hostlist);
1305 if (hostlist_copy == NULL)
1306 {
1307 rpcapd_log(LOGPRIO_ERROR, "Out of memory copying the host/port list");
1308 exit(0);
1309 }
1310 (void)daemon_serviceloop(sockctrl, 0, hostlist_copy,
1311 nullAuthAllowed, uses_ssl);
1312
1313 exit(0);
1314 }
1315
1316 // I am the parent
1317 // Close the socket for this session (must be open only in the child)
1318 closesocket(sockctrl);
1319 #endif /* _WIN32 */
1320 }
1321
1322 /*!
1323 \brief 'true' main of the program in case the active mode is turned on.
1324
1325 This function loops forever trying to connect to the remote host, until the
1326 daemon is turned down.
1327
1328 \param ptr: it keeps the 'activepars' parameters. It is a 'void *'
1329 just because the thread APIs want this format.
1330 */
1331 #ifdef _WIN32
1332 static unsigned __stdcall
1333 #else
1334 static void *
1335 #endif
main_active(void * ptr)1336 main_active(void *ptr)
1337 {
1338 char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed
1339 PCAP_SOCKET sockctrl; // keeps the socket ID for this control connection
1340 struct addrinfo hints; // temporary struct to keep settings needed to open the new socket
1341 struct addrinfo *addrinfo; // keeps the addrinfo chain; required to open a new socket
1342 struct active_pars *activepars;
1343
1344 activepars = (struct active_pars *) ptr;
1345
1346 // Prepare to open a new server socket
1347 memset(&hints, 0, sizeof(struct addrinfo));
1348 // WARNING Currently it supports only ONE socket family among IPv4 and IPv6
1349 hints.ai_family = AF_INET; // PF_UNSPEC to have both IPv4 and IPv6 server
1350 hints.ai_socktype = SOCK_STREAM;
1351 hints.ai_family = activepars->ai_family;
1352
1353 rpcapd_log(LOGPRIO_DEBUG, "Connecting to host %s, port %s, using protocol %s",
1354 activepars->address, activepars->port, (hints.ai_family == AF_INET) ? "IPv4":
1355 (hints.ai_family == AF_INET6) ? "IPv6" : "Unspecified");
1356
1357 // Initialize errbuf
1358 memset(errbuf, 0, sizeof(errbuf));
1359
1360 // Do the work
1361 addrinfo = sock_initaddress(activepars->address, activepars->port,
1362 &hints, errbuf, PCAP_ERRBUF_SIZE);
1363 if (addrinfo == NULL)
1364 {
1365 rpcapd_log(LOGPRIO_DEBUG, "%s", errbuf);
1366 return 0;
1367 }
1368
1369 for (;;)
1370 {
1371 int activeclose;
1372
1373 if ((sockctrl = sock_open(activepars->address, addrinfo, SOCKOPEN_CLIENT, 0, errbuf, PCAP_ERRBUF_SIZE)) == INVALID_SOCKET)
1374 {
1375 rpcapd_log(LOGPRIO_DEBUG, "%s", errbuf);
1376
1377 DIAG_OFF_FORMAT_TRUNCATION
1378 snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error connecting to host %s, port %s, using protocol %s",
1379 activepars->address, activepars->port, (hints.ai_family == AF_INET) ? "IPv4":
1380 (hints.ai_family == AF_INET6) ? "IPv6" : "Unspecified");
1381 DIAG_ON_FORMAT_TRUNCATION
1382
1383 rpcapd_log(LOGPRIO_DEBUG, "%s", errbuf);
1384
1385 sleep_secs(RPCAP_ACTIVE_WAIT);
1386
1387 continue;
1388 }
1389
1390 char *hostlist_copy = strdup(hostlist);
1391 if (hostlist_copy == NULL)
1392 {
1393 rpcapd_log(LOGPRIO_ERROR, "Out of memory copying the host/port list");
1394 activeclose = 0;
1395 sock_close(sockctrl, NULL, 0);
1396 }
1397 else
1398 {
1399 //
1400 // daemon_serviceloop() will free the copy.
1401 //
1402 activeclose = daemon_serviceloop(sockctrl, 1,
1403 hostlist_copy, nullAuthAllowed, uses_ssl);
1404 }
1405
1406 // If the connection is closed by the user explicitly, don't try to connect to it again
1407 // just exit the program
1408 if (activeclose == 1)
1409 break;
1410 }
1411
1412 freeaddrinfo(addrinfo);
1413 return 0;
1414 }
1415
1416 #ifdef _WIN32
1417 //
1418 // Main routine of a passive-mode service thread.
1419 //
main_passive_serviceloop_thread(void * ptr)1420 unsigned __stdcall main_passive_serviceloop_thread(void *ptr)
1421 {
1422 struct params_copy params = *(struct params_copy *)ptr;
1423 free(ptr);
1424
1425 //
1426 // Handle this client.
1427 // This is passive mode, so we don't care whether we were
1428 // told by the client to close.
1429 //
1430 (void)daemon_serviceloop(params.sockctrl, 0, params.hostlist,
1431 nullAuthAllowed, uses_ssl);
1432
1433 return 0;
1434 }
1435 #endif
1436