포트와 방화벽
리스너 상태와 LISTEN 포트, 바인딩 주소, 클라이언트 포트 도달성과 오류 메시지별 원인, 정적, 동적 서비스 등록, firewalld의 runtime, permanent, rich rule, zone과 진단 순서
#핵심 요약
접속 장애는 "서버 안에서 리스너가 포트를 열지 않음"과 "포트는 열렸지만 클라이언트가 닿지 못함" 두 갈래로 먼저 나눔
서버에서는 lsnrctl status(리스너가 아는 끝점, 서비스)와 ss -tnlp(커널이 보는 LISTEN 소켓)를 함께 봄0.0.0.0:포트는 모든 IPv4 주소, 127.0.0.1:포트는 서버 자신에서만 받음
클라이언트의 telnet, nc는 Connection refused(포트 미대기), timed out(중간 차단), Name or service not known(이름 해석)으로 원인을 가름
firewall-cmd --add-port는 지금만, --permanent는 파일에만 쓰므로 --permanent 뒤 --reload를 한 세트로 씀
#개념과 동작 원리
| 결과 | 볼 곳 |
|---|---|
ss에 LISTEN 없음 |
리스너 미기동, 포트 설정, listener.ora |
127.0.0.1:포트만 보임 |
외부 접속 불가, HOST 바인딩 |
telnet Connected |
네트워크, 포트는 정상, 서비스명, 계정, tnsnames.ora |
Connection refused |
서버에 닿았으나 포트를 받는 프로세스 없음 |
Connection timed out |
방화벽, 보안 그룹, 라우팅 |
Name or service not known |
/etc/hosts, DNS, HOST 이름 |
리스너가 알아야 하는 것은 주소, 포트, 프로토콜(TCP), 서비스 이름임
서비스 등록은 listener.ora의 SID_LIST_LISTENER에 적는 정적 등록과, 인스턴스가 기동 뒤 스스로 리스너에 알리는 동적 등록 두 가지임lsnrctl status의 UNKNOWN은 정적 등록 항목, READY는 동적으로 등록된 인스턴스임
#필수 명령어 또는 SQL
#리스너와 LISTEN 포트 확인
lsnrctl status
lsnrctl services
lsnrctl status LISTENERss -tnlp | grep <PORT>
ss -lntp '( sport = :<PORT> )'
netstat -tnlp | grep <PORT>
ss -tnlp | grep tnslsnr
ps -fp <PID>
readlink -f /proc/<PID>/exe
hostname -I결과 해석:
ss -tnlp의 t는 TCP, n은 숫자 그대로, l은 LISTEN만, p는 프로세스 정보임tnslsnr와 포트가 함께 보이면 리스너 프로세스가 그 포트를 연 것임
netstat은 net-tools 패키지가 있어야 하며, 최신 서버에서는 ss를 먼저 씀
PID로 ps -fp, /proc/<PID>/exe를 보면 어느 계정이 어느 ORACLE_HOME의 리스너를 띄웠는지 알 수 있어, 19c, 21c 홈이 함께 있는 서버에서 혼동을 줄임
리스너가 여러 개면 lsnrctl status LISTENER_TEST처럼 이름을 붙여 각각 포트와 서비스를 확인함
lsnrctl services에서 서비스가 READY면 리스너가 그 DB를 아는 것이고, 서비스가 없으면 동적 등록 실패, local_listener 설정, DB 상태를 봄
#바인딩 주소와 정적, 동적 등록
LISTENER =
(DESCRIPTION_LIST =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = <HOST>)(PORT = <PORT>))
(ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC<PORT>))
)
)
SID_LIST_LISTENER =
(SID_LIST =
(SID_DESC =
(GLOBAL_DBNAME = ORCL2)
(ORACLE_HOME = /u01/app/oracle/product/19.3.0/dbhome_1)
(SID_NAME = ORCL2)
)
)cp listener.ora listener.ora_$(date +%Y%m%d)
vi listener.ora
lsnrctl stop
lsnrctl start
lsnrctl reload LISTENER
grep -n "HOST\|PORT" listener.ora
getent hosts <HOST>결과 해석:
실습은 HOST를 127.0.0.1로 바꿔 외부 접속을 막아 본 뒤 원래대로 되돌림
서버 안에서 localhost 접속이 된다고 외부 접속까지 정상이라고 판단하지 않음
HOST가 호스트명이면 그 이름이 어떤 IP로 해석되는지가 바인딩을 정함
호스트명이 127.0.0.1로 해석되면 리스너가 외부 접속을 받지 못함
SID_LIST_LISTENER 블록을 지우면 동적 등록만 남아, 인스턴스가 기동해 리스너에 알릴 때까지 서비스가 보이지 않음
reload는 리스너를 내리지 않고 설정만 다시 읽고, stop, start는 그사이 새 접속이 실패함
바꾼 뒤에는 ss -tnlp와 lsnrctl status로 실제 반영을 확인함
수업 자료는 서비스 이름이 인스턴스 이름과 같다고 적었으나, 이는 기본 구성의 경우이며 service_names와 PDB 서비스처럼 다를 수 있음
리스너가 stop도 start도 되지 않을 때 실습은 kill -9로 tnslsnr를 끝냈는데, 이는 진행 중인 접속을 모두 끊는 마지막 수단임
#클라이언트에서 포트 도달성 확인
telnet <HOST> <PORT>
nc -zv <HOST> <PORT>
nc -zvw 3 <HOST> <PORT>
getent hosts <HOST>
ping -c 2 <HOST>dism /online /Enable-Feature /FeatureName:TelnetClient결과 해석:
Windows는 기본으로 telnet 클라이언트가 꺼져 있어 dism으로 켜고, Linux 최소 설치에는 yum install -y telnet이 필요함
nc -zv는 데이터를 주고받지 않고 포트가 열렸는지만 보며, -w 3은 최대 3초만 기다림
실습 기록: 다른 수강생 서버의 1521에 Ncat: Connected to ...:1521.
localhost, 서버 IP, 호스트명으로 각각 시험해 루프백, 실제 인터페이스 바인딩, 이름 해석과 라우팅 및 방화벽을 거친 경로를 따로 확인함
Connected인데 SQL*Plus만 실패하면 네트워크가 아니라 서비스명, SID, 계정, tnsnames.ora 쪽을 봄
#firewalld 상태와 규칙 확인
firewall-cmd --state
systemctl is-active firewalld
firewall-cmd --list-all
firewall-cmd --list-ports
firewall-cmd --list-services
firewall-cmd --get-active-zones
firewall-cmd --get-default-zone
firewall-cmd --permanent --list-ports
cat /etc/firewalld/zones/public.xml결과 해석:
not running이면 방화벽은 원인이 아니므로 리스너, 이름 해석, 서비스 등록을 다시 봄
기본 상태의 services: ssh dhcpv6-client, 빈 ports:는 SSH는 되고 리스너 포트는 막힌 상태이며, SSH는 되는데 DB 접속만 안 되는 전형적인 증상임
Oracle 리스너 포트에는 firewalld의 미리 정의된 서비스 이름이 없어 포트 번호로 엶
포트는 인터페이스가 묶인 zone에 열어야 하므로 --get-active-zones로 먼저 확인함
--permanent --list-ports는 메모리가 아니라 /etc/firewalld/zones/*.xml에 저장된 값을 보여 줘 runtime 목록과 다를 수 있음
#포트 열기, 닫기와 대역 제한
firewall-cmd --add-port=<PORT>/tcp
firewall-cmd --reload
firewall-cmd --list-ports
firewall-cmd --permanent --add-port=<PORT>/tcp
firewall-cmd --reload
firewall-cmd --list-ports
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="<CLIENT_NET>/24" port port="<PORT>" protocol="tcp" accept'
firewall-cmd --reload
firewall-cmd --list-rich-rules
firewall-cmd --permanent --remove-port=<PORT>/tcp
firewall-cmd --reload결과 해석:
--permanent 없이 연 포트는 --reload나 재부팅 뒤 사라짐
실습은 열었다가 reload로 사라지는 것을 직접 확인한 뒤 permanent로 다시 엶
rich rule은 허용할 출발지 대역과 포트를 함께 지정해, 애플리케이션 서버 대역에서만 리스너 포트에 접속하게 함
전체 허용 규칙(--add-port)이 남아 있으면 rich rule만으로는 다른 대역을 막지 못하므로 전체 허용 규칙을 지움
수업은 포트 번호를 물어 숫자인지 검사한 뒤 --permanent --add-port, --remove-port와 --reload를 실행하는 addport.sh, removeport.sh를 만들어 점검 메뉴 스크립트에 붙임
#방화벽이 원인인지 가르기
systemctl stop firewalld
firewall-cmd --state
systemctl start firewalldiptables -L -n --line-numbers결과 해석:
방화벽을 잠시 멈춘 상태에서 접속되면 원인이 방화벽으로 확정되지만, 확인이 끝나면 반드시 다시 켜고 포트를 바르게 여는 방식으로 해결함
실제로 패킷을 거르는 것은 커널의 iptables, nftables이고 firewalld는 그 규칙을 관리함
INPUT 체인은 위에서부터 적용되며 마지막 REJECT가 나머지를 막음
firewalld를 쓰는 서버에서 iptables -I로 직접 넣은 규칙은 firewalld reload나 재부팅 때 사라질 수 있어 firewalld 명령으로만 관리함
#DB 접속 IP 제한 (sqlnet.ora)
TCP.VALIDNODE_CHECKING = YES
TCP.INVITED_NODES = (<SERVER_IP>, <CLIENT_IP>)결과 해석:
방화벽과 별도로 리스너 단계에서 등록한 IP만 접속을 받게 하는 설정이며, 실습은 서버 자신과 Windows PC 주소를 넣은 뒤 리스너를 다시 올림
서버 자신의 IP를 빼면 서버 안에서 IP로 접속하는 것도 막히므로 함께 넣음
#사용 조건과 주의사항
리스너 stop, kill, 방화벽 중지, listener.ora HOST, PORT 변경은 운영 접속을 끊으므로 작업 시간을 정하고 하며, 변경 뒤 ss, lsnrctl status, 클라이언트 nc로 다시 확인함
포트 번호를 바꾸면 listener.ora, 클라이언트 tnsnames.ora, 방화벽 규칙을 모두 같은 값으로 맞춰야 함
firewall-cmd --list-ports만으로 모든 허용, 차단 조건을 판단하지 않으며, 서버 밖의 네트워크 장비, 보안 그룹도 원인이 될 수 있음