Home | History | Annotate | Line # | Download | only in dist
      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