개요 — 무엇을 하나
포트 연결(Port Connections) 은 Infrastructure ▸ Connectivity & Traffic 의 플래그십 화면인 PORT OVERVIEW 다. 운영 정책에 등록된 감시 포트(예: 80·443·22·3306 …)마다 카드를 하나씩 띄우고, 각 카드 안에서 서버별로 그 포트에 붙은 TCP 세션을 상태별로 100% 스택바로 쪼개 보여줍니다. "지금 이 포트에 누가·얼마나·어떤 상태로 붙어 있는가"를 한 화면에서 훑는 것이 목적입니다.
원천은 레거시 트래픽 DB(legacy_glory 커넥션)의 traffic_session_ct 스냅샷 테이블이며, 수집기 check_ct.js 가 주기적으로 세션 스냅샷을 적재합니다. 앱은 읽기 전용입니다 — 이 화면은 아무것도 쓰지 않습니다.
각 서버 타일은 다음을 보여줍니다.
- TCP 상태 100% 스택바 — ESTABLISHED / LISTEN / SYN SENT / SYN RECV / FIN WAIT / CLOSE WAIT / TIME WAIT 비율(그 외는
기타). ESTABLISHED 를 항상 왼쪽에 배치하고 나머지는 세션 수 내림차순. - SRC 서클 — 그 서버·포트에 붙은 서로 다른 소스 IP 개수(distinct
remote_ip). 클릭하면 소스 IP 목록 팝업이 열립니다. - 상위 3 소스 IP — 세션 수가 많은 순서로 상위 3개 원격 IP 와 세션 수.
언제 쓰나
- 연결 급증·이상 상태 파악: 특정 포트에 SYN_RECV(반쯤 열린 연결)나 TIME_WAIT 가 비정상적으로 몰리면 SYN 플러드·연결 폭주·앱 커넥션 누수를 의심.
- 어느 서버가 부하를 받나: 같은 포트라도 서버별 세션 분포가 다릅니다 — 로드밸런싱 편중, 특정 노드 과부하 확인.
- 의심 소스 추적: 상위 소스 IP 또는 SRC 서클에서 특정 IP 를 눌러 어느 서버·포트에·얼마나 붙었는지, 지오/ASN, 기간 이력을 조사하고 필요하면 평판 조회·차단으로 넘어갑니다.
- 서비스 딥링크 진입: 다른 화면(서비스 ▸ 웹 등)에서
?src_ip=…&port=…로 넘어오면 해당 포트로 자동 필터되고 IP 조사 팝업이 바로 열립니다.
화면 구성
상단 컨트롤
| 요소 | 동작 |
|---|---|
| 타이머 1분 / 5분 / 1시간 | 세션 집계 창(window) 폭. 선택은 localStorage(infr:timer:traffic-ports)에 영속되어 다음 방문에도 유지. |
| 포트 칩 | 감시 포트 목록(운영 정책). 칩을 눌러 카드를 켜고 끕니다. 전체 토글로 전부 선택/해제. 필터는 이번 세션에만 적용(영속 안 함) — 다음 방문 기본은 항상 전체. |
| 스냅샷 시각 | 현재 창의 기준이 된 최신 스냅샷 시각(표시 시간대 보정 적용). |
| 새로고침 / 폴링 | 30초마다 자동으로 /infra/traffic/ports/live 를 폴링해 카드를 갱신. |
포트 카드 (masonry)
카드는 드래그로 순서 변경이 가능하고 그 순서는 localStorage(infr:order:traffic-ports)에 저장됩니다. 카드 높이가 제각각이라 row-span masonry(sortable_masonry 믹스인)로 빈틈 없이 배치됩니다. 한 카드 안의 서버 타일은 소스 IP 수 많은 순 → 총 세션 순 → 서버 인덱스 순으로 정렬됩니다.
TCP 상태 레전드
스택바의 색은 상태 의미별 CSS 토큰(var(--infr-state-*))입니다. 레전드가 색↔상태 매핑을 안내합니다.
| 토큰 | 표시 | 의미 |
|---|---|---|
established |
ESTABLISHED | 정상 수립된 연결 |
listen |
LISTEN | 수신 대기(서버 소켓) |
syn_sent |
SYN SENT | 연결 시도(클라이언트) |
syn_recv |
SYN RECV | SYN 수신·반쯤 열림 — 급증 시 SYN 플러드 의심 |
fin_wait |
FIN WAIT | 종료 진행(FIN_WAIT1/2 통합) |
close_wait |
CLOSE WAIT | 상대가 닫음·앱이 미종료 — 누적 시 커넥션 누수 |
time_wait |
TIME WAIT | 종료 후 대기 |
other |
기타 | 위 7종 외 상태 |
사용법
- 타이머 선택 — 좁게 보려면
1분(가장 최신 스냅샷 배치), 완만한 추세는5분·1시간. - 포트 칩으로 관심 포트만 남기기 — 예: 웹만 보려면 80·443 만 켭니다.
- 스택바 읽기 — ESTABLISHED 비중이 낮고 SYN_RECV/TIME_WAIT 가 크면 이상 신호.
- SRC 서클 클릭 — 그 서버·포트의 소스 IP 목록 팝업(원격 IP·원격 포트·세션·최초/최종 관측)이 열립니다.
- IP 클릭 → 단일 IP 조사 — 그 IP 가 어느 서버·포트에·어떤 상태로 붙는지 분해, 지오/ASN, 기간 이력(5분·시간별·일별 롤업)을 확인. 여기서 평판 조회·차단으로 이어집니다.
- 카드 재정렬 — 자주 보는 포트를 위로 드래그하면 순서가 저장됩니다.
일별(
1day) 이력은 롤업 특성상 개별 IP 가 아니라 그 IP 의 /24 대역(256 IP) 기준으로 집계됩니다. 팝업에211.224.128.0/24 기준같은 CIDR 라벨이 붙으면 이는 대역 전체의 합이라는 뜻입니다.
데이터 소스
모든 쿼리는 legacy_glory 커넥션에서 실행되며 파라미터 바인딩된 쿼리빌더로 App\Repositories\TrafficRepository 에 격리되어 있습니다(문자열 보간 금지).
창(window) 앵커링
표시 창은 앱의 now() 가 아니라 데이터의 최신 스냅샷(MAX(snapshot_ts))을 기준으로 잡습니다. 수집기 저장 시계와 앱 시계가 몇 시간씩 어긋날 수 있어, now() 로 창을 잡으면 데이터를 벗어나 빈 화면이 되기 때문입니다.
| 타이머 | SQL 경계(snapshot_ts) |
|---|---|
| 1분 | 최신 스냅샷 분의 startOfMinute ~ endOfMinute |
| 5분 | 최신 스냅샷 − 4분의 startOfMinute ~ 최신 endOfMinute |
| 1시간 | 최신 스냅샷 − 59분의 startOfMinute ~ 최신 endOfMinute |
snapshot_ts의 WHERE 경계는 레거시 저장 시각을 그대로 씁니다. 화면에 보이는 스냅샷 시각만 운영 정책의 표시 시간대 보정(traffic_tz_offset_hours)이 더해져 표시됩니다.
핵심 쿼리 — portOverview()
SELECT a.local_port, a.server_name, a.server_index, a.remote_ip,
a.state_code, b.state_name,
SUM(a.session_count) AS total_sessions
FROM traffic_session_ct AS a
LEFT JOIN protocol_state AS b ON a.state_code = b.state_code
WHERE a.snapshot_ts BETWEEN :min AND :max
AND a.local_port IN (:ports) -- 운영 정책 감시 포트
GROUP BY a.local_port, a.server_name, a.server_index,
a.remote_ip, a.state_code, b.state_name;
traffic_session_ct⋈protocol_state— 상태 코드(int)를 사람이 읽는 상태명으로 변환해 레전드·스택바에 씁니다.snapshot_ts BETWEEN좁은 창 +local_port IN화이트리스트로 대용량 스냅샷 테이블(≈605K행)을 좁힙니다.
관련 테이블
| 테이블 | 커넥션 | 역할 | 공급 |
|---|---|---|---|
traffic_session_ct |
legacy_glory | 세션 스냅샷(host/remote/state/count) | check_ct.js |
protocol_state |
legacy_glory | TCP state 코드 → 상태명 룩업 | — |
traffic_session_ct_5min/_1hour/_1day |
legacy_glory | IP 조사 팝업의 기간 이력 롤업 | aggregate.js |
ip_info_loop |
legacy_glory | IP 조사 팝업의 지오/ASN/ISP 인리치 | — |
서버 응답 형태(요약)
{
"ports": [80, 443, 22],
"timer": 1,
"snapshot": "2026-08-13 10:24:00",
"ports_data": [
{ "port": 443, "server_data": [
{ "alias": "web1", "idx": 12, "host_count": 84,
"top_req": [ { "remote_ip": "203.0.113.10", "session_count": 61 } ],
"connections": [ { "state": "established", "count": 420, "pct": 78 } ],
"total": 538 }
] }
]
}
portsData() 는 20초 캐시(타이머 + 포트 목록 해시별)로 원격 왕복을 억제합니다.
권한
Infrastructure 역할 영역은 최소 user_level 1(뷰어)로 열람 가능합니다. 포트 연결 화면은 읽기 전용이라 별도 쓰기 게이트가 없습니다 — 데모(1)·스태프(5)·관리자(10) 모두 조회할 수 있습니다. 라우트는 infr.auth 세션 인증만 요구합니다.
| 작업 | 필요 레벨 |
|---|---|
| 포트 연결 조회·폴링·IP 조사 팝업 | 1 (인증된 모든 사용자) |
| 감시 포트 목록 편집(운영 정책) | 10 (Administration) — 운영 정책 |
IP 조사 팝업에서 이어지는 차단은 Security ▸ 차단 목록으로 넘어가며 그쪽은 쓰기
user_level2 이상 + 감사 로그를 요구합니다. 이 화면 자체는 차단을 수행하지 않습니다.
문제해결 · FAQ
카드는 뜨는데 서버 데이터가 비어 있어요.
해당 창에 그 포트로 붙은 세션이 없다는 뜻입니다. 타이머를 5분/1시간으로 넓히거나, 실제로 그 포트가 열려 트래픽이 있는지 확인합니다.
모든 카드가 비어 있고 "연결 스냅샷이 없습니다"가 떠요.
legacy_glory 의 traffic_session_ct 에 최근 스냅샷이 없습니다(수집기 check_ct.js 중단 또는 DB 연결 실패). 최신 스냅샷 시각이 표시되지 않으면 수집기 상태를 점검합니다.
포트가 안 보여요.
감시 포트 목록(infra_monitored_ports)에 없으면 카드가 생성되지 않습니다. Administration ▸ 운영 정책에서 CSV 로 추가합니다(1~65535, 최대 30개, 입력 순서 보존). 기본값:
infra_monitored_ports = 80,443,22,3306,25,465,27017,21,53,3030,8080,6379,6001
스냅샷 시각이 실제 시각과 몇 시간 달라요.
레거시 DB 저장 시계와 표시 시간대가 다르면 운영 정책의 traffic_tz_offset_hours(±14h)로 표시 시각을 보정합니다. 쿼리 경계에는 적용되지 않고 표시에만 반영됩니다.
일별 이력이 비어 있어요.
_1day 롤업은 하루 지연될 수 있고 /24 대역 기준으로 집계됩니다. 5분·시간별 grain 으로 확인합니다.
관련 항목
- IP 연결 (host view) — 서버별 원격 peer IP × 포트 강도
- 트래픽 (network I/O) — server_traffic 인/아웃 바이트·패킷 시계열
- 운영 정책 — 감시 포트 목록·시간대 보정 설정
- IP 평판 조회 — 조사 팝업에서 AbuseIPDB 평판
- 방화벽 (공격면) — 물리 포트 오픈/노출 관제
- 차단 목록 & 평판 — 조사 팝업에서 이어지는 IP 차단
