File Coverage

blib/lib/Net/DLookup.pm
Criterion Covered Total %
statement 41 167 24.5
branch 12 90 13.3
condition 4 33 12.1
subroutine 7 12 58.3
pod 0 5 0.0
total 64 307 20.8


line stmt bran cond sub pod time code
1             package Net::DLookup;
2              
3             =head1 NAME
4              
5             Net::DLookup - Perform domain lookups on 2-letter and 3-letter TLDs
6              
7             =head1 SYNOPSIS
8              
9             use Net::DLookup;
10              
11             # Initialize Net::DLookup object
12             my $dlu = Net::DLookup -> new;
13              
14             # Replace domain definitions from a file
15             $dlu -> LoadTLD($file, 1);
16              
17             # Add domain definitions from a file
18             $dlu -> LoadTLD($file, 0);
19              
20             # Check domain name validity and assign it to the object
21             @errors = $dlu -> IsValid($domain);
22              
23             # Return availability
24             @response = $dlu -> DoWhois(0);
25              
26             # Return availability and registrar information
27             @response = $dlu -> DoWhois(1);
28              
29              
30             =head1 DESCRIPTION
31              
32             Net::DLookup performs domain lookups for 2-letter and 3-letter top level domains. It also verifies the validity of
33             domain names by checking punctuation, length, metacharacters, etc..
34              
35             Information for currently recognized top level domains is included within the module. This list may be replaced or
36             added to by calling $dlu->LoadTLD().
37              
38             With the advent of new registrars for 3-letter top level domains, it's become difficult to get the
39             whois output from a single domain lookup, unless you know what registration agency to look at. Net::DLookup solves
40             this problem by checking Internic's database first and then performing a second query to the respective registrar
41             for full whois output.
42              
43              
44             =head1 USAGE
45              
46             These functions must be used in order:
47              
48             Of course:
49              
50             use Net::DLookup;
51              
52             Create an object that contains the default top level domains.
53              
54             my $dlu = Net::DLookup -> new;
55              
56             Validate domain name ($domaintocheck) and associate it with the object.
57             This must be the full domain name, such as yourdomain.com.
58              
59             my @errors = $dlu -> IsValid($domaintocheck);
60              
61             It checks for the following possible errors:
62              
63             =over 4
64              
65             =item Is 67 characters or less for 3-letter TLDs
66              
67             =item Is not a 3rd level domain for 3-letter TLDs (me.yourdomain.com)
68              
69             =item Is 26 characters or less for 2-letter TLDs
70              
71             =item Is not a 4th level domain for 2-letter TLDs (me.yourdomain.co.uk)
72              
73             =item Does not start or end with a non-alphanumeric character
74              
75             =item Does not contain non alphanumeric characters (except a dash) within the domain name
76              
77             =item Is a valid TLD*
78              
79             =back
80              
81             * All CCTLDs (Country Code TLDs) currently listed at IANA as well as the .com, .net, .org, .edu and .mil are checked
82              
83             @errors will contain a list of all possible errors that the domain name may have, such as:
84              
85             =over 4
86              
87             =item Domain name can't start or end with non-alphanumeric character.
88              
89             =item Domains with the .com extension cannot exceed 67 characters.
90              
91             =back
92              
93             Last, the domain lookup.
94              
95             @response = $domain->Net::DLookup::DoWhois();
96              
97             =over 4 @response will contain (in order)
98              
99             =item Is domain registered? 1 for yes; 0 for no
100              
101             =item Name of Registration Agency or Country
102              
103             =item URL of Registration Agency for TLD
104              
105             =item Whois Server for TLD
106              
107             =item Whois Output
108              
109             =item A "worded" reponse for domain availability "{domain} is available"
110              
111             =back
112              
113             If you're looking up a 3-letter TLD domain (.com, .net, .org, .edu and .mil), you have the choice to NOT perform
114             the second lookup. This would be useful if you're just checking for domain availability and don't care who's
115             already registered it. You can disable the second lookup by removing the 1. This will give you Internic's
116             plain Jane, uninformative whois information.
117              
118             @response = $domain->Net::DLookup::DoWhois(1);
119              
120             =cut
121              
122              
123             =head1 RESTRICTIONS
124              
125             Net::DLookup requires that the Sockets (included with the Perl distribution) module is installed.
126              
127             =head1 VERSION
128              
129             Net::DLookup Version 1.01 6/10/2000
130              
131             =head1 CAVEATS
132              
133             Registration agencies are finicky beasts. They may change their whois server, urls, or responses (that this module
134             relies on) without notice. As of 6/10/2000, the agency data in the module is accurate.
135              
136             =head1 CREDITS
137              
138             Many thanks goes to Michael Chase for the new LoadTLD() and DumpTLD() routines.
139              
140             =head1 AUTHOR
141              
142             D. Jasmine Merced , CPAN ID: DJASMINE
143              
144             The Perl Archive
145              
146             =head1 COPYRIGHT
147              
148             This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
149             If you make modifications, the author would like to know so that they can be incorporated into future releases.
150              
151             =cut
152              
153              
154 1     1   6149 use strict;
  1         2  
  1         66  
