CodeCommitsIssuesPull requestsActionsInsightsSecurity
820835c3f0fd4e85304b36696074f2269dd2ed82

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

Cpanel/CloudFlare.pm

694lines · modecode

1package Cpanel::CloudFlare;
2
3# cpanel - Cpanel/CloudFlare.pm Copyright(c) 2011 CloudFlare, Inc.
4# All rights Reserved.
5# copyright@cloudflare.com http://cloudflare.com
6# @author ian@cloudflare.com
7# This code is subject to the cPanel license. Unauthorized copying is prohibited
8
9use Cpanel::DnsUtils::UsercPanel ();
10use Cpanel::AdminBin ();
11use Cpanel::Locale ();
12use Cpanel::Logger ();
13use Cpanel::UrlTools ();
14use Cpanel::SocketIP ();
15use Cpanel::Encoder::URI ();
16use Cpanel::AcctUtils ();
17use Cpanel::DomainLookup ();
18use Cpanel::DataStore ();
19
20use Socket ();
21use JSON::Syck ();
22use Digest::MD5 qw(md5_hex);
23use strict;
24
25my $logger = Cpanel::Logger->new();
26my $locale;
27my $cf_config_file = "/usr/local/cpanel/etc/cloudflare.json";
28my $cf_local_config_file = "/usr/local/cpanel/etc/cloudflare_local.json";
29my $cf_data_file_name = ".cpanel/datastore/cloudflare_data.yaml";
30my $cf_old_data_file_name = "/usr/local/cpanel/etc/cloudflare_data.yaml";
31my $cf_data_file;
32my $cf_host_key;
33my $cf_host_name;
34my $cf_host_uri;
35my $cf_user_name;
36my $cf_user_uri;
37my $cf_host_port;
38my $cf_host_on_cloud_msg;
39my $cf_host_prefix;
40my $has_ssl;
41my $cf_debug_mode;
42my $hoster_name;
43my $cf_cp_version;
44my $cf_global_data = {};
45my $DEFAULT_HOSTER_NAME = "your web hosting provider";
46
47my %KEYMAP = ( 'line' => 'Line', 'ttl' => 'ttl', 'name' => 'name',
48 'class' => 'class', 'address' => 'address', 'type' => 'type',
49 'txtdata' => 'txtdata', 'preference' => 'preference', 'exchange' => 'exchange' );
50
51## Initialize vars here.
52sub CloudFlare_init {
53 my $data = JSON::Syck::LoadFile($cf_config_file);
54 my $local_data = (-e $cf_local_config_file)? JSON::Syck::LoadFile($cf_local_config_file): {};
55
56 $cf_host_key = $data->{"host_key"};
57 $cf_host_name = $data->{"host_name"};
58 $cf_host_uri = $data->{"host_uri"};
59 $cf_host_port = $data->{"host_port"};
60 $cf_host_prefix = $data->{"host_prefix"};
61 $cf_debug_mode = $data->{"debug"};
62 $cf_user_name = $data->{"user_name"};
63 $cf_user_uri = $data->{"user_uri"};
64 $cf_cp_version = $data->{"cp_version"};
65 $hoster_name = $data->{"host_formal_name"};
66 $cf_host_on_cloud_msg = ($local_data->{"cloudflare_on_message"})? $local_data->{"cloudflare_on_message"}: "";
67 if (!$hoster_name) {
68 $hoster_name = $DEFAULT_HOSTER_NAME;
69 }
70
71 eval { use Net::SSLeay qw(post_https make_headers make_form); $has_ssl = 1 };
72 if ( !$has_ssl ) {
73 $logger->warn("Failed to load Net::SSLeay: $@.\nDisabling functionality until fixed.");
74 }
75
76 ## Load the api key.
77 if (-x "/usr/local/cpanel/bin/apikeywrap") {
78 my $response=`/usr/local/cpanel/bin/apikeywrap $cf_host_key`;
79 chomp $response;
80 $cf_host_key = $response;
81 }
82}
83
84# Can only be called with json or xml api because it uses
85# a non-standard return
86sub api2_user_create {
87 my %OPTS = @_;
88
89 if (!$cf_host_key) {
90 $logger->info("Missing cf_host_key! Define this in $cf_config_file.");
91 return [];
92 }
93
94 __load_data_file($OPTS{"homedir"});
95 # Use a random string as a password.
96 my $password = ($OPTS{"password"})? $OPTS{"password"}: crypt(int(rand(10000000)), time);
97 $logger->info("Creating Cloudflare user for " . $OPTS{"email"} . " -- " . $password);
98 $cf_global_data->{"cf_user_tokens"}->{$OPTS{"user"}} = md5_hex($OPTS{"user"} . $cf_host_key);
99 $logger->info("Making user token: " . $cf_global_data->{"cf_user_tokens"}->{$OPTS{"user"}});
100
101 ## Otherwise, try to create this user.
102 my $args = {
103 "host" => $cf_host_name,
104 "uri" => $cf_host_uri,
105 "port" => $cf_host_port,
106 "query" => {
107 "act" => "user_create",
108 "host_key" => $cf_host_key,
109 "cloudflare_email" => $OPTS{"email"},
110 "cloudflare_pass" => $password,
111 "unique_id" => $cf_global_data->{"cf_user_tokens"}->{$OPTS{"user"}},
112 },
113 };
114
115 Cpanel::DataStore::store_ref($cf_data_file, $cf_global_data);
116 my $result = __https_post_req->($args);
117 return JSON::Syck::Load($result);
118}
119
120# Can only be called with json or xml api because it uses
121# a non-standard return
122sub api2_user_lookup {
123 my %OPTS = @_;
124
125 __load_data_file($OPTS{"homedir"}, $OPTS{"user"});
126 if (!$cf_host_key) {
127 $logger->info("Missing cf_host_key! Define this in $cf_config_file.");
128 return [];
129 }
130
131 if ( !$has_ssl ) {
132 $logger->info("No SSL Configured");
133 return [{"result"=>"error",
134 "msg" => "CloudFlare is disabled until Net::SSLeay is installed on this server."}];
135 }
136
137 if ($cf_global_data->{"cf_user_tokens"}->{$OPTS{"user"}}) {
138 if ($cf_debug_mode) {
139 $logger->info("Using user token");
140 }
141 my $login_args = {
142 "host" => $cf_host_name,
143 "uri" => $cf_host_uri,
144 "port" => $cf_host_port,
145 "query" => {
146 "act" => "user_lookup",
147 "host_key" => $cf_host_key,
148 "unique_id" => $cf_global_data->{"cf_user_tokens"}->{$OPTS{"user"}},
149 },
150 };
151
152 my $result = JSON::Syck::Load(__https_post_req->($login_args));
153 $result->{"on_cloud_message"} = $cf_host_on_cloud_msg;
154 return ($result);
155 } else {
156 if ($cf_debug_mode) {
157 $logger->info("Using user email");
158 }
159 my $login_args = {
160 "host" => $cf_host_name,
161 "uri" => $cf_host_uri,
162 "port" => $cf_host_port,
163 "query" => {
164 "act" => "user_lookup",
165 "host_key" => $cf_host_key,
166 "cloudflare_email" => $OPTS{"email"},
167 },
168 };
169
170 my $result = JSON::Syck::Load(__https_post_req->($login_args));
171 $result->{"on_cloud_message"} = $cf_host_on_cloud_msg;
172 return ($result);
173 }
174}
175
176## Pulls certain stats for the passed in zone.
177sub api2_get_stats {
178 my %OPTS = @_;
179
180 if (!$OPTS{"user_api_key"}) {
181 $logger->info("Missing user_api_key!");
182 return [];
183 }
184
185 if ( !$has_ssl ) {
186 $logger->info("No SSL Configured");
187 return [{"result"=>"error",
188 "msg" => "CloudFlare is disabled until Net::SSLeay is installed on this server."}];
189 }
190
191 ## Otherwise, pull this users stats.
192 my $stats_args = {
193 "host" => $cf_user_name,
194 "uri" => $cf_user_uri,
195 "port" => $cf_host_port,
196 "query" => {
197 "a" => "stats",
198 "z" => $OPTS{"zone_name"},
199 "tkn" => $OPTS{"user_api_key"},
200 "u" => $OPTS{"user_email"},
201 "interval" => 30, # 30 = last 7 days, 20 = last 30 days 40 = last 24 hours
202 },
203 };
204
205 my $result = __https_post_req->($stats_args);
206 return JSON::Syck::Load($result);
207}
208
209sub api2_edit_cf_setting {
210 my %OPTS = @_;
211
212 if (!$OPTS{"user_api_key"}) {
213 $logger->info("Missing user_api_key!");
214 return [];
215 }
216
217 if ( !$has_ssl ) {
218 $logger->info("No SSL Configured");
219 return [{"result"=>"error",
220 "msg" => "CloudFlare is disabled until Net::SSLeay is installed on this server."}];
221 }
222
223 ## Otherwise, pull this users stats.
224 my $stats_args = {
225 "host" => $cf_user_name,
226 "uri" => $cf_user_uri,
227 "port" => $cf_host_port,
228 "query" => {
229 "a" => $OPTS{"a"},
230 "z" => $OPTS{"zone_name"},
231 "tkn" => $OPTS{"user_api_key"},
232 "u" => $OPTS{"user_email"},
233 "v" => $OPTS{"v"},
234 },
235 };
236
237 my $result = __https_post_req->($stats_args);
238 return JSON::Syck::Load($result);
239}
240
241# Can only be called with json or xml api because it uses
242# a non-standard return
243sub api2_zone_set {
244 my %OPTS = @_;
245
246 if (!$cf_host_key || !$cf_host_prefix) {
247 $logger->info("Missing cf_host_key or $cf_host_prefix! Define these in $cf_config_file.");
248 return [];
249 }
250
251 __load_data_file($OPTS{"homedir"});
252 my $domain = ".".$OPTS{"zone_name"}.".";
253 my $subs = $OPTS{"subdomains"};
254 $subs =~ s/${domain}//g;
255
256 ## Unpack the mapping from recs to lines (ugg, this is SOOO BAAD)
257 my $recs2lines = JSON::Syck::Load($OPTS{"cf_recs"});
258
259 ## Set up the zone_set args.
260 my $login_args = {
261 "host" => $cf_host_name,
262 "uri" => $cf_host_uri,
263 "port" => $cf_host_port,
264 "query" => {
265 "act" => "zone_set",
266 "host_key" => $cf_host_key,
267 "user_key" => $OPTS{"user_key"},
268 "zone_name" => $OPTS{"zone_name"},
269 "resolve_to" => $cf_host_prefix . "." . $OPTS{"zone_name"},
270 "subdomains" => $subs
271 },
272 };
273
274 if (!$subs) {
275 $login_args->{"query"}->{"act"} = "zone_delete";
276 $cf_global_data->{"cf_zones"}->{$OPTS{"zone_name"}} = 0
277 }
278
279 my $result = JSON::Syck::Load(__https_post_req->($login_args));
280
281 ## Args for updating local DNS.
282 my %zone_args = ("domain" => $OPTS{"zone_name"},
283 "class" => "IN",
284 "type" => "CNAME",
285 "name" => $cf_host_prefix,
286 "ttl" => 1400,
287 "cname" => $OPTS{"zone_name"},
288 );
289
290 my $is_cf = 0;
291
292 ## If we get an error, do nothing and return the error to the user.
293 if ($result->{"result"} eq "error") {
294 $logger->info("CloudFlare Error: " . $result->{"msg"});
295 } else {
296 ## Otherwise, update the dns for this zone.
297 my $dom = ".".$OPTS{"zone_name"};
298
299 ## First Make sure that the resolve to is set.
300 my $res = Cpanel::AdminBin::adminfetchnocache( 'zone', '', 'ADD', 'storable', $OPTS{"zone_name"},
301 __serialize_request( \%zone_args ) );
302
303 ## If there's a delete, remove this record from being CF.
304 if ($OPTS{"old_line"}) {
305 $zone_args{"line"} = $OPTS{"old_line"};
306 $zone_args{"name"} = $OPTS{"old_rec"};
307 $zone_args{"name"} =~ s/$domain//g;
308 $zone_args{"cname"} = $OPTS{"zone_name"};
309 $res = Cpanel::AdminBin::adminfetchnocache( 'zone', '', 'EDIT', 'storable', $OPTS{"zone_name"},
310 __serialize_request( \%zone_args ) );
311 }
312
313 ## Now, go ahead and update all of the CF enabled recs.
314 foreach my $ft (keys %{$result->{"response"}->{"forward_tos"}}) {
315 $zone_args{"line"} = $recs2lines->{$ft."."};
316 $zone_args{"name"} = $ft;
317 $zone_args{"name"} =~ s/$dom//g;
318 $zone_args{"cname"} = $result->{"response"}->{"forward_tos"}->{$ft};
319
320 $res = Cpanel::AdminBin::adminfetchnocache( 'zone', '', 'EDIT', 'storable', $OPTS{"zone_name"},
321 __serialize_request( \%zone_args ) );
322 if (!$res->{"status"}) {
323 ## Try again, bumping up the line by 1. -- no idea why this works.
324 $zone_args{"line"}++;
325 $res = Cpanel::AdminBin::adminfetchnocache( 'zone', '', 'EDIT', 'storable', $OPTS{"zone_name"},
326 __serialize_request( \%zone_args ) );
327 }
328
329 if (!$res->{"status"}) {
330 $logger->info("Failed to set DNS for CloudFlare record $ft!");
331 $logger->info(JSON::Syck::Dump($res));
332 $result->{"result"} = "error";
333 $result->{"msg"} = $res->{"statusmsg"};
334 }
335
336 ## Note that if at least one rec is on, this zone is on CF.
337 $cf_global_data->{"cf_zones"}->{$OPTS{"zone_name"}} = 1;
338 $is_cf = 1;
339 }
340 }
341
342 if (!$is_cf) {
343 $cf_global_data->{"cf_zones"}->{$OPTS{"zone_name"}} = 0;
344 }
345
346 ## Save the updated global data arg.
347 Cpanel::DataStore::store_ref($cf_data_file, $cf_global_data);
348
349 return $result;
350}
351
352sub api2_zone_delete {
353 my %OPTS = @_;
354
355 if (!$cf_host_key || !$cf_host_prefix) {
356 $logger->info("Missing cf_host_key or $cf_host_prefix! Define these in $cf_config_file.");
357 return [];
358 }
359
360 __load_data_file($OPTS{"homedir"});
361 my $domain = ".".$OPTS{"zone_name"}.".";
362
363 ## Unpack the mapping from recs to lines (ugg, this is SOOO BAAD)
364 my $recs2lines = JSON::Syck::Load($OPTS{"cf_recs"});
365
366 ## Set up the zone_set args.
367 my $login_args = {
368 "host" => $cf_host_name,
369 "uri" => $cf_host_uri,
370 "port" => $cf_host_port,
371 "query" => {
372 "act" => "zone_delete",
373 "host_key" => $cf_host_key,
374 "user_key" => $OPTS{"user_key"},
375 "zone_name" => $OPTS{"zone_name"}
376 },
377 };
378
379 $cf_global_data->{"cf_zones"}->{$OPTS{"zone_name"}} = 0;
380
381 my $result = JSON::Syck::Load(__https_post_req->($login_args));
382
383 ## Args for updating local DNS.
384 my %zone_args = ("domain" => $OPTS{"zone_name"},
385 "class" => "IN",
386 "type" => "CNAME",
387 "name" => $cf_host_prefix,
388 "ttl" => 1400,
389 "cname" => $OPTS{"zone_name"},
390 );
391
392 ## If we get an error, do nothing and return the error to the user.
393 if ($result->{"result"} eq "error") {
394 $logger->info("CloudFlare Error: " . $result->{"msg"});
395 } else {
396 ## Otherwise, update the dns for this zone.
397 my $dom = ".".$OPTS{"zone_name"};
398
399 ## Loop over list of subs, removing from CF.
400 my $res;
401 foreach my $linecom (split(/,/, $OPTS{"subdomains"})) {
402 my @line = split(':', $linecom);
403 $zone_args{"line"} = $line[1];
404 $zone_args{"name"} = $line[0];
405 $zone_args{"name"} =~ s/$domain//g;
406 $zone_args{"cname"} = $OPTS{"zone_name"};
407 $res = Cpanel::AdminBin::adminfetchnocache( 'zone', '', 'EDIT', 'storable', $OPTS{"zone_name"},
408 __serialize_request( \%zone_args ) );
409 }
410 }
411
412 ## Save the updated global data arg.
413 Cpanel::DataStore::store_ref($cf_data_file, $cf_global_data);
414
415 return $result;
416}
417
418sub api2_fetchzone {
419 my $raw = __fetchzone(@_);
420 my $results = [];
421 my %OPTS = @_;
422 my $domain = $OPTS{'domain'}.".";
423
424 foreach my $res (@{$raw->{"record"}}) {
425 if ((($res->{"type"} eq "CNAME") || ($res->{"type"} eq "A")) &&
426 ($res->{"name"} !~ /(^direct|^ssh|^ftp|ssl|mx|^ns[^.]*|^imap[^.]*|^pop[^.]*|smtp[^.]*|^mail[^.]*|^mx[^.]*|^exchange[^.]*|^smtp[^.]*|google[^.]*|^secure|^sftp|^svn|^git|^irc|^email|^mobilemail|^pda|^webmail|^e\.|^video|^vid|^vids|^sites|^calendar|^svn|^cvs|^git|^cpanel|^panel|^repo|^webstats|^local|localhost|$cf_host_prefix)/) &&
427 ($res->{"name"} ne $domain) &&
428 ($res->{"cname"} !~ /google.com/)){
429 if ($res->{"cname"} =~ /cdn.cloudflare.net$/) {
430 $res->{"cloudflare"} = 1;
431 } else {
432 $res->{"cloudflare"} = 0;
433 }
434 push @$results, $res;
435 }
436 }
437 return $results;
438}
439
440sub api2_getbasedomains {
441 my %OPTS = @_;
442 __load_data_file($OPTS{"homedir"}, $OPTS{"user"});
443 my $res = Cpanel::DomainLookup::api2_getbasedomains(@_);
444 my $has_cf = 0;
445 foreach my $dom (@$res) {
446 if ($cf_global_data->{"cf_zones"}->{$dom->{"domain"}}) {
447 $dom->{"cloudflare"} = 1;
448 $has_cf = 1;
449 } else {
450 $dom->{"cloudflare"} = 0;
451 }
452 }
453 return {"has_cf" => $has_cf, "res" => $res, "hoster" => $hoster_name};
454}
455
456sub api2 {
457 my $func = shift;
458
459 my %API;
460
461 $API{'user_create'}{'func'} = 'api2_user_create';
462 $API{'user_create'}{'engine'} = 'hasharray';
463 $API{'user_lookup'}{'func'} = 'api2_user_lookup';
464 $API{'user_lookup'}{'engine'} = 'hasharray';
465 $API{'zone_set'}{'func'} = 'api2_zone_set';
466 $API{'zone_set'}{'engine'} = 'hasharray';
467 $API{'zone_delete'}{'func'} = 'api2_zone_delete';
468 $API{'zone_delete'}{'engine'} = 'hasharray';
469 $API{'fetchzone'}{'func'} = 'api2_fetchzone';
470 $API{'fetchzone'}{'engine'} = 'hasharray';
471 $API{'getbasedomains'}{'func'} = 'api2_getbasedomains';
472 $API{'getbasedomains'}{'engine'} = 'hasharray';
473 $API{'zone_get_stats'}{'func'} = 'api2_get_stats';
474 $API{'zone_get_stats'}{'engine'} = 'hasharray';
475 $API{'zone_edit_cf_setting'}{'func'} = 'api2_edit_cf_setting';
476 $API{'zone_edit_cf_setting'}{'engine'} = 'hasharray';
477
478 return ( \%{ $API{$func} } );
479}
480
481## Run the auto-update here
482sub check_auto_update {
483
484 print "Checking CloudFlare for latest version\n";
485 CloudFlare_init();
486 print "Current Version: $cf_cp_version\n";
487
488 my $check_args = {
489 "host" => $cf_host_name,
490 "uri" => $cf_host_uri,
491 "port" => $cf_host_port,
492 "query" => {
493 "act" => "cpanel_info",
494 "host_key" => $cf_host_key,
495 },
496 };
497
498 my $result = JSON::Syck::Load(__https_post_req->($check_args));
499 print "Latest Version: " . $result->{"response"}{"cpanel_latest"} . "\n";
500 print "Latest SHA1: " . $result->{"response"}{"cpanel_sha1"} . "\n";
501
502 if ($result->{"response"}{"cpanel_latest"} > $cf_cp_version) {
503 print "Downloading the latest version.\n";
504 `curl -L https://github.com/cloudflare/CloudFlare-CPanel/tarball/master > /tmp/cloudflare.tar.gz`;
505 if (`sha1sum /tmp/cloudflare.tar.gz | grep $result->{"response"}{"cpanel_sha1"}`) {
506 print "Valid Checksum\n";
507 } else {
508 print "Checksum failed, aborting upgrade\n";
509 unlink("/tmp/cloudflare.tar.gz");
510 }
511 } else {
512 print "You already have the latest version.\n";
513 }
514}
515
516## Returns a list of all users and zones on CF.
517sub list_active_zones {
518 if ($>) {
519 die("must be root to run.");
520 }
521
522 CloudFlare_init();
523 my %zones;
524 foreach my $user (`ls /home`) {
525 chomp $user;
526 if ( -e "/home/$user/$cf_data_file_name") {
527 __load_data_file("/home/$user", $user);
528 foreach my $zone (keys %{$cf_global_data->{"cf_zones"}}) {
529 if ($cf_global_data->{"cf_zones"}{$zone}) {
530 $zones{$zone} = 1;
531 }
532 }
533 }
534 }
535
536 print "The following zones are currently active on CloudFlare:\n";
537 foreach my $zone (keys %zones) {
538 print "$zone\n";
539 }
540}
541
542########## Internal Functions Defined Below #########
543
544sub __load_data_file {
545 my $home_dir = shift;
546 my $user = shift;
547 $cf_data_file = $home_dir . "/" . $cf_data_file_name;
548 if( Cpanel::DataStore::load_ref($cf_data_file, $cf_global_data ) ) {
549 if ($cf_debug_mode) {
550 $logger->info("Successfully loaded cf data -- $cf_data_file");
551 }
552 } else {
553 ## Try to load the data from the old default data file (if it exists)
554 if (-e $cf_old_data_file_name) {
555 $logger->info( "Failed to load cf data -- Trying to copy from $cf_old_data_file_name for $user");
556 my $tmp_data = {};
557 Cpanel::DataStore::load_ref($cf_old_data_file_name, $tmp_data);
558 $cf_global_data->{"cf_user_tokens"}->{$user} = $tmp_data->{"cf_user_tokens"}->{$user};
559 $cf_global_data->{"cf_zones"} = $tmp_data->{"cf_zones"};
560
561 } else {
562 $cf_global_data = {"cf_zones" => {}};
563 $logger->info( "Failed to load cf data -- storing blank data at $cf_data_file");
564 }
565 Cpanel::DataStore::store_ref($cf_data_file, $cf_global_data);
566 chmod 0600, $cf_data_file;
567 }
568}
569
570sub __fetchzone {
571 my %OPTS = @_;
572 my $domain = $OPTS{'domain'};
573 my $results = Cpanel::AdminBin::adminfetchnocache( 'zone', '', 'FETCH', 'storable', $domain, ($OPTS{'customonly'} ? 1 : 0) );
574
575 if ( ref $results->{'record'} eq 'ARRAY' ) {
576 for(0 .. $#{ $results->{'record'} }) {
577 $results->{'record'}->[$_]->{'record'} = ($results->{'record'}->[$_]->{'address'} || $results->{'record'}->[$_]->{'cname'} || $results->{'record'}->[$_]->{'txtdata'});
578 $results->{'record'}->[$_]->{'line'} = ($results->{'record'}->[$_]->{'Line'});
579 }
580 foreach my $key ( keys %KEYMAP ) {
581 if ( exists $OPTS{$key} && defined $OPTS{$key} ) {
582 my %MULTITYPES = map { $_ => undef } split(/[\|\,]/, $OPTS{$key});
583 @{ $results->{'record'} } = grep { exists $MULTITYPES{$_->{ $KEYMAP{$key} }} } @{ $results->{'record'} };
584 }
585 }
586 }
587
588 return $results;
589}
590
591sub __https_post_req {
592 my ( $args_hr ) = @_;
593 if ($args_hr->{'port'} ne "443") {
594 ## Downgrade to http
595 return __http_post_req($args_hr);
596 } else {
597 my ( $args_hr ) = @_;
598 my ($page, $response, %reply_headers)
599 = post_https($args_hr->{'host'}, $args_hr->{'port'}, $args_hr->{'uri'}, '',
600 make_form(%{$args_hr->{'query'}}));
601 if ($cf_debug_mode) {
602 $logger->info($response);
603 $logger->info($page);
604 }
605 return $page;
606 }
607}
608
609sub __http_post_req {
610 my ( $args_hr ) = @_;
611 my $query = $args_hr->{'query'};
612 if ( ref $args_hr->{'query'} eq 'HASH' ) {
613 $query = '';
614 foreach my $key ( keys %{ $args_hr->{'query'} } ) {
615 if ( ref $args_hr->{'query'}{$key} eq 'ARRAY' ) {
616 for my $val ( @{ $args_hr->{'query'}{$key} } ) {
617 $query .=
618 $query
619 ? "&$key=" . Cpanel::Encoder::URI::uri_encode_str($val)
620 : "$key=" . Cpanel::Encoder::URI::uri_encode_str($val);
621 }
622 }
623 else {
624 $query .=
625 $query
626 ? "&$key=" . Cpanel::Encoder::URI::uri_encode_str( $args_hr->{'query'}{$key} )
627 : "$key=" . Cpanel::Encoder::URI::uri_encode_str( $args_hr->{'query'}{$key} );
628 }
629 }
630 }
631
632 my $postdata_len = length($query);
633
634 if ($cf_debug_mode) {
635 $logger->info($query);
636 }
637
638 my $proto = getprotobyname('tcp');
639 return unless defined $proto;
640
641 socket( my $socket_fh, &Socket::AF_INET, &Socket::SOCK_STREAM, $proto );
642 return unless $socket_fh;
643
644 my $iaddr = gethostbyname($args_hr->{'host'});
645 my $port = $args_hr->{'port'};
646
647 return unless ( defined $iaddr && defined $port );
648
649 my $sin = Socket::sockaddr_in( $port, $iaddr );
650 return unless defined $sin;
651
652 my $result = "";
653 if ( connect( $socket_fh, $sin ) ) {
654 send $socket_fh, "POST /$args_hr->{'uri'} HTTP/1.0\nContent-Length: $postdata_len\nContent-Type: application/x-www-form-urlencoded\nHost: $args_hr->{'host'}\n\n$query", 0;
655
656 my $in_header = 1;
657 while (<$socket_fh>) {
658 if ( /^\n$/ || /^\r\n$/ || /^$/ ) {
659 $in_header = 0;
660 next;
661 }
662
663 if (!$in_header) {
664 $result .= $_;
665 }
666 }
667 }
668
669 close $socket_fh;
670
671 if ($cf_debug_mode) {
672 $logger->info($result);
673 }
674
675 return $result;
676}
677
678sub __serialize_request {
679 my $opt_ref = shift;
680 my @KEYLIST;
681 foreach my $opt ( keys %$opt_ref ) {
682 push @KEYLIST, Cpanel::Encoder::URI::uri_encode_str($opt) . '=' . Cpanel::Encoder::URI::uri_encode_str( $opt_ref->{$opt} );
683 }
684 return join( '&', @KEYLIST );
685}
686
687## Are we running from the command line?
688if ($ARGV[0] eq "check") {
689 check_auto_update();
690} elsif ($ARGV[0] eq "list") {
691 list_active_zones();
692}
693
6941; # Ah, perl.