Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
540f4b85ac | ||
|
|
ee278848ee | ||
|
|
6f912dc137 | ||
|
|
5ec943ebff |
No files matched your search
+7
-1
@@ -117,7 +117,13 @@ All notable changes to Housecarl are documented here. The format follows
|
||||
this version.
|
||||
- Negating a match is said first: the zone, From and To fields (rules
|
||||
and NAT) start with "any of" / "any but" instead of a checkbox under
|
||||
the list, and an "any but" list is tinted red.
|
||||
the list, shown once the list has an entry, and an "any but" list is
|
||||
marked with a red bar. An empty list is never saved as negated (it
|
||||
matched everything anyway, but would have negated what was added to
|
||||
it later).
|
||||
- docs/rules.md: "Matching everything but a few", on leaving some
|
||||
addresses out with a zone and "any but", and what to do when the range
|
||||
isn't a zone.
|
||||
- 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
|
||||
|
||||
@@ -128,7 +128,7 @@ The web UI is on `http://127.0.0.1:8070/` (see `listen` in
|
||||
|
||||
## Status
|
||||
|
||||
Housecarl 0.2.0 is in testing (0.2.0-rc.3+52e6a98): zones, address sets and
|
||||
Housecarl 0.2.0 is in testing (0.2.0-rc.3+git60-ee27884): zones, address sets and
|
||||
services with ordered rules, IPv4 and IPv6, port forwards with hairpin NAT
|
||||
and IPv6 pinholes, source NAT and redirects, built-ins, probation for
|
||||
network changes (confirmed by the client that made them), the ruleset
|
||||
|
||||
@@ -135,6 +135,14 @@ As for Jarl and Steward:
|
||||
3. Run `make test && make e2e`.
|
||||
4. Commit as "Release X", tag it `git tag -a vX -m "Housecarl X"`, and push.
|
||||
|
||||
A fix to a release candidate may go out as a build of it rather than a
|
||||
new candidate: `0.2.0-rc.3+git<count>-<commit>`, where `<commit>` is the
|
||||
short ID of the last commit before "Release X" and `<count>` is `git
|
||||
rev-list --count` of it. The count orders the builds (apt compares it as a
|
||||
number; the ID alone would order them at random); each sorts after
|
||||
`0.2.0-rc.3` and before `0.2.0-rc.4`. Debian writes it
|
||||
`0.2.0~rc.3+git<count>~<commit>`.
|
||||
|
||||
The tag starts `.gitea/workflows/release.yml`, which checks the tag
|
||||
against `VERSION` and the CHANGELOG, runs the tests, builds the tarballs,
|
||||
the CLI for each OS and the `.deb`s, and publishes them
|
||||
|
||||
@@ -165,6 +165,40 @@ hc rule add forward --in wan --status dnat
|
||||
hc rule add forward --in wan -a drop
|
||||
```
|
||||
|
||||
### Matching everything but a few
|
||||
|
||||
A field matches **any of** its entries, or with `--not-…` ("any but" in
|
||||
the web UI) anything else; it can't do both. "The LAN except the NAS" is
|
||||
still one rule: the zone says which network, and the addresses say which
|
||||
of it to leave out, because zones and addresses are different fields and
|
||||
a rule needs all of them to match.
|
||||
|
||||
| What you want | One rule |
|
||||
|---|---|
|
||||
| the LAN, except the NAS | `--in lan --from nas --not-from` |
|
||||
| everyone on guest, except one device, has a quota | `--in guest --from tv --not-from --quota 10gbytes,over,daily` |
|
||||
| the internet, except one host | `--out wan --to blocked --not-to` |
|
||||
|
||||
```sh
|
||||
# Each device on the LAN: 50 GB a month, but not the NAS (its backups)
|
||||
hc rule add forward --in lan --out wan --from nas --not-from --quota 50gbytes,over,per-source,monthly -a drop
|
||||
```
|
||||
|
||||
Leaving part of an address range out ("10.0.0.0/8 except 10.0.5.0/24")
|
||||
when it isn't a zone takes one of:
|
||||
|
||||
* **Two rules, the exception first**, when the exception gets the
|
||||
opposite action: `--from 10.0.5.0/24 -a drop` above `--from
|
||||
10.0.0.0/8`. There is no action that skips a rule and goes on, so this
|
||||
doesn't work when the exception should just fall through to later
|
||||
rules.
|
||||
* **Ranges around the hole**: `--from 10.0.0.0-10.0.4.255 --from
|
||||
10.0.6.0-10.255.255.255`.
|
||||
* **A [raw rule](#raw-rules)**: `ip saddr 10.0.0.0/8 ip saddr != 10.0.5.0/24 accept`.
|
||||
|
||||
There's no need to leave a zone out of other zones: an interface belongs
|
||||
to one zone, so "any of lan, guest" already leaves out everything else.
|
||||
|
||||
### Bandwidth and quotas
|
||||
|
||||
A **byte rate** limits bandwidth: `--limit 20mbytes/second,over,per-source
|
||||
|
||||
@@ -382,7 +382,7 @@ pre.wrap { white-space: pre-wrap; word-break: break-all; font-size: 12px; }
|
||||
.negatable { display: flex; gap: 8px; align-items: flex-start; flex-wrap: wrap; }
|
||||
.negatable > .list-editor { flex: 1; min-width: 0; }
|
||||
.negatable.negated > select { color: var(--err); border-color: var(--err); font-weight: 600; }
|
||||
.negatable.negated .list-row input { background: var(--err-soft); color: var(--del-text); border-color: var(--err); }
|
||||
.negatable.negated .list-rows { border-left: 3px solid var(--err); padding-left: 8px; }
|
||||
input.short { width: 7em; }
|
||||
.builtins { margin-bottom: 10px; line-height: 1.6; }
|
||||
.policy { margin-top: 10px; }
|
||||
|
||||
@@ -67,13 +67,23 @@ export function listEditor(values, opts = {}) {
|
||||
|
||||
// negatable puts "any of" / "any but" in front of a list editor, so a
|
||||
// field says first whether it matches its entries or everything else;
|
||||
// "any but" tints the list. value() is the list, negated() the choice.
|
||||
// "any but" marks the list. The choice shows once the list has a row
|
||||
// (empty is "any"), and an empty list is never negated. value() is the
|
||||
// list, negated() the choice.
|
||||
function negatable(list, not) {
|
||||
const mode = select([["", "any of"], ["not", "any but"]], not ? "not" : "", { class: "inline", "aria-label": "match these, or everything but these" });
|
||||
const box = h("div", { class: "negatable" + (not ? " negated" : "") }, mode, list);
|
||||
mode.addEventListener("change", () => box.classList.toggle("negated", mode.value === "not"));
|
||||
const mode = select([["", "any of"], ["not", "any but"]], not ? "not" : "", { class: "inline" });
|
||||
const box = h("div", { class: "negatable" }, mode, list);
|
||||
const rows = () => list.querySelector(".list-rows").children.length;
|
||||
const update = () => {
|
||||
mode.classList.toggle("hidden", rows() === 0);
|
||||
box.classList.toggle("negated", mode.value === "not" && rows() > 0);
|
||||
};
|
||||
mode.addEventListener("change", update);
|
||||
// Add and remove act on their own click first; this runs after.
|
||||
list.addEventListener("click", update);
|
||||
update();
|
||||
box.value = list.value;
|
||||
box.negated = () => mode.value === "not";
|
||||
box.negated = () => mode.value === "not" && list.value().length > 0;
|
||||
return box;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user