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