Đóng thủ công một cổng từ dòng lệnh


112

Tôi muốn đóng một cổng mở ở chế độ nghe giữa ứng dụng khách và máy chủ của tôi.

Có tùy chọn dòng lệnh thủ công nào trong Linux để đóng cổng không?

LƯU Ý: Tôi đã biết rằng "chỉ ứng dụng sở hữu ổ cắm được kết nối mới đóng nó, điều này sẽ xảy ra khi ứng dụng chấm dứt."

Tôi không hiểu tại sao ứng dụng chỉ mở được ... Nhưng tôi vẫn háo hức muốn biết liệu có cách nào khác để làm điều đó không.


5
Không, các cổng đã mở thuộc về quá trình mở chúng, không thể kiểm soát được từ bên ngoài. Đó là một điều tốt, hoặc tất cả các ứng dụng sẽ phải dự đoán các cổng (và tệp) đang mở của chúng bị rối. Tuy nhiên, bạn có thể chặn lưu lượng truy cập vào một cổng bằng cách tường lửa (iptables), nhưng điều đó sẽ không đóng và từ bỏ cổng để sử dụng khác.
Jürgen Strobel

10
Rất nhiều người trả lời đã bỏ lỡ điểm của câu hỏi này. Thật là vô nghĩa khi tuyên bố rằng chỉ có ứng dụng sở hữu cổng có thể ngắt kết nối nó. Tôi có thể ngắt kết nối nó bằng cách đi đến hộp và rút cáp ethernet ra khỏi ổ cắm hoặc bằng cách tắt ứng dụng ở đầu kia của kết nối! Ứng dụng phải được viết để xử lý việc này. Vậy --- làm thế nào để bạn kiểm tra để chắc chắn rằng ứng dụng được viết đúng mà không cần sự can thiệp vật lý và / hoặc kiểm soát của máy tính khác?
Dale Wilson

"... không có sự kiểm soát nào từ bên ngoài." Đó là một nhận xét quan trọng, đó là hướng dẫn tôi đến câu hỏi tiếp theo, làm thế nào tôi có thể là một phần của quá trình từ bên ngoài? GDB.
Dankó Dávid

@ JürgenStrobel Thực sự có thể kiểm soát từ bên ngoài - cả tcpkill và ss đều có thể làm chính xác những gì được yêu cầu. Bởi vì các cổng mở không thực sự thuộc về một quy trình; chúng là tài nguyên kernel, với một số quyền được gán cho một tiến trình, nhưng vẫn chỉ tồn tại ở niềm vui của kernel.
Tom Anderson

@ tom-anderson DaleW: tcpkill là một công cụ tường lửa và tôi đã đề cập đến tùy chọn này. Bạn có thể ngăn lưu lượng truy cập đến một cổng, khác với việc đóng một cổng (ổ cắm).
Jürgen Strobel

Câu trả lời:


134

Tôi đã có một vấn đề tương tự, quá trình phải tiếp tục sống nhưng ổ cắm phải đóng lại. Đóng một ổ cắm trong một quy trình đang chạy không phải là không thể nhưng khó khăn:

  1. xác định vị trí quá trình:

    netstat -np
    

    Bạn có một source/destination ip:port portstate pid/processnamebản đồ

  2. xác định vị trí mô tả tệp của ổ cắm trong quá trình

    lsof -np $pid
    

    Bạn nhận được một danh sách: tên tiến trình, pid, người dùng, fileDescriptor, ... một chuỗi kết nối.

    Xác định vị trí số fileDescriptor phù hợp cho kết nối. Nó sẽ là một cái gì đó như "97u" có nghĩa là "97".

  3. Bây giờ kết nối quá trình:

    gdb -p $pid
    
  4. Bây giờ hãy đóng ổ cắm:

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

    thí dụ:

    call close(97)
    

    Sau đó tách gdb:

    quit
    

    Và ổ cắm được đóng lại.


1
sudo lsof -np $pidcung cấp cho tôi khoảng 200 dòng và tôi bối rối về cách tìm FD mong muốn. Trong quá trình trường hợp của tôi là một tab Chrome và tôi đang cố gắng để đóng WebSockets mở ...
SET

