<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Cyberdyne Systems</title>
    <link>https://noblogo.org/aytin/</link>
    <description>&#34;Fare o non fare. Non c&#39;è provare!&#34;</description>
    <pubDate>Mon, 03 Aug 2026 09:10:26 +0000</pubDate>
    <item>
      <title>sshaudit.com di nuovo online!!!</title>
      <link>https://noblogo.org/aytin/sshaudit-com-di-nuovo-online</link>
      <description>&lt;![CDATA[tux-sshaudit&#xA;&#xA;Oh, gaudio!&#xA;&#xA;Oh, giubilo!&#xA;&#xA;ssh–audit è di nuovo fra noi.&#xA;!--more--&#xA;Il 4 luglio 2026 Joe Testa porta la sua creatura dalla versione 3.3.0, risalente ormai a due anni fa, alla versione 3.9.0, un aggiornamento corposo che riguarda:&#xA;&#xA;aggiornamento supporto python 3.14, eliminazione python 3.8 e python 3.9&#xA;preparazione alla crittografia post-quantistica (warning se gli algoritmi di exchange non lo sono)&#xA;rimozione supporto sshv1&#xA;Modifica della policy built-in per Debian 12&#xA;Aggiunta delle policy built-in per OpenSSH 10.0, 10.1, 10.2, 10.3, and 10.4.&#xA;Aggiunta delle guide all’hardenizzazione di Debian 13, Rocky Linux 10, Ubuntu 26.04.&#xA;**Avendo sempre come riferimento la resistenza post quantistica, sono stati aggiunti due nuovi algoritmi di key exchange e 11 nuove hostkeys&#xA;ecc.&#xA;&#xA;Anche sshaudit.com è di nuovo online anche se le guide non hanno ancora recepito gli aggiornamenti presenti nella cli.&#xA;&#xA;Ma la notizia più rincuorante è che pare che Joe Testa stia bene e che abbia trovato uno sponsor che sta finanziando il suo sviluppo.&#xA;&#xA;Mi riservo di approfondire a breve.&#xA;&#xA;Intanto ben ritornato, Joe Testa ❤️. &#xA;&#xA;#ssh #sshaudit]]&gt;</description>
      <content:encoded><![CDATA[<p><img src="https://pixelfed.uno/storage/m/_v2/489827599091373610/4c90d8e69-c5a1c2/BWleV9bHP3yP/QpgAO24mgYLinoTiMlgEqitAqICyn6z59JBhydu0.jpg" alt="tux-sshaudit"></p>

<p>Oh, gaudio!</p>

<p>Oh, giubilo!</p>

<p><a href="https://github.com/jtesta/ssh-audit" rel="nofollow">ssh–audit</a> è di nuovo fra noi.

Il 4 luglio 2026 Joe Testa porta la sua creatura dalla versione 3.3.0, risalente ormai a due anni fa, alla <a href="https://github.com/jtesta/ssh-audit/releases/tag/v3.9.0" rel="nofollow">versione 3.9.0</a>, un aggiornamento corposo che riguarda:</p>
<ul><li>aggiornamento supporto python 3.14, eliminazione python 3.8 e python 3.9</li>
<li>preparazione alla crittografia post-quantistica (warning se gli algoritmi di exchange non lo sono)
rimozione supporto sshv1</li>
<li><strong>Modifica della policy built-in per Debian 12</strong></li>
<li><strong>Aggiunta delle policy built-in per OpenSSH 10.0, 10.1, 10.2, 10.3, and 10.4.</strong></li>
<li><strong>Aggiunta delle guide all’hardenizzazione di Debian 13, Rocky Linux 10, Ubuntu 26.04.</strong></li>
<li>**Avendo sempre come riferimento la resistenza post quantistica, sono stati aggiunti due nuovi algoritmi di key exchange e 11 nuove host_keys</li>
<li>ecc.</li></ul>

<p>Anche <a href="https://www.sshaudit.com" rel="nofollow">sshaudit.com</a> è di nuovo online anche se le guide non hanno ancora recepito gli aggiornamenti presenti nella cli.</p>

<p>Ma la notizia più rincuorante è che pare che Joe Testa stia bene e che abbia trovato uno sponsor che sta finanziando il suo sviluppo.</p>

<p>Mi riservo di approfondire a breve.</p>

<p>Intanto ben ritornato, Joe Testa ❤️.</p>

<p><a href="/aytin/tag:ssh" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">ssh</span></a> <a href="/aytin/tag:sshaudit" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">sshaudit</span></a></p>
]]></content:encoded>
      <guid>https://noblogo.org/aytin/sshaudit-com-di-nuovo-online</guid>
      <pubDate>Mon, 13 Jul 2026 03:57:06 +0000</pubDate>
    </item>
    <item>
      <title>Sveliamo i misteri di Firewalld (Parte 2 di 2)</title>
      <link>https://noblogo.org/aytin/sveliamo-i-misteri-di-firewalld-parte-2-di-2</link>
      <description>&lt;![CDATA[tux-firewalld&#xA;---&#xA;N.B. Sono stato costretto a spezzare l&#39;articolo perché, quello originale di 8836 parole (per un totale di 76309 bytes effettivi), veniva troncato dopo il salvataggio a 7533 parole (65.356 bytes), cosa che mi fa sospettare che la grandezza del body non possa superare i 64k.&#xA;---&#xA;Nel capitolo precedente (Sveliamo i misteri di firewalld (Parte 1 di 2), abbiamo esaminato abbastanza nel dettaglio la cli di firewalld (firewall-cmd) con un focus particolare sul suo man, fatto molto bene.&#xA;&#xA;Nel seguito ci concentreremo soprattutto su casi d&#39;uso per vedere firewalld in azione, analizzando alcuni possibili cortocircuiti logici e approfondendo  quanto già enunciato nei capitoli 1, 2, 4 della parte 1.&#xA;!--more--&#xA;&#xA;5. Esempi&#xA;   5.1. Caso 1: host con una sola interfaccia&#xA;      5.1.2. Esposizione di servizi custom con restrizioni&#xA;      5.1.3. Esposizione con port forwarding statico&#xA;   5.2. Caso 2: Configurazione di un fw personale su un host con 3 interfacce&#xA;   5.3. Caso 3: Router Firewall-Gateway&#xA;   5.4. Trappole nascoste&#xA;      5.4.1. Caso 1. Restrizioni con solo \-\-add-source&#xA;      5.4.2. Caso 2: Combinazione di \-\-add-source e \-\-add-interface&#xA;      5.4.3. Remediation per la zone &#34;hijacking&#34;&#xA;6. Tips&#xA;&#x9;6.1. Le azioni di firewall-cmd&#xA;&#x9;6.2. Comandi utili&#xA;&#x9;6.3. Considerazioni di contorno&#xA;&#xA;5. Esempi&#xA;Nel configurare firewalld, da utente, la difficoltà più grande per me consiste nel sapersi districare in mezzo alla ragnatela di zone, policy, servizi, nat, rich-rules ecc.&#xA;&#xA;Come dicevo in precedenza per un firewall personale, bastano le zone con la dichiarazione dei servizi, così da filtrare il traffico in ingresso e finisce il gioco.&#xA;&#xA;Quando invece lo scenario si complica, è necessario capire bene come funzioni il routing dei pacchetti fatto da firewalld e qual sia l&#39;ordine di valutazione che firewalld fa dei vari oggetti che poi si traduce nell&#39;accettazione o nel rifiuto del pacchetto.&#xA;&#xA;Provo a tracciare una scaletta che però è frutto di esperienza nell&#39;uso, di sperimentazione  personale, nulla di ufficiale.&#xA;&#xA;Fase 1: Associazione alle Zone&#xA;firewalld per prima cosa deve capire quali siano le zone interessate controllando l&#39;ip sorgente del pacchetto.&#xA;&#xA;Se c&#39;è una sorgente associata esplicitamente ad una zona, il pacchetto viene assegnato a quella zona.&#xA;Se non c&#39;è alcuna sorgente, si controlla l&#39;interfaccia fisica da cui è entrato il pacchetto e si assegna alla zona che trusta quell&#39;interfaccia.&#xA;Se non c&#39;è nessuna zona associata all&#39;interfaccia, il pacchetto finisce alla zona impostata come default&#xA;&#xA;Fase 2: Selezione del contesto (zone vs policy)&#xA;Una volta identificate la zona di ingresso (e l&#39;eventuale zona di uscita se il traffico è in transito/forwarding), firewalld decide quale &#34;contenitore di regole&#34; applicare:&#xA;&#xA;Le policy vengono valutate prima delle singole regole delle zone.&#xA;In base alle zone associate, firewalld verifica se esiste una Policy che le unisce e applica i filtri presenti nella policy&#xA;Se non ci sono policy object applicabili a quel flusso, il pacchetto viene processato direttamente all&#39;interno della singola zona identificata nella Fase 1. Questo vuol dire che se ci sono filtri nella zona e c&#39;è una policy del tipo zone-to-host, i filtri della policy vincono.&#xA;&#xA;Fase 3: Valutazione delle regole interne (servizi, porte e NAT)&#xA;Ora che abbiamo il contesto, è importante capire in che ordine firewalld applica i filtri.&#xA;&#xA;come prima cosa si valutano le rich-rules con priorità negativa;&#xA;in seguito si prende in esame il dnat in modo che i filtri successivi lavorino sull&#39;indirizzo e sulla porta di destinazione corretti;&#xA;successivamente si valutano i servizi e le porte standard, quelli aggiunti con --add-service e --add-port per capirci&#xA;dopo i servizi, vengono valutate le rich-rule tradizionali, quelle con priorità 0&#xA;come ultimo passo, se c&#39;è, viene preso in carico il SNAT Masquerade&#xA;&#xA;Fase 4: Il target di default&#xA;Se un pacchetto è arrivato fino a questo punto significa che non ha trovato nessuna regola esplicita (nessun servizio o porta lo ha accettato o rifiutato prima) e viene applicato il target della zona (DROP/REJECT/ACCEPT/default) o della policy (DROP/REJECT/ACCEPT/CONTINUE)&#xA;&#xA;La fase 3 è quella critica, quella che emette il verdetto di accettazione o rifiuto. E qui bisogna fare attenzione.&#xA;&#xA;Le azioni di manipolazione dei pacchetti come il NAT non corrispondono ad un verdetto, che avviene invece:&#xA;&#xA;nei servizi (--add-service o --add-port): accettazione (o rifiuto) implicita&#xA;nelle rich-rule se uno dei target viene esplicitato&#xA;&#xA;Quindi, ad es. se nella zona o nella policy, c&#39;è un add-service che accetta un determinato servizio e di seguito una rich rule che invece lo nega, add-service ha priorità e un pacchetto che richieda quel servizio verrebbe accettato e non scartato. Come pure, in una zona/policy default drop, se fosse presente un masquerade o un dnat senza alcuna accettazione esplicite, il pacchetto verrebbe rifiutato dalle politiche della zona/policy.&#xA;&#xA;Alla luce di questa nuova consapevolezza, proverò a mostrare  come risolvere alcuni tipici casi d&#39;uso, partendo dalla configurazione di un semplice firewall personale che protegge l&#39;esposizione di servizi standard, per proseguire in maniera incrementale arricchendo di volta in volta la configurazione iniziale.&#xA;5.1. Caso 1: host con una sola interfaccia&#xA;È il caso classico di un personal firewall.&#xA;&#xA;Nel primo blocco di esempi mostrerò anche le configurazioni di un approccio full-policy. &#xA;&#xA;Non ci sono vantaggi evidenti perché si tratta di casi semplici però concentrare la logica nelle policy piuttosto che nelle zone permette per es. di bloccare tutto il traffico in una zona default drop semplicemente disabilitando la policy.&#xA;&#xA;Oppure posso usare la stessa logica di filtraggio su altre zone senza doverle replicare ma solo aggiungendo egress-zone e ingress-zone opportue. &#xA;5.1.1. Esposizione semplice&#xA;Ipotizziamo quindi di avere un host con una sola interfaccia e di voler configurare il firewall per filtrare i servizi ssh (22/tcp) e http(s) (80,443/tcp) che questo host espone su una lan.&#xA;&#xA;Versione zone-oriented:&#xA;creazione zona, binding su eth0, policy di default DROP (l&#39;host non sarà nemmeno &#34;pingabile&#34;)&#xA;firewall-cmd --permanent --new-zone=server-lan&#xA;firewall-cmd --permanent --zone=&#34;server-lan&#34; --set-target=DROP&#xA;firewall-cmd --permanent --zone=&#34;server-lan&#34; --add-interface=eth0&#xA;&#xA;abilitazione servizi ssh, http(s)&#xA;firewall-cmd --permanent --zone=&#34;server-lan&#34; --add-service=ssh&#xA;firewall-cmd --permanent --zone=&#34;server-lan&#34; --add-service=http&#xA;firewall-cmd --permanent --zone=&#34;server-lan&#34; --add-service=https&#xA;Come si può vedere, la configurazione è pulita, lineare ed è veramente &#34;parlante&#34;.&#xA;Chiunque bussi all&#39;interfaccia eth0, accede ai servizi esposti dall&#39;host.&#xA;&#xA;Versione policy-oriented:&#xA;creazione zona, binding su eth0, policy di default DROP (l&#39;host non sarà nemmeno &#34;pingabile&#34;)&#xA;firewall-cmd --permanent --new-zone=&#34;server-lan&#34;&#xA;firewall-cmd --permanent --zone=&#34;server-lan&#34; --set-target=DROP&#xA;firewall-cmd --permanent --zone=&#34;server-lan&#34; --add-interface=eth0&#xA;&#xA;creazione policy&#xA;firewall-cmd --permanent --new-policy=&#34;lan-to-host&#34;&#xA;firewall-cmd --permanent --policy=&#34;lan-to-host&#34; --add-ingress-zone=&#34;server-lan&#34;&#xA;firewall-cmd --permanent --policy=&#34;lan-to-host&#34; --add-egress-zone=HOST&#xA;firewall-cmd --permanent --policy=&#34;lan-to-host&#34; --set-target=REJECT&#xA;&#xA;binding dei servizi ssh, http(s)&#xA;firewall-cmd --permanent --policy=lan-to-host --add-service=ssh&#xA;firewall-cmd --permanent --policy=lan-to-host --add-service=http&#xA;firewall-cmd --permanent --policy=lan-to-host --add-service=https&#xA;Non cambia quasi nulla se non il fatto che il filtering ora avviene attraverso la policy mentre la zona contiene solo il trust delle sorgenti.&#xA;5.1.2. Esposizione di servizi custom con restrizioni&#xA;L&#39;host stavolta esporrà i servizi su porte custom con questi vincoli:&#xA;&#xA;chiunque bussi a eth0 avrà accesso web&#xA;mentre ssh sarà ristretto al solo ip 192.168.10.21&#xA;&#xA;Versione zone-oriented:&#xA;creazione zona, binding su eth0, policy di default DROP (l&#39;host non sarà nemmeno &#34;pingabile&#34;)&#xA;firewall-cmd --permanent --new-zone=server-lan&#xA;firewall-cmd --permanent --zone=&#34;server-lan&#34; --set-target=DROP&#xA;firewall-cmd --permanent --zone=&#34;server-lan&#34; --add-interface=eth0&#xA;&#xA;creazione servizio &#34;webcustom&#34;&#xA;firewall-cmd --permanent --new-service=&#34;webcustom&#34;&#xA;firewall-cmd --permanent --service=&#34;webcustom&#34; --set-description=&#34;My HTTP(S) service&#34;&#xA;firewall-cmd --permanent --service=&#34;webcustom&#34; --add-port=8080/tcp --add-port=8443/tcp&#xA;&#xA;creazione servizio &#34;sshcustom&#34;&#xA;firewall-cmd --permanent --new-service=&#34;sshcustom&#34;&#xA;firewall-cmd --permanent --service=&#34;sshcustom&#34; --set-description=&#34;My SSH service&#34;&#xA;firewall-cmd --permanent --service=&#34;sshcustom&#34; --add-port=2222/tcp&#xA;&#xA;chiunque bussi a eth0 sulle porte 8080 e 8443, verrà accettato &#xA;firewall-cmd --permanent --zone=&#34;server-lan&#34; --add-service=webcustom&#xA;&#xA;sshcustom invece è ristretto con una rich-rule al solo ip 192.168.10.21&#xA;firewall-cmd --permanent --zone=&#34;server-lan&#34; --add-rich-rule=&#39;rule family=&#34;ipv4&#34; source address=&#34;192.168.10.21&#34; service name=&#34;sshcustom&#34; accept&#39;&#xA;Versione policy-oriented:&#xA;creazione zona, binding su eth0, policy di default DROP (l&#39;host non sarà nemmeno &#34;pingabile&#34;)&#xA;firewall-cmd --permanent --new-zone=&#34;server-lan&#34;&#xA;firewall-cmd --permanent --zone=&#34;server-lan&#34; --set-target=DROP&#xA;firewall-cmd --permanent --zone=&#34;server-lan&#34; --add-interface=eth0&#xA;&#xA;creazione servizio &#34;webcustom&#34;&#xA;firewall-cmd --permanent --new-service=&#34;webcustom&#34;&#xA;firewall-cmd --permanent --service=&#34;webcustom&#34; --set-description=&#34;My HTTP(S) service&#34;&#xA;firewall-cmd --permanent --service=&#34;webcustom&#34; --add-port=8080/tcp --add-port=8443/tcp&#xA;&#xA;creazione servizio &#34;sshcustom&#34;&#xA;firewall-cmd --permanent --new-service=&#34;sshcustom&#34;&#xA;firewall-cmd --permanent --service=&#34;sshcustom&#34; --set-description=&#34;My SSH service&#34;&#xA;firewall-cmd --permanent --service=&#34;sshcustom&#34; --add-port=2222/tcp&#xA;&#xA;creazione policy&#xA;firewall-cmd --permanent --new-policy=&#34;lan-to-host&#34;&#xA;firewall-cmd --permanent --policy=&#34;lan-to-host&#34; --add-ingress-zone=&#34;server-lan&#34;&#xA;firewall-cmd --permanent --policy=&#34;lan-to-host&#34; --add-egress-zone=HOST&#xA;firewall-cmd --permanent --policy=&#34;lan-to-host&#34; --set-target=REJECT&#xA;&#xA;binding webcustom su tutta eth0&#xA;firewall-cmd --permanent --policy=&#34;lan-to-host&#34; --add-service=webcustom&#xA;&#xA;sshcustom invece è ristretto con una rich-rule al solo ip 192.168.10.21&#xA;firewall-cmd --permanent --policy=&#34;lan-to-host&#34; --add-rich-rule=&#39;rule family=&#34;ipv4&#34; source address=&#34;192.168.10.21&#34; service name=&#34;sshcustom&#34; accept&#39;&#xA;5.1.3. Esposizione con port forwarding statico&#xA;Facciamo il caso che i servizi ssh e web siano in ascolto sull&#39;interfaccia di loopback.&#xA;Vogliamo comunque esporli attraverso un port redirect facendo in modo che:&#xA;&#xA;HOST:22   → localhost:2222&#xA;HOST:8080 → localhost:8080&#xA;HOST:8443 → localhost:8443&#xA;&#xA;In più vogliamo restringere l&#39;accesso ssh a 3 soli ip: 192.168.10.20, 192.168.10.21, 192.168.10.22 e vogliamo bloccare tutto il traffico ICMP ad eccezione di echo-request.&#xA;&#xA;Versione zone-oriented:&#xA;creazione zona, binding su eth0, policy di default DROP&#xA;firewall-cmd --permanent --new-zone=&#34;server-lan&#34;&#xA;firewall-cmd --permanent --zone=&#34;server-lan&#34; --set-target=DROP&#xA;firewall-cmd --permanent --zone=&#34;server-lan&#34; --add-interface=eth0&#xA;&#xA;icmp solo request&#xA;firewall-cmd --permanent --zone=&#34;server-lan&#34; --add-icmp-block-inversion&#xA;firewall-cmd --permanent --zone=&#34;server-lan&#34; --add-icmp-block=echo-request&#xA;&#xA;ipset per ssh&#xA;firewall-cmd --permanent --new-ipset=&#34;ssh-allowed&#34; --type=hash:ip&#xA;firewall-cmd --permanent --ipset=&#34;ssh-allowed&#34; --add-entry=&#34;192.168.10.20&#34; &#xA;firewall-cmd --permanent --ipset=&#34;ssh-allowed&#34; --add-entry=&#34;192.168.10.21&#34; &#xA;firewall-cmd --permanent --ipset=&#34;ssh-allowed&#34; --add-entry=&#34;192.168.10.22&#34;&#xA;&#xA;Esposizione dei servizi&#xA;firewall-cmd --permanent --zone=&#34;server-lan&#34; --add-service=&#34;http&#34;&#xA;firewall-cmd --permanent --zone=&#34;server-lan&#34; --add-service=&#34;https&#34;&#xA;firewall-cmd --permanent --zone=&#34;server-lan&#34; --add-service=&#34;ssh&#34;&#xA;&#xA;Per il local forward è necessario abilitare il routing verso loopback&#xA;sysctl -w net.ipv4.conf.eth0.routelocalnet=1&#xA;&#xA;local forward 80 → 8080, 443 → 8443&#xA;firewall-cmd --permanent --zone=&#34;server-lan&#34; --add-forward-port=port=80:proto=tcp:to-port=8080:to-addr=127.0.0.1&#xA;firewall-cmd --permanent --zone=&#34;server-lan&#34; --add-forward-port=port=443:proto=tcp:to-port=8443:to-addr=127.0.0.1&#xA;&#xA;rich-rule per l&#39;accesso filtrato ssh con local forward 22 → 2222&#xA;firewall-cmd --permanent --zone=&#34;server-lan&#34; --add-rich-rule=&#39;rule family=&#34;ipv4&#34; source ipset=&#34;ssh-allowed&#34; forward-port port=&#34;22&#34; protocol=&#34;tcp&#34; to-port=&#34;2222&#34; to-addr=&#34;127.0.0.1&#34;&#39;&#xA;Anche qui la configurazione rimane molto pulita e lineare.&#xA;&#xA;Versione policy-oriented:&#xA;creazione zona, binding su eth0, policy di default DROP&#xA;firewall-cmd --permanent --new-zone=&#34;server-lan&#34;&#xA;firewall-cmd --permanent --zone=&#34;server-lan&#34; --set-target=DROP&#xA;firewall-cmd --permanent --zone=&#34;server-lan&#34; --add-interface=eth0&#xA;&#xA;icmp solo request&#xA;firewall-cmd --permanent --zone=&#34;server-lan&#34; --add-icmp-block-inversion&#xA;firewall-cmd --permanent --zone=&#34;server-lan&#34; --add-icmp-block=echo-request&#xA;&#xA;ipset per ssh&#xA;firewall-cmd --permanent --new-ipset=&#34;ssh-allowed&#34; --type=hash:ip&#xA;firewall-cmd --permanent --ipset=&#34;ssh-allowed&#34; --add-entry=&#34;192.168.10.20&#34;&#xA;firewall-cmd --permanent --ipset=&#34;ssh-allowed&#34; --add-entry=&#34;192.168.10.21&#34;&#xA;firewall-cmd --permanent --ipset=&#34;ssh-allowed&#34; --add-entry=&#34;192.168.10.22&#34;&#xA;&#xA;firewall-cmd --permanent --new-policy=&#34;lan-to-host&#34;&#xA;firewall-cmd --permanent --policy=&#34;lan-to-host&#34; --add-ingress-zone=&#34;server-lan&#34;&#xA;firewall-cmd --permanent --policy=&#34;lan-to-host&#34; --add-egress-zone=HOST&#xA;firewall-cmd --permanent --policy=&#34;lan-to-host&#34; --set-target=REJECTED&#xA;&#xA;Esposizione dei servizi&#xA;firewall-cmd --permanent --policy=&#34;lan-to-host&#34; --add-service=&#34;http&#34;&#xA;firewall-cmd --permanent --policy=&#34;lan-to-host&#34; --add-service=&#34;https&#34;&#xA;firewall-cmd --permanent --policy=&#34;lan-to-host&#34; --add-service=&#34;ssh&#34;&#xA;&#xA;Per il local forward è necessario abilitare il routing verso loopback&#xA;sysctl -w net.ipv4.conf.eth0.routelocalnet=1&#xA;&#xA;local forward 80 → 8080, 443 → 8443&#xA;firewall-cmd --permanent --policy=&#34;lan-to-host&#34; --add-forward-port=port=80:proto=tcp:to-port=8080:to-addr=127.0.0.1&#xA;firewall-cmd --permanent--policy=&#34;lan-to-host&#34; --add-forward-port=port=443:proto=tcp:to-port=8443:to-addr=127.0.0.1&#xA;&#xA;rich-rule per l&#39;accesso filtrato ssh con local forward 22 → 2222&#xA;firewall-cmd --permanent --policy=&#34;lan-to-host&#34; --add-rich-rule=&#39;rule family=&#34;ipv4&#34; source ipset=&#34;ssh-allowed&#34; forward-port port=&#34;22&#34; protocol=&#34;tcp&#34; to-port=&#34;2222&#34; to-addr=&#34;127.0.0.1&#34;&#39;&#xA;N.B. In realtà, casi di questo genere che non rientrano nella casistica più ampia del routing e del dnat che giustificherebbero l&#39;uso di regole firewall, si risolverebbero più elegantemente con un reverse proxy (posto che i servizi siano reverse-proxabili), agire quindi a livello applicativo (L7) invece che a livello di indirizzamento e trasporto (L3 e L4 rispettivamente.)&#xA;&#xA;Infine, ciliegina sulla torta, vogliamo che sia filtrato anche il traffico in uscita consentendo solo il traffico web  per gli aggiornamenti di sistema (80,443/tcp) e quello dns (53/udp)&#xA;&#xA;Sarà necessario un policy object per il flusso in uscita, sia nella versione zone-oriented che in quella policy-oriented&#xA;creazione policy object, default policy REJECT&#xA;firewall-cmd --permanent --new-policy=host-to-any&#xA;firewall-cmd --permanent --policy=host-to-any --set-target=REJECT&#xA;&#xA;definizione della direzione del traffico: HOST → dmz (eth0)&#xA;firewall-cmd --permanent --policy=&#34;host-to-any&#34; --add-ingress-zone=HOST&#xA;firewall-cmd --permanent --policy=&#34;host-to-any&#34; --add-egress-zone=myZone&#xA;&#xA;traffico consentito: http(s), dns&#xA;firewall-cmd --permanent --policy=&#34;host-to-any&#34; --add-service=http&#xA;firewall-cmd --permanent --policy=&#34;host-to-any&#34; --add-service=https&#xA;firewall-cmd --permanent --policy=&#34;host-to-any&#34; --add-service=dns&#xA;Per la configurazione di un firewall personale, esempi di questo tipo coprono il 95% dei casi ordinari, anche senza considerare il filtro del traffico in uscita.&#xA;5.2. Caso 2: Configurazione di un fw personale su un host con 3 interfacce&#xA;Proviamo a immaginare uno scenario leggermente più complesso, un host con 3 interfacce per segregare la rete in 3 flussi: management, ingresso, uscita. &#xA;&#xA;un&#39;interfaccia per la rete di management (eth0: 192.168.0.0/24)&#xA;un&#39;interfaccia per il traffico in ingresso, la rete per il provisioning o per i servizi che l&#39;host espone (eth1: 192.168.1.0/24)&#xA;un&#39;interfaccia per il data networking, la rete server-to server (eth2: 192.168.2.0/24)&#xA;&#xA;L&#39;host espone un servizio web, fa delle richieste ad un server mysql nel backend e consente di essere contattato via ssh per il management.&#xA;Dall&#39;interfaccia di backend invece l&#39;host non può essere contattato.&#xA;&#xA;Le policy invece riguarderanno la gestione del traffico in ingresso, dalle rispettive interfacce solo per ssh e web, e del traffico in uscita solo verso il backend mysql.&#xA;ip che possono accedere al management dell&#39;host&#xA;firewall-cmd --permanent --new-ipset=&#34;sshallowed&#34; --type=&#34;hash:net&#34;&#xA;firewall-cmd --permanent --ipset=&#34;sshallowed&#34; --add-entry=&#34;192.168.5.32/27&#34; --add-entry=&#34;192.168.6.32/27&#34;&#xA;&#xA;per aggregare http/https in un unico servizio&#xA;firewall-cmd --permanent --new-service=&#34;web&#34;&#xA;firewall-cmd --permanent --service=&#34;web&#34; --add-include=&#34;http&#34; --add-include=&#34;https&#34;&#xA;&#xA;zona di management&#xA;firewall-cmd --permanent --new-zone=&#34;mgmt&#34;&#xA;firewall-cmd --permanent --zone=&#34;mgmt&#34; --add-interface=eth0&#xA;firewall-cmd --permanent --zone=&#34;mgmt&#34; --set-target=DROP&#xA;&#xA;zona del servizio web&#xA;firewall-cmd --permanent --new-zone=&#34;webserver&#34;&#xA;firewall-cmd --permanent --zone=&#34;webserver&#34; --add-interface=eth1&#xA;firewall-cmd --permanent --zone=&#34;webserver&#34; --set-target=DROP&#xA;&#xA;zona del backend&#xA;firewall-cmd --permanent --new-zone=&#34;backend&#34;&#xA;firewall-cmd --permanent --zone=&#34;backend&#34; --add-interface=eth2&#xA;firewall-cmd --permanent --zone=&#34;backend&#34; --set-target=DROP&#xA;&#xA;policy per il traffico WEBSERVER → HOST (traffico IN ↑)&#xA;firewall-cmd --permanent --new-policy=&#34;any-to-webserver&#34;&#xA;firewall-cmd --permanent --policy=&#34;any-to-webserver&#34; --add-ingress-zone=webserver&#xA;firewall-cmd --permanent --policy=&#34;any-to-webserver&#34; --add-egress-zone=HOST&#xA;firewall-cmd --permanent --policy=&#34;any-to-webserver&#34; --set-target=DROP&#xA;firewall-cmd --permanent --policy=&#34;any-to-webserver&#34; --add-service=&#34;web&#34;&#xA;&#xA;policy per il traffico MGMT → HOST (traffico IN ↑)&#xA;firewall-cmd --permanent --new-policy=&#34;mgmt-host&#34;&#xA;firewall-cmd --permanent --policy=&#34;mgmt-host&#34; --add-ingress-zone=mgmt&#xA;firewall-cmd --permanent --policy=&#34;mgmt-host&#34; --add-egress-zone=HOST&#xA;firewall-cmd --permanent --policy=&#34;mgmt-host&#34; --set-target=DROP&#xA;firewall-cmd --permanent --policy=&#34;mgmt-host&#34; --add-rich-rule=&#39;rule family=&#34;ipv4&#34; source ipset=&#34;sshallowed&#34; service name=&#34;ssh&#34; accept&#39;&#xA;&#xA;policy per il traffico HOST → backend (traffico OUT ↓)&#xA;firewall-cmd --permanent --new-policy=&#34;webserver-to-backend&#34;&#xA;firewall-cmd --permanent --policy=&#34;webserver-to-backend&#34; --add-ingress-zone=HOST&#xA;firewall-cmd --permanent --policy=&#34;webserver-to-backend&#34; --add-egress-zone=backend&#xA;firewall-cmd --permanent --policy=&#34;webserver-to-backend&#34; --set-target=DROP&#xA;firewall-cmd --permanent --policy=&#34;webserver-to-backend&#34; --add-rich-rule=&#39;rule family=&#34;ipv4&#34; service name=&#34;mysql&#34; accept&#39;&#xA;Il fatto che ci siano servizi con restrizioni sul sorgente, mi permetterà di porre l&#39;attenzione su una particolarità di firewalld poco evidente ma responsabile di errori talmente gravi da invalidare le nostre policy di sicurezza.&#xA;&#xA;In generale, i servizi con restrizioni si gestiscono SEMPRE con rich-rule per evitare spiacevoli effetti laterali.&#xA;&#xA;Le rich-rules danno la granularità necessaria in questi casi accettando solo il traffico indicato in zone default drop.&#xA;&#xA;Come negli esempi precedenti, alle definizioni di zona posso sostituire quelle di policy se voglio un approccio policy-oriented.&#xA;5.3. Caso 3: Router Firewall-Gateway&#xA;Ora facciamo l&#39;esempio del classico router-firewall domestico.&#xA;&#xA;L&#39;host avrà quattro interfacce per altrettante reti. Una wan, una rete guest, una dmz e un backend che ospita servizi.&#xA;&#xA;Condizioni&#xA;&#xA;In DMZ c&#39;è un reverse proxy, un server web e un client di file sharing (p2p).&#xA;Il Backend ospita un server mysql ad uso del server web, un servizio di file sharing solo per la rete di Backend (nfs).&#xA;La rete pubblica non accetta connessioni in ingresso, salvo che quelle destinate al reverse proxy e al client di file sharing via port forwarding.&#xA;Il reverseproxy media il contatto col server web che gira in localhost.&#xA;Il Backend è inaccessibile da qualunque rete. La DMZ può contattare il Backend esclusivamente per i transiti:&#xA;&#x9;server web → server mysql&#xA;&#x9;client p2p → server nfs&#xA;La rete guest ha accesso pieno a internet ma deve essere isolata sia da DMZ che da Backend. Anche i servizi esposti in DMZ possono essere contattati solo da rete pubblica.&#xA;&#xA;Piano di indirizzamento&#xA;&#xA;wan0: 151.22.44.88, è l&#39;indirizzo ip della zona pubblica&#xA;eth0: 192.168.1.1 (192.168.1.0/24), gateway per la DMZ&#xA;wlan0: 192.168.2.1 (192.168.2.0/24), gateway per il Backend&#xA;wlan1: 192.168.3.1 (192.168.3.0/24), gateway per il guest.&#xA;&#xA;Host in DMZ&#xA;&#xA;192.168.1.2: server reverse-proxy (port 8080,8443)  / web (localhost)&#xA;192.168.1.3:  client p2p (port 36119)&#xA;&#xA;Host in Backend&#xA;&#xA;192.168.2.2: server mysql (port 3306)&#xA;192.168.2.3: server nfs (port 2049)&#xA;&#xA;###########&#xA;Servizi &#xA;###########&#xA;firewall-cmd --permanent --new-service=&#34;web&#34;&#xA;firewall-cmd --permanent --service=&#34;web&#34; --add-include=&#34;http&#34; --add-include=&#34;https&#34;&#xA;&#xA;firewall-cmd --permanent --new-service=&#34;p2p&#34;&#xA;firewall-cmd --permanent --service=&#34;p2p&#34; --add-port=&#34;36119/tcp&#34; --add-port=&#34;36119/udp&#34;&#xA;&#xA;########&#xA;Zone &#xA;########&#xA;firewall-cmd --permanent --new-zone=&#34;pubblica&#34;&#xA;firewall-cmd --permanent --zone=&#34;pubblica&#34; --add-interface=&#34;wan0&#34;&#xA;firewall-cmd --permanent --zone=&#34;pubblica&#34; --set-target=DROP&#xA;&#xA;firewall-cmd --permanent --new-zone=&#34;dmz&#34;&#xA;firewall-cmd --permanent --zone=&#34;dmz&#34; --add-interface=&#34;eth0&#34;&#xA;firewall-cmd --permanent --zone=&#34;dmz&#34; --set-target=DROP&#xA;&#xA;firewall-cmd --permanent --new-zone=&#34;p2p&#34;&#xA;firewall-cmd --permanent --zone=&#34;p2p&#34; --add-interface=&#34;eth1&#34;&#xA;firewall-cmd --permanent --zone=&#34;p2p&#34; --set-target=DROP&#xA;&#xA;firewall-cmd --permanent --new-zone=&#34;backend&#34;&#xA;firewall-cmd --permanent --zone=&#34;backend&#34; --add-interface=&#34;wlan0&#34;&#xA;firewall-cmd --permanent --zone=&#34;backend&#34; --set-target=DROP&#xA;&#xA;firewall-cmd --permanent --new-zone=&#34;guest&#34;&#xA;firewall-cmd --permanent --zone=&#34;guest&#34; --add-interface=&#34;wlan1&#34;&#xA;firewall-cmd --permanent --zone=&#34;guest&#34; --set-target=DROP&#xA;&#xA;##########&#xA;Policy &#xA;##########&#xA;##############################&#xA;pubblica-dmz (wan0 → eth0) &#xA;##############################&#xA;Dalla rete pubblica arrivano le richieste da inoltrare sui&#xA;server interni (DMZ).&#xA;Definizione policy con default target DROP.&#xA;firewall-cmd --permanent --new-policy=&#34;pubblica-to-dmz&#34;&#xA;firewall-cmd --permanent --policy=&#34;pubblica-to-dmz&#34; --add-ingress-zone=&#34;pubblica&#34;&#xA;firewall-cmd --permanent --policy=&#34;pubblica-to-dmz&#34; --add-egress-zone=&#34;dmz&#34;&#xA;firewall-cmd --permanent --policy=&#34;pubblica-to-dmz&#34; --set-target=DROP&#xA;Inoltri consentiti verso il reverse proxy.&#xA;firewall-cmd --permanent --policy=&#34;pubblica-to-dmz&#34; --add-rich-rule=&#39;rule family=&#34;ipv4&#34; forward-port port=&#34;80&#34; protocol=&#34;tcp&#34; to-port=&#34;8080&#34; to-addr=&#34;192.168.1.2&#34; accept&#39;&#xA;firewall-cmd --permanent --policy=&#34;pubblica-to-dmz&#34; --add-rich-rule=&#39;rule family=&#34;ipv4&#34; forward-port port=&#34;443&#34; protocol=&#34;tcp&#34; to-port=&#34;8443&#34; to-addr=&#34;192.168.1.2&#34; accept&#39;&#xA;firewall-cmd --permanent --policy=&#34;pubblica-to-dmz&#34; --add-rich-rule=&#39;rule family=&#34;ipv4&#34; forward-port port=&#34;36119&#34; protocol=&#34;tcp&#34; to-port=&#34;36119&#34; to-addr=&#34;192.168.1.3&#34; accept&#39;&#xA;firewall-cmd --permanent --policy=&#34;pubblica-to-dmz&#34; --add-rich-rule=&#39;rule family=&#34;ipv4&#34; forward-port port=&#34;36119&#34; protocol=&#34;udp&#34; to-port=&#34;36119&#34; to-addr=&#34;192.168.1.3&#34; accept&#39;&#xA;&#xA;##############################&#xA;dmz-backend (eth0 → wlan0) &#xA;##############################&#xA;Solo il reverse proxy (DMZ) può contattare mysql e nfs (Backend).&#xA;Definizione policy con default target DROP.&#xA;firewall-cmd --permanent --new-policy=&#34;dmz-to-backend&#34;&#xA;firewall-cmd --permanent --policy=&#34;dmz-to-backend&#34; --add-ingress-zone=&#34;dmz&#34;&#xA;firewall-cmd --permanent --policy=&#34;dmz-to-backend&#34; --add-egress-zone=&#34;backend&#34;&#xA;firewall-cmd --permanent --policy=&#34;dmz-to-backend&#34; --set-target=DROP&#xA;Transito consentito solo per rp verso mysql e per p2p verso nfs.&#xA;firewall-cmd --permanent --policy=&#34;dmz-to-backend&#34; --add-rich-rule=&#39;rule family=&#34;ipv4&#34; source address=&#34;192.168.1.2&#34; destination address=&#34;192.168.2.2&#34; service name=&#34;mysql&#34; accept&#39;&#xA;firewall-cmd --permanent --policy=&#34;dmz-to-backend&#34; --add-rich-rule=&#39;rule family=&#34;ipv4&#34; source address=&#34;192.168.1.3&#34; destination address=&#34;192.168.2.3&#34; service name=&#34;p2p&#34; accept&#39;&#xA;&#xA;##############################&#xA;dmz-pubblica (eth0 → wan0) &#xA;##############################&#xA;Abilitazione del solo browsing agli host (nattati) in DMZ.&#xA;Abilitazione full all&#39;host p2p (nattato) in DMZ.&#xA;Definizione policy con default target DROP.&#xA;firewall-cmd --permanent --new-policy=&#34;dmz-to-pubblica&#34;&#xA;firewall-cmd --permanent --policy=&#34;dmz-to-pubblica&#34; --add-ingress-zone=&#34;dmz&#34;&#xA;firewall-cmd --permanent --policy=&#34;dmz-to-pubblica&#34; --add-egress-zone=&#34;pubblica&#34;&#xA;firewall-cmd --permanent --policy=&#34;dmz-to-pubblica&#34; --set-target=DROP&#xA;Servizi&#xA;firewall-cmd --permanent --policy=&#34;dmz-to-pubblica&#34; --add-rich-rule=&#39;rule family=&#34;ipv4&#34; source address=&#34;192.168.1.2 service=&#34;web&#34; masquerade accept&#39;&#xA;firewall-cmd --permanent --policy=&#34;dmz-to-pubblica&#34; --add-rich-rule=&#39;rule family=&#34;ipv4&#34; source address=&#34;192.168.1.3 masquerade accept&#39;&#xA;&#xA;##################################&#xA;backend-pubblica (eth0 → wan0) &#xA;##################################&#xA;Abilitazione del solo browsing degli host (nattati) in Backend.&#xA;Qualunque altra richiesta verrà droppata dalle policy di zona.&#xA;Definizione policy con default target DROP.&#xA;firewall-cmd --permanent --new-policy=&#34;backend-to-pubblica&#34;&#xA;firewall-cmd --permanent --policy=&#34;backend-to-pubblica&#34; --add-ingress-zone=&#34;backend&#34;&#xA;firewall-cmd --permanent --policy=&#34;backend-to-pubblica&#34; --add-egress-zone=&#34;pubblica&#34;&#xA;firewall-cmd --permanent --policy=&#34;backend-to-pubblica&#34; --set-target=DROP&#xA;servizi&#xA;firewall-cmd --permanent --policy=&#34;backend-to-pubblica&#34; --add-service=&#34;web&#34;&#xA;firewall-cmd --permanent --policy=&#34;backend-to-pubblica&#34; --add-service=&#34;dns&#34;&#xA;masquerade&#xA;firewall-cmd --permanent --policy=&#34;backend-to-pubblica&#34; --add-masquerade&#xA;&#xA;#################################&#xA;guest-pubblica (wlan1 → wan0) &#xA;#################################&#xA;I client, nattati, hanno pieno accesso alla rete pubblica.&#xA;Qualunque richiesta verso altre reti, verrà droppata&#xA;dalle policy di zona.&#xA;Definizione policy con default target ACCEPT.&#xA;firewall-cmd --permanent --new-policy=&#34;guest-to-pubblica&#34;&#xA;firewall-cmd --permanent --policy=&#34;guest-to-pubblica&#34; --add-ingress-zone=&#34;guest&#34;&#xA;firewall-cmd --permanent --policy=&#34;guest-to-pubblica&#34; --add-egress-zone=&#34;pubblica&#34;&#xA;firewall-cmd --permanent --policy=&#34;guest-to-pubblica&#34; --set-target=ACCEPT&#xA;masquerade&#xA;firewall-cmd --permanent --policy=&#34;guest-to-pubblica&#34; --add-masquerade&#xA;5.4. Trappole nascoste&#xA;Può capitare che definizioni di zone poco accorte aprano le maglie della gabbia che noi vorremmo cucire attorno all&#39;esposizione dei servizi.&#xA;&#xA;Vediamo un po&#39; di scenari per analizzare le conseguenza delle scelte di design.&#xA;&#xA;Per semplicità esaminerò il caso di un singolo host (192.168.1.2) che ospita un servizio web e un servizio mysql che vogliamo confinare con firewalld nel seguente modo:&#xA;&#xA;Il servizio web deve essere raggiungibile solo da 192.168.1.3&#xA;Il servizio mysql deve essere raggiungibile solo da 192.168.1.4&#xA;&#xA;5.4.1. Caso 1. Restrizioni con solo \-\-add-source&#xA;firewall-cmd --permanent --new-zone=zone1&#xA;firewall-cmd --permanent --zone=zone1 --set-target=REJECT&#xA;firewall-cmd --permanent --zone=zone1 --add-source=192.168.1.3&#xA;firewall-cmd --permanent --zone=zone1 --add-service=http&#xA;firewall-cmd --permanent --zone=zone1 --add-service=https&#xA;&#xA;firewall-cmd --permanent --new-zone=zone2&#xA;firewall-cmd --permanent --zone=zone2 --set-target=REJECT&#xA;firewall-cmd --permanent --zone=zone2 --add-source=192.168.1.4&#xA;firewall-cmd --permanent --zone=zone2 --add-service=mysql&#xA;&#xA;firewall-cmd --set-default-zone=zone2&#xA;Questo tipo di configurazione è soggetto a quello che viene chiamato &#34;zone hijacking&#34; che permette a ip non autorizzati di accedere a risorse a cui non dovrebbero avere accesso situate nella zona di default o di fallback.&#xA;&#xA;Nel caso specifico, un ip come 192.168.1.10, o qualunque altro a cui le policy di routing consentano di bussare lecitamente all&#39;interfaccia, chiede di accedere a mysql, avrà il via libera vanificando tutte le nostre politiche di confinamento.&#xA;&#xA;Vediamo perché succede questo.&#xA;&#xA;192.168.1.10 bussa alla porta 3306&#xA;Step 1: Verifica sorgenti&#xA;&#x9;192.168.1.10 corrisponde a zone1 (192.168.1.3)? NO.&#xA;&#x9;192.168.1.10 corrisponde a zone2 (192.168.1.4)? NO.&#xA;Step 2: Verifica interfacce&#xA;&#x9;Non ci sono interfacce associate&#xA;Il pacchetto viene consegnato alla zona di fallback, zone2, per l&#39;elaboraziona finale,  richiede lecitamente l&#39;accesso a mysql che viene autorizzato →  ❌ ERRORE!&#xA;&#xA;5.4.2. Caso 2: Combinazione di \-\-add-source e \-\-add-interface&#xA;Quando l&#39;ingresso alla zona viene mediato da una combinazione sorgenti e interfacce, non c&#39;è il rischio di zone hijacking ma può essere ugualmente insidioso se non si capisce bene che fine facciano i pacchetti.&#xA;&#xA;In generale basta ricordarsi sempre che la presenza di sorgenti e interfacce ha l&#39;obiettivo opposto della restrizione perché va ad estendere l&#39;insieme degli aventi diritto al servizio.&#xA;&#xA;Facciamo sempre conto che 192.168.1.10 provi a bussare sulla 3306.&#xA;firewall-cmd --permanent --new-zone=zone1&#xA;firewall-cmd --permanent --zone=zone1 --set-target=REJECT&#xA;firewall-cmd --permanent --zone=zone1 --add-source=192.168.1.3&#xA;firewall-cmd --permanent --zone=zone1 --add-service=http&#xA;firewall-cmd --permanent --zone=zone1 --add-service=https&#xA;&#xA;firewall-cmd --permanent --new-zone=zone2&#xA;firewall-cmd --permanent --zone=zone2 --set-target=REJECT&#xA;firewall-cmd --permanent --zone=zone2 --add-source=192.168.1.4&#xA;firewall-cmd --permanent --zone=zone2 --add-interface=eth0&#xA;firewall-cmd --permanent --zone=zone2 --add-service=mysql&#xA;&#xA;firewall-cmd --set-default-zone=zone2&#xA;Anche facendo finta di non accorgersi che l&#39;add-source della zona2 sia ridondante avendo la disponibilità dell&#39;intera interfaccia che lo contiene, l&#39;accesso in questo caso sarà consentito proprio perchè nello step2 della valutazione, la presenza dell&#39;interfaccia fa ricadere il pacchetto nella zona 2 (accesso consentito) → ⚠️ ATTENZIONE!&#xA;&#xA;Se invece spostassi il binding dell&#39;interfaccia nella zona1,&#xA;firewall-cmd --permanent --new-zone=zone1&#xA;firewall-cmd --permanent --zone=zone1 --set-target=REJECT&#xA;firewall-cmd --permanent --zone=zone2 --add-interface=eth0&#xA;firewall-cmd --permanent --zone=zone1 --add-source=192.168.1.3&#xA;firewall-cmd --permanent --zone=zone1 --add-service=http&#xA;firewall-cmd --permanent --zone=zone1 --add-service=https&#xA;&#xA;firewall-cmd --permanent --new-zone=zone2&#xA;firewall-cmd --permanent --zone=zone2 --set-target=REJECT&#xA;firewall-cmd --permanent --zone=zone2 --add-source=192.168.1.4&#xA;firewall-cmd --permanent --zone=zone2 --add-service=mysql&#xA;&#xA;firewall-cmd --set-default-zone=zone2&#xA;il binding dell&#39;interfaccia fa ricadere la richiesta nella zona1 che rifiuta l&#39;accesso → ⚠️ ATTENZIONE!&#xA;5.4.3. Remediation per la &#34;zone hijacking&#34;&#xA;L&#39;utilizzo delle sole sorgenti per restringere l&#39;accesso non è sufficiente perché ip che transitano sull&#39;host e non appartengano a nessuna sorgente di zona, possono richiedere lecitamente i servizi appartenenti alla zona di fallback&#xA;&#xA;Ci sono un paio di modi per evitare questo tranello.&#xA;&#xA;Uno consiste nell&#39;usare le rich-rules come abbiamo fatto nella gestione delle zone di management e di backend del punto 5.2. Caso 2: Configurazione di un fw personale su un host con 3 interfacce. Accesso pieno alle sole interfacce e i sorgenti nelle rich-rules sono le white-list che consentono puntualmente chi può accedere a cosa.&#xA;&#xA;Un altro metodo consiste nell&#39;usare come zona di default, una zona senza alcun binding, con lo scopo di droppare tutto ciò che vi finisce dentro.&#xA;firewall-cmd --permanent --new-zone=default-drop&#xA;firewall-cmd --permanent --zone=default-drop --set-target=DROP&#xA;firewall-cmd --set-default-zone=default-drop&#xA;In questo modo la zona di default che riceverà il pacchetto sospeso non avrà alcun servizio associato a differenza di prima, ma dropperà tutto ciò che incontra.&#xA;6. Tips&#xA;6.1. Le azioni di firewall-cmd&#xA;Per districarsi rapidamente nella sintassi di firewall-cmd, mi viene comodo ricordare &#34;le azioni&#34; distintive principali in un&#39;ottica CRUD:&#xA;&#xA;--get / --info /  --list. recupera (legge) informazioni sulla configurazione&#xA;--new / --add, crea nuovi oggetti / elementi&#xA;--set, modifica gli elementi&#xA;--remove / --delete, rimuove gli elementi / oggetti&#xA;&#xA;E più precisamente:&#xA;&#xA;--get, restituisce un elenco di oggetti complessi a livello di sistema (ad es. icmptypes, servizi, zone o policy) o il valore di un suo campo ;&#xA;--set, imposta il valore di un campo;&#xA;--info, restituisce il recordset di un determinato oggetto complesso come un servizio, una policy, una zona, un ipset;&#xA;--list, come --info ma più articolato; &#xA;--new, crea nuovi oggetti complessi;&#xA;--add, aggiunge un elemento ad un oggetto complesso;&#xA;--remove, rimuove elementi da un oggetto complesso ad es. un servizio da una zona/policy, una entry da un servizio, una rule da una zona/policy ecc.&#xA;--delete, rimuove un oggetto complesso come una zona, una policy, un ipset, un servizio ecc.&#xA;&#xA;6.2. Comandi utili&#xA;Di seguito. un sottinsieme di comandi già visti, utili per catturare velocemente informazioni sulla configurazione del firewall.&#xA;&#xA;Elenco di tutti gli ipset:&#xA;firewall-cmd --permanent --get-ipsets&#xA;Elenco di tutti i tipi di ipset:&#xA;firewall-cmd --get-ipset-types&#xA;Elenco di tutti tipi di icmp:&#xA;firewall-cmd --get-icmptypes&#xA;Elenco di tutti i servizi:&#xA;firewall-cmd --get-services&#xA;Individuare la zona dall&#39;interfaccia:&#xA;firewall-cmd --permanent --get-zone-of-interface=&#34;nome interfaccia&#34;&#xA;Individuare la zona dal sorgente:&#xA;firewall-cmd --permanent --get-zone-of-source=ip | MAC | ipset:&#34;nomeipset&#34;&#xA;Zona di default:&#xA;firewall-cmd --get-default-zone&#xA;Zone attive:&#xA;firewall-cmd --get-active-zones&#xA;Elenco di tutte le zone/policies:&#xA;firewall-cmd --get-zones&#xA;firewall-cmd --get-policies&#xA;Dettaglio delle configurazione di tutte le zone/policy:&#xA;firewall-cmd --list-all-zone&#xA;firewall-cmd --list-all-policies&#xA;Dettaglio della configurazione di una zona/policy:&#xA;firewall-cmd --permanent --info-zone=&#34;nomezona&#34;&#xA;firewall-cmd --permanent --info-policy=&#34;nomepolicy&#34;&#xA;Elenco di tutti i servizi di una zona/policy:&#xA;firewall-cmd --zone=&#34;nomezona&#34; --list-services&#xA;firewall-cmd --policy=&#34;nomepolicy&#34; --list-services&#xA;Elenco di tutte le porte di una zona/policy:&#xA;firewall-cmd --permanent --zone=&#34;nomezona&#34; --list-ports&#xA;firewall-cmd --permanent --policy=&#34;nomepolicy&#34; --list-ports&#xA;Elenco di tutte le rich rules di una zona/policy:&#xA;firewall-cmd --permanent --zone=&#34;nomezona&#34; --list-rich-rules&#xA;firewall-cmd --permanent --policy=&#34;nomepolicy&#34; --list-rich-rules&#xA;Elenco di tutte le forward ports di una zona/policy:&#xA;firewall-cmd --permanent --zone=&#34;nomezona&#34; --list-forward-ports&#xA;firewall-cmd --permanent --policy=&#34;nomepolicy&#34; --list-forward-ports&#xA;Dettaglio della configurazione di un servizio:&#xA;firewall-cmd --permanent --info-service=&#34;nomeservizio&#34;&#xA;Elenco di tutte le porte di un servizio:&#xA;firewall-cmd --permanent --service=&#34;nomeservizio&#34; --get-ports&#xA;Dettaglio della configurazione di un ipset:&#xA;firewall-cmd --permanent --info-ipset=&#34;nomeipset&#34;&#xA;Elenco di tutte le entry di un ipset:&#xA;firewall-cmd --permanent --ipset=&#34;nomeipset&#34; --get-entries&#xA;6.3. Considerazioni di contorno&#xA;Concludendo, firewalld, in quanto frontend fedele di nftables, rappresenta il futuro del firewalling linux.&#xA;&#xA;Aspetti comuni:&#xA;&#xA;Configurare i servizi ove possibile è sempre da preferire rispetto a porte/protocolli sparati direttamente nella zona o nella policy.&#xA;Ricorrere alle rich-rules solo se si devono gestire flussi puntuali, altrimenti è sufficiente il bind dell&#39;interfaccia alla zona.&#xA;&#xA;Approccio conservativo:&#xA;Per configurazioni semplici, bastano zone e servizi.&#xA;&#xA;In presenza di più interfacce, obbligatorio anche il ricorso ai policy object, perché ci sarà da gestire di sicuro traffico interzona.&#xA;&#xA;Pro: curva d&#39;apprendimento morbida, ideale se la necessità è di essere operativi nel breve. Ideali per firewall personali e configurazioni semplici.&#xA;Contro: le configurazioni tendono ad irrigidirsi al crescere della complessità degli scenari e quindi a complicare le manutenzioni.&#xA;&#xA;Approccio spregiudicato:&#xA;Delegare alle zone solo il trust delle sorgenti e spostare la logica dei flussi interamente ai policy object.&#xA;&#xA;Pro: massima flessibilità, maggiore pulizia delle configurazioni. Ideale per scenari complessi.&#xA;Contro: curva d&#39;apprendimento più ripida, le configurazioni più semplici tendono ad apparire molto più verbose e di conseguenza meno chiare.&#xA;&#xA;#firewall #firewallcmd #firewalld #iptables #netfilter  #nftables #ufw]]&gt;</description>
      <content:encoded><![CDATA[<p><img src="https://pixelfed.uno/storage/m/_v2/489827599091373610/b5862bd14-4506fa/gBxZ8Bb3JsyX/aoPYucfwCvDfgYXOXGHOkG7aqrFBwjspQetNhz0S.jpg" alt="tux-firewalld"></p>

<hr>

<p><strong>N.B. Sono stato costretto a spezzare l&#39;articolo perché, quello originale di 8836 parole (per un totale di 76309 bytes effettivi), veniva troncato dopo il salvataggio a 7533 parole (65.356 bytes), cosa che mi fa sospettare che la grandezza del body non possa superare i 64k.</strong></p>

<hr>

<p>Nel capitolo precedente (<a href="/aytin/sveliamo-i-misteri-di-firewalld-parte-1-di-2/" rel="nofollow">Sveliamo i misteri di firewalld (Parte 1 di 2)</a>, abbiamo esaminato abbastanza nel dettaglio la cli di firewalld (<code>firewall-cmd</code>) con un focus particolare sul suo man, fatto molto bene.</p>

<p>Nel seguito ci concentreremo soprattutto su casi d&#39;uso per vedere firewalld in azione, analizzando alcuni possibili cortocircuiti logici e approfondendo  quanto già enunciato nei capitoli 1, 2, 4 della parte 1.
</p>
<ul><li><a href="#5-esempi" rel="nofollow">5. Esempi</a>
<ul><li><a href="#5-1-caso-1-host-con-una-sola-interfaccia" rel="nofollow">5.1. Caso 1: host con una sola interfaccia</a>
<ul><li><a href="#5-1-2-esposizione-di-servizi-custom-con-restrizioni" rel="nofollow">5.1.2. Esposizione di servizi custom con restrizioni</a></li>
<li><a href="#5-1-3-esposizione-con-port-forwarding-statico" rel="nofollow">5.1.3. Esposizione con port forwarding statico</a></li></ul></li>
<li><a href="#5-2-caso-2-configurazione-di-un-fw-personale-su-un-host-con-3-interfacce" rel="nofollow">5.2. Caso 2: Configurazione di un fw personale su un host con 3 interfacce</a></li>
<li><a href="#5-3-caso-3-router-firewall-gateway" rel="nofollow">5.3. Caso 3: Router Firewall-Gateway</a></li>
<li><a href="#5-4-trappole-nascoste" rel="nofollow">5.4. Trappole nascoste</a>
<ul><li><a href="#5-4-1-caso-1-restrizioni-con-solo-add-source" rel="nofollow">5.4.1. Caso 1. Restrizioni con solo --add-source</a></li>
<li><a href="#5-4-2-caso-2-combinazione-di-add-source-e-add-interface" rel="nofollow">5.4.2. Caso 2: Combinazione di --add-source e --add-interface</a></li>
<li><a href="#5-4-3-remediation-per-la-zone-hijacking" rel="nofollow">5.4.3. Remediation per la zone “hijacking”</a></li></ul></li></ul></li>
<li><a href="#6-tips" rel="nofollow">6. Tips</a>
<ul><li><a href="#6-1-le-azioni-di-firewall-cmd" rel="nofollow">6.1. Le azioni di firewall-cmd</a></li>
<li><a href="#6-2-comandi-utili" rel="nofollow">6.2. Comandi utili</a></li>
<li><a href="#6-3-considerazioni-di-contorno" rel="nofollow">6.3. Considerazioni di contorno</a></li></ul></li></ul>

<h2 id="5-esempi">5. Esempi</h2>

<p>Nel configurare firewalld, da utente, la difficoltà più grande per me consiste nel sapersi districare in mezzo alla ragnatela di zone, policy, servizi, nat, rich-rules ecc.</p>

<p>Come dicevo in precedenza per un firewall personale, bastano le zone con la dichiarazione dei servizi, così da filtrare il traffico in ingresso e finisce il gioco.</p>

<p>Quando invece lo scenario si complica, è necessario capire bene come funzioni il routing dei pacchetti fatto da firewalld e qual sia l&#39;ordine di valutazione che firewalld fa dei vari oggetti che poi si traduce nell&#39;accettazione o nel rifiuto del pacchetto.</p>

<p>Provo a tracciare una scaletta che però è frutto di esperienza nell&#39;uso, di sperimentazione  personale, nulla di ufficiale.</p>

<p><strong>Fase 1: Associazione alle Zone</strong>
firewalld per prima cosa deve capire quali siano le zone interessate controllando l&#39;ip sorgente del pacchetto.</p>
<ol><li>Se c&#39;è una sorgente associata esplicitamente ad una zona, il pacchetto viene assegnato a quella zona.</li>
<li>Se non c&#39;è alcuna sorgente, si controlla l&#39;interfaccia fisica da cui è entrato il pacchetto e si assegna alla zona che trusta quell&#39;interfaccia.</li>
<li>Se non c&#39;è nessuna zona associata all&#39;interfaccia, il pacchetto finisce alla zona impostata come default</li></ol>

<p><strong>Fase 2: Selezione del contesto (zone vs policy)</strong>
Una volta identificate la zona di ingresso (e l&#39;eventuale zona di uscita se il traffico è in transito/forwarding), firewalld decide quale “contenitore di regole” applicare:</p>
<ol><li>Le policy <strong>vengono valutate prima</strong> delle singole regole delle zone.
In base alle zone associate, firewalld verifica se esiste una Policy che le unisce e applica i filtri presenti nella policy</li>
<li>Se non ci sono policy object applicabili a quel flusso, il pacchetto viene processato direttamente all&#39;interno della singola zona identificata nella Fase 1. Questo vuol dire che se ci sono filtri nella zona e c&#39;è una policy del tipo zone-to-host, i filtri della policy vincono.</li></ol>

<p><strong>Fase 3: Valutazione delle regole interne (servizi, porte e NAT)</strong>
Ora che abbiamo il contesto, è importante capire in che ordine firewalld applica i filtri.</p>
<ol><li>come prima cosa si valutano le rich-rules con priorità negativa;</li>
<li>in seguito si prende in esame il <strong>dnat</strong> in modo che i filtri successivi lavorino sull&#39;indirizzo e sulla porta di destinazione corretti;</li>
<li>successivamente si valutano i servizi e le porte standard, quelli aggiunti con <code>--add-service</code> e <code>--add-port</code> per capirci</li>
<li>dopo i servizi, vengono valutate le rich-rule tradizionali, quelle con priorità 0</li>
<li>come ultimo passo, se c&#39;è, viene preso in carico il SNAT Masquerade</li></ol>

<p><strong>Fase 4: Il target di default</strong>
Se un pacchetto è arrivato fino a questo punto significa che non ha trovato nessuna regola esplicita (nessun servizio o porta lo ha accettato o rifiutato prima) e viene applicato il target della zona (DROP/REJECT/ACCEPT/default) o della policy (DROP/REJECT/ACCEPT/CONTINUE)</p>

<p>La fase 3 è quella critica, quella che emette il verdetto di accettazione o rifiuto. E qui bisogna fare attenzione.</p>

<p>Le azioni di manipolazione dei pacchetti come il NAT non corrispondono ad un verdetto, che avviene invece:</p>
<ol><li>nei servizi (<code>--add-service</code> o <code>--add-port</code>): accettazione (o rifiuto) implicita</li>
<li>nelle rich-rule se uno dei target viene esplicitato</li></ol>

<p>Quindi, ad es. se nella zona o nella policy, c&#39;è un add-service che accetta un determinato servizio e di seguito una rich rule che invece lo nega, add-service ha priorità e un pacchetto che richieda quel servizio verrebbe accettato e non scartato. Come pure, in una zona/policy default drop, se fosse presente un masquerade o un dnat senza alcuna accettazione esplicite, il pacchetto verrebbe rifiutato dalle politiche della zona/policy.</p>

<p>Alla luce di questa nuova consapevolezza, proverò a mostrare  come risolvere alcuni tipici casi d&#39;uso, partendo dalla configurazione di un semplice firewall personale che protegge l&#39;esposizione di servizi standard, per proseguire in maniera incrementale arricchendo di volta in volta la configurazione iniziale.</p>

<h3 id="5-1-caso-1-host-con-una-sola-interfaccia">5.1. Caso 1: host con una sola interfaccia</h3>

<p>È il caso classico di un personal firewall.</p>

<p>Nel primo blocco di esempi mostrerò anche le configurazioni di un approccio full-policy.</p>

<p>Non ci sono vantaggi evidenti perché si tratta di casi semplici però concentrare la logica nelle policy piuttosto che nelle zone permette per es. di bloccare tutto il traffico in una zona default drop semplicemente disabilitando la policy.</p>

<p>Oppure posso usare la stessa logica di filtraggio su altre zone senza doverle replicare ma solo aggiungendo egress-zone e ingress-zone opportue.</p>

<h4 id="5-1-1-esposizione-semplice">5.1.1. Esposizione semplice</h4>

<p>Ipotizziamo quindi di avere un host con una sola interfaccia e di voler configurare il firewall per filtrare i servizi ssh (22/tcp) e http(s) (80,443/tcp) che questo host espone su una lan.</p>

<p><strong>Versione zone-oriented:</strong></p>

<pre><code class="language-bash"># creazione zona, binding su eth0, policy di default DROP (l&#39;host non sarà nemmeno &#34;pingabile&#34;)
firewall-cmd --permanent --new-zone=server-lan
firewall-cmd --permanent --zone=&#34;server-lan&#34; --set-target=DROP
firewall-cmd --permanent --zone=&#34;server-lan&#34; --add-interface=eth0

# abilitazione servizi ssh, http(s)
firewall-cmd --permanent --zone=&#34;server-lan&#34; --add-service=ssh
firewall-cmd --permanent --zone=&#34;server-lan&#34; --add-service=http
firewall-cmd --permanent --zone=&#34;server-lan&#34; --add-service=https
</code></pre>

<p>Come si può vedere, la configurazione è pulita, lineare ed è veramente “parlante”.
Chiunque bussi all&#39;interfaccia eth0, accede ai servizi esposti dall&#39;host.</p>

<p><strong>Versione policy-oriented:</strong></p>

<pre><code class="language-bash"># creazione zona, binding su eth0, policy di default DROP (l&#39;host non sarà nemmeno &#34;pingabile&#34;)
firewall-cmd --permanent --new-zone=&#34;server-lan&#34;
firewall-cmd --permanent --zone=&#34;server-lan&#34; --set-target=DROP
firewall-cmd --permanent --zone=&#34;server-lan&#34; --add-interface=eth0

# creazione policy
firewall-cmd --permanent --new-policy=&#34;lan-to-host&#34;
firewall-cmd --permanent --policy=&#34;lan-to-host&#34; --add-ingress-zone=&#34;server-lan&#34;
firewall-cmd --permanent --policy=&#34;lan-to-host&#34; --add-egress-zone=HOST
firewall-cmd --permanent --policy=&#34;lan-to-host&#34; --set-target=REJECT

# binding dei servizi ssh, http(s)
firewall-cmd --permanent --policy=lan-to-host --add-service=ssh
firewall-cmd --permanent --policy=lan-to-host --add-service=http
firewall-cmd --permanent --policy=lan-to-host --add-service=https
</code></pre>

<p>Non cambia quasi nulla se non il fatto che il filtering ora avviene attraverso la policy mentre la zona contiene solo il trust delle sorgenti.</p>

<h4 id="5-1-2-esposizione-di-servizi-custom-con-restrizioni">5.1.2. Esposizione di servizi custom con restrizioni</h4>

<p>L&#39;host stavolta esporrà i servizi su porte custom con questi vincoli:</p>
<ul><li>chiunque bussi a eth0 avrà accesso web</li>
<li>mentre ssh sarà ristretto al solo ip 192.168.10.21</li></ul>

<p><strong>Versione zone-oriented:</strong></p>

<pre><code class="language-bash"># creazione zona, binding su eth0, policy di default DROP (l&#39;host non sarà nemmeno &#34;pingabile&#34;)
firewall-cmd --permanent --new-zone=server-lan
firewall-cmd --permanent --zone=&#34;server-lan&#34; --set-target=DROP
firewall-cmd --permanent --zone=&#34;server-lan&#34; --add-interface=eth0

# creazione servizio &#34;web_custom&#34;
firewall-cmd --permanent --new-service=&#34;web_custom&#34;
firewall-cmd --permanent --service=&#34;web_custom&#34; --set-description=&#34;My HTTP(S) service&#34;
firewall-cmd --permanent --service=&#34;web_custom&#34; --add-port=8080/tcp --add-port=8443/tcp

# creazione servizio &#34;ssh_custom&#34;
firewall-cmd --permanent --new-service=&#34;ssh_custom&#34;
firewall-cmd --permanent --service=&#34;ssh_custom&#34; --set-description=&#34;My SSH service&#34;
firewall-cmd --permanent --service=&#34;ssh_custom&#34; --add-port=2222/tcp

# chiunque bussi a eth0 sulle porte 8080 e 8443, verrà accettato 
firewall-cmd --permanent --zone=&#34;server-lan&#34; --add-service=web_custom

# ssh_custom invece è ristretto con una rich-rule al solo ip 192.168.10.21
firewall-cmd --permanent --zone=&#34;server-lan&#34; --add-rich-rule=&#39;rule family=&#34;ipv4&#34; source address=&#34;192.168.10.21&#34; service name=&#34;ssh_custom&#34; accept&#39;
</code></pre>

<p><strong>Versione policy-oriented:</strong></p>

<pre><code class="language-bash"># creazione zona, binding su eth0, policy di default DROP (l&#39;host non sarà nemmeno &#34;pingabile&#34;)
firewall-cmd --permanent --new-zone=&#34;server-lan&#34;
firewall-cmd --permanent --zone=&#34;server-lan&#34; --set-target=DROP
firewall-cmd --permanent --zone=&#34;server-lan&#34; --add-interface=eth0

# creazione servizio &#34;web_custom&#34;
firewall-cmd --permanent --new-service=&#34;web_custom&#34;
firewall-cmd --permanent --service=&#34;web_custom&#34; --set-description=&#34;My HTTP(S) service&#34;
firewall-cmd --permanent --service=&#34;web_custom&#34; --add-port=8080/tcp --add-port=8443/tcp

# creazione servizio &#34;ssh_custom&#34;
firewall-cmd --permanent --new-service=&#34;ssh_custom&#34;
firewall-cmd --permanent --service=&#34;ssh_custom&#34; --set-description=&#34;My SSH service&#34;
firewall-cmd --permanent --service=&#34;ssh_custom&#34; --add-port=2222/tcp

# creazione policy
firewall-cmd --permanent --new-policy=&#34;lan-to-host&#34;
firewall-cmd --permanent --policy=&#34;lan-to-host&#34; --add-ingress-zone=&#34;server-lan&#34;
firewall-cmd --permanent --policy=&#34;lan-to-host&#34; --add-egress-zone=HOST
firewall-cmd --permanent --policy=&#34;lan-to-host&#34; --set-target=REJECT

# binding web_custom su tutta eth0
firewall-cmd --permanent --policy=&#34;lan-to-host&#34; --add-service=web_custom

# ssh_custom invece è ristretto con una rich-rule al solo ip 192.168.10.21
firewall-cmd --permanent --policy=&#34;lan-to-host&#34; --add-rich-rule=&#39;rule family=&#34;ipv4&#34; source address=&#34;192.168.10.21&#34; service name=&#34;ssh_custom&#34; accept&#39;
</code></pre>

<h4 id="5-1-3-esposizione-con-port-forwarding-statico">5.1.3. Esposizione con port forwarding statico</h4>

<p>Facciamo il caso che i servizi ssh e web siano in ascolto sull&#39;interfaccia di loopback.
Vogliamo comunque esporli attraverso un port redirect facendo in modo che:</p>
<ul><li><code>HOST:22   → localhost:2222</code></li>
<li><code>HOST:8080 → localhost:8080</code></li>
<li><code>HOST:8443 → localhost:8443</code></li></ul>

<p>In più vogliamo restringere l&#39;accesso ssh a 3 soli ip: 192.168.10.20, 192.168.10.21, 192.168.10.22 e vogliamo bloccare tutto il traffico ICMP ad eccezione di <code>echo-request</code>.</p>

<p><strong>Versione zone-oriented:</strong></p>

<pre><code class="language-bash"># creazione zona, binding su eth0, policy di default DROP
firewall-cmd --permanent --new-zone=&#34;server-lan&#34;
firewall-cmd --permanent --zone=&#34;server-lan&#34; --set-target=DROP
firewall-cmd --permanent --zone=&#34;server-lan&#34; --add-interface=eth0

# icmp solo request
firewall-cmd --permanent --zone=&#34;server-lan&#34; --add-icmp-block-inversion
firewall-cmd --permanent --zone=&#34;server-lan&#34; --add-icmp-block=echo-request

# ipset per ssh
firewall-cmd --permanent --new-ipset=&#34;ssh-allowed&#34; --type=hash:ip
firewall-cmd --permanent --ipset=&#34;ssh-allowed&#34; --add-entry=&#34;192.168.10.20&#34; 
firewall-cmd --permanent --ipset=&#34;ssh-allowed&#34; --add-entry=&#34;192.168.10.21&#34; 
firewall-cmd --permanent --ipset=&#34;ssh-allowed&#34; --add-entry=&#34;192.168.10.22&#34;

# Esposizione dei servizi
firewall-cmd --permanent --zone=&#34;server-lan&#34; --add-service=&#34;http&#34;
firewall-cmd --permanent --zone=&#34;server-lan&#34; --add-service=&#34;https&#34;
firewall-cmd --permanent --zone=&#34;server-lan&#34; --add-service=&#34;ssh&#34;

# Per il local forward è necessario abilitare il routing verso loopback
sysctl -w net.ipv4.conf.eth0.route_localnet=1

# local forward 80 → 8080, 443 → 8443
firewall-cmd --permanent --zone=&#34;server-lan&#34; --add-forward-port=port=80:proto=tcp:to-port=8080:to-addr=127.0.0.1
firewall-cmd --permanent --zone=&#34;server-lan&#34; --add-forward-port=port=443:proto=tcp:to-port=8443:to-addr=127.0.0.1

# rich-rule per l&#39;accesso filtrato ssh con local forward 22 → 2222
firewall-cmd --permanent --zone=&#34;server-lan&#34; --add-rich-rule=&#39;rule family=&#34;ipv4&#34; source ipset=&#34;ssh-allowed&#34; forward-port port=&#34;22&#34; protocol=&#34;tcp&#34; to-port=&#34;2222&#34; to-addr=&#34;127.0.0.1&#34;&#39;
</code></pre>

<p>Anche qui la configurazione rimane molto pulita e lineare.</p>

<p>Versione <strong>policy-oriented:</strong></p>

<pre><code class="language-bash"># creazione zona, binding su eth0, policy di default DROP
firewall-cmd --permanent --new-zone=&#34;server-lan&#34;
firewall-cmd --permanent --zone=&#34;server-lan&#34; --set-target=DROP
firewall-cmd --permanent --zone=&#34;server-lan&#34; --add-interface=eth0

# icmp solo request
firewall-cmd --permanent --zone=&#34;server-lan&#34; --add-icmp-block-inversion
firewall-cmd --permanent --zone=&#34;server-lan&#34; --add-icmp-block=echo-request

# ipset per ssh
firewall-cmd --permanent --new-ipset=&#34;ssh-allowed&#34; --type=hash:ip
firewall-cmd --permanent --ipset=&#34;ssh-allowed&#34; --add-entry=&#34;192.168.10.20&#34;
firewall-cmd --permanent --ipset=&#34;ssh-allowed&#34; --add-entry=&#34;192.168.10.21&#34;
firewall-cmd --permanent --ipset=&#34;ssh-allowed&#34; --add-entry=&#34;192.168.10.22&#34;

firewall-cmd --permanent --new-policy=&#34;lan-to-host&#34;
firewall-cmd --permanent --policy=&#34;lan-to-host&#34; --add-ingress-zone=&#34;server-lan&#34;
firewall-cmd --permanent --policy=&#34;lan-to-host&#34; --add-egress-zone=HOST
firewall-cmd --permanent --policy=&#34;lan-to-host&#34; --set-target=REJECTED

# Esposizione dei servizi
firewall-cmd --permanent --policy=&#34;lan-to-host&#34; --add-service=&#34;http&#34;
firewall-cmd --permanent --policy=&#34;lan-to-host&#34; --add-service=&#34;https&#34;
firewall-cmd --permanent --policy=&#34;lan-to-host&#34; --add-service=&#34;ssh&#34;

# Per il local forward è necessario abilitare il routing verso loopback
sysctl -w net.ipv4.conf.eth0.route_localnet=1

# local forward 80 → 8080, 443 → 8443
firewall-cmd --permanent --policy=&#34;lan-to-host&#34; --add-forward-port=port=80:proto=tcp:to-port=8080:to-addr=127.0.0.1
firewall-cmd --permanent--policy=&#34;lan-to-host&#34; --add-forward-port=port=443:proto=tcp:to-port=8443:to-addr=127.0.0.1

# rich-rule per l&#39;accesso filtrato ssh con local forward 22 → 2222
firewall-cmd --permanent --policy=&#34;lan-to-host&#34; --add-rich-rule=&#39;rule family=&#34;ipv4&#34; source ipset=&#34;ssh-allowed&#34; forward-port port=&#34;22&#34; protocol=&#34;tcp&#34; to-port=&#34;2222&#34; to-addr=&#34;127.0.0.1&#34;&#39;
</code></pre>

<p><strong>N.B.</strong> In realtà, casi di questo genere che non rientrano nella casistica più ampia del routing e del dnat che giustificherebbero l&#39;uso di regole firewall, si risolverebbero più elegantemente con un reverse proxy (posto che i servizi siano reverse-proxabili), agire quindi a livello applicativo (L7) invece che a livello di indirizzamento e trasporto (L3 e L4 rispettivamente.)</p>

<p>Infine, ciliegina sulla torta, vogliamo che sia filtrato anche il traffico in uscita consentendo solo il traffico web  per gli aggiornamenti di sistema (80,443/tcp) e quello dns (53/udp)</p>

<p>Sarà necessario un policy object per il flusso in uscita, sia nella versione <strong>zone-oriented</strong> che in quella <strong>policy-oriented</strong></p>

<pre><code class="language-bash"># creazione policy object, default policy REJECT
firewall-cmd --permanent --new-policy=host-to-any
firewall-cmd --permanent --policy=host-to-any --set-target=REJECT

# definizione della direzione del traffico: HOST → dmz (eth0)
firewall-cmd --permanent --policy=&#34;host-to-any&#34; --add-ingress-zone=HOST
firewall-cmd --permanent --policy=&#34;host-to-any&#34; --add-egress-zone=myZone

# traffico consentito: http(s), dns
firewall-cmd --permanent --policy=&#34;host-to-any&#34; --add-service=http
firewall-cmd --permanent --policy=&#34;host-to-any&#34; --add-service=https
firewall-cmd --permanent --policy=&#34;host-to-any&#34; --add-service=dns
</code></pre>

<p>Per la configurazione di un firewall personale, esempi di questo tipo coprono il 95% dei casi ordinari, anche senza considerare il filtro del traffico in uscita.</p>

<h3 id="5-2-caso-2-configurazione-di-un-fw-personale-su-un-host-con-3-interfacce">5.2. Caso 2: Configurazione di un fw personale su un host con 3 interfacce</h3>

<p>Proviamo a immaginare uno scenario leggermente più complesso, un host con 3 interfacce per segregare la rete in 3 flussi: management, ingresso, uscita.</p>
<ul><li>un&#39;interfaccia per la rete di management (<strong>eth0</strong>: 192.168.0.0/24)</li>
<li>un&#39;interfaccia per il traffico in ingresso, la rete per il provisioning o per i servizi che l&#39;host espone (<strong>eth1</strong>: 192.168.1.0/24)</li>
<li>un&#39;interfaccia per il data networking, la rete server-to server (<strong>eth2</strong>: 192.168.2.0/24)</li></ul>

<p>L&#39;host espone un servizio web, fa delle richieste ad un server mysql nel backend e consente di essere contattato via ssh per il management.
Dall&#39;interfaccia di backend invece l&#39;host non può essere contattato.</p>

<p>Le policy invece riguarderanno la gestione del traffico in ingresso, dalle rispettive interfacce solo per ssh e web, e del traffico in uscita solo verso il backend mysql.</p>

<pre><code class="language-bash"># ip che possono accedere al management dell&#39;host
firewall-cmd --permanent --new-ipset=&#34;ssh_allowed&#34; --type=&#34;hash:net&#34;
firewall-cmd --permanent --ipset=&#34;ssh_allowed&#34; --add-entry=&#34;192.168.5.32/27&#34; --add-entry=&#34;192.168.6.32/27&#34;

# per aggregare http/https in un unico servizio
firewall-cmd --permanent --new-service=&#34;web&#34;
firewall-cmd --permanent --service=&#34;web&#34; --add-include=&#34;http&#34; --add-include=&#34;https&#34;

# zona di management
firewall-cmd --permanent --new-zone=&#34;mgmt&#34;
firewall-cmd --permanent --zone=&#34;mgmt&#34; --add-interface=eth0
firewall-cmd --permanent --zone=&#34;mgmt&#34; --set-target=DROP

# zona del servizio web
firewall-cmd --permanent --new-zone=&#34;webserver&#34;
firewall-cmd --permanent --zone=&#34;webserver&#34; --add-interface=eth1
firewall-cmd --permanent --zone=&#34;webserver&#34; --set-target=DROP

# zona del backend
firewall-cmd --permanent --new-zone=&#34;backend&#34;
firewall-cmd --permanent --zone=&#34;backend&#34; --add-interface=eth2
firewall-cmd --permanent --zone=&#34;backend&#34; --set-target=DROP

# policy per il traffico WEBSERVER → HOST (traffico IN ↑)
firewall-cmd --permanent --new-policy=&#34;any-to-webserver&#34;
firewall-cmd --permanent --policy=&#34;any-to-webserver&#34; --add-ingress-zone=webserver
firewall-cmd --permanent --policy=&#34;any-to-webserver&#34; --add-egress-zone=HOST
firewall-cmd --permanent --policy=&#34;any-to-webserver&#34; --set-target=DROP
firewall-cmd --permanent --policy=&#34;any-to-webserver&#34; --add-service=&#34;web&#34;

# policy per il traffico MGMT → HOST (traffico IN ↑)
firewall-cmd --permanent --new-policy=&#34;mgmt-host&#34;
firewall-cmd --permanent --policy=&#34;mgmt-host&#34; --add-ingress-zone=mgmt
firewall-cmd --permanent --policy=&#34;mgmt-host&#34; --add-egress-zone=HOST
firewall-cmd --permanent --policy=&#34;mgmt-host&#34; --set-target=DROP
firewall-cmd --permanent --policy=&#34;mgmt-host&#34; --add-rich-rule=&#39;rule family=&#34;ipv4&#34; source ipset=&#34;ssh_allowed&#34; service name=&#34;ssh&#34; accept&#39;

# policy per il traffico HOST → backend (traffico OUT ↓)
firewall-cmd --permanent --new-policy=&#34;webserver-to-backend&#34;
firewall-cmd --permanent --policy=&#34;webserver-to-backend&#34; --add-ingress-zone=HOST
firewall-cmd --permanent --policy=&#34;webserver-to-backend&#34; --add-egress-zone=backend
firewall-cmd --permanent --policy=&#34;webserver-to-backend&#34; --set-target=DROP
firewall-cmd --permanent --policy=&#34;webserver-to-backend&#34; --add-rich-rule=&#39;rule family=&#34;ipv4&#34; service name=&#34;mysql&#34; accept&#39;
</code></pre>

<p>Il fatto che ci siano servizi con restrizioni sul sorgente, mi permetterà di porre l&#39;attenzione su una particolarità di firewalld poco evidente ma responsabile di errori talmente gravi da invalidare le nostre policy di sicurezza.</p>

<p>In generale, i servizi con restrizioni si gestiscono <strong>SEMPRE</strong> con rich-rule per evitare spiacevoli effetti laterali.</p>

<p>Le rich-rules danno la granularità necessaria in questi casi accettando solo il traffico indicato in zone default drop.</p>

<p>Come negli esempi precedenti, alle definizioni di zona posso sostituire quelle di policy se voglio un approccio policy-oriented.</p>

<h3 id="5-3-caso-3-router-firewall-gateway">5.3. Caso 3: Router Firewall-Gateway</h3>

<p>Ora facciamo l&#39;esempio del classico router-firewall domestico.</p>

<p>L&#39;host avrà quattro interfacce per altrettante reti. Una wan, una rete guest, una dmz e un backend che ospita servizi.</p>

<p><strong>Condizioni</strong></p>
<ul><li>In DMZ c&#39;è un reverse proxy, un server web e un client di file sharing (p2p).</li>
<li>Il Backend ospita un server mysql ad uso del server web, un servizio di file sharing solo per la rete di Backend (nfs).</li>
<li>La rete pubblica non accetta connessioni in ingresso, salvo che quelle destinate al reverse proxy e al client di file sharing via port forwarding.</li>
<li>Il reverseproxy media il contatto col server web che gira in localhost.</li>
<li>Il Backend è inaccessibile da qualunque rete. La DMZ può contattare il Backend esclusivamente per i transiti:
<ul><li>server web → server mysql</li>
<li>client p2p → server nfs</li></ul></li>
<li>La rete guest ha accesso pieno a internet ma deve essere isolata sia da DMZ che da Backend. Anche i servizi esposti in DMZ possono essere contattati solo da rete pubblica.</li></ul>

<p><strong>Piano di indirizzamento</strong></p>
<ul><li>wan0: 151.22.44.88, è l&#39;indirizzo ip della zona pubblica</li>
<li>eth0: 192.168.1.1 (192.168.1.0/24), gateway per la DMZ</li>
<li>wlan0: 192.168.2.1 (192.168.2.0/24), gateway per il Backend</li>
<li>wlan1: 192.168.3.1 (192.168.3.0/24), gateway per il guest.</li></ul>

<p><strong>Host in DMZ</strong></p>
<ul><li>192.168.1.2: server reverse-proxy (port 8080,8443)  / web (localhost)</li>
<li>192.168.1.3:  client p2p (port 36119)</li></ul>

<p><strong>Host in Backend</strong></p>
<ul><li>192.168.2.2: server mysql (port 3306)</li>
<li>192.168.2.3: server nfs (port 2049)</li></ul>

<pre><code class="language-bash">###########
# Servizi #
###########
firewall-cmd --permanent --new-service=&#34;web&#34;
firewall-cmd --permanent --service=&#34;web&#34; --add-include=&#34;http&#34; --add-include=&#34;https&#34;

firewall-cmd --permanent --new-service=&#34;p2p&#34;
firewall-cmd --permanent --service=&#34;p2p&#34; --add-port=&#34;36119/tcp&#34; --add-port=&#34;36119/udp&#34;

########
# Zone #
########
firewall-cmd --permanent --new-zone=&#34;pubblica&#34;
firewall-cmd --permanent --zone=&#34;pubblica&#34; --add-interface=&#34;wan0&#34;
firewall-cmd --permanent --zone=&#34;pubblica&#34; --set-target=DROP

firewall-cmd --permanent --new-zone=&#34;dmz&#34;
firewall-cmd --permanent --zone=&#34;dmz&#34; --add-interface=&#34;eth0&#34;
firewall-cmd --permanent --zone=&#34;dmz&#34; --set-target=DROP

firewall-cmd --permanent --new-zone=&#34;p2p&#34;
firewall-cmd --permanent --zone=&#34;p2p&#34; --add-interface=&#34;eth1&#34;
firewall-cmd --permanent --zone=&#34;p2p&#34; --set-target=DROP

firewall-cmd --permanent --new-zone=&#34;backend&#34;
firewall-cmd --permanent --zone=&#34;backend&#34; --add-interface=&#34;wlan0&#34;
firewall-cmd --permanent --zone=&#34;backend&#34; --set-target=DROP

firewall-cmd --permanent --new-zone=&#34;guest&#34;
firewall-cmd --permanent --zone=&#34;guest&#34; --add-interface=&#34;wlan1&#34;
firewall-cmd --permanent --zone=&#34;guest&#34; --set-target=DROP


##########
# Policy #
##########
##############################
# pubblica-dmz (wan0 → eth0) #
##############################
# Dalla rete pubblica arrivano le richieste da inoltrare sui
# server interni (DMZ).
# Definizione policy con default target DROP.
firewall-cmd --permanent --new-policy=&#34;pubblica-to-dmz&#34;
firewall-cmd --permanent --policy=&#34;pubblica-to-dmz&#34; --add-ingress-zone=&#34;pubblica&#34;
firewall-cmd --permanent --policy=&#34;pubblica-to-dmz&#34; --add-egress-zone=&#34;dmz&#34;
firewall-cmd --permanent --policy=&#34;pubblica-to-dmz&#34; --set-target=DROP
# Inoltri consentiti verso il reverse proxy.
firewall-cmd --permanent --policy=&#34;pubblica-to-dmz&#34; --add-rich-rule=&#39;rule family=&#34;ipv4&#34; forward-port port=&#34;80&#34; protocol=&#34;tcp&#34; to-port=&#34;8080&#34; to-addr=&#34;192.168.1.2&#34; accept&#39;
firewall-cmd --permanent --policy=&#34;pubblica-to-dmz&#34; --add-rich-rule=&#39;rule family=&#34;ipv4&#34; forward-port port=&#34;443&#34; protocol=&#34;tcp&#34; to-port=&#34;8443&#34; to-addr=&#34;192.168.1.2&#34; accept&#39;
firewall-cmd --permanent --policy=&#34;pubblica-to-dmz&#34; --add-rich-rule=&#39;rule family=&#34;ipv4&#34; forward-port port=&#34;36119&#34; protocol=&#34;tcp&#34; to-port=&#34;36119&#34; to-addr=&#34;192.168.1.3&#34; accept&#39;
firewall-cmd --permanent --policy=&#34;pubblica-to-dmz&#34; --add-rich-rule=&#39;rule family=&#34;ipv4&#34; forward-port port=&#34;36119&#34; protocol=&#34;udp&#34; to-port=&#34;36119&#34; to-addr=&#34;192.168.1.3&#34; accept&#39;

##############################
# dmz-backend (eth0 → wlan0) #
##############################
# Solo il reverse proxy (DMZ) può contattare mysql e nfs (Backend).
# Definizione policy con default target DROP.
firewall-cmd --permanent --new-policy=&#34;dmz-to-backend&#34;
firewall-cmd --permanent --policy=&#34;dmz-to-backend&#34; --add-ingress-zone=&#34;dmz&#34;
firewall-cmd --permanent --policy=&#34;dmz-to-backend&#34; --add-egress-zone=&#34;backend&#34;
firewall-cmd --permanent --policy=&#34;dmz-to-backend&#34; --set-target=DROP
# Transito consentito solo per rp verso mysql e per p2p verso nfs.
firewall-cmd --permanent --policy=&#34;dmz-to-backend&#34; --add-rich-rule=&#39;rule family=&#34;ipv4&#34; source address=&#34;192.168.1.2&#34; destination address=&#34;192.168.2.2&#34; service name=&#34;mysql&#34; accept&#39;
firewall-cmd --permanent --policy=&#34;dmz-to-backend&#34; --add-rich-rule=&#39;rule family=&#34;ipv4&#34; source address=&#34;192.168.1.3&#34; destination address=&#34;192.168.2.3&#34; service name=&#34;p2p&#34; accept&#39;

##############################
# dmz-pubblica (eth0 → wan0) #
##############################
# Abilitazione del solo browsing agli host (nattati) in DMZ.
# Abilitazione full all&#39;host p2p (nattato) in DMZ.
# Definizione policy con default target DROP.
firewall-cmd --permanent --new-policy=&#34;dmz-to-pubblica&#34;
firewall-cmd --permanent --policy=&#34;dmz-to-pubblica&#34; --add-ingress-zone=&#34;dmz&#34;
firewall-cmd --permanent --policy=&#34;dmz-to-pubblica&#34; --add-egress-zone=&#34;pubblica&#34;
firewall-cmd --permanent --policy=&#34;dmz-to-pubblica&#34; --set-target=DROP
# Servizi
firewall-cmd --permanent --policy=&#34;dmz-to-pubblica&#34; --add-rich-rule=&#39;rule family=&#34;ipv4&#34; source address=&#34;192.168.1.2 service=&#34;web&#34; masquerade accept&#39;
firewall-cmd --permanent --policy=&#34;dmz-to-pubblica&#34; --add-rich-rule=&#39;rule family=&#34;ipv4&#34; source address=&#34;192.168.1.3 masquerade accept&#39;

##################################
# backend-pubblica (eth0 → wan0) #
##################################
# Abilitazione del solo browsing degli host (nattati) in Backend.
# Qualunque altra richiesta verrà droppata dalle policy di zona.
# Definizione policy con default target DROP.
firewall-cmd --permanent --new-policy=&#34;backend-to-pubblica&#34;
firewall-cmd --permanent --policy=&#34;backend-to-pubblica&#34; --add-ingress-zone=&#34;backend&#34;
firewall-cmd --permanent --policy=&#34;backend-to-pubblica&#34; --add-egress-zone=&#34;pubblica&#34;
firewall-cmd --permanent --policy=&#34;backend-to-pubblica&#34; --set-target=DROP
# servizi
firewall-cmd --permanent --policy=&#34;backend-to-pubblica&#34; --add-service=&#34;web&#34;
firewall-cmd --permanent --policy=&#34;backend-to-pubblica&#34; --add-service=&#34;dns&#34;
# masquerade
firewall-cmd --permanent --policy=&#34;backend-to-pubblica&#34; --add-masquerade

#################################
# guest-pubblica (wlan1 → wan0) #
#################################
# I client, nattati, hanno pieno accesso alla rete pubblica.
# Qualunque richiesta verso altre reti, verrà droppata
# dalle policy di zona.
# Definizione policy con default target ACCEPT.
firewall-cmd --permanent --new-policy=&#34;guest-to-pubblica&#34;
firewall-cmd --permanent --policy=&#34;guest-to-pubblica&#34; --add-ingress-zone=&#34;guest&#34;
firewall-cmd --permanent --policy=&#34;guest-to-pubblica&#34; --add-egress-zone=&#34;pubblica&#34;
firewall-cmd --permanent --policy=&#34;guest-to-pubblica&#34; --set-target=ACCEPT
# masquerade
firewall-cmd --permanent --policy=&#34;guest-to-pubblica&#34; --add-masquerade
</code></pre>

<h3 id="5-4-trappole-nascoste">5.4. Trappole nascoste</h3>

<p>Può capitare che definizioni di zone poco accorte aprano le maglie della gabbia che noi vorremmo cucire attorno all&#39;esposizione dei servizi.</p>

<p>Vediamo un po&#39; di scenari per analizzare le conseguenza delle scelte di design.</p>

<p>Per semplicità esaminerò il caso di un singolo host (192.168.1.2) che ospita un servizio web e un servizio mysql che vogliamo confinare con firewalld nel seguente modo:</p>
<ul><li>Il servizio web deve essere raggiungibile solo da 192.168.1.3</li>
<li>Il servizio mysql deve essere raggiungibile solo da 192.168.1.4</li></ul>

<h4 id="5-4-1-caso-1-restrizioni-con-solo-add-source">5.4.1. Caso 1. Restrizioni con solo --add-source</h4>

<pre><code class="language-bash">firewall-cmd --permanent --new-zone=zone1
firewall-cmd --permanent --zone=zone1 --set-target=REJECT
firewall-cmd --permanent --zone=zone1 --add-source=192.168.1.3
firewall-cmd --permanent --zone=zone1 --add-service=http
firewall-cmd --permanent --zone=zone1 --add-service=https

firewall-cmd --permanent --new-zone=zone2
firewall-cmd --permanent --zone=zone2 --set-target=REJECT
firewall-cmd --permanent --zone=zone2 --add-source=192.168.1.4
firewall-cmd --permanent --zone=zone2 --add-service=mysql

firewall-cmd --set-default-zone=zone2
</code></pre>

<p>Questo tipo di configurazione è soggetto a quello che viene chiamato “<strong>zone hijacking</strong>” che permette a ip non autorizzati di accedere a risorse a cui non dovrebbero avere accesso situate nella <strong>zona di default o di fallback</strong>.</p>

<p>Nel caso specifico, un ip come 192.168.1.10, o qualunque altro a cui le policy di routing consentano di bussare lecitamente all&#39;interfaccia, chiede di accedere a mysql, avrà il via libera vanificando tutte le nostre politiche di confinamento.</p>

<p>Vediamo perché succede questo.</p>
<ol><li>192.168.1.10 bussa alla porta 3306</li>
<li>Step 1: Verifica sorgenti
<ol><li>192.168.1.10 corrisponde a zone1 (192.168.1.3)? NO.</li>
<li>192.168.1.10 corrisponde a zone2 (192.168.1.4)? NO.</li></ol></li>
<li>Step 2: Verifica interfacce
<ol><li>Non ci sono interfacce associate</li></ol></li>
<li>Il pacchetto viene consegnato alla zona di fallback, zone2, per l&#39;elaboraziona finale,  richiede lecitamente l&#39;accesso a mysql che viene autorizzato →  ❌ <strong>ERRORE!</strong></li></ol>

<h4 id="5-4-2-caso-2-combinazione-di-add-source-e-add-interface">5.4.2. Caso 2: Combinazione di --add-source e --add-interface</h4>

<p>Quando l&#39;ingresso alla zona viene mediato da una combinazione sorgenti e interfacce, non c&#39;è il rischio di zone hijacking ma può essere ugualmente insidioso se non si capisce bene che fine facciano i pacchetti.</p>

<p>In generale basta <strong>ricordarsi sempre</strong> che la presenza di sorgenti e interfacce ha l&#39;obiettivo opposto della restrizione perché va ad <strong>estendere l&#39;insieme degli aventi diritto al servizio</strong>.</p>

<p>Facciamo sempre conto che 192.168.1.10 provi a bussare sulla 3306.</p>

<pre><code class="language-bash">firewall-cmd --permanent --new-zone=zone1
firewall-cmd --permanent --zone=zone1 --set-target=REJECT
firewall-cmd --permanent --zone=zone1 --add-source=192.168.1.3
firewall-cmd --permanent --zone=zone1 --add-service=http
firewall-cmd --permanent --zone=zone1 --add-service=https

firewall-cmd --permanent --new-zone=zone2
firewall-cmd --permanent --zone=zone2 --set-target=REJECT
firewall-cmd --permanent --zone=zone2 --add-source=192.168.1.4
firewall-cmd --permanent --zone=zone2 --add-interface=eth0
firewall-cmd --permanent --zone=zone2 --add-service=mysql

firewall-cmd --set-default-zone=zone2
</code></pre>

<p>Anche facendo finta di non accorgersi che l&#39;add-source della zona2 sia ridondante avendo la disponibilità dell&#39;intera interfaccia che lo contiene, l&#39;accesso in questo caso sarà consentito proprio perchè nello step2 della valutazione, la presenza dell&#39;interfaccia fa ricadere il pacchetto nella zona 2 (accesso consentito) → ⚠️ <strong>ATTENZIONE!</strong></p>

<p>Se invece spostassi il binding dell&#39;interfaccia nella zona1,</p>

<pre><code class="language-bash">firewall-cmd --permanent --new-zone=zone1
firewall-cmd --permanent --zone=zone1 --set-target=REJECT
firewall-cmd --permanent --zone=zone2 --add-interface=eth0
firewall-cmd --permanent --zone=zone1 --add-source=192.168.1.3
firewall-cmd --permanent --zone=zone1 --add-service=http
firewall-cmd --permanent --zone=zone1 --add-service=https

firewall-cmd --permanent --new-zone=zone2
firewall-cmd --permanent --zone=zone2 --set-target=REJECT
firewall-cmd --permanent --zone=zone2 --add-source=192.168.1.4
firewall-cmd --permanent --zone=zone2 --add-service=mysql

firewall-cmd --set-default-zone=zone2
</code></pre>

<p>il binding dell&#39;interfaccia fa ricadere la richiesta nella zona1 che rifiuta l&#39;accesso → ⚠️ <strong>ATTENZIONE!</strong></p>

<h4 id="5-4-3-remediation-per-la-zone-hijacking">5.4.3. Remediation per la “zone hijacking”</h4>

<p>L&#39;utilizzo delle sole sorgenti per restringere l&#39;accesso non è sufficiente perché ip che transitano sull&#39;host e non appartengano a nessuna sorgente di zona, <strong>possono richiedere lecitamente i servizi appartenenti alla zona di fallback</strong></p>

<p>Ci sono un paio di modi per evitare questo tranello.</p>

<p>Uno consiste nell&#39;usare le rich-rules come abbiamo fatto nella gestione delle zone di management e di backend del punto <a href="#5-2-caso-2-configurazione-di-un-fw-personale-su-un-host-con-3-interfacce" rel="nofollow">5.2. Caso 2: Configurazione di un fw personale su un host con 3 interfacce</a>. Accesso pieno alle sole interfacce e i sorgenti nelle rich-rules sono le white-list che consentono puntualmente chi può accedere a cosa.</p>

<p>Un altro metodo consiste nell&#39;usare come zona di default, una zona senza alcun binding, con lo scopo di droppare tutto ciò che vi finisce dentro.</p>

<pre><code class="language-bash">firewall-cmd --permanent --new-zone=default-drop
firewall-cmd --permanent --zone=default-drop --set-target=DROP
firewall-cmd --set-default-zone=default-drop
</code></pre>

<p>In questo modo la zona di default che riceverà il pacchetto sospeso non avrà alcun servizio associato a differenza di prima, ma dropperà tutto ciò che incontra.</p>

<h2 id="6-tips">6. Tips</h2>

<h3 id="6-1-le-azioni-di-firewall-cmd">6.1. Le azioni di firewall-cmd</h3>

<p>Per districarsi rapidamente nella sintassi di <code>firewall-cmd</code>, mi viene comodo ricordare “le azioni” distintive principali in un&#39;ottica CRUD:</p>
<ul><li><code>--get</code> / <code>--info</code> /  <code>--list</code>. <strong>recupera (legge)</strong> informazioni sulla configurazione</li>
<li><code>--new</code> / <code>--add</code>, <strong>crea</strong> nuovi oggetti / elementi</li>
<li><code>--set</code>, <strong>modifica</strong> gli elementi</li>
<li><code>--remove</code> / <code>--delete</code>, <strong>rimuove</strong> gli elementi / oggetti</li></ul>

<p>E più precisamente:</p>
<ul><li><code>--get</code>, restituisce un elenco di oggetti complessi a livello di sistema (ad es. icmptypes, servizi, zone o policy) o il valore di un suo campo ;</li>
<li><code>--set</code>, imposta il valore di un campo;</li>
<li><code>--info</code>, restituisce il recordset di un determinato oggetto complesso come un servizio, una policy, una zona, un ipset;</li>
<li><code>--list</code>, come <code>--info</code> ma più articolato;</li>
<li><code>--new</code>, crea nuovi oggetti complessi;</li>
<li><code>--add</code>, aggiunge un elemento ad un oggetto complesso;</li>
<li><code>--remove</code>, rimuove elementi da un oggetto complesso ad es. un servizio da una zona/policy, una entry da un servizio, una rule da una zona/policy ecc.</li>
<li><code>--delete</code>, rimuove un oggetto complesso come una zona, una policy, un ipset, un servizio ecc.</li></ul>

<h3 id="6-2-comandi-utili">6.2. Comandi utili</h3>

<p>Di seguito. un sottinsieme di comandi già visti, utili per catturare velocemente informazioni sulla configurazione del firewall.</p>

<p><strong>Elenco di tutti gli ipset:</strong></p>

<pre><code class="language-bash">firewall-cmd --permanent --get-ipsets
</code></pre>

<p><strong>Elenco di tutti i tipi di ipset:</strong></p>

<pre><code class="language-bash">firewall-cmd --get-ipset-types
</code></pre>

<p><strong>Elenco di tutti tipi di icmp:</strong></p>

<pre><code class="language-bash">firewall-cmd --get-icmptypes
</code></pre>

<p><strong>Elenco di tutti i servizi:</strong></p>

<pre><code class="language-bash">firewall-cmd --get-services
</code></pre>

<p><strong>Individuare la zona dall&#39;interfaccia:</strong></p>

<pre><code class="language-bash">firewall-cmd --permanent --get-zone-of-interface=&#34;&lt;nome interfaccia&gt;&#34;
</code></pre>

<p><strong>Individuare la zona dal sorgente:</strong></p>

<pre><code class="language-bash">firewall-cmd --permanent --get-zone-of-source=ip | MAC | ipset:&#34;&lt;nome_ipset&gt;&#34;
</code></pre>

<p><strong>Zona di default:</strong></p>

<pre><code class="language-bash">firewall-cmd --get-default-zone
</code></pre>

<p><strong>Zone attive:</strong></p>

<pre><code class="language-bash">firewall-cmd --get-active-zones
</code></pre>

<p><strong>Elenco di tutte le zone/policies:</strong></p>

<pre><code class="language-bash">firewall-cmd --get-zones
firewall-cmd --get-policies
</code></pre>

<p><strong>Dettaglio delle configurazione di tutte le zone/policy:</strong></p>

<pre><code class="language-bash">firewall-cmd --list-all-zone
firewall-cmd --list-all-policies
</code></pre>

<p><strong>Dettaglio della configurazione di una zona/policy:</strong></p>

<pre><code class="language-bash">firewall-cmd --permanent --info-zone=&#34;&lt;nome_zona&gt;&#34;
firewall-cmd --permanent --info-policy=&#34;&lt;nome_policy&gt;&#34;
</code></pre>

<p><strong>Elenco di tutti i servizi di una zona/policy:</strong></p>

<pre><code class="language-bash">firewall-cmd --zone=&#34;&lt;nome_zona&gt;&#34; --list-services
firewall-cmd --policy=&#34;&lt;nome_policy&gt;&#34; --list-services
</code></pre>

<p><strong>Elenco di tutte le porte di una zona/policy:</strong></p>

<pre><code class="language-bash">firewall-cmd --permanent --zone=&#34;&lt;nome_zona&gt;&#34; --list-ports
firewall-cmd --permanent --policy=&#34;&lt;nome_policy&gt;&#34; --list-ports
</code></pre>

<p><strong>Elenco di tutte le rich rules di una zona/policy:</strong></p>

<pre><code class="language-bash">firewall-cmd --permanent --zone=&#34;&lt;nome_zona&gt;&#34; --list-rich-rules
firewall-cmd --permanent --policy=&#34;&lt;nome_policy&gt;&#34; --list-rich-rules
</code></pre>

<p><strong>Elenco di tutte le forward ports di una zona/policy:</strong></p>

<pre><code class="language-bash">firewall-cmd --permanent --zone=&#34;&lt;nome_zona&gt;&#34; --list-forward-ports
firewall-cmd --permanent --policy=&#34;&lt;nome_policy&gt;&#34; --list-forward-ports
</code></pre>

<p><strong>Dettaglio della configurazione di un servizio:</strong></p>

<pre><code class="language-bash">firewall-cmd --permanent --info-service=&#34;&lt;nome_servizio&gt;&#34;
</code></pre>

<p><strong>Elenco di tutte le porte di un servizio:</strong></p>

<pre><code class="language-bash">firewall-cmd --permanent --service=&#34;&lt;nome_servizio&gt;&#34; --get-ports
</code></pre>

<p><strong>Dettaglio della configurazione di un ipset:</strong></p>

<pre><code class="language-bash">firewall-cmd --permanent --info-ipset=&#34;&lt;nome_ipset&gt;&#34;
</code></pre>

<p><strong>Elenco di tutte le entry di un ipset:</strong></p>

<pre><code class="language-bash">firewall-cmd --permanent --ipset=&#34;&lt;nome_ipset&gt;&#34; --get-entries
</code></pre>

<h3 id="6-3-considerazioni-di-contorno">6.3. Considerazioni di contorno</h3>

<p>Concludendo, firewalld, in quanto frontend fedele di nftables, rappresenta il futuro del firewalling linux.</p>

<p><strong>Aspetti comuni:</strong></p>
<ol><li>Configurare i servizi ove possibile è sempre da preferire rispetto a porte/protocolli sparati direttamente nella zona o nella policy.</li>
<li>Ricorrere alle rich-rules solo se si devono gestire flussi puntuali, altrimenti è sufficiente il bind dell&#39;interfaccia alla zona.</li></ol>

<p><strong>Approccio conservativo:</strong>
Per configurazioni semplici, bastano zone e servizi.</p>

<p>In presenza di più interfacce, obbligatorio anche il ricorso ai policy object, perché ci sarà da gestire di sicuro traffico interzona.</p>
<ul><li><strong>Pro:</strong> curva d&#39;apprendimento morbida, ideale se la necessità è di essere operativi nel breve. Ideali per firewall personali e configurazioni semplici.</li>
<li><strong>Contro:</strong> le configurazioni tendono ad irrigidirsi al crescere della complessità degli scenari e quindi a complicare le manutenzioni.</li></ul>

<p><strong>Approccio spregiudicato:</strong>
Delegare alle zone solo il trust delle sorgenti e spostare la logica dei flussi interamente ai policy object.</p>
<ul><li><strong>Pro:</strong> massima flessibilità, maggiore pulizia delle configurazioni. Ideale per scenari complessi.</li>
<li><strong>Contro:</strong> curva d&#39;apprendimento più ripida, le configurazioni più semplici tendono ad apparire molto più verbose e di conseguenza meno chiare.</li></ul>

<p><a href="/aytin/tag:firewall" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">firewall</span></a> <a href="/aytin/tag:firewallcmd" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">firewallcmd</span></a> <a href="/aytin/tag:firewalld" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">firewalld</span></a> <a href="/aytin/tag:iptables" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">iptables</span></a> <a href="/aytin/tag:netfilter" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">netfilter</span></a>  <a href="/aytin/tag:nftables" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">nftables</span></a> <a href="/aytin/tag:ufw" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">ufw</span></a></p>
]]></content:encoded>
      <guid>https://noblogo.org/aytin/sveliamo-i-misteri-di-firewalld-parte-2-di-2</guid>
      <pubDate>Fri, 10 Jul 2026 14:14:03 +0000</pubDate>
    </item>
    <item>
      <title>Sveliamo i misteri di Firewalld (Parte 1 di 2)</title>
      <link>https://noblogo.org/aytin/sveliamo-i-misteri-di-firewalld-parte-1-di-2</link>
      <description>&lt;![CDATA[tux-firewalld&#xA;---&#xA;N.B. Sono stato costretto a spezzare l&#39;articolo perché, quello originale di 8836 parole (per un totale di 76309 bytes effettivi), veniva troncato dopo il salvataggio a 7533 parole (65.356 bytes), cosa che mi fa sospettare che la grandezza del body non possa superare i 64k.&#xA;---&#xA;firewalld fornisce funzionalità firewall fungendo da frontend per netfilter.&#xA;&#xA;Nell&#39;interagire con netfilter, analogamente a ufw con iptables, firewalld usa come backend nftables, un tool nella user-space del kernel linux, che va a sostituire proprio iptables. Entrambi i backend forniscono filtraggio e classificazione dei pacchetti di rete /datagrammi/frame.&#xA;!--more--&#xA;&#xA;1. Come ragiona firewalld&#xA;2. Come procedo nella configurazione di Firewalld?&#xA;3. Il man di firewall-cmd&#xA;4. Come configurare firewalld&#xA;   4.1. Helpers&#xA;   4.2. Servizi&#xA;   4.3. Gestione ICMP&#xA;   4.4. Porte e protocolli&#xA;   4.5. IPset&#xA;   4.6. Rich-Rules&#xA;   4.7. Forwarding e Masquerade&#xA;   4.8. Zona&#xA;   4.9. Policy Objects&#xA;   4.10. Comandi di utilità generale&#xA;&#xA;Attualmente ufw usa ancora iptables ma in modalità legacy, consistente in uno strato software che traduce i comandi iptables nei corrispondenti comandi nftables.&#xA;&#xA;Firewalld supporta le zone di rete/firewall che definiscono il livello di fiducia delle connessioni o delle interfacce di rete.&#xA;&#xA;C&#39;è una separazione fra runtime e configurazione permanente che consente di testare una configurazione prima di renderla effettiva.&#xA;&#xA;firewalld, con nftables, è certamente il frontend ideale per netfilter dal momento che recepisce tutte le sue innovazioni. La possibilità di usare, nella stessa cli, filtraggio, routing, snat e dnat per es. rende l&#39;esperienza certamente più omogenea (con ufw, masquerade e port-forwarding richiedono una gestione aggiuntiva direttamente con iptables per ora).&#xA;&#xA;Sebbene destinato ad essere rimpiazzato, iptables continua ad avere una sua specificità visto che viene ancora usato da docker per agire direttamente su netfilter bypassando eventuali firewall locali quano deve esporre una porta.&#xA;&#xA;Con l&#39;attuale versione di docker, la 29, è stato introdotto il supporto diretto su nftables in via sperimentale.&#xA;&#xA;Ad ogni modo, chi approccia per la prima volta a firewalld (come è successo a me) all&#39;inizio può essere sopraffatto dall&#39;allegro affollamento di opzioni a disposizione.&#xA;&#xA;zone&#xA;porte&#xA;protocolli&#xA;servizi&#xA;policy objects&#xA;rich-rules&#xA;port forwarding&#xA;masquerade&#xA;ipset&#xA;helper&#xA;....&#xA;&#xA;La gui (firewall-config) mette certamente ordine ma non aiuta fino in fondo. Oltre a questo la gui non racchiude tutta la logica della cli (ad es. mancano i policy objects).&#xA;&#xA;La cli di firewalld è il riferimento e come tutte le cli, può spaventare.&#xA;&#xA;In realtà la cli, firewall-cmd nello specifico, è una delle più pulite e lineari che conosca, basta conoscere gli la logica a oggetti che governa firewalld.&#xA;1. Come ragiona firewalld&#xA;Se guardassi firewalld dall&#39;alto, riconoscerei 7 oggetti principali:&#xA;&#xA;Zone&#xA;Policy Objects&#xA;Services&#xA;IPSet&#xA;ICMP Types&#xA;Helper&#xA;Direct Options (Deprecato)&#xA;&#xA;Zone: è un po&#39; il tratto distintivo di firewalld. Concettualmente rappresenta il livello di fiducia che si ha nei confronti di una rete connessa a una specifica interfaccia (es. eth0) o di un indirizzo IP. Ogni pacchetto dati che entra nel server viene catturato da una zona in base alla sua sorgente o all&#39;interfaccia da cui arriva. È qui che avviene la configurazione del traffico in ingresso.&#xA;&#xA;Policy Objects: è una delle novità di firewalld. I policy object nascono per gestire il traffico inter-zona. Inizialmente il filtraggio avveniva all&#39;interno dell&#39;oggetto (la zona) che accoglie il pacchetto, ora viene disaccoppiato e trasferito in un altro oggetto che gestisce il transito dei pacchetti tra una zona e l&#39;altra (o se stessa).&#xA;In questo modo cambia profondamente il paradigma di manipolazione dei pacchetti. La zona attiva il filtraggio quando il pacchetto entra da una delle sorgenti associate alla zone. La policy, attiva il filtraggio quando il pacchetto transita tra le zone specifiche definite dalla policy.&#xA;&#xA;Services: rappresenta ciò che esponiamo (o che dobbiamo raggiungere, se filtriamo il traffico in uscita dal nostro host quando si comporta da client).&#xA;&#xA;L&#39;IPSet: permette di definire dei blocchi di ip a cui applicare regole massivamente invece che definirle puntalmente.&#xA;&#xA;ICMP Types: è relativo ai pacchetti ICMP e permette di rendere disponibile il pacchetto scelto al traffico di tipo ipv4 e/o ipv6  &#xA;&#xA;Helper: torna comodo invece per quei protocolli che aprono una connessione su una porta e poi negoziano dinamicamente un&#39;altra porta per il trasferimento dei dati (es. ftp, netbios-ns, sip, vecchi protocolli di gaming/streaming ecc.). Invece che aprire un intervallo ampio di porte, l&#39;helper, che è un modulo del kernel, &#34;ascolta&#34; il flusso di controllo, capisce quale porta casuale sta per essere usata e la apre temporaneamente al volo solo per quel trasferimento.&#xA;&#xA;Direct Options: le direct options (ormai deprecate e sostituite dai policy objects) sono la parte legacy di firewalld attraverso cui parla con iptables invece che con nftables.&#xA;&#xA;Questi sono gli oggetti principali su cui si costruiscono le regole per il firewall attraverso una sintassi molto corposa ma ragionata e lineare.&#xA;&#xA;La cli mette a disposizione delle istruzioni per fare praticamente qualunque cosa:&#xA;&#xA;visualizzare lo stato del firewall;&#xA;istanziare gli oggetti;&#xA;combinare gli oggetti istanziati al fine di creare la nostra logica di firewalling;&#xA;effettuare delle query di verifica esistenziale sugli oggetti;&#xA;effettuare il binding delle zone con interfacce o sorgenti;&#xA;&#xA;Da tenere presente che la configurazione di firewalld, come iptables, può essere effimera. Se la configurazione a caldo non viene resa &#34;permanente&#34;, produce effetti fino a quando il servizio viene riavviato. Quando avviene, lo stato di firewalld ritorna ad essere quello che era prima delle modifiche.&#xA;2. Come procedo nella configurazione di Firewalld?&#xA;Come abbiamo visto, firewalld ha una logica di funzionamento molto più versatile di iptables, decisamente più rigido al confronto.&#xA;Questa versatilità però può portare a rendere gli scenari più caotici potendo mescolare diverse tecniche di filtraggio. &#xA;Come dire, il solito problema della scelta quando ce n&#39;è troppa.&#xA;&#xA;My two cents:&#xA;&#xA;Se l&#39;esigenza è quella di configurare un firewall personale, è sufficiente configurare opportunamente zone e servizi.&#xA;Se bisogna tenere in considerazione traffico inter-zona (in presenza di più interfacce per es.) ci vengono in aiuto i policy objects.&#xA;Se abbiamo ulteriori esigenze di granularità, la zona permette di definire delle rich-rules.&#xA;&#xA;Un canovaccio del genere aiuta a mantenere la configurazione pulita, altrimenti potrei sporcarla in mille modi differenti rendendo però complicata la manutenzione futura.&#xA;&#xA;Cercando di mettere a fattor comune quello che faccio con firewall-cmd la maggior parte delle volte, se volessi configurare un firewall personale secondo il canovaccio di cui sopra, i passi da fare sono i seguenti:&#xA;&#xA;creo la zona&#xA;se non sono presenti nel default perché magari le porte dei servizi sono custom, creo anche i servizi (descrizione, porta/e e protocollo/i)&#xA;nella configurazione della zona, faccio il binding con l&#39;interfaccia e con i servizi (eventualmente custom) che ho definito.&#xA;&#xA;Stop.&#xA;&#xA;Non occorre altro.&#xA;&#xA;Ma firewalld permette anche configurazioni molto più borderline.&#xA;&#xA;Nella mia zona potrei non avere alcun oggetto di tipo servizio ma potrei semplicemente assegnare direttamente una sbrodolata di porte e protocolli.&#xA;&#xA;Oppure potrei lavorare direttamente con le rich-rules (approccio simil-ufw).&#xA;&#xA;Oppure potrei affidare la logica direttamente ai policy objects.&#xA;&#xA;Personalmente, tutte queste alternative (a parte l&#39;ultima) le vedo più come un esercizio accademico senza una reale utilità pratica perché in scenari complessi questi approcci possono dar luogo a configurazioni estremamente caoitche.&#xA;3. Il man di firewall-cmd&#xA;Il man di firewall-cmd è molto chiaro e lineare e sarebbe bene tenerlo presente quando ci si lavora per le prime volte.&#xA;&#xA;È strutturato in 3 grossi blocchi:&#xA;&#xA;Sezioni di carattere generale. Stato firewall, verbosity log, salvataggio configurazioni, ecc&#xA;&#xA;General Options&#xA;Status Options&#xA;Log Denied Options&#xA;Permanent Options&#xA;Panic Options&#xA;&#xA;Sezioni per la configurazione delle componenti core. Zone , Policy Objects, IPSet, Service, ecc.&#xA;&#xA;Zone Options&#xA;Policy Options&#xA;IPSet Options&#xA;Service Options&#xA;Helper Options&#xA;ICMP type Options&#xA;Direct Options (deprecato)&#xA;&#xA;Sezioni per l&#39;interrogazione e la configurazione delle combinazioni fra zone, policy objects, interfacce e sorgenti&#xA;&#xA;Options to Adapt and Query Zones and Policies&#xA;Options to Adapt and Query Zones&#xA;Options to Adapt and Query Policies&#xA;Options to Handle Bindings of Interfaces&#xA;Options to Handle Bindings of Sources&#xA;&#xA;4. Come configurare firewalld&#xA;Come anticipato, la configurazione della zona con associati servizi, interfaccia e sorgenti, è tutto ciò che serve.&#xA;&#xA;Se le mie policy sono complesse e ho necessità di centralizzarle, posso usare i policy objects.&#xA;&#xA;Se si deve intervenire chirurgicamente per impedire o abilitare del traffico, ci sono le rich-rules.&#xA;&#xA;In sostanza, tutto ruota attorno a due grossi item, le zone e i policy objects, che, forse in maniera un po&#39; ridondante, combinano una serie di componenti che concorrono a formare la logica di firewalling.&#xA;&#xA;Per entrare nel merito della configurazione partirò da quelle che per me sono le &#34;foglie&#34; di un ipotetico albero che, attraverso una serie di inclusioni, termina con 2 grosse radici: zone o police objects.&#xA;&#xA;Fra gli elementi terminali nella gerarchia di firewalld, per me, ci sono gli helpers che poi concorrono a formare i servizi che insieme a porte e protocolli, IPset, forwarding, masquerade finiranno in zone, policy objects e rich-rules.&#xA;4.1. Helpers&#xA;Gli helpers sono degli oggetti basati sul modulo nfconntrack del kernel Netfilter, che permettono di tracciare le connessioni, per la precisione sono delle interfacce che permettono a firewalld di caricare e configurare il relativo modulo nfconntrack del kernel. &#xA;&#xA;Ci sono protocolli come ftp, tftp, alcuni protocolli di gaming, voip ecc. che, oltre che esporre la porta per essere contattati, in un secondo momento devono negoziare dinamicamente con il client un&#39;altra porta per lo scambio dei dati.&#xA;&#xA;Questo tipo di servizi non è facilmente controllabile senza gli helpers perché la negoziazione dinamica imporrebbe di aprire un set molto ampio di porte.&#xA;&#xA;Con gli helpers le connessioni di questi servizi &#34;anomali&#34; verranno tracciate in modo che, quando dal cliente arriva un pacchetto che richiede l&#39;apertura di una porta random per lo scambio dati, quella connessione verrà marchiata come RELATED, che come tutto il traffico RELATED viene accettata nativamente, invece che come NEW che sarebbe destinata ad essere scartata.&#xA;&#xA;Gli helpers, lista dei quali disponibile con:&#xA;firewall-cmd --get-helpers&#xA;corrispondono all&#39;incirca ai moduli nfconntrack presenti nel kernel Netfilter e si trovano in /lib/modules/$(uname -r)/kernel/net/netfilter.&#xA;&#xA;Andranno aggiunti ai servizi, qualora servissero, in modo che firewalld accetti, e solo per quei servizi, connessioni da porte dinamiche.&#xA;&#xA;Un po&#39; di storia&#xA;In passato, il kernel linux abilitava (con qualcosa tipo nfconntrackhelper=1) gli helpers per default su tutto il traffico favorendo attacchi basati sullo spoofing dei pacchetti con cui farsi aprire porte a caso.&#xA;&#xA;Poi quest&#39;opzione è stata prima disabilitata di defautl con nfconntrackhelper=0 permettendo un&#39;attivazione prudente solo da file di configurazione con AutomaticHelpers=yes/no/system, poi è stata definitivamente rimossa sia dal kernel che dal file di configurazione.&#xA;&#xA;Oggi, per attivare gli helper, basta dichiararli e associarli ad un servizio. Firewalld provvederà a caricare dinamicamente solo i moduli del kernel Netfilter necessari gestendo sia la porta dalla quale il servizio verrà contattato sia le porte dinamiche che verranno negoziate per lo scambio dei dati.&#xA;restituisce tutte le informazioni di un helper&#xA;firewall-cmd --permanent --info-helper=&#34;nomehelper&#34;&#xA;&#xA;dichiaro un nuovo helper&#xA;firewall-cmd --permanent --new-helper=&#34;nomehelper&#34; --module=nfconntracknomemodulo&#xA;&#xA;restituisce tutti gli helper presenti&#xA;firewall-cmd --permanent --get-helpers&#xA;&#xA;imposta / restituisce una descrizione&#xA;firewall-cmd --permanent --helper=&#34;nomehelper&#34; --set-description=&#34;descrizione&#34;&#xA;firewall-cmd --permanent --helper=&#34;nomehelper&#34; --get-description&#xA;&#xA;imposta / restituisce una descrizione breve&#xA;firewall-cmd --permanent --helper=&#34;nomehelper&#34; --set-short=&#34;descrizione&#34;&#xA;firewall-cmd --permanent --helper=&#34;nomehelper&#34; --get-short&#xA;&#xA;aggiunge/rimuove la porta o il range di porte dall&#39;helper&#xA;firewall-cmd --permanent --helper=&#34;nomehelper&#34; --add-port=port[-port]/protocol&#xA;firewall-cmd --permanent --helper=&#34;nomehelper&#34; --remove-port=port[-port]/protocol&#xA;&#xA;restituisce tutte le porte associate all&#39;helper&#xA;firewall-cmd --permanent --helper=&#34;nomehelper&#34; --get-ports&#xA;&#xA;imposta / restituisce un modulo per l&#39;helper&#xA;firewall-cmd --permanent --helper=&#34;nomehelper&#34; --set-module=nfconntracknomemodulo&#xA;firewall-cmd --permanent --helper=&#34;nomehelper&#34; --get-module&#xA;&#xA;rimuove un helper da sistema&#xA;--permanent --delete-helper=&#34;nomehelper&#34;&#xA;&#xA;4.2. Servizi&#xA;Per creare un servizio, si assegna un nome e un insieme di porte e protocolli.&#xA;firewall-cmd --permanent --new-service=&#34;nomeservizio&#34;&#xA;firewall-cmd --permanent --service=&#34;nomeservizio&#34; --set-description=&#34;Descrizione del servizio&#34;&#xA;firewall-cmd --permanent --service=&#34;nomeservizio&#34; [--add-port=port/tcp | udp | sctp | dccp]+&#xA;Di seguito una lista di comandi utili:&#xA;elenco di tutti i servizi&#xA;firewall-cmd --get-services&#xA;elenco dei servizi della zona attiva&#xA;firewall-cmd --list-services&#xA;elenco dei servizi di una determinata zona&#xA;firewall-cmd --permanent --zone=&#34;nomezona&#34; --list-services&#xA;restituisce le info di un servizio&#xA;firewall-cmd --permanent --info-service=&#34;nomeservizio&#34;&#xA;&#xA;imposta / restituisce una descrizione&#xA;firewall-cmd --permanent --service=&#34;nomeservizio&#34; --get-description&#xA;firewall-cmd --permanent --service=&#34;nomeservizio&#34; --set-description=&#34;descrizione&#34;&#xA;&#xA;imposta / restituisce una descrizione breve&#xA;firewall-cmd --permanent --service=&#34;nomeservizio&#34; --get-short-description&#xA;firewall-cmd --permanent --service=&#34;nomeservizio&#34; --set-short-description=&#34;descrizione&#34;&#xA;&#xA;restituisce tutte le porte del servizio&#xA;firewall-cmd --permanent --service=&#34;nomeservizio&#34; --get-ports&#xA;&#xA;imposta / restituisce un (o più) protocollo di un servizio&#xA;firewall-cmd --permanent --service=&#34;nomeservizio&#34; --get-protocols&#xA;firewall-cmd --permanent --service=&#34;nomeservizio&#34; [--add-protocol=tcp | udp | sctp | dccp]+&#xA;&#xA;rimozione (porta, protocollo) / protocollo&#xA;firewall-cmd --permanent --service=&#34;nomeservizio&#34; [--remove-port=port/tcp | udp | sctp | dccp]+&#xA;firewall-cmd --permanent --service=&#34;nomeservizio&#34; [--remove-protocol=tcp | udp | sctp | dccp]+&#xA;&#xA;aggiunge / rimuove un helper da un servizio&#xA;firewall-cmd --permanent --service=&#34;nomeservizio&#34; --add-helper=&#34;nomehelper&#34;&#xA;firewall-cmd --permanent --service=&#34;nomeservizio&#34; --remove-helper=&#34;nomehelper&#34;&#xA;&#xA;restituisce gli helper collegati al servizio&#xA;firewall-cmd --permanent --service=&#34;nomeservizio&#34; --get-service-helpers&#xA;&#xA;elimina un servizio&#xA;firewall-cmd --permanent --delete-service==&#34;nomeservizio&#34;&#xA;(rif. man service)&#xA;4.3. Gestione ICMP&#xA;Il traffico ICMP viene impostato a livello di zona o a livello di policy object.&#xA;&#xA;Al solito, agire a livello di zona è più semplice, usare i policy objects permette di guadagnare in modularità e scalabilità.&#xA;&#xA;Di default, ICMP lavora su blacklist. È tutto consentito tranne ciò che viene esplicitamente vietato con le istruzioni --add-icmp-block per aggiungere il tipo icmp che si vuole bloccare o --remove-icmp-block per rimuovere il blocco.&#xA;&#xA;È possibile invertire la logica di funzionamento, a livello globale o di singola zona, passando ad una whitelist. È tutto vietato tranne cio che è consentito con --add-icmp-block (un po&#39; fuorviante, ne convengo). --remove-icmp-block rimuove il consenso.&#xA;&#xA;Di seguito, un elenco dei comandi di utilità disponibili per gli icmptype:&#xA;Elenca tutti gli icmptype&#xA;firewall-cmd --get-icmptypes&#xA;&#xA;inverte / disattiva globalmente la logica del blocco icmp (attiva / disattiva whitelist)&#xA;firewall-cmd --permanent --add-icmp-block-inversion&#xA;firewall-cmd --permanent --remove-icmp-block-inversion&#xA;&#xA;Creazione e cancellazione di un icmptype&#xA;firewall-cmd  --permanent --new-icmptype=&#34;nome icmptype&#34;&#xA;firewall-cmd  --permanent --delete-icmptype=&#34;nome icmptype&#34;&#xA;&#xA;imposta / restituisce la descrizione di un icmptype&#xA;firewall-cmd  --permanent --icmptype=&#34;nome icmptype&#34; --set-description=&#34;descrizione&#34;&#xA;firewall-cmd  --permanent --icmptype=&#34;nome icmptype&#34; --get-description&#xA;&#xA;imposta / restituisce la descrizione breve di un icmptype&#xA;firewall-cmd  --permanent --icmptype=&#34;nome icmptype&#34; --set-short=&#34;descrizione&#34;&#xA;firewall-cmd  --permanent --icmptype=&#34;nome icmptype&#34; --get-short&#xA;&#xA;imposta/cancella/restituisce la destinazione (ipv4 o ipv6) di un icmptype&#xA;firewall-cmd  --permanent --icmptype=&#34;nome icmptype&#34; --add-destination=&#34;[ipv4 | ipv6]&#34;&#xA;firewall-cmd  --permanent --icmptype=&#34;nome icmptype&#34; --remove-destination=&#34;[ipv4 | ipv6]&#34;&#xA;firewall-cmd  --permanent --icmptype=&#34;nome icmptype&#34; --get-destinations&#xA;(rif. man icmp type) &#xA;4.4. Porte e protocolli&#xA;Zone e policy objects permettono di fare binding diretto su porte e protocolli.&#xA;&#xA;Non è generalmente una cosa che mi faccia impazzire perché si bypassano i servizi.&#xA;&#xA;Si fa tutto più velocemente, è vero, ma quando le regole sono numerose e si usano porte non canoniche, la probabilità che, al tendere, non si capisca più su quale servizio si stia agendo, è elevatissima. (cfr. 4.8. Zona e 4.9. Policy objects)&#xA;4.5. IPset&#xA;Gli ipset sono liste di subnet o di ip che definiscono le sorgenti nelle zone, nei policy object o nelle rich-rules. La centralizzazione della dichiarazione delle sorgenti disaccoppia la dichiarazione dal suo utilizzo.&#xA;&#xA;Per gli ipset basta indicarre, nome, tipo e una lista di entry.&#xA;firewall-cmd --permanent --new-ipset=&#34;nomeipset&#34; --type=type&#xA;firewall-cmd --permanent --ipset=&#34;nomeipset&#34; [--add-entry= subnet | ip]+&#xA;Di seguito, un elenco dei comandi di utilità disponibili per gli ipsets:&#xA;Restituisce tutti gli ipsets&#xA;firewall-cmd --permanent --get-ipsets&#xA;&#xA;Restituisce tutte le info di un ipset&#xA;firewall-cmd --permanent --info-ipset=&#34;nomeipset&#34;&#xA;&#xA;Restituisce la lista dei tipi di ipset:&#xA;firewall-cmd --get-ipset-types&#xA;&#xA;Restituisce tutte le entry di un ipset&#xA;firewall-cmd --permanent --ipset=&#34;nomeipset&#34; --get-entries&#xA;&#xA;Cancella un ipset&#xA;firewall-cmd --permanent --ipset=&#34;nomeipset&#34; --remove-entry=subnet | ip&#xA;&#xA;Cancella una (o più) entry da un ipset&#xA;firewall-cmd --permanent --ipset=&#34;nomeipset&#34; [--delete-entry=subnet | ip]+&#xA;&#xA;imposta / restituisce la descrizione di un ipset&#xA;firewall-cmd --permanent --ipset=&#34;nomeipset&#34; --set-description=&#34;descrizione&#34;&#xA;firewall-cmd --permanent --ipset=&#34;nomeipset&#34; --get-description&#xA;&#xA;imposta / restituisce la descrizione breve di un ipset&#xA;firewall-cmd --permanent --ipset=&#34;nomeipset&#34; --set-short=&#34;descrizionebreve&#34;&#xA;firewall-cmd --permanent --ipset=&#34;nomeipset&#34; --get-short-description&#xA;(rif. man ipset) &#xA;4.6. Rich-Rules&#xA;Le rich rules danno quel controllo granulare alle zone che è essenziale se si deve intervenire chirurgicamente per accettare o negare del traffico specifico.&#xA;&#xA;Le rich-rules hanno una sintassi leggermente più corposa dello standard firewalld, è un approccio simil-iptables, o meglio, simil-ufw, e vanno aggiunte o alle zone o alle policy. O a entrambe.&#xA;&#xA;Con le rich-rules possiamo abilitare o negare puntualmente il traffico (a seconda della action scelta),&#xA;firewall-cmd --permanent --zone=&#34;nomezona&#34; --add-rich-rule=&#39;rule family=&#34;ipv4 | ipv6&#34; \&#xA;  source address=&#34;nomeipset&#34; | subnet | ip \&#xA;  destination address=&#34;nomeipset&#34; | subnet | ip \&#xA;  # traffico indicato come servizio o come port:protocol&#xA;  service name=&#34;nomeservizio&#34; | port=port protocol=tcp|udp|sctp|dccp \&#xA;  log prefix=&#34;prefix&#34; \&#xA;  level=&#34;emerg | alert | crit | error | warning | notice | info | debug&#34; \&#xA;  limit value=&#34;rate/duration&#34; \&#xA;  # azioni&#xA;  accept | reject | drop | mark&#39;&#xA;configurare il masquerade,&#xA;firewall-cmd --permanent --zone=&#34;nomezona&#34; --add-rich-rule=&#39;rule family=&#34;ipv4 | ipv6&#34; \&#xA;  source address=&#34;nomeipset&#34; | &#34;subnet&#34; | &#34;ip&#34; \&#xA;  destination address=&#34;nomeipset&#34; | &#34;subnet&#34; | &#34;ip&#34; \&#xA;  masquerade&#39;&#xA;agire di fino sul NAT,&#xA;firewall-cmd --permanent --zone=&#34;nomezona&#34; --add-rich-rule=&#39;rule family=&#34;ipv4 | ipv6&#34; \&#xA;  source address=&#34;nomeipset&#34; | &#34;subnet&#34; | &#34;ip&#34; \&#xA;  destination address=&#34;nomeipset&#34; | &#34;subnet&#34; | &#34;ip&#34; \&#xA;  forward-port port=&#34;[port]+&#34; protocol=&#34;tcp|udp|sctp|dccp&#34; \&#xA;  to-port=&#34;[port]+&#34; to-addr=&#34;ip&#34;&#39;&#xA;bloccare traffico ICMP.&#xA;firewall-cmd --permanent --zone=&#34;nomezona&#34; --add-rich-rule=&#39;rule family=&#34;ipv4 | ipv6&#34; \ &#xA;  source address=&#34;nomeipset&#34; | &#34;subnet&#34; | &#34;ip&#34; \&#xA;  destination address=&#34;nomeipset&#34; | &#34;subnet&#34; | &#34;ip&#34; \&#xA;  [icmp-block name=&#34;nomeicmptype&#34; [drop | reject]]+&#xA;Di seguito una lista di comandi utili:&#xA;Rimozione di una rich-rule&#xA;firewall-cmd --permanent [--zone=&#34;nomezona&#34; | --policy=&#34;nomepolicy&#34;] --remove-rich-rule=&#39;rule&#39;&#xA;&#xA;Elenca tutte le rich-rules di una policy&#xA;firewall-cmd --permanent [--zone=&#34;nomezona&#34; | --policy=&#34;nomepolicy&#34;] --list-rich-rules&#xA;(rif. man rich-rules)&#xA;4.7. Forwarding e Masquerade&#xA;Firewalld gestisce il nat attraverso dei costrutti all&#39;interno delle zone, dei policy objects o delle rich-rules.&#xA;&#xA;In particolare, zone e policy consentono di configurare velocemente casi particolari di DNAT e SNAT, port forwarding e masquerade nello specifico, mentre per una gestione del DNAT più granulare si ricorre alle rich-rules, a livello di zona o di policy a seconda che si vogliano, al solito, manipolare i pacchetti quando entrano nella zona o quando il pacchetto transita tra le zone specifiche definite dalla policy.&#xA;&#xA;Esempio Port forwarding statico:&#xA;inoltra a 192.168.2.10:22, tutto ciò che la zona riceve sulla &#xA;porta 2222&#xA;firewall-cmd --permanent --zone=esterna --add-forward-port=port=2222:proto=tcp:to-port=22:to-addr=192.168.2.10&#xA;In questo modo inoltro tutto il traffico relativo alla zona.&#xA;&#xA;Se voglio un controllo più fine, devo ricorrere alla combo policy (o zona) +  rich-rules.&#xA;In questo modo posso arrivare a determinare quale sia l&#39;ip (o il gruppo di ip) client per il quale è abilitato l&#39;inoltro ed eventualmente verso quale ip pubblico server, potendone scegliere diversi, effettuare l&#39;inoltro.&#xA;&#xA;Esempio DNAT generico:&#xA;inoltro di tutto il traffico proveniente da un ip fisso &#xA;verso un ip privato, con remapping delle porte.&#xA;firewall-cmd --permanent --policy=&#34;esterna-interna&#34; \&#xA;--add-rich-rule=&#39;rule family=&#34;ipv4&#34; \&#xA;  source address=&#34;93.12.34.56&#34; \&#xA;  forward-port port=&#34;5001-6000&#34; protocol=&#34;udp&#34; to-port=&#34;15001-16000&#34; to-addr=&#34;192.168.1.100&#34;&#39;&#xA;&#xA;stesso esempio di prima in cui il sorgente client è un gruppo &#xA;di ip (ipset) fissi &#xA;firewall-cmd --permanent --policy=&#34;esterna-interna&#34; \&#xA;--add-rich-rule=&#39;rule family=&#34;ipv4&#34; \&#xA;  source ipset=&#34;myipset&#34; \&#xA;  forward-port port=&#34;80&#34; protocol=&#34;tcp&#34; to-port=&#34;8080&#34; to-addr=&#34;192.168.1.100&#34;&#39;&#xA;&#xA;In questo caso suppongo che il fw esponga più indirizzi pubblici.&#xA;Solo un ip specifico può inoltrare il suo traffico &#xA;richiedendolo ad uno degli indirizzi pubblici del firewall&#xA;firewall-cmd --permanent --policy=&#34;esterna-interna&#34; \&#xA;--add-rich-rule=&#39;rule family=&#34;ipv4&#34; \&#xA;  source address=&#34;151.12.13.14&#34;    # ip client \&#xA;  destination address=&#34;9.10.20.31&#34; # ip pubblico fw \&#xA;  forward-port port=&#34;53947&#34; protocol=&#34;tcp&#34; to-port=&#34;3306&#34; to-addr=&#34;192.168.1.100&#34;&#39;&#xA;Esempio Masquerade:&#xA;firewall-cmd --permanent --zone=esterna --add-masquerade&#xA;Come nell&#39;esempio del port forwarding statico, il nat a livello di zona o di policy altera qualunque pacchetto che transita nella zona o nella policy.&#xA;&#xA;Anche qui, per avere un controllo migliore l&#39;approccio policy (o zona) + rich-rules risulta vincente.&#xA;In questo modo posso arrivare a scegliere quali dei server interni deve essere nattato ed eventualmente verso quali ip (snat condizionale).&#xA;nat di un singolo ip interno&#xA;firewall-cmd --permanent --policy=&#34;interna-esterna&#34; \&#xA;--add-rich-rule=&#39;rule family=&#34;ipv4&#34; \&#xA;  source address=192.168.10.10 masquerade&#39;&#xA;&#xA;nat di un gruppo di ip interni (ipset)&#xA;firewall-cmd --permanent --policy=&#34;interna-esterna&#34; \&#xA;--add-rich-rule=&#39;rule family=&#34;ipv4&#34; \&#xA;  source ipset=&#34;myipset&#34; masquerade&#39;&#xA;&#xA;nat di tutta la zona interna quando la destinazione è un ip &#xA;(o gruppo di ip) specifico&#xA;firewall-cmd --permanent --policy=&#34;interna-esterna&#34; \&#xA;--add-rich-rule=&#39;rule family=&#34;ipv4&#34; \&#xA;  destination ipset=&#34;myipset&#34; masquerade&#39;&#xA;&#xA;o, al contrario, si vuole nattare tutta la rete interna, o un&#xA;suo segmento, TRANNE il traffico destinato ad UN&#39;ALTRA rete&#xA;specifica (es. una vpn o altro).&#xA;firewall-cmd --permanent --policy=&#34;interna-esterna&#34; \&#xA;--add-rich-rule=&#39;rule family=&#34;ipv4&#34; \&#xA;  source address=&#34;myipset&#34;&#xA;  destination not address=&#34;10.4.10.0/24&#34; masquerade&#39;&#xA;&#xA;nat di un gruppo di ip solo per il servizio web&#xA;firewall-cmd --permanent --new-service=&#34;navigazioneweb&#34;&#xA;firewall-cmd --permanent --service=&#34;navigazioneweb&#34; \&#xA;  --add-include=&#34;http&#34; \&#xA;  --add-include=&#34;https&#34; \&#xA;  --add-include=&#34;dns&#34;&#xA;&#xA;firewall-cmd --permanent --policy=&#34;interna-esterna&#34; \&#xA;--add-rich-rule=&#39;rule family=&#34;ipv4&#34; \&#xA;  source ipset=&#34;myipset&#34; \&#xA;  service name=&#34;navigazioneweb&#34; masquerade&#39;&#xA;4.8. Zona&#xA;Per creare una zona basta assegnarle un nome e associarle una o più interfacce e/o una o più sorgente di indirizzi ip.&#xA;&#xA;Una zona senza alcun binding non è attiva.&#xA;firewall-cmd --permanent --new-zone=&#34;nomezona&#34;&#xA;&#xA;aggiunge un&#39;interfaccia&#xA;firewall-cmd --permanent --zone=&#34;nomezona&#34; [--add-interface=&#34;nomeinterfaccia&#34;]+&#xA;&#xA;aggiunge sorgenti&#xA;firewall-cmd --permanent --zone=&#34;nomezona&#34; [--add-source=subnet | ip | &#34;nomeipset&#34;]+&#xA;Se nella configurazione sono presenti sia l&#39;interfaccia che le sorgenti di ip, sto dichiarando che tutto ciò che transita per l&#39;interfaccia o che rientra nelle sorgenti indicate, ricadrà nelle regole della zona.&#xA;&#xA;Faccio notare che Il binding (sorgenti o interfacce) funziona in aggiunta, non restringe ciò che ad es. transita dall&#39;interfaccia.&#xA;Tenete bene a mente che nella gestione del routing dei pacchetti verso le zone che fa firewalld, vengono valutate prima le sorgenti e dopo l&#39;interfaccia.&#xA;&#xA;Se avessi l&#39;esigenza di restringere il traffico nella zona, si potrebbe pensare di limitare il binding alle sole sorgenti, escludendo l&#39;interfaccia, in modo che qualunque pacchetto che non provenga dagli ip o dalle subnet, a prescindere dall&#39;interfaccia, indicate venga respinto (in base alla politica della zona).&#xA;&#xA;Va tenuto presente che configurazioni di questo tipo, per quanto pulite e semplici da realizzare, possono dare luogo ad errori estremamente subdoli e pericolosissimi (vedremo un esempio in seguito).&#xA;&#xA;Tutti i pacchetti che, transitando per l&#39;host, non vengono assorbiti da alcuna zona, saranno gestiti dalla zona di default.&#xA;&#xA;Di seguito una lista di comandi utili:&#xA;restituisce la zona di default&#xA;firewall-cmd --get-default-zone&#xA;&#xA;setta la zona di default&#xA;firewall-cmd --set-default-zone=&#34;nomezona&#34;&#xA;&#xA;restituisce tutte le zone attive (tutte quelle con un binding ad un&#39;interfaccia e/o ad un sorgente)&#xA;firewall-cmd --get-active-zones&#xA;&#xA;restituisce tutte le zone accoppiate ad una specifica interfaccia/sorgente&#xA;firewall-cmd --permanent --get-zone-of-interface=&#34;nomeinterfaccia&#34;&#xA;firewall-cmd --permanent --get-zone-of-source=subnet | ip | &#34;nomeipset&#34;&#xA;&#xA;restituisce info dettagliate sulla zone&#xA;firewall-cmd --permanent --info-zone=&#34;nomezona&#34;&#xA;&#xA;elenca tutte le zone&#xA;firewall-cmd --permanent --list-all-zones&#xA;&#xA;cancella una zona&#xA;firewall-cmd --permanent --delete-zone=&#34;nomezona&#34;&#xA;&#xA;###########&#xA;Servizi &#xA;###########&#xA;aggiungi / cancella servizi da una zona o dalla zona attiva (se il nome zona non è specificato)&#xA;firewall-cmd --permanent --zone=&#34;nomezona&#34; [--add-service=&#34;nomeservizio&#34;]+&#xA;firewall-cmd --permanent --zone=&#34;nomezona&#34; [--remove-service=&#34;nomeservizio&#34;]+&#xA;&#xA;######################&#xA;porte e protocolli &#xA;######################&#xA;elencare tutte le porte e i protocolli della zona&#xA;firewall-cmd --permanent --zone=&#34;nomezona&#34; --list-ports&#xA;firewall-cmd --permanent --zone=&#34;nomezona&#34; --list-protocols&#xA;&#xA;aggiungere/cancellare una porta alla zona&#xA;firewall-cmd --permanent --zone=&#34;nomezona&#34; [--add-port=port/tcp | udp | sctp | dccp]+&#xA;firewall-cmd --permanent --zone=&#34;nomezona&#34; [--remove-port=port/tcp | udp | sctp | dccp]+&#xA;&#xA;aggiungere/cancellare un protocollo alla zona&#xA;firewall-cmd --permanent --zone=&#34;nomezona&#34; --add-protocol=protocol&#xA;firewall-cmd --permanent --zone=&#34;nomezona&#34; --remove-protocol=protocol&#xA;&#xA;##############&#xA;Rich-rules &#xA;##############&#xA;aggiungere/cancellare un protocollo alla zona&#xA;firewall-cmd --permanent --zone=&#34;nomezona&#34; --add-rich-rule=&#34;nomerich-rule&#34;&#xA;firewall-cmd --permanent --zone=&#34;nomezona&#34; --remove-rich-rule=&#34;nomerich-rule&#34;&#xA;&#xA;#############&#xA;ICMP Type &#xA;#############&#xA;inverte / disattiva la logica del blocco icmp nella zona (attiva / disattiva whitelist)&#xA;firewall-cmd --permanent --zone=&#34;nomezona&#34; --add-imcp-block-inversion&#xA;firewall-cmd --permanent --zone=&#34;nomezona&#34; --remove-imcp-block-inversion&#xA;&#xA;aggiunge un tipo icmp alla whitelist/blacklist&#xA;firewall-cmd --permanent --zone=&#34;nomezona&#34; [--add-imcp-block=&#34;tipoicmp&#34;]+&#xA;&#xA;rimuove un tipo icmp dalla whitelist/blacklist&#xA;firewall-cmd --permanent --zone=&#34;nomezona&#34; [--remove-imcp-block=&#34;tipoicmp&#34;]+&#xA;&#xA;##############&#xA;Masquerade &#xA;##############&#xA;aggiunge / rimuove il masquerade&#xA;firewall-cmd --permanent --zone=&#34;nomezona&#34; --add-masquerade&#xA;firewall-cmd --permanent --zone=&#34;nomezona&#34; --remove-masquerade&#xA;&#xA;###########################&#xA;Port forwarding statico &#xA;###########################&#xA;aggiunge / rimuove il port forwarding&#xA;firewall-cmd --permanent --zone=&#34;nomezona&#34; --add-forward-port=port=port-port]:proto=[tcp|udp|sctp|dccp]:to-port=port[-port&#xA;firewall-cmd --permanent --zone=&#34;nomezona&#34; --remove-forward-port=port=port-port]:proto=[tcp|udp|sctp|dccp]:to-port=port[-port&#xA;&#xA;es. di inoltro veerso un ip interno di un range di porte con offset deterministico&#xA;firewall-cmd --permanent --zone=&#34;esterna&#34; --add-forward-port=port=2501-3000:proto=tcp:to-port=5001-5500:to-addr=192.168.10.20&#xA;firewall-cmd --permanent --zone=&#34;esterna&#34; --remove-forward-port=port=2501-3000:proto=tcp:to-port=5001-5500:to-addr=192.168.10.20&#xA;(rif. man zone)&#xA;4.9. Policy Objects&#xA;I policy objects, presenti dall&#39;ormai lontano 2020 con la versione 0.9.0, hanno posto le basi per il futuro di firewalld. È il posto in cui si concentrano le policy di filtraggio sia per il traffico intra-zona che, soprattutto, per il traffico inter-zona.&#xA;&#xA;I policy objects cambiano radicalmente il disegno delle regole che, come detto in precedenza, vengono disaccoppiate dalla dichiarazione della zona che rimane il luogo in cui viene effettuato principalmente il trust delle sorgenti.&#xA;&#xA;Conseguenza immediata è una notevole flessibilità perché ho la possibilità di variare dinamicamente le regole da applicare alle zone semplicemente aggiungendo le policy opportune.&#xA;&#xA;Lavorare sulle zone è più immediato ma più lo scenario diventa articolato, più le configurazioni si complicano, oltre al fatto che alcune cose come il routing e l&#39;inoltro, con le sole zone non sono proprio realizzabili&#xA;&#xA;Le policy, al contrario, richiedono una maggiore complessità iniziale ma ha il vantaggio di mantenere il disegno generale più pulito nei casi in cui le configurazioni cambino con una certa frequenza o tendano a diventare via via più articolate.&#xA;&#xA;Nel seguito mostrerò degli esempi di configurazioni  fatte in modalità zone-oriented e policy-oriented.&#xA;&#xA;Gli elementi costitutivi del policy object sono il nome, il target policy (di base, &#34;default&#34;), la specifica della direzione del traffico, uno o più servizi da abilitare.&#xA;firewall-cmd --permanent --new-policy=&#34;nomepolicy&#34;&#xA;firewall-cmd --permanent --policy=&#34;nomepolicy&#34; --set-target=DROP | REJECT | ACCEPT | CONTINUE&#xA;&#xA;definizione della direzione del traffico&#xA;firewall-cmd --permanent --policy=&#34;nomepolicy&#34; [--add-ingress-zone=HOST | &#34;nomezona&#34; | ANY]+&#xA;firewall-cmd --permanent --policy=&#34;nomepolicy&#34; [--add-egress-zone=HOST | &#34;nomezona&#34; | ANY]+&#xA;&#xA;traffico consentito&#xA;firewall-cmd per --permanent --policy=&#34;nomepolicy&#34; [--add-service=&#34;nomeservizio&#34;]+&#xA;Di seguito, una lista di comandi utili:&#xA;elenco, sintetico o dettagliato, di tutti i policy objects&#xA;firewall-cmd --get-policies&#xA;firewall-cmd --permanent --list-all-policies&#xA;&#xA;estrae tutti i componenti della policy&#xA;firewall-cmd --permanent --policy=&#34;nomepolicy&#34; --list-all&#xA;&#xA;restituisce le ingress / egress zone&#xA;firewall-cmd --permanent --policy=&#34;nomepolicy&#34; --list-egress-zones&#xA;firewall-cmd --permanent --policy=&#34;nomepolicy&#34; --list-ingress-zones&#xA;&#xA;restituisce i servizi&#xA;firewall-cmd --permanent --policy=&#34;nomepolicy&#34; --list-services&#xA;&#xA;restituisce le rich-rules&#xA;firewall-cmd --permanent --policy=&#34;nomepolicy&#34; --list-rich-rules&#xA;&#xA;info di un policy object&#xA;firewall-cmd --permanent --info-policy=&#34;nomepolicy&#34;&#xA;&#xA;cambiare target di un policy object&#xA;firewall-cmd --permanent --policy=&#34;nomepolicy&#34; --set-target=DROP | REJECT | ACCEPT | CONTINUE&#xA;&#xA;eliminare un policy object&#xA;firewall-cmd --permanent --delete-policy=&#34;nomepolicy&#34;&#xA;&#xA;###########&#xA;Servizi &#xA;###########&#xA;aggiungi / cancella servizi dal policy object specificato&#xA;firewall-cmd --permanent --policy=&#34;nomepolicy&#34; [--add-service=&#34;nomeservizio&#34;]+&#xA;firewall-cmd --permanent --policy=&#34;nomepolicy&#34; [--remove-service=&#34;nomeservizio&#34;]+&#xA;&#xA;######################&#xA;Porte e protocolli &#xA;######################&#xA;elencare tutte le porte e i protocolli del policy object specificato&#xA;firewall-cmd --permanent --policy=&#34;nomepolicy&#34; --list-ports&#xA;firewall-cmd --permanent --policy=&#34;nomepolicy&#34; --list-protocols&#xA;&#xA;aggiungere/cancellare una porta dal policy object specificato&#xA;firewall-cmd --permanent --policy=&#34;nomepolicy&#34; [--add-port=port/tcp | udp | sctp | dccp]+&#xA;firewall-cmd --permanent --policy=&#34;nomepolicy&#34; [--remove-port=port/tcp | udp | sctp | dccp]+&#xA;&#xA;aggiungere/cancellare un protocollo dal policy object specificato&#xA;firewall-cmd --permanent --policy=&#34;nomepolicy&#34; --add-protocol=[tcp | udp | sctp | dccp]&#xA;firewall-cmd --permanent --policy=&#34;nomepolicy&#34; --remove-protocol=[tcp | udp | sctp | dccp]&#xA;&#xA;##############&#xA;Rich-rules &#xA;##############&#xA;aggiungere/cancellare una (o più) rich-rule dal policy object specificato&#xA;firewall-cmd --permanent --policy=&#34;nomepolicy&#34; [--add-rich-rule=&#34;nomerich-rule&#34;]+&#xA;firewall-cmd --permanent --policy=&#34;nomepolicy&#34; [--remove-rich-rule=&#34;nomerich-rule&#34;]+&#xA;&#xA;##############&#xA;ICMP Types &#xA;##############&#xA;Aggiunge un tipo icmp alla whitelist/blacklist&#xA;firewall-cmd --permanent --policy=&#34;nomepolicy&#34; [--add-imcp-block=&#34;tipoicmp&#34;]+&#xA;&#xA;Rimuove un tipo icmp dalla whitelist/blacklist&#xA;firewall-cmd --permanent --policy=&#34;nomepolicy&#34; [--remove-imcp-block=&#34;tipoicmp&#34;]+&#xA;&#xA;##############&#xA;Masquerade &#xA;##############&#xA;aggiunge / rimuove il masquerade&#xA;firewall-cmd --permanent --policy=&#34;nomepolicy&#34; --add-masquerade&#xA;firewall-cmd --permanent --policy=&#34;nomepolicy&#34; --remove-masquerade&#xA;&#xA;###########################&#xA;Port forwarding statico &#xA;###########################&#xA;aggiunge / rimuove il port forwarding&#xA;firewall-cmd --permanent --policy=&#34;nomepolicy&#34; --add-forward-port=port=port-port]:proto=[tcp | udp | sctp | dccp]:to-port=port[-port&#xA;firewall-cmd --permanent --policy=&#34;nome_policy&#34; --remove-forward-port=port=port-port]:proto=[tcp | udp | sctp | dccp]:to-port=port[-port&#xA;&#xA;es. di inoltro veerso un ip interno di un range di porte con offset deterministico&#xA;firewall-cmd --permanent --policy=&#34;wan-to-lan&#34; --add-forward-port=port=2501-3000:proto=tcp:to-port=5001-5500:to-addr=192.168.10.20&#xA;firewall-cmd --permanent --zone=&#34;wan-to-lan&#34; --remove-forward-port=port=2501-3000:proto=tcp:to-port=5001-5500:to-addr=192.168.10.20&#xA;(rif. man policy, man policies)&#xA;4.10. Comandi di utilità generale&#xA;Di seguito, un elenco dei comandi di utilità generale disponibili per firewalld:&#xA;Restituisce lo stato di firewalld&#xA;firewall-cmd --state&#xA;&#xA;Riavvia firewalld&#xA;firewall-cmd --reload&#xA;&#xA;Riavvia firewalld ricaricando anche i moduli netfilter del kernel&#xA;firewall-cmd --complete-reload&#xA;&#xA;Restituisce il log level di firewalld&#xA;firewall-cmd --get-log-denied&#xA;&#xA;Imposta il log level di firewalld&#xA;firewall-cmd --set-log-denied=all | unicast | broadcast | multicast | off&#xA;&#xA;Rende permanente tutte le configurazioni effimere di firewalld. Necessario il reload.&#xA;firewall-cmd --runtime-to-permanent&#xA;&#xA;Kill switch ON /OFF&#xA;firewalld --panic-on&#xA;firewalld --panic-off&#xA;&#xA;Stato Kill switch [0 | 1]&#xA;firewalld --query-panic&#xA;&#xA;#firewall #firewallcmd #firewalld #iptables #netfilter  #nftables #ufw]]&gt;</description>
      <content:encoded><![CDATA[<p><img src="https://pixelfed.uno/storage/m/_v2/489827599091373610/b5862bd14-4506fa/gBxZ8Bb3JsyX/aoPYucfwCvDfgYXOXGHOkG7aqrFBwjspQetNhz0S.jpg" alt="tux-firewalld"></p>

<hr>

<p><strong>N.B. Sono stato costretto a spezzare l&#39;articolo perché, quello originale di 8836 parole (per un totale di 76309 bytes effettivi), veniva troncato dopo il salvataggio a 7533 parole (65.356 bytes), cosa che mi fa sospettare che la grandezza del body non possa superare i 64k.</strong></p>

<hr>

<p><strong>firewalld</strong> fornisce funzionalità firewall fungendo da frontend per <strong>netfilter</strong>.</p>

<p>Nell&#39;interagire con netfilter, analogamente a <strong>ufw</strong> con <strong>iptables</strong>, firewalld usa come backend <strong>nftables</strong>, un tool nella user-space del kernel linux, che va a sostituire proprio <strong>iptables</strong>. Entrambi i backend forniscono filtraggio e classificazione dei pacchetti di rete /datagrammi/frame.
</p>
<ul><li><a href="#1-come-ragiona-firewalld" rel="nofollow">1. Come ragiona firewalld</a></li>
<li><a href="#2-come-procedo-nella-configurazione-di-firewalld" rel="nofollow">2. Come procedo nella configurazione di Firewalld?</a></li>
<li><a href="#3-il-man-di-firewall-cmd" rel="nofollow">3. Il man di firewall-cmd</a></li>
<li><a href="#4-come-configurare-firewalld" rel="nofollow">4. Come configurare firewalld</a>
<ul><li><a href="#4-1-helpers" rel="nofollow">4.1. Helpers</a></li>
<li><a href="#4-2-servizi" rel="nofollow">4.2. Servizi</a></li>
<li><a href="#4-3-gestione-icmp" rel="nofollow">4.3. Gestione ICMP</a></li>
<li><a href="#4-4-porte-e-protocolli" rel="nofollow">4.4. Porte e protocolli</a></li>
<li><a href="#4-5-ipset" rel="nofollow">4.5. IPset</a></li>
<li><a href="#4-6-rich-rules" rel="nofollow">4.6. Rich-Rules</a></li>
<li><a href="#4-7-forwarding-e-masquerade" rel="nofollow">4.7. Forwarding e Masquerade</a></li>
<li><a href="#4-8-zona" rel="nofollow">4.8. Zona</a></li>
<li><a href="#4-9-policy-objects" rel="nofollow">4.9. Policy Objects</a></li>
<li><a href="#4-10-comandi-di-utilit%C3%A0-generale" rel="nofollow">4.10. Comandi di utilità generale</a></li></ul></li></ul>

<p>Attualmente ufw usa ancora iptables ma in modalità legacy, consistente in uno strato software che traduce i comandi iptables nei corrispondenti comandi nftables.</p>

<p>Firewalld supporta le zone di rete/firewall che definiscono il livello di fiducia delle connessioni o delle interfacce di rete.</p>

<p>C&#39;è una separazione fra runtime e configurazione permanente che consente di testare una configurazione prima di renderla effettiva.</p>

<p>firewalld, con nftables, è certamente il frontend ideale per netfilter dal momento che recepisce tutte le sue innovazioni. La possibilità di usare, nella stessa cli, filtraggio, routing, snat e dnat per es. rende l&#39;esperienza certamente più omogenea (con ufw, masquerade e port-forwarding richiedono una gestione aggiuntiva direttamente con iptables per ora).</p>

<p>Sebbene destinato ad essere rimpiazzato, iptables continua ad avere una sua specificità visto che viene ancora usato da docker per agire direttamente su netfilter bypassando eventuali firewall locali quano deve esporre una porta.</p>

<p>Con l&#39;attuale versione di docker, la 29, è stato introdotto il supporto diretto su nftables in via sperimentale.</p>

<p>Ad ogni modo, chi approccia per la prima volta a <strong>firewalld</strong> (come è successo a me) all&#39;inizio può essere sopraffatto dall&#39;allegro affollamento di opzioni a disposizione.</p>
<ul><li>zone</li>
<li>porte</li>
<li>protocolli</li>
<li>servizi</li>
<li>policy objects</li>
<li>rich-rules</li>
<li>port forwarding</li>
<li>masquerade</li>
<li>ipset</li>
<li>helper</li>
<li>....</li></ul>

<p>La gui (<strong>firewall-config</strong>) mette certamente ordine ma non aiuta fino in fondo. Oltre a questo la gui non racchiude tutta la logica della cli (ad es. mancano i policy objects).</p>

<p>La cli di firewalld è il riferimento e come tutte le cli, può spaventare.</p>

<p>In realtà la cli, <strong>firewall-cmd</strong> nello specifico, è una delle più pulite e lineari che conosca, basta conoscere gli la logica a oggetti che governa firewalld.</p>

<h2 id="1-come-ragiona-firewalld">1. Come ragiona firewalld</h2>

<p>Se guardassi firewalld dall&#39;alto, riconoscerei 7 oggetti principali:</p>
<ul><li>Zone</li>
<li>Policy Objects</li>
<li>Services</li>
<li>IPSet</li>
<li>ICMP Types</li>
<li>Helper</li>
<li>Direct Options (Deprecato)</li></ul>

<p><strong>Zone</strong>: è un po&#39; il tratto distintivo di firewalld. Concettualmente rappresenta il livello di fiducia che si ha nei confronti di una rete connessa a una specifica interfaccia (es. eth0) o di un indirizzo IP. Ogni pacchetto dati che <strong>entra</strong> nel server viene catturato da una zona in base alla sua sorgente o all&#39;interfaccia da cui arriva. È qui che avviene la configurazione del traffico in ingresso.</p>

<p><strong>Policy Objects</strong>: è una delle novità di firewalld. I policy object nascono per gestire il traffico inter-zona. Inizialmente il filtraggio avveniva <strong>all&#39;interno</strong> dell&#39;oggetto (la zona) che accoglie il pacchetto, ora viene disaccoppiato e trasferito in un altro oggetto che <strong>gestisce il transito</strong> dei pacchetti tra una zona e l&#39;altra (o se stessa).
In questo modo cambia profondamente il paradigma di manipolazione dei pacchetti. La zona attiva il filtraggio quando <strong>il pacchetto entra</strong> da una delle sorgenti associate alla zone. La policy, attiva il filtraggio quando <strong>il pacchetto transita</strong> tra le zone specifiche definite dalla policy.</p>

<p><strong>Services</strong>: rappresenta ciò che esponiamo (o che dobbiamo raggiungere, se filtriamo il traffico in uscita dal nostro host quando si comporta da client).</p>

<p>L&#39;<strong>IPSet</strong>: permette di definire dei blocchi di ip a cui applicare regole massivamente invece che definirle puntalmente.</p>

<p><strong>ICMP Types</strong>: è relativo ai pacchetti ICMP e permette di rendere disponibile il pacchetto scelto al traffico di tipo ipv4 e/o ipv6</p>

<p><strong>Helper</strong>: torna comodo invece per quei protocolli che aprono una connessione su una porta e poi negoziano dinamicamente <strong>un&#39;altra porta</strong> per il trasferimento dei dati (es. ftp, netbios-ns, sip, vecchi protocolli di gaming/streaming ecc.). Invece che aprire un intervallo ampio di porte, l&#39;helper, che è un modulo del kernel, “ascolta” il flusso di controllo, capisce quale porta casuale sta per essere usata e la apre temporaneamente al volo solo per quel trasferimento.</p>

<p><strong>Direct Options</strong>: le direct options (ormai deprecate e sostituite dai policy objects) sono la parte legacy di firewalld attraverso cui parla con <strong>iptables</strong> invece che con <strong>nftables</strong>.</p>

<p>Questi sono gli oggetti principali su cui si costruiscono le regole per il firewall attraverso una sintassi molto corposa ma ragionata e lineare.</p>

<p>La cli mette a disposizione delle istruzioni per fare praticamente qualunque cosa:</p>
<ul><li>visualizzare lo stato del firewall;</li>
<li>istanziare gli oggetti;</li>
<li>combinare gli oggetti istanziati al fine di creare la nostra logica di firewalling;</li>
<li>effettuare delle query di verifica esistenziale sugli oggetti;</li>
<li>effettuare il binding delle zone con interfacce o sorgenti;</li></ul>

<p>Da tenere presente che la configurazione di firewalld, come iptables, può essere <strong>effimera</strong>. Se la configurazione a caldo non viene resa “permanente”, produce effetti fino a quando il servizio viene riavviato. Quando avviene, lo stato di firewalld ritorna ad essere quello che era prima delle modifiche.</p>

<h2 id="2-come-procedo-nella-configurazione-di-firewalld">2. Come procedo nella configurazione di Firewalld?</h2>

<p>Come abbiamo visto, firewalld ha una logica di funzionamento molto più versatile di iptables, decisamente più rigido al confronto.
Questa versatilità però può portare a rendere gli scenari più caotici potendo mescolare diverse tecniche di filtraggio.
Come dire, il solito problema della scelta quando ce n&#39;è troppa.</p>

<p>My two cents:</p>
<ol><li>Se l&#39;esigenza è quella di configurare un firewall personale, è sufficiente configurare opportunamente zone e servizi.</li>
<li>Se bisogna tenere in considerazione traffico inter-zona (in presenza di più interfacce per es.) ci vengono in aiuto i policy objects.</li>
<li>Se abbiamo ulteriori esigenze di granularità, la zona permette di definire delle rich-rules.</li></ol>

<p>Un canovaccio del genere aiuta a mantenere la configurazione pulita, altrimenti potrei sporcarla in mille modi differenti rendendo però complicata la manutenzione futura.</p>

<p>Cercando di mettere a fattor comune quello che faccio con firewall-cmd la maggior parte delle volte, se volessi configurare un firewall personale secondo il canovaccio di cui sopra, i passi da fare sono i seguenti:</p>
<ol><li>creo la zona</li>
<li>se non sono presenti nel default perché magari le porte dei servizi sono custom, creo anche i servizi (descrizione, porta/e e protocollo/i)</li>
<li>nella configurazione della zona, faccio il binding con l&#39;interfaccia e con i servizi (eventualmente custom) che ho definito.</li></ol>

<p>Stop.</p>

<p>Non occorre altro.</p>

<p>Ma firewalld permette anche configurazioni molto più borderline.</p>

<p>Nella mia zona potrei non avere alcun oggetto di tipo servizio ma potrei semplicemente assegnare direttamente una sbrodolata di porte e protocolli.</p>

<p>Oppure potrei lavorare direttamente con le rich-rules (approccio simil-ufw).</p>

<p>Oppure potrei affidare la logica direttamente ai policy objects.</p>

<p>Personalmente, tutte queste alternative (a parte l&#39;ultima) le vedo più come un esercizio accademico senza una reale utilità pratica perché in scenari complessi questi approcci possono dar luogo a configurazioni estremamente caoitche.</p>

<h2 id="3-il-man-di-firewall-cmd">3. Il man di firewall-cmd</h2>

<p>Il man di firewall-cmd è molto chiaro e lineare e sarebbe bene tenerlo presente quando ci si lavora per le prime volte.</p>

<p>È strutturato in 3 grossi blocchi:</p>

<p><strong>Sezioni di carattere generale. Stato firewall, verbosity log, salvataggio configurazioni, ecc</strong></p>
<ul><li>General Options</li>
<li>Status Options</li>
<li>Log Denied Options</li>
<li>Permanent Options</li>
<li>Panic Options</li></ul>

<p><strong>Sezioni per la configurazione delle componenti core. Zone , Policy Objects, IPSet, Service, ecc.</strong></p>
<ul><li>Zone Options</li>
<li>Policy Options</li>
<li>IPSet Options</li>
<li>Service Options</li>
<li>Helper Options</li>
<li>ICMP type Options</li>
<li>Direct Options (deprecato)</li></ul>

<p><strong>Sezioni per l&#39;interrogazione e la configurazione delle combinazioni fra zone, policy objects, interfacce e sorgenti</strong></p>
<ul><li>Options to Adapt and Query Zones and Policies</li>
<li>Options to Adapt and Query Zones</li>
<li>Options to Adapt and Query Policies</li>
<li>Options to Handle Bindings of Interfaces</li>
<li>Options to Handle Bindings of Sources</li></ul>

<h2 id="4-come-configurare-firewalld">4. Come configurare firewalld</h2>

<p>Come anticipato, la configurazione della zona con associati servizi, interfaccia e sorgenti, è tutto ciò che serve.</p>

<p>Se le mie policy sono complesse e ho necessità di centralizzarle, posso usare i <strong>policy objects</strong>.</p>

<p>Se si deve intervenire chirurgicamente per impedire o abilitare del traffico, ci sono le <strong>rich-rules</strong>.</p>

<p>In sostanza, tutto ruota attorno a due grossi item, le <strong>zone</strong> e i <strong>policy objects</strong>, che, forse in maniera un po&#39; ridondante, combinano una serie di componenti che concorrono a formare la logica di firewalling.</p>

<p>Per entrare nel merito della configurazione partirò da quelle che per me sono le “foglie” di un ipotetico albero che, attraverso una serie di inclusioni, termina con 2 grosse radici: zone o police objects.</p>

<p>Fra gli elementi terminali nella gerarchia di firewalld, per me, ci sono gli <strong>helpers</strong> che poi concorrono a formare i <strong>servizi</strong> che insieme a <strong>porte e protocolli</strong>, <strong>IPset</strong>, <strong>forwarding</strong>, <strong>masquerade</strong> finiranno in <strong>zone</strong>, <strong>policy objects</strong> e <strong>rich-rules</strong>.</p>

<h3 id="4-1-helpers">4.1. Helpers</h3>

<p>Gli <strong>helpers</strong> sono degli oggetti basati sul modulo <strong>nf_conntrack</strong> del kernel Netfilter, che permettono di tracciare le connessioni, per la precisione sono delle interfacce che permettono a firewalld di caricare e configurare il relativo modulo <strong>nf_conntrack</strong> del kernel.</p>

<p>Ci sono protocolli come ftp, tftp, alcuni protocolli di gaming, voip ecc. che, oltre che esporre la porta per essere contattati, in un secondo momento devono negoziare dinamicamente con il client un&#39;altra porta per lo scambio dei dati.</p>

<p>Questo tipo di servizi non è facilmente controllabile senza gli helpers perché la negoziazione dinamica imporrebbe di aprire un set molto ampio di porte.</p>

<p>Con gli helpers le connessioni di questi servizi “anomali” verranno tracciate in modo che, quando dal cliente arriva un pacchetto che richiede l&#39;apertura di una porta random per lo scambio dati, quella connessione verrà marchiata come <strong>RELATED</strong>, che come tutto il traffico <strong>RELATED</strong> viene accettata nativamente, invece che come <strong>NEW</strong> che sarebbe destinata ad essere scartata.</p>

<p>Gli helpers, lista dei quali disponibile con:</p>

<pre><code class="language-bash">firewall-cmd --get-helpers
</code></pre>

<p>corrispondono all&#39;incirca ai moduli <strong>nf_conntrack</strong> presenti nel kernel Netfilter e si trovano in <code>/lib/modules/$(uname -r)/kernel/net/netfilter</code>.</p>

<p>Andranno aggiunti ai servizi, qualora servissero, in modo che firewalld accetti, e solo per quei servizi, connessioni da porte dinamiche.</p>

<p><strong>Un po&#39; di storia</strong>
In passato, il kernel linux abilitava (con qualcosa tipo <code>nf_conntrack_helper=1</code>) gli helpers per default su tutto il traffico favorendo attacchi basati sullo spoofing dei pacchetti con cui farsi aprire porte a caso.</p>

<p>Poi quest&#39;opzione è stata prima disabilitata di defautl con <code>nf_conntrack_helper=0</code> permettendo un&#39;attivazione prudente solo da file di configurazione con <code>AutomaticHelpers=yes/no/system</code>, poi è stata definitivamente rimossa sia dal kernel che dal file di configurazione.</p>

<p>Oggi, per attivare gli helper, basta dichiararli e associarli ad un servizio. Firewalld provvederà a caricare dinamicamente solo i moduli del kernel Netfilter necessari gestendo sia la porta dalla quale il servizio verrà contattato sia le porte dinamiche che verranno negoziate per lo scambio dei dati.</p>

<pre><code class="language-bash"># restituisce tutte le informazioni di un helper
firewall-cmd --permanent --info-helper=&#34;&lt;nome_helper&gt;&#34;

# dichiaro un nuovo helper
firewall-cmd --permanent --new-helper=&#34;&lt;nome_helper&gt;&#34; --module=nf_conntrack_&lt;nome_modulo&gt;

# restituisce tutti gli helper presenti
firewall-cmd --permanent --get-helpers

# imposta / restituisce una descrizione
firewall-cmd --permanent --helper=&#34;&lt;nome_helper&gt;&#34; --set-description=&#34;&lt;descrizione&gt;&#34;
firewall-cmd --permanent --helper=&#34;&lt;nome_helper&gt;&#34; --get-description

# imposta / restituisce una descrizione breve
firewall-cmd --permanent --helper=&#34;&lt;nome_helper&gt;&#34; --set-short=&#34;&lt;descrizione&gt;&#34;
firewall-cmd --permanent --helper=&#34;&lt;nome_helper&gt;&#34; --get-short

# aggiunge/rimuove la porta o il range di porte dall&#39;helper
firewall-cmd --permanent --helper=&#34;&lt;nome_helper&gt;&#34; --add-port=&lt;port&gt;[-&lt;port&gt;]/&lt;protocol&gt;
firewall-cmd --permanent --helper=&#34;&lt;nome_helper&gt;&#34; --remove-port=&lt;port&gt;[-&lt;port&gt;]/&lt;protocol&gt;

# restituisce tutte le porte associate all&#39;helper
firewall-cmd --permanent --helper=&#34;&lt;nome_helper&gt;&#34; --get-ports

# imposta / restituisce un modulo per l&#39;helper
firewall-cmd --permanent --helper=&#34;&lt;nome_helper&gt;&#34; --set-module=nf_conntrack_&lt;nome_modulo&gt;
firewall-cmd --permanent --helper=&#34;&lt;nome_helper&gt;&#34; --get-module

# rimuove un helper da sistema
--permanent --delete-helper=&#34;&lt;nome_helper&gt;&#34;
</code></pre>

<h3 id="4-2-servizi">4.2. Servizi</h3>

<p>Per creare un servizio, si assegna un nome e un insieme di porte e protocolli.</p>

<pre><code class="language-bash">firewall-cmd --permanent --new-service=&#34;&lt;nome_servizio&gt;&#34;
firewall-cmd --permanent --service=&#34;&lt;nome_servizio&gt;&#34; --set-description=&#34;Descrizione del servizio&#34;
firewall-cmd --permanent --service=&#34;&lt;nome_servizio&gt;&#34; [--add-port=&lt;port&gt;/tcp | udp | sctp | dccp]+
</code></pre>

<p>Di seguito una lista di comandi utili:</p>

<pre><code class="language-bash"># elenco di tutti i servizi
firewall-cmd --get-services
# elenco dei servizi della zona attiva
firewall-cmd --list-services
# elenco dei servizi di una determinata zona
firewall-cmd --permanent --zone=&#34;&lt;nome_zona&gt;&#34; --list-services
# restituisce le info di un servizio
firewall-cmd --permanent --info-service=&#34;&lt;nome_servizio&gt;&#34;

# imposta / restituisce una descrizione
firewall-cmd --permanent --service=&#34;&lt;nome_servizio&gt;&#34; --get-description
firewall-cmd --permanent --service=&#34;&lt;nome_servizio&gt;&#34; --set-description=&#34;&lt;descrizione&gt;&#34;

# imposta / restituisce una descrizione breve
firewall-cmd --permanent --service=&#34;&lt;nome_servizio&gt;&#34; --get-short-description
firewall-cmd --permanent --service=&#34;&lt;nome_servizio&gt;&#34; --set-short-description=&#34;&lt;descrizione&gt;&#34;

# restituisce tutte le porte del servizio
firewall-cmd --permanent --service=&#34;&lt;nome_servizio&gt;&#34; --get-ports

# imposta / restituisce un (o più) protocollo di un servizio
firewall-cmd --permanent --service=&#34;&lt;nome_servizio&gt;&#34; --get-protocols
firewall-cmd --permanent --service=&#34;&lt;nome_servizio&gt;&#34; [--add-protocol=tcp | udp | sctp | dccp]+

# rimozione (porta, protocollo) / protocollo
firewall-cmd --permanent --service=&#34;&lt;nome_servizio&gt;&#34; [--remove-port=&lt;port&gt;/tcp | udp | sctp | dccp]+
firewall-cmd --permanent --service=&#34;&lt;nome_servizio&gt;&#34; [--remove-protocol=tcp | udp | sctp | dccp]+

# aggiunge / rimuove un helper da un servizio
firewall-cmd --permanent --service=&#34;&lt;nome_servizio&gt;&#34; --add-helper=&#34;&lt;nome_helper&gt;&#34;
firewall-cmd --permanent --service=&#34;&lt;nome_servizio&gt;&#34; --remove-helper=&#34;&lt;nome_helper&gt;&#34;

# restituisce gli helper collegati al servizio
firewall-cmd --permanent --service=&#34;&lt;nome_servizio&gt;&#34; --get-service-helpers

# elimina un servizio
firewall-cmd --permanent --delete-service==&#34;&lt;nome_servizio&gt;&#34;
</code></pre>

<p>(rif. <a href="https://firewalld.org/documentation/man-pages/firewalld.service.html" rel="nofollow">man service</a>)</p>

<h3 id="4-3-gestione-icmp">4.3. Gestione ICMP</h3>

<p>Il traffico ICMP viene impostato a livello di zona o a livello di policy object.</p>

<p>Al solito, agire a livello di zona è più semplice, usare i policy objects permette di guadagnare in modularità e scalabilità.</p>

<p>Di default, ICMP lavora su <strong>blacklist</strong>. È tutto consentito tranne ciò che viene esplicitamente vietato con le istruzioni <code>--add-icmp-block</code> per aggiungere il tipo icmp che si vuole bloccare o <code>--remove-icmp-block</code> per rimuovere il blocco.</p>

<p>È possibile invertire la logica di funzionamento, a livello globale o di singola zona, passando ad una <strong>whitelist</strong>. È tutto vietato tranne cio che è consentito con <code>--add-icmp-block</code> (un po&#39; fuorviante, ne convengo). <code>--remove-icmp-block</code> rimuove il consenso.</p>

<p>Di seguito, un elenco dei comandi di utilità disponibili per gli icmptype:</p>

<pre><code class="language-bash"># Elenca tutti gli icmptype
firewall-cmd --get-icmptypes

# inverte / disattiva globalmente la logica del blocco icmp (attiva / disattiva whitelist)
firewall-cmd --permanent --add-icmp-block-inversion
firewall-cmd --permanent --remove-icmp-block-inversion

# Creazione e cancellazione di un icmptype
firewall-cmd  --permanent --new-icmptype=&#34;&lt;nome icmptype&gt;&#34;
firewall-cmd  --permanent --delete-icmptype=&#34;&lt;nome icmptype&gt;&#34;

# imposta / restituisce la descrizione di un icmptype
firewall-cmd  --permanent --icmptype=&#34;&lt;nome icmptype&gt;&#34; --set-description=&#34;&lt;descrizione&gt;&#34;
firewall-cmd  --permanent --icmptype=&#34;&lt;nome icmptype&gt;&#34; --get-description

# imposta / restituisce la descrizione breve di un icmptype
firewall-cmd  --permanent --icmptype=&#34;&lt;nome icmptype&gt;&#34; --set-short=&#34;&lt;descrizione&gt;&#34;
firewall-cmd  --permanent --icmptype=&#34;&lt;nome icmptype&gt;&#34; --get-short

# imposta/cancella/restituisce la destinazione (ipv4 o ipv6) di un icmptype
firewall-cmd  --permanent --icmptype=&#34;&lt;nome icmptype&gt;&#34; --add-destination=&#34;[ipv4 | ipv6]&#34;
firewall-cmd  --permanent --icmptype=&#34;&lt;nome icmptype&gt;&#34; --remove-destination=&#34;[ipv4 | ipv6]&#34;
firewall-cmd  --permanent --icmptype=&#34;&lt;nome icmptype&gt;&#34; --get-destinations
</code></pre>

<p>(rif. <a href="https://firewalld.org/documentation/icmptype/options.html" rel="nofollow">man icmp type</a>)</p>

<h3 id="4-4-porte-e-protocolli">4.4. Porte e protocolli</h3>

<p>Zone e policy objects permettono di fare binding diretto su porte e protocolli.</p>

<p>Non è generalmente una cosa che mi faccia impazzire perché si bypassano i servizi.</p>

<p>Si fa tutto più velocemente, è vero, ma quando le regole sono numerose e si usano porte non canoniche, la probabilità che, al tendere, non si capisca più su quale servizio si stia agendo, è elevatissima. (cfr. <a href="#4-8-zona" rel="nofollow">4.8. Zona</a> e <a href="#4-9-policy-objects" rel="nofollow">4.9. Policy objects</a>)</p>

<h3 id="4-5-ipset">4.5. IPset</h3>

<p>Gli <strong>ipset</strong> sono liste di subnet o di ip che definiscono le sorgenti nelle zone, nei policy object o nelle rich-rules. La centralizzazione della dichiarazione delle sorgenti disaccoppia la dichiarazione dal suo utilizzo.</p>

<p>Per gli ipset basta indicarre, nome, tipo e una lista di entry.</p>

<pre><code class="language-bash">firewall-cmd --permanent --new-ipset=&#34;&lt;nome_ipset&gt;&#34; --type=&lt;type&gt;
firewall-cmd --permanent --ipset=&#34;&lt;nome_ipset&gt;&#34; [--add-entry= subnet | ip]+
</code></pre>

<p>Di seguito, un elenco dei comandi di utilità disponibili per gli ipsets:</p>

<pre><code class="language-bash"># Restituisce tutti gli ipsets
firewall-cmd --permanent --get-ipsets

# Restituisce tutte le info di un ipset
firewall-cmd --permanent --info-ipset=&#34;&lt;nome_ipset&gt;&#34;

# Restituisce la lista dei tipi di ipset:
firewall-cmd --get-ipset-types

# Restituisce tutte le entry di un ipset
firewall-cmd --permanent --ipset=&#34;&lt;nome_ipset&gt;&#34; --get-entries

# Cancella un ipset
firewall-cmd --permanent --ipset=&#34;&lt;nome_ipset&gt;&#34; --remove-entry=subnet | ip

# Cancella una (o più) entry da un ipset
firewall-cmd --permanent --ipset=&#34;&lt;nome_ipset&gt;&#34; [--delete-entry=subnet | ip]+

# imposta / restituisce la descrizione di un ipset
firewall-cmd --permanent --ipset=&#34;&lt;nome_ipset&gt;&#34; --set-description=&#34;&lt;descrizione&gt;&#34;
firewall-cmd --permanent --ipset=&#34;&lt;nome_ipset&gt;&#34; --get-description

# imposta / restituisce la descrizione breve di un ipset
firewall-cmd --permanent --ipset=&#34;&lt;nome_ipset&gt;&#34; --set-short=&#34;&lt;descrizione_breve&gt;&#34;
firewall-cmd --permanent --ipset=&#34;&lt;nome_ipset&gt;&#34; --get-short-description
</code></pre>

<p>(rif. <a href="https://firewalld.org/documentation/man-pages/firewalld.ipset.html" rel="nofollow">man ipset</a>)</p>

<h3 id="4-6-rich-rules">4.6. Rich-Rules</h3>

<p>Le rich rules danno quel controllo granulare alle zone che è essenziale se si deve intervenire chirurgicamente per accettare o negare del traffico specifico.</p>

<p>Le rich-rules hanno una sintassi leggermente più corposa dello standard firewalld, è un approccio simil-iptables, o meglio, simil-ufw, e vanno aggiunte o alle zone o alle policy. O a entrambe.</p>

<p>Con le rich-rules possiamo abilitare o negare puntualmente il traffico (a seconda della action scelta),</p>

<pre><code class="language-bash">firewall-cmd --permanent --zone=&#34;&lt;nome_zona&gt;&#34; --add-rich-rule=&#39;rule family=&#34;ipv4 | ipv6&#34; \
  source address=&#34;&lt;nome_ipset&gt;&#34; | subnet | ip \
  destination address=&#34;&lt;nome_ipset&gt;&#34; | subnet | ip \
  # traffico indicato come servizio o come port:protocol
  service name=&#34;&lt;nome_servizio&gt;&#34; | port=&lt;port&gt; protocol=tcp|udp|sctp|dccp \
  log prefix=&#34;&lt;prefix&gt;&#34; \
  level=&#34;emerg | alert | crit | error | warning | notice | info | debug&#34; \
  limit value=&#34;rate/duration&#34; \
  # azioni
  accept | reject | drop | mark&#39;
</code></pre>

<p>configurare il masquerade,</p>

<pre><code class="language-bash">firewall-cmd --permanent --zone=&#34;&lt;nome_zona&gt;&#34; --add-rich-rule=&#39;rule family=&#34;ipv4 | ipv6&#34; \
  source address=&#34;&lt;nome_ipset&gt;&#34; | &#34;subnet&#34; | &#34;ip&#34; \
  destination address=&#34;&lt;nome_ipset&gt;&#34; | &#34;subnet&#34; | &#34;ip&#34; \
  masquerade&#39;
</code></pre>

<p>agire di fino sul NAT,</p>

<pre><code class="language-bash">firewall-cmd --permanent --zone=&#34;&lt;nome_zona&gt;&#34; --add-rich-rule=&#39;rule family=&#34;ipv4 | ipv6&#34; \
  source address=&#34;&lt;nome_ipset&gt;&#34; | &#34;subnet&#34; | &#34;ip&#34; \
  destination address=&#34;&lt;nome_ipset&gt;&#34; | &#34;subnet&#34; | &#34;ip&#34; \
  forward-port port=&#34;[port]+&#34; protocol=&#34;tcp|udp|sctp|dccp&#34; \
  to-port=&#34;[port]+&#34; to-addr=&#34;&lt;ip&gt;&#34;&#39;
</code></pre>

<p>bloccare traffico ICMP.</p>

<pre><code class="language-bash">firewall-cmd --permanent --zone=&#34;&lt;nome_zona&gt;&#34; --add-rich-rule=&#39;rule family=&#34;ipv4 | ipv6&#34; \ 
  source address=&#34;&lt;nome_ipset&gt;&#34; | &#34;subnet&#34; | &#34;ip&#34; \
  destination address=&#34;&lt;nome_ipset&gt;&#34; | &#34;subnet&#34; | &#34;ip&#34; \
  [icmp-block name=&#34;&lt;nome_icmptype&gt;&#34; [drop | reject]]+
</code></pre>

<p>Di seguito una lista di comandi utili:</p>

<pre><code class="language-bash"># Rimozione di una rich-rule
firewall-cmd --permanent [--zone=&#34;&lt;nome_zona&gt;&#34; | --policy=&#34;&lt;nome_policy&gt;&#34;] --remove-rich-rule=&#39;rule&#39;

# Elenca tutte le rich-rules di una policy
firewall-cmd --permanent [--zone=&#34;&lt;nome_zona&gt;&#34; | --policy=&#34;&lt;nome_policy&gt;&#34;] --list-rich-rules
</code></pre>

<p>(rif. <a href="https://firewalld.org/documentation/man-pages/firewalld.richlanguage.html" rel="nofollow">man rich-rules</a>)</p>

<h3 id="4-7-forwarding-e-masquerade">4.7. Forwarding e Masquerade</h3>

<p>Firewalld gestisce il nat attraverso dei costrutti all&#39;interno delle zone, dei policy objects o delle rich-rules.</p>

<p>In particolare, zone e policy consentono di configurare velocemente casi particolari di <strong>DNAT</strong> e <strong>SNAT</strong>, port forwarding e masquerade nello specifico, mentre per una gestione del <strong>DNAT</strong> più granulare si ricorre alle rich-rules, a livello di zona o di policy a seconda che si vogliano, al solito, manipolare i pacchetti quando entrano nella zona o quando il pacchetto transita tra le zone specifiche definite dalla policy.</p>

<p><strong>Esempio Port forwarding statico:</strong></p>

<pre><code class="language-bash"># inoltra a 192.168.2.10:22, tutto ciò che la zona riceve sulla 
# porta 2222
firewall-cmd --permanent --zone=esterna --add-forward-port=port=2222:proto=tcp:to-port=22:to-addr=192.168.2.10
</code></pre>

<p>In questo modo inoltro tutto il traffico relativo alla zona.</p>

<p>Se voglio un controllo più fine, devo ricorrere alla combo policy (o zona) +  rich-rules.
In questo modo posso arrivare a determinare quale sia l&#39;ip (o il gruppo di ip) client per il quale è abilitato l&#39;inoltro ed eventualmente verso quale ip pubblico server, potendone scegliere diversi, effettuare l&#39;inoltro.</p>

<p><strong>Esempio DNAT generico:</strong></p>

<pre><code class="language-bash"># inoltro di tutto il traffico proveniente da un ip fisso 
# verso un ip privato, con remapping delle porte.
firewall-cmd --permanent --policy=&#34;esterna-interna&#34; \
--add-rich-rule=&#39;rule family=&#34;ipv4&#34; \
  source address=&#34;93.12.34.56&#34; \
  forward-port port=&#34;5001-6000&#34; protocol=&#34;udp&#34; to-port=&#34;15001-16000&#34; to-addr=&#34;192.168.1.100&#34;&#39;

# stesso esempio di prima in cui il sorgente client è un gruppo 
# di ip (ipset) fissi 
firewall-cmd --permanent --policy=&#34;esterna-interna&#34; \
--add-rich-rule=&#39;rule family=&#34;ipv4&#34; \
  source ipset=&#34;my_ipset&#34; \
  forward-port port=&#34;80&#34; protocol=&#34;tcp&#34; to-port=&#34;8080&#34; to-addr=&#34;192.168.1.100&#34;&#39;

# In questo caso suppongo che il fw esponga più indirizzi pubblici.
# Solo un ip specifico può inoltrare il suo traffico 
# richiedendolo ad uno degli indirizzi pubblici del firewall
firewall-cmd --permanent --policy=&#34;esterna-interna&#34; \
--add-rich-rule=&#39;rule family=&#34;ipv4&#34; \
  source address=&#34;151.12.13.14&#34;    # ip client \
  destination address=&#34;9.10.20.31&#34; # ip pubblico fw \
  forward-port port=&#34;53947&#34; protocol=&#34;tcp&#34; to-port=&#34;3306&#34; to-addr=&#34;192.168.1.100&#34;&#39;
</code></pre>

<p><strong>Esempio Masquerade:</strong></p>

<pre><code class="language-bash">firewall-cmd --permanent --zone=esterna --add-masquerade
</code></pre>

<p>Come nell&#39;esempio del port forwarding statico, il nat a livello di zona o di policy altera qualunque pacchetto che transita nella zona o nella policy.</p>

<p>Anche qui, per avere un controllo migliore l&#39;approccio policy (o zona) + rich-rules risulta vincente.
In questo modo posso arrivare a scegliere quali dei server interni deve essere nattato ed eventualmente verso quali ip (snat condizionale).</p>

<pre><code class="language-bash"># nat di un singolo ip interno
firewall-cmd --permanent --policy=&#34;interna-esterna&#34; \
--add-rich-rule=&#39;rule family=&#34;ipv4&#34; \
  source address=192.168.10.10 masquerade&#39;

# nat di un gruppo di ip interni (ipset)
firewall-cmd --permanent --policy=&#34;interna-esterna&#34; \
--add-rich-rule=&#39;rule family=&#34;ipv4&#34; \
  source ipset=&#34;my_ipset&#34; masquerade&#39;

# nat di tutta la zona interna quando la destinazione è un ip 
# (o gruppo di ip) specifico
firewall-cmd --permanent --policy=&#34;interna-esterna&#34; \
--add-rich-rule=&#39;rule family=&#34;ipv4&#34; \
  destination ipset=&#34;my_ipset&#34; masquerade&#39;

# o, al contrario, si vuole nattare tutta la rete interna, o un
# suo segmento, TRANNE il traffico destinato ad UN&#39;ALTRA rete
# specifica (es. una vpn o altro).
firewall-cmd --permanent --policy=&#34;interna-esterna&#34; \
--add-rich-rule=&#39;rule family=&#34;ipv4&#34; \
  source address=&#34;my_ipset&#34;
  destination not address=&#34;10.4.10.0/24&#34; masquerade&#39;

# nat di un gruppo di ip solo per il servizio web
firewall-cmd --permanent --new-service=&#34;navigazione_web&#34;
firewall-cmd --permanent --service=&#34;navigazione_web&#34; \
  --add-include=&#34;http&#34; \
  --add-include=&#34;https&#34; \
  --add-include=&#34;dns&#34;

firewall-cmd --permanent --policy=&#34;interna-esterna&#34; \
--add-rich-rule=&#39;rule family=&#34;ipv4&#34; \
  source ipset=&#34;my_ipset&#34; \
  service name=&#34;navigazione_web&#34; masquerade&#39;
</code></pre>

<h3 id="4-8-zona">4.8. Zona</h3>

<p>Per creare una zona basta assegnarle un nome e associarle una o più interfacce e/o una o più sorgente di indirizzi ip.</p>

<p>Una zona senza alcun binding <strong>non è attiva</strong>.</p>

<pre><code class="language-bash">firewall-cmd --permanent --new-zone=&#34;&lt;nome_zona&gt;&#34;

# aggiunge un&#39;interfaccia
firewall-cmd --permanent --zone=&#34;&lt;nome_zona&gt;&#34; [--add-interface=&#34;&lt;nome_interfaccia&gt;&#34;]+

# aggiunge sorgenti
firewall-cmd --permanent --zone=&#34;&lt;nome_zona&gt;&#34; [--add-source=subnet | ip | &#34;&lt;nome_ipset&gt;&#34;]+
</code></pre>

<p>Se nella configurazione sono presenti <strong>sia l&#39;interfaccia che le sorgenti di ip</strong>, sto dichiarando che tutto ciò che transita per l&#39;interfaccia o che rientra nelle sorgenti indicate, ricadrà nelle regole della zona.</p>

<p>Faccio notare che Il binding (sorgenti o interfacce) funziona <strong>in aggiunta</strong>, non restringe ciò che ad es. transita dall&#39;interfaccia.
Tenete bene a mente che nella gestione del routing dei pacchetti verso le zone che fa firewalld, vengono valutate <strong>prima</strong> le sorgenti e <strong>dopo</strong> l&#39;interfaccia.</p>

<p>Se avessi l&#39;esigenza di restringere il traffico nella zona, si potrebbe pensare di limitare il binding <strong>alle sole</strong> sorgenti, escludendo l&#39;interfaccia, in modo che qualunque pacchetto che non provenga dagli ip o dalle subnet, a prescindere dall&#39;interfaccia, indicate venga respinto (in base alla politica della zona).</p>

<p>Va tenuto presente che configurazioni di questo tipo, per quanto pulite e semplici da realizzare, possono dare luogo ad errori estremamente subdoli e pericolosissimi (vedremo un esempio in seguito).</p>

<p>Tutti i pacchetti che, transitando per l&#39;host, non vengono assorbiti da alcuna zona, saranno gestiti dalla zona di default.</p>

<p>Di seguito una lista di comandi utili:</p>

<pre><code class="language-bash"># restituisce la zona di default
firewall-cmd --get-default-zone

# setta la zona di default
firewall-cmd --set-default-zone=&#34;&lt;nome_zona&gt;&#34;

# restituisce tutte le zone attive (tutte quelle con un binding ad un&#39;interfaccia e/o ad un sorgente)
firewall-cmd --get-active-zones

# restituisce tutte le zone accoppiate ad una specifica interfaccia/sorgente
firewall-cmd --permanent --get-zone-of-interface=&#34;&lt;nome_interfaccia&gt;&#34;
firewall-cmd --permanent --get-zone-of-source=subnet | ip | &#34;&lt;nome_ipset&gt;&#34;

# restituisce info dettagliate sulla zone
firewall-cmd --permanent --info-zone=&#34;&lt;nome_zona&gt;&#34;

# elenca tutte le zone
firewall-cmd --permanent --list-all-zones

# cancella una zona
firewall-cmd --permanent --delete-zone=&#34;&lt;nome_zona&gt;&#34;


###########
# Servizi #
###########
# aggiungi / cancella servizi da una zona o dalla zona attiva (se il nome zona non è specificato)
firewall-cmd --permanent --zone=&#34;&lt;nome_zona&gt;&#34; [--add-service=&#34;&lt;nome_servizio&gt;&#34;]+
firewall-cmd --permanent --zone=&#34;&lt;nome_zona&gt;&#34; [--remove-service=&#34;&lt;nome_servizio&gt;&#34;]+


######################
# porte e protocolli #
######################
# elencare tutte le porte e i protocolli della zona
firewall-cmd --permanent --zone=&#34;&lt;nome_zona&gt;&#34; --list-ports
firewall-cmd --permanent --zone=&#34;&lt;nome_zona&gt;&#34; --list-protocols

# aggiungere/cancellare una porta alla zona
firewall-cmd --permanent --zone=&#34;&lt;nome_zona&gt;&#34; [--add-port=&lt;port&gt;/tcp | udp | sctp | dccp]+
firewall-cmd --permanent --zone=&#34;&lt;nome_zona&gt;&#34; [--remove-port=&lt;port&gt;/tcp | udp | sctp | dccp]+

# aggiungere/cancellare un protocollo alla zona
firewall-cmd --permanent --zone=&#34;&lt;nome_zona&gt;&#34; --add-protocol=&lt;protocol&gt;
firewall-cmd --permanent --zone=&#34;&lt;nome_zona&gt;&#34; --remove-protocol=&lt;protocol&gt;


##############
# Rich-rules #
##############
# aggiungere/cancellare un protocollo alla zona
firewall-cmd --permanent --zone=&#34;&lt;nome_zona&gt;&#34; --add-rich-rule=&#34;&lt;nome_rich-rule&gt;&#34;
firewall-cmd --permanent --zone=&#34;&lt;nome_zona&gt;&#34; --remove-rich-rule=&#34;&lt;nome_rich-rule&gt;&#34;


#############
# ICMP Type #
#############
# inverte / disattiva la logica del blocco icmp nella zona (attiva / disattiva whitelist)
firewall-cmd --permanent --zone=&#34;&lt;nome_zona&gt;&#34; --add-imcp-block-inversion
firewall-cmd --permanent --zone=&#34;&lt;nome_zona&gt;&#34; --remove-imcp-block-inversion

# aggiunge un tipo icmp alla whitelist/blacklist
firewall-cmd --permanent --zone=&#34;&lt;nome_zona&gt;&#34; [--add-imcp-block=&#34;&lt;tipo_icmp&gt;&#34;]+

# rimuove un tipo icmp dalla whitelist/blacklist
firewall-cmd --permanent --zone=&#34;&lt;nome_zona&gt;&#34; [--remove-imcp-block=&#34;&lt;tipo_icmp&gt;&#34;]+


##############
# Masquerade #
##############
# aggiunge / rimuove il masquerade
firewall-cmd --permanent --zone=&#34;&lt;nome_zona&gt;&#34; --add-masquerade
firewall-cmd --permanent --zone=&#34;&lt;nome_zona&gt;&#34; --remove-masquerade


###########################
# Port forwarding statico #
###########################
# aggiunge / rimuove il port forwarding
firewall-cmd --permanent --zone=&#34;&lt;nome_zona&gt;&#34; --add-forward-port=port=&lt;port&gt;[-&lt;port&gt;]:proto=[tcp|udp|sctp|dccp]:to-port=&lt;port&gt;[-&lt;port&gt;][:to-addr=&lt;ip&gt;[/&lt;mask&gt;]
firewall-cmd --permanent --zone=&#34;&lt;nome_zona&gt;&#34; --remove-forward-port=port=&lt;port&gt;[-&lt;port&gt;]:proto=[tcp|udp|sctp|dccp]:to-port=&lt;port&gt;[-&lt;port&gt;][:to-addr=&lt;ip&gt;[/&lt;mask&gt;]

# es. di inoltro veerso un ip interno di un range di porte con offset deterministico
firewall-cmd --permanent --zone=&#34;esterna&#34; --add-forward-port=port=2501-3000:proto=tcp:to-port=5001-5500:to-addr=192.168.10.20
firewall-cmd --permanent --zone=&#34;esterna&#34; --remove-forward-port=port=2501-3000:proto=tcp:to-port=5001-5500:to-addr=192.168.10.20
</code></pre>

<p>(rif. <a href="https://firewalld.org/documentation/man-pages/firewalld.zone.html" rel="nofollow">man zone</a>)</p>

<h3 id="4-9-policy-objects">4.9. Policy Objects</h3>

<p>I policy objects, presenti dall&#39;ormai lontano 2020 con la versione 0.9.0, hanno posto le basi per il futuro di firewalld. È il posto in cui si concentrano le policy di filtraggio sia per il traffico intra-zona che, soprattutto, per il traffico inter-zona.</p>

<p>I policy objects cambiano radicalmente il disegno delle regole che, come detto in precedenza, vengono disaccoppiate dalla dichiarazione della zona che rimane il luogo in cui viene effettuato principalmente il trust delle sorgenti.</p>

<p>Conseguenza immediata è una notevole flessibilità perché ho la possibilità di variare dinamicamente le regole da applicare alle zone semplicemente aggiungendo le policy opportune.</p>

<p>Lavorare sulle zone è più immediato ma più lo scenario diventa articolato, più le configurazioni si complicano, oltre al fatto che alcune cose come il routing e l&#39;inoltro, con le sole zone non sono proprio realizzabili</p>

<p>Le policy, al contrario, richiedono una maggiore complessità iniziale ma ha il vantaggio di mantenere il disegno generale più pulito nei casi in cui le configurazioni cambino con una certa frequenza o tendano a diventare via via più articolate.</p>

<p>Nel seguito mostrerò degli esempi di configurazioni  fatte in modalità zone-oriented e policy-oriented.</p>

<p>Gli elementi costitutivi del policy object sono il nome, il target policy (di base, “default”), la specifica della direzione del traffico, uno o più servizi da abilitare.</p>

<pre><code class="language-bash">firewall-cmd --permanent --new-policy=&#34;&lt;nome_policy&gt;&#34;
firewall-cmd --permanent --policy=&#34;&lt;nome_policy&gt;&#34; --set-target=DROP | REJECT | ACCEPT | CONTINUE

# definizione della direzione del traffico
firewall-cmd --permanent --policy=&#34;&lt;nome_policy&gt;&#34; [--add-ingress-zone=HOST | &#34;&lt;nome_zona&gt;&#34; | ANY]+
firewall-cmd --permanent --policy=&#34;&lt;nome_policy&gt;&#34; [--add-egress-zone=HOST | &#34;&lt;nome_zona&gt;&#34; | ANY]+

# traffico consentito
firewall-cmd per --permanent --policy=&#34;&lt;nome_policy&gt;&#34; [--add-service=&#34;&lt;nome_servizio&gt;&#34;]+
</code></pre>

<p>Di seguito, una lista di comandi utili:</p>

<pre><code class="language-bash"># elenco, sintetico o dettagliato, di tutti i policy objects
firewall-cmd --get-policies
firewall-cmd --permanent --list-all-policies

# estrae tutti i componenti della policy
firewall-cmd --permanent --policy=&#34;&lt;nome_policy&gt;&#34; --list-all

# restituisce le ingress / egress zone
firewall-cmd --permanent --policy=&#34;&lt;nome_policy&gt;&#34; --list-egress-zones
firewall-cmd --permanent --policy=&#34;&lt;nome_policy&gt;&#34; --list-ingress-zones

# restituisce i servizi
firewall-cmd --permanent --policy=&#34;&lt;nome_policy&gt;&#34; --list-services

# restituisce le rich-rules
firewall-cmd --permanent --policy=&#34;&lt;nome_policy&gt;&#34; --list-rich-rules

# info di un policy object
firewall-cmd --permanent --info-policy=&#34;&lt;nome_policy&gt;&#34;

# cambiare target di un policy object
firewall-cmd --permanent --policy=&#34;&lt;nome_policy&gt;&#34; --set-target=DROP | REJECT | ACCEPT | CONTINUE

# eliminare un policy object
firewall-cmd --permanent --delete-policy=&#34;&lt;nome_policy&gt;&#34;


###########
# Servizi #
###########
# aggiungi / cancella servizi dal policy object specificato
firewall-cmd --permanent --policy=&#34;&lt;nome_policy&gt;&#34; [--add-service=&#34;&lt;nome_servizio&gt;&#34;]+
firewall-cmd --permanent --policy=&#34;&lt;nome_policy&gt;&#34; [--remove-service=&#34;&lt;nome_servizio&gt;&#34;]+


######################
# Porte e protocolli #
######################
# elencare tutte le porte e i protocolli del policy object specificato
firewall-cmd --permanent --policy=&#34;&lt;nome_policy&gt;&#34; --list-ports
firewall-cmd --permanent --policy=&#34;&lt;nome_policy&gt;&#34; --list-protocols

# aggiungere/cancellare una porta dal policy object specificato
firewall-cmd --permanent --policy=&#34;&lt;nome_policy&gt;&#34; [--add-port=&lt;port&gt;/tcp | udp | sctp | dccp]+
firewall-cmd --permanent --policy=&#34;&lt;nome_policy&gt;&#34; [--remove-port=&lt;port&gt;/tcp | udp | sctp | dccp]+

# aggiungere/cancellare un protocollo dal policy object specificato
firewall-cmd --permanent --policy=&#34;&lt;nome_policy&gt;&#34; --add-protocol=[tcp | udp | sctp | dccp]
firewall-cmd --permanent --policy=&#34;&lt;nome_policy&gt;&#34; --remove-protocol=[tcp | udp | sctp | dccp]


##############
# Rich-rules #
##############
# aggiungere/cancellare una (o più) rich-rule dal policy object specificato
firewall-cmd --permanent --policy=&#34;&lt;nome_policy&gt;&#34; [--add-rich-rule=&#34;&lt;nome_rich-rule&gt;&#34;]+
firewall-cmd --permanent --policy=&#34;&lt;nome_policy&gt;&#34; [--remove-rich-rule=&#34;&lt;nome_rich-rule&gt;&#34;]+


##############
# ICMP Types #
##############
# Aggiunge un tipo icmp alla whitelist/blacklist
firewall-cmd --permanent --policy=&#34;&lt;nome_policy&gt;&#34; [--add-imcp-block=&#34;&lt;tipo_icmp&gt;&#34;]+

# Rimuove un tipo icmp dalla whitelist/blacklist
firewall-cmd --permanent --policy=&#34;&lt;nome_policy&gt;&#34; [--remove-imcp-block=&#34;&lt;tipo_icmp&gt;&#34;]+


##############
# Masquerade #
##############
# aggiunge / rimuove il masquerade
firewall-cmd --permanent --policy=&#34;&lt;nome_policy&gt;&#34; --add-masquerade
firewall-cmd --permanent --policy=&#34;&lt;nome_policy&gt;&#34; --remove-masquerade


###########################
# Port forwarding statico #
###########################
# aggiunge / rimuove il port forwarding
firewall-cmd --permanent --policy=&#34;&lt;nome_policy&gt;&#34; --add-forward-port=port=&lt;port&gt;[-&lt;port&gt;]:proto=[tcp | udp | sctp | dccp]:to-port=&lt;port&gt;[-&lt;port&gt;][:to-addr=&lt;ip&gt;[/&lt;mask&gt;]
firewall-cmd --permanent --policy=&#34;&lt;nome_policy&gt;&#34; --remove-forward-port=port=&lt;port&gt;[-&lt;port&gt;]:proto=[tcp | udp | sctp | dccp]:to-port=&lt;port&gt;[-&lt;port&gt;][:to-addr=&lt;ip&gt;[/&lt;mask&gt;]

# es. di inoltro veerso un ip interno di un range di porte con offset deterministico
firewall-cmd --permanent --policy=&#34;wan-to-lan&#34; --add-forward-port=port=2501-3000:proto=tcp:to-port=5001-5500:to-addr=192.168.10.20
firewall-cmd --permanent --zone=&#34;wan-to-lan&#34; --remove-forward-port=port=2501-3000:proto=tcp:to-port=5001-5500:to-addr=192.168.10.20
</code></pre>

<p>(rif. <a href="https://firewalld.org/documentation/man-pages/firewalld.policy.html" rel="nofollow">man policy</a>, <a href="https://firewalld.org/documentation/man-pages/firewalld.policies.html" rel="nofollow">man policies</a>)</p>

<h3 id="4-10-comandi-di-utilità-generale">4.10. Comandi di utilità generale</h3>

<p>Di seguito, un elenco dei comandi di utilità generale disponibili per firewalld:</p>

<pre><code class="language-bash"># Restituisce lo stato di firewalld
firewall-cmd --state

# Riavvia firewalld
firewall-cmd --reload

# Riavvia firewalld ricaricando anche i moduli netfilter del kernel
firewall-cmd --complete-reload

# Restituisce il log level di firewalld
firewall-cmd --get-log-denied

# Imposta il log level di firewalld
firewall-cmd --set-log-denied=all | unicast | broadcast | multicast | off

# Rende permanente tutte le configurazioni effimere di firewalld. Necessario il reload.
firewall-cmd --runtime-to-permanent

# Kill switch ON /OFF
firewalld --panic-on
firewalld --panic-off

# Stato Kill switch [0 | 1]
firewalld --query-panic
</code></pre>

<p><a href="/aytin/tag:firewall" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">firewall</span></a> <a href="/aytin/tag:firewallcmd" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">firewallcmd</span></a> <a href="/aytin/tag:firewalld" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">firewalld</span></a> <a href="/aytin/tag:iptables" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">iptables</span></a> <a href="/aytin/tag:netfilter" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">netfilter</span></a>  <a href="/aytin/tag:nftables" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">nftables</span></a> <a href="/aytin/tag:ufw" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">ufw</span></a></p>
]]></content:encoded>
      <guid>https://noblogo.org/aytin/sveliamo-i-misteri-di-firewalld-parte-1-di-2</guid>
      <pubDate>Mon, 08 Jun 2026 13:10:26 +0000</pubDate>
    </item>
    <item>
      <title>Cose molto notevoli su LVM</title>
      <link>https://noblogo.org/aytin/cose-molto-notevoli-su-lvm</link>
      <description>&lt;![CDATA[lvm plus&#xA;Oltre che alla grande flessibilità nella gestione dei volumi, LVM attraverso device mapper, aggiunge tutta una serie di ulteriori capacità che rendono questa tecnologia estremamente versatile.&#xA;&#xA;La possibilità di disporre di meccanismi per la gestione di snapshot, cache pool. thin provisioning e raid, rendono LVM qualcosa di più di un gestore di volumi. &#xA;!--more--&#xA;&#xA;1. Snapshot&#xA;   1.1. Attenzione: Dimensione della snapshot&#xA;   1.2. Esempio&#xA;2. Thin Pool&#xA;3. Thin Pool e snapshot&#xA;4. Cache Pool&#xA;   4.1. Caso 1: configurazione automatica del cache pool lv&#xA;   4.2. Caso 2: configurazione manuale del cache pool lv&#xA;   4.3. Switch della modalità&#xA;   4.4. Rimozione della cache&#xA;   4.5. Monitoraggio&#xA;5. LVM Stripe&#xA;6. LVM Mirror&#xA;7. LVM Raid&#xA;   7.1. Raid 0 (Stripe)&#xA;   7.2. Raid 1 (Mirroring)&#xA;   7.3. Raid 5 (Stripe con parità singola)&#xA;   7.4. Raid 6 (Stripe con parità doppia)&#xA;   7.5. Raid 10&#xA;   7.6. Come monitorare il raid&#xA;   7.7. Come intervenire in caso di guasto&#xA;&#xA;1. Snapshot&#xA;Le snapshot LVM usano la tecnica del Copy-on-Write (CoW) allo scopo di ridurre la duplicazione. &#xA;&#xA;La snapshot dovrà essre la fotografia del volume prima all&#39;origine.&#xA;&#xA;Ad ogni modifica / cancellazione, il file originale verrà portato sulla snapshot prima dell&#39;operazione.&#xA;Sul volume originale verranno scritti tutti i dati nuovi e quelli modificati.&#xA;&#xA;Per il ripristino, si effettua quello che si chiama merge, dove i dati vecchi vengono ripristinati dalla snapshot e quelli nuovi cancellati dal volume.&#xA;&#xA;Per il consolidamento delle modifiche, basterò rimuovere la snapshot,&#xA;&#xA;1.1. Attenzione: Dimensione della snapshot&#xA;&#xA;Se la snapshot ha la stessa dimensione del volume logico non ci sono problemi.&#xA;&#xA;Se è più piccola, occorre prestare attenzione a che la quantità dei dati modificati sul volume logico non superino la dimensione della snapshot.&#xA;&#xA;In questo caso infatti la snapshot risulterà inutilizzabile e non potrà più essere usata per il ripristino ma potrà essree solo rimossa.&#xA;&#xA;1.2. Esempio&#xA;Supponiamo di avere un gruppo di volumi, myvg, composto da 3 volumi logici:&#xA;&#xA;lvroot (30 GiB)&#xA;lvhome (200 GiB)&#xA;lvdati (500 GiB)&#xA;&#xA;e di voler creare una snapshot precauzionale sulla root (supponendo di avere spazio a sufficienza altrimenti dovrò fare bene i miei conti per non riempire oltremisura la snapshot rendendola inservibile).&#xA;&#xA;Creazione snapshot&#xA;lvcreate -s -L 30G -n  lvrootsnap myvg/snap&#xA;Ripristino&#xA;umount /dev/myvg/lvroot&#xA;lvconvert --merge myvg/snap&#xA;Consolidamento&#xA;lvremove snap&#xA;2. Thin Pool&#xA;Il thin provisioning di LVM è l&#39;alternativa dinamica alla classica gestione di volumi, thick, che prevede l&#39;assegnazione statica delle dimensioni dei volumi.&#xA;&#xA;Se è vero che il thick provisioning risulta comunque abbastastanza agevole per via della flessibilità intrinseca dei volumi in caso di riduzione o aumento della superficie allocabile, il thin provisioning può aumentare i vantaggi derivanti da LVM in alcuni scenari.&#xA;&#xA;Il thin provisioning si basa sul principio che lo spazio assegnato ai volumi non viene usato mai completamente e mai tutto in una volta.&#xA;&#xA;Ecco perché un&#39;allocazione dinamica ci permetterebbe di definire volumi che si riempiono solo man mano che lo spazio viene occupato.&#xA;&#xA;Se si opta per un thin provisioning sarebbe opportuno non usare tutto il gruppo di volumi ma lasciarne un 20% in previsione di future espansioni.&#xA;&#xA;Con i thin pool non solo abbiamo la stessa flessibilità della gestione thick, ma possiamo lavorare anche in over provisioning ossia creare pool di volumi la cui somma potenziale sia superiore allo spazio realmente allocabile.&#xA;&#xA;Es. Supponiamo avere un device da 100 GiB, /dev/sdb, su cui definisco un volume group e creare un thin pool di 50 GiB. Su questo thin pool creeremo 3 volumi &#34;virtuali&#34; da 20, 30 e 20 GiB.&#xA;creazione volume group di 100 GiB&#xA;vgcreate vglab /dev/sdb&#xA;&#xA;creazione thin pool da 50 GiB&#xA;lvcreate -L 50G --thinpool vglab/lvtp&#xA;&#xA;creazione dei 3 volumi virtuali in &#34;over provisioning&#34; &#xA;lvcreate -V 20G --thin -n vol1virt --thinpool vglab/lvtp&#xA;lvcreate -V 30G --thin -n vol2virt --thinpool vglab/lvtp&#xA;lvcreate -V 20G --thin -n vol3virt --thinpool vglab/lvtp&#xA;Una volta creati i volumi possono essere formattati e montati come di consueto.&#xA;&#xA;Lo spazio effettivamente occupato è quasi nullo, il sistema solleverà solo un warning per avvertirci che i volumi virtuali rischiano di saturare lo spazio disponibile.&#xA;&#xA;Ecco perché bisogna prestare attenzione al raggiungimento della soglia critica.&#xA;Bisognerà estendere subito il thin pool ed i volumi virtuali nel modo consueto.&#xA;&#xA;⚠️⚠️⚠️ ATTENZIONE ⚠️⚠️⚠️&#xA;L&#39;estensione di un volume virtuale non differisce molto da quello di un volume &#34;classico&#34;.&#xA;Se lo spazio per le fette si sta esaurendo, si estendono nell&#39;ordine:&#xA;&#xA;il gruppo di volumi (se necessario)&#xA;il thin pool (se nel volume group c&#39;è spazio a sufficienza)&#xA;i volumi virtuali&#xA;i filesystem&#xA;&#xA;Se non siamo con l&#39;acqua alla gola, i punti 3 e 4 sono sufficienti. L&#39;estensione del volume virtuale è più rapida di quella classica perché non viene allocato spazio.&#xA;L&#39;estensione di un volume logico classico corrisponde all&#39;estensione del thin pool.&#xA;&#xA;Nel caso di riduzione, la situazione cambia parecchio perché la riduzione di un volume virtuale non fa guadagnare spazio allocabile visto che l&#39;ampiezza del volume è solo teorica, ciò avviene solo con fstrim.&#xA;Inoltre accorciando il volume virtuale al di sotto dei dati effettivamente scritti, si rischia di corrompere l&#39;intero filesystem.&#xA;Consiglio spassionato: ESTENDI SEMPRE E NON RIDURRE MAI!!!&#xA;&#xA;Altra considerazione va fatta anche per i metadati.&#xA;&#xA;A differenza dell&#39;LVM classico dove la creazione di un volume logico necessitava di un extent per i metadati, il thin provisioning di LVM riserva un volume logico per i dati e un volume logico per i metadati.&#xA;&#xA;L&#39;estensione continua di piccole fette, può riempire il volume dei metadati col rischio di corrompere l&#39;intero thin pool e prima che succeda, anche il volume dei metadati può dover essere esteso.&#xA;lvextend --poolmetadatasize +1G vglab/lvtp&#xA;3. Thin Pool e snapshot&#xA;Un altro bel vantaggio della modalità thin pool è quello di facilitare l&#39;uso delle snapshot.&#xA;&#xA;Trattandosi di volumi virtuali, la dimensione della snapshot non ha bisogno di essere dichiarata. La creazione di snapshot è estremamente semplice.&#xA;creazione di una snapshot&#xA;lvcreate -s -n lvsnap vglab/volvirt&#xA;Come pure sia la creazione di snapshot annidate che il rollback risultano molto più semplici ed efficienti.&#xA;creazione di una snapshot&#xA;lvcreate -s -n lvsnap1 vglab/volvirt&#xA;&#xA;creazione di una snapshot annidata&#xA;lvcreate -s -n lvsnap2 vglab/lvsnap1&#xA;&#xA;rollback&#xA;umount vol1&#xA;lvconvert --merge vglab/lvsnap2&#xA;mount -t ext4 -o defaults /dev/vglab/volvirt vol1&#xA;E a proposito di snapshot, occorre fare qualche osservazione.&#xA;&#xA;Una serie di snapshot thin annidate, non è una catena di patch incrementali esposte al filesystem come si potrebbe pensare.&#xA;In virtù del CoW, la snapshot annidate fotograferanno sempre lo stesso istante: quello del file system all&#39;origine.&#xA;&#xA;Facciamo un esempio:&#xA;lvcreate -V 10g -T vgtest/thinpool -n vmroot&#xA;mkfs.ext4 /dev/vgtest/vmroot&#xA;mount /dev/vgtest/vmroot /mnt/test&#xA;echo ORIGINAL   /mnt/test/file.txt&#xA;umount test&#xA;&#xA;lvcreate -s -n snap1 vgtest/vmroot&#xA;&#xA;mount /dev/vgtest/vmroot /mnt/test&#xA;echo MOD1   /mnt/test/file.txt&#xA;umount /mnt/test&#xA;&#xA;lvcreate -s -n snap2 vgtest/snap1&#xA;&#xA;mount /dev/vgtest/vmroot /mnt/test&#xA;echo MOD2   /mnt/test/file.txt&#xA;umount /mnt/test&#xA;&#xA;lvcreate -s -n snap3 vgtest/snap2&#xA;&#xA;mount /dev/vgtest/vmroot /mnt/test&#xA;echo MOD3   /mnt/test/file.txt&#xA;umount /mnt/test&#xA;In questo esempio creo un volume virtuale, vmroot, e 3 snap annidate.&#xA;&#xA;Monto il volume virtuale.&#xA;La prima snapshot, snap1, fotografa il file system del volume virtuale che contiene il file con &#34;ORIGINAL&#34;.&#xA;Il volume virtuale viene montato e il file viene modificato.&#xA;La seconda snapshot, snap2, fotografa snap1 che a sua volta conteneva il file system del volume virtuale che contiene il file con &#34;ORIGINAL&#34;.&#xA;Il volume virtuale viene montato e il file viene modificato.&#xA;La terza snapshot, snap3, fotografa snap2 che a sua volta conteneva snap1.. ecc.&#xA;&#xA;Quindi snapshot siffatte non realizzano un versioning del file system come si potrebbe pensare, piuttosto possono essere utili per creare alberi di cloni/read-only, ambienti temporanei derivati da uno stato consistente, ecc.&#xA;&#xA;In sostanza tornano utili quando ho una base da cui faccio derivare n snapshot che condividono i blocchi comune e con CoW minimizzo lo spazio.&#xA;&#xA;Il merge di una qualunque snapshot ricondurrà il file system allo stato originario.&#xA;origin&#xA; ├── snap1&#xA; ├── snap2&#xA; ├── snap3&#xA;Per lavorare sul delta come immaginiamo, si dovranno montare via via le snapshop, non il volume virtuale, e modificare quelle.&#xA;lvcreate -V 10g -T vgtest/thinpool -n vmroot&#xA;mkfs.ext4 /dev/vgtest/vmroot&#xA;mount /dev/vgtest/vmroot /mnt/test&#xA;echo ORIGINAL   /mnt/test/file.txt&#xA;umount /mnt/test&#xA;&#xA;lvcreate -s -n snap1 vgtest/vmroot&#xA;&#xA;lvchange -ay -K vgtest/snap1&#xA;mount /dev/vgtest/snap1 /mnt/test&#xA;echo MOD1   /mnt/test/file.txt&#xA;umount /mnt/test&#xA;&#xA;lvcreate -s -n snap2 vgtest/snap1&#xA;&#xA;lvchange -ay -K vgtest/snap2&#xA;mount /dev/vgtest/snap2 /mnt/test&#xA;echo MOD2   /mnt/test/file.txt&#xA;umount /mnt/test&#xA;&#xA;lvcreate -s -n snap3 vgtest/snap2&#xA;&#xA;lvchange -ay -K vgtest/snap3&#xA;mount /dev/vgtest/snap3 /mnt/test&#xA;echo MOD3   /mnt/test/file.txt&#xA;umount /mnt/test&#xA;In questo modo si &#34;inverte&#34; la logica del merge che, prima riconduceva il file system allo stato inizale, ora invece consolida le modifiche delle snapshot&#xA;origin&#xA; └── snap1&#xA;      └── snap2&#xA;           └── snap3&#xA;Il merge va fatto in ordine se si vogliono acquisire correttamente i delta.&#xA;Tuttavia questo approccio&#xA;&#xA;è raro&#xA;è difficile da gestire&#xA;complica i merge&#xA;può creare dependency tree intricati&#xA;&#xA;Per questo quasi tutti:&#xA;&#xA;snapshot sempre dell’origin&#xA;mai snapshot di snapshot&#xA;rollback lineare&#xA;&#xA;4. Cache Pool&#xA;Il cache pool di LVM serve a migliorare l&#39;accesso a dispositivi tradizionalmente lenti e lo fa combinando dischi  HDD con SSD/NVMe.&#xA;&#xA;In sostanza avremo un gruppo di volumi costituito dai dischi HDD e un altro gruppo di volumi costituito dai dischi SDD/NVMe, la nostra cache.&#xA;&#xA;Il Logical Volume Cache sul disco veloce migliora l&#39;accesso ad uno specifico volume logico del disco lento e prevede il ricorso a tutta una serie di tipi di volumi logici abbastanza variegata:&#xA;&#xA;Origin LV: volume logico orignale costituito dai dischi lenti&#xA;Cache pool LV: volume logico composto  a sua volta da altri due voumi logici: dati della cache e metadati della cache&#xA;&#x9;Cache data LV: volume logico contenente i blocchi di dati per il Cache pool LV.&#xA;&#x9;Cache metadata LV: volume logico contenente i metadatati per il Cache pool LV.&#xA;Cache LV: volume logico contenente l&#39;Origin LV e Il Cache pool LV. È il volume realemente utilizzabile&#xA;Spare metadata LV: volume logico correlato ad una funzione di recovery data failure&#xA;&#xA;cacheLVM.jpg&#xA;&#xA;Quando si crea una cache ho due possibilità a seconda che si voglia massimizzare velocità o affidabilità:&#xA;&#xA;writethrough: Le operazioni di scrittura vengono inviate sia alla cache SSD che all&#39;Origin HDD. La lettura avviene preferibilmente dalla cache.&#xA;È la modalità più sicura. Se l&#39;SSD muore, nessun dato va perso ma è meno efficiente in scrittura perché Origin HDD diventa il collo di bottiglia,&#xA;writeback: più veloce ma meno sicuro. Le scritture vengono salvate immediatamente sulla cache veloce e sincronizzate sull&#39;HDD in background in un secondo momento. Se si dovesse rompere il disco di cache, c&#39;è il rischio di una perdita di dati.&#xA;&#xA;Il dimensionamento della cache è proporzionale alla dimensione del disco origin.&#xA;Di solito si aggira in un range del 2-10%&#xA;&#xA;2%: archiviazione sequenziale, file di grandi dimensioni;&#xA;5%: standard consigliato. File server generico, utilizzo desktop/workstation;&#xA;10%: carichi di lavoro intensivi e casuali come database SQL/NoSQL attivi, nodi di virtualizzazione densi (molte VM), ecc.&#xA;&#xA;Non è necessario prevedere da subito Il disco di cache (se c&#39;è stata la possibilità tanto meglio), ma si può aggiungere in un secondo momento estendendo il gruppo di volumi contenente l&#39;HDD e battezzando l&#39;LV di cache.&#xA;&#xA;Perpariamo il nostro laboratorio in cui abbiamo un HD lento con un unico volume logico a cui applichiamo una cache.&#xA;&#xA;disco lento: 2 GiB&#xA;disco veloce: 500 MiB&#xA;cache: 5% di 2 GiB (~100 MiB)&#xA;&#xA;creazione del device fisico per il laboratorio&#xA;fallocate -l 2GiB slowdisk.img&#xA;&#xA;attach del device e creazione del gruppo di volumi&#xA;vgcreate vglab $(losetup -Pf --show slowdisk.img)&#xA;&#xA;creazione e formattazione dell&#39;unico volume logico&#xA;lvcreate -n lvorigin vglab -l 100%FREE&#xA;mkfs.ext4 /dev/vglab/lvorigin&#xA;Ora aggiungiamo il disco che farà da cache estendendo il gruppo di volumi:&#xA;creazione del device fisico di cache per il laboratorio&#xA;fallocate -l 500MiB fastdisk.img&#xA;&#xA;attach del dispositivo e estensione del gruppo di volumi&#xA;DEVFAST=$(losetup -Pf --show fastdisk.img)&#xA;vgextend vglab &#34;${DEVFAST}&#34;&#xA;Il cache pool lv può essere configurato automaticamente oppure manualente.&#xA;4.1. Caso 1: configurazione automatica del cache pool lv&#xA;In un unico passaggio, convertiamo il volume logico attuale in un volume logico con cache.&#xA;lvcreate \&#xA;  --type cache \&#xA;  --cachemode writethrough \&#xA;  -l 5%FREE \&#xA;  -n cachepool vglab/lvorigin &#34;${DEVFAST}&#34;&#xA;Dopo questo comando vedremo che il volume logico lv\origin incapsula il cache pool (lv\origincache\cpool) e il volume logico dei dati (lv\origin\corig).&#xA;&#xA;Il cache pool è composto da due volumi logici per i dati (lv\origincache\cpool\cdata) e i metadati (lv\origincache\cpool\cmeta).&#xA;&#xA;Infine distinguiamo anche il volume logico di metadati spare da utilizzare per un eventuale data recovery failure (lvol0\pmspare).&#xA;lvs -a&#xA;  LV                           VG        Attr       LSize   Pool                   Origin            Data%  Meta%  Move Log Cpy%Sync Convert&#xA;  home                         vgfedora -wi-ao---- 409,81g                                                           &#xA;  root                         vgfedora -wi-ao----  50,00g                                                           &#xA;  swap                         vgfedora -wi-ao----  16,00g                                                           &#xA;  lvorigin                    vglab    Cwi-a-C---  &lt;2,00g [lvorigincachecpool] [lvorigincorig] 0,00   0,59            0,00&#xA;  [lvorigincorig]            vglab    owi-aoC---  &lt;2,00g                                                           &#xA;  [lvorigincachecpool]       vglab    Cwi---C---   8,00m                                          0,00   0,59            0,00&#xA;  [lvorigincachecpoolcdata] vglab    Cwi-ao----   8,00m                                                           &#xA;  [lvorigincachecpoolcmeta] vglab    ewi-ao----   8,00m                                                           &#xA;  [lvol0pmspare]              vglab    ewi-------   8,00m &#xA;&#xA;4.2. Caso 2: configurazione manuale del cache pool lv&#xA;Se invece vogliamo intervenire su ogni singolo passaggio della creazione del cache pool:&#xA;creazione dei volumi logici meta e dati per il cache pool&#xA;lvcreate -n cachepoolmeta -L 10M vglab &#34;${DEVFAST}&#34;&#xA;lvcreate -n cachepool -l 5%FREE vglab &#34;${DEVFAST}&#34;&#xA;&#xA;creazione del cache pool assemblando meta e data&#xA;lvconvert \&#xA;  --type cache-pool \&#xA;  --cachemode writethrough \&#xA;  --poolmetadata vglab/cachepoolmeta vglab/cachepool&#xA;&#xA;conversione del volume logico origin nel nuovo volume logico con cache&#xA;lvconvert \&#xA;  --type cache \&#xA;  --cachepool vglab/cachepool vglab/lvorigin&#xA;In realtà è meglio lasciare a LVM il compito di dimensionare correttamente il volume per i metadati.&#xA;creazione della cache pool&#xA;lvcreate --type cache-pool -l 5%FREE -n cachecpool vglab &#34;${DEVFAST}&#34;&#xA;&#xA;conversione del volume logico originale in un volume logico con cache&#xA;lvconvert \&#xA;  --type cache \&#xA;  --cachepool vglab/cachecpool vglab/lvorigin&#xA;4.3. Switch della modalità&#xA;Per cambiare modalità fra writetrough e writeback (se non specificato nella definizione della cache pool, il default è writethrough).&#xA;lvchange --cachemode writeback vglab/lvorigin&#xA;4.4. Rimozione della cache&#xA;Se volessi levare il disco di cache e ritornare al volume logico di partenza:&#xA;lvconvert --uncache vglab/lvorigin&#xA;  Logical volume &#34;lvorigincachecpool&#34; successfully removed.&#xA;  Logical volume vglab/lvorigin is not cached.&#xA;e lvs -a mostra il volume logico in queste condizioni:&#xA;lvs -a&#xA;  LV        VG        Attr       LSize   Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert&#xA;  lvorigin vglab    -wi-a-----  &lt;2,00g&#xA;4.5. Monitoraggio&#xA;lvs -a -o lvname,lvsize,cachemode,datapercent,metadatapercent vglab&#xA;5. LVM Stripe&#xA;Analogo a Raid 0, l&#39;uso diretto di stripe in lvm  attraverso il mappatore interno dm-stripe, permette di definire su quali e quanti dischi va frammentata l&#39;informazione da memorizzare allo scopo di aumentare le prestazioni.&#xA;&#xA;Considerazioni:&#xA;&#xA;Il gruppo di volumi deve contenere almeno due dischi fisici.&#xA;È preferibile che i dischi fisici abbiano tutti la stessa velocità altrimenti quello più lento diventerà il collo di bottiglia.&#xA;È possibile che i &lt; n, dove i è il numero di dischi per  lo stripe e n è il numero totale di dischi del gruppo di volumi&#xA;È anche possibile specificare i dischi va applicato lo stripe.&#xA;La dimensione dello stripe è di 64K come default. Ma per file molto grandi, video o database, la dimensione può essere anche di 128K o 256K&#xA;&#xA;creazione di un gruppo di volumi con 3 dischi&#xA;vgcreate vglab /dev/sdb /dev/sdc /dev/sdd&#xA;&#xA;stripe su due dischi a caso di vglab&#xA;lvcreate -i 2 -I 64k -L 10G -n lvstripe vglab&#xA;&#xA;stripe su tutti i dischi di vglab&#xA;lvcreate -i 3 -I 64k -L 10G -n lvstripe vglab&#xA;&#xA;stripe sui dischi sdc e sdd con uno stripe size di 128K&#xA;lvcreate -i 2 -I 128k -L 10G -n lvstripe vglab /dev/sdc /dev/sdd&#xA;Come ogni raid 0, massime prestazioni e sicurezza 0. Se un disco si rompe, addio ai dati.&#xA;6. LVM Mirror&#xA;Come per lvm stripe analogo a raid 0, il mirror in lvm tramite il mappatore interno dm-mirror, è assimiliabile a raid 1.&#xA;&#xA;Come ogni raid 1 che si rispetti, il chiaro vantaggio di questo approccio è proprio la ridondanza dei dati che, al costo del sacrificio di un disco, permette di correre ai ripari se uno dei dischi si danneggia.&#xA;creazione di un gruppo di volumi con 2 dischi&#xA;vgcreate vglab /dev/sdb /dev/sdc&#xA;&#xA;creazione del volume logico &#34;mirror&#34;&#xA;lvcreate -m 1 -L 10G -n lvmirror vglab&#xA;Il mirror diretto attraverso LVM in realtà è considerato legacy. Si consiglia di usare l&#39;approccio più moderno che prevede di specificare il tipo, raid x, nell&#39;invocazione di lvcreate perché userà il modulo specializzato del kernel per il raid software.&#xA;&#xA;LVM mirror infatti pur essendo funzionalmente equivalente ad un raid 1 non è altrettanto efficace perché si basa su un log di sincronizzazione dove lvm tiene traccia degli elementi allineati.&#xA;&#xA;Tale log deve stare su un altro disco (che diventa un altro punto di vulnerabilità) e quando c&#39;è bisogno di ricostruire l&#39;array in caso di rottura di un disco, l&#39;operazione è molto lenta.&#xA;7. LVM Raid&#xA;Il raid lvm è un modo per prendere il meglio dei due mondi.&#xA;&#xA;Non è che LVM abbia una sua implementazione del raid.&#xA;Il raid &#34;tradizionale&#34; si basa sul sottosistema Multiple Devices del kernel e lavora direttamente sui dispositivi a blocchi.&#xA;&#xA;LVM si interfaccia direttamente con il modulo md del kernel per attingere alle funzioni di raid così da offrire, attraverso device mapper, un&#39;interfaccia unica per la gestione dei volumi e del raid.&#xA;7.1. Raid 0 (Stripe)&#xA;lvcreate --type raid0 -i 2 -I 64k -L 10G -n lvraid0 vglab&#xA;A differenza del mirror, non ci sono gli stessi problemi per stripe. Il mappatore nativo di LVM, dm-stripe, fa bene il suo lavoro.&#xA;&#xA;Usare lvmraid in questo caso resta vantaggioso per ragioni di coerenza. L&#39;uso del modulo md rende possibile un&#39;eventuale evoluzione verso livelli superiori (come RAID 1 o RAID 5).&#xA;7.2. Raid 1 (Mirroring)&#xA;L&#39;alternativa moderna al vecchio lvm mirror che risolve i suoi problemi di efficienza usando il modulo md.&#xA;&#xA;Basandoci sull&#39;esempio di prima:&#xA;lvcreate --type raid1 -m 1 -L 10G -n lvraid1 vglab&#xA;7.3. Raid 5 (Stripe con parità singola)&#xA;Creiamo un volume logico con RAID 5 basato su 4 dischi (stripe su 3 dischi e uno per la parità):&#xA;creazione di un gruppo di volumi con 4 dischi&#xA;vgcreate vglab /dev/sdb /dev/sdc /dev/sdd /dev/sde&#xA;&#xA;creazione del volume logico con RAID 5&#xA;lvcreate --type raid5 -i 3 -L 10G -n lvraid5 vglab&#xA;7.4. Raid 6 (Stripe con parità doppia)&#xA;Se vogliamo una parità doppia su 4 dischi (2 stripe e due di parità);&#xA;creazione di un gruppo di volumi con 4 dischi&#xA;vgcreate vglab /dev/sdb /dev/sdc /dev/sdd /dev/sde&#xA;&#xA;creazione del volume logico con RAID 5&#xA;lvcreate --type raid6 -i 2 -L 10G -n lvraid6 vglab&#xA;7.5. Raid 10&#xA;E veniamo al RAID 1+0, uno stripe su n array in mirror per combinare l&#39;efficienza dello stripe con la sicurezza del mirror:&#xA;creazione di un gruppo di volumi con 4 dischi&#xA;vgcreate vglab /dev/sdb /dev/sdc /dev/sdd /dev/sde&#xA;&#xA;creazione del volume logico con RAID 5&#xA;lvcreate --type raid10 -i 2 -m 1 -L 10G -n lvraid10 vglab&#xA;7.6. Come monitorare il raid&#xA;Metodo rapido:&#xA;lvs -o name,vgname,copypercent,lvattr,raidhealthstatus,devices vglab&#xA;&#xA;Combinandolo con watch posso vedere per es. la percentuale &#xA;di completamento della copia in caso di sostituzione del disco&#xA;watch -n 1 lvs -o name,vgname,copypercent,lvattr,raidhealthstatus,devices vglab&#xA;Metodo dettagliato:&#xA;lvdisplay vglab/lvraid5&#xA;Monitoraggio a basso livello:&#xA;Balamente, visto che viene usato il modulo md:&#xA;cat /proc/mdstat&#xA;7.7. Come intervenire in caso di guasto&#xA;Con lvs vedremo che lo stato del volume è diventato degraded.&#xA;Con pvpdisplay possiamo individuare il device danneggiato che comparirà come unknown device o con un sacco di errori I/O .&#xA;&#xA;Dopo aver estratto il disco e messo quello nuovo, supponendo sia /dev/sdc, procediamo con la ricostruzione dell&#39;array:&#xA;inizializzazione nuovo disco&#xA;pvcreate /dev/sdc&#xA;&#xA;aggiunta del nuovo disco al gruppo&#xA;vgextend vglab /dev/sdc&#xA;&#xA;array rebuild&#xA;lvconvert --repair vglab/lvraid5&#xA;&#xA;rimozione disco danneggiato dal gruppo di volumi&#xA;vgreduce --removemissing vglab&#xA;#lvm #dm #devicemapper #md #multipledevices #snapshot #thinpool #thinprovisioning #cachepool #raid #lvmraid]]&gt;</description>
      <content:encoded><![CDATA[<p><img src="https://pixelfed.uno/storage/m/_v2/489827599091373610/0d402c64b-2701fc/8LVsevJUK9RB/pIGAWHQBQQtrEFdtoftvYLD9uFIUaLRrpYrDYhz0.jpg" alt="lvm plus">
Oltre che alla grande flessibilità nella gestione dei volumi, LVM attraverso <strong>device mapper</strong>, aggiunge tutta una serie di ulteriori capacità che rendono questa tecnologia estremamente versatile.</p>

<p>La possibilità di disporre di meccanismi per la gestione di snapshot, cache pool. thin provisioning e raid, rendono LVM qualcosa di più di un gestore di volumi.
</p>
<ul><li><a href="#1-snapshot" rel="nofollow">1. Snapshot</a>
<ul><li><a href="#1-1-attenzione-dimensione-della-snapshot" rel="nofollow">1.1. Attenzione: Dimensione della snapshot</a></li>
<li><a href="#1-2-esempio" rel="nofollow">1.2. Esempio</a></li></ul></li>
<li><a href="#2-thin-pool" rel="nofollow">2. Thin Pool</a></li>
<li><a href="#3-thin-pool-e-snapshot" rel="nofollow">3. Thin Pool e snapshot</a></li>
<li><a href="#4-cache-pool" rel="nofollow">4. Cache Pool</a>
<ul><li><a href="#4-1-caso-1-configurazione-automatica-del-cache-pool-lv" rel="nofollow">4.1. Caso 1: configurazione automatica del cache pool lv</a></li>
<li><a href="#4-2-caso-2-configurazione-manuale-del-cache-pool-lv" rel="nofollow">4.2. Caso 2: configurazione manuale del cache pool lv</a></li>
<li><a href="#4-3-switch-della-modalit%C3%A0" rel="nofollow">4.3. Switch della modalità</a></li>
<li><a href="#4-4-rimozione-della-cache" rel="nofollow">4.4. Rimozione della cache</a></li>
<li><a href="#4-5-monitoraggio" rel="nofollow">4.5. Monitoraggio</a></li></ul></li>
<li><a href="#5-lvm-stripe" rel="nofollow">5. LVM Stripe</a></li>
<li><a href="#6-lvm-mirror" rel="nofollow">6. LVM Mirror</a></li>
<li><a href="#7-lvm-raid" rel="nofollow">7. LVM Raid</a>
<ul><li><a href="#7-1-raid-0-stripe" rel="nofollow">7.1. Raid 0 (Stripe)</a></li>
<li><a href="#7-2-raid-1-mirroring" rel="nofollow">7.2. Raid 1 (Mirroring)</a></li>
<li><a href="#7-3-raid-5-stripe-con-parit%C3%A0-singola" rel="nofollow">7.3. Raid 5 (Stripe con parità singola)</a></li>
<li><a href="#7-4-raid-6-stripe-con-parit%C3%A0-doppia" rel="nofollow">7.4. Raid 6 (Stripe con parità doppia)</a></li>
<li><a href="#7-5-raid-10" rel="nofollow">7.5. Raid 10</a></li>
<li><a href="#7-6-come-monitorare-il-raid" rel="nofollow">7.6. Come monitorare il raid</a></li>
<li><a href="#7-7-come-intervenire-in-caso-di-guasto" rel="nofollow">7.7. Come intervenire in caso di guasto</a></li></ul></li></ul>

<h2 id="1-snapshot">1. Snapshot</h2>

<p>Le snapshot LVM usano la tecnica del <strong>C</strong>opy-<strong>o</strong>n-<strong>W</strong>rite (<strong>CoW</strong>) allo scopo di ridurre la duplicazione.</p>

<p>La snapshot dovrà essre la fotografia del volume prima all&#39;origine.</p>

<p>Ad ogni modifica / cancellazione, il file originale verrà portato sulla snapshot prima dell&#39;operazione.
Sul volume originale verranno scritti tutti i dati nuovi e quelli modificati.</p>

<p>Per il <strong>ripristino</strong>, si effettua quello che si chiama <strong>merge</strong>, dove i dati vecchi vengono ripristinati dalla snapshot e quelli nuovi cancellati dal volume.</p>

<p>Per il consolidamento delle modifiche, basterò rimuovere la snapshot,</p>

<h3 id="1-1-attenzione-dimensione-della-snapshot">1.1. Attenzione: Dimensione della snapshot</h3>

<p>Se la snapshot ha la stessa dimensione del volume logico non ci sono problemi.</p>

<p>Se è più piccola, occorre prestare attenzione a che la quantità dei dati modificati sul volume logico non superino la dimensione della snapshot.</p>

<p>In questo caso infatti la snapshot risulterà inutilizzabile e non potrà più essere usata per il ripristino ma potrà essree solo rimossa.</p>

<h3 id="1-2-esempio">1.2. Esempio</h3>

<p>Supponiamo di avere un gruppo di volumi, <strong>my_vg</strong>, composto da 3 volumi logici:</p>
<ul><li><strong>lv_root</strong> (30 GiB)</li>
<li><strong>lv_home</strong> (200 GiB)</li>
<li><strong>lv_dati</strong> (500 GiB)</li></ul>

<p>e di voler creare una snapshot precauzionale sulla root (supponendo di avere spazio a sufficienza altrimenti dovrò fare bene i miei conti per non riempire oltremisura la snapshot rendendola inservibile).</p>

<p><strong>Creazione snapshot</strong></p>

<pre><code class="language-bash">lvcreate -s -L 30G -n  lv_root_snap my_vg/snap
</code></pre>

<p><strong>Ripristino</strong></p>

<pre><code class="language-bash">umount /dev/my_vg/lv_root
lvconvert --merge my_vg/snap
</code></pre>

<p><strong>Consolidamento</strong></p>

<pre><code class="language-bash">lvremove snap
</code></pre>

<h2 id="2-thin-pool">2. Thin Pool</h2>

<p>Il <strong>thin provisioning</strong> di LVM è l&#39;alternativa dinamica alla classica gestione di volumi, <strong>thick</strong>, che prevede l&#39;assegnazione statica delle dimensioni dei volumi.</p>

<p>Se è vero che il <strong>thick provisioning</strong> risulta comunque abbastastanza agevole per via della flessibilità intrinseca dei volumi in caso di riduzione o aumento della superficie allocabile, il <strong>thin provisioning</strong> può aumentare i vantaggi derivanti da LVM in alcuni scenari.</p>

<p>Il thin provisioning si basa sul principio che lo spazio assegnato ai volumi non viene usato mai completamente e mai tutto in una volta.</p>

<p>Ecco perché un&#39;allocazione dinamica ci permetterebbe di definire volumi che si riempiono <strong>solo</strong> man mano che lo spazio viene occupato.</p>

<p>Se si opta per un thin provisioning sarebbe opportuno non usare tutto il gruppo di volumi ma lasciarne un 20% in previsione di future espansioni.</p>

<p>Con i thin pool non solo abbiamo la stessa flessibilità della gestione thick, ma possiamo lavorare anche in <strong>over provisioning</strong> ossia creare pool di volumi la cui somma potenziale sia superiore allo spazio realmente allocabile.</p>

<p>Es. Supponiamo avere un device da 100 GiB, <code>/dev/sdb</code>, su cui definisco un volume group e creare un thin pool di 50 GiB. Su questo thin pool creeremo 3 volumi “virtuali” da 20, 30 e 20 GiB.</p>

<pre><code class="language-bash"># creazione volume group di 100 GiB
vgcreate vg_lab /dev/sdb

# creazione thin pool da 50 GiB
lvcreate -L 50G --thinpool vg_lab/lv_tp

# creazione dei 3 volumi virtuali in &#34;over provisioning&#34; 
lvcreate -V 20G --thin -n vol1_virt --thinpool vg_lab/lv_tp
lvcreate -V 30G --thin -n vol2_virt --thinpool vg_lab/lv_tp
lvcreate -V 20G --thin -n vol3_virt --thinpool vg_lab/lv_tp
</code></pre>

<p>Una volta creati i volumi possono essere formattati e montati come di consueto.</p>

<p>Lo spazio effettivamente occupato è quasi nullo, il sistema solleverà solo un warning per avvertirci che i volumi virtuali rischiano di saturare lo spazio disponibile.</p>

<p>Ecco perché bisogna prestare attenzione al raggiungimento della soglia critica.
Bisognerà estendere subito il thin pool ed i volumi virtuali nel <a href="https://cyberdynesystem.wordpress.com/2026/04/21/ridimensionare-volumi-lvm/#step-4-estendere-il-volume-logico" rel="nofollow">modo consueto</a>.</p>

<p>⚠️⚠️⚠️ <strong>ATTENZIONE</strong> ⚠️⚠️⚠️
L&#39;estensione di un volume virtuale non differisce molto da quello di un volume “classico”.
Se lo spazio per le fette si sta esaurendo, si estendono nell&#39;ordine:</p>
<ol><li>il gruppo di volumi (se necessario)</li>
<li>il thin pool (se nel volume group c&#39;è spazio a sufficienza)</li>
<li>i volumi virtuali</li>
<li>i filesystem</li></ol>

<p>Se non siamo con l&#39;acqua alla gola, i punti 3 e 4 sono sufficienti. L&#39;estensione del volume virtuale è più rapida di quella classica perché non viene allocato spazio.
L&#39;estensione di un volume logico classico corrisponde all&#39;estensione del thin pool.</p>

<p>Nel caso di riduzione, la situazione cambia parecchio perché la riduzione di un volume virtuale non fa guadagnare spazio allocabile visto che l&#39;ampiezza del volume è solo teorica, ciò avviene solo con <code>fstrim</code>.
Inoltre accorciando il volume virtuale al di sotto dei dati effettivamente scritti, si rischia di corrompere l&#39;intero filesystem.
<strong>Consiglio spassionato:</strong> ESTENDI SEMPRE E NON RIDURRE MAI!!!</p>

<p>Altra considerazione va fatta anche per i metadati.</p>

<p>A differenza dell&#39;LVM classico dove la creazione di un volume logico necessitava di un extent per i metadati, il thin provisioning di LVM riserva un volume logico per i dati e un volume logico per i metadati.</p>

<p>L&#39;estensione continua di piccole fette, può riempire il volume dei metadati col rischio di corrompere l&#39;intero thin pool e prima che succeda, anche il volume dei metadati può dover essere esteso.</p>

<pre><code class="language-bash">lvextend --poolmetadatasize +1G vg_lab/lv_tp
</code></pre>

<h2 id="3-thin-pool-e-snapshot">3. Thin Pool e snapshot</h2>

<p>Un altro bel vantaggio della modalità thin pool è quello di facilitare l&#39;uso delle snapshot.</p>

<p>Trattandosi di volumi virtuali, la dimensione della snapshot non ha bisogno di essere dichiarata. La creazione di snapshot è estremamente semplice.</p>

<pre><code class="language-bash"># creazione di una snapshot
lvcreate -s -n lv_snap vg_lab/vol_virt
</code></pre>

<p>Come pure sia la creazione di snapshot annidate che il rollback risultano molto più semplici ed efficienti.</p>

<pre><code class="language-bash"># creazione di una snapshot
lvcreate -s -n lv_snap1 vg_lab/vol_virt

# creazione di una snapshot annidata
lvcreate -s -n lv_snap2 vg_lab/lv_snap1

# rollback
umount vol_1
lvconvert --merge vg_lab/lv_snap2
mount -t ext4 -o defaults /dev/vg_lab/vol_virt vol_1
</code></pre>

<p>E a proposito di snapshot, occorre fare qualche osservazione.</p>

<p>Una serie di snapshot thin annidate, non è una catena di patch incrementali esposte al filesystem come si potrebbe pensare.
In virtù del CoW, la snapshot annidate fotograferanno sempre lo stesso istante: quello del file system all&#39;origine.</p>

<p>Facciamo un esempio:</p>

<pre><code class="language-bash">lvcreate -V 10g -T vgtest/thinpool -n vmroot
mkfs.ext4 /dev/vgtest/vmroot
mount /dev/vgtest/vmroot /mnt/test
echo ORIGINAL &gt; /mnt/test/file.txt
umount test

lvcreate -s -n snap1 vgtest/vmroot

mount /dev/vgtest/vmroot /mnt/test
echo MOD1 &gt; /mnt/test/file.txt
umount /mnt/test

lvcreate -s -n snap2 vgtest/snap1

mount /dev/vgtest/vmroot /mnt/test
echo MOD2 &gt; /mnt/test/file.txt
umount /mnt/test

lvcreate -s -n snap3 vgtest/snap2

mount /dev/vgtest/vmroot /mnt/test
echo MOD3 &gt; /mnt/test/file.txt
umount /mnt/test
</code></pre>

<p>In questo esempio creo un volume virtuale, <code>vmroot</code>, e 3 snap annidate.</p>
<ol><li>Monto il volume virtuale.</li>
<li>La prima snapshot, <code>snap1</code>, fotografa il file system del volume virtuale che contiene il file con “ORIGINAL”.</li>
<li>Il volume virtuale viene montato e il file viene modificato.</li>
<li>La seconda snapshot, <code>snap2</code>, fotografa <code>snap1</code> che <strong>a sua volta conteneva il file system del volume virtuale che contiene il file con “ORIGINAL”</strong>.</li>
<li>Il volume virtuale viene montato e il file viene modificato.</li>
<li>La terza snapshot, <code>snap3</code>, fotografa <code>snap2</code> che <strong>a sua volta conteneva snap1.. ecc.</strong></li></ol>

<p>Quindi snapshot siffatte non realizzano un versioning del file system come si potrebbe pensare, piuttosto possono essere utili per creare alberi di cloni/read-only, ambienti temporanei derivati da uno stato consistente, ecc.</p>

<p>In sostanza tornano utili quando ho una base da cui faccio derivare <em>n</em> snapshot che condividono i blocchi comune e con CoW minimizzo lo spazio.</p>

<p>Il merge di una qualunque snapshot ricondurrà il file system allo stato originario.</p>

<pre><code>origin
 ├── snap1
 ├── snap2
 ├── snap3
</code></pre>

<p>Per lavorare sul delta come immaginiamo, si dovranno montare via via le snapshop, non il volume virtuale, e modificare quelle.</p>

<pre><code class="language-bash">lvcreate -V 10g -T vgtest/thinpool -n vmroot
mkfs.ext4 /dev/vgtest/vmroot
mount /dev/vgtest/vmroot /mnt/test
echo ORIGINAL &gt; /mnt/test/file.txt
umount /mnt/test

lvcreate -s -n snap1 vgtest/vmroot

lvchange -ay -K vgtest/snap1
mount /dev/vgtest/snap1 /mnt/test
echo MOD1 &gt; /mnt/test/file.txt
umount /mnt/test

lvcreate -s -n snap2 vgtest/snap1

lvchange -ay -K vgtest/snap2
mount /dev/vgtest/snap2 /mnt/test
echo MOD2 &gt; /mnt/test/file.txt
umount /mnt/test

lvcreate -s -n snap3 vgtest/snap2

lvchange -ay -K vgtest/snap3
mount /dev/vgtest/snap3 /mnt/test
echo MOD3 &gt; /mnt/test/file.txt
umount /mnt/test
</code></pre>

<p>In questo modo si “inverte” la logica del merge che, prima riconduceva il file system allo stato inizale, ora invece consolida le modifiche delle snapshot</p>

<pre><code>origin
 └── snap1
      └── snap2
           └── snap3
</code></pre>

<p>Il merge va fatto in ordine se si vogliono acquisire correttamente i delta.
Tuttavia questo approccio</p>
<ul><li>è raro</li>
<li>è difficile da gestire</li>
<li>complica i merge</li>
<li>può creare dependency tree intricati</li></ul>

<p>Per questo quasi tutti:</p>
<ul><li>snapshot sempre dell’origin</li>
<li>mai snapshot di snapshot</li>
<li>rollback lineare</li></ul>

<h2 id="4-cache-pool">4. Cache Pool</h2>

<p>Il cache pool di LVM serve a migliorare l&#39;accesso a dispositivi tradizionalmente lenti e lo fa combinando dischi  HDD con SSD/NVMe.</p>

<p>In sostanza avremo un gruppo di volumi costituito dai dischi HDD e un altro gruppo di volumi costituito dai dischi SDD/NVMe, la nostra cache.</p>

<p>Il <strong>Logical Volume Cache</strong> sul disco veloce migliora l&#39;accesso ad uno specifico volume logico del disco lento e prevede il ricorso a tutta una serie di tipi di volumi logici abbastanza variegata:</p>
<ul><li><strong>Origin LV</strong>: volume logico orignale costituito dai dischi lenti</li>
<li><strong>Cache pool LV</strong>: volume logico composto  a sua volta da altri due voumi logici: dati della cache e metadati della cache
<ul><li><strong>Cache data LV</strong>: volume logico contenente i <strong>blocchi di dati</strong> per il <strong>Cache pool LV</strong>.</li>
<li><strong>Cache metadata LV</strong>: volume logico contenente i <strong>metadatati</strong> per il <strong>Cache pool LV</strong>.</li></ul></li>
<li><strong>Cache LV</strong>: volume logico contenente l&#39;<strong>Origin LV</strong> e Il <strong>Cache pool LV</strong>. È il volume realemente utilizzabile</li>
<li><strong>Spare metadata LV</strong>: volume logico correlato ad una funzione di recovery data failure</li></ul>

<p><img src="https://pixelfed.uno/storage/m/_v2/489827599091373610/0d402c64b-2701fc/ghjmK6oYuYls/Zt6F2X7EaV5JxGJ3ZsvML0XgUmFAPWjrC4BlHSAA.jpg" alt="cacheLVM.jpg"></p>

<p>Quando si crea una cache ho due possibilità a seconda che si voglia massimizzare velocità o affidabilità:</p>
<ul><li><strong>writethrough</strong>: Le operazioni di scrittura vengono inviate sia alla cache SSD che all&#39;Origin HDD. La lettura avviene preferibilmente dalla cache.
È la modalità più sicura. Se l&#39;SSD muore, nessun dato va perso ma è meno efficiente in scrittura perché Origin HDD diventa il collo di bottiglia,</li>
<li><strong>writeback</strong>: più veloce ma meno sicuro. Le scritture vengono salvate immediatamente sulla cache veloce e sincronizzate sull&#39;HDD in background in un secondo momento. Se si dovesse rompere il disco di cache, c&#39;è il rischio di una perdita di dati.</li></ul>

<p>Il dimensionamento della cache è proporzionale alla dimensione del disco origin.
Di solito si aggira in un range del 2-10%</p>
<ul><li>2%: archiviazione sequenziale, file di grandi dimensioni;</li>
<li>5%: <strong>standard consigliato</strong>. File server generico, utilizzo desktop/workstation;</li>
<li>10%: carichi di lavoro intensivi e casuali come database SQL/NoSQL attivi, nodi di virtualizzazione densi (molte VM), ecc.</li></ul>

<p>Non è necessario prevedere da subito Il disco di cache (se c&#39;è stata la possibilità tanto meglio), ma si può aggiungere in un secondo momento estendendo il gruppo di volumi contenente l&#39;HDD e battezzando l&#39;LV di cache.</p>

<p>Perpariamo il nostro laboratorio in cui abbiamo un HD lento con un unico volume logico a cui applichiamo una cache.</p>
<ul><li>disco lento: 2 GiB</li>
<li>disco veloce: 500 MiB</li>
<li>cache: 5% di 2 GiB (~100 MiB)</li></ul>

<pre><code class="language-bash"># creazione del device fisico per il laboratorio
fallocate -l 2GiB slow_disk.img

# attach del device e creazione del gruppo di volumi
vgcreate vg_lab $(losetup -Pf --show slow_disk.img)

# creazione e formattazione dell&#39;unico volume logico
lvcreate -n lv_origin vg_lab -l 100%FREE
mkfs.ext4 /dev/vg_lab/lv_origin
</code></pre>

<p>Ora aggiungiamo il disco che farà da cache estendendo il gruppo di volumi:</p>

<pre><code class="language-bash"># creazione del device fisico di cache per il laboratorio
fallocate -l 500MiB fast_disk.img

# attach del dispositivo e estensione del gruppo di volumi
DEV_FAST=$(losetup -Pf --show fast_disk.img)
vgextend vg_lab &#34;${DEV_FAST}&#34;
</code></pre>

<p>Il cache pool lv può essere configurato automaticamente oppure manualente.</p>

<h3 id="4-1-caso-1-configurazione-automatica-del-cache-pool-lv">4.1. Caso 1: configurazione automatica del cache pool lv</h3>

<p>In un unico passaggio, convertiamo il volume logico attuale in un volume logico con cache.</p>

<pre><code class="language-bash">lvcreate \
  --type cache \
  --cachemode writethrough \
  -l 5%FREE \
  -n cache_pool vg_lab/lv_origin &#34;${DEV_FAST}&#34;
</code></pre>

<p>Dopo questo comando vedremo che il volume logico <strong>lv_origin</strong> incapsula il cache pool (<strong>lv_origincache_cpool</strong>) e il volume logico dei dati (<strong>lv_origin_corig</strong>).</p>

<p>Il cache pool è composto da due volumi logici per i dati (<strong>lv_origincache_cpool_cdata</strong>) e i metadati (<strong>lv_origincache_cpool_cmeta</strong>).</p>

<p>Infine distinguiamo anche il volume logico di metadati spare da utilizzare per un eventuale data recovery failure (<strong>lvol0_pmspare</strong>).</p>

<pre><code class="language-bash">lvs -a
  LV                           VG        Attr       LSize   Pool                   Origin            Data%  Meta%  Move Log Cpy%Sync Convert
  home                         vg_fedora -wi-ao---- 409,81g                                                           
  root                         vg_fedora -wi-ao----  50,00g                                                           
  swap                         vg_fedora -wi-ao----  16,00g                                                           
  lv_origin                    vg_lab    Cwi-a-C---  &lt;2,00g [lv_origincache_cpool] [lv_origin_corig] 0,00   0,59            0,00
  [lv_origin_corig]            vg_lab    owi-aoC---  &lt;2,00g                                                           
  [lv_origincache_cpool]       vg_lab    Cwi---C---   8,00m                                          0,00   0,59            0,00
  [lv_origincache_cpool_cdata] vg_lab    Cwi-ao----   8,00m                                                           
  [lv_origincache_cpool_cmeta] vg_lab    ewi-ao----   8,00m                                                           
  [lvol0_pmspare]              vg_lab    ewi-------   8,00m 

</code></pre>

<h3 id="4-2-caso-2-configurazione-manuale-del-cache-pool-lv">4.2. Caso 2: configurazione manuale del cache pool lv</h3>

<p>Se invece vogliamo intervenire su ogni singolo passaggio della creazione del cache pool:</p>

<pre><code class="language-bash"># creazione dei volumi logici meta e dati per il cache pool
lvcreate -n cache_pool_meta -L 10M vg_lab &#34;${DEV_FAST}&#34;
lvcreate -n cache_pool -l 5%FREE vg_lab &#34;${DEV_FAST}&#34;

# creazione del cache pool assemblando meta e data
lvconvert \
  --type cache-pool \
  --cachemode writethrough \
  --poolmetadata vg_lab/cache_pool_meta vg_lab/cache_pool

# conversione del volume logico origin nel nuovo volume logico con cache
lvconvert \
  --type cache \
  --cachepool vg_lab/cache_pool vg_lab/lv_origin
</code></pre>

<p>In realtà è meglio lasciare a LVM il compito di dimensionare correttamente il volume per i metadati.</p>

<pre><code class="language-bash"># creazione della cache pool
lvcreate --type cache-pool -l 5%FREE -n cache_cpool vg_lab &#34;${DEV_FAST}&#34;

# conversione del volume logico originale in un volume logico con cache
lvconvert \
  --type cache \
  --cachepool vg_lab/cache_cpool vg_lab/lv_origin
</code></pre>

<h3 id="4-3-switch-della-modalità">4.3. Switch della modalità</h3>

<p>Per cambiare modalità fra <strong>writetrough</strong> e <strong>writeback</strong> (se non specificato nella definizione della cache pool, il default è <strong>writethrough</strong>).</p>

<pre><code class="language-bash">lvchange --cachemode writeback vg_lab/lv_origin
</code></pre>

<h3 id="4-4-rimozione-della-cache">4.4. Rimozione della cache</h3>

<p>Se volessi levare il disco di cache e ritornare al volume logico di partenza:</p>

<pre><code class="language-bash">lvconvert --uncache vg_lab/lv_origin
  Logical volume &#34;lv_origincache_cpool&#34; successfully removed.
  Logical volume vg_lab/lv_origin is not cached.
```https://noblogo.org/ebdpsbxxid/edit#publish
e `lvs -a` mostra il volume logico in queste condizioni:
```bash
lvs -a
  LV        VG        Attr       LSize   Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
  lv_origin vg_lab    -wi-a-----  &lt;2,00g
</code></pre>

<h3 id="4-5-monitoraggio">4.5. Monitoraggio</h3>

<pre><code class="language-bash">lvs -a -o lv_name,lv_size,cache_mode,data_percent,metadata_percent vg_lab
</code></pre>

<h2 id="5-lvm-stripe">5. LVM Stripe</h2>

<p>Analogo a <strong>Raid 0</strong>, l&#39;uso diretto di stripe in lvm  attraverso il mappatore interno <strong>dm-stripe</strong>, permette di definire su quali e quanti dischi va frammentata l&#39;informazione da memorizzare allo scopo di aumentare le prestazioni.</p>

<p><strong>Considerazioni:</strong></p>
<ul><li>Il gruppo di volumi deve contenere almeno due dischi fisici.</li>
<li>È preferibile che i dischi fisici abbiano tutti la stessa velocità altrimenti quello più lento diventerà il collo di bottiglia.</li>
<li>È possibile che <em>i</em> &lt; <em>n</em>, dove <em>i</em> è il numero di dischi per  lo stripe e <em>n</em> è il numero totale di dischi del gruppo di volumi</li>
<li>È anche possibile specificare i dischi va applicato lo stripe.</li>
<li>La dimensione dello stripe è di 64K come default. Ma per file molto grandi, video o database, la dimensione può essere anche di 128K o 256K</li></ul>

<pre><code class="language-bash"># creazione di un gruppo di volumi con 3 dischi
vgcreate vg_lab /dev/sdb /dev/sdc /dev/sdd

# stripe su due dischi a caso di vg_lab
lvcreate -i 2 -I 64k -L 10G -n lv_stripe vg_lab

# stripe su tutti i dischi di vg_lab
lvcreate -i 3 -I 64k -L 10G -n lv_stripe vg_lab

# stripe sui dischi sdc e sdd con uno stripe size di 128K
lvcreate -i 2 -I 128k -L 10G -n lv_stripe vg_lab /dev/sdc /dev/sdd
</code></pre>

<p>Come ogni raid 0, massime prestazioni e sicurezza 0. Se un disco si rompe, addio ai dati.</p>

<h2 id="6-lvm-mirror">6. LVM Mirror</h2>

<p>Come per <strong>lvm stripe</strong> analogo a <strong>raid 0</strong>, il <strong>mirror</strong> in lvm tramite il mappatore interno <strong>dm-mirror</strong>, è assimiliabile a <strong>raid 1</strong>.</p>

<p>Come ogni raid 1 che si rispetti, il chiaro vantaggio di questo approccio è proprio la ridondanza dei dati che, al costo del sacrificio di un disco, permette di correre ai ripari se uno dei dischi si danneggia.</p>

<pre><code class="language-bash"># creazione di un gruppo di volumi con 2 dischi
vgcreate vg_lab /dev/sdb /dev/sdc

# creazione del volume logico &#34;mirror&#34;
lvcreate -m 1 -L 10G -n lv_mirror vg_lab
</code></pre>

<p>Il mirror diretto attraverso LVM in realtà è considerato legacy. Si consiglia di usare l&#39;approccio più moderno che prevede di specificare il tipo, raid <em>x</em>, nell&#39;invocazione di <strong>lvcreate</strong> perché userà il modulo specializzato del kernel per il raid software.</p>

<p>LVM mirror infatti pur essendo funzionalmente equivalente ad un raid 1 non è altrettanto efficace perché si basa su un log di sincronizzazione dove lvm tiene traccia degli elementi allineati.</p>

<p>Tale log deve stare su un altro disco (che diventa un altro punto di vulnerabilità) e quando c&#39;è bisogno di ricostruire l&#39;array in caso di rottura di un disco, l&#39;operazione è molto lenta.</p>

<h2 id="7-lvm-raid">7. LVM Raid</h2>

<p>Il raid lvm è un modo per prendere il meglio dei due mondi.</p>

<p>Non è che LVM abbia una sua implementazione del raid.
Il raid “tradizionale” si basa sul sottosistema <strong>Multiple Devices</strong> del kernel e lavora direttamente sui dispositivi a blocchi.</p>

<p>LVM si interfaccia direttamente con il modulo <strong>md</strong> del kernel per attingere alle funzioni di raid così da offrire, attraverso <strong>device mapper</strong>, un&#39;interfaccia unica per la gestione dei volumi e del raid.</p>

<h3 id="7-1-raid-0-stripe">7.1. Raid 0 (Stripe)</h3>

<pre><code class="language-bash">lvcreate --type raid0 -i 2 -I 64k -L 10G -n lv_raid0 vg_lab
</code></pre>

<p>A differenza del mirror, non ci sono gli stessi problemi per stripe. Il mappatore nativo di LVM, <strong>dm-stripe</strong>, fa bene il suo lavoro.</p>

<p>Usare lvmraid in questo caso resta vantaggioso per ragioni di coerenza. L&#39;uso del modulo <strong>md</strong> rende possibile un&#39;eventuale evoluzione verso livelli superiori (come RAID 1 o RAID 5).</p>

<h3 id="7-2-raid-1-mirroring">7.2. Raid 1 (Mirroring)</h3>

<p>L&#39;alternativa moderna al vecchio lvm mirror che risolve i suoi problemi di efficienza usando il modulo <strong>md</strong>.</p>

<p>Basandoci sull&#39;esempio di prima:</p>

<pre><code class="language-bash">lvcreate --type raid1 -m 1 -L 10G -n lv_raid1 vg_lab
</code></pre>

<h3 id="7-3-raid-5-stripe-con-parità-singola">7.3. Raid 5 (Stripe con parità singola)</h3>

<p>Creiamo un volume logico con RAID 5 basato su 4 dischi (stripe su 3 dischi e uno per la parità):</p>

<pre><code class="language-bash"># creazione di un gruppo di volumi con 4 dischi
vgcreate vg_lab /dev/sdb /dev/sdc /dev/sdd /dev/sde

# creazione del volume logico con RAID 5
lvcreate --type raid5 -i 3 -L 10G -n lv_raid5 vg_lab
</code></pre>

<h3 id="7-4-raid-6-stripe-con-parità-doppia">7.4. Raid 6 (Stripe con parità doppia)</h3>

<p>Se vogliamo una parità doppia su 4 dischi (2 stripe e due di parità);</p>

<pre><code class="language-bash"># creazione di un gruppo di volumi con 4 dischi
vgcreate vg_lab /dev/sdb /dev/sdc /dev/sdd /dev/sde

# creazione del volume logico con RAID 5
lvcreate --type raid6 -i 2 -L 10G -n lv_raid6 vg_lab
</code></pre>

<h3 id="7-5-raid-10">7.5. Raid 10</h3>

<p>E veniamo al RAID 1+0, uno stripe su <em>n</em> array in mirror per combinare l&#39;efficienza dello stripe con la sicurezza del mirror:</p>

<pre><code class="language-bash"># creazione di un gruppo di volumi con 4 dischi
vgcreate vg_lab /dev/sdb /dev/sdc /dev/sdd /dev/sde

# creazione del volume logico con RAID 5
lvcreate --type raid10 -i 2 -m 1 -L 10G -n lv_raid10 vg_lab
</code></pre>

<h3 id="7-6-come-monitorare-il-raid">7.6. Come monitorare il raid</h3>

<p><strong>Metodo rapido:</strong></p>

<pre><code class="language-bash">lvs -o name,vg_name,copy_percent,lv_attr,raid_health_status,devices vg_lab

# Combinandolo con watch posso vedere per es. la percentuale 
# di completamento della copia in caso di sostituzione del disco
watch -n 1 lvs -o name,vg_name,copy_percent,lv_attr,raid_health_status,devices vg_lab
</code></pre>

<p><strong>Metodo dettagliato:</strong></p>

<pre><code class="language-bash">lvdisplay vg_lab/lv_raid5
</code></pre>

<p><strong>Monitoraggio a basso livello:</strong>
Balamente, visto che viene usato il modulo <strong>md</strong>:</p>

<pre><code class="language-bash">cat /proc/mdstat
</code></pre>

<h3 id="7-7-come-intervenire-in-caso-di-guasto">7.7. Come intervenire in caso di guasto</h3>

<p>Con <code>lvs</code> vedremo che lo stato del volume è diventato <code>degraded</code>.
Con <code>pvpdisplay</code> possiamo individuare il device danneggiato che comparirà come <code>unknown device</code> o con un sacco di errori I/O .</p>

<p>Dopo aver estratto il disco e messo quello nuovo, supponendo sia <code>/dev/sdc</code>, procediamo con la ricostruzione dell&#39;array:</p>

<pre><code class="language-bash"># inizializzazione nuovo disco
pvcreate /dev/sdc

# aggiunta del nuovo disco al gruppo
vgextend vg_lab /dev/sdc

# array rebuild
lvconvert --repair vg_lab/lv_raid5

# rimozione disco danneggiato dal gruppo di volumi
vgreduce --removemissing vg_lab
</code></pre>

<p><a href="/aytin/tag:lvm" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">lvm</span></a> <a href="/aytin/tag:dm" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">dm</span></a> <a href="/aytin/tag:devicemapper" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">devicemapper</span></a> <a href="/aytin/tag:md" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">md</span></a> <a href="/aytin/tag:multipledevices" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">multipledevices</span></a> <a href="/aytin/tag:snapshot" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">snapshot</span></a> <a href="/aytin/tag:thinpool" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">thinpool</span></a> <a href="/aytin/tag:thinprovisioning" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">thinprovisioning</span></a> <a href="/aytin/tag:cachepool" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">cachepool</span></a> <a href="/aytin/tag:raid" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">raid</span></a> <a href="/aytin/tag:lvmraid" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">lvmraid</span></a></p>
]]></content:encoded>
      <guid>https://noblogo.org/aytin/cose-molto-notevoli-su-lvm</guid>
      <pubDate>Mon, 25 May 2026 06:08:02 +0000</pubDate>
    </item>
    <item>
      <title>Ridimensionare volumi LVM</title>
      <link>https://noblogo.org/aytin/ridimensionare-volumi-lvm</link>
      <description>&lt;![CDATA[lvm&#xA;Supponiamo di avere 3 volumi logici, ad es. vol1, vol2, vol3 e di voler aumentare il secondo a discapito degli altri due.&#xA;&#xA;Un’esigenza analoga, su un filesystem partizionato in 3 parti in maniera canonica, è un mezzo incubo perché il ridimensionamento della partizione centrale prevede un discreto numero di salti mortali per manenere la contiguità e per non rischiare di lasciare buchetti inutilizzabili fra una partizione e l’altra. &#xA;!--more--&#xA;&#xA;1. Cose che è bene ricordare quando si manipolano i volumi logici&#xA;2. Scenario 1: Estensione e riduzione di volumi logici&#xA;   2.1. Step 0: curiosità&#xA;   2.2. Step 1: Smontare i dischi&#xA;   2.3. Step 2: Riduzione del filesystem&#xA;   2.4. Step 3: Ridimensionare i volumi logici&#xA;   2.5. Step 4: Estendere il volume logico&#xA;   2.6. Step 5: Bonus&#xA;3. Scenario 2: Estensione e riduzione di gruppi di volume&#xA;4. Conclusione&#xA;&#xA;Provo a buttare giù due righe su quello che mi verrebbe di fare:&#xA;&#xA;riduco la prima partizione&#xA;riduco la terza partizione&#xA;sposto la terza partizione fino alla fine del disco&#xA;sposto la seconda partizione fino alla fine della prima partizione&#xA;estendo la seconda partizione fino alla fine della prima&#xA;&#xA;Tutto questo tenendo presente che l’unità minima allocabile è il blocco (512 bytes) e che l’operazione che mi fa più paura è il move della partizione. parted non ha un comando “move” diretto. La procedura richiede di calcolare i nuovi settori, spostare i dati e aggiornare la tabella delle partizioni.&#xA;&#xA;Senza una GUI come quella di gparted, bisogna farsi letteralmente i conti con carta e penna prima di agire e c’è il rischio, comunque molto alto, di commettere errori che sarebbero disastrosi.&#xA;&#xA;LVM, al confronto, è una boccata d’ossigeno.&#xA;&#xA;LVM dà la possibilità di ridimensionare volumi in maniera più semplice rispetto al partizionamento più tradizionale perché la dimensione della partizione è disaccoppiata da concetti di contiguità e dalla geometria del disco.&#xA;&#xA;Nel caso del partizionamento tradizionale infatti le partizioni sono dei blocchi di settori consecutivi in cui ogni partizione inizia in un settore finisce in un altro.&#xA;&#xA;Con LVM invece l’approccio è radicalmente diverso. La minima unità allocabile è l’extent (default 4 MiB) che serve per mappare un volume fisico in un volume logico.&#xA;&#xA;Se immaginiamo che il volume fisico possa essere spezzettato in altrettanti extents in una sorta di “paniere”, il volume group, il volume logico non è altro che un insieme di questi extents pescati dal volume group (senza alcuna pretesa d’ordinamento) a cui posso:&#xA;&#xA;aggiungere extents prelevandoli dal volume group&#xA;levare extents riponendoli nel volume group (o assegnandoli ad altri volumi logici).&#xA;&#xA;Queste proprietà conferiscono una grande flessibilità alle operazioni di riduzione ed estensione dei volumi.&#xA;&#xA;1. Cose che è bene ricordare quando si manipolano i volumi logici.&#xA;&#xA;Partizioni&#xA;Quando si riduce o aumenta un filesystem, è bene smontare le partizioni e volumi logici.&#xA;&#xA;Ridurre un volume logico&#xA;Quando si riduce un volume logico, si deve:&#xA;&#xA;fare un check del filesystem&#xA;ridurre il filesystem&#xA;ridurre il volume logico&#xA;&#xA;Estendere un volume logico&#xA;Quando si aumenta un volume logico, al contrario, si deve:&#xA;&#xA;estendere il volume logico&#xA;estendere il filesystem&#xA;fare un check del filesystem&#xA;&#xA;Calcolare lo spazio allocabile&#xA;Un volume logico è composto da un insieme di extents, blocchi grandi di default 4 MiB, che sono la minima unità allocabile. Un volume logico è quindi sempre corrispondente ad un multiplo di 4 MiB, n extents di cui n\-1 allocabili, il rimanente per i metadati. Ad es. un volume logico di 2 GiB è composta da 512 extents di cui 511 allocabili.&#xA;&#xA;La potenza di due&#xA;Si deve tenere sempre presente che, nella matematica del calcolo dello spazio, si considerano le potenze di 2. Non di 10. Quindi un GiB equivale a 1024 MiB, non a 1000. Di conseguenza, se dividessi un GiB in due parti uguali avrei 2 blocchi da 512 MiB non da 500.&#xA;&#xA;Estensione e riduzione&#xA;Nelle istruzioni di estensione (lvextend) e riduzione (lvreduce) possiamo scegliere ciò che va specificato fra 4 modalità:&#xA;&#xA;il numero totale di extents&#xA;il delta in aggiunta o in diminuzione degli extents (a seconde che l’operazione sia rispettivamente di estensione o di riduzione)&#xA;la dimensione totale espressa in KiB-MiB-GiB-TiB&#xA;come prima, il delta in aggiunta o in diminuzione della dimensione espresso in KiB-MiB-GiB-TiB&#xA;&#xA;2. Scenario 1: Estensione e riduzione di volumi logici&#xA;Supponiamo di avere un disco da 2 GiB (2048 MiB) diviso in 3 volumi logici da 550 MiB, 350 MiB e 1148 MiB di e di volerne ridurre due per ampliare il terzo.&#xA;&#xA;Vogliamo ridurre il primo di 150 MiB, il terzo di 330 MiB e aumentare corrispondentemente il secondo volume di 480 MiB.&#xA;&#xA;Prepariamo il laboratorio col solito file appiccicato ad un loop device. Su quello definirò il volume group, il mio “paniere” di extents.&#xA;creazione device&#xA;fallocate -l 2GiB disk1.img&#xA;&#xA;creazione device e volum group&#xA;vgcreate vglab $(losetup -Pf --show disk1.img)&#xA;&#xA;creazione volumi logici&#xA;lvcreate -n lvlab1 vglab -L 550M&#xA;lvcreate -n lvlab2 vglab -L 350M&#xA;lvcreate -n lvlab3 vglab -l 100%FREE&#xA;&#xA;formattazione volumi logici&#xA;mkfs.ext4 /dev/vglab/lvlab1&#xA;mkfs.ext4 /dev/vglab/lvlab2&#xA;mkfs.ext4 /dev/vglab/lvlab3&#xA;&#xA;mount dei volumi&#xA;mkdir vol1 vol2 vol3&#xA;mount -t ext4 -o defaults /dev/vglab/lvlab1 vol1&#xA;mount -t ext4 -o defaults /dev/vglab/lvlab2 vol2&#xA;mount -t ext4 -o defaults /dev/vglab/lvlab3 vol3&#xA;2.1. Step 0: curiosità&#xA;Prima di cominciare esaminiamo un po’ di dati, ad es. di quanti extents sono composti i nostri oggetti.&#xA;pvdisplay /dev/loop9&#xA;  --- Physical volume ---&#xA;  PV Name               /dev/loop9&#xA;  VG Name               vglab&#xA;  PV Size               2,00 GiB / not usable 4,00 MiB&#xA;  Allocatable           yes (but full)&#xA;  PE Size               4,00 MiB&#xA;  Total PE              511&#xA;  Free PE               0&#xA;  Allocated PE          511&#xA;  PV UUID               YmLOru-bIdL-iqGb-vJfI-RsTk-yhv7-vSJhkX&#xA;pvdisplay mi dà informazioni sul disco fisico che andrò ad aggiungere nel volume group. Fra queste:&#xA;&#xA;PV Name: il nome del device, /dev/loop9&#xA;VG Name: è il nome del gruppo di volume, vglab, visibile solo perché abbiamo creato il gruppo di volume direttamente sul dispositivo invece che passare prima da pvcreate.&#xA;PV Size: 2 GiB, la dimensione del nostro “disco”&#xA;PE Size: dove PE sta Physical Extent, è di 4 MiB&#xA;Total PE sono i PE totali e sono 511, come previsto.&#xA;&#xA;vgdisplay vglab&#xA;  --- Volume group ---&#xA;  VG Name               vglab&#xA;  System ID&#xA;  Format                lvm2&#xA;  Metadata Areas        1&#xA;  Metadata Sequence No  1&#xA;  VG Access             read/write&#xA;  VG Status             resizable&#xA;  MAX LV                0&#xA;  Cur LV                0&#xA;  Open LV               0&#xA;  Max PV                0&#xA;  Cur PV                1&#xA;  Act PV                1&#xA;  VG Size               &lt;2,00 GiB&#xA;  PE Size               4,00 MiB&#xA;  Total PE              511&#xA;  Alloc PE / Size       0 / 0&#xA;  Free  PE / Size       511 / &lt;2,00 GiB&#xA;  VG UUID               6D89ck-c2Ni-XlMN-5Was-rh5j-vi2t-5juCXt&#xA;vgdisplay mi dà informazioni sul gruppo di volumi. Fra queste, disitnguiamo&#xA;&#xA;VG Name: il nome del volume group, già visto in pvdisplay, vglab&#xA;VG Size: la dimensione del volume group, minore di 2 GiB perché ci sono i metadati da considerari&#xA;PE Size: la dimensione di un extent, 4 MiB&#xA;Total PE / Size: Il numero totale di extent allocabili, che conferma VG Size, pari a 511 invece che 512.&#xA;Alloc PE: il numero totale di extent allocati, momento della creazione del volume group è 0&#xA;Free PE / Size: il numero totale di extent liberi, prima della creazione dei volumi logici è 511&#xA;&#xA;Cosa succede quando creerò i volumi logici? Che cambia il numero di PE liberi e allocati. Siccome userò tutti gli extent disponibili, i valori per Alloc PE e Free PE si invertiranno rispetto a prima.&#xA;&#xA;Infatti dopo la creazione dei volumi logici, vgdisplay mi dirà:&#xA;vgdisplay vglab&#xA;  --- Volume group ---&#xA;  VG Name               vglab&#xA;  ...&#xA;  Alloc PE / Size       511 / &lt;2,00 GiB&#xA;  Free  PE / Size       0 / 0&#xA;  ...  &#xA;511 extents allocati come confermato dai dati desumibili dei 3 volumi logici&#xA;lvdisplay vglab&#xA; --- Logical volume ---&#xA;  LV Path                /dev/vglab/lvlab1&#xA;  LV Name                lvlab1&#xA;  VG Name                vglab&#xA;...&#xA;  LV Size                552,00 MiB&#xA;  Current LE             138&#xA;...&#xA; --- Logical volume ---&#xA;  LV Path                /dev/vglab/lvlab2&#xA;  LV Name                lvlab2&#xA;  VG Name                vglab&#xA;...&#xA;  LV Size                352,00 MiB&#xA;  Current LE             88&#xA;...&#xA; --- Logical volume ---&#xA;  LV Path                /dev/vglab/lvlab3&#xA;  LV Name                lvlab2&#xA;  VG Name                vglab&#xA;...&#xA;  LV Size                1,11 GiB&#xA;  Current LE             285&#xA;...&#xA;Per il primo, il secondo e il terzo volume logico abbiamo rispettivamente:&#xA;&#xA;138, 88, 285 extents corrispondenti a&#xA;552 MiB, 352 MiB e 1140 MiB (1,11 GiB)&#xA;per un totale di 2044 MiB, al netto dei metadati.&#xA;&#xA;Possiamo notare subito che le dimensioni non corrispondono a quanto indicato in lvcreate.&#xA;lvcreate -n lvlab1 vglab -L 550M&#xA;lvcreate -n lvlab2 vglab -L 350M&#xA;lvcreate -n lvlab3 vglab -l 100%FREE&#xA;Questo succede perché vengono sempre approssimate all’extent più vicino. Ecco perché il primo e il secondo volume sono diventati di 552 (138 extents) e 352 MiB (88 extents).&#xA;&#xA;Sempre ricordando la particolarità dei multipli di 4 MiB legati a LVM, anche la riduzione di 150 MiB e di 330 MiB dei due volumi saranno approssimate sempre all’extent più vicino (152 MiB=38 extents e 332=83 extents). Questo dettaglio si rivelerà fondamentale quando dovremo ridimensionare il filesystem.&#xA;&#xA;Con questa rinnovata consapevolezza cominciamo a ridimensionare.&#xA;2.2. Step 1: Smontare i dischi&#xA;umount /dev/vglab/lvlab1&#xA;umount /dev/vglab/lvlab2&#xA;umount /dev/vglab/lvlab3&#xA;2.3. Step 2: Riduzione del filesystem&#xA;Se dovessi ridimensionare solo il filesystem, sarebbe sufficiente considerare dimensioni che siano potenze di 2 e non di 10.&#xA;&#xA;Ma sapendo che sotto c’è un LVM, sappiamo che per mantenere l’allineamento fra filesystem e volumi logici, oltre che potenze di due le dimensioni devono essere anche multipli di 4MiB.&#xA;&#xA;Ecco perché anche nel resize reale del filesystem non dovrò levare 150 MiB e 330 MiB ma 148 MiB (37 PE) e 328 (82 PE) (è buona norma approssimare per difetto all’extent più vicino per maggior prudenza) per un totale effettivo di 476 MiB (119 PE)&#xA;&#xA;Il filesystem del primo volume sarà dunque di 552 MiB - 148 MiB = 404 MiB. Il filesystem del terzo volume sarà di 1140 MiB - 328 MiB = 812 MiB.&#xA;check dei filesystem&#xA;e2fsck -f /dev/vglab/lvlab1&#xA;e2fsck -f /dev/vglab/lvlab2&#xA;e2fsck -f /dev/vglab/lvlab3&#xA;&#xA;Riduco il primo filesystem di 148 MiB&#xA;resize2fs /dev/vglab/lvlab1 404M&#xA;&#xA;Riduco il terzo filesystem di 328 MiB&#xA;resize2fs /dev/vglab/lvlab3 812M&#xA;2.4. Step 3: Ridimensionare i volumi logici&#xA;La riduzione del volume logico può essere fatta in 4 modi come sappiamo, ad es. sul primo volume:&#xA;il numero totale di extents, 138 PE - 37 PE = 101 PE&#xA;lvreduce -l 101 /dev/vglab/lvlab1 #oppure&#xA;&#xA;il numero di exrtents da sottrarre, 38 PE&#xA;lvreduce -l -37 /dev/vglab/lvlab1 #oppure&#xA;&#xA;la dimensione totale da ottenere, 404 MiB&#xA;lvreduce -L 404M /dev/vglab/lvlab1 #oppure&#xA;&#xA;il numero di MiB da sottrarre, 148 MiB&#xA;lvreduce -L -148M /dev/vglab/lvlab1 #oppure&#xA;Per maggior chiarezza userò il size assoluto in modo da farlo corrispondere a resize2fs&#xA;Riduco il primo volume logico di 148 Mib&#xA;lvreduce -L 404M /dev/vglab/lvlab1&#xA;&#xA;Riduco il terzo volume logico di 328 Mib&#xA;lvreduce -L 812M /dev/vglab/lvlab3&#xA;Verifichiamo quanti siano i PE residui&#xA;vgdisplay vglab | grep &#34;Free  PE&#34;&#xA; Free  PE / Size       119 / 476,00 MiB&#xA;119 extents, come previsto.&#xA;2.5. Step 4: Estendere il volume logico&#xA;Dopo aver ridotto il primo e il terzo volume, non ci rimane che estendere il secondo in base alla scaletta indicata prima:&#xA;&#xA;si estende il secondo volume logico&#xA;si estende il filesystem&#xA;si esegue il check fnale del filesystem&#xA;&#xA;L’estensione del volume, come ormai ben sappiamo, non sarà di 480 MiB ma di 476 MiB (37 PE + 82 PE = 119 PE) per via degli arrotondamenti effettuati nella riduzione degli altri volumi logici.&#xA;specifico gli extent che so essere residui&#xA;lvextend -l +119 /dev/vglab/lvlab2&#xA;o, equivalentemente&#xA;lvextend -L +476M /dev/vglab/lvlab2&#xA;&#xA;estendo il filesystem&#xA;resize2fs /dev/vglab/lvlab2 828M&#xA;&#xA;check filesystem&#xA;e2fsck -f /dev/vglab/lvlab2&#xA;2.6. Step 5: Bonus&#xA;Come premio per essere arrivato in fondo, posso rivelare come fare in un colpo solo tutte le operazioni descritte sopra.&#xA;&#xA;È vero che c&#39;è poco da considerare, giusto tenere a mente che su LVM ogni oggetto è multiplo di 4 MiB e che bisogna ridimensionare filesystem e volumi logici in ugual modo per non generare pericolose anomalie, ma tutte le operazioni che ho descritto nei passi 2-4 possono essere fatte con un unico comando che provvederà ad eseguire nell&#39;ordine corretto e con le giuste approssimazioni:&#xA;&#xA;il check del filesystem&#xA;il ridimensionamento del filesystem&#xA;il ridimensionamento dei volumi logici&#xA;&#xA;Dunque, tutto il pippone atomico precedente può essere condensato in un unico, solido comando:&#xA;Riduce il primo volume logico e il filesystem&#xA;lvreduce -r -L -150M /dev/vglab/lvlab1&#xA;&#xA;Riduce il terzo volume logico e il filesystem&#xA;lvreduce -r -L -330M /dev/vglab/lvlab3&#xA;&#xA;Estende il secondo volume logico e il filesystem&#xA;lvextend -r -l +119 /dev/vglab/lvlab2&#xA;Ora spieghiamo il perché soprattutto dell&#39;extend, che è interessante.&#xA;&#xA;Diciamo che è tutto molto guidato e le eventuali correzioni da apportare, senza spaccarsi troppo il cervello, sono suggerite con estrema chiarezza, basta leggere.&#xA;lvreduce -r -L -150M /dev/vglab/lvlab1&#xA; Rounding size to boundary between physical extents: 148.00 MiB.&#xA;  File system ext4 found on vglab/lvlab1.&#xA;  File system size (552.00 MiB) is larger than the requested size (404.00 MiB).&#xA;  File system reduce is required using resize2fs.&#xA;...&#xA;  Size of logical volume vglab/lvlab1 changed from 552.00 MiB (138 extents) to 404.00 MiB (101 extents).&#xA;  Logical volume vglab/lvlab1 successfully resized.&#xA;Ci dice innanzitutto che:&#xA;&#xA;c&#39;è stato un arrotondamento a 148 MiB (37 extents);&#xA;il filesystem è più grande del volume richiesto pertanto va subito ridimensionato;&#xA;infine si ridimensiona il volume logico da 552 MiB (138 extents) a 404 MiB (101 extents).&#xA;&#xA;Anche il secondo lvreduce ha un risultato analogo&#xA;lvreduce -r -L -330M /dev/vglab/lvlab3&#xA;  Rounding size to boundary between physical extents: 328.00 MiB.&#xA;  File system ext4 found on vglab/lvlab3.&#xA;  File system size (1.11 GiB) is larger than the requested size (812.00 MiB).&#xA;  File system reduce is required using resize2fs.&#xA;...&#xA;  Size of logical volume vglab/lvlab3 changed from 1.11 GiB (285 extents) to 812.00 MiB (203 extents).&#xA;  Logical volume vglab/lvlab3 successfully resized.&#xA;&#xA;anche qui abbiamo un arrotondamento a 328 MiB (82 extents);&#xA;il filesystem è più grande del volume richiesto pertanto va subito ridimensionato;&#xA;infine si ridimensiona il volume logico da 1140 MiB (285 extents) a 812 MiB (203 extents).&#xA;&#xA;È facilissimo desumere che la massima dimensione dell&#39;estensione sia 148 MiB + 328 MiB = 476 MiB (119 extents), basta fare una somma.&#xA;&#xA;Ma supponiamo di essere particolarmente distratti e proviamo ad estendere considerando le quantità iniziali: 150 MiB + 330 MiB = 480 MiB&#xA;lvextend -r -L +480M /dev/vglab/lvlab2&#xA;  File system ext4 found on vglab/lvlab2.&#xA;  File system fsck will be run before extend.&#xA;  Insufficient free space: 120 extents needed, but only 119 available&#xA;Nonostante la mia distrazione, come si può vedere, non si producono danni perché l&#39;ouput è categorico: &#34;non faccio nulla. Se vuoi, puoi aumentare al max di 476 MiB (119 extents)&#34;.&#xA;Non ci sono danni e anzi c&#39;è pure il suggerimento risolutivo.&#xA;&#xA;Ed ecco spiegato il mio extend di prima.&#xA;3. Scenario 2: Estensione e riduzione di gruppi di volume&#xA;Esaminiamo le possibilità di aggiungere o rimuovere dispositivi ad un volume group esistente.&#xA;&#xA;Ricreiamo il laboratorio partendo da 3 dischi, poi aggiungeremo due nuovi dischi e ne rimuoveremo altrettanti, il tutto senza intaccare l&#39;integrità dei dati.&#xA;&#xA;creazione di 5 device&#xA;for i in {1..5}: do fallocate -l 1GiB disk${i}.img; done&#xA;&#xA;creazione del gruppo di volumi con 3 device&#xA;vgcreate vglab \&#xA;  $(losetup -Pf --show disk1.img) \&#xA;  $(losetup -Pf --show disk2.img) \&#xA;  $(losetup -Pf --show disk3.img)&#xA;&#xA;crezione di 3 volumi logici&#xA;lvcreate -n lvlab1 vglab -l 300&#xA;lvcreate -n lvlab2 vglab -l 250&#xA;lvcreate -n lvlab3 vglab -l 100%FREE&#xA;&#xA;formattazione dei 3 dispositivi&#xA;mkfs.ext4 /dev/vglab/lvlab1&#xA;mkfs.ext4 /dev/vglab/lvlab2&#xA;mkfs.ext4 /dev/vglab/lvlab3&#xA;Ecco come sono distribuiti i volumi logici all&#39;interno dei dischi fisici&#xA;lsblk -o NAME,FSTYPE,SIZE,TYPE&#xA;  NAME               FSTYPE        SIZE      TYPE&#xA;  loop9              LVM2member     1G      loop&#xA;  └─vglab-lvlab1                1,2G      lvm&#xA;  loop10             LVM2member     1G      loop&#xA;  ├─vglab-lvlab1                1,2G      lvm&#xA;  └─vglab-lvlab3                860M      lvm&#xA;  loop11             LVM2member     1G      loop&#xA;  ├─vglab-lvlab2               1000M      lvm&#xA;  └─vglab-lvlab3                860M      lvm&#xA;Il gruppo di volumi è composto da 3 volumi fisici tutti attivi&#xA;vgdisplay vglab |grep PV&#xA;  Max PV                0&#xA;  Cur PV                3&#xA;  Act PV                3&#xA;Andiamo ad estendere il nostro gurppo di volumi con altri due device&#xA;vgextend vglab $(losetup -Pf --show disk4.img) $(losetup -Pf --show disk5.img)&#xA;I nuovi dischi sono visibili in fondo, come si può vedere anche da  vgdisplay che mostra i 5 dischi tutti attivi. &#xA;lsblk -o NAME,FSTYPE,SIZE,TYPE&#xA;  NAME               FSTYPE        SIZE      TYPE&#xA;  loop9              LVM2member     1G      loop&#xA;  └─vglab-lvlab1                1,2G      lvm&#xA;  loop10             LVM2member     1G      loop&#xA;  ├─vglab-lvlab1                1,2G      lvm&#xA;  └─vglab-lvlab3                860M      lvm&#xA;  loop11             LVM2member     1G      loop&#xA;  ├─vglab-lvlab2               1000M      lvm&#xA;  └─vglab-lvlab3                860M      lvmchan&#xA;  loop12             LVM2member     1G      loop&#xA;  loop13             LVM2member     1G      loop&#xA;&#xA;vgdisplay vglab |grep PV&#xA;  Max PV                0&#xA;  Cur PV                5&#xA;  Act PV                5&#xA;Potremo usare i nuovi dischi per estendere i volumi logici esistenti ma li impiegheremo invece per rimpiazzare i primi due dischi. &#xA;&#xA;pvmove distribuisce tutti gli extents del disco fra tutti i volumi fisici che hanno spazio a sufficienza. Se non dovesse essercene, restituirà un messaggio d&#39;errore.&#xA;pvmove /dev/loop9&#xA;  /dev/loop9: Moved: 3,14%&#xA;  /dev/loop9: Moved: 100,00%&#xA;Alla fine dell&#39;operazione il disco s&#39;è liberato di tutti i suoi extents e può essere rimosso&#xA;lsblk -o NAME,FSTYPE,SIZE,TYPE&#xA;  NAME               FSTYPE        SIZE      TYPE&#xA;  loop9              LVM2member     1G      loop&#xA;  loop10             LVM2member     1G      loop&#xA;  ├─vglab-lvlab1                1,2G      lvm&#xA;  └─vglab-lvlab3                860M      lvm&#xA;  loop11             LVM2member     1G      loop&#xA;  ├─vglab-lvlab2               1000M      lvm&#xA;  └─vglab-lvlab3                860M      lvm&#xA;  loop12             LVM2member     1G      loop&#xA;  └─vglab-lvlab1                1,2G      lvm&#xA;  loop13             LVM2member     1G      loop&#xA;Prima si estrae il volume fisico dal gruppo di volumi e poi si rimuove il volume fisico e così può essere scollegato.&#xA;vgreduce vglab /dev/loop9&#xA;pvremove /dev/loop9&#xA;Verifichiamo che il volume fisico non sia più presente.&#xA;vgdisplay vglab |grep PV&#xA;  Max PV                0&#xA;  Cur PV                4&#xA;  Act PV                4&#xA;Procediamo allo stesso modo col secondo disco.&#xA;pvmove /dev/loop10&#xA;  /dev/loop10: Moved: 9,80%&#xA;  /dev/loop10: Moved: 17,65%&#xA;  /dev/loop10: Moved: 100,00%&#xA;&#xA;vgreduce vglab /dev/loop10&#xA;  Removed &#34;/dev/loop10&#34; from volume group &#34;vglab&#34;&#xA;&#xA;pvremove /dev/loop10&#xA;  Labels on physical volume &#34;/dev/loop10&#34; successfully wiped.&#xA;In conclusione possiamo vedere il gruppo di volumi con solo 3 dischi, gli altri due completamente disimpegnati col gruppo di volumi ricostituitosi attorno ai 3 dischi rimanenti. E tutto spostando semplicemente gli extents dove c&#39;era disponibilità in maniera totalmente trasparente per il filesystem.&#xA;vgdisplay vglab |grep PV&#xA;  Max PV                0&#xA;  Cur PV                3&#xA;  Act PV                3&#xA;&#xA;lsblk -o NAME,FSTYPE,SIZE,TYPE&#xA;  NAME               FSTYPE        SIZE      TYPE&#xA;  loop9                              1G      loop&#xA;  loop10                             1G      loop&#xA;  loop11             LVM2member     1G      loop&#xA;  ├─vglab-lvlab2               1000M      lvm&#xA;  └─vglab-lvlab3                860M      lvm&#xA;  loop12             LVM2member     1G      loop&#xA;  └─vglab-lvlab1                1,2G      lvm&#xA;  loop13             LVM2member     1G      loop&#xA;  ├─vglab-lvlab1                1,2G      lvm&#xA;  └─vglab-lvlab_3                860M      lvm&#xA;4. Conclusione&#xA;Ho solo sfiorato la complessità e le capacità offerte da LVM.&#xA;&#xA;L&#39;estensione e la riduzione di volumi logici e di gruppi di volumi sono scenari di base. Tuttavia sono sufficienti per mostrare come sia semplice, con i volumi logici, compiere operazioni che con un filesystem partizionato in maniera classica sarebbero complicatissime.&#xA;&#xA;#lvm #volumegroup #logicalvolume #filesystem #devicemapper]]&gt;</description>
      <content:encoded><![CDATA[<p><img src="https://pixelfed.uno/storage/m/_v2/489827599091373610/31410d826-759a86/YynFD6sqFGzb/E2tgEVkaEtWT6Ucn0rqMrtk9qnJlr5p9nLl9m5pu.jpg" alt="lvm">
Supponiamo di avere 3 volumi logici, ad es. vol1, vol2, vol3 e di voler aumentare il secondo a discapito degli altri due.</p>

<p>Un’esigenza analoga, su un filesystem partizionato in 3 parti in maniera canonica, è un mezzo incubo perché il ridimensionamento della partizione centrale prevede un discreto numero di salti mortali per manenere la contiguità e per non rischiare di lasciare buchetti inutilizzabili fra una partizione e l’altra.
</p>
<ul><li><a href="#1-cose-che-%C3%A8-bene-ricordare-quando-si-manipolano-i-volumi-logici" rel="nofollow">1. Cose che è bene ricordare quando si manipolano i volumi logici</a></li>
<li><a href="#2-scenario-1-estensione-e-riduzione-di-volumi-logici" rel="nofollow">2. Scenario 1: Estensione e riduzione di volumi logici</a>
<ul><li><a href="#2-1-step-0-curiosit%C3%A0" rel="nofollow">2.1. Step 0: curiosità</a></li>
<li><a href="#2-2-step-1-smontare-i-dischi" rel="nofollow">2.2. Step 1: Smontare i dischi</a></li>
<li><a href="#2-3-step-2-riduzione-del-filesystem" rel="nofollow">2.3. Step 2: Riduzione del filesystem</a></li>
<li><a href="#2-4-step-3-ridimensionare-i-volumi-logici" rel="nofollow">2.4. Step 3: Ridimensionare i volumi logici</a></li>
<li><a href="#2-5-step-4-estendere-il-volume-logico" rel="nofollow">2.5. Step 4: Estendere il volume logico</a></li>
<li><a href="#2-6-step-5-bonus" rel="nofollow">2.6. Step 5: Bonus</a></li></ul></li>
<li><a href="#3-scenario-2-estensione-e-riduzione-di-gruppi-di-volume" rel="nofollow">3. Scenario 2: Estensione e riduzione di gruppi di volume</a></li>
<li><a href="#4-conclusione" rel="nofollow">4. Conclusione</a></li></ul>

<p>Provo a buttare giù due righe su quello che mi verrebbe di fare:</p>
<ol><li>riduco la prima partizione</li>
<li>riduco la terza partizione</li>
<li>sposto la terza partizione fino alla fine del disco</li>
<li>sposto la seconda partizione fino alla fine della prima partizione</li>
<li>estendo la seconda partizione fino alla fine della prima</li></ol>

<p>Tutto questo tenendo presente che l’unità minima allocabile è il blocco (512 bytes) e che l’operazione che mi fa più paura è il move della partizione. <code>parted</code> non ha un comando “move” diretto. La procedura richiede di calcolare i nuovi settori, spostare i dati e aggiornare la tabella delle partizioni.</p>

<p>Senza una GUI come quella di <strong>gparted</strong>, bisogna farsi letteralmente i conti con carta e penna prima di agire e c’è il rischio, comunque molto alto, di commettere errori che sarebbero disastrosi.</p>

<p>LVM, al confronto, è una boccata d’ossigeno.</p>

<p>LVM dà la possibilità di ridimensionare volumi in maniera più semplice rispetto al partizionamento più tradizionale perché la dimensione della partizione è disaccoppiata da concetti di contiguità e dalla geometria del disco.</p>

<p>Nel caso del partizionamento tradizionale infatti le partizioni sono dei blocchi di settori consecutivi in cui ogni partizione inizia in un settore finisce in un altro.</p>

<p>Con LVM invece l’approccio è radicalmente diverso. La minima unità allocabile è l’<strong>extent</strong> (default 4 MiB) che serve per mappare un volume fisico in un volume logico.</p>

<p>Se immaginiamo che il volume fisico possa essere spezzettato in altrettanti extents in una sorta di “paniere”, il <strong>volume group</strong>, il volume logico non è altro che un insieme di questi extents pescati dal volume group (senza alcuna pretesa d’ordinamento) a cui posso:</p>
<ul><li>aggiungere extents prelevandoli dal volume group</li>
<li>levare extents riponendoli nel volume group (o assegnandoli ad altri volumi logici).</li></ul>

<p>Queste proprietà conferiscono una grande flessibilità alle operazioni di riduzione ed estensione dei volumi.</p>

<h2 id="1-cose-che-è-bene-ricordare-quando-si-manipolano-i-volumi-logici">1. Cose che è bene ricordare quando si manipolano i volumi logici.</h2>

<p><strong>Partizioni</strong>
Quando si riduce o aumenta un filesystem, è bene smontare le partizioni e volumi logici.</p>

<p><strong>Ridurre un volume logico</strong>
Quando si riduce un volume logico, si deve:</p>
<ol><li>fare un check del filesystem</li>
<li>ridurre il filesystem</li>
<li>ridurre il volume logico</li></ol>

<p><strong>Estendere un volume logico</strong>
Quando si aumenta un volume logico, al contrario, si deve:</p>
<ol><li>estendere il volume logico</li>
<li>estendere il filesystem</li>
<li>fare un check del filesystem</li></ol>

<p><strong>Calcolare lo spazio allocabile</strong>
Un volume logico è composto da un <strong>insieme di extents</strong>, blocchi grandi di default 4 MiB, che sono la minima unità allocabile. Un volume logico è quindi <strong>sempre</strong> corrispondente ad un multiplo di 4 MiB, <em>n</em> extents di cui <em>n</em>-1 allocabili, il rimanente per i metadati. Ad es. un volume logico di 2 GiB è composta da 512 extents di cui <strong>511 allocabili</strong>.</p>

<p><strong>La potenza di due</strong>
Si deve tenere <strong>sempre</strong> presente che, nella matematica del calcolo dello spazio, si considerano le potenze di 2. Non di 10. Quindi un GiB equivale a 1024 MiB, non a 1000. Di conseguenza, se dividessi un GiB in due parti uguali avrei 2 blocchi da 512 MiB non da 500.</p>

<p><strong>Estensione e riduzione</strong>
Nelle istruzioni di estensione (<strong>lvextend</strong>) e riduzione (<strong>lvreduce</strong>) possiamo scegliere ciò che va specificato fra 4 modalità:</p>
<ol><li>il <strong>numero totale</strong> di extents</li>
<li>il <strong>delta</strong> in aggiunta o in diminuzione degli extents (a seconde che l’operazione sia rispettivamente di estensione o di riduzione)</li>
<li>la dimensione totale espressa in KiB-MiB-GiB-TiB</li>
<li>come prima, il delta in aggiunta o in diminuzione della dimensione espresso in KiB-MiB-GiB-TiB</li></ol>

<h2 id="2-scenario-1-estensione-e-riduzione-di-volumi-logici">2. Scenario 1: Estensione e riduzione di volumi logici</h2>

<p>Supponiamo di avere un disco da 2 GiB (2048 MiB) diviso in 3 volumi logici da <strong>550 MiB</strong>, <strong>350 MiB</strong> e <strong>1148 MiB</strong> di e di volerne ridurre due per ampliare il terzo.</p>

<p>Vogliamo ridurre il primo di <strong>150 MiB</strong>, il terzo di <strong>330 MiB</strong> e aumentare corrispondentemente il secondo volume di <strong>480 MiB</strong>.</p>

<p>Prepariamo il laboratorio col solito file appiccicato ad un loop device. Su quello definirò il volume group, il mio “paniere” di extents.</p>

<pre><code class="language-bash"># creazione device
fallocate -l 2GiB disk_1.img

# creazione device e volum group
vgcreate vg_lab $(losetup -Pf --show disk_1.img)

# creazione volumi logici
lvcreate -n lv_lab_1 vg_lab -L 550M
lvcreate -n lv_lab_2 vg_lab -L 350M
lvcreate -n lv_lab_3 vg_lab -l 100%FREE

# formattazione volumi logici
mkfs.ext4 /dev/vg_lab/lv_lab_1
mkfs.ext4 /dev/vg_lab/lv_lab_2
mkfs.ext4 /dev/vg_lab/lv_lab_3

# mount dei volumi
mkdir vol_1 vol_2 vol_3
mount -t ext4 -o defaults /dev/vg_lab/lv_lab_1 vol_1
mount -t ext4 -o defaults /dev/vg_lab/lv_lab_2 vol_2
mount -t ext4 -o defaults /dev/vg_lab/lv_lab_3 vol_3
</code></pre>

<h3 id="2-1-step-0-curiosità">2.1. Step 0: curiosità</h3>

<p>Prima di cominciare esaminiamo un po’ di dati, ad es. di quanti extents sono composti i nostri oggetti.</p>

<pre><code class="language-bash">pvdisplay /dev/loop9
  --- Physical volume ---
  PV Name               /dev/loop9
  VG Name               vg_lab
  PV Size               2,00 GiB / not usable 4,00 MiB
  Allocatable           yes (but full)
  PE Size               4,00 MiB
  Total PE              511
  Free PE               0
  Allocated PE          511
  PV UUID               YmLOru-bIdL-iqGb-vJfI-RsTk-yhv7-vSJhkX
</code></pre>

<p><code>pvdisplay</code> mi dà informazioni sul disco fisico che andrò ad aggiungere nel volume group. Fra queste:</p>
<ul><li><strong>PV Name</strong>: il nome del device, <strong>/dev/loop9</strong></li>
<li><strong>VG Name</strong>: è il nome del gruppo di volume, <strong>vg_lab</strong>, visibile solo perché abbiamo creato il gruppo di volume direttamente sul dispositivo invece che passare prima da <strong>pvcreate</strong>.</li>
<li><strong>PV Size</strong>: 2 GiB, la dimensione del nostro “disco”</li>
<li><strong>PE Size</strong>: dove <strong>PE</strong> sta <strong>P</strong>hysical <strong>E</strong>xtent, è di 4 MiB</li>
<li><strong>Total PE</strong> sono i PE totali e sono <strong>511</strong>, come previsto.</li></ul>

<pre><code class="language-bash">vgdisplay vg_lab
  --- Volume group ---
  VG Name               vg_lab
  System ID
  Format                lvm2
  Metadata Areas        1
  Metadata Sequence No  1
  VG Access             read/write
  VG Status             resizable
  MAX LV                0
  Cur LV                0
  Open LV               0
  Max PV                0
  Cur PV                1
  Act PV                1
  VG Size               &lt;2,00 GiB
  PE Size               4,00 MiB
  Total PE              511
  Alloc PE / Size       0 / 0
  Free  PE / Size       511 / &lt;2,00 GiB
  VG UUID               6D89ck-c2Ni-XlMN-5Was-rh5j-vi2t-5juCXt
</code></pre>

<p><code>vgdisplay</code> mi dà informazioni sul gruppo di volumi. Fra queste, disitnguiamo</p>
<ul><li><strong>VG Name</strong>: il nome del volume group, già visto in <code>pvdisplay</code>, <strong>vg_lab</strong></li>
<li><strong>VG Size</strong>: la dimensione del volume group, minore di 2 GiB perché ci sono i metadati da considerari</li>
<li><strong>PE Size</strong>: la dimensione di un extent, 4 MiB</li>
<li><strong>Total PE / Size</strong>: Il numero totale di extent allocabili, che conferma <strong>VG Size</strong>, pari a <strong>511</strong> invece che <strong>512</strong>.</li>
<li><strong>Alloc PE</strong>: il numero totale di extent allocati, momento della creazione del volume group è <strong>0</strong></li>
<li><strong>Free PE / Size</strong>: il numero totale di extent liberi, prima della creazione dei volumi logici è <strong>511</strong></li></ul>

<p>Cosa succede quando creerò i volumi logici? Che cambia il numero di PE liberi e allocati. Siccome userò tutti gli extent disponibili, i valori per <code>Alloc PE</code> e <code>Free PE</code> si invertiranno rispetto a prima.</p>

<p>Infatti dopo la creazione dei volumi logici, <code>vgdisplay</code> mi dirà:</p>

<pre><code class="language-bash">vgdisplay vg_lab
  --- Volume group ---
  VG Name               vg_lab
  ...
  Alloc PE / Size       511 / &lt;2,00 GiB
  Free  PE / Size       0 / 0
  ...  
</code></pre>

<p><strong>511 extents</strong> allocati come confermato dai dati desumibili dei 3 volumi logici</p>

<pre><code class="language-bash">lvdisplay vg_lab
 --- Logical volume ---
  LV Path                /dev/vg_lab/lv_lab_1
  LV Name                lv_lab_1
  VG Name                vg_lab
...
  LV Size                552,00 MiB
  Current LE             138
...
 --- Logical volume ---
  LV Path                /dev/vg_lab/lv_lab_2
  LV Name                lv_lab_2
  VG Name                vg_lab
...
  LV Size                352,00 MiB
  Current LE             88
...
 --- Logical volume ---
  LV Path                /dev/vg_lab/lv_lab_3
  LV Name                lv_lab_2
  VG Name                vg_lab
...
  LV Size                1,11 GiB
  Current LE             285
...
</code></pre>

<p>Per il primo, il secondo e il terzo volume logico abbiamo rispettivamente:</p>
<ul><li><strong>138, 88, 285 extents</strong> corrispondenti a</li>
<li><strong>552 MiB, 352 MiB e 1140 MiB (1,11 GiB)</strong></li>
<li>per un totale di <strong>2044 MiB</strong>, al netto dei metadati.</li></ul>

<p>Possiamo notare subito che le dimensioni non corrispondono a quanto indicato in <code>lvcreate</code>.</p>

<pre><code class="language-bash">lvcreate -n lv_lab_1 vg_lab -L 550M
lvcreate -n lv_lab_2 vg_lab -L 350M
lvcreate -n lv_lab_3 vg_lab -l 100%FREE
</code></pre>

<p>Questo succede perché vengono <strong>sempre</strong> approssimate all’extent più vicino. Ecco perché il primo e il secondo volume sono diventati di <strong>552</strong> (138 extents) e <strong>352 MiB</strong> (88 extents).</p>

<p>Sempre ricordando la particolarità dei multipli di 4 MiB legati a LVM, anche la riduzione di 150 MiB e di 330 MiB dei due volumi saranno approssimate sempre all’extent più vicino (<strong>152 MiB=38 extents</strong> e <strong>332=83 extents</strong>). Questo dettaglio si rivelerà fondamentale quando dovremo ridimensionare il filesystem.</p>

<p>Con questa rinnovata consapevolezza cominciamo a ridimensionare.</p>

<h3 id="2-2-step-1-smontare-i-dischi">2.2. Step 1: Smontare i dischi</h3>

<pre><code class="language-bash">umount /dev/vg_lab/lv_lab_1
umount /dev/vg_lab/lv_lab_2
umount /dev/vg_lab/lv_lab_3
</code></pre>

<h3 id="2-3-step-2-riduzione-del-filesystem">2.3. Step 2: Riduzione del filesystem</h3>

<p>Se dovessi ridimensionare solo il filesystem, sarebbe sufficiente considerare dimensioni che siano potenze di 2 e non di 10.</p>

<p>Ma sapendo che sotto c’è un LVM, sappiamo che per mantenere l’allineamento fra filesystem e volumi logici, oltre che potenze di due le dimensioni devono essere anche multipli di 4MiB.</p>

<p>Ecco perché <strong>anche</strong> nel resize reale del filesystem non dovrò levare <strong>150 MiB</strong> e <strong>330 MiB</strong> ma <strong>148 MiB (37 PE)</strong> e <strong>328 (82 PE)</strong> (è buona norma approssimare per difetto all’extent più vicino per maggior prudenza) per un totale effettivo di <strong>476 MiB (119 PE)</strong></p>

<p>Il filesystem del primo volume sarà dunque di <em>552 MiB – 148 MiB = 404 MiB</em>. Il filesystem del terzo volume sarà di <em>1140 MiB – 328 MiB = 812 MiB</em>.</p>

<pre><code class="language-bash"># check dei filesystem
e2fsck -f /dev/vg_lab/lv_lab_1
e2fsck -f /dev/vg_lab/lv_lab_2
e2fsck -f /dev/vg_lab/lv_lab_3

# Riduco il primo filesystem di 148 MiB
resize2fs /dev/vg_lab/lv_lab_1 404M

# Riduco il terzo filesystem di 328 MiB
resize2fs /dev/vg_lab/lv_lab_3 812M
</code></pre>

<h3 id="2-4-step-3-ridimensionare-i-volumi-logici">2.4. Step 3: Ridimensionare i volumi logici</h3>

<p>La riduzione del volume logico può essere fatta in 4 modi come sappiamo, ad es. sul primo volume:</p>

<pre><code class="language-bash"># il numero totale di extents, 138 PE - 37 PE = 101 PE
lvreduce -l 101 /dev/vg_lab/lv_lab_1 #oppure

# il numero di exrtents da sottrarre, 38 PE
lvreduce -l -37 /dev/vg_lab/lv_lab_1 #oppure

# la dimensione totale da ottenere, 404 MiB
lvreduce -L 404M /dev/vg_lab/lv_lab_1 #oppure

# il numero di MiB da sottrarre, 148 MiB
lvreduce -L -148M /dev/vg_lab/lv_lab_1 #oppure
</code></pre>

<p>Per maggior chiarezza userò il size assoluto in modo da farlo corrispondere a <code>resize2fs</code></p>

<pre><code class="language-bash"># Riduco il primo volume logico di 148 Mib
lvreduce -L 404M /dev/vg_lab/lv_lab_1

# Riduco il terzo volume logico di 328 Mib
lvreduce -L 812M /dev/vg_lab/lv_lab_3
</code></pre>

<p>Verifichiamo quanti siano i PE residui</p>

<pre><code class="language-bash">vgdisplay vg_lab | grep &#34;Free  PE&#34;
 Free  PE / Size       119 / 476,00 MiB
</code></pre>

<p>119 extents, come previsto.</p>

<h3 id="2-5-step-4-estendere-il-volume-logico">2.5. Step 4: Estendere il volume logico</h3>

<p>Dopo aver ridotto il primo e il terzo volume, non ci rimane che estendere il secondo in base alla scaletta indicata prima:</p>
<ol><li>si estende il secondo volume logico</li>
<li>si estende il filesystem</li>
<li>si esegue il check fnale del filesystem</li></ol>

<p>L’estensione del volume, come ormai ben sappiamo, non sarà di <strong>480 MiB</strong> ma di <strong>476 MiB (37 PE + 82 PE = 119 PE)</strong> per via degli arrotondamenti effettuati nella riduzione degli altri volumi logici.</p>

<pre><code class="language-bash"># specifico gli extent che so essere residui
lvextend -l +119 /dev/vg_lab/lv_lab_2
# o, equivalentemente
# lvextend -L +476M /dev/vg_lab/lv_lab_2

# estendo il filesystem
resize2fs /dev/vg_lab/lv_lab_2 828M

# check filesystem
e2fsck -f /dev/vg_lab/lv_lab_2
</code></pre>

<h3 id="2-6-step-5-bonus">2.6. Step 5: Bonus</h3>

<p>Come premio per essere arrivato in fondo, posso rivelare come fare in un colpo solo tutte le operazioni descritte sopra.</p>

<p>È vero che c&#39;è poco da considerare, giusto tenere a mente che su LVM ogni oggetto è multiplo di 4 MiB e che bisogna ridimensionare filesystem e volumi logici in ugual modo per non generare pericolose anomalie, ma tutte le operazioni che ho descritto nei passi 2-4 possono essere fatte con un unico comando che provvederà ad eseguire nell&#39;ordine corretto e con le giuste approssimazioni:</p>
<ul><li>il check del filesystem</li>
<li>il ridimensionamento del filesystem</li>
<li>il ridimensionamento dei volumi logici</li></ul>

<p>Dunque, tutto il pippone atomico precedente può essere condensato in un unico, solido comando:</p>

<pre><code class="language-bash"># Riduce il primo volume logico e il filesystem
lvreduce -r -L -150M /dev/vg_lab/lv_lab_1

# Riduce il terzo volume logico e il filesystem
lvreduce -r -L -330M /dev/vg_lab/lv_lab_3

# Estende il secondo volume logico e il filesystem
lvextend -r -l +119 /dev/vg_lab/lv_lab_2
</code></pre>

<p>Ora spieghiamo il perché soprattutto dell&#39;extend, che è interessante.</p>

<p>Diciamo che è tutto molto guidato e le eventuali correzioni da apportare, senza spaccarsi troppo il cervello, sono suggerite con estrema chiarezza, basta leggere.</p>

<pre><code class="language-bash">lvreduce -r -L -150M /dev/vg_lab/lv_lab_1
 Rounding size to boundary between physical extents: 148.00 MiB.
  File system ext4 found on vg_lab/lv_lab_1.
  File system size (552.00 MiB) is larger than the requested size (404.00 MiB).
  File system reduce is required using resize2fs.
...
  Size of logical volume vg_lab/lv_lab_1 changed from 552.00 MiB (138 extents) to 404.00 MiB (101 extents).
  Logical volume vg_lab/lv_lab_1 successfully resized.
</code></pre>

<p>Ci dice innanzitutto che:</p>
<ul><li>c&#39;è stato un arrotondamento a <strong>148 MiB (37 extents)</strong>;</li>
<li>il filesystem è più grande del volume richiesto pertanto va subito ridimensionato;</li>
<li>infine si ridimensiona il volume logico da <strong>552 MiB (138 extents)</strong> a <strong>404 MiB (101 extents)</strong>.</li></ul>

<p>Anche il secondo <code>lvreduce</code> ha un risultato analogo</p>

<pre><code class="language-bash">lvreduce -r -L -330M /dev/vg_lab/lv_lab_3
  Rounding size to boundary between physical extents: 328.00 MiB.
  File system ext4 found on vg_lab/lv_lab_3.
  File system size (1.11 GiB) is larger than the requested size (812.00 MiB).
  File system reduce is required using resize2fs.
...
  Size of logical volume vg_lab/lv_lab_3 changed from 1.11 GiB (285 extents) to 812.00 MiB (203 extents).
  Logical volume vg_lab/lv_lab_3 successfully resized.
</code></pre>
<ul><li>anche qui abbiamo un arrotondamento a <strong>328 MiB (82 extents)</strong>;</li>
<li>il filesystem è più grande del volume richiesto pertanto va subito ridimensionato;</li>
<li>infine si ridimensiona il volume logico da <strong>1140 MiB (285 extents)</strong> a <strong>812 MiB (203 extents)</strong>.</li></ul>

<p>È facilissimo desumere che la massima dimensione dell&#39;estensione sia <strong>148 MiB + 328 MiB = 476 MiB (119 extents)</strong>, basta fare una somma.</p>

<p>Ma supponiamo di essere particolarmente distratti e proviamo ad estendere considerando le quantità iniziali: 150 MiB + 330 MiB = <strong>480 MiB</strong></p>

<pre><code class="language-bash">lvextend -r -L +480M /dev/vg_lab/lv_lab_2
  File system ext4 found on vg_lab/lv_lab_2.
  File system fsck will be run before extend.
  Insufficient free space: 120 extents needed, but only 119 available
</code></pre>

<p>Nonostante la mia distrazione, come si può vedere, non si producono danni perché l&#39;ouput è categorico: “non faccio nulla. Se vuoi, puoi aumentare al max di 476 MiB (119 extents)”.
Non ci sono danni e anzi c&#39;è pure il suggerimento risolutivo.</p>

<p>Ed ecco spiegato il mio extend di prima.</p>

<h2 id="3-scenario-2-estensione-e-riduzione-di-gruppi-di-volume">3. Scenario 2: Estensione e riduzione di gruppi di volume</h2>

<p>Esaminiamo le possibilità di aggiungere o rimuovere dispositivi ad un volume group esistente.</p>

<p>Ricreiamo il laboratorio partendo da 3 dischi, poi aggiungeremo due nuovi dischi e ne rimuoveremo altrettanti, il tutto senza intaccare l&#39;integrità dei dati.</p>

<pre><code class="language-bash"># creazione di 5 device
for i in {1..5}: do fallocate -l 1GiB disk_${i}.img; done

# creazione del gruppo di volumi con 3 device
vgcreate vg_lab \
  $(losetup -Pf --show disk_1.img) \
  $(losetup -Pf --show disk_2.img) \
  $(losetup -Pf --show disk_3.img)

# crezione di 3 volumi logici
lvcreate -n lv_lab_1 vg_lab -l 300
lvcreate -n lv_lab_2 vg_lab -l 250
lvcreate -n lv_lab_3 vg_lab -l 100%FREE

# formattazione dei 3 dispositivi
mkfs.ext4 /dev/vg_lab/lv_lab_1
mkfs.ext4 /dev/vg_lab/lv_lab_2
mkfs.ext4 /dev/vg_lab/lv_lab_3
</code></pre>

<p>Ecco come sono distribuiti i volumi logici all&#39;interno dei dischi fisici</p>

<pre><code class="language-bash">lsblk -o NAME,FSTYPE,SIZE,TYPE
  NAME               FSTYPE        SIZE      TYPE
  loop9              LVM2_member     1G      loop
  └─vg_lab-lv_lab_1                1,2G      lvm
  loop10             LVM2_member     1G      loop
  ├─vg_lab-lv_lab_1                1,2G      lvm
  └─vg_lab-lv_lab_3                860M      lvm
  loop11             LVM2_member     1G      loop
  ├─vg_lab-lv_lab_2               1000M      lvm
  └─vg_lab-lv_lab_3                860M      lvm
</code></pre>

<p>Il gruppo di volumi è composto da 3 volumi fisici tutti attivi</p>

<pre><code class="language-bash">vgdisplay vg_lab |grep PV
  Max PV                0
  Cur PV                3
  Act PV                3
</code></pre>

<p>Andiamo ad estendere il nostro gurppo di volumi con altri due device</p>

<pre><code class="language-bash">vgextend vg_lab $(losetup -Pf --show disk_4.img) $(losetup -Pf --show disk_5.img)
</code></pre>

<p>I nuovi dischi sono visibili in fondo, come si può vedere anche da  <code>vgdisplay</code> che mostra i 5 dischi tutti attivi.</p>

<pre><code class="language-bash">lsblk -o NAME,FSTYPE,SIZE,TYPE
  NAME               FSTYPE        SIZE      TYPE
  loop9              LVM2_member     1G      loop
  └─vg_lab-lv_lab_1                1,2G      lvm
  loop10             LVM2_member     1G      loop
  ├─vg_lab-lv_lab_1                1,2G      lvm
  └─vg_lab-lv_lab_3                860M      lvm
  loop11             LVM2_member     1G      loop
  ├─vg_lab-lv_lab_2               1000M      lvm
  └─vg_lab-lv_lab_3                860M      lvmchan
  loop12             LVM2_member     1G      loop
  loop13             LVM2_member     1G      loop

vgdisplay vg_lab |grep PV
  Max PV                0
  Cur PV                5
  Act PV                5
</code></pre>

<p>Potremo usare i nuovi dischi per estendere i volumi logici esistenti ma li impiegheremo invece per rimpiazzare i primi due dischi.</p>

<p><code>pvmove</code> distribuisce tutti gli extents del disco fra tutti i volumi fisici che hanno spazio a sufficienza. Se non dovesse essercene, restituirà un messaggio d&#39;errore.</p>

<pre><code class="language-bash">pvmove /dev/loop9
  /dev/loop9: Moved: 3,14%
  /dev/loop9: Moved: 100,00%
</code></pre>

<p>Alla fine dell&#39;operazione il disco s&#39;è liberato di tutti i suoi extents e può essere rimosso</p>

<pre><code class="language-bash">lsblk -o NAME,FSTYPE,SIZE,TYPE
  NAME               FSTYPE        SIZE      TYPE
  loop9              LVM2_member     1G      loop
  loop10             LVM2_member     1G      loop
  ├─vg_lab-lv_lab_1                1,2G      lvm
  └─vg_lab-lv_lab_3                860M      lvm
  loop11             LVM2_member     1G      loop
  ├─vg_lab-lv_lab_2               1000M      lvm
  └─vg_lab-lv_lab_3                860M      lvm
  loop12             LVM2_member     1G      loop
  └─vg_lab-lv_lab_1                1,2G      lvm
  loop13             LVM2_member     1G      loop
</code></pre>

<p>Prima si estrae il volume fisico dal gruppo di volumi e poi si rimuove il volume fisico e così può essere scollegato.</p>

<pre><code class="language-bash">vgreduce vg_lab /dev/loop9
pvremove /dev/loop9
</code></pre>

<p>Verifichiamo che il volume fisico non sia più presente.</p>

<pre><code class="language-bash">vgdisplay vg_lab |grep PV
  Max PV                0
  Cur PV                4
  Act PV                4
</code></pre>

<p>Procediamo allo stesso modo col secondo disco.</p>

<pre><code class="language-bash">pvmove /dev/loop10
  /dev/loop10: Moved: 9,80%
  /dev/loop10: Moved: 17,65%
  /dev/loop10: Moved: 100,00%

vgreduce vg_lab /dev/loop10
  Removed &#34;/dev/loop10&#34; from volume group &#34;vg_lab&#34;

pvremove /dev/loop10
  Labels on physical volume &#34;/dev/loop10&#34; successfully wiped.
</code></pre>

<p>In conclusione possiamo vedere il gruppo di volumi con solo 3 dischi, gli altri due completamente disimpegnati col gruppo di volumi ricostituitosi attorno ai 3 dischi rimanenti. E tutto spostando semplicemente gli extents dove c&#39;era disponibilità in maniera totalmente trasparente per il filesystem.</p>

<pre><code class="language-bash">vgdisplay vg_lab |grep PV
  Max PV                0
  Cur PV                3
  Act PV                3


lsblk -o NAME,FSTYPE,SIZE,TYPE
  NAME               FSTYPE        SIZE      TYPE
  loop9                              1G      loop
  loop10                             1G      loop
  loop11             LVM2_member     1G      loop
  ├─vg_lab-lv_lab_2               1000M      lvm
  └─vg_lab-lv_lab_3                860M      lvm
  loop12             LVM2_member     1G      loop
  └─vg_lab-lv_lab_1                1,2G      lvm
  loop13             LVM2_member     1G      loop
  ├─vg_lab-lv_lab_1                1,2G      lvm
  └─vg_lab-lv_lab_3                860M      lvm
</code></pre>

<h2 id="4-conclusione">4. Conclusione</h2>

<p>Ho solo sfiorato la complessità e le capacità offerte da LVM.</p>

<p>L&#39;estensione e la riduzione di volumi logici e di gruppi di volumi sono scenari di base. Tuttavia sono sufficienti per mostrare come sia semplice, con i volumi logici, compiere operazioni che con un filesystem partizionato in maniera classica sarebbero complicatissime.</p>

<p><a href="/aytin/tag:lvm" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">lvm</span></a> <a href="/aytin/tag:volumegroup" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">volumegroup</span></a> <a href="/aytin/tag:logicalvolume" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">logicalvolume</span></a> <a href="/aytin/tag:filesystem" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">filesystem</span></a> <a href="/aytin/tag:devicemapper" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">devicemapper</span></a></p>
]]></content:encoded>
      <guid>https://noblogo.org/aytin/ridimensionare-volumi-lvm</guid>
      <pubDate>Mon, 20 Apr 2026 21:13:18 +0000</pubDate>
    </item>
    <item>
      <title>Come aumentare il volume di una traccia audio</title>
      <link>https://noblogo.org/aytin/come-aumentare-il-volume-di-una-traccia-audio</link>
      <description>&lt;![CDATA[normalizzazione&#xA;Quando si deve aumentare il volume di una traccia audio, si deve ricorrere a ad un&#39;operazione di &#34;normalizzazione&#34;.&#xA;!--more--&#xA;&#xA;1. Cos’è la normalizzazione&#xA;2. Come misurare il &#34;picco&#34;?&#xA;3. Come leggere correttamente questa misura&#xA;   3.1. Perché usare il loudness invece di RMS?&#xA;4. Come ti normalizzo il file&#xA;  4.1. Peak normalization&#xA;  4.2. Loudness Normalization&#xA;     4.2.1. Loudness Normalization statica (ffmpeg)&#xA;     4.2.2. Loudness Normalization dinamica&#xA;     4.2.3. Loudness Normalization statica (rsgain)&#xA;&#xA;1. Cos&#39;è la normalizzazione&#xA;La normalizzazione è un&#39;operazione lineare che consiste nell&#39;analisi del file audio, nel calcolare la differenza (offset) fra il volume attuale ed un volume target, nell&#39;applicare una correzione di guadagno (Gain).&#xA;&#xA;La normalizzazione può essere distinta in base  al &#34;come&#34; e al &#34;dove&#34;.&#xA;&#xA;Il &#34;come&#34;&#xA;La normalizzazione classica si basa sui picchi. Cerca il punto più alto della forma d&#39;onda e lo porta a un valore massimo (es. 0 dB). Ignora la percezione umana; un brano con un singolo &#34;click&#34; molto forte risulterà comunque silenzioso perché quel picco blocca l&#39;aumento del volume.&#xA;&#xA;La normalizzazione più moderna si basa sui LUFS, ossia su come, mediamente, l&#39;audio viene effettivamente percepito dall&#39;orecchio umano (psicoacustica). Porta l&#39;intero brano a un livello di pressione sonora media costante, rendendo l&#39;ascolto uniforme tra diverse tracce.&#xA;&#xA;Il &#34;dove&#34;&#xA;Quando si normalizza una traccia audio si può scegliere di farla modificando ogni singolo sample della traccia audio oppure di agire sui metadati.&#xA;&#xA;Nel primo caso il file originale viene modificato (ricodifica quasi sempre lossy), nel secondo viene lasciato inalterato.&#xA;&#xA;Altro fattore di cui tenere conto è che una normalizzazione lossy funziona su ogni player, una normalizzazione che agisce sui metadati funziona solo se il player è in grado di leggerli.&#xA;&#xA;Possiamo fare quindi una prima distinzione:&#xA;&#xA;normalizzazione di picco (RMS) o iPeak Normalization/i: applicazione di un guadagno statico (RMS) in modalità lossy: non altera la dinamica del brano, richiede una ricodifica;&#xA;normalizzazione della sonorità (LUFS) o iLoudness Normalization/i:&#xA;   applicazione di un guadagno statico (LUFS) in modalità lossy: non altera la dinamica del brano, richiede una ricodifica;&#xA;   applicazione di un guadagno statico (LUFS) basato su tag: non altera la dinamica del brano, lascia il file inalterato (rsgain);&#xA;   agisce con un compressore / limiter in modalità lossy: altera la dinamica del brano, richiede una ricodifica.&#xA;&#xA;A questo punto la domanda diventa: quale scegliere?&#xA;&#xA;Per quel che mi riguarda, la salomonica risposta è: dipende.&#xA;&#xA;Come si può immaginare, non c&#39;è una risposta definitiva ma dipende dalla qualità della traccia, dal contesto ecc.&#xA;2. Come misurare il &#34;picco&#34;?&#xA;C&#39;è bisogno di un elemento misurabile che mi permetta di capire come agire con la normalizzazione.&#xA;&#xA;RMS (Root Mean Square): è un calcolo matematico asciutto su quanto sia potente elettricamente/digitalmente il segnale audio. È utile per capire l&#39;energia costante, ma non tiene conto del fatto che l&#39;orecchio umano è più sensibile ad alcune frequenze rispetto ad altre.&#xA;&#xA;LUFS (Loudness Units Full Scale): È lo standard moderno (EBU R128). Simula l&#39;udito umano applicando dei filtri che pesano maggiormente le frequenze medie.&#xA;&#xA;Per misurare il picco RMS posso ricorrere ad ffmpeg&#xA;ffmpeg -hidebanner -i &#34;audio.m4a&#34; -filter:a &#34;volumedetect&#34; -f null -&#xA;...&#xA;[...] nsamples: 18522112&#xA;[...] meanvolume: -20.3 dB&#xA;[...] maxvolume: -5.4 dB&#xA;[...] histogram5db: 40&#xA;[...] histogram6db: 1436&#xA;[...] histogram7db: 6443&#xA;[...] histogram8db: 18606&#xA;...&#xA;che mi mostrerà:&#xA;&#xA;il numero dei samples di cui si compone la traccia&#xA;il volume medio (meanvolume)&#xA;il picco (maxvolume)&#xA;&#xA;Il picco mi dice di quanto possa alzare il volume (fino al limite fisico di 0dB) staticamente senza causare distorsioni.&#xA;&#xA;La differenza fra volume medio e picco mi dà informazioni sulla dinamica del brano. Maggiore è la differenza, maggiore è la dinamica. Tipicamente:&#xA;&#xA;valori &lt; 5 sono tipici della musica dance, forte, uniforme, e molto compressa.&#xA;valori fra 5 e 15 sono tipici di brani pop-rock, ben bilanciati&#xA;valori   15 sono attribuibili a brani di musica classica, jazz, con una dinamica ricca.&#xA;&#xA;Per misurare il loudness, sempre con ffmpeg:&#xA;ffmpeg -hidebanner -i &#34;audio.m4a&#34; -filter:a &#34;ebur128=peak=true&#34; -f null - &#xA;...&#xA; Integrated loudness:&#xA;    I:         -18.1 LUFS&#xA;    Threshold: -28.4 LUFS&#xA;&#xA;  Loudness range:&#xA;    LRA:         4.1 LU&#xA;    Threshold: -38.3 LUFS&#xA;    LRA low:   -21.2 LUFS&#xA;    LRA high:  -17.1 LUFS&#xA;&#xA;  True peak:&#xA;    Peak:       -5.4 dBFS&#xA;La misurazione è più articolata rispetto alla precedente.&#xA;&#xA;FFmpeg innanzitutto mostra due sezioni: Integrated Loudness, rappresentante il volume medio complessivo del file e la Loudness Range che mi descrive la dinamica del brano come differenza di volume fra le parti più silenziose e quelle più rumorose.&#xA;&#xA;Sezione Integrated loudness:&#xA;   I: è il valore più importante. È il volume medio percepito dell&#39;intero brano (come si può vedere, diverso rispetto all&#39;RMS di prima. Il primo è pura potenza digitale, il secondo è volume percepito).&#xA;   Threshold: è la soglia usata per evitare che i silenzi abbassino artificialmente la media del volume. L&#39;algoritmo ignora tutto ciò che sta sotto questa soglia nel calcolo dell&#39;Integrated Loudness.&#xA;Sezione Loudness range:&#xA;   LRA: è un indice della variazione dinamica del brano. Più è basso, più il suono tende ad essere uniforme e probabilmente compresso&#xA;   Threshold: come prima, è la soglia oltre la quale i suoni vengono ignorati nel calcolo del range dinamico.&#xA;   LRA Low: indica il limite inferiore del loudness&#xA;   LRA High: indica il limite superiorebr&#xA;   quindi LRA = LRA High - LRA Low&#xA;Sezione True peak:&#xA;   Peak: Simile al max\volume dell&#39;RMS, indica il picco reale del brano in termini di sonorità.&#xA;&#xA;Un altro modo, forse meno pratico ma decisamente più scenografico, per analizzare un file audio è questo:&#xA;ffplay -f lavfi -i &#34;amovie=audio.m4a,ebur128=video=1:meter=18 out0&#34;&#xA;Disegna un grafico dell&#39;onda sonora in tempo reale.&#xA;3. Come leggere correttamente questa misura&#xA;L&#39;integrated loudness mi dice qual è il volume medio del brano.&#xA;True peak mi dice di quanto posso alzare prima di distorcere.&#xA;Queste sono le due informazioni cruciali sufficienti per applicare un guadagno statico senza fare danni.&#xA;&#xA;I valori High e Low del Loudness Range, che racchiudono asintoticamente il brano, tornano utili quando bisogna agire sulla dinamica.&#xA;&#xA;Notare che Integrated loudness è sempre compreso fra LRA Low e LRA High.&#xA;3.1. Perché usare il loudness invece di RMS?&#xA;L&#39;RMS è un calcolo puramente matematico che non tiene conto del fatto che l&#39;orecchio umano è molto più sensibile alle frequenze medie che non ai bassi estemi e agli acuti altissimi.&#xA;&#xA; A questo provvede il LUFS che è un&#39;evoluzione dell&#39;RMS perché include dei filtri di ponderazione che, prima di calcolare la media, esaltano le frequenze medie attenuando quelle basse.&#xA;&#xA;La conseguenza è che se agisco sul volume dei brani prendendo LUFS come riferimento, questi suoneranno tutti allo stesso volume. Se considerassi un adeguamento basato su RMS, i brani con più bassi sembreranno avere meno volume di quelli con frequenze medie più marcate. &#xA;4. Come ti normalizzo il file&#xA;La scelta fra una normalizzazione di picco e una di volume (loudness) è abbastanza semplice in realtà.&#xA;&#xA;A parte poche eccezioni in cui può avere senso avere RMS come riferimento, è sempre preferibile una normalizzazione della sonorità.&#xA;&#xA;Quest&#39;ultima può essere fatta modificando solo i metadati o agendo chirurgicamente sul file ricodificandolo.&#xA;4.1. Peak normalization&#xA;Una volta noti i dati di Max Volume e Mean Volume visti in precedenza, la normalizzazione è piuttosto semplice.&#xA;&#xA;Supponendo Max Volume = 6dB&#xA;ffmpeg -i audio.m4a -filter:a &#34;volume=6dB&#34; -c:a aac -b:a 192k audionormalized.m4a&#xA;Dovendo ricodificare, scelgo un bitrate piuttosto alto per limitare la perdita fisiologica di una ricodifica lossy.&#xA;&#xA;Come si può immaginare, è una aggiunta lineare secca a tutta la traccia a cui aumento solo la potenza digitale senza tenere conto della percezione sonora.&#xA;&#xA;Piccola nota: Conviene scegliere un valore che si avvicini, ma non equivalga, al limite di 0 dB perché altrimenti FFmpeg taglierà brutalmente le creste dell&#39;onda sonora che superano lo zero, creando quella tipica distorsione metallica grattata chiamata clipping.&#xA;&#xA;4.2. Loudness Normalization&#xA;La normalizzazione di volume, in base alla nostra scelta di alterare o meno la dinamica del brano, può essere fatta come detto applicando:&#xA;&#xA;un guadagno statico LUFS (lossy)&#xA;un guadagno statico LUFS sui metadati (non lossy)&#xA;compressore / limiter (sempre lossy) &#xA;&#xA;Il guadagno statico, quello con i metadati, avverrà con rsgain.&#xA;&#xA;La normalizzazione con perdita di qualità (lossy) avverrà con ffmpeg usando il filtro loudnorm che dispone di un compressore/limiter piuttosto efficace.&#xA;&#xA;Questo filtro è un processore dinamico (dual-pass o single-pass). Non si limita ad alzare il volume; se trova una parte troppo forte, può comprimere leggermente solo quella parte per permettere al resto della canzone di suonare più forte.&#xA;&#xA;loudnorm porta il loudness di default a -24 LUFS che è lo standard per il broadcast televisivo.&#xA;&#xA;I colossi dello streaming applicano automaticamente un loudness decisamente più marcato, salvo poche eccezioni, non si discostano da -14 LUFS. Ad es. Youtube, Amazon Music, Spotify, Soundcloud viaggiano mediamente su -14 LUFS, Deezer -15, Apple Music -16.&#xA;&#xA;Si può verificare facilmente, come sappiamo fare, come un audio presente su una di queste piattaforme, abbia uno dei loudness indicati.&#xA;&#xA;4.2.1. Loudness Normalization statica (ffmpeg)&#xA;Riprendiamo l&#39;esempio di prima.&#xA;ffmpeg -hidebanner -i &#34;audio.m4a&#34; -filter:a &#34;ebur128=peak=true&#34; -f null - &#xA;...&#xA; Integrated loudness:&#xA;    I:         -18.1 LUFS&#xA;    Threshold: -28.4 LUFS&#xA;&#xA;  Loudness range:&#xA;    LRA:         4.1 LU&#xA;    Threshold: -38.3 LUFS&#xA;    LRA low:   -21.2 LUFS&#xA;    LRA high:  -17.1 LUFS&#xA;&#xA;  True peak:&#xA;    Peak:       -5.4 dBFS&#xA;Con ffmpeg e loudnorm in modalità single-pass, posso applicare un guadagno statico 5.4 dBFS, con un true peak di -1 (Il default è -2), per arrivare, da -18.1 LUFS, a -13.0 LUFS senza distorsioni.&#xA;ffmpeg -i audio.m4a -filter:a &#34;loudnorm=I=-12.7:TP=-1.0&#34; -c:a aac -b:a 160k -vn audionorm.m4a&#xA;Verifichiamo:&#xA;ffmpeg -hidebanner -i &#34;audio.m4a&#34; -filter:a &#34;ebur128=peak=true&#34; -f null - &#xA;...&#xA;   Integrated loudness:&#xA;    I:         -12.5 LUFS&#xA;    Threshold: -22.6 LUFS&#xA;&#xA;  Loudness range:&#xA;    LRA:         4.0 LU&#xA;    Threshold: -32.6 LUFS&#xA;    LRA low:   -15.1 LUFS&#xA;    LRA high:  -11.1 LUFS&#xA;&#xA;  True peak:&#xA;    Peak:       -0.4 dBFS&#xA;...&#xA;Come si vede, sono arrivato al limite, forse un po&#39; troppo, del guadagno che potevo ottenere. Probabimente su dispositivi economici, l&#39;analogico di un brano così potrebbe gracchiare un po&#39;.&#xA;&#xA;Se avessi applicato il default  di  loudnorm, la sonorità sarebbe stata livellata sui -24 LUFS con una soglia true peak pari a -2 dBFS.&#xA;4.2.2. Loudness Normalization dinamica&#xA;Nei casi in cui:&#xA;&#xA;si vuole enfatizzare l&#39;audio di un podcast, di un parlato in generale;&#xA;la dinamica del brano è composta da picchi altissimi e una sonorità media molto bassa (un guadagno statico farebbe cambiare poco o nulla)&#xA;&#xA;con ffmpeg e loudnorm possiamo correggere ogni singolo sample del brano per rendere la dinamica più uniforme.&#xA;&#xA;Per ottenere un risultato ottimale, si deve procedere col dual-pass, in cui ffmpeg nel primo passaggio analizza il file e raccoglie i dati, nel secondo passaggio applica le correzioni puntualmente avendo già conoscenza della dinamica e dei picchi presenti nel file.&#xA;ffmpeg -i &#34;audio.m4a&#34; -filter:a &#34;loudnorm=I=-14:TP=-1.0:printformat=json&#34; -f null -&#xA;Ecco il json risultante dall&#39;analisi. I valori di input sono quelli che forniremo a ffmepg affinché possa impostare il loudness scelto da noi nel miglior modo possibile&#xA;{&#xA;&#x9;&#34;inputi&#34; : &#34;-18.17&#34;,&#xA;&#x9;&#34;inputtp&#34; : &#34;-5.41&#34;,&#xA;&#x9;&#34;inputlra&#34; : &#34;4.20&#34;,&#xA;&#x9;&#34;inputthresh&#34; : &#34;-28.47&#34;,&#xA;&#x9;&#34;outputi&#34; : &#34;-13.36&#34;,&#xA;&#x9;&#34;outputtp&#34; : &#34;-1.00&#34;,&#xA;&#x9;&#34;outputlra&#34; : &#34;4.30&#34;,&#xA;&#x9;&#34;outputthresh&#34; : &#34;-23.50&#34;,&#xA;&#x9;&#34;normalizationtype&#34; : &#34;dynamic&#34;,&#xA;&#x9;&#34;targetoffset&#34; : &#34;-0.64&#34;&#xA;}&#xA;Configurazione ffmpeg.&#xA;ffmpeg -i &#34;audio.m4a&#34; -filter:a &#34;loudnorm=I=-14:TP=-1.0:measuredI=-18.17:measuredTP=-5.41:measuredLRA=4.20:measuredthresh=-23.50:linear=true&#34; -c:a aac -b:a 160k -vn &#34;audionorm.m4a&#34;&#xA;Il compressore/limiter del filtro loudnorm è abbastanza intelligente da schiacciare i picchi affinche il guadagno di volume non produca clipping e alzerà le parti più &#34;deboli&#34;, livellando il suono e alterando la dinamica.&#xA;&#xA;4.2.3. Loudness Normalization statica (rsgain)&#xA;Rsgain permette di applicare un guadagno statico loseless, senza ricodifica, agendo sui metadati del brano con l&#39;applicazione dei tag.&#xA;&#xA;Se da un lato questo metodo ha l&#39;indubbio vantaggio di non alterare fisicamente il file, dall&#39;altro è necessario che il player che eseguirà il brano dovra essere capace di leggere e interpretare i tag. Nel caso precedente, la ricodifica rende il file disponibile per chiunque.&#xA;&#xA;Trattandosi di un guadagno statico, il campo d&#39;applicazione è quello visto per la Peak Normalization, cioè quando si vuole preservare la dinamica del brano, Ma nei casi particolari cui accennavo in precedenza, presenza di picchi altissimi e maggioranza sonorità medie molto basse, anche rsgain non è sufficiente.&#xA;&#xA;Come avevo detto all&#39;inizio, rsgain è una normalizzaziome della sonorità ottenuta agendo sui metadati del brano, applicando dei tag, che così non viene alternato in alcun modo.&#xA;&#xA;Rsgain è l&#39;evoluzione del vecchio mp3gain e come il suo predecessore ha due modalità di lavoro&#xA;&#xA;sul singolo brano (detta é custom)&#xA;su collezioni di brani (detta easy)&#xA;&#xA;La modalità custom è considerato un approccio legacy fatta per intervenire puntualmente sul brano con configurazioni ad-hoc ideali per lo scripting, quella easy, basata su presets, permette di normalizzare intere collezioni di brani che è lo scopo principale di rsgain.&#xA;&#xA;Analisi del file&#xA;rsgain custom -t audio.m4a&#xA;[✔] Scanning &#39;audio.m4a&#39;&#xA;[✔] Container: QuickTime / MOV [mov,mp4,m4a,3gp,3g2,mj2]&#xA;[✔] Stream #0: AAC (Advanced Audio Coding), 44.100 Hz, 2 ch&#xA; 100% [====================================================]&#xA;&#xA;Track: audio.m4a&#xA;  Loudness:   -18.12 LUFS&#xA;  Peak:     0.536630 (-5.41 dB)&#xA;  Gain:         0.12 dB&#xA;il flag -t individua il true peak&#xA;&#xA;Loudness: è la sonorità del brano in LUFS&#xA;Peak: è il true peak, esprime il guadagno che posso ottenere prima di distorcere&#xA;Gain: è il guadagno per arrivare allo standard LUFS di rsgain che è -18&#xA;&#xA;Nel nostro caso, Gain ci dice di diminuire di 0.12 LUFS mentre Peak ci dice che potrei aumentare di 5.41 LUFS&#xA;&#xA;Gain&#xA;rsgain custom -s i -l -13 -c p audio.m4a&#xA;Track: audio.m4a&#xA;  Loudness:   -18.12 LUFS&#xA;  Peak:     0.534149 (-5.45 dB)&#xA;  Gain:         5.12 dB&#xA;&#xA;-s i: scrive il tag&#xA;-l -13: imposta il loudness&#xA;-c p: protezione clipping&#xA;&#xA;Portando il loudness a -13 è come se avessi aumentato il volume di 5,12 dB mantenendo un cuscinetto di -0.33 dB (differenza fra peak e gain).&#xA;&#xA;Se provassi a spingere di più, il flag -c p impedisce al suono di distorcere.&#xA;rsgain custom -s i -l -10 -c p audio.m4a&#xA;Track: audio.m4a&#xA;  Loudness:   -18.12 LUFS&#xA;  Peak:     0.534149 (-5.45 dB)&#xA;  Gain:         5.45 dB  (adjusted to prevent clipping)&#xA;&#34;(adjusted to prevent clipping)&#34; è la conferma che la protezione anti-clipping è entrata in azione.&#xA;&#xA;Se non ci fosse stata:&#xA;rsgain custom -s i -l -10 audio.m4a&#xA;Track: audio.m4a&#xA;  Loudness:   -18.12 LUFS&#xA;  Peak:     0.534149 (-5.45 dB)&#xA;  Gain:         8.12 dB&#xA;La differenza fra peak e gain indica un&#39;evidente distorsione.&#xA;&#xA;Esempio di esecuzione del brano sfruttando il replaygain:&#xA;mpv --replaygain=track audio.m4a&#xA;Senza il flag --replaygain=track, il brano verrebbe letto normalmente.&#xA;&#xA;Cancellazione del tag&#xA;Basta cancellare il tag per riportare tutto alla normalità&#xA;verifico la presenza del tag prima&#xA;ffprobe -hidebanner -i &#34;audio.m4a&#34; 2  &amp;1 | grep -i &#34;replaygain&#34;&#xA;REPLAYGAINTRACKGAIN: 8.12 dB&#xA;REPLAYGAINTRACKPEAK: 0.534149&#xA;replaygain: track gain - 8.120000, track peak - 0.000012, album gain - unknown, album peak - unknown,&#xA;&#xA;cancello il tag&#xA;rsgain custom -s d audio.m4a&#xA;&#xA;verifico che il tag non si ci sia più&#xA;ffprobe -hidebanner -i &#34;audio.m4a&#34; 2  &amp;1 | grep -i &#34;replaygain&#34;&#xA;&#xA;Un altro modo più compatto per verificare la presenza del tag:&#xA;ffprobe -i &#34;audio.m4a&#34; -showentries formattags=REPLAYGAINTRACKGAIN -v quiet -of csv=&#34;p=0&#34;&#xA;Se c&#39;è il tag, mostra solo il gain.&#xA;&#xA;Easy mode&#xA;I flag impostati nella modalità custom nella modalitò easy sono affidati ad un file di configurazione.&#xA;&#xA;Su Gnu/Linux i file di default si trovano in /usr/share/rsgain/presets e sono 4&#xA;&#xA;default.ini&#xA;ebur128.ini&#xA;loudgain.ini&#xA;no\album.ini&#xA;&#xA;C&#39;è una sezione globla e delle sezioni specifiche per tipo di file.&#xA;&#xA;L&#39;override di queste configurazioni o la creazione di nuove, si fa in:&#xA;&#xA;~/.config/rsgain/presets&#xA;&#xA;e per la corrispondenza campi - flag custom vi rimando alla documentazione: https://github.com/complexlogic/rsgain?tab=readme-ov-file#scan-presets&#xA;&#xA;Una volta deciso il preset che fa per noi, basta chiamare rsgain su una directory in questo modo:&#xA;rsgain easy -s nomepreset pathalbum&#xA;rsgain farà la scansione e applicherà massivamente le configurazioni che potranno consistere per es.:&#xA;&#xA;nell&#39;applicazione di un loudness a tutti i brani per uniformare la sonorità;&#xA;nella cancellazione di tutti i tag;&#xA;nell&#39;analisi dei brani;&#xA;ecc.&#xA;&#xA;Esempio di file di configurazione per una scansione&#xA;[Global]&#xA;TagMode=s&#xA;Album=true&#xA;TargetLoudness=-18&#xA;ClipMode=p&#xA;MaxPeakLevel=-1.0&#xA;TruePeak=true&#xA;Lowercase=false&#xA;ID3v2Version=keep&#xA;OpusMode=d&#xA;PreserveMtimes=false&#xA;DualMono=false&#xA;In questo modo rsgain produrrà un&#39;analisi in modalità &#34;album&#34; per tutta la collezione, il gain da applicare all&#39;album e  una sintesi sulla media dei valori di picco ottenuti.&#xA;rsgain easy -p scan pathalbum &#xA;...&#xA;Track: pathalbum/track1&#xA;  Loudness:   -17.80 LUFS&#xA;  Peak:     0.743221 (-2.58 dB)&#xA;  Gain:        -0.20 dB&#xA;&#xA;Track: pathalbum/track2&#xA;  Loudness:   -17.81 LUFS&#xA;  Peak:     0.790007 (-2.05 dB)&#xA;  Gain:        -0.19 dB&#xA;&#xA;Track: pathalbum/track3&#xA;  Loudness:   -17.47 LUFS&#xA;  Peak:     0.834655 (-1.57 dB)&#xA;  Gain:        -0.53 dB&#xA;&#xA;...&#xA;&#xA;Album:&#xA;  Loudness:   -16.51 LUFS&#xA;  Peak:     0.991804 (-0.07 dB)&#xA;  Gain:        -1.49 dB&#xA;&#xA;Scanning Complete&#xA;Time Elapsed:      00:00:27&#xA;Files Scanned:     18&#xA;Clip Adjustments:  0 (0.0% of files)&#xA;Average Loudness:  -16.61 LUFS&#xA;Average Gain:      -1.39 dB&#xA;Average Peak:      0.823503 (-1.69 dB)&#xA;Negative Gains:    16 (88.9% of files)&#xA;Positive Gains:    2 (11.1% of files)&#xA;L&#39;ultima sezione, &#34;Album&#34;, mi dà le informazioni sul guadagno da applicare, in questo caso poco o nulla perché sono brani già normalizzati,.&#xA;&#xA;Con un altro presets, ad es. myGain.ini, posso normalizzare tutto l&#39;album in colpo solo.&#xA;&#xA;rsgain easy -p myGain pathalbum&#xA;In altre parole, tutto ciò che la modalità custom affida allo scripting, ora viene automatizzata dalla modalità easy.&#xA;&#xA;small Riferimenti:**&#xA;&#xA;https://ffmpeg.org/ffmpeg-filters.html#loudnorm&#xA;https://ffmpeg.org/ffmpeg-filters.html#toc-volumedetect&#xA;https://github.com/complexlogic/rsgain&#xA;/small&#xA;&#xA;#ffmpeg #rsgain #loudness #loudnorm]]&gt;</description>
      <content:encoded><![CDATA[<p><img src="https://pixelfed.uno/storage/m/_v2/489827599091373610/31410d826-759a86/dW3U92YRrKI4/EQCqOi56fpS0p9w4OdD2VsE3ZG4W8j3KZvbK0TWZ.jpg" alt="normalizzazione">
Quando si deve aumentare il volume di una traccia audio, si deve ricorrere a ad un&#39;operazione di “<strong>normalizzazione</strong>”.
</p>
<ul><li><a href="#1-cos-%C3%A8-la-normalizzazione" rel="nofollow">1. Cos’è la normalizzazione</a></li>
<li><a href="#2-come-misurare-il-picco" rel="nofollow">2. Come misurare il “picco”?</a></li>
<li><a href="#3-come-leggere-correttamente-questa-misura" rel="nofollow">3. Come leggere correttamente questa misura</a>
<ul><li><a href="#3-1-perch%C3%A9-usare-il-loudness-invece-di-rms" rel="nofollow">3.1. Perché usare il loudness invece di RMS?</a></li></ul></li>
<li><a href="#4-come-ti-normalizzo-il-file" rel="nofollow">4. Come ti normalizzo il file</a>
<ul><li><a href="#4-1-peak-normalization" rel="nofollow">4.1. Peak normalization</a></li>
<li><a href="#4-2-loudness-normalization" rel="nofollow">4.2. Loudness Normalization</a>
<ul><li><a href="#4-2-1-loudness-normalization-statica-ffmpeg" rel="nofollow">4.2.1. Loudness Normalization statica (ffmpeg)</a></li>
<li><a href="#4-2-2-loudness-normalization-dinamica" rel="nofollow">4.2.2. Loudness Normalization dinamica</a></li>
<li><a href="#4-2-3-loudness-normalization-statica-rsgain" rel="nofollow">4.2.3. Loudness Normalization statica (rsgain)</a></li></ul></li></ul></li></ul>

<h2 id="1-cos-è-la-normalizzazione">1. Cos&#39;è la normalizzazione</h2>

<p>La normalizzazione è un&#39;operazione lineare che consiste nell&#39;analisi del file audio, nel calcolare la differenza (offset) fra il volume attuale ed un volume target, nell&#39;applicare una correzione di guadagno (Gain).</p>

<p>La normalizzazione può essere distinta in base  al “come” e al “dove”.</p>

<p><strong>Il “come”</strong>
La normalizzazione classica si basa sui picchi. Cerca il punto più alto della forma d&#39;onda e lo porta a un valore massimo (es. 0 dB). Ignora la percezione umana; un brano con un singolo “click” molto forte risulterà comunque silenzioso perché quel picco blocca l&#39;aumento del volume.</p>

<p>La normalizzazione più moderna si basa sui <strong>LUFS</strong>, ossia su come, <strong>mediamente</strong>, l&#39;audio viene effettivamente percepito dall&#39;orecchio umano (psicoacustica). Porta l&#39;intero brano a un livello di pressione sonora media costante, rendendo l&#39;ascolto uniforme tra diverse tracce.</p>

<p><strong>Il “dove”</strong>
Quando si normalizza una traccia audio si può scegliere di farla modificando ogni singolo sample della traccia audio oppure di agire sui metadati.</p>

<p>Nel primo caso il file originale viene modificato (ricodifica quasi sempre lossy), nel secondo viene lasciato inalterato.</p>

<p>Altro fattore di cui tenere conto è che una normalizzazione lossy funziona su ogni player, una normalizzazione che agisce sui metadati funziona solo se il player è in grado di leggerli.</p>

<p>Possiamo fare quindi una prima distinzione:</p>
<ol><li>normalizzazione di picco (<strong>RMS</strong>) o <i>Peak Normalization</i>: applicazione di un <strong>guadagno statico</strong> (RMS) in modalità lossy: non altera la dinamica del brano, richiede una ricodifica;</li>
<li>normalizzazione della sonorità (<strong>LUFS</strong>) o <i>Loudness Normalization</i>:
<ol><li>applicazione di un <strong>guadagno statico</strong> (LUFS) in modalità lossy: non altera la dinamica del brano, richiede una ricodifica;</li>
<li>applicazione di un <strong>guadagno statico</strong> (LUFS) basato su tag: non altera la dinamica del brano, lascia il file inalterato (rsgain);</li>
<li>agisce con un compressore / limiter in modalità lossy: altera la dinamica del brano, richiede una ricodifica.</li></ol></li></ol>

<p>A questo punto la domanda diventa: quale scegliere?</p>

<p>Per quel che mi riguarda, la salomonica risposta è: dipende.</p>

<p>Come si può immaginare, non c&#39;è una risposta definitiva ma dipende dalla qualità della traccia, dal contesto ecc.</p>

<h2 id="2-come-misurare-il-picco">2. Come misurare il “picco”?</h2>

<p>C&#39;è bisogno di un elemento misurabile che mi permetta di capire come agire con la normalizzazione.</p>

<p><strong>RMS (Root Mean Square)</strong>: è un calcolo matematico asciutto su quanto sia potente elettricamente/digitalmente il segnale audio. È utile per capire l&#39;energia costante, ma non tiene conto del fatto che l&#39;orecchio umano è più sensibile ad alcune frequenze rispetto ad altre.</p>

<p><strong>LUFS (Loudness Units Full Scale)</strong>: È lo standard moderno (EBU R128). Simula l&#39;udito umano applicando dei filtri che pesano maggiormente le frequenze medie.</p>

<p>Per misurare il picco RMS posso ricorrere ad <strong>ffmpeg</strong></p>

<pre><code class="language-bash">ffmpeg -hide_banner -i &#34;audio.m4a&#34; -filter:a &#34;volumedetect&#34; -f null -
...
[...] n_samples: 18522112
[...] mean_volume: -20.3 dB
[...] max_volume: -5.4 dB
[...] histogram_5db: 40
[...] histogram_6db: 1436
[...] histogram_7db: 6443
[...] histogram_8db: 18606
...
</code></pre>

<p>che mi mostrerà:</p>
<ul><li>il numero dei samples di cui si compone la traccia</li>
<li>il volume medio (<em>mean_volume</em>)</li>
<li>il picco (<em>max_volume</em>)</li></ul>

<p>Il picco mi dice di quanto possa alzare il volume (fino al limite fisico di 0dB) staticamente senza causare distorsioni.</p>

<p>La differenza fra volume medio e picco mi dà informazioni sulla dinamica del brano. Maggiore è la differenza, maggiore è la dinamica. Tipicamente:</p>
<ul><li>valori &lt; 5 sono tipici della musica dance, forte, uniforme, e molto compressa.</li>
<li>valori fra 5 e 15 sono tipici di brani pop-rock, ben bilanciati</li>
<li>valori &gt; 15 sono attribuibili a brani di musica classica, jazz, con una dinamica ricca.</li></ul>

<p>Per misurare il loudness, sempre con ffmpeg:</p>

<pre><code class="language-bash">ffmpeg -hide_banner -i &#34;audio.m4a&#34; -filter:a &#34;ebur128=peak=true&#34; -f null - 
...
 Integrated loudness:
    I:         -18.1 LUFS
    Threshold: -28.4 LUFS

  Loudness range:
    LRA:         4.1 LU
    Threshold: -38.3 LUFS
    LRA low:   -21.2 LUFS
    LRA high:  -17.1 LUFS

  True peak:
    Peak:       -5.4 dBFS
</code></pre>

<p>La misurazione è più articolata rispetto alla precedente.</p>

<p>FFmpeg innanzitutto mostra due sezioni: <strong>Integrated Loudness</strong>, rappresentante il <strong>volume medio</strong> complessivo del file e la <strong>Loudness Range</strong> che mi descrive la dinamica del brano come differenza di volume fra le parti più silenziose e quelle più rumorose.</p>
<ol><li>Sezione <strong>Integrated loudness</strong>:
<ul><li><strong>I</strong>: è il valore più importante. È il volume medio percepito dell&#39;intero brano (come si può vedere, diverso rispetto all&#39;RMS di prima. Il primo è pura potenza digitale, il secondo è <strong>volume percepito</strong>).</li>
<li><strong>Threshold</strong>: è la soglia usata per evitare che i silenzi abbassino artificialmente la media del volume. L&#39;algoritmo ignora tutto ciò che sta sotto questa soglia nel calcolo dell&#39;Integrated Loudness.</li></ul></li>
<li>Sezione <strong>Loudness range</strong>:
<ul><li><strong>LRA</strong>: è un indice della variazione dinamica del brano. Più è basso, più il suono tende ad essere uniforme e probabilmente compresso</li>
<li><strong>Threshold</strong>: come prima, è la soglia oltre la quale i suoni vengono ignorati nel calcolo del range dinamico.</li>
<li><strong>LRA Low</strong>: indica il limite inferiore del loudness</li>
<li><strong>LRA High</strong>: indica il limite superiore<br>
quindi <em>LRA = LRA High – LRA Low</em></li></ul></li>
<li>Sezione <strong>True peak</strong>:
<ul><li><strong>Peak</strong>: Simile al <em>max_volume</em> dell&#39;RMS, indica il picco <strong>reale</strong> del brano in termini di sonorità.</li></ul></li></ol>

<p>Un altro modo, forse meno pratico ma decisamente più scenografico, per analizzare un file audio è questo:</p>

<pre><code class="language-bash">ffplay -f lavfi -i &#34;amovie=audio.m4a,ebur128=video=1:meter=18 [out0][out1]&#34;
</code></pre>

<p>Disegna un grafico dell&#39;onda sonora in tempo reale.</p>

<h2 id="3-come-leggere-correttamente-questa-misura">3. Come leggere correttamente questa misura</h2>

<p>L&#39;<strong>integrated loudness</strong> mi dice qual è il volume <strong>medio</strong> del brano.
<strong>True peak</strong> mi dice di quanto posso alzare prima di distorcere.
Queste sono le due informazioni cruciali sufficienti per applicare un <strong>guadagno statico</strong> senza fare danni.</p>

<p>I valori <strong>High</strong> e <strong>Low</strong> del <strong>Loudness Range</strong>, che racchiudono asintoticamente il brano, tornano utili quando bisogna agire sulla dinamica.</p>

<p>Notare che <strong>Integrated loudness</strong> è sempre compreso fra <strong>LRA Low</strong> e <strong>LRA High</strong>.</p>

<h3 id="3-1-perché-usare-il-loudness-invece-di-rms">3.1. Perché usare il loudness invece di RMS?</h3>

<p>L&#39;RMS è un calcolo puramente matematico che non tiene conto del fatto che l&#39;orecchio umano è molto più sensibile alle frequenze medie che non ai bassi estemi e agli acuti altissimi.</p>

<p> A questo provvede il LUFS che è un&#39;evoluzione dell&#39;RMS perché include dei <strong>filtri di ponderazione</strong> che, prima di calcolare la media, esaltano le frequenze medie attenuando quelle basse.</p>

<p>La conseguenza è che se agisco sul volume dei brani prendendo LUFS come riferimento, questi suoneranno tutti allo stesso volume. Se considerassi un adeguamento basato su RMS, i brani con più bassi sembreranno avere meno volume di quelli con frequenze medie più marcate.</p>

<h2 id="4-come-ti-normalizzo-il-file">4. Come ti normalizzo il file</h2>

<p>La scelta fra una normalizzazione di picco e una di volume (loudness) è abbastanza semplice in realtà.</p>

<p>A parte poche eccezioni in cui può avere senso avere RMS come riferimento, è sempre preferibile una normalizzazione della sonorità.</p>

<p>Quest&#39;ultima può essere fatta modificando solo i metadati o agendo chirurgicamente sul file ricodificandolo.</p>

<h3 id="4-1-peak-normalization">4.1. Peak normalization</h3>

<p>Una volta noti i dati di <em>Max Volume</em> e <em>Mean Volume</em> visti in precedenza, la normalizzazione è piuttosto semplice.</p>

<p>Supponendo <code>Max Volume = 6dB</code></p>

<pre><code class="language-bash">ffmpeg -i audio.m4a -filter:a &#34;volume=6dB&#34; -c:a aac -b:a 192k audio_normalized.m4a
</code></pre>

<p>Dovendo ricodificare, scelgo un bitrate piuttosto alto per limitare la perdita fisiologica di una ricodifica lossy.</p>

<p>Come si può immaginare, è una aggiunta lineare secca a tutta la traccia a cui aumento solo la potenza digitale senza tenere conto della percezione sonora.</p>

<p>Piccola nota: Conviene scegliere un valore che si avvicini, ma non equivalga, al limite di 0 dB perché altrimenti FFmpeg taglierà brutalmente le creste dell&#39;onda sonora che superano lo zero, creando quella tipica distorsione metallica grattata chiamata <strong>clipping</strong>.</p>

<h3 id="4-2-loudness-normalization">4.2. Loudness Normalization</h3>

<p>La normalizzazione di volume, in base alla nostra scelta di alterare o meno la dinamica del brano, può essere fatta come detto applicando:</p>
<ul><li>un guadagno statico LUFS (lossy)</li>
<li>un guadagno statico LUFS sui metadati (non lossy)</li>
<li>compressore / limiter (sempre lossy)</li></ul>

<p>Il guadagno statico, quello con i metadati, avverrà con <strong>rsgain</strong>.</p>

<p>La normalizzazione con perdita di qualità (lossy) avverrà con ffmpeg usando il filtro <strong>loudnorm</strong> che dispone di un compressore/limiter piuttosto efficace.</p>

<p>Questo filtro è un processore dinamico (dual-pass o single-pass). Non si limita ad alzare il volume; se trova una parte troppo forte, può comprimere leggermente solo quella parte per permettere al resto della canzone di suonare più forte.</p>

<p><code>loudnorm</code> porta il loudness di default a -24 LUFS che è lo standard per il broadcast televisivo.</p>

<p>I colossi dello streaming applicano automaticamente un loudness decisamente più marcato, salvo poche eccezioni, non si discostano da -14 LUFS. Ad es. Youtube, Amazon Music, Spotify, Soundcloud viaggiano mediamente su -14 LUFS, Deezer -15, Apple Music -16.</p>

<p>Si può verificare facilmente, come sappiamo fare, come un audio presente su una di queste piattaforme, abbia uno dei loudness indicati.</p>

<h4 id="4-2-1-loudness-normalization-statica-ffmpeg">4.2.1. Loudness Normalization statica (ffmpeg)</h4>

<p>Riprendiamo l&#39;esempio di prima.</p>

<pre><code class="language-bash">ffmpeg -hide_banner -i &#34;audio.m4a&#34; -filter:a &#34;ebur128=peak=true&#34; -f null - 
...
 Integrated loudness:
    I:         -18.1 LUFS
    Threshold: -28.4 LUFS

  Loudness range:
    LRA:         4.1 LU
    Threshold: -38.3 LUFS
    LRA low:   -21.2 LUFS
    LRA high:  -17.1 LUFS

  True peak:
    Peak:       -5.4 dBFS
</code></pre>

<p>Con <code>ffmpeg</code> e <code>loudnorm</code> in modalità <strong>single-pass</strong>, posso applicare un guadagno statico 5.4 dBFS, con un true peak di -1 (Il default è -2), per arrivare, da -18.1 LUFS, a -13.0 LUFS senza distorsioni.</p>

<pre><code class="language-bash">ffmpeg -i audio.m4a -filter:a &#34;loudnorm=I=-12.7:TP=-1.0&#34; -c:a aac -b:a 160k -vn audio_norm.m4a
</code></pre>

<p>Verifichiamo:</p>

<pre><code class="language-bash">ffmpeg -hide_banner -i &#34;audio.m4a&#34; -filter:a &#34;ebur128=peak=true&#34; -f null - 
...
   Integrated loudness:
    I:         -12.5 LUFS
    Threshold: -22.6 LUFS

  Loudness range:
    LRA:         4.0 LU
    Threshold: -32.6 LUFS
    LRA low:   -15.1 LUFS
    LRA high:  -11.1 LUFS

  True peak:
    Peak:       -0.4 dBFS
...
</code></pre>

<p>Come si vede, sono arrivato al limite, forse un po&#39; troppo, del guadagno che potevo ottenere. Probabimente su dispositivi economici, l&#39;analogico di un brano così potrebbe gracchiare un po&#39;.</p>

<p>Se avessi applicato il default  di  <code>loudnorm</code>, la sonorità sarebbe stata livellata sui -24 LUFS con una soglia true peak pari a -2 dBFS.</p>

<h4 id="4-2-2-loudness-normalization-dinamica">4.2.2. Loudness Normalization dinamica</h4>

<p>Nei casi in cui:</p>
<ul><li>si vuole enfatizzare l&#39;audio di un podcast, di un parlato in generale;</li>
<li>la dinamica del brano è composta da picchi altissimi e una sonorità media molto bassa (un guadagno statico farebbe cambiare poco o nulla)</li></ul>

<p>con <code>ffmpeg</code> e <code>loudnorm</code> possiamo correggere ogni singolo sample del brano per rendere la dinamica più uniforme.</p>

<p>Per ottenere un risultato ottimale, si deve procedere col <strong>dual-pass</strong>, in cui ffmpeg nel primo passaggio analizza il file e raccoglie i dati, nel secondo passaggio applica le correzioni puntualmente avendo già conoscenza della dinamica e dei picchi presenti nel file.</p>

<pre><code class="language-bash">ffmpeg -i &#34;audio.m4a&#34; -filter:a &#34;loudnorm=I=-14:TP=-1.0:print_format=json&#34; -f null -
</code></pre>

<p>Ecco il json risultante dall&#39;analisi. I valori di input sono quelli che forniremo a ffmepg affinché possa impostare il loudness scelto da noi nel miglior modo possibile</p>

<pre><code class="language-json">{
	&#34;input_i&#34; : &#34;-18.17&#34;,
	&#34;input_tp&#34; : &#34;-5.41&#34;,
	&#34;input_lra&#34; : &#34;4.20&#34;,
	&#34;input_thresh&#34; : &#34;-28.47&#34;,
	&#34;output_i&#34; : &#34;-13.36&#34;,
	&#34;output_tp&#34; : &#34;-1.00&#34;,
	&#34;output_lra&#34; : &#34;4.30&#34;,
	&#34;output_thresh&#34; : &#34;-23.50&#34;,
	&#34;normalization_type&#34; : &#34;dynamic&#34;,
	&#34;target_offset&#34; : &#34;-0.64&#34;
}
</code></pre>

<p>Configurazione ffmpeg.</p>

<pre><code class="language-bash">ffmpeg -i &#34;audio.m4a&#34; -filter:a &#34;loudnorm=I=-14:TP=-1.0:measured_I=-18.17:measured_TP=-5.41:measured_LRA=4.20:measured_thresh=-23.50:linear=true&#34; -c:a aac -b:a 160k -vn &#34;audio_norm.m4a&#34;
</code></pre>

<p>Il compressore/limiter del filtro loudnorm è abbastanza intelligente da schiacciare i picchi affinche il guadagno di volume non produca clipping e alzerà le parti più “deboli”, livellando il suono e alterando la dinamica.</p>

<h4 id="4-2-3-loudness-normalization-statica-rsgain">4.2.3. Loudness Normalization statica (rsgain)</h4>

<p>Rsgain permette di applicare un guadagno statico loseless, senza ricodifica, agendo sui metadati del brano con l&#39;applicazione dei tag.</p>

<p>Se da un lato questo metodo ha l&#39;indubbio vantaggio di non alterare fisicamente il file, dall&#39;altro è necessario che il player che eseguirà il brano dovra essere capace di leggere e interpretare i tag. Nel caso precedente, la ricodifica rende il file disponibile per chiunque.</p>

<p>Trattandosi di un guadagno statico, il campo d&#39;applicazione è quello visto per la Peak Normalization, cioè quando si vuole preservare la dinamica del brano, Ma nei casi particolari cui accennavo in precedenza, presenza di picchi altissimi e maggioranza sonorità medie molto basse, anche rsgain non è sufficiente.</p>

<p>Come avevo detto all&#39;inizio, rsgain è una normalizzaziome della sonorità ottenuta agendo sui metadati del brano, applicando dei tag, che così non viene alternato in alcun modo.</p>

<p>Rsgain è l&#39;evoluzione del vecchio mp3gain e come il suo predecessore ha due modalità di lavoro</p>
<ul><li>sul singolo brano (detta é <strong>custom</strong>)</li>
<li>su collezioni di brani (detta <strong>easy</strong>)</li></ul>

<p>La modalità <strong>custom</strong> è considerato un approccio legacy fatta per intervenire puntualmente sul brano con configurazioni ad-hoc ideali per lo scripting, quella <strong>easy</strong>, basata su presets, permette di normalizzare intere collezioni di brani che è lo scopo principale di rsgain.</p>

<p><strong>Analisi del file</strong></p>

<pre><code class="language-bash">rsgain custom -t audio.m4a
[✔] Scanning &#39;audio.m4a&#39;
[✔] Container: QuickTime / MOV [mov,mp4,m4a,3gp,3g2,mj2]
[✔] Stream #0: AAC (Advanced Audio Coding), 44.100 Hz, 2 ch
 100% [====================================================]

Track: audio.m4a
  Loudness:   -18.12 LUFS
  Peak:     0.536630 (-5.41 dB)
  Gain:         0.12 dB
</code></pre>

<p>il flag <code>-t</code> individua il true peak</p>
<ul><li><strong>Loudness</strong>: è la sonorità del brano in LUFS</li>
<li><strong>Peak</strong>: è il true peak, esprime il guadagno che posso ottenere prima di distorcere</li>
<li><strong>Gain</strong>: è il guadagno per arrivare allo standard LUFS di rsgain che è -18</li></ul>

<p>Nel nostro caso, Gain ci dice di diminuire di 0.12 LUFS mentre Peak ci dice che potrei aumentare di 5.41 LUFS</p>

<p><strong>Gain</strong></p>

<pre><code class="language-bash">rsgain custom -s i -l -13 -c p audio.m4a
Track: audio.m4a
  Loudness:   -18.12 LUFS
  Peak:     0.534149 (-5.45 dB)
  Gain:         5.12 dB
</code></pre>
<ul><li><code>-s i</code>: scrive il tag</li>
<li><code>-l -13</code>: imposta il loudness</li>
<li><code>-c p</code>: protezione clipping</li></ul>

<p>Portando il loudness a -13 è come se avessi aumentato il volume di 5,12 dB mantenendo un cuscinetto di -0.33 dB (differenza fra peak e gain).</p>

<p>Se provassi a spingere di più, il flag <code>-c p</code> impedisce al suono di distorcere.</p>

<pre><code class="language-bash">rsgain custom -s i -l -10 -c p audio.m4a
Track: audio.m4a
  Loudness:   -18.12 LUFS
  Peak:     0.534149 (-5.45 dB)
  Gain:         5.45 dB  (adjusted to prevent clipping)
</code></pre>

<p>“<em>(adjusted to prevent clipping)</em>” è la conferma che la protezione anti-clipping è entrata in azione.</p>

<p>Se non ci fosse stata:</p>

<pre><code class="language-bash">rsgain custom -s i -l -10 audio.m4a
Track: audio.m4a
  Loudness:   -18.12 LUFS
  Peak:     0.534149 (-5.45 dB)
  Gain:         8.12 dB
</code></pre>

<p>La differenza fra peak e gain indica un&#39;evidente distorsione.</p>

<p><strong>Esempio di esecuzione del brano sfruttando il replaygain</strong>:</p>

<pre><code class="language-bash">mpv --replaygain=track audio.m4a
</code></pre>

<p>Senza il flag <code>--replaygain=track</code>, il brano verrebbe letto normalmente.</p>

<p><strong>Cancellazione del tag</strong>
Basta cancellare il tag per riportare tutto alla normalità</p>

<pre><code class="language-bash"># verifico la presenza del tag prima
ffprobe -hide_banner -i &#34;audio.m4a&#34; 2&gt;&amp;1 | grep -i &#34;replaygain&#34;
REPLAYGAIN_TRACK_GAIN: 8.12 dB
REPLAYGAIN_TRACK_PEAK: 0.534149
replaygain: track gain - 8.120000, track peak - 0.000012, album gain - unknown, album peak - unknown,

# cancello il tag
rsgain custom -s d audio.m4a

# verifico che il tag non si ci sia più
ffprobe -hide_banner -i &#34;audio.m4a&#34; 2&gt;&amp;1 | grep -i &#34;replaygain&#34;
**
</code></pre>

<p>Un altro modo più compatto per verificare la presenza del tag:</p>

<pre><code>ffprobe -i &#34;audio.m4a&#34; -show_entries format_tags=REPLAYGAIN_TRACK_GAIN -v quiet -of csv=&#34;p=0&#34;
</code></pre>

<p>Se c&#39;è il tag, mostra solo il gain.</p>

<p><strong>Easy mode</strong>
I flag impostati nella modalità custom nella modalitò easy sono affidati ad un file di configurazione.</p>

<p>Su Gnu/Linux i file di default si trovano in <code>/usr/share/rsgain/presets</code> e sono 4</p>
<ul><li>default.ini</li>
<li>ebur128.ini</li>
<li>loudgain.ini</li>
<li>no_album.ini</li></ul>

<p>C&#39;è una sezione globla e delle sezioni specifiche per tipo di file.</p>

<p>L&#39;override di queste configurazioni o la creazione di nuove, si fa in:</p>

<p><code>~/.config/rsgain/presets</code></p>

<p>e per la corrispondenza campi – flag custom vi rimando alla documentazione: <a href="https://github.com/complexlogic/rsgain?tab=readme-ov-file#scan-presets" rel="nofollow">https://github.com/complexlogic/rsgain?tab=readme-ov-file#scan-presets</a></p>

<p>Una volta deciso il preset che fa per noi, basta chiamare rsgain su una directory in questo modo:</p>

<pre><code class="language-bash">rsgain easy -s &lt;nome_preset&gt; &lt;path_album&gt;
</code></pre>

<p>rsgain farà la scansione e applicherà massivamente le configurazioni che potranno consistere per es.:</p>
<ul><li>nell&#39;applicazione di un loudness a tutti i brani per uniformare la sonorità;</li>
<li>nella cancellazione di tutti i tag;</li>
<li>nell&#39;analisi dei brani;</li>
<li>ecc.</li></ul>

<p><strong>Esempio di file di configurazione per una scansione</strong></p>

<pre><code>[Global]
TagMode=s
Album=true
TargetLoudness=-18
ClipMode=p
MaxPeakLevel=-1.0
TruePeak=true
Lowercase=false
ID3v2Version=keep
OpusMode=d
PreserveMtimes=false
DualMono=false
</code></pre>

<p>In questo modo rsgain produrrà un&#39;analisi in modalità “<strong>album</strong>” per tutta la collezione, il gain da applicare all&#39;album e  una sintesi sulla media dei valori di picco ottenuti.</p>

<pre><code class="language-bash">rsgain easy -p scan &lt;path_album&gt; 
...
Track: &lt;path_album&gt;/track_1
  Loudness:   -17.80 LUFS
  Peak:     0.743221 (-2.58 dB)
  Gain:        -0.20 dB


Track: &lt;path_album&gt;/track_2
  Loudness:   -17.81 LUFS
  Peak:     0.790007 (-2.05 dB)
  Gain:        -0.19 dB


Track: &lt;path_album&gt;/track_3
  Loudness:   -17.47 LUFS
  Peak:     0.834655 (-1.57 dB)
  Gain:        -0.53 dB

...

Album:
  Loudness:   -16.51 LUFS
  Peak:     0.991804 (-0.07 dB)
  Gain:        -1.49 dB


Scanning Complete
Time Elapsed:      00:00:27
Files Scanned:     18
Clip Adjustments:  0 (0.0% of files)
Average Loudness:  -16.61 LUFS
Average Gain:      -1.39 dB
Average Peak:      0.823503 (-1.69 dB)
Negative Gains:    16 (88.9% of files)
Positive Gains:    2 (11.1% of files)
</code></pre>

<p>L&#39;ultima sezione, “<strong>Album</strong>”, mi dà le informazioni sul guadagno da applicare, in questo caso poco o nulla perché sono brani già normalizzati,.</p>

<p>Con un altro presets, ad es. <code>myGain.ini</code>, posso normalizzare tutto l&#39;album in colpo solo.</p>

<pre><code>rsgain easy -p myGain &lt;path_album&gt;
</code></pre>

<p>In altre parole, tutto ciò che la modalità <strong>custom</strong> affida allo scripting, ora viene automatizzata dalla modalità <strong>easy</strong>.</p>

<p><small> <strong>Riferimenti:</strong></p>
<ul><li><a href="https://ffmpeg.org/ffmpeg-filters.html#loudnorm" rel="nofollow">https://ffmpeg.org/ffmpeg-filters.html#loudnorm</a></li>
<li><a href="https://ffmpeg.org/ffmpeg-filters.html#toc-volumedetect" rel="nofollow">https://ffmpeg.org/ffmpeg-filters.html#toc-volumedetect</a></li>
<li><a href="https://github.com/complexlogic/rsgain" rel="nofollow">https://github.com/complexlogic/rsgain</a>
</small></li></ul>

<p><a href="/aytin/tag:ffmpeg" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">ffmpeg</span></a> <a href="/aytin/tag:rsgain" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">rsgain</span></a> <a href="/aytin/tag:loudness" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">loudness</span></a> <a href="/aytin/tag:loudnorm" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">loudnorm</span></a></p>
]]></content:encoded>
      <guid>https://noblogo.org/aytin/come-aumentare-il-volume-di-una-traccia-audio</guid>
      <pubDate>Mon, 13 Apr 2026 15:03:39 +0000</pubDate>
    </item>
    <item>
      <title>Installazione di Cloudflare WARP su OSMC</title>
      <link>https://noblogo.org/aytin/installazione-di-cloudflare-warp-su-osmc</link>
      <description>&lt;![CDATA[cloudflare-warp&#xA;È noto come l&#39;uso dei resolver Cloudflare sia uno dei modi per anonimizzare il proprio IP all&#39;ISP.&#xA;&#xA;Cloudflare offre anche altre modalità di risoluzione ancora più efficaci:&#xA;&#xA;DNS over HTTPS (DoH)&#xA;DNS over TCP (DoT)&#xA;DNS over WARP (DoW)&#xA;&#xA;!--more--&#xA;I primi due sono relativi a richieste dns crittografate e incapsulate, in una richiesta https (porta 443) la prima, e in una connessione TLS (porta 853) la seconda.&#xA;&#xA;La terza modalità è una richiesta dns in chiaro ma all&#39;interno di un tunnel Wireguard o MASQUE (QUIC + HTTP/3 - rif. https://datatracker.ietf.org/meeting/interim-2021-masque-03/materials/slides-interim-2021-masque-03-sessa-masque-interim-2021-04-h3-dgram-00). Molto interessante ed è quella che approfondirò in seguito.&#xA;&#xA;Senza entrare nel merito, tutte le soluzioni anonimizzano le query dns. L&#39;ultima, quella che mi ha stutzzicato, è in realtà un tunnel vpn che crittografa TUTTO il traffico, non solo le richieste DNS.&#xA;&#xA;DoT è una cifratura TLS che lascia intatto il pacchetto UDP iniziale, è quindi più efficiente di DoH che converte una richieste DNS in una HTTP cifrata dal layer TLS.&#xA;&#xA;DoT di solito viene fatta a livello di dispositivo, DoH per singole applicazioni.&#xA;&#xA;DoT, basandosi su una porta specifica, 853, è facilmente identificabile (e bloccabile) come traffico DNS (benché cifrato), DoH è una richiesta HTTPS e si mescola col traffico che viaggia sulla porta 443 (difficilmente si invaliderà tutto quel tipo di traffico).&#xA;&#xA;DoT, DoH, DoW, mitigano notevolmente il cache poisoning dei resolver perché rendono quasi impossibilie per un attaccante alterare una richiesta che viene protetta per l&#39;intero percorso. Va detto che la soluzione ideale in questo contesto è la combinazione con DNSSEC, che fornisce autenticità e integrità alla riservatezza fornita da DoH/DoT.&#xA;&#xA;Anche se l&#39;obiettivo rimane l&#39;approfondimento di CLoudflare WARP, vale la pena di spendere due parole anche sulle altre modalità di risoluzione, DoT/DoH&#xA;Configurare risoluzioni DNS DoH&#xA;Configurare DoH è molto semplice perché è qualcosa legato all&#39;applicazione, il browser tipicamente. Se l&#39;applicazione lo supporta, di solito è poco di più di un flag da abilitare.&#xA;&#xA;Ad es. Firefox o Chrome permettono di attivare una sorte di &#34;protezione avanzata del DNS&#34; indicando semplicemente un resolver che la supporti (es. Cloudflare, NextDNS o Quad9).&#xA;Configurare risoluzioni DNS DoT&#xA;DoT, come detto, è una configurazione che avviene a livello di dispositivo, l&#39;anonimizzazione delle query DNS si ottiene quindi per ogni applicazione. Sul come farlo, dipende dal dispositivo.&#xA;&#xA;Ad es. su una linux box basta aggiungere due righe su systemd-resolved e riavviare il relativo servizio.&#xA;sudo vi /etc/systemd/resolved.conf&#xA;...&#xA;DNS=1.1.1.1&#xA;DNSOverTLS=yes&#xA;&#xA;dopo aver salvato il file&#xA;systemctl restart systemd-resolved&#xA;Un veloce test su https://1.1.1.1/help  (da qualunque browser) ci mostrerà qualcosa del tipo:&#xA;Connected to 1.1.1.1        Yes&#xA;Using DNS over HTTPS (DoH)  No&#xA;Using DNS over TLS (DoT)    Yes&#xA;Using DNS over WARP         No&#xA;AS Name                     Cloudflare, Inc.&#xA;AS Number                   13335&#xA;Cloudflare Data Center      MXP&#xA;indice che DoT è attivo e funzionante. Lo stesso test poteva essere fatto anche per DoH.&#xA;Cloudflare WARP&#xA;E poi c&#39;è DoW, che è qualcosa di ancora più estremo perché, all&#39;occorrenza, anonimizza non solo le richieste DNS ma tutto il nostro traffico (e infatti diversi servizi di streaming non lo consentono).&#xA;&#xA;Cloudflare Warp attiva diverse modalità di risoluzione dns fra cui DoH e DoT.&#xA;&#xA;Dal momento che Cloudflare Warp agisce su tutta la connessione, è il modo più semplice per avere risoluzione dns di tipo DoH o DoT, su qualunque dispositivo su cui è presente Cloudflare Warp senza gli sbattimenti di systemd o altro.&#xA;&#xA;Cloudflare Warp in modalità tunnel è un client che instaura un collegamento cifrato punto-punto (un tunnel) fra il nostro host e un endpoint Cloudflare. In questo modo ogni bit che esce dal nostro dispositivo viene cifrato prima della comunicazione, che diventa così totalmente schermata.&#xA;&#xA;La vpn di Coudflare si basa su wireguard o su MASQUE. Nel primo caso è una normale vpn con un setup roadwarrior, il secondo caso offre in più la possibilità di associare al tunnel anche le modalità DoH/DoT per le richieste dns.&#xA;Anonimato sì/no?&#xA;Cloudflare WARP è uno strumento incentrato sulla sicurezza, progettato per crittografare il traffico internet e proteggere la privacy dagli ISP, piuttosto che per garantire l&#39;anonimato completo o nascondere la posizione dell&#39;utente.&#xA;&#xA;Sostituisce l&#39;IP dell&#39;utente con un IP di Cloudflare che generalmente corrisponde alla sua reale area geografica, rendendolo inadatto a eludere le restrizioni basate sulla posizione.&#xA;&#xA;Non è una VPN tradizionale. WARP non maschera la nostra posizione ai siti web, che spesso possono visualizzare la tua posizione approssimativa.&#xA;&#xA;Per migliorare la privacy, si dovrebbe utilizzare il protocollo MASQUE, che offre anche una maggiore efficienza.&#xA;&#xA;In sintesi, WARP fornisce un &#34;tunnel sicuro&#34; per proteggere la privacy dei dati da amministratori di rete indiscreti, protegge il traffico perché eccelle nella crittografia del traffico su reti non sicure (ad esempio, Wi-Fi pubbliche), ma non offre le funzionalità di anonimato dei tradizionali servizi VPN incentrati sulla privacy.&#xA;&#xA;Fatta questa doverosa premessa, vediamo come può essere usato.&#xA;Configurare Cloudflare WARP&#xA;L&#39;installazione del client è molto semplice. Per Gnu/Linux c&#39;è la versione cli, per android un app, per altri sistemi, Win /MacOS, un installer.&#xA;La parte applicativa prima di tutto registra il dispositivo sulla rete Cloudflare generando degli ID e una chiave di licenza. In un secondo momento si generano le chiavi di cifratura.&#xA;&#xA;Per fissare le idee, una volta fatte le operazioni di inizializzazione, sulla linux box per tunnellizzare ogni nostra comunicazione con una risoluzione DoT, basta:&#xA;facoltativo&#xA;warp-cli mode warp+dot&#xA;&#xA;connessione&#xA;warp-cli connect&#xA;Per terminare:&#xA;warp-cli disconnect&#xA;Questo approccio torna molto comodo quando per es. vogliamo usare wifi pubbliche, in città o in aeroporto. A meno di non avere un&#39;installazione personale di una nostra vpn, questa è una soluzione immediata. Certo, bisogna fidarsi di Cloudflare ma è certamente meglio che fidarsi delle wifi free.&#xA;&#xA;E arriviamo al caso d&#39;uso che volevo approfondire riguardante l&#39;&#34;anonimizzazione&#34; di un mediacenter casalingo per il quale non vogliamo rendere noto il suo utilizzo.&#xA;&#xA;L&#39;esperienza che ho avuto al proposito è stata interessante, visto che uso da anni OSMC su una RasbPi 3 e ho deciso di metterla dietro Cloudflare.&#xA;&#xA;OSMC insieme a LibreELEC sono ottime soluzioni di mediacenter per SBC. La prima più &#34;general&#34;, essendo una debian customizzata per ospitare un mediacenter, la seconda invece meno elastica ma più essenziale ed efficiente.&#xA;&#xA;Nonostante la Raspberry Pi 3 sia dotata di un processore ARM64, la versione di OSMC che ho installato a suo tempo è a 32 bit e per quella non c&#39;è disponibilità per il client cloudflare (solo ARM64).&#xA;&#xA;Ho dovuto ricorrere ad un client &#34;unofficial&#34;, wgcf, che permette di registrare il dispositivo e di generare le chiavi ma solo per la modalità Wireguard, non MASQUE, quindi niente Warp+DoT/DoH (per inciso, wgcf rappresenta un&#39;ottima alternativa anche per chi non vuole usare il client Cloudflare su Gnu/Linux).&#xA;&#xA;A questo aggiungo che, sebbebe OSMC sia una Debian su cui posso installare e configurare tanta roba, l&#39;installazione di Wireguard, e penso di qualunque cosa che vada a toccare lo stack di rete, diventa qualcosa di estremamente complicato da fare, dal momento che OSMC si rifiuta categoricamente di eseguire operazione che metterebbero a rischio il suo essere un mediacenter, fondamentalmente.&#xA;&#xA;Tradotto in soldoni, il client wireguard si installa, sale su correttamente ma non c&#39;è verso di far funzionare la risoluzione. L&#39;unica via d&#39;usicta è stata configurare Wireguard attraverso il gestore di rete di OSMC che è connman.&#xA;&#xA;Una volta fatto questo, sono stati necessari solo un paio di piccoli accorgimenti per far si che, in seguito all&#39;avvio del mediacenter, la configurazione vpn venisse caricata automaticamente da connman, contestualmente alla connessione vpn.&#xA;Configurazione wgcf&#xA;Account cloudflare&#xA;curl -L https://github.com/ViRb3/wgcf/releases/latest/download/wgcf2.2.30linuxarmv7 -o /usr/local/bin/wgcf&#xA;chmod u+x /usr/local/bin/wgcf&#xA;wgcf register&#xA;wgcf generate&#xA;&#xA;status &amp; trace&#xA;wgcf status&#xA;curl https://www.cloudflare.com/cdn-cgi/trace&#xA;Configurazione connman&#xA;Su OSMC connman ha i suoi file di configurazione in /var/lib/connman e /var/lib/connman-vpn&#xA;&#xA;Nel file di configurazione, l&#39;host va indicato con l&#39;ip non con l&#39;fqdn (engage.cloudflareclients.com)&#xA;Configurazione wireguard cloudflare&#xA;La configurazione della vpn deve essere un file .config sotto /var/lib/connman-vpn&#xA;&#xA;vi /var/lib/connman-vpn/cloudflarewarp.config&#xA;[provider*]&#xA;Type = WireGuard&#xA;Name = CloudflareWARP&#xA;Host = 162.159.192.1&#xA;AutoConnect = true&#xA;WireGuard.Address = 172.16.0.2/24&#xA;WireGuard.ListenPort = 51280&#xA;WireGuard.PrivateKey = myprivatekey&#xA;WireGuard.PublicKey = cloudlarewgpublickey&#xA;WireGuard.DNS = 1.1.1.1, 1.0.0.1&#xA;WireGuard.AllowedIPs = 0.0.0.0/0&#xA;WireGuard.EndpointPort = 2408&#xA;WireGuard.PersistentKeepalive = 25&#xA;Dopo aver creato il file di configurazione, possiamo vedere il nuovo servizio pronto per essere richiamato da comman-vpnd&#xA;elenco servizi attivi&#xA;connmanctl services&#xA;AO SSID           wifiidmanagedpsk&#xA;R CloudflareWARP      vpn1621591921&#xA;Affinché la connessione alla vpn parta all&#39;avvio di OSMC, è necessario disporre di un servizio che:&#xA;&#xA;esegua common-vpnd per caricare il file di configurazione&#xA;effettui la connessione vpn&#xA;&#xA;Creazione nuovo servizio in /lib/systemd/system/connman-vpn.service&#xA;[Unit]&#xA;Description=ConnMan VPN service&#xA;After=network-online.target&#xA;Wants=network-online.target&#xA;&#xA;[Service]&#xA;Type=dbus&#xA;BusName=net.connman.vpn&#xA;ExecStart=/usr/sbin/connman-vpnd -n&#xA;ExecStop=/usr/local/bin/vpn-autoconnect.sh&#xA;StandardOutput=null&#xA;Restart=on-failure&#xA;&#xA;[Install]&#xA;WantedBy=multi-user.target&#xA;Script richiamato dal servizio per la connessione alla vpn:&#xA;connessione vpn&#xA;vi /usr/local/bin/vpn-autoconnect.sh&#xA;!/bin/bash&#xA;Attende che il demone VPN sia pronto&#xA;sleep 5&#xA;Tenta la connessione (usa il nome esatto che vedi in connmanctl services)&#xA;connmanctl connect vpn1621591921&#xA;Inifine si rende il file eseguibile e si avvia il servizio&#xA;chmod +x /usr/local/bin/vpn-autoconnect.sh&#xA;&#xA;avvio servizio&#xA;systemctl daemon-reload&#xA;systemctl enable connman-vpn.service&#xA;systemctl start connman-vpn.service&#xA;E il gioco è fatto.&#xA;&#xA;Da questo momento in poi, OSMC tunnellizza tutto il suo traffico verso Cloudflare.&#xA;&#xA;Come detto, in questo modo ho &#34;solo&#34; la configurazione di un tunnel wireguard verso l&#39;endpoint Cloudflare, non dispongo delle altre funzionalità che warp-cli offre.&#xA;&#xA;Tuttavia è un procedimento abbastanza trasparente che non prevede la convivenza con ulteriori servizi come nel caso di warp-cli e che può essere un&#39;alternativa anonimizzante valida anche su una linux box normale.&#xA;&#xA;#dns #doh #dot #warp #vpn #tunnel #cloudflare #wireguard #masque #osmc]]&gt;</description>
      <content:encoded><![CDATA[<p><img src="https://pixelfed.uno/storage/m/_v2/489827599091373610/31410d826-759a86/nDDNn0ObGm8H/bTjZEfazDrIzF1UqmzhRRGXWvH807nU98C2cdm16.jpg" alt="cloudflare-warp">
È noto come l&#39;uso dei resolver Cloudflare sia uno dei modi per anonimizzare il proprio IP all&#39;ISP.</p>

<p>Cloudflare offre anche altre modalità di risoluzione ancora più efficaci:</p>
<ol><li>DNS over HTTPS (<strong>DoH</strong>)</li>
<li>DNS over TCP (<strong>DoT</strong>)</li>
<li>DNS over WARP (<strong>DoW</strong>)</li></ol>



<p>I primi due sono relativi a richieste dns crittografate e incapsulate, in una richiesta https (porta 443) la prima, e in una connessione TLS (porta 853) la seconda.</p>

<p>La terza modalità è una richiesta dns <strong>in chiaro</strong> ma all&#39;interno di un tunnel <strong>Wireguard</strong> o <strong>MASQUE</strong> (<strong>QUIC</strong> + <strong>HTTP/3</strong> – rif. <a href="https://datatracker.ietf.org/meeting/interim-2021-masque-03/materials/slides-interim-2021-masque-03-sessa-masque-interim-2021-04-h3-dgram-00" rel="nofollow">https://datatracker.ietf.org/meeting/interim-2021-masque-03/materials/slides-interim-2021-masque-03-sessa-masque-interim-2021-04-h3-dgram-00</a>). Molto interessante ed è quella che approfondirò in seguito.</p>

<p>Senza entrare nel merito, tutte le soluzioni anonimizzano le query dns. L&#39;ultima, quella che mi ha stutzzicato, è in realtà un tunnel vpn che crittografa <strong>TUTTO</strong> il traffico, non solo le richieste DNS.</p>

<p><strong>DoT</strong> è una cifratura TLS che lascia intatto il pacchetto UDP iniziale, è quindi più efficiente di <strong>DoH</strong> che converte una richieste DNS in una HTTP cifrata dal layer TLS.</p>

<p><strong>DoT</strong> di solito viene fatta a livello di dispositivo, <strong>DoH</strong> per singole applicazioni.</p>

<p><strong>DoT</strong>, basandosi su una porta specifica, 853, è facilmente identificabile (e bloccabile) come traffico DNS (benché cifrato), <strong>DoH</strong> è una richiesta HTTPS e si mescola col traffico che viaggia sulla porta 443 (difficilmente si invaliderà tutto quel tipo di traffico).</p>

<p><strong>DoT</strong>, <strong>DoH</strong>, <strong>DoW</strong>, mitigano notevolmente il <strong>cache poisoning</strong> dei resolver perché rendono quasi impossibilie per un attaccante alterare una richiesta che viene protetta per l&#39;intero percorso. Va detto che la soluzione ideale in questo contesto è la combinazione con <strong>DNSSEC</strong>, che fornisce autenticità e integrità alla riservatezza fornita da DoH/DoT.</p>

<p>Anche se l&#39;obiettivo rimane l&#39;approfondimento di CLoudflare WARP, vale la pena di spendere due parole anche sulle altre modalità di risoluzione, DoT/DoH</p>

<h2 id="configurare-risoluzioni-dns-doh">Configurare risoluzioni DNS DoH</h2>

<p>Configurare <strong>DoH</strong> è molto semplice perché è qualcosa legato all&#39;applicazione, il browser tipicamente. Se l&#39;applicazione lo supporta, di solito è poco di più di un flag da abilitare.</p>

<p>Ad es. Firefox o Chrome permettono di attivare una sorte di “protezione avanzata del DNS” indicando semplicemente un resolver che la supporti (es. Cloudflare, NextDNS o Quad9).</p>

<h2 id="configurare-risoluzioni-dns-dot">Configurare risoluzioni DNS DoT</h2>

<p>DoT, come detto, è una configurazione che avviene a livello di dispositivo, l&#39;anonimizzazione delle query DNS si ottiene quindi per <strong>ogni</strong> applicazione. Sul come farlo, dipende dal dispositivo.</p>

<p>Ad es. su una linux box basta aggiungere due righe su <code>systemd-resolved</code> e riavviare il relativo servizio.</p>

<pre><code class="language-bash">sudo vi /etc/systemd/resolved.conf
...
DNS=1.1.1.1
DNSOverTLS=yes

# dopo aver salvato il file
systemctl restart systemd-resolved
</code></pre>

<p>Un veloce test su <a href="https://1.1.1.1/help" rel="nofollow">https://1.1.1.1/help</a>  (da qualunque browser) ci mostrerà qualcosa del tipo:</p>

<pre><code>Connected to 1.1.1.1        Yes
Using DNS over HTTPS (DoH)  No
Using DNS over TLS (DoT)    Yes
Using DNS over WARP         No
AS Name                     Cloudflare, Inc.
AS Number                   13335
Cloudflare Data Center      MXP
</code></pre>

<p>indice che DoT è attivo e funzionante. Lo stesso test poteva essere fatto anche per DoH.</p>

<h2 id="cloudflare-warp">Cloudflare WARP</h2>

<p>E poi c&#39;è <strong>DoW</strong>, che è qualcosa di ancora più estremo perché, all&#39;occorrenza, anonimizza non solo le richieste DNS ma tutto il <strong>nostro</strong> traffico (e infatti diversi servizi di streaming non lo consentono).</p>

<p><strong>Cloudflare Warp</strong> attiva diverse modalità di risoluzione dns fra cui DoH e DoT.</p>

<p>Dal momento che Cloudflare Warp agisce su tutta la connessione, è il modo più semplice per avere risoluzione dns di tipo DoH o DoT, su qualunque dispositivo su cui è presente Cloudflare Warp senza gli sbattimenti di systemd o altro.</p>

<p><strong>Cloudflare Warp</strong> in modalità tunnel è un client che instaura un collegamento cifrato punto-punto (un tunnel) fra il nostro host e un endpoint Cloudflare. In questo modo ogni bit che esce dal nostro dispositivo viene cifrato prima della comunicazione, che diventa così totalmente schermata.</p>

<p>La vpn di Coudflare si basa su wireguard o su MASQUE. Nel primo caso è una normale vpn con un setup roadwarrior, il secondo caso offre in più la possibilità di associare al tunnel anche le modalità DoH/DoT per le richieste dns.</p>

<h3 id="anonimato-sì-no">Anonimato sì/no?</h3>

<p>Cloudflare WARP è uno strumento incentrato sulla sicurezza, progettato per crittografare il traffico internet e proteggere la privacy dagli ISP, piuttosto che per garantire l&#39;anonimato completo o nascondere la posizione dell&#39;utente.</p>

<p>Sostituisce l&#39;IP dell&#39;utente con un IP di Cloudflare che generalmente corrisponde alla sua reale area geografica, rendendolo inadatto a eludere le restrizioni basate sulla posizione.</p>

<p>Non è una VPN tradizionale. WARP non maschera la nostra posizione ai siti web, che spesso possono visualizzare la tua posizione approssimativa.</p>

<p>Per migliorare la privacy, si dovrebbe utilizzare il protocollo MASQUE, che offre anche una maggiore efficienza.</p>

<p>In sintesi, WARP fornisce un “tunnel sicuro” per proteggere la privacy dei dati da amministratori di rete indiscreti, protegge il traffico perché eccelle nella crittografia del traffico su reti non sicure (ad esempio, Wi-Fi pubbliche), ma non offre le funzionalità di anonimato dei tradizionali servizi VPN incentrati sulla privacy.</p>

<p>Fatta questa doverosa premessa, vediamo come può essere usato.</p>

<h3 id="configurare-cloudflare-warp">Configurare Cloudflare WARP</h3>

<p>L&#39;installazione del client è molto semplice. Per Gnu/Linux c&#39;è la versione cli, per android un app, per altri sistemi, Win /MacOS, un installer.
La parte applicativa prima di tutto registra il dispositivo sulla rete Cloudflare generando degli ID e una chiave di licenza. In un secondo momento si generano le chiavi di cifratura.</p>

<p>Per fissare le idee, una volta fatte le operazioni di inizializzazione, sulla linux box per tunnellizzare ogni nostra comunicazione con una risoluzione DoT, basta:</p>

<pre><code class="language-bash"># facoltativo
warp-cli mode warp+dot

#connessione
warp-cli connect
</code></pre>

<p>Per terminare:</p>

<pre><code class="language-bash">warp-cli disconnect
</code></pre>

<p>Questo approccio torna molto comodo quando per es. vogliamo usare wifi pubbliche, in città o in aeroporto. A meno di non avere un&#39;installazione personale di una nostra vpn, questa è una soluzione immediata. Certo, bisogna fidarsi di Cloudflare ma è certamente meglio che fidarsi delle wifi free.</p>

<p>E arriviamo al caso d&#39;uso che volevo approfondire riguardante l&#39;“anonimizzazione” di un mediacenter casalingo per il quale non vogliamo rendere noto il suo utilizzo.</p>

<p>L&#39;esperienza che ho avuto al proposito è stata interessante, visto che uso da anni OSMC su una RasbPi 3 e ho deciso di metterla dietro Cloudflare.</p>

<p><strong>OSMC</strong> insieme a <strong>LibreELEC</strong> sono ottime soluzioni di mediacenter per SBC. La prima più “general”, essendo una debian customizzata per ospitare un mediacenter, la seconda invece meno elastica ma più essenziale ed efficiente.</p>

<p>Nonostante la Raspberry Pi 3 sia dotata di un processore ARM64, la versione di OSMC che ho installato a suo tempo è a 32 bit e per quella non c&#39;è disponibilità per il client cloudflare (solo ARM64).</p>

<p>Ho dovuto ricorrere ad un client “unofficial”, <strong>wgcf</strong>, che permette di registrare il dispositivo e di generare le chiavi ma solo per la modalità Wireguard, non MASQUE, quindi niente Warp+DoT/DoH (per inciso, wgcf rappresenta un&#39;ottima alternativa anche per chi non vuole usare il client Cloudflare su Gnu/Linux).</p>

<p>A questo aggiungo che, sebbebe OSMC sia una Debian su cui posso installare e configurare tanta roba, l&#39;installazione di Wireguard, e penso di qualunque cosa che vada a toccare lo stack di rete, diventa qualcosa di estremamente complicato da fare, dal momento che OSMC si rifiuta categoricamente di eseguire operazione che metterebbero a rischio il suo essere un mediacenter, fondamentalmente.</p>

<p>Tradotto in soldoni, il client wireguard si installa, sale su correttamente ma non c&#39;è verso di far funzionare la risoluzione. L&#39;unica via d&#39;usicta è stata configurare Wireguard attraverso il gestore di rete di OSMC che è <strong>connman</strong>.</p>

<p>Una volta fatto questo, sono stati necessari solo un paio di piccoli accorgimenti per far si che, in seguito all&#39;avvio del mediacenter, la configurazione vpn venisse caricata automaticamente da connman, contestualmente alla connessione vpn.</p>

<h3 id="configurazione-wgcf">Configurazione wgcf</h3>

<pre><code class="language-bash"># Account cloudflare
curl -L https://github.com/ViRb3/wgcf/releases/latest/download/wgcf_2.2.30_linux_armv7 -o /usr/local/bin/wgcf
chmod u+x /usr/local/bin/wgcf
wgcf register
wgcf generate

# status &amp; trace
wgcf status
curl https://www.cloudflare.com/cdn-cgi/trace
</code></pre>

<h3 id="configurazione-connman">Configurazione connman</h3>

<p>Su OSMC connman ha i suoi file di configurazione in <code>/var/lib/connman</code> e <code>/var/lib/connman-vpn</code></p>

<p>Nel file di configurazione, l&#39;host va indicato con l&#39;ip non con l&#39;fqdn (engage.cloudflareclients.com)</p>

<pre><code class="language-bash"># Configurazione wireguard cloudflare
# La configurazione della vpn deve essere un file .config sotto /var/lib/connman-vpn

vi /var/lib/connman-vpn/cloudflare_warp.config
[provider_*]
Type = WireGuard
Name = Cloudflare_WARP
Host = 162.159.192.1
AutoConnect = true
WireGuard.Address = 172.16.0.2/24
WireGuard.ListenPort = 51280
WireGuard.PrivateKey = &lt;my_private_key&gt;
WireGuard.PublicKey = &lt;cloudlare_wg_public_key&gt;
WireGuard.DNS = 1.1.1.1, 1.0.0.1
WireGuard.AllowedIPs = 0.0.0.0/0
WireGuard.EndpointPort = 2408
WireGuard.PersistentKeepalive = 25
</code></pre>

<p>Dopo aver creato il file di configurazione, possiamo vedere il nuovo servizio pronto per essere richiamato da <code>comman-vpnd</code></p>

<pre><code class="language-bash"># elenco servizi attivi
connmanctl services
* AO &lt;SSID&gt;           wifi_&lt;id&gt;_managed_psk
* R Cloudflare_WARP      vpn_162_159_192_1
</code></pre>

<p>Affinché la connessione alla vpn parta all&#39;avvio di OSMC, è necessario disporre di un servizio che:</p>
<ol><li>esegua <code>common-vpnd</code> per caricare il file di configurazione</li>
<li>effettui la connessione vpn</li></ol>

<pre><code class="language-bash"># Creazione nuovo servizio in /lib/systemd/system/connman-vpn.service
[Unit]
Description=ConnMan VPN service
After=network-online.target
Wants=network-online.target

[Service]
Type=dbus
BusName=net.connman.vpn
ExecStart=/usr/sbin/connman-vpnd -n
ExecStop=/usr/local/bin/vpn-autoconnect.sh
StandardOutput=null
Restart=on-failure

[Install]
WantedBy=multi-user.target
</code></pre>

<p>Script richiamato dal servizio per la connessione alla vpn:</p>

<pre><code class="language-bash"># connessione vpn
vi /usr/local/bin/vpn-autoconnect.sh
#!/bin/bash
# Attende che il demone VPN sia pronto
sleep 5
# Tenta la connessione (usa il nome esatto che vedi in connmanctl services)
connmanctl connect vpn_162_159_192_1
</code></pre>

<p>Inifine si rende il file eseguibile e si avvia il servizio</p>

<pre><code class="language-bash">chmod +x /usr/local/bin/vpn-autoconnect.sh

# avvio servizio
systemctl daemon-reload
systemctl enable connman-vpn.service
systemctl start connman-vpn.service
</code></pre>

<p>E il gioco è fatto.</p>

<p>Da questo momento in poi, OSMC tunnellizza tutto il suo traffico verso Cloudflare.</p>

<p>Come detto, in questo modo ho “solo” la configurazione di un tunnel wireguard verso l&#39;endpoint Cloudflare, non dispongo delle altre funzionalità che <code>warp-cli</code> offre.</p>

<p>Tuttavia è un procedimento abbastanza trasparente che non prevede la convivenza con ulteriori servizi come nel caso di <code>warp-cli</code> e che può essere un&#39;alternativa anonimizzante valida anche su una linux box normale.</p>

<p><a href="/aytin/tag:dns" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">dns</span></a> <a href="/aytin/tag:doh" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">doh</span></a> <a href="/aytin/tag:dot" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">dot</span></a> <a href="/aytin/tag:warp" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">warp</span></a> <a href="/aytin/tag:vpn" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">vpn</span></a> <a href="/aytin/tag:tunnel" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">tunnel</span></a> <a href="/aytin/tag:cloudflare" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">cloudflare</span></a> <a href="/aytin/tag:wireguard" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">wireguard</span></a> <a href="/aytin/tag:masque" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">masque</span></a> <a href="/aytin/tag:osmc" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">osmc</span></a></p>
]]></content:encoded>
      <guid>https://noblogo.org/aytin/installazione-di-cloudflare-warp-su-osmc</guid>
      <pubDate>Fri, 03 Apr 2026 22:33:32 +0000</pubDate>
    </item>
    <item>
      <title>Device Mapper: LUKS + LVM</title>
      <link>https://noblogo.org/aytin/device-mapper-luks-lvm</link>
      <description>&lt;![CDATA[luks-lvm&#xA;(segue da &#34;Cenni sulla creazione di pool di storage con LVM&#34;)&#xA;...anche se è la base per una serie di sviluppi interessanti. &#xA;&#xA;Come ormai sappiamo, device mapper è il framework del kernel Linux col quale mappare dispositivi a blocchi fisici su dispositivi a blocchi logici, che costituisce la base per fornire funzionalità ulteriori quali:&#xA;!--more--&#xA;&#xA;volumi logici&#xA;raid&#xA;cifratura (Full Disk Encryption)&#xA;snapshot di volumi&#xA;&#xA;Scenario 1&#xA;È molto comune per es. cifrare l&#39;intero disco e &#34;affettarlo&#34; con volumi logici in base alle proprie esigenze di partizionamento .&#xA;&#xA;Il doppio vantaggio è dato da:&#xA;&#xA;offuscamento totale dello schema di partizionamento&#xA;estrema versatilità / flessibilità del partizionamento grazie ai volumi logici &#xA;&#xA;Come si agisce?&#xA;&#xA;si cifra il dispositivo fisico&#xA;si crea un gruppo di volumi avente come volume fisico il volume cifrato&#xA;si creano i volumi logici in base allo schema di partizionamento desiderato.&#xA;&#xA;luks-lvm&#xA;Passo 1 - Inizializzazione&#xA;Simulo il mio dispositivo fisico ricorrendo ai loop device.&#xA;&#xA;Il &#34;disco&#34; avrà una grandezza simbolica di 2 GiB, non avrà header detachable. L&#39;algoritmo di hash sarà sha512 e la chiave sarà da 512 bit. Il resto è il default di luks2 (argon2id come pbkdf, per maggiori dettagli vedi cryptsetup --help)&#xA;1. Preparazione disco &#34;fisico&#34;&#xA;fallocate -l 2g cipherdisk.img&#xA;&#xA;2. loop device che simula l&#39;attach del dispositivo&#xA;DEV=$(losetup -Pf --show cipherdisk.img)&#xA;&#xA;3. Inizializzazione cifratura&#xA;cryptsetup luksFormat  \&#xA;    --type luks2 \&#xA;    --hash sha512 \&#xA;    --key-size 512 \&#xA;    $DEV&#xA;Passo 2&#xA;Il passo successivo consiste nell&#39;apertura del dispositivo cifrato e nella definizione dello schema di partizionamento in volumi logici&#xA;1. apertura del disco cifrato&#xA;cryptsetup open \&#xA;    --type luks2 \&#xA;    $DEV cipherdisk&#xA;Nell&#39;apertura, device mapper fa la sua prima magia.&#xA;&#xA;Infatti, se osserviamo lo stato dei dispositivi, vedremo una situazione simile:&#xA;lsblk&#xA;...&#xA;loop9                7:9    Kib0     2G  0 loop  &#xA;└─cipherdisk      252:3    0     2G  0 crypt &#xA;...&#xA;Cio vuol dire che sopra il dispositivo fisico, /dev/loop9 in questo caso, device mapper ha &#34;poggiato&#34; cipherdisk (/dev/mapper/cipherdisk).&#xA;&#xA;Questo sarà il nostro volume fisico per definire gruppi di volume e, conseguentemente, i volumi logici.&#xA;2. creazione gruppo di volumi&#xA;vgcreate vglab /dev/mapper/cipherdisk&#xA;&#xA;3. creazione volumi logici&#xA;lvcreate -n lvlab1 vglab -L 700M&#xA;lvcreate -n lvlab2 vglab -L 600M&#xA;lvcreate -n lvlab3 vglab -l 100%FREE&#xA;La situazione dei dispositivi è ora questa:&#xA;lsblk&#xA;...&#xA;loop9                7:9    0     2G  0 loop  &#xA;└─cipherdisk      252:3    0     2G  0 crypt&#xA;  ├─vglab-lvlab1 252:4    0   700M  0 lvm&#xA;  ├─vglab-lvlab2 252:5    0   600M  0 lvm&#xA;  └─vglab-lvlab3 252:6    0   728M  0 lvm&#xA;...&#xA;Sopra /dev/loop9 c&#39;è cipherdisk (/dev/mapper/cipherdisk) e sopra di esso, i 3 volumi logici&#xA;&#xA;lvlab1 (/dev/mapper/vglab-lvlab1)&#xA;lvlab2 (/dev/mapper/vglab-lvlab2)&#xA;lvlab3 (/dev/mapper/vglab-lvlab3)&#xA;&#xA;Formatto e monto i volumi logici&#xA;4. formattazione dei 3 volumi logici&#xA;mkfs.ext4 /dev/mapper/vglab-lvlab1&#xA;mkfs.ext4 /dev/mapper/vglab-lvlab2&#xA;mkfs.ext4 /dev/mapper/vglab-lvlab3&#xA;&#xA;5. creo e preparo i punti di mmontaggio&#xA;mkdir disk1 disk2 disk3&#xA;mount -t ext4 -o user,noauto,rw  /dev/mapper/vglab-lvlab1 disk1&#xA;mount -t ext4 -o user,noauto,rw  /dev/mapper/vglab-lvlab2 disk2&#xA;mount -t ext4 -o user,noauto,rw  /dev/mapper/vglab-lvlab3 disk3&#xA;chown $USER disk1 disk2 disk3&#xA;&#xA;6. unmount di tutti i dispositivi&#xA;umount disk1 disk2 disk3&#xA;vgchange -an vglab&#xA;cryptsetup close cipherdisk&#xA;losetup -d $DEV&#xA;Passo 3&#xA;Infine, per completezza, gli script di mount e unmount del dispositivo.&#xA;mount&#xA;1. attach del dispositivo&#xA;DEV=$(losetup -Pf --show cipherdisk.img)&#xA;&#xA;2. Apre il disco cifrato &#xA;cryptsetup open \&#xA;    --type luks2 \&#xA;    $DEV cipherdisk&#xA;&#xA;3. monta il gruppo di volume&#xA;(opzionale. L&#39;apertura del disco cifrato dovrebbe montare &#xA;automaticamente il gruppo di volumi)&#xA;vgchange -ay vglab&#xA;&#xA;4. monta i volumi logici&#xA;mount -t ext4 -o user,noauto,rw  /dev/mapper/vglab-lvlab1 disk1&#xA;mount -t ext4 -o user,noauto,rw  /dev/mapper/vglab-lvlab2 disk2&#xA;mount -t ext4 -o user,noauto,rw  /dev/mapper/vglab-lvlab3 disk3&#xA;unmount&#xA;1. smonta i 3 dischi&#xA;umount disk1 disk2 disk3&#xA;&#xA;2. smonta il gruppo di volumi&#xA;vgchange -an vglab&#xA;&#xA;3. chiude il disco cifrato&#xA;cryptsetup close cipherdisk&#xA;&#xA;4. &#34;stacca&#34; il dispositivo fisico&#xA;losetup -d $DEV&#xA;&#xA;Questo è ciò che si farebbe normalmente quando si vuole il full disk encryption sul proprio pc. Ma con una piccola eccezione.&#xA;&#xA;In realtà ciò che viene cifrata è una partizione quasi completa del disco, perché almeno una piccola partizione, quella contenente il boot, /BOOT, deve essere in chiaro per consentire:&#xA;&#xA;a UEFI di avviare GRUB che conosce le partizioni,&#xA;GRUB provvederà all&#39;avvio del kernel,&#xA;l&#39;avvio del kernel con initramfs chiederà la password per sbloccare la partizione cifrata.&#xA;&#xA;La cifratura totale (che proprio totale non sarà perché /boot/efi deve rimanere in chiaro) eleva di molto la complessità del setup iniziale.&#xA;&#xA;Affidare a GRUB la gestione della cifratura potrebbe voler dire, oltre alla complessità della configurazione iniziale che dovrà far ricorso a moduli come cryptodisk, che bisognerà rinunciare ad Argon2 perché GRUB ancora non lo supporta pienamente e, a differenza del kernel, non ha sufficiente potenza per farlo lavorare come si deve.&#xA;&#xA;Un buon compromesso potrebbe essere il ricorso ad un dispositivo esterno, es. una pendrive, che contenga tutta la partizione /boot in chiaro, anche  l&#39;header del disco cifrato.&#xA;GRUB dovrà solo sapere dove si trovi il boot, il resto dell&#39;avvio viene affidato come di consueto al kernel.&#xA;Scenario 2&#xA;Rimanendo nell&#39;ambito dell&#39;esplorazione di device mapper e della cifratura di dispositivi esterni non avviabili, immaginiamo qualcosa di più estremo.&#xA;&#xA;Supponiamo di dover custodire un segreto in qualcosa che non sia un semplice vault cifrato.&#xA;&#xA;Per diminuire il rischio di compromettere un unico vault, decido di dividerlo in varie parti, come gli horcrux ma con 0 malignità. Ogni parte sarà cifrata con una sua chiave che affiderò ad una persona diversa, di mia fiducia. Solo io, titolare ultimo del segreto, avrò accesso ai dati e solo la mia chiave (come l&#39;Anello che li domina tutti) aprirà il vault.&#xA;&#xA;Supponiamo di avere 3 dispositivi fisici (che nel laboratoro saranno simulati da loop device come al solito) per altrettanti &#34;custodi&#34;, ognuno dei quali verrà cifrato con la chiave e con dei parametri da consegnare al &#34;custode&#34; specifico.&#xA;&#xA;I 3 dispositivi cifrati costituiranno un gruppo di volumi con un volume logico (dai requisiti posti non c&#39;è necessità di sfruttare la flessibilità di partizionamento dei volumi logici) che verrà cifrato con la mia chiave master.&#xA;&#xA;luks-lvm-luks&#xA;&#x9;&#xA;Ogni dispositivo, volume logico finale compreso, prima della cifratura, verrà inizializzato con del rumore casuale. Questo per impedire ad un&#39;analisi forense di risalire ad un qualunque pattern sul dispositivo raw.&#xA;&#xA;Caratteristiche di ogni cifratura:&#xA;&#xA;dispositivi inizializzati con rumore casuale&#xA;header detachable&#xA;offset custom&#xA;key-file&#xA;default di argon2id (controlla il tuo default con cryptsetup benchmark)&#xA;&#xA;Quando vorrò aprire il vault, sarà necessario che i 3 &#34;custodi&#34; aprano il loro &#34;pezzo&#34; e solo io potrò ricostruire e decifrare il volume con la mia chiave.&#xA;&#xA;L&#39;inzializzazione con rumore casuale dei dispositivo, tralasciando l&#39;uso di dd su /dev/urandom che sappiamo essere CPU-intensive, può essere fatta ricorrendo:&#xA;&#xA;ad openssl rand, come sappiamo da &#34;Come generare una password o un keyfile sicuri (Trilogia Della Password – 1 di 3&#34;&#xA;oppure usando furbescamente cryptsetup, con cui apriamo il dispositivo in modalità plain, senza header, e riempiendolo di zeri (da /dev/zero con dd) che, attraversando il motore di cifratura, verranno scritti sul dispositivo come dati casuali ad alta velocità.&#xA;&#xA;################################&#xA;Emulazione dei device fisici &#xA;################################&#xA;fallocate -l 512M cipherdisk1.img&#xA;fallocate -l 512M cipherdisk2.img&#xA;fallocate -l 512M cipherdisk3.img&#xA;&#xA;###########################&#xA;creazione dei 3 keyfile &#xA;###########################&#xA;keyfile del custode n° 1&#xA;dd if=/dev/urandom bs=1024 count=4 | \&#xA;    gpg --yes -o cipherdisk1.key.gpg -c \&#xA;        --s2k-mode 3 \&#xA;        --s2k-count 32505856 \&#xA;        --s2k-cipher-algo aes256 \&#xA;        --s2k-digest-algo sha512 \&#xA;        --force-mdc -&#xA;&#xA;keyfile del custode n° 2&#xA;dd if=/dev/urandom bs=1024 count=4 | \&#xA;    gpg --yes -o cipherdisk2.key.gpg -c \&#xA;        --s2k-mode 3 \&#xA;        --s2k-count 32505856 \&#xA;        --s2k-cipher-algo aes256 \&#xA;        --s2k-digest-algo sha512 \&#xA;        --force-mdc -&#xA;&#xA;keyfile del custode n° 3&#xA;dd if=/dev/urandom bs=1024 count=4 | \&#xA;    gpg --yes -o cipherdisk3.key.gpg -c \&#xA;        --s2k-mode 3 \&#xA;        --s2k-count 32505856 \&#xA;        --s2k-cipher-algo aes256 \&#xA;        --s2k-digest-algo sha512 \&#xA;        --force-mdc -&#xA;&#xA;keyfile master&#xA;dd if=/dev/urandom bs=1024 count=4 | \&#xA;    gpg --yes -o master.key.gpg -c \&#xA;        --s2k-mode 3 \&#xA;        --s2k-count 32505856 \&#xA;        --s2k-cipher-algo aes256 \&#xA;        --s2k-digest-algo sha512 \&#xA;        --force-mdc -&#xA;&#xA;##########################&#xA;cifratura dei 3 device &#xA;##########################&#xA;attach dispositivo&#xA;DEV1=$(losetup -Pf --show cipherdisk1.img)&#xA;&#xA;inizializzazione dev1 con rumore casuale&#xA;cryptsetup open --type plain ${DEV1} container --key-file /dev/urandom&#xA;dd if=/dev/zero of=/dev/mapper/container status=progress&#xA;cryptsetup close container&#xA;&#xA;cifratura dispositivo n° 1&#xA;gpg -d cipherdisk1.key.gpg | \&#xA;    cryptsetup luksFormat  \&#xA;        --type luks2 \&#xA;        --key-file - \&#xA;        --header header1.img \&#xA;        --offset 32768 \&#xA;        --hash sha512 \&#xA;        --key-size 512 \&#xA;        --cipher aes-xts-plain64 \&#xA;        ${DEV1}&#xA;&#xA;attach dispositivo&#xA;DEV2=$(losetup -Pf --show cipherdisk2.img)&#xA;&#xA;inizializzazione dev2 con rumore casuale&#xA;cryptsetup open --type plain ${DEV2} container --key-file /dev/urandom&#xA;dd if=/dev/zero of=/dev/mapper/container status=progress&#xA;cryptsetup close container&#xA;&#xA;cifratura dispositivo n° 2&#xA;gpg -d cipherdisk2.key.gpg | \&#xA;    cryptsetup luksFormat  \&#xA;        --type luks2 \&#xA;        --key-file - \&#xA;        --header header2.img \&#xA;        --offset 36864 \&#xA;        --hash sha512 \&#xA;        --key-size 512 \&#xA;        --cipher aes-xts-plain64 \&#xA;        ${DEV2}&#xA;&#xA;attach dispositivo&#xA;DEV3=$(losetup -Pf --show cipherdisk3.img)&#xA;&#xA;inizializzazione dev3 con rumore casuale&#xA;cryptsetup open --type plain ${DEV3} container --key-file /dev/urandom&#xA;dd if=/dev/zero of=/dev/mapper/container status=progress&#xA;cryptsetup close container&#xA;&#xA;cifratura dispositivo n° 3&#xA;gpg -d cipherdisk3.key.gpg | \&#xA;    cryptsetup luksFormat  \&#xA;        --type luks2 \&#xA;        --key-file - \&#xA;        --header header3.img \&#xA;        --offset 40960 \&#xA;        --hash sha512 \&#xA;        --key-size 512 \&#xA;        --cipher aes-xts-plain64 \&#xA;        ${DEV3}&#xA;&#xA;##############################&#xA;Creazione gruppo di volumi &#xA;##############################&#xA;&#34;apro&#34; il volume 1&#xA;gpg -d cipherdisk1.key.gpg | \&#xA;    cryptsetup open \&#xA;         --type luks2 \&#xA;         --header header1.img \&#xA;         --key-file - \&#xA;         ${DEV1} cipherdisk1&#xA;&#xA;&#34;apro&#34; il volume 2&#xA;gpg -d cipherdisk2.key.gpg | \&#xA;    cryptsetup open \&#xA;         --type luks2 \&#xA;         --header header2.img \&#xA;         --key-file - \&#xA;         ${DEV2} cipherdisk2&#xA;&#xA;&#34;apro&#34; il volume 3&#xA;gpg -d cipherdisk3.key.gpg | \&#xA;    cryptsetup open \&#xA;         --type luks2 \&#xA;         --header header3.img \&#xA;         --key-file - \&#xA;         ${DEV3} cipherdisk3&#xA;&#xA;Creo il mio gruppo di volumi con i 3 volumi &#34;fisici&#34;:&#xA;1. /dev/mapper/cipherdisk1&#xA;2. /dev/mapper/cipherdisk2&#xA;3. /dev/mapper/cipherdisk3&#xA;vgcreate vgmaster /dev/mapper/cipherdisk1  /dev/mapper/cipherdisk2  /dev/mapper/cipherdisk3&#xA;&#xA;creazione dell&#39;unico volume logico&#xA;lvcreate -n lvmaster vgmaster -l 100%FREE&#xA;&#xA;################################&#xA;cifratura e mount del master &#xA;################################&#xA;cifratura dispositivo master&#xA;dd if=/dev/urandom of=/dev/mapper/vgmaster-lvmaster bs=1M count=32 status=progress&#xA;gpg -d master.key.gpg | \&#xA;    cryptsetup luksFormat  \&#xA;        --type luks2 \&#xA;        --key-file - \&#xA;        --header headermaster.img \&#xA;&#x9;&#x9;--offset 65536 \&#xA;        --hash sha512 \&#xA;        --key-size 512 \&#xA;        --cipher aes-xts-plain64 \&#xA;        /dev/mapper/vgmaster-lvmaster&#xA;&#xA;apriamo il dispositivo master&#xA;gpg -d master.key.gpg | \&#xA;    cryptsetup open \&#xA;         --type luks2 \&#xA;         --header headermaster.img \&#xA;         --key-file - \&#xA;         /dev/mapper/vgmaster-lvmaster cipherdiskmaster&#xA;&#xA;e finalmente lo formattiamo&#xA;mkfs.ext4 /dev/mapper/cipherdiskmaster&#xA;&#xA;Test: montiamo il disco&#xA;mkdir -p /run/media/master/diskmaster&#xA;chown -R ${USER}:${USER} /run/media/master/diskmaster&#xA;mount -t auto /dev/mapper/cipherdiskmaster /run/media/master/diskmaster&#xA;&#xA;Infine chiudiamo tutto&#xA;umount /run/media/master/diskmaster&#xA;cryptsetup close cipherdiskmaster&#xA;vgchange -an vgmaster&#xA;cryptsetup close cipherdisk1&#xA;cryptsetup close cipherdisk2&#xA;cryptsetup close cipherdisk3&#xA;losetup -d ${DEV1} ${DEV2} ${DEV3}&#xA;Dopo aver appurato che tutto funzioni, consegno ad ogni &#34;custode&#34; dispositivo, keyfile e header.&#xA;&#xA;Se un attaccante dovesse entrare in possesso di uno o più dispositivi, troverebbe solo un mucchio di dati incomprensibili.&#xA;&#xA;Posto che riuscisse a decifrare il dispositivo, troverebbe un pezzo di un gruppo di volumi, cifrato e inutilizzabile.&#xA;&#xA;Il master a questo punto non dovrà fare altro che aprire e chiudere il vault, dopo aver riunito tutti i pezzi, come segue:&#xA;&#xA;Apertura del vault&#xA;Attach dei dispositivi&#xA;DEV1=$(losetup -Pf --show cipherdisk1.img)&#xA;DEV2=$(losetup -Pf --show cipherdisk2.img)&#xA;DEV3=$(losetup -Pf --show cipherdisk3.img)&#xA;&#xA;&#34;apro&#34; il volume 1&#xA;gpg -d cipherdisk1.key.gpg | \&#xA;    cryptsetup open \&#xA;         --type luks2 \&#xA;         --header header1.img \&#xA;         --key-file - \&#xA;         ${DEV1} cipherdisk1&#xA;&#xA;&#34;apro&#34; il volume 2&#xA;gpg -d cipherdisk2.key.gpg | \&#xA;    cryptsetup open \&#xA;         --type luks2 \&#xA;         --header header2.img \&#xA;         --key-file - \&#xA;         ${DEV2} cipherdisk2&#xA;&#xA;&#34;apro&#34; il volume 3&#xA;gpg -d cipherdisk3.key.gpg | \&#xA;    cryptsetup open \&#xA;         --type luks2 \&#xA;         --header header3.img \&#xA;         --key-file - \&#xA;         ${DEV3} cipherdisk3&#xA;&#xA;(facoltativo) apre il gruppo di volumi&#xA;vgchange -ay vgmaster&#xA;&#xA;&#34;apre&#34; il master volume&#xA;gpg -d master.key.gpg | \&#xA;    cryptsetup open \&#xA;         --type luks2 \&#xA;         --header headermaster.img \&#xA;         --key-file - \&#xA;         /dev/mapper/vgmaster-lvmaster cipherdiskmaster&#xA;&#xA;Monta il volume&#xA;mount -t auto /dev/mapper/cipherdiskmaster /run/media/master/diskmaster&#xA;Chiusura del vault&#xA;smonta il volume cifrato&#xA;umount /run/media/master/diskmaster&#xA;&#xA;chiusura del vault master&#xA;cryptsetup close cipherdiskmaster&#xA;&#xA;chiusura del gruppo di volumi&#xA;vgchange -an vgmaster&#xA;&#xA;chiusura dei singoli vault cifrati&#xA;cryptsetup close cipherdisk1&#xA;cryptsetup close cipherdisk2&#xA;cryptsetup close cipherdisk3&#xA;&#xA;deattach dei dispositivi&#xA;losetup -d ${DEV1} ${DEV2} ${DEV3}&#xA;&#xA;#cryptsetup #devicemapper #dmcrypt #gpg #loseup #luks #lvm #loopdevice #storage]]&gt;</description>
      <content:encoded><![CDATA[<p><img src="https://pixelfed.uno/storage/m/_v2/489827599091373610/fbedcc803-0ec729/JqVu1t3agiao/CSE9exMSdTVlv9adGCHXwSbkxvn9EPD0SPJNIsQo.jpg" alt="luks-lvm">
<em>(segue da <a href="https://noblogo.org/aytin/cenni-sulla-creazione-di-pool-di-storage-con-lvm/" rel="nofollow">“<strong>Cenni sulla creazione di pool di storage con LVM</strong>“</a>)</em>
...anche se è la base per una serie di sviluppi interessanti.</p>

<p>Come ormai sappiamo, <strong>device mapper</strong> è il framework del kernel Linux col quale mappare dispositivi a blocchi fisici su dispositivi a blocchi logici, che costituisce la base per fornire funzionalità ulteriori quali:
</p>
<ul><li>volumi logici</li>
<li>raid</li>
<li>cifratura (<strong>F</strong>ull <strong>D</strong>isk <strong>E</strong>ncryption)</li>
<li>snapshot di volumi</li></ul>

<h2 id="scenario-1">Scenario 1</h2>

<p>È molto comune per es. cifrare l&#39;intero disco e “affettarlo” con volumi logici in base alle proprie esigenze di partizionamento .</p>

<p>Il doppio vantaggio è dato da:</p>
<ol><li>offuscamento totale dello schema di partizionamento</li>
<li>estrema versatilità / flessibilità del partizionamento grazie ai volumi logici</li></ol>

<p>Come si agisce?</p>
<ol><li>si cifra il dispositivo fisico</li>
<li>si crea un gruppo di volumi avente come volume fisico il volume cifrato</li>
<li>si creano i volumi logici in base allo <strong>schema di partizionamento</strong> desiderato.</li></ol>

<p><img src="https://pixelfed.uno/storage/m/_v2/489827599091373610/fbedcc803-0ec729/e9tSS2DIxi6F/Bc8zWpFAR2KxQSK92F6I3Z6ocbA5E67bT3ziz1Ke.jpg" alt="luks-lvm"></p>

<h3 id="passo-1-inizializzazione">Passo 1 – Inizializzazione</h3>

<p>Simulo il mio dispositivo fisico ricorrendo ai <strong>loop device</strong>.</p>

<p>Il “disco” avrà una grandezza simbolica di 2 GiB, non avrà header detachable. L&#39;algoritmo di hash sarà sha512 e la chiave sarà da 512 bit. Il resto è il default di luks2 (argon2id come pbkdf, per maggiori dettagli vedi <code>cryptsetup --help</code>)</p>

<pre><code class="language-bash"># 1. Preparazione disco &#34;fisico&#34;
fallocate -l 2g cipher_disk.img

# 2. loop device che simula l&#39;attach del dispositivo
DEV=$(losetup -Pf --show cipher_disk.img)

# 3. Inizializzazione cifratura
cryptsetup luksFormat  \
    --type luks2 \
    --hash sha512 \
    --key-size 512 \
    $DEV
</code></pre>

<h3 id="passo-2">Passo 2</h3>

<p>Il passo successivo consiste nell&#39;apertura del dispositivo cifrato e nella definizione dello schema di partizionamento in volumi logici</p>

<pre><code class="language-bash"># 1. apertura del disco cifrato
cryptsetup open \
    --type luks2 \
    $DEV cipher_disk
</code></pre>

<p>Nell&#39;apertura, device mapper fa la sua prima magia.</p>

<p>Infatti, se osserviamo lo stato dei dispositivi, vedremo una situazione simile:</p>

<pre><code>lsblk
...
loop9                7:9    Kib0     2G  0 loop  
└─cipher_disk      252:3    0     2G  0 crypt 
...
</code></pre>

<p>Cio vuol dire che sopra il dispositivo fisico, <code>/dev/loop9</code>in questo caso, device mapper ha “poggiato” <strong>cipher_disk</strong> (<code>/dev/mapper/cipher_disk</code>).</p>

<p>Questo sarà il nostro volume fisico per definire gruppi di volume e, conseguentemente, i volumi logici.</p>

<pre><code class="language-bash"># 2. creazione gruppo di volumi
vgcreate vg_lab /dev/mapper/cipher_disk

# 3. creazione volumi logici
lvcreate -n lv_lab_1 vg_lab -L 700M
lvcreate -n lv_lab_2 vg_lab -L 600M
lvcreate -n lv_lab_3 vg_lab -l 100%FREE
</code></pre>

<p>La situazione dei dispositivi è ora questa:</p>

<pre><code>lsblk
...
loop9                7:9    0     2G  0 loop  
└─cipher_disk      252:3    0     2G  0 crypt
  ├─vg_lab-lv_lab_1 252:4    0   700M  0 lvm
  ├─vg_lab-lv_lab_2 252:5    0   600M  0 lvm
  └─vg_lab-lv_lab_3 252:6    0   728M  0 lvm
...
</code></pre>

<p>Sopra <code>/dev/loop9</code> c&#39;è <code>cipher_disk</code> (<code>/dev/mapper/cipher_disk</code>) e sopra di esso, i 3 volumi logici</p>
<ul><li><code>lv_lab_1</code> (<code>/dev/mapper/vg_lab-lv_lab_1</code>)</li>
<li><code>lv_lab_2</code> (<code>/dev/mapper/vg_lab-lv_lab_2</code>)</li>
<li><code>lv_lab_3</code> (<code>/dev/mapper/vg_lab-lv_lab_3</code>)</li></ul>

<p>Formatto e monto i volumi logici</p>

<pre><code class="language-bash"># 4. formattazione dei 3 volumi logici
mkfs.ext4 /dev/mapper/vg_lab-lv_lab_1
mkfs.ext4 /dev/mapper/vg_lab-lv_lab_2
mkfs.ext4 /dev/mapper/vg_lab-lv_lab_3

# 5. creo e preparo i punti di mmontaggio
mkdir disk_1 disk_2 disk_3
mount -t ext4 -o user,noauto,rw  /dev/mapper/vg_lab-lv_lab_1 disk_1
mount -t ext4 -o user,noauto,rw  /dev/mapper/vg_lab-lv_lab_2 disk_2
mount -t ext4 -o user,noauto,rw  /dev/mapper/vg_lab-lv_lab_3 disk_3
chown $USER disk_1 disk_2 disk_3

# 6. unmount di tutti i dispositivi
umount disk_1 disk_2 disk_3
vgchange -an vg_lab
cryptsetup close cipher_disk
losetup -d $DEV
</code></pre>

<h3 id="passo-3">Passo 3</h3>

<p>Infine, per completezza, gli script di mount e unmount del dispositivo.
<strong>mount</strong></p>

<pre><code class="language-bash"># 1. attach del dispositivo
DEV=$(losetup -Pf --show cipher_disk.img)

# 2. Apre il disco cifrato 
cryptsetup open \
    --type luks2 \
    $DEV cipher_disk

# 3. monta il gruppo di volume
# (opzionale. L&#39;apertura del disco cifrato dovrebbe montare 
# automaticamente il gruppo di volumi)
vgchange -ay vg_lab

# 4. monta i volumi logici
mount -t ext4 -o user,noauto,rw  /dev/mapper/vg_lab-lv_lab_1 disk_1
mount -t ext4 -o user,noauto,rw  /dev/mapper/vg_lab-lv_lab_2 disk_2
mount -t ext4 -o user,noauto,rw  /dev/mapper/vg_lab-lv_lab_3 disk_3
</code></pre>

<p><strong>unmount</strong></p>

<pre><code class="language-bash"># 1. smonta i 3 dischi
umount disk_1 disk_2 disk_3

# 2. smonta il gruppo di volumi
vgchange -an vg_lab

# 3. chiude il disco cifrato
cryptsetup close cipher_disk

# 4. &#34;stacca&#34; il dispositivo fisico
losetup -d $DEV
</code></pre>

<p>Questo è ciò che si farebbe normalmente quando si vuole il full disk encryption sul proprio pc. Ma con una piccola eccezione.</p>

<p>In realtà ciò che viene cifrata è una partizione quasi completa del disco, perché almeno una piccola partizione, quella contenente il boot, <code>/BOOT</code>, deve essere in chiaro per consentire:</p>
<ul><li>a UEFI di avviare GRUB che conosce le partizioni,</li>
<li>GRUB provvederà all&#39;avvio del kernel,</li>
<li>l&#39;avvio del kernel con initramfs chiederà la password per sbloccare la partizione cifrata.</li></ul>

<p>La cifratura totale (che proprio totale non sarà perché <code>/boot/efi</code> deve rimanere in chiaro) eleva di molto la complessità del setup iniziale.</p>

<p>Affidare a GRUB la gestione della cifratura potrebbe voler dire, oltre alla complessità della configurazione iniziale che dovrà far ricorso a moduli come <code>cryptodisk</code>, che bisognerà rinunciare ad Argon2 perché GRUB ancora non lo supporta pienamente e, a differenza del kernel, non ha sufficiente potenza per farlo lavorare come si deve.</p>

<p>Un buon compromesso potrebbe essere il ricorso ad un dispositivo esterno, es. una pendrive, che contenga tutta la partizione <code>/boot</code> in chiaro, anche  l&#39;header del disco cifrato.
GRUB dovrà solo sapere dove si trovi il boot, il resto dell&#39;avvio viene affidato come di consueto al kernel.</p>

<h2 id="scenario-2">Scenario 2</h2>

<p>Rimanendo nell&#39;ambito dell&#39;esplorazione di device mapper e della cifratura di dispositivi esterni non avviabili, immaginiamo qualcosa di più estremo.</p>

<p>Supponiamo di dover custodire un segreto in qualcosa che non sia un semplice vault cifrato.</p>

<p>Per diminuire il rischio di compromettere un unico vault, decido di dividerlo in varie parti, come gli horcrux ma con 0 malignità. Ogni parte sarà cifrata con una sua chiave che affiderò ad una persona diversa, di mia fiducia. Solo io, titolare ultimo del segreto, avrò accesso ai dati e solo la mia chiave (come l&#39;Anello che li domina tutti) aprirà il vault.</p>

<p>Supponiamo di avere 3 dispositivi fisici (che nel laboratoro saranno simulati da loop device come al solito) per altrettanti “custodi”, ognuno dei quali verrà cifrato con la chiave e con dei parametri da consegnare al “custode” specifico.</p>

<p>I 3 dispositivi cifrati costituiranno un gruppo di volumi con un volume logico (dai requisiti posti non c&#39;è necessità di sfruttare la flessibilità di partizionamento dei volumi logici) che verrà cifrato con la mia chiave master.</p>

<p><img src="https://pixelfed.uno/storage/m/_v2/489827599091373610/fbedcc803-0ec729/pnRafhfUlqts/Wl6xNlvrbnZJIjRVRbAIM0fmo6KZAnYoy1Wga0C2.jpg" alt="luks-lvm-luks"></p>

<p>Ogni dispositivo, volume logico finale compreso, prima della cifratura, verrà inizializzato con del rumore casuale. Questo per impedire ad un&#39;analisi forense di risalire ad un qualunque pattern sul dispositivo raw.</p>

<p>Caratteristiche di ogni cifratura:</p>
<ul><li>dispositivi inizializzati con rumore casuale</li>
<li>header detachable</li>
<li>offset custom</li>
<li>key-file</li>
<li>default di argon2id (controlla il tuo default con <code>cryptsetup benchmark</code>)</li></ul>

<p>Quando vorrò aprire il vault, sarà necessario che i 3 “custodi” aprano il loro “pezzo” e solo io potrò ricostruire e decifrare il volume con la mia chiave.</p>

<p>L&#39;inzializzazione con rumore casuale dei dispositivo, tralasciando l&#39;uso di <code>dd</code> su <code>/dev/urandom</code> che sappiamo essere CPU-intensive, può essere fatta ricorrendo:</p>
<ul><li>ad <code>openssl rand</code>, come sappiamo da <em><a href="https://noblogo.org/aytin/come-generare-una-password-o-un-keyfile-sicuri-trilogia-della-password-1-di/" rel="nofollow">“<strong>Come generare una password o un keyfile sicuri (Trilogia Della Password – 1 di 3</strong>“</a></em></li>
<li>oppure usando furbescamente <strong>cryptsetup</strong>, con cui apriamo il dispositivo in modalità plain, senza header, e riempiendolo di zeri (da <code>/dev/zero</code> con <code>dd</code>) che, attraversando il motore di cifratura, verranno scritti sul dispositivo come dati casuali ad alta velocità.</li></ul>

<pre><code class="language-bash">################################
# Emulazione dei device fisici #
################################
fallocate -l 512M cipher_disk_1.img
fallocate -l 512M cipher_disk_2.img
fallocate -l 512M cipher_disk_3.img



###########################
# creazione dei 3 keyfile #
###########################
# keyfile del custode n° 1
dd if=/dev/urandom bs=1024 count=4 | \
    gpg --yes -o cipher_disk_1.key.gpg -c \
        --s2k-mode 3 \
        --s2k-count 32505856 \
        --s2k-cipher-algo aes256 \
        --s2k-digest-algo sha512 \
        --force-mdc -

# keyfile del custode n° 2
dd if=/dev/urandom bs=1024 count=4 | \
    gpg --yes -o cipher_disk_2.key.gpg -c \
        --s2k-mode 3 \
        --s2k-count 32505856 \
        --s2k-cipher-algo aes256 \
        --s2k-digest-algo sha512 \
        --force-mdc -

# keyfile del custode n° 3
dd if=/dev/urandom bs=1024 count=4 | \
    gpg --yes -o cipher_disk_3.key.gpg -c \
        --s2k-mode 3 \
        --s2k-count 32505856 \
        --s2k-cipher-algo aes256 \
        --s2k-digest-algo sha512 \
        --force-mdc -

# keyfile master
dd if=/dev/urandom bs=1024 count=4 | \
    gpg --yes -o master.key.gpg -c \
        --s2k-mode 3 \
        --s2k-count 32505856 \
        --s2k-cipher-algo aes256 \
        --s2k-digest-algo sha512 \
        --force-mdc -



##########################
# cifratura dei 3 device #
##########################
# attach dispositivo
DEV_1=$(losetup -Pf --show cipher_disk_1.img)

# inizializzazione dev_1 con rumore casuale
cryptsetup open --type plain ${DEV_1} container --key-file /dev/urandom
dd if=/dev/zero of=/dev/mapper/container status=progress
cryptsetup close container

# cifratura dispositivo n° 1
gpg -d cipher_disk_1.key.gpg | \
    cryptsetup luksFormat  \
        --type luks2 \
        --key-file - \
        --header header_1.img \
        --offset 32768 \
        --hash sha512 \
        --key-size 512 \
        --cipher aes-xts-plain64 \
        ${DEV_1}

# attach dispositivo
DEV_2=$(losetup -Pf --show cipher_disk_2.img)

# inizializzazione dev_2 con rumore casuale
cryptsetup open --type plain ${DEV_2} container --key-file /dev/urandom
dd if=/dev/zero of=/dev/mapper/container status=progress
cryptsetup close container

# cifratura dispositivo n° 2
gpg -d cipher_disk_2.key.gpg | \
    cryptsetup luksFormat  \
        --type luks2 \
        --key-file - \
        --header header_2.img \
        --offset 36864 \
        --hash sha512 \
        --key-size 512 \
        --cipher aes-xts-plain64 \
        ${DEV_2}

# attach dispositivo
DEV_3=$(losetup -Pf --show cipher_disk_3.img)

# inizializzazione dev_3 con rumore casuale
cryptsetup open --type plain ${DEV_3} container --key-file /dev/urandom
dd if=/dev/zero of=/dev/mapper/container status=progress
cryptsetup close container

# cifratura dispositivo n° 3
gpg -d cipher_disk_3.key.gpg | \
    cryptsetup luksFormat  \
        --type luks2 \
        --key-file - \
        --header header_3.img \
        --offset 40960 \
        --hash sha512 \
        --key-size 512 \
        --cipher aes-xts-plain64 \
        ${DEV_3}



##############################
# Creazione gruppo di volumi #
##############################
# &#34;apro&#34; il volume 1
gpg -d cipher_disk_1.key.gpg | \
    cryptsetup open \
         --type luks2 \
         --header header_1.img \
         --key-file - \
         ${DEV_1} cipher_disk_1

# &#34;apro&#34; il volume 2
gpg -d cipher_disk_2.key.gpg | \
    cryptsetup open \
         --type luks2 \
         --header header_2.img \
         --key-file - \
         ${DEV_2} cipher_disk_2

# &#34;apro&#34; il volume 3
gpg -d cipher_disk_3.key.gpg | \
    cryptsetup open \
         --type luks2 \
         --header header_3.img \
         --key-file - \
         ${DEV_3} cipher_disk_3

# Creo il mio gruppo di volumi con i 3 volumi &#34;fisici&#34;:
# 1. /dev/mapper/cipher_disk_1
# 2. /dev/mapper/cipher_disk_2
# 3. /dev/mapper/cipher_disk_3
vgcreate vg_master /dev/mapper/cipher_disk_1  /dev/mapper/cipher_disk_2  /dev/mapper/cipher_disk_3

# creazione dell&#39;unico volume logico
lvcreate -n lv_master vg_master -l 100%FREE



################################
# cifratura e mount del master #
################################
# cifratura dispositivo master
dd if=/dev/urandom of=/dev/mapper/vg_master-lv_master bs=1M count=32 status=progress
gpg -d master.key.gpg | \
    cryptsetup luksFormat  \
        --type luks2 \
        --key-file - \
        --header header_master.img \
		--offset 65536 \
        --hash sha512 \
        --key-size 512 \
        --cipher aes-xts-plain64 \
        /dev/mapper/vg_master-lv_master

# apriamo il dispositivo master
gpg -d master.key.gpg | \
    cryptsetup open \
         --type luks2 \
         --header header_master.img \
         --key-file - \
         /dev/mapper/vg_master-lv_master cipher_disk_master

# e finalmente lo formattiamo
mkfs.ext4 /dev/mapper/cipher_disk_master

# Test: montiamo il disco
mkdir -p /run/media/master/disk_master
chown -R ${USER}:${USER} /run/media/master/disk_master
mount -t auto /dev/mapper/cipher_disk_master /run/media/master/disk_master

# Infine chiudiamo tutto
umount /run/media/master/disk_master
cryptsetup close cipher_disk_master
vgchange -an vg_master
cryptsetup close cipher_disk_1
cryptsetup close cipher_disk_2
cryptsetup close cipher_disk_3
losetup -d ${DEV_1} ${DEV_2} ${DEV_3}
</code></pre>

<p>Dopo aver appurato che tutto funzioni, consegno ad ogni “custode” dispositivo, keyfile e header.</p>

<p>Se un attaccante dovesse entrare in possesso di uno o più dispositivi, troverebbe solo un mucchio di dati incomprensibili.</p>

<p>Posto che riuscisse a decifrare il dispositivo, troverebbe un pezzo di un gruppo di volumi, cifrato e inutilizzabile.</p>

<p>Il master a questo punto non dovrà fare altro che aprire e chiudere il vault, dopo aver riunito tutti i pezzi, come segue:</p>

<p><strong>Apertura del vault</strong></p>

<pre><code class="language-bash"># Attach dei dispositivi
DEV_1=$(losetup -Pf --show cipher_disk_1.img)
DEV_2=$(losetup -Pf --show cipher_disk_2.img)
DEV_3=$(losetup -Pf --show cipher_disk_3.img)

# &#34;apro&#34; il volume 1
gpg -d cipher_disk_1.key.gpg | \
    cryptsetup open \
         --type luks2 \
         --header header_1.img \
         --key-file - \
         ${DEV_1} cipher_disk_1

# &#34;apro&#34; il volume 2
gpg -d cipher_disk_2.key.gpg | \
    cryptsetup open \
         --type luks2 \
         --header header_2.img \
         --key-file - \
         ${DEV_2} cipher_disk_2

# &#34;apro&#34; il volume 3
gpg -d cipher_disk_3.key.gpg | \
    cryptsetup open \
         --type luks2 \
         --header header_3.img \
         --key-file - \
         ${DEV_3} cipher_disk_3

# (facoltativo) apre il gruppo di volumi
vgchange -ay vg_master

# &#34;apre&#34; il master volume
gpg -d master.key.gpg | \
    cryptsetup open \
         --type luks2 \
         --header header_master.img \
         --key-file - \
         /dev/mapper/vg_master-lv_master cipher_disk_master

# Monta il volume
mount -t auto /dev/mapper/cipher_disk_master /run/media/master/disk_master
</code></pre>

<p><strong>Chiusura del vault</strong></p>

<pre><code class="language-bash"># smonta il volume cifrato
umount /run/media/master/disk_master

# chiusura del vault master
cryptsetup close cipher_disk_master

# chiusura del gruppo di volumi
vgchange -an vg_master

# chiusura dei singoli vault cifrati
cryptsetup close cipher_disk_1
cryptsetup close cipher_disk_2
cryptsetup close cipher_disk_3

# deattach dei dispositivi
losetup -d ${DEV_1} ${DEV_2} ${DEV_3}
</code></pre>

<p><a href="/aytin/tag:cryptsetup" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">cryptsetup</span></a> <a href="/aytin/tag:devicemapper" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">devicemapper</span></a> <a href="/aytin/tag:dmcrypt" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">dmcrypt</span></a> <a href="/aytin/tag:gpg" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">gpg</span></a> <a href="/aytin/tag:loseup" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">loseup</span></a> <a href="/aytin/tag:luks" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">luks</span></a> <a href="/aytin/tag:lvm" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">lvm</span></a> <a href="/aytin/tag:loopdevice" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">loopdevice</span></a> <a href="/aytin/tag:storage" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">storage</span></a></p>
]]></content:encoded>
      <guid>https://noblogo.org/aytin/device-mapper-luks-lvm</guid>
      <pubDate>Mon, 23 Feb 2026 10:58:17 +0000</pubDate>
    </item>
    <item>
      <title>Archiviare le password in sicurezza con KDF/password-hashing (Trilogia Della Password - 3 di 3)</title>
      <link>https://noblogo.org/aytin/archiviare-le-password-in-sicurezza-con-kdf-password-hashing-trilogia-della</link>
      <description>&lt;![CDATA[password hashing&#xA;&#xA;Dopo aver capito come creare password inviolabili anche avendo a disposizione tutta l&#39;energia termica dell&#39;universo, pensiamo al modo migliore per archiviarle.&#xA;&#xA;Pensare di lasciare la password raw in un database, rappresenta un grosso rischio in virtù di un possibile attacco offline.&#xA;!--more--&#xA;&#xA;Rainbow Table&#xA;Come ti blocco la Rainbow Table: Il “Salt” (sale)&#xA;Il livello successivo: Il Pepper&#xA;Final step: L’hashing&#xA;  PBKDF2&#xA;  Bcrypt&#xA;  Scrypt&#xA;  yescrypt&#xA;  Argon2&#xA;Un piccolo esempio: hashing di una password con Argon2&#xA;Gestione del pepper&#xA;HSM&#xA;Key / Algo Rotation&#xA;  Caso A: Algo rotation&#xA;  Caso B: Pepper rotation&#xA;&#xA;Una prima linea di difesa consiste nel memorizzare il digest della password, una stringa alfanumerica univoca generata da un apposito algoritmo, così da lasciare nelle mani dell&#39;attaccante degli oggetti che, per la loro non invertibilità, non permettono di risalire alle password.&#xA;&#xA;La scelta dell&#39;algoritmo di hashing diventa critica al fine di scongiurare altri tipi di attacchi. Ad es. SHA-256, pur essendo ottimo e molto efficiente per il digest e la firma anche di file di grandi dimensioni, mostra il fianco, proprio in virtù della sua velocità, nel caso di attacchi con:&#xA;&#xA;brute-force: si calcola l’hash di password casuali fino a trovare una corrispondenza,&#xA;dizionario: un&#39;alternativa intelligente alla forza bruta. Si punta alle password più comuni, si calcola l&#39;hash e si controlla se c&#39;è corrispondenza.&#xA;Rainbow Table: l&#39;attacco al dizionario più insidioso di tutti&#xA;&#xA;Oltre al fatto che, la funzione di hashing , essendo deterministica, permette di capire chi sono gli utenti che hanno la stessa password, dal momento che avranno lo stesso digest.&#xA;Rainbow Table&#xA;Una Rainbow Table è un enorme dizionario pre-calcolato che contiene:&#xA;&#xA;Milioni di password comuni.&#xA;Il relativo hash corrispondente.&#xA;&#xA;Invece di calcolare l’entropia di ogni tentativo, l’attaccante ruba il database degli hash e fa un semplice “Cerca e Trova”. Se l’hash della tua password è nella tabella, la tua password è violata in millisecondi, indipendentemente da quanto fosse alta la sua entropia teorica.&#xA;&#xA;smallOss.: Una password totalmente casuale, generata da un CSPRNG affidabile, con un&#39;alta entropia (  120), rimarrebbe comunque inviolabile anche dalla rainbow table perché la probabilità che quella password si trovi nel dizionario, sarebbe equivalente ad indovinarla./small&#xA;Come ti blocco la Rainbow Table: Il “Salt” (sale)&#xA;Per rendere inutili le Rainbow Table, i sistemi sicuri utilizzano il Salt. Il salt è una stringa di dati casuali (generati da una sorgente d’entropia affidabile ovviamente) che viene aggiunta alla password prima di calcolarne il digest.&#xA;&#xA;In questo modo le rainbow table vengono vanificate perché gli hash precalcolati sulle password raccolte, mancando il salt, non valgono più. Anche se due utenti avessero la stessa password, avrebbero degli hash completamente diversi.&#xA;&#xA;Anche per questo motivo non è un problema che il salt sia pubblico, perché il suo obiettivo non è nascondere quello che è un pezzetto di password a tutti gli effetti, ma di impedire economie di scala degli attacchi perché, pur potendo disporre offline di un database di decine di milioni di utenti, gli hash della mia Rainbow Table (che può arrivare a pesare anche decine di GB) andrebbero tutti ricalcolati per ogni utente, con un costo computazionale e di archiviazione inimmaginabile.&#xA;&#xA;Per riassumere, gli ingredienti di base sono:&#xA;&#xA;una buona sorgente d’entropia: una fonte di casualità certificata per generare un salt unico;&#xA;entropia della password: sempre buona norma, ove possibile, come sappiamo ormai fare (https://noblogo.org/aytin/come-generare-una-password-o-un-keyfile-sicuri-trilogia-della-password-1-di). Evita attacchi brute-force o al dizionario in cui l’attaccante prova a indovinare;&#xA;salt: protegge la password dagli attacchi basati su database pre-calcolati (Rainbow Table).&#xA;&#xA;Il livello successivo: Il Pepper&#xA;È vero che col salt andiamo a complicare lo sfruttamento di un attacco offline ma possiamo fare di meglio.&#xA;&#xA;Il punto d&#39;attenzione è che il salt protegge le password di tutti gli utenti.&#xA;Ma un attaccante potrebbe non essere affatto interessato a violare ogni singolo utente (niente economia di scala) ma solo alcuni. E allora l&#39;attacco attraverso Ranbow Table potrebbe essere di nuovo praticabile.&#xA;&#xA;Ma gli informatici sono dei gran giocherelloni, si sa.&#xA;Visto che abbiamo già il &#34;sale&#34;, perché non finire aggiustando con un po’ di “pepe”? Detto, fatto!&#xA;&#xA;Il pepper, come il salt, è un&#39;altra password generata con gli stessi criteri del salt ma le analogie finiscono qua perché:&#xA;&#xA;a differenza del salt che si trova nel database, il pepper è separato da ques&#39;ultimo. L&#39;ideale sarebbe un HSM;&#xA;Il salt è visibile a tutti, attaccante compreso. Il pepper è segreto. Un eventuale data breach che permette all&#39;attaccante di disporre offline di tutto il database degli utenti, &#34;vedrà&#34; certamente gli eventuali salt ma sarà ignaro del fatto che gli mancherà sempre un pezzo di chiave;&#xA;il salt è diverso per ogni utente, il pepper, di solito, è unico;&#xA;il salt serve a rendere uniche la password degli utenti, il pepper protegge l&#39;intero database da attacchi offline.&#xA;&#xA;Il pepper è la chiave di un HMAC, o di un meccanismo di cifratura simmetrica, applicato al digest della password (che ricordo essere salt+password in realtà), che sarà ciò che verrà archiviato.&#xA;&#xA;Va detto che l&#39;uso del &#34;pepper&#34; complica ulteriormente lo scenario di archiviazione.&#xA;Nella stragrande maggioranza dei casi è sufficiente scegliere un buon algoritmo di password hashing (vedi paragrafo successivo) per scoraggiare gli attaccanti.&#xA;&#34;Pepare&#34; le password prevederebbe, come detto sopra, l&#39;uso di un HSM per es, e tutta una serie di riflessioni di contorno che evidenzierò più avanti.&#xA;Final step: L&#39;hashing&#xA;L&#39;ultimo punto da dettagliare è l&#39;hash della password.&#xA;&#xA;L&#39;hash crittografico, in uso in questi casi, deve soddisfare le seguenti proprietà:&#xA;&#xA;resistenza alla pre-immagine: dato un hash h, deve essere impossibile trovare una password p t.c. H(p) = h (non invertibilità della funzione hash)&#xA;resistenza alla pre-immagine secondaria: dato una password psub1/sub, deve essere impossibile trovare un&#39;altra password psub2/sub t.c. H(psub1/sub) = H(psub2/sub) (resistenza debole alle collisioni)&#xA;resistenza alle collisioni: è impossibile trovare due password diverse, psub1/sub e psub2/sub, t.c. H(psub1/sub) = H(psub2/sub) (resistenza forte alle collisioni)&#xA;effetto valanga: il cambio di un solo bit della password deve cambiare radicalmente l&#39;intero hash&#xA;&#xA;In un sistema moderno, l&#39;hash non può essere delegato a funzioni di tipo SHA perché nascono per altri compiti,&#xA;&#xA;SHA-2 e SHA-3 nascono per il digest veloce, per verificare l&#39;integrità di file anche molto grossi o firmare documenti. La loro eccellente velocità diventa il loro più grosso difetto quando si parla di password.&#xA;Negli scenari precedenti di attachi offline, l&#39;hacker che dispone di una grossa potenza di calcolo, può ricostituire velocemente le rainbow table per n utenti. Magari non di tutti ma di quelli attenzionati.&#xA;&#xA;Le funzioni di derivazione della chiave (KDF) come pbkdf2 e quelle ancora più estreme come B/Scrypt, Argon2, oltre che soddisfare tutti i punti precedentemente elencati tipici di funzioni di password hashing, sono progettate per essere computazionalmente pesantissime da calcolare perché il loro scopo non è il digest ma la protezione di un segreto contro il brute-force.&#xA;E mentre le vecchie KDF come pbdfk2 sono CPU bound, ma non GPU bound, le KDF più moderne come Bcrypt, Scrypt ma soprattutto Argon2, agiscono pesantemente su tempo, memoria e parallelismo e l&#39;attacco offline di cui sopra diventa impraticabile.&#xA;PBKDF2&#xA;È il decano delle KDF. Applica iterativamente una funzione pseudorandomica, come HMAC con uno SHA, con salt alla password.&#xA;Il conteggio delle iterazioni è un parametro configurabile.&#xA;&#xA;PBDKF2 è uno standard di lunga data ampiamente adottato. Se non ci sono necessità stringenti di sicurezza o requisiti legacy, è una buona scelta.&#xA;&#xA;Il fatto di essere solo CPU bound però non la rende la scelta ideale in scenari dove gli attaccanti possono attingere a risorse di calcolo considerevoli&#xA;Bcrypt&#xA;Basato su Blowfish, anche Bcrypt usa un hash crittografico sulla password con parametri il salt e un fattore di costo.&#xA;&#xA;Il fattore di costo aumenta esponenzialmente il numero di iterazioni per adattarsi all&#39;aumento di potenza di calcolo dell&#39;hardware.&#xA;&#xA;Bcrypt è stato progetto per essere lento e resistente a semplici attacchi di forzat bruta.&#xA;Tuttavia, il basso utilizzo di ram richiesto dal calcolo lo rendono poco resistente ad attacchi sferrati usando hardware specializzato.&#xA;&#xA;Bcrypt ha dalla sua una storia solidissima in ragione della quale da 20 anni a questa parte non sono state trovate vulnerabilità critiche nel suo design.&#xA;&#xA;Per questo motivo Bcrypt cifra le password di sistema di OpenBSD dal 1999, come pure ha cifrato quelle di tante distro Linux per anni, prima che passassero ad Argon2 o yescrypt (default di Fedora).&#xA;&#xA;Domina nei framework web (\[Python\] Django, \[Ruby\] Ruby on Rails, \[PHP\] Laravel), \[Java\] Spring, Node.js), nelle applicazioni (Ansible / Terraform, Docker), nel web (la cifratura in .htpasswd di Apache e Nginx) visto che la sua semplcitià di implementazione gli ha permesso di trovarsi praticamente in ogni linguaggio.&#xA;&#xA;È presente come alternativa anche nei password manager benché molti di essi abbiano spostato il default verso Argon2 o PBKDF2 per conformità agli standard FIPS.&#xA;&#xA;È molto semplice implementare e anche da usare perché bisogna agire solo sul fattore di costo (consigliato almeno 10-12, altrimenti diventa troppo vulnerabile ad attacchi sferrati attraverso la GPU)&#xA;Scrypt&#xA;Rilasciato nel 2009, Scrypt è stato il primo algoritmo a introdurre il concetto di Memory Hardness ed è stato progettato per rendere economicamente poco conveniente il ricorso ad hardware specializzato come gli ASIC o i FPGA e incidere pesantemente su CPU, ram e parallelismo.&#xA;&#xA;Il suo alveo principale sono state le cripto-valute, molte monete lo usano per il mining.&#xA;&#xA;Scrypt lo troviamo in quasi tutti i linguaggi di programmazione, in Tarsnap, servizio di baclup online creato dallo stesso autore di Scrypt, è stato usato da LastPass ed è presente come opzione in VeraCrypt per derivare la chiave dalla password.&#xA;Fino ad Android 9 era l&#39;algoritmo usato per la FDE del dispositvio (passato poi al FBE) .&#xA;Presente anche su FreeBSD come opzione per la cifratura delle password di sistema e come opzione su LUKS per la cifratura degli slot delle chiavi.&#xA;&#xA;Su Scrypt i parametri da configurare sono:&#xA;&#xA;Costro CPU/Memoria (N): un parametro che aumenta i costi computazionali di cpu e memoria&#xA;DImensione del blocco (R): influenza la larghezza di banda della memoria&#xA;Parallelizzazione (p): indica quanto deve incidere sul calcolo parallelo&#xA;&#xA;In questo modo riesce ad essere sia CPU bound che GPU bound che, a differenza di Bcrypt, lo rende resistente anche ad attacchi facenti uso di hardware specializzato..&#xA;&#xA;Di contro, in ambiente in cui siamo vincolati dalle risorse disponibili, la sua potenza diventa un fattore limitante.&#xA;Quasi paragonabile ad Argon2 in quanto a robustezza, il suo unico tallone d&#39;Achille è la permeabilità ad attacchi di tipo side-channel. &#xA;yescrypt&#xA;Piccola menzione per yescrypt, appartenente alla famiglia &#34;Scrypt&#34;, pensato per essere ancora più resistente di Scrypt agli attacchi GPU e FPGA ma con una gestione più intelligente delle risorse.&#xA;&#xA;Grazie alle sue peculiarità, di fatto, è diventato il successore spirituale di Bcrypt nei sistemi operativi gnu/linux dove, a cominciare da Fedora, passando per Debian, Ubuntu, Arch, Kali, è il default per la cifratura delle password di sistema in /etc/shadow.&#xA;&#xA;È talmente incardinato ormai nei sistemi operativi, che è la libreria libxcrypt di yescrypt a gestire la tipica funzione crypt() di C che è la base della crittografia su tutti i sistemi gnu/linux moderni.&#xA;&#xA;La sua robustezza unita alla gestione intelligente delle risorse lo rende un coltellino svizzero di riferimento utile per es. per versione custom di LUKS su sistemi embedded, che magari fanno uso di cpu meno recenti,  oppure come opzione per strumenti di backup specialistici&#xA;&#xA;Di fatto, sui sistemi operativi, yescrypt s&#39;è guadagnato un consenso amplissimo dovuto alla sua scalabilità, alla sua capacità di usare anche la ROM per rendere il cracking ancora più difficile e senza pesare sulla RAM e alla sua compatibilità potendosi inserire perfettamente nella storica funzione crypt() di C come detto prima.&#xA;&#xA;Se Argon2 è il vincitore accademico avendo vinto il Password Hashing Competition del 2015, yescrypt per la sua robustezza, efficienza e flessibilità si ritaglia un profilo di indispensabilità nei sistemi operativi,&#xA;Argon2&#xA;E veniamo al dominatore indiscusso di questa che non è una llista esaustiva di KDF.&#xA;&#xA;Argon2 è LO standard moderno per il password hashing raccomandato da OWASP e IETF.&#xA;&#xA;È il riferimento per praticamente ogni password manager: Bitwarden, KeppasXC, 1Password, a cui assegnanp la protezione della Master Password&#xA;&#xA;È la scelta principale per la cifratura degli hard disk anche con impostazioni molto aggressive, in ragione delle quali un ritardo di mezzo secondo (un tempo enorme se venisse scalato esponenzialmente) nell&#39;apertura di un HD è assolutamente accettabile.&#xA;È il default di LUKS2 (LUKS1 usava PBKDF2) e di VeraCrypt, con cui ha sostituito SHA-512.&#xA;&#xA;Come Bcrypt, è implementato estensivamente su praticamente ogni frameword web e backend, da PHP, Django (Python), Laravel fino a Node.js.&#xA;&#xA;Nei sistemi operativi, laddove yescrytpt domina nella gestione delle password utente, Argon2 è usato per compiti più critici.&#xA;Dal kernel Linux per gestire internamente le chiavi crittografiche o da macOS / iOS, dove algoritmi proprietari ispirati fortemente ad Argon2, proteggono i dati nel Secure Enclave.&#xA;&#xA;Argon2  setta 3 parametri principali per regolare la sua forza:&#xA;&#xA;t: iterazioni, quante volte vengono rimescolati i dati (default Bitwarden = 3)&#xA;m: memoria, quanta ram deve occupare il calcolo. Questa è la misura anti-GPU (default Bitwarden = 16 (64MB))&#xA;p: parallelismo, quanti core della cpu usare. Questa è la misura anti-CPU (default Bitwarden = 4)&#xA;&#xA;La variante id è anche resistente agli attacchi side-channel perché impediscono a un attaccante di capire la password osservando i tempi di accesso alla memoria.&#xA;&#xA;Un piccolo esempio: hashing di una password con Argon2&#xA;Il grosso vantaggio degli algoritmi di kdf è che sono naturalmente resilienti rispetto all&#39;evoluzione tecnologica che produce macchine con sempre maggiore potenza di calcolo.&#xA;Da pbkdf2 in poi, il salt implicito che invalida le rainbow table precalcolate e la possibilità di calibrare il key stretching in moda da agire intensivamente su ram e cpu, permettono all&#39;algoritmo di adeguarsi per conservare la sua robustezza.&#xA;&#xA;Mini-script per l&#39;hashing di una password fornita dall&#39;utente con argon2 settato al default di Bitwarden:&#xA;echo -n &#34;Password: &#34;; read -s PASSWORD&#xA;Genero un Salt casuale di 128 bit&#xA;SALT=$(openssl rand -base64 128)&#xA;PASSWORDHASH=$(echo &#34;${PASSWORD}&#34; | argon2 &#34;${SALT}&#34; -m 16 -t 3 -p 4 -id -e)&#xA;&#xA;PASSWORDHASH e SALT sono i dati che verranno archiviati e, poiché argon2 &#34;frulla&#34; la password con un salt, è praticamente impossibile risalire alla password originale.&#xA;&#xA;La verifica è tuttavia banale perché, avendo il salt e la password da verificare, si ricrea l&#39;hash con argon2 e si confronta con l&#39;hash memorizzato.&#xA;&#xA;Per maggior sicurezza salt e digest possono essere memorizzati in punti differenti. L&#39;importante è che possano essere recuperate a partire dall&#39;utente.&#xA;Gestione del pepper&#xA;Col pepper le cose cambiano un pochino perché:&#xA;&#xA;deve essere archiviato con tutte le paranoie possibili in un punto diverso dal database degli utenti&#xA;il key rotation del pepper non è banale&#xA;&#xA;Mini-script che mostra come applicare salt e pepper all&#39;hashing di una password:&#xA;L&#39;utente inserisce la password&#xA;echo -n &#34;Password: &#34;; read -s PASSWORD&#xA;&#xA;Genero un Salt casuale di 128 bit unico per ogni utente&#xA;SALT=$(openssl rand -base64 128)&#xA;&#xA;Anche PEPPER sarà qualcosa del tipo &#34;openssl rand -base64 128&#34;&#xA;e si troverà in un punto esterno al database degli utenti.&#xA;PEPPER=$(getpepperfromext)&#xA;&#xA;Digest della password+salt&#xA;PASSWORDHASH=$(echo &#34;${PASSWORD}&#34; | argon2 &#34;${SALT}&#34; -m 16 -t 3 -p 4 -id -e)&#xA;&#xA;HMAC del digest con PEPPER come chiave&#xA;PASSWORDPEPPER=$(echo &#34;${PASSWORDHASH}&#34; | openssl dgst -sha256 -hmac &#34;${PEPPER}&#34; -binary | base64)&#xA;HSM&#xA;Quella vista prima è una versione molto edulcorata di ciò che avviene nella realtà.&#xA;Il pepper, non può essere gestito con leggerezza visto che è un segreto che protegge non un singolo oggetto ma intere classi, come db di utenti.&#xA;&#xA;L&#39;apparato che gestisce chiavi di questo tipo e di questa importanza, deve essere robusto, praticamente inattaccabile, quasi completamente isolato dal resto dei sistemi a meno delle applicazioni, e solo di quelle, che hanno il permesso di richiedere una chiave,&#xA;&#xA;Apparati hardware specializzati che assolvono a tutte queste funzioni e anche di più, sono gli HSM (Hardware Security Module) che garantiscono il ciclo di vita delle chiavi, dalla generazione alla distruzione, includendo versionamento, rotazione e backup.&#xA;Sono concepiti per resistere anche a manipolazioni forzate che possono innescare un meccanismo di autodistruzione e, particolare rilevante, le operazioni crittografiche basate sulle chiavi protette vengono svolte dall&#39;hsm che consegna al client il risultato delle operazioni, non le chiavi. Nel nostro caso, l&#39;HSM dovrebbe restituirci l&#39;hmac del digest della password che gli inviamo.&#xA;Key / Algo Rotation&#xA;Cosa succede se cambio pepper o algoritmo (anche la sua configurazione)?&#xA;Non avendo disponibilità in alcun modo della password dovrò adottare una strategia ad-hoc.&#xA;Fra tutti gli scenari possibili, il miglior compromesso fra sicurezza e comodità secondo me, è quello basato sul wrapping.&#xA;&#xA;È necessario innanzitutto che vengano conservate le versioni delle chiavi per i servizi che le richiedono. E a questo dovrebbe pensarci l&#39;HSM, se ce n&#39;è uno o qualcosa di custom che abbia funzionalità analoghe.&#xA;Inoltre dovrebbero esserci dei flag che indichino quali sono gli utenti a cui sono state applicate le nuove configurazioni.&#xA;&#xA;Caso A: Algo rotation&#xA;Supponiamo che l&#39;algoritmo di hashing venga cambiato o vengano cambiate le sue configurazioni.&#xA;&#xA;Premessa:&#xA;Nel mio DB degli utenti, in corrispondenza di ogni utente, avrò:&#xA;&#xA;il digest della password &#34;pepato&#34;: HMAC ( pepper, HASH ( salt, password ) ) &#xA;il salt&#xA;&#xA;Il wrapping:&#xA;La strategia sarà quello di &#34;avvolgere&#34; la password di ogni utente col nuovo algoritmo, settare un qualche flag che mi indichi l&#39;operazione compiuta e archiviare il tutto.&#xA;&#xA;Imponiamo il nuovo algoritmo a tutti gli utenti &#34;imbustando&#34; il digest attuale (in questo caso &#39;HMAC in realtà, visto che abbiamo a che fare anche col pepper) con il nuovo digest HASH\NEW:&#xA;HASH\NEW ( salt\new, HMAC ( pepper, HASH ( salt, password ) ) ).&#xA;Per ogni utente averemo dunque:&#xA;&#x9;il nuovo digest al posto di quello vecchio,&#xA;&#x9;il nuovo salt &#xA;&#x9;il vecchio salt&#xA;Settiamo il flag del cambio algoritmo a true (o quello che è)&#xA;Quando l&#39;utente effettuerà il login con successo e il flag sarà a &#34;true&#34;, abbiamo la password che ci permetterà di eliminare il vecchio &#34;involucro&#34; e ripristinare l&#39;HMAC del nuovo digest: HMAC ( pepper, HASH\NEW ( salt\new, password ) ) e il flag ritornerà a &#34;false&#34;&#xA;&#xA;Considerazioni:&#xA;&#xA;La sicurezza non viene compromessa perché il digest di un digest, con KDF configurate a dovere, non comporta alcun rischio.&#xA;La fase di verifica è quella che si complica di più perché in base al valore del flag, dovrà essere effettuata in maniera differente.&#xA;   Se il flag è &#34;true&#34; (nella nostra convenzione), dopo il login devo avere gli elementi per calcolare il digest in questo modo: HASH\NEW ( salt\new, HMAC ( pepper, HASH ( salt, password ) ) ).&#xA;   Se il flag è a false, calcolerò al solito: HMAC ( pepper, HASH\NEW ( salt\new, password ) )&#xA;&#xA;Caso B: Pepper rotation&#xA;Supponiamo che a ruotare sia il pepper.&#xA;Procediamo sempre con il wrapping massivo su tutti gli utenti incapsulando il digest :&#xA;&#xA;HMAC ( pepper, HASH ( salt, password ) )&#xA;&#xA;con quello nuovo:&#xA;&#xA;HMAC ( pepper\new, HMAC ( pepper, HASH ( salt, password ) ) )&#xA;&#xA;mettendo il flag a &#34;true&#34;.&#xA;&#xA;Come prima, una volta che gli utenti cominceranno a fare il login, se il flag è &#34;true&#34; innanzitutto verificherò che:&#xA;&#xA;HMAC ( pepper\new, HMAC ( pepper, HASH ( salt, password ) ) ) &#xA;&#xA;sia uguale a ciò che è stato archiviato.&#xA;Se così fosse, ora che sono di nuovo in possesso della password, ripristinerò l&#39;HMAC con:&#xA;&#xA;HMAC ( pepper\new, HASH ( salt, password ) )_&#xA;&#xA;memorizzandolo al posto di quello vecchio e rimettendo il flag a false.&#xA;&#xA;Considerazioni:&#xA;La modifica massiva delle password degli utenti, stavolta passa dall&#39;HSM e potrebbe essere un problema perché un HSM è progettato per scoraggiare flooding di richieste.&#xA;&#xA;È vero che il pepper è sempre lo stesso per tutti gli utenti ma, come ricordavo prima, di solito un HSM non fornisce i suoi segreti ma solo i risultati crittografici delle loro applicazioni.&#xA;&#xA;#kdf #pbkdf2 #bcrypt #scrypt #yescrypt #argon2 #luks #cryptography #aes #sha #digest #RainbowTable #BruteForce #salt #pepper #entropy #hsm #hmac #hash]]&gt;</description>
      <content:encoded><![CDATA[<p><img src="https://pixelfed.uno/storage/m/_v2/489827599091373610/ffe7c43a6-a8b5f2/dnumO91UA8rS/L0t7UvdH6Z7pYPEvBDVb3aulMdNhW1WPBRIRKHMF.jpg" alt="password hashing"></p>

<p>Dopo aver capito come creare password inviolabili anche avendo a disposizione tutta l&#39;energia termica dell&#39;universo, pensiamo al modo migliore per archiviarle.</p>

<p>Pensare di lasciare la password raw in un database, rappresenta un grosso rischio in virtù di un possibile attacco offline.
</p>
<ul><li><a href="#rainbow-table" rel="nofollow">Rainbow Table</a></li>
<li><a href="#come-ti-blocco-la-rainbow-table-il-salt-sale" rel="nofollow">Come ti blocco la Rainbow Table: Il “Salt” (sale)</a></li>
<li><a href="#il-livello-successivo-il-pepper" rel="nofollow">Il livello successivo: Il Pepper</a></li>
<li><a href="#final-step-l-hashing" rel="nofollow">Final step: L’hashing</a>
<ul><li><a href="#pbkdf2" rel="nofollow">PBKDF2</a></li>
<li><a href="#bcrypt" rel="nofollow">Bcrypt</a></li>
<li><a href="#scrypt" rel="nofollow">Scrypt</a></li>
<li><a href="#yescrypt" rel="nofollow">yescrypt</a></li>
<li><a href="#argon2" rel="nofollow">Argon2</a></li></ul></li>
<li><a href="#un-piccolo-esempio-hashing-di-una-password-con-argon2" rel="nofollow">Un piccolo esempio: hashing di una password con Argon2</a></li>
<li><a href="#gestione-del-pepper" rel="nofollow">Gestione del pepper</a></li>
<li><a href="#hsm" rel="nofollow">HSM</a></li>
<li><a href="#key-algo-rotation" rel="nofollow">Key / Algo Rotation</a>
<ul><li><a href="#caso-a-algo-rotation" rel="nofollow">Caso A: Algo rotation</a></li>
<li><a href="#caso-b-pepper-rotation" rel="nofollow">Caso B: Pepper rotation</a></li></ul></li></ul>

<p>Una prima linea di difesa consiste nel memorizzare il <strong>digest della password</strong>, una stringa alfanumerica univoca generata da un apposito algoritmo, così da lasciare nelle mani dell&#39;attaccante degli oggetti che, per la loro non invertibilità, non permettono di risalire alle password.</p>

<p>La <strong>scelta</strong> dell&#39;algoritmo di hashing diventa critica al fine di scongiurare altri tipi di attacchi. Ad es. SHA-256, pur essendo ottimo e molto efficiente per il digest e la firma anche di file di grandi dimensioni, mostra il fianco, proprio in virtù della sua velocità, nel caso di attacchi con:</p>
<ul><li><strong>brute-force:</strong> si calcola l’hash di password casuali fino a trovare una corrispondenza,</li>
<li><strong>dizionario:</strong> un&#39;alternativa intelligente alla forza bruta. Si punta alle password più comuni, si calcola l&#39;hash e si controlla se c&#39;è corrispondenza.</li>
<li><strong>Rainbow Table:</strong> l&#39;attacco al dizionario più insidioso di tutti</li></ul>

<p>Oltre al fatto che, la funzione di hashing , essendo deterministica, permette di capire chi sono gli utenti che hanno la stessa password, dal momento che avranno lo stesso digest.</p>

<h2 id="rainbow-table">Rainbow Table</h2>

<p>Una <strong>Rainbow Table</strong> è un enorme dizionario pre-calcolato che contiene:</p>
<ul><li>Milioni di password comuni.</li>
<li>Il relativo hash corrispondente.</li></ul>

<p>Invece di calcolare l’entropia di ogni tentativo, l’attaccante ruba il database degli hash e fa un semplice “Cerca e Trova”. Se l’hash della tua password è nella tabella, la tua password è violata in millisecondi, indipendentemente da quanto fosse alta la sua entropia teorica.</p>

<p><small><strong>Oss.:</strong> Una password totalmente casuale, generata da un CSPRNG affidabile, con un&#39;alta entropia (&gt;120), rimarrebbe comunque inviolabile anche dalla rainbow table perché la probabilità che quella password si trovi nel dizionario, sarebbe equivalente ad indovinarla.</small></p>

<h2 id="come-ti-blocco-la-rainbow-table-il-salt-sale">Come ti blocco la Rainbow Table: Il “Salt” (sale)</h2>

<p>Per rendere inutili le Rainbow Table, i sistemi sicuri utilizzano il <strong>Salt</strong>. Il salt è una stringa di dati casuali (generati da una sorgente d’entropia affidabile ovviamente) che viene aggiunta alla password prima di calcolarne il digest.</p>

<p>In questo modo le rainbow table vengono vanificate perché gli hash precalcolati sulle password raccolte, mancando il salt, non valgono più. Anche se due utenti avessero la stessa password, avrebbero degli hash completamente diversi.</p>

<p>Anche per questo motivo non è un problema che il salt sia pubblico, perché il suo obiettivo non è nascondere quello che è un pezzetto di password a tutti gli effetti, ma di impedire <strong>economie di scala</strong> degli attacchi perché, pur potendo disporre offline di un database di decine di milioni di utenti, gli hash della mia Rainbow Table (che può arrivare a pesare anche decine di GB) <strong>andrebbero tutti ricalcolati per ogni utente</strong>, con un costo computazionale e di archiviazione inimmaginabile.</p>

<p>Per riassumere, gli ingredienti di base sono:</p>
<ol><li><strong>una buona sorgente d’entropia:</strong> una fonte di casualità certificata per generare un salt unico;</li>
<li><strong>entropia della password:</strong> sempre buona norma, ove possibile, come sappiamo ormai fare (<a href="https://noblogo.org/aytin/come-generare-una-password-o-un-keyfile-sicuri-trilogia-della-password-1-di" rel="nofollow">https://noblogo.org/aytin/come-generare-una-password-o-un-keyfile-sicuri-trilogia-della-password-1-di</a>). Evita attacchi brute-force o al dizionario in cui l’attaccante prova a indovinare;</li>
<li><strong>salt:</strong> protegge la password dagli attacchi basati su database pre-calcolati (Rainbow Table).</li></ol>

<h2 id="il-livello-successivo-il-pepper">Il livello successivo: Il Pepper</h2>

<p>È vero che col salt andiamo a complicare lo sfruttamento di un attacco offline ma possiamo fare di meglio.</p>

<p>Il punto d&#39;attenzione è che il salt protegge le password di <strong>tutti gli utenti</strong>.
Ma un attaccante potrebbe non essere affatto interessato a violare <strong>ogni singolo utente</strong> (niente economia di scala) ma solo alcuni. E allora l&#39;attacco attraverso Ranbow Table potrebbe essere di nuovo praticabile.</p>

<p>Ma gli informatici sono dei gran giocherelloni, si sa.
Visto che abbiamo già il “sale”, perché non finire aggiustando con un po’ di “pepe”? Detto, fatto!</p>

<p>Il <strong>pepper</strong>, come il salt, è un&#39;altra password generata con gli stessi criteri del salt ma le analogie finiscono qua perché:</p>
<ul><li>a differenza del <strong>salt</strong> che si trova nel database, il <strong>pepper</strong> è separato da ques&#39;ultimo. L&#39;ideale sarebbe un <strong>HSM</strong>;</li>
<li>Il <strong>salt</strong> è visibile a tutti, attaccante compreso. Il <strong>pepper</strong> è segreto. Un eventuale data breach che permette all&#39;attaccante di disporre offline di tutto il database degli utenti, “vedrà” certamente gli eventuali salt ma sarà ignaro del fatto che gli mancherà sempre un pezzo di chiave;</li>
<li>il <strong>salt</strong> è diverso per ogni utente, il <strong>pepper</strong>, di solito, è unico;</li>
<li>il <strong>salt</strong> serve a rendere uniche la password degli utenti, il <strong>pepper</strong> protegge l&#39;intero database da attacchi offline.</li></ul>

<p><strong>Il pepper è la chiave di un HMAC, o di un meccanismo di cifratura simmetrica, applicato al digest della password</strong> (che ricordo essere salt+password in realtà), che sarà ciò che verrà archiviato.</p>

<p>Va detto che l&#39;uso del “pepper” complica ulteriormente lo scenario di archiviazione.
Nella stragrande maggioranza dei casi è sufficiente scegliere un buon algoritmo di password hashing (vedi paragrafo successivo) per scoraggiare gli attaccanti.
“Pepare” le password prevederebbe, come detto sopra, l&#39;uso di un HSM per es, e tutta una serie di riflessioni di contorno che evidenzierò più avanti.</p>

<h2 id="final-step-l-hashing">Final step: L&#39;hashing</h2>

<p>L&#39;ultimo punto da dettagliare è l&#39;hash della password.</p>

<p>L&#39;<strong>hash crittografico</strong>, in uso in questi casi, deve soddisfare le seguenti proprietà:</p>
<ol><li><strong>resistenza alla pre-immagine:</strong> dato un hash <em>h</em>, deve essere impossibile trovare una password <em>p</em> t.c. <em>H(p) = h</em> (non invertibilità della funzione hash)</li>
<li><strong>resistenza alla pre-immagine secondaria:</strong> dato una password <em>p<sub>1</sub></em>, deve essere impossibile trovare un&#39;altra password <em>p<sub>2</sub></em> t.c. <em>H(p<sub>1</sub>) = H(p<sub>2</sub>)</em> (resistenza debole alle collisioni)</li>
<li><strong>resistenza alle collisioni:</strong> è impossibile trovare due password diverse, <em>p<sub>1</sub></em> e <em>p<sub>2</sub></em>, t.c. <em>H(p<sub>1</sub>) = H(p<sub>2</sub>)</em> (resistenza forte alle collisioni)</li>
<li><strong>effetto valanga:</strong> il cambio di un solo bit della password deve cambiare radicalmente l&#39;intero hash</li></ol>

<p>In un sistema moderno, l&#39;hash non può essere delegato a funzioni di tipo SHA perché nascono per altri compiti,</p>

<p><strong>SHA-2</strong> e <strong>SHA-3</strong> nascono per il digest veloce, per verificare l&#39;integrità di file anche molto grossi o firmare documenti. La loro eccellente velocità diventa il loro più grosso difetto quando si parla di password.
Negli scenari precedenti di attachi offline, l&#39;hacker che dispone di una grossa potenza di calcolo, può ricostituire velocemente le rainbow table per <em>n</em> utenti. Magari non di tutti ma di quelli attenzionati.</p>

<p>Le funzioni di derivazione della chiave (<strong>KDF</strong>) come <strong>pbkdf2</strong> e quelle ancora più estreme come <strong>B/Scrypt</strong>, <strong>Argon2</strong>, oltre che soddisfare tutti i punti precedentemente elencati tipici di funzioni di password hashing, sono progettate per essere computazionalmente pesantissime da calcolare perché il loro scopo non è il digest ma la protezione di un segreto contro il brute-force.
E mentre le vecchie KDF come <strong>pbdfk2</strong> sono CPU bound, ma non GPU bound, le KDF più moderne come <strong>Bcrypt</strong>, <strong>Scrypt</strong> ma soprattutto <strong>Argon2</strong>, agiscono pesantemente su tempo, memoria e parallelismo e l&#39;attacco offline di cui sopra diventa impraticabile.</p>

<h3 id="pbkdf2">PBKDF2</h3>

<p>È il decano delle KDF. Applica iterativamente una funzione pseudorandomica, come HMAC con uno SHA, con salt alla password.
Il conteggio delle iterazioni è un parametro configurabile.</p>

<p>PBDKF2 è uno standard di lunga data ampiamente adottato. Se non ci sono necessità stringenti di sicurezza o requisiti legacy, è una buona scelta.</p>

<p>Il fatto di essere solo CPU bound però non la rende la scelta ideale in scenari dove gli attaccanti possono attingere a risorse di calcolo considerevoli</p>

<h3 id="bcrypt">Bcrypt</h3>

<p>Basato su Blowfish, anche Bcrypt usa un hash crittografico sulla password con parametri il salt e un fattore di costo.</p>

<p>Il fattore di costo aumenta esponenzialmente il numero di iterazioni per adattarsi all&#39;aumento di potenza di calcolo dell&#39;hardware.</p>

<p>Bcrypt è stato progetto per essere lento e resistente a semplici attacchi di forzat bruta.
Tuttavia, il basso utilizzo di ram richiesto dal calcolo lo rendono poco resistente ad attacchi sferrati usando hardware specializzato.</p>

<p>Bcrypt ha dalla sua una storia solidissima in ragione della quale da 20 anni a questa parte non sono state trovate vulnerabilità critiche nel suo design.</p>

<p>Per questo motivo Bcrypt cifra le password di sistema di OpenBSD dal 1999, come pure ha cifrato quelle di tante distro Linux per anni, prima che passassero ad Argon2 o <strong>yescrypt</strong> (default di Fedora).</p>

<p>Domina nei framework web ([Python] Django, [Ruby] Ruby on Rails, [PHP] Laravel), [Java] Spring, Node.js), nelle applicazioni (Ansible / Terraform, Docker), nel web (la cifratura in .htpasswd di Apache e Nginx) visto che la sua semplcitià di implementazione gli ha permesso di trovarsi praticamente in ogni linguaggio.</p>

<p>È presente come alternativa anche nei password manager benché molti di essi abbiano spostato il default verso Argon2 o PBKDF2 per conformità agli standard FIPS.</p>

<p>È molto semplice implementare e anche da usare perché bisogna agire solo sul <strong>fattore di costo</strong> (consigliato almeno 10-12, altrimenti diventa troppo vulnerabile ad attacchi sferrati attraverso la GPU)</p>

<h3 id="scrypt">Scrypt</h3>

<p>Rilasciato nel 2009, Scrypt è stato il primo algoritmo a introdurre il concetto di <strong>Memory Hardness</strong> ed è stato progettato per rendere economicamente poco conveniente il ricorso ad hardware specializzato come gli ASIC o i FPGA e incidere pesantemente su CPU, ram e parallelismo.</p>

<p>Il suo alveo principale sono state le cripto-valute, molte monete lo usano per il mining.</p>

<p>Scrypt lo troviamo in quasi tutti i linguaggi di programmazione, in <strong>Tarsnap</strong>, servizio di baclup online creato dallo stesso autore di Scrypt, è stato usato da <strong>LastPass</strong> ed è presente come opzione in <strong>VeraCrypt</strong> per derivare la chiave dalla password.
Fino ad Android 9 era l&#39;algoritmo usato per la <strong>FDE</strong> del dispositvio (passato poi al <strong>FBE</strong>) .
Presente anche su FreeBSD come opzione per la cifratura delle password di sistema e come opzione su <strong>LUKS</strong> per la cifratura degli slot delle chiavi.</p>

<p>Su Scrypt i parametri da configurare sono:</p>
<ul><li><strong>Costro CPU/Memoria <em>(N)</em>:</strong> un parametro che aumenta i costi computazionali di cpu e memoria</li>
<li><strong>DImensione del blocco <em>®</em>:</strong> influenza la larghezza di banda della memoria</li>
<li><strong>Parallelizzazione <em>(p)</em>:</strong> indica quanto deve incidere sul calcolo parallelo</li></ul>

<p>In questo modo riesce ad essere sia CPU bound che GPU bound che, a differenza di Bcrypt, lo rende resistente anche ad attacchi facenti uso di hardware specializzato..</p>

<p>Di contro, in ambiente in cui siamo vincolati dalle risorse disponibili, la sua potenza diventa un fattore limitante.
Quasi paragonabile ad Argon2 in quanto a robustezza, il suo unico tallone d&#39;Achille è la permeabilità ad attacchi di tipo <strong>side-channel</strong>.</p>

<h3 id="yescrypt">yescrypt</h3>

<p>Piccola menzione per <strong>yescrypt</strong>, appartenente alla famiglia “Scrypt”, pensato per essere ancora più resistente di Scrypt agli attacchi GPU e FPGA ma con una gestione più intelligente delle risorse.</p>

<p>Grazie alle sue peculiarità, di fatto, è diventato il successore spirituale di Bcrypt nei sistemi operativi gnu/linux dove, a cominciare da Fedora, passando per Debian, Ubuntu, Arch, Kali, è il default per la cifratura delle password di sistema in <code>/etc/shadow</code>.</p>

<p>È talmente incardinato ormai nei sistemi operativi, che è la libreria <code>libxcrypt</code> di <strong>yescrypt</strong> a gestire la tipica funzione <code>crypt()</code> di C che è la base della crittografia su tutti i sistemi gnu/linux moderni.</p>

<p>La sua robustezza unita alla gestione intelligente delle risorse lo rende un coltellino svizzero di riferimento utile per es. per versione custom di LUKS su sistemi embedded, che magari fanno uso di cpu meno recenti,  oppure come opzione per strumenti di backup specialistici</p>

<p>Di fatto, sui sistemi operativi, <strong>yescrypt</strong> s&#39;è guadagnato un consenso amplissimo dovuto alla sua scalabilità, alla sua capacità di usare anche la ROM per rendere il cracking ancora più difficile e senza pesare sulla RAM e alla sua compatibilità potendosi inserire perfettamente nella storica funzione <code>crypt()</code> di C come detto prima.</p>

<p>Se Argon2 è il vincitore accademico avendo vinto il Password Hashing Competition del 2015, <strong>yescrypt</strong> per la sua robustezza, efficienza e flessibilità si ritaglia un profilo di indispensabilità nei sistemi operativi,</p>

<h3 id="argon2">Argon2</h3>

<p>E veniamo al dominatore indiscusso di questa che non è una llista esaustiva di KDF.</p>

<p>Argon2 è LO standard moderno per il password hashing raccomandato da OWASP e IETF.</p>

<p>È il riferimento per praticamente ogni password manager: <strong>Bitwarden</strong>, <strong>KeppasXC</strong>, <strong>1Password</strong>, a cui assegnanp la protezione della <strong>Master Password</strong></p>

<p>È la scelta principale per la cifratura degli hard disk anche con impostazioni molto aggressive, in ragione delle quali un ritardo di mezzo secondo (un tempo enorme se venisse scalato esponenzialmente) nell&#39;apertura di un HD è assolutamente accettabile.
È il default di <strong>LUKS2</strong> (LUKS1 usava PBKDF2) e di <strong>VeraCrypt</strong>, con cui ha sostituito SHA-512.</p>

<p>Come Bcrypt, è implementato estensivamente su praticamente ogni frameword web e backend, da PHP, Django (Python), Laravel fino a Node.js.</p>

<p>Nei sistemi operativi, laddove <strong>yescrytpt</strong> domina nella gestione delle password utente, <strong>Argon2</strong> è usato per compiti più critici.
Dal kernel Linux per gestire internamente le chiavi crittografiche o da macOS / iOS, dove algoritmi proprietari ispirati fortemente ad Argon2, proteggono i dati nel Secure Enclave.</p>

<p>Argon2  setta 3 parametri principali per regolare la sua forza:</p>
<ul><li><strong>t: iterazioni</strong>, quante volte vengono rimescolati i dati <em>(default Bitwarden = 3)</em></li>
<li><strong>m: memoria</strong>, quanta ram deve occupare il calcolo. Questa è la misura anti-GPU <em>(default Bitwarden = 16 (64MB))</em></li>
<li><strong>p: parallelismo</strong>, quanti core della cpu usare. Questa è la misura anti-CPU <em>(default Bitwarden = 4)</em></li></ul>

<p>La variante <em>id</em> è anche resistente agli <strong>attacchi side-channel</strong> perché impediscono a un attaccante di capire la password osservando i tempi di accesso alla memoria.</p>

<h2 id="un-piccolo-esempio-hashing-di-una-password-con-argon2">Un piccolo esempio: hashing di una password con Argon2</h2>

<p>Il grosso vantaggio degli algoritmi di kdf è che sono naturalmente resilienti rispetto all&#39;evoluzione tecnologica che produce macchine con sempre maggiore potenza di calcolo.
Da pbkdf2 in poi, il salt implicito che invalida le rainbow table precalcolate e la possibilità di calibrare il key stretching in moda da agire intensivamente su ram e cpu, permettono all&#39;algoritmo di adeguarsi per conservare la sua robustezza.</p>

<p>Mini-script per l&#39;hashing di una password fornita dall&#39;utente con argon2 settato al default di Bitwarden:</p>

<pre><code class="language-bash">echo -n &#34;Password: &#34;; read -s PASSWORD
# Genero un Salt casuale di 128 bit
SALT=$(openssl rand -base64 128)
PASSWORD_HASH=$(echo &#34;${PASSWORD}&#34; | argon2 &#34;${SALT}&#34; -m 16 -t 3 -p 4 -id -e)
</code></pre>

<p><code>PASSWORD_HASH</code> e <code>SALT</code> sono i dati che verranno archiviati e, poiché argon2 “frulla” la password con un salt, è praticamente impossibile risalire alla password originale.</p>

<p>La verifica è tuttavia banale perché, avendo il salt e la password da verificare, si ricrea l&#39;hash con argon2 e si confronta con l&#39;hash memorizzato.</p>

<p>Per maggior sicurezza salt e digest possono essere memorizzati in punti differenti. L&#39;importante è che possano essere recuperate a partire dall&#39;utente.</p>

<h2 id="gestione-del-pepper">Gestione del pepper</h2>

<p>Col pepper le cose cambiano un pochino perché:</p>
<ul><li>deve essere archiviato con tutte le paranoie possibili in un punto diverso dal database degli utenti</li>
<li>il key rotation del pepper non è banale</li></ul>

<p>Mini-script che mostra come applicare salt e pepper all&#39;hashing di una password:</p>

<pre><code class="language-bash"># L&#39;utente inserisce la password
echo -n &#34;Password: &#34;; read -s PASSWORD

# Genero un Salt casuale di 128 bit unico per ogni utente
SALT=$(openssl rand -base64 128)

# Anche PEPPER sarà qualcosa del tipo &#34;openssl rand -base64 128&#34;
# e si troverà in un punto esterno al database degli utenti.
PEPPER=$(get_pepper_from_ext)

# Digest della password+salt
PASSWORD_HASH=$(echo &#34;${PASSWORD}&#34; | argon2 &#34;${SALT}&#34; -m 16 -t 3 -p 4 -id -e)

# HMAC del digest con PEPPER come chiave
PASSWORD_PEPPER=$(echo &#34;${PASSWORD_HASH}&#34; | openssl dgst -sha256 -hmac &#34;${PEPPER}&#34; -binary | base64)
</code></pre>

<h2 id="hsm">HSM</h2>

<p>Quella vista prima è una versione molto edulcorata di ciò che avviene nella realtà.
Il pepper, non può essere gestito con leggerezza visto che è un segreto che protegge non un singolo oggetto ma intere classi, come db di utenti.</p>

<p>L&#39;apparato che gestisce chiavi di questo tipo e di questa importanza, deve essere robusto, praticamente inattaccabile, quasi completamente isolato dal resto dei sistemi a meno delle applicazioni, e solo di quelle, che hanno il permesso di richiedere una chiave,</p>

<p>Apparati hardware specializzati che assolvono a tutte queste funzioni e anche di più, sono gli <strong>HSM</strong> (<strong>H</strong>ardware <strong>S</strong>ecurity <strong>M</strong>odule) che garantiscono il ciclo di vita delle chiavi, dalla generazione alla distruzione, includendo versionamento, rotazione e backup.
Sono concepiti per resistere anche a manipolazioni forzate che possono innescare un meccanismo di autodistruzione e, particolare rilevante, <strong>le operazioni crittografiche basate sulle chiavi protette vengono svolte dall&#39;hsm che consegna al client il risultato delle operazioni, non le chiavi</strong>. Nel nostro caso, l&#39;HSM dovrebbe restituirci l&#39;hmac del digest della password che gli inviamo.</p>

<h2 id="key-algo-rotation">Key / Algo Rotation</h2>

<p>Cosa succede se cambio pepper o algoritmo (anche la sua configurazione)?
Non avendo disponibilità in alcun modo della password dovrò adottare una strategia ad-hoc.
Fra tutti gli scenari possibili, il miglior compromesso fra sicurezza e comodità secondo me, è quello basato sul wrapping.</p>

<p>È necessario innanzitutto che vengano conservate le versioni delle chiavi per i servizi che le richiedono. E a questo dovrebbe pensarci l&#39;HSM, se ce n&#39;è uno o qualcosa di custom che abbia funzionalità analoghe.
Inoltre dovrebbero esserci dei flag che indichino quali sono gli utenti a cui sono state applicate le nuove configurazioni.</p>

<h3 id="caso-a-algo-rotation">Caso A: Algo rotation</h3>

<p>Supponiamo che <strong>l&#39;algoritmo di hashing venga cambiato</strong> o vengano cambiate le sue configurazioni.</p>

<p><strong>Premessa:</strong>
Nel mio DB degli utenti, in corrispondenza di ogni utente, avrò:</p>
<ol><li>il digest della password “pepato”: <em>HMAC ( pepper, HASH ( salt, password ) )</em></li>
<li>il salt</li></ol>

<p><strong>Il wrapping:</strong>
La strategia sarà quello di “avvolgere” la password di ogni utente col nuovo algoritmo, settare un qualche flag che mi indichi l&#39;operazione compiuta e archiviare il tutto.</p>
<ol><li>Imponiamo il nuovo algoritmo a tutti gli utenti “imbustando” il digest attuale (in questo caso &#39;HMAC in realtà, visto che abbiamo a che fare anche col pepper) con il nuovo digest <em><strong>HASH_NEW</strong></em>:
<em><strong>HASH_NEW</strong> ( <strong>salt_new</strong>, HMAC ( pepper, HASH ( salt, password ) ) )</em>.</li>
<li>Per ogni utente averemo dunque:
<ol><li>il nuovo digest al posto di quello vecchio,</li>
<li>il nuovo salt</li>
<li>il vecchio salt</li></ol></li>
<li>Settiamo il flag del cambio algoritmo a <em>true</em> (o quello che è)</li>
<li>Quando l&#39;utente effettuerà il login con successo e il flag sarà a “<em>true</em>”, abbiamo la password che ci permetterà di eliminare il vecchio “involucro” e ripristinare l&#39;HMAC del nuovo digest: <em>HMAC ( pepper, <strong>HASH_NEW</strong> ( <strong>salt_new</strong>, password ) )</em> e il flag ritornerà a “<em>false</em>“</li></ol>

<p><strong>Considerazioni:</strong></p>
<ul><li>La sicurezza non viene compromessa perché il digest di un digest, con KDF configurate a dovere, non comporta alcun rischio.</li>
<li>La fase di verifica è quella che si complica di più perché in base al valore del flag, dovrà essere effettuata in maniera differente.
<ul><li>Se il flag è “<em>true</em>” (nella nostra convenzione), dopo il login devo avere gli elementi per calcolare il digest in questo modo: <em><strong>HASH_NEW</strong> ( <strong>salt_new</strong>, HMAC ( pepper, HASH ( salt, password ) ) )</em>.</li>
<li>Se il flag è a <em>false</em>, calcolerò al solito: <em>HMAC ( pepper, <strong>HASH_NEW</strong> ( <strong>salt_new</strong>, password ) )</em></li></ul></li></ul>

<h3 id="caso-b-pepper-rotation">Caso B: Pepper rotation</h3>

<p>Supponiamo che a ruotare sia il pepper.
Procediamo sempre con il wrapping massivo su tutti gli utenti incapsulando il digest :</p>

<p><em>HMAC ( pepper, HASH ( salt, password ) )</em></p>

<p>con quello nuovo:</p>

<p><em>HMAC ( <strong>pepper_new</strong>, HMAC ( pepper, HASH ( salt, password ) ) )</em></p>

<p>mettendo il flag a “<em>true</em>”.</p>

<p>Come prima, una volta che gli utenti cominceranno a fare il login, se il flag è “<em>true</em>” innanzitutto verificherò che:</p>

<p><em>HMAC ( <strong>pepper_new</strong>, HMAC ( pepper, HASH ( salt, password ) ) )</em></p>

<p>sia uguale a ciò che è stato archiviato.
Se così fosse, ora che sono di nuovo in possesso della password, ripristinerò l&#39;HMAC con:</p>

<p><em>HMAC ( <strong>pepper_new</strong>, HASH ( salt, password ) )</em></p>

<p>memorizzandolo al posto di quello vecchio e rimettendo il flag a false.</p>

<p><strong>Considerazioni:</strong>
La modifica massiva delle password degli utenti, stavolta passa dall&#39;HSM e potrebbe essere un problema perché un HSM è progettato per scoraggiare flooding di richieste.</p>

<p>È vero che il pepper è sempre lo stesso per tutti gli utenti ma, come ricordavo prima, di solito un HSM non fornisce i suoi segreti ma solo <strong>i risultati crittografici delle loro applicazioni.</strong></p>

<p><a href="/aytin/tag:kdf" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">kdf</span></a> <a href="/aytin/tag:pbkdf2" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">pbkdf2</span></a> <a href="/aytin/tag:bcrypt" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">bcrypt</span></a> <a href="/aytin/tag:scrypt" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">scrypt</span></a> <a href="/aytin/tag:yescrypt" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">yescrypt</span></a> <a href="/aytin/tag:argon2" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">argon2</span></a> <a href="/aytin/tag:luks" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">luks</span></a> <a href="/aytin/tag:cryptography" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">cryptography</span></a> <a href="/aytin/tag:aes" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">aes</span></a> <a href="/aytin/tag:sha" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">sha</span></a> <a href="/aytin/tag:digest" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">digest</span></a> <a href="/aytin/tag:RainbowTable" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">RainbowTable</span></a> <a href="/aytin/tag:BruteForce" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">BruteForce</span></a> <a href="/aytin/tag:salt" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">salt</span></a> <a href="/aytin/tag:pepper" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">pepper</span></a> <a href="/aytin/tag:entropy" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">entropy</span></a> <a href="/aytin/tag:hsm" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">hsm</span></a> <a href="/aytin/tag:hmac" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">hmac</span></a> <a href="/aytin/tag:hash" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">hash</span></a></p>
]]></content:encoded>
      <guid>https://noblogo.org/aytin/archiviare-le-password-in-sicurezza-con-kdf-password-hashing-trilogia-della</guid>
      <pubDate>Thu, 29 Jan 2026 17:49:50 +0000</pubDate>
    </item>
    <item>
      <title>Come valutare la resistenza di una password (Trilogia Della Password - 2 di 3)</title>
      <link>https://noblogo.org/aytin/come-valutare-la-resistenza-di-una-password-trilogia-della-password-2-di-3</link>
      <description>&lt;![CDATA[ent,zxcvb,diceware&#xA;&#xA;In &#34;Come generare una password o un keyfile sicuri&#34; abbiamo visto come generare password e keyfile che si basassero su dati il più possibile casuali.&#xA;La verifica matematica di una password si basa sulla determinazione del numero di tentativi necessari a un attaccante per indovinarla.&#xA;!--more--&#xA;Esistono due approcci: quello teorico (brute force) e quello realistico (pattern matching).&#xA;&#xA;Calcolo teorico (Entropia di Shannon)&#xA;  Spiegazione dell’entropia di Shannon&#xA;  Esempi d’uso&#xA;Calcolo realistico (pattern matching)&#xA;  Ent&#xA;  zxcvbn&#xA;  Riassumendo&#xA;Metodo Diceware&#xA;&#xA;Calcolo teorico (Entropia di Shannon)&#xA;Un primo strumento per la valutazione di una password è dato dall&#39;entropia di Shannon, che chiunque abbia usato un password manager certamente conoscerà.&#xA;&#xA;Questo calcolo assume che l&#39;attaccante non sappia nulla della nostra password e debba provare ogni possibile combinazione (forza bruta).&#xA;&#xA;Dato un alfabeto di R simboli e una password di lunghezza L, l&#39;entropia E sarà pari a: &#xA;&#xA;E = logsub2/sub ( RsupL/sup ) = L  \ logsub2/sub ( R )&#xA;&#xA;L&#39;entropia è un valore numerico espresso in bit (gli &#34;Shannon&#34;) che rappresenta una misura, non tanto della robustezza, quanto della &#34;densità&#34; della password, ossia di quanto lavoro richieda ad un calcolatore per essere indovinata. Più è alta, meglio è.&#xA;Spiegazione dell&#39;entropia di Shannon&#xA;Innanzitutto notiamo che RsupL/sup è la dimensione dello spazio di possibilità in cui esiste la mia password e, per R e L sufficientemente grandi, è un numero talmente enorme da essere difficilmente comprensibile.&#xA;&#xA;L&#39;equivalente E, che non è altro che l&#39;esponente della potenza di 2 tale per cui 2supE/sup = RsupL/sup, risulta invece molto più gestibile e confrontabile.&#xA;&#xA;Semplificando, se alla mia password lunga L corrisponde quindi un&#39;analoga chiave in bit lunga E, un attaccante che voglia scoprire la mia password, invece che indovinare gli L simboli da un alfabeto R, compirà lo stesso sforzo rispondendo correttamente ad un numero di domande binarie (SI / NO) pari a E, per ricostruire la giusta sequenza binaria.&#xA;&#xA;Quanto costa ricostruire la sequenza?&#xA;O, in altre parole, qual è lo sforzo computazionale richiesto?&#xA;&#xA;Si parla di  caso medio ottimale corrispondente ad una ricerca binaria in cui ogni domanda dimezza lo spazio di possibilità fino ad azzerarlo completamente.&#xA;&#xA;E = L \ logsub2/sub ( R ), è quel numero di bit che mi dice quant&#39;è profondo l&#39;albero delle decisioni che il calcolatore deve percorrere, albero in cui il numero dei possibili cammini radice-foglia (equivalenti a tutte le possibili password) è 2supE/sup = RsupL/sup.&#xA; &#xA;Nel caso migliore, rispondo correttamente a tutte le E domande al primo tentativo (trovo subito il mio cammino sull&#39;albero).&#xA;Nel caso peggiore, mi occorreranno 2supE/sup risposte (percorro tutti i cammini dell&#39;albero) equivalente proprio a RsupL/sup.&#xA;&#xA;Possiamo allora definire formalmente l&#39;entropia come quella quantità minima di informazione necessaria ad azzerare l&#39;incertezza legata all&#39;identificazione della password. Per questo motivo è espressa in bit.&#xA;&#xA;Una misurazione di questo tipo ha senso solo se ipotizziamo che i simboli siano tutti equiprobabili.&#xA;&#xA;La formula di Shannon misura, sì, l&#39;entropia, ma al suo massimo potenziale, quando la distribuzione dei simboli nella sequenza è omogenea e assolutamente casuale.&#xA;Esempi d&#39;uso&#xA;Facciamo l&#39;esempio di una password lunga 20, costruita su un alfabeto di 66 simboli (alfanumerico con maiuscole e minuscole più 4 simboli speciali).&#xA;La dimensione di questo spazio di possibilità è pari a:&#xA;&#xA;Ssubp/sub = RsupL/sup = 66sup20/sup = 2,46 \ 10sup36/sup&#xA;&#xA;Tentare un attacco di forza bruta su un oggetto del genere è semplicemente impensabile.&#xA;Faccio un esempio.&#xA;&#xA;Per forzare la nostra password, supponiamo di avere a disposizione il più potente supercomputer del mondo, El Capitan ad oggi, dotato di una potenza di calcolo spaventosa, in media 2.000 exaFLOPS con picchi di 2.746 exaFLOPS, dove 1 exaFLOPS è un quintilione (10sup18/sup) di operazioni al secondo.&#xA;&#xA;Il calcolo di una password si misura in Hash al secondo, H/s per usare una notazione compatta, che è più dispendiosa della singola operazione.&#xA;&#xA;Approssimando per eccesso con molto ottimismo e nell&#39;ipotesi di usare algoritmi estrememente deboli e poco costosi dal punto di vista computazionale come NTLM o MD5, possiamo pensare che il nostro sistema possa arrivare a calcolare, in queste condizioni, circa 1,5 quintilioni  ( 1,5 \ 10sup18/sup ) H/s.&#xA;Per algoritmi come bcrypt o argon2, progettati per essere molto dispendiosi, tale potenza si riduce drasticamente di molti ordini di grandezza. Da 10sup18/sup a 10sup9/sup - 10sup6/sup. Ma consideriamo il caso più favorevole perché sembra appunto una potenza enorme.&#xA;&#xA;Ma anche questa tremenda esibizione di potenza annichilisce di fronte al numero di calcoli da compiere nel nosro spazio di possibilità.&#xA;Dato Ssubp/sub lo spazio di possibilità (il numero di possibili combinazioni), il tempo T espresso in secondi necessario ad eseguire tutte le operazioni sarà:&#xA;&#xA;Ssubp/sub = 66sup20/sup = 2,46 \ 10sup36/sup&#xA;&#xA;T = 2,46 \ sup36/sup / 1,5 \ 10sup18/sup = 1,64 \ 10sup18/sup&#xA;&#xA;Che equivale a circa 52 miliardi di anni.&#xA;&#xA;Per avere un&#39;idea di questa grandezza cosmica, si pensi che l&#39;età del nostro universo è di circa 13,8 miliardi di anni. Quindi il calcolo della nostra password potrebbe richiedere un tempo che è grossomodo 3,8 volte l&#39;età dell&#39;universo.&#xA;&#xA;I 120 bit di entropia, sono dunque la misura di questo sforzo potenziale, interpretabile equivalentemente in due modi differenti:&#xA;&#xA;la probabilità di riuscire a trovare la password tirando a indovinare, probabilità che è 1 su 2sup120/sup&#xA;&#xA;oppure&#xA;&#xA;la capacità di rispondere correttamente e consecutivamente a 120 domande di tipo (SI / NO) (ricerca del giusto cammino in un albero decisionale binario profondo 120 livelli)&#xA;&#xA;Allungando la nostra password di altri due caratteri, l&#39;entropia arriva a circa 133 e il calcolo delle possibili combinazioni, posto che fosse possibile ignorando le leggi della termodinamica, richiederebbe circa 16.500 di volte l&#39;età dell&#39;universo.&#xA;&#xA;Considerazione a margine: è la lunghezza della password ad incidere più che la complessità dell&#39;alfabeto. E lo vediamo dalla formula dell&#39;entropia, perché, in una funzione di elevamento a potenza RsupL/sup, aumentare l&#39;esponente L fa crescere molto più rapidamente la funzione che non aumentando la base R.&#xA;Calcolo realistico (pattern matching)&#xA;L&#39;entropia di Shannon fornisce un riscontro utilizzabile solo ipotizzando che:&#xA;&#xA;le scelte siano indipendenti &#xA;la distribuzione sia uniforme&#xA;&#xA;e in uno scenario di questo tipo, l&#39;attacco di forza bruta non è una via percorribile.&#xA;&#xA;Allo stesso tempo, se non vengono rispettati questi vincoli, l&#39;entropia dà una falsa sicurezza perché la formula di Shannon &#34;standard&#34; non tiene conto della ridondanza:&#xA;&#xA;Consideriamo questa password: Password12345678&#xA;&#xA;teoria: la formula E = L  log2R direbbe che la sua entropia sia 95, ottima.&#xA;realtà: poiché è una sequenza ovvia, l&#39;attaccante la proverà per prima. La sua entropia reale sarà vicina a 0 bit.&#xA;&#xA;L&#39;entropia quindi misura la &#34;densità&#34; della password, la sua imprevedibilità potenziale ma non dà nessuna informazione sulla presenza di schemi ripetuti e sul pattern matching.&#xA;&#xA;Ent&#xA;L&#39;essere umano come generatore di entropia fa schifo.&#xA;Ecco perché, per un attaccante, prima ancora di provare tutte le possibili combinazioni di caratteri, un attacco a dizionario può far risparmiare un sacco di tempo.&#xA;Infatti sempre Shannon ci dice che nelle parole dei linguaggi naturali alcune lettere ricorrono più di altre, non serve lo stesso numero di domanda ma molto meno e così l&#39;entropia media diminuisce.&#xA;Per prevenire questi effetti collaterali, il nostro metodo di generazione e quindi ciò che viene generato, deve essere testato con qualcos&#39;altro che non sia la semplice entropia.&#xA;&#xA;ent è un tool a linea di comando che fa 4 valutazioni differenti:&#xA;&#xA;entropia&#xA;Chi-quadrato&#xA;Media aritmetica&#xA;Monte Carlo Pi&#xA;&#xA;N.B. ent non è adatto alla valutazione della singola password perché ha bisogno di migliaia di dati (almeno 1K). Una singola password di 24 caratteri per es. (24 byte) non ha materiale casuale sufficiente affinché ent converga verso un giudizio oggettivo.&#xA;&#xA;Entropia&#xA;L&#39;entropia misura la densità di informazione. In ent, viene calcolata in bit per carattere (byte).&#xA;&#xA;Il valore: Si analizza il file byte per byte, il valore massimo è 8.0 (ogni byte è totalmente imprevedibile).&#xA;Interpretazione: Più il valore è vicino a 8, più la casualità è &#34;densa&#34; e difficile da indovinare tramite attacchi basati su dizionario. Se il valore è basso (es. 2.0 o 3.0), significa che ci sono molte ripetizioni o uno schema prevedibile.&#xA;Compressione: ent ti dice anche quanto il file potrebbe essere compresso. Un&#39;entropia di 8.0 significa che il file è già &#34;puro caos&#34; e non può essere compresso ulteriormente.&#xA;&#xA;Chi-quadrato&#xA;Il test del chi-quadrato prova a capire se il disordine presente nel file sia veramente equo o se si preferiscono certi caratteri ad altri. Esamina la distribuzione dei caratteri e la confronta con una distribuzione uniforme teorica. Il risultato viene presentato come percentuale con questi scaglioni:&#xA;&#xA;10% \ chi&lt;sup2/sup \&lt; 90%: La sequenza è considerata casuale. Il 50% è il valore &#34;perfetto&#34;.&#xA;chisup2/sup \ 1% o chi&lt;sup2/sup \  99%: È quasi certamente non casuale.&#xA;&#x9;chisup2/sup = 99.99%: i dati sono sospettosamente regolari;&#xA;&#x9;chisup2/sup = 0.01%: i dati sono &#34;troppo&#34; casuali per essere naturali (sospetta manipolazione)&#xA;&#xA;Media aritmetica&#xA;Per capire se la distribuzione è sufficientemente omogenea, si fa la somma dei valori dei byte del file e si fa una media.&#xA;&#xA;Poiché i byte vanno da 0 a 255, il valore ideale della media sarebbe 127,5.&#xA;Se è troppo lontano dalla media avvcinandosi ad uno dei due estremi (ad es. 50 o 190), vuol dire che si sta usando solo un piccola parte dei caratteri a disposizione e questo, a suo modo di vedere, rende le password più prevedibili.&#xA;&#xA;Monte Carlo Pi&#xA;È il metodo più fantasioso di tutti.&#xA;I dati casuali vengono trasformati in una serie di &#34;dardi&#34; virtuali che vanno a colpire un bersaglio. L&#39;obiettivo non è quello di colpire un ipotico centro ma di verificare che i &#34;dardi&#34; si distribuiscano uniformemente nel bersaglio.&#xA;&#xA;Tutto ciò si realizza immaginando di avere un quadrato 1x1 e 1/4 di cerchio al suo interno di raggio 1 e area π/4&#xA;I dati della sequenza casuale vengono prelevati a gruppi di n byte e supponiamo n = 3 per ora.&#xA;Ogni gruppo di 3 byte sarà un numero compreso tra 0 e 2sup24/sup-1.&#xA;Se normalizziamo questo numero dividendolo per  2sup24/sup, otteniamo un numero compreso fra 0 e 1.&#xA;Calcolando le coordinate in questo modo, col teorema di Pitagora possiamo verificare se la coordinata (X,Y) &#34;cada&#34; nel quarto di cerchio oppure no e ciò succede se:&#xA;&#xA;Xsup2/sup + Ysup2/sup ≤ 1&#xA;&#xA;Lanciando un migliaio di queste &#34;frecce&#34;, accumuliamo dati sufficiente per fare una stima.&#xA;&#xA;Se indichiamo con In il numero di &#34;lanci&#34; con successo e con Total il numero totale di lanci effettuati:&#xA;&#xA;4 \ (ln/Total) si avvicinerà a π solo se la distribuzione dei caratteri sarà uniforme (indice di una casualità omogenea), altrimenti divergerà in maniera significativa (indice della presenza di pattern o di ripetizioni).&#xA;&#xA;zxcvbn&#xA;ent fa un&#39;analisi statistica della distribuzione dei bit in un generatore di casualità.&#xA;&#xA;zxcvbn invece fa un&#39;analisi di tipo euristico, è verticale sulla verifica delle password in particolare nel rilevare se vi sono schemi o ripetizioni di caratteri che renderebbero le password violabili.&#xA;&#xA;Il suo algoritmo scompone le password in pezzi dei quali cerca corrispondenze in dizionari o schemi come:&#xA;&#xA;dizionari: controlla la presenza di parole di uso comune&#xA;sequenze: controlla la presenza di serie di caratteri prevedibili come &#34;123456&#34;, &#34;abcde&#34;&#xA;pattern spaziali: controlla la presenza di percorsi sulla tastiera come &#34;qwerty&#34;, &#34;asdfg&#34;, &#34;zcvbn&#34; o sequenze diagonali&#xA;ripetizioni: ripetizione di caratteri come &#34;kkkkkkkkkk&#34; o &#34;12121212&#34;&#xA;l33t: una parola come &#34;p4$$w0rd&#34; viene subito riconosciuta come &#34;password&#34;&#xA;date: riconosce giorni, mesi, anni, anche composti come &#34;15062026&#34;&#xA;&#xA;Il suo uso è molto semplice.&#xA;Le si dà in pasto la password e zxcvbn restituisce diverse informazioni utili:&#xA;&#xA;uno score da &#34;0&#34; (terribile) a &#34;4 (ottima);&#xA;la stima di quanto tempo impiegherebbe un hacker a violarla in base a vari scenari di attacco;&#xA;suggerimenti su come migliorare eventualmente la password.&#xA;&#xA;zxcvbn era una libreria javascript orginariamente sviluppata da Dropbox e ora disponibile in tante forme: go, python, c++.&#xA;&#xA;L&#39;originale Dropbox in javascript, non più manutenuto, può essere trovata qui: https://github.com/dropbox/zxcvbn.&#xA;&#xA;Benché esistano diversi porting in python, se c&#39;è l&#39;esigenza di usare la versione legacy, gli stessi sviluppatori dell&#39;originale zxcvbn consigliano questa versione: https://github.com/dwolfhub/zxcvbn-python, che può essere installata con pip.&#xA;&#xA;In realtà la versione migliore è un fork in typescript, zxcvbn-ts che offre modularità (a differenza della versione python che è monolitica), maggior sicurezza, risoluzione di bug, aggiornamento continuo dizionari compresi.&#xA;&#xA;Per capirci, mentre ent usa l&#39;entropia di Shannon per valutare la probabilità statistica dei byte, zxcvbn cerca di calcolare una stima dei tempi necessari per indovinare la password.&#xA;&#xA;Una passphrase su ent avrebbe un punteggio risibile perché le entropie di parole comuni sono molto basse. Su zxcvbn invece avrebbe un punteggio molto alto perché l&#39;entropia di una parola viene calcolata sulla posizione del dizionario che la contiene per cui un hacker dovrebbe provare milioni di combinazioni prima di trovarla.&#xA;&#xA;Allo stesso modo, password che per ent sarebbero ottime, per zxcvbn sarebbero da evitare perché legate a pattern o a ripetizioni.&#xA;&#xA;Riassumendo&#xA;Se si deve testare una password / passphrase, sicuramente zxcvbn.&#xA;Se si deve testare un generatore di casualità o un keyfile di almeno 2k, sicuramente ent.&#xA;&#xA;Metodo Diceware&#xA;Visto che nell&#39;ultima parte abbiamo evidenziato l&#39;anomalia che sorge nel momento in cui si valuta un oggetto casuale o dal punto di vista puramente statistico o dal punto di vista euristico, vale la pena di spendere due parole sulla modalità di creazione delle passphrase usando il metodo Diceware.&#xA;&#xA;Usando come password parole estratte dal linguaggio naturale bisogna fare i conti col problema della prevedibilità.&#xA;Shannon ha dimostrato che la lingua italiana (o inglese) ha un&#39;entropia molto bassa (circa 1-1.5 bit per lettera) perché dopo una &#34;q&#34; ci si aspetta quasi sempre una &#34;u&#34;, e dopo un soggetto ci si aspetta un verbo. E così via.&#xA;Ecco perché, piuttosto che valutare l&#39;entropia nel suo complesso e provare ogni possibile combinazione, un moderno calcolatore inzia col far ricorso a &#34;pattern&#34; umani per violare password in pochi minuti invece che millenni.&#xA;&#xA;Per unire la sicurezza del calcolo casuale alla comodità di una password menmonica, si ricorre al metodo Diceware che consiste nel far uso di un dizionario di migliaia di parole.&#xA;&#xA;Quello classico, di 7776 parole inglesi, curato dall EFF si può trovare qui:&#xA;curl -L https://www.eff.org/files/2016/07/18/efflargewordlist.txt   dicdiceware.txt&#xA;Altrimenti Tarin Gamberini espone il suo dizionario diceware , aggiornato al 2019, qui: https://www.taringamberini.com/downloads/dicewareitIT/lista-di-parole-diceware-in-italiano/4/wordlistdicewareit-IT-4.txt.&#xA;&#xA;Questo dizionario contiene 6sup5/sup parole numerate da 11111 a 66666.&#xA;La passphrase è composta da n di queste parole il cui indice è ricavato lanciando un dado (o un analogo virtuale) per 5 volte.&#xA;In questo modo le parole non sono correlate fra di loro come si potrebbero trovare in una frase, vanificando ogni possibile speculazione sulla sua composizione.&#xA;&#xA;Volendo fare un calcolo dell&#39;entropia, supponendo di costruire una passphrase di 6 parole:&#xA;&#xA;E = L \ logsub2/sub R = 6 \ logsub2/sub 7776 ~ 77,6 &#xA;&#xA;Nella password classiche basate su un alfabeto di R simboli, il mattoncino è rappresentato dal singolo carattere che ha una probabilità 1/R di essere estratto.&#xA;&#xA;Con Diceware, il mattoncino è la parola che ha una probabilità su 7776 di essere estratta. Ogni parola in più, aggiunge una quantità enorme di incertezza.&#xA;&#xA;Ecco perché con sole 6 parole abbiamo già una passphrase molto robusta e con 10 parole siamo di fronte ad una passphrase inattacabile, almeno dal punto di vista dell&#39;analisi statistica (E   129_) e imperforabile anche ricorrendo ad analisi euristiche.&#xA;&#xA;Regola aurea: la scelta delle parole deve essere realmente casuale e non seguire regole grammaticali o preferenze personali. Altrimenti sarà un gioco da ragazzi violarla con un approccio a-là zxcvbn.&#xA;&#xA;#entropy #shannon #bruteforce #ent #zxcvbn #diceware #passphrase #PatternMatching]]&gt;</description>
      <content:encoded><![CDATA[<p><img src="https://pixelfed.uno/storage/m/_v2/489827599091373610/ffe7c43a6-a8b5f2/dgaPhFXQtnxH/E2m9YHqhOVs4GDAjNBVqJmqOE2yoFdq8S1IjuD96.jpg" alt="ent,zxcvb,diceware"></p>

<p>In <a href="https://noblogo.org/aytin/come-generare-una-password-o-un-keyfile-sicuri-trilogia-della-password-1-di" rel="nofollow">“Come generare una password o un keyfile sicuri”</a> abbiamo visto come generare password e keyfile che si basassero su dati il più possibile casuali.
La verifica matematica di una password si basa sulla determinazione del numero di tentativi necessari a un attaccante per indovinarla.

Esistono due approcci: quello teorico (<strong>brute force</strong>) e quello realistico (<strong>pattern matching</strong>).</p>
<ul><li><a href="#calcolo-teorico-entropia-di-shannon" rel="nofollow">Calcolo teorico (Entropia di Shannon)</a>
<ul><li><a href="#spiegazione-dell-entropia-di-shannon" rel="nofollow">Spiegazione dell’entropia di Shannon</a></li>
<li><a href="#esempi-d-uso" rel="nofollow">Esempi d’uso</a></li></ul></li>
<li><a href="#calcolo-realistico-pattern-matching" rel="nofollow">Calcolo realistico (pattern matching)</a>
<ul><li><a href="#ent" rel="nofollow">Ent</a></li>
<li><a href="#zxcvbn" rel="nofollow">zxcvbn</a></li>
<li><a href="#riassumendo" rel="nofollow">Riassumendo</a></li></ul></li>
<li><a href="#metodo-diceware" rel="nofollow">Metodo Diceware</a></li></ul>

<h2 id="calcolo-teorico-entropia-di-shannon">Calcolo teorico (Entropia di Shannon)</h2>

<p>Un primo strumento per la valutazione di una password è dato dall&#39;<strong>entropia di Shannon</strong>, che chiunque abbia usato un password manager certamente conoscerà.</p>

<p>Questo calcolo assume che l&#39;attaccante non sappia nulla della nostra password e debba provare ogni possibile combinazione (forza bruta).</p>

<p>Dato un alfabeto di <em>R</em> simboli e una password di lunghezza <em>L</em>, l&#39;entropia <em>E</em> sarà pari a:</p>

<p><em>E = log<sub>2</sub></em> ( <em>R<sup>L</sup></em> ) <em>= L  * log<sub>2</sub></em> ( <em>R</em> )</p>

<p>L&#39;entropia è un valore numerico espresso in bit (gli “Shannon”) che <strong>rappresenta una misura, non tanto della robustezza, quanto della “densità” della password</strong>, ossia di quanto lavoro richieda ad un calcolatore per essere indovinata. Più è alta, meglio è.</p>

<h3 id="spiegazione-dell-entropia-di-shannon">Spiegazione dell&#39;entropia di Shannon</h3>

<p>Innanzitutto notiamo che <em>R</em><sup>L</sup> è la <strong>dimensione dello spazio di possibilità in cui esiste la mia password</strong> e, per <em>R</em> e <em>L</em> sufficientemente grandi, è un numero talmente enorme da essere difficilmente comprensibile.</p>

<p>L&#39;equivalente <em>E</em>, che non è altro che l&#39;esponente della potenza di 2 tale per cui <em>2<sup>E</sup> = R<sup>L</sup></em>, risulta invece molto più gestibile e confrontabile.</p>

<p>Semplificando, se alla mia password lunga <em>L</em> corrisponde quindi un&#39;analoga chiave in bit lunga <em>E</em>, un attaccante che voglia scoprire la mia password, invece che indovinare gli <em>L</em> simboli da un alfabeto <em>R</em>, compirà lo stesso sforzo rispondendo correttamente ad un numero di <strong>domande binarie (SI / NO)</strong> pari a <em>E</em>, per ricostruire la giusta sequenza binaria.</p>

<p>Quanto costa ricostruire la sequenza?
O, in altre parole, qual è lo sforzo computazionale richiesto?</p>

<p>Si parla di  <strong>caso medio ottimale</strong> corrispondente ad una ricerca binaria in cui <strong>ogni domanda dimezza</strong> lo spazio di possibilità fino ad azzerarlo completamente.</p>

<p><em>E = L * log<sub>2</sub></em> ( <em>R</em> ), è quel numero di bit che mi dice <strong>quant&#39;è profondo</strong> l&#39;albero delle decisioni che il calcolatore deve percorrere, albero in cui il numero dei possibili cammini radice-foglia (equivalenti a tutte le possibili password) è <em>2<sup>E</sup> = R<sup>L</sup></em>.</p>
<ul><li>Nel <strong>caso migliore</strong>, rispondo correttamente a <strong>tutte le <em>E</em> domande</strong> al primo tentativo (trovo subito il mio cammino sull&#39;albero).</li>
<li>Nel <strong>caso peggiore</strong>, mi occorreranno <em>2<sup>E</sup></em> risposte (percorro tutti i cammini dell&#39;albero) equivalente proprio a <em>R<sup>L</sup></em>.</li></ul>

<p>Possiamo allora definire formalmente l&#39;entropia come <strong>quella quantità minima di informazione necessaria ad azzerare l&#39;incertezza legata all&#39;identificazione della password</strong>. Per questo motivo è espressa in bit.</p>

<p>Una misurazione di questo tipo <strong>ha senso solo se ipotizziamo che i simboli siano tutti equiprobabili</strong>.</p>

<p>La formula di Shannon misura, sì, l&#39;entropia, ma <strong>al suo massimo potenziale</strong>, quando la distribuzione dei simboli nella sequenza è omogenea e assolutamente casuale.</p>

<h3 id="esempi-d-uso">Esempi d&#39;uso</h3>

<p>Facciamo l&#39;esempio di una password lunga 20, costruita su un alfabeto di 66 simboli (alfanumerico con maiuscole e minuscole più 4 simboli speciali).
La dimensione di questo spazio di possibilità è pari a:</p>

<p><em>S<sub>p</sub> = R<sup>L</sup> = 66<sup>20</sup> = 2,46 * 10<sup>36</sup></em></p>

<p>Tentare un attacco di forza bruta su un oggetto del genere è semplicemente impensabile.
Faccio un esempio.</p>

<p>Per forzare la nostra password, supponiamo di avere a disposizione il più potente supercomputer del mondo, <strong>El Capitan</strong> ad oggi, dotato di una potenza di calcolo spaventosa, in media 2.000 exaFLOPS con picchi di 2.746 exaFLOPS, dove 1 exaFLOPS è <strong>un quintilione (10<sup>18</sup>) di operazioni al secondo</strong>.</p>

<p>Il calcolo di una password si misura in <strong>Hash al secondo</strong>, H/s per usare una notazione compatta, che è più dispendiosa della singola operazione.</p>

<p>Approssimando per eccesso con molto ottimismo e nell&#39;ipotesi di usare algoritmi estrememente deboli e poco costosi dal punto di vista computazionale come <strong>NTLM</strong> o <strong>MD5</strong>, possiamo pensare che il nostro sistema possa arrivare a calcolare, in queste condizioni, circa <strong>1,5 quintilioni</strong>  ( 1,5 * 10<sup>18</sup> ) <strong>H/s</strong>.
Per algoritmi come <strong>bcrypt</strong> o <strong>argon2</strong>, progettati per essere molto dispendiosi, tale potenza si riduce drasticamente di molti ordini di grandezza. Da 10<sup>18</sup> a 10<sup>9</sup> – 10<sup>6</sup>. Ma consideriamo il caso più favorevole perché sembra appunto una potenza enorme.</p>

<p>Ma anche questa tremenda esibizione di potenza annichilisce di fronte al numero di calcoli da compiere nel nosro spazio di possibilità.
Dato <em>S<sub>p</sub></em> lo spazio di possibilità (il numero di possibili combinazioni), il tempo <em>T</em> espresso in secondi necessario ad eseguire tutte le operazioni sarà:</p>

<p><em>S<sub>p</sub> = 66<sup>20</sup> = 2,46 * 10<sup>36</sup></em></p>

<p><em>T = 2,46 * <sup>36</sup> / 1,5 * 10<sup>18</sup> = 1,64 * 10<sup>18</sup></em></p>

<p>Che equivale a circa <strong>52 miliardi di anni</strong>.</p>

<p>Per avere un&#39;idea di questa grandezza cosmica, si pensi che l&#39;età del nostro universo è di circa <strong>13,8 miliardi di anni.</strong> Quindi il calcolo della nostra password potrebbe richiedere un tempo che è grossomodo <strong>3,8 volte l&#39;età dell&#39;universo</strong>.</p>

<p>I 120 bit di entropia, sono dunque <strong>la misura di questo sforzo potenziale</strong>, interpretabile equivalentemente in due modi differenti:</p>
<ul><li>la <strong>probabilità</strong> di riuscire a trovare la password tirando a indovinare, probabilità che è 1 su 2<sup>120</sup></li></ul>

<p>oppure</p>
<ul><li>la <strong>capacità</strong> di rispondere <strong>correttamente e consecutivamente</strong> a 120 domande di tipo (SI / NO) (ricerca del giusto cammino in un albero decisionale binario profondo <strong>120 livelli</strong>)</li></ul>

<p>Allungando la nostra password di altri due caratteri, l&#39;entropia arriva a circa 133 e il calcolo delle possibili combinazioni, posto che fosse possibile ignorando le leggi della termodinamica, richiederebbe circa <strong>16.500 di volte l&#39;età dell&#39;universo</strong>.</p>

<p><strong>Considerazione a margine:</strong> è la lunghezza della password ad incidere più che la complessità dell&#39;alfabeto. E lo vediamo dalla formula dell&#39;entropia, perché, in una funzione di elevamento a potenza <em>R<sup>L</sup></em>, aumentare l&#39;esponente <em>L</em> fa crescere molto più rapidamente la funzione che non aumentando la base <em>R</em>.</p>

<h2 id="calcolo-realistico-pattern-matching">Calcolo realistico (pattern matching)</h2>

<p>L&#39;entropia di Shannon fornisce un riscontro utilizzabile solo ipotizzando che:</p>
<ul><li>le scelte siano indipendenti</li>
<li>la distribuzione sia uniforme</li></ul>

<p>e in uno scenario di questo tipo, l&#39;attacco di forza bruta non è una via percorribile.</p>

<p>Allo stesso tempo, se non vengono rispettati questi vincoli, l&#39;entropia dà una falsa sicurezza perché la formula di Shannon “standard” non tiene conto della ridondanza:</p>

<p>Consideriamo questa password: <code>Password12345678</code></p>
<ul><li><strong>teoria</strong>: la formula <em>E = L * log2R</em> direbbe che la sua entropia sia 95, ottima.</li>
<li><strong>realtà</strong>: poiché è una sequenza ovvia, l&#39;attaccante la proverà per prima. La sua entropia reale sarà vicina a <strong>0 bit</strong>.</li></ul>

<p>L&#39;entropia quindi misura la “densità” della password, la sua imprevedibilità potenziale ma non dà nessuna informazione sulla presenza di schemi ripetuti e sul <strong>pattern matching</strong>.</p>

<h3 id="ent">Ent</h3>

<p>L&#39;essere umano come generatore di entropia fa schifo.
Ecco perché, per un attaccante, prima ancora di provare tutte le possibili combinazioni di caratteri, un attacco a dizionario può far risparmiare un sacco di tempo.
Infatti sempre Shannon ci dice che nelle parole dei linguaggi naturali alcune lettere ricorrono più di altre, non serve lo stesso numero di domanda ma molto meno e così l&#39;entropia media diminuisce.
Per prevenire questi effetti collaterali, il nostro metodo di generazione e quindi ciò che viene generato, deve essere testato con qualcos&#39;altro che non sia la semplice entropia.</p>

<p><code>ent</code> è un tool a linea di comando che fa 4 valutazioni differenti:</p>
<ul><li>entropia</li>
<li>Chi-quadrato</li>
<li>Media aritmetica</li>
<li>Monte Carlo Pi</li></ul>

<p><strong>N.B.</strong> <code>ent</code> non è adatto alla valutazione della singola password perché ha bisogno di migliaia di dati (almeno 1K). Una singola password di 24 caratteri per es. (24 byte) non ha materiale casuale sufficiente affinché <code>ent</code> converga verso un giudizio oggettivo.</p>

<p><strong>Entropia</strong>
L&#39;entropia misura la densità di informazione. In ent, viene calcolata in bit per carattere (byte).</p>
<ul><li><strong>Il valore</strong>: Si analizza il file byte per byte, il valore massimo è 8.0 (ogni byte è totalmente imprevedibile).</li>
<li><strong>Interpretazione</strong>: Più il valore è vicino a 8, più la casualità è “densa” e difficile da indovinare tramite attacchi basati su dizionario. Se il valore è basso (es. 2.0 o 3.0), significa che ci sono molte ripetizioni o uno schema prevedibile.</li>
<li><strong>Compressione</strong>: ent ti dice anche quanto il file potrebbe essere compresso. Un&#39;entropia di 8.0 significa che il file è già “puro caos” e non può essere compresso ulteriormente.</li></ul>

<p><strong>Chi-quadrato</strong>
Il test del chi-quadrato prova a capire se il disordine presente nel file sia veramente equo o se si preferiscono certi caratteri ad altri. Esamina la distribuzione dei caratteri e la confronta con una distribuzione uniforme teorica. Il risultato viene presentato come percentuale con questi scaglioni:</p>
<ul><li><strong>10% &lt; chi<sup>2</sup> &lt; 90%</strong>: La sequenza è considerata casuale. Il 50% è il valore “perfetto”.</li>
<li><strong>chi<sup>2</sup> &lt; 1% o chi<sup>2</sup> &gt; 99%</strong>: È quasi certamente non casuale.
<ul><li><strong>chi<sup>2</sup> = 99.99%</strong>: i dati sono sospettosamente regolari;</li>
<li><strong>chi<sup>2</sup> = 0.01%</strong>: i dati sono “troppo” casuali per essere naturali (sospetta manipolazione)</li></ul></li></ul>

<p><strong>Media aritmetica</strong>
Per capire se la distribuzione è sufficientemente omogenea, si fa la somma dei valori dei byte del file e si fa una media.</p>

<p>Poiché i byte vanno da 0 a 255, il valore ideale della media sarebbe 127,5.
Se è troppo lontano dalla media avvcinandosi ad uno dei due estremi (ad es. 50 o 190), vuol dire che si sta usando solo un piccola parte dei caratteri a disposizione e questo, a suo modo di vedere, rende le password più prevedibili.</p>

<p><strong>Monte Carlo Pi</strong>
È il metodo più fantasioso di tutti.
I dati casuali vengono trasformati in una serie di “dardi” virtuali che vanno a colpire un bersaglio. L&#39;obiettivo non è quello di colpire un ipotico centro ma di verificare che i “dardi” si distribuiscano uniformemente nel bersaglio.</p>

<p>Tutto ciò si realizza immaginando di avere un quadrato <em>1x1</em> e ¼ di cerchio al suo interno di raggio 1 e area π/4
I dati della sequenza casuale vengono prelevati a gruppi di <em>n</em> byte e supponiamo <em>n = 3</em> per ora.
Ogni gruppo di 3 byte sarà un numero compreso tra <em>0 e 2<sup>24</sup>-1</em>.
Se normalizziamo questo numero dividendolo per  <em>2<sup>24</sup></em>, otteniamo un numero compreso fra 0 e 1.
Calcolando le coordinate in questo modo, col teorema di Pitagora possiamo verificare se la coordinata (X,Y) “cada” nel quarto di cerchio oppure no e ciò succede se:</p>

<p><em>X<sup>2</sup> + Y<sup>2</sup> ≤ 1</em></p>

<p>Lanciando un migliaio di queste “frecce”, accumuliamo dati sufficiente per fare una stima.</p>

<p>Se indichiamo con <em>In</em> il numero di “lanci” con successo e con <em>Total</em> il numero totale di lanci effettuati:</p>

<p><em>4 * (ln/Total)</em> si avvicinerà a π solo se la distribuzione dei caratteri sarà uniforme (indice di una casualità omogenea), altrimenti divergerà in maniera significativa (indice della presenza di pattern o di ripetizioni).</p>

<h3 id="zxcvbn">zxcvbn</h3>

<p><code>ent</code> fa un&#39;analisi statistica della distribuzione dei bit in un generatore di casualità.</p>

<p><code>zxcvbn</code> invece fa un&#39;analisi di tipo euristico, è verticale sulla verifica delle password in particolare nel rilevare se vi sono schemi o ripetizioni di caratteri che renderebbero le password violabili.</p>

<p>Il suo algoritmo scompone le password in pezzi dei quali cerca corrispondenze in dizionari o schemi come:</p>
<ul><li><strong>dizionari</strong>: controlla la presenza di parole di uso comune</li>
<li><strong>sequenze</strong>: controlla la presenza di serie di caratteri prevedibili come “123456”, “abcde”</li>
<li><strong>pattern spaziali</strong>: controlla la presenza di percorsi sulla tastiera come “qwerty”, “asdfg”, “zcvbn” o sequenze diagonali</li>
<li><strong>ripetizioni</strong>: ripetizione di caratteri come “kkkkkkkkkk” o “12121212”</li>
<li><strong>l33t</strong>: una parola come “p4$$w0rd” viene subito riconosciuta come “password”</li>
<li><strong>date</strong>: riconosce giorni, mesi, anni, anche composti come “15062026”</li></ul>

<p>Il suo uso è molto semplice.
Le si dà in pasto la password e <code>zxcvbn</code> restituisce diverse informazioni utili:</p>
<ul><li>uno score da “0” (terribile) a “4 (ottima);</li>
<li>la stima di quanto tempo impiegherebbe un hacker a violarla in base a vari scenari di attacco;</li>
<li>suggerimenti su come migliorare eventualmente la password.</li></ul>

<p><code>zxcvbn</code> era una libreria javascript orginariamente sviluppata da Dropbox e ora disponibile in tante forme: go, python, c++.</p>

<p>L&#39;originale Dropbox in javascript, non più manutenuto, può essere trovata qui: <a href="https://github.com/dropbox/zxcvbn" rel="nofollow">https://github.com/dropbox/zxcvbn</a>.</p>

<p>Benché esistano diversi porting in python, se c&#39;è l&#39;esigenza di usare la versione legacy, gli stessi sviluppatori dell&#39;originale <code>zxcvbn</code> consigliano questa versione: <a href="https://github.com/dwolfhub/zxcvbn-python" rel="nofollow">https://github.com/dwolfhub/zxcvbn-python</a>, che può essere installata con <code>pip</code>.</p>

<p>In realtà la versione migliore è un fork in typescript, <strong>zxcvbn-ts</strong> che offre modularità (a differenza della versione python che è monolitica), maggior sicurezza, risoluzione di bug, aggiornamento continuo dizionari compresi.</p>

<p>Per capirci, mentre <code>ent</code> usa l&#39;entropia di Shannon per valutare la probabilità statistica dei byte, <code>zxcvbn</code> cerca di calcolare una stima dei tempi necessari per indovinare la password.</p>

<p>Una passphrase su ent avrebbe un punteggio risibile perché le entropie di parole comuni sono molto basse. Su <code>zxcvbn</code> invece avrebbe un punteggio molto alto perché l&#39;entropia di una parola viene calcolata sulla posizione del dizionario che la contiene per cui un hacker dovrebbe provare milioni di combinazioni prima di trovarla.</p>

<p>Allo stesso modo, password che per <code>ent</code> sarebbero ottime, per <code>zxcvbn</code> sarebbero da evitare perché legate a pattern o a ripetizioni.</p>

<h3 id="riassumendo">Riassumendo</h3>

<p>Se si deve testare una password / passphrase, sicuramente <code>zxcvbn</code>.
Se si deve testare un generatore di casualità o un keyfile di almeno 2k, sicuramente <code>ent</code>.</p>

<h2 id="metodo-diceware">Metodo Diceware</h2>

<p>Visto che nell&#39;ultima parte abbiamo evidenziato l&#39;anomalia che sorge nel momento in cui si valuta un oggetto casuale o dal punto di vista puramente statistico o dal punto di vista euristico, vale la pena di spendere due parole sulla modalità di creazione delle passphrase usando il <strong>metodo Diceware</strong>.</p>

<p>Usando come password parole estratte dal linguaggio naturale bisogna fare i conti col problema della <strong>prevedibilità</strong>.
Shannon ha dimostrato che la lingua italiana (o inglese) ha un&#39;entropia molto bassa (circa 1-1.5 bit per lettera) perché dopo una “q” ci si aspetta quasi sempre una “u”, e dopo un soggetto ci si aspetta un verbo. E così via.
Ecco perché, piuttosto che valutare l&#39;entropia nel suo complesso e provare ogni possibile combinazione, un moderno calcolatore inzia col far ricorso a “pattern” umani per violare password in pochi minuti invece che millenni.</p>

<p>Per unire la sicurezza del calcolo casuale alla comodità di una password menmonica, si ricorre al <strong>metodo Diceware</strong> che consiste nel far uso di un dizionario di migliaia di parole.</p>

<p>Quello classico, di 7776 parole inglesi, curato dall EFF si può trovare qui:</p>

<pre><code class="language-bash">curl -L https://www.eff.org/files/2016/07/18/eff_large_wordlist.txt &gt; dic_diceware.txt
</code></pre>

<p>Altrimenti Tarin Gamberini espone il suo dizionario diceware , aggiornato al 2019, qui: <a href="https://www.taringamberini.com/downloads/diceware_it_IT/lista-di-parole-diceware-in-italiano/4/word_list_diceware_it-IT-4.txt" rel="nofollow">https://www.taringamberini.com/downloads/diceware_it_IT/lista-di-parole-diceware-in-italiano/4/word_list_diceware_it-IT-4.txt</a>.</p>

<p>Questo dizionario contiene 6<sup>5</sup> parole numerate da 11111 a 66666.
La passphrase è composta da <em>n</em> di queste parole il cui indice è ricavato lanciando un dado (o un analogo virtuale) per 5 volte.
In questo modo le parole non sono correlate fra di loro come si potrebbero trovare in una frase, vanificando ogni possibile speculazione sulla sua composizione.</p>

<p>Volendo fare un calcolo dell&#39;entropia, supponendo di costruire una passphrase di 6 parole:</p>

<p><em>E = L * log<sub>2</sub> R = 6 * log<sub>2</sub> 7776 ~ 77,6</em></p>

<p>Nella password classiche basate su un alfabeto di <em>R</em> simboli, il mattoncino è rappresentato dal <strong>singolo carattere</strong> che ha una probabilità <em>1/R</em> di essere estratto.</p>

<p>Con Diceware, il mattoncino è <strong>la parola</strong> che ha <strong>una probabilità su 7776</strong> di essere estratta. Ogni parola in più, aggiunge una quantità enorme di incertezza.</p>

<p>Ecco perché con sole 6 parole abbiamo già una passphrase molto robusta e con 10 parole siamo di fronte ad una passphrase inattacabile, almeno dal punto di vista dell&#39;analisi statistica (<em>E &gt; 129</em>) e imperforabile anche ricorrendo ad analisi euristiche.</p>

<p><strong>Regola aurea</strong>: la scelta delle parole deve essere <strong>realmente</strong> casuale e non seguire regole grammaticali o preferenze personali. Altrimenti sarà un gioco da ragazzi violarla con un approccio a-là <code>zxcvbn</code>.</p>

<p><a href="/aytin/tag:entropy" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">entropy</span></a> <a href="/aytin/tag:shannon" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">shannon</span></a> <a href="/aytin/tag:bruteforce" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">bruteforce</span></a> <a href="/aytin/tag:ent" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">ent</span></a> <a href="/aytin/tag:zxcvbn" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">zxcvbn</span></a> <a href="/aytin/tag:diceware" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">diceware</span></a> <a href="/aytin/tag:passphrase" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">passphrase</span></a> <a href="/aytin/tag:PatternMatching" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">PatternMatching</span></a></p>
]]></content:encoded>
      <guid>https://noblogo.org/aytin/come-valutare-la-resistenza-di-una-password-trilogia-della-password-2-di-3</guid>
      <pubDate>Thu, 22 Jan 2026 19:04:39 +0000</pubDate>
    </item>
  </channel>
</rss>