00001 /* 00002 * Copyright (c) 2002 - 2003 00003 * NetGroup, Politecnico di Torino (Italy) 00004 * All rights reserved. 00005 * 00006 * Redistribution and use in source and binary forms, with or without 00007 * modification, are permitted provided that the following conditions 00008 * are met: 00009 * 00010 * 1. Redistributions of source code must retain the above copyright 00011 * notice, this list of conditions and the following disclaimer. 00012 * 2. Redistributions in binary form must reproduce the above copyright 00013 * notice, this list of conditions and the following disclaimer in the 00014 * documentation and/or other materials provided with the distribution. 00015 * 3. Neither the name of the Politecnico di Torino nor the names of its 00016 * contributors may be used to endorse or promote products derived from 00017 * this software without specific prior written permission. 00018 * 00019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00020 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00021 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 00022 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 00023 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 00024 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 00025 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 00026 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 00027 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00028 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 00029 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00030 * 00031 */ 00032 00033 #include <pcap.h> // for libpcap/WinPcap calls 00034 #include <pcap-int.h> // for the pcap_t definition 00035 #include <errno.h> // for the errno variable 00036 #include <stdlib.h> // for malloc(), free(), ... 00037 #include <string.h> // for strlen(), ... 00038 #include <pthread.h> 00039 #include "pcap-remote.h" 00040 #include "daemon.h" 00041 #include "sockutils.h" // for socket calls 00042 00043 #ifndef WIN32 // for select() and such 00044 #include <unistd.h> 00045 #include <sys/time.h> 00046 #include <sys/types.h> 00047 #include <pwd.h> // for password management 00048 #endif 00049 00050 #ifdef linux 00051 #include <shadow.h> // for password management 00052 #endif 00053 00054 00055 00056 // Locally defined functions 00057 int daemon_checkauth(SOCKET sockctrl, int nullAuthAllowed, char *errbuf); 00058 int daemon_AuthUserPwd(char *username, char *password, char *errbuf); 00059 00060 int daemon_findalldevs(SOCKET sockctrl, char *errbuf); 00061 00062 int daemon_opensource(SOCKET sockctrl, char *source, int srclen, uint32 plen, char *errbuf); 00063 pcap_t *daemon_startcapture(SOCKET sockctrl, pthread_t *threaddata, char *source, int active, 00064 struct rpcap_sampling *samp_param, uint32 plen, char *errbuf); 00065 int daemon_endcapture(pcap_t *fp, pthread_t *threaddata, char *errbuf); 00066 00067 int daemon_updatefilter(pcap_t *fp, uint32 plen); 00068 int daemon_unpackapplyfilter(pcap_t *fp, unsigned int *nread, int *plen, char *errbuf); 00069 00070 int daemon_getstats(pcap_t *fp); 00071 int daemon_getstatsnopcap(SOCKET sockctrl, unsigned int ifdrops, unsigned int ifrecv, 00072 unsigned int krnldrop, unsigned int svrcapt, char *errbuf); 00073 00074 int daemon_setsampling(SOCKET sockctrl, struct rpcap_sampling *samp_param, int plen, char *errbuf); 00075 00076 void daemon_seraddr(struct sockaddr_storage *sockaddrin, struct sockaddr_storage *sockaddrout); 00077 void daemon_thrdatamain(void *ptr); 00078 00079 00080 00081 /* 00082 \brief Global variable; needed to keep the message due to an error that we want to discard. 00083 00084 This can happen, for instance, because we already have an error message and we want to keep 00085 the first one. 00086 */ 00087 char fakeerrbuf[PCAP_ERRBUF_SIZE + 1]; 00088 00089 00090 00091 // Function bodies 00092 00093 00094 00095 00096 00109 void daemon_serviceloop( void *ptr ) 00110 { 00111 char errbuf[PCAP_ERRBUF_SIZE + 1]; // keeps the error string, prior to be printed 00112 char source[PCAP_BUF_SIZE]; // keeps the string that contains the interface to open 00113 struct rpcap_header header; // RPCAP message general header 00114 pcap_t *fp= NULL; // pcap_t main variable 00115 struct daemon_slpars *pars; // parameters related to the present daemon loop 00116 00117 pthread_t threaddata= 0; // handle to the 'read from daemon and send to client' thread 00118 00119 unsigned int ifdrops, ifrecv, krnldrop, svrcapt; // needed to save the values of the statistics 00120 00121 struct rpcap_sampling samp_param; // in case sampling has been requested 00122 00123 // Structures needed for the select() call 00124 fd_set rfds; // set of socket descriptors we have to check 00125 struct timeval tv; // maximum time the select() can block waiting for data 00126 int retval; // select() return value 00127 00128 00129 pars= (struct daemon_slpars *) ptr; 00130 00131 *errbuf= 0; // Initialize errbuf 00132 00133 // If we're in active mode, this is not a separate thread 00134 if (! pars->isactive) 00135 { 00136 // Modify thread params so that it can be killed at any time 00137 if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) ) 00138 goto end; 00139 if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL) ) 00140 goto end; 00141 } 00142 00143 auth_again: 00144 // If we're in active mode, we have to check for the initial timeout 00145 if (!pars->isactive) 00146 { 00147 FD_ZERO(&rfds); 00148 // We do not have to block here 00149 tv.tv_sec = RPCAP_TIMEOUT_INIT; 00150 tv.tv_usec = 0; 00151 00152 FD_SET(pars->sockctrl, &rfds); 00153 00154 retval = select(pars->sockctrl + 1, &rfds, NULL, NULL, &tv); 00155 if (retval == -1) 00156 { 00157 sock_geterror("select(): ", errbuf, PCAP_ERRBUF_SIZE); 00158 rpcap_senderror(pars->sockctrl, errbuf, PCAP_ERR_NETW, fakeerrbuf); 00159 goto end; 00160 } 00161 00162 // The timeout has expired 00163 // So, this was a fake connection. Drop it down 00164 if (retval == 0) 00165 { 00166 rpcap_senderror(pars->sockctrl, "The RPCAP initial timeout has expired", PCAP_ERR_INITTIMEOUT, fakeerrbuf); 00167 goto end; 00168 } 00169 } 00170 00171 00172 retval= daemon_checkauth(pars->sockctrl, pars->nullAuthAllowed, errbuf); 00173 00174 if (retval) 00175 { 00176 // the other user requested to close the connection 00177 // It can be also the case of 'active mode', in which this host is not 00178 // allowed to connect to the other peer; in that case, it drops down the connection 00179 if (retval == -3) 00180 goto end; 00181 00182 // It can be an authentication failure or an unrecoverable error 00183 rpcap_senderror(pars->sockctrl, errbuf, PCAP_ERR_AUTH, fakeerrbuf); 00184 00185 // authentication error 00186 if (retval == -2) 00187 { 00188 // suspend for 1 sec 00189 // WARNING: this day is inserted only in this point; if the user drops down the connection 00190 // and it connects again, this suspension time does not have any effects. 00191 pthread_suspend(RPCAP_SUSPEND_WRONGAUTH*1000); 00192 goto auth_again; 00193 } 00194 00195 // Unrecoverable error 00196 if (retval == -1) 00197 goto end; 00198 } 00199 00200 while (1) 00201 { 00202 int retval; 00203 00204 errbuf[0]= 0; // clear errbuf 00205 00206 // Avoid zombies connections; check if the connection is opens but no commands are performed 00207 // from more than RPCAP_TIMEOUT_RUNTIME 00208 // Conditions: 00209 // - I have to be in normal mode (no active mode) 00210 // - if the device is open, I don't have to be in the middle of a capture (fp->rmt_sockdata) 00211 // - if the device is closed, I have always to check if a new command arrives 00212 // 00213 // Be carefully: the capture can have been started, but an error occurred (so fp != NULL, but 00214 // rmt_sockdata is 0 00215 if ( (!pars->isactive) && ( (fp == NULL) || ( (fp != NULL) && (fp->rmt_sockdata == 0) ) )) 00216 { 00217 // Check for the initial timeout 00218 FD_ZERO(&rfds); 00219 // We do not have to block here 00220 tv.tv_sec = RPCAP_TIMEOUT_RUNTIME; 00221 tv.tv_usec = 0; 00222 00223 FD_SET(pars->sockctrl, &rfds); 00224 00225 retval = select(pars->sockctrl + 1, &rfds, NULL, NULL, &tv); 00226 if (retval == -1) 00227 { 00228 sock_geterror("select(): ", errbuf, PCAP_ERRBUF_SIZE); 00229 rpcap_senderror(pars->sockctrl, errbuf, PCAP_ERR_NETW, fakeerrbuf); 00230 goto end; 00231 } 00232 00233 // The timeout has expired 00234 // So, this was a fake connection. Drop it down 00235 if (retval == 0) 00236 { 00237 SOCK_ASSERT("The RPCAP runtime timeout has expired", 1); 00238 rpcap_senderror(pars->sockctrl, "The RPCAP runtime timeout has expired", PCAP_ERR_RUNTIMETIMEOUT, fakeerrbuf); 00239 goto end; 00240 } 00241 } 00242 00243 if (sock_recv(pars->sockctrl, (char *) &header, sizeof(struct rpcap_header), SOCK_RECEIVEALL_YES, errbuf, PCAP_ERRBUF_SIZE) == -1) 00244 goto end; 00245 00246 // Checks if the message is correct 00247 // In case it is wrong, it discard the data 00248 retval= rpcap_checkmsg(errbuf, pars->sockctrl, &header, 00249 RPCAP_MSG_FINDALLIF_REQ, 00250 RPCAP_MSG_OPEN_REQ, 00251 RPCAP_MSG_STARTCAP_REQ, 00252 RPCAP_MSG_UPDATEFILTER_REQ, 00253 RPCAP_MSG_STATS_REQ, 00254 RPCAP_MSG_ENDCAP_REQ, 00255 RPCAP_MSG_SETSAMPLING_REQ, 00256 RPCAP_MSG_CLOSE, 00257 RPCAP_MSG_ERROR, 00258 0); 00259 00260 switch (retval) 00261 { 00262 case -3: // Unrecoverable network error 00263 goto end; // Do nothing; just exit from findalldevs; the error code is already into the errbuf 00264 00265 case -2: // The other endpoint send a message that is not allowed here 00266 { 00267 rpcap_senderror(pars->sockctrl, "The RPCAP daemon received a message that is not valid", PCAP_ERR_WRONGMSG, errbuf); 00268 } 00269 case -1: // The other endpoint has a version number that is not compatible with our 00270 { 00271 rpcap_senderror(pars->sockctrl, "RPCAP version number mismatch", PCAP_ERR_WRONGVER, errbuf); 00272 } 00273 break; 00274 00275 case RPCAP_MSG_FINDALLIF_REQ: 00276 { 00277 // Checks that the header does not contain other data; if so, discard it 00278 if (ntohl(header.plen)) 00279 sock_discard(pars->sockctrl, ntohl(header.plen), errbuf, PCAP_ERRBUF_SIZE); 00280 00281 if (daemon_findalldevs(pars->sockctrl, errbuf) ) 00282 SOCK_ASSERT(errbuf, 1); 00283 00284 break; 00285 }; 00286 00287 case RPCAP_MSG_OPEN_REQ: 00288 { 00289 retval= daemon_opensource(pars->sockctrl, source, sizeof(source), ntohl(header.plen), errbuf); 00290 00291 if (retval == -1) 00292 SOCK_ASSERT(errbuf, 1); 00293 00294 break; 00295 }; 00296 00297 case RPCAP_MSG_SETSAMPLING_REQ: 00298 { 00299 retval= daemon_setsampling(pars->sockctrl, &samp_param, ntohl(header.plen), errbuf); 00300 00301 if (retval == -1) 00302 SOCK_ASSERT(errbuf, 1); 00303 00304 break; 00305 }; 00306 00307 case RPCAP_MSG_STARTCAP_REQ: 00308 { 00309 fp= daemon_startcapture(pars->sockctrl, &threaddata, source, pars->isactive, &samp_param, ntohl(header.plen), errbuf); 00310 00311 if (fp == NULL) 00312 SOCK_ASSERT(errbuf, 1); 00313 00314 break; 00315 }; 00316 00317 case RPCAP_MSG_UPDATEFILTER_REQ: 00318 { 00319 if (fp) 00320 { 00321 if (daemon_updatefilter(fp, ntohl(header.plen)) ) 00322 SOCK_ASSERT(fp->errbuf, 1); 00323 } 00324 else 00325 { 00326 rpcap_senderror(pars->sockctrl, "Device not opened. Cannot update filter", PCAP_ERR_UPDATEFILTER, errbuf); 00327 } 00328 00329 break; 00330 }; 00331 00332 case RPCAP_MSG_STATS_REQ: 00333 { 00334 // Checks that the header does not contain other data; if so, discard it 00335 if (ntohl(header.plen)) 00336 sock_discard(pars->sockctrl, ntohl(header.plen), errbuf, PCAP_ERRBUF_SIZE); 00337 00338 if (fp) 00339 { 00340 if (daemon_getstats(fp) ) 00341 SOCK_ASSERT(fp->errbuf, 1); 00342 } 00343 else 00344 { 00345 SOCK_ASSERT("GetStats: this call should't be allowed here", 1); 00346 00347 if (daemon_getstatsnopcap(pars->sockctrl, ifdrops, ifrecv, krnldrop, svrcapt, errbuf) ) 00348 SOCK_ASSERT(errbuf, 1); 00349 // we have to keep compatibility with old applications, which ask for statistics 00350 // also when the capture has already stopped 00351 00352 // rpcap_senderror(pars->sockctrl, "Device not opened. Cannot get statistics", PCAP_ERR_GETSTATS, errbuf); 00353 } 00354 00355 break; 00356 }; 00357 00358 case RPCAP_MSG_ENDCAP_REQ: // The other endpoint close the current capture session 00359 { 00360 if (fp) 00361 { 00362 struct pcap_stat stats; 00363 00364 // Save statistics (we can need them in the future) 00365 if (pcap_stats(fp, &stats) ) 00366 { 00367 ifdrops= stats.ps_ifdrop; 00368 ifrecv= stats.ps_recv; 00369 krnldrop= stats.ps_drop; 00370 svrcapt= fp->md.TotCapt; 00371 } 00372 else 00373 ifdrops= ifrecv= krnldrop= svrcapt= 0; 00374 00375 if ( daemon_endcapture(fp, &threaddata, errbuf) ) 00376 SOCK_ASSERT(errbuf, 1); 00377 fp= NULL; 00378 } 00379 else 00380 { 00381 rpcap_senderror(pars->sockctrl, "Device not opened. Cannot close the capture", PCAP_ERR_ENDCAPTURE, errbuf); 00382 } 00383 break; 00384 }; 00385 00386 case RPCAP_MSG_CLOSE: // The other endpoint close the pcap session 00387 { 00388 // signal to the main that the user closed the control connection 00389 // This is used only in case of active mode 00390 pars->activeclose= 1; 00391 SOCK_ASSERT("The other end system asked to close the connection.", 1); 00392 goto end; 00393 break; 00394 }; 00395 00396 case RPCAP_MSG_ERROR: // The other endpoint reported an error 00397 { 00398 // Do nothing; just exit; the error code is already into the errbuf 00399 SOCK_ASSERT(errbuf, 1); 00400 break; 00401 }; 00402 00403 default: 00404 { 00405 SOCK_ASSERT("Internal error.", 1); 00406 break; 00407 }; 00408 } 00409 } 00410 00411 end: 00412 // The child thread is about to end 00413 00414 // perform pcap_t cleanup, in case it has not been done 00415 if (fp) 00416 { 00417 if (threaddata) 00418 { 00419 pthread_cancel(threaddata); 00420 threaddata= 0; 00421 } 00422 if (fp->rmt_sockdata) 00423 { 00424 sock_close(fp->rmt_sockdata, fakeerrbuf, PCAP_ERRBUF_SIZE); 00425 fp->rmt_sockdata= 0; 00426 } 00427 pcap_close(fp); 00428 fp= NULL; 00429 } 00430 00431 // Print message and exit 00432 SOCK_ASSERT("I'm exiting from the child loop", 1); 00433 SOCK_ASSERT(errbuf, 1); 00434 00435 if (!pars->isactive) 00436 { 00437 if (pars->sockctrl) 00438 sock_close(pars->sockctrl, fakeerrbuf, PCAP_ERRBUF_SIZE); 00439 00440 free(pars); 00441 #ifdef WIN32 00442 pthread_exit(0); 00443 #endif 00444 } 00445 } 00446 00447 00471 int daemon_checkauth(SOCKET sockctrl, int nullAuthAllowed, char *errbuf) 00472 { 00473 struct rpcap_header header; // RPCAP message general header 00474 int retval; // generic return value 00475 unsigned int nread; // number of bytes of the payload read from the socket 00476 struct rpcap_auth auth; // RPCAP authentication header 00477 char *string1, *string2; // two strings exchanged by the authentication message 00478 unsigned int plen; // length of the payload 00479 int retcode; // the value we have to return to the caller 00480 00481 if (sock_recv(sockctrl, (char *) &header, sizeof(struct rpcap_header), SOCK_RECEIVEALL_YES, errbuf, PCAP_ERRBUF_SIZE) == -1) 00482 return -1; 00483 00484 plen= ntohl(header.plen); 00485 00486 retval= rpcap_checkmsg(errbuf, sockctrl, &header, 00487 RPCAP_MSG_AUTH_REQ, 00488 RPCAP_MSG_CLOSE, 00489 0); 00490 00491 if (retval != RPCAP_MSG_AUTH_REQ) 00492 { 00493 switch (retval) 00494 { 00495 case -3: // Unrecoverable network error 00496 return -1; // Do nothing; just exit; the error code is already into the errbuf 00497 00498 case -2: // The other endpoint send a message that is not allowed here 00499 case -1: // The other endpoint has a version number that is not compatible with our 00500 return -2; 00501 00502 case RPCAP_MSG_CLOSE: 00503 { 00504 // Check if all the data has been read; if not, discard the data in excess 00505 if (ntohl(header.plen) ) 00506 { 00507 if (sock_discard(sockctrl, ntohl(header.plen), fakeerrbuf, PCAP_ERRBUF_SIZE) ) 00508 { 00509 retcode= -1; 00510 goto error; 00511 } 00512 } 00513 return -3; 00514 }; 00515 00516 case RPCAP_MSG_ERROR: 00517 return -3; 00518 00519 default: 00520 { 00521 SOCK_ASSERT("Internal error.", 1); 00522 retcode= -2; 00523 goto error; 00524 }; 00525 } 00526 } 00527 00528 // If it comes here, it means that we have an authentication request message 00529 if ( (nread= sock_recv(sockctrl, (char *) &auth, sizeof(struct rpcap_auth), SOCK_RECEIVEALL_YES, errbuf, PCAP_ERRBUF_SIZE)) == -1) 00530 { 00531 retcode= -1; 00532 goto error; 00533 } 00534 00535 switch (ntohs(auth.type) ) 00536 { 00537 case RPCAP_RMTAUTH_NULL: 00538 { 00539 if (!nullAuthAllowed) 00540 { 00541 snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed; NULL autentication not permitted."); 00542 retcode= -2; 00543 goto error; 00544 } 00545 break; 00546 } 00547 00548 case RPCAP_RMTAUTH_PWD: 00549 { 00550 int len1, len2; 00551 00552 len1= ntohs(auth.slen1); 00553 len2= ntohs(auth.slen2); 00554 00555 string1= (char *) malloc (len1 + 1); 00556 string2= (char *) malloc (len2 + 1); 00557 00558 if ( (string1 == NULL) || (string2 == NULL) ) 00559 { 00560 snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno)); 00561 retcode= -1; 00562 goto error; 00563 } 00564 00565 if ( (nread+= sock_recv(sockctrl, string1, len1, SOCK_RECEIVEALL_YES, errbuf, PCAP_ERRBUF_SIZE)) == -1) 00566 { 00567 retcode= -1; 00568 goto error; 00569 } 00570 if ( (nread+= sock_recv(sockctrl, string2, len2, SOCK_RECEIVEALL_YES, errbuf, PCAP_ERRBUF_SIZE)) == -1) 00571 { 00572 retcode= -1; 00573 goto error; 00574 } 00575 00576 string1[len1]= 0; 00577 string2[len2]= 0; 00578 00579 if (daemon_AuthUserPwd(string1, string2, errbuf) ) 00580 { 00581 retcode= -2; 00582 goto error; 00583 } 00584 00585 break; 00586 } 00587 00588 default: 00589 snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication type not recognized."); 00590 retcode= -2; 00591 goto error; 00592 } 00593 00594 00595 // Check if all the data has been read; if not, discard the data in excess 00596 if (nread != plen) 00597 { 00598 if (sock_discard(sockctrl, plen - nread, fakeerrbuf, PCAP_ERRBUF_SIZE) ) 00599 { 00600 retcode= -1; 00601 goto error; 00602 } 00603 } 00604 00605 rpcap_createhdr(&header, RPCAP_MSG_AUTH_REPLY, 0, 0); 00606 00607 // Send the ok message back 00608 if ( sock_send(sockctrl, (char *) &header, sizeof (struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE) == -1) 00609 { 00610 retcode= -1; 00611 goto error; 00612 } 00613 00614 return 0; 00615 00616 error: 00617 // Check if all the data has been read; if not, discard the data in excess 00618 if (nread != plen) 00619 sock_discard(sockctrl, plen - nread, fakeerrbuf, PCAP_ERRBUF_SIZE); 00620 00621 return retcode; 00622 } 00623 00624 00625 00626 int daemon_AuthUserPwd(char *username, char *password, char *errbuf) 00627 { 00628 #ifdef WIN32 00629 /* 00630 Warning: the user which launches the process must have the SE_TCB_NAME right. 00631 This corresponds to have the "Act as part of the Operating System" turined on 00632 (administrative tools, local security settings, local policies, user right assignment) 00633 However, it seems to me that if you run it as a service, this right should be 00634 provided by default. 00635 */ 00636 HANDLE Token; 00637 if (LogonUser(username, ".", password, LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, &Token) == 0) 00638 { 00639 int error; 00640 00641 error = GetLastError(); 00642 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, errbuf, 00643 PCAP_ERRBUF_SIZE, NULL); 00644 00645 return -1; 00646 } 00647 00648 // This call should change the current thread to the selected user. 00649 // I didn't test it. 00650 if (ImpersonateLoggedOnUser(Token) == 0) 00651 { 00652 int error; 00653 00654 error = GetLastError(); 00655 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, errbuf, 00656 PCAP_ERRBUF_SIZE, NULL); 00657 00658 return -1; 00659 } 00660 00661 return 0; 00662 00663 #else 00664 /* Standard user authentication: 00665 http://www.unixpapa.com/incnote/passwd.html 00666 Problem: it is not able to merge the standard pwd file with the shadow one 00667 00668 Shadow user authentication: 00669 http://www.tldp.org/HOWTO/Shadow-Password-HOWTO-8.html 00670 Problem: the program must either (1) run as root, or (2) run as user, but it 00671 must be owned by root and must be SUID root (chmod u+s rpcapd) 00672 */ 00673 00674 struct passwd *user; 00675 struct spwd *usersp; 00676 00677 // This call is needed to get the uid 00678 if ((user= getpwnam(username)) == NULL) 00679 { 00680 snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed: no such user"); 00681 return -1; 00682 } 00683 00684 #ifdef linux 00685 // This call is needed to get the password; otherwise 'x' is returned 00686 if ((usersp= getspnam(username)) == NULL) 00687 { 00688 snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed: no such user"); 00689 return -1; 00690 } 00691 00692 if (strcmp(usersp->sp_pwdp, (char *) crypt(password, usersp->sp_pwdp) ) != 0) 00693 { 00694 snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed: password incorrect"); 00695 return -1; 00696 } 00697 #endif 00698 00699 #ifdef bsd 00700 if (strcmp(user->pw_passwd, (char *) crypt(password, user->pw_passwd) ) != 0) 00701 { 00702 snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed: password incorrect"); 00703 return -1; 00704 } 00705 #endif 00706 00707 if (setuid(user->pw_uid) ) 00708 { 00709 snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s", pcap_strerror(errno) ); 00710 return -1; 00711 } 00712 00713 /* if (setgid(user->pw_gid) ) 00714 { 00715 SOCK_ASSERT("setgid failed", 1); 00716 snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s", pcap_strerror(errno) ); 00717 return -1; 00718 } 00719 */ 00720 return 0; 00721 00722 #endif 00723 00724 } 00725 00726 00727 00728 // PORTING WARNING We assume u_int is a 32bit value 00729 int daemon_findalldevs(SOCKET sockctrl, char *errbuf) 00730 { 00731 char sendbuf[RPCAP_NETBUF_SIZE]; // temporary buffer in which data to be sent is buffered 00732 int sendbufidx= 0; // index which keeps the number of bytes currently buffered 00733 pcap_if_t *alldevs; // pointer to the heade of the interface chain 00734 pcap_if_t *d; // temp pointer neede to scan the interface chain 00735 uint16 plen= 0; // length of the payload of this message 00736 struct pcap_addr *address; // pcap structure that keeps a network address of an interface 00737 struct rpcap_findalldevs_if *findalldevs_if;// rpcap structure that packet all the data of an interface together 00738 uint16 nif= 0; // counts the number of interface listed 00739 00740 // Retrieve the device list 00741 if (pcap_findalldevs(&alldevs, errbuf) == -1) 00742 { 00743 rpcap_senderror(sockctrl, errbuf, PCAP_ERR_FINDALLIF, fakeerrbuf); 00744 return -1; 00745 } 00746 00747 if (alldevs == NULL) 00748 { 00749 rpcap_senderror(sockctrl, 00750 "No interfaces found! Make sure libpcap/WinPcap is properly installed" 00751 " and you have the right to access to the remote device.", 00752 PCAP_ERR_NOREMOTEIF, 00753 errbuf); 00754 return -1; 00755 } 00756 00757 // checks the number of interfaces and it computes the total length of the payload 00758 for (d= alldevs; d != NULL; d= d->next) 00759 { 00760 nif++; 00761 00762 if (d->description) 00763 plen+= strlen(d->description); 00764 if (d->name) 00765 plen+= strlen(d->name); 00766 00767 plen+= sizeof(struct rpcap_findalldevs_if); 00768 00769 for (address= d->addresses; address != NULL; address= address->next) 00770 plen+= ( sizeof(struct sockaddr_storage) * 4); 00771 } 00772 00773 // RPCAP findalldevs command 00774 if ( sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, 00775 &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE) == -1) 00776 return -1; 00777 00778 rpcap_createhdr( (struct rpcap_header *) sendbuf, RPCAP_MSG_FINDALLIF_REPLY, nif, plen); 00779 00780 // send the interface list 00781 for (d= alldevs; d != NULL; d= d->next) 00782 { 00783 uint16 lname, ldescr; 00784 00785 findalldevs_if= (struct rpcap_findalldevs_if *) &sendbuf[sendbufidx]; 00786 00787 if ( sock_bufferize(NULL, sizeof(struct rpcap_findalldevs_if), NULL, 00788 &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE) == -1) 00789 return -1; 00790 00791 memset(findalldevs_if, 0, sizeof(struct rpcap_findalldevs_if) ); 00792 00793 if (d->description) ldescr= (short) strlen(d->description); 00794 else ldescr= 0; 00795 if (d->name) lname= (short) strlen(d->name); 00796 else lname= 0; 00797 00798 findalldevs_if->desclen= htons(ldescr); 00799 findalldevs_if->namelen= htons(lname); 00800 findalldevs_if->flags= htonl(d->flags); 00801 00802 for (address= d->addresses; address != NULL; address= address->next) 00803 findalldevs_if->naddr++; 00804 00805 findalldevs_if->naddr= htons(findalldevs_if->naddr); 00806 00807 if (sock_bufferize(d->name, lname, sendbuf, &sendbufidx, 00808 RPCAP_NETBUF_SIZE, SOCKBUF_BUFFERIZE, errbuf, PCAP_ERRBUF_SIZE) == -1) 00809 return -1; 00810 00811 if (sock_bufferize(d->description, ldescr, sendbuf, &sendbufidx, 00812 RPCAP_NETBUF_SIZE, SOCKBUF_BUFFERIZE, errbuf, PCAP_ERRBUF_SIZE) == -1) 00813 return -1; 00814 00815 // send all addresses 00816 for (address= d->addresses; address != NULL; address= address->next) 00817 { 00818 struct sockaddr_storage *sockaddr; 00819 00820 sockaddr= (struct sockaddr_storage *) &sendbuf[sendbufidx]; 00821 if (sock_bufferize(NULL, sizeof(struct sockaddr_storage), NULL, 00822 &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE) == -1) 00823 return -1; 00824 daemon_seraddr( (struct sockaddr_storage *) address->addr, sockaddr); 00825 00826 sockaddr= (struct sockaddr_storage *) &sendbuf[sendbufidx]; 00827 if (sock_bufferize(NULL, sizeof(struct sockaddr_storage), NULL, 00828 &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE) == -1) 00829 return -1; 00830 daemon_seraddr( (struct sockaddr_storage *) address->netmask, sockaddr); 00831 00832 sockaddr= (struct sockaddr_storage *) &sendbuf[sendbufidx]; 00833 if (sock_bufferize(NULL, sizeof(struct sockaddr_storage), NULL, 00834 &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE) == -1) 00835 return -1; 00836 daemon_seraddr( (struct sockaddr_storage *) address->broadaddr, sockaddr); 00837 00838 sockaddr= (struct sockaddr_storage *) &sendbuf[sendbufidx]; 00839 if (sock_bufferize(NULL, sizeof(struct sockaddr_storage), NULL, 00840 &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE) == -1) 00841 return -1; 00842 daemon_seraddr( (struct sockaddr_storage *) address->dstaddr, sockaddr); 00843 } 00844 } 00845 00846 // Send a final command that says "now send it!" 00847 if (sock_send(sockctrl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1) 00848 return -1; 00849 00850 // We do no longer need the device list. Free it 00851 pcap_freealldevs(alldevs); 00852 00853 // everything is fine 00854 return 0; 00855 } 00856 00857 00858 00859 00860 00861 /* 00862 \param plen: the length of the current message (needed in order to be able 00863 to discard excess data in the message, if present) 00864 */ 00865 int daemon_opensource(SOCKET sockctrl, char *source, int srclen, uint32 plen, char *errbuf) 00866 { 00867 pcap_t *fp= NULL; // pcap_t main variable 00868 unsigned int nread; // number of bytes of the payload read from the socket 00869 char sendbuf[RPCAP_NETBUF_SIZE]; // temporary buffer in which data to be sent is buffered 00870 int sendbufidx= 0; // index which keeps the number of bytes currently buffered 00871 struct rpcap_openreply *openreply; // open reply message 00872 00873 00874 strcpy(source, PCAP_SRC_IF_STRING); 00875 00876 if (srclen <= (int) (strlen(PCAP_SRC_IF_STRING) + plen) ) 00877 { 00878 rpcap_senderror(sockctrl, "Source string too long", PCAP_ERR_OPEN, fakeerrbuf); 00879 return -1; 00880 } 00881 00882 if ( (nread= sock_recv(sockctrl, &source[strlen(PCAP_SRC_IF_STRING)], plen, SOCK_RECEIVEALL_YES, errbuf, PCAP_ERRBUF_SIZE)) == -1) 00883 return -1; 00884 00885 // Check if all the data has been read; if not, discard the data in excess 00886 if (nread != plen) 00887 sock_discard(sockctrl, plen - nread, fakeerrbuf, PCAP_ERRBUF_SIZE); 00888 00889 // Puts a '0' to terminate the source string 00890 source[strlen(PCAP_SRC_IF_STRING) + plen]= 0; 00891 00892 // Open the selected device 00893 // This is a fake open, since we do that only to get the needed parameters, then we close the device again 00894 if ( (fp= pcap_open(source, 00895 1500 /* fake snaplen */, 00896 0 /* no promis */, 00897 1000 /* fake timeout */, 00898 NULL /* local device, so no auth */, 00899 errbuf)) == NULL) 00900 { 00901 rpcap_senderror(sockctrl, errbuf, PCAP_ERR_OPEN, fakeerrbuf); 00902 return -1; 00903 } 00904 00905 00906 // Now, I can send a RPCAP open reply message 00907 if ( sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, &sendbufidx, 00908 RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE) == -1) 00909 goto error; 00910 00911 rpcap_createhdr( (struct rpcap_header *) sendbuf, RPCAP_MSG_OPEN_REPLY, 0, sizeof(struct rpcap_openreply) ); 00912 00913 openreply= (struct rpcap_openreply *) &sendbuf[sendbufidx]; 00914 00915 if ( sock_bufferize(NULL, sizeof(struct rpcap_openreply), NULL, &sendbufidx, 00916 RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE) == -1) 00917 goto error; 00918 00919 memset(openreply, 0, sizeof(struct rpcap_openreply) ); 00920 openreply->linktype= htonl(fp->linktype); 00921 openreply->tzoff= htonl(fp->tzoff); 00922 00923 if ( sock_send(sockctrl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1) 00924 goto error; 00925 00926 // I have to close the device again, since it has been opened with wrong parameters 00927 pcap_close(fp); 00928 fp= NULL; 00929 00930 return 0; 00931 00932 error: 00933 if (fp) 00934 { 00935 pcap_close(fp); 00936 fp= NULL; 00937 } 00938 00939 return -1; 00940 } 00941 00942 00943 00944 00945 00946 /* 00947 \param plen: the length of the current message (needed in order to be able 00948 to discard excess data in the message, if present) 00949 */ 00950 pcap_t *daemon_startcapture(SOCKET sockctrl, pthread_t *threaddata, char *source, int active, struct rpcap_sampling *samp_param, uint32 plen, char *errbuf) 00951 { 00952 char portdata[PCAP_BUF_SIZE]; // temp variable needed to derive the data port 00953 char peerhost[PCAP_BUF_SIZE]; // temp variable needed to derive the host name of our peer 00954 pcap_t *fp= NULL; // pcap_t main variable 00955 unsigned int nread; // number of bytes of the payload read from the socket 00956 char sendbuf[RPCAP_NETBUF_SIZE]; // temporary buffer in which data to be sent is buffered 00957 int sendbufidx= 0; // index which keeps the number of bytes currently buffered 00958 00959 // socket-related variables 00960 SOCKET sockdata= 0; // socket descriptor of the data connection 00961 struct addrinfo hints; // temp, needed to open a socket connection 00962 struct addrinfo *addrinfo; // temp, needed to open a socket connection 00963 struct sockaddr_storage saddr; // temp, needed to retrieve the network data port chosen on the local machine 00964 socklen_t saddrlen; // temp, needed to retrieve the network data port chosen on the local machine 00965 00966 // RPCAP-related variables 00967 struct rpcap_startcapreq startcapreq; // start capture request message 00968 struct rpcap_startcapreply *startcapreply; // start capture reply message 00969 int serveropen_dp; // keeps who is going to open the data connection 00970 00971 addrinfo= NULL; 00972 00973 if ( (nread= sock_recv(sockctrl, (char *) &startcapreq, sizeof(struct rpcap_startcapreq), SOCK_RECEIVEALL_YES, errbuf, PCAP_ERRBUF_SIZE)) == -1) 00974 return NULL; 00975 00976 startcapreq.flags= ntohs(startcapreq.flags); 00977 00978 // Open the selected device 00979 if ( (fp= pcap_open(source, 00980 ntohl(startcapreq.snaplen), 00981 (startcapreq.flags & RPCAP_STARTCAPREQ_FLAG_PROMISC) ? PCAP_OPENFLAG_PROMISCUOUS : 0 /* local device, other flags not needed */, 00982 ntohl(startcapreq.read_timeout), 00983 NULL /* local device, so no auth */, 00984 errbuf)) == NULL) 00985 { 00986 rpcap_senderror(sockctrl, errbuf, PCAP_ERR_OPEN, fakeerrbuf); 00987 return NULL; 00988 } 00989 00990 // Apply sampling parameters 00991 fp->rmt_samp.method= samp_param->method; 00992 fp->rmt_samp.value= samp_param->value; 00993 00994 /* 00995 We're in active mode if: 00996 - we're using TCP, and the user wants us to be in active mode 00997 - we're using UDP 00998 */ 00999 serveropen_dp= (startcapreq.flags & RPCAP_STARTCAPREQ_FLAG_SERVEROPEN) || (startcapreq.flags & RPCAP_STARTCAPREQ_FLAG_DGRAM) || active; 01000 01001 // get the sockaddr structure referred to the other peer in the ctrl connection 01002 /* 01003 We need that because: 01004 - if we're in passive mode, we need to know the address family we want to use 01005 (the same used for the ctrl socket 01006 - if we're in active mode, we need to know the network address of the other host 01007 we want to connect to 01008 */ 01009 saddrlen = sizeof(struct sockaddr_storage); 01010 if (getpeername(sockctrl, (struct sockaddr *) &saddr, &saddrlen) == -1) 01011 { 01012 sock_geterror("getpeername(): ", errbuf, PCAP_ERRBUF_SIZE); 01013 goto error; 01014 } 01015 01016 memset(&hints, 0, sizeof(struct addrinfo) ); 01017 hints.ai_socktype = (startcapreq.flags & RPCAP_STARTCAPREQ_FLAG_DGRAM) ? SOCK_DGRAM : SOCK_STREAM; 01018 hints.ai_family = saddr.ss_family; 01019 01020 // Now we have to create a new socket to send packets 01021 if (serveropen_dp) // Data connection is opened by the server toward the client 01022 { 01023 sprintf(portdata, "%d", ntohs(startcapreq.portdata) ); 01024 01025 // Get the name of the other peer (needed to connect to that specific network address) 01026 if (getnameinfo( (struct sockaddr *) &saddr, saddrlen, peerhost, 01027 sizeof(peerhost), NULL, 0, NI_NUMERICHOST) ) 01028 { 01029 sock_geterror("getnameinfo(): ", errbuf, PCAP_ERRBUF_SIZE); 01030 goto error; 01031 } 01032 01033 if (sock_initaddress(peerhost, portdata, &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1) 01034 goto error; 01035 01036 if ( (sockdata= sock_open(addrinfo, SOCKOPEN_CLIENT, 0, errbuf, PCAP_ERRBUF_SIZE)) == -1) 01037 goto error; 01038 } 01039 else // Data connection is opened by the client toward the server 01040 { 01041 hints.ai_flags = AI_PASSIVE; 01042 01043 // Let's the server socket pick up a free network port for us 01044 if (sock_initaddress(NULL, "0", &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1) 01045 goto error; 01046 01047 if ( (sockdata= sock_open(addrinfo, SOCKOPEN_SERVER, 1 /* max 1 connection in queue */, errbuf, PCAP_ERRBUF_SIZE)) == -1) 01048 goto error; 01049 01050 // get the complete sockaddr structure used in the data connection 01051 saddrlen = sizeof(struct sockaddr_storage); 01052 if (getsockname(sockdata, (struct sockaddr *) &saddr, &saddrlen) == -1) 01053 { 01054 sock_geterror("getsockname(): ", errbuf, PCAP_ERRBUF_SIZE); 01055 goto error; 01056 } 01057 01058 // Get the local port the system picked up 01059 if (getnameinfo( (struct sockaddr *) &saddr, saddrlen, NULL, 01060 0, portdata, sizeof(portdata), NI_NUMERICSERV) ) 01061 { 01062 sock_geterror("getnameinfo(): ", errbuf, PCAP_ERRBUF_SIZE); 01063 goto error; 01064 } 01065 } 01066 01067 // addrinfo is no longer used 01068 freeaddrinfo(addrinfo); 01069 addrinfo= NULL; 01070 01071 // save the socket ID for the next calls 01072 fp->rmt_sockctrl= sockctrl; // Needed to send an error on the ctrl connection 01073 01074 // Now I can set the filter 01075 if ( daemon_unpackapplyfilter(fp, &nread, &plen, errbuf) ) 01076 goto error; 01077 01078 01079 // Now, I can send a RPCAP start capture reply message 01080 if ( sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, &sendbufidx, 01081 RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE) == -1) 01082 goto error; 01083 01084 rpcap_createhdr( (struct rpcap_header *) sendbuf, RPCAP_MSG_STARTCAP_REPLY, 0, sizeof(struct rpcap_startcapreply) ); 01085 01086 startcapreply= (struct rpcap_startcapreply *) &sendbuf[sendbufidx]; 01087 01088 if ( sock_bufferize(NULL, sizeof(struct rpcap_startcapreply), NULL, 01089 &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE) == -1) 01090 goto error; 01091 01092 memset(startcapreply, 0, sizeof(struct rpcap_startcapreply) ); 01093 startcapreply->bufsize= htonl(fp->bufsize); 01094 01095 if (!serveropen_dp) 01096 { 01097 sscanf(portdata, "%d", &(startcapreply->portdata) ); 01098 startcapreply->portdata= htons(startcapreply->portdata); 01099 } 01100 01101 if ( sock_send(sockctrl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1) 01102 goto error; 01103 01104 if (!serveropen_dp) 01105 { 01106 SOCKET socktemp; // We need another socket, since we're going to accept() a connection 01107 01108 // Connection creation 01109 saddrlen = sizeof(struct sockaddr_storage); 01110 01111 socktemp= accept(sockdata, (struct sockaddr *) &saddr, &saddrlen); 01112 01113 if (socktemp == -1) 01114 { 01115 sock_geterror("accept(): ", errbuf, PCAP_ERRBUF_SIZE); 01116 goto error; 01117 } 01118 01119 // Now that I accepted the connection, the server socket is no longer needed 01120 sock_close(sockdata, errbuf, PCAP_ERRBUF_SIZE); 01121 sockdata= socktemp; 01122 } 01123 01124 fp->rmt_sockdata= sockdata; 01125 01126 // Now we have to create a new thread to receive packets 01127 if ( pthread_create(threaddata, NULL, (void *) &daemon_thrdatamain, (void *) fp) ) 01128 { 01129 snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error creating the data thread"); 01130 goto error; 01131 } 01132 01133 // Check if all the data has been read; if not, discard the data in excess 01134 if (nread != plen) 01135 sock_discard(sockctrl, plen - nread, fakeerrbuf, PCAP_ERRBUF_SIZE); 01136 01137 return fp; 01138 01139 error: 01140 rpcap_senderror(sockctrl, errbuf, PCAP_ERR_STARTCAPTURE, fakeerrbuf); 01141 01142 if (addrinfo) 01143 freeaddrinfo(addrinfo); 01144 01145 if (threaddata) 01146 pthread_cancel(*threaddata); 01147 01148 if (sockdata) 01149 sock_close(sockdata, fakeerrbuf, PCAP_ERRBUF_SIZE); 01150 01151 // Check if all the data has been read; if not, discard the data in excess 01152 if (nread != plen) 01153 sock_discard(sockctrl, plen - nread, fakeerrbuf, PCAP_ERRBUF_SIZE); 01154 01155 if (fp) 01156 { 01157 pcap_close(fp); 01158 fp= NULL; 01159 } 01160 01161 return NULL; 01162 } 01163 01164 01165 01166 int daemon_endcapture(pcap_t *fp, pthread_t *threaddata, char *errbuf) 01167 { 01168 struct rpcap_header header; 01169 SOCKET sockctrl; 01170 01171 if (threaddata) 01172 { 01173 pthread_cancel(*threaddata); 01174 threaddata= 0; 01175 } 01176 if (fp->rmt_sockdata) 01177 { 01178 sock_close(fp->rmt_sockdata, fakeerrbuf, PCAP_ERRBUF_SIZE); 01179 fp->rmt_sockdata= 0; 01180 } 01181 01182 sockctrl= fp->rmt_sockctrl; 01183 01184 pcap_close(fp); 01185 fp= NULL; 01186 01187 rpcap_createhdr( &header, RPCAP_MSG_ENDCAP_REPLY, 0, 0); 01188 01189 if ( sock_send(sockctrl, (char *) &header, sizeof(struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE) == -1) 01190 return -1; 01191 01192 return 0; 01193 } 01194 01195 01196 01197 int daemon_unpackapplyfilter(pcap_t *fp, unsigned int *nread, int *plen, char *errbuf) 01198 { 01199 struct rpcap_filter filter; 01200 struct rpcap_filterbpf_insn insn; 01201 struct bpf_insn *bf_insn; 01202 struct bpf_program bf_prog; 01203 unsigned int i; 01204 01205 01206 if ( ( *nread+= sock_recv(fp->rmt_sockctrl, (char *) &filter, sizeof(struct rpcap_filter), SOCK_RECEIVEALL_YES, errbuf, PCAP_ERRBUF_SIZE)) == -1) 01207 { 01208 // to avoid blocking on the sock_discard() 01209 *plen= *nread; 01210 return -1; 01211 } 01212 01213 bf_prog.bf_len= ntohl(filter.nitems); 01214 01215 if (bf_prog.bf_len == 0) // No filters have been specified; so, let's apply a "fake" filter 01216 { 01217 if (pcap_compile(fp, &bf_prog, NULL, 1, 0) == -1) 01218 return -1; 01219 } 01220 else 01221 { 01222 if (ntohs(filter.filtertype) != RPCAP_UPDATEFILTER_BPF) 01223 { 01224 snprintf(errbuf, PCAP_ERRBUF_SIZE, "Only BPF/NPF filters are currently supported"); 01225 return -1; 01226 } 01227 01228 bf_insn= (struct bpf_insn *) malloc ( sizeof(struct bpf_insn) * bf_prog.bf_len); 01229 if (bf_insn == NULL) 01230 { 01231 snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno)); 01232 return -1; 01233 } 01234 01235 bf_prog.bf_insns= bf_insn; 01236 01237 for (i= 0; i < bf_prog.bf_len; i++) 01238 { 01239 if ( ( *nread+= sock_recv(fp->rmt_sockctrl, (char *) &insn, 01240 sizeof(struct rpcap_filterbpf_insn), SOCK_RECEIVEALL_YES, errbuf, PCAP_ERRBUF_SIZE)) == -1) 01241 return -1; 01242 01243 bf_insn->code= ntohs(insn.code); 01244 bf_insn->jf= insn.jf; 01245 bf_insn->jt= insn.jt; 01246 bf_insn->k= ntohl(insn.k); 01247 01248 bf_insn++; 01249 } 01250 01251 if (bpf_validate(bf_prog.bf_insns, bf_prog.bf_len) == 0) 01252 { 01253 snprintf(errbuf, PCAP_ERRBUF_SIZE, "The filter contains bogus instructions"); 01254 return -1; 01255 } 01256 } 01257 01258 if (pcap_setfilter(fp, &bf_prog) ) 01259 { 01260 snprintf(errbuf, PCAP_ERRBUF_SIZE, "RPCAP error: %s", fp->errbuf); 01261 return -1; 01262 } 01263 01264 return 0; 01265 } 01266 01267 01268 01269 int daemon_updatefilter(pcap_t *fp, uint32 plen) 01270 { 01271 struct rpcap_header header; // keeps the answer to the updatefilter command 01272 unsigned int nread; 01273 01274 if ( daemon_unpackapplyfilter(fp, &nread, &plen, fp->errbuf) ) 01275 goto error; 01276 01277 // Check if all the data has been read; if not, discard the data in excess 01278 if (nread != plen) 01279 { 01280 if (sock_discard(fp->rmt_sockctrl, plen - nread, fakeerrbuf, PCAP_ERRBUF_SIZE) ) 01281 { 01282 nread= plen; // just to avoid to call discard again in the 'error' section 01283 goto error; 01284 } 01285 } 01286 01287 // A response is needed, otherwise the other host does not know that everything went well 01288 rpcap_createhdr( &header, RPCAP_MSG_UPDATEFILTER_REPLY, 0, 0); 01289 01290 if ( sock_send(fp->rmt_sockctrl, (char *) &header, sizeof (struct rpcap_header), fp->errbuf, PCAP_ERRBUF_SIZE) ) 01291 goto error; 01292 01293 return 0; 01294 01295 01296 error: 01297 if (nread != plen) 01298 sock_discard(fp->rmt_sockctrl, plen - nread, fakeerrbuf, PCAP_ERRBUF_SIZE); 01299 01300 rpcap_senderror(fp->rmt_sockctrl, fp->errbuf, PCAP_ERR_UPDATEFILTER, fakeerrbuf); 01301 01302 return -1; 01303 } 01304 01305 01306 01310 int daemon_setsampling(SOCKET sockctrl, struct rpcap_sampling *samp_param, int plen, char *errbuf) 01311 { 01312 struct rpcap_header header; 01313 struct rpcap_sampling rpcap_samp; 01314 int nread; // number of bytes of the payload read from the socket 01315 01316 01317 if ( ( nread= sock_recv(sockctrl, (char *) &rpcap_samp, sizeof(struct rpcap_sampling), 01318 SOCK_RECEIVEALL_YES, errbuf, PCAP_ERRBUF_SIZE)) == -1) 01319 goto error; 01320 01321 01322 // Save these settings in the pcap_t 01323 samp_param->method= rpcap_samp.method; 01324 samp_param->value= ntohl(rpcap_samp.value); 01325 01326 01327 // A response is needed, otherwise the other host does not know that everything went well 01328 rpcap_createhdr( &header, RPCAP_MSG_SETSAMPLING_REPLY, 0, 0); 01329 01330 if ( sock_send(sockctrl, (char *) &header, sizeof (struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE) ) 01331 goto error; 01332 01333 if (nread != plen) 01334 sock_discard(sockctrl, plen - nread, fakeerrbuf, PCAP_ERRBUF_SIZE); 01335 01336 return 0; 01337 01338 error: 01339 if (nread != plen) 01340 sock_discard(sockctrl, plen - nread, fakeerrbuf, PCAP_ERRBUF_SIZE); 01341 01342 rpcap_senderror(sockctrl, errbuf, PCAP_ERR_SETSAMPLING, fakeerrbuf); 01343 01344 return -1; 01345 } 01346 01347 01348 01349 int daemon_getstats(pcap_t *fp) 01350 { 01351 char sendbuf[RPCAP_NETBUF_SIZE]; // temporary buffer in which data to be sent is buffered 01352 int sendbufidx= 0; // index which keeps the number of bytes currently buffered 01353 struct pcap_stat stats; // local statistics 01354 struct rpcap_stats *netstats; // statistics sent on the network 01355 01356 if ( sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, 01357 &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, fp->errbuf, PCAP_ERRBUF_SIZE) == -1) 01358 goto error; 01359 01360 rpcap_createhdr( (struct rpcap_header *) sendbuf, RPCAP_MSG_STATS_REPLY, 0, (uint16) sizeof(struct rpcap_stats)); 01361 01362 netstats= (struct rpcap_stats *) &sendbuf[sendbufidx]; 01363 01364 if ( sock_bufferize(NULL, sizeof(struct rpcap_stats), NULL, 01365 &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, fp->errbuf, PCAP_ERRBUF_SIZE) == -1) 01366 goto error; 01367 01368 if (pcap_stats(fp, &stats) ) 01369 goto error; 01370 01371 netstats->ifdrop= htonl(stats.ps_ifdrop); 01372 netstats->ifrecv= htonl(stats.ps_recv); 01373 netstats->krnldrop= htonl(stats.ps_drop); 01374 netstats->svrcapt= htonl(fp->md.TotCapt); 01375 01376 // Send the packet 01377 if ( sock_send(fp->rmt_sockctrl, sendbuf, sendbufidx, fp->errbuf, PCAP_ERRBUF_SIZE) == -1) 01378 goto error; 01379 01380 return 0; 01381 01382 error: 01383 rpcap_senderror(fp->rmt_sockctrl, fp->errbuf, PCAP_ERR_GETSTATS, fakeerrbuf); 01384 return -1; 01385 } 01386 01387 01388 01389 01390 int daemon_getstatsnopcap(SOCKET sockctrl, unsigned int ifdrops, unsigned int ifrecv, 01391 unsigned int krnldrop, unsigned int svrcapt, char *errbuf) 01392 { 01393 char sendbuf[RPCAP_NETBUF_SIZE]; // temporary buffer in which data to be sent is buffered 01394 int sendbufidx= 0; // index which keeps the number of bytes currently buffered 01395 struct rpcap_stats *netstats; // statistics sent on the network 01396 01397 if ( sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, 01398 &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE) == -1) 01399 goto error; 01400 01401 rpcap_createhdr( (struct rpcap_header *) sendbuf, RPCAP_MSG_STATS_REPLY, 0, (uint16) sizeof(struct rpcap_stats)); 01402 01403 netstats= (struct rpcap_stats *) &sendbuf[sendbufidx]; 01404 01405 if ( sock_bufferize(NULL, sizeof(struct rpcap_stats), NULL, 01406 &sendbufidx, RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE) == -1) 01407 goto error; 01408 01409 netstats->ifdrop= htonl(ifdrops); 01410 netstats->ifrecv= htonl(ifrecv); 01411 netstats->krnldrop= htonl(krnldrop); 01412 netstats->svrcapt= htonl(svrcapt); 01413 01414 // Send the packet 01415 if ( sock_send(sockctrl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1) 01416 goto error; 01417 01418 return 0; 01419 01420 error: 01421 rpcap_senderror(sockctrl, errbuf, PCAP_ERR_GETSTATS, fakeerrbuf); 01422 return -1; 01423 } 01424 01425 01426 01427 01428 void daemon_thrdatamain(void *ptr) 01429 { 01430 char errbuf[PCAP_ERRBUF_SIZE + 1]; // error buffer 01431 pcap_t *fp; // pointer to a 'pcap' structure 01432 int retval; // general variable used to keep the return value of other functions 01433 struct rpcap_pkthdr *net_pkt_header;// header of the packet 01434 struct pcap_pkthdr *pkt_header; // pointer to the buffer that contains the header of the current packet 01435 u_char *pkt_data; // pointer to the buffer that contains the current packet 01436 char sendbuf[RPCAP_NETBUF_SIZE]; // temporary buffer in which data to be sent is buffered 01437 int sendbufidx; // index which keeps the number of bytes currently buffered 01438 int samp_npkt= 0; // parameter needed for sampling, whtn '1 out of N' method has been requested 01439 struct timeval samp_time; // parameter needed for sampling, whtn '1 every N ms' method has been requested 01440 01441 fp= (pcap_t *) ptr; 01442 01443 memset(&samp_time, 0, sizeof (struct timeval) ); 01444 01445 fp->md.TotCapt= 0; // counter which is incremented each time a packet is received 01446 01447 // Initialize errbuf 01448 memset(errbuf, 0, sizeof(errbuf) ); 01449 01450 // Modify thread params so that it can be killed at any time 01451 if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) ) 01452 goto error; 01453 if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL) ) 01454 goto error; 01455 01456 // Retrieve the packets 01457 while ((retval = pcap_next_ex(fp, &pkt_header, &pkt_data)) >= 0) 01458 { 01459 if (retval == 0) // Read timeout elapsed 01460 continue; 01461 01462 if (fp->rmt_samp.method == PCAP_SAMP_1_EVERY_N) 01463 { 01464 samp_npkt= (samp_npkt + 1) % fp->rmt_samp.value; 01465 01466 // Discard all packets that are not '1 out of N' 01467 if (samp_npkt != 0) 01468 continue; 01469 } 01470 01471 if (fp->rmt_samp.method == PCAP_SAMP_FIRST_AFTER_N_MS) 01472 { 01473 // Check if the timestamp of the arrived packet is smaller than our target time 01474 if ( (pkt_header->ts.tv_sec < samp_time.tv_sec) || 01475 ( (pkt_header->ts.tv_sec == samp_time.tv_sec) && (pkt_header->ts.tv_usec < samp_time.tv_usec) ) ) 01476 continue; 01477 01478 // The arrived packet is suitable for being sent to the remote host 01479 // So, let's update the target time 01480 samp_time.tv_usec= pkt_header->ts.tv_usec + fp->rmt_samp.value * 1000; 01481 if (samp_time.tv_usec > 1000000) 01482 { 01483 samp_time.tv_sec= pkt_header->ts.tv_sec + samp_time.tv_usec / 1000000; 01484 samp_time.tv_usec= samp_time.tv_usec % 1000000; 01485 } 01486 01487 } 01488 01489 sendbufidx= 0; 01490 01491 // Bufferize the general header 01492 if ( sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, &sendbufidx, 01493 RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE) == -1) 01494 goto error; 01495 01496 rpcap_createhdr( (struct rpcap_header *) sendbuf, RPCAP_MSG_PACKET, 0, 01497 (uint16) (sizeof(struct rpcap_pkthdr) + pkt_header->caplen) ); 01498 01499 net_pkt_header= (struct rpcap_pkthdr *) &sendbuf[sendbufidx]; 01500 01501 // Bufferize the pkt header 01502 if ( sock_bufferize(NULL, sizeof(struct rpcap_pkthdr), NULL, &sendbufidx, 01503 RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE) == -1) 01504 goto error; 01505 01506 net_pkt_header->caplen= htonl(pkt_header->caplen); 01507 net_pkt_header->len= htonl(pkt_header->len); 01508 net_pkt_header->npkt= htonl( ++(fp->md.TotCapt) ); 01509 net_pkt_header->timestamp_sec= htonl(pkt_header->ts.tv_sec); 01510 net_pkt_header->timestamp_usec= htonl(pkt_header->ts.tv_usec); 01511 01512 // Bufferize the pkt data 01513 if ( sock_bufferize((char *) pkt_data, pkt_header->caplen, sendbuf, &sendbufidx, 01514 RPCAP_NETBUF_SIZE, SOCKBUF_BUFFERIZE, errbuf, PCAP_ERRBUF_SIZE) == -1) 01515 goto error; 01516 01517 // Send the packet 01518 if ( sock_send(fp->rmt_sockdata, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1) 01519 goto error; 01520 01521 } 01522 01523 if (retval == -1) 01524 { 01525 snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error reading the packets: %s", pcap_geterr(fp) ); 01526 rpcap_senderror(fp->rmt_sockctrl, errbuf, PCAP_ERR_READEX, fakeerrbuf); 01527 goto error; 01528 } 01529 01530 error: 01531 01532 SOCK_ASSERT(errbuf, 1); 01533 closesocket(fp->rmt_sockdata); 01534 fp->rmt_sockdata= 0; 01535 01536 return; 01537 } 01538 01539 01540 01558 void daemon_seraddr(struct sockaddr_storage *sockaddrin, struct sockaddr_storage *sockaddrout) 01559 { 01560 memset(sockaddrout, 0, sizeof(struct sockaddr_storage) ); 01561 01562 // There can be the case in which the sockaddrin is not available 01563 if (sockaddrin == NULL) return; 01564 01565 // Warning: we support only AF_INET and AF_INET6 01566 if (sockaddrin->ss_family == AF_INET) 01567 { 01568 struct sockaddr_in *sockaddr; 01569 01570 sockaddr= (struct sockaddr_in *) sockaddrin; 01571 sockaddr->sin_family= htons(sockaddr->sin_family); 01572 sockaddr->sin_port= htons(sockaddr->sin_port); 01573 memcpy(sockaddrout, sockaddr, sizeof(struct sockaddr_in) ); 01574 } 01575 else 01576 { 01577 struct sockaddr_in6 *sockaddr; 01578 01579 sockaddr= (struct sockaddr_in6 *) sockaddrin; 01580 sockaddr->sin6_family= htons(sockaddr->sin6_family); 01581 sockaddr->sin6_port= htons(sockaddr->sin6_port); 01582 sockaddr->sin6_flowinfo= htonl(sockaddr->sin6_flowinfo); 01583 sockaddr->sin6_scope_id= htonl(sockaddr->sin6_scope_id); 01584 memcpy(sockaddrout, sockaddr, sizeof(struct sockaddr_in6) ); 01585 } 01586 } 01587 01588 01589 01590 01591 01597 void pthread_suspend(int msec) 01598 { 01599 #ifdef WIN32 01600 Sleep(msec); 01601 #else 01602 struct timespec abstime; 01603 struct timeval now; 01604 01605 pthread_cond_t cond; 01606 pthread_mutex_t mutex; 01607 pthread_mutexattr_t attr; 01608 01609 pthread_mutexattr_init(&attr); 01610 pthread_mutex_init(&mutex, &attr); 01611 pthread_mutex_lock(&mutex); 01612 01613 pthread_cond_init(&cond, NULL); 01614 01615 gettimeofday(&now, NULL); 01616 01617 abstime.tv_sec = now.tv_sec + msec/1000; 01618 abstime.tv_nsec = now.tv_usec * 1000 + (msec%1000) * 1000 * 1000; 01619 01620 pthread_cond_timedwait(&cond, &mutex, &abstime); 01621 01622 pthread_mutex_destroy(&mutex); 01623 pthread_cond_destroy(&cond); 01624 #endif 01625 } 01626 01627 01628
documentation. Copyright (c) 2002-2003 Politecnico di Torino. All rights reserved.