~ubuntu-branches/ubuntu/vivid/net-dns-fingerprint/vivid

« back to all changes in this revision

Viewing changes to Fingerprint.pm

  • Committer: Bazaar Package Importer
  • Author(s): Anand Kumria
  • Date: 2005-10-20 23:30:37 UTC
  • Revision ID: james.westby@ubuntu.com-20051020233037-k7rftpzvydhokdgr
Tags: upstream-0.9.3
ImportĀ upstreamĀ versionĀ 0.9.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/perl
 
2
#
 
3
# $Id: Fingerprint.pm,v 1.17 2005/09/05 13:33:36 jakob Exp $
 
4
#
 
5
# Copyright (c) 2003,2004,2005 Roy Arends & Jakob Schlyter.
 
6
# All rights reserved.
 
7
#
 
8
# Redistribution and use in source and binary forms, with or without
 
9
# modification, are permitted provided that the following conditions
 
10
# are met:
 
11
 
12
# 1. Redistributions of source code must retain the above copyright
 
13
#    notice, this list of conditions and the following disclaimer.
 
14
# 2. Redistributions in binary form must reproduce the above copyright
 
15
#    notice, this list of conditions and the following disclaimer in the
 
16
#    documentation and/or other materials provided with the distribution.
 
17
# 3. The name of the authors may not be used to endorse or promote products
 
18
#    derived from this software without specific prior written permission.
 
19
 
20
# THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
 
21
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 
22
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 
23
# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 
24
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 
25
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 
26
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 
27
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
28
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 
29
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
30
 
 
31
require 5.6.0;
 
32
 
 
33
package Net::DNS::Fingerprint;
 
34
 
 
35
use strict;
 
36
use warnings;
 
37
use Net::DNS 0.42;
 
38
 
 
39
our $VERSION = "0.9.3";
 
40
 
 
41
my %default = (
 
42
    source   => undef,
 
43
    timeout  => 5,
 
44
    retry    => 1,
 
45
    forcetcp => 0,
 
46
    debug    => 0,
 
47
    qversion => 0,
 
48
    qchaos   => 0,
 
49
);
 
50
 
 
51
my $versionlength = 40;
 
52
 
 
53
my @qy = ("0,IQUERY,0,0,1,0,0,0,NOERROR,0,0,0,0",
 
54
          "0,NS_NOTIFY_OP,0,0,0,0,0,0,NOERROR,0,0,0,0",
 
55
          "0,QUERY,0,0,0,0,0,0,NOERROR,0,0,0,0",
 
56
          "0,IQUERY,0,0,0,0,1,1,NOERROR,0,0,0,0",
 
57
          "0,QUERY,0,0,0,0,0,0,NOTIMP,0,0,0,0",
 
58
          "0,IQUERY,1,0,1,1,1,1,NOERROR,0,0,0,0",
 
59
          "0,UPDATE,0,0,0,1,0,0,NOERROR,0,0,0,0",
 
60
          "0,QUERY,1,1,1,1,1,1,NOERROR,0,0,0,0", 
 
61
          "0,QUERY,0,0,0,0,0,1,NOERROR,0,0,0,0",
 
62
         );
 
63
 
 
64
my %initrule = (header => $qy[0], query  => ". IN A", );
 
65
my @iq = ("1,IQUERY,0,0,1,0,0,0,FORMERR,0,0,0,0",   # iq0
 
66
          "1,IQUERY,0,0,1,0,0,0,FORMERR,1,0,0,0",   # iq1
 
67
          "1,IQUERY,0,0,1,0,0,0,NOTIMP,0,0,0,0",    # iq2
 
68
          "1,IQUERY,0,0,1,0,0,0,NOTIMP,1,0,0,0",    # iq3
 
69
          "1,IQUERY,0,0,1,1,0,0,FORMERR,0,0,0,0",   # iq4
 
70
          "1,IQUERY,0,0,1,1,0,0,NOTIMP,0,0,0,0",    # iq5 
 
71
          "1,IQUERY,0,0,1,1,0,0,NOTIMP,1,0,0,0",    # iq6
 
72
          "1,IQUERY,1,0,1,0,0,0,NOTIMP,1,0,0,0",    # iq7
 
73
          "1,QUERY,1,0,1,0,0,0,NOTIMP,1,0,0,0",
 
74
          "1,QUERY,0,0,0,0,0,0,NOTIMP,0,0,0,0",
 
75
          "1,IQUERY,0,0,1,1,0,0,FORMERR,1,0,0,0",   # iq10
 
76
          "1,NS_NOTIFY_OP,0,0,0,0,0,0,FORMERR,1,0,0,0",
 
77
          "1,NS_NOTIFY_OP,0,0,0,0,0,0,NOTIMP,0,0,0,0",
 
78
          "1,NS_NOTIFY_OP,0,0,0,0,0,0,NOTIMP,1,0,0,0",
 
79
          "1,NS_NOTIFY_OP,0,0,0,0,0,0,NXDOMAIN,1,0,0,0",
 
80
          "1,NS_NOTIFY_OP,0,0,0,0,0,0,REFUSED,1,0,0,0",
 
81
          "1,NS_NOTIFY_OP,0,0,0,0,0,0,SERVFAIL,1,0,0,0",
 
82
          "1,NS_NOTIFY_OP,0,0,0,1,0,0,FORMERR,1,0,0,0",
 
83
          "1,NS_NOTIFY_OP,0,0,0,1,0,0,NOTIMP,0,0,0,0",
 
84
          "1,NS_NOTIFY_OP,0,0,0,1,0,0,NOTIMP,1,0,0,0",
 
85
          "1,NS_NOTIFY_OP,0,0,0,1,0,0,REFUSED,1,0,0,0", # iq20
 
86
          "1,NS_NOTIFY_OP,0,0,0,1,0,0,SERVFAIL,1,0,0,0",
 
87
          "1,NS_NOTIFY_OP,1,0,0,0,0,0,NOTIMP,1,0,0,0",
 
88
          "1,QUERY,1,0,0,0,0,0,NOTIMP,1,0,0,0",
 
89
          "1,NS_NOTIFY_OP,1,0,0,0,0,0,SERVFAIL,1,0,0,0",
 
90
          "1,IQUERY,0,0,0,0,1,1,NOTIMP,0,0,0,0",
 
91
          "1,IQUERY,0,0,0,0,0,0,NOTIMP,0,0,0,0",
 
92
          "1,IQUERY,0,0,1,1,1,1,FORMERR,0,0,0,0",
 
93
          "1,IQUERY,1,0,1,1,1,1,FORMERR,0,0,0,0",
 
94
          "1,QUERY,.,0,1,.,.,.,NOTIMP,.+,.+,.+,.+",
 
95
          "1,QUERY,.,0,1,.,.,.,.+,.+,.+,.+,.+", #iq30
 
96
          "1,QUERY,0,0,.,.,0,0,NXDOMAIN,1,0,0,0",    
 
97
          "1,QUERY,0,0,.,.,0,0,FORMERR,1,0,0,0",
 
98
          "1,UPDATE,0,0,0,0,0,0,NOTIMP,0,0,0,0",
 
99
          "1,UPDATE,0,0,0,1,0,0,NOTIMP,0,0,0,0",
 
100
          "1,QUERY,0,0,1,0,0,0,NOERROR,1,0,0,0",
 
101
          "1,QUERY,1,1,1,1,1,1,NOTIMP,1,0,0,0",
 
102
          "1,QUERY,0,0,0,0,0,0,NOERROR,1,0,.+,0",
 
103
          "1,QUERY,0,0,1,0,0,0,FORMERR,1,0,0,0",
 
104
          "1,IQUERY,0,0,1,0,1,1,NOTIMP,1,0,0,0",
 
105
          "1,IQUERY,0,0,0,1,1,1,REFUSED,1,0,0,0", #iq40
 
106
          "1,UPDATE,0,0,0,1,0,0,REFUSED,1,0,0,0",
 
107
          "1,IQUERY,0,0,0,1,1,1,FORMERR,0,0,0,0",
 
108
          "1,IQUERY,0,0,0,1,0,0,NOTIMP,0,0,0,0",
 
109
          "1,QUERY,1,0,1,0,0,0,FORMERR,1,0,0,0",
 
110
          "1,UPDATE,0,0,0,0,0,0,FORMERR,1,0,0,0",
 
111
          "1,UPDATE,0,0,0,0,0,0,FORMERR,0,0,0,0",
 
112
          "1,QUERY,0,0,1,0,0,0,FORMERR,0,0,0,0",
 
113
          "1,QUERY,0,0,1,0,0,0,SERVFAIL,1,0,0,0", #iq48
 
114
          "1,QUERY,1,0,1,0,0,0,NXDOMAIN,1,0,1,0",
 
115
          "1,QUERY,0,0,1,0,0,0,REFUSED,1,0,0,0", #iq50
 
116
          "1,QUERY,0,0,1,0,0,0,NOERROR,1,1,0,0",
 
117
          "1,IQUERY,0,0,1,0,0,0,REFUSED,0,0,0,0",
 
118
          "1,QUERY,0,0,0,0,0,0,FORMERR,0,0,0,0",
 
119
          "1,QUERY,0,0,1,1,1,0,NOERROR,1,0,1,0",
 
120
          "1,QUERY,0,0,1,1,0,0,NOERROR,1,0,1,0",
 
121
          "1,QUERY,0,0,1,0,1,0,NOERROR,.+,.+,.+,.+", 
 
122
          "1,QUERY,0,0,1,0,0,0,.+,.+,.+,.+,.+",
 
123
          "1,QUERY,1,0,1,0,0,0,NOERROR,1,1,0,0",
 
124
          "1,QUERY,0,0,1,1,0,0,SERVFAIL,1,0,0,0", 
 
125
          "1,QUERY,1,0,1,1,0,0,NOERROR,1,1,0,0", #iq60
 
126
          "1,QUERY,0,0,1,1,0,0,REFUSED,1,0,0,0",
 
127
          "1,QUERY,0,0,0,0,0,0,NOTIMP,1,0,0,0",
 
128
          "1,QUERY,1,0,1,1,0,0,NOERROR,1,0,1,0",
 
129
          "1,IQUERY,0,0,1,1,1,1,NOTIMP,0,0,0,0",
 
130
          "1,UPDATE,0,0,0,0,0,0,REFUSED,0,0,0,0",
 
131
          "1,IQUERY,0,0,0,1,1,1,NOTIMP,1,0,0,0",
 
132
          "1,IQUERY,0,0,0,1,0,0,NOTIMP,1,0,0,0",
 
133
          "1,QUERY,0,1,1,1,1,1,NOERROR,1,0,.,0",
 
134
          "1,QUERY,0,1,1,1,0,1,NOERROR,1,0,.,0",
 
135
          "1,IQUERY,0,0,1,0,0,0,REFUSED,1,0,0,0", #iq70
 
136
          "1,IQUERY,1,0,1,1,1,1,NOTIMP,1,0,0,0",
 
137
          "1,IQUERY,0,0,1,0,0,0,NOERROR,1,0,0,0",
 
138
          "1,QUERY,1,0,1,1,0,0,NOERROR,1,0,0,0",
 
139
          "1,IQUERY,1,0,1,1,0,0,NXDOMAIN,1,0,0,0",
 
140
          "1,UPDATE,0,0,0,1,0,0,FORMERR,0,0,0,0",
 
141
          "1,IQUERY,1,0,1,0,0,0,NXDOMAIN,1,0,0,0",
 
142
          "1,QUERY,0,0,1,1,0,0,FORMERR,1,0,0,0",
 
143
          "1,QUERY,0,0,0,1,0,0,SERVFAIL,1,0,0,0",
 
144
          "1,QUERY,0,0,1,1,0,0,NOERROR,1,1,0,0",
 
145
          "1,IQUERY,1,0,1,0,0,0,NOERROR,1,0,0,0", #iq80
 
146
          "1,IQUERY,1,0,1,1,0,0,NOTIMP,1,0,0,0",
 
147
          "1,QUERY,0,0,1,1,0,0,NOERROR,1,0,0,0",
 
148
          "1,QUERY,1,0,1,1,0,0,NOERROR,1,1,1,.+",
 
149
          "1,QUERY,0,0,1,1,0,0,REFUSED,0,0,0,0",
 
150
          "1,UPDATE,0,0,0,1,0,0,NOTIMP,1,0,0,0",
 
151
          "1,QUERY,1,0,0,1,0,0,NXDOMAIN,1,0,0,0",
 
152
          "1,QUERY,0,0,0,1,0,0,NOTIMP,0,0,0,0",
 
153
          "1,QUERY,0,0,0,0,0,0,REFUSED,1,0,0,0",
 
154
          "1,QUERY,1,0,1,1,0,0,NXDOMAIN,1,0,0,0",
 
155
          "1,QUERY,1,0,0,0,0,0,NOERROR,1,1,0,0", #iq90
 
156
          "1,IQUERY,1,0,1,1,0,1,NOTIMP,1,0,0,0",
 
157
          "1,QUERY,0,0,0,1,0,0,NOTIMP,1,0,0,0",
 
158
          "1,QUERY,0,0,1,0,0,1,SERVFAIL,1,0,0,0",
 
159
);
 
