From mboxrd@z Thu Jan 1 00:00:00 1970 From: Michael Tremer To: development@lists.ipfire.org Subject: Re: [PATCH] New addon: Portredirect 1.0 Date: Mon, 28 Jun 2021 17:04:27 +0100 Message-ID: <3A259275-0D4A-4863-9DEC-17F9689F0127@ipfire.org> In-Reply-To: <20210627134819.2088-1-matthias.fischer@ipfire.org> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============4582014111212784294==" List-Id: --===============4582014111212784294== Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Hello Matthias, > On 27 Jun 2021, at 14:48, Matthias Fischer = wrote: >=20 > From: Marcel Lorenz Thank you for sending this patch on Marcel=E2=80=99s behalf, but I would much= more prefer if he would submit his patches on his own. I do not see why that= isn=E2=80=99t possible. > Please note: > This is a new addon written by Marcel Lorenz . >=20 > It adds a new GUI to IPFire for DNS/NTP *and* user specific port redirectio= ns. >=20 > How its working: > It has exactly the same functionalities as "Forcing DNS/NTP..." - and some= more. >=20 > By setting switches, DNS/NTP requests are automatically > redirected to the local IPFire DNS/NTP servers. >=20 > Additionally, the user can specify custom redirections. >=20 > These rules are added to a new chain in PREROUTING =3D> PORT_REDIRECT. >=20 > To avoid problems with (e.g.) transparent 'squid' configurations, > redirection rules are added automatically before existing 'squid' rules. This message does unfortunately not say why this add-on would be useful. I am= emphasising this again and again that it is not very important how something= is done specially. That should be commented in the code and other implementa= tion details should also be documented there. As I have stated on this functionality many times before, I do not see why th= is is necessary at all. Why is this an add-on? Why do we not extend the firewall UI probably by about 20 lines of code inste= ad of adding many hundreds of lines? Please can someone elaborate on this more? -Michael > Signed-off-by: Matthias Fischer > --- > config/portredir/EX-portredir.menu | 6 + > config/portredir/lang/portredir.de.pl | 19 + > config/portredir/lang/portredir.en.pl | 19 + > config/portredir/portredir-backup | 1 + > config/portredir/portredir.cgi | 525 ++++++++++++++++++++++++++ > config/rootfiles/common/misc-progs | 1 + > config/rootfiles/packages/portredir | 11 + > lfs/portredir | 85 +++++ > make.sh | 1 + > src/initscripts/packages/portredir | 191 ++++++++++ > src/misc-progs/Makefile | 2 +- > src/misc-progs/portredirctrl.c | 47 +++ > src/paks/portredir/install.sh | 32 ++ > src/paks/portredir/uninstall.sh | 28 ++ > src/paks/portredir/update.sh | 26 ++ > 15 files changed, 993 insertions(+), 1 deletion(-) > create mode 100644 config/portredir/EX-portredir.menu > create mode 100644 config/portredir/lang/portredir.de.pl > create mode 100644 config/portredir/lang/portredir.en.pl > create mode 100644 config/portredir/portredir-backup > create mode 100644 config/portredir/portredir.cgi > create mode 100644 config/rootfiles/packages/portredir > create mode 100644 lfs/portredir > create mode 100644 src/initscripts/packages/portredir > create mode 100644 src/misc-progs/portredirctrl.c > create mode 100644 src/paks/portredir/install.sh > create mode 100644 src/paks/portredir/uninstall.sh > create mode 100644 src/paks/portredir/update.sh >=20 > diff --git a/config/portredir/EX-portredir.menu b/config/portredir/EX-portr= edir.menu > new file mode 100644 > index 000000000..8376e8053 > --- /dev/null > +++ b/config/portredir/EX-portredir.menu > @@ -0,0 +1,6 @@ > + $subfirewall->{'95.portredir'} =3D { > + 'caption' =3D> $Lang::tr{'portredir port redirections'}, > + 'uri' =3D> '/cgi-bin/portredir.cgi', > + 'title' =3D> "$Lang::tr{'portredir port redirections'}", > + 'enabled' =3D> 1 > + }; > diff --git a/config/portredir/lang/portredir.de.pl b/config/portredir/lang/= portredir.de.pl > new file mode 100644 > index 000000000..b932d4a85 > --- /dev/null > +++ b/config/portredir/lang/portredir.de.pl > @@ -0,0 +1,19 @@ > +%tr =3D ( > +%tr, > +'portredir enable addon' =3D> 'Addon aktivieren', > +'portredir common settings' =3D> 'Allgemeine Einstellungen', > +'portredir port redirections' =3D> 'Portumleitungen', > +'portredir fw for interface' =3D> 'Firewalloptionen f=C3=BCr das Interface= ', > +'portredir enable user redirections' =3D> 'Aktiviere benutzerdefinierte Po= rtumleitungen', > +'portredir force local dns' =3D> 'Erzwinge lokale DNS-Server', > +'portredir force local ntp' =3D> 'Erzwinge lokale NTP-Server', > +'portredir custom redirections' =3D> 'Benutzerdefinierte Portumleitungen', > +'portredir remove rule' =3D> 'Entferne Regel', > +'portredir add rule' =3D> 'Hinzuf=C3=BCgen', > +'portredir no entries' =3D> 'Keine Eintr=C3=A4ge vorhanden.', > +'portredir invalid address' =3D> 'Ung=C3=BCltige Host-Addresse.', > +'portredir empty input' =3D> 'Fehlende Angabe: Bitte geben Sie einen g=C3= =BCltigen Host an.', > +'portredir save to activate' =3D> 'Speichern, um =C3=84nderungen zu aktivi= eren', > +); > + > +#EOF > diff --git a/config/portredir/lang/portredir.en.pl b/config/portredir/lang/= portredir.en.pl > new file mode 100644 > index 000000000..f442f3eaa > --- /dev/null > +++ b/config/portredir/lang/portredir.en.pl > @@ -0,0 +1,19 @@ > +%tr =3D ( > +%tr, > +'portredir enable addon' =3D> 'Enable addon', > +'portredir common settings' =3D> 'Common settings', > +'portredir port redirections' =3D> 'Port redirections', > +'portredir fw for interface' =3D> 'Firewall options for interface', > +'portredir enable user redirections' =3D> 'Enable user port redirections', > +'portredir force local dns' =3D> 'Enforce local DNS servers', > +'portredir force local ntp' =3D> 'Enforce local NTP servers', > +'portredir custom redirections' =3D> 'Custom port redirections', > +'portredir remove rule' =3D> 'Remove rule', > +'portredir add rule' =3D> 'Add new', > +'portredir no entries' =3D> 'No entries at the moment.', > +'portredir invalid address' =3D> 'Invalid host address.', > +'portredir empty input' =3D> 'Empty input: Please enter a valid host.', > +'portredir save to activate' =3D> 'Save to activate changes', > +); > + > +#EOF > diff --git a/config/portredir/portredir-backup b/config/portredir/portredir= -backup > new file mode 100644 > index 000000000..bd2ada742 > --- /dev/null > +++ b/config/portredir/portredir-backup > @@ -0,0 +1 @@ > +/var/ipfire/portredir > diff --git a/config/portredir/portredir.cgi b/config/portredir/portredir.cgi > new file mode 100644 > index 000000000..4913dda3f > --- /dev/null > +++ b/config/portredir/portredir.cgi > @@ -0,0 +1,525 @@ > +#!/usr/bin/perl > +##########################################################################= ##### > +# = # > +# IPFire.org - A linux based firewall = # > +# Copyright (C) 2021 IPFire Team = # > +# = # > +# This program is free software: you can redistribute it and/or modify = # > +# it under the terms of the GNU General Public License as published by = # > +# the Free Software Foundation, either version 3 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. = # > +# = # > +# You should have received a copy of the GNU General Public License = # > +# along with this program. If not, see . = # > +# = # > +##########################################################################= ##### > + > +use strict; > + > +# enable only the following on debugging purpose > +use warnings; > +use CGI::Carp 'fatalsToBrowser'; > + > +require '/var/ipfire/general-functions.pl'; > +require "${General::swroot}/lang.pl"; > +require "${General::swroot}/header.pl"; > + > +# File declarations > +my $settingsfile =3D "${General::swroot}/portredir/settings"; > +my $redirectsfile =3D "${General::swroot}/portredir/redirects"; > + > +# Create empty settingsfiles if they does not exist yet > +unless (-e "$settingsfile") { system ("touch $settingsfile"); } > +unless (-e "$redirectsfile") { system ("touch $redirectsfile"); } > + > +# load ipfire settings > +our %netsettings =3D (); > +our %color =3D (); > +&General::readhash("${General::swroot}/ethernet/settings", \%netsettings); > +&General::readhash("/srv/web/ipfire/html/themes/ipfire/include/colors.txt"= , \%color); > + > +my %settings=3D(); > +my %portredirs=3D(); > +my %checked=3D(); # Checkbox manipulations > +my $errormessage=3D''; > +my %selected=3D(); > +our %redirects=3D(); > + > +$settings{'ACTION'} =3D ''; > +$settings{'REDIR_ENABLE_ADDON'}=3D"off"; > +$settings{'REDIR_CUSTOM_GREEN'}=3D"off"; > +$settings{'REDIR_CUSTOM_BLUE'}=3D"off"; > +$settings{'REDIR_CUSTOM_ORANGE'}=3D"off"; > +$settings{'REDIR_DNS_GREEN'}=3D"off"; > +$settings{'REDIR_NTP_GREEN'}=3D"off"; > +$settings{'REDIR_DNS_BLUE'}=3D"off"; > +$settings{'REDIR_NTP_BLUE'}=3D"off"; > +$settings{'REDIR_DNS_ORANGE'}=3D"off"; > +$settings{'REDIR_NTP_ORANGE'}=3D"off"; > + > +&Header::showhttpheaders(); > + > +# Get GUI values > +&Header::getcgihash(\%settings); > + > +# Save action > +if ($settings{'ACTION'} eq $Lang::tr{'save'}) { > + > + # If custom rules enabled, deactivate default rules on interface > + if ($settings{'REDIR_CUSTOM_GREEN'} eq "on" ) { > + $settings{'REDIR_DNS_GREEN'}=3D"off"; > + $settings{'REDIR_NTP_GREEN'}=3D"off"; > + } > + > + if ($settings{'REDIR_CUSTOM_BLUE'} eq "on" ) { > + $settings{'REDIR_DNS_BLUE'}=3D"off"; > + $settings{'REDIR_NTP_BLUE'}=3D"off"; > + } > + > + if ($settings{'REDIR_CUSTOM_ORANGE'} eq "on" ) { > + $settings{'REDIR_DNS_ORANGE'}=3D"off"; > + $settings{'REDIR_NTP_ORANGE'}=3D"off"; > + } > + > + &General::writehash($settingsfile, \%settings); > + > + if ($settings{'REDIR_ENABLE_ADDON'} eq "on") { > + system ('/usr/local/bin/portredirctrl restart >/dev/null 2>&1'); > + system ('/usr/local/bin/portredirctrl enable >/dev/null 2>&1'); > + &General::log('portredir addon: port redirections enabled'); > + } > + if ($settings{'REDIR_ENABLE_ADDON'} eq "off") { > + system ('/usr/local/bin/portredirctrl disable >/dev/null 2>&1'); > + system ('/usr/local/bin/portredirctrl stop >/dev/null 2>&1'); > + &General::log('portredir addon: port redirections disabled'); > + } > + > +# Add/edit an entry to the redirectsfile. > + > +} elsif (($settings{'ACTION'} eq $Lang::tr{'add'}) || ($settings{'ACTION'}= eq $Lang::tr{'update'})) { > + > + # Check if any input has been performed. > + if ($settings{'REDIR_ENTRY_ADDRESS'} ne '') { > + > + # Check if the given input is no valid IP-address, display an error mess= age. > + if (!&General::validip($settings{'REDIR_ENTRY_ADDRESS'})) { > + $errormessage =3D "$Lang::tr{'portredir invalid address'}"; > + } > + } else { > + $errormessage =3D "$Lang::tr{'portredir empty input'}"; > + } > + > + # Go further if there was no error. > + if ($errormessage eq '') { > + my %redirects =3D (); > + my $id; > + my $status; > + > + # Assign hash values. > + my $new_entry_interface =3D $settings{'REDIR_ENTRY_INTERFACE'}; > + my $new_entry_protocol =3D $settings{'REDIR_ENTRY_PROTOCOL'}; > + my $new_entry_port =3D $settings{'REDIR_ENTRY_PORT'}; > + my $new_entry_address =3D $settings{'REDIR_ENTRY_ADDRESS'}; > + my $new_entry_remark =3D $settings{'REDIR_ENTRY_REMARK'}; > + > + # Read-in redirectsfile. > + &General::readhasharray($redirectsfile, \%redirects); > + > + # Check if we should edit an existing entry and got an ID. > + if (($settings{'ACTION'} eq $Lang::tr{'update'}) && ($settings{'ID'})) { > + # Assin the provided id. > + $id =3D $settings{'ID'}; > + > + # Undef the given ID. > + undef($settings{'ID'}); > + > + # Grab the configured status of the corresponding entry. > + $status =3D $redirects{$id}[4]; > + } else { > + # Each newly added entry automatically should be enabled. > + $status =3D "enabled"; > + > + # Generate the ID for the new entry. > + # > + # Sort the keys by their ID and store them in an array. > + my @keys =3D sort { $a <=3D> $b } keys %redirects; > + > + # Reverse the key array. > + my @reversed =3D reverse(@keys); > + > + # Obtain the last used id. > + my $last_id =3D @reversed[0]; > + > + # Increase the last id by one and use it as id for the new entry. > + $id =3D ++$last_id; > + } > + > + # Add/Modify the entry to/in the redirects hash. > + $redirects{$id} =3D ["$new_entry_interface", "$new_entry_protocol", "$ne= w_entry_port", "$new_entry_address","$status", "$new_entry_remark"]; > + > + # Write the changed redirects hash to the redirects file. > + &General::writehasharray($redirectsfile, \%redirects); > + } > + > +# Toggle Enabled/Disabled for an existing entry on the redirects list. > + > +} elsif ($settings{'ACTION'} eq $Lang::tr{'toggle enable disable'}) { > + my %redirects =3D (); > + > + # Only go further, if an ID has been passed. > + if ($settings{'ID'}) { > + # Assign the given ID. > + my $id =3D $settings{'ID'}; > + > + # Undef the given ID. > + undef($settings{'ID'}); > + > + # Read-in ignoredfile. > + &General::readhasharray($redirectsfile, \%redirects); > + > + # Grab the configured status of the corresponding entry. > + my $status =3D $redirects{$id}[4]; > + > + # Switch the status. > + if ($status eq "disabled") { > + $status =3D "enabled"; > + } else { > + $status =3D "disabled"; > + } > + > + # Modify the status of the existing entry. > + $redirects{$id} =3D ["$redirects{$id}[0]", "$redirects{$id}[1]", "$redir= ects{$id}[2]", "$redirects{$id}[3]","$status", "$redirects{$id}[5]"]; > + > + # Write the changed ignored hash to the redirects file. > + &General::writehasharray($redirectsfile, \%redirects); > + } > + > +# Remove entry from redirects list. > + > +} elsif ($settings{'ACTION'} eq $Lang::tr{'remove'}) { > + my %redirects =3D (); > + > + # Read-in redirectsfile. > + &General::readhasharray($redirectsfile, \%redirects); > + > + # move data on key up > + foreach my $key (sort keys %redirects) { > + if ($key >=3D $settings{'ID'}) { > + my $next =3D $key + 1; > + if (exists $redirects{$next}) { > + foreach my $i (0 .. $#{$redirects{$next}}) { $redirects{$key}[$i] =3D = $redirects{$next}[$i]; } > + } > + } > + } > + > + my $last_key =3D (sort {$a <=3D> $b} keys %redirects)[-1]; > + delete $redirects{$last_key}; > + > + # Undef the given ID. > + undef($settings{'ID'}); > + > + # Write the changed redirects hash to file. > + &General::writehasharray($redirectsfile, \%redirects); > +} > + > +# Load settings from file > +&General::readhash($settingsfile, \%settings); > +&General::readhasharray($redirectsfile, \%redirects); > + > +# Call functions to generate whole page. > +&Header::openpage($Lang::tr{'portredir port redirections'}, 1, ''); > +&Header::openbigbox('100%', 'left', '', $errormessage); > + > +if ($errormessage) { > + &Header::openbox('100%', 'left', $Lang::tr{'warning messages'}); > + print "$errormessage "; > + &Header::closebox(); > +} > + > +$checked{'REDIR_ENABLE_ADDON'}{'off'} =3D ''; > +$checked{'REDIR_ENABLE_ADDON'}{'on'} =3D ''; > +$checked{'REDIR_ENABLE_ADDON'}{$settings{'REDIR_ENABLE_ADDON'}} =3D "check= ed=3D'checked'"; > +$checked{'REDIR_CUSTOM_GREEN'}{'off'} =3D ''; > +$checked{'REDIR_CUSTOM_GREEN'}{'on'} =3D ''; > +$checked{'REDIR_CUSTOM_GREEN'}{$settings{'REDIR_CUSTOM_GREEN'}} =3D "check= ed=3D'checked'"; > +$checked{'REDIR_CUSTOM_BLUE'}{'off'} =3D ''; > +$checked{'REDIR_CUSTOM_BLUE'}{'on'} =3D ''; > +$checked{'REDIR_CUSTOM_BLUE'}{$settings{'REDIR_CUSTOM_BLUE'}} =3D "checked= =3D'checked'"; > +$checked{'REDIR_CUSTOM_ORANGE'}{'off'} =3D ''; > +$checked{'REDIR_CUSTOM_ORANGE'}{'on'} =3D ''; > +$checked{'REDIR_CUSTOM_ORANGE'}{$settings{'REDIR_CUSTOM_ORANGE'}} =3D "che= cked=3D'checked'"; > +$checked{'REDIR_DNS_GREEN'}{'off'} =3D ''; > +$checked{'REDIR_DNS_GREEN'}{'on'} =3D ''; > +$checked{'REDIR_DNS_GREEN'}{$settings{'REDIR_DNS_GREEN'}} =3D "checked=3D'= checked'"; > +$checked{'REDIR_NTP_GREEN'}{'off'} =3D ''; > +$checked{'REDIR_NTP_GREEN'}{'on'} =3D ''; > +$checked{'REDIR_NTP_GREEN'}{$settings{'REDIR_NTP_GREEN'}} =3D "checked=3D'= checked'"; > +$checked{'REDIR_DNS_BLUE'}{'off'} =3D ''; > +$checked{'REDIR_DNS_BLUE'}{'on'} =3D ''; > +$checked{'REDIR_DNS_BLUE'}{$settings{'REDIR_DNS_BLUE'}} =3D "checked=3D'ch= ecked'"; > +$checked{'REDIR_NTP_BLUE'}{'off'} =3D ''; > +$checked{'REDIR_NTP_BLUE'}{'on'} =3D ''; > +$checked{'REDIR_NTP_BLUE'}{$settings{'REDIR_NTP_BLUE'}} =3D "checked=3D'ch= ecked'"; > +$checked{'REDIR_DNS_ORANGE'}{'off'} =3D ''; > +$checked{'REDIR_DNS_ORANGE'}{'on'} =3D ''; > +$checked{'REDIR_DNS_ORANGE'}{$settings{'REDIR_DNS_ORANGE'}} =3D "checked= =3D'checked'"; > +$checked{'REDIR_NTP_ORANGE'}{'off'} =3D ''; > +$checked{'REDIR_NTP_ORANGE'}{'on'} =3D ''; > +$checked{'REDIR_NTP_ORANGE'}{$settings{'REDIR_NTP_ORANGE'}} =3D "checked= =3D'checked'"; > + > +$selected{'REDIR_ENTRY_INTERFACE'}{$settings{'REDIR_ENTRY_INTERFACE'}} =3D= 'selected'; > +$selected{'REDIR_ENTRY_PROTOCOL'}{$settings{'REDIR_ENTRY_PROTOCOL'}} =3D '= selected'; > + > +&showMainBox(); > +&showRedirectsBox(); > + > +&Header::closebigbox(); > +&Header::closepage(); > + > +# Function to show main settings and options. > +sub showMainBox() { > + > + &Header::openbox('100%', 'center', "$Lang::tr{'settings'}"); > + print "
"; > + > +print < + > + + > + > + > + > + > +END > + > + # create html table with header line 1 > + print "
$La= ng::tr{'portredir common settings'}
$Lang::tr{'portredir enable addon'}: > +
 
