File Coverage

blib/lib/Net/Whois/RIPE.pm
Criterion Covered Total %
statement 100 109 91.7
branch 36 54 66.6
condition 8 9 88.8
subroutine 29 30 96.6
pod 18 18 100.0
total 191 220 86.8


line stmt bran cond sub pod time code
1             package Net::Whois::RIPE;
2              
3 5     5   324799 use 5.006;
  5         57  
4 5     5   27 use warnings;
  5         10  
  5         157  
5 5     5   26 use strict;
  5         10  
  5         94  
6 5     5   2229 use Net::Whois::Generic;
  5         14  
  5         184  
7 5     5   37 use IO::Socket::INET;
  5         8  
  5         58  
8 5     5   2490 use IO::Select;
  5         11  
  5         227  
9 5     5   32 use Iterator;
  5         26  
  5         366  
10              
11 5         7890 use constant { SOON => 30,
12             END_OF_OBJECT_MARK => "\n\n",
13             EOL => "\015\012",
14             QUERY_KEEPALIVE => q{-k },
15             QUERY_NON_RECURSIVE => q{-r },
16             QUERY_REFERRAL => q{-R },
17             QUERY_GROUPING => q{-G },
18             QUERY_UNFILTERED => q{-B },
19             QUERY_LIST_OBJECTS => q{-qtypes },
20             QUERY_LIST_SOURCES => q{-qsources },
21             QUERY_FETCH_TEMPLATE => q{-t%s },
22             QUERY_LIMIT_OBJECT_TYPE => q{-T%s },
23 5     5   31 };
  5         11  
