honeyweb-core 2.0.5 → 2.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,7 +6,7 @@ const DNSVerifier = require('../utils/dns-verify');
6
6
  // Known legitimate bots with their domain patterns
7
7
  const KNOWN_BOTS = {
8
8
  'Googlebot': {
9
- patterns: [/Googlebot/i],
9
+ patterns: [/Googlebot/i, /Google-InspectionTool/i],
10
10
  domains: ['googlebot.com', 'google.com']
11
11
  },
12
12
  'Bingbot': {
@@ -78,6 +78,7 @@ class BotWhitelist {
78
78
  }
79
79
 
80
80
  // Verify with DNS
81
+ let lastError = null;
81
82
  for (const domain of botInfo.domains) {
82
83
  const verification = await this.dnsVerifier.verify(ip, domain);
83
84
 
@@ -89,14 +90,17 @@ class BotWhitelist {
89
90
  hostname: verification.hostname
90
91
  };
91
92
  }
93
+ lastError = verification.error;
92
94
  }
93
95
 
94
96
  // User-Agent claims to be bot but DNS verification failed
97
+ console.warn(`[BotWhitelist] DNS verification failed for ${botName} (IP: ${ip}): ${lastError}`);
95
98
  return {
96
99
  isLegitimate: false,
97
100
  botName: `Fake ${botName}`,
98
101
  verified: false,
99
- reason: 'DNS verification failed'
102
+ reason: 'DNS verification failed',
103
+ dnsError: lastError
100
104
  };
101
105
  }
102
106
  }
@@ -90,6 +90,7 @@ function createDashboard(config, storage, botTracker, detector, events) {
90
90
  const stats = await storage.getStats();
91
91
  const detectionStats = detector.getStats();
92
92
  const botVisits = botTracker.getAllVisits();
93
+ console.log('[Debug] Current Bot Visits:', botVisits);
93
94
  const botStats = botTracker.getStats();
94
95
 
95
96
  const html = `<!DOCTYPE html>
@@ -3,6 +3,7 @@ function createRequestAnalyzer(config, storage, botTracker, detector, aiAnalyzer
3
3
 
4
4
  return async function analyzeRequest(req, res, next) {
5
5
  const clientIP = req.ip || req.connection.remoteAddress;
6
+ console.log(`[RequestAnalyzer] ${req.method} ${req.path} | IP: ${clientIP} | UA: ${req.headers['user-agent']}`);
6
7
  const analysis = await detector.analyze(req, clientIP);
7
8
 
8
9
  // Legitimate bots skip all checks
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "honeyweb-core",
3
- "version": "2.0.5",
3
+ "version": "2.0.6",
4
4
  "description": "Production-ready honeypot middleware with behavioral analysis, bot fingerprinting, and AI threat intelligence",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -2,120 +2,24 @@
2
2
 
3
3
  const dns = require('dns').promises;
4
4
  const LRUCache = require('./cache');
5
- const https = require('https');
6
-
7
- // Known bot IP ranges (fallback when DNS fails on Windows)
8
- const BOT_IP_RANGES = {
9
- 'googlebot.com': null, // Will be fetched dynamically
10
- 'google.com': null,
11
- 'search.msn.com': null,
12
- 'slack.com': null,
13
- 'facebook.com': null,
14
- 'twitter.com': null,
15
- 'linkedin.com': null,
16
- 'apple.com': null,
17
- 'duckduckgo.com': null
18
- };
19
5
 
20
6
  class DNSVerifier {
21
7
  constructor(cacheTTL = 86400000) {
22
8
  this.cache = new LRUCache(500, cacheTTL);
23
- this.ipRangesCache = null;
24
- this.ipRangesCacheTime = 0;
25
- this.ipRangesCacheTTL = 86400000; // 24 hours
26
- }
27
-
28
- // Fetch Googlebot IP ranges from Google's official API
29
- async fetchGooglebotRanges() {
30
- const now = Date.now();
31
- if (this.ipRangesCache && (now - this.ipRangesCacheTime) < this.ipRangesCacheTTL) {
32
- return this.ipRangesCache;
33
- }
34
-
35
- return new Promise((resolve, reject) => {
36
- https.get('https://developers.google.com/search/apis/ipranges/googlebot.json', (res) => {
37
- let data = '';
38
- res.on('data', chunk => data += chunk);
39
- res.on('end', () => {
40
- try {
41
- const json = JSON.parse(data);
42
- const ranges = json.prefixes
43
- .filter(p => p.ipv4Prefix)
44
- .map(p => p.ipv4Prefix);
45
- this.ipRangesCache = ranges;
46
- this.ipRangesCacheTime = now;
47
- resolve(ranges);
48
- } catch (err) {
49
- reject(err);
50
- }
51
- });
52
- }).on('error', reject);
53
- });
54
- }
55
-
56
- // Check if IP is in CIDR range
57
- ipInRange(ip, cidr) {
58
- const [range, bits] = cidr.split('/');
59
- const mask = ~(2 ** (32 - parseInt(bits)) - 1);
60
-
61
- const ipNum = ip.split('.').reduce((acc, octet) => (acc << 8) + parseInt(octet), 0) >>> 0;
62
- const rangeNum = range.split('.').reduce((acc, octet) => (acc << 8) + parseInt(octet), 0) >>> 0;
63
-
64
- return (ipNum & mask) === (rangeNum & mask);
65
- }
66
-
67
- // Fallback verification using IP ranges
68
- async verifyByIpRange(ip, expectedDomain) {
69
- // Only support Googlebot for now
70
- if (!expectedDomain.includes('google')) {
71
- return { verified: false, hostname: null, error: 'IP range verification only available for Google' };
72
- }
73
-
74
- try {
75
- const ranges = await this.fetchGooglebotRanges();
76
- const inRange = ranges.some(cidr => this.ipInRange(ip, cidr));
77
-
78
- if (inRange) {
79
- return {
80
- verified: true,
81
- hostname: 'googlebot.com (verified by IP range)',
82
- error: null,
83
- method: 'ip-range'
84
- };
85
- } else {
86
- return {
87
- verified: false,
88
- hostname: null,
89
- error: 'IP not in Googlebot ranges',
90
- method: 'ip-range'
91
- };
92
- }
93
- } catch (err) {
94
- return {
95
- verified: false,
96
- hostname: null,
97
- error: `IP range check failed: ${err.message}`,
98
- method: 'ip-range'
99
- };
100
- }
101
9
  }
102
10
 
103
11
  async verify(ip, expectedDomain) {
104
- const cacheKey = `${ip}:${expectedDomain}`;
12
+ // Normalize IPv4-mapped IPv6 addresses (::ffff:x.x.x.x -> x.x.x.x)
13
+ const normalizedIP = ip.replace(/^::ffff:/i, '');
14
+
15
+ const cacheKey = `${normalizedIP}:${expectedDomain}`;
105
16
  if (this.cache.has(cacheKey)) return this.cache.get(cacheKey);
106
17
 
107
18
  try {
108
- // Try DNS verification first
109
- const hostnames = await dns.reverse(ip);
19
+ // Reverse DNS: IP -> hostname
20
+ const hostnames = await dns.reverse(normalizedIP);
110
21
 
111
22
  if (!hostnames || hostnames.length === 0) {
112
- // DNS failed - try IP range fallback for Google
113
- if (expectedDomain.includes('google')) {
114
- const rangeResult = await this.verifyByIpRange(ip, expectedDomain);
115
- this.cache.set(cacheKey, rangeResult);
116
- return rangeResult;
117
- }
118
-
119
23
  const result = { verified: false, hostname: null, error: 'No reverse DNS record found' };
120
24
  this.cache.set(cacheKey, result);
121
25
  return result;
@@ -132,24 +36,17 @@ class DNSVerifier {
132
36
  // Forward DNS: hostname -> IP (verification)
133
37
  const addresses = await dns.resolve4(hostname);
134
38
 
135
- if (!addresses.includes(ip)) {
39
+ if (!addresses.includes(normalizedIP)) {
136
40
  const result = { verified: false, hostname, error: 'Forward DNS does not match original IP' };
137
41
  this.cache.set(cacheKey, result);
138
42
  return result;
139
43
  }
140
44
 
141
- const result = { verified: true, hostname, error: null, method: 'dns' };
45
+ const result = { verified: true, hostname, error: null };
142
46
  this.cache.set(cacheKey, result);
143
47
  return result;
144
48
 
145
49
  } catch (err) {
146
- // DNS lookup failed - try IP range fallback for Google
147
- if (expectedDomain.includes('google')) {
148
- const rangeResult = await this.verifyByIpRange(ip, expectedDomain);
149
- this.cache.set(cacheKey, rangeResult, 300000);
150
- return rangeResult;
151
- }
152
-
153
50
  const result = { verified: false, hostname: null, error: err.message };
154
51
  this.cache.set(cacheKey, result, 300000);
155
52
  return result;
@@ -158,7 +55,6 @@ class DNSVerifier {
158
55
 
159
56
  clearCache() {
160
57
  this.cache.clear();
161
- this.ipRangesCache = null;
162
58
  }
163
59
  }
164
60