line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Net::DNS::DynDNS; |
2
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
754
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
42
|
|
4
|
1
|
|
|
1
|
|
6
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
33
|
|
5
|
1
|
|
|
1
|
|
1996
|
use LWP(); |
|
1
|
|
|
|
|
95666
|
|
|
1
|
|
|
|
|
26
|
|
6
|
1
|
|
|
1
|
|
1613
|
use HTTP::Cookies(); |
|
1
|
|
|
|
|
9391
|
|
|
1
|
|
|
|
|
24
|
|
7
|
1
|
|
|
1
|
|
7
|
use HTTP::Headers(); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
14
|
|
8
|
1
|
|
|
1
|
|
5
|
use Carp(); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
19
|
|
9
|
1
|
|
|
1
|
|
937
|
use English qw(-no_match_vars); |
|
1
|
|
|
|
|
5765
|
|
|
1
|
|
|
|
|
5
|
|
10
|
|
|
|
|
|
|
our $VERSION = '0.9992'; |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
our @CARP_NOT = ('Net::DNS::DynDNS'); |
13
|
3
|
|
|
3
|
0
|
11
|
sub DEFAULT_TIMEOUT { return 60 } |
14
|
1
|
|
|
1
|
0
|
5
|
sub NUMBER_OF_OCTETS_IN_IP_ADDRESS { return 4; } |
15
|
4
|
|
|
4
|
0
|
23
|
sub MAXIMUM_VALUE_OF_AN_OCTET { return 256; } |
16
|
1
|
|
|
1
|
0
|
8
|
sub FIRST_BYTE_OF_10_PRIVATE_RANGE { return 10; } |
17
|
1
|
|
|
1
|
0
|
9
|
sub FIRST_BYTE_OF_172_16_PRIVATE_RANGE { return 172; } |
18
|
0
|
|
|
0
|
0
|
0
|
sub SECOND_BYTE_OF_172_16_PRIVATE_RANGE { return 16; } |
19
|
1
|
|
|
1
|
0
|
8
|
sub FIRST_BYTE_OF_192_168_PRIVATE_RANGE { return 192; } |
20
|
0
|
|
|
0
|
0
|
0
|
sub SECOND_BYTE_OF_192_168_PRIVATE_RANGE { return 168; } |
21
|
1
|
|
|
1
|
0
|
7
|
sub LOCALHOST_RANGE { return 127; } |
22
|
1
|
|
|
1
|
0
|
7
|
sub MULTICAST_RESERVED_LOWEST_RANGE { return 224; } |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
sub new { |
25
|
3
|
|
|
3
|
1
|
1179
|
my ( $class, $user_name, $password, $params ) = @_; |
26
|
3
|
|
|
|
|
11
|
my $self = {}; |
27
|
3
|
|
|
|
|
19
|
my $timeout = DEFAULT_TIMEOUT(); |
28
|
3
|
50
|
33
|
|
|
112
|
if ( ( ref $user_name ) && ( ref $user_name eq 'SCALAR' ) ) { |
|
|
50
|
33
|
|
|
|
|
29
|
0
|
0
|
0
|
|
|
0
|
if ( not( ( ref $password ) && ( ref $password eq 'SCALAR' ) ) ) { |
30
|
0
|
|
|
|
|
0
|
Carp::croak('No password supplied'); |
31
|
|
|
|
|
|
|
} |
32
|
|
|
|
|
|
|
} |
33
|
|
|
|
|
|
|
elsif ( ( ref $user_name ) && ( ( ref $user_name ) eq 'HASH' ) ) { |
34
|
0
|
|
|
|
|
0
|
$params = $user_name; |
35
|
0
|
|
|
|
|
0
|
$user_name = undef; |
36
|
0
|
|
|
|
|
0
|
$password = undef; |
37
|
|
|
|
|
|
|
} |
38
|
3
|
50
|
|
|
|
17
|
if ( exists $params->{timeout} ) { |
39
|
0
|
0
|
0
|
|
|
0
|
if ( ( $params->{timeout} ) && ( $params->{timeout} =~ /^\d+$/xsm ) ) { |
40
|
0
|
|
|
|
|
0
|
$timeout = $params->{timeout}; |
41
|
|
|
|
|
|
|
} |
42
|
|
|
|
|
|
|
else { |
43
|
0
|
|
|
|
|
0
|
Carp::croak(q[The 'timeout' parameter must be a number]); |
44
|
|
|
|
|
|
|
} |
45
|
|
|
|
|
|
|
} |
46
|
3
|
|
|
|
|
18
|
my $name = "Net::DNS::DynDNS $VERSION " |
47
|
|
|
|
|
|
|
; # a space causes the default LWP User Agent to be appended. |
48
|
3
|
50
|
|
|
|
15
|
if ( exists $params->{user_agent} ) { |
49
|
0
|
0
|
0
|
|
|
0
|
if ( ( $params->{user_agent} ) && ( $params->{user_agent} =~ /\S/xsm ) ) |
50
|
|
|
|
|
|
|
{ |
51
|
0
|
|
|
|
|
0
|
$name = $params->{user_agent}; |
52
|
|
|
|
|
|
|
} |
53
|
|
|
|
|
|
|
} |
54
|
3
|
|
|
|
|
30
|
my $ua = LWP::UserAgent->new( timeout => $timeout ) |
55
|
|
|
|
|
|
|
; # no sense in using keep_alive => 1 because updates and checks are supposed to happen infrequently |
56
|
3
|
|
|
|
|
997
|
$ua->env_proxy(); |
57
|
3
|
|
|
|
|
18482
|
$ua->agent($name); |
58
|
3
|
|
|
|
|
291
|
my $cookie_jar = HTTP::Cookies->new( hide_cookie2 => 1 ); |
59
|
3
|
|
|
|
|
104
|
$ua->cookie_jar($cookie_jar); |
60
|
3
|
|
|
|
|
459
|
$ua->requests_redirectable( ['GET'] ); |
61
|
3
|
|
|
|
|
54
|
$self->{_ua} = $ua; |
62
|
3
|
|
|
|
|
16
|
my $headers = HTTP::Headers->new(); |
63
|
|
|
|
|
|
|
|
64
|
3
|
100
|
66
|
|
|
112
|
if ( ($user_name) && ($password) ) { |
65
|
2
|
|
|
|
|
14
|
$headers->authorization_basic( $user_name, $password ); |
66
|
|
|
|
|
|
|
} |
67
|
3
|
|
|
|
|
390
|
$self->{_headers} = $headers; |
68
|
3
|
|
50
|
|
|
29
|
$self->{server} = $params->{server} || 'dyndns.org'; |
69
|
3
|
|
50
|
|
|
22
|
$self->{dns_server} = $params->{dns_server} || 'members.dyndns.org'; |
70
|
3
|
|
50
|
|
|
20
|
$self->{check_ip} = $params->{check_ip} || 'checkip.dyndns.org'; |
71
|
3
|
|
|
|
|
11
|
bless $self, $class; |
72
|
3
|
|
|
|
|
18
|
$self->update_allowed(1); |
73
|
3
|
|
|
|
|
20
|
return $self; |
74
|
|
|
|
|
|
|
} |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
sub _get { |
77
|
3
|
|
|
3
|
|
34
|
my ( $self, $uri ) = @_; |
78
|
3
|
|
|
|
|
8
|
my $ua = $self->{_ua}; |
79
|
3
|
|
|
|
|
8
|
my $headers = $self->{_headers}; |
80
|
3
|
|
|
|
|
30
|
my $request = HTTP::Request->new( 'GET' => $uri, $headers ); |
81
|
3
|
|
|
|
|
7073
|
my $response; |
82
|
|
|
|
|
|
|
eval { |
83
|
|
|
|
|
|
|
local $SIG{'ALRM'} = |
84
|
3
|
|
|
0
|
|
53
|
sub { Carp::croak "Timeout when retrieving $uri"; }; |
|
0
|
|
|
|
|
0
|
|
85
|
3
|
|
|
|
|
18
|
alarm $ua->timeout(); |
86
|
3
|
|
|
|
|
59
|
$response = $ua->request($request); |
87
|
3
|
|
|
|
|
31743982
|
alarm 0; |
88
|
3
|
|
|
|
|
75
|
1; |
89
|
3
|
50
|
|
|
|
7
|
} or do { |
90
|
0
|
|
|
|
|
0
|
chomp $EVAL_ERROR; |
91
|
0
|
|
|
|
|
0
|
Carp::croak "Failed to get a response from '$uri':$EVAL_ERROR"; |
92
|
|
|
|
|
|
|
}; |
93
|
3
|
|
|
|
|
20
|
return $response; |
94
|
|
|
|
|
|
|
} |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
sub default_ip_address { |
97
|
1
|
|
|
1
|
1
|
450680
|
my ( $proto, $params ) = @_; |
98
|
1
|
|
|
|
|
3
|
my ($self); |
99
|
1
|
50
|
|
|
|
8
|
if ( ref $proto ) { |
100
|
0
|
|
|
|
|
0
|
$self = $proto; |
101
|
|
|
|
|
|
|
} |
102
|
|
|
|
|
|
|
else { |
103
|
1
|
|
|
|
|
7
|
$self = $proto->new($params); |
104
|
|
|
|
|
|
|
} |
105
|
1
|
|
|
|
|
5
|
my ($check_ip_uri) = $self->_check_ip_address_uri($params); |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
# user_name / password is not necessary for checkip. |
108
|
|
|
|
|
|
|
# therefore don't send user_name / password |
109
|
|
|
|
|
|
|
|
110
|
1
|
|
|
|
|
3
|
my $headers = $self->{_headers}; |
111
|
1
|
|
|
|
|
6
|
my ( $user_name, $password ) = $headers->authorization_basic(); |
112
|
1
|
|
|
|
|
7588
|
$headers->remove_header('Authorization'); |
113
|
|
|
|
|
|
|
|
114
|
1
|
|
|
|
|
18
|
my ( $response, $network_error ); |
115
|
1
|
50
|
|
|
|
3
|
eval { $response = $self->_get($check_ip_uri); } or do { |
|
1
|
|
|
|
|
6
|
|
116
|
0
|
|
|
|
|
0
|
$network_error = $EVAL_ERROR; |
117
|
|
|
|
|
|
|
}; |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
# restore user_name / password |
120
|
|
|
|
|
|
|
|
121
|
1
|
50
|
33
|
|
|
9
|
if ( ($user_name) && ($password) ) { |
122
|
0
|
|
|
|
|
0
|
$headers->authorization_basic( $user_name, $password ); |
123
|
|
|
|
|
|
|
} |
124
|
|
|
|
|
|
|
|
125
|
1
|
50
|
|
|
|
6
|
if ($network_error) { |
126
|
0
|
|
|
|
|
0
|
chomp $network_error; |
127
|
0
|
|
|
|
|
0
|
Carp::croak($network_error); |
128
|
|
|
|
|
|
|
} |
129
|
1
|
|
|
|
|
12
|
return $self->_parse_ip_address( $check_ip_uri, $response ); |
130
|
|
|
|
|
|
|
} |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
sub _check_ip_address_uri { |
133
|
1
|
|
|
1
|
|
3
|
my ( $self, $params ) = @_; |
134
|
1
|
|
|
|
|
2
|
my $protocol = 'http' |
135
|
|
|
|
|
|
|
; # default protocol is http because no user_name / passwords are required |
136
|
1
|
50
|
|
|
|
4
|
if ( exists $params->{protocol} ) { |
137
|
0
|
0
|
0
|
|
|
0
|
if ( ( defined $params->{protocol} ) && ( $params->{protocol} ) ) { |
138
|
0
|
|
|
|
|
0
|
$params->{protocol} = lc( $params->{protocol} ); |
139
|
0
|
0
|
0
|
|
|
0
|
if ( ( $params->{protocol} ne 'http' ) |
140
|
|
|
|
|
|
|
&& ( $params->{protocol} ne 'https' ) ) |
141
|
|
|
|
|
|
|
{ |
142
|
0
|
|
|
|
|
0
|
Carp::croak( |
143
|
|
|
|
|
|
|
q[The 'protocol' parameter must be one of 'http' or 'https'] |
144
|
|
|
|
|
|
|
); |
145
|
|
|
|
|
|
|
} |
146
|
|
|
|
|
|
|
} |
147
|
|
|
|
|
|
|
else { |
148
|
0
|
|
|
|
|
0
|
Carp::croak( |
149
|
|
|
|
|
|
|
q[The 'protocol' parameter must be one of 'http' or 'https']); |
150
|
|
|
|
|
|
|
} |
151
|
0
|
|
|
|
|
0
|
$protocol = $params->{protocol}; |
152
|
|
|
|
|
|
|
} |
153
|
1
|
50
|
|
|
|
5
|
if ( $protocol eq 'https' ) { |
154
|
0
|
0
|
|
|
|
0
|
eval { require Net::HTTPS; } or do { |
|
0
|
|
|
|
|
0
|
|
155
|
0
|
|
|
|
|
0
|
Carp::croak(q[Cannot load Net::HTTPS]); |
156
|
|
|
|
|
|
|
}; |
157
|
|
|
|
|
|
|
} |
158
|
1
|
|
|
|
|
5
|
return $protocol . '://' . $self->{check_ip}; |
159
|
|
|
|
|
|
|
} |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
sub _parse_ip_address { |
162
|
1
|
|
|
1
|
|
5
|
my ( $self, $check_ip_uri, $response ) = @_; |
163
|
1
|
|
|
|
|
3
|
my $ip_address; |
164
|
1
|
50
|
|
|
|
8
|
if ( $response->is_success() ) { |
165
|
1
|
|
|
|
|
28
|
my $content = $response->content(); |
166
|
1
|
50
|
|
|
|
29
|
if ( $content =~ /Current\sIP\sAddress:\s(\d+.\d+.\d+.\d+)/xsm ) { |
167
|
1
|
|
|
|
|
6
|
$ip_address = $1; |
168
|
|
|
|
|
|
|
} |
169
|
|
|
|
|
|
|
else { |
170
|
0
|
|
|
|
|
0
|
Carp::croak("Failed to parse response from '$check_ip_uri'"); |
171
|
|
|
|
|
|
|
} |
172
|
|
|
|
|
|
|
} |
173
|
|
|
|
|
|
|
else { |
174
|
0
|
|
|
|
|
0
|
my $content = $response->content(); |
175
|
0
|
|
|
|
|
0
|
$content =~ s/\s*$//smx; |
176
|
0
|
0
|
|
|
|
0
|
if ( $content =~ /Can't\sconnect\sto\s$self->{check_ip}/xsm ) { |
177
|
0
|
|
|
|
|
0
|
Carp::croak("Failed to connect to '$check_ip_uri'"); |
178
|
|
|
|
|
|
|
} |
179
|
|
|
|
|
|
|
else { |
180
|
0
|
|
|
|
|
0
|
Carp::croak( |
181
|
|
|
|
|
|
|
"Failed to get a success type response from '$check_ip_uri':$content" |
182
|
|
|
|
|
|
|
); |
183
|
|
|
|
|
|
|
} |
184
|
|
|
|
|
|
|
} |
185
|
1
|
|
|
|
|
86
|
return $ip_address; |
186
|
|
|
|
|
|
|
} |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
sub _validate_update { |
189
|
2
|
|
|
2
|
|
6
|
my ( $self, $hostnames, $ip_address, $params ) = @_; |
190
|
2
|
|
|
|
|
7
|
my $headers = $self->{_headers}; |
191
|
2
|
|
|
|
|
10
|
my ( $user_name, $password ) = $headers->authorization_basic(); |
192
|
2
|
50
|
|
|
|
116
|
if ( not $self->update_allowed() ) { |
193
|
0
|
|
|
|
|
0
|
Carp::croak( |
194
|
|
|
|
|
|
|
"$self->{server} has forbidden updates until the previous error is corrected" |
195
|
|
|
|
|
|
|
); |
196
|
|
|
|
|
|
|
} |
197
|
2
|
50
|
33
|
|
|
29
|
if ( not( ($user_name) && ($password) ) ) { |
198
|
0
|
|
|
|
|
0
|
Carp::croak(q[Username and password must be supplied for an update]); |
199
|
|
|
|
|
|
|
} |
200
|
2
|
50
|
|
|
|
9
|
if ( not($hostnames) ) { |
201
|
0
|
|
|
|
|
0
|
Carp::croak(q[The update method must be supplied with a hostname]); |
202
|
|
|
|
|
|
|
} |
203
|
2
|
50
|
|
|
|
27
|
if ( |
204
|
|
|
|
|
|
|
not( $hostnames =~ |
205
|
|
|
|
|
|
|
/^(?:(?:[[:alpha:]\d\-]+[.])+[[:alpha:]\d\-]+,?)+$/xsm ) |
206
|
|
|
|
|
|
|
) |
207
|
|
|
|
|
|
|
{ |
208
|
0
|
|
|
|
|
0
|
Carp::croak( |
209
|
|
|
|
|
|
|
"The hostnames do not seem to be in a valid format. Try 'test.$self->{server}'" |
210
|
|
|
|
|
|
|
); |
211
|
|
|
|
|
|
|
} |
212
|
2
|
|
|
|
|
10
|
$self->_validate_ip_address($ip_address); |
213
|
2
|
100
|
66
|
|
|
17
|
if ( ( ref $params ) && ( ( ref $params ) eq 'HASH' ) ) { |
|
|
50
|
|
|
|
|
|
214
|
1
|
|
|
|
|
6
|
$self->_check_wildcard($params); |
215
|
1
|
|
|
|
|
4
|
$self->_check_mx($params); |
216
|
1
|
|
|
|
|
4
|
$self->_check_backmx($params); |
217
|
1
|
|
|
|
|
4
|
$self->_check_offline($params); |
218
|
1
|
50
|
|
|
|
4
|
if ( exists $params->{protocol} ) { |
219
|
1
|
|
|
|
|
4
|
$self->_check_protocol($params); |
220
|
|
|
|
|
|
|
} |
221
|
|
|
|
|
|
|
else { |
222
|
0
|
|
|
|
|
0
|
$params->{protocol} = 'https'; |
223
|
|
|
|
|
|
|
} |
224
|
|
|
|
|
|
|
} |
225
|
|
|
|
|
|
|
elsif ($params) { |
226
|
0
|
|
|
|
|
0
|
Carp::croak( |
227
|
|
|
|
|
|
|
q[Extra parameters must be passed in as a reference to a hash]); |
228
|
|
|
|
|
|
|
} |
229
|
2
|
|
|
|
|
7
|
return; |
230
|
|
|
|
|
|
|
} |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
sub _validate_ip_address { |
233
|
2
|
|
|
2
|
|
5
|
my ( $self, $ip_address ) = @_; |
234
|
2
|
100
|
|
|
|
9
|
if ( defined $ip_address ) { |
235
|
1
|
|
|
|
|
6
|
my @bytes = split /[.]/xsm, $ip_address; |
236
|
1
|
50
|
|
|
|
5
|
if ( ( scalar @bytes ) != NUMBER_OF_OCTETS_IN_IP_ADDRESS() ) { |
237
|
0
|
|
|
|
|
0
|
Carp::croak(q[Bad IP address]); |
238
|
|
|
|
|
|
|
} |
239
|
1
|
|
|
|
|
3
|
foreach my $byte (@bytes) { |
240
|
4
|
50
|
|
|
|
18
|
if ( not( $byte =~ /^\d+$/xsm ) ) { |
241
|
0
|
|
|
|
|
0
|
Carp::croak(q[Bad IP address. Each byte must be numeric]); |
242
|
|
|
|
|
|
|
} |
243
|
4
|
50
|
33
|
|
|
8
|
if ( ( $byte >= MAXIMUM_VALUE_OF_AN_OCTET() ) || ( $byte < 0 ) ) { |
244
|
0
|
|
|
|
|
0
|
Carp::croak(q[Bad IP address. Each byte must be within 0-255]); |
245
|
|
|
|
|
|
|
} |
246
|
|
|
|
|
|
|
} |
247
|
1
|
50
|
33
|
|
|
8
|
if ( |
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
248
|
|
|
|
|
|
|
( $bytes[0] == 0 ) |
249
|
|
|
|
|
|
|
|| ( $bytes[0] == LOCALHOST_RANGE() ) |
250
|
|
|
|
|
|
|
|| ( $bytes[0] == FIRST_BYTE_OF_10_PRIVATE_RANGE() ) |
251
|
|
|
|
|
|
|
|| ( ( $bytes[0] == FIRST_BYTE_OF_172_16_PRIVATE_RANGE() ) |
252
|
|
|
|
|
|
|
&& ( $bytes[1] == SECOND_BYTE_OF_172_16_PRIVATE_RANGE() ) ) |
253
|
|
|
|
|
|
|
|| # private |
254
|
|
|
|
|
|
|
( |
255
|
|
|
|
|
|
|
( $bytes[0] == FIRST_BYTE_OF_192_168_PRIVATE_RANGE() ) |
256
|
|
|
|
|
|
|
&& ( $bytes[1] == SECOND_BYTE_OF_192_168_PRIVATE_RANGE() ) |
257
|
|
|
|
|
|
|
) |
258
|
|
|
|
|
|
|
|| # private |
259
|
|
|
|
|
|
|
( $bytes[0] >= MULTICAST_RESERVED_LOWEST_RANGE() ) |
260
|
|
|
|
|
|
|
) # multicast && reserved |
261
|
|
|
|
|
|
|
{ |
262
|
0
|
|
|
|
|
0
|
Carp::croak( |
263
|
|
|
|
|
|
|
q[Bad IP address. The IP address is in a range that is not publically addressable] |
264
|
|
|
|
|
|
|
); |
265
|
|
|
|
|
|
|
} |
266
|
|
|
|
|
|
|
} |
267
|
|
|
|
|
|
|
} |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
sub _check_wildcard { |
270
|
1
|
|
|
1
|
|
2
|
my ( $self, $params ) = @_; |
271
|
1
|
50
|
|
|
|
5
|
if ( exists $params->{wildcard} ) { |
272
|
1
|
50
|
33
|
|
|
7
|
if ( ( defined $params->{wildcard} ) && ( $params->{wildcard} ) ) { |
273
|
1
|
|
|
|
|
4
|
$params->{wildcard} = uc( $params->{wildcard} ); |
274
|
1
|
0
|
33
|
|
|
13
|
if ( ( $params->{wildcard} ne 'ON' ) |
|
|
|
33
|
|
|
|
|
275
|
|
|
|
|
|
|
&& ( $params->{wildcard} ne 'OFF' ) |
276
|
|
|
|
|
|
|
&& ( $params->{wildcard} ne 'NOCHG' ) ) |
277
|
|
|
|
|
|
|
{ |
278
|
0
|
|
|
|
|
0
|
Carp::croak( |
279
|
|
|
|
|
|
|
q[The 'wildcard' parameter must be one of 'ON','OFF' or 'NOCHG'] |
280
|
|
|
|
|
|
|
); |
281
|
|
|
|
|
|
|
} |
282
|
|
|
|
|
|
|
} |
283
|
|
|
|
|
|
|
else { |
284
|
0
|
|
|
|
|
0
|
Carp::croak( |
285
|
|
|
|
|
|
|
q[The 'wildcard' parameter must be one of 'ON','OFF' or 'NOCHG'] |
286
|
|
|
|
|
|
|
); |
287
|
|
|
|
|
|
|
} |
288
|
|
|
|
|
|
|
} |
289
|
|
|
|
|
|
|
} |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
sub _check_mx { |
292
|
1
|
|
|
1
|
|
3
|
my ( $self, $params ) = @_; |
293
|
1
|
50
|
|
|
|
4
|
if ( exists $params->{mx} ) { |
294
|
1
|
50
|
33
|
|
|
8
|
if ( ( defined $params->{mx} ) && ( $params->{mx} ) ) { |
295
|
1
|
50
|
|
|
|
10
|
if ( |
296
|
|
|
|
|
|
|
not( $params->{mx} =~ |
297
|
|
|
|
|
|
|
/^(?:(?:[[:alpha:]\d\-]+[.])+[[:alpha:]\d\-]+,?)+$/xsm ) |
298
|
|
|
|
|
|
|
) |
299
|
|
|
|
|
|
|
{ |
300
|
0
|
|
|
|
|
0
|
Carp::croak( |
301
|
|
|
|
|
|
|
"The 'mx' parameter does not seem to be in a valid format. Try 'test.$self->{server}'" |
302
|
|
|
|
|
|
|
); |
303
|
|
|
|
|
|
|
} |
304
|
|
|
|
|
|
|
} |
305
|
|
|
|
|
|
|
else { |
306
|
0
|
|
|
|
|
0
|
Carp::croak( |
307
|
|
|
|
|
|
|
q[The 'mx' parameter must be a valid fully qualified domain name] |
308
|
|
|
|
|
|
|
); |
309
|
|
|
|
|
|
|
} |
310
|
|
|
|
|
|
|
} |
311
|
|
|
|
|
|
|
else { |
312
|
0
|
0
|
|
|
|
0
|
if ( exists $params->{backmx} ) { |
313
|
0
|
|
|
|
|
0
|
Carp::croak( |
314
|
|
|
|
|
|
|
q[The 'backmx' parameter cannot be set without specifying the 'mx' parameter] |
315
|
|
|
|
|
|
|
); |
316
|
|
|
|
|
|
|
} |
317
|
|
|
|
|
|
|
} |
318
|
|
|
|
|
|
|
} |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
sub _check_backmx { |
321
|
1
|
|
|
1
|
|
2
|
my ( $self, $params ) = @_; |
322
|
1
|
50
|
|
|
|
5
|
if ( exists $params->{backmx} ) { |
323
|
1
|
50
|
33
|
|
|
8
|
if ( ( defined $params->{backmx} ) && ( $params->{backmx} ) ) { |
324
|
1
|
|
|
|
|
3
|
$params->{backmx} = uc( $params->{backmx} ); |
325
|
1
|
50
|
33
|
|
|
5
|
if ( ( $params->{backmx} ne 'YES' ) |
326
|
|
|
|
|
|
|
&& ( $params->{backmx} ne 'NO' ) ) |
327
|
|
|
|
|
|
|
{ |
328
|
0
|
|
|
|
|
0
|
Carp::croak( |
329
|
|
|
|
|
|
|
q[The 'backmx' parameter must be one of 'YES' or 'NO']); |
330
|
|
|
|
|
|
|
} |
331
|
|
|
|
|
|
|
} |
332
|
|
|
|
|
|
|
else { |
333
|
0
|
|
|
|
|
0
|
Carp::croak(q[The 'backmx' parameter must be one of 'YES' or 'NO']); |
334
|
|
|
|
|
|
|
} |
335
|
|
|
|
|
|
|
} |
336
|
|
|
|
|
|
|
} |
337
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
sub _check_offline { |
339
|
1
|
|
|
1
|
|
2
|
my ( $self, $params ) = @_; |
340
|
1
|
50
|
|
|
|
4
|
if ( exists $params->{offline} ) { |
341
|
1
|
50
|
33
|
|
|
7
|
if ( ( defined $params->{offline} ) && ( $params->{offline} ) ) { |
342
|
1
|
|
|
|
|
3
|
$params->{offline} = uc( $params->{offline} ); |
343
|
1
|
50
|
33
|
|
|
42
|
if ( ( $params->{offline} ne 'YES' ) |
344
|
|
|
|
|
|
|
&& ( $params->{offline} ne 'NO' ) ) |
345
|
|
|
|
|
|
|
{ |
346
|
0
|
|
|
|
|
0
|
Carp::croak( |
347
|
|
|
|
|
|
|
q[The 'offline' parameter must be one of 'YES' or 'NO']); |
348
|
|
|
|
|
|
|
} |
349
|
|
|
|
|
|
|
} |
350
|
|
|
|
|
|
|
else { |
351
|
0
|
|
|
|
|
0
|
Carp::croak( |
352
|
|
|
|
|
|
|
q[The 'offline' parameter must be one of 'YES' or 'NO']); |
353
|
|
|
|
|
|
|
} |
354
|
|
|
|
|
|
|
} |
355
|
|
|
|
|
|
|
} |
356
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
sub _check_protocol { |
358
|
1
|
|
|
1
|
|
3
|
my ( $self, $params ) = @_; |
359
|
1
|
50
|
33
|
|
|
8
|
if ( ( defined $params->{protocol} ) && ( $params->{protocol} ) ) { |
360
|
1
|
|
|
|
|
3
|
$params->{protocol} = lc( $params->{protocol} ); |
361
|
1
|
50
|
33
|
|
|
6
|
if ( ( $params->{protocol} ne 'http' ) |
362
|
|
|
|
|
|
|
&& ( $params->{protocol} ne 'https' ) ) |
363
|
|
|
|
|
|
|
{ |
364
|
0
|
|
|
|
|
0
|
Carp::croak( |
365
|
|
|
|
|
|
|
q[The 'protocol' parameter must be one of 'http' or 'https']); |
366
|
|
|
|
|
|
|
} |
367
|
|
|
|
|
|
|
} |
368
|
|
|
|
|
|
|
else { |
369
|
0
|
|
|
|
|
0
|
Carp::croak( |
370
|
|
|
|
|
|
|
q[The 'protocol' parameter must be one of 'http' or 'https']); |
371
|
|
|
|
|
|
|
} |
372
|
|
|
|
|
|
|
} |
373
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
sub update_allowed { |
375
|
6
|
|
|
6
|
1
|
18
|
my ( $self, $allowed ) = @_; |
376
|
6
|
|
|
|
|
11
|
my $old; |
377
|
6
|
50
|
66
|
|
|
37
|
if ( ( exists $self->{update_allowed} ) && ( $self->{update_allowed} ) ) { |
378
|
3
|
|
|
|
|
8
|
$old = $self->{update_allowed}; |
379
|
|
|
|
|
|
|
} |
380
|
6
|
100
|
|
|
|
23
|
if ( defined $allowed ) { |
381
|
4
|
|
|
|
|
11
|
$self->{update_allowed} = $allowed; |
382
|
|
|
|
|
|
|
} |
383
|
6
|
|
|
|
|
20
|
return $old; |
384
|
|
|
|
|
|
|
} |
385
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
sub _error { |
387
|
1
|
|
|
1
|
|
4
|
my ( $self, $code, $content ) = @_; |
388
|
1
|
|
|
|
|
6
|
$self->update_allowed(0); |
389
|
1
|
|
|
|
|
13
|
my %errors = ( |
390
|
|
|
|
|
|
|
'badauth' => 'The username and password pair do not match a real user', |
391
|
|
|
|
|
|
|
'!donator' => |
392
|
|
|
|
|
|
|
'An option available only to credited users (such as offline URL) was specified, but the user is not a credited user', |
393
|
|
|
|
|
|
|
'notfqdn' => |
394
|
|
|
|
|
|
|
'The hostname specified is not a fully-qualified domain name (not in the form hostname.dyndns.org or domain.com)', |
395
|
|
|
|
|
|
|
'nohost' => |
396
|
|
|
|
|
|
|
'The hostname specified does not exist in this user account', |
397
|
|
|
|
|
|
|
'numhost' => 'Too many hosts (more than 20) specified in an update', |
398
|
|
|
|
|
|
|
'abuse' => 'The hostname specified is blocked for update abuse', |
399
|
|
|
|
|
|
|
'badagent' => |
400
|
|
|
|
|
|
|
'The user agent was not sent or HTTP method is not permitted', |
401
|
|
|
|
|
|
|
'dnserr' => 'DNS error encountered', |
402
|
|
|
|
|
|
|
'911' => 'There is a problem or scheduled maintenance on our side', |
403
|
|
|
|
|
|
|
); |
404
|
1
|
|
33
|
|
|
197
|
Carp::croak( $errors{$code} || "Unknown error:$code:$content" ); |
405
|
|
|
|
|
|
|
} |
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
sub update { |
408
|
2
|
|
|
2
|
1
|
752
|
my ( $self, $hostnames, $ip_address, $params ) = @_; |
409
|
2
|
50
|
33
|
|
|
12
|
if ( ( ref $ip_address ) && ( ref $ip_address eq 'HASH' ) ) { |
410
|
0
|
|
|
|
|
0
|
$params = $ip_address; |
411
|
0
|
|
|
|
|
0
|
$ip_address = undef; |
412
|
|
|
|
|
|
|
} |
413
|
2
|
|
|
|
|
10
|
$self->_validate_update( $hostnames, $ip_address, $params ); |
414
|
2
|
|
|
|
|
5
|
my $protocol = |
415
|
|
|
|
|
|
|
'https'; # default protocol is https to protect user_name / password |
416
|
2
|
100
|
|
|
|
9
|
if ( $params->{protocol} ) { |
417
|
1
|
|
|
|
|
3
|
$protocol = $params->{protocol}; |
418
|
|
|
|
|
|
|
} |
419
|
2
|
100
|
|
|
|
10
|
if ( $protocol eq 'https' ) { |
420
|
1
|
50
|
|
|
|
4
|
eval { require Net::HTTPS; } or do { |
|
1
|
|
|
|
|
20
|
|
421
|
0
|
|
|
|
|
0
|
Carp::croak(q[Cannot load Net::HTTPS]); |
422
|
|
|
|
|
|
|
}; |
423
|
|
|
|
|
|
|
} |
424
|
2
|
|
|
|
|
15
|
my $update_uri = |
425
|
|
|
|
|
|
|
$protocol . "://$self->{dns_server}/nic/update?hostname=" . $hostnames; |
426
|
2
|
100
|
|
|
|
8
|
if ( defined $ip_address ) { |
427
|
1
|
|
|
|
|
5
|
$update_uri .= '&myip=' . $ip_address; |
428
|
|
|
|
|
|
|
} |
429
|
2
|
100
|
|
|
|
8
|
if ( exists $params->{wildcard} ) { |
430
|
1
|
|
|
|
|
4
|
$update_uri .= '&wildcard=' . $params->{wildcard}; |
431
|
|
|
|
|
|
|
} |
432
|
2
|
100
|
|
|
|
8
|
if ( exists $params->{mx} ) { |
433
|
1
|
|
|
|
|
3
|
$update_uri .= '&mx=' . $params->{mx}; |
434
|
|
|
|
|
|
|
} |
435
|
2
|
100
|
|
|
|
7
|
if ( exists $params->{backmx} ) { |
436
|
1
|
|
|
|
|
3
|
$update_uri .= '&backmx=' . $params->{backmx}; |
437
|
|
|
|
|
|
|
} |
438
|
2
|
100
|
|
|
|
7
|
if ( exists $params->{offline} ) { |
439
|
1
|
|
|
|
|
3
|
$update_uri .= '&offline=' . $params->{offline}; |
440
|
|
|
|
|
|
|
} |
441
|
2
|
|
|
|
|
9
|
my $response = $self->_get($update_uri); |
442
|
2
|
|
|
|
|
12
|
my $content = $response->content(); |
443
|
2
|
|
|
|
|
32
|
my $result = $self->_parse_content( $update_uri, $content ); |
444
|
1
|
|
|
|
|
43
|
return $result; |
445
|
|
|
|
|
|
|
} |
446
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
sub _parse_content { |
448
|
2
|
|
|
2
|
|
6
|
my ( $self, $update_uri, $content ) = @_; |
449
|
2
|
|
|
|
|
12
|
my @lines = split /\015?\012/xsm, $content; |
450
|
2
|
|
|
|
|
5
|
my $result; |
451
|
2
|
|
|
|
|
6
|
foreach my $line (@lines) { |
452
|
3
|
100
|
|
|
|
25
|
if ( |
|
|
50
|
|
|
|
|
|
453
|
|
|
|
|
|
|
$line =~ m{ |
454
|
|
|
|
|
|
|
( \S + ) # response code |
455
|
|
|
|
|
|
|
\s+ |
456
|
|
|
|
|
|
|
(\S.*) $ # ip address (possible) |
457
|
|
|
|
|
|
|
}xsm |
458
|
|
|
|
|
|
|
) |
459
|
|
|
|
|
|
|
{ |
460
|
2
|
|
|
|
|
46
|
my ( $code, $additional ) = ( $1, $2 ); |
461
|
2
|
50
|
33
|
|
|
14
|
if ( |
|
|
|
33
|
|
|
|
|
462
|
|
|
|
|
|
|
( $code eq 'good' ) |
463
|
|
|
|
|
|
|
|| ( $code eq 'nochg' ) |
464
|
|
|
|
|
|
|
|| ( $code eq '200' |
465
|
|
|
|
|
|
|
) # used by http://www.changeip.com/accounts/knowledgebase.php?action=displayarticle&id=47 |
466
|
|
|
|
|
|
|
) |
467
|
|
|
|
|
|
|
{ |
468
|
2
|
100
|
|
|
|
6
|
if ($result) { |
469
|
1
|
50
|
|
|
|
6
|
if ( $result ne $additional ) { |
470
|
0
|
|
|
|
|
0
|
Carp::croak( |
471
|
|
|
|
|
|
|
"Could not understand multi-line response\n$content" |
472
|
|
|
|
|
|
|
); |
473
|
|
|
|
|
|
|
} |
474
|
|
|
|
|
|
|
} |
475
|
|
|
|
|
|
|
else { |
476
|
1
|
|
|
|
|
3
|
$result = $additional; |
477
|
|
|
|
|
|
|
} |
478
|
|
|
|
|
|
|
} |
479
|
|
|
|
|
|
|
else { |
480
|
0
|
|
|
|
|
0
|
$self->_error( $code, $content ); |
481
|
|
|
|
|
|
|
} |
482
|
|
|
|
|
|
|
} |
483
|
|
|
|
|
|
|
elsif ( |
484
|
|
|
|
|
|
|
$line =~ m{ |
485
|
|
|
|
|
|
|
^ ( \S + ) $ # if this line of the response is a single code word |
486
|
|
|
|
|
|
|
}xsm |
487
|
|
|
|
|
|
|
) |
488
|
|
|
|
|
|
|
{ |
489
|
1
|
|
|
|
|
4
|
my ($code) = ($1); |
490
|
1
|
|
|
|
|
6
|
$self->_error( $code, $content ); |
491
|
|
|
|
|
|
|
} |
492
|
|
|
|
|
|
|
else { |
493
|
0
|
|
|
|
|
0
|
Carp::croak( |
494
|
|
|
|
|
|
|
"Failed to parse response from '$update_uri'\n$content"); |
495
|
|
|
|
|
|
|
} |
496
|
|
|
|
|
|
|
} |
497
|
1
|
|
|
|
|
4
|
return $result; |
498
|
|
|
|
|
|
|
} |
499
|
|
|
|
|
|
|
|
500
|
|
|
|
|
|
|
1; |
501
|
|
|
|
|
|
|
|
502
|
|
|
|
|
|
|
__END__ |