Secara manual menutup port dari commandline

112

Saya ingin menutup port terbuka yang berada dalam mode mendengarkan antara aplikasi klien dan server saya.

Apakah ada opsi baris perintah manual di Linux untuk menutup port?

CATATAN: Saya jadi tahu bahwa "hanya aplikasi yang memiliki soket yang terhubung yang harus menutupnya, yang akan terjadi ketika aplikasi berakhir."

Saya tidak mengerti mengapa itu hanya mungkin dilakukan oleh aplikasi yang membukanya ... Tapi saya masih ingin tahu apakah ada cara lain untuk melakukannya.

Glorfindel
sumber
5
Tidak, port yang terbuka adalah bagian dari proses yang membukanya, tidak ada kontrol yang mungkin dari luar. Yang merupakan hal yang baik, atau semua aplikasi harus mengantisipasi port terbuka mereka (dan file) yang berantakan. Namun, Anda dapat memblokir lalu lintas ke port dengan firewall (iptables), tetapi itu tidak akan menutup dan menyerahkan port untuk penggunaan lain.
Jürgen Strobel
10
Banyak responden yang tidak mengerti maksud pertanyaan ini. Tidak masuk akal untuk menyatakan bahwa hanya aplikasi yang memiliki port yang dapat memutuskannya. Saya dapat mencabutnya dengan berjalan ke kotak dan menarik kabel ethernet keluar dari soket, atau dengan membunuh aplikasi di ujung koneksi yang lain! Aplikasi harus ditulis untuk menangani hal ini. Jadi --- bagaimana Anda menguji untuk memastikan aplikasi ditulis dengan benar tanpa memerlukan intervensi fisik dan / atau kontrol komputer lain?
Dale Wilson
"... tidak ada kontrol yang mungkin dari luar." Itu komentar penting, yang menuntun saya ke pertanyaan berikutnya, bagaimana saya bisa menjadi bagian dari proses dari luar? GDB.
Dankó Dávid
@ JürgenStrobel Memang ada kontrol yang mungkin dari luar - baik tcpkill dan ss dapat melakukan apa yang diminta. Karena port yang terbuka tidak benar-benar milik proses; mereka adalah sumber daya kernel, dengan beberapa hak yang diberikan untuk suatu proses, tetapi masih ada hanya dengan kesenangan kernel.
Tom Anderson
@ tom-anderson DaleW: tcpkill adalah alat firewall, dan saya menyebutkan opsi ini. Anda dapat mencegah lalu lintas ke port, yang berbeda dari menutup port (soket).
Jürgen Strobel

Jawaban:

134

Saya memiliki masalah yang sama, prosesnya harus tetap hidup tetapi soket harus ditutup. Menutup soket dalam proses yang berjalan bukan tidak mungkin tetapi sulit:

  1. cari proses:

    netstat -np
    

    Anda mendapatkan source/destination ip:port portstate pid/processnamepeta

  2. cari deskriptor file soket dalam proses

    lsof -np $pid
    

    Anda mendapatkan daftar: nama proses, pid, pengguna, fileDescriptor, ... string koneksi.

    Temukan nomor fileDescriptor yang cocok untuk koneksi. Ini akan menjadi sesuatu seperti "97u" yang berarti "97".

  3. Sekarang hubungkan proses:

    gdb -p $pid
    
  4. Sekarang tutup soket:

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

    contoh:

    call close(97)
    

    Kemudian lepaskan gdb:

    quit
    

    Dan soket ditutup.

