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