222 lines
6.9 KiB
Plaintext
222 lines
6.9 KiB
Plaintext
|
#!/bin/bash
|
||
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||
|
source "$(dirname "$0")/ulib/ulib" || exit 1
|
||
|
urequire DEFAULTS
|
||
|
|
||
|
function display_help() {
|
||
|
uecho "$scriptname: se connecter par ssh à un ou plusieurs hôtes
|
||
|
|
||
|
USAGE
|
||
|
$scriptname [options] hosts
|
||
|
$scriptname [options] @hostsfile
|
||
|
$scriptname -r hosts
|
||
|
|
||
|
OPTIONS
|
||
|
hosts
|
||
|
@hostsfile
|
||
|
Spécifier un ou plusieurs hôtes distants sur lequels faire la connexion.
|
||
|
Pour spécifier plusieurs hôtes, il faut les séparer par un espace ou le
|
||
|
caractère ':', e.g. 'host1 host2' ou 'host1:host2'. Si la spécification
|
||
|
contient les caractères { et }, l'expansion est effectuée, e.g
|
||
|
'root@{host1,host2}.univ.run'
|
||
|
La forme @hostsfile permet de lire la liste des hôtes depuis le fichier
|
||
|
hostsfile, à raison d'un hôte par ligne.
|
||
|
|
||
|
Toutes les options de ssh sont reconnues. Les options longues suivantes sont
|
||
|
reconnues comme alias de certaines options courtes de ssh:
|
||
|
--quiet
|
||
|
alias de -q, activer le mode non verbeux
|
||
|
--tty
|
||
|
alias de -t, forcer l'allocation d'un TTY
|
||
|
--login USER
|
||
|
alias de -l, spécifier le user avec lequel se connecter
|
||
|
--port PORT
|
||
|
alias de -p, spécifier le port sur lequel se connecter
|
||
|
|
||
|
Les options suivantes sont exclusives à ce script:
|
||
|
-d, --domain DOMAIN
|
||
|
Spécifier un domaine par défaut pour les hôtes qui sont spécifiés sans
|
||
|
domaine.
|
||
|
-z, --ssh SSH
|
||
|
Spécifier l'exécutable à utiliser pour lancer ssh.
|
||
|
-r, --remove
|
||
|
Lancer 'ssh-keygen -R' pour chacun des hôtes spécifiés avant de s'y
|
||
|
connecter. Par exemple:
|
||
|
$scriptname -r host.tld
|
||
|
est équivalent à:
|
||
|
ssh-keygen -R host.tld
|
||
|
ssh-keygen -R host
|
||
|
ssh-keygen -R 10.10.1.5
|
||
|
ssh host.tld
|
||
|
si l'adresse ip de host.tld est 10.10.1.5
|
||
|
Quand cette option est spécifié, l'option -j est reconnue et permet de
|
||
|
NE PAS se reconnecter à l'hôte juste après avoir nettoyé les clés. Avec
|
||
|
l'option -j, TOUS les arguments sont des noms d'hôte puisqu'aucune
|
||
|
connexion n'est effectuée."
|
||
|
}
|
||
|
|
||
|
__PARSED_HOSTS=()
|
||
|
__PARSED_FILES=()
|
||
|
function parse_hostsfile() {
|
||
|
# Lire chacun des fichiers $* et initialiser __PARSED_HOSTS avec la liste
|
||
|
# des hôtes mentionnés dans les fichiers.
|
||
|
local inputfile basedir inputs input
|
||
|
for inputfile in "$@"; do
|
||
|
inputfile="$(abspath "$inputfile")"
|
||
|
array_contains __PARSED_FILES "$inputfile" && {
|
||
|
ewarn "$(ppath "$inputfile"): inclusion récursive"
|
||
|
continue
|
||
|
}
|
||
|
array_add __PARSED_FILES "$inputfile"
|
||
|
basedir="$(dirname "$inputfile")"
|
||
|
|
||
|
array_from_lines inputs "$(<"$inputfile" filter_conf)" || {
|
||
|
ewarn "$inputfile: fichier ingnoré"
|
||
|
continue
|
||
|
}
|
||
|
for input in "${inputs[@]}"; do
|
||
|
if [ "${input#@}" != "$input" ]; then
|
||
|
# fichier inclus
|
||
|
parse_hostsfile "$(abspath "${input#@}" "$basedir")"
|
||
|
else
|
||
|
array_addu __PARSED_HOSTS "$input"
|
||
|
fi
|
||
|
done
|
||
|
done
|
||
|
}
|
||
|
function __expand_braces() {
|
||
|
if [[ "$1" == *{* ]] && [[ "$1" == *}* ]]; then
|
||
|
eval "echo $1"
|
||
|
else
|
||
|
echo "$1"
|
||
|
fi
|
||
|
}
|
||
|
function __dot_is_localhost() { [ "$1" == "." ] && echo "localhost." || echo "$1"; }
|
||
|
function fix_hosts() {
|
||
|
# Si hosts contient des éléments multiple, comme a:b, séparer ces
|
||
|
# éléments. i.e (a b:c "d e") --> (a b c d e)
|
||
|
# Supporter la syntaxe @hostsfile qui permet de charger la liste des hôtes
|
||
|
# depuis un fichier.
|
||
|
# Remplacer aussi les '.' par 'localhost'
|
||
|
array_map hosts __expand_braces
|
||
|
array_fix_paths hosts ":"
|
||
|
array_fix_paths hosts " "
|
||
|
|
||
|
local -a _hosts _tmphosts host
|
||
|
for host in "${hosts[@]}"; do
|
||
|
host="${host%/}"
|
||
|
if [ "${host#@}" != "$host" ]; then
|
||
|
__PARSED_HOSTS=()
|
||
|
parse_hostsfile "${host#@}"
|
||
|
array_fix_paths __PARSED_HOSTS
|
||
|
array_extendu _hosts __PARSED_HOSTS
|
||
|
else
|
||
|
array_addu _hosts "$host"
|
||
|
fi
|
||
|
done
|
||
|
array_copy hosts _hosts
|
||
|
array_map hosts __dot_is_localhost
|
||
|
}
|
||
|
|
||
|
function remove_key() {
|
||
|
estep "$1"
|
||
|
ssh-keygen -R "$1" >&/dev/null
|
||
|
}
|
||
|
function remove_keys() {
|
||
|
urequire ipcalc
|
||
|
|
||
|
local -a __hosts; array_copy __hosts hosts
|
||
|
local -a allhosts hosts ips; local host user ip
|
||
|
array_copy allhosts __hosts
|
||
|
|
||
|
etitle "Suppression des entrées dans ~/.ssh/known_hosts"
|
||
|
for host in "${allhosts[@]}"; do
|
||
|
splituserhost "$host" user host
|
||
|
if [ "${host%.}" != "$host" ]; then
|
||
|
host="${host%.}"
|
||
|
elif ! [[ "$host" == *.* ]]; then
|
||
|
host="$host${DOMAIN:+.$DOMAIN}"
|
||
|
fi
|
||
|
|
||
|
if ipcalc_checkip "$host" >/dev/null; then
|
||
|
ip="$host"
|
||
|
remove_key "$ip"
|
||
|
|
||
|
resolv_hosts hosts "$ip"
|
||
|
for host in "${hosts[@]}"; do
|
||
|
remove_key "$host"
|
||
|
hostname="${host%%.*}"
|
||
|
[ "$hostname" != "$host" ] && remove_key "$hostname"
|
||
|
done
|
||
|
else
|
||
|
remove_key "$host"
|
||
|
hostname="${host%%.*}"
|
||
|
[ "$hostname" != "$host" ] && remove_key "$hostname"
|
||
|
|
||
|
resolv_ips ips "$host"
|
||
|
for ip in "${ips[@]}"; do
|
||
|
remove_key "$ip"
|
||
|
done
|
||
|
fi
|
||
|
done
|
||
|
eend
|
||
|
}
|
||
|
|
||
|
function do_ssh() {
|
||
|
[ -n "$SSH" ] || SSH=ssh
|
||
|
[ "${#hosts[*]}" -gt 1 ] && showtitle=1 || showtitle=
|
||
|
for host in "${hosts[@]}"; do
|
||
|
splituserhost "$host" user host
|
||
|
if [ "${host%.}" != "$host" ]; then
|
||
|
host="${host%.}"
|
||
|
elif ! [[ "$host" == *.* ]]; then
|
||
|
host="$host${DOMAIN:+.$DOMAIN}"
|
||
|
fi
|
||
|
|
||
|
[ -n "$showtitle" ] && etitle "${user:+$user@}$host"
|
||
|
"$SSH" "${SSHOPTS[@]}" "${user:+$user@}$host" "$@"
|
||
|
[ -n "$showtitle" ] && eend
|
||
|
done
|
||
|
}
|
||
|
|
||
|
set_defaults nutools
|
||
|
SSHOPTS=(${USSH_USER:+-l "$USSH_USER"}) # options de ssh
|
||
|
function sshopt() { SSHOPTS=("${SSHOPTS[@]}" "$@"); }
|
||
|
|
||
|
DOMAIN="$USSH_DOMAIN"
|
||
|
SSH=
|
||
|
remove=
|
||
|
remove_only=
|
||
|
parse_opts "${PRETTYOPTS[@]}" \
|
||
|
--help '$exit_with display_help' \
|
||
|
-1,-2,-4,-6,-A,-a,-C,-f,-g,-K,-k,-M,-N,-n,-q,-s,-T,-t,-V,-v,-X,-x,-Y,-y '$sshopt "$option_"' \
|
||
|
-b:,-c:,-D:,-e:,-F:,-I:,-i:,-L:,-l:,-m:,-O:,-o:,-p:,-R:,-S:,-W:,-w: '$sshopt "$option_" "$value_"' \
|
||
|
--quiet '$sshopt -q' \
|
||
|
--tty '$sshopt -t' \
|
||
|
--login: '$sshopt -l "$value_"' \
|
||
|
--port: '$sshopt -p "$value_"' \
|
||
|
-d:,--domain: DOMAIN= \
|
||
|
-z:,--ssh: SSH= \
|
||
|
-r,--remove remove=1 \
|
||
|
-j remove_only=1 \
|
||
|
@ args -- "$@" && set -- "${args[@]}" || die "$args"
|
||
|
|
||
|
if [ -n "$remove" ]; then
|
||
|
[ -n "$*" ] || die "Vous devez spécifier les hôtes à supprimer de ~/.ssh/known_hosts"
|
||
|
if [ -n "$remove_only" ]; then
|
||
|
hosts=("$@")
|
||
|
fix_hosts
|
||
|
remove_keys
|
||
|
exit 0
|
||
|
fi
|
||
|
|
||
|
hosts=("$1"); shift
|
||
|
fix_hosts
|
||
|
remove_keys
|
||
|
else
|
||
|
hosts=("$1"); shift
|
||
|
fix_hosts
|
||
|
fi
|
||
|
|
||
|
do_ssh "$@"
|