INET Framework for OMNeT++/OMNEST
acl Class Reference

#include <acl.h>

Inheritance diagram for acl:
INotifiable

List of all members.

Protected Member Functions

virtual void handleMessage (cMessage *msg)
virtual void initialize (int stage)
virtual void finish ()
virtual void receiveChangeNotification (int category, const cPolymorphic *details)
virtual int numInitStages () const

Protected Attributes

NotificationBoardnotificationBoard

Private Member Functions

bool loadConfigFromXML (const char *filename)
bool processPacket (IPDatagram *packet, TACL *acl)
TACLgetRules (int gateIndex, bool dir)
bool filterPacket (TACL *acl, TIP source, TIP dest, int protocol)
bool ipIsEqual (TIP *ip, TIP *packet)
bool portIsEqual (TIP *ip, TIP *packet)
void getAction (std::string action, TRule *rule)
void getProtocol (std::string pom, TRule *rule)
void getPort (std::string pom, std::string p_beg, std::string p_end, TIP *ip)
void andIpWithMask (TRule *rule)
IPAddress negateWildcard (IPAddress wc)

Private Attributes

std::list< TACLacls
std::list< TInterfaceinterfaces
std::list< Statstats
bool aclEnabled
int numPackets
int packetsDropped
int packetsPermitted
int packetsAllowed

Detailed Description

Definition at line 89 of file acl.h.


Member Function Documentation

void acl::andIpWithMask ( TRule rule) [private]

Definition at line 85 of file acl.cc.

{
        rule->source.ipAddr =   rule->source.ipAddr.doAnd(rule->source.netmask);
        rule->dest.ipAddr =     rule->dest.ipAddr.doAnd(rule->dest.netmask);
}
bool acl::filterPacket ( TACL acl,
TIP  source,
TIP  dest,
int  protocol 
) [private]

Definition at line 475 of file acl.cc.

{
        for (TACL_it it = acl->begin(); it != acl->end(); it++)
        {
                if (!(it->protocol == protocol || it->protocol == PROT_IP))
                  continue;
                ev << "acl::filterPacket: PROTOCOL MATCH" << endl;
                if (!ipIsEqual(&(it->source), &source))
                  continue;
                ev << "acl::filterPacket: SOURCE IP MATCH" << endl;
                if (it->protocol == PROT_UDP || it->protocol == PROT_TCP)
                {
                  if (!portIsEqual(&(it->source), &source))
                          continue;
                  else
                          ev << "acl::filterPacket: SOURCE PORT MATCH" << endl;
                }
                if (!ipIsEqual(&(it->dest), &dest))
                  continue;
                ev << "acl::filterPacket: DESTINATION IP MATCH" << endl;
                if (it->protocol == PROT_UDP || it->protocol == PROT_TCP)
                {
                  if (!portIsEqual(&(it->dest), &dest))
                          continue;
                  else
                          ev << "acl::filterPacket: DESTINATION PORT MATCH" << endl;
                }
                (*(it->used))++;
                return it->action; // if match is found with current record of ACL, action is returned
        }
        cout << "BUG" << endl;
        return false; // if no match in whole ACL is found
}
void acl::finish ( ) [protected, virtual]

Definition at line 650 of file acl.cc.

{
  /*
        cout << "IP datagrams received: " << this->numPackets << endl;
        cout << "IP packets permitted without ACL action: " << this->packetsAllowed  << endl;
        cout << "IP packets permitted by ACL action: " << this->packetsPermitted << endl;
        cout << "IP packets denied by an ACL action: " << this->packetsDropped << endl;
        for (std::list<Stat>::iterator it = this->stats.begin(); it != this->stats.end(); it++)
        {
                cout << it->text << " (" << it->used << " matches)" << endl;
        }
        cout << "--------------------------------------------------------" << endl;
        */
}
void acl::getAction ( std::string  action,
TRule rule 
) [private]

Definition at line 110 of file acl.cc.

{
        if (action == "deny")
                rule->action = A_DENY;
        else if (action == "permit")
                rule->action = A_PERMIT;
}
void acl::getPort ( std::string  pom,
std::string  p_beg,
std::string  p_end,
TIP ip 
) [private]

Definition at line 155 of file acl.cc.

{
        int p1, p2;
        stringstream ss (stringstream::in | stringstream::out);
        /* if port is given as text string, it is converted to short int number */
        if (p_beg == "ftp-data") p1 = 20;
        if (p_beg == "ftp") p1 = 21;
        if (p_beg == "telnet") p1 = 23;
        if (p_beg == "smtp") p1 = 25;
        if (p_beg == "tftp") p1 = 69;
        if ((p_beg == "www") || (p_beg == "http") || (p_beg == "www-http")) p1 = 80;
        if ((p_beg == "pop3") || (p_beg == "pop")) p1 = 110;
        if (p_beg == "snmp") p1 = 161;
        if (p_beg == "irc") p1 = 194;
        if (p_beg == "ipx") p1 = 213;
        if (p_beg == "ldap") p1 = 389;
        if (p_beg == "https") p1 = 443;

        ss << p_beg;
        ss >> p1;
        ss << p_end;
        ss >> p2;

        /* resolution of port operators*/
        if (pom == "eq")                        // EQ
                ip->port_op = PORT_EQ;
        else if (pom == "neq")          // NEQ
                ip->port_op = PORT_NEQ;
        else if (pom == "gt")           // GT
                ip->port_op = PORT_GT;
        else if (pom == "lt")           // LT
                ip->port_op = PORT_LT;
        else if (pom == "range")        // RANGE
                ip->port_op = PORT_RNG;
        else // if port operator is "" or not defined: NDEF
        {
                ip->port_op = PORT_NDEF;
        }
        switch (ip->port_op) { // based on presence of current port operator
                case PORT_EQ:
                case PORT_NEQ:
                case PORT_GT:
                case PORT_LT: // if operator is any of following [eq, neq, gt, lt]: load only one port no. from portBeg
                        ip->portBeg = p1;
                        break;
                case PORT_RNG: // if operator = RANGE, load two port number in the range of portBeg to portEnd
                        ip->portBeg = p1;
                        ip->portEnd = p2;
                        break;
                case PORT_NDEF: // if any port operator is present, port range is full range of ports [0 - 65535]
                        ip->portBeg = 0;
                        ip->portEnd = 65535;
                        break;
        }
}
void acl::getProtocol ( std::string  pom,
TRule rule 
) [private]

Definition at line 127 of file acl.cc.

{
        if (pom == "ip" || pom == "4")
                rule->protocol = PROT_IP;
        else if (pom == "tcp" || pom == "6")
                rule->protocol = PROT_TCP;
        else if (pom == "udp" || pom == "17")
                rule->protocol = PROT_UDP;
        else if (pom == "icmp" || pom == "1")
                rule->protocol = PROT_ICMP;
        else if (pom == "igmp" || pom == "2")
                rule->protocol = PROT_IGMP;
        else if (pom == "eigrp" || pom == "igrp" || pom == "88")
                rule->protocol = PROT_EIGRP;
        else if (pom == "ospf" || pom == "89")
                rule->protocol = PROT_OSPF;
}
TACL * acl::getRules ( int  gateIndex,
bool  dir 
) [private]

Definition at line 391 of file acl.cc.

{
        for (std::list<TInterface>::iterator it = this->interfaces.begin(); it != this->interfaces.end(); it++)
        {
                TInterface* _if = &(*it);
                if (_if->gateIndex == gateIndex && _if->dir == dir)
                        return _if->rules;
        }
        return NULL;
}
void acl::handleMessage ( cMessage *  msg) [protected, virtual]

Definition at line 520 of file acl.cc.

