Kiểm tra nếu một cổng trên hệ thống từ xa có thể truy cập được (không có telnet)


353

Ngày xưa, chúng ta thường telnetxem một cổng trên máy chủ từ xa có mở không: telnet hostname portsẽ cố gắng kết nối với bất kỳ cổng nào trên bất kỳ máy chủ nào và cung cấp cho bạn quyền truy cập vào luồng TCP thô.

Ngày nay, các hệ thống tôi làm việc không được cài đặt telnet (vì lý do bảo mật) và tất cả các kết nối ra bên ngoài đến tất cả các máy chủ đều bị chặn theo mặc định. Theo thời gian, thật dễ dàng để mất theo dõi cổng nào được mở cho máy chủ nào.

Có cách nào khác để kiểm tra xem một cổng trên hệ thống từ xa có mở không - sử dụng hệ thống Linux với số lượng gói hạn chế được cài đặt và telnetkhông khả dụng?



Tôi đã có vấn đề tương tự. Câu trả lời của @Subhranath Chunder dưới đây đã giúp. Tuy nhiên, sau đó tôi phát hiện ra rằng cài đặt Telnet là một vấn đề nhỏ khi chạy brew install telnet. Vì vậy, tôi hy vọng người dùng Linux có thể làm tương tự với yumapt-get.
Mig82

Câu trả lời:


277

Bash đã có thể truy cập các cổng TCPUDP trong một thời gian. Từ trang người đàn ông:

/dev/tcp/host/port
    If host is a valid hostname or Internet address, and port is an integer port number
    or service name, bash attempts to open a TCP connection to the corresponding socket.
/dev/udp/host/port
    If host is a valid hostname or Internet address, and port is an integer port number
    or service name, bash attempts to open a UDP connection to the corresponding socket.

Vì vậy, bạn có thể sử dụng một cái gì đó như thế này:

xenon-lornix:~> cat < /dev/tcp/127.0.0.1/22
SSH-2.0-OpenSSH_6.2p2 Debian-6
^C pressed here

Taa Daa!


Điều này dường như cũng hoạt động trong MinGW . Chẳng hạn, một máy chủ VNC từ xa trên 192.168.2.100 phản hồi với "RFB 003.008" bằng cách sử dụng "cat </dev/tcp/192.168.2.100/5900".
Peter Mortensen

1
@lornix, ok, nhưng trong trường hợp này tôi phải nhận được kết quả tương tự với việc sử dụng nc mà không có tùy chọn -z, nhưng nó vẫn không hoạt động: # nc -v -w5 127.0.0.1 18080 Kết nối với cổng 127.0.0.1 18080 [tcp / *] đã thành công! # cat </dev/tcp/127.0.0.1/18080 Chỉ bị treo mà không có kết quả. Chỉ muốn hiểu khi nào tôi có thể sử dụng tùy chọn "/ dev / tcp / host / port"
Alexandr

5
@Alexandr ... thực ra, "treo mà không có kết quả" là hành vi được mong đợi khá nhiều. mèo đang chờ đầu vào. nc có thêm thông minh để cho phép nó cảm nhận không có dữ liệu đang chờ xử lý và ngừng thử. mèo không phải là khá thông minh. Hãy thử cat < /dev/tcp/localhost/22, bạn sẽ nhận được tiêu đề sshd của bạn. Rõ ràng, quá trình của bạn trên cổng 18080 chờ đợi một cái gì đó đến, trước khi gửi bất cứ điều gì. Cổng 22 ( ssh ) chào đón bạn với phiên bản của nó và không có gì. Hãy thử nó!
lornix

1
@lornix, cảm ơn bạn rất nhiều vì đã giải thích! Bây giờ hạn chế là rõ ràng. Tôi nghĩ rằng sử dụng nc nên là một cách ưa thích để kiểm tra các cổng.
Alexandr

2
Điều này cực kỳ hữu ích khi làm việc với một container docker không có gì được cài đặt. Đã có thể nhanh chóng xác minh rằng container có quyền truy cập vào DB không được chứa thông qua DNS. Ví dụ: mèo </ dev / tcp / tên máy chủ / 5432
Michael Hobbs

404