160
 
 
161
my @ruleset = (
 
162
    { fingerprint => "query timed out" , header => $qy[0],  query => "com. IN A", ruleset => [
 
163
          { fingerprint => "query timed out", header => $qy[7], query => ". CH A", ruleset => [
 
164
                 { fingerprint => "query timed out", header => $qy[6], query => ". IN A", ruleset => [
 
165
                        { fingerprint => $iq[38], result => { vendor => "Digital Lumber", product => "Oak DNS", version =>"" },  qv => "version.oak",}, 
 
166
                        { fingerprint => "query timed out", result => "TIMEOUT",}, 
 
167
                        { fingerprint => ".+", state => "q0tq0tq7tq6r?", }, ]
 
168
                 },
 
169
                 { fingerprint => $iq[35], result => { vendor => "XBILL", product => "jnamed (dnsjava)", version => "" }, },
 
170
                 { fingerprint => $iq[36], result => { vendor => "menandmice", product => "QuickDNS", version => ""}, }, 
 
171
                 { fingerprint => $iq[37], result => { vendor => "unknown", product => "NonSequitur DNS", version => ""}, },
 
172
                 { fingerprint => ".+", state => "q0tq0tq7r?", }, ]  
 
173
          },
 
174
          { fingerprint => $iq[35], result => { vendor => "eNom", product => "eNom DNS", version =>""}, },
 
175
          { fingerprint => ".+", state => "q0tq0r?", },]
 
176
    },
 
177
 
 
178
    { fingerprint => $iq[0], header => $qy[1], query=> "jjjjjjjjjjjj IN A", ruleset => [
 
179
          { fingerprint => $iq[12], result => { vendor => "ISC", product => "BIND", version => "8.4.1-p1" },  qv => "version.bind",},                         
 
180
          { fingerprint => $iq[13], result => { vendor => "ISC", product => "BIND", version => "8 plus root server modifications"},  qv => "version.bind",}, 
 
181
          { fingerprint => $iq[15], result => { vendor => "Cisco", product => "CNR", version => ""}, },
 
182
          { fingerprint => $iq[16], header => $qy[2], query => "hostname.bind CH TXT", ruleset => [
 
183
                  { fingerprint => $iq[58], result => { vendor => "ISC", product => "BIND", version => "8.3.0-RC1 -- 8.4.4"},  qv => "version.bind",},     
 
184
                  { fingerprint => $iq[50], result => { vendor => "ISC", product => "BIND", version => "8.3.0-RC1 -- 8.4.4"},  qv => "version.bind",},    
 
185
                  { fingerprint => $iq[48], result => { vendor => "ISC", product => "BIND", version => "8.2.2-P3 -- 8.3.0-T2A"},  qv => "version.bind",},
 
186
                  { fingerprint => ".+", state => "q0r0q1r16q2r?", },]
 
187
          },
 
188
          { fingerprint => ".+", state => "q0r0q1r?", },]
 
189
    },
 
190
 
 
191
    { fingerprint => $iq[1], header => $qy[2], query => ". IN IXFR", ruleset => [
 
192
          { fingerprint => $iq[31], result => { vendor => "Microsoft", product => "Windows DNS", version => "2000" }, },                                
 
193
          { fingerprint => $iq[32], result => { vendor => "Microsoft", product => "Windows DNS", version => "NT4" }, },
 
194
          { fingerprint => $iq[50], result => { vendor => "Microsoft", product => "Windows DNS", version => "2003"}, },
 
195
          { fingerprint => ".+", state => "q0r1q2r?", }, ]
 
196
    },
 
197
 
 
198
    { fingerprint => $iq[2], header => $qy[1], ruleset => [
 
199
          { fingerprint => $iq[11], result => { vendor => "ISC", product => "BIND", version => "9.2.3rc1 -- 9.4.0a0" }, qv => "version.bind",},    
 
200
          { fingerprint => $iq[12], header => $qy[3], ruleset => [
 
201
                { fingerprint => $iq[25], header => $qy[6], ruleset => [
 
202
                      { fingerprint => $iq[33], result => { vendor => "bboy", product => "MyDNS", version => "" },},                            
 
203
                      { fingerprint => $iq[34], header => $qy[2],  query  => "012345678901234567890123456789012345678901234567890123456789012.012345678901234567890123456789012345678901234567890123456789012.012345678901234567890123456789012345678901234567890123456789012.0123456789012345678901234567890123456789012345678901234567890. IN A", ruleset => [
 
204
                           { fingerprint => $iq[47], result => { vendor => "NLnetLabs", product => "NSD", version => "1.0.3 -- 1.2.1"}, qv => "version.server", }, 
 
205
                           { fingerprint => $iq[48], header => $qy[2],  query  => "hostname.bind CH TXT", ruleset => [
 
206
                                     { fingerprint => $iq[50], result => { vendor => "NLnetLabs", product => "NSD", version => "1.2.2" }, qv => "version.server", },
 
207
                                     { fingerprint => $iq[51], header => $qy[8], query => ". IN A", ruleset => [
 
208
                                           { fingerprint => $iq[93], result => { vendor => "NLnetLabs", product => "NSD", version => "1.2.3 -- 2.1.2" } , qv => "version.server",  },
 
209
                                           { fingerprint => $iq[48], result => { vendor => "NLnetLabs", product => "NSD", version => "2.1.3" }, qv => "version.server",  }, 
 
210
                                           { fingerprint => ".+", state => "q0r2q1r12q3r25q6r34q2r48q2r51q8r?", }, ]
 
211
                                     },
 
212
                                     { fingerprint => ".+", state => "q0r2q1r12q3r25q6r34q2r48q2r?", }, ]
 
213
                           },
 
214
                           { fingerprint => $iq[49], header => $qy[2],  query  => "hostname.bind CH TXT", ruleset => [
 
215
                                     { fingerprint => $iq[50], result => { vendor => "NLnetLabs", product => "NSD", version => "1.2.2 [root]"} , qv => "version.server",  },
 
216
                                     { fingerprint => $iq[51], result => { vendor => "NLnetLabs", product => "NSD", version => "1.2.3 [root]"}, qv => "version.server", }, 
 
217
                                     { fingerprint => ".+", state => "q0r2q1r12q3r25q6r34q2r49q2r?", }, ]
 
218
                           },
 
219
                           { fingerprint => $iq[53], result => { vendor => "NLnetLabs", product=>"NSD", version => "1.0.2"}, qv => "version.server", },
 
220
                           { fingerprint => ".+", state => "q0r2q1r12q3r25q6r34q2a?", },]
 
221
                      },
 
222
                      { fingerprint => ".+", state => "q0r2q1r12q3r25q6r?", },]
 
223
                },
 
224
                { fingerprint => $iq[26], result => { vendor => "VeriSign", product => "ATLAS", version => ""},}, 
 
225
                { fingerprint => ".+", state => "q0r2q1r12q3r?", },] 
 
226
          },
 
227
          { fingerprint => $iq[15],  header => $qy[6], ruleset => [
 
228
               { fingerprint => $iq[45], result => { vendor => "Nominum", product =>"ANS", version =>""}, qv => "version.bind",},
 
229
               { fingerprint => $iq[65], result => { vendor => "ISC", product => "BIND", version => "9.2.3rc1 -- 9.4.0a0" },  qv => "version.bind",},
 
230
               { fingerprint => $iq[46], header => $qy[7], ruleset => [
 
231
                      { fingerprint => $iq[56], result => { vendor => "ISC", product => "BIND", version => "9.0.0b5 -- 9.0.1" }, qv => "version.bind",},
 
232
                      { fingerprint => $iq[57], result => { vendor => "ISC", product => "BIND", version => "9.1.0 -- 9.1.3" }, qv => "version.bind",}, 
 
233
                      { fingerprint => ".+", state => "q0r2q1r15q6r46q7r?", }, ]
 
234
               },
 
235
               { fingerprint => ".+", state => "q0r2q1r15q6r?", },]
 
236
          },
 
237
          { fingerprint => $iq[16], header => $qy[4], ruleset => [
 
238
                { fingerprint => $iq[29], result => { vendor => "ISC", product => "BIND", version => "9.2.0a1 -- 9.2.0rc3"}, qv => "version.bind",},
 
239
                { fingerprint => $iq[30],  header => $qy[0], query  => ". A CLASS0" , ruleset => [
 
240
                        { fingerprint => $iq[2], result => { vendor=>"ISC", product => "BIND", version =>"9.2.0rc7 -- 9.2.2-P3"}, qv => "version.bind", },
 
241
                        { fingerprint => $iq[0], result => { vendor=>"ISC", product => "BIND", version =>"9.2.0rc4 -- 9.2.0rc6"}, qv => "version.bind", },
 
242
                        { fingerprint => ".+", result => { vendor => "ISC", product => "BIND", version =>"9.2.0rc4 -- 9.2.2-P3"}, qv => "version.bind", }, ]
 
243
                },
 
244
                { fingerprint => ".+", state => "q0r2q1r16q4r?", },]
 
245
          },
 
246
          { fingerprint => ".+", state => "q0r2q1r?", }, ]
 
247
    },
 
248
    
 
249
    { fingerprint => $iq[3], header => $qy[1], ruleset => [
 
250
          { fingerprint => "query timed out", header => $qy[5], ruleset => [
 
251
                { fingerprint => $iq[3], result => { vendor => "sourceforge", product =>"Dents", version =>""}, qv => "version.bind", },
 
252
                { fingerprint => $iq[81], result => { vendor => "Microsoft", product => "Windows DNS", version => "2003" },},
 
253
                { fingerprint => $iq[91], result => { vendor => "Microsoft", product => "Windows DNS", version => "2003" },},
 
254
                { fingerprint => ".+", state => "q0r3q1tq5r?", }, ]
 
255
 
 
256
          },     
 
257
          { fingerprint => $iq[14], result => { vendor => "UltraDNS", product => "", version =>"v2.7.0.2 -- 2.7.3"}, qv => "version.bind", }, 
 
258
          { fingerprint => $iq[13], header => $qy[5], ruleset => [
 
259
                { fingerprint => $iq[39], result => { vendor => "pliant", product => "DNS Server", version =>""},},
 
260
                { fingerprint => $iq[7], result => { vendor => "JHSOFT", product => "simple DNS plus", version =>""}, }, 
 
261
                { fingerprint => $iq[71], header => $qy[6], ruleset => [
 
262
                        { fingerprint => $iq[41], result => { vendor =>"Netnumber", product =>"ENUM server", version =>""}, },
 
263
                        { fingerprint => $iq[85], result => { vendor =>"Raiden", product => "DNSD", version => ""}, }, ]
 
264
                },
 
265
                { fingerprint => ".+", state => "q0r3q1r13q5r?", }, ]
 
266
                },
 
267
          { fingerprint => ".+", state => "q0r3q1r?", }, ]
 
268
    },
 
269
    
 
270
    { fingerprint => $iq[4], header => $qy[1], query=> "jjjjjjjjjjjj IN A", ruleset => [
 
271
          { fingerprint => $iq[17], result => { vendor => "ISC", product => "BIND", version =>"9.0.0b5 -- 9.0.1 [rcursion enabled]"},qv => "version.bind", },
 
272
          { fingerprint => $iq[18], header => $qy[5], query=> ". IN A" , ruleset => [
 
273
                { fingerprint => $iq[27], result => { vendor => "ISC", product => "BIND", version => "4.9.3 -- 4.9.11"}, qv => "version.bind", },
 
274
                { fingerprint => $iq[28], result => { vendor => "ISC", product => "BIND", version => "4.8 -- 4.8.3"}, }, 
 
275
                { fingerprint => ".+", state => "q0r4q1r18q5r?", }, ]
 
276
          },
 
277
          { fingerprint => $iq[19], result => {vendor => "ISC", product =>"BIND", version => "8.2.1 [recursion enabled]"}, qv => "version.bind", },           
 
278
          { fingerprint => $iq[20], header => $qy[3], query=> ". IN A", ruleset => [
 
279
                { fingerprint => $iq[42], result => {vendor => "ISC", product =>"BIND", version =>"8.1-REL -- 8.2.1-T4B [recursion enabled]"}, qv => "version.bind", }, 
 
280
                { fingerprint => ".+", state => "q0r4q1r20q3r?", },]
 
281
          },
 
282
          { fingerprint => $iq[21], header => $qy[2], query => "hostname.bind CH TXT", ruleset => [
 
283
                { fingerprint => $iq[60], result => {vendor =>"ISC", product => "BIND", version => "8.3.0-RC1 -- 8.4.4 [recursion enabled]"},  qv => "version.bind",},
 
284
                { fingerprint => $iq[59], header => $qy[7], query=> ". IN A", ruleset => [
 
285
                         { fingerprint => $iq[68], result => {vendor =>"ISC", product => "BIND", version => "8.1-REL -- 8.2.1-T4B [recursion enabled]"}, qv => "version.bind", },
 
286
                         { fingerprint => $iq[69], result => {vendor =>"ISC", product => "BIND", version => "8.2.2-P3 -- 8.3.0-T2A [recursion enabled]"},  qv => "version.bind",},
 
287
                         { fingerprint => "connection failed", result => { vendor =>"Runtop", product => "dsl/cable", version =>""},},
 
288
                         { fingerprint => ".+", state => "q0r4q1r21q2r59q7r?", },]
 
289
                },
 
290
 
 
291
                { fingerprint => $iq[58], result => {vendor => "ISC", product =>"BIND", version => "8.3.0-RC1 -- 8.4.4 [recursion local]"},  qv => "version.bind",},
 
292
                { fingerprint => $iq[50], result => {vendor => "ISC", product =>"BIND", version => "8.3.0-RC1 -- 8.4.4 [recursion local]"},  qv => "version.bind",},
 
293
                { fingerprint => $iq[61], result => {vendor => "ISC", product =>"BIND", version => "8.3.0-RC1 -- 8.4.4 [recursion local]"},  qv => "version.bind",},
 
294
                { fingerprint => $iq[48], result => {vendor => "ISC", product =>"BIND", version => "8.2.2-P3 -- 8.3.0-T2A [recursion local]"},  qv => "version.bind",},
 
295
                { fingerprint => ".+", state => "q0r4q1r21q2r?", },]
 
296
          },
 
297
          { fingerprint => ".+", state => "q0r4q1r?", }, ]
 
298
    },
 
299
 
 
300
    { fingerprint => $iq[5], header => $qy[1], ruleset => [
 
301
          { fingerprint => $iq[11], result => { vendor => "ISC", product => "BIND", version => "9.2.3rc1 -- 9.4.0a0", option => "recursion enabled,split view" }, qv => "version.bind",},
 
302
          { fingerprint => $iq[17], result => {vendor => "ISC", product =>"BIND", version => "9.2.3rc1 -- 9.4.0a0 [recursion enabled]"}, qv => "version.bind",},
 
303
          { fingerprint => $iq[18], header => $qy[5], ruleset => [
 
304
                { fingerprint => $iq[5], header => $qy[7], query  => ". IN A", ruleset => [
 
305
                     { fingerprint => $iq[84], result => {vendor => "Nominum", product =>"CNS", version => ""}, qv => "version.bind",},
 
306
                     { fingerprint => $iq[59], result => {vendor => "Mikrotik", product =>"dsl/cable", version => ""}, },
 
307
                     { fingerprint => $iq[82], result => {vendor => "Mikrotik", product =>"dsl/cable", version => ""}, },
 
308
                     { fingerprint => ".+", state => "q0r5q1r18q5r5q7r?", }, ]
 
309
                },
 
310
                { fingerprint => $iq[64], result => "unknown, smells like old BIND 4", },
 
311
                { fingerprint => ".+", state => "q0r5q1r18q5r?", }, ]
 
312
          }, 
 
313
          { fingerprint => $iq[20], header => $qy[7], ruleset => [
 
314
                { fingerprint => $iq[54], result => {vendor => "ISC", product =>"BIND", version => "9.0.0b5 -- 9.0.1 [recursion enabled]"}, qv => "version.bind",},
 
315
                { fingerprint => $iq[55], result => {vendor => "ISC", product =>"BIND", version => "9.1.0 -- 9.1.3 [recursion enabled]"}, qv => "version.bind",},
 
316
                { fingerprint => $iq[63], result => {vendor => "ISC", product =>"BIND", version => "4.9.3 -- 4.9.11 [recursion enabled]"}, qv => "version.bind",},
 
317
                { fingerprint => $iq[61], result => {vendor => "ISC", product =>"BIND", version => "9.0.0b5 -- 9.1.3 [recursion local]"}, qv => "version.bind",},
 
318
                { fingerprint => ".+", state => "q0r5q1r20q7r?", }, ]
 
319
          },   
 
320
          { fingerprint => $iq[21], header => $qy[4], ruleset => [
 
321
                { fingerprint => "query timed out", result => {vendor => "ISC", product =>"BIND", version => "9.2.0a1 -- 9.2.2-P3 [recursion enabled]"}, qv => "version.bind", },
 
322
                { fingerprint => $iq[29], result => {vendor => "ISC", product =>"BIND", version => "9.2.0a1 -- 9.2.0rc3 [recursion enabled]"}, qv => "version.bind", },
 
323
                { fingerprint => $iq[61], header => $qy[0], query  => ". A CLASS0" , ruleset => [
 
324
                        { fingerprint => $iq[2], result => {vendor => "ISC", product =>"BIND", version => "9.2.0rc7 -- 9.2.2-P3 [recursion local]"}, qv => "version.bind", },
 
325
                        { fingerprint => $iq[0], result => {vendor => "ISC", product =>"BIND", version => "9.2.0a1 -- 9.2.0rc6 [recursion local]"}, qv => "version.bind", },
 
326
                        { fingerprint => ".+", result => {vendor => "ISC", product =>"BIND", version => "9.2.0a1 -- 9.2.2-P3 [recursion local]"}, qv => "version.bind", }, ]
 
327
                },
 
328
                { fingerprint => $iq[30], header => $qy[0], query  => ". A CLASS0" , ruleset => [
 
329
                        { fingerprint => $iq[2], result => {vendor => "ISC", product =>"BIND", version => "9.2.0rc7 -- 9.2.2-P3 [recursion enabled]"}, qv => "version.bind", },
 
330
                        { fingerprint => $iq[0], result => {vendor => "ISC", product =>"BIND", version => "9.2.0rc4 -- 9.2.0rc6 [recursion enabled]"}, qv => "version.bind", },
 
331
                        { fingerprint => ".+", result => {vendor => "ISC", product =>"BIND", version => "9.2.0rc4 -- 9.2.2-P3 [recursion enabled]"}, qv => "version.bind", }, ] 
 
332
                },
 
333
                { fingerprint => ".+", state => "q0r5q1r21q4r?", }, ]
 
334
          }, 
 
335
          { fingerprint => ".+", state => "q0r5q1r?", }, ]
 
336
    },
 
337
         
 
338
    { fingerprint => $iq[6], header => $qy[1], ruleset => [
 
339
          { fingerprint => $iq[15], result => {vendor => "incognito", product =>"DNS commander", version => "v2.3.1.1 -- 4.0.5.1"}, qv => "version.bind",  },
 
340
          { fingerprint => $iq[19], header => $qy[3], ruleset => [
 
341
                { fingerprint => $iq[66], result => {vendor => "vermicelli", product =>"totd", version => ""}, },
 
342
                { fingerprint => $iq[67], result => {vendor => "JHSOFT", product =>"simple DNS plus", version => "[recursion enabled]"}, }, 
 
343
                { fingerprint => ".+", state => "q0r6q1r19q3r?", }, ]
 
344
          },
 
345
          { fingerprint => ".+", state => "q0r6q1r?", }, ]
 
346
    },
 
347
    
 
348
    { fingerprint => $iq[7], header => $qy[1], ruleset => [
 
349
          { fingerprint => $iq[22], result => {vendor => "PowerDNS", product =>"PowerDNS", version => "2.9.4 -- 2.9.11"}, qv => "version.bind", },
 
350
          { fingerprint => $iq[24], result => {vendor => "PowerDNS", product =>"PowerDNS", version => "2.8 -- 2.9.3"}, qv => "version.bind", },
 
351
          { fingerprint => ".+", state => "q0r7q1r?", }, ]
 
352
    },
 
353
 
 
354
    { fingerprint => $iq[8], header => $qy[1], ruleset => [
 
355
          { fingerprint => $iq[23], header => $qy[2] , query => ". CH A", ruleset => [
 
356
                { fingerprint => "query timed out", result => { vendor => "DJ Bernstein", product => "TinyDNS", version => "1.04"} ,},
 
357
                { fingerprint => $iq[32], result => {vendor => "DJ Bernstein", product => "TinyDNS", version => "1.05"} ,}, 
 
358
                { fingerprint => ".+", state => "q0r8q1r23q2r?",},]
 
359
          },
 
360
          { fingerprint => ".+", state => "q0r8q1r?", }, ]
 
361
    },
 
362
    
 
363
    { fingerprint => $iq[9], header => $qy[1], ruleset => [
 
364
          { fingerprint => $iq[9], result => { vendor => "Sam Trenholme", product =>"MaraDNS", version => ""}, qv => "erre-con-erre-cigarro.maradns.org"}, 
 
365
          { fingerprint => ".+", state => "q0r9q1r?", }, ]
 
366
    },
 
367
 
 
368
    { fingerprint => $iq[10], result => { vendor => "Microsoft", product =>"?", version => ""}, },
 
369
    { fingerprint => $iq[26], result => { vendor => "Meilof Veeningen", product =>"Posadis", version =>""}, },
 
370
    { fingerprint => $iq[43], header => $qy[6], ruleset => [
 
371
                { fingerprint => $iq[34], result => { vendor => "Paul Rombouts", product =>"pdnsd", version =>""}, },
 
372
                { fingerprint => $iq[75], result => { vendor => "antirez", product =>"Yaku-NS", version =>""}, },
 
373
                { fingerprint => ".+", state => "q0r43q6r?", }, ]
 
374
    },
 
375
 
 
376
    { fingerprint => $iq[44], result => { vendor =>"cpan", product=>"Net::DNS Nameserver", version =>""}, qv => "version.bind", },
 
377
    { fingerprint => $iq[52], result => { vendor =>"NLnetLabs", product=>"NSD", version => "1.0 alpha"}, },
 
378
    { fingerprint => $iq[55], result => { vendor =>"robtex", product=>"Viking DNS module", version=>""}, },
 
379
    { fingerprint => $iq[59], result => { vendor =>"Max Feoktistov", product=>"small HTTP server [recursion enabled]", version =>""}, },
 
380
    { fingerprint => $iq[60], result => { vendor =>"Axis", product=>"video server", version =>""}, },
 
381
    { fingerprint => $iq[62], header => $qy[7], query => "1.0.0.127.in-addr.arpa. IN PTR", ruleset => [
 
382
                { fingerprint => $iq[62], result => { vendor =>"Michael Tokarev", product=>"rbldnsd",version=>""}, qv => "version.bind", },
 
383
                { fingerprint => $iq[79], result => { vendor =>"4D", product=>"WebSTAR", version=>""}, },
 
384
                { fingerprint => $iq[83], result => { vendor =>"Netopia", product =>"dsl/cable", version => ""},},
 
385
                { fingerprint => $iq[90], result => { vendor =>"TZO", product=>"Tzolkin DNS",version=>""}, },
 
386
                { fingerprint => "query timed out", result => { vendor =>"Netopia", product =>"dsl/cable", version=>""},},
 
387
                { fingerprint => ".+", state => "q0r62q7r?", }, ]
 
388
    },
 
389
    { fingerprint => $iq[70], result => { vendor =>"Yutaka Sato", product=>"DeleGate DNS", version=>""},},
 
390
    { fingerprint => $iq[72], result => { vendor =>"", product =>"sheerdns", version=>""}, },
 
391
    { fingerprint => $iq[73], result => { vendor =>"Matthew Pratt", product=>"dproxy", version=>""}, },
 
392
    { fingerprint => $iq[74], result => { vendor =>"Brad Garcia", product=>"dnrd",version=>""}, },
 
393
    { fingerprint => $iq[76], result => { vendor =>"Sourceforge", product=>"JDNSS",version=>""}, },
 
394
    { fingerprint => $iq[77], result => { vendor =>"Dan Kaminsky", product=>"nomde DNS tunnel",version=>""}, },
 
395
    { fingerprint => $iq[78], result => { vendor =>"Max Feoktistov", product=>"small HTTP server", version =>""}, },
 
396
    { fingerprint => $iq[79], result => { vendor =>"robtex", product=>"Viking DNS module", version=>""}, },
 
397
    { fingerprint => $iq[80], result => { vendor =>"Fasthosts", product=>"Envisage DNS server", version=>""}, },
 
398
    { fingerprint => $iq[81], result => { vendor =>"WinGate", product=>"Wingate DNS", version=>""},},
 
399
    { fingerprint => $iq[82], result => { vendor =>"Ascenvision", product=>"SwiftDNS", version=>""},},
 
400
    { fingerprint => $iq[86], result => { vendor =>"Nortel Networks", product=>"Instant Internet",version=>""}, },
 
401
    { fingerprint => $iq[87], result => { vendor =>"ATOS", product=>"Stargate ADSL", version=>""},},
 
402
    { fingerprint => $iq[88], result => { vendor =>"3Com", product=>"Office Connect Remote", version=>""},},
 
403
    { fingerprint => $iq[89], result => { vendor =>"Alteon", product=>"ACEswitch", version=>""},},
 
404
    { fingerprint => $iq[90], result => { vendor =>"javaprofessionals", product=>"javadns/jdns", version=>""},},
 
405
 
 
406
    { fingerprint => $iq[92], result => { vendor =>"Beehive", product=>"CoDoNS",version=>""}, },
 
407
    { fingerprint => ".+", state => "q0r?", }, 
 
408
 
 
409
);
 
