Utilisez deux adresses IP différentes par hôte dans SSH

23

J'ai un serveur, nommé gamma, constamment opérationnel et au travail. Parfois, je m'y connecte depuis chez moi, auquel cas j'utilise l'adresse IP publique 55.22.33.99. Parfois, je me connecte à quand je suis au travail, et plutôt que de rebondir mes paquets autour inutilement, je me connecte via l'adresse IP locale, 192.168.1.100.

Pour le moment, je les ai divisés en deux entrées différentes dans ~/.ssh/conf

Host gamma-local
        HostName 192.168.1.100
        Port 22
        User andreas

Host gamma-remote
        HostName 55.22.33.99
        Port 12345
        User andreas

Donc, si je suis au travail, tout ce que je dois taper est ssh gamma-localet je suis; si je suis à la maison (ou ailleurs dans le monde), je cours ssh gamma-remote.

Lors de la connexion au serveur, je préfère ne pas avoir à taper un nom différent selon l'endroit où je suis, je préfère que la partie se fasse automatiquement; par exemple, dans certains cas, j'ai des scripts automatisés qui se connectent sans savoir où je suis.

Il y a une question qui résout ce problème en utilisant un script Bash pour "essayer" de se connecter d'abord au local, et s'il ne se connecte pas, essayez de vous connecter à l'adresse IP distante. C'est bien, mais (1) semble inefficace (d'autant plus que parfois vous devez "attendre" que les connexions expirent car elles ne renvoient pas toujours immédiatement une erreur) et (2) nécessite Bash et traîner le script.

Existe-t-il un autre moyen d'y parvenir qui ne repose pas sur l'utilisation de scripts Bash, ni sur des "tests" pour voir si la connexion fonctionne en premier?

IQAndreas
la source
Ce que j'essaie de savoir, c'est si on peut jouer avec /etc/hostsou le fichier de configuration SSH pour y parvenir? Ou peut-être un moyen de "détecter" le LAN auquel vous êtes actuellement connecté?
IQAndreas du
Avez-vous un ensemble distinct de serveurs de noms utilisés par votre réseau de bureau?
Sree
@Sree Ah, je vois où tu vas avec ça; intelligent! Nous n'exécutons pas de serveur de noms pour le moment, mais je pourrais certainement convertir l'une des machines en une seule.
IQAndreas
@Sree N'hésitez pas à élaborer et à ajouter cela comme une réponse qui commence par la ligne "Si vous avez un serveur de noms sur votre réseau de bureau ..."
IQAndreas
Fait ça. N'hésitez pas à voter haut / bas :)
Sree

Réponses:

28

Si vous avez un moyen de reconnaître le réseau sur lequel vous vous trouvez, vous pouvez utiliser le Matchmot - clé ~/.ssh/configpour faire ce que vous voulez. Cela nécessite OpenSSH ≥6,5.

J'utilise quelque chose de similaire à

Match originalhost gamma exec "[ x$(/sbin/iwgetid --scheme) != xMyHomeESSID ]"
  HostName 192.168.1.100
  Port 22

Host gamma
  User andreas
  Port 12345
  HostName 55.22.33.99

J'utilise donc l'identifiant du réseau wifi utilisé pour décider si je suis à la maison aux fins de la connexion SSH, mais la vérification de l'adresse IP attribuée à votre ordinateur ou de toute autre chose qui différencie les deux réseaux peut également être utilisée .

Michał Politowski
la source
+1 utilisation intelligente de Match, merci! Il pourrait être judicieux d'envelopper la détection dans un script sortant avec un état de sortie nul ou non nul, car cela le rendrait réutilisable.
peterph
@peterph, il pourrait certainement être résumé dans un script externe, mais je n'avais besoin que d'un seul endroit jusqu'à présent, donc la règle des trois n'a pas encore été mise en place.
Michał Politowski
Que se passerait-il si vous étiez au travail, mais que vous souhaitez réellement vous connecter à une autre machine? La déclaration exec ne correspondrait-elle pas puisque vous n'êtes pas en WiFi avec votre HomeESSID, et donc définir le nom d'hôte sur 192.168.1.100?
disparu
@ disparu, je ne comprends pas la question. Le match est également sur l'hôte cible.
Michał Politowski
1
@typelogic Pas facilement, pour autant que je sache. Vous pourriez essayer d'utiliser ProxyCommand nc $address ssh, mais alors par exemple. tous les appareils ont-ils la même clé d'hôte? Si vous devez de toute façon définir une variable d'environnement, ne sera-t-il pas plus facile de simplement donner l'adresse à laquelle se connecter directement comme argument ssh?
Michał Politowski
5

Si vous avez un serveur de noms privé au travail et si vous utilisez le même ordinateur portable au bureau et à la maison, vous pouvez en profiter pour y parvenir:

  1. Modifiez votre nsswitch.confdans votre machine pour enregistrer le DNS en premier
  2. Créez une entrée DNS pour gammarésoudre en 192.168.1.100 dans votre DNS privé au bureau.
  3. Créez une entrée dans le fichier / etc / hosts de votre machine à résoudre gammaen 55.22.33.99.

De cette façon, lorsque vous ssh gammapartirez du bureau, il résoudra du DNS du bureau vers le 192.168.1.100 et lorsque vous vous connectez depuis votre domicile, il se résoudra en 55.22.33.99 à partir de votre fichier d'hôtes.

PS : Cette réponse suppose que vous ne voulez pas que gamma ait une entrée DNS publique. De plus, si vous vous connectez à votre serveur à partir d'une machine Windows, je pense qu'il devrait y avoir un endroit équivalent au fichier nssswitch.conf pour remplacer les entrées du fichier hôtes.

Sree
la source
Il y a - c'est le fichier hosts. Et c'est exactement comme ça que je le fais - quand à la maison mon domaine public se résout à mon adresse IP locale. Excellente réponse - c'était aussi la première chose à laquelle j'ai pensé. Eh bien ... c'est-à-dire aujourd'hui, quand je l'ai installé il y a quelques années, j'ai dû beaucoup chercher sur Google pour trouver une solution.
mikeserv
2

Je ne sais pas s'il est possible de le faire, ~/.ssh/configmais une autre approche serait de se connecter à l'un ou à l'autre en fonction de votre adresse IP externe. Étant donné que, probablement, lorsque vous êtes au travail, votre adresse IP sera 55.22.33.NNN, vous pouvez exécuter quelque chose comme:

[[ $(wget -qO - http://wtfismyip.com/text) =~ ^'55.22.33.' ]] && 
    ssh 192.168.1.100 ||
    ssh -p 12345 55.22.33.99

Une approche encore plus simple consiste à utiliser votre adresse IP interne. Je ne sais pas comment vos deux réseaux sont configurés, mais s'il est facile de déterminer si vous êtes au travail ou non via votre IP (par exemple, si vous avez une IP spécifique au travail, par exemple 192.168.1.12), vous pouvez le faire ( changer eth0le nom de votre carte réseau):

[[ $(ip address show dev eth0 | grep -Po 'inet \K[\d.]+') = '192.168.1.12' ]] && 
    ssh 192.168.1.100 ||
    ssh -p 12345 55.22.33.99

Quelle que soit votre décision, vous pouvez l'ajouter en tant qu'alias à votre shell (ajoutez cette ligne au fichier d'initialisation de votre shell, ~/.bashrcsi vous utilisez bash):

alias gamma="[[ $(wget -qO - http://wtfismyip.com/text) =~ ^'55.22.33.' ]] && ssh 192.168.1.100 || ssh -p 12345 55.22.33.99

Vous pouvez également en faire un script si vous souhaitez que d'autres scripts y aient accès (les alias de .bashrcne sont pas lus lors de l'exécution d'un script).

terdon
la source
2

Vous ne pouvez pas y parvenir ~/.ssh/configlorsque vous utilisez des adresses IP comme noms d'hôtes. Une complication supplémentaire est introduite par le fait que vous ne vous connectez pas seulement à différentes adresses IP mais également à différents ports, car cela exclut à peu près tout ajustement de votre résolveur DNS.

Je suis corrigé - vous pouvez utiliser le Match originalhost ... exec ...combo dans ~/.ssh/config- voir la réponse de @ MichałPolitowski . Cependant, même si cela fonctionnera parfaitement pour OpenSSH, vous ne trouverez pas nécessairement des fonctionnalités similaires dans d'autres clients SSH.

Vous pouvez contourner le problème à l'aide d'un simple wrapper (soit une fonction shell ou un script si vous devez l'utiliser à partir de différents shells) ssh, qui vérifiera sur quel réseau vous êtes et utilisera l' Hostentrée appropriée . La grande question est de savoir comment détecter de manière fiable le réseau sur lequel vous vous trouvez. L'adresse IP locale vient à l'esprit, mais n'est pas fiable, car vous pouvez également vous connecter à partir d'un LAN qui utilise le même sous-réseau que votre réseau de travail.

Si vous pouvez avoir le même port pour les réseaux locaux et distants, vous pouvez modifier votre en /etc/resolv.conffonction du réseau sur lequel vous vous trouvez - cela devrait évidemment être fait automatiquement (très probablement à partir d'un script de raccordement de votre client DHCP). Ou - mieux - exécutez le serveur de noms local (comme par exemple dnsmasq) et fournissez-lui la configuration appropriée. Cela dépasse cependant la portée de cette question.

Une autre option - si vous avez seulement besoin de vous connecter de manière interactive - consiste à utiliser la complétion de commande qui scannerait ~/.ssh/config. Cela vous éviterait de taper (surtout si vous avez suffisamment d' Hostentrées variables ). Quelque chose comme ça (pour l' bashinitialisation):

# complete session names for ssh
declare -g _ssh_complete_hostlist 2> /dev/null
function _ssh_complete_init () {
    _ssh_complete_hostlist=$( \
        sed -nr '/^\s*Host\s*=/{s/^[^=]+= *//;s/ /\n/g;p}' ~/.ssh/config \
        | sort )
}
_ssh_complete_init

function _ssh_complete () {
    local match=${COMP_WORDS[${COMP_CWORD}]}
    local hosts=
    local default=
    for h in $_ssh_complete_hostlist; do
        if [[ $h =~ ^$match ]]; then
            hosts="$hosts $h"
        fi
    done
    if ! (( ${COMP_CWORD} == ${#COMP_WORDS[@]}-1 )); then
        default=$( compgen -f ${COMP_WORDS[${COMP_CWORD}]} )
    fi
    COMPREPLY=($hosts $default)
}
complete -F _ssh_complete ssh

La première fonction crée une liste à partir de laquelle les hôtes sont terminés (généralement il suffit de l'exécuter une fois dans chaque shell), la seconde effectue l'achèvement réel, mais de manière un peu maladroite - elle ne complète le nom d'hôte que lorsqu'elle est le dernier jeton sur la ligne de commande.

Cela dit, la bonne façon d'aborder ce problème est de se connecter au réseau professionnel via un VPN et d'avoir ainsi l'adresse IP professionnelle locale accessible comme si vous étiez au bureau. Vous pouvez ensuite raccorder directement l'adresse dans tout selon la couche que vous préférez: ~/.ssh/config, /etc/resolv.confou (AMHA meilleure option) serveur de noms de bureau.

peterph
la source
Les ports ne sont pas figés. Je pourrais définitivement changer le port SSH local de gammapour correspondre au port distant si cela rendait les choses plus faciles.
IQAndreas
2

Il y a quelques années, j'ai écrit un programme dans un but similaire. Cela pourrait répondre à vos besoins. Avec ce programme, la configuration ssh pourrait ressembler à ceci:

Host gamma
    ProxyCommand ssh-multipath-proxy 192.168.1.100:22 55.22.33.99:12345
    User andreas
kasperd
la source
1

Une autre solution consiste à utiliser deux fichiers de configuration différents pour SSH. Vous pourriez considérer cela un peu moins élégant que d'avoir tout dans un seul fichier de configuration, mais c'est plus facile à maintenir.

Vous sélectionnez le fichier de configuration que vous souhaitez utiliser avec -F <configfile>.

Marcel Loose
la source
Merci. J'aime l' -Foption.
typelogic
0

Réponse partielle:

De nombreuses réponses ci-dessus commencent par "si vous pouvez détecter le réseau sur lequel vous vous trouvez". Pour cela, j'utilise un script qui s'exécute lorsque les interfaces sont connectées pour démarrer diverses choses (VPN, généralement) lorsque je me connecte à l'un de mes réseaux habituels. La technique consiste à utiliser ARP pour obtenir l'adresse MAC de la passerelle:

function identifyConnection {
    gatewayIP=$(route -n | grep -e '^0\.0\.0\.0' | tr -s ' ' | cut -d ' ' -f 2)

    if [[ ! -z "$gatewayIP" ]]
    then
        # Identify the gateway by its MAC (uniqueness...)
        log "Gateway IP address=$gatewayIP"
        log "Obtaining corresponding gateway MAC address"
        gatewayData=($(arp -n $gatewayIP | grep -e $gatewayIP | tr -s ' '))
        if [[ "${gatewayData[1]}" == "(incomplete)" ]]
        then
            log "Status of gateway $gatewayIP "incomplete""
            echo ""
        elif [[ "${gatewayData[2]}" == "--" ]]
        then 
            log "No MAC address found for $gatewayIP"
            echo ""
        else
            log "Gateway MAC address=[${gatewayData[2]}]"
            echo "${gatewayData[2]}"
        fi
    fi
}

Et puis j'ai une table de recherche pour associer le réseau à la passerelle MAC. Bien sûr, cette table peut contenir plusieurs MAC pour le même réseau (le cas typique est les différents hotspots Wifi sur un grand site d'entreprise). Une autre table de recherche est utilisée pour déterminer le script à exécuter pour ce réseau.

Dans mon cas, le script est exécuté à l'aide des notifications du bureau Plasma, donc tout est dans le pays utilisateur.

xénoïde
la source