데이터베이스 연구실.log

포트와 방화벽

리스너 상태와 LISTEN 포트, 바인딩 주소, 클라이언트 포트 도달성과 오류 메시지별 원인, 정적, 동적 서비스 등록, firewalld의 runtime, permanent, rich rule, zone과 진단 순서

lsnrctlsstelnetncfirewall-cmdrich rule정적 등록TCP.VALIDNODE_CHECKING

#핵심 요약

접속 장애는 "서버 안에서 리스너가 포트를 열지 않음"과 "포트는 열렸지만 클라이언트가 닿지 못함" 두 갈래로 먼저 나눔

서버에서는 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 포트 확인

Linux Bash (oracle)조회만 함
lsnrctl status
lsnrctl services
lsnrctl status LISTENER
root 셸조회만 함
ss -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 상태를 봄

#바인딩 주소와 정적, 동적 등록

파일 ($ORACLE_HOME/network/admin/listener.ora, 정적 등록)객체 또는 설정을 변경함
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)
    )
  )
Linux Bash (oracle, $ORACLE_HOME/network/admin)인스턴스 또는 서비스 중단이 필요함
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>
Windows 관리자 명령 프롬프트객체 또는 설정을 변경함
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 상태와 규칙 확인

root 셸조회만 함
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 목록과 다를 수 있음

#포트 열기, 닫기와 대역 제한

root 셸객체 또는 설정을 변경함
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를 만들어 점검 메뉴 스크립트에 붙임

#방화벽이 원인인지 가르기

root 셸인스턴스 또는 서비스 중단이 필요함
systemctl stop firewalld
firewall-cmd --state
systemctl start firewalld
root 셸조회만 함
iptables -L -n --line-numbers

결과 해석:

방화벽을 잠시 멈춘 상태에서 접속되면 원인이 방화벽으로 확정되지만, 확인이 끝나면 반드시 다시 켜고 포트를 바르게 여는 방식으로 해결함

실제로 패킷을 거르는 것은 커널의 iptables, nftables이고 firewalld는 그 규칙을 관리함
INPUT 체인은 위에서부터 적용되며 마지막 REJECT가 나머지를 막음

firewalld를 쓰는 서버에서 iptables -I로 직접 넣은 규칙은 firewalld reload나 재부팅 때 사라질 수 있어 firewalld 명령으로만 관리함

#DB 접속 IP 제한 (sqlnet.ora)

파일 ($ORACLE_HOME/network/admin/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만으로 모든 허용, 차단 조건을 판단하지 않으며, 서버 밖의 네트워크 장비, 보안 그룹도 원인이 될 수 있음

SEO_HKabsumveritas@gmail.comBuilt with Claude Code & Codex

마지막 갱신 개인 학습 기록이며 운영 환경 적용 전 공식 문서 확인 필요

두 글자 이상 입력, 위아래 화살표로 이동하고 Enter로 열기