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