Use dos direcciones IP diferentes por host en SSH

23

Tengo un servidor, llamado gamma, constantemente en funcionamiento en el trabajo. A veces me conecto desde casa, en cuyo caso utilizo la dirección IP pública 55.22.33.99. A veces, me conecto a ella cuando estoy en el trabajo, y en lugar de rebotar mis paquetes alrededor innecesariamente, lo conecto a través de la dirección IP local, 192.168.1.100.

Por el momento, los he dividido en dos entradas diferentes en ~/.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

Entonces, si estoy en el trabajo, todo lo que tengo que escribir es ssh gamma-localy estoy; si estoy en casa (o en cualquier otro lugar del mundo), corro ssh gamma-remote.

Al conectarme al servidor, preferiría no tener que escribir un nombre diferente dependiendo de dónde esté, prefiero que esa parte se realice automáticamente; por ejemplo, en algunos casos tengo scripts automatizados que conectan a quienes no saben dónde estoy.

Hay una pregunta que resuelve este problema mediante el uso de un script Bash para "intentar" conectarse al local primero, y si no se conecta, intente conectarse a la dirección IP remota. Esto es bueno, pero (1) parece ineficiente (especialmente porque a veces hay que "esperar" a que se agote el tiempo de espera de las conexiones, ya que no siempre envían un error de inmediato) y (2) requiere Bash y cargar el script.

¿Existe una forma alternativa de lograr esto que no se base en el uso de scripts Bash, ni en "pruebas" para ver si la conexión funciona primero?

IQAndreas
fuente
Lo que estoy tratando de averiguar es si uno puede jugar con /etc/hostsel archivo de configuración SSH para lograr esto. ¿O tal vez alguna forma de "detectar" a qué LAN está conectado actualmente?
IQAndreas
¿Tiene un conjunto separado de servidores de nombres utilizados por la red de su oficina?
Sree
@Sree Ah, veo a dónde te diriges con esto; ¡inteligente! No estamos ejecutando un servidor de nombres en este momento, pero definitivamente podría convertir una de las máquinas en una.
IQAndreas
@Sree Siéntase libre de elaborar y agregar eso como una respuesta que comienza con la línea "Si tiene un servidor de nombres en la red de su oficina ..."
IQAndreas
Hizo que. Siéntase libre de votar arriba / abajo :)
Sree

Respuestas:

28

Si tiene una manera de reconocer en qué red se encuentra, puede usar la Matchpalabra clave ~/.ssh/configpara hacer lo que quiera. Esto requiere OpenSSH ≥6.5.

Yo uso algo similar a

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

Así que estoy usando el identificador de la red wifi utilizada para decidir si estoy en casa para los fines de la conexión SSH, pero también puedo usar la dirección IP asignada a su computadora o cualquier otra cosa que diferencie las dos redes. .

Michał Politowski
fuente
+1 uso inteligente de Match, gracias! Puede ser una buena idea incluir la detección en un script que sale con un estado de salida cero o no cero, ya que eso lo haría reutilizable.
Peter
@peterph ciertamente podría abstraerse a un script externo, pero solo lo necesitaba en un lugar hasta ahora, por lo que la regla de los tres aún no se ha implementado.
Michał Politowski
¿Qué pasaría si estuvieras en el trabajo, pero realmente quieres conectarte a otra máquina? ¿No coincidiría la declaración ejecutiva ya que no está en WiFi con su HomeESSID y, por lo tanto, establece el nombre de host en 192.168.1.100?
desaparecido el
@gone No entiendo la pregunta. El partido también está en el host objetivo.
Michał Politowski
1
@typelogic No es fácil, que yo sepa. Podría intentar usar ProxyCommand nc $address ssh, pero luego, por ejemplo. ¿Todos los dispositivos tienen la misma clave de host? Anuncio si tiene que establecer una variable de entorno de todos modos, ¿no será más fácil simplemente dar la dirección para conectarse directamente como argumento ssh?
Michał Politowski
5

Si tiene un servidor de nombres privado en el trabajo y usa la misma computadora portátil de la oficina y el hogar, puede aprovechar eso para lograr esto:

  1. Modifique su nsswitch.confen su máquina para verificar primero el DNS
  2. Cree una entrada DNS para gammaresolver 192.168.1.100 en su DNS privado en la oficina.
  3. Cree una entrada en el archivo / etc / hosts de su máquina para resolver gammaa 55.22.33.99.

De esta manera, cuando salga ssh gammade la oficina, se resolverá desde el DNS de la oficina al 192.168.1.100 y cuando se conecte desde su hogar, se resolverá a 55.22.33.99 desde su archivo de hosts.

PD : Esta respuesta supone que no desea que gamma tenga una entrada de DNS pública. Además, si está enviando SSH a su servidor desde una máquina Windows, creo que debería haber algún lugar equivalente al archivo nssswitch.conf para anular las entradas del archivo hosts.

Sree
fuente
Hay, es el archivo de hosts. Y así es exactamente como lo hago: cuando estoy en casa, mi dominio público se resuelve en mi IP local. Excelente respuesta: fue lo primero que pensé también. Bueno ... hoy es decir, cuando lo configuré hace un par de años, tuve que buscar mucho en Google para encontrar una solución.
mikeserv
2

