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

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

#include "netams.h"

const char *policy_type_name[POLICY_TYPES_NUM]={ "unknown", "acct", "fw" };

const char pstat_prefix[5] = { 'F', 'H', 'D', 'W', 'M' };

PolicyList *PolicyL;

time_t fw_check_changed;
/////////////////////////////////////////////////////////////////////////
u_char IsNetCheckBroken(NetUnit *u, Policy *p); //1-broken, 0-not
/////////////////////////////////////////////////////////////////////////
// Policy class
Policy::Policy():Object() {
      name=NULL;
      bwi=NULL;
      hidden=0;
      
      bzero(&target, sizeof(policy_target));
      target.target_type=PT_UNKNOWN;
      target.check_type=PC_UNKNOWN;
      
      target.unit=NULL; target.unit_id=0; target.unit_name=NULL;
      
      target.ports.num=0;
      target.num_addrs=0;
      target.ifs.num=0;
      target.ases.num=0;
      target.num_dses=0;
      target.num_vlans=0;

      target.file=NULL;
      
      target.proto=PROTO_ANY; //set default to ANY
      
      target.t_begin=target.t_end=0;
      
      for (u_char i=0; i<7; i++) target.day_allowed[i]=1; // allow every day
      target.day_d1=target.day_d2=-1;
      
      target.num_policies=0;
      target.logic=PL_OR; 

      target.direction=0;
}

Policy::~Policy() {
      if(bwi) aFree(bwi);
      if(name) aFree(name);
//do not unmark target.unit because it can be marked by another policy also
//    if (target.check_type&PC_UNIT && target.unit) target.unit->flags&=~NETUNIT_POLICY_TARGET;
      if (target.check_type&PC_FILE)  delete target.file;
}

void Policy::setName(char *n){
      if (name) aFree(name);
      name=set_string(n);
}

#define TARGET(type, check) {       \
      target.target_type|=type;     \
      target.check_type|=check;     \
}

#define NO_TARGET(tgt) {            \
      if(no_flag) {                 \
            target.check_type&=~tgt;\
            break;                  \
      }                       \
}

