tcpprep.c 24 KB

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