No sé si es posible hacerlo, ~/.ssh/configpero otro enfoque sería conectarse a uno u otro en función de su dirección IP externa. Dado que, presumiblemente, cuando esté en el trabajo, su IP será 55.22.33.NNN, puede ejecutar algo como:

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

Un enfoque aún más simple es usar su IP interna. No sé cómo están configuradas sus dos redes, pero si es fácil determinar si está trabajando o no a través de su IP (por ejemplo, si tiene una IP específica en el trabajo, por ejemplo 192.168.1.12), puede hacer ( cambie eth0a cual sea el nombre de su tarjeta de red):

[[ $(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

Independientemente de lo que decida usar, puede agregarlo como un alias a su shell (agregue esta línea al archivo de inicialización de su shell, ~/.bashrcsi está usando bash):

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

También puede convertir eso en un script si desea que otros scripts tengan acceso a él (los alias .bashrcno se leen cuando se ejecuta un script).

terdon
fuente
2

No puede lograr esto ~/.ssh/configcuando usa direcciones IP como nombres de host. El hecho de que no solo se está conectando a diferentes direcciones IP, sino también a diferentes puertos, presenta una complicación adicional, ya que eso prácticamente descarta cualquier ajuste de su resolución DNS.

Estoy corregido - puedes usar el Match originalhost ... exec ...combo en ~/.ssh/config- mira la respuesta de @ MichałPolitowski . Sin embargo, aunque funcionará perfectamente bien para OpenSSH, no necesariamente encontrará una funcionalidad similar en otros clientes SSH.

Puede solucionar el problema utilizando un contenedor simple (ya sea una función de shell o un script si necesita usarlo desde varios shells) para ssh, que verificará en qué red se encuentra y usará la Hostentrada adecuada . La gran pregunta es cómo detectar de manera confiable en qué red se encuentra. Me viene a la mente la dirección IP local, pero no es confiable, ya que es muy posible que se conecte desde una LAN que usa la misma subred que su red de trabajo.

Si puede tener el mismo puerto para redes locales y remotas, puede editarlo /etc/resolv.confdependiendo de la red en la que se encuentre, obviamente, tendría que hacerse automáticamente (probablemente desde un script de enlace de su cliente DHCP). O, mejor, ejecute el servidor de nombres local (como, por ejemplo dnsmasq) y proporcione la configuración adecuada. Sin embargo, eso va más allá del alcance de esta pregunta.

Otra opción, si solo necesita conectarse de forma interactiva, es utilizar la finalización de comandos que escanearía ~/.ssh/config. Eso le ahorraría algo de escritura (especialmente si tiene suficientes Hostentradas variables ). Algo como esto (para la bashinicialización):

# 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 primera función crea una lista desde la cual se completan los hosts (generalmente es suficiente ejecutar esto una vez en cada shell), la segunda realiza la finalización real, aunque de una manera un poco torpe: solo completa el nombre del host cuando está El último token en la línea de comando.

Dicho todo esto, la forma correcta de abordar este problema es conectarse a la red de trabajo a través de una VPN y, por lo tanto, tener la dirección IP de trabajo local accesible como si estuviera en la oficina. A continuación, puede dura hilos en la dirección de lo que sea lo que la capa que prefiera: ~/.ssh/config, /etc/resolv.confo (en mi humilde opinión la mejor opción) servidor de nombres de oficina.

Peterph
fuente
Los puertos no están en piedra. Definitivamente podría cambiar el puerto SSH local gammapara que coincida con el puerto remoto si eso facilitara las cosas.
IQAndreas
2

Hace algunos años, escribí un programa para un propósito similar. Puede satisfacer sus necesidades. Con ese programa, la configuración ssh podría verse así:

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

Otra solución es usar dos archivos de configuración diferentes para SSH. Puede considerar esto un poco menos elegante que tener todo en un archivo de configuración, pero es más fácil de mantener.

Selecciona el archivo de configuración con el que deseas usar -F <configfile>.

Marcel Loose
fuente
Gracias. Me gusta la -Fopcion.
typelogic
0

Respuesta parcial:

Muchas de las respuestas anteriores comienzan con "si puede detectar en qué red se encuentra". Para esto utilizo un script que se ejecuta cuando las interfaces están conectadas para iniciar varias cosas (VPN, generalmente) cuando me conecto a una de mis redes habituales. La técnica es utilizar ARP para obtener la dirección MAC de la puerta de enlace:

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
}

Y luego tengo una tabla de búsqueda para asociar la red a la puerta de enlace MAC. Por supuesto, esa tabla puede contener varios MAC para la misma red (el caso típico son los diversos puntos de acceso Wifi en un sitio corporativo grande). Se utiliza otra tabla de búsqueda para determinar el script que se ejecutará para esa red.

En mi caso, el script se ejecuta utilizando las notificaciones de escritorio de Plasma, por lo que todo está en tierra de usuario.

xenoide
fuente