Bir bağlantı noktasını komut satırından el ile kapatma


112

İstemci ve sunucu uygulamam arasında dinleme modunda olan açık bir portu kapatmak istiyorum.

Bir portu kapatmak için Linux'ta herhangi bir manuel komut satırı seçeneği var mı?

NOT: “Sadece bağlı sokete sahip olan uygulamanın kapanması gerektiğini, uygulama sonlandığında gerçekleşeceğini” öğrendim.

Neden sadece onu açan uygulama ile mümkün olduğunu anlamıyorum ... Ama bunu yapmanın başka bir yolu olup olmadığını hala öğrenmeye hevesliyim.


5
Hayır, açılan limanlar onları açan sürece aittir , dışarıdan kontrol mümkün değildir. Bu iyi bir şey, yoksa tüm uygulamaların açık portlarının (ve dosyalarının) karışmasını beklemek zorunda kalacaklardı. Ancak, güvenlik duvarını (iptables) kullanarak bir bağlantı noktasına gelen trafiği engelleyebilirsiniz, ancak bu kapanmayacak ve bağlantı noktasını diğer kullanımlardan vazgeçmeyeceksiniz.
Jürgen Strobel

10
Bir çok katılımcı bu sorunun noktasını kaçırdı. Yalnızca bağlantı noktasına sahip olan uygulamanın bağlantıyı kesebileceğini beyan etmek saçmadır. Kutuya kadar yürüyerek ve ethernet kablosunu prizden çekerek veya bağlantıyı diğer ucundaki uygulamayı öldürerek çıkarabilirim! Bu konuyu ele almak için başvuru yazılmalıdır. Peki --- uygulamanın, diğer bilgisayarın fiziksel müdahalesine ve / veya kontrolüne gerek kalmadan düzgün bir şekilde yazıldığından emin olmak için nasıl test yapıyorsunuz?
Dale Wilson

“... dışarıdan kontrol mümkün değil.” Bu önemli bir not, bu beni bir sonraki soruya yönlendirdi, dışardan sürecin bir parçası nasıl olabilirim? GDB.
Dankó Dávid

@ JürgenStrobel Gerçekten dışarıdan kontrol mümkün - hem tcpkill hem de ss tam olarak isteneni yapabilir. Çünkü açılan limanlar gerçekten bir sürece ait değil; bunlar bir sürece atanan bazı haklara sahip, ancak yalnızca çekirdeklerin zevkine göre var olan çekirdek kaynaklarıdır.
Tom Anderson

@ tom-anderson DaleW: tcpkill bir güvenlik duvarı aracı ve bu seçeneğe değindim. Bir portu (soket) kapatmaktan farklı bir porttan gelen trafiği önleyebilirsiniz.
Jürgen Strobel

Yanıtlar:


134

Ben de aynı problemi yaşadım, süreç devam etmeli ama priz kapanmalı. Çalışmakta olan bir işlemde bir soketi kapatmak imkansız değil, zor olabilir:

  1. Süreci bulun:

    netstat -np
    

    Bir source/destination ip:port portstate pid/processnameharita almak

  2. Soketin dosya tanımlayıcısını işlem sırasında bulun

    lsof -np $pid
    

    Bir liste alırsınız: işlem adı, pid, kullanıcı, fileDescriptor, ... bir bağlantı dizesi.

    Bağlantının eşleşen fileDescriptor numarasını bulun. "97" anlamına gelen "97u" gibi bir şey olacak.

  3. Şimdi süreci bağlayın:

    gdb -p $pid
    
  4. Şimdi soketi kapatın:

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

    örnek:

    call close(97)
    

    Sonra gdb'yi ayırın:

    quit
    

    Ve soket kapalı.


1
sudo lsof -np $pidbana yaklaşık 200 satır verir ve istenen FD'nin nasıl bulunacağı konusunda kafam karıştı. Benim durumumda bir Chrome sekmesi ve açılan web soketlerini kapatmaya çalışıyorum ...
SET

