Fechando manualmente uma porta a partir da linha de comando

112

Desejo fechar uma porta aberta que esteja no modo de escuta entre meu aplicativo cliente e servidor.

Existe alguma opção de linha de comando manual no Linux para fechar uma porta?

NOTA: Soube que "somente o aplicativo que possui o soquete conectado deve fechá-lo, o que acontecerá quando o aplicativo terminar".

Não entendo por que isso só é possível pelo aplicativo que o abre ... Mas ainda estou ansioso para saber se existe outra maneira de fazer isso.

Glorfindel
fonte
5
Não, as portas abertas pertencem ao processo que as abriu, não há controle possível de fora. O que é uma coisa boa, ou todos os aplicativos teriam que antecipar que suas portas abertas (e arquivos) fossem alteradas. No entanto, você pode bloquear o tráfego para uma porta usando firewall (iptables), mas isso não fecha e abre a porta para outro uso.
Jürgen Strobel
10
Muitos respondentes perderam o objetivo desta pergunta. Não faz sentido declarar que apenas o aplicativo que possui a porta pode desconectá-la. Eu posso desconectá-lo caminhando até a caixa e puxando o cabo ethernet para fora do soquete ou matando o aplicativo na outra extremidade da conexão! O aplicativo deve ser escrito para lidar com isso. Então --- como você testa para garantir que o aplicativo seja escrito corretamente sem exigir intervenção física e / ou controle do outro computador?
Dale Wilson
"... não há controle possível do lado de fora." Essa é uma observação importante, que me guiou para a próxima pergunta: como posso fazer parte do processo de fora? GDB.
Dankó Dávid
@ JürgenStrobel De fato, é possível ter controle externo - tanto o tcpkill quanto o ss podem fazer exatamente o que é solicitado. Porque portas abertas realmente não pertencem a um processo; eles são recursos do kernel, com alguns direitos atribuídos a um processo, mas ainda existem apenas no prazer do kernel.
Tom Anderson
@ tom-anderson DaleW: o tcpkill é uma ferramenta de firewall e mencionei essa opção. Você pode impedir o tráfego para uma porta, que é diferente de fechar uma porta (soquete).
Jürgen Strobel

Respostas:

134

Eu tive o mesmo problema, o processo deve permanecer vivo, mas o soquete deve fechar. Fechar um soquete em um processo em execução não é impossível, mas difícil:

  1. localize o processo:

    netstat -np
    

    Você pega um source/destination ip:port portstate pid/processnamemapa

  2. localize o descritor de arquivo do soquete no processo

    lsof -np $pid
    

    Você obtém uma lista: nome do processo, pid, usuário, fileDescriptor, ... uma cadeia de conexão.

    Localize o número fileDescriptor correspondente para a conexão. Será algo como "97u", que significa "97".

  3. Agora conecte o processo:

    gdb -p $pid
    
  4. Agora feche o soquete:

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

    exemplo:

    call close(97)
    

    Em seguida, desanexe o gdb:

    quit
    

    E a tomada está fechada.

Dankó Dávid
fonte
1
sudo lsof -np $piddá-me cerca de 200 linhas e estou confuso sobre como encontrar o FD desejado. No meu processo caso é um separador Chrome e eu estou tentando fechar websockets abertos ...
SET
2
Uma linha normalmente se parece com: firefox 14812 szupervigyor 97u IPv4 32814564 0t0 TCP 192.168.2.4:40385->173.194.39.65:https (ESTABLISHED) como: process_name pid user fd [open_for] protocolo dispositivo inode protocol_data_toString
Dankó Dávid
2
* Uma linha normalmente se parece com: firefox 14812 szupervigyor 97u IPv4 32814564 0t0 TCP 192.168.2.4:40385->173.194.39.65:https (ESTABLISHED) como: process_name pid user fd [open_for] protocolo dispositivo inode protocol_data_toString Você precisa conhecer o ip remoto endereço e encontrar no último col. No meu exemplo, o 97 é o FileDescriptor. A pesquisa é difícil se você abriu várias conexões com o host de destino.
Dankó Dávid
7
esta é uma solução brilhante
Marcorossi
8
Se você quiser simular o socket sendo fechado até o final remoto (por exemplo, o ponto de sair) é melhor usar shutdown: call shutdown($fileDescriptor, 0).
ecatmur
75

