У меня есть мой ~/.ssh/config
настроен с различными хостами, которые доступны либо в нашей компании VPN, либо через прокси-сервер SSH.
На данный момент у меня только есть
Host internal-server
ProxyCommand ssh -W internal.ip:22 external-server
Однако, если я нахожусь во внутренней сети, я могу напрямую получить доступ к внутреннему ip, поэтому проксирование через внешний сервер просто добавляет задержку для подключения.
Есть ли способ временно прокси, если внутренний IP-адрес недоступен, и подключиться напрямую в противном случае?
Обычно я настраиваю что-то вроде этого. Предполагается, что промежуточный хост сможет разрешить имя.
Host *%homeproxy
ProxyCommand ssh user@proxyhost /bin/netcat -w 1 $(echo %h | cut -d%% -f1) 22
Я бы подключился к лайку ssh blah%homeproxy
.
Я использую другой метод, используя Match. В моем случае я хочу использовать локальный прокси, если он работает, или нет, если он не работает. Следующая директива прекрасно справляется с этим:
Match Exec "nc -z 127.0.0.1 1086"
ProxyCommand nc -X 5 -x 127.0.0.1:1086 %h %p
Он соответствует каждой попытке ssh и выполняет быструю проверку с помощью nc
чтобы увидеть, работает ли мой прокси на 1086 (в этом случае nc
выходит без ошибок). Если это произойдет, он устанавливает ProxyCommand.
Десять лет назад я написал прокси-команда для такого сценария. В вашем случае мою команду прокси можно использовать следующим образом:
Host internal-server
ProxyCommand ssh-multipath-proxy %h:%p -- ssh -W %h:%p external-server
Несколько предостережений: мне немного неловко признать, что он не поддерживает IPv6 и будет пробовать только один IP-адрес для каждого имени хоста. Кроме того, он не будет передавать баннер клиента на сервер до того, как баннер сервера будет отправлен. Но вряд ли это вызовет проблемы.
Спасибо Ответ @Till, это меня очень вдохновило.
Я обнаружил, что вы можете принудительно перенаправить свое соединение с ProxyCommand nc dst dst-port
.
Например, вы фактически подключитесь к B.com
если вы используете
ssh A.com -o ProxyCommand="nc B.com 22"
Но UserKnownHostsFile
по-прежнему будет записывать как A.com
Таким образом, вы можете добавить домен "авто" к своему ssh_config
Host auto.internal-server
Hostname {internal-server ip or domain}
ProxyCommand bash -c '(timeout 0.1 nc -z %h %p) && nc %h %p || ssh -W %h:%p external-server'
Я заменил nc -w 1 %h %p
с участием (timeout 0.1 nc -z %h %p) && nc %h %p
, это будет быстрее, если вы сможете достичь внутреннего сервера менее 100 мс.
Или вы можете заменить на ping
, но это может указывать на неверную информацию, если вы используете прокси на основе TCP, например proxychains
, или сервер не разрешает эхо-запрос ICMP.
Host auto.internal-server
Hostname {internal-server ip or domain}
ProxyCommand bash -c '(ping %h &>/dev/null) && nc %h %p || ssh -W %h:%p external-server'
Вы можете заменить (timeout 0.1 nc -z %h %p)
со всем, что определяет, находитесь ли вы на внутреннем сервере.
Если у вас несколько IP-адресов кандидатов, даже вы можете использовать это:
Host auto.internal-server
Hostname {internal-server ip or domain}
ProxyCommand bash -c 'f(){(timeout 0.1 ping -c 1 $1 &>/dev/null) && nc $1 %p;}; f 1.1.1.1 || f 2.2.2.2 || f 3.3.3.3'
Он попытается подключиться 1.1.1.1
, в случае неудачи попробуйте подключиться 2.2.2.2
, а потом 3.3.3.3
.
Это работает немного более автоматически с небольшой дополнительной задержкой 0,1 с:
Host proxyhost.example.com
ProxyCommand none
Host *.example.com
ProxyCommand sh -c "socat 2>/dev/null - tcp4:%h:%p,connect-timeout=0.1 || exec ssh -W %h:%p proxyhost.example.com"
Обычно я бы создавал другую запись примерно так -
Host myVM
ProxyCommand ssh -W internal.ip:22 external-server
User ubuntu
Host myVM-np
User ubuntu
Затем просто вызовите тот, который вам нужен, в зависимости от вашей текущей прокси-среды.
С Match и Exec вы можете проверить, доступен ли порт SSH, и использовать ProxyCommand, если нет. Смотрите мой пример здесь: https://stackoverflow.com/questions/40746463/how-to-automatically-switch-ssh-config-based-on-local-subnet/62924483#62924483