From patchwork Sun Jun 27 13:48:19 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Matthias Fischer X-Patchwork-Id: 4468 Return-Path: Received: from mail01.ipfire.org (mail01.haj.ipfire.org [172.28.1.202]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) server-digest SHA384 client-signature ECDSA (P-384) client-digest SHA384) (Client CN "mail01.haj.ipfire.org", Issuer "R3" (verified OK)) by web04.haj.ipfire.org (Postfix) with ESMTPS id 4GCXBh6rkhz3x1K for ; Sun, 27 Jun 2021 13:48:28 +0000 (UTC) Received: from mail02.haj.ipfire.org (mail02.haj.ipfire.org [172.28.1.201]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) server-digest SHA384 client-signature ECDSA (P-384) client-digest SHA384) (Client CN "mail02.haj.ipfire.org", Issuer "R3" (verified OK)) by mail01.ipfire.org (Postfix) with ESMTPS id 4GCXBf2TF4zQ0; Sun, 27 Jun 2021 13:48:26 +0000 (UTC) Received: from mail02.haj.ipfire.org (localhost [127.0.0.1]) by mail02.haj.ipfire.org (Postfix) with ESMTP id 4GCXBf0qYlz2yTP; Sun, 27 Jun 2021 13:48:26 +0000 (UTC) Received: from mail01.ipfire.org (mail01.haj.ipfire.org [172.28.1.202]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) server-digest SHA384 client-signature ECDSA (P-384) client-digest SHA384) (Client CN "mail01.haj.ipfire.org", Issuer "R3" (verified OK)) by mail02.haj.ipfire.org (Postfix) with ESMTPS id 4GCXBc49rkz2xPL for ; Sun, 27 Jun 2021 13:48:24 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) server-digest SHA384) (No client certificate requested) by mail01.ipfire.org (Postfix) with ESMTPSA id 4GCXBb32f2zQ0; Sun, 27 Jun 2021 13:48:23 +0000 (UTC) DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=ipfire.org; s=202003ed25519; t=1624801703; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=xbnsSIbdSm4SxXVVznlnb0c16prbeGkkHunSe1WOjDk=; b=tWe4uPFjdz7FZtNMXNR7VAlOAaI04gdKNCxcXAMEebqS77iIYf3+ZSWNXxejtpITTLnjw9 +qrd77NNmVbrTsDA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ipfire.org; s=202003rsa; t=1624801703; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=xbnsSIbdSm4SxXVVznlnb0c16prbeGkkHunSe1WOjDk=; b=hM6dM4I1gzW9vHb8tu1tZ9jyfPxO8gIJ7uxwm41VdIyI5N+FV7/VMLgZ4dANovFEU7pUwO 5S5vJnluNyML8MO8HhqNfqdT4rtf/ldnQcx2m2lLNT1ej2WA2kHEOpU60YG9rMzeIQJuZ8 tXqOKZDxeOl7JodZTaNP2HorlJgrIVcP3eY7k1E0qDG1a9L9eaH7634dgrWWARNPZccuOl xKKLqYQQKEXaQ53tGzl82ZcyCvUyjAray67D4kA37pIblkcxAK2QVF3JaXRjnyJvzQknFl dOLemmFyfZlJM02kNYc6U8MlChcRrlS8M9upr9ZeHNIrDuv9ENPl8U1gODXORQ== From: Matthias Fischer To: development@lists.ipfire.org Subject: [PATCH] New addon: Portredirect 1.0 Date: Sun, 27 Jun 2021 15:48:19 +0200 Message-Id: <20210627134819.2088-1-matthias.fischer@ipfire.org> MIME-Version: 1.0 X-BeenThere: development@lists.ipfire.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: IPFire development talk List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: development-bounces@lists.ipfire.org Sender: "Development" From: Marcel Lorenz Please note: This is a new addon written by Marcel Lorenz . 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 --- 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 # +# # +# 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 = "${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 "$errormessage "; + &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 "
"; + +print < + $Lang::tr{'portredir common settings'} + $Lang::tr{'portredir enable addon'}: + + + +   +END + + # create html table with header line 1 + print ""; + 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{'portredir 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 remove single members of it. +sub showRedirectsBox() { + &Header::openbox('100%', 'center', "$Lang::tr{'portredir custom redirections'}"); + + print < + + $Lang::tr{'interface'} + $Lang::tr{'protocol'} + $Lang::tr{'port'} + $Lang::tr{'ip address'} + $Lang::tr{'remark'} + + +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 < + $Lang::tr{$interface} + $protocol + $port +  $address +  $remark + +
+ + + +
+ + +
+ + + +
+ + +
+ + + +
+ + +END + } + } else { + # Print notice that currently no ports are redirected. + print "\n"; + print "$Lang::tr{'portredir no entries'}\n"; + print "\n"; + } + + print "\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 should be edited. + if ($settings{'ID'} ne '') { + $buttontext = $Lang::tr{'update'}; + print "\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 "\n"; + print "\n"; + } + + print < + + + + + + + + + + + + + + + + + + + + + + +
$Lang::tr{'update'}
$Lang::tr{'dnsforward 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/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 # +# # +# 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 = 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 +#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 (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 . # +# # +############################################################################ +# +. /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