Вопрос или проблема
Я могу проверить доступность сайта, выполнив curl -I https://www.example.com
. Это возвращает HTTP/1.1 200 OK
(и остальные заголовки, что хорошо).
У меня есть контейнер (на основе образа ubi8/openjdk-17), в котором инструменты, которые я обычно использую (curl
и nc
, а также wget
), недоступны, и я не могу их установить. Как я могу проверить соединение без их использования?
Я нашел эту статью, которая привела меня к следующему коду
exec 3<>"/dev/tcp/www.google.com/443" && \
echo -e "GET / HTTP/1.1\r\nHost: www.google.com\r\nConnection: close\r\n\r\n" >&3 && \
cat <&3
… который не срабатывает (т.е. пустой вывод, потому что этот URL — https).
Если я попробую это с URL http://
, все работает нормально.
Образ
Я немного разобрался в образе. Я предполагал, что это Alpine, но согласно базовому образу ubi8/ubi-minimal это …
… OCI-совместимые базовые образы операционной системы контейнера с дополнительными языками выполнения и пакетами, которые могут свободно распространяться.
и поскольку это RedHat, я предполагаю, что это означает, что это образ RedHat.
Bash не имеет встроенной поддержки TLS. Вы не можете устанавливать TLS-соединения, используя только Bash.
Существуют реализации TLS на чистом Bash, которые вы могли бы адаптировать для своих нужд. Однако они не очень практичны (например, эта ограничена очень специфическими наборами шифров) из-за ограничений языка, делающих написание такого кода утомительным. Обратите внимание, что даже эта реализация не является на 100% чистым Bash; она полагается на несколько других инструментов, таких как bc
для дополнительных математических операций.
Тем не менее, вам все равно нужно перенести ее на систему – в этом случае вы также легко можете перенести скомпилированный бинарный файл, который будет построен вокруг полнофункциональной библиотеки TLS (например, статически связанный инструмент Golang или Rust, не зависящий от существующего libssl.so).
(Вообще-то, разве чистая система Alpine не содержит busybox
? Вы должны быть в состоянии использовать busybox wget
, чтобы вызвать его встроенную имитацию wget и так далее.)
.
Ответ или решение
Теория
Для проверки доступности HTTPS-порта без использования стандартных инструментов, таких как curl
, wget
или nc
, требуется учитывать защитный слой шифрования TLS, который используется при соединении с HTTPS. Bash сам по себе не поддерживает TLS напрямую, что и вызывает сложности при попытке соединения с использованием /dev/tcp
.
Пример
При попытке выполнить следующую команду:
exec 3<>"/dev/tcp/www.google.com/443" && \
echo -e "GET / HTTP/1.1\r\nHost: www.google.com\r\nConnection: close\r\n\r\n" >&3 && \
cat <&3
вы столкнётесь с проблемой, что ответ будет пустым. Это происходит потому, что команды, доступные в bash, не поддерживают установление TLS-соединений.
Применение
Вариант 1: Использование сторонних скриптов
Существуют реализации TLS на чистом Bash, такие как bash_tls, которые можно адаптировать под ваши нужды. Однако, стоит учитывать, что они имеют ограничения и могут не поддерживать все параметры современных TLS-соединений. Эти скрипты часто требуют дополнительные утилиты, такие как bc
, которые также могут быть недоступны на минималистичных системах.
Вариант 2: Использование доступныx локальных инструментов
Если ваша система основана на Red Hat UBI (Universal Base Image), возможно, на ней предустановлен openssl
. Можно использовать openssl s_client
для проверки соединения с сервером:
echo -e "GET / HTTP/1.1\r\nHost: www.google.com\r\nConnection: close\r\n\r\n" | openssl s_client -connect www.google.com:443 -quiet
Эта команда установит TLS-соединение и отправит HTTP-запрос, позволяя вам увидеть ответ от сервера, включая заголовки.
Заключение
В условиях ограниченного инструментария подход с использованием openssl
является более соответствующим, так как он позволяет справиться с особенностями TLS на уровне шифрования, нежели попытка обойти это с помощью импровизированных решений в Bash. Использование скриптов или решений, которые были бы перенесены на сервер, может быть неоправданно сложным и менее надежным.