2
Bir satır tipik gibi görünüyor: IPv4 97u ateş 14812 szupervigyor 32.814.564 0T0 TCP 192.168.2.4:40385->173.194.39.65:https (KURULMUŞ) olarak: Process_Name PID kullanıcı [opened_for] protokol cihazı düğüm protocol_data_toString fd
Dankó Dávid

2
* Bir satır genellikle şöyle görünür: firefox 14812 szupervigyor 97u IPv4 32814564 0t0 TCP 192.168.2.4:40385->173.194.39.65:https (ESTABLISHED) olarak: işlem_adı pid kullanıcısı fd [Açılan_için] protokol_devamı_tr_dev_tr_dnyay adresleyin ve son sütunda bulun. Benim örneğimde 97, FileDescriptor. Hedef ana bilgisayara birden çok bağlantı açtıysanız arama yapmak zordur.
Dankó Dávid

7
bu harika bir çözüm
marcorossi

8
Eğer soket simüle etmek istiyorsanız (örneğin akran çıkan) kullanmak daha iyidir uzaktan sonuna kadar kapatılıyor shutdown: call shutdown($fileDescriptor, 0).
ecatmur

75

Burada yanlış soruyu soruyorsun. Üzerini dinleyen soketi açan uygulamanın dışından bir portu kapatmak gerçekten mümkün değil. Bunu yapmanın tek yolu limana sahip olan süreci tamamen öldürmektir. Ardından, yaklaşık bir veya iki dakika içinde, bağlantı noktası tekrar kullanım için uygun hale gelecektir. İşte olanlar: (umursamıyorsanız, size belirli bir limana sahip olan süreci nasıl öldüreceğinizi gösterdiğim noktaya atlayın):

Limanlar, işletim sistemi tarafından farklı işlemlere tahsis edilen kaynaklardır. Bu, işletim sisteminden bir dosya işaretçisini istemeye benzer. Ancak, dosya işaretçilerinden farklı olarak, bir seferde yalnızca bir işlem bir bağlantı noktasına sahip olabilir. BSD soket arayüzü aracılığıyla, işlemler OS'nin daha sonra sağlayacağı bir porttan dinleme isteği yapabilir. İşletim sistemi aynı zamanda başka hiçbir işlemin aynı bağlantı noktasını almadığından emin olacaktır. Herhangi bir noktada, işlem soketi kapatarak bağlantı noktasını serbest bırakabilir. İşletim sistemi daha sonra bağlantı noktasını geri alacaktır. Alternatif olarak, işlem bağlantı noktasını serbest bırakmadan sona ererse, işletim sistemi sonunda bağlantı noktasını geri alacaktır (hemen gerçekleşmeyecek olsa da: birkaç dakika sürer).

Şimdi, ne yapmak istediğinizi (sadece bağlantı noktasını komut satırından kapatın), iki nedenden dolayı mümkün değildir. Birincisi, mümkün olsaydı, bir sürecin basitçe başka bir sürecin kaynağını (liman) çalması anlamına gelirdi. Ayrıcalıklı süreçlerle sınırlı olmadığı sürece, bu kötü bir politika olacaktır. İkinci sebep ise, devam etmesine izin verirsek, limanın sahip olduğu sürece ne olacağı belli değil. İşlemin kodu, bu kaynağa sahip olduğu varsayılarak yazılır. Basitçe elinden atsaydık, kendi başına çökmesine neden olacaktı, bu yüzden ayrıcalıklı bir süreç olsanız bile işletim sistemi bunu yapmanıza izin vermiyor. Bunun yerine, onları basitçe öldürmek zorundasınız.

Her neyse, işte belirli bir limana sahip olan bir süreci nasıl öldüreceğinizi:

sudo netstat -ap | grep :<port_number>

