tcpprep.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715
  1. /* $Id: tcpprep.c 878 2004-11-07 03:31:04Z aturner $ */
  2. /*
  3. * Copyright (c) 2001-2004 Aaron Turner.
  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 names of the copyright owners nor the names of its
  16. * contributors may be used to endorse or promote products derived from
  17. * this software without specific prior written permission.
  18. *
  19. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
  20. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  21. * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  22. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
  23. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  24. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
  25. * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  26. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
  27. * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  28. * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  29. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. */
  31. /*
  32. * Purpose:
  33. * 1) Remove the performance bottleneck in tcpreplay for choosing an NIC
  34. * 2) Seperate code to make it more manageable
  35. * 3) Add addtional features which require multiple passes of a pcap
  36. *
  37. * Support:
  38. * Right now we support matching source IP based upon on of the following:
  39. * - Regular expression
  40. * - IP address is contained in one of a list of CIDR blocks
  41. * - Auto learning of CIDR block for servers (clients all other)
  42. */
  43. #include <libnet.h>
  44. #include <pcap.h>
  45. #include <stdio.h>
  46. #include <stdlib.h>
  47. #include <string.h>
  48. #include <regex.h>
  49. #include <string.h>
  50. #include <unistd.h>
  51. #include "config.h"
  52. #include "tcpreplay.h"
  53. #include "cache.h"
  54. #include "cidr.h"
  55. #include "tcpprep.h"
  56. #include "tree.h"
  57. #include "list.h"
  58. #include "xX.h"
  59. #include "err.h"
  60. #include "rbtree.h"
  61. #include "utils.h"
  62. #include "services.h"
  63. #include "sll.h"
  64. #include "fakepcap.h"
  65. /*
  66. * global variables
  67. */
  68. #ifdef DEBUG
  69. int debug = 0;
  70. #endif
  71. int info = 0;
  72. char *ourregex = NULL;
  73. char *cidr = NULL;
  74. regex_t *preg = NULL;
  75. CIDR *cidrdata = NULL;
  76. CACHE *cachedata = NULL;
  77. struct data_tree treeroot;
  78. struct options options;
  79. struct bpf_program bpf;
  80. char tcpservices[NUM_PORTS], udpservices[NUM_PORTS];
  81. int mode = 0;
  82. int automode = 0;
  83. double ratio = 0.0;
  84. int max_mask = DEF_MAX_MASK;
  85. int min_mask = DEF_MIN_MASK;
  86. extern char *optarg;
  87. extern int optind, opterr, optopt;
  88. int include_exclude_mode;
  89. CIDR *xX_cidr = NULL;
  90. LIST *xX_list = NULL;
  91. /* required to include utils.c */
  92. int non_ip = 0;
  93. int maxpacket = 0;
  94. /* we get this from libpcap */
  95. extern char pcap_version[];
  96. static void usage();
  97. static void version();
  98. static int check_ip_regex(const unsigned long ip);
  99. static unsigned long process_raw_packets(pcap_t * pcap);
  100. static int check_dst_port(ip_hdr_t *ip_hdr, int len);
  101. static void
  102. version()
  103. {
  104. fprintf(stderr, "tcpprep version: %s", VERSION);
  105. #ifdef DEBUG
  106. fprintf(stderr, " (debug)\n");
  107. #else
  108. fprintf(stderr, "\n");
  109. #endif
  110. fprintf(stderr, "Cache file supported: %s\n", CACHEVERSION);
  111. fprintf(stderr, "Compiled against libnet: %s\n", LIBNET_VERSION);
  112. fprintf(stderr, "Compiled against libpcap: %s\n", pcap_version);
  113. exit(0);
  114. }
  115. /*
  116. * usage
  117. */
  118. static void
  119. usage()
  120. {
  121. fprintf(stderr, "Usage: tcpprep [-a -n <mode> -N <type> | -c <cidr> | -p | -r <regex>] \\\n\t\t-o <out> -i <in> <args>\n");
  122. fprintf(stderr, "-a\t\t\tSplit traffic in Auto Mode\n"
  123. "-c CIDR1,CIDR2,...\tSplit traffic in CIDR Mode\n"
  124. "-C <comment>\t\tEmbed comment in tcpprep cache file\n");
  125. #ifdef DEBUG
  126. fprintf(stderr, "-d <level>\t\tEnable debug output to STDERR\n");
  127. #endif
  128. fprintf(stderr, "-h\t\t\tHelp\n"
  129. "-i <capfile>\t\tInput capture file to process\n"
  130. "-m <minmask>\t\tMinimum mask length in Auto/Router mode\n"
  131. "-M <maxmask>\t\tMaximum mask length in Auto/Router mode\n"
  132. "-n <auto mode>\t\tUse specified algorithm in Auto Mode\n"
  133. "-N client|server\tClassify non-IP traffic as client/server\n"
  134. "-o <outputfile>\t\tOutput cache file name\n"
  135. "-p\t\t\tSplit traffic based on destination port\n"
  136. "-P <file>\t\tPrint comment in tcpprep file\n");
  137. fprintf(stderr, "-r <regex>\t\tSplit traffic in Regex Mode\n"
  138. "-R <ratio>\t\tSpecify a ratio to use in Auto Mode\n"
  139. "-s <file>\t\tSpecify service ports in /etc/services format\n"
  140. "-x <match>\t\tOnly send the packets specified\n"
  141. "-X <match>\t\tSend all the packets except those specified\n"
  142. "-v\t\t\tVerbose\n"
  143. "-V\t\t\tVersion\n");
  144. exit(0);
  145. }
  146. static void
  147. print_comment(char *file)
  148. {
  149. char *cachedata = NULL;
  150. u_int64_t count = 0;
  151. count = read_cache(&cachedata, file);
  152. printf("tcpprep args: %s\n", options.tcpprep_comment);
  153. printf("Cache contains data for %llu packets\n", count);
  154. exit(0);
  155. }
  156. /*
  157. * checks the dst port to see if this is destined for a server port.
  158. * returns 1 for true, 0 for false
  159. */
  160. static int
  161. check_dst_port(ip_hdr_t *ip_hdr, int len)
  162. {
  163. tcp_hdr_t *tcp_hdr = NULL;
  164. udp_hdr_t *udp_hdr = NULL;
  165. dbg(3, "Checking the destination port...");
  166. if (ip_hdr->ip_p == IPPROTO_TCP) {
  167. tcp_hdr = (tcp_hdr_t *)get_layer4(ip_hdr);
  168. /* is a service? */
  169. if (tcpservices[ntohs(tcp_hdr->th_dport)]) {
  170. dbg(1, "TCP packet is destined for a server port: %d", ntohs(tcp_hdr->th_dport));
  171. return 1;
  172. }
  173. /* nope */
  174. dbg(1, "TCP packet is NOT destined for a server port: %d", ntohs(tcp_hdr->th_dport));
  175. return 0;
  176. } else if (ip_hdr->ip_p == IPPROTO_UDP) {
  177. udp_hdr = (udp_hdr_t *)get_layer4(ip_hdr);
  178. /* is a service? */
  179. if (udpservices[ntohs(udp_hdr->uh_dport)]) {
  180. dbg(1, "UDP packet is destined for a server port: %d", ntohs(udp_hdr->uh_dport));
  181. return 1;
  182. }
  183. /* nope */
  184. dbg(1, "UDP packet is NOT destined for a server port: %d", ntohs(udp_hdr->uh_dport));
  185. return 0;
  186. }
  187. /* not a TCP or UDP packet... return as non_ip */
  188. dbg(1, "Packet isn't a UDP or TCP packet... no port to process.");
  189. return non_ip;
  190. }
  191. /*
  192. * checks to see if an ip address matches a regex. Returns 1 for true
  193. * 0 for false
  194. */
  195. static int
  196. check_ip_regex(const unsigned long ip)
  197. {
  198. int eflags = 0;
  199. u_char src_ip[16];
  200. size_t nmatch = 0;
  201. regmatch_t *pmatch = NULL;
  202. memset(src_ip, '\0', 16);
  203. strncat((char *)src_ip, (char *)libnet_addr2name4(ip, LIBNET_DONT_RESOLVE),
  204. 15);
  205. if (regexec(preg, (char *)src_ip, nmatch, pmatch, eflags) == 0) {
  206. return (1);
  207. }
  208. else {
  209. return (0);
  210. }
  211. }
  212. /*
  213. * uses libpcap library to parse the packets and build
  214. * the cache file.
  215. */
  216. static unsigned long
  217. process_raw_packets(pcap_t * pcap)
  218. {
  219. ip_hdr_t *ip_hdr = NULL;
  220. eth_hdr_t *eth_hdr = NULL;
  221. struct sll_header *sll_hdr = NULL;
  222. struct cisco_hdlc_header *hdlc_hdr = NULL;
  223. int l2len = 0;
  224. u_int16_t protocol = 0;
  225. struct pcap_pkthdr pkthdr;
  226. const u_char *pktdata = NULL;
  227. unsigned long packetnum = 0;
  228. int linktype = 0;
  229. #ifdef FORCE_ALIGN
  230. u_char ipbuff[MAXPACKET];
  231. #endif
  232. while ((pktdata = pcap_next(pcap, &pkthdr)) != NULL) {
  233. packetnum++;
  234. eth_hdr = NULL;
  235. sll_hdr = NULL;
  236. ip_hdr = NULL;
  237. hdlc_hdr = NULL;
  238. linktype = pcap_datalink(pcap);
  239. dbg(1, "Linktype is %s (0x%x)",
  240. pcap_datalink_val_to_description(linktype), linktype);
  241. switch (linktype) {
  242. case DLT_EN10MB:
  243. eth_hdr = (eth_hdr_t *) pktdata;
  244. l2len = LIBNET_ETH_H;
  245. protocol = eth_hdr->ether_type;
  246. break;
  247. case DLT_LINUX_SLL:
  248. sll_hdr = (struct sll_header *) pktdata;
  249. l2len = SLL_HDR_LEN;
  250. protocol = sll_hdr->sll_protocol;
  251. break;
  252. case DLT_RAW:
  253. protocol = ETHERTYPE_IP;
  254. l2len = 0;
  255. break;
  256. case DLT_CHDLC:
  257. hdlc_hdr = (struct cisco_hdlc_header *)pktdata;
  258. protocol = hdlc_hdr->protocol;
  259. l2len = CISCO_HDLC_LEN;
  260. break;
  261. default:
  262. errx(1, "WTF? How'd we get here with an invalid DLT type: %s (0x%x)",
  263. pcap_datalink_val_to_description(linktype), linktype);
  264. break;
  265. }
  266. dbg(1, "Packet %d", packetnum);
  267. /* look for include or exclude LIST match */
  268. if (xX_list != NULL) {
  269. if (include_exclude_mode < xXExclude) {
  270. if (!check_list(xX_list, (packetnum))) {
  271. add_cache(&cachedata, 0, 0);
  272. continue;
  273. }
  274. }
  275. else if (check_list(xX_list, (packetnum))) {
  276. add_cache(&cachedata, 0, 0);
  277. continue;
  278. }
  279. }
  280. if (htons(protocol) != ETHERTYPE_IP) {
  281. dbg(2, "Packet isn't IP: %#0.4x", protocol);
  282. if (mode != AUTO_MODE) /* we don't want to cache
  283. * these packets twice */
  284. add_cache(&cachedata, 1, non_ip);
  285. continue;
  286. }
  287. #ifdef FORCE_ALIGN
  288. /*
  289. * copy layer 3 and up to our temp packet buffer
  290. * for now on, we have to edit the packetbuff because
  291. * just before we send the packet, we copy the packetbuff
  292. * back onto the pkt.data + l2len buffer
  293. * we do all this work to prevent byte alignment issues
  294. */
  295. ip_hdr = (ip_hdr_t *) & ipbuff;
  296. memcpy(ip_hdr, (pktdata + l2len), (pkthdr.caplen - l2len));
  297. #else
  298. /*
  299. * on non-strict byte align systems, don't need to memcpy(),
  300. * just point to l2len bytes into the existing buffer
  301. */
  302. ip_hdr = (ip_hdr_t *) (pktdata + l2len);
  303. #endif
  304. /* look for include or exclude CIDR match */
  305. if (xX_cidr != NULL) {
  306. if (!process_xX_by_cidr(include_exclude_mode, xX_cidr, ip_hdr)) {
  307. add_cache(&cachedata, 0, 0);
  308. continue;
  309. }
  310. }
  311. switch (mode) {
  312. case REGEX_MODE:
  313. add_cache(&cachedata, 1, check_ip_regex(ip_hdr->ip_src.s_addr));
  314. break;
  315. case CIDR_MODE:
  316. add_cache(&cachedata, 1,
  317. check_ip_CIDR(cidrdata, ip_hdr->ip_src.s_addr));
  318. break;
  319. case AUTO_MODE:
  320. /* first run through in auto mode: create tree */
  321. add_tree(ip_hdr->ip_src.s_addr, pktdata);
  322. break;
  323. case ROUTER_MODE:
  324. add_cache(&cachedata, 1,
  325. check_ip_CIDR(cidrdata, ip_hdr->ip_src.s_addr));
  326. break;
  327. case BRIDGE_MODE:
  328. /*
  329. * second run through in auto mode: create bridge
  330. * based cache
  331. */
  332. add_cache(&cachedata, 1,
  333. check_ip_tree(UNKNOWN, ip_hdr->ip_src.s_addr));
  334. break;
  335. case SERVER_MODE:
  336. /*
  337. * second run through in auto mode: create bridge
  338. * where unknowns are servers
  339. */
  340. add_cache(&cachedata, 1,
  341. check_ip_tree(SERVER, ip_hdr->ip_src.s_addr));
  342. break;
  343. case CLIENT_MODE:
  344. /*
  345. * second run through in auto mode: create bridge
  346. * where unknowns are clients
  347. */
  348. add_cache(&cachedata, 1,
  349. check_ip_tree(CLIENT, ip_hdr->ip_src.s_addr));
  350. break;
  351. case PORT_MODE:
  352. /*
  353. * process ports based on their destination port
  354. */
  355. add_cache(&cachedata, 1,
  356. check_dst_port(ip_hdr, (pkthdr.caplen - l2len)));
  357. break;
  358. }
  359. }
  360. return packetnum;
  361. }
  362. /*
  363. * main()
  364. */
  365. int
  366. main(int argc, char *argv[])
  367. {
  368. int out_file, ch, regex_error = 0, mask_count = 0;
  369. int regex_flags = REG_EXTENDED|REG_NOSUB;
  370. int i;
  371. char *infilename = NULL;
  372. char *outfilename = NULL;
  373. char ebuf[EBUF_SIZE];
  374. u_int64_t totpackets = 0;
  375. void *xX = NULL;
  376. pcap_t *pcap = NULL;
  377. char errbuf[PCAP_ERRBUF_SIZE];
  378. char myargs[1024];
  379. memset(&options, '\0', sizeof(options));
  380. options.bpf_optimize = BPF_OPTIMIZE;
  381. preg = (regex_t *) malloc(sizeof(regex_t));
  382. if (preg == NULL)
  383. err(1, "malloc");
  384. /* set default server ports (override w/ -s) */
  385. memset(tcpservices, '\0', NUM_PORTS);
  386. memset(udpservices, '\0', NUM_PORTS);
  387. for (i = DEFAULT_LOW_SERVER_PORT; i <= DEFAULT_HIGH_SERVER_PORT; i++) {
  388. tcpservices[i] = 1;
  389. udpservices[i] = 1;
  390. }
  391. #ifdef DEBUG
  392. while ((ch = getopt(argc, argv, "ad:c:C:r:R:o:pP:i:hm:M:n:N:s:x:X:vV")) != -1)
  393. #else
  394. while ((ch = getopt(argc, argv, "ac:C:r:R:o:pP:i:hm:M:n:N:s:x:X:vV")) != -1)
  395. #endif
  396. switch (ch) {
  397. case 'a':
  398. mode = AUTO_MODE;
  399. break;
  400. case 'c':
  401. if (!parse_cidr(&cidrdata, optarg, ",")) {
  402. usage();
  403. }
  404. mode = CIDR_MODE;
  405. break;
  406. case 'C':
  407. /* our comment_len is only 16bit - myargs[] */
  408. if (strlen(optarg) > ((1 << 16) - 1 - sizeof(myargs)))
  409. errx(1, "Comment length %d is longer then max allowed (%d)",
  410. strlen(optarg), (1 << 16) - 1 - sizeof(myargs));
  411. /* copy all of our args to myargs */
  412. memset(myargs, '\0', sizeof(myargs));
  413. for (i = 1; i < argc; i ++) {
  414. /* skip the -C <comment> */
  415. if (strcmp(argv[i], "-C") == 0)
  416. i += 2;
  417. strncat(myargs, argv[i], sizeof(myargs) - 1);
  418. strncat(myargs, " ", sizeof(myargs) - 1);
  419. }
  420. strncat(myargs, "\n", sizeof(myargs) - 1);
  421. dbg(1, "comment args length: %d", strlen(myargs));
  422. /* malloc our buffer to be + 1 strlen so we can null terminate */
  423. if ((options.tcpprep_comment = (char *)malloc(strlen(optarg)
  424. + strlen(myargs) + 1)) == NULL)
  425. errx(1, "Unable to malloc() memory for comment");
  426. memset(options.tcpprep_comment, '\0', strlen(optarg) + 1 + strlen(myargs));
  427. strcpy(options.tcpprep_comment, myargs);
  428. strcat(options.tcpprep_comment, optarg);
  429. dbg(1, "comment length: %d", strlen(optarg));
  430. break;
  431. #ifdef DEBUG
  432. case 'd':
  433. debug = atoi(optarg);
  434. break;
  435. #endif
  436. case 'h':
  437. usage();
  438. break;
  439. case 'i':
  440. infilename = optarg;
  441. break;
  442. case 'm':
  443. min_mask = atoi(optarg);
  444. mask_count++;
  445. break;
  446. case 'M':
  447. max_mask = atoi(optarg);
  448. mask_count++;
  449. break;
  450. case 'n':
  451. if (strcmp(optarg, "bridge") == 0) {
  452. automode = BRIDGE_MODE;
  453. }
  454. else if (strcmp(optarg, "router") == 0) {
  455. automode = ROUTER_MODE;
  456. }
  457. else if (strcmp(optarg, "client") == 0) {
  458. automode = CLIENT_MODE;
  459. }
  460. else if (strcmp(optarg, "server") == 0) {
  461. automode = SERVER_MODE;
  462. }
  463. else {
  464. errx(1, "Invalid auto mode type: %s", optarg);
  465. }
  466. break;
  467. case 'N':
  468. if (strcmp(optarg, "client") == 0) {
  469. non_ip = 0;
  470. }
  471. else if (strcmp(optarg, "server") == 0) {
  472. non_ip = 1;
  473. }
  474. else {
  475. errx(1, "-N must be client or server");
  476. }
  477. break;
  478. case 'o':
  479. outfilename = optarg;
  480. break;
  481. case 'p':
  482. mode = PORT_MODE;
  483. break;
  484. case 'P':
  485. print_comment(optarg);
  486. /* exits */
  487. break;
  488. case 'r':
  489. ourregex = optarg;
  490. mode = REGEX_MODE;
  491. if ((regex_error = regcomp(preg, ourregex, regex_flags))) {
  492. if (regerror(regex_error, preg, ebuf, EBUF_SIZE) != -1) {
  493. errx(1, "Error compiling regex: %s", ebuf);
  494. }
  495. else {
  496. errx(1, "Error compiling regex.");
  497. }
  498. exit(1);
  499. }
  500. break;
  501. case 'R':
  502. ratio = atof(optarg);
  503. break;
  504. case 's':
  505. printf("Parsing services...\n");
  506. parse_services(optarg);
  507. break;
  508. case 'x':
  509. if (include_exclude_mode != 0)
  510. errx(1, "Error: Can only specify -x OR -X");
  511. include_exclude_mode = 'x';
  512. if ((include_exclude_mode =
  513. parse_xX_str(include_exclude_mode, optarg, &xX)) == 0)
  514. errx(1, "Unable to parse -x: %s", optarg);
  515. if (include_exclude_mode & xXPacket) {
  516. xX_list = (LIST *) xX;
  517. }
  518. else if (! (include_exclude_mode & xXBPF)) {
  519. xX_cidr = (CIDR *) xX;
  520. }
  521. break;
  522. case 'X':
  523. if (include_exclude_mode != 0)
  524. errx(1, "Error: Can only specify -x OR -X");
  525. include_exclude_mode = 'X';
  526. if ((include_exclude_mode =
  527. parse_xX_str(include_exclude_mode, optarg, &xX)) == 0)
  528. errx(1, "Unable to parse -X: %s", optarg);
  529. if (include_exclude_mode & xXPacket) {
  530. xX_list = (LIST *) xX;
  531. }
  532. else {
  533. xX_cidr = (CIDR *) xX;
  534. }
  535. break;
  536. case 'v':
  537. info = 1;
  538. break;
  539. case 'V':
  540. version();
  541. break;
  542. default:
  543. usage();
  544. }
  545. /* process args */
  546. if ((mode != CIDR_MODE) && (mode != REGEX_MODE) &&
  547. (mode != AUTO_MODE) && (mode != PORT_MODE))
  548. errx(1, "You need to specifiy a vaild CIDR list or regex, or choose auto or port mode");
  549. if ((mask_count > 0) && (mode != AUTO_MODE))
  550. errx(1,
  551. "You can't specify a min/max mask length unless you use auto mode");
  552. if ((mode == AUTO_MODE) && (automode == 0))
  553. errx(1,
  554. "You must specify -n (bridge|router|client|server) with auto mode (-a)");
  555. if ((ratio != 0.0) && (mode != AUTO_MODE))
  556. errx(1, "Ratio (-R) only works in auto mode (-a).");
  557. if (ratio < 0)
  558. errx(1, "Ratio must be a non-negative number.");
  559. if (info && mode == AUTO_MODE)
  560. fprintf(stderr, "Building auto mode pre-cache data structure...\n");
  561. if (info && mode == CIDR_MODE)
  562. fprintf(stderr, "Building cache file from CIDR list...\n");
  563. if (info && mode == REGEX_MODE)
  564. fprintf(stderr, "Building cache file from regex...\n");
  565. if (infilename == NULL)
  566. errx(1, "You must specify a pcap file to read via -i");
  567. /* set ratio to the default if unspecified */
  568. if (ratio == 0.0)
  569. ratio = DEF_RATIO;
  570. /* open the cache file */
  571. out_file =
  572. open(outfilename, O_WRONLY | O_CREAT | O_TRUNC,
  573. S_IREAD | S_IWRITE | S_IRGRP | S_IWGRP | S_IROTH);
  574. if (out_file == -1)
  575. err(1, "Unable to open cache file %s for writing.", outfilename);
  576. readpcap:
  577. /* open the pcap file */
  578. if ((pcap = pcap_open_offline(infilename, errbuf)) == NULL) {
  579. errx(1, "Error opening file: %s", errbuf);
  580. }
  581. if ((pcap_datalink(pcap) != DLT_EN10MB) &&
  582. (pcap_datalink(pcap) != DLT_LINUX_SLL) &&
  583. (pcap_datalink(pcap) != DLT_RAW) &&
  584. (pcap_datalink(pcap) != DLT_CHDLC)) {
  585. errx(1, "Unsupported pcap DLT type: 0x%x", pcap_datalink(pcap));
  586. }
  587. /* do we apply a bpf filter? */
  588. if (options.bpf_filter != NULL) {
  589. if (pcap_compile(pcap, &bpf, options.bpf_filter,
  590. options.bpf_optimize, 0) != 0) {
  591. errx(1, "Error compiling BPF filter: %s", pcap_geterr(pcap));
  592. }
  593. pcap_setfilter(pcap, &bpf);
  594. }
  595. if ((totpackets = process_raw_packets(pcap)) == 0) {
  596. pcap_close(pcap);
  597. errx(1, "Error: no packets were processed. Filter too limiting?");
  598. }
  599. pcap_close(pcap);
  600. /* we need to process the pcap file twice in HASH/AUTO mode */
  601. if (mode == AUTO_MODE) {
  602. mode = automode;
  603. if (mode == ROUTER_MODE) { /* do we need to convert TREE->CIDR? */
  604. if (info)
  605. fprintf(stderr, "Building network list from pre-cache...\n");
  606. if (!process_tree()) {
  607. errx(1,
  608. "Error: unable to build a valid list of servers. Aborting.");
  609. }
  610. }
  611. else {
  612. /*
  613. * in bridge mode we need to calculate client/sever
  614. * manually since this is done automatically in
  615. * process_tree()
  616. */
  617. tree_calculate(&treeroot);
  618. }
  619. if (info)
  620. fprintf(stderr, "Buliding cache file...\n");
  621. /*
  622. * re-process files, but this time generate
  623. * cache
  624. */
  625. goto readpcap;
  626. }
  627. #ifdef DEBUG
  628. if (debug && (cidrdata != NULL))
  629. print_cidr(cidrdata);
  630. #endif
  631. /* write cache data */
  632. totpackets = write_cache(cachedata, out_file, totpackets);
  633. if (info)
  634. fprintf(stderr, "Done.\nCached %llu packets.\n", totpackets);
  635. /* close cache file */
  636. close(out_file);
  637. return 0;
  638. }