u_char Policy::setTarget(struct cli_def *cli, char **tgt, u_char *i, u_char no_flag){
      while(tgt[*i+1]) {
            (*i)++;
            if (STRNARG(tgt[*i], "proto", 5)) {
                  (*i)+=1;
                  NO_TARGET(PC_IP_PROTO);
                  
                  if(STRNEQ(tgt[*i], "any", 3)) {
                        target.proto=PROTO_ANY;
                        target.check_type&=~PC_IP_PROTO;
                        continue; //unregister proto check if we want all
                  }

                  struct protoent *proto;
                  proto=getprotobyname(tgt[*i]);
                  if(!proto) {
                        u_short p=strtol(tgt[*i], NULL, 10);
                        proto=getprotobynumber(p);
                        if(!proto) return 0;
                  }
                  target.proto=proto->p_proto;
                  TARGET(PT_IP_TRAFFIC, PC_IP_PROTO);
            }
            else if (STRNARG(tgt[*i], "tos", 3)) {
                  NO_TARGET(PC_IP_TOS);
                  
                  target.ip_tos=strtol(tgt[*i+1], NULL, 10);
                  (*i)+=1;
                  TARGET(PT_IP_TRAFFIC, PC_IP_TOS);
            }
            else if (STRNARG(tgt[*i], "time", 4)) { // "target time 9-18" or "target time 00:40-21:30"   
                  NO_TARGET(PC_TIME);

                  char *p = strchr(tgt[*i+1], '-'); if (!p) { (*i)+=1; continue;} 
                  char *s1 = strchr(tgt[*i+1], ':'); if (s1>p) s1=NULL;
                  char *s2 = strchr(p, ':');                
                  int beg_h, beg_m=0, end_h, end_m=0;
                  sscanf(tgt[*i+1], "%u", &beg_h);
                  if (s1) sscanf(s1+1, "%u", &beg_m);
                  sscanf(p+1, "%u", &end_h);
                  if (s2) sscanf(s2+1, "%u", &end_m);
                  target.t_begin=beg_h*60+beg_m;
                  target.t_end=end_h*60+end_m;
                  (*i)+=1;
                  TARGET(PT_IP_TRAFFIC, PC_TIME);
            }
            else if (STRNARG(tgt[*i], "day", 3)) { // "target day Mon-Fri" or "target day Sun"   
                  NO_TARGET(PC_DAYOFWEEK);

                  char *p = strchr(tgt[*i+1], '-'); 
                  int d2,d1=getdayofweek(tgt[*i+1]);
                  if (p) d2=getdayofweek(p+1); else d2=d1;
                  if (d1!=-1 && d2!=-1) {
                        if (d1<=d2) 
                              for (u_char k=0; k<7; k++) 
                                    if (k>=d1 && k<=d2) target.day_allowed[k]=1; 
                                    else target.day_allowed[k]=0;
                        else 
                              for (int k=0; k<7; k++)
                                    if (k<d1 && k>d2) target.day_allowed[k]=0;
                                    else target.day_allowed[k]=1;
                        
                        target.day_d1=d1; 
                        target.day_d2=d2;
                  }
                  (*i)+=1;
                  TARGET(PT_IP_TRAFFIC, PC_DAYOFWEEK);
            }
            else if (STRNEQ("addr", tgt[*i], 4)) {
                  NO_TARGET(PC_IP_ADDR);

                  u_char j=0;
                  
                  while (tgt[j+*i+1] && j<PC_MAX_ADDRS) {
                        if(!isdigit(tgt[j+*i+1][0])) break;

                        getAddr(tgt[j+*i+1], &target.addr[j], &target.addr_mask[j]);
                        if(STRNARG(tgt[j+*i+2], "mask", 4)) {
                              inet_aton(tgt[j+*i+3], &target.addr_mask[j]);
                              (*i)+=2;
                        } else if (target.addr_mask[j].s_addr==INADDR_ANY)
                              target.addr_mask[j].s_addr=HOST_MASK;
                        
                        target.addr[j].s_addr&=target.addr_mask[j].s_addr;
                        j++;
                  }
                  target.num_addrs=j;
                  (*i)+=j;
                  if(j) TARGET(PT_IP_TRAFFIC, PC_IP_ADDR);     
            }
            else if (STRNEQ(tgt[*i], "port", 4)) {    // target ports s25 22 d24... proto defined before
                  NO_TARGET(PC_IP_PORTS);

                  if(target.proto!=IPPROTO_TCP && target.proto!=IPPROTO_UDP) {
                        struct protoent *proto;
                        proto = getprotobynumber(target.proto);
                        cli_error(cli, "ports undefined for this proto %s", proto?proto->p_name:"");
                        continue;
                  }
                  
                  u_char num = target.ports.SetPolicy(&tgt[*i+1]);
                  (*i)+=num;
                  if(num) TARGET(PT_IP_TRAFFIC, PC_IP_PORTS);
            }
            else if (STRNEQ(tgt[*i], "as", 2)) {      // target ases s8342 2485 d30910...
                  NO_TARGET(PC_AS_NUMBER);

                  u_char num = target.ases.SetPolicy(&tgt[*i+1]);
                  (*i)+=num;
                  if(num) TARGET(PT_NETFLOW_TRAFFIC, PC_AS_NUMBER);
            }
            else if (STRNEQ(tgt[*i], "ds", 2)) {  // target 0 1 2 3 ... 256
                  NO_TARGET(PC_DS_NUMBER);
                  
                  u_char j=0;
                  char *ptr;
                  u_char value;

                        while (tgt[j+*i+1] && j<PC_MAX_DSES) {
                        ptr=tgt[j+*i+1];
                        
                        value=strtol(ptr, NULL, 10);
                        if(value==0 && ptr[0]!='0') break;
                        
                        target.dses[j]=value;
                        
                        j++;
                  }
                  if(STREQ(tgt[j+*i+1],"all") || STREQ(tgt[j+*i+1],"*"))
                        target.num_dses=0;
                  else 
                        target.num_dses=j;
                  (*i)+=j;
                  if(j) TARGET(PT_IP_TRAFFIC, PC_DS_NUMBER);
            }
            else if (STRNEQ(tgt[*i], "vlan", 4)) {  // target 0 1 2 3 ... 1024
                  NO_TARGET(PC_VLAN_NUMBER);
                  
                  u_char j=0;
                  char *ptr;
                  u_char value;

                  while (tgt[j+*i+1] && j<PC_MAX_VLANS){
                        ptr=tgt[j+*i+1]; 
                        
                        value=strtol(ptr, NULL, 10);
                        if(value==0) break;

                        target.vlans[j]=DOT1X_GET_VLAN(value); //with autocorrection to vlan
                        j++;
                  }
                  target.num_vlans=j;
                  (*i)+=j;
                  if(j) TARGET(PT_IP_TRAFFIC, PC_VLAN_NUMBER);
            }
            else if (STRNARG(tgt[*i], "unit", 4)) {   // syntax is follows: target units {oid 12345|name AAAA}
                  NO_TARGET(PC_UNIT);

                  if (STRARG("oid", tgt[*i+1])) {
                        target.unit_id=strtol(tgt[*i+2], NULL, 16);
                  }
                  else if (STRARG("name", tgt[*i+1])) {
                        target.unit_name=set_string(tgt[*i+2]);
                  }
                  else continue;
                  (*i)+=2;
                  TARGET(PT_IP_TRAFFIC, PC_UNIT);
            }
            else if (STRNARG(tgt[*i], "file", 4)) {
                  NO_TARGET(PC_FILE);
                  if(no_flag && target.file) delete target.file;  //special case

                  target.file = new PrefixFile();
                  if(target.file->Load(tgt[*i+1])>=0) {
                        TARGET(PT_IP_TRAFFIC, PC_FILE);
                  }
                  (*i)+=1;
            }
            //it's unclear for me how this should work
            else if (STRNEQ(tgt[*i], "ifindex", 7)) {   // target if s10 8 d7
                  NO_TARGET(PC_IFINDEX);

                  u_char num = target.ifs.SetPolicy(&tgt[*i+1]);
                        (*i)+=num;
                  TARGET(PT_NETFLOW_TRAFFIC, PC_IFINDEX);
            }
            else if (STRNEQ(tgt[*i], "ingress", 8) || STRNEQ(tgt[*i], "egress", 7)) {
                  if(no_flag) {
                        NO_TARGET(PC_FLOW_DIRECTION);
                        break;
                  }
                  target.direction=STRNEQ(tgt[*i], "egress", 7)?1:0;
                  TARGET(PT_NETFLOW_TRAFFIC, PC_FLOW_DIRECTION);
            }
            else if (STRNEQ(tgt[*i], "layer7-detect", 13)) {   
                  if(no_flag) 
                        target.target_type&=~PT_LAYER7;
                  else 
                        TARGET(PT_LAYER7, PC_UNKNOWN);
            }
            else if (STRNEQ(tgt[*i], "policy", 6)) {
                  if(no_flag) {
                        target.target_type&=~PT_POLICY;     
                        break;
                  }     

                  if (STRNEQ(tgt[*i]+6, "-and", 4))   target.logic=PL_AND;
                  else if (STRNEQ(tgt[*i]+6, "-or", 3))     target.logic=PL_OR;
                  else cli_error(cli, "Unknown policy logic: %s (continue with OR)", tgt[*i]);
                  
                  u_char j=0;
                  Policy *p;
                  char *str;
                  u_char inversion;
                  
                  while (tgt[j+*i+1] && j<PC_MAX_POLICIES) {
                        str=tgt[j+*i+1];
                        if(str[0]=='!') {
                              inversion=1;
                              str++;
                        }
                        else inversion=0;

                        p = PolicyL->getPolicy(str);
                        if (p==NULL) p = (Policy*)PolicyL->getById(strtol(str, NULL, 16));
                        if (p==NULL) break;
                        target.list[j]=p;
                        target.inversion[j]=inversion;
                        j++;
                  }
                  target.num_policies=j;                    
                  (*i)+=j;
                  if(j) TARGET(PT_POLICY, PC_UNKNOWN);
            }
            else if (STREQ(tgt[*i], "bw")) {
                  (*i)-=2;
                  break;
                  //this is next command
            }
            else 
                  cli_error(cli, "Wrong target command: %s", tgt[*i]);
      }
      return 1;
}

void Policy::getTarget(struct cli_def *cli){
      if(target.target_type&PT_IP_TRAFFIC) {
            if(target.check_type&PC_IP_PROTO) {
                  struct protoent *proto;
                  proto=getprotobynumber(target.proto);
                  if(proto) cli_bufprint(cli, " proto %s", proto->p_name);
                  else cli_bufprint(cli, " proto %u", target.proto);
            }
            if (target.check_type&PC_IP_TOS) {
                  cli_bufprint(cli, " tos %u", target.ip_tos);
            }
            if (target.check_type&PC_TIME) {
                  int beg_h, beg_m, end_h, end_m;
                  beg_h=target.t_begin/60; beg_m=target.t_begin%60; end_h=target.t_end/60; end_m=target.t_end%60;  
                  cli_bufprint(cli, " time %02d:%02d-%02d:%02d", beg_h,beg_m,end_h,end_m);
            }
            if (target.check_type&PC_DAYOFWEEK && target.day_d1!=-1 && target.day_d2!=-1) {
                  if (target.day_d1==target.day_d2) cli_bufprint(cli, " day %s", daysofweek[target.day_d1]);
                  else cli_bufprint(cli, " day %s-%s", daysofweek[target.day_d1], daysofweek[target.day_d2]);
            }
            if (target.check_type&PC_IP_ADDR) {
                  if(target.num_addrs) cli_bufprint(cli, " addr");
                  for (u_char i=0; i<target.num_addrs; i++) {
                        char buffer[32];
                        cli_bufprint(cli, " %s", inet_ntop(AF_INET, &(target.addr[i]), buffer, 32));
                        if(target.addr_mask[i].s_addr!=HOST_MASK) 
                              cli_bufprint(cli, "/%u", MASK2MLEN(target.addr_mask[i]));
                  }
            }
            if(target.check_type&PC_IP_PORTS) {
                  if(target.ports.num) {
                        cli_bufprint(cli, " port");
                        target.ports.GetPolicy(cli);  
                  } 
            }
            if (target.check_type&PC_UNIT) {
                  if(!target.unit_id) {
                        NetUnit *u;
                        if(!(target.unit_name && (u=Units->getUnit(target.unit_name)))) {
                              cli_bufprint(cli, " units name %s",target.unit_name);
                              goto SHOW_PC_FILE;
                        }
                        target.unit_id=u->id;
                  }
                  cli_bufprint(cli, " units oid %06X",target.unit_id);
            }
SHOW_PC_FILE:
            if (target.check_type&PC_FILE) {    
                  if(target.file) cli_bufprint(cli, " file %s", target.file->filename);
            }
      }
      if(target.target_type&PT_NETFLOW_TRAFFIC) {
            if(target.check_type&PC_IFINDEX) {
                  if(target.ifs.num) {
                        cli_bufprint(cli, " ifindex");
                        target.ifs.GetPolicy(cli);
                  }
            }
            if(target.check_type&PC_AS_NUMBER) {
                  if(target.ases.num) {
                        cli_bufprint(cli, " as");
                        target.ases.GetPolicy(cli);
                  }
            }
            if(target.check_type&PC_FLOW_DIRECTION) {
                  cli_bufprint(cli, " %s", target.direction?"egress":"ingress");
            }
      }

      if(target.target_type&PT_LAYER7) {
            cli_bufprint(cli, " layer7-detect");
            }

      if(target.target_type&PT_POLICY) {
            cli_bufprint(cli, " policy-%s", target.logic?"and":"or");
            for (u_char i=0; i<target.num_policies; i++) {
                  if (target.list[i]->name)
                        cli_bufprint(cli, " %s%s", target.inversion[i]?"!":"", target.list[i]->name);
                  else
                        cli_bufprint(cli, " %s%06X", target.inversion[i]?"!":"", target.list[i]->id);
            }
      }

      //DSES
      if(target.check_type&PC_DS_NUMBER) {
            if(target.num_dses) {
                  cli_bufprint(cli, " ds");
                  for(u_char i=0; i<target.num_dses; i++ )
                        cli_bufprint(cli, " %u", target.dses[i]);
            }
      }
      //VLANS
      if(target.check_type&PC_VLAN_NUMBER) {
            if(target.num_vlans) {
                  cli_bufprint(cli, " vlan");
                  for(u_char i=0; i<target.num_vlans; i++ )
                        cli_bufprint(cli, " %u", target.vlans[i]);
            }
      }
}

u_char Policy::Check(Flow *list, match mf){
      u_char res=1;
      struct flow_info_value  *flow_info  = (struct flow_info_value*)list->get(ATTR_FLOW_INFO);

      #ifdef DEBUG
            if(aDebug(DEBUG_POLICY, "Policy %s check on flow %p:\n", name, list)) {
                  list->Debug(DEBUG_POLICY);
            }
      #endif
      
      if(target.target_type & PT_IP_TRAFFIC) {
            struct ipv4_info_value  *ipv4_info  = (struct ipv4_info_value*)list->get(ATTR_IPV4_INFO);       
            
            if(ipv4_info == NULL) {
                  //how me managed to get into this?
                  aLog(D_WARN, "No IPv4 attribute in Policy::Check\n");
                  return 0;
            }
            if(target.check_type&PC_IP_PROTO) {
                  if(target.proto && target.proto!=ipv4_info->ip_p) return 0;
            }
            
            if(target.check_type&PC_IP_PORTS) {
                  const union attribute_value   *tcp_value = list->get(ATTR_TCP_INFO);

                  if(tcp_value == NULL)
                        return 0;

                  if(!target.ports.CheckPolicy(tcp_value->tcp_info.src_port, tcp_value->tcp_info.dst_port)) return 0;
            }
            
            if(target.check_type&PC_IP_TOS) {
                  if(target.ip_tos!=ipv4_info->ip_tos) return 0;
            }
            
            if(target.check_type&PC_TIME) {
                  struct tm tm;
                  time_t t=flow_info->flow_first;
                  localtime_r(&t, &tm);
                  int flow_t = tm.tm_hour*60+tm.tm_min;
                  if (target.t_begin<target.t_end) {
                        if (flow_t<target.t_begin || target.t_end<flow_t) return 0;
                  } else
                        if (flow_t<target.t_begin && target.t_end<flow_t) return 0;
            }

            if(target.check_type&PC_DAYOFWEEK) {
                  struct tm tm;
                  time_t t=flow_info->flow_first;
                  localtime_r(&t, &tm);
                  int flow_dw = tm.tm_wday-1; if (flow_dw==-1) flow_dw=6;
                  if (target.day_allowed[flow_dw]==0) return 0;
            }

            if(target.check_type&PC_IP_ADDR) {
                  
                  if(mf&MATCH_SRC) 
                        for (u_char i=0; i<target.num_addrs; i++) 
                              if(target.addr[i].s_addr==(ipv4_info->ip_dst.s_addr&target.addr_mask[i].s_addr))
                                    goto CHECK_PC_UNIT;
      
                  if(mf&MATCH_DST)
                        for (u_char i=0; i<target.num_addrs; i++)
                              if(target.addr[i].s_addr==(ipv4_info->ip_src.s_addr&target.addr_mask[i].s_addr))
                                    goto CHECK_PC_UNIT;
                  return 0;
            }
CHECK_PC_UNIT:
            if (target.check_type&PC_UNIT) {
                  if (target.unit_id || target.unit_name) {
                        NetUnit *u=NULL;
                        
                        if (target.unit) u=target.unit;
                        else if (target.unit_id) {
                              if(!(u=(NetUnit*)Units->getById(target.unit_id))) {
                                    aDebug(DEBUG_POLICY, "IP 'units' policy %s but target unit not exist,skip this check\n", name);
                                    goto CHECK_PC_FILE;
                              }
                              target.unit=u;
                              u->flags|=NETUNIT_POLICY_TARGET;
                        }
                        else if (target.unit_name) {
                              if(!(u=Units->getUnit(target.unit_name))) {
                                    aDebug(DEBUG_POLICY, "IP 'units' policy %s but target unit not exist,skip this check\n", name);
                                    goto CHECK_PC_FILE;
                              }
                              target.unit=u;
                              u->flags|=NETUNIT_POLICY_TARGET;
                        }
                        
                        if(!u) return 0;

                        //this check if another point of connection is target unit
                        match utmf=u->Check(ipv4_info->ip_src, ipv4_info->ip_dst);
                        if(utmf==MATCH_NONE || ((mf|utmf)!=MATCH_BOTH)) return 0;
                  }
            }
CHECK_PC_FILE: 
            if (target.check_type&PC_FILE) {
                  if (target.file->list==NULL) {
                        aDebug(DEBUG_POLICY, "prefix check but file is not loaded, skiping this check\n"); 
                        goto CHECK_PT_NETFLOW;
                  }

                  if(mf&MATCH_SRC && target.file->Check(ipv4_info->ip_dst.s_addr)) 
                        goto CHECK_PT_NETFLOW;
                  
                  if(mf&MATCH_DST && target.file->Check(ipv4_info->ip_src.s_addr))
                        goto CHECK_PT_NETFLOW;
                  
                  return 0;
            }
      } //PT_IP_TRAFFIC 

CHECK_PT_NETFLOW:
      
      if(target.target_type&PT_NETFLOW_TRAFFIC) {
            if(target.check_type&PC_IFINDEX) {
                  const union attribute_value   *ifindex_value = list->get(ATTR_IFINDEX_INFO);

                  if(ifindex_value == NULL)
                        return 0;

                  if(!target.ifs.CheckPolicy(ifindex_value->ifindex_info.if_in, ifindex_value->ifindex_info.if_out)) return 0;
            }
            if(target.check_type&PC_AS_NUMBER) {
                  const union attribute_value   *as_value = list->get(ATTR_AS_INFO);

                  if(as_value == NULL)
                        return 0;

                  if(!target.ases.CheckPolicy(as_value->as_info.as_src, as_value->as_info.as_dst)) return 0;
            }
            if(target.check_type&PC_FLOW_DIRECTION) {
                  if(flow_info->direction!=target.direction)
                        return 0;
            }
      } //PT_NETFLOW_TRAFFIC

      if(target.target_type & PT_POLICY) {
            res=0;
            for (u_char i=0; i<target.num_policies; i++) {
                  res=target.list[i]->Check(list, mf);
                  if(target.inversion[i]) res=(res?0:1);
                  
                  if (target.logic^res) break;
            }
            if(!res) return 0;
      }

      if(target.check_type & PC_DS_NUMBER) {
            res=0;
            for(u_char i=0; i<target.num_dses; i++) {
                  if(list->ds_id == target.dses[i]) {
                        res=1;
                        break;
                  }
            }
            if(!res) return 0;
      }

      if(target.check_type & PC_VLAN_NUMBER) {
            const union attribute_value   *vlan_value = list->get(ATTR_VLAN_INFO);
            
            if(vlan_value == NULL)
                  return 0;

            res=0;
            for(u_char i=0; i<target.num_vlans; i++) {
                  //not so beauty but not clear yet what to do with others fields - PRI and CFI
                  if(DOT1X_GET_VLAN(ntohs(vlan_value->vlan_info.dot1x)) == target.vlans[i]) {
                        res=1;
                        break;
                  }
            }
            if(!res) return 0;
      }

      if(target.target_type&PT_LAYER7) {
            return 1;
      }
      
      // BW always matches
      if (bwi) res=1;
      
      //if there is no successfull checks - result will be 0
      aDebug(DEBUG_POLICY, "%s(%06X) matched with res=%d\n", name, id, res);
      return res;
}

