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