pcap-new.c 12 KB

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