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

filter.cc

/*
 * WallFire -- a comprehensive firewall administration tool.
 * 
 * Copyright (C) 2001 Hervé Eychenne <rv@wallfire.org>
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 * 
 */

using namespace std;

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <sys/types.h> /* for regex.h */
#include <regex.h>

extern "C" time_t get_date(const char *p, const time_t *now);

#include "filter.h"
#include "defs.h"


/* Indexes must be the same than enum filter_op_unary */
const char* ops_unary[] = {
  "-",
  "!",
  "+"
};

/* Indexes must be the same than enum filter_op_binary */
const char* ops_binary[] = {
  "||",
  "&&",
  "==",
  "!=",
  "=~",  /* regular expression */
  "<",
  ">",
  "<=",
  ">=",
  "^",
  "|",
  "&",
  "+",
  "-"
};


exprnode_unary::exprnode_unary(enum filter_op_unary op, exprnode* node) :
  _op(op),
  _child(node)
{
}

exprnode_unary::~exprnode_unary() {
  delete _child;
}

exprnode_unary::exprnode_unary(const exprnode_unary& unary) :
  _op(unary._op),
  _child(unary._child)
{
}


bool
exprnode_unary::check() const {
  /* unary operator only applies to terminals of numerical type */
  if (_child->ret_type() != FOP_VAR_TYPE_INT) {
    cerr << _("error: unary operator can only apply to numeric value") << endl;
    return false;
  }
  return _child->check();
}

int
exprnode_unary::eval() const {
  int result;
  switch (_op) {
  case FOP_NEG:
    result = - _child->eval(); break;
  case FOP_NOT:
    result = ! _child->eval(); break;
  case FOP_POS:
    result = _child->eval(); break;
  default:
    result = 0; // RV@@9 this shouldn't happen
  }
  return result;
}

ostream&
exprnode_unary::print(ostream& os) const {
  os << ops_unary[_op] << '(';
  _child->print(os);
  return os << ')';
}




exprnode_binary::exprnode_binary(enum filter_op_binary op,
                         exprnode* lft, exprnode* rt) :
  _op(op),
  _left(lft),
  _right(rt)
{
}

exprnode_binary::~exprnode_binary() {
  delete _left;
  delete _right;
}

exprnode_binary::exprnode_binary(const exprnode_binary& binary) :
  _op(binary._op),
  _left(binary._left),
  _right(binary._right)
{
}

bool
exprnode_binary::check() const {
  enum filter_op_var_type left_type = _left->ret_type(),
    right_type = _right->ret_type();

  if (_op == FOP_REG) {
    if (left_type != FOP_VAR_TYPE_STR) {
      cerr << _("error: regular expression should apply to a string") << endl;
      return false;
    }
    if (right_type == FOP_VAR_TYPE_REGEXP)
      return true;
    if (right_type == FOP_VAR_TYPE_STR)
      cerr << _("error: regular expression should be /.../, not \"...\"") << endl;
    else
      cerr << _("error: invalid use of regexp operator") << endl;
    return false;
  }

  if (left_type != right_type) {
    ostream_printf(cerr, _("error: operator `%s' used with different types\n"),
               ops_binary[_op]);
    return false;
  }
  /* From now on, left_type == right_type. */
  if (left_type == FOP_VAR_TYPE_STR) { /* types are terminal and string */
    if (_op != FOP_EQ && _op != FOP_NE) {
      ostream_printf(cerr, _("error: invalid operator `%s' used with string\n"),
                   ops_binary[_op]);
      return false;
    }
  }
  return _left->check() && _right->check();
}

int
exprnode_binary::eval() const {
  int result = 0; /* initialized in order to avoid warnings */

  if (_op == FOP_REG)  /* types are supposed to be good (after check()) */
    return ((exprnode_var_regexp*)_right)->regmatch(((exprnode_var*)_left)->str());

  enum filter_op_var_type type = _left->ret_type();
  /* _left and _right are of the same type (check() has ensured that). */

  if (type == FOP_VAR_TYPE_INT) { /* types are numerical */
    switch (_op) {
    case FOP_LOR:
      result = _left->eval() || _right->eval(); break;
    case FOP_LAND:
      result = _left->eval() && _right->eval(); break;
    case FOP_EQ:
      result = _left->eval() == _right->eval(); break;
    case FOP_NE:
      result = _left->eval() != _right->eval(); break;
    case FOP_LT:
      result = _left->eval() < _right->eval(); break;
    case FOP_GT:
      result = _left->eval() > _right->eval(); break;
    case FOP_LE:
      result = _left->eval() <= _right->eval(); break;
    case FOP_GE:
      result = _left->eval() >= _right->eval(); break;
    case FOP_AND:
      result = _left->eval() & _right->eval(); break;
    case FOP_OR:
      result = _left->eval() | _right->eval(); break;
    case FOP_XOR:
      result = _left->eval() ^ _right->eval(); break;
    case FOP_PLUS:
      result = _left->eval() + _right->eval(); break;
    case FOP_MINUS:
      result = _left->eval() - _right->eval(); break;
    default:
      ; // RV@@9 this shouldn't happen
    }
  }
  else if (type == FOP_VAR_TYPE_STR) { /* types are terminal and string */
    string leftstr = ((exprnode_var*)_left)->str();
    string rightstr = ((exprnode_var*)_right)->str();
    switch (_op) {
    case FOP_EQ:
      result = leftstr == rightstr; break;
    case FOP_NE: 
      result = leftstr != rightstr; break;
    default:
      ; // RV@@9 this shouldn't happen
    }
  }
  else if (type == FOP_VAR_TYPE_IPNET) {
    wf_ipaddr ipaddr = ((exprnode_var*)_left)->ipaddr();
    wf_network network = ((exprnode_var_ipnet*)_right)->_network;
    switch (_op) {
    case FOP_EQ:
      result = network.belong(ipaddr); break;
    case FOP_NE: 
      result = !network.belong(ipaddr); break;
    default:
      ; // RV@@9 this shouldn't happen
    }
  }
  else if (type == FOP_VAR_TYPE_MACADDR) {
    wf_macaddr lmacaddr = ((exprnode_var*)_left)->macaddr();
    wf_macaddr rmacaddr = ((exprnode_var_macaddr*)_right)->_macaddr;
    switch (_op) {
    case FOP_EQ:
      result = lmacaddr == rmacaddr; break;
    case FOP_NE: 
      result = lmacaddr != rmacaddr; break;
    default:
      ; // RV@@9 this shouldn't happen
    }
  }
  
  return result;
}

ostream&
exprnode_binary::print(ostream& os) const {
  os << '(';
  _left->print(os);
  os << ' ' << ops_binary[_op] << ' ';
  _right->print(os);
  return os << ')';
}



/* dummy method:never called */
int
exprnode_var::eval() const {
  return 0;
}

/* dummy method: never called */
string
exprnode_var::str() const {
  return "";
}

/* dummy method: never called */
wf_ipaddr
exprnode_var::ipaddr() const {
  return wf_ipaddr();
}

/* dummy method: never called */
wf_macaddr
exprnode_var::macaddr() const {
  return wf_macaddr();
}


struct vars {
  const string name;
  enum filter_op_var_type type;
};

/* Warning: must have the same order than enum vars_num */
struct vars vararr[] = {
  { "format", FOP_VAR_TYPE_STR },
  { "count", FOP_VAR_TYPE_INT },
  { "start_time", FOP_VAR_TYPE_INT },
  { "end_time", FOP_VAR_TYPE_INT },
  { "hostname", FOP_VAR_TYPE_STR},
  { "chainlabel", FOP_VAR_TYPE_STR},
  { "branchname", FOP_VAR_TYPE_STR},
  { "input_iface", FOP_VAR_TYPE_STR},
  { "output_iface", FOP_VAR_TYPE_STR},
  { "protocol", FOP_VAR_TYPE_INT },
  { "datalen", FOP_VAR_TYPE_INT },
  { "sipaddr", FOP_VAR_TYPE_IPNET },
  { "sport", FOP_VAR_TYPE_INT },
  { "smacaddr", FOP_VAR_TYPE_MACADDR },
  { "dipaddr", FOP_VAR_TYPE_IPNET },
  { "dport", FOP_VAR_TYPE_INT },
  { "dmacaddr", FOP_VAR_TYPE_MACADDR },
  { "tcpflags", FOP_VAR_TYPE_INT },
};

exprnode_var_id::exprnode_var_id(const string& name) {
  unsigned int i;
  
  for (i = 0; i < sizeof(vararr) / sizeof(struct vars); i++)
    if (vararr[i].name == name) {
      _num = (enum vars_num)i;
      return;
    }

  _num = VARS_UNKNOWN;
  return;
}

exprnode_var_id::~exprnode_var_id() {
}

