aboutsummaryrefslogblamecommitdiffstats
path: root/libglouglou/libggnet.c
blob: 832de5483b6db7e921aac06ee76aa6d303af3b39 (plain) (tree)
1
2
3
4
5
6
7
                   
                   
                  
 
                     
                         
 











                                                                        
 
              
                            
 













                                                            

 





                                            
                                              

                                                                                                        
 


                                       

 
    
                                         

                                                                         
 






                                                    


    

                                           
                         


    

                             










                                                           






                                                       
                       
                                           
 
                                                 




                                                    
                                      


                                                    
                              


                                                                                         






                                                       


                                                                                  
         
                       
                                                           
 
                              


                                                         
 
                              














                                                          


                                            
                          




                                                           
                             

 


                                          
                        

 

                                                                    

                                                                       





                                   
                       












                                                                                           




                                                   
                           
                                             



                                                   
                           
                                             
 
                                              



                                                    







                                         
                             
                                
                          







                                                                                
                       
                                            
 



                                                           
                                

                                     




                                                       
                       




















                                                                      
                 

                                                                 
         

                       
                          
                                            
                       
                          
                                            




                              

                                                                     
                                                                            
 
                             


                                                           







                                                                                     









                                                               


                                                
                             

                                               


                                 



                                          
                                                           
 
                             

                                               



                                                             




                                            
                          




                                                           
                             




                                        
                      




                                        
                      

 


                                                      
                          




                                                                     
                             

 


                                                 
                         
 

                               
                                                                        
                                               
 




























                                                             




                                                               
                                                     

                                                                                        
         
                       









                                                           

 

                                                                         
 
                                  
 












                                                                      







                                                        
















                                                                                   




                                                        

                       
 


                                             

 


                                                           









                                                               

 
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#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; i<GGNET_CONN_FREEIDS_COUNT-1; i++)
			net->conn_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);
	}
}