1
0
mirror of https://github.com/fwbuilder/fwbuilder synced 2026-03-24 20:27:22 +01:00
fwbuilder/src/fwcompiler/NATCompiler.cpp
2008-05-27 18:12:41 +00:00

818 lines
23 KiB
C++

/*
Firewall Builder
Copyright (C) 2002 NetCitadel, LLC
Author: Vadim Kurland vadim@vk.crocodile.org
$Id: NATCompiler.cpp 974 2006-09-09 05:02:58Z vkurland $
This program is free software which we release under the GNU General Public
License. You may redistribute and/or modify this program under the terms
of that 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.
To get a copy of the GNU General Public License, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <assert.h>
#include "NATCompiler.h"
#include "fwbuilder/NAT.h"
#include "fwbuilder/Rule.h"
#include "fwbuilder/InterfacePolicy.h"
#include "fwbuilder/Firewall.h"
#include "fwbuilder/RuleSet.h"
#include "fwbuilder/InetAddr.h"
#include "fwbuilder/Interface.h"
#include "fwbuilder/Network.h"
#include "fwbuilder/FWObjectDatabase.h"
#include "fwbuilder/RuleElement.h"
#include <iostream>
#include <iomanip>
#include <sstream>
using namespace fwcompiler;
using namespace libfwbuilder;
using namespace std;
int NATCompiler::prolog()
{
Compiler::prolog();
FWObject *nat=fw->getFirstByType(NAT::TYPENAME);
assert(nat);
combined_ruleset = new NAT();
fw->add( combined_ruleset );
temp_ruleset = new NAT(); // working copy of the policy
fw->add( temp_ruleset );
/*
* build combined policy by collapsing all the rules together.
* store ID of the interface in each rule of interface policy.
*
* also calculate global numbers for all rules and store them, too.
* These are used to detect rule shadowing.
*/
int global_num=0;
// list<FWObject*> l3=nat->getByType(NATRule::TYPENAME);
// for (list<FWObject*>::iterator j=l3.begin(); j!=l3.end(); ++j) {
FWObject *ruleset = source_ruleset;
if (ruleset == NULL) ruleset = nat;
for (FWObject::iterator i=ruleset->begin(); i!=ruleset->end(); i++)
{
Rule *r= Rule::cast(*i);
if (r->isDisabled()) continue;
r->setInterfaceId("");
r->setLabel( createRuleLabel("NAT", r->getPosition()) );
r->setAbsRuleNumber(global_num); global_num++;
r->setUniqueId( r->getId() );
combined_ruleset->add( r );
}
initialized=true;
return combined_ruleset->size();
}
bool NATCompiler::checkForShadowing(const NATRule &r1,const NATRule &r2)
{
Address *osrc1=getFirstOSrc(&r1);
Address *odst1=getFirstODst(&r1);
Service *osrv1=getFirstOSrv(&r1);
Address *osrc2=getFirstOSrc(&r2);
Address *odst2=getFirstODst(&r2);
Service *osrv2=getFirstOSrv(&r2);
if (osrc1==NULL || odst1==NULL || osrv1==NULL)
throw FWException("Can not compare rules because rule "+r1.getLabel()+" has a group in one of its elements. Aborting.");
if (osrc2==NULL || odst2==NULL || osrv2==NULL)
throw FWException("Can not compare rules because rule "+r2.getLabel()+" has a group in one of its elements. Aborting.");
return ( fwcompiler::checkForShadowing(*osrc1, *osrc2) &&
fwcompiler::checkForShadowing(*odst1, *odst2) &&
fwcompiler::checkForShadowing(*osrv1, *osrv2) );
// if ( (*osrc2 <= *osrc1) && (*odst2 <= *odst1) && (*osrv2 <= *osrv1) ) return 1;
return false;
}
/*
* TODO: implement this
*/
bool NATCompiler::cmpRules(const NATRule&, const NATRule&)
{
return false;
}
bool NATCompiler::classifyNATRule::processNext()
{
NATRule *rule=getNext(); if (rule==NULL) return false;
tmp_queue.push_back(rule);
if (rule->getRuleType()!=NATRule::Unknown) return true;
RuleElementTDst *tdstre=rule->getTDst();
// Address *osrc=compiler->getFirstOSrc(rule);
// Address *odst=compiler->getFirstODst(rule);
Service *osrv=compiler->getFirstOSrv(rule);
Address *tsrc=compiler->getFirstTSrc(rule);
Address *tdst=compiler->getFirstTDst(rule);
Service *tsrv=compiler->getFirstTSrv(rule);
if ( tsrc->isAny() && tdst->isAny() && tsrv->isAny() )
{
rule->setRuleType(NATRule::NONAT);
return true;
}
if ( ! tsrc->isAny() && tdst->isAny() )
{
if ( Network::isA(tsrc) )
/*
* this is Netnat rule ( NETMAP in iptables)
* we always do additional sanity checks in VerifyRules
*/
rule->setRuleType(NATRule::SNetnat);
else
rule->setRuleType(NATRule::SNAT);
return true;
}
if ( tsrc->isAny() && ! tdst->isAny() )
{
/* this is load balancing rule if there are multiple objects in TDst */
if ( tdstre->size()>1 ) rule->setRuleType(NATRule::LB);
else
{
if ( Network::isA(tdst) )
/*
* this is Netnat rule ( NETMAP in iptables)
* we always do additional sanity checks in VerifyRules
*/
rule->setRuleType(NATRule::DNetnat);
else {
/*
* treat it as redirect only if TDst is a firewall object. Use DNAT
* if it is interface or an address; this allows for "redirects" to specific
* interface on the firewall which comes useful for example if http proxy is
* running only on internal interface.
*/
if ( tdst->getId()==compiler->fw->getId()) rule->setRuleType(NATRule::Redirect);
else rule->setRuleType(NATRule::DNAT);
// if ( compiler->complexMatch(tdst,compiler->fw) ) rule->setRuleType(NATRule::Redirect);
// else rule->setRuleType(NATRule::DNAT);
}
}
return true;
}
/*
* SDNAT rule is rather special. We should split it onto two normal
* rules, one SNAT and another DNAT and run this rule processor again
* for each. This algorithm should be implemented for each platform
* separately. Platforms where it does not seem possible to implement
* at all should catch SDNAT rules and abort in their own
* verifyNATRule processor.
*/
if ( ! tsrc->isAny() && ! tdst->isAny() )
{
rule->setRuleType(NATRule::SDNAT);
return true;
}
if ( !( *osrv == *tsrv ) ) // have operator==, but do not have operator!=
{
rule->setRuleType(NATRule::DNAT);
return true;
}
throw FWException("Unsupported NAT rule: "+rule->getLabel());
return false;
}
bool NATCompiler::ExpandMultipleAddresses::processNext()
{
NATRule *rule=getNext(); if (rule==NULL) return false;
tmp_queue.push_back(rule);
RuleElement *rel;
if (rule->getRuleType()==NATRule::NONAT ||
rule->getRuleType()==NATRule::Return)
{
rel=rule->getOSrc(); assert(rel); compiler->_expandAddr(rule,rel);
rel=rule->getODst(); assert(rel); compiler->_expandAddr(rule,rel);
}
if (rule->getRuleType()==NATRule::SNAT)
{
rel=rule->getOSrc(); assert(rel); compiler->_expandAddr(rule,rel);
rel=rule->getODst(); assert(rel); compiler->_expandAddr(rule,rel);
rel=rule->getTSrc(); assert(rel); compiler->_expandAddr(rule,rel);
rel=rule->getTDst(); assert(rel); compiler->_expandAddr(rule,rel);
}
if (rule->getRuleType()==NATRule::DNAT)
{
rel=rule->getOSrc(); assert(rel); compiler->_expandAddr(rule,rel);
rel=rule->getODst(); assert(rel); compiler->_expandAddr(rule,rel);
rel=rule->getTSrc(); assert(rel); compiler->_expandAddr(rule,rel);
rel=rule->getTDst(); assert(rel); compiler->_expandAddr(rule,rel);
}
if (rule->getRuleType()==NATRule::Redirect)
{
rel=rule->getOSrc(); assert(rel); compiler->_expandAddr(rule,rel);
rel=rule->getODst(); assert(rel); compiler->_expandAddr(rule,rel);
rel=rule->getTSrc(); assert(rel); compiler->_expandAddr(rule,rel);
}
return true;
}
bool NATCompiler::ExpandAddressRanges::processNext()
{
NATRule *rule=getNext(); if (rule==NULL) return false;
tmp_queue.push_back(rule);
RuleElement *rel;
rel=rule->getOSrc(); assert(rel);
compiler->_expandAddressRanges(rule,rel);
rel=rule->getODst(); assert(rel);
compiler->_expandAddressRanges(rule,rel);
rel=rule->getTSrc(); assert(rel);
compiler->_expandAddressRanges(rule,rel);
rel=rule->getTDst(); assert(rel);
compiler->_expandAddressRanges(rule,rel);
return true;
}
bool NATCompiler::ExpandGroups::processNext()
{
NATRule *rule=getNext(); if (rule==NULL) return false;
tmp_queue.push_back(rule);
RuleElement *osrc=rule->getOSrc(); assert(osrc);
RuleElement *odst=rule->getODst(); assert(odst);
RuleElement *osrv=rule->getOSrv(); assert(osrv);
RuleElement *tsrc=rule->getTSrc(); assert(tsrc);
RuleElement *tdst=rule->getTDst(); assert(tdst);
RuleElement *tsrv=rule->getTSrv(); assert(tsrv);
compiler->expandGroupsInRuleElement(osrc);
compiler->expandGroupsInRuleElement(odst);
compiler->expandGroupsInRuleElement(osrv);
compiler->expandGroupsInRuleElement(tsrc);
compiler->expandGroupsInRuleElement(tdst);
compiler->expandGroupsInRuleElement(tsrv);
return true;
}
bool NATCompiler::checkForUnnumbered::processNext()
{
NATRule *rule=getNext(); if (rule==NULL) return false;
if ( compiler->catchUnnumberedIfaceInRE( rule->getOSrc() ) ||
compiler->catchUnnumberedIfaceInRE( rule->getODst() ) ||
compiler->catchUnnumberedIfaceInRE( rule->getTSrc() ) ||
compiler->catchUnnumberedIfaceInRE( rule->getTDst() ) )
compiler->abort("Can not use unnumbered interfaces in rules. Rule "+rule->getLabel());
tmp_queue.push_back(rule);
return true;
}
bool NATCompiler::ConvertToAtomicForOriginal::processNext()
{
NATRule *rule=getNext(); if (rule==NULL) return false;
RuleElementOSrc *osrc=rule->getOSrc(); assert(osrc);
RuleElementODst *odst=rule->getODst(); assert(odst);
RuleElementOSrv *osrv=rule->getOSrv(); assert(osrv);
for (FWObject::iterator i1=osrc->begin(); i1!=osrc->end(); ++i1)
{
for (FWObject::iterator i2=odst->begin(); i2!=odst->end(); ++i2)
{
for (FWObject::iterator i3=osrv->begin(); i3!=osrv->end(); ++i3)
{
NATRule *r = NATRule::cast(
compiler->dbcopy->create(NATRule::TYPENAME) );
r->duplicate(rule);
compiler->temp_ruleset->add(r);
FWObject *s;
s=r->getOSrc(); assert(s);
s->clearChildren();
s->add( *i1 );
s=r->getODst(); assert(s);
s->clearChildren();
s->add( *i2 );
s=r->getOSrv(); assert(s);
s->clearChildren();
s->add( *i3 );
tmp_queue.push_back(r);
}
}
}
return true;
}
bool NATCompiler::ConvertToAtomicForAddresses::processNext()
{
NATRule *rule=getNext(); if (rule==NULL) return false;
RuleElementOSrc *osrc=rule->getOSrc(); assert(osrc);
RuleElementODst *odst=rule->getODst(); assert(odst);
RuleElementOSrv *osrv=rule->getOSrv(); assert(osrv);
RuleElementTSrc *tsrc=rule->getTSrc(); assert(tsrc);
RuleElementTDst *tdst=rule->getTDst(); assert(tdst);
RuleElementTSrv *tsrv=rule->getTSrv(); assert(tsrv);
for (FWObject::iterator i1=osrc->begin(); i1!=osrc->end(); ++i1)
{
for (FWObject::iterator i2=odst->begin(); i2!=odst->end(); ++i2)
{
for (FWObject::iterator i4=tsrc->begin(); i4!=tsrc->end(); ++i4)
{
for (FWObject::iterator i5=tdst->begin(); i5!=tdst->end(); ++i5)
{
NATRule *r = NATRule::cast(
compiler->dbcopy->create(NATRule::TYPENAME) );
r->duplicate(rule);
compiler->temp_ruleset->add(r);
FWObject *s;
s=r->getOSrc(); assert(s);
s->clearChildren();
s->add( *i1 );
s=r->getODst(); assert(s);
s->clearChildren();
s->add( *i2 );
// s=r->getOSrv(); assert(s);
// *s=*osrv;
s=r->getTSrc(); assert(s);
s->clearChildren();
s->add( *i4 );
s=r->getTDst(); assert(s);
s->clearChildren();
s->add( *i5 );
// s=r->getTSrv(); assert(s);
// *s=*tsrv;
tmp_queue.push_back(r);
}
}
}
}
return true;
}
bool NATCompiler::ConvertToAtomicForTSrc::processNext()
{
NATRule *rule=getNext(); if (rule==NULL) return false;
RuleElementTSrc *tsrc=rule->getTSrc(); assert(tsrc);
for (FWObject::iterator i1=tsrc->begin(); i1!=tsrc->end(); ++i1)
{
NATRule *r = NATRule::cast(
compiler->dbcopy->create(NATRule::TYPENAME) );
r->duplicate(rule);
compiler->temp_ruleset->add(r);
FWObject *s;
s=r->getTSrc(); assert(s);
s->clearChildren();
s->add( *i1 );
tmp_queue.push_back(r);
}
return true;
}
bool NATCompiler::ConvertToAtomicForTDst::processNext()
{
NATRule *rule=getNext(); if (rule==NULL) return false;
RuleElementTDst *tsrc=rule->getTDst(); assert(tsrc);
for (FWObject::iterator i1=tsrc->begin(); i1!=tsrc->end(); ++i1)
{
NATRule *r = NATRule::cast(
compiler->dbcopy->create(NATRule::TYPENAME) );
r->duplicate(rule);
compiler->temp_ruleset->add(r);
FWObject *s;
s=r->getTDst(); assert(s);
s->clearChildren();
s->add( *i1 );
tmp_queue.push_back(r);
}
return true;
}
bool NATCompiler::ConvertToAtomicForTSrv::processNext()
{
NATRule *rule=getNext(); if (rule==NULL) return false;
RuleElementTSrv *tsrc=rule->getTSrv(); assert(tsrc);
for (FWObject::iterator i1=tsrc->begin(); i1!=tsrc->end(); ++i1)
{
NATRule *r = NATRule::cast(
compiler->dbcopy->create(NATRule::TYPENAME) );
r->duplicate(rule);
compiler->temp_ruleset->add(r);
FWObject *s;
s=r->getTSrv(); assert(s);
s->clearChildren();
s->add( *i1 );
tmp_queue.push_back(r);
}
return true;
}
bool NATCompiler::ConvertToAtomic::processNext()
{
NATRule *rule=getNext(); if (rule==NULL) return false;
RuleElementOSrc *osrc=rule->getOSrc(); assert(osrc);
RuleElementODst *odst=rule->getODst(); assert(odst);
RuleElementOSrv *osrv=rule->getOSrv(); assert(osrv);
RuleElementTSrc *tsrc=rule->getTSrc(); assert(tsrc);
RuleElementTDst *tdst=rule->getTDst(); assert(tdst);
RuleElementTSrv *tsrv=rule->getTSrv(); assert(tsrv);
for (FWObject::iterator i1=osrc->begin(); i1!=osrc->end(); ++i1)
{
for (FWObject::iterator i2=odst->begin(); i2!=odst->end(); ++i2)
{
for (FWObject::iterator i3=osrv->begin(); i3!=osrv->end(); ++i3)
{
for (FWObject::iterator i4=tsrc->begin(); i4!=tsrc->end(); ++i4)
{
for (FWObject::iterator i5=tdst->begin(); i5!=tdst->end(); ++i5)
{
for (FWObject::iterator i6=tsrv->begin(); i6!=tsrv->end(); ++i6)
{
NATRule *r = NATRule::cast(
compiler->dbcopy->create(NATRule::TYPENAME) );
r->duplicate(rule);
compiler->temp_ruleset->add(r);
FWObject *s;
s=r->getOSrc(); assert(s);
s->clearChildren();
s->add( *i1 );
s=r->getODst(); assert(s);
s->clearChildren();
s->add( *i2 );
s=r->getOSrv(); assert(s);
s->clearChildren();
s->add( *i3 );
s=r->getTSrc(); assert(s);
s->clearChildren();
s->add( *i4 );
s=r->getTDst(); assert(s);
s->clearChildren();
s->add( *i5 );
s=r->getTSrv(); assert(s);
s->clearChildren();
s->add( *i6 );
tmp_queue.push_back(r);
}
}
}
}
}
}
return true;
}
bool NATCompiler::MACFiltering::checkRuleElement(RuleElement *re)
{
bool res=true;
std::list<FWObject*> lst;
for (FWObject::iterator i=re->begin(); i!=re->end(); i++)
{
FWObject *o= *i;
if (FWReference::cast(o)!=NULL) o=FWReference::cast(o)->getPointer();
if (physAddress::isA(o))
{
lst.push_back(o);
res=false;
}
}
for (FWObject::iterator i1=lst.begin(); i1!=lst.end(); i1++) re->removeRef(*i1);
return res;
}
bool NATCompiler::MACFiltering::processNext()
{
NATRule *rule=getNext(); if (rule==NULL) return false;
tmp_queue.push_back(rule);
RuleElement *osrc=rule->getOSrc();
RuleElement *odst=rule->getODst();
string lbl=rule->getLabel();
if ( ! checkRuleElement(osrc) )
{
if (last_rule_lbl!=lbl)
compiler->warning( "MAC address matching is not supported. One or several MAC addresses removed from Original Source in the rule "+lbl);
if (osrc->empty() || osrc->isAny())
compiler->abort("Original Source becomes 'Any' after all MAC addresses have been removed in the rule "+lbl);
last_rule_lbl=lbl;
}
if ( ! checkRuleElement(odst) )
{
if (last_rule_lbl!=lbl)
compiler->warning("MAC address matching is not supported. One or several MAC addresses removed from Original Destination in the rule "+lbl);
if (odst->empty() || odst->isAny())
compiler->abort("Original Destination becomes 'Any' after all MAC addresses have been removed in the rule "+lbl);
last_rule_lbl=lbl;
}
return true;
}
/*
* splits rule if ODst has multiple objects that belong to different
* subnets
*/
bool NATCompiler::splitODstForSNAT::processNext()
{
NATRule *rule=getNext(); if (rule==NULL) return false;
if (rule->getRuleType()==NATRule::SNAT)
{
RuleElementODst *rel=rule->getODst();
if (!rel->isAny() && rel->size()>1)
{
map<string, list<FWObject*> > il;
for (FWObject::iterator i=rel->begin(); i!=rel->end(); i++)
{
FWObject *o= *i;
if (FWReference::cast(o)!=NULL) o=FWReference::cast(o)->getPointer();
Address *a=Address::cast(o);
string iid="";
Interface *iface=compiler->findInterfaceFor( a , compiler->fw );
if (iface!=NULL) iid=iface->getId();
il[iid].push_back( a );
}
if (il.size()>1)
{
map<string, list<FWObject*> >::iterator j;
for (j=il.begin(); j!=il.end(); j++)
{
NATRule *r= NATRule::cast(
compiler->dbcopy->create(NATRule::TYPENAME) );
compiler->temp_ruleset->add(r);
r->duplicate(rule);
RuleElementODst *nodst=r->getODst();
nodst->clearChildren();
list<FWObject*>::iterator k;
for (k= j->second.begin(); k!=j->second.end(); k++)
nodst->addRef( *k );
tmp_queue.push_back(r);
}
} else tmp_queue.push_back(rule);
} else tmp_queue.push_back(rule);
} else tmp_queue.push_back(rule);
return true;
}
bool NATCompiler::DropRulesByAddressFamily::processNext()
{
NATRule *rule = getNext(); if (rule==NULL) return false;
RuleElementOSrc *osrc = rule->getOSrc();
RuleElementODst *odst = rule->getODst();
RuleElementTSrc *tsrc = rule->getTSrc();
RuleElementTDst *tdst = rule->getTDst();
compiler->DropAddressFamilyInRE(osrc, drop_ipv6);
compiler->DropAddressFamilyInRE(odst, drop_ipv6);
compiler->DropAddressFamilyInRE(tsrc, drop_ipv6);
compiler->DropAddressFamilyInRE(tdst, drop_ipv6);
tmp_queue.push_back(rule);
return true;
}
bool NATCompiler::dropRuleWithEmptyRE::processNext()
{
NATRule *rule = getNext(); if (rule==NULL) return false;
RuleElementOSrc *osrcrel = rule->getOSrc();
RuleElementODst *odstrel = rule->getODst();
RuleElementTSrc *tsrcrel = rule->getTSrc();
RuleElementTDst *tdstrel = rule->getTDst();
if ((osrcrel->size() == 0) || (odstrel->size() == 0)) return true;
if ((tsrcrel->size() == 0) || (tdstrel->size() == 0)) return true;
Address *osrc = compiler->getFirstOSrc(rule);
Address *odst = compiler->getFirstODst(rule);
Address *tsrc = compiler->getFirstTSrc(rule);
Address *tdst = compiler->getFirstTDst(rule);
if (osrc!=NULL && odst!=NULL && tsrc!=NULL && tdst!=NULL)
tmp_queue.push_back(rule);
return true;
}
string NATCompiler::debugPrintRule(libfwbuilder::Rule *r)
{
NATRule *rule = NATRule::cast(r);
RuleElementOSrc *osrcrel = rule->getOSrc();
RuleElementODst *odstrel = rule->getODst();
RuleElementOSrv *osrvrel = rule->getOSrv();
RuleElementTSrc *tsrcrel = rule->getTSrc();
RuleElementTDst *tdstrel = rule->getTDst();
RuleElementTSrv *tsrvrel = rule->getTSrv();
ostringstream str;
// str << setw(70) << setfill('-') << "-";
int no = 0;
FWObject::iterator i1 = osrcrel->begin();
FWObject::iterator i2 = odstrel->begin();
FWObject::iterator i3 = osrvrel->begin();
FWObject::iterator i4 = tsrcrel->begin();
FWObject::iterator i5 = tdstrel->begin();
FWObject::iterator i6 = tsrvrel->begin();
while ( i1!=osrcrel->end() || i2!=odstrel->end() || i3!=osrvrel->end() ||
i4!=tsrcrel->end() || i5!=tdstrel->end() || i6!=tsrvrel->end() ) {
str << endl;
string osrc = " ";
string odst = " ";
string osrv = " ";
string tsrc = " ";
string tdst = " ";
string tsrv = " ";
if (i1!=osrcrel->end()) {
FWObject *o=*i1;
if (FWReference::cast(o)!=NULL) o=objcache[o->getStr("ref")];
osrc=o->getName();
}
if (i2!=odstrel->end()) {
FWObject *o=*i2;
if (FWReference::cast(o)!=NULL) o=objcache[o->getStr("ref")];
odst=o->getName();
}
if (i3!=osrvrel->end()) {
FWObject *o=*i3;
if (FWReference::cast(o)!=NULL) o=objcache[o->getStr("ref")];
osrv=o->getName();
}
if (i4!=tsrcrel->end()) {
FWObject *o=*i4;
if (FWReference::cast(o)!=NULL) o=objcache[o->getStr("ref")];
tsrc=o->getName();
}
if (i5!=tdstrel->end()) {
FWObject *o=*i5;
if (FWReference::cast(o)!=NULL) o=objcache[o->getStr("ref")];
tdst=o->getName();
}
if (i6!=tsrvrel->end()) {
FWObject *o=*i6;
if (FWReference::cast(o)!=NULL) o=objcache[o->getStr("ref")];
tsrv=o->getName();
}
int w=0;
if (no==0) {
str << rule->getLabel();
w=rule->getLabel().length();
}
str << setw(8-w) << setfill(' ') << " ";
str << setw(16) << setfill(' ') << osrc.c_str();
str << setw(16) << setfill(' ') << odst.c_str();
str << setw(10) << setfill(' ') << osrv.c_str();
// str << endl;
//
// str << setw(8) << setfill(' ') << " ";
str << setw(16) << setfill(' ') << tsrc.c_str();
str << setw(16) << setfill(' ') << tdst.c_str();
str << setw(10) << setfill(' ') << tsrv.c_str();
++no;
if ( i1!=osrcrel->end() ) ++i1;
if ( i2!=odstrel->end() ) ++i2;
if ( i3!=osrvrel->end() ) ++i3;
if ( i4!=tsrcrel->end() ) ++i4;
if ( i5!=tdstrel->end() ) ++i5;
if ( i6!=tsrvrel->end() ) ++i6;
}
return str.str();
}