#!/usr/bin/perl
use DBI;
use Net::DNS;
use Net::DNS::Nameserver;
use Cache::Bounded;

my $dnsResolver = Net::DNS::Resolver->new;
$dnsResolver->nameservers('8.8.8.8','8.8.4.4'); 
my $dnsServer = Net::DNS::Nameserver->new(ReplyHandler => \&reply_handler);
my $dnsCache= new Cache::Bounded();

require "./database_settings.inc";

sub reply_handler {

	my ($qname, $qclass, $qtype, $peerhost,$query,$conn) = @_;
	my ($rcode, @ans, @auth, @add);
	
	my @cached_storage = $dnsCache->get($qname.$qclass.$qtype);
	
	if (@cached_storage[0] eq undef)
	{
		my $dbh = DBI->connect('DBI:mysql:'.$db_dtbs.':'.$db_host, $db_user, $db_pass);
		
		my $check_blocked = $dbh->prepare("SELECT COUNT(1) FROM `tvpn_blocked_sites` WHERE `domain`=?")->execute($qname);
		my ($is_blocked) = $check_blocked->fetchrow_array();
		$check_blocked->finish();
				
		if($is_blocked != 0) {
			$rcode = "NXDOMAIN";
		} else {
			my $dnsQuery = $dnsResolver->search($qname,$qtype,$qclass);
						
			if ($dnsQuery != undef) {
				@ans = $dnsQuery->answer;
				@auth = $dnsQuery->authority;
				@add = $dnsQuery->additional;
				$rcode = "NOERROR";
			} else {$rcode = "NXDOMAIN";}
		}
		
		@cached_storage = ($rcode,\@ans,\@auth,\@add);
		$dnsCache->set($qname.$qclass.$qtype, \@cached_storage, "1 hour");
		
		$dbh->disconnect();
	}
	else
	{
		$rcode = @cached_storage[0]->[0];
		for ($i = 0; $i != length @cached_storage[0]->[1]; $i++) {push(@ans ,@cached_storage[0]->[1]->[$i])};
		for ($i = 0; $i != length @cached_storage[0]->[2]; $i++) {push(@auth,@cached_storage[0]->[2]->[$i])};
		for ($i = 0; $i != length @cached_storage[0]->[3]; $i++) {push(@add ,@cached_storage[0]->[3]->[$i])};
	}
	
	return ($rcode, \@ans, \@auth, \@add, { aa => 1 });
};

$dnsServer->main_loop;
