Ręczne zamykanie portu z linii poleceń


97

Chcę zamknąć otwarty port, który jest w trybie nasłuchu między aplikacją klienta a serwerem.

Czy w Linuksie istnieje jakaś ręczna opcja wiersza polecenia, aby zamknąć port?

UWAGA: Dowiedziałem się, że „tylko aplikacja, która jest właścicielem podłączonego gniazda, powinna je zamknąć, co nastąpi po zakończeniu aplikacji”.

Nie rozumiem, dlaczego jest to możliwe tylko dzięki aplikacji, która ją otwiera ... Ale wciąż chcę wiedzieć, czy jest jakikolwiek inny sposób, aby to zrobić.


5
Nie, otwarte porty należeć do procesu, który je otworzył, nie ma możliwości kontroli z zewnątrz. Co jest dobrą rzeczą, lub wszystkie aplikacje będą musiały przewidzieć, że ich otwarte porty (i pliki) zostały zmienione. Możesz jednak zablokować ruch do portu przez zaporę ogniową (iptables), ale nie zamknie się i nie odda portu do innego użytku.
Jürgen Strobel

9
Wielu respondentów nie trafiło w sedno tego pytania. Bezsensowne jest deklarowanie, że tylko aplikacja będąca właścicielem portu może go rozłączyć. Mogę go odłączyć, podchodząc do pudełka i wyciągając kabel ethernetowy z gniazda lub zabijając aplikację na drugim końcu połączenia! Aplikacja musi być napisana, aby to obsługiwać. Więc - jak testujesz, aby upewnić się, że aplikacja jest napisana poprawnie bez konieczności fizycznej interwencji i / lub kontroli nad innym komputerem?
Dale Wilson

„... nie ma kontroli z zewnątrz”. To ważna uwaga, która poprowadziła mnie do następnego pytania: jak mogę być częścią procesu z zewnątrz? GDB.
Dankó Dávid

Odpowiedzi:


116

Miałem ten sam problem, proces musi się utrzymać, ale gniazdo musi się zamknąć. Zamknięcie gniazda w uruchomionym procesie nie jest niemożliwe, ale trudne:

  1. zlokalizuj proces:

    netstat -np
    

    Dostaniesz source/destination ip:port portstate pid/processname mapa

  2. zlokalizuj deskryptor pliku gniazda w procesie

    lsof -np $pid
    

    Otrzymasz listę: nazwa procesu, pid, użytkownik, fileDescriptor, ... ciąg połączenia.

    Znajdź odpowiedni numer plikuDescriptor dla połączenia.

    Teraz połącz proces:

    gdb -p $pid
    
  3. Teraz zamknij gniazdo:

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

    Następnie odłącz:

    quit
    

    A gniazdo jest zamknięte.


1
sudo lsof -np $pid daje mi około 200 linii i jestem zdezorientowany, jak znaleźć pożądane FD. W moim przypadku proces to karta Chrome i próbuję zamknąć otwarte witryny internetowe ...
SET

2
Typowy wiersz wygląda następująco: firefox 14812 szupervigyor 97u IPv4 32814564 0t0 TCP 192.168.2.4:40385->173.194.39.65:https (ESTABLISHED) jako: nazwa_procesu pid użytkownik fd [otwarty_dla] protokół urządzenie i-węzeł protokół_data_do_strony
Dankó Dávid

2
* Zazwyczaj wiersz wygląda następująco: firefox 14812 szupervigyor 97u IPv4 32814564 0t0 TCP 192.168.2.4:40385->173.194.39.65:https (ESTABLISHED) jako: nazwa_procesu pid użytkownik fd [otwarty_dla] protokół urządzenie i-węzeł protokół_dane_doStringu adres IP i znajdź na ostatniej kol. W moim przykładzie 97 to FileDescriptor. Wyszukiwanie jest trudne, jeśli otworzyłeś wiele połączeń z hostem docelowym.
Dankó Dávid

7
to genialne rozwiązanie
marcorossi

7
Jeśli chcesz symulować gniazdo zamknięte przez zdalny koniec (np. Wyjście peera), lepiej jest użyć shutdown: call shutdown($fileDescriptor, 0).
ecatmur

75

Tutaj zadajesz złe pytanie. Nie jest możliwe po prostu „zamknąć port” spoza aplikacji, która otworzyła gniazdo nasłuchując na nim. Jedynym sposobem na to jest całkowite zabicie procesu, który jest właścicielem portu. Następnie, za minutę lub dwie, port będzie ponownie dostępny do użytku. Oto, co się dzieje (jeśli nie obchodzi cię to, przejdź do końca, gdzie pokażę ci, jak zabić proces będący właścicielem konkretnego portu):

Porty to zasoby przydzielane przez system operacyjny różnym procesom. Jest to podobne do pytania systemu operacyjnego o wskaźnik pliku. Jednak w przeciwieństwie do wskaźników plików, tylko JEDEN proces na raz może posiadać port. Dzięki interfejsowi gniazda BSD procesy mogą żądać nasłuchu na porcie, który system operacyjny następnie udzieli. System operacyjny upewni się również, że żaden inny proces nie uzyska tego samego portu. W dowolnym momencie proces może zwolnić port, zamykając gniazdo. System operacyjny odzyska port. Alternatywnie, jeśli proces zakończy się bez zwolnienia portu, system operacyjny ostatecznie odzyska port (choć nie nastąpi to natychmiast: zajmie to kilka minut).

Teraz, co chcesz zrobić (po prostu zamknij port z linii poleceń), nie jest możliwe z dwóch powodów. Po pierwsze, gdyby było to możliwe, oznaczałoby to, że jeden proces mógłby po prostu wykraść zasób innego procesu (port). Byłaby to zła polityka, chyba że byłaby ograniczona do procesów uprzywilejowanych. Drugim powodem jest to, że nie jest jasne, co stanie się z procesem, który był właścicielem portu, jeśli pozwolimy mu kontynuować działanie. Kod procesu jest napisany przy założeniu, że jest właścicielem tego zasobu. Gdybyśmy go po prostu usunęli, skończyłoby się to na jego własnym zawieszeniu, więc OS nie pozwala ci tego zrobić, nawet jeśli jesteś uprzywilejowanym procesem. Zamiast tego musisz je po prostu zabić.

W każdym razie, jak zabić proces, który jest właścicielem konkretnego portu:

sudo netstat -ap | grep :<port_number>

Spowoduje to wyświetlenie linii odpowiadającej portowi wstrzymania procesu, na przykład:

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

W tym przypadku, procHoldingPort to nazwa procesu, który otworzył port, 4683 jest jego pid i 8000 (zauważ, że jest to TCP) to numer portu, który przechowuje.

Następnie spójrz na ostatnią kolumnę, zobaczysz /. Następnie wykonaj to:

kill  <pid>

Jeśli to nie zadziała (możesz sprawdzić, uruchamiając ponownie polecenie netstat). Zrób to:

kill -9 <pid>

Ogólnie lepiej jest unikać wysyłania SIGKILL, jeśli możesz. Dlatego mówię ci, żebyś spróbował kill przed kill -9. Po prostu używam kill wysyła łagodniejszego SIGTERM.

Jak już powiedziałem, ponowne otwarcie portu zajmie kilka minut, jeśli to zrobisz. Nie wiem, jak to przyspieszyć. Jeśli ktoś inny, chciałbym to usłyszeć.


@smehmood - Dzięki za szczegółowe wyjaśnienie .. Niewielka wątpliwość .. Jak jądro odzyskuje otwarty port przez nagle zabity proces? .. rozwiązanie, które podałeś wydaje się zabijać proces utrzymywania portu ...

3
@codingfreak Jądro wie, że proces zniknął. Wie, że może odzyskać port. W rzeczywistości istnieją zasady dotyczące czasu zamknięcia portu, aby upewnić się, że w sieci nie ma żadnych zabłąkanych pakietów. Skąd wie, że ma te zasoby? to właśnie robi jądro, śledzi rzeczy.
Rich Homolka

Dopóki ktoś nie opublikuje czegoś sensownego unix.tools.port.close(<my port number>) użyłbym init 6.
Snowcrash

19

Można również użyć utrwalacza

fuser -k -n *protocol portno*

Tutaj protokołem jest tcp / udp, a portno to numer, który chcesz zamknąć. Na przykład.

fuser -k -n tcp 37

Więcej informacji na stronie strona man fuser


Sam proces zabijania nie działał dla mnie, ale działał utrwalacz. Dzięki!
webwurst