Você está fazendo a pergunta errada aqui. Não é realmente possível simplesmente "fechar uma porta" de fora do aplicativo que abriu o soquete. A única maneira de fazer isso é matar completamente o processo que possui a porta. Então, em cerca de um minuto ou dois, a porta ficará disponível novamente para uso. Aqui está o que está acontecendo (se você não se importa, pule para o final, onde eu mostro como eliminar o processo que possui uma porta específica):

Portas são recursos alocados pelo sistema operacional para diferentes processos. Isso é semelhante a pedir ao sistema operacional um ponteiro de arquivo. No entanto, diferentemente dos ponteiros de arquivo, apenas UM processo de cada vez pode possuir uma porta. Por meio da interface do soquete BSD, os processos podem solicitar uma escuta em uma porta, que o sistema operacional concederá. O sistema operacional também garantirá que nenhum outro processo obtenha a mesma porta. A qualquer momento, o processo pode liberar a porta fechando o soquete. O sistema operacional recuperará a porta. Como alternativa, se o processo terminar sem liberar a porta, o sistema operacional acabará por recuperá-la (embora isso não aconteça imediatamente: levará alguns minutos).

Agora, o que você deseja fazer (basta fechar a porta na linha de comando) não é possível por dois motivos. Primeiro, se fosse possível, isso significaria que um processo poderia simplesmente roubar o recurso de outro processo (a porta). Isso seria uma política ruim, a menos que restrito a processos privilegiados. A segunda razão é que não está claro o que aconteceria com o processo que possuía a porta se a deixássemos continuar em execução. O código do processo é escrito assumindo que ele possui esse recurso. Se simplesmente o retirássemos, ele acabaria travando por conta própria, para que os sistemas operacionais não o deixem fazer isso, mesmo que você seja um processo privilegiado. Em vez disso, você deve simplesmente matá-los.

De qualquer forma, veja como matar um processo que possui uma porta específica:

sudo netstat -ap | grep :<port_number>

Isso produzirá a linha correspondente à porta de retenção do processo, por exemplo:

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

Nesse caso, procHoldingPort é o nome do processo que abriu a porta, 4683 é seu pid e 8000 (observe que é TCP) é o número da porta que possui.

Então, olhe na última coluna, você verá /. Em seguida, execute o seguinte:

kill  <pid>

Se isso não funcionar (você pode verificar executando novamente o comando netstat). Fazem isto:

kill -9 <pid>

Em geral, é melhor evitar o envio de SIGKILL, se puder. É por isso que eu digo para você tentar killantes kill -9. Apenas usar killenvia o SIGTERM mais suave.

Como eu disse, ainda levará alguns minutos para a porta reabrir se você fizer isso. Não sei como acelerar isso. Se alguém o fizer, eu adoraria ouvir.

Guy Avraham
fonte
@smehmood - Obrigado pela explicação detalhada .. Uma pequena dúvida .. Como o kernel recupera uma porta aberta por um processo interrompido abruptamente? .. a solução u fornecido parece estar matando o processo segurando a porta ...
3
@codingfreak O kernel sabe que o processo se foi. Ele sabe que pode recuperar a porta. Na verdade, existem regras sobre o momento de fechar a porta, para garantir que não haja pacotes perdidos flutuando na rede. Como ele sabe que possui esses recursos? é isso que o kernel faz, acompanha as coisas.
Rich Homolka
Até que alguém poste algo sensato como unix.tools.port.close(<my port number>)eu usaria init 6.
Snowcrash
Esta é uma excelente resposta para uma pergunta diferente. Esta pergunta é sobre anexar um depurador e alterar um programa em execução para fazer com que esse programa chame uma função em um descritor de arquivo.
Arthur Ulfeldt
19

O fusor também pode ser usado

fuser -k -n *protocol portno*

Aqui, o protocolo é tcp / udp e portno é o número que você deseja fechar. Por exemplo

fuser -k -n tcp 37

