tcpprep.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782
  1. /* $Id: tcpprep.c 2302 2009-05-06 18:41:29Z aturner $ */
  2. /*
  3. * Copyright (c) 2001-2007 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 "config.h"
  44. #include "defines.h"
  45. #include "common.h"
  46. #include <stdio.h>
  47. #include <stdlib.h>
  48. #include <string.h>
  49. #include <regex.h>
  50. #include <string.h>
  51. #include <unistd.h>
  52. #include <errno.h>
  53. #include "tcpprep.h"
  54. #include "tcpedit/tcpedit.h"
  55. #include "tcpprep_opts.h"
  56. #include "lib/tree.h"
  57. #include "tree.h"
  58. #include "lib/sll.h"
  59. #include "lib/strlcpy.h"
  60. /*
  61. * global variables
  62. */
  63. #ifdef DEBUG
  64. int debug = 0;
  65. #endif
  66. #ifdef ENABLE_VERBOSE
  67. tcpdump_t tcpdump;
  68. #endif
  69. tcpprep_opt_t options;
  70. int info = 0;
  71. char *ourregex = NULL;
  72. char *cidr = NULL;
  73. tcpr_data_tree_t treeroot;
  74. static void init(void);
  75. static void post_args(int, char *[]);
  76. static void print_comment(const char *);
  77. static void print_info(const char *);
  78. static void print_stats(const char *);
  79. static int check_ipv4_regex(const unsigned long ip);
  80. static int check_ipv6_regex(const struct tcpr_in6_addr *addr);
  81. static COUNTER process_raw_packets(pcap_t * pcap);
  82. static int check_dst_port(ipv4_hdr_t *ip_hdr, ipv6_hdr_t *ip6_hdr, int len);
  83. /*
  84. * main()
  85. */
  86. int
  87. main(int argc, char *argv[])
  88. {
  89. int out_file;
  90. COUNTER totpackets = 0;
  91. char errbuf[PCAP_ERRBUF_SIZE];
  92. int optct = 0;
  93. init(); /* init our globals */
  94. optct = optionProcess(&tcpprepOptions, argc, argv);
  95. post_args(argc, argv);
  96. argc -= optct;
  97. argv += optct;
  98. /* open the cache file */
  99. if ((out_file = open(OPT_ARG(CACHEFILE), O_WRONLY | O_CREAT | O_TRUNC,
  100. S_IREAD | S_IWRITE | S_IRGRP | S_IWGRP | S_IROTH)) == -1)
  101. errx(-1, "Unable to open cache file %s for writing: %s",
  102. OPT_ARG(CACHEFILE), strerror(errno));
  103. readpcap:
  104. /* open the pcap file */
  105. if ((options.pcap = pcap_open_offline(OPT_ARG(PCAP), errbuf)) == NULL)
  106. errx(-1, "Error opening file: %s", errbuf);
  107. /* make sure we support the DLT type */
  108. switch(pcap_datalink(options.pcap)) {
  109. case DLT_EN10MB:
  110. case DLT_LINUX_SLL:
  111. case DLT_RAW:
  112. case DLT_C_HDLC:
  113. break; /* do nothing because all is good */
  114. default:
  115. errx(-1, "Unsupported pcap DLT type: 0x%x", pcap_datalink(options.pcap));
  116. }
  117. /* Can only split based on MAC address for ethernet */
  118. if ((pcap_datalink(options.pcap) != DLT_EN10MB) &&
  119. (options.mode == MAC_MODE)) {
  120. err(-1, "MAC mode splitting is only supported by DLT_EN10MB packet captures.");
  121. }
  122. #ifdef ENABLE_VERBOSE
  123. if (HAVE_OPT(VERBOSE)) {
  124. tcpdump_open(&tcpdump, options.pcap);
  125. }
  126. #endif
  127. /* do we apply a bpf filter? */
  128. if (options.bpf.filter != NULL) {
  129. if (pcap_compile(options.pcap, &options.bpf.program, options.bpf.filter,
  130. options.bpf.optimize, 0) != 0) {
  131. errx(-1, "Error compiling BPF filter: %s", pcap_geterr(options.pcap));
  132. }
  133. pcap_setfilter(options.pcap, &options.bpf.program);
  134. }
  135. if ((totpackets = process_raw_packets(options.pcap)) == 0) {
  136. pcap_close(options.pcap);
  137. err(-1, "No packets were processed. Filter too limiting?");
  138. }
  139. pcap_close(options.pcap);
  140. #ifdef ENABLE_VERBOSE
  141. tcpdump_close(&tcpdump);
  142. #endif
  143. /* we need to process the pcap file twice in HASH/AUTO mode */
  144. if (options.mode == AUTO_MODE) {
  145. options.mode = options.automode;
  146. if (options.mode == ROUTER_MODE) { /* do we need to convert TREE->CIDR? */
  147. if (info)
  148. notice("Building network list from pre-cache...\n");
  149. if (!process_tree()) {
  150. err(-1, "Error: unable to build a valid list of servers. Aborting.");
  151. }
  152. }
  153. else {
  154. /*
  155. * in bridge mode we need to calculate client/sever
  156. * manually since this is done automatically in
  157. * process_tree()
  158. */
  159. tree_calculate(&treeroot);
  160. }
  161. if (info)
  162. notice("Buliding cache file...\n");
  163. /*
  164. * re-process files, but this time generate
  165. * cache
  166. */
  167. goto readpcap;
  168. }
  169. #ifdef DEBUG
  170. if (debug && (options.cidrdata != NULL))
  171. print_cidr(options.cidrdata);
  172. #endif
  173. /* write cache data */
  174. totpackets = write_cache(options.cachedata, out_file, totpackets,
  175. options.comment);
  176. if (info)
  177. notice("Done.\nCached " COUNTER_SPEC " packets.\n", totpackets);
  178. /* close cache file */
  179. close(out_file);
  180. return 0;
  181. }
  182. /**
  183. * checks the dst port to see if this is destined for a server port.
  184. * returns 1 for true, 0 for false
  185. */
  186. static int
  187. check_dst_port(ipv4_hdr_t *ip_hdr, ipv6_hdr_t *ip6_hdr, int len)
  188. {
  189. tcp_hdr_t *tcp_hdr = NULL;
  190. udp_hdr_t *udp_hdr = NULL;
  191. u_char proto;
  192. u_char *l4;
  193. if (ip_hdr) {
  194. if (len < ((ip_hdr->ip_hl * 4) + 4))
  195. return 0; /* not enough data in the packet to know */
  196. proto = ip_hdr->ip_p;
  197. l4 = get_layer4_v4(ip_hdr);
  198. } else if (ip6_hdr) {
  199. if (len < (TCPR_IPV6_H + 4))
  200. return 0; /* not enough data in the packet to know */
  201. proto = get_ipv6_l4proto(ip6_hdr);
  202. dbgx(3, "Our layer4 proto is 0x%hhu", proto);
  203. l4 = get_layer4_v6(ip6_hdr);
  204. dbgx(3, "Found proto %u at offset %p. base %p (%u)", proto, (void *)l4, (void *)ip6_hdr, (l4 - (u_char *)ip6_hdr));
  205. } else {
  206. assert(0);
  207. }
  208. dbg(3, "Checking the destination port...");
  209. if (proto == IPPROTO_TCP) {
  210. tcp_hdr = (tcp_hdr_t *)l4;
  211. /* is a service? */
  212. if (options.services.tcp[ntohs(tcp_hdr->th_dport)]) {
  213. dbgx(1, "TCP packet is destined for a server port: %d", ntohs(tcp_hdr->th_dport));
  214. return 1;
  215. }
  216. /* nope */
  217. dbgx(1, "TCP packet is NOT destined for a server port: %d", ntohs(tcp_hdr->th_dport));
  218. return 0;
  219. } else if (proto == IPPROTO_UDP) {
  220. udp_hdr = (udp_hdr_t *)l4;
  221. /* is a service? */
  222. if (options.services.udp[ntohs(udp_hdr->uh_dport)]) {
  223. dbgx(1, "UDP packet is destined for a server port: %d", ntohs(udp_hdr->uh_dport));
  224. return 1;
  225. }
  226. /* nope */
  227. dbgx(1, "UDP packet is NOT destined for a server port: %d", ntohs(udp_hdr->uh_dport));
  228. return 0;
  229. }
  230. /* not a TCP or UDP packet... return as non_ip */
  231. dbg(1, "Packet isn't a UDP or TCP packet... no port to process.");
  232. return options.nonip;
  233. }
  234. /**
  235. * checks to see if an ip address matches a regex. Returns 1 for true
  236. * 0 for false
  237. */
  238. static int
  239. check_ipv4_regex(const unsigned long ip)
  240. {
  241. int eflags = 0;
  242. u_char src_ip[16];
  243. size_t nmatch = 0;
  244. regmatch_t *pmatch = NULL;
  245. memset(src_ip, '\0', 16);
  246. strlcpy((char *)src_ip, (char *)get_addr2name4(ip, RESOLVE),
  247. sizeof(src_ip));
  248. if (regexec(&options.preg, (char *)src_ip, nmatch, pmatch, eflags) == 0) {
  249. return 1;
  250. } else {
  251. return 0;
  252. }
  253. }
  254. static int
  255. check_ipv6_regex(const struct tcpr_in6_addr *addr)
  256. {
  257. int eflags = 0;
  258. u_char src_ip[INET6_ADDRSTRLEN];
  259. size_t nmatch = 0;
  260. regmatch_t *pmatch = NULL;
  261. memset(src_ip, '\0', 16);
  262. strlcpy((char *)src_ip, (char *)get_addr2name6(addr, RESOLVE), sizeof(src_ip));
  263. if (regexec(&options.preg, (char *)src_ip, nmatch, pmatch, eflags) == 0) {
  264. return 1;
  265. } else {
  266. return 0;
  267. }
  268. }
  269. /**
  270. * uses libpcap library to parse the packets and build
  271. * the cache file.
  272. */
  273. static COUNTER
  274. process_raw_packets(pcap_t * pcap)
  275. {
  276. ipv4_hdr_t *ip_hdr = NULL;
  277. ipv6_hdr_t *ip6_hdr = NULL;
  278. eth_hdr_t *eth_hdr = NULL;
  279. struct pcap_pkthdr pkthdr;
  280. const u_char *pktdata = NULL;
  281. COUNTER packetnum = 0;
  282. int l2len, cache_result = 0;
  283. u_char ipbuff[MAXPACKET], *buffptr;
  284. tcpr_dir_t direction;
  285. #ifdef ENABLE_VERBOSE
  286. struct pollfd poller[1];
  287. poller[0].fd = tcpdump.outfd;
  288. poller[0].events = POLLIN;
  289. poller[0].revents = 0;
  290. #endif
  291. assert(pcap);
  292. while ((pktdata = pcap_next(pcap, &pkthdr)) != NULL) {
  293. packetnum++;
  294. dbgx(1, "Packet " COUNTER_SPEC, packetnum);
  295. /* look for include or exclude LIST match */
  296. if (options.xX.list != NULL) {
  297. if (options.xX.mode < xXExclude) {
  298. if (!check_list(options.xX.list, packetnum)) {
  299. add_cache(&(options.cachedata), DONT_SEND, 0);
  300. continue;
  301. }
  302. }
  303. else if (check_list(options.xX.list, packetnum)) {
  304. add_cache(&(options.cachedata), DONT_SEND, 0);
  305. continue;
  306. }
  307. }
  308. /*
  309. * If the packet doesn't include an IPv4 header we should just treat
  310. * it as a non-IP packet, UNLESS we're in MAC mode, in which case
  311. * we should let the MAC matcher below handle it
  312. */
  313. eth_hdr = (eth_hdr_t *)pktdata;
  314. if (options.mode != MAC_MODE) {
  315. dbg(3, "Looking for IPv4/v6 header in non-MAC mode");
  316. /* get the IP header (if any) */
  317. buffptr = ipbuff;
  318. /* first look for IPv4 */
  319. if ((ip_hdr = (ipv4_hdr_t *)get_ipv4(pktdata, pkthdr.caplen,
  320. pcap_datalink(pcap), &buffptr))) {
  321. dbg(2, "Packet is IPv4");
  322. }
  323. /* then look for IPv6 */
  324. else if ((ip6_hdr = (ipv6_hdr_t *)get_ipv6(pktdata, pkthdr.caplen,
  325. pcap_datalink(pcap), &buffptr))) {
  326. dbg(2, "Packet is IPv6");
  327. }
  328. /* we're something else... */
  329. else {
  330. dbg(2, "Packet isn't IPv4/v6");
  331. /* we don't want to cache these packets twice */
  332. if (options.mode != AUTO_MODE) {
  333. dbg(3, "Adding to cache using options for Non-IP packets");
  334. add_cache(&options.cachedata, SEND, options.nonip);
  335. }
  336. /* go to next packet */
  337. continue;
  338. }
  339. l2len = get_l2len(pktdata, pkthdr.caplen, pcap_datalink(pcap));
  340. /* look for include or exclude CIDR match */
  341. if (options.xX.cidr != NULL) {
  342. if (ip_hdr) {
  343. if (!process_xX_by_cidr_ipv4(options.xX.mode, options.xX.cidr, ip_hdr)) {
  344. add_cache(&options.cachedata, DONT_SEND, 0);
  345. continue;
  346. }
  347. } else if (ip6_hdr) {
  348. if (!process_xX_by_cidr_ipv6(options.xX.mode, options.xX.cidr, ip6_hdr)) {
  349. add_cache(&options.cachedata, DONT_SEND, 0);
  350. continue;
  351. }
  352. }
  353. }
  354. }
  355. switch (options.mode) {
  356. case REGEX_MODE:
  357. dbg(2, "processing regex mode...");
  358. if (ip_hdr) {
  359. direction = check_ipv4_regex(ip_hdr->ip_src.s_addr);
  360. } else if (ip6_hdr) {
  361. direction = check_ipv6_regex(&ip6_hdr->ip_src);
  362. }
  363. /* reverse direction? */
  364. if (HAVE_OPT(REVERSE) && (direction == TCPR_DIR_C2S || direction == TCPR_DIR_S2C))
  365. direction = direction == TCPR_DIR_C2S ? TCPR_DIR_S2C : TCPR_DIR_C2S;
  366. cache_result = add_cache(&options.cachedata, SEND, direction);
  367. break;
  368. case CIDR_MODE:
  369. dbg(2, "processing cidr mode...");
  370. if (ip_hdr) {
  371. direction = check_ip_cidr(options.cidrdata, ip_hdr->ip_src.s_addr) ? TCPR_DIR_C2S : TCPR_DIR_S2C;
  372. } else if (ip6_hdr) {
  373. direction = check_ip6_cidr(options.cidrdata, &ip6_hdr->ip_src) ? TCPR_DIR_C2S : TCPR_DIR_S2C;
  374. }
  375. /* reverse direction? */
  376. if (HAVE_OPT(REVERSE) && (direction == TCPR_DIR_C2S || direction == TCPR_DIR_S2C))
  377. direction = direction == TCPR_DIR_C2S ? TCPR_DIR_S2C : TCPR_DIR_C2S;
  378. cache_result = add_cache(&options.cachedata, SEND, direction);
  379. break;
  380. case MAC_MODE:
  381. dbg(2, "processing mac mode...");
  382. direction = macinstring(options.maclist, (u_char *)eth_hdr->ether_shost);
  383. /* reverse direction? */
  384. if (HAVE_OPT(REVERSE) && (direction == TCPR_DIR_C2S || direction == TCPR_DIR_S2C))
  385. direction = direction == TCPR_DIR_C2S ? TCPR_DIR_S2C : TCPR_DIR_C2S;
  386. cache_result = add_cache(&options.cachedata, SEND, direction);
  387. break;
  388. case AUTO_MODE:
  389. dbg(2, "processing first pass of auto mode...");
  390. /* first run through in auto mode: create tree */
  391. if (options.automode != FIRST_MODE) {
  392. if (ip_hdr) {
  393. add_tree_ipv4(ip_hdr->ip_src.s_addr, pktdata);
  394. } else if (ip6_hdr) {
  395. add_tree_ipv6(&ip6_hdr->ip_src, pktdata);
  396. }
  397. } else {
  398. if (ip_hdr) {
  399. add_tree_first_ipv4(pktdata);
  400. } else if (ip6_hdr) {
  401. add_tree_first_ipv6(pktdata);
  402. }
  403. }
  404. break;
  405. case ROUTER_MODE:
  406. /*
  407. * second run through in auto mode: create route
  408. * based cache
  409. */
  410. dbg(2, "processing second pass of auto: router mode...");
  411. if (ip_hdr) {
  412. cache_result = add_cache(&options.cachedata, SEND,
  413. check_ip_tree(options.nonip, ip_hdr->ip_src.s_addr));
  414. } else {
  415. cache_result = add_cache(&options.cachedata, SEND,
  416. check_ip6_tree(options.nonip, &ip6_hdr->ip_src));
  417. }
  418. break;
  419. case BRIDGE_MODE:
  420. /*
  421. * second run through in auto mode: create bridge
  422. * based cache
  423. */
  424. dbg(2, "processing second pass of auto: bridge mode...");
  425. if (ip_hdr) {
  426. cache_result = add_cache(&options.cachedata, SEND,
  427. check_ip_tree(DIR_UNKNOWN, ip_hdr->ip_src.s_addr));
  428. } else {
  429. cache_result = add_cache(&options.cachedata, SEND,
  430. check_ip6_tree(DIR_UNKNOWN, &ip6_hdr->ip_src));
  431. }
  432. break;
  433. case SERVER_MODE:
  434. /*
  435. * second run through in auto mode: create bridge
  436. * where unknowns are servers
  437. */
  438. dbg(2, "processing second pass of auto: server mode...");
  439. if (ip_hdr) {
  440. cache_result = add_cache(&options.cachedata, SEND,
  441. check_ip_tree(DIR_SERVER, ip_hdr->ip_src.s_addr));
  442. } else {
  443. cache_result = add_cache(&options.cachedata, SEND,
  444. check_ip6_tree(DIR_SERVER, &ip6_hdr->ip_src));
  445. }
  446. break;
  447. case CLIENT_MODE:
  448. /*
  449. * second run through in auto mode: create bridge
  450. * where unknowns are clients
  451. */
  452. dbg(2, "processing second pass of auto: client mode...");
  453. if (ip_hdr) {
  454. cache_result = add_cache(&options.cachedata, SEND,
  455. check_ip_tree(DIR_CLIENT, ip_hdr->ip_src.s_addr));
  456. } else {
  457. cache_result = add_cache(&options.cachedata, SEND,
  458. check_ip6_tree(DIR_CLIENT, &ip6_hdr->ip_src));
  459. }
  460. break;
  461. case PORT_MODE:
  462. /*
  463. * process ports based on their destination port
  464. */
  465. dbg(2, "processing port mode...");
  466. cache_result = add_cache(&options.cachedata, SEND,
  467. check_dst_port(ip_hdr, ip6_hdr, (pkthdr.caplen - l2len)));
  468. break;
  469. case FIRST_MODE:
  470. /*
  471. * First packet mode, looks at each host and picks clients
  472. * by the ones which send the first packet in a session
  473. */
  474. dbg(2, "processing second pass of auto: first packet mode...");
  475. if (ip_hdr) {
  476. cache_result = add_cache(&options.cachedata, SEND,
  477. check_ip_tree(DIR_UNKNOWN, ip_hdr->ip_src.s_addr));
  478. } else {
  479. cache_result = add_cache(&options.cachedata, SEND,
  480. check_ip6_tree(DIR_UNKNOWN, &ip6_hdr->ip_src));
  481. }
  482. break;
  483. default:
  484. errx(-1, "Whops! What mode are we in anyways? %d", options.mode);
  485. }
  486. #ifdef ENABLE_VERBOSE
  487. if (options.verbose)
  488. tcpdump_print(&tcpdump, &pkthdr, pktdata);
  489. #endif
  490. }
  491. return packetnum;
  492. }
  493. /**
  494. * init our options
  495. */
  496. void
  497. init(void)
  498. {
  499. int i;
  500. memset(&options, '\0', sizeof(options));
  501. options.bpf.optimize = BPF_OPTIMIZE;
  502. for (i = DEFAULT_LOW_SERVER_PORT; i <= DEFAULT_HIGH_SERVER_PORT; i++) {
  503. options.services.tcp[i] = 1;
  504. options.services.udp[i] = 1;
  505. }
  506. }
  507. /**
  508. * post process args
  509. */
  510. static void
  511. post_args(int argc, char *argv[])
  512. {
  513. char myargs[MYARGS_LEN];
  514. int i, bufsize;
  515. char *tempstr;
  516. memset(myargs, 0, MYARGS_LEN);
  517. /* print_comment and print_info don't return */
  518. if (HAVE_OPT(PRINT_COMMENT))
  519. print_comment(OPT_ARG(PRINT_COMMENT));
  520. if (HAVE_OPT(PRINT_INFO))
  521. print_info(OPT_ARG(PRINT_INFO));
  522. if (HAVE_OPT(PRINT_STATS))
  523. print_stats(OPT_ARG(PRINT_STATS));
  524. if (! HAVE_OPT(CACHEFILE) && ! HAVE_OPT(PCAP))
  525. err(-1, "Must specify an output cachefile (-o) and input pcap (-i)");
  526. if (! options.mode)
  527. err(-1, "Must specify a processing mode: -a, -c, -r, -p");
  528. #ifdef DEBUG
  529. if (HAVE_OPT(DBUG))
  530. debug = OPT_VALUE_DBUG;
  531. #endif
  532. #ifdef ENABLE_VERBOSE
  533. if (HAVE_OPT(VERBOSE)) {
  534. options.verbose = 1;
  535. }
  536. if (HAVE_OPT(DECODE))
  537. tcpdump.args = safe_strdup(OPT_ARG(DECODE));
  538. /*
  539. * put the open after decode options so they are passed to tcpdump
  540. */
  541. #endif
  542. /*
  543. * if we are to include the cli args, then prep it for the
  544. * cache file header
  545. */
  546. if (! options.nocomment) {
  547. /* copy all of our args to myargs */
  548. for (i = 1; i < argc; i ++) {
  549. /* skip the -C <comment> */
  550. if (strcmp(argv[i], "-C") == 0) {
  551. i += 2;
  552. continue;
  553. }
  554. strlcat(myargs, argv[i], MYARGS_LEN);
  555. strlcat(myargs, " ", MYARGS_LEN);
  556. }
  557. /* remove trailing space */
  558. myargs[strlen(myargs) - 1] = 0;
  559. dbgx(1, "Comment args length: %zu", strlen(myargs));
  560. }
  561. /* setup or options.comment buffer so that that we get args\ncomment */
  562. if (options.comment != NULL) {
  563. strlcat(myargs, "\n", MYARGS_LEN);
  564. bufsize = strlen(options.comment) + strlen(myargs) + 1;
  565. options.comment = (char *)safe_realloc(options.comment,
  566. bufsize);
  567. tempstr = strdup(options.comment);
  568. strlcpy(options.comment, myargs, bufsize);
  569. strlcat(options.comment, tempstr, bufsize);
  570. } else {
  571. bufsize = strlen(myargs) + 1;
  572. options.comment = (char *)safe_malloc(bufsize);
  573. strlcpy(options.comment, myargs, bufsize);
  574. }
  575. dbgx(1, "Final comment length: %zu", strlen(options.comment));
  576. /* copy over our min/max mask */
  577. options.min_mask = OPT_VALUE_MINMASK;
  578. options.max_mask = OPT_VALUE_MAXMASK;
  579. if (! options.min_mask > options.max_mask)
  580. errx(-1, "Min network mask len (%d) must be less then max network mask len (%d)",
  581. options.min_mask, options.max_mask);
  582. options.ratio = atof(OPT_ARG(RATIO));
  583. if (options.ratio < 0)
  584. err(-1, "Ratio must be a non-negative number.");
  585. }
  586. /**
  587. * print the tcpprep cache file comment
  588. */
  589. static void
  590. print_comment(const char *file)
  591. {
  592. char *cachedata = NULL;
  593. char *comment = NULL;
  594. COUNTER count = 0;
  595. count = read_cache(&cachedata, file, &comment);
  596. printf("tcpprep args: %s\n", comment);
  597. printf("Cache contains data for " COUNTER_SPEC " packets\n", count);
  598. exit(0);
  599. }
  600. /**
  601. * prints out the cache file details
  602. */
  603. static void
  604. print_info(const char *file)
  605. {
  606. char *cachedata = NULL;
  607. char *comment = NULL;
  608. COUNTER count = 0, i;
  609. count = read_cache(&cachedata, file, &comment);
  610. for (i = 1; i <= count; i ++) {
  611. switch (check_cache(cachedata, i)) {
  612. case TCPR_DIR_C2S:
  613. printf("Packet " COUNTER_SPEC " -> Primary\n", i);
  614. break;
  615. case TCPR_DIR_S2C:
  616. printf("Packet " COUNTER_SPEC " -> Secondary\n", i);
  617. break;
  618. case TCPR_DIR_NOSEND:
  619. printf("Packet " COUNTER_SPEC " -> Don't Send\n", i);
  620. break;
  621. default:
  622. err(-1, "Invalid cachedata value!");
  623. break;
  624. }
  625. }
  626. exit(0);
  627. }
  628. /**
  629. * Print the per-packet statistics
  630. */
  631. static void
  632. print_stats(const char *file)
  633. {
  634. char *cachedata = NULL;
  635. char *comment = NULL;
  636. COUNTER count = 0;
  637. COUNTER pri = 0, sec = 0, nosend = 0;
  638. count = read_cache(&cachedata, file, &comment);
  639. for (COUNTER i = 1; i <= count; i ++) {
  640. int cacheval = check_cache(cachedata, i);
  641. switch (cacheval) {
  642. case TCPR_DIR_C2S:
  643. pri ++;
  644. break;
  645. case TCPR_DIR_S2C:
  646. sec ++;
  647. break;
  648. case TCPR_DIR_NOSEND:
  649. nosend ++;
  650. break;
  651. default:
  652. errx(-1, "Unknown cache value: %d", cacheval);
  653. }
  654. }
  655. printf("Primary packets:\t" COUNTER_SPEC "\n", pri);
  656. printf("Secondary packets:\t" COUNTER_SPEC "\n", sec);
  657. printf("Skipped packets:\t" COUNTER_SPEC "\n", nosend);
  658. printf("------------------------------\n");
  659. printf("Total packets:\t\t" COUNTER_SPEC "\n", count);
  660. exit(0);
  661. }