Dankó Dávid
sumber
1
sudo lsof -np $pidmemberi saya sekitar 200 baris dan saya bingung tentang bagaimana menemukan FD yang diinginkan. Dalam proses kasus saya adalah tab Chrome dan saya mencoba menutup soket web yang terbuka ...
SET
2
Sederet biasanya terlihat seperti: firefox 14.812 szupervigyor 97u IPv4 32.814.564 0T0 TCP 192.168.2.4:40385->173.194.39.65:https (ESTABLISHED) sebagai: process_name pid pengguna fd [opened_for] protokol perangkat inode protocol_data_toString
Danko Dávid
2
* Sebuah baris biasanya terlihat seperti: firefox 14812 szupervigyor 97u IPv4 32814564 0t0 TCP 192.168.2.4:40385->173.194.39.65:https (ESTABLISHED) sebagai: process_name pid pengguna fd [opens_for] protokol perangkat inode protocol_data_tahu tahu bahwa Anda perlu remote. alamat dan temukan pada col terakhir. Dalam contoh saya, 97 adalah FileDescriptor. Pencarian sulit jika Anda membuka banyak koneksi ke host target.
Dankó Dávid
7
ini adalah solusi cemerlang
marcorossi
8
Jika Anda ingin mensimulasikan soket ditutup pada akhir jarak jauh (misalnya peer keluar) itu lebih baik menggunakan shutdown: call shutdown($fileDescriptor, 0).
ecatmur
75

Anda agak menanyakan pertanyaan yang salah di sini. Sangat tidak mungkin untuk hanya "menutup port" dari luar aplikasi yang membuka soket mendengarkannya. Satu-satunya cara untuk melakukan ini adalah sepenuhnya membunuh proses yang memiliki port. Kemudian, dalam sekitar satu atau dua menit, port akan tersedia lagi untuk digunakan. Inilah yang sedang terjadi (jika Anda tidak peduli, lewati sampai akhir di mana saya menunjukkan kepada Anda cara membunuh proses yang memiliki port tertentu):

Port adalah sumber daya yang dialokasikan oleh OS untuk berbagai proses. Ini mirip dengan meminta OS untuk penunjuk file. Namun, tidak seperti file pointer, hanya SATU proses pada suatu waktu yang dapat memiliki port. Melalui antarmuka soket BSD, proses dapat membuat permintaan untuk mendengarkan pada port, yang kemudian diberikan oleh OS. OS juga akan memastikan tidak ada proses lain yang mendapatkan port yang sama. Pada titik mana pun, proses dapat melepaskan port dengan menutup soket. OS kemudian akan mengklaim kembali port tersebut. Atau, jika proses berakhir tanpa melepaskan port, OS pada akhirnya akan mengklaim kembali port (meskipun itu tidak akan terjadi segera: itu akan memakan waktu beberapa menit).

Sekarang, apa yang ingin Anda lakukan (cukup tutup port dari baris perintah), tidak mungkin karena dua alasan. Pertama, jika memungkinkan, itu berarti satu proses bisa mencuri sumber daya proses lain (pelabuhan). Ini akan menjadi kebijakan yang buruk, kecuali terbatas pada proses istimewa. Alasan kedua adalah tidak jelas apa yang akan terjadi pada proses yang dimiliki pelabuhan jika kita membiarkannya terus berjalan. Kode proses ditulis dengan asumsi bahwa ia memiliki sumber daya ini. Jika kita hanya mengambilnya, itu akan berakhir dengan sendirinya, jadi OS jangan biarkan Anda melakukan ini, bahkan jika Anda adalah proses yang istimewa. Sebaliknya, Anda harus membunuh mereka.

Bagaimanapun, berikut ini cara membunuh proses yang memiliki port tertentu:

sudo netstat -ap | grep :<port_number>

Itu akan menampilkan garis yang sesuai dengan port holding proses, misalnya:

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

Dalam hal ini, procHoldingPort adalah nama proses yang membuka port, 4683 adalah pid, dan 8000 (perhatikan bahwa itu adalah TCP) adalah nomor port yang dipegangnya.

Kemudian, lihat di kolom terakhir, Anda akan melihat /. Kemudian jalankan ini:

kill  <pid>