Bu, işlem tutma portuna karşılık gelen satırı verecektir, örneğin:

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

Bu durumda, procHoldingPort , bağlantı noktasını açan işlemin adı, 4683 bunun ücreti ve 8000 (TCP olduğunu unutmayın), sahip olduğu bağlantı noktası numarasıdır.

Sonra son sütuna bakın, / göreceksiniz. Ardından şunu yürütün:

kill  <pid>

Bu işe yaramazsa (netstat komutunu yeniden çalıştırarak kontrol edebilirsiniz). Bunu yap:

kill -9 <pid>

Genel olarak, eğer yapabiliyorsanız SIGKILL göndermekten kaçınmak daha iyidir. Bu yüzden size daha killönce denemenizi söyledim kill -9. Sadece kullanarak killnazik SIGTERM gönderir.

Dediğim gibi, bunu yaparsanız portun yeniden açılması birkaç dakika sürecektir. Bunu hızlandırmanın bir yolunu bilmiyorum. Başka biri yaparsa, duymayı çok isterim.


@smehmood - Ayrıntılı açıklama için teşekkürler .. Küçük bir şüphe .. Çekirdek, aniden öldürülen bir işlemle açık bir limanı nasıl ele geçirir? ..

3
@codingfreak Çekirdek işlemin gittiğini biliyor. Limanı geri alabileceğini biliyor. Ağ üzerinde yüzen herhangi bir başıboş paket bulunmadığından emin olmak için bağlantı noktasını kapatma zamanlamasıyla ilgili kurallar vardır. Bu kaynaklara sahip olduğunu nereden biliyor? Çekirdeğin yaptığı şey budur.
Rich Homolka

Biri unix.tools.port.close(<my port number>)benim kullanacağım gibi mantıklı bir şey yazana kadar init 6.
Snowcrash

Bu, farklı bir soruya mükemmel bir cevap. Bu soru, bir hata ayıklayıcı eklemek ve o programın bir dosya tanıtıcısında bir işlevi çağırmasını sağlamak için çalışan bir programı değiştirmekle ilgilidir.
Arthur Ulfeldt

19

Isıtıcı da kullanılabilir

fuser -k -n *protocol portno*

Burada protokol tcp / udp ve portno kapatmak istediğiniz sayıdır. Örneğin

fuser -k -n tcp 37

Isıtıcı adam sayfasında daha fazla bilgi


Sadece sahip olma sürecini öldürmek benim için işe yaramadı ama kaynaştırıcı yaptı. Teşekkür!
webwurst,

Kaynaştırıcı kullandıktan sonra bile, portu öldürülmüş uygulamadan tekrar kullanmaya çalıştığımda "root zaten kullanmaya çalıştığımda" zaten kullanımda olan soketi kullandım. Öte yandan, soketi serbest bırakmak için zaman daha kısa gibi görünüyordu, yine de teşekkürler.
Jan Vlcinsky

@JanVlcinsky Belki fuserçalıştırıldıktan sonra öldürülen işlemi tekrar başlatan bir "koruyucu" süreç var ?
RedBaron

@RedBaron: superuser.com/a/415236/153413 yorumuna göre sorunum, sonlandırılan soketi temizlemeyen / kapatmayan kötü yazılmış bir uygulamadan kaynaklanıyor. Böylece fuserportu kullanarak işlemi bulur ve onu öldürür, ancak soketin kapalı olmadığı gerçeğini çözmez. 60 saniye ve çekirdek benim için yapar.
Jan Vlcinsky,

6

Alternatif olarak iptables kullanabilirsiniz:

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

Temelde istediğinizi gerçekleştirir. Bu, tüm TCP trafiğini 80 numaralı bağlantı noktasına bırakacaktır.