Mais informações na página de manual do fusor

Barão Vermelho
fonte
Apenas matar o processo de posse não funcionou para mim, mas o fusor funcionou. Valeu!
Webwurst
Eu obtive resultados mistos com ele, mesmo depois de usar o fusor, obtive "soquete já em uso" ao tentar reutilizar a porta do aplicativo morto, mesmo fazendo isso como root. Por outro lado, o tempo para liberar o soquete parecia menor do que antes, então, de qualquer forma, obrigado.
Jan Vlcinsky
@JanVlcinsky Talvez exista um processo de "guardião" que reinicie o processo morto momentos após a fuserexecução?
RedBaron
@ RedBaron: de acordo com o comentário superuser.com/a/415236/153413, meu problema se origina em aplicativos mal escritos, que não limpam / fecham o soquete em terminação. Portanto, fuserlocaliza o processo usando a porta e a mata, mas não resolve o fato de que o soquete não está fechado. 60 segundos e o kernel faz isso por mim.
Jan Vlcinsky
6

Você também pode usar o iptables:

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

Basicamente, realiza o que você deseja. Isso descartará todo o tráfego TCP para a porta 80.

supercheetah
fonte
4
Não, isso manterá o soquete aberto até que todos os tempos limite os fechem. (Ele ocultará todo o tráfego do processo de propriedade que, então, não tem como saber que deve fechá-lo.) Você poderia usar -j REJECTpara retornar o sinalizador de redefinição de TCP, que seria visto como meu processo de propriedade (mas apenas quando o outro lado tentar para enviar algo).
Marki555
3
netstat -anp | grep 80

Deve informar, se você estiver executando o apache, "httpd" (este é apenas um exemplo, use a porta que seu aplicativo está usando, em vez de 80)

pkill -9 httpd 

ou

killall -9 httpd
Ben
fonte
4
tente uma morte normal, antes de recorrer a -9
Thilo
@omfgroflmao - Mas isso matará o processo que abriu a porta?
@codingfreak O processo que está segurando a porta, sim, ela a mata.
2

Você provavelmente poderia descobrir qual processo abriu o soquete ao qual a porta está associada e eliminar esse processo.

Mas, você teria que perceber que, a menos que esse processo tenha um manipulador que des-inicialize todas as coisas que estava usando (arquivos abertos, soquetes, garfos, coisas que podem permanecer a menos que seja fechado corretamente após a rescisão), você teria criado isso arraste no desempenho do sistema. Além disso, o soquete permanecerá aberto até que o kernel perceba que o processo foi encerrado. Isso geralmente leva apenas um minuto.

Suponho que a melhor pergunta seria: Qual porta (pertencente a qual processo) você deseja parar?

Se você está tentando acabar com um backdoor ou vírus que encontrou, pelo menos deve saber quais dados estão indo e voltando antes de finalizá-los. (o wireshark é bom para isso) (e o nome do executável do processo para que você possa excluí-lo e impedir que ele volte à reinicialização) ou, se for algo que você instalou (como HTTPD ou FTPD ou algo assim), então você já deve ter acesso a o próprio processo.

Normalmente ele terá um programa de controle (HTTPD stop | start ou algo assim). Ou, se for uma coisa do sistema, você provavelmente não deve mexer com isso. Enfim, eu pensei que, já que todo mundo está lhe dando o ângulo "como fazer", eu deveria lhe dar as advertências.

jackenheimer
fonte
Muito bom comentário. Eu tenho um programa que, em terminação, não fecha o soquete, o que resulta no comportamento descrito - o soquete fica inutilizável por cerca de 60 segundos. Quando paro e inicio esse processo, está reclamando por cerca de um minuto que o endereço e a porta já estão em uso. A melhor solução é corrigir o mau comportamento do processo para fechar corretamente, mas às vezes isso não é uma opção. Existe uma maneira de pedir ao kernel que verifique esse soquete bloqueado antes de 60 segundos?
Jan Vlcinsky
2

Procurei primeiro os processos mongo e node e, em seguida, fiz o seguinte:

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

Uma vez identificado, basta matar os processos com o comando kill.

kill -9 10418
kill -9 10490

