#!/usr/bin/perl # comp-host-list : compare two runs of ssh keys # Usage: comp-host-list old_known_host_file new_known_host_file # This will tell you the differences between your present known_hosts file # and one that may have been collected with, for example, ssh-keyscan. # # Differences are reported on standard error. If you supply the "-l" option, # a new, combined, file is generated on standard output. # Normally, a host which has changed its keys will not be included in # the list; this can be overridden with the "-c" - option. DANGER: # A host which has changed its key may be an indication of a man in # the middle attack. # # The "-o" option will warn you about hosts which are present in the # 'old' host file, but not in the new one; usually, this is caused # by hosts being down during a scan run, and is no cause for alarm. # # Written by Thomas.Koenig@ciw.uni-karlsruhe.de # This code is in the public domain # $Id: comp-host-list,v 1.3 1996/02/25 19:57:02 ig25 Exp $ require 'getopts.pl'; &Getopts("olc"); &usage unless @ARGV == 2; $oldfile = shift; $newfile = shift; open (OLDFILE,"$oldfile") || die ("Cannot open $oldfile\n"); open (NEWFILE,"$newfile") || die ("Cannot open $newfile\n"); while () { chop; s/\#.*//; next if /^\s*$/; ($names, $bits, $exp, $mantissa) = split(' ',$_); @namelist = split(/,/,$names); @iplist = &sort_ip(grep (/^\d+\.\d+\.\d+\.\d+$/, @namelist)); $canon_ip = @iplist[0]; $old_bits{$canon_ip} = $bits; $old_exp{$canon_ip} = $exp; $old_mantissa{$canon_ip} = $mantissa; $old_line{$canon_ip} = $_; } while () { chop; s/\#.*//; next if /^\s*$/; ($names, $bits, $exp, $mantissa) = split(' ',$_); @namelist = split(/,/,$names); @iplist = &sort_ip(grep (/^\d+\.\d+\.\d+\.\d+$/, @namelist)); $canon_ip = @iplist[0]; $new_bits{$canon_ip} = $bits; $new_exp{$canon_ip} = $exp; $new_mantissa{$canon_ip} = $mantissa; $new_line{$canon_ip} = $_; } for (keys %new_line) { if (!defined $old_line{$_}) { print STDERR "NEWHOST: $new_line{$_}\n"; next; } if (($new_bits{$_} != $old_bits{$_}) || ($new_exp{$_} != $old_exp{$_}) || $new_mantissa{$_} ne $old_mantissa{$_}) { print STDERR "CHANGEKEY: $_ changed key from $old_line{$_} to $new_line{$_}\n"; delete $new_line{$_} unless $opt_c; } delete $old_line{$_}; } for (keys %old_line) { if ($opt_d) { print STDERR "OFFLINE: ${_} $old_line{$_}\n"; } $new_line{$_} = $old_line{$_}; } if ($opt_l) { for (&sort_ip (keys %new_line)) { print "$new_line{$_}\n"; } } sub usage { print STDERR "Usage: $0 [-olc] known_hosts.old known_hosts.new\n"; print STDERR "\t-o: warn about hosts which are offline\n"; print STDERR "\t-l: list combined hosts to standard output\n"; print STDERR "\t-c: also include hosts which have changed their keys (DANGEROUS)\n"; exit(1); } sub sort_ip { local(@ip_list) = @_; local(@ip_pack) = (); local(@vals); foreach $ip (@ip_list) { push(@ip_pack, pack("CCCC", split(/\./,$ip,4))); } @ip_pack = sort @ip_pack; @ip_list = (); foreach $packed_ip(@ip_pack) { push(@ip_list, join(".", unpack("C4", $packed_ip))); } return @ip_list; }