3 # Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC")
4 # Copyright (C) 2001 Internet Software Consortium.
6 # Permission to use, copy, modify, and/or distribute this software for any
7 # purpose with or without fee is hereby granted, provided that the above
8 # copyright notice and this permission notice appear in all copies.
10 # THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
11 # REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
12 # AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
13 # INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14 # LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15 # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16 # PERFORMANCE OF THIS SOFTWARE.
18 # Id: ans.pl,v 1.6 2007/09/24 04:13:25 marka Exp
21 # This is the name server from hell. It provides canned
22 # responses based on pattern matching the queries, and
23 # can be reprogrammed on-the-fly over a TCP connection.
25 # The server listens for control connections on port 5301.
26 # A control connection is a TCP stream of lines like
37 # There can be any number of patterns, each associated
38 # with any number of response RRs. Each pattern is a
39 # Perl regular expression.
41 # Each incoming query is converted into a string of the form
42 # "qname qtype" (the printable query domain name, space,
43 # printable query type) and matched against each pattern.
45 # The first pattern matching the query is selected, and
46 # the RR following the pattern line are sent in the
47 # answer section of the response.
49 # Each new control connection causes the current set of
50 # patterns and responses to be cleared before adding new
53 # The server handles UDP and TCP queries. Zone transfer
54 # responses work, but must fit in a single 64 k message.
62 my $ctlsock = IO
::Socket
::INET
->new(LocalAddr
=> "10.53.0.2",
63 LocalPort
=> 5301, Proto
=> "tcp", Listen
=> 5, Reuse
=> 1) or die "$!";
65 my $udpsock = IO
::Socket
::INET
->new(LocalAddr
=> "10.53.0.2",
66 LocalPort
=> 5300, Proto
=> "udp", Reuse
=> 1) or die "$!";
68 my $tcpsock = IO
::Socket
::INET
->new(LocalAddr
=> "10.53.0.2",
69 LocalPort
=> 5300, Proto
=> "tcp", Listen
=> 5, Reuse
=> 1) or die "$!";
71 my $pidf = new IO
::File
"ans.pid", "w" or die "cannot open pid file: $!";
72 print $pidf "$$\n" or die "cannot write pid file: $!";
73 $pidf->close or die "cannot close pid file: $!";;
74 sub rmpid
{ unlink "ans.pid"; exit 1; };
84 my ($packet, $err) = new Net
::DNS
::Packet
(\
$buf, 0);
87 $packet->header->qr(1);
88 $packet->header->aa(1);
90 my @questions = $packet->question;
91 my $qname = $questions[0]->qname;
92 my $qtype = $questions[0]->qtype;
96 my $pattern = $r->{pattern
};
97 warn "match $qname $qtype == $pattern";
98 if ("$qname $qtype" =~ /$pattern/) {
100 foreach $a (@
{$r->{answer
}}) {
101 $packet->push("answer", $a);
109 return $packet->data;
114 vec($rin, fileno($ctlsock), 1) = 1;
115 vec($rin, fileno($tcpsock), 1) = 1;
116 vec($rin, fileno($udpsock), 1) = 1;
118 select($rout = $rin, undef, undef, undef);
120 if (vec($rout, fileno($ctlsock), 1)) {
122 my $conn = $ctlsock->accept;
124 while (my $line = $conn->getline) {
126 if ($line =~ m!^/(.*)/$!) {
127 $rule = { pattern
=> $1, answer
=> [] };
130 push(@
{$rule->{answer
}},
131 new Net
::DNS
::RR
($line));
136 } elsif (vec($rout, fileno($udpsock), 1)) {
137 printf "UDP request\n";
138 $udpsock->recv($buf, 512);
139 $response = handle
($buf);
140 $udpsock->send($response);
141 } elsif (vec($rout, fileno($tcpsock), 1)) {
142 my $conn = $tcpsock->accept;
144 printf "TCP request\n";
145 my $n = $conn->sysread($lenbuf, 2);
147 my $len = unpack("n", $lenbuf);
148 $n = $conn->sysread($buf, $len);
149 last unless $n == $len;
150 $response = handle
($buf);
151 $len = length($response);
152 $n = $conn->syswrite(pack("n", $len), 2);
153 $n = $conn->syswrite($response, $len);