File Coverage

blib/lib/Net/Domain/Info/Whois.pm
Criterion Covered Total %
statement 18 55 32.7
branch 0 14 0.0
condition 0 6 0.0
subroutine 4 6 66.6
pod 1 2 50.0
total 23 83 27.7


line stmt bran cond sub pod time code
1             package Net::Domain::Info::Whois;
2              
3 3     3   2659 use Class::Easy;
  3         6  
  3         23  
4              
5 3     3   3553 use Net::Whois::Raw ();
  3         251005  
  3         79  
6 3     3   3151 use Net::Domain::ExpireDate ();
  3         68862  
  3         2964  
7              
8             sub _init {
9 3     3   10 my $class = shift;
10 3         7 my $parent = shift;
11            
12 3         19 make_accessor ($parent, 'fetch_whois', default => \&fetch_whois);
13 3         144 make_accessor ($parent, 'raw_whois');
14 3         214 make_accessor ($parent, 'created');
15 3         153 make_accessor ($parent, 'expires');
16 3         144 make_accessor ($parent, 'contacts');
17 3         74 make_accessor ($parent, 'whois_failed', is => 'rw');
18 3         85 make_accessor ($parent, 'whois_defined', is => 'rw');
19             }
20              
21             sub fetch_whois {
22 0     0 1   my $self = shift;
23            
24 0           my $domain = $self->name;
25            
26 0           $Net::Whois::Raw::CHECK_FAIL = 2;
27 0           $Net::Whois::Raw::CHECK_EXCEED = 1;
28            
29 0           my $whois;
30 0           eval {
31 0 0         $whois = $self->{raw_whois} = Net::Whois::Raw::whois (
32             $domain, undef, $domain =~ /\.(?:com|net|org)$/i ? 'QRY_FIRST' : undef
33             );
34             };
35            
36 0 0         if ($@) {
37 0           $self->whois_failed (1); # who knows? rate limit? connection failed?
38 0           return;
39             }
40            
41 0           $self->whois_failed (0);
42            
43 0 0         if (! defined $whois) {
44 0           $self->whois_defined (0);
45 0           return;
46             }
47            
48 0           $self->whois_defined (1);
49            
50 0           my $tld = ($domain =~ /.*\.(\w+)/)[0];
51            
52 0           my ($creation, $expiration)
53             = Net::Domain::ExpireDate::domdates_int ($whois, $tld);
54            
55 0 0         $self->{created} = $creation->ymd
56             if defined $creation;
57 0 0         $self->{expires} = $expiration->ymd
58             if defined $expiration;
59            
60             # debug "$domain: created: $creation expires: $expiration";
61            
62 0           $self->{contacts} = [];
63            
64 0           my $emails = find_emails ($whois);
65            
66 0 0 0       if (!scalar keys %$emails and $domain =~ /\.(?:com|net|org)$/i) {
67 0           eval {
68 0           $whois = Net::Whois::Raw::whois (
69             $domain, undef, 'QRY_LAST'
70             );
71            
72 0 0 0       if (defined $whois and $whois ne $self->{raw_whois}) {
73 0           $self->{raw_whois} .= $whois;
74 0           $emails = find_emails ($whois);
75             }
76             };
77             }
78            
79 0           foreach (keys %$emails) {
80 0           push @{$self->{contacts}}, {proto => 'email', address => $_};
  0            
81             }
82             }
83              
84             # Regular expression built using Jeffrey Friedl's example in
85             # _Mastering Regular Expressions_ (http://www.ora.com/catalog/regexp/).
86              
87             my $RFC822PAT = <<'EOF';
88             [\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\
89             xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xf
90             f\n\015()]*)*\)[\040\t]*)*(?:(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\x
91             ff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|"[^\\\x80-\xff\n\015
92             "]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015"]*)*")[\040\t]*(?:\([^\\\x80-\
93             xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80
94             -\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*
95             )*(?:\.[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\
96             \\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\
97             x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x8
98             0-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|"[^\\\x80-\xff\n
99             \015"]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015"]*)*")[\040\t]*(?:\([^\\\x
100             80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^
101             \x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040
102             \t]*)*)*@[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([
103             ^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\
104             \\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\
105             x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-
106             \xff\n\015\[\]]|\\[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()
107             ]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\
108             x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:\.[\04
109             0\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\
110             n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\
111             015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?!
112             [^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\
113             ]]|\\[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\
114             x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\01
115             5()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*)*|(?:[^(\040)<>@,;:".
116             \\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]
117             )|"[^\\\x80-\xff\n\015"]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015"]*)*")[^
118             ()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037]*(?:(?:\([^\\\x80-\xff\n\0
119             15()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][
120             ^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)|"[^\\\x80-\xff\
121             n\015"]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015"]*)*")[^()<>@,;:".\\\[\]\
122             x80-\xff\000-\010\012-\037]*)*<[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?
123             :(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-
124             \xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:@[\040\t]*
125             (?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015
126             ()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()
127             ]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\0
128             40)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\
129             [^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\
130             xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*
131             )*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:\.[\040\t]*(?:\([^\\\x80
132             -\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x
133             80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t
134             ]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\
135             \[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff])
136             *\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x
137             80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80
138             -\xff\n\015()]*)*\)[\040\t]*)*)*(?:,[\040\t]*(?:\([^\\\x80-\xff\n\015(
139             )]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\
140             \x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*@[\040\t
141             ]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\0
142             15()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015
143             ()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(
144             \040)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|
145             \\[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80
146             -\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()
147             ]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:\.[\040\t]*(?:\([^\\\x
148             80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^
149             \x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040
150             \t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".
151             \\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff
152             ])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\
153             \x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x
154             80-\xff\n\015()]*)*\)[\040\t]*)*)*)*:[\040\t]*(?:\([^\\\x80-\xff\n\015
155             ()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\
156             \\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*)?(?:[^
157             (\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-
158             \037\x80-\xff])|"[^\\\x80-\xff\n\015"]*(?:\\[^\x80-\xff][^\\\x80-\xff\
159             n\015"]*)*")[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|
160             \([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))
161             [^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:\.[\040\t]*(?:\([^\\\x80-\xff
162             \n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\x
163             ff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(
164             ?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\
165             000-\037\x80-\xff])|"[^\\\x80-\xff\n\015"]*(?:\\[^\x80-\xff][^\\\x80-\
166             xff\n\015"]*)*")[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\x
167             ff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)
168             *\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*)*@[\040\t]*(?:\([^\\\x80-\x
169             ff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-
170             \xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)
171             *(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\
172             ]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff])*\]
173             )[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-
174             \xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\x
175             ff\n\015()]*)*\)[\040\t]*)*(?:\.[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(
176             ?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80
177             -\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<
178             >@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x8
179             0-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff])*\])[\040\t]*(?:
180             \([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]
181             *(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)
182             *\)[\040\t]*)*)*>)
183             EOF
184              
185             $RFC822PAT =~ s/\n//g;
186              
187             sub find_emails {
188 0     0 0   my $text = shift;
189              
190 0           my %emails;
191            
192 0           while ($text =~ /($RFC822PAT)/gso) {
193 0           my $email = $1;
194 0           $email =~ s/\s+//g;
195 0           $emails{$email} = 1;
196             }
197            
198 0           return \%emails;
199             }
200              
201             1;
202              
203             =head1 NAME
204              
205             Net::Domain::Info::Whois - Net::Domain::Info plugin for requesting whois information
206              
207             =head1 SYNOPSIS
208              
209             This module provides Whois data fetch and simple parsing (currently only
210             create/expire dates and email information)
211              
212             use Net::Domain::Info qw(::Whois); # used Whois plugin
213              
214             Net::Domain::Info->new ($domain);
215              
216             $domain_info->fetch_whois;
217              
218             $domain_info->created;
219             $domain_info->expires;
220              
221             $domain_info->contacts;
222              
223             =head1 METHODS
224              
225             =head2 fetch_whois
226              
227             Fetches Whois and stores Whois information in the object. Then parses
228             "create" and "expire" dates for domain and tries to fetch email addresses.
229             When no address is found, tries to receive the last Whois in the chain
230             and searches for addresses again.
231              
232             =cut
233              
234             =head2 created
235              
236             Accessor for domain record creation date.
237              
238             =cut
239              
240             =head2 expires
241              
242             Accessor for domain record expiration date.
243              
244             =cut
245              
246             =head2 contacts
247              
248             Returns arrayref of contacts with prototypes. Currently
249             only "e–mail" prototype ia supported. In the future support
250             for phone and people contacts is planned.
251              
252             =cut
253              
254             =head2 whois_failed
255              
256             Returns status of Whois fetch. As example, you can receive undefined
257             Whois data. This can happen because server failed, or you exceeded rate
258             limit, or domain does not exist. whois_failed flag is set only when
259             something is wrong with Whois server and you can (and must!) recheck
260             Whois later.
261              
262             =cut
263              
264             =head1 AUTHOR
265              
266             Ivan Baktsheev, C<< >>
267              
268             =head1 BUGS
269              
270             Please report any bugs or feature requests to my email address,
271             or through the web interface at L.
272             I will be notified, and then you'll automatically be notified
273             of progress on your bug as I make changes.
274              
275             =head1 SUPPORT
276              
277              
278              
279             =head1 ACKNOWLEDGEMENTS
280              
281              
282              
283             =head1 COPYRIGHT & LICENSE
284              
285             Copyright 2008 Ivan Baktsheev
286              
287             This program is free software; you can redistribute it and/or modify it
288             under the same terms as Perl itself.
289              
290              
291             =cut