쉘 스크립트에서 원격 TCP 포트가 열려 있는지 테스트


297

셸 스크립트 내부에서 원격 서버에 지정된 TCP 포트가 열려 있는지 테스트하는 빠르고 간단한 방법을 찾고 있습니다.

나는 telnet 명령으로 그것을 관리했고, 포트가 열릴 때 잘 작동하지만 포트가 열리지 않을 때 시간 초과되지 않는 것 같습니다 ...

샘플은 다음과 같습니다.

l_TELNET=`echo "quit" | telnet $SERVER $PORT | grep "Escape character is"`
if [ "$?" -ne 0 ]; then
  echo "Connection to $SERVER on port $PORT failed"
  exit 1
else
  echo "Connection to $SERVER on port $PORT succeeded"
  exit 0
fi

예를 들어 8 초 이내에 연결되지 않으면 텔넷이 시간 초과되도록 강제하고 셸 (반환 코드 또는 stdout의 문자열)에서 잡을 수있는 것을 반환하는 더 좋은 방법이 필요합니다.

IO :: Socket :: INET 모듈을 사용하고 포트를 테스트하는 성공적인 스크립트를 작성했지만 가능하면 Perl을 사용하지 않는 Perl 메소드를 알고 있습니다.

참고 : 이것은 내 서버가 실행중인 것입니다 (이를 실행 해야하는 곳)

SunOS 5.10 Generic_139556-08 i86pc i386 i86pc


무엇에 대한 netcat을 또는 Nmap은 ?
예레미야 윌콕

그 대답은 기대와 함께있었습니다. 우리는 필요한 포트에서 텔넷을 보내는 간단한 스크립트를 작성했습니다. 시간은 8 초입니다. 선택할 수있는 많은 예제가 있습니다. 우리는이 게시물 기반으로 우리 : unix.com/shell-programming-scripting/...
Yanick Girouard는

1
github.com/monitoring-plugins/monitoring-plugins의 check_tcp 는 문자열 입력 및 예상 답변 확인을 포함하여이를 수행 할 수 있습니다.

답변:


452

B. Rhodes가 지적한대로 nc업무를 수행합니다. 그것을 사용하는보다 간단한 방법 :

nc -z <host> <port>

그렇게 nc하면 포트가 열려 있는지 확인하고 성공하면 0으로, 실패하면 1로 종료합니다.

빠른 대화식 검사 (5 초 시간 초과) :

nc -z -v -w5 <host> <port>

48
centos7은 기본적으로 nmap netcat을 사용하며 -z 옵션이 없습니다.
jolestar

7
RHEL / Centos에서는 작동하지 않습니다. 이러한 배포판의 경우 다음을 수행해야합니다. nc -vn <host> <port>
Justin Dennahower

2
FWIW, 나는 RHEL 6과 RHEL 7에 별도로 적용 되는 예제로 내 대답을 완전히 정비했습니다 .
Acumenus

4
Mac에서는 최소한 기본적으로 읽기 시간 초과 기능을하는 -G#시간 초과와 별도로 / 연결 시간 초과를 설정 하기 위해 추가해야 할 수도 있습니다 -w#.
Doktor J

1
@jolestar Centos 7에서 Ncat을 수동으로 업그레이드하여 -z옵션 을 얻을 수 있습니다. 당신은 고려할 수 있습니다 : unix.stackexchange.com/questions/393762/...
데미안 Ó Ceallaigh

150

-z-w TIMEOUT옵션을 사용하여 쉽게 수행 할 수 nc있지만 모든 시스템이 nc설치되어있는 것은 아닙니다 . 최신 버전의 bash가 있으면 다음과 같이 작동합니다.

# Connection successful:
$ timeout 1 bash -c 'cat < /dev/null > /dev/tcp/google.com/80'
$ echo $?
0

# Connection failure prior to the timeout
$ timeout 1 bash -c 'cat < /dev/null > /dev/tcp/sfsfdfdff.com/80'
bash: sfsfdfdff.com: Name or service not known
bash: /dev/tcp/sfsfdfdff.com/80: Invalid argument
$ echo $?
1

