tree.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594
  1. /* $Id: tree.c 1493 2006-07-11 22:51:39Z aturner $ */
  2. /*
  3. * Copyright (c) 2001-2005 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. #include "config.h"
  32. #include "defines.h"
  33. #include "common.h"
  34. #include <stdio.h>
  35. #include <stdlib.h>
  36. #include "tree.h"
  37. #include "tcpprep.h"
  38. #include "tcpprep_opts.h"
  39. extern tcpr_data_tree_t treeroot;
  40. extern tcpprep_opt_t options;
  41. #ifdef DEBUG
  42. extern int debug;
  43. #endif
  44. /* static buffer used by tree_print*() functions */
  45. char tree_print_buff[TREEPRINTBUFFLEN];
  46. static tcpr_tree_t *new_tree();
  47. static tcpr_tree_t *packet2tree(const u_char *);
  48. static char *tree_print(tcpr_data_tree_t *);
  49. static char *tree_printnode(const char *, const tcpr_tree_t *);
  50. static void tree_buildcidr(tcpr_data_tree_t *, tcpr_buildcidr_t *);
  51. static int tree_checkincidr(tcpr_data_tree_t *, tcpr_buildcidr_t *);
  52. RB_PROTOTYPE(tcpr_data_tree_s, tcpr_tree_s, node, tree_comp)
  53. RB_GENERATE(tcpr_data_tree_s, tcpr_tree_s, node, tree_comp)
  54. /*
  55. * used with rbwalk to walk a tree and generate cidr_t * cidrdata.
  56. * is smart enough to prevent dupes. void * arg is cast to bulidcidr_t
  57. */
  58. void
  59. tree_buildcidr(tcpr_data_tree_t *treeroot, tcpr_buildcidr_t * bcdata)
  60. {
  61. tcpr_tree_t *node = NULL;
  62. tcpr_cidr_t *newcidr = NULL;
  63. unsigned long network = 0;
  64. unsigned long mask = ~0; /* turn on all bits */
  65. dbg(1, "Running: tree_buildcidr()");
  66. RB_FOREACH(node, tcpr_data_tree_s, treeroot) {
  67. /* we only check types that are vaild */
  68. if (bcdata->type != ANY) /* don't check if we're adding ANY */
  69. if (bcdata->type != node->type) /* no match, exit early */
  70. return;
  71. /*
  72. * in cases of leaves and last visit add to cidrdata if
  73. * necessary
  74. */
  75. dbgx(4, "Checking if %s exists in cidrdata...", get_addr2name4(node->ip, RESOLVE));
  76. if (!check_ip_cidr(options.cidrdata, node->ip)) { /* if we exist, abort */
  77. dbgx(3, "Node %s doesn't exist... creating.",
  78. get_addr2name4(node->ip, RESOLVE));
  79. newcidr = new_cidr();
  80. newcidr->masklen = bcdata->masklen;
  81. network = node->ip & (mask << (32 - bcdata->masklen));
  82. dbgx(3, "Using network: %s",
  83. get_addr2name4(network, RESOLVE));
  84. newcidr->network = network;
  85. add_cidr(&options.cidrdata, &newcidr);
  86. }
  87. }
  88. }
  89. /*
  90. * uses rbwalk to check to see if a given ip address of a given type in the
  91. * tree is inside any of the cidrdata
  92. *
  93. */
  94. static int
  95. tree_checkincidr(tcpr_data_tree_t *treeroot, tcpr_buildcidr_t * bcdata)
  96. {
  97. tcpr_tree_t *node = NULL;
  98. RB_FOREACH(node, tcpr_data_tree_s, treeroot) {
  99. /* we only check types that are vaild */
  100. if (bcdata->type != ANY) /* don't check if we're adding ANY */
  101. if (bcdata->type != node->type) /* no match, exit early */
  102. return 0;
  103. /*
  104. * in cases of leaves and last visit add to cidrdata if
  105. * necessary
  106. */
  107. if (check_ip_cidr(options.cidrdata, node->ip)) { /* if we exist, abort */
  108. return 1;
  109. }
  110. }
  111. return 0;
  112. }
  113. /*
  114. * processes the tree using rbwalk / tree2cidr to generate a CIDR
  115. * used for 2nd pass, router mode
  116. *
  117. * returns > 0 for success (the mask len), 0 for fail
  118. */
  119. int
  120. process_tree()
  121. {
  122. int mymask = 0;
  123. tcpr_buildcidr_t *bcdata;
  124. dbg(1, "Running: process_tree()");
  125. bcdata = (tcpr_buildcidr_t *)safe_malloc(sizeof(tcpr_buildcidr_t));
  126. for (mymask = options.max_mask; mymask <= options.min_mask; mymask++) {
  127. dbgx(1, "Current mask: %u", mymask);
  128. /* set starting vals */
  129. bcdata->type = SERVER;
  130. bcdata->masklen = mymask;
  131. /* build cidrdata with servers */
  132. tree_buildcidr(&treeroot, bcdata);
  133. /* calculate types of all IP's */
  134. tree_calculate(&treeroot);
  135. /* try to find clients in cidrdata */
  136. bcdata->type = CLIENT;
  137. if (! tree_checkincidr(&treeroot, bcdata)) { /* didn't find any clients in cidrdata */
  138. return (mymask); /* success! */
  139. }
  140. else {
  141. destroy_cidr(options.cidrdata); /* clean up after our mess */
  142. options.cidrdata = NULL;
  143. }
  144. }
  145. /* we failed to find a vaild cidr list */
  146. return (0);
  147. }
  148. /*
  149. * processes rbdata to bulid cidrdata based upon the
  150. * given type (SERVER, CLIENT, UNKNOWN) using the given masklen
  151. *
  152. * is smart enough to prevent dupes
  153. void
  154. tcpr_tree_to_cidr(const int masklen, const int type)
  155. {
  156. }
  157. */
  158. /*
  159. * Checks to see if an IP is client or server by finding it in the tree
  160. * returns CACHE_PRIMARY or CACHE_SECONDARY or -1 on error
  161. * if mode = UNKNOWN, then abort on unknowns
  162. * if mode = CLIENT, then unknowns become clients
  163. * if mode = SERVER, then unknowns become servers
  164. */
  165. int
  166. check_ip_tree(const int mode, const unsigned long ip)
  167. {
  168. tcpr_tree_t *node = NULL, *finder = NULL;
  169. finder = new_tree();
  170. finder->ip = ip;
  171. node = RB_FIND(tcpr_data_tree_s, &treeroot, finder);
  172. if (node == NULL && mode == UNKNOWN)
  173. errx(1, "%s (%lu) is an unknown system... aborting.!\n"
  174. "Try a different auto mode (-n router|client|server)",
  175. get_addr2name4(ip, RESOLVE), ip);
  176. #ifdef DEBUG
  177. if (node->type == SERVER) {
  178. dbgx(1, "Server: %s", get_addr2name4(ip, RESOLVE));
  179. }
  180. else if (node->type == CLIENT) {
  181. dbgx(1, "Client: %s", get_addr2name4(ip, RESOLVE));
  182. }
  183. else {
  184. dbgx(1, "Unknown: %s", get_addr2name4(ip, RESOLVE));
  185. }
  186. #endif
  187. /* return node type if we found the node, else return the default (mode) */
  188. if (node != NULL) {
  189. if (node->type == SERVER) {
  190. return CACHE_PRIMARY;
  191. } else if (node->type == CLIENT) {
  192. return CACHE_SECONDARY;
  193. }
  194. }
  195. else {
  196. if (mode == SERVER) {
  197. return CACHE_PRIMARY;
  198. } else if (mode == CLIENT) {
  199. return CACHE_SECONDARY;
  200. }
  201. }
  202. err(1, "Uh, we shouldn't of gotten here.");
  203. return(-1);
  204. }
  205. /*
  206. * adds an entry to the tree (phase 1 of auto mode)
  207. */
  208. void
  209. add_tree(const unsigned long ip, const u_char * data)
  210. {
  211. tcpr_tree_t *node = NULL, *newnode = NULL;
  212. newnode = packet2tree(data);
  213. assert(ip == newnode->ip);
  214. if (newnode->type == UNKNOWN) {
  215. /* couldn't figure out if packet was client or server */
  216. dbgx(2, "%s (%lu) unknown client/server",
  217. get_addr2name4(newnode->ip, RESOLVE), newnode->ip);
  218. }
  219. /* try to find a simular entry in the tree */
  220. node = RB_FIND(tcpr_data_tree_s, &treeroot, newnode);
  221. dbgx(3, "%s", tree_printnode("add_tree", node));
  222. /* new entry required */
  223. if (node == NULL) {
  224. /* increment counters */
  225. if (newnode->type == SERVER) {
  226. newnode->server_cnt++;
  227. }
  228. else if (newnode->type == CLIENT) {
  229. newnode->client_cnt++;
  230. }
  231. /* insert it in */
  232. RB_INSERT(tcpr_data_tree_s, &treeroot, newnode);
  233. }
  234. else {
  235. /* we found something, so update it */
  236. dbgx(2, " node: %p\nnewnode: %p", node, newnode);
  237. dbgx(3, "%s", tree_printnode("update node", node));
  238. /* increment counter */
  239. if (newnode->type == SERVER) {
  240. node->server_cnt++;
  241. }
  242. else if (newnode->type == CLIENT) {
  243. /* temp debug code */
  244. node->client_cnt++;
  245. }
  246. /* didn't insert it, so free it */
  247. free(newnode);
  248. }
  249. dbg(2, "------- START NEXT -------");
  250. dbgx(3, "%s", tree_print(&treeroot));
  251. }
  252. /*
  253. * calculates wether an IP is a client, server, or unknown for each node in the tree
  254. */
  255. void
  256. tree_calculate(tcpr_data_tree_t *treeroot)
  257. {
  258. tcpr_tree_t *node;
  259. dbg(1, "Running tree_calculate()");
  260. RB_FOREACH(node, tcpr_data_tree_s, treeroot) {
  261. dbgx(4, "Processing %s", get_addr2name4(node->ip, RESOLVE));
  262. if ((node->server_cnt > 0) || (node->client_cnt > 0)) {
  263. /* type based on: server >= (client*ratio) */
  264. if ((double)node->server_cnt >= (double)node->client_cnt * options.ratio) {
  265. node->type = SERVER;
  266. dbgx(3, "Setting %s to server",
  267. get_addr2name4(node->ip, RESOLVE));
  268. }
  269. else {
  270. node->type = CLIENT;
  271. dbgx(3, "Setting %s to client",
  272. get_addr2name4(node->ip, RESOLVE));
  273. }
  274. }
  275. else { /* IP had no client or server connections */
  276. node->type = UNKNOWN;
  277. dbgx(3, "Setting %s to unknown",
  278. get_addr2name4(node->ip, RESOLVE));
  279. }
  280. }
  281. }
  282. /*
  283. * tree_comp(), called by rbsearch compares two treees and returns:
  284. * 1 = first > second
  285. * -1 = first < second
  286. * 0 = first = second
  287. * based upon the ip address stored
  288. *
  289. */
  290. int
  291. tree_comp(tcpr_tree_t *t1, tcpr_tree_t *t2)
  292. {
  293. if (t1->ip > t2->ip) {
  294. dbgx(2, "%s > %s", get_addr2name4(t1->ip, RESOLVE),
  295. get_addr2name4(t2->ip, RESOLVE));
  296. return 1;
  297. }
  298. if (t1->ip < t2->ip) {
  299. dbgx(2, "%s < %s", get_addr2name4(t1->ip, RESOLVE),
  300. get_addr2name4(t2->ip, RESOLVE));
  301. return -1;
  302. }
  303. dbgx(2, "%s = %s", get_addr2name4(t1->ip, RESOLVE),
  304. get_addr2name4(t2->ip, RESOLVE));
  305. return 0;
  306. }
  307. /*
  308. * creates a new TREE * with reasonable defaults
  309. */
  310. static tcpr_tree_t *
  311. new_tree()
  312. {
  313. tcpr_tree_t *node;
  314. node = (tcpr_tree_t *)safe_malloc(sizeof(tcpr_tree_t));
  315. memset(node, '\0', sizeof(tcpr_tree_t));
  316. node->server_cnt = 0;
  317. node->client_cnt = 0;
  318. node->type = UNKNOWN;
  319. node->masklen = -1;
  320. node->ip = 0;
  321. return (node);
  322. }
  323. /*
  324. * returns a struct of TREE * from a packet header
  325. * and sets the type to be SERVER or CLIENT or UNKNOWN
  326. * if it's an undefined packet, we return -1 for the type
  327. * the u_char * data should be the data that is passed by pcap_dispatch()
  328. */
  329. tcpr_tree_t *
  330. packet2tree(const u_char * data)
  331. {
  332. tcpr_tree_t *node = NULL;
  333. eth_hdr_t *eth_hdr = NULL;
  334. ip_hdr_t ip_hdr;
  335. tcp_hdr_t tcp_hdr;
  336. udp_hdr_t udp_hdr;
  337. icmp_hdr_t icmp_hdr;
  338. dns_hdr_t dns_hdr;
  339. node = new_tree();
  340. eth_hdr = (eth_hdr_t *) (data);
  341. /* prevent issues with byte alignment, must memcpy */
  342. memcpy(&ip_hdr, (data + LIBNET_ETH_H), LIBNET_IP_H);
  343. /* copy over the source mac */
  344. strncpy((char *)node->mac, (char *)eth_hdr->ether_shost, 6);
  345. /* copy over the source ip */
  346. node->ip = ip_hdr.ip_src.s_addr;
  347. /*
  348. * TCP
  349. */
  350. if (ip_hdr.ip_p == IPPROTO_TCP) {
  351. dbgx(3, "%s uses TCP... ",
  352. get_addr2name4(ip_hdr.ip_src.s_addr, RESOLVE));
  353. /* memcpy it over to prevent alignment issues */
  354. memcpy(&tcp_hdr, (data + LIBNET_ETH_H + (ip_hdr.ip_hl * 4)),
  355. LIBNET_TCP_H);
  356. /* ftp-data is going to skew our results so we ignore it */
  357. if (tcp_hdr.th_sport == 20) {
  358. return (node);
  359. }
  360. /* set TREE->type based on TCP flags */
  361. if (tcp_hdr.th_flags == TH_SYN) {
  362. node->type = CLIENT;
  363. dbg(3, "is a client");
  364. }
  365. else if (tcp_hdr.th_flags == (TH_SYN | TH_ACK)) {
  366. node->type = SERVER;
  367. dbg(3, "is a server");
  368. }
  369. else {
  370. dbg(3, "is an unknown");
  371. }
  372. /*
  373. * UDP
  374. */
  375. }
  376. else if (ip_hdr.ip_p == IPPROTO_UDP) {
  377. /* memcpy over to prevent alignment issues */
  378. memcpy(&udp_hdr, (data + LIBNET_ETH_H + (ip_hdr.ip_hl * 4)),
  379. LIBNET_UDP_H);
  380. dbgx(3, "%s uses UDP... ",
  381. get_addr2name4(ip_hdr.ip_src.s_addr, RESOLVE));
  382. switch (ntohs(udp_hdr.uh_dport)) {
  383. case 0x0035: /* dns */
  384. /* prevent memory alignment issues */
  385. memcpy(&dns_hdr,
  386. (data + LIBNET_ETH_H + (ip_hdr.ip_hl * 4) + LIBNET_UDP_H),
  387. LIBNET_DNS_H);
  388. if (dns_hdr.flags & DNS_QUERY_FLAG) {
  389. /* bit set, response */
  390. node->type = SERVER;
  391. dbg(3, "is a dns server");
  392. }
  393. else {
  394. /* bit not set, query */
  395. node->type = CLIENT;
  396. dbg(3, "is a dns client");
  397. }
  398. return (node);
  399. break;
  400. default:
  401. break;
  402. }
  403. switch (ntohs(udp_hdr.uh_sport)) {
  404. case 0x0035: /* dns */
  405. /* prevent memory alignment issues */
  406. memcpy(&dns_hdr,
  407. (data + LIBNET_ETH_H + (ip_hdr.ip_hl * 4) + LIBNET_UDP_H),
  408. LIBNET_DNS_H);
  409. if ((dns_hdr.flags & 0x7FFFF) ^ DNS_QUERY_FLAG) {
  410. /* bit set, response */
  411. node->type = SERVER;
  412. dbg(3, "is a dns server");
  413. }
  414. else {
  415. /* bit not set, query */
  416. node->type = CLIENT;
  417. dbg(3, "is a dns client");
  418. }
  419. return (node);
  420. break;
  421. default:
  422. dbgx(3, "unknown UDP protocol: %hu->%hu", udp_hdr.uh_sport,
  423. udp_hdr.uh_dport);
  424. break;
  425. }
  426. /*
  427. * ICMP
  428. */
  429. }
  430. else if (ip_hdr.ip_p == IPPROTO_ICMP) {
  431. /* prevent alignment issues */
  432. memcpy(&icmp_hdr, (data + LIBNET_ETH_H + (ip_hdr.ip_hl * 4)),
  433. LIBNET_ICMP_H);
  434. dbgx(3, "%s uses ICMP... ",
  435. get_addr2name4(ip_hdr.ip_src.s_addr, RESOLVE));
  436. /*
  437. * if port unreachable, then source == server, dst == client
  438. */
  439. if ((icmp_hdr.icmp_type == ICMP_UNREACH) &&
  440. (icmp_hdr.icmp_code == ICMP_UNREACH_PORT)) {
  441. node->type = SERVER;
  442. dbg(3, "is a server with a closed port");
  443. }
  444. }
  445. return (node);
  446. }
  447. /*
  448. * prints out a node of the tree to stderr
  449. */
  450. static char *
  451. tree_printnode(const char *name, const tcpr_tree_t *node)
  452. {
  453. memset(&tree_print_buff, '\0', TREEPRINTBUFFLEN);
  454. if (node == NULL) {
  455. snprintf(tree_print_buff, TREEPRINTBUFFLEN, "%s node is null", name);
  456. }
  457. else {
  458. snprintf(tree_print_buff, TREEPRINTBUFFLEN,
  459. "-- %s: %p\nIP: %s\nMask: %d\nSrvr: %d\nClnt: %d\n",
  460. name, (void *)node, get_addr2name4(node->ip, RESOLVE),
  461. node->masklen, node->server_cnt, node->client_cnt);
  462. if (node->type == SERVER) {
  463. strlcat(tree_print_buff, "Type: Server\n--\n", TREEPRINTBUFFLEN);
  464. }
  465. else {
  466. strlcat(tree_print_buff, "Type: Client\n--", TREEPRINTBUFFLEN);
  467. }
  468. }
  469. return (tree_print_buff);
  470. }
  471. /*
  472. * prints out the entire tree
  473. */
  474. static char *
  475. tree_print(tcpr_data_tree_t *treeroot)
  476. {
  477. tcpr_tree_t *node = NULL;
  478. memset(&tree_print_buff, '\0', TREEPRINTBUFFLEN);
  479. RB_FOREACH(node, tcpr_data_tree_s, treeroot) {
  480. tree_printnode("my node", node);
  481. }
  482. return (tree_print_buff);
  483. }
  484. /*
  485. Local Variables:
  486. mode:c
  487. indent-tabs-mode:nil
  488. c-basic-offset:4
  489. End:
  490. */