template <int max_items>
u_char policy_target_array<max_items>::SetPolicy(char **tgt) {
      u_char j=0;
      u_short val;
      u_short max_val;
      char *maxptr;
      char *ptr;
      
      while(tgt[j] && j<max_items) {
            if (tgt[j][0]=='s' || tgt[j][0]=='d' || tgt[j][0]=='b')
                  ptr=tgt[j]+1;
            else
                  ptr=tgt[j];

            maxptr = strchr(ptr, ':');
            if (!maxptr) maxptr = strchr(ptr, '-');
            
            val=strtol(ptr, NULL, 10);
            if(val==0 && ptr[0]!='0') break;

            if (maxptr) {
                max_val = strtol(maxptr+1, NULL, 10);
                if (val>max_val) max_val = 0;
            } else max_val = 0;
            max[j] = htons(max_val);
            value[j] = htons(val);


            switch (tgt[j][0]) {
                  case 's':
                        mf[j]=MATCH_SRC;
                        break;
                  case 'd':
                        mf[j]=MATCH_DST;
                        break;
                  default:
                        mf[j]=MATCH_BOTH;
                        break;
            }
            j++;
      }
      
      num = j;
      return j;
}

template <int max_items>
void policy_target_array<max_items>::GetPolicy(struct cli_def *cli) {
      char prefix[2];
    
      prefix[1]=0;
      for (u_char i=0; i<num; i++) {
            if (mf[i]==MATCH_BOTH) prefix[0] = 0;
            else if (mf[i]==MATCH_SRC) prefix[0] = 's';
            else if (mf[i]==MATCH_DST) prefix[0] = 'd';
            else continue;
            
            if (max[i])
                cli_bufprint(cli, " %s%u:%u", prefix, ntohs(value[i]), ntohs(max[i]));
            else
                cli_bufprint(cli, " %s%u", prefix, ntohs(value[i]));
      }
}

template <int max_items>
bool policy_target_array<max_items>::CheckPolicy(u_short src, u_short dst) {
    for (u_char i=0; i<num; i++) {             
            if (((mf[i]&MATCH_SRC) && (src==value[i]))||((mf[i]&MATCH_DST) && (dst==value[i])))
                return 1;

          if (max[i]) {
            if ((mf[i]&MATCH_SRC)&&(ntohs(src)>=ntohs(value[i]))&&(ntohs(src)<=ntohs(max[i])))
                return 1;
            if ((mf[i]&MATCH_DST)&&(ntohs(dst)>=ntohs(value[i]))&&(ntohs(dst)<=ntohs(max[i])))
                return 1;
          }
    }
    return 0;         
}

/////////////////////////////////////////////////////////////////////////
// PolicyList class
PolicyList::PolicyList():List(){
}

void PolicyList::DeleteUnitFromTarget(NetUnit *u) {
      Policy *d;

      netams_rwlock_rdlock(&rwlock);
      for(d=(Policy*)root; d!=NULL; d=(Policy*)d->next)
            if (d->target.check_type&PC_UNIT && d->target.unit)
                  d->target.unit=NULL;
      
      netams_rwlock_unlock(&rwlock);
}

Policy* PolicyList::getPolicy(char *name){
      Policy *d;
      
      netams_rwlock_rdlock(&rwlock);
      for(d=(Policy*)root; d!=NULL; d=(Policy*)d->next)     {
            if (STREQ(d->name, name))
                  break;
      }
      netams_rwlock_unlock(&rwlock);

      if(!d) {
            oid id=strtol(name, NULL, 16);
            d=(Policy*)getById(id);
      }
      return d;
}

void PolicyList::ShowConfig(struct cli_def *cli, u_char flags) {
      netams_rwlock_rdlock(&rwlock);
      for (Policy *p=(Policy*)root; p!=NULL; p=(Policy*)p->next) {
            cli_bufprint(cli, "policy oid %06X", p->id);
            if (p->name) 
                  SHOW_STR(cli, "name", p->name);
            if (p->hidden)
                  cli_bufprint(cli, " hidden");
            if (p->target.target_type) { 
                  cli_bufprint(cli, " target");
                  p->getTarget(cli);
            }
            if (p->bwi) {
                  cli_bufprint(cli, " bw");
                  getBW(p->bwi, cli);
            }
            cli_bufprint(cli, "\n");
      }
      netams_rwlock_unlock(&rwlock);      
}
/////////////////////////////////////////////////////////////////////////
Policy* aParsePolicy(char *param[], u_char *i, oid *pid) {
      Policy *p;

      if (STRARG(param[*i], "name")) {
            p=PolicyL->getPolicy(param[(*i)+1]);
            if(p!=NULL) 
                  (*i)+=2;
            return p;
      } else if (STRARG(param[*i], "oid")) {
            oid id=strtol(param[++(*i)], NULL, 16);
            p=(Policy*)PolicyL->getById(id);
            if(pid!=NULL) *pid = id;
      } else {
            oid id=strtol(param[*i], NULL, 16);
            p=(Policy*)PolicyL->getById(id);
            if(p==NULL) 
                  p=PolicyL->getPolicy(param[*i]);
            else if(pid!=NULL) *pid = id;
      }
      (*i)++;
      return p;
}

