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.
36 #include <pcap.h> // for libpcap/WinPcap calls
37 #include <errno.h> // for the errno variable
38 #include <stdlib.h> // for malloc(), free(), ...
39 #include <string.h> // for strlen(), ...
41 #include "sockutils.h" // for socket calls
42 #include "rpcap-protocol.h"
43 #include "pcap-rpcap-int.h"
46 #ifndef _WIN32 // for select() and such
49 #include <sys/types.h>
50 #include <pwd.h> // for password management
54 #include <shadow.h> // for password management
57 #define RPCAP_TIMEOUT_INIT 90 /* Initial timeout for RPCAP connections (default: 90 sec) */
58 #define RPCAP_TIMEOUT_RUNTIME 180 /* Run-time timeout for RPCAP connections (default: 3 min) */
59 #define RPCAP_SUSPEND_WRONGAUTH 1 /* If the authentication is wrong, stops 1 sec before accepting a new auth message */
62 * Data for a session managed by a thread.
71 // Locally defined functions
72 static int daemon_checkauth(SOCKET sockctrl
, int nullAuthAllowed
, char *errbuf
);
73 static int daemon_AuthUserPwd(char *username
, char *password
, char *errbuf
);
75 static int daemon_findalldevs(SOCKET sockctrl
, char *errbuf
);
77 static int daemon_opensource(SOCKET sockctrl
, char *source
, int srclen
, uint32 plen
, char *errbuf
);
78 static struct session
*daemon_startcapture(SOCKET sockctrl
, pthread_t
*threaddata
, char *source
, int active
,
79 struct rpcap_sampling
*samp_param
, uint32 plen
, char *errbuf
);
80 static int daemon_endcapture(struct session
*session
, pthread_t
*threaddata
, char *errbuf
);
82 static int daemon_updatefilter(struct session
*session
, uint32 plen
);
83 static int daemon_unpackapplyfilter(struct session
*session
, uint32
*totread
, uint32
*plen
, char *errbuf
);
85 static int daemon_getstats(struct session
*session
);
86 static int daemon_getstatsnopcap(SOCKET sockctrl
, unsigned int ifdrops
, unsigned int ifrecv
,
87 unsigned int krnldrop
, unsigned int svrcapt
, char *errbuf
);
89 static int daemon_setsampling(SOCKET sockctrl
, struct rpcap_sampling
*samp_param
, int plen
, char *errbuf
);
91 static void daemon_seraddr(struct sockaddr_storage
*sockaddrin
, struct rpcap_sockaddr
*sockaddrout
);
92 static void *daemon_thrdatamain(void *ptr
);
95 \brief Main serving funtion
96 This function is the one which does the job. It is the main() of the child
97 thread, which is created as soon as a new connection is accepted.
99 \param ptr: a void pointer that keeps the reference of the 'pthread_chain'
100 value corrisponding to this thread. This variable is casted into a 'pthread_chain'
101 value in order to retrieve the socket we're currently using, the therad ID, and
102 some pointers to the previous and next elements into this struct.
106 void daemon_serviceloop(void *ptr
)
108 char errbuf
[PCAP_ERRBUF_SIZE
+ 1]; // keeps the error string, prior to be printed
109 char source
[PCAP_BUF_SIZE
]; // keeps the string that contains the interface to open
110 struct rpcap_header header
; // RPCAP message general header
111 struct session
*session
= NULL
; // struct session main variable
112 struct daemon_slpars
*pars
; // parameters related to the present daemon loop
114 pthread_t threaddata
= 0; // handle to the 'read from daemon and send to client' thread
116 unsigned int ifdrops
, ifrecv
, krnldrop
, svrcapt
; // needed to save the values of the statistics
118 struct rpcap_sampling samp_param
; // in case sampling has been requested
120 // Structures needed for the select() call
121 fd_set rfds
; // set of socket descriptors we have to check
122 struct timeval tv
; // maximum time the select() can block waiting for data
123 int retval
; // select() return value
125 pars
= (struct daemon_slpars
*) ptr
;
127 *errbuf
= 0; // Initialize errbuf
129 // If we're in active mode, this is not a separate thread
130 if (! pars
->isactive
)
132 // Modify thread params so that it can be killed at any time
133 if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE
, NULL
))
135 if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS
, NULL
))
140 // If we're in active mode, we have to check for the initial timeout
144 // We do not have to block here
145 tv
.tv_sec
= RPCAP_TIMEOUT_INIT
;
148 FD_SET(pars
->sockctrl
, &rfds
);
150 retval
= select(pars
->sockctrl
+ 1, &rfds
, NULL
, NULL
, &tv
);
153 sock_geterror("select(): ", errbuf
, PCAP_ERRBUF_SIZE
);
154 rpcap_senderror(pars
->sockctrl
, errbuf
, PCAP_ERR_NETW
, NULL
);
158 // The timeout has expired
159 // So, this was a fake connection. Drop it down
162 rpcap_senderror(pars
->sockctrl
, "The RPCAP initial timeout has expired", PCAP_ERR_INITTIMEOUT
, NULL
);
167 retval
= daemon_checkauth(pars
->sockctrl
, pars
->nullAuthAllowed
, errbuf
);
171 // the other user requested to close the connection
172 // It can be also the case of 'active mode', in which this host is not
173 // allowed to connect to the other peer; in that case, it drops down the connection
177 // It can be an authentication failure or an unrecoverable error
178 rpcap_senderror(pars
->sockctrl
, errbuf
, PCAP_ERR_AUTH
, NULL
);
180 // authentication error
184 // WARNING: this day is inserted only in this point; if the user drops down the connection
185 // and it connects again, this suspension time does not have any effects.
186 pthread_suspend(RPCAP_SUSPEND_WRONGAUTH
*1000);
190 // Unrecoverable error
197 errbuf
[0] = 0; // clear errbuf
199 // Avoid zombies connections; check if the connection is opens but no commands are performed
200 // from more than RPCAP_TIMEOUT_RUNTIME
202 // - I have to be in normal mode (no active mode)
203 // - if the device is open, I don't have to be in the middle of a capture (session->sockdata)
204 // - if the device is closed, I have always to check if a new command arrives
206 // Be carefully: the capture can have been started, but an error occurred (so session != NULL, but
208 if ((!pars
->isactive
) && ((session
== NULL
) || ((session
!= NULL
) && (session
->sockdata
== 0))))
210 // Check for the initial timeout
212 // We do not have to block here
213 tv
.tv_sec
= RPCAP_TIMEOUT_RUNTIME
;
216 FD_SET(pars
->sockctrl
, &rfds
);
218 retval
= select(pars
->sockctrl
+ 1, &rfds
, NULL
, NULL
, &tv
);
221 sock_geterror("select(): ", errbuf
, PCAP_ERRBUF_SIZE
);
222 rpcap_senderror(pars
->sockctrl
, errbuf
, PCAP_ERR_NETW
, NULL
);
226 // The timeout has expired
227 // So, this was a fake connection. Drop it down
230 SOCK_ASSERT("The RPCAP runtime timeout has expired", 1);
231 rpcap_senderror(pars
->sockctrl
, "The RPCAP runtime timeout has expired", PCAP_ERR_RUNTIMETIMEOUT
, NULL
);
236 if (sock_recv(pars
->sockctrl
, (char *) &header
, sizeof(struct rpcap_header
), SOCK_RECEIVEALL_YES
, errbuf
, PCAP_ERRBUF_SIZE
) == -1)
239 // Checks if the message is correct
240 // In case it is wrong, it discard the data
241 retval
= rpcap_checkmsg(errbuf
, pars
->sockctrl
, &header
,
242 RPCAP_MSG_FINDALLIF_REQ
,
244 RPCAP_MSG_STARTCAP_REQ
,
245 RPCAP_MSG_UPDATEFILTER_REQ
,
247 RPCAP_MSG_ENDCAP_REQ
,
248 RPCAP_MSG_SETSAMPLING_REQ
,
255 case -3: // Unrecoverable network error
256 goto end
; // Do nothing; just exit from findalldevs; the error code is already into the errbuf
258 case -2: // The other endpoint send a message that is not allowed here
260 rpcap_senderror(pars
->sockctrl
, "The RPCAP daemon received a message that is not valid", PCAP_ERR_WRONGMSG
, errbuf
);
262 case -1: // The other endpoint has a version number that is not compatible with our
264 rpcap_senderror(pars
->sockctrl
, "RPCAP version number mismatch", PCAP_ERR_WRONGVER
, errbuf
);
268 case RPCAP_MSG_FINDALLIF_REQ
:
270 // Checks that the header does not contain other data; if so, discard it
271 if (ntohl(header
.plen
))
272 sock_discard(pars
->sockctrl
, ntohl(header
.plen
), errbuf
, PCAP_ERRBUF_SIZE
);
274 if (daemon_findalldevs(pars
->sockctrl
, errbuf
))
275 SOCK_ASSERT(errbuf
, 1);
280 case RPCAP_MSG_OPEN_REQ
:
282 retval
= daemon_opensource(pars
->sockctrl
, source
, sizeof(source
), ntohl(header
.plen
), errbuf
);
285 SOCK_ASSERT(errbuf
, 1);
290 case RPCAP_MSG_SETSAMPLING_REQ
:
292 retval
= daemon_setsampling(pars
->sockctrl
, &samp_param
, ntohl(header
.plen
), errbuf
);
295 SOCK_ASSERT(errbuf
, 1);
300 case RPCAP_MSG_STARTCAP_REQ
:
302 session
= daemon_startcapture(pars
->sockctrl
, &threaddata
, source
, pars
->isactive
, &samp_param
, ntohl(header
.plen
), errbuf
);
305 SOCK_ASSERT(errbuf
, 1);
310 case RPCAP_MSG_UPDATEFILTER_REQ
:
314 if (daemon_updatefilter(session
, ntohl(header
.plen
)))
315 SOCK_ASSERT(pcap_geterr(session
->fp
), 1);
319 rpcap_senderror(pars
->sockctrl
, "Device not opened. Cannot update filter", PCAP_ERR_UPDATEFILTER
, errbuf
);
325 case RPCAP_MSG_STATS_REQ
:
327 // Checks that the header does not contain other data; if so, discard it
328 if (ntohl(header
.plen
))
329 sock_discard(pars
->sockctrl
, ntohl(header
.plen
), errbuf
, PCAP_ERRBUF_SIZE
);
331 if (session
&& session
->fp
)
333 if (daemon_getstats(session
))
334 SOCK_ASSERT(pcap_geterr(session
->fp
), 1);
338 SOCK_ASSERT("GetStats: this call should't be allowed here", 1);
340 if (daemon_getstatsnopcap(pars
->sockctrl
, ifdrops
, ifrecv
, krnldrop
, svrcapt
, errbuf
))
341 SOCK_ASSERT(errbuf
, 1);
342 // we have to keep compatibility with old applications, which ask for statistics
343 // also when the capture has already stopped
345 // rpcap_senderror(pars->sockctrl, "Device not opened. Cannot get statistics", PCAP_ERR_GETSTATS, errbuf);
351 case RPCAP_MSG_ENDCAP_REQ
: // The other endpoint close the current capture session
353 if (session
&& session
->fp
)
355 struct pcap_stat stats
;
357 // Save statistics (we can need them in the future)
358 if (pcap_stats(session
->fp
, &stats
))
360 ifdrops
= stats
.ps_ifdrop
;
361 ifrecv
= stats
.ps_recv
;
362 krnldrop
= stats
.ps_drop
;
363 svrcapt
= session
->TotCapt
;
366 ifdrops
= ifrecv
= krnldrop
= svrcapt
= 0;
368 if (daemon_endcapture(session
, &threaddata
, errbuf
))
369 SOCK_ASSERT(pcap_geterr(session
->fp
), 1);
375 rpcap_senderror(pars
->sockctrl
, "Device not opened. Cannot close the capture", PCAP_ERR_ENDCAPTURE
, errbuf
);
380 case RPCAP_MSG_CLOSE
: // The other endpoint close the pcap session
382 // signal to the main that the user closed the control connection
383 // This is used only in case of active mode
384 pars
->activeclose
= 1;
385 SOCK_ASSERT("The other end system asked to close the connection.", 1);
390 case RPCAP_MSG_ERROR
: // The other endpoint reported an error
392 // Do nothing; just exit; the error code is already into the errbuf
393 SOCK_ASSERT(errbuf
, 1);
399 SOCK_ASSERT("Internal error.", 1);
406 // The child thread is about to end
408 // perform pcap_t cleanup, in case it has not been done
413 pthread_cancel(threaddata
);
416 if (session
->sockdata
)
418 sock_close(session
->sockdata
, NULL
, 0);
419 session
->sockdata
= 0;
421 pcap_close(session
->fp
);
426 // Print message and exit
427 SOCK_ASSERT("I'm exiting from the child loop", 1);
428 SOCK_ASSERT(errbuf
, 1);
433 sock_close(pars
->sockctrl
, NULL
, 0);
443 \brief It checks if the authentication credentials supplied by the user are valid.
445 This function is called each time the rpcap daemon starts a new serving thread.
446 It reads the authentication message from the network and it checks that the
447 user information are valid.
449 \param sockctrl: the socket if of the control connection.
451 \param nullAuthAllowed: '1' if the NULL authentication is allowed.
453 \param errbuf: a user-allocated buffer in which the error message (if one) has to be written.
455 \return '0' if everything is fine, '-1' if an unrecoverable error occurred.
456 The error message is returned in the 'errbuf' variable.
457 '-2' is returned in case the authentication failed or in case of a recoverable error (like
458 wrong version). In that case, 'errbuf' keeps the reason of the failure. This provides
459 a way to know that the connection does not have to be closed.
461 In case the message is a 'CLOSE' or an 'ERROR', it returns -3. The error can be due to a
462 connection refusal in active mode, since this host cannot be allowed to connect to the remote
465 int daemon_checkauth(SOCKET sockctrl
, int nullAuthAllowed
, char *errbuf
)
467 struct rpcap_header header
; // RPCAP message general header
468 int retval
; // generic return value
469 uint32 totread
= 0; // number of bytes of the payload read from the socket
471 struct rpcap_auth auth
; // RPCAP authentication header
472 char *string1
, *string2
; // two strings exchanged by the authentication message
473 unsigned int plen
; // length of the payload
474 int retcode
; // the value we have to return to the caller
476 if (sock_recv(sockctrl
, (char *) &header
, sizeof(struct rpcap_header
), SOCK_RECEIVEALL_YES
, errbuf
, PCAP_ERRBUF_SIZE
) == -1)
479 plen
= ntohl(header
.plen
);
481 retval
= rpcap_checkmsg(errbuf
, sockctrl
, &header
,
486 if (retval
!= RPCAP_MSG_AUTH_REQ
)
490 case -3: // Unrecoverable network error
491 return -1; // Do nothing; just exit; the error code is already into the errbuf
493 case -2: // The other endpoint send a message that is not allowed here
494 case -1: // The other endpoint has a version number that is not compatible with our
497 case RPCAP_MSG_CLOSE
:
499 // Check if all the data has been read; if not, discard the data in excess
500 if (ntohl(header
.plen
))
502 if (sock_discard(sockctrl
, ntohl(header
.plen
), NULL
, 0))
508 case RPCAP_MSG_ERROR
:
513 SOCK_ASSERT("Internal error.", 1);
520 // If it comes here, it means that we have an authentication request message
521 nread
= sock_recv(sockctrl
, (char *) &auth
, sizeof(struct rpcap_auth
),
522 SOCK_RECEIVEALL_YES
, errbuf
, PCAP_ERRBUF_SIZE
);
530 switch (ntohs(auth
.type
))
532 case RPCAP_RMTAUTH_NULL
:
534 if (!nullAuthAllowed
)
536 snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "Authentication failed; NULL autentication not permitted.");
543 case RPCAP_RMTAUTH_PWD
:
547 len1
= ntohs(auth
.slen1
);
548 len2
= ntohs(auth
.slen2
);
550 string1
= (char *) malloc (len1
+ 1);
551 string2
= (char *) malloc (len2
+ 1);
553 if ((string1
== NULL
) || (string2
== NULL
))
555 snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "malloc() failed: %s", pcap_strerror(errno
));
560 nread
= sock_recv(sockctrl
, string1
, len1
,
561 SOCK_RECEIVEALL_YES
, errbuf
, PCAP_ERRBUF_SIZE
);
568 nread
= sock_recv(sockctrl
, string2
, len2
,
569 SOCK_RECEIVEALL_YES
, errbuf
, PCAP_ERRBUF_SIZE
);
580 if (daemon_AuthUserPwd(string1
, string2
, errbuf
))
590 snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "Authentication type not recognized.");
596 // Check if all the data has been read; if not, discard the data in excess
599 if (sock_discard(sockctrl
, plen
- totread
, NULL
, 0))
606 rpcap_createhdr(&header
, RPCAP_MSG_AUTH_REPLY
, 0, 0);
608 // Send the ok message back
609 if (sock_send(sockctrl
, (char *) &header
, sizeof (struct rpcap_header
), errbuf
, PCAP_ERRBUF_SIZE
) == -1)
618 // Check if all the data has been read; if not, discard the data in excess
620 sock_discard(sockctrl
, plen
- totread
, NULL
, 0);
625 int daemon_AuthUserPwd(char *username
, char *password
, char *errbuf
)
629 * Warning: the user which launches the process must have the
631 * This corresponds to have the "Act as part of the Operating System"
632 * turned on (administrative tools, local security settings, local
633 * policies, user right assignment)
634 * However, it seems to me that if you run it as a service, this
635 * right should be provided by default.
638 if (LogonUser(username
, ".", password
, LOGON32_LOGON_NETWORK
, LOGON32_PROVIDER_DEFAULT
, &Token
) == 0)
642 error
= GetLastError();
643 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
, NULL
, error
, 0, errbuf
,
644 PCAP_ERRBUF_SIZE
, NULL
);
649 // This call should change the current thread to the selected user.
651 if (ImpersonateLoggedOnUser(Token
) == 0)
655 error
= GetLastError();
656 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
, NULL
, error
, 0, errbuf
,
657 PCAP_ERRBUF_SIZE
, NULL
);
668 * Standard user authentication:
670 * http://www.unixpapa.com/incnote/passwd.html
672 * Problem: it is not able to merge the standard pwd file with
675 * Shadow user authentication:
677 * http://www.tldp.org/HOWTO/Shadow-Password-HOWTO-8.html
679 * Problem: the program must either (1) run as root, or (2) run
680 * as user, but it must be owned by root and must be SUID root
688 // This call is needed to get the uid
689 if ((user
= getpwnam(username
)) == NULL
)
691 snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "Authentication failed: no such user");
696 // This call is needed to get the password; otherwise 'x' is returned
697 if ((usersp
= getspnam(username
)) == NULL
)
699 snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "Authentication failed: no such user");
703 if (strcmp(usersp
->sp_pwdp
, (char *) crypt(password
, usersp
->sp_pwdp
)) != 0)
705 snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "Authentication failed: password incorrect");
711 if (strcmp(user
->pw_passwd
, (char *) crypt(password
, user
->pw_passwd
)) != 0)
713 snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "Authentication failed: password incorrect");
718 if (setuid(user
->pw_uid
))
720 snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "%s", pcap_strerror(errno
));
724 /* if (setgid(user->pw_gid))
726 SOCK_ASSERT("setgid failed", 1);
727 snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s", pcap_strerror(errno));
737 // PORTING WARNING We assume u_int is a 32bit value
738 int daemon_findalldevs(SOCKET sockctrl
, char *errbuf
)
740 char sendbuf
[RPCAP_NETBUF_SIZE
]; // temporary buffer in which data to be sent is buffered
741 int sendbufidx
= 0; // index which keeps the number of bytes currently buffered
742 pcap_if_t
*alldevs
; // pointer to the heade of the interface chain
743 pcap_if_t
*d
; // temp pointer neede to scan the interface chain
744 uint16 plen
= 0; // length of the payload of this message
745 struct pcap_addr
*address
; // pcap structure that keeps a network address of an interface
746 struct rpcap_findalldevs_if
*findalldevs_if
;// rpcap structure that packet all the data of an interface together
747 uint16 nif
= 0; // counts the number of interface listed
749 // Retrieve the device list
750 if (pcap_findalldevs(&alldevs
, errbuf
) == -1)
752 rpcap_senderror(sockctrl
, errbuf
, PCAP_ERR_FINDALLIF
, NULL
);
758 rpcap_senderror(sockctrl
,
759 "No interfaces found! Make sure libpcap/WinPcap is properly installed"
760 " and you have the right to access to the remote device.",
766 // checks the number of interfaces and it computes the total length of the payload
767 for (d
= alldevs
; d
!= NULL
; d
= d
->next
)
772 plen
+= strlen(d
->description
);
774 plen
+= strlen(d
->name
);
776 plen
+= sizeof(struct rpcap_findalldevs_if
);
778 for (address
= d
->addresses
; address
!= NULL
; address
= address
->next
)
781 * Send only IPv4 and IPv6 addresses over the wire.
783 switch (address
->addr
->sa_family
)
789 plen
+= (sizeof(struct rpcap_sockaddr
) * 4);
798 // RPCAP findalldevs command
799 if (sock_bufferize(NULL
, sizeof(struct rpcap_header
), NULL
,
800 &sendbufidx
, RPCAP_NETBUF_SIZE
, SOCKBUF_CHECKONLY
, errbuf
, PCAP_ERRBUF_SIZE
) == -1)
803 rpcap_createhdr((struct rpcap_header
*) sendbuf
, RPCAP_MSG_FINDALLIF_REPLY
, nif
, plen
);
805 // send the interface list
806 for (d
= alldevs
; d
!= NULL
; d
= d
->next
)
808 uint16 lname
, ldescr
;
810 findalldevs_if
= (struct rpcap_findalldevs_if
*) &sendbuf
[sendbufidx
];
812 if (sock_bufferize(NULL
, sizeof(struct rpcap_findalldevs_if
), NULL
,
813 &sendbufidx
, RPCAP_NETBUF_SIZE
, SOCKBUF_CHECKONLY
, errbuf
, PCAP_ERRBUF_SIZE
) == -1)
816 memset(findalldevs_if
, 0, sizeof(struct rpcap_findalldevs_if
));
818 if (d
->description
) ldescr
= (short) strlen(d
->description
);
820 if (d
->name
) lname
= (short) strlen(d
->name
);
823 findalldevs_if
->desclen
= htons(ldescr
);
824 findalldevs_if
->namelen
= htons(lname
);
825 findalldevs_if
->flags
= htonl(d
->flags
);
827 for (address
= d
->addresses
; address
!= NULL
; address
= address
->next
)
830 * Send only IPv4 and IPv6 addresses over the wire.
832 switch (address
->addr
->sa_family
)
838 findalldevs_if
->naddr
++;
845 findalldevs_if
->naddr
= htons(findalldevs_if
->naddr
);
847 if (sock_bufferize(d
->name
, lname
, sendbuf
, &sendbufidx
,
848 RPCAP_NETBUF_SIZE
, SOCKBUF_BUFFERIZE
, errbuf
, PCAP_ERRBUF_SIZE
) == -1)
851 if (sock_bufferize(d
->description
, ldescr
, sendbuf
, &sendbufidx
,
852 RPCAP_NETBUF_SIZE
, SOCKBUF_BUFFERIZE
, errbuf
, PCAP_ERRBUF_SIZE
) == -1)
855 // send all addresses
856 for (address
= d
->addresses
; address
!= NULL
; address
= address
->next
)
858 struct rpcap_sockaddr
*sockaddr
;
861 * Send only IPv4 and IPv6 addresses over the wire.
863 switch (address
->addr
->sa_family
)
869 sockaddr
= (struct rpcap_sockaddr
*) &sendbuf
[sendbufidx
];
870 if (sock_bufferize(NULL
, sizeof(struct rpcap_sockaddr
), NULL
,
871 &sendbufidx
, RPCAP_NETBUF_SIZE
, SOCKBUF_CHECKONLY
, errbuf
, PCAP_ERRBUF_SIZE
) == -1)
873 daemon_seraddr((struct sockaddr_storage
*) address
->addr
, sockaddr
);
875 sockaddr
= (struct rpcap_sockaddr
*) &sendbuf
[sendbufidx
];
876 if (sock_bufferize(NULL
, sizeof(struct rpcap_sockaddr
), NULL
,
877 &sendbufidx
, RPCAP_NETBUF_SIZE
, SOCKBUF_CHECKONLY
, errbuf
, PCAP_ERRBUF_SIZE
) == -1)
879 daemon_seraddr((struct sockaddr_storage
*) address
->netmask
, sockaddr
);
881 sockaddr
= (struct rpcap_sockaddr
*) &sendbuf
[sendbufidx
];
882 if (sock_bufferize(NULL
, sizeof(struct rpcap_sockaddr
), NULL
,
883 &sendbufidx
, RPCAP_NETBUF_SIZE
, SOCKBUF_CHECKONLY
, errbuf
, PCAP_ERRBUF_SIZE
) == -1)
885 daemon_seraddr((struct sockaddr_storage
*) address
->broadaddr
, sockaddr
);
887 sockaddr
= (struct rpcap_sockaddr
*) &sendbuf
[sendbufidx
];
888 if (sock_bufferize(NULL
, sizeof(struct rpcap_sockaddr
), NULL
,
889 &sendbufidx
, RPCAP_NETBUF_SIZE
, SOCKBUF_CHECKONLY
, errbuf
, PCAP_ERRBUF_SIZE
) == -1)
891 daemon_seraddr((struct sockaddr_storage
*) address
->dstaddr
, sockaddr
);
900 // Send a final command that says "now send it!"
901 if (sock_send(sockctrl
, sendbuf
, sendbufidx
, errbuf
, PCAP_ERRBUF_SIZE
) == -1)
904 // We do no longer need the device list. Free it
905 pcap_freealldevs(alldevs
);
907 // everything is fine
912 \param plen: the length of the current message (needed in order to be able
913 to discard excess data in the message, if present)
915 static int daemon_opensource(SOCKET sockctrl
, char *source
, int srclen
, uint32 plen
, char *errbuf
)
917 pcap_t
*fp
= NULL
; // pcap_t main variable
918 uint32 totread
; // number of bytes of the payload read from the socket
920 char sendbuf
[RPCAP_NETBUF_SIZE
]; // temporary buffer in which data to be sent is buffered
921 int sendbufidx
= 0; // index which keeps the number of bytes currently buffered
922 struct rpcap_openreply
*openreply
; // open reply message
924 strcpy(source
, PCAP_SRC_IF_STRING
);
926 if (srclen
<= (int) (strlen(PCAP_SRC_IF_STRING
) + plen
))
928 rpcap_senderror(sockctrl
, "Source string too long", PCAP_ERR_OPEN
, NULL
);
932 nread
= sock_recv(sockctrl
, &source
[strlen(PCAP_SRC_IF_STRING
)], plen
,
933 SOCK_RECEIVEALL_YES
, errbuf
, PCAP_ERRBUF_SIZE
);
938 // Check if all the data has been read; if not, discard the data in excess
940 sock_discard(sockctrl
, plen
- totread
, NULL
, 0);
942 // Puts a '0' to terminate the source string
943 source
[strlen(PCAP_SRC_IF_STRING
) + plen
] = 0;
945 // Open the selected device
946 // This is a fake open, since we do that only to get the needed parameters, then we close the device again
947 if ((fp
= pcap_open_live(source
,
948 1500 /* fake snaplen */,
950 1000 /* fake timeout */,
953 rpcap_senderror(sockctrl
, errbuf
, PCAP_ERR_OPEN
, NULL
);
958 // Now, I can send a RPCAP open reply message
959 if (sock_bufferize(NULL
, sizeof(struct rpcap_header
), NULL
, &sendbufidx
,
960 RPCAP_NETBUF_SIZE
, SOCKBUF_CHECKONLY
, errbuf
, PCAP_ERRBUF_SIZE
) == -1)
963 rpcap_createhdr((struct rpcap_header
*) sendbuf
, RPCAP_MSG_OPEN_REPLY
, 0, sizeof(struct rpcap_openreply
));
965 openreply
= (struct rpcap_openreply
*) &sendbuf
[sendbufidx
];
967 if (sock_bufferize(NULL
, sizeof(struct rpcap_openreply
), NULL
, &sendbufidx
,
968 RPCAP_NETBUF_SIZE
, SOCKBUF_CHECKONLY
, errbuf
, PCAP_ERRBUF_SIZE
) == -1)
971 memset(openreply
, 0, sizeof(struct rpcap_openreply
));
972 openreply
->linktype
= htonl(pcap_datalink(fp
));
973 openreply
->tzoff
= 0; /* This is always 0 for live captures */
975 if (sock_send(sockctrl
, sendbuf
, sendbufidx
, errbuf
, PCAP_ERRBUF_SIZE
) == -1)
978 // I have to close the device again, since it has been opened with wrong parameters
995 \param plen: the length of the current message (needed in order to be able
996 to discard excess data in the message, if present)
998 static struct session
*daemon_startcapture(SOCKET sockctrl
, pthread_t
*threaddata
, char *source
, int active
, struct rpcap_sampling
*samp_param
, uint32 plen
, char *errbuf
)
1000 char portdata
[PCAP_BUF_SIZE
]; // temp variable needed to derive the data port
1001 char peerhost
[PCAP_BUF_SIZE
]; // temp variable needed to derive the host name of our peer
1002 struct session
*session
; // saves state of session
1003 uint32 totread
; // number of bytes of the payload read from the socket
1005 char sendbuf
[RPCAP_NETBUF_SIZE
]; // temporary buffer in which data to be sent is buffered
1006 int sendbufidx
= 0; // index which keeps the number of bytes currently buffered
1008 // socket-related variables
1009 SOCKET sockdata
= 0; // socket descriptor of the data connection
1010 struct addrinfo hints
; // temp, needed to open a socket connection
1011 struct addrinfo
*addrinfo
; // temp, needed to open a socket connection
1012 struct sockaddr_storage saddr
; // temp, needed to retrieve the network data port chosen on the local machine
1013 socklen_t saddrlen
; // temp, needed to retrieve the network data port chosen on the local machine
1015 pthread_attr_t detachedAttribute
; // temp, needed to set the created thread as detached
1017 // RPCAP-related variables
1018 struct rpcap_startcapreq startcapreq
; // start capture request message
1019 struct rpcap_startcapreply
*startcapreply
; // start capture reply message
1020 int serveropen_dp
; // keeps who is going to open the data connection
1024 nread
= sock_recv(sockctrl
, (char *) &startcapreq
,
1025 sizeof(struct rpcap_startcapreq
), SOCK_RECEIVEALL_YES
,
1026 errbuf
, PCAP_ERRBUF_SIZE
);
1031 startcapreq
.flags
= ntohs(startcapreq
.flags
);
1033 // Create a session structure
1034 session
= malloc(sizeof(struct session
));
1035 if (session
== NULL
)
1037 rpcap_senderror(sockctrl
, "Can't allocate session structure",
1038 PCAP_ERR_OPEN
, NULL
);
1042 // Open the selected device
1043 if ((session
->fp
= pcap_open(source
,
1044 ntohl(startcapreq
.snaplen
),
1045 (startcapreq
.flags
& RPCAP_STARTCAPREQ_FLAG_PROMISC
) ? PCAP_OPENFLAG_PROMISCUOUS
: 0 /* local device, other flags not needed */,
1046 ntohl(startcapreq
.read_timeout
),
1047 NULL
/* local device, so no auth */,
1050 rpcap_senderror(sockctrl
, errbuf
, PCAP_ERR_OPEN
, NULL
);
1055 // Apply sampling parameters
1056 fp
->rmt_samp
.method
= samp_param
->method
;
1057 fp
->rmt_samp
.value
= samp_param
->value
;
1061 We're in active mode if:
1062 - we're using TCP, and the user wants us to be in active mode
1065 serveropen_dp
= (startcapreq
.flags
& RPCAP_STARTCAPREQ_FLAG_SERVEROPEN
) || (startcapreq
.flags
& RPCAP_STARTCAPREQ_FLAG_DGRAM
) || active
;
1068 Gets the sockaddr structure referred to the other peer in the ctrl connection
1070 We need that because:
1071 - if we're in passive mode, we need to know the address family we want to use
1072 (the same used for the ctrl socket)
1073 - if we're in active mode, we need to know the network address of the other host
1074 we want to connect to
1076 saddrlen
= sizeof(struct sockaddr_storage
);
1077 if (getpeername(sockctrl
, (struct sockaddr
*) &saddr
, &saddrlen
) == -1)
1079 sock_geterror("getpeername(): ", errbuf
, PCAP_ERRBUF_SIZE
);
1083 memset(&hints
, 0, sizeof(struct addrinfo
));
1084 hints
.ai_socktype
= (startcapreq
.flags
& RPCAP_STARTCAPREQ_FLAG_DGRAM
) ? SOCK_DGRAM
: SOCK_STREAM
;
1085 hints
.ai_family
= saddr
.ss_family
;
1087 // Now we have to create a new socket to send packets
1088 if (serveropen_dp
) // Data connection is opened by the server toward the client
1090 sprintf(portdata
, "%d", ntohs(startcapreq
.portdata
));
1092 // Get the name of the other peer (needed to connect to that specific network address)
1093 if (getnameinfo((struct sockaddr
*) &saddr
, saddrlen
, peerhost
,
1094 sizeof(peerhost
), NULL
, 0, NI_NUMERICHOST
))
1096 sock_geterror("getnameinfo(): ", errbuf
, PCAP_ERRBUF_SIZE
);
1100 if (sock_initaddress(peerhost
, portdata
, &hints
, &addrinfo
, errbuf
, PCAP_ERRBUF_SIZE
) == -1)
1103 if ((sockdata
= sock_open(addrinfo
, SOCKOPEN_CLIENT
, 0, errbuf
, PCAP_ERRBUF_SIZE
)) == -1)
1106 else // Data connection is opened by the client toward the server
1108 hints
.ai_flags
= AI_PASSIVE
;
1110 // Let's the server socket pick up a free network port for us
1111 if (sock_initaddress(NULL
, "0", &hints
, &addrinfo
, errbuf
, PCAP_ERRBUF_SIZE
) == -1)
1114 if ((sockdata
= sock_open(addrinfo
, SOCKOPEN_SERVER
, 1 /* max 1 connection in queue */, errbuf
, PCAP_ERRBUF_SIZE
)) == -1)
1117 // get the complete sockaddr structure used in the data connection
1118 saddrlen
= sizeof(struct sockaddr_storage
);
1119 if (getsockname(sockdata
, (struct sockaddr
*) &saddr
, &saddrlen
) == -1)
1121 sock_geterror("getsockname(): ", errbuf
, PCAP_ERRBUF_SIZE
);
1125 // Get the local port the system picked up
1126 if (getnameinfo((struct sockaddr
*) &saddr
, saddrlen
, NULL
,
1127 0, portdata
, sizeof(portdata
), NI_NUMERICSERV
))
1129 sock_geterror("getnameinfo(): ", errbuf
, PCAP_ERRBUF_SIZE
);
1134 // addrinfo is no longer used
1135 freeaddrinfo(addrinfo
);
1138 session
->sockctrl
= sockctrl
; // Needed to send an error on the ctrl connection
1140 // Now I can set the filter
1141 if (daemon_unpackapplyfilter(session
, &totread
, &plen
, errbuf
))
1145 // Now, I can send a RPCAP start capture reply message
1146 if (sock_bufferize(NULL
, sizeof(struct rpcap_header
), NULL
, &sendbufidx
,
1147 RPCAP_NETBUF_SIZE
, SOCKBUF_CHECKONLY
, errbuf
, PCAP_ERRBUF_SIZE
) == -1)
1150 rpcap_createhdr((struct rpcap_header
*) sendbuf
, RPCAP_MSG_STARTCAP_REPLY
, 0, sizeof(struct rpcap_startcapreply
));
1152 startcapreply
= (struct rpcap_startcapreply
*) &sendbuf
[sendbufidx
];
1154 if (sock_bufferize(NULL
, sizeof(struct rpcap_startcapreply
), NULL
,
1155 &sendbufidx
, RPCAP_NETBUF_SIZE
, SOCKBUF_CHECKONLY
, errbuf
, PCAP_ERRBUF_SIZE
) == -1)
1158 memset(startcapreply
, 0, sizeof(struct rpcap_startcapreply
));
1159 startcapreply
->bufsize
= htonl(pcap_bufsize(session
->fp
));
1163 unsigned short port
= (unsigned short)strtoul(portdata
,NULL
,10);
1164 startcapreply
->portdata
= htons(port
);
1167 if (sock_send(sockctrl
, sendbuf
, sendbufidx
, errbuf
, PCAP_ERRBUF_SIZE
) == -1)
1172 SOCKET socktemp
; // We need another socket, since we're going to accept() a connection
1174 // Connection creation
1175 saddrlen
= sizeof(struct sockaddr_storage
);
1177 socktemp
= accept(sockdata
, (struct sockaddr
*) &saddr
, &saddrlen
);
1181 sock_geterror("accept(): ", errbuf
, PCAP_ERRBUF_SIZE
);
1185 // Now that I accepted the connection, the server socket is no longer needed
1186 sock_close(sockdata
, errbuf
, PCAP_ERRBUF_SIZE
);
1187 sockdata
= socktemp
;
1190 session
->sockdata
= sockdata
;
1192 /* GV we need this to create the thread as detached. */
1193 /* GV otherwise, the thread handle is not destroyed */
1194 pthread_attr_init(&detachedAttribute
);
1195 pthread_attr_setdetachstate(&detachedAttribute
, PTHREAD_CREATE_DETACHED
);
1197 // Now we have to create a new thread to receive packets
1198 if (pthread_create(threaddata
, &detachedAttribute
, daemon_thrdatamain
, (void *) session
))
1200 snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "Error creating the data thread");
1201 pthread_attr_destroy(&detachedAttribute
);
1205 pthread_attr_destroy(&detachedAttribute
);
1206 // Check if all the data has been read; if not, discard the data in excess
1207 if (totread
!= plen
)
1208 sock_discard(sockctrl
, plen
- totread
, NULL
, 0);
1213 rpcap_senderror(sockctrl
, errbuf
, PCAP_ERR_STARTCAPTURE
, NULL
);
1216 freeaddrinfo(addrinfo
);
1219 pthread_cancel(*threaddata
);
1222 sock_close(sockdata
, NULL
, 0);
1224 // Check if all the data has been read; if not, discard the data in excess
1225 if (totread
!= plen
)
1226 sock_discard(sockctrl
, plen
- totread
, NULL
, 0);
1230 pcap_close(session
->fp
);
1237 static int daemon_endcapture(struct session
*session
, pthread_t
*threaddata
, char *errbuf
)
1239 struct rpcap_header header
;
1243 pthread_cancel(*threaddata
);
1246 if (session
->sockdata
)
1248 sock_close(session
->sockdata
, NULL
, 0);
1249 session
->sockdata
= 0;
1252 pcap_close(session
->fp
);
1254 rpcap_createhdr(&header
, RPCAP_MSG_ENDCAP_REPLY
, 0, 0);
1256 if (sock_send(session
->sockctrl
, (char *) &header
, sizeof(struct rpcap_header
), errbuf
, PCAP_ERRBUF_SIZE
) == -1)
1262 static int daemon_unpackapplyfilter(struct session
*session
, uint32
*totread
, uint32
*plen
, char *errbuf
)
1265 struct rpcap_filter filter
;
1266 struct rpcap_filterbpf_insn insn
;
1267 struct bpf_insn
*bf_insn
;
1268 struct bpf_program bf_prog
;
1271 nread
= sock_recv(session
->sockctrl
, (char *) &filter
,
1272 sizeof(struct rpcap_filter
), SOCK_RECEIVEALL_YES
,
1273 errbuf
, PCAP_ERRBUF_SIZE
);
1276 // to avoid blocking on the sock_discard()
1282 bf_prog
.bf_len
= ntohl(filter
.nitems
);
1284 if (ntohs(filter
.filtertype
) != RPCAP_UPDATEFILTER_BPF
)
1286 snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "Only BPF/NPF filters are currently supported");
1290 bf_insn
= (struct bpf_insn
*) malloc (sizeof(struct bpf_insn
) * bf_prog
.bf_len
);
1291 if (bf_insn
== NULL
)
1293 snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "malloc() failed: %s", pcap_strerror(errno
));
1297 bf_prog
.bf_insns
= bf_insn
;
1299 for (i
= 0; i
< bf_prog
.bf_len
; i
++)
1301 nread
= sock_recv(session
->sockctrl
, (char *) &insn
,
1302 sizeof(struct rpcap_filterbpf_insn
), SOCK_RECEIVEALL_YES
,
1303 errbuf
, PCAP_ERRBUF_SIZE
);
1308 bf_insn
->code
= ntohs(insn
.code
);
1309 bf_insn
->jf
= insn
.jf
;
1310 bf_insn
->jt
= insn
.jt
;
1311 bf_insn
->k
= ntohl(insn
.k
);
1316 if (bpf_validate(bf_prog
.bf_insns
, bf_prog
.bf_len
) == 0)
1318 snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "The filter contains bogus instructions");
1322 if (pcap_setfilter(session
->fp
, &bf_prog
))
1324 snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "RPCAP error: %s", pcap_geterr(session
->fp
));
1331 int daemon_updatefilter(struct session
*session
, uint32 plen
)
1333 struct rpcap_header header
; // keeps the answer to the updatefilter command
1338 if (daemon_unpackapplyfilter(session
, &nread
, &plen
, pcap_geterr(session
->fp
)))
1341 // Check if all the data has been read; if not, discard the data in excess
1344 if (sock_discard(session
->sockctrl
, plen
- nread
, NULL
, 0))
1346 nread
= plen
; // just to avoid to call discard again in the 'error' section
1351 // A response is needed, otherwise the other host does not know that everything went well
1352 rpcap_createhdr(&header
, RPCAP_MSG_UPDATEFILTER_REPLY
, 0, 0);
1354 if (sock_send(session
->sockctrl
, (char *) &header
, sizeof (struct rpcap_header
), pcap_geterr(session
->fp
), PCAP_ERRBUF_SIZE
))
1362 sock_discard(session
->sockctrl
, plen
- nread
, NULL
, 0);
1364 rpcap_senderror(session
->sockctrl
, pcap_geterr(session
->fp
), PCAP_ERR_UPDATEFILTER
, NULL
);
1370 \brief Received the sampling parameters from remote host and it stores in the pcap_t structure.
1372 int daemon_setsampling(SOCKET sockctrl
, struct rpcap_sampling
*samp_param
, int plen
, char *errbuf
)
1374 struct rpcap_header header
;
1375 struct rpcap_sampling rpcap_samp
;
1376 int nread
; // number of bytes of the payload read from the socket
1378 if ((nread
= sock_recv(sockctrl
, (char *) &rpcap_samp
, sizeof(struct rpcap_sampling
),
1379 SOCK_RECEIVEALL_YES
, errbuf
, PCAP_ERRBUF_SIZE
)) == -1)
1382 // Save these settings in the pcap_t
1383 samp_param
->method
= rpcap_samp
.method
;
1384 samp_param
->value
= ntohl(rpcap_samp
.value
);
1386 // A response is needed, otherwise the other host does not know that everything went well
1387 rpcap_createhdr(&header
, RPCAP_MSG_SETSAMPLING_REPLY
, 0, 0);
1389 if (sock_send(sockctrl
, (char *) &header
, sizeof (struct rpcap_header
), errbuf
, PCAP_ERRBUF_SIZE
))
1393 sock_discard(sockctrl
, plen
- nread
, NULL
, 0);
1399 sock_discard(sockctrl
, plen
- nread
, NULL
, 0);
1401 rpcap_senderror(sockctrl
, errbuf
, PCAP_ERR_SETSAMPLING
, NULL
);
1406 int daemon_getstats(struct session
*session
)
1408 char sendbuf
[RPCAP_NETBUF_SIZE
]; // temporary buffer in which data to be sent is buffered
1409 int sendbufidx
= 0; // index which keeps the number of bytes currently buffered
1410 struct pcap_stat stats
; // local statistics
1411 struct rpcap_stats
*netstats
; // statistics sent on the network
1413 if (sock_bufferize(NULL
, sizeof(struct rpcap_header
), NULL
,
1414 &sendbufidx
, RPCAP_NETBUF_SIZE
, SOCKBUF_CHECKONLY
, pcap_geterr(session
->fp
), PCAP_ERRBUF_SIZE
) == -1)
1417 rpcap_createhdr((struct rpcap_header
*) sendbuf
, RPCAP_MSG_STATS_REPLY
, 0, (uint16
) sizeof(struct rpcap_stats
));
1419 netstats
= (struct rpcap_stats
*) &sendbuf
[sendbufidx
];
1421 if (sock_bufferize(NULL
, sizeof(struct rpcap_stats
), NULL
,
1422 &sendbufidx
, RPCAP_NETBUF_SIZE
, SOCKBUF_CHECKONLY
, pcap_geterr(session
->fp
), PCAP_ERRBUF_SIZE
) == -1)
1425 if (pcap_stats(session
->fp
, &stats
))
1428 netstats
->ifdrop
= htonl(stats
.ps_ifdrop
);
1429 netstats
->ifrecv
= htonl(stats
.ps_recv
);
1430 netstats
->krnldrop
= htonl(stats
.ps_drop
);
1431 netstats
->svrcapt
= htonl(session
->TotCapt
);
1434 if (sock_send(session
->sockctrl
, sendbuf
, sendbufidx
, pcap_geterr(session
->fp
), PCAP_ERRBUF_SIZE
) == -1)
1440 rpcap_senderror(session
->sockctrl
, pcap_geterr(session
->fp
), PCAP_ERR_GETSTATS
, NULL
);
1444 int daemon_getstatsnopcap(SOCKET sockctrl
, unsigned int ifdrops
, unsigned int ifrecv
,
1445 unsigned int krnldrop
, unsigned int svrcapt
, char *errbuf
)
1447 char sendbuf
[RPCAP_NETBUF_SIZE
]; // temporary buffer in which data to be sent is buffered
1448 int sendbufidx
= 0; // index which keeps the number of bytes currently buffered
1449 struct rpcap_stats
*netstats
; // statistics sent on the network
1451 if (sock_bufferize(NULL
, sizeof(struct rpcap_header
), NULL
,
1452 &sendbufidx
, RPCAP_NETBUF_SIZE
, SOCKBUF_CHECKONLY
, errbuf
, PCAP_ERRBUF_SIZE
) == -1)
1455 rpcap_createhdr((struct rpcap_header
*) sendbuf
, RPCAP_MSG_STATS_REPLY
, 0, (uint16
) sizeof(struct rpcap_stats
));
1457 netstats
= (struct rpcap_stats
*) &sendbuf
[sendbufidx
];
1459 if (sock_bufferize(NULL
, sizeof(struct rpcap_stats
), NULL
,
1460 &sendbufidx
, RPCAP_NETBUF_SIZE
, SOCKBUF_CHECKONLY
, errbuf
, PCAP_ERRBUF_SIZE
) == -1)
1463 netstats
->ifdrop
= htonl(ifdrops
);
1464 netstats
->ifrecv
= htonl(ifrecv
);
1465 netstats
->krnldrop
= htonl(krnldrop
);
1466 netstats
->svrcapt
= htonl(svrcapt
);
1469 if (sock_send(sockctrl
, sendbuf
, sendbufidx
, errbuf
, PCAP_ERRBUF_SIZE
) == -1)
1475 rpcap_senderror(sockctrl
, errbuf
, PCAP_ERR_GETSTATS
, NULL
);
1479 void *daemon_thrdatamain(void *ptr
)
1481 char errbuf
[PCAP_ERRBUF_SIZE
+ 1]; // error buffer
1482 struct session
*session
; // pointer to the struct session for this session
1483 int retval
; // general variable used to keep the return value of other functions
1484 struct rpcap_pkthdr
*net_pkt_header
;// header of the packet
1485 struct pcap_pkthdr
*pkt_header
; // pointer to the buffer that contains the header of the current packet
1486 u_char
*pkt_data
; // pointer to the buffer that contains the current packet
1487 char *sendbuf
; // temporary buffer in which data to be sent is buffered
1488 int sendbufidx
; // index which keeps the number of bytes currently buffered
1490 session
= (struct session
*) ptr
;
1492 session
->TotCapt
= 0; // counter which is incremented each time a packet is received
1494 // Initialize errbuf
1495 memset(errbuf
, 0, sizeof(errbuf
));
1497 // Some platforms (e.g. Win32) allow creating a static variable with this size
1498 // However, others (e.g. BSD) do not, so we're forced to allocate this buffer dynamically
1499 sendbuf
= (char *) malloc (sizeof(char) * RPCAP_NETBUF_SIZE
);
1500 if (sendbuf
== NULL
)
1502 snprintf(errbuf
, sizeof(errbuf
) - 1, "Unable to create the buffer for this child thread");
1506 // Modify thread params so that it can be killed at any time
1507 if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE
, NULL
))
1509 if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS
, NULL
))
1512 // Retrieve the packets
1513 while ((retval
= pcap_next_ex(session
->fp
, &pkt_header
, (const u_char
**) &pkt_data
)) >= 0) // cast to avoid a compiler warning
1515 if (retval
== 0) // Read timeout elapsed
1520 // Bufferize the general header
1521 if (sock_bufferize(NULL
, sizeof(struct rpcap_header
), NULL
, &sendbufidx
,
1522 RPCAP_NETBUF_SIZE
, SOCKBUF_CHECKONLY
, errbuf
, PCAP_ERRBUF_SIZE
) == -1)
1525 rpcap_createhdr((struct rpcap_header
*) sendbuf
, RPCAP_MSG_PACKET
, 0,
1526 (uint16
) (sizeof(struct rpcap_pkthdr
) + pkt_header
->caplen
));
1528 net_pkt_header
= (struct rpcap_pkthdr
*) &sendbuf
[sendbufidx
];
1530 // Bufferize the pkt header
1531 if (sock_bufferize(NULL
, sizeof(struct rpcap_pkthdr
), NULL
, &sendbufidx
,
1532 RPCAP_NETBUF_SIZE
, SOCKBUF_CHECKONLY
, errbuf
, PCAP_ERRBUF_SIZE
) == -1)
1535 net_pkt_header
->caplen
= htonl(pkt_header
->caplen
);
1536 net_pkt_header
->len
= htonl(pkt_header
->len
);
1537 net_pkt_header
->npkt
= htonl(++(session
->TotCapt
));
1538 net_pkt_header
->timestamp_sec
= htonl(pkt_header
->ts
.tv_sec
);
1539 net_pkt_header
->timestamp_usec
= htonl(pkt_header
->ts
.tv_usec
);
1541 // Bufferize the pkt data
1542 if (sock_bufferize((char *) pkt_data
, pkt_header
->caplen
, sendbuf
, &sendbufidx
,
1543 RPCAP_NETBUF_SIZE
, SOCKBUF_BUFFERIZE
, errbuf
, PCAP_ERRBUF_SIZE
) == -1)
1547 if (sock_send(session
->sockdata
, sendbuf
, sendbufidx
, errbuf
, PCAP_ERRBUF_SIZE
) == -1)
1554 snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "Error reading the packets: %s", pcap_geterr(session
->fp
));
1555 rpcap_senderror(session
->sockctrl
, errbuf
, PCAP_ERR_READEX
, NULL
);
1561 SOCK_ASSERT(errbuf
, 1);
1562 closesocket(session
->sockdata
);
1563 session
->sockdata
= 0;
1571 \brief It serializes a network address.
1573 It accepts a 'sockaddr_storage' structure as input, and it converts it appropriately into a format
1574 that can be used to be sent on the network. Basically, it applies all the hton()
1575 conversion required to the input variable.
1577 \param sockaddrin: a 'sockaddr_storage' pointer to the variable that has to be
1578 serialized. This variable can be both a 'sockaddr_in' and 'sockaddr_in6'.
1580 \param sockaddrout: an 'rpcap_sockaddr' pointer to the variable that will contain
1581 the serialized data. This variable has to be allocated by the user.
1585 \warning This function supports only AF_INET and AF_INET6 address families.
1587 void daemon_seraddr(struct sockaddr_storage
*sockaddrin
, struct rpcap_sockaddr
*sockaddrout
)
1589 memset(sockaddrout
, 0, sizeof(struct sockaddr_storage
));
1591 // There can be the case in which the sockaddrin is not available
1592 if (sockaddrin
== NULL
) return;
1594 // Warning: we support only AF_INET and AF_INET6
1595 switch (sockaddrin
->ss_family
)
1599 struct sockaddr_in
*sockaddrin_ipv4
;
1600 struct rpcap_sockaddr_in
*sockaddrout_ipv4
;
1602 sockaddrin_ipv4
= (struct sockaddr_in
*) sockaddrin
;
1603 sockaddrout_ipv4
= (struct rpcap_sockaddr_in
*) sockaddrout
;
1604 sockaddrout_ipv4
->family
= htons(RPCAP_AF_INET
);
1605 sockaddrout_ipv4
->port
= htons(sockaddrin_ipv4
->sin_port
);
1606 memcpy(&sockaddrout_ipv4
->addr
, &sockaddrin_ipv4
->sin_addr
, sizeof(sockaddrout_ipv4
->addr
));
1607 memset(sockaddrout_ipv4
->zero
, 0, sizeof(sockaddrout_ipv4
->zero
));
1614 struct sockaddr_in6
*sockaddrin_ipv6
;
1615 struct rpcap_sockaddr_in6
*sockaddrout_ipv6
;
1617 sockaddrin_ipv6
= (struct sockaddr_in6
*) sockaddrin
;
1618 sockaddrout_ipv6
= (struct rpcap_sockaddr_in6
*) sockaddrout
;
1619 sockaddrout_ipv6
->family
= htons(RPCAP_AF_INET6
);
1620 sockaddrout_ipv6
->port
= htons(sockaddrin_ipv6
->sin6_port
);
1621 sockaddrout_ipv6
->flowinfo
= htonl(sockaddrin_ipv6
->sin6_flowinfo
);
1622 memcpy(&sockaddrout_ipv6
->addr
, &sockaddrin_ipv6
->sin6_addr
, sizeof(sockaddrout_ipv6
->addr
));
1623 sockaddrout_ipv6
->scope_id
= htonl(sockaddrin_ipv6
->sin6_scope_id
);
1631 \brief Suspends a pthread for msec milliseconds.
1633 This function is provided since pthreads do not have a suspend() call.
1635 void pthread_suspend(int msec
)
1640 struct timespec abstime
;
1643 pthread_cond_t cond
;
1644 pthread_mutex_t mutex
;
1645 pthread_mutexattr_t attr
;
1647 pthread_mutexattr_init(&attr
);
1648 pthread_mutex_init(&mutex
, &attr
);
1649 pthread_mutex_lock(&mutex
);
1651 pthread_cond_init(&cond
, NULL
);
1653 gettimeofday(&now
, NULL
);
1655 abstime
.tv_sec
= now
.tv_sec
+ msec
/1000;
1656 abstime
.tv_nsec
= now
.tv_usec
* 1000 + (msec
%1000) * 1000 * 1000;
1658 pthread_cond_timedwait(&cond
, &mutex
, &abstime
);
1660 pthread_mutex_destroy(&mutex
);
1661 pthread_cond_destroy(&cond
);