Profili
Il profilo è la policy. Dispositivi, gruppi e subnet sono il modo in cui Warden decide quale policy applicare.
Cos’è
Un profilo è un insieme nominato di comportamenti del filtro: quali aree tematiche filtrare, quali admin rule sovrapporre, che forma deve avere la risposta canonica quando una query viene rifiutata e — opzionalmente — record DNS statici, riscritture di nomi, SafeSearch e una policy EDNS Client Subnet. Ogni entità che si risolve in una decisione di filtro — dispositivi, gruppi, subnet e il default_profile globale — punta a un profilo tramite il suo id.
Un profilo non enumera le blocklist. Dichiara dei tag, e una lista si applica quando i suoi tag intersecano il set di tag in cui la query si è risolta. Quell’indirezione è la cosa più importante di questa pagina; tutto il resto è dettaglio.
Questa pagina copre quando aggiungere una voce [profiles.<id>], ogni dimensione che puoi regolare al suo interno, le superfici CLI / TUI / API che li leggono e li scrivono, e come il contenuto di un profilo interagisce con l’overlay per dispositivo. Per il quadro più ampio di come una query viene abbinata a un profilo, vedi il processo di filtraggio e l’ordine di precedenza qui sotto.
Quando ti serve
Crea un profilo per comportamento di filtro che vuoi esprimere, non uno per dispositivo. Un setup tipico finisce con tre o cinque profili:
- Un profilo
defaultper qualsiasi host sulla LAN, taggato per le aree tematiche privacy e sicurezza. - Un profilo
kidsche aggiunge il tag dei contenuti per adulti, nega alcuni domini specifici, attiva SafeSearch e cambia la risposta di blocco anxdomaincosì le app iOS smettono di riprovare. - Un profilo
kids-night(block_all = truepiù una piccola allowlist admin), legato da una pianificazione tra le 21:00 e le 07:00. - Un profilo
iottaggato per la telemetria dei produttori, con qualchelocal_recordsfissato perché le app della smart TV smettano di telefonare a casa. - Un profilo
workricavato dal profilo kids con i domini delle classi rimessi.
Non ti serve un profilo a parte per le eccezioni una tantum. Un singolo dominio da bloccare o consentire per una persona appartiene a [[devices]].allow_rules / deny_rules — vedi dispositivi.
Ti serve invece un profilo a parte ogni volta che un’eccezione non deve sbordare. I profili sono piatti — non c’è extends, niente ereditarietà, niente fusione di due profili. warden group allow e warden group deny scrivono sul profilo sottostante del gruppo, quindi la regola raggiunge anche tutto il resto legato a quel profilo.
Schema
Un profilo è una mappa TOML chiavi-id — a differenza di [[devices]], [[blocklists]], o [[subnets]], i profili usano [profiles.<id>], non array-of-tables. L’id (la parte dopo il punto) è quello che ogni altra entità referenzia.
[profiles.kids]
display_name = "Profilo bambini"
tags = ["ads", "tracking", "malicious", "adult-content"]
block_response = "nxdomain"
blocked_ttl_secs = 300
admin_rules = ["kids-allow-classroom"]
block_all = false
safe_search = trueCome si agganciano le liste: intersezione dei tag
Entrambi i lati dichiarano aree tematiche. Il motore le interseca.
effective_tags(device) = device.tags ∪ profile.tags ∪ group.tags (source has a [[devices]] row)
= profile.tags ∪ subnet.tags (anonymous source, no device row)
group.tags = union across every group the device belongs to
a blocklist applies <=> blocklist.tags ∩ effective_tags is non-emptyLeggi i due rami con attenzione — non sono cumulativi. Una sorgente con una riga [[devices]] esplicita prende device.tags ∪ profile.tags ∪ group.tags e la subnet non contribuisce nulla, anche quando l’IP cade dentro un CIDR configurato. I tag della subnet esistono per le sorgenti che Warden non ha mai visto prima.
Tre conseguenze da interiorizzare:
- Uno dei due lati vuoto significa che la lista non si applica mai. Un profilo con
tags = []non filtra alcuna lista; e nemmeno una blocklist senza tag. L’intersezione cortocircuita sulla vacuità prima di tutto il resto. - Aggiungere una lista è un’operazione a tocco zero sui profili. Tagga un nuovo feed con
adse ogni profilo che già chiedeadslo prende al reload successivo. Non modifichi mai un profilo per sottoscriverlo. - Un typo non è un errore. I tag non hanno un registro — esistono per il fatto di essere usati.
tags = ["addult-content"]è uno slug perfettamente valido che non interseca nulla. Warden emette un WARN e continua a girare; vedi risoluzione problemi.
Lo stato della lista fa da secondo cancello all’intersezione. Una lista il cui fetch è fallito continua a proteggere dalla sua copia in cache; una lista senza cache non contribuisce nulla. Fonte: src/profiles/profile.rs:448-478 (list_applies).
warden profile tag add|remove <id> <tag> scrive profile.tags — idempotente, lo slug è validato al confine della CLI, e una modifica reale attiva un hot reload. Lo strato IPC lo supporta: ProfileUpdatePatch porta un campo tags, quindi anche il chip picker dei tag dell’editor di profili della TUI li imposta. Il lato offerta ha warden blocklist tag add|remove, e gli altri lati domanda hanno warden device tag, warden group tag e warden subnet tag. Usa warden tags list per vedere il panorama live dei tag prima di digitare uno slug.Riferimento completo sui tag: tag. La grammatica dello slug è ^[a-z][a-z0-9-]{0,31}$ — inizia con lettera minuscola, niente trattino finale, massimo 32 byte.
Dimensioni
Un profilo è un vettore lungo questi assi indipendenti. Ogni dimensione ha un default sensato ed è opzionale tranne l’id.
| Gruppo | Dimensione | Campo TOML | Cosa regola |
|---|---|---|---|
| Identità | id | (chiave della mappa) | Riferimento incrociato stabile. Ogni dispositivo, gruppo, subnet e pianificazione che vuole questo profilo nomina questo id. |
| Nome leggibile | display_name | Etichetta operatore mostrata nelle liste della TUI e della CLI. | |
| Selezione delle liste | Tag di area tematica | tags | L’unica leva su quali blocklist si applicano. Interseca i tag propri di ogni lista. |
| Regole personalizzate | Riferimenti a admin rule | admin_rules | L’unico canale per pattern @@ allow, $important, e regex — le liste esterne sono confinate fuori da questi poteri. |
| Risposta a livello wire | Forma della risposta su blocco | block_response | zero (default), nxdomain, refused, soa_nodata. Vedi la tabella più sotto. |
| TTL della risposta di blocco | blocked_ttl_secs | Override per profilo; ricade su [server].default_blocked_ttl_secs. | |
| Modalità | Interruttore nega-per-default | block_all | Se true, ogni query è negata tranne quelle coperte da una admin rule di allow. |
| DNS statico | Record per profilo | local_records | Voci A/AAAA/CNAME servite prima di andare a monte. Consultate prima della tabella globale [local_dns]. |
| Riscritture | Redirezioni nome-a-nome | rewrite_rules | Applicate dopo il controllo di blocco e prima del forward a monte, così una riscrittura non può bypassare il filtraggio sul nome originale. |
| Preset SafeSearch | safe_search | Un solo bool; inietta a tempo di risoluzione otto riscritture di motori di ricerca documentate dai vendor. | |
| A monte | Policy ECS | [profiles.<id>.ecs] | Override EDNS Client Subnet per profilo. Governato dall’interruttore master [upstream.ecs].enabled. |
| Binding di pianificazione (esterno) | Pianificazioni che puntano a questo profilo | [[schedules]].profile | Una pianificazione cambia il profilo di un dispositivo o di un gruppo a questo dentro la sua finestra. |
| Binding del resolver (esterno) | Dispositivi, gruppi, subnet e [server].default_profile che referenziano questo id | (altre entità) | I profili sono referenziati; non referenziano indietro. Rimuovere un profilo referenziato è rifiutato. |
Cose che sembrano dimensioni del profilo ma non lo sono:
- Sottoscrizioni esplicite a blocklist. Rimosse.
blocklistsecategoriesnon sono più campi; i tag hanno sostituito entrambi. - Ereditarietà del profilo. I profili sono piatti — non c’è
extends. La composizione avviene allo strato dei tag: una sorgente con dispositivo uniscedevice ∪ profile ∪ group, una sorgente senza dispositivo unisceprofile ∪ subnet. Dispositivo e subnet non contribuiscono mai insieme. - TTL di cache è globale (
[cache]) — solo il TTL della risposta di blocco è per profilo. - Scelta del forwarder a monte è globale (
[[forwarding]]) — non puoi fissare “kids usa Quad9, work usa Cloudflare”. ECS è l’unica manopola a monte che è per profilo. - Rate limit per profilo — RRL è globale (
[security]).
Riferimento dei campi
| Campo | Tipo | Obbligatorio | Default | Scopo |
|---|---|---|---|---|
<id> (chiave della mappa) | stringa, [a-z0-9-], 1–64 byte | sì | — | Riferimento incrociato stabile. |
display_name | stringa | no | "" | Etichetta TUI / CLI. |
tags | lista di slug di tag, ^[a-z][a-z0-9-]{0,31}$ | no | [] | Aree tematiche. Intersecate con i tag di ogni blocklist per decidere l’applicabilità. |
admin_rules | lista di id di admin rule | no | [] | Regole curate dall’operatore; l’unico posto dove @@, $important, e regex vengono onorati. |
block_response | enum | no | eredita da [server].default_block_response | zero | nxdomain | refused | soa_nodata. |
blocked_ttl_secs | u32 (secondi) | no | eredita da [server].default_blocked_ttl_secs | TTL stampato sulla risposta di blocco canonica. |
block_all | bool | no | false | Se true, nega ogni query tranne le corrispondenze di admin allow. |
local_records | lista di LocalDnsRecord | no | [] | A/AAAA/CNAME per profilo, con ttl_secs e match_subdomains opzionali. Consultati prima della tabella globale. |
rewrite_rules | lista di RewriteRule | no | [] | Riscritture nome-a-nome, applicate post-filtro e pre-forward. |
safe_search | bool | no | false | Inietta il set curato di riscritture dei motori di ricerca. Vedi SafeSearch. |
ecs | sotto-tabella | no | eredita da [upstream.ecs] | mode (off | coarse | subnet), più source_prefix_v4 / source_prefix_v6 sotto subnet. Ogni campo ricade in modo indipendente. |
#[serde(deny_unknown_fields)] è attivo — i typo falliscono al caricamento con unknown field. Ciò include le chiavi v1 ritirate: un profilo che porta blocklists o categories viene rifiutato, non migrato sul posto. Usa warden migrate per convertire una config pre-tag; mappa ogni lista kind = "deny" a tags = ["uncategorized"] e ogni lista kind = "allow" a tags = []. Fonte: src/config/schema/profile.rs:60-130.
Varianti di block response
| Valore TOML | Effetto sul filo | Quando usarlo |
|---|---|---|
zero (default) | 0.0.0.0 per A, :: per AAAA, NOERROR. | Resa rapida del client. I browser smettono di riprovare in millisecondi. Il default giusto. |
nxdomain | RCODE=NXDOMAIN. | Le app trattano il nome come mancante e cachano aggressivamente. Le app iOS in particolare smettono di riprovare. Alcuni stub resolver ricadono su un DNS secondario — bypassabile in quel caso. |
refused | RCODE=REFUSED. | Gli stub resolver ricadono sul DNS successivo configurato. Utile solo quando Warden è uno tra più upstream di proposito. Sempre usato dai percorsi di sicurezza, indipendentemente dal valore del profilo. |
soa_nodata | NOERROR + risposta vuota + SOA in authority. | RFC 2308, amico della negative-cache. Il migliore per chi interroga molto (tablet, IoT) che onora il TTL minimo dell’SOA e smette di richiedere. |
Tutte e quattro sono impostabili dalla CLI, più clear per ricadere sul globale del server.
Esempi
Un default domestico — aree tematiche privacy e sicurezza, resa rapida:
[profiles.default]
display_name = "Home default"
tags = ["ads", "tracking", "malicious"]
block_response = "zero"Le liste che lo soddisfano vivono sull’altro lato dell’intersezione:
[[blocklists]]
id = "oisd-basic"
url = "https://big.oisd.nl/domainswild"
kind = "deny"
tags = ["ads", "tracking"]
[[blocklists]]
id = "urlhaus"
url = "https://urlhaus.abuse.ch/downloads/hostfile/"
kind = "deny"
tags = ["malicious"]Un profilo kids — un tag in più, NXDOMAIN per spegnere i retry, SafeSearch attivo, un allow scolastico in cima:
[profiles.kids]
display_name = "Bambini"
tags = ["ads", "tracking", "malicious", "adult-content"]
admin_rules = ["kids-allow-classroom"]
block_response = "nxdomain"
blocked_ttl_secs = 300
safe_search = trueUn profilo kids-night legato a una pianificazione — nega tutto tranne una piccola allowlist admin. Il profilo non dichiara alcun tags: sotto block_all lo strato delle liste è irrilevante, perché nulla lo raggiunge. La voce local_records si risolve comunque, perché i record locali sono risposti prima che il filtro giri.
[profiles.kids-night]
display_name = "Bambini, notte"
tags = []
block_all = true
admin_rules = ["kids-night-bedtime-audio"]
[[profiles.kids-night.local_records]]
name = "homework.lan"
type = "A"
value = "10.10.1.20"[[schedules]]
id = "kids-bedtime"
target_type = "group"
target_id = "kids"
profile = "kids-night"
days = ["mon", "tue", "wed", "thu", "sun"]
start = "21:00"
end = "07:00"Un profilo IoT che filtra la telemetria, sopprime ECS così la CDN del vendor non impara nulla sulla LAN, e fissa un override locale:
[profiles.iot]
display_name = "IoT"
tags = ["telemetry", "malicious"]
block_response = "soa_nodata"
[profiles.iot.ecs]
mode = "off"
[[profiles.iot.local_records]]
name = "samsungcloudsolution.com"
type = "A"
value = "0.0.0.0"
match_subdomains = trueprofiles.d/*.toml (un file per persona — default.toml, kids.toml, iot.toml, work.toml). Il config.toml master li include tramite includes. warden profile allow e warden profile deny accettano --into <file> per instradare la scrittura nel file giusto.CLI
Il sottocomando è warden profile (singolare). Ogni verbo di scrittura attiva un hot reload del daemon (swap atomico della config, niente restart). I verbi di sola lettura funzionano anche senza il daemon.
| Comando | Cosa fa |
|---|---|
warden profile list | Elenca i profili configurati con un riassunto su una riga. |
warden profile show <id> | Dump di dettaglio completo di un profilo. |
warden profile create <id> --display-name <n> | Crea un profilo. Rifiutato se l’id esiste già. |
warden profile update <id> --display-name <n> | Cambia l’etichetta. |
warden profile block-response <id> <variante> | Imposta la risposta di blocco a livello wire. Varianti: zero | nxdomain | refused | soa_nodata | clear. |
warden profile blocked-ttl <id> <secs> | Imposta il TTL della risposta di blocco. 0 lo azzera (eredita il globale del server). |
warden profile block-all <id> <true|false> | Commuta il nega-per-default. |
warden profile admin-rule-add <id> <rule_id> | Referenzia una riga [[admin_rules]] esistente. Crea prima la riga con warden rules. |
warden profile admin-rule-remove <id> <rule_id> | Rimuove il riferimento. La riga della regola in sé resta. |
warden profile tag add|remove <id> <tag> [--into <file>] | Aggiunge o rimuove un tag di area tematica — lo scrittore di profile.tags. Idempotente; lo slug è validato al confine della CLI; una modifica reale attiva un hot reload. |
warden profile allow <id> <dominio> [--id <rule_id>] [--remove] [--into <file>] | Sintetizza una admin rule `@@ |
warden profile deny <id> <dominio> [...stessi flag] | Simmetrico — sintetizza ||domain^. |
warden profile ecs <id> --mode <m> [--prefix-v4 N] [--prefix-v6 N] | Imposta la policy ECS per profilo. I prefissi valgono solo sotto --mode subnet. |
warden profile ecs-clear <id> | Rimuove il sottoalbero [profiles.<id>.ecs] così il profilo eredita [upstream.ecs]. |
warden profile remove <id> | Cancella il profilo. Rifiutato se un dispositivo, subnet, o pianificazione lo referenzia ancora. |
Non c’è un verbo per local_records o rewrite_rules — quelli si modificano a mano nel TOML più warden reload. tags, invece, ha il verbo dedicato warden profile tag qui sopra. Non c’è nemmeno warden profile blocklists; è stato rimosso insieme al campo su cui scriveva.
Pattern comuni:
# Tagga una lista così ogni profilo che chiede quell'area tematica la prende
sudo warden blocklist tag add oisd-basic ads
# Controlla il panorama live dei tag prima di digitare un nuovo slug
warden tags list
# Blocca un dominio solo sul profilo kids
sudo warden profile deny kids tiktok.com
# Cambia la forma del RCODE così gli stub iOS smettono di ricadere su un secondario
sudo warden profile block-response kids nxdomain
# Ispeziona cosa succederebbe per un IP, senza bisogno del daemon
warden resolve 10.10.1.107Dopo ogni modifica con hot-reload, viene stampato esattamente uno di quattro messaggi — gli stessi usati da ogni percorso di scrittura della CLI:
daemon reloaded — change is livedaemon not running — change will take effect on next startnote: change landed on disk but no admin token is available to request a daemon reload. Run warden token generate or restart the daemon to activate.warning: change landed on disk but the daemon rejected the reload (<msg>). Check journalctl -u purge-warden and consider systemctl restart purge-warden.
Fonte: src/cli/mod.rs:536-630, src/cli/commands/profiles.rs.
TUI
C’è una tab Profili dedicata — la quarta foglia della sezione Network, una vista master/detail supportata offline su [profiles].
| Tab | Rilevanza per i profili | Tasti utili |
|---|---|---|
| Profiles | Master list più card di dettaglio. Add / Edit / Delete pilotano direttamente i verbi IPC ProfileCreate / ProfileUpdate / ProfileDelete. Il modal di edit copre display_name, block_response, blocked_ttl_secs, block_all, admin_rules, ecs, e un chip picker dei tags. | a aggiungi, e modifica, d elimina. |
| Tags | Ogni slug in uso tra blocklist, dispositivi, profili e subnet, con i conteggi d’uso. Crea, rinomina, elimina per i tag non di sistema; uncategorized rifiuta entrambi. | c crea, R rinomina, d elimina inutilizzati, / cerca. |
| Dispositivi | Colonna profilo per riga. La card di dettaglio separa i tag propri del dispositivo da quelli ereditati via profilo, e segnala UNFILTERED. Group-by profile è una delle opzioni del ciclo. | e modifica, a aggiungi, G cicla l’asse di raggruppamento. |
| Lists | Ogni riga di blocklist mostra quali profili la raggiungono tramite intersezione dei tag. | Enter modifica, a aggiungi, B picker del catalogo, K commuta block/allow. |
| Local DNS | Due pannelli — la tabella globale e i record per profilo. | o cambia pannello, n/N cicla profilo, a aggiungi. |
| Rules | Admin rule per profilo e per dispositivo. | f cicla il filtro. |
Il resolver inspector (s da qualsiasi foglia) prende un IP sorgente e mostra la catena completa — dispositivo abbinato, livello di match, profilo attivo, pianificazione attiva. È il modo più rapido per rispondere a “perché questo client riceve quel profilo?”.
Il chip picker dei tags del modal di edit scrive profile.tags via IPC (ProfileUpdatePatch.tags), quindi puoi cambiare quali liste un profilo filtra direttamente dalla TUI — o con warden profile tag …. Fonte: src/tui/app.rs:117-149, src/tui/ui.rs:592-600, src/tui/profile_modal.rs:129-158, src/ipc/protocol.rs:407.
API REST
| Metodo | Path | Cosa |
|---|---|---|
GET | /api/config | Configurazione completa fusa, inclusi [profiles.*] in JSON. token_hash è oscurato. |
GET | /api/whitelist | La lista di allow del profilo default, ricostruita dai riferimenti admin_rules il cui testo di regola inizia con @@. |
POST | /api/whitelist/add | Aggiunge una regola di allow al profilo default. 409 se già presente. |
DELETE | /api/whitelist/remove | Simmetrico. 404 se assente. |
Tutte le route /api/* sono protette da Bearer token (Authorization: Bearer ps_<64hex>), verificato in tempo costante, con lockout di 10 fallimenti / 5 minuti. Ogni route autenticata ha un timeout di 30 secondi.
Non c’è una CRUD REST per i profili arbitrari. Gli endpoint della whitelist sono una forma di compatibilità sul solo profilo default; tutto il resto passa per la CLI, la TUI, o una modifica a mano più reload.
IPC
Sul socket Unix esistono tre verbi per i profili, tutti nel livello Mutating (richiede admin token):
ProfileCreate { id, display_name }— rifiuta se l’id esiste.ProfileUpdate { id, patch }— il patch portadisplay_name,block_response,blocked_ttl_secs,block_all,admin_rules(delta add / remove),ecs, etags(un delta suProfile.tags).ProfileDelete { id }— rifiuta se un dispositivo, subnet, o pianificazione referenzia ancora l’id.
I campi modificati a mano atterrano su disco e il daemon li riprende via IpcCommand::Reload { token }, lo stesso percorso usato da ogni mutazione CLI. DeviceUpdate e DevicePromote portano un campo opzionale profile per ricollegare un dispositivo. Fonte: src/api/handlers.rs:863-895, src/ipc/protocol.rs:267-300,407.
Ordine di precedenza
Una query attraversa due passi ordinati: scegli il profilo, poi valuta al suo interno.
Scelta del profilo
Cinque livelli, vince il primo match. La tabella dà l’ordine di valutazione a runtime accanto all’etichetta stampata da warden resolve e dall’audit log — i due non girano nella stessa sequenza, cosa che confonde.
| Valutato | Etichetta di livello | Condizione |
|---|---|---|
| 1° | schedule | Una finestra di pianificazione è attiva per il dispositivo abbinato o per uno dei suoi gruppi. |
| 2° | device-direct | La riga [[devices]] imposta profile = "...". |
| 3° | group | Il gruppo a priorità più alta del dispositivo. Stessa priorità + profili diversi è un errore del validator, quindi la scelta non è mai ambigua. |
| 4° | subnet | Match a prefisso più lungo contro [[subnets]]. Solo per sorgenti senza riga [[devices]] — o per un dispositivo declassato dall’enforcement MAC. |
| 5° | global-default | [server].default_profile. Se non impostato, la risposta è REFUSED. |
L’ordine pianificazione-prima-del-diretto è deliberato: un operatore che scrive una pianificazione per un dispositivo che fissa anche un profilo sta chiaramente chiedendo alla pianificazione di vincere dentro la sua finestra, altrimenti la pianificazione non farebbe nulla. I test fissano questa scelta.
enforce_device_mac = true più una discrepanza ARP declassa il dispositivo al livello subnet per quella query — pianificazione, diretto e gruppo sono tutti saltati.
È la stessa catena documentata in dispositivi e gruppi. Fonte: src/profiles/resolver.rs:440-520.
Valutazione dentro il profilo
Prima di tutto questo, il gestore sonda i local_records del profilo. Un hit è risposto subito e bypassa interamente il filtro, la cache e l’upstream — non è “lasciato passare” oltre il filtro, non lo raggiunge mai. Vale anche sotto block_all, ed è ciò che mantiene homework.lan raggiungibile nell’esempio della buonanotte qui sopra. Partecipano solo A, AAAA e CNAME; qualsiasi altro qtype ricade sulla tabella globale [local_dns] e poi a monte. Fonte: src/dns/handler.rs:940-985.
Una volta che quello manca, il filtro percorre questi stadi. Vince la prima decisione.
- Cortocircuito di
block_all. Seblock_all = true: forwarda solo quando una admin rule di allow matcha (set esatto per dominio o una regola di allow corrispondente nella scansione a priorità). Tutto il resto è negato, attribuito alla policy del profilo piuttosto che alla regola che era il match prossimo. Le liste in direzione allow deliberatamente non perforanoblock_all— una allowlist esterna confinata non deve indebolire un esplicito “nega tutto” dell’operatore. - Scansione a priorità delle admin rule, quattro livelli, vince il più alto:
| Priorità | Forma della regola |
|---|---|
| 3 | allow $important — cortocircuita tutto ciò che sta sotto |
| 2 | deny $important |
| 1 | allow normale |
| 0 | deny normale |
- Walk unificato per sottodominio, un solo passaggio di byte che sonda ogni set abilitato per posizione del punto:
- hit del set allow esatto per dominio → forward (batte un deny di livello 0 che ha già matchato)
- hit del set deny esatto per dominio → blocco (consultato solo quando nessuna regola ha prodotto un risultato)
- hit della maschera di lista in direzione allow → forward
- hit della maschera di lista in direzione deny → blocco
- Forward di default — qualsiasi cosa non abbia matchato nulla va a monte.
Dopo il verdetto e prima del forward, si applicano rewrite_rules e i preset SafeSearch. Quell’ordine è ciò che impedisce di usare una riscrittura per sfuggire a un match di blocklist sul nome originale.
Allow batte deny a parità di forza: allow $important > deny $important > allow normale > allow a livello di lista > deny a livello di lista ~ deny normale. Fonte: src/filter/engine.rs:401-560, src/filter/evaluator.rs:22-83.
Overlay del dispositivo (per query, sopra il profilo risolto)
Un dispositivo può portare i propri allow_rules e deny_rules, più override_profile_deny: bool. Sulle nove combinazioni di (decisione del profilo × decisione del dispositivo × flag di override), una riga è portante:
Il profilo nega, il dispositivo consente, override_profile_deny = true → la query è consentita, attribuita a RuleSource::Device(<id>) [OVERRIDE].
Quando override_profile_deny = false la stessa situazione ricade su blocco — difensivo sulla deriva; CLI e TUI rifiutano anche di scrivere un allow contraddittorio senza alzare il flag. Il deny per dispositivo è sempre additivo: può bloccare ciò che il profilo consentirebbe, ma il profilo non può sovrascriverlo.
Il dispositivo non può sovrascrivere block_response, blocked_ttl_secs, block_all, local_records, o rewrite_rules — quelli vengono solo dal profilo risolto. Ciò che il dispositivo può contribuire sono i tags, che si uniscono al set effettivo prima che giri la selezione delle liste. Fonte: src/profiles/profile.rs:629-741.
Note di sicurezza
- Solo
admin_rulesonorano@@,$important, e le regex. Le liste esterne sono confinate — possono negare ma non possono fare override né usare pattern ancorati / regex. Questo impedisce a una fonte di lista ostile o compromessa di forare i tuoi override. - I
local_recordssono non filtrati per costruzione. Un record con scope di profilo è servito prima del filtro, della cache e dell’upstream — nessuna blocklist, nessuna admin rule e nessunblock_allgli si applica. Tratta la lista come una piccola allowlist deliberata che per giunta risponde, non come una comodità per fissare nomi che vuoi comunque controllati. - Un profilo senza tag non filtra nulla. Non c’è una sottoscrizione di default implicita.
tags = []su un profilo i cui dispositivi non portano nemmeno tag significa che ogni query è forwardata — il validator avverte, non rifiuta. Controlla le righe WARN dopo ogni reload che ha toccato i tag. block_unmapped_clientsnon c’è più. Esprimi “nega i client non mappati” lasciando[server].default_profilenon impostato, così la catena restituisceREFUSEDal livello global-default. La chiave legacy viene rifiutata comeunknown field.- Il query log registra
client_ip,client_name, dominio interrogato, RCODE, e il nome del profilo risolto. Non registra il MAC. - Il ciclo di vita del profilo non è auditato — le modifiche ai tag tramite il verbo sì. Create, update, remove, e i cambi ECS non sono scritti nell’audit log. Ciò che è auditato:
rule.add/rule.remove/rule.undo(per cui passanowarden profile allowedeny, portandoscope,target_id, e il profilo effettivo),profile.tag_add/profile.tag_remove(dawarden profile tag), più l’auto-promozione delle blocklist e i warning di intersezione dei tag a zero. Per tracciare “chi ha cambiato la modalità di blocco del profilo kids?”, usa la git history del file; le modifiche ai tag fatte tramite il verbo sono sulla traccia di audit. warden audit tail [-n N]stampa le righe di audit recenti come righe tab-allineate: timestamp, tag dell’evento, uid, ok / rifiutato, dettaglio.- L’enforcement del MAC è ergonomico, non crittografico. Un attaccante deciso sulla LAN può falsificare. Vedi il modello delle minacce.
Risoluzione problemi
Non viene bloccato nulla, ma il profilo sembra giusto. Quasi sempre un’intersezione vuota. Il daemon avverte al reload sul canale di audit:
profile "kids" contributes no tags — devices using it rely entirely on device-level tags profile "kids" has tags but none match any enabled deny list blocklist "oisd-basic" tags match no device, profile, or subnet — the list applies to nothing device "anna-iphone" has tags but none match any enabled deny list — no list filtering applies
Tutti e quattro sono solo WARN e non bloccano mai il reload — un tag preparato per una lista che non hai ancora aggiunto è legittimo. Leggili dopo ogni modifica ai tag:
journalctl -u purge-warden | grep -E 'no tags|match no|matches nothing'
warden tags listUn tag con conteggio d’uso pari a 1 in warden tags list è quasi sempre un typo.
Un reload fallisce con unknown field: blocklists. Il profilo usa ancora lo schema v1 ritirato. blocklists e categories sono stati sostituiti da tags; deny_unknown_fields li rifiuta invece di ignorarli. Esegui warden migrate su una config pre-tag, oppure converti a mano — ogni vecchio id di blocklist diventa un tag condiviso dalla lista e dai profili che vi si sottoscrivevano.
Un reload fallisce con “profile X not found”. Qualche entità referenzia un profilo che non esiste più — di solito un typo, a volte un profilo cancellato. Il validator rifiuta il reload e il daemon resta sulla configurazione precedente. Esegui warden config lint, o grep sull’albero della config:
grep -RnE 'profile\s*=\s*"[^"]+"' /etc/purge-wardenwarden profile remove viene rifiutato. Un dispositivo, subnet, o pianificazione lo referenzia ancora. L’errore li nomina — riassegnali prima. Lo stesso vale se [server].default_profile punta al profilo che stai cancellando.
[server].default_profile non è impostato e i client non mappati falliscono. L’ultimo livello restituisce REFUSED per tutto. Sintomo: un laptop ospite riceve RCODE=REFUSED per ogni nome. O imposti default_profile su un id esplicito, oppure accetti questa come policy — almeno impedisce a un open resolver di forwardare per gli sconosciuti.
Un dispositivo con override_profile_deny = true continua a sfuggire al profilo kids. È esattamente il senso del flag, ma verifica se intendevi lasciarlo attivo:
warden device show anna-iphone | grep -E 'allow|override'Un dispositivo si risolve al profilo giusto ma salta ogni lista. Controlla unfiltered. Un dispositivo con unfiltered = true deve avere tags = [] (il validator impone il mutex) e cortocircuita a un set effettivo vuoto — risoluzione DNS, query logging e statistiche continuano tutti a funzionare, quindi il dispositivo sembra sano mentre non filtra nulla.
Per altro, vedi risoluzione problemi.
Vedi anche
- Tag — lo strato di slug che decide quali liste un profilo filtra.
- Liste di blocco — l’altro lato dell’intersezione.
- Dispositivi — fissa un host a un profilo, sovrapponi tag e overlay per dispositivo.
- Gruppi — assegna un solo profilo a molti dispositivi in una volta.
- Subnet — profilo e tag di fallback per sorgenti senza riga device.
- Pianificazioni — cambi di profilo basati sull’orario.
- Regole admin — cosa referenzia
admin_rules; l’unico posto dove vivono@@/$important/ regex. - SafeSearch — cosa attiva il bool
safe_search. - Record DNS locali — la tabella globale che
local_recordsmette in ombra per profilo. - Riferimento TOML — ogni campo, ogni vincolo.
- Riferimento CLI — la superficie completa di
warden profile ….