Đẹp và dài dòng! Từ những trang đàn ông.
Cổng đơn:

nc -zv 127.0.0.1 80

Nhiều cổng:

nc -zv 127.0.0.1 22 80 8080

Phạm vi cảng:

nc -zv 127.0.0.1 20-30

6
Có vẻ là câu trả lời tốt nhất, cảm ơn. ;-)
lpapp

6
Điều này bị treo khi thử trên Ubuntu 14.04 (Trusty Tahr) cho một máy chủ từ xa (cùng mạng LAN) cho các cổng đóng (nó đã hết thời gian sau 127 giây) - do đó không phù hợp lắm trong các tập lệnh. Nó đã làm việc mặc dù cho một dịch vụ có một cổng mở. Sử dụng tùy chọn "-w2" có thể là giải pháp.
Peter Mortensen

6
Sử dụng tùy chọn -u cho các cổng UDP.
Efren

8
Trên phiên bản 6.4 của ncat -z không được công nhận. Tôi đã có thể làm mà không cần z
smishra

5
Bạn có thể kiểm tra nhiều phạm vi với: nc -zv 127.0.0.1 22,80,8080,20-30,443-446(nc Phiên bản: 1.107-4).
bobbel

102

Netcat là một công cụ hữu ích:

nc 127.0.0.1 123 &> /dev/null; echo $?

Sẽ xuất 0nếu cổng 123 mở và 1nếu nó đóng.


Đây là một câu trả lời thanh lịch và kịch bản hơn nhiều so với của tôi. Thật không may cho tôi rằng các sysadins có ý thức bảo mật đã giữ lại telnetcũng bị giữ lại nc(mặc dù - kỳ lạ - không curlhoặc wget).
Steve HHH

Vâng, đó là hoàn toàn độc đoán và ngớ ngẩn.
thnee

3
Hãy để những FORtuyên bố bắt đầu!
Chad Harrison

1
Điều này bị treo khi thử trên Ubuntu 14.04 (Trusty Tahr) cho một máy chủ từ xa (cùng mạng LAN) cho các cổng đóng (nó đã hết thời gian sau khoảng 127 giây) - do đó không phù hợp lắm trong các tập lệnh. Nó đã hoạt động mặc dù đối với một dịch vụ có cổng mở, trả về 0. Sử dụng tùy chọn "-w2" có thể là giải pháp.
Peter Mortensen

1
Tôi nghĩ rằng -G 2sẽ thích hợp hơn cho thời gian chờ TCP
AB

58

Phương pháp đơn giản nhất mà không sử dụng một công cụ khác, như socat, được mô tả trong câu trả lời của @ lornix ở trên. Đây chỉ là để thêm một ví dụ thực tế về cách người ta sẽ sử dụng thiết bị psuedo /dev/tcp/...trong Bash nếu bạn muốn, kiểm tra xem máy chủ khác có một cổng nhất định có thể truy cập qua dòng lệnh hay không.

Ví dụ

Nói rằng tôi có một máy chủ lưu trữ trên mạng của tôi được đặt tên skinner.

$ (echo > /dev/tcp/skinner/22) >/dev/null 2>&1 \
    && echo "It's up" || echo "It's down"
It's up

$ (echo > /dev/tcp/skinner/222) >/dev/null 2>&1 && \
    echo "It's up" || echo "It's down"
It's down

Lý do bạn muốn gói các echo > /dev/...dấu ngoặc đơn như thế này (echo > /dev/...)là bởi vì nếu bạn không, sau đó với các bài kiểm tra kết nối bị hỏng, bạn sẽ nhận được các loại tin nhắn này hiển thị.

$ (echo > /dev/tcp/skinner/223) && echo hi
bash: connect: Connection refused
bash: /dev/tcp/skinner/223: Connection refused

Chúng không thể được chuyển hướng đơn giản /dev/nullvì chúng xuất phát từ nỗ lực ghi dữ liệu vào thiết bị /dev/tcp. Vì vậy, chúng tôi nắm bắt tất cả đầu ra trong một lệnh phụ, tức là (...cmds...)và chuyển hướng đầu ra của lệnh phụ.


Thật tuyệt vời. Chúc nó sẽ được bình chọn lên đến đỉnh. Tôi chỉ đọc đến đây trên trang vì tôi vô tình cuộn trước khi đóng nó.
Still.Tony

@ Okuma.Tony - vâng, đó luôn là vấn đề với Q có nhiều câu trả lời 8-). Cảm ơn cho các phản hồi mặc dù, nó đánh giá cao.
slm

46

Tôi thấy rằng curlcó thể hoàn thành công việc theo cách tương tự telnet, và curlthậm chí sẽ cho bạn biết giao thức mà người nghe mong đợi.

Xây dựng URI HTTP từ tên máy chủ và cổng làm đối số đầu tiên curl. Nếu curlcó thể kết nối, nó sẽ báo cáo một giao thức không khớp và thoát (nếu người nghe không phải là dịch vụ web). Nếu curlkhông thể kết nối, nó sẽ hết thời gian.

Ví dụ: cổng 5672 trên máy chủ 10.0.0.99 bị đóng hoặc chặn bởi tường lửa:

$ curl http://10.0.0.99:5672
curl: (7) couldn't connect to host

Tuy nhiên, từ một hệ thống khác, có thể truy cập cổng 5672 trên máy chủ 10.0.0.99 và dường như đang chạy trình nghe AMQP.

$ curl http://10.0.0.99:5672
curl: (56) Failure when receiving data from the peer
AMQP

Điều quan trọng là phải phân biệt giữa các thông báo khác nhau: thất bại đầu tiên là do curlkhông thể kết nối với cổng. Thất bại thứ hai là một thử nghiệm thành công, mặc dù curlmong đợi một người nghe HTTP thay vì người nghe AMQP.


5
Nếu curl không có sẵn, wget có thể. wget -qS -O- http://ip.add.re.ss:porthiệu quả nên làm điều tương tự.
một CVn

4
Điều này thậm chí hoạt động với một tên máy chủ, ví dụ. curl myhost:22.
에 ảnh

Điều này có thể không chính xác. Tôi đang có một dịch vụ tomcat đang chạy, nhưng gặp lỗi 404. # curl -k 192.168.194.4:6443 <html> <head> <title> Apache Tomcat / 7.0.34 - Báo cáo lỗi </ title> <style> <! - H1 --- HR {color: # 525D76;} -> </ style> </ head> <body> <h1> Trạng thái HTTP 404 - / </ h1> <HR size = "1" noshade = "noshade"> <p> <b> gõ </ b> Báo cáo trạng thái </ p> <p> <b> tin nhắn </ b> <u> / </ u> </ p> <p> <b> mô tả </ b> <u> Tài nguyên được yêu cầu không khả dụng. </ u> </ p> <HR size = "1" noshade = "noshade"> <h3> Apache Tomcat / 7.0.34 </ h3> </ body> </ html>

Xem bài viết của tôi với cách tiếp cận tương tự.
kenorb

12
[admin@automation-server 1.2.2]# nc -v -z -w2 192.168.193.173 6443
nc: connect to 192.168.193.173 port 6443 (tcp) failed: Connection refused

[admin@automation-server 1.2.2]# nc -v -z -w2 192.168.194.4 6443
Connection to 192.168.194.4 6443 port [tcp/sun-sr-https] succeeded!

Hy vọng nó giải quyết vấn đề của bạn :)


1
Vâng, điều này là tốt hơn - hết thời gian gần như ngay lập tức cho các cổng đóng.
Peter Mortensen

1
Có phải điều này luôn sử dụng TCP hoặc có cách nào để kiểm tra UDP không?
kmoe


6

Tôi đã vật lộn cả ngày vì dường như không có câu trả lời nào phù hợp với tôi. Vấn đề là phiên bản gần đây nhất nckhông còn có -zcờ, trong khi truy cập trực tiếp qua TCP (theo @lornix và @slm) không thành công khi không thể truy cập máy chủ. Cuối cùng tôi đã tìm thấy trang này , nơi cuối cùng tôi đã tìm thấy không chỉ một mà hai ví dụ hoạt động:

  1. nc -w1 127.0.0.1 22 </dev/null

    ( -wcờ sẽ xử lý thời gian chờ và </dev/nullthay thế -zcờ)

  2. timeout 1 bash -c '(echo > /dev/tcp/127.0.0.1/22) >/dev/null 2>&1'

    ( timeoutlệnh xử lý thời gian chờ và phần còn lại là từ @slm)

