From 9e5479dd8c44d7d9bb079f669647a786ca2b07b7 Mon Sep 17 00:00:00 2001 From: ale Date: Thu, 12 Feb 2026 00:36:42 +0100 Subject: [PATCH] fix geoip Signed-off-by: ale --- README.md | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++----- index.js | 24 ++++++++++++--- 2 files changed, 102 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index f71c9fb..a07468c 100644 --- a/README.md +++ b/README.md @@ -149,14 +149,14 @@ CACHE_CHECK_INTERVAL=5000 ## GeoIP Enrichment -The application automatically enriches captured packets with geolocation data for remote IP addresses: +The application automatically enriches captured packets with geolocation data for public IP addresses: **Features:** -- Automatically detects the server's public IP address +- Automatically detects the server's public IP address and its geolocation - Identifies private/local IP addresses (RFC 1918, link-local, etc.) -- Only enriches remote public IP addresses +- Enriches all public IP addresses (including the server's own IP) - Uses local GeoIP database (no external API calls during capture) -- Adds geolocation data for both source and destination IPs +- Adds geolocation data for both source and destination IPs when they are public **GeoIP Data Included:** - Country code and name @@ -168,9 +168,17 @@ The application automatically enriches captured packets with geolocation data fo **How it works:** 1. On startup, the application detects its public IP using an external service (ipify.org) -2. For each packet, it identifies if source/destination IPs are remote -3. Remote IPs are enriched with GeoIP data from the local database -4. Private IPs, loopback, and the server's own IP are excluded +2. The public IP's geolocation is fetched and cached for the session +3. For each packet: + - Source IP: If public (including server's IP), GeoIP data is added to `geoip_src` + - Destination IP: If public (including server's IP), GeoIP data is added to `geoip_dst` + - Private IPs, loopback addresses are excluded from GeoIP enrichment +4. The server's own IP is included in geolocation to provide complete visibility of traffic origin and destination + +**Traffic visibility:** +- **Outbound traffic**: `geoip_src` = server location, `geoip_dst` = remote destination location +- **Inbound traffic**: `geoip_src` = remote source location, `geoip_dst` = server location +- **External to external**: Both IPs geolocated (if packet is captured in transit) **Example GeoIP document structure:** ```json @@ -353,6 +361,38 @@ curl -X GET "localhost:9200/network-packets/_search?pretty" -H 'Content-Type: ap ' ``` +**Find packets to a specific country:** +```bash +curl -X GET "localhost:9200/network-packets/_search?pretty" -H 'Content-Type: application/json' -d' +{ + "query": { + "term": { + "geoip_dst.country": "CN" + } + } +} +' +``` + +**Find all outbound international traffic:** +```bash +curl -X GET "localhost:9200/network-packets/_search?pretty" -H 'Content-Type: application/json' -d' +{ + "query": { + "bool": { + "must": [ + { "exists": { "field": "geoip_src" } }, + { "exists": { "field": "geoip_dst" } } + ], + "must_not": [ + { "term": { "geoip_src.country": { "value": "geoip_dst.country" } } } + ] + } + } +} +' +``` + **Find packets to/from a specific geographic area:** ```bash curl -X GET "localhost:9200/network-packets/_search?pretty" -H 'Content-Type: application/json' -d' @@ -378,7 +418,8 @@ curl -X GET "localhost:9200/network-packets/_search?pretty" -H 'Content-Type: ap "aggs": { "countries": { "terms": { - "field": "geoip_dst.country" + "field": "geoip_dst.country", + "size": 20 } } } @@ -386,6 +427,39 @@ curl -X GET "localhost:9200/network-packets/_search?pretty" -H 'Content-Type: ap ' ``` +**Find traffic between two specific countries:** +```bash +curl -X GET "localhost:9200/network-packets/_search?pretty" -H 'Content-Type: application/json' -d' +{ + "query": { + "bool": { + "must": [ + { "term": { "geoip_src.country": "US" } }, + { "term": { "geoip_dst.country": "GB" } } + ] + } + } +} +' +``` + +**Map visualization - Get traffic with coordinates:** +```bash +curl -X GET "localhost:9200/network-packets/_search?pretty" -H 'Content-Type: application/json' -d' +{ + "query": { + "bool": { + "must": [ + { "exists": { "field": "geoip_src.location" } }, + { "exists": { "field": "geoip_dst.location" } } + ] + } + }, + "_source": ["ip.src", "ip.dst", "geoip_src.location", "geoip_dst.location", "geoip_src.city", "geoip_dst.city"] +} +' +``` + ## Performance Considerations - **Promiscuous mode** can generate high packet volumes on busy networks diff --git a/index.js b/index.js index 80567ed..338ac83 100644 --- a/index.js +++ b/index.js @@ -29,6 +29,7 @@ const ES_CHECK_INTERVAL = config.cache.checkInterval; // Public IP detection let publicIP = null; +let publicIPGeoData = null; // Statistics tracking const stats = { @@ -186,11 +187,11 @@ function isPrivateIP(ip) { } /** - * Check if IP is remote (not local, not private, not our public IP) + * Check if IP is remote (not local, not private) + * Now includes the public IP for geolocation */ function isRemoteIP(ip) { if (!ip || isPrivateIP(ip)) return false; - if (publicIP && ip === publicIP) return false; return true; } @@ -198,10 +199,15 @@ function isRemoteIP(ip) { * Get GeoIP information for an IP address */ function getGeoIPData(ip) { - if (!ip || !isRemoteIP(ip)) { + if (!ip || isPrivateIP(ip)) { return null; } + // Return cached GeoIP data for our public IP + if (publicIP && ip === publicIP && publicIPGeoData) { + return publicIPGeoData; + } + try { const geo = geoip.lookup(ip); @@ -825,10 +831,20 @@ async function main() { process.exit(1); } - // Get public IP address for GeoIP filtering + // Get public IP address and GeoIP data try { publicIP = await getPublicIP(); logger.info(`Detected public IP: ${publicIP}`); + + // Get GeoIP data for our public IP + if (publicIP) { + publicIPGeoData = getGeoIPData(publicIP); + if (publicIPGeoData) { + logger.info(`Public IP geolocation: ${publicIPGeoData.city || 'Unknown'}, ${publicIPGeoData.country || 'Unknown'}`); + } else { + logger.warn('Could not determine geolocation for public IP'); + } + } } catch (error) { logger.warn('Failed to detect public IP address:', error.message); logger.warn('GeoIP will be applied to all non-private IPs');