90
README.md
90
README.md
@@ -149,14 +149,14 @@ CACHE_CHECK_INTERVAL=5000
|
|||||||
|
|
||||||
## GeoIP Enrichment
|
## 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:**
|
**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.)
|
- 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)
|
- 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:**
|
**GeoIP Data Included:**
|
||||||
- Country code and name
|
- Country code and name
|
||||||
@@ -168,9 +168,17 @@ The application automatically enriches captured packets with geolocation data fo
|
|||||||
|
|
||||||
**How it works:**
|
**How it works:**
|
||||||
1. On startup, the application detects its public IP using an external service (ipify.org)
|
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
|
2. The public IP's geolocation is fetched and cached for the session
|
||||||
3. Remote IPs are enriched with GeoIP data from the local database
|
3. For each packet:
|
||||||
4. Private IPs, loopback, and the server's own IP are excluded
|
- 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:**
|
**Example GeoIP document structure:**
|
||||||
```json
|
```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:**
|
**Find packets to/from a specific geographic area:**
|
||||||
```bash
|
```bash
|
||||||
curl -X GET "localhost:9200/network-packets/_search?pretty" -H 'Content-Type: application/json' -d'
|
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": {
|
"aggs": {
|
||||||
"countries": {
|
"countries": {
|
||||||
"terms": {
|
"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
|
## Performance Considerations
|
||||||
|
|
||||||
- **Promiscuous mode** can generate high packet volumes on busy networks
|
- **Promiscuous mode** can generate high packet volumes on busy networks
|
||||||
|
|||||||
24
index.js
24
index.js
@@ -29,6 +29,7 @@ const ES_CHECK_INTERVAL = config.cache.checkInterval;
|
|||||||
|
|
||||||
// Public IP detection
|
// Public IP detection
|
||||||
let publicIP = null;
|
let publicIP = null;
|
||||||
|
let publicIPGeoData = null;
|
||||||
|
|
||||||
// Statistics tracking
|
// Statistics tracking
|
||||||
const stats = {
|
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) {
|
function isRemoteIP(ip) {
|
||||||
if (!ip || isPrivateIP(ip)) return false;
|
if (!ip || isPrivateIP(ip)) return false;
|
||||||
if (publicIP && ip === publicIP) return false;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,10 +199,15 @@ function isRemoteIP(ip) {
|
|||||||
* Get GeoIP information for an IP address
|
* Get GeoIP information for an IP address
|
||||||
*/
|
*/
|
||||||
function getGeoIPData(ip) {
|
function getGeoIPData(ip) {
|
||||||
if (!ip || !isRemoteIP(ip)) {
|
if (!ip || isPrivateIP(ip)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return cached GeoIP data for our public IP
|
||||||
|
if (publicIP && ip === publicIP && publicIPGeoData) {
|
||||||
|
return publicIPGeoData;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const geo = geoip.lookup(ip);
|
const geo = geoip.lookup(ip);
|
||||||
|
|
||||||
@@ -825,10 +831,20 @@ async function main() {
|
|||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get public IP address for GeoIP filtering
|
// Get public IP address and GeoIP data
|
||||||
try {
|
try {
|
||||||
publicIP = await getPublicIP();
|
publicIP = await getPublicIP();
|
||||||
logger.info(`Detected public IP: ${publicIP}`);
|
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) {
|
} catch (error) {
|
||||||
logger.warn('Failed to detect public IP address:', error.message);
|
logger.warn('Failed to detect public IP address:', error.message);
|
||||||
logger.warn('GeoIP will be applied to all non-private IPs');
|
logger.warn('GeoIP will be applied to all non-private IPs');
|
||||||
|
|||||||
Referencia en una nueva incidencia
Block a user