From: Stefan Schantl Date: Sun, 14 Jul 2013 09:55:29 +0000 (+0200) Subject: dnsmasq: Add feature to forward domains to certain DNS servers. X-Git-Tag: v2.13-core71~11^2 X-Git-Url: http://git.ipfire.org/?p=ipfire-2.x.git;a=commitdiff_plain;h=e4ba53ed590428632025982d0dbd7af9b4e71084;ds=sidebyside dnsmasq: Add feature to forward domains to certain DNS servers. Fixes #10369. --- diff --git a/config/menu/30-network.menu b/config/menu/30-network.menu index bb9205af29..c50508f818 100644 --- a/config/menu/30-network.menu +++ b/config/menu/30-network.menu @@ -35,24 +35,30 @@ 'title' => "$Lang::tr{'edit hosts'}", 'enabled' => 1, }; - $subnetwork->{'51.routes'} = { + $subnetwork->{'51.dnsmenu'} = { + 'caption' => $Lang::tr{'dns menu'}, + 'uri' => '/cgi-bin/dns.cgi', + 'title' => "$Lang::tr{'dns menu'}", + 'enabled' => `grep "RED_TYPE=DHCP" /var/ipfire/ethernet/settings`, + }; + $subnetwork->{'52.dnsforward'} = { + 'caption' => $Lang::tr{'dnsforward'}, + 'uri' => '/cgi-bin/dnsforward.cgi', + 'title' => "$Lang::tr{'dnsforward'}", + 'enabled' => 1 + }; + $subnetwork->{'60.routes'} = { 'caption' => $Lang::tr{'static routes'}, 'uri' => '/cgi-bin/routing.cgi', 'title' => "$Lang::tr{'static routes'}", 'enabled' => 1, }; - $subnetwork->{'60.aliases'} = { + $subnetwork->{'70.aliases'} = { 'caption' => $Lang::tr{'aliases'}, 'uri' => '/cgi-bin/aliases.cgi', 'title' => "$Lang::tr{'aliases'}", 'enabled' => `grep "RED_TYPE=STATIC" /var/ipfire/ethernet/settings`, }; - $subnetwork->{'70.dnsmenu'} = { - 'caption' => $Lang::tr{'dns menu'}, - 'uri' => '/cgi-bin/dns.cgi', - 'title' => "$Lang::tr{'dns menu'}", - 'enabled' => `grep "RED_TYPE=DHCP" /var/ipfire/ethernet/settings`, - }; $subnetwork->{'80.macadressmenu'} = { 'caption' => $Lang::tr{'mac address menu'}, 'uri' => '/cgi-bin/mac.cgi', diff --git a/html/cgi-bin/dnsforward.cgi b/html/cgi-bin/dnsforward.cgi new file mode 100644 index 0000000000..15d430cf10 --- /dev/null +++ b/html/cgi-bin/dnsforward.cgi @@ -0,0 +1,359 @@ +#!/usr/bin/perl +############################################################################### +# # +# IPFire.org - A linux based firewall # +# Copyright (C) 2013 IPFire Development 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"; + +#workaround to suppress a warning when a variable is used only once +my @dummy = ( ${Header::colouryellow} ); +undef (@dummy); + +my %cgiparams=(); +my %checked=(); +my %selected=(); +my $errormessage = ''; +my $filename = "${General::swroot}/dnsforward/config"; +my $changed = 'no'; + +my %color = (); +my %mainsettings = (); +&General::readhash("${General::swroot}/main/settings", \%mainsettings); +&General::readhash("/srv/web/ipfire/html/themes/".$mainsettings{'THEME'}."/include/colors.txt", \%color); + +&Header::showhttpheaders(); + +$cgiparams{'ENABLED'} = 'off'; +$cgiparams{'ACTION'} = ''; +$cgiparams{'ZONE'} = ''; +$cgiparams{'FORWARD_SERVER'} = ''; +$cgiparams{'REMARK'} =''; +&Header::getcgihash(\%cgiparams); +open(FILE, $filename) or die 'Unable to open config file.'; +my @current = ; +close(FILE); + +### +# Add / Edit entries. +# +if ($cgiparams{'ACTION'} eq $Lang::tr{'add'}) +{ + # Check if the entered domainname is valid. + unless (&General::validdomainname($cgiparams{'ZONE'})) { + $errormessage = $Lang::tr{'invalid domain name'}; + } + + # Check if the settings for the forward server are valid. + unless(&General::validip($cgiparams{'FORWARD_SERVER'})) { + $errormessage = $Lang::tr{'invalid ip'}; + } + + # Go further if there was no error. + if ( ! $errormessage) + { + # Check if a remark has been entered. + $cgiparams{'REMARK'} = &Header::cleanhtml($cgiparams{'REMARK'}); + + # Check if we want to edit an existing or add a new entry. + if($cgiparams{'EDITING'} eq 'no') { + open(FILE,">>$filename") or die 'Unable to open config file.'; + flock FILE, 2; + print FILE "$cgiparams{'ENABLED'},$cgiparams{'ZONE'},$cgiparams{'FORWARD_SERVER'},$cgiparams{'REMARK'}\n"; + } else { + open(FILE, ">$filename") or die 'Unable to open config file.'; + flock FILE, 2; + my $id = 0; + foreach my $line (@current) + { + $id++; + if ($cgiparams{'EDITING'} eq $id) { + print FILE "$cgiparams{'ENABLED'},$cgiparams{'ZONE'},$cgiparams{'FORWARD_SERVER'},$cgiparams{'REMARK'}\n"; + } else { print FILE "$line"; } + } + } + close(FILE); + undef %cgiparams; + $changed = 'yes'; + } else { + # stay on edit mode if an error occur + if ($cgiparams{'EDITING'} ne 'no') + { + $cgiparams{'ACTION'} = $Lang::tr{'edit'}; + $cgiparams{'ID'} = $cgiparams{'EDITING'}; + } + } + # Restart dnsmasq. + system('/usr/local/bin/dnsmasqctrl restart >/dev/null'); +} + +### +# Remove existing entries. +# +if ($cgiparams{'ACTION'} eq $Lang::tr{'remove'}) +{ + my $id = 0; + open(FILE, ">$filename") or die 'Unable to open config file.'; + flock FILE, 2; + foreach my $line (@current) + { + $id++; + unless ($cgiparams{'ID'} eq $id) { print FILE "$line"; } + } + close(FILE); + # Restart dnsmasq. + system('/usr/local/bin/dnsmasqctrl restart >/dev/null'); +} + +### +# Toggle Enable/Disable for entries. +# +if ($cgiparams{'ACTION'} eq $Lang::tr{'toggle enable disable'}) +{ + open(FILE, ">$filename") or die 'Unable to open config file.'; + flock FILE, 2; + my $id = 0; + foreach my $line (@current) + { + $id++; + unless ($cgiparams{'ID'} eq $id) { print FILE "$line"; } + else + { + chomp($line); + my @temp = split(/\,/,$line); + print FILE "$cgiparams{'ENABLE'},$temp[1],$temp[2],$temp[3]\n"; + } + } + close(FILE); + # Restart dnsmasq. + system('/usr/local/bin/dnsmasqctrl restart >/dev/null'); +} + +### +# Read items for edit mode. +# +if ($cgiparams{'ACTION'} eq $Lang::tr{'edit'}) +{ + my $id = 0; + foreach my $line (@current) + { + $id++; + if ($cgiparams{'ID'} eq $id) + { + chomp($line); + my @temp = split(/\,/,$line); + $cgiparams{'ENABLED'} = $temp[0]; + $cgiparams{'ZONE'} = $temp[1]; + $cgiparams{'FORWARD_SERVER'} = $temp[2]; + $cgiparams{'REMARK'} = $temp[3]; + } + } +} + +$checked{'ENABLED'}{'off'} = ''; +$checked{'ENABLED'}{'on'} = ''; +$checked{'ENABLED'}{$cgiparams{'ENABLED'}} = "checked='checked'"; + +&Header::openpage($Lang::tr{'dnsforward configuration'}, 1, ''); + +&Header::openbigbox('100%', 'left', '', $errormessage); + +### +# Error messages layout. +# +if ($errormessage) { + &Header::openbox('100%', 'left', $Lang::tr{'error messages'}); + print "$errormessage\n"; + print " \n"; + &Header::closebox(); +} + +print "
\n"; + +my $buttontext = $Lang::tr{'add'}; +if ($cgiparams{'ACTION'} eq $Lang::tr{'edit'}) { + &Header::openbox('100%', 'left', $Lang::tr{'dnsforward edit an entry'}); + $buttontext = $Lang::tr{'update'}; +} else { + &Header::openbox('100%', 'left', $Lang::tr{'dnsforward add a new entry'}); +} + +### +# Content of the main page. +# +print < + + $Lang::tr{'dnsforward zone'}: + + $Lang::tr{'enabled'} + + + + $Lang::tr{'dnsforward forward_server'}: + + + + + + + + + +
$Lang::tr{'remark'}: *
+ +
+ + + + + + +
* $Lang::tr{'this field may be blank'} + + +
+END +; +if ($cgiparams{'ACTION'} eq $Lang::tr{'edit'}) { + print "\n"; +} else { + print "\n"; +} + +&Header::closebox(); +print "\n"; + +### +# Existing rules. +# +&Header::openbox('100%', 'left', $Lang::tr{'dnsforward entries'}); +print < + + $Lang::tr{'dnsforward zone'} + $Lang::tr{'dnsforward forward_server'} + $Lang::tr{'remark'} + $Lang::tr{'action'} + +END +; + +# If something has happened re-read config +if($cgiparams{'ACTION'} ne '' or $changed ne 'no') +{ + open(FILE, $filename) or die 'Unable to open config file.'; + @current = ; + close(FILE); +} + +### +# Re-read entries and highlight selected item for editing. +# +my $id = 0; +foreach my $line (@current) +{ + $id++; + chomp($line); + my @temp = split(/\,/,$line); + my $toggle = ''; + my $gif = ''; + my $gdesc = ''; + my $toggle = ''; + + if($cgiparams{'ACTION'} eq $Lang::tr{'edit'} && $cgiparams{'ID'} eq $id) { + print "\n"; } + elsif ($id % 2) { + print "\n"; } + else { + print "\n"; } + + if ($temp[0] eq 'on') { $gif='on.gif'; $toggle='off'; $gdesc=$Lang::tr{'click to disable'};} + else { $gif='off.gif'; $toggle='on'; $gdesc=$Lang::tr{'click to enable'}; } + +### +# Display edit page. +# +print <$temp[1] + $temp[2] + $temp[3] + +
+ + + + +
+ + +
+ + + +
+ + +
+ + + +
+ + +END + ; +} +print "\n"; + +### +# Print the legend at the bottom if there are any configured entries. +# +# Check if the file size is zero - no existing entries. +if ( ! -z "$filename") { +print < + +   $Lang::tr{'legend'}: +   $Lang::tr{ + $Lang::tr{'click to disable'} +     $Lang::tr{ + $Lang::tr{'click to enable'} +     $Lang::tr{ + $Lang::tr{'edit'} +     $Lang::tr{ + $Lang::tr{'remove'} + + +END +; +} + +&Header::closebox(); + +&Header::closebigbox(); + +&Header::closepage(); diff --git a/langs/de/cgi-bin/de.pl b/langs/de/cgi-bin/de.pl index 84b102f36b..6de84e455b 100644 --- a/langs/de/cgi-bin/de.pl +++ b/langs/de/cgi-bin/de.pl @@ -715,6 +715,13 @@ 'dns saved txt' => 'Die beiden eingegebenen DNS-Server-Adressen wurde erfolgreich gespeichert.
Um die Änderung wirksam zu machen, müssen Sie neustarten oder wiederverbinden!', 'dns server' => 'DNS Server', 'dns title' => 'Domain Name System', +'dnsforward' => 'DNS-Weiterleitung', +'dnsforward add a new entry' => 'Neuen Eintrag hinzufügen:', +'dnsforward configuration' => 'Einstellungen für DNS Weiterleitung', +'dnsforward edit an entry' => 'Existierenden Eintrag bearbeiten:', +'dnsforward entries' => 'Aktuelle Einträge:', +'dnsforward forward_server' => 'DNS-Server', +'dnsforward zone' => 'Zone', 'do not log this port list' => 'Verwerfe diese Port-Liste kurz bevor sie protokolliert werden (reduziert Protokollgröße)', 'dod' => 'Dial-on-Demand-Modus', 'dod for dns' => 'Dial-on-Demand für DNS:', diff --git a/langs/en/cgi-bin/en.pl b/langs/en/cgi-bin/en.pl index 8ff2608a0a..7b92b7e9b0 100644 --- a/langs/en/cgi-bin/en.pl +++ b/langs/en/cgi-bin/en.pl @@ -737,6 +737,13 @@ 'dns saved txt' => 'The two entered DNS server addresses have been saved successfully.
You have to reboot or reconnect that the changes have effect!', 'dns server' => 'DNS Server', 'dns title' => 'Domain Name System', +'dnsforward' => 'DNS forwarding', +'dnsforward add a new entry' => 'Add a new entry:', +'dnsforward configuration' => 'DNS forward configuration', +'dnsforward edit an entry' => 'Edit an existing entry:', +'dnsforward entries' => 'Current entries:', +'dnsforward forward_server' => 'Nameserver', +'dnsforward zone' => 'Zone', 'do not log this port list' => 'Drop this port list just before they are logged (reduces log size)', 'dod' => 'Dial on Demand', 'dod for dns' => 'Dial on Demand for DNS:', diff --git a/src/initscripts/init.d/dnsmasq b/src/initscripts/init.d/dnsmasq index 1b2c0c206d..a02097e410 100644 --- a/src/initscripts/init.d/dnsmasq +++ b/src/initscripts/init.d/dnsmasq @@ -22,6 +22,26 @@ fi SHOW_SRV=1 +function dns_forward_args() { + local file="${1}" + + # Do nothing if file is empty. + [ -s "${file}" ] || return + + local cmdline + + local enabled zone server remark + while IFS="," read -r enabled zone server remark; do + # Line must be enabled. + [ "${enabled}" = "on" ] || continue + + cmdline="${cmdline} --server=/${zone}/${server}" + done < ${file} + + echo "${cmdline}" +} + + case "${1}" in start) # kill already running copy of dnsmasq... @@ -47,8 +67,12 @@ case "${1}" in fi fi [ -e "/var/ipfire/red/active" ] && ARGS="$ARGS -r /var/ipfire/red/resolv.conf" - + ARGS="$ARGS --domain=`cat /var/ipfire/main/settings |grep DOMAIN |cut -d = -f 2`" + + # Add custom forward dns zones. + ARGS="${ARGS} $(dns_forward_args /var/ipfire/dnsforward/config)" + ARGS="$ARGS $CUSTOM_ARGS" loadproc /usr/sbin/dnsmasq -l /var/state/dhcp/dhcpd.leases $ARGS diff --git a/src/misc-progs/Makefile b/src/misc-progs/Makefile index 0a4fda63e0..ac1d01f644 100644 --- a/src/misc-progs/Makefile +++ b/src/misc-progs/Makefile @@ -33,7 +33,7 @@ SUID_PROGS = setdmzholes setportfw setxtaccess \ redctrl syslogdctrl extrahdctrl sambactrl upnpctrl tripwirectrl \ smartctrl clamavctrl addonctrl pakfire mpfirectrl wlanapctrl \ setaliases urlfilterctrl updxlratorctrl fireinfoctrl rebuildroutes \ - getconntracktable wirelessclient + getconntracktable wirelessclient dnsmasqctrl SUID_UPDX = updxsetperms install : all @@ -161,3 +161,6 @@ getconntracktable: getconntracktable.c setuid.o ../install+setup/libsmooth/varva wirelessclient: wirelessclient.c setuid.o ../install+setup/libsmooth/varval.o $(COMPILE) -I../install+setup/libsmooth/ wirelessclient.c setuid.o ../install+setup/libsmooth/varval.o -o $@ + +dnsmasqctrl: dnsmasqctrl.c setuid.o ../install+setup/libsmooth/varval.o + $(COMPILE) -I../install+setup/libsmooth/ dnsmasqcrtl.c setuid.o ../install+setup/libsmooth/varval.o -o $@ diff --git a/src/misc-progs/dnsmasqctrl.c b/src/misc-progs/dnsmasqctrl.c new file mode 100644 index 0000000000..8ac3360e06 --- /dev/null +++ b/src/misc-progs/dnsmasqctrl.c @@ -0,0 +1,34 @@ +/* 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); + + if (argc < 2) { + fprintf(stderr, "\nNo argument given.\n\ndnsmasqctrl (restart)\n\n"); + exit(1); + } + + if (strcmp(argv[1], "restart") == 0) { + safe_system("/etc/rc.d/init.d/dnsmasq restart"); + } else { + fprintf(stderr, "\nBad argument given.\n\ndnsmasqctrl (restart)\n\n"); + exit(1); + } + + return 0; +}