Por fim, digite meteore deve estar funcionando novamente.

abautista
fonte
1

Você pode escrever um script que modifique as tabelas de ip e as reinicie. Um script para adicionar uma regra descartando todos os pacotes na porta, outro script para remover a referida regra.

As outras respostas mostraram como matar o processo vinculado à porta - isso pode não ser o que você deseja. Se você deseja que o servidor continue em execução, mas para impedir conexões de clientes, deseja bloquear a porta, não pare o processo.

Michael Shimmins
fonte
@ Michael Shimmins ... hmm parece interessante, pois podemos bloquear a porta no lado do servidor para que o cliente não envie nenhuma mensagem.
Bem, o cliente pode enviar mensagens de todos eles querem que acabamos de fechar a porta para que eles não podem entrar.
1

Mais uma questão: em algum momento o kernel possui portas próprias. Eu sei que o roteamento NAT mantém algumas portas abertas para uso do NAT. Você não pode matar um processo para isso, este é um kernel e é necessária uma reconfiguração e uma reinicialização.

Rich Homolka
fonte
1

Se você deseja que sua porta seja lançada mais cedo, defina o seguinte valor:

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

para configurá-lo de 60 segundos (padrão) para 1 segundo

Daniel
fonte
1

Você pode usar o comando killcx, fechando uma conexão sem que nenhum processo seja morto.

  • sintaxe:
killcx [dest_ip:dest_port] {interface}

  dest_ip              : remote IP
  dest_port            : remote port
  interface (optional) : network interface (eth0, lo etc).
  • exemplo:
killcx 120.121.122.123:1234
killcx 120.121.122.123:1234 eth0
shuaiming
fonte
//, a maioria das máquinas Linux possui killcx? Nenhum dos que eu tentei tem esse comando killcx disponível sem instalar pacotes indisponíveis para eles com sua configuração de repositório atual.
Nathan Basanese
não, você pode encontrar a ferramenta aqui: killcx.sourceforge.net
shuaiming 15/01/16
//, eu sei que posso encontrar a ferramenta, é apenas uma tarefa instalá-la em milhares de servidores.
Nathan Basanese
Use Puppet @NathanBasanese :)
SHOUBHIK BOSE
1

Estou ciente de que esta resposta não responde à pergunta propriamente dita, mas estritamente a leitura pode ser uma informação relevante:

O comportamento padrão de vincular um soquete a uma porta (e endereço) é que, quando o soquete é fechado por um encerramento abrupto do processo, o soquete permanece no TIME_WAIT por um tempo. Isso significa que você não pode se reconectar imediatamente a este endereço / porta. Se você estiver desenvolvendo o próprio sistema por meio da interface de soquete BSD padrão, poderá (pelo menos até certo ponto) controlar esse comportamento com a opção de soquete SO_REUSEADDR. Basicamente, isso permitirá que você ligue novamente ao mesmo endereço / porta se o soquete estiver no status TIME_WAIT. Ainda um soquete por porta!

No entanto, essas informações devem ser usadas apenas como ajuda ao desenvolvimento, pois há uma razão para que TIME_WAIT exista em primeiro lugar, já explicado nas outras respostas.

Tommi Tuura
fonte
// , Direito. Obviamente, matar processos não é a melhor maneira de liberar portas. Percebi que, quando eu mato o processo do Vagrant, se ele travar, não consigo mais vagar por um tempo. Aposto que essa coisa da TIME_WAIT tem algo a ver com isso.
Nathan Basanese
0

Se você não deseja tráfego no soquete, mas deseja manter vivo o processo: tcpkill .

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

Inicia um daemon sniffing que intercepta e destrói todo o tráfego nessa porta. Muito útil para testar seus aplicativos quanto a divisões de rede.

RickyA
fonte
0

Você pode fechar um soquete de escuta usando ss :

sudo ss --kill state listening src :1234

Onde 1234 é o seu número da porta.

ss faz parte do pacote iproute2, portanto há uma mudança forte que já está instalada em um Linux moderno.

Aprendi sobre isso com uma resposta a uma pergunta relacionada .

Tom Anderson
fonte