# HG changeset patch # User Heiko Schlittermann # Date 1510235763 -3600 # Node ID b3cd686b8cf6cb37a496539d16554f1a7af2fd3d # Parent e127de596921b5faeeb4661bc61325c5dff82f54 Move to git.schlittermann.de/user/heiko/dns-autoslave diff -r e127de596921 -r b3cd686b8cf6 Makefile --- a/Makefile Thu Jul 14 10:03:39 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,19 +0,0 @@ - -p = dns-autoslave -SCRIPT = dns-autoslave -RC = rc.dns-autoslave - -prefix = /usr/local -sbindir = $(prefix)/stow/$p/sbin - -rcdir = /etc/init.d/ - -all: - @perl -c dns-autoslave - -stow: - install -m 0755 -d $(sbindir) - install -m 0755 -d $(rcdir) - install -m 0755 $(SCRIPT) $(sbindir)/ - install -m 0755 $(RC) $(rcdir)/$(p) - stow -d /usr/local/stow -vR $(p) diff -r e127de596921 -r b3cd686b8cf6 README --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/README Thu Nov 09 14:56:03 2017 +0100 @@ -0,0 +1,1 @@ +Moved to git.schlittermann.de/user/heiko/dns-autoslave diff -r e127de596921 -r b3cd686b8cf6 dns-autoslave --- a/dns-autoslave Thu Jul 14 10:03:39 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,184 +0,0 @@ -#! /usr/bin/perl - -use strict; -use warnings; -use Unix::Syslog qw(:macros :subs); -use File::Basename; -use Net::Pcap; -use Net::DNS::Packet; -use Net::DNS::Resolver; -use Fcntl ":flock"; -use AppConfig; -use POSIX qw(SIGTERM); - -# Es kommen Zeilen -# add slave domain.com -use constant ME => basename $0; -use constant CF_FILE => "/etc/".ME."/".ME.".conf"; -use constant LIB_DIR => "/etc/".ME; -use constant PROMISC => 0; - -use constant CONFIG => ( - { CASE => 1 }, - dev => { ARGS => "=s", DEFAULT => "eth0", ALIAS => "interface" }, - filter => { ARGS => "=s", DEFAULT => "udp and src host (%accept) and dst port domain" }, - accept => { ARGS => "=s" }, - pid => { ARGS => "=s", DEFAULT => "/var/run/".ME.".pid" }, -); - -sub process($$$); - -openlog(ME, LOG_PERROR | LOG_NDELAY | LOG_PID, LOG_DAEMON); -$SIG{__DIE__} = sub { die @_ if $^S; syslog(LOG_ERR, shift, @_); exit 1; }; -$SIG{__WARN__} = sub { syslog(LOG_WARNING, shift, @_); }; - -my $Cf = new AppConfig CONFIG or die; - $Cf->file(CF_FILE) or die if -f CF_FILE; - $Cf->args or die; - -my %Seen; - -MAIN: { - - $_ = $Cf->filter; - s/%accept/join " or ", split " ", $Cf->accept/e; - $Cf->filter($_); - - require lib; - import lib LIB_DIR; - require "local.pm"; - - - my $err; - my ($net, $mask); - my ($pcap, $filter); - - Net::Pcap::lookupnet($Cf->dev, \($net, $mask, $err)) == 0 or die $err; - $pcap = Net::Pcap::open_live($Cf->dev, 1500, PROMISC, 10, \$err) or die $err; - Net::Pcap::compile($pcap, \$filter, $Cf->filter, 1, $mask) == 0 or die $@; - Net::Pcap::setfilter($pcap, $filter); - - ## - my $pidfile = $Cf->pid; - my $pid; - open(PID, "+>>$pidfile") or die "Can't open $pidfile: $!\n"; - flock(PID, LOCK_EX) or die "Can't flock $pidfile: $!\n"; - seek(PID, 0, 0) or die "Can't seek $pidfile: $!\n"; - if (defined ($pid = )) { - chomp $pid; - die "Process $pid is running\n" if kill 0, $pid; - } - seek(PID, 0, 0); - truncate(PID, 0); - - $pid = fork; - die "Can't fork: $!\n" if not defined $pid; - - if ($pid) { - print PID "$pid\n"; - warn "Child pid: $pid\n"; - exit 0; - } - - POSIX::sigaction(SIGTERM, POSIX::SigAction->new(sub { Net::Pcap::breakloop($pcap); } )) - or die "Error setting SIGTERM Handler: $!\n"; - close(STDIN); close(STDOUT); close(STDERR); close(PID); - $0 = ME." [capturing]"; - Net::Pcap::loop($pcap, -1, \&process, undef) == -1 and die Net::Pcap::geterr($pcap); - warn "Exit.\n"; - unlink $Cf->pid; - exit 0; -} - - -sub process($$$) { - my (undef, $hdr, $data) = @_; - - { - # Link-Level: - # Dest 6 byte - # Src 6 byte - # type 2 byte - my $type = unpack("x12 n", $data); - if ($type != 0x800) { - warn "unexpected link layer type: ", sprintf("0x%x", $type), "\n"; - return; - } - # Link layer abschneiden - $data = substr($data, 14); - } - - my $src; - { - # IP-Header - # im ersten Byte stecken Version+Header-Länge - @_ = unpack("C x11 C4", $data); - my $hlen = ($_[0] & 0xf) * 4; - $src = join ".",@_[1..4]; - - # IP-Header abschneiden - $data = substr($data, $hlen); - } - - my $dns; - { - # UDP: SRC-Port 16 bit - # DST-Port 16 bit - # Len 16 bit - # Chksum 16 bit => 8 byte - $data = substr($data, 8); - $dns = new Net::DNS::Packet(\$data) or do { - warn "Can't decode packet\n"; - return; - } - } - - # Das, was wir bekommen, ist eine SOA-Query mit dem Opcode "NOTIFY", - # - # Sollen wir jetzt annehmen, daß der NS in der SOA (MNAME) der Master ist, - # oder sollen wir annehmen, daß die IP, von der es kommt, die des Masters - # ist? Beides kann falsch sein. - # - # Bei "hidden" Masters ist der Master höchstwahrscheinlich der interne (und damit - # nicht erreichbare) Name des Masters, das würde uns also nichts nützen. Wir könnten - # natürlich jetzt eine komplizierte Logik versuchen: - # DNS-Anfrage an den, von dem das NOTIFY kam über die IP des MNAME, - # wenn die OK ist, dann ... aber woher wissen wir, daß die OK ist. - # - # Wir gehen also einfach mal davon aus, daß der Master derjenige ist, - # welcher uns das NOTIFY geschickt hat. Und haben in der Konfig-Datei ein - # Mapping, damit wir die Fälle, wo der Master eine falsche Absender-IP - # nutzt (HA-Cluster) auch ordentlich behandeln können. - - return unless $dns->header->opcode =~ /^(?:NS_)?NOTIFY(?:_OP)?$/; - - # Das, was dort kommt, hat eine QUESTION und eine ANSWER, in der ANSWER steckt - foreach my $q ($dns->question) { - next unless $q->qtype eq "SOA"; - - my $domain = $q->qname; - my $msg = "NOTIFY from $src about $domain:"; - - if (exists $Seen{$domain} && (time - $Seen{$domain} < 60) ) { - warn "$msg OK(seen)\n"; - next; - } - - if ($_ = (new Net::DNS::Resolver (nameservers => ['127.0.0.1'], recurse => 0))->query($domain, "SOA") - and $_->header->aa) { - $Seen{$domain} = time; - warn "$msg OK(soa checked)\n"; - next; - } - - if (local::addZone($domain, $src)) { - warn "$msg ADDED", $@ ? "($@)" : "", "\n"; - next; - } - - warn "ERROR ", $@ ? "($@)" : "", "\n"; - - } -} - -# vim:sts=4 sw=4 aw ai sm: diff -r e127de596921 -r b3cd686b8cf6 dns-autoslave.conf.ex --- a/dns-autoslave.conf.ex Thu Jul 14 10:03:39 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ -accept = 192.168.7.2 \ - 192.168.7.3 diff -r e127de596921 -r b3cd686b8cf6 gen-dep-deb --- a/gen-dep-deb Thu Jul 14 10:03:39 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ -#!/usr/bin/equivs-build - -Section: perl -Priority: optional -Standards-Version: 3.6.2 - -Package: dns-autoslave-deps -Depends: perl-modules, libunix-syslog-perl, libnet-pcap-perl, libnet-dns-perl, libappconfig-perl -Description: dns-autoslave Dependencies - Installing this package will pull all Dependencies for dns-autoslave diff -r e127de596921 -r b3cd686b8cf6 ius/local.pm --- a/ius/local.pm Thu Jul 14 10:03:39 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,73 +0,0 @@ -# Example -# $Id$ -# $URL$ - -# remove the next line if you know, what you're doing -#die "Sure? You should adapt this file to your needs!"; - -package local; - -# in: zone name -# src ip -# out: 0 failure ($@ contains message) -# !0 ok ($@ may contain message) -sub addZone($$) { - my ($zone, $src) = @_; - my $hdns = '84.19.194.5'; - - # Filename ist für das File selbst und auch für die Konfig - (my $file = $zone) =~ s/[\/&|]/_/g; - - my $txt = <<__; -// Autoadded %time by $0 -zone "$zone" IN { - type slave; - file "/etc/bind/s/$file"; - masters { %masters; }; - allow-query { any; }; - allow-transfer { %transferees; }; -}; - -__ - - # 84.19.194.5 ist die ip unseres hidden master - my $transferees = $src eq $hdns ? 'localhost; key hh.schlittermann.de' : 'none'; - - $txt =~ s/%time/scalar localtime/eg; - $txt =~ s/%masters/$src/g; - $txt =~ s/%transferees/$transferees/g; - - if (-f ($_ = "/etc/bind/zones.auto/$file")) { - $@ = "$_ already exists"; - return 0; - } - - if (-f ($_ = "/etc/bind/zones.auto/.removed/$file")) { - $@ = "$_ removed"; - return 0; - } - - s/\.removed\///; - - open(OUT, $_ = ">$_") or die "Can't open $_: $!\n"; - print OUT $txt; - - open(OUT, $_ = ">>/etc/bind/zones.all") or die "Can't open $_: $!\n"; - print OUT $txt; - - close OUT; - - # return 0 == system("rndc reload"); - local @ARGV = qw(/var/run/named/named.pid); - chomp($_ = <>); - warn "Sending HUP to $_\n"; - $@ = "Nameserver reloaded (HUP sent)"; - kill "HUP", $_ and return 1; - - $@ = "No process $_"; - return 0; -} - - -1; -# vim:sts=4 sw=4 aw ai sm: diff -r e127de596921 -r b3cd686b8cf6 local.pm.ex-1 --- a/local.pm.ex-1 Thu Jul 14 10:03:39 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -# Example -# $Id$ -# $URL$ - -# remove the next line if you know, what you're doing -die "Sure? You should adapt this file to your needs!"; - -package local; - -# in: zone name -# src ip -# out: 0 failure ($@ contains message) -# !0 ok ($@ may contain message) -sub addZone($$) { - my ($zone, $src) = @_; - - # Filename ist für das File selbst und auch für die Konfig - (my $file = $zone) =~ s/[\/&|]/_/g; - - my $txt = <<__; -// Autoadded %time by $0 -zone "$zone" IN { - type slave; - file "/etc/bind/s/$file"; - masters { %masters; }; - allow-query { any; }; - allow-transfer { none; }; -}; - -__ - - $txt =~ s/%time/scalar localtime/eg; - $txt =~ s/%masters/$src/g; - - if (-f ($_ = "/etc/bind/zones.d/$file")) { - $@ = "$_ already exists"; - return 0; - } - - open(OUT, $_ = ">$_") or die "Can't open $_: $!\n"; - print OUT $txt; - - open(OUT, $_ = ">>/etc/bind/zones.all") or die "Can't open $_: $!\n"; - print OUT $txt; - - close OUT; - - # return 0 == system("rndc reload"); - local @ARGV = qw(/var/run/bind/run/named.pid); - chomp($_ = <>); - warn "Sending HUP to $_\n"; - $@ = "Nameserver reloaded (HUP sent)"; - kill "HUP", $_ and return 1; - - $@ = "No process $_"; - return 0; -} - - -1; -# vim:sts=4 sw=4 aw ai sm: diff -r e127de596921 -r b3cd686b8cf6 local.pm.ex-2 --- a/local.pm.ex-2 Thu Jul 14 10:03:39 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -# Example - -# remove the next line if you know, what you're doing -#die "Sure? You should adapt this file to your needs!"; - -package local; - -# in: zone name -# src ip -# out: 0 failure ($@ contains message) -# !0 ok ($@ may contain message) -sub addZone($$) { - my ($zone, $src) = @_; - my $hdns = '84.19.194.5'; - - # Filename ist für das File selbst und auch für die Konfig - (my $file = $zone) =~ s/[\/&|]/_/g; - - # 84.19.194.5 ist die ip unseres hidden master - my $transferees = $src eq $hdns ? 'localhost; key hh.schlittermann.de' : 'none'; - - my $txt = <<__; -{ - type slave; - file "/etc/cache/bind/slave/$file"; - masters { $src; }; - allow-query { any; }; - allow-transfer { $transferees; }; -}; - -__ - - # set - # allow-new-zones yes; - # in /etc/bind/named.conf.options - system rndc => ( - addzone => $zone, - $txt - ); - - if ($?) { - warn "rndc addzone $zone failed\n"; - return 0; - } - - $@ = "zone $zone added via rndc addzone\n"; - return 1; - -} - -1; -# vim:sts=4 sw=4 aw ai sm: diff -r e127de596921 -r b3cd686b8cf6 rc.dns-autoslave --- a/rc.dns-autoslave Thu Jul 14 10:03:39 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,38 +0,0 @@ -#! /bin/sh - -### BEGIN INIT INFO -# Provides: dns-autoslave -# Required-Start: $local_fs $remote_fs $syslog $named $network $time -# Required-Stop: $local_fs $remote_fs $syslog $named $network -# Should-Start: -# Should-Stop: -# Default-Start: 2 3 4 5 -# Default-Stop: 0 1 6 -# Short-Description: Start/Stop the dns-autoslave daemon -### END INIT INFO - -DAEMON=/usr/local/sbin/dns-autoslave -PIDFILE=/var/run/`basename $DAEMON`.pid - -case $1 in - - start) - start-stop-daemon -v --start --pidfile $PIDFILE --startas $DAEMON - ;; - - stop) - start-stop-daemon -v --stop --retry 30 --pidfile $PIDFILE - ;; - - restart) echo "Restarting $NAME..." - $0 stop - $0 start - ;; - - *) - echo "Usage: $0 {start|stop|restart}" >&2 - exit 1 - ;; -esac - -exit 0