# Connection not established by the timeout
$ timeout 1 bash -c 'cat < /dev/null > /dev/tcp/google.com/81'
$ echo $?
124

여기서 일어나는 일은 timeout지정된 시간 초과 (위 예제에서 1 초) 내에 종료되지 않으면 하위 명령을 실행하고 종료 한다는 것입니다. 이 경우 bash부속 명령이며 특수한 / dev / tcp 처리 를 사용하여 지정된 서버 및 포트에 대한 연결을 시도하고 엽니 다. 경우 bash제한 시간 내에 연결을 열 수있는 cat것입니다 단지 가까운 즉시 (그것의에서 읽기 때문에 /dev/null상태 코드 종료)의 0어떤을 통해 전파됩니다 bash다음과 timeout. 경우 bash지정된 시간 종료 이전에 연결 실패를 가져, 다음 bash1의 종료 코드로 종료됩니다 timeout도 반환합니다. bash가 연결을 설정할 수없고 지정된 시간 초과가 만료되면timeoutbash과 (124)의 상태로 종료합니다.


1
/dev/tcp리눅스가 아닌 다른 시스템에서 사용 가능? 특히 Mac은 어떻습니까?
피터

8
/ dev / tcp는 bash의 기능이므로 그렇습니다. 그러나 그것은 ... 시간 제한이없는 맥처럼 보이는
onlynone

1
@onlynone- timeoutFreeBSD에는 존재하지 않는 것 같습니다 . 그리고 오래된 Ubuntu 상자에는 설치 가능한 패키지이지만 기본적으로 존재하지 않습니다. 시간 초과 또는 netcat과 같은 타사 도구없이 bash에서만이 작업을 수행 할 수있는 방법이 있다면 좋을 것입니다.
Graham

3
그냥 언급하고 싶었 timeout나타난다는 GNU의로 coreutils의 일부로, 그리고 사제와 맥에 설치할 수 있습니다 brew install coreutils. 그러면로 사용할 수 있습니다 gtimeout.
onlyn

1
@Wildcard 호스트 이름에 대한 지원이 추가되었지만 bash 변경 로그가 제안 합니다. bash-2.04-develbash-2.05-alpha1
Acumenus

109

TOC :

  • bash 사용 timeout
    • 명령
  • 사용 nc
    • 명령
    • RHEL 6 (nc-1.84)
      • 설치
    • RHEL 7 (nmap-ncat-6.40)
      • 설치
  • 비고

bash 및 timeout:

참고 timeoutRHEL 6+에 존재하는지, 대안 GNU에서 발견은 8.22로 coreutils. MacOS에서는 다음을 사용하여 설치 brew install coreutils하고로 사용하십시오 gtimeout.

명령:

$ timeout $TIMEOUT_SECONDS bash -c "</dev/tcp/${HOST}/${PORT}"; echo $?

호스트와 포트를 parametrizing 경우로를 지정해야 ${HOST}하고 ${PORT}위와입니다. 같은 단지를 지정하지 마십시오 $HOST$PORT중괄호없이, 즉; 이 경우에는 작동하지 않습니다.

예:

성공:

$ timeout 2 bash -c "</dev/tcp/canyouseeme.org/80"; echo $?
0

실패:

$ timeout 2 bash -c "</dev/tcp/canyouseeme.org/81"; echo $?
124

의 종료 상태를 유지해야하는 경우 bash,

$ timeout --preserve-status 2 bash -c "</dev/tcp/canyouseeme.org/81"; echo $?
143

사용 nc:

이전 버전과 호환되지 않는 버전의 ncRHEL 7에 설치되었습니다.

명령:

아래 명령은 RHEL 6과 7에서 동일하다는 점에서 고유합니다. 이는 설치와 출력이 다릅니다.

$ nc -w $TIMEOUT_SECONDS -v $HOST $PORT </dev/null; echo $?

RHEL 6 (nc-1.84) :

설치:

