Rule dialog: only the zone fields the chain can use
Input and early have no outgoing interface, output no incoming one, so the dialog hides those fields (they could only be refused) and a zone left in a hidden field isn't sent. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
0e958289de
commit
e841986a86
3 files changed
+19
-4
No files matched your search
@@ -115,6 +115,10 @@ All notable changes to Housecarl are documented here. The format follows
|
||||
ruleset, for entries made before this version too: the configuration
|
||||
before and after it is got back from the current one and rendered by
|
||||
this version.
|
||||
- The rule dialog shows only the zone fields its chain can use: no
|
||||
"Going out on" for input and early, no "Coming in on" for output
|
||||
(they could only be refused). A zone left in a field the chain hides
|
||||
isn't sent.
|
||||
- History lists a changed setting by its own fields
|
||||
(`builtins.drop_invalid: false → true`), on the web page and in `hc
|
||||
history show`, instead of the whole `builtins` before and after.
|
||||
|
||||
@@ -260,6 +260,9 @@ export async function ruleDialog(r, chain) {
|
||||
r = r || { chain, action: "accept" };
|
||||
const ch = select(["input", "forward", "output", "early"], r.chain || chain);
|
||||
const match = matchEditor(r, n);
|
||||
const chainZones = () => match.zones(ch.value !== "output", ch.value === "forward" || ch.value === "output");
|
||||
ch.addEventListener("change", chainZones);
|
||||
chainZones();
|
||||
const action = select([["accept", "accept"], ["drop", "drop"], ["reject", "reject"], ["log", "log only (and go on)"]], r.action);
|
||||
const rejectWith = select([["", "with an ICMP error"], ["tcp-reset", "with a TCP reset (TCP rules only)"]], r.reject_with || "");
|
||||
const every = checkbox("every packet: also stop connections already open, not just new ones", r.every_packet);
|
||||
@@ -371,6 +374,7 @@ export async function ruleDialog(r, chain) {
|
||||
const addersLabel = h("label");
|
||||
sections.raw.onShow = (on) => {
|
||||
for (const n of [...matchNodes, ...actionField, ...logField]) n.classList.toggle("hidden", on);
|
||||
if (!on) chainZones();
|
||||
for (const [k, sec] of Object.entries(sections)) {
|
||||
if (k === "raw") continue;
|
||||
if (on && sec.open) for (const n of sec.nodes) n.classList.add("hidden");
|
||||
|
||||
@@ -77,9 +77,11 @@ export function matchEditor(m, n, opts = {}) {
|
||||
const notSrc = checkbox("any source but these", m.not_sources), notDst = checkbox("any destination but these", m.not_destinations);
|
||||
const svc = listEditor(m.services, { suggestions: n.services, placeholder: "ssh, https, tcp/8080, udp/1000-2000, icmp/echo-request", addLabel: "Add service" });
|
||||
const fam = select([["", "IPv4 and IPv6"], ["ipv4", "IPv4 only"], ["ipv6", "IPv6 only"]], m.family || "");
|
||||
const inField = opts.in !== false ? field("Coming in on", h("div", null, inZ, notIn)) : null;
|
||||
const outField = opts.out !== false ? field("Going out on", h("div", null, outZ, notOut)) : null;
|
||||
const fields = [
|
||||
opts.in !== false ? field("Coming in on", h("div", null, inZ, notIn)) : null,
|
||||
opts.out !== false ? field("Going out on", h("div", null, outZ, notOut)) : null,
|
||||
inField,
|
||||
outField,
|
||||
field("From", h("div", null, src, notSrc), "Sets, addresses, prefixes or ranges, IPv4 and IPv6 mixed. Empty: any."),
|
||||
field("To", h("div", null, dst, notDst)),
|
||||
field("Services", svc, "Named services (built in, or yours) or entries such as tcp/8080. Empty: any traffic."),
|
||||
@@ -88,10 +90,15 @@ export function matchEditor(m, n, opts = {}) {
|
||||
fields.value = () => {
|
||||
const v = { sources: src.value(), not_sources: notSrc.input.checked, destinations: dst.value(), not_destinations: notDst.input.checked,
|
||||
services: svc.value(), family: fam.value };
|
||||
if (opts.in !== false) Object.assign(v, { in_zones: inZ.value(), not_in: notIn.input.checked });
|
||||
if (opts.out !== false) Object.assign(v, { out_zones: outZ.value(), not_out: notOut.input.checked });
|
||||
// A hidden zone field (the chain has no such interface) matches nothing.
|
||||
if (inField) Object.assign(v, inField[1].classList.contains("hidden") ? { in_zones: [], not_in: false } : { in_zones: inZ.value(), not_in: notIn.input.checked });
|
||||
if (outField) Object.assign(v, outField[1].classList.contains("hidden") ? { out_zones: [], not_out: false } : { out_zones: outZ.value(), not_out: notOut.input.checked });
|
||||
return v;
|
||||
};
|
||||
// zones shows the zone fields a chain can use: input and early have no
|
||||
// outgoing interface, output no incoming one.
|
||||
const show = (f, on) => f && f.filter(Boolean).forEach((e) => e.classList.toggle("hidden", !on));
|
||||
fields.zones = (inOn, outOn) => { show(inField, inOn); show(outField, outOn); };
|
||||
return fields;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user