410
 
 
411
######################################################################
 
412
 
 
413
sub new
 
414
{
 
415
    my $proto = shift;
 
416
    my $class = ref($proto) || $proto;
 
417
    my $self = {};
 
418
 
 
419
    my %config = @_;
 
420
 
 
421
    foreach my $k (keys %default) {
 
422
        if (defined $config{$k}) {
 
423
            $self->{$k} = $config{$k};
 
424
        } else {
 
425
            $self->{$k} = $default{$k};
 
426
        }
 
427
    }
 
428
 
 
429
    bless $self, $class;
 
430
    return $self;
 
431
}
 
432
 
 
433
sub hash
 
434
{
 
435
    my $self = shift;
 
436
 
 
437
    my $addr = shift;
 
438
    my $port = shift;
 
439
 
 
440
    $port = 53 unless($port);
 
441
 
 
442
    return $self->init($addr, $port);
 
443
}
 
444
 
 
445
sub string
 
446
{
 
447
    my $self = shift;
 
448
 
 
449
    my $addr = shift;
 
450
    my $port = shift;
 
451
 
 
452
    $port = 53 unless($port);
 
453
 
 
454
    my %r = $self->hash($addr, $port);
 
455
 
 
456
    my @s = ();
 
457
 
 
458
    if (defined $r{error}) {
 
459
        push @s, $r{error};
 
460
    } elsif (defined $r{result}) {
 
461
        push @s, $r{result};
 
462
    } else {
 
463
        push @s, $r{vendor}  if(defined $r{vendor});
 
464
        push @s, $r{product} if(defined $r{product});
 
465
        push @s, $r{version} if(defined $r{version});
 
466
        push @s, "[$r{option}]" if(defined $r{option});
 
467
    }
 
468
 
 
469
    push @s, $r{vstring} if(defined $r{vstring});
 
470
 
 
471
    push @s, "($r{state};$r{id})" if($self->{debug});
 
472
 
 
473
    return join(" ", @s);
 
474
}
 