int cPolicy(struct cli_def *cli, char **param, int argc, u_char no_flag){
      Policy *p=NULL;
      u_char i=1;
      oid id=0;
      
      p=aParsePolicy(param, &i, &id);

      if (!p && !no_flag) { 
            p = new Policy();
            p->id = newOid(id);
            cli_error(cli, "policy %06X created", p->id); 
            PolicyL->Insert(p);
      } else if (!p && no_flag) {
            cli_error(cli, "policy not exist");
            return CLI_OK;
      }
      else if (p && no_flag){
            cli_error(cli, "policy %06X deleted", p->id);
            ((List*)PolicyL)->Delete(p);
            Units->DeletePolicyElsewhere(p);
            delete p;
            return CLI_OK;
      }
      
      for(;i<argc; i+=2) {
            if (STRARG(param[i], "name")) { 
                  p->setName(param[i+1]);
                  cli_error(cli, "policy %06X name set: %s", p->id, p->name);
                  sPConstructStoreOidMessage(NULL, p);
            }
            else if (STREQ(param[i], "no")) {
                  no_flag=1;
                  i--;
            }
            else if (STREQ(param[i], "target")) {
                  u_char j=p->setTarget(cli, param, &i, no_flag); 
                  if (j) {
                        cli_bufprint(cli, "policy %06X target set:", p->id);
                        p->getTarget(cli);
                        cli_bufprint(cli,"\n");
                  } else
                        cli_error(cli, "policy %06X target invalid", p->id); 
            }
            else if (STREQ(param[i], "do")) {
                  if (p->target.check_type&PC_FILE) {
                        cli_error(cli, "policy %06X file do: '%s'", p->id, param[i+1]);
                        p->target.file->Do(cli, param[i+1]);
                  } else
                        cli_error(cli, "policy %06X action unsupported!", p->id);   
            }
            else if (STREQ(param[i], "bw")) {
                  p->bwi=setBW(p->bwi, param, &i);
#ifndef HAVE_BW
                  cli_error(cli, "policy %06X: trying to set BW while this runtime has no BW support; please recompile!", p->id);
                  aLog(D_WARN, "policy %06X: \n\ttrying to set BW while this runtime has no BW support; please recompile!\n\n", p->id);
#else
                  cli_bufprint(cli, "policy %06X allowed bandwidth set:", p->id);
                  getBW(p->bwi, cli);
                  cli_bufprint(cli, "\n");
#endif
            }
            else if (STREQ(param[i], "oid")) ;//do nothing
            else if (STREQ(param[i], "hidden")) { 
                  cli_bufprint(cli, "policy %06X will be hidden in HTML output\n", p->id);
                  p->hidden=1; 
                  i--; 
                  }
            else
                  cli_error(cli, "policy %06X command unknown: %s", p->id, param[i]);
      }
      return CLI_OK;
}
/////////////////////////////////////////////////////////////////////////
int cShowPolicy(struct cli_def *cli, const char *cmd, char **argv, int argc){
      Policy *d;

      cli_print(cli, "%6s | %15s | %-20s", "OID", "NAME", "PARAMS");
      
      netams_rwlock_rdlock(&PolicyL->rwlock);
      for (d=(Policy*)PolicyL->root; d!=NULL; d=(Policy*)d->next) {
            cli_bufprint(cli, "%06X | %15s | ", d->id, d->name?d->name:"<\?\?>");
            if (d->bwi) {
                  cli_bufprint(cli, "bw:");
                  getBW(d->bwi, cli);
                  }
            else if (d->target.target_type) {
                  cli_bufprint(cli, "target:");
                   d->getTarget(cli);
            }
            cli_bufprint(cli, "\n");
      }
      netams_rwlock_unlock(&PolicyL->rwlock);
      return CLI_OK;
}

/////////////////////////////////////////////////////////////////////////
// PdList class
PdList::PdList(){
      root=NULL;
      num_policies=0;
        netams_rwlock_init(&rwlock, NULL);
}

PdList::~PdList(){
      policy_data *tmp;
      while(root) {
            tmp=root;
            root=root->next;
            aFree(tmp);
      }
      netams_rwlock_destroy(&rwlock);
}

policy_data *PdList::Add(Policy *p, u_char pflags, u_char place) {
      policy_data *after=NULL;
      policy_data *npd = NULL;
      
      u_char curr_place=0;
      if (!place) place=255;

      netams_rwlock_wrlock(&rwlock);
      for (policy_data *prev=NULL,*d=root; d!=NULL; d=d->next) {
            if (d->policy==p && d->policy_flags==pflags) {
                  if(root==d) root=d->next;
                  else prev->next=d->next;
                  npd = d;
                  continue;
            }
            prev = d;
            curr_place++;
            if (curr_place<place) after=d;
      }

      if(!npd) {
            npd = (policy_data*)aMalloc(sizeof(policy_data));
            npd->flags=0;
            npd->policy_flags=pflags;
            npd->next=NULL;
            npd->timestamp=0;          
            npd->policy=p;
            npd->check=npd->match=0;
            num_policies++;

            npd->flow.from=time(NULL);
            struct time_counters tc;
            PrepareTimeCounters(&tc, npd->flow.from);
            FillTimeCounters(npd,&tc);
      }

      if (root==NULL) root=npd;   // empty list
      else if (after==NULL) { npd->next=root; root=npd; } // first
      else { npd->next=after->next; after->next=npd; }
      
      netams_rwlock_unlock(&rwlock);
      return npd;
}

