1 /* 2 * Copyright (c) 2002 - 2005 NetGroup, Politecnico di Torino (Italy) 3 * Copyright (c) 2005 - 2008 CACE Technologies, Davis (California) 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the Politecnico di Torino, CACE Technologies 16 * nor the names of its contributors may be used to endorse or promote 17 * products derived from this software without specific prior written 18 * permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 * 32 */ 33 34 #ifdef HAVE_CONFIG_H 35 #include "config.h" 36 #endif 37 38 #include "pcap-int.h" // for the details of the pcap_t structure 39 #include "pcap-rpcap.h" 40 #include "sockutils.h" 41 #include <errno.h> // for the errno variable 42 #include <stdlib.h> // for malloc(), free(), ... 43 #include <string.h> // for strstr, etc 44 45 #ifndef WIN32 46 #include <dirent.h> // for readdir 47 #endif 48 49 /* Keeps a list of all the opened connections in the active mode. */ 50 extern struct activehosts *activeHosts; 51 52 /* 53 * \brief Keeps the main socket identifier when we want to accept a new remote connection (active mode only). 54 * See the documentation of pcap_remoteact_accept() and pcap_remoteact_cleanup() for more details. 55 */ 56 SOCKET sockmain; 57 58 /* String identifier to be used in the pcap_findalldevs_ex() */ 59 #define PCAP_TEXT_SOURCE_FILE "File" 60 /* String identifier to be used in the pcap_findalldevs_ex() */ 61 #define PCAP_TEXT_SOURCE_ADAPTER "Network adapter" 62 63 /* String identifier to be used in the pcap_findalldevs_ex() */ 64 #define PCAP_TEXT_SOURCE_ON_LOCAL_HOST "on local host" 65 /* String identifier to be used in the pcap_findalldevs_ex() */ 66 #define PCAP_TEXT_SOURCE_ON_REMOTE_HOST "on remote node" 67 68 /* 69 * Private data for capturing on WinPcap devices. 70 */ 71 struct pcap_win { 72 int nonblock; 73 int rfmon_selfstart; /* a flag tells whether the monitor mode is set by itself */ 74 int filtering_in_kernel; /* using kernel filter */ 75 76 #ifdef HAVE_DAG_API 77 int dag_fcs_bits; /* Number of checksum bits from link layer */ 78 #endif 79 }; 80 81 /**************************************************** 82 * * 83 * Function bodies * 84 * * 85 ****************************************************/ 86 87 int pcap_findalldevs_ex(char *source, struct pcap_rmtauth *auth, pcap_if_t **alldevs, char *errbuf) 88 { 89 SOCKET sockctrl; /* socket descriptor of the control connection */ 90 uint32 totread = 0; /* number of bytes of the payload read from the socket */ 91 int nread; 92 struct addrinfo hints; /* temp variable needed to resolve hostnames into to socket representation */ 93 struct addrinfo *addrinfo; /* temp variable needed to resolve hostnames into to socket representation */ 94 struct rpcap_header header; /* structure that keeps the general header of the rpcap protocol */ 95 int i, j; /* temp variables */ 96 int naddr; /* temp var needed to avoid problems with IPv6 addresses */ 97 struct pcap_addr *addr; /* another such temp */ 98 int retval; /* store the return value of the functions */ 99 int nif; /* Number of interfaces listed */ 100 int active = 0; /* 'true' if we the other end-party is in active mode */ 101 char host[PCAP_BUF_SIZE], port[PCAP_BUF_SIZE], name[PCAP_BUF_SIZE], path[PCAP_BUF_SIZE], filename[PCAP_BUF_SIZE]; 102 int type; 103 pcap_t *fp; 104 char tmpstring[PCAP_BUF_SIZE + 1]; /* Needed to convert names and descriptions from 'old' syntax to the 'new' one */ 105 pcap_if_t *dev; /* Previous device into the pcap_if_t chain */ 106 107 108 if (strlen(source) > PCAP_BUF_SIZE) 109 { 110 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The source string is too long. Cannot handle it correctly."); 111 return -1; 112 } 113 114 /* 115 * Determine the type of the source (file, local, remote) 116 * There are some differences if pcap_findalldevs_ex() is called to list files and remote adapters. 117 * In the first case, the name of the directory we have to look into must be present (therefore 118 * the 'name' parameter of the pcap_parsesrcstr() is present). 119 * In the second case, the name of the adapter is not required (we need just the host). So, we have 120 * to use a first time this function to get the source type, and a second time to get the appropriate 121 * info, which depends on the source type. 122 */ 123 if (pcap_parsesrcstr(source, &type, NULL, NULL, NULL, errbuf) == -1) 124 return -1; 125 126 if (type == PCAP_SRC_IFLOCAL) 127 { 128 if (pcap_parsesrcstr(source, &type, host, NULL, NULL, errbuf) == -1) 129 return -1; 130 131 /* Initialize temporary string */ 132 tmpstring[PCAP_BUF_SIZE] = 0; 133 134 /* The user wants to retrieve adapters from a local host */ 135 if (pcap_findalldevs(alldevs, errbuf) == -1) 136 return -1; 137 138 if ((alldevs == NULL) || (*alldevs == NULL)) 139 { 140 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, 141 "No interfaces found! Make sure libpcap/WinPcap is properly installed" 142 " on the local machine."); 143 return -1; 144 } 145 146 /* Scan all the interfaces and modify name and description */ 147 /* This is a trick in order to avoid the re-implementation of the pcap_findalldevs here */ 148 dev = *alldevs; 149 while (dev) 150 { 151 /* Create the new device identifier */ 152 if (pcap_createsrcstr(tmpstring, PCAP_SRC_IFLOCAL, NULL, NULL, dev->name, errbuf) == -1) 153 return -1; 154 155 /* Delete the old pointer */ 156 free(dev->name); 157 158 /* Make a copy of the new device identifier */ 159 dev->name = strdup(tmpstring); 160 if (dev->name == NULL) 161 { 162 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno)); 163 return -1; 164 } 165 166 /* Create the new device description */ 167 if ((dev->description == NULL) || (dev->description[0] == 0)) 168 pcap_snprintf(tmpstring, sizeof(tmpstring) - 1, "%s '%s' %s", PCAP_TEXT_SOURCE_ADAPTER, 169 dev->name, PCAP_TEXT_SOURCE_ON_LOCAL_HOST); 170 else 171 pcap_snprintf(tmpstring, sizeof(tmpstring) - 1, "%s '%s' %s", PCAP_TEXT_SOURCE_ADAPTER, 172 dev->description, PCAP_TEXT_SOURCE_ON_LOCAL_HOST); 173 174 /* Delete the old pointer */ 175 free(dev->description); 176 177 /* Make a copy of the description */ 178 dev->description = strdup(tmpstring); 179 if (dev->description == NULL) 180 { 181 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno)); 182 return -1; 183 } 184 185 dev = dev->next; 186 } 187 188 return 0; 189 } 190 191 (*alldevs) = NULL; 192 193 if (type == PCAP_SRC_FILE) 194 { 195 size_t stringlen; 196 #ifdef WIN32 197 WIN32_FIND_DATA filedata; 198 HANDLE filehandle; 199 #else 200 struct dirent *filedata; 201 DIR *unixdir; 202 #endif 203 204 if (pcap_parsesrcstr(source, &type, host, port, name, errbuf) == -1) 205 return -1; 206 207 /* Check that the filename is correct */ 208 stringlen = strlen(name); 209 210 /* The directory must end with '\' in Win32 and '/' in UNIX */ 211 #ifdef WIN32 212 #define ENDING_CHAR '\\' 213 #else 214 #define ENDING_CHAR '/' 215 #endif 216 217 if (name[stringlen - 1] != ENDING_CHAR) 218 { 219 name[stringlen] = ENDING_CHAR; 220 name[stringlen + 1] = 0; 221 222 stringlen++; 223 } 224 225 /* Save the path for future reference */ 226 pcap_snprintf(path, sizeof(path), "%s", name); 227 228 #ifdef WIN32 229 /* To perform directory listing, Win32 must have an 'asterisk' as ending char */ 230 if (name[stringlen - 1] != '*') 231 { 232 name[stringlen] = '*'; 233 name[stringlen + 1] = 0; 234 } 235 236 filehandle = FindFirstFile(name, &filedata); 237 238 if (filehandle == INVALID_HANDLE_VALUE) 239 { 240 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error when listing files: does folder '%s' exist?", path); 241 return -1; 242 } 243 244 #else 245 /* opening the folder */ 246 unixdir= opendir(path); 247 248 /* get the first file into it */ 249 filedata= readdir(unixdir); 250 251 if (filedata == NULL) 252 { 253 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error when listing files: does folder '%s' exist?", path); 254 return -1; 255 } 256 #endif 257 258 do 259 { 260 261 #ifdef WIN32 262 pcap_snprintf(filename, sizeof(filename), "%s%s", path, filedata.cFileName); 263 #else 264 pcap_snprintf(filename, sizeof(filename), "%s%s", path, filedata->d_name); 265 #endif 266 267 fp = pcap_open_offline(filename, errbuf); 268 269 if (fp) 270 { 271 /* allocate the main structure */ 272 if (*alldevs == NULL) /* This is in case it is the first file */ 273 { 274 (*alldevs) = (pcap_if_t *)malloc(sizeof(pcap_if_t)); 275 dev = (*alldevs); 276 } 277 else 278 { 279 dev->next = (pcap_if_t *)malloc(sizeof(pcap_if_t)); 280 dev = dev->next; 281 } 282 283 /* check that the malloc() didn't fail */ 284 if (dev == NULL) 285 { 286 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno)); 287 return -1; 288 } 289 290 /* Initialize the structure to 'zero' */ 291 memset(dev, 0, sizeof(pcap_if_t)); 292 293 /* Create the new source identifier */ 294 if (pcap_createsrcstr(tmpstring, PCAP_SRC_FILE, NULL, NULL, filename, errbuf) == -1) 295 return -1; 296 297 stringlen = strlen(tmpstring); 298 299 dev->name = (char *)malloc(stringlen + 1); 300 if (dev->name == NULL) 301 { 302 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno)); 303 return -1; 304 } 305 306 strlcpy(dev->name, tmpstring, stringlen); 307 308 dev->name[stringlen] = 0; 309 310 /* Create the description */ 311 pcap_snprintf(tmpstring, sizeof(tmpstring) - 1, "%s '%s' %s", PCAP_TEXT_SOURCE_FILE, 312 filename, PCAP_TEXT_SOURCE_ON_LOCAL_HOST); 313 314 stringlen = strlen(tmpstring); 315 316 dev->description = (char *)malloc(stringlen + 1); 317 318 if (dev->description == NULL) 319 { 320 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno)); 321 return -1; 322 } 323 324 /* Copy the new device description into the correct memory location */ 325 strlcpy(dev->description, tmpstring, stringlen + 1); 326 327 pcap_close(fp); 328 } 329 } 330 #ifdef WIN32 331 while (FindNextFile(filehandle, &filedata) != 0); 332 #else 333 while ( (filedata= readdir(unixdir)) != NULL); 334 #endif 335 336 337 #ifdef WIN32 338 /* Close the search handle. */ 339 FindClose(filehandle); 340 #endif 341 342 return 0; 343 } 344 345 /* If we come here, it is a remote host */ 346 347 /* Retrieve the needed data for getting adapter list */ 348 if (pcap_parsesrcstr(source, &type, host, port, NULL, errbuf) == -1) 349 return -1; 350 351 /* Warning: this call can be the first one called by the user. */ 352 /* For this reason, we have to initialize the WinSock support. */ 353 if (sock_init(errbuf, PCAP_ERRBUF_SIZE) == -1) 354 return -1; 355 356 /* Check for active mode */ 357 sockctrl = rpcap_remoteact_getsock(host, &active, errbuf); 358 if (sockctrl == INVALID_SOCKET) 359 return -1; 360 361 if (!active) { 362 /* 363 * We're not in active mode; let's try to open a new 364 * control connection. 365 */ 366 addrinfo = NULL; 367 368 memset(&hints, 0, sizeof(struct addrinfo)); 369 hints.ai_family = PF_UNSPEC; 370 hints.ai_socktype = SOCK_STREAM; 371 372 if (port[0] == 0) 373 { 374 /* the user chose not to specify the port */ 375 if (sock_initaddress(host, RPCAP_DEFAULT_NETPORT, &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1) 376 return -1; 377 } 378 else 379 { 380 if (sock_initaddress(host, port, &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1) 381 return -1; 382 } 383 384 if ((sockctrl = sock_open(addrinfo, SOCKOPEN_CLIENT, 0, errbuf, PCAP_ERRBUF_SIZE)) == -1) 385 goto error; 386 387 /* addrinfo is no longer used */ 388 freeaddrinfo(addrinfo); 389 addrinfo = NULL; 390 391 if (rpcap_sendauth(sockctrl, auth, errbuf) == -1) 392 { 393 sock_close(sockctrl, NULL, 0); 394 return -1; 395 } 396 } 397 398 /* RPCAP findalldevs command */ 399 rpcap_createhdr(&header, RPCAP_MSG_FINDALLIF_REQ, 0, 0); 400 401 if (sock_send(sockctrl, (char *)&header, sizeof(struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE) == -1) 402 goto error; 403 404 if (sock_recv(sockctrl, (char *)&header, sizeof(struct rpcap_header), SOCK_RECEIVEALL_YES, errbuf, PCAP_ERRBUF_SIZE) == -1) 405 goto error; 406 407 /* Checks if the message is correct */ 408 retval = rpcap_checkmsg(errbuf, sockctrl, &header, RPCAP_MSG_FINDALLIF_REPLY, RPCAP_MSG_ERROR, 0); 409 410 if (retval != RPCAP_MSG_FINDALLIF_REPLY) /* the message is not the one expected */ 411 { 412 switch (retval) 413 { 414 case -3: /* Unrecoverable network error */ 415 case -2: /* The other endpoint send a message that is not allowed here */ 416 case -1: /* The other endpoint has a version number that is not compatible with our */ 417 break; 418 419 case RPCAP_MSG_ERROR: /* The other endpoint reported an error */ 420 break; 421 422 default: 423 { 424 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Internal error"); 425 break; 426 }; 427 } 428 429 if (!active) 430 sock_close(sockctrl, NULL, 0); 431 432 return -1; 433 } 434 435 /* read the number of interfaces */ 436 nif = ntohs(header.value); 437 438 /* loop until all interfaces have been received */ 439 for (i = 0; i < nif; i++) 440 { 441 struct rpcap_findalldevs_if findalldevs_if; 442 char tmpstring2[PCAP_BUF_SIZE + 1]; /* Needed to convert names and descriptions from 'old' syntax to the 'new' one */ 443 size_t stringlen; 444 445 tmpstring2[PCAP_BUF_SIZE] = 0; 446 447 /* receive the findalldevs structure from remote host */ 448 nread = sock_recv(sockctrl, (char *)&findalldevs_if, 449 sizeof(struct rpcap_findalldevs_if), SOCK_RECEIVEALL_YES, 450 errbuf, PCAP_ERRBUF_SIZE); 451 if (nread == -1) 452 goto error; 453 totread += nread; 454 455 findalldevs_if.namelen = ntohs(findalldevs_if.namelen); 456 findalldevs_if.desclen = ntohs(findalldevs_if.desclen); 457 findalldevs_if.naddr = ntohs(findalldevs_if.naddr); 458 459 /* allocate the main structure */ 460 if (i == 0) 461 { 462 (*alldevs) = (pcap_if_t *)malloc(sizeof(pcap_if_t)); 463 dev = (*alldevs); 464 } 465 else 466 { 467 dev->next = (pcap_if_t *)malloc(sizeof(pcap_if_t)); 468 dev = dev->next; 469 } 470 471 /* check that the malloc() didn't fail */ 472 if (dev == NULL) 473 { 474 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno)); 475 goto error; 476 } 477 478 /* Initialize the structure to 'zero' */ 479 memset(dev, 0, sizeof(pcap_if_t)); 480 481 /* allocate mem for name and description */ 482 if (findalldevs_if.namelen) 483 { 484 485 if (findalldevs_if.namelen >= sizeof(tmpstring)) 486 { 487 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface name too long"); 488 goto error; 489 } 490 491 /* Retrieve adapter name */ 492 nread = sock_recv(sockctrl, tmpstring, 493 findalldevs_if.namelen, SOCK_RECEIVEALL_YES, 494 errbuf, PCAP_ERRBUF_SIZE); 495 if (nread == -1) 496 goto error; 497 totread += nread; 498 499 tmpstring[findalldevs_if.namelen] = 0; 500 501 /* Create the new device identifier */ 502 if (pcap_createsrcstr(tmpstring2, PCAP_SRC_IFREMOTE, host, port, tmpstring, errbuf) == -1) 503 return -1; 504 505 stringlen = strlen(tmpstring2); 506 507 dev->name = (char *)malloc(stringlen + 1); 508 if (dev->name == NULL) 509 { 510 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno)); 511 goto error; 512 } 513 514 /* Copy the new device name into the correct memory location */ 515 strlcpy(dev->name, tmpstring2, stringlen + 1); 516 } 517 518 if (findalldevs_if.desclen) 519 { 520 if (findalldevs_if.desclen >= sizeof(tmpstring)) 521 { 522 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface description too long"); 523 goto error; 524 } 525 526 /* Retrieve adapter description */ 527 nread = sock_recv(sockctrl, tmpstring, 528 findalldevs_if.desclen, SOCK_RECEIVEALL_YES, 529 errbuf, PCAP_ERRBUF_SIZE); 530 if (nread == -1) 531 goto error; 532 totread += nread; 533 534 tmpstring[findalldevs_if.desclen] = 0; 535 536 pcap_snprintf(tmpstring2, sizeof(tmpstring2) - 1, "%s '%s' %s %s", PCAP_TEXT_SOURCE_ADAPTER, 537 tmpstring, PCAP_TEXT_SOURCE_ON_REMOTE_HOST, host); 538 539 stringlen = strlen(tmpstring2); 540 541 dev->description = (char *)malloc(stringlen + 1); 542 543 if (dev->description == NULL) 544 { 545 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno)); 546 goto error; 547 } 548 549 /* Copy the new device description into the correct memory location */ 550 strlcpy(dev->description, tmpstring2, stringlen + 1); 551 } 552 553 dev->flags = ntohl(findalldevs_if.flags); 554 555 naddr = 0; 556 addr = NULL; 557 /* loop until all addresses have been received */ 558 for (j = 0; j < findalldevs_if.naddr; j++) 559 { 560 struct rpcap_findalldevs_ifaddr ifaddr; 561 562 /* Retrieve the interface addresses */ 563 nread = sock_recv(sockctrl, (char *)&ifaddr, 564 sizeof(struct rpcap_findalldevs_ifaddr), 565 SOCK_RECEIVEALL_YES, errbuf, PCAP_ERRBUF_SIZE); 566 if (nread == -1) 567 goto error; 568 totread += nread; 569 570 /* 571 * WARNING libpcap bug: the address listing is 572 * available only for AF_INET. 573 * 574 * XXX - IPv6? 575 */ 576 if (ntohs(ifaddr.addr.ss_family) == AF_INET) 577 { 578 if (addr == NULL) 579 { 580 dev->addresses = (struct pcap_addr *) malloc(sizeof(struct pcap_addr)); 581 addr = dev->addresses; 582 } 583 else 584 { 585 addr->next = (struct pcap_addr *) malloc(sizeof(struct pcap_addr)); 586 addr = addr->next; 587 } 588 naddr++; 589 590 if (addr == NULL) 591 { 592 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno)); 593 goto error; 594 } 595 addr->next = NULL; 596 597 if (rpcap_deseraddr((struct sockaddr_storage *) &ifaddr.addr, 598 (struct sockaddr_storage **) &addr->addr, errbuf) == -1) 599 goto error; 600 if (rpcap_deseraddr((struct sockaddr_storage *) &ifaddr.netmask, 601 (struct sockaddr_storage **) &addr->netmask, errbuf) == -1) 602 goto error; 603 if (rpcap_deseraddr((struct sockaddr_storage *) &ifaddr.broadaddr, 604 (struct sockaddr_storage **) &addr->broadaddr, errbuf) == -1) 605 goto error; 606 if (rpcap_deseraddr((struct sockaddr_storage *) &ifaddr.dstaddr, 607 (struct sockaddr_storage **) &addr->dstaddr, errbuf) == -1) 608 goto error; 609 610 if ((addr->addr == NULL) && (addr->netmask == NULL) && 611 (addr->broadaddr == NULL) && (addr->dstaddr == NULL)) 612 { 613 free(addr); 614 addr = NULL; 615 if (naddr == 1) 616 naddr = 0; /* the first item of the list had NULL addresses */ 617 } 618 } 619 } 620 } 621 622 /* Checks if all the data has been read; if not, discard the data in excess */ 623 if (totread != ntohl(header.plen)) 624 { 625 if (sock_discard(sockctrl, ntohl(header.plen) - totread, errbuf, PCAP_ERRBUF_SIZE) == 1) 626 return -1; 627 } 628 629 /* Control connection has to be closed only in case the remote machine is in passive mode */ 630 if (!active) 631 { 632 /* DO not send RPCAP_CLOSE, since we did not open a pcap_t; no need to free resources */ 633 if (sock_close(sockctrl, errbuf, PCAP_ERRBUF_SIZE)) 634 return -1; 635 } 636 637 /* To avoid inconsistencies in the number of sock_init() */ 638 sock_cleanup(); 639 640 return 0; 641 642 error: 643 /* 644 * In case there has been an error, I don't want to overwrite it with a new one 645 * if the following call fails. I want to return always the original error. 646 * 647 * Take care: this connection can already be closed when we try to close it. 648 * This happens because a previous error in the rpcapd, which requested to 649 * closed the connection. In that case, we already recognized that into the 650 * rpspck_isheaderok() and we already acknowledged the closing. 651 * In that sense, this call is useless here (however it is needed in case 652 * the client generates the error). 653 * 654 * Checks if all the data has been read; if not, discard the data in excess 655 */ 656 if (totread != ntohl(header.plen)) 657 { 658 if (sock_discard(sockctrl, ntohl(header.plen) - totread, NULL, 0) == 1) 659 return -1; 660 } 661 662 /* Control connection has to be closed only in case the remote machine is in passive mode */ 663 if (!active) 664 sock_close(sockctrl, NULL, 0); 665 666 /* To avoid inconsistencies in the number of sock_init() */ 667 sock_cleanup(); 668 669 return -1; 670 } 671 672 int pcap_createsrcstr(char *source, int type, const char *host, const char *port, const char *name, char *errbuf) 673 { 674 switch (type) 675 { 676 case PCAP_SRC_FILE: 677 { 678 strlcpy(source, PCAP_SRC_FILE_STRING, PCAP_BUF_SIZE); 679 if ((name) && (*name)) 680 { 681 strlcat(source, name, PCAP_BUF_SIZE); 682 return 0; 683 } 684 else 685 { 686 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The file name cannot be NULL."); 687 return -1; 688 } 689 } 690 691 case PCAP_SRC_IFREMOTE: 692 { 693 strlcpy(source, PCAP_SRC_IF_STRING, PCAP_BUF_SIZE); 694 if ((host) && (*host)) 695 { 696 if ((strcspn(host, "aAbBcCdDeEfFgGhHjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ")) == strlen(host)) 697 { 698 /* the host name does not contains alphabetic chars. So, it is a numeric address */ 699 /* In this case we have to include it between square brackets */ 700 strlcat(source, "[", PCAP_BUF_SIZE); 701 strlcat(source, host, PCAP_BUF_SIZE); 702 strlcat(source, "]", PCAP_BUF_SIZE); 703 } 704 else 705 strlcat(source, host, PCAP_BUF_SIZE); 706 707 if ((port) && (*port)) 708 { 709 strlcat(source, ":", PCAP_BUF_SIZE); 710 strlcat(source, port, PCAP_BUF_SIZE); 711 } 712 713 strlcat(source, "/", PCAP_BUF_SIZE); 714 } 715 else 716 { 717 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The host name cannot be NULL."); 718 return -1; 719 } 720 721 if ((name) && (*name)) 722 strlcat(source, name, PCAP_BUF_SIZE); 723 724 return 0; 725 } 726 727 case PCAP_SRC_IFLOCAL: 728 { 729 strlcpy(source, PCAP_SRC_IF_STRING, PCAP_BUF_SIZE); 730 731 if ((name) && (*name)) 732 strlcat(source, name, PCAP_BUF_SIZE); 733 734 return 0; 735 } 736 737 default: 738 { 739 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The interface type is not valid."); 740 return -1; 741 } 742 } 743 } 744 745 int pcap_parsesrcstr(const char *source, int *type, char *host, char *port, char *name, char *errbuf) 746 { 747 char *ptr; 748 int ntoken; 749 char tmpname[PCAP_BUF_SIZE]; 750 char tmphost[PCAP_BUF_SIZE]; 751 char tmpport[PCAP_BUF_SIZE]; 752 int tmptype; 753 754 /* Initialization stuff */ 755 tmpname[0] = 0; 756 tmphost[0] = 0; 757 tmpport[0] = 0; 758 759 if (host) 760 *host = 0; 761 if (port) 762 *port = 0; 763 if (name) 764 *name = 0; 765 766 /* Look for a 'rpcap://' identifier */ 767 if ((ptr = strstr(source, PCAP_SRC_IF_STRING)) != NULL) 768 { 769 if (strlen(PCAP_SRC_IF_STRING) == strlen(source)) 770 { 771 /* The source identifier contains only the 'rpcap://' string. */ 772 /* So, this is a local capture. */ 773 *type = PCAP_SRC_IFLOCAL; 774 return 0; 775 } 776 777 ptr += strlen(PCAP_SRC_IF_STRING); 778 779 if (strchr(ptr, '[')) /* This is probably a numeric address */ 780 { 781 ntoken = sscanf(ptr, "[%[1234567890:.]]:%[^/]/%s", tmphost, tmpport, tmpname); 782 783 if (ntoken == 1) /* probably the port is missing */ 784 ntoken = sscanf(ptr, "[%[1234567890:.]]/%s", tmphost, tmpname); 785 786 tmptype = PCAP_SRC_IFREMOTE; 787 } 788 else 789 { 790 ntoken = sscanf(ptr, "%[^/:]:%[^/]/%s", tmphost, tmpport, tmpname); 791 792 if (ntoken == 1) 793 { 794 /* 795 * This can be due to two reasons: 796 * - we want a remote capture, but the network port is missing 797 * - we want to do a local capture 798 * To distinguish between the two, we look for the '/' char 799 */ 800 if (strchr(ptr, '/')) 801 { 802 /* We're on a remote capture */ 803 sscanf(ptr, "%[^/]/%s", tmphost, tmpname); 804 tmptype = PCAP_SRC_IFREMOTE; 805 } 806 else 807 { 808 /* We're on a local capture */ 809 if (*ptr) 810 strlcpy(tmpname, ptr, PCAP_BUF_SIZE); 811 812 /* Clean the host name, since it is a remote capture */ 813 /* NOTE: the host name has been assigned in the previous "ntoken= sscanf(...)" line */ 814 tmphost[0] = 0; 815 816 tmptype = PCAP_SRC_IFLOCAL; 817 } 818 } 819 else 820 tmptype = PCAP_SRC_IFREMOTE; 821 } 822 823 if (host) 824 strlcpy(host, tmphost, PCAP_BUF_SIZE); 825 if (port) 826 strlcpy(port, tmpport, PCAP_BUF_SIZE); 827 if (type) 828 *type = tmptype; 829 830 if (name) 831 { 832 /* 833 * If the user wants the host name, but it cannot be located into the source string, return error 834 * However, if the user is not interested in the interface name (e.g. if we're called by 835 * pcap_findalldevs_ex(), which does not have interface name, do not return error 836 */ 837 if (tmpname[0]) 838 { 839 strlcpy(name, tmpname, PCAP_BUF_SIZE); 840 } 841 else 842 { 843 if (errbuf) 844 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The interface name has not been specified in the source string."); 845 846 return -1; 847 } 848 } 849 850 return 0; 851 } 852 853 /* Look for a 'file://' identifier */ 854 if ((ptr = strstr(source, PCAP_SRC_FILE_STRING)) != NULL) 855 { 856 ptr += strlen(PCAP_SRC_FILE_STRING); 857 if (*ptr) 858 { 859 if (name) 860 strlcpy(name, ptr, PCAP_BUF_SIZE); 861 862 if (type) 863 *type = PCAP_SRC_FILE; 864 865 return 0; 866 } 867 else 868 { 869 if (errbuf) 870 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The file name has not been specified in the source string."); 871 872 return -1; 873 } 874 875 } 876 877 /* Backward compatibility; the user didn't use the 'rpcap://, file://' specifiers */ 878 if ((source) && (*source)) 879 { 880 if (name) 881 strlcpy(name, source, PCAP_BUF_SIZE); 882 883 if (type) 884 *type = PCAP_SRC_IFLOCAL; 885 886 return 0; 887 } 888 else 889 { 890 if (errbuf) 891 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The interface name has not been specified in the source string."); 892 893 return -1; 894 } 895 }; 896 897 pcap_t *pcap_open(const char *source, int snaplen, int flags, int read_timeout, struct pcap_rmtauth *auth, char *errbuf) 898 { 899 char host[PCAP_BUF_SIZE], port[PCAP_BUF_SIZE], name[PCAP_BUF_SIZE]; 900 int type; 901 pcap_t *fp; 902 int result; 903 904 if (strlen(source) > PCAP_BUF_SIZE) 905 { 906 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The source string is too long. Cannot handle it correctly."); 907 return NULL; 908 } 909 910 /* determine the type of the source (file, local, remote) */ 911 if (pcap_parsesrcstr(source, &type, host, port, name, errbuf) == -1) 912 return NULL; 913 914 915 switch (type) 916 { 917 case PCAP_SRC_FILE: 918 fp = pcap_open_offline(name, errbuf); 919 break; 920 921 case PCAP_SRC_IFREMOTE: 922 fp = pcap_create(source, errbuf); 923 if (fp == NULL) 924 { 925 return NULL; 926 } 927 928 /* 929 * Although we already have host, port and iface, we prefer TO PASS only 'pars' to the 930 * pcap_open_remote() so that it has to call the pcap_parsesrcstr() again. 931 * This is less optimized, but much clearer. 932 */ 933 934 result = pcap_opensource_remote(fp, auth); 935 936 if (result != 0) 937 { 938 pcap_close(fp); 939 return NULL; 940 } 941 942 struct pcap_md *md; /* structure used when doing a remote live capture */ 943 md = (struct pcap_md *) ((u_char*)fp->priv + sizeof(struct pcap_win)); 944 945 fp->snapshot = snaplen; 946 fp->opt.timeout = read_timeout; 947 md->rmt_flags = flags; 948 break; 949 950 case PCAP_SRC_IFLOCAL: 951 952 fp = pcap_open_live(name, snaplen, (flags & PCAP_OPENFLAG_PROMISCUOUS), read_timeout, errbuf); 953 954 #ifdef WIN32 955 /* 956 * these flags are supported on Windows only 957 */ 958 if (fp != NULL && fp->adapter != NULL) 959 { 960 /* disable loopback capture if requested */ 961 if (flags & PCAP_OPENFLAG_NOCAPTURE_LOCAL) 962 { 963 if (!PacketSetLoopbackBehavior(fp->adapter, NPF_DISABLE_LOOPBACK)) 964 { 965 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Unable to disable the capture of loopback packets."); 966 pcap_close(fp); 967 return NULL; 968 } 969 } 970 971 /* set mintocopy to zero if requested */ 972 if (flags & PCAP_OPENFLAG_MAX_RESPONSIVENESS) 973 { 974 if (!PacketSetMinToCopy(fp->adapter, 0)) 975 { 976 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Unable to set max responsiveness."); 977 pcap_close(fp); 978 return NULL; 979 } 980 } 981 } 982 #endif /* WIN32 */ 983 984 break; 985 986 default: 987 strlcpy(errbuf, "Source type not supported", PCAP_ERRBUF_SIZE); 988 return NULL; 989 } 990 return fp; 991 } 992 993 struct pcap_samp *pcap_setsampling(pcap_t *p) 994 { 995 struct pcap_md *md; /* structure used when doing a remote live capture */ 996 997 md = (struct pcap_md *) ((u_char*)p->priv + sizeof(struct pcap_win)); 998 return &(md->rmt_samp); 999 } 1000 1001 SOCKET pcap_remoteact_accept(const char *address, const char *port, const char *hostlist, char *connectinghost, struct pcap_rmtauth *auth, char *errbuf) 1002 { 1003 /* socket-related variables */ 1004 struct addrinfo hints; /* temporary struct to keep settings needed to open the new socket */ 1005 struct addrinfo *addrinfo; /* keeps the addrinfo chain; required to open a new socket */ 1006 struct sockaddr_storage from; /* generic sockaddr_storage variable */ 1007 socklen_t fromlen; /* keeps the length of the sockaddr_storage variable */ 1008 SOCKET sockctrl; /* keeps the main socket identifier */ 1009 struct activehosts *temp, *prev; /* temp var needed to scan he host list chain */ 1010 1011 *connectinghost = 0; /* just in case */ 1012 1013 /* Prepare to open a new server socket */ 1014 memset(&hints, 0, sizeof(struct addrinfo)); 1015 /* WARNING Currently it supports only ONE socket family among ipv4 and IPv6 */ 1016 hints.ai_family = AF_INET; /* PF_UNSPEC to have both IPv4 and IPv6 server */ 1017 hints.ai_flags = AI_PASSIVE; /* Ready to a bind() socket */ 1018 hints.ai_socktype = SOCK_STREAM; 1019 1020 /* Warning: this call can be the first one called by the user. */ 1021 /* For this reason, we have to initialize the WinSock support. */ 1022 if (sock_init(errbuf, PCAP_ERRBUF_SIZE) == -1) 1023 return -1; 1024 1025 /* Do the work */ 1026 if ((port == NULL) || (port[0] == 0)) 1027 { 1028 if (sock_initaddress(address, RPCAP_DEFAULT_NETPORT_ACTIVE, &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1) 1029 { 1030 SOCK_ASSERT(errbuf, 1); 1031 return -2; 1032 } 1033 } 1034 else 1035 { 1036 if (sock_initaddress(address, port, &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1) 1037 { 1038 SOCK_ASSERT(errbuf, 1); 1039 return -2; 1040 } 1041 } 1042 1043 1044 if ((sockmain = sock_open(addrinfo, SOCKOPEN_SERVER, 1, errbuf, PCAP_ERRBUF_SIZE)) == -1) 1045 { 1046 SOCK_ASSERT(errbuf, 1); 1047 return -2; 1048 } 1049 1050 /* Connection creation */ 1051 fromlen = sizeof(struct sockaddr_storage); 1052 1053 sockctrl = accept(sockmain, (struct sockaddr *) &from, &fromlen); 1054 1055 /* We're not using sock_close, since we do not want to send a shutdown */ 1056 /* (which is not allowed on a non-connected socket) */ 1057 closesocket(sockmain); 1058 sockmain = 0; 1059 1060 if (sockctrl == -1) 1061 { 1062 sock_geterror("accept(): ", errbuf, PCAP_ERRBUF_SIZE); 1063 return -2; 1064 } 1065 1066 /* Get the numeric for of the name of the connecting host */ 1067 if (getnameinfo((struct sockaddr *) &from, fromlen, connectinghost, RPCAP_HOSTLIST_SIZE, NULL, 0, NI_NUMERICHOST)) 1068 { 1069 sock_geterror("getnameinfo(): ", errbuf, PCAP_ERRBUF_SIZE); 1070 rpcap_senderror(sockctrl, errbuf, PCAP_ERR_REMOTEACCEPT, NULL); 1071 sock_close(sockctrl, NULL, 0); 1072 return -1; 1073 } 1074 1075 /* checks if the connecting host is among the ones allowed */ 1076 if (sock_check_hostlist((char *)hostlist, RPCAP_HOSTLIST_SEP, &from, errbuf, PCAP_ERRBUF_SIZE) < 0) 1077 { 1078 rpcap_senderror(sockctrl, errbuf, PCAP_ERR_REMOTEACCEPT, NULL); 1079 sock_close(sockctrl, NULL, 0); 1080 return -1; 1081 } 1082 1083 /* Send authentication to the remote machine */ 1084 if (rpcap_sendauth(sockctrl, auth, errbuf) == -1) 1085 { 1086 rpcap_senderror(sockctrl, errbuf, PCAP_ERR_REMOTEACCEPT, NULL); 1087 sock_close(sockctrl, NULL, 0); 1088 return -3; 1089 } 1090 1091 /* Checks that this host does not already have a cntrl connection in place */ 1092 1093 /* Initialize pointers */ 1094 temp = activeHosts; 1095 prev = NULL; 1096 1097 while (temp) 1098 { 1099 /* This host already has an active connection in place, so I don't have to update the host list */ 1100 if (sock_cmpaddr(&temp->host, &from) == 0) 1101 return sockctrl; 1102 1103 prev = temp; 1104 temp = temp->next; 1105 } 1106 1107 /* The host does not exist in the list; so I have to update the list */ 1108 if (prev) 1109 { 1110 prev->next = (struct activehosts *) malloc(sizeof(struct activehosts)); 1111 temp = prev->next; 1112 } 1113 else 1114 { 1115 activeHosts = (struct activehosts *) malloc(sizeof(struct activehosts)); 1116 temp = activeHosts; 1117 } 1118 1119 if (temp == NULL) 1120 { 1121 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno)); 1122 rpcap_senderror(sockctrl, errbuf, PCAP_ERR_REMOTEACCEPT, NULL); 1123 sock_close(sockctrl, NULL, 0); 1124 return -1; 1125 } 1126 1127 memcpy(&temp->host, &from, fromlen); 1128 temp->sockctrl = sockctrl; 1129 temp->next = NULL; 1130 1131 return sockctrl; 1132 } 1133 1134 int pcap_remoteact_close(const char *host, char *errbuf) 1135 { 1136 struct activehosts *temp, *prev; /* temp var needed to scan the host list chain */ 1137 struct addrinfo hints, *addrinfo, *ai_next; /* temp var needed to translate between hostname to its address */ 1138 int retval; 1139 1140 temp = activeHosts; 1141 prev = NULL; 1142 1143 /* retrieve the network address corresponding to 'host' */ 1144 addrinfo = NULL; 1145 memset(&hints, 0, sizeof(struct addrinfo)); 1146 hints.ai_family = PF_UNSPEC; 1147 hints.ai_socktype = SOCK_STREAM; 1148 1149 retval = getaddrinfo(host, "0", &hints, &addrinfo); 1150 if (retval != 0) 1151 { 1152 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "getaddrinfo() %s", gai_strerror(retval)); 1153 return -1; 1154 } 1155 1156 while (temp) 1157 { 1158 ai_next = addrinfo; 1159 while (ai_next) 1160 { 1161 if (sock_cmpaddr(&temp->host, (struct sockaddr_storage *) ai_next->ai_addr) == 0) 1162 { 1163 struct rpcap_header header; 1164 1165 /* Close this connection */ 1166 rpcap_createhdr(&header, RPCAP_MSG_CLOSE, 0, 0); 1167 1168 /* I don't check for errors, since I'm going to close everything */ 1169 sock_send(temp->sockctrl, (char *)&header, sizeof(struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE); 1170 1171 if (sock_close(temp->sockctrl, errbuf, PCAP_ERRBUF_SIZE)) 1172 { 1173 /* To avoid inconsistencies in the number of sock_init() */ 1174 sock_cleanup(); 1175 1176 return -1; 1177 } 1178 1179 if (prev) 1180 prev->next = temp->next; 1181 else 1182 activeHosts = temp->next; 1183 1184 freeaddrinfo(addrinfo); 1185 1186 free(temp); 1187 1188 /* To avoid inconsistencies in the number of sock_init() */ 1189 sock_cleanup(); 1190 1191 return 0; 1192 } 1193 1194 ai_next = ai_next->ai_next; 1195 } 1196 prev = temp; 1197 temp = temp->next; 1198 } 1199 1200 if (addrinfo) 1201 freeaddrinfo(addrinfo); 1202 1203 /* To avoid inconsistencies in the number of sock_init() */ 1204 sock_cleanup(); 1205 1206 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The host you want to close the active connection is not known"); 1207 return -1; 1208 } 1209 1210 void pcap_remoteact_cleanup(void) 1211 { 1212 /* Very dirty, but it works */ 1213 if (sockmain) 1214 { 1215 closesocket(sockmain); 1216 1217 /* To avoid inconsistencies in the number of sock_init() */ 1218 sock_cleanup(); 1219 } 1220 1221 } 1222 1223 int pcap_remoteact_list(char *hostlist, char sep, int size, char *errbuf) 1224 { 1225 struct activehosts *temp; /* temp var needed to scan the host list chain */ 1226 size_t len; 1227 char hoststr[RPCAP_HOSTLIST_SIZE + 1]; 1228 1229 temp = activeHosts; 1230 1231 len = 0; 1232 *hostlist = 0; 1233 1234 while (temp) 1235 { 1236 /*int sock_getascii_addrport(const struct sockaddr_storage *sockaddr, char *address, int addrlen, char *port, int portlen, int flags, char *errbuf, int errbuflen) */ 1237 1238 /* Get the numeric form of the name of the connecting host */ 1239 if (sock_getascii_addrport((struct sockaddr_storage *) &temp->host, hoststr, 1240 RPCAP_HOSTLIST_SIZE, NULL, 0, NI_NUMERICHOST, errbuf, PCAP_ERRBUF_SIZE) != -1) 1241 /* if (getnameinfo( (struct sockaddr *) &temp->host, sizeof (struct sockaddr_storage), hoststr, */ 1242 /* RPCAP_HOSTLIST_SIZE, NULL, 0, NI_NUMERICHOST) ) */ 1243 { 1244 /* sock_geterror("getnameinfo(): ", errbuf, PCAP_ERRBUF_SIZE); */ 1245 return -1; 1246 } 1247 1248 len = len + strlen(hoststr) + 1 /* the separator */; 1249 1250 if ((size < 0) || (len >= (size_t)size)) 1251 { 1252 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The string you provided is not able to keep " 1253 "the hostnames for all the active connections"); 1254 return -1; 1255 } 1256 1257 strlcat(hostlist, hoststr, PCAP_ERRBUF_SIZE); 1258 hostlist[len - 1] = sep; 1259 hostlist[len] = 0; 1260 1261 temp = temp->next; 1262 } 1263 1264 return 0; 1265 } 1266