@opensecurity/zonzon-core 0.1.4 → 0.1.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.
@@ -245,7 +245,6 @@ function buildNoErrorResponse(id, flags, questions) {
245
245
  export class DevDnsServer {
246
246
  config;
247
247
  cacheMap = new Map();
248
- cacheOrder = [];
249
248
  dnsCacheMaxSize;
250
249
  dnsCacheTtlMs;
251
250
  constructor(config) {
@@ -279,10 +278,10 @@ export class DevDnsServer {
279
278
  return questions.map((q) => `${q.name}:${q.type}`).join("|");
280
279
  }
281
280
  evictCacheEntry() {
282
- if (this.cacheOrder.length === 0)
283
- return;
284
- const oldestKey = this.cacheOrder.shift();
285
- this.cacheMap.delete(oldestKey);
281
+ const oldestKey = this.cacheMap.keys().next().value;
282
+ if (oldestKey !== undefined) {
283
+ this.cacheMap.delete(oldestKey);
284
+ }
286
285
  }
287
286
  getFromCache(key) {
288
287
  const entry = this.cacheMap.get(key);
@@ -290,15 +289,10 @@ export class DevDnsServer {
290
289
  return null;
291
290
  if (this.dnsCacheTtlMs > 0 && Date.now() - entry.insertedAt >= this.dnsCacheTtlMs) {
292
291
  this.cacheMap.delete(key);
293
- const idx = this.cacheOrder.indexOf(key);
294
- if (idx >= 0)
295
- this.cacheOrder.splice(idx, 1);
296
292
  return null;
297
293
  }
298
- const idx = this.cacheOrder.indexOf(key);
299
- if (idx >= 0)
300
- this.cacheOrder.splice(idx, 1);
301
- this.cacheOrder.push(key);
294
+ this.cacheMap.delete(key);
295
+ this.cacheMap.set(key, entry);
302
296
  const remainingTtlMs = Math.max(0, this.dnsCacheTtlMs - (Date.now() - entry.insertedAt));
303
297
  entry.ttlMs = remainingTtlMs;
304
298
  return entry;
@@ -306,7 +300,7 @@ export class DevDnsServer {
306
300
  addToCache(key, response) {
307
301
  if (this.dnsCacheTtlMs <= 0)
308
302
  return;
309
- while (this.cacheOrder.length >= this.dnsCacheMaxSize) {
303
+ while (this.cacheMap.size >= this.dnsCacheMaxSize) {
310
304
  this.evictCacheEntry();
311
305
  }
312
306
  const remainingSeconds = Math.max(1, Math.floor(this.dnsCacheTtlMs / 1000));
@@ -316,11 +310,8 @@ export class DevDnsServer {
316
310
  insertedAt: Date.now(),
317
311
  ttlMs: this.dnsCacheTtlMs,
318
312
  };
313
+ this.cacheMap.delete(key);
319
314
  this.cacheMap.set(key, entry);
320
- const idx = this.cacheOrder.indexOf(key);
321
- if (idx >= 0)
322
- this.cacheOrder.splice(idx, 1);
323
- this.cacheOrder.push(key);
324
315
  }
325
316
  skipQuestionSection(buffer, offset) {
326
317
  const savedOffset = offset;
@@ -1,5 +1,5 @@
1
1
  import { describe, it } from "node:test";
2
- import assert from "assert";
2
+ import assert from "node:assert";
3
3
  import { DevDnsServer } from "./dns-service.js";
4
4
  import { DNS_TYPES, DNS_RCODE } from "./types.js";
5
5
  function buildQuery(name, type) {
@@ -1,5 +1,5 @@
1
1
  import { describe, it } from "node:test";
2
- import assert from "assert";
2
+ import assert from "node:assert";
3
3
  import { DevDnsServer } from "./dns-service.js";
4
4
  import { DNS_TYPES, DNS_RCODE } from "./types.js";
5
5
  function buildQuery(name, type) {
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,104 @@
1
+ import { describe, it } from "node:test";
2
+ import assert from "node:assert";
3
+ import { DnsHandler } from "./dns-handler.js";
4
+ import { DevDnsServer } from "./dns-service.js";
5
+ function createMockReqRes(method, url, headers = {}) {
6
+ const req = {
7
+ method,
8
+ url,
9
+ headers,
10
+ socket: { remoteAddress: "127.0.0.1" },
11
+ destroy: () => { }
12
+ };
13
+ let statusCode = 0;
14
+ let endData = null;
15
+ const resHeaders = {};
16
+ const res = {
17
+ writeHead: (code, headers) => {
18
+ statusCode = code;
19
+ if (headers)
20
+ Object.assign(resHeaders, headers);
21
+ },
22
+ end: (data) => {
23
+ endData = data;
24
+ }
25
+ };
26
+ return { req, res, getStatus: () => statusCode, getEndData: () => endData, getHeaders: () => resHeaders };
27
+ }
28
+ describe("Modern DNS Protocols (DoH)", () => {
29
+ const config = {
30
+ port: 53,
31
+ hosts: {}
32
+ };
33
+ const server = new DevDnsServer(config);
34
+ const handler = new DnsHandler(server, config);
35
+ it("rejects DoH request on invalid path", async () => {
36
+ const { req, res, getStatus } = createMockReqRes("GET", "/invalid-path");
37
+ // @ts-ignore - Accessing private method for strict L7 unit testing
38
+ await handler.handleDohRequest(req, res);
39
+ assert.strictEqual(getStatus(), 404);
40
+ });
41
+ it("rejects DoH GET request missing dns query parameter", async () => {
42
+ const { req, res, getStatus } = createMockReqRes("GET", "/dns-query");
43
+ // @ts-ignore
44
+ await handler.handleDohRequest(req, res);
45
+ assert.strictEqual(getStatus(), 400);
46
+ });
47
+ it("rejects DoH GET request with invalid base64url payload", async () => {
48
+ const { req, res, getStatus } = createMockReqRes("GET", "/dns-query?dns=!!!invalid_base64!!!");
49
+ // @ts-ignore
50
+ await handler.handleDohRequest(req, res);
51
+ assert.strictEqual(getStatus(), 400);
52
+ });
53
+ it("rejects DoH POST request with invalid content-type", async () => {
54
+ const { req, res, getStatus } = createMockReqRes("POST", "/dns-query", {
55
+ "content-type": "application/json"
56
+ });
57
+ // @ts-ignore
58
+ await handler.handleDohRequest(req, res);
59
+ assert.strictEqual(getStatus(), 415);
60
+ });
61
+ it("rejects unsupported HTTP methods", async () => {
62
+ const { req, res, getStatus } = createMockReqRes("PUT", "/dns-query");
63
+ // @ts-ignore
64
+ await handler.handleDohRequest(req, res);
65
+ assert.strictEqual(getStatus(), 405);
66
+ });
67
+ it("rejects payloads that are too short to be valid DNS packets", async () => {
68
+ const { req, res, getStatus } = createMockReqRes("GET", "/dns-query?dns=abcd");
69
+ // @ts-ignore
70
+ await handler.handleDohRequest(req, res);
71
+ assert.strictEqual(getStatus(), 400);
72
+ });
73
+ it("enforces memory bounds on DoH POST payloads to prevent exhaustion", async () => {
74
+ const { req, res, getStatus } = createMockReqRes("POST", "/dns-query", {
75
+ "content-type": "application/dns-message"
76
+ });
77
+ const oversizedBuffer = Buffer.alloc(65 * 1024); // Exceeds MAX_TCP_BUFFER_SIZE (64KB)
78
+ req[Symbol.asyncIterator] = async function* () {
79
+ yield oversizedBuffer;
80
+ };
81
+ // @ts-ignore
82
+ await handler.handleDohRequest(req, res);
83
+ assert.strictEqual(getStatus(), 413);
84
+ });
85
+ it("processes a structurally valid DoH POST request", async () => {
86
+ const { req, res, getStatus, getHeaders } = createMockReqRes("POST", "/dns-query", {
87
+ "content-type": "application/dns-message"
88
+ });
89
+ // Create a minimal 12-byte valid DNS header
90
+ const validDnsHeader = Buffer.alloc(12);
91
+ validDnsHeader.writeUInt16BE(0x1234, 0); // ID
92
+ validDnsHeader.writeUInt16BE(0x0100, 2); // Flags (Standard Query)
93
+ validDnsHeader.writeUInt16BE(0x0000, 4); // QDCOUNT
94
+ req[Symbol.asyncIterator] = async function* () {
95
+ yield validDnsHeader;
96
+ };
97
+ // @ts-ignore
98
+ await handler.handleDohRequest(req, res);
99
+ assert.strictEqual(getStatus(), 200);
100
+ const headers = getHeaders();
101
+ assert.strictEqual(headers["Content-Type"], "application/dns-message");
102
+ assert.strictEqual(headers["Cache-Control"], "max-age=0");
103
+ });
104
+ });
@@ -3,6 +3,8 @@ export declare class FirewallEngine {
3
3
  private ipToInt;
4
4
  private matchCidr;
5
5
  private matchDomain;
6
+ isRestrictedOutbound(ip: string): boolean;
7
+ evaluateOutbound(ip: string, fw?: FirewallConfig): "ALLOW" | "DENY";
6
8
  evaluateIp(ip: string, fw?: FirewallConfig): "ALLOW" | "DENY";
7
9
  evaluateDomain(domain: string, fw?: FirewallConfig): "ALLOW" | "DENY";
8
10
  }
package/dist/firewall.js CHANGED
@@ -1,4 +1,4 @@
1
- import * as net from "net";
1
+ import * as net from "node:net";
2
2
  export class FirewallEngine {
3
3
  ipToInt(ip) {
4
4
  return ip.split('.').reduce((int, octet) => (int << 8) + parseInt(octet, 10), 0) >>> 0;
@@ -22,26 +22,85 @@ export class FirewallEngine {
22
22
  return true;
23
23
  if (normPattern.startsWith("*.")) {
24
24
  const suffix = normPattern.slice(2);
25
- return normDomain === suffix || normDomain.endsWith("." + suffix);
25
+ return normDomain.endsWith("." + suffix);
26
26
  }
27
27
  return false;
28
28
  }
29
+ isRestrictedOutbound(ip) {
30
+ if (net.isIPv6(ip)) {
31
+ const normalized = ip.toLowerCase();
32
+ if (normalized === "::1")
33
+ return true;
34
+ if (normalized === "::")
35
+ return true;
36
+ if (normalized.startsWith("fe80:"))
37
+ return true;
38
+ if (normalized.startsWith("fc00:") || normalized.startsWith("fd"))
39
+ return true;
40
+ if (normalized.includes("::ffff:127."))
41
+ return true;
42
+ if (normalized.includes("::ffff:169.254."))
43
+ return true;
44
+ return false;
45
+ }
46
+ if (!net.isIPv4(ip))
47
+ return true;
48
+ const parts = ip.split('.').map(Number);
49
+ if (parts[0] === 0)
50
+ return true;
51
+ if (parts[0] === 10)
52
+ return true;
53
+ if (parts[0] === 127)
54
+ return true;
55
+ if (parts[0] === 100 && parts[1] >= 64 && parts[1] <= 127)
56
+ return true;
57
+ if (parts[0] === 169 && parts[1] === 254)
58
+ return true;
59
+ if (parts[0] === 172 && parts[1] >= 16 && parts[1] <= 31)
60
+ return true;
61
+ if (parts[0] === 192 && parts[1] === 168)
62
+ return true;
63
+ if (parts[0] >= 224 && parts[0] <= 239)
64
+ return true;
65
+ if (parts[0] >= 240 && parts[0] <= 255)
66
+ return true;
67
+ return false;
68
+ }
69
+ evaluateOutbound(ip, fw) {
70
+ if (fw) {
71
+ if (fw.allowlist_ips && fw.allowlist_ips.includes(ip))
72
+ return "ALLOW";
73
+ if (net.isIPv4(ip)) {
74
+ for (const range of fw.allowlist_ranges || []) {
75
+ if (this.matchCidr(ip, range))
76
+ return "ALLOW";
77
+ }
78
+ }
79
+ }
80
+ if (this.isRestrictedOutbound(ip))
81
+ return "DENY";
82
+ return "ALLOW";
83
+ }
29
84
  evaluateIp(ip, fw) {
30
85
  if (!fw)
31
86
  return "ALLOW";
32
- if (!net.isIPv4(ip))
87
+ if (!net.isIPv4(ip) && !net.isIPv6(ip))
33
88
  return "DENY";
34
89
  if (fw.blocklist_ips && fw.blocklist_ips.includes(ip))
35
90
  return "DENY";
36
- for (const range of fw.blocklist_ranges || []) {
37
- if (this.matchCidr(ip, range))
38
- return "DENY";
91
+ if (net.isIPv4(ip)) {
92
+ for (const range of fw.blocklist_ranges || []) {
93
+ if (this.matchCidr(ip, range))
94
+ return "DENY";
95
+ }
39
96
  }
40
97
  if (fw.allowlist_ips && fw.allowlist_ips.includes(ip))
41
98
  return "ALLOW";
42
- for (const range of fw.allowlist_ranges || []) {
43
- if (this.matchCidr(ip, range))
44
- return "ALLOW";
99
+ if (net.isIPv4(ip)) {
100
+ for (const range of fw.allowlist_ranges || []) {
101
+ if (this.matchCidr(ip, range))
102
+ return "ALLOW";
103
+ }
45
104
  }
46
105
  return fw.defaultPolicy === "allow" ? "ALLOW" : "DENY";
47
106
  }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,165 @@
1
+ import { describe, it } from "node:test";
2
+ import assert from "node:assert";
3
+ import { FirewallEngine } from "./firewall.js";
4
+ describe("FirewallEngine - Domain Evaluation", () => {
5
+ const engine = new FirewallEngine();
6
+ it("returns ALLOW when firewall config is undefined", () => {
7
+ assert.strictEqual(engine.evaluateDomain("example.com"), "ALLOW");
8
+ });
9
+ it("respects default deny policy", () => {
10
+ const config = { defaultPolicy: "deny" };
11
+ assert.strictEqual(engine.evaluateDomain("example.com", config), "DENY");
12
+ });
13
+ it("respects default allow policy", () => {
14
+ const config = { defaultPolicy: "allow" };
15
+ assert.strictEqual(engine.evaluateDomain("example.com", config), "ALLOW");
16
+ });
17
+ it("blocks explicitly blocklisted domains", () => {
18
+ const config = {
19
+ defaultPolicy: "allow",
20
+ blocklist_domains: ["evil.com"],
21
+ };
22
+ assert.strictEqual(engine.evaluateDomain("evil.com", config), "DENY");
23
+ });
24
+ it("allows explicitly allowlisted domains overriding default deny", () => {
25
+ const config = {
26
+ defaultPolicy: "deny",
27
+ allowlist_domains: ["good.com"],
28
+ };
29
+ assert.strictEqual(engine.evaluateDomain("good.com", config), "ALLOW");
30
+ });
31
+ it("prioritizes blocklist over allowlist", () => {
32
+ const config = {
33
+ defaultPolicy: "allow",
34
+ allowlist_domains: ["conflict.com"],
35
+ blocklist_domains: ["conflict.com"],
36
+ };
37
+ assert.strictEqual(engine.evaluateDomain("conflict.com", config), "DENY");
38
+ });
39
+ it("supports exact domain matching case-insensitively", () => {
40
+ const config = {
41
+ defaultPolicy: "deny",
42
+ allowlist_domains: ["secure.loop"],
43
+ };
44
+ assert.strictEqual(engine.evaluateDomain("SECURE.LOOP", config), "ALLOW");
45
+ });
46
+ it("supports wildcard domain matching", () => {
47
+ const config = {
48
+ defaultPolicy: "deny",
49
+ allowlist_domains: ["*.internal.net"],
50
+ };
51
+ assert.strictEqual(engine.evaluateDomain("api.internal.net", config), "ALLOW");
52
+ assert.strictEqual(engine.evaluateDomain("db.internal.net", config), "ALLOW");
53
+ assert.strictEqual(engine.evaluateDomain("internal.net", config), "DENY");
54
+ });
55
+ it("handles trailing dots seamlessly", () => {
56
+ const config = {
57
+ defaultPolicy: "deny",
58
+ allowlist_domains: ["trailing.loop"],
59
+ };
60
+ assert.strictEqual(engine.evaluateDomain("trailing.loop.", config), "ALLOW");
61
+ });
62
+ });
63
+ describe("FirewallEngine - IP Evaluation", () => {
64
+ const engine = new FirewallEngine();
65
+ it("blocks malformed IPs universally", () => {
66
+ const config = { defaultPolicy: "allow" };
67
+ assert.strictEqual(engine.evaluateIp("not.an.ip", config), "DENY");
68
+ assert.strictEqual(engine.evaluateIp("999.999.999.999", config), "DENY");
69
+ });
70
+ it("blocks explicitly blocklisted IPs", () => {
71
+ const config = {
72
+ defaultPolicy: "allow",
73
+ blocklist_ips: ["192.168.1.100"],
74
+ };
75
+ assert.strictEqual(engine.evaluateIp("192.168.1.100", config), "DENY");
76
+ });
77
+ it("blocks IPs matching blocklist CIDR ranges", () => {
78
+ const config = {
79
+ defaultPolicy: "allow",
80
+ blocklist_ranges: ["10.0.0.0/8"],
81
+ };
82
+ assert.strictEqual(engine.evaluateIp("10.5.5.5", config), "DENY");
83
+ assert.strictEqual(engine.evaluateIp("11.0.0.1", config), "ALLOW");
84
+ });
85
+ it("allows IPs matching allowlist CIDR ranges overriding default deny", () => {
86
+ const config = {
87
+ defaultPolicy: "deny",
88
+ allowlist_ranges: ["172.16.0.0/12"],
89
+ };
90
+ assert.strictEqual(engine.evaluateIp("172.20.5.1", config), "ALLOW");
91
+ assert.strictEqual(engine.evaluateIp("192.168.1.1", config), "DENY");
92
+ });
93
+ it("prioritizes IP blocklist over IP allowlist", () => {
94
+ const config = {
95
+ defaultPolicy: "deny",
96
+ allowlist_ips: ["1.1.1.1"],
97
+ blocklist_ips: ["1.1.1.1"],
98
+ };
99
+ assert.strictEqual(engine.evaluateIp("1.1.1.1", config), "DENY");
100
+ });
101
+ it("safely ignores malformed CIDR ranges without crashing", () => {
102
+ const config = {
103
+ defaultPolicy: "deny",
104
+ allowlist_ranges: ["invalid/cidr/string"],
105
+ allowlist_ips: ["8.8.8.8"]
106
+ };
107
+ assert.strictEqual(engine.evaluateIp("8.8.8.8", config), "ALLOW");
108
+ assert.strictEqual(engine.evaluateIp("1.1.1.1", config), "DENY");
109
+ });
110
+ });
111
+ describe("FirewallEngine - Outbound SSRF Protection", () => {
112
+ const engine = new FirewallEngine();
113
+ it("blocks IPv4 loopback addresses natively", () => {
114
+ assert.strictEqual(engine.isRestrictedOutbound("127.0.0.1"), true);
115
+ assert.strictEqual(engine.isRestrictedOutbound("127.255.255.254"), true);
116
+ });
117
+ it("blocks IPv4 RFC1918 private network addresses natively", () => {
118
+ assert.strictEqual(engine.isRestrictedOutbound("10.0.0.1"), true);
119
+ assert.strictEqual(engine.isRestrictedOutbound("172.16.0.1"), true);
120
+ assert.strictEqual(engine.isRestrictedOutbound("172.31.255.255"), true);
121
+ assert.strictEqual(engine.isRestrictedOutbound("192.168.1.1"), true);
122
+ });
123
+ it("blocks IPv4 link-local and broadcast addresses natively", () => {
124
+ assert.strictEqual(engine.isRestrictedOutbound("169.254.169.254"), true);
125
+ assert.strictEqual(engine.isRestrictedOutbound("0.0.0.0"), true);
126
+ assert.strictEqual(engine.isRestrictedOutbound("224.0.0.1"), true);
127
+ assert.strictEqual(engine.isRestrictedOutbound("255.255.255.255"), true);
128
+ });
129
+ it("blocks IPv4 Carrier-Grade NAT addresses natively", () => {
130
+ assert.strictEqual(engine.isRestrictedOutbound("100.64.0.1"), true);
131
+ assert.strictEqual(engine.isRestrictedOutbound("100.127.255.254"), true);
132
+ });
133
+ it("allows standard public IPv4 addresses", () => {
134
+ assert.strictEqual(engine.isRestrictedOutbound("8.8.8.8"), false);
135
+ assert.strictEqual(engine.isRestrictedOutbound("1.1.1.1"), false);
136
+ assert.strictEqual(engine.isRestrictedOutbound("104.21.5.1"), false);
137
+ });
138
+ it("blocks IPv6 loopback and unspecified addresses natively", () => {
139
+ assert.strictEqual(engine.isRestrictedOutbound("::1"), true);
140
+ assert.strictEqual(engine.isRestrictedOutbound("::"), true);
141
+ });
142
+ it("blocks IPv6 link-local and unique local addresses natively", () => {
143
+ assert.strictEqual(engine.isRestrictedOutbound("fe80::1"), true);
144
+ assert.strictEqual(engine.isRestrictedOutbound("fc00::1"), true);
145
+ assert.strictEqual(engine.isRestrictedOutbound("fd00::1"), true);
146
+ });
147
+ it("blocks IPv4-mapped IPv6 addresses for restricted ranges", () => {
148
+ assert.strictEqual(engine.isRestrictedOutbound("::ffff:127.0.0.1"), true);
149
+ assert.strictEqual(engine.isRestrictedOutbound("::ffff:169.254.169.254"), true);
150
+ });
151
+ it("allows configured overrides for restricted IPs via allowlist", () => {
152
+ const config = {
153
+ defaultPolicy: "deny",
154
+ allowlist_ips: ["127.0.0.1"],
155
+ };
156
+ assert.strictEqual(engine.evaluateOutbound("127.0.0.1", config), "ALLOW");
157
+ });
158
+ it("allows configured overrides for restricted IPs via CIDR", () => {
159
+ const config = {
160
+ defaultPolicy: "deny",
161
+ allowlist_ranges: ["10.0.0.0/8"],
162
+ };
163
+ assert.strictEqual(engine.evaluateOutbound("10.5.0.1", config), "ALLOW");
164
+ });
165
+ });
@@ -1,5 +1,5 @@
1
1
  import { describe, it } from "node:test";
2
- import assert from "assert";
2
+ import assert from "node:assert";
3
3
  import * as http from "http";
4
4
  describe("HTTP Body Forwarding Integration", () => {
5
5
  let upstreamServer;
@@ -131,6 +131,9 @@ describe("HTTP Body Forwarding Integration", () => {
131
131
  try {
132
132
  const config = {
133
133
  port: 53,
134
+ firewall: {
135
+ allowlist_ips: ["127.0.0.1"]
136
+ },
134
137
  hosts: {
135
138
  "app.loop": {
136
139
  records: [{ type: "A", address: "127.0.0.1" }],
@@ -170,6 +173,9 @@ describe("HTTP Body Forwarding Integration", () => {
170
173
  try {
171
174
  const config = {
172
175
  port: 53,
176
+ firewall: {
177
+ allowlist_ips: ["127.0.0.1"]
178
+ },
173
179
  hosts: {
174
180
  "app.loop": {
175
181
  records: [{ type: "A", address: "127.0.0.1" }],
@@ -209,6 +215,9 @@ describe("HTTP Body Forwarding Integration", () => {
209
215
  try {
210
216
  const config = {
211
217
  port: 53,
218
+ firewall: {
219
+ allowlist_ips: ["127.0.0.1"]
220
+ },
212
221
  hosts: {
213
222
  "app.loop": {
214
223
  records: [{ type: "A", address: "127.0.0.1" }],
@@ -246,6 +255,9 @@ describe("HTTP Body Forwarding Integration", () => {
246
255
  try {
247
256
  const config = {
248
257
  port: 53,
258
+ firewall: {
259
+ allowlist_ips: ["127.0.0.1"]
260
+ },
249
261
  hosts: {
250
262
  "app.loop": {
251
263
  records: [{ type: "A", address: "127.0.0.1" }],
@@ -285,6 +297,9 @@ describe("HTTP Body Forwarding Integration", () => {
285
297
  try {
286
298
  const config = {
287
299
  port: 53,
300
+ firewall: {
301
+ allowlist_ips: ["127.0.0.1"]
302
+ },
288
303
  hosts: {
289
304
  "app.loop": {
290
305
  records: [{ type: "A", address: "127.0.0.1" }],
@@ -1,5 +1,5 @@
1
1
  import { describe, it } from "node:test";
2
- import assert from "assert";
2
+ import assert from "node:assert";
3
3
  import { HttpProxyService } from "./http-proxy.js";
4
4
  function makeBodyForwardingConfig() {
5
5
  return {
@@ -8,11 +8,13 @@ export declare class HttpHandler {
8
8
  private server;
9
9
  private circuitBreakers;
10
10
  private activeConnections;
11
+ private idleTimeoutMs;
11
12
  constructor(dnsServer: DevDnsServer, config: ServerConfig, port?: number);
12
13
  private getCircuitBreaker;
13
14
  private findWildcardHost;
14
- private injectCustomHeaders;
15
15
  private handleConnect;
16
+ private doHttpProxy;
17
+ private readRequestBodySafe;
16
18
  private handleForwardProxy;
17
19
  private handleRequest;
18
20
  start(): Promise<void>;