4
Hayır, bu tüm zaman aşımları kapanana kadar soketi açık tutacaktır. (Trafiği tüm trafiği gizleme sürecinden gizleyecektir, bu da kapanması gerektiğini bilmesi için hiçbir yolu yoktur.) -j REJECTTCP sıfırlama işaretini döndürmek için kullanabilirsiniz . bir şey göndermek için).
Marki555

3
netstat -anp | grep 80

Apache kullanıyorsanız, "httpd" (Bu sadece bir örnektir, uygulamanızın 80 yerine kullandığı bağlantı noktasını kullanın).

pkill -9 httpd 

veya

killall -9 httpd

4
-9'a gitmeden önce normal bir öldürmeyi dene
Thilo

@omfgroflmao - Ama limanı açan süreci öldürecek?

@codingfreak Limanı tutan işlem, evet onu öldürür.

2

Muhtemelen portun ilişkili olduğu soketi hangi işlemin açtığını öğrenebilir ve bu işlemi öldürebilirsiniz.

Ancak, bu işlemin kullandığı tüm şeyleri (açık dosyalar, soketler, çatallar, fesihlerde düzgün bir şekilde kapatılmadıkça oyalanabilecek olan şeyleri) baştan başlatan bir işleyiciye sahip olmadığı sürece, o zaman yaratmış olacağınızı anlamalısınız. sistem performansını sürükleyin. Ayrıca, çekirdek, sürecin öldüğünü anlayana kadar yuva açık kalacaktır. Bu genellikle sadece bir dakika sürer.

Sanırım daha iyi bir soru olacaktır: Hangi limanı (hangi sürece ait) durdurmak istiyorsun?

Bulduğunuz bir arka kapıya veya virüse bir son vermeye çalışıyorsanız, en azından sonlandırmadan önce hangi verilerin ileri geri gittiğini öğrenmelisiniz. (wireshark bunun için iyidir) (Ve işlemin çalıştırılabilir adı böylece onu silebilir ve yeniden başlatılmasını engelleyebilirsiniz) ya da kurduğunuz bir şey (HTTPD veya FTPD ya da başka bir şey gibi) varsa, zaten erişebilmeniz gerekir. sürecin kendisi.

Genellikle bir kontrol programına sahip olacaktır (HTTPD stop | start veya başka birşey). Veya, eğer bir sistem olayıysa, muhtemelen onunla uğraşmamalısınız. Her neyse, herkesin size "nasıl yapılır" açısını verdiğinden, size uyarıları vermem gerektiğini düşündüm.


Çok iyi yorum. Sonlandırılmış durumda soketi kapatıp, açıklanan davranışla sonuçlanan bir program var - soket yaklaşık 60 saniye boyunca kullanılamaz. Durduğumda ve bu süreci başlattığımda, adres ve limanın zaten kullanımda olduğundan bir dakika kadar şikayet ediyor. En iyi çözüm, düzgün kapanması için kötü davranış gösteren davranışı düzeltmektir, ancak bazen bu bir seçenek değildir. Çekirdeğin engellenmiş soketini 60 saniyeden daha kısa bir sürede kontrol etmesini istemek için bir yol var mı?
Jan Vlcinsky,

2

Önce mongo ve node işlemlerini aradım, sonra şunları yaptım:

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

Belirlendikten sonra, sadece kill komutuyla süreçleri öldürün.

kill -9 10418
kill -9 10490

Son olarak, yazın meteorve tekrar çalışıyor olması gerekir.


1

Iptables'ı değiştiren ve yeniden başlatan bir script yazabilirsiniz. Bir kural eklemek için bir komut dosyası, bağlantı noktasında tüm paketleri bırakarak, söz konusu kuralı kaldırmak için başka bir komut dosyası.

Diğer cevaplar, limana bağlı süreci nasıl öldüreceğinizi gösterdi - istediğiniz şey olmayabilir. Sunucunun çalışmaya devam etmesini istiyorsanız, ancak istemcilerden gelen bağlantıları engellemek için bağlantı noktasını engellemek istiyorsanız işlemi durdurmazsınız.


