/** * calculates wether each node in the tree is a client, server, or unknown for each node in the tree */ void tree_calculate(tcpr_data_tree_t *treeroot) { tcpr_tree_t *node; tcpprep_opt_t *options = tcpprep->options; dbg(1, "Running tree_calculate()"); RB_FOREACH(node, tcpr_data_tree_s, treeroot) { dbgx(4, "Processing %s", get_addr2name4(node->u.ip, RESOLVE)); if ((node->server_cnt > 0) || (node->client_cnt > 0)) { /* type based on: server >= (client*ratio) */ if ((double)node->server_cnt >= (double)node->client_cnt * options->ratio) { node->type = DIR_SERVER; dbgx(3, "Setting %s to server", get_addr2name4(node->u.ip, RESOLVE)); } else { node->type = DIR_CLIENT; dbgx(3, "Setting %s to client", get_addr2name4(node->u.ip, RESOLVE)); } } else { /* IP had no client or server connections */ node->type = DIR_UNKNOWN; dbgx(3, "Setting %s to unknown", get_addr2name4(node->u.ip, RESOLVE)); } }
/** * \brief Converts the binary network address of a tcpr_cidr_t to a string */ const char * get_cidr2name(const tcpr_cidr_t *cidr_ptr, bool dnslookup) { if (cidr_ptr->family == AF_INET) { return get_addr2name4(cidr_ptr->u.network, dnslookup); } else if (cidr_ptr->family == AF_INET6) { return get_addr2name6(&cidr_ptr->u.network6, dnslookup); } else { return NULL; } }
/** * adds an entry to the tree (phase 1 of auto mode). We add each host * to the tree if it doesn't yet exist. We go through and track: * - number of times each host acts as a client or server * - the way the host acted the first time we saw it (client or server) */ void add_tree_ipv4(const unsigned long ip, const u_char * data) { tcpr_tree_t *newnode = NULL; assert(data); newnode = packet2tree(data); assert(ip == newnode->u.ip); if (newnode->type == DIR_UNKNOWN) { /* couldn't figure out if packet was client or server */ dbgx(2, "%s (%lu) unknown client/server", get_addr2name4(newnode->u.ip, RESOLVE), newnode->u.ip); } add_tree_node(newnode); }
/** * takes in an IP and masklen, and returns a string in * cidr format: x.x.x.x/y. This malloc's memory. */ u_char * ip2cidr(const unsigned long ip, const int masklen) { u_char *network; char mask[3]; network = (u_char *)safe_malloc(20); strlcpy((char *)network, (char *)get_addr2name4(ip, RESOLVE), 20); strcat((char *)network, "/"); if (masklen < 10) { snprintf(mask, 1, "%d", masklen); strncat((char *)network, mask, 1); } else { snprintf(mask, 2, "%d", masklen); strncat((char *)network, mask, 2); } return (network); }
/** * used with rbwalk to walk a tree and generate cidr_t * cidrdata. * is smart enough to prevent dupes. void * arg is cast to bulidcidr_t */ void tree_buildcidr(tcpr_data_tree_t *treeroot, tcpr_buildcidr_t * bcdata) { tcpr_tree_t *node = NULL; tcpr_cidr_t *newcidr = NULL; unsigned long network = 0; struct tcpr_in6_addr network6; unsigned long mask = ~0; /* turn on all bits */ tcpprep_opt_t *options = tcpprep->options; int i, j, k; dbg(1, "Running: tree_buildcidr()"); RB_FOREACH(node, tcpr_data_tree_s, treeroot) { /* we only check types that are valid */ if (bcdata->type != DIR_ANY) /* don't check if we're adding ANY */ if (bcdata->type != node->type) /* no match, exit early */ return; /* * in cases of leaves and last visit add to cidrdata if * necessary. First check IPv4 */ dbgx(4, "Checking if %s exists in cidrdata...", get_addr2name4(node->u.ip, RESOLVE)); if (node->family == AF_INET) { if (! check_ip_cidr(options->cidrdata, node->u.ip)) { /* if we exist, abort */ dbgx(3, "Node %s doesn't exist... creating.", get_addr2name4(node->u.ip, RESOLVE)); newcidr = new_cidr(); newcidr->masklen = bcdata->masklen; network = node->u.ip & (mask << (32 - bcdata->masklen)); dbgx(3, "Using network: %s", get_addr2name4(network, RESOLVE)); newcidr->u.network = network; add_cidr(&options->cidrdata, &newcidr); } } /* Check IPv6 Address */ else if (node->family == AF_INET6) { if (! check_ip6_cidr(options->cidrdata, &node->u.ip6)) { /* if we exist, abort */ dbgx(3, "Node %s doesn't exist... creating.", get_addr2name6(&node->u.ip6, RESOLVE)); newcidr = new_cidr(); newcidr->masklen = bcdata->masklen; /* init each 4 quads to zero */ for (i = 0; i < 4; i++) network6.tcpr_s6_addr32[i] = 0; /* Build our mask */ j = bcdata->masklen / 8; for (i = 0; i < j; i++) network6.tcpr_s6_addr[i] = node->u.ip6.tcpr_s6_addr[i]; if ((k = bcdata->masklen % 8) != 0) { k = ~0 << (8 - k); network6.tcpr_s6_addr[j] = node->u.ip6.tcpr_s6_addr[i] & k; } dbgx(3, "Using network: %s", get_addr2name6(&network6, RESOLVE)); newcidr->u.network6 = network6; add_cidr(&options->cidrdata, &newcidr); } } } }
/** * Checks to see if an IP is client or server by finding it in the tree * returns TCPR_DIR_C2S or TCPR_DIR_S2C or -1 on error * if mode = UNKNOWN, then abort on unknowns * if mode = CLIENT, then unknowns become clients * if mode = SERVER, then unknowns become servers */ tcpr_dir_t check_ip_tree(const int mode, const unsigned long ip) { tcpr_tree_t *node = NULL, *finder = NULL; finder = new_tree(); finder->family = AF_INET; finder->u.ip = ip; node = RB_FIND(tcpr_data_tree_s, &treeroot, finder); if (node == NULL && mode == DIR_UNKNOWN) errx(-1, "%s (%lu) is an unknown system... aborting.!\n" "Try a different auto mode (-n router|client|server)", get_addr2name4(ip, RESOLVE), ip); #ifdef DEBUG switch (node->type) { case DIR_SERVER: dbgx(1, "DIR_SERVER: %s", get_addr2name4(ip, RESOLVE)); break; case DIR_CLIENT: dbgx(1, "DIR_CLIENT: %s", get_addr2name4(ip, RESOLVE)); break; case DIR_UNKNOWN: dbgx(1, "DIR_UNKNOWN: %s", get_addr2name4(ip, RESOLVE)); break; case DIR_ANY: dbgx(1, "DIR_ANY: %s", get_addr2name4(ip, RESOLVE)); break; } #endif /* return node type if we found the node, else return the default (mode) */ if (node != NULL) { switch (node->type) { case DIR_SERVER: return TCPR_DIR_S2C; break; case DIR_CLIENT: return TCPR_DIR_C2S; break; case DIR_UNKNOWN: case DIR_ANY: /* use our current mode to determine return code */ goto return_unknown; default: errx(-1, "Node for %s has invalid type: %d", get_addr2name4(ip, RESOLVE), node->type); } } return_unknown: switch (mode) { case DIR_SERVER: return TCPR_DIR_S2C; break; case DIR_CLIENT: return TCPR_DIR_C2S; break; default: return -1; } }