Sau đó, chỉ cần sử dụng &&và / hoặc ||(hoặc thậm chí $?) để trích xuất kết quả. Hy vọng, ai đó sẽ tìm thấy thông tin này hữu ích.


4

Kết hợp các câu trả lời từ @kenorb và @Azukikuru, bạn có thể kiểm tra cổng mở / đóng / tường lửa.

timeout 1 bash -c '</dev/tcp/127.0.0.1/22 && echo Port is open || echo Port is closed' || echo Connection timeout

Một cách tiếp cận khác với curl để đạt được bất kỳ cổng

curl telnet://127.0.0.1:22

3

Đây là một chức năng sẽ chọn một trong các phương thức tùy thuộc vào những gì được cài đặt trên hệ thống của bạn:

# Check_port <address> <port> 
check_port() {
if [ "$(which nc)" != "" ]; then 
    tool=nc
elif [ "$(which curl)" != "" ]; then
     tool=curl
elif [ "$(which telnet)" != "" ]; then
     tool=telnet
elif [ -e /dev/tcp ]; then
      if [ "$(which gtimeout)" != "" ]; then  
       tool=gtimeout
      elif [ "$(which timeout)" != "" ]; then  
       tool=timeout
      else
       tool=devtcp
      fi
fi
echo "Using $tool to test access to $1:$2"
case $tool in
nc) nc -v -G 5 -z -w2 $1 $2 ;;
curl) curl --connect-timeout 10 http://$1:$2 ;;
telnet) telnet $1 $2 ;;
gtimeout)  gtimeout 1 bash -c "</dev/tcp/${1}/${2} && echo Port is open || echo Port is closed" || echo Connection timeout ;;
timeout)  timeout 1 bash -c "</dev/tcp/${1}/${2} && echo Port is open || echo Port is closed" || echo Connection timeout ;;
devtcp)  </dev/tcp/${1}/${2} && echo Port is open || echo Port is closed ;;
*) echo "no tools available to test $1 port $2";;
esac

}
export check_port

2

Nó không nên có sẵn trên hộp của bạn, nhưng hãy thử với nmap.


4
nmaplà một công cụ tốt, nhưng không có sẵn trên các hệ thống này. Thay vì tải xuống nmap, biên dịch nó, cài đặt nó vào thư mục nhà của tôi, sau đó sao chép nó sang tất cả các hệ thống khác, tôi đã hy vọng tìm ra cách sử dụng các công cụ hiện có trong hầu hết các cài đặt Linux.
Steve HHH

1

để tham khảo, mở rộng câu trả lời của @peperunas:

cách sử dụng nmap để kiểm tra là:

nmap -p 22 127.0.0.1

(ví dụ trên sử dụng localhost cho mục đích trình diễn)


0

Nếu bạn muốn kiểm tra nhiều hơn trên hệ thống, bạn có thể sử dụng công cụ kiểm tra dda-serverpec của chúng tôi ( https://github.com/DomainDrivenArch architecture / dda-serverspec-crate ) cho các tác vụ đó. Bạn có thể xác định kỳ vọng của bạn

{:netcat [{:host "mywebserver.com" :port "443"}
          {:host "telnet mywebserver.com" :port "80"}
          {:host "telnet mywebserver.com" :port "8443"}]}

và kiểm tra những kỳ vọng này đối với localhost hoặc với các máy chủ từ xa (kết nối bằng ssh). Đối với các thử nghiệm từ xa, bạn phải xác định mục tiêu:

{:existing [{:node-name "test-vm1"
             :node-ip "35.157.19.218"}
            {:node-name "test-vm2"
             :node-ip "18.194.113.138"}]
 :provisioning-user {:login "ubuntu"}}

Bạn có thể chạy thử nghiệm với java -jar dda-serverspec.jar --targets targets.edn serverspec.edn

Dưới mui xe, chúng tôi đang sử dụng netcat như được đẩy ở trên ...

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.