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

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

#include "netams.h"

static int initialized=0;
//////////////////////////////////////////////////////////////////////////
int cSend         (struct cli_def *cli, const char *cmd, char **argv, int argc);
int cShowAlerter  (struct cli_def *cli, const char *cmd, char **argv, int argc);
void aReport(char **message, NetUnit *u, oid report_id, u_char is_recursive, u_char level=0);
//////////////////////////////////////////////////////////////////////////
//defined commands
static const  struct CMD_DB cmd_db[] = {
{ 2, 0, 0, "show",      PRIVILEGE_UNPRIVILEGED, MODE_EXEC, NULL,                "shows various system parameters" },
{ 0, 2, 0, "alerter",   PRIVILEGE_UNPRIVILEGED, MODE_EXEC, cShowAlerter,      "active aler actions"   },
{ 7, 0, 0, "send",      PRIVILEGE_UNPRIVILEGED, MODE_EXEC, NULL,        NULL },
{ 0, 7, 0, "report",    PRIVILEGE_UNPRIVILEGED, MODE_EXEC, cSend,       NULL },
{ 0, 7, 0, "command",   PRIVILEGE_UNPRIVILEGED, MODE_EXEC, cSend,       NULL },
{ 0, 0, 0, "report",    PRIVILEGE_UNPRIVILEGED, MODE_ALERTER, cServiceProcessCfg,   NULL },
{ 0, 0, 0, "smtp-server", PRIVILEGE_UNPRIVILEGED, MODE_ALERTER, cServiceProcessCfg, NULL },
{ 0, 0, 0, "sms-server", PRIVILEGE_UNPRIVILEGED, MODE_ALERTER, cServiceProcessCfg,  NULL },
{ 0, 0, 0, "pager-server", PRIVILEGE_UNPRIVILEGED, MODE_ALERTER, cServiceProcessCfg,      NULL },
{ 0, 0, 0, "start",     PRIVILEGE_UNPRIVILEGED, MODE_ALERTER, cServiceStart,            NULL },
{ 0, 0, 0, "stop",      PRIVILEGE_UNPRIVILEGED, MODE_ALERTER, cServiceStop,             NULL },
{ -1, 0, 0, NULL,  0, 0, NULL, NULL }
};
//////////////////////////////////////////////////////////////////////////
class Service_Alerter : public Service {
public:
      Service_Alerter();
      ~Service_Alerter();

      FIFO *queue;
      char *smtp_server;
      char *sms_server;
      char *pager_server;
      char *our_host_name;

      void ShowCfg(struct cli_def *cli, u_char flags);
      int ProcessCfg(struct cli_def *cli, char **argv, int argc, u_char no_flag);
      void ShowInfo(struct cli_def *cli);
      void Worker();
      int ProcessMessage(void *msg);

      int ProcessAlert(alert *al);
};
//////////////////////////////////////////////////////////////////////////
Service* InitAlerterService() {
        if(!initialized) {
                InitCliCommands(cmd_db);
                initialized = 1;
        }
        return (Service*)new Service_Alerter();
}
//////////////////////////////////////////////////////////////////////////
Service_Alerter::Service_Alerter(): Service(SERVICE_ALERTER) {
      queue=new FIFO(255);
      smtp_server=sms_server=pager_server=NULL;
      our_host_name=NULL;
}

