/**
|
|
* @file NATRouter.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->lastUsedPort = 0;
|
|
this->initalizeNatTable();
|
|
}
|
|
|
|
NATRouter::NATRouter(string hostname) : Node(hostname)
|
|
{
|
|
this->lastUsedPort = 0;
|
|
this->initalizeNatTable();
|
|
}
|
|
|
|
NATRouter::NATRouter(string hostname, string ip, string mask) : Node(hostname, ip, mask)
|
|
{
|
|
this->lastUsedPort = 0;
|
|
this->initalizeNatTable();
|
|
}
|
|
|
|
NATRouter::NATRouter(string hostname, string ip, string mask, string gatewayIp) : Node(hostname, ip, mask, gatewayIp)
|
|
{
|
|
this->lastUsedPort = 0;
|
|
this->initalizeNatTable();
|
|
}
|
|
|
|
int NATRouter::getFreePort()
|
|
{
|
|
if (this->lastUsedPort == NAT_TABLE_LEN-1)
|
|
this->lastUsedPort = 0;
|
|
|
|
for (int i = this->lastUsedPort+1; i<NAT_TABLE_LEN; ++i)
|
|
if (this->natTable[i].isFree())
|
|
{
|
|
this->lastUsedPort = i;
|
|
return i;
|
|
}
|
|
|
|
for (int i = 1; i<this->lastUsedPort; ++i)
|
|
if (this->natTable[i].isFree())
|
|
{
|
|
this->lastUsedPort = i;
|
|
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;
|
|
}
|
|
|
|
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)
|
|
{
|
|
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<string, int>(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;
|
|
}
|
|
|
|
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->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;
|
|
}
|
|
|
|
int NATRouter::getAllocatedPort(string srcIp, int srcPort)
|
|
{
|
|
map<string, int>::iterator it;
|
|
int pos = -1;
|
|
|
|
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; i<NAT_TABLE_LEN; ++i)
|
|
if (this->natTable[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;
|
|
}
|