From 03b25ab4300595bedaa4b3985a9830f4fac8b9d7 Mon Sep 17 00:00:00 2001 From: Vadim Kurland Date: Fri, 28 Dec 2007 08:31:28 +0000 Subject: [PATCH] synchronized with 2.1.16 on tag sync-12-14 --- doc/ChangeLog | 36 + doc/doc.pro | 4 +- runqmake.sh | 55 +- src/gui/ActionsDialog.cpp | 2 + src/gui/SSHSession.cpp | 33 +- src/gui/SSHUnx.cpp | 3 +- src/gui/actionsdialog_q.ui | 2341 +++++++++++----------- src/gui/instDialog.cpp | 139 +- src/gui/instDialog.h | 23 +- src/gui/main.cpp | 16 +- src/gui/platforms.cpp | 17 + src/gui/platforms.h | 3 + src/ipt/OSConfigurator_linux24.cpp | 78 +- src/ipt/ipt.cpp | 129 +- src/pflib/PolicyCompiler_pf_writers.cpp | 151 +- test/pf/objects-for-regression-tests.fwb | 880 +++++++- 16 files changed, 2500 insertions(+), 1410 deletions(-) diff --git a/doc/ChangeLog b/doc/ChangeLog index 6d1651631..e5dcd541d 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,39 @@ +2007-12-19 vadim + + * v2.1.16 release + +2007-12-15 vadim + + * OSConfigurator_linux24.cpp + (OSConfigurator_linux24::printRunTimeWrappers): + fixed bug #1851166: "Installscript does not test for destination + ip address". The problem affected specific case of a firewall with + two (or more) interfaces that get their address dynamically and a + policy rule that has one such interface in source and another in + destination. Generated iptables script retrieves actual addresses + of both interfaces and assigns them to variables, then uses these + variables in actual iptables rules. Special check is provided in + case some interface did not obtain any ip address at a time of + execution of the script. Previously such test was only done for + one dynamic interface per rule. This change makes the script check + for both. + + * ipt.cpp: bug #1850352: "Install script wrongly completes + successful". Storing exit status of iptables-restore so that + generated firewall script can return the same status after it + executes commands that set kernel parameters and runs user-defined + epilog code. + + * PolicyCompiler_pf_writers.cpp (PrintRule::_printRouteOptions): + applied patch #1850357: "Add support fo load balancing with pf to + PolicyRule::Route" by Tom Judge (tomjudge@users.sourceforge.net) + that adds support for load balancing rules in PF. Extended the + patch adding support for address/netmask format of the next hop. + Added checks for illegal IP addresses and netmasks in the next + hop. Test cases for the PF load balancing rules are in + test/pf/objects-for-regression-tests.fwb, firewall object + firewall40-1. + 2007-12-13 vadim * linux24.xml.in: working on bug #1850352: "Install script wrongly diff --git a/doc/doc.pro b/doc/doc.pro index a1a639c9e..b7058eadd 100644 --- a/doc/doc.pro +++ b/doc/doc.pro @@ -47,7 +47,9 @@ doc.files = AUTHORS \ ReleaseNotes_2.1.14.html \ ReleaseNotes_2.1.14.txt \ ReleaseNotes_2.1.15.html \ - ReleaseNotes_2.1.15.txt + ReleaseNotes_2.1.15.txt \ + ReleaseNotes_2.1.16.html \ + ReleaseNotes_2.1.16.txt doc.path = $$DOCDIR diff --git a/runqmake.sh b/runqmake.sh index b00f38160..7f3f0c495 100644 --- a/runqmake.sh +++ b/runqmake.sh @@ -19,39 +19,46 @@ ${QMAKE} -o po/Makefile po/po.pro if test -n "$CCACHE"; then -${QMAKE} 'QMAKE_CXX=ccache g++' -o src/antlr/Makefile src/antlr/antlr.pro + test -d src/unit_tests && { + ${QMAKE} 'QMAKE_CXX=ccache g++' -o src/unit_tests/importer/Makefile \ + src/unit_tests/importer/importer.pro + } -${QMAKE} 'QMAKE_CXX=ccache g++' -o src/gui/Makefile src/gui/gui.pro -${QMAKE} 'QMAKE_CXX=ccache g++' -o src/fwblookup/Makefile src/fwblookup/fwblookup.pro -${QMAKE} 'QMAKE_CXX=ccache g++' -o src/fwbedit/Makefile src/fwbedit/fwbedit.pro -${QMAKE} 'QMAKE_CXX=ccache g++' -o src/ipt/Makefile src/ipt/ipt.pro -${QMAKE} 'QMAKE_CXX=ccache g++' -o src/pflib/Makefile src/pflib/pflib.pro -${QMAKE} 'QMAKE_CXX=ccache g++' -o src/pf/Makefile src/pf/pf.pro -${QMAKE} 'QMAKE_CXX=ccache g++' -o src/ipf/Makefile src/ipf/ipf.pro -${QMAKE} 'QMAKE_CXX=ccache g++' -o src/ipfw/Makefile src/ipfw/ipfw.pro + ${QMAKE} 'QMAKE_CXX=ccache g++' -o src/antlr/Makefile src/antlr/antlr.pro -${QMAKE} 'QMAKE_CXX=ccache g++' -o src/parsers/Makefile src/parsers/parsers.pro + ${QMAKE} 'QMAKE_CXX=ccache g++' -o src/gui/Makefile src/gui/gui.pro + ${QMAKE} 'QMAKE_CXX=ccache g++' -o src/fwblookup/Makefile \ + src/fwblookup/fwblookup.pro + ${QMAKE} 'QMAKE_CXX=ccache g++' -o src/fwbedit/Makefile \ + src/fwbedit/fwbedit.pro + ${QMAKE} 'QMAKE_CXX=ccache g++' -o src/ipt/Makefile src/ipt/ipt.pro + ${QMAKE} 'QMAKE_CXX=ccache g++' -o src/pflib/Makefile src/pflib/pflib.pro + ${QMAKE} 'QMAKE_CXX=ccache g++' -o src/pf/Makefile src/pf/pf.pro + ${QMAKE} 'QMAKE_CXX=ccache g++' -o src/ipf/Makefile src/ipf/ipf.pro + ${QMAKE} 'QMAKE_CXX=ccache g++' -o src/ipfw/Makefile src/ipfw/ipfw.pro -test -d src/unit_tests && ${QMAKE} 'QMAKE_CXX=ccache g++' -o src/unit_tests/importer/Makefile \ -src/unit_tests/importer/importer.pro + ${QMAKE} 'QMAKE_CXX=ccache g++' -o src/parsers/Makefile \ + src/parsers/parsers.pro else -${QMAKE} -o src/antlr/Makefile src/antlr/antlr.pro + test -d src/unit_tests && { + ${QMAKE} -o src/unit_tests/importer/Makefile \ + src/unit_tests/importer/importer.pro + } -${QMAKE} -o src/gui/Makefile src/gui/gui.pro -${QMAKE} -o src/fwblookup/Makefile src/fwblookup/fwblookup.pro -${QMAKE} -o src/fwbedit/Makefile src/fwbedit/fwbedit.pro -${QMAKE} -o src/ipt/Makefile src/ipt/ipt.pro -${QMAKE} -o src/pflib/Makefile src/pflib/pflib.pro -${QMAKE} -o src/pf/Makefile src/pf/pf.pro -${QMAKE} -o src/ipf/Makefile src/ipf/ipf.pro -${QMAKE} -o src/ipfw/Makefile src/ipfw/ipfw.pro + ${QMAKE} -o src/antlr/Makefile src/antlr/antlr.pro -${QMAKE} -o src/parsers/Makefile src/parsers/parsers.pro + ${QMAKE} -o src/gui/Makefile src/gui/gui.pro + ${QMAKE} -o src/fwblookup/Makefile src/fwblookup/fwblookup.pro + ${QMAKE} -o src/fwbedit/Makefile src/fwbedit/fwbedit.pro + ${QMAKE} -o src/ipt/Makefile src/ipt/ipt.pro + ${QMAKE} -o src/pflib/Makefile src/pflib/pflib.pro + ${QMAKE} -o src/pf/Makefile src/pf/pf.pro + ${QMAKE} -o src/ipf/Makefile src/ipf/ipf.pro + ${QMAKE} -o src/ipfw/Makefile src/ipfw/ipfw.pro -test -d src/unit_tests && ${QMAKE} -o src/unit_tests/importer/Makefile \ -src/unit_tests/importer/importer.pro + ${QMAKE} -o src/parsers/Makefile src/parsers/parsers.pro fi diff --git a/src/gui/ActionsDialog.cpp b/src/gui/ActionsDialog.cpp index 831ad14cc..ef710458d 100644 --- a/src/gui/ActionsDialog.cpp +++ b/src/gui/ActionsDialog.cpp @@ -249,6 +249,7 @@ void ActionsDialog::setRule(PolicyRule *r ) // build a map for combobox so visible combobox items can be localized QStringList route_options = getRouteOptions_pf_ipf( platform.c_str() ); + QStringList route_load_options = getRouteLoadOptions_pf( platform.c_str() ); // iptables data.registerOption ( m_dialog->ipt_iif , ropt , "ipt_iif" ); @@ -265,6 +266,7 @@ void ActionsDialog::setRule(PolicyRule *r ) // pf data.registerOption ( m_dialog->pf_fastroute , ropt , "pf_fastroute" ); + data.registerOption( m_dialog->pf_route_load_option , ropt , "pf_route_load_option", route_load_options ); data.registerOption ( m_dialog->pf_route_option , ropt , "pf_route_option", route_options); data.registerOption ( m_dialog->pf_route_opt_if , ropt , "pf_route_opt_if" ); diff --git a/src/gui/SSHSession.cpp b/src/gui/SSHSession.cpp index 4dff3d564..552a382ca 100644 --- a/src/gui/SSHSession.cpp +++ b/src/gui/SSHSession.cpp @@ -135,21 +135,30 @@ void SSHSession::startSession() qDebug("SSHSession::startSession this=%p proc=%p heartBeatTimer=%p", this,proc,heartBeatTimer); - connect(proc,SIGNAL(readyReadStandardOutput()), this, SLOT(readFromStdout() ) ); - connect(proc,SIGNAL(readyReadStandardError()), this, SLOT(readFromStderr() ) ); - connect(proc,SIGNAL(finished( int, QProcess::ExitStatus )), this, SLOT(finished( int ) ) ); + connect(proc,SIGNAL(readyReadStandardOutput()), + this, SLOT(readFromStdout() ) ); + connect(proc,SIGNAL(readyReadStandardError()), + this, SLOT(readFromStderr() ) ); + connect(proc,SIGNAL(finished( int, QProcess::ExitStatus )), + this, SLOT(finished( int ) ) ); QTextCodec::setCodecForCStrings(QTextCodec::codecForName("latin1")); - QStringList arguments; + assert(args.size() > 0); - for (QStringList::const_iterator i=args.begin(); i!=args.end(); ++i) + QStringList arguments; + QStringList::const_iterator i=args.begin(); + QString program = *i; + ++i; + + for ( ; i!=args.end(); ++i) { arguments << *i; //proc->addArgument( *i ); cmd += *i; } + QStringList env; #ifdef _WIN32 @@ -178,9 +187,15 @@ void SSHSession::startSession() proc->setEnvironment(env); - assert(arguments.size() > 0); //i suppose first argument is the program to start - QString program = arguments[0]; //if it isn't so, we'll fail here - + if (fwbdebug) + { + qDebug("Launch external ssh client %s", program.toAscii().constData()); + qDebug("Arguments:"); + QStringList::const_iterator i; + for (i=arguments.begin(); i!=arguments.end(); ++i) + qDebug(" %s", (*i).toAscii().constData()); + } + proc->start(program, arguments); if ( !proc->waitForStarted() ) @@ -201,7 +216,9 @@ void SSHSession::startSession() SSHSession::~SSHSession() { + if (fwbdebug) qDebug("SSHSession::destructor"); terminate(); + if (fwbdebug) qDebug("SSHSession::destructor done"); } /* diff --git a/src/gui/SSHUnx.cpp b/src/gui/SSHUnx.cpp index bd3ac5649..2cb23dab8 100644 --- a/src/gui/SSHUnx.cpp +++ b/src/gui/SSHUnx.cpp @@ -71,6 +71,7 @@ SSHUnx::SSHUnx(QWidget *_par, iptables_errors.push_back("'iptables --help' for more information."); iptables_errors.push_back("'iptables-restore --help' for more information."); + iptables_errors.push_back("iptables-restore: line .* failed"); } SSHUnx::~SSHUnx() @@ -87,7 +88,7 @@ bool SSHUnx::checkForErrors(QStringList *errptr) if (fwbdebug) qDebug(QString("SSHUnx::stateMachine: error='%1'").arg(*i).toAscii().constData()); - if ( stdoutBuffer.lastIndexOf(*i,-1)!=-1 ) + if ( stdoutBuffer.lastIndexOf(QRegExp(*i),-1)!=-1 ) { if (fwbdebug) qDebug("SSHUnx::stateMachine: MATCH. Error detected."); diff --git a/src/gui/actionsdialog_q.ui b/src/gui/actionsdialog_q.ui index 4931857e8..c20accf49 100644 --- a/src/gui/actionsdialog_q.ui +++ b/src/gui/actionsdialog_q.ui @@ -25,7 +25,7 @@ 11 - + @@ -87,503 +87,257 @@ QFrame::Sunken - - - 11 + + + + 13 + 13 + 606 + 257 + - - 11 + + + 320 + 0 + - - 11 + + QFrame::NoFrame - - 11 + + QFrame::Plain - - - - - 320 - 0 - + + 12 + + + + + 0 - - QFrame::NoFrame + + 0 - - QFrame::Plain + + 0 - - - - 0 + + 0 + + + + + + + + Tag string: - - 0 + + false - - 0 + + + + + + Qt::Vertical - - 0 + + QSizePolicy::Expanding - - - - - + + + 20 + 20 + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 40 + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + If rule action is 'Reject', this option defines firewall's reaction to the packet matching the rule + + + Qt::AlignVCenter + + + true + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + 300 + 0 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 40 + 20 + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + This action has no parameters. + + + Qt::AlignCenter + + + true + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + - Tag string: + Tag value: false - - - - Qt::Vertical + + + + + 0 + 0 + - - QSizePolicy::Expanding - - - - 20 - 20 - - - - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 20 - 40 - - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 20 - 20 - - - - - - - - If rule action is 'Reject', this option defines firewall's reaction to the packet matching the rule - - - Qt::AlignVCenter - - - true - - - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 20 - 20 - - - - - - - - - 300 - 0 - - - - - - - - Qt::Horizontal - - - QSizePolicy::Expanding - - - - 40 - 20 - - - - - - - - Qt::Horizontal - - - QSizePolicy::Expanding - - - - 40 - 20 - - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - This action has no parameters. - - - Qt::AlignCenter - - - true - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - Tag value: - - - false - - - - - - - - 0 - 0 - - - - - 80 - 0 - - - - 65535 - - - - - - - Qt::Horizontal - - - QSizePolicy::Expanding - - - - 40 - 20 - - - - - - - - - - Requires CONNMARK target - - - Mark connections created by packets that match this rule - - - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 20 - 20 - - - - - - - - Note: this action translates into MARK target for iptables. Normally this target is non-terminating, that is, other rules with Classify or Tag actions belog this one will process the same packet. However, Firewall Builder can emulate terminating behavior for this action. Option in the "compiler" tab of the firewall object properties dialog activates emulation. - - - Qt::AlignVCenter - - - true - - - - - - - Emulation is currently ON, the rule will be terminating - - - Qt::AlignCenter - - - false - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Rule name for accounting. (white spaces and special characters are not allowed) - - - Qt::AlignVCenter - - - true - - - - - - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 20 - 40 - - - - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 20 - 40 - - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Packet classification can be implemented in different ways: - - - Qt::AlignVCenter - - - true - - - - - - - - - - - 5 - - - 5 - - - 5 - - - 5 - - - 2 - - - 2 - - - - - use dummynet(4) 'pipe' - - - - - - - use dummynet(4) 'queue' - - - - - - - - - - Pipe or queue number: - - - false - - - - - - - Qt::Horizontal - - - QSizePolicy::Expanding - - - - 40 - 20 - - - - - - 80 @@ -591,185 +345,11 @@ - 999999 - - - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 20 - 40 - - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 20 - 21 - - - - - - - - Custom string: - - - false + 65535 - - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 20 - 41 - - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Classify string: - - - false - - - - - - - - - - Note: CLASSIFY target in iptables is non-terminating, that is other rules with Classify or Mark target below this will process the same packet. However, Firewall Builder can emulate terminating behavior for this action. Emulation is activated by an option in the "compiler" tab of the firewall object properties dialog. - - - Qt::AlignVCenter - - - true - - - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 20 - 20 - - - - - - - - Emulation is currently ON, rule will be terminating - - - Qt::AlignCenter - - - false - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Divert socket port number: - - - false - - - - Qt::Horizontal @@ -785,495 +365,946 @@ - - - - - 80 - 0 - - - - 999999 - + + + + + + Requires CONNMARK target + + + Mark connections created by packets that match this rule + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + Note: this action translates into MARK target for iptables. Normally this target is non-terminating, that is, other rules with Classify or Tag actions belog this one will process the same packet. However, Firewall Builder can emulate terminating behavior for this action. Option in the "compiler" tab of the firewall object properties dialog activates emulation. + + + Qt::AlignVCenter + + + true + + + + + + + Emulation is currently ON, the rule will be terminating + + + Qt::AlignCenter + + + false + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Rule name for accounting. (white spaces and special characters are not allowed) + + + Qt::AlignVCenter + + + true + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 40 + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 40 + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Packet classification can be implemented in different ways: + + + Qt::AlignVCenter + + + true + + + + + + + + + + + 5 + + + 5 + + + 5 + + + 5 + + + 2 + + + 2 + + + + + use dummynet(4) 'pipe' + + + + + + + use dummynet(4) 'queue' + + + + + + + + + + Pipe or queue number: + + + false + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 40 + 20 + + + + + + + + + 80 + 0 + + + + 999999 + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 40 + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 21 + + + + + + + + Custom string: + + + false + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 41 + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Classify string: + + + false + + + + + + + + + + Note: CLASSIFY target in iptables is non-terminating, that is other rules with Classify or Mark target below this will process the same packet. However, Firewall Builder can emulate terminating behavior for this action. Emulation is activated by an option in the "compiler" tab of the firewall object properties dialog. + + + Qt::AlignVCenter + + + true + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + Emulation is currently ON, rule will be terminating + + + Qt::AlignCenter + + + false + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Divert socket port number: + + + false + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 40 + 20 + + + + + + + + + 80 + 0 + + + + 999999 + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 40 + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 40 + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + User-defined chain name: + + + false + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + In addition to 'filter', create branching rule in 'mangle' table as well + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Anchor name: + + + false + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 40 + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 40 + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 50 + + + + + + + + + + + Route through + + + + + Route reply through + + + + + Route a copy through + + - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 20 - 40 - - - - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 20 - 40 - - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 20 - 20 - - - - - - + + - User-defined chain name: + interface false - - + + - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 20 - 20 - - - - - - + + - In addition to 'filter', create branching rule in 'mangle' table as well - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Anchor name: + next hop false - - - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 20 - 40 - - - - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 20 - 40 - - - + + - - - - - 0 + + + + + Qt::Vertical - - 0 + + QSizePolicy::Expanding - - 0 + + + 20 + 40 + - - 0 + + + + + + + + + + Qt::Vertical - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 20 - 50 - - - - - - + + QSizePolicy::Expanding + + + + 20 + 40 + + + + + + + + - - - - Route through - - - - - Route reply through - - - - - Route a copy through - - - + + Route through + - - - interface - - - false - - + + Route reply through + - + + Route a copy through + - - - - next hop - - - false - - - - - - - - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 20 - 40 - - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Fastroute - - - - - - - - Route through - - - - - Route reply through - - - - - Route a copy through - - - - - - - - interface - - - false - - - - - - - - - - next hop - - - false - - - - - - - - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 20 - 30 - - - - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 20 - 40 - - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - + + - Change inbound interface to + interface false - - + + + + + - Route through gateway + next hop false - - - - - - - Change outbound interface to - - - false - - - - - - - - - - - - - Qt::Horizontal - - - QSizePolicy::Expanding - - - - 170 - 20 - - - - - - - - Continue packet inspection - - - - - - - Make a copy - - + + - - - - + + + + + Fastroute + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 40 + 20 + + + + + + + + Load Balancing: + + + + + + + + None + + + + + Bitmask + + + + + Random + + + + + Source Hash + + + + + Round Robin + + + + + + + + Qt::Horizontal + + + + 131 + 20 + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 553 + 51 + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Change inbound interface to + + + false + + + + + + + Route through gateway + + + false + + + + + + + + + + Change outbound interface to + + + false + + + + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 170 + 20 + + + + + + + + Continue packet inspection + + + + + + + Make a copy + + + + + + - - - - Qt::Horizontal - - - QSizePolicy::Expanding - - - - 40 - 20 - - - - - @@ -1283,8 +1314,8 @@ changed() - 20 - 20 + 196 + 222 20 @@ -1299,8 +1330,8 @@ changed() - 20 - 20 + 52 + 181 20 @@ -1315,8 +1346,8 @@ changed() - 20 - 20 + 52 + 164 20 @@ -1331,8 +1362,8 @@ changed() - 20 - 20 + 45 + 214 20 @@ -1347,8 +1378,8 @@ changed() - 20 - 20 + 119 + 106 20 @@ -1363,8 +1394,8 @@ tagvalueChanged(int) - 20 - 20 + 119 + 106 20 @@ -1379,8 +1410,8 @@ changed() - 20 - 20 + 119 + 106 20 @@ -1395,8 +1426,8 @@ changed() - 20 - 20 + 178 + 240 20 @@ -1411,8 +1442,8 @@ changed() - 20 - 20 + 57 + 206 20 @@ -1427,8 +1458,8 @@ changed() - 20 - 20 + 313 + 206 20 @@ -1443,8 +1474,8 @@ changed() - 20 - 20 + 494 + 207 20 @@ -1459,8 +1490,8 @@ changed() - 20 - 20 + 55 + 243 20 @@ -1475,8 +1506,8 @@ changed() - 20 - 20 + 45 + 105 20 @@ -1491,8 +1522,8 @@ changed() - 20 - 20 + 45 + 105 20 @@ -1507,8 +1538,8 @@ changed() - 20 - 20 + 45 + 141 20 @@ -1523,8 +1554,8 @@ changed() - 20 - 20 + 45 + 105 20 @@ -1539,8 +1570,8 @@ changed() - 20 - 20 + 45 + 105 20 @@ -1555,8 +1586,8 @@ iptRouteContinueToggled() - 20 - 20 + 45 + 105 20 @@ -1571,8 +1602,8 @@ changed() - 20 - 20 + 45 + 105 20 @@ -1587,8 +1618,8 @@ changed() - 20 - 20 + 45 + 250 20 @@ -1603,8 +1634,8 @@ changed() - 20 - 20 + 45 + 221 20 @@ -1619,8 +1650,8 @@ changed() - 20 - 20 + 301 + 221 20 @@ -1635,8 +1666,8 @@ changed() - 20 - 20 + 482 + 222 20 @@ -1651,8 +1682,8 @@ changed() - 20 - 20 + 225 + 218 20 @@ -1667,8 +1698,8 @@ changed() - 20 - 20 + 46 + 233 20 @@ -1683,8 +1714,8 @@ changed() - 20 - 20 + 46 + 131 20 @@ -1699,8 +1730,8 @@ changed() - 20 - 20 + 47 + 221 20 @@ -1715,8 +1746,8 @@ changed() - 20 - 20 + 46 + 233 20 @@ -1731,8 +1762,8 @@ changed() - 20 - 20 + 46 + 233 20 @@ -1740,5 +1771,21 @@ + + pf_route_load_option + activated(int) + ActionsDialog_q + changed() + + + 338 + 233 + + + 317 + 177 + + + diff --git a/src/gui/instDialog.cpp b/src/gui/instDialog.cpp index d7a672940..1069b8e6f 100644 --- a/src/gui/instDialog.cpp +++ b/src/gui/instDialog.cpp @@ -103,8 +103,21 @@ instDialog::instDialog(QWidget* p, BatchOperation op, t_fwSet reqFirewalls_) : Q pendingLogLine = ""; rejectDialogFlag=false; + /* object proc is used to launch policy compilers as background + * processes. SSH sessions in installers are controlled by class + * SSHSession (and classes derived from it). This leads to some + * duplication, such as all the apparatus for reading from stdout + * of the background process is duplicated in SSHSession and here. + * + * The same object is also used to launch custom installer scripts. + * + * TODO(vadim): need to move everything that deals with compiler + * process into its own class CompilerSession derived from + * SSHSession. Perhaps also rename SSHSession to BackgroundSession + * or something. + */ + connect(&proc, SIGNAL(readyReadStandardOutput()), this, SLOT(readFromStdout()) ); - //connect(&proc, SIGNAL(readyReadStandardError()), this, SLOT(readFromStderr()) ); connect(&proc, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(processExited(int)) ); proc.setProcessChannelMode(QProcess::MergedChannels); @@ -119,7 +132,7 @@ instDialog::instDialog(QWidget* p, BatchOperation op, t_fwSet reqFirewalls_) : Q findFirewalls(); if (firewalls.size()==0) { - setTitle( pageCount()-1, tr("There is no firewalls to process.") ); + setTitle( pageCount()-1, tr("There are no firewalls to process.") ); for (int i=0;igetOptionsObject(); fwb_prompt="--**--**--"; @@ -855,7 +868,8 @@ bool instDialog::doInstallPage(Firewall* f) #else args.push_back(argv0.c_str()); args.push_back("-X"); // fwbuilder works as ssh wrapper -// args.push_back("-d"); + //if (fwbdebug) + // args.push_back("-d"); args.push_back("-t"); args.push_back("-t"); @@ -967,10 +981,36 @@ bool instDialog::doInstallPage(Firewall* f) return true; } +/* reset ssh session to continue the same installation process, such as + * when we need to copy several files to the firewall + */ void instDialog::resetInstallSSHSession() { if (fwbdebug) qDebug("instDialog::resetInstallSSHSession"); + if (session!=NULL) + QTimer::singleShot( 0, this, SLOT(stopSessionAndDisconnectSignals())); + + activationCommandDone = false; + + if (fwbdebug) qDebug("instDialog::resetInstallSSHSession done"); +} + +/* instDialog::stopSessionAndDisconnectSignals runs when we have no + * other events in the events queue. This is necessary because call to + * instDialog::finishInstall can come from inside the state machine + * (e.g. when error was detected). This means we are trying to + * terminate working session right in the middle, when there could be + * some more output from its stdout to be collected. To avoid race + * conditions with events that have not been processed, we schedule + * all termination and clean-up operations so they will be done at + * idle time when there are no events in the queue + */ +void instDialog::stopSessionAndDisconnectSignals() +{ + if (fwbdebug) + qDebug("instDialog::stopSessionAndDisconnectSignals()"); + if (session!=NULL) { disconnect(session,SIGNAL(printStdout_sign(const QString&)), @@ -991,7 +1031,8 @@ void instDialog::resetInstallSSHSession() session=NULL; } - activationCommandDone=false; + if (fwbdebug) + qDebug("instDialog::stopSessionAndDisconnectSignals() done"); } /* @@ -1129,7 +1170,9 @@ void instDialog::initiateCopy(const QString &file) #else args.push_back(argv0.c_str()); args.push_back("-X"); // fwbuilder works as ssh wrapper -// if (fwbdebug>1) args.push_back("-d"); + //if (fwbdebug) + // args.push_back("-d"); + // args.push_back("-t"); // args.push_back("-t"); #endif @@ -1249,31 +1292,26 @@ void instDialog::finishInstall(bool success) if(opListIterator!=opList.end() && m_dialog->batchInstall->isChecked() && !stopProcessFlag) { - installSelected(); +// installSelected(); + QTimer::singleShot( 0, this, SLOT(installSelected())); return; } setNextEnabled( 1, true); } +/* + * continueRun is called via idle event handler after the session object + * is destroyed in stopSessionAndDisconnectSignals. + * + * Various methods call resetInstallSSHSession, which schedules call + * to stopSessionAndDisconnectSignals. installerFinished() also + * schedules call to continueRun() right after that. So continueRun() + * is always called when we have no active session object. + */ void instDialog::continueRun() { if (fwbdebug) qDebug("instDialog::continueRun"); - if (session) - { - if (session->getErrorStatus()) - { - if (fwbdebug) qDebug("session error"); - addToLog( tr("Fatal error, terminating install sequence\n") ); - finishInstall(false); - //setFinishEnabled( page(1), true ); - return; - } - - delete session; - session=NULL; - } - if (activationCommandDone) { if (fwbdebug) qDebug("activationCommandDone"); @@ -1314,6 +1352,8 @@ void instDialog::continueRun() #else args.push_back(argv0.c_str()); args.push_back("-X"); // fwbuilder works as ssh wrapper + //if (fwbdebug) + // args.push_back("-d"); args.push_back("-t"); args.push_back("-t"); #endif @@ -1344,7 +1384,7 @@ void instDialog::continueRun() if (cnf.verbose) displayCommand(args); - activationCommandDone=true; + activationCommandDone = true; runSSH( new SSHUnx(this, cnf.fwobj->getName().c_str(), @@ -1400,29 +1440,9 @@ void instDialog::finishClicked() void instDialog::cancelClicked() { if (fwbdebug) qDebug("instDialog::cancelClicked()"); - if (session!=NULL) - { - if (fwbdebug) - qDebug("instDialog::reject() killing ssh session"); - - disconnect(session,SIGNAL(printStdout_sign(const QString&)), - this,SLOT(append(const QString&))); - - disconnect(session,SIGNAL(sessionFinished_sign()), - this,SLOT(installerFinished())); - - disconnect(session,SIGNAL(sessionFatalError_sign()), - this,SLOT(installerError())); - - disconnect(session,SIGNAL(updateProgressBar_sign(int,bool)), - this,SLOT(updateProgressBar(int,bool))); - - session->terminate(); - - delete session; - session=NULL; - } + stopSessionAndDisconnectSignals(); + // What is this? Do we need this? This code is not present in 2.1.16. if (proc.state() == QProcess::Running) { rejectDialogFlag = true; @@ -1885,25 +1905,22 @@ void instDialog::installerError() addToLog( tr("Error: Terminating install sequence\n") ); finishInstall(false); - resetInstallSSHSession(); - //setFinishEnabled( page(1), true ); - - if (session) delete session; - session=NULL; + // session object is destroyed in stopSessionAndDisconnectSignals() + QTimer::singleShot( 0, this, SLOT(stopSessionAndDisconnectSignals())); } void instDialog::installerFinished() { if( fwbdebug) qDebug("instDialog::installerFinished"); - + if (session->getErrorStatus()) - { installerError(); + else + { + // session object is destroyed in stopSessionAndDisconnectSignals() + QTimer::singleShot( 0, this, SLOT(stopSessionAndDisconnectSignals())); } - - if (session) delete session; - session=NULL; - + QTimer::singleShot( 0, this, SLOT(continueRun()) ); } @@ -1944,7 +1961,7 @@ void instDialog::processExited(int res) if (opListIterator!=opList.end() && m_dialog->batchInstall->isChecked() && !stopProcessFlag) { - installSelected(); + QTimer::singleShot( 0, this, SLOT(installSelected())); } else { @@ -2021,7 +2038,8 @@ void instDialog::processExited(int res) } ++opListIterator; } - if (currentFirewallsBar) currentFirewallsBar->setValue(currentFirewallsBar->maximum()); + if (currentFirewallsBar) + currentFirewallsBar->setValue(currentFirewallsBar->maximum()); if (currentStopButton) { @@ -2235,20 +2253,19 @@ bool instDialog::runInstall(Firewall *fw) if (fwbdebug) qDebug("custom script"); summary(); - addToLog( args.join(" ") ); + addToLog(args.join(" ")); QString path = args[0]; args.pop_front(); proc.start(path, args); - if ( !proc.waitForStarted() ) + if (!proc.waitForStarted()) { addToLog( tr("Error: Failed to start program") ); return false; } args.push_front(path); //return to previous state - } else { diff --git a/src/gui/instDialog.h b/src/gui/instDialog.h index fccde3b0f..487bf8a09 100644 --- a/src/gui/instDialog.h +++ b/src/gui/instDialog.h @@ -151,7 +151,6 @@ class instDialog : public QDialog, public FakeWizard bool testFirewall(libfwbuilder::Firewall*); void finishInstall(bool success=true); void fillInstallOpList(); - void installSelected(); void initInstall(); void analyseInstallQueue(bool &fPix, bool &fCustInst); libfwbuilder::Firewall *findFirewallbyListItem(QTreeWidgetItem* item); @@ -193,19 +192,20 @@ protected: QString getFullPath(instConf &cnf, const QString &file ); protected slots: - void processExited(int code); - void installerFinished(); - void installerError(); - void showPage(const int page); + void processExited(int code); + void installerFinished(); + void installerError(); + void installSelected(); + void showPage(const int page); - void finishClicked(); - void cancelClicked(); + void finishClicked(); + void cancelClicked(); - void testRunRequested(); + void testRunRequested(); - void append(const QString &line); - void appendRich(const QString &line); - void updateProgressBar(int n,bool setsize); + void append(const QString &line); + void appendRich(const QString &line); + void updateProgressBar(int n,bool setsize); void continueRun(); virtual void saveLog(); @@ -219,6 +219,7 @@ protected: virtual void nextClicked(); virtual void backClicked(); + void stopSessionAndDisconnectSignals(); void compileSelected(); void stopCompile(); diff --git a/src/gui/main.cpp b/src/gui/main.cpp index f66afd97f..ea4aaf289 100644 --- a/src/gui/main.cpp +++ b/src/gui/main.cpp @@ -372,16 +372,17 @@ int main( int argc, char ** argv ) i=1; j=1; - for ( ; argv[i]!=NULL; i++) + //for ( ; argv[i]!=NULL; i++) + for ( ; i getVersionsForPlatform(const QString &platform); @@ -83,6 +84,8 @@ const QStringList& getActionsOnReject(const QString &platform); */ const QStringList& getRouteOptions_pf_ipf(const QString &platform); +const QStringList& getRouteLoadOptions_pf(const QString &platform); + /** * returns a list of Prolog places (mapping list) */ diff --git a/src/ipt/OSConfigurator_linux24.cpp b/src/ipt/OSConfigurator_linux24.cpp index 78e31a517..9630ecc5a 100644 --- a/src/ipt/OSConfigurator_linux24.cpp +++ b/src/ipt/OSConfigurator_linux24.cpp @@ -641,7 +641,6 @@ string OSConfigurator_linux24::printRunTimeWrappers(FWObject *rule, const string &command) { string command_line = command; - ostringstream res; ostringstream ext_command_line; int nlines = 0; @@ -674,41 +673,62 @@ string OSConfigurator_linux24::printRunTimeWrappers(FWObject *rule, } /* if anywhere in command_line we used variable holding an address of - * dynamic interface (named $i_something) then we need to add - * this command with a check for the value of this variable. We execute + * dynamic interface (named $i_something) then we need to add this + * command with a check for the value of this variable. We execute * iptables command only if the value is a non-empty string. + * + * bug #1851166: there could be two dynamic interfaces in the same + * rule. */ + if (command_line.find("$i_")==string::npos) return command_line; - p1=command_line.find("$i_"); - string iface_name; - string iface_var; - if ( p1==string::npos ) return command_line; + ostringstream res; + bool wildcard_interfaces = false; + p1=0; + while ((p1=command_line.find("$i_", p1))!=string::npos) + { + string iface_name; + string iface_var; - p2=command_line.find(" ",p1); - p3=command_line.find("_",p1) +1; - iface_name=command_line.substr(p3,p2-p3); - iface_var= command_line.substr(p1,p2-p1); + p2=command_line.find(" ",p1); + p3=command_line.find("_",p1) +1; + iface_name=command_line.substr(p3,p2-p3); + iface_var= command_line.substr(p1,p2-p1); /* if interface name ends with '*', this is a wildcard interface. */ - string::size_type p4; - if ((p4=iface_name.find("*"))!=string::npos) + string::size_type p4; + if ((p4=iface_name.find("*"))!=string::npos) + { + wildcard_interfaces = true; + string cmdline=command_line; + string iface_family_name=iface_name.substr(0,p4); + res << "getinterfaces " << iface_family_name << " | while read I; do" << endl; + res << " ivar=`getInterfaceVarName $I`" << endl; + res << " getaddr $I $ivar" << endl; + res << " cmd=\"$\"$ivar" << endl; + res << " eval \"addr=$cmd\"" << endl; + cmdline.replace(p1,p2-p1,"$addr"); + res << " test -n \"$addr\" && "; + if (nlines>1) res << "{" << endl; + res << cmdline; + if (nlines>1) res << "}" << endl; + res << "done" << endl; + } else + { + // bug #1851166: there could be two dynamic interfaces in + // the same rule. Just print "test" command here and continue + // in the "while" loop. We'll print actual commands when the loop + // ends. + res << "test -n \"" << iface_var << "\" && "; + } + p1++; // p1 points at the previous "$i_" fragment + } + + + // for wildcard interfaces we only support one such interface + // per rule and we have already printed the actual command above. + if (!wildcard_interfaces) { - string cmdline=command_line; - string iface_family_name=iface_name.substr(0,p4); - res << "getinterfaces " << iface_family_name << " | while read I; do" << endl; - res << " ivar=`getInterfaceVarName $I`" << endl; - res << " getaddr $I $ivar" << endl; - res << " cmd=\"$\"$ivar" << endl; - res << " eval \"addr=$cmd\"" << endl; - cmdline.replace(p1,p2-p1,"$addr"); - res << " test -n \"$addr\" && "; - if (nlines>1) res << "{" << endl; - res << cmdline; - if (nlines>1) res << "}" << endl; - res << "done" << endl; - } else - { - res << "test -n \"" << iface_var << "\" && "; if (nlines>1) res << "{" << endl; res << command_line; if (nlines>1) res << "}" << endl; diff --git a/src/ipt/ipt.cpp b/src/ipt/ipt.cpp index 1f317142f..c3b1c0e8b 100644 --- a/src/ipt/ipt.cpp +++ b/src/ipt/ipt.cpp @@ -594,65 +594,33 @@ _("Dynamic interface %s should not have an IP address object attached to it. Thi if (options->getBool("use_iptables_restore")) { - if (have_dynamic_interfaces) + script << "(" << endl; + + script << c.flushAndSetDefaultPolicy(); + + if (prolog_place == "after_flush") { - script << "(" << endl; - - script << c.flushAndSetDefaultPolicy(); - - if (prolog_place == "after_flush") - { - script << addPrologScript(nocomm, - fw->getOptionsObject()->getStr("prolog_script")); - } - - script << c.getCompiledScript(); - script << c.commit(); - - if (m.getCompiledScriptLength()>0) - { - script << m.flushAndSetDefaultPolicy(); - script << m.getCompiledScript(); - script << m.commit(); - } - if (n.getCompiledScriptLength()>0) - { - script << n.flushAndSetDefaultPolicy(); - script << n.getCompiledScript(); - script << n.commit(); - } - script << "#" << endl; - script << ") | $IPTABLES_RESTORE" << endl; - } else - { - script << "cat << EOF | $IPTABLES_RESTORE" << endl; - - script << c.flushAndSetDefaultPolicy(); - - if (prolog_place == "after_flush") - { - script << addPrologScript(nocomm, - fw->getOptionsObject()->getStr("prolog_script")); - } - - script << c.getCompiledScript(); - script << c.commit(); - - if (m.getCompiledScriptLength()>0) - { - script << m.flushAndSetDefaultPolicy(); - script << m.getCompiledScript(); - script << m.commit(); - } - if (n.getCompiledScriptLength()>0) - { - script << n.flushAndSetDefaultPolicy(); - script << n.getCompiledScript(); - script << n.commit(); - } - script << "#" << endl; - script << "EOF" << endl; + script << addPrologScript(nocomm, + fw->getOptionsObject()->getStr("prolog_script")); } + + script << c.getCompiledScript(); + script << c.commit(); + + if (m.getCompiledScriptLength()>0) + { + script << m.flushAndSetDefaultPolicy(); + script << m.getCompiledScript(); + script << m.commit(); + } + if (n.getCompiledScriptLength()>0) + { + script << n.flushAndSetDefaultPolicy(); + script << n.getCompiledScript(); + script << n.commit(); + } + script << "#" << endl; + script << ") | $IPTABLES_RESTORE; IPTABLES_RESTORE_RES=$?" << endl; } else { @@ -709,52 +677,15 @@ _("Dynamic interface %s should not have an IP address object attached to it. Thi script << "#" << endl; } + script << endl; + + if (options->getBool("use_iptables_restore")) + script << "exit $IPTABLES_RESTORE_RES"; + script << endl; string sbuf = script.str(); -/* starting with 2.0.3 we copy script to linksys using scp and do not - * need to escape double quotes and '$' anymore - */ - -#if 0 - if ( Resources::getTargetOptionBool(fw->getStr("host_OS"), - "escape_everything") ) - { -/* need to escape single and double quotes, as well as '$' in the script */ - - string::size_type i; - - i = 0; - while ( (i=sbuf.find('\"',i))!=string::npos ) - { - sbuf.replace(i,1,"\\\""); - i+=2; - } - - i = 0; - while ( (i=sbuf.find('\'',i))!=string::npos ) - { - sbuf.replace(i,1,"\\\'"); - i+=2; - } - - i = 0; - while ( (i=sbuf.find('`',i))!=string::npos ) - { - sbuf.replace(i,1,"\\`"); - i+=2; - } - - i = 0; - while ( (i=sbuf.find('$',i))!=string::npos ) - { - sbuf.replace(i,1,"\\$"); - i+=2; - } - } -#endif - ofstream fw_file; fw_file.exceptions(ofstream::eofbit|ofstream::failbit|ofstream::badbit); diff --git a/src/pflib/PolicyCompiler_pf_writers.cpp b/src/pflib/PolicyCompiler_pf_writers.cpp index 3d25380fa..5bc910019 100644 --- a/src/pflib/PolicyCompiler_pf_writers.cpp +++ b/src/pflib/PolicyCompiler_pf_writers.cpp @@ -134,34 +134,137 @@ void PolicyCompiler_pf::PrintRule::_printRouteOptions(PolicyRule *rule) if (rule->getAction() == PolicyRule::Route) { - if (ruleopt->getBool("pf_fastroute")) + string prefix = "pf"; + if (compiler->myPlatformName()=="ipf") + prefix="ipf"; + string ro = ruleopt->getStr(prefix+"_route_option"); + if (ruleopt->getBool("pf_fastroute") && ro != "none") + { + compiler->abort("Cannot use fastroute and route method in same rule they are mutually exclusive in rule "+rule->getLabel()); + } else if (ruleopt->getBool("pf_fastroute") && ro == "none" ) { compiler->output << "fastroute "; + } else { + string roif = ruleopt->getStr(prefix+"_route_opt_if"); + string roaddr_list = ruleopt->getStr(prefix+"_route_opt_addr"); + string roload = ruleopt->getStr("pf_route_load_option"); + if (!ro.empty()) + { + if (roif.empty()) + compiler->abort("Interface specification is required for action Route in rule "+rule->getLabel()); - string prefix = "pf"; - if (compiler->myPlatformName()=="ipf") - prefix="ipf"; + if (ro == "route_through") + compiler->output << "route-to "; + else if (ro == "route_reply_through") + compiler->output << "reply-to "; + else if (ro == "route_copy_through") + compiler->output << "dup-to "; + else + compiler->abort("Unknown option for rule action Route: '" + + ro + "' in rule "+rule->getLabel()); + + compiler->output << "{ "; - string ro = ruleopt->getStr(prefix+"_route_option"); - string roif = ruleopt->getStr(prefix+"_route_opt_if"); - string roaddr = ruleopt->getStr(prefix+"_route_opt_addr"); + int route_member = 0; + + std::istringstream buf(roaddr_list); + string roaddr; + while (std::getline(buf, roaddr, ',')) + { + if (!roaddr.empty()) + { + if (route_member > 0 ) + { + compiler->output << ", "; + } + compiler->output << "( "; + compiler->output << roif << " "; + compiler->output << roaddr << " "; + compiler->output << ") "; + int sp = roaddr.find('/'); + if (sp!=std::string::npos) + { + // roaddr is addr/netmask + try + { + string a = roaddr.substr(0,sp); + IPAddress roaddr_addr = IPAddress(a); + } catch (FWException &ex) + { + compiler->abort( + "Illegal IP address for next hop in rule "+rule->getLabel()); + } + try + { + Netmask roaddr_netmask; + string n = roaddr.substr(sp+1); + if (n.find('.')!=std::string::npos) + { + roaddr_netmask = n; + } else + { + roaddr_netmask = Netmask( + atoi(n.c_str())); + } + if (roaddr_netmask.getLength()==32) + route_member++; + else + // lame way to tell compiler that + // we actually have several addresses for + // the next hop. We do not exactly care + // how many there are, as long as it is + // greater than 1. + route_member += 2; + } catch (FWException &ex) + { + compiler->abort( + "Illegal netmask for next hop in rule "+rule->getLabel()); + } + } else + { + // roaddr is just an addres + try + { + IPAddress roaddr_addr = IPAddress(roaddr); + } catch (FWException &ex) + { + compiler->abort( + "Illegal IP address for next hop in rule "+rule->getLabel()); + } + route_member++; + } + } + } + if (route_member < 1) + { + compiler->abort("No router specified rule action Route: '"+ + ro + "' in rule "+rule->getLabel()); + } + if (route_member >= 2 && (roload.empty() || roload == "none")) + { + compiler->abort("More than one router specified without load balancing for rule action Route: '" + + ro + "' in rule "+rule->getLabel()); + } + if (route_member == 1 && ((!roload.empty()) && roload != "none")) + { + compiler->abort("Only one router specified with load balancing for rule action Route: '" + + ro + "' in rule "+rule->getLabel()); + } - if (!ro.empty()) - { - if (roif.empty()) - compiler->abort("Interface specification is required for action Route in rule "+rule->getLabel()); - - if (ro == "route_through") compiler->output << "route-to "; - else if (ro == "route_reply_through") compiler->output << "reply-to "; - else if (ro == "route_copy_through") compiler->output << "dup-to "; - else - compiler->abort("Unknown option for rule action Route: '" + - ro + "' in rule "+rule->getLabel()); - - compiler->output << "( "; - compiler->output << roif << " "; - if (!roaddr.empty()) compiler->output << roaddr << " "; - compiler->output << ") "; - } + compiler->output << "} "; + + if (!roload.empty()) + { + if (roload == "bitmask") + compiler->output << "bitmask "; + else if (roload == "random") + compiler->output << "random "; + else if (roload == "source_hash") + compiler->output << "source-hash "; + else if (roload == "round_robin") + compiler->output << "round-robin "; + } + } + } } } diff --git a/test/pf/objects-for-regression-tests.fwb b/test/pf/objects-for-regression-tests.fwb index 7b3e2e3cb..d64bfa299 100644 --- a/test/pf/objects-for-regression-tests.fwb +++ b/test/pf/objects-for-regression-tests.fwb @@ -1,6 +1,6 @@ - + @@ -9149,6 +9149,884 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +