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 #include <config.h> 35 36 #include "ftmacros.h" 37 #include "diag-control.h" 38 39 /* 40 * sockutils.h may include <crtdbg.h> on Windows, and pcap-int.h will 41 * include portability.h, and portability.h, on Windows, expects that 42 * <crtdbg.h> has already been included, so include sockutils.h first. 43 */ 44 #include "sockutils.h" 45 #include "pcap-int.h" // for the details of the pcap_t structure 46 #include "pcap-rpcap.h" 47 #include "rpcap-protocol.h" 48 #include <errno.h> // for the errno variable 49 #include <stdlib.h> // for malloc(), free(), ... 50 #include <string.h> // for strstr, etc 51 52 #ifndef _WIN32 53 #include <dirent.h> // for readdir 54 #endif 55 56 /* String identifier to be used in the pcap_findalldevs_ex() */ 57 #define PCAP_TEXT_SOURCE_FILE "File" 58 #define PCAP_TEXT_SOURCE_FILE_LEN (sizeof PCAP_TEXT_SOURCE_FILE - 1) 59 /* String identifier to be used in the pcap_findalldevs_ex() */ 60 #define PCAP_TEXT_SOURCE_ADAPTER "Network adapter" 61 #define PCAP_TEXT_SOURCE_ADAPTER_LEN (sizeof "Network adapter" - 1) 62 63 /* String identifier to be used in the pcap_findalldevs_ex() */ 64 #define PCAP_TEXT_SOURCE_ON_LOCAL_HOST "on local host" 65 #define PCAP_TEXT_SOURCE_ON_LOCAL_HOST_LEN (sizeof PCAP_TEXT_SOURCE_ON_LOCAL_HOST + 1) 66 67 /**************************************************** 68 * * 69 * Function bodies * 70 * * 71 ****************************************************/ 72 73 int pcap_findalldevs_ex(const char *source, struct pcap_rmtauth *auth, pcap_if_t **alldevs, char *errbuf) 74 { 75 int type; 76 char name[PCAP_BUF_SIZE], path[PCAP_BUF_SIZE], filename[PCAP_BUF_SIZE]; 77 size_t pathlen; 78 size_t stringlen; 79 pcap_t *fp; 80 char tmpstring[PCAP_BUF_SIZE + 1]; /* Needed to convert names and descriptions from 'old' syntax to the 'new' one */ 81 pcap_if_t *lastdev; /* Last device in the pcap_if_t list */ 82 pcap_if_t *dev; /* Device we're adding to the pcap_if_t list */ 83 84 /* List starts out empty. */ 85 (*alldevs) = NULL; 86 lastdev = NULL; 87 88 if (source == NULL) 89 { 90 snprintf(errbuf, PCAP_ERRBUF_SIZE, 91 "The source string must not be NULL."); 92 return -1; 93 } 94 if (strlen(source) > PCAP_BUF_SIZE) 95 { 96 snprintf(errbuf, PCAP_ERRBUF_SIZE, "The source string is too long. Cannot handle it correctly."); 97 return -1; 98 } 99 100 /* 101 * Determine the type of the source (file, local, remote) 102 * 103 * To list files in a local directory, the source string must specify 104 * the directory name. To list local or remote capture devices, the 105 * source string must not specify a device name. Retrieve the name 106 * component now and validate it for each source type next. 107 */ 108 if (pcap_parsesrcstr(source, &type, NULL, NULL, name, errbuf) == -1) 109 return -1; 110 111 switch (type) 112 { 113 case PCAP_SRC_IFLOCAL: 114 if (strlen(name)) { 115 snprintf(errbuf, PCAP_ERRBUF_SIZE, 116 "To list local capture devices, the source string must not include a device name."); 117 return -1; 118 } 119 120 /* Initialize temporary string */ 121 tmpstring[PCAP_BUF_SIZE] = 0; 122 123 /* The user wants to retrieve adapters from a local host */ 124 if (pcap_findalldevs(alldevs, errbuf) == -1) 125 return -1; 126 127 if (*alldevs == NULL) 128 { 129 snprintf(errbuf, PCAP_ERRBUF_SIZE, 130 "No interfaces found! Make sure libpcap/Npcap is properly installed" 131 " on the local machine."); 132 return -1; 133 } 134 135 /* Scan all the interfaces and modify name and description */ 136 /* This is a trick in order to avoid the re-implementation of the pcap_findalldevs here */ 137 dev = *alldevs; 138 while (dev) 139 { 140 char *localdesc, *desc; 141 142 /* Create the new device identifier */ 143 if (pcap_createsrcstr(tmpstring, PCAP_SRC_IFLOCAL, NULL, NULL, dev->name, errbuf) == -1) 144 return -1; 145 146 /* Delete the old pointer */ 147 free(dev->name); 148 149 /* Make a copy of the new device identifier */ 150 dev->name = strdup(tmpstring); 151 if (dev->name == NULL) 152 { 153 pcapint_fmt_errmsg_for_errno(errbuf, 154 PCAP_ERRBUF_SIZE, errno, 155 "malloc() failed"); 156 pcap_freealldevs(*alldevs); 157 return -1; 158 } 159 160 /* 161 * Create the description. 162 */ 163 if ((dev->description == NULL) || (dev->description[0] == 0)) 164 localdesc = dev->name; 165 else 166 localdesc = dev->description; 167 if (pcapint_asprintf(&desc, "%s '%s' %s", 168 PCAP_TEXT_SOURCE_ADAPTER, localdesc, 169 PCAP_TEXT_SOURCE_ON_LOCAL_HOST) == -1) 170 { 171 pcapint_fmt_errmsg_for_errno(errbuf, 172 PCAP_ERRBUF_SIZE, errno, 173 "malloc() failed"); 174 pcap_freealldevs(*alldevs); 175 return -1; 176 } 177 178 /* Now overwrite the description */ 179 free(dev->description); 180 dev->description = desc; 181 182 dev = dev->next; 183 } 184 185 return 0; 186 187 case PCAP_SRC_FILE: 188 { 189 #ifdef _WIN32 190 WIN32_FIND_DATA filedata; 191 HANDLE filehandle; 192 #else 193 struct dirent *filedata; 194 DIR *unixdir; 195 #endif 196 197 /* Check that the filename is correct */ 198 stringlen = strlen(name); 199 200 if (! stringlen) { 201 snprintf(errbuf, PCAP_ERRBUF_SIZE, 202 "To list local files, the source string must include a directory."); 203 return -1; 204 } 205 206 /* The directory must end with '\' in Win32 and '/' in UNIX */ 207 #ifdef _WIN32 208 #define ENDING_CHAR '\\' 209 #else 210 #define ENDING_CHAR '/' 211 #endif 212 213 if (name[stringlen - 1] != ENDING_CHAR) 214 { 215 name[stringlen] = ENDING_CHAR; 216 name[stringlen + 1] = 0; 217 218 stringlen++; 219 } 220 221 /* Save the path for future reference */ 222 snprintf(path, sizeof(path), "%s", name); 223 pathlen = strlen(path); 224 225 #ifdef _WIN32 226 /* To perform directory listing, Win32 must have an 'asterisk' as ending char */ 227 if (name[stringlen - 1] != '*') 228 { 229 name[stringlen] = '*'; 230 name[stringlen + 1] = 0; 231 } 232 233 filehandle = FindFirstFile(name, &filedata); 234 235 if (filehandle == INVALID_HANDLE_VALUE) 236 { 237 snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error when listing files: does folder '%s' exist?", path); 238 return -1; 239 } 240 241 #else 242 /* opening the folder */ 243 unixdir= opendir(path); 244 if (unixdir == NULL) { 245 DIAG_OFF_FORMAT_TRUNCATION 246 snprintf(errbuf, PCAP_ERRBUF_SIZE, 247 "Error when listing files in '%s': %s", path, pcap_strerror(errno)); 248 DIAG_ON_FORMAT_TRUNCATION 249 return -1; 250 } 251 252 /* get the first file into it */ 253 errno = 0; 254 filedata= readdir(unixdir); 255 256 if (filedata == NULL) 257 { 258 DIAG_OFF_FORMAT_TRUNCATION 259 snprintf(errbuf, PCAP_ERRBUF_SIZE, 260 "Error when listing files in '%s': %s", path, pcap_strerror(errno)); 261 DIAG_ON_FORMAT_TRUNCATION 262 closedir(unixdir); 263 return -1; 264 } 265 #endif 266 267 /* Add all files we find to the list. */ 268 do 269 { 270 #ifdef _WIN32 271 /* Skip the file if the pathname won't fit in the buffer */ 272 if (pathlen + strlen(filedata.cFileName) >= sizeof(filename)) 273 continue; 274 snprintf(filename, sizeof(filename), "%s%s", path, filedata.cFileName); 275 #else 276 if (pathlen + strlen(filedata->d_name) >= sizeof(filename)) 277 continue; 278 DIAG_OFF_FORMAT_TRUNCATION 279 snprintf(filename, sizeof(filename), "%s%s", path, filedata->d_name); 280 DIAG_ON_FORMAT_TRUNCATION 281 #endif 282 283 fp = pcap_open_offline(filename, errbuf); 284 285 if (fp) 286 { 287 /* allocate the main structure */ 288 dev = (pcap_if_t *)malloc(sizeof(pcap_if_t)); 289 if (dev == NULL) 290 { 291 pcapint_fmt_errmsg_for_errno(errbuf, 292 PCAP_ERRBUF_SIZE, errno, 293 "malloc() failed"); 294 pcap_freealldevs(*alldevs); 295 #ifdef _WIN32 296 FindClose(filehandle); 297 #else 298 closedir(unixdir); 299 #endif 300 return -1; 301 } 302 303 /* Initialize the structure to 'zero' */ 304 memset(dev, 0, sizeof(pcap_if_t)); 305 306 /* Append it to the list. */ 307 if (lastdev == NULL) 308 { 309 /* 310 * List is empty, so it's also 311 * the first device. 312 */ 313 *alldevs = dev; 314 } 315 else 316 { 317 /* 318 * Append after the last device. 319 */ 320 lastdev->next = dev; 321 } 322 /* It's now the last device. */ 323 lastdev = dev; 324 325 /* Create the new source identifier */ 326 if (pcap_createsrcstr(tmpstring, PCAP_SRC_FILE, NULL, NULL, filename, errbuf) == -1) 327 { 328 pcap_freealldevs(*alldevs); 329 #ifdef _WIN32 330 FindClose(filehandle); 331 #else 332 closedir(unixdir); 333 #endif 334 return -1; 335 } 336 337 dev->name = strdup(tmpstring); 338 if (dev->name == NULL) 339 { 340 pcapint_fmt_errmsg_for_errno(errbuf, 341 PCAP_ERRBUF_SIZE, errno, 342 "malloc() failed"); 343 pcap_freealldevs(*alldevs); 344 #ifdef _WIN32 345 FindClose(filehandle); 346 #else 347 closedir(unixdir); 348 #endif 349 return -1; 350 } 351 352 /* 353 * Create the description. 354 */ 355 if (pcapint_asprintf(&dev->description, 356 "%s '%s' %s", PCAP_TEXT_SOURCE_FILE, 357 filename, PCAP_TEXT_SOURCE_ON_LOCAL_HOST) == -1) 358 { 359 pcapint_fmt_errmsg_for_errno(errbuf, 360 PCAP_ERRBUF_SIZE, errno, 361 "malloc() failed"); 362 pcap_freealldevs(*alldevs); 363 #ifdef _WIN32 364 FindClose(filehandle); 365 #else 366 closedir(unixdir); 367 #endif 368 return -1; 369 } 370 371 pcap_close(fp); 372 } 373 } 374 #ifdef _WIN32 375 while (FindNextFile(filehandle, &filedata) != 0); 376 #else 377 while ( (filedata= readdir(unixdir)) != NULL); 378 #endif 379 380 381 /* Close the search handle. */ 382 #ifdef _WIN32 383 FindClose(filehandle); 384 #else 385 closedir(unixdir); 386 #endif 387 388 return 0; 389 } 390 391 case PCAP_SRC_IFREMOTE: 392 if (strlen(name)) { 393 snprintf(errbuf, PCAP_ERRBUF_SIZE, 394 "To list remote capture devices, the source string must not include a device name."); 395 return -1; 396 } 397 398 return pcap_findalldevs_ex_remote(source, auth, alldevs, errbuf); 399 400 default: 401 pcapint_strlcpy(errbuf, "Source type not supported", PCAP_ERRBUF_SIZE); 402 return -1; 403 } 404 } 405 406 pcap_t *pcap_open(const char *source, int snaplen, int flags, int read_timeout, struct pcap_rmtauth *auth, char *errbuf) 407 { 408 char name[PCAP_BUF_SIZE]; 409 int type; 410 pcap_t *fp; 411 int status; 412 413 /* 414 * A null device name is equivalent to the "any" device - 415 * which might not be supported on this platform, but 416 * this means that you'll get a "not supported" error 417 * rather than, say, a crash when we try to dereference 418 * the null pointer. 419 */ 420 if (source == NULL) 421 source = "any"; 422 423 if (strlen(source) > PCAP_BUF_SIZE) 424 { 425 snprintf(errbuf, PCAP_ERRBUF_SIZE, "The source string is too long. Cannot handle it correctly."); 426 return NULL; 427 } 428 429 /* 430 * Determine the type of the source (file, local, remote) and, 431 * if it's file or local, the name of the file or capture device. 432 */ 433 if (pcap_parsesrcstr(source, &type, NULL, NULL, name, errbuf) == -1) 434 return NULL; 435 436 switch (type) 437 { 438 case PCAP_SRC_FILE: 439 if (! strlen(name)) { 440 snprintf(errbuf, PCAP_ERRBUF_SIZE, 441 "To open a local file, the source string must include the file path."); 442 return NULL; 443 } 444 return pcap_open_offline(name, errbuf); 445 446 case PCAP_SRC_IFLOCAL: 447 if (! strlen(name)) { 448 snprintf(errbuf, PCAP_ERRBUF_SIZE, 449 "To open a local capture device, the source string must include the device name."); 450 return NULL; 451 } 452 fp = pcap_create(name, errbuf); 453 break; 454 455 case PCAP_SRC_IFREMOTE: 456 if (! strlen(name)) { 457 snprintf(errbuf, PCAP_ERRBUF_SIZE, 458 "To open a remote capture device, the source string must include the device name."); 459 return NULL; 460 } 461 /* 462 * Although we already have host, port and iface, we prefer 463 * to pass only 'source' to pcap_open_rpcap(), so that it 464 * has to call pcap_parsesrcstr() again. 465 * This is less optimized, but much clearer. 466 */ 467 return pcap_open_rpcap(source, snaplen, flags, read_timeout, auth, errbuf); 468 469 default: 470 pcapint_strlcpy(errbuf, "Source type not supported", PCAP_ERRBUF_SIZE); 471 return NULL; 472 } 473 474 if (fp == NULL) 475 return (NULL); 476 status = pcap_set_snaplen(fp, snaplen); 477 if (status < 0) 478 goto fail; 479 if (flags & PCAP_OPENFLAG_PROMISCUOUS) 480 { 481 status = pcap_set_promisc(fp, 1); 482 if (status < 0) 483 goto fail; 484 } 485 if (flags & PCAP_OPENFLAG_MAX_RESPONSIVENESS) 486 { 487 status = pcap_set_immediate_mode(fp, 1); 488 if (status < 0) 489 goto fail; 490 } 491 #ifdef _WIN32 492 /* 493 * This flag is supported on Windows only. 494 * XXX - is there a way to support it with 495 * the capture mechanisms on UN*X? It's not 496 * exactly a "set direction" operation; I 497 * think it means "do not capture packets 498 * injected with pcap_sendpacket() or 499 * pcap_inject()". 500 */ 501 /* disable loopback capture if requested */ 502 if (flags & PCAP_OPENFLAG_NOCAPTURE_LOCAL) 503 fp->opt.nocapture_local = 1; 504 #endif /* _WIN32 */ 505 status = pcap_set_timeout(fp, read_timeout); 506 if (status < 0) 507 goto fail; 508 status = pcap_activate(fp); 509 if (status < 0) 510 goto fail; 511 return fp; 512 513 fail: 514 DIAG_OFF_FORMAT_TRUNCATION 515 if (status == PCAP_ERROR) 516 snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", 517 name, fp->errbuf); 518 else if (status == PCAP_ERROR_NO_SUCH_DEVICE || 519 status == PCAP_ERROR_PERM_DENIED || 520 status == PCAP_ERROR_PROMISC_PERM_DENIED) 521 snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s (%s)", 522 name, pcap_statustostr(status), fp->errbuf); 523 else 524 snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", 525 name, pcap_statustostr(status)); 526 DIAG_ON_FORMAT_TRUNCATION 527 pcap_close(fp); 528 return NULL; 529 } 530 531 struct pcap_samp *pcap_setsampling(pcap_t *p) 532 { 533 return &p->rmt_samp; 534 } 535