Linux netcat слушатель (nc -l) завис

488
Thomas Grusz

На моем терминале Raspberry Pi 3 (Linux) я набрал следующее и нажал Enter:

printf 'HTTP/1.1 302 Moved\r\nLocation: https://www.eff.org/' | nc -l 2345 

Raspberry Pi 3 является частью моей домашней сети с фиксированным адресом 192.168.0.8. Затем на своем Mac я набрал в браузере следующее (Chrome) и нажал Enter:

192.168.0.8:2345 

Я вижу запрос браузера GET на моем терминале Linux (Raspberry Pi), но ncслушатель застревает и не отправляет ответ (сообщение перенаправления HTTP 302) в браузер.

Только когда я прекращаю ncпрограмму нажатием Ctrl+ C, браузер получает ответное сообщение и отображает https://www.eff.orgвеб-сайт.

У кого-нибудь есть идея, почему ncслушатель застревает вместо того, чтобы отправить ответ и закрыть соединение?

0
(1) Откуда вы знаете, что процесс `nc` застрял? Вы сделали "связку" или понюхали сеть? (2) Но сначала попробуйте добавить еще один `\ r \ n` в конец текстовой строки` printf`. G-Man 6 лет назад 0

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

0
Kamil Maciorowski

Я повторил твою проблему. Когда я подключаюсь к другому, ncа не к браузеру, я вижу, что ответ отправляется немедленно. Я думаю, что ваш браузер также получает ответ, но так ncкак не прерывает соединение, браузер не знает, что это все, и все в порядке, чтобы продолжить перенаправление.

(Примечание: во время моих тестов мне понадобился финал \r\nв ответе от, ncчтобы успешно перенаправить мой браузер, поэтому все мои примеры используют это исправление.)


Редактировать: простое исправление

Здесь я нашел следующее:

HTTP-запросы и HTTP-ответы используют общий формат сообщения RFC 822 для передачи требуемых данных. Этот общий формат сообщения состоит из следующих четырех элементов.

  • [...]
  • [...]
  • Пустая строка (т. Е. Строка, не предшествующая CRLF), указывающая конец полей заголовка
  • [...]

Итак, ваш ответ должен быть:

printf 'HTTP/1.1 302 Moved\r\nLocation: https://www.eff.org/\r\n\r\n' | ... 

После получения этого ваш браузер должен продолжить перенаправление, разорвав соединение ncот своего имени. В начале декабря 2017 года он работает с Оперой и Вивальди; он не работает с Firefox, Chrome или Safari, для которых вам может потребоваться другое исправление (см. ниже).



Оригинальный, теперь неполноценный ответ (он все еще может быть полезен для связи не с HTTP nc)

В соответствии с этим ответом на сервере Fault вам нужно использовать -c, -qили аналогичный вариант, в зависимости от ncреализации.

В моем Debian установлена ​​соответствующая -qверсия. затем

printf 'HTTP/1.1 302 Moved\r\nLocation: https://www.eff.org/\r\n' | nc -q 0 -l -p 2345 

работает нормально (обратите внимание, мне также нужно -pуказать порт). Объяснение:

-q seconds
после того, как EOFна stdin, ждать определенное количество секунд, а затем бросить курить. Если секунды отрицательны, подождите вечно (по умолчанию).


Если у вас ncнет подходящей опции, то обходной путь может заключаться в обнаружении связи с клиентом и уничтожении всей командной строки. Пример, который работает в моем Debian bash:

printf 'HTTP/1.1 302 Moved\r\nLocation: https://www.eff.org/\r\n' | nc -l -p 2345 | { read foo; sleep 1; kill 0; } 

При запуске канала bashвсе процессы помещаются в одну группу процессов; kill 0отправляет сигналы всей группе процессов. Этот способ ncуничтожается примерно через 1 секунду после получения любого инициирующего запроса read.

Спасибо! Я попробовал простое исправление, добавив \ r \ n \ r \ n в конце строки, как вы предложили. Это работает только в браузере Opera (последняя версия). Однако с Firefox, Chrome или Safari (все последние версии) процесс все равно застревает. Но когда я добавляю опцию `-q 0` к команде` nc`, она работает во всех браузерах. Thomas Grusz 6 лет назад 0
@ThomasGrusz Спасибо. Я протестировал Vivaldi и добавил в свой ответ примечание о совместимости браузера - для будущих пользователей. Kamil Maciorowski 6 лет назад 0