Проблема с netcat по UDP

2032
jia103

Во время устранения проблемы, описанной здесь, я попробовал кое-что действительно простое: я попытался настроить очень простое соединение Netcat через UDP, и я заметил, что оно не работает, как я ожидаю.

Как и в приведенном ниже рисунке TCP, я ожидал, что случай UDP будет отображать тот же вывод в окне 1, что и при наборе в окне 2; вместо этого я не получаю вывод в окне 1 в случае UDP.

Я использую Debian Jessie на своем ноутбуке, и у меня работает Wireshark со следующим фильтром захвата:

udp and not (port 123 or port 5353 or port 1900) 

В одном окне терминала я начал с теста TCP, выполнив следующую команду:

$ nc -l 6900 

Во втором окне терминала я запустил следующее:

$ nc localhost 6900 

В окне 2 я набрал «one» и нажал Enter, затем набрал «two» и нажал Enter, и наконец я нажал Ctrl + D для выхода.

После нажатия Enter на «один», я увидел «один», отраженный в окне 1. После нажатия «Enter» на «два», я увидел «два», отраженный в окне 1. Когда я нажал Ctrl + D, оба экземпляра netcat вышли, и я вернулся на подсказку.

Это демонстрирует, что я мог получить соединение TCP без проблем. Далее я попробовал UDP.

Окно 1:

$ nc -l -u 6900 

Окно 2:

$ nc -u localhost 6900 

Это забавно. Я думаю, что я мог бы только набрать «один», нажать Enter, затем «два» и нажать Enter, и я автоматически вернулся к приглашению в окне 2.

В окне 1 я не вижу никакого вывода.

Я повторил -vв окне 1:

$ nc -v -l -u 6900 Listening on [0.0.0.0] (family 0, port 6900) 

Забавно, когда я повторил -vв окне 2:

$ nc -v -u localhost 6900 $ 

Это как netcat никогда не бежал; Я немедленно вернулся к подсказке.

Обновление: если я заменю localhostна 127.0.0.1, прогресс будет достигнут.

С «сервером», слушающим в Окне 1:

$ nc -v -l -u 6900 one two three 

Мне удалось получить вывод эхом из окна 2 при вводе «один», «два» и «три»:

$ nc -u 127.0.0.1 6900 one two three ^C 

Это -vвсе еще озадачивает, потому что это то же самое, что и выше.

2

2 ответа на вопрос

4
Kamil Maciorowski

ТЛ; др

Смотрите выводы в самом конце.


преамбула

Я могу объяснить ваши результаты. Я использую Kubuntu, а не Debian, но все же я считаю, что основные моменты являются общими. Чтобы полностью понять, что происходит, полезно проанализировать случай TCP, а затем сравнить с UDP.

Если вы хотите повторить мое исследование, не прекращайте и не убивайте, ncесли я не скажу об этом или оно не прекратится само по себе. Убей, ncкогда я скажу. Это очень важно. Прочитав полный ответ, вы поймете смысл этого.

Этот анализ требует нескольких терминалов (или tmux, или screen).


TCP чехол

Сначала избавьтесь от всех предыдущих ncпроцессов.

killall nc 

Запустите процесс прослушивания:

nc -l 6900 

Изучите вывод lsof -i :6900. Ваш ncуказан как процесс прослушивания там.

Запустите процесс подключения:

nc localhost 6900 

Изучите вывод lsof -i :6900. Два ncs - это концы установленного соединения.

Поскольку ваш первый ncне слушает больше, вы можете запустить второй процесс прослушивания:

nc -l 6900 

и второй процесс подключения:

nc localhost 6900 

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

Проверьте еще lsof -i :6900раз. Хотя два (ранее) прослушивающих ncиспользуют один и тот же порт 6900, два соединения не смешиваются, потому что ncна других концах используются разные порты. Когда пакет приходит в 6900порт, ядро ​​проверяет этот другой порт и решает, кто из (ранее) прослушивающих ncдолжен его получить.

Вы можете запустить дополнительные (непарные) подключения nc:

nc localhost 6900 || echo fail 

и это немедленно провалится.

У вас все еще есть два отдельных соединения. Завершите одну ncиз каждой пары с помощью Ctrl+ Cили Ctrl+, Dи вы заметите, что соответствующие концы также прекратятся. Это потому, что TCP ориентирован на соединение. Когда соединение изящно завершается с любого из его концов, другой конец уведомляется, чтобы он мог соответственно реагировать - в этом случае ncпросто завершается.


Случай UDP

Важный:

killall nc 

Выполните следующие команды последовательно, каждая в отдельной консоли. Также проверьте lsof -i :6900после каждого, чтобы увидеть, что происходит. Команды:

nc -ul 6900 nc -u localhost 6900 

Введите что-то в первую очередь («прослушивание») nc(хит Enter); проверить lsof -i :6900; наберите что-нибудь во второй nc(хит Enter); проверьте еще lsof -i :6900раз и обратите внимание на изменение.

Затем подготовьте другую пару (в отдельных консолях):

nc -ul 6900 nc -u localhost 6900 

Передайте несколько строк назад и вперед, чтобы увидеть, работает ли это. Завершите один ncс Ctrl+ C( Ctrl+ Dне будет работать) и заметьте, что другой nc(на соответствующем конце) все еще работает. Другая сторона «соединения» не знает, когда «соединение» «прервано». Как вы могли видеть, lsofон не знает, что «соединение» «установлено», пока данные не начнут течь.

Я приведу здесь несколько слов, потому что UDP не использует соединение, и в этом главное отличие.


Что может быть сложным?

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

Важный:

killall nc 

Подготовьте «прослушивание» nc:

nc -ul 6900 

Проверьте lsof -i :6900. Вывод будет выглядеть так:

… UDP *:6900 

Подготовьте «соединение» nc:

nc -u localhost 6900 

Проверьте lsof -i :6900. Пример вывода (ваш 54766может отличаться):

… UDP *:6900 … UDP localhost:54766->localhost:6900 

Передайте некоторые данные от второго ncк первому. Проверьте lsof -i :6900:

… UDP localhost:6900->localhost:54766 … UDP localhost:54766->localhost:6900 

Завершите второе ncс помощью Ctrl+ C. Еще раз lsof -i :6900:

… UDP localhost:6900->localhost:54766 

Это означает, что первый nc«общается» только с портом 54766на другом конце «соединения». Когда вы пытаетесь соединиться с третьим nc:

nc -u localhost 6900 

Скорее всего, он выберет другой случайный порт на своей стороне. Попытайся. Вы сможете "пропустить" (примерно) две строки, как вы это делали в своем вопросе, прежде чем это ncзакончится.

(Примечание: это ncзавершается из-за ICMP-пакета, см. Это ; вы можете захватить пакет, wiresharkкак я.)

Однако вы можете принудительно настроить правильный порт (изменить, 54766чтобы он соответствовал вашему lsofвыводу):

nc -up 54766 localhost 6900 

и этот четвертый ncсможет передавать данные! Первый ncне увидит разницы. Будет так, как если бы второе ncникогда не заканчивалось.

Завершите четвертый, ncпрежде чем продолжить. Оставьте первый работающим.


-vвариант

Последняя загадка: почему nc -v -u localhost 6900немедленно ушли?

В приведенном выше примере у нас было четыре ncс:

  1. первый - «слушающий»;
  2. вторая - успешно подключена, затем прекращена;
  3. третий - невозможно подключиться из-за неправильного локального порта;
  4. четвертый - возможность подключения благодаря правильному (принудительному) локальному порту.

В моем Kubuntu nc -uv …, если это второй, передает мало Xсимволов, вероятно, чтобы проверить соединение. По этой причине, если он третий, ему не нужно (около) двух строк внешнего ввода для сбоя, он сразу выходит из строя. После первого nc запуска попробуйте:

nc -uv localhost 6900 

Это должно потерпеть неудачу. Опять же, вы можете принудительно настроить правильный порт, и он будет работать так же, как четвертый nc в приведенном выше примере.

nc -uvp 54766 localhost 6900 

Когда я вызываю это, я вижу Xнапечатанные -s в консоли первого nc .


очищающий

killall nc 

Выводы

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

Если я заменю localhostс 127.0.0.1, есть прогресс

Ненужные. Я полагаю, в этом случае вы только начали чистить, как мы сделали после killall nc.

Этот ответ дает отличные детали, и я смог проследить его до конца; однако мне нужно было изменить многие команды `nc`, чтобы дополнительно указать` -4` в ответе Даниэля. jia103 6 лет назад 0
3
Daniel B

Используя macOS, я прихожу к другому выводу. Ключ IPv6. localhostразрешает как IPv6, так и IPv4. Однако следующая командная строка вызовет ncпрослушивание IPv4:

nc -l -u 6900 

Результат:

$ lsof -n -i:6900 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME nc 63923 fuzzy 3u IPv4 0xad7f669b928a178b 0t0 UDP *:6900 

Теперь, когда вы используете это для «подключения»:

nc -u localhost 6900 

... это на самом деле подключается к IPv6. При использовании 127.0.0.1его не будет.

Однако он не подключается, потому что UDP не подключен. Таким образом, нет способа узнать, существует ли действительно удаленный конец соединения. Таким образом, он не может обнаружить, что должен вернуться к IPv4. Ваши сообщения будут отправлены, но ничего не прослушивается.

При отправке можно наблюдать следующее:

$ tcpdump -i lo0 udp port 6900 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on lo0, link-type NULL (BSD loopback), capture size 262144 bytes 00:46:37.543273 IP6 localhost.54473 > localhost.6900: UDP, length 6 

С помощью TCP он попытается подключиться по IPv6, определит, что это не работает, и повторите попытку с IPv4:

$ tcpdump -i lo0 port 6900 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on lo0, link-type NULL (BSD loopback), capture size 262144 bytes 00:50:21.495107 IP6 localhost.64306 > localhost.6900: Flags [SEW], seq 1432891337, win 65535, options [mss 16324,nop,wscale 5,nop,nop,TS val 766376063 ecr 0,sackOK,eol], length 0 00:50:21.495136 IP6 localhost.6900 > localhost.64306: Flags [R.], seq 0, ack 1432891338, win 0, length 0 00:50:21.495231 IP localhost.64307 > localhost.6900: Flags [S], seq 307818799, win 65535, options [mss 16344,nop,wscale 5,nop,nop,TS val 766376063 ecr 0,sackOK,eol], length 0 00:50:21.495283 IP localhost.6900 > localhost.64307: Flags [S.], seq 4254625238, ack 307818800, win 65535, options [mss 16344,nop,wscale 5,nop,nop,TS val 766376063 ecr 766376063,sackOK,eol], length 0 00:50:21.495295 IP localhost.64307 > localhost.6900: Flags [.], ack 1, win 12759, options [nop,nop,TS val 766376063 ecr 766376063], length 0 00:50:21.495306 IP localhost.6900 > localhost.64307: Flags [.], ack 1, win 12759, options [nop,nop,TS val 766376063 ecr 766376063], length 0 

Вы можете заставить ncиспользовать IPv4:

nc -4u localhost 6900