mirror of git://anongit.mindrot.org/openssh.git
738 lines
21 KiB
Perl
738 lines
21 KiB
Perl
|
#!/usr/bin/perl -w
|
||
|
# -*- perl -*-
|
||
|
######################################################################
|
||
|
# make-ssh-known-hosts.pl -- Make ssh-known-hosts file
|
||
|
# Copyright (c) 1995 Tero Kivinen
|
||
|
# All Rights Reserved.
|
||
|
#
|
||
|
# Make-ssh-known-hosts is distributed in the hope that it will be
|
||
|
# useful, but WITHOUT ANY WARRANTY. No author or distributor accepts
|
||
|
# responsibility to anyone for the consequences of using it or for
|
||
|
# whether it serves any particular purpose or works at all, unless he
|
||
|
# says so in writing. Refer to the GNU General Public License for full
|
||
|
# details.
|
||
|
#
|
||
|
# Everyone is granted permission to copy, modify and redistribute
|
||
|
# make-ssh-known-hosts, but only under the conditions described in
|
||
|
# the GNU General Public License. A copy of this license is supposed to
|
||
|
# have been given to you along with make-ssh-known-hosts so you can
|
||
|
# know your rights and responsibilities. It should be in a file named
|
||
|
# gnu-COPYING-GPL. Among other things, the copyright notice and this notice
|
||
|
# must be preserved on all copies.
|
||
|
######################################################################
|
||
|
# Program: make-ssh-known-hosts.pl
|
||
|
# $Source: /var/cvs/openssh/contrib/Attic/make-ssh-known-hosts.pl,v $
|
||
|
# Author : $Author: damien $
|
||
|
#
|
||
|
# (C) Tero Kivinen 1995 <Tero.Kivinen@hut.fi>
|
||
|
#
|
||
|
# Creation : 19:52 Jun 27 1995 kivinen
|
||
|
# Last Modification : 00:07 Jul 8 1998 kivinen
|
||
|
# Last check in : $Date: 2000/03/15 01:13:03 $
|
||
|
# Revision number : $Revision: 1.1 $
|
||
|
# State : $State: Exp $
|
||
|
# Version : 1.343
|
||
|
# Edit time : 242 min
|
||
|
#
|
||
|
# Description : Make ssh-known-host file from dns data.
|
||
|
#
|
||
|
# $Log: make-ssh-known-hosts.pl,v $
|
||
|
# Revision 1.1 2000/03/15 01:13:03 damien
|
||
|
# - Created contrib/ subdirectory. Included helpers from Phil Hands'
|
||
|
# Debian package, README file and chroot patch from Ricardo Cerqueira
|
||
|
# <rmcc@clix.pt>
|
||
|
# - Moved gnome-ssh-askpass.c to contrib directory and reomved config
|
||
|
# option.
|
||
|
# - Slight cleanup to doc files
|
||
|
#
|
||
|
# Revision 1.6 1998/07/08 00:44:23 kivinen
|
||
|
# Fixed to understand bind 8 nslookup output.
|
||
|
#
|
||
|
# Revision 1.5 1998/04/30 01:53:33 kivinen
|
||
|
# Moved kill before close and added sending SIGINT first and
|
||
|
# then 1 second sleep before sending SIGKILL.
|
||
|
#
|
||
|
# Revision 1.4 1998/04/17 00:39:19 kivinen
|
||
|
# Changed to close ssh program filedescriptor before killing it.
|
||
|
# Removed ^ from the password matching prompt.
|
||
|
#
|
||
|
# Revision 1.3 1997/04/17 04:21:27 kivinen
|
||
|
# Changed to use 3des by default.
|
||
|
#
|
||
|
# Revision 1.2 1997/03/26 07:14:01 kivinen
|
||
|
# Added EWOULDBLOCK.
|
||
|
#
|
||
|
# Revision 1.1.1.1 1996/02/18 21:38:10 ylo
|
||
|
# Imported ssh-1.2.13.
|
||
|
#
|
||
|
# Revision 1.4 1995/10/02 01:23:45 ylo
|
||
|
# Ping packet size fixes from Kivinen.
|
||
|
#
|
||
|
# Revision 1.3 1995/08/29 22:37:39 ylo
|
||
|
# Now uses GlobalKnownHostsFile and UserKnownHostsFile.
|
||
|
#
|
||
|
# Revision 1.2 1995/07/15 13:26:37 ylo
|
||
|
# Changes from kivinen.
|
||
|
#
|
||
|
# Revision 1.1.1.1 1995/07/12 22:41:05 ylo
|
||
|
# Imported ssh-1.0.0.
|
||
|
#
|
||
|
#
|
||
|
#
|
||
|
# If you have any useful modifications or extensions please send them to
|
||
|
# Tero.Kivinen@hut.fi
|
||
|
#
|
||
|
######################################################################
|
||
|
# initialization
|
||
|
|
||
|
require 5.000;
|
||
|
use Getopt::Long;
|
||
|
use FileHandle;
|
||
|
use POSIX;
|
||
|
use Socket;
|
||
|
use Fcntl;
|
||
|
|
||
|
$version = ' $Id: make-ssh-known-hosts.pl,v 1.1 2000/03/15 01:13:03 damien Exp $ ';
|
||
|
|
||
|
$command_line = "$0 ";
|
||
|
foreach $a (@ARGV) {
|
||
|
$command_line .= $a . " ";
|
||
|
}
|
||
|
STDERR->autoflush(1);
|
||
|
|
||
|
######################################################################
|
||
|
# default values for options
|
||
|
|
||
|
$debug = 5;
|
||
|
$defserver = '';
|
||
|
$bell='\a';
|
||
|
$public_key = '/etc/ssh_host_key.pub';
|
||
|
$private_ssh_known_hosts = "/tmp/ssh_known_hosts$$";
|
||
|
$timeout = 60;
|
||
|
$ping_timeout = 3;
|
||
|
$passwordtimeout = undef;
|
||
|
$trustdaemon = 1;
|
||
|
$domainnamesplit = 0;
|
||
|
$recursive = 1;
|
||
|
|
||
|
######################################################################
|
||
|
# Programs and their options
|
||
|
|
||
|
$nslookup = "nslookup";
|
||
|
|
||
|
$ssh="ssh -a -c 3des -x -o 'ConnectionAttempts 1' -o 'FallBackToRsh no' -o 'GlobalKnownHostsFile /dev/null' -o 'KeepAlive yes' -o 'StrictHostKeyChecking no' -o 'UserKnownHostsFile $private_ssh_known_hosts'";
|
||
|
$sshdisablepasswordoption="-o 'BatchMode yes' -o 'PasswordAuthentication no'";
|
||
|
|
||
|
######################################################################
|
||
|
# Cleanup and initialization
|
||
|
|
||
|
unlink($private_ssh_known_hosts);
|
||
|
$sockaddr = 'S n a4 x8';
|
||
|
($junk, $junk, $sshport) = getservbyname("ssh", "tcp");
|
||
|
if (!defined($sshport)) {
|
||
|
$sshport = 22;
|
||
|
}
|
||
|
($tcpprotoname, $junk, $tcpproto) = getprotobyname('tcp');
|
||
|
defined($tcpprotoname) || die "getprotobyname : $!";
|
||
|
|
||
|
######################################################################
|
||
|
# Parse options
|
||
|
|
||
|
GetOptions("initialdns=s", "server=s", "subdomains=s",
|
||
|
"debug=i", "timeout=i", "passwordtimeout=i",
|
||
|
"trustdaemon!", "domainnamesplit", "silent",
|
||
|
"nslookup=s", "pingtimeout=i", "recursive!",
|
||
|
"keyscan",
|
||
|
"ssh=s")
|
||
|
|| die "Getopt : $!";
|
||
|
|
||
|
if (defined($opt_initialdns)) { $defserver = $opt_initialdns; }
|
||
|
|
||
|
if (defined($opt_server)) { $server = $opt_server; }
|
||
|
|
||
|
if (defined($opt_subdomains)) { @subdomains = split(/,/, $opt_subdomains); }
|
||
|
|
||
|
if (defined($opt_debug)) { $debug = $opt_debug; }
|
||
|
|
||
|
if (defined($opt_timeout)) { $timeout = $opt_timeout; }
|
||
|
|
||
|
if (defined($opt_pingtimeout)) { $ping_timeout = $opt_pingtimeout; }
|
||
|
|
||
|
if (defined($opt_passwordtimeout)) {
|
||
|
$passwordtimeout = $opt_passwordtimeout;
|
||
|
$sshdisablepasswordoption = '';
|
||
|
}
|
||
|
|
||
|
if (defined($opt_trustdaemon)) { $trustdaemon = $opt_trustdaemon; }
|
||
|
|
||
|
if (defined($opt_recursive)) { $recursive = $opt_recursive; }
|
||
|
|
||
|
if (defined($opt_domainnamesplit)) { $domainnamesplit = $opt_domainnamesplit; }
|
||
|
|
||
|
if (defined($opt_silent)) { $bell = ''; }
|
||
|
|
||
|
if (defined($opt_nslookup)) { $nslookup = $opt_nslookup; }
|
||
|
|
||
|
if (defined($opt_ssh)) { $ssh = $opt_ssh; } else {
|
||
|
$ssh = "$ssh $sshdisablepasswordoption";
|
||
|
}
|
||
|
|
||
|
if ($#ARGV == 0) {
|
||
|
$domain = "\L$ARGV[0]\E";
|
||
|
$grep_yes = '.*';
|
||
|
$grep_no = '^$';
|
||
|
} elsif ($#ARGV == 1) {
|
||
|
$domain = "\L$ARGV[0]\E";
|
||
|
$grep_yes = $ARGV[1];
|
||
|
$grep_no = '^$';
|
||
|
} elsif ($#ARGV == 2) {
|
||
|
$domain = "\L$ARGV[0]\E";
|
||
|
$grep_yes = $ARGV[1];
|
||
|
$grep_no = $ARGV[2];
|
||
|
} else {
|
||
|
print(STDERR "$0 [--initialdns initial_dns_server] [--server dns_server] [--subdomains sub.sub.domain,sub.sub,sub,] [--debug debug_level] [--timeout ssh_exec_timeout_in_secs] [--pingtimeout ping_timeout_in_secs] [--passwordtimeout timeout_for_password_in_secs] [--notrustdaemon] [--norecursive] [--domainnamesplit] [--silent] [--keyscan] [--nslookup path_to_nslookup] [--ssh path_to_ssh] full.domain [ host_info_take_regexp [ host_info_remove_regex ]]\n");
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
######################################################################
|
||
|
# Check that ssh program exists
|
||
|
|
||
|
if (system("$ssh > /dev/null 2>&1 ") != 256) {
|
||
|
print(STDERR "Error: Could not run ssh program ($ssh): $!\nError: Try giving the path to it with --ssh option\n");
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
######################################################################
|
||
|
# Generate subdomains list
|
||
|
|
||
|
if (!$domainnamesplit) {
|
||
|
debug(6, "Auto splitting host entries");
|
||
|
} elsif (!defined(@subdomains)) {
|
||
|
debug(6, "Generating subdomain list");
|
||
|
|
||
|
# split domain to pieces
|
||
|
@domain_pieces = split(/\./, $domain);
|
||
|
|
||
|
# add empty domain part
|
||
|
push(@subdomains, '');
|
||
|
|
||
|
# add rest parts, except the one before full domain name
|
||
|
$entry='';
|
||
|
for(; $#domain_pieces > 1; ) {
|
||
|
$entry .= "." . shift(@domain_pieces);
|
||
|
push(@subdomains, $entry);
|
||
|
}
|
||
|
|
||
|
# add full domain name
|
||
|
push(@subdomains, ".$domain");
|
||
|
debug(5, "Subdomain list: " . join(',', @subdomains));
|
||
|
} else {
|
||
|
debug(5, "Using given subdomain list:" . join(',', @subdomains));
|
||
|
}
|
||
|
|
||
|
######################################################################
|
||
|
# finding SOA entry for domain
|
||
|
|
||
|
@other_servers = ();
|
||
|
if (!defined($server)) {
|
||
|
debug(6, "Finding DNS database SOA entry");
|
||
|
|
||
|
($server, @other_servers) = find_soa($domain, $defserver);
|
||
|
|
||
|
if (!defined($server)) {
|
||
|
print(STDERR "Error: Could not find DNS SOA entry from default dns server\nError: Try giving the initial nameserver with --initialdns option\n");
|
||
|
exit(1);
|
||
|
} else {
|
||
|
debug(5, "DNS server found : $server");
|
||
|
}
|
||
|
} else {
|
||
|
debug(5, "Using given DNS server : $server");
|
||
|
}
|
||
|
|
||
|
######################################################################
|
||
|
# Print header
|
||
|
|
||
|
($name, $junk, $junk, $junk, $junk, $junk, $gecos) = getpwuid($<);
|
||
|
$gecos =~ s/,.*$//g;
|
||
|
|
||
|
if (!defined($opt_keyscan)) {
|
||
|
print(STDOUT "# This file is generated with make-ssh-known-hosts.pl\n");
|
||
|
print(STDOUT "#$version\n");
|
||
|
print(STDOUT "# with command line :\n");
|
||
|
print(STDOUT "# $command_line\n");
|
||
|
print(STDOUT "#\n");
|
||
|
print(STDOUT "# The script was run by $gecos ($name) at " . localtime() . "\n");
|
||
|
print(STDOUT "# using perl ($^X) version $].\n");
|
||
|
}
|
||
|
|
||
|
######################################################################
|
||
|
# Get DNS database list from server
|
||
|
|
||
|
do {
|
||
|
$domains_done{$domain} = 1;
|
||
|
delete $domains_waiting{$domain};
|
||
|
|
||
|
$hostcnt = 0;
|
||
|
$cnamecnt = 0;
|
||
|
$lines = 0;
|
||
|
$soa = 0;
|
||
|
undef %host;
|
||
|
undef %cname;
|
||
|
undef %hostdata;
|
||
|
|
||
|
dnsagain:
|
||
|
debug(1, "Getting DNS database for $domain from server $server");
|
||
|
open(DNS, "echo ls -d $domain | nslookup - $server 2>&1 |") ||
|
||
|
die "Error: Could not start nslookup to make dns list : $!\nError: Try giving --nslookup option and telling the path to nslookup program\n";
|
||
|
|
||
|
while(<DNS>) {
|
||
|
$lines++;
|
||
|
chomp;
|
||
|
undef $hostname if/^\s*$/;
|
||
|
if (/^\s{0,1}([a-zA-Z0-9-]\S*)/) {
|
||
|
$hostname = "\L$1\E";
|
||
|
}
|
||
|
next unless defined $hostname;
|
||
|
if (/^.*\s(SOA)\s+(.*)\s*$/ || $hostname eq "SOA") {
|
||
|
undef $soa if(/^.*\s(SOA)\s+(.*)\s*$/);
|
||
|
$data = $_ if ($hostname eq "SOA");
|
||
|
$data = $2 unless $hostname eq "SOA";
|
||
|
$data =~ s/\s*;.*$//;
|
||
|
$data =~ s/^\s+//;
|
||
|
if( defined $soa ) {
|
||
|
$soa .= " \L$data\E";
|
||
|
} else {
|
||
|
$soa = "\L$data\E";
|
||
|
}
|
||
|
$hostname = "SOA";
|
||
|
} elsif (/^.*\s(A|CNAME|NS)\s+(.*)\s*$/) {
|
||
|
$host = $hostname;
|
||
|
$field = "\L$1\E";
|
||
|
$data = "\L$2\E";
|
||
|
debug(70, "Line = /$host/$field/$data/");
|
||
|
if ($host !~ /\.$/) {
|
||
|
$host .= ".$domain";
|
||
|
} else {
|
||
|
$host =~ s/\.$//g;
|
||
|
}
|
||
|
if ($field eq "a") {
|
||
|
if ($host =~ /$domain$/) {
|
||
|
if (defined($host{$host})) {
|
||
|
$host{$host} .= ",$data";
|
||
|
} else {
|
||
|
$host{$host} = "$data";
|
||
|
$hostcnt++;
|
||
|
}
|
||
|
debug(30, "$host A == $host{$host}");
|
||
|
}
|
||
|
} elsif ($field eq "cname") {
|
||
|
if ($data !~ /\.$/ && ! /^\s/ ) {
|
||
|
$data .= ".$domain";
|
||
|
} else {
|
||
|
$data =~ s/\.$//g;
|
||
|
}
|
||
|
if ($host =~ /$domain$/) {
|
||
|
if (defined($cname{$data})) {
|
||
|
$cname{$data} .= ",$host";
|
||
|
} else {
|
||
|
$cname{$data} = "$host";
|
||
|
$cnamecnt++;
|
||
|
}
|
||
|
debug(30, "$host CNAME $data");
|
||
|
$junk = $data;
|
||
|
$data = $host;
|
||
|
$host = $junk;
|
||
|
}
|
||
|
} elsif ($field eq "ns") {
|
||
|
if (!defined($domains_done{$host})) {
|
||
|
if (!defined($domains_waiting{$host})) {
|
||
|
debug(10, "Adding subdomain $host to domains list, with NS $data");
|
||
|
$domains_waiting{$host} = $data;
|
||
|
push(@domains_waiting, $host);
|
||
|
} else {
|
||
|
debug(10, "Adding NS $data for domain $host");
|
||
|
$domains_waiting{$host} .= ",$data";
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (!defined($hostdata{$host})) {
|
||
|
$hostdata{$host} = "$host\n$field=$data\n";
|
||
|
} else {
|
||
|
$hostdata{$host} .= "$field=$data\n";
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
close(DNS);
|
||
|
if ($hostcnt == 0 && $cnamecnt == 0) {
|
||
|
if ($#other_servers != -1) {
|
||
|
$server = shift(@other_servers);
|
||
|
goto dnsagain;
|
||
|
}
|
||
|
}
|
||
|
debug(1, "Found $hostcnt hosts, $cnamecnt CNAMEs (total $lines lines)");
|
||
|
if (!defined($opt_keyscan)) {
|
||
|
print(STDOUT "#\n");
|
||
|
print(STDOUT "# Domain = $domain, server = $server\n");
|
||
|
print(STDOUT "# Found $hostcnt hosts, $cnamecnt CNAMEs (total $lines lines)\n");
|
||
|
print(STDOUT "# SOA = $soa\n");
|
||
|
print(STDOUT "#\n");
|
||
|
}
|
||
|
|
||
|
######################################################################
|
||
|
# Loop through hosts and try to connect to hosts
|
||
|
|
||
|
foreach $i (sort (keys %host)) {
|
||
|
debug(50, "Host = $i, Hostdata = $hostdata{$i}");
|
||
|
if ($hostdata{$i} =~ /$grep_yes/im &&
|
||
|
$hostdata{$i} !~ /$grep_no/im &&
|
||
|
$i !~ /^localhost\./ &&
|
||
|
$host{$i} !~ /^127.0.0.1$|^127.0.0.1,|,127.0.0.1$|,127.0.0.1,/) {
|
||
|
debug(2, "Trying host $i");
|
||
|
|
||
|
@hostnames = ();
|
||
|
if (defined($cname{$i})) {
|
||
|
expand($i, \@hostnames, \@subdomains);
|
||
|
foreach $j (split(/,/, $cname{$i})) {
|
||
|
expand($j, \@hostnames, \@subdomains);
|
||
|
}
|
||
|
} else {
|
||
|
expand($i, \@hostnames, \@subdomains);
|
||
|
}
|
||
|
foreach $j (split(/,/, $host{$i})) {
|
||
|
push(@hostnames, $j);
|
||
|
}
|
||
|
$hostnames = join(',', (@hostnames));
|
||
|
|
||
|
if (defined($opt_keyscan)) {
|
||
|
printf(STDOUT "$host{$i}\t$hostnames\n");
|
||
|
} elsif (try_ping($i, $host{$i})) {
|
||
|
$trusted = 1;
|
||
|
$err = 'Timeout expired';
|
||
|
$ssh_key = try_ssh("$i");
|
||
|
if (!defined($ssh_key)) {
|
||
|
$ssh_key = find_host_from_known_hosts($i);
|
||
|
$trusted = 0;
|
||
|
}
|
||
|
if (defined($ssh_key)) {
|
||
|
if ($trusted) {
|
||
|
debug(2, "Ssh to $i succeded");
|
||
|
} else {
|
||
|
debug(2, "Ssh to $i failed, using local known_hosts entry");
|
||
|
}
|
||
|
debug(4, "adding entries : $hostnames");
|
||
|
$ssh_key =~ s/root@//i;
|
||
|
if (!$trusted && !$trustdaemon) {
|
||
|
print(STDOUT "# $hostnames $ssh_key\n");
|
||
|
} else {
|
||
|
print(STDOUT "$hostnames $ssh_key\n");
|
||
|
}
|
||
|
} else {
|
||
|
debug(2, "ssh failed : $err");
|
||
|
}
|
||
|
} else {
|
||
|
debug(2, "ping failed");
|
||
|
}
|
||
|
} else {
|
||
|
debug(10, "Skipped host $i");
|
||
|
}
|
||
|
}
|
||
|
again:
|
||
|
$domain = shift(@domains_waiting);
|
||
|
if (defined($domain)) {
|
||
|
$server = $domains_waiting{$domain};
|
||
|
@other_servers = split(',', $server);
|
||
|
$server = shift(@other_servers);
|
||
|
($server, @other_servers) = find_soa($domain, $server);
|
||
|
if(!defined($server)) {
|
||
|
debug(1, "Skipping domain $domain because no DNS SOA entry found");
|
||
|
$domains_done{$domain} = 1;
|
||
|
delete $domains_waiting{$domain};
|
||
|
goto again;
|
||
|
}
|
||
|
}
|
||
|
} while ($recursive && defined($domain));
|
||
|
|
||
|
unlink($private_ssh_known_hosts);
|
||
|
exit (0);
|
||
|
|
||
|
######################################################################
|
||
|
# try_ping -- try to ping to host and return 1 if success
|
||
|
# $success = try_ping($host, $list_ip_addrs);
|
||
|
|
||
|
sub try_ping {
|
||
|
my($host, $ipaddrs) = @_;
|
||
|
my(@ipaddrs, $ipaddr, $serv, $ip);
|
||
|
my($rin, $rout, $win, $wout, $nfound, $tmout, $buf, $len, $ret, $err);
|
||
|
|
||
|
$buf = '';
|
||
|
debug(51,"Trying to ping host $host");
|
||
|
@ipaddrs = split(/,/, $ipaddrs);
|
||
|
|
||
|
while ($ipaddr = shift(@ipaddrs)) {
|
||
|
|
||
|
debug(55,"Trying ipaddr $ipaddr");
|
||
|
|
||
|
#initialize socket
|
||
|
socket(PING, PF_INET, SOCK_STREAM, $tcpproto) ||
|
||
|
die "socket failed : $!";
|
||
|
setsockopt(PING, SOL_SOCKET, SO_REUSEADDR, 1) ||
|
||
|
die "setsockopt failed : $!";
|
||
|
PING->autoflush(1);
|
||
|
fcntl(PING, F_SETFL, fcntl(PING, F_GETFL, 0) | POSIX::O_NONBLOCK) ||
|
||
|
die "fcntl failed : $!";
|
||
|
|
||
|
$ip = pack('C4', split(/\./, $ipaddr, 4));
|
||
|
$serv = pack($sockaddr, AF_INET, $sshport, $ip);
|
||
|
|
||
|
again:
|
||
|
# try connect
|
||
|
$ret = connect(PING, $serv);
|
||
|
$err = $!;
|
||
|
if (!$ret) {
|
||
|
debug(60, "Connect failed : $err");
|
||
|
if ($err == EINTR) {
|
||
|
goto again;
|
||
|
}
|
||
|
# socket not yet connected, wait for result, it will
|
||
|
# wake up for writing when done
|
||
|
$tmout = $ping_timeout;
|
||
|
|
||
|
$rin = '';
|
||
|
$win = '';
|
||
|
vec($rin, fileno(PING), 1) = 1;
|
||
|
vec($win, fileno(PING), 1) = 1;
|
||
|
debug(60, "Waiting in select, rin = " . unpack('H*', $rin) .
|
||
|
", win = " . unpack('H*', $win));
|
||
|
($nfound) = select($rout = $rin, $wout = $win, undef, $tmout);
|
||
|
$err = $!;
|
||
|
debug(80, "Select returned $nfound, rout = " . unpack('H*', $rout) .
|
||
|
", wout = " . unpack('H*', $wout));
|
||
|
if ($nfound != 0) {
|
||
|
# connect done, read the status with sysread
|
||
|
$ret = sysread(PING, $buf, 1);
|
||
|
$err = $!;
|
||
|
if (defined($ret) || $err == EAGAIN || $err == EWOULDBLOCK) {
|
||
|
debug(60, "Select ok, read ok ($err), returning ok");
|
||
|
# connection done, return ok
|
||
|
shutdown(PING, 2);
|
||
|
close(PING);
|
||
|
return 1;
|
||
|
} else {
|
||
|
# connection failed, try next ipaddr
|
||
|
debug(60, "Select ok, read failed : $err, trying next");
|
||
|
close(PING);
|
||
|
}
|
||
|
} else {
|
||
|
# timeout exceeded, try next ipaddr
|
||
|
debug(60, "Select failed : $err, trying next");
|
||
|
close(PING);
|
||
|
}
|
||
|
} else {
|
||
|
# connect succeeded, return ok.
|
||
|
debug(60, "Connect ok, returning ok");
|
||
|
shutdown(PING, 2);
|
||
|
close(PING);
|
||
|
return 1;
|
||
|
}
|
||
|
}
|
||
|
debug(60, "Returning fail");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
######################################################################
|
||
|
# try_ssh -- try ssh connection to host and return ssh_key if success
|
||
|
# if failure return undef, and set $err string to contain error message.
|
||
|
# $ssh_key = try_ssh($host);
|
||
|
|
||
|
sub try_ssh {
|
||
|
my($host) = @_;
|
||
|
my($buf, $ret, $pos, $pid, $rin, $nfound, $tmout);
|
||
|
|
||
|
$pid = open(SSH, "$ssh $host cat $public_key 2>&1 |");
|
||
|
$err = undef;
|
||
|
|
||
|
if ($pid == 0) {
|
||
|
$err = "could not open ssh connection to host";
|
||
|
return undef;
|
||
|
}
|
||
|
$ret = 1;
|
||
|
$pos = 0;
|
||
|
$buf = '';
|
||
|
$tmout = $timeout;
|
||
|
debug(10, "Starting ssh select loop");
|
||
|
loop:
|
||
|
while (1) {
|
||
|
|
||
|
$rin = '';
|
||
|
vec($rin, fileno(SSH), 1) = 1;
|
||
|
($nfound, $tmout) = select($rin, undef, undef, $tmout);
|
||
|
|
||
|
# Timeout
|
||
|
if ($nfound <= 0) {
|
||
|
debug(20, "Ssh select timed out");
|
||
|
kill(2, $pid); sleep(1); kill(9, $pid);
|
||
|
close(SSH);
|
||
|
$err = "Timeout expired";
|
||
|
return undef;
|
||
|
}
|
||
|
|
||
|
$ret = sysread(SSH, $buf, 256, $pos);
|
||
|
# EOF or error
|
||
|
if ($ret <= 0) {
|
||
|
# Yes, close the pipe and return
|
||
|
close(SSH);
|
||
|
debug(20, "Ssh select closed status = $?");
|
||
|
$err = "No reply from ssh";
|
||
|
return undef;
|
||
|
}
|
||
|
$pos += $ret;
|
||
|
while ($buf =~ /^(.*)\n\r?([\000-\377]*)$/) {
|
||
|
$_ = $1;
|
||
|
$buf = $2;
|
||
|
$pos = length($buf);
|
||
|
debug(20, "Ssh select loop, line = \"$_\"");
|
||
|
if (/^connection.*refused/i) {
|
||
|
$err = "connection refused";
|
||
|
} elsif (/^permission/i) {
|
||
|
$err = "permission denied";
|
||
|
} elsif (/$public_key.*no\s+file/i) {
|
||
|
$err = "$public_key file not found";
|
||
|
} elsif (/$public_key.*permission\s+denied/i) {
|
||
|
$err = "$public_key file permission denied";
|
||
|
} elsif (/^\d+\s+\d+\s+\d/) {
|
||
|
kill(2, $pid); sleep(1); kill(9, $pid);
|
||
|
close(SSH);
|
||
|
return $_;
|
||
|
}
|
||
|
if (defined($err)) {
|
||
|
kill(2, $pid); sleep(1); kill(9, $pid);
|
||
|
close(SSH);
|
||
|
return undef;
|
||
|
}
|
||
|
}
|
||
|
if ($buf =~ /password: $/i) {
|
||
|
if (defined($passwordtimeout)) {
|
||
|
$tmout = $passwordtimeout;
|
||
|
print(STDERR "$bell\n\rPassword: ");
|
||
|
if ($tmout == 0) {
|
||
|
$tmout = undef;
|
||
|
}
|
||
|
} else {
|
||
|
$tmout = 0;
|
||
|
}
|
||
|
$buf = '';
|
||
|
$pos = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
######################################################################
|
||
|
# find_hosts_from_known_hosts -- find host key from private known_hosts file
|
||
|
# $ssh_key = find_host_from_known_hosts($host);
|
||
|
|
||
|
sub find_host_from_known_hosts {
|
||
|
my($host) = @_;
|
||
|
open(KNOWNHOSTS, "<$private_ssh_known_hosts") || return undef;
|
||
|
while(<KNOWNHOSTS>) {
|
||
|
@_ = split(/\s+/, $_);
|
||
|
if ($_[0] =~ /^$host$|^$host,|,$host$/) {
|
||
|
shift(@_);
|
||
|
close(KNOWNHOSTS);
|
||
|
return join(' ', @_);
|
||
|
}
|
||
|
}
|
||
|
close(KNOWNHOSTS);
|
||
|
return undef;
|
||
|
}
|
||
|
|
||
|
######################################################################
|
||
|
# expand -- insert expanded hostnames to hostnames table
|
||
|
# expand($hostname, \@hostnames, \@subdomains);
|
||
|
|
||
|
sub expand {
|
||
|
my($host, $hostnames, $subdomains) = @_;
|
||
|
my($newhost, $sub, $entry);
|
||
|
|
||
|
if (!$domainnamesplit) {
|
||
|
my(@domain_pieces);
|
||
|
|
||
|
# split domain to pieces
|
||
|
@domain_pieces = split(/\./, $host);
|
||
|
|
||
|
# add rest parts, except the one before full domain name
|
||
|
$entry = shift(@domain_pieces);
|
||
|
|
||
|
debug(20, "Adding autosplit entry $entry");
|
||
|
push(@$hostnames, $entry);
|
||
|
|
||
|
for(; $#domain_pieces > 1; ) {
|
||
|
$entry .= "." . shift(@domain_pieces);
|
||
|
debug(20, "Adding autosplit entry $entry");
|
||
|
push(@$hostnames, $entry);
|
||
|
}
|
||
|
# add full domain name
|
||
|
debug(20, "Adding autosplit entry $host");
|
||
|
push(@$hostnames, $host);
|
||
|
} else {
|
||
|
if ($host =~ /^(.*)$domain$/i) {
|
||
|
$newhost = $1;
|
||
|
$newhost =~ s/\.$//g;
|
||
|
foreach $sub (@$subdomains) {
|
||
|
$entry = $newhost . $sub;
|
||
|
$entry =~ s/^\.//g;
|
||
|
if ($entry ne '') {
|
||
|
debug(20, "Adding entry $entry");
|
||
|
push(@$hostnames, $entry);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
######################################################################
|
||
|
# Print debug text
|
||
|
# debug(text_debug_level, string)
|
||
|
|
||
|
sub debug {
|
||
|
my($level, $str) = @_;
|
||
|
if ($debug > $level) {
|
||
|
print(STDERR "$0:debug[$level]: $str\n");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
######################################################################
|
||
|
# find_soa -- find soa entry for domain
|
||
|
# ($soa_origin, @other_servers) = find_soa($domain, $initial_server)
|
||
|
|
||
|
sub find_soa {
|
||
|
my($domain, $initial_server) = @_;
|
||
|
my($field, $data, $server, @other_servers);
|
||
|
|
||
|
open(DNS, "$nslookup -type=soa $domain $initial_server 2>&1 |") ||
|
||
|
die "Error: Could not start nslookup to find SOA entry for $domain : $!\nError: Try giving the path to it with --nslookup option\n";
|
||
|
|
||
|
while (<DNS>) {
|
||
|
if (/^[^=]*origin\s*=\s*(.*)/) {
|
||
|
$server = $1;
|
||
|
debug(10, "Found origin : $1");
|
||
|
} elsif (/^[^=]*nameserver\s*=\s*(.*)\s*$/) {
|
||
|
push(@other_servers, $1);
|
||
|
debug(10, "Found nameserver : $1");
|
||
|
}
|
||
|
}
|
||
|
close(DNS);
|
||
|
return($server, @other_servers);
|
||
|
}
|
||
|
|
||
|
######################################################################
|
||
|
# make_perl_happy -- use some symbols, so perl doesn't complain so much
|
||
|
# make_perl_happy();
|
||
|
|
||
|
sub make_perl_happy {
|
||
|
if (0) {
|
||
|
print $opt_silent;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
1;
|