File Coverage

blib/lib/DNS/PunyDNS.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             package DNS::PunyDNS;
2              
3 1     1   106065 use 5.006;
  1         4  
  1         47  
4 1     1   7 use strict;
  1         2  
  1         39  
5 1     1   7 use warnings;
  1         7  
  1         43  
6 1     1   8914 use LWP::UserAgent;
  1         132970  
  1         41  
7 1     1   1431 use XML::Simple;
  0            
  0            
8             use Readonly;
9              
10             =head1 NAME
11              
12             DNS::PunyDNS - Interact with your SAPO dynamic DNS entries
13              
14             =head1 VERSION
15              
16             Version 0.02
17              
18             =cut
19              
20             our $VERSION = '0.02';
21              
22             Readonly::Scalar my $BASE_URL => 'https://services.sapo.pt/PunyUrl/DNS/';
23              
24             Readonly::Scalar my $LISTDNS => 'ListDns';
25             Readonly::Scalar my $LISTDNSINFO => 'ListDnsInfo';
26             Readonly::Scalar my $GETDNSINFO => 'GetDnsInformation';
27             Readonly::Scalar my $ADDDNS => 'AddDns';
28             Readonly::Scalar my $REMOVEDNS => 'RemoveDns';
29             Readonly::Scalar my $UPDATEDNS => 'UpdateDns';
30              
31             =head1 SYNOPSIS
32              
33             This module allows you to create/remove/update your SAPO dynamic DNS entries (L).
34              
35             use DNS::PunyDNS;
36              
37             my $dns = DNS::PunyDNS->new({'username' => '', password => '' } );
38              
39             my $added = $dns->add_dns( $domain, $ip, $record_type );
40              
41             if (!$added) {
42             warn $dns->{'error'};
43             }
44             ...
45              
46              
47             =head1 METHODS
48              
49             =head2 new
50              
51             Creates a new DNS::PunyDNS object.
52              
53              
54             DNS::PunyDNS->new( { 'username' => '', 'password' => '' } )
55              
56             Your SAPO username and password must be provided.
57              
58             =head2 add_dns
59              
60             Adds a dynamic DNS entry.
61              
62             $dns->add_dns( $domain, $ip, $record_type );
63              
64             This function returns false if the operation fails, the cause of the failure is set in C<< $dns->{'error'} >>.
65              
66             =head2 update_dns
67              
68             Updates a dynamic DNS entry.
69              
70             $dns->update_dns( $domain, $ip, $record_type, [$old_record_type]);
71              
72             This function returns false if the operation fails, the cause of the failure is set in C<< $dns->{'error'} >>.
73              
74             =head2 get_dns_info
75              
76             Gets DNS information of a specific entrry.
77              
78             my $info = $dns->get_dns_info( $domain );
79              
80              
81             =head2 list_dns
82              
83             Gets all the dynamic DNS entry names associated with your account.
84              
85             my $list = $dns->list_dns();
86              
87             =head2 list_dns_info
88              
89             Gets all the dynamic DNS entrys information.
90              
91             my $list_info = $dns->list_dns_info();
92              
93             =head2 remove_dns
94              
95             Removes a DNS entry.
96              
97             $removed = $dns->remove_dns( $domain, [$record_type] );
98              
99             This function returns false if the operation fails, the cause of the failure is set in C<< $dns->{'error'} >>.
100              
101              
102             =cut
103              
104             sub new {
105             my ( $class, @args ) = @_;
106             my $self = {};
107             bless $self, $class || $class;
108             $self->{'username'} = $args[0]->{'username'} || die "No username provided";
109             $self->{'password'} = $args[0]->{'password'} || die "No password provided";
110              
111             return $self;
112             }
113              
114             sub update_dns {
115             my ( $self, $domain, $ip, $record_type, $old_record_type ) = @_;
116             die "You must provide a domain" if !$domain;
117             die "You must provide an IP address" if !$ip;
118              
119             my %args = (
120             'domain' => $domain,
121             'ip' => $ip,
122             'record_type' => $record_type,
123             );
124             $args{'old_record_type'} = $old_record_type if $old_record_type;
125             my $response = $self->_get_it( $UPDATEDNS, \%args );
126             return $response;
127              
128             }
129              
130             sub remove_dns {
131             my ( $self, $domain, $record_type ) = @_;
132             die "You must provide a domain" if !$domain;
133             my %args = ( 'domain' => $domain );
134             $args{'record_type'} = $record_type if $record_type;
135             my $response = $self->_get_it( $REMOVEDNS, \%args );
136             return 0 if ( $self->{'error'} );
137             return 1;
138             }
139              
140             sub add_dns {
141             my ( $self, $domain, $ip, $record_type ) = @_;
142             die "You must provide a domain" if !$domain;
143             die "You must provide an IP address" if !$ip;
144             die "You must provide a Record Type" if !$record_type;
145             my $response = $self->_get_it(
146             $ADDDNS,
147             {
148             'domain' => $domain,
149             'ip' => $ip,
150             'record_type' => $record_type
151             } );
152             return 0 if ( $self->{'error'} );
153             return 1;
154             }
155              
156             sub get_dns_info {
157             my ( $self, $domain ) = @_;
158             die "You must provide a domain to check" if ( !$domain );
159             my $response = $self->_get_it( $GETDNSINFO, { 'domain' => $domain } );
160             return if ( $self->{'error'} );
161             my @domain_info = ();
162             my $info = $response->{'info'};
163             if ( ref($info) eq 'ARRAY' ) {
164             for my $dnsinfo ( @{$info} ) {
165             my %tmp_info;
166             $tmp_info{'domain'} = $response->{'domain'};
167             $tmp_info{'ip'} = $dnsinfo->{'ip'};
168             $tmp_info{'type'} = $dnsinfo->{'type'};
169             push @domain_info, \%tmp_info;
170             }
171             } else {
172             my %tmp_info = (
173             'domain' => $response->{'domain'},
174             'ip' => $info->{'ip'},
175             'type' => $info->{'type'},
176             );
177             push @domain_info, \%tmp_info;
178             }
179              
180             return \@domain_info;
181             } ## end sub get_dns_info
182              
183             sub list_dns_info {
184             my ($self) = @_;
185             my $response = $self->_get_it($LISTDNSINFO);
186             my @domains = ();
187             if ( $response->{'domains'}{'domain'} ) {
188             if ( ref( $response->{'domains'}{'domain'} ) eq 'ARRAY' ) {
189             push @domains, @{ $response->{'domains'}{'domain'} };
190             } else {
191             push @domains, $response->{'domains'}{'domain'};
192             }
193             }
194             return \@domains;
195             }
196              
197             sub list_dns {
198             my ($self) = @_;
199             my $response = $self->_get_it($LISTDNS);
200             my @domains = ();
201             if ( $response->{'domain'} ) {
202             if ( ref( $response->{'domains'} ) eq 'ARRAY' ) {
203             push @domains, @{ $response->{'domain'} };
204             } else {
205             push @domains, $response->{'domain'};
206             }
207             }
208             return \@domains;
209             }
210              
211             sub _build_request {
212             my ( $self, $endpoint, $args ) = @_;
213             $args->{'ESBUsername'} = $self->{'username'};
214             $args->{'ESBPassword'} = $self->{'password'};
215             $args->{'lang'} = 'en';
216             my @keys = keys %{$args};
217              
218             my $url = $BASE_URL . $endpoint . '?' . join( '&', map { $_ . '=' . $args->{$_} } @keys );
219              
220             return $url;
221             }
222              
223             sub _get_it {
224             my ( $self, $endpoint, $args ) = @_;
225              
226             my $url = $self->_build_request( $endpoint, $args );
227             delete $self->{'error'};
228              
229             my $ua = new LWP::UserAgent();
230             my $req = new HTTP::Request( 'GET', $url );
231             my $response = $ua->request($req);
232              
233             if ( $response->is_success ) {
234             my $content = $response->content;
235             my $decoded_content = XMLin( \$content, KeyAttr => 'domain' );
236             if ( $decoded_content->{'error'} ) {
237             $self->{'error'} = $decoded_content->{'error'};
238             }
239             return $decoded_content;
240             } else {
241             die "There was a problem with the request\n" . $response->status_line;
242             }
243              
244             } ## end sub _get_it
245              
246             =head1 AUTHOR
247              
248             Bruno Martins, C<< >>
249              
250             =head1 NOTES
251              
252             =head2 Handling Errors
253              
254             There are several ways that the operations can fail, for example, you can try to add a dns entry that already exists or you can try to update a dns entry that is not under your account, etc.
255              
256             Each time an operation is executed and raises an error C<< $dns->{'error'} >> is set with the error reason.
257              
258             =head2 SAPO dynamic DNS API authentication
259              
260             SAPO dynamic DNS API is only available over https, so your username and password are not sent I
261              
262             =head2 Record Types
263              
264             SAPO dynamic DNS API only allows A and AAAA record types
265              
266             =head2 Domain names
267              
268             At this time, SAPO dynamic DNS only allows .sl.pt domains
269              
270             =head1 SUPPORT
271              
272             You can find documentation for this module with the perldoc command.
273              
274             perldoc DNS::PunyDNS
275              
276              
277             You can also look for information at:
278              
279             =over 4
280              
281             =item * Search CPAN
282              
283             L
284              
285             =back
286              
287              
288             =head1 LICENSE AND COPYRIGHT
289              
290             Copyright 2011 Bruno Martins C<< >> and SAPO L, all rights reserved.
291              
292              
293             This program is free software; you can redistribute it and/or modify it
294             under the terms of either: the GNU General Public License as published
295             by the Free Software Foundation; or the Artistic License.
296              
297              
298             See http://dev.perl.org/licenses/ for more information.
299              
300             =cut
301              
302             1; # End of DNS::PunyDNS