#!/usr/bin/perl
use Net::DNS;
use threads;
use threads::shared;
use strict;
use warnings;

my $res = Net::DNS::Resolver->new;
  
# user-supplied:
my $sites_file = "/usr/local/etc/sitelist.conf";
# generated by this script:
my $ssh_config = "/etc/ssh/ssh_config_hosts";
# generated by this script:
my $ssh_keys = "/etc/ssh/ssh_known_hosts";


open(SITES, $sites_file);
my @sites = <SITES>;
close(SITES);
chomp foreach (@sites);

my %keyhash;
# Read in each old key from file, using "hostname type" as key
open(KEYS, $ssh_keys);
while (<KEYS>) {
    chomp;
    my @keyline = split(" ");
    $keyhash{join(" ", @keyline[0..1])} = $keyline[2];
}
close(KEYS);

my %hosts;

my @hostconfigs;
print "Analyzing dns txt records...\n";
foreach my $site (@sites) {
    print "$site\n";
    my $siteshort = $site;
    $siteshort =~ s/\.egeland\.net//;
    my $query = $res->query("$site", "TXT");
    # a txt record is found
    if ($query) {
	my $txtline;
	foreach my $rr (grep { $_->type eq 'TXT' } $query->answer) {
	    $txtline .= $rr->txtdata;
	}
	my @txtwords = split(" ", $txtline);
	foreach my $word (@txtwords) {
	    my @elements = split(":", $word);
	    if ($elements[1] eq "ssh") {
		print "   found $elements[0]\n";
                # the site's root name is the key, the port the value:
		$hosts{"$elements[0].$site"} = $elements[2];
		if ($elements[2] eq "22") {
		    push (@hostconfigs, "Host $elements[0]\n" .
		    "   Hostname $elements[0].$site\n" .
		    "   HostKeyAlias $elements[0].$site\n" .
		    "Host $siteshort\n" .
		    "   Hostname $elements[0].$site\n" .
		    "   HostKeyAlias $elements[0].$site\n" .
		    "Host $site\n" .
		    "   Hostname $elements[0].$site\n" .
		    "   HostKeyAlias $elements[0].$site\n");
		}
		# a sub-site
		else {
		    push (@hostconfigs, "Host $elements[0]\n" .
		    "   Port $elements[2]\n" .
		    "   Hostname $elements[0].$site\n" .
		    "   HostKeyAlias $elements[0].$site\n" .
		    "Host $elements[0].$site\n" .
		    "   Port $elements[2]\n");
		}
	    }
	}
    } # no txt record found
    else {
	push (@hostconfigs, "Host $siteshort\n" .
	"   Hostname $site\n");
	$hosts{"$site"} = "22";
    }
}

print "\nWriting SSH config file to $ssh_config\n";
open(SSHCONFIG, ">", "$ssh_config");
print SSHCONFIG @hostconfigs;
print SSHCONFIG "Host egeland.net
   Hostname mail.egeland.net
   HostKeyAlias mail.egeland.net
";
close (SSHCONFIG);


# Now scan each host in %hosts for keys using threads
my @key_thr; # Holds ssh keyscan threads
my @keys :shared;
print "\nGetting host SSH keys...\n";

# Run a separate thread for each keyscan process (each host)
foreach my $host (keys %hosts) {
    push(@key_thr, async {
	push (@keys, `ssh-keyscan -t dsa,rsa -p $hosts{$host} $host`);
	 }
	);
}
$_->join for (@key_thr);

# Overwrite any stored keyfiles and keep undiscovered ones
foreach (@keys) {
    my @keyline = split(" ");
    $keyhash{join(" ", @keyline[0..1])} = $keyline[2];
}

# Write completed updated keyhash to file
open(KEYS, ">", "$ssh_keys");
print "\nSaving SSH Keys to $ssh_keys.\n";
foreach my $key (sort keys %keyhash) {
    print KEYS "$key $keyhash{$key}\n";
}
close(KEYS);

# Simple hack to combine ssh_config_base with keys
print "Writing /etc/ssh/ssh_config.\n";
`cp /etc/ssh/ssh_config_base /etc/ssh/ssh_config`;
`cat $ssh_config >> /etc/ssh/ssh_config`;
