File: Programmable.pm

package info (click to toggle)
libnet-dns-resolver-programmable-perl 0.003-3
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 156 kB
  • ctags: 10
  • sloc: perl: 55; makefile: 2
file content (287 lines) | stat: -rw-r--r-- 7,773 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
#
# Net::DNS::Resolver::Programmable
# A Net::DNS::Resolver descendant class for offline emulation of DNS
#
# (C) 2006-2007 Julian Mehnle <julian@mehnle.net>
# $Id: Programmable.pm 13 2007-05-30 22:12:35Z julian $
#
##############################################################################

package Net::DNS::Resolver::Programmable;

=head1 NAME

Net::DNS::Resolver::Programmable - programmable DNS resolver class for offline
emulation of DNS

=head1 VERSION

0.003

=cut

use version; our $VERSION = qv('0.003');

use warnings;
use strict;

use base 'Net::DNS::Resolver';

use Net::DNS::Packet;

use constant TRUE   => (0 == 0);
use constant FALSE  => not TRUE;

# Interface:
##############################################################################

=head1 SYNOPSIS

    use Net::DNS::Resolver::Programmable;
    use Net::DNS::RR;
    
    my $resolver = Net::DNS::Resolver::Programmable->new(
        records         => {
            'example.com'     => [
                Net::DNS::RR->new('example.com.     NS  ns.example.org.'),
                Net::DNS::RR->new('example.com.     A   192.168.0.1')
            ],
            'ns.example.org'  => [
                Net::DNS::RR->new('ns.example.org.  A   192.168.1.1')
            ]
        },
        
        resolver_code   => sub {
            my ($domain, $rr_type, $class) = @_;
            ...
            return ($result, $aa, @rrs);
        }
    );

=cut

# Implementation:
##############################################################################

=head1 DESCRIPTION

B<Net::DNS::Resolver::Programmable> is a B<Net::DNS::Resolver> descendant
class that allows a virtual DNS to be emulated instead of querying the real
DNS.  A set of static DNS records may be supplied, or arbitrary code may be
specified as a means for retrieving DNS records, or even generating them on the
fly.

=head2 Constructor

The following constructor is provided:

=over

=item B<new(%options)>: returns I<Net::DNS::Resolver::Programmable>

Creates a new programmed DNS resolver object.

%options is a list of key/value pairs representing any of the following
options:

=over

=item B<records>

A reference to a hash of arrays containing a static set of I<Net::DNS::RR>
objects.  The hash entries must be indexed by fully qualified domain names
(lower-case, without any trailing dots), and the entries themselves must be
arrays of the RR objects pertaining to these domain names.  For example:

    records => {
        'example.com'     => [
            Net::DNS::RR->new('example.com.     NS  ns.example.org.'),
            Net::DNS::RR->new('example.com.     A   192.168.0.1')
        ],
        'www.example.com' => [
            Net::DNS::RR->new('www.example.com. A   192.168.0.2')
        ],
        'ns.example.org'  => [
            Net::DNS::RR->new('ns.example.org.  A   192.168.1.1')
        ]
    }

If this option is specified, the resolver retrieves requested RRs from this
data structure.

=item B<resolver_code>

A code reference used as a call-back for dynamically retrieving requested RRs.

The code must take the following query parameters as arguments: the I<domain>,
I<RR type>, and I<class>.

It must return a list composed of: the response's I<RCODE> (by name, as
returned by L<< Net::DNS::Header->rcode|Net::DNS::Header/rcode >>), the
I<< C<aa> (authoritative answer) flag >> (I<boolean>, use B<undef> if you don't
care), and the I<Net::DNS::RR answer objects>.  If an error string is returned
instead of a valid RCODE, a I<Net::DNS::Packet> object is not constructed but
an error condition for the resolver is signaled instead.

For example:

    resolver_code => sub {
        my ($domain, $rr_type, $class) = @_;
        ...
        return ($result, $aa, @rrs);
    }

If both this and the C<records> option are specified, then statically
programmed records are used in addition to any that are returned by the
configured resolver code.

=item B<defnames>

=item B<dnsrch>

=item B<domain>

