@opensecurity/zonzon-core 0.1.6 → 0.1.9
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/http-handler.js +43 -15
- package/dist/sni-proxy.js +9 -2
- package/package.json +1 -1
package/dist/http-handler.js
CHANGED
|
@@ -96,16 +96,19 @@ export class HttpHandler {
|
|
|
96
96
|
const targetUrl = req.url || "";
|
|
97
97
|
const [hostname, portStr] = targetUrl.split(':');
|
|
98
98
|
const port = portStr ? parseInt(portStr, 10) : 443;
|
|
99
|
+
let srvSocket = null;
|
|
99
100
|
try {
|
|
100
101
|
const validatedIps = await this.proxyService.validateTargetFirewall(`https://${hostname}:${port}`, this.config.firewall);
|
|
101
102
|
const targetIp = validatedIps[0];
|
|
102
103
|
audit.http(clientIp, "CONNECT", hostname, `:${port}`, 200, `TCP Tunnel Established -> ${targetIp}`);
|
|
103
104
|
clientSocket.setTimeout(this.idleTimeoutMs);
|
|
104
105
|
clientSocket.on("timeout", () => {
|
|
105
|
-
audit.error(`CONNECT Client tunnel idle timeout reached for ${clientIp}`);
|
|
106
106
|
clientSocket.destroy();
|
|
107
|
+
if (srvSocket && !srvSocket.destroyed) {
|
|
108
|
+
srvSocket.destroy();
|
|
109
|
+
}
|
|
107
110
|
});
|
|
108
|
-
|
|
111
|
+
srvSocket = net.connect(port, targetIp, () => {
|
|
109
112
|
clientSocket.write('HTTP/1.1 200 Connection Established\r\n\r\n');
|
|
110
113
|
if (head && head.length > 0) {
|
|
111
114
|
srvSocket.write(head);
|
|
@@ -115,18 +118,29 @@ export class HttpHandler {
|
|
|
115
118
|
});
|
|
116
119
|
srvSocket.setTimeout(this.idleTimeoutMs);
|
|
117
120
|
srvSocket.on("timeout", () => {
|
|
118
|
-
audit.error(`CONNECT Upstream tunnel idle timeout reached for ${hostname}:${port}`);
|
|
119
121
|
srvSocket.destroy();
|
|
122
|
+
if (!clientSocket.destroyed) {
|
|
123
|
+
clientSocket.destroy();
|
|
124
|
+
}
|
|
120
125
|
});
|
|
121
126
|
this.activeConnections.add(srvSocket);
|
|
122
|
-
srvSocket.on('close', () =>
|
|
127
|
+
srvSocket.on('close', () => {
|
|
128
|
+
this.activeConnections.delete(srvSocket);
|
|
129
|
+
if (!clientSocket.destroyed) {
|
|
130
|
+
clientSocket.destroy();
|
|
131
|
+
}
|
|
132
|
+
});
|
|
123
133
|
srvSocket.on('error', (err) => {
|
|
124
134
|
audit.error(`Upstream tunnel fault on ${hostname}:${port} - ${err.message}`);
|
|
125
135
|
if (!clientSocket.destroyed)
|
|
126
136
|
clientSocket.destroy();
|
|
127
137
|
});
|
|
128
138
|
clientSocket.on('error', (err) => {
|
|
129
|
-
if (!srvSocket.destroyed)
|
|
139
|
+
if (srvSocket && !srvSocket.destroyed)
|
|
140
|
+
srvSocket.destroy();
|
|
141
|
+
});
|
|
142
|
+
clientSocket.on('close', () => {
|
|
143
|
+
if (srvSocket && !srvSocket.destroyed)
|
|
130
144
|
srvSocket.destroy();
|
|
131
145
|
});
|
|
132
146
|
}
|
|
@@ -353,17 +367,31 @@ export class HttpHandler {
|
|
|
353
367
|
return;
|
|
354
368
|
}
|
|
355
369
|
}
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
370
|
+
const isLiteralIp = net.isIP(hostname) !== 0;
|
|
371
|
+
if (isLiteralIp) {
|
|
372
|
+
if (firewallEngine.evaluateIp(hostname, this.config.firewall) === "DENY") {
|
|
373
|
+
audit.http(clientIp, reqMethod, hostname, reqUrl, 403, "Blocked by IP Firewall");
|
|
374
|
+
res.writeHead(403);
|
|
375
|
+
res.end("Forbidden");
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
else {
|
|
380
|
+
if (firewallEngine.evaluateDomain(hostname, this.config.firewall) === "DENY") {
|
|
381
|
+
audit.http(clientIp, reqMethod, hostname, reqUrl, 403, "Blocked by Domain Firewall");
|
|
382
|
+
res.writeHead(403);
|
|
383
|
+
res.end("Forbidden");
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
let targetIp = hostname;
|
|
388
|
+
if (!isLiteralIp) {
|
|
389
|
+
const records = await dns.resolve(hostname);
|
|
390
|
+
const targetIps = records.filter(ip => typeof ip === "string");
|
|
391
|
+
if (targetIps.length === 0)
|
|
392
|
+
throw new Error("NXDOMAIN");
|
|
393
|
+
targetIp = targetIps[0];
|
|
361
394
|
}
|
|
362
|
-
const records = await dns.resolve(hostname);
|
|
363
|
-
const targetIps = records.filter(ip => typeof ip === "string");
|
|
364
|
-
if (targetIps.length === 0)
|
|
365
|
-
throw new Error("NXDOMAIN");
|
|
366
|
-
const targetIp = targetIps[0];
|
|
367
395
|
if (firewallEngine.evaluateIp(targetIp, this.config.firewall) === "DENY") {
|
|
368
396
|
audit.http(clientIp, reqMethod, hostname, reqUrl, 403, "Blocked by IP Firewall");
|
|
369
397
|
res.writeHead(403);
|
package/dist/sni-proxy.js
CHANGED
|
@@ -75,8 +75,10 @@ export class SniProxyService {
|
|
|
75
75
|
let upstreamSocket = null;
|
|
76
76
|
clientSocket.setTimeout(this.idleTimeoutMs);
|
|
77
77
|
clientSocket.on("timeout", () => {
|
|
78
|
-
audit.error(`SNI Client tunnel idle timeout reached for ${clientIp}`);
|
|
79
78
|
clientSocket.destroy();
|
|
79
|
+
if (upstreamSocket && !upstreamSocket.destroyed) {
|
|
80
|
+
upstreamSocket.destroy();
|
|
81
|
+
}
|
|
80
82
|
});
|
|
81
83
|
const absoluteHandshakeTimeout = setTimeout(() => {
|
|
82
84
|
if (!isHandled && !clientSocket.destroyed) {
|
|
@@ -131,12 +133,17 @@ export class SniProxyService {
|
|
|
131
133
|
});
|
|
132
134
|
upstreamSocket.setTimeout(this.idleTimeoutMs);
|
|
133
135
|
upstreamSocket.on("timeout", () => {
|
|
134
|
-
audit.error(`SNI Upstream tunnel idle timeout reached for ${sni}:${targetIp}`);
|
|
135
136
|
upstreamSocket.destroy();
|
|
137
|
+
if (!clientSocket.destroyed) {
|
|
138
|
+
clientSocket.destroy();
|
|
139
|
+
}
|
|
136
140
|
});
|
|
137
141
|
this.activeConnections.add(upstreamSocket);
|
|
138
142
|
upstreamSocket.on("close", () => {
|
|
139
143
|
this.activeConnections.delete(upstreamSocket);
|
|
144
|
+
if (!clientSocket.destroyed) {
|
|
145
|
+
clientSocket.destroy();
|
|
146
|
+
}
|
|
140
147
|
});
|
|
141
148
|
upstreamSocket.on("error", (err) => {
|
|
142
149
|
audit.error(`Upstream tunnel fault on ${sni}:443 - ${err.message}`);
|