Files
smartnftables/ts/nft.rulebuilder.nat.ts
2026-03-26 10:32:05 +00:00

83 lines
2.1 KiB
TypeScript

import type { TNftFamily, TNftProtocol, INftDnatRule, INftSnatRule, INftMasqueradeRule } from './nft.types.js';
/**
* Expand a protocol spec into concrete protocol strings.
*/
function expandProtocols(protocol?: TNftProtocol): string[] {
switch (protocol ?? 'tcp') {
case 'tcp': return ['tcp'];
case 'udp': return ['udp'];
case 'both': return ['tcp', 'udp'];
}
}
/**
* Build DNAT rules for port forwarding.
* Generates DNAT + optional masquerade for each protocol.
* Direct port of Rust build_dnat_rule.
*/
export function buildDnatRules(
tableName: string,
family: TNftFamily,
rule: INftDnatRule,
): string[] {
const protocols = expandProtocols(rule.protocol);
const commands: string[] = [];
for (const proto of protocols) {
// DNAT rule
commands.push(
`nft add rule ${family} ${tableName} prerouting ${proto} dport ${rule.sourcePort} dnat to ${rule.targetHost}:${rule.targetPort}`
);
// Masquerade (SNAT) unless preserveSourceIP is set
if (!rule.preserveSourceIP) {
commands.push(
`nft add rule ${family} ${tableName} postrouting ${proto} dport ${rule.targetPort} masquerade`
);
}
}
return commands;
}
/**
* Build an SNAT rule to rewrite source address.
*/
export function buildSnatRule(
tableName: string,
family: TNftFamily,
rule: INftSnatRule,
): string[] {
const protocols = expandProtocols(rule.protocol);
const commands: string[] = [];
for (const proto of protocols) {
commands.push(
`nft add rule ${family} ${tableName} postrouting ${proto} dport ${rule.targetPort} snat to ${rule.sourceAddress}`
);
}
return commands;
}
/**
* Build a masquerade rule for outgoing NAT.
*/
export function buildMasqueradeRule(
tableName: string,
family: TNftFamily,
rule: INftMasqueradeRule,
): string[] {
const protocols = expandProtocols(rule.protocol);
const commands: string[] = [];
for (const proto of protocols) {
commands.push(
`nft add rule ${family} ${tableName} postrouting ${proto} dport ${rule.targetPort} masquerade`
);
}
return commands;
}