desktop: route wildcard zones to a local DNS stub
A hosts file cannot express a wildcard, so '*.youtube.com' was only ever the
base domain plus the guessed labels. The patterns the server now hands over
as unexpandable are answered by a stub on 127.0.0.1, and the helper owns one
systemd-resolved drop-in that points just those zones at it:
* the stub is listening before the drop-in is written, and the drop-in is
removed before the stub stops, so a zone's queries never land on a dead
port;
* stub and route live as long as the app, not the interval: between
intervals they forward everything, instead of restarting resolved (and
dropping its cache) on every pomodoro;
* a crashed run leaves a world-readable drop-in the next start adopts, and
the stub comes back before anything else;
* masks with nothing routable after their last '*' ('*gram*') are reported
as unenforceable, not silently dropped.
The Blocker page now reports what is really in place — the hosts region, the
routed zones, and the masks this machine cannot do — rather than the whole
expansion. 39 desktop tests, including the ordering invariants.
This commit is contained in:
12 files changed
+1695
-29
No files matched your search
@@ -1,8 +1,10 @@
|
||||
// The focus guard: what is blocked, when, and what it caught.
|
||||
//
|
||||
// Lists accept masks. A hosts file has no wildcards of its own, so `*.x.com` is
|
||||
// expanded server-side into real hostnames; this page shows that count and says
|
||||
// plainly when a pattern cannot be expressed that way.
|
||||
// expanded server-side into real hostnames, and the patterns that leaves over
|
||||
// are answered by the local DNS stub for the zones it can route. The stats show
|
||||
// what is *really* in place on this computer — the hosts region and the routed
|
||||
// zones — and every banner says plainly what could not be enforced here.
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
@@ -42,6 +44,26 @@ ScrollView {
|
||||
visible: controller.blockerError !== ""
|
||||
text: controller.blockerError
|
||||
}
|
||||
Banner {
|
||||
visible: controller.invalidExpansions.length > 0
|
||||
text: controller.invalidExpansions.join(", ")
|
||||
+ " is not a subdomain label, so it was ignored. Each entry is one "
|
||||
+ "label — web, m, mobile. A bare `*` is kept and means every subdomain."
|
||||
}
|
||||
Banner {
|
||||
visible: controller.blockerActive && controller.unroutableDomains.length > 0
|
||||
text: controller.unroutableDomains.join(", ")
|
||||
+ " cannot be blocked on this computer: no DNS zone can be routed for "
|
||||
+ "a mask with nothing after its last `*`. The phone still matches it "
|
||||
+ "against the URLs you open."
|
||||
}
|
||||
Banner {
|
||||
visible: controller.blockerActive && controller.blockedDomains.length > 0
|
||||
&& controller.appliedDomains.length === 0
|
||||
text: "Blocking is on, but this machine's hosts file has none of the "
|
||||
+ controller.blockedDomains.length + " hostnames in it yet. Either the "
|
||||
+ "write has not run, or it was refused — a message above would say which."
|
||||
}
|
||||
|
||||
Panel {
|
||||
padding: 0
|
||||
@@ -50,8 +72,21 @@ ScrollView {
|
||||
spacing: 0
|
||||
Repeater {
|
||||
model: [
|
||||
{ label: "Hostnames", value: "" + controller.blockedDomains.length, caption: "after expansion" },
|
||||
{ label: "Apps", value: "" + controller.blockedApps.length, caption: "closed on sight" },
|
||||
{ label: "Hostnames",
|
||||
value: "" + controller.appliedDomains.length,
|
||||
caption: controller.config.enforce_blocking && controller.config.block_hosts_file
|
||||
? "in /etc/hosts"
|
||||
: "not written (enforcement off)" },
|
||||
{ label: "Zones",
|
||||
value: "" + controller.routedZones.length,
|
||||
caption: "routed to the stub" },
|
||||
{ label: "Apps",
|
||||
value: "" + controller.blockedApps.length,
|
||||
caption: !controller.config.enforce_blocking || !controller.config.block_apps
|
||||
? "not enforced"
|
||||
: (controller.settings.blocker
|
||||
&& controller.settings.blocker.kill_blocked_apps
|
||||
? "closed on sight" : "warned only") },
|
||||
{ label: "Attempts today",
|
||||
value: controller.stats.today ? "" + controller.stats.today.blocked_attempts : "0",
|
||||
caption: "turned away" },
|
||||
@@ -125,8 +160,9 @@ ScrollView {
|
||||
Repeater {
|
||||
model: [
|
||||
{ pattern: "youtube.com", meaning: "the site itself, plus www. and m." },
|
||||
{ pattern: "*.google.com", meaning: "every subdomain in the expansion list" },
|
||||
{ pattern: "*gram*", meaning: "matches apps; a hosts file cannot express it" }
|
||||
{ pattern: "*.google.com", meaning: "the bare domain plus every subdomain in the expansion list" },
|
||||
{ pattern: "*gram*", meaning: "matches apps, and URLs on the phone; no DNS zone can be routed for it" },
|
||||
{ pattern: "* in the list below", meaning: "makes *.site cover every subdomain — answered by the DNS stub" }
|
||||
]
|
||||
delegate: RowLayout {
|
||||
required property var modelData
|
||||
@@ -260,7 +296,7 @@ ScrollView {
|
||||
TextField {
|
||||
id: subdomainField
|
||||
Layout.preferredWidth: 420
|
||||
placeholderText: "*.site expands to: www, m, app…"
|
||||
placeholderText: "*.site expands to: www, m, web… (`*` = every subdomain)"
|
||||
text: (controller.settings.blocker && controller.settings.blocker.subdomain_expansions
|
||||
? controller.settings.blocker.subdomain_expansions : []).join(", ")
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user