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

s_acl_server.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: s_acl_server.c,v 1.32 2009-08-01 09:23:54 anton Exp $ */

#include "netams.h"

static int initialized=0;

#define S_ACLSERVER_DEF_delay 300
#define S_ACLSERVER_DEF_aclnumber 180
#define S_ACLSERVER_DEF_cmdport 514
//////////////////////////////////////////////////////////////////////////
unsigned long long sAclServer_ParseUptime(char *buffer);
/////////////////////////////////////////////////////////////////////////
//defined commands
static const  struct CMD_DB cmd_db[] = {
{ 0, 0, 0, "hostname",  PRIVILEGE_UNPRIVILEGED, MODE_ACL_SERVER, cServiceProcessCfg,      NULL },
{ 11, 0, 0, "direction", PRIVILEGE_UNPRIVILEGED, MODE_ACL_SERVER, NULL,             NULL },
{ 0, 11, 0, "src",      PRIVILEGE_UNPRIVILEGED, MODE_ACL_SERVER, cServiceProcessCfg,      NULL },
{ 0, 11, 0, "dst",      PRIVILEGE_UNPRIVILEGED, MODE_ACL_SERVER, cServiceProcessCfg,      NULL },
{ 0, 0, 0, "dynamic-name", PRIVILEGE_UNPRIVILEGED, MODE_ACL_SERVER, cServiceProcessCfg, NULL },
{ 0, 0, 0, "acl-number", PRIVILEGE_UNPRIVILEGED, MODE_ACL_SERVER, cServiceProcessCfg,     NULL },
{ 0, 0, 0, "delay",     PRIVILEGE_UNPRIVILEGED, MODE_ACL_SERVER, cServiceProcessCfg,      NULL },
{ 0, 0, 0, "set-uptime", PRIVILEGE_UNPRIVILEGED, MODE_ACL_SERVER, cServiceProcessCfg,   NULL },
{ 0, 0, 0, "start",     PRIVILEGE_UNPRIVILEGED, MODE_ACL_SERVER, cServiceStart,         NULL },
{ 0, 0, 0, "stop",      PRIVILEGE_UNPRIVILEGED, MODE_ACL_SERVER, cServiceStop,          NULL },
{ -1, 0, 0, NULL,  0, 0, NULL, NULL }
};
//////////////////////////////////////////////////////////////////////////
class Service_AclServer: public Service {
      public:        
            char *hostname;
            unsigned short port;
            unsigned short direction; // 0=SRC, 1=DST
            char *dynamic_name;
            unsigned short acl_number;
            unsigned short is_cisco;
            unsigned delay;
            unsigned long long uptime;
            FIFO *in;
            
            Service_AclServer();
            ~Service_AclServer();   
            
            void ShowCfg(struct cli_def *cli, u_char flags);
            int ProcessCfg(struct cli_def *cli, char **argv, int argc, u_char no_flag);
            void Worker();
            int ProcessMessage(void *ptr);

            int SendCommand(const char *tx, char *rx, int max_rx, FILE **fd, struct addrinfo *res);   
};
//////////////////////////////////////////////////////////////////////////
Service* InitAclServerService() {
      if(!initialized) {
            InitCliCommands(cmd_db);
            initialized = 1;
      }
      return (Service*)new Service_AclServer();
}
//////////////////////////////////////////////////////////////////////////
Service_AclServer::Service_AclServer(): Service(SERVICE_ACL_SERVER){
      hostname=set_string("localhost");
      port=S_ACLSERVER_DEF_cmdport;
      direction=0;
      dynamic_name=NULL;
      acl_number=S_ACLSERVER_DEF_aclnumber;
      is_cisco=0;
      delay=S_ACLSERVER_DEF_delay;
      uptime=0;
      in=new FIFO(MAX_UNITS);
}

Service_AclServer::~Service_AclServer(){
      if (dynamic_name) aFree(dynamic_name);
      delete in;
}
//////////////////////////////////////////////////////////////////////////
int Service_AclServer::ProcessCfg(struct cli_def *cli, char **argv, int argc, u_char no_flag){
      
      if (STRARG(argv[0], "hostname")) {
            if (hostname) aFree(hostname);
            hostname=set_string(argv[1]);
            cli_error(cli, "hostname is set to %s", hostname);
            if (argc>2) {
                  port=strtol(argv[2], NULL, 10);
                  cli_error(cli, "port is set to %u", port);
            }
      }
      else if (STRARG(argv[0], "direction")) {
            if (STREQ(argv[1], "src")) direction=0;
            else if (STREQ(argv[1], "dst")) direction=1;
            cli_error(cli, "acl direction is set to \'%s\'", direction?"dst":"src");
      }
      else if (STREQ(argv[0], "dynamic-name")) {
            if (argc>1) {
                  dynamic_name=set_string(argv[1]);
                  cli_error(cli, "dynamic acl name is set to %s", dynamic_name);
            }
            else {
                  dynamic_name=NULL;
                  cli_error(cli, "dynamic acl name cleared");
            }
      }
      else if (STREQ(argv[0], "acl-number")) {
            if (argc>1) {
                  acl_number=strtol(argv[1], NULL, 10);
                  if (STRARG(argv[2], "cisco"))is_cisco=1;
                  else is_cisco=0;
                  cli_error(cli, "acl number is set to %u, device type is %scisco",
                        acl_number, is_cisco?"":"non-");
            }
            else cli_error(cli, "cannot set acl number");
      }
       else if (STRARG(argv[0], "delay")) {
            delay=strtol(argv[1], NULL, 10);
            cli_error(cli, "acl check delay is set to %u", delay);
      }
       else if (STRARG(argv[0], "set-uptime")) {
            uptime=strtoll(argv[1], NULL, 10);
            cli_error(cli, "acl uptime forcibly set to %llu", uptime);
      }
      return CLI_OK;
}
//////////////////////////////////////////////////////////////////////////
void Service_AclServer::Worker(){
      struct addrinfo *res;
      struct addrinfo hints; 
      bzero(&hints, sizeof(hints));
      hints.ai_family = PF_UNSPEC;
      hints.ai_socktype = SOCK_STREAM;
      FILE *fd;
      char buffer_tx[256];
      char buffer_rx[4096];
      char ip_s[32];
      Message *msg;
      Message_AclServer *msgacl;
      unsigned msgs_proc, msgs_proc_ok;
      
      while(1) {
            Sleep(delay);

            uptime++;

            aDebug(DEBUG_ACLSERVER, "acl server checking every %u seconds\n", delay);
            
            sprintf(ip_s, "%u", port);
            int error=getaddrinfo(hostname, ip_s, &hints, &res);
            if (error) {
                  aDebug(DEBUG_ACLSERVER, "acl getaddrinfo error: %s \n", gai_strerror(error));
                  continue;
            }
            
            fd=NULL;
            if (SendCommand("show version | i uptime", buffer_rx, 1024*4, &fd, res)) {
                  continue;
            }

            unsigned long long c_uptime = sAclServer_ParseUptime(buffer_rx);
            aDebug(DEBUG_ACLSERVER, "known: %llu, remote uptime: %s %llu \n", uptime, buffer_rx, c_uptime);
            if (uptime  > c_uptime + delay || uptime==1) {
                  // 1.1. flush old list of rules
                  // 1.2. install the new list for ALL units with !sys-allow

                  netams_rwlock_rdlock(&Units->rwlock);
                  for (NetUnit *u=(NetUnit*)Units->root; u!=NULL; u=(NetUnit*)u->next) {
                        ProcessMessage(u);
                  }
                  netams_rwlock_unlock(&Units->rwlock);
            }
            uptime=c_uptime+1;

            // 2. check the input queue
            msgs_proc=msgs_proc_ok=0;
            while((msg=in->TryPop())) {
                  if (msg->type==MSG_ACLSERVER) {
                        msgacl=(Message_AclServer*)msg;
                        inet_ntop(AF_INET, &(msgacl->ip), ip_s, 32);
                        aDebug(DEBUG_ACLSERVER, "message ip=%s action=%s\n", ip_s, msgacl->flag?"ADD":"REMOVE");
                        // 2.1. send the request 
                        if (msgacl->flag) { // add
                              if (direction) { // add-dst
                                    //access-template alc-num dyn-acl-name any host XXX 
                                    snprintf(buffer_tx, 256, "access-template %u %s any host %s\n", acl_number, dynamic_name?dynamic_name:"", ip_s);
                              } else { // add-src
                                    //access-template alc-num dyn-acl-name any host XXX 
                                    snprintf(buffer_tx, 256, "access-template %u %s host %s any\n", acl_number, dynamic_name?dynamic_name:"", ip_s);
                              }
                        } 
                        else { //remove
                              if (direction) { // remove-dst
                                    //access-template alc-num dyn-acl-name any host XXX 
                                    snprintf(buffer_tx, 256, "clear access-template %u %s any host %s\n", acl_number, dynamic_name?dynamic_name:"", ip_s);
                              } else { // remove-src
                                    //access-template alc-num dyn-acl-name any host XXX 
                                    snprintf(buffer_tx, 256, "clear access-template %u %s host %s any\n", acl_number, dynamic_name?dynamic_name:"", ip_s);
                              }
                        }// remove
                        msgs_proc++;
                        if (SendCommand(buffer_tx, buffer_rx, 1024*4, &fd, res)) {
                              aDebug(DEBUG_ACLSERVER, "acl command \"%s\" failed \n", buffer_tx);
                        } else msgs_proc_ok++;
                  } else {
                        aDebug(DEBUG_ACLSERVER, "message type %u not ACLSERVER - discarded\n", msg->type);
                  }
                  msg=in->Pop();
            }           
            
            // 99. close and clean
            if (fd) {
                  shutdown(fileno(fd), SHUT_RDWR);
                  fclose(fd);
            }           
            freeaddrinfo(res); 
            aDebug(DEBUG_ACLSERVER, "messages processed: %u, failed: %u\n", msgs_proc, msgs_proc-msgs_proc_ok);
      }
}

//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
void Service_AclServer::ShowCfg(struct cli_def *cli, u_char flags){
      if (port!=S_ACLSERVER_DEF_cmdport) cli_print(cli, "hostname %s %u", hostname, port);
      else cli_print(cli, "hostname %s", hostname);
      cli_print(cli, "direction %s", direction?"dst":"src");
      if (dynamic_name) cli_print(cli, "dynamic-name %s", dynamic_name);
      cli_print(cli, "acl-number %u %s", acl_number, is_cisco?"cisco":"");
      if (delay!=S_ACLSERVER_DEF_delay) cli_print(cli, "delay %u", delay);
}
//////////////////////////////////////////////////////////////////////////
unsigned long long sAclServer_ParseUptime(char *buffer){
      /* What we can receive in the buffer:
       * 
       * dl-www:~#rsh 223.313.57.30 "show version | i uptime"
       * cisco-rtr uptime is 1 week, 2 days, 9 hours, 39 minutes
       * 
       * i.e. we can get from 1 to 5 numbers here, years to minutes
       * 
       */
       char *p = strchr(buffer, ' ');
       if (p) buffer=p+1; else return 0L;
       unsigned int value[5]; 
       int i;
       unsigned long long ret;
       for (i=0; i<5; i++) value[i]=0;
       for (i=0; buffer[i]!=0; i++) if (!isdigit(buffer[i])) buffer[i]=' '; // wipe all but numbers 
       i=sscanf(buffer, "%u%u%u%u%u", &value[0],&value[1],&value[2],&value[3],&value[4]);
       if (value[0]+value[1]+value[2]+value[3]+value[4]==0) return 0L;
       //printf("\t1(%u)\t", i); for (int k=0; k<5; k++) printf("%u ", value[k]); printf("\n");
       memmove(&value[5-i], value, sizeof(unsigned int)*(i)); bzero(value, sizeof(unsigned int)*(5-i));
       //printf("\t2\t"); for (int k=0; k<5; k++) printf("%u ", value[k]); printf("\n");
       ret=value[0]*365*24*60*60 + value[1]*7*24*60*60 + value[2]*24*60*60 + value[3]*60*60 + value[4]*60;
       return ret;
}
//////////////////////////////////////////////////////////////////////////
int Service_AclServer::SendCommand(const char *tx, char *rx, int max_rx, FILE **fd, struct addrinfo *res){
    int sock, lport;
      
      if (*fd == NULL) { // reopen connection

            sock=rresvport(&lport);
            if (sock==-1) {
                  aDebug(DEBUG_ACLSERVER, "acl socket src bind to privileged port failed: %s \n", strerror(errno));
                  return -1;
            }

            if (connect(sock, res->ai_addr, res->ai_addrlen) < 0) {
                  aDebug(DEBUG_ACLSERVER, "acl connect error: %s \n", strerror(errno));
                  return -2;
            }

            *fd = fdopen(sock, "w+");
            if (fd==NULL) {
                  aDebug(DEBUG_ACLSERVER, "acl fdopen error: %s \n", strerror(errno));
                  return -3;
            }
      }
                  
      // processing starts here
      // 0. send the protocol-specific junk
      fputc('0', *fd); fputc(0, *fd); fflush(*fd);
      fprintf(*fd, "root"); fputc(0, *fd); fprintf(*fd, "netams"); fputc(0, *fd);
      
      // 1. get the uptime
      fprintf(*fd, "%s", tx); fputc(0, *fd);
      fflush(*fd);
      fgetc(*fd);
      fgets(rx, max_rx, *fd);
      
      if (is_cisco) {
            shutdown(fileno(*fd), SHUT_RDWR);
            fclose(*fd);
            *fd = NULL;
      }
      return 0;
}
//////////////////////////////////////////////////////////////////////////
int Service_AclServer::ProcessMessage(void *ptr) {
      NetUnit *u = (NetUnit*)ptr;
      struct in_addr addr;
      addr.s_addr = INADDR_ANY;
      
      if (u->type==NETUNIT_HOST || u->type==NETUNIT_USER) {
            switch(u->type) {
                  case NETUNIT_HOST:
                        addr.s_addr = ((NetUnit_host*)u)->ip.s_addr;
                        break;
                  case NETUNIT_USER:
                        addr.s_addr = ((NetUnit_user*)u)->ip.s_addr;
                        break;
                  default:
                        break;                                     
            }
            if (addr.s_addr!=INADDR_ANY) {
                  Message_AclServer *msg = (Message_AclServer*)MsgMgr->New(MSG_ACLSERVER);
                  msg->flag = u->sys_policy?ADD:REMOVE;
                  msg->ip.s_addr = addr.s_addr;
                  in->Push(msg);
                  aDebug(DEBUG_ACLSERVER, "queue u=%06X flag=%u sp_now=%u\n", u->id, msg->flag, u->sys_policy);
                  return 1;
            } 
      }
      return 0;
}
//////////////////////////////////////////////////////////////////////////

Generated by  Doxygen 1.6.0   Back to index