Mini Shell
#!/usr/bin/perl
# encoding: utf-8
#
# author: Kyle Yetter
#
# to skip certificate verification
$ENV{'PERL_LWP_SSL_VERIFY_HOSTNAME'} = 0;
our $VERSION = 1.0;
use strict;
use LWP::UserAgent;
use URI;
use File::Basename;
use LWP::Protocol::https;
use JSON::Syck;
use YAML::Any;
our $HOSTNAME = `hostname`;
chomp $HOSTNAME;
our $DOMAINIPS_FILE = "/etc/domainips";
our $TRUEUSERDOMAINS_FILE = "/etc/trueuserdomains";
our $RESERVED_IPS_FILE = "/etc/reservedipreasons";
our $IP_ASSIGNMENT_DETAILS = {};
our $DOMAINS_TO_USERS = {};
our $RESERVED_IPS = {};
if ( -f $RESERVED_IPS_FILE ) {
open( my $in, "< $RESERVED_IPS_FILE" ) or die "Failed to open $RESERVED_IPS_FILE - $!";
foreach ( <$in> ) {
chomp;
s(^\s+|\s+$)()g; # strip the line
next if /^\s*(?:#.*)?$/; # skip over blank and comment lines
my ( $ip, $comment ) = split( /\s*=\s*/, $_, 2 );
$RESERVED_IPS->{ $ip } = $comment;
}
close( $in );
}
#
# Harvest the user <=> primary domain relationships on the server, as maintained
# within /etc/trueuserdomains. Point the domain to the username in the $DOMAINS_TO_USERS
# hash.
#
if ( -f $TRUEUSERDOMAINS_FILE ) {
open( my $in, "< $TRUEUSERDOMAINS_FILE" ) or die "Failed to open $TRUEUSERDOMAINS_FILE - $!";
foreach ( <$in> ) {
chomp;
s(^\s+|\s+$)()g; # strip the line
next if /^\s*(?:#.*)?$/; # skip over blank and comment lines
my ( $domain, $user ) = split( /\s*:\s*/, $_, 2 );
$DOMAINS_TO_USERS->{ $domain } = $user;
}
close( $in );
}
#
# Harvest the domain <=> dedicated IP relationships on the server, as maintained
# within /etc/domainips. Use the domain to get any available user information
# havested above. Create a record tying together the user, domain, and IP and
# push it onto a list associated with the IP address.
#
if ( -f $DOMAINIPS_FILE ) {
open( my $in, "< $DOMAINIPS_FILE" ) or die "Failed to open $DOMAINIPS_FILE - $!";
foreach ( <$in> ) {
chomp;
s(^\s+|\s+$)()g; # strip the line
next if /^\s*(?:#.*)?$/; # skip over blank and comment lines
my ( $ip, $domain ) = split( /\s*:\s*/, $_, 2 );
if ( exists $DOMAINS_TO_USERS->{ $domain } ) {
my $user = $DOMAINS_TO_USERS->{ $domain };
#my $dig = shell_join( "dig", "+short", $domain );
#my @dig_results = `$dig`;
#chomp for @dig_results;
#my $dig_matches = grep { $_ eq $ip } @dig_results;
my $reserved = 0;
if ( exists $RESERVED_IPS->{ $ip } ) {
$reserved = $RESERVED_IPS->{ $ip } || 1;
}
my $record = {
ip => $ip,
user => $user,
domain => $domain,
reserved => $reserved #,
#dig_matches => $dig_matches
};
push @{ $IP_ASSIGNMENT_DETAILS->{ $ip } }, $record;
}
}
close( $in );
}
# set to 1 if we had to generate an access key
our $created_access_hash = 0;
our $access_key;
END {
#
# If we had to create a temporary access hash to make this work,
# make sure it gets trashed
#
if ( -f '/root/.accesshash' && $created_access_hash ) {
unlink( '/root/.accesshash' ) or die( "failed to remove /root/.accesshash" );
}
}
#
# If successful, the call will return a reference to an array of IP records on the server,
# where each record is a hash with a key named 'ip' to indicate the IP it represents.
#
our $ip_list = &api_call( "listips" );
#
# Iterate through each entry in the IP list, where each hash is assigned to Perl's
# special $_ variable in the loop below. If additional details are found in the
# $IP_ASSIGNMENT_DETAILS data map gathered above, merge that hash with the IP data
# returned by the API. Assigning to $_ changes the item in the array in-place.
#
for ( @$ip_list ) {
my $address = $_->{ ip };
if ( exists $IP_ASSIGNMENT_DETAILS->{ $address } ) {
my $details = pop( @{ $IP_ASSIGNMENT_DETAILS->{ $address } } );
my %merged = ( %$_, %$details );
$_ = \%merged;
} elsif ( $_->{ mainaddr } or exists $RESERVED_IPS->{ $address } ) {
$_->{ domain } = $HOSTNAME;
$_->{ user } = '';
}
}
#
# Finally, rebuild the original API call hash { result => [ ip info... ] } and
# dump it as JSON to be used by System Center.
#
open( OUT, "> /opt/scops/out/ips" ) or die $!;
print OUT JSON::Syck::Dump({ result => $ip_list });
close( OUT ) or die $!;
###############################################################################
############################### Helper Functions ##############################
###############################################################################
sub access_key {
if ( $access_key ) { return $access_key; }
unless ( -f '/root/.accesshash' ) {
$ENV{ REMOTE_USER } = 'root';
`/usr/local/cpanel/bin/mkaccesshash`;
delete $ENV{ REMOTE_USER };
$created_access_hash = 1;
}
if ( -f '/root/.accesshash' ) {
open( my $f, "< /root/.accesshash" ) or die "could not read /root/.accesshash: $!";
my @lines = <$f>;
close( $f );
$access_key = join( '', @lines );
$access_key =~ s/\n//g;
} else {
die "could not read /root/.accesshash: $!";
}
return $access_key;
}
sub load_json($) {
my ( $source ) = @_;
my $data;
eval { $data = JSON::Syck::Load( $source ); };
if ( $@ ) {
die( $@ . "\nJSON SOURCE:\n" . $source );
}
return $data;
}
sub api_call($%) {
my $function = shift;
my %params = @_;
my $uri = URI->new( "https://127.0.0.1:2087/json-api/$function" );
$uri->query_form( %params );
my $auth = "WHM root:" . access_key();
my $ua = LWP::UserAgent->new;
my $request = HTTP::Request->new( GET => "$uri" );
$request->header( Authorization => $auth );
my $response = $ua->request( $request );
return &load_json( $response->content )->{ result };
}
#
# shell_escape
#
# Given a string argument, escape shell-unsafe characters to ensure the string
# represents a single token in a command line
#
sub shell_escape {
my $token = @_ ? shift : $_;
if ( length( $token ) == 0 ) { return "''"; }
$token =~ s/([^A-Za-z0-9_\-\.,:\/@\n])/\\$1/g;
$token =~ s/\n/'\n'/g;
return $token;
}
sub shell_join {
return join( ' ', map { shell_escape } @_ );
}
Zerion Mini Shell 1.0