#!/usr/bin/perl
use strict;
use warnings;
use POSIX;
my $logger = "/usr/bin/logger";
my $resolv = "/etc/resolv.conf";
my $rclocal = "/etc/rc.local";
my $install_dir = "/usr/local/sbin";
my $name = "dns_kludge";
my $prgname = "$install_dir/$name";
my $P1 = '#!/usr/bin/perl
use strict;
use warnings;
use subs qw (fatal_err logmsg);
my %DNS_static = (';
my $P2 = ');
my $logger = "/usr/bin/logger";
my $resolv = "/etc/resolv.conf";
my $sleeps = 0;
my $max_sleep = 10;

# ------------------------------------------------------------------------

sub logmsg {
	my ($msg) = @_;
	$msg =~ s/\s+$//;
	system "$logger $0: $msg\n";
}

# ------------------------------------------------------------------------

sub fatal_err {
	logmsg "FATAL: $_[0]";
	die $_[0];
}
# ------------------------------------------------------------------------

logmsg "commenced";
while (1) {
	my @dns;
	my @head;
	my @tail;
	my %DNS = %DNS_static;
	$sleeps++;
	$sleeps = $max_sleep / 2 if ($sleeps > $max_sleep);
	sleep $sleeps * 60;
	open RESOLV,$resolv || fatal_err "Cannot open $resolv";
	while (<RESOLV>) {
		if (/^nameserver (\S+)/) {
			my $dns = $1;
			push @dns,$_;
			delete $DNS{$dns} if ($DNS{$dns});
		} else {
			if (@dns) {
				push @tail,$_;
			} else {
				push @head,$_;
			}
		}
	}
	if ( keys %DNS ) {
		logmsg "Over-writing $resolv";
		open RESOLV,">$resolv" || fatal_err "Cannot open: $resolv";
		foreach (@head) {print RESOLV}
		foreach my $dns (sort{$DNS{$a}<=>$DNS{$b}} keys %DNS){
			print RESOLV "nameserver $dns\n";
		}
		foreach (@dns) {print RESOLV}
		foreach (@tail) {print RESOLV}
		close RESOLV;
		$sleeps = 0;
	}
}';
my $reply;
my @dns;
die "\nERROR: MUST specify either 'install' or 'uninstall' as an argument\n\n" unless (@ARGV);
if ( $ARGV[0] eq "install" ) {
	# install
	unless ( -e $resolv && -w $resolv ) {
		die "ERROR: $resolv is missing or not writeable!\n";
	}
	unless ( -e $rclocal && -w $rclocal ) {
		die "ERROR: $rclocal is missing or not writeable!\n";
	}
	unless ( -d $install_dir) {
		mkdir $install_dir || die "Cannot create $install_dir - $!";
		die "Cannot find folder: $install_dir" unless (-d $install_dir);
		print "INFO: Created folder $install_dir\n";
	}
	unless ( -x $logger ) {
		print STDERR "ERROR: cannot find $logger\n";
		die "Do you need to install util-linux?\n";
	}
	print "\nEnter DNS servers, one at a time, as IP addr (Press Enter When Done):\n";
	while (<STDIN>) {
		my $reply = $_;
		$reply =~ s/\s+$//;
		$reply =~ s/^\s+//;
		last unless ($reply);
		unless ($reply =~ /^\d+\.\d+\.\d+\.\d+$/) {
			print "ERROR: $reply does not seem to be an IP address\n";
			next;
		}
		my $ping = `ping -c1 $reply 2>&1`;
		if ($?) {
			print "WARNING: Cannot ping $reply!\n";
		}
		push @dns,$reply;
	}
	die "\nERROR: Must specify at least one DNS server\n\n" unless (@dns);
	open PRG,">$prgname" || die "Cannot open $prgname for output - $!";
	print PRG "$P1\n";
	my $i = 1;
	foreach my $dns (@dns) {
		printf PRG "\t\"%s\" => %d,\n",$dns,$i++;
	}
	print PRG "$P2\n";
	close PRG;
	chmod 0755,"$prgname";
	open RCLOCAL,"$rclocal" || die "Cannot open: $rclocal - $!";
	open NEW,">$rclocal.new" || die "Cannot open: $rclocal.new - $!";
	my $exit = 0;
	while (<RCLOCAL>) {
		if ( /^exit/ && $exit == 0) {
			$exit++;
			print NEW "nohup $prgname &\n";
		}
		print NEW;
	}
	print NEW "nohup $prgname &\n" unless ($exit);
	close NEW;
	close RCLOCAL;
	rename $rclocal,sprintf("%s.bak.%s",$rclocal,POSIX::strftime( "%y%m%d%H%M", localtime));
	rename "$rclocal.new",$rclocal;
	chmod 0755,"$rclocal";
	print "\nInstalled -- Reboot to activate\n\n";
} elsif ( $ARGV[0] eq "uninstall" ) {
	# uninstall
	unlink $prgname || die "Cannot unlink $prgname - $!";
	open RCLOCAL,"$rclocal" || die "Cannot open: $rclocal - $!";
	open NEW,">$rclocal.new" || die "Cannot open: $rclocal.new - $!";
	while (<RCLOCAL>) {
		next if (index ($_,"nohup $prgname") == 0 );
		print NEW;
	}
	close NEW;
	close RCLOCAL;
	rename $rclocal,sprintf("%s.bak.%s",$rclocal,POSIX::strftime( "%y%m%d%H%M", localtime));
	rename "$rclocal.new",$rclocal;
	chmod 0755,"$rclocal";
	print "\nUninstalled -- Reboot to remove\n\n";
} else {
	die "\nERROR: MUST specify either 'install' or 'uninstall'\n\n";
}