475
 
 
476
sub query_version
 
477
{  
 
478
    my $self = shift;
 
479
 
 
480
    my $qserver = shift;
 
481
    my $qport   = shift;
 
482
    my $ident   = shift;
 
483
 
 
484
    my $rrset = " id: ";
 
485
    my $resolver = Net::DNS::Resolver->new;
 
486
 
 
487
    $resolver->nameservers($qserver);
 
488
    $resolver->port($qport);
 
489
    $resolver->srcaddr($self->{source});
 
490
    $resolver->retry($self->{retry});
 
491
    $resolver->retrans($self->{timeout});
 
492
    $resolver->usevc($self->{forcetcp});
 
493
    my $query = $resolver->query($ident, 'TXT', 'CH');
 
494
 
 
495
    if ($query && $query->header->ancount > 0) {
 
496
        foreach my $rr ($query->answer) {
 
497
            ($rrset = $rrset . "\"" . $rr->txtdata . "\" ") if ($rr->type eq "TXT");
 
498
        }
 
499
       $rrset =~ s/\n/\" \"/g;
 
500
       if (length($rrset) > $versionlength) {
 
501
          $rrset = substr($rrset,0,$versionlength)."..."
 
502
       }
 
503
       return $rrset;
 
504
    }
 
505
 
 
506
    return " id unavailable (".$resolver->errorstring.")";
 
507
}
 
508
 
 
509
sub init
 
510
{
 
511
    my $self = shift;
 
512
 
 
513
    my $qserver = shift;
 
514
    my $qport   = shift;
 
515
 
 
516
    return $self->process($qserver, $qport,
 
517
                          $initrule{header}, $initrule{query}, \@ruleset);
 
518
}
 
519
 
 
520
sub process
 
521
{
 
522
    my $self = shift;
 
523
 
 
524
    my $qserver = shift;
 
525
    my $qport   = shift;
 
526
    my $qheader = shift;
 
527
    my $qstring = shift;
 
528
    my $ruleref = shift;
 
529
    my $ver;
 
530
    my $id;
 
531
    my %ret;
 
532
 
 
533
    if ($self->{debug}) {
 
534
        print STDERR "==> PROCESS $qserver:$qport $qheader $qstring\n";
 
535
        print STDERR "\n";
 
536
    }
 
537
 
 
538
    my ($answer, $ress) = $self->probe($qserver, $qport,
 
539
                                       $qheader, $qstring);
 
540
 
 
541
    if ($answer) {
 
542
        $id = header2fp($answer->header);
 
543
    } else {
 
544
        $id = $ress;
 
545
    }
 
546
 
 
547
    print STDERR "==> \"$id\"\n" if ($self->{debug});
 
548
 
 
549
    for my $rule (@$ruleref) {
 
550
 
 
551
        $ver = " "; 
 
552
 
 
553
        # we must have a fingerprint
 
554
        die "missing fingerprint" unless (defined $rule->{fingerprint});
 
555
 
 
556
        # skip to next rule unless we have a matching fingerprint
 
557
        next unless ($id =~ /$rule->{fingerprint}/);
 
558
 
 
559
        # return if we have a result
 
560
        if (defined $rule->{result}) {
 
561
            if (defined $rule->{qv}) {
 
562
                $ver = $self->query_version($qserver, $qport,
 
563
                                            $rule->{qv}) if $self->{qversion};
 
564
            }
 
565
            if ($self->{qchaos}) {
 
566
                $ver = $self->query_version($qserver, $qport,
 
567
                                            "version.bind");
 
568
            }
 
569
            $ret{vstring} = $ver if($ver);
 
570
 
 
571
            if (ref($rule->{result})) {
 
572
                $ret{vendor}  = $rule->{result}{vendor};
 
573
                $ret{product} = $rule->{result}{product};
 
574
                $ret{version} = $rule->{result}{version};
 
575
                $ret{option}  = $rule->{result}{option};
 
576
            } else {            
 
577
                $ret{result} = $rule->{result};
 
578
            }
 
579
 
 
580
            return %ret;
 
581
        }
 
582
 
 
583
        # print state if no matches
 
584
        if (defined $rule->{state}) {
 
585
            $ver = $self->query_version($qserver, $qport,
 
586
                                        "hostname.bind") if $self->{qversion};
 
587
            $ret{vstring} = $ver if($ver);
 
588
 
 
589
            $ret{error} = "No match found";
 
590
            $ret{state} = $rule->{state};
 
591
            $ret{id} = $id;
 
592
 
 
593
            return %ret;
 
594
        }
 
595
 
 
596
        # update query if defined
 
597
        if (defined $rule->{query}) {
 
598
            $qstring = $rule->{query};
 
599
        }
 
600
 
 
601
        # recurse if we have a new header and a new ruleset
 
602
        if (defined $rule->{header} && defined $rule->{ruleset}) {
 
603
            return $self->process($qserver, $qport,
 
604
                                  $rule->{header}, $qstring, $rule->{ruleset});
 
605
        }
 
606
 
 
607
        die "syntax error";
 
608
    }
 
609
 
 
610
    return %ret;
 
611
}
 
612
 
 
613
sub header2fp
 
614
{
 
615
    my $header = shift;
 
616
 
 
617
    my @list = ($header->qr, 
 
618
                $header->opcode,
 
619
                $header->aa,
 
620
                $header->tc,
 
621
                $header->rd,
 
622
                $header->ra,
 
623
                $header->ad,
 
624
                $header->cd,
 
625
                $header->rcode,
 
626
                $header->qdcount,
 
627
                $header->ancount,
 
628
                $header->nscount,
 
629
                $header->arcount);
 
630
 
 
631
    return join(",", @list);
 
632
}
 
633
 
 
634
sub fp2header
 
635
{
 
636
    my @list = split(/,/, shift);
 
637
 
 
638
    my $header = Net::DNS::Header->new;
 
639
 
 
640
    $header->qr(shift @list);
 
641
    $header->opcode(shift @list);
 
642
    $header->aa(shift @list);
 
643
    $header->tc(shift @list);
 
644
    $header->rd(shift @list);
 
645
    $header->ra(shift @list);
 
646
    $header->ad(shift @list);
 
647
    $header->cd(shift @list);
 
648
    $header->rcode(shift @list);
 
649
    $header->qdcount(shift @list);
 
650
    $header->ancount(shift @list);
 
651
    $header->nscount(shift @list);
 
652
    $header->arcount(shift @list);
 
653
 
 
654
    return $header;
 
655
}
 