24              
25             =head1 NAME
26              
27             Net::Whois::RIPE - a pure-Perl implementation of the RIPE Database client.
28              
29             =head1 VERSION
30              
31             Version 2.007003
32              
33             =cut
34              
35             our $VERSION = 2.007003;
36              
37             =head1 SYNOPSIS
38              
39             This is a complete rewrite of version 1.31 of the module, which I inherited
40             from Paul Gampe during the time I've worked for the RIPE NCC, between Nov 2007
41             and Feb 2010.
42              
43             It intends to provide a cleaner, simpler, and complete implementation of a RIPE
44             Database client.
45              
46             The usage should remain mostly the same:
47              
48             use Net::Whois::RIPE;
49              
50             my $whois = Net::Whois::RIPE->new( %options );
51             $iterator = $whois->query( 'AS333' );
52              
53             From version 2.005000 you can also use the Net::Whois::Generic interface
54             that mimics Net::Whois::Object while offering access to data from other sources
55             than RIPE (AFRINIC, APNIC)
56              
57             use Net::Whois::RIPE;
58              
59             my @objects = Net::Whois::Generic->query( 'ORG-AFNC1-AFRINIC' );
60              
61             Please see L documentation for more details
62              
63             Of course, comments are more than welcome. If you believe you can help, please
64             do not hesitate in contacting me.
65              
66             =head1 BACKWARD COMPATIBILITY
67              
68             I've choose to break backwards compatibility with older versions of the L
69             module for several different reasons. I will try to explain and justify them here, as design documentation.
70             I will also strive to provide practical solutions for porting problems, if any.
71              
72             =head2 Architecture
73              
74             The old module provided it's own L implementation. This was common
75             practice 10 years ago, when the module was initially written. I believe Perl
76             has a stable and useful standard implementation of L now, and
77             adopted it instead of maintaining my own. This allows me to reduce the
78             necessary code base without losing features.
79              
80             =head2 Query Options
81              
82             From release 2.0 onwards, L will allow almost all query
83             options understanded by the RIPE Database Server. I bumped in the lack of
84             options myself, sometimes, and I believe other programmers can also use the
85             extra features offered.
86              
87             There are nice, sane defaults provided for most of the options. This should
88             make it possible for a beginner to just ignore all options and settings and
89             still be able to make some use of the module.
90              
91             =head2 Memory Footprint
92              
93             I had the intention of reducing the memory footprint of this module when doing
94             heavy-lifting. I still don't have measurements, but that was the idea behind
95             adopting an L wrapping the L used to return results.
96              
97             =head2 Better Data Structures
98              
99             A production release of this module will be able to feed a L with
100             RPSL objects extracted from the RIPE Database and return full-fledged objects
101             containing a parsed version of the text (way more useful than a text blob, I
102             believe).
103             L (from release 2.00_010) is the first attempt toward this
104             goal.
105              
106             # You can now do
107             my @objects = Net::Whois::Object->query( 'AS333' );
108              
109             # And manipulate the object the OO ways
110             for my $object (@objects) {
111             print $object->remarks();
112             }
113              
114             =head1 METHODS
115              
116             =head2 B
117              
118             Constructor. Returns a new L object with an open connection
119             to the RIPE Database service of choice (defaulting to C).
120              
121             The C<%options> hash migth contain configuration options for the RIPE Database
122             server. Not all options provided by the RIPE Database server are suitable for
123             this implementation, but the idea is to provide everything someone can show a
124             use for. The options currently recognized are:
125              
126             =over 4
127              
128             =item B (IPv4 address or DNS name. Default is C)
129              
130             The hostname or IP address of the service to connect to
131              
132             =item B (integer, default is C<43>)
133              
134             The TCP port of the service to connect to
135              
136             =item B (integer, default is C<5>)
137              
138             The time-out (in seconds) for the TCP connection.
139              
140             =item B (boolean, default is C)
141              
142             Wherever we want (C) or not (C) to keep the connection to the
143             server open. This option implements the functionality available through RIPE
144             Database's "-k" parameter.
145              
146             =item B (boolean, default is C)
147              
148             When true, prevents the server from using the referral mechanism for domain
149             lookups, so that the RIPE Database server returns an object in the RIPE
150             Database with the exact match with the lookup argument, rather than doing a
151             referral lookup.
152              
153             =item B (boolean, default is C)
154              
155             When set to C, prevents recursion into queried objects for personal
156             information. This prevents lots of unsolicited objects from showing up on
157             queries.
158              
159             =item B (boolean, default is C)
160              
161             When C enables object grouping in server responses. There's little
162             utility to enable this option, as the objects will be parsed and returned on a
163             much reasonable format most of the time. For the brave or more knowledgeable
164             people that want to have they answers in plain text, this can help stablishing
165             a 'good' ordering for the RPSL objects returned by a query ('good' is RIPE
166             NCC's definition of 'good' in this case).
167              
168             =item B (boolean, default is C)
169              
170             When C enables unfiltered object output responses. This produces objects
171             that can be presented back to the RIPE Database for updating.
172              
173             =item B (list of valid RIPE Database object types, default is empty, meaning all types)
174              
175             Restrict the RPSL object types allowed in the response to those in the list.
176             Using this option will cause the L object to query the RIPE
177             Database for the available object types for validating the list. The response
178             will be cached for speed and bandwidth.
179              
180             =item B (boolean, default is C)
181              
182             Prevents the constructor from automatically opening a connection to the service
183             specified (conneting the socket is the default behavior). When set (C),
184             the programmer is responsible for calling C in order to stablish a
185             connection to the RIPE Database service desired.
186              
187             =back
188              
189             =cut
190              
191             {
192             my %default_options = ( hostname => 'whois.ripe.net',
193             port => '43',
194             timeout => 5,
195             keepalive => 0,
196             referral => 0,
197             recursive => 0,
198             grouping => 1,
199             unfiltered => 0,
200             types => undef,
201             disconnected => 0,
202             );
203              
204             sub new {
205 3     3 1 1723 my ( $class, %options ) = @_;
206 3         6 my %known_options;
207 3 100       46 $known_options{$_} = exists $options{$_} ? $options{$_} : $default_options{$_} foreach keys %default_options;
208              
209 3         14 my $self = bless { __options => \%known_options }, $class;
210              
211 3 100       31 $self->connect unless delete $self->{__options}{disconnected};
212 3         13 return $self;
213             }
214             }
215              
216             =head2 B
217              
218             Accessor to the hostname. Accepts an optional hostname, always return the
219             current hostname.
220              
221             =cut
222              
223             sub hostname {
224 8     8 1 395 my ( $self, $hostname ) = @_;
225 8 100       36 $self->{__options}{hostname} = $hostname if defined $hostname;
226 8         32 return $self->{__options}{hostname};
227             }
228              
229             =head2 B
230              
231             Accessor to the port. Accepts an optional port, always return the current
232             port.
233              
234             =cut
235              
236             sub port {
237 10     10 1 23 my ( $self, $port ) = @_;
238 10 100 100     53 $self->{__options}{port} = $port if defined $port && $port =~ m{^\d+$};
239 10         36 return $self->{__options}{port};
240             }
241              
242             =head2 B
243              
244             Accessor to the timeout configuration option. Accepts an optional timeout,
245             always return the current timeout.
246              
247             =cut
248              
249             sub timeout {
250 16     16 1 36 my ( $self, $timeout ) = @_;
251 16 100 100     60 $self->{__options}{timeout} = $timeout
252             if defined $timeout && $timeout =~ m{^\d+$};
253 16         88 return $self->{__options}{timeout};
254             }
255              
256             =begin UNDOCUMENTED
257              
258             =head2 B<__boolean_accessor( $self, $attribute [, $value ] )>
259              
260             Private method. Shouldn't be used from other modules.
261              
262             Generic implementation of an accessor for booleans. Receives a reference to the
263             current instance, the attribute name, and a value to be interpreted under
264             Perl's boolean rules. Sets or gets the named attribute with the given value.
265             Always returns the most up-to-date value of the attribute.
266              
267             =end UNDOCUMENTED
268              
269             =cut
270              
271             sub __boolean_accessor {
272 32     32   79 my ( $self, $attribute ) = ( shift, shift );
273 32 100       77 if ( scalar @_ == 1 ) {
274 8         14 my $value = shift;
275 8 100       23 $self->{__options}{$attribute} = $value ? 1 : 0;
276             }
277 32         136 return $self->{__options}{$attribute};
278             }
279              
280             =head2 B
281              
282             Accessor to the keepalive configuration option. Accepts an optional keepalive,
283             always return the current keepalive.
284              
285             =cut
286              
287             sub keepalive {
288 13     13 1 29 my $self = shift;
289 13         37 return $self->__boolean_accessor( 'keepalive', @_ );
290             }
291              
292             =head2 B
293              
294             Accessor to the referral configuration option. Accepts an optional referral,
295             always return the current referral.
296              
297             =cut
298              
299             sub referral {
300 6     6 1 13 my $self = shift;
301 6         14 return $self->__boolean_accessor( 'referral', @_ );
302             }
303              
304             =head2 B
305              
306             Accessor to the recursive configuration option. Accepts an optional recursive,
307             always return the current recursive.
308              
309             =cut
310              
311             sub recursive {
312 6     6 1 13 my $self = shift;
313 6         15 return $self->__boolean_accessor( 'recursive', @_ );
314             }
315              
316             =head2 B
317              
318             Accessor to the grouping configuration option. Accepts an optional grouping,
319             always return the current grouping.
320              
321             =cut
322              
323             sub grouping {
324 5     5 1 9 my $self = shift;
325 5         11 return $self->__boolean_accessor( 'grouping', @_ );
326             }
327              
328             =head2 B
329              
330             Accessor to the unfiltered configuration option.
331              
332             =cut
333              
334             sub unfiltered {
335 2     2 1 5 my $self = shift;
336 2         7 return $self->__boolean_accessor( 'unfiltered', @_ );
337             }
338              
339             =head2 B
340              
341             Initiates a connection with the current object's configuration.
342              
343             =cut
344              
345             sub connect {
346 5     5 1 15 my $self = shift;
347 5         19 my %connection = ( Proto => 'tcp',
348             Type => SOCK_STREAM,
349             PeerAddr => $self->hostname,
350             PeerPort => $self->port,
351             Timeout => $self->timeout,
352             Domain => AF_INET,
353             Multihomed => 1,
354             );
355              
356             # Create a new IO::Socket object
357 5         49 my $socket = $self->{__state}{socket} = IO::Socket::INET->new(%connection);
358 5 50       151250 die q{Can't connect to "} . $self->hostname . ':' . $self->port . qq{". Reason: [$@].\n}
359             unless defined $socket;
360              
361             # Register $socket with the IO::Select object
362 5 100       50 if ( my $ios = $self->ios ) {
363 3 50       17 $ios->add($socket) unless $ios->exists($socket);
364             } else {
365 2         11 $self->{__state}{ioselect} = IO::Select->new($socket);
366             }
367              
368             # Set RIPE Database's "keepalive" capability
369 5 50       341 $self->send(QUERY_KEEPALIVE) if $self->keepalive;
370             }
371              
372             =head2 B
373              
374             Accessor to the L object coordinating the I/O to the L
375             object used by this module to communicate with the RIPE Database Server. You
376             shouldn't use this object, but the L and L<"query( $query_string )">
377             methods instead.
378              
379             =cut
380              
381 13     13 1 60 sub ios { return $_[0]->{__state}{ioselect} }
382              
383             =head2 B
384              
385             Read-only accessor to the L object used by this module.
386              
387             =cut
388              
389 22     22 1 537 sub socket { return $_[0]->{__state}{socket} }
390              
391             =head2 B
392              
393             Sends a message to the RIPE Database server instance to which we're connected
394             to. Dies if it cannot write, or if there's no open connection to the server.
395              
396             Return C if the message could be written to the socket, C
397             otherwise.
398              
399             =cut
400              
401             sub send {
402 0     0 1 0 my ( $self, $message ) = @_;
403 0 0       0 die q{Not connected} unless $self->is_connected;
404 0 0       0 if ( $self->ios->can_write( SOON + $self->timeout ) ) {
405 0         0 $self->socket->print( $message, EOL );
406 0         0 $self->socket->flush;
407 0         0 return 1;
408             }
409 0         0 return 0;
410             }
411              
412             =head2 B
413              
414             Reconnects to the server in case we lost connection.
415              
416             =cut
417              
418             sub reconnect {
419 3     3 1 5 my $self = shift;
420 3 50       9 $self->disconnect if $self->is_connected;
421 3         10 $self->connect;
422             }
423              
424             =head2 B
425              
426             Disconnects this client from the server. This renders the client useless until
427             you call L again. This method is called by L as part of
428             an object's clean-up process.
429              
430             =cut
431              
432             sub disconnect {
433 7     7 1 1233 my $self = shift;
434 7 100       21 if ( $self->is_connected ) {
435 5         145 my $socket = $self->{__state}{socket};
436 5         32 $socket->close;
437             $self->{__state}{ioselect}->remove($socket)
438 5 50       656 if $self->{__state}{ioselect};
439 5         509 delete $self->{__state}{socket};
440             }
441             }
442              
443             =head2 B
444              
445             Returns C if this instance is connected to the RIPE Database service
446             configured.
447              
448             =cut
449              
450             sub is_connected {
451 15     15 1 1250 my $self = shift;
452 15         34 my $socket = $self->socket;
453 15 100 66     245 return UNIVERSAL::isa( $socket, 'IO::Socket' )
454             && $socket->connected ? 1 : 0;
455             }
456              
457             =head2 B
458              
459             Net::Whois::RIPE object destructor. Called by the Perl interpreter upon
460             destruction of an instance.
461              
462             =cut
463              
464             sub DESTROY {
465 3     3   1405 my $self = shift;
466 3         14 $self->disconnect;
467             }
468              
469             =head2 B
470              
471             Sends a query to the server. Returns an L object that will return one RPSL block at a time.
472              
473             =cut
474              
475             # TODO: Identify and ignore comments within the Iterator scope?
476             # TODO: Identify and rise as soon as possible "%ERROR:\d+:.+" results.
477              
478             sub query {
479 1     1 1 4 my ( $self, $query ) = @_;
480 1         3 my $parameters = "";
481 1 50       3 $parameters .= q{ } . QUERY_KEEPALIVE if $self->keepalive;
482 1 50       4 $parameters .= q{ } . QUERY_UNFILTERED if $self->unfiltered;
483 1 50       18 $parameters .= q{ } . QUERY_NON_RECURSIVE unless $self->recursive;
484 1 50       5 $parameters .= q{ } . QUERY_REFERRAL if $self->referral;
485 1         4 my $fullquery = $parameters . $query;
486 1         5 return $self->__query($fullquery);
487             }
488              
489             # Allows me to pass in queries without having all the automatic options added
490             # up to it.
491             sub __query {
492 2     2   7 my ( $self, $query ) = @_;
493 2 50       6 $self->reconnect unless $self->keepalive;
494 2 50       9 die "Not connected" unless $self->is_connected;
495              
496 2 50       49 if ( $self->ios->can_write( SOON + $self->timeout ) ) {
497 2         95 $self->socket->print( $query, EOL );
498              
499             return Iterator->new(
500             sub {
501 4     4   103 local $/ = "\n\n";
502 4 50       14 if ( $self->ios->can_read( SOON + $self->timeout ) ) {
503 4         35006 my $block = $self->socket->getline;
504 4 50       229 return $block if defined $block;
505             }
506 0         0 Iterator::is_done;
507             }
508 2         257 );
509             }
510             }
511              
512             =head2 B
513              
514             Return a list of known object types from the RIPE Database.
515              
516             RIPE currently returns 21 types (Limerik have been removed):
517             as-block as-set aut-num domain filter-set inet6num inetnum inet-rtr irt
518             key-cert mntner organisation peering-set person poem poetic-form role route
519             route6 route-set rtr-set
520              
521             Due to some strange mis-behaviour in the protocol (or documentation?) the RIPE
522             Database server won't allow a keep-alive token with this query, meaning the
523             connection will be terminated after this query.
524              
525             =cut
526              
527             sub object_types {
528 1     1 1 1244 my $self = shift;
529 1         4 my $iterator = $self->__query(QUERY_LIST_OBJECTS);
530 1         33 while ( !$iterator->is_exhausted ) {
531 2         17 my $value = $iterator->value;
532 2 100       53 return split /\s+/, $value if $value !~ /^%\s/;
533             }
534 0           return;
535             }
536              
537             =head1 AUTHOR
538              
539             Luis Motta Campos, C<< >>
540              
541             =head1 CAVEATS
542              
543             =over 4
544              
545             =item B
546              
547             There's no support for IPv6 still on this module. I'm planning to add it in a
548             future version.
549              
550             =item B
551              
552             As this is the initial alpha release, there is still some work to do in terms
553             of testing. One of the first things I must work on is to eliminate the
554             dependency on connectivity to the RIPE Database.
555              
556             =item B
557              
558             I plan to implement a drop-in replacement to the old interface soon, as an extension to this module. For now, this module just breaks compatibility with the old interface. Please read the full discussion about compatibility with older version of the L in the L section.
559              
560             =back
561              
562             =head1 BUGS
563              
564             Please report any bugs or feature requests to C
565             rt.cpan.org>, or through the web interface at
566             L. I will be
567             notified, and then you'll automatically be notified of progress on your bug as
568             I make changes.
569              
570              
571             =head1 SUPPORT
572              
573             You can find documentation for this module with the perldoc command.
574              
575             perldoc Net::Whois::RIPE
576              
577              
578             You can also look for information at:
579              
580             =over 4
581              
582             =item * RT: CPAN's request tracker
583              
584             L
585              
586             =item * AnnoCPAN: Annotated CPAN documentation
587              
588             L
589              
590             =item * CPAN Ratings
591              
592             L
593              
594             =item * Search CPAN
595              
596             L
597              
598             =back
599              
600              
601             =head1 ACKNOWLEDGEMENTS
602              
603             Thanks to Paul Gampe and Kevin Backer for writing previous versions of this
604             module;
605              
606             Thanks to Paul Gampe for allowing me to handle me the maintenance of this
607             module on CPAN;
608              
609             Thanks to RIPE NCC for allowing me to work on this during some of my office
610             hours.
611              
612             Thanks to Carlos Fuentes for the nice patch with bugfixes for version 2.00_008.
613              
614             Thanks to Moritz Lenz for all his contributions
615             Thanks to Noris Network AG for allowing him to contribute to this module.
616              
617             =head1 COPYRIGHT & LICENSE
618              
619             Copyright 2010 Luis Motta Campos, all rights reserved.
620              
621             This program is free software; you can redistribute it and/or modify it
622             under the same terms as Perl itself.
623              
624             =cut
625              
626             1;