enum vars_num
exprnode_var_id::num() const {
  return _num;
}

exprnode_var_id_wflogs::exprnode_var_id_wflogs(const string& name) :
  exprnode_var_id(name)
{
}

exprnode_wflogs::exprnode_wflogs(const exprnode_wflogs& wflogs) :
  _entry(wflogs._entry)
{
}

bool
exprnode_var_id::check() const {
  if (_num != VARS_UNKNOWN)
    return true;

  cerr << _("error: unknown var") << endl;
  return false;
}

enum filter_op_var_type
exprnode_var_id::ret_type() const {
  return vararr[_num].type;
}

ostream&
exprnode_var_id::print(ostream& os) const {
  return os << '$' << vararr[_num].name;
}




exprnode_var_int::exprnode_var_int(int val) :
  _value(val)
{
}

exprnode_var_int::~exprnode_var_int() {
}


int
exprnode_var_int::eval() const {
  return _value;
}

ostream&
exprnode_var_int::print(ostream& os) const {
  return os << _value;
}


void
exprnode_var_int::value(int val) {
  _value = val;
}




exprnode_var_str::exprnode_var_str(const string& str) :
  _str(str)
{
}

exprnode_var_str::~exprnode_var_str() {
}


string
exprnode_var_str::str() const {
  return _str;
}

ostream&
exprnode_var_str::print(ostream& os) const {
  return os << '"' << _str << '"';
}



exprnode_var_regexp::exprnode_var_regexp() :
  _regexp(),
  _str()
{
}

exprnode_var_regexp::~exprnode_var_regexp() {
  regfree(&_regexp);
}


bool
exprnode_var_regexp::set(const string& str, int flags) {
  int ret = regcomp(&_regexp, str.c_str(), flags|REG_NOSUB|REG_EXTENDED);
  if (ret) {
    char errtext[1024];
    _str.erase();
    regerror(ret, &_regexp, errtext, sizeof(errtext));
    ostream_printf(cerr, _("error: cannot compile regexp `%s': "), str.c_str());
    cerr << errtext << endl;
    return false;
  }
  _str = str;
  return true;
}

bool
exprnode_var_regexp::regmatch(const string& str) const {
  int ret = regexec(&_regexp, str.c_str(), 0, NULL, 0);
  switch (ret) {
  case 0:
    return true;
  case REG_NOMATCH:
    break;
  default:
    char errtext[1024];
    regerror(ret, &_regexp, errtext, sizeof(errtext));
    ostream_printf(cerr, _("error: cannot apply regexp `%s': "), _str.c_str());
    cerr << errtext << endl;
  }
  return false;
}

ostream&
exprnode_var_regexp::print(ostream& os) const {
  return os << '/' << _str << '/';
}





exprnode_var_ipnet::exprnode_var_ipnet(const wf_ipaddr& ipaddr) {
  _network.set(ipaddr, 32);
}

exprnode_var_ipnet::exprnode_var_ipnet(const wf_network& ipnet) :
  _network(ipnet)
{
}


ostream&
exprnode_var_ipnet::print(ostream& os) const {
  return os << _network;
}

bool
exprnode_var_ipnet::belong(const wf_ipaddr& ipaddr) const {
  return _network.belong(ipaddr);
}




exprnode_var_macaddr::exprnode_var_macaddr(const wf_macaddr& macaddr) :
  _macaddr(macaddr)
{
}


ostream&
exprnode_var_macaddr::print(ostream& os) const {
  return os << _macaddr;
}



exprnode_var_date::exprnode_var_date() :
  _time(-1)
{
}

exprnode_var_date::~exprnode_var_date() {
}


bool
exprnode_var_date::set(const string& str) {
  _time = get_date(str.c_str(), NULL);
  return _time != -1;
}

int
exprnode_var_date::eval() const {
  return _time;
}

ostream&
exprnode_var_date::print(ostream& os) const {
  char* str = ctime(&_time);
  str[strlen(str) - 1] = '\0';
  return os << '[' << str << ']';
}


/* optimize 
   cerr << "OPERATOR" << endl;
   if ($2->isvar()) { // check int type RV@@9
   cerr << "COUCOU1 " << $1 << endl;
   if ($1 == '-') {
   cerr << "COUCOU" << endl;
   $2->value(-($2->value()));
   }
   else if ($1 == '!')
   $2->value(!($2->value()));
   }
   $$ = $2; // RV@@9 wrong: what about operator?
*/

Generated by  Doxygen 1.6.0   Back to index