2 * Copyright (c) 2002 - 2003
3 * NetGroup, Politecnico di Torino (Italy)
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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.
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(), ...
43 #include "sockutils.h" // for socket calls
44 #include "rpcap-protocol.h"
45 #include "pcap-rpcap-int.h"
48 #ifndef _WIN32 // for select() and such
51 #include <sys/types.h>
52 #include <pwd.h> // for password management
56 #include <shadow.h> // for password management
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 */
64 * Data for a session managed by a thread.
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
);
77 static int daemon_findalldevs(SOCKET sockctrl
, char *errbuf
);
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
);
84 static int daemon_updatefilter(struct session
*session
, uint32 plen
);
85 static int daemon_unpackapplyfilter(struct session
*session
, uint32
*totread
, uint32
*plen
, char *errbuf
);
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
);
91 static int daemon_setsampling(SOCKET sockctrl
, struct rpcap_sampling
*samp_param
, int plen
, char *errbuf
);
93 static void daemon_seraddr(struct sockaddr_storage
*sockaddrin
, struct rpcap_sockaddr
*sockaddrout
);
94 static void *daemon_thrdatamain(void *ptr
);
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.
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.
108 void daemon_serviceloop(void *ptr
)
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
116 pthread_t threaddata
= 0; // handle to the 'read from daemon and send to client' thread
118 unsigned int ifdrops
, ifrecv
, krnldrop
, svrcapt
; // needed to save the values of the statistics
120 struct rpcap_sampling samp_param
; // in case sampling has been requested
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
127 pars
= (struct daemon_slpars
*) ptr
;
129 *errbuf
= 0; // Initialize errbuf
131 // If we're in active mode, this is not a separate thread
132 if (! pars
->isactive
)
134 // Modify thread params so that it can be killed at any time
135 if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE
, NULL
))
137 if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS
, NULL
))
142 // If we're in active mode, we have to check for the initial timeout
146 // We do not have to block here
147 tv
.tv_sec
= RPCAP_TIMEOUT_INIT
;
150 FD_SET(pars
->sockctrl
, &rfds
);
152 retval
= select(pars
->sockctrl
+ 1, &rfds
, NULL
, NULL
, &tv
);
155 sock_geterror("select(): ", errbuf
, PCAP_ERRBUF_SIZE
);
156 rpcap_senderror(pars
->sockctrl
, errbuf
, PCAP_ERR_NETW
, NULL
);
160 // The timeout has expired
161 // So, this was a fake connection. Drop it down
164 rpcap_senderror(pars
->sockctrl
, "The RPCAP initial timeout has expired", PCAP_ERR_INITTIMEOUT
, NULL
);
169 retval
= daemon_checkauth(pars
->sockctrl
, pars
->nullAuthAllowed
, errbuf
);
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
179 // It can be an authentication failure or an unrecoverable error
180 rpcap_senderror(pars
->sockctrl
, errbuf
, PCAP_ERR_AUTH
, NULL
);
182 // authentication error
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);
192 // Unrecoverable error
199 errbuf
[0] = 0; // clear errbuf
201 // Avoid zombies connections; check if the connection is opens but no commands are performed
202 // from more than RPCAP_TIMEOUT_RUNTIME
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
208 // Be carefully: the capture can have been started, but an error occurred (so session != NULL, but
210 if ((!pars
->isactive
) && ((session
== NULL
) || ((session
!= NULL
) && (session
->sockdata
== 0))))
212 // Check for the initial timeout
214 // We do not have to block here
215 tv
.tv_sec
= RPCAP_TIMEOUT_RUNTIME
;
218 FD_SET(pars
->sockctrl
, &rfds
);
220 retval
= select(pars
->sockctrl
+ 1, &rfds
, NULL
, NULL
, &tv
);
223 sock_geterror("select(): ", errbuf
, PCAP_ERRBUF_SIZE
);
224 rpcap_senderror(pars
->sockctrl
, errbuf
, PCAP_ERR_NETW
, NULL
);
228 // The timeout has expired
229 // So, this was a fake connection. Drop it down
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
);
238 if (sock_recv(pars
->sockctrl
, (char *) &header
, sizeof(struct rpcap_header
), SOCK_RECEIVEALL_YES
, errbuf
, PCAP_ERRBUF_SIZE
) == -1)
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
,
246 RPCAP_MSG_STARTCAP_REQ
,
247 RPCAP_MSG_UPDATEFILTER_REQ
,
249 RPCAP_MSG_ENDCAP_REQ
,
250 RPCAP_MSG_SETSAMPLING_REQ
,
257 case -3: // Unrecoverable network error
258 goto end
; // Do nothing; just exit from findalldevs; the error code is already into the errbuf
260 case -2: // The other endpoint send a message that is not allowed here
262 rpcap_senderror(pars
->sockctrl
, "The RPCAP daemon received a message that is not valid", PCAP_ERR_WRONGMSG
, errbuf
);
264 case -1: // The other endpoint has a version number that is not compatible with our
266 rpcap_senderror(pars
->sockctrl
, "RPCAP version number mismatch", PCAP_ERR_WRONGVER
, errbuf
);
270 case RPCAP_MSG_FINDALLIF_REQ
:
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
);
276 if (daemon_findalldevs(pars
->sockctrl
, errbuf
))
277 SOCK_ASSERT(errbuf
, 1);
282 case RPCAP_MSG_OPEN_REQ
:
284 retval
= daemon_opensource(pars
->sockctrl
, source
, sizeof(source
), ntohl(header
.plen
), errbuf
);
287 SOCK_ASSERT(errbuf
, 1);
292 case RPCAP_MSG_SETSAMPLING_REQ
:
294 retval
= daemon_setsampling(pars
->sockctrl
, &samp_param
, ntohl(header
.plen
), errbuf
);
297 SOCK_ASSERT(errbuf
, 1);
302 case RPCAP_MSG_STARTCAP_REQ
:
304 session
= daemon_startcapture(pars
->sockctrl
, &threaddata
, source
, pars
->isactive
, &samp_param
, ntohl(header
.plen
), errbuf
);
307 SOCK_ASSERT(errbuf
, 1);
312 case RPCAP_MSG_UPDATEFILTER_REQ
:
316 if (daemon_updatefilter(session
, ntohl(header
.plen
)))
317 SOCK_ASSERT(pcap_geterr(session
->fp
), 1);
321 rpcap_senderror(pars
->sockctrl
, "Device not opened. Cannot update filter", PCAP_ERR_UPDATEFILTER
, errbuf
);
327 case RPCAP_MSG_STATS_REQ
:
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
);
333 if (session
&& session
->fp
)
335 if (daemon_getstats(session
))
336 SOCK_ASSERT(pcap_geterr(session
->fp
), 1);
340 SOCK_ASSERT("GetStats: this call should't be allowed here", 1);
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
347 // rpcap_senderror(pars->sockctrl, "Device not opened. Cannot get statistics", PCAP_ERR_GETSTATS, errbuf);
353 case RPCAP_MSG_ENDCAP_REQ
: // The other endpoint close the current capture session
355 if (session
&& session
->fp
)
357 struct pcap_stat stats
;
359 // Save statistics (we can need them in the future)
360 if (pcap_stats(session
->fp
, &stats
))
362 ifdrops
= stats
.ps_ifdrop
;
363 ifrecv
= stats
.ps_recv
;
364 krnldrop
= stats
.ps_drop
;
365 svrcapt
= session
->TotCapt
;
368 ifdrops
= ifrecv
= krnldrop
= svrcapt
= 0;
370 if (daemon_endcapture(session
, &threaddata
, errbuf
))
371 SOCK_ASSERT(pcap_geterr(session
->fp
), 1);
377 rpcap_senderror(pars
->sockctrl
, "Device not opened. Cannot close the capture", PCAP_ERR_ENDCAPTURE
, errbuf
);
382 case RPCAP_MSG_CLOSE
: // The other endpoint close the pcap session
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);
392 case RPCAP_MSG_ERROR
: // The other endpoint reported an error
394 // Do nothing; just exit; the error code is already into the errbuf
395 SOCK_ASSERT(errbuf
, 1);
401 SOCK_ASSERT("Internal error.", 1);
408 // The child thread is about to end
410 // perform pcap_t cleanup, in case it has not been done
415 pthread_cancel(threaddata
);
418 if (session
->sockdata
)
420 sock_close(session
->sockdata
, NULL
, 0);
421 session
->sockdata
= 0;
423 pcap_close(session
->fp
);
428 // Print message and exit
429 SOCK_ASSERT("I'm exiting from the child loop", 1);
430 SOCK_ASSERT(errbuf
, 1);
435 sock_close(pars
->sockctrl
, NULL
, 0);
445 \brief It checks if the authentication credentials supplied by the user are valid.
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.
451 \param sockctrl: the socket if of the control connection.
453 \param nullAuthAllowed: '1' if the NULL authentication is allowed.
455 \param errbuf: a user-allocated buffer in which the error message (if one) has to be written.
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.
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
467 int daemon_checkauth(SOCKET sockctrl
, int nullAuthAllowed
, char *errbuf
)
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
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
478 if (sock_recv(sockctrl
, (char *) &header
, sizeof(struct rpcap_header
), SOCK_RECEIVEALL_YES
, errbuf
, PCAP_ERRBUF_SIZE
) == -1)
481 plen
= ntohl(header
.plen
);
483 retval
= rpcap_checkmsg(errbuf
, sockctrl
, &header
,
488 if (retval
!= RPCAP_MSG_AUTH_REQ
)
492 case -3: // Unrecoverable network error
493 return -1; // Do nothing; just exit; the error code is already into the errbuf
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
499 case RPCAP_MSG_CLOSE
:
501 // Check if all the data has been read; if not, discard the data in excess
502 if (ntohl(header
.plen
))
504 if (sock_discard(sockctrl
, ntohl(header
.plen
), NULL
, 0))
510 case RPCAP_MSG_ERROR
:
515 SOCK_ASSERT("Internal error.", 1);
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
);
532 switch (ntohs(auth
.type
))
534 case RPCAP_RMTAUTH_NULL
:
536 if (!nullAuthAllowed
)
538 snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "Authentication failed; NULL autentication not permitted.");
545 case RPCAP_RMTAUTH_PWD
:
549 len1
= ntohs(auth
.slen1
);
550 len2
= ntohs(auth
.slen2
);
552 string1
= (char *) malloc (len1
+ 1);
553 string2
= (char *) malloc (len2
+ 1);
555 if ((string1
== NULL
) || (string2
== NULL
))
557 snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "malloc() failed: %s", pcap_strerror(errno
));
562 nread
= sock_recv(sockctrl
, string1
, len1
,
563 SOCK_RECEIVEALL_YES
, errbuf
, PCAP_ERRBUF_SIZE
);
570 nread
= sock_recv(sockctrl
, string2
, len2
,
571 SOCK_RECEIVEALL_YES
, errbuf
, PCAP_ERRBUF_SIZE
);
582 if (daemon_AuthUserPwd(string1
, string2
, errbuf
))
592 snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "Authentication type not recognized.");
598 // Check if all the data has been read; if not, discard the data in excess
601 if (sock_discard(sockctrl
, plen
- totread
, NULL
, 0))
608 rpcap_createhdr(&header
, RPCAP_MSG_AUTH_REPLY
, 0, 0);
610 // Send the ok message back
611 if (sock_send(sockctrl
, (char *) &header
, sizeof (struct rpcap_header
), errbuf
, PCAP_ERRBUF_SIZE
) == -1)
620 // Check if all the data has been read; if not, discard the data in excess
622 sock_discard(sockctrl
, plen
- totread
, NULL
, 0);
627 int daemon_AuthUserPwd(char *username
, char *password
, char *errbuf
)
631 * Warning: the user which launches the process must have the
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.
640 if (LogonUser(username
, ".", password
, LOGON32_LOGON_NETWORK
, LOGON32_PROVIDER_DEFAULT
, &Token
) == 0)
644 error
= GetLastError();
645 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
, NULL
, error
, 0, errbuf
,
646 PCAP_ERRBUF_SIZE
, NULL
);
651 // This call should change the current thread to the selected user.
653 if (ImpersonateLoggedOnUser(Token
) == 0)
657 error
= GetLastError();
658 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
, NULL
, error
, 0, errbuf
,
659 PCAP_ERRBUF_SIZE
, NULL
);
670 * Standard user authentication:
672 * http://www.unixpapa.com/incnote/passwd.html
674 * Problem: it is not able to merge the standard pwd file with
677 * Shadow user authentication:
679 * http://www.tldp.org/HOWTO/Shadow-Password-HOWTO-8.html
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
690 // This call is needed to get the uid
691 if ((user
= getpwnam(username
)) == NULL
)
693 snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "Authentication failed: no such user");
698 // This call is needed to get the password; otherwise 'x' is returned
699 if ((usersp
= getspnam(username
)) == NULL
)
701 snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "Authentication failed: no such user");
705 if (strcmp(usersp
->sp_pwdp
, (char *) crypt(password
, usersp
->sp_pwdp
)) != 0)
707 snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "Authentication failed: password incorrect");
713 if (strcmp(user
->pw_passwd
, (char *) crypt(password
, user
->pw_passwd
)) != 0)
715 snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "Authentication failed: password incorrect");
720 if (setuid(user
->pw_uid
))
722 snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "%s", pcap_strerror(errno
));
726 /* if (setgid(user->pw_gid))
728 SOCK_ASSERT("setgid failed", 1);
729 snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s", pcap_strerror(errno));
739 // PORTING WARNING We assume u_int is a 32bit value
740 int daemon_findalldevs(SOCKET sockctrl
, char *errbuf
)
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
751 // Retrieve the device list
752 if (pcap_findalldevs(&alldevs
, errbuf
) == -1)
754 rpcap_senderror(sockctrl
, errbuf
, PCAP_ERR_FINDALLIF
, NULL
);
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.",
768 // checks the number of interfaces and it computes the total length of the payload
769 for (d
= alldevs
; d
!= NULL
; d
= d
->next
)
774 plen
+= strlen(d
->description
);
776 plen
+= strlen(d
->name
);
778 plen
+= sizeof(struct rpcap_findalldevs_if
);
780 for (address
= d
->addresses
; address
!= NULL
; address
= address
->next
)
783 * Send only IPv4 and IPv6 addresses over the wire.
785 switch (address
->addr
->sa_family
)
791 plen
+= (sizeof(struct rpcap_sockaddr
) * 4);
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)
805 rpcap_createhdr((struct rpcap_header
*) sendbuf
, RPCAP_MSG_FINDALLIF_REPLY
, nif
, plen
);
807 // send the interface list
808 for (d
= alldevs
; d
!= NULL
; d
= d
->next
)
810 uint16 lname
, ldescr
;
812 findalldevs_if
= (struct rpcap_findalldevs_if
*) &sendbuf
[sendbufidx
];
814 if (sock_bufferize(NULL
, sizeof(struct rpcap_findalldevs_if
), NULL
,
815 &sendbufidx
, RPCAP_NETBUF_SIZE
, SOCKBUF_CHECKONLY
, errbuf
, PCAP_ERRBUF_SIZE
) == -1)
818 memset(findalldevs_if
, 0, sizeof(struct rpcap_findalldevs_if
));
820 if (d
->description
) ldescr
= (short) strlen(d
->description
);
822 if (d
->name
) lname
= (short) strlen(d
->name
);
825 findalldevs_if
->desclen
= htons(ldescr
);
826 findalldevs_if
->namelen
= htons(lname
);
827 findalldevs_if
->flags
= htonl(d
->flags
);
829 for (address
= d
->addresses
; address
!= NULL
; address
= address
->next
)
832 * Send only IPv4 and IPv6 addresses over the wire.
834 switch (address
->addr
->sa_family
)
840 findalldevs_if
->naddr
++;
847 findalldevs_if
->naddr
= htons(findalldevs_if
->naddr
);
849 if (sock_bufferize(d
->name
, lname
, sendbuf
, &sendbufidx
,
850 RPCAP_NETBUF_SIZE
, SOCKBUF_BUFFERIZE
, errbuf
, PCAP_ERRBUF_SIZE
) == -1)
853 if (sock_bufferize(d
->description
, ldescr
, sendbuf
, &sendbufidx
,
854 RPCAP_NETBUF_SIZE
, SOCKBUF_BUFFERIZE
, errbuf
, PCAP_ERRBUF_SIZE
) == -1)
857 // send all addresses
858 for (address
= d
->addresses
; address
!= NULL
; address
= address
->next
)
860 struct rpcap_sockaddr
*sockaddr
;
863 * Send only IPv4 and IPv6 addresses over the wire.
865 switch (address
->addr
->sa_family
)
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)
875 daemon_seraddr((struct sockaddr_storage
*) address
->addr
, sockaddr
);
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)
881 daemon_seraddr((struct sockaddr_storage
*) address
->netmask
, sockaddr
);
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)
887 daemon_seraddr((struct sockaddr_storage
*) address
->broadaddr
, sockaddr
);
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)
893 daemon_seraddr((struct sockaddr_storage
*) address
->dstaddr
, sockaddr
);
902 // Send a final command that says "now send it!"
903 if (sock_send(sockctrl
, sendbuf
, sendbufidx
, errbuf
, PCAP_ERRBUF_SIZE
) == -1)
906 // We do no longer need the device list. Free it
907 pcap_freealldevs(alldevs
);
909 // everything is fine
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)
917 static int daemon_opensource(SOCKET sockctrl
, char *source
, int srclen
, uint32 plen
, char *errbuf
)
919 pcap_t
*fp
= NULL
; // pcap_t main variable
920 uint32 totread
; // number of bytes of the payload read from the socket
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
926 strcpy(source
, PCAP_SRC_IF_STRING
);
928 if (srclen
<= (int) (strlen(PCAP_SRC_IF_STRING
) + plen
))
930 rpcap_senderror(sockctrl
, "Source string too long", PCAP_ERR_OPEN
, NULL
);
934 nread
= sock_recv(sockctrl
, &source
[strlen(PCAP_SRC_IF_STRING
)], plen
,
935 SOCK_RECEIVEALL_YES
, errbuf
, PCAP_ERRBUF_SIZE
);
940 // Check if all the data has been read; if not, discard the data in excess
942 sock_discard(sockctrl
, plen
- totread
, NULL
, 0);
944 // Puts a '0' to terminate the source string
945 source
[strlen(PCAP_SRC_IF_STRING
) + plen
] = 0;
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 */,
952 1000 /* fake timeout */,
955 rpcap_senderror(sockctrl
, errbuf
, PCAP_ERR_OPEN
, NULL
);
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)
965 rpcap_createhdr((struct rpcap_header
*) sendbuf
, RPCAP_MSG_OPEN_REPLY
, 0, sizeof(struct rpcap_openreply
));
967 openreply
= (struct rpcap_openreply
*) &sendbuf
[sendbufidx
];
969 if (sock_bufferize(NULL
, sizeof(struct rpcap_openreply
), NULL
, &sendbufidx
,
970 RPCAP_NETBUF_SIZE
, SOCKBUF_CHECKONLY
, errbuf
, PCAP_ERRBUF_SIZE
) == -1)
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 */
977 if (sock_send(sockctrl
, sendbuf
, sendbufidx
, errbuf
, PCAP_ERRBUF_SIZE
) == -1)
980 // I have to close the device again, since it has been opened with wrong parameters
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)
1000 static struct session
*daemon_startcapture(SOCKET sockctrl
, pthread_t
*threaddata
, char *source
, int active
, struct rpcap_sampling
*samp_param
, uint32 plen
, char *errbuf
)
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
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
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
1017 pthread_attr_t detachedAttribute
; // temp, needed to set the created thread as detached
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
1026 nread
= sock_recv(sockctrl
, (char *) &startcapreq
,
1027 sizeof(struct rpcap_startcapreq
), SOCK_RECEIVEALL_YES
,
1028 errbuf
, PCAP_ERRBUF_SIZE
);
1033 startcapreq
.flags
= ntohs(startcapreq
.flags
);
1035 // Create a session structure
1036 session
= malloc(sizeof(struct session
));
1037 if (session
== NULL
)
1039 rpcap_senderror(sockctrl
, "Can't allocate session structure",
1040 PCAP_ERR_OPEN
, NULL
);
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 */,
1052 rpcap_senderror(sockctrl
, errbuf
, PCAP_ERR_OPEN
, NULL
);
1057 // Apply sampling parameters
1058 fp
->rmt_samp
.method
= samp_param
->method
;
1059 fp
->rmt_samp
.value
= samp_param
->value
;
1063 We're in active mode if:
1064 - we're using TCP, and the user wants us to be in active mode
1067 serveropen_dp
= (startcapreq
.flags
& RPCAP_STARTCAPREQ_FLAG_SERVEROPEN
) || (startcapreq
.flags
& RPCAP_STARTCAPREQ_FLAG_DGRAM
) || active
;
1070 Gets the sockaddr structure referred to the other peer in the ctrl connection
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
1078 saddrlen
= sizeof(struct sockaddr_storage
);
1079 if (getpeername(sockctrl
, (struct sockaddr
*) &saddr
, &saddrlen
) == -1)
1081 sock_geterror("getpeername(): ", errbuf
, PCAP_ERRBUF_SIZE
);
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
;
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
1092 sprintf(portdata
, "%d", ntohs(startcapreq
.portdata
));
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
))
1098 sock_geterror("getnameinfo(): ", errbuf
, PCAP_ERRBUF_SIZE
);
1102 if (sock_initaddress(peerhost
, portdata
, &hints
, &addrinfo
, errbuf
, PCAP_ERRBUF_SIZE
) == -1)
1105 if ((sockdata
= sock_open(addrinfo
, SOCKOPEN_CLIENT
, 0, errbuf
, PCAP_ERRBUF_SIZE
)) == -1)
1108 else // Data connection is opened by the client toward the server
1110 hints
.ai_flags
= AI_PASSIVE
;
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)
1116 if ((sockdata
= sock_open(addrinfo
, SOCKOPEN_SERVER
, 1 /* max 1 connection in queue */, errbuf
, PCAP_ERRBUF_SIZE
)) == -1)
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)
1123 sock_geterror("getsockname(): ", errbuf
, PCAP_ERRBUF_SIZE
);
1127 // Get the local port the system picked up
1128 if (getnameinfo((struct sockaddr
*) &saddr
, saddrlen
, NULL
,
1129 0, portdata
, sizeof(portdata
), NI_NUMERICSERV
))
1131 sock_geterror("getnameinfo(): ", errbuf
, PCAP_ERRBUF_SIZE
);
1136 // addrinfo is no longer used
1137 freeaddrinfo(addrinfo
);
1140 session
->sockctrl
= sockctrl
; // Needed to send an error on the ctrl connection
1142 // Now I can set the filter
1143 if (daemon_unpackapplyfilter(session
, &totread
, &plen
, errbuf
))
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)
1152 rpcap_createhdr((struct rpcap_header
*) sendbuf
, RPCAP_MSG_STARTCAP_REPLY
, 0, sizeof(struct rpcap_startcapreply
));
1154 startcapreply
= (struct rpcap_startcapreply
*) &sendbuf
[sendbufidx
];
1156 if (sock_bufferize(NULL
, sizeof(struct rpcap_startcapreply
), NULL
,
1157 &sendbufidx
, RPCAP_NETBUF_SIZE
, SOCKBUF_CHECKONLY
, errbuf
, PCAP_ERRBUF_SIZE
) == -1)
1160 memset(startcapreply
, 0, sizeof(struct rpcap_startcapreply
));
1161 startcapreply
->bufsize
= htonl(pcap_bufsize(session
->fp
));
1165 unsigned short port
= (unsigned short)strtoul(portdata
,NULL
,10);
1166 startcapreply
->portdata
= htons(port
);
1169 if (sock_send(sockctrl
, sendbuf
, sendbufidx
, errbuf
, PCAP_ERRBUF_SIZE
) == -1)
1174 SOCKET socktemp
; // We need another socket, since we're going to accept() a connection
1176 // Connection creation
1177 saddrlen
= sizeof(struct sockaddr_storage
);
1179 socktemp
= accept(sockdata
, (struct sockaddr
*) &saddr
, &saddrlen
);
1183 sock_geterror("accept(): ", errbuf
, PCAP_ERRBUF_SIZE
);
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
;
1192 session
->sockdata
= sockdata
;
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
);
1199 // Now we have to create a new thread to receive packets
1200 if (pthread_create(threaddata
, &detachedAttribute
, daemon_thrdatamain
, (void *) session
))
1202 snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "Error creating the data thread");
1203 pthread_attr_destroy(&detachedAttribute
);
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);
1215 rpcap_senderror(sockctrl
, errbuf
, PCAP_ERR_STARTCAPTURE
, NULL
);
1218 freeaddrinfo(addrinfo
);
1221 pthread_cancel(*threaddata
);
1224 sock_close(sockdata
, NULL
, 0);
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);
1232 pcap_close(session
->fp
);
1239 static int daemon_endcapture(struct session
*session
, pthread_t
*threaddata
, char *errbuf
)
1241 struct rpcap_header header
;
1245 pthread_cancel(*threaddata
);
1248 if (session
->sockdata
)
1250 sock_close(session
->sockdata
, NULL
, 0);
1251 session
->sockdata
= 0;
1254 pcap_close(session
->fp
);
1256 rpcap_createhdr(&header
, RPCAP_MSG_ENDCAP_REPLY
, 0, 0);
1258 if (sock_send(session
->sockctrl
, (char *) &header
, sizeof(struct rpcap_header
), errbuf
, PCAP_ERRBUF_SIZE
) == -1)
1264 static int daemon_unpackapplyfilter(struct session
*session
, uint32
*totread
, uint32
*plen
, char *errbuf
)
1267 struct rpcap_filter filter
;
1268 struct rpcap_filterbpf_insn insn
;
1269 struct bpf_insn
*bf_insn
;
1270 struct bpf_program bf_prog
;
1273 nread
= sock_recv(session
->sockctrl
, (char *) &filter
,
1274 sizeof(struct rpcap_filter
), SOCK_RECEIVEALL_YES
,
1275 errbuf
, PCAP_ERRBUF_SIZE
);
1278 // to avoid blocking on the sock_discard()
1284 bf_prog
.bf_len
= ntohl(filter
.nitems
);
1286 if (ntohs(filter
.filtertype
) != RPCAP_UPDATEFILTER_BPF
)
1288 snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "Only BPF/NPF filters are currently supported");
1292 bf_insn
= (struct bpf_insn
*) malloc (sizeof(struct bpf_insn
) * bf_prog
.bf_len
);
1293 if (bf_insn
== NULL
)
1295 snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "malloc() failed: %s", pcap_strerror(errno
));
1299 bf_prog
.bf_insns
= bf_insn
;
1301 for (i
= 0; i
< bf_prog
.bf_len
; i
++)
1303 nread
= sock_recv(session
->sockctrl
, (char *) &insn
,
1304 sizeof(struct rpcap_filterbpf_insn
), SOCK_RECEIVEALL_YES
,
1305 errbuf
, PCAP_ERRBUF_SIZE
);
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
);
1318 if (bpf_validate(bf_prog
.bf_insns
, bf_prog
.bf_len
) == 0)
1320 snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "The filter contains bogus instructions");
1324 if (pcap_setfilter(session
->fp
, &bf_prog
))
1326 snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "RPCAP error: %s", pcap_geterr(session
->fp
));
1333 int daemon_updatefilter(struct session
*session
, uint32 plen
)
1335 struct rpcap_header header
; // keeps the answer to the updatefilter command
1340 if (daemon_unpackapplyfilter(session
, &nread
, &plen
, pcap_geterr(session
->fp
)))
1343 // Check if all the data has been read; if not, discard the data in excess
1346 if (sock_discard(session
->sockctrl
, plen
- nread
, NULL
, 0))
1348 nread
= plen
; // just to avoid to call discard again in the 'error' section
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);
1356 if (sock_send(session
->sockctrl
, (char *) &header
, sizeof (struct rpcap_header
), pcap_geterr(session
->fp
), PCAP_ERRBUF_SIZE
))
1364 sock_discard(session
->sockctrl
, plen
- nread
, NULL
, 0);
1366 rpcap_senderror(session
->sockctrl
, pcap_geterr(session
->fp
), PCAP_ERR_UPDATEFILTER
, NULL
);
1372 \brief Received the sampling parameters from remote host and it stores in the pcap_t structure.
1374 int daemon_setsampling(SOCKET sockctrl
, struct rpcap_sampling
*samp_param
, int plen
, char *errbuf
)
1376 struct rpcap_header header
;
1377 struct rpcap_sampling rpcap_samp
;
1378 int nread
; // number of bytes of the payload read from the socket
1380 if ((nread
= sock_recv(sockctrl
, (char *) &rpcap_samp
, sizeof(struct rpcap_sampling
),
1381 SOCK_RECEIVEALL_YES
, errbuf
, PCAP_ERRBUF_SIZE
)) == -1)
1384 // Save these settings in the pcap_t
1385 samp_param
->method
= rpcap_samp
.method
;
1386 samp_param
->value
= ntohl(rpcap_samp
.value
);
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);
1391 if (sock_send(sockctrl
, (char *) &header
, sizeof (struct rpcap_header
), errbuf
, PCAP_ERRBUF_SIZE
))
1395 sock_discard(sockctrl
, plen
- nread
, NULL
, 0);
1401 sock_discard(sockctrl
, plen
- nread
, NULL
, 0);
1403 rpcap_senderror(sockctrl
, errbuf
, PCAP_ERR_SETSAMPLING
, NULL
);
1408 int daemon_getstats(struct session
*session
)
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
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)
1419 rpcap_createhdr((struct rpcap_header
*) sendbuf
, RPCAP_MSG_STATS_REPLY
, 0, (uint16
) sizeof(struct rpcap_stats
));
1421 netstats
= (struct rpcap_stats
*) &sendbuf
[sendbufidx
];
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)
1427 if (pcap_stats(session
->fp
, &stats
))
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
);
1436 if (sock_send(session
->sockctrl
, sendbuf
, sendbufidx
, pcap_geterr(session
->fp
), PCAP_ERRBUF_SIZE
) == -1)
1442 rpcap_senderror(session
->sockctrl
, pcap_geterr(session
->fp
), PCAP_ERR_GETSTATS
, NULL
);
1446 int daemon_getstatsnopcap(SOCKET sockctrl
, unsigned int ifdrops
, unsigned int ifrecv
,
1447 unsigned int krnldrop
, unsigned int svrcapt
, char *errbuf
)
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
1453 if (sock_bufferize(NULL
, sizeof(struct rpcap_header
), NULL
,
1454 &sendbufidx
, RPCAP_NETBUF_SIZE
, SOCKBUF_CHECKONLY
, errbuf
, PCAP_ERRBUF_SIZE
) == -1)
1457 rpcap_createhdr((struct rpcap_header
*) sendbuf
, RPCAP_MSG_STATS_REPLY
, 0, (uint16
) sizeof(struct rpcap_stats
));
1459 netstats
= (struct rpcap_stats
*) &sendbuf
[sendbufidx
];
1461 if (sock_bufferize(NULL
, sizeof(struct rpcap_stats
), NULL
,
1462 &sendbufidx
, RPCAP_NETBUF_SIZE
, SOCKBUF_CHECKONLY
, errbuf
, PCAP_ERRBUF_SIZE
) == -1)
1465 netstats
->ifdrop
= htonl(ifdrops
);
1466 netstats
->ifrecv
= htonl(ifrecv
);
1467 netstats
->krnldrop
= htonl(krnldrop
);
1468 netstats
->svrcapt
= htonl(svrcapt
);
1471 if (sock_send(sockctrl
, sendbuf
, sendbufidx
, errbuf
, PCAP_ERRBUF_SIZE
) == -1)
1477 rpcap_senderror(sockctrl
, errbuf
, PCAP_ERR_GETSTATS
, NULL
);
1481 void *daemon_thrdatamain(void *ptr
)
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
1492 session
= (struct session
*) ptr
;
1494 session
->TotCapt
= 0; // counter which is incremented each time a packet is received
1496 // Initialize errbuf
1497 memset(errbuf
, 0, sizeof(errbuf
));
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
)
1504 snprintf(errbuf
, sizeof(errbuf
) - 1, "Unable to create the buffer for this child thread");
1508 // Modify thread params so that it can be killed at any time
1509 if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE
, NULL
))
1511 if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS
, NULL
))
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
1517 if (retval
== 0) // Read timeout elapsed
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)
1527 rpcap_createhdr((struct rpcap_header
*) sendbuf
, RPCAP_MSG_PACKET
, 0,
1528 (uint16
) (sizeof(struct rpcap_pkthdr
) + pkt_header
->caplen
));
1530 net_pkt_header
= (struct rpcap_pkthdr
*) &sendbuf
[sendbufidx
];
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)
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
);
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)
1549 if (sock_send(session
->sockdata
, sendbuf
, sendbufidx
, errbuf
, PCAP_ERRBUF_SIZE
) == -1)
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
);
1563 SOCK_ASSERT(errbuf
, 1);
1564 closesocket(session
->sockdata
);
1565 session
->sockdata
= 0;
1573 \brief It serializes a network address.
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.
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'.
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.
1587 \warning This function supports only AF_INET and AF_INET6 address families.
1589 void daemon_seraddr(struct sockaddr_storage
*sockaddrin
, struct rpcap_sockaddr
*sockaddrout
)
1591 memset(sockaddrout
, 0, sizeof(struct sockaddr_storage
));
1593 // There can be the case in which the sockaddrin is not available
1594 if (sockaddrin
== NULL
) return;
1596 // Warning: we support only AF_INET and AF_INET6
1597 switch (sockaddrin
->ss_family
)
1601 struct sockaddr_in
*sockaddrin_ipv4
;
1602 struct rpcap_sockaddr_in
*sockaddrout_ipv4
;
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
));
1616 struct sockaddr_in6
*sockaddrin_ipv6
;
1617 struct rpcap_sockaddr_in6
*sockaddrout_ipv6
;
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
);
1633 \brief Suspends a pthread for msec milliseconds.
1635 This function is provided since pthreads do not have a suspend() call.
1637 void pthread_suspend(int msec
)
1642 struct timespec abstime
;
1645 pthread_cond_t cond
;
1646 pthread_mutex_t mutex
;
1647 pthread_mutexattr_t attr
;
1649 pthread_mutexattr_init(&attr
);
1650 pthread_mutex_init(&mutex
, &attr
);
1651 pthread_mutex_lock(&mutex
);
1653 pthread_cond_init(&cond
, NULL
);
1655 gettimeofday(&now
, NULL
);
1657 abstime
.tv_sec
= now
.tv_sec
+ msec
/1000;
1658 abstime
.tv_nsec
= now
.tv_usec
* 1000 + (msec
%1000) * 1000 * 1000;
1660 pthread_cond_timedwait(&cond
, &mutex
, &abstime
);
1662 pthread_mutex_destroy(&mutex
);
1663 pthread_cond_destroy(&cond
);