모니터링&보안

위치 API + Leaflet.js로 IP 주소 위치를 지도에 시각화

JooRi 2025. 5. 25. 21:27
728x90
반응형
SMALL

* 위치 API와 Leaflet.js로 IP 주소 위치를 지도에 시각화

이번 기능은 fail2ban을 활용한 실제로 차단된 IP 로그와의 연동 이전에,

Leaflet.js와 IP 위치 조회 API(ip-api.com)를 활용해 가짜 IP 로그(mock_ban_log.txt)를 만들어서 지도 위에 마커 찍는 걸 먼저 테스트해 보았다.

추후에는 fail2ban과 실제로 연동하여, 로그인 다수 실패 또는 차단된 IP가 실시간으로 지도에 표시되도록 확장할 예정이다.

미리 mock 로그로 테스트해 봄으로써 실제 연동 시 오류 가능성을 줄이고 시각화 UI도 미리 다듬을 수 있었다.

 

Leaflet.js OpenStreetMap 기반의 지도 시각화 라이브러리
ip-api.com IP 주소로부터 위도, 경도, 국가, 도시 등의 위치 정보를 받아오는 API
JavaScript (fetch) API 호출 및 마커 렌더링 로직 구현
Flask (Python) IP 로그를 응답하는 백엔드 REST API
mock 로그 파일 (txt) 테스트용 Ban IP 로그를 담은 파일 (Fail2ban 미연동)

 

Mock 로그

fail2ban 없이도 지도 기능을 테스트하기 위해 가짜 Ban 로그가 담긴 mock_ban_log.txt를 만들었다.

 

 

Flask API 라우트 (IP 로그 응답)

mock_ban_log.txt로 저장 후, Flask에서 이 파일을 반환하도록 구성.

Flask는 이 텍스트 파일을 읽어 JSON 리스트로 반환한다.

브라우저에서 GET /api/ip_bans를 하면 ["Ban 8.8.8.8", "Ban 1.1.1.1",...] 형태로 반환된다.

 

각 IP는 아래와 같은 URL로 위치 조회를 할 수 있다.

http://ip-api.com/json/8.8.8.8

 

응답 예시:

{
  "status": "success",
  "country": "United States",
  "city": "Mountain View",
  "lat": 37.386,
  "lon": -122.0838,
  ...
}

위 응답을 기반으로 지도 마커를 찍게 된다.

 

 

html

HTML

 

 

let ipMap;
let ipMarkers = [];

function toggleMap() {
  const container = document.getElementById("ipMapContainer");
  const wasHidden = container.style.display === "none";
  container.style.display = wasHidden ? "block" : "none";
  if (wasHidden && !ipMap) {
    initMap();
    updateIPMap();
  }
}

function initMap() {
  ipMap = L.map('ipMap').setView([20, 0], 2); // 전 세계 지도
  L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
    attribution: 'Map data © OpenStreetMap contributors'
  }).addTo(ipMap);
}

async function updateIPMap() {
  const res = await fetch("/api/ip_bans");
  const logs = await res.json();

  const ips = logs
    .map(line => {
      const match = line.match(/Ban (\d+\.\d+\.\d+\.\d+)/);
      return match ? match[1] : null;
    })
    .filter(Boolean);

  // 기존 마커 삭제
  ipMarkers.forEach(m => ipMap.removeLayer(m));
  ipMarkers = [];

  for (const ip of ips) {
    try {
      const geo = await fetch(`http://ip-api.com/json/${ip}`).then(r => r.json());
      if (geo.status === "success") {
        const marker = L.marker([geo.lat, geo.lon]).addTo(ipMap)
          .bindPopup(`${ip}<br>${geo.country}, ${geo.city || ''}`);
        ipMarkers.push(marker);
      }
    } catch (err) {
      console.error(`IP ${ip} 위치 조회 실패`, err);
    }
  }
}

자바스크립트 함수

 

 

결과

끝.

 

 

 

 

728x90
반응형
LIST