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

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