2
Một hàng thường trông giống như: firefox 14.812 szupervigyor 97u IPv4 32.814.564 0t0 TCP 192.168.2.4:40385->173.194.39.65:https (ESTABLISHED) như: process_name sử dụng pid fd [opened_for] giao thức thiết bị inode protocol_data_toString
Danko Dávid

2
* Một hàng thường trông giống như: firefox 14812 szupervigyor 97u IPv4 32814564 0t0 TCP 192.168.2.4:40385->173.194.39,65:https (ESTABOUNDED) như: process_name pid user fd [opens_for] địa chỉ và tìm trên col cuối cùng. Trong ví dụ của tôi, 97 là FileDescriptor. Tìm kiếm rất khó nếu bạn mở nhiều kết nối đến máy chủ đích.
Dankó Dávid

7
đây là một giải pháp tuyệt vời
marcorossi

8
Nếu bạn muốn mô phỏng ổ cắm bị đóng bởi đầu từ xa (ví dụ: thoát ngang hàng) thì tốt hơn nên sử dụng shutdown: call shutdown($fileDescriptor, 0).
ecatmur

75

Bạn đang hỏi sai câu hỏi ở đây. Thật sự không thể chỉ đơn giản là "đóng một cổng" từ bên ngoài ứng dụng đã mở ổ cắm nghe trên nó. Cách duy nhất để làm điều này là tiêu diệt hoàn toàn quy trình sở hữu cổng. Sau đó, trong khoảng một hoặc hai phút, cổng sẽ có sẵn để sử dụng lại. Đây là những gì đang diễn ra (nếu bạn không quan tâm, bỏ qua đến cuối nơi tôi chỉ cho bạn cách giết quá trình sở hữu một cổng cụ thể):

Các cổng là tài nguyên được HĐH phân bổ cho các quy trình khác nhau. Điều này tương tự với việc yêu cầu HĐH cho một con trỏ tệp. Tuy nhiên, không giống như con trỏ tệp, chỉ MỘT quá trình tại một thời điểm có thể sở hữu một cổng. Thông qua giao diện ổ cắm BSD, các quy trình có thể đưa ra yêu cầu lắng nghe trên một cổng, sau đó HĐH sẽ cấp. HĐH cũng sẽ đảm bảo không có quá trình nào khác có cùng cổng. Tại bất kỳ thời điểm nào, quá trình có thể giải phóng cổng bằng cách đóng ổ cắm. Hệ điều hành sau đó sẽ lấy lại cổng. Ngoài ra, nếu quá trình kết thúc mà không giải phóng cổng, HĐH cuối cùng sẽ lấy lại cổng (mặc dù điều đó sẽ không xảy ra ngay lập tức: sẽ mất vài phút).

Bây giờ, những gì bạn muốn làm (chỉ cần đóng cổng từ dòng lệnh), không thể vì hai lý do. Đầu tiên, nếu có thể, điều đó có nghĩa là một quy trình đơn giản có thể lấy cắp tài nguyên của quy trình khác (cổng). Đây sẽ là chính sách tồi, trừ khi bị hạn chế trong các quy trình đặc quyền. Lý do thứ hai là không rõ điều gì sẽ xảy ra với quy trình sở hữu cổng nếu chúng ta để nó tiếp tục chạy. Mã của quy trình được viết giả định rằng nó sở hữu tài nguyên này. Nếu chúng ta chỉ đơn giản là lấy nó đi, nó sẽ tự sụp đổ, vì vậy OS sẽ không cho phép bạn làm điều này, ngay cả khi bạn là một quy trình đặc quyền. Thay vào đó, bạn chỉ cần giết chúng.

Dù sao, đây là cách để giết một quá trình sở hữu một cổng cụ thể:

sudo netstat -ap | grep :<port_number>

Điều đó sẽ xuất ra dòng tương ứng với cổng giữ quá trình, ví dụ:

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

Trong trường hợp này, ProcHoldingPort là tên của quá trình mở cổng, 4683 là pid của nó và 8000 (lưu ý rằng đó là TCP) là số cổng mà nó giữ.

Sau đó, nhìn vào cột cuối cùng, bạn sẽ thấy /. Sau đó thực hiện điều này:

kill  <pid>

Nếu điều đó không hoạt động (bạn có thể kiểm tra bằng cách chạy lại lệnh netstat). Làm cái này:

kill -9 <pid>

Nói chung, tốt hơn hết là tránh gửi SIGKILL nếu bạn có thể. Đây là lý do tại sao tôi nói với bạn để thử killtrước kill -9. Chỉ cần sử dụng killsẽ gửi SIGTERM nhẹ nhàng hơn.

Như tôi đã nói, sẽ vẫn mất vài phút để cổng mở lại nếu bạn làm điều này. Tôi không biết một cách để tăng tốc độ này. Nếu ai đó làm như vậy, tôi rất thích nghe nó.


@smehmood - Cảm ơn bạn đã giải thích chi tiết .. Một nghi ngờ nhỏ .. Làm thế nào để kernel lấy lại một cổng mở bằng một quá trình bị giết đột ngột ?? .. giải pháp bạn cung cấp dường như đang giết chết quá trình giữ cổng ...

3
@codingfreak Nhân biết quá trình đã biến mất. Nó biết nó có thể lấy lại cảng. Thực sự có các quy tắc về thời gian đóng cổng, để đảm bảo không có bất kỳ gói đi lạc nào trôi nổi trên mạng. Làm thế nào để nó biết nó có những tài nguyên này? đó là những gì hạt nhân làm, theo dõi mọi thứ.
Rich Homolka

Cho đến khi ai đó đăng một cái gì đó hợp lý như unix.tools.port.close(<my port number>)tôi sẽ sử dụng init 6.
Snowcrash

Đây là một câu trả lời tuyệt vời cho một câu hỏi khác nhau. Câu hỏi này là về việc đính kèm trình gỡ lỗi và thay đổi chương trình đang chạy để khiến chương trình đó gọi một hàm trên bộ mô tả tệp.
Arthur Ulfeldt

19

Fuser cũng có thể được sử dụng

fuser -k -n *protocol portno*

Ở đây giao thức là tcp / udp và portno là số bạn muốn đóng. Ví dụ

fuser -k -n tcp 37

Thêm thông tin tại trang fuser man


Chỉ giết quá trình sở hữu đã không làm việc cho tôi, nhưng fuser đã làm. Cám ơn!
webwurst

Tôi đã nhận được kết quả khác nhau với nó, ngay cả sau khi sử dụng bộ nhiệt áp, tôi đã nhận được "socket đã được sử dụng" khi cố gắng sử dụng lại cổng từ ứng dụng đã bị giết ngay cả khi đã root như vậy. Mặt khác, thời gian để giải phóng ổ cắm dường như ngắn hơn trước đó, vì vậy dù sao cũng cảm ơn.
Jan Vlcinsky

@JanVlcinsky Có lẽ có một quy trình "người giám hộ" khởi động lại những khoảnh khắc quá trình bị giết sau khi fuserđược chạy?
RedBaron

@RedBaron: theo nhận xét superuser.com/a/415236/153413 vấn đề của tôi bắt nguồn từ ứng dụng viết kém, không dọn dẹp / đóng ổ cắm khi chấm dứt. Vì vậy, fusertìm quá trình sử dụng cổng và giết nó, nhưng không giải quyết được thực tế là ổ cắm không được đóng. 60 giây và kernel làm điều đó cho tôi.
Jan Vlcinsky

6

Bạn cũng có thể sử dụng iptables:

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

Về cơ bản nó hoàn thành những gì bạn muốn. Điều này sẽ giảm tất cả lưu lượng TCP xuống cổng 80.


4
Không, điều này sẽ giữ cho ổ cắm mở cho đến khi hết thời gian đóng chúng. (Nó sẽ ẩn tất cả lưu lượng truy cập khỏi quy trình sở hữu mà sau đó không có phương tiện để biết nó sẽ đóng nó.) Bạn có thể sử dụng -j REJECTđể trả lại cờ đặt lại TCP, sau đó sẽ thấy quá trình sở hữu của tôi để gửi một cái gì đó).
Marki555

3
netstat -anp | grep 80

Nó sẽ cho bạn biết, nếu bạn đang chạy apache, "httpd" (đây chỉ là một ví dụ, hãy sử dụng cổng mà ứng dụng của bạn đang sử dụng thay vì 80)

pkill -9 httpd 

hoặc là

killall -9 httpd

4
thử giết bình thường trước khi dùng đến -9
Thilo

@omfgroflmao - Nhưng nó sẽ giết quá trình đã mở cổng ??

@codingfreak Quá trình giữ cổng, vâng, nó sẽ giết nó.

2

Bạn có thể chỉ cần tìm ra quá trình mở ổ cắm mà cổng được liên kết và giết quá trình đó.

Nhưng, bạn sẽ phải nhận ra rằng trừ khi quá trình đó có trình xử lý khởi tạo lại tất cả những thứ mà nó đang sử dụng (mở tệp, ổ cắm, dĩa, thứ có thể tồn tại trừ khi nó đóng đúng khi chấm dứt) thì bạn sẽ tạo ra kéo theo hiệu suất hệ thống. Thêm vào đó, ổ cắm sẽ vẫn mở cho đến khi kernel nhận ra rằng quy trình đã bị giết. Điều đó thường chỉ mất khoảng một phút.

Tôi cho rằng câu hỏi tốt hơn sẽ là: Cổng nào (thuộc quy trình nào) mà bạn muốn dừng lại?

Nếu bạn đang cố gắng chấm dứt một cửa hậu hoặc virus mà bạn đã tìm thấy, thì ít nhất bạn nên tìm hiểu dữ liệu nào sẽ qua lại trước khi bạn chấm dứt nó. . quá trình tự.

Thông thường nó sẽ có một chương trình điều khiển (dừng HTTPD | bắt đầu hoặc một cái gì đó). Hoặc, nếu đó là một thứ hệ thống, có lẽ bạn không nên lộn xộn với nó. Dù sao, tôi nghĩ rằng vì mọi người khác đang cho bạn góc "làm thế nào", tôi sẽ cho bạn sự cẩn thận.


Nhận xét rất tốt. Tôi có một chương trình, theo sự chấm dứt sẽ không đóng ổ cắm dẫn đến hành vi được mô tả - ổ cắm không sử dụng được trong khoảng 60 giây. Khi tôi dừng lại và bắt đầu quá trình đó, nó sẽ phàn nàn trong khoảng một phút, rằng địa chỉ và cổng đã được sử dụng. Giải pháp tốt nhất là sửa chữa quy trình ứng xử tồi để đóng đúng cách, nhưng đôi khi đây không phải là một lựa chọn. Có cách nào để yêu cầu kiểm tra kernel mà ổ cắm bị chặn sớm hơn trong 60 giây không?
Jan Vlcinsky

2

Trước tiên tôi tìm các quá trình mongo và nút, sau đó thực hiện như sau:

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

Sau khi xác định, chỉ cần giết các quá trình với lệnh kill.

kill -9 10418
kill -9 10490

Cuối cùng, gõ meteorvà nó sẽ hoạt động trở lại.


1

Bạn có thể viết một tập lệnh sửa đổi iptables và khởi động lại chúng. Một tập lệnh để thêm quy tắc thả tất cả các gói trên cổng, một tập lệnh khác để xóa quy tắc đã nói.

Các câu trả lời khác đã chỉ cho bạn cách tiêu diệt quá trình bị ràng buộc với cổng - đây có thể không phải là điều bạn muốn. Nếu bạn muốn máy chủ tiếp tục chạy, nhưng để ngăn kết nối từ máy khách thì bạn muốn chặn cổng, không dừng quá trình.


@Michael Shimmins ... hmm nghe có vẻ khó hiểu vì chúng ta có thể chặn cổng ở phía máy chủ để khách hàng không gửi bất kỳ tin nhắn nào.

