public inbox for development@lists.ipfire.org
 help / color / mirror / Atom feed
[parent not found: <CD95E831-4AE9-40B7-BB91-27B3F3164270@gmail.com>]
[parent not found: <6EBF1B5C-79B2-4258-B117-C2A4EB16CCFD@gmail.com>]
[parent not found: <ADA23788-C972-417C-8F55-DD9D3B335BE9@gmail.com>]
[parent not found: <A699ABA7-74D3-4551-A981-E2E3A0935F8E@gmail.com>]
[parent not found: <305D680D-4D10-4D99-9F1D-3589BDF08FA9@gmail.com>]
* [PATCH] New addon: Portredirect 1.0
@ 2021-06-27 13:48 Matthias Fischer
  2021-06-28 16:04 ` Michael Tremer
  0 siblings, 1 reply; 9+ messages in thread
From: Matthias Fischer @ 2021-06-27 13:48 UTC (permalink / raw)
  To: development

[-- Attachment #1: Type: text/plain, Size: 49002 bytes --]

From: Marcel Lorenz <marcel.lorenz(a)ipfire.org>

Please note:
This is a new addon written by Marcel Lorenz <marcel.lorenz(a)ipfire.org>.

It adds a new GUI to IPFire for DNS/NTP *and* user specific port redirections.

How its working:
It has exactly the same functionalities as "Forcing DNS/NTP..."  - and some more.

By setting switches, DNS/NTP requests are automatically
redirected to the local IPFire DNS/NTP servers.

Additionally, the user can specify custom redirections.

These rules are added to a new chain in PREROUTING => PORT_REDIRECT.

To avoid problems with (e.g.) transparent 'squid' configurations,
redirection rules are added automatically before existing 'squid' rules.

Signed-off-by: Matthias Fischer <matthias.fischer(a)ipfire.org>
---
 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

diff --git a/config/portredir/EX-portredir.menu b/config/portredir/EX-portredir.menu
new file mode 100644
index 000000000..8376e8053
--- /dev/null
+++ b/config/portredir/EX-portredir.menu
@@ -0,0 +1,6 @@
+    $subfirewall->{'95.portredir'} = {
+				'caption' => $Lang::tr{'portredir port redirections'},
+				'uri' => '/cgi-bin/portredir.cgi',
+				'title' => "$Lang::tr{'portredir port redirections'}",
+				'enabled' => 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 = (
+%tr,
+'portredir enable addon' => 'Addon aktivieren',
+'portredir common settings' => 'Allgemeine Einstellungen',
+'portredir port redirections' => 'Portumleitungen',
+'portredir fw for interface' => 'Firewalloptionen für das Interface',
+'portredir enable user redirections' => 'Aktiviere benutzerdefinierte Portumleitungen',
+'portredir force local dns' => 'Erzwinge lokale DNS-Server',
+'portredir force local ntp' => 'Erzwinge lokale NTP-Server',
+'portredir custom redirections' => 'Benutzerdefinierte Portumleitungen',
+'portredir remove rule' => 'Entferne Regel',
+'portredir add rule' => 'Hinzufügen',
+'portredir no entries' => 'Keine Einträge vorhanden.',
+'portredir invalid address' => 'Ungültige Host-Addresse.',
+'portredir empty input' => 'Fehlende Angabe: Bitte geben Sie einen gültigen Host an.',
+'portredir save to activate' => 'Speichern, um Änderungen zu aktivieren',
+);
+
+#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 = (
+%tr,
+'portredir enable addon' => 'Enable addon',
+'portredir common settings' => 'Common settings',
+'portredir port redirections' => 'Port redirections',
+'portredir fw for interface' => 'Firewall options for interface',
+'portredir enable user redirections' => 'Enable user port redirections',
+'portredir force local dns' => 'Enforce local DNS servers',
+'portredir force local ntp' => 'Enforce local NTP servers',
+'portredir custom redirections' => 'Custom port redirections',
+'portredir remove rule' => 'Remove rule',
+'portredir add rule' => 'Add new',
+'portredir no entries' => 'No entries at the moment.',
+'portredir invalid address' => 'Invalid host address.',
+'portredir empty input' => 'Empty input: Please enter a valid host.',
+'portredir save to activate' => '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  <info(a)ipfire.org>                          #
+#                                                                             #
+# 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 <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+###############################################################################
+
+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 = "${General::swroot}/portredir/settings";
+my $redirectsfile = "${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 = ();
+our %color = ();
+&General::readhash("${General::swroot}/ethernet/settings", \%netsettings);
+&General::readhash("/srv/web/ipfire/html/themes/ipfire/include/colors.txt", \%color);
+
+my %settings=();
+my %portredirs=();
+my %checked=(); # Checkbox manipulations
+my $errormessage='';
+my %selected=();
+our %redirects=();
+
+$settings{'ACTION'} = '';
+$settings{'REDIR_ENABLE_ADDON'}="off";
+$settings{'REDIR_CUSTOM_GREEN'}="off";
+$settings{'REDIR_CUSTOM_BLUE'}="off";
+$settings{'REDIR_CUSTOM_ORANGE'}="off";
+$settings{'REDIR_DNS_GREEN'}="off";
+$settings{'REDIR_NTP_GREEN'}="off";
+$settings{'REDIR_DNS_BLUE'}="off";
+$settings{'REDIR_NTP_BLUE'}="off";
+$settings{'REDIR_DNS_ORANGE'}="off";
+$settings{'REDIR_NTP_ORANGE'}="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'}="off";
+		$settings{'REDIR_NTP_GREEN'}="off";
+	}
+
+	if ($settings{'REDIR_CUSTOM_BLUE'} eq "on" ) {
+		$settings{'REDIR_DNS_BLUE'}="off";
+		$settings{'REDIR_NTP_BLUE'}="off";
+	}
+
+	if ($settings{'REDIR_CUSTOM_ORANGE'} eq "on" ) {
+		$settings{'REDIR_DNS_ORANGE'}="off";
+		$settings{'REDIR_NTP_ORANGE'}="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 message.
+		if (!&General::validip($settings{'REDIR_ENTRY_ADDRESS'}))  {
+			$errormessage = "$Lang::tr{'portredir invalid address'}";
+		}
+	} else {
+		$errormessage = "$Lang::tr{'portredir empty input'}";
+	}
+
+	# Go further if there was no error.
+	if ($errormessage eq '') {
+		my %redirects = ();
+		my $id;
+		my $status;
+
+		# Assign hash values.
+		my $new_entry_interface = $settings{'REDIR_ENTRY_INTERFACE'};
+		my $new_entry_protocol = $settings{'REDIR_ENTRY_PROTOCOL'};
+		my $new_entry_port = $settings{'REDIR_ENTRY_PORT'};
+		my $new_entry_address = $settings{'REDIR_ENTRY_ADDRESS'};
+		my $new_entry_remark = $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 = $settings{'ID'};
+
+			# Undef the given ID.
+			undef($settings{'ID'});
+
+			# Grab the configured status of the corresponding entry.
+			$status = $redirects{$id}[4];
+		} else {
+			# Each newly added entry automatically should be enabled.
+			$status = "enabled";
+
+			# Generate the ID for the new entry.
+			#
+			# Sort the keys by their ID and store them in an array.
+			my @keys = sort { $a <=> $b } keys %redirects;
+
+			# Reverse the key array.
+			my @reversed = reverse(@keys);
+
+			# Obtain the last used id.
+			my $last_id = @reversed[0];
+
+			# Increase the last id by one and use it as id for the new entry.
+			$id = ++$last_id;
+		}
+
+		# Add/Modify the entry to/in the redirects hash.
+		$redirects{$id} = ["$new_entry_interface", "$new_entry_protocol", "$new_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 = ();
+
+	# Only go further, if an ID has been passed.
+	if ($settings{'ID'}) {
+		# Assign the given ID.
+		my $id = $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 = $redirects{$id}[4];
+
+		# Switch the status.
+		if ($status eq "disabled") {
+			$status = "enabled";
+		} else {
+			$status = "disabled";
+		}
+
+		# Modify the status of the existing entry.
+		$redirects{$id} = ["$redirects{$id}[0]", "$redirects{$id}[1]", "$redirects{$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 = ();
+
+	# Read-in redirectsfile.
+	&General::readhasharray($redirectsfile, \%redirects);
+
+	# move data on key up
+	foreach my $key (sort keys %redirects) {
+		if ($key >= $settings{'ID'}) {
+			my $next = $key + 1;
+			if (exists $redirects{$next}) {
+				foreach my $i (0 .. $#{$redirects{$next}}) { $redirects{$key}[$i] = $redirects{$next}[$i]; }
+			}
+		}
+	}
+
+	my $last_key = (sort {$a <=> $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 "<font color='red'>$errormessage&nbsp;</font>";
+        &Header::closebox();
+}
+
+$checked{'REDIR_ENABLE_ADDON'}{'off'} = '';
+$checked{'REDIR_ENABLE_ADDON'}{'on'} = '';
+$checked{'REDIR_ENABLE_ADDON'}{$settings{'REDIR_ENABLE_ADDON'}} = "checked='checked'";
+$checked{'REDIR_CUSTOM_GREEN'}{'off'} = '';
+$checked{'REDIR_CUSTOM_GREEN'}{'on'} = '';
+$checked{'REDIR_CUSTOM_GREEN'}{$settings{'REDIR_CUSTOM_GREEN'}} = "checked='checked'";
+$checked{'REDIR_CUSTOM_BLUE'}{'off'} = '';
+$checked{'REDIR_CUSTOM_BLUE'}{'on'} = '';
+$checked{'REDIR_CUSTOM_BLUE'}{$settings{'REDIR_CUSTOM_BLUE'}} = "checked='checked'";
+$checked{'REDIR_CUSTOM_ORANGE'}{'off'} = '';
+$checked{'REDIR_CUSTOM_ORANGE'}{'on'} = '';
+$checked{'REDIR_CUSTOM_ORANGE'}{$settings{'REDIR_CUSTOM_ORANGE'}} = "checked='checked'";
+$checked{'REDIR_DNS_GREEN'}{'off'} = '';
+$checked{'REDIR_DNS_GREEN'}{'on'} = '';
+$checked{'REDIR_DNS_GREEN'}{$settings{'REDIR_DNS_GREEN'}} = "checked='checked'";
+$checked{'REDIR_NTP_GREEN'}{'off'} = '';
+$checked{'REDIR_NTP_GREEN'}{'on'} = '';
+$checked{'REDIR_NTP_GREEN'}{$settings{'REDIR_NTP_GREEN'}} = "checked='checked'";
+$checked{'REDIR_DNS_BLUE'}{'off'} = '';
+$checked{'REDIR_DNS_BLUE'}{'on'} = '';
+$checked{'REDIR_DNS_BLUE'}{$settings{'REDIR_DNS_BLUE'}} = "checked='checked'";
+$checked{'REDIR_NTP_BLUE'}{'off'} = '';
+$checked{'REDIR_NTP_BLUE'}{'on'} = '';
+$checked{'REDIR_NTP_BLUE'}{$settings{'REDIR_NTP_BLUE'}} = "checked='checked'";
+$checked{'REDIR_DNS_ORANGE'}{'off'} = '';
+$checked{'REDIR_DNS_ORANGE'}{'on'} = '';
+$checked{'REDIR_DNS_ORANGE'}{$settings{'REDIR_DNS_ORANGE'}} = "checked='checked'";
+$checked{'REDIR_NTP_ORANGE'}{'off'} = '';
+$checked{'REDIR_NTP_ORANGE'}{'on'} = '';
+$checked{'REDIR_NTP_ORANGE'}{$settings{'REDIR_NTP_ORANGE'}} = "checked='checked'";
+
+$selected{'REDIR_ENTRY_INTERFACE'}{$settings{'REDIR_ENTRY_INTERFACE'}} = 'selected';
+$selected{'REDIR_ENTRY_PROTOCOL'}{$settings{'REDIR_ENTRY_PROTOCOL'}} = 'selected';
+
+&showMainBox();
+&showRedirectsBox();
+
+&Header::closebigbox();
+&Header::closepage();
+
+# Function to show main settings and options.
+sub showMainBox() {
+
+	&Header::openbox('100%', 'center', "$Lang::tr{'settings'}");
+	print "<form method='post' action='$ENV{'SCRIPT_NAME'}'>";
+
+print <<END;
+<table width='80%' cellspacing='0' border='0'>
+	<tr><td colspan='2' class='base' bgcolor='$color{'color20'}'><b>$Lang::tr{'portredir common settings'}</b></td></tr
+	<tr>
+		<td width='25%' class='base'>$Lang::tr{'portredir enable addon'}:</td>
+		<td><input type='checkbox' name='REDIR_ENABLE_ADDON' $checked{'REDIR_ENABLE_ADDON'}{'on'} /></td>
+	</tr>
+	<tr><td colspan='2'></td></tr>
+	<tr><td colspan='2'>&nbsp;</td></tr>
+END
+
+	# create html table with header line 1
+	print "<table width='80%' cellspacing='0' border='0'><tr>";
+	print "<th class='base' width='40%' align='left'><b>$Lang::tr{'portredir fw for interface'}</th>";
+	if ($netsettings{'GREEN_DEV'})  {print "<th class='base' width='10%'><b><font color=green>$Lang::tr{'green'}</font></th>";
+		} else {		 print "<th class='base' width='10%'></font></th>"; }
+	if ($netsettings{'BLUE_DEV'})   {print "<th class='base' width='10%'><b><font color=blue>$Lang::tr{'blue'}</font></th>";
+		} else {		 print "<th class='base' width='10%'></font></th>"; }
+	if ($netsettings{'ORANGE_DEV'}) {print "<th class='base' width='10%'><b><font color=orange>$Lang::tr{'orange'}</font></th>";
+		} else {		 print "<th class='base' width='10%'></font></th>"; }
+
+	# the empty right row
+	print "<th class='base' width='30%'><td></td></th></tr>";
+
+	# line 2
+	print "<tr><td>$Lang::tr{'portredir force local dns'}</td>";
+	if ($netsettings{'GREEN_DEV'})  {print "<td class='base' align='center'><input type='checkbox' name='REDIR_DNS_GREEN' $checked{'REDIR_DNS_GREEN'}{'on'}></td>";} else { print "<td></td>";}
+	if ($netsettings{'BLUE_DEV'})   {print "<td class='base' align='center'><input type='checkbox' name='REDIR_DNS_BLUE' $checked{'REDIR_DNS_BLUE'}{'on'}></td>";} else { print "<td></td>";}
+	if ($netsettings{'ORANGE_DEV'}) {print "<td class='base' align='center'><input type='checkbox' name='REDIR_DNS_ORANGE' $checked{'REDIR_DNS_ORANGE'}{'on'}></td>";} else { print "<td></td>";}
+
+	# line 3
+	print "</tr><tr><td>$Lang::tr{'portredir force local ntp'}</td>";
+	if ($netsettings{'GREEN_DEV'})  {print "<td class='base' align='center'><input type='checkbox' name='REDIR_NTP_GREEN' $checked{'REDIR_NTP_GREEN'}{'on'}></td>";} else { print "<td></td>";}
+	if ($netsettings{'BLUE_DEV'})   {print "<td class='base' align='center'><input type='checkbox' name='REDIR_NTP_BLUE' $checked{'REDIR_NTP_BLUE'}{'on'}></td>";} else { print "<td></td>";}
+	if ($netsettings{'ORANGE_DEV'}) {print "<td class='base' align='center'><input type='checkbox' name='REDIR_NTP_ORANGE' $checked{'REDIR_NTP_ORANGE'}{'on'}></td>";} else { print "<td></td>";}
+
+	# line 4
+	print "</tr><tr><td>$Lang::tr{'portredir enable user redirections'}</td>";
+	if ($netsettings{'GREEN_DEV'})  {print "<td class='base' align='center'><input type='checkbox' name='REDIR_CUSTOM_GREEN' $checked{'REDIR_CUSTOM_GREEN'}{'on'}></td>";} else { print "<td></td>";}
+	if ($netsettings{'BLUE_DEV'})   {print "<td class='base' align='center'><input type='checkbox' name='REDIR_CUSTOM_BLUE' $checked{'REDIR_CUSTOM_BLUE'}{'on'}></td>";} else { print "<td></td>";}
+	if ($netsettings{'ORANGE_DEV'}) {print "<td class='base' align='center'><input type='checkbox' name='REDIR_CUSTOM_ORANGE' $checked{'REDIR_CUSTOM_ORANGE'}{'on'}></td>";} else { print "<td></td>";}
+
+	print <<END;
+	</tr></table>
+	<table width='80%' cellspacing='0' border='0'>
+		<tr><td colspan='2'>&nbsp;</td></tr>
+		<tr><td align='left'><b>$Lang::tr{'portredir save to activate'}</b></td><td width='5%' align='center'><input type='submit' name='ACTION' value='  $Lang::tr{'save'}  '></td></tr>
+	</table></form>
+END
+
+&Header::closebox();
+}
+
+# Function to show elements of the redirects file and allow to add or remove single members of it.
+sub showRedirectsBox() {
+        &Header::openbox('100%', 'center', "$Lang::tr{'portredir custom redirections'}");
+
+	print <<END;
+		<table width='80%' cellspacing='1' border='0'>
+			<tr>
+				<td class='base' bgcolor='$color{'color20'}' align='center'><b>$Lang::tr{'interface'}</b></td>
+				<td class='base' bgcolor='$color{'color20'}' align='center'><b>$Lang::tr{'protocol'}</b></td>
+				<td class='base' bgcolor='$color{'color20'}' align='center'><b>$Lang::tr{'port'}</b></td>
+				<td class='base' bgcolor='$color{'color20'}' align='center'><b>$Lang::tr{'ip address'}</b></td>
+				<td class='base' bgcolor='$color{'color20'}' align='center'><b>$Lang::tr{'remark'}</b></td>
+				<td class='base' colspan='3' bgcolor='$color{'color20'}'></td>
+			</tr>
+END
+			# Check if some rules have been added to be redirects.
+			if (keys (%redirects)) {
+				my $col = "";
+
+				# List all entries of the hash.
+				foreach my $key (sort keys %redirects){
+
+					# Assign data array positions to some nice variable names.
+					my $interface = $redirects{$key}[0];
+					my $protocol = $redirects{$key}[1];
+					my $port  = $redirects{$key}[2];
+					my $address = $redirects{$key}[3];
+					my $status  = $redirects{$key}[4];
+					my $remark  = $redirects{$key}[5];
+
+					# Check if the key (id) number is even or not.
+					if ($settings{'ID'} eq $key) {
+						$col="bgcolor='${Header::colouryellow}'";
+					} elsif ($key % 2) {
+						$col="bgcolor='$color{'color22'}'";
+					} else {
+						$col="bgcolor='$color{'color20'}'";
+					}
+
+					# Choose icon for the checkbox.
+					my $gif;
+					my $gdesc;
+
+					# Check if the status is enabled and select the correct image and description.
+					if ($status eq 'enabled' ) {
+						$gif = 'on.gif';
+						$gdesc = $Lang::tr{'click to disable'};
+					} else {
+						$gif = 'off.gif';
+						$gdesc = $Lang::tr{'click to enable'};
+					}
+
+					print <<END;
+					<tr>
+						<td width='15%' class='base' align='center' $col><b><font color=$interface>$Lang::tr{$interface}</font></b></td>
+						<td width='10%' class='base' align='center' $col>$protocol</td>
+						<td width='10%' class='base' align='center' $col>$port</td>
+						<td width='15%' class='base' align='center' $col>&nbsp;$address</td>
+						<td width='40%' class='base' align='center' $col>&nbsp;$remark</td>
+						<td align='center' $col>
+							<form method='post' action='$ENV{'SCRIPT_NAME'}'>
+								<input type='hidden' name='ACTION' value='$Lang::tr{'toggle enable disable'}' />
+								<input type='image' name='$Lang::tr{'toggle enable disable'}' src='/images/$gif' alt='$gdesc' title='$gdesc' />
+								<input type='hidden' name='ID' value='$key' />
+							</form>
+						</td>
+						<td align='center' $col>
+							<form method='post' action='$ENV{'SCRIPT_NAME'}'>
+								<input type='hidden' name='ACTION' value='$Lang::tr{'edit'}' />
+								<input type='image' name='$Lang::tr{'edit'}' src='/images/edit.gif' alt='$Lang::tr{'edit'}' title='$Lang::tr{'edit'}' />
+								<input type='hidden' name='ID' value='$key' />
+							</form>
+						</td>
+						<td align='center' $col>
+							<form method='post' name='$key' action='$ENV{'SCRIPT_NAME'}'>
+								<input type='image' name='$Lang::tr{'remove'}' src='/images/delete.gif' title='$Lang::tr{'remove'}' alt='$Lang::tr{'remove'}'>
+								<input type='hidden' name='ID' value='$key'>
+								<input type='hidden' name='ACTION' value='$Lang::tr{'remove'}'>
+							</form>
+						</td>
+					</tr>
+END
+				}
+			} else {
+				# Print notice that currently no ports are redirected.
+				print "<tr>\n";
+				print "<td class='base' colspan='2'>$Lang::tr{'portredir no entries'}</td>\n";
+				print "</tr>\n";
+			}
+
+		print "</table>\n";
+
+	# Section to add new elements or edit existing ones.
+	print <<END;
+	<br>
+	<hr>
+	<br>
+	<div align='center'>
+		<table width='100%' cellspacing='0' border='0'>
+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 should be edited.
+	if ($settings{'ID'} ne '') {
+		$buttontext = $Lang::tr{'update'};
+		print "<tr><td class='boldbase' colspan='6'><b>$Lang::tr{'update'}</b></td></tr>\n";
+
+		# Grab address and remark for the given key.
+		$entry_interface = $redirects{$settings{'ID'}}[0];
+		$entry_protocol = $redirects{$settings{'ID'}}[1];
+		$entry_port = $redirects{$settings{'ID'}}[2];
+		$entry_address = $redirects{$settings{'ID'}}[3];
+		$entry_remark = $redirects{$settings{'ID'}}[5];
+
+	} else {
+		$buttontext = $Lang::tr{'add'};
+		print "<tr><td class='boldbase' colspan='11'><b>$Lang::tr{'dnsforward add a new entry'}</b></td></tr>\n";
+		print "<tr><td>&nbsp</td></tr>\n";
+	}
+
+	print <<END;
+			<tr>
+				<td class='base' width='1%'  bgcolor='$color{'color22'}'></td>
+				<td class='base' width='15%' bgcolor='$color{'color22'}' align='left'><b>$Lang::tr{'interface'}</b></td>
+				<td class='base' width='10%' bgcolor='$color{'color22'}' align='left'><b>$Lang::tr{'protocol'}</b></td>
+				<td class='base' width='10%' bgcolor='$color{'color22'}' align='left'>&nbsp;<b>$Lang::tr{'port'}</b></td>
+				<td class='base' width='13%' bgcolor='$color{'color22'}' align='left'>&nbsp;<b>$Lang::tr{'ip address'}</b></td>
+				<td class='base' width='30%' bgcolor='$color{'color22'}' align='left'>&nbsp;<b>$Lang::tr{'remark'}</b></td>
+				<td class='base' width='15%' bgcolor='$color{'color22'}'></td>
+				<td class='base' width='1%'  bgcolor='$color{'color22'}'></td>
+			</tr>
+
+			<form method='post' action='$ENV{'SCRIPT_NAME'}'>
+			<input type='hidden' name='ID' value='$settings{'ID'}'>
+			<tr>
+				<td class='base'></td>
+				<td><select style='width:90px;' id='interface' name='REDIR_ENTRY_INTERFACE'>
+END
+				if ($netsettings{'GREEN_DEV'}) {
+					if ($entry_interface eq "green") {
+						print "<option value='green' selected='selected' {'green'}>$Lang::tr{'green'}</option>";
+					} else { print "<option value='green' {'green'}>$Lang::tr{'green'}</option>";}
+				}
+				if ($netsettings{'BLUE_DEV'}) {
+					if ($entry_interface eq "blue") { 
+						print "<option value='blue' selected='selected' {'blue'}>$Lang::tr{'blue'}</option>";
+					} else { print "<option value='blue' {'blue'}>$Lang::tr{'blue'}</option>";}
+				}
+				if ($netsettings{'ORANGE_DEV'}) {
+					if ($entry_interface eq "orange") { 
+						print "<option value='orange' selected='selected' {'orange'}>$Lang::tr{'orange'}</option>";
+					} else { print "<option value='orange' {'orange'}>$Lang::tr{'orange'}</option>";}
+				}
+
+			print "</select><td><select style='width:50px;' name='REDIR_ENTRY_PROTOCOL'>";
+			if ((!$entry_protocol) || ($entry_protocol eq "tcp")) {
+				print "<option selected='selected' id='protocol' value='tcp' {'tcp'}>tcp</option>";
+				print "<option value='udp' {'udp'}>udp</option>";
+			} elsif ($entry_protocol eq "udp") {
+				print "<option value='tcp' {'tcp'}>tcp</option>";
+				print "<option selected='selected' value='udp' {'udp'}>udp</option>";
+			}
+	print <<END;
+				</select></td>
+				<td><input type='text' name='REDIR_ENTRY_PORT'    value='$entry_port'    size='4'></td>
+				<td><input type='text' name='REDIR_ENTRY_ADDRESS' value='$entry_address' size='14'></td>
+				<td><input type='text' name='REDIR_ENTRY_REMARK'  value='$entry_remark'  size='35'></td>
+				<td width='10%' align='center'><input type='submit' name='ACTION' value='  $buttontext  '></td>
+				<td class='base'></td>
+			</tr>
+			</form>
+		</table>
+	</div>
+END
+	&Header::closebox();
+}
diff --git a/config/rootfiles/common/misc-progs b/config/rootfiles/common/misc-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/packages/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  <info(a)ipfire.org>                     #
+#                                                                             #
+# 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 <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+###############################################################################
+
+###############################################################################
+# Definitions
+###############################################################################
+
+include Config
+
+VER        = 1.0
+
+THISAPP    = portredir-$(VER)
+DIR_APP    = $(DIR_SRC)/$(THISAPP)
+TARGET     = $(DIR_INFO)/$(THISAPP)
+PROG       = portredir
+PAK_VER    = 1
+
+###############################################################################
+# Top-level Rules
+###############################################################################
+
+install : $(TARGET)
+
+check :
+
+download :
+
+md5 :
+
+dist: 
+	@$(PAK)
+
+###############################################################################
+# Installation Details
+###############################################################################
+
+$(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects))
+	@$(PREBUILD)
+	@rm -rf $(DIR_APP) && cd $(DIR_SRC)
+
+	#install cgi 
+	install -v -m 755 $(DIR_CONF)/portredir/portredir.cgi /srv/web/ipfire/cgi-bin/
+
+	#create configuration dir 
+	-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/backup/addons/includes/portredir
+
+	# Install menu file
+	install -v -m 644 $(DIR_CONF)/portredir/EX-portredir.menu /var/ipfire/menu.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/addon-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
 }
 
 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 
+#		port redirection rules
+#
+########################################################################
+
+. /etc/sysconfig/rc
+. ${rc_functions}
+
+IPT="/sbin/iptables";
+parent_chain="PREROUTING";
+chain="PORT_REDIRECT";
+
+confdir="/var/ipfire/portredir";
+settingsfile="${confdir}/settings";
+redirectsfile="${confdir}/redirects";
+SYSLOG="NO";
+VERBOSE="NO";
+
+eval $(/usr/local/bin/readhash /var/ipfire/ethernet/settings);
+eval $(/usr/local/bin/readhash ${settingsfile});
+
+logtext() {
+	if [ "${SYSLOG}" = "YES" ]; then logger -t "portredir" ${1}; fi;
+	if [ "${VERBOSE}" = "YES" ]; then echo ${1}; fi;}
+
+create_chain() {
+
+	local line=$(${IPT} -t nat -L ${parent_chain} --line-numbers |grep "SQUID" |awk '{printf($1)}');
+
+	if [[ "${REDIR_ENABLE_ADDON}" == "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 position...";
+			${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() {
+	
+	local array=();
+	local redirects=();
+	local i;
+	index=();
+	iface=();
+	protocol=();
+	port=();
+	targetip=();
+	enabled=();
+
+	IFS=$'\n' read -d '' -ra redirects < ${redirectsfile};
+
+	for i in "${!redirects[@]}"
+	do
+		IFS=$',' read -ra array <<< ${redirects[i]};
+		index[i]=${array[0]};
+		iface[i]=${array[1]};
+		protocol[i]=${array[2]};
+		port[i]=${array[3]};
+		targetip[i]=${array[4]};
+		enabled[i]=${array[5]};
+	done
+
+	for i in "${!index[@]}"
+	do
+		if [[ ! -z "${GREEN_DEV}" &&  "${iface[i]}" = "green" && "${enabled[i]}" = "enabled" ]]; then
+
+			logtext "add redirect in ${chain} on ${GREEN_DEV} ip ${targetip[i]} protocol ${protocol[i]} port ${port[i]} ";
+			${IPT} -t nat -A ${chain} -i ${GREEN_DEV} -d ${targetip[i]} -p ${protocol[i]} -m ${protocol[i]} --dport ${port[i]} -j RETURN;
+			${IPT} -t nat -A ${chain} -i ${GREEN_DEV} -p ${protocol[i]} -m ${protocol[i]} --dport ${port[i]} -j REDIRECT;
+		fi
+		if [[ ! -z "${BLUE_DEV}" &&  "${iface[i]}" = "blue" && "${enabled[i]}" = "enabled" ]]; then
+			logtext "add redirect in ${chain} on ${BLUE_DEV} ip ${targetip[i]} protocol ${protocol[i]} port ${port[i]} ";
+			${IPT} -t nat -A ${chain} -i ${BLUE_DEV} -d ${targetip[i]} -p ${protocol[i]} -m ${protocol[i]} --dport ${port[i]} -j RETURN;
+			${IPT} -t nat -A ${chain} -i ${BLUE_DEV} -p ${protocol[i]} -m ${protocol[i]} --dport ${port[i]} -j REDIRECT;
+		fi
+		if [[ ! -z "${ORANGE_DEV}" &&  "${iface[i]}" = "orange" && "${enabled[i]}" = "enabled" ]]; then
+			logtext "add redirect in ${chain} on ${ORANGE_DEV} ip ${targetip[i]} protocol ${protocol[i]} port ${port[i]} ";
+			${IPT} -t nat -A ${chain} -i ${ORANGE_DEV} -d ${targetip[i]} -p ${protocol[i]} -m ${protocol[i]} --dport ${port[i]} -j RETURN;
+			${IPT} -t nat -A ${chain} -i ${ORANGE_DEV} -p ${protocol[i]} -m ${protocol[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;
+	
+	# Force DNS REDIRECTs on GREEN (udp, tcp, 53)
+	if [[ "${REDIR_DNS_GREEN}" == "on" &&  "${REDIR_CUSTOM_GREEN}" = "off" ]]; 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}" == "on" &&  "${REDIR_CUSTOM_BLUE}" = "off" ]]; then
+		${IPT} -t nat -A ${chain} -i ${BLUE_DEV} -d ${BLUE_ADDRESS} -p udp -m udp --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 tcp --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}" == "on" &&  "${REDIR_CUSTOM_ORANGE}" = "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}" == "on" &&  "${REDIR_CUSTOM_GREEN}" = "off" ]]; 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 REDIRECT
+	fi
+
+	# Force NTP REDIRECTs on BLUE (udp, 123)
+	if [[ "${REDIR_NTP_BLUE}" == "on" &&  "${REDIR_CUSTOM_BLUE}" = "off" ]]; then
+		${IPT} -t nat -A ${chain} -i ${BLUE_DEV} -d ${BLUE_ADDRESS} -p udp -m udp --dport ntp -j RETURN
+		${IPT} -t nat -A ${chain} -i ${BLUE_DEV} -p udp -m udp --dport ntp -j REDIRECT
+	fi
+
+	# Force NTP REDIRECTs on ORANGE (udp, 123)
+	if [[ "${REDIR_NTP_ORANGE}" == "on" &&  "${REDIR_CUSTOM_ORANGE}" = "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)	
+		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 = 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 portredirctrl \
 	getconntracktable wirelessclient torctrl ddnsctrl unboundctrl \
 	captivectrl
 
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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#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 (start|stop|restart|enable|disable)\n\n");
+                exit(1);
+        }
+
+        if (strcmp(argv[1], "start") == 0) {
+                safe_system("/etc/rc.d/init.d/portredir start");
+        } else if (strcmp(argv[1], "stop") == 0) {
+                safe_system("/etc/rc.d/init.d/portredir stop");
+        } else if (strcmp(argv[1], "restart") == 0) {
+                safe_system("/etc/rc.d/init.d/portredir restart");
+	} else if (strcmp(argv[1], "enable") == 0) {
+		safe_system("touch /var/ipfire/portredir/enable");
+		safe_system("ln -snf /etc/rc.d/init.d/portredir /etc/rc.d/rc3.d/S23portredir >/dev/null 2>&1");
+		safe_system("ln -snf /etc/rc.d/init.d/portredir /etc/rc.d/rc0.d/K77portredir >/dev/null 2>&1");
+		safe_system("ln -snf /etc/rc.d/init.d/portredir /etc/rc.d/rc6.d/K77portredir >/dev/null 2>&1");
+	} else if (strcmp(argv[1], "disable") == 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 (start|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 <info(a)ipfire.org>.                        #
+#                                                                          #
+############################################################################
+#
+. /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 <info(a)ipfire.org>.                        #
+#                                                                          #
+############################################################################
+#
+. /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 <info(a)ipfire.org>.                        #
+#                                                                          #
+############################################################################
+#
+. /opt/pakfire/lib/functions.sh
+./uninstall.sh
+./install.sh
-- 
2.18.0


^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2021-08-06 15:57 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <E41194E1-4002-4960-BF73-F57D6BCCD152@gmail.com>
2021-07-05 12:07 ` [PATCH] New addon: Portredirect 1.0 Stefan Schantl
     [not found] <CD95E831-4AE9-40B7-BB91-27B3F3164270@gmail.com>
2021-08-05 20:33 ` Michael Tremer
2021-08-06 15:57   ` Stefan Schantl
     [not found] <6EBF1B5C-79B2-4258-B117-C2A4EB16CCFD@gmail.com>
2021-07-05 12:08 ` Stefan Schantl
     [not found] <ADA23788-C972-417C-8F55-DD9D3B335BE9@gmail.com>
2021-07-01 15:24 ` Michael Tremer
     [not found] <A699ABA7-74D3-4551-A981-E2E3A0935F8E@gmail.com>
2021-07-01  8:08 ` Michael Tremer
     [not found] <305D680D-4D10-4D99-9F1D-3589BDF08FA9@gmail.com>
2021-06-28 17:56 ` Michael Tremer
2021-06-27 13:48 Matthias Fischer
2021-06-28 16:04 ` Michael Tremer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox