Testing DNS Redirect code snippet

Hi Matthias,

Continuing the discussion from Forcing all DNS traffic from the LAN to the firewall:

I tried to test some of the code from your developer list post. I really am not sure how to apply any of the patches in the post so I grabbed a chunk of code, removed the + and dropped it into my firewall.local. Not the most elegant solution!

#!/bin/sh
set -x

# Used for private firewall rules
#
# Use this at your OWN RISK.  It is not fully supported!
#	https://community.ipfire.org/t/forcing-all-dns-traffic-from-the-lan-to-the-firewall/3512
#
# See how we were called.

case "$1" in
  start)
        ## add your 'start' rules here
		DNS_FORCE_ON_GREEN="on"
		DNS_FORCE_ON_BLUE="on"
		NTP_FORCE_ON_GREEN="on"
		NTP_FORCE_ON_BLUE="on"
        ;;
  stop)
        ## add your 'stop' rules here
		DNS_FORCE_ON_GREEN=""
		DNS_FORCE_ON_BLUE=""
		NTP_FORCE_ON_GREEN=""
		NTP_FORCE_ON_BLUE=""
        ;;
  reload)
        $0 stop
        $0 start
        ## add your 'reload' rules here
        ;;
   flush)
        iptables -t nat -F CUSTOMPREROUTING
        ;;
  *)
        echo "Usage: $0 {start|stop|reload|flush}"
        ;;
esac

# Force DNS REDIRECT on GREEN (udp, tcp, 53)
if [ "$DNS_FORCE_ON_GREEN" == "on" ]; then
	if ! iptables -t nat -C CUSTOMPREROUTING -i green0 -p udp -m udp --dport 53 -j REDIRECT >/dev/null 2>&1; then
		iptables -t nat -A CUSTOMPREROUTING -i green0 -p udp -m udp --dport 53 -j REDIRECT
	fi

	if ! iptables -t nat -C CUSTOMPREROUTING -i green0 -p tcp -m tcp --dport 53 -j REDIRECT >/dev/null 2>&1; then
		iptables -t nat -A CUSTOMPREROUTING -i green0 -p tcp -m tcp --dport 53 -j REDIRECT
	fi

else

	if iptables -t nat -C CUSTOMPREROUTING -i green0 -p udp -m udp --dport 53 -j REDIRECT >/dev/null 2>&1; then
		iptables -t nat -D CUSTOMPREROUTING -i green0 -p udp -m udp --dport 53 -j REDIRECT >/dev/null 2>&1
	fi

	if iptables -t nat -C CUSTOMPREROUTING -i green0 -p tcp -m tcp --dport 53 -j REDIRECT >/dev/null 2>&1; then
		iptables -t nat -D CUSTOMPREROUTING -i green0 -p tcp -m tcp --dport 53 -j REDIRECT >/dev/null 2>&1
	fi
fi

# Force DNS REDIRECT on BLUE (udp, tcp, 53)
if [ "$DNS_FORCE_ON_BLUE" == "on" ]; then
	if ! iptables -t nat -C CUSTOMPREROUTING -i blue0 -p udp -m udp --dport 53 -j REDIRECT >/dev/null 2>&1; then
		iptables -t nat -A CUSTOMPREROUTING -i blue0 -p udp -m udp --dport 53 -j REDIRECT
	fi

	if ! iptables -t nat -C CUSTOMPREROUTING -i blue0 -p tcp -m tcp --dport 53 -j REDIRECT >/dev/null 2>&1; then
		iptables -t nat -A CUSTOMPREROUTING -i blue0 -p tcp -m tcp --dport 53 -j REDIRECT
	fi

else

	if iptables -t nat -C CUSTOMPREROUTING -i blue0 -p udp -m udp --dport 53 -j REDIRECT >/dev/null 2>&1; then
		iptables -t nat -D CUSTOMPREROUTING -i blue0 -p udp -m udp --dport 53 -j REDIRECT >/dev/null 2>&1
	fi

	if iptables -t nat -C CUSTOMPREROUTING -i blue0 -p tcp -m tcp --dport 53 -j REDIRECT >/dev/null 2>&1; then
		iptables -t nat -D CUSTOMPREROUTING -i blue0 -p tcp -m tcp --dport 53 -j REDIRECT >/dev/null 2>&1
	fi

fi

# Force NTP REDIRECT on GREEN (udp, 123)
if [ "$NTP_FORCE_ON_GREEN" == "on" ]; then
	if ! iptables -t nat -C CUSTOMPREROUTING -i green0 -p udp -m udp --dport 123 -j REDIRECT >/dev/null 2>&1; then
		iptables -t nat -A CUSTOMPREROUTING -i green0 -p udp -m udp --dport 123 -j REDIRECT
	fi

else

	if iptables -t nat -C CUSTOMPREROUTING -i green0 -p udp -m udp --dport 123 -j REDIRECT >/dev/null 2>&1; then
		iptables -t nat -D CUSTOMPREROUTING -i green0 -p udp -m udp --dport 123 -j REDIRECT >/dev/null 2>&1
	fi

fi

# Force DNS REDIRECT on BLUE (udp, 123)
if [ "$NTP_FORCE_ON_BLUE" == "on" ]; then
	if ! iptables -t nat -C CUSTOMPREROUTING -i blue0 -p udp -m udp --dport 123 -j REDIRECT >/dev/null 2>&1; then
		iptables -t nat -A CUSTOMPREROUTING -i blue0 -p udp -m udp --dport 123 -j REDIRECT
	fi

else

	if iptables -t nat -C CUSTOMPREROUTING -i blue0 -p udp -m udp --dport 123 -j REDIRECT >/dev/null 2>&1; then
		iptables -t nat -D CUSTOMPREROUTING -i blue0 -p udp -m udp --dport 123 -j REDIRECT >/dev/null 2>&1
	fi

fi

Anyway, this snippet of code works A-OK!!

Hi Jon,

thanks for testing!

At first I was I bit puzzled. I would never have come up with the idea that someone would going to use this code in firewall.local. It was meant for /etc/init.d/firewall.

But while checking my patches once more, I saw that they are not easy to apply. The given paths are from my local upload-directory and were created with ‘WinMerge’. This can never work with GIT or a development environment, sorry.

But nevertheless I’m happy that it seems to work.

I’ll rebuild these patches, so they can be applied through GIT, e.g…

Best,
Matthias

1 Like

Hi Jon,

here you’ll find the updated patches:

optionsfw.cgi => https://git.ipfire.org/?p=people/mfischer/ipfire-2.x.git;a=commit;h=c44cde5efb1dd4b6dfa957501814405a5a7fce20

/etc/init.d/firewall => https://git.ipfire.org/?p=people/mfischer/ipfire-2.x.git;a=commit;h=305e0488303a44b41006d233cc5ac173d02883c4

Language files => https://git.ipfire.org/?p=people/mfischer/ipfire-2.x.git;a=commit;h=e7df4b37ccf0b4e2b80da6277fd0c8e1ef9f607a

I hope this will work better. :wink:

Best,
Matthias

I saw the patches! But…

This is the only way I know how to apply the git patches. Is there an easy way for me to apply the patches without adding the entire development build to my IPFire box?

 


 

Ah, I see.

Then I think it would be the best to make it the “other way”. :wink:

You’re running Core 152? Never mind - should work.

  1. Download the attached zip-archive - it contains four files.
    optionsfw.cgi, firewall, de.pl and en.pl.

force_dns.zip (90.5 KB)

Make backup copies from the original files:

cp /srv/web/ipfire/cgi-bin/optionsfw.cgi /srv/web/ipfire/cgi-bin/optionsfw.cgi.org
cp /etc/rc.d/init.d/firewall /etc/rc.d/init.d/firewall.org
cp /var/ipfire/langs/de.pl /var/ipfire/langs/de.pl.bak
cp /var/ipfire/langs/en.pl /var/ipfire/langs/en.pl.bak
  1. Copy the downloaded files to the appropriate directories, overwriting the originals and make sure each one got the correct file rights:

/srv/web/ipfire/cgi-bin/optionsfw.cgi => root / 0755

24 -rwxr-xr-x 1 root root 21270 Nov  8 20:17 optionsfw.cgi]

/etc/rc.d/init.d/firewall => root / 0754

20 -rwxr-xr-- 1 root root 18146 Nov 21 01:37 firewall

/var/ipfire/langs/de.pl and en.pl => root / 0644

124 -rw-r--r-- 1 root root 126780 Nov 21 19:12 de.pl
116 -rw-r--r-- 1 root root 116331 Nov 21 19:11 en.pl

The file sizes of the language files can differ! I got heavily tuned ones. I modified and uploaded ‘next’ files for you.

Besides, for the translations you need only six strings in each language file.

de.pl:

'dns force on blue' => 'Erzwinge lokale DNS-Server auf BLAU',
'dns force on green' => 'Erzwinge lokale DNS-Server auf GRÜN',
'fw green' => 'Firewalloptionen für das Grüne Interface',
'fw settings save and restart' => 'Speichern und Neustart',
'ntp force on blue' => 'Erzwinge lokale NTP-Server auf BLAU',
'ntp force on green' => 'Erzwinge lokale NTP-Server auf GRÜN',

en.pl:

'dns force on green' => 'Force DNS to use local DNS servers on GREEN',
'dns force on blue' => 'Force DNS to use local DNS servers on BLUE',
'fw green' => 'Firewall options for GREEN Interface',
'fw settings save and restart' => 'Save and Restart',
'ntp force on green' => 'Force NTP to use local NTP servers on GREEN',
'ntp force on blue' => 'Force NTP to use local NTP servers on BLUE',

Run

update-lang-cache

Thats it.

But be sure to remove your modifications from firewall.local before doing this…

Reload the firewall options, take your choices.

Best,
Matthias

2 Likes

Hi Jon,

one more note:

I just saw that I’ve sent the current optionsfw.cgi that I use on my machine right now.

In the attached ZIP archive you find another optionsfw.cgi.

This one contains the ‘Save and Restart’-function and button, which I can’t get to work yet. And this CGI needs the translation string for ‘Save and Restart’.

It doesn’t do any harm ( :wink: ) - the ‘Save and Restart’ button just doesn’t work.
Settings are saved, but the firewall init won’t be restarted.

The line triggers the command in line 92 - but doesn’t do anything :

system("/etc/rc.d/init.d/firewall restart >/dev/null 2>&1 ");

The goal is to restart and reload the firewall rules through this line. This would be the last step, avoiding a complete reboot of IPFire or restarting settings through console.That means, for changes to take effect, you have to restart the firewall option settings manually through a root console with:

/etc/rc.d/init.d/firewall restart

If you want to take a look, just copy this CGI to /srv/web/ipfire/cgi-bin as described in my previous mail.

Best,
Matthas

1 Like

just getting started but I think there is missing leading tabs in the firewall file:

Lines 249 to 319 are missing leading tab:

It looks like the default settings are missing for the new items:

so far so good! All seems to work as it should.

Thanks for the hint about firewall.local. I would have forgotten that one!!

Also I didn’t find the 2nd optionsfw.cgi file.

I’ll keep testing.

1 Like

Hi Jon,

Erm…here it is. optionsfw.cgi_wth_save_and_restart.zip (3.3 KB)

My fault - I forgot the upload…

That’s intentional so I could easily see what I’ve added. Its an ‘alpha’-version. Hrm! :grinning:

Yep. I know. You just take your pick - click ‘Save’ - and they’re added.

The final version will need something like:

optionsfw_file="/var/ipfire/optionsfw/settings"

# Add default line for new option.
echo "FORCE_DNS_ON_GREEN=off" >> ${optionsfw_file}
echo "FORCE_DNS_ON_BLUE=off" >> ${optionsfw_file}
echo "FORCE_NTP_ON_GREEN=off" >> ${optionsfw_file}
echo "FORCE_NTP_ON_BLUE=off" >> ${optionsfw_file}
...

in update.sh. That’s finetuning.

Best,
Matthias

1 Like

FYI - all is working as expected. The changes to optionsfw.cgi, firewall, and en.pl all look good.

I have blue enabled on my IPFire but nothing connected to blue ethernet. So I’m not able to test the blue redirects at this time.

Got blue running and testing on 1 computer. All is A-OK for an hour of testing redirect DNS and redirect NTP. I’ll keep trying to break it!

1 Like

Hi Jon,

very good - this code must be really stable, make sure you break it! :sunglasses:

But I still haven’t found a way to execute /etc/rc.d/init.d/firewall restart via GUI.

It seems that the rights available via GUI are - per design - not sufficient to rewrite the settings AND execute a root script.

Best,
Matthias

Curious - What is the code behind Apply changes? Will that help?

Hi Jon,

in detail, its this piece of code (optionsfw.cgi, line 72-95) which does the ‘Save and Restart’:

if ($settings{'ACTION'} eq $Lang::tr{'fw settings save and restart'}) {
if ($settings{'defpol'} ne '1'){
	$errormessage .= $Lang::tr{'new optionsfw later'};
	&General::writehash($filename, \%settings);             # Save good settings
	system("/usr/local/bin/firewallctrl");
}else{
	if ($settings{'POLICY'} ne ''){
		$fwdfwsettings{'POLICY'} = $settings{'POLICY'};
	}
	if ($settings{'POLICY1'} ne ''){
		$fwdfwsettings{'POLICY1'} = $settings{'POLICY1'};
	}
	my $MODE = $fwdfwsettings{'POLICY'};
	my $MODE1 = $fwdfwsettings{'POLICY1'};
	%fwdfwsettings = ();
	$fwdfwsettings{'POLICY'} = "$MODE";
	$fwdfwsettings{'POLICY1'} = "$MODE1";
	&General::writehash("${General::swroot}/firewall/settings", \%fwdfwsettings);
	&General::readhash("${General::swroot}/firewall/settings", \%fwdfwsettings);
	system("/usr/local/bin/firewallctrl");
	system("/etc/rc.d/init.d/firewall restart >/dev/null 2>&1 ");  # <=== THIS IS NOT WORKING!
}
&General::readhash($filename, \%settings);             # Load good settings

}

Its nearly the same as the code from line 48-70. I added just one line:

system("/etc/rc.d/init.d/firewall restart >/dev/null 2>&1 ");

This should call the firewall init script, which then starts adding the choosen iptables rules.

As I see it, its not possible to run such a script through the GUI because it has to be run with root privileges. Didn’t find a solution, yet.

Best,
Matthias

Wild suggestion… Instead of doing this:

system("/etc/rc.d/init.d/firewall restart >/dev/null 2>&1 ");

Maybe do this:

system("/usr/local/bin/firewallctrl");

found here:


 

 

Second suggestion…

I’ve look at the code a few time but I am having a terrible time following it all (the existing firewall code. not your updated code).

The only “cheap and dirty” solution I can suggest is to copy the code segments from either this:

-or this-

and have the user click Apply changes on the firewall.cgi page.

It may not be the best way but it is the current and it is familiar…

Concerning the wild guess…

It looks? like this system("/usr/local/bin/firewallctrl") is firewallctrl.c.

And firewallctrl.c just runs safe_system("/usr/lib/firewall/rules.pl") and resets a file flag.

And looks like rules.pl reloads the firewall rules. Hopefully helping the new code of Redirect DNS.

Hi Jon,

···

On 19.12.2020 23:28, Jon via IPFire Community wrote:

Wild suggestion… Instead of doing this:

system("/etc/rc.d/init.d/firewall restart >/dev/null 2>&1 ");

Maybe do this:

system("/usr/local/bin/firewallctrl");

found here:
ipfire-2.x/general-functions.pl at master · ipfire/ipfire-2.x · GitHub
 


 

BTDT. :wink:

I created ‘optionsfwctrl.c’ - it looks like this:

/* 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 "setuid.h"

int main(void)
{
	if (!(initsetuid()))
		exit(1);

	safe_system("/etc/rc.d/init.d/firewall restart");

	return 0;
}

Same behavior. The ‘save’ command is OK, but ‘optionsfwctrl.c’ doesn’t
run from GUI. From a root console: OK.

Second suggestion…

I’ve look at the code a few time but I am having a terrible time following it all (the existing firewall code. not your updated code).

I’m with you. It’s not easy…

The only “cheap and dirty” solution I can suggest is to copy the code segments from either this:

ipfire-2.x/location-block.cgi at master · ipfire/ipfire-2.x · GitHub

-or this-

ipfire-2.x/p2p-block.cgi at master · ipfire/ipfire-2.x · GitHub

and have the user click Apply changes on the firewall.cgi page. It may not be the best way but it is the current and it is familiar…

The way I see it, this is not sufficient.

The problem is I can’t start a program from GUI which needs root
rights. In this case I need a complete restart of the firewall init
script, including ‘iptables’.

What I’m trying to achieve:

  1. Open GUI, Pick your choices (Force DNS ON/OFF, whatever).

  2. Write this settings to the settings file.
    No problem until here.

  3. Then I must run '/etc/rc.d/init.d/firewall restart, including all
    kinds of ‘iptables’-commands.
    And this is were the trouble begins. I’m not allowed to do this from
    GUI. I must be root to do this.

Workaround could be:
The CGI writes the settings file and a signal-file while another
process looks for the existence of this file and restarts the firewall.
Could perhaps be done with a minutely (or ‘cyclic’ = every five
minutes) cron job.

Something like:
if exist FORCE_DNS_SIGNAL-file then;
restart firewall and delete FORCE_DNS_SIGNAL-file. :wink:
fi

I hadn’t much time in the last weeks, but I’m still at it…I have a few
ideas…

Best,
Matthias

Hi,

Concerning the wild guess…

It looks? like this system("/usr/local/bin/firewallctrl") is firewallctrl.c.

Exactly.

And firewallctrl.c just runs safe_system("/usr/lib/firewall/rules.pl") and resets a file flag.

Yep.

And looks like rules.pl reloads the firewall rules.

Yep. But I need a complete firewall restart, including ‘iptables’.

Hopefully helping the new code of Redirect DNS.

I had the same idea. Not working yet - see my previous mail.

Best,
Matthias

I was working my way thru the development mailing list post and I saw a post from Leo. Maybe Leo can help? We can invite him to this thread.

Or I can make this entire thread “public” instead of “private”. But I won’t do this without your OK.