Наши партнеры

UnixForum





Библиотека сайта rus-linux.net

Как открыть TCP-/UDP-сокет средствами командной оболочки bash

Оригинал: How to open a TCP/UDP socket in a bash shell
Автор: Dan Nanni
Дата публикации: 24 мая 2016 г.
Перевод: А.Панин
Дата перевода: 23 июля 2016 г.

Как открыть TCP-/UDP-сокет средствами командной оболочки bash

Представьте, что вам по какой-либо причине необходимо открыть TCP-/UDP-сокет на работающем под управлением Linux сервере. Например, вам нужно проверить доступность определенного порта на удаленном узле с известным адресом. Также у вас может возникнуть потребность в загрузке определенной веб-страницы с удаленного веб-сервера или задействования restful API для тестирования сетевого сервиса. Кроме того, вы можете просто захотеть соединиться с сервером IRC или каким-либо другим удаленным сервером. Но что делать в том случае, если на вашем сервере имеется лишь очень ограниченное в плане функций рабочее окружение? Так, в нем могут быть просто не установлены такие стандартные инструменты для работы с сетью, как netcat, curl и wget, при этом в вашем распоряжении может иметься лишь командная оболочка bash.

Фактически, одной из встроенных функций командной оболочки bash является функция открытия TCP-/UDP-сокетов с помощью файлов устройств /dev/tcp и /dev/udp соответственно. В данном руководстве мы постараемся разобраться в том, как открывать TCP-/UDP-сокеты, а также осуществлять посредством них прием и передачу данных в процессе работы с командной оболочкой bash.

Открытие и закрытие TCP-/UDP-сокета средствами командной оболочки bash

По сути, вы можете открыть TCP-/UDP-сокет средствами командной оболочки bash, воспользовавшись следующей синтаксической конструкцией:

$ exec {дескриптор-файла}<>/dev/{протокол}/{адрес-узла}/{номер-порта}

Вместо строки "дескриптор-файла" следует использовать уникальные неотрицательные целочисленные идентификаторы (дескрипторы), которые будут ассоциированы с каждым из создаваемых сокетов. Файловые дескрипторы 0, 1 и 2 зарезервированы за стандартными потоками ввода (stdin), вывода (stdout) и ошибок (stderr) соответственно. Исходя из этого, вы должны использовать значения, начиная с 3 (которые не используются) в качестве файловых дескрипторов.

Сочетание символов "<>" указывает на то, что сокет должен быть открыт для чтения и записи. В зависимости от ваших потребностей, вы можете открыть сокет только для чтения ("<") или только для записи (">").

В поле "протокол" может располагаться строка "tcp", либо "udp". Назначение полей "адрес-узла" и "номер-порта" не требует особых комментариев.

Например, для открытия двунаправленного TCP-сокета, соединенного с основным портом HTTP-сервера ресурса xmodulo.com, с файловым дескриптором 3 достаточно выполнить следующую команду:

$ exec 3<>/dev/tcp/xmodulo.com/80

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

$ exec {дескриптор-файла}<&-
$ exec {дескриптор-файла}>&-

Прием и передача данных через TCP-/UDP-сокет средствами командной оболочки bash

После открытия сокета вы можете использовать его для приема или передачи сообщений.

Для передачи сообщения, хранящегося в переменной $MESSAGE, через сокет следует использовать одну из следующих команд:

$ echo -ne $MESSAGE >&3
$ printf $MESSAGE >&3

Для чтения сообщения из сокета и сохранения его в переменной $MESSAGE — одну из следующих команд (в переменных $NUM_BYTES и $COUNT должны храниться числовые значения, равные количеству байт сообщения и количеству сообщений соответственно — прим.пер.):

$ read -r -u -n $MESSAGE <&3
$ MESSAGE=$(dd bs=$NUM_BYTES count=$COUNT <&3 2> /dev/null)

Примеры использования TCP-/UDP-сокетов при работе с командной оболочкой bash

Ниже я привел несколько примеров сценариев, в рамках которых создаются и используются TCP-сокеты.

1. Получение веб-страницы с удаленного сервера и вывод ее исходного кода

#!/bin/bash
exec 3<>/dev/tcp/xmodulo.com/80
echo -e "GET / HTTP/1.1\r\nhost: xmodulo.com\r\nConnection: close\r\n\r\n" >&3
cat <&3

2. Вывод информации о версии установленного на удаленном узле SSH-сервера

#!/bin/bash
exec 3</dev/tcp/192.168.0.10/22
timeout 1 cat <&3

Фактически, приведенный выше сценарий может быть сокращен до следующего однострочного сценария:

#!/bin/bash
timeout 1 cat </dev/tcp/192.168.0.10/22

3. Вывод информации о текущем времени, полученной с веб-сайта nist.gov

#!/bin/bash
cat </dev/tcp/time.nist.gov/13

4. Проверка работоспособности соединения с сетью Интернет

#!/bin/bash
 
HOST=www.mit.edu
PORT=80
 
(echo >/dev/tcp/${HOST}/${PORT}) &>/dev/null
if [ $? -eq 0 ]; then
    echo "Соединение успешно установлено"
else
    echo "Не удалось установить соединение"
fi

5. Сканирование TCP-портов удаленного узла

#!/bin/bash
host=$1
port_first=1
port_last=65535
for ((port=$port_first; port<=$port_last; port++))
do
  (echo >/dev/tcp/$host/$port) >/dev/null 2>&1 && echo "Порт $port открыт"
done

Заключительные слова

Для получения возможности открытия сокетов средствами командной оболочки bash необходима активация механизма поддержки виртуальных файлов устройств сокетов на этапе сборки бинарного файла этой командной оболочки из исходных кодов (т.е., его сборки с активацией возможности "--enable-net-redirections"). В устаревших версиях дистрибутивов данная возможность bash может быть деактивирована, причем в этом случае вы будете получать следующее сообщение об ошибке после каждой попытки открытия сокета:

/dev/tcp/xmodulo.com/80: No such file or directory

Помимо командной оболочки bash, виртуальные устройства сокетов поддерживаются такими командными оболочками, как ksh и zsh.



Средняя оценка 4 при 1 голосовавших