Используйте два разных IP-адреса на хост в SSH

23

У меня есть сервер с именем gamma, постоянно включенным и работающим на работе. Иногда я подключаюсь к нему из дома, и в этом случае я использую публичный IP-адрес 55.22.33.99. Иногда я подключаюсь к нему, когда я на работе, и вместо того, чтобы пересылать свои пакеты без необходимости, я подключаюсь через локальный IP-адрес 192.168.1.100.

На данный момент я разделил их на две записи в ~/.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

Итак, если я на работе, все, что я должен напечатать, ssh gamma-localи я в; если я дома (или где-либо еще в мире), я бегу ssh gamma-remote.

При подключении к серверу я бы предпочел не вводить другое имя в зависимости от того, где я нахожусь, я бы предпочел, чтобы эта часть выполнялась автоматически; например, в некоторых случаях у меня есть автоматические скрипты, которые подключаются, кто не знает, где я.

Существует вопрос, который решает эту проблему с помощью сценария Bash, чтобы «попытаться» сначала подключиться к локальному, а если он не подключается, попытаться подключиться к удаленному IP-адресу. Это хорошо, но (1) кажется неэффективным (особенно если учесть, что иногда приходится «ждать» истечения времени ожидания соединений, поскольку они не всегда сразу возвращают ошибку), и (2) требуется Bash и обход сценария.

Есть ли альтернативный способ достижения этого, который не зависит ни от использования скриптов Bash, ни от «тестирования», чтобы увидеть, работает ли сначала соединение?

IQAndreas
источник
То, что я пытаюсь выяснить, это то, можно ли поиграться /etc/hostsили файл конфигурации SSH, чтобы добиться этого? Или, может быть, какой-то способ «определить», к какой локальной сети вы сейчас подключены?
IQAndreas
У вас есть отдельный набор серверов имен, используемых в вашей офисной сети?
Сри
@Sree Ах, я вижу, куда ты идешь с этим; умная! В данный момент мы не работаем с сервером имен, но я определенно могу преобразовать одну из машин в одну.
IQAndreas
@Sree Не стесняйтесь разрабатывать и добавлять это как ответ, который начинается со строки «Если у вас есть
сервер
Сделал это. Не стесняйтесь, голосуйте вверх / вниз :)
Sree

Ответы:

28

Если у вас есть способ узнать, в какой сети вы находитесь, вы можете использовать Matchключевое слово, ~/.ssh/configчтобы делать то, что вы хотите. Для этого требуется OpenSSH ≥6.5.

Я использую что-то похожее на

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

Поэтому я использую идентификатор использованной сети Wi-Fi, чтобы решить, дома ли я для целей SSH-соединения, но можно также проверить IP-адрес, назначенный вашему компьютеру, или что-либо еще, что отличает эти две сети. ,

Михал Политовски
источник
+1 умное использование Match, спасибо! Это может быть хорошей идеей, чтобы обернуть обнаружение в скрипт, выход с нулевым или ненулевым состоянием выхода, так как это сделает его многоразовым.
Петер
@peterph, конечно, его можно абстрагировать от внешнего скрипта, но до сих пор мне нужно было только одно место, поэтому правило трех еще не вступило в силу.
Михал Политовски,
Что бы произошло, если бы вы были на работе, но вы действительно хотите подключиться к какой-то другой машине? Разве оператор exec не будет соответствовать, так как вы не используете WiFi с вашим HomeESSID, и, следовательно, установите для имени хоста 192.168.1.100?
ушел
@ ушел я не понимаю вопроса. Матч также на целевом хосте.
Михал Политовски,
1
@typelogic Не так легко, насколько я знаю. Вы можете попробовать использовать ProxyCommand nc $address ssh, но тогда, например. все ли устройства имеют одинаковый ключ хоста? Если вам все равно нужно установить переменную окружения, не будет ли проще просто дать адрес для прямого подключения в качестве аргумента ssh?
Михал Политовски
5

Если у вас есть личные серверы имен на работе, и если вы используете один и тот же ноутбук из офиса и дома, вы можете воспользоваться этим для достижения следующих целей:

  1. Внесите изменения nsswitch.confв свою машину, чтобы сначала проверить DNS
  2. Создайте запись DNS для gammaразрешения 192.168.1.100 в вашем личном DNS в офисе.
  3. Создайте запись в файле / etc / hosts на своем компьютере, чтобы разрешить ее gammaв 55.22.33.99.

Таким образом, когда вы ssh gammaиз офиса, он преобразуется из офисного DNS в 192.168.1.100, а когда вы подключаетесь из дома, он преобразуется в 55.22.33.99 из вашего файла hosts.

PS : Этот ответ предполагает, что вы не хотите, чтобы у гаммы была публичная запись DNS. Кроме того, если вы используете SSHing для вашего сервера с компьютера с Windows, я думаю, что должно быть какое-то место, эквивалентное файлу nssswitch.conf, чтобы переопределить записи файла hosts.

Sree
источник
Есть - это файл hosts. И это именно так, как я это делаю - когда дома мое публичное достояние разрешается на мой локальный IP. Отличный ответ - это было первое, о чем я тоже подумал. Ну ... сегодня, то есть, когда я настроил его пару лет назад, мне пришлось много гуглить, чтобы найти решение.
mikeserv
2

Я не знаю, возможно ли сделать это через, ~/.ssh/configно другой подход будет состоять в том, чтобы подключиться к одному или другому на основе вашего внешнего IP-адреса. Поскольку, по-видимому, когда вы на работе, ваш IP будет 55.22.33.NNN, вы можете запустить что-то вроде:

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

Еще более простой подход - использовать ваш внутренний IP. Я не знаю, как настроены ваши две сети, но если по вашему IP легко определить, работаете вы или нет (например, если у вас есть определенный IP на работе, например 192.168.1.12), вы можете это сделать ( измените eth0имя вашей сетевой карты на другое):

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

Что бы вы ни решили использовать, вы можете добавить его в качестве псевдонима для вашей оболочки (добавьте эту строку в файл инициализации вашей оболочки, ~/.bashrcесли вы используете bash):

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

Вы также можете сделать это в сценарии, если хотите, чтобы другие сценарии имели к нему доступ (псевдонимы из .bashrcне читаются при запуске сценария).

Тердон
источник
2

Вы не можете достичь этого ~/.ssh/configпри использовании IP-адресов в качестве имен хостов. Дополнительное усложнение связано с тем, что вы подключаетесь не только к разным IP-адресам, но и к разным портам, поскольку это в значительной степени исключает любые изменения вашего DNS-преобразователя.

Я исправлен - вы можете использовать Match originalhost ... exec ...комбо в ~/.ssh/config- см . Ответ @ MichałPolitowski . Однако, хотя он будет отлично работать для OpenSSH, вы не обязательно найдете подобную функциональность в других клиентах SSH.

Вы можете обойти проблему, используя простую оболочку (либо функцию оболочки, либо сценарий, если вам нужно использовать ее из различных оболочек) ssh, которая проверит, в какой сети вы находитесь, и использует соответствующую Hostзапись. Большой вопрос, как надежно определить, в какой сети вы находитесь. Локальный IP-адрес приходит на ум, но не является надежным, поскольку вы также можете подключаться из локальной сети, которая использует ту же подсеть, что и ваша рабочая сеть.

Если у вас может быть один и тот же порт как для локальной, так и для удаленной сети, вы можете редактировать свой в /etc/resolv.confзависимости от сети, в которой вы находитесь - очевидно, это должно быть сделано автоматически (скорее всего из сценария подключения вашего DHCP-клиента). Или - лучше - запустить локальный сервер имен (как, например dnsmasq) и предоставить ему соответствующую конфигурацию. Это выходит за рамки этого вопроса, хотя.

Другой вариант - если вам нужно только подключиться в интерактивном режиме - это использовать завершение команды, которое будет сканировать ~/.ssh/config. Это избавит вас от необходимости печатать (особенно если у вас достаточно разных Hostзаписей). Примерно так (для bashинициализации):

# 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

Первая функция создает список, из которого завершаются узлы (обычно этого достаточно, чтобы выполнить это один раз в каждой оболочке), вторая выполняет фактическое завершение, хотя и немного неуклюже - она ​​завершает имя узла только тогда, когда последний токен в командной строке.

Все это говорит о том, что правильным способом решения этой проблемы является подключение к рабочей сети через VPN и, таким образом, локальный рабочий IP-адрес, доступный, как если бы вы были в офисе. Вы можете затем жесткий провод адреса в зависимости от того , независимо от уровня вы предпочитаете: ~/.ssh/config, /etc/resolv.confили (имхо лучший вариант) имя сервера офиса.

peterph
источник
Порты не установлены в камне. Я мог бы определенно изменить локальный порт SSH, gammaчтобы он соответствовал удаленному порту, если это облегчит задачу.
IQAndreas
2

Несколько лет назад я написал программу для аналогичной цели. Это может удовлетворить ваши потребности. С этой программой конфигурация ssh может выглядеть так:

Host gamma
    ProxyCommand ssh-multipath-proxy 192.168.1.100:22 55.22.33.99:12345
    User andreas
kasperd
источник
1

Еще одно решение - использовать два разных конфигурационных файла для SSH. Вы можете считать это немного менее элегантным, чем иметь все в одном файле конфигурации, но это проще в обслуживании.

Вы выбираете файл конфигурации, который хотите использовать -F <configfile>.

Марсель Луз
источник
Спасибо. Мне нравится -Fвариант.
typelogic
0

Частичный ответ:

Многие ответы выше начинаются с «если вы можете определить, в какой сети вы находитесь». Для этого я использую скрипт, который запускается при подключении интерфейсов для запуска различных вещей (обычно VPN), когда я подключаюсь к одной из моих обычных сетей. Метод заключается в использовании ARP для получения MAC-адреса шлюза:

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
}

И тогда у меня есть таблица поиска, чтобы связать сеть со шлюзом MAC. Конечно, эта таблица может содержать несколько MAC для одной и той же сети (типичный случай - различные точки доступа Wifi на большом корпоративном сайте). Другая таблица поиска используется для определения сценария, который будет запущен для этой сети.

В моем случае скрипт запускается с использованием уведомлений рабочего стола Plasma, поэтому все находится в пользовательском пространстве.

xenoid
источник