ans.pl revision 0c27b3fe77ac1d5094ba3521e8142d9e7973133f
#
# Copyright (C) 2011, 2012, 2016 Internet Systems Consortium, Inc. ("ISC")
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
# $Id: ans.pl,v 1.2 2011/08/31 06:49:10 marka Exp $
#
# This is the name server from hell. It provides canned
# responses based on pattern matching the queries, and
# can be reprogrammed on-the-fly over a TCP connection.
#
# The server listens for control connections on port 5301.
# A control connection is a TCP stream of lines like
#
# /pattern/
# name ttl type rdata
# name ttl type rdata
# ...
# /pattern/
# name ttl type rdata
# name ttl type rdata
# ...
#
# There can be any number of patterns, each associated
# with any number of response RRs. Each pattern is a
# Perl regular expression.
#
# Each incoming query is converted into a string of the form
# "qname qtype" (the printable query domain name, space,
# printable query type) and matched against each pattern.
#
# The first pattern matching the query is selected, and
# the RR following the pattern line are sent in the
# answer section of the response.
#
# Each new control connection causes the current set of
# patterns and responses to be cleared before adding new
# ones.
#
# The server handles UDP and TCP queries. Zone transfer
# responses work, but must fit in a single 64 k message.
#
#
# /pattern <key> <key_data>/
# name ttl type rdata
# name ttl type rdata
#
# Note that this data will still be sent with any request for
# pattern, only this data will be signed. Currently, this is only
# done for TCP.
use strict;
# Ignore SIGPIPE so we won't fail if peer closes a TCP socket early
# Flush logged output after every line
local $| = 1;
my $server_addr = "10.53.0.4";
print "listening on $server_addr:5300.\n";
$pidf->close or die "cannot close pid file: $!";;
#my @answers = ();
my @rules;
sub handleUDP {
my ($buf) = @_;
my $packet;
$@ and die $@;
} else {
my $err;
}
# get the existing signature if any, and clear the additional section
my $prev_tsig;
}
}
my $r;
foreach $r (@rules) {
print "[handleUDP] $dbtype, $key_name, $key_data \n";
if ("$qname $qtype" =~ /$dbtype/) {
my $a;
foreach $a (@{$r->{answer}}) {
$packet->push("answer", $a);
}
# Sign the packet
print " Signing the response with " .
"$key_name/$key_data\n";
new("$key_name TSIG $key_data");
# These kluges are necessary because Net::DNS
# doesn't know how to sign responses. We
# clear compnames so that the TSIG key and
# algorithm name won't be compressed, and
# add one to arcount because the signing
# function will attempt to decrement it,
# which is incorrect in a response. Finally
# we set request_mac to the previous digest.
$packet->{"compnames"} = {};
if (defined($prev_tsig)) {
my $rmac = pack('n H*',
$tsig->{"request_mac"} =
unpack("H*", $rmac);
}
}
last;
}
}
#$packet->print;
}
# namelen:
# given a stream of data, reads a DNS-formatted name and returns its
# total length, thus making it possible to skip past it.
sub namelen {
my ($data) = @_;
my $len = 0;
my $label_len = 0;
do {
} while ($label_len != 0);
return ($len);
}
# packetlen:
# given a stream of data, reads a DNS wire-format packet and returns
# its total length, making it possible to skip past it.
sub packetlen {
my ($data) = @_;
my $q;
my $rr;
}
}
}
}
return $offset;
}
# sign_tcp_continuation:
# This is a hack to correct the problem that Net::DNS has no idea how
# to sign multiple-message TCP responses. Several data that are included
# in the digest when signing a query or the first message of a response are
# omitted when signing subsequent messages in a TCP stream.
#
# Net::DNS::Packet->sign_tsig() has the ability to use a custom signing
# function (specified by calling Packet->sign_func()). We use this
# function as the signing function for TCP continuations, and it removes
# the unwanted data from the digest before calling the default sign_hmac
# function.
sub sign_tcp_continuation {
# copy out first two bytes: size of the previous MAC
# copy out previous MAC
# try parsing out the packet information
# remove the keyname, ttl, class, and algorithm name
# preserve the TSIG data
# prepare a new digest and sign with it
}
sub handleTCP {
my ($buf) = @_;
my $packet;
$@ and die $@;
} else {
my $err;
}
# get the existing signature if any, and clear the additional section
my $prev_tsig;
my $signer;
}
}
my @results = ();
my $count_these = 0;
my $r;
foreach $r (@rules) {
print "[handleTCP] $dbtype, $key_name, $key_data \n";
if ("$qname $qtype" =~ /$dbtype/) {
$count_these++;
my $a;
foreach $a (@{$r->{answer}}) {
$packet->push("answer", $a);
}
# sign the packet
print " Signing the data with " .
"$key_name/$key_data\n";
new("$key_name TSIG $key_data");
# These kluges are necessary because Net::DNS
# doesn't know how to sign responses. We
# clear compnames so that the TSIG key and
# algorithm name won't be compressed, and
# add one to arcount because the signing
# function will attempt to decrement it,
# which is incorrect in a response. Finally
# we set request_mac to the previous digest.
$packet->{"compnames"} = {};
if (defined($prev_tsig)) {
my $rmac = pack('n H*',
$tsig->{"request_mac"} =
unpack("H*", $rmac);
}
$signer = \&sign_tcp_continuation;
my $copy =
}
#$packet->print;
}
}
print " A total of $count_these patterns matched\n";
return \@results;
}
# Main
my $rin;
my $rout;
for (;;) {
$rin = '';
printf "UDP request\n";
my $buf;
my $buf;
for (;;) {
my $lenbuf;
last unless $n == 2;
}
sleep(1);
}
}