Questão Fechando manualmente uma porta da linha de comando


Eu quero fechar uma porta aberta que está em modo de escuta entre o meu cliente e aplicativo do servidor.

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

NOTA:  Eu vim a saber que "apenas o aplicativo que possui o soquete conectado deve fechá-lo, o que acontecerá quando o aplicativo for encerrado".

Eu não entendo porque isso só é possível pelo aplicativo que abre ... Mas eu ainda estou ansioso para saber se existe alguma outra maneira de fazer isso.


91


origem


Não, portas abertas pertencer para o processo que os abriu, não há controle possível a partir do exterior. O que é uma coisa boa, ou todos os aplicativos teriam que antecipar suas portas abertas (e arquivos) sendo confundidos. No entanto, você pode bloquear o tráfego para uma porta por meio de firewall (iptables), mas isso não será fechado e abrirá a porta para outro uso. - Jürgen Strobel
Muitos respondedores perderam o ponto de vista dessa questão. É um absurdo declarar que somente o aplicativo que possui a porta pode desconectá-lo. Eu posso desconectá-lo andando 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 ter certeza de que o aplicativo está escrito corretamente, sem a necessidade de intervenção física e / ou controle do outro computador? - Dale Wilson
"... não há controle possível de fora." Essa é uma observação importante, que me guiou para a próxima pergunta: como posso ser parte do processo de fora? GDB. - Dankó Dávid


Respostas:


Eu tive o mesmo problema, o processo deve manter 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ê ganha um source/destination ip:port portstate pid/processname mapa

  2. localize o descritor de arquivo do soquete no processo

    lsof -np $pid
    

    Você obtém uma lista: nome do processo, pid, user, fileDescriptor, ... uma string de conexão.

    Localize o número correspondente de fileDescriptor para a conexão.

    Agora conecte o processo:

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

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

    Em seguida, destaque:

    quit
    

    E o soquete está fechado.


108



sudo lsof -np $pid me dá cerca de 200 linhas e estou confuso sobre como encontrar o FD desejado. No meu caso, o processo é uma guia do Chrome e estou tentando fechar websockets abertos ... - SET
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: nome_do_processo pid usuário fd [aberto_para] protocolo dispositivo inode protocol_data_toString - Dankó Dávid
* 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: nome_do_processo pid usuário fd [aberto_para] protocolo dispositivo inode protocol_data_toString Você precisa conhecer o ip remoto endereço e encontrar na última col. No meu exemplo, o 97 é o FileDescriptor. A pesquisa é difícil se você tiver aberto várias conexões ao host de destino. - Dankó Dávid
esta é uma solução brilhante - marcorossi
Se você quiser simular o socket sendo fechado pelo final remoto (por exemplo, o peer saindo) é melhor usar shutdown: call shutdown($fileDescriptor, 0). - ecatmur


Você está meio que fazendo a pergunta errada aqui. Não é realmente possível simplesmente "fechar uma porta" de fora do aplicativo que abriu o soquete escutando. 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 mostrarei como matar o processo que possui uma porta específica):

Portas são recursos alocados pelo SO para diferentes processos. Isso é semelhante a perguntar ao SO por um ponteiro de arquivo. No entanto, ao contrário dos ponteiros de arquivo, somente UM processo por vez pode possuir uma porta. Através da interface do socket BSD, os processos podem fazer um pedido para escutar em uma porta, que o SO irá então conceder. O sistema operacional também garante que nenhum outro processo receba a mesma porta. A qualquer momento, o processo pode liberar a porta fechando o soquete. O SO irá então recuperar a porta. Como alternativa, se o processo terminar sem liberar a porta, o SO acabará recuperando a porta (embora isso não aconteça imediatamente: levará alguns minutos).

Agora, o que você quer fazer (basta fechar a porta a partir da linha de comando) não é possível por dois motivos. Primeiro, se fosse possível, significaria que um processo poderia simplesmente roubar o recurso de outro processo (a porta). Isso seria uma política ruim, a menos que restritas 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 possui este recurso. Se nós simplesmente o retirássemos, ele acabaria caindo sozinho, então os sistemas operacionais não permitem que você faça isso, mesmo que você seja um processo privilegiado. Em vez disso, você deve simplesmente matá-los.

De qualquer forma, aqui está 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 o porto, 4683 é o seu pid e 8000 (note que é TCP) é o número da porta que contém.

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

kill  <pid>

Se isso não funcionar (você pode verificar executando novamente o comando netstat). Faça isso:

kill -9 <pid>

Em geral, é melhor evitar enviar SIGKILL se puder. É por isso que eu te digo para tentar kill antes kill -9. Apenas usando kill envia o gentil SIGTERM.

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


73



@smehmood - Obrigado pela explicação detalhada. Uma pequena dúvida. Como o kernel reclama uma porta aberta por um processo morto abruptamente? .. a solução fornecida parece estar matando o processo que mantém a porta ...
@codingfreak O kernel sabe que o processo desapareceu. Sabe que pode recuperar a porta. Na verdade, existem regras sobre o tempo de fechamento da porta, para garantir que não haja pacotes perdidos flutuando na rede. Como ele sabe que tem esses recursos? é isso que o kernel faz, acompanha as coisas. - Rich Homolka
Até alguém postar algo sensato como unix.tools.port.close(<my port number>) eu usaria init 6. - Snowcrash


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 em página de homem do fusor


18



Apenas matando o processo de propriedade não funcionou para mim, mas o fusor fez. THX! - webwurst
Eu tenho resultados mistos com ele, mesmo depois de usar o fusor, eu tenho "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 socket parecia ser menor do que antes, então obrigado mesmo assim. - Jan Vlcinsky
@JanVlcinsky Talvez haja um processo de "guardião" que reinicia o processo morto momentos após fuser é executado? - RedBaron
@RedBaron: de acordo com o comentário superuser.com/a/415236/153413 meu problema origina-se em aplicativo mal escrito, que não limpa / fecha o soquete sob terminação. assim fuser localiza o processo usando a porta e mata, mas não resolve o fato de que o soquete não está fechado. 60 segundos e kernel faz isso por mim. - Jan Vlcinsky


Você poderia alternativamente usar o iptables:

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

Basicamente, realiza o que você quer. Isso eliminará todo o tráfego TCP na porta 80.


4



Não, isso manterá o soquete aberto até que todos os tempos limite os fechem. (Ele irá esconder todo o tráfego do processo de propriedade que então não tem meios para saber que deve fechá-lo.) Você pode usar -j REJECT para retornar o sinalizador de redefinição do TCP, que seria, então, visto como meu processo proprietário (mas apenas quando o outro lado tentar enviar algo). - Marki555


netstat -anp | grep 80

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

pkill -9 httpd 

ou

killall -9 httpd

3



tente uma morte normal antes de recorrer a -9 - Thilo
@omfgroflmao - Mas vai matar o processo que abriu o port ??
@codingfreak O processo que está segurando a porta, sim, ela irá matá-lo.


Você provavelmente poderia apenas descobrir o processo que abriu o soquete que a porta é associado e elimine esse processo.

Mas, você teria que perceber que a menos que esse processo tem um manipulador que não inicializa todas as coisas que estava usando (aberto arquivos, soquetes, garfos, coisas que podem permanecer a menos que sejam fechadas corretamente na finalização) então você teria criado esse arrasto no desempenho do sistema. Além disso, o soquete permanecerá aberto até que o kernel perceba que o processo foi morto. Isso geralmente só leva cerca de um minuto.

Eu suponho que a melhor pergunta seria: Que porto (pertencente a que processo) você quer parar?

Se você está tentando colocar um fim em um backdoor ou vírus que você encontrou, então você deve pelo menos aprender quais dados estão indo e voltando antes de terminá-lo. (wireshark é bom para isso) (E o nome executável do processo para que você possa excluí-lo e impedir que ele seja reiniciado) ou, se for algo que você instalou (como HTTPD ou FTPD ou algo assim), você já deve ter acesso a o processo em si.

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


2



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


Primeiro procurei pelos processos mongo e node e 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, apenas mate os processos com o comando kill.

kill -9 10418
kill -9 10490

Por fim, digite meteor e deveria estar funcionando novamente.


2





Você pode escrever um script que modifique o iptables e reinicie-o. Um script para adicionar uma regra descartando todos os pacotes na porta, outro script para remover essa regra.

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


1



@Michael Shimmins ... hmm soa intresting como podemos bloquear a porta no lado do servidor para que o cliente não envie nenhuma mensagem.
Bem, o cliente pode enviar mensagens tudo o que eles querem, nós apenas fechamos a porta para que eles não possam entrar.