⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ipfilter.cc

📁 COPE the first practical network coding scheme which is developped on click
💻 CC
📖 第 1 页 / 共 3 页
字号:
/* * ipfilter.{cc,hh} -- IP-packet filter with tcpdumplike syntax * Eddie Kohler * * Copyright (c) 2000-2004 Mazu Networks, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, subject to the conditions * listed in the Click LICENSE file. These conditions include: you must * preserve this copyright notice, and you cannot mention the copyright * holders in advertising related to the Software without their permission. * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This * notice is a summary of the Click LICENSE file; the license in that file is * legally binding. */#include <click/config.h>#include "ipfilter.hh"#include <click/glue.hh>#include <click/error.hh>#include <click/confparse.hh>#include <click/straccum.hh>#include <clicknet/ip.h>#include <clicknet/tcp.h>#include <clicknet/icmp.h>#include <click/hashmap.hh>#include <click/integers.hh>#include <click/nameinfo.hh>CLICK_DECLSstatic const StaticNameDB::Entry type_entries[] = {    { "ce", IPFilter::TYPE_IPCE },    { "dest", IPFilter::TYPE_SYNTAX },    { "dscp", IPFilter::FIELD_DSCP },    { "dst", IPFilter::TYPE_SYNTAX },    { "ect", IPFilter::TYPE_IPECT },    { "frag", IPFilter::TYPE_IPFRAG },    { "hl", IPFilter::FIELD_HL },    { "host", IPFilter::TYPE_HOST },    { "id", IPFilter::FIELD_ID },    { "ip", IPFilter::TYPE_SYNTAX },    { "len", IPFilter::FIELD_IPLEN },    { "net", IPFilter::TYPE_NET },    { "not", IPFilter::TYPE_SYNTAX },    { "opt", IPFilter::TYPE_TCPOPT },    { "port", IPFilter::TYPE_PORT },    { "proto", IPFilter::TYPE_PROTO },    { "src", IPFilter::TYPE_SYNTAX },    { "tos", IPFilter::FIELD_TOS },    { "ttl", IPFilter::FIELD_TTL },    { "type", IPFilter::FIELD_ICMP_TYPE },    { "unfrag", IPFilter::TYPE_IPUNFRAG },    { "vers", IPFilter::FIELD_VERSION },    { "win", IPFilter::FIELD_TCP_WIN }};static const StaticNameDB::Entry tcp_opt_entries[] = {    { "ack", TH_ACK },    { "fin", TH_FIN },    { "psh", TH_PUSH },    { "rst", TH_RST },    { "syn", TH_SYN },    { "urg", TH_URG }};static const uint32_t db2type[] = {    IPFilter::TYPE_PROTO, IPFilter::TYPE_PORT, IPFilter::TYPE_PORT,    IPFilter::TYPE_TCPOPT, IPFilter::FIELD_ICMP_TYPE};static Stringunparse_word(int type, int proto, const String &word){    String tn = IPFilter::Primitive::unparse_type(0, type);    String tr = IPFilter::Primitive::unparse_transp_proto(proto);    if (tn)	tn += " ";    if (tr || (word && tn))	tr += " ";    return tn + tr + word;}intIPFilter::lookup(String word, int type, int proto, uint32_t &data, ErrorHandler *errh) const{    // type queries always win if they occur    if (type == 0 || type == TYPE_TYPE)	if (NameInfo::query(NameInfo::T_IPFILTER_TYPE, this, word, &data, sizeof(uint32_t)))	    return (data == TYPE_SYNTAX ? -1 : TYPE_TYPE);        // query each relevant database    int got[5];    int32_t val[5];    got[0] = NameInfo::query(NameInfo::T_IP_PROTO, this, word, &val[0], sizeof(uint32_t));    got[1] = NameInfo::query(NameInfo::T_TCP_PORT, this, word, &val[1], sizeof(uint32_t));    got[2] = NameInfo::query(NameInfo::T_UDP_PORT, this, word, &val[2], sizeof(uint32_t));    got[3] = NameInfo::query(NameInfo::T_TCP_OPT, this, word, &val[3], sizeof(uint32_t));    got[4] = NameInfo::query(NameInfo::T_ICMP_TYPE, this, word, &val[4], sizeof(uint32_t));    // exit if no match    if (!got[0] && !got[1] && !got[2] && !got[3] && !got[4])	return -1;    // filter    int tgot[5];    tgot[0] = got[0] && (type == 0 || type == TYPE_PROTO);    tgot[1] = got[1] && (type == 0 || type == TYPE_PORT)	&& (proto == UNKNOWN || proto == IP_PROTO_TCP || proto == IP_PROTO_TCP_OR_UDP);    tgot[2] = got[2] && (type == 0 || type == TYPE_PORT)	&& (proto == UNKNOWN || proto == IP_PROTO_UDP || proto == IP_PROTO_TCP_OR_UDP);    tgot[3] = got[3] && (type == 0 || type == TYPE_TCPOPT)	&& (proto == UNKNOWN || proto == IP_PROTO_TCP || proto == IP_PROTO_TCP_OR_UDP);    tgot[4] = got[4] && (type == 0 || type == FIELD_ICMP_TYPE)	&& (proto == UNKNOWN || proto == IP_PROTO_ICMP);        // remove one of TCP and UDP port if they give the same value    if (tgot[1] && tgot[2] && val[1] == val[2])	tgot[2] = false;    // return    int ngot = tgot[0] + tgot[1] + tgot[2] + tgot[3] + tgot[4];    if (ngot == 1) {	for (int i = 0; i < 5; i++)	    if (tgot[i]) {		data = val[i];		return db2type[i];	    }    }    StringAccum sa;    for (int i = 0; i < 5; i++)	if (got[i]) {	    if (sa)		sa << ", ";	    sa << '\'' << unparse_word(db2type[i], proto, word) << '\'';	}    if (errh)	errh->error("'%s' is %s; try %s", unparse_word(type, proto, word).c_str(), (ngot > 1 ? "ambiguous" : "meaningless"), sa.c_str());    return -2;}static NameDB *dbs[2];voidIPFilter::static_initialize(){    dbs[0] = new StaticNameDB(NameInfo::T_IPFILTER_TYPE, String(), type_entries, sizeof(type_entries) / sizeof(type_entries[0]));    dbs[1] = new StaticNameDB(NameInfo::T_TCP_OPT, String(), tcp_opt_entries, sizeof(tcp_opt_entries) / sizeof(tcp_opt_entries[0]));    NameInfo::installdb(dbs[0], 0);    NameInfo::installdb(dbs[1], 0);}voidIPFilter::static_cleanup(){    NameInfo::removedb(dbs[0]);    NameInfo::removedb(dbs[1]);    delete dbs[0];    delete dbs[1];}IPFilter::IPFilter(){}IPFilter::~IPFilter(){}//// CONFIGURATION//voidIPFilter::Primitive::clear(){  _type = _srcdst = 0;  _transp_proto = UNKNOWN;  _data = 0;  _op = OP_EQ;  _op_negated = false;}voidIPFilter::Primitive::set_type(int x, ErrorHandler *errh){  if (_type)    errh->error("type specified twice");  _type = x;}voidIPFilter::Primitive::set_srcdst(int x, ErrorHandler *errh){  if (_srcdst)    errh->error("'src' or 'dst' specified twice");  _srcdst = x;}voidIPFilter::Primitive::set_transp_proto(int x, ErrorHandler *errh){  if (_transp_proto != UNKNOWN && _transp_proto != x)    errh->error("transport protocol specified twice");  _transp_proto = x;}intIPFilter::Primitive::set_mask(uint32_t full_mask, int shift, uint32_t provided_mask, ErrorHandler *errh){    uint32_t data = _u.u;    uint32_t this_mask = (provided_mask ? provided_mask : full_mask);    if ((this_mask & full_mask) != this_mask)	return errh->error("mask 0x%X out of range (0-0x%X)", provided_mask, full_mask);    if (_op == OP_GT || _op == OP_LT) {	// Check for comparisons that are always true or false.	if ((_op == OP_LT && (data == 0 || data > this_mask))	    || (_op == OP_GT && data >= this_mask)) {	    bool will_be = (_op == OP_LT && data > this_mask ? !_op_negated : _op_negated);	    errh->warning("relation '%s %u' is always %s (range 0-%u)", unparse_op().cc(), data, (will_be ? "true" : "false"), this_mask);	    _u.u = _mask.u = 0;	    _op_negated = !will_be;	    _op = OP_EQ;	    return 0;	}	// value < X == !(value > (X - 1))	if (_op == OP_LT) {	    _u.u--;	    _op_negated = !_op_negated;	    _op = OP_GT;	}	_u.u = (_u.u << shift) | ((1 << shift) - 1);	_mask.u = (this_mask << shift) | ((1 << shift) - 1);	// Want (_u.u & _mask.u) == _u.u.	// So change 'tcp[0] & 5 > 2' into the equivalent 'tcp[0] & 5 > 1':	// find the highest bit in _u that is not set in _mask,	// and turn on all lower bits.	if ((_u.u & _mask.u) != _u.u) {	    uint32_t full_mask_u = (full_mask << shift) | ((1 << shift) - 1);	    uint32_t missing_bits = (_u.u & _mask.u) ^ (_u.u & full_mask_u);	    uint32_t add_mask = 0xFFFFFFFFU >> ffs_msb(missing_bits);	    _u.u = (_u.u | add_mask) & _mask.u;	}	return 0;    }    if (data > full_mask)	return errh->error("value %u out of range (0-%u)", data, full_mask);    _u.u = data << shift;    _mask.u = this_mask << shift;    return 0;}StringIPFilter::Primitive::unparse_type(int srcdst, int type){  StringAccum sa;    switch (srcdst) {   case SD_SRC: sa << "src "; break;   case SD_DST: sa << "dst "; break;   case SD_OR: sa << "src or dst "; break;   case SD_AND: sa << "src and dst "; break;  }    switch (type) {   case TYPE_NONE: sa << "<none>"; break;   case TYPE_HOST: sa << "ip host"; break;   case TYPE_PROTO: sa << "proto"; break;   case TYPE_IPFRAG: sa << "ip frag"; break;   case TYPE_PORT: sa << "port"; break;   case TYPE_TCPOPT: sa << "tcp opt"; break;   case TYPE_NET: sa << "ip net"; break;   case TYPE_IPUNFRAG: sa << "ip unfrag"; break;   case TYPE_IPECT: sa << "ip ect"; break;   case TYPE_IPCE: sa << "ip ce"; break;   default:    if (type & TYPE_FIELD) {      switch (type) {       case FIELD_IPLEN: sa << "ip len"; break;       case FIELD_ID: sa << "ip id"; break;       case FIELD_VERSION: sa << "ip vers"; break;       case FIELD_HL: sa << "ip hl"; break;       case FIELD_TOS: sa << "ip tos"; break;       case FIELD_DSCP: sa << "ip dscp"; break;       case FIELD_TTL: sa << "ip ttl"; break;       case FIELD_TCP_WIN: sa << "tcp win"; break;       case FIELD_ICMP_TYPE: sa << "icmp type"; break;       default:	if (type & FIELD_PROTO_MASK)	  sa << unparse_transp_proto((type & FIELD_PROTO_MASK) >> FIELD_PROTO_SHIFT);	else	  sa << "ip";	sa << "[...]";	break;      }    } else      sa << "<unknown type " << type << ">";    break;  }  return sa.take_string();}StringIPFilter::Primitive::unparse_transp_proto(int transp_proto){  switch (transp_proto) {   case UNKNOWN: return "";   case IP_PROTO_ICMP: return "icmp";   case IP_PROTO_IGMP: return "igmp";   case IP_PROTO_IPIP: return "ipip";   case IP_PROTO_TCP: return "tcp";   case IP_PROTO_UDP: return "udp";   case IP_PROTO_TCP_OR_UDP: return "tcpudp";   case IP_PROTO_TRANSP: return "transp";   default: return "ip proto " + String(transp_proto);  }}StringIPFilter::Primitive::unparse_type() const{  return unparse_type(_srcdst, _type);}StringIPFilter::Primitive::unparse_op() const{  if (_op == OP_GT)    return (_op_negated ? "<=" : ">");  else if (_op == OP_LT)    return (_op_negated ? ">=" : "<");  else    return (_op_negated ? "!=" : "=");}voidIPFilter::Primitive::simple_negate(){  assert(negation_is_simple());  _op_negated = !_op_negated;  if (_type == TYPE_PROTO && _mask.u == 0xFF)    _transp_proto = (_op_negated ? UNKNOWN : _u.i);}intIPFilter::Primitive::check(const Primitive &p, uint32_t provided_mask, ErrorHandler *errh){  int old_srcdst = _srcdst;  // if _type is erroneous, return -1 right away  if (_type < 0)    return -1;    // set _type if it was not specified  if (!_type) {   retry:    switch (_data) {     case TYPE_HOST:     case TYPE_NET:     case TYPE_TCPOPT:      _type = _data;      if (!_srcdst)	_srcdst = p._srcdst;      break;     case TYPE_PROTO:      _type = TYPE_PROTO;      break;           case TYPE_PORT:      _type = TYPE_PORT;      if (!_srcdst)	_srcdst = p._srcdst;      if (_transp_proto == UNKNOWN)	_transp_proto = p._transp_proto;      break;           case TYPE_INT:      if (!(p._type & TYPE_FIELD) && p._type != TYPE_PROTO && p._type != TYPE_PORT)	return errh->error("specify header field or 'port'");      _data = p._type;      goto retry;     case TYPE_NONE:      if (_transp_proto != UNKNOWN)	_type = TYPE_PROTO;      else	return errh->error("partial directive");      break;           default:      if (_data & TYPE_FIELD) {	_type = _data;	if ((_type & FIELD_PROTO_MASK) && _transp_proto == UNKNOWN)	  _transp_proto = (_type & FIELD_PROTO_MASK) >> FIELD_PROTO_SHIFT;      } else	return errh->error("unknown type '%s'", unparse_type(0, _data).cc());      break;    }  }  // check that _data and _type agree

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -