]> The Tcpdump Group git mirrors - libpcap/blob - rpcapd/daemon.c
3b2ab0100c9cdd3458fae60604a04b7871a87d82
[libpcap] / rpcapd / daemon.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 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
35
36 #include <pcap.h> // for libpcap/WinPcap calls
37 #include <errno.h> // for the errno variable
38 #include <stdlib.h> // for malloc(), free(), ...
39 #include <string.h> // for strlen(), ...
40 #include <pthread.h>
41 #include "sockutils.h" // for socket calls
42 #include "rpcap-protocol.h"
43 #include "pcap-rpcap-int.h"
44 #include "daemon.h"
45
46 #ifndef _WIN32 // for select() and such
47 #include <unistd.h>
48 #include <sys/time.h>
49 #include <sys/types.h>
50 #include <pwd.h> // for password management
51 #endif
52
53 #ifdef linux
54 #include <shadow.h> // for password management
55 #endif
56
57 #define RPCAP_TIMEOUT_INIT 90 /* Initial timeout for RPCAP connections (default: 90 sec) */
58 #define RPCAP_TIMEOUT_RUNTIME 180 /* Run-time timeout for RPCAP connections (default: 3 min) */
59 #define RPCAP_SUSPEND_WRONGAUTH 1 /* If the authentication is wrong, stops 1 sec before accepting a new auth message */
60
61 /*
62 * Data for a session managed by a thread.
63 */
64 struct session {
65 SOCKET sockctrl;
66 SOCKET sockdata;
67 pcap_t *fp;
68 unsigned int TotCapt;
69 };
70
71 // Locally defined functions
72 static int daemon_checkauth(SOCKET sockctrl, int nullAuthAllowed, char *errbuf);
73 static int daemon_AuthUserPwd(char *username, char *password, char *errbuf);
74
75 static int daemon_findalldevs(SOCKET sockctrl, char *errbuf);
76
77 static int daemon_opensource(SOCKET sockctrl, char *source, int srclen, uint32 plen, char *errbuf);
78 static struct session *daemon_startcapture(SOCKET sockctrl, pthread_t *threaddata, char *source, int active,
79 struct rpcap_sampling *samp_param, uint32 plen, char *errbuf);
80 static int daemon_endcapture(struct session *session, pthread_t *threaddata, char *errbuf);
81
82 static int daemon_updatefilter(struct session *session, uint32 plen);
83 static int daemon_unpackapplyfilter(struct session *session, uint32 *totread, uint32 *plen, char *errbuf);
84
85 static int daemon_getstats(struct session *session);
86 static int daemon_getstatsnopcap(SOCKET sockctrl, unsigned int ifdrops, unsigned int ifrecv,
87 unsigned int krnldrop, unsigned int svrcapt, char *errbuf);
88
89 static int daemon_setsampling(SOCKET sockctrl, struct rpcap_sampling *samp_param, int plen, char *errbuf);
90
91 static void daemon_seraddr(struct sockaddr_storage *sockaddrin, struct rpcap_sockaddr *sockaddrout);
92 static void *daemon_thrdatamain(void *ptr);
93
94 /*!
95 \brief Main serving funtion
96 This function is the one which does the job. It is the main() of the child
97 thread, which is created as soon as a new connection is accepted.
98
99 \param ptr: a void pointer that keeps the reference of the 'pthread_chain'
100 value corrisponding to this thread. This variable is casted into a 'pthread_chain'
101 value in order to retrieve the socket we're currently using, the therad ID, and
102 some pointers to the previous and next elements into this struct.
103
104 \return None.
105 */
106 void daemon_serviceloop(void *ptr)
107 {
108 char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed
109 char source[PCAP_BUF_SIZE]; // keeps the string that contains the interface to open
110 struct rpcap_header header; // RPCAP message general header
111 struct session *session = NULL; // struct session main variable
112 struct daemon_slpars *pars; // parameters related to the present daemon loop
113
114 pthread_t threaddata = 0; // handle to the 'read from daemon and send to client' thread
115
116 unsigned int ifdrops, ifrecv, krnldrop, svrcapt; // needed to save the values of the statistics
117
118 struct rpcap_sampling samp_param; // in case sampling has been requested
119
120 // Structures needed for the select() call
121 fd_set rfds; // set of socket descriptors we have to check
122 struct timeval tv; // maximum time the select() can block waiting for data
123 int retval; // select() return value
124
125 pars = (struct daemon_slpars *) ptr;
126
127 *errbuf = 0; // Initialize errbuf
128
129 // If we're in active mode, this is not a separate thread
130 if (! pars->isactive)
131 {
132 // Modify thread params so that it can be killed at any time
133 if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL))
134 goto end;
135 if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL))
136 goto end;
137 }
138
139 auth_again:
140 // If we're in active mode, we have to check for the initial timeout
141 if (!pars->isactive)
142 {
143 FD_ZERO(&rfds);
144 // We do not have to block here
145 tv.tv_sec = RPCAP_TIMEOUT_INIT;
146 tv.tv_usec = 0;
147
148 FD_SET(pars->sockctrl, &rfds);
149
150 retval = select(pars->sockctrl + 1, &rfds, NULL, NULL, &tv);
151 if (retval == -1)
152 {
153 sock_geterror("select(): ", errbuf, PCAP_ERRBUF_SIZE);
154 rpcap_senderror(pars->sockctrl, errbuf, PCAP_ERR_NETW, NULL);
155 goto end;
156 }
157
158 // The timeout has expired
159 // So, this was a fake connection. Drop it down
160 if (retval == 0)
161 {
162 rpcap_senderror(pars->sockctrl, "The RPCAP initial timeout has expired", PCAP_ERR_INITTIMEOUT, NULL);
163 goto end;
164 }
165 }
166
167 retval = daemon_checkauth(pars->sockctrl, pars->nullAuthAllowed, errbuf);
168
169 if (retval)
170 {
171 // the other user requested to close the connection
172 // It can be also the case of 'active mode', in which this host is not
173 // allowed to connect to the other peer; in that case, it drops down the connection
174 if (retval == -3)
175 goto end;
176
177 // It can be an authentication failure or an unrecoverable error
178 rpcap_senderror(pars->sockctrl, errbuf, PCAP_ERR_AUTH, NULL);
179
180 // authentication error
181 if (retval == -2)
182 {
183 // suspend for 1 sec
184 // WARNING: this day is inserted only in this point; if the user drops down the connection
185 // and it connects again, this suspension time does not have any effects.
186 pthread_suspend(RPCAP_SUSPEND_WRONGAUTH*1000);
187 goto auth_again;
188 }
189
190 // Unrecoverable error
191 if (retval == -1)
192 goto end;
193 }
194
195 while (1)
196 {
197 errbuf[0] = 0; // clear errbuf
198
199 // Avoid zombies connections; check if the connection is opens but no commands are performed
200 // from more than RPCAP_TIMEOUT_RUNTIME
201 // Conditions:
202 // - I have to be in normal mode (no active mode)
203 // - if the device is open, I don't have to be in the middle of a capture (session->sockdata)
204 // - if the device is closed, I have always to check if a new command arrives
205 //
206 // Be carefully: the capture can have been started, but an error occurred (so session != NULL, but
207 // sockdata is 0
208 if ((!pars->isactive) && ((session == NULL) || ((session != NULL) && (session->sockdata == 0))))
209 {
210 // Check for the initial timeout
211 FD_ZERO(&rfds);
212 // We do not have to block here
213 tv.tv_sec = RPCAP_TIMEOUT_RUNTIME;
214 tv.tv_usec = 0;
215
216 FD_SET(pars->sockctrl, &rfds);
217
218 retval = select(pars->sockctrl + 1, &rfds, NULL, NULL, &tv);
219 if (retval == -1)
220 {
221 sock_geterror("select(): ", errbuf, PCAP_ERRBUF_SIZE);
222 rpcap_senderror(pars->sockctrl, errbuf, PCAP_ERR_NETW, NULL);
223 goto end;
224 }
225
226 // The timeout has expired
227 // So, this was a fake connection. Drop it down
228 if (retval == 0)
229 {
230 SOCK_ASSERT("The RPCAP runtime timeout has expired", 1);
231 rpcap_senderror(pars->sockctrl, "The RPCAP runtime timeout has expired", PCAP_ERR_RUNTIMETIMEOUT, NULL);
232 goto end;
233 }
234 }
235
236 if (sock_recv(pars->sockctrl, (char *) &header, sizeof(struct rpcap_header), SOCK_RECEIVEALL_YES, errbuf, PCAP_ERRBUF_SIZE) == -1)
237 goto end;
238
239 // Checks if the message is correct
240 // In case it is wrong, it discard the data
241 retval = rpcap_checkmsg(errbuf, pars->sockctrl, &header,
242 RPCAP_MSG_FINDALLIF_REQ,
243 RPCAP_MSG_OPEN_REQ,
244 RPCAP_MSG_STARTCAP_REQ,
245 RPCAP_MSG_UPDATEFILTER_REQ,
246 RPCAP_MSG_STATS_REQ,
247 RPCAP_MSG_ENDCAP_REQ,
248 RPCAP_MSG_SETSAMPLING_REQ,
249 RPCAP_MSG_CLOSE,
250 RPCAP_MSG_ERROR,
251 0);
252
253 switch (retval)
254 {
255 case -3: // Unrecoverable network error
256 goto end; // Do nothing; just exit from findalldevs; the error code is already into the errbuf
257
258 case -2: // The other endpoint send a message that is not allowed here
259 {
260 rpcap_senderror(pars->sockctrl, "The RPCAP daemon received a message that is not valid", PCAP_ERR_WRONGMSG, errbuf);
261 }
262 case -1: // The other endpoint has a version number that is not compatible with our
263 {
264 rpcap_senderror(pars->sockctrl, "RPCAP version number mismatch", PCAP_ERR_WRONGVER, errbuf);
265 }
266 break;
267
268 case RPCAP_MSG_FINDALLIF_REQ:
269 {
270 // Checks that the header does not contain other data; if so, discard it
271 if (ntohl(header.plen))
272 sock_discard(pars->sockctrl, ntohl(header.plen), errbuf, PCAP_ERRBUF_SIZE);
273
274 if (daemon_findalldevs(pars->sockctrl, errbuf))
275 SOCK_ASSERT(errbuf, 1);
276
277 break;
278 };
279
280 case RPCAP_MSG_OPEN_REQ:
281 {
282 retval = daemon_opensource(pars->sockctrl, source, sizeof(source), ntohl(header.plen), errbuf);
283
284 if (retval == -1)
285 SOCK_ASSERT(errbuf, 1);
286
287 break;
288 };
289
290 case RPCAP_MSG_SETSAMPLING_REQ:
291 {
292 retval = daemon_setsampling(pars->sockctrl, &samp_param, ntohl(header.plen), errbuf);
293
294 if (retval == -1)
295 SOCK_ASSERT(errbuf, 1);
296
297 break;
298 };
299
300 case RPCAP_MSG_STARTCAP_REQ:
301 {
302 session = daemon_startcapture(pars->sockctrl, &threaddata, source, pars->isactive, &samp_param, ntohl(header.plen), errbuf);
303
304 if (session == NULL)
305 SOCK_ASSERT(errbuf, 1);
306
307 break;
308 };
309
310 case RPCAP_MSG_UPDATEFILTER_REQ:
311 {
312 if (session)
313 {
314 if (daemon_updatefilter(session, ntohl(header.plen)))
315 SOCK_ASSERT(pcap_geterr(session->fp), 1);
316 }
317 else
318 {
319 rpcap_senderror(pars->sockctrl, "Device not opened. Cannot update filter", PCAP_ERR_UPDATEFILTER, errbuf);
320 }
321
322 break;
323 };
324
325 case RPCAP_MSG_STATS_REQ:
326 {
327 // Checks that the header does not contain other data; if so, discard it
328 if (ntohl(header.plen))
329 sock_discard(pars->sockctrl, ntohl(header.plen), errbuf, PCAP_ERRBUF_SIZE);
330
331 if (session && session->fp)
332 {
333 if (daemon_getstats(session))
334 SOCK_ASSERT(pcap_geterr(session->fp), 1);
335 }
336 else
337 {
338 SOCK_ASSERT("GetStats: this call should't be allowed here", 1);
339
340 if (daemon_getstatsnopcap(pars->sockctrl, ifdrops, ifrecv, krnldrop, svrcapt, errbuf))
341 SOCK_ASSERT(errbuf, 1);
342 // we have to keep compatibility with old applications, which ask for statistics
343 // also when the capture has already stopped
344
345 // rpcap_senderror(pars->sockctrl, "Device not opened. Cannot get statistics", PCAP_ERR_GETSTATS, errbuf);
346 }
347
348 break;
349 };
350
351 case RPCAP_MSG_ENDCAP_REQ: // The other endpoint close the current capture session
352 {
353 if (session && session->fp)
354 {
355 struct pcap_stat stats;
356
357 // Save statistics (we can need them in the future)
358 if (pcap_stats(session->fp, &stats))
359 {
360 ifdrops = stats.ps_ifdrop;
361 ifrecv = stats.ps_recv;
362 krnldrop = stats.ps_drop;
363 svrcapt = session->TotCapt;
364 }
365 else
366 ifdrops = ifrecv = krnldrop = svrcapt = 0;
367
368 if (daemon_endcapture(session, &threaddata, errbuf))
369 SOCK_ASSERT(pcap_geterr(session->fp), 1);
370 free(session);
371 session = NULL;
372 }
373 else
374 {
375 rpcap_senderror(pars->sockctrl, "Device not opened. Cannot close the capture", PCAP_ERR_ENDCAPTURE, errbuf);
376 }
377 break;
378 };
379
380 case RPCAP_MSG_CLOSE: // The other endpoint close the pcap session
381 {
382 // signal to the main that the user closed the control connection
383 // This is used only in case of active mode
384 pars->activeclose = 1;
385 SOCK_ASSERT("The other end system asked to close the connection.", 1);
386 goto end;
387 break;
388 };
389
390 case RPCAP_MSG_ERROR: // The other endpoint reported an error
391 {
392 // Do nothing; just exit; the error code is already into the errbuf
393 SOCK_ASSERT(errbuf, 1);
394 break;
395 };
396
397 default:
398 {
399 SOCK_ASSERT("Internal error.", 1);
400 break;
401 };
402 }
403 }
404
405 end:
406 // The child thread is about to end
407
408 // perform pcap_t cleanup, in case it has not been done
409 if (session)
410 {
411 if (threaddata)
412 {
413 pthread_cancel(threaddata);
414 threaddata = 0;
415 }
416 if (session->sockdata)
417 {
418 sock_close(session->sockdata, NULL, 0);
419 session->sockdata = 0;
420 }
421 pcap_close(session->fp);
422 free(session);
423 session = NULL;
424 }
425
426 // Print message and exit
427 SOCK_ASSERT("I'm exiting from the child loop", 1);
428 SOCK_ASSERT(errbuf, 1);
429
430 if (!pars->isactive)
431 {
432 if (pars->sockctrl)
433 sock_close(pars->sockctrl, NULL, 0);
434
435 free(pars);
436 #ifdef _WIN32
437 pthread_exit(0);
438 #endif
439 }
440 }
441
442 /*!
443 \brief It checks if the authentication credentials supplied by the user are valid.
444
445 This function is called each time the rpcap daemon starts a new serving thread.
446 It reads the authentication message from the network and it checks that the
447 user information are valid.
448
449 \param sockctrl: the socket if of the control connection.
450
451 \param nullAuthAllowed: '1' if the NULL authentication is allowed.
452
453 \param errbuf: a user-allocated buffer in which the error message (if one) has to be written.
454
455 \return '0' if everything is fine, '-1' if an unrecoverable error occurred.
456 The error message is returned in the 'errbuf' variable.
457 '-2' is returned in case the authentication failed or in case of a recoverable error (like
458 wrong version). In that case, 'errbuf' keeps the reason of the failure. This provides
459 a way to know that the connection does not have to be closed.
460
461 In case the message is a 'CLOSE' or an 'ERROR', it returns -3. The error can be due to a
462 connection refusal in active mode, since this host cannot be allowed to connect to the remote
463 peer.
464 */
465 int daemon_checkauth(SOCKET sockctrl, int nullAuthAllowed, char *errbuf)
466 {
467 struct rpcap_header header; // RPCAP message general header
468 int retval; // generic return value
469 uint32 totread = 0; // number of bytes of the payload read from the socket
470 ssize_t nread;
471 struct rpcap_auth auth; // RPCAP authentication header
472 char *string1, *string2; // two strings exchanged by the authentication message
473 unsigned int plen; // length of the payload
474 int retcode; // the value we have to return to the caller
475
476 if (sock_recv(sockctrl, (char *) &header, sizeof(struct rpcap_header), SOCK_RECEIVEALL_YES, errbuf, PCAP_ERRBUF_SIZE) == -1)
477 return -1;
478
479 plen = ntohl(header.plen);
480
481 retval = rpcap_checkmsg(errbuf, sockctrl, &header,
482 RPCAP_MSG_AUTH_REQ,
483 RPCAP_MSG_CLOSE,
484 0);
485
486 if (retval != RPCAP_MSG_AUTH_REQ)
487 {
488 switch (retval)
489 {
490 case -3: // Unrecoverable network error
491 return -1; // Do nothing; just exit; the error code is already into the errbuf
492
493 case -2: // The other endpoint send a message that is not allowed here
494 case -1: // The other endpoint has a version number that is not compatible with our
495 return -2;
496
497 case RPCAP_MSG_CLOSE:
498 {
499 // Check if all the data has been read; if not, discard the data in excess
500 if (ntohl(header.plen))
501 {
502 if (sock_discard(sockctrl, ntohl(header.plen), NULL, 0))
503 return -1;
504 }
505 return -3;
506 };
507
508 case RPCAP_MSG_ERROR:
509 return -3;
510
511 default:
512 {
513 SOCK_ASSERT("Internal error.", 1);
514 retcode = -2;
515 goto error;
516 };
517 }
518 }
519
520 // If it comes here, it means that we have an authentication request message
521 nread = sock_recv(sockctrl, (char *) &auth, sizeof(struct rpcap_auth),
522 SOCK_RECEIVEALL_YES, errbuf, PCAP_ERRBUF_SIZE);
523 if (nread == -1)
524 {
525 retcode = -1;
526 goto error;
527 }
528 totread += nread;
529
530 switch (ntohs(auth.type))
531 {
532 case RPCAP_RMTAUTH_NULL:
533 {
534 if (!nullAuthAllowed)
535 {
536 snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed; NULL autentication not permitted.");
537 retcode = -2;
538 goto error;
539 }
540 break;
541 }
542
543 case RPCAP_RMTAUTH_PWD:
544 {
545 int len1, len2;
546
547 len1 = ntohs(auth.slen1);
548 len2 = ntohs(auth.slen2);
549
550 string1 = (char *) malloc (len1 + 1);
551 string2 = (char *) malloc (len2 + 1);
552
553 if ((string1 == NULL) || (string2 == NULL))
554 {
555 snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno));
556 retcode = -1;
557 goto error;
558 }
559
560 nread = sock_recv(sockctrl, string1, len1,
561 SOCK_RECEIVEALL_YES, errbuf, PCAP_ERRBUF_SIZE);
562 if (nread == -1)
563 {
564 retcode = -1;
565 goto error;
566 }
567 totread = nread;
568 nread = sock_recv(sockctrl, string2, len2,
569 SOCK_RECEIVEALL_YES, errbuf, PCAP_ERRBUF_SIZE);
570 if (nread == -1)
571 {
572 retcode = -1;
573 goto error;
574 }
575 totread += nread;
576
577 string1[len1] = 0;
578 string2[len2] = 0;
579
580 if (daemon_AuthUserPwd(string1, string2, errbuf))
581 {
582 retcode = -2;
583 goto error;
584 }
585
586 break;
587 }
588
589 default:
590 snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication type not recognized.");
591 retcode = -2;
592 goto error;
593 }
594
595
596 // Check if all the data has been read; if not, discard the data in excess
597 if (totread != plen)
598 {
599 if (sock_discard(sockctrl, plen - totread, NULL, 0))
600 {
601 retcode = -1;
602 goto error;
603 }
604 }
605
606 rpcap_createhdr(&header, RPCAP_MSG_AUTH_REPLY, 0, 0);
607
608 // Send the ok message back
609 if (sock_send(sockctrl, (char *) &header, sizeof (struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE) == -1)
610 {
611 retcode = -1;
612 goto error;
613 }
614
615 return 0;
616
617 error:
618 // Check if all the data has been read; if not, discard the data in excess
619 if (totread != plen)
620 sock_discard(sockctrl, plen - totread, NULL, 0);
621
622 return retcode;
623 }
624
625 int daemon_AuthUserPwd(char *username, char *password, char *errbuf)
626 {
627 #ifdef _WIN32
628 /*
629 * Warning: the user which launches the process must have the
630 * SE_TCB_NAME right.
631 * This corresponds to have the "Act as part of the Operating System"
632 * turned on (administrative tools, local security settings, local
633 * policies, user right assignment)
634 * However, it seems to me that if you run it as a service, this
635 * right should be provided by default.
636 */
637 HANDLE Token;
638 if (LogonUser(username, ".", password, LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, &Token) == 0)
639 {
640 int error;
641
642 error = GetLastError();
643 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, errbuf,
644 PCAP_ERRBUF_SIZE, NULL);
645
646 return -1;
647 }
648
649 // This call should change the current thread to the selected user.
650 // I didn't test it.
651 if (ImpersonateLoggedOnUser(Token) == 0)
652 {
653 int error;
654
655 error = GetLastError();
656 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, errbuf,
657 PCAP_ERRBUF_SIZE, NULL);
658
659 CloseHandle(Token);
660 return -1;
661 }
662
663 CloseHandle(Token);
664 return 0;
665
666 #else
667 /*
668 * Standard user authentication:
669 *
670 * http://www.unixpapa.com/incnote/passwd.html
671 *
672 * Problem: it is not able to merge the standard pwd file with
673 * the shadow one
674 *
675 * Shadow user authentication:
676 *
677 * http://www.tldp.org/HOWTO/Shadow-Password-HOWTO-8.html
678 *
679 * Problem: the program must either (1) run as root, or (2) run
680 * as user, but it must be owned by root and must be SUID root
681 * (chmod u+s rpcapd)
682 */
683 struct passwd *user;
684 #ifdef linux
685 struct spwd *usersp;
686 #endif
687
688 // This call is needed to get the uid
689 if ((user = getpwnam(username)) == NULL)
690 {
691 snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed: no such user");
692 return -1;
693 }
694
695 #ifdef linux
696 // This call is needed to get the password; otherwise 'x' is returned
697 if ((usersp = getspnam(username)) == NULL)
698 {
699 snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed: no such user");
700 return -1;
701 }
702
703 if (strcmp(usersp->sp_pwdp, (char *) crypt(password, usersp->sp_pwdp)) != 0)
704 {
705 snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed: password incorrect");
706 return -1;
707 }
708 #endif
709
710 #ifdef bsd
711 if (strcmp(user->pw_passwd, (char *) crypt(password, user->pw_passwd)) != 0)
712 {
713 snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed: password incorrect");
714 return -1;
715 }
716 #endif
717
718 if (setuid(user->pw_uid))
719 {
720 snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s", pcap_strerror(errno));
721 return -1;
722 }
723
724 /* if (setgid(user->pw_gid))
725 {
726 SOCK_ASSERT("setgid failed", 1);
727 snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s", pcap_strerror(errno));
728 return -1;
729 }
730 */
731 return 0;
732
733 #endif
734
735 }
736
737 // PORTING WARNING We assume u_int is a 32bit value
738 int daemon_findalldevs(SOCKET sockctrl, char *errbuf)
739 {
740 char sendbuf[RPCAP_NETBUF_SIZE]; // temporary buffer in which data to be sent is buffered
741 int sendbufidx = 0; // index which keeps the number of bytes currently buffered
742 pcap_if_t *alldevs; // pointer to the heade of the interface chain
743 pcap_if_t *d; // temp pointer neede to scan the interface chain
744 uint16 plen = 0; // length of the payload of this message
745 struct pcap_addr *address; // pcap structure that keeps a network address of an interface
746 struct rpcap_findalldevs_if *findalldevs_if;// rpcap structure that packet all the data of an interface together
747 uint16 nif = 0; // counts the number of interface listed
748
749 // Retrieve the device list
750 if (pcap_findalldevs(&alldevs, errbuf) == -1)
751 {
752 rpcap_senderror(sockctrl, errbuf, PCAP_ERR_FINDALLIF, NULL);
753 return -1;
754 }
755
756 if (alldevs == NULL)
757 {
758 rpcap_senderror(sockctrl,
759 "No interfaces found! Make sure libpcap/WinPcap is properly installed"
760 " and you have the right to access to the remote device.",
761 PCAP_ERR_NOREMOTEIF,
762 errbuf);
763 return -1;
764 }
765
766 // checks the number of interfaces and it computes the total length of the payload
767 for (d = alldevs; d != NULL; d = d->next)
768 {
769 nif++;
770
771 if (d->description)
772 plen+= strlen(d->description);
773 if (d->name)
774 plen+= strlen(d->name);
775
776 plen+= sizeof(struct rpcap_findalldevs_if);
777
778 for (address = d->addresses; address != NULL; address = address->next)
779 {
780 /*
781 * Send only IPv4 and IPv6 addresses over the wire.
782 */
783 switch (address->addr->sa_family)
784 {
785 case AF_INET:
786 #ifdef AF_INET6
787 case AF_INET6:
788 #endif
789 plen+= (sizeof(struct rpcap_sockaddr) * 4);
790 break;
791
792 default:
793 break;
794 }
795 }
796 }
797
798 // RPCAP findalldevs command
799 if (sock_bufferize(NULL, sizeof(struct rpcap_header), NULL,
800 &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE) == -1)
801 return -1;
802
803 rpcap_createhdr((struct rpcap_header *) sendbuf, RPCAP_MSG_FINDALLIF_REPLY, nif, plen);
804
805 // send the interface list
806 for (d = alldevs; d != NULL; d = d->next)
807 {
808 uint16 lname, ldescr;
809
810 findalldevs_if = (struct rpcap_findalldevs_if *) &sendbuf[sendbufidx];
811
812 if (sock_bufferize(NULL, sizeof(struct rpcap_findalldevs_if), NULL,
813 &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE) == -1)
814 return -1;
815
816 memset(findalldevs_if, 0, sizeof(struct rpcap_findalldevs_if));
817
818 if (d->description) ldescr = (short) strlen(d->description);
819 else ldescr = 0;
820 if (d->name) lname = (short) strlen(d->name);
821 else lname = 0;
822
823 findalldevs_if->desclen = htons(ldescr);
824 findalldevs_if->namelen = htons(lname);
825 findalldevs_if->flags = htonl(d->flags);
826
827 for (address = d->addresses; address != NULL; address = address->next)
828 {
829 /*
830 * Send only IPv4 and IPv6 addresses over the wire.
831 */
832 switch (address->addr->sa_family)
833 {
834 case AF_INET:
835 #ifdef AF_INET6
836 case AF_INET6:
837 #endif
838 findalldevs_if->naddr++;
839 break;
840
841 default:
842 break;
843 }
844 }
845 findalldevs_if->naddr = htons(findalldevs_if->naddr);
846
847 if (sock_bufferize(d->name, lname, sendbuf, &sendbufidx,
848 RPCAP_NETBUF_SIZE, SOCKBUF_BUFFERIZE, errbuf, PCAP_ERRBUF_SIZE) == -1)
849 return -1;
850
851 if (sock_bufferize(d->description, ldescr, sendbuf, &sendbufidx,
852 RPCAP_NETBUF_SIZE, SOCKBUF_BUFFERIZE, errbuf, PCAP_ERRBUF_SIZE) == -1)
853 return -1;
854
855 // send all addresses
856 for (address = d->addresses; address != NULL; address = address->next)
857 {
858 struct rpcap_sockaddr *sockaddr;
859
860 /*
861 * Send only IPv4 and IPv6 addresses over the wire.
862 */
863 switch (address->addr->sa_family)
864 {
865 case AF_INET:
866 #ifdef AF_INET6
867 case AF_INET6:
868 #endif
869 sockaddr = (struct rpcap_sockaddr *) &sendbuf[sendbufidx];
870 if (sock_bufferize(NULL, sizeof(struct rpcap_sockaddr), NULL,
871 &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE) == -1)
872 return -1;
873 daemon_seraddr((struct sockaddr_storage *) address->addr, sockaddr);
874
875 sockaddr = (struct rpcap_sockaddr *) &sendbuf[sendbufidx];
876 if (sock_bufferize(NULL, sizeof(struct rpcap_sockaddr), NULL,
877 &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE) == -1)
878 return -1;
879 daemon_seraddr((struct sockaddr_storage *) address->netmask, sockaddr);
880
881 sockaddr = (struct rpcap_sockaddr *) &sendbuf[sendbufidx];
882 if (sock_bufferize(NULL, sizeof(struct rpcap_sockaddr), NULL,
883 &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE) == -1)
884 return -1;
885 daemon_seraddr((struct sockaddr_storage *) address->broadaddr, sockaddr);
886
887 sockaddr = (struct rpcap_sockaddr *) &sendbuf[sendbufidx];
888 if (sock_bufferize(NULL, sizeof(struct rpcap_sockaddr), NULL,
889 &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE) == -1)
890 return -1;
891 daemon_seraddr((struct sockaddr_storage *) address->dstaddr, sockaddr);
892 break;
893
894 default:
895 break;
896 }
897 }
898 }
899
900 // Send a final command that says "now send it!"
901 if (sock_send(sockctrl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
902 return -1;
903
904 // We do no longer need the device list. Free it
905 pcap_freealldevs(alldevs);
906
907 // everything is fine
908 return 0;
909 }
910
911 /*
912 \param plen: the length of the current message (needed in order to be able
913 to discard excess data in the message, if present)
914 */
915 static int daemon_opensource(SOCKET sockctrl, char *source, int srclen, uint32 plen, char *errbuf)
916 {
917 pcap_t *fp = NULL; // pcap_t main variable
918 uint32 totread; // number of bytes of the payload read from the socket
919 ssize_t nread;
920 char sendbuf[RPCAP_NETBUF_SIZE]; // temporary buffer in which data to be sent is buffered
921 int sendbufidx = 0; // index which keeps the number of bytes currently buffered
922 struct rpcap_openreply *openreply; // open reply message
923
924 strcpy(source, PCAP_SRC_IF_STRING);
925
926 if (srclen <= (int) (strlen(PCAP_SRC_IF_STRING) + plen))
927 {
928 rpcap_senderror(sockctrl, "Source string too long", PCAP_ERR_OPEN, NULL);
929 return -1;
930 }
931
932 nread = sock_recv(sockctrl, &source[strlen(PCAP_SRC_IF_STRING)], plen,
933 SOCK_RECEIVEALL_YES, errbuf, PCAP_ERRBUF_SIZE);
934 if (nread == -1)
935 return -1;
936 totread = nread;
937
938 // Check if all the data has been read; if not, discard the data in excess
939 if (totread != plen)
940 sock_discard(sockctrl, plen - totread, NULL, 0);
941
942 // Puts a '0' to terminate the source string
943 source[strlen(PCAP_SRC_IF_STRING) + plen] = 0;
944
945 // Open the selected device
946 // This is a fake open, since we do that only to get the needed parameters, then we close the device again
947 if ((fp = pcap_open_live(source,
948 1500 /* fake snaplen */,
949 0 /* no promis */,
950 1000 /* fake timeout */,
951 errbuf)) == NULL)
952 {
953 rpcap_senderror(sockctrl, errbuf, PCAP_ERR_OPEN, NULL);
954 return -1;
955 }
956
957
958 // Now, I can send a RPCAP open reply message
959 if (sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, &sendbufidx,
960 RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE) == -1)
961 goto error;
962
963 rpcap_createhdr((struct rpcap_header *) sendbuf, RPCAP_MSG_OPEN_REPLY, 0, sizeof(struct rpcap_openreply));
964
965 openreply = (struct rpcap_openreply *) &sendbuf[sendbufidx];
966
967 if (sock_bufferize(NULL, sizeof(struct rpcap_openreply), NULL, &sendbufidx,
968 RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE) == -1)
969 goto error;
970
971 memset(openreply, 0, sizeof(struct rpcap_openreply));
972 openreply->linktype = htonl(pcap_datalink(fp));
973 openreply->tzoff = 0; /* This is always 0 for live captures */
974
975 if (sock_send(sockctrl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
976 goto error;
977
978 // I have to close the device again, since it has been opened with wrong parameters
979 pcap_close(fp);
980 fp = NULL;
981
982 return 0;
983
984 error:
985 if (fp)
986 {
987 pcap_close(fp);
988 fp = NULL;
989 }
990
991 return -1;
992 }
993
994 /*
995 \param plen: the length of the current message (needed in order to be able
996 to discard excess data in the message, if present)
997 */
998 static struct session *daemon_startcapture(SOCKET sockctrl, pthread_t *threaddata, char *source, int active, struct rpcap_sampling *samp_param, uint32 plen, char *errbuf)
999 {
1000 char portdata[PCAP_BUF_SIZE]; // temp variable needed to derive the data port
1001 char peerhost[PCAP_BUF_SIZE]; // temp variable needed to derive the host name of our peer
1002 struct session *session; // saves state of session
1003 uint32 totread; // number of bytes of the payload read from the socket
1004 ssize_t nread;
1005 char sendbuf[RPCAP_NETBUF_SIZE]; // temporary buffer in which data to be sent is buffered
1006 int sendbufidx = 0; // index which keeps the number of bytes currently buffered
1007
1008 // socket-related variables
1009 SOCKET sockdata = 0; // socket descriptor of the data connection
1010 struct addrinfo hints; // temp, needed to open a socket connection
1011 struct addrinfo *addrinfo; // temp, needed to open a socket connection
1012 struct sockaddr_storage saddr; // temp, needed to retrieve the network data port chosen on the local machine
1013 socklen_t saddrlen; // temp, needed to retrieve the network data port chosen on the local machine
1014
1015 pthread_attr_t detachedAttribute; // temp, needed to set the created thread as detached
1016
1017 // RPCAP-related variables
1018 struct rpcap_startcapreq startcapreq; // start capture request message
1019 struct rpcap_startcapreply *startcapreply; // start capture reply message
1020 int serveropen_dp; // keeps who is going to open the data connection
1021
1022 addrinfo = NULL;
1023
1024 nread = sock_recv(sockctrl, (char *) &startcapreq,
1025 sizeof(struct rpcap_startcapreq), SOCK_RECEIVEALL_YES,
1026 errbuf, PCAP_ERRBUF_SIZE);
1027 if (nread == -1)
1028 return NULL;
1029 totread = nread;
1030
1031 startcapreq.flags = ntohs(startcapreq.flags);
1032
1033 // Create a session structure
1034 session = malloc(sizeof(struct session));
1035 if (session == NULL)
1036 {
1037 rpcap_senderror(sockctrl, "Can't allocate session structure",
1038 PCAP_ERR_OPEN, NULL);
1039 return NULL;
1040 }
1041
1042 // Open the selected device
1043 if ((session->fp = pcap_open(source,
1044 ntohl(startcapreq.snaplen),
1045 (startcapreq.flags & RPCAP_STARTCAPREQ_FLAG_PROMISC) ? PCAP_OPENFLAG_PROMISCUOUS : 0 /* local device, other flags not needed */,
1046 ntohl(startcapreq.read_timeout),
1047 NULL /* local device, so no auth */,
1048 errbuf)) == NULL)
1049 {
1050 rpcap_senderror(sockctrl, errbuf, PCAP_ERR_OPEN, NULL);
1051 return NULL;
1052 }
1053
1054 #if 0
1055 // Apply sampling parameters
1056 fp->rmt_samp.method = samp_param->method;
1057 fp->rmt_samp.value = samp_param->value;
1058 #endif
1059
1060 /*
1061 We're in active mode if:
1062 - we're using TCP, and the user wants us to be in active mode
1063 - we're using UDP
1064 */
1065 serveropen_dp = (startcapreq.flags & RPCAP_STARTCAPREQ_FLAG_SERVEROPEN) || (startcapreq.flags & RPCAP_STARTCAPREQ_FLAG_DGRAM) || active;
1066
1067 /*
1068 Gets the sockaddr structure referred to the other peer in the ctrl connection
1069
1070 We need that because:
1071 - if we're in passive mode, we need to know the address family we want to use
1072 (the same used for the ctrl socket)
1073 - if we're in active mode, we need to know the network address of the other host
1074 we want to connect to
1075 */
1076 saddrlen = sizeof(struct sockaddr_storage);
1077 if (getpeername(sockctrl, (struct sockaddr *) &saddr, &saddrlen) == -1)
1078 {
1079 sock_geterror("getpeername(): ", errbuf, PCAP_ERRBUF_SIZE);
1080 goto error;
1081 }
1082
1083 memset(&hints, 0, sizeof(struct addrinfo));
1084 hints.ai_socktype = (startcapreq.flags & RPCAP_STARTCAPREQ_FLAG_DGRAM) ? SOCK_DGRAM : SOCK_STREAM;
1085 hints.ai_family = saddr.ss_family;
1086
1087 // Now we have to create a new socket to send packets
1088 if (serveropen_dp) // Data connection is opened by the server toward the client
1089 {
1090 sprintf(portdata, "%d", ntohs(startcapreq.portdata));
1091
1092 // Get the name of the other peer (needed to connect to that specific network address)
1093 if (getnameinfo((struct sockaddr *) &saddr, saddrlen, peerhost,
1094 sizeof(peerhost), NULL, 0, NI_NUMERICHOST))
1095 {
1096 sock_geterror("getnameinfo(): ", errbuf, PCAP_ERRBUF_SIZE);
1097 goto error;
1098 }
1099
1100 if (sock_initaddress(peerhost, portdata, &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1)
1101 goto error;
1102
1103 if ((sockdata = sock_open(addrinfo, SOCKOPEN_CLIENT, 0, errbuf, PCAP_ERRBUF_SIZE)) == -1)
1104 goto error;
1105 }
1106 else // Data connection is opened by the client toward the server
1107 {
1108 hints.ai_flags = AI_PASSIVE;
1109
1110 // Let's the server socket pick up a free network port for us
1111 if (sock_initaddress(NULL, "0", &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1)
1112 goto error;
1113
1114 if ((sockdata = sock_open(addrinfo, SOCKOPEN_SERVER, 1 /* max 1 connection in queue */, errbuf, PCAP_ERRBUF_SIZE)) == -1)
1115 goto error;
1116
1117 // get the complete sockaddr structure used in the data connection
1118 saddrlen = sizeof(struct sockaddr_storage);
1119 if (getsockname(sockdata, (struct sockaddr *) &saddr, &saddrlen) == -1)
1120 {
1121 sock_geterror("getsockname(): ", errbuf, PCAP_ERRBUF_SIZE);
1122 goto error;
1123 }
1124
1125 // Get the local port the system picked up
1126 if (getnameinfo((struct sockaddr *) &saddr, saddrlen, NULL,
1127 0, portdata, sizeof(portdata), NI_NUMERICSERV))
1128 {
1129 sock_geterror("getnameinfo(): ", errbuf, PCAP_ERRBUF_SIZE);
1130 goto error;
1131 }
1132 }
1133
1134 // addrinfo is no longer used
1135 freeaddrinfo(addrinfo);
1136 addrinfo = NULL;
1137
1138 session->sockctrl = sockctrl; // Needed to send an error on the ctrl connection
1139
1140 // Now I can set the filter
1141 if (daemon_unpackapplyfilter(session, &totread, &plen, errbuf))
1142 goto error;
1143
1144
1145 // Now, I can send a RPCAP start capture reply message
1146 if (sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, &sendbufidx,
1147 RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE) == -1)
1148 goto error;
1149
1150 rpcap_createhdr((struct rpcap_header *) sendbuf, RPCAP_MSG_STARTCAP_REPLY, 0, sizeof(struct rpcap_startcapreply));
1151
1152 startcapreply = (struct rpcap_startcapreply *) &sendbuf[sendbufidx];
1153
1154 if (sock_bufferize(NULL, sizeof(struct rpcap_startcapreply), NULL,
1155 &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE) == -1)
1156 goto error;
1157
1158 memset(startcapreply, 0, sizeof(struct rpcap_startcapreply));
1159 startcapreply->bufsize = htonl(pcap_bufsize(session->fp));
1160
1161 if (!serveropen_dp)
1162 {
1163 unsigned short port = (unsigned short)strtoul(portdata,NULL,10);
1164 startcapreply->portdata = htons(port);
1165 }
1166
1167 if (sock_send(sockctrl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
1168 goto error;
1169
1170 if (!serveropen_dp)
1171 {
1172 SOCKET socktemp; // We need another socket, since we're going to accept() a connection
1173
1174 // Connection creation
1175 saddrlen = sizeof(struct sockaddr_storage);
1176
1177 socktemp = accept(sockdata, (struct sockaddr *) &saddr, &saddrlen);
1178
1179 if (socktemp == -1)
1180 {
1181 sock_geterror("accept(): ", errbuf, PCAP_ERRBUF_SIZE);
1182 goto error;
1183 }
1184
1185 // Now that I accepted the connection, the server socket is no longer needed
1186 sock_close(sockdata, errbuf, PCAP_ERRBUF_SIZE);
1187 sockdata = socktemp;
1188 }
1189
1190 session->sockdata = sockdata;
1191
1192 /* GV we need this to create the thread as detached. */
1193 /* GV otherwise, the thread handle is not destroyed */
1194 pthread_attr_init(&detachedAttribute);
1195 pthread_attr_setdetachstate(&detachedAttribute, PTHREAD_CREATE_DETACHED);
1196
1197 // Now we have to create a new thread to receive packets
1198 if (pthread_create(threaddata, &detachedAttribute, (void *) daemon_thrdatamain, (void *) session))
1199 {
1200 snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error creating the data thread");
1201 pthread_attr_destroy(&detachedAttribute);
1202 goto error;
1203 }
1204
1205 pthread_attr_destroy(&detachedAttribute);
1206 // Check if all the data has been read; if not, discard the data in excess
1207 if (totread != plen)
1208 sock_discard(sockctrl, plen - totread, NULL, 0);
1209
1210 return session;
1211
1212 error:
1213 rpcap_senderror(sockctrl, errbuf, PCAP_ERR_STARTCAPTURE, NULL);
1214
1215 if (addrinfo)
1216 freeaddrinfo(addrinfo);
1217
1218 if (threaddata)
1219 pthread_cancel(*threaddata);
1220
1221 if (sockdata)
1222 sock_close(sockdata, NULL, 0);
1223
1224 // Check if all the data has been read; if not, discard the data in excess
1225 if (totread != plen)
1226 sock_discard(sockctrl, plen - totread, NULL, 0);
1227
1228 if (session->fp)
1229 {
1230 pcap_close(session->fp);
1231 }
1232 free(session);
1233
1234 return NULL;
1235 }
1236
1237 static int daemon_endcapture(struct session *session, pthread_t *threaddata, char *errbuf)
1238 {
1239 struct rpcap_header header;
1240
1241 if (threaddata)
1242 {
1243 pthread_cancel(*threaddata);
1244 threaddata = 0;
1245 }
1246 if (session->sockdata)
1247 {
1248 sock_close(session->sockdata, NULL, 0);
1249 session->sockdata = 0;
1250 }
1251
1252 pcap_close(session->fp);
1253
1254 rpcap_createhdr(&header, RPCAP_MSG_ENDCAP_REPLY, 0, 0);
1255
1256 if (sock_send(session->sockctrl, (char *) &header, sizeof(struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE) == -1)
1257 return -1;
1258
1259 return 0;
1260 }
1261
1262 static int daemon_unpackapplyfilter(struct session *session, uint32 *totread, uint32 *plen, char *errbuf)
1263 {
1264 ssize_t nread;
1265 struct rpcap_filter filter;
1266 struct rpcap_filterbpf_insn insn;
1267 struct bpf_insn *bf_insn;
1268 struct bpf_program bf_prog;
1269 unsigned int i;
1270
1271 nread = sock_recv(session->sockctrl, (char *) &filter,
1272 sizeof(struct rpcap_filter), SOCK_RECEIVEALL_YES,
1273 errbuf, PCAP_ERRBUF_SIZE);
1274 if (nread == -1)
1275 {
1276 // to avoid blocking on the sock_discard()
1277 *plen = *totread;
1278 return -1;
1279 }
1280 *totread += nread;
1281
1282 bf_prog.bf_len = ntohl(filter.nitems);
1283
1284 if (ntohs(filter.filtertype) != RPCAP_UPDATEFILTER_BPF)
1285 {
1286 snprintf(errbuf, PCAP_ERRBUF_SIZE, "Only BPF/NPF filters are currently supported");
1287 return -1;
1288 }
1289
1290 bf_insn = (struct bpf_insn *) malloc (sizeof(struct bpf_insn) * bf_prog.bf_len);
1291 if (bf_insn == NULL)
1292 {
1293 snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno));
1294 return -1;
1295 }
1296
1297 bf_prog.bf_insns = bf_insn;
1298
1299 for (i = 0; i < bf_prog.bf_len; i++)
1300 {
1301 nread = sock_recv(session->sockctrl, (char *) &insn,
1302 sizeof(struct rpcap_filterbpf_insn), SOCK_RECEIVEALL_YES,
1303 errbuf, PCAP_ERRBUF_SIZE);
1304 if (nread == -1)
1305 return -1;
1306 *totread += nread;
1307
1308 bf_insn->code = ntohs(insn.code);
1309 bf_insn->jf = insn.jf;
1310 bf_insn->jt = insn.jt;
1311 bf_insn->k = ntohl(insn.k);
1312
1313 bf_insn++;
1314 }
1315
1316 if (bpf_validate(bf_prog.bf_insns, bf_prog.bf_len) == 0)
1317 {
1318 snprintf(errbuf, PCAP_ERRBUF_SIZE, "The filter contains bogus instructions");
1319 return -1;
1320 }
1321
1322 if (pcap_setfilter(session->fp, &bf_prog))
1323 {
1324 snprintf(errbuf, PCAP_ERRBUF_SIZE, "RPCAP error: %s", pcap_geterr(session->fp));
1325 return -1;
1326 }
1327
1328 return 0;
1329 }
1330
1331 int daemon_updatefilter(struct session *session, uint32 plen)
1332 {
1333 struct rpcap_header header; // keeps the answer to the updatefilter command
1334 unsigned int nread;
1335
1336 nread = 0;
1337
1338 if (daemon_unpackapplyfilter(session, &nread, &plen, pcap_geterr(session->fp)))
1339 goto error;
1340
1341 // Check if all the data has been read; if not, discard the data in excess
1342 if (nread != plen)
1343 {
1344 if (sock_discard(session->sockctrl, plen - nread, NULL, 0))
1345 {
1346 nread = plen; // just to avoid to call discard again in the 'error' section
1347 goto error;
1348 }
1349 }
1350
1351 // A response is needed, otherwise the other host does not know that everything went well
1352 rpcap_createhdr(&header, RPCAP_MSG_UPDATEFILTER_REPLY, 0, 0);
1353
1354 if (sock_send(session->sockctrl, (char *) &header, sizeof (struct rpcap_header), pcap_geterr(session->fp), PCAP_ERRBUF_SIZE))
1355 goto error;
1356
1357 return 0;
1358
1359
1360 error:
1361 if (nread != plen)
1362 sock_discard(session->sockctrl, plen - nread, NULL, 0);
1363
1364 rpcap_senderror(session->sockctrl, pcap_geterr(session->fp), PCAP_ERR_UPDATEFILTER, NULL);
1365
1366 return -1;
1367 }
1368
1369 /*!
1370 \brief Received the sampling parameters from remote host and it stores in the pcap_t structure.
1371 */
1372 int daemon_setsampling(SOCKET sockctrl, struct rpcap_sampling *samp_param, int plen, char *errbuf)
1373 {
1374 struct rpcap_header header;
1375 struct rpcap_sampling rpcap_samp;
1376 int nread; // number of bytes of the payload read from the socket
1377
1378 if ((nread = sock_recv(sockctrl, (char *) &rpcap_samp, sizeof(struct rpcap_sampling),
1379 SOCK_RECEIVEALL_YES, errbuf, PCAP_ERRBUF_SIZE)) == -1)
1380 goto error;
1381
1382 // Save these settings in the pcap_t
1383 samp_param->method = rpcap_samp.method;
1384 samp_param->value = ntohl(rpcap_samp.value);
1385
1386 // A response is needed, otherwise the other host does not know that everything went well
1387 rpcap_createhdr(&header, RPCAP_MSG_SETSAMPLING_REPLY, 0, 0);
1388
1389 if (sock_send(sockctrl, (char *) &header, sizeof (struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE))
1390 goto error;
1391
1392 if (nread != plen)
1393 sock_discard(sockctrl, plen - nread, NULL, 0);
1394
1395 return 0;
1396
1397 error:
1398 if (nread != plen)
1399 sock_discard(sockctrl, plen - nread, NULL, 0);
1400
1401 rpcap_senderror(sockctrl, errbuf, PCAP_ERR_SETSAMPLING, NULL);
1402
1403 return -1;
1404 }
1405
1406 int daemon_getstats(struct session *session)
1407 {
1408 char sendbuf[RPCAP_NETBUF_SIZE]; // temporary buffer in which data to be sent is buffered
1409 int sendbufidx = 0; // index which keeps the number of bytes currently buffered
1410 struct pcap_stat stats; // local statistics
1411 struct rpcap_stats *netstats; // statistics sent on the network
1412
1413 if (sock_bufferize(NULL, sizeof(struct rpcap_header), NULL,
1414 &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, pcap_geterr(session->fp), PCAP_ERRBUF_SIZE) == -1)
1415 goto error;
1416
1417 rpcap_createhdr((struct rpcap_header *) sendbuf, RPCAP_MSG_STATS_REPLY, 0, (uint16) sizeof(struct rpcap_stats));
1418
1419 netstats = (struct rpcap_stats *) &sendbuf[sendbufidx];
1420
1421 if (sock_bufferize(NULL, sizeof(struct rpcap_stats), NULL,
1422 &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, pcap_geterr(session->fp), PCAP_ERRBUF_SIZE) == -1)
1423 goto error;
1424
1425 if (pcap_stats(session->fp, &stats))
1426 goto error;
1427
1428 netstats->ifdrop = htonl(stats.ps_ifdrop);
1429 netstats->ifrecv = htonl(stats.ps_recv);
1430 netstats->krnldrop = htonl(stats.ps_drop);
1431 netstats->svrcapt = htonl(session->TotCapt);
1432
1433 // Send the packet
1434 if (sock_send(session->sockctrl, sendbuf, sendbufidx, pcap_geterr(session->fp), PCAP_ERRBUF_SIZE) == -1)
1435 goto error;
1436
1437 return 0;
1438
1439 error:
1440 rpcap_senderror(session->sockctrl, pcap_geterr(session->fp), PCAP_ERR_GETSTATS, NULL);
1441 return -1;
1442 }
1443
1444 int daemon_getstatsnopcap(SOCKET sockctrl, unsigned int ifdrops, unsigned int ifrecv,
1445 unsigned int krnldrop, unsigned int svrcapt, char *errbuf)
1446 {
1447 char sendbuf[RPCAP_NETBUF_SIZE]; // temporary buffer in which data to be sent is buffered
1448 int sendbufidx = 0; // index which keeps the number of bytes currently buffered
1449 struct rpcap_stats *netstats; // statistics sent on the network
1450
1451 if (sock_bufferize(NULL, sizeof(struct rpcap_header), NULL,
1452 &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE) == -1)
1453 goto error;
1454
1455 rpcap_createhdr((struct rpcap_header *) sendbuf, RPCAP_MSG_STATS_REPLY, 0, (uint16) sizeof(struct rpcap_stats));
1456
1457 netstats = (struct rpcap_stats *) &sendbuf[sendbufidx];
1458
1459 if (sock_bufferize(NULL, sizeof(struct rpcap_stats), NULL,
1460 &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE) == -1)
1461 goto error;
1462
1463 netstats->ifdrop = htonl(ifdrops);
1464 netstats->ifrecv = htonl(ifrecv);
1465 netstats->krnldrop = htonl(krnldrop);
1466 netstats->svrcapt = htonl(svrcapt);
1467
1468 // Send the packet
1469 if (sock_send(sockctrl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
1470 goto error;
1471
1472 return 0;
1473
1474 error:
1475 rpcap_senderror(sockctrl, errbuf, PCAP_ERR_GETSTATS, NULL);
1476 return -1;
1477 }
1478
1479 void *daemon_thrdatamain(void *ptr)
1480 {
1481 char errbuf[PCAP_ERRBUF_SIZE + 1]; // error buffer
1482 struct session *session; // pointer to the struct session for this session
1483 int retval; // general variable used to keep the return value of other functions
1484 struct rpcap_pkthdr *net_pkt_header;// header of the packet
1485 struct pcap_pkthdr *pkt_header; // pointer to the buffer that contains the header of the current packet
1486 u_char *pkt_data; // pointer to the buffer that contains the current packet
1487 char *sendbuf; // temporary buffer in which data to be sent is buffered
1488 int sendbufidx; // index which keeps the number of bytes currently buffered
1489
1490 session = (struct session *) ptr;
1491
1492 session->TotCapt = 0; // counter which is incremented each time a packet is received
1493
1494 // Initialize errbuf
1495 memset(errbuf, 0, sizeof(errbuf));
1496
1497 // Some platforms (e.g. Win32) allow creating a static variable with this size
1498 // However, others (e.g. BSD) do not, so we're forced to allocate this buffer dynamically
1499 sendbuf = (char *) malloc (sizeof(char) * RPCAP_NETBUF_SIZE);
1500 if (sendbuf == NULL)
1501 {
1502 snprintf(errbuf, sizeof(errbuf) - 1, "Unable to create the buffer for this child thread");
1503 goto error;
1504 }
1505
1506 // Modify thread params so that it can be killed at any time
1507 if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL))
1508 goto error;
1509 if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL))
1510 goto error;
1511
1512 // Retrieve the packets
1513 while ((retval = pcap_next_ex(session->fp, &pkt_header, (const u_char **) &pkt_data)) >= 0) // cast to avoid a compiler warning
1514 {
1515 if (retval == 0) // Read timeout elapsed
1516 continue;
1517
1518 sendbufidx = 0;
1519
1520 // Bufferize the general header
1521 if (sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, &sendbufidx,
1522 RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE) == -1)
1523 goto error;
1524
1525 rpcap_createhdr((struct rpcap_header *) sendbuf, RPCAP_MSG_PACKET, 0,
1526 (uint16) (sizeof(struct rpcap_pkthdr) + pkt_header->caplen));
1527
1528 net_pkt_header = (struct rpcap_pkthdr *) &sendbuf[sendbufidx];
1529
1530 // Bufferize the pkt header
1531 if (sock_bufferize(NULL, sizeof(struct rpcap_pkthdr), NULL, &sendbufidx,
1532 RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE) == -1)
1533 goto error;
1534
1535 net_pkt_header->caplen = htonl(pkt_header->caplen);
1536 net_pkt_header->len = htonl(pkt_header->len);
1537 net_pkt_header->npkt = htonl(++(session->TotCapt));
1538 net_pkt_header->timestamp_sec = htonl(pkt_header->ts.tv_sec);
1539 net_pkt_header->timestamp_usec = htonl(pkt_header->ts.tv_usec);
1540
1541 // Bufferize the pkt data
1542 if (sock_bufferize((char *) pkt_data, pkt_header->caplen, sendbuf, &sendbufidx,
1543 RPCAP_NETBUF_SIZE, SOCKBUF_BUFFERIZE, errbuf, PCAP_ERRBUF_SIZE) == -1)
1544 goto error;
1545
1546 // Send the packet
1547 if (sock_send(session->sockdata, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
1548 goto error;
1549
1550 }
1551
1552 if (retval == -1)
1553 {
1554 snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error reading the packets: %s", pcap_geterr(session->fp));
1555 rpcap_senderror(session->sockctrl, errbuf, PCAP_ERR_READEX, NULL);
1556 goto error;
1557 }
1558
1559 error:
1560
1561 SOCK_ASSERT(errbuf, 1);
1562 closesocket(session->sockdata);
1563 session->sockdata = 0;
1564
1565 free(sendbuf);
1566
1567 return NULL;
1568 }
1569
1570 /*!
1571 \brief It serializes a network address.
1572
1573 It accepts a 'sockaddr_storage' structure as input, and it converts it appropriately into a format
1574 that can be used to be sent on the network. Basically, it applies all the hton()
1575 conversion required to the input variable.
1576
1577 \param sockaddrin: a 'sockaddr_storage' pointer to the variable that has to be
1578 serialized. This variable can be both a 'sockaddr_in' and 'sockaddr_in6'.
1579
1580 \param sockaddrout: an 'rpcap_sockaddr' pointer to the variable that will contain
1581 the serialized data. This variable has to be allocated by the user.
1582
1583 \return None
1584
1585 \warning This function supports only AF_INET and AF_INET6 address families.
1586 */
1587 void daemon_seraddr(struct sockaddr_storage *sockaddrin, struct rpcap_sockaddr *sockaddrout)
1588 {
1589 memset(sockaddrout, 0, sizeof(struct sockaddr_storage));
1590
1591 // There can be the case in which the sockaddrin is not available
1592 if (sockaddrin == NULL) return;
1593
1594 // Warning: we support only AF_INET and AF_INET6
1595 switch (sockaddrin->ss_family)
1596 {
1597 case AF_INET:
1598 {
1599 struct sockaddr_in *sockaddrin_ipv4;
1600 struct rpcap_sockaddr_in *sockaddrout_ipv4;
1601
1602 sockaddrin_ipv4 = (struct sockaddr_in *) sockaddrin;
1603 sockaddrout_ipv4 = (struct rpcap_sockaddr_in *) sockaddrout;
1604 sockaddrout_ipv4->family = htons(RPCAP_AF_INET);
1605 sockaddrout_ipv4->port = htons(sockaddrin_ipv4->sin_port);
1606 memcpy(&sockaddrout_ipv4->addr, &sockaddrin_ipv4->sin_addr, sizeof(sockaddrout_ipv4->addr));
1607 memset(sockaddrout_ipv4->zero, 0, sizeof(sockaddrout_ipv4->zero));
1608 break;
1609 }
1610
1611 #ifdef AF_INET6
1612 case AF_INET6:
1613 {
1614 struct sockaddr_in6 *sockaddrin_ipv6;
1615 struct rpcap_sockaddr_in6 *sockaddrout_ipv6;
1616
1617 sockaddrin_ipv6 = (struct sockaddr_in6 *) sockaddrin;
1618 sockaddrout_ipv6 = (struct rpcap_sockaddr_in6 *) sockaddrout;
1619 sockaddrout_ipv6->family = htons(RPCAP_AF_INET6);
1620 sockaddrout_ipv6->port = htons(sockaddrin_ipv6->sin6_port);
1621 sockaddrout_ipv6->flowinfo = htonl(sockaddrin_ipv6->sin6_flowinfo);
1622 memcpy(&sockaddrout_ipv6->addr, &sockaddrin_ipv6->sin6_addr, sizeof(sockaddrout_ipv6->addr));
1623 sockaddrout_ipv6->scope_id = htonl(sockaddrin_ipv6->sin6_scope_id);
1624 break;
1625 }
1626 #endif
1627 }
1628 }
1629
1630 /*!
1631 \brief Suspends a pthread for msec milliseconds.
1632
1633 This function is provided since pthreads do not have a suspend() call.
1634 */
1635 void pthread_suspend(int msec)
1636 {
1637 #ifdef _WIN32
1638 Sleep(msec);
1639 #else
1640 struct timespec abstime;
1641 struct timeval now;
1642
1643 pthread_cond_t cond;
1644 pthread_mutex_t mutex;
1645 pthread_mutexattr_t attr;
1646
1647 pthread_mutexattr_init(&attr);
1648 pthread_mutex_init(&mutex, &attr);
1649 pthread_mutex_lock(&mutex);
1650
1651 pthread_cond_init(&cond, NULL);
1652
1653 gettimeofday(&now, NULL);
1654
1655 abstime.tv_sec = now.tv_sec + msec/1000;
1656 abstime.tv_nsec = now.tv_usec * 1000 + (msec%1000) * 1000 * 1000;
1657
1658 pthread_cond_timedwait(&cond, &mutex, &abstime);
1659
1660 pthread_mutex_destroy(&mutex);
1661 pthread_cond_destroy(&cond);
1662 #endif
1663 }