/dev/tcp 설명 및 사용 방법

Bash의 /dev/tcp 기능을 포트 확인, HTTP 요청, SSH 포워딩과의 차이, nc/curl 비교 기준으로 정리했습니다. 파일시스템 오해와 timeout 없는 점검 위험도 함께 다룹니다.

/dev/tcp는 실제 디스크에 존재하는 장치 파일이 아니라 Bash가 리다이렉션을 처리할 때 특별히 해석하는 네트워크 기능입니다. 그래서 ls /dev/tcp로 확인되지 않아도 Bash에서 > /dev/tcp/host/port 형태로 쓰면 TCP 연결을 시도할 수 있습니다. POSIX sh의 표준 기능은 아니므로 스크립트에서 사용할 때는 반드시 실행 셸을 bash로 고정해야 합니다.

동작 방식

형식은 다음처럼 단순합니다. 호스트에는 IP 주소나 DNS 이름을 넣고, 포트에는 TCP 포트 번호를 넣습니다.

/dev/tcp/<host>/<port>

Bash는 이 경로를 파일로 여는 대신 내부에서 소켓 연결을 생성합니다. 연결이 성공하면 리다이렉션 대상이 열린 것으로 간주되고, 실패하면 명령 전체가 실패 상태를 반환합니다. 이 특성 때문에 아주 가벼운 포트 확인, HTTP 요청 테스트, 임시 TCP 송신에 사용할 수 있습니다.

먼저 Bash에서 실행되는지 확인

/dev/tcp 예제를 그대로 복사했는데 동작하지 않는 경우 대부분은 dash, sh, 제한된 셸, 혹은 오래된 BusyBox 환경에서 실행했기 때문입니다.

echo "$SHELL"
bash --version

# 스크립트라면 shebang을 명시합니다.
#!/usr/bin/env bash

Ubuntu에서 /bin/sh는 보통 dash를 가리킵니다. 따라서 크론이나 자동화에서 사용할 때는 sh script.sh가 아니라 bash script.sh로 실행해야 합니다.

포트가 열려 있는지 빠르게 확인

가장 단순한 사용법은 특정 포트로 TCP 연결이 되는지 확인하는 것입니다. 연결 성공 여부만 필요하다면 다음처럼 사용할 수 있습니다.

host="www.example.com"
port="80"

if timeout 3 bash -c "cat < /dev/null > /dev/tcp/${host}/${port}"; then
 echo "${host}:${port} 연결 성공"
else
 echo "${host}:${port} 연결 실패"
fi

timeout을 붙이는 이유는 방화벽에서 패킷을 드롭하는 경우 명령이 오래 멈출 수 있기 때문입니다. 운영 점검 스크립트에서는 반드시 제한 시간을 둬야 합니다.

HTTP 요청을 직접 보내기

HTTP는 텍스트 기반 프로토콜이므로 요청 줄과 헤더를 직접 써서 응답을 확인할 수 있습니다. 단순한 연결 확인을 넘어 “TCP는 열렸는데 HTTP 응답이 정상인가”까지 볼 때 유용합니다.

exec 3<>/dev/tcp/www.example.com/80
printf 'GET / HTTP/1.1\r\nHost: www.example.com\r\nConnection: close\r\n\r\n' >&3
cat <&3
exec 3<&-
exec 3>&-

여기서는 파일 디스크립터 3번을 열어서 요청을 보내고 응답을 읽습니다. 한 줄짜리 echo보다 구조가 분명하고, 요청과 응답의 방향이 분리되어 디버깅하기 쉽습니다.

SSH 포트 포워딩과는 역할이 다릅니다

예시에 있던 ssh -L 1234:/dev/tcp/www.example.com/80 형태는 SSH 로컬 포워딩의 대상 문법과 맞지 않습니다. SSH의 -L은 로컬 포트, 목적지 호스트, 목적지 포트를 직접 지정합니다. 이때 /dev/tcp를 끼워 넣지 않습니다.

ssh -L 127.0.0.1:1234:www.example.com:80 user@ssh-gateway.example.com

위 명령은 로컬 127.0.0.1:1234로 들어온 연결을 SSH 게이트웨이를 통해 www.example.com:80으로 전달합니다. /dev/tcp는 간단한 TCP 송수신 도구이고, SSH 터널은 암호화된 포워딩 기능이므로 서로 대체 관계가 아닙니다.

파일 전송에 사용할 때의 주의점

cat file.txt > /dev/tcp/host/port는 “파일을 보낸다”라기보다 지정한 TCP 포트로 바이트를 밀어 넣는 동작입니다. 상대편에서 해당 데이터를 받아 저장하는 서버가 떠 있지 않으면 파일 전송은 성립하지 않습니다.

# 수신 측 예시: 임시 랩에서만 사용
nc -l -p 1234 > received.txt

# 송신 측 예시
cat file.txt > /dev/tcp/receiver.example.com/1234

실제 파일 전송은 scp, sftp, rsync처럼 인증, 무결성, 재시도, 권한 처리가 있는 도구를 사용하는 것이 맞습니다. /dev/tcp 방식은 학습이나 폐쇄된 랩에서 TCP 흐름을 이해할 때만 사용하세요.

nc, curl과 비교

/dev/tcp의 장점은 별도 패키지가 없어도 Bash만 있으면 매우 작은 테스트를 만들 수 있다는 점입니다. 반대로 응답 파싱, TLS, 프록시, 재시도, 상세 오류 처리는 약합니다.

# TCP 포트 확인에는 nc가 더 읽기 쉽습니다.
nc -vz -w 3 www.example.com 80

# HTTP/HTTPS 점검에는 curl이 더 적합합니다.
curl -I --connect-timeout 3 https://www.example.com/

정리하면 /dev/tcp는 “Bash만 있는 환경에서 TCP 연결을 아주 가볍게 확인하는 방법”으로 이해하면 됩니다. 정식 모니터링, HTTPS 검사, 파일 전송, 운영 자동화의 장기 유지보수에는 목적에 맞는 전용 도구를 쓰는 편이 더 안전합니다.

BGM EVER