<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>certificati &amp;mdash; Cyberdyne Systems</title>
    <link>https://noblogo.org/aytin/tag:certificati</link>
    <description>&#34;Fare o non fare. Non c&#39;è provare!&#34;</description>
    <pubDate>Thu, 30 Apr 2026 11:33:22 +0000</pubDate>
    <item>
      <title>Script per la gestione della configurazione di una vpn wireguard</title>
      <link>https://noblogo.org/aytin/script-per-la-gestione-della-configurazione-di-una-vpn-wireguard</link>
      <description>&lt;![CDATA[vpn&#xA;&#xA;Cos&#39;è wireguard e come si configura, lo sappiamo ma mi serviva qualcosa che mi permettesse di fare provisioning e deprovisioning dei certificati in maniera più semplice di quanto già si faccia con i tool disponibili nella userland, wg e wg-quick.&#xA;&#xA;E questo è il motivo principale per cui è nato questo script.&#xA;!--more--&#xA;Prende come riferimento una configurazione road warrior, il primo scenario di una topologia point-to-site, quella più comune.&#xA;&#xA;Alcune considerazioni&#xA;Lo script definisce una workdir dove deposita tutte le configurazioni e i certificati.&#xA;Le precondizioni sono legate alla presenza dei tool userland wg-tools (ovviamente) e di ufw. Vengono comunque verificate nello script.&#xA;&#xA;Altra semplificazione è data dal fatto di allocare una /24 come rete wireguard. 254 host per una rete domestica sono più che sufficienti.&#xA;&#xA;L&#39;allocazione degli ip viene fatta con un progressivo memorizzato nel file &#39;ip\renew&#39;. Gli ip dei certificati revocati vengono mantenuti in un file, &#39;ip\release&#39;.&#xA;Quando si crea un nuovo certificato, si controlla prima che ci sia un ip da recuperare in ip\release. Se la lista è vuota si ricorre al progressivo.&#xA;&#xA;La creazione della configurazione lato server passa da due file di configurazione: una configurazione globale ottenuta tracciando l&#39;evoluzione iniziale in termini di aggiunta o rimozione dei client peer e destinata al rilascio in esecuzione. L&#39;altra contenente la sola configurazione del server e usata unicamente per la rigenerazione della configurazione globale a partire dai peer esistenti.&#xA;&#xA;L&#39;operazione di init è propedeutica per addclient, removeclient, rebuild, deploy, share.&#xA;&#xA;Le operazioni a disposizione sono:&#xA;&#xA;init: inizializza la configurazione di un server wireguard&#xA;addclient: crea il certificato lato client e aggiunge il relativo peer sulla configurazione del server&#xA;removeclient: cancella il certificato lato client e rimuove il relativo peer sulla configurazione del server&#xA;rebuild: rigenera la configurazione del server usando i certificati client esistenti&#xA;deploy: finalizza la configurazione riavviando il servizio con le nuove impostazioni&#xA;share: crea i qr-code per i certificati client da utilizzare nelle configurazioni&#xA;&#xA;Per tutto il resto, i commenti nel codice sono abbastanza esplicativi.&#xA;Lo script&#xA;!/bin/bash&#xA;&#xA;Questo è il file di configurazione globale, i dati sono fittizi.&#xA;Può essere mantenuto nello script o nella home dell&#39;utente &#xA;(es. $HOME/.config/wgman.conf) e importato &#xA;con &#39;source&#39; all&#39;inizio.&#xA;WGINTERFACE=wg0&#xA;PHYSICALINTERFACE=eth0&#xA;NETWORK=&#34;192.168.15.0&#34;&#xA;SUBNETMASK=&#34;24&#34;&#xA;SERVERIPADDRESS=&#34;192.168.15.1&#34;&#xA;DNS=&#34;1.1.1.1&#34;&#xA;LISTENPORT=&#34;51820&#34;&#xA;ENDPOINT=wireguard.nodns.net:51820&#34;&#xA;WORKDIR=&#34;$HOME/wireguard&#34;&#xA;&#xA;checkdependency() {&#xA;    if test -e /usr/sbin/ufw; then&#xA;        if test -e /usr/bin/wg; then&#xA;            return 0&#xA;        else&#xA;            return 2&#xA;        fi&#xA;    else&#xA;        return 1&#xA;    fi&#xA;}&#xA;&#xA;isinit() {&#xA;    test -e ${WORKDIR}/conf.d/serverwg.conf &amp;&amp; return 0 || return 1&#xA;}&#xA;&#xA;Genera la chiave privata&#xA;genprivkey() {&#xA;    wg genkey | tee ${WORKDIR}/keys/$1privkey&#xA;}&#xA;&#xA;Genera la pre-shared key&#xA;genclientpsk() {&#xA;    # Evita il warning sui permessi del file che devono essere 600&#xA;    umask 077&#xA;    wg genpsk | tee ${WORKDIR}/psk/$1psk&#xA;}&#xA;&#xA;Rilascio di un nuovo indirizzo ip. Questa funziona viene invocata da&#xA;addclient().&#xA;&#xA;I primi 3 ottetti li ottengo dalla variabile globale NETWORK.&#xA;L&#39;ultimo ottetto, relativo all&#39;host, lo ricavo dalla lista degli ip&#xA;riutilizzabili (&#34;iprelease&#34;).&#xA;&#xA;Se non è vuota, prelevo il primo e lo rimuovo dalla lista. Se è vuota,&#xA;prelevo l&#39;ultimo ottetto da &#34;iprenew&#34; e lo incremento per il successivo&#xA;assegnamento.&#xA;iprenew() {&#xA;    # Selezioni i primi 3 ottetti del network&#xA;    SUBIP=$(echo ${NETWORK}|awk -F &#34;.&#34; &#39;{print $1&#34;.&#34;$2&#34;.&#34;$3}&#39;)&#xA;&#xA;    if [[ ! -e ${WORKDIR}/conf.d/iprelease || ! -s ${WORKDIR}/conf.d/iprelease ]]; then&#xA;        # Genero il nuovo ip (Incremento di 1 l&#39;ultimo ottetto)&#xA;        IP=$(cat ${WORKDIR}/conf.d/iprenew)&#xA;        echo $((++IP))   ${WORKDIR}/conf.d/iprenew&#xA;&#xA;        # Restituisco i 3 ottetti + il quarto&#xA;        #echo -n ${SUBIP};cat ${WORKDIR}/conf.d/iprenew&#xA;    else&#xA;        IP=$(head -n 1 ${WORKDIR}/conf.d/iprelease)&#xA;        sed -i &#34;1d&#34; ${WORKDIR}/conf.d/iprelease&#xA;    fi&#xA;    echo -n ${SUBIP}&#34;.&#34;${IP}&#xA;}&#xA;&#xA;Riallocazione di un indirizzo ip. Questa funzione viene invocata da&#xA;removeclient().&#xA;Aggiungo l&#39;ultimo ottetto alla lista degli ip riallocabili.&#xA;@par 1: ultimo ottetto.&#xA;iprelease() {&#xA;    echo $1|cut -d&#34;.&#34; -f 4     ${WORKDIR}/conf.d/iprelease&#xA;}&#xA;&#xA;Aggiunge il nuovo peer al file di configurazione del server&#xA;@par 1: CLIENTPUBLICKEY&#xA;@par 2: CLIENTPSK&#xA;@par 3: CLIENTIPADDRESS&#xA;@par 4: CLIENTNAME&#xA;addpeertoserver() {&#xA;    cat     ${WORKDIR}/conf.d/serverwg.conf &lt;&lt; EOF&#xA;$4&#xA;[Peer]&#xA;PublicKey = $1&#xA;PresharedKey = $2&#xA;AllowedIPs = $3/32&#xA;PersistentKeepalive = 25&#xA;&#xA;EOF&#xA;}&#xA;&#xA;Inizializza la configurazione del server wireguard.&#xA;&#xA;Questa operazione può essere fatta una sola volta a meno che non si&#xA;cancelli tutta la workdir.&#xA;&#xA;Verranno creati due file  di configurazione: serverwg.conf e &#xA;serverwgraw.conf&#xA;&#xA;Il primo conterrà la configurazione completa del server e dei peer,&#xA;verrà aggiornato ad ogni modifica dei client (aggiunta o rimozione) e&#xA;verrà usato per il deploy della configurazione.&#xA;&#xA;Il secondo conterrà la configurazione del solo server e verrà usato&#xA;solo per rigenerare il primo file di configurazione.&#xA;init() {&#xA;    # Controllo che wireguard sia almeno abilitato&#xA;    echo -n &#34;Inserire la password di Amministratore: &#34;; read -s PASSWORD&#xA;    sudo -k&#xA;    if echo $PASSWORD|sudo -S echo &#34;got a root&#34;   /dev/null; then&#xA;        if ! sudo systemctl is-enabled --quiet wg-quick@${WGINTERFACE}; then&#xA;            echo -en &#34;\nAttivazione servizio wireguard... &#34;&#xA;            #sudo systemctl enable --quiet wg-quick@${WGINTERFACE}&#xA;            echo &#34;fatto.&#34;&#xA;        fi&#xA;        sudo -k &#xA;        &#xA;        #Verifico che queste cartelle esistano. Se lo sono, non faccio nulla, se no le creo.&#xA;        echo -n &#34;Creazione workdir... &#34;&#xA;        [[ ! -e ${WORKDIR}/conf.d || ! -e ${WORKDIR}/psk  || ! -e ${WORKDIR}/keys ]] \&#xA;            &amp;&amp; { mkdir -p ${WORKDIR}/{conf.d,keys,psk}; } \&#xA;            || { echo &#34;inizializzazione già effettuata.&#34;; exit; }&#xA;        echo &#34;fatto.&#34;&#xA;        &#xA;        # Genero la chiave privata per il server&#xA;        echo -n &#34;Creazione chiave private del server...&#34;&#xA;        SERVERPRIVKEY=$(genprivkey &#34;serverwg&#34;)&#xA;        echo &#34;fatto.&#34;&#xA;&#xA;        # Genero il file di configurazione&#xA;        echo -n &#34;Inizializzazione del server... &#34;&#xA;        cat   ${WORKDIR}/conf.d/serverwg.conf &lt;&lt; EOF&#xA;[Interface]&#xA;Address = ${SERVERIPADDRESS}/${SUBNETMASK}&#xA;SaveConfig = true&#xA;&#xA;PreUp = ufw route allow in on ${WGINTERFACE} out on ${PHYSICALINTERFACE} log from ${NETWORK}/${SUBNETMASK} to 0.0.0.0/0&#xA;PostDown = ufw route delete allow in on ${WGINTERFACE} out on ${PHYSICALINTERFACE} log from ${NETWORK}/${SUBNETMASK} to 0.0.0.0/0&#xA;&#xA;IP masquerading&#xA;PreUp = iptables -t nat -A POSTROUTING -o ${PHYSICALINTERFACE} -s ${NETWORK}/${SUBNETMASK} -j MASQUERADE&#xA;PostDown = iptables -t nat -D POSTROUTING -o ${PHYSICALINTERFACE} -s ${NETWORK}/${SUBNETMASK} -j MASQUERADE&#xA;&#xA;IP filtering&#xA;PreUp = ufw allow in on ${PHYSICALINTERFACE} log to 0.0.0.0/0 app Wireguard&#xA;PostDown = ufw delete allow in on ${PHYSICALINTERFACE} log to 0.0.0.0/0 app Wireguard&#xA;&#xA;ListenPort = ${LISTENPORT}&#xA;PrivateKey = ${SERVERPRIVKEY}&#xA;&#xA;EOF&#xA;        echo &#34;fatto.&#34;&#xA;        cp ${WORKDIR}/conf.d/serverwg.conf ${WORKDIR}/conf.d/serverwgraw.conf&#xA;        # Inizializza l&#39;erogatore di ip&#xA;        echo 1   ${WORKDIR}/conf.d/iprenew&#xA;    else&#xA;        echo &#34;Sono necessarie le credenziali di amministrazione per eseguire questo comando.&#34;&#xA;        exit 1&#xA;    fi&#xA;}&#xA;&#xA;Genera un certificato per il client composto da:&#xA;chiave privata del client&#xA;chiave pre-condivisa&#xA;client ip&#xA;chiave pubblica del server&#xA;nome simbolico del client&#xA;&#xA;Dopo la creazione e il salvataggio in WORKDIR/conf.d, verrà aggiunto&#xA;il relativo peer nella configurazione del server (serverwg.conf).&#xA;@par1 @par2 @par3...: lista di nomi relativi ai certificati da creare.&#xA;addclient() {&#xA;    if isinit; then&#xA;        # Se non c&#39;è alcun input, esco.&#xA;        if [[ $# -lt 1 ]]; then&#xA;            echo -e &#34;Devi inserire almeno un nome.&#34;&#xA;            exit 1&#xA;        else&#xA;            # Per ogni nome presente in input, creo una configurazione &#xA;            # client e l&#39;aggiungo alla configurazione del server.&#xA;            for CLIENTNAME in &#34;$@&#34;; do&#xA;                echo -n &#34;Creazione certificato per il client \&#34;${CLIENTNAME}\&#34;... &#34;&#xA;                &#xA;                # Controllo se la configurazione esista già discriminando&#xA;                # in base al nome del file.&#xA;                if [[ -e ${WORKDIR}/conf.d/client${CLIENTNAME}.conf ]]; then&#xA;                    echo &#34;già esistente.&#34;&#xA;                else&#xA;                    # Creo la configurazione del client&#xA;                    CLIENTPRIVKEY=$(genprivkey ${CLIENTNAME})&#xA;                    CLIENTPUBLICKEY=$(echo ${CLIENTPRIVKEY} | wg pubkey)&#xA;                    CLIENTPSK=$(genclientpsk ${CLIENTNAME})&#xA;                    CLIENTIPADDRESS=$(iprenew)&#xA;                    SERVERPUBLICKEY=$(grep PrivateKey ${WORKDIR}/conf.d/serverwg.conf | cut -d &#34; &#34; -f 3 | tr -d &#34; &#34; | wg pubkey)&#xA;                    CLIENTNAMEUPPER=$(echo ${CLIENTNAME} | tr &#39;[:lower:]&#39; &#39;[:upper:]&#39;)&#xA;                    cat   ${WORKDIR}/conf.d/client${CLIENTNAME}.conf &lt;&lt; EOF&#xA;    # ${CLIENTNAMEUPPER}&#xA;    [Interface]&#xA;    Address = ${CLIENTIPADDRESS}/${SUBNETMASK}&#xA;    DNS = ${DNS}&#xA;    PrivateKey = ${CLIENTPRIVKEY}&#xA;&#xA;    [Peer]&#xA;    PublicKey = ${SERVERPUBLICKEY}&#xA;    PresharedKey = ${CLIENTPSK}&#xA;    AllowedIPs = 0.0.0.0/0&#xA;    Endpoint = ${ENDPOINT}&#xA;    PersistentKeepalive = 25&#xA;EOF&#xA;                    echo &#34;fatto.&#34;&#xA;                    echo -n &#34;Aggiunta peer \&#34;${CLIENTNAME}\&#34; al file di configurazione del server... &#34;&#xA;                    &#xA;                    # Aggiungo il peer alla configurazione del server.&#xA;                    addpeertoserver ${CLIENTPUBLICKEY} ${CLIENTPSK} ${CLIENTIPADDRESS} ${CLIENTNAMEUPPER}&#xA;                    echo -e &#34;fatto.\n&#34;                &#xA;                fi&#xA;            done&#xA;        fi&#xA;    else&#xA;        echo &#34;È necessario inizializzare il server con &#39;wginit.sh init&#39;.&#34;&#xA;        echo &#34;L&#39;operazione richiesta non sarà completata&#34;&#xA;    fi&#xA;}&#xA;&#xA;Rimuove file di configurazioni, chiavi e pre-shared key realtive a file&#xA;dati in input.&#xA;Rimuove inoltre il peer dal file di configurazione serverwg.conf.&#xA;@par1 @par2 @par3...: lista di nomi relativi ai certificati da rimuovere.&#xA;removeclient() {&#xA;    if isinit; then&#xA;        if [[ $# -lt 1 ]]; then&#xA;            echo -e &#34;Devi inserire almeno un nome.&#34;&#xA;            exit 1&#xA;        else&#xA;            for CLIENTNAME in &#34;$@&#34;; do&#xA;                echo -n &#34;Rimozione client \&#34;${CLIENTNAME}\&#34;... &#34;&#xA;                if [[ ! -e ${WORKDIR}/conf.d/client${CLIENTNAME}.conf ]]; then&#xA;                    echo &#34;non esistente.&#34;&#xA;                else&#xA;                    # Estraggo l&#39;ultimo ottetto dell&#39;ip del client.&#xA;                    IP=$(grep &#34;Address&#34; ${WORKDIR}/conf.d/client${CLIENTNAME}.conf|cut -d &#34; &#34; -f 3|tr -d &#34; &#34;|cut -d &#34;/&#34; -f 1)&#xA;                    &#xA;                    # Lo inserisco nella lista degli ip riallocabili.&#xA;                    iprelease ${IP}&#xA;                    &#xA;                    # Cancello file di configurazione, chiave e psk del client.&#xA;                    rm ${WORKDIR}/conf.d/client${CLIENTNAME}.conf ${WORKDIR}/keys/${CLIENTNAME}privkey ${WORKDIR}/psk/${CLIENTNAME}psk&#xA;                    echo &#34;terminata con successo.&#34;&#xA;                    echo -n &#34;Rimozione peer \&#34;${CLIENTNAME}\&#34; dal file di configurazione del server... &#34;&#xA;                    &#xA;                    # Rimuovo il peer dalla configurazione del server.&#xA;                    CLIENTNAMEUPPER=$(echo ${CLIENTNAME} | tr &#39;[:lower:]&#39; &#39;[:upper:]&#39;)&#xA;                    sed -i &#34;/# ${CLIENTNAMEUPPER}/,+6d&#34; ${WORKDIR}/conf.d/serverwg.conf&#xA;                    echo -e &#34;terminata con successo.\n&#34;   &#xA;                fi&#xA;            done&#xA;        fi&#xA;    else&#xA;        echo &#34;È necessario inizializzare il server con &#39;wginit.sh init&#39;.&#34;&#xA;        echo &#34;L&#39;operazione richiesta non sarà completata&#34;&#xA;    fi&#xA;}&#xA;&#xA;rebuild() {&#xA;    if isinit; then&#xA;        # Rigenero il file di configurazione del server da serverwgraw.conf.&#xA;        echo -n &#34;Ripristino del file di configurazione del server... &#34;&#xA;        cat ${WORKDIR}/conf.d/serverwgraw.conf   ${WORKDIR}/conf.d/serverwg.conf&#xA;        echo &#34;fatto.&#34;&#xA;        &#xA;        # Per ogni file di configurazione client, aggiungo il relativo peer&#xA;        # nel file di configurazione serverwg.conf.&#xA;        for FILECONF in ${WORKDIR}/conf.d/client.conf; do&#xA;            CLIENTPUBLICKEY=$(grep &#34;PrivateKey&#34; ${FILECONF}|cut -d &#34; &#34; -f 3|tr -d &#34; &#34; | wg pubkey)&#xA;            CLIENTPSK=$(grep &#34;PresharedKey&#34; ${FILECONF}|cut -d &#34; &#34; -f 3|tr -d &#34; &#34;)&#xA;            CLIENTIPADDRESS=$(grep &#34;Address&#34; ${FILECONF}|cut -d &#34; &#34; -f 3|tr -d &#34; &#34;|cut -d &#34;/&#34; -f 1)&#xA;            CLIENTNAMEUPPER=$(grep &#34;#&#34; ${FILECONF} | cut -d &#34; &#34; -f 2)&#xA;            echo -n &#34;Aggiunta peer \&#34;$(echo ${CLIENTNAMEUPPER} | tr &#39;[:upper:]&#39; &#39;[:lower:]&#39;)\&#34;... &#34;&#xA;            addpeertoserver ${CLIENTPUBLICKEY} ${CLIENTPSK} ${CLIENTIPADDRESS} ${CLIENTNAMEUPPER}&#xA;            echo -e &#34;fatto.&#34;&#xA;        done&#xA;    else&#xA;        echo &#34;È necessario inizializzare il server con &#39;wginit.sh init&#39;.&#34;&#xA;        echo &#34;L&#39;operazione richiesta non sarà completata&#34;&#xA;    fi&#xA;}&#xA;&#xA;Avvia il server wireguard con la nuova configurazione&#xA;deploy() {&#xA;    if isinit; then&#xA;        echo -n &#34;Inserire la password di Amministratore: &#34;; read -s PASSWORD&#xA;        sudo -k&#xA;        if echo $PASSWORD|sudo -S echo &#34;got a root&#34;   /dev/null; then&#xA;   &#xA;            # Stoppo il servizio wireguard&#xA;            echo -ne &#34;\nStop wireguard... &#34;&#xA;            sudo systemctl stop wg-quick@${WGINTERFACE}&#xA;            echo &#34;fatto.&#34;&#xA;            &#xA;            # Aggiorno la configurazione&#xA;            echo -n &#34;Copia della nuova configurazione... &#34;&#xA;            sudo cp ${WORKDIR}/conf.d/serverwg.conf /etc/wireguard/${WGINTERFACE}&#xA;            echo &#34;fatto.&#34;&#xA;            &#xA;            # Riavvio il servizio wireguard&#xA;            echo -n &#34;Riavvio wireguard... &#34;&#xA;            sudo systemctl start wg-quick@${WGINTERFACE}&#xA;            echo &#34;fatto.&#34;&#xA;            &#xA;            # Revoco i privilegi di amministrazione&#xA;            sudo -k&#xA;        else&#xA;            echo &#34;Sono necessarie le credenziali di amministrazione per eseguire questo comando.&#34;&#xA;            exit 1&#xA;        fi&#xA;    else&#xA;        echo &#34;È necessario inizializzare il server con &#39;wginit.sh init&#39;.&#34;&#xA;        echo &#34;L&#39;operazione richiesta non sarà completata&#34;&#xA;    fi&#xA;}&#xA;&#xA;Crea il qr-code della configurazione del client nella cartella corrente.&#xA;share() {&#xA;    if isinit; then&#xA;        if [[ $# -lt 1 ]]; then&#xA;            echo -e &#34;Devi inserire almeno un nome.&#34;&#xA;            exit 1&#xA;        else&#xA;            for CLIENTNAME in &#34;$@&#34;; do&#xA;                echo -n &#34;Creazione qr-code per il client \&#34;${CLIENTNAME}\&#34;... &#34;&#xA;                qrencode -r ${WORKDIR}/conf.d/client${CLIENTNAME}.conf -o qrcodeclient${CLIENTNAME}.jpg&#xA;                echo &#34;fatto.&#34;&#xA;            done&#xA;        fi&#xA;    else&#xA;        echo &#34;È necessario inizializzare il server con &#39;wginit.sh init&#39;.&#34;&#xA;        echo &#34;L&#39;operazione richiesta non sarà completata&#34;&#xA;    fi&#xA;}&#xA;&#xA;help() {&#xA;&#xA;[[ $1 != &#34;&#34; &amp;&amp; $1 != &#34;help&#34; ]] &amp;&amp; echo -e &#34;Comando inesistente.&#34;&#xA;&#xA;    cat&lt;&lt;EOF&#xA;Usa come: ./wgman.sh [command] ARG&#xA;dove:&#xA;    [command]&#xA;        init                     : Inizializza la configurazione del server.&#xA;        addclient lista nomi   : Aggiunge i client indicati in lista nomi.&#xA;        removeclient lista nomi: Rimuove i client indicati in lista nomi.&#xA;        rebuild                  : Ricostruisce il file di configurazione&#xA;                                   del server partendo dalle configurazioni&#xA;                                   di tutti i client registrati.&#xA;        deploy                   : Riavvia il server wireguard con l&#39;ultima&#xA;                                   configurazione disponibile.&#xA;        share lista nomi       : Genera i qr-code relativi ai client indicati in lista nomi.&#xA;        help                     : Stampa questa pagina di help.&#xA;&#xA;ESEMPI:&#xA;    INiZIALIZZA IL SERVER WIREGUARD&#xA;    wgman.sh init&#xA;&#xA;    AGGIUNGE I CLIENT &#39;macbookpro&#39;, &#39;mobile&#39;&#xA;    wgman.sh addclient macbookpro mobile&#xA;&#xA;    RIMUOVE I CLIENT &#39;iphoneluca&#39;, &#39;workstation&#39;&#xA;    wgman.sh removeclient iphoneluca workstation&#xA;&#xA;    RICOSTRUISCE LA CONFIGURAZIONE DEL SERVER WIREGUARD&#xA;    wgman.sh rebuild&#xA;    &#xA;    ATTIVA LA NUOVA CONFIGURAZIONE&#xA;    wgman.sh deploy&#xA;&#xA;    GENERA I QRCODE PER &#39;pcufficio&#39;, &#39;laptop&#39;&#xA;    wgman.sh share pcufficio laptop&#xA;EOF&#xA;}&#xA;&#xA;main() {&#xA;    case $1 in&#xA;        init         ) init ;;&#xA;        addclient    ) shift; addclient &#34;$@&#34; ;;&#xA;        removeclient ) shift; removeclient &#34;$@&#34; ;;&#xA;        rebuild      ) rebuild ;;&#xA;        deploy       ) deploy ;;&#xA;        share        ) shift; share &#34;$@&#34; ;;&#xA;        ) help ;;&#xA;    esac&#xA;}&#xA;&#xA;check_dependency&#xA;case $? in&#xA;    &#34;0&#34; ) main $* ;;&#xA;    &#34;1&#34; ) echo -e &#34;UFW non presente. Installare UFW.&#34;; exit 1 ;;&#xA;    &#34;2&#34; ) echo -e &#34;wireguard-tools non presenti. È necessario installarli.&#34;; exit 1 ;;&#xA;esac&#xA;&#xA;#bash #wireguard #psk #chiavi #certificati #crittografia&#xA;]]&gt;</description>
      <content:encoded><![CDATA[<p><img src="https://pixelfed.uno/storage/m/_v2/489827599091373610/586f75268-5004eb/XBn3L6jB84Ka/b6zYDZWzIcLbax1taLgBnIQu8hoy7ZeZVlXBkGf0.png" alt="vpn"></p>

<p><a href="https://noblogo.org/aytin/vpn-con-wireguard-semplice-e-veloce" rel="nofollow">Cos&#39;è wireguard e come si configura</a>, lo sappiamo ma mi serviva qualcosa che mi permettesse di fare provisioning e deprovisioning dei certificati in maniera più semplice di quanto già si faccia con i tool disponibili nella userland, wg e wg-quick.</p>

<p>E questo è il motivo principale per cui è nato questo script.

Prende come riferimento una configurazione road warrior, <a href="https://noblogo.org/aytin/vpn-con-wireguard-semplice-e-veloce#primo-scenario" rel="nofollow">il primo scenario di una topologia point-to-site</a>, quella più comune.</p>

<h2 id="alcune-considerazioni">Alcune considerazioni</h2>
<ol><li><p>Lo script definisce una workdir dove deposita tutte le configurazioni e i certificati.
Le precondizioni sono legate alla presenza dei tool userland <strong>wg-tools</strong> (ovviamente) e di <strong>ufw</strong>. Vengono comunque verificate nello script.</p></li>

<li><p>Altra semplificazione è data dal fatto di allocare una /24 come rete wireguard. 254 host per una rete domestica sono più che sufficienti.</p></li>

<li><p>L&#39;allocazione degli ip viene fatta con un progressivo memorizzato nel file &#39;ip_renew&#39;. Gli ip dei certificati revocati vengono mantenuti in un file, &#39;ip_release&#39;.
Quando si crea un nuovo certificato, si controlla prima che ci sia un ip da recuperare in ip_release. Se la lista è vuota si ricorre al progressivo.</p></li>

<li><p>La creazione della configurazione lato server passa da due file di configurazione: una configurazione <strong>globale</strong> ottenuta tracciando l&#39;evoluzione iniziale in termini di aggiunta o rimozione dei client peer e destinata al rilascio in esecuzione. L&#39;altra contenente <strong>la sola configurazione del server</strong> e usata unicamente per la rigenerazione della configurazione globale a partire dai peer esistenti.</p></li>

<li><p>L&#39;operazione di <strong>init</strong> è propedeutica per <strong>addclient</strong>, <strong>removeclient</strong>, <strong>rebuild</strong>, <strong>deploy</strong>, <strong>share</strong>.</p></li></ol>

<p>Le operazioni a disposizione sono:</p>
<ul><li><strong>init:</strong> inizializza la configurazione di un server wireguard</li>
<li><strong>addclient:</strong> crea il certificato lato client e aggiunge il relativo peer sulla configurazione del server</li>
<li><strong>removeclient:</strong> cancella il certificato lato client e rimuove il relativo peer sulla configurazione del server</li>
<li><strong>rebuild:</strong> rigenera la configurazione del server usando i certificati client esistenti</li>
<li><strong>deploy:</strong> finalizza la configurazione riavviando il servizio con le nuove impostazioni</li>
<li><strong>share:</strong> crea i qr-code per i certificati client da utilizzare nelle configurazioni</li></ul>

<p>Per tutto il resto, i commenti nel codice sono abbastanza esplicativi.</p>

<h2 id="lo-script">Lo script</h2>

<pre><code class="language-bash">#!/bin/bash

# Questo è il file di configurazione globale, i dati sono fittizi.
# Può essere mantenuto nello script o nella home dell&#39;utente 
# (es. $HOME/.config/wg_man.conf) e importato 
# con &#39;source&#39; all&#39;inizio.
WG_INTERFACE=wg0
PHYSICAL_INTERFACE=eth0
NETWORK=&#34;192.168.15.0&#34;
SUBNET_MASK=&#34;24&#34;
SERVER_IP_ADDRESS=&#34;192.168.15.1&#34;
DNS=&#34;1.1.1.1&#34;
LISTEN_PORT=&#34;51820&#34;
ENDPOINT=wireguard.nodns.net:51820&#34;
WORKDIR=&#34;$HOME/wireguard&#34;



check_dependency() {
    if test -e /usr/sbin/ufw; then
        if test -e /usr/bin/wg; then
            return 0
        else
            return 2
        fi
    else
        return 1
    fi
}



is_init() {
    test -e ${WORKDIR}/conf.d/server_wg.conf &amp;&amp; return 0 || return 1
}



# Genera la chiave privata
gen_priv_key() {
    wg genkey | tee ${WORKDIR}/keys/$1_privkey
}



# Genera la pre-shared key
gen_client_psk() {
    # Evita il warning sui permessi del file che devono essere 600
    umask 077
    wg genpsk | tee ${WORKDIR}/psk/$1_psk
}



# Rilascio di un nuovo indirizzo ip. Questa funziona viene invocata da
# addclient().
#
# I primi 3 ottetti li ottengo dalla variabile globale NETWORK.
# L&#39;ultimo ottetto, relativo all&#39;host, lo ricavo dalla lista degli ip
# riutilizzabili (&#34;ip_release&#34;).
#
# Se non è vuota, prelevo il primo e lo rimuovo dalla lista. Se è vuota,
# prelevo l&#39;ultimo ottetto da &#34;ip_renew&#34; e lo incremento per il successivo
# assegnamento.
ip_renew() {
    # Selezioni i primi 3 ottetti del network
    SUB_IP=$(echo ${NETWORK}|awk -F &#34;.&#34; &#39;{print $1&#34;.&#34;$2&#34;.&#34;$3}&#39;)

    if [[ ! -e ${WORKDIR}/conf.d/ip_release || ! -s ${WORKDIR}/conf.d/ip_release ]]; then
        # Genero il nuovo ip (Incremento di 1 l&#39;ultimo ottetto)
        IP=$(cat ${WORKDIR}/conf.d/ip_renew)
        echo $((++IP)) &gt; ${WORKDIR}/conf.d/ip_renew

        # Restituisco i 3 ottetti + il quarto
        #echo -n ${SUB_IP};cat ${WORKDIR}/conf.d/ip_renew
    else
        IP=$(head -n 1 ${WORKDIR}/conf.d/ip_release)
        sed -i &#34;1d&#34; ${WORKDIR}/conf.d/ip_release
    fi
    echo -n ${SUB_IP}&#34;.&#34;${IP}
}



# Riallocazione di un indirizzo ip. Questa funzione viene invocata da
# removeclient().
# Aggiungo l&#39;ultimo ottetto alla lista degli ip riallocabili.
# @par 1: ultimo ottetto.
ip_release() {
    echo $1|cut -d&#34;.&#34; -f 4 &gt;&gt; ${WORKDIR}/conf.d/ip_release
}



# Aggiunge il nuovo peer al file di configurazione del server
# @par 1: CLIENT_PUBLIC_KEY
# @par 2: CLIENT_PSK
# @par 3: CLIENT_IP_ADDRESS
# @par 4: CLIENT_NAME
add_peer_to_server() {
    cat &gt;&gt; ${WORKDIR}/conf.d/server_wg.conf &lt;&lt; EOF
# $4
[Peer]
PublicKey = $1
PresharedKey = $2
AllowedIPs = $3/32
PersistentKeepalive = 25

EOF
}



# Inizializza la configurazione del server wireguard.
#
# Questa operazione può essere fatta una sola volta a meno che non si
# cancelli tutta la workdir.
#
# Verranno creati due file  di configurazione: server_wg.conf e 
# server_wg_raw.conf
#
# Il primo conterrà la configurazione completa del server e dei peer,
# verrà aggiornato ad ogni modifica dei client (aggiunta o rimozione) e
# verrà usato per il deploy della configurazione.
#
# Il secondo conterrà la configurazione del solo server e verrà usato
# solo per rigenerare il primo file di configurazione.
init() {
    # Controllo che wireguard sia almeno abilitato
    echo -n &#34;Inserire la password di Amministratore: &#34;; read -s PASSWORD
    sudo -k
    if echo $PASSWORD|sudo -S echo &#34;got a root&#34; &gt; /dev/null; then
        if ! sudo systemctl is-enabled --quiet wg-quick@${WG_INTERFACE}; then
            echo -en &#34;\nAttivazione servizio wireguard... &#34;
            #sudo systemctl enable --quiet wg-quick@${WG_INTERFACE}
            echo &#34;fatto.&#34;
        fi
        sudo -k 
        
        #Verifico che queste cartelle esistano. Se lo sono, non faccio nulla, se no le creo.
        echo -n &#34;Creazione workdir... &#34;
        [[ ! -e ${WORKDIR}/conf.d || ! -e ${WORKDIR}/psk  || ! -e ${WORKDIR}/keys ]] \
            &amp;&amp; { mkdir -p ${WORKDIR}/{conf.d,keys,psk}; } \
            || { echo &#34;inizializzazione già effettuata.&#34;; exit; }
        echo &#34;fatto.&#34;
        
        # Genero la chiave privata per il server
        echo -n &#34;Creazione chiave private del server...&#34;
        SERVER_PRIV_KEY=$(gen_priv_key &#34;server_wg&#34;)
        echo &#34;fatto.&#34;

        # Genero il file di configurazione
        echo -n &#34;Inizializzazione del server... &#34;
        cat &gt; ${WORKDIR}/conf.d/server_wg.conf &lt;&lt; EOF
[Interface]
Address = ${SERVER_IP_ADDRESS}/${SUBNET_MASK}
# SaveConfig = true

PreUp = ufw route allow in on ${WG_INTERFACE} out on ${PHYSICAL_INTERFACE} log from ${NETWORK}/${SUBNET_MASK} to 0.0.0.0/0
PostDown = ufw route delete allow in on ${WG_INTERFACE} out on ${PHYSICAL_INTERFACE} log from ${NETWORK}/${SUBNET_MASK} to 0.0.0.0/0

# IP masquerading
PreUp = iptables -t nat -A POSTROUTING -o ${PHYSICAL_INTERFACE} -s ${NETWORK}/${SUBNET_MASK} -j MASQUERADE
PostDown = iptables -t nat -D POSTROUTING -o ${PHYSICAL_INTERFACE} -s ${NETWORK}/${SUBNET_MASK} -j MASQUERADE

# IP filtering
PreUp = ufw allow in on ${PHYSICAL_INTERFACE} log to 0.0.0.0/0 app Wireguard
PostDown = ufw delete allow in on ${PHYSICAL_INTERFACE} log to 0.0.0.0/0 app Wireguard

ListenPort = ${LISTEN_PORT}
PrivateKey = ${SERVER_PRIV_KEY}

EOF
        echo &#34;fatto.&#34;
        cp ${WORKDIR}/conf.d/server_wg.conf ${WORKDIR}/conf.d/server_wg_raw.conf
        # Inizializza l&#39;erogatore di ip
        echo 1 &gt; ${WORKDIR}/conf.d/ip_renew
    else
        echo &#34;Sono necessarie le credenziali di amministrazione per eseguire questo comando.&#34;
        exit 1
    fi
}



# Genera un certificato per il client composto da:
# * chiave privata del client
# * chiave pre-condivisa
# * client ip
# * chiave pubblica del server
# * nome simbolico del client
#
# Dopo la creazione e il salvataggio in &lt;WORKDIR&gt;/conf.d, verrà aggiunto
# il relativo peer nella configurazione del server (server_wg.conf).
# @par_1 @par_2 @par_3...: lista di nomi relativi ai certificati da creare.
add_client() {
    if is_init; then
        # Se non c&#39;è alcun input, esco.
        if [[ $# -lt 1 ]]; then
            echo -e &#34;Devi inserire almeno un nome.&#34;
            exit 1
        else
            # Per ogni nome presente in input, creo una configurazione 
            # client e l&#39;aggiungo alla configurazione del server.
            for CLIENT_NAME in &#34;$@&#34;; do
                echo -n &#34;Creazione certificato per il client \&#34;${CLIENT_NAME}\&#34;... &#34;
                
                # Controllo se la configurazione esista già discriminando
                # in base al nome del file.
                if [[ -e ${WORKDIR}/conf.d/client_${CLIENT_NAME}.conf ]]; then
                    echo &#34;già esistente.&#34;
                else
                    # Creo la configurazione del client
                    CLIENT_PRIV_KEY=$(gen_priv_key ${CLIENT_NAME})
                    CLIENT_PUBLIC_KEY=$(echo ${CLIENT_PRIV_KEY} | wg pubkey)
                    CLIENT_PSK=$(gen_client_psk ${CLIENT_NAME})
                    CLIENT_IP_ADDRESS=$(ip_renew)
                    SERVER_PUBLIC_KEY=$(grep PrivateKey ${WORKDIR}/conf.d/server_wg.conf | cut -d &#34; &#34; -f 3 | tr -d &#34; &#34; | wg pubkey)
                    CLIENT_NAME_UPPER=$(echo ${CLIENT_NAME} | tr &#39;[:lower:]&#39; &#39;[:upper:]&#39;)
                    cat &gt; ${WORKDIR}/conf.d/client_${CLIENT_NAME}.conf &lt;&lt; EOF
    # ${CLIENT_NAME_UPPER}
    [Interface]
    Address = ${CLIENT_IP_ADDRESS}/${SUBNET_MASK}
    DNS = ${DNS}
    PrivateKey = ${CLIENT_PRIV_KEY}

    [Peer]
    PublicKey = ${SERVER_PUBLIC_KEY}
    PresharedKey = ${CLIENT_PSK}
    AllowedIPs = 0.0.0.0/0
    Endpoint = ${ENDPOINT}
    PersistentKeepalive = 25
EOF
                    echo &#34;fatto.&#34;
                    echo -n &#34;Aggiunta peer \&#34;${CLIENT_NAME}\&#34; al file di configurazione del server... &#34;
                    
                    # Aggiungo il peer alla configurazione del server.
                    add_peer_to_server ${CLIENT_PUBLIC_KEY} ${CLIENT_PSK} ${CLIENT_IP_ADDRESS} ${CLIENT_NAME_UPPER}
                    echo -e &#34;fatto.\n&#34;                
                fi
            done
        fi
    else
        echo &#34;È necessario inizializzare il server con &#39;wg_init.sh init&#39;.&#34;
        echo &#34;L&#39;operazione richiesta non sarà completata&#34;
    fi
}



# Rimuove file di configurazioni, chiavi e pre-shared key realtive a file
# dati in input.
# Rimuove inoltre il peer dal file di configurazione server_wg.conf.
# @par_1 @par_2 @par_3...: lista di nomi relativi ai certificati da rimuovere.
remove_client() {
    if is_init; then
        if [[ $# -lt 1 ]]; then
            echo -e &#34;Devi inserire almeno un nome.&#34;
            exit 1
        else
            for CLIENT_NAME in &#34;$@&#34;; do
                echo -n &#34;Rimozione client \&#34;${CLIENT_NAME}\&#34;... &#34;
                if [[ ! -e ${WORKDIR}/conf.d/client_${CLIENT_NAME}.conf ]]; then
                    echo &#34;non esistente.&#34;
                else
                    # Estraggo l&#39;ultimo ottetto dell&#39;ip del client.
                    IP=$(grep &#34;Address&#34; ${WORKDIR}/conf.d/client_${CLIENT_NAME}.conf|cut -d &#34; &#34; -f 3|tr -d &#34; &#34;|cut -d &#34;/&#34; -f 1)
                    
                    # Lo inserisco nella lista degli ip riallocabili.
                    ip_release ${IP}
                    
                    # Cancello file di configurazione, chiave e psk del client.
                    rm ${WORKDIR}/conf.d/client_${CLIENT_NAME}.conf ${WORKDIR}/keys/${CLIENT_NAME}_privkey ${WORKDIR}/psk/${CLIENT_NAME}_psk
                    echo &#34;terminata con successo.&#34;
                    echo -n &#34;Rimozione peer \&#34;${CLIENT_NAME}\&#34; dal file di configurazione del server... &#34;
                    
                    # Rimuovo il peer dalla configurazione del server.
                    CLIENT_NAME_UPPER=$(echo ${CLIENT_NAME} | tr &#39;[:lower:]&#39; &#39;[:upper:]&#39;)
                    sed -i &#34;/# ${CLIENT_NAME_UPPER}/,+6d&#34; ${WORKDIR}/conf.d/server_wg.conf
                    echo -e &#34;terminata con successo.\n&#34;   
                fi
            done
        fi
    else
        echo &#34;È necessario inizializzare il server con &#39;wg_init.sh init&#39;.&#34;
        echo &#34;L&#39;operazione richiesta non sarà completata&#34;
    fi
}



rebuild() {
    if is_init; then
        # Rigenero il file di configurazione del server da server_wg_raw.conf.
        echo -n &#34;Ripristino del file di configurazione del server... &#34;
        cat ${WORKDIR}/conf.d/server_wg_raw.conf &gt; ${WORKDIR}/conf.d/server_wg.conf
        echo &#34;fatto.&#34;
        
        # Per ogni file di configurazione client, aggiungo il relativo peer
        # nel file di configurazione server_wg.conf.
        for FILE_CONF in ${WORKDIR}/conf.d/client_*.conf; do
            CLIENT_PUBLIC_KEY=$(grep &#34;PrivateKey&#34; ${FILE_CONF}|cut -d &#34; &#34; -f 3|tr -d &#34; &#34; | wg pubkey)
            CLIENT_PSK=$(grep &#34;PresharedKey&#34; ${FILE_CONF}|cut -d &#34; &#34; -f 3|tr -d &#34; &#34;)
            CLIENT_IP_ADDRESS=$(grep &#34;Address&#34; ${FILE_CONF}|cut -d &#34; &#34; -f 3|tr -d &#34; &#34;|cut -d &#34;/&#34; -f 1)
            CLIENT_NAME_UPPER=$(grep &#34;#&#34; ${FILE_CONF} | cut -d &#34; &#34; -f 2)
            echo -n &#34;Aggiunta peer \&#34;$(echo ${CLIENT_NAME_UPPER} | tr &#39;[:upper:]&#39; &#39;[:lower:]&#39;)\&#34;... &#34;
            add_peer_to_server ${CLIENT_PUBLIC_KEY} ${CLIENT_PSK} ${CLIENT_IP_ADDRESS} ${CLIENT_NAME_UPPER}
            echo -e &#34;fatto.&#34;
        done
    else
        echo &#34;È necessario inizializzare il server con &#39;wg_init.sh init&#39;.&#34;
        echo &#34;L&#39;operazione richiesta non sarà completata&#34;
    fi
}



# Avvia il server wireguard con la nuova configurazione
deploy() {
    if is_init; then
        echo -n &#34;Inserire la password di Amministratore: &#34;; read -s PASSWORD
        sudo -k
        if echo $PASSWORD|sudo -S echo &#34;got a root&#34; &gt; /dev/null; then
   
            # Stoppo il servizio wireguard
            echo -ne &#34;\nStop wireguard... &#34;
            sudo systemctl stop wg-quick@${WG_INTERFACE}
            echo &#34;fatto.&#34;
            
            # Aggiorno la configurazione
            echo -n &#34;Copia della nuova configurazione... &#34;
            sudo cp ${WORKDIR}/conf.d/server_wg.conf /etc/wireguard/${WG_INTERFACE}
            echo &#34;fatto.&#34;
            
            # Riavvio il servizio wireguard
            echo -n &#34;Riavvio wireguard... &#34;
            sudo systemctl start wg-quick@${WG_INTERFACE}
            echo &#34;fatto.&#34;
            
            # Revoco i privilegi di amministrazione
            sudo -k
        else
            echo &#34;Sono necessarie le credenziali di amministrazione per eseguire questo comando.&#34;
            exit 1
        fi
    else
        echo &#34;È necessario inizializzare il server con &#39;wg_init.sh init&#39;.&#34;
        echo &#34;L&#39;operazione richiesta non sarà completata&#34;
    fi
}



# Crea il qr-code della configurazione del client nella cartella corrente.
share() {
    if is_init; then
        if [[ $# -lt 1 ]]; then
            echo -e &#34;Devi inserire almeno un nome.&#34;
            exit 1
        else
            for CLIENT_NAME in &#34;$@&#34;; do
                echo -n &#34;Creazione qr-code per il client \&#34;${CLIENT_NAME}\&#34;... &#34;
                qrencode -r ${WORKDIR}/conf.d/client_${CLIENT_NAME}.conf -o qrcode_client_${CLIENT_NAME}.jpg
                echo &#34;fatto.&#34;
            done
        fi
    else
        echo &#34;È necessario inizializzare il server con &#39;wg_init.sh init&#39;.&#34;
        echo &#34;L&#39;operazione richiesta non sarà completata&#34;
    fi
}



help() {

[[ $1 != &#34;&#34; &amp;&amp; $1 != &#34;help&#34; ]] &amp;&amp; echo -e &#34;Comando inesistente.&#34;

    cat&lt;&lt;EOF
Usa come: ./wg_man.sh [command] ARG
dove:
    [command]
        init                     : Inizializza la configurazione del server.
        addclient &lt;lista nomi&gt;   : Aggiunge i client indicati in &lt;lista nomi&gt;.
        removeclient &lt;lista nomi&gt;: Rimuove i client indicati in &lt;lista nomi&gt;.
        rebuild                  : Ricostruisce il file di configurazione
                                   del server partendo dalle configurazioni
                                   di tutti i client registrati.
        deploy                   : Riavvia il server wireguard con l&#39;ultima
                                   configurazione disponibile.
        share &lt;lista nomi&gt;       : Genera i qr-code relativi ai client indicati in &lt;lista nomi&gt;.
        help                     : Stampa questa pagina di help.

ESEMPI:
    INiZIALIZZA IL SERVER WIREGUARD
    wg_man.sh init

    AGGIUNGE I CLIENT &#39;macbook_pro&#39;, &#39;mobile&#39;
    wg_man.sh addclient macbook_pro mobile

    RIMUOVE I CLIENT &#39;iphone_luca&#39;, &#39;workstation&#39;
    wg_man.sh removeclient iphone_luca workstation

    RICOSTRUISCE LA CONFIGURAZIONE DEL SERVER WIREGUARD
    wg_man.sh rebuild
    
    ATTIVA LA NUOVA CONFIGURAZIONE
    wg_man.sh deploy

    GENERA I QRCODE PER &#39;pc_ufficio&#39;, &#39;laptop&#39;
    wg_man.sh share pc_ufficio laptop
EOF
}



main() {
    case $1 in
        init         ) init ;;
        addclient    ) shift; add_client &#34;$@&#34; ;;
        removeclient ) shift; remove_client &#34;$@&#34; ;;
        rebuild      ) rebuild ;;
        deploy       ) deploy ;;
        share        ) shift; share &#34;$@&#34; ;;
        *            ) help ;;
    esac
}



check_dependency
case $? in
    &#34;0&#34; ) main $* ;;
    &#34;1&#34; ) echo -e &#34;UFW non presente. Installare UFW.&#34;; exit 1 ;;
    &#34;2&#34; ) echo -e &#34;wireguard-tools non presenti. È necessario installarli.&#34;; exit 1 ;;
esac
</code></pre>

<p><a href="/aytin/tag:bash" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">bash</span></a> <a href="/aytin/tag:wireguard" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">wireguard</span></a> <a href="/aytin/tag:psk" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">psk</span></a> <a href="/aytin/tag:chiavi" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">chiavi</span></a> <a href="/aytin/tag:certificati" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">certificati</span></a> <a href="/aytin/tag:crittografia" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">crittografia</span></a></p>
]]></content:encoded>
      <guid>https://noblogo.org/aytin/script-per-la-gestione-della-configurazione-di-una-vpn-wireguard</guid>
      <pubDate>Sun, 22 Sep 2024 13:27:09 +0000</pubDate>
    </item>
  </channel>
</rss>