656
 
 
657
sub probe
 
658
{
 
659
    my $self = shift;
 
660
 
 
661
    my $qserver = shift;
 
662
    my $qport = shift;
 
663
    my $qheader = shift;
 
664
    my @qstring = split(/ /, shift);
 
665
 
 
666
    my $header = fp2header($qheader);
 
667
 
 
668
    my $packet = Net::DNS::Packet->new(\$header->data);
 
669
    $packet->push("question", Net::DNS::Question->new(@qstring));
 
670
 
 
671
    if ($self->{debug}) {
 
672
        print STDERR "==> QUERY BEGIN\n";
 
673
        print STDERR $packet->print, "\n";
 
674
        print STDERR "==> QUERY END\n";
 
675
        print STDERR "\n";
 
676
    }
 
677
 
 
678
    my $resolver =  Net::DNS::Resolver->new;
 
679
    $resolver->nameservers($qserver);
 
680
    $resolver->port($qport);
 
681
    $resolver->srcaddr($self->{source});
 
682
    $resolver->retry($self->{retry});
 
683
    $resolver->retrans($self->{timeout});
 
684
    $resolver->usevc($self->{forcetcp});
 
685
    my $answer = $resolver->send($packet);
 
686
    if ($answer && $self->{debug}) {
 
687
        print STDERR "==> ANSWER BEGIN\n";
 
688
        print STDERR $answer->string, "\n";
 
689
        print STDERR "==> ANSWER END\n";
 
690
        print STDERR "\n";
 
691
    }
 
692
 
 
693
    return ($answer, $resolver->errorstring);
 
694
}
 
695
 
 
696
sub version
 
697
{
 
698
    return $VERSION;
 
699
}
 
700
 
 
701
1;