#include #include #include #include "libggnet.h" #include "libggnet_dns.h" static struct ggnet_nodegroup *nodegroup_add(struct ggnet *, enum ggnet_grouptype, void *, struct ggnet_nodegroup *); static void nodegroup_del(struct ggnet *, struct ggnet_nodegroup *); static struct ggnet_nodegroup *nodegroup_find(struct ggnet *, enum ggnet_grouptype type, void *param); static void nodegroup_set(struct ggnet *, struct ggnet_node *); static void nodegroup_unset(struct ggnet *, struct ggnet_node *); static void _cb_dns_reverse(struct in_addr *, char *, void *); struct ggnet * ggnet_new(int manage_connid) { struct ggnet *net; int i; net = calloc(1, sizeof(struct ggnet)); if (!net) { printf("could not allocate ggnet\n"); exit(1); } net->manage_connid = manage_connid; if (manage_connid) for (i=0; iconn_freeids[i] = i; return net; } /** * Sets grouping option * * Note: Must be set before any use of ggnet */ void ggnet_set_grouping(struct ggnet *net, int set, void (*cb_addgroup)(struct ggnet *, struct ggnet_nodegroup *, struct ggnet_nodegroup *), void (*cb_delgroup)(struct ggnet *, struct ggnet_nodegroup *)) { net->use_grouping = set; net->cb_addgroup = cb_addgroup; net->cb_delgroup = cb_delgroup; } void ggnet_set_dns(struct ggnet *net, int set, struct event_base *ev_base, void (*cb_nodename)(struct ggnet *, struct ggnet_node *)) { net->use_dns = set; if (set) { net->ggdns = ggnet_dns_new(ev_base); net->cb_nodename = cb_nodename; } else if (net->use_dns) ggnet_dns_free(net->ggdns); } void ggnet_debug_set(struct ggnet *net, int set) { net->debug = set; } void ggnet_free(struct ggnet *net) { struct ggnet_conn *c, *ctmp; struct ggnet_node *n, *ntmp; struct ggnet_nodegroup *g, *gtmp; LIST_FOREACH_SAFE(c, &net->conn_list, entry, ctmp) ggnet_conn_del(net, c); LIST_FOREACH_SAFE(n, &net->node_list, entry, ntmp) ggnet_node_del(net, n); LIST_FOREACH_SAFE(g, &net->group_list, entry, gtmp) nodegroup_del(net, g); free(net); } struct ggnet_node * ggnet_node_add(struct ggnet *net, struct in_addr *addr) { struct ggnet_node *n; if (net->debug) printf("ggnet_node_add\n"); n = calloc(1, sizeof(struct ggnet_node)); if (!n) { printf("could not allocate node\n"); exit(1); } n->net = net; n->addr.s_addr = addr->s_addr; n->lastseen = net->time; LIST_INSERT_HEAD(&net->node_list, n, entry); net->node_count++; if (net->use_grouping) nodegroup_set(net, n); if (net->use_dns) n->dns_req = ggnet_dns_reverse(net->ggdns, &n->addr, _cb_dns_reverse, n); return n; } void ggnet_node_del(struct ggnet *net, struct ggnet_node *n) { if (n->used) { printf("FATAL: ggnet_node_del: trying to remove a used node !\n"); exit(1); } if (net->debug) printf("ggnet_node_del: ggnet_node_del\n"); if (net->use_grouping) nodegroup_unset(net, n); if (n->dns_req) ggnet_dns_cancel(net->ggdns, n->dns_req); LIST_REMOVE(n, entry); free(n); net->node_count--; } struct ggnet_node * ggnet_node_find(struct ggnet *net, struct in_addr *remote) { struct ggnet_node *n; LIST_FOREACH(n, &net->node_list, entry) if (n->addr.s_addr == remote->s_addr) return n; return NULL; } void * ggnet_node_usrdata_get(struct ggnet_node *n) { return n->usrdata; } void ggnet_node_usrdata_set(struct ggnet_node *n, void *usrdata) { n->usrdata = usrdata; } struct ggnet_nodegroup * ggnet_node_group_get(struct ggnet_node *n) { return n->group; } struct ggnet_conn * ggnet_conn_add(struct ggnet *net, struct in_addr *src, int src_port, struct in_addr *dst, int dst_port, int proto, int size, int given_id) { struct ggnet_conn *c; struct ggnet_node *srcnode; struct ggnet_node *dstnode; int id; if (net->debug) printf("ggnet_conn_add, %x:%d->%x:%d %d [%d]\n", src->s_addr, src_port, dst->s_addr, dst_port, proto, size); if (net->manage_connid) { if (net->conn_freeids_ptr == GGNET_CONN_FREEIDS_COUNT) { printf("ggnet_conn_add: ERROR: out of connection identifiers !"); return NULL; } id = net->conn_freeids[net->conn_freeids_ptr]; net->conn_freeids_ptr++; } else { id = given_id; } srcnode = ggnet_node_find(net, src); if (!srcnode) srcnode = ggnet_node_add(net, src); srcnode->used++; if (srcnode->group) srcnode->group->conn_count++; dstnode = ggnet_node_find(net, dst); if (!dstnode) dstnode = ggnet_node_add(net, dst); dstnode->used++; if (dstnode->group) dstnode->group->conn_count++; c = malloc(sizeof(struct ggnet_conn)); if (!c) { printf("could not allocate conn\n"); exit(1); } c->id = id; c->state = CONNSTATE_ESTABLISHED; c->src = srcnode; c->src_port = src_port; c->dst = dstnode; c->dst_port = dst_port; c->proto = proto; c->size = size; c->size_response = 0; c->lastseen = net->time; c->usrdata = NULL; LIST_INSERT_HEAD(&net->conn_list, c, entry); return c; } void ggnet_conn_data(struct ggnet *net, struct ggnet_conn *c, int size, int response) { if (net->debug) printf("ggnet_conn_data\n"); if (!response) c->size = c->size + size; else c->size_response = c->size_response + size; c->lastseen = net->time; c->src->lastseen = net->time; c->dst->lastseen = net->time; } void ggnet_conn_del(struct ggnet *net, struct ggnet_conn *c) { if (net->debug) printf("ggnet_conn_del\n"); /* UNSUPPORTED if (c->proto == IPPROTO_TCP) { switch (c->state) { case CONNSTATE_ESTABLISHED: c->state = CONNSTATE_TCPFIN; return; case CONNSTATE_TCPFIN: c->state = CONNSTATE_TCPFIN2; return; case CONNSTATE_TCPFIN2: break; } } */ if (net->manage_connid) { if (net->conn_freeids_ptr == 0) { printf("FATAL: net->conn_freeids_ptr == 0\n"); exit(1); } net->conn_freeids_ptr--; net->conn_freeids[net->conn_freeids_ptr] = c->id; } c->src->used--; if (c->src->group) c->src->group->conn_count--; c->dst->used--; if (c->dst->group) c->dst->group->conn_count--; LIST_REMOVE(c, entry); free(c); } struct ggnet_conn * ggnet_conn_find(struct ggnet *net, struct in_addr *src, int src_port, struct in_addr *dst, int dst_port, int proto, int *response) { struct ggnet_conn *c; LIST_FOREACH(c, &net->conn_list, entry) { if (((c->src->addr.s_addr == src->s_addr && c->src_port == src_port && c->dst->addr.s_addr == dst->s_addr && c->dst_port == dst_port) || (c->src->addr.s_addr == dst->s_addr && c->src_port == dst_port && c->dst->addr.s_addr == src->s_addr && c->dst_port == src_port)) && c->proto == proto) { if (c->src->addr.s_addr == src->s_addr) *response = 0; else *response = 1; return c; } } return NULL; } struct ggnet_conn * ggnet_conn_find_by_id(struct ggnet *net, int id) { struct ggnet_conn *c; LIST_FOREACH(c, &net->conn_list, entry) if (c->id == id) return c; return NULL; } struct ggnet_conn * ggnet_conn_find_by_node(struct ggnet *net, struct ggnet_node *a, struct ggnet_node *b) { struct ggnet_conn *c; LIST_FOREACH(c, &net->conn_list, entry) if ((c->src == a && c->dst == b) || (c->src == b && c->dst == a)) return c; return NULL; } void * ggnet_conn_usrdata_get(struct ggnet_conn *c) { return c->usrdata; } void ggnet_conn_usrdata_set(struct ggnet_conn *c, void *usrdata) { c->usrdata = usrdata; } void * ggnet_conn_src_get(struct ggnet_conn *c) { return c->src; } void * ggnet_conn_dst_get(struct ggnet_conn *c) { return c->dst; } void * ggnet_nodegroup_usrdata_get(struct ggnet_nodegroup *g) { return g->usrdata; } void ggnet_nodegroup_usrdata_set(struct ggnet_nodegroup *g, void *usrdata) { g->usrdata = usrdata; } void ggnet_time_update(struct ggnet *net, time_t time) { net->time = time; } static struct ggnet_nodegroup * nodegroup_add(struct ggnet *net, enum ggnet_grouptype type, void *param, struct ggnet_nodegroup *parent) { struct ggnet_nodegroup *group; group = calloc(1, sizeof(struct ggnet_nodegroup)); if (!group) { printf("could not allocate nodegroup\n"); exit(1); } group->type = type; if (parent) { group->parent = parent; parent->child_groups_count++; } switch (type) { case GROUP_ADDRESS: group->addr.s_addr = *(u_int *)param; break; case GROUP_WHOIS: case GROUP_DNS: case GROUP_ROUTE: /* UNSUPPORTED */ free(group); return NULL; } LIST_INSERT_HEAD(&net->group_list, group, entry); net->cb_addgroup(net, group, parent); return group; } static void nodegroup_del(struct ggnet *net, struct ggnet_nodegroup *group) { if (group->node_count || group->conn_count) { printf("FATAL: ggnet_nodegroup_del: trying to remove a used group !\n"); exit(1); } if (net->debug) printf("ggnet_nodegroup_del\n"); net->cb_delgroup(net, group); if (group->parent) { group->parent->child_groups_count--; if (group->parent->child_groups_count == 0) nodegroup_del(net, group->parent); } LIST_REMOVE(group, entry); free(group); } static struct ggnet_nodegroup * nodegroup_find(struct ggnet *net, enum ggnet_grouptype type, void *param) { struct ggnet_nodegroup *g; LIST_FOREACH(g, &net->group_list, entry) { switch (g->type) { case GROUP_ADDRESS: if (g->addr.s_addr == *(u_int *)param) return g; case GROUP_WHOIS: case GROUP_DNS: case GROUP_ROUTE: /* UNSUPPORTED */ break; } } return NULL; } static void nodegroup_set(struct ggnet *net, struct ggnet_node *n) { struct ggnet_nodegroup *group, *groot, *gclassb; u_int addr, addr2; addr = n->addr.s_addr & 0xffff0000; group = nodegroup_find(net, GROUP_ADDRESS, &addr); if (!group) { addr2 = 0x00000000; groot = nodegroup_find(net, GROUP_ADDRESS, &addr2); if (!groot) groot = nodegroup_add(net, GROUP_ADDRESS, &addr2, NULL); addr2 = addr & 0xff000000; gclassb = nodegroup_find(net, GROUP_ADDRESS, &addr2); if (!gclassb) gclassb = nodegroup_add(net, GROUP_ADDRESS, &addr2, groot); group = nodegroup_add(net, GROUP_ADDRESS, &addr, gclassb); } n->group = group; group->node_count++; } static void nodegroup_unset(struct ggnet *net, struct ggnet_node *n) { if (!n->group) return; n->group->node_count--; if (n->group->node_count == 0) nodegroup_del(net, n->group); } static void _cb_dns_reverse(struct in_addr *ip, char *name, void *data) { struct ggnet *net; struct ggnet_node *n; n = data; net = n->net; n->dns_req = NULL; if (name) { snprintf(n->fqdn, sizeof(n->fqdn), "%s", name); net->cb_nodename(net, n); } }