"; > + print ""; > + if ($netsettings{'GREEN_DEV'}) {print ""; > + } else { print ""; } > + if ($netsettings{'BLUE_DEV'}) {print ""; > + } else { print ""; } > + if ($netsettings{'ORANGE_DEV'}) {print ""; > + } else { print ""; } > + > + # the empty right row > + print ""; > + > + # line 2 > + print ""; > + if ($netsettings{'GREEN_DEV'}) {print "";} else { print "";} > + if ($netsettings{'BLUE_DEV'}) {print "";} else { print "";} > + if ($netsettings{'ORANGE_DEV'}) {print "";} else { print "";} > + > + # line 3 > + print ""; > + if ($netsettings{'GREEN_DEV'}) {print "";} else { print "";} > + if ($netsettings{'BLUE_DEV'}) {print "";} else { print "";} > + if ($netsettings{'ORANGE_DEV'}) {print "";} else { print "";} > + > + # line 4 > + print ""; > + if ($netsettings{'GREEN_DEV'}) {print "";} else { print "";} > + if ($netsettings{'BLUE_DEV'}) {print "";} else { print "";} > + if ($netsettings{'ORANGE_DEV'}) {print "";} else { print "";} > + > + print < +
$Lang::tr{'port= redir fw for interface'}= $Lang::tr{'green'}= $Lang::tr{'blue'}= $Lang::tr{'orange'}
$Lang::tr{'portredir force local dns'}
$Lang::tr{'portredir force local ntp'}
$Lang::tr{'portredir enable user redirections'}
> + > + > + > +
 
$Lang::tr{'portredir save to activate'}
> +END > + > +&Header::closebox(); > +} > + > +# Function to show elements of the redirects file and allow to add or remo= ve single members of it. > +sub showRedirectsBox() { > + &Header::openbox('100%', 'center', "$Lang::tr{'portredir custom re= directions'}"); > + > + print < + > + > + > + > + > + > + > + > + > +END > + # Check if some rules have been added to be redirects. > + if (keys (%redirects)) { > + my $col =3D ""; > + > + # List all entries of the hash. > + foreach my $key (sort keys %redirects){ > + > + # Assign data array positions to some nice variable names. > + my $interface =3D $redirects{$key}[0]; > + my $protocol =3D $redirects{$key}[1]; > + my $port =3D $redirects{$key}[2]; > + my $address =3D $redirects{$key}[3]; > + my $status =3D $redirects{$key}[4]; > + my $remark =3D $redirects{$key}[5]; > + > + # Check if the key (id) number is even or not. > + if ($settings{'ID'} eq $key) { > + $col=3D"bgcolor=3D'${Header::colouryellow}'"; > + } elsif ($key % 2) { > + $col=3D"bgcolor=3D'$color{'color22'}'"; > + } else { > + $col=3D"bgcolor=3D'$color{'color20'}'"; > + } > + > + # Choose icon for the checkbox. > + my $gif; > + my $gdesc; > + > + # Check if the status is enabled and select the correct image and des= cription. > + if ($status eq 'enabled' ) { > + $gif =3D 'on.gif'; > + $gdesc =3D $Lang::tr{'click to disable'}; > + } else { > + $gif =3D 'off.gif'; > + $gdesc =3D $Lang::tr{'click to enable'}; > + } > + > + print < + > + > + > + > + > + > + > + > + > + > +END > + } > + } else { > + # Print notice that currently no ports are redirected. > + print "\n"; > + print "\n"; > + print "\n"; > + } > + > + print "
$= Lang::tr{'interface'}$= Lang::tr{'protocol'}$= Lang::tr{'port'}$= Lang::tr{'ip address'}$= Lang::tr{'remark'}
$Lang::tr{$interface}$protocol$port $addres= s $remark= > +
> + > + > + > +
> +
> +
> + > + > + > +
> +
> +
> + > + > + > +
> +
$Lang::tr{'portredir no entrie= s'}
\n"; > + > + # Section to add new elements or edit existing ones. > + print < +
> +
> +
> +
> + > +END > + > + # Assign correct headline and button text. > + my $buttontext; > + my $entry_interface; > + my $entry_protocol; > + my $entry_port; > + my $entry_address; > + my $entry_remark; > + > + # Check if an ID (key) has been given, in this case an existing entry sho= uld be edited. > + if ($settings{'ID'} ne '') { > + $buttontext =3D $Lang::tr{'update'}; > + print "\n"; > + > + # Grab address and remark for the given key. > + $entry_interface =3D $redirects{$settings{'ID'}}[0]; > + $entry_protocol =3D $redirects{$settings{'ID'}}[1]; > + $entry_port =3D $redirects{$settings{'ID'}}[2]; > + $entry_address =3D $redirects{$settings{'ID'}}[3]; > + $entry_remark =3D $redirects{$settings{'ID'}}[5]; > + > + } else { > + $buttontext =3D $Lang::tr{'add'}; > + print "\n"; > + print "\n"; > + } > + > + print < + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > + > +
$Lang::tr{'update'}
$Lang::tr{'dnsforwar= d add a new entry'}
 
$Lang::tr{'interface'}$Lang::tr{'protocol'} $Lang::tr{'port'} $Lang::tr{'ip address'} $Lang::tr{'remark'}
> +
> +END > + &Header::closebox(); > +} > diff --git a/config/rootfiles/common/misc-progs b/config/rootfiles/common/m= isc-progs > index d6594b3f8..fbad2af8b 100644 > --- a/config/rootfiles/common/misc-progs > +++ b/config/rootfiles/common/misc-progs > @@ -17,6 +17,7 @@ usr/local/bin/logwatch > #usr/local/bin/mpfirectrl > usr/local/bin/openvpnctrl > usr/local/bin/pakfire > +#usr/local/bin/portredirctrl > usr/local/bin/qosctrl > usr/local/bin/rebuildhosts > usr/local/bin/rebuildroutes > diff --git a/config/rootfiles/packages/portredir b/config/rootfiles/package= s/portredir > new file mode 100644 > index 000000000..4b4ba8366 > --- /dev/null > +++ b/config/rootfiles/packages/portredir > @@ -0,0 +1,11 @@ > +etc/rc.d/init.d/portredir > +etc/rc.d/rc0.d/K77portredir > +etc/rc.d/rc3.d/S23portredir > +etc/rc.d/rc6.d/K77portredir > +srv/web/ipfire/cgi-bin/portredir.cgi > +usr/local/bin/portredirctrl > +var/ipfire/addon-lang/portredir.de.pl > +var/ipfire/addon-lang/portredir.en.pl > +var/ipfire/backup/addons/includes/portredir > +var/ipfire/menu.d/EX-portredir.menu > +var/ipfire/portredir > diff --git a/lfs/portredir b/lfs/portredir > new file mode 100644 > index 000000000..a4911f71f > --- /dev/null > +++ b/lfs/portredir > @@ -0,0 +1,85 @@ > +##########################################################################= ##### > +# = # > +# IPFire.org - A linux based firewall = # > +# Copyright (C) 2007-2021 IPFire Team = # > +# = # > +# This program is free software: you can redistribute it and/or modify = # > +# it under the terms of the GNU General Public License as published by = # > +# the Free Software Foundation, either version 3 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. = # > +# = # > +# You should have received a copy of the GNU General Public License = # > +# along with this program. If not, see . = # > +# = # > +##########################################################################= ##### > + > +##########################################################################= ##### > +# Definitions > +##########################################################################= ##### > + > +include Config > + > +VER =3D 1.0 > + > +THISAPP =3D portredir-$(VER) > +DIR_APP =3D $(DIR_SRC)/$(THISAPP) > +TARGET =3D $(DIR_INFO)/$(THISAPP) > +PROG =3D portredir > +PAK_VER =3D 1 > + > +##########################################################################= ##### > +# Top-level Rules > +##########################################################################= ##### > + > +install : $(TARGET) > + > +check : > + > +download : > + > +md5 : > + > +dist:=20 > + @$(PAK) > + > +##########################################################################= ##### > +# Installation Details > +##########################################################################= ##### > + > +$(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects)) > + @$(PREBUILD) > + @rm -rf $(DIR_APP) && cd $(DIR_SRC) > + > + #install cgi=20 > + install -v -m 755 $(DIR_CONF)/portredir/portredir.cgi /srv/web/ipfire/cgi= -bin/ > + > + #create configuration dir=20 > + -mkdir -pv /var/ipfire/portredir/ > + chown -R nobody:nobody /var/ipfire/portredir/ > + > + # Install include file for backup > + install -v -m 644 $(DIR_CONF)/portredir/portredir-backup /var/ipfire/back= up/addons/includes/portredir > + > + # Install menu file > + install -v -m 644 $(DIR_CONF)/portredir/EX-portredir.menu /var/ipfire/men= u.d/ > + chown nobody:nobody /var/ipfire/menu.d/EX-portredir.menu > + > + # Install addon-specific language-files > + install -v -m 644 $(DIR_CONF)/portredir/lang/portredir.*.pl /var/ipfire/a= ddon-lang/ > + > + #install initscripts > + $(call INSTALL_INITSCRIPT,portredir) > + > + # Create symlinks for runlevel interaction. > + ln -svf /etc/rc.d/init.d/portredir /etc/rc.d/rc3.d/S23portredir > + ln -svf /etc/rc.d/init.d/portredir /etc/rc.d/rc0.d/K77portredir > + ln -svf /etc/rc.d/init.d/portredir /etc/rc.d/rc6.d/K77portredir > + > + @rm -rf $(DIR_APP) > + @$(POSTBUILD) > + > diff --git a/make.sh b/make.sh > index fc03ebcd5..ab9fe881a 100755 > --- a/make.sh > +++ b/make.sh > @@ -1623,6 +1623,7 @@ buildipfire() { > lfsmake2 socat > lfsmake2 libcdada > lfsmake2 pmacct > + lfsmake2 portredir > } >=20 > buildinstaller() { > diff --git a/src/initscripts/packages/portredir b/src/initscripts/packages/= portredir > new file mode 100644 > index 000000000..cc57fb9cc > --- /dev/null > +++ b/src/initscripts/packages/portredir > @@ -0,0 +1,191 @@ > +#!/bin/sh > +######################################################################## > +# Begin $rc_base/init.d/portredir > +# > +# Description : portredir init script for DNS/NTP and custom=20 > +# port redirection rules > +# > +######################################################################## > + > +. /etc/sysconfig/rc > +. ${rc_functions} > + > +IPT=3D"/sbin/iptables"; > +parent_chain=3D"PREROUTING"; > +chain=3D"PORT_REDIRECT"; > + > +confdir=3D"/var/ipfire/portredir"; > +settingsfile=3D"${confdir}/settings"; > +redirectsfile=3D"${confdir}/redirects"; > +SYSLOG=3D"NO"; > +VERBOSE=3D"NO"; > + > +eval $(/usr/local/bin/readhash /var/ipfire/ethernet/settings); > +eval $(/usr/local/bin/readhash ${settingsfile}); > + > +logtext() { > + if [ "${SYSLOG}" =3D "YES" ]; then logger -t "portredir" ${1}; fi; > + if [ "${VERBOSE}" =3D "YES" ]; then echo ${1}; fi;} > + > +create_chain() { > + > + local line=3D$(${IPT} -t nat -L ${parent_chain} --line-numbers |grep "SQU= ID" |awk '{printf($1)}'); > + > + if [[ "${REDIR_ENABLE_ADDON}" =3D=3D "off" || -z "${REDIR_ENABLE_ADDON}" = ]]; then > + logtext "addon not enabled in web interface..."; > + echo "Portredir addon not enabled in web interface..."; > + exit 0; > + fi; > + > + if [ -z "$(${IPT} -t nat -L ${parent_chain} |grep ${chain})" ]; then > + ${IPT} -t nat -N ${chain}; > + > + if [ ! -z "${line}" ]; then > + logtext "create chain ${chain} and link in ${parent_chain} at position = ${line}..."; > + ${IPT} -t nat -I ${parent_chain} ${line} -j ${chain}; > + else > + logtext "create chain ${chain} and link in ${parent_chain} at last posi= tion..."; > + ${IPT} -t nat -A ${parent_chain} -j ${chain}; > + fi > + else > + return 1; > + fi; > + return 0; > +} > + > +remove_chain() { > + if [ ! -z "$(${IPT} -t nat -L ${parent_chain} |grep ${chain})" ]; then > + logtext "remove chain ${chain} and link in ${parent_chain} from system..= ."; > + ${IPT} -t nat -D "${parent_chain}" -j ${chain}; > + ${IPT} -t nat -F ${chain}; > + ${IPT} -t nat -X ${chain}; > + else > + return 1; > + fi; > + return 0; > +} > + > +activate_custom_redirections() { > +=09 > + local array=3D(); > + local redirects=3D(); > + local i; > + index=3D(); > + iface=3D(); > + protocol=3D(); > + port=3D(); > + targetip=3D(); > + enabled=3D(); > + > + IFS=3D$'\n' read -d '' -ra redirects < ${redirectsfile}; > + > + for i in "${!redirects[@]}" > + do > + IFS=3D$',' read -ra array <<< ${redirects[i]}; > + index[i]=3D${array[0]}; > + iface[i]=3D${array[1]}; > + protocol[i]=3D${array[2]}; > + port[i]=3D${array[3]}; > + targetip[i]=3D${array[4]}; > + enabled[i]=3D${array[5]}; > + done > + > + for i in "${!index[@]}" > + do > + if [[ ! -z "${GREEN_DEV}" && "${iface[i]}" =3D "green" && "${enabled[i]= }" =3D "enabled" ]]; then > + > + logtext "add redirect in ${chain} on ${GREEN_DEV} ip ${targetip[i]} pro= tocol ${protocol[i]} port ${port[i]} "; > + ${IPT} -t nat -A ${chain} -i ${GREEN_DEV} -d ${targetip[i]} -p ${protoc= ol[i]} -m ${protocol[i]} --dport ${port[i]} -j RETURN; > + ${IPT} -t nat -A ${chain} -i ${GREEN_DEV} -p ${protocol[i]} -m ${protoc= ol[i]} --dport ${port[i]} -j REDIRECT; > + fi > + if [[ ! -z "${BLUE_DEV}" && "${iface[i]}" =3D "blue" && "${enabled[i]}"= =3D "enabled" ]]; then > + logtext "add redirect in ${chain} on ${BLUE_DEV} ip ${targetip[i]} prot= ocol ${protocol[i]} port ${port[i]} "; > + ${IPT} -t nat -A ${chain} -i ${BLUE_DEV} -d ${targetip[i]} -p ${protoco= l[i]} -m ${protocol[i]} --dport ${port[i]} -j RETURN; > + ${IPT} -t nat -A ${chain} -i ${BLUE_DEV} -p ${protocol[i]} -m ${protoco= l[i]} --dport ${port[i]} -j REDIRECT; > + fi > + if [[ ! -z "${ORANGE_DEV}" && "${iface[i]}" =3D "orange" && "${enabled[= i]}" =3D "enabled" ]]; then > + logtext "add redirect in ${chain} on ${ORANGE_DEV} ip ${targetip[i]} pr= otocol ${protocol[i]} port ${port[i]} "; > + ${IPT} -t nat -A ${chain} -i ${ORANGE_DEV} -d ${targetip[i]} -p ${proto= col[i]} -m ${protocol[i]} --dport ${port[i]} -j RETURN; > + ${IPT} -t nat -A ${chain} -i ${ORANGE_DEV} -p ${protocol[i]} -m ${proto= col[i]} --dport ${port[i]} -j REDIRECT; > + fi > + done > + unset array redirects i index iface protocol port targetip enabled; > + return 0; > +} > + > +activate_redirections() { > + > + if ! create_chain; then return 1; fi; > +=09 > + # Force DNS REDIRECTs on GREEN (udp, tcp, 53) > + if [[ "${REDIR_DNS_GREEN}" =3D=3D "on" && "${REDIR_CUSTOM_GREEN}" =3D "o= ff" ]]; then > + ${IPT} -t nat -A ${chain} -i ${GREEN_DEV} -d ${GREEN_ADDRESS} -p udp -m = udp --dport domain -j RETURN; > + ${IPT} -t nat -A ${chain} -i ${GREEN_DEV} -p udp -m udp --dport domain -= j REDIRECT; > + ${IPT} -t nat -A ${chain} -i ${GREEN_DEV} -d ${GREEN_ADDRESS} -p tcp -m = tcp --dport domain -j RETURN; > + ${IPT} -t nat -A ${chain} -i ${GREEN_DEV} -p tcp -m tcp --dport domain -= j REDIRECT; > + fi > + > + # Force DNS REDIRECTs on BLUE (udp, tcp, 53) > + if [[ "${REDIR_DNS_BLUE}" =3D=3D "on" && "${REDIR_CUSTOM_BLUE}" =3D "off= " ]]; then > + ${IPT} -t nat -A ${chain} -i ${BLUE_DEV} -d ${BLUE_ADDRESS} -p udp -m ud= p --dport domain -j RETURN > + ${IPT} -t nat -A ${chain} -i ${BLUE_DEV} -p udp -m udp --dport domain -j= REDIRECT > + ${IPT} -t nat -A ${chain} -i ${BLUE_DEV} -d ${BLUE_ADDRESS} -p tcp -m tc= p --dport domain -j RETURN > + ${IPT} -t nat -A ${chain} -i ${BLUE_DEV} -p tcp -m tcp --dport domain -j= REDIRECT > + fi > + > + # Force DNS REDIRECTs on ORANGE (udp, tcp, 53) > + if [[ "${REDIR_DNS_ORANGE}" =3D=3D "on" && "${REDIR_CUSTOM_ORANGE}" =3D = "off" ]]; then > + ${IPT} -t nat -A ${chain} -i ${ORANGE_DEV} -d ${ORANGE_ADDRESS} -p udp -= m udp --dport domain -j RETURN > + ${IPT} -t nat -A ${chain} -i ${ORANGE_DEV} -p udp -m udp --dport domain = -j REDIRECT > + ${IPT} -t nat -A ${chain} -i ${ORANGE_DEV} -d ${ORANGE_ADDRESS} -p tcp -= m tcp --dport domain -j RETURN > + ${IPT} -t nat -A ${chain} -i ${ORANGE_DEV} -p tcp -m tcp --dport domain = -j REDIRECT > + fi > + > + # Force NTP REDIRECTs on GREEN (udp, 123) > + if [[ "${REDIR_NTP_GREEN}" =3D=3D "on" && "${REDIR_CUSTOM_GREEN}" =3D "o= ff" ]]; then > + ${IPT} -t nat -A ${chain} -i ${GREEN_DEV} -d ${GREEN_ADDRESS} -p udp -m = udp --dport ntp -j RETURN > + ${IPT} -t nat -A ${chain} -i ${GREEN_DEV} -p udp -m udp --dport ntp -j R= EDIRECT > + fi > + > + # Force NTP REDIRECTs on BLUE (udp, 123) > + if [[ "${REDIR_NTP_BLUE}" =3D=3D "on" && "${REDIR_CUSTOM_BLUE}" =3D "off= " ]]; then > + ${IPT} -t nat -A ${chain} -i ${BLUE_DEV} -d ${BLUE_ADDRESS} -p udp -m ud= p --dport ntp -j RETURN > + ${IPT} -t nat -A ${chain} -i ${BLUE_DEV} -p udp -m udp --dport ntp -j RE= DIRECT > + fi > + > + # Force NTP REDIRECTs on ORANGE (udp, 123) > + if [[ "${REDIR_NTP_ORANGE}" =3D=3D "on" && "${REDIR_CUSTOM_ORANGE}" =3D = "off" ]]; then > + ${IPT} -t nat -A ${chain} -i ${ORANGE_DEV} -d ${ORANGE_ADDRESS} -p udp -= m udp --dport ntp -j RETURN > + ${IPT} -t nat -A ${chain} -i ${ORANGE_DEV} -p udp -m udp --dport ntp -j = REDIRECT > + fi > + > + if ! activate_custom_redirections; then return 1; fi; > + > + return 0; > +} > + > +case "${1}" in > + start) > + boot_mesg "Loading port redirections..." > + activate_redirections; > + evaluate_retval; > + ;; > + > + stop)=09 > + boot_mesg "Removing port redirections..." > + remove_chain; > + evaluate_retval; > + ;; > + > + restart) > + ${0} stop > + ${0} start > + ;; > + > + *) > + echo "Usage: ${0} {start|stop|restart}" > + exit 1 > + ;; > +esac > + > +# End $rc_base/init.d/portredir > diff --git a/src/misc-progs/Makefile b/src/misc-progs/Makefile > index 7c3ef7529..850f8fdcc 100644 > --- a/src/misc-progs/Makefile > +++ b/src/misc-progs/Makefile > @@ -30,7 +30,7 @@ SUID_PROGS =3D squidctrl sshctrl ipfirereboot \ > wirelessctrl getipstat qosctrl \ > redctrl syslogdctrl extrahdctrl sambactrl \ > smartctrl clamavctrl addonctrl pakfire mpfirectrl wlanapctrl \ > - setaliases urlfilterctrl updxlratorctrl fireinfoctrl rebuildroutes \ > + setaliases urlfilterctrl updxlratorctrl fireinfoctrl rebuildroutes portre= dirctrl \ > getconntracktable wirelessclient torctrl ddnsctrl unboundctrl \ > captivectrl >=20 > diff --git a/src/misc-progs/portredirctrl.c b/src/misc-progs/portredirctrl.c > new file mode 100644 > index 000000000..7897d711c > --- /dev/null > +++ b/src/misc-progs/portredirctrl.c > @@ -0,0 +1,47 @@ > +/* This file is part of the IPFire Firewall. > + * > + * This program is distributed under the terms of the GNU General Public > + * Licence. See the file COPYING for details. > + * > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include "setuid.h" > + > +int main(int argc, char *argv[]) { > + if (!(initsetuid())) > + exit(1); > + > + // Check what command is asked > + if (argc < 2) { > + fprintf(stderr, "\nNo argument given.\n\nportredirctrl (st= art|stop|restart|enable|disable)\n\n"); > + exit(1); > + } > + > + if (strcmp(argv[1], "start") =3D=3D 0) { > + safe_system("/etc/rc.d/init.d/portredir start"); > + } else if (strcmp(argv[1], "stop") =3D=3D 0) { > + safe_system("/etc/rc.d/init.d/portredir stop"); > + } else if (strcmp(argv[1], "restart") =3D=3D 0) { > + safe_system("/etc/rc.d/init.d/portredir restart"); > + } else if (strcmp(argv[1], "enable") =3D=3D 0) { > + safe_system("touch /var/ipfire/portredir/enable"); > + safe_system("ln -snf /etc/rc.d/init.d/portredir /etc/rc.d/rc3.d/S23portr= edir >/dev/null 2>&1"); > + safe_system("ln -snf /etc/rc.d/init.d/portredir /etc/rc.d/rc0.d/K77portr= edir >/dev/null 2>&1"); > + safe_system("ln -snf /etc/rc.d/init.d/portredir /etc/rc.d/rc6.d/K77portr= edir >/dev/null 2>&1"); > + } else if (strcmp(argv[1], "disable") =3D=3D 0) { > + safe_system("/etc/rc.d/init.d/portredir stop"); > + safe_system("unlink /var/ipfire/portredir/enable"); > + safe_system("rm -rf /etc/rc.d/rc*.d/*portredir >/dev/null 2>&1"); > + } else { > + fprintf(stderr, "\nBad argument given.\n\nportredirctrl (s= tart|stop|restart|enable|disable)\n\n"); > + exit(1); > + } > + > + return 0; > +} > diff --git a/src/paks/portredir/install.sh b/src/paks/portredir/install.sh > new file mode 100644 > index 000000000..9f69aeae2 > --- /dev/null > +++ b/src/paks/portredir/install.sh > @@ -0,0 +1,32 @@ > +#!/bin/bash > +##########################################################################= ## > +# = # > +# This file is part of the IPFire Firewall. = # > +# = # > +# IPFire is free software; you can redistribute it and/or modify = # > +# it under the terms of the GNU General Public License as published by = # > +# the Free Software Foundation; either version 2 of the License, or = # > +# (at your option) any later version. = # > +# = # > +# IPFire 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. = # > +# = # > +# You should have received a copy of the GNU General Public License = # > +# along with IPFire; if not, write to the Free Software = # > +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA= # > +# = # > +# Copyright (C) 2021 IPFire-Team . = # > +# = # > +##########################################################################= ## > +# > +. /opt/pakfire/lib/functions.sh > +extract_files > +restore_backup ${NAME} > + > +/usr/local/bin/update-lang-cache > + > +chown root:nobody /usr/local/bin/portredirctrl > +chmod 4750 /usr/local/bin/portredirctrl > +chmod u+s /usr/local/bin/portredirctrl > diff --git a/src/paks/portredir/uninstall.sh b/src/paks/portredir/uninstall= .sh > new file mode 100644 > index 000000000..df9270125 > --- /dev/null > +++ b/src/paks/portredir/uninstall.sh > @@ -0,0 +1,28 @@ > +#!/bin/bash > +##########################################################################= ## > +# = # > +# This file is part of the IPFire Firewall. = # > +# = # > +# IPFire is free software; you can redistribute it and/or modify = # > +# it under the terms of the GNU General Public License as published by = # > +# the Free Software Foundation; either version 2 of the License, or = # > +# (at your option) any later version. = # > +# = # > +# IPFire 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. = # > +# = # > +# You should have received a copy of the GNU General Public License = # > +# along with IPFire; if not, write to the Free Software = # > +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA= # > +# = # > +# Copyright (C) 2007 IPFire-Team . = # > +# = # > +##########################################################################= ## > +# > +. /opt/pakfire/lib/functions.sh > +make_backup ${NAME} > +remove_files > + > +/usr/local/bin/update-lang-cache > diff --git a/src/paks/portredir/update.sh b/src/paks/portredir/update.sh > new file mode 100644 > index 000000000..89c40d0d7 > --- /dev/null > +++ b/src/paks/portredir/update.sh > @@ -0,0 +1,26 @@ > +#!/bin/bash > +##########################################################################= ## > +# = # > +# This file is part of the IPFire Firewall. = # > +# = # > +# IPFire is free software; you can redistribute it and/or modify = # > +# it under the terms of the GNU General Public License as published by = # > +# the Free Software Foundation; either version 2 of the License, or = # > +# (at your option) any later version. = # > +# = # > +# IPFire 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. = # > +# = # > +# You should have received a copy of the GNU General Public License = # > +# along with IPFire; if not, write to the Free Software = # > +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA= # > +# = # > +# Copyright (C) 2007 IPFire-Team . = # > +# = # > +##########################################################################= ## > +# > +. /opt/pakfire/lib/functions.sh > +./uninstall.sh > +./install.sh > --=20 > 2.18.0 >=20 --===============4582014111212784294==--