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

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