155 1     1   6 use vars qw( $VERSION %_tld_data );
  1         2  
  1         78  
156             $VERSION = '1.01';
157              
158 1     1   6 use Exporter;
  1         4  
  1         2312  
159             my @ISA = qw( Exporter );
160              
161             # Initialize class level data
162             my ( $MAX2TLD, $MAX3TLD, @ERRORS ) = ( 26, 67 );
163              
164             sub new {
165 1   33 1 0 71 my $class = ref $_[0] || $_[0];
166              
167 1         14 my $dlu = bless {
168             _TLD_DATA => undef,
169              
170             _FULLDOMAIN => $_[1],
171             _NAME => undef,
172             _TLD => undef,
173             _NATION => undef,
174              
175             _ISVALID => undef,
176             _RESPONSE => undef,
177             _WHOISOUTPUT => undef,
178             _ISREGISTERED => undef,
179              
180             _TLDNAME => undef,
181             _TLDURL => undef,
182             _TLDMATCHRESP => undef,
183             _TLDQUERYDB => undef,
184              
185             ERROR => undef,
186              
187             }, $class;
188              
189 1         15 $dlu -> LoadTLD( $_[1], 1 );
190 1         11 return $dlu;
191             }
192              
193             sub LoadTLD {
194 2     2 0 5 my ( $dlu, $file, $clear ) = @_;
195 2         4 my $oldfile = '';
196 2         3 my ( $TLD, $URL, $QUERYDB, $MATCHRESP, $NAME );
197              
198 2 50 33     15 $dlu -> {_TLD_DATA} = {} if $clear || ! $dlu -> {_TLD_DATA};
199              
200 2 100       6 if ( $file ) {
201 1 50       11 if ( ! ref $file ) {
202 0 0       0 open( FILE, "<$file" ) or die "Can't read from $file, $!";
203 0         0 $oldfile = $file;
204 0         0 $file = \*FILE;
205             }
206 1         584 while ( <$file> ) {
207 413         2523 s/\s+$//;
208 413 100 66     18094 next if '' eq $_ || /^\s*#/;
209 411         2122 ( $TLD, $URL, $QUERYDB, $MATCHRESP, $NAME ) = split(/\t/,$_);
210 411         864 foreach ( $TLD, $URL, $QUERYDB, $MATCHRESP, $NAME ) {
211 2055 100       11130 $_ = '' if ! defined $_;
212             }
213 411         1118 ${$dlu -> {_TLD_DATA}}{$TLD} = [ $URL, $QUERYDB, $MATCHRESP, $NAME ];
  411         7746  
214             }
215 1 50       8 close $file if $oldfile;
216             }
217 2 100       4 if ( ! keys %{$dlu -> {_TLD_DATA}} ) {
  2         10  
218 1         3 my $start = tell DATA;
219 1         6 $dlu -> LoadTLD( \*DATA, 1 );
220 1         10 seek DATA, $start, 0;
221             }
222             }
223              
224             sub DumpTLD {
225 0     0 0 0 my ( $dlu, $file ) = @_;
226 0 0 0     0 return if ! $file || ! $dlu -> {_TLD_DATA};
227 0         0 my ( $oldfile, $TLD, $line, @dom );
228              
229 0 0       0 if ( ! ref $file ) {
230 0 0       0 open( FILE, ">$file" ) or die "Can't write to $file, $!";
231 0         0 $oldfile = $file;
232 0         0 $file = \*FILE;
233             }
234 0         0 foreach $TLD (
  0         0  
235             # Sort domains by most general part first
236 0         0 map { @dom = split /\t/, $_; join ".", reverse @dom }
  0         0  
237             sort
238 0         0 map { @dom = split /\./, $_; join "\t", reverse @dom }
  0         0  
239             keys %{$dlu -> {_TLD_DATA}}
240             ){
241 0         0 $line = join "\t", $TLD, @{$dlu -> {_TLD_DATA}{$TLD}};
  0         0  
242 0         0 $line =~ s/\s+$//;
243 0         0 print $file "$line\n";
244             }
245 0 0       0 close $file if $oldfile;
246             }
247              
248              
249             sub IsValid {
250 1     1 0 10 my ($self,$domain) = @_;
251 1         3 @ERRORS = ();
252 1 50       5 unless ($domain){
253 1         3 push(@ERRORS,"Error. No domain has been entered.\n");
254             }
255             else {
256 0         0 $self->{_FULLDOMAIN} = $domain;
257 0         0 my @DOMAIN = ();
258 0         0 @DOMAIN = split(/\./,$self->{_FULLDOMAIN});
259 0         0 my @REVERSED = reverse @DOMAIN;
260              
261 0 0       0 if($DOMAIN[3]){
    0          
262 0         0 push(@ERRORS,"Error. Fourth level domains are not acceptable.\n")
263             }
264             elsif ($DOMAIN[2]){
265 0 0       0 if(length($REVERSED[0])==2){
266 0         0 $self->{_TLD} = $REVERSED[1].'.'.$REVERSED[0];
267 0         0 $self->{_NAME} = $REVERSED[2];
268             }
269             else {
270 0         0 push(@ERRORS,"This program cannot handle 3rd level domains.\n");
271             }
272             }
273             else {
274 0         0 $self->{_TLD} = $REVERSED[0];
275 0         0 $self->{_NAME} = $REVERSED[1];
276             }
277              
278 0 0 0     0 if (($self->{_TLD})&&($self->{_NAME})){
279 0         0 _GetRegistrar($self);
280 0         0 _ValidateName($self);
281             }
282             else {
283 0         0 push(@ERRORS,"Error. Invalid domain name.\n");
284             }
285              
286             }
287 1         5 return @ERRORS;
288             }
289              
290             sub DoWhois {
291 0     0 0   my $self = shift;
292 0           my $INTERNICWHOIS = shift;
293 0           my ($ATTEMPTS,$MAXTRIES) = "";
294              
295 0 0         unless ($self->{TLDQUERYDB}){
296 0           _GetRegistrar($self);
297             }
298              
299 0 0         if ($self->{_TLDQUERYDB}){
300              
301 0           my (@RESULT) = _PerformWhois($self);
302 0           foreach(@RESULT){
303 0           $self->{_WHOISOUTPUT} .= $_;
304             }
305              
306 0           $self->{_ISREGISTERED} = 1;
307              
308 0           $self->{_RESPONSE} = "$self->{_FULLDOMAIN} is already registered.\n";
309              
310 0 0         if ($self->{_WHOISOUTPUT} =~ /$self->{_TLDMATCHRESP}/mig){
    0          
    0          
311 0           $self->{_ISREGISTERED} = 0;
312 0           $self->{_RESPONSE} = "$self->{_FULLDOMAIN} is available for registration.";
313             }
314             elsif ($self->{_WHOISOUTPUT} =~ /^\*/mig) {
315 0           $ATTEMPTS++;
316 0           sleep(1);
317 0 0         if ($ATTEMPTS > $MAXTRIES) {
318 0           $self->{_RESPONSE} = "Internic's Whois database is unavailable.";
319             }
320             }
321             elsif ($self->{_RESPONSE} =~ /$!/g) {
322 0           $self->{_RESPONSE} = "Could not connect to whois server $self->{_TLDQUERYDB}: $!";
323             }
324              
325 0 0 0       if (($self->{_ISREGISTERED}==1)&&(length($self->{_TLD})==3)){
326 0           foreach(@RESULT){
327 0           chomp;
328 0 0         if (/Registrar: /){
329 0           $self->{_TLDNAME} = (split(/Registrar: /,$_))[1];
330             }
331 0 0         if (/Whois Server\: /){
332 0           $self->{_TLDQUERYDB} = (split(/Whois Server: /,$_))[1];
333             }
334 0 0         if (/Referral URL: /){
335 0           $self->{_TLDURL} = (split(/Referral URL: /,$_))[1];
336             }
337             }
338             }
339 0 0         if($INTERNICWHOIS){
340 0           @RESULT = _PerformWhois($self);
341 0 0         if (@RESULT){$self->{_WHOISOUTPUT}=undef;}
  0            
342 0           foreach(@RESULT){
343 0           $self->{_WHOISOUTPUT} .= $_;
344             }
345             }
346             }
347             else {
348 0           $self->{_RESPONSE} = "$self->{_TLD} does not have a whois server to look up. ";
349 0 0         $self->{_RESPONSE} .= "More information can be found at $self->{_TLDURL}" if $self->{_TLDURL};
350             }
351              
352 0           return ($self->{_ISREGISTERED},$self->{_TLDNAME},$self->{_TLDURL},$self->{_TLDQUERYDB},$self->{_WHOISOUTPUT},$self->{_RESPONSE},$self->{_TLD});
353             }
354              
355             sub _ValidateName {
356 0     0     my $self = shift;
357              
358 0           my $tldlength = length($self->{_TLD});
359 0           my $domlength = length($self->{_FULLDOMAIN});
360 0           my $strip_dashes = $self->{_NAME};
361 0           my $temptest = $self->{_TLD};
362 0           my @tippytoptld = split(/\./,$self->{_TLD});
363              
364 0 0         unless($tippytoptld[1]){
365 0           $tippytoptld[1] = $tippytoptld[0];
366             }
367              
368 0           $strip_dashes =~ s/(-||\.)//g;
369              
370             # Check TLD length
371 0 0 0       if (($tldlength > 6)||($tldlength <2)){
372 0           push(@ERRORS,"Invalid TLD.\n")
373             }
374              
375             # Check fully qualified domain name length
376 0 0 0       if ((length($tippytoptld[1]) == 2)&&($domlength > $MAX2TLD)){
    0 0        
377 0           push(@ERRORS,"Domains with the $self->{_TLD} extension cannot exceed $MAX2TLD characters.\n");
378             }
379             elsif ((length($tippytoptld[1]) == 3)&&($domlength > $MAX3TLD)){
380 0           push(@ERRORS,"Domains with the $self->{_TLD} extension cannot exceed $MAX3TLD characters.\n");
381             }
382              
383             # Check dash placement
384 0 0 0       if (($self->{_NAME} =~ /^\W/)||($self->{_NAME} =~ /\W$/)){
385 0           push(@ERRORS,"Domain name can't start or end with non-alphanumeric character.\n");
386             }
387              
388             # Check for invalid characters
389 0 0         if ($strip_dashes =~ /\W/){
390 0           push(@ERRORS,"Invalid characters in domain name $strip_dashes.\n");
391             }
392              
393             }
394              
395              
396             sub _GetRegistrar {
397 0     0     my $self = shift;
398              
399 0 0         $self -> LoadTLD( '', 1 ) if ! keys %{$self -> {_TLD_DATA}};
  0            
400              
401 0           my $TLD = '';
402 0 0 0       if ( exists $self -> {_TLD_DATA}{$self -> {_TLD}} ) {
    0          
403 0           $TLD = $self -> {_TLD};
404             }
405             elsif ( exists $self -> {_NATION} &&
406             exists $self -> {_TLD_DATA}{$self -> {_NATION}} ) {
407 0           $TLD = $self -> {_NATION};
408             }
409              
410 0 0         if ( $TLD ) {
411 0           my ( $URL, $QUERYDB, $MATCHRESP, $NAME ) = @{$self -> {_TLD_DATA}{$TLD}};
  0            
412 0           $self -> {_TLDNAME} = $NAME;
413 0           $self -> {_TLDURL} = $URL;
414 0           $self -> {_TLDMATCHRESP} = $MATCHRESP;
415 0           $self -> {_TLDQUERYDB} = $QUERYDB;
416             }
417              
418 0 0         unless ($self->{_TLDNAME}){
419 0           push @ERRORS, ".$self->{_TLD} is not a valid top level domain.\n";
420             }
421              
422             }
423              
424             sub _PerformWhois {
425 0     0     my $self = shift;
426 0           my(@RESULT,$SIN,$LEN,$OFFSET,$WRITTEN,$BUFFER) = "";
427 0 0         return "No whois server for $self->{_TLD}" if ! $self->{_TLDQUERYDB};
428 0           my ( $whois, $opts ) = ( $self->{_TLDQUERYDB}, '' );
429 0 0         ( $whois, $opts ) = split /\s+/, $whois, 2 if $whois =~ /\s/;
430 1     1   1411 use Socket;
  1         4535  
  1         921  
431 0 0         socket(SOCK, PF_INET, SOCK_STREAM, (getprotobyname('tcp'))[2]) || return ((""));
432              
433 0           $SIN = sockaddr_in(43, inet_aton( $whois ));
434 0 0         connect(SOCK, $SIN) || return (("$!"));
435 0           $OFFSET = 0;
436 0           $BUFFER = $self->{_FULLDOMAIN} . "$opts\r\n";
437 0           $LEN = length($BUFFER);
438 0           while($LEN) {
439 0           $WRITTEN = syswrite(SOCK,$BUFFER,$LEN,$OFFSET);
440 0           $LEN -= $WRITTEN;
441 0           $OFFSET += $WRITTEN;
442             }
443              
444 0           @RESULT=;
445 0           close(SOCK);
446 0           return @RESULT;
447             }
448              
449             1;
450              
451              
452             __DATA__