개요 — 무엇을 하나
IP 연결은 Infrastructure ▸ Connectivity & Traffic 의 두 번째 화면(host view)입니다. 포트 연결이 "포트 → 서버"를 축으로 보는 반면, 이 화면은 **"서버(호스트) → 원격 peer IP"**를 축으로 봅니다. 각 서버 카드는 그 서버에 붙어 있는 원격 IP들을 연결 강도순으로 나열하고, IP마다 감시 포트별 세션 강도 도트를 보여줍니다. 어느 IP가 어떤 서버의 어떤 포트로 얼마나 붙는지를 한눈에 파악하는 것이 목적입니다.
peer IP를 클릭하면 공용 IP 조사(investigation) 팝업이 열려, 그 IP의 접속 분포(어느 서버·포트·TCP 상태·세션 수), 기간 연결 이력 스파크라인, 지오/ASN/ISP 인리치, 외부 평판 링크, 그리고 차단 목록으로 넘어가는 차단 딥링크까지 한 곳에서 조사할 수 있습니다.
- 라우트:
/infra/traffic/ips(페이지) ·/infra/traffic/ips/live(폴링 JSON) ·/infra/traffic/ip-detail(조사 팝업 JSON) - 컨트롤러:
App\Http\Controllers\Infra\TrafficController@ips - 빌더:
App\Services\Traffic\SessionQueryService::ipsData()+ipDetail() - 원천 쿼리:
App\Repositories\TrafficRepository(레거시legacy_glory커넥션, 읽기 전용) - 원천 테이블:
traffic_session_ct(+ 롤업traffic_session_ct_5min/_1hour/_1day, 인리치ip_info_loop)
모든 데이터는 레거시 트래픽 DB(
legacy_glory)를 읽기 전용으로 조회합니다. 이 화면 자체는 아무것도 쓰지 않습니다 — 차단 같은 쓰기 동작은 팝업의 딥링크로 차단 목록 화면에 넘겨 거기서 수행합니다.
언제 쓰나
- 특정 서버에 비정상적으로 많은 원격 peer가 붙는지 확인할 때(스캔·봇넷·크롤러 폭주).
- 한 IP가 여러 서버·포트에 동시에 붙는 횡적 확산 패턴을 잡아낼 때.
- IDS/방화벽 경보에서 나온 IP를 트래픽 관점에서 역추적할 때(어느 서버·포트·상태로 실제 세션이 있었나).
- 차단 결정 전 그 IP의 접속 규모·기간 이력·지오/평판을 확인할 때.
- 포트 연결의 SRC 서클에서 넘어온 소스 IP를 개별 심층 조사할 때.
화면 구성
히어로 · timer
우상단에 표시 창을 정하는 **timer 토글(1분 / 5분 / 1시간)**과 최신 스냅샷 시각, 수동 새로고침 버튼이 있습니다. timer는 최신 스냅샷을 앵커로 한 조회 창의 길이입니다.
| timer | 조회 창 |
|---|---|
1 (기본) |
최신 스냅샷 분 1개 |
5 |
최신 스냅샷 기준 최근 5분 |
60 |
최신 스냅샷 기준 최근 60분 |
선택한 timer는 localStorage['infr:timer:traffic-ips']에 저장돼 다음 방문에도 유지됩니다. 허용값은 1/5/60뿐이며 그 외 입력은 1로 보정됩니다.
연결 강도 레전드 + 서버 칩
- 연결 강도 레전드: 도트 색이 포트당 세션 수 버킷을 뜻합니다 —
1–9(good) ·10–49(warn) ·50+(crit). - 서버 칩: 표시할 서버(호스트)를 고르는 필터. 기본은 전체 선택이며, 칩 필터는 세션 한정(localStorage에 영속하지 않음)이라 다음 방문 시 다시 전체로 돌아옵니다.
[전체]칩으로 전체 선택/해제를 토글합니다.
서버(호스트) 카드
선택된 서버마다 카드 하나. 카드 헤더에 호스트명과 peer 수가 있고, 본문은 표 형태입니다.
- 행(peer) = 원격 IP 하나. 열:
원격 IP·합계(총 세션) · 그다음 감시 포트별 강도 도트(감시 포트 앞 8개). - peer는 총 연결(세션) 수 내림차순으로 정렬되며, 서버당 최대 100개 peer까지 표시됩니다.
- 강도 도트는 그 peer가 해당 포트로 가진 세션 수를 색으로 표현합니다(아래 표).
- 행을 클릭하면 그 IP의 조사 팝업이 열립니다.
카드는 드래그 그립으로 순서를 바꿀 수 있고(순서는 infr:order:traffic-ips에 영속), row-span masonry로 재배치되며 20개 단위로 페이지네이션됩니다.
포트 강도 도트 색
| 세션 수 | 토큰 | 색 | 의미 |
|---|---|---|---|
0 |
none | 흐림 | 이 포트로 붙지 않음 |
1–9 |
good | 녹색 | 낮은 강도 |
10–49 |
warn | 황색 | 중간 강도 |
50+ |
crit | 적색 | 높은 강도 |
IP 조사 팝업
공용 믹스인 mixins/ip_detail.js + 파셜 infra/partials/ip-detail-modal.blade.php로 구동됩니다. 두 모드가 있습니다.
- sources 모드 — (서버, 포트) 창에 붙은 소스 IP 목록. 포트 연결의 SRC 서클에서 진입합니다.
- investigate 모드(이 화면의 기본 진입) — 단일 IP 심층 조사. peer 행 클릭으로 진입합니다.
investigate 모드가 보여주는 것:
| 영역 | 내용 | 원천 |
|---|---|---|
| 요약 KPI | 총 세션 · 서버 수 · 포트 수 · 최초/최종 관측 | ipSeenSpan()(전체 보존창 MIN/MAX(created_at)) |
| 지오 | 국가·도시·ASN·ISP | ip_info_loop (ipEnrichment()) |
| 연결 이력 | grain(5분/시간별/일별) 스파크라인 | 롤업 테이블(ipHistory()) |
| 접속 분포 | 서버 × 포트 × TCP 상태별 세션·원격포트·최초/최종 | traffic_session_ct (ipBreakdown()) |
팝업 하단 액션(investigate): IP 복사 · IP 조회(이 페이지에서 ?src_ip=로 재조사) · 평판 ↗(외부 AbuseIPDB 새 탭) · IP 차단(차단 목록으로 ?add= 딥링크).
팝업의 평판 ↗ 버튼은 외부
abuseipdb.com/check/…링크를 새 탭으로 여는 단순 링큽니다. 화면 안에서 신뢰도 게이지·신고 내역을 보여주는 인앱 평판 팝업은 보안 화면 전용 기능입니다 — IP 평판 조회 참고.
사용법
기본 흐름
- timer로 창(1/5/60분)을 정합니다. 짧을수록 "지금 붙어 있는" 것에 가깝습니다.
- 서버 칩으로 관심 서버만 남깁니다(기본 전체).
- 서버 카드에서 강도 도트가 붉은 peer(50+ 세션)나 여러 포트에 걸친 peer를 찾습니다.
- 의심 peer 행을 클릭해 조사 팝업을 엽니다.
- 팝업에서 접속 분포로 어느 서버·포트·상태에 붙었는지, 연결 이력으로 지속성(일회성 vs 반복)을, 지오/ASN으로 출신을 확인합니다.
- 필요하면 **평판 ↗**로 외부 신고 이력을 보고, 악성이면 IP 차단으로 차단 목록에 넘깁니다.
연결 이력 grain 전환
팝업의 이력 섹션에서 grain을 전환하면 롤업 테이블이 바뀝니다. 기본 grain은 시간별(1hour) — 밀도와 속도의 균형이 좋습니다.
5분(5min) → traffic_session_ct_5min · 개별 IP · 최신 스냅샷 −6h 창
시간별(1hour)→ traffic_session_ct_1hour · 개별 IP · 최신 스냅샷 −3d 창 (기본)
일별(1day) → traffic_session_ct_1day · /24 대역 · 최신 스냅샷 −120d 창
일별(
1day) 이력은 개별 IP가 아니라 그 IP의 /24 대역(앞 3옥텟, 256개 IP) 기준으로 집계됩니다. 롤업 수집기가_1day를 C클래스로 저장하기 때문입니다. 팝업은 이때211.224.128.0/24같은 CIDR 스코프 라벨을 함께 띄워 범위를 명시합니다. 5분·시간별은 개별 IP 그대로입니다.
딥링크
?src_ip=203.0.113.10— 페이지 로드 시 그 IP의 조사 팝업을 자동으로 엽니다(다른 화면·경보에서 넘어올 때).?alias=…/?servers=…/?server=…— 서버 칩 필터를 사전 적용합니다(콤마·공백 구분, 대소문자 무시 매칭). 이번 방문에만 적용되고 영속하지 않습니다.
/infra/traffic/ips?src_ip=203.0.113.10
/infra/traffic/ips?servers=glory,blue
폴링
페이지는 30초마다 /infra/traffic/ips/live를 폴링해 자동 갱신합니다(Reverb 아님 — 수집기가 Laravel 밖에서 DB에 직접 쓰므로 폴링이 합리적). 갱신 시 전체선택이었다면 새로 나타난 서버도 자동 포함하고, 사라진 서버는 선택에서 제거합니다.
데이터 소스
조회 창 앵커링
표시 창은 앱의 now()가 아니라 데이터의 최신 스냅샷(MAX(snapshot_ts))을 앵커로 잡습니다. 수집기의 저장 시계와 앱 시계가 최대 ~9시간까지 어긋날 수 있어, now() 기준이면 좁은 창이 데이터를 벗어나 빈 화면이 되기 때문입니다.
host view 쿼리 (ipPeers)
-- TrafficRepository::ipPeers (파라미터 바인딩)
SELECT server_name, remote_ip, local_port, SUM(session_count) AS total_sessions
FROM traffic_session_ct
WHERE snapshot_ts BETWEEN :min AND :max
AND local_port IN (:ports) -- OpsPolicy::monitoredPorts()
GROUP BY server_name, remote_ip, local_port;
감시 포트는 하드코딩이 아니라 운영 정책의 infra_monitored_ports(CSV)에서 옵니다. ipsData() 결과는 20초 캐시됩니다(키 infr:traffic:ips:v1:{timer}:{ports}).
조사 팝업 쿼리
| 메서드 | 테이블 | 하는 일 |
|---|---|---|
ipSeenSpan() |
traffic_session_ct |
MIN/MAX(created_at) = 진짜 관측 스팬(≈8h 보존창), MAX(snapshot_ts) = 이 IP의 자체 최신 배치(분포 앵커) |
ipBreakdown() |
traffic_session_ct |
서버×포트×상태별 세션 합·원격포트·최초/최종 (LIMIT 200) |
ipHistory() |
롤업 3종 | grain별 세션 이력 (LIMIT 400) |
ipEnrichment() |
ip_info_loop |
국가·도시·ASN·ISP (없으면 graceful null) |
접속 분포는 전역 최신 창이 아니라 그 IP의 자체 최신 스냅샷 배치를 앵커로 잡습니다. 지금은 접속이 없지만 과거에 붙었던 IP도 마지막 관측 시점 기준으로 분포를 복원해 보여주기 위한 설계입니다.
롤업 인덱스 주의 (성능 임계)
ipHistory()는 항상 direction IN ('inbound','outbound')를 명시합니다.
-- _1day 는 t_ip(direction, remote_ip) 복합 인덱스를 쓴다.
-- direction 을 명시하지 않으면 created_at 범위만 스캔 → 12s+.
-- 명시하면 인덱스 적중 → ~20ms (실측 2026-08-06).
SELECT created_at, SUM(session_count) AS sessions
FROM traffic_session_ct_1day
WHERE direction IN ('inbound','outbound')
AND remote_ip = :cclass_key -- 일별은 /24 앞 3옥텟 키
AND created_at >= :since
GROUP BY created_at
ORDER BY created_at
LIMIT 400;
롤업은 초대용량(_5min ≈ 209M · _1hour ≈ 112M · _1day ≈ 24M)이라 tight created_at >= 창 + LIMIT이 필수입니다. 팝업 결과는 investigate 25초 · sources 20초 캐시로 보호됩니다.
권한
- 이 화면은 Infrastructure 역할 영역(최소
user_level1)에 속합니다 — 읽기 전용이라 로그인한 사용자(demo=1)면 조회할 수 있습니다. - 페이지·
/live·/ip-detail모두 별도 레벨 게이트 없이infr.auth(로그인) 아래에 있습니다. - 쓰기는 없습니다. 조사 팝업의 IP 차단은 차단 목록 화면으로 넘기는 딥링크이며, 실제 차단(
blacklist_info쓰기)은 그 화면에서user_level2 이상 + 감사 로그로 수행됩니다.
문제해결 · FAQ
카드가 비어 있고 "이 창에 peer 가 없습니다"만 뜹니다.
최신 스냅샷의 감시 포트에 연결이 없다는 뜻입니다. (1) timer를 5나 60으로 넓혀 보고, (2) 운영 정책의 infra_monitored_ports에 실제 서비스 포트가 등록됐는지, (3) traffic_session_ct에 최근 스냅샷이 들어오는지(수집기 check_ct.js) 확인합니다.
전체가 비고 스냅샷 시각도 없습니다.
legacy_glory 커넥션 또는 traffic_session_ct 자체가 비었을 가능성이 큽니다. .env의 legacy_glory DB 접속과 트래픽 수집기 가동을 확인합니다. 조회 실패 시 payload에 error:true가 실립니다.
일별 이력만 "이 대역(/24)의 일별 롤업 이력이 없습니다"로 뜹니다. 일별 집계는 하루 지연될 수 있고 /24 대역 기준입니다. 5분·시간별 grain을 먼저 확인하세요. 대역에 아직 롤업이 없으면 정상입니다.
IP를 클릭했는데 접속 분포가 비어 있습니다. 그 IP는 최근 스냅샷에 세션이 없지만 과거 관측은 있는 경우입니다. 요약 KPI의 최초/최종 관측과 연결 이력으로 과거 활동을 확인하세요(분포는 IP의 마지막 스냅샷 배치를 앵커로 복원합니다).
팝업의 "평판 ↗"가 화면 안이 아니라 새 탭으로 열립니다. 의도된 동작입니다. 이 트래픽 팝업은 외부 AbuseIPDB 링크를 씁니다. 신뢰도 게이지·신고 내역을 콘솔 안에서 보려면 보안 화면의 인앱 평판 팝업을 사용하세요.
강도 도트 색이 무슨 기준인가. 포트당 세션 수 버킷입니다 — 1–9 녹색 · 10–49 황색 · 50+ 적색 · 0이면 흐린 도트. 열은 감시 포트 앞 8개만 표시합니다.
관련 항목
- 포트 연결 — 포트 → 서버 축의 PORT OVERVIEW(상태바·SRC 서클)
- 트래픽(네트워크 I/O) — 서버별 인/아웃 바이트·패킷 처리량
- 차단 목록 & 평판 — 팝업 "IP 차단" 딥링크의 도착지(쓰기·감사)
- IP 평판 조회 — 콘솔 내 AbuseIPDB 신뢰도 게이지 팝업
- 운영 정책 — 감시 포트(
infra_monitored_ports) 설정 - 경보 — 임계 위반 시 담당자 SMS/메일 발송
