@bitcall/webrtc-sip-gateway 0.3.3 → 0.3.5
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/README.md +8 -3
- package/lib/firewall.js +76 -18
- package/package.json +1 -1
- package/src/index.js +29 -13
package/README.md
CHANGED
|
@@ -7,10 +7,15 @@ Latest updates:
|
|
|
7
7
|
startup, so advertise/origin/SIP transport values are runtime-accurate.
|
|
8
8
|
- `init` and `reconfigure` stop an existing stack before preflight checks so
|
|
9
9
|
the gateway's own `:5060` listener does not trigger false port conflicts.
|
|
10
|
-
- `update` now syncs `BITCALL_GATEWAY_IMAGE` to the CLI target image tag
|
|
11
|
-
|
|
10
|
+
- `update` now syncs `BITCALL_GATEWAY_IMAGE` to the CLI target image tag,
|
|
11
|
+
pulls, and force-recreates containers so new image layers are applied.
|
|
12
12
|
- Docker image includes `sngrep` and `tcpdump` for SIP troubleshooting.
|
|
13
|
-
- `sip-trace` opens a live SIP message viewer using `sngrep` in the container
|
|
13
|
+
- `sip-trace` opens a live SIP message viewer using `sngrep` in the container
|
|
14
|
+
via compose service execution.
|
|
15
|
+
- Fixed nftables media firewall rule generation for IPv6 media-block mode
|
|
16
|
+
(nft-compatible port ranges and rule action order).
|
|
17
|
+
- Media firewall status now checks both nft and ip6tables marker rules so
|
|
18
|
+
legacy ip6tables protections are reported correctly.
|
|
14
19
|
- `TURN_MODE=coturn` now generates a compose stack with a dedicated coturn
|
|
15
20
|
container.
|
|
16
21
|
|
package/lib/firewall.js
CHANGED
|
@@ -94,8 +94,11 @@ function buildNftRuleset(options = {}) {
|
|
|
94
94
|
];
|
|
95
95
|
|
|
96
96
|
for (const rule of rules) {
|
|
97
|
+
const nftDport = String(rule.dport).includes(":")
|
|
98
|
+
? String(rule.dport).replace(":", "-")
|
|
99
|
+
: String(rule.dport);
|
|
97
100
|
lines.push(
|
|
98
|
-
` meta nfproto ipv6 ${rule.proto} dport ${
|
|
101
|
+
` meta nfproto ipv6 ${rule.proto} dport ${nftDport} drop comment \"${MARKER}\"`
|
|
99
102
|
);
|
|
100
103
|
}
|
|
101
104
|
|
|
@@ -282,8 +285,19 @@ function applyMediaIpv4OnlyRules(options = {}, runtime = {}) {
|
|
|
282
285
|
const backend = runtime.backend || detectFirewallBackend(d);
|
|
283
286
|
|
|
284
287
|
if (backend === "nft") {
|
|
285
|
-
|
|
286
|
-
|
|
288
|
+
try {
|
|
289
|
+
applyNftRules(options, d);
|
|
290
|
+
return { backend };
|
|
291
|
+
} catch (error) {
|
|
292
|
+
if (runtime.backend || !d.commandExists("ip6tables")) {
|
|
293
|
+
throw error;
|
|
294
|
+
}
|
|
295
|
+
applyIp6tablesRules(options, d);
|
|
296
|
+
return {
|
|
297
|
+
backend: "ip6tables",
|
|
298
|
+
fallbackFrom: "nft",
|
|
299
|
+
};
|
|
300
|
+
}
|
|
287
301
|
}
|
|
288
302
|
|
|
289
303
|
if (backend === "ip6tables") {
|
|
@@ -296,33 +310,77 @@ function applyMediaIpv4OnlyRules(options = {}, runtime = {}) {
|
|
|
296
310
|
|
|
297
311
|
function removeMediaIpv4OnlyRules(options = {}, runtime = {}) {
|
|
298
312
|
const d = withDeps(runtime.deps);
|
|
299
|
-
const backend = runtime.backend
|
|
313
|
+
const backend = runtime.backend;
|
|
300
314
|
|
|
301
|
-
if (backend
|
|
315
|
+
if (!backend) {
|
|
316
|
+
const removed = [];
|
|
317
|
+
|
|
318
|
+
if (d.commandExists("nft") && isNftPresent(d)) {
|
|
319
|
+
removeNftRules(d);
|
|
320
|
+
removed.push("nft");
|
|
321
|
+
}
|
|
322
|
+
if (d.commandExists("ip6tables") && isIp6tablesPresent(d)) {
|
|
323
|
+
removeIp6tablesRules(options, d);
|
|
324
|
+
removed.push("ip6tables");
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
if (removed.length > 0) {
|
|
328
|
+
return { backend: removed.join("+") };
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
const selectedBackend = backend || detectFirewallBackend(d);
|
|
333
|
+
|
|
334
|
+
if (selectedBackend === "nft") {
|
|
302
335
|
removeNftRules(d);
|
|
303
|
-
return { backend };
|
|
336
|
+
return { backend: selectedBackend };
|
|
304
337
|
}
|
|
305
338
|
|
|
306
|
-
if (
|
|
339
|
+
if (selectedBackend === "ip6tables") {
|
|
307
340
|
removeIp6tablesRules(options, d);
|
|
308
|
-
return { backend };
|
|
341
|
+
return { backend: selectedBackend };
|
|
309
342
|
}
|
|
310
343
|
|
|
311
|
-
throw new Error(`Unsupported firewall backend: ${
|
|
344
|
+
throw new Error(`Unsupported firewall backend: ${selectedBackend}`);
|
|
312
345
|
}
|
|
313
346
|
|
|
314
347
|
function isMediaIpv4OnlyRulesPresent(runtime = {}) {
|
|
315
348
|
const d = withDeps(runtime.deps);
|
|
316
|
-
|
|
349
|
+
const backend = runtime.backend;
|
|
350
|
+
|
|
351
|
+
if (!backend) {
|
|
352
|
+
const nftEnabled = d.commandExists("nft") ? isNftPresent(d) : false;
|
|
353
|
+
if (nftEnabled) {
|
|
354
|
+
return {
|
|
355
|
+
enabled: true,
|
|
356
|
+
backend: "nft",
|
|
357
|
+
marker: MARKER,
|
|
358
|
+
};
|
|
359
|
+
}
|
|
317
360
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
}
|
|
361
|
+
const ip6tablesEnabled = d.commandExists("ip6tables") ? isIp6tablesPresent(d) : false;
|
|
362
|
+
if (ip6tablesEnabled) {
|
|
363
|
+
return {
|
|
364
|
+
enabled: true,
|
|
365
|
+
backend: "ip6tables",
|
|
366
|
+
marker: MARKER,
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
try {
|
|
371
|
+
const preferredBackend = detectFirewallBackend(d);
|
|
372
|
+
return {
|
|
373
|
+
enabled: false,
|
|
374
|
+
backend: preferredBackend,
|
|
375
|
+
marker: MARKER,
|
|
376
|
+
};
|
|
377
|
+
} catch (error) {
|
|
378
|
+
return {
|
|
379
|
+
enabled: false,
|
|
380
|
+
backend: null,
|
|
381
|
+
error: error.message,
|
|
382
|
+
};
|
|
383
|
+
}
|
|
326
384
|
}
|
|
327
385
|
|
|
328
386
|
if (backend === "nft") {
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -1424,16 +1424,23 @@ function logsCommand(service, options) {
|
|
|
1424
1424
|
|
|
1425
1425
|
function sipTraceCommand() {
|
|
1426
1426
|
ensureInitialized();
|
|
1427
|
-
const
|
|
1428
|
-
const
|
|
1427
|
+
const serviceName = "gateway";
|
|
1428
|
+
const containerNameFallback = "bitcall-gateway";
|
|
1429
1429
|
|
|
1430
1430
|
// Check if sngrep is available in the container
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
{ cwd: GATEWAY_DIR, check: false, stdio: "pipe" }
|
|
1431
|
+
let check = runCompose(
|
|
1432
|
+
["exec", "-T", serviceName, "which", "sngrep"],
|
|
1433
|
+
{ check: false, stdio: "pipe" }
|
|
1435
1434
|
);
|
|
1436
1435
|
|
|
1436
|
+
// Backward-compatible fallback for stacks where service naming diverged.
|
|
1437
|
+
if (check.status !== 0) {
|
|
1438
|
+
check = run("docker", ["exec", containerNameFallback, "which", "sngrep"], {
|
|
1439
|
+
check: false,
|
|
1440
|
+
stdio: "pipe",
|
|
1441
|
+
});
|
|
1442
|
+
}
|
|
1443
|
+
|
|
1437
1444
|
if (check.status !== 0) {
|
|
1438
1445
|
console.error("sngrep is not available in this gateway image.");
|
|
1439
1446
|
console.error("Update to the latest image: sudo bitcall-gateway update");
|
|
@@ -1441,11 +1448,10 @@ function sipTraceCommand() {
|
|
|
1441
1448
|
}
|
|
1442
1449
|
|
|
1443
1450
|
// Run sngrep interactively inside the container
|
|
1444
|
-
const result =
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
);
|
|
1451
|
+
const result = runCompose(["exec", serviceName, "sngrep"], {
|
|
1452
|
+
check: false,
|
|
1453
|
+
stdio: "inherit",
|
|
1454
|
+
});
|
|
1449
1455
|
|
|
1450
1456
|
process.exit(result.status || 0);
|
|
1451
1457
|
}
|
|
@@ -1624,7 +1630,8 @@ function updateCommand() {
|
|
|
1624
1630
|
}
|
|
1625
1631
|
|
|
1626
1632
|
runCompose(["pull"], { stdio: "inherit" });
|
|
1627
|
-
|
|
1633
|
+
runCompose(["up", "-d", "--force-recreate", "--remove-orphans"], { stdio: "inherit" });
|
|
1634
|
+
run("systemctl", ["start", SERVICE_NAME], { check: false, stdio: "ignore" });
|
|
1628
1635
|
|
|
1629
1636
|
console.log(`\n${clr(_c.green, "✓")} Gateway updated to ${clr(_c.bold, PACKAGE_VERSION)}.`);
|
|
1630
1637
|
console.log(clr(_c.dim, " To update the CLI: sudo npm i -g @bitcall/webrtc-sip-gateway@latest"));
|
|
@@ -1835,7 +1842,16 @@ function buildProgram() {
|
|
|
1835
1842
|
|
|
1836
1843
|
async function main(argv = process.argv) {
|
|
1837
1844
|
const program = buildProgram();
|
|
1838
|
-
|
|
1845
|
+
const normalizedArgv = argv.map((value, index) => {
|
|
1846
|
+
if (index <= 1) {
|
|
1847
|
+
return value;
|
|
1848
|
+
}
|
|
1849
|
+
if (value === "--sip-trace" || value === "-sip-trace") {
|
|
1850
|
+
return "sip-trace";
|
|
1851
|
+
}
|
|
1852
|
+
return value;
|
|
1853
|
+
});
|
|
1854
|
+
await program.parseAsync(normalizedArgv);
|
|
1839
1855
|
}
|
|
1840
1856
|
|
|
1841
1857
|
module.exports = {
|