Chà, khách hàng có thể gửi tin nhắn tất cả những gì họ muốn, chúng tôi chỉ cần đóng cửa để họ không thể vào được.

1

Một vấn đề nữa: đôi khi kernel sở hữu các cổng. Tôi biết định tuyến NAT giữ một số cổng mở để sử dụng NAT. Bạn không thể giết quá trình cho việc này, đây là kernel và cấu hình lại và khởi động lại là bắt buộc.


1

Nếu bạn muốn cổng của mình được phát hành sớm hơn, bạn phải đặt giá trị sau:

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

để đặt nó từ 60 giây (mặc định) thành 1 giây


1

Bạn có thể sử dụng lệnh có tên killcx, đóng kết nối mà không có bất kỳ quá trình nào bị giết.

  • cú pháp:
killcx [dest_ip:dest_port] {interface}

  dest_ip              : remote IP
  dest_port            : remote port
  interface (optional) : network interface (eth0, lo etc).
  • thí dụ:
killcx 120.121.122.123:1234
killcx 120.121.122.123:1234 eth0

//, Hầu hết các máy Linux có killcx không? Không ai trong số những người tôi đã thử có sẵn lệnh killcx này mà không cài đặt các gói không có sẵn cho họ với cấu hình kho lưu trữ hiện tại của họ.
Nathan Basan

không, bạn có thể tìm thấy công cụ ở đây: killcx.sourceforge.net
shuaiming

//, Tôi biết rằng tôi có thể tìm thấy công cụ này, thật khó để cài đặt nó trên hàng ngàn máy chủ.
Nathan Basan

Sử dụng con rối @NathanBasan :)
SHOUBHIK BOSE 17/03/2016

1

Tôi biết rằng câu trả lời này không tự trả lời câu hỏi, nhưng nói đúng ra, nhưng đọc nó có thể là thông tin liên quan:

Hành vi mặc định của việc gắn một ổ cắm vào một cổng (và địa chỉ) là khi ổ cắm bị đóng do quá trình chấm dứt đột ngột, ổ cắm sẽ ở trong TIME_WAIT trong một thời gian. Điều này có nghĩa là bạn không thể liên kết lại ngay lập tức với địa chỉ / cổng này. Nếu bạn đang tự phát triển hệ thống thông qua giao diện ổ cắm BSD tiêu chuẩn, bạn có thể (ít nhất là ở một mức độ nào đó) kiểm soát hành vi này với tùy chọn ổ cắm SO_REUSEADDR. Điều này về cơ bản sẽ cho phép bạn liên kết vào cùng một địa chỉ / cổng nếu ổ cắm ở trạng thái TIME_WAIT. Vẫn còn một ổ cắm trên mỗi cổng!

Tuy nhiên, thông tin này chỉ nên được sử dụng làm hỗ trợ phát triển, vì có lý do để TIME_WAIT tồn tại ở nơi đầu tiên, đã được giải thích trong các câu trả lời khác.


// , Đúng. Tất nhiên, giết quá trình không phải là cách tốt nhất để giải phóng các cổng. Tôi đã nhận thấy rằng khi tôi giết quá trình Vagrant nếu nó bị treo, tôi không thể mơ hồ một lần nữa. Tôi cá là thứ TIME_WAIT này có liên quan đến nó.
Nathan Basan

0

Nếu bạn muốn không có lưu lượng truy cập qua ổ cắm nhưng muốn tiếp tục quá trình: tcpkill .

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

Sẽ bắt đầu một trình nền đánh hơi chặn và chặn tất cả lưu lượng truy cập trên cổng đó. Rất thuận tiện để kiểm tra các ứng dụng của bạn để phân chia mạng.


0

Bạn có thể đóng ổ cắm nghe bằng ss :

sudo ss --kill state listening src :1234

Trong đó 1234 là số cổng của bạn.

ss là một phần của gói iproute2, vì vậy có một sự thay đổi mạnh mẽ mà nó đã được cài đặt trên một Linux hiện đại.

Tôi đã học được điều này từ một câu trả lời cho một câu hỏi liên quan .

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.