Diagnosing Sockets and Ports
한국어 원문으로 표시합니다.
목표
리스닝 소켓의 바인딩 범위를 구분하고, ss 와 /proc/net/tcp 두 경로로 같은 사실을 확인합니다.
왜 중요한가
"서버 안에서 curl 은 되는데 밖에서는 안 된다"는 신고의 대부분은 방화벽이 아니라 바인딩 문제입니다. 127.0.0.1:8080 에 묶인 소켓은 같은 호스트에서 온 연결만 받고, 외부 패킷은 커널이 아예 전달하지 않습니다. 이 구분은 보안 설계이기도 합니다 - 관리용 포트를 일부러 루프백에만 묶는 것이 표준 관행입니다. 그리고 리스닝 소켓의 Send-Q 는 백로그 최대치, Recv-Q 는 accept 대기 큐의 현재 길이입니다. 확립된 연결에서의 뜻과 다르기 때문에 자주 오독됩니다.
단계
/root/net 디렉터리에서 작업합니다.
python3 -m http.server 8080 --bind 127.0.0.1을 백그라운드로 띄우고 PID 를/root/net/http_pid.txt에 적으세요.python3 -m http.server 8081 --bind 0.0.0.0을 백그라운드로 띄우고 PID 를/root/net/all_pid.txt에 적으세요. 8080 은 그대로 루프백 전용이어야 합니다.- 두 포트의 바인딩 범위를
/root/net/binding.txt에 다음 두 줄로 적으세요. 값은loopback또는all입니다.8080=<값>8081=<값>
- 8081 로 연결을 하나 열어 닫지 않고 유지하는 프로세스를 띄우고 PID 를
/root/net/client_pid.txt에 적으세요. - 10진수 8080 을 16진수 4자리 대문자로 바꿔
/root/net/hexport.txt에 적으세요. - 8080 리스닝 소켓의 백로그 최대치를
/root/net/backlog.txt에 숫자만 적으세요. - 8080 을 잡고 있는 프로세스의 PID 를
ss로 확인해/root/net/owner.txt에 적으세요. /root/net/portcheck.sh <포트>를 만드세요. 그 포트에서 듣고 있으면port=<포트> state=listen pid=<PID>를 출력하고 종료 코드 0, 아무도 안 들으면port=<포트> state=free를 출력하고 종료 코드 1. 인자가 없으면 0이 아닌 코드입니다.
참고
ss -ltnH는 헤더 없이 리스닝 TCP 소켓만 보여 줍니다. 열 순서는Recv-Q Send-Q Local Peer입니다./proc/net/tcp의local_address는IP:PORT가 모두 16진수이고 상태0A가 LISTEN 입니다.python3 -c "import socket,time; s=socket.create_connection(('127.0.0.1',8081)); time.sleep(9999)" &로 연결을 붙잡을 수 있습니다.- 흔한 실수 1: 4번에서 연결을 열자마자 닫으면 ESTABLISHED 가 사라집니다.
- 흔한 실수 2: 7번에서
-p없이ss -ltn만 쓰면 프로세스 정보가 안 나옵니다.
루프백에만 묶어 서버 띄우기
python3 -m http.server 8080 --bind 127.0.0.1 을 백그라운드로 띄우고 PID 를 /root/net/http_pid.txt 에 적으세요.
python3 -m http.server 에 --bind 옵션이 있습니다. 백그라운드로 띄우고 PID 를 적으세요.
모든 주소에 묶어 띄우기
python3 -m http.server 8081 --bind 0.0.0.0 을 백그라운드로 띄우고 PID 를 /root/net/all_pid.txt 에 적으세요. 8080 은 그대로 루프백 전용이어야 합니다.
0.0.0.0 에 묶으면 어느 인터페이스로 와도 받습니다. 8080 은 그대로 루프백이어야 합니다.
바인딩 범위 기록하기
두 포트의 바인딩 범위를 /root/net/binding.txt 에 다음 두 줄로 적으세요. 값은 loopback 또는 all 입니다.
8080=<값>8081=<값>
ss -ltn 의 Local Address 열을 보세요. 두 포트가 어떻게 다른지 적습니다.
연결 붙잡아 두기
8081 로 연결을 하나 열어 닫지 않고 유지하는 프로세스를 띄우고 PID 를 /root/net/client_pid.txt 에 적으세요.
연결을 열고 닫지 않은 채 유지해야 합니다. python3 로 create_connection 후 sleep 하면 됩니다.
/proc/net/tcp 직접 읽기
10진수 8080 을 16진수 4자리 대문자로 바꿔 /root/net/hexport.txt 에 적으세요.
포트가 16진수로 적혀 있습니다. 8080 을 16진수 4자리 대문자로 바꿔 보세요.
백로그 최대치 읽기
8080 리스닝 소켓의 백로그 최대치를 /root/net/backlog.txt 에 숫자만 적으세요.
리스닝 소켓에서는 Send-Q 가 백로그 최대치입니다. ss -ltn 의 두 번째 열입니다.
포트의 주인 찾기
8080 을 잡고 있는 프로세스의 PID 를 ss 로 확인해 /root/net/owner.txt 에 적으세요.
ss 에 프로세스 정보를 보여 주는 옵션이 있습니다. 출력에서 pid= 부분을 뽑으세요.
포트 점유 확인 스크립트
/root/net/portcheck.sh <포트> 를 만드세요. 그 포트에서 듣고 있으면 port=<포트> state=listen pid=<PID> 를 출력하고 종료 코드 0, 아무도 안 들으면 port=<포트> state=free 를 출력하고 종료 코드 1. 인자가 없으면 0이 아닌 코드입니다.
듣고 있으면 pid 까지 알려 주고 0, 비어 있으면 free 와 1 을 냅니다.