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