Logo Search packages:      
Sourcecode: netams version File versions  Download package

ds_netgraph.c

/*************************************************************************
***   Authentication, authorization, accounting + firewalling package
***   Copyright 1998-2002 Anton Vinokurov <anton@netams.com>
***   Copyright 2002-2008 NeTAMS Development Team
***   This code is GPL v3
***   For latest version and more info, visit this project web page
***   located at http://www.netams.com
***                                       
*************************************************************************/
/* $Id: ds_netgraph.c,v 1.44 2009-07-06 19:21:36 anton Exp $ */

#ifdef FREEBSD
#ifndef MACOS
#include "netams.h"
#include "ds_any.h"
#include "ng_netams.h"

#include <netgraph.h> /* for user-space netgraph functions */

void ds_netgraph_cancel(void *ptr);
void ds_netgraph_stats(struct cli_def *cli, Service_DS *ds);

unsigned long long ng_total_flows;

struct ds_data {
      struct ng_mesg *ng_mesg;
      int socket; //control socket for netgraph
};

/////////////////////////////////////////////////////////////////////////////////////
void ds_netgraph(Service_DS *ds) {
      int status;
      time_t t_msg1=0, t_msg2=0;   
 
      struct ds_data *dsdata=(struct ds_data*)aMalloc(sizeof(struct ds_data *));

      pthread_cleanup_push(ds_netgraph_cancel, (void*)dsdata);
      pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
      
      char ng_daemon_node[32];
      sprintf(ng_daemon_node, "netams_daemon_%u", getpid());
      if (NgMkSockNode(ng_daemon_node, &(dsdata->socket), NULL)==-1) {
            aLog(D_ERR, "NETGRAPH control socket cannot be created\n");
            return;
      }
      int socket = dsdata->socket;

      // set options
      status  = bigsockbuf(socket, SO_RCVBUF, FT_SO_RCV_BUFSIZE);
      if( status < 0 ) {
            aLog(D_ERR, "failed to setsockopt receive buffer: %s", strerror(errno));
            return;
      } else {
            aLog(D_INFO, "receive bufer set to %u\n", status);
      }

      /* int flags;
      if ((flags = fcntl(socket, F_GETFL, 0)) == -1) {
            aLog(D_ERR, "NETGRAPH fcntl(F_GETFL)\n");
            return;
      }
      flags |= O_NONBLOCK;
      if (fcntl(socket, F_SETFL, flags) == -1) {
            aLog(D_ERR, "NETGRAPH fcntl(F_SETFL)\n");
            return;
      }
      */
      
      SET_POLL(socket);
      
      int token;
      u_int32_t cookie=random()&0xFFFF;
      if ((token=NgSendMsg(socket, ds->src_cmd, NG_NETAMS_COOKIE, NG_NETAMS_REGISTER, &cookie, sizeof (u_int32_t)))==-1){
            aLog(D_ERR, "NETGRAPH register msg send error!\n\nMaybe NETGRAPH module 'ng_netams' is not loaded? \n\n");
      }

      aLog(D_INFO, "NETGRAPH flow processing for data-source:%u initialized\n",ds->instance);

      // statistic data packets (as control data from "netams:" node
      ng_total_flows=0;
      struct ng_mesg *ng_mesg;
      struct ng_entry *e;
      dsdata->ng_mesg = ng_mesg = (struct ng_mesg*) aMalloc(sizeof (struct ng_mesg) + sizeof (struct ng_entry));
      int j;

      struct ng_netams_info *info = (struct ng_netams_info*) aMalloc(sizeof (struct ng_netams_info));
      ds->pcap_data = (void*)info;
      
      FlowEngine  *FE   = ds->FE;   
      Flow        *flow = ds->ds_flow = new Flow(ds->instance,ds->max_flow_slots);

      entry             E;      //need this for FW check
      bzero(&E, sizeof(entry));
      E.flow      = flow;

      struct flow_info_value        *flow_info;
      struct ipv4_info_value        *ipv4_info;
      struct tcp_info_value         *tcp_info;
      struct ifindex_info_value     *ifindex_info;
      
      
      while(1) {
            CHECK_POLL(ds,status);

            t_msg1=netams_time(NULL);
            if (t_msg2 && (t_msg1-t_msg2>20)) { // register again
                  cookie=random()&0xFFFF;
                  if ((token=NgSendMsg(socket, ds->src_cmd, NG_NETAMS_COOKIE, NG_NETAMS_REGISTER, &cookie, sizeof (u_int32_t)))==-1) { aLog(D_ERR, "NETGRAPH registration failed! Maybe NETGRAPH module 'ng_netams' is not loaded?\n"); }
                  t_msg2=t_msg1;
            }

            if(!status) continue;
            
            j=NgRecvMsg(socket, ng_mesg, sizeof(struct ng_mesg) + sizeof (struct ng_entry), NULL);

            if (j==-1) {
                  aLog(D_ERR, "NETGRAPH ctl msg err: %u\n", errno);
            }
            else if (ng_mesg->header.token != cookie) {
                  aLog(D_ERR, "NETGRAPH ctl msg %d repl cookie err: %u %u\n", j, ng_mesg->header.token, cookie);
            }
            else if (ng_mesg->header.typecookie != NG_NETAMS_COOKIE) {
                  aLog(D_ERR, "NETGRAPH ctl msg %d repl typecookie err: %u %u\n\nMaybe your daemon and kernel node versions are different?\n\n", j, ng_mesg->header.typecookie, NG_NETAMS_COOKIE);
            }
            else { 

                  if (ng_mesg->header.cmd==NG_NETAMS_INFO) {
                        ng_netams_info *info_t = (ng_netams_info*)ng_mesg->data;
                        memcpy(info, info_t, sizeof (struct ng_netams_info));
                        t_msg2=t_msg1;
                        continue;
                  }

                  // we have a control message received from kernel node; process it
                  e = (struct ng_entry*)ng_mesg->data;
#ifdef DEBUG                  
                  u_char debug = aDebug(DEBUG_FLOW, "netgraph(%d): flow hash=%u, bytes=%d\n", j, e->hash, e->dOctets);
#endif
                  //flow
                  flow_info         = (struct flow_info_value*)flow->put(ATTR_FLOW_INFO);
                  flow_info->flow_first   = e->First;
                  flow_info->flow_last    = e->Last;
                  flow_info->packets      = e->dPkts;
                  flow_info->octets = e->dOctets;

                  //ipv4
                  ipv4_info         = (struct ipv4_info_value*)flow->put(ATTR_IPV4_INFO);
                  ipv4_info->ip_p         = e->prot;
                  ipv4_info->ip_tos = e->tos;
                  ipv4_info->ip_src = e->srcaddr;
                  ipv4_info->ip_dst = e->dstaddr;

                  if(e->prot == IPPROTO_TCP || e->prot == IPPROTO_UDP) {
                        tcp_info          = (struct tcp_info_value*)flow->put(ATTR_TCP_INFO);
                        tcp_info->src_port      = e->srcport;
                        tcp_info->dst_port      = e->dstport;
                  }
                  
                  //ifindex
                  ifindex_info            = (struct ifindex_info_value*)flow->put(ATTR_IFINDEX_INFO);
                  ifindex_info->if_in     = e->input;
                  ifindex_info->if_out    = e->output;
      
                  //for debugging to proper see hash id           
                  //E.hash = e->hash;

                  switch (ng_mesg->header.cmd) {
                        case NG_NETAMS_DATA: // data massage, send it to accounting
                              ng_total_flows++;
                              aDebug(DEBUG_FLOW, "NG_NETAMS_DATA: flow %p\n", flow);  
                              FE->DoSend(flow);
                              break;
                        case NG_NETAMS_FWREQUEST: // new flow message, check FW and rend reply
                              aDebug(DEBUG_FLOW, "NG_NETAMS_FWREQUEST: flow %p\n", flow);
                              if (ds->ds_flags==DS_TEE)
                                    aLog(D_WARN, "NETGRAPH ctl msg %d FWREQUEST in TEE mode\n", j);
                              else {
                                    if (FE->FW(&E)) e->flags=0; // allow
                                    else e->flags=ENTRY_BLOCKED; // deny
                                    // we have not yet implemented BW policy forwarding back to kernel
                                    NgSendMsg(socket, ds->src_cmd, NG_NETAMS_COOKIE, NG_NETAMS_FWREPLY, e, sizeof (struct ng_entry));
                              }
                              break;
                        default:
                              aLog(D_WARN, "NETGRAPH ctl msg %d repl cmd err: %u\n", j, ng_mesg->header.cmd);
                              break;
                  }
#ifdef DEBUG
                  if(debug) flow->Debug(DEBUG_FLOW);
#endif
                  flow->reuse();
            }
            
      }
      pthread_cleanup_pop(0);
      return;
}
/////////////////////////////////////////////////////////////////////////////////////
void ds_netgraph_cancel(void *ptr) {
      struct ds_data *dsdata = (struct ds_data*)ptr;
      if(dsdata->ng_mesg) aFree(dsdata->ng_mesg);
      close(dsdata->socket);
      aFree(dsdata);
      aLog(D_INFO, "NETGRAPH flow processing cancelled\n");
}
/////////////////////////////////////////////////////////////////////////////////////
void ds_netgraph_stats(struct cli_def *cli, Service_DS *ds) {
      ng_netams_info *info = (ng_netams_info*)ds->pcap_data;
      cli_print(cli, "\tds_netgraph data messages: %llu", ng_total_flows);
      cli_print(cli, "\t%s mode=%u, pkt_rx=%u, pkt_tx=%u",
            ds->src_cmd, info->mode, info->packets_in, info->packets_out);
      if (info->mode==NG_NETAMS_MODE_TEE)
            cli_print(cli, "\tflows: active=%u, total=%u",
                  info->active_flows, info->total_flows);
      else if (info->mode==NG_NETAMS_MODE_DIVERT)
            cli_print(cli, "\tflows: active(now)=%u, queued(now)=%u, blocked(total)=%u, total=%u",
                  info->active_flows, info->queued_flows, info->blocked_flows, info->total_flows);
}
#endif
#endif
/////////////////////////////////////////////////////////////////////////////////////

Generated by  Doxygen 1.6.0   Back to index