98

Я хочу закрыть открытый порт, который находится в режиме прослушивания между моим клиентским и серверным приложением.

Есть ли какая-либо опция командной строки в Linux для закрытия порта?

ПРИМЕЧАНИЕ: я узнал, что «только приложение, которому принадлежит подключенный сокет, должно закрывать его, что произойдет, когда приложение завершится».

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

13 ответов13

118

У меня была такая же проблема, процесс должен остаться в живых, но сокет должен закрыться. Закрытие сокета в работающем процессе не является невозможным, но трудным:

  1. найдите процесс:

    netstat -np
    

    Вы получаете source/destination ip:port portstate pid/processname map процесса

  2. найдите дескриптор файла сокета в процессе

    lsof -np $pid
    

    Вы получаете список: имя процесса, pid, пользователь, fileDescriptor, ... строка подключения.

    Найдите соответствующий номер fileDescriptor для соединения.

    Теперь подключите процесс:

    gdb -p $pid
    
  3. Теперь закройте сокет:

    call close($fileDescritor)
    
    //does not need ; at end.
    

    Затем отсоедините:

    quit
    

    И розетка закрыта.

75

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

Порты - это ресурсы, выделяемые ОС различным процессам. Это похоже на запрос ОС к указателю файла. Однако, в отличие от файловых указателей, порт может иметь только ОДИН процесс за раз. Через интерфейс сокета BSD процессы могут сделать запрос на прослушивание порта, который ОС затем предоставит. ОС также будет следить за тем, чтобы другие процессы не получали такой же порт. В любой момент процесс может освободить порт, закрыв сокет. Затем ОС восстановит порт. В качестве альтернативы, если процесс завершится без освобождения порта, ОС в конечном итоге восстановит порт (хотя это произойдет не сразу: это займет несколько минут).

Теперь то, что вы хотите сделать (просто закрыть порт из командной строки), невозможно по двум причинам. Во-первых, если бы это было возможно, это означало бы, что один процесс мог просто украсть ресурс другого процесса (порт). Это было бы плохой политикой, если не ограничено привилегированными процессами. Вторая причина - неясно, что произойдет с процессом, которому принадлежит порт, если мы позволим ему продолжить работу. Код процесса написан в предположении, что он владеет этим ресурсом. Если бы мы просто забрали его, он сам бы закончился сбоем, поэтому ОС не позволяет вам этого делать, даже если вы являетесь привилегированным процессом. Вместо этого вы должны просто убить их.

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

sudo netstat -ap | grep :<port_number>

Это выведет строку, соответствующую порту удержания процесса, например:

tcp  0  0 *:8000   *:* LISTEN  4683/procHoldingPort

В этом случае procHoldingPort - это имя процесса, который открыл порт, 4683 - это его pid, а 8000 (обратите внимание, что это TCP) - это номер порта, который он содержит.

Затем посмотрите в последнем столбце, вы увидите /. Затем выполните это:

kill  <pid>

Если это не сработает (вы можете проверить, повторно выполнив команду netstat). Сделай это:

kill -9 <pid>

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

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

19

Фьюзер также может быть использован

fuser -k -n *protocol portno*

Здесь протокол tcp/udp, а portno - номер, который вы хотите закрыть. Например

fuser -k -n tcp 37

Больше информации на странице man fuser

5

В качестве альтернативы вы можете использовать iptables:

iptables -I INPUT -p tcp --dport 80 -j DROP

Это в основном выполняет то, что вы хотите. Это отбросит весь трафик TCP на порт 80.

3
netstat -anp | grep 80

Он должен сказать вам, если вы используете apache, "httpd" (это только пример, используйте порт, который ваше приложение использует вместо 80)

pkill -9 httpd 

или же

killall -9 httpd
2

Вы могли бы просто узнать, какой процесс открыл сокет, с которым связан порт, и убить этот процесс.

