App-DNS-Adblock
view release on metacpan or search on metacpan
lib/App/DNS/Adblock.pm view on Meta::CPAN
my $attributes;
sub new {
my ( $class, %self ) = @_;
my $self = { %self };
bless $self, $class;
$attributes = freeze($self);
$self->read_config();
my $host = Sys::HostIP->new;
my %devices = reverse %{ $host->interfaces };
my $hostip = $host->ip;
$self->{interface} = $devices{ $hostip };
$self->{host} = $hostip unless $self->{host};
$self->{port} = 53 unless $self->{port};
$self->{debug} = 0 unless $self->{debug};
my $ns = Net::DNS::Nameserver->new(
LocalAddr => $self->{host},
LocalPort => $self->{port},
ReplyHandler => sub { $self->reply_handler(@_); },
Verbose => ($self->{debug} > 1 ? 1 : 0)
) || die "couldn't create nameserver object: $!";
$self->{nameserver} = $ns;
my $res = Net::DNS::Resolver->new(
nameservers => [ @{ $self->{forwarders} } ],
port => $self->{forwarders_port} || 53,
recurse => 1,
debug => ($self->{debug} > 2 ? 1 : 0),
);
$self->{resolver} = $res;
return $self;
}
sub run {
my ( $self ) = shift;
$self->set_local_dns() if $self->{setdns};
$SIG{KILL} = sub { $self->signal_handler(@_) };
$SIG{QUIT} = sub { $self->signal_handler(@_) };
$SIG{TERM} = sub { $self->signal_handler(@_) };
$SIG{INT} = sub { $self->signal_handler(@_) };
$SIG{HUP} = sub { $self->read_config() };
$self->log("nameserver accessible locally @ $self->{host}", 1);
$self->{nameserver}->main_loop;
};
sub set_local_dns {
my ( $self ) = shift;
my $stdout;
my $stderr;
my @result;
if ($^O =~ /darwin/i) { # is osx
eval {
($self->{service}, $stderr, @result) = capture { system("networksetup -listallhardwareports | grep -B 1 $self->{interface} | cut -c 16-32") };
if ($stderr || ($result[0] < 0)) {
die $stderr || $result[0];
} else {
$self->{service} =~ s/\n//g;
system("networksetup -setdnsservers $self->{service} $self->{host}");
system("networksetup -setsearchdomains $self->{service} empty");
}
}
}
if (!grep { $^O eq $_ } qw(VMS MSWin32 os2 dos MacOS darwin NetWare beos vos)) { # is unix
eval {
($stdout, $stderr, @result) = capture { system("cp /etc/resolv.conf /etc/resolv.bk") };
if ($stderr || ($result[0] < 0)) {
die $stderr || $result[0];
} else {
open(CONF, ">", "/etc/resolv.conf");
print CONF "nameserver $self->{host}\n";
close CONF;
}
}
}
if ($stderr||$result[0]) {
$self->log("switching of local dns settings failed: $@", 1);
undef $self->{setdns};
} else {
$self->log("local dns settings ($self->{interface}) switched", 1);
}
}
sub restore_local_dns {
my ( $self ) = shift;
my $stdout;
my $stderr;
my @result;
if ($^O =~ /darwin/i) { # is osx
eval {
($stdout, $stderr, @result) = capture { system("networksetup -setdnsservers $self->{service} empty") };
if ($stderr || ($result[0] < 0)) {
die $stderr || $result[0];
} else {
system("networksetup -setsearchdomains $self->{service} empty");
}
}
}
if (!grep { $^O eq $_ } qw(VMS MSWin32 os2 dos MacOS darwin NetWare beos vos)) { # is unix
eval {
($stdout, $stderr, @result) = capture { system("mv /etc/resolv.bk /etc/resolv.conf") };
die $stderr || $result[0];
}
}
($stderr||$result[0]) ? $self->log("local dns settings failed to restore: $@", 1)
: $self->log("local dns settings restored", 1);
}
sub signal_handler {
my ( $self, $signal ) = @_;
$self->log("shutting down: signal $signal");
$self->restore_local_dns() if $self->{setdns};
exit;
}
sub reply_handler {
my ($self, $qname, $qclass, $qtype, $peerhost, $query,$conn) = @_;
my ($rcode, @ans, @auth, @add);
if ($self->{adfilter} && ($qtype eq 'AAAA' || $qtype eq 'A' || $qtype eq 'PTR')) {
if (my $ip = $self->query_adfilter( $qname, $qtype )) {
$self->log("received query from $peerhost: qtype '$qtype', qname '$qname'");
$self->log("[local] resolved $qname to $ip NOERROR");
my ($ttl, $rdata) = ( 300, $ip );
push @ans, Net::DNS::RR->new("$qname $ttl $qclass $qtype $rdata");
$rcode = "NOERROR";
return ($rcode, \@ans, \@auth, \@add, { aa => 1, ra => 1 });
}
}
my $answer = $self->{resolver}->send($qname, $qtype, $qclass);
if ($answer) {
$rcode = $answer->header->rcode;
@ans = $answer->answer;
@auth = $answer->authority;
@add = $answer->additional;
$self->log("[proxy] response from remote resolver: $qname $rcode");
return ($rcode, \@ans, \@auth, \@add);
} else {
$self->log("[proxy] can not resolve $qtype $qname - no answer from remote resolver. Sending NXDOMAIN response.");
$rcode = "NXDOMAIN";
return ($rcode, \@ans, \@auth, \@add, { aa => 1, ra => 1 });
}
}
sub log {
my ( $self, $msg, $force_flag ) = @_;
print "[" . strftime('%Y-%m-%d %H:%M:%S', localtime(time)) . "] " . $msg . "\n" if $self->{debug} || $force_flag;
( run in 3.488 seconds using v1.01-cache-2.11-cpan-d8267643d1d )