=item B<searchlist>

=item B<debug>

These Net::DNS::Resolver options are also meaningful with
Net::DNS::Resolver::Programmable.  See L<Net::DNS::Resolver> for their
descriptions.

=back

=cut

sub new {
    my ($self, %options) = @_;
    
    # Create new object:
    $self = $self->SUPER::new(%options);
    
    $self->{records}       = $options{records};
    $self->{resolver_code} = $options{resolver_code};
    
    return $self;
}

=back

=head2 Instance methods

The following instance methods of I<Net::DNS::Resolver> are also supported by
I<Net::DNS::Resolver::Programmable>:

=over

=item B<search>: returns I<Net::DNS::Packet>

=item B<query>: returns I<Net::DNS::Packet>

=item B<send>: returns I<Net::DNS::Packet>

Performs an offline DNS query, using the statically programmed DNS RRs and/or
the configured dynamic resolver code.  See the L</new> constructor's C<records>
and C<resolver_code> options.  See the descriptions of L<search, query, and
send|Net::DNS::Resolver/search> for details about the calling syntax of these
methods.

=cut

sub send {
    my $self = shift;
    
    my $query_packet = $self->make_query_packet(@_);
    my $question = ($query_packet->question)[0];
    my $domain   = lc($question->qname);
    my $rr_type  = $question->qtype;
    my $class    = $question->qclass;
    
    $self->_reset_errorstring;
    
    my ($result, $aa, @answer_rrs);
    
    if (defined(my $resolver_code = $self->{resolver_code})) {
        ($result, $aa, @answer_rrs) = $resolver_code->($domain, $rr_type, $class);
    }

    if (not defined($result)
         or defined($Net::DNS::rcodesbyname{$result})
         or defined($Net::DNS::Parameters::rcodebyname{$result})) {
        # Valid RCODE, return a packet:
        
        $aa     = TRUE      if not defined($aa);
        $result = 'NOERROR' if not defined($result);
        
        if (defined(my $records = $self->{records})) {
            if (ref(my $rrs_for_domain = $records->{$domain}) eq 'ARRAY') {
                foreach my $rr (@$rrs_for_domain) {
                    push(@answer_rrs, $rr)
                        if  $rr->name  eq $domain
                        and $rr->type  eq $rr_type
                        and $rr->class eq $class;
                }
            }
        }
        
        my $packet = Net::DNS::Packet->new($domain, $rr_type, $class);
        $packet->header->qr(TRUE);
        $packet->header->rcode($result);
        $packet->header->aa($aa);
        $packet->push(answer => @answer_rrs);
        
        return $packet;
    }
    else {
        # Invalid RCODE, signal error condition by not returning a packet:
        $self->errorstring($result);
        return undef;
    }
}

=item B<print>

=item B<string>: returns I<string>

=item B<searchlist>: returns I<list> of I<string>

=item B<defnames>: returns I<boolean>

=item B<dnsrch>: returns I<boolean>

=item B<debug>: returns I<boolean>

=item B<errorstring>: returns I<string>

=item B<answerfrom>: returns I<string>

=item B<answersize>: returns I<integer>

See L<Net::DNS::Resolver/METHODS>.

=back

Currently the following methods of I<Net::DNS::Resolver> are B<not> supported:
B<axfr>, B<axfr_start>, B<axfr_next>, B<nameservers>, B<port>, B<srcport>,
B<srcaddr>, B<bgsend>, B<bgread>, B<bgisready>, B<tsig>, B<retrans>, B<retry>,
B<recurse>, B<usevc>, B<tcp_timeout>, B<udp_timeout>, B<persistent_tcp>,
B<persistent_udp>, B<igntc>, B<dnssec>, B<cdflag>, B<udppacketsize>.
The effects of using these on I<Net::DNS::Resolver::Programmable> objects are
undefined.

=head1 SEE ALSO

L<Net::DNS::Resolver>

For availability, support, and license information, see the README file
included with Net::DNS::Resolver::Programmable.

=head1 AUTHORS

Julian Mehnle <julian@mehnle.net>

=cut

TRUE;

# vim:sts=4 sw=4 et