$ sudo yum install nc

예 :

성공:
$ nc -w 2 -v canyouseeme.org 80 </dev/null; echo $?
Connection to canyouseeme.org 80 port [tcp/http] succeeded!
0
실패:
$ nc -w 2 -v canyouseeme.org 81 </dev/null; echo $?
nc: connect to canyouseeme.org port 81 (tcp) timed out: Operation now in progress
1

호스트 이름이 여러 IP에 매핑되면 위의 명령이 실패하거나 많은 IP 전체를 순환합니다. 예를 들면 다음과 같습니다.

$ nc -w 2 -v microsoft.com 81 </dev/null; echo $?
nc: connect to microsoft.com port 81 (tcp) timed out: Operation now in progress
nc: connect to microsoft.com port 81 (tcp) timed out: Operation now in progress
nc: connect to microsoft.com port 81 (tcp) timed out: Operation now in progress
nc: connect to microsoft.com port 81 (tcp) timed out: Operation now in progress
nc: connect to microsoft.com port 81 (tcp) timed out: Operation now in progress
1

RHEL 7 (nmap-ncat-6.40) :

설치:

$ sudo yum install nmap-ncat

예 :

성공:
$ nc -w 2 -v canyouseeme.org 80 </dev/null; echo $?
Ncat: Version 6.40 ( http://nmap.org/ncat )
Ncat: Connected to 52.202.215.126:80.
Ncat: 0 bytes sent, 0 bytes received in 0.22 seconds.
0
실패:
$ nc -w 2 -v canyouseeme.org 81 </dev/null; echo $?
Ncat: Version 6.40 ( http://nmap.org/ncat )
Ncat: Connection timed out.
1

호스트 이름이 여러 IP에 매핑되면 위의 명령이 실패하거나 많은 IP 전체를 순환합니다. 예를 들면 다음과 같습니다.

$ nc -w 2 -v microsoft.com 81 </dev/null; echo $?
Ncat: Version 6.40 ( http://nmap.org/ncat )
Ncat: Connection to 104.43.195.251 failed: Connection timed out.
Ncat: Trying next address...
Ncat: Connection to 23.100.122.175 failed: Connection timed out.
Ncat: Trying next address...
Ncat: Connection to 23.96.52.53 failed: Connection timed out.
Ncat: Trying next address...
Ncat: Connection to 191.239.213.197 failed: Connection timed out.
Ncat: Trying next address...
Ncat: Connection timed out.
1

비고 :

-v( --verbose) 인수와 echo $?명령은 설명을위한 물론이다.


3
timeout 2 bash -c "</dev/tcp/canyouseeme.org/81"; echo $?좋은 지적입니다!
ipeacocks

추가 2>&1하지 에코 상태 result_test=$(nc -w 2 $ip_addreess 80 </dev/null 2>&1 ; echo $?)
삼아 Snex

55

다음과 netcat같이 포트가 열려 있는지 확인할 수 있습니다.

nc my.example.com 80 < /dev/null

ncTCP 포트를 열면 의 반환 값 이 성공하고 TCP 연결을 만들 수 없으면 실패 (일반적으로 반환 코드 1)가됩니다.

nc에서 파일 끝을 수신 한 후에도 소켓의 전송 절반을 닫지 않기 때문에이 버전을 시도하면 일부 버전 이 중단됩니다 /dev/null. 내 자신의 Ubuntu 랩톱 (18.04)에서 netcat-openbsd설치 한 netcat 버전은 해결 방법을 제공합니다. -N즉각적인 결과를 얻으려면 옵션이 필요합니다.

nc -N my.example.com 80 < /dev/null

1
깃발을 nc지원하지 않는 풍미에 좋습니다 -w.
David Dossot

5
덕분에- -z지원 없이 nc 버전에서도 작동 -예를 들어 RHEL / CentOS 7에서 작동
Andrew

1
이 접근 방식은 좋지만 -w스크립트에 사용될 때 명령이 10 초 이상 중단 될 수있는 실패입니다. 가 포함 된 답변 을 작성했습니다 -w.
Acumenus

2
+1 이것은 nc가 alpine linux와 ubuntu 모두 표준으로 제공되기 때문에 훌륭합니다. 아마도 다른 사람들 일 것입니다. 원격에있을 때 추가로 설치할 필요가 없습니다. 이거 고마워! 내가 추가 할 수도 있습니다nc host port -w 2 && echo it works
std''OrgnlDave

2
나는 선호한다 nc -vz localhost 3306. 더 자세한 출력을 제공합니다. Mac에서만 시도했습니다.
EFreak

29

Bash 에서 TCP / UDP 연결을 위해 의사 장치 파일 을 사용 하는 것은 간단합니다. 스크립트는 다음과 같습니다.

#!/usr/bin/env bash
SERVER=example.com
PORT=80
</dev/tcp/$SERVER/$PORT
if [ "$?" -ne 0 ]; then
  echo "Connection to $SERVER on port $PORT failed"
  exit 1
else
  echo "Connection to $SERVER on port $PORT succeeded"
  exit 0
fi

테스트 :

$ ./test.sh 
Connection to example.com on port 80 succeeded

다음은 one-liner (Bash 구문)입니다.

</dev/tcp/localhost/11211 && echo Port open. || echo Port closed.

일부 서버는 SYN 플러드 공격으로부터 방화벽으로 보호 될 수 있으므로 TCP 연결 시간 초과 (~ 75 초)가 발생할 수 있습니다. 시간 초과 문제를 해결하려면 다음을 시도하십시오.

timeout 1 bash -c "</dev/tcp/stackoverflow.com/81" && echo Port open. || echo Port closed.

참조 : 어떻게 TCP 연결 () 시스템 호출 제한 시간을 감소시킵니다?


1
@ABB SYN 서비스 장애 공격을 방지하기위한 응답을 제공하지 않는 서버의 방화벽 구성과 관련이 있습니다. 달리기 telnet canyouseeme.org 81도 중단됩니다. 이것은 아마도 bash로 하드 코딩 된 타임 아웃 한계에 의해 제어됩니다. TCP connect () 시스템 호출 시간 초과 줄이기를 참조하십시오 .
kenorb

매개 변수화를 들어, 지금은 지정할 필요가있을 것으로 보인다 $SERVER$PORT중괄호, 적어도으로 ${SERVER}${PORT}.
Acumenus

13

여러 자식 저장소에서 작업하기위한보다 유연한 솔루션이 필요했기 때문에 12를 기반으로 다음 sh 코드를 작성했습니다 . gitlab.com 대신 서버 주소를 사용하고 22 대신 포트를 사용할 수 있습니다.

SERVER=gitlab.com
PORT=22
nc -z -v -w5 $SERVER $PORT
result1=$?

#Do whatever you want

if [  "$result1" != 0 ]; then
  echo  'port 22 is closed'
else
  echo 'port 22 is open'
fi

1
감사! 그것은 /etc/rc.local에 쉽게 내 인생을 만든다
샤힌 칼레드

10

ksh 또는 bash 를 사용하는 경우 둘 다 / dev / tcp / IP / PORT를 사용하여 소켓으로 /에서 IO 리디렉션을 지원합니다 구문을 합니다. 이러한면에서 Korn 쉘의 예를 들어 내가 리디렉션하고 어떠한 조합의 ( : ) 수 std하지-의 소켓에서 :

W$ python -m SimpleHTTPServer &
[1]     16833
Serving HTTP on 0.0.0.0 port 8000 ...
W$ : </dev/tcp/127.0.0.1/8000

소켓이 열려 있지 않으면 쉘은 오류를 인쇄합니다.

W$ : </dev/tcp/127.0.0.1/8001
ksh: /dev/tcp/127.0.0.1/8001: cannot open [Connection refused]

따라서 이것을 테스트 로 사용할 수 있습니다 if 조건 에서이를 .

SERVER=127.0.0.1 PORT=8000
if (: < /dev/tcp/$SERVER/$PORT) 2>/dev/null
then
    print succeeded
else
    print failed
fi

no-op은 서브 쉘에 있으므로 std-in 리디렉션이 실패하면 std-err를 버릴 수 있습니다.

나는 자주 사용한다 HTTP를 통한 리소스의 가용성을 확인하기 위해 / dev / tcp 를 .

W$ print arghhh > grr.html
W$ python -m SimpleHTTPServer &
[1]     16863
Serving HTTP on 0.0.0.0 port 8000 ...
W$ (print -u9 'GET /grr.html HTTP/1.0\n';cat <&9) 9<>/dev/tcp/127.0.0.1/8000
HTTP/1.0 200 OK
Server: SimpleHTTP/0.6 Python/2.6.1
Date: Thu, 14 Feb 2013 12:56:29 GMT
Content-type: text/html
Content-Length: 7
Last-Modified: Thu, 14 Feb 2013 12:55:44 GMT

arghhh
W$ 

이 단일 라이너 는 소켓에서 읽고 쓰기 위해 파일 디스크립터 9 를 열고 HTTP GET 을 소켓에 인쇄 하고 소켓 cat에서 읽는 데 사용 합니다.


1
@ABB 필터링 된 포트와 같이 포트가 응답하지 않거나 IP에 아무것도없는 경우 포트가 오랫동안 멈추는 것을 의미한다고 생각합니다. 포트가 적극적으로 연결을 거부하더라도 닫힌 포트는 지연을 유발하지 않습니다. 많은 목적으로 이것은 꽤 수용 가능합니다.
mc0e

이 기술은 kenorb사전 답변 에서이 답변 전에 이미 게시 되었습니다 . 어쨌든, 더 큰 요점은 포트가 응답하지 않으면 오랫동안 중단된다는 것입니다. 예를 들어, </dev/tcp/canyouseeme.org/80and를 시도하십시오 </dev/tcp/canyouseeme.org/81.
Acumenus

9

오래된 질문이지만 방금 변형을 다루었지만 여기에 적용 할 수있는 솔루션이 없으므로 다른 것을 발견하고 후손을 위해 추가하고 있습니다. 예, OP가이 옵션에 대해 알고 있다고하는데 적합하지 않다는 것을 알고 있지만, 이후에 오는 사람에게는 유용 할 수 있습니다.

필자의 경우 빌드 apt-cacher-ng에서 로컬 서비스 의 가용성을 테스트하고 싶습니다 docker. 즉, 테스트 전에는 아무것도 설치할 수 없습니다. 아니 nc, nmap, expect, telnet또는 python. perl그러나 핵심 라이브러리와 함께 존재하므로 이것을 사용했습니다.

perl -MIO::Socket::INET -e 'exit(! defined( IO::Socket::INET->new("172.17.42.1:3142")))'

6

curl, telnet, nc o nmap과 같은 도구를 사용할 수없는 경우에도 wget을 사용할 수 있습니다

if [[ $(wget -q -t 1 --spider --dns-timeout 3 --connect-timeout 10  host:port; echo $?) -eq 0 ]]; then echo "OK"; else echo "FAIL"; fi

6

bash를 사용하여 포트 확인

$ ./test_port_bash.sh 192.168.7.7 22

포트 22가 열려 있습니다

암호

HOST=$1
PORT=$2
exec 3> /dev/tcp/${HOST}/${PORT}
if [ $? -eq 0 ];then echo "the port $2 is open";else echo "the port $2 is closed";fi

4

당신이 사용하고자하는 경우 nc만 지원하는 버전이없는 -z, 사용 시도를 --send-only:

nc --send-only <IP> <PORT> </dev/null

그리고 시간 초과 :

nc -w 1 --send-only <IP> <PORT> </dev/null

IP 인 경우 DNS 조회없이 :

nc -n -w 1 --send-only <IP> <PORT> </dev/null

-z연결 가능 여부에 따라 코드를 기반으로 반환합니다 .


1

대답하기에는 너무 늦었을 것입니다. 이것은 좋지 않을 수도 있지만 여기에 있습니다 ...

타이머가있는 while 루프 안에 넣는 것은 어떻습니까? 나는 솔라리스보다 펄 녀석이지만, 사용중인 쉘에 따라 다음과 같은 작업을 수행 할 수 있어야합니다.

TIME = 'date +%s' + 15
while TIME != `date +%s'
do whatever

그리고 while 루프에 플래그를 추가하면 완료하기 전에 시간이 초과되면 실패 이유로 시간 초과를 인용 할 수 있습니다.

텔넷에도 타임 아웃 스위치가 있다고 생각하지만 머리 꼭대기에서 벗어나면 위의 내용이 효과가 있다고 생각합니다.


1

cron에서 실행되고 출력되지 않은 짧은 스크립트가 필요했습니다. nmap을 사용하여 문제를 해결합니다.

open=`nmap -p $PORT $SERVER | grep "$PORT" | grep open`
if [ -z "$open" ]; then
  echo "Connection to $SERVER on port $PORT failed"
  exit 1
else
  echo "Connection to $SERVER on port $PORT succeeded"
  exit 0
fi

실행하려면 nmap이 기본 설치 패키지가 아니므로 설치해야합니다.


nmapgrepable 출력은 -oG -stdout으로 전송하는 데 유용 할 수 있습니다. (grep을 수정하지 조금 필요)
거트 반 베르그 덴

0

이것은 뒤에서 텔넷을 사용하며 mac / linux에서 잘 작동하는 것 같습니다. linux / mac 버전의 차이로 인해 netcat을 사용하지 않으며 기본 mac 설치에서 작동합니다.

예:

$ is_port_open.sh 80 google.com
OPEN

$ is_port_open.sh 8080 google.com
CLOSED

is_port_open.sh

PORT=$1
HOST=$2
TIMEOUT_IN_SEC=${3:-1}
VALUE_IF_OPEN=${4:-"OPEN"}
VALUE_IF_CLOSED=${5:-"CLOSED"}

function eztern()
{
  if [ "$1" == "$2" ]
  then
    echo $3
  else
    echo $4
  fi
}

# cross platform timeout util to support mac mostly
# https://gist.github.com/jaytaylor/6527607
function eztimeout() { perl -e 'alarm shift; exec @ARGV' "$@"; }

function testPort()
{
  OPTS=""

  # find out if port is open using telnet
  # by saving telnet output to temporary file
  # and looking for "Escape character" response
  # from telnet
  FILENAME="/tmp/__port_check_$(uuidgen)"
  RESULT=$(eztimeout $TIMEOUT_IN_SEC telnet $HOST $PORT &> $FILENAME; cat $FILENAME | tail -n1)
  rm -f $FILENAME;
  SUCCESS=$(eztern "$RESULT" "Escape character is '^]'." "$VALUE_IF_OPEN" "$VALUE_IF_CLOSED")

  echo "$SUCCESS"
}

testPort 

0

가장 높은 투표 응답을 바탕으로 두 개의 포트가 열릴 때까지 대기하는 기능과 시간 초과가 있습니다. max_attempts (초당 1 개)뿐만 아니라 8890 및 1111 포트가 열려 있어야합니다.

function wait_for_server_to_boot()
{
    echo "Waiting for server to boot up..."
    attempts=0
    max_attempts=30
    while ( nc 127.0.0.1 8890 < /dev/null || nc 127.0.0.1 1111 < /dev/null )  && [[ $attempts < $max_attempts ]] ; do
        attempts=$((attempts+1))
        sleep 1;
        echo "waiting... (${attempts}/${max_attempts})"
    done
}

-1

아직 사용하지 않는 로컬 포트를 테스트하기위한 nmap-ncat


availabletobindon() {
  port="$1"
  nc -w 2 -i 1 localhost "$port" 2>&1 | grep -v -q 'Idle timeout expired'
  return "$?"
}

포트 80이 열려 있다고 말하지 않습니다.
totoro
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.