Service_Alerter::~Service_Alerter(){
      if(smtp_server) aFree(smtp_server);
      if(sms_server) aFree(sms_server);
      if(pager_server) aFree(pager_server);
      aFree(our_host_name);
      delete queue;
}
//////////////////////////////////////////////////////////////////////////
int Service_Alerter::ProcessCfg(struct cli_def *cli, char **argv, int argc, u_char no_flag){
      if (STREQ(argv[0], "report")) {
            // we are not defining actual report here
            // builtin report with oid=06100
            cli_error(cli, "default report with oid=06100 created");
      }
      else if (STRARG(argv[0], "smtp-server")) {
            if (smtp_server) aFree(smtp_server);
            smtp_server=set_string(argv[1]);
            cli_error(cli, "smtp server name set to %s", smtp_server);
      }
      else if (STRARG(argv[0], "sms-server")) {
            if (sms_server) aFree(sms_server);
            sms_server=set_string(argv[1]);
            cli_error(cli, "sms server name set to %s", sms_server);
      }
      else if (STRARG(argv[0], "pager-server")) {
            if (pager_server) aFree(pager_server);
            pager_server=set_string(argv[1]);
            cli_error(cli, "pager server name set to %s", pager_server);
      }
      return CLI_OK;
}
//////////////////////////////////////////////////////////////////////////
void Service_Alerter::ShowCfg(struct cli_def *cli, u_char flags){
      cli_print(cli, "report oid 06100 name rep1 type traffic period day detail simple");
      if (smtp_server) cli_print(cli, "smtp-server %s", smtp_server);
      if (sms_server) cli_print(cli, "sms-server %s", sms_server);
      if (pager_server) cli_print(cli, "pager-server %s", pager_server);
}
//////////////////////////////////////////////////////////////////////////
int cShowAlerter(struct cli_def *cli, const char *cmd, char **argv, int argc){
        Service *s=NULL;
      while((s=Services->getServiceNextByType(SERVICE_ALERTER,s))) {
                  Service_Alerter *al=(Service_Alerter*)s;
            cli_print(cli, "service alerter %u",al->instance);
            cli_print(cli, "\tAlerter queue max: %u, current: %u",
                  al->queue->max_items, al->queue->num_items);
      }
      return CLI_OK;
}
//////////////////////////////////////////////////////////////////////////
void Service_Alerter::Worker(){
      Message *msg;
      alert *al;

      //determine our own IP in string
      our_host_name=(char*)aMalloc(256);
      if (gethostname(our_host_name, 256)!=0){
            aLog(D_WARN, "gethostname: %d (%s)\n", h_errno, strerror(h_errno));
            strcpy(our_host_name, "localhost");
      }
      aDebug(DEBUG_ALERT, "Our name address for outgoing SMTP will be %s\n", our_host_name);

      aLog(D_INFO, "service alerter:%u processing queue\n", instance);
      while (1) {
            while(queue->num_items > 0) {
                  msg=queue->TryPop();
                  if (msg->type==MSG_ALERT || msg->type==MSG_COMMAND)
                        al=(alert*)((Message_Alert*)msg)->al;
                  else {
                        aDebug(DEBUG_ALERT, "non-alert (%u) in alerter:%u queue\n", msg->type, instance);
                        continue;
                  }
                  aDebug(DEBUG_ALERT, "ALERT: id:%u, type: %u, rep_id %06X, user_id %06X, tryN: %u\n",
                        al->alert_id, al->type, al->report_id, al->user_id[0], al->tries);
                  if (!ProcessAlert(al)) {
                        aFree(al->data);
                        queue->Pop();
                  }
                  else {
                        al->tries++;
                        break;
                  }
            }
            Sleep(50); //sleep for 50 secs
      }
}
//////////////////////////////////////////////////////////////////////////
void Service_Alerter::ShowInfo(struct cli_def *cli) {
      cli_print(cli, "Alerter %u queue max: %u, current: %u",
            instance, queue->max_items, queue->num_items);
}
//////////////////////////////////////////////////////////////////////////
int cSend(struct cli_def *cli, const char *cmd, char **argv, int argc){
      Service_Alerter *s;

      if(!argc) return CLI_ERROR;

      // we looking for 1st alerter service and will use it
      // if we want ue specific alerter service we should rework parsing
      // in way  send alerter <num> ...
        s=(Service_Alerter*)Services->getServiceNextByType(SERVICE_ALERTER, NULL);
      if(!s) {
            cli_error(cli, "cannot send because alerter service is not running!\n");
            return CLI_OK;
      }

      Message *msg;
      alert *al;
      u_char i=2;
      char *command=NULL;

      msg = MsgMgr->New(MSG_ALERT);

      al=((Message_Alert*)msg)->al;
      al->sent=time(NULL);
      al->expired=al->sent+60*60; // one hour expire
      al->report_id=0x06100;
      al->tries=0;
      al->alert_id=s->queue->total_items+1;

      u_char uid_idx;
      for (uid_idx=0; uid_idx<MAX_ID_PER_ALERT; uid_idx++)
            al->user_id[uid_idx]=0;
      uid_idx=0;

      u_char nid_idx;
      for (nid_idx=0; nid_idx<MAX_ID_PER_ALERT; nid_idx++) {
            al->unit_id[nid_idx]=0;
            al->unit_id_recursive[nid_idx]=0;
      }
      nid_idx=0;

      if (STREQ(argv[1], "report")) {
            msg->type=MSG_ALERT;
            aDebug(DEBUG_ALERT, "constructing MAIL report %u\n", al->alert_id);
      }
      else if (STRARG(argv[1], "command")) {
            msg->type=MSG_COMMAND;
            aDebug(DEBUG_ALERT, "constructing MAIL command %u\n", al->alert_id);
            command=set_string(argv[2]);
            aDebug(DEBUG_ALERT, "executing command \"%s\"...\n", command);
            i=3;
      }

      for(; i<argc; i++) {
            if (STRARG(argv[i], "to")) {
                  User *u;
                  u=Users->getUser(argv[i+1]);
                  if (u) {
                        al->user_id[uid_idx]=u->id;
                        uid_idx++;
                        cli_error(cli, "user %s(%06X) added to MAIL msg as a recipient", u->name, u->id);
                  }
                  else {
                        cli_error(cli, "user %s not exist", argv[i+1]);
                  }
                  i++;
            }
            else if (STRARG(argv[i], "on")) {
                  NetUnit *u;
                  char *c_param; u_char j;
                  c_param=argv[i+1]; j=strlen(c_param);
                  if (c_param[j-1]=='+') { argv[i+1][j-1]='\0'; j=1; } else j=0;
                  u=Units->getUnit(argv[i+1]);
                  if (u) {
                        al->unit_id[nid_idx]=u->id;
                        al->unit_id_recursive[nid_idx]=j;
                        nid_idx++;
                        cli_error(cli, "unit %s(%06X)%s added to MAIL alert as a data", u->name, u->id, j?"+":"");
                  }
                  else {
                        cli_error(cli, "unit %s not exist", argv[i+1]);
                  }
                  i++;
            }
            else {
                  cli_error(cli, "SEND: parameter '%s' not understood\n", argv[i]);
            }
      } //while

      char *subject, *message, *buffer, time_buf[64];
      subject=message=buffer=NULL;

      timeU2T(time(NULL), time_buf);

      if (msg->type==MSG_ALERT){
            buffer = cExec("show health");
            print_to_string(&message, "This is automatically generated report by %s\r\nTime: %s\r\n%s",
                  SHOW_VERSION, time_buf, buffer);

            NetUnit *u;
            print_to_string(&subject, "Report %06X %s on [", al->report_id, time_buf);
            for (nid_idx=0; nid_idx<MAX_ID_PER_ALERT || !al->unit_id[nid_idx] ; nid_idx++) {
                  u=(NetUnit*)Units->getById(al->unit_id[nid_idx]);
                  if (!u) continue;
                  if (u->name)
                        print_to_string(&subject, " %s%s", u->name, al->unit_id_recursive[nid_idx]?"+":"");
                  else
                        print_to_string(&subject, " %06X%s", u->id, al->unit_id_recursive[nid_idx]?"+":"");
                  aReport(&message, u, al->report_id, al->unit_id_recursive[nid_idx], 0);
            }
            print_to_string(&subject, " ]");
      }
      else if (msg->type==MSG_COMMAND){
            buffer = cExec(command);
            print_to_string(&subject, "%s command \"%s\"", aaa_fw_software_name, command);
            print_to_string(&message, "This is processed command \"%s\" by %s\r\nTime: %s\r\n\r\n%s",
                  command, SHOW_VERSION, time_buf, buffer);
            if(command) aFree(command);
      }


      al->data=NULL;
      print_to_string(&al->data, "%s\r\n%s\r\n", subject, message);
      aFree(subject);
      aFree(message);
      aFree(buffer);

      cli_error(cli, "alert %u complete, data is %u bytes", al->alert_id, strlen(al->data));
      s->queue->Push((Message*)msg);
      s->Wakeup();

      return CLI_OK;
}
//////////////////////////////////////////////////////////////////////////
int Service_Alerter::ProcessAlert(alert *al){
      int sock, status;
      struct sockaddr_in addr;
      struct hostent *hp;
      FILE *fd;
      char buffer[4096];

      if ((sock=socket(AF_INET,SOCK_STREAM,0))==-1 ) {
            aLog(D_ERR, "creation of alerter socket failed: %d (%s)\n", sock, strerror(sock));
            return -1;
      }

      switch (al->type){
            case MAIL: {
                  // first we must check the validness of e-mail and report oid
                  if (!(al->report_id==0x06100 || al->report_id==0x06101)) {
                        aLog(D_WARN, "unable to process alert %u: report unknown\n", al->alert_id);
                        return -1;
                  }

                  if (smtp_server==NULL) {
                        aLog(D_WARN, "no SMTP server defined!\n");
                        return -1;
                  }
                  hp=gethostbyname(smtp_server);
                  if (hp==NULL) {
                        aLog(D_ERR, "gethostbyname: %d (%s)\n", h_errno, strerror(h_errno));
                        return -1;
                  }

                  bzero(&addr, sizeof(addr));
                  addr.sin_family=AF_INET;
                  addr.sin_port=htons((unsigned short)25);
                  memcpy((char*)&addr.sin_addr, hp->h_addr_list[0], hp->h_length);

                  status=connect(sock, (struct sockaddr*)&addr, sizeof(addr));
                  if (status==-1 ){
                        aLog(D_ERR, "connect of socket failed: %d, (%s)\nPossibly no SMTP servers there!\n%s\n", errno, strerror(errno), smtp_server);
                        return -1;
                  }

                  fd = fdopen(sock, "w+");
                  if (fd==NULL)
                        aLog(D_ERR, "fdopen of server socket() failed\n");

                  fgets(buffer, 4*1024, fd);
                  fprintf(fd, "HELO %s\r\n", our_host_name);
                  fgets(buffer, 4*1024, fd);

                  fprintf(fd, "MAIL FROM: netams@localhost\r\n");
                  fgets(buffer, 4*1024, fd);

                  unsigned num_rcpts=0;

                  if (al->unit_id[0] && al->report_id==0x06101) {
                        NetUnit *uu;
                        uu=(NetUnit*)Units->getById(al->unit_id[0]);
                        if (uu && uu->email) {
                              fprintf(fd, "RCPT TO: %s\r\n", uu->email);
                              aDebug(DEBUG_ALERT, "UNIT RCPT %u added: %s\n", num_rcpts+1, uu->email);
                              num_rcpts++;
                              fgets(buffer, 4*1024, fd);
                        }
                  }

                  if (al->user_id[0]) {
                        User *uu;
                        int j=0;
                        while (al->user_id[j]){
                              uu=(User*)Users->getById(al->user_id[j]);
                              if (uu && uu->email) {
                                    fprintf(fd, "RCPT TO: <%s>\r\n", uu->email);
                                    aDebug(DEBUG_ALERT, "USER RCPT %u added: %s\n", num_rcpts+1, uu->email);
                                    num_rcpts++;
                                    fgets(buffer, 4*1024, fd);
                              }
                              j++;
                        }
                  }

                  aDebug(DEBUG_ALERT, "RECIPIENTS DONE: total %u\n", num_rcpts);
                  if (num_rcpts==0) {
                        fprintf(fd, "QUIT\r\n");
                        fgets(buffer, 4*1024, fd);
                        aLog(D_WARN, "unable to process alert %u: no recipients found\n", al->alert_id);
                        return -1;
                  }

                  fprintf(fd, "DATA\r\n");
                  fgets(buffer, 4*1024, fd);

                  fprintf(fd, "From: %s daemon <root@%s>\r\nSubject: %s\r\n.\r\n", aaa_fw_software_name, our_host_name, al->data);
                  fgets(buffer, 4*1024, fd);

                  fprintf(fd, "QUIT\r\n");
                  fgets(buffer, 4*1024, fd);

                  fclose(fd);
                  aDebug(DEBUG_ALERT, "MAIL (alert %u) sent ok (tries %u, bytes %u, rcpts=%u)\n", al->alert_id,  al->tries, strlen(al->data), num_rcpts);
                  aLog(D_INFO, "MAIL (alert %u) sent ok (tries %u, bytes %u, rcpts=%u)\n", al->alert_id,  al->tries, strlen(al->data), num_rcpts);
                  break;
            }
            default:
                  return -1;
      } //switch

      shutdown(sock, SHUT_RDWR);
      close(sock);

      return 0;
}

int Service_Alerter::ProcessMessage(void *msg) {
      queue->Push((Message*)msg);
      Wakeup();
      return 1;
}
//////////////////////////////////////////////////////////////////////////
void aReport(char **message, NetUnit *u, oid report_id, u_char is_recursive, u_char level){

      if (!level || u->type==NETUNIT_GROUP) {
            print_to_string(message, "\r\nProcessing NetUnit oid %06X, name %s\r\n",
                  u->id, u->name?u->name:"<\?\?>");
            if(u->parents) {
                  NetUnit_group *gr;
                  print_to_string(message, "Parents %s", is_recursive?"recursive tree:":"");
                  ELIST_FOR_EACH(u->parents, gr) {
                        print_to_string(message, " %s", gr->name);
                  }
            }
            print_to_string(message, "%8s | %10s | %10s | %10s | %10s | %10s | %10s\r\n",
                  "TYPE", "NAME", "AC-POLICY", "DAY-IN", "DAY-OUT", "MON-IN", "MON-OUT");
      }

      if(u->ap) {
            policy_data *pd;
            unsigned is_nonzero_counters=0;

            netams_rwlock_rdlock(&u->ap->rwlock);
            for (pd=u->ap->root; pd!=NULL; pd=pd->next)
                  if (pd->d.in || pd->d.out || pd->m.in || pd->m.out)
                        is_nonzero_counters=1;

            for (pd=u->ap->root; is_nonzero_counters && pd!=NULL; pd=pd->next) {
                  print_to_string(message, " %8s | %10s | %10s | %10llu | %10llu | %10llu | %10llu\r\n",
                        netunit_type_name[u->type], u->name, pd->policy->name,
                        pd->d.in, pd->d.out, pd->m.in, pd->m.out);
            }
            netams_rwlock_unlock(&u->ap->rwlock);
      }

      if (is_recursive && u->type==NETUNIT_GROUP) {
            NetUnit_group *gr = (NetUnit_group*)u;
            ELIST_FOR_EACH(gr->childrens, u){
                  aReport(message, u, report_id, is_recursive, level+1);
            }
      }
}
//////////////////////////////////////////////////////////////////////////

Generated by  Doxygen 1.6.0   Back to index