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