Jika itu tidak berhasil (Anda dapat memeriksa dengan menjalankan kembali perintah netstat). Melakukan hal ini:

kill -9 <pid>

Secara umum, lebih baik untuk menghindari pengiriman SIGKILL jika Anda bisa. Inilah sebabnya saya memberitahu Anda untuk mencoba killsebelumnya kill -9. Hanya menggunakan killmengirimkan SIGTERM yang lebih lembut.

Seperti yang saya katakan, port masih perlu beberapa menit untuk membuka kembali jika Anda melakukan ini. Saya tidak tahu cara mempercepat ini. Jika orang lain melakukannya, saya ingin mendengarnya.

Guy Avraham
sumber
@smehmood - Terima kasih atas penjelasan terperincinya .. Sebuah keraguan kecil .. Bagaimana kernel mendapatkan kembali port terbuka dengan proses yang mati mendadak ?? .. solusi yang Anda berikan tampaknya akan membunuh proses memegang port ...
3
@codingfreak Kernel tahu prosesnya hilang. Ia tahu itu bisa merebut kembali port. Sebenarnya ada aturan tentang waktu penutupan port, untuk memastikan tidak ada paket liar yang mengambang di internet. Bagaimana ia tahu ia memiliki sumber daya ini? itulah yang dilakukan kernel, melacak hal-hal.
Rich Homolka
Sampai seseorang memposting sesuatu yang masuk akal seperti yang unix.tools.port.close(<my port number>)akan saya gunakan init 6.
Snowcrash
Ini adalah jawaban yang bagus untuk pertanyaan yang berbeda. Pertanyaan ini adalah tentang melampirkan debugger dan mengubah program yang sedang berjalan yang menyebabkan program memanggil fungsi pada deskriptor file.
Arthur Ulfeldt
19

Fuser juga bisa digunakan

fuser -k -n *protocol portno*

Protokol di sini adalah tcp / udp dan portno adalah nomor yang ingin Anda tutup. Misalnya

fuser -k -n tcp 37

Info lebih lanjut di halaman manual fuser

RedBaron
sumber
Hanya membunuh proses kepemilikan tidak bekerja untuk saya, tetapi fuser melakukannya. Terima kasih!
webwurst
Saya mendapat hasil yang beragam dengan itu, bahkan setelah menggunakan fuser, saya mendapat "soket sudah digunakan" ketika mencoba untuk menggunakan kembali port dari aplikasi yang terbunuh bahkan dengan melakukan root. Di sisi lain, waktu untuk membebaskan soket sepertinya lebih pendek dari sebelumnya, jadi terima kasih.
Jan Vlcinsky
@ JanVlcinsky Mungkin ada proses "wali" yang memulai kembali proses yang terbunuh beberapa saat setelah fuserdijalankan?
RedBaron
@RedBaron: menurut komentar superuser.com/a/415236/153413 masalah saya berasal dari aplikasi yang ditulis dengan buruk, yang tidak membersihkan / menutup soket di bawah penghentian. Jadi fusermenemukan proses menggunakan port dan membunuhnya, tetapi tidak menyelesaikan fakta, bahwa soket tidak ditutup. 60 detik dan kernel melakukannya untuk saya.
Jan Vlcinsky
6

Anda dapat menggunakan iptables sebagai alternatif:

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

Ini pada dasarnya mencapai apa yang Anda inginkan. Ini akan menjatuhkan semua lalu lintas TCP ke port 80.

supercheetah
sumber
4
Tidak, ini akan membuat soket terbuka sampai semua waktu habis menutupnya. (Ini akan menyembunyikan semua lalu lintas dari proses kepemilikan yang kemudian tidak memiliki cara untuk mengetahui bahwa itu harus menutupnya.) Anda dapat menggunakan -j REJECTuntuk mengembalikan flag reset TCP, yang kemudian akan melihat proses kepemilikan saya (tetapi hanya ketika pihak lain mencoba untuk mengirim sesuatu).
Marki555
3
netstat -anp | grep 80

Seharusnya memberi tahu Anda, jika Anda menjalankan apache, "httpd" (ini hanya contoh, gunakan port yang digunakan aplikasi Anda alih-alih 80)

pkill -9 httpd 

atau

killall -9 httpd
Ben
sumber
4
coba pembunuhan normal sebelum beralih ke -9
Thilo
@omfgroflmao - Tapi itu akan membunuh proses yang telah membuka port ??
@codingfreak Proses yang menahan port, ya itu akan membunuhnya.
2

Anda mungkin bisa mengetahui proses apa yang membuka soket yang terkait dengan port, dan mematikan proses itu.

Tapi, Anda harus menyadari bahwa kecuali proses itu memiliki penangan yang mende-inisialisasi semua hal yang digunakannya (buka file, soket, garpu, barang-barang yang dapat berlama-lama kecuali ditutup dengan benar saat penghentian) maka Anda harus menciptakan itu seret pada kinerja sistem. Plus, soket akan tetap terbuka sampai kernel menyadari bahwa prosesnya telah dimatikan. Itu biasanya hanya membutuhkan waktu sekitar satu menit.

Saya kira pertanyaan yang lebih baik adalah: Port apa (milik proses apa) yang ingin Anda hentikan?

Jika Anda mencoba untuk mengakhiri backdoor atau virus yang Anda temukan, maka Anda setidaknya harus mempelajari data apa yang bolak-balik sebelum Anda menghentikannya. (wireshark baik untuk ini) (Dan nama yang dapat dieksekusi proses 'sehingga Anda dapat menghapusnya dan mencegahnya kembali pada reboot) atau, jika itu adalah sesuatu yang Anda instal (seperti HTTPD atau FTPD atau sesuatu) maka Anda seharusnya sudah memiliki akses ke proses itu sendiri.

Biasanya ia akan memiliki program kontrol (HTTPD stop | start atau sesuatu). Atau, jika itu masalah sistem, Anda mungkin tidak boleh mengacaukannya. Ngomong-ngomong, saya pikir karena semua orang memberi Anda sudut "bagaimana", saya harus memberi Anda peringatan.

jackenheimer
sumber
Komentar yang sangat bagus Saya punya satu program, yang di bawah terminasi tidak menutup soket apa yang menghasilkan perilaku yang dijelaskan - soket tidak dapat digunakan selama sekitar 60 detik. Ketika saya berhenti dan memulai proses itu, mengeluh selama sekitar satu menit, bahwa alamat dan port sudah digunakan. Solusi terbaik adalah memperbaiki proses berperilaku buruk untuk menutup dengan benar, tetapi kadang-kadang ini bukan pilihan. Apakah ada cara untuk meminta kernel memeriksa soket yang diblokir lebih cepat daripada dalam 60 detik?
Jan Vlcinsky
2

Saya pertama kali mencari proses mongo dan simpul, kemudian melakukan hal berikut:

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

Setelah diidentifikasi, matikan saja prosesnya dengan perintah kill.

kill -9 10418
kill -9 10490

Terakhir, ketik meteordan harus berfungsi lagi.

abautista
sumber
1

Anda bisa menulis skrip yang memodifikasi iptables dan me-restart-nya. Satu skrip untuk menambahkan aturan yang menjatuhkan semua paket di port, skrip lain untuk menghapus aturan tersebut.

Jawaban lain menunjukkan kepada Anda cara membunuh proses yang terikat pada port - ini mungkin bukan yang Anda inginkan. Jika Anda ingin server tetap berjalan, tetapi untuk mencegah koneksi dari klien maka Anda ingin memblokir port, tidak menghentikan proses.

Michael Shimmins
sumber
@Michael Shimmins ... hmm terdengar menarik karena kita dapat memblokir port di sisi server sehingga klien tidak akan mengirim pesan apa pun.
Nah klien dapat mengirim pesan semua yang mereka inginkan. Kami baru saja menutup pintu sehingga mereka tidak bisa masuk.
1

Satu masalah lagi: kadang-kadang kernel memiliki port sendiri. Saya tahu routing NAT menahan beberapa port terbuka untuk penggunaan NAT. Anda tidak dapat mematikan proses untuk ini, ini adalah kernel, dan diperlukan konfigurasi ulang dan reboot.

Homolka yang kaya
sumber
1

Jika Anda ingin port Anda dirilis lebih cepat, Anda harus menetapkan nilai berikut:

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

untuk mengaturnya dari 60 detik (default) ke 1 detik

Daniel
sumber
1

Anda dapat menggunakan perintah bernama killcx, menutup koneksi tanpa proses apa pun untuk dimatikan.

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

  dest_ip              : remote IP
  dest_port            : remote port
  interface (optional) : network interface (eth0, lo etc).
  • contoh:
killcx 120.121.122.123:1234
killcx 120.121.122.123:1234 eth0
shuaiming
sumber
//, Apakah sebagian besar mesin Linux memiliki killcx? Tidak ada yang saya coba memiliki perintah killcx ini tersedia tanpa menginstal paket yang tidak tersedia bagi mereka dengan konfigurasi repositori mereka saat ini.
Nathan Basanese
tidak, Anda dapat menemukan alat di sini: killcx.sourceforge.net
shuaiming
//, aku tahu aku bisa menemukan alatnya, itu hanya rasa sakit untuk menginstalnya di ribuan server.
Nathan Basanese
Pakai Boneka @NathanBasanese :)
SHOUBHIK BOSE
1

Saya sadar bahwa jawaban ini tidak menjawab pertanyaan itu sendiri, secara tegas, tetapi membacanya mungkin informasi yang relevan:

Perilaku default dari mengikat socket ke port (dan alamat) adalah ketika socket ditutup dengan penghentian proses yang tiba-tiba, socket akan tetap dalam TIME_WAIT untuk sementara waktu. Ini berarti Anda tidak dapat segera mengikat kembali ke alamat / port ini. Jika Anda mengembangkan sistem itu sendiri melalui antarmuka soket BSD standar, Anda dapat (setidaknya sampai batas tertentu) mengendalikan perilaku ini dengan opsi soket SO_REUSEADDR. Ini pada dasarnya akan memungkinkan Anda untuk mengikat ke alamat / port yang sama lagi jika soket dalam status TIME_WAIT. Masih satu soket per port sekalipun!

Namun, informasi ini hanya boleh digunakan sebagai bantuan pembangunan, karena ada alasan untuk TIME_WAIT ada di tempat pertama, sudah dijelaskan dalam jawaban lain.

Tommi Tuura
sumber
// , Baik. Tentu saja, membunuh proses bukanlah cara terbaik untuk membebaskan pelabuhan. Saya perhatikan bahwa ketika saya membunuh proses Gelandangan jika hang, saya tidak bisa gelandangan lagi untuk sementara waktu. Saya yakin TIME_WAIT ini ada hubungannya dengan itu.
Nathan Basanese
0

Jika Anda tidak ingin lalu lintas melalui soket tetapi ingin tetap hidup prosesnya: tcpkill .

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

Akan memulai daemon mengendus yang memotong dan menghancurkan semua lalu lintas di port itu. Sangat berguna untuk menguji aplikasi Anda untuk pemisahan jaringan.

RickyA
sumber
0

Anda dapat menutup soket mendengarkan menggunakan ss :

sudo ss --kill state listening src :1234

Di mana 1234 adalah nomor port Anda.

ss adalah bagian dari paket iproute2, jadi ada perubahan kuat yang sudah diinstal pada Linux modern.

Saya belajar tentang ini dari jawaban untuk pertanyaan terkait .

Tom Anderson
sumber