Використовуйте дві різні 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, а також на "тестування", щоб перевірити, чи працює з'єднання спочатку?


Що я намагаюся дізнатись, чи можна з цим поспілкуватися /etc/hostsабо з конфігураційним файлом SSH? Або, можливо, якийсь спосіб "виявити" до якої локальної мережі ви зараз підключені?
IQAndreas

Чи є у вас окремий набір серверів імен, які використовуються у вашій офісній мережі?
Sree

@ Sree Ах, я бачу, куди ти йдеш із цим; розумний! Наразі у нас не працює сервер імен, але я однозначно міг би перетворити одну з машин на одну.
IQAndreas

@Sree Не соромтеся деталізувати і додайте, що як відповідь, що починається з рядка "Якщо у вас в офісній мережі є сервер імен ..."
IQAndreas

Зробив це. Сміливо вгору / вниз голосування :)
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 це, безумовно, може бути абстраговано зовнішнім сценарієм, але мені потрібно було лише в одному місці до цих пір, тому правило трійки ще не застосовано.
Michał Politowski

Що буде, якби ви були на роботі, але насправді хочете підключитися до якоїсь іншої машини? Чи не відповідає заяві exec, оскільки ви не перебуваєте на WiFi зі своїм HomeESSID, і тому встановите ім'я хоста на 192.168.1.100?
пішов

@gone Я не розумію питання. Матч також на цільовому господарі.
Michał Politowski

1
@typelogic Нелегко, наскільки я знаю. Ви можете спробувати використовувати ProxyCommand nc $address ssh, але тоді, наприклад. чи всі пристрої мають однаковий ключ хоста? Оголошення, якщо вам доведеться все-таки встановити змінну середовища, не буде простіше просто вказати адресу для прямого підключення як аргумент ssh?
Michał Politowski

5

Якщо у вас є приватні сервери імен на роботі, і якщо ви використовуєте один і той же ноутбук в офісі і вдома, ви можете скористатися цим для досягнення цього:

  1. Змініть свій nsswitch.confапарат у своєму пристрої, щоб спочатку перевірити DNS
  2. Створіть запис DNS, gammaщоб вирішити значення 192.168.1.100 у своєму приватному DNS в офісі.
  3. Створіть запис у файлі / etc / hosts вашої машини, щоб дозволити gamma55.22.33.99.

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

PS : Ця відповідь передбачає, що ви не хочете, щоб гамма мала публічний запис DNS. Крім того, якщо ви SSHing на своєму сервері з машини Windows, я думаю, що має бути якесь місце, еквівалентне файлу nssswitch.conf, щоб змінити записи файлів хостів.


Є - це файл хостів. І саме так я це роблю - коли вдома моє публічне надбання відповідає моєму локальному ip. Відмінна відповідь - це було перше, що я подумав теж. Ну ... сьогодні це, коли я його встановив пару років тому, мені довелося багато шукати в Google, щоб знайти рішення.
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або (имхо кращий варіант) ім'я сервера офісу.


Порти не встановлені в камені. Я напевно міг би змінити локальний порт SSH, gammaщоб він відповідав віддаленому порту, якщо це полегшить ситуацію.
IQAndreas

2

Деякі роки тому я написав програму з подібною метою. Це може відповідати вашим потребам. З цією програмою конфігурація ssh може виглядати так:

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

1

Ще одне рішення - використовувати два різні конфігураційні файли для SSH. Ви можете вважати це дещо менш елегантним, ніж мати все в одному конфігураційному файлі, але це простіше в обслуговуванні.

Ви вибираєте конфігураційний файл, з яким потрібно використовувати -F <configfile>.


Спасибі. Мені подобається -Fваріант.
машинопис

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 для однієї мережі (типовий випадок - це різні точки доступу Wi-Fi на великому корпоративному сайті). Інша таблиця пошуку використовується для визначення сценарію для запуску в цій мережі.

У моєму випадку сценарій запускається за допомогою сповіщень на робочому столі Plasma, тому все знаходиться в країні користувача.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.