Zrobiłem z tym mieszane rezultaty, nawet po użyciu fuser, dostałem "gniazdo już używane" podczas próby ponownego użycia portu z zabitej aplikacji, nawet tak jak root. Z drugiej strony czas uwolnienia gniazda wydawał się krótszy niż wcześniej, więc i tak dziękuję.
Jan Vlcinsky

@JanVlcinsky Być może istnieje proces „strażnika”, który ponownie uruchamia zabity proces chwilę później fuser prowadzony jest?
RedBaron

@RedBaron: według komentarza superuser.com/a/415236/153413 mój problem pochodzi ze źle napisanej aplikacji, która nie czyści / zamyka gniazda w przypadku rozwiązania. Więc fuser znajduje proces używający portu i zabija go, ale nie rozwiązuje faktu, że gniazdo nie jest zamknięte. 60 sekund, a jądro robi to za mnie.
Jan Vlcinsky

5

Możesz alternatywnie użyć iptables:

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

W zasadzie osiąga to, co chcesz. Spowoduje to usunięcie całego ruchu TCP do portu 80.


4
Nie, dzięki temu gniazdo będzie otwarte, dopóki wszystkie limity czasu ich nie zamkną. (To ukryje cały ruch z procesu posiadania, który wtedy nie ma możliwości wiedzieć, że powinien go zamknąć.) Możesz użyć -j REJECT aby zwrócić flagę resetowania TCP, która byłaby wtedy postrzegana jako mój proces posiadania (ale tylko wtedy, gdy druga strona próbuje coś wysłać).
Marki555

3
netstat -anp | grep 80

Powinien ci powiedzieć, jeśli używasz apache, „httpd” (to tylko przykład, użyj portu, którego używa aplikacja zamiast 80)

pkill -9 httpd 

lub

killall -9 httpd

3
spróbuj normalnego zabicia przed ucieczką do -9
Thilo

@omfgroflmao - Ale zabije proces, który otworzył port?

@ codefreak Proces, który trzyma port, tak go zabije.

2

Prawdopodobnie po prostu dowiesz się, jaki proces otworzył gniazdo, w którym znajduje się port związane z i zabij ten proces.

Ale musiałbyś to sobie uświadomić, chyba że ten proces ma procedurę obsługi, która deinicjalizuje wszystkie używane elementy (otwarte pliki, gniazda, widelce, rzeczy, które mogą pozostać, dopóki nie zostaną prawidłowo zamknięte po zakończeniu) wtedy stworzyłbyś ten ciąg na wydajności systemu. Dodatkowo gniazdo pozostanie otwórz aż jądro zda sobie sprawę, że proces został zabity. To zwykle tylko trwa około minuty.

Przypuszczam, że lepszym pytaniem byłoby: Jaki port (należący do jaki proces) chcesz zatrzymać?

Jeśli próbujesz położyć kres backdoorowi lub wirusa, który znalazłeś, powinieneś przynajmniej dowiedzieć się, jakie dane przechodzą tam iz powrotem przed zakończeniem. (wireshark jest na to dobry) (I nazwa pliku wykonywalnego procesu, abyś mógł go usunąć i zapobiec jego ponownemu uruchomieniu) lub, jeśli jest to coś, co zainstalowałeś (np. HTTPD lub FTPD lub coś takiego), powinieneś już mieć dostęp do sam proces.

Zazwyczaj będzie miał program sterujący (HTTPD stop | start lub coś). Lub, jeśli jest to sprawa systemowa, prawdopodobnie nie powinieneś się tym zaśmiecać. W każdym razie pomyślałem, że skoro wszyscy inni dają ci kąt „jak to zrobić”, powinienem dać ci zastrzeżenia.


Bardzo dobry komentarz. Mam jeden program, który po zamknięciu nie zamyka gniazda, co powoduje opisane zachowanie - gniazdo nie nadaje się do użytku przez około 60 sekund. Kiedy zatrzymuję się i rozpoczynam ten proces, narzeka on na około minutę, że adres i port są już używane. Najlepszym rozwiązaniem jest poprawienie źle zachowującego się procesu, aby zamknąć go prawidłowo, ale czasami nie jest to możliwe. Czy istnieje sposób, aby poprosić jądro o sprawdzenie tego zablokowanego gniazda wcześniej niż za 60 sekund?
Jan Vlcinsky

