/* * NATItem.cpp * * Created on: 11-01-2017 * Author: Piotr Dergun */ #include "NATRouter.h" void NATRouter::initalizeNatTable() { try { natTable = new NATItem[NAT_TABLE_LEN]; } catch (bad_alloc &ba) { cerr << "Nie mozna zaalokowac pamieci dla tablicy NAT!" << endl; exit(1); } } NATRouter::NATRouter() { this->initalizeNatTable(); } NATRouter::NATRouter(string hostname) : Node(hostname) { this->initalizeNatTable(); } NATRouter::NATRouter(string hostname, string ip, string mask) : Node(hostname, ip, mask) { this->initalizeNatTable(); } NATRouter::NATRouter(string hostname, string ip, string mask, string gatewayIp) : Node(hostname, ip, mask, gatewayIp) { this->initalizeNatTable(); } int NATRouter::getFreePort() { if (this->lastUsedPort == NAT_TABLE_LEN-1) this->lastUsedPort = 0; //if (this->natTable[this->lastUsedPort+1].isFree()) // return ++this->lastUsedPort; for (int i = this->lastUsedPort+1; inatTable[i].isFree()) { this->lastUsedPort = i; return i; } for (int i = 1; ilastUsedPort; ++i) if (this->natTable[i].isFree()) { this->lastUsedPort = i; return i; } /* for (int i=1; inatTable[i].isFree()) return i; */ return -1; // nie ma żadnego wolnego portu } NATRouter::~NATRouter() { if (natTable) delete [] natTable; } void NATRouter::onRecv() { while (true) { Packet p = this->recv(); stringstream s; if (p.getSrcPort() != 0) { // jezeli pakiet idzie z jednego wezla do drugiego w danej possieci to odeslij mu "jak switch" if (this->calculateNetwork(p.getDstIp(), this->getMask()) == this->getNetwork() && p.getDstIp() != this->getIp()) { this->send(p, true); } else if (p.getDstIp() != this->getIp() && p.getDstIp() != this->getWanIp()) { this->sNAT(&p); } else if (p.getDstIp() == this->getWanIp() && !this->natTable[p.getDstPort()].isFree()) { this->dNAT(&p); } else { // TUTAJ ew. implementacja obslugi pakietu adresowanego do routera } this->delay(); } else { #ifndef DEBUG this->print("onRecv() sleeping..."); #endif } this->delay(); } } void NATRouter::setWanIp(string wanIp) { this->netWanConf.ip = wanIp; this->setWanNetwork(); } void NATRouter::setWanMask(string wanMask) { this->netWanConf.mask = wanMask; this->setWanNetwork(); } void NATRouter::setWanGatewayIp(string wanGatewayIp) { this->netWanConf.gatewayIp = wanGatewayIp; } string NATRouter::getWanIp() { return this->netWanConf.ip; } string NATRouter::getWanMask() { return this->netWanConf.mask; } /* * funkcja SNAT zapisuje w tablicy NAT * numer portu zrodlowego komputera z LAN * oraz jego IP i przeksztalca pakiet, zmieniajac * zrodlowy IP na IP zewn. routera oraz wolny * port z tablicy NAT. Jezeli portu nie ma to funkcja * czeka, az sie zwolni */ void NATRouter::sNAT(Packet *packet) { int port; NATItem *natItem; bool allocated = false; stringstream ss; // mozliwe, ze juz port zostal zaalokowany, to trzeba wykorzystac port = this->getAllocatedPort(packet->getSrcIp(), packet->getSrcPort()); if (port == -1) while ((port = this->getFreePort()) == -1) { //TESTOWO this->print("NAT table full, waiting 1s", true); this->delay(1); } else allocated = true; // wstawiam do tablicy NAT info ze port zarezerowany na odbior natItem = &this->natTable[port]; natItem->setIp(packet->getSrcIp()); natItem->setPort(packet->getSrcPort()); if (allocated) natItem->increaseTimeout(15); else natItem->setTimeout(15); ss << packet->getSrcIp() << ":" << packet->getSrcPort(); if (!allocated) this->natHelper.insert(pair(ss.str(), port)); ss.str(""); ss << "SNAT " << packet->getSrcIp() << ":" << packet->getSrcPort() << " --> " << this->getWanIp() << ":" << port; packet->setSrcIp(this->getWanIp()); // zamieniam IP lokalne na WAN'owe packet->setSrcPort(port); // zamieniam port lokalny na WAN'owy - z tablicy NAT this->print(ss.str(), true); this->delay(); this->send(*packet, true); // wysylam dalej natItem = NULL; } /* * funkcja DNAT ma za zadanie znalezc w tablicy NAT * port i adres IP wezla na ktory ma wrocic odpowiedz * z sieci Internet (z zewnatrz), a takze przedluzyc * czas zycia tego portu */ void NATRouter::dNAT(Packet* packet) { NATItem *natItem = &this->natTable[packet->getDstPort()]; stringstream ss; ss << "DNAT " << packet->getDstIp() << ":" << packet->getDstPort() << " --> " << natItem->getIp() << ":" << natItem->getPort(); packet->setDstIp(natItem->getIp()); // zamieniam IP lokalne na WAN'owe packet->setDstPort(natItem->getPort()); // zamieniam port NAT na lokalny wezla //natItem->free(); // zwalniam port w routerze natItem->increaseTimeout(5); // podbijam o kolejne 5 sekund skoro transmisja trwa this->print(ss.str()); this->delay(); this->send(*packet, true); // wysylam dalej natItem = NULL; } void NATRouter::setWanNetwork() { this->netWanConf.network = this->calculateNetwork(this->getWanIp(), this->getWanMask()); } string NATRouter::getWanNetwork() { return this->netWanConf.network; } /* * funkcja szuka aktywnego zaalokowanego portu (aktywna * transmisja) w tablicy NAT dla pary (srcIp:srcPort) */ int NATRouter::getAllocatedPort(string srcIp, int srcPort) { map::iterator it; int pos = -1; /*for (int i=1; inatTable[i].getIp() == srcIp && this->natTable[i].getPort() == srcPort) return i; */ stringstream ss; ss << srcIp << ":" << srcPort; it = this->natHelper.find(ss.str()); if (it != this->natHelper.end()) { // sprawdz czy wpis o podanym IP z nat nie zostal napisany (referencja nieaktualna) if (this->natTable[it->second].getIp() != srcIp || this->natTable[it->second].getPort() != srcPort) this->natHelper.erase(it); else pos = it->second; } return pos; } void NATRouter::freePorts() { stringstream ss; int i, ports, peak=NAT_TABLE_LEN-1; Log portsLog; string name = "NAT"; portsLog.setLogParams(3, GREEN, "\t\t"); portsLog.setObjectName(&name); portsLog.setDelay(100000); while(true) { ports = 0; ss.str(""); for (i=1; inatTable[i].isFree()) ++ports; if (ports < peak) peak = ports; ss << "Free/Reserved:\t" << ports << " (" << peak << ")/" << (NAT_TABLE_LEN-ports-1) << " (" << (NAT_TABLE_LEN-peak-1) << ")"; // poprawka na nieuzywany port 0 portsLog.print(ss.str()); portsLog.printProgressBar(4, 4, "Utilization", (float)(NAT_TABLE_LEN-ports-1)/(NAT_TABLE_LEN-1)); portsLog.delay(); } } string NATRouter::getWanGatewayIp() { return this->netWanConf.gatewayIp; }