@Michael Shimmins ... istemci tarafında herhangi bir mesaj göndermemesi için portu sunucu tarafında engelleyebildiğimiz için ilginç bir ses çıkarır.

Müşteri kapıyı kapattıktan sonra istediklerimize mesaj gönderebilir, böylece içeri

1

Bir sorun daha: bazen çekirdeğin kendileri limanlara sahip. NAT yönlendirmesinin NAT kullanımı için bazı portları açık tuttuğunu biliyorum. Bunun için bir işlemi öldüremezsiniz, bu bir çekirdektir ve bir yeniden yapılandırma ve yeniden başlatma gereklidir.


1

Bağlantı noktanızın daha önce serbest bırakılmasını istiyorsanız, aşağıdaki değeri ayarlamanız gerekir:

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

60 saniyeden (varsayılan) 1 saniyeye ayarlamak için


1

Killcx adlı komutu kullanarak öldürülecek herhangi bir işlem yapmadan bir bağlantıyı kapatabilirsiniz.

  • sözdizimi:
killcx [dest_ip:dest_port] {interface}

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

//, Linux makinelerinin çoğunda killcx var mı? Denediklerimden hiçbiri bu killcx komutunu, mevcut depo konfigürasyonları ile kullanılamayan paketleri kurmadan kullanabiliyor.
Nathan Basanese,

Hayır, aracı burada bulabilirsiniz: killcx.sourceforge.net
15:16 'da

//, aracı bulabileceğimi biliyorum, bu binlerce sunucuya kurmak sadece bir acı.
Nathan Basanese,

Kukla @NathanBasanese :) Kullanın
SHOUBHIK BOSE

1

Bu cevabın, soruyu kesin olarak cevaplamadığını, kesinlikle konuşmayacağının farkındayım, ancak bunu okumak bununla ilgili bilgiler olabilir:

Bir soketi bir bağlantı noktasına (ve adrese) bağlamanın varsayılan davranışı, soketin bir anda sonlandırılmasıyla kapatıldığı zaman soketin bir süre TIME_WAIT'te kalacağıdır. Bu, hemen bu adrese / bağlantı noktasına yeniden bağlanamayacağınız anlamına gelir. Sistemin kendisini standart BSD soket arayüzü ile geliştiriyorsanız, bu davranışa SO_REUSEADDR soket seçeneğiyle (en azından bir dereceye kadar) kontrol edebilirsiniz. Bu, temelde, soket TIME_WAIT durumundaysa, aynı adres / bağlantı noktasına tekrar bağlanmanıza izin verecektir. Yine de port başına hala bir soket!

Bununla birlikte, bu bilgi yalnızca geliştirme yardımı olarak kullanılmalıdır, çünkü TIME_WAIT'in ilk etapta var olmasının bir nedeni daha önce diğer cevaplarda açıklanmıştır.


// , Sağ. Tabii ki, öldürme işlemleri limanları boşaltmanın en iyi yolu değil. Vagrant sürecini kapattığımda, takılırsa bir süre daha sersemlemeyeceğimi fark ettim. Bahse girerim bu TIME_WAIT olayının bununla bir ilgisi var.
Nathan Basanese,

0

Soket üzerinden trafik almak istemiyor, ancak işlemi canlı tutmak istiyorsanız: tcpkill .

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

Bu limandaki tüm trafiği engelleyen ve çöpe atan bir koklama cini başlatacak. Ağ bölmelerindeki uygulamalarınızı test etmek için çok kullanışlıdır.


0

Ss kullanarak bir dinleme soketini kapatabilirsiniz :

sudo ss --kill state listening src :1234

Liman numaranız 1234.

ss, iproute2 paketinin bir parçası olduğundan, modern bir Linux'ta yüklü olan güçlü bir değişiklik var.

Bununla ilgili bir sorunun cevabından bunu öğrendim .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.