2

Najpierw szukałem procesów mongo i węzłów, a następnie:

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

Po zidentyfikowaniu po prostu zabij procesy za pomocą polecenia kill.

kill -9 10418
kill -9 10490

Na koniec wpisz meteor i powinno działać ponownie.


1

Możesz napisać skrypt, który zmodyfikował iptables i uruchomił je ponownie. Jeden skrypt do dodawania reguły upuszczającej wszystkie pakiety na porcie, kolejny skrypt do usuwania wspomnianej reguły.

Inne odpowiedzi pokazały, jak zabić proces związany z portem - to może nie być to, czego chcesz. Jeśli chcesz, aby serwer działał, ale aby zapobiec połączeniom z klientami, chcesz zablokować port, a nie zatrzymać proces.


@Michael Shimmins ... hmm brzmi interesująco, ponieważ możemy zablokować port po stronie serwera, aby klient nie wysyłał żadnych wiadomości.

Klient może wysyłać wiadomości, których chcą, po prostu zamknęliśmy drzwi, aby nie mogli wejść.

1

Jeszcze jeden problem: kiedyś jądro jest właścicielem portów. Wiem, że routing NAT zawiera niektóre porty otwarte do użycia NAT. Nie można zabić procesu, jest to jądro, wymagana jest rekonfiguracja i ponowne uruchomienie.


1

Jeśli chcesz, aby Twój port został zwolniony wcześniej, musisz ustawić następującą wartość:

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

aby ustawić od 60 sekund (domyślnie) do 1 sekundy


1

Możesz użyć polecenia o nazwie killcx, zamykając połączenie bez żadnego procesu, który ma zostać zabity.

  • składnia:
killcx [dest_ip:dest_port] {interface}

  dest_ip              : remote IP
  dest_port            : remote port
  interface (optional) : network interface (eth0, lo etc).
  • przykład:
killcx 120.121.122.123:1234
killcx 120.121.122.123:1234 eth0

//, Czy większość komputerów z Linuksem ma killcx? Żadna z tych, których próbowałem, nie ma dostępnej komendy killcx bez instalowania pakietów niedostępnych dla nich z ich aktualną konfiguracją repozytorium.
Nathan Basanese

nie, możesz znaleźć narzędzie tutaj: killcx.sourceforge.net
shuaiming

//, wiem, że mogę znaleźć narzędzie, to tylko ból instalowanie go na tysiącach serwerów.
Nathan Basanese

Użyj Puppet @NathanBasanese :)
SHOUBHIK BOSE

1

Zdaję sobie sprawę, że ta odpowiedź nie odpowiada na samo pytanie, ściśle mówiąc, ale przeczytanie tego może być istotną informacją:

Domyślnym sposobem wiązania gniazda z portem (i adresem) jest to, że gdy gniazdo zostanie zamknięte przez nagłe zakończenie procesu, gniazdo pozostanie przez pewien czas w TIME_WAIT. Oznacza to, że nie możesz natychmiast ponownie powiązać tego adresu / portu. Jeśli sam tworzysz system za pomocą standardowego interfejsu gniazda BSD, możesz (przynajmniej w pewnym stopniu) kontrolować to zachowanie za pomocą opcji gniazda SO_REUSEADDR. Pozwoli to w zasadzie ponownie połączyć się z tym samym adresem / portem, jeśli gniazdo ma status TIME_WAIT. Wciąż jedno gniazdo na port!

Jednak ta informacja powinna być wykorzystywana jedynie jako pomoc rozwojowa, ponieważ istnieje powód, dla którego TIME_WAIT istnieje przede wszystkim, już wyjaśniono w innych odpowiedziach.


// , Dobrze. Oczywiście zabijanie procesów nie jest najlepszym sposobem na uwolnienie portów. Zauważyłem, że gdy zabiję proces Vagranta, jeśli się zawiesza, nie mogę się przez chwilę znów włóczyć. Założę się, że to ma coś wspólnego z TIME_WAIT.
Nathan Basanese

0

Jeśli nie chcesz ruchu przez gniazdo, ale chcesz zachować proces: tcpkill .

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

Uruchomi demona wąchania, który przechwytuje i niszczy cały ruch na tym porcie. Bardzo przydatny do testowania aplikacji pod kątem podziałów sieciowych.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.