summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJo-Philipp Wich2022-01-27 15:23:23 +0000
committerJo-Philipp Wich2022-01-28 08:42:52 +0000
commit0df6ba035bfa87976ae66cb6403887c439af4df9 (patch)
tree273689e711764471c8fe2f7b596b6f75ba98ce58
parentc08eb4478d50ccc903987160fa3535457fdb3289 (diff)
downloadfirewall4-0df6ba035bfa87976ae66cb6403887c439af4df9.tar.gz
fw4: fix address selection logic for DNAT reflection rules
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
-rw-r--r--root/usr/share/ucode/fw4.uc56
1 files changed, 35 insertions, 21 deletions
diff --git a/root/usr/share/ucode/fw4.uc b/root/usr/share/ucode/fw4.uc
index 9b6fcaa..b428cad 100644
--- a/root/usr/share/ucode/fw4.uc
+++ b/root/usr/share/ucode/fw4.uc
@@ -2509,6 +2509,7 @@ return {
switch (r.target) {
case "dnat":
r.chain = sprintf("dstnat_%s", r.src.zone.name);
+ r.src.zone.dflags.dnat = true;
if (!r.raddr)
r.target = "redirect";
@@ -2517,6 +2518,7 @@ return {
case "snat":
r.chain = sprintf("srcnat_%s", r.dest.zone.name);
+ r.dest.zone.dflags.snat = true;
break;
}
@@ -2593,7 +2595,7 @@ return {
mark: redir.mark
};
- let eaddrs = subnets_split_af(length(dip) ? dip : { addrs: redir.src.zone.related_subnets });
+ let eaddrs = length(dip) ? dip : subnets_split_af({ addrs: map(redir.src.zone.related_subnets, to_hostaddr) });
let rzones = length(redir.reflection_zone) ? redir.reflection_zone : [ redir.dest ];
for (let rzone in rzones) {
@@ -2607,34 +2609,46 @@ return {
let iaddrs = subnets_split_af({ addrs: rzone.zone.related_subnets });
let refaddrs = (redir.reflection_src == "internal") ? iaddrs : eaddrs;
- refaddrs = [
- map(refaddrs[0], to_hostaddr),
- map(refaddrs[1], to_hostaddr)
- ];
-
- eaddrs = [
- map(eaddrs[0], to_hostaddr),
- map(eaddrs[1], to_hostaddr)
- ];
-
for (let i = 0; i <= 1; i++) {
if (length(rip[i])) {
- refredir.src = rzone;
- refredir.dest = null;
- refredir.target = "dnat";
+ let snat_addr = refaddrs[i]?.[0];
+
+ /* For internal reflection sources try to find a suitable candiate IP
+ * among the reflection zone subnets which is within the same subnet
+ * as the original DNAT destination. If we can't find any matching
+ * one then simply take the first candidate. */
+ if (redir.reflection_src == "internal") {
+ for (let zone_addr in rzone.zone.related_subnets) {
+ if (zone_addr.family != rip[i][0].family)
+ continue;
+
+ let r = apply_mask(rip[i][0].addr, zone_addr.mask);
+ let a = apply_mask(zone_addr.addr, zone_addr.mask);
+
+ if (r != a)
+ continue;
+
+ snat_addr = zone_addr;
+ break;
+ }
+ }
- for (let saddrs in subnets_group_by_masking(iaddrs[i]))
- for (let daddrs in subnets_group_by_masking(eaddrs[i]))
- add_rule(i ? 6 : 4, proto, saddrs, daddrs, rip[i], sport, dport, rport, null, refredir);
+ if (snat_addr) {
+ refredir.src = rzone;
+ refredir.dest = null;
+ refredir.target = "dnat";
+
+ for (let saddrs in subnets_group_by_masking(iaddrs[i]))
+ for (let daddrs in subnets_group_by_masking(eaddrs[i]))
+ add_rule(i ? 6 : 4, proto, saddrs, daddrs, rip[i], sport, dport, rport, null, refredir);
- for (let refaddr in refaddrs[i]) {
refredir.src = null;
refredir.dest = rzone;
refredir.target = "snat";
- for (let saddrs in subnets_group_by_masking(iaddrs[i]))
- for (let daddrs in subnets_group_by_masking(rip[i]))
- add_rule(i ? 6 : 4, proto, saddrs, daddrs, [ refaddr ], null, rport, null, null, refredir);
+ for (let daddrs in subnets_group_by_masking(rip[i]))
+ for (let saddrs in subnets_group_by_masking(iaddrs[i]))
+ add_rule(i ? 6 : 4, proto, saddrs, daddrs, [ to_hostaddr(snat_addr) ], null, rport, null, null, refredir);
}
}
}