Но вы должны понимать, что если у этого процесса нет обработчика, который деинициализирует весь используемый им материал (открытые файлы, сокеты, вилки, вещи, которые могут задерживаться, если он не будет закрыт должным образом после завершения), вы бы создали перетащите на производительность системы. Кроме того, сокет будет оставаться открытым, пока ядро не поймет, что процесс был убит. Обычно это занимает около минуты.

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

Если вы пытаетесь положить конец обнаруженному бэкдору или вирусу, то вам следует, по крайней мере, узнать, какие данные передаются взад-вперед, прежде чем уничтожить их. (wireshark хорош для этого) (И имя исполняемого файла процесса, чтобы вы могли удалить его и предотвратить его повторный запуск при перезагрузке) или, если это что-то, что вы установили (например, HTTPD или FTPD или что-то), то у вас уже должен быть доступ к сам процесс.

Обычно это будет управляющая программа (HTTPD stop | start или что-то в этом роде). Или, если это системная вещь, вы, вероятно, не должны связываться с ней. Во всяком случае, я подумал, что, поскольку все остальные дают вам угол «как», я должен дать вам предостережения.

2

Сначала я искал процессы монго и ноды, затем сделал следующее:

ps -A | grep node

10418 pts/23   00:00:05 node

10551 pts/23   00:00:00 node

ps -A | grep mongo

10490 pts/23   00:00:00 mongod

После идентификации просто убейте процессы командой kill.

kill -9 10418
kill -9 10490

Наконец, введите meteor и он должен снова работать.

1

Если вы хотите, чтобы ваш порт был освобожден раньше, вам необходимо установить следующее значение:

echo 1 > /proc/sys/net/ipv4/tcp_fin_timeout

установить от 60 секунд (по умолчанию) до 1 секунды

1

Я знаю, что этот ответ, собственно говоря, не отвечает самому вопросу, но, читая его, это может быть важной информацией:

Поведение по умолчанию привязки сокета к порту (и адресу) таково, что когда сокет закрывается из-за внезапного завершения процесса, сокет некоторое время будет оставаться в TIME_WAIT. Это будет означать, что вы не можете немедленно повторно привязать этот адрес / порт. Если вы разрабатываете саму систему через стандартный интерфейс сокетов BSD, вы можете (по крайней мере, до некоторой степени) управлять этим поведением с помощью опции сокета SO_REUSEADDR. В основном это позволит вам снова подключиться к тому же адресу / порту, если сокет находится в состоянии TIME_WAIT. Тем не менее, один сокет на порт!

Однако эту информацию следует использовать только в качестве вспомогательного средства для разработки, поскольку существует причина существования TIME_WAIT в первую очередь, уже объясненная в других ответах.

1

Вы можете написать скрипт, который модифицирует iptables и перезапускает их. Один скрипт для добавления правила отбрасывания всех пакетов на порт, другой скрипт для удаления указанного правила.

Другие ответы показали, как убить процесс, связанный с портом - это может быть не то, что вам нужно. Если вы хотите, чтобы сервер продолжал работать, но для предотвращения соединений с клиентами, то вы хотите заблокировать порт, а не останавливать процесс.

1

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

  • синтаксис:
killcx [dest_ip:dest_port] {interface}

  dest_ip              : remote IP
  dest_port            : remote port
  interface (optional) : network interface (eth0, lo etc).
  • пример:
killcx 120.121.122.123:1234
killcx 120.121.122.123:1234 eth0
1

Еще одна проблема: иногда ядру принадлежат сами порты. Я знаю, что NAT-маршрутизация держит некоторые порты открытыми для использования NAT. Вы не можете убить процесс для этого, это ядро, и требуется перенастройка и перезагрузка.

0

Если вам не нужен трафик через сокет, но вы хотите сохранить процесс: tcpkill.

tcpkill -i eth0 host xxx.xxx.xxx.xxx and port yyyy

Запустит демон прослушивания, который перехватывает и перехватывает весь трафик на этом порту. Очень удобно для тестирования ваших приложений на разрыв сети.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .