@push.rocks/smartproxy 19.6.13 → 19.6.14
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.
- package/dist_ts/core/utils/log-deduplicator.d.ts +36 -0
- package/dist_ts/core/utils/log-deduplicator.js +224 -0
- package/dist_ts/core/utils/shared-security-manager.d.ts +2 -1
- package/dist_ts/core/utils/shared-security-manager.js +22 -2
- package/dist_ts/proxies/http-proxy/http-proxy.d.ts +1 -0
- package/dist_ts/proxies/http-proxy/http-proxy.js +94 -9
- package/dist_ts/proxies/http-proxy/models/types.d.ts +2 -0
- package/dist_ts/proxies/http-proxy/models/types.js +1 -1
- package/dist_ts/proxies/http-proxy/security-manager.d.ts +42 -1
- package/dist_ts/proxies/http-proxy/security-manager.js +121 -2
- package/dist_ts/proxies/smart-proxy/connection-manager.d.ts +14 -0
- package/dist_ts/proxies/smart-proxy/connection-manager.js +74 -26
- package/dist_ts/proxies/smart-proxy/http-proxy-bridge.js +5 -1
- package/dist_ts/proxies/smart-proxy/models/interfaces.d.ts +1 -0
- package/dist_ts/proxies/smart-proxy/route-connection-handler.js +24 -8
- package/dist_ts/proxies/smart-proxy/security-manager.d.ts +9 -0
- package/dist_ts/proxies/smart-proxy/security-manager.js +63 -1
- package/dist_ts/proxies/smart-proxy/smart-proxy.js +4 -1
- package/package.json +1 -1
- package/readme.hints.md +80 -1
- package/readme.plan.md +34 -353
- package/ts/core/utils/log-deduplicator.ts +280 -0
- package/ts/core/utils/shared-security-manager.ts +24 -1
- package/ts/proxies/http-proxy/http-proxy.ts +129 -9
- package/ts/proxies/http-proxy/models/types.ts +4 -0
- package/ts/proxies/http-proxy/security-manager.ts +136 -1
- package/ts/proxies/smart-proxy/connection-manager.ts +93 -27
- package/ts/proxies/smart-proxy/http-proxy-bridge.ts +5 -0
- package/ts/proxies/smart-proxy/models/interfaces.ts +1 -0
- package/ts/proxies/smart-proxy/route-connection-handler.ts +45 -14
- package/ts/proxies/smart-proxy/security-manager.ts +76 -1
- package/ts/proxies/smart-proxy/smart-proxy.ts +4 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Log deduplication utility to reduce log spam for repetitive events
|
|
3
|
+
*/
|
|
4
|
+
export declare class LogDeduplicator {
|
|
5
|
+
private globalFlushTimer?;
|
|
6
|
+
private aggregatedEvents;
|
|
7
|
+
private flushInterval;
|
|
8
|
+
private maxBatchSize;
|
|
9
|
+
constructor(flushInterval?: number);
|
|
10
|
+
/**
|
|
11
|
+
* Log a deduplicated event
|
|
12
|
+
* @param key - Aggregation key (e.g., 'connection-rejected', 'cleanup-batch')
|
|
13
|
+
* @param level - Log level
|
|
14
|
+
* @param message - Log message template
|
|
15
|
+
* @param data - Additional data
|
|
16
|
+
* @param dedupeKey - Deduplication key within the aggregation (e.g., IP address, reason)
|
|
17
|
+
*/
|
|
18
|
+
log(key: string, level: 'info' | 'warn' | 'error' | 'debug', message: string, data?: any, dedupeKey?: string): void;
|
|
19
|
+
/**
|
|
20
|
+
* Flush aggregated events for a specific key
|
|
21
|
+
*/
|
|
22
|
+
flush(key: string): void;
|
|
23
|
+
/**
|
|
24
|
+
* Flush all pending events
|
|
25
|
+
*/
|
|
26
|
+
flushAll(): void;
|
|
27
|
+
private flushConnectionRejections;
|
|
28
|
+
private flushConnectionCleanups;
|
|
29
|
+
private flushIPRejections;
|
|
30
|
+
private flushGeneric;
|
|
31
|
+
/**
|
|
32
|
+
* Cleanup and stop deduplication
|
|
33
|
+
*/
|
|
34
|
+
cleanup(): void;
|
|
35
|
+
}
|
|
36
|
+
export declare const connectionLogDeduplicator: LogDeduplicator;
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { logger } from './logger.js';
|
|
2
|
+
/**
|
|
3
|
+
* Log deduplication utility to reduce log spam for repetitive events
|
|
4
|
+
*/
|
|
5
|
+
export class LogDeduplicator {
|
|
6
|
+
constructor(flushInterval) {
|
|
7
|
+
this.aggregatedEvents = new Map();
|
|
8
|
+
this.flushInterval = 5000; // 5 seconds
|
|
9
|
+
this.maxBatchSize = 100;
|
|
10
|
+
if (flushInterval) {
|
|
11
|
+
this.flushInterval = flushInterval;
|
|
12
|
+
}
|
|
13
|
+
// Set up global periodic flush to ensure logs are emitted regularly
|
|
14
|
+
this.globalFlushTimer = setInterval(() => {
|
|
15
|
+
this.flushAll();
|
|
16
|
+
}, this.flushInterval * 2); // Flush everything every 2x the normal interval
|
|
17
|
+
if (this.globalFlushTimer.unref) {
|
|
18
|
+
this.globalFlushTimer.unref();
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Log a deduplicated event
|
|
23
|
+
* @param key - Aggregation key (e.g., 'connection-rejected', 'cleanup-batch')
|
|
24
|
+
* @param level - Log level
|
|
25
|
+
* @param message - Log message template
|
|
26
|
+
* @param data - Additional data
|
|
27
|
+
* @param dedupeKey - Deduplication key within the aggregation (e.g., IP address, reason)
|
|
28
|
+
*/
|
|
29
|
+
log(key, level, message, data, dedupeKey) {
|
|
30
|
+
const eventKey = dedupeKey || message;
|
|
31
|
+
const now = Date.now();
|
|
32
|
+
if (!this.aggregatedEvents.has(key)) {
|
|
33
|
+
this.aggregatedEvents.set(key, {
|
|
34
|
+
key,
|
|
35
|
+
events: new Map(),
|
|
36
|
+
flushTimer: undefined
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
const aggregated = this.aggregatedEvents.get(key);
|
|
40
|
+
if (aggregated.events.has(eventKey)) {
|
|
41
|
+
const event = aggregated.events.get(eventKey);
|
|
42
|
+
event.count++;
|
|
43
|
+
event.lastSeen = now;
|
|
44
|
+
if (data) {
|
|
45
|
+
event.data = { ...event.data, ...data };
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
aggregated.events.set(eventKey, {
|
|
50
|
+
level,
|
|
51
|
+
message,
|
|
52
|
+
data,
|
|
53
|
+
count: 1,
|
|
54
|
+
firstSeen: now,
|
|
55
|
+
lastSeen: now
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
// Check if we should flush due to size
|
|
59
|
+
if (aggregated.events.size >= this.maxBatchSize) {
|
|
60
|
+
this.flush(key);
|
|
61
|
+
}
|
|
62
|
+
else if (!aggregated.flushTimer) {
|
|
63
|
+
// Schedule flush
|
|
64
|
+
aggregated.flushTimer = setTimeout(() => {
|
|
65
|
+
this.flush(key);
|
|
66
|
+
}, this.flushInterval);
|
|
67
|
+
if (aggregated.flushTimer.unref) {
|
|
68
|
+
aggregated.flushTimer.unref();
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Flush aggregated events for a specific key
|
|
74
|
+
*/
|
|
75
|
+
flush(key) {
|
|
76
|
+
const aggregated = this.aggregatedEvents.get(key);
|
|
77
|
+
if (!aggregated || aggregated.events.size === 0) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
if (aggregated.flushTimer) {
|
|
81
|
+
clearTimeout(aggregated.flushTimer);
|
|
82
|
+
aggregated.flushTimer = undefined;
|
|
83
|
+
}
|
|
84
|
+
// Emit aggregated log based on the key
|
|
85
|
+
switch (key) {
|
|
86
|
+
case 'connection-rejected':
|
|
87
|
+
this.flushConnectionRejections(aggregated);
|
|
88
|
+
break;
|
|
89
|
+
case 'connection-cleanup':
|
|
90
|
+
this.flushConnectionCleanups(aggregated);
|
|
91
|
+
break;
|
|
92
|
+
case 'ip-rejected':
|
|
93
|
+
this.flushIPRejections(aggregated);
|
|
94
|
+
break;
|
|
95
|
+
default:
|
|
96
|
+
this.flushGeneric(aggregated);
|
|
97
|
+
}
|
|
98
|
+
// Clear events
|
|
99
|
+
aggregated.events.clear();
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Flush all pending events
|
|
103
|
+
*/
|
|
104
|
+
flushAll() {
|
|
105
|
+
for (const key of this.aggregatedEvents.keys()) {
|
|
106
|
+
this.flush(key);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
flushConnectionRejections(aggregated) {
|
|
110
|
+
const totalCount = Array.from(aggregated.events.values()).reduce((sum, e) => sum + e.count, 0);
|
|
111
|
+
const byReason = new Map();
|
|
112
|
+
for (const [, event] of aggregated.events) {
|
|
113
|
+
const reason = event.data?.reason || 'unknown';
|
|
114
|
+
byReason.set(reason, (byReason.get(reason) || 0) + event.count);
|
|
115
|
+
}
|
|
116
|
+
const reasonSummary = Array.from(byReason.entries())
|
|
117
|
+
.sort((a, b) => b[1] - a[1])
|
|
118
|
+
.map(([reason, count]) => `${reason}: ${count}`)
|
|
119
|
+
.join(', ');
|
|
120
|
+
logger.log('warn', `Rejected ${totalCount} connections`, {
|
|
121
|
+
reasons: reasonSummary,
|
|
122
|
+
uniqueIPs: aggregated.events.size,
|
|
123
|
+
duration: Date.now() - Math.min(...Array.from(aggregated.events.values()).map(e => e.firstSeen)),
|
|
124
|
+
component: 'connection-dedup'
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
flushConnectionCleanups(aggregated) {
|
|
128
|
+
const totalCount = Array.from(aggregated.events.values()).reduce((sum, e) => sum + e.count, 0);
|
|
129
|
+
const byReason = new Map();
|
|
130
|
+
for (const [, event] of aggregated.events) {
|
|
131
|
+
const reason = event.data?.reason || 'normal';
|
|
132
|
+
byReason.set(reason, (byReason.get(reason) || 0) + event.count);
|
|
133
|
+
}
|
|
134
|
+
const reasonSummary = Array.from(byReason.entries())
|
|
135
|
+
.sort((a, b) => b[1] - a[1])
|
|
136
|
+
.slice(0, 5) // Top 5 reasons
|
|
137
|
+
.map(([reason, count]) => `${reason}: ${count}`)
|
|
138
|
+
.join(', ');
|
|
139
|
+
logger.log('info', `Cleaned up ${totalCount} connections`, {
|
|
140
|
+
reasons: reasonSummary,
|
|
141
|
+
duration: Date.now() - Math.min(...Array.from(aggregated.events.values()).map(e => e.firstSeen)),
|
|
142
|
+
component: 'connection-dedup'
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
flushIPRejections(aggregated) {
|
|
146
|
+
const byIP = new Map();
|
|
147
|
+
for (const [ip, event] of aggregated.events) {
|
|
148
|
+
if (!byIP.has(ip)) {
|
|
149
|
+
byIP.set(ip, { count: 0, reasons: new Set() });
|
|
150
|
+
}
|
|
151
|
+
const ipData = byIP.get(ip);
|
|
152
|
+
ipData.count += event.count;
|
|
153
|
+
if (event.data?.reason) {
|
|
154
|
+
ipData.reasons.add(event.data.reason);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
// Log top offenders
|
|
158
|
+
const topOffenders = Array.from(byIP.entries())
|
|
159
|
+
.sort((a, b) => b[1].count - a[1].count)
|
|
160
|
+
.slice(0, 10)
|
|
161
|
+
.map(([ip, data]) => `${ip} (${data.count}x, ${Array.from(data.reasons).join('/')})`)
|
|
162
|
+
.join(', ');
|
|
163
|
+
const totalRejections = Array.from(byIP.values()).reduce((sum, data) => sum + data.count, 0);
|
|
164
|
+
logger.log('warn', `Rejected ${totalRejections} connections from ${byIP.size} IPs`, {
|
|
165
|
+
topOffenders,
|
|
166
|
+
duration: Date.now() - Math.min(...Array.from(aggregated.events.values()).map(e => e.firstSeen)),
|
|
167
|
+
component: 'ip-dedup'
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
flushGeneric(aggregated) {
|
|
171
|
+
const totalCount = Array.from(aggregated.events.values()).reduce((sum, e) => sum + e.count, 0);
|
|
172
|
+
const level = aggregated.events.values().next().value?.level || 'info';
|
|
173
|
+
// Special handling for IP cleanup events
|
|
174
|
+
if (aggregated.key === 'ip-cleanup') {
|
|
175
|
+
const totalCleaned = Array.from(aggregated.events.values()).reduce((sum, e) => {
|
|
176
|
+
return sum + (e.data?.cleanedIPs || 0) + (e.data?.cleanedRateLimits || 0);
|
|
177
|
+
}, 0);
|
|
178
|
+
if (totalCleaned > 0) {
|
|
179
|
+
logger.log(level, `IP tracking cleanup: removed ${totalCleaned} entries across ${totalCount} cleanup cycles`, {
|
|
180
|
+
duration: Date.now() - Math.min(...Array.from(aggregated.events.values()).map(e => e.firstSeen)),
|
|
181
|
+
component: 'log-dedup'
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
logger.log(level, `${aggregated.key}: ${totalCount} events`, {
|
|
187
|
+
uniqueEvents: aggregated.events.size,
|
|
188
|
+
duration: Date.now() - Math.min(...Array.from(aggregated.events.values()).map(e => e.firstSeen)),
|
|
189
|
+
component: 'log-dedup'
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Cleanup and stop deduplication
|
|
195
|
+
*/
|
|
196
|
+
cleanup() {
|
|
197
|
+
this.flushAll();
|
|
198
|
+
if (this.globalFlushTimer) {
|
|
199
|
+
clearInterval(this.globalFlushTimer);
|
|
200
|
+
this.globalFlushTimer = undefined;
|
|
201
|
+
}
|
|
202
|
+
for (const aggregated of this.aggregatedEvents.values()) {
|
|
203
|
+
if (aggregated.flushTimer) {
|
|
204
|
+
clearTimeout(aggregated.flushTimer);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
this.aggregatedEvents.clear();
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
// Global instance for connection-related log deduplication
|
|
211
|
+
export const connectionLogDeduplicator = new LogDeduplicator(5000); // 5 second batches
|
|
212
|
+
// Ensure logs are flushed on process exit
|
|
213
|
+
process.on('beforeExit', () => {
|
|
214
|
+
connectionLogDeduplicator.flushAll();
|
|
215
|
+
});
|
|
216
|
+
process.on('SIGINT', () => {
|
|
217
|
+
connectionLogDeduplicator.cleanup();
|
|
218
|
+
process.exit(0);
|
|
219
|
+
});
|
|
220
|
+
process.on('SIGTERM', () => {
|
|
221
|
+
connectionLogDeduplicator.cleanup();
|
|
222
|
+
process.exit(0);
|
|
223
|
+
});
|
|
224
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9nLWRlZHVwbGljYXRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3RzL2NvcmUvdXRpbHMvbG9nLWRlZHVwbGljYXRvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBaUJyQzs7R0FFRztBQUNILE1BQU0sT0FBTyxlQUFlO0lBTTFCLFlBQVksYUFBc0I7UUFKMUIscUJBQWdCLEdBQWtDLElBQUksR0FBRyxFQUFFLENBQUM7UUFDNUQsa0JBQWEsR0FBVyxJQUFJLENBQUMsQ0FBQyxZQUFZO1FBQzFDLGlCQUFZLEdBQVcsR0FBRyxDQUFDO1FBR2pDLElBQUksYUFBYSxFQUFFLENBQUM7WUFDbEIsSUFBSSxDQUFDLGFBQWEsR0FBRyxhQUFhLENBQUM7UUFDckMsQ0FBQztRQUVELG9FQUFvRTtRQUNwRSxJQUFJLENBQUMsZ0JBQWdCLEdBQUcsV0FBVyxDQUFDLEdBQUcsRUFBRTtZQUN2QyxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7UUFDbEIsQ0FBQyxFQUFFLElBQUksQ0FBQyxhQUFhLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxnREFBZ0Q7UUFFNUUsSUFBSSxJQUFJLENBQUMsZ0JBQWdCLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDaEMsSUFBSSxDQUFDLGdCQUFnQixDQUFDLEtBQUssRUFBRSxDQUFDO1FBQ2hDLENBQUM7SUFDSCxDQUFDO0lBRUQ7Ozs7Ozs7T0FPRztJQUNJLEdBQUcsQ0FDUixHQUFXLEVBQ1gsS0FBMEMsRUFDMUMsT0FBZSxFQUNmLElBQVUsRUFDVixTQUFrQjtRQUVsQixNQUFNLFFBQVEsR0FBRyxTQUFTLElBQUksT0FBTyxDQUFDO1FBQ3RDLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztRQUV2QixJQUFJLENBQUMsSUFBSSxDQUFDLGdCQUFnQixDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsRUFBRSxD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
|
|
@@ -66,9 +66,10 @@ export declare class SharedSecurityManager {
|
|
|
66
66
|
*
|
|
67
67
|
* @param route - The route to check
|
|
68
68
|
* @param context - The request context
|
|
69
|
+
* @param routeConnectionCount - Current connection count for this route (optional)
|
|
69
70
|
* @returns Whether access is allowed
|
|
70
71
|
*/
|
|
71
|
-
isAllowed(route: IRouteConfig, context: IRouteContext): boolean;
|
|
72
|
+
isAllowed(route: IRouteConfig, context: IRouteContext, routeConnectionCount?: number): boolean;
|
|
72
73
|
/**
|
|
73
74
|
* Check if a client IP is allowed for a route
|
|
74
75
|
*
|
|
@@ -101,9 +101,10 @@ export class SharedSecurityManager {
|
|
|
101
101
|
*
|
|
102
102
|
* @param route - The route to check
|
|
103
103
|
* @param context - The request context
|
|
104
|
+
* @param routeConnectionCount - Current connection count for this route (optional)
|
|
104
105
|
* @returns Whether access is allowed
|
|
105
106
|
*/
|
|
106
|
-
isAllowed(route, context) {
|
|
107
|
+
isAllowed(route, context, routeConnectionCount) {
|
|
107
108
|
if (!route.security) {
|
|
108
109
|
return true; // No security restrictions
|
|
109
110
|
}
|
|
@@ -112,6 +113,13 @@ export class SharedSecurityManager {
|
|
|
112
113
|
this.logger?.debug?.(`IP ${context.clientIp} is blocked for route ${route.name || 'unnamed'}`);
|
|
113
114
|
return false;
|
|
114
115
|
}
|
|
116
|
+
// --- Route-level connection limit ---
|
|
117
|
+
if (route.security.maxConnections !== undefined && routeConnectionCount !== undefined) {
|
|
118
|
+
if (routeConnectionCount >= route.security.maxConnections) {
|
|
119
|
+
this.logger?.debug?.(`Route connection limit (${route.security.maxConnections}) exceeded for route ${route.name || 'unnamed'}`);
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
115
123
|
// --- Rate limiting ---
|
|
116
124
|
if (route.security.rateLimit?.enabled && !this.isWithinRateLimit(route, context)) {
|
|
117
125
|
this.logger?.debug?.(`Rate limit exceeded for route ${route.name || 'unnamed'}`);
|
|
@@ -225,6 +233,18 @@ export class SharedSecurityManager {
|
|
|
225
233
|
cleanupCaches() {
|
|
226
234
|
// Clean up rate limits
|
|
227
235
|
cleanupExpiredRateLimits(this.rateLimits, this.logger);
|
|
236
|
+
// Clean up IP connection tracking
|
|
237
|
+
let cleanedIPs = 0;
|
|
238
|
+
for (const [ip, info] of this.connectionsByIP.entries()) {
|
|
239
|
+
// Remove IPs with no active connections and no recent timestamps
|
|
240
|
+
if (info.connections.size === 0 && info.timestamps.length === 0) {
|
|
241
|
+
this.connectionsByIP.delete(ip);
|
|
242
|
+
cleanedIPs++;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
if (cleanedIPs > 0 && this.logger?.debug) {
|
|
246
|
+
this.logger.debug(`Cleaned up ${cleanedIPs} IPs with no active connections`);
|
|
247
|
+
}
|
|
228
248
|
// IP filter cache doesn't need cleanup (tied to routes)
|
|
229
249
|
}
|
|
230
250
|
/**
|
|
@@ -249,4 +269,4 @@ export class SharedSecurityManager {
|
|
|
249
269
|
this.ipFilterCache.clear();
|
|
250
270
|
}
|
|
251
271
|
}
|
|
252
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
272
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2hhcmVkLXNlY3VyaXR5LW1hbmFnZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy9jb3JlL3V0aWxzL3NoYXJlZC1zZWN1cml0eS1tYW5hZ2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sa0JBQWtCLENBQUM7QUFRNUMsT0FBTyxFQUNMLGNBQWMsRUFDZCxtQkFBbUIsRUFDbkIsbUJBQW1CLEVBQ25CLGVBQWUsRUFDZixnQkFBZ0IsRUFDaEIsd0JBQXdCLEVBQ3hCLG9CQUFvQixFQUNyQixNQUFNLHFCQUFxQixDQUFDO0FBRTdCOzs7R0FHRztBQUNILE1BQU0sT0FBTyxxQkFBcUI7SUFpQmhDOzs7OztPQUtHO0lBQ0gsWUFBWSxPQUtYLEVBQVUsTUFBd0I7UUFBeEIsV0FBTSxHQUFOLE1BQU0sQ0FBa0I7UUEzQm5DLHlCQUF5QjtRQUNqQixvQkFBZSxHQUFtQyxJQUFJLEdBQUcsRUFBRSxDQUFDO1FBRXBFLCtCQUErQjtRQUN2QixlQUFVLEdBQTZDLElBQUksR0FBRyxFQUFFLENBQUM7UUFFekUsOERBQThEO1FBQ3RELGtCQUFhLEdBQXNDLElBQUksR0FBRyxFQUFFLENBQUM7UUFNckUseUJBQXlCO1FBQ2pCLG9CQUFlLEdBQTBCLElBQUksQ0FBQztRQWNwRCxJQUFJLENBQUMsbUJBQW1CLEdBQUcsT0FBTyxDQUFDLG1CQUFtQixJQUFJLEdBQUcsQ0FBQztRQUM5RCxJQUFJLENBQUMsNEJBQTRCLEdBQUcsT0FBTyxDQUFDLDRCQUE0QixJQUFJLEdBQUcsQ0FBQztRQUVoRiw4Q0FBOEM7UUFDOUMsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLElBQUk7WUFDdEIsSUFBSSxFQUFFLE9BQU8sQ0FBQyxHQUFHO1lBQ2pCLElBQUksRUFBRSxPQUFPLENBQUMsSUFBSTtZQUNsQixLQUFLLEVBQUUsT0FBTyxDQUFDLEtBQUs7U0FDckIsQ0FBQztRQUVGLGdDQUFnQztRQUNoQyxNQUFN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
|
|
@@ -19,6 +19,7 @@ export declare class HttpProxy implements IMetricsTracker {
|
|
|
19
19
|
private router;
|
|
20
20
|
private routeManager;
|
|
21
21
|
private functionCache;
|
|
22
|
+
private securityManager;
|
|
22
23
|
socketMap: plugins.lik.ObjectMap<plugins.net.Socket>;
|
|
23
24
|
activeContexts: Set<string>;
|
|
24
25
|
connectedClients: number;
|
|
@@ -9,6 +9,8 @@ import { WebSocketHandler } from './websocket-handler.js';
|
|
|
9
9
|
import { HttpRouter } from '../../routing/router/index.js';
|
|
10
10
|
import { cleanupSocket } from '../../core/utils/socket-utils.js';
|
|
11
11
|
import { FunctionCache } from './function-cache.js';
|
|
12
|
+
import { SecurityManager } from './security-manager.js';
|
|
13
|
+
import { connectionLogDeduplicator } from '../../core/utils/log-deduplicator.js';
|
|
12
14
|
/**
|
|
13
15
|
* HttpProxy provides a reverse proxy with TLS termination, WebSocket support,
|
|
14
16
|
* automatic certificate management, and high-performance connection pooling.
|
|
@@ -78,6 +80,8 @@ export class HttpProxy {
|
|
|
78
80
|
maxCacheSize: this.options.functionCacheSize || 1000,
|
|
79
81
|
defaultTtl: this.options.functionCacheTtl || 5000
|
|
80
82
|
});
|
|
83
|
+
// Initialize security manager
|
|
84
|
+
this.securityManager = new SecurityManager(this.logger, [], this.options.maxConnectionsPerIP || 100, this.options.connectionRateLimitPerMinute || 300);
|
|
81
85
|
// Initialize other components
|
|
82
86
|
this.certificateManager = new CertificateManager(this.options);
|
|
83
87
|
this.connectionPool = new ConnectionPool(this.options);
|
|
@@ -204,36 +208,115 @@ export class HttpProxy {
|
|
|
204
208
|
*/
|
|
205
209
|
setupConnectionTracking() {
|
|
206
210
|
this.httpsServer.on('connection', (connection) => {
|
|
207
|
-
|
|
211
|
+
let remoteIP = connection.remoteAddress || '';
|
|
212
|
+
const connectionId = Math.random().toString(36).substring(2, 15);
|
|
213
|
+
const isFromSmartProxy = this.options.portProxyIntegration && connection.remoteAddress?.includes('127.0.0.1');
|
|
214
|
+
// For SmartProxy connections, wait for CLIENT_IP header
|
|
215
|
+
if (isFromSmartProxy) {
|
|
216
|
+
let headerBuffer = Buffer.alloc(0);
|
|
217
|
+
let headerParsed = false;
|
|
218
|
+
const parseHeader = (data) => {
|
|
219
|
+
if (headerParsed)
|
|
220
|
+
return data;
|
|
221
|
+
headerBuffer = Buffer.concat([headerBuffer, data]);
|
|
222
|
+
const headerStr = headerBuffer.toString();
|
|
223
|
+
const headerEnd = headerStr.indexOf('\r\n');
|
|
224
|
+
if (headerEnd !== -1) {
|
|
225
|
+
const header = headerStr.substring(0, headerEnd);
|
|
226
|
+
if (header.startsWith('CLIENT_IP:')) {
|
|
227
|
+
remoteIP = header.substring(10); // Extract IP after "CLIENT_IP:"
|
|
228
|
+
this.logger.debug(`Extracted client IP from SmartProxy: ${remoteIP}`);
|
|
229
|
+
}
|
|
230
|
+
headerParsed = true;
|
|
231
|
+
// Store the real IP on the connection
|
|
232
|
+
connection._realRemoteIP = remoteIP;
|
|
233
|
+
// Validate the real IP
|
|
234
|
+
const ipValidation = this.securityManager.validateIP(remoteIP);
|
|
235
|
+
if (!ipValidation.allowed) {
|
|
236
|
+
connectionLogDeduplicator.log('ip-rejected', 'warn', `HttpProxy connection rejected (via SmartProxy)`, { remoteIP, reason: ipValidation.reason, component: 'http-proxy' }, remoteIP);
|
|
237
|
+
connection.destroy();
|
|
238
|
+
return null;
|
|
239
|
+
}
|
|
240
|
+
// Track connection by real IP
|
|
241
|
+
this.securityManager.trackConnectionByIP(remoteIP, connectionId);
|
|
242
|
+
// Return remaining data after header
|
|
243
|
+
return headerBuffer.slice(headerEnd + 2);
|
|
244
|
+
}
|
|
245
|
+
return null;
|
|
246
|
+
};
|
|
247
|
+
// Override the first data handler to parse header
|
|
248
|
+
const originalEmit = connection.emit;
|
|
249
|
+
connection.emit = function (event, ...args) {
|
|
250
|
+
if (event === 'data' && !headerParsed) {
|
|
251
|
+
const remaining = parseHeader(args[0]);
|
|
252
|
+
if (remaining && remaining.length > 0) {
|
|
253
|
+
// Call original emit with remaining data
|
|
254
|
+
return originalEmit.apply(connection, ['data', remaining]);
|
|
255
|
+
}
|
|
256
|
+
else if (headerParsed) {
|
|
257
|
+
// Header parsed but no remaining data
|
|
258
|
+
return true;
|
|
259
|
+
}
|
|
260
|
+
// Header not complete yet, suppress this data event
|
|
261
|
+
return true;
|
|
262
|
+
}
|
|
263
|
+
return originalEmit.apply(connection, [event, ...args]);
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
else {
|
|
267
|
+
// Direct connection - validate immediately
|
|
268
|
+
const ipValidation = this.securityManager.validateIP(remoteIP);
|
|
269
|
+
if (!ipValidation.allowed) {
|
|
270
|
+
connectionLogDeduplicator.log('ip-rejected', 'warn', `HttpProxy connection rejected`, { remoteIP, reason: ipValidation.reason, component: 'http-proxy' }, remoteIP);
|
|
271
|
+
connection.destroy();
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
// Track connection by IP
|
|
275
|
+
this.securityManager.trackConnectionByIP(remoteIP, connectionId);
|
|
276
|
+
}
|
|
277
|
+
// Then check global max connections
|
|
208
278
|
if (this.socketMap.getArray().length >= this.options.maxConnections) {
|
|
209
|
-
|
|
279
|
+
connectionLogDeduplicator.log('connection-rejected', 'warn', 'HttpProxy max connections reached', {
|
|
280
|
+
reason: 'global-limit',
|
|
281
|
+
currentConnections: this.socketMap.getArray().length,
|
|
282
|
+
maxConnections: this.options.maxConnections,
|
|
283
|
+
component: 'http-proxy'
|
|
284
|
+
}, 'http-proxy-global-limit');
|
|
210
285
|
connection.destroy();
|
|
211
286
|
return;
|
|
212
287
|
}
|
|
213
|
-
// Add connection to tracking
|
|
288
|
+
// Add connection to tracking with metadata
|
|
289
|
+
connection._connectionId = connectionId;
|
|
290
|
+
connection._remoteIP = remoteIP;
|
|
214
291
|
this.socketMap.add(connection);
|
|
215
292
|
this.connectedClients = this.socketMap.getArray().length;
|
|
216
293
|
// Check for connection from SmartProxy by inspecting the source port
|
|
217
294
|
const localPort = connection.localPort || 0;
|
|
218
295
|
const remotePort = connection.remotePort || 0;
|
|
219
|
-
// If this connection is from a SmartProxy
|
|
220
|
-
if (
|
|
296
|
+
// If this connection is from a SmartProxy
|
|
297
|
+
if (isFromSmartProxy) {
|
|
221
298
|
this.portProxyConnections++;
|
|
222
|
-
this.logger.debug(`New connection from SmartProxy (local: ${localPort}, remote: ${remotePort})`);
|
|
299
|
+
this.logger.debug(`New connection from SmartProxy for client ${remoteIP} (local: ${localPort}, remote: ${remotePort})`);
|
|
223
300
|
}
|
|
224
301
|
else {
|
|
225
|
-
this.logger.debug(`New direct connection (local: ${localPort}, remote: ${remotePort})`);
|
|
302
|
+
this.logger.debug(`New direct connection from ${remoteIP} (local: ${localPort}, remote: ${remotePort})`);
|
|
226
303
|
}
|
|
227
304
|
// Setup connection cleanup handlers
|
|
228
305
|
const cleanupConnection = () => {
|
|
229
306
|
if (this.socketMap.checkForObject(connection)) {
|
|
230
307
|
this.socketMap.remove(connection);
|
|
231
308
|
this.connectedClients = this.socketMap.getArray().length;
|
|
309
|
+
// Remove IP tracking
|
|
310
|
+
const connId = connection._connectionId;
|
|
311
|
+
const connIP = connection._realRemoteIP || connection._remoteIP;
|
|
312
|
+
if (connId && connIP) {
|
|
313
|
+
this.securityManager.removeConnectionByIP(connIP, connId);
|
|
314
|
+
}
|
|
232
315
|
// If this was a SmartProxy connection, decrement the counter
|
|
233
316
|
if (this.options.portProxyIntegration && connection.remoteAddress?.includes('127.0.0.1')) {
|
|
234
317
|
this.portProxyConnections--;
|
|
235
318
|
}
|
|
236
|
-
this.logger.debug(`Connection closed. ${this.connectedClients} connections remaining`);
|
|
319
|
+
this.logger.debug(`Connection closed from ${connIP || 'unknown'}. ${this.connectedClients} connections remaining`);
|
|
237
320
|
}
|
|
238
321
|
};
|
|
239
322
|
connection.on('close', cleanupConnection);
|
|
@@ -374,6 +457,8 @@ export class HttpProxy {
|
|
|
374
457
|
// Close all connection pool connections
|
|
375
458
|
this.connectionPool.closeAllConnections();
|
|
376
459
|
// Certificate management cleanup is handled by SmartCertManager
|
|
460
|
+
// Flush any pending deduplicated logs
|
|
461
|
+
connectionLogDeduplicator.flushAll();
|
|
377
462
|
// Close the HTTPS server
|
|
378
463
|
return new Promise((resolve) => {
|
|
379
464
|
this.httpsServer.close(() => {
|
|
@@ -414,4 +499,4 @@ export class HttpProxy {
|
|
|
414
499
|
return this.routeManager.getRoutes();
|
|
415
500
|
}
|
|
416
501
|
}
|
|
417
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaHR0cC1wcm94eS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3RzL3Byb3hpZXMvaHR0cC1wcm94eS9odHRwLXByb3h5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sa0JBQWtCLENBQUM7QUFDNUMsT0FBTyxFQUNMLFlBQVksR0FDYixNQUFNLG1CQUFtQixDQUFDO0FBQzNCLE9BQU8sRUFBRSxrQkFBa0IsSUFBSSxZQUFZLEVBQUUsTUFBTSxxQ0FBcUMsQ0FBQztBQU96RixPQUFPLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSxvQ0FBb0MsQ0FBQztBQUM1RSxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUM5RCxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDdEQsT0FBTyxFQUFFLGNBQWMsRUFBd0IsTUFBTSxzQkFBc0IsQ0FBQztBQUM1RSxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUMxRCxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFDM0QsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLGtDQUFrQyxDQUFDO0FBQ2pFLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUVwRDs7OztHQUlHO0FBQ0gsTUFBTSxPQUFPLFNBQVM7SUFDcEIsaUdBQWlHO0lBQzFGLE1BQU07UUFDWCxPQUFPLEVBQUUsQ0FBQztJQUNaLENBQUM7SUFvQ0Q7O09BRUc7SUFDSCxZQUFZLFVBQTZCO1FBcENsQyxXQUFNLEdBQW1CLEVBQUUsQ0FBQztRQVUzQixXQUFNLEdBQUcsSUFBSSxVQUFVLEVBQUUsQ0FBQyxDQUFDLHNCQUFzQjtRQUl6RCxpQkFBaUI7UUFDVixjQUFTLEdBQUcsSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLFNBQVMsRUFBc0IsQ0FBQztRQUM1RCxtQkFBYyxHQUFnQixJ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
|
|
502
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaHR0cC1wcm94eS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3RzL3Byb3hpZXMvaHR0cC1wcm94eS9odHRwLXByb3h5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sa0JBQWtCLENBQUM7QUFDNUMsT0FBTyxFQUNMLFlBQVksR0FDYixNQUFNLG1CQUFtQixDQUFDO0FBQzNCLE9BQU8sRUFBRSxrQkFBa0IsSUFBSSxZQUFZLEVBQUUsTUFBTSxxQ0FBcUMsQ0FBQztBQU96RixPQUFPLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSxvQ0FBb0MsQ0FBQztBQUM1RSxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUM5RCxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDdEQsT0FBTyxFQUFFLGNBQWMsRUFBd0IsTUFBTSxzQkFBc0IsQ0FBQztBQUM1RSxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUMxRCxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFDM0QsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLGtDQUFrQyxDQUFDO0FBQ2pFLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUNwRCxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDeEQsT0FBTyxFQUFFLHlCQUF5QixFQUFFLE1BQU0sc0NBQXNDLENBQUM7QUFFakY7Ozs7R0FJRztBQUNILE1BQU0sT0FBTyxTQUFTO0lBQ3BCLGlHQUFpRztJQUMxRixNQUFNO1FBQ1gsT0FBTyxFQUFFLENBQUM7SUFDWixDQUFDO0lBcUNEOztPQUVHO0lBQ0gsWUFBWSxVQUE2QjtRQXJDbEMsV0FBTSxHQUFtQixFQUFFLENBQUM7UUFVM0IsV0FBTSxHQUFHLElBQUksVUFBVSxFQUFFLENBQUMsQ0FBQyxzQkFBc0I7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
|