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