aboutsummaryrefslogblamecommitdiffstats
path: root/libglouglou/libggnet.c
blob: 10c2cf58b273bd588963ab084a20c80e4c56caf0 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
                   
                   
                  
 
                     
                         
 
                                                            

                                                                          
                                                                    


                                                                        

                                                                 
                                                              
 
              
                            

                    
        
 




                                         
                                     


                                                
 


             





                                            
                                              
                                                                                                           






                                                                                 
    

                                         
                                                                       










                                        





                                           



                              
                                   




                                                    

                                                     







                                                       

                                     
 




                                                 
               
                                      


                                                    

                              

                                                                             






                                                       





                                                                                  
 

                              

                                             
 
                              














                                                          











                                                           





                                          

                                                                    

                                                                      





                                   


                                                                      
 

                                                            
                                                                       






                                                  




                                                   

                                       



                                                   

                                       
 




                                              







                                         
                             
                                
                          







                                                                                

                                      
 



                                               
                                

                                     




                                                       

                                     
 
                











                                                     
          
 
                           



                                                    


                                                     

                       

                                      
                       

                                      




                              

























                                                                            















































                                                                   











                                                                     




                                                 

                               

                                                                        


                                




                                                    
                     



                                 













                                                   
                                       






                                                               





                                                                                        
 
                               




                                               



                            

                                                                         
 
                                  
 


                                            

                                            






                       











                                                        
               








                                                                 
















                                                        








                                                           
             
                                                   

                             

 
#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);
  }
}