Last active
August 6, 2023 19:15
-
-
Save robinkaty/b110e0deb81af698dcb7a39daa1244f1 to your computer and use it in GitHub Desktop.
Validate Known Hosts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env perl | |
# perl script to validate entries in the known_hosts file | |
# by pinging or nslookup. | |
# tried several versions of perl modules for the ping and validate but they were | |
# very unreliable or requred root. | |
# the process uf using the shell seems to work reliably | |
# The output is written to ~/.ssh/new_known_hosts. | |
use strict; | |
use warnings; | |
use Time::HiRes qw( sleep ); | |
#use Data::Dumper; | |
# signal handler for ctrl-c | |
$SIG{INT} = \&ctrl_c_handler;ig | |
sub ctrl_c_handler | |
{ | |
print "\nCtrl-C received. Exiting gracefully...\n"; | |
exit; | |
} | |
sub is_host_reachable | |
{ | |
my ($host) = @_; | |
my $timeout = 2; # Timeout in seconds | |
# Run system ping command | |
my $result = system("ping -c 1 -W $timeout $host > /dev/null 2>&1"); | |
return $result > 0 ? 0 : 1; | |
} | |
sub is_host_resolvable | |
{ | |
my ($host) = @_; | |
# Run system nslookup command | |
my $result = system("nslookup $host > /dev/null 2>&1"); | |
return $result > 0 ? 0 : 1; | |
} | |
sub main | |
{ | |
# Signal handler for Ctrl-C | |
# Signal handler for Ctrl-C | |
$SIG{INT} = \&ctrl_c_handler; | |
# Path to the known_hosts file | |
my $known_hosts_file = "$ENV{HOME}/.ssh/known_hosts"; | |
# Path to the new_known_hosts file | |
my $new_known_hosts_file = "$ENV{HOME}/.ssh/new_known_hosts"; | |
# Read the known_hosts file into an array | |
open( my $fh, '<', $known_hosts_file ) or die "Error opening $known_hosts_file: $!"; | |
my @known_hosts = <$fh>; | |
close($fh); | |
# Create an array to store valid host lines | |
my @valid_host_lines; | |
my @normalized_lines; | |
# Check and validate each host in the known_hosts file | |
foreach my $host_line (@known_hosts) | |
{ | |
#sleep(0.050); | |
chomp $host_line; # Remove trailing newline | |
# Split the host entry into separate components | |
my ( $hosts, $key_type, $key ) = split ' ', $host_line, 3; | |
next unless $hosts; # Skip empty lines | |
# Split the hosts on commas | |
my @hosts = split( /,/, $hosts ); | |
foreach my $host_entry (@hosts) | |
{ | |
$host_entry =~ s/^\s+|\s+$//g; # Remove leading and trailing whitespaces | |
# Check if the host entry is empty or undefined | |
if ($host_entry) | |
{ | |
push @normalized_lines, "$host_entry $key_type $key\n"; | |
print "$host_entry $key_type $key\n"; | |
} | |
} | |
} | |
my %seen; | |
my @sorted_normalized_lines = grep { !$seen{$_}++ } sort @normalized_lines; | |
#print Dumper(@sorted_normalized_lines); | |
foreach my $host_line (@sorted_normalized_lines) | |
{ | |
sleep(0.050); | |
my ( $host_entry, $key_type, $key ) = split ' ', $host_line, 3; | |
$host_entry =~ s/^\s+|\s+$//g; # Remove leading and trailing whitespaces | |
# Check if the host entry is empty or undefined | |
if ($host_entry) | |
{ | |
# Check host availability with TCP port scanning | |
#if ( is_host_reachable( $host_entry ) || is_host_resolvable($host_entry) ) | |
if ( is_host_resolvable($host_entry) || is_host_reachable($host_entry) ) | |
{ | |
# The host is reachable, add the host entry to the array | |
print "Host is alive/valid : $host_entry\n"; | |
push @valid_host_lines, "$host_entry $key_type $key"; | |
} | |
else | |
{ | |
print "Host is not reachable: $host_entry\n"; | |
} | |
} | |
else | |
{ | |
print "Empty host entry found, skipping...\n"; | |
} | |
} | |
# Write the sorted and deduplicated host lines to new_known_hosts file | |
open( my $new_fh, '>', $new_known_hosts_file ) or die "Error opening $new_known_hosts_file: $!"; | |
print $new_fh @valid_host_lines; | |
close($new_fh); | |
} | |
main(); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment