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

pcap-new.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-int.h>   // for the details of the pcap_t structure
00034 #include <pcap-remote.h>
00035 #include <sockutils.h>
00036 #include <errno.h>      // for the errno variable
00037 #include <stdlib.h>     // for malloc(), free(), ...
00038 #include <string.h>     // for strstr, etc
00039 
00040 #ifndef WIN32
00041 #include <dirent.h>     // for readdir
00042 #endif
00043 
00044 
00045 /*
00046     \brief Global variable; needed to keep the message due to an error that we want to discard.
00047     
00048     This can happen, for instance, because we already have an error message and we want to keep 
00049     the first one.
00050 */
00051 char fakeerrbuf[PCAP_ERRBUF_SIZE + 1];
00052 
00053 
00055 extern struct activehosts *activeHosts;
00056 
00057 
00063 SOCKET sockmain;
00064 
00065 
00067 #define PCAP_TEXT_SOURCE_FILE "File"
00068 
00069 #define PCAP_TEXT_SOURCE_ADAPTER "Network adapter"
00070 
00072 #define PCAP_TEXT_SOURCE_ON_LOCAL_HOST "on local host"
00073 
00074 #define PCAP_TEXT_SOURCE_ON_REMOTE_HOST "on remote node"
00075 
00076 
00077 
00078 /****************************************************
00079  *                                                  *
00080  * Function bodies                                  *
00081  *                                                  *
00082  ****************************************************/
00083 
00084 
00147 int pcap_findalldevs_ex(char *source, struct pcap_rmtauth *auth, pcap_if_t **alldevs, char *errbuf) 
00148 {
00149 SOCKET sockctrl;            // socket descriptor of the control connection
00150 unsigned int nread= 0;      // number of bytes of the payload read from the socket
00151 struct addrinfo hints;      // temp variable needed to resove hostnames into to socket representation
00152 struct addrinfo *addrinfo;  // temp variable needed to resove hostnames into to socket representation
00153 struct rpcap_header header; // structure that keeps the general header of the rpcap protocol
00154 int i,j;        // temp variables
00155 int naddr;      // temp var needed to avoid problems with IPv6 addresses
00156 int retval;     // store the return value of the functions
00157 int nif;        // Number of interfaces listed
00158 int active= 0;  // 'true' if we the other end-party is in active mode
00159 char host[PCAP_BUF_SIZE], port[PCAP_BUF_SIZE], name[PCAP_BUF_SIZE], path[PCAP_BUF_SIZE], filename[PCAP_BUF_SIZE];
00160 int type;
00161 pcap_t *fp;
00162 char tmpstring[PCAP_BUF_SIZE + 1];      // Needed to convert names and descriptions from 'old' syntax to the 'new' one
00163 
00164     if (strlen(source) > PCAP_BUF_SIZE)
00165     {
00166         snprintf(errbuf, PCAP_ERRBUF_SIZE, "The source string is too long. Cannot handle it correctly.");
00167         return -1;
00168     }
00169 
00170     // determine the type of the source (file, local, remote)
00171     if (pcap_parsesrcstr(source, &type, host, port, NULL /* we're not interested in interface name */, errbuf) == -1)
00172         return -1;
00173 
00174     if (type == PCAP_SRC_IFLOCAL)
00175     {
00176     pcap_if_t *dev;     // Previous device into the pcap_if_t chain
00177 
00178         // Initialize temporary string
00179         tmpstring[PCAP_BUF_SIZE]= 0;
00180 
00181         // The user wants to retrieve adapters from a local host
00182         if (pcap_findalldevs(alldevs, errbuf) == -1)
00183             return -1;
00184 
00185         if ( (alldevs == NULL) || (*alldevs == NULL) )
00186         {
00187             snprintf(errbuf, PCAP_ERRBUF_SIZE,
00188                 "No interfaces found! Make sure libpcap/WinPcap is properly installed"
00189                 " on the local machine.");
00190             return -1;
00191         }
00192 
00193         // Scan all the interfaces and modify name and description
00194         // This is a trick in order to avoid the re-implementation of the pcap_findalldevs here
00195         dev= *alldevs;
00196         while (dev)
00197         {
00198             // Create the new device identifier
00199             if (pcap_createsrcstr(tmpstring, PCAP_SRC_IFLOCAL, NULL, NULL, dev->name, errbuf) == -1)
00200                 return -1;
00201 
00202             // Delete the old pointer
00203             free(dev->name);
00204 
00205             dev->name= (char *) malloc( strlen(tmpstring) + 1);
00206 
00207             if (dev->name == NULL)
00208             {
00209                 snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno));
00210                 return -1;
00211             }
00212 
00213             // Copy the new device identifier into the correct memory location
00214             strncpy(dev->name, tmpstring, strlen(tmpstring) + 1);
00215 
00216 
00217             // Create the new device description
00218             if ( (dev->description == NULL) || (dev->description[0] == 0) )
00219                 snprintf(tmpstring, sizeof(tmpstring) - 1, "%s '%s' %s", PCAP_TEXT_SOURCE_ADAPTER, 
00220                     dev->name, PCAP_TEXT_SOURCE_ON_LOCAL_HOST);
00221             else
00222                 snprintf(tmpstring, sizeof(tmpstring) - 1, "%s '%s' %s", PCAP_TEXT_SOURCE_ADAPTER, 
00223                     dev->description, PCAP_TEXT_SOURCE_ON_LOCAL_HOST);
00224 
00225             // Delete the old pointer
00226             free(dev->description);
00227 
00228             dev->description= (char *) malloc( strlen(tmpstring) + 1);
00229 
00230             if (dev->description == NULL)
00231             {
00232                 snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno));
00233                 return -1;
00234             }
00235 
00236             // Copy the new device description into the correct memory location
00237             strncpy(dev->description, tmpstring, strlen(tmpstring) + 1);
00238 
00239             dev= dev->next;
00240         }
00241 
00242         return 0;
00243     }
00244 
00245     (*alldevs)= NULL;
00246 
00247     if (type == PCAP_SRC_FILE)
00248     {
00249         int stringlen;
00250 #ifdef WIN32
00251         WIN32_FIND_DATA filedata; 
00252         HANDLE filehandle; 
00253 #else
00254         struct dirent *filedata;
00255         DIR *unixdir;
00256 #endif
00257 
00258         // Check that the filename is correct
00259         stringlen= strlen(name);
00260 
00261         // The directory must end with '\' in Win32 and '/' in UNIX
00262 #ifdef WIN32
00263     #define ENDING_CHAR '\\'
00264 #else
00265     #define ENDING_CHAR '/'
00266 #endif
00267 
00268         if (name[stringlen - 1] != ENDING_CHAR )
00269         {
00270             name[stringlen]= ENDING_CHAR;
00271             name[stringlen + 1]= 0;
00272 
00273             stringlen++;
00274         }
00275         
00276         // Save the path for future reference
00277         snprintf(path, sizeof(path), "%s", name);
00278 
00279 #ifdef WIN32
00280         // To perform directory listing, Win32 must have an 'asterisk' as ending char
00281         if (name[stringlen - 1] != '*' )
00282         {
00283             name[stringlen]= '*';
00284             name[stringlen + 1]= 0;
00285         }
00286 
00287         filehandle = FindFirstFile(name, &filedata);
00288 
00289         if (filehandle == INVALID_HANDLE_VALUE)
00290         {
00291             snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error when listing files: does folder '%s' exist?", path);
00292             return -1;
00293         }
00294 
00295 #else
00296         // opening the folder
00297         unixdir= opendir(path);
00298 
00299         // get the first file into it
00300         filedata= readdir(unixdir);
00301 
00302         if (filedata == NULL)
00303         {
00304             snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error when listing files: does folder '%s' exist?", path);
00305             return -1;
00306         }
00307 #endif
00308 
00309         do
00310         {
00311 
00312 #ifdef WIN32
00313             snprintf(filename, sizeof(filename), "%s%s", path, filedata.cFileName);
00314 #else
00315             snprintf(filename, sizeof(filename), "%s%s", path, filedata->d_name);
00316 #endif
00317 
00318             fp= pcap_open_offline(filename, errbuf);
00319 
00320             if (fp)
00321             {
00322             pcap_if_t *dev;     // Previous device into the pcap_if_t chain
00323 
00324                 // allocate the main structure
00325                 if (*alldevs == NULL)   // This is in case it is the first file
00326                 {
00327                     (*alldevs)= (pcap_if_t *) malloc(sizeof(pcap_if_t) );
00328                     dev= (*alldevs);
00329                 }
00330                 else
00331                 {
00332                     dev->next= (pcap_if_t *) malloc(sizeof(pcap_if_t) );
00333                     dev= dev->next;
00334                 }
00335 
00336                 // check that the malloc() didn't fail
00337                 if (dev == NULL)
00338                 {
00339                     snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno));
00340                     return -1;
00341                 }
00342 
00343                 // Initialize the structure to 'zero'
00344                 memset(dev, 0, sizeof(pcap_if_t) );
00345 
00346                 // Create the new source identifier
00347                 if (pcap_createsrcstr(tmpstring, PCAP_SRC_FILE, NULL, NULL, filename, errbuf) == -1)
00348                     return -1;
00349 
00350                 stringlen= strlen(tmpstring);
00351 
00352                 dev->name= (char *) malloc(stringlen + 1);
00353                 if (dev->name == NULL)
00354                 {
00355                     snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno));
00356                     return -1;
00357                 }
00358 
00359                 strncpy(dev->name, tmpstring, stringlen);
00360 
00361                 dev->name[stringlen]= 0;
00362 
00363                 // Create the description
00364                 snprintf(tmpstring, sizeof(tmpstring) - 1, "%s '%s' %s", PCAP_TEXT_SOURCE_FILE, 
00365                     dev->name, PCAP_TEXT_SOURCE_ON_LOCAL_HOST);
00366 
00367                 stringlen= strlen(tmpstring);
00368 
00369                 dev->description= (char *) malloc(stringlen + 1);
00370 
00371                 if (dev->description == NULL)
00372                 {
00373                     snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno));
00374                     return -1;
00375                 }
00376 
00377                 // Copy the new device description into the correct memory location
00378                 strncpy(dev->description, tmpstring, stringlen + 1);
00379 
00380                 pcap_close(fp);
00381             }
00382         }
00383 #ifdef WIN32
00384         while (FindNextFile(filehandle, &filedata) != 0);
00385 #else
00386         while ( (filedata= readdir(unixdir)) != NULL);
00387 #endif
00388 
00389 
00390 #ifdef WIN32
00391         // Close the search handle. 
00392         FindClose(filehandle);
00393 #endif
00394 
00395         return 0;
00396     }
00397 
00398     // If we come here, it is a remote host
00399 
00400     // Warning: this call can be the first one called by the user.
00401     // For this reason, we have to initialize the WinSock support.
00402     if (sock_init(errbuf, PCAP_ERRBUF_SIZE) == -1)
00403         return -1;
00404 
00405     // Check for active mode
00406     if ( (retval= rpcap_remoteact_getsock(host, errbuf)) == -1)
00407         return -1;
00408 
00409     if (retval)
00410     {
00411         sockctrl= retval;
00412         active= 1;
00413     }
00414     else    // we're not in active mode; let's opening a new control connection (if needed)
00415     {
00416         addrinfo= NULL;
00417 
00418         memset(&hints, 0, sizeof(struct addrinfo) );
00419         hints.ai_family = PF_UNSPEC;
00420         hints.ai_socktype = SOCK_STREAM;
00421 
00422         if ( (port == NULL) || (port[0] == 0) )
00423         {
00424             // the user chose not to specify the port
00425             if (sock_initaddress(host, RPCAP_DEFAULT_NETPORT, &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1)
00426                 return -1;
00427         }
00428         else
00429         {
00430             if (sock_initaddress(host, port, &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1)
00431                 return -1;
00432         }
00433 
00434         if ( (sockctrl= sock_open(addrinfo, SOCKOPEN_CLIENT, 0, errbuf, PCAP_ERRBUF_SIZE)) == -1)
00435             goto error;
00436 
00437         // addrinfo is no longer used
00438         freeaddrinfo(addrinfo);
00439         addrinfo= NULL;
00440 
00441         if ( rpcap_sendauth(sockctrl, auth, errbuf) == -1)
00442         {
00443             // Control connection has to be closed only in case the remote machine is in passive mode
00444             if (!active)
00445                 sock_close(sockctrl, fakeerrbuf, PCAP_ERRBUF_SIZE);
00446             return -1;
00447         }
00448     }
00449 
00450     // RPCAP findalldevs command
00451     rpcap_createhdr(&header, RPCAP_MSG_FINDALLIF_REQ, 0, 0);
00452 
00453     if ( sock_send(sockctrl, (char *) &header, sizeof(struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE) == -1 )
00454         goto error;
00455 
00456     if ( sock_recv(sockctrl, (char *) &header, sizeof(struct rpcap_header), SOCK_RECEIVEALL_YES, errbuf, PCAP_ERRBUF_SIZE) == -1)
00457         goto error;
00458 
00459     // Checks if the message is correct
00460     retval= rpcap_checkmsg(errbuf, sockctrl, &header, RPCAP_MSG_FINDALLIF_REPLY, RPCAP_MSG_ERROR, 0);
00461 
00462     if (retval != RPCAP_MSG_FINDALLIF_REPLY)        // the message is not the one expected
00463     {
00464         switch (retval)
00465         {
00466             case -3:    // Unrecoverable network error
00467             case -2:    // The other endpoint send a message that is not allowed here
00468             case -1:    // The other endpoint has a version number that is not compatible with our
00469                 break;
00470 
00471             case RPCAP_MSG_ERROR:       // The other endpoint reported an error
00472                 break;
00473 
00474             default:
00475             {
00476                 snprintf(errbuf, PCAP_ERRBUF_SIZE, "Internal error");
00477                 break;
00478             };
00479         }
00480 
00481         if (!active)
00482             sock_close(sockctrl, fakeerrbuf, PCAP_ERRBUF_SIZE);
00483 
00484         return -1;
00485     }
00486 
00487     // read the number of interfaces
00488     nif= ntohs(header.value);
00489 
00490     // loop until all interfaces have been received
00491     for (i= 0; i < nif; i++)
00492     {
00493     struct rpcap_findalldevs_if findalldevs_if;
00494     pcap_if_t *dev;     // Previous device into the pcap_if_t chain
00495     char tmpstring2[PCAP_BUF_SIZE + 1];     // Needed to convert names and descriptions from 'old' syntax to the 'new' one
00496     int stringlen;
00497 
00498         tmpstring2[PCAP_BUF_SIZE]= 0;
00499 
00500         // receive the findalldevs structure from remote hsot
00501         if ( (nread+= sock_recv(sockctrl, (char *) &findalldevs_if, 
00502             sizeof(struct rpcap_findalldevs_if), SOCK_RECEIVEALL_YES, errbuf, PCAP_ERRBUF_SIZE) ) == -1)
00503             goto error;
00504 
00505         findalldevs_if.namelen= ntohs(findalldevs_if.namelen);
00506         findalldevs_if.desclen= ntohs(findalldevs_if.desclen);
00507         findalldevs_if.naddr= ntohs(findalldevs_if.naddr);
00508 
00509         // allocate the main structure
00510         if (i == 0)
00511         {
00512             (*alldevs)= (pcap_if_t *) malloc(sizeof(pcap_if_t) );
00513             dev= (*alldevs);
00514         }
00515         else
00516         {
00517             dev->next= (pcap_if_t *) malloc(sizeof(pcap_if_t) );
00518             dev= dev->next;
00519         }
00520 
00521         // check that the malloc() didn't fail
00522         if (dev == NULL)
00523         {
00524             snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno));
00525             goto error;
00526         }
00527 
00528         // Initialize the structure to 'zero'
00529         memset(dev, 0, sizeof(pcap_if_t) );
00530 
00531         // allocate mem for name and description
00532         if (findalldevs_if.namelen)
00533         {
00534 
00535             if (findalldevs_if.namelen >= sizeof(tmpstring) )
00536             {
00537                 snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface name too long");
00538                 goto error;
00539             }
00540 
00541             // Retrieve adapter name
00542             if ( (nread+= sock_recv(sockctrl, tmpstring, findalldevs_if.namelen, SOCK_RECEIVEALL_YES, errbuf, PCAP_ERRBUF_SIZE) ) == -1)
00543                 goto error;
00544 
00545             tmpstring[findalldevs_if.namelen]= 0;
00546 
00547             // Create the new device identifier
00548             if (pcap_createsrcstr(tmpstring2, PCAP_SRC_IFREMOTE, host, port, tmpstring, errbuf) == -1)
00549                 return -1;
00550 
00551             stringlen= strlen(tmpstring2);
00552 
00553             dev->name= (char *) malloc(stringlen + 1);
00554             if (dev->name == NULL)
00555             {
00556                 snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno));
00557                 goto error;
00558             }
00559 
00560             // Copy the new device name into the correct memory location
00561             strncpy(dev->name, tmpstring2, stringlen + 1);
00562         }
00563 
00564         if (findalldevs_if.desclen)
00565         {
00566             if (findalldevs_if.desclen >= sizeof(tmpstring) )
00567             {
00568                 snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface description too long");
00569                 goto error;
00570             }
00571 
00572             // Retrieve adapter description
00573             if ( (nread+= sock_recv(sockctrl, tmpstring, findalldevs_if.desclen, SOCK_RECEIVEALL_YES, errbuf, PCAP_ERRBUF_SIZE) ) == -1)
00574                 goto error;
00575 
00576             tmpstring[findalldevs_if.desclen]= 0;
00577 
00578 
00579             snprintf(tmpstring2, sizeof(tmpstring2) - 1, "%s '%s' %s %s", PCAP_TEXT_SOURCE_ADAPTER, 
00580                 tmpstring, PCAP_TEXT_SOURCE_ON_REMOTE_HOST, host);
00581 
00582             stringlen= strlen(tmpstring2);
00583 
00584             dev->description= (char *) malloc(stringlen + 1);
00585 
00586             if (dev->description == NULL)
00587             {
00588                 snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno));
00589                 goto error;
00590             }
00591 
00592             // Copy the new device description into the correct memory location
00593             strncpy(dev->description, tmpstring2, stringlen + 1);
00594         }
00595 
00596         dev->flags= ntohl(findalldevs_if.flags);
00597 
00598         naddr= 0;
00599         // loop until all addresses have been received
00600         for (j= 0; j < findalldevs_if.naddr; j++)
00601         {
00602         struct rpcap_findalldevs_ifaddr ifaddr;
00603 
00604             // Retrieve the interface addresses
00605             if (  (nread+= sock_recv(sockctrl, (char *) &ifaddr, 
00606                 sizeof(struct rpcap_findalldevs_ifaddr), SOCK_RECEIVEALL_YES, errbuf, PCAP_ERRBUF_SIZE) ) == -1)
00607                 goto error;
00608 
00609             // WARNING libpcap bug: the address listing is available only for AF_INET
00610             if ( ntohs(ifaddr.addr.ss_family) == AF_INET)
00611             {
00612             struct pcap_addr *addr;
00613 
00614                 if (naddr == 0)
00615                 {
00616                     dev->addresses= (struct pcap_addr *) malloc ( sizeof(struct pcap_addr) );
00617                     addr= dev->addresses;
00618                 }
00619                 else
00620                 {
00621                     addr->next= (struct pcap_addr *) malloc ( sizeof(struct pcap_addr) );
00622                     addr= addr->next;
00623                 }
00624                 naddr++;
00625 
00626                 if (addr == NULL)
00627                 {
00628                     snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno));
00629                     goto error;
00630                 }
00631                 addr->next= NULL;
00632 
00633                 if (rpcap_deseraddr( (struct sockaddr_storage *) &ifaddr.addr, 
00634                     (struct sockaddr_storage **) &addr->addr, errbuf) == -1)
00635                     goto error;
00636                 if (rpcap_deseraddr( (struct sockaddr_storage *) &ifaddr.netmask, 
00637                     (struct sockaddr_storage **) &addr->netmask, errbuf) == -1)
00638                     goto error;
00639                 if (rpcap_deseraddr( (struct sockaddr_storage *) &ifaddr.broadaddr, 
00640                     (struct sockaddr_storage **) &addr->broadaddr, errbuf) == -1)
00641                     goto error;
00642                 if (rpcap_deseraddr( (struct sockaddr_storage *) &ifaddr.dstaddr, 
00643                     (struct sockaddr_storage **) &addr->dstaddr, errbuf) == -1)
00644                     goto error;
00645 
00646                 if ( (addr->addr == NULL) && (addr->netmask == NULL) && 
00647                     (addr->broadaddr == NULL) && (addr->dstaddr == NULL) )
00648                 {
00649                     free(addr);
00650                     addr= NULL;
00651                     if (naddr == 1)
00652                         naddr= 0;   // the first item of the list had NULL addresses
00653                 }
00654             }
00655         }
00656     }
00657 
00658     // Checks if all the data has been read; if not, discard the data in excess
00659     if (nread != ntohl(header.plen))
00660     {
00661         if (sock_discard(sockctrl, ntohl(header.plen) - nread, errbuf, PCAP_ERRBUF_SIZE) == 1)
00662             return -1;
00663     }
00664 
00665     // Control connection has to be closed only in case the remote machine is in passive mode
00666     if (!active)
00667     {
00668         // DO not send RPCAP_CLOSE, since we did not open a pcap_t; no need to free resources
00669         if ( sock_close(sockctrl, errbuf, PCAP_ERRBUF_SIZE) )
00670             return -1;
00671     }
00672 
00673     // To avoid inconsistencies in the number of sock_init()
00674     sock_cleanup();
00675 
00676     return 0;
00677 
00678 error:
00679     // In case there has been an error, I don't want to overwrite it with a new one
00680     // if the following call fails. I want to return always the original error.
00681     //
00682     // Take care: this connection can already be closed when we try to close it.
00683     // This happens because a previous error in the rpcapd, which requested to
00684     // closed the connection. In that case, we already recognized that into the
00685     // rpspck_isheaderok() and we already acknowledged the closing.
00686     // In that sense, this call is useless here (however it is needed in case
00687     // the client generates the error).
00688 
00689     // Checks if all the data has been read; if not, discard the data in excess
00690     if (nread != ntohl(header.plen))
00691     {
00692         if (sock_discard(sockctrl, ntohl(header.plen) - nread, fakeerrbuf, PCAP_ERRBUF_SIZE) == 1)
00693             return -1;
00694     }
00695 
00696     // Control connection has to be closed only in case the remote machine is in passive mode
00697     if (!active)
00698         sock_close(sockctrl, fakeerrbuf, PCAP_ERRBUF_SIZE);
00699 
00700     // To avoid inconsistencies in the number of sock_init()
00701     sock_cleanup();
00702 
00703     return -1;
00704 }
00705 
00706 
00707 
00708 
00753 int pcap_createsrcstr(char *source, int type, const char *host, const char *port, const char *name, char *errbuf)
00754 {
00755     switch (type)
00756     {
00757         case PCAP_SRC_FILE:
00758         {
00759             strncpy(source, PCAP_SRC_FILE_STRING, PCAP_BUF_SIZE);
00760             if ((name) && (*name) )
00761             {
00762                 strncat(source, name, PCAP_BUF_SIZE);
00763                 return 0;
00764             }
00765             else
00766             {
00767                 snprintf(errbuf, PCAP_ERRBUF_SIZE, "The file name cannot be NULL.");
00768                 return -1;
00769             }
00770         }
00771 
00772         case PCAP_SRC_IFREMOTE:
00773         {
00774             strncpy(source, PCAP_SRC_IF_STRING, PCAP_BUF_SIZE);
00775             if ((host) && (*host) )
00776             {
00777                 if ( (strcspn(host, "aAbBcCdDeEfFgGhHjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ")) == strlen(host) )
00778                 {
00779                     // the host name does not contains alphabetic chars. So, it is a numeric address
00780                     // In this case we have to include it between square brackets
00781                     strncat(source, "[", PCAP_BUF_SIZE);
00782                     strncat(source, host, PCAP_BUF_SIZE);
00783                     strncat(source, "]", PCAP_BUF_SIZE);
00784                 }
00785                 else
00786                     strncat(source, host, PCAP_BUF_SIZE);
00787 
00788                 if ((port) && (*port) )
00789                 {
00790                     strncat(source, ":", PCAP_BUF_SIZE);
00791                     strncat(source, port, PCAP_BUF_SIZE);
00792                 }
00793 
00794                 strncat(source, "/", PCAP_BUF_SIZE);
00795             }
00796             else
00797             {
00798                 snprintf(errbuf, PCAP_ERRBUF_SIZE, "The host name cannot be NULL.");
00799                 return -1;
00800             }
00801 
00802             if ((name) && (*name) )
00803                 strncat(source, name, PCAP_BUF_SIZE);
00804 
00805             return 0;
00806         }
00807 
00808         case PCAP_SRC_IFLOCAL:
00809         {
00810             strncpy(source, PCAP_SRC_IF_STRING, PCAP_BUF_SIZE);
00811 
00812             if ((name) && (*name) )
00813                 strncat(source, name, PCAP_BUF_SIZE);
00814 
00815             return 0;
00816         }
00817 
00818         default:
00819         {
00820             snprintf(errbuf, PCAP_ERRBUF_SIZE, "The interface type is not valid.");
00821             return -1;
00822         }
00823     }
00824 }
00825 
00826 
00827 
00828 
00885 int pcap_parsesrcstr(const char *source, int *type, char *host, char *port, char *name, char *errbuf)
00886 {
00887 char *ptr;
00888 int ntoken;
00889 char tmpname[PCAP_BUF_SIZE];
00890 char tmphost[PCAP_BUF_SIZE];
00891 char tmpport[PCAP_BUF_SIZE];
00892 int tmptype;
00893 
00894     // Initialization stuff
00895     tmpname[0]= 0;
00896     tmphost[0]= 0;
00897     tmpport[0]= 0;
00898 
00899     if (host)
00900         *host= 0;
00901     if (port) 
00902         *port= 0;
00903     if (name)
00904         *name= 0;
00905 
00906     // Look for a 'rpcap://' identifier
00907     if ( (ptr= strstr(source, PCAP_SRC_IF_STRING)) != NULL)
00908     {
00909         if (strlen(PCAP_SRC_IF_STRING) == strlen(source) )
00910         {
00911             // The source identifier contains only the 'rpcap://' string.
00912             // So, this is a local capture.
00913             *type= PCAP_SRC_IFLOCAL;
00914             return 0;
00915         }
00916 
00917         ptr+= strlen(PCAP_SRC_IF_STRING);
00918 
00919         if (strchr(ptr, '[')) // This is probably a numeric address
00920         {
00921             ntoken= sscanf(ptr, "[%[1234567890:.]]:%[^/]/%s", tmphost, tmpport, tmpname);
00922 
00923             if (ntoken == 1)    // probably the port is missing
00924                 ntoken= sscanf(ptr, "[%[1234567890:.]]/%s", tmphost, tmpname);
00925 
00926             tmptype= PCAP_SRC_IFREMOTE;
00927         }
00928         else
00929         {
00930             ntoken= sscanf(ptr, "%[^/:]:%[^/]/%s", tmphost, tmpport, tmpname);
00931 
00932             if (ntoken == 1)
00933             {
00934                 // This can be due to two reasons:
00935                 // - we want a remote capture, but the network port is missing
00936                 // - we want to do a local capture
00937                 // To distinguish between the two, we look for the '/' char
00938                 if (strchr(ptr, '/'))
00939                 {
00940                     // We're on a remote capture
00941                     sscanf(ptr, "%[^/]/%s", tmphost, tmpname);
00942                     tmptype= PCAP_SRC_IFREMOTE;
00943                 }
00944                 else
00945                 {
00946                     // We're on a local capture
00947                     if (*ptr)
00948                         strncpy(tmpname, ptr, PCAP_BUF_SIZE);
00949 
00950                     // Clean the host name, since it is a remote capture
00951                     // NOTE: the host name has been assigned in the previous "ntoken= sscanf(...)" line
00952                     tmphost[0]= 0;
00953 
00954                     tmptype= PCAP_SRC_IFLOCAL;
00955                 }
00956             }
00957             else
00958                 tmptype= PCAP_SRC_IFREMOTE;
00959         }
00960 
00961         if (host)
00962             strcpy(host, tmphost);
00963         if (port) 
00964             strcpy(port, tmpport);
00965         if (type)
00966             *type= tmptype;
00967 
00968         if (name)
00969         {
00970             // If the user wants the host name, but it cannot be located into the source string, return error
00971             // However, if the user is not interested in the interface name (e.g. if we're called by 
00972             // pcap_findalldevs_ex(), which does not have interface name, do not return error
00973             if (tmpname[0])
00974             {
00975                 strcpy(name, tmpname);
00976             }
00977             else
00978             {
00979                 if (errbuf)
00980                     snprintf(errbuf, PCAP_ERRBUF_SIZE, "The interface name has not been specified.");
00981 
00982                 return -1;
00983             }
00984         }
00985 
00986         return 0;
00987     }
00988 
00989     // Look for a 'file://' identifier
00990     if ( (ptr= strstr(source, PCAP_SRC_FILE_STRING)) != NULL)
00991     {
00992         ptr+= strlen(PCAP_SRC_FILE_STRING);
00993         if (*ptr)
00994         {
00995             if (name)
00996                 strncpy(name, ptr, PCAP_BUF_SIZE);
00997 
00998             if (type)
00999                 *type= PCAP_SRC_FILE;
01000 
01001             return 0;
01002         }
01003         else
01004         {
01005             if (errbuf)
01006                 snprintf(errbuf, PCAP_ERRBUF_SIZE, "The file name has not been specified.");
01007 
01008             return -1;
01009         }
01010 
01011     }
01012 
01013     // Backward compatibility; the user didn't use the 'rpcap://, file://'  specifiers
01014     if ( (source) && (*source) )
01015     {
01016         if (name)
01017             strncpy(name, source, PCAP_BUF_SIZE);
01018 
01019         if (type)
01020             *type= PCAP_SRC_IFLOCAL;
01021 
01022         return 0;
01023     }
01024     else
01025     {
01026         if (errbuf)
01027             snprintf(errbuf, PCAP_ERRBUF_SIZE, "The interface name has not been specified.");
01028 
01029         return -1;
01030     }
01031 };
01032 
01033 
01034 
01102 pcap_t *pcap_open(const char *source, int snaplen, int flags, int read_timeout, struct pcap_rmtauth *auth, char *errbuf)
01103 {
01104 char host[PCAP_BUF_SIZE], port[PCAP_BUF_SIZE], name[PCAP_BUF_SIZE];
01105 int type;
01106 pcap_t *fp;
01107 
01108     if (strlen(source) > PCAP_BUF_SIZE)
01109     {
01110         snprintf(errbuf, PCAP_ERRBUF_SIZE, "The source string is too long. Cannot handle it correctly.");
01111         return NULL;
01112     }
01113 
01114     // determine the type of the source (file, local, remote)
01115     if (pcap_parsesrcstr(source, &type, host, port, name, errbuf) == -1)
01116         return NULL;
01117 
01118 
01119     switch (type) 
01120     {
01121         case PCAP_SRC_FILE:
01122             fp = pcap_open_offline(name, errbuf);
01123             break;
01124 
01125         case PCAP_SRC_IFREMOTE:
01126             // Although we already have host, port and iface, we prefer TO PASS only 'pars' to the 
01127             // pcap_open_remote() so that it has to call the pcap_parsesrcstr() again.
01128             // This is less optimized, but much clearer.
01129             fp= pcap_opensource_remote(source, auth, errbuf);
01130 
01131             if (fp == NULL)
01132                 return NULL;
01133 
01134             fp->snapshot= snaplen;
01135 #ifdef linux
01136             fp->md.timeout= read_timeout;
01137 #else
01138             fp->timeout= read_timeout;
01139 #endif
01140             fp->rmt_flags= flags;
01141             break;
01142 
01143         case PCAP_SRC_IFLOCAL:
01144             fp= pcap_open_live(name, snaplen, (flags & PCAP_OPENFLAG_PROMISCUOUS), read_timeout, errbuf);
01145             break;
01146 
01147         default:
01148             strcpy(errbuf, "Source type not supported");
01149             return NULL;
01150     }
01151     return fp;
01152 }
01153 
01154 
01169 struct pcap_samp *pcap_setsampling(pcap_t *p)
01170 {
01171     return &(p->rmt_samp);
01172 }
01173 
01174 
01237 SOCKET pcap_remoteact_accept(const char *address, const char *port, const char *hostlist, char *connectinghost, struct pcap_rmtauth *auth, char *errbuf)
01238 {
01239 // socket-related variables
01240 struct addrinfo hints;          // temporary struct to keep settings needed to open the new socket
01241 struct addrinfo *addrinfo;      // keeps the addrinfo chain; required to open a new socket
01242 struct sockaddr_storage from;   // generic sockaddr_storage variable
01243 socklen_t fromlen;              // keeps the length of the sockaddr_storage variable
01244 SOCKET sockctrl;                // keeps the main socket identifier
01245 struct activehosts *temp, *prev;    // temp var needed to scan he host list chain
01246 
01247     *connectinghost= 0;     // just in case
01248 
01249     // Prepare to open a new server socket
01250     memset(&hints, 0, sizeof(struct addrinfo));
01251                                     // WARNING Currently it supports only ONE socket family among ipv4 and IPv6 
01252     hints.ai_family = AF_INET;      // PF_UNSPEC to have both IPv4 and IPv6 server
01253     hints.ai_flags = AI_PASSIVE;    // Ready to a bind() socket
01254     hints.ai_socktype = SOCK_STREAM;
01255 
01256     // Warning: this call can be the first one called by the user.
01257     // For this reason, we have to initialize the WinSock support.
01258     if (sock_init(errbuf, PCAP_ERRBUF_SIZE) == -1)
01259         return -1;
01260 
01261     // Do the work
01262     if ((port == NULL) || (port[0] == 0) )
01263     {   
01264         if (sock_initaddress(address, RPCAP_DEFAULT_NETPORT_ACTIVE, &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1)
01265         {
01266             SOCK_ASSERT(errbuf, 1);
01267             return -2;
01268         }
01269     }
01270     else
01271     {
01272         if (sock_initaddress(address, port, &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1)
01273         {
01274             SOCK_ASSERT(errbuf, 1);
01275             return -2;
01276         }
01277     }
01278 
01279 
01280     if ( (sockmain= sock_open(addrinfo, SOCKOPEN_SERVER, 1, errbuf, PCAP_ERRBUF_SIZE)) == -1)
01281     {
01282         SOCK_ASSERT(errbuf, 1);
01283         return -2;
01284     }
01285 
01286     // Connection creation
01287     fromlen = sizeof(struct sockaddr_storage);
01288 
01289     sockctrl= accept(sockmain, (struct sockaddr *) &from, &fromlen);
01290 
01291     // We're not using sock_close, since we do not want to send a shutdown
01292     // (which is not allowed on a non-connected socket)
01293     closesocket(sockmain);
01294     sockmain= 0;
01295 
01296     if (sockctrl == -1)
01297     {
01298         sock_geterror("accept(): ", errbuf, PCAP_ERRBUF_SIZE);
01299         return -2;
01300     }
01301 
01302     // Get the numeric for of the name of the connecting host
01303     if (getnameinfo( (struct sockaddr *) &from, fromlen, connectinghost, RPCAP_HOSTLIST_SIZE, NULL, 0, NI_NUMERICHOST) )
01304     {
01305         sock_geterror("getnameinfo(): ", errbuf, PCAP_ERRBUF_SIZE);
01306         rpcap_senderror(sockctrl, errbuf, PCAP_ERR_REMOTEACCEPT, fakeerrbuf);
01307         sock_close(sockctrl, fakeerrbuf, PCAP_ERRBUF_SIZE);
01308         return -1;
01309     }
01310 
01311     // checks if the connecting host is among the ones allowed
01312     if (sock_check_hostlist((char *) hostlist, RPCAP_HOSTLIST_SEP, &from, errbuf, PCAP_ERRBUF_SIZE) < 0)
01313     {
01314         rpcap_senderror(sockctrl, errbuf, PCAP_ERR_REMOTEACCEPT, fakeerrbuf);
01315         sock_close(sockctrl, fakeerrbuf, PCAP_ERRBUF_SIZE);
01316         return -1;
01317     }
01318 
01319     // Send authentication to the remote machine
01320     if ( rpcap_sendauth(sockctrl, auth, errbuf) == -1)
01321     {
01322         rpcap_senderror(sockctrl, errbuf, PCAP_ERR_REMOTEACCEPT, fakeerrbuf);
01323         sock_close(sockctrl, fakeerrbuf, PCAP_ERRBUF_SIZE);
01324         return -3;
01325     }
01326 
01327     // Checks that this host does not already have a cntrl connection in place
01328 
01329     // Initialize pointers
01330     temp= activeHosts;
01331     prev= NULL;
01332     
01333     while (temp)
01334     {
01335         // This host already has an active connection in place, so I don't have to update the host list
01336         if (sock_cmpaddr(&temp->host, &from) == 0)
01337             return sockctrl;
01338 
01339         prev= temp;
01340         temp= temp->next;
01341     }
01342 
01343     // The host does not exist in the list; so I have to update the list
01344     if (prev)
01345     {
01346         prev->next= (struct activehosts *) malloc (sizeof (struct activehosts) );
01347         temp= prev->next;
01348     }
01349     else
01350     {
01351         activeHosts= (struct activehosts *) malloc (sizeof (struct activehosts) );
01352         temp= activeHosts;
01353     }
01354 
01355     if (temp == NULL)
01356     {
01357         snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno));
01358         rpcap_senderror(sockctrl, errbuf, PCAP_ERR_REMOTEACCEPT, fakeerrbuf);
01359         sock_close(sockctrl, fakeerrbuf, PCAP_ERRBUF_SIZE);
01360         return -1;
01361     }
01362 
01363     memcpy(&temp->host, &from, fromlen);
01364     temp->sockctrl= sockctrl;
01365     temp->next= NULL;
01366 
01367     return sockctrl;
01368 }
01369 
01370 
01371 
01391 int pcap_remoteact_close(const char *host, char *errbuf)
01392 {
01393 struct activehosts *temp, *prev;    // temp var needed to scan the host list chain
01394 struct addrinfo hints, *addrinfo, *ai_next; // temp var needed to translate between hostname to its address
01395 int retval;
01396 
01397     temp= activeHosts;
01398     prev= NULL;
01399 
01400     // retrieve the network address corresponding to 'host'
01401     addrinfo = NULL;
01402     memset(&hints, 0, sizeof (struct addrinfo) );
01403     hints.ai_family = PF_UNSPEC;
01404     hints.ai_socktype= SOCK_STREAM;
01405 
01406     retval = getaddrinfo(host, "0", &hints, &addrinfo);
01407     if (retval != 0)
01408     {
01409         snprintf(errbuf, PCAP_ERRBUF_SIZE, "getaddrinfo() %s", gai_strerror(retval));
01410         return -1;
01411     }
01412 
01413     while (temp)
01414     {
01415         ai_next= addrinfo;
01416         while(ai_next)
01417         {
01418             if (sock_cmpaddr(&temp->host, (struct sockaddr_storage *) ai_next->ai_addr ) == 0)
01419             {
01420             struct rpcap_header header;
01421 
01422                 // Close this connection
01423                 rpcap_createhdr( &header, RPCAP_MSG_CLOSE, 0, 0);
01424 
01425                 // I don't check for errors, since I'm going to close everything
01426                 sock_send(temp->sockctrl, (char *) &header, sizeof (struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE);
01427 
01428                 if (sock_close(temp->sockctrl, errbuf, PCAP_ERRBUF_SIZE) )
01429                 {
01430                     // To avoid inconsistencies in the number of sock_init()
01431                     sock_cleanup();
01432 
01433                     return -1;
01434                 }
01435 
01436                 if (prev)
01437                     prev->next= temp->next;
01438                 else
01439                     activeHosts= temp->next;
01440 
01441                 freeaddrinfo(addrinfo);
01442 
01443                 free(temp);
01444 
01445                 // To avoid inconsistencies in the number of sock_init()
01446                 sock_cleanup();
01447 
01448                 return 0;
01449             }
01450 
01451             ai_next= ai_next->ai_next;
01452         }
01453         prev= temp;
01454         temp= temp->next;
01455     }
01456 
01457     if (addrinfo)
01458         freeaddrinfo(addrinfo);
01459 
01460     // To avoid inconsistencies in the number of sock_init()
01461     sock_cleanup();
01462 
01463     snprintf(errbuf, PCAP_ERRBUF_SIZE, "The host you want to close the active connection is not known");
01464     return -1;
01465 }
01466 
01467 
01489 void pcap_remoteact_cleanup()
01490 {
01491     // Very dirty, but it works
01492     if (sockmain)
01493     {
01494         closesocket(sockmain);
01495 
01496         // To avoid inconsistencies in the number of sock_init()
01497         sock_cleanup();
01498     }
01499 
01500 }
01501 
01502 
01526 int pcap_remoteact_list(char *hostlist, char sep, int size, char *errbuf)
01527 {
01528 struct activehosts *temp;   // temp var needed to scan the host list chain
01529 int len;
01530 char hoststr[RPCAP_HOSTLIST_SIZE + 1];
01531 
01532     temp= activeHosts;
01533 
01534     len= 0;
01535     *hostlist= 0;
01536 
01537     while (temp)
01538     {
01539 //int sock_getascii_addrport(const struct sockaddr_storage *sockaddr, char *address, int addrlen, char *port, int portlen, int flags, char *errbuf, int errbuflen)
01540 
01541         // Get the numeric form of the name of the connecting host
01542         if (sock_getascii_addrport( (struct sockaddr_storage *) &temp->host,hoststr, 
01543                 RPCAP_HOSTLIST_SIZE, NULL, 0, NI_NUMERICHOST, errbuf, PCAP_ERRBUF_SIZE) != -1)
01544 //      if (getnameinfo( (struct sockaddr *) &temp->host, sizeof (struct sockaddr_storage), hoststr, 
01545 //              RPCAP_HOSTLIST_SIZE, NULL, 0, NI_NUMERICHOST) )
01546         {
01547 //          sock_geterror("getnameinfo(): ", errbuf, PCAP_ERRBUF_SIZE);
01548             return -1;
01549         }
01550 
01551         len= len + strlen(hoststr) + 1 /* the separator */;
01552 
01553         if (len >= size)
01554         {
01555             snprintf(errbuf, PCAP_ERRBUF_SIZE, "The string you provided is not able to keep "
01556                 "the hostnames for all the active connections");
01557             return -1;
01558         }
01559 
01560         strcat(hostlist, hoststr);
01561         hostlist[len - 1]= sep;
01562         hostlist[len]= 0;
01563 
01564         temp= temp->next;
01565     }
01566 
01567     return 0;
01568 }
01569 

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