Use dois endereços IP diferentes por host no SSH

23

Eu tenho um servidor chamado gamma, constantemente em funcionamento no trabalho. Às vezes, eu me conecto a ele em casa e, nesse caso, uso o endereço IP público 55.22.33.99. Às vezes, eu me conecto a ele quando estou no trabalho e, em vez de devolver meus pacotes desnecessariamente, conecto-me através do endereço IP local 192.168.1.100.

No momento, eu os tenho divididos em duas entradas diferentes em ~/.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

Então, se estou no trabalho, tudo o que tenho que digitar é ssh gamma-locale estou; se estou em casa (ou em qualquer outro lugar do mundo), corro ssh gamma-remote.

Ao conectar-me ao servidor, eu preferiria não precisar digitar um nome diferente, dependendo de onde estou, preferiria que essa parte fosse feita automaticamente; por exemplo, em alguns casos, tenho scripts automatizados que conectam quem não sabe onde estou.

uma pergunta que resolve esse problema usando um script Bash para "tentar" conectar-se ao local primeiro e, se não conectar, tente conectar-se ao endereço IP remoto. Isso é legal, mas (1) parece ineficiente (especialmente porque às vezes você precisa "esperar" o tempo limite das conexões, pois elas nem sempre enviam um erro imediatamente) e (2) requer Bash e arrastando o script.

Existe uma maneira alternativa de conseguir isso que não dependa do uso de scripts Bash, nem de "testar" para verificar se a conexão funciona primeiro?

IQAndreas
fonte
O que estou tentando descobrir é se alguém pode mexer com /etc/hostso arquivo de configuração SSH para conseguir isso? Ou talvez alguma maneira de "detectar" a qual LAN você está conectado atualmente?
IQAndreas
Você tem um conjunto separado de servidores de nomes usados ​​pela rede do seu escritório?
Sree
@Ree Ah, eu vejo onde você está indo com isso; inteligente! No momento, não estamos executando um servidor de nomes, mas eu definitivamente poderia converter uma das máquinas em uma.
IQAndreas
@Sree Sinta-se à vontade para elaborar e acrescentar isso como uma resposta que começa com a linha "Se você possui um servidor de nomes na rede do seu escritório ..."
IQAndreas
Fiz isso. Sinta-se livre para cima / baixo voto :)
Sree

Respostas:

28

Se você tiver uma maneira de reconhecer em qual rede você está, poderá usar a Matchpalavra - chave ~/.ssh/configpara fazer o que deseja. Isso requer o OpenSSH ≥6,5.

Eu uso algo parecido com

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

Portanto, estou usando o identificador da rede wifi usada para decidir se estou em casa para os propósitos da conexão SSH, mas verificando o endereço IP atribuído ao seu computador ou qualquer outra coisa que diferencie as duas redes também .

Michał Politowski
fonte
+1 uso inteligente de Match, obrigado! Pode ser uma boa ideia agrupar a detecção em um script que saia com status de saída zero ou diferente de zero, pois isso a tornaria reutilizável.
Peterph
@ Peterph certamente poderia ser abstraído para um script externo, mas eu só precisava de um lugar até agora, então a regra dos três ainda não foi lançada.
Michał Politowski
O que aconteceria se você estivesse no trabalho, mas realmente deseja se conectar a outra máquina? A declaração exec não corresponderia, pois você não está usando o WiFi do seu HomeESSID e, portanto, define o nome do host como 192.168.1.100?
foi
@ ido embora eu não entendo a pergunta. A partida também está no host de destino.
Michał Politowski
1
@typelogic Não é fácil, tanto quanto eu sei. Você pode tentar usar ProxyCommand nc $address ssh, mas então por exemplo. todos os dispositivos têm a mesma chave de host? Se você precisar definir uma variável de ambiente de qualquer maneira, não será mais fácil fornecer o endereço ao qual se conectar diretamente como argumento ssh?
Michał Politowski 8/03
5

Se houver servidores de nomes particulares no trabalho e se você usar o mesmo laptop no escritório e em casa, poderá tirar proveito disso para conseguir isso:

  1. Modifique o seu nsswitch.confem sua máquina para verificar primeiro o DNS
  2. Crie uma entrada DNS para gammaresolver para 192.168.1.100 no seu DNS privado no escritório.
  3. Crie uma entrada no arquivo / etc / hosts da sua máquina para resolver gammapara 55.22.33.99.

Dessa forma, quando você estiver ssh gammano escritório, ele resolverá do DNS do escritório para o 192.168.1.100 e quando você se conectar de casa, resolverá para 55.22.33.99 do arquivo de hosts.

PS : Esta resposta assume que você não deseja que o gamma tenha uma entrada DNS pública. Além disso, se você estiver executando o SSH no servidor a partir de uma máquina Windows, acho que deve haver algum lugar equivalente ao arquivo nssswitch.conf para substituir as entradas do arquivo hosts.

Sree
fonte
Existe - é o arquivo hosts. E é exatamente assim que eu faço - quando em casa meu domínio público resolve meu IP local. Excelente resposta - foi a primeira coisa que pensei também. Bem ... hoje, quando o configurei há alguns anos, tive que pesquisar muito no Google para encontrar uma solução.
mikeserv
2

Não sei se é possível fazer isso, ~/.ssh/configmas outra abordagem seria conectar-se a um ou outro com base no seu endereço IP externo. Como, presumivelmente, quando você estiver no trabalho, seu IP estará 55.22.33.NNN, você poderá executar algo como:

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

Uma abordagem ainda mais simples é usar seu IP interno. Não sei como suas duas redes estão configuradas, mas se é fácil determinar se você está no trabalho ou não através do seu IP (por exemplo, se você tem um IP específico no trabalho, como 192.168.1.12), é possível ( mude eth0para o nome da sua placa de rede):

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

Qualquer que seja a sua decisão, você pode adicioná-lo como um alias ao seu shell (adicione esta linha ao arquivo de inicialização do seu shell, ~/.bashrcse estiver 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

Você também pode transformar isso em um script se desejar que outros scripts tenham acesso a ele (os aliases de .bashrcnão são lidos ao executar um script).

terdon
fonte
2

Você não pode conseguir isso ~/.ssh/configao usar endereços IP como nomes de host. Uma complicação adicional é introduzida pelo fato de você não estar apenas se conectando a diferentes endereços IP, mas também a portas diferentes, pois isso praticamente exclui qualquer ajuste no seu resolvedor de DNS.

Estou corrigido - você pode usar o Match originalhost ... exec ...combo ~/.ssh/config- veja a resposta de @ MichałPolitowski . No entanto, embora funcione perfeitamente para o OpenSSH, talvez você não encontre necessariamente funcionalidades semelhantes em outros clientes SSH.

Você pode solucionar o problema usando um invólucro simples (uma função de shell ou um script se precisar usá-lo de várias shells) para ssh, que verificará em qual rede você está e usará a Hostentrada apropriada . A grande questão é: como detectar com segurança em que rede você está. O endereço IP local vem à mente, mas não é confiável, pois você também pode estar se conectando a partir de uma LAN que usa a mesma sub-rede que a sua rede de trabalho.

Se você puder ter a mesma porta para as redes local e remota, poderá editar /etc/resolv.confdependendo da rede em que está - obviamente isso deve ser feito automaticamente (provavelmente a partir de um script de gancho do seu cliente DHCP). Ou - melhor - execute o servidor de nomes local (como por exemplo dnsmasq) e forneça a configuração apropriada. Isso vai além do escopo desta questão.

Outra opção - se você precisar se conectar apenas de maneira interativa - é usar a conclusão de comandos que seria verificada ~/.ssh/config. Isso economizaria algumas digitações (especialmente se você tiver Hostentradas suficientes variadas ). Algo assim (para bashinicialização):

# 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

A primeira função cria uma lista a partir da qual os hosts são concluídos (geralmente é suficiente executá-la uma vez em cada shell), a segunda faz a conclusão real, embora de uma maneira um pouco desajeitada - ela só completa o nome do host quando é o último token na linha de comando.

Tudo isso dito, a maneira correta de abordar esse problema é conectar-se à rede de trabalho por meio de uma VPN e, assim, ter o endereço IP do trabalho local acessível como se você estivesse no escritório. Você pode, então, hard-wire o endereço em qualquer qualquer camada que você prefere: ~/.ssh/config, /etc/resolv.confou (imho melhor opção) servidor de nome de escritório.

peterph
fonte
Os portos não estão gravados em pedra. Definitivamente, eu poderia alterar a porta SSH local gammapara corresponder à porta remota se isso tornasse as coisas mais fáceis.
IQAndreas
2

Alguns anos atrás, escrevi um programa para um objetivo semelhante. Pode atender às suas necessidades. Com esse programa, a configuração do ssh pode ficar assim:

Host gamma
    ProxyCommand ssh-multipath-proxy 192.168.1.100:22 55.22.33.99:12345
    User andreas
Kasperd
fonte
1

Outra solução é usar dois arquivos de configuração diferentes para SSH. Você pode considerar isso um pouco menos elegante do que ter tudo em um arquivo de configuração, mas é mais fácil de manter.

Você seleciona o arquivo de configuração com o qual deseja usar -F <configfile>.

Marcel Loose
fonte
Obrigado. Eu gosto da -Fopção
typelogic
0

Resposta parcial:

Muitas respostas acima começam com "se você puder detectar em qual rede você está". Para isso, uso um script que é executado quando as interfaces são conectadas para iniciar várias coisas (VPNs, geralmente) quando eu me conecto a uma das minhas redes habituais. A técnica é usar o ARP para obter o endereço MAC do gateway:

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
}

E então eu tenho uma tabela de pesquisa para associar a rede ao gateway MAC. Obviamente, essa tabela pode conter vários MAC para a mesma rede (o caso típico são os vários hotspots Wifi em um grande site corporativo). Outra tabela de pesquisa é usada para determinar o script a ser executado nessa rede.

No meu caso, o script é executado usando as notificações da área de trabalho do Plasma, para que tudo esteja na terra do usuário.

xenoid
fonte