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

documentation. Copyright (c) 2002-2003 Politecnico di Torino. All rights reserved.