{
        cGate* gate = msg->getArrivalGate();
        string name = gate->getBaseName();
        int index = gate->getIndex();
        bool dir = true; // packet heading from networkLayer IN to interface (pres ACL); ifIn, ifOut (in == true)
        TACL* acl;

        if (name == "toNetworkLayerIn")
                dir = false; // packet heading from interface OUT to networkLayer (pres ACL); toNetworkLayerIn, toNetworkLayerOut
                                         // (out == false)
        if (!(this->aclEnabled))
        { // if ACLs part is NOT listed in XML configuration file for current router
                if (dir)
                {       /* send packet to upper layer: from interface out to networkLayer */
                        this->send(msg, "toNetworkLayerOut", index);
                        ev << "ACL DISABLED, just directly send from interface out to networkLayer" << endl;
                }
                else
                {       /* send packet to lower layer: from networkLayer out to interface */
                        this->send(msg, "ifOut", index);
                        ev << "ACL DISABLED, just directly send from networkLayer out to interface" << endl;
                }
        }
        else  /* ACL configuration part is found on current router (however, ACL list still might be empty */
        {
                acl = getRules(index, dir);  // get pointer to ACL list bound within current packet

                cMessage *copy = msg->dup(); // duplicate the message due to instability during operations with an original message

                cPacket *test = (cPacket*)(copy);
                string typ = test->getClassName();
                if (typ != "IPDatagram")
                {       // if the message is not an IP packet, message is just forwarded
                        if (dir)
                        {
                                ev << "Not an IP packet, sending directly from interface out to networkLayer" << endl;
                                this->send (msg, "toNetworkLayerOut", index);
                        }
                        else
                        {
                                ev << "Not an IP packet, sending directly from networkLayer out to interface..." << endl;
                                this->send (msg, "ifOut", index);
                        }
                }
                else // if dynamic_cast is correctly done - message is IPDatagram (an IP packet)
                {
                        this->numPackets++;
                        if (acl == NULL) // doesn't exist ACL for packet's interface and direction
                        {
                                ev << "No ACL found for this router/interface." << endl;
                                this->packetsAllowed++;
                                if (dir)
                                {       /* send packet to upper layer: from interface out to networkLayer */
                                        this->send(msg, "toNetworkLayerOut", index);
                                        ev << "+packet sent to upper layer without ACL action" << endl;
                                }
                                else
                                {       /* send packet to lower layer: from networkLayer out to interface */
                                        this->send(msg, "ifOut", index);
                                        ev << "+packet sent to lower layer without ACL action" << endl;
                                }
                        }
                        else // ACL is bound within packet's interface and direction, need to filter
                        {
                                ev << "An ACL list bound correctly for this router/interface." << endl;
                                IPDatagram *packet = dynamic_cast<IPDatagram*> (copy); // dynamic_cast is taken
                                if (processPacket(packet, acl)) // action according to ACL is "permit"
                                {
                                        if (dir)
                                        {       /* send packet to upper layer: from interface out to networkLayer */
                                            this->send(msg, "toNetworkLayerOut", index);
                                            ev << "+ACL ACTION:  PERMIT +++ from interface out to networkLayer" << endl;
                                        }
                                        else
                                        {       /* send packet to lower layer: from networkLayer out to interface */
                                                this->send(msg, "ifOut", index);
                                            ev << "+ACL ACTION:  PERMIT +++ from networkLayer out to interface" << endl;
                                        }
                                }
                                else // action according to ACL is "deny"
                                {
                                        delete msg;
                                }
                        }
                }
                delete copy;
        }
}
void acl::initialize ( int  stage) [protected, virtual]

Definition at line 616 of file acl.cc.