u_char PdList::Delete(Policy *s) {
      policy_data *d, *p=NULL;

      netams_rwlock_wrlock(&rwlock);
      for (d=root; d!=NULL; d=d->next){
            if (d->policy==s) {
                  if (d==root) root=d->next;
                  else p->next=d->next;

                  num_policies--;
                  aFree(d);
                  break;
            }
            p=d; 
      }
      netams_rwlock_unlock(&rwlock);
      return num_policies;
}

void PdList::List(struct cli_def *cli){
      policy_data *d;
      
      netams_rwlock_rdlock(&rwlock);
      for (d=root; d!=NULL; d=d->next){
            cli_bufprint(cli, " %s(%06X)", d->policy->name, d->policy->id);
      }
      netams_rwlock_unlock(&rwlock);
}

void PdList::ListForCfg(struct cli_def *cli, u_char flags){
      policy_data *d;
      
      netams_rwlock_rdlock(&rwlock);
      for (d=root; d!=NULL; d=d->next){
            cli_bufprint(cli, " %s%s",
                  (d->policy_flags&POLICY_FLAG_INV)?"!":"",
                  (d->policy_flags&POLICY_FLAG_BRK)?"%":"");
            SHOW_OIDS(cli, flags, d->policy->name, d->policy->id);
      }
      netams_rwlock_unlock(&rwlock);
}

void PdList::SetForUnit(policy_type pt, NetUnit *u, struct cli_def *cli){
      policy_data *d,*pd;
      // notice!!! there is no deadlock between rwlock and Add(d->policy) 
      // they are from different units
      netams_rwlock_rdlock(&rwlock);
      for (d=root; d!=NULL; d=d->next){
            if (pt==POLICY_ACCT) {
                  if(!u->ap) u->ap = new PdList();
                  pd=u->ap->Add(d->policy, d->policy_flags, 0);
                  if(cli) cli_error(cli, "unit %06X acct %s%spolicy %s added",
                        u->id,
                        (d->policy_flags&POLICY_FLAG_INV)?"!":"",
                        (d->policy_flags&POLICY_FLAG_BRK)?"%":"",
                        d->policy->name);
            } else if (pt==POLICY_FW) {
                  if(!u->fp) u->fp = new PdList();
                  u->fp->Add(d->policy, d->policy_flags, 0); 
                  if(cli) cli_error(cli, "unit %06X fw %s%spolicy %s added \n",
                        u->id,
                        (d->policy_flags&POLICY_FLAG_INV)?"!":"",
                        (d->policy_flags&POLICY_FLAG_BRK)?"%":"",
                        d->policy->name);
            }
      }
      netams_rwlock_unlock(&rwlock);
}

policy_data *PdList::Get(Policy *p){
      policy_data *d;

      netams_rwlock_rdlock(&rwlock);
      for (d=root; d!=NULL; d=d->next) 
            if (d->policy==p)
                  break;
      
      netams_rwlock_unlock(&rwlock);
      return d;
}

time_t PdList::LastUsed(){
      policy_data *d;
      time_t l=0;

      netams_rwlock_rdlock(&rwlock);
      for (d=root; d!=NULL; d=d->next) 
            if (d->timestamp > l)
                  l=d->timestamp;
      
      netams_rwlock_unlock(&rwlock);
      return l;
}

void PdList::ClearLastUsed(){
      policy_data *d;
      netams_rwlock_wrlock(&rwlock);
      for (d=root; d!=NULL; d=d->next)
            d->timestamp=0;
      
      netams_rwlock_unlock(&rwlock);
}
/////////////////////////////////////////////////////////////////////////
// we need this fucntion to find out will be ip packet checked correctly for given policy
// for this unit
// see PR 59
u_char PdList::IsNetCheckBroken(NetUnit *u) {

      if(u->type!=NETUNIT_CLUSTER && u->type!=NETUNIT_NET) return 0; //all is ok with this units

      if(u->type==NETUNIT_NET) {
            unsigned mask=((NetUnit_net*)u)->mask.s_addr;
            if(mask==0 || mask==0xFF000000 || mask==0xFFFF0000 || mask==0xFFFFFF00 || mask==0xFFFFFFFF) return 0;
      }

      Policy *p;
      u_char res=0;
      
      netams_rwlock_rdlock(&rwlock);
      for (policy_data *d=root; d!=NULL; d=d->next) {
            p=d->policy;
            if(p->target.target_type&PT_IP_TRAFFIC) {
            //this is only case we might perform wrong check
                  if((p->target.check_type&PC_UNIT) || (p->target.check_type&PC_FILE)) {
                        res=1;
                        break;
                  }
            }
      }
      netams_rwlock_unlock(&rwlock);
      return res;
}
/////////////////////////////////////////////////////////////////////////
void PolicyDataUpdate(match m, policy_data *p, Flow *list){
      const union attribute_value   *value = list->get(ATTR_FLOW_INFO);
      
      if(value->flow_info.flow_last > p->timestamp) p->timestamp=value->flow_info.flow_last;

      if (m&MATCH_DST) { 
            p->flow.in+=value->flow_info.octets;
      }

      if (m&MATCH_SRC) { 
            p->flow.out+=value->flow_info.octets;
      }
}
/////////////////////////////////////////////////////////////////////////
void PolicyAdd(NetUnit *u, u_char *i, policy_type po, struct cli_def *cli, char *param[], u_char no_flag){
      Policy *p;
      char *c_param;
      policy_flag pflags;
      u_char place=0;

      while ((c_param=param[++(*i)])) {
            pflags=POLICY_FLAG_NONE;
            if (c_param[0]=='!') { pflags|=POLICY_FLAG_INV; c_param++; }
            if (c_param[0]=='%') { pflags|=POLICY_FLAG_BRK; c_param++; }
            if (c_param[0]=='!') { pflags|=POLICY_FLAG_INV; c_param++; }
            
            if (!place) {
                  if ((place=(u_char)strtol(c_param, NULL, 10))!=0)
                        continue;
                  else
                        place=0;
            }
            
            p=PolicyL->getPolicy(c_param);
            if (p)  {
                  PdList **pdl=NULL;
                  policy_data *pdc=NULL;
                  const char *action=NULL;
                  u_char uflags=0;

                  if (po==POLICY_ACCT) {
                        pdl=&u->ap;
                        uflags=NETUNIT_BROKEN_ACCT_MF;
                  } else if (po==POLICY_FW) {
                        pdl=&u->fp;
                        uflags=NETUNIT_BROKEN_FW_MF;
                  }

                  if (no_flag) {
                        if(!*pdl) return;
                        if(!(*pdl)->Delete(p)) {delete *pdl; *pdl=NULL; }
                        action="removed";
                  } else {
                        if(!*pdl) *pdl = new PdList();
                        if ((pdc=(*pdl)->Add(p, pflags, place))==NULL) return;
                        action="added";
                  }
                  if(*pdl && (*pdl)->IsNetCheckBroken(u)) u->flags |= uflags;
                  else u->flags &= ~uflags;
                  
                  //perform specific actions
                  if (po==POLICY_FW)
                        FW_CHECK_CHANGED(time(NULL));
                  
                  cli_error(cli, "unit %06X %s %s%spolicy %s %s <%u>",
                        u->id, policy_type_name[po],
                        (pflags&POLICY_FLAG_INV)?"inverted ":"", (pflags&POLICY_FLAG_BRK)?"break ":"",
                        c_param, action, place);
            } else { // policy is defined
                  cli_error(cli, "unit %06X policy '%s' undefined", u->id, c_param);
                  *i-=2;
                  return;
            }
            place=0;
      }
}
/////////////////////////////////////////////////////////////////////////
void GetSysPolicy(struct cli_def *cli, SysPolicy p, oid perm){
      if(perm) cli_bufprint(cli, " sys-%s-%06X", (p&SP_DENY)?"deny":"allow", perm);
      else if(p&SP_DENY) cli_bufprint(cli, " sys-deny");
      if(p&SP_DENY_MONEY) cli_bufprint(cli, " sys-deny-money");
      if(p&SP_DENY_BLOCK) cli_bufprint(cli, " sys-deny-block");
      if(p&SP_DENY_QUOTA) cli_bufprint(cli, " sys-deny-quota");
      if(p&SP_DENY_LOGIN) cli_bufprint(cli, " sys-deny-login");
      if(p&SP_DENY_AUTH) cli_bufprint(cli, " sys-deny-auth");
      if(p&SP_DENY_MAC) cli_bufprint(cli, " sys-deny-mac");
}

void SetSysPolicy(struct cli_def *cli, NetUnit *u, char *p){
      char *p1, *p2;
      char *s1=NULL, *s2=NULL;
      int direction=REMOVE; // ???
      oid id=u->sys_policy_perm;
      SysPolicy prev=u->sys_policy;
      p1=p+4;
      if (!p1) {
            cli_error(cli, "incorrect NetUnit sys-* value");
            return;
      }

      p2=strchr(p1, '-'); 
      if (p2)  {
            p2++;
            s1=(char*)aMalloc(p2-p1+2); strncpy(s1, p1, p2-p1-1);
            s2=(char*)aMalloc(strlen(p2)+2); strncpy(s2, p2, strlen(p2));
            if(s2[0]=='0') {
                  id=strtol(s2, NULL, 16); //here we depends that our oids looks like 0XXXXX
                  NetUnit *pu=(NetUnit*)Units->getById(id);
                  if(!pu) {
                        cli_error(cli, "No such unit %06X", id);
                        goto END;
                  }
            }
      }
      else {
            s1=(char*)aMalloc(strlen(p1)+2); strncpy(s1, p1, strlen(p1));
            s2=(char*)aMalloc(2); strncpy(s2, "", 1);
      }
      
      aDebug(DEBUG_PARSE, "SysPolicy got '%s' '%s'\n", s1, s2);
      
      if (STREQ(s1, "allow")) direction = REMOVE;
      else if (STREQ(s1, "deny")) direction = ADD;

      if(id) u->SetSysPolicy(SP_DENY, direction, 0);
      else if (STREQ(s2, "")) {
            if (direction==REMOVE) {
                  u->sys_policy = SP_NONE;
                  u->SetSysPolicy(SP_NONE, direction, 0);
            } else if (direction==ADD)
                  u->SetSysPolicy(SP_DENY, direction, 0);
      }
      else if (STREQ(s2, "money")) u->SetSysPolicy(SP_DENY_MONEY, direction, 0);
      else if (STREQ(s2, "block")) u->SetSysPolicy(SP_DENY_BLOCK, direction, 0);
      else if (STREQ(s2, "quota")) u->SetSysPolicy(SP_DENY_QUOTA, direction, 0);
      else if (STREQ(s2, "login")) u->SetSysPolicy(SP_DENY_LOGIN, direction, 0);
      else if (STREQ(s2, "auth")) u->SetSysPolicy(SP_DENY_AUTH, direction, 0);
      else cli_error(cli, "System policy for %06X allow: is incorrect", u->id);
                        
      if (prev!=u->sys_policy || id!=u->sys_policy_perm) {
            u->sys_policy_perm=id;
            if (s2[0])
                  cli_error(cli, "System policy for %06X set to '%s-%s'", u->id, s1, s2);
            else
                  cli_error(cli, "System policy for %06X set to '%s'", u->id, s1);
      }

      FW_CHECK_CHANGED(time(NULL));

END:
      aFree(s1); aFree(s2);
}
/////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////

Generated by  Doxygen 1.6.0   Back to index