Main Page   Modules   Data Structures   File List   Data Fields   Globals   Related Pages  

daemon.c

Go to the documentation of this file.
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.