{
        switch (stage)
        {
                        case 0: // get access to notification board
                                notificationBoard = NotificationBoardAccess().get();
                                notificationBoard->subscribe(this, NF_INTERFACE_STATE_CHANGED);
                                break;
                        case 4: // initialization of the ACL module
                                const char *fileName = par("configFile"); // XML file name read from parameter
                                if (loadConfigFromXML(fileName)) // success loading configuration data from XML file
                                {
                                        //cout << "ACL: Configuration successfully loaded." << endl;
                                }
                                else // error loading configuration data from XML file
                                {
                                        //cout << "ACL: Error loading configuration." << endl;
                                }
                                /* initialization of ACL action counters - usage in statistics */
                                this->packetsAllowed = 0;
                                this->packetsDropped = 0;
                                this->packetsPermitted = 0;
                                this->numPackets = 0;

                                /* added class of statistics information onto Watch list */
                                WATCH_LIST(stats);
        }
}
bool acl::ipIsEqual ( TIP ip,
TIP packet 
) [private]

Definition at line 24 of file acl.cc.

{
        ev << "ACL rule, ip  : " << ip->ipAddr.str() << endl;
        ev << "ACL rule, mask: " << ip->netmask.str() << endl;
        ev << "packet, ip    : " << packet->ipAddr.str() << endl;
        ev << "packet_masked : " << packet->ipAddr.doAnd(ip->netmask).str() << endl;
        if (ip->ipAddr != (packet->ipAddr.doAnd(ip->netmask)))
        {
                ev << "IP DOESN'T MATCH" << endl;
                return false;
        }
        ev << "IP MATCH OK" << endl;
        return true;
}
bool acl::loadConfigFromXML ( const char *  filename) [private]

Definition at line 219 of file acl.cc.

{
        /* get access into Routing Table and Interface Table modules */
        IRoutingTable* rt = RoutingTableAccess().get();
        IInterfaceTable* ift = InterfaceTableAccess().get();

        /* resolution of configuration XML file according to specified filename */
        cXMLElement* document = ev.getXMLDocument(fileName);
        if (document == NULL)
        {       /* if no file with such name is provided, error is recognized */
                error("Cannot read AS configuration from file %s", fileName);
                return false;
        }

        /* try to find current router in XML on running instance of this ACL module */
        std::string routerXPath("Router[@id='");
        std::string routerId = rt->getRouterId().str();
        routerXPath += routerId;
        routerXPath += "']";

        cXMLElement* router = document->getElementByPath(routerXPath.c_str());
        if (router == NULL)
        {       /* current router configuration is completely missing in XML configuration - error */
                error("No configuration for Router ID: %s", routerId.c_str());
                this->aclEnabled = false;
                return true;
        }
        cXMLElement* ACLs = router->getFirstChildWithTag("ACLs"); // find ACL configuration part
        if (ACLs == NULL)
        {       /* ACL configuration part is missing in XML configuration */
                //cout << "ACL: ACL is NOT ENABLED on Router id = " << routerId.c_str() << endl;
                this->aclEnabled = false; // ACL indicator is FALSE
                return true;
        }
        cXMLElement* ACL = ACLs->getFirstChildWithTag("ACL");
        if (ACL == NULL)
        {
                //cout << "ACL: ACL is NOT ENABLED on Router id = " << routerId.c_str() << endl;
                this->aclEnabled = false;
                return true;
        }
        else
        {
                this->aclEnabled = true;
                //cout << "ACL: Loading ACL entries for Router id = " << routerId.c_str() << "\n";
        }
        while (ACL != NULL)
        {
                cXMLElement *entry = ACL->getFirstChildWithTag("entry");
                TACL _acl;

                while (entry != NULL)
                {
                        cXMLElement *leaf = entry->getFirstChild();
                        TRule rule;
                        Stat stat;
                        stat.used = 0;

                        std::string src_port_op = "";
                        std::string src_port_beg = "";
                        std::string src_port_end = "";
                        std::string dst_port_op = "";
                        std::string dst_port_beg = "";
                        std::string dst_port_end = "";

                        /* processing current leaf under XML node <entry> */
                        while (leaf != NULL)
                        {
                                const char* tagName = leaf->getTagName();
                                const char* value = leaf->getNodeValue();

                                if (strcmp(tagName, "action") == 0)
                                        getAction(value, &rule);
                                else if (strcmp(tagName, "IP_src") == 0)
                                        rule.source.ipAddr.set(value);
                                else if (strcmp(tagName, "WC_src") == 0)
                                        rule.source.netmask = negateWildcard(IPAddress(value));
                                else if (strcmp(tagName, "protocol") == 0)
                                        getProtocol(value, &rule);
                                else if (strcmp(tagName, "IP_dst") == 0)
                                        rule.dest.ipAddr.set(value);
                                else if (strcmp(tagName, "WC_dst") == 0)
                                        rule.dest.netmask = negateWildcard(IPAddress(value));
                                else if (strcmp(tagName, "port_op_src") == 0)
                                        src_port_op = value;
                                else if (strcmp(tagName, "port_beg_src") == 0)
                                        src_port_beg = value;
                                else if (strcmp(tagName, "port_end_src") == 0)
                                        src_port_end = value;
                                else if (strcmp(tagName, "port_op_dst") == 0)
                                        dst_port_op = value;
                                else if (strcmp(tagName, "port_beg_dst") == 0)
                                        dst_port_beg = value;
                                else if (strcmp(tagName, "port_end_dst") == 0)
                                        dst_port_end = value;
                                else if (strcmp(tagName, "orig") == 0)
                                        stat.text = value;
                                leaf = leaf->getNextSibling();
                        }

                        /* AND (&) IP ADDRESS WITH NETWORK MASK IN CURRENT ACL RULE */
                        andIpWithMask(&rule);
                        /* PROCESS PORT INFORMATION FROM XML CONFIGURATION FILE */
                        getPort(src_port_op, src_port_beg, src_port_end, &rule.source);
                        getPort(dst_port_op, dst_port_beg, dst_port_end, &rule.dest);

                        /* generate statistics for processed rule */
                        stats.push_back(stat);
                        Stat* pStat = &this->stats.back();
                        rule.used = &(pStat->used);

                        _acl.push_back(rule); // processed rule is added at the end of ACL list

                        entry = entry->getNextSiblingWithTag("entry");
                }
                /* create default rule at the end of the ACL list - deny ip any any */
                TRule rule;
                Stat stat;
                stat.used = 0;
                rule.action = A_DENY;
                rule.protocol = PROT_IP;
                stat.text = "access-list deny ip any any";
                rule.source.ipAddr.set("0.0.0.0");
                rule.dest.ipAddr.set("0.0.0.0");
                rule.source.netmask.set("0.0.0.0");
                rule.dest.netmask.set("0.0.0.0");
                getPort("", "", "", &rule.source);
                getPort("", "", "", &rule.dest);

                /* generate statistics for the default rule*/
                stats.push_back(stat);
                Stat* pStat = &this->stats.back();
                rule.used = &(pStat->used);

                _acl.push_back(rule); // implicit rule is finally added at the end of the list

                this->acls.push_back(_acl); // current ACL list is added at the end of ACLs (list of lists)

                cXMLElement *interfaces = ACL->getFirstChildWithTag("interfaces");
                cXMLElement *interface  = interfaces->getFirstChildWithTag("interface");

                /* processing interface information - binding ACL list to interface and direction */
                while (interface != NULL)
                {
                        InterfaceEntry *targetInt = ift->getInterfaceByName(interface->getNodeValue());
                        TInterface _if;

                        _if.gateIndex = targetInt->getNetworkLayerGateIndex();
                        if (interface->getAttribute("dir") == std::string("in"))
                                _if.dir = true;
                        else
                                _if.dir = false;
                        _if.rules = &this->acls.back();

                        this->interfaces.push_back(_if);
                        interface = interface->getNextSibling();
                }

                ACL = ACL->getNextSiblingWithTag("ACL");
        }
        return true;
}

Definition at line 97 of file acl.cc.

{
        return (IPAddress(~(wc.getInt())));
}
virtual int acl::numInitStages ( ) const [inline, protected, virtual]

Definition at line 120 of file acl.h.

{ EV << "numinitstages\n"; return 5;}
bool acl::portIsEqual ( TIP ip,
TIP packet 
) [private]

Definition at line 48 of file acl.cc.

{
        switch (ip->port_op) {
                case PORT_EQ:
                        if (ip->portBeg == packet->portBeg)
                                return true;
                        break;
                case PORT_NEQ:
                        if (ip->portBeg != packet->portBeg)
                                return true;
                        break;
                case PORT_GT:
                        if (ip->portBeg < packet->portBeg)
                                return true;
                        break;
                case PORT_LT:
                        if (ip->portBeg > packet->portBeg)
                                return true;
                        break;
                case PORT_RNG:
                case PORT_NDEF:
                        if ((ip->portBeg <= packet->portBeg) && (ip->portEnd >= packet->portBeg))
                                return true;
                        break;
                default:
                        cout << "BUG" << endl;
        }
        return false;
}
bool acl::processPacket ( IPDatagram packet,
TACL acl 
) [private]

Definition at line 413 of file acl.cc.

{
        TIP source, dest;
        source.ipAddr = packet->getSrcAddress();
        dest.ipAddr = packet->getDestAddress();
        int protocol = packet->getTransportProtocol();

        ev << "Packet Source IP Address: " << source.ipAddr.str() << endl;
        ev << "Packet Dest.  IP Address: " << dest.ipAddr.str() << endl;
        ev << "Packet Protocol ID      : " << protocol << endl;

        UDPPacket *udppacket;
        TCPSegment *tcppacket;

        switch (protocol)
        {
                case PROT_UDP: // if protocol is UDP, ports need to be checked
                        udppacket = dynamic_cast<UDPPacket *> (packet->decapsulate());
                        source.portBeg = udppacket->getSourcePort();
                        ev << "UDP packet, source port: " << source.portBeg << endl;
                        dest.portBeg = udppacket->getDestinationPort();
                        ev << "UDP packet, dest.  port: " << dest.portBeg << endl;
                        delete udppacket;
                        break;
                case PROT_TCP: // if protocol is TCP, ports need to be checked
                        tcppacket = dynamic_cast<TCPSegment *> (packet->decapsulate());
                        source.portBeg = tcppacket->getSrcPort();
                        ev << "TCP packet, source port: " << source.portBeg << endl;
                        dest.portBeg = tcppacket->getDestPort();
                        ev << "TCP packet, dest.  port: " << dest.portBeg << endl;
                        delete tcppacket;
                        break;
                default:
                        ev << "Protocol is other than TCP or UDP, ports don't need to be checked..." << endl;
                        break;
        }
        if (filterPacket(acl, source, dest, protocol))
        {
                // rule is 'permit'
                this->packetsPermitted++;
                return true;
        }
        else
        {
            ev << "- ACL ACTION:  DENY, packet dropped   ---" << endl;
            this->packetsDropped++;
                return false;
        }
}
virtual void acl::receiveChangeNotification ( int  category,
const cPolymorphic *  details 
) [inline, protected, virtual]

Called by the NotificationBoard whenever a change of a category occurs to which this client has subscribed.

Implements INotifiable.

Definition at line 119 of file acl.h.

{}

Member Data Documentation

bool acl::aclEnabled [private]

Definition at line 108 of file acl.h.

std::list<TACL> acl::acls [private]

Definition at line 105 of file acl.h.

std::list<TInterface> acl::interfaces [private]

Definition at line 106 of file acl.h.

Definition at line 118 of file acl.h.

int acl::numPackets [private]

Definition at line 109 of file acl.h.

int acl::packetsAllowed [private]

Definition at line 112 of file acl.h.

int acl::packetsDropped [private]

Definition at line 110 of file acl.h.

int acl::packetsPermitted [private]

Definition at line 111 of file acl.h.

std::list<Stat> acl::stats [private]

Definition at line 107 of file acl.h.


The documentation for this class was generated from the following files: