<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><title>Stéphane HUC :: IT Log</title><subtitle>Documentations for SysAdmin, Network by Stéphane HUC</subtitle><link href="https://doc.huc.fr.eu.org/en/atom.xml" hreflang="en" rel="self" type="application/atom+xml"/><link href="https://doc.huc.fr.eu.org/fr/atom.xml" hreflang="fr" rel="alternate" type="application/atom+xml"/><link href="http://creativecommons.org/publicdomain/zero/1.0/legalcode.en" hreflang="en" rel="license"/><link href="http://creativecommons.org/publicdomain/zero/1.0/deed.en" hreflang="en" rel="license"/><rights>2026 Stéphane HUC</rights><icon>/img/favicon.ico</icon><logo>/svg/Logo_final.svg</logo><updated>2026-10-02T15:49:57+02:00</updated><author><name>Stéphane HUC</name><email>consult+hugo@huc.fr.eu.org</email><uri>https://it-log.fr.eu.org/en/</uri></author><generator uri="https://gohugo.io" version="0.165.0">Hugo</generator><entry><id>tag:doc.huc.fr.eu.org,2026-06-22:/en/post/linux-elite-dangerous/#60fe04b72f5df9a9bd62a6fb46a117a57be972494eedf50ce02ac7ba84f67911</id><link href="https://it-log.fr.eu.org/en/post/linux-elite-dangerous/" rel="alternate" type="text/html"/><title>(Linux) Elite Dangerous: complementary tools</title><author><name>Stéphane HUC</name></author><category term="Games" scheme="https://it-log.fr.eu.org/en/tags/games/"/><category term="Steam" scheme="https://it-log.fr.eu.org/en/tags/steam/"/><category term="Linux" scheme="https://it-log.fr.eu.org/en/tags/linux/"/><content type="html"><![CDATA[<h2 id="description">Description</h2>
<ul>
<li>Environment : Steam / Debian Sid / Xfce</li>
<li>Game : Elite Dangerous ; DLC : Odyssey</li>
<li>Compatibility : no specific Steam Play compatibility tool</li>
</ul>
<p>o7, CMDR: The game is functional without particular worries…</p>
<h2 id="configuration">Configuration</h2>
<ul>
<li>
<p>Installation folder of the game : <code>steam/steamapps/common/Elite Dangerous/</code>; <em>this one is easily found in Steam, click D on the game, then “Properties”; menu “Installed files”; then click on the [ Browse… ] button that will open the directory in question</em>.</p>
</li>
<li>
<p>Path to the Binary <code>EliteDangerous64.exe</code>: <code>steam/steamapps/common/Elite Dangerous/Products/elite-dangerous-odyssey-64/</code></p>
</li>
<li>
<p>Path of the “windows” data of the game: <code>steam/steamapps/compatdata/359320/pfx/drive_c/users/steamuser/AppData/Local/Frontier Developments/Elite Dangerous/</code></p>
</li>
<li>
<p>Game backup folder: <code>steam/steamapps/compatdata/359320/pfx/drive_c/users/steamuser/Saved Games/Frontier Developments/Elite Dangerous/</code></p>
</li>
</ul>
<h3 id="keybinding">Keybinding</h3>
<p>Setting up keyboard key management is not a part of the fun.</p>
<p>You must create a directory called “Bindings” in the subdirectory “Options” of the “windows” data folder of the game, such as: <br>
<code>steam/steamapps/compatdata/359320/pfx/drive_c/users/steamuser/AppData/Local/Frontier Developments/Elite Dangerous/Options/Bindings/</code>.</p>
<hr>
<p>⇒ Profiles are available mainly on EDRefCard.</p>
<p>Here is my version : <a href="/share/Custom.4.2.binds.txt">Custom.4.2.binds</a> ; remove the extension <code>.txt</code> ;)</p>
<ul>
<li>Relaunch the game and change the profile in the Game Options &gt; Controls; then choose to change the presets.</li>
</ul>
<h3 id="steam-desktop-shortcut">Steam desktop shortcut</h3>
<p>It’s possible that Steam created a game desktop launcher; but in fact, it won’t work.</p>
<ul>
<li>
<p>Right-click on the launcher to “Edit Launcher” and then in the “Order” field, fill in the absolute path to the Steam executable, such as (under Debian): <br>
<code>/usr/games/steam steam://…</code></p>
</li>
<li>
<p>To find out where the absolute path to the Steam binary is, in a console, run the following command: <br>
<code>:$ command -v steam</code></p>
</li>
</ul>
<p>This modification being made, the desktop launcher will indeed launch the game.</p>
<h3 id="desktop-authorizations">Desktop Authorizations</h3>
<p>You must allow the file to be executed as a .desktop file.</p>
<p><em>If at the first launch, you refused, it does not matter</em>; right click on the launcher:</p>
<ul>
<li>
<p>choose “Properties…”,</p>
</li>
<li>
<p>click on the “Launcher” tab and in the “Security” section, click on the checkboxes in front:</p>
<ul>
<li><input disabled="" type="checkbox"> Allow this file to be run as a .desktop file</li>
<li><input disabled="" type="checkbox"> Set this file as approved</li>
</ul>
</li>
</ul>
<h2 id="tools">Tools</h2>
<p>All of the tools below run on Linux, with some configurations.</p>
<p>It is not, however, that it is necessary to install them all; in any case, ensure that only a single tool that collects them datas, (<em>Inara, EDSM, etc.</em>), such as <a href="/en/post/linux-elite-dangerous/#edmarketconnector">EDMarketConnector</a> or <a href="/en/post/linux-elite-dangerous/#eddiscovery">EDDiscovery</a> for example.</p>
<hr>
<p>For some, the use of the tool <code>protontricks</code> will be necessary; fortunately in many distributions, including Debian, it is provided as a package; install it!</p>
<h3 id="edhm-ui">EDHM-UI</h3>
<p><strong>EDHM-UI</strong> v3 is a tool to modify the graphical interface.</p>
<ul>
<li>Official website: <a href="https://bluemystical.github.io/edhm-api/" rel="external">https://bluemystical.github.io/edhm-api/</a></li>
<li>Git: <a href="https://github.com/BlueMystical/EDHM_UI" rel="external">https://github.com/BlueMystical/EDHM_UI</a></li>
<li>Used version: <del>3.0.67</del>, 3.0.70</li>
</ul>
<p>Once installed :</p>
<ul>
<li>Configuration files : <code>$HOME/.local/share/EDHM-UI-V3/</code></li>
</ul>
<hr>
<p>In the repository, you have to go to the <a href="https://github.com/BlueMystical/EDHM_UI/releases" rel="external">Release</a> page and download:</p>
<ul>
<li>the archive <strong>edhm-ui-v3-linux-x64.zip</strong></li>
<li>the <strong>shell script linux_installer.sh</strong></li>
</ul>
<p>Once the archive is downloaded, unzip it and copy into the install script. Give the script execution rights and run it.</p>
<hr>
<p>The tool is accessible from the system menu; <em>with Xfce, in the “Accessories” menu</em>.</p>
<p>By default, the tool seeks to communicate with the game for the correct setting; it is necessary to restore the absolute path of the directory “elite-dangerous-odyssey-64”; if you missed something in the step, choose the menu “Main menu” &gt; “Settings”.</p>
<h3 id="edmarketconnector">EDMarketConnector</h3>
<p><strong>EDMarketConnector</strong> is a python tool to “improve” trade in Elite Dangerous, mainly, although it is able to use secondary features through plugins.</p>
<p>Two versions exist: one via <a href="https://flathub.org/fr/apps/io.edcd.EDMarketConnector" rel="external">flatpak</a>, and the other through the sources into the Git repository.</p>
<ul>
<li>
<p>Git: <a href="https://github.com/EDCD/EDMarketConnector" rel="external">https://github.com/EDCD/EDMarketConnector</a></p>
</li>
<li>
<p>Used version: 6.1.2</p>
</li>
<li>
<p>Configuration files:</p>
<ul>
<li>via flatpak: <code>$HOME/.var/app/io.edcd.EDMarketConnector/</code></li>
<li>via git: <code>$HOME/.local/share/EDMarketConnector/</code></li>
</ul>
</li>
<li>
<p>The main configuration file: <code>config.toml</code>.</p>
</li>
</ul>
<hr>
<p>⇒ Installation from the sources is done quite easily:</p>
<pre tabindex="0"><code>:$ git clone https://github.com/EDCD/EDMarketConnector.git

:$ cd EDMarketConnector
EDMarketConnector :$ python3 -m venv venv
EDMarketConnector :$ source venv/bin/activate
EDMarketConnector :$ pip3 install -r requirements.txt
EDMarketConnector :$ python3 EDMarketConnector.py
</code></pre><p>Since the tool must be launched in a python environment, I created a shell launcher:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#776e71">#!/bin/bash
</span></span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ef6155">dir</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;~/Games/EDMarketConnector/&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>cd <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">dir</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>source venv/bin/activate
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>python3 EDMarketConnector.py
</span></span></code></pre></div><p>Then a desktop launcher that points to the shell script, while setting the icon with the icon of the tool at the root. (Choose “Files images”). <br>
<em>If the icon is not in the archive, you will find it in the repository</em>.</p>
<hr>
<ul>
<li>The functional plugins—which I use… :</li>
</ul>
<p>⇒ <strong>cargo-manifest</strong>: it seems necessary to change the name of the main directory; from <code>cargo-manifest</code> to <code>cargo_manifest</code>. <br>
With this slight modification, the plugin is functional!</p>
<p>⇒ <strong>docking-denied-raison</strong></p>
<p>⇒ <strong>EDMC-Bioscan</strong> requires ExploData which requires <code>sqlalchemy</code>.</p>
<ul>
<li>If you are using the flatpak version of EDMC, download the named version <code>ExploData-***-db-***-flatpak.zip</code>; Because it embarks sqlalchemy.</li>
<li>If you are using the sources, you will need to install <code>python3-slqalchemy</code> in the dedicated python3 environment!</li>
</ul>
<p>⇒ <strong>EDMCHotKeys</strong></p>
<p>⇒ <strong>EDMCModerOverlay</strong></p>
<p>⇒ <strong>EDMC-NavRoute</strong></p>
<p>⇒ <strong>EDMC-NeutronDancer</strong></p>
<p>⇒ <strong>EDMC-Pioneer</strong></p>
<p>⇒ <strong>EDMC-Screenshot-Linux</strong></p>
<p>⇒ <strong>UpdateTD</strong></p>
<hr>
<p><em>Other plugins exist; they should work</em>…</p>
<h3 id="eddiscovery">EDDiscovery</h3>
<p><strong>EDDiscovery</strong> is a complete dashboard to manage all the aspects that the game offers.</p>
<ul>
<li>
<p>Git: <a href="https://github.com/EDDiscovery/EDDiscovery/" rel="external">https://github.com/EDDiscovery/EDDiscovery/</a></p>
</li>
<li>
<p>Used version: 19.1.9.0</p>
</li>
<li>
<p>Steam:</p>
<ul>
<li>forced compatibility option: Proton 9.0-4</li>
<li>launch option: none</li>
</ul>
</li>
</ul>
<hr>
<p>From the ‘<a href="https://github.com/EDDiscovery/EDDiscovery/releases" rel="external">Release</a>’ page of the repository, download the Portable zip archive; unzip it wherever you want.</p>
<p>In Steam:</p>
<ul>
<li>click on the “Games” menu &gt; “Add a game name Steam to my library…”, choose the binary <code>EDDiscovery.exe</code> which is in the decompressed archive.</li>
<li>right-click for the “game” properties, and force compatibility – <em>currently, I’m using the “Proton 9.0-4” version</em>.</li>
<li>right click again for the “Manage” menu &gt; “Create a shortcut on desktop”.</li>
</ul>
<p>All the remarks made in the <a href="/en/post/linux-elite-dangerous/#steam-desktop-shortcut">Steam desktop shortcut</a> chapter are to be made!</p>
<hr>
<p>Once EDD is opened, go to the “Settings” tab:</p>
<ul>
<li>In the “Settings” section, click the [ Add ] button, a new window will open called “CommanderForm”.
<ul>
<li>In the “Journal Related Information” section:
<ul>
<li>Write the name of your Commander, in the “Commander Name” field</li>
<li>click on the [ Browse ] button to select the game backup directory.</li>
<li>make any other desired configuration</li>
<li>click on the [ OK ] button to validate the configuration.</li>
<li>delete the profile named “Jameson (Default)”.</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>Return to the “History” tab, you will find the feedback related to the commander used in the game.</p>
<hr>
<p>To be able to set the icons, and the desktop launcher, and in the Steam app, you need to unzip the archive <code>eddwebsite.zip</code>, located at the root of the Portable archive. The image to be used mainly is in the subdirectory “Images” and is called “EdLogo600.png”.</p>
<hr>
<p><em>Note: Some plugins, such as those to display Inara, EDSM sites do not work because it lacks a tool called WebView2</em>.</p>
<h3 id="elite-dangerous-monitor-daemon">Elite Dangerous Monitor Daemon</h3>
<p><strong>Elite Dangerous Monitor Daemon</strong> alias <em>EDMD</em> is another complete dashboard to monitor in real time the game session, made for Linux natively (GTK4 interface).</p>
<ul>
<li>Git: <a href="https://github.com/Maldor/EDMD" rel="external">https://github.com/Maldor/EDMD</a></li>
</ul>
<p>Once installed :</p>
<ul>
<li>Configuration file: <code>$HOME/.config/EDMD/config.toml</code></li>
</ul>
<h3 id="ed-odyssey-materials-helper">ED Odyssey Materials Helper</h3>
<p><strong>Elite Dangerous Odyssey Materials Helper</strong> is the tool that revolutionizes the acquisition of the necessary materials in the relations with engineers. It shows you what you have, what you miss, the relationship with such an engineer, and much more…</p>
<ul>
<li>website: <a href="https://edomh.nl/" rel="external">https://edomh.nl/</a></li>
<li>Git: <a href="https://github.com/jixxed/ed-odyssey-materials-helper/" rel="external">https://github.com/jixxed/ed-odyssey-materials-helper/</a></li>
<li>Discord: <a href="https://discord.gg/M8Rgz4AmmA" rel="external">https://discord.gg/M8Rgz4AmmA</a></li>
<li>Used version: <del>3.13.8</del>, 3.13.12</li>
</ul>
<p>From the ‘<a href="https://github.com/jixxed/ed-odyssey-materials-helper/releases" rel="external">Release</a>’ page, download at least the zip archive, but prefers the autoupdater .deb, .rpm package.</p>
<hr>
<p>From the binary, everything is installed in the system where it is necessary and becomes accessible from the system menu; <em>under Xfce, menu “Other” &gt; “Elite Dangerous Odyssey Materials Helper”</em>.</p>
<p>Once the application is open:</p>
<ul>
<li>Click on the “Settings” menu</li>
<li>on “Folder Journal” line, click on the [ Select Directory ] button and choose the absolute path related to the game’s backup directory.</li>
</ul>
<p>Then, do all the other configurations, such as the language, and then use the tool.</p>
<h3 id="min-ed-launcher">Min ED Launcher</h3>
<p><strong>Min ED Launcher</strong> is not a tool. It replaces the official launcher, while being very light, which is convenient under Linux, and has other practical aspects, <em>including third-party tool execution, such as <a href="/en/post/linux-elite-dangerous/#srv-survey">SRVSurvey</a></em>.</p>
<ul>
<li>
<p>Git: <a href="https://github.com/Rfvgyhn/min-ed-launcher/" rel="external">https://github.com/Rfvgyhn/min-ed-launcher/</a></p>
</li>
<li>
<p>Used version: 0.13.0</p>
</li>
<li>
<p>Steam:</p>
<ul>
<li>forced compatibility option : none</li>
<li>launch option : yes; <em><strong>read the explanations below</strong></em>.</li>
</ul>
</li>
</ul>
<p>Once installed:</p>
<ul>
<li>Configuration file: <code>$HOME/.config/min-ed-launcher/settings.json</code></li>
<li>log: <code>$HOME/.local/state/min-ed-launcher/min-ed-launcher.log</code></li>
</ul>
<hr>
<p>From the ‘<a href="https://github.com/rfvgyhn/min-ed-launcher/releases" rel="external">Release</a>’ page, download the zip archive for Linux, and then unzip it.</p>
<ul>
<li>Copy the binary <code>MinEdLauncher</code> into the ED&rsquo;s installation folder.</li>
</ul>
<hr>
<p>⇒ In Steam:</p>
<ul>
<li>Right-click to open the game properties</li>
<li>in the launch options, write at least:
<ul>
<li>for Gnome—<em>run too into Xfce4!</em>:  <br>
<code>gnome-terminal -- ./MinEdLauncher %command% /autorun /autoquit</code>
<ul>
<li>what works for me: <br>
<code>gnome-terminal --hide-menubar -t &quot;Min ED Launcher&quot; -- ./MinEdLauncher %command% /autorun /autoquit waitForExit</code></li>
</ul>
</li>
<li>for Xfce4: <br>
<code>xfce4-terminal --disable-server -x ./MinEdLauncher %command% /autorun /autoquit waitForExit</code>
<ul>
<li>what I&rsquo;m using: <br>
<code>xfce4-terminal --disable-server --hide-menubar --hide-scrollbar --hide-toolbar -T &quot;Min ED Launcher&quot; -x ./MinEdLauncher %command% /autorun /autoquit waitForExit</code></li>
</ul>
</li>
</ul>
</li>
</ul>
<p>(<em>It is possible to use other terminals in the launch options; please read the information on the repository!</em>).</p>
<hr>
<p>⇒ The archive provided a desktop launcher and icon. It is possible to copy the desktop launcher to your desktop. Then right-click to change the command, such as: <br>
<code>/usr/games/steam steam://rungameid/359320 /edo</code> <br>
This will run the launch of the Odyssey version of the game directly.</p>
<p>⇒ All the remarks made in the <a href="/en/post/linux-elite-dangerous/#steam-desktop-shortcut">Steam desktop shortcut</a> chapter are to be made!</p>
<p>⇒ It is imperative that the launch options are written in the general properties of the game; cf above!</p>
<hr>
<p>Note:</p>
<ul>
<li>It is important that the two layers IPv4 AND IPv6 networks are functional, otherwise it will not work.</li>
</ul>
<h3 id="od-explorer">OD Explorer</h3>
<p><strong>OD Explorer</strong> is truly THE companion to Elite Dangerous, to help us in exploration and exobiology research.</p>
<p>Note: This tool is designed to work well with the English language of the game Elite Dangerous, in the other languages of the game, it will not be able to bring everything up properly. But if you understand the English language well enough: “go!”</p>
<ul>
<li>
<p>Git: <a href="https://github.com/WarmedxMints/OD-Explorer" rel="external">https://github.com/WarmedxMints/OD-Explorer</a></p>
</li>
<li>
<p>Used version: <del>2.0.14</del>, 2.0.15</p>
</li>
<li>
<p>Steam:</p>
<ul>
<li>forced compatibility option: Proton 9.0-4</li>
<li>launch options: none</li>
</ul>
</li>
</ul>
<p>The Logo is available from the repository in the subdirectory <code>Resources/</code> and is named <code>Astronaut.png</code>.</p>
<hr>
<p>From the ‘<a href="https://github.com/WarmedxMints/OD-Explorer/releases" rel="external">Release</a>’ page of the repository, download the <code>ODExplorer-Portable.zip</code> version.</p>
<p>Unwind it, for example, in such a way that you have it: <code>~/Games/ODExplorer-Portable</code></p>
<hr>
<p>Then you have to use the <code>protontricks</code> tool.</p>
<p>That being done, in Steam:</p>
<ul>
<li>Click on the “Games” menu &gt; “Add a game name Steam to my library…”.</li>
<li>right-click for the “game” properties, and force compatibility – <em>currently, I’m using the “Proton 9.0-4” version</em>.</li>
</ul>
<p>Click the [ Play ] button…</p>
<hr>
<p>At the first launch, a window will open asking for the installation of the “runtime v8.0” of Microsoft Windows. Close the windows by pressing the [ No ] button.</p>
<p>Next, open Protontricks and target “Non-Steam shortcut: ODExplorer.exe: …”. Choose to install a component, select <code>dotnetdesktop8</code>.</p>
<p>
    

            
                    
                    <figure role="figure">
    <a href="/images/post/elite-dangerous/protontricks-odexplorer-line.png">
        <picture>
                
                    
                    <source srcset="/images/post/elite-dangerous/protontricks-odexplorer-line_hu_b779dc657a4504d9.avif" type="image/avif">
                    
                    <source srcset="/images/post/elite-dangerous/protontricks-odexplorer-line_hu_570c924189cf8aed.webp" type="image/webp">
            <img loading="lazy"
                    alt="Protontricks - select Steam app; line ‘ODExplorer.exe: …’"
                    height="200"
                    id="img_images_post_elite-dangerous_protontricks-odexplorer-line.png_0"
                    src="/images/post/elite-dangerous/protontricks-odexplorer-line.png"
                    width="300">
        </picture>
    </a>
</figure></p>
<p>
    

            
                    
                    <figure role="figure">
    <a href="/images/post/elite-dangerous/winetricks-wineprefix-install-component.png">
        <picture>
                
                    
                    <source srcset="/images/post/elite-dangerous/winetricks-wineprefix-install-component_hu_50b7b595ff9e578b.avif" type="image/avif">
                    
                    <source srcset="/images/post/elite-dangerous/winetricks-wineprefix-install-component_hu_dafe7b8ead8209b6.webp" type="image/webp">
            <img loading="lazy"
                    alt="Winetricks - wineprefix; install component"
                    height="147"
                    id="img_images_post_elite-dangerous_winetricks-wineprefix-install-component.png_1"
                    src="/images/post/elite-dangerous/winetricks-wineprefix-install-component.png"
                    width="300">
        </picture>
    </a>
</figure></p>
<p>
    

            
                    
                    <figure role="figure">
    <a href="/images/post/elite-dangerous/winetricks-package-dotnetdesktop8.png">
        <picture>
                
                    
                    <source srcset="/images/post/elite-dangerous/winetricks-package-dotnetdesktop8_hu_7efb317f3429eaeb.avif" type="image/avif">
                    
                    <source srcset="/images/post/elite-dangerous/winetricks-package-dotnetdesktop8_hu_ecb7e6a984cc476c.webp" type="image/webp">
            <img loading="lazy"
                    alt="Winetricks - wineprefix; choose dotnetdesktop8"
                    height="147"
                    id="img_images_post_elite-dangerous_winetricks-package-dotnetdesktop8.png_2"
                    src="/images/post/elite-dangerous/winetricks-package-dotnetdesktop8.png"
                    width="300">
        </picture>
    </a>
</figure></p>
<p>Once the installation is complete, before running the binary from Steam again, right-click again and choose the “Manage” &gt; “Create a shortcut on desktop” menu.</p>
<p>The remarks made for the game’s <a href="/en/post/linux-elite-dangerous/#steam-desktop-shortcut">Steam desktop shortcut</a> are exactly the same for this shortcut; so make the same changes.</p>
<hr>
<p><em>PS: Although we have mono installable under Linux, the use of mono <code>ODExplorer.exe</code> does not work</em>.</p>
<h3 id="srv-survey">SRV Survey</h3>
<p><strong>SRV Survey</strong> is a useful support companion by displaying data on the game screen, during a game session; it is useful for organic scans during exploration, to track the player’s position, and useful on the sites of the “Guardians”.</p>
<ul>
<li>Git: <a href="https://github.com/njthomson/SrvSurvey" rel="external">https://github.com/njthomson/SrvSurvey</a></li>
<li>Used version: 2.0.95.23</li>
</ul>
<hr>
<p>Here is the procedure to operate this tool:</p>
<ul>
<li><a href="/en/post/linux-elite-dangerous/#min-ed-launcher"><strong>Min ED Launcher</strong></a> is required</li>
<li>then the installation of SRV Survey, and a complementary script</li>
<li>Then the use of <code>protontricks</code>.</li>
</ul>
<p>⇒ 1. Download the zip archive from the “<a href="https://github.com/njthomson/SrvSurvey/releases" rel="external">Releases</a>” page, <em>currently version 2.0.95.23</em>.</p>
<ul>
<li>Uncompress the archive</li>
<li>Go to the “Application Files” directory</li>
<li>Copy the directory named <strong>SrvSurvey_number-version</strong> to the ED game installation directory</li>
<li>Rename the directory in <code>SrvSurvey</code>.</li>
<li>Download the shell script <a href="https://github.com/user-attachments/files/23442962/SRV_Survey.sh" rel="external">SRV_Survey.sh</a>, provided by Maldor, the author of <a href="/en/post/linux-elite-dangerous/#edmd">EDMD</a>.</li>
<li>Edit the <code>SRV_Survey.sh</code> shell script and copy to the “SrvSurvey” directory, <em>previously copied, renamed to the installation directory of the game</em>.</li>
</ul>
<p>⇒ Concern <strong>Min ED Launcher</strong>: whatever your configuration, you must add a process declaration; change the key <code>processes</code> to a similar statement:</p>
<pre tabindex="0"><code>    &#34;processes&#34;: [
        { &#34;fileName&#34;: &#34;/home/userid/.local/share/steam/steamapps/common/Elite Dangerous/SrvSurvey/SRV_Survey.sh&#34; }
    ],
</code></pre><p><em><strong>Change litteraly &ldquo;<code>/home/userid</code>&rdquo; by your!</strong></em></p>
<p>⇒ <strong>SRV Survey</strong> requires the to be installed to work. This is where the use of the <code>protontricks</code> tool comes in:</p>
<ul>
<li>
<p>once protontricks is executed:</p>
</li>
<li>
<p>select the line corresponding to the game “Elite Dangerous : 359320”, then click on the [ Validate ] button.

    

            
                    
                    <figure role="figure">
    <a href="/images/post/elite-dangerous/protontricks-elite-dangerous-line.png">
        <picture>
                
                    
                    <source srcset="/images/post/elite-dangerous/protontricks-elite-dangerous-line_hu_fe8028f5e87282b5.avif" type="image/avif">
                    
                    <source srcset="/images/post/elite-dangerous/protontricks-elite-dangerous-line_hu_bcddff3cea275678.webp" type="image/webp">
            <img loading="lazy"
                    alt="Protontricks - select Steam app; ‘Elite Dangerous: 359320’ line"
                    height="200"
                    id="img_images_post_elite-dangerous_protontricks-elite-dangerous-line.png_3"
                    src="/images/post/elite-dangerous/protontricks-elite-dangerous-line.png"
                    width="300">
        </picture>
    </a>
</figure></p>
</li>
<li>
<p>different windows of error messages related to winetricks appear, click [ Validate ].</p>
</li>
<li>
<p>the “Winetricks - choose a wineprefix” window ends up appearing: select, <em>if not the case</em>, the choice “( ) Select the default wineprefix” and then click on the [ Validate ] button.

    

            
                    
                    <figure role="figure">
    <a href="/images/post/elite-dangerous/winetricks-choose-a-wineprefix.png">
        <picture>
                
                    
                    <source srcset="/images/post/elite-dangerous/winetricks-choose-a-wineprefix_hu_18e4a6fe9ada839c.avif" type="image/avif">
                    
                    <source srcset="/images/post/elite-dangerous/winetricks-choose-a-wineprefix_hu_e9155a2c43739cf0.webp" type="image/webp">
            <img loading="lazy"
                    alt="Winetricks - choose a prefix; select default"
                    height="148"
                    id="img_images_post_elite-dangerous_winetricks-choose-a-wineprefix.png_4"
                    src="/images/post/elite-dangerous/winetricks-choose-a-wineprefix.png"
                    width="300">
        </picture>
    </a>
</figure></p>
</li>
<li>
<p>the “Winetricks - current prefix” window opens, choose “( ) Install a Windows DLL or component”, and then click the [ Validate ] button.

    

            
                    
                    <figure role="figure">
    <a href="/images/post/elite-dangerous/winetricks-current-prefix-install-component.png">
        <picture>
                
                    
                    <source srcset="/images/post/elite-dangerous/winetricks-current-prefix-install-component_hu_aea1df8afbdd035c.avif" type="image/avif">
                    
                    <source srcset="/images/post/elite-dangerous/winetricks-current-prefix-install-component_hu_cbba97991fa98119.webp" type="image/webp">
            <img loading="lazy"
                    alt="Winetricks - current prefix; install DLL or component"
                    height="147"
                    id="img_images_post_elite-dangerous_winetricks-current-prefix-install-component.png_5"
                    src="/images/post/elite-dangerous/winetricks-current-prefix-install-component.png"
                    width="300">
        </picture>
    </a>
</figure></p>
</li>
<li>
<p>a new window “Winetricks - current prefix” opens and asks which package is to be installed; scroll until you find the choice “[ ] dotnetdesktop9 MS . NET Desktop Runtime 9.0 LTS”, then click the [ Validate ] button.

    

            
                    
                    <figure role="figure">
    <a href="/images/post/elite-dangerous/winetricks-current-prefix-which-package.png">
        <picture>
                
                    
                    <source srcset="/images/post/elite-dangerous/winetricks-current-prefix-which-package_hu_d2a939ab6cbdf6.avif" type="image/avif">
                    
                    <source srcset="/images/post/elite-dangerous/winetricks-current-prefix-which-package_hu_3de2ee4286015ba1.webp" type="image/webp">
            <img loading="lazy"
                    alt="Winetricks - current prefix; choose dotnetdesktop9"
                    height="145"
                    id="img_images_post_elite-dangerous_winetricks-current-prefix-which-package.png_6"
                    src="/images/post/elite-dangerous/winetricks-current-prefix-which-package.png"
                    width="300">
        </picture>
    </a>
</figure></p>
</li>
<li>
<p>Once installed, click the [ Cancel ] buttons until the protontricks tool closes.</p>
</li>
</ul>
<hr>
<p>⇒ <em>If SRV_Survey does not really launch, even Min Ed Launcher indicates that it&rsquo;s, please read this section</em>: <a href="/en/post/linux-elite-dangerous/#proton-version">Proton version</a>!</p>
<p>With all these changes, <strong>SRV Survey</strong> should finally work!</p>
<p>Keep in mind that some features could crash the software. If so, close the game, and restart it so that <strong>Min ED Launcher</strong> will open both apps again.</p>
<hr>
<p>Acknowledgements:</p>
<ul>
<li><a href="https://github.com/njthomson/SrvSurvey/discussions/524" rel="external">https://github.com/njthomson/SrvSurvey/discussions/524</a></li>
</ul>
<h3 id="squadron-manager">Squadron Manager</h3>
<p><strong>Squadron Manager</strong> is a tool to manage or participate one squadron. Yes, it&rsquo;s possible to run this Windows app under Linux, by using protontricks and Steam.</p>
<p>You need to register first on website!</p>
<ul>
<li>
<p>Repository: <a href="https://github.com/SquadronManager/App/" rel="external">https://github.com/SquadronManager/App/</a></p>
</li>
<li>
<p>Logo: <a href="https://squadronmanager.comtac-fr.space/logos/logo2.png" rel="external">https://squadronmanager.comtac-fr.space/logos/logo2.png</a></p>
</li>
<li>
<p>Website: <a href="https://squadronmanager.comtac-fr.space/" rel="external">https://squadronmanager.comtac-fr.space/</a></p>
</li>
<li>
<p>Used version: 3.5.6</p>
</li>
<li>
<p>Steam:</p>
<ul>
<li>forced compatibility option: Proton 9.0-4</li>
<li>launch option: none</li>
</ul>
</li>
</ul>
<hr>
<p>After download the exceutable Setup, clic-right to launch with  <strong>protontricks</strong>.</p>
<ul>
<li>Select the wineprefix for Elite Dangerous line, and finish normally the installation.</li>
</ul>
<p>The install folder is: <br>
<code>steamapps/compatdata/359320/pfx/drive_c/users/steamuser/AppData/Local/Programs/Squadron Manager/</code></p>
<p>⇒ Once the installation is complete, before running the binary from Steam again, right-click again and choose the “Manage” &gt; “Create a shortcut on desktop” menu.</p>
<p>The remarks made for the game’s <a href="/en/post/linux-elite-dangerous/#steam-desktop-shortcut">Steam desktop shortcut</a> are exactly the same for this shortcut; so make the same changes. Use the website logo for the launcher icon, available on URL belowe.</p>
<hr>
<p>A <a href="/en/post/linux-elite-dangerous/#edmarketconnector">EDMC</a> plugin, named <strong>Michelle</strong>, is needed to communicate correctly between EDMC and Squadron Manager.</p>
<ul>
<li>Repository: <a href="https://github.com/taloche1/Michelle/" rel="external">https://github.com/taloche1/Michelle/</a></li>
<li>Used version: 3.86</li>
</ul>
<p>to install into the EDMC&rsquo;s <code>plugins</code> folder.</p>
<h3 id="elite-intel">Elite Intel</h3>
<p><strong>Elite Intel</strong> is an AI voice assistant for Elite Dangerous, using NVIDIA Parakeet, and working either local LLM or cloud.</p>
<ul>
<li>
<p>version: 1.0</p>
</li>
<li>
<p>GPU specs min.: 12 Go VRAM</p>
</li>
<li>
<p>website: <a href="https://www.elite-intel.org/index.html" rel="external">https://www.elite-intel.org/index.html</a></p>
</li>
<li>
<p>Repository: <a href="https://github.com/SudoKrondor/EliteIntel" rel="external">https://github.com/SudoKrondor/EliteIntel</a></p>
</li>
</ul>
<h2 id="troubleshooting">Troubleshooting</h2>
<h3 id="proton-version">Proton version</h3>
<p>⇒ A note regarding SRV_Survey and the version of Proton:</p>
<p><strong>SRV_Survey must run on the same version of Proton as ED!</strong></p>
<ul>
<li>SRV_Survey.sh <em>modified</em>:</li>
</ul>
<pre tabindex="0"><code>#!/usr/bin/env bash
PROTON_Version=&#34;Proton 9.0 (Beta)&#34;
sleep 10s
export STEAM_COMPAT_DATA_PATH=&#34;$HOME/.steam/steam/steamapps/compatdata/359320&#34;
export STEAM_COMPAT_CLIENT_INSTALL_PATH=&#34;$HOME/.steam/steam&#34;
 &#34;$HOME/.steam/steam/steamapps/common/${PROTON_Version}/proton&#34; run $HOME/steam/steamapps/common/Elite Dangerous/SrvSurvey/SRV_survey/SrvSurvey.exe
</code></pre><hr>
<p>The <strong>Min ED Launcher log</strong> informs from the beginning which arguments it calls, such as:</p>
<pre tabindex="0"><code>----------
2026-06-21 11:38:57.294 +02:00 [INF] Elite Dangerous: Minimal Launcher - v0.13.0+6e50d0e0
2026-06-21 11:38:57.385 +02:00 [DBG]
    Args: [|&#34;/home/myusername/.steam/debian-installation/ubuntu12_32/steam-launch-wrapper&#34;; &#34;--&#34;;
  &#34;/home/myusername/.steam/debian-installation/ubuntu12_32/reaper&#34;; &#34;SteamLaunch&#34;;
  &#34;AppId=359320&#34;; &#34;--&#34;;
  &#34;/home/myusername/.steam/debian-installation/steamapps/common/SteamLinuxRuntime_sniper/_v2-entry-point&#34;;
  &#34;--verb=waitforexitandrun&#34;; &#34;--&#34;;
  &#34;/home/myusername/Games/Steam/steamapps/common/Proton 9.0 (Beta)/proton&#34;;
  &#34;waitforexitandrun&#34;;
  &#34;/run/media/myusername/games/SteamLibrary/steamapps/common/Elite Dangerous/EDLaunch.exe&#34;;
  &#34;/Steam&#34;; &#34;/novr&#34;; &#34;/autorun&#34;; &#34;/autoquit&#34;; &#34;waitForExit&#34;|]
    OS: Linux64
    Env: STEAM_COMPAT_DATA_PATH=/run/media/myusername/games/SteamLibrary/steamapps/compatdata/359320

(…)
</code></pre><p>cf the sixth line… <code>&quot;/home/myusername/Games/Steam/steamapps/common/Proton 9.0 (Beta)/proton&quot;;</code> ;-)</p>
<p>Because ED is launch with this Proton version!</p>
<h3 id="no-such-file-or-directory">No such file or directory</h3>
<p>⇒ A mention about using SRV_Survey with Min Ed Launcher:</p>
<ul>
<li>If you see on Min Ed Launcher logfile, similar statements:</li>
</ul>
<blockquote>
<p>2026-08-01 21:07:05.623 -05:00 [INF] Starting process $HOME/.steam/steam/steamapps/common/Elite Dangerous/SrvSurvey/SRV_Survey.sh
2026-08-01 21:07:05.629 -05:00 [FTL] Unable to start process $HOME/.steam/steam/steamapps/common/Elite Dangerous/SrvSurvey/SRV_Survey.sh
HRESULT: 0x80004005
Win32 Error Code: 2</p>
<p>System.ComponentModel.Win32Exception (2): ErrorStartingProcess, $HOME/.steam/steam/steamapps/common/Elite Dangerous/SrvSurvey/SRV_Survey.sh, $HOME/.steam/steam/steamapps/common/Elite Dangerous/SrvSurvey, No such file or directory</p>
</blockquote>
<p><strong>Modify into the Min Ed Launcher&rsquo;s JSON file yours writing</strong>; you use <code>$HOME</code> instead of writing litteraly your home user, like: <code>/home/michael</code>!</p>
<p><code>$HOME</code> is only a shell variable; JSON can’t use it because he doesn’t know what to do with it!</p>
<hr>
<h2 id="eof">EOF</h2>
<p>Here you go!</p>
<p>“<em>Fly safe, or fly trouble… it’s up to you! or not…”</em> o7</p>
]]></content><summary>Installation and configuration of additional tools to play Elite Dangerous (Steam) on Linux</summary><published>2026-06-13T02:16:42+02:00</published><updated>2026-10-02T15:49:57+02:00</updated></entry><entry><id>tag:doc.huc.fr.eu.org,2026-06-22:/en/post/linux-forza-horizon/#816b6fcc62fd175fe64083e81757575fb952b696b37c93a8e7310cda46392ba8</id><link href="https://it-log.fr.eu.org/en/post/linux-forza-horizon/" rel="alternate" type="text/html"/><title>(Linux) Forza Horizon: troubleshooting</title><author><name>Stéphane HUC</name></author><category term="Games" scheme="https://it-log.fr.eu.org/en/tags/games/"/><category term="Steam" scheme="https://it-log.fr.eu.org/en/tags/steam/"/><category term="Linux" scheme="https://it-log.fr.eu.org/en/tags/linux/"/><content type="html"><![CDATA[<h2 id="description">Description</h2>
<ul>
<li>Environment : Steam Linux / Debian Sid</li>
<li>Game : Forza Horizon 5</li>
</ul>
<hr>
<p>NO! this little article is not to promote or learn to play any of the Forza Horizon.</p>
<h2 id="troubleshooting">Troubleshooting</h2>
<h3 id="connection">Connection</h3>
<p>When opening the game, a window prevents you from playing by stating that a mandatory connection is required.</p>
<pre tabindex="0"><code>Mandatory Connexion

You cannot continue without being logged in to a profile.

[ OK ]
</code></pre><ul>
<li>
<p>Stop the game</p>
</li>
<li>
<p>Go to the game installation folder, accessible from the ‘Properties…’ menu, then go to the ‘Installed Files’ menu and click the [ Browse… ] button to open the file browser to the game installation folder.</p>
<ul>
<li>Head to <code>SteamLibrary/steamapps/compatdata/1551360/pfx/</code>. <em>You have to go back two files to get to the file <code>steamapps</code> from the installation directory of the game</em>.</li>
</ul>
</li>
<li>
<p>Open the file <code>user.reg</code>.</p>
</li>
<li>
<p>Search the key <code>Xbl|DeviceKey</code>; which should be around line 2040.</p>
</li>
<li>
<p>Delete the entire block corresponding to the equivalent of the following:</p>
</li>
</ul>
<pre tabindex="0"><code>[Software\\Wine\\Credential Manager\\Generic: Xbl|DeviceKey] 1781126654
#time=1dcf91f7c643250
@=&#34;Xbl|DeviceKey&#34;
&#34;Comment&#34;=&#34;{3F754FAD-C788-48B1-A0F4-0F6279924F2A}|00000000|1&#34;
&#34;Flags&#34;=dword:00000000
&#34;LastWritten&#34;=hex:eb,2e,64,7c,1f,f9,dc,01
&#34;Password&#34;=hex:(…)
&#34;Persist&#34;=dword:00000002
&#34;Type&#34;=dword:00000001
</code></pre><ul>
<li>
<p>Save</p>
</li>
<li>
<p>Relaunching the game; normally the Microsoft login window must open and allow the connection (<em>often by already having the user name filled</em>). <br>
Once validated, the game will open.</p>
</li>
</ul>
<hr>
]]></content><summary>tips for how the game Forza Horizon works (5) on Linux</summary><published>2026-06-10T23:34:26+02:00</published><updated>2026-10-02T15:49:57+02:00</updated></entry><entry><id>tag:doc.huc.fr.eu.org,2026-06-08:/en/post/gmail-detect-error/#466b7cf62c85ee2e89d2b8149d41ff519a2d480ac6790febfc7ef96ee20ffa62</id><link href="https://it-log.fr.eu.org/en/post/gmail-detect-error/" rel="alternate" type="text/html"/><title>Gmail Detect Error 550-5.7.1 (gsmtp)</title><author><name>Stéphane HUC</name></author><category term="gmail" scheme="https://it-log.fr.eu.org/en/tags/gmail/"/><category term="error" scheme="https://it-log.fr.eu.org/en/tags/error/"/><content type="html"><![CDATA[<h2 id="merciless">Merciless</h2>
<p>“Communication” with Gmail services seems anything but a model of good communication!</p>
<p>In the serie &ldquo;Gmail, your ruthless world…&rdquo;:</p>
<h2 id="description">Description</h2>
<p>Personally, I own two domain names—one free and one yearly paid.
I manage my DNS zones (on OpenBSD, using <code>nsd</code>); and the MX servers are managed by a friend (on OpenBSD, too, using OpenSMTPD).</p>
<p>DNS zones for both domains contains DKIM, DMARC, and SPF records, such as:</p>
<pre tabindex="0"><code>$ grep -E &#39;dkim|dmarc|spf&#39; /etc/ns/huc.fr.eu.org
dkimpubkey._domainkey    IN TXT    ( &#34;v=DKIM1; k=rsa; t=s; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8zDa4/c/HZYbd2NwouHXwgWoUVtRnmc89gjH4xYfVICd8n74Ojr7UVHSz80xiqsQEzEq+UM0FLPqt6IMgCb3&#34; &#34;1zZIF2CJqIa1U2esJi50+Kl50aho3e9bOL76uXMiY0VinrjeWbRU1gQ/ZEhYJdMeQZj60CULXXphVeBqOItNXoXGlJ/lBZZZHZ1Fv/PB8aLwU3fG1CsL9xiY9/PGclhOubwXUUbSgrKJQFAawvgpYp6DZIoZnbDun/uJCwR/1Q+jXGJ56ps45XGeRfZbx17B&#34; &#34;X9ldnQ3iliKpWl9jLSWJ/mR/GdqGIuYeLuzZW7CxrNjd+TGEg9j0Poqf+MGzRpwLOwIDAQAB&#34;)
_dmarc IN TXT &#34;v=DMARC1; p=reject; sp=reject;&#34;
@       IN TXT  &#34;v=spf1 a mx ~all&#34;

$ grep -E &#39;dkim|dmarc|spf&#39; /etc/ns/stephane-huc.net
dkimpubkey._domainkey    IN TXT    ( &#34;v=DKIM1; k=rsa; t=s; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8zDa4/c/HZYbd2NwouHXwgWoUVtRnmc89gjH4xYfVICd8n74Ojr7UVHSz80xiqsQEzEq+UM0FLPqt6IMgCb3&#34; &#34;1zZIF2CJqIa1U2esJi50+Kl50aho3e9bOL76uXMiY0VinrjeWbRU1gQ/ZEhYJdMeQZj60CULXXphVeBqOItNXoXGlJ/lBZZZHZ1Fv/PB8aLwU3fG1CsL9xiY9/PGclhOubwXUUbSgrKJQFAawvgpYp6DZIoZnbDun/uJCwR/1Q+jXGJ56ps45XGeRfZbx17B&#34; &#34;X9ldnQ3iliKpWl9jLSWJ/mR/GdqGIuYeLuzZW7CxrNjd+TGEg9j0Poqf+MGzRpwLOwIDAQAB&#34;)
_dmarc IN TXT &#34;v=DMARC1; p=reject; sp=reject;&#34;
@       IN TXT  &#34;v=spf1 a mx ~all&#34;
</code></pre><p>Actually, the mail-tester.com website shows a &ldquo;Perfect&rdquo; rating. Regarding:</p>
<ul>
<li>an email sent from my <code>huc.fr.eu.org</code> domain: <a href="https://mail-tester.com/test-loynfonhr" rel="external">https://mail-tester.com/test-loynfonhr</a></li>
<li>an email sent from my <code>stephane-huc.net</code> domain: <a href="https://mail-tester.com/test-7b231r0vz" rel="external">https://mail-tester.com/test-7b231r0vz</a></li>
</ul>
<p>Honestly, it&rsquo;s hard to do better—not impossible, but…</p>
<hr>
<p>Running DNS queries to check if the PTR record is valid returns the correct results:</p>
<pre tabindex="0"><code>:$ dig mx.huc.fr.eu.org +short
89.234.141.148
:$ dig mx.huc.fr.eu.org AAAA +short
2a00:5881:8110:1e00::2

:$ dig -x 89.234.141.148 +short
mx.vinishor.xyz.
:$ dig -x 2a00:5881:8110:1e00::2 +short
mx.vinishor.xyz.
</code></pre><p>Same result for the other domain.</p>
<hr>
<p>I mainly use these email accounts for receiving messages; on average, I send one or two emails, and in rare cases, about ten; and I have NEVER engaged in mass emailing or any similar automated process.</p>
<p>However: as soon as I send an email to a Gmail address from an email address associated with the <code>huc…</code> domain, it’s guaranteed to be rejected and the email blocked!</p>
<pre tabindex="0"><code>Hi! This is the MAILER-DAEMON, please DO NOT REPLY to this email. An error has occurred while attempting to deliver a message for the following list of recipients: stephane.huc@gmail.com: 550-5.7.1 [89.234.141.148 12] Gmail has detected that this message is likely unsolicited mail. To reduce the amount of spam sent to Gmail, this message has been blocked. For more information, go to https://support.google.com/mail/?p=UnsolicitedMessage
Error ffacd0b85a97d-4601f38a6f1si30466498f8f.340 - gsmtp Below is a copy of the original message:

Reporting-MTA: dns; mx.vinishor.xyz
 Final-Recipient: rfc822; stephane.huc@gmail.com
Action: failed
Status: 5.0.0
</code></pre><p>There was a time when messages ended up in the spam folder, but now they don&rsquo;t even do that anymore. It&rsquo;s a &ldquo;flat-out&rdquo; rejection, simply because they&rsquo;re “unsolicited.” But what gives them the right?!</p>
<hr>
<p>As you can see, I also have a Gmail account.</p>
<p>In short, it seems to me that there’s no way to communicate with users who have Gmail addresses.</p>
<h2 id="ehlo">Ehlo</h2>
<p>⇒ It&rsquo;s impossible to speak with an actual professional on the team, even if you&rsquo;re willing to pay for the service. Why not try contacting them through the support site?</p>
<p>They just pass the buck to the community.</p>
<p>⇒ When you try to describe the issue on the Google Support website, the submission is automatically rejected, with the following message displayed in red: &lsquo;Failed to post. The content violates the <a href="https://support.google.com/communities/answer/7425194" rel="external">Community Guidelines</a>.&rsquo;</p>
<p>The content I tried to post via the support website is exactly what is written here, in the <a href="/en/post/gmail-detect-error/#description">description</a> section, word for word, but in French. What in that content could possibly violate the rules?!</p>
<p>Gmail, Helo? <br>
In short, it&rsquo;s a hopeless technical situation…</p>
<hr>
]]></content><summary>Help, about Gmail (gsmtp) service! Your email support and response are unbearable… You're not playing the rules, even though DKIM, DMARC, SPF, and PTR records are all correct!</summary><published>2026-06-08T13:38:29+02:00</published><updated>2026-10-02T15:49:57+02:00</updated></entry><entry><id>tag:doc.huc.fr.eu.org,2026-05-04:/en/web/hugo/week-number/#ba4e036770af61d17af4a01853f81171f420b17982ef710ff05cf282525ab174</id><link href="https://it-log.fr.eu.org/en/web/hugo/week_number/" rel="alternate" type="text/html"/><title>Hugo: Get the week number of the year (tips)</title><author><name>Stéphane HUC</name></author><category term="Hugo" scheme="https://it-log.fr.eu.org/en/tags/hugo/"/><category term="Time" scheme="https://it-log.fr.eu.org/en/tags/time/"/><category term="tips" scheme="https://it-log.fr.eu.org/en/tags/tips/"/><content type="html"><![CDATA[<h2 id="description">Description</h2>
<p>Actually, Hugo (the SSG) is not capable to get a week number! <br>
It&rsquo;s ‘under consideration’!</p>
<p>However, Go language provides the <a href="https://pkg.go.dev/time#Time.ISOWeek" rel="external">IsoWeek()</a>
method.</p>
<p>Find the week number serves a purpose, whilst uncommon, is certainly useful. <br>
As instance, a weekly newsletter :)</p>
<p>I&rsquo;m going to show you two differents functions:</p>
<ul>
<li>by <a href="/en/web/hugo/week_number/#getisoweek"><code>getIsoWeek</code></a></li>
<li>or with <a href="/en/web/hugo/week_number/#getweeknumber"><code>getWeekNumber</code></a></li>
</ul>
<h2 id="getisoweek">getisoweek</h2>
<p>First, create a partial template: <code>/func/getIsoWeek</code>:</p>
<pre tabindex="0"><code class="language-hugo" data-lang="hugo">{{- $date := time.AsTime . -}}
{{- $weekday := $date.Weekday }}
{{/* 1. Normalize Weekday (Mon=1 ... Sun=7) */}}
{{- $isoDay := cond (eq $weekday 0) 7 (int $weekday) -}}
{{/* 2. Find Thursday (ISO Week belongs to the year of its Thursday) */}}
{{- $offset := sub 4 $isoDay -}}
{{- $thursday := $date.AddDate 0 0 $offset -}}
{{/* 3. Calculate Week Number */}}
{{- $isoYear := $thursday.Year -}}
{{- $isoWeek := add (div (sub $thursday.YearDay 1) 7) 1 -}}
{{/* 4. Return the data */}}
{{- $str := dict &#34;week&#34; (printf &#34;%02d&#34; $isoWeek) &#34;year&#34; (printf &#34;%04d&#34; $isoYear) -}}
{{- $data := dict &#34;week&#34; $isoWeek &#34;year&#34; $isoYear &#34;str&#34; $str -}}
{{- return $data -}}
</code></pre><p>The call:</p>
<pre tabindex="0"><code class="language-hugo" data-lang="hugo">{{- partial &#34;func/getisoweek&#34; .Date -}}
</code></pre><p>Or any other varible using Time, such as <code>now</code>.</p>
<p>⇒ Remark about <code>getIsoWeek</code> :</p>
<ul>
<li>if I want values as <code>int</code>, I call <code>$data.week</code> and <code>$data.year</code></li>
<li>if I want values as <code>str</code>, I call <code>$data.str.week</code> and <code>$data.str.year</code></li>
</ul>
<hr>
<p>Personnaly, I&rsquo;ve too created another partial template, called <code>utils/formatIsoDate</code>.</p>
<p>The code as follows:</p>
<pre tabindex="0"><code class="language-hugo" data-lang="hugo">{{- $data := partial &#34;func/getIsoWeek&#34; . -}}
{{- $s := printf &#34;w%s-y%s&#34; $data.str.week $data.str.year -}}
{{- return $s -}}
</code></pre><hr>
<p>I can call it either from the <code>default</code> archetypes, or anywhere into the templates or shortcodes, as I wish, such as: <br>
<code>{{ partial &quot;utils/formatIsoDate&quot; .Date }}</code> ou <code>{{ partial &quot;utils/formatIsoDate&quot; now }}</code>.</p>
<h2 id="getweeknumber">getweeknumber</h2>
<p>This second method for finding the week number is a little trickier!</p>
<p>This time, I have two main files.</p>
<p>⇒ The first function, <code>func/splitNameYMO</code>, is designed to “break down” a standardized date (<code>YYYY-MM-DD</code>) into the corresponding day, month, and year, and return a dictionary.</p>
<pre tabindex="0"><code class="language-hugo" data-lang="hugo">{{- $str := split . &#34;-&#34; -}}
{{- $d = (int (index $str 2)) -}}
{{- $m = (int (index $str 1)) -}}
{{- $y = (int (index $str 0)) -}}
{{- return (dict &#34;day&#34; $d &#34;month&#34; $m &#34;year&#34; $y) -}}
</code></pre><p><em>I created this file because I use it frequently throughout my code…</em></p>
<p>⇒ The second file is the main function, named <code>func/getWeekNumber</code></p>
<pre tabindex="0"><code class="language-hugo" data-lang="hugo">{{- $date := &#34;&#34; -}}
{{- $tz := site.Params.timeZone -}}
{{- $week := 0 -}}

{{ $type := printf &#34;%T&#34; . }}

{{ if eq $type &#34;string&#34; }}

    {{- $data := partial &#34;func/splitNameYMO&#34; . }}
    {{- $date = time (printf &#34;%04d-%02d-%02d&#34; $data.year $data.month $data.day) $tz -}}

{{ else }}

    {{- $date = time . $tz -}}

{{- end -}}

{{/* Calcul &#39;doy: day of the year&#39;, &#39;dow: day of the week&#39; */}}
{{- $doy := $date.YearDay -}}
{{- $dow := int $date.Weekday -}}
{{- $year := $date.Year -}}

{{/* calcul week number */}}
{{- $week = div (add (sub $doy $dow) 10) 7 -}}
{{- if eq $dow 0 -}}
    {{- $week = sub $week 1 -}}
{{- end -}}

{{- $str := dict &#34;week&#34; (printf &#34;%02d&#34; $week) &#34;year&#34; (printf &#34;%04d&#34; $year) -}}
{{- $data := dict &#34;week&#34; $week &#34;year&#34; $year &#34;str&#34; $str -}}
{{- return $data -}}
</code></pre><p>Explanations:</p>
<ul>
<li>
<p>First, I need to determine the type of the value I&rsquo;m injecting into the file call — whether it’s a <code>string</code> or something else, in this case a timestamp — <em>keep in mind that Hugo doesn’t know how to declare a value type for a timestamp, but in the repository, it is defined as <code>Time.time</code></em>.</p>
</li>
<li>
<p>Next, I determine which day of the year the date (<code>$doy</code>) corresponds to, which day of the week it falls on (<code>$dow</code>), and finally the year, of course.</p>
</li>
<li>
<p>Calcul of the week number is <a href="https://en.wikipedia.org/wiki/ISO_week_date#Calculating_the_week_number_from_an_ordinal_date" rel="external">known</a>:</p>
<ul>
<li>subtract the day of the week from the day of the year</li>
<li>add <code>10</code></li>
<li>and divide the result by <code>7</code></li>
<li>and finally, if the day of the week is a Sunday, I subtract <code>1</code> from the week number found — <em>this applies to Hugo, where weeks start on Sunday</em></li>
</ul>
</li>
</ul>
<hr>
<p>Voila!</p>
<h2 id="documentation">Documentation</h2>
<ul>
<li><a href="https://gohugo.io/quick-reference/methods/#time" rel="external">https://gohugo.io/quick-reference/methods/#time</a></li>
</ul>
<h2 id="acknowledgements">Acknowledgements</h2>
<ul>
<li><a href="https://discourse.gohugo.io/t/group-content-by-week-number-of-year/11894/6" rel="external">https://discourse.gohugo.io/t/group-content-by-week-number-of-year/11894/6</a></li>
</ul>
]]></content><summary>Hugo: Get a week number since Date!</summary><published>2026-05-04T13:06:25+02:00</published><updated>2026-10-02T15:49:57+02:00</updated></entry><entry><id>tag:doc.huc.fr.eu.org,2026-03-18:/en/post/bat-cat</id><link href="https://it-log.fr.eu.org/en/post/bat-cat/" rel="alternate" type="text/html"/><title>BAT: a 'cat killer'… with wings, for color and syntax highligthing!</title><author><name>Stéphane HUC</name></author><category term="Sys" scheme="https://it-log.fr.eu.org/en/tags/sys/"/><category term="outil" scheme="https://it-log.fr.eu.org/en/tags/outil/"/><content type="html"><![CDATA[<h2 id="description">Description</h2>
<p>Introducing to <code>bat</code> tool, an &ldquo;enhanced&rdquo; clone of <code>cat</code>, which offers syntax
highlighting and colouring, supports multiple languages and integrates with Git!</p>
<p>It&rsquo;s a tool available under an open-source licence, either MIT or Apache 2.0
licence, wrote since several years (<em>4y, at the time of writing this article</em>).</p>
<p>Note: Prefers to use a terminal capable of handling a 24-bit colour palette
properly.</p>
<ul>
<li>Officiel repository: <a href="https://github.com/sharkdp/bat" rel="external">https://github.com/sharkdp/bat</a></li>
</ul>
<h2 id="installation">Installation</h2>
<p>Regardless you&rsquo;re using either Linux or *BSD, the package to be installed is
<code>bat</code>.</p>
<hr>
<ul>
<li>on Debian: the binary is <code>batcat</code></li>
<li>on OpenBSD : <code>bat</code>!</li>
</ul>
<h2 id="configuration">Configuration</h2>
<p>You can generate a file config, as instance:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:$ bat --generate-config-file
</span></span></code></pre></div><p>To use <code>truecolor</code> or <code>24bit</code> on the terminal, add the environment variable:
<code>COLORTERM</code> :</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">if [ -x $(command -v bat) ]; then</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">export COLORTERM</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;truecolor&#34; # or &#34;24bit&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">fi</span>
</span></span></code></pre></div><p>(<em>For Debian/*Buntu, change the binary name!</em>)</p>
<h2 id="utilisation">Utilisation</h2>
<p>One using case is to combine with others tools, like <code>git</code>, <code>find</code>, <code>man</code>, etc.</p>
<h3 id="find">find</h3>
<p>To use <code>bat</code> with <code>find</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>find … -exec bat <span style="color:#5bc4bf">{}</span> +
</span></span></code></pre></div><p><em>where &lsquo;…&rsquo; represents the search term.</em></p>
<h3 id="git">git</h3>
<p><code>bat</code> can show you the git diff, by highlighting term, whilst maintaining the
indentation.</p>
<p>Make a <code>batdiff</code> function:</p>
<pre tabindex="0"><code>batdiff() {
    git diff --name-only --relative --diff-filter=d -z | xargs -0 bat --diff
}
</code></pre><h3 id="man">man</h3>
<p>Add the <code>MANPAGER</code> environment variable:</p>
<pre tabindex="0"><code>export MANPAGER=&#34;bat -pl man&#34;
</code></pre><p><em>Of course, it&rsquo;s possible to implement any feature supported by <code>bat</code> tool</em>.</p>
<p>And finally, call simply (<em>the best</em>) <code>man</code>:</p>
<ul>
<li>Debian : <code>man batcat</code></li>
</ul>
<p>
    

            
                    
                    <figure role="figure">
    <a href="/images/post/debian-batcat-man.png">
        <picture>
                
                    
                    <source srcset="/images/post/debian-batcat-man_hu_3cc503cacf8b31ca.avif" type="image/avif">
                    
                    <source srcset="/images/post/debian-batcat-man_hu_591483d71d811558.webp" type="image/webp">
            <img loading="lazy"
                    alt="Debian : man batcat"
                    height="134"
                    id="img_images_post_debian-batcat-man.png_0"
                    src="/images/post/debian-batcat-man.png"
                    width="300">
        </picture>
    </a>
</figure></p>
<ul>
<li>OpenBSD : <code>man pf.conf</code></li>
</ul>
<p>
    

            
                    
                    <figure role="figure">
    <a href="/images/post/openbsd-bat-man.png">
        <picture>
                
                    
                    <source srcset="/images/post/openbsd-bat-man_hu_d6fcc6312cf7b7b6.avif" type="image/avif">
                    
                    <source srcset="/images/post/openbsd-bat-man_hu_5e95e196aa2bb610.webp" type="image/webp">
            <img loading="lazy"
                    alt="OpenBSD : man pf.conf"
                    height="114"
                    id="img_images_post_openbsd-bat-man.png_1"
                    src="/images/post/openbsd-bat-man.png"
                    width="300">
        </picture>
    </a>
</figure></p>
<hr>
<h3 id="tip">Tip</h3>
<p>You will notice that the output also contains ANSI escape characters or symbols,
which are incomprehensible to us, humans.</p>
<p>Pipe <code>col</code> to <code>bat</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>man<span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>    sh -c <span style="color:#48b685">&#34;man &#39;</span><span style="color:#ef6155">$@</span><span style="color:#48b685">&#39; | col -bx | bat -l man&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span></code></pre></div><p>And use simply <code>man</code>. (<em>always the best</em>).</p>
<hr>
<h2 id="documentation">Documentation</h2>
<ul>
<li><a href="https://github.com/sharkdp/bat" rel="external">A cat(1) clone with syntax highlighting and Git integration</a>: <a href="https://github.com/sharkdp/bat" rel="external">https://github.com/sharkdp/bat</a></li>
<li><a href="https://github.com/eth-p/bat-extras" rel="external">Bash scripts that integrate bat with various command line tools</a>: <a href="https://github.com/eth-p/bat-extras" rel="external">https://github.com/eth-p/bat-extras</a></li>
<li><a href="https://sebastiano.tronto.net/blog/2022-09-05-man-col/" rel="external">Pipe man into col -b to get rid of ^H</a></li>
<li><a href="https://poor.dev/terminal-anatomy/" rel="external">Anatomy of a Terminal Emulator</a></li>
</ul>
<h2 id="acknowledgements">Acknowledgements</h2>
<ul>
<li>Wesley: <a href="https://framapiaf.org/@obj@bsd.cafe/116240454529047739" rel="external">@obj@bsd.cafe</a></li>
<li>Justine Smithies: <a href="https://snac.smithies.me.uk/justine/p/1773688945.119139" rel="external">@justine@snac.smithies.me.uk</a></li>
</ul>
<hr>
]]></content><summary>Bat: THE tool that replaces cat; AND highlights syntax with colours, supports multiple languages.</summary><published>2026-03-18T10:03:45+01:00</published><updated>2026-10-02T15:49:57+02:00</updated></entry><entry><id>tag:doc.huc.fr.eu.org,2023-02-19:/en/sys/openwrt/unbound-dot</id><link href="https://it-log.fr.eu.org/en/sys/openwrt/unbound-dot/" rel="alternate" type="text/html"/><title>OpenWRT + Unbound: Using DoT</title><author><name>Stéphane HUC</name></author><category term="OpenWRT" scheme="https://it-log.fr.eu.org/en/tags/openwrt/"/><category term="unbound" scheme="https://it-log.fr.eu.org/en/tags/unbound/"/><category term="DNS" scheme="https://it-log.fr.eu.org/en/tags/dns/"/><category term="DNSSEC" scheme="https://it-log.fr.eu.org/en/tags/dnssec/"/><category term="DoT" scheme="https://it-log.fr.eu.org/en/tags/dot/"/><content type="html"><![CDATA[<div class="tab-info i-deprecated"><strong>opkg → apk</strong></div>
<div class="alert alert-deprecated" role="alert"><strong>Since OpenWRT 25.12.0, **apk** *(Alpine Package Keeper)* is the new package manager; the oldier `opkg` is no longer maintened! See the relative page: https://openwrt.org/docs/guide-user/additional-software/opkg-to-apk-cheatsheet to the official transition.</strong></div>

<h2 id="description">Description</h2>
<p>The purpose is to add unbound to enable the 




















<span lang="en">DoT <em>(DNS-over-TCP)</em></span>


























































































 protocol, slightly modifying dnsmasq, installed by default:</p>
<p>Reasons are:</p>
<ul>
<li>encrypt DNS traffic to improve its confidentiality.</li>
<li>prevent DNS leaks and hijacking</li>
<li>bypass regional restrictions, or those imposed by your 











































<span lang="en">ISP <em>(Internet Service Provider)</em></span>



































































.</li>
</ul>
<h2 id="installation">Installation</h2>
<p>Install packages needed: <strong>unbound unbound-control luci-app-unbound</strong></p>
<pre tabindex="0"><code class="language-ash" data-lang="ash">:# opkg update
:# opkg install unbound unbound-control luci-app-unbound
</code></pre><p>May usefull to install too:</p>
<ul>
<li><strong>unbound-checkconf</strong>: to ensure the compliance of the configuration</li>
<li><strong>unbound-control-setup</strong>: allows you to install/create the required certificates for the tool control</li>
<li><strong>unbound-host</strong>: test…</li>
</ul>
<h2 id="configuration">Configuration</h2>
<h3 id="dnsmasq">dnsmasq</h3>
<p>First, edit the file <code>/etc/config/dhcp</code>, to use two options:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">option noresolv &#39;1&#39;</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">list server &#39;127.0.0.1#531&#39;</span>
</span></span></code></pre></div><ul>
<li>the first requires that the file <code>/etc/resolv.conf</code> not be use</li>
<li>the second requires redirecting DNS requests locally to the selected port, here: <code>531</code>.</li>
</ul>
<hr>
<p>Of course, these options can be modified directly using LUCI:</p>
<ul>
<li>&lsquo;Resolv and Hosts Files&rsquo; &gt; <strong>Ignore resolv file</strong> option</li>
<li>&lsquo;General Settings&rsquo; &gt; <strong>DNS forwardings</strong> option</li>
</ul>
<hr>
<p>About using <code>uci</code>, in your terminal:</p>
<pre tabindex="0"><code class="language-ash" data-lang="ash">uci set dhcp.@dnsmasq[0].noresolv=&#39;1&#39;
uci set dhcp.@dnsmasq[0].server=&#39;127.0.0.1#531&#39;
uci commit
</code></pre><hr>
<p><strong>Restart your dnsmasq service</strong>!</p>
<h3 id="unbound">unbound</h3>
<p>The simplest thing to do is to enable Unbound and check <strong>Manual Conf</strong> option to edit manually the configuration file through LUCI.</p>
<p>Add your networks in the <strong>Trigger Networks</strong> option, at least <strong>lan</strong>.</p>
<ul>
<li>File configuration : <code>/var/lib/unbound/unbound.conf</code></li>
</ul>
<hr>
<p>The minimum changes to be made correspond to the following variables:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">server:</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">(…)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">port: 531</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">do-ip4: yes</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">do-ip6: yes</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">do-tcp: yes</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">hide-identity: yes</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">hide-version: yes</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">qname-minimisation: yes</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">prefetch: yes</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">rrset-roundrobin: yes</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">minimal-responses: yes</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">tls-cert-bundle: &#34;/etc/ssl/certs/ca-certificates.crt&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">(…)</span>
</span></span></code></pre></div><p>Regarding the port number chosen, here <code>531</code>: we dont choose <code>5353</code>, which is normally reserved for the mdns service. Of course, you can change it, in the dnsmasq configuration; but, be sure to choose it from amont the preferred port numbers. (ie. below <code>1024</code>…)</p>
<hr>
<p>⇒ Be sure to add/modify the <code>access-control</code> variables to allow only:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span>    <span style="color:#06b6ef">access-control: 0.0.0.0/0 refuse</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">access-control: ::0/0 refuse</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">access-control: 127.0.0.0/8 allow</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">access-control: ::1 allow</span>
</span></span></code></pre></div><p>Then declare the LAN&rsquo;s IPv(4|6), or even your Wi-Fi…</p>
<hr>
<p>It&rsquo;s necessary to modify the <code>forward-zone</code> section:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">forward-zone:</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">name: &#34;.&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">forward-tls-upstream: yes</span>
</span></span></code></pre></div><p>Then add all IP addresses of the DoT servers; of course, both IPv4 and IPv6 are functional.</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span>    <span style="color:#06b6ef">forward-addr: 9.9.9.9@853       # Quad9</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">forward-addr: 1.1.1.1@853       # Cloudflare</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">forward-addr: 149.112.112.112@853       # Quad9 secondaire</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">forward-addr: 1.0.0.1@853       # Cloudflare secondaire</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">forward-addr: 2620:fe::fe@853       # Quad9 / IPv6</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">forward-addr: 2606:4700:4700::1111@853  # Cloudflare / IPv6</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">forward-addr: 2606:4700:4700::1001@853  # Cloudflare secondaire / IPv6</span>
</span></span></code></pre></div><p>The above example shows how the &ldquo;greats of this world&rdquo; are used.</p>
<hr>
<p>Here some interesting alternatives:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span>    <span style="color:#776e71"># FDN DoT</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">forward-addr: 80.67.169.12@853</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">forward-addr: 80.67.169.40@853</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">forward-addr: 2001:910:800::12@853</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">forward-addr: 2001:910:800::40@853</span>
</span></span><span style="display:flex;"><span>    <span style="color:#776e71"># dns.sb</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">forward-addr: 185.222.222.222@853</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">forward-addr: 45.11.45.11@853</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">forward-addr: 2a09::@853</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">forward-addr: 2a11::@853</span>
</span></span><span style="display:flex;"><span>    <span style="color:#776e71"># dns4eu</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">forward-addr: 86.54.11.11@853</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">forward-addr: 86.54.11.211@853</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">forward-addr: 2a13:1001::86:54:11:11@853</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">forward-addr: 2a13:1001::86:54:11:211@853</span>
</span></span><span style="display:flex;"><span>    <span style="color:#776e71"># dot.bortzmeyer.fr</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">forward-addr: 193.70.85.11@853</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">forward-addr: 2001:41d0:302:2200::180@853</span>
</span></span><span style="display:flex;"><span>    <span style="color:#776e71"># applied-privacy.net</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">forward-addr: 146.255.56.98@853</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">forward-addr: 2a02:1b8:10:234::2@853</span>
</span></span><span style="display:flex;"><span>    <span style="color:#776e71"># cleanbrowsing.org: family filter https://cleanbrowsing.org/filters/</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">forward-addr: 185.228.168.168@853</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">forward-addr: 185.228.169.168@853</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">forward-addr: 2a0d:2a00:1::@853</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">forward-addr: 2a0d:2a00:2::@853</span>
</span></span><span style="display:flex;"><span>    <span style="color:#776e71"># cz.nic</span>
</span></span><span style="display:flex;"><span>    <span style="color:#776e71">#forward-addr: 193.17.47.1@853</span>
</span></span><span style="display:flex;"><span>    <span style="color:#776e71">#forward-addr: 185.43.135.1@853</span>
</span></span><span style="display:flex;"><span>    <span style="color:#776e71">#forward-addr: 2001:148f:ffff::1@853</span>
</span></span><span style="display:flex;"><span>    <span style="color:#776e71">#forward-addr: 2001:148f:fffe::1@853</span>
</span></span><span style="display:flex;"><span>    <span style="color:#776e71"># dnsforfamily.com</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">forward-addr: 78.47.64.161@853</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">forward-addr: 94.130.180.225@853</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">forward-addr: 2a01:4f8:1c0c:40db::1@853</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">forward-addr: 2a01:4f8:1c17:4df8::1@853</span>
</span></span><span style="display:flex;"><span>    <span style="color:#776e71"># he.net</span>
</span></span><span style="display:flex;"><span>    <span style="color:#776e71">#forward-addr: 74.82.42.42@853</span>
</span></span><span style="display:flex;"><span>    <span style="color:#776e71">#forward-addr: 2001:470:20::2@853</span>
</span></span><span style="display:flex;"><span>    <span style="color:#776e71"># libredns.gr</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">forward-addr: 116.202.176.26@853</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">forward-addr: 2a01:4f8:1c0c:8274::1@853</span>
</span></span><span style="display:flex;"><span>    <span style="color:#776e71"># dns4all</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">forward-addr: 194.0.5.3@853</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">forward-addr: 194.0.5.64@853</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">forward-addr: 2001:678:8::3@853</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">forward-addr: 2001:678:8::64@853</span>
</span></span></code></pre></div><hr>
<p>That&rsquo;s for the basic configuration, which should allow you to use unbound with dnsmasq.</p>
<p>Be sure to restart the unbound service!</p>
<h2 id="check">Check</h2>
<p>⇒ If you decide to install the <strong>unbound-checkconf</strong> tool, now it&rsquo;s time to use it to verify all are correct. <br>
If it&rsquo;s well, the tool returns this informational message:</p>
<pre tabindex="0"><code class="language-ash" data-lang="ash"># unbound-checkconf
unbound-checkconf: no errors in /var/lib/unbound/unbound.conf
</code></pre><p>If there are any errors, the tool will tell you where!</p>
<hr>
<p>⇒ If you decide to install the <strong>unbound-host</strong> tool, you can test the connection, for example:</p>
<pre tabindex="0"><code class="language-ash" data-lang="ash"># unbound-host -vf /var/lib/unbound/root.key com.
com. has no address (secure)
com. has no IPv6 address (secure)
com. has no mail handler record (secure)
</code></pre><p>Do the same for the <strong><a href="https://www.ripe.net" rel="external">www.ripe.net</a></strong>, <strong><a href="https://www.afnic.fr" rel="external">www.afnic.fr</a></strong>, <strong>dnssec.cz</strong> addresses. <br>
The <strong>(secure)</strong> label guarantess a secure connection.</p>
<h2 id="control">Control</h2>
<p>A brief note about checking that unbound works properly. <br>
It&rsquo;s necessary to initialize the settings:</p>
<pre tabindex="0"><code class="language-ash" data-lang="ash"># unbound-control-setup
setup in directory /var/lib/unbound/
generating unbound_server.key
Generating RSA private key, 3072 bit long modulus
...............................................................................................................++
............................................................++
e is 65537 (0x10001)
generating unbound_control.key
Generating RSA private key, 3072 bit long modulus
........................................................................++
..................++
e is 65537 (0x10001)
create unbound_server.pem (self signed certificate)
create unbound_control.pem (signed client certificate)
Signature ok
subject=/CN=unbound-control
Getting CA Private Key
Setup success. Certificates created. Enable in unbound.conf file to use
</code></pre><p>Then modify the unbound configuration file to add/uncomment the <code>remote-control</code> section, as follows:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">remote-control:</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">control-enable: yes</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">control-interface: 127.0.0.1</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">control-interface: ::1</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">control-port: 8953</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">control-use-cert: no</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">server-key-file: &#34;/var/lib/unbound/unbound_server.key&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">server-cert-file: &#34;/var/lib/unbound/unbound_server.pem&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">control-key-file: &#34;/var/lib/unbound/unbound_control.key&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">control-cert-file: &#34;/var/lib/unbound/unbound_control.pem&#34;</span>
</span></span></code></pre></div><p><strong>After restarting the service</strong>, all that remains is to test it with the <code>unbound-control</code> tool, as in this example:</p>
<pre tabindex="0"><code class="language-ash" data-lang="ash"># unbound-control -s ::1 status
version: 1.17.0
verbosity: 1
threads: 4
modules: 2 [ validator iterator ]
uptime: 3482 seconds
options: reuseport control
unbound (pid 32307) is running...
</code></pre><p>It&rsquo;s possible to find the value of any option by using <code>get_option</code> option followed by the name of the option. <br>
Similarly, it&rsquo;s still possible to dump the cache for flow analysis, using the <code>dump_cache</code> option redirected to a file name.</p>
<hr>
<p>Voila!</p>
<hr>
]]></content><summary>Add Unbound to OpenWRT using DoT protocol.</summary><published>2023-02-19T15:37:43+01:00</published><updated>2026-10-02T15:49:57+02:00</updated></entry><entry><id>tag:doc.huc.fr.eu.org,2022-10-04:/en/post/openbsd-nsd-dnssec-tlsa</id><link href="https://it-log.fr.eu.org/en/post/openbsd-nsd-dnssec-tlsa/" rel="alternate" type="text/html"/><title>OpenBSD: Manage DNS, DNSSEC (to automate TLSA records)</title><author><name>Stéphane HUC</name></author><category term="DNS" scheme="https://it-log.fr.eu.org/en/tags/dns/"/><category term="DANE" scheme="https://it-log.fr.eu.org/en/tags/dane/"/><category term="DNSSEC" scheme="https://it-log.fr.eu.org/en/tags/dnssec/"/><category term="OpenBSD" scheme="https://it-log.fr.eu.org/en/tags/openbsd/"/><category term="TLSA" scheme="https://it-log.fr.eu.org/en/tags/tlsa/"/><content type="html"><![CDATA[<h2 id="description">Description</h2>
<p>Since 2018, I asked me about how to manage TLSA records, according to the
DANE and DNSSEC protocols, for my DNS.
<em>(I wroted one article in french, on March 2018, about creating TLSA records
in shell or PHP languages; if you read french, see:
<a href="/fr/post/generer-enregistrement-tlsa/">DNS: Générer un enregistrement TLSA</a>…)</em></p>
<p><em>Someone prefers using <strong>knot</strong>, as package on OpenBSD, because they thing
that&rsquo;s complex to manage. Here, we&rsquo;ll see some tips to manage this,
an automated way, in shell, on OpenBSD.</em></p>
<p>My DNS service run since 4 years, under OpenBSD native tool named <strong>nsd</strong>.
I manage DNSSEC with <strong><a href="https://openports.pl/path/net/ldns,-utils" rel="external">ldns</a></strong>
tools, a package into ports. <br>
In the facts, I use <strong><a href="https://www.22decembre.eu/en/2017/11/01/ldnscripts/" rel="external">ldnscript</a></strong>
tool to create all needed keys and manage DNSSEC.</p>
<p>⇒ Starting Juin 2022, I decided to switch from RSA to use ECDSA.</p>
<p>Before going any further in this direction, let&rsquo;s move on to the installation
of the necessary prerequisites necessary:</p>
<h2 id="installation">Installation</h2>
<h3 id="ldnscript">ldnscript</h3>
<p>To remind myself how to do this, I made myself the following little memo:</p>
<ol>
<li>
<p>Install ldns-utils:<br>
<code>$ doas pkg_add ldns-utils git</code></p>
</li>
<li>
<p>Download and install ldnscripts</p>
</li>
</ol>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>$ cd /usr/local/src/
</span></span><span style="display:flex;"><span>$ doas mkdir ldnscripts
</span></span><span style="display:flex;"><span>$ doas chown <span style="color:#ef6155">$USER</span> ldnscripts
</span></span><span style="display:flex;"><span>$ git clone https://framagit.org/22decembre/ldnscripts.git
</span></span><span style="display:flex;"><span>$ cd ldnscripts
</span></span><span style="display:flex;"><span>$ doas make install
</span></span></code></pre></div><ol start="3">
<li>Configure /etc/ns/ldnscript.conf</li>
</ol>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#776e71">; SHA256 est largement suffisant et sécuritaire</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ALG</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">ECDSAP256SHA256 </span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">NSEC3_ALG</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">SHA-256</span>
</span></span></code></pre></div><ol start="4">
<li>
<p>Init the domain name:<br>
<code>$ doas ldnscript init domain.tld</code></p>
</li>
<li>
<p>You need to create symbolic link from <code>/usr/bin/dig</code> to <code>/usr/sbin/dig</code>:<br>
<code>$ doas ln -sf /usr/bin/dig /usr/sbin/dig</code> <br>
<em>(without this, the <code>ldnscript</code> tool will not be able to find the binary
and therefore will refuse to run, displaying error message)</em>.</p>
</li>
</ol>
<h2 id="configuration">Configuration</h2>
<h3 id="etcmonthlylocal">/etc/monthly.local</h3>
<p>Into the <code>/etc/monthly.local</code> script, I include this shellcode to create
the needed rollover keys:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#776e71">### ldnscript</span>
</span></span><span style="display:flex;"><span>printf <span style="color:#48b685">&#39;%s\n&#39;</span> <span style="color:#48b685">&#34;⇒ ldnscript rollover&#34;</span>
</span></span><span style="display:flex;"><span>/usr/local/sbin/ldnscript rollover all
</span></span></code></pre></div><h4 id="lets-encrypt">Let&rsquo;s Encrypt</h4>
<p>Next, the shell script queries the Let&rsquo;s Encrypt services to know if it&rsquo;s
necessary to renew the certificates for the domain names I use.</p>
<p><em>Normally, one would use the native <code>acme</code> client on OpenBSD, but I
had some problems, I decided to switch to <code>certbot</code>.</em></p>
<p>To renew, on shell, that&rsquo;s enough:<br>
<code>/usr/local/bin/certbot renew --pre-hook &quot;rcctl stop nginx&quot; --post-hook &quot;rcctl start nginx&quot;</code></p>
<p><em>(Yesss, I known; I use nginx, because I prefer… but, I you like <strong>httpd</strong>,
the native webserver, replace by his name service).</em></p>
<p>In fact, this part is not directly related to the DNS(SEC) management.
This is important to take carefull because during certificate renewall,
it&rsquo;s necessary to regenerate TLSA records. <em>We&rsquo;ll see that later…</em></p>
<h3 id="dns-zone-example">DNS Zone Example</h3>
<p>Here, for instance, a minimilastic DNS Zone, managed by <strong>ns</strong> server:</p>
<pre tabindex="0"><code class="language-conf" data-lang="conf">$TTL 1H
$ORIGIN domain.tld.
@   IN  SOA domain.tld. dns.domain.tld. (
    2022090101 ;
    3H ; refresh
    1H ; retry
    2W ; expire
    1H ; negative
)
                    
@   IN NS   ns1.domain.tld.
@   IN NS   ns2.domain.tld.

@   IN A    46.23.90.29
    IN AAAA 2a03:6000:6e65:619::29

; enregistrement CAA
@    IN CAA  0 iodef &#34;mailto:mail@domain.tld&#34;
@    IN CAA  0 issue &#34;letsencrypt.org&#34;
@    IN CAA  0 issuewild &#34;letsencrypt.org&#34;

www IN A    46.23.90.29
    IN AAAA 2a03:6000:6e65:619::29

; TLSA
_443._tcp.domain.tld. IN TLSA 3 1 2 5c8fdd68178ce4cd8d88bd90b82a96df41674d555340b88283c24a0b3416aa375144cd6c16a58160ba3b168e59f5003bff656ce67cb24931b462fe4910bd62f5
</code></pre><h2 id="shell">shell</h2>
<h3 id="generate-tlsa-record">Generate TLSA Record</h3>
<p>On shellcode, managing a TLSA record is simple — <em>need to use openssl</em>:<br>
<code>openssl x509 -noout -pubkey -in &quot;${cert}&quot; | openssl &quot;${command}&quot; -pubin -outform der 2&gt;/dev/null | &quot;${algo}&quot; | tr &quot;a-z&quot; &quot;A-Z&quot;</code></p>
<p><strong>Explains</strong> :</p>
<p>⇒ The above command generate a <code>tlsa_cert_associated</code> variable, where:</p>
<ul>
<li><code>$cert</code>: the absolute pathname for the server TLS cert, on the
filesystem, about one domain name.</li>
<li><code>$command</code>: the command name used by openssl, either <code>rsa</code> or
<code>ec</code> <em>(reciprocally for RSA or ECDSA encryption records)</em>.</li>
<li><code>$algo</code>: <code>sha256</code>, or <code>sha512</code> tool to use.</li>
</ul>
<p>⇒ Writing the TLSA record is also simple:<br>
<code>tlsa_record=&quot;_${tls_port}._${tls_proto}.${domain}. IN TLSA ${tlsa_usage} ${tlsa_selector} ${tlsa_method} ${tlsa_cert_associated}&quot;</code></p>
<ul>
<li><code>${tls_port}</code>: port number of the webservice; by default <strong>443</strong></li>
<li><code>${tls_proto}</code>: protocol name used; by default <strong>tls</strong></li>
<li><code>${domain}</code>: the domain name</li>
<li><code>${tlsa_usage}</code>: the number according the <strong>DANE-EE</strong> constraint;
<strong>3</strong> is recommended by Let&rsquo;s Encrypt,</li>
<li><code>${tlsa_selector}</code>: the number according to the <strong>SPKI</strong> selector;
<strong>1</strong> is recommended by Let&rsquo;s Encrypt,</li>
<li><code>${tlsa_method}</code>: the method segun the choosed algorythm; by default:
<strong>SHA256</strong>, <em>which offers currently a secure level of encryption,
egually recommended by Let&rsquo;s Encrypt</em>.</li>
<li>finishing with the previous <code>tlsa_cert_associated</code> variable.</li>
</ul>
<h3 id="check-tlsa-record">Check TLSA Record</h3>
<p>Check a TLSA record is more complex; you need to:</p>
<ol>
<li>1/ query the DNS server to known the actual TLSA record, with <code>dig</code>
tool, for example.</li>
<li>2/ compare with the <code>openssl</code> output; OpenSSL requesting the cert to
the webserver, linked to the domain name.</li>
</ol>
<hr>
<ul>
<li>queries the DNS server, like:</li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#ef6155">tlsa</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#815ba4">$(</span>dig TLSA _443._tcp.<span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">domain</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> +short<span style="color:#815ba4">)</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#ef6155">d_tlsa</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#815ba4">$(</span>echo <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">tlsa</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> | awk <span style="color:#48b685">&#39;{ for(i=4;i&lt;=NF;++i) printf &#34;%s&#34;, tolower($i); print &#34;&#34; }&#39;</span><span style="color:#815ba4">)</span><span style="color:#48b685">&#34;</span>
</span></span></code></pre></div><ul>
<li>use openssl to request TLS certificate used on the webserver:</li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#ef6155">tlsa</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#815ba4">$(</span>echo | openssl s_client -servername <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">domain</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> -showcerts -connect <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">domain</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>:443 2&gt;/dev/null | openssl x509 -noout -pubkey | openssl pkey -outform der -pubin 2&gt;/dev/null | openssl dgst -<span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">algo</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> 2&gt;/dev/null <span style="color:#815ba4">)</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#ef6155">o_tlsa</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#815ba4">$(</span>echo <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">tlsa</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> | awk -F<span style="color:#48b685">&#39;=&#39;</span> <span style="color:#48b685">&#39;{ print $2 }&#39;</span> | tr -d <span style="color:#48b685">&#39; &#39;</span><span style="color:#815ba4">)</span><span style="color:#48b685">&#34;</span>
</span></span></code></pre></div><p>Finally, it enoughs to compare both shell variables, <code>d_tlsa</code> and <code>o_tlsa</code>.
In normal time, that should be case.
<strong>Except in case of renewal certificate, which will require the renewal
of the TLSA record in the domain name zone, on the DNS server.</strong></p>
<p>NOTE: if this is not done, a DNS server query on the DNSSEC protocol will
generate an error since the TLSA record will not match a freshly used, or
renewed TLS cert, which will result in that consequence:<br>
access to the server, linked to the target domain name, will be impossible.<br>
<strong>It will be necessary to generate a new TLSA record corresponding to the
renewal of the TLS certificate, then egual to regenerate the signature of
the DNSSEC records, for the DNS zone of the target domain.</strong></p>
<h2 id="shell-scripts">Shell Scripts</h2>
<p>Note: Put the <strong>tlsa.sh</strong>, <strong>dns.conf</strong>, <strong>dns.ksh</strong> shell scripts on your
home. <em>If you change their location on the filesystem, think to modify your
monthly local.</em></p>
<h3 id="monthlylocal">monthly.local</h3>
<p>Here, a <strong>monthly.local</strong>:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#776e71">#!/bin/sh
</span></span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">### ldnscript</span>
</span></span><span style="display:flex;"><span>printf <span style="color:#48b685">&#39;%s\n&#39;</span> <span style="color:#48b685">&#34;⇒ ldnscript rollover&#34;</span>
</span></span><span style="display:flex;"><span>/usr/local/sbin/ldnscript rollover all
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">### renew ssl by certbot</span>
</span></span><span style="display:flex;"><span>printf <span style="color:#48b685">&#39;%s\n&#39;</span> <span style="color:#48b685">&#34;⇒ renew letsencrypt certs&#34;</span>
</span></span><span style="display:flex;"><span>/usr/local/bin/certbot renew --pre-hook <span style="color:#48b685">&#34;rcctl stop nginx&#34;</span> --post-hook <span style="color:#48b685">&#34;rcctl start nginx&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">### check tlsa records for domain; only for tcp:443</span>
</span></span><span style="display:flex;"><span><span style="color:#815ba4">for</span> domain in <span style="color:#48b685">&#34;sub.domain.tld&#34;</span> <span style="color:#48b685">&#34;domain.tld&#34;</span> <span style="color:#48b685">&#34;www.domain.tld&#34;</span> <span style="color:#48b685">&#34;sub.domain2.tld&#34;</span> <span style="color:#48b685">&#34;domain2.tld&#34;</span> <span style="color:#48b685">&#34;www.domain2.tld&#34;</span>; <span style="color:#815ba4">do</span>
</span></span><span style="display:flex;"><span>	printf <span style="color:#48b685">&#39;%s\n&#39;</span> <span style="color:#48b685">&#34;⇒ Test TLSA for </span><span style="color:#f99b15">${</span><span style="color:#ef6155">domain</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>	/home/-your-user-/dns-tools/tlsa.sh <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">domain</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#815ba4">done</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">(</span>…<span style="color:#5bc4bf">)</span>
</span></span></code></pre></div><h3 id="tlsash">tlsa.sh</h3>
<p>Here, the <strong>tlsa.sh</strong> script:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#776e71">#!/bin/sh
</span></span></span><span style="display:flex;"><span>set -e
</span></span><span style="display:flex;"><span><span style="color:#776e71">#set -x</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">########################################################################</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># Author: Stéphane HUC</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># mail: devs@stephane-huc.net</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># gpg:fingerprint: CE2C CF7C AB68 0329 0D20  5F49 6135 D440 4D44 BD58</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># License: BSD Simplified</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># Github: </span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># Date: 2022/07/01 06:45</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">########################################################################</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># Purpose: tool  to test TLSA record</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#  - for the geek: DANE-TLSA...</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># Needed tools: dig, openssl</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># OS: Tested on OpenBSD, Devuan</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">########################################################################</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">###</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">##</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># see: https://www.bortzmeyer.org/monitor-dane.html</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">##</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">###</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">########################################################################</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ef6155">ROOT</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#815ba4">$(</span>dirname <span style="color:#48b685">&#34;</span><span style="color:#815ba4">$(</span>readlink -f -- <span style="color:#48b685">&#34;</span><span style="color:#ef6155">$0</span><span style="color:#48b685">&#34;</span><span style="color:#815ba4">)</span><span style="color:#48b685">&#34;</span><span style="color:#815ba4">)</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>. <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">ROOT</span><span style="color:#f99b15">}</span><span style="color:#48b685">/dns.conf&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ef6155">dir_admin</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;/home/-your-user-/dns-tools&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#ef6155">domain</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#ef6155">$1</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">### DO NOT TOUCH!</span>
</span></span><span style="display:flex;"><span><span style="color:#ef6155">d_tlsa</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#39;&#39;</span>	<span style="color:#776e71"># TLSA record by dig</span>
</span></span><span style="display:flex;"><span><span style="color:#ef6155">o_tlsa</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#39;&#39;</span>	<span style="color:#776e71"># TLSA record by openssl</span>
</span></span><span style="display:flex;"><span><span style="color:#ef6155">tlsa_record</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#39;&#39;</span>	<span style="color:#776e71"># TLSA record </span>
</span></span><span style="display:flex;"><span><span style="color:#ef6155">tlsa_method</span><span style="color:#5bc4bf">=</span><span style="color:#f99b15">2</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">########################################################################</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">####</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">##</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#   All needed functions! DO NOT TOUCH-IT!</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">##</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">###</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">########################################################################</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>byebye<span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    mssg <span style="color:#48b685">&#34;KO&#34;</span> <span style="color:#48b685">&#34;Script stop here!&#34;</span>
</span></span><span style="display:flex;"><span>    mssg <span style="color:#48b685">&#34;KO&#34;</span> <span style="color:#48b685">&#34;Please, search to understand reasons.&#34;</span>
</span></span><span style="display:flex;"><span>    exit <span style="color:#f99b15">1</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>check_uid<span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">if</span> <span style="color:#5bc4bf">[</span> <span style="color:#48b685">&#34;</span><span style="color:#815ba4">$(</span>id -u<span style="color:#815ba4">)</span><span style="color:#48b685">&#34;</span> -ne <span style="color:#f99b15">0</span> <span style="color:#5bc4bf">]</span>; <span style="color:#815ba4">then</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        mssg <span style="color:#48b685">&#34;KO&#34;</span> <span style="color:#48b685">&#34;ERROR: Script not launch with rights admin!&#34;</span>
</span></span><span style="display:flex;"><span>        byebye
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>_dig<span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#ef6155">tlsa</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#815ba4">$(</span>dig TLSA _443._tcp.<span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">domain</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> +short<span style="color:#815ba4">)</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#ef6155">d_tlsa</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#815ba4">$(</span>echo <span style="color:#ef6155">$tlsa</span> | awk <span style="color:#48b685">&#39;{ for(i=4;i&lt;=NF;++i) printf &#34;%s&#34;, tolower($i); print &#34;&#34; }&#39;</span><span style="color:#815ba4">)</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>_openssl<span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#ef6155">tlsa</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#815ba4">$(</span>echo | openssl s_client -servername <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">domain</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> -showcerts -connect <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">domain</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>:443 2&gt;/dev/null | openssl x509 -noout -pubkey | openssl pkey -outform der -pubin 2&gt;/dev/null | openssl dgst -<span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">algo</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> 2&gt;/dev/null <span style="color:#815ba4">)</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#ef6155">o_tlsa</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#815ba4">$(</span>echo <span style="color:#ef6155">$tlsa</span> | awk -F<span style="color:#48b685">&#39;=&#39;</span> <span style="color:#48b685">&#39;{ print $2 }&#39;</span> | tr -d <span style="color:#48b685">&#39; &#39;</span><span style="color:#815ba4">)</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>mssg<span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    typeset statut info text
</span></span><span style="display:flex;"><span>    <span style="color:#ef6155">statut</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#ef6155">$1</span><span style="color:#48b685">&#34;</span> <span style="color:#ef6155">info</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#ef6155">$2</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">case</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">statut</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> in
</span></span><span style="display:flex;"><span>        <span style="color:#48b685">&#34;KO&#34;</span><span style="color:#5bc4bf">)</span> <span style="color:#ef6155">text</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;[ </span><span style="color:#f99b15">${</span><span style="color:#ef6155">red</span><span style="color:#f99b15">}${</span><span style="color:#ef6155">statut</span><span style="color:#f99b15">}${</span><span style="color:#ef6155">neutral</span><span style="color:#f99b15">}</span><span style="color:#48b685"> ]    </span><span style="color:#f99b15">${</span><span style="color:#ef6155">info</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> ;;
</span></span><span style="display:flex;"><span>        <span style="color:#48b685">&#34;OK&#34;</span><span style="color:#5bc4bf">)</span> <span style="color:#ef6155">text</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;[ </span><span style="color:#f99b15">${</span><span style="color:#ef6155">green</span><span style="color:#f99b15">}${</span><span style="color:#ef6155">statut</span><span style="color:#f99b15">}${</span><span style="color:#ef6155">neutral</span><span style="color:#f99b15">}</span><span style="color:#48b685"> ]   </span><span style="color:#f99b15">${</span><span style="color:#ef6155">info</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> ;;
</span></span><span style="display:flex;"><span>        <span style="color:#776e71">#*) mssg=&#34;${text}&#34; ;;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">esac</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    printf <span style="color:#48b685">&#34;%s \n&#34;</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">text</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    unset info statut text
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>new_tlsa<span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#ef6155">cert</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;/etc/letsencrypt/live/</span><span style="color:#f99b15">${</span><span style="color:#ef6155">domain</span><span style="color:#f99b15">}</span><span style="color:#48b685">/cert.pem&#34;</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#815ba4">case</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">le_key_type</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> in 
</span></span><span style="display:flex;"><span>		<span style="color:#48b685">&#34;ecdsa&#34;</span><span style="color:#5bc4bf">)</span>
</span></span><span style="display:flex;"><span>			<span style="color:#ef6155">tlsa_cert_associated</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#815ba4">$(</span>openssl x509 -noout -pubkey -in <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">cert</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> | openssl ec -pubin -outform der 2&gt;/dev/null | <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">algo</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span><span style="color:#815ba4">)</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>		;;
</span></span><span style="display:flex;"><span>		<span style="color:#48b685">&#34;rsa&#34;</span><span style="color:#5bc4bf">)</span>
</span></span><span style="display:flex;"><span>			<span style="color:#ef6155">tlsa_cert_associated</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#815ba4">$(</span>openssl x509 -noout -pubkey -in <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">cert</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> | openssl rsa -pubin -outform der 2&gt;/dev/null | <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">algo</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span><span style="color:#815ba4">)</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>		;;
</span></span><span style="display:flex;"><span>	<span style="color:#815ba4">esac</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#ef6155">tlsa_record</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;_</span><span style="color:#f99b15">${</span><span style="color:#ef6155">tls_port</span><span style="color:#f99b15">}</span><span style="color:#48b685">._</span><span style="color:#f99b15">${</span><span style="color:#ef6155">tls_proto</span><span style="color:#f99b15">}</span><span style="color:#48b685">.</span><span style="color:#f99b15">${</span><span style="color:#ef6155">domain</span><span style="color:#f99b15">}</span><span style="color:#48b685">. IN TLSA </span><span style="color:#f99b15">${</span><span style="color:#ef6155">tlsa_usage</span><span style="color:#f99b15">}</span><span style="color:#48b685"> </span><span style="color:#f99b15">${</span><span style="color:#ef6155">tlsa_selector</span><span style="color:#f99b15">}</span><span style="color:#48b685"> </span><span style="color:#f99b15">${</span><span style="color:#ef6155">tlsa_method</span><span style="color:#f99b15">}</span><span style="color:#48b685"> </span><span style="color:#f99b15">${</span><span style="color:#ef6155">tlsa_cert_associated</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>	unset tlsa_cert_associated
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">########################################################################</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">####</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">##</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#   Execution</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">##</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">###</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">########################################################################</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#815ba4">if</span> <span style="color:#5bc4bf">[</span> -z <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">domain</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> <span style="color:#5bc4bf">]</span>; <span style="color:#815ba4">then</span> printf <span style="color:#48b685">&#39;%s\n&#39;</span> <span style="color:#48b685">&#34;[ KO ] Script stops here; no domain!&#34;</span>; exit; <span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>_dig
</span></span><span style="display:flex;"><span>_openssl
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#815ba4">if</span> <span style="color:#5bc4bf">[</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">d_tlsa</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> <span style="color:#5bc4bf">=</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">o_tlsa</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> <span style="color:#5bc4bf">]</span>; <span style="color:#815ba4">then</span>
</span></span><span style="display:flex;"><span>	mssg <span style="color:#48b685">&#34;OK&#34;</span> <span style="color:#48b685">&#34;Similar TLSA records! :D&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#815ba4">else</span>
</span></span><span style="display:flex;"><span>	mssg <span style="color:#48b685">&#34;KO&#34;</span> <span style="color:#48b685">&#34;There seems to be a problem with the TLSA records of the domain: </span><span style="color:#f99b15">${</span><span style="color:#ef6155">domain</span><span style="color:#f99b15">}</span><span style="color:#48b685">!&#34;</span>
</span></span><span style="display:flex;"><span>	printf <span style="color:#48b685">&#39;%s\n&#39;</span> <span style="color:#48b685">&#34;Have you renew recently the TLS certs for the domain? If yes, change the TLSA record into the DNS zone relevent!&#34;</span>
</span></span><span style="display:flex;"><span>	printf <span style="color:#48b685">&#39;%s\n%s\n&#39;</span> <span style="color:#48b685">&#34;⇒ Perhaps, the dns.sh script shell can help you. ;-)&#34;</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	check_uid
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	printf <span style="color:#48b685">&#39;%s\n&#39;</span> <span style="color:#48b685">&#34;⇒ Display new TLSA record:&#34;</span>
</span></span><span style="display:flex;"><span>	new_tlsa
</span></span><span style="display:flex;"><span>	printf <span style="color:#48b685">&#39;%s\n%s\n&#39;</span> <span style="color:#48b685">&#34;Add/modify tlsa into your DNS zone for </span><span style="color:#f99b15">${</span><span style="color:#ef6155">domain</span><span style="color:#f99b15">}</span><span style="color:#48b685">: &#34;</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">tlsa_record</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	printf <span style="color:#48b685">&#39;%s\n&#39;</span> <span style="color:#48b685">&#34;⇒ Modify TLSA record into the domain zone for </span><span style="color:#f99b15">${</span><span style="color:#ef6155">domain</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">dir_admin</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>/dns.ksh tlsa <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">domain</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span><span style="color:#815ba4">fi</span>
</span></span></code></pre></div><p><strong>ATTENTION: You need to modify the <code>dir_admin</code> variable, at the top of
script!</strong></p>
<p><strong>Explains</strong>:</p>
<ul>
<li>it call the <strong>dns.conf</strong> file config; see below,</li>
<li>and, if the TLSA records does not match, it call the pdksh <strong>dns.ksh</strong>
script, with <code>tlsa</code> and targeted domain name as arguments.</li>
</ul>
<h3 id="dnsconf">dns.conf</h3>
<p>Here, the file config — <em>needed for both <strong>dns.ksh</strong> and <strong>tlsa.sh</strong> shell
scripts</em>:</p>
<pre tabindex="0"><code class="language-conf" data-lang="conf">########################################################################
#
# Author: Stéphane HUC
# mail: devs@stephane-huc.net
# gpg:fingerprint: CE2C CF7C AB68 0329 0D20  5F49 6135 D440 4D44 BD58
#
# License: BSD Simplified
#
# Github: https://framagit.org/hucste/AH.git
#
# Date: 2022/06/01 07:20
#
########################################################################
###
##
# Config file to dns.ksh script
##
###
########################################################################

### Algorithm
## values: sha256, sha512; choose-it segun TLSA Method
algo=&#34;sha256&#34;
### SOA Serial type
## values: date, timestamp
## DNS recommandation: prefer date
SOA_serial_type=&#34;date&#34;
### Port number
tls_port=443
### Protocols
## values: stcp, tcp, udp
tls_proto=&#34;tcp&#34;

### TLSA 
## Lets Encrypt Recommandation; 
## 	see: https://community.letsencrypt.org/t/please-avoid-3-0-1-and-3-0-2-dane-tlsa-records-with-le-certificates/7022
## usage: Lets Encrypt recommands 3, at least 2
## values: 0 =&gt; 3; or (PKIX-TA, PKIX-EE, DANE-TA, DANE-EE; respectivly: 0 -&gt; 3)
tlsa_usage=3
## selector: Lets Encrypt recommands 1
## values: 0 or 1; or (CERT, SPKI; respectively: O or 1)
tlsa_selector=1
## method: Lets Encrypt recommands 1
## values: 0 =&gt; 2; or (FULL, SHA256, SHA512; respectively: 0 -&gt; 2)
# this change segun algo
tlsa_method=1

### Key Type Letsencrypt
## rsa or ecdsa
## if ecdsa, specify elliptic curve: secp256r1, secp384r1, secp512r1 (256 is enough)
le_key_type=ecdsa
le_curve=secp256r1
</code></pre><p>I personally choose to use:</p>
<ul>
<li>the <strong>sha512</strong> algorythm</li>
<li>the <strong>ecdsa</strong> to use the <strong>ec</strong> command with openssl. <em>Of course, it&rsquo;s
possible to use <strong>rsa</strong>; in this case, those shell scripts will not
use the <code>$le_curve</code> variable</em>.</li>
</ul>
<h3 id="dnsksh">dns.ksh</h3>
<p>This complex and large script is available to:</p>
<ul>
<li>generate DNSSEC signs for the DNS zone.</li>
<li>modify TLSA records and regenerate DNSSEC signs; in this case:
<ul>
<li>find the SOA record</li>
<li>create a new file for the DNS zone and backup the actual</li>
<li>if the new file is available, the script will write:
<ul>
<li>a new SOA record</li>
<li>replace the oldier TLSA record with the new</li>
<li>try to sign the DNS zone with the DNSSEC protocol:
<ul>
<li>if succeeded, it destroy the oldier DNS zone file,</li>
<li>if it fails, it warns, stops the execution <strong>and</strong> this case
you need to rename manually the backuped file.<br>
<em>You can modify the <code>debug</code> variable to 1, and relaunch
the script; it logs the differents steps.
This helps to review and analyse why…</em></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>Maybe, <code>./dns.ksh help</code> will show you more information.</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-ksh" data-lang="ksh"><span style="display:flex;"><span><span style="color:#776e71">#!/bin/ksh
</span></span></span><span style="display:flex;"><span>set -e
</span></span><span style="display:flex;"><span><span style="color:#776e71">#set -x</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">################################################################################</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># Author: Stéphane HUC</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># mail: devs@stephane-huc.net</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># gpg:fingerprint: CE2C CF7C AB68 0329 0D20  5F49 6135 D440 4D44 BD58</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># License: BSD Simplified</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># Github: </span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># Date: 2022/06/01 07:25</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">################################################################################</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># Purpose: to add a TLSA Record into DNS zone, segun your cert TLS (LE)</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#  - for the geek: DANE-TLSA...</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#### IMPORTANT: recreate your TLSA Record after (re?)new cert...</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># Needed tools: nsd* and ldnscript</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">## ldnscript is a tool to sign dns zone. (DNSSEC)</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">## https://framagit.org/22decembre/ldnscripts.git</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># OS: Tested on OpenBSD</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">################################################################################</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ef6155">ROOT</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#815ba4">$(</span>dirname <span style="color:#48b685">&#34;</span><span style="color:#815ba4">$(</span>readlink -f -- <span style="color:#48b685">&#34;</span><span style="color:#ef6155">$0</span><span style="color:#48b685">&#34;</span><span style="color:#815ba4">)</span><span style="color:#48b685">&#34;</span><span style="color:#815ba4">)</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>. <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">ROOT</span><span style="color:#f99b15">}</span><span style="color:#48b685">/dns.conf&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">################################################################################</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">###</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">##</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#   DONT TOUCH THOSES VARIABLES!</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">##</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">###</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">################################################################################</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ef6155">debug</span><span style="color:#5bc4bf">=</span><span style="color:#f99b15">0</span>
</span></span><span style="display:flex;"><span><span style="color:#ef6155">dir_le</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;/etc/letsencrypt/live&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#ef6155">dir_ns_cfg</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;/etc/ns&#34;</span>    <span style="color:#776e71"># folder config ns</span>
</span></span><span style="display:flex;"><span><span style="color:#ef6155">dir_sbin</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;/usr/local/sbin&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#ef6155">log</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">ROOT</span><span style="color:#f99b15">}</span><span style="color:#48b685">/dns-script.log&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#ef6155">nsd_cfg</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;/var/nsd/etc/nsd.conf&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ef6155">timestamp</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#815ba4">$(</span>date +%s<span style="color:#815ba4">)</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#ef6155">today</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#815ba4">$(</span>date +<span style="color:#48b685">&#34;%Y%m%d&#34;</span><span style="color:#815ba4">)</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ef6155">server</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;nsd&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ef6155">SOA_ns</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ef6155">tlsa_record</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;&#34;</span>
</span></span><span style="display:flex;"><span>set -A tlsa_records	<span style="color:#776e71"># if X509 DNS Alternative Names &gt; 1</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>set -A tlsa_method_names -- <span style="color:#48b685">&#34;FULL&#34;</span> <span style="color:#48b685">&#34;SHA256&#34;</span> <span style="color:#48b685">&#34;SHA512&#34;</span>
</span></span><span style="display:flex;"><span>set -A tlsa_selector_names -- <span style="color:#48b685">&#34;CERT&#34;</span> <span style="color:#48b685">&#34;SPKI&#34;</span>
</span></span><span style="display:flex;"><span>set -A tlsa_usage_names -- <span style="color:#48b685">&#34;PKIX-TA&#34;</span> <span style="color:#48b685">&#34;PKIX-EE&#34;</span> <span style="color:#48b685">&#34;DANE-TA&#34;</span> <span style="color:#48b685">&#34;DANE-EE&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ef6155">NB_PARAMS</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#ef6155">$#</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>set -A PARAMS -- <span style="color:#48b685">&#34;</span><span style="color:#ef6155">$@</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ef6155">ROOT</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#815ba4">$(</span>dirname <span style="color:#48b685">&#34;</span><span style="color:#815ba4">$(</span>readlink -f -- <span style="color:#48b685">&#34;</span><span style="color:#ef6155">$0</span><span style="color:#48b685">&#34;</span><span style="color:#815ba4">)</span><span style="color:#48b685">&#34;</span><span style="color:#815ba4">)</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#815ba4">if</span> <span style="color:#5bc4bf">[</span> -z <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">PARAMS</span>[0]<span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> <span style="color:#5bc4bf">]</span>; <span style="color:#815ba4">then</span> <span style="color:#ef6155">MENU_CHOICE</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;help&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#815ba4">else</span>
</span></span><span style="display:flex;"><span>    PARAMS<span style="color:#5bc4bf">[</span>0<span style="color:#5bc4bf">]=</span><span style="color:#48b685">&#34;</span><span style="color:#815ba4">$(</span>printf <span style="color:#48b685">&#39;%s&#39;</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">PARAMS</span>[0]<span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> | tr -s <span style="color:#48b685">&#34;[:upper:]&#34;</span> <span style="color:#48b685">&#34;[:lower:]&#34;</span><span style="color:#815ba4">)</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#ef6155">MENU_CHOICE</span><span style="color:#5bc4bf">=</span><span style="color:#f99b15">${</span><span style="color:#ef6155">PARAMS</span>[0]<span style="color:#f99b15">}</span>
</span></span><span style="display:flex;"><span><span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">[</span> -n <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">PARAMS</span>[1]<span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> <span style="color:#5bc4bf">]</span> <span style="color:#5bc4bf">&amp;&amp;</span> <span style="color:#ef6155">domain</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#815ba4">$(</span>printf <span style="color:#48b685">&#39;%s&#39;</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">PARAMS</span>[1]<span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> | tr -s <span style="color:#48b685">&#34;[:upper:]&#34;</span> <span style="color:#48b685">&#34;[:lower:]&#34;</span><span style="color:#815ba4">)</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">################################################################################</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">####</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">##</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#   All needed functions! DO NOT TOUCH-IT!</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">##</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">###</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">################################################################################</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>_add_tlsa<span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	check_var_algo
</span></span><span style="display:flex;"><span>	check_var_soa_serial_type
</span></span><span style="display:flex;"><span>	check_var_tls_port
</span></span><span style="display:flex;"><span>	check_var_tls_proto
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	check_tlsa_methods
</span></span><span style="display:flex;"><span>	check_tlsa_selectors
</span></span><span style="display:flex;"><span>	check_tlsa_usages
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	get_soa_ns
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#ef6155">danefile</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">zonefile</span><span style="color:#f99b15">}</span><span style="color:#48b685">.dane&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#ef6155">newzonefile</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">zonefile</span><span style="color:#f99b15">}</span><span style="color:#48b685">.</span><span style="color:#f99b15">${</span><span style="color:#ef6155">today</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#ef6155">oldzonefile</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">zonefile</span><span style="color:#f99b15">}</span><span style="color:#48b685">.</span><span style="color:#f99b15">${</span><span style="color:#ef6155">OLD_SOA_sn</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>    create_new_filezone
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">if</span> <span style="color:#5bc4bf">[</span> -f <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">newzonefile</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> <span style="color:#5bc4bf">]</span>; <span style="color:#815ba4">then</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		write_soa_serial_number
</span></span><span style="display:flex;"><span>		
</span></span><span style="display:flex;"><span>		build_tlsa_record
</span></span><span style="display:flex;"><span>		write_tlsa_record
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		mv_new_file_zone
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		<span style="color:#815ba4">if</span> _resign; <span style="color:#815ba4">then</span> del_old_zonefile; <span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>		
</span></span><span style="display:flex;"><span>	<span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	unset danefile newzonefile oldzonefile
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>build_needed_variables<span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>    check_var_domain
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span>    printf <span style="color:#48b685">&#39;%s\n&#39;</span> <span style="color:#48b685">&#34;*** Build needed variables:&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#776e71"># build cert variable if menu &#39;tlsa&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">if</span> <span style="color:#5bc4bf">[</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">MENU_CHOICE</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> <span style="color:#5bc4bf">=</span> <span style="color:#48b685">&#34;tlsa&#34;</span> <span style="color:#5bc4bf">]</span>; <span style="color:#815ba4">then</span>
</span></span><span style="display:flex;"><span>        <span style="color:#ef6155">cert</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">dir_le</span><span style="color:#f99b15">}</span><span style="color:#48b685">/</span><span style="color:#f99b15">${</span><span style="color:#ef6155">domain</span><span style="color:#f99b15">}</span><span style="color:#48b685">/cert.pem&#34;</span>
</span></span><span style="display:flex;"><span>        
</span></span><span style="display:flex;"><span>        <span style="color:#815ba4">if</span> <span style="color:#5bc4bf">[</span> ! -f <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">cert</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> <span style="color:#5bc4bf">]</span>; <span style="color:#815ba4">then</span>
</span></span><span style="display:flex;"><span>			display_mssg <span style="color:#48b685">&#34;KO&#34;</span> <span style="color:#48b685">&#34;*** It seems cert file not exists!&#34;</span>
</span></span><span style="display:flex;"><span>			byebye
</span></span><span style="display:flex;"><span>		<span style="color:#815ba4">else</span>
</span></span><span style="display:flex;"><span>			printf <span style="color:#48b685">&#39;%s\n&#39;</span> <span style="color:#48b685">&#34;cert: </span><span style="color:#f99b15">${</span><span style="color:#ef6155">cert</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>		<span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#776e71"># build zonedir and zonefile variables</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ef6155">zonedir</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#815ba4">$(</span>awk -F <span style="color:#48b685">&#39;&#34;&#39;</span> <span style="color:#48b685">&#39;/zonesdir/ { print substr($2,-1) }&#39;</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">nsd_cfg</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span><span style="color:#815ba4">)</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">if</span> <span style="color:#5bc4bf">[</span> -z <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">zonedir</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> <span style="color:#5bc4bf">]</span>; <span style="color:#815ba4">then</span> <span style="color:#ef6155">zonedir</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;/var/nsd/zones/&#34;</span>; <span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>    printf <span style="color:#48b685">&#39;%s\n&#39;</span> <span style="color:#48b685">&#34;zonedir: </span><span style="color:#f99b15">${</span><span style="color:#ef6155">zonedir</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#776e71">#zonefile=&#34;$(awk -F &#39;&#34;&#39; &#39;/zonefile: &#34;[a-z]*\/&#39;&#34;${domain}&#34;&#39;&#34;/ { print substr($2, -1) }&#39; &#34;${nsd_cfg}&#34;)&#34;    </span>
</span></span><span style="display:flex;"><span>    <span style="color:#776e71">#if [ &#34;$(printf &#39;%s&#39; &#34;${zonefile}&#34; | awk -F&#39;/&#39; &#39;{ print $1}&#39;)&#34; == &#34;signed&#34; ]; then</span>
</span></span><span style="display:flex;"><span>        <span style="color:#776e71">##zonefilesigned=$zonefile        </span>
</span></span><span style="display:flex;"><span>        <span style="color:#776e71">#zonefile=&#34;$(find &#34;${dir_ns_cfg}&#34; -name &#34;${domain}&#34;)&#34;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#776e71">#if [ -z &#34;${zonefile}&#34; ]; then zonefile=&#34;$(find &#34;${zonedir}&#34; -name &#34;${domain}&#34;)&#34;; fi</span>
</span></span><span style="display:flex;"><span>        <span style="color:#776e71">#if [ -z &#34;${zonefile}&#34; ]; then</span>
</span></span><span style="display:flex;"><span>            <span style="color:#776e71">#display_mssg &#34;KO&#34; &#34;ERROR: It seems zonefile for domain: &#39;${domain}&#39; not exists!&#34;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#776e71">#byebye</span>
</span></span><span style="display:flex;"><span>        <span style="color:#776e71">#fi</span>
</span></span><span style="display:flex;"><span>    <span style="color:#776e71">#else</span>
</span></span><span style="display:flex;"><span>        <span style="color:#776e71">#zonefile=&#34;${zonedir}${zonefile}&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#776e71">#fi</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ef6155">zonefile</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">dir_ns_cfg</span><span style="color:#f99b15">}</span><span style="color:#48b685">/</span><span style="color:#f99b15">${</span><span style="color:#ef6155">domain</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>    printf <span style="color:#48b685">&#39;%s\n&#39;</span> <span style="color:#48b685">&#34;zonefile: </span><span style="color:#f99b15">${</span><span style="color:#ef6155">zonefile</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>build_tlsa_record<span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#776e71"># get TLSA by reading cert pem</span>
</span></span><span style="display:flex;"><span>	<span style="color:#815ba4">case</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">le_key_type</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> in 
</span></span><span style="display:flex;"><span>		<span style="color:#48b685">&#34;ecdsa&#34;</span><span style="color:#5bc4bf">)</span>
</span></span><span style="display:flex;"><span>			<span style="color:#ef6155">command</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;ec&#34;</span>
</span></span><span style="display:flex;"><span>		;;
</span></span><span style="display:flex;"><span>		<span style="color:#48b685">&#34;rsa&#34;</span><span style="color:#5bc4bf">)</span>
</span></span><span style="display:flex;"><span>			<span style="color:#ef6155">command</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;rsa&#34;</span>
</span></span><span style="display:flex;"><span>		;;
</span></span><span style="display:flex;"><span>	<span style="color:#815ba4">esac</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#ef6155">tlsa_cert_associated</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#815ba4">$(</span>openssl x509 -noout -pubkey -in <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">cert</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> | openssl <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">command</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> -pubin -outform der 2&gt;/dev/null | <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">algo</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span><span style="color:#815ba4">)</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>    _log <span style="color:#48b685">&#34;TLSA Cert Associated: </span><span style="color:#f99b15">${</span><span style="color:#ef6155">tlsa_cert_associated</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>    unset command
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">if</span> <span style="color:#5bc4bf">[</span> -z <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">tlsa_cert_associated</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> <span style="color:#5bc4bf">]</span>; <span style="color:#815ba4">then</span>
</span></span><span style="display:flex;"><span>        display_mssg <span style="color:#48b685">&#34;KO&#34;</span> <span style="color:#48b685">&#34;ERROR: TLSA Cert Associated could not generated!&#34;</span>
</span></span><span style="display:flex;"><span>        byebye
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">else</span>
</span></span><span style="display:flex;"><span>        <span style="color:#776e71"># rebuild tlsa method segun algo choosed; possible: 0 (no match), 1 (sha256), 2 (sha512)</span>
</span></span><span style="display:flex;"><span>        <span style="color:#815ba4">case</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">algo</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> in
</span></span><span style="display:flex;"><span>            <span style="color:#48b685">&#34;sha256&#34;</span><span style="color:#5bc4bf">)</span> <span style="color:#ef6155">tlsa_method</span><span style="color:#5bc4bf">=</span><span style="color:#f99b15">1</span> ;;
</span></span><span style="display:flex;"><span>            <span style="color:#48b685">&#34;sha512&#34;</span><span style="color:#5bc4bf">)</span> <span style="color:#ef6155">tlsa_method</span><span style="color:#5bc4bf">=</span><span style="color:#f99b15">2</span> ;;
</span></span><span style="display:flex;"><span>            *<span style="color:#5bc4bf">)</span> <span style="color:#ef6155">tlsa_method</span><span style="color:#5bc4bf">=</span><span style="color:#f99b15">0</span> ;;
</span></span><span style="display:flex;"><span>        <span style="color:#815ba4">esac</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		<span style="color:#815ba4">if</span> <span style="color:#5bc4bf">[</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">tls_port</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> <span style="color:#5bc4bf">=</span> <span style="color:#48b685">&#34;443&#34;</span> <span style="color:#5bc4bf">]</span> <span style="color:#5bc4bf">&amp;&amp;</span> <span style="color:#5bc4bf">[</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">tls_proto</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> <span style="color:#5bc4bf">=</span> <span style="color:#48b685">&#34;tcp&#34;</span> <span style="color:#5bc4bf">]</span>; <span style="color:#815ba4">then</span>
</span></span><span style="display:flex;"><span>			get_dns_alternative_names
</span></span><span style="display:flex;"><span>			<span style="color:#ef6155">count</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#f99b15">${#</span><span style="color:#ef6155">domains</span>[@]<span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>			
</span></span><span style="display:flex;"><span>			<span style="color:#815ba4">if</span> <span style="color:#5bc4bf">[</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">count</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> -eq <span style="color:#f99b15">1</span> <span style="color:#5bc4bf">]</span>; <span style="color:#815ba4">then</span>
</span></span><span style="display:flex;"><span>				set_tlsa_record			
</span></span><span style="display:flex;"><span>			<span style="color:#815ba4">else</span>
</span></span><span style="display:flex;"><span>				set_tlsa_records
</span></span><span style="display:flex;"><span>			<span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>			
</span></span><span style="display:flex;"><span>        <span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    unset tlsa_cert_associated
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>byebye<span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    display_mssg <span style="color:#48b685">&#34;KO&#34;</span> <span style="color:#48b685">&#34;Script stop here!&#34;</span>
</span></span><span style="display:flex;"><span>    display_mssg <span style="color:#48b685">&#34;KO&#34;</span> <span style="color:#48b685">&#34;Please, search to understand reasons.&#34;</span>
</span></span><span style="display:flex;"><span>    exit <span style="color:#f99b15">1</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>check_domain_name<span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#ef6155">pattern</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])</span>$<span style="color:#48b685">&#34;</span> <span style="color:#776e71"># like RFC 1123</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">if</span> <span style="color:#5bc4bf">[</span> <span style="color:#f99b15">${#</span><span style="color:#ef6155">domain</span><span style="color:#f99b15">}</span> -gt <span style="color:#f99b15">67</span> <span style="color:#5bc4bf">]</span>; <span style="color:#815ba4">then</span>    <span style="color:#776e71"># Larg domain name &lt;= 67</span>
</span></span><span style="display:flex;"><span>        display_mssg <span style="color:#48b685">&#34;KO&#34;</span> <span style="color:#48b685">&#34;Error: Domain Length: </span><span style="color:#f99b15">${</span><span style="color:#ef6155">domain</span><span style="color:#f99b15">}</span><span style="color:#48b685">; &gt;= 67 carachters!&#34;</span>
</span></span><span style="display:flex;"><span>        byebye
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">if</span> printf <span style="color:#48b685">&#39;%s\n&#39;</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">domain</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> | grep -Eio <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">pattern</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>; <span style="color:#815ba4">then</span>
</span></span><span style="display:flex;"><span>        display_mssg <span style="color:#48b685">&#34;OK&#34;</span> <span style="color:#48b685">&#34;Domain Name: </span><span style="color:#f99b15">${</span><span style="color:#ef6155">domain</span><span style="color:#f99b15">}</span><span style="color:#48b685"> is valid!&#34;</span>
</span></span><span style="display:flex;"><span>        sleep <span style="color:#f99b15">1</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">else</span>
</span></span><span style="display:flex;"><span>        display_mssg <span style="color:#48b685">&#34;KO&#34;</span> <span style="color:#48b685">&#34;Error: Bad Domain Name: </span><span style="color:#f99b15">${</span><span style="color:#ef6155">domain</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>        byebye
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    unset pattern
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>check_tlsa_methods<span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#815ba4">case</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">tlsa_method</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> in 
</span></span><span style="display:flex;"><span>		0|<span style="color:#48b685">&#34;FULL&#34;</span><span style="color:#5bc4bf">)</span> 	<span style="color:#ef6155">tlsa_method</span><span style="color:#5bc4bf">=</span><span style="color:#f99b15">0</span> ;; 
</span></span><span style="display:flex;"><span>		1|<span style="color:#48b685">&#34;SHA256&#34;</span><span style="color:#5bc4bf">)</span> <span style="color:#ef6155">tlsa_method</span><span style="color:#5bc4bf">=</span><span style="color:#f99b15">1</span> ;;
</span></span><span style="display:flex;"><span>		2|<span style="color:#48b685">&#34;SHA512&#34;</span><span style="color:#5bc4bf">)</span>	<span style="color:#ef6155">tlsa_method</span><span style="color:#5bc4bf">=</span><span style="color:#f99b15">2</span> ;;
</span></span><span style="display:flex;"><span>		*<span style="color:#5bc4bf">)</span>
</span></span><span style="display:flex;"><span>			display_mssg <span style="color:#48b685">&#34;KO&#34;</span> <span style="color:#48b685">&#34;/!\  The TLSA Method: not correctly configurated!&#34;</span>
</span></span><span style="display:flex;"><span>			byebye
</span></span><span style="display:flex;"><span>		::
</span></span><span style="display:flex;"><span>	<span style="color:#815ba4">esac</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	_log <span style="color:#48b685">&#34;TLSA Method: </span><span style="color:#f99b15">${</span><span style="color:#ef6155">tlsa_method</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>check_tlsa_selectors<span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#815ba4">case</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">tlsa_selector</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> in 
</span></span><span style="display:flex;"><span>		0|<span style="color:#48b685">&#34;CERT&#34;</span><span style="color:#5bc4bf">)</span> 	<span style="color:#ef6155">tlsa_selector</span><span style="color:#5bc4bf">=</span><span style="color:#f99b15">0</span> ;; 
</span></span><span style="display:flex;"><span>		1|<span style="color:#48b685">&#34;SPKI&#34;</span><span style="color:#5bc4bf">)</span> 	<span style="color:#ef6155">tlsa_selector</span><span style="color:#5bc4bf">=</span><span style="color:#f99b15">1</span> ;;
</span></span><span style="display:flex;"><span>		*<span style="color:#5bc4bf">)</span>
</span></span><span style="display:flex;"><span>			display_mssg <span style="color:#48b685">&#34;KO&#34;</span> <span style="color:#48b685">&#34;/!\  The TLSA Selector: not correctly configurated!&#34;</span>
</span></span><span style="display:flex;"><span>			byebye
</span></span><span style="display:flex;"><span>		;;
</span></span><span style="display:flex;"><span>	<span style="color:#815ba4">esac</span>
</span></span><span style="display:flex;"><span>	_log <span style="color:#48b685">&#34;TLSA Selector: </span><span style="color:#f99b15">${</span><span style="color:#ef6155">tlsa_selector</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>check_tlsa_usages<span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#815ba4">case</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">tlsa_usage</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> in 
</span></span><span style="display:flex;"><span>		0|<span style="color:#48b685">&#34;PKIX-TA&#34;</span><span style="color:#5bc4bf">)</span> 	<span style="color:#ef6155">tlsa_usage</span><span style="color:#5bc4bf">=</span><span style="color:#f99b15">0</span> ;; 
</span></span><span style="display:flex;"><span>		1|<span style="color:#48b685">&#34;PKIX-EE&#34;</span><span style="color:#5bc4bf">)</span> 	<span style="color:#ef6155">tlsa_usage</span><span style="color:#5bc4bf">=</span><span style="color:#f99b15">1</span> ;;
</span></span><span style="display:flex;"><span>		2|<span style="color:#48b685">&#34;DANE-TA&#34;</span><span style="color:#5bc4bf">)</span>	<span style="color:#ef6155">tlsa_usage</span><span style="color:#5bc4bf">=</span><span style="color:#f99b15">2</span> ;;
</span></span><span style="display:flex;"><span>		3|<span style="color:#48b685">&#34;DANE-EE&#34;</span><span style="color:#5bc4bf">)</span>	<span style="color:#ef6155">tlsa_usage</span><span style="color:#5bc4bf">=</span><span style="color:#f99b15">3</span> ;;
</span></span><span style="display:flex;"><span>		*<span style="color:#5bc4bf">)</span>
</span></span><span style="display:flex;"><span>			display_mssg <span style="color:#48b685">&#34;KO&#34;</span> <span style="color:#48b685">&#34;/!\  The TLSA Usage: not correctly configurated!&#34;</span>
</span></span><span style="display:flex;"><span>			byebye
</span></span><span style="display:flex;"><span>		;;
</span></span><span style="display:flex;"><span>	<span style="color:#815ba4">esac</span>
</span></span><span style="display:flex;"><span>	_log <span style="color:#48b685">&#34;TLSA Usage: </span><span style="color:#f99b15">${</span><span style="color:#ef6155">tlsa_usage</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>check_uid<span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">if</span> <span style="color:#5bc4bf">[</span> <span style="color:#48b685">&#34;</span><span style="color:#815ba4">$(</span>id -u<span style="color:#815ba4">)</span><span style="color:#48b685">&#34;</span> -ne <span style="color:#f99b15">0</span> <span style="color:#5bc4bf">]</span>; <span style="color:#815ba4">then</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        display_mssg <span style="color:#48b685">&#34;KO&#34;</span> <span style="color:#48b685">&#34;ERROR: Script not launch with rights admin!&#34;</span>
</span></span><span style="display:flex;"><span>        byebye
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>check_var_algo <span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#815ba4">if</span> <span style="color:#5bc4bf">[</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">algo</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> !<span style="color:#5bc4bf">=</span> <span style="color:#48b685">&#34;sha256&#34;</span> <span style="color:#5bc4bf">]</span> <span style="color:#5bc4bf">&amp;&amp;</span> <span style="color:#5bc4bf">[</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">algo</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> !<span style="color:#5bc4bf">=</span> <span style="color:#48b685">&#34;sha512&#34;</span> <span style="color:#5bc4bf">]</span>; <span style="color:#815ba4">then</span>
</span></span><span style="display:flex;"><span>			display_mssg <span style="color:#48b685">&#34;KO&#34;</span> <span style="color:#48b685">&#34;/!\ Algorythm: not correctly configurated!&#34;</span>
</span></span><span style="display:flex;"><span>			byebye
</span></span><span style="display:flex;"><span>	<span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>	_log <span style="color:#48b685">&#34;Algo: </span><span style="color:#f99b15">${</span><span style="color:#ef6155">algo</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>check_var_domain<span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#815ba4">if</span> <span style="color:#5bc4bf">[</span> -z <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">domain</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> <span style="color:#5bc4bf">]</span>; <span style="color:#815ba4">then</span>
</span></span><span style="display:flex;"><span>        display_mssg <span style="color:#48b685">&#34;KO&#34;</span> <span style="color:#48b685">&#34;*** It seems fault informations!&#34;</span>
</span></span><span style="display:flex;"><span>        help
</span></span><span style="display:flex;"><span>        byebye
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>    _log <span style="color:#48b685">&#34;Domain: </span><span style="color:#f99b15">${</span><span style="color:#ef6155">domain</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>check_var_soa_serial_type<span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#815ba4">if</span> <span style="color:#5bc4bf">[</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">SOA_serial_type</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> !<span style="color:#5bc4bf">=</span> <span style="color:#48b685">&#34;date&#34;</span> <span style="color:#5bc4bf">]</span> <span style="color:#5bc4bf">&amp;&amp;</span> <span style="color:#5bc4bf">[</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">SOA_serial_type</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> !<span style="color:#5bc4bf">=</span> <span style="color:#48b685">&#34;timestamp&#34;</span> <span style="color:#5bc4bf">]</span>; <span style="color:#815ba4">then</span>
</span></span><span style="display:flex;"><span>			display_mssg <span style="color:#48b685">&#34;KO&#34;</span> <span style="color:#48b685">&#34;/!\ SOA Serial Type: not correctly configurated!&#34;</span>
</span></span><span style="display:flex;"><span>			byebye
</span></span><span style="display:flex;"><span>	<span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>	_log <span style="color:#48b685">&#34;SOA Serial Type: </span><span style="color:#f99b15">${</span><span style="color:#ef6155">SOA_serial_type</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>check_var_tls_port<span style="color:#5bc4bf">(){</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#815ba4">if</span> <span style="color:#5bc4bf">[</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">tls_port</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> -lt <span style="color:#f99b15">0</span> <span style="color:#5bc4bf">]</span>; <span style="color:#815ba4">then</span>
</span></span><span style="display:flex;"><span>		display_mssg <span style="color:#48b685">&#34;KO&#34;</span> <span style="color:#48b685">&#34;/!\ TLS port: not correctly configurated!&#34;</span>
</span></span><span style="display:flex;"><span>		byebye
</span></span><span style="display:flex;"><span>	<span style="color:#815ba4">fi</span> 
</span></span><span style="display:flex;"><span>	_log <span style="color:#48b685">&#34;TLS port: </span><span style="color:#f99b15">${</span><span style="color:#ef6155">tls_port</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>check_var_tls_proto<span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#815ba4">if</span> <span style="color:#5bc4bf">[</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">tls_proto</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> !<span style="color:#5bc4bf">=</span> <span style="color:#48b685">&#34;sctp&#34;</span> <span style="color:#5bc4bf">]</span> <span style="color:#5bc4bf">&amp;&amp;</span> <span style="color:#5bc4bf">[</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">tls_proto</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> !<span style="color:#5bc4bf">=</span> <span style="color:#48b685">&#34;tcp&#34;</span> <span style="color:#5bc4bf">]</span> <span style="color:#5bc4bf">&amp;&amp;</span> <span style="color:#5bc4bf">[</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">tls_proto</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> !<span style="color:#5bc4bf">=</span> <span style="color:#48b685">&#34;tcp&#34;</span> <span style="color:#5bc4bf">]</span>; <span style="color:#815ba4">then</span>
</span></span><span style="display:flex;"><span>			display_mssg <span style="color:#48b685">&#34;KO&#34;</span> <span style="color:#48b685">&#34;/!\ TLS proto: not correctly configurated!&#34;</span>
</span></span><span style="display:flex;"><span>			byebye
</span></span><span style="display:flex;"><span>	<span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>	_log <span style="color:#48b685">&#34;TLS proto: </span><span style="color:#f99b15">${</span><span style="color:#ef6155">tls_proto</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>checkconf<span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    nsd-checkconf <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">nsd_cfg</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>checkzone<span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    nsd-checkzone <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">domain</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">zonefile</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>confirm <span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    read -r response?<span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">1</span><span style="color:#f99b15">}</span><span style="color:#48b685"> [y|n] &#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">case</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">response</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> in
</span></span><span style="display:flex;"><span>        <span style="color:#776e71"># &#39;o&#39;, &#39;O&#39;: Oui and not 0!</span>
</span></span><span style="display:flex;"><span>        y|Y|o|O|1<span style="color:#5bc4bf">)</span>  true ;;
</span></span><span style="display:flex;"><span>        *<span style="color:#5bc4bf">)</span>          false ;;
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">esac</span>
</span></span><span style="display:flex;"><span>    unset response
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>create_new_filezone<span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	cp <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">zonefile</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">newzonefile</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>del_old_zonefile<span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">if</span> <span style="color:#5bc4bf">[</span> -f <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">oldzonefile</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> <span style="color:#5bc4bf">]</span>; <span style="color:#815ba4">then</span>
</span></span><span style="display:flex;"><span>        rm -fP <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">oldzonefile</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>display_mssg<span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    typeset statut info text
</span></span><span style="display:flex;"><span>    <span style="color:#ef6155">statut</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#ef6155">$1</span><span style="color:#48b685">&#34;</span> <span style="color:#ef6155">info</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#ef6155">$2</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">case</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">statut</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> in
</span></span><span style="display:flex;"><span>        <span style="color:#48b685">&#34;KO&#34;</span><span style="color:#5bc4bf">)</span> <span style="color:#ef6155">text</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;[ </span><span style="color:#f99b15">${</span><span style="color:#ef6155">red</span><span style="color:#f99b15">}${</span><span style="color:#ef6155">statut</span><span style="color:#f99b15">}${</span><span style="color:#ef6155">neutral</span><span style="color:#f99b15">}</span><span style="color:#48b685"> ]    </span><span style="color:#f99b15">${</span><span style="color:#ef6155">info</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> ;;
</span></span><span style="display:flex;"><span>        <span style="color:#48b685">&#34;OK&#34;</span><span style="color:#5bc4bf">)</span> <span style="color:#ef6155">text</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;[ </span><span style="color:#f99b15">${</span><span style="color:#ef6155">green</span><span style="color:#f99b15">}${</span><span style="color:#ef6155">statut</span><span style="color:#f99b15">}${</span><span style="color:#ef6155">neutral</span><span style="color:#f99b15">}</span><span style="color:#48b685"> ]   </span><span style="color:#f99b15">${</span><span style="color:#ef6155">info</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> ;;
</span></span><span style="display:flex;"><span>        <span style="color:#776e71">#*) mssg=&#34;${text}&#34; ;;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">esac</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    printf <span style="color:#48b685">&#34;%s \n&#34;</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">text</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    unset info statut text
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>get_dns_alternative_names<span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#776e71"># get &#34;X509 DNS Alternative Names&#34; characters</span>
</span></span><span style="display:flex;"><span>	<span style="color:#ef6155">domains</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#815ba4">$(</span>echo | openssl x509 -text -noout -in <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">cert</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> | awk -F <span style="color:#48b685">&#39;,&#39;</span> <span style="color:#48b685">&#39;/DNS:/ { for(i=1;i&lt;NF;i++) { p=match($i,&#34;:&#34;); print substr($i,p+1) }}&#39;</span><span style="color:#815ba4">)</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#776e71"># convert into array; no double-quotes, else not run!</span>
</span></span><span style="display:flex;"><span>	set -A domains -- <span style="color:#f99b15">${</span><span style="color:#ef6155">domains</span>[@]<span style="color:#f99b15">}</span>
</span></span><span style="display:flex;"><span>	printf <span style="color:#48b685">&#39;%s\n&#39;</span> <span style="color:#48b685">&#34;domains: </span><span style="color:#f99b15">${</span><span style="color:#ef6155">domains</span>[*]<span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>	_log <span style="color:#48b685">&#34;domains: </span><span style="color:#f99b15">${</span><span style="color:#ef6155">domains</span>[*]<span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>get_soa_ns<span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#ef6155">OLD_SOA_sn</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#815ba4">$(</span>grep -A1 <span style="color:#48b685">&#34;SOA&#34;</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">zonefile</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> | tail -n1 | awk -F <span style="color:#48b685">&#39; &#39;</span> <span style="color:#48b685">&#39;{ print $1 }&#39;</span><span style="color:#815ba4">)</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>	_log <span style="color:#48b685">&#34;Old SOA Serial Number: </span><span style="color:#f99b15">${</span><span style="color:#ef6155">OLD_SOA_sn</span><span style="color:#f99b15">}</span><span style="color:#48b685">!&#34;</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>get_soa_serial_number<span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#ef6155">OLD_SOA_sn</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#815ba4">$(</span>printf <span style="color:#48b685">&#39;%s\n&#39;</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">line</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> | awk -F <span style="color:#48b685">&#39; &#39;</span> <span style="color:#48b685">&#39;{ print $1 }&#39;</span><span style="color:#815ba4">)</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>	_log <span style="color:#48b685">&#34;OLD SOA Serial Number: </span><span style="color:#f99b15">${</span><span style="color:#ef6155">OLD_SOA_sn</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>help<span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    printf <span style="color:#48b685">&#39;%s\n&#39;</span> <span style="color:#48b685">&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#48b685">    </span><span style="color:#ef6155">$0</span><span style="color:#48b685"> sign domain      # to sign a domain
</span></span></span><span style="display:flex;"><span><span style="color:#48b685">    </span><span style="color:#ef6155">$0</span><span style="color:#48b685"> tlsa domain      # to add a tlsa record into domain zone
</span></span></span><span style="display:flex;"><span><span style="color:#48b685">    ----
</span></span></span><span style="display:flex;"><span><span style="color:#48b685">    when use tlsa, this script will resign the domain zone...
</span></span></span><span style="display:flex;"><span><span style="color:#48b685">    &#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>init_zone<span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">dir_sbin</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>/ldnscript init <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">domain</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>in_array<span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span>    local <span style="color:#ef6155">i</span><span style="color:#5bc4bf">=</span><span style="color:#f99b15">0</span> <span style="color:#ef6155">need</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#ef6155">$1</span><span style="color:#48b685">&#34;</span> <span style="color:#ef6155">IFS</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34; &#34;</span>; shift; set -A array -- <span style="color:#ef6155">$*</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ef6155">count</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#f99b15">${#</span><span style="color:#ef6155">array</span>[@]<span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">while</span> <span style="color:#5bc4bf">[</span> <span style="color:#ef6155">$i</span> -le <span style="color:#ef6155">$count</span> <span style="color:#5bc4bf">]</span>; <span style="color:#815ba4">do</span>
</span></span><span style="display:flex;"><span>        <span style="color:#815ba4">if</span> <span style="color:#5bc4bf">[</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">array</span>[<span style="color:#ef6155">$i</span>]<span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> <span style="color:#5bc4bf">=</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">need</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> <span style="color:#5bc4bf">]</span>; <span style="color:#815ba4">then</span> <span style="color:#815ba4">return</span> 0; <span style="color:#815ba4">fi</span> <span style="color:#776e71"># true</span>
</span></span><span style="display:flex;"><span>        <span style="color:#776e71">#let &#34;i=$i+1&#34;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#5bc4bf">((</span> <span style="color:#ef6155">i</span><span style="color:#5bc4bf">=</span>i+1 <span style="color:#5bc4bf">))</span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">done</span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">return</span> <span style="color:#f99b15">1</span>
</span></span><span style="display:flex;"><span>    unset i need IFS array
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>_log<span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#815ba4">if</span> <span style="color:#5bc4bf">[</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">debug</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> -eq <span style="color:#f99b15">1</span> <span style="color:#5bc4bf">]</span>; <span style="color:#815ba4">then</span> printf <span style="color:#48b685">&#39;%s\n&#39;</span> <span style="color:#48b685">&#34;</span><span style="color:#ef6155">$1</span><span style="color:#48b685">&#34;</span> &gt;&gt; <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">log</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>; <span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>main<span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>		
</span></span><span style="display:flex;"><span>	check_uid
</span></span><span style="display:flex;"><span>	verify_need_softs
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	build_needed_variables
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>    check_domain_name
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">case</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">MENU_CHOICE</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> in
</span></span><span style="display:flex;"><span>        <span style="color:#48b685">&#34;help&#34;</span><span style="color:#5bc4bf">)</span> help ;;
</span></span><span style="display:flex;"><span>        <span style="color:#48b685">&#34;sign&#34;</span><span style="color:#5bc4bf">)</span> _resign ;;
</span></span><span style="display:flex;"><span>        <span style="color:#48b685">&#34;tlsa&#34;</span><span style="color:#5bc4bf">)</span> _add_tlsa ;;
</span></span><span style="display:flex;"><span>        *<span style="color:#5bc4bf">)</span>
</span></span><span style="display:flex;"><span>            display_mssg <span style="color:#48b685">&#34;KO&#34;</span> <span style="color:#48b685">&#34;ERROR: this option </span><span style="color:#f99b15">${</span><span style="color:#ef6155">MENU_CHOICE</span><span style="color:#f99b15">}</span><span style="color:#48b685"> is not exists!&#34;</span>
</span></span><span style="display:flex;"><span>            help
</span></span><span style="display:flex;"><span>            byebye
</span></span><span style="display:flex;"><span>        ;;
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">esac</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>mv_new_file_zone<span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">if</span> <span style="color:#5bc4bf">[</span> -f <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">newzonefile</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> <span style="color:#5bc4bf">]</span>; <span style="color:#815ba4">then</span>
</span></span><span style="display:flex;"><span>        mv <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">zonefile</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">oldzonefile</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>        mv <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">newzonefile</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">zonefile</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>_resign<span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">if</span> checkzone <span style="color:#5bc4bf">&amp;&amp;</span> checkconf; <span style="color:#815ba4">then</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        display_mssg <span style="color:#48b685">&#34;OK&#34;</span> <span style="color:#48b685">&#34;file config nsd and zone </span><span style="color:#f99b15">${</span><span style="color:#ef6155">domain</span><span style="color:#f99b15">}</span><span style="color:#48b685"> are good! :D&#34;</span>
</span></span><span style="display:flex;"><span>        sign_zone
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">else</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        display_mssg <span style="color:#48b685">&#34;KO&#34;</span> <span style="color:#48b685">&#34;ERROR: it exists a problem with file config nsd or zone </span><span style="color:#f99b15">${</span><span style="color:#ef6155">domain</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>        byebye
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>restart_server<span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>    printf <span style="color:#48b685">&#39;%s\n&#39;</span> <span style="color:#48b685">&#34;=&gt; Restart Server: &#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    stop_server
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    start_server
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    status_server
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>set_soa_serial_number<span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">case</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">SOA_serial_type</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> in
</span></span><span style="display:flex;"><span>        <span style="color:#48b685">&#34;date&#34;</span><span style="color:#5bc4bf">)</span>
</span></span><span style="display:flex;"><span>            <span style="color:#ef6155">SOA_date</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#815ba4">$(</span>printf <span style="color:#48b685">&#39;%s&#39;</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">OLD_SOA_sn</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> | awk <span style="color:#48b685">&#39;{print substr($0, 0, 8)}&#39;</span><span style="color:#815ba4">)</span><span style="color:#48b685">&#34;</span>;
</span></span><span style="display:flex;"><span>            <span style="color:#ef6155">SOA_number</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#815ba4">$(</span>printf <span style="color:#48b685">&#39;%s&#39;</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">OLD_SOA_sn</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> | awk <span style="color:#48b685">&#39;{print substr($0, 9)}&#39;</span><span style="color:#815ba4">)</span><span style="color:#48b685">&#34;</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>            <span style="color:#815ba4">if</span> <span style="color:#5bc4bf">[</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">SOA_date</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> <span style="color:#5bc4bf">==</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">today</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> <span style="color:#5bc4bf">]</span>; <span style="color:#815ba4">then</span>
</span></span><span style="display:flex;"><span>                <span style="color:#776e71">#let SOA_number=$SOA_number+1</span>
</span></span><span style="display:flex;"><span>                <span style="color:#5bc4bf">((</span> <span style="color:#ef6155">SOA_number</span><span style="color:#5bc4bf">=</span><span style="color:#f99b15">${</span><span style="color:#ef6155">SOA_number</span><span style="color:#f99b15">}</span>+1 <span style="color:#5bc4bf">))</span> <span style="color:#5bc4bf">||</span> true
</span></span><span style="display:flex;"><span>                <span style="color:#815ba4">if</span> <span style="color:#5bc4bf">[</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">SOA_number</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> -lt <span style="color:#f99b15">10</span> <span style="color:#5bc4bf">]</span>; <span style="color:#815ba4">then</span> <span style="color:#ef6155">SOA_number</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;0</span><span style="color:#f99b15">${</span><span style="color:#ef6155">SOA_number</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>; <span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>                <span style="color:#ef6155">SOA_sn</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">SOA_date</span><span style="color:#f99b15">}${</span><span style="color:#ef6155">SOA_number</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#815ba4">else</span>
</span></span><span style="display:flex;"><span>                <span style="color:#ef6155">SOA_sn</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">today</span><span style="color:#f99b15">}</span><span style="color:#48b685">01&#34;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>        ;;
</span></span><span style="display:flex;"><span>        <span style="color:#48b685">&#34;timestamp&#34;</span><span style="color:#5bc4bf">)</span>
</span></span><span style="display:flex;"><span>            <span style="color:#ef6155">SOA_sn</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">timestamp</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>        ;;
</span></span><span style="display:flex;"><span>        *<span style="color:#5bc4bf">)</span>
</span></span><span style="display:flex;"><span>			display_mssg <span style="color:#48b685">&#34;KO&#34;</span> <span style="color:#48b685">&#34;Invalid SOA Serial Type!&#34;</span>
</span></span><span style="display:flex;"><span>			byebye
</span></span><span style="display:flex;"><span>        ;;
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">esac</span>
</span></span><span style="display:flex;"><span>    _log <span style="color:#48b685">&#34;New SOA Serial Number: </span><span style="color:#f99b15">${</span><span style="color:#ef6155">SOA_sn</span><span style="color:#f99b15">}</span><span style="color:#48b685">!&#34;</span>
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>set_tlsa_record<span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#776e71"># build tlsa record</span>
</span></span><span style="display:flex;"><span>	tlsa_records<span style="color:#5bc4bf">[</span>0<span style="color:#5bc4bf">]=</span><span style="color:#48b685">&#34;_</span><span style="color:#f99b15">${</span><span style="color:#ef6155">tls_port</span><span style="color:#f99b15">}</span><span style="color:#48b685">._</span><span style="color:#f99b15">${</span><span style="color:#ef6155">tls_proto</span><span style="color:#f99b15">}</span><span style="color:#48b685">.</span><span style="color:#f99b15">${</span><span style="color:#ef6155">domains</span>[0]<span style="color:#f99b15">}</span><span style="color:#48b685">. IN TLSA </span><span style="color:#f99b15">${</span><span style="color:#ef6155">tlsa_usage</span><span style="color:#f99b15">}</span><span style="color:#48b685"> </span><span style="color:#f99b15">${</span><span style="color:#ef6155">tlsa_selector</span><span style="color:#f99b15">}</span><span style="color:#48b685"> </span><span style="color:#f99b15">${</span><span style="color:#ef6155">tlsa_method</span><span style="color:#f99b15">}</span><span style="color:#48b685"> </span><span style="color:#f99b15">${</span><span style="color:#ef6155">tlsa_cert_associated</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>	_log <span style="color:#48b685">&#34;TLSA Record: </span><span style="color:#f99b15">${</span><span style="color:#ef6155">tlsa_records</span>[0]<span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>set_tlsa_records<span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#776e71"># do not use domain variable here</span>
</span></span><span style="display:flex;"><span>	<span style="color:#ef6155">i</span><span style="color:#5bc4bf">=</span><span style="color:#f99b15">0</span>
</span></span><span style="display:flex;"><span>	<span style="color:#815ba4">for</span> dom in <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">domains</span>[@]<span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>; <span style="color:#815ba4">do</span> 
</span></span><span style="display:flex;"><span>		tlsa_records<span style="color:#5bc4bf">[</span><span style="color:#ef6155">$i</span><span style="color:#5bc4bf">]=</span><span style="color:#48b685">&#34;_</span><span style="color:#f99b15">${</span><span style="color:#ef6155">tls_port</span><span style="color:#f99b15">}</span><span style="color:#48b685">._</span><span style="color:#f99b15">${</span><span style="color:#ef6155">tls_proto</span><span style="color:#f99b15">}</span><span style="color:#48b685">.</span><span style="color:#f99b15">${</span><span style="color:#ef6155">dom</span><span style="color:#f99b15">}</span><span style="color:#48b685">. IN TLSA </span><span style="color:#f99b15">${</span><span style="color:#ef6155">tlsa_usage</span><span style="color:#f99b15">}</span><span style="color:#48b685"> </span><span style="color:#f99b15">${</span><span style="color:#ef6155">tlsa_selector</span><span style="color:#f99b15">}</span><span style="color:#48b685"> </span><span style="color:#f99b15">${</span><span style="color:#ef6155">tlsa_method</span><span style="color:#f99b15">}</span><span style="color:#48b685"> </span><span style="color:#f99b15">${</span><span style="color:#ef6155">tlsa_cert_associated</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>		<span style="color:#5bc4bf">((</span> <span style="color:#ef6155">i</span><span style="color:#5bc4bf">=</span>i+1 <span style="color:#5bc4bf">))</span>
</span></span><span style="display:flex;"><span>	<span style="color:#815ba4">done</span>
</span></span><span style="display:flex;"><span>	unset i dom
</span></span><span style="display:flex;"><span>	_log <span style="color:#48b685">&#34;TLSA Records: </span><span style="color:#f99b15">${</span><span style="color:#ef6155">tlsa_records</span>[*]<span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>sign_zone<span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">dir_sbin</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>/ldnscript signing <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">domain</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>start_server<span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>    printf <span style="color:#48b685">&#39;%s\n&#39;</span> <span style="color:#48b685">&#34;Start serveur: </span><span style="color:#f99b15">${</span><span style="color:#ef6155">server</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>    rcctl start <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">server</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>    sleep 1s
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>status_server<span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    printf <span style="color:#48b685">&#39;%s\n&#39;</span> <span style="color:#48b685">&#34;Check serveur: </span><span style="color:#f99b15">${</span><span style="color:#ef6155">server</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>    rcctl check <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">server</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>stop_server<span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    printf <span style="color:#48b685">&#39;%s\n&#39;</span> <span style="color:#48b685">&#34;Stop serveur: </span><span style="color:#f99b15">${</span><span style="color:#ef6155">server</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>    rcctl stop <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">server</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>    sleep 1s
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>verify_need_softs<span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">if</span> <span style="color:#5bc4bf">[</span> ! -f <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">dir_sbin</span><span style="color:#f99b15">}</span><span style="color:#48b685">/ldnscript&#34;</span> <span style="color:#5bc4bf">]</span>; <span style="color:#815ba4">then</span>
</span></span><span style="display:flex;"><span>        display_mssg <span style="color:#48b685">&#34;KO&#34;</span> <span style="color:#48b685">&#34;ERROR: ldnscript seems not install!&#34;</span>
</span></span><span style="display:flex;"><span>        byebye
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">elif</span> <span style="color:#5bc4bf">[</span> ! -x <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">dir_sbin</span><span style="color:#f99b15">}</span><span style="color:#48b685">/ldnscript&#34;</span> <span style="color:#5bc4bf">]</span>; <span style="color:#815ba4">then</span>
</span></span><span style="display:flex;"><span>        display_mssg <span style="color:#48b685">&#34;KO&#34;</span> <span style="color:#48b685">&#34;ERROR: ldnscript is not executable!&#34;</span>
</span></span><span style="display:flex;"><span>        byebye
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>write_soa_serial_number<span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	set_soa_serial_number
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#815ba4">if</span> sed -i -e <span style="color:#48b685">&#34;s#\(.*\)</span><span style="color:#f99b15">${</span><span style="color:#ef6155">OLD_SOA_sn</span><span style="color:#f99b15">}</span><span style="color:#48b685"> \;#\1</span><span style="color:#f99b15">${</span><span style="color:#ef6155">SOA_sn</span><span style="color:#f99b15">}</span><span style="color:#48b685"> \;#&#34;</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">newzonefile</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>; <span style="color:#815ba4">then</span>
</span></span><span style="display:flex;"><span>		_log <span style="color:#48b685">&#34;SOA serial number changed!&#34;</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#815ba4">else</span> 
</span></span><span style="display:flex;"><span>		display_mssg <span style="color:#48b685">&#34;KO&#34;</span> <span style="color:#48b685">&#34;/!\  Script cant change SOA serial number!&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>write_tlsa_record<span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#815ba4">if</span> <span style="color:#5bc4bf">[</span> ! -f <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">danefile</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> <span style="color:#5bc4bf">]</span>; <span style="color:#815ba4">then</span> touch <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">danefile</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>; <span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>	
</span></span><span style="display:flex;"><span>	<span style="color:#ef6155">i</span><span style="color:#5bc4bf">=</span><span style="color:#f99b15">0</span>
</span></span><span style="display:flex;"><span>    <span style="color:#776e71"># add tlsa records into dns zone</span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">for</span> tlsa_record in <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">tlsa_records</span>[@]<span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>; <span style="color:#815ba4">do</span>
</span></span><span style="display:flex;"><span>		<span style="color:#ef6155">dom</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">domains</span>[<span style="color:#ef6155">$i</span>]<span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>		_log <span style="color:#48b685">&#34;domain: </span><span style="color:#ef6155">$dom</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>		<span style="color:#776e71">### /!\ ERROR with $domain /!\ </span>
</span></span><span style="display:flex;"><span>		<span style="color:#815ba4">if</span> sed -i -e <span style="color:#48b685">&#34;s#_</span><span style="color:#f99b15">${</span><span style="color:#ef6155">tls_port</span><span style="color:#f99b15">}</span><span style="color:#48b685">._</span><span style="color:#f99b15">${</span><span style="color:#ef6155">tls_proto</span><span style="color:#f99b15">}</span><span style="color:#48b685">.</span><span style="color:#f99b15">${</span><span style="color:#ef6155">dom</span><span style="color:#f99b15">}</span><span style="color:#48b685">. IN TLSA\(.*\)#</span><span style="color:#f99b15">${</span><span style="color:#ef6155">tlsa_record</span><span style="color:#f99b15">}</span><span style="color:#48b685">#&#34;</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">newzonefile</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>; <span style="color:#815ba4">then</span>
</span></span><span style="display:flex;"><span>			_log <span style="color:#48b685">&#34;TLSA Record rewrited!&#34;</span>
</span></span><span style="display:flex;"><span>						
</span></span><span style="display:flex;"><span>		<span style="color:#815ba4">else</span>
</span></span><span style="display:flex;"><span>			printf <span style="color:#48b685">&#39;%s\n&#39;</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">tlsa_record</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> &gt;&gt; <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">newzonefile</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>			_log <span style="color:#48b685">&#34;TLSA Record added!&#34;</span>
</span></span><span style="display:flex;"><span>		<span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>		
</span></span><span style="display:flex;"><span>		<span style="color:#5bc4bf">((</span> <span style="color:#ef6155">i</span><span style="color:#5bc4bf">=</span>i+1 <span style="color:#5bc4bf">))</span>
</span></span><span style="display:flex;"><span>		<span style="color:#776e71"># add record in first line into dane file</span>
</span></span><span style="display:flex;"><span>		printf <span style="color:#48b685">&#39;%s\n&#39;</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">timestamp</span><span style="color:#f99b15">}</span><span style="color:#48b685">:</span><span style="color:#f99b15">${</span><span style="color:#ef6155">tlsa_record</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> &gt;&gt; <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">danefile</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>		_log <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">timestamp</span><span style="color:#f99b15">}</span><span style="color:#48b685">:</span><span style="color:#f99b15">${</span><span style="color:#ef6155">tlsa_record</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>		unset dom
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">done</span>
</span></span><span style="display:flex;"><span>    unset i tlsa_record
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">################################################################################</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>main
</span></span></code></pre></div><hr>
<h2 id="eod">EOD</h2>
<p><strong>End Of Documentation</strong></p>
<p>Voila; this is my process to manage my DNS zones, with DNSSEC for the
TLSA records.</p>
<p>From a large and complex process, I can manage simply with the two useful commands:</p>
<ul>
<li>sign my DNS zones by DNSSEC:</li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>./dns.ksh sign domain
</span></span></code></pre></div><ul>
<li>check the TLSA records, at any time, and if necessary, regenerate them:</li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>./tlsa.sh domain
</span></span></code></pre></div><p>But if you have understood, the monthly cron takes care of it all and
makes the appropriate report, so I know how it was executed.</p>
<hr>
]]></content><summary>How to manage DNSSEC, TLSA records, to validate TLS certificates on OpenBSD with nsd, ldns and others…</summary><published>2022-10-04T00:32:16+02:00</published><updated>2026-10-02T15:49:57+02:00</updated></entry><entry><id>tag:doc.huc.fr.eu.org,2022-04-19:/en/monitor/iblock-openbsd</id><link href="https://it-log.fr.eu.org/en/monitor/iblock-openbsd/" rel="alternate" type="text/html"/><title>iblock: block scanner TCP connections under OpenBSD</title><author><name>Stéphane HUC</name></author><category term="Monitoring" scheme="https://it-log.fr.eu.org/en/tags/monitoring/"/><category term="TCP" scheme="https://it-log.fr.eu.org/en/tags/tcp/"/><category term="OpenBSD" scheme="https://it-log.fr.eu.org/en/tags/openbsd/"/><category term="PF" scheme="https://it-log.fr.eu.org/en/tags/pf/"/><category term="inetd" scheme="https://it-log.fr.eu.org/en/tags/inetd/"/><content type="html"><![CDATA[<h2 id="description">Description</h2>
<p><strong>iblock</strong> is a software whose purpose is to detect TCP connections, on
specific ports, in order to block the corresponding IP adresses, through
Packet Filter.</p>
<p>The inetd service is responsible for active listening.</p>
<ul>
<li>Author: Solène Rapenne</li>
<li>URL: <a href="https://tildegit.org/solene/iblock.git" rel="external">https://tildegit.org/solene/iblock.git</a></li>
<li>list of banned URLs: <a href="http://perso.pw/blocklist.txt" rel="external">http://perso.pw/blocklist.txt</a></li>
</ul>
<h2 id="installation">Installation</h2>
<p>Let&rsquo;s start with the copy of Git depository:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:$ git clone https://tildegit.org/solene/iblock.git
</span></span><span style="display:flex;"><span>:$ cd iblock
</span></span></code></pre></div><p>Compile the binary — <em>OpenBSD contains natively the appropriate tools</em>:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:$ doas make
</span></span><span style="display:flex;"><span>cc -o iblock main.c
</span></span><span style="display:flex;"><span>; vérifions la présence du binaire
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>:$ ls -al iblock
</span></span><span style="display:flex;"><span>-rwxr-xr-x  <span style="color:#f99b15">1</span> root  moi  <span style="color:#f99b15">8496</span> Apr <span style="color:#f99b15">10</span> 12:23 iblock*
</span></span></code></pre></div><p><em>If the compilation phase does not run correctly, contact Solène!</em></p>
<p>Solène did not create the &ldquo;install&rdquo; target, so let&rsquo;s copy it into the
target directory:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:$ doas cp iblock /usr/local/bin/
</span></span><span style="display:flex;"><span>:$ ls -al /usr/local/bin/iblock
</span></span><span style="display:flex;"><span>-rwxr-xr-x  <span style="color:#f99b15">1</span> root  wheel  <span style="color:#f99b15">8496</span> Apr <span style="color:#f99b15">10</span> 12:26 /usr/local/bin/iblock*
</span></span></code></pre></div><p>Let&rsquo;s move to the configuration:</p>
<h2 id="configuration">Configuration</h2>
<h3 id="_iblock">_iblock</h3>
<p>In first, create a dedicated user, named <strong>_iblock</strong>:</p>
<p><code>:$ doas useradd -s /sbin/nologin _iblock</code></p>
<h3 id="doas">doas</h3>
<ul>
<li>Configuration file: <code>/etc/doas.conf</code></li>
</ul>
<p>Now, add the below rule into the doas configuration file to allow the
dedicated user to use <code>pfctl</code>:</p>
<p><code>permit nopass _iblock cmd /sbin/pfctl</code></p>
<h3 id="inetd">inetd</h3>
<ul>
<li>Configuration file: <code>/etc/inetd.conf</code></li>
</ul>
<p>Configure the <strong>inetd</strong> service:</p>
<pre tabindex="0"><code class="language-conf" data-lang="conf">666 stream tcp nowait _iblock /usr/local/bin/iblock iblock blocked_tcp
666 stream tcp6 nowait _iblock /usr/local/bin/iblock iblock blocked_tcp
</code></pre><ul>
<li><strong>666</strong>: used port — <em>of course, you can change…</em></li>
<li>the <strong>_iblock</strong> user manage the binary <code>iblock</code></li>
<li>the last argument: the name of the added parameter to the IP addresses
stored in the PF table.</li>
</ul>
<p>And, now, let&rsquo;s active and start the service:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:$ doas rcctl enable inetd <span style="color:#5bc4bf">&amp;&amp;</span> doas rcctl start inetd
</span></span></code></pre></div><h3 id="shutdown">shutdown</h3>
<p>Create a &ldquo;backup&rdquo; file to make the future table persistent in PF, on
server shutdown and restart:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:# touch /etc/pf-blocked_tcp.txt
</span></span></code></pre></div><p>And, create|modify the <code>/etc/rc.shutdown</code> file:</p>
<pre tabindex="0"><code class="language-conf" data-lang="conf">pfctl -t blocked_tcp -T show &gt; /etc/pf-blocked_tcp.txt
</code></pre><h3 id="pf">PF</h3>
<p>Here is an instance of rules to add to Packet Filter:</p>
<ol>
<li>one variable, named <strong>block_tcp_ports</strong>: a set of ports to monitor</li>
<li>one persistent table, named <strong>blocked_tcp</strong>.</li>
<li>the blocking rule, labeled <strong>iblock</strong>.</li>
<li>the two ultime rules analyze the TCP flow, on IPv(4|6) protocols, by
active listening on the stored ports into the <strong>block_tcp_ports</strong>
variable, and then redirect on the local interface, to the port <strong>666</strong>.</li>
</ol>
<pre tabindex="0"><code class="language-conf" data-lang="conf">block_tcp_ports = &#34;{ 21 23 111 135 137:139 445 1433 3306 3389 5432 6000:6010 7890 9999 25565 27019 }&#34;

table &lt;blocked_tcp&gt; persist file &#34;/etc/pf-blocked_tcp.txt&#34;

### iblock: block all in table
block in quick from &lt;blocked_tcp&gt; label iblock

### iblock: redirect to inetd service on localhost
pass in quick on egress inet  proto tcp to port $block_tcp_ports rdr-to 127.0.0.1 port 666
pass in quick on egress inet6 proto tcp to port $block_tcp_ports rdr-to ::1       port 666
</code></pre>
<div class="tab-info i-info">Info</div><div class="alert alert-info" role="alert">By default, the set of the ports are FTP, telnet, DNS, RPC, SMB, MSSQL,
MySQL, PostgreSQL, Minecraft, Steam. <br>
I add: X11, Goaccess, pfstat; <em>it&rsquo;s up to you…</em></div>


<div class="tab-info i-warning">Warning</div><div class="alert alert-warning" role="alert">If you are hosting a service, such as DNS, you will block all connections,
because by default the appropriate port 53 is scanned. <br>
<em>(this applies to any service you host!)</em></div>

<p>Remember: reload the rule set: <br>
<code>:$ doas pfctl -f /etc/pf.conf</code></p>
<h2 id="monitoring">Monitoring</h2>
<blockquote>
<p>But, who is the monitor?</p>
</blockquote>
<p>⇒ The activity is recorded in the two logs &lsquo;daemon&rsquo; and &lsquo;messages&rsquo;.</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:$ grep iblock /var/log/messages
</span></span><span style="display:flex;"><span>Apr <span style="color:#f99b15">10</span> 12:26:38 sh1 iblock: blocking 46.23.148.71
</span></span><span style="display:flex;"><span>Apr <span style="color:#f99b15">10</span> 12:30:28 sh1 iblock: blocking 180.225.98.236
</span></span><span style="display:flex;"><span>Apr <span style="color:#f99b15">10</span> 12:31:48 sh1 iblock: blocking 46.23.157.246
</span></span><span style="display:flex;"><span>Apr <span style="color:#f99b15">10</span> 12:32:43 sh1 iblock: blocking 95.57.218.103
</span></span><span style="display:flex;"><span>Apr <span style="color:#f99b15">10</span> 12:36:00 sh1 iblock: blocking 103.89.91.158
</span></span><span style="display:flex;"><span>Apr <span style="color:#f99b15">10</span> 12:38:41 sh1 iblock: blocking 23.128.248.41
</span></span></code></pre></div><p>⇒ Also, <code>pfctl</code> can show us the different IP addresses registered into
the PF table:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:$ doas pfctl -t blocked_tcp -T show
</span></span><span style="display:flex;"><span>   23.128.248.41
</span></span><span style="display:flex;"><span>   46.23.148.71
</span></span><span style="display:flex;"><span>   46.23.157.246
</span></span><span style="display:flex;"><span>   95.57.218.103
</span></span><span style="display:flex;"><span>   103.89.91.158
</span></span><span style="display:flex;"><span>   180.225.98.236
</span></span></code></pre></div><p>or event to use it to find the related statistics to —
<em><a href="https://man.openbsd.org/pfctl#s~8" rel="external">see documentation for column meaning</a></em>:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:$ doas pfctl -sl | grep iblock
</span></span><span style="display:flex;"><span>iblock <span style="color:#f99b15">44666</span> <span style="color:#f99b15">1188</span> <span style="color:#f99b15">58504</span> <span style="color:#f99b15">1188</span> <span style="color:#f99b15">58504</span> <span style="color:#f99b15">0</span> <span style="color:#f99b15">0</span> <span style="color:#f99b15">0</span>
</span></span></code></pre></div><p>⇒ It&rsquo;s possible to monitoring the user <strong>_iblock</strong> —
<em>but, in this case, not very useful</em>:</p>
<ul>
<li><code>top -U _iblock</code></li>
<li><code>fstat -u _iblock -n</code></li>
<li><code>ps aux -U _iblock</code></li>
</ul>
<h3 id="munin">munin</h3>
<p>If you want to get statistics with <a class="tag" href="/en/tags/munin">munin</a>
, Solène provided me
a script, to be executed with the rights of the user <strong>_munin</strong>:</p>
<pre tabindex="0"><code class="language-conf" data-lang="conf">#!/bin/sh

if [ &#34;$1&#34; = &#34;config&#34; ]; then
        echo &#34;graph_title Banned IP absolute number&#34;
        echo &#34;graph_vlabel gauge&#34;
        echo &#34;a1.label value&#34;
        exit 0
fi

printf &#34;a1.value &#34;
doas /sbin/pfctl -t blocked_tcp -T show | sort -n -u | awk &#39;END { print NR }&#39;
</code></pre><p>This need to modify the configuration of <a href="/en/monitor/iblock-openbsd/#doas">doas</a> to allow the user
<strong>_munin</strong> to use <code>pfctl</code>:</p>
<pre tabindex="0"><code class="language-conf" data-lang="conf"># iblock: auth _munin-plugin to use pfctl
permit nopass _munin-plugin cmd /sbin/pfctl args -t blocked_tcp -T show
</code></pre><hr>
<p>Below, here a view of statistics of blocked IP addresses, gived by Solène,</p>
<p>Ci-dessous, voici une image de statistiques d&rsquo;adresses IP bloquées, restituée
par Solène, on 2022/10/04:</p>
<figure>
    <a href="/images/monitor/iblock-stats.png" title="Statistics of IP addresses blocked with iblock">
    <picture>
        
        <source srcset="/images/monitor/iblock-stats_hu_3dbffc249bb7edfe.webp" type="image/webp">
        
        <img alt="Statistics of IP addresses blocked with iblock" height="142" loading="lazy" src="/images/monitor/iblock-stats_hu_ab68ffa9accd8a1b.png" type="image/png" width="250">
    </picture>
    </a>
    <figcaption>Statistics of IP addresses blocked with iblock</figcaption>
</figure>
<h2 id="troubleshooting">Troubleshooting</h2>
<p>Into the both logs &lsquo;daemon&rsquo; and &lsquo;messages&rsquo;, see the message:</p>
<p><code>inetd[69849]: execv /usr/local/bin/iblock: No such file or directory</code></p>
<p><strong>Make sure you have compiled and copied the iblock binary to the target
directory!</strong></p>
<hr>
<p>Voila!</p>
<hr>
]]></content><summary>iblock: a tool to block scanner on unused ports, TCP connections, adding the IP to a Packet Filter table, on OpenBSD, using inetd service.</summary><published>2022-04-19T14:00:06+02:00</published><updated>2026-10-02T15:49:57+02:00</updated></entry><entry><id>tag:doc.huc.fr.eu.org,2021-07-30:/en/monitor/goaccess-openbsd</id><link href="https://it-log.fr.eu.org/en/monitor/goaccess-openbsd/" rel="alternate" type="text/html"/><title>Goaccess / OpenBSD</title><author><name>Stéphane HUC</name></author><category term="Monitoring" scheme="https://it-log.fr.eu.org/en/tags/monitoring/"/><category term="dataviz" scheme="https://it-log.fr.eu.org/en/tags/dataviz/"/><category term="log" scheme="https://it-log.fr.eu.org/en/tags/log/"/><category term="goaccess" scheme="https://it-log.fr.eu.org/en/tags/goaccess/"/><category term="OpenBSD" scheme="https://it-log.fr.eu.org/en/tags/openbsd/"/><category term="httpd" scheme="https://it-log.fr.eu.org/en/tags/httpd/"/><category term="nginx" scheme="https://it-log.fr.eu.org/en/tags/nginx/"/><content type="html"><![CDATA[<h2 id="description">Description</h2>
<p><strong>Goaccess</strong> is a FLoSS, known to be light, fast, in order to to analyze
in real time or not the activity on a web server, either directly within
a Unix terminal, or on the HTTPS protocol.</p>
<p>It&rsquo;s able to produce statistics on HTML, JSON even CSV format.</p>
<hr>
<p>⇒ Environnement:</p>
<ul>
<li>OpenBSD: <del>6.9</del> → 7.1</li>
</ul>
<h2 id="installation">Installation</h2>
<p>Usual: <code>:# pkg_add goaccess</code></p>
<h2 id="configuration">Configuration</h2>
<p>The main file config is on: <code>/etc/goaccess/goaccess.conf</code>.</p>
<hr>
<p>⇒ You can use goaccess without any modifications on its file config. <br>
This need to pass all options on the CLI, but few options are clearly
commons and can be &ldquo;frozen&rdquo; on the file config.</p>
<p>⇒ Too, it&rsquo;s also possible to create numerous files config, each specific
to a web domain, to set particularly segun this domain. In this case, you
need to specify it…</p>
<p><em>In this article, I use one configuration file, and put some options on
the CLI.</em></p>
<p>Now, let&rsquo;s see the main configuration options:</p>
<h3 id="time-and-date-formats">Time and Date formats</h3>
<p>Formatting the time!</p>
<p>⇒ If you use <strong>httpd</strong>, you need to be careful to set correctly the style
of the log, and into in the goaccess configuration file in the
<strong>Time Format Options</strong> section.</p>
<ul>
<li>see: <a href="https://man.openbsd.org/httpd.conf.5#style" rel="external">httpd.conf</a>(5)#style</li>
</ul>
<p>⇒ For <strong>nginx</strong>, it will be enough to uncomment the following options:</p>
<ul>
<li><strong>time-format %H:%M:%S</strong></li>
<li><strong>date-format %d/%b/%Y</strong> - this being into <strong>Date Format Options</strong>
section.</li>
</ul>
<h3 id="log-format">Log format</h3>
<ul>
<li><strong>log-format</strong>: prefer the <strong>COMBINED</strong> format — <em>for httpd, you can
choose the <strong>common</strong> format, too</em>.</li>
</ul>
<p><em>If you use <strong>nginx</strong>, it is imperative to register all statuses,
not to filter the 2xx and 3xx — if you had created the <strong>map</strong> directive
you will have at least to comment it and restart the web service</em>.</p>
<h3 id="file-options">File Options</h3>
<p>If you have only one web domaine on the server to analyze, it&rsquo;s usefull
to set the <strong>log-file</strong> option with the absolute directory of the <strong>access.log</strong>
relient.</p>
<h3 id="parse-options">Parse Options</h3>
<ul>
<li>
<p><strong>exclude-ip</strong>: use this option to exclude adresses IP or network segments,
<em>like you personal network at home</em></p>
</li>
<li>
<p><strong>444-as-404</strong>: the <strong>444</strong> error is nginx&rsquo;s specific.
If you want to analyze as an <strong>404</strong> error, change to <strong>true</strong>.
It&rsquo;s up to you!</p>
</li>
<li>
<p><strong>ignore-crawlers</strong>: to ignore all crawlers robots; change to <strong>true</strong></p>
</li>
<li>
<p><strong>ignore-panel</strong> is one panel that can be disabled. On Europe, with the
RGPD, it is better to disable, at least, the <strong>REMOTE_USER</strong> panel.</p>
</li>
<li>
<p><strong>anonymize-ip</strong> : change to <strong>true</strong> - <em>egual, because RGPD, disable!</em></p>
</li>
</ul>
<h3 id="persistence-options">Persistence Options</h3>
<ul>
<li><strong>db-path</strong>: the absolute directory of the goaccess database ­— <em>configure
only one domain.</em></li>
<li><strong>persist</strong>: to backup the analyzed datas.</li>
<li><strong>restore</strong>: load the data to be visualized from the saved data.</li>
</ul>
<p>⇒ Enable both last options to <strong>true</strong>, if you want to save the data into
the goaccess database.</p>
<hr>
<p>Of course, there are numerous options.</p>
<p>After, <a href="/en/monitor/goaccess-openbsd/#basic-use">just use</a> goaccess.</p>
<hr>
<p>Now, let&rsquo;s push the configuration a further:</p>
<h3 id="user-system">User system</h3>
<p>I prefer to create and use a dedicated user system. Among the advantages
are the search in log messages and even cron.</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:# useradd -s /sbin/nologin -d /var/db/goaccess _goaccess
</span></span></code></pre></div><hr>
<p>⇒ to search in log messages:</p>
<p><code>:$ grep goaccess /var/log/messages</code> or <br>
<code>:$ doas grep _goaccess /var/cron/log</code></p>
<h4 id="doas">doas</h4>
<p>⇒ I preferred to add the permission to use the <strong>goaccess</strong> binary into
<code>/etc/doas.conf</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">permit nopass _goaccess cmd /usr/local/bin/goaccess</span>
</span></span></code></pre></div><p><em>(I&rsquo;m not absolutly sure about the necessity)</em>.</p>
<h4 id="database-directory">database directory</h4>
<p>⇒ Go to create the main directory for the goaccess database:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:# mkdir -p /var/db/goaccess
</span></span><span style="display:flex;"><span>:# chown _goaccess:daemon /var/db/goaccess
</span></span></code></pre></div><p><em>(personally, I preferred another absolute folder)</em>.</p>
<p><strong>Think to add at yours backups!</strong></p>
<hr>
<p>Then if like me, you have several web domains on your server, create
many subdirectories with the name of the web domain, such as:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:$ <span style="color:#ef6155">domain</span><span style="color:#5bc4bf">=</span>
</span></span><span style="display:flex;"><span>:$ doas -u _goaccess mkdir <span style="color:#48b685">&#34;/var/db/goaccess/</span><span style="color:#f99b15">${</span><span style="color:#ef6155">domain</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span></code></pre></div><p>Thus, future statistics will be really dedicated to a domain.</p>
<h4 id="crontab">crontab</h4>
<p>⇒ You need to set cron rules:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:$ doas -u _goaccess crontab -e
</span></span></code></pre></div><p><em>(Egual, it&rsquo;s possible to do by: <code>doas crontab -u _goaccess -e</code>)</em>.</p>
<p>Add:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">*/15 * * * * -ns goaccess -a --db-path &#34;/var/db/goaccess/domain/&#34; -f /var/www/logs/domain/access.log -o /var/www/goaccess/domain/stats.html</span>
</span></span></code></pre></div><p>Littles explainations:</p>
<ul>
<li>one crontab to execute every 15 minutes. <em>Keep on mind, it&rsquo;s an example.</em></li>
<li>replace the <em>domain</em> string by the domain name.</li>
</ul>
<h3 id="authenticate">Authenticate</h3>
<p>It&rsquo;s up to you if you want web authentication before viewing; some people
think you should, others don&rsquo;t; personally I prefer it.</p>
<p>After using <strong>htpasswd</strong>, you need to configure on the server directive
on the virtual host:</p>
<ul>
<li>for http, use <strong>authenticate</strong>.</li>
<li>on nginx, both <strong>auth_basic</strong> and <strong>auth_basic_user_file</strong> directives.</li>
</ul>
<h4 id="httpd-configuration">httpd configuration</h4>
<p>Basically:</p>
<pre tabindex="0"><code class="language-httpd" data-lang="httpd">server &#34;domain.tld&#34; {

(…)

    root &#34;/htdocs/domain.tld/www&#34;

    location &#34;/stats&#34; {
        authenticate with &#34;/file_htpwd&#34;
        directory auto index
    }

(…)

}
</code></pre><p><strong>Do not forget: the path of the htpasswd file is relative to the web chroot!</strong></p>
<h4 id="nginx-configuration">nginx configuration</h4>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-nginx" data-lang="nginx"><span style="display:flex;"><span><span style="color:#815ba4">(…)</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#48b685">location</span> <span style="color:#48b685">/stats/</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#5bc4bf">auth_basic</span> <span style="color:#48b685">&#34;Auth</span> <span style="color:#48b685">Area&#34;</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#5bc4bf">auth_basic_user_file</span> <span style="color:#48b685">/file_htpwd</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#5bc4bf">autoindex</span> <span style="color:#ef6155">on</span>;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#815ba4">(…)</span>
</span></span></code></pre></div><hr>
<p>Voila for the &ldquo;configuration&rdquo; part!</p>
<hr>
<h2 id="use">Use</h2>
<h3 id="basic-use">Basic use</h3>
<p>Execute the binary, as:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:$ goaccess -o /var/www/htdocs/domain.tld/stats/index.html
</span></span></code></pre></div><h3 id="use-_goaccess">use _goaccess</h3>
<p>⇒ Use goaccess with the <strong>_goaccess</strong> user:</p>
<p>For instance, the first time, to precise datation with month and year:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:$ <span style="color:#ef6155">domain</span><span style="color:#5bc4bf">=</span>
</span></span><span style="display:flex;"><span>:$ <span style="color:#ef6155">date</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#815ba4">$(</span>date +<span style="color:#48b685">&#39;%Y-%m&#39;</span><span style="color:#815ba4">)</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>:$ doas -u _goaccess goaccess -a --db-path <span style="color:#48b685">&#34;/var/db/goaccess/</span><span style="color:#f99b15">${</span><span style="color:#ef6155">domain</span><span style="color:#f99b15">}</span><span style="color:#48b685">/&#34;</span> -f <span style="color:#48b685">&#34;/var/www/logs/</span><span style="color:#f99b15">${</span><span style="color:#ef6155">domain</span><span style="color:#f99b15">}</span><span style="color:#48b685">/access.log&#34;</span> -o <span style="color:#48b685">&#34;/var/db/goaccess/</span><span style="color:#f99b15">${</span><span style="color:#ef6155">domain</span><span style="color:#f99b15">}</span><span style="color:#48b685">/stats-</span><span style="color:#f99b15">${</span><span style="color:#ef6155">domain</span><span style="color:#f99b15">}</span><span style="color:#48b685">-</span><span style="color:#f99b15">${</span><span style="color:#ef6155">date</span><span style="color:#f99b15">}</span><span style="color:#48b685">.html&#34;</span>
</span></span></code></pre></div><hr>
<p>I created a shell script, named <strong>goaccess.sh</strong>:</p>
<pre tabindex="0"><code class="language-file" data-lang="file">#!/bin/sh

###
#
# manage statistics by domain
#
##

date=&#34;$(date +&#39;%m-%Y&#39;)&#34;
dir_db=&#34;/var/db/goaccess&#34;
domain=&#34;$1&#34;

if [ -z &#34;${domain}&#34; ]; then
    printf &#39;%s %s\n&#39; &#34;KO&#34; &#34;No domain. Script stops!&#34;
    logger &#34;$0: no domain found as option; script stops!&#34;
    exit 1
fi

if [ ! -d &#34;${dir_db}/${domain}/&#34; ]; then
    printf &#39;%s %s\n&#39; &#34;KO&#34; &#34;The destination directory &#39;${dir_db}/${domain}/&#39; seems not exist!&#34;
    logger &#34;$0: The destination directory for goaccess not exists; script stops!&#34;
    exit 2
fi

goaccess -a --db-path &#34;${dir_db}/${domain}/&#34; -f &#34;/var/www/logs/${domain}/access.log&#34; -o &#34;${dir_db}/${domain}/stats-${domain}-${date}.html&#34;
</code></pre><p>And, after setting up the <strong>_goaccess</strong> crontab:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">*/15 * * * * -ns /directory/goaccess.sh domain-x.tld</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">0    * * * * -ns /directory/goaccess.sh domain-y.tld</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">0    0 * * * -ns /directory/goaccess.sh domain-z.tld</span>
</span></span></code></pre></div><p><em>(at differents times)</em>.</p>
<hr>
<p>No! It&rsquo;s not finish…</p>
<p>In fact, the generated HTML file to dataviz is wrote on the database directory.
The <strong>_goaccess</strong> user cant write on the web directory, and does not have
access.</p>
<p>On the other hand, it is possible to ask the web user <strong>www</strong> to copy
the HTML statistics file on the corresponding web directory.</p>
<p>Here, I use this following shell script, named <strong>cp_stats.sh</strong>:</p>
<pre tabindex="0"><code class="language-file" data-lang="file">#!/bin/sh

set -e
#set -x

###
#
# copy statistics files into the domain web directory
#
##

date=&#34;$(date +&#39;%m-%Y&#39;)&#34;
domain=&#34;$1&#34;
dir_db=&#34;/var/db/goaccess&#34;
dir_stats=&#34;/var/www/htdocs/${domain}/www/stats/&#34;

if [ -z &#34;${domain}&#34; ]; then
    printf &#39;%s %s\n&#39; &#34;KO&#34; &#34;No domain. Script stops!&#34;
    logger &#34;$0: no domain found as option; script stops!&#34;
    exit 1
fi

if [ ! -f &#34;${dir_db}/${domain}/stats-${domain}-${date}.html&#34; ]; then
    printf &#39;%s %s\n&#39; &#34;KO&#34; &#34;The needed file &#39;${dir_db}/${domain}/stats-${domain}-${date}.html&#39; not exists. Script stops!&#34;
    logger &#34;$0: The needed file &#39;${dir_db}/${domain}/stats-${domain}-${date}.html&#39; not exists; script stops!&#34;
    exit 2
fi

if [ ! -d &#34;${dir_stats}&#34; ]; then mkdir -p &#34;${dir_stats}&#34;; fi

cp &#34;${dir_db}/${domain}/stats-${domain}-${date}.html&#34; &#34;${dir_stats}&#34;
chown -R www &#34;${dir_stats}&#34;
</code></pre><p>You need to modify the crontab of the web user:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:$ doas -u www crontab -e
</span></span></code></pre></div><p>Like, for instance:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">*/15 * * * * -ns /directory/cp_stats.sh domain-x.tld</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">5    * * * * -ns /directory/cp_stats.sh domain-y.tld</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">5    0 * * * -ns /directory/cp_stats.sh domain-z.tld</span>
</span></span></code></pre></div><h3 id="time-real">Time-real</h3>
<p>The real time use is done in two possible ways.</p>
<p>Into those contexts, we will not need the <strong>_goaccess</strong> user.</p>
<h4 id="terminal">Terminal</h4>
<p>⇒ at least, tape:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:$ goaccess -f /var/www/logs/<span style="color:#f99b15">${</span><span style="color:#ef6155">domain</span><span style="color:#f99b15">}</span>/access.log
</span></span></code></pre></div><p>Enjoy the aesthetic view based on monokai colors, by default.</p>
<h4 id="web-proxy">Web proxy</h4>
<p>Here, it&rsquo;s really interesting, but a &ldquo;bit complicated&rdquo;:</p>
<h5 id="relay-httpd">relay httpd</h5>
<p>I have not found solution for the httpd service. Maybe, with relayd ;-)</p>
<h5 id="proxy-nginx">proxy nginx</h5>
<p>Lets to set the server configuration to add the <strong>location</strong> directive:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-nginx" data-lang="nginx"><span style="display:flex;"><span><span style="color:#815ba4">location</span> <span style="color:#48b685">/ws</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#5bc4bf">proxy_pass</span> <span style="color:#48b685">http://localhost:7890</span>;
</span></span><span style="display:flex;"><span>        <span style="color:#5bc4bf">proxy_http_version</span> <span style="color:#f99b15">1</span><span style="color:#48b685">.1</span>;
</span></span><span style="display:flex;"><span>        <span style="color:#5bc4bf">proxy_set_header</span> <span style="color:#48b685">Upgrade</span> <span style="color:#ef6155">$http_upgrade</span>;
</span></span><span style="display:flex;"><span>        <span style="color:#5bc4bf">proxy_set_header</span> <span style="color:#48b685">Connection</span> <span style="color:#48b685">&#34;Upgrade&#34;</span>;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><h5 id="websocket">websocket</h5>
<p>Now, you need to execute goaccess with the <strong>www</strong> web user rights:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:$ doas -u www goaccess -p /etc/goaccess/goaccess.realtime.conf -o /var/www/htdocs/huc.fr.eu.org/www/stats/realtime.html --ws-url<span style="color:#5bc4bf">=</span>wss://huc.fr.eu.org:443/ws --port <span style="color:#f99b15">7890</span>
</span></span><span style="display:flex;"><span> <span style="color:#5bc4bf">[</span>PARSING /var/www/logs/doc.huc.fr.eu.org/access.log<span style="color:#5bc4bf">]</span> <span style="color:#5bc4bf">{</span>0<span style="color:#5bc4bf">}</span> @ <span style="color:#5bc4bf">{</span>0/s<span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>WebSocket server ready to accept new client connections
</span></span></code></pre></div><p>Note: for this test, I have to:</p>
<ul>
<li>create a new configuration file named <strong>goaccess.realtime.conf</strong></li>
<li>to create a new HTML file</li>
<li>and to listen the server on the secure websocket.</li>
</ul>
<p>Also, we can monitoring, in real time, the user, into a SSH console, with
binaries like <strong>fstat</strong>, <strong>ps</strong>; see:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:$ fstat -u www -n
</span></span><span style="display:flex;"><span>USER     CMD          PID   FD  DEV      INUM        MODE   R/W    SZ|DV
</span></span><span style="display:flex;"><span>www  goaccess   <span style="color:#f99b15">76729</span>   wd  4,15   <span style="color:#f99b15">725760</span>        <span style="color:#f99b15">40755</span>    r      <span style="color:#f99b15">512</span>
</span></span><span style="display:flex;"><span>www  goaccess   <span style="color:#f99b15">76729</span>    <span style="color:#f99b15">0</span>  4,0     <span style="color:#f99b15">78329</span>        <span style="color:#f99b15">20620</span>   rw    5,0
</span></span><span style="display:flex;"><span>www  goaccess   <span style="color:#f99b15">76729</span>    <span style="color:#f99b15">1</span>  4,0     <span style="color:#f99b15">78329</span>        <span style="color:#f99b15">20620</span>   rw    5,0
</span></span><span style="display:flex;"><span>www  goaccess   <span style="color:#f99b15">76729</span>    <span style="color:#f99b15">2</span>  4,0     <span style="color:#f99b15">78329</span>        <span style="color:#f99b15">20620</span>   rw    5,0
</span></span><span style="display:flex;"><span>www  goaccess   <span style="color:#f99b15">76729</span>    <span style="color:#f99b15">3</span>  4,3       <span style="color:#f99b15">175</span>        <span style="color:#f99b15">10644</span>   rw        <span style="color:#f99b15">0</span>
</span></span><span style="display:flex;"><span>www  goaccess   <span style="color:#f99b15">76729</span>    <span style="color:#f99b15">4</span>  4,3       <span style="color:#f99b15">176</span>        <span style="color:#f99b15">10644</span>   rw        <span style="color:#f99b15">0</span>
</span></span><span style="display:flex;"><span>www  goaccess   <span style="color:#f99b15">76729</span>    <span style="color:#f99b15">5</span>  4,3       <span style="color:#f99b15">175</span>        <span style="color:#f99b15">10644</span>    w        <span style="color:#f99b15">0</span>
</span></span><span style="display:flex;"><span>www  goaccess   <span style="color:#f99b15">76729</span>    <span style="color:#f99b15">6</span>  4,3       <span style="color:#f99b15">176</span>        <span style="color:#f99b15">10644</span>    w        <span style="color:#f99b15">0</span>
</span></span><span style="display:flex;"><span>www  goaccess   <span style="color:#f99b15">76729</span>    <span style="color:#f99b15">7</span> pipe 0x0 state:
</span></span><span style="display:flex;"><span>www  goaccess   <span style="color:#f99b15">76729</span>    <span style="color:#f99b15">8</span> pipe 0x0 state:
</span></span><span style="display:flex;"><span>www  goaccess   <span style="color:#f99b15">76729</span>    9* internet stream tcp 0x0 *:7890
</span></span><span style="display:flex;"><span>www  goaccess   <span style="color:#f99b15">76729</span>   <span style="color:#f99b15">10</span> pipe 0x0 state:
</span></span><span style="display:flex;"><span>www  goaccess   <span style="color:#f99b15">76729</span>   <span style="color:#f99b15">11</span> pipe 0x0 state:
</span></span><span style="display:flex;"><span>www  goaccess   <span style="color:#f99b15">76729</span>   12* internet stream tcp 0x0 127.0.0.1:7890 &lt;-- 127.0.0.1:6459
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>:$ ps aux -U www
</span></span><span style="display:flex;"><span>USER       PID %CPU %MEM   VSZ   RSS TT  STAT   STARTED       TIME COMMAND
</span></span><span style="display:flex;"><span>www   <span style="color:#f99b15">4071</span>  0.0  0.1  <span style="color:#f99b15">1572</span>  <span style="color:#f99b15">3488</span> ??  S      10:12AM    0:00.88 sshd: www@notty <span style="color:#5bc4bf">(</span>sshd<span style="color:#5bc4bf">)</span>
</span></span><span style="display:flex;"><span>www  <span style="color:#f99b15">76729</span>  0.0  0.3 <span style="color:#f99b15">10096</span> <span style="color:#f99b15">12752</span> p0  S+      7:56PM    0:01.49 goaccess -p /etc/goaccess/goaccess.realtime.conf -o /var/www/htdocs/huc.fr.eu.org/www/stats/realtime.html /var/www/logs/do
</span></span></code></pre></div><p>Now, go to view the <strong>realtime.html</strong> file on your web browser.</p>
<figure>
    <a href="/images/monitor/goaccess-realtime.png" title="dashboard goaccess real time">
    <picture>
        
        <source srcset="/images/monitor/goaccess-realtime_hu_32de140a245efaa6.webp" type="image/webp">
        
        <img alt="dashboard goaccess real time" height="36" loading="lazy" src="/images/monitor/goaccess-realtime_hu_1e00616802b3e058.png" type="image/png" width="250">
    </picture>
    </a>
    <figcaption>dashboard goaccess real time</figcaption>
</figure>
<p>Note the little dash below the parameter icone, at the top left on the
screen.</p>
<p><em>It seems necessary to reload the page; after some time, it lose the connector.
Press <kbd>F5</kbd>…</em></p>
<hr>
<p>Finally, we cant execute goaccess as service, either by the <strong>&ndash;daemonize</strong>
option, or by configuring the dedicated configuration file.</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:$ doas -u www goaccess --daemonize -p /etc/goaccess/goaccess.realtime.conf -o /var/www/htdocs/huc.fr.eu.org/www/stats/realtime.html --ws-url<span style="color:#5bc4bf">=</span>wss://huc.fr.eu.org:443/ws --port <span style="color:#f99b15">7890</span>
</span></span><span style="display:flex;"><span>Daemonized GoAccess: <span style="color:#f99b15">48646</span>
</span></span></code></pre></div><p>This option <strong>only works with real time option</strong> enabled.</p>
<p>Egual, it&rsquo;s <strong>imperative that the web user is given access to the path that
will write the PID process file</strong> — <em>otherwise, you will fail!</em></p>
<p>You need to set the <strong>pid-file</strong> option into the configuration file.</p>
<p>As reminder, on OpenBSD, by default, it&rsquo;s on the web chroot: <code>/var/www/run</code>.
Prefer to create a sub-directory dedicated to the user <strong>www</strong>.</p>
<hr>
<p>Of course, all of this, it&rsquo;s for the FUN, and the example! :D</p>
<hr>
<p>Voila!</p>
<p><em>(It&rsquo;s my XP… and yours‽)</em></p>
<h2 id="troubleshooting">Troubleshooting</h2>
<p>Here are some errors encountered:</p>
<h3 id="permission-denied">Permission denied</h3>
<ul>
<li><code>Couldn't open file /var/db/goaccess/xxx/I32_DATES.db: Permission denied</code></li>
<li><code>Unable to open the specified pid file. Permission denied</code></li>
<li><code>Unable to open the specified pid file. Permission denied</code></li>
</ul>
<ol>
<li>goaccess can not write into the directory!</li>
<li>check that directory exists.</li>
<li>check rights user; they must match the one of the user who runs
goaccess, like : <code>_goaccess:daemon</code></li>
</ol>
<p>This is the same problem during the generation of HTML files.</p>
<p>Example:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>GoAccess - version 1.5.1 - Sep <span style="color:#f99b15">26</span> <span style="color:#f99b15">2021</span> 14:08:19
</span></span><span style="display:flex;"><span>Config file: /etc/goaccess/goaccess.conf
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>Fatal error has occurred
</span></span><span style="display:flex;"><span>Error occurred at: src/output.c - output_html - <span style="color:#f99b15">1183</span>
</span></span><span style="display:flex;"><span>Unable to open HTML file: Permission denied.
</span></span></code></pre></div><h3 id="error-opening-the-specified-maxmind-db-file">Error opening the specified MaxMind DB file</h3>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>GoAccess - version 1.5.5 - Apr  <span style="color:#f99b15">8</span> <span style="color:#f99b15">2022</span> 09:03:43
</span></span><span style="display:flex;"><span>Config file: /etc/goaccess/goaccess.conf
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>Fatal error has occurred
</span></span><span style="display:flex;"><span>Error occurred at: src/geoip2.c - init_geoip - <span style="color:#f99b15">89</span>
</span></span><span style="display:flex;"><span>Unable to open GeoIP2 database /var/db/GeoIP/GeoLite2-Country.mmdb: Error opening the specified MaxMind DB file
</span></span></code></pre></div><p>You have certainly activate the <code>geoip-database</code> option.</p>
<p>But did you download the necessary files and install them in the directory
<code>/var/db/GeoIP/</code>?</p>
<h3 id="no-home-directory">No home directory</h3>
<ul>
<li><strong>Make sure that the home directory for the dedicated user really exists !</strong></li>
</ul>
<p>Then check the existence of the path in your filesystem, without forgetting
the user rights on!</p>
<ul>
<li>make sure that the home directory of the dedicated user AND the <code>dir_db</code>
variable on the <code>goaccess.sh</code> script matches.</li>
</ul>
<h2 id="documentations">Documentations</h2>
<ul>
<li><a href="https://www.geeek.org/goaccess-analyser-access-log/" rel="external">https://www.geeek.org/goaccess-analyser-access-log/</a></li>
</ul>
<h3 id="wikipédia">Wikipédia</h3>
<ul>
<li><a href="https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#4xx_client_errors" title="Wikipedia Article: List_of_HTTP_status_codes">
    List_of_HTTP_status_codes : 4xx_client_errors
    <sup><abbr class="is-italic" title="Wikipedia">WP</abbr></sup>
</a>
</li>
</ul>
<hr>
]]></content><summary>Install to use Goaccess on OpenBSD (with configuration snippets for both webserver, httpd and nginx)</summary><published>2021-07-30T15:35:45+02:00</published><updated>2026-10-02T15:49:57+02:00</updated></entry><entry><id>tag:doc.huc.fr.eu.org,2021-07-28:/en/monitor/pfstat-openbsd</id><link href="https://it-log.fr.eu.org/en/monitor/pfstat-openbsd/" rel="alternate" type="text/html"/><title>pfstat on OpenBSD: analyze stream on IPv4 and IPv6 through PF</title><author><name>Stéphane HUC</name></author><category term="Monitoring" scheme="https://it-log.fr.eu.org/en/tags/monitoring/"/><category term="dataviz" scheme="https://it-log.fr.eu.org/en/tags/dataviz/"/><category term="pfstat" scheme="https://it-log.fr.eu.org/en/tags/pfstat/"/><category term="OpenBSD" scheme="https://it-log.fr.eu.org/en/tags/openbsd/"/><category term="httpd" scheme="https://it-log.fr.eu.org/en/tags/httpd/"/><content type="html"><![CDATA[<h2 id="description">Description</h2>
<p><strong>pfstat</strong> is a project made by Daniel Hartmeir to generate graphic
statistiques about the network stream through the firewall <abbr title="Packet Filter">PF</abbr>.</p>
<ul>
<li>Official website: <a href="https://www.benzedrine.ch/pfstat.html" rel="external">https://www.benzedrine.ch/pfstat.html</a></li>
</ul>
<hr>
<p>⇒ Environnement:</p>
<ul>
<li>OpenBSD : <del>6.9</del> ⇒ 7.1</li>
</ul>
<h2 id="installation">Installation</h2>
<p>Usual: <code># pkg_add pfstat pfstatd</code></p>
<p><strong>pfstatd</strong> is not essential for a simpliest configuration. It becomes
interesting to run with dedicated user.</p>
<h2 id="configuration">Configuration</h2>
<h3 id="pf">PF</h3>
<p>Assuming that the network interface is <strong>em0</strong>, we need to modify
<code>/etc/pf.conf</code> to add:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">set loginterface em0</span>
</span></span></code></pre></div>
<div class="tab-info i-info">Info</div><div class="alert alert-info" role="alert">If you have several network interfaces, it is possible to analyze all;
add them line by line.</div>

<h3 id="pfstat">pfstat</h3>
<p>Configure <strong>pfstat</strong> is not complicated. By installing the package, the
file config is created, as instance on <code>/etc/pfstat.conf</code>.</p>
<p>You need to change the web directory where the future images
will be create.</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#776e71"># sed -i -e &#39;s/sis0/em0/g;s/benzedrine.cx/pfstat/g&#39; /etc/pfstat.conf</span>
</span></span></code></pre></div><p>This change all lines where:</p>
<ul>
<li><strong>sis0</strong> interface by <strong>em0</strong></li>
<li>the folder <em>benzedrine.cx</em> by our future directory <em>pfstat</em>.</li>
</ul>
<hr>
<p>Next, you need to configure the crontab of root to run <strong>pftstat</strong>.</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">*  * * * * -ns /usr/local/bin/pfstat -q -d /var/db/pfstat/pfstat.db</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">*/15 * * * * -ns /usr/local/bin/pfstat -p -d /var/db/pfstat/pfstat.db</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">30 0 * * * -ns /usr/local/bin/pfstat -t 30 -d /var/db/pfstat/pfstat.db</span>
</span></span></code></pre></div><ul>
<li>first line executed every minute to analyze the network stream and
save on database</li>
<li>second line generate the images every 15 minutes</li>
<li>third will delete every data, at 0:30, datas older than thirty days.</li>
</ul>
<p>⇒ Create the future folder of the database:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#776e71"># mkdir -p /var/db/pfstat/</span>
</span></span></code></pre></div>
<div class="tab-info i-info">Info</div><div class="alert alert-info" role="alert">FYI, you can create a folder when you wish. It&rsquo;s up to you!</div>

<hr>
<p>Voila: a minimum functional configuration.</p>
<p>Now, we will create a user system, without right, no password to manage
both daemon and package.</p>
<h3 id="_pfstat">_pfstat</h3>
<p>Create the user <strong>_pfstat</strong> is usefull to start daemon <strong>pfstatd</strong> and
after to use the binary <strong>pfstat</strong>:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#776e71"># useradd -s /sbin/nologin -d /var/db/pfstat  _pfstat</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># chown _pfstat /var/db/pfstat</span>
</span></span></code></pre></div><h4 id="pfstatd">pfstatd</h4>
<p>Just enable, set, and active the daemon:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#776e71"># rcctl enable pfstatd</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># rcctl set pfstatd flags -u _pfstat -a 127.0.0.1</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># rcctl start pfstatd</span>
</span></span></code></pre></div><p>We have not set port number; by default is 9999.</p>
<p>Tools, like nc, help to assume service is run correctly, like: <br>
<code>nc localhost 9999</code> — normally, stats are displayed, line by line;
<em>if not the case, you have one problem…</em></p>
<h5 id="pfstatd-and-pf">pfstatd and PF</h5>
<p>I strongly encourage you to block into OpenBSD firewall, all connections
on the pfstatd service!</p>
<p>A rule like the following should be sufficient:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">block drop in on ! lo0 proto tcp to port 9999</span>
</span></span></code></pre></div><h4 id="pfstat-and-_pfstat">pfstat and _pfstat</h4>
<p>Now, we need to reconfigure how using <strong>pfstat</strong> with the user <strong>_pfstat</strong>.</p>
<ol>
<li>First time, we need to comment or delete all writings into the crontab
of the root.</li>
<li>and set that of the user <strong>_pfstat</strong> :
<ul>
<li>create a filenamed <strong>crontab4pfstat</strong>, with those rules:</li>
</ul>
</li>
</ol>
<pre tabindex="0"><code class="language-conf" data-lang="conf">*  * * * * -ns /usr/local/bin/pfstat -q -d /var/db/pfstat/pfstat.db -r 127.0.0.1
*/15 * * * * -ns /usr/local/bin/pfstat -p -d /var/db/pfstat/pfstat.db
30 0 * * * -ns /usr/local/bin/pfstat -t 30 -d /var/db/pfstat/pfstat.db
</code></pre><p>Little explaination:</p>
<ul>
<li>option <code>-r</code> followed by the loopback address: to remote the statistics
and save them on the database.</li>
</ul>
<p>Now, add the file content <strong>crontab4pfstat</strong> into the  <strong>_pfstat</strong> user crontab:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#776e71"># crontab -u _pfstat crontab4pfstat</span>
</span></span></code></pre></div><h4 id="monitoring-_pfstat">Monitoring _pfstat</h4>
<p>It exists differents ways to monitoring the <strong>_pfstat</strong> user activity:</p>
<ul>
<li><code>top -U _pfstat</code> :</li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>load averages:  0.05,  0.38,  0.38                                      
</span></span><span style="display:flex;"><span><span style="color:#f99b15">56</span> processes: <span style="color:#f99b15">54</span> idle, <span style="color:#f99b15">2</span> on processor                                   
</span></span><span style="display:flex;"><span>CPU0 states:  0.0% user,  0.0% nice,  0.0% sys,  0.0% spin,  0.0% intr,  100% idle
</span></span><span style="display:flex;"><span>Memory: Real: 84M/5985M act/tot Free: 9778M Cache: 2757M Swap: 0K/32G
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  PID USERNAME PRI NICE  SIZE   RES STATE     WAIT      TIME    CPU COMMAND
</span></span><span style="display:flex;"><span><span style="color:#f99b15">16833</span> _pfstat    <span style="color:#f99b15">2</span>    <span style="color:#f99b15">0</span>  700K  984K sleep/6   netcon    0:00  0.00% pfstatd
</span></span></code></pre></div><hr>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>$ fstat -u _pfstat -n
</span></span><span style="display:flex;"><span>USER     CMD          PID   FD  DEV      INUM        MODE   R/W    SZ|DV
</span></span><span style="display:flex;"><span>_pfstat  pfstatd    <span style="color:#f99b15">16833</span>   wd  4,0         <span style="color:#f99b15">2</span>        <span style="color:#f99b15">40755</span>    r      <span style="color:#f99b15">512</span>
</span></span><span style="display:flex;"><span>_pfstat  pfstatd    <span style="color:#f99b15">16833</span>    <span style="color:#f99b15">0</span>  4,0     <span style="color:#f99b15">27162</span>        <span style="color:#f99b15">20666</span>   rw    2,2  
</span></span><span style="display:flex;"><span>_pfstat  pfstatd    <span style="color:#f99b15">16833</span>    <span style="color:#f99b15">1</span>  4,0     <span style="color:#f99b15">27162</span>        <span style="color:#f99b15">20666</span>   rw    2,2  
</span></span><span style="display:flex;"><span>_pfstat  pfstatd    <span style="color:#f99b15">16833</span>    <span style="color:#f99b15">2</span>  4,0     <span style="color:#f99b15">27162</span>        <span style="color:#f99b15">20666</span>   rw    2,2  
</span></span><span style="display:flex;"><span>_pfstat  pfstatd    <span style="color:#f99b15">16833</span>    <span style="color:#f99b15">3</span>  4,0     <span style="color:#f99b15">27028</span>        <span style="color:#f99b15">20600</span>    r   73,0  
</span></span><span style="display:flex;"><span>_pfstat  pfstatd    <span style="color:#f99b15">16833</span>    4* internet stream tcp 0x0 127.0.0.1:9999
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>$ ps aux -U _pfstat
</span></span><span style="display:flex;"><span>USER       PID %CPU %MEM   VSZ   RSS TT  STAT   STARTED       TIME COMMAND
</span></span><span style="display:flex;"><span>_pfstat  <span style="color:#f99b15">16833</span>  0.0  0.0   <span style="color:#f99b15">700</span>   <span style="color:#f99b15">984</span> ??  I       1:19AM    0:00.02 /usr/local/bin/pfstatd -u _pfstat -a 127.0.0.1
</span></span></code></pre></div><p>Those commands confirm that:</p>
<ul>
<li><strong>pfstatd</strong> is started and managed by the user <strong>_pfstat</strong>.</li>
<li>the daemon listen on local interface, on number port 9999, is waiting
a connection — <em>on these examples</em>.</li>
</ul>
<hr>
<p>Now, configure httpd:</p>
<h3 id="httpd">httpd</h3>
<p>Start to create the needed folder:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#776e71"># mkdir -p /var/www/htdocs/pfstat/</span>
</span></span></code></pre></div><p>Next, add the following directives to the file configuration <code>/etc/httpd.conf</code>,
as:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">types {</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">include &#34;/usr/share/misc/mime.types&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">server &#34;pfstat&#34; {</span>
</span></span><span style="display:flex;"><span>	<span style="color:#06b6ef">listen on 127.0.0.1 port 80</span>
</span></span><span style="display:flex;"><span> 
</span></span><span style="display:flex;"><span>	<span style="color:#06b6ef">location &#34;/pfstat/&#34; {</span>
</span></span><span style="display:flex;"><span>		<span style="color:#06b6ef">directory auto index</span>
</span></span><span style="display:flex;"><span>		<span style="color:#06b6ef">root &#34;/htdocs/&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#06b6ef">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">}</span>
</span></span></code></pre></div><p>Check the configuration, and enable and start the service:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#776e71"># rcctl enable httpd</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># httpd -n &amp;&amp; rcctl start httpd</span>
</span></span></code></pre></div><p>Now, we can consult locally, at: http://localhost/pfstat</p>
<hr>
<p>Voila!</p>
<p><em>(another time… but it&rsquo;s not the final time of)</em></p>
<h4 id="httpd-and-_pfstat">httpd and _pfstat</h4>
<p>Add the <strong>_pfstat</strong> user to the web group and change the user rights on
the web directory:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#776e71"># usermod -G www _pfstat</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># chown -R _pfstat:www /var/www/htdocs/pfstat</span>
</span></span></code></pre></div><hr>
<h2 id="pfstats">PFstats</h2>
<p><strong>PFstats</strong> is my little projet: create a responsive webpage to consult
easier the created images by pfstat.</p>
<p>It is designed to analyze hourly, daily, weekly, monthly and even yearly
statistics.</p>
<ul>
<li>Git depot: <a href="https://tildegit.org/hucste/pfstats" rel="external">https://tildegit.org/hucste/pfstats</a></li>
<li>See <a href="https://tildegit.org/hucste/pfstats/src/branch/main/README.md" rel="external">README.md</a></li>
<li><a href="https://tildegit.org/hucste/pfstats/src/branch/main/LICENSE" rel="external">Modified BSD License</a></li>
</ul>
<p>Here one screenshot:</p>
<figure>
    <a href="/images/openbsd/pfstats.html.png" title="Screenshot of &#39;pfstat.hml&#39; webpage">
    <picture>
        
        <source srcset="/images/openbsd/pfstats.html_hu_44f5065c3fc752c1.webp" type="image/webp">
        
        <img alt="Screenshot of &#39;pfstat.hml&#39; webpage" height="204" loading="lazy" src="/images/openbsd/pfstats.html_hu_888bbe36212847bd.png" type="image/png" width="250">
    </picture>
    </a>
    <figcaption>Screenshot of 'pfstat.hml' webpage</figcaption>
</figure>
<hr>
<p>Explainations:</p>
<h3 id="pfstatconf">pfstat.conf</h3>
<p>⇒ <strong>pfstat.conf</strong> is configured:</p>
<ul>
<li>to analyze IPv4 and IPv6, with the interface <strong>em0</strong></li>
<li>to view the hourly, daily, weekly, monthly graphics</li>
<li>to publish on web directory: <code>/var/www/htdocs/pfstat</code>.</li>
</ul>
<p>You need to copy into <code>/etc</code>.</p>
<hr>

<div class="tab-info i-info">Info</div><div class="alert alert-info" role="alert">I comment all queues directives; by default, it&rsquo;s not supported.</div>

<h3 id="pfstathtml">pfstat.html</h3>
<p>Copy all .css, .js and .html files on the web directory.</p>
<h3 id="convert-imgsh">convert-img.sh</h3>
<p>⇒ The shell script transform/convert images JPEG to the Avif and Webp
format.</p>
<p>You need to install <strong>libavif</strong>, and <strong>libwebp</strong> packages.</p>
<p>Finally:</p>
<ul>
<li>add <strong>_pfstat</strong> user to your user group, and</li>
<li>chmod needed rights to the script</li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#776e71"># usermod -G userid _pfstat</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># chmod 0750 /home/userid/folder/pfstats/convert-img.sh</span>
</span></span></code></pre></div>
<div class="tab-info i-info">Info</div><div class="alert alert-info" role="alert">Generate AVIF images can be slow; this is not the case for Webp. Too,
depend on your machine.</div>

<h3 id="pfstats-and-crontab">pfstats and crontab</h3>
<p>You need to modify the second line on the <strong>_pfstat</strong> crontab:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">15 * * * * -ns /usr/local/bin/pfstat -p -d /var/db/pfstat/pfstat.db; /dir/convert-img.sh</span>
</span></span></code></pre></div><h3 id="pfstats-and-httpd">pfstats and httpd</h3>
<p>To manage correctly both images format (avif and webp), it may be necessary
to slightly modify the configuration of httpd, to add:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">image/avif	avif</span>
</span></span></code></pre></div><p>Like:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">types {</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">include &#34;/usr/share/misc/mime.types&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">image/avif	avif</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">}</span>
</span></span></code></pre></div><p>⇒ To check the support of the webp format:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>$ grep webp /usr/share/misc/mime.types
</span></span><span style="display:flex;"><span>image/webp						webp
</span></span></code></pre></div><p>If the command not display result, we nee to add <code>image/webp	webp</code> into
the directive <strong>types</strong>. <em>Since OpenBSD 6.9, it&rsquo;s normally not needed!</em></p>
<hr>
<h2 id="troubleshots">Troubleshots</h2>
<h3 id="altq-style-queues-not-supported-anymore">ALTQ-style queues not supported anymore</h3>
<p>The complete message is:
<code>/etc/pfstat.conf:61: ALTQ-style queues not supported anymore</code></p>
<p>It seems, by default, that the queues analyze is not possible. Delete or
comment all relevent lines.</p>
<h3 id="dbopen-vardbpfstatpfstatdb-no-such-file-or-directory">dbopen: /var/db/pfstat/pfstat.db: No such file or directory</h3>
<p>Check if the folder is created!</p>
<hr>
<p>Voila!</p>
<p><em>(the final count… is down!<br>the final countdown!)</em></p>
<hr>
<h2 id="documentations">Documentations</h2>
<p>⇒ Those formats are supported by:</p>
<ul>
<li><a href="https://caniuse.com/avif" rel="external">https://caniuse.com/avif</a></li>
<li><a href="https://caniuse.com/webp" rel="external">https://caniuse.com/webp</a></li>
</ul>
]]></content><summary>Install pfstat to analyze stream on IPv4, IPv6 through the firewall PF (Packet Filter), on OpenBSD!</summary><published>2021-07-28T00:13:24+02:00</published><updated>2026-10-02T15:49:57+02:00</updated></entry><entry><id>tag:doc.huc.fr.eu.org,2021-07-24:/en/sys/openbsd/gnome</id><link href="https://it-log.fr.eu.org/en/sys/openbsd/gnome/" rel="alternate" type="text/html"/><title>OpenBSD: Gnome</title><author><name>Stéphane HUC</name></author><category term="OpenBSD" scheme="https://it-log.fr.eu.org/en/tags/openbsd/"/><category term="Gnome" scheme="https://it-log.fr.eu.org/en/tags/gnome/"/><content type="html"><![CDATA[<h2 id="description">Description</h2>
<p><strong>Gnome</strong> is one Desktop Environment, available on OpenBSD.</p>
<p>⇒ Environnement:</p>
<ul>
<li>OpenBSD: <del>6.9</del> → 7.1</li>
</ul>
<hr>
<p>In this tutorial, I assume that OpenBSD has just been freshly installed,
and that everything has to be done.</p>
<h2 id="installation">Installation</h2>
<p>Usual: <code># pkg_add gnome gnome-extras</code></p>
<p>Some dependancies are installed, like <strong>avahi</strong>, <strong>consolekit2</strong>, <strong>dbus</strong>,
<strong>samba</strong>, <strong>sane-backend</strong>, and many more.</p>
<h2 id="configuration">Configuration</h2>
<p>The Gnome3 environment works differently from other desktop environments.</p>
<p>Don&rsquo;t try to set up personal files <code>profile</code>, <code>.kshrc</code>, or even <code>.xsession</code>; they will not be taken into your account when starting and using Gnome.</p>
<h3 id="daemons">Daemons</h3>
<p>If during the OpenBSD installation you have activated <code>xenodm</code> — <em>the default X Display Manager</em> ­— disable it!</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:# rcctl disable xenodm
</span></span><span style="display:flex;"><span>:# rcctl stop xenodm
</span></span></code></pre></div><p>After, active <code>gdm</code>, the session manager, and all needed daemons.</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:# rcctl enable multicast messagebus avahi_daemon gdm
</span></span><span style="display:flex;"><span>:# rcctl start multicast messagebus avahi_daemon gdm
</span></span></code></pre></div><h3 id="language">Language</h3>
<p>To manage your language — <em>mine is FR</em> — you need to modify the <code>/etc/gdm/locale.conf</code>
file, as:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#776e71"># $OpenBSD: locale.conf,v 1.4 2014/01/08 14:07:48 ajacoutot Exp $</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># Mimics Linux&#39;s /etc/locale.conf.</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># See locale(1) for a list of supported locales (`locale -a`).</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># OpenBSD setlocale(3) does not handle LANG</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#LANG=&#34;en_US.UTF-8&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">LC_CTYPE</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;fr_FR.UTF-8&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">LC_MESSAGES</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;fr_FR.UTF-8&#34;</span>
</span></span></code></pre></div><p><em>If you do not make this change, and if you have a password with accented characters in your language, according to the keyboard settings during the OpenBSD installation, you will not be able to log in, because gdm uses English by default</em>.</p>
<hr>
<p>Think to restart gdm.</p>
<h3 id="power-management">Power Management</h3>
<p>To use the suspend and hibernate features, you need to active the <strong>apmd</strong>
daemon:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#776e71"># rcctl enable apmd</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># rcctl set apmd flags -A</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># rcctl start apmd</span>
</span></span></code></pre></div><h3 id="printing">Printing</h3>
<p>To print, install Cups:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#776e71"># pkg_add cups cups-filters cups-libs foomatic-db gutenprint</span>
</span></span></code></pre></div><p>Start both services <code>cupsd</code>, and <code>cups_browsed</code> — <em>this second is useful to detect printers on network using Bonjour broadcast messages, as Avahi</em>.</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#776e71"># rcctl enable cupsd cups_browsed</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># rcctl start cups cups_browsed</span>
</span></span></code></pre></div><p>You can administrate by the Printing Parameters, the webui of Cups, *available on <code>http://localhost:631*, or by tools as </code>cupsctl<code>, </code>lpadmin`.</p>
<h3 id="libreoffice">LibreOffice</h3>
<p>The <strong>gnome-documents</strong> manager does not support Office types documents.
Install the <code>unoconv</code> package!</p>
<h2 id="tips">Tips</h2>
<h3 id="keyboard">Keyboard</h3>
<h4 id="display-desktop">Display Desktop</h4>
<p>⇒ Don&rsquo;t try to hide all windows to show just the desktop, the option is not activated by default!</p>
<p>Open &ldquo;Parameters&rdquo; &gt; &ldquo;Keyboard&rdquo;. Into the <strong>Navigate windows</strong> section, search &ldquo;Minimize all windows&rdquo;. Click on and set the desired key combination, like the <kbd>Super + D</kbd> keys.</p>
<h3 id="random-wallpaper">Random Wallpaper</h3>
<p>This feature does not exist by default!</p>
<p>I provide two scripts to implement this feature, on my Gitlab:
<a href="https://framagit.org/hucste/tools/tree/master/OpenBSD/Gnome3/WallpaperManager" rel="external">WallpaperManager</a></p>
<p>Read the instructions to install and use it.</p>
<h2 id="troubleshooting">Troubleshooting</h2>
<p><strong>GDM</strong> refuse to start!</p>
<p>Directly, read the daemon log file, or even that of the messages log:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#776e71"># grep gdm /var/log/daemon</span>
</span></span></code></pre></div><h3 id="gdm-couldnt-connect-to-system-bus">Gdm: Couldn&rsquo;t connect to system bus:</h3>
<p>Into both files, <strong>daemons</strong>, <strong>messages</strong>, you have the equivalent of this message:</p>
<pre tabindex="0"><code class="language-log" data-lang="log">Jul 23 09:38:14 og3 gdm[56941]: Gdm: Couldn&#39;t connect to system bus: Could not connect: No such file or directory
</code></pre><p>Probably, this is because the <strong>messagebus</strong> service is not activated and started.</p>
<p>Have you activated all the services as written at the beginning of this article‽</p>
<h2 id="documentations">Documentations</h2>
<ul>
<li>the differents pkg-readme files:
<ul>
<li>/usr/local/share/doc/pkg-readmes/gnome</li>
<li>/usr/local/share/doc/pkg-readmes/gnupg</li>
<li>/usr/local/share/doc/pkg-readmes/samba</li>
<li>/usr/local/share/doc/pkg-readmes/sane-backends</li>
<li>and others…</li>
</ul>
</li>
</ul>
<hr>
<p>Voila!</p>
<hr>
]]></content><summary>How to install, set and use Gnome on OpenBSD!</summary><published>2021-07-24T20:00:00+02:00</published><updated>2026-10-02T15:49:57+02:00</updated></entry><entry><id>tag:doc.huc.fr.eu.org,2021-07-20:/en/sys/openbsd/xfce4</id><link href="https://it-log.fr.eu.org/en/sys/openbsd/xfce4/" rel="alternate" type="text/html"/><title>OpenBSD: Xfce4</title><author><name>Stéphane HUC</name></author><category term="OpenBSD" scheme="https://it-log.fr.eu.org/en/tags/openbsd/"/><category term="Xfce" scheme="https://it-log.fr.eu.org/en/tags/xfce/"/><category term="Xfce4" scheme="https://it-log.fr.eu.org/en/tags/xfce4/"/><content type="html"><![CDATA[<h2 id="description">Description</h2>
<p><strong>Xfce4</strong> is a Desktop Environnement, available on OpenBSD.</p>
<p>⇒ Environnement:</p>
<ul>
<li>OpenBSD: <del>6.6</del> → 7.8</li>
<li>Xfce4: <del>4.14</del> → 4.20</li>
</ul>
<hr>
<p>In this tutorial, I assume that OpenBSD has just been freshly installed, and that everything has to be done.</p>
<h2 id="installation">Installation</h2>
<p>Usual: <code>:# pkg_add xfce xfce-extras</code></p>
<p>Some dependancies are installed, like <code>dbus</code>, <code>consolekit2</code>.</p>
<h3 id="additionnal-packages">Additionnal packages</h3>
<p>By default, some packages are not installed.</p>
<ul>
<li><strong>xfce4-icon-theme</strong>: additional icons pack</li>
<li><strong>xfce4-power-manager</strong>: power management for laptop</li>
<li><strong>xfce4-pulseaudio</strong>: plugin for the pulseaudio sound system - <em>but, it&rsquo;s not necessary… OSS works great!</em></li>
<li><strong>xfce4-xkb</strong> : switch between layers keyboard languages - <em>but, is-it really useful, when using the command <code>setxkbmap</code>, or even just <code>kbd</code>, followed with the language code… is enough‽</em></li>
</ul>
<h2 id="configuration">Configuration</h2>
<p>Since Xfce4 4.14, available on OpenBSD 6.6, it&rsquo;s a bit easier to configure simply your personal environment system.</p>
<p>In a first step, I talk about a basic functional configuration; and, I&rsquo;ll add information to improve your comfort.</p>
<h3 id="xsession">.xsession</h3>
<p>The first file to create is: <code>~/.xsession</code>.</p>
<p>Add:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">/usr/local/bin/ck-launch-session  xfce4-session</span>
</span></span></code></pre></div><hr>
<p>Voila!</p>
<p>It&rsquo;s enough to run correctly Xfce4.
Think to restart your session or the machine.</p>
<hr>
<p>Now, let&rsquo;s go a little further in the configuration, like setting the
French language, <em>or yours</em>, and others useful tips.</p>
<h3 id="profile">.profile</h3>
<p>Start setting your personal file: <code>~/.profile</code></p>
<p>to add the following mentions:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">EDITOR</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">vi   # or nano, emacs, vim</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ENV</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">$HOME/.kshrc</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">LC_MESSAGES</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">fr  # or fr_FR.UTF8; it&#39;s egual!</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">export EDITOR ENV LC_MESSAGES</span>
</span></span></code></pre></div><p>⇒ Explains:</p>
<ul>
<li>I love <strong>nano</strong> as editor; into the base, <strong>vi</strong> is installed. The others need to be installed.</li>
<li>We declare a personal ENVironment; here, the <strong>pdksh</strong>.</li>
<li>Finally, define the language, as french.</li>
</ul>
<p>And we export the three variables.</p>
<p>Of course, it&rsquo;s possible to configure any environment variable, like <code>PS1</code>:</p>
<p><code>export PS1=&quot;[\t] \e[0;35m:\u@\h: \e[0;32m\w \e[0;36m\$ \e[m&quot;</code></p>
<hr>
<p>Here an complete instance:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#776e71"># $OpenBSD: dot.profile,v 1.7 2020/01/24 02:09:51 okan Exp $</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># sh/ksh initialization</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">PATH</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">$HOME/bin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/X11R6/bin:/usr/local/bin:/usr/local/sbin:/usr/games</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">export PATH HOME TERM</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">EDITOR</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">nano</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ENV</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">$HOME/.kshrc</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">LC_MESSAGES</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">fr</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">export EDITOR ENV LC_MESSAGES</span>
</span></span></code></pre></div><hr>
<p>You need to change your personal file <code>~/.xsession</code> to add your
environment profile:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">. $HOME/.profile</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">/usr/local/bin/ck-launch-session xfce4-session</span>
</span></span></code></pre></div><p>Thus your graphic session will take account differents settings of your
profile, such as language.</p>
<h3 id="kshrc">.kshrc</h3>
<p>The content of this personal file is not complicated. Here is what to
add to be functional:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">. /etc/ksh.kshrc</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">. $HOME/.profile</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">HISTCONTROL</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">ignoredumps</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">HISTFILE</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">$HOME/.mksh_hist</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">HISTSIZE</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">10000</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">PAGER</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">less</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">export PAGER</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">/usr/local/bin/ck-launch-session xfce4-session</span>
</span></span></code></pre></div><p>⇒ Useful explains:</p>
<ul>
<li>
<p>We source the global initialization for ksh to obtain a correct
environment shell.</p>
</li>
<li>
<p>We source your personal profil file.</p>
</li>
<li>
<p><strong>HIST</strong> variables are usefull to historize the orders commands:</p>
<ul>
<li><code>HISTFILE</code>: to define the backup file history</li>
<li><code>HISTSIZE</code>: the number of commands to remember; do not confuse with
the number of lines into file, defined with <code>HISTFILESIZE</code> - <em>not here</em>.</li>
<li>it&rsquo;s not necessary to export them.</li>
</ul>
</li>
</ul>
<h3 id="dbus">dbus</h3>
<p><strong>dbus</strong> is installed as dependancy.</p>
<p>The changes below are not essential, although useful. They&rsquo;re reported on the relative pkg-readme file.</p>
<p>Add into your personal file <code>~/.xsession</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">if [ -x /usr/local/bin/dbus-launch -a -z &#34;${DBUS_SESSION_BUS_ADDRESS}&#34; ]; then</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">eval `dbus-launch --sh-syntax --exit-with-x11`</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">fi</span>
</span></span></code></pre></div><p>The file will look like this:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">. $HOME/.profile</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">if [ -x /usr/local/bin/dbus-launch -a -z &#34;${DBUS_SESSION_BUS_ADDRESS}&#34; ]; then</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">eval `dbus-launch --sh-syntax --exit-with-x11`</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">fi</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">exec xfce4-session</span>
</span></span></code></pre></div><hr>
<p>Egual, pkg-readme <strong>upower</strong> informs us that it&rsquo;s useful to run the <strong>apmd</strong>
and <strong>messagebus</strong> services, so the power management system works; let&rsquo;s
go to enable the latter:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#776e71"># rcctl enable messagebus</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># rcctl start messagebus</span>
</span></span></code></pre></div><p>⇒ if your machine is a laptop, think to install <strong>xfce4-powermanager</strong>
package, which is not provided by default.</p>
<h3 id="printing">Printing</h3>
<p>To print, install Cups:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#776e71"># pkg_add  cups cups-filters cups-libs foomatic-db gutenprint</span>
</span></span></code></pre></div><p>Start both services <strong>cupsd</strong>, and <strong>cups_browsed</strong> — <em>this second is useful
to detect printers on network using Bonjour broadcast messages</em>.</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#776e71"># rcctl enable cupsd cups_browsed</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># rcctl start cups cups_browsed</span>
</span></span></code></pre></div><p>You can administrate by the webui of Cups, available on http://localhost:631,
or by tools as <strong>cupsctl</strong>, <strong>lpadmin</strong>.</p>
<hr>
<p>Since OpenBSD 6.2, binaries <strong>lpq</strong>, <strong>lpr</strong>, and <strong>lprm</strong> need to be symbolics
links to run smoothly.</p>
<p>Edit again your personal file <code>~/.kshrc</code> to add:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">for i in lpq lpr lprm; do alias $i</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">/usr/local/bin/$i; done</span>
</span></span></code></pre></div><h3 id="avahi">Avahi</h3>
<p><strong>Avahi</strong> is, on OpenBSD, the DNS multicast discovery service.</p>
<p>Just install the <strong>avahi</strong> package, and after active and start the
services:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#776e71"># rcctl enable multicast avahi_daemon</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># rcctl order messagebus avahi_daemon</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># rcctl start avahi_daemon</span>
</span></span></code></pre></div><p>Normally, messagebus is already started!</p>
<h3 id="performances">Performances</h3>
<h4 id="apmd">apmd</h4>
<p>To use the sleep and hibernate functions, <strong>apmd</strong> need to be set.
We set on automatic performance adjustement mode.</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#776e71"># rcctl enable apmd</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># rcctl set apmd flags -A</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># rcctl start apmd</span>
</span></span></code></pre></div><h4 id="obsdfreqd">obsdfreqd</h4>
<p>If you have a laptop or would like the system to manage performance
fine-tune performance, you may prefer to use the use of <strong>obsdfreqd</strong>.</p>
<p><strong>obsdfreqd</strong> is a CPU frequency manager, created by Solène
Rapenne, packaged since OpenBSD 7.1.</p>
<p>It replace the native <strong>apmd</strong> daemon.</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#776e71"># rcctl enable obsdfreqd</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># rcctl stop apmd</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># rcctl set apmd flags -L</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># rcctl start apmd obsdfreqd</span>
</span></span></code></pre></div><p><strong>Explanations</strong>:</p>
<ul>
<li>it&rsquo;s necessary to start <strong>apmd</strong> in the manual mode, for obsdfreqd can handle it.</li>
<li>obsdfreqd&rsquo;s defaults settings are enough.</li>
</ul>
<h2 id="tips">Tips</h2>
<h3 id="pf">PF</h3>
<p>I&rsquo;ve not discuted about firewall rules, but here is an example:</p>
<p>⇒ Cups :</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">pass in on egress proto tcp from egress:network to egress port 631 flags S/SA modulate state</span>
</span></span></code></pre></div><p>⇒ Avahi :</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">pass proto udp from any to 224.0.0.251 port mdns allow-opts</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">pass inet6 proto udp from any to ff02::fb port mdns allow-opts</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">pass proto udp from any to 239.255.255.250 port ssdp allow-opts</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">pass inet6 proto udp from any to { ff02::c, ff05::c, ff08::c } port ssdp allow-opts</span>
</span></span></code></pre></div><p>Of course, it&rsquo;s up to you!</p>
<h3 id="voila">Voila</h3>
<p>Think to restart your session, after modifying yours personals files.</p>
<p>After, you can install others packages…</p>
<hr>
<p>Voila!</p>
<h2 id="documentations">Documentations</h2>
<ul>
<li>the differents pkg-readme files:
<ul>
<li>/usr/local/share/doc/pkg-readmes/xfce</li>
<li>/usr/local/share/doc/pkg-readmes/dbus</li>
<li>/usr/local/share/doc/pkg-readmes/upower</li>
</ul>
</li>
</ul>
<hr>
<ul>
<li>Official FAQ: <a href="https://wiki.xfce.org/faq" rel="external">https://wiki.xfce.org/faq</a></li>
<li>Official tips: <a href="https://wiki.xfce.org/tips" rel="external">https://wiki.xfce.org/tips</a></li>
</ul>
<hr>
]]></content><summary>How-to install, set and use Xfce4 on OpenBSD!</summary><published>2021-07-20T21:05:54+02:00</published><updated>2026-10-02T15:49:57+02:00</updated></entry><entry><id>tag:doc.huc.fr.eu.org,2021-07-18:/en/sys/openbsd/nut</id><link href="https://it-log.fr.eu.org/en/sys/openbsd/nut/" rel="alternate" type="text/html"/><title>OpenBSD: Managing an inverter/converter with NUT</title><author><name>Stéphane HUC</name></author><category term="OpenBSD" scheme="https://it-log.fr.eu.org/en/tags/openbsd/"/><category term="NUT" scheme="https://it-log.fr.eu.org/en/tags/nut/"/><category term="UPS" scheme="https://it-log.fr.eu.org/en/tags/ups/"/><content type="html"><![CDATA[<h2 id="description">Description</h2>
<p>Having an Eaton Ellipse ECO UPS, I use the <abbr title="Network UPS Tools">NUT</abbr>
project to manage it under OpenBSD.</p>
<p>⇒ OS:</p>
<ul>
<li>OpenBSD: <del>6.9</del> ⇒ 7.6</li>
</ul>
<p>⇒ UPS Hardware: <del>Eaton Ellipse ECO 650 VA USB FR</del>, <strong>MGE ELLIPSE 1000</strong></p>
<h2 id="installation">Installation</h2>
<p>Like as : <code># pkg_add nut</code></p>
<h2 id="configuration">Configuration</h2>
<p>The <strong>nut-scanner</strong> tool allow to detect any UPS hardware connected, either
by USB, or network.</p>
<p>With administrator rights:</p>
<ul>
<li>Example for Eaton Ellipse ECO 650 VA USB FR :</li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:$ doas nut-scanner
</span></span><span style="display:flex;"><span>SNMP library not found. SNMP search disabled.
</span></span><span style="display:flex;"><span>Neon library not found. XML search disabled.
</span></span><span style="display:flex;"><span>AVAHI client library not found. AVAHI search disabled.
</span></span><span style="display:flex;"><span>Scanning USB bus.
</span></span><span style="display:flex;"><span>No start IP, skipping NUT bus <span style="color:#5bc4bf">(</span>old connect method<span style="color:#5bc4bf">)</span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">[</span>nutdev1<span style="color:#5bc4bf">]</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ef6155">driver</span> <span style="color:#5bc4bf">=</span> <span style="color:#48b685">&#34;usbhid-ups&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ef6155">port</span> <span style="color:#5bc4bf">=</span> <span style="color:#48b685">&#34;auto&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ef6155">vendorid</span> <span style="color:#5bc4bf">=</span> <span style="color:#48b685">&#34;0463&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ef6155">productid</span> <span style="color:#5bc4bf">=</span> <span style="color:#48b685">&#34;FFFF&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ef6155">product</span> <span style="color:#5bc4bf">=</span> <span style="color:#48b685">&#34;Ellipse ECO&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ef6155">serial</span> <span style="color:#5bc4bf">=</span> <span style="color:#48b685">&#34;000000000&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ef6155">vendor</span> <span style="color:#5bc4bf">=</span> <span style="color:#48b685">&#34;EATON&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ef6155">bus</span> <span style="color:#5bc4bf">=</span> <span style="color:#48b685">&#34;005&#34;</span>
</span></span></code></pre></div><ul>
<li>Example for MGE ELLIPSE 1000 :</li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>Cannot load SNMP library <span style="color:#5bc4bf">(</span>libnetsnmp.so<span style="color:#5bc4bf">)</span> : file not found. SNMP search disabled.
</span></span><span style="display:flex;"><span>Cannot load XML library <span style="color:#5bc4bf">(</span>libneon.so<span style="color:#5bc4bf">)</span> : file not found. XML search disabled.
</span></span><span style="display:flex;"><span>Scanning USB bus.
</span></span><span style="display:flex;"><span>No start IP, skipping NUT bus <span style="color:#5bc4bf">(</span>old connect method<span style="color:#5bc4bf">)</span>
</span></span><span style="display:flex;"><span>Scanning NUT bus <span style="color:#5bc4bf">(</span>avahi method<span style="color:#5bc4bf">)</span>.
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">[</span>nutdev1<span style="color:#5bc4bf">]</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ef6155">driver</span> <span style="color:#5bc4bf">=</span> <span style="color:#48b685">&#34;usbhid-ups&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ef6155">port</span> <span style="color:#5bc4bf">=</span> <span style="color:#48b685">&#34;auto&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ef6155">vendorid</span> <span style="color:#5bc4bf">=</span> <span style="color:#48b685">&#34;0463&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ef6155">productid</span> <span style="color:#5bc4bf">=</span> <span style="color:#48b685">&#34;FFFF&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ef6155">product</span> <span style="color:#5bc4bf">=</span> <span style="color:#48b685">&#34;ELLIPSE&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ef6155">serial</span> <span style="color:#5bc4bf">=</span> <span style="color:#48b685">&#34;1H6G4401F&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ef6155">vendor</span> <span style="color:#5bc4bf">=</span> <span style="color:#48b685">&#34;MGE UPS SYSTEMS&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ef6155">bus</span> <span style="color:#5bc4bf">=</span> <span style="color:#48b685">&#34;001&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ef6155">device</span> <span style="color:#5bc4bf">=</span> <span style="color:#48b685">&#34;002&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ef6155">busport</span> <span style="color:#5bc4bf">=</span> <span style="color:#48b685">&#34;002&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#776e71">###NOTMATCHED-YET###bcdDevice = &#34;4241&#34;</span>
</span></span></code></pre></div><p>Now, few configuration files are to be modified. Any change on one of them
needs to restart the ad hoc services.</p>
<h3 id="upsconf">ups.conf</h3>
<ul>
<li>Configuration file: <code>/etc/nut/ups.conf</code></li>
</ul>
<p>You have to fill this file with the returned informations by the software:</p>
<ul>
<li>Example for Eaton Ellipse ECO 650 VA USB FR :</li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">(…)</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#815ba4">[eaton]</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">desc</span> <span style="color:#5bc4bf">=</span> <span style="color:#48b685">&#34;Eaton Ellipse ECO 650 VA USB FR&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#48b685">    driver = &#34;usbhid-ups&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#48b685">    port = &#34;auto&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#48b685">    vendorid = &#34;0463&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#48b685">    productid = &#34;FFFF&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#48b685">    product = &#34;Ellipse ECO&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#48b685">    serial = &#34;000000000&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#48b685">    vendor = &#34;EATON&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#48b685">    bus = &#34;005&#34;</span>
</span></span></code></pre></div><h3 id="upsdconf">upsd.conf</h3>
<ul>
<li>Configuration file: <code>/etc/nut/upsd.conf</code></li>
</ul>
<p>This file allow to set the access control to the managed datas by upds.
By default, the server is only accessible on localhost, in IPv4, IPv6,
on port 3493.</p>
<p>As instance, you need to set this file to use TLS.</p>

<div class="tab-info i-info">Info</div><div class="alert alert-info" role="alert"><p>Since v2.4.0, the <strong>ACL</strong> and <strong>allowfrom</strong> directives have been replaced
by the <strong>LISTEN</strong> directive and tcp-wrappers! <br>
<em>(cf la <a href="https://networkupstools.org/docs/user-manual.chunked/apis12.html" rel="external">note de changements</a>…)</em></p>
<p>Do not use thoses oldiers ACL directives; many old tutorials refer to it :( <br>
Take it into account!</p>
</div>


<div class="tab-info i-warning">Warning</div><div class="alert alert-warning" role="alert">If the LISTEN directive is configured to allow access on IPv4, IPv6 adress,
you have to manage PF to allow the connexion on the adequat port…</div>

<h3 id="upsdusers">upsd.users</h3>
<ul>
<li>Configuration file: <code>/etc/nut/upsd.users</code></li>
</ul>
<p>This configuration file allow to set users who will have rights to interact
with the upsd server.</p>

<div class="tab-info i-warning">Warning</div><div class="alert alert-warning" role="alert"><p>It is IMPERATIVE that this file has the most minimalist system rights! <br>
<em>By default, on OpenBSD, only the dedicate user had read and write access.</em></p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:$ doas chmod <span style="color:#f99b15">0400</span> /etc/nut/upsd.users
</span></span></code></pre></div></div>

<p>Now, set an user who will have the rights to comminucate between upsd and
upmon servers:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#815ba4">[upsmon]</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">password</span> <span style="color:#5bc4bf">=</span> <span style="color:#48b685">***
</span></span></span><span style="display:flex;"><span><span style="color:#48b685">    upsmon master</span>
</span></span></code></pre></div><p>More explains, here we are:</p>
<ul>
<li>an <strong>upsmon</strong> username <em>into the brackets</em></li>
<li>with master rights on upsmon service.
<ul>
<li><em>(this defines the role which, according to its dominance, will
stop the system first or last, in the case of management of several
connected OS; in the context of a single managed OS, the value
<strong>master</strong> is imposed by itself)</em>.</li>
</ul>
</li>
<li>and, set the <strong>password</strong> value, by your choice.</li>
</ul>
<hr>
<p>Now, we modify the <strong>upsmon.conf</strong> file.</p>
<h3 id="upsmonconf">upsmon.conf</h3>
<ul>
<li>Configuration file: <code>/etc/nut/upsmon.conf</code></li>
</ul>
<p>This configuration file allow the monitor service.</p>

<div class="tab-info i-warning">Warning</div><div class="alert alert-warning" role="alert">Warning: this file contains sensitive information, it is therefore
imperative to check the permissions and user rights.</div>

<p>Following the modification of the <strong>upsd.users</strong> file to configure a
<strong>upsmon</strong> user, we need to add a <strong>MONITOR</strong> directive, such as:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">MONITOR eaton@localhost 1 upsmon *** master</span>
</span></span></code></pre></div><p><em>(Change &lsquo;***&rsquo; by your upsmon password)</em></p>
<p>⇒ Now, at least, we need to modify <strong>NOTIFYMSG</strong>, <strong>NOTIFYFLAG</strong> directives;
<em>please, see the official documentation</em>…</p>
<p>⇒ About the <strong>NOTIFYFLAG</strong> directives, it is important to add the <strong>EXEC</strong>
flag for the execution of commands. Without it, they will not be executed.</p>
<p>⇒ About the <strong>NOTIFYCMD</strong> directive: this is not set up correctly:</p>
<ul>
<li>first, uncomment it, and</li>
<li>change the path to the <strong>upssched</strong> binary, like: <br>
<code>NOTIFYCMD /usr/local/sbin/upssched</code></li>
</ul>
<p>Now, the <strong>upsmon</strong> service will relay to <strong>upsched</strong> binary; this tool
will read the <strong>upssched.conf</strong> configuration file. <br>
<em>See the <strong><a href="https://networkupstools.org/docs/user-manual.chunked/ar01s07.html" rel="external">Suppressing notify storms</a></strong>
official documentation about why it&rsquo;s needed!</em></p>
<h3 id="upsschedconf">upssched.conf</h3>
<ul>
<li>Configuration file: <code>/etc/nut/upssched.conf</code></li>
</ul>
<p>This configuration file allow actions to plan.</p>
<p>It&rsquo;s necessary to uncomment <strong>PIPEFN</strong>, <strong>LOCKFN</strong>, and <strong>AT</strong> directives.</p>
<p>⇒ About <strong>LOCKFN</strong> and <strong>PIPEFN</strong>: the absolute pathname by default not
exists; you need to create and give access for the <strong>_ups</strong> user:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:# install -d -o _ups -g wheel -m <span style="color:#f99b15">750</span> /var/db/nut/upssched
</span></span></code></pre></div><p>⇒ Now, we create the needed <strong>AT</strong> directives; as instance:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">(…)</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">AT ONBATT * START-TIMER onbatt 15</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">AT ONBATT * START-TIMER onbattwarn 30</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">(…)</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">AT ONLINE * CANCEL-TIMER onbatt</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">AT ONLINE * CANCEL-TIMER onbattwarn</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">(…)</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">AT ONLINE * EXECUTE ups-back-on-line</span>
</span></span></code></pre></div><p>FYI: it&rsquo;s possible to modify the <code>/usr/local/bin/upssched-cmd</code> script
to interact with the system according to the called event.
<em>See the official documentation</em>…</p>
<h3 id="upssetconf">upsset.conf</h3>
<ul>
<li>Configuration file: <code>/etc/nut/upsset.conf</code></li>
</ul>
<p>This file allow to use CGI scripts, builded on the <strong>nut-cgi</strong> package.
One only role: to certify that the configuration to use the CGI scripts
is indeed (supposedly?) secure.</p>
<p>It is <strong>only</strong> useful in this context.</p>
<h3 id="permissions">Permissions</h3>

<div class="tab-info i-info">Info</div><div class="alert alert-info" role="alert">At each OpenBSD release migration, it will be necessary to change the
permissions again, as they are permissions again, as they are reset.</div>

<p>During the installation, here are configured:</p>
<ul>
<li>an <strong>_ups</strong> user</li>
<li>and an <strong>_ups</strong> group</li>
</ul>
<p>It is necessary to configure user permissions in order to have access
to the appropriate device node.</p>
<p>⇒ For the USB devices, you need to identify the USB controller to which
the UPS device is connected, or even the <strong>ugen</strong> device node(s).</p>
<p>We use the <strong>usbdevs</strong> command, like as:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:$ doas usbdevs
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">(</span>…<span style="color:#5bc4bf">)</span>
</span></span><span style="display:flex;"><span>Controller /dev/usb5:
</span></span><span style="display:flex;"><span>addr 01: 1002:0000 ATI, OHCI root hub
</span></span><span style="display:flex;"><span>addr 02: 0463:ffff EATON, Ellipse ECO
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">(</span>…<span style="color:#5bc4bf">)</span>
</span></span></code></pre></div><p><em>In this cas, the UPS device is connected on the <strong>usb5</strong> controller,
without specified device nodes</em>.</p>
<hr>
<p>Now, we change the rights user on the device; on this case:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:$ doas chown :_ups /dev/usb5 <span style="color:#776e71"># ou, chgrp _ups /dev/usb5</span>
</span></span><span style="display:flex;"><span>:$ doas chmod g+w /dev/usb5
</span></span></code></pre></div><p>Now, the <strong>_ups</strong> group gained access to the controller!</p>
<p>Finally, let&rsquo;s make sure we have user rights on the files into &lsquo;/etc/nut&rsquo;:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:$ doas chown _ups:_ups /etc/nut/ups*
</span></span></code></pre></div><p>Normally, this enough to start the services.</p>
<hr>

<div class="tab-info i-warning">Warning</div><div class="alert alert-warning" role="alert">Few USB APC-like inverters have problems; see the pkg-readme file!</div>

<hr>
<p>⇒ if the inverter is connected by RS232, either you need to:</p>
<ul>
<li>add the <strong>_ups</strong> user to the <strong>dialer</strong> group, or</li>
<li>modify the user rights on the <code>/dev/tty</code> adequat, that the <strong>_ups</strong> user
can manage it.</li>
</ul>
<h3 id="services">Services</h3>
<p>About services, you have to enable and start those follow daemons:</p>
<ul>
<li><strong>upsd</strong>: to manage network server</li>
<li><strong>upsmon</strong>: to manage the monitor</li>
</ul>
<p><strong>upsd</strong> need to start in first, before <strong>upsmon</strong>.</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:$ doas rcctl enable upsd upsmon
</span></span><span style="display:flex;"><span>:$ doas rcctl set upsd flags -u _ups
</span></span><span style="display:flex;"><span>:$ doas rcctl start upsd upsmon
</span></span></code></pre></div><p>Normally, the <strong>daemon</strong> log notify thoses services:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#5bc4bf">(</span>…<span style="color:#5bc4bf">)</span>
</span></span><span style="display:flex;"><span>Jul <span style="color:#f99b15">17</span> 13:25:34 sh1 usbhid-ups<span style="color:#5bc4bf">[</span>47317<span style="color:#5bc4bf">]</span>: Startup successful
</span></span><span style="display:flex;"><span>Jul <span style="color:#f99b15">17</span> 13:25:34 sh1 upsd<span style="color:#5bc4bf">[</span>83153<span style="color:#5bc4bf">]</span>: listening on ::1 port <span style="color:#f99b15">3493</span>
</span></span><span style="display:flex;"><span>Jul <span style="color:#f99b15">17</span> 13:25:34 sh1 upsd<span style="color:#5bc4bf">[</span>83153<span style="color:#5bc4bf">]</span>: listening on 127.0.0.1 port <span style="color:#f99b15">3493</span>
</span></span><span style="display:flex;"><span>Jul <span style="color:#f99b15">17</span> 13:25:34 sh1 upsd<span style="color:#5bc4bf">[</span>83153<span style="color:#5bc4bf">]</span>: Connected to UPS <span style="color:#5bc4bf">[</span>eaton<span style="color:#5bc4bf">]</span>: usbhid-ups-eaton
</span></span><span style="display:flex;"><span>Jul <span style="color:#f99b15">17</span> 13:25:34 sh1 upsd<span style="color:#5bc4bf">[</span>90348<span style="color:#5bc4bf">]</span>: Startup successful
</span></span><span style="display:flex;"><span>Jul <span style="color:#f99b15">17</span> 13:25:34 sh1 upsmon<span style="color:#5bc4bf">[</span>19005<span style="color:#5bc4bf">]</span>: Startup successful
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">(</span>…<span style="color:#5bc4bf">)</span>
</span></span></code></pre></div><h2 id="check">Check</h2>
<h3 id="status">Status</h3>
<p><strong>upsc</strong> is a tool to check the inverter status, like: <br>
<code>:$ upsc eaton</code> est la même chose que faire <code>$ upsc eaton@localhost</code></p>
<p>⇒ To known the battery status:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:$ upsc eaton ups.status
</span></span><span style="display:flex;"><span>OL
</span></span></code></pre></div><p>Few explains:</p>
<ul>
<li><strong>OL</strong> signify <strong>On Line</strong>; all is good!</li>
<li><strong>OB</strong>: <strong>On Battery</strong>: the inverter now only works on the battery</li>
<li><strong>LB</strong>: <strong>Low Battery</strong>: the battery is at its lowest charge level!</li>
</ul>
<p><strong>OB</strong> and <strong>LB</strong> must trigger actions; they are configured on <strong>upsmon.conf</strong>
file, or even <strong>upssched.conf</strong>.</p>
<h3 id="process-and-files">Process and files</h3>
<p>You can check what are the process managed by the <strong>_ups</strong> user, and the
opened files; as instance, with <code>ps</code> and <code>fstat</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:$ ps aux -U _ups
</span></span><span style="display:flex;"><span>USER       PID %CPU %MEM   VSZ   RSS TT  STAT   STARTED       TIME COMMAND
</span></span><span style="display:flex;"><span>_ups     <span style="color:#f99b15">31655</span>  0.0  0.0   <span style="color:#f99b15">836</span>  <span style="color:#f99b15">1668</span> ??  S       5:07PM    0:00.70 /usr/local/bin/usbhid-ups -a eaton
</span></span><span style="display:flex;"><span>_ups      <span style="color:#f99b15">4840</span>  0.0  0.0   <span style="color:#f99b15">764</span>  <span style="color:#f99b15">1308</span> ??  S       5:07PM    0:00.12 /usr/local/sbin/upsd -u _ups
</span></span><span style="display:flex;"><span>_ups     <span style="color:#f99b15">65469</span>  0.0  0.0   <span style="color:#f99b15">780</span>  <span style="color:#f99b15">3084</span> ??  S       5:07PM    0:00.09 /usr/local/sbin/upsmon
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>:$ fstat -u _ups -n
</span></span><span style="display:flex;"><span>USER     CMD          PID   FD  DEV      INUM        MODE   R/W    SZ|DV
</span></span><span style="display:flex;"><span>_ups     upsmon     <span style="color:#f99b15">65469</span>   wd  4,0    <span style="color:#f99b15">103712</span>        <span style="color:#f99b15">40700</span>    r      <span style="color:#f99b15">512</span>
</span></span><span style="display:flex;"><span>_ups     upsmon     <span style="color:#f99b15">65469</span>    <span style="color:#f99b15">0</span>  4,0     <span style="color:#f99b15">27162</span>        <span style="color:#f99b15">20666</span>   rw    2,2
</span></span><span style="display:flex;"><span>_ups     upsmon     <span style="color:#f99b15">65469</span>    <span style="color:#f99b15">1</span>  4,0     <span style="color:#f99b15">27162</span>        <span style="color:#f99b15">20666</span>   rw    2,2
</span></span><span style="display:flex;"><span>_ups     upsmon     <span style="color:#f99b15">65469</span>    <span style="color:#f99b15">2</span>  4,0     <span style="color:#f99b15">27162</span>        <span style="color:#f99b15">20666</span>   rw    2,2
</span></span><span style="display:flex;"><span>_ups     upsmon     <span style="color:#f99b15">65469</span>    3* internet stream tcp 0x0 127.0.0.1:26706 --&gt; 127.0.0.1:3493
</span></span><span style="display:flex;"><span>_ups     upsmon     <span style="color:#f99b15">65469</span>    <span style="color:#f99b15">4</span> pipe 0x0 state:
</span></span><span style="display:flex;"><span>_ups     upsd        <span style="color:#f99b15">4840</span>   wd  4,4     <span style="color:#f99b15">26111</span>        <span style="color:#f99b15">40700</span>    r      <span style="color:#f99b15">512</span>
</span></span><span style="display:flex;"><span>_ups     upsd        <span style="color:#f99b15">4840</span>    <span style="color:#f99b15">0</span>  4,0     <span style="color:#f99b15">27162</span>        <span style="color:#f99b15">20666</span>   rw    2,2
</span></span><span style="display:flex;"><span>_ups     upsd        <span style="color:#f99b15">4840</span>    <span style="color:#f99b15">1</span>  4,0     <span style="color:#f99b15">27162</span>        <span style="color:#f99b15">20666</span>   rw    2,2
</span></span><span style="display:flex;"><span>_ups     upsd        <span style="color:#f99b15">4840</span>    <span style="color:#f99b15">2</span>  4,0     <span style="color:#f99b15">27162</span>        <span style="color:#f99b15">20666</span>   rw    2,2
</span></span><span style="display:flex;"><span>_ups     upsd        <span style="color:#f99b15">4840</span>    3* internet6 stream tcp 0x0 <span style="color:#5bc4bf">[</span>::1<span style="color:#5bc4bf">]</span>:3493
</span></span><span style="display:flex;"><span>_ups     upsd        <span style="color:#f99b15">4840</span>    4* internet stream tcp 0x0 127.0.0.1:3493
</span></span><span style="display:flex;"><span>_ups     upsd        <span style="color:#f99b15">4840</span>    5* unix stream 0x0
</span></span><span style="display:flex;"><span>_ups     upsd        <span style="color:#f99b15">4840</span>    6* internet stream tcp 0x0 127.0.0.1:3493 &lt;-- 127.0.0.1:26706
</span></span><span style="display:flex;"><span>_ups     usbhid-ups <span style="color:#f99b15">31655</span>   wd  4,4     <span style="color:#f99b15">26111</span>        <span style="color:#f99b15">40700</span>    r      <span style="color:#f99b15">512</span>
</span></span><span style="display:flex;"><span>_ups     usbhid-ups <span style="color:#f99b15">31655</span>    <span style="color:#f99b15">0</span>  4,0     <span style="color:#f99b15">27162</span>        <span style="color:#f99b15">20666</span>   rw    2,2
</span></span><span style="display:flex;"><span>_ups     usbhid-ups <span style="color:#f99b15">31655</span>    <span style="color:#f99b15">1</span>  4,0     <span style="color:#f99b15">27162</span>        <span style="color:#f99b15">20666</span>   rw    2,2
</span></span><span style="display:flex;"><span>_ups     usbhid-ups <span style="color:#f99b15">31655</span>    <span style="color:#f99b15">2</span>  4,0     <span style="color:#f99b15">27162</span>        <span style="color:#f99b15">20666</span>   rw    2,2
</span></span><span style="display:flex;"><span>_ups     usbhid-ups <span style="color:#f99b15">31655</span>    <span style="color:#f99b15">3</span> pipe 0x0 state:
</span></span><span style="display:flex;"><span>_ups     usbhid-ups <span style="color:#f99b15">31655</span>    <span style="color:#f99b15">4</span> pipe 0x0 state:
</span></span><span style="display:flex;"><span>_ups     usbhid-ups <span style="color:#f99b15">31655</span>    5* unix stream 0x0 /var/db/nut/usbhid-ups-eaton
</span></span><span style="display:flex;"><span>_ups     usbhid-ups <span style="color:#f99b15">31655</span>    6* unix stream 0x0 /var/db/nut/usbhid-ups-eaton
</span></span></code></pre></div><p>We notice:</p>
<ul>
<li>
<p>upsd and upsmon run correctly, well managed by <strong>_ups</strong> user</p>
<ul>
<li>streams TCP are correctly created, and used on localhost</li>
</ul>
</li>
<li>
<p>the <strong>eaton</strong> profil is correctly managed by <strong>usbhid-ups</strong>!</p>
</li>
</ul>
<h2 id="troubleshooting">Troubleshooting</h2>
<h3 id="connection-refused">Connection refused</h3>
<p>Here, an example about errors messages:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#5bc4bf">(</span>…<span style="color:#5bc4bf">)</span>
</span></span><span style="display:flex;"><span>upsd<span style="color:#5bc4bf">[</span>55984<span style="color:#5bc4bf">]</span>: Can<span style="color:#ef6155">&#39;</span>t connect to UPS <span style="color:#5bc4bf">[</span>eaton<span style="color:#5bc4bf">]</span> <span style="color:#5bc4bf">(</span>usbhid-ups-eaton<span style="color:#5bc4bf">)</span>: Connection refused
</span></span><span style="display:flex;"><span>upsmon<span style="color:#5bc4bf">[</span>20574<span style="color:#5bc4bf">]</span>: Poll UPS <span style="color:#5bc4bf">[</span>eaton@localhost<span style="color:#5bc4bf">]</span> failed - Driver not connected
</span></span><span style="display:flex;"><span>upsmon<span style="color:#5bc4bf">[</span>20574<span style="color:#5bc4bf">]</span>: Communications with UPS eaton@localhost lost
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">(</span>…<span style="color:#5bc4bf">)</span>
</span></span><span style="display:flex;"><span>upsmon<span style="color:#5bc4bf">[</span>44238<span style="color:#5bc4bf">]</span>: UPS eaton@localhost is unavailable
</span></span><span style="display:flex;"><span>upsmon<span style="color:#5bc4bf">[</span>44238<span style="color:#5bc4bf">]</span>: UPS <span style="color:#5bc4bf">[</span>eaton@localhost<span style="color:#5bc4bf">]</span>: connect failed: Connection failure: Connection refused
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">(</span>…<span style="color:#5bc4bf">)</span>
</span></span></code></pre></div><p>At least, two possibles reasons:</p>
<ul>
<li>
<p><strong>check the physical USB connection</strong>. May be, it&rsquo;s usefull to change
the USB cable, or disconnect to reconnect it. Even, the USB ports on the
motherboard or your USB hub can be defective/faulty.</p>
</li>
<li>
<p><strong>after a OpenBSD upgrade</strong>: it&rsquo;s necessary to redo the needed
<a href="/en/sys/openbsd/nut/#permissions">permissions</a> !</p>
</li>
</ul>
<h3 id="login-failed">Login failed</h3>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>upsmon<span style="color:#5bc4bf">[</span>39287<span style="color:#5bc4bf">]</span>: Login on UPS <span style="color:#5bc4bf">[</span>eaton@localhost<span style="color:#5bc4bf">]</span> failed - got <span style="color:#5bc4bf">[</span>ERR ACCESS-DENIED<span style="color:#5bc4bf">]</span>
</span></span></code></pre></div><p>Check your managed user between <strong>upsd.users</strong> and <strong>upsmon.conf</strong> files.</p>
<h3 id="permission-denied">Permission denied</h3>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>upsd<span style="color:#5bc4bf">[</span>87303<span style="color:#5bc4bf">]</span>: Can<span style="color:#ef6155">&#39;</span>t open /etc/nut/upsd.conf: Permission denied
</span></span></code></pre></div><p>Check the user rights on this file; it must belong to the <strong>_ups</strong> user.</p>
<hr>
<h2 id="nut-cgi">nut-cgi</h2>
<p><strong>nut-cgi</strong> provides CGI scripts to monitor the inverter through the web
service.</p>
<p>Actually, this officially works only with the Apache server, and requires
writing a configuration file <strong>hosts.conf</strong>, not created by default.</p>
<hr>
<h2 id="documentations">Documentations</h2>
<ul>
<li>Projet NUT : <a href="https://networkupstools.org/" rel="external">https://networkupstools.org/</a></li>
<li>pkg-readme : <code>/usr/local/share/doc/pkg-readmes/nut</code></li>
</ul>
<hr>
]]></content><summary>Managing an inverter with the NUT project on OpenBSD</summary><published>2021-07-18T15:34:24+02:00</published><updated>2026-10-02T15:49:57+02:00</updated></entry><entry><id>tag:doc.huc.fr.eu.org,2021-02-21:/en/sys/openbsd/vmd-serial-console</id><link href="https://it-log.fr.eu.org/en/sys/openbsd/vmd-serial-console/" rel="alternate" type="text/html"/><title>[OpenBSD :: Virtualization] No login screen ; no login!</title><author><name>Stéphane HUC</name></author><category term="OpenBSD" scheme="https://it-log.fr.eu.org/en/tags/openbsd/"/><category term="vmd" scheme="https://it-log.fr.eu.org/en/tags/vmd/"/><category term="astuce" scheme="https://it-log.fr.eu.org/en/tags/astuce/"/><content type="html"><![CDATA[<h1 id="description">Description</h1>
<p>As a reminder, the <a href="https://man.openbsd.org/vmm" rel="external">vmm(4)</a> hypervisor on OpenBSD
not have graphic support on the VM guests. <strong>Only serial console access is
available.</strong></p>
<p>When you do virtualization on OpenBSD am64, i386, OpenBSD handles all correctly.
So, the serial console access is configured on <code>/etc/boot.conf</code>; <code>tty00</code>
to use correctly the serial console.</p>
<hr>
<p>The following problem results when you have the idea to create VM under
another OS, Linux for example, unless you answer specifically <strong>yes</strong> when
the installer asks to configure <strong>com0</strong>:</p>
<p><strong>No login screen ; no login!</strong></p>
<p>To illustrate: once OpenBSD VM is copied on the OpenBSD host, here is the
boot:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-ksh" data-lang="ksh"><span style="display:flex;"><span>$ vmctl start -c vm-test
</span></span><span style="display:flex;"><span>Using drive 0, partition 3.
</span></span><span style="display:flex;"><span>Loading......
</span></span><span style="display:flex;"><span>probing: pc0 com0 mem<span style="color:#5bc4bf">[</span>638K 1022M <span style="color:#ef6155">a20</span><span style="color:#5bc4bf">=</span>on<span style="color:#5bc4bf">]</span>
</span></span><span style="display:flex;"><span>disk: hd0+
</span></span><span style="display:flex;"><span>&gt;&gt; OpenBSD/amd64 BOOT 3.52
</span></span><span style="display:flex;"><span>boot&gt;
</span></span><span style="display:flex;"><span>booting hd0a:/bsd: 14329128+3191816+337072+0+872448 <span style="color:#5bc4bf">[</span>999468+128+1135344+859361<span style="color:#5bc4bf">]=</span>0x14ba488
</span></span><span style="display:flex;"><span>entry point at 0xffffffff81001000
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">[</span> using <span style="color:#f99b15">2995336</span> bytes of bsd ELF symbol table <span style="color:#5bc4bf">]</span>
</span></span><span style="display:flex;"><span>Copyright <span style="color:#5bc4bf">(</span>c<span style="color:#5bc4bf">)</span> 1982, 1986, 1989, 1991, <span style="color:#f99b15">1993</span>
</span></span><span style="display:flex;"><span>    The Regents of the University of California.  All rights reserved.
</span></span><span style="display:flex;"><span>Copyright <span style="color:#5bc4bf">(</span>c<span style="color:#5bc4bf">)</span> 1995-2020 OpenBSD. All rights reserved.  https://www.OpenBSD.org
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>OpenBSD 6.8 <span style="color:#5bc4bf">(</span>GENERIC<span style="color:#5bc4bf">)</span> <span style="color:#776e71">#4: Mon Jan 11 10:34:36 MST 2021</span>
</span></span><span style="display:flex;"><span>    root@syspatch-68-amd64.openbsd.org:/usr/src/sys/arch/amd64/compile/GENERIC
</span></span><span style="display:flex;"><span>real <span style="color:#ef6155">mem</span> <span style="color:#5bc4bf">=</span> <span style="color:#f99b15">1056956416</span> <span style="color:#5bc4bf">(</span>1007MB<span style="color:#5bc4bf">)</span>
</span></span><span style="display:flex;"><span>avail <span style="color:#ef6155">mem</span> <span style="color:#5bc4bf">=</span> <span style="color:#f99b15">1010040832</span> <span style="color:#5bc4bf">(</span>963MB<span style="color:#5bc4bf">)</span>
</span></span><span style="display:flex;"><span>random: good seed from bootblocks
</span></span><span style="display:flex;"><span>mpath0 at root
</span></span><span style="display:flex;"><span>scsibus0 at mpath0: <span style="color:#f99b15">256</span> targets
</span></span><span style="display:flex;"><span>mainbus0 at root
</span></span><span style="display:flex;"><span>bios0 at mainbus0: SMBIOS rev. 2.4 @ 0xf3f40 <span style="color:#5bc4bf">(</span><span style="color:#f99b15">10</span> entries<span style="color:#5bc4bf">)</span>
</span></span><span style="display:flex;"><span>bios0: vendor SeaBIOS version <span style="color:#48b685">&#34;1.11.0p3-OpenBSD-vmm&#34;</span> date 01/01/2011
</span></span><span style="display:flex;"><span>bios0: OpenBSD VMM
</span></span><span style="display:flex;"><span>acpi at bios0 not configured
</span></span><span style="display:flex;"><span>cpu0 at mainbus0: <span style="color:#5bc4bf">(</span>uniprocessor<span style="color:#5bc4bf">)</span>
</span></span><span style="display:flex;"><span>cpu0: AMD FX-8320E Eight-Core Processor, 3211.59 MHz, 15-02-00
</span></span><span style="display:flex;"><span>cpu0: FPU,VME,DE,PSE,TSC,MSR,PAE,CX8,SEP,PGE,CMOV,PAT,PSE36,CFLUSH,MMX,FXSR,SSE,SSE2,SSE3,PCLMUL,SSSE3,FMA3,CX16,SSE4.1,SSE4.2,POPCNT,AES,XSAVE,AVX,F16C,HV,NXE,MMXX,FFXSR,PAGE1GB,LONG,LAHF,CMPLEG,EAPICSP,AMCR8,ABM,SSE4A,MASSE,3DNOWP,OSVW,IBS,XOP,SKINIT,WDT,FMA4,TCE,NODEID,TBM,TOPEXT,CPCTR,ITSC,BMI1
</span></span><span style="display:flex;"><span>cpu0: 64KB 64b/line 2-way I-cache, 16KB 64b/line 4-way D-cache, 2MB 64b/line 16-way L2 cache, 8MB 64b/line 64-way L3 cache
</span></span><span style="display:flex;"><span>cpu0: ITLB <span style="color:#f99b15">48</span> 4KB entries fully associative, <span style="color:#f99b15">24</span> 4MB entries fully associative
</span></span><span style="display:flex;"><span>cpu0: DTLB <span style="color:#f99b15">64</span> 4KB entries fully associative, <span style="color:#f99b15">64</span> 4MB entries fully associative
</span></span><span style="display:flex;"><span>cpu0: smt 0, core 0, package <span style="color:#f99b15">0</span>
</span></span><span style="display:flex;"><span>pvbus0 at mainbus0: OpenBSD
</span></span><span style="display:flex;"><span>pvclock0 at pvbus0
</span></span><span style="display:flex;"><span>pci0 at mainbus0 bus <span style="color:#f99b15">0</span>
</span></span><span style="display:flex;"><span>pchb0 at pci0 dev <span style="color:#f99b15">0</span> <span style="color:#815ba4">function</span> <span style="color:#f99b15">0</span> <span style="color:#48b685">&#34;OpenBSD VMM Host&#34;</span> rev 0x00
</span></span><span style="display:flex;"><span>virtio0 at pci0 dev <span style="color:#f99b15">1</span> <span style="color:#815ba4">function</span> <span style="color:#f99b15">0</span> <span style="color:#48b685">&#34;Qumranet Virtio RNG&#34;</span> rev 0x00
</span></span><span style="display:flex;"><span>viornd0 at virtio0
</span></span><span style="display:flex;"><span>virtio0: irq <span style="color:#f99b15">3</span>
</span></span><span style="display:flex;"><span>virtio1 at pci0 dev <span style="color:#f99b15">2</span> <span style="color:#815ba4">function</span> <span style="color:#f99b15">0</span> <span style="color:#48b685">&#34;Qumranet Virtio Network&#34;</span> rev 0x00
</span></span><span style="display:flex;"><span>vio0 at virtio1: address fe:e1:bb:d1:a9:7b
</span></span><span style="display:flex;"><span>virtio1: irq <span style="color:#f99b15">5</span>
</span></span><span style="display:flex;"><span>virtio2 at pci0 dev <span style="color:#f99b15">3</span> <span style="color:#815ba4">function</span> <span style="color:#f99b15">0</span> <span style="color:#48b685">&#34;Qumranet Virtio Storage&#34;</span> rev 0x00
</span></span><span style="display:flex;"><span>vioblk0 at virtio2
</span></span><span style="display:flex;"><span>scsibus1 at vioblk0: <span style="color:#f99b15">1</span> targets
</span></span><span style="display:flex;"><span>sd0 at scsibus1 targ <span style="color:#f99b15">0</span> lun 0: &lt;VirtIO, Block Device, &gt;
</span></span><span style="display:flex;"><span>sd0: 51200MB, <span style="color:#f99b15">512</span> bytes/sector, <span style="color:#f99b15">104857600</span> sectors
</span></span><span style="display:flex;"><span>virtio2: irq <span style="color:#f99b15">6</span>
</span></span><span style="display:flex;"><span>virtio3 at pci0 dev <span style="color:#f99b15">4</span> <span style="color:#815ba4">function</span> <span style="color:#f99b15">0</span> <span style="color:#48b685">&#34;OpenBSD VMM Control&#34;</span> rev 0x00
</span></span><span style="display:flex;"><span>vmmci0 at virtio3
</span></span><span style="display:flex;"><span>virtio3: irq <span style="color:#f99b15">7</span>
</span></span><span style="display:flex;"><span>isa0 at mainbus0
</span></span><span style="display:flex;"><span>isadma0 at isa0
</span></span><span style="display:flex;"><span>com0 at isa0 port 0x3f8/8 irq 4: ns8250, no fifo
</span></span><span style="display:flex;"><span>com0: console
</span></span><span style="display:flex;"><span>vscsi0 at root
</span></span><span style="display:flex;"><span>scsibus2 at vscsi0: <span style="color:#f99b15">256</span> targets
</span></span><span style="display:flex;"><span>softraid0 at root
</span></span><span style="display:flex;"><span>scsibus3 at softraid0: <span style="color:#f99b15">256</span> targets
</span></span><span style="display:flex;"><span>root on sd0a <span style="color:#5bc4bf">(</span>6dc570f70e2c7991.a<span style="color:#5bc4bf">)</span> swap on sd0b dump on sd0b
</span></span><span style="display:flex;"><span>Automatic boot in progress: starting file system checks.
</span></span><span style="display:flex;"><span>/dev/sd0a <span style="color:#5bc4bf">(</span>6dc570f70e2c7991.a<span style="color:#5bc4bf">)</span>: file system is clean; not checking
</span></span><span style="display:flex;"><span>/dev/sd0m <span style="color:#5bc4bf">(</span>6dc570f70e2c7991.m<span style="color:#5bc4bf">)</span>: file system is clean; not checking
</span></span><span style="display:flex;"><span>/dev/sd0d <span style="color:#5bc4bf">(</span>6dc570f70e2c7991.d<span style="color:#5bc4bf">)</span>: file system is clean; not checking
</span></span><span style="display:flex;"><span>/dev/sd0f <span style="color:#5bc4bf">(</span>6dc570f70e2c7991.f<span style="color:#5bc4bf">)</span>: file system is clean; not checking
</span></span><span style="display:flex;"><span>/dev/sd0g <span style="color:#5bc4bf">(</span>6dc570f70e2c7991.g<span style="color:#5bc4bf">)</span>: file system is clean; not checking
</span></span><span style="display:flex;"><span>/dev/sd0h <span style="color:#5bc4bf">(</span>6dc570f70e2c7991.h<span style="color:#5bc4bf">)</span>: file system is clean; not checking
</span></span><span style="display:flex;"><span>/dev/sd0j <span style="color:#5bc4bf">(</span>6dc570f70e2c7991.j<span style="color:#5bc4bf">)</span>: file system is clean; not checking
</span></span><span style="display:flex;"><span>/dev/sd0i <span style="color:#5bc4bf">(</span>6dc570f70e2c7991.i<span style="color:#5bc4bf">)</span>: file system is clean; not checking
</span></span><span style="display:flex;"><span>/dev/sd0e <span style="color:#5bc4bf">(</span>6dc570f70e2c7991.e<span style="color:#5bc4bf">)</span>: file system is clean; not checking
</span></span><span style="display:flex;"><span>/dev/sd0k <span style="color:#5bc4bf">(</span>6dc570f70e2c7991.k<span style="color:#5bc4bf">)</span>: file system is clean; not checking
</span></span><span style="display:flex;"><span>/dev/sd0l <span style="color:#5bc4bf">(</span>6dc570f70e2c7991.l<span style="color:#5bc4bf">)</span>: file system is clean; not checking
</span></span><span style="display:flex;"><span>pf enabled
</span></span><span style="display:flex;"><span>kern.seminfo.semmni: <span style="color:#f99b15">10</span> -&gt; <span style="color:#f99b15">60</span>
</span></span><span style="display:flex;"><span>kern.seminfo.semmns: <span style="color:#f99b15">60</span> -&gt; <span style="color:#f99b15">1024</span>
</span></span><span style="display:flex;"><span>starting network
</span></span><span style="display:flex;"><span>reordering libraries: <span style="color:#815ba4">done</span>.
</span></span><span style="display:flex;"><span>starting early daemons: syslogd pflogd nsd ntpd.
</span></span><span style="display:flex;"><span>starting RPC daemons:.
</span></span><span style="display:flex;"><span>savecore: no core dump
</span></span><span style="display:flex;"><span>checking quotas: <span style="color:#815ba4">done</span>.
</span></span><span style="display:flex;"><span>clearing /tmp
</span></span><span style="display:flex;"><span>kern.securelevel: <span style="color:#f99b15">0</span> -&gt; <span style="color:#f99b15">1</span>
</span></span><span style="display:flex;"><span>creating runtime link editor directory cache.
</span></span><span style="display:flex;"><span>preserving editor files.
</span></span><span style="display:flex;"><span>starting network daemons: sshd smtpd.
</span></span><span style="display:flex;"><span>starting local daemons: cron.
</span></span><span style="display:flex;"><span>Thu Feb <span style="color:#f99b15">18</span> 12:25:45 CET <span style="color:#f99b15">2021</span>
</span></span></code></pre></div><p>It stops at the time display… and the session login screen will never come
up!</p>
<hr>
<p>No, it&rsquo;s not due to a corruption during the copy/synchronisation. Tests
based on sha256 checksum were done before and after the copy, such as:</p>
<p>⇒ on Linux:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>$ cat vm-test.qcow2.sha256
</span></span><span style="display:flex;"><span>73054a89bb2e0b13d78e8cb446424baa01f7761099d8681a59137655b28c979c  vm-test.qcow2
</span></span></code></pre></div><p>⇒ then, on OpenBSD:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-ksh" data-lang="ksh"><span style="display:flex;"><span>$ sha256 vm-test.qcow2                                                                                                                                                                    
</span></span><span style="display:flex;"><span>SHA256 <span style="color:#5bc4bf">(</span>vm-test.qcow2<span style="color:#5bc4bf">)</span> <span style="color:#5bc4bf">=</span> 73054a89bb2e0b13d78e8cb446424baa01f7761099d8681a59137655b28c979c
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>$ sha256 -C vm-test.qcow2.sha256 vm-test.qcow2
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">(</span>SHA256<span style="color:#5bc4bf">)</span> vm-test.qcow2: OK
</span></span></code></pre></div><hr>
<p>What to do?!</p>
<p>On your OS source, where the VM has been created, connect you on the VM,
and make the <strong>two</strong> following necessary modifications:</p>
<h2 id="configuration">Configuration</h2>
<h3 id="bootconf">boot.conf</h3>
<p>The <code>/etc/boot.conf/</code> file config was not created. It must contain at least:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">set tty com0</span>
</span></span></code></pre></div><p>By default, the connection rate is 9200 baups.</p>
<hr>
<p>Since the future host is OpenBSD, write:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">stty com0 115200</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">set tty com0</span>
</span></span></code></pre></div><p>So, we configure to use secure tty at 115200 baups.</p>
<h3 id="ttys">ttys</h3>
<p>The second modification is to set the terminal session <strong>tty00</strong>.</p>
<p>You need to change the line matching <strong>tty00</strong> into the <code>/etc/ttys</code> file:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">tty00   &#34;/usr/libexec/getty std.115200&#34; vt220    on secure</span>
</span></span></code></pre></div><hr>
<p>Voila!</p>
<p>When the VM is copied on OpenBSD, you will have the login screen.</p>
<h2 id="documentations">Documentations</h2>
<ul>
<li>the OpenBSD FAQ &ldquo;<a href="https://www.openbsd.org/faq/faq7.html#SerCon" rel="external">Configuring a Serial Console</a>&rdquo;
<em>(cf : la traduction <a href="https://wiki.openbsd.fr.eu.org/doku.php/openbsd.org/faq/faq7#configurer-une-console-serie" rel="external">FR</a> faite par la communauté &ldquo;OpenBSD Pour Tous&rdquo;)</em></li>
</ul>
<h2 id="acknowledgements">Acknowledgements</h2>
<p>@<a href="http://daemonforums.org/showthread.php?t=11643" rel="external">jggimi</a>…</p>
<hr>
]]></content><summary>Solve serial console problem for a VM, copied from another OS to OpenBSD!</summary><published>2021-02-21T23:14:42+01:00</published><updated>2026-10-02T15:49:57+02:00</updated></entry><entry><id>tag:doc.huc.fr.eu.org,2021-02-21:/en/sys/openbsd/vmd-host-guest-on-same-network</id><link href="https://it-log.fr.eu.org/en/sys/openbsd/vmd-host-guest-on-same-network/" rel="alternate" type="text/html"/><title>[OpenBSD :: Virtualization] Host and guests on the same network</title><author><name>Stéphane HUC</name></author><category term="OpenBSD" scheme="https://it-log.fr.eu.org/en/tags/openbsd/"/><category term="vmd" scheme="https://it-log.fr.eu.org/en/tags/vmd/"/><content type="html"><![CDATA[<h2 id="description">Description</h2>
<p>To virtualize on OpenBSD, since 5.9, is easy; you need to pay attention
to certains details.</p>
<p>This article is about to virtualize host and guests on same network.</p>
<ul>
<li>Version : <strong>native</strong></li>
<li>OS : OpenBSD <strong>6.4</strong> → <strong>6.9</strong></li>
</ul>
<h2 id="prerequisites">Prerequisites</h2>
<p>First, check if the machine is CPU compliant:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-ksh" data-lang="ksh"><span style="display:flex;"><span>$ dmesg | egrep <span style="color:#48b685">&#39;(VMX/EPT|SVM/RVI)&#39;</span>
</span></span></code></pre></div><p>The result should be:</p>
<p>⇒ for Intel CPU:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-ksh" data-lang="ksh"><span style="display:flex;"><span>vmm0 at mainbus0: VMX/EPT
</span></span></code></pre></div><p>⇒ for AMD CPU:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-ksh" data-lang="ksh"><span style="display:flex;"><span>vmm0 at mainbus0: SVM/RVI
</span></span></code></pre></div><p>If the system returns no result, then the virtualization is not possible,
never. Just in case, check on your BIOS|UEFI, and see if the option is disabled.</p>

<div class="tab-info i-info">Info</div><div class="alert alert-info" role="alert"><p>In relation with Meltdow and Spectre attacks, few Intel CPU are patched
to mitigate <a href="https://www.intel.fr/content/www/fr/fr/architecture-and-technology/l1tf.html" rel="external">L1TF</a>.</p>
<p>On OpenBSD, these CPUs receive an appropriate patch. Sadly, this impact
the virtualization, make it impossible.</p>
</div>

<h2 id="creation">Creation</h2>
<p>After downloading the ultime <code>instalXX.iso</code>, and checking it…</p>
<p>Why using, preferably, the iso image? To install OpenBSD by option <code>cd</code>,
because the install sets are on.</p>
<p>For instance, with the 6.9 release:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-ksh" data-lang="ksh"><span style="display:flex;"><span>$ ftp https://cdn.openbsd.org/pub/OpenBSD/6.9/amd64/<span style="color:#5bc4bf">{</span>install69.iso,SHA256,SHA256.sig<span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>$ sha256 -C SHA256 install69.iso
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">(</span>SHA256<span style="color:#5bc4bf">)</span> install69.iso: OK
</span></span><span style="display:flex;"><span>$ signify -Cp /etc/signify/openbsd-69-base.pub -x SHA256.sig install69.iso
</span></span><span style="display:flex;"><span>Signature Verified
</span></span><span style="display:flex;"><span>install69.iso: OK
</span></span></code></pre></div><p>⇒ Create the VM:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-ksh" data-lang="ksh"><span style="display:flex;"><span>$ vmctl create -s 50G disk.qcow2
</span></span></code></pre></div><p>⇒ Start the install:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-ksh" data-lang="ksh"><span style="display:flex;"><span><span style="color:#776e71"># vmctl start -c -m 1G -i 1 -r installXX.iso -d disk.qcow2 test</span>
</span></span></code></pre></div>
<div class="tab-info i-warning">Warning</div><div class="alert alert-warning" role="alert"><p>You need to declare a network interface, with the option <code>-i</code>. This allows
automatically one <strong><a href="https://man.openbsd.org/tap.4" rel="external">tap(4)</a></strong> interface
to the VM.</p>
<p>Egual, <strong>do not use the option <code>-L</code></strong> to manage host and guests on same
network; this option declare a local interface, preventing communication
with the bridge. <em>In this cas, we need to configure forwarding, sysctl, etc.</em></p>
</div>

<p>Do the install, and after a few minutes, at the end, choose <code>[halt]</code> to
shutdown correctly the OS into the VM. To leave the serial console, use
the escape sequence : <code>~.</code>; or if you are on SSH session: <code>~~.</code>.</p>

<div class="tab-info i-info">Info</div><div class="alert alert-info" role="alert"><p>Another reason why you need to stop the VM: if you do not, the VM reboot
normally, without any problem… but, without network connections.
Do not try to modify yours networks parameters, perhaps just to verify
adresses IP gateway and DNS resolver.</p>
<p>The tip: configure  the file <code>/etc/vm.conf</code> on the host, restart the vmd
daemon et after start the VM. Now, the network should work correctly!</p>
</div>

<h2 id="configuration">Configuration</h2>
<p>Assuming that:</p>
<ul>
<li>the network segment is on Class C, as 192.168.1.0</li>
<li>address IP of gateway: 192.168.1.1</li>
<li><a href="https://www.fdn.fr/actions/dns/" rel="external">DNS resolvers</a>: perhaps those about FDN…</li>
</ul>
<p>These informations are the network parameters to configure the VM.</p>
<hr>
<p>The following parameters are made on:</p>
<h3 id="networking">Networking</h3>
<p><strong>Only the Ethernet devices, not Wireless, can be used</strong>.</p>
<p>Prefer to use static adress IP, because dhcp can complicate matters.</p>
<h3 id="hostnameiface">hostname.iface</h3>
<p>In this article, we assume that your network interface is managed by the
<strong><a href="https://man.openbsd.org/man4/em.4" rel="external">em(4)</a></strong> Intel firmware.</p>
<p><em>Change segun your case, if necessary.</em></p>
<p>Configue the <code>/etc/hostname.em0</code> file:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">inet 192.168.1.2</span>
</span></span></code></pre></div><h3 id="vmconf">vm.conf</h3>
<p><code>/etc/vm.conf</code> is the file configuration:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">switch &#34;sw&#34; {</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">interface bridge0</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">vm &#34;test&#34; {</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">disk /home/your_user/disk.qcow2 format qcow2</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">enable</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">memory 1G</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">interface { switch &#34;sw&#34; }</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">owner your_user</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">}</span>
</span></span></code></pre></div><h3 id="bridge">Bridge</h3>
<p>Configure the bridge to manage em0:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-ksh" data-lang="ksh"><span style="display:flex;"><span><span style="color:#776e71"># echo &#39;add em0&#39; &gt; /etc/hostname.bridge0</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># sh /etc/netstart bridge0</span>
</span></span></code></pre></div><p>Voilà!</p>
<hr>
<p>Which is not mentioned in the FAQ, has a lot to do with PF, mainly.</p>
<p>Another important information: when the VM is running, on tap interface
is created and mounted by the bridge.</p>
<h3 id="pf">PF</h3>

<div class="tab-info i-warning">Warning</div><div class="alert alert-warning" role="alert">DO NOT use the <a href="https://www.openbsd.org/faq/pf/filter.html#urpf" rel="external">uRPF</a>
feature with vm; otherwize yours VMs can not communicate!</div>

<p>According to the <a href="https://man.openbsd.org/bridge.4#NOTES" rel="external">notes of the bridge manpage</a>,
set the rules on PF to manage the bridge is possible, but you need to be
very fine-tuned and have an excellent understanding about the network
flow within PF.</p>
<p>Do simple:</p>
<p>⇒ pass all on the interface group <strong>tap</strong>:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">pass on tap</span>
</span></span></code></pre></div>
<div class="tab-info i-info">Info</div><div class="alert alert-info" role="alert"><p>If you prefer to manage individually all interfaces <strong>tap</strong>, you can declare,
by exemple, only <strong>tap0</strong>:</p>
<p><code>pass on tap0</code></p>
</div>

<p>Now, you need to manage the physical network interface; here: <strong>em0</strong></p>
<hr>
<p>⇒ create a table to manage all the VMs:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">table &lt;vm_tap&gt; const { 192.168.1.3 192.168.1.4 }</span>
</span></span></code></pre></div><p>and, for the exemple, authozise SSH to VMs:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">pass in log on em0 inet proto tcp from any to &lt;vm_tab&gt; port 22</span>
</span></span></code></pre></div><p>Of course, these PF rules are minimalist. It&rsquo;s up to you!</p>
<p>Finally, remember to manage PF rules within the VM.</p>
<h3 id="tap---ethernet-tunnel-pseudo-device">tap - Ethernet tunnel pseudo-device</h3>
<p>OpenBSD create 4 tap interfaces, by default. If you need more VM, you need
to create more tap interfaces.</p>
<p>See the <a href="https://man.openbsd.org/vm.conf.5#SWITCH_CONFIGURATION" rel="external">note</a>…</p>
<p>And use <a href="https://man.openbsd.org/MAKEDEV.8" rel="external">MAKEDEV(8)</a>, as:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-ksh" data-lang="ksh"><span style="display:flex;"><span><span style="color:#776e71"># sh MAKEDEV tap5</span>
</span></span></code></pre></div><p>Egual, it&rsquo;s possible to assign such pseudo virtual device tap to such VM.
Use the keyword <strong><a href="https://man.openbsd.org/vm.conf.5#interface" rel="external">interface</a></strong>:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">vm &#34;test&#34; {</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">(…)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">interface tap5 { … }</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">(…)</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">}</span>
</span></span></code></pre></div><p>Another information to understand: as long as the VM is not active, the
matching tap interface will not be created and mounted on the bridge.
Compare with <code>ifconfig</code> command, before and after. ;-)</p>
<h3 id="sysctl">sysctl</h3>
<p>NO, it&rsquo;s not necessary to configure systcl to forward the trafic. We do
not make NAT!</p>
<p>See the manpage <strong><a href="https://man.openbsd.org/vmctl.8#LOCAL_INTERFACES" rel="external">vmctl</a></strong>:</p>
<blockquote>
<p>If NAT is desired, the net.inet.ip.forwarding sysctl(8) must also be set to 1.</p>
</blockquote>
<p>So, in the bridge context where host and guests are on same network, no
need to forward the flow.</p>
<hr>
<h2 id="documentations">Documentations</h2>
<ul>
<li>
<p>See the official <strong><a href="https://www.openbsd.org/faq/faq16.html" rel="external">FAQ Virtualisation</a></strong> in order to understand the
different informations needed.</p>
</li>
<li>
<p>It&rsquo;s highly interesting to read the manpages:</p>
<ul>
<li>
<a class="man" href="https://man.openbsd.org/vmctl.8" title="OpenBSD Manual Page Server for: vmctl">vmctl(8)</a>
</li>
<li>
<a class="man" href="https://man.openbsd.org/vmd.8" title="OpenBSD Manual Page Server for: vmd">vmd(8)</a>
</li>
<li>
<a class="man" href="https://man.openbsd.org/vm.conf.5" title="OpenBSD Manual Page Server for: vm.conf">vm.conf(5)</a>
</li>
<li>
<a class="man" href="https://man.openbsd.org/vmm.4" title="OpenBSD Manual Page Server for: vmm">vmm(4)</a>
</li>
<li>sans oublier 
<a class="man" href="https://man.openbsd.org/bridge.4" title="OpenBSD Manual Page Server for: bridge">bridge(4)</a>
</li>
</ul>
</li>
</ul>
<hr>
<ul>
<li>Here an <a href="http://daemonforums.org/showthread.php?t=11628" rel="external">example</a> of a
patched L1TF Intel CPU where the boot media was not found, with error
message in <code>dmesg</code>: <br>
<code>vmx_fault_page: uvm_fault returns 14, GPA=0xffffca78, rip=0xfbd49</code></li>
</ul>
<hr>
]]></content><summary>Tips to virtualize serenely under OpenBSD with vmd, where host and guest(s) are part of the same network!</summary><published>2021-02-21T19:54:31+01:00</published><updated>2026-10-02T15:49:57+02:00</updated></entry><entry><id>tag:doc.huc.fr.eu.org,2020-09-20:/en/sys/openwrt/openssh</id><link href="https://it-log.fr.eu.org/en/sys/openwrt/openssh/" rel="alternate" type="text/html"/><title>OpenWRT: OpenSSH instead of Dropbear</title><author><name>Stéphane HUC</name></author><category term="OpenWRT" scheme="https://it-log.fr.eu.org/en/tags/openwrt/"/><category term="OpenSSH" scheme="https://it-log.fr.eu.org/en/tags/openssh/"/><category term="SSH" scheme="https://it-log.fr.eu.org/en/tags/ssh/"/><content type="html"><![CDATA[<h2 id="description">Description</h2>
<p>In fact, Dropbear is the SSH server on OpenWRT. Even if this lightweight server use only SSH Protocol v2, it has some gaps:</p>
<ul>
<li>A partial support of SFTP protocol; you need to add the package <strong>openssh-sftp-server</strong></li>
<li>No user privilege separation</li>
<li>No official support for cryptographic modules, approved by approved by the <strong>FIPS 140-2</strong>.
<em>(although in our particular context, it is not a necessity)</em></li>
<li>Since version <strong>2020.79</strong>, Dropbear seems to manage the Elliptic curve algorithms — <em>which is not the case for the previous versions, included before OpenWRT 19.07.4</em> ­—:
<ul>
<li>hostkey <strong>ed25519</strong></li>
<li>chiffer <strong>chacha20-poly1305</strong></li>
<li>or even the key signatures  <strong>rsa-sha2</strong></li>
</ul>
</li>
</ul>
<h2 id="installation">Installation</h2>
<pre tabindex="0"><code class="language-ash" data-lang="ash">:# /etc/init.d/sshd enable
:# /etc/init.d/sshd start
</code></pre>
<div class="tab-info i-info">Info</div><div class="alert alert-info" role="alert"><p>The <strong>openssh-moduli</strong> package is not stritcly necessary. As a reminder, the <code>/etc/ssh/moduli</code> file is a file containing the prime numbers and generators to be used by the SSH server in the</p>
<p><span lang="en">DH <em>(Diffie-Hellman)</em></span></p>
<p>group key exchange method. Prefer to install it…</p>
</div>

<h2 id="configuration">Configuration</h2>
<h3 id="dropbear-configuration">Dropbear configuration</h3>
<p>Let&rsquo;s the default port on Dropbear</p>
<p>However, you can configure it, either through the LUCI interface, or in CLI, like as:</p>
<pre tabindex="0"><code class="language-ash" data-lang="ash">:# uci set dropbear.@dropbear[0].Port=xxx
:# uci commit dropbear
:# /etc/init.d/dropbear restart
</code></pre><ul>
<li><em>xxx</em>: the port number segun your choice.</li>
</ul>
<p>and connect you on this port…</p>
<h3 id="openssh-configuration">OpenSSH Configuration</h3>
<ul>
<li>Configuration file: <code>/etc/ssh/sshd_config</code></li>
</ul>
<hr>
<p>Apply ABSOLUTELY this following recommandations:</p>
<ul>
<li>Use <strong>only</strong> the v2 protocol,</li>
<li><strong>Do not connect with root account</strong></li>
<li>disable the <strong>PasswordAuthentication</strong> option</li>
<li>use <strong>only</strong> the <strong>PubkeyAuthentication</strong> option</li>
</ul>
<hr>
<p>Now, we harden the configuration:</p>
<ul>
<li><a href="/en/sec/ssh/sshd-harden#recreate-host-keys">recreate the host keys</a>, and allow <strong>only</strong> the <strong>Ed25519</strong> algorithm.</li>
</ul>

<div class="tab-info i-info">Info</div><div class="alert alert-info" role="alert">When OpenSSH starts, it will recreate the <strong>ECDSA</strong> keys.</div>

<ul>
<li>auth <strong>only</strong>:
<ul>
<li>strong <a href="/en/sec/ssh/sshd-harden#ciphers/">encryption</a></li>
<li>the following algorithms:
<ul>
<li><a href="/en/sec/ssh/sshd-harden#KeyExchange">key exchange</a></li>
<li><a href="/en/sec/ssh/sshd-harden#HostKeyAlgorithms">host keys</a></li>
<li><a href="/en/sec/ssh/sshd-harden#MACs">message authentication codes</a></li>
</ul>
</li>
</ul>
</li>
</ul>

<div class="tab-info i-warning">Warning</div><div class="alert alert-warning" role="alert">The <code>sk-ssh-ed25519@openssh.com,sk-ssh-ed25519-cert-v01@openssh.com</code> host keys algorithms not seem to be recognized; <strong>do not use!</strong></div>

<h4 id="moduli">moduli</h4>
<p>If you installed the <strong>openssh-moduli</strong> package, prefer accept only 












<abbr lang="en" title="Diffie-Hellman">DH</abbr>



































































































 key exchange greater than or equal to 3072 bits.</p>
<p>Let&rsquo;s save the file, before, in case of…</p>
<pre tabindex="0"><code class="language-ash" data-lang="ash">:# cp /etc/ssh/moduli /etc/ssh/moduli.bckp
:# chmod 0400 /etc/ssh/moduli.bckp
</code></pre><p>Then, you need to <a href="/en/sec/ssh/sshd-harden#moduli--linux">recreate</a></p>

<div class="tab-info i-tip">Tip</div><div class="alert alert-tip" role="alert"><p>If you have correctly configured a user with <a href="/en/sys/openwrt/sudo/">sudo</a> rights:</p>
<pre tabindex="0"><code class="language-ash" data-lang="ash">:# sudo awk &#39;$5 &gt;= 3071&#39; /etc/ssh/moduli | sudo tee /etc/ssh/moduli.safe
:# mv /etc/ssh/moduli.safe /etc/ssh/moduli
</code></pre></div>

<h4 id="tldr">TL;DR</h4>
<p>Here a minimalist example of the configuration file:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">HostKey /etc/ssh/ssh_host_rsa_key</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">HostKey /etc/ssh/ssh_host_ed25519_key</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">HostKeyAlgorithms ssh-ed25519,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-256,rsa-sha2-512,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">PermitRootLogin no</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">MaxAuthTries 3</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">PubkeyAuthentication yes</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">AuthorizedKeysFile  .ssh/authorized_keys</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">PasswordAuthentication no</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">PermitEmptyPasswords no</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">Subsystem   sftp    /usr/lib/sftp-server</span>
</span></span></code></pre></div>
<div class="tab-info i-warning">Warning</div><div class="alert alert-warning" role="alert">Have you set the <strong>ListenAddress</strong> option? <br>
Forget or you win a <a href="/en/sys/openwrt/openssh/#race-condition">race condition</a>!</div>

<hr>
<h2 id="service-management">Service management</h2>
<h3 id="openssh-service">OpenSSH Service</h3>
<p>Voila, now, connect you… but, after testing the configuration and start the service:</p>
<p><code>:# sshd -t</code></p>
<p>If the configuration is valid:</p>
<pre tabindex="0"><code class="language-ash" data-lang="ash">:# /etc/init.d/sshd enable
:# /etc/init.d/sshd start
</code></pre><h3 id="dropbear-service">Dropbear Service</h3>
<p>Now, it&rsquo;s possible to stop and disable the dropbear service:</p>
<pre tabindex="0"><code class="language-ash" data-lang="ash">:# /etc/init.d/dropbear stop
:# /etc/init.d/dropbear disable
</code></pre><hr>
<h2 id="backup-system">Backup system</h2>
<p>Normally, the <code>/etc/ssh</code> directory and its contents are included in the backup system maded by the <code>sysupgrade</code> tool.</p>
<p>To check: <code>:# sysupgrade -l | grep ssh</code></p>
<p>If it&rsquo;s not case, edit the <code>/etc/sysupgrade.conf</code> file to add this folder.</p>
<h2 id="troubleshooting">Troubleshooting</h2>
<h3 id="race-condition">Race condition</h3>
<p>⇒ Not possible to connect after reboot:</p>
<p>Have you set the <code>ListenAdress</code> option on the configuration file?</p>
<p>If yes, <span class="red">comment the corresponding line</span>
.
OpenSSH can not start due to race condition.</p>
<p>When you specify this option, OpenSSH will run when you start on the CLI.
But, during the (re)boot, OpenSSH will fail because the network interface(s) is|are not ready!</p>
<p>Then, do not specify this option and configure you firewall to auth only your LAN network interface.</p>
<p><em><a href="https://forum.openwrt.org/t/luci-https-not-working-after-upgrade-to-19-7-4/74352/16" rel="external">source</a></em></p>
<h2 id="documentation">Documentation</h2>
<h3 id="wikipedia">Wikipedia</h3>
<ul>
<li><a href="https://en.wikipedia.org/wiki/Comparison_of_SSH_servers" title="Wikipedia Article: Comparison_of_SSH_servers">
    Comparison_of_SSH_servers
    <sup><abbr class="is-italic" title="Wikipedia">WP</abbr></sup>
</a>
, <a href="https://en.wikipedia.org/wiki/FIPS_140-2" title="Wikipedia Article: FIPS_140-2">
    FIPS_140-2
    <sup><abbr class="is-italic" title="Wikipedia">WP</abbr></sup>
</a>
</li>
<li><a href="https://en.wikipedia.org/wiki/Race_condition" title="Wikipedia Article: Race_condition">
    Race_condition
    <sup><abbr class="is-italic" title="Wikipedia">WP</abbr></sup>
</a>
</li>
</ul>
<hr>
]]></content><summary>Install OpenSSH to replace Dropbear, on OpenWRT</summary><published>2020-09-20T12:02:05+02:00</published><updated>2026-10-02T15:49:57+02:00</updated></entry><entry><id>tag:doc.huc.fr.eu.org,2020-09-18:/en/sec/ssh/sshd-harden</id><link href="https://it-log.fr.eu.org/en/sec/ssh/sshd-harden/" rel="alternate" type="text/html"/><title>OpenSSH : Harden the service</title><author><name>Stéphane HUC</name></author><category term="SSH" scheme="https://it-log.fr.eu.org/en/tags/ssh/"/><category term="harden" scheme="https://it-log.fr.eu.org/en/tags/harden/"/><content type="html"><![CDATA[<h2 id="description">Description</h2>
<p>By default, even on OpenBSD, the SSH configuration is not the most secure.</p>
<p>NISTP Algorithms — <em>likely to be an NSA backdoor; but beware, this is
seem to be a rumor</em>, even SHA1 are always used.</p>

<div class="tab-info i-warning">Warning</div><div class="alert alert-warning" role="alert">Use absolutly an OpenSSH version greater than the v6.5!</div>

<h2 id="configuration">Configuration</h2>
<ul>
<li>Configuration file: <code>/etc/ssh/sshd_config</code></li>
</ul>
<hr>
<p>Apply ABSOLUTELY this following recommandations:</p>
<ul>
<li>Use <strong>only</strong> the v2 protocol,</li>
<li><strong>Do not connect with root account</strong></li>
<li>disable the <strong>PasswordAuthentication</strong> option</li>
<li>use <strong>only</strong> the <strong>PubkeyAuthentication</strong> option</li>
</ul>
<h3 id="recreate-host-keys">Recreate host keys</h3>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:$ cd /etc/ssh
</span></span><span style="display:flex;"><span>:# rm ssh_host_*
</span></span><span style="display:flex;"><span>:# ssh-keygen -t ed25519 -f ssh_host_ed25519_key -N <span style="color:#48b685">&#34;&#34;</span>
</span></span><span style="display:flex;"><span>:# ssh-keygen -t rsa -b <span style="color:#f99b15">4096</span> -f ssh_host_rsa_key -N <span style="color:#48b685">&#34;&#34;</span> -o -a <span style="color:#f99b15">64</span>
</span></span></code></pre></div>
<div class="tab-info i-info">Info</div><div class="alert alert-info" role="alert"><p>Do not use passphrase during the generation, otherwise the server will not
be able to read them…</p>
<p>Anyway, the <code>/var/log/auth</code> file will help you!</p>
</div>

<hr>
<p>Next, you need to pay attention to the following:</p>
<h3 id="hostkey">HostKey</h3>

<div class="tab-info i-warning">Warning</div><div class="alert alert-warning" role="alert"><span class="red">DO NOT USE the DSA, ECDSA protocols!</span></div>

<p><strong>Comment</strong> the <code>HostKey</code> options to <span em>keep only related RSA and
ED25519 encryptions</span>.</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">HostKey /etc/ssh/ssh_host_rsa_key</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">HostKey /etc/ssh/ssh_host_ed25519_key</span>
</span></span></code></pre></div>
<div class="tab-info i-tip">Tip</div><div class="alert alert-tip" role="alert">You can use only elliptic curves keys, such ed25519. In this case, make
sure that all your SSH clients can use this encryption mode too.</div>

<h3 id="ciphers">Ciphers</h3>
<p>Allow those <strong>ciphers</strong>:</p>
<p><code>Ciphers chacha20-poly1305@openssh.com</code></p>
<h3 id="hostkeyalgorithms">HostKeyAlgorithms</h3>
<p>The <strong>HostKeyAlgorithms</strong>:</p>
<p><code>HostKeyAlgorithms ssh-ed25519-cert-v01@openssh.com,ssh-ed25519</code></p>

<div class="tab-info i-info">Info</div><div class="alert alert-info" role="alert">Segun you OpenSSH version, it&rsquo;s possible to obtain a error message. <br>
See the section &ldquo;<a href="/en/sec/ssh/sshd-harden/#bad-key-types">Troubleshooting</a>&rdquo;!</div>

<h3 id="keyexchange">KeyExchange</h3>
<p>Focus on those <strong>KeyExchange algoritms</strong>:</p>
<p><code>KexAlgorithms mlkem768x25519-sha256,sntrup761x25519-sha512,sntrup761x25519-sha512@openssh.com</code></p>
<h3 id="macs">MACs</h3>
<p>Choose those <strong>Message Authentication Codes</strong>:</p>
<p><code>MACs umac-64-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com</code></p>
<h3 id="moduli">Moduli</h3>
<p>The moduli file containt prime numbers and generators to be used by the
SSH server in the  











<span lang="en">DH <em>(Diffie-Hellman)</em></span>



































































































 group key exchange method.</p>

<div class="tab-info i-warning">Warning</div><div class="alert alert-warning" role="alert"><p>Since 2017, this <a href="https://bugzilla.mindrot.org/show_bug.cgi?id=2793" rel="external">bug #2793</a>
explains that in some contexts the proper functioning fails, following
recommendations below.</p>
<p>If you can no longer login, consider reversing this change!</p>
</div>

<h4 id="moduli--linux">Moduli / Linux</h4>
<p>It is recommended to recreate it, in such a way:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>awk <span style="color:#48b685">&#39;$5 &gt;= 3071&#39;</span> /etc/ssh/moduli &gt; /etc/ssh/moduli.safe
</span></span><span style="display:flex;"><span>mv /etc/ssh/moduli.safe /etc/ssh/moduli
</span></span></code></pre></div><h4 id="moduli--openbsd">Moduli / OpenBSD</h4>
<p>Yes, it is possible to create, as: <br>
<code>ssh-keygen -G /etc/ssh/moduli -b 3072</code></p>
<p>Attention, the generation will be long and depends very strongly on the
power of your server.</p>
<p>However, you should know that for a few years/versions, the file is
already generated and happens to be in <code>/etc/moduli</code></p>
<p>See 
<a class="man" href="https://man.openbsd.org/moduli.5" title="OpenBSD Manual Page Server for: moduli">moduli(5)</a>
</p>
<h3 id="sandbox">Sandbox</h3>

<div class="tab-info i-warning">Warning</div><div class="alert alert-warning" role="alert"><p>Since v7.5, this is an <span em>deprecated and obsolete</span> option!</p>
<p><strong>Do not use it anymore!</strong></p>
</div>

<h2 id="tldr">TL;DR</h2>
<p>Here is a minimalist example of the secure configuration file on the server
side:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">Port 22</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ListenAddress 192.168.xxx.yyy</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ListenAddress fd00:abcd:efg0::1</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">HostKey /etc/ssh/ssh_host_rsa_key</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">HostKey /etc/ssh/ssh_host_ed25519_key</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">HostKeyAlgorithms ssh-ed25519,ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,sk-ssh-ed25519-cert-v01@openssh.com,rsa-sha2-256,rsa-sha2-512,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">MACs hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,umac-128-etm@openssh.com</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">PermitRootLogin no</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">PubkeyAuthentication yes</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">AuthorizedKeysFile  .ssh/authorized_keys</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">PasswordAuthentication no</span>
</span></span></code></pre></div><h2 id="troubleshooting">Troubleshooting</h2>
<h3 id="bad-key-types">Bad key types</h3>
<p>If you had this following error:<br>
<code>/etc/ssh/sshd_config line 26: Bad key types 'ssh-ed25519,ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,sk-ssh-ed25519-cert-v01@openssh.com,rsa-sha2-256,rsa-sha2-512,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com'</code></p>
<p>Delete those <code>sk-ssh-ed25519@openssh.com,sk-ssh-ed25519-cert-v01@openssh.com</code>
algorithms, and <a href="/en/sec/ssh/sshd-harden/#test">test</a> again. If, <strong>OK</strong>, reload the service.</p>
<h3 id="logingracetime">LoginGraceTime</h3>
<p>Think to grow the value of the <code>LoginGraceTime</code> option. Using RSA + PKBDF,
or ed25519 keys, require more time for connections.
Egual, you will not see any error messages into the auth log.</p>
<hr>
<h3 id="test">Test</h3>
<ul>
<li>To check the configuration: <code>:# sshd -t</code></li>
</ul>
<hr>
<h4 id="ssh-audit">ssh-audit</h4>
<p>It exists a tool, named <code>ssh-audit</code> to check if your configuration is secure.</p>
<p>Install and execute against your server as:</p>
<p><code>:$ ssh-audit adresse-ip-serveur-ssh</code></p>
<ul>
<li>You need to fix URGENTLY all red colored messages.</li>
<li>A green colored message mean OK</li>
</ul>
<h4 id="sshaudit-on-internet">sshaudit on internet</h4>
<p>It is possible to test too your server with the <strong>sshaudit</strong> website:
<a href="https://www.sshaudit.com" rel="external">https://www.sshaudit.com</a></p>
<hr>
<h2 id="documentation">Documentation</h2>
<h3 id="manpages">Manpages</h3>
<ul>
<li>
<a class="man" href="https://man.openbsd.org/sshd.8" title="OpenBSD Manual Page Server for: sshd">sshd(8)</a>
, 
<a class="man" href="https://man.openbsd.org/sshd_config.5" title="OpenBSD Manual Page Server for: sshd_config">sshd_config(5)</a>
, 
<a class="man" href="https://man.openbsd.org/sftp-server.8" title="OpenBSD Manual Page Server for: sftp-server">sftp-server(8)</a>
</li>
<li>
<a class="man" href="https://man.openbsd.org/moduli.5" title="OpenBSD Manual Page Server for: moduli">moduli(5)</a>
</li>
</ul>
<h3 id="others">Others</h3>
<ul>
<li><a href="https://infosec.mozilla.org/guidelines/openssh" rel="external">https://infosec.mozilla.org/guidelines/openssh</a></li>
<li><a href="https://www.sshaudit.com/hardening_guides.html" rel="external">https://www.sshaudit.com/hardening_guides.html</a></li>
</ul>
<hr>
]]></content><summary>Harden SSH server!</summary><published>2020-09-18T15:58:58+02:00</published><updated>2026-10-02T15:49:57+02:00</updated></entry><entry><id>tag:doc.huc.fr.eu.org,2020-09-14:/en/sys/openwrt/sysupgrade</id><link href="https://it-log.fr.eu.org/en/sys/openwrt/sysupgrade/" rel="alternate" type="text/html"/><title>OpenWRT: Manage correctly the process to upgrade to the new version!</title><author><name>Stéphane HUC</name></author><category term="OpenWRT" scheme="https://it-log.fr.eu.org/en/tags/openwrt/"/><category term="sysupgrade" scheme="https://it-log.fr.eu.org/en/tags/sysupgrade/"/><category term="opkg" scheme="https://it-log.fr.eu.org/en/tags/opkg/"/><category term="sysadmin" scheme="https://it-log.fr.eu.org/en/tags/sysadmin/"/><category term="router" scheme="https://it-log.fr.eu.org/en/tags/router/"/><category term="Ubiquiti" scheme="https://it-log.fr.eu.org/en/tags/ubiquiti/"/><category term="EdgeRouter" scheme="https://it-log.fr.eu.org/en/tags/edgerouter/"/><category term="Xiaomi" scheme="https://it-log.fr.eu.org/en/tags/xiaomi/"/><category term="Mi" scheme="https://it-log.fr.eu.org/en/tags/mi/"/><category term="Redmi" scheme="https://it-log.fr.eu.org/en/tags/redmi/"/><category term="AC2100" scheme="https://it-log.fr.eu.org/en/tags/ac2100/"/><category term="AX3000T" scheme="https://it-log.fr.eu.org/en/tags/ax3000t/"/><category term="One" scheme="https://it-log.fr.eu.org/en/tags/one/"/><content type="html"><![CDATA[<div class="tab-info i-deprecated"><strong>opkg → apk</strong></div>
<div class="alert alert-deprecated" role="alert"><strong>Since OpenWRT 25.12.0, **apk** *(Alpine Package Keeper)* is the new package manager; the oldier `opkg` is no longer maintened! See the relative page: https://openwrt.org/docs/guide-user/additional-software/opkg-to-apk-cheatsheet to the official transition.</strong></div>

<h2 id="description">Description</h2>

<div class="tab-info i-danger">Danger</div><div class="alert alert-danger" role="alert"><p>Before updating your system, it is ESSENTIAL that you read the following the OpenWRT release announcement, especially the chapters “Upgrading to…” and “ Known issues”.</p>
<p>These chapters may contain information relating to your router; skipping them could damage your damage your equipment and render it unusable!</p>
</div>

<p><strong>OpenWRT</strong> has a tool to upgrade the system, named <strong>sysupgrade</strong>. You can invoque on the Luci&rsquo;s web admin.</p>
<p>If you are more interesting by sysupgrade on LuCI, go to this note:
<a href="/en/sys/openwrt/sysupgrade/#flash-on-luci">Flash on LuCI</a></p>
<hr>
<p>The following procedure explains step by step the sysupgrade in CLI mode, while preserving the user configuration…</p>
<h2 id="process">Process</h2>
<p>The first action is install the tool <code>curl</code>, because the native <code>wget</code> does not support TLS.</p>
<p><code>:# opkg install curl</code></p>
<h3 id="opkgscriptsh">opkgscript.sh</h3>
<p>The <code>opkgscript.sh</code> script is used to save the list of packages installed in addition to the base.</p>
<p>⇒ Now, fetch <a href="https://raw.githubusercontent.com/richb-hanover/OpenWrtScripts/master/opkgscript.sh" rel="external">opkgscript.sh</a>: <br>
<code>:$ curl -O https://raw.githubusercontent.com/richb-hanover/OpenWrtScripts/master/opkgscript.sh</code></p>
<p>⇒ Put the <code>+x</code> needed rights: <br>
<code>:# chmod 0700 opkgscript.sh</code></p>
<p>⇒ backup the list of installed packages; <em>to re-install easy them after the sysupgrade process</em>: \</p>
<p><code>:# ./opkgscript.sh -v write</code></p>
<p>This script write the list into file <code>/etc/config/opkg.installed</code>.</p>
<h3 id="download-firmware">Download firmware</h3>
<p>Let&rsquo;s retrieve the new firmware version:</p>
<ul>
<li>e.g. the current version:</li>
</ul>
<p><code>:# v=&quot;24.10.5&quot;</code></p>
<p>⇒ for the <strong>OpenWRT One</strong>:</p>
<p><code>:# curl -O https://downloads.openwrt.org/releases/&quot;${v}&quot;/targets/mediatek/filogic/{openwrt-&quot;${v}&quot;-mediatek-filogic-openwrt_one-squashfs-sysupgrade.itb,sha256sums}</code></p>
<p>⇒ for the <strong>Ubiquiti EdgeRouter X</strong>:</p>
<p><code>:#curl -O https://downloads.openwrt.org/releases/&quot;${v}&quot;/targets/ramips/mt7621/{openwrt-&quot;${v}&quot;-ramips-mt7621-ubnt_edgerouter-x-squashfs-sysupgrade.bin,sha256sums}</code></p>
<p>⇒ for the <strong>Xiaomi Mi Router AX3000T</strong>:</p>
<p><code>:# curl -O https://downloads.openwrt.org/releases/&quot;${v}&quot;/targets/mediatek/filogic/{openwrt-&quot;${v}&quot;-mediatek-filogic-xiaomi_mi-router-ax3000t-squashfs-sysupgrade.bin,sha256sums}</code></p>
<p>⇒ for the <strong>Xiaomi Redmi Router AC2100</strong>:</p>
<p><code>:# curl -O https://downloads.openwrt.org/releases/&quot;${v}&quot;/targets/ramips/mt7621/{openwrt-&quot;${v}&quot;-ramips-mt7621-xiaomi_redmi-router-ac2100-squashfs-sysupgrade.bin,sha256sums}</code></p>
<p>And, we check the checksum: <br>
<code>:# sha256sum -c sha256sums 2&gt; /dev/null | grep OK</code></p>
<p>⇒ Correct result for <strong>OpenWRT One</strong>: <br>
<code>openwrt-24.10.4-mediatek-filogic-openwrt_one-squashfs-sysupgrade.itb: OK</code></p>

<div class="tab-info i-danger">Danger</div><div class="alert alert-danger" role="alert"><p><strong>ATTENTION</strong>: If the verification fails, go to discuss it on the forum!</p>
<p><strong>Don&rsquo;t try to upgrade with a corrupted firmware!</strong></p>
</div>

<h3 id="backup-configuration">Backup configuration</h3>
<p>The next step check the backup configuration:</p>
<p><code># sysupgrade -l</code></p>
<p>If necessary, you can edit the file <code>/etc/sysupgrade.conf</code> to add some folders/files; for instance, in the case where <a href="/en/sys/openwrt/sudo">a user has been added to the <strong>sudo</strong> group</a>, you need to add those:</p>
<ul>
<li>/etc/sudoers</li>
<li>/etc/sudoers.d/</li>
</ul>
<p>Check again; and, backup the configuration:</p>
<pre tabindex="0"><code>:# sysupgrade -b /tmp/backup-${HOSTNAME}-$(date +%F).tar.gz
</code></pre><p>And, after, it is necessary to retrieve this backup: <br>
<code>:$ scp root@openwrt:/tmp/backup*.tar.gz $(pwd)</code>  <br>
<em>(where &lsquo;openwrt&rsquo; is the adresse IP about your router)</em></p>

<div class="tab-info i-info">Info</div><div class="alert alert-info" role="alert"><p>If you obtain this error message: <br>
<code>ash: /usr/libexec/sftp-server: not found</code></p>
<p>Please, see this note, belowe, about <a href="/en/sys/openwrt/sysupgrade/#ssh-v90-and-higher">SSH v9.0 and higher</a></p>
<hr>
<p>The note <a href="/en/sys/openwrt/sysupgrade/#freeing-memory">Freeing memory</a> may be interesting, but it&rsquo;s not very useful on Ubiquiti EdgeRouter X or Xiaomi Redmi Router AC2100.</p>
</div>

<h3 id="upgrade-system">Upgrade system</h3>
<p>Now, it&rsquo;s time to upgrade the system:</p>
<p><code>:# sysupgrade -v openwrt-&quot;${v}&quot;-*-sysupgrade.bin</code> or <br>
<code>:# sysupgrade -v openwrt-&quot;${v}&quot;-*-sysupgrade.itb</code> depends on the router.</p>
<p>Example, for the <strong>OpenWRT One</strong>:</p>
<pre tabindex="0"><code class="language-ash" data-lang="ash">:# sysupgrade -v openwrt-&#34;$v&#34;-mediatek-filogic-openwrt_one-squashfs-sysupgrade.itb
(date) upgrade: Saving config files...
etc/config/attendedsysupgrade
etc/config/dhcp
etc/config/dropbear
etc/config/firewall
etc/config/https-dns-proxy
etc/config/luci
etc/config/network
etc/config/opkg.installed
etc/config/rpcd
etc/config/system
etc/config/ubihealthd
etc/config/ubootenv
etc/config/uhttpd
etc/config/unbound
etc/config/wifi_schedule
etc/config/wireless
etc/crontabs/root
etc/dropbear/authorized_keys
etc/dropbear/dropbear_ed25519_host_key
etc/dropbear/dropbear_rsa_host_key
etc/fw_env.config
etc/group
etc/hosts
etc/inittab
etc/luci-uploads/.placeholder
etc/nftables.d/10-custom-filter-chains.nft
etc/nftables.d/README
etc/opkg/keys/8a11255d14aef6c8
etc/opkg/keys/d310c6f2833e97f7
etc/passwd
etc/profile
etc/profile.d/busybox-history-file.sh
etc/rc.local
etc/shadow
etc/shells
etc/shinit
etc/sysctl.conf
etc/sysupgrade.conf
etc/uhttpd.crt
etc/uhttpd.key
etc/unbound/unbound.conf
etc/unbound/unbound_ext.conf
root/opkgscript.sh
(date) upgrade: Commencing upgrade. Closing all shell sessions.
</code></pre>
<div class="tab-info i-tip">Tip</div><div class="alert alert-tip" role="alert">Notice the presence of the file <code>/etc/config/opkg.installed</code> into the
backup.</div>

<p>At this moment, your SSH session close, and the router reboot!</p>
<hr>

<div class="tab-info i-info">Info</div><div class="alert alert-info" role="alert"><p>When reconnecting to your router from your SSH client, it may happen that the SSH connection fails with the following error message: <br>
<code>WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED</code>. <br>
In this case, please see the note <a href="/en/sys/openwrt/sysupgrade/#ssh-remote-host-identification">SSH Remote Host Identification</a></p>
<hr>
<p>If you migrate from 19.07.x to ≥ 21.02.x, please read carefully the note <a href="/en/sys/openwrt/sysupgrade/#migration-to--2102">Migration to ≥ 21.02.*</a></p>
<hr>
<p>After rebooting, if your router cant access to the Internet, check the nameserver on <code>/etc/resolv.conf</code>.</p>
</div>

<hr>
<h4 id="verify-the-new-os-version">Verify the new OS version</h4>
<p>After the reboot, you will find the information about the new version:</p>
<ul>
<li>In LuCI, go to Status &gt; Overview, see the section &ldquo;System&rdquo; and &ldquo;Firmware version&rdquo;.</li>
<li>In SSH, the login banner has the release information. As instance:</li>
</ul>
<pre tabindex="0"><code class="language-ash" data-lang="ash">BusyBox v1.36.1 (2025-12-17 21:08:22 UTC) built-in shell (ash)

  _______                     ________        __
 |       |.-----.-----.-----.|  |  |  |.----.|  |_
 |   -   ||  _  |  -__|     ||  |  |  ||   _||   _|
 |_______||   __|_____|__|__||________||__|  |____|
          |__| W I R E L E S S   F R E E D O M
 -----------------------------------------------------
 OpenWrt 24.10.5, r29087-d9c5716d1d
 -----------------------------------------------------
</code></pre><h3 id="upgrade-packages">Upgrade packages</h3>

<div class="tab-info i-warning">Warning</div><div class="alert alert-warning" role="alert"><p>Note that on a device with only 4MB of NVRAM, these updates may not fit; ensure there is at least 600KB or so free.</p>
<p>Check your router&rsquo;s specifications!</p>
</div>

<p>Let&rsquo;s upgrade the third-party packages:</p>
<p>⇒ On the SSH console, do:</p>
<p><code>:# opkg update &amp;&amp; opkg list-upgradable</code></p>
<p>If the result show some binaries to update, launch this command:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:# <span style="color:#815ba4">for</span> name in <span style="color:#48b685">`</span>opkg list-upgradable | awk <span style="color:#48b685">&#39;{print $1}&#39;</span><span style="color:#48b685">`</span>; <span style="color:#815ba4">do</span> opkg upgrade <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">name</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>; <span style="color:#815ba4">done</span>
</span></span></code></pre></div><h3 id="restore-user-profil">Restore &ldquo;user profil&rdquo;</h3>
<p>To restore the user profile:</p>
<p>After repeating the step about curl and the script <code>opkgscript.sh</code>, we run the script to reinstall all packages previously intalled by you:</p>
<p><code>:# ./opkgscript.sh -v install</code></p>
<p>And, after… the last but not the least: reboot!</p>
<h2 id="ultimates-checks">Ultimates Checks</h2>
<p>Check your configuration:</p>
<ul>
<li>your various network interfaces are always present and operational?</li>
<li>your firewall configuration is correct?</li>
<li>your different services run correctly? Have you a IPv6 tunnel, OpenVPN,
or others services, usually, accessed by the menu &ldquo;Services&rdquo;?</li>
</ul>
<hr>
<p>Voila!</p>
<hr>
<h2 id="notes">Notes</h2>
<p>You will find various useful informations, only for certain contexts:</p>
<h3 id="flash-on-luci">Flash on LuCI</h3>
<p>Since the menu &ldquo;System&rdquo; &gt; &ldquo;Backup / Flash firmware&rdquo;:</p>
<p>1/ It can be usefull in the &lsquo;Configuration&rsquo; tab to modify the list of custom files to save… <br>
If you installed some packages, relatives files and folders are not backuped if there are not wroted here.</p>
<p>2/ Make a backup of your OpenWRT configuration before, from the &lsquo;Actions&rsquo; tab.</p>
<p>3/ During the process of flashing a new sysupgrade image:</p>
<p>⇒ use those options:</p>
<ul>
<li><strong>KEEP SETTINGS AND RETAIN THE CURRENT CONFIGURATION</strong>, at least</li>
<li><strong>INCLUDE IN BACKUP A LIST OF CURRENT INSTALLED PACKAGES AT /ETC/BACKUP/INSTALLED_PACKAGES.TXT</strong>.</li>
</ul>
<p>If those are not checked, you lost your entire configuration of OpenWRT.</p>
<p>In all cases, all previous installed packages need to be reinstall, perhaps to configure again.</p>
<p>Keep on mind that changes included by upgrades to major version can cause problems during migration. There may be critical changes.</p>
<h3 id="ssh-v90-and-higher">SSH v9.0 and higher</h3>
<p>If your SSH client version is ≥ 9.0:</p>
<p>Since SSH v9.0, the behavior of <code>scp</code> has changed.</p>
<p>The above command will fail with the error message:</p>
<pre tabindex="0"><code class="language-ash" data-lang="ash">scp router:/tmp/backup-***-2022-04-21.tar.gz .
ash: /usr/libexec/sftp-server: not found
scp: Connection closed
</code></pre><p>In the fact, Dropbrear cant discuss with… <br>
To resolve this, add the <code>-O</code> option to the command, instance: <br>
<code>$ scp -O root@openwrt:/tmp/backup*.tar.gz $(pwd)</code> <br>
<em>(this restore the old SFTP behavior of scp)</em></p>
<p>Another tips is to <a href="/en/sys/openwrt/openssh/">install the OpenSSH server instead of Dropbear</a>.</p>
<h3 id="freeing-memory">Freeing memory</h3>
<p>This section is most useful if <code>/tmp</code> is not enough large to store the sysupgrade OpenWRT image. The following actions will temporary free up space in RAM.</p>
<p>Let&rsquo;s make sure of the memory and disk space with the commands <code>free</code> and <code>df</code>, or <code>cat /proc/meminfo</code>; the goal is to verify that <strong>the size of <em>free</em> RAM is larger than the size of the downloaded image</strong>. <br>
If it&rsquo;s the case, then go to continue the process… else, &ldquo;houston, we have a problem&rdquo; and go to discuss on the OpenWRT forum!</p>
<hr>
<p>Take an example to better understand:</p>
<p>⇒ the size of the sysupgrade binary to the current version:</p>
<pre tabindex="0"><code class="language-ash" data-lang="ash">:$ ll -h
(…)
-rw-rw-r-- 1 root root 6.7M Sep  10 13:53 openwrt-22.03.0-ramips-mt7621-xiaomi_redmi-router-ac2100-squashfs-sysupgrade.bin
(…)
</code></pre><p>it is 6.7 Mb.</p>
<p>⇒ the available space in <code>/tmp</code>:</p>
<pre tabindex="0"><code class="language-ash" data-lang="ash">:# df -h
Filesystem                Size      Used Available Use% Mounted on
/dev/root                 3.8M      3.8M         0 100% /rom
tmpfs                    59.7M    540.0K     59.1M   1% /tmp
/dev/ubi0_1              97.2M      7.8M     84.7M   8% /overlay
overlayfs:/overlay       97.2M      7.8M     84.7M   8% /
tmpfs                   512.0K         0    512.0K   0% /dev
</code></pre><p>In the context of the Xiaomi Redmi AC2100, the available space is 59.1Mb, which is more enough to retrieve the sysupgrade image and manage it.</p>
<p>⇒ Also, the space freed memory:</p>
<pre tabindex="0"><code class="language-ash" data-lang="ash">:# free -m
              total        used        free      shared  buff/cache   available
Mem:         122220       40532       61400         540       20288       46700
Swap:             0           0           0
</code></pre><p>In this context, the free memory space is about 60Mb. Again, there is
enough space to manage the sysupgrade image.</p>
<p><strong>If</strong>, in your context, the total space available, i.e. memory + space <code>/tmp</code> is not enough, it&rsquo;s possible to try the following actions — delete what is not useless:</p>
<ul>
<li>package list files:
<code>:# rm -r /tmp/opkg-lists/</code></li>
<li>caches:
<code>:# sync &amp;&amp; echo 3 &gt; /proc/sys/vm/drop_caches</code></li>
<li>the following wifi drivers:
<code>:# rm /etc/modules.d/*{80211,ath9k,b43}*</code></li>
<li>and, finally, check that there are no symbolic links into <code>/etc/modules.d</code>; if, it&rsquo;s the cas, delete-them. This which will free up RAM at the next startup.</li>
<li>And <strong>reboot</strong> before the sysupgrade process.</li>
</ul>
<h3 id="ssh-remote-host-identification">SSH Remote Host Identification</h3>
<p>When connecting again via SSH, it is normally possible that you will get the following error message:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
</span></span><span style="display:flex;"><span>@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
</span></span><span style="display:flex;"><span>@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
</span></span><span style="display:flex;"><span>IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
</span></span><span style="display:flex;"><span>Someone could be eavesdropping on you right now <span style="color:#5bc4bf">(</span>man-in-the-middle attack<span style="color:#5bc4bf">)</span>!
</span></span><span style="display:flex;"><span>It is also possible that a host key has just been changed.
</span></span><span style="display:flex;"><span>The fingerprint <span style="color:#815ba4">for</span> the ED25519 key sent by the remote host is
</span></span><span style="display:flex;"><span>SHA256:0atP7BnQQ98EVJciOCBDYAUD245lKm2tbau8BgWMpQ0.
</span></span><span style="display:flex;"><span>Please contact your system administrator.
</span></span><span style="display:flex;"><span>Add correct host key in /home/you/.ssh/known_hosts to get rid of this message.
</span></span><span style="display:flex;"><span>Offending RSA key in /home/you/.ssh/known_hosts:93
</span></span><span style="display:flex;"><span>  remove with:
</span></span><span style="display:flex;"><span>  ssh-keygen -f <span style="color:#48b685">&#34;/home/you/.ssh/known_hosts&#34;</span> -R <span style="color:#48b685">&#34;192.168.xyz.1&#34;</span>
</span></span><span style="display:flex;"><span>ED25519 host key <span style="color:#815ba4">for</span> 192.168.xyz.1 has changed and you have requested strict checking.
</span></span><span style="display:flex;"><span>Host key verification failed.
</span></span></code></pre></div><p><strong>DO NOT PANIC! It&rsquo;s a normal process.</strong></p>
<p>We changed the version, and the identification host, too. <br>
Apply the ssh-keygen command, like wroted, to delete the older. And, after retry your connection.</p>

<div class="tab-info i-warning">Warning</div><div class="alert alert-warning" role="alert"><p>After the upgrade, the machines behind the router no longer have proper access to the Internet; it&rsquo;s normal; do not panic!</p>
<p>Dont forget: in fact, <code>sysupgrade</code> remove all user configuration datas.</p>
</div>

<h3 id="migration-to--2102">Migration to ≥ 21.02.*</h3>

<div class="tab-info i-warning">Warning</div><div class="alert alert-warning" role="alert"><p><strong>minimum hardware requirements</strong>:</p>
<p>Since version 21.02.0, devices now need at least 8 MB of flash and 64 MB of RAM to run a default build of OpenWRT.</p>
<p>See: <a href="https://openwrt.org/supported_devices/864_warning" rel="external">https://openwrt.org/supported_devices/864_warning</a></p>
</div>

<p>You chose to migrate at the 21.02.* version from v19.7.*, it&rsquo;s fine!</p>
<p>But, you need to connect on the WebUI, and click on the &ldquo;Interfaces&rdquo; menu. <br>
The interface will propose you to migrate the configuration, do-it now!</p>
<p>And after, reboot!</p>
<hr>
<h3 id="resolvconf">resolv.conf</h3>
<p>Check the <code>/etc/resolv.conf</code>, and if necessary, modify it to write IP address of a reachable DNS server.</p>
<p>As instance:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:# sed -i -e <span style="color:#48b685">&#39;s/127.0.0.1/9.9.9.9/&#39;</span> /etc/resolv.conf
</span></span></code></pre></div><h2 id="documentations">Documentations</h2>
<p>As you can read in the documentation of the OpenWRT wiki, there are other methods; the one I propose seems the most relevant…</p>
<ul>
<li><a href="https://openwrt.org/docs/guide-user/installation/generic.sysupgrade" rel="external">Upgrading OpenWrt firmware using LuCI and CLI</a></li>
<li><a href="https://openwrt.org/docs/guide-quick-start/sysupgrade.luci" rel="external">Upgrading OpenWrt firmware using LuCI</a></li>
<li><a href="https://openwrt.org/docs/guide-user/installation/sysupgrade.cli" rel="external">Upgrading OpenWrt firmware using CLI</a></li>
</ul>
<hr>
]]></content><summary>Howto upgrade correctly OpenWRT… without losing user configuration datas; and some explains to migrate versions, on routers like OpenWRT One, Ubiquiti EdgeRouter X, Xiaomi Redmi AC2100, Xiaomi Mi Router AX3000T</summary><published>2020-09-14T18:03:35+02:00</published><updated>2026-10-02T15:49:57+02:00</updated></entry><entry><id>tag:doc.huc.fr.eu.org,2020-08-25:/en/web/hugo/hugo-search-jqueryui-autocomplete-json</id><link href="https://it-log.fr.eu.org/en/web/hugo/hugo-search-jqueryui-autocomplete-json/" rel="alternate" type="text/html"/><title>Hugo Search: a 'build-in' search engine (JQueryUI: Autocomplete + JSON)</title><author><name>Stéphane HUC</name></author><category term="Hugo" scheme="https://it-log.fr.eu.org/en/tags/hugo/"/><category term="search" scheme="https://it-log.fr.eu.org/en/tags/search/"/><category term="JQuery" scheme="https://it-log.fr.eu.org/en/tags/jquery/"/><category term="JSON" scheme="https://it-log.fr.eu.org/en/tags/json/"/><content type="html"><![CDATA[<h2 id="description">Description</h2>
<p>Few months ago, I wrote this first article to build a &lsquo;build-in&rsquo; base search engine, with JQueryUI <code>autocomplete()</code>. (See <a href="/en/web/hugo/hugo-search/">Hugo search</a>)</p>
<p>On this blog, Hugo generates one feed at the JSON format, named <strong>feed.json</strong>, <em>available on the homepage</em>. And, Hugo has a native function <code>getJSON</code>…</p>
<p>Let&rsquo;s go back to the code !</p>
<h2 id="code">Code</h2>
<h3 id="hugo">Hugo</h3>
<p>Firstly, I write a <code>$feed</code> variable; her value is the absolute path for the file <strong>feed.json</strong>.</p>
<pre tabindex="0"><code class="language-hugo" data-lang="hugo">{{- $baseURL := site.BaseURL | absLangURL -}}
{{- $feed :=  urls.JoinPath $baseURL &#34;/feed.json&#34; | absLangURL -}}
</code></pre><h3 id="jquery">JQuery</h3>
<p>JQuery code is quasi the same: except this difference, Hugo&rsquo;s <code>range</code> function will directly call the content returned by the <code>getJSON</code> function.</p>
<p>The code:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-js" data-lang="js"><span style="display:flex;"><span>{{<span style="color:#5bc4bf">-</span> <span style="color:#815ba4">with</span> <span style="color:#06b6ef">resources</span>.<span style="color:#06b6ef">Get</span> <span style="color:#06b6ef">$feed</span> <span style="color:#5bc4bf">-</span>}}
</span></span><span style="display:flex;"><span><span style="color:#776e71">&lt;!--</span> <span style="color:#06b6ef">Javascript</span> <span style="color:#5bc4bf">--&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">&lt;</span><span style="color:#06b6ef">script</span><span style="color:#5bc4bf">&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">$</span>(<span style="color:#815ba4">function</span>() {
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">var</span> <span style="color:#06b6ef">projects</span> <span style="color:#5bc4bf">=</span> [
</span></span><span style="display:flex;"><span>        {{<span style="color:#5bc4bf">-</span> <span style="color:#06b6ef">range</span> .<span style="color:#06b6ef">items</span> <span style="color:#5bc4bf">-</span>}}
</span></span><span style="display:flex;"><span>        {
</span></span><span style="display:flex;"><span>            <span style="color:#06b6ef">value</span><span style="color:#5bc4bf">:</span> <span style="color:#48b685">&#34;{{ safeHTML .title }}&#34;</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#06b6ef">label</span><span style="color:#5bc4bf">:</span> <span style="color:#48b685">&#34;{{ safeHTML .summary }}&#34;</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#06b6ef">url</span><span style="color:#5bc4bf">:</span><span style="color:#48b685">&#34;{{ safeURL .url }}&#34;</span>
</span></span><span style="display:flex;"><span>        },
</span></span><span style="display:flex;"><span>        {{<span style="color:#5bc4bf">-</span> <span style="color:#06b6ef">end</span> <span style="color:#5bc4bf">-</span>}}
</span></span><span style="display:flex;"><span>        ];
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">$</span>(<span style="color:#48b685">&#34;#search&#34;</span>).<span style="color:#06b6ef">autocomplete</span>({
</span></span><span style="display:flex;"><span>        <span style="color:#06b6ef">minLength</span><span style="color:#5bc4bf">:</span> <span style="color:#f99b15">0</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#06b6ef">source</span><span style="color:#5bc4bf">:</span> <span style="color:#06b6ef">projects</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#06b6ef">focus</span><span style="color:#5bc4bf">:</span> <span style="color:#815ba4">function</span>( <span style="color:#06b6ef">event</span>, <span style="color:#06b6ef">ui</span> ) {
</span></span><span style="display:flex;"><span>            <span style="color:#06b6ef">$</span>(<span style="color:#48b685">&#34;#search&#34;</span>).<span style="color:#06b6ef">val</span>( <span style="color:#06b6ef">ui</span>.<span style="color:#06b6ef">item</span>.<span style="color:#06b6ef">label</span> );
</span></span><span style="display:flex;"><span>            <span style="color:#815ba4">return</span> <span style="color:#815ba4">false</span>;
</span></span><span style="display:flex;"><span>        },
</span></span><span style="display:flex;"><span>        <span style="color:#06b6ef">select</span><span style="color:#5bc4bf">:</span> <span style="color:#815ba4">function</span>( <span style="color:#06b6ef">event</span>, <span style="color:#06b6ef">ui</span> ) {
</span></span><span style="display:flex;"><span>            <span style="color:#06b6ef">$</span>(<span style="color:#48b685">&#34;#search&#34;</span>).<span style="color:#06b6ef">val</span>( <span style="color:#06b6ef">ui</span>.<span style="color:#06b6ef">item</span>.<span style="color:#06b6ef">label</span> );
</span></span><span style="display:flex;"><span>            <span style="color:#06b6ef">$</span>(<span style="color:#48b685">&#34;#replyer&#34;</span>).<span style="color:#06b6ef">val</span>( <span style="color:#06b6ef">ui</span>.<span style="color:#06b6ef">item</span>.<span style="color:#06b6ef">value</span> );
</span></span><span style="display:flex;"><span>            <span style="color:#815ba4">return</span> <span style="color:#815ba4">false</span>;
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>    })
</span></span><span style="display:flex;"><span>    .<span style="color:#06b6ef">data</span>(<span style="color:#48b685">&#39;ui-autocomplete&#39;</span>).<span style="color:#06b6ef">_renderItem</span> <span style="color:#5bc4bf">=</span> <span style="color:#815ba4">function</span>(<span style="color:#06b6ef">ul</span>, <span style="color:#06b6ef">item</span>) {
</span></span><span style="display:flex;"><span>        <span style="color:#815ba4">return</span> <span style="color:#06b6ef">$</span>(<span style="color:#48b685">&#39;&lt;li&gt;&#39;</span>)
</span></span><span style="display:flex;"><span>        .<span style="color:#06b6ef">append</span>(<span style="color:#48b685">&#39;&lt;a href=&#34;&#39;</span> <span style="color:#5bc4bf">+</span> <span style="color:#06b6ef">item</span>.<span style="color:#06b6ef">url</span> <span style="color:#5bc4bf">+</span> <span style="color:#48b685">&#39;&#34; alt=&#34;&#39;</span><span style="color:#5bc4bf">+</span> <span style="color:#06b6ef">item</span>.<span style="color:#06b6ef">label</span> <span style="color:#5bc4bf">+</span> <span style="color:#48b685">&#39;&#34;&gt;&#39;</span> <span style="color:#5bc4bf">+</span> <span style="color:#06b6ef">item</span>.<span style="color:#06b6ef">value</span> <span style="color:#5bc4bf">+</span> <span style="color:#48b685">&#39;&lt;/a&gt;&#39;</span> )
</span></span><span style="display:flex;"><span>        .<span style="color:#06b6ef">appendTo</span>(<span style="color:#06b6ef">ul</span>);
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>});
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">&lt;</span><span style="color:#ef6155">/script&gt;</span>
</span></span><span style="display:flex;"><span>{{<span style="color:#5bc4bf">-</span> <span style="color:#06b6ef">end</span> <span style="color:#5bc4bf">-</span>}}
</span></span></code></pre></div><h3 id="html">HTML</h3>
<p>Make HTML is always so simple:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-html" data-lang="html"><span style="display:flex;"><span>&lt;<span style="color:#5bc4bf">input</span> <span style="color:#06b6ef">class</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;form-control&#34;</span> <span style="color:#06b6ef">id</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;search&#34;</span> <span style="color:#06b6ef">placeholder</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;{{ T &#34;</span><span style="color:#06b6ef">searchHolderTitle</span><span style="color:#ef6155">&#34;</span> <span style="color:#ef6155">}}&#34;</span>&gt;
</span></span><span style="display:flex;"><span>&lt;<span style="color:#5bc4bf">input</span> <span style="color:#06b6ef">aria-hidden</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;true&#34;</span> <span style="color:#06b6ef">id</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;replyer&#34;</span> <span style="color:#06b6ef">class</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;hidden&#34;</span>&gt;
</span></span></code></pre></div><h3 id="tldr">TL;DR</h3>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-html" data-lang="html"><span style="display:flex;"><span>&lt;<span style="color:#5bc4bf">div</span> <span style="color:#06b6ef">id</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;search&#34;</span>&gt;
</span></span><span style="display:flex;"><span>    &lt;<span style="color:#5bc4bf">input</span> <span style="color:#06b6ef">class</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;form-control&#34;</span> <span style="color:#06b6ef">id</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;search&#34;</span> <span style="color:#06b6ef">placeholder</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;{{ T &#34;</span><span style="color:#06b6ef">searchHolderTitle</span><span style="color:#ef6155">&#34;</span> <span style="color:#ef6155">}}&#34;</span>&gt;
</span></span><span style="display:flex;"><span>    &lt;<span style="color:#5bc4bf">input</span> <span style="color:#06b6ef">aria-hidden</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;true&#34;</span> <span style="color:#06b6ef">id</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;replyer&#34;</span> <span style="color:#06b6ef">class</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;hidden&#34;</span>&gt;
</span></span><span style="display:flex;"><span>    {{- $baseURL := site.BaseURL | absLangURL -}}
</span></span><span style="display:flex;"><span>    {{- $feed :=  urls.JoinPath $baseURL &#34;/feed.json&#34; | absLangURL -}}
</span></span><span style="display:flex;"><span>    {{- with resources.Get $feed -}}
</span></span><span style="display:flex;"><span>    <span style="color:#776e71">&lt;!-- Javascript --&gt;</span>
</span></span><span style="display:flex;"><span>    &lt;<span style="color:#5bc4bf">script</span>&gt;
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">$</span>(<span style="color:#815ba4">function</span>() {
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">var</span> <span style="color:#06b6ef">projects</span> <span style="color:#5bc4bf">=</span> [
</span></span><span style="display:flex;"><span>        {{<span style="color:#5bc4bf">-</span> <span style="color:#06b6ef">range</span> .<span style="color:#06b6ef">items</span> <span style="color:#5bc4bf">-</span>}}
</span></span><span style="display:flex;"><span>        {
</span></span><span style="display:flex;"><span>            <span style="color:#06b6ef">value</span><span style="color:#5bc4bf">:</span> <span style="color:#48b685">&#34;{{ safeHTML .title }}&#34;</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#06b6ef">label</span><span style="color:#5bc4bf">:</span> <span style="color:#48b685">&#34;{{ safeHTML .summary }}&#34;</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#06b6ef">url</span><span style="color:#5bc4bf">:</span><span style="color:#48b685">&#34;{{ safeURL .url }}&#34;</span>
</span></span><span style="display:flex;"><span>        },
</span></span><span style="display:flex;"><span>        {{<span style="color:#5bc4bf">-</span> <span style="color:#06b6ef">end</span> <span style="color:#5bc4bf">-</span>}}
</span></span><span style="display:flex;"><span>        ];
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">$</span>(<span style="color:#48b685">&#34;#search&#34;</span>).<span style="color:#06b6ef">autocomplete</span>({
</span></span><span style="display:flex;"><span>        <span style="color:#06b6ef">minLength</span><span style="color:#5bc4bf">:</span> <span style="color:#f99b15">0</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#06b6ef">source</span><span style="color:#5bc4bf">:</span> <span style="color:#06b6ef">projects</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#06b6ef">focus</span><span style="color:#5bc4bf">:</span> <span style="color:#815ba4">function</span>( <span style="color:#06b6ef">event</span>, <span style="color:#06b6ef">ui</span> ) {
</span></span><span style="display:flex;"><span>            <span style="color:#06b6ef">$</span>(<span style="color:#48b685">&#34;#search&#34;</span>).<span style="color:#06b6ef">val</span>( <span style="color:#06b6ef">ui</span>.<span style="color:#06b6ef">item</span>.<span style="color:#06b6ef">label</span> );
</span></span><span style="display:flex;"><span>            <span style="color:#815ba4">return</span> <span style="color:#815ba4">false</span>;
</span></span><span style="display:flex;"><span>        },
</span></span><span style="display:flex;"><span>        <span style="color:#06b6ef">select</span><span style="color:#5bc4bf">:</span> <span style="color:#815ba4">function</span>( <span style="color:#06b6ef">event</span>, <span style="color:#06b6ef">ui</span> ) {
</span></span><span style="display:flex;"><span>            <span style="color:#06b6ef">$</span>(<span style="color:#48b685">&#34;#search&#34;</span>).<span style="color:#06b6ef">val</span>( <span style="color:#06b6ef">ui</span>.<span style="color:#06b6ef">item</span>.<span style="color:#06b6ef">label</span> );
</span></span><span style="display:flex;"><span>            <span style="color:#06b6ef">$</span>(<span style="color:#48b685">&#34;#replyer&#34;</span>).<span style="color:#06b6ef">val</span>( <span style="color:#06b6ef">ui</span>.<span style="color:#06b6ef">item</span>.<span style="color:#06b6ef">value</span> );
</span></span><span style="display:flex;"><span>            <span style="color:#815ba4">return</span> <span style="color:#815ba4">false</span>;
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>    })
</span></span><span style="display:flex;"><span>    .<span style="color:#06b6ef">data</span>(<span style="color:#48b685">&#39;ui-autocomplete&#39;</span>).<span style="color:#06b6ef">_renderItem</span> <span style="color:#5bc4bf">=</span> <span style="color:#815ba4">function</span>(<span style="color:#06b6ef">ul</span>, <span style="color:#06b6ef">item</span>) {
</span></span><span style="display:flex;"><span>        <span style="color:#815ba4">return</span> <span style="color:#06b6ef">$</span>(<span style="color:#48b685">&#39;&lt;li&gt;&#39;</span>)
</span></span><span style="display:flex;"><span>        .<span style="color:#06b6ef">append</span>(<span style="color:#48b685">&#39;&lt;a href=&#34;&#39;</span> <span style="color:#5bc4bf">+</span> <span style="color:#06b6ef">item</span>.<span style="color:#06b6ef">url</span> <span style="color:#5bc4bf">+</span> <span style="color:#48b685">&#39;&#34; alt=&#34;&#39;</span><span style="color:#5bc4bf">+</span> <span style="color:#06b6ef">item</span>.<span style="color:#06b6ef">label</span> <span style="color:#5bc4bf">+</span> <span style="color:#48b685">&#39;&#34;&gt;&#39;</span> <span style="color:#5bc4bf">+</span> <span style="color:#06b6ef">item</span>.<span style="color:#06b6ef">value</span> <span style="color:#5bc4bf">+</span> <span style="color:#48b685">&#39;&lt;/a&gt;&#39;</span> )
</span></span><span style="display:flex;"><span>        .<span style="color:#06b6ef">appendTo</span>(<span style="color:#06b6ef">ul</span>);
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>});
</span></span><span style="display:flex;"><span>    &lt;/<span style="color:#5bc4bf">script</span>&gt;
</span></span><span style="display:flex;"><span>    {{- end -}}
</span></span><span style="display:flex;"><span>&lt;/<span style="color:#5bc4bf">div</span>&gt;
</span></span></code></pre></div><hr>
<p>Voila!</p>
<h3 id="error">Error</h3>
<p><abbr title="Question">Q</abbr>
: When you use Hugo into its environment development,
it made severals errors, and stop, as: <br>
<code>ERROR 2020/08/27 08:16:41 Failed to get JSON resource “http://localhost:1313/fr/feed.json”: Get “http://localhost:1313/fr/feed.json”: dial tcp [::1]:1313: connect: connection refused</code></p>
<p><abbr title="Answer">A</abbr>
: The server is not able to call a data not builded.</p>
<hr>
<h2 id="documentations">Documentations</h2>
<ul>
<li><a href="https://gohugo.io/tools/search/" title="Link to the official site Hugo: Tools &gt; Search">Hugo Documentation: Tools &gt; Search</a>
</li>
<li>Hugo <code>getJSON</code> function: <a href="https://gohugo.io/templates/data-templates/#load-local-files" title="Link to the official site Hugo: Templates &gt; Data templates">Hugo Documentation: Templates &gt; Data templates</a>
</li>
<li>JQuery UI <code>autocomplete()</code> method: <a href="https://jqueryui.com/autocomplete" rel="external">https://jqueryui.com/autocomplete</a></li>
</ul>
<hr>
]]></content><summary>Using the JSON feed to integrate a 'search engine' in Hugo, with JQuery UI autocomplete()</summary><published>2020-08-25T23:32:48+02:00</published><updated>2026-10-02T15:49:57+02:00</updated></entry><entry><id>tag:doc.huc.fr.eu.org,2020-05-28:/en/web/httpd/httpd-deliver-compressed-files</id><link href="https://it-log.fr.eu.org/en/web/httpd/httpd-delivers-compressed-files/" rel="alternate" type="text/html"/><title>httpd: deliver compressed static files (+slowcgi)</title><author><name>Stéphane HUC</name></author><category term="httpd" scheme="https://it-log.fr.eu.org/en/tags/httpd/"/><category term="slowcgi" scheme="https://it-log.fr.eu.org/en/tags/slowcgi/"/><category term="OpenBSD" scheme="https://it-log.fr.eu.org/en/tags/openbsd/"/><category term="CGI" scheme="https://it-log.fr.eu.org/en/tags/cgi/"/><category term="deflate" scheme="https://it-log.fr.eu.org/en/tags/deflate/"/><category term="gzip" scheme="https://it-log.fr.eu.org/en/tags/gzip/"/><category term="brotli" scheme="https://it-log.fr.eu.org/en/tags/brotli/"/><content type="html"><![CDATA[<h2 id="description">Description</h2>
<p><strong>OpenBSD</strong> has, by default, in basesystem:</p>
<ul>
<li>
<p>a webserver, named <strong>httpd</strong>, since 5.7</p>
</li>
<li>
<p>a server CGI, named <strong>slowcgi</strong>, since 5.4</p>
</li>
<li>
<p>OpenBSD : <strong>6.6, 6.7</strong></p>
</li>
</ul>
<hr>
<p><strong>Principle</strong>: if web client accepts datas compression in the deflate, gzip,
brotli format, then <strong>httpd</strong> redirects to <strong>slowcgi</strong> to deliver the
compressed static content.</p>

<div class="tab-info i-warning">Warning</div><div class="alert alert-warning" role="alert">This is not means compression dynamicly, or &ldquo;compression on the fly!&rdquo;</div>

<p><strong>httpd</strong> is not able to manage delivery about compressed static content.</p>
<p>The tip is to use the server <strong>slowcgi</strong> CGI for.</p>
<p>In facts, by CGI script shell, we&rsquo;ll assume the delivery of those compressed
static content:</p>
<ul>
<li>for the format: <strong>atom</strong>, <strong>css</strong>, <strong>html</strong>, <strong>js</strong>, <strong>json</strong>, <strong>svg</strong>,
<strong>txt</strong>, <strong>xml</strong></li>
<li>to both compression: <strong>gzip</strong>, and <strong>brotli</strong>.</li>
</ul>
<h2 id="installation">Installation</h2>
<p>You do to <a href="https://framagit.org/hucste/tools/-/raw/master/OpenBSD/slowcgi/sbw.cgi" rel="external">download my script <strong>sbw.cgi</strong></a>.</p>
<p>When it&rsquo;s done, you need to put into the <code>cgi-bin</code> folder on web chroot.
For this, use the command <code>install</code> as: <br>
<code>:# install -o www -g bin -m 0550 sbw.cgi /var/www/cgi-bin/sbw.cgi</code></p>
<p>Indeed, we install correctly with minimals/needed rights to the web user
<code>www</code> and the group <code>bin</code>.</p>
<h3 id="dependencies">Dependencies</h3>
<p>This script need the installation in the web chroot of several binaries
and some libraries, to run correctly:</p>
<p>Copy from:</p>
<ul>
<li>first: <strong>sh</strong>, and binaries: <strong>cat</strong>, <strong>date</strong> and <strong>sha256</strong> —
<em>which are all in the <code>/bin</code> system directory</em>.</li>
<li>all others binaries: <strong>basename</strong>, <strong>logger</strong> <sup><span class="orange">1</span>
</sup>,
<strong>stat</strong> - <em>which are all in the <code>/usr/bin</code> system directory</em>.</li>
<li>the shared libc: <code>/usr/lib/libc.so.xx.0</code> <sup><span class="orange">2</span>
</sup></li>
<li>the library to execution: <code>/usr/libexec/ld.so</code></li>
</ul>
<p>to the respective folders into web chroot <code>/var/www/</code>.</p>
<p>All need <code>root</code> user and <code>bin</code> group rights:</p>
<ul>
<li>with 0555 mode for the binaries, e.g.:
<ul>
<li><strong>sh</strong>:<br>
<code>:# install -o root -g bin -m 0555 /bin/sh /var/www/bin/</code></li>
<li><strong>stat</strong>:<br>
<code>:# iinstall -o root -g bin -m 0555 /usr/bin/stat /var/www/usr/bin/</code></li>
</ul>
</li>
<li>and 0444 mode for the libraries, as:
<ul>
<li><strong>libc</strong>:<br>
<code>:# iinstall -o root -g bin -m 0444 /usr/lib/libc.so.xx.0 /var/www/usr/lib/</code></li>
<li><strong>ld.so</strong>:<br>
<code>:# iinstall -o root -g bin -m 0444 /usr/libexec/ld.so /var/www/usr/libexec/</code></li>
</ul>
</li>
</ul>
<p>Before, you need to create the corresponding directories in the web chroot!</p>
<p>See my <a href="https://framagit.org/hucste/tools/-/blob/master/OpenBSD/chroot_deps" rel="external">dependencies script</a>.</p>
<hr>
<p><sup><span class="orange">1</span>
</sup> about the interest of the binary <code>logger</code>:
Normaly, ideally, we don&rsquo;t need the logger. It is about logging some actions,
which in case of failure, have written in the logs <code>/var/log/{daemon,messages}</code>.</p>
<p>Also, if the <code>debug</code> variable is set to <code>1</code>, on the main function, then
the logger will return the values corresponding to the different variables,
for analysis: ensure that variable receive one value, and what value‽</p>
<p><sup><span class="orange">2</span>
</sup> The <strong>libc.so</strong> change name,
at each version of OpenBSD:</p>
<ul>
<li>v6.7 : <code>libc.so.96.0</code></li>
<li>v6.6 : <code>libc.so.95.1</code></li>
</ul>
<p>This detail is important, can be hardly scripted. You need to modify the
script, at the new version of OpenBSD, to change the name of the library,
otherwise, it will not work!</p>
<hr>

<div class="tab-info i-tip">Tip</div><div class="alert alert-tip" role="alert">To known, what are the dependencies from a binary, use the command <code>ldd</code>.</div>

<h2 id="configuration">Configuration</h2>
<h3 id="httpd">httpd</h3>
<p>Add at your context <code>server</code>, all following needed <code>location</code> statements:</p>
<pre tabindex="0"><code class="language-httpd" data-lang="httpd">location &#34;/*.atom&#34; { include &#34;/etc/httpd.d/sbw.conf&#34; }
location &#34;/*.css&#34; { include &#34;/etc/httpd.d/sbw.conf&#34; }
location &#34;/*.html&#34; { include &#34;/etc/httpd.d/sbw.conf&#34; }
location &#34;/*.js&#34; { include &#34;/etc/httpd.d/sbw.conf&#34; }
location &#34;/*.json&#34; { include &#34;/etc/httpd.d/sbw.conf&#34; }
location &#34;/*.svg&#34; { include &#34;/etc/httpd.d/sbw.conf&#34; }
location &#34;/*.txt&#34; { include &#34;/etc/httpd.d/sbw.conf&#34; }
location &#34;/*.xml&#34; { include &#34;/etc/httpd.d/sbw.conf&#34; }
</code></pre><p>The file <code>sbw.conf</code> contains the following <code>fastcgi</code> statements:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">root &#34;/cgi-bin/sbw.cgi&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">fastcgi param realroot &#34;/htdocs/domaine.tld/www&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">fastcgi param cachecontrol &#34;1814400&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">fastcgi param file404 &#34;/404.html&#34;</span>
</span></span></code></pre></div><p><strong>Explainations</strong> :</p>
<p>It&rsquo;s important to define, at least:</p>
<ul>
<li><strong>root</strong>: the relative path of script CGI, into the web chroot.</li>
<li><strong>realroot</strong>: a parameter for your web root</li>
<li>and optionals paramaters, specially of the cache.</li>
</ul>
<h3 id="slowcgi">slowcgi</h3>
<p>The server <strong>slowcgi</strong> does not require any configuration. Only, you enable
and start with the tool <code>rcctl</code>.</p>
<h2 id="history">History</h2>
<h3 id="vulnerabilities">Vulnerabilities</h3>
<p>In fact, the story of the 






























<span lang="en">HTTP <em>(HyperText Transfer Protocol)</em></span>
















































































 protocol
reveals us two majors vulnerabilities related to the on-the-fly compression:
<strong>CRIME</strong> and <strong>BREACH</strong> — <em>the second is forked on the first</em>. <br>
Thoses vulnerabilities can even impact 































































































<span lang="en">TLS <em>(Transport Layer Secure)</em></span>















.</p>
<p>Among the countermeasures has been the adoption since 































<abbr lang="en" title="HyperText Transfer Protocol">HTTP</abbr>
















































































 1.1 of
block encoding transfer — <em>the famous <code>Transfer-Encoding: chunked</code> header</em>;
similarly, it is strongly recommended to implement a <strong>Referrer</strong> policy
to allow delivery of compressed content ONLY from the current domain,
and to refuse it from any other domain.</p>
<h3 id="about-httpd">about httpd</h3>
<p>Reyk Floeter, the httpd author/developer, <a href="https://github.com/reyk/httpd/issues/21" rel="external">denies support for the compressed
content</a>. Even, one <a href="https://github.com/reyk/httpd/issues/80" rel="external">request</a> had be done to support pre-compressed
content, it&rsquo;s not ready to be integrated.</p>
<h3 id="brotli">brotli</h3>
<p><strong>brotli</strong> is a compression format invented by a team from the company Google.
It is considered to be the successor to gzip because it is faster and has
a better compression ratio.</p>
<p>For more informations, see:</p>
<ul>
<li><a href="https://brotli.org/" rel="external">https://brotli.org/</a></li>
<li>Does your web client support it: <a href="https://caniuse.com/#search=brotli" rel="external">https://caniuse.com/#search=brotli</a></li>
</ul>
<p><strong>curl</strong>, since v7.57.0, support brotli, by adding the option <code>--compressed</code>,
or <code>-H</code> — <em>this manage finely HTTP headers</em>. (see the <a href="https://curl.haxx.se/docs/manpage.html" rel="external">manpage</a>)*</p>
<h4 id="unsupported-clients">unsupported clients</h4>
<ul>
<li>On OpenBSD, <strong>curl</strong> seems not supported brotli.</li>
<li>Egual, on all OS, <strong>lynx</strong>, <strong>w3m</strong> does not support it.</li>
</ul>
<h3 id="firefox">Firefox</h3>
<p>Since v64, <a href="https://support.mozilla.org/en-US/kb/feed-reader-replacements-firefox" rel="external">Firefox does not support Atom or RSS feed</a>.</p>
<p>Actually, it&rsquo;s more subtle than it sounds:</p>
<ul>
<li>if you deliver Atom or RSS with mime type <strong>text/xml</strong>, both are XML files,
Firefox accepts to read and native display.</li>
<li>if you deliver it with their mime type, respectively <strong>application/atom+xml</strong>
and <strong>application/rss+xml</strong>, a RFC standard, then Firefox ask you what
to do with.</li>
</ul>
<p>&ldquo;A nameless aberration!!!&rdquo;</p>
<h3 id="the-little-story">the little story</h3>
<p>For the little story, Xavier Cartron @prx is the original author of this
genious idea to deliver compressed static content, by adding the header
<code>ETag</code>. <em>This is an id for the delivered ressource</em>.</p>
<p>It is in this context, that the binary <strong>sha256</strong> is useful.</p>
<hr>
<p>My work, based on his first version, was to add several things:</p>
<p>About <a href="/en/web/httpd/httpd-delivers-compressed-files/#brotli">brotli</a>, so I resumed/continued writing in order to be able to
deliver static content previously compressed with this format.</p>
<p>Next, I added code to manage others needed headers:</p>
<ul>
<li><code>Content-Length</code>: to send weight of delivered document. <br>
<em>It is in this context, that the binary <strong>stat</strong> is useful</em>.</li>
<li><code>Last-Modified</code>: to get the modification date of the delivered document;
someone considers this header is more relevant than <strong>ETag</strong>. <br>
<em>It is in this context, that the binaries <strong>date</strong> and <strong>stat</strong> are useful</em>.</li>
<li><code>Transfer-Encoding</code>: to send the delivered document with the good compression
format, if necessary.</li>
</ul>
<p>Then, I wrote the necessary code to detect if the useful dependencies were
in the web chroot, otherwise the script can&rsquo;t work. If it&rsquo;s the case, the
serveur send an error 500, with an explicit HTML message.</p>
<p><strong>ATTENTION</strong>: the script not installs and can not install the dependancies;
because, it on the web chroot, it can not &ldquo;view&rdquo; the OS filesystem.</p>
<p>Next, after some research on the web, I understant that the format <strong>deflate</strong>,
that may be requested by some web clients, is managed by the format <strong>gzip</strong>;
then, the script supports too.</p>
<hr>
<p>But I was confronted with dysfunctions that I couldn&rsquo;t understand, let alone solve.
<em>I stopped the project</em> :(</p>
<p>But, two &ldquo;things&rdquo; helped seriously to continue:</p>
<ul>
<li>Solène Rapenne, from the OpenBSD team, helped to understand I was making
the mistake of sending too many line breaks, when I need only one,
at the right time, one between the sending of the different headers
and the document itself, whether it is compressed or not.</li>
<li>the idea to implement a variable <code>debug</code> and use the binary <code>logger</code> to
ensure some differents returns.</li>
</ul>
<p>One tips that Solène gave me is the local use of this command:<br>
<code>env HTTP_ACCEPT_ENCODING=br realroot=/var/www/htdocs/domaine.tld/dev/ PATH_INFO=index.html /var/www/cgi-bin/sbw.cgi | less</code><br>
explaining me that it is possible to query the CGI server locally directly,
by sending it the different possible values before the call.<br>
Amazing! :D</p>
<p>About this, since we installed the CGI shell script <strong>sbw.cgi</strong> with the
user rights to <strong>0550</strong>, we had this erreur: <br>
<code>env: /var/www/cgi-bin/sbw2.cgi: Permission denied</code> <br>
you need to change the other rights to <code>+x</code> <em>(or, <code>0551</code>)</em>. ;-)</p>
<hr>
<p>I improved the detection of the mime type by getting it from the file
called on the filesystem — <em>this need to use the binary <strong>basename</strong></em> -
and the management of the mime type about feed Atom or RSS.</p>
<p>Finally, I wrote the necessary code to detect if the user agent was
<a href="/en/web/httpd/httpd-delivers-compressed-files/#firefox">Firefox</a>:</p>
<ul>
<li>If yes, to obtain his version number. A little hack to deliver feed Atom
and RSS to the &ldquo;false&rdquo; mime-type <strong>text/xml</strong>. Also, Firefox accepts
to read the feed instead asking to open with another application!</li>
</ul>
<p>I wrote the first draft of this hack requiring the addition of the binaries
<code>grep</code> and <code>awk</code> — <em>but, this functional solution did not satisfy me</em>.
When, an user on the forum about the french community &ldquo;OpenBSD pour tous&rdquo;,
@eol makes me to think to use shell expansion.</p>
<p><span lang="fr">&ldquo;Et, voilà!&quot;</span></p>
<hr>
<p>Actualy, @prx rewrote his script in C:</p>
<ul>
<li>the advantage is that there is no need for any dependency; too, it&rsquo;s
&ldquo;protected&rdquo; by the system call security measures pledge(2) and unveil(2).</li>
<li>however, it ONLY supports gzip compression; egual, no header <strong>Last-Modified</strong>,
or brotli, and deflate support, at least not directly|automatically.</li>
</ul>
<h2 id="documentation">Documentation</h2>
<p>For more documentation about <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy" rel="external">referrer policy</a>.</p>
<h3 id="manpage">manpage</h3>
<ul>
<li>
<a class="man" href="https://man.openbsd.org/install" title="OpenBSD Manual Page Server for: install">install</a>
</li>
<li>
<a class="man" href="https://man.openbsd.org/slowcgi.8" title="OpenBSD Manual Page Server for: slowcgi">slowcgi(8)</a>
, 
<a class="man" href="https://man.openbsd.org/rcctl.8" title="OpenBSD Manual Page Server for: rcctl">rcctl(8)</a>
</li>
<li>
<a class="man" href="https://man.openbsd.org/pledge.2" title="OpenBSD Manual Page Server for: pledge">pledge(2)</a>
, 
<a class="man" href="https://man.openbsd.org/unveil.2" title="OpenBSD Manual Page Server for: unveil">unveil(2)</a>
</li>
</ul>
<h3 id="wikipédia">Wikipédia</h3>
<ul>
<li>About the <strong>BREACH</strong> vulnerability: <a href="https://en.wikipedia.org/wiki/BREACH" rel="external">https://en.wikipedia.org/wiki/BREACH</a></li>
<li>and the <strong>CRIME</strong> exploit: <a href="https://en.wikipedia.org/wiki/CRIME_(security_exploit)" rel="external">https://en.wikipedia.org/wiki/CRIME_(security_exploit)</a></li>
</ul>
<hr>
]]></content><summary>To deliver compressed static content (in the deflate, gzip, brotli format) by httpd+slowcgi, natives servers on OpenBSD</summary><published>2020-05-28T20:00:11+02:00</published><updated>2026-10-02T15:49:57+02:00</updated></entry><entry><id>tag:doc.huc.fr.eu.org,2020-05-17:/en/web/httpd/relayd-log</id><link href="https://it-log.fr.eu.org/en/web/httpd/relayd-log/" rel="alternate" type="text/html"/><title>Relayd: Log</title><author><name>Stéphane HUC</name></author><category term="relayd" scheme="https://it-log.fr.eu.org/en/tags/relayd/"/><category term="log" scheme="https://it-log.fr.eu.org/en/tags/log/"/><category term="OpenBSD" scheme="https://it-log.fr.eu.org/en/tags/openbsd/"/><category term="astuce" scheme="https://it-log.fr.eu.org/en/tags/astuce/"/><content type="html"><![CDATA[<h2 id="description">Description</h2>
<p><strong>OpenBSD</strong> has, by default, in basesystem, since 5.7, the relay server
named <strong>relayd</strong>.</p>
<ul>
<li>
<p>Website: <a href="https://bsd.plumbing/" rel="external">https://bsd.plumbing/</a></p>
</li>
<li>
<p>OpenBSD: <strong>6.6, 6.7</strong></p>
</li>
</ul>
<hr>
<p>The purpose of this article is to learn how to set up a logging of the
HTTP(S) stream that passes through <strong>relayd</strong>.</p>
<p>So very simple!</p>
<h2 id="configuration">Configuration</h2>
<ul>
<li>File configuration is: <code>/etc/relayd.conf</code></li>
</ul>
<h3 id="global-configuration">Global Configuration</h3>
<p>In first, we need to declare the global parameter <code>log</code> into the file config.
<em>
<a class="" href="https://man.openbsd.org/relayd.conf.5#log" title="OpenBSD Manual Page Server for: relayd.conf">relayd.conf(5)#log</a>
</em></p>
<p><strong>Explainations</strong></p>
<p>The following log declarations are those signification:</p>
<ul>
<li><code>log state changes</code> and <code>log host checks</code> are useful to follow the state
of the host or the checks. Those states can be of type:
<ul>
<li><code>up</code>: if state is positive</li>
<li><code>down</code>: if the host is down, or the checks are not good.</li>
<li><code>unknown</code>: if the host is disable or not yet controled.</li>
</ul>
</li>
<li><code>log connection</code>: to log all the traffic TCP, only <strong>if relayd act as
relay</strong>. <sup><span class="orange">1</span>
</sup>.<br>
Note:  the option <code>errors</code> is useful when we will log only if TCP connections
send errors.</li>
</ul>
<p><sup><span class="orange">1</span>
</sup> <em>In fact, <strong>relayd</strong> can be
configured too as a router, or redirection server</em>.</p>
<h3 id="filters-rules">Filters rules</h3>
<p>Relays are able to filter the connections by adding specific filters parameters.</p>
<p>We will use the action <code>match</code> on which we apply the logging option <code>log</code>.
<em>
<a class="" href="https://man.openbsd.org/relayd.conf.5#match" title="OpenBSD Manual Page Server for: relayd.conf">relayd.conf(5)#match</a>
</em><br>
This corresponding action will apply on:</p>
<ul>
<li><code>cookie</code>: an action on a cookie. <sup><span class="orange">2</span>
</sup>
<em>
<a class="" href="https://man.openbsd.org/relayd.conf.5#cookie" title="OpenBSD Manual Page Server for: relayd.conf">relayd.conf(5)#cookie</a>
</em></li>
<li><code>header</code>: to target an HTTP header.
<em>
<a class="" href="https://man.openbsd.org/relayd.conf.5#header" title="OpenBSD Manual Page Server for: relayd.conf">relayd.conf(5)#header</a>
</em></li>
<li><code>path</code>: to scan the asked URL. <sup><span class="orange">2</span>
</sup>
<em>
<a class="" href="https://man.openbsd.org/relayd.conf.5#path" title="OpenBSD Manual Page Server for: relayd.conf">relayd.conf(5)#path</a>
</em></li>
<li><code>query</code>: to analyse the URL queries. <sup><span class="orange">2</span>
</sup>
<em>
<a class="" href="https://man.openbsd.org/relayd.conf.5#query" title="OpenBSD Manual Page Server for: relayd.conf">relayd.conf(5)#query</a>
</em></li>
<li><code>url</code>: to get complete URL. <sup><span class="orange">2</span>
</sup>
<em>
<a class="" href="https://man.openbsd.org/relayd.conf.5#url" title="OpenBSD Manual Page Server for: relayd.conf">relayd.conf(5)#url</a>
</em></li>
</ul>
<p><sup><span class="orange">2</span>
</sup> <em>only available on HTTP request.</em></p>
<h3 id="configuration-example">Configuration: example</h3>
<p>The follow exampe show us five filters rules:</p>
<ul>
<li>the first four on the matching header</li>
<li>the last log the complete URL</li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#776e71">### ips externe auth</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip4</span> <span style="color:#5bc4bf">=</span> <span style="color:#48b685">&#34;addresse-ipv4-public&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">### manage logs</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">log state changes</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">log connection</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#log connection errors</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">http protocol &#34;hw&#34; {</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">match header log &#34;Host&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">match header log &#34;X-Forwarded-For&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">match header log &#34;User-Agent&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">match header log &#34;Referer&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">match url log</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">block</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">(…)</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">relay &#34;www&#34; {</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">listen on $ip4 port 80</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">protocol hw</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">forward to 127.0.0.1 port 80</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">}</span>
</span></span></code></pre></div><h2 id="logs">Logs</h2>
<p>All logs are visibles into:</p>
<ul>
<li><code>/var/log/daemon</code>,</li>
<li><code>/var/log/message</code>.</li>
</ul>
<h3 id="log-daemon-example">log daemon: example</h3>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>$ grep relayd /var/log/daemon
</span></span><span style="display:flex;"><span>May <span style="color:#f99b15">17</span> 16:37:21 sh1 relayd<span style="color:#5bc4bf">[</span>25237<span style="color:#5bc4bf">]</span>: relay www, session <span style="color:#f99b15">13</span> <span style="color:#5bc4bf">(</span><span style="color:#f99b15">2</span> active<span style="color:#5bc4bf">)</span>, 0, 192.168.1.1 -&gt; :80, <span style="color:#815ba4">done</span>
</span></span><span style="display:flex;"><span>May <span style="color:#f99b15">17</span> 16:37:21 sh1 relayd<span style="color:#5bc4bf">[</span>45869<span style="color:#5bc4bf">]</span>: relay www, session <span style="color:#f99b15">7</span> <span style="color:#5bc4bf">(</span><span style="color:#f99b15">2</span> active<span style="color:#5bc4bf">)</span>, 0, 192.168.1.1 -&gt; :80, <span style="color:#815ba4">done</span>
</span></span><span style="display:flex;"><span>May <span style="color:#f99b15">17</span> 16:37:21 sh1 relayd<span style="color:#5bc4bf">[</span>45869<span style="color:#5bc4bf">]</span>: relay www, session <span style="color:#f99b15">8</span> <span style="color:#5bc4bf">(</span><span style="color:#f99b15">1</span> active<span style="color:#5bc4bf">)</span>, 0, 192.168.1.1 -&gt; :80, <span style="color:#815ba4">done</span>
</span></span><span style="display:flex;"><span>May <span style="color:#f99b15">17</span> 16:37:22 sh1 relayd<span style="color:#5bc4bf">[</span>25237<span style="color:#5bc4bf">]</span>: relay www, session <span style="color:#f99b15">14</span> <span style="color:#5bc4bf">(</span><span style="color:#f99b15">1</span> active<span style="color:#5bc4bf">)</span>, 0, 192.168.1.1 -&gt; :80, <span style="color:#815ba4">done</span>
</span></span><span style="display:flex;"><span>May <span style="color:#f99b15">17</span> 17:01:19 sh1 relayd<span style="color:#5bc4bf">[</span>45869<span style="color:#5bc4bf">]</span>: relay www, session <span style="color:#f99b15">9</span> <span style="color:#5bc4bf">(</span><span style="color:#f99b15">1</span> active<span style="color:#5bc4bf">)</span>, 0, 207.180.140.98 -&gt; :80, Forbidden <span style="color:#5bc4bf">(</span><span style="color:#f99b15">403</span> Forbidden<span style="color:#5bc4bf">)</span>, <span style="color:#5bc4bf">[</span>&lt;em&gt;Stop scanning <span style="color:#815ba4">for</span> PHP: none&lt;/em&gt;!, User-Agent: polaris<span style="color:#5bc4bf">]</span> GET: Invalid argument
</span></span><span style="display:flex;"><span>May <span style="color:#f99b15">17</span> 17:01:19 sh1 relayd<span style="color:#5bc4bf">[</span>45869<span style="color:#5bc4bf">]</span>: relay www, session <span style="color:#f99b15">10</span> <span style="color:#5bc4bf">(</span><span style="color:#f99b15">1</span> active<span style="color:#5bc4bf">)</span>, 0, 207.180.140.98 -&gt; :80, <span style="color:#815ba4">done</span>
</span></span><span style="display:flex;"><span>May <span style="color:#f99b15">17</span> 17:02:43 sh1 relayd<span style="color:#5bc4bf">[</span>7531<span style="color:#5bc4bf">]</span>: relay www, session <span style="color:#f99b15">13</span> <span style="color:#5bc4bf">(</span><span style="color:#f99b15">1</span> active<span style="color:#5bc4bf">)</span>, 0, 84.161.80.36 -&gt; :80, Forbidden <span style="color:#5bc4bf">(</span><span style="color:#f99b15">403</span> Forbidden<span style="color:#5bc4bf">)</span>, <span style="color:#5bc4bf">[</span>&lt;em&gt;Stop scanning <span style="color:#815ba4">for</span> an admin interface: none&lt;/em&gt;!, Host: 88.136.16.221<span style="color:#5bc4bf">]</span> <span style="color:#5bc4bf">[</span>&lt;em&gt;Stop scanning <span style="color:#815ba4">for</span> an admin interface: none&lt;/em&gt;!, User-Agent: Mozilla/5.0 <span style="color:#5bc4bf">(</span>Windows NT 10.0; WOW64<span style="color:#5bc4bf">)</span> AppleWebKit/537.36 <span style="color:#5bc4bf">(</span>KHTML, like Gecko<span style="color:#5bc4bf">)</span> Chrome/51.0.2704.103 Safari/537.36<span style="color:#5bc4bf">]</span> <span style="color:#5bc4bf">[</span>&lt;em&gt;Stop scanning <span style="color:#815ba4">for</span> an admin interface: none&lt;/em&gt;!, 88.136.16.221/phpmyadmin/<span style="color:#5bc4bf">]</span> GET: Invalid argument
</span></span></code></pre></div><p>Into this example, we have:</p>
<ul>
<li>done connections</li>
<li>failed connections, error 403, bloqued by filters rule <code>block</code></li>
</ul>
<h3 id="log-message-example">log message: example</h3>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>$ grep relayd /var/log/messages
</span></span><span style="display:flex;"><span>May <span style="color:#f99b15">17</span> 16:22:23 sh1 relayd<span style="color:#5bc4bf">[</span>7531<span style="color:#5bc4bf">]</span>: relay www, session <span style="color:#f99b15">11</span> <span style="color:#5bc4bf">(</span><span style="color:#f99b15">1</span> active<span style="color:#5bc4bf">)</span>, 0, 37.49.230.25 -&gt; :80, Forbidden <span style="color:#5bc4bf">(</span><span style="color:#f99b15">403</span> Forbidden<span style="color:#5bc4bf">)</span>, <span style="color:#5bc4bf">[</span>&lt;em&gt;Stop scanning <span style="color:#815ba4">for</span> PHP: none&lt;/em&gt;!, User-Agent: Uirusu/2.0<span style="color:#5bc4bf">]</span> GET: Invalid argument
</span></span><span style="display:flex;"><span>May <span style="color:#f99b15">17</span> 17:01:19 sh1 relayd<span style="color:#5bc4bf">[</span>45869<span style="color:#5bc4bf">]</span>: relay www, session <span style="color:#f99b15">9</span> <span style="color:#5bc4bf">(</span><span style="color:#f99b15">1</span> active<span style="color:#5bc4bf">)</span>, 0, 207.180.140.98 -&gt; :80, Forbidden <span style="color:#5bc4bf">(</span><span style="color:#f99b15">403</span> Forbidden<span style="color:#5bc4bf">)</span>, <span style="color:#5bc4bf">[</span>&lt;em&gt;Stop scanning <span style="color:#815ba4">for</span> PHP: none&lt;/em&gt;!, User-Agent: polaris<span style="color:#5bc4bf">]</span> GET: Invalid argument
</span></span><span style="display:flex;"><span>May <span style="color:#f99b15">17</span> 17:02:43 sh1 relayd<span style="color:#5bc4bf">[</span>7531<span style="color:#5bc4bf">]</span>: relay www, session <span style="color:#f99b15">13</span> <span style="color:#5bc4bf">(</span><span style="color:#f99b15">1</span> active<span style="color:#5bc4bf">)</span>, 0, 84.161.80.36 -&gt; :80, Forbidden <span style="color:#5bc4bf">(</span><span style="color:#f99b15">403</span> Forbidden<span style="color:#5bc4bf">)</span>, <span style="color:#5bc4bf">[</span>&lt;em&gt;Stop scanning <span style="color:#815ba4">for</span> an admin interface: none&lt;/em&gt;!, Host: 88.136.16.221<span style="color:#5bc4bf">]</span> <span style="color:#5bc4bf">[</span>&lt;em&gt;Stop scanning <span style="color:#815ba4">for</span> an admin interface: none&lt;/em&gt;!, User-Agent: Mozilla/5.0 <span style="color:#5bc4bf">(</span>Windows NT 10.0; WOW64<span style="color:#5bc4bf">)</span> AppleWebKit/537.36 <span style="color:#5bc4bf">(</span>KHTML, like Gecko<span style="color:#5bc4bf">)</span> Chrome/51.0.2704.103 Safari/537.36<span style="color:#5bc4bf">]</span> <span style="color:#5bc4bf">[</span>&lt;em&gt;Stop scanning <span style="color:#815ba4">for</span> an admin interface: none&lt;/em&gt;!, 88.136.16.221/phpmyadmin/<span style="color:#5bc4bf">]</span> GET: Invalid argument
</span></span></code></pre></div><p>In this other example, we see 3 writing about bloqued rules, with error 403.</p>
<h2 id="documentations">Documentations</h2>
<h3 id="manpages">Manpages</h3>
<ul>
<li>
<a class="man" href="https://man.openbsd.org/relayd.conf.5" title="OpenBSD Manual Page Server for: relayd.conf">relayd.conf(5)</a>
</li>
</ul>
<hr>
]]></content><summary>How to log with relayd, relay server on OpenBSD</summary><published>2020-05-17T13:09:05+02:00</published><updated>2026-10-02T15:49:57+02:00</updated></entry><entry><id>tag:doc.huc.fr.eu.org,2020-05-07:/en/web/httpd/relayd-cache-httpd</id><link href="https://it-log.fr.eu.org/en/web/httpd/relayd-cache-httpd/" rel="alternate" type="text/html"/><title>Relayd: Web caching for httpd</title><author><name>Stéphane HUC</name></author><category term="relayd" scheme="https://it-log.fr.eu.org/en/tags/relayd/"/><category term="Cache" scheme="https://it-log.fr.eu.org/en/tags/cache/"/><category term="httpd" scheme="https://it-log.fr.eu.org/en/tags/httpd/"/><category term="HTTP" scheme="https://it-log.fr.eu.org/en/tags/http/"/><category term="OpenBSD" scheme="https://it-log.fr.eu.org/en/tags/openbsd/"/><content type="html"><![CDATA[<h2 id="description">Description</h2>
<p><strong>OpenBSD</strong> has, by default, in basesystem, since 5.7:</p>
<ul>
<li>
<p>a webserver, named <strong>httpd</strong>,</p>
</li>
<li>
<p>un server relay, named <strong>relayd</strong></p>
</li>
<li>
<p>Website: <a href="https://bsd.plumbing/" rel="external">https://bsd.plumbing/</a></p>
</li>
<li>
<p>OpenBSD: <strong>6.6, 6.7</strong></p>
</li>
</ul>
<hr>
<p><strong>httpd</strong> is not able to manage delivery about cache static content.</p>
<p>So we pass the relay to the <strong>relayd</strong> server which is able to do it; so,
it does in the global manner, not-domain specific.</p>
<h2 id="configuration">Configuration</h2>
<p>We need to modify the <strong>httpd</strong> and <strong>relayd</strong> configuration, i.e.:</p>
<ul>
<li><strong>relayd</strong> will receive all traffic on web port and redirects to localhost
on corresponding ports. Off course, il possible to act on both IPv4
and IPv6 protocols.</li>
<li><strong>httpd</strong> will query only the localhost on the dedicated ports.</li>
</ul>
<p>Do not forget to restart both daemons after modyfing the configuration.</p>
<h3 id="relayd">relayd</h3>
<ul>
<li>File configuration is: <code>/etc/relayd.conf</code></li>
</ul>
<p>In the contexte of the <code>http</code> protocol:</p>
<ul>
<li>We target all static files, by scanning all web requests:
<ul>
<li>for the image GIF, JPEG, PNG, SVG</li>
<li>for the CSS and JS files</li>
<li>and others HTML and XML files (as Atom, RSS, Sitemap, etc.)</li>
</ul>
</li>
<li>we apply a tag policy, with the option <code>tag</code>.</li>
<li>and finally, we send an header <code>Cache-Control</code>, labelled by the tag.</li>
</ul>
<p>Next, we apply the http protocol to a target relay.</p>
<h4 id="relayd-example">relayd: example</h4>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">ip4</span> <span style="color:#5bc4bf">=</span> <span style="color:#48b685">&#34;public-address-ipv4&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">http protocol &#34;hw&#34; {</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">match request path &#34;/*.atom&#34; tag &#34;CACHE&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">match request path &#34;/*.css&#34;  tag &#34;CACHE&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">match request path &#34;/*.gif&#34;  tag &#34;CACHE&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">match request path &#34;/*.html&#34; tag &#34;CACHE&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">match request path &#34;/*.ico&#34;  tag &#34;CACHE&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">match request path &#34;/*.jpg&#34;  tag &#34;CACHE&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">match request path &#34;/*.js&#34;   tag &#34;CACHE&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">match request path &#34;/*.png&#34;  tag &#34;CACHE&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">match request path &#34;/*.rss&#34;  tag &#34;CACHE&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">match request path &#34;/*.svg&#34;  tag &#34;CACHE&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">match request path &#34;/*.xml&#34;  tag &#34;CACHE&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">match response tagged &#34;CACHE&#34; header set &#34;Cache-Control&#34; value &#34;public, max-age</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">86400&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">tcp { nodelay, sack, socket buffer 65536, backlog 100 }</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">pass</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">relay &#34;www&#34; {</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">listen on $ip4 port 80</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">protocol hw</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">forward to 127.0.0.1 port 80</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">}</span>
</span></span></code></pre></div><h2 id="documentations">Documentations</h2>
<h3 id="manpages">Manpages</h3>
<ul>
<li>
<a class="man" href="https://man.openbsd.org/httpd.8" title="OpenBSD Manual Page Server for: httpd">httpd(8)</a>
, 
<a class="man" href="https://man.openbsd.org/httpd.conf.5" title="OpenBSD Manual Page Server for: httpd.conf">httpd.conf(5)</a>
</li>
</ul>
<hr>
]]></content><summary>How to caching static content with httpd & relayd, natives servers on OpenBSD</summary><published>2020-05-07T16:49:36+02:00</published><updated>2026-10-02T15:49:57+02:00</updated></entry><entry><id>tag:doc.huc.fr.eu.org,2020-05-06:/en/web/httpd/relayd-headers-httpd</id><link href="https://it-log.fr.eu.org/en/web/httpd/relayd-headers-httpd/" rel="alternate" type="text/html"/><title>Relayd: Manage HTTP headers</title><author><name>Stéphane HUC</name></author><category term="relayd" scheme="https://it-log.fr.eu.org/en/tags/relayd/"/><category term="Header" scheme="https://it-log.fr.eu.org/en/tags/header/"/><category term="httpd" scheme="https://it-log.fr.eu.org/en/tags/httpd/"/><category term="HTTP" scheme="https://it-log.fr.eu.org/en/tags/http/"/><category term="OpenBSD" scheme="https://it-log.fr.eu.org/en/tags/openbsd/"/><content type="html"><![CDATA[<h2 id="description">Description</h2>
<p><strong>OpenBSD</strong> has, by default, in basesystem, since 5.7:</p>
<ul>
<li>
<p>a webserver, named <strong>httpd</strong>,</p>
</li>
<li>
<p>un server relay, named <strong>relayd</strong></p>
</li>
<li>
<p>Webiste: <a href="https://bsd.plumbing/" rel="external">https://bsd.plumbing/</a></p>
</li>
<li>
<p>OpenBSD: <strong>6.6, 6.7</strong></p>
</li>
</ul>
<hr>
<p><strong>httpd</strong> is not able to manage HTTP headers; and <a href="https://marc.info/?l=openbsd-misc&amp;m=142407262812306&amp;w=2" rel="external">the author do not want it</a>!</p>
<p>So we pass the relay to the <strong>relayd</strong> server which is able to do it; so,
it does in the global manner, not-domain specific.</p>
<h2 id="configuration">Configuration</h2>
<p>We need to modify the <strong>httpd</strong> and <strong>relayd</strong> configuration, i.e.:</p>
<ul>
<li><strong>relayd</strong> will receive all traffic on web port and redirects to localhost
on corresponding ports. Off course, il possible to act on both IPv4
and IPv6 protocols.</li>
<li><strong>httpd</strong> will query only the localhost on the dedicated ports.</li>
</ul>
<p>Do not forget to restart both daemons after modyfing the configuration.</p>
<h3 id="httpd">httpd</h3>
<ul>
<li>File configuration is: <code>/etc/httpd.conf</code></li>
</ul>
<p>Into the context <code>server</code>, we need to set 3 importants details:</p>
<ul>
<li><code>listen on</code>: the listener on the localhost — <em>cf : <a href="https://man.openbsd.org/httpd.conf#listen" rel="external">listen on</a></em></li>
<li><code>log</code>: the logger; you need to modify the option <code>style</code> to <code>forwarder</code>
paramater — <em>cf : <a href="https://man.openbsd.org/httpd.conf#style" rel="external">style</a></em></li>
</ul>

<div class="tab-info i-info">Info</div><div class="alert alert-info" role="alert">Someone wrote a redirection to port 8080, instead of 80. It&rsquo;s up to you!</div>

<p>Only, the <abbr title="HTTP Strict Transport Security">HSTS</abbr>
 header is managed
differently:</p>
<h4 id="httpd-hsts">httpd: HSTS</h4>
<p>We can modify the <strong>HSTS</strong> header by using simply the option <code>hsts</code> <em>(cf : <a href="https://man.openbsd.org/httpd.conf#hsts" rel="external">hsts</a>)</em>.</p>
<p>It is managed, of course, in the context of the
<abbr title="HyperText Transport Protocol Secure">HTTPS</abbr>
 protocol, via
<abbr title="Transport Layer Secure">TLS</abbr>
.</p>
<h4 id="httpd-example">httpd: example</h4>
<pre tabindex="0"><code class="language-httpd" data-lang="httpd">server &#34;domain.tld&#34; {

    listen on 127.0.0.1 port 80
    listen on ::1 port 80

    # enable hsts only if you use TLS for HTTPS
    hsts {
        max-age 63072000
        preload
        subdomains
    }

    location &#34;/.well-known/acme-challenge/*&#34; {
        root &#34;/acme&#34;
        request strip 2
    }

    location &#34;/&#34; {
        directory index index.html
    }

    log {
        access &#34;domain.tld/access.log&#34;
        error  &#34;domain.tld/errors.log&#34;
        style forwarded
    }

    root &#34;/htdocs/domain.tld/www&#34;
}
</code></pre><h4 id="httpd-log">httpd: log</h4>
<p>Here is a log example:</p>
<pre tabindex="0"><code class="language-log" data-lang="log">domain.tld 127.0.0.1 - - [06/May/2020:04:08:51 +0200] &#34;GET / HTTP/1.1&#34; 200 0 &#34;&#34; &#34;Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)&#34; 66.249.79.202 -
domain.tld 127.0.0.1 - - [06/May/2020:09:48:36 +0200] &#34;GET /robots.txt HTTP/1.1&#34; 200 0 &#34;&#34; &#34;Mozilla/5.0 (compatible; AhrefsBot/6.1; +http://ahrefs.com/robot/)&#34; 5.196.87.174 -
domain.tld 127.0.0.1 - - [06/May/2020:10:29:29 +0200] &#34;GET / HTTP/1.1&#34; 200 0 &#34;&#34; &#34;Mozilla/5.0 (compatible; AhrefsBot/6.1; +http://ahrefs.com/robot/)&#34; 54.36.148.31 -
</code></pre><p>We remark that address IP of the client is specified on the end of the line.<br>
It&rsquo;s due to the parameter <code>forwarder</code>.</p>
<h3 id="relayd">relayd</h3>
<ul>
<li>File configuration is: <code>/etc/relayd.conf</code></li>
</ul>
<p>In the facts:</p>
<ul>
<li>We declare a <strong>http</strong> protocol</li>
<li>the matching filters <code>match</code> to create the responses <code>header</code>s.
<ul>
<li>both first values are needed to capture and redirect correctly:
<ul>
<li><code>$SERVER_ADDR:$SERVER_PORT</code> for <code>X-Forwarded-By</code> parameter,</li>
<li><code>$REMOTE_ADDR</code> for <code>X-Forwarded-For</code> parameter.</li>
</ul>
</li>
</ul>
</li>
<li>next, we relay by setting the matching <code>relay</code> :
<ul>
<li><code>listen</code>: the listener on the public address IP and the web port,</li>
<li>when we target the <strong>http</strong> protocol to apply the rules on the headers</li>
<li><code>forward</code>: to redirect to the localhost, and the choosed port, matching
to the one the <strong>httpd</strong> server listen on.</li>
</ul>
</li>
</ul>
<h4 id="relayd-httpoxy">relayd: Httpoxy</h4>
<p>Someone, more attentives, have seen the follow declaration:<br>
<code>match request header remove &quot;Proxy&quot;</code></p>
<p>This is usefull to mitigate the <strong><a href="https://httpoxy.org/" rel="external">Httpoxy</a></strong> vulnerability that affect
CGI, PHP applications.</p>
<p>It is recognized as the best way to block this.<br>
Another way to protect you is to use <abbr title="HyperText Transfert Protocol Secure">HTTPS</abbr>
.</p>
<h4 id="relayd-example">relayd: example</h4>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">ip4</span> <span style="color:#5bc4bf">=</span> <span style="color:#48b685">&#34;ipv4_public_address&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6</span> <span style="color:#5bc4bf">=</span> <span style="color:#48b685">&#34;ipv6_public_address&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">http protocol &#34;hw&#34; {</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">match request header set &#34;X-Forwarded-By&#34;   value &#34;$SERVER_ADDR:$SERVER_PORT&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">match request header set &#34;X-Forwarded-For&#34;  value &#34;$REMOTE_ADDR&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">match request header remove &#34;Proxy&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">match response header set &#34;Cache-Control&#34;           value &#34;max-age</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">1814400&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#48b685">    match response header set &#34;Content-Security-Policy&#34; value &#34;upgrade-insecure-requests; default-src https: &#39;self&#39;&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#48b685">    match response header set &#34;Permissions-Policy&#34;      value &#34;fullscreen=(), geolocation=(), microphone()&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#48b685">    match response header set &#34;Frame-Options&#34;           value &#34;SAMEORIGIN&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#48b685">    match response header set &#34;Referrer-Policy&#34;         value &#34;strict-origin&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#48b685">    match response header set &#34;Server&#34;                  value &#34;OpenBSD Relayd+httpd&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">match response header set &#34;X-Content-Type-Options&#34; value &#34;nosniff&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">match response header set &#34;X-Download-Options&#34;     value &#34;noopen&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">match response header set &#34;X-Frame-Options&#34;        value &#34;SAMEORIGIN&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">match response header set &#34;X-Powered-By&#34;           value &#34;!&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">match response header set &#34;X-Robots-Tag&#34;           value &#34;index, nofollow&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">match response header set &#34;X-Xss-Protection&#34;       value &#34;1; mode</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">block&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">tcp { nodelay, sack, socket buffer 65536, backlog 100 }</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">pass</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">relay &#34;www&#34; {</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">listen on $ip4 port 80</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">protocol hw</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">forward to 127.0.0.1 port 80</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">relay &#34;www6&#34; {</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">listen on $ip6 port 80</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">protocol hw</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">forward to ::1 port 80</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">}</span>
</span></span></code></pre></div><h2 id="documentations">Documentations</h2>
<h3 id="manpages">Manpages</h3>
<ul>
<li>
<a class="man" href="https://man.openbsd.org/httpd.8" title="OpenBSD Manual Page Server for: httpd">httpd(8)</a>
, 
<a class="man" href="https://man.openbsd.org/httpd.conf.5" title="OpenBSD Manual Page Server for: httpd.conf">httpd.conf(5)</a>
</li>
<li>
<a class="man" href="https://man.openbsd.org/relayd.8" title="OpenBSD Manual Page Server for: relayd">relayd(8)</a>
, 
<a class="man" href="https://man.openbsd.org/relayd.conf.5" title="OpenBSD Manual Page Server for: relayd.conf">relayd.conf(5)</a>
, 
<a class="man" href="https://man.openbsd.org/relayctl.8" title="OpenBSD Manual Page Server for: relayctl">relayctl(8)</a>
</li>
</ul>
<h3 id="autres-documentations">Autres documentations</h3>
<ul>
<li><del>Here a <a href="https://www.alexander-pluhar.de/openbsd-webserver.html" rel="external">very complete example</a>, with TLS.</del></li>
</ul>
<hr>
]]></content><summary>How to manage HTTP headers with both natives servers: httpd & relayd on OpenBSD</summary><published>2020-05-06T15:00:23+02:00</published><updated>2020-05-07T18:20:36+02:00</updated></entry><entry><id>tag:doc.huc.fr.eu.org,2020-04-27:/en/sys/debian/devuan_opensmtpd-client-auth</id><link href="https://it-log.fr.eu.org/en/sys/debian/devuan_opensmtpd-client-auth/" rel="alternate" type="text/html"/><title>Devuan: Opensmtpd Client Auth</title><author><name>Stéphane HUC</name></author><category term="Debian" scheme="https://it-log.fr.eu.org/en/tags/debian/"/><category term="Devuan" scheme="https://it-log.fr.eu.org/en/tags/devuan/"/><category term="Linux Mint" scheme="https://it-log.fr.eu.org/en/tags/linux-mint/"/><category term="OpenSMPTD" scheme="https://it-log.fr.eu.org/en/tags/opensmptd/"/><category term="smtp" scheme="https://it-log.fr.eu.org/en/tags/smtp/"/><category term="client" scheme="https://it-log.fr.eu.org/en/tags/client/"/><category term="mail" scheme="https://it-log.fr.eu.org/en/tags/mail/"/><category term="auth" scheme="https://it-log.fr.eu.org/en/tags/auth/"/><content type="html"><![CDATA[<h2 id="description">Description</h2>
<p><strong>OpenSMTPD</strong> is a free implementation of the SMTP protocol, as defined in <a href="https://www.rfc-editor.org/info/rfc5321" title="RFC Editor: Information on RFC 5321">RFC 5321</a>
, with some additional standard extensions. It allows the machines to exchange mail.</p>
<p><strong>OpenSMTPD</strong> is a part the OpenBSD base system. It was ported to others OSes, as Devuan.</p>
<p>Informations:</p>
<ul>
<li>Website: <a href="https://www.opensmtpd.org" rel="external">https://www.opensmtpd.org</a></li>
</ul>
<hr>
<p><abbr title="Question">Q</abbr>
 : <strong>Why do I use OpenSMTPD?</strong></p>
<p>Because, OpenSMTPD is:</p>
<ul>
<li><strong>easy to <a href="/en/sys/debian/devuan_opensmtpd-client-auth/#configuration">config</a>:</strong> only one file text!</li>
<li>recognized as reliable AND secure.</li>
</ul>
<hr>
<p>Fully functional and tested on:</p>
<ul>
<li>Debian Sid, Devuan Ceres</li>
<li>Linux Mint</li>
</ul>
<h2 id="installation">Installation</h2>
<p><code>apt install opensmtpd</code></p>
<ul>
<li>the file log: <code>/var/log/mail.log</code></li>
</ul>
<h2 id="configuration">Configuration</h2>
<ul>
<li>The file config: <code>/etc/smtpd.conf</code></li>
</ul>
<p>To send a mail by SMTP to a mail service requiring identification, it is necessary to first create a file <code>secrets</code> with the appropriate rights on your system, then we have to configure the file <code>smtpd.conf</code>.</p>
<h3 id="file-secrets">File secrets</h3>
<p>To create the secrets file:</p>
<pre tabindex="0"><code>:$ mkdir -p .config/mail
:$ touch .config/mail/secrets
:$ chmod 0640 .config/mail/secrets
</code></pre><p>Then, it&rsquo;s necessary to write: <br>
<code>identifiant username:password</code> <br>
<span class="red">Do Not Write TEXTUALLY this information</span>
,
replace with:</p>
<ul>
<li><code>identifiant</code>: your choosed id — <em>this will use later on your config file</em>.</li>
<li><code>username</code>: usually, your email.</li>
<li><code>password</code>: the password for your email identification.</li>
</ul>

<div class="tab-info i-warning">Warning</div><div class="alert alert-warning" role="alert"><p>It&rsquo;s possible to (re?)name the secrets file as you want, and put in other place on your system.</p>
<p>It&rsquo;s better put rights <code>0400</code> on this secrets file. <em>Default: <code>0640</code></em>.</p>
<p>Even, it&rsquo;s possible for the service to access at your secrets file, with your personal rights as <code>$USER:$USER</code>, it&rsquo;s better to put the group right <code>opensmtpd</code>.</p>
</div>

<h3 id="file-smtpdconf">File smtpd.conf</h3>
<p>Now, edit the config file <code>/etc/smtpd.conf</code></p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#776e71">#   $OpenBSD: smtpd.conf,v 1.10 2018/05/24 11:40:17 gilles Exp $</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># This is the smtpd server system-wide configuration file.</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># See smtpd.conf(5) for more information.</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">table aliases file:/etc/aliases</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">table secrets file:/home/your-id/.config/mail/secrets</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">queue compression</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># To accept external mail, replace with: listen on all</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">listen on localhost</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">action &#34;local&#34; maildir alias &lt;aliases&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">action &#34;relay&#34; relay host smtp+tls://identifiant@server auth &lt;secrets&gt; mail-from &#34;@your-domain.tld&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># Uncomment the following to accept external mail for domain &#34;example.org&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># match from any for domain &#34;example.org&#34; action &#34;local&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">match for local action &#34;local&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">match from local for any action &#34;relay&#34;</span>
</span></span></code></pre></div><hr>
<p><strong>Explainations</strong></p>
<p>So compared to the original version, we added:</p>
<ul>
<li>the line <code>table secrets</code>: it call the secrets file
— <em>write your custom filename</em>.</li>
<li>the line <code>action relay</code>: to define the necessary action to send emails to the server.
<ul>
<li>NOTE about <code>identifiant@serveur</code>:
<ul>
<li>you have to replace the string <code>identifiant</code> by your created.</li>
<li>and too, to replace the <code>serveur</code> by the name of SMTP server.</li>
</ul>
</li>
<li>the string <code>smtp+tls</code> is the used protocol to connect at the SMTP server. <br>
others protocols are:
<ul>
<li><code>lmtp</code>: to connect on a <abbr title="Local Mail Transfer Protocol">LMTP</abbr>
 session.</li>
<li><code>smtp</code>: to attempt a connection with a STARTTLS session, if possible.</li>
<li><code>smtp+tls</code>: to force the connection on a STARTTLS session.</li>
<li><code>smtp+notls</code>: to use a plain text SMTP session without TLS.</li>
<li><code>smtps</code>: to force the connexion via <abbr title="Transport Layer Secure">TLS</abbr>
 — <em>default port: 465</em></li>
<li>with no specified protocol, the connection will be done on the default port: 25.</li>
</ul>
</li>
<li>the string <code>auth</code>: to specify the secrets table.</li>
<li>the string <code>mail-from</code>: to specify the domain name to use.</li>
<li>the line <code>match … action &quot;relay&quot;</code>: this is the action that will be triggered to send the emails.</li>
</ul>
</li>
</ul>
<h3 id="aliases">aliases</h3>
<p>About aliases system:</p>
<p>It is interesting to manage the alias related to your <code>root</code> account or even that of your main user…</p>
<p>Edit the file <code>/etc/aliases</code>, with rights admin. <br>
At the end of file, modify <code>root</code> with your desired address email. <br>
Do the same for your system user. ;)</p>
<p>And, do not forget to reload the aliases base, with the command <code>newaliases</code>!</p>
<h2 id="utilisation">Utilisation</h2>

<div class="tab-info i-warning">Warning</div><div class="alert alert-warning" role="alert"><p>Before restart the <strong>opensmtpd</strong> service, we need to test the config file: <br>
<code>:# smtpd -n</code></p>
<p>If the result is: <code>configuration OK</code> <br>
that&rsquo;s folk!</p>
<p>Otherwise, re-edit the file, at the line indicated first!</p>
</div>

<p>Now, restart the service: <br>
<code>:# service opensmtpd restart</code></p>
<h3 id="send">Send</h3>
<p>So:</p>
<ul>
<li><code>echo &quot;Test to send email on $(hostname); date: $(date)&quot; | mail -s &quot;Email test&quot; email</code></li>
<li>or, <code>echo &quot;Test to send email on $(hostname); date: $(date)&quot; | mail -s &quot;Email test&quot; root</code></li>
</ul>
<p>For all cases, the log will display messages, as:</p>
<pre tabindex="0"><code class="language-log" data-lang="log">(…)
Apr 27 09:16:47 pc-z smtpd[1718]: 09cca279ca1178e4 smtp connected address=local host=***
Apr 27 09:16:47 pc-z smtpd[1718]: 09cca279ca1178e4 smtp message msgid=85868a25 size=474 nrcpt=1 proto=ESMTP
Apr 27 09:16:47 pc-z smtpd[1718]: 09cca279ca1178e4 smtp envelope evpid=85868a25fcb1569a from=&lt;my-id@***&gt; to=&lt;my-id@***&gt;
Apr 27 09:16:47 pc-z smtpd[1718]: 09cca279ca1178e4 smtp disconnected reason=quit
Apr 27 09:16:51 pc-z smtpd[1718]: 09cca27892fa38ea mta delivery evpid=85868a25fcb1569a from=&lt;my-id@huc.fr.eu.org&gt; to=&lt;email@nom-de-domaine.tld&gt; rcpt=&lt;my-id@***&gt; source=&#34;192.168.47.47&#34; relay=&#34;80.67.160.70 (lautre.net)&#34; delay=4s result=&#34;Ok&#34; stat=&#34;250 2.0.0 Ok: queued as 53C92112839&#34;
Apr 27 09:17:02 pc-z smtpd[1718]: 09cca27892fa38ea mta disconnected reason=quit messages=2
(…)
</code></pre><p>Now, you can send email from console/terminal or yours scripts shell with SMTP authentification!</p>
<h3 id="errors">Errors</h3>
<p>Look the different possible errors on my <a href="/en/sys/openbsd/smtpd-config-auth/">article</a></p>
<h2 id="documentations">Documentations</h2>
<p>The SMTP protocol defined by RFC 5321:</p>

<h3 id="rfc-5321">RFC 5321</h3>
<dl class="rfc">
	<dt>IETF Tools</dt>
	<dd>
		<a href="https://tools.ietf.org/html/rfc5321" title="RFC 5321: HTML format">HTML</a>,
		<a href="https://tools.ietf.org/pdf/rfc5321" title="RFC 5321: PDF format">PDF</a>,
		<a href="https://tools.ietf.org/rfc/rfc5321.txt" title="RFC 5321: TXT format">TXT</a>
	</dd>
	<dt>RFC Editor</dt>
	<dd>
		<a href="https://www.rfc-editor.org/rfc/rfc5321.html" title="RFC 5321: HTML format">HTML</a>,
		<a href="https://www.rfc-editor.org/rfc/pdfrfc/rfc5321.txt.pdf" title="RFC 5321: PDF format">PDF</a>,
		<a href="https://www.rfc-editor.org/rfc/rfc5321.txt" title="RFC 5321: TXT format">TXT</a>
	</dd>
</dl>

<h3 id="manpages">Manpages</h3>
<ul>
<li>
<a class="man" href="https://man.openbsd.org/smtpd.conf.5" title="OpenBSD Manual Page Server for: smtpd.conf">smtpd.conf(5)</a>
</li>
</ul>
<h3 id="wikipedia">Wikipedia</h3>
<ul>
<li><a href="https://en.wikipedia.org/wiki/Local_Mail_Transfer_Protocol" title="Wikipedia Article: Local_Mail_Transfer_Protocol">
    Local_Mail_Transfer_Protocol
    <sup><abbr class="is-italic" title="Wikipedia">WP</abbr></sup>
</a>
</li>
</ul>
<hr>
]]></content><summary>Howto Install OpenSMTPD on Devuan, and config as client with auth SMTP</summary><published>2020-04-27T09:19:56+02:00</published><updated>2026-10-02T15:49:57+02:00</updated></entry><entry><id>tag:doc.huc.fr.eu.org,2020-04-25:/en/sys/debian/devuan_openntpd</id><link href="https://it-log.fr.eu.org/en/sys/debian/devuan_openntpd/" rel="alternate" type="text/html"/><title>Devuan: use the OpenNTPD time synchronization client</title><author><name>Stéphane HUC</name></author><category term="Devuan" scheme="https://it-log.fr.eu.org/en/tags/devuan/"/><category term="OpenNTPD" scheme="https://it-log.fr.eu.org/en/tags/openntpd/"/><category term="ntp" scheme="https://it-log.fr.eu.org/en/tags/ntp/"/><category term="client" scheme="https://it-log.fr.eu.org/en/tags/client/"/><category term="temps" scheme="https://it-log.fr.eu.org/en/tags/temps/"/><content type="html"><![CDATA[<h2 id="description">Description</h2>
<p><strong>OpenNTPD</strong> is a service that can be used to synchronize the system clock to the time servers using the 


































































<span lang="en">NTP <em>(Network Time Protocol)</em></span>












































.</p>
<p><strong>OpenNTPD</strong> is a part the OpenBSD base system. It was ported to others OSes, as Devuan.</p>
<h2 id="installation">Installation</h2>
<p>With the <code>apt</code> tool: <code>apt install openntpd</code></p>
<h2 id="configuration">Configuration</h2>
<ul>
<li>The file config is: <code>/etc/opennptd/ntpd.conf</code></li>
</ul>
<p>By default, it runs without no needed modification.</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#776e71"># $OpenBSD: ntpd.conf,v 1.14 2015/07/15 20:28:37 ajacoutot Exp $</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># sample ntpd configuration file, see ntpd.conf(5)</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># Addresses to listen on (ntpd does not listen by default)</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#listen on *</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#listen on 127.0.0.1</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#listen on ::1</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># sync to a single server</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#server ntp.example.org</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># use a random selection of NTP Pool Time Servers</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># see http://support.ntp.org/bin/view/Servers/NTPPoolServers</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#servers pool.ntp.org</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># Choose servers announced from Debian NTP Pool</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">servers 0.debian.pool.ntp.org</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">servers 1.debian.pool.ntp.org</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">servers 2.debian.pool.ntp.org</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">servers 3.debian.pool.ntp.org</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># use a specific local timedelta sensor (radio clock, etc)</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#sensor nmea0</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># use all detected timedelta sensors</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#sensor *</span>
</span></span></code></pre></div><p><strong>Explanations</strong></p>
<p>About options:</p>
<ul>
<li><code>server</code>: to target on time server, in particular.</li>
<li><code>servers</code>: to targer a pool of time servers - <em>prefer this</em></li>
<li><code>sensor</code>: to use local timedelta sensor</li>
</ul>
<h2 id="utilisation">Utilisation</h2>
<h3 id="checks">Checks</h3>
<p>To check the file config, use the option <code>-n</code>, as-is:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:# openntpd -n
</span></span><span style="display:flex;"><span>configuration OK
</span></span></code></pre></div><p>If not good, you need to review the file config.</p>
<hr>
<p><code>ntpctl</code> is the tool to control the time informations.</p>
<ul>
<li>the option <code>-s all</code> - or <code>-sa</code> - is to display availables informations.</li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:# ntpctl -sa
</span></span><span style="display:flex;"><span>4/4 peers valid, clock unsynced, clock offset is -552.476ms
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>peer
</span></span><span style="display:flex;"><span>   wt tl st  next  poll          offset       delay      jitter
</span></span><span style="display:flex;"><span>82.64.42.185 from pool 0.debian.pool.ntp.org
</span></span><span style="display:flex;"><span>    <span style="color:#f99b15">1</span> <span style="color:#f99b15">10</span>  <span style="color:#f99b15">2</span>    6s   32s         0.203ms    60.784ms    31.533ms
</span></span><span style="display:flex;"><span>194.177.34.116 from pool 0.debian.pool.ntp.org
</span></span><span style="display:flex;"><span>    <span style="color:#f99b15">1</span> <span style="color:#f99b15">10</span>  <span style="color:#f99b15">3</span>    9s   32s         2.000ms    54.595ms    17.411ms
</span></span><span style="display:flex;"><span>212.129.10.70 from pool 0.debian.pool.ntp.org
</span></span><span style="display:flex;"><span>    <span style="color:#f99b15">1</span> <span style="color:#f99b15">10</span>  <span style="color:#f99b15">2</span>    9s   33s         5.552ms    51.518ms     4.078ms
</span></span><span style="display:flex;"><span>162.159.200.1 from pool 0.debian.pool.ntp.org
</span></span><span style="display:flex;"><span>    <span style="color:#f99b15">1</span> <span style="color:#f99b15">10</span>  <span style="color:#f99b15">3</span>    7s   33s        -0.176ms    55.383ms    17.593ms
</span></span></code></pre></div>
<div class="tab-info i-info">Info</div><div class="alert alert-info" role="alert">To known all usefull options, please see the manpage <a href="/en/sys/debian/devuan_openntpd/#manpages">ntpctl</a>.</div>

<h3 id="service">Service</h3>
<p>The service name is <strong>openntpd</strong>, to manage with the <code>service</code>.</p>
<p><code>service openntpd command</code></p>
<ul>
<li><code>command</code> is one of possibles actions on a service, as <code>start</code>, <code>stop</code>, <code>restart</code>.</li>
</ul>
<h2 id="troubleshooting">Troubleshooting</h2>
<p>It can happen at startup that there is a time lag. Using the option <code>-s</code> solve:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:# openntpd -s -d
</span></span><span style="display:flex;"><span>adjtimex returns frequency of 0.000000ppm
</span></span><span style="display:flex;"><span>/var/lib/openntpd/db/ntpd.drift is empty
</span></span><span style="display:flex;"><span>ntp engine ready
</span></span><span style="display:flex;"><span>reply from 212.83.179.156: offset -522.890034 delay 0.054365, next query 7s
</span></span><span style="display:flex;"><span>set local clock to Sat Apr <span style="color:#f99b15">25</span> 12:09:03 CEST <span style="color:#f99b15">2020</span> <span style="color:#5bc4bf">(</span>offset -522.890034s<span style="color:#5bc4bf">)</span>
</span></span><span style="display:flex;"><span>reply from 5.135.3.88: negative delay -522.825725s, next query 3203s
</span></span><span style="display:flex;"><span>reply from 46.105.237.136: negative delay -522.823915s, next query 3197s
</span></span><span style="display:flex;"><span>reply from 185.21.216.198: negative delay -522.821620s, next query 3012s
</span></span><span style="display:flex;"><span>reply from 51.15.175.180: negative delay -522.821769s, next query 3010s
</span></span><span style="display:flex;"><span>reply from 37.187.104.44: negative delay -522.820949s, next query 3031s
</span></span><span style="display:flex;"><span>reply from 46.235.141.130: negative delay -522.816360s, next query 3274s
</span></span><span style="display:flex;"><span>reply from 162.159.200.1: negative delay -522.816819s, next query 3030s
</span></span><span style="display:flex;"><span>reply from 5.39.60.244: negative delay -522.816297s, next query 3254s
</span></span><span style="display:flex;"><span>reply from 95.81.173.155: negative delay -522.812132s, next query 3176s
</span></span><span style="display:flex;"><span>reply from 51.15.191.239: negative delay -522.810759s, next query 3017s
</span></span><span style="display:flex;"><span>reply from 5.39.60.244: negative delay -522.809750s, next query 3082s
</span></span><span style="display:flex;"><span>reply from 51.158.147.92: negative delay -522.805041s, next query 3250s
</span></span><span style="display:flex;"><span>reply from 212.85.158.10: negative delay -522.800165s, next query 3041s
</span></span><span style="display:flex;"><span>reply from 88.212.196.95: negative delay -522.784156s, next query 3179s
</span></span><span style="display:flex;"><span>reply from 156.38.0.219: negative delay -522.657588s, next query 3023s
</span></span><span style="display:flex;"><span>reply from 212.83.179.156: offset -0.004612 delay 0.049539, next query 7s
</span></span><span style="display:flex;"><span>reply from 212.83.179.156: offset -0.007646 delay 0.049241, next query 9s
</span></span><span style="display:flex;"><span>peer 212.83.179.156 now valid
</span></span></code></pre></div><h3 id="constraint">Constraint</h3>
<p>It seems the constraint option is not available!</p>

<div class="tab-info i-info">Info</div><div class="alert alert-info" role="alert"><p>This option <code>constraint</code> ensures that time queries are made on the protocol</p>
<p><span lang="en">HTTPS <em>(HyperText Transfer Protocol Secure)</em></span></p>
<p>, via</p>
<p><span lang="en">TLS <em>(Transport Layer Secure)</em></span></p>
<p>.</p>
</div>

<h3 id="peer-not-valid">peer not valid</h3>
<p>You have this message:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>   wt tl st  next  poll          offset       delay      jitter
</span></span><span style="display:flex;"><span>95.81.173.8 from pool 0.debian.pool.ntp.org
</span></span><span style="display:flex;"><span>    <span style="color:#f99b15">1</span>  <span style="color:#f99b15">4</span>  <span style="color:#f99b15">2</span>    8s    9s             ---- peer not valid ----
</span></span></code></pre></div><p>Wait a little for the ntp queries to be returned. <br>
Normally at the next query, this should no longer be the case.</p>
<p>Otherwise, check that the NTP servers registered in the file config are well written, reachable and functional.</p>
<h2 id="documentation">Documentation</h2>
<p>The NTP protocol is defined in:</p>
<ul>
<li>version <strong>3</strong> by <a href="/en/sys/debian/devuan_openntpd/#rfc-1305">RFC 1305</a></li>
<li>version <strong>4</strong> by <a href="/en/sys/debian/devuan_openntpd/#rfc-5905">RFC 5905</a></li>
</ul>
<p>
<h3 id="rfc-1305">RFC 1305</h3>
<dl class="rfc">
	<dt>IETF Tools</dt>
	<dd>
		<a href="https://tools.ietf.org/html/rfc1305" title="RFC 1305: HTML format">HTML</a>,
		<a href="https://tools.ietf.org/pdf/rfc1305" title="RFC 1305: PDF format">PDF</a>,
		<a href="https://tools.ietf.org/rfc/rfc1305.txt" title="RFC 1305: TXT format">TXT</a>
	</dd>
	<dt>RFC Editor</dt>
	<dd>
		<a href="https://www.rfc-editor.org/rfc/rfc1305.html" title="RFC 1305: HTML format">HTML</a>,
		<a href="https://www.rfc-editor.org/rfc/pdfrfc/rfc1305.txt.pdf" title="RFC 1305: PDF format">PDF</a>,
		<a href="https://www.rfc-editor.org/rfc/rfc1305.txt" title="RFC 1305: TXT format">TXT</a>
	</dd>
</dl>


<h3 id="rfc-5905">RFC 5905</h3>
<dl class="rfc">
	<dt>IETF Tools</dt>
	<dd>
		<a href="https://tools.ietf.org/html/rfc5905" title="RFC 5905: HTML format">HTML</a>,
		<a href="https://tools.ietf.org/pdf/rfc5905" title="RFC 5905: PDF format">PDF</a>,
		<a href="https://tools.ietf.org/rfc/rfc5905.txt" title="RFC 5905: TXT format">TXT</a>
	</dd>
	<dt>RFC Editor</dt>
	<dd>
		<a href="https://www.rfc-editor.org/rfc/rfc5905.html" title="RFC 5905: HTML format">HTML</a>,
		<a href="https://www.rfc-editor.org/rfc/pdfrfc/rfc5905.txt.pdf" title="RFC 5905: PDF format">PDF</a>,
		<a href="https://www.rfc-editor.org/rfc/rfc5905.txt" title="RFC 5905: TXT format">TXT</a>
	</dd>
</dl>
</p>
<h3 id="manpages">Manpages</h3>
<p>Please, read the manpages:</p>
<ul>
<li>
<a class="man" href="https://man.openbsd.org/ntpd.8" title="OpenBSD Manual Page Server for: ntpd">ntpd(8)</a>
, 
<a class="man" href="https://man.openbsd.org/ntpd.conf.5" title="OpenBSD Manual Page Server for: ntpd.conf">ntpd.conf(5)</a>
, 
<a class="man" href="https://man.openbsd.org/ntpctl.8" title="OpenBSD Manual Page Server for: ntpctl">ntpctl(8)</a>
</li>
</ul>
<hr>
]]></content><summary>To use on Devuan the OpenNTPD time synchronization client</summary><published>2020-04-25T12:17:36+02:00</published><updated>2026-10-02T15:49:57+02:00</updated></entry><entry><id>tag:doc.huc.fr.eu.org,2020-04-14:/en/web/hugo/hugo-opensearch</id><link href="https://it-log.fr.eu.org/en/web/hugo/hugo-opensearch/" rel="alternate" type="text/html"/><title>Hugo: Opensearch</title><author><name>Stéphane HUC</name></author><category term="Hugo" scheme="https://it-log.fr.eu.org/en/tags/hugo/"/><category term="Opensearch" scheme="https://it-log.fr.eu.org/en/tags/opensearch/"/><category term="search" scheme="https://it-log.fr.eu.org/en/tags/search/"/><content type="html"><![CDATA[<h2 id="description">Description</h2>
<p><strong>Opensearch</strong> is a collection of simple formats for the sharing of search results on your website.</p>
<p>Most browsers web will offer you to add your site as a search engine, you need to manage the <a href="/en/web/hugo/hugo-opensearch/#autodiscovery">autodiscovery</a>.</p>
<p><strong>Hugo</strong>, by default, not manage Opensearch. We are going to modify the <a href="/en/web/hugo/hugo-opensearch/#configuration">configuration</a> to create a new custom output format.</p>
<h2 id="documentation">Documentation</h2>
<p>the Hugo official documentation:</p>
<ul>
<li><a href="https://gohugo.io/templates/output-formats/" title="Link to the official site Hugo: Templates &gt; Output formats">Hugo Documentation: Templates &gt; Output formats</a>
</li>
</ul>
<p>the Opensearch official documentation:</p>
<ul>
<li><a href="https://github.com/dewitt/opensearch/blob/master/opensearch-1-1-draft-6.md" rel="external">https://github.com/dewitt/opensearch/blob/master/opensearch-1-1-draft-6.md</a></li>
</ul>
<h2 id="configuration">Configuration</h2>
<ul>
<li>the main config file: <code>config.toml</code></li>
</ul>
<p>It&rsquo;s necessary to modify this file config to create a new:</p>
<ul>
<li><a href="/en/web/hugo/hugo-opensearch/#mediatype">Media Type</a> <a href="/en/web/hugo/hugo-opensearch/#" title="Go to the anchor: "></a>
</li>
<li><a href="/en/web/hugo/hugo-opensearch/#ouputformat">Output Format</a></li>
<li><a href="/en/web/hugo/hugo-opensearch/#template">Template</a> for the Opensearch file.</li>
</ul>
<h3 id="mediatype">MediaType</h3>
<p>The related MimeType to the Opensearch description format is: <code>application/opensearchdescription+xml</code>.</p>
<h4 id="hugo--020">Hugo &gt;= 0.20</h4>
<p>Since Hugo 0.20, you need to add:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-toml" data-lang="toml"><span style="display:flex;"><span>[<span style="color:#06b6ef">mediaTypes</span>]
</span></span><span style="display:flex;"><span>    [<span style="color:#06b6ef">mediaTypes</span>.<span style="color:#48b685">&#34;application/opensearchdescription+xml&#34;</span>]
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">suffix</span> = <span style="color:#48b685">&#34;xml&#34;</span>
</span></span></code></pre></div><p>Here, we added a new type of format for the mime type: <code>application/opensearchdescription+xml</code>, with the extension name: <code>xml</code>.</p>
<h4 id="hugo--044">Hugo &gt;= 0.44</h4>
<p>Since Hugo 0.44, you need to add:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-toml" data-lang="toml"><span style="display:flex;"><span>[<span style="color:#06b6ef">mediaTypes</span>]
</span></span><span style="display:flex;"><span>    [<span style="color:#06b6ef">mediaTypes</span>.<span style="color:#48b685">&#34;application/opensearchdescription+xml&#34;</span>]
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">suffixes</span> = [<span style="color:#48b685">&#34;xml&#34;</span>]
</span></span></code></pre></div>
<div class="tab-info i-tip">Tip</div><div class="alert alert-tip" role="alert">If your old configuration was before the v0.44, you have to transform the variable <code>suffix</code> to <code>suffixes = ['xml']</code> !</div>

<h3 id="ouputformat">OuputFormat</h3>
<p>The output format declaration to add:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-toml" data-lang="toml"><span style="display:flex;"><span>[<span style="color:#06b6ef">outputs</span>]
</span></span><span style="display:flex;"><span>    [<span style="color:#06b6ef">outputFormats</span>.<span style="color:#06b6ef">OpenSearch</span>]
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">baseName</span> = <span style="color:#48b685">&#34;opensearch&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">isHTML</span> = <span style="color:#815ba4">false</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">isPlainText</span> = <span style="color:#815ba4">false</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">mediaType</span> = <span style="color:#48b685">&#34;application/opensearchdescription+xml&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">noUgly</span> = <span style="color:#815ba4">true</span>
</span></span></code></pre></div><p>Next, you need to add <code>&quot;OpenSearch&quot;</code> at your <code>home</code> variable:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-toml" data-lang="toml"><span style="display:flex;"><span>[<span style="color:#06b6ef">outputs</span>]
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">home</span> = [<span style="color:#48b685">&#34;HTML&#34;</span>, <span style="color:#48b685">&#34;OpenSearch&#34;</span>]
</span></span></code></pre></div><h3 id="template">Template</h3>
<p>Simply, create the template as <code>layouts/_default/index.opensearch.xml</code>.</p>
<ul>
<li>If your site is multilingual, the alternates links to the version of
language are generated.</li>
</ul>
<hr>

<div class="tab-info i-info">Info</div><div class="alert alert-info" role="alert">ATTENTION: the presented template manages a multilingual website.</div>

<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span>{{ printf `<span style="color:#776e71">&lt;?xml version=&#34;1.0&#34; encoding=&#34;utf-8&#34; ?&gt;</span>` | safeHTML }}
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">&lt;OpenSearchDescription</span> <span style="color:#06b6ef">xmlns=</span><span style="color:#48b685">&#34;http://a9.com/-/spec/opensearch/1.1/&#34;</span> <span style="color:#06b6ef">xmlns:ie=</span><span style="color:#48b685">&#34;http://schemas.microsoft.com/Search/2008/&#34;</span> <span style="color:#06b6ef">xmlns:moz=</span><span style="color:#48b685">&#34;http://www.mozilla.org/2006/browser/search/&#34;</span><span style="color:#5bc4bf">&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#5bc4bf">&lt;Attribution&gt;</span>© {{ $.Date.Format &#34;2006&#34; | safeHTML }} {{ site.Author.name }}; http://creativecommons.org/publicdomain/zero/1.0/legalcode.{{ site.Language.Lang }}<span style="color:#5bc4bf">&lt;/Attribution&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#5bc4bf">&lt;Contact&gt;</span>{{ site.Author.email | safeHTML }}<span style="color:#5bc4bf">&lt;/Contact&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#5bc4bf">&lt;Description&gt;</span>{{ i18n &#34;opensearchDescription&#34; }}<span style="color:#5bc4bf">&lt;/Description&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#5bc4bf">&lt;Developer&gt;</span>{{ site.Author.name | safeHTML }}<span style="color:#5bc4bf">&lt;/Developer&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#5bc4bf">&lt;InputEncoding&gt;</span>utf-8<span style="color:#5bc4bf">&lt;/InputEncoding&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#5bc4bf">&lt;Image</span> <span style="color:#06b6ef">width=</span><span style="color:#48b685">&#34;64&#34;</span> <span style="color:#06b6ef">height=</span><span style="color:#48b685">&#34;64&#34;</span> <span style="color:#06b6ef">type=</span><span style="color:#48b685">&#34;image/png&#34;</span><span style="color:#5bc4bf">&gt;</span>{{ site.BaseURL }}img/Logo-64px.png<span style="color:#5bc4bf">&lt;/Image&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#5bc4bf">&lt;Image</span> <span style="color:#06b6ef">width=</span><span style="color:#48b685">&#34;16&#34;</span> <span style="color:#06b6ef">height=</span><span style="color:#48b685">&#34;16&#34;</span> <span style="color:#06b6ef">type=</span><span style="color:#48b685">&#34;image/vnd.microsoft.icon&#34;</span><span style="color:#5bc4bf">&gt;</span>{{ site.BaseURL }}img/favicon.ico<span style="color:#5bc4bf">&lt;/Image&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#5bc4bf">&lt;Language&gt;</span>{{ site.LanguageCode }}<span style="color:#5bc4bf">&lt;/Language&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#5bc4bf">&lt;LongName&gt;</span>{{ site.Title }} :: {{ site.Language.Lang }}<span style="color:#5bc4bf">&lt;/LongName&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#5bc4bf">&lt;OutputEncoding&gt;</span>UTF-8<span style="color:#5bc4bf">&lt;/OutputEncoding&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#5bc4bf">&lt;ShortName&gt;</span>Websearch<span style="color:#5bc4bf">&lt;/ShortName&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#5bc4bf">&lt;SyndicationRight&gt;</span>open<span style="color:#5bc4bf">&lt;/SyndicationRight&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#5bc4bf">&lt;ie:PreviewUrl</span> <span style="color:#06b6ef">type=</span><span style="color:#48b685">&#34;text/html&#34;</span> <span style="color:#06b6ef">method=</span><span style="color:#48b685">&#34;GET&#34;</span> <span style="color:#06b6ef">template=</span><span style="color:#48b685">&#34;{{ site.BaseURL }}{{ site.Language.Lang }}/tags/{searchTerms}/&#34;</span><span style="color:#5bc4bf">/&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#5bc4bf">&lt;moz:SearchForm&gt;</span>{{ site.BaseURL }}{{ site.Language.Lang }}/tags/{searchTerms}/<span style="color:#5bc4bf">&lt;/moz:SearchForm&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#5bc4bf">&lt;Url</span> <span style="color:#06b6ef">template=</span><span style="color:#48b685">&#34;{{ site.BaseURL }}{{ site.Language.Lang }}/tags/{searchTerms}/&#34;</span> <span style="color:#06b6ef">type=</span><span style="color:#48b685">&#34;text/html&#34;</span> <span style="color:#5bc4bf">/&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#5bc4bf">&lt;Url</span> <span style="color:#06b6ef">rel=</span><span style="color:#48b685">&#34;self&#34;</span> <span style="color:#06b6ef">template=</span><span style="color:#48b685">&#34;{{ site.BaseURL }}opensearch.xml&#34;</span> <span style="color:#06b6ef">type=</span><span style="color:#48b685">&#34;application/opensearchdescription+xml&#34;</span> <span style="color:#5bc4bf">/&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">&lt;/OpenSearchDescription&gt;</span>
</span></span></code></pre></div><h2 id="autodiscovery">autodiscovery</h2>
<p>The autodiscovery is the method to inform the web clients about the
Opensearch format description in your web site.</p>

<div class="tab-info i-warning">Warning</div><div class="alert alert-warning" role="alert">Make sure that the value of the <code>title</code> attribute matches that of the
<code>ShortName</code> element!</div>

<h3 id="atom">Atom</h3>
<p>If you have modified your Hugo configuration to generate an <a href="/en/web/hugo/hugo-feed/">Atom</a> feed, you will need to modify it to add the following:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-html" data-lang="html"><span style="display:flex;"><span>&lt;<span style="color:#5bc4bf">link</span> <span style="color:#06b6ef">href</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;{{ site.BaseURL }}/opensearch.xml&#34;</span> <span style="color:#06b6ef">rel</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;search&#34;</span> <span style="color:#06b6ef">type</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;application/opensearchdescription+xml&#34;</span> <span style="color:#06b6ef">title</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;Websearch&#34;</span> /&gt;
</span></span></code></pre></div><h3 id="html">HTML</h3>
<p>Add a <code>link</code> element:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-html" data-lang="html"><span style="display:flex;"><span>&lt;<span style="color:#5bc4bf">link</span> <span style="color:#06b6ef">rel</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;search&#34;</span> <span style="color:#06b6ef">href</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;/opensearch.xml&#34;</span> <span style="color:#06b6ef">title</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;Websearch&#34;</span> <span style="color:#06b6ef">type</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;application/opensearchdescription+xml&#34;</span>&gt;
</span></span></code></pre></div><h3 id="rss">RSS</h3>
<p>If you generate your <a href="/en/web/hugo/hugo-feed/">RSS</a> feed, make sure to edit it, to add:</p>
<ul>
<li>the <code>xmlns:atom=&quot;http://www.w3.org/2005/Atom&quot;</code> attribute, into your <code>rss</code> element:</li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-html" data-lang="html"><span style="display:flex;"><span>&lt;<span style="color:#5bc4bf">rss</span> <span style="color:#06b6ef">version</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;2.0&#34;</span> <span style="color:#06b6ef">xmlns:atom</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;http://www.w3.org/2005/Atom&#34;</span>&gt;
</span></span></code></pre></div><ul>
<li>in order to declarate <code>atom:link</code> item, as:</li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-html" data-lang="html"><span style="display:flex;"><span>&lt;<span style="color:#5bc4bf">atom:link</span> <span style="color:#06b6ef">href</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;{{ site.BaseURL }}/opensearch.xml&#34;</span> <span style="color:#06b6ef">rel</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;search&#34;</span> <span style="color:#06b6ef">type</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;application/opensearchdescription+xml&#34;</span> <span style="color:#06b6ef">title</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;Websearch&#34;</span> /&gt;
</span></span></code></pre></div><hr>
<h2 id="acknowledgments">Acknowledgments</h2>
<p>Once again, a thruly thank you @<a href="https://dataswamp.org/~solene/" rel="external">solene</a> who introduced me to Opensearch.</p>
<hr>
]]></content><summary>Howto set up the Opensearch description format into Hugo!</summary><published>2020-04-14T16:54:07+02:00</published><updated>2026-10-02T15:49:57+02:00</updated></entry><entry><id>tag:doc.huc.fr.eu.org,2020-02-26:/en/sys/openwrt/ssh-tunnel</id><link href="https://it-log.fr.eu.org/en/sys/openwrt/ssh-tunnel/" rel="alternate" type="text/html"/><title>OpenWRT: Tunnel SSH for LuCI</title><author><name>Stéphane HUC</name></author><category term="OpenWRT" scheme="https://it-log.fr.eu.org/en/tags/openwrt/"/><category term="SSH" scheme="https://it-log.fr.eu.org/en/tags/ssh/"/><category term="tunnel" scheme="https://it-log.fr.eu.org/en/tags/tunnel/"/><content type="html"><![CDATA[<h2 id="description">Description</h2>
<p>In this article, we explain how to encapsule the LuCI HTTP access by 

























































































<abbr lang="en" title="Secure SHell">SSH</abbr>






















.</p>
<h2 id="configuration">Configuration</h2>
<h3 id="ssh-tunnel">SSH Tunnel</h3>
<p>By default, the LuCI web admin is available only on 































<abbr lang="en" title="HyperText Transfer Protocol">HTTP</abbr>
















































































 protocol, listen all interfaces, and everywhere.</p>
<p>One way to protect is to redirect the web flow to the local interface into an 

























































































<abbr lang="en" title="Secure SHell">SSH</abbr>






















 tunnel.</p>
<p>After your SSH connection at your OpenWRT router:</p>
<ol>
<li>
<p>First, on OpenWRT, you need to reconfigure the <strong>uhttpd</strong> webserver; edit the file configuration <code>/etc/config/uhttpd</code>:</p>
<ul>
<li>
<p>comment the both lines, by adding the <code>#</code> symbol before: <code>list listen_http 0.0.0.0:80</code> and <code>list listen_https   0.0.0.0:443</code></p>
</li>
<li>
<p>add: <code>list listen_http  127.0.0.1:80</code> <em>(and for IPv6: <code>list listen_http [::1]:80</code>)</em></p>
</li>
<li>
<p>restart the web service: <code>/etc/init.d/uhttpd restart</code></p>
</li>
<li>
<p>and, check that the web service only listens to port 80 on the local interface:</p>
</li>
</ul>
</li>
</ol>
<pre tabindex="0"><code>:$ netstat -ant | grep -E &#34;:80&#34;
tcp        0      0 127.0.0.1:80            0.0.0.0:*               LISTEN
tcp        0      0 ::1:80                  :::*                    LISTEN
</code></pre><ol start="2">
<li>Next, the command to redirect on SSH is: <br>
<code>ssh -L 127.0.0.1:8080:127.0.0.1:80 -p 22 id@address-ip</code> <br>
where:
<ul>
<li><code>-p 22</code>: ssh number port</li>
<li><code>id</code>: your id; See: <a href="/en/sys/openwrt/sudo/">sudo</a>.</li>
<li><code>address-ip</code>: IPv4 address, on your LAN, in your OpenWRT router.</li>
</ul>
</li>
</ol>
<p>See this example:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">Host luciweb</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">Ciphers aes256-ctr</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">Hostname 192.168.1.1</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">IdentityFile ~/.ssh/id_rsa</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">LocalForward 127.0.0.1:8080 127.0.0.1:80</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">MACs hmac-sha2-256</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">Port 22</span>
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">User identifiant</span>
</span></span></code></pre></div><p>So, you will only have to execute: <code>$ ssh luciweb</code></p>
<p>And, on your web browser: <code>localhost:8080</code></p>
<p>Voila!</p>
<h3 id="shell">Shell</h3>
<ul>
<li>The file config: <code>/etc/config/dropbear</code></li>
<li>the <strong>dropbear</strong> service: <code>/etc/init.d/dropbear</code>.</li>
</ul>
<h2 id="troubleshooting">Troubleshooting</h2>
<h3 id="error-no-matching-cipher-found-their-offer-aes128-ctraes256-ctr">Error: no matching cipher found. Their offer: aes128-ctr,aes256-ctr</h3>
<p>The <strong>dropbear</strong> SSH server is not able to handle strong encryptions other than those given in the error message. <br>
Add to your SSH client configuration: <code>Ciphers aes256-ctr</code></p>
<h3 id="error-no-matching-host-key-type-found-their-offer-ssh-rsa">Error: no matching host key type found. Their offer: ssh-rsa</h3>
<p>The <strong>dropbear</strong> SSH server is not able to handle host key types other than those given in the error message. <br>
Add to your SSH client configuration: <code>HostKeyAlgorithms ssh-rsa</code></p>
<h3 id="error-no-matching-mac-found-their-offer-hmac-sha1hmac-sha2-256">Error: no matching MAC found. Their offer: hmac-sha1,hmac-sha2-256</h3>
<p>The <strong>dropbear</strong> SSH server is not able to handle 




















































<abbr lang="en" title="Message Authentication Code">MAC</abbr>



























































 other than those given in the error message. <br>
Add to your SSH client configuration: <code>MACs hmac-sha2-256</code></p>
<hr>
]]></content><summary>Howto set OpenWRT to use SSH to connect on the LuCI web admin!</summary><published>2020-02-26T15:44:44+01:00</published><updated>2026-10-02T15:49:57+02:00</updated></entry><entry><id>tag:doc.huc.fr.eu.org,2020-02-24:/en/sys/openwrt/sudo</id><link href="https://it-log.fr.eu.org/en/sys/openwrt/sudo/" rel="alternate" type="text/html"/><title>OpenWRT: sudo</title><author><name>Stéphane HUC</name></author><category term="OpenWRT" scheme="https://it-log.fr.eu.org/en/tags/openwrt/"/><category term="sudo" scheme="https://it-log.fr.eu.org/en/tags/sudo/"/><category term="sysadmin" scheme="https://it-log.fr.eu.org/en/tags/sysadmin/"/><content type="html"><![CDATA[<div class="tab-info i-deprecated"><strong>opkg → apk</strong></div>
<div class="alert alert-deprecated" role="alert"><strong>Since OpenWRT 25.12.0, **apk** *(Alpine Package Keeper)* is the new package manager; the oldier `opkg` is no longer maintened! See the relative page: https://openwrt.org/docs/guide-user/additional-software/opkg-to-apk-cheatsheet to the official transition.</strong></div>

<h2 id="description">Description</h2>
<p>By default, <strong>OpenWRT</strong> has one only user: the <strong>root</strong> admin.</p>
<p>We will create a new user, without privilege, only the one to administrate correctly the system with the tool <code>sudo</code>.</p>
<h2 id="installation">Installation</h2>
<p>As <strong>root</strong>, execute all those commands:</p>
<pre tabindex="0"><code class="language-ash" data-lang="ash"># opkg update
# opkg install shadow-useradd sudo
</code></pre>
<div class="tab-info i-tip">Tip</div><div class="alert alert-tip" role="alert">It&rsquo;s possible to install the <code>shadow-usermod</code> package; this intents to set the user account.</div>

<h2 id="configuration">Configuration</h2>
<h3 id="user-configuration">user configuration</h3>
<p>Now, config the user account:</p>
<ul>
<li><code># useradd ego</code>: <code>ego</code> is the account name - <em>it&rsquo;s up to your convenience…</em></li>
<li><code># passwd ego</code>: define the password</li>
<li><code># mkdir -p /home/ego/.ssh</code>: make the main home, and the ssh folder.</li>
<li><code># touch /home/ego/.ssh/authorized_keys</code>: create empty file <em>(to copy your SSH public keys)</em></li>
<li><code># chown -R ego:ego /home/ego</code>: give the user rights on his home.</li>
<li><code># chmod 0700 /home/ego</code>: auth only this user.</li>
</ul>
<h3 id="sudo-configuration">sudo configuration</h3>
<p>I would only talk about the sudo most secure method of configuration: <br>
This method allows you to simply use the administrator&rsquo;s password without having to login with the administrator account. <br>
The command <code>sudo</code> must be preceded by any other necessary command.</p>
<p>We edit the <code>/etc/sudoers</code> with the <code>visudo</code> command:</p>
<p><code># visudo</code></p>
<p>Place at the bottom of the file, and uncomment the both lignes, to remove the <code>#</code> symbol:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#776e71"># Defaults targetpw  # Ask for the password of the target user</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># ALL ALL=(ALL) ALL  # WARNING: only use this together with &#39;Defaults targetpw&#39;</span>
</span></span></code></pre></div>
<div class="tab-info i-tip">Tip</div><div class="alert alert-tip" role="alert">To save the file, after the modification, type: <code>:wq!</code></div>

<p>After saving and quit, your user can use any administration commands.</p>
<h3 id="ssh-configuration">SSH configuration</h3>
<p>Now, it&rsquo;s the good time to add your ssh auth key into the <code>/home/ego/.ssh/authorized_keys</code> file.</p>

<div class="tab-info i-warning">Warning</div><div class="alert alert-warning" role="alert">Be sure to copy your public key, only with the <code>.pub</code> extension!</div>

<h3 id="sysupgrade-configuration">sysupgrade configuration</h3>
<p>Think to edit the file <code>/etc/sysupgrade.conf</code> to add:</p>
<ul>
<li>your home folder,</li>
<li>and <code>/etc/sudoers.d</code> <em>(only if you add config into this folder)</em></li>
</ul>
<p>and check with the command <code>sysupgrade -l</code>.</p>
<p>So, for the <a href="/en/sys/openwrt/sysupgrade">future upgrade</a>, yours personals datas will be saved.</p>
<hr>
<h2 id="documentation">Documentation</h2>
<ul>
<li><a href="https://openwrt.org/docs/guide-user/security/secure.access#create_a_non-privileged_user_in_openwrt" rel="external">https://openwrt.org/docs/guide-user/security/secure.access#create_a_non-privileged_user_in_openwrt</a></li>
</ul>
<hr>
]]></content><summary>Howto create a non-privileged user, to use sudo temporarily and correctly!</summary><published>2020-02-24T19:41:07+01:00</published><updated>2026-10-02T15:49:57+02:00</updated></entry><entry><id>tag:doc.huc.fr.eu.org,2020-02-24:/en/sys/openwrt/opkg-upgrade</id><link href="https://it-log.fr.eu.org/en/sys/openwrt/opkg-upgrade/" rel="alternate" type="text/html"/><title>OpenWRT : opkg upgrade (tips)</title><author><name>Stéphane HUC</name></author><category term="OpenWRT" scheme="https://it-log.fr.eu.org/en/tags/openwrt/"/><category term="upgrade" scheme="https://it-log.fr.eu.org/en/tags/upgrade/"/><category term="opkg" scheme="https://it-log.fr.eu.org/en/tags/opkg/"/><category term="tips" scheme="https://it-log.fr.eu.org/en/tags/tips/"/><category term="sysadmin" scheme="https://it-log.fr.eu.org/en/tags/sysadmin/"/><content type="html"><![CDATA[<div class="tab-info i-deprecated"><strong>opkg → apk</strong></div>
<div class="alert alert-deprecated" role="alert"><strong>Since OpenWRT 25.12.0, **apk** *(Alpine Package Keeper)* is the new package manager; the oldier `opkg` is no longer maintened! See the relative page: https://openwrt.org/docs/guide-user/additional-software/opkg-to-apk-cheatsheet to the official transition.</strong></div>

<h2 id="description">Description</h2>
<p>OpenWRT has a native tool to manage package: <code>opkg</code>.</p>
<p>But, by default, there are not plan to upgrade easily all packages, even <code>upgrade</code> option exists.</p>
<p>This is the tips:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#776e71"># for name in `opkg list-upgradable | awk &#39;{print $1}&#39;`; do opkg upgrade &#34;${name}&#34;; done</span>
</span></span></code></pre></div><p>Or, if you you have created a user who has the right to use the <code>sudo</code>
command:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>$ <span style="color:#815ba4">for</span> name in <span style="color:#48b685">`</span>sudo opkg list-upgradable | awk <span style="color:#48b685">&#39;{print $1}&#39;</span><span style="color:#48b685">`</span>; <span style="color:#815ba4">do</span> sudo opkg upgrade <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">name</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>; <span style="color:#815ba4">done</span>
</span></span></code></pre></div><hr>
]]></content><summary>howto upgrade packages on OpenWRT with the tool opkg!</summary><published>2020-02-24T19:17:42+01:00</published><updated>2026-10-02T15:49:57+02:00</updated></entry><entry><id>tag:doc.huc.fr.eu.org,2020-02-21:/en/don</id><link href="https://it-log.fr.eu.org/en/don/" rel="alternate" type="text/html"/><title>Donate Page</title><author><name>Stéphane HUC</name></author><category term="Don" scheme="https://it-log.fr.eu.org/en/tags/don/"/><content type="html"><![CDATA[<h2 id="description">Description</h2>
<p>You appreciate my articles for the quality, their seriousness… <br>
you want to make a nice gesture, a donate like the price of a coffee, a beer… <br>
or, just to thank me, to encourage-me ;-) :p</p>
<p>Make a donate. So simply, so easy!</p>
<p><strong>By advance: Thank you!</strong> :D</p>
<p>⇒ If you do, and you desire: your name or nickname/pseudo/alias will be
displayed here, with your agreement, on the date of the donation…</p>
<p>⇒ Please, if you desire to display your informations, said-it me on your
message…</p>
<h2 id="how">How</h2>
<h3 id="ko-fi">Ko-fi</h3>
<ul>
<li><a href="https://ko-fi.com/hucste" rel="external">https://ko-fi.com/hucste</a></li>
</ul>


<figure class="pure-img">
    <a href="/svg/qrcode/ko-fi.svg" title="One Ko-fi for Stéphane HUC">
    <svg xmlns="http://www.w3.org/2000/svg" class="qr-svg " height="128" viewBox="0 0 53 53" width="128">
<defs><style>rect{shape-rendering:crispEdges}</style></defs>
<path class="qr-4 " stroke="transparent" fill="#fff" fill-opacity="1" d="M16 4 h2 v1 h-2Z M19 4 h1 v1 h-1Z M24 4 h1 v1 h-1Z M28 4 h1 v1 h-1Z M30 4 h2 v1 h-2Z M36 4 h1 v1 h-1Z M13 5 h4 v1 h-4Z M20 5 h2 v1 h-2Z M23 5 h1 v1 h-1Z M25 5 h2 v1 h-2Z M29 5 h1 v1 h-1Z M31 5 h4 v1 h-4Z M37 5 h1 v1 h-1Z M14 6 h3 v1 h-3Z M19 6 h1 v1 h-1Z M21 6 h2 v1 h-2Z M24 6 h3 v1 h-3Z M29 6 h4 v1 h-4Z M36 6 h1 v1 h-1Z M13 7 h3 v1 h-3Z M17 7 h3 v1 h-3Z M21 7 h4 v1 h-4Z M26 7 h3 v1 h-3Z M30 7 h1 v1 h-1Z M32 7 h1 v1 h-1Z M35 7 h2 v1 h-2Z M13 8 h1 v1 h-1Z M19 8 h1 v1 h-1Z M21 8 h2 v1 h-2Z M29 8 h5 v1 h-5Z M36 8 h1 v1 h-1Z M14 9 h1 v1 h-1Z M17 9 h4 v1 h-4Z M22 9 h1 v1 h-1Z M29 9 h1 v1 h-1Z M33 9 h1 v1 h-1Z M35 9 h3 v1 h-3Z M14 11 h3 v1 h-3Z M20 11 h4 v1 h-4Z M31 11 h1 v1 h-1Z M34 11 h4 v1 h-4Z M39 11 h1 v1 h-1Z M14 12 h1 v1 h-1Z M17 12 h3 v1 h-3Z M33 12 h2 v1 h-2Z M37 12 h1 v1 h-1Z M39 12 h1 v1 h-1Z M5 13 h3 v1 h-3Z M11 13 h1 v1 h-1Z M13 13 h3 v1 h-3Z M20 13 h4 v1 h-4Z M25 13 h1 v1 h-1Z M30 13 h3 v1 h-3Z M34 13 h2 v1 h-2Z M38 13 h1 v1 h-1Z M40 13 h1 v1 h-1Z M45 13 h1 v1 h-1Z M47 13 h2 v1 h-2Z M4 14 h2 v1 h-2Z M8 14 h2 v1 h-2Z M13 14 h4 v1 h-4Z M18 14 h2 v1 h-2Z M26 14 h2 v1 h-2Z M33 14 h1 v1 h-1Z M39 14 h5 v1 h-5Z M4 15 h2 v1 h-2Z M7 15 h1 v1 h-1Z M12 15 h4 v1 h-4Z M21 15 h2 v1 h-2Z M24 15 h2 v1 h-2Z M28 15 h2 v1 h-2Z M33 15 h1 v1 h-1Z M36 15 h3 v1 h-3Z M40 15 h6 v1 h-6Z M47 15 h1 v1 h-1Z M6 16 h1 v1 h-1Z M8 16 h1 v1 h-1Z M12 16 h1 v1 h-1Z M16 16 h2 v1 h-2Z M22 16 h5 v1 h-5Z M35 16 h4 v1 h-4Z M41 16 h2 v1 h-2Z M44 16 h1 v1 h-1Z M5 17 h4 v1 h-4Z M12 17 h1 v1 h-1Z M17 17 h1 v1 h-1Z M19 17 h2 v1 h-2Z M22 17 h1 v1 h-1Z M25 17 h1 v1 h-1Z M28 17 h1 v1 h-1Z M30 17 h1 v1 h-1Z M32 17 h2 v1 h-2Z M36 17 h4 v1 h-4Z M42 17 h5 v1 h-5Z M48 17 h1 v1 h-1Z M4 18 h1 v1 h-1Z M8 18 h2 v1 h-2Z M12 18 h5 v1 h-5Z M19 18 h2 v1 h-2Z M22 18 h5 v1 h-5Z M28 18 h1 v1 h-1Z M31 18 h1 v1 h-1Z M35 18 h2 v1 h-2Z M44 18 h2 v1 h-2Z M47 18 h2 v1 h-2Z M5 19 h1 v1 h-1Z M8 19 h2 v1 h-2Z M11 19 h1 v1 h-1Z M13 19 h1 v1 h-1Z M16 19 h4 v1 h-4Z M22 19 h3 v1 h-3Z M28 19 h1 v1 h-1Z M34 19 h2 v1 h-2Z M37 19 h1 v1 h-1Z M39 19 h1 v1 h-1Z M44 19 h1 v1 h-1Z M48 19 h1 v1 h-1Z M4 20 h3 v1 h-3Z M11 20 h2 v1 h-2Z M19 20 h3 v1 h-3Z M23 20 h4 v1 h-4Z M30 20 h5 v1 h-5Z M36 20 h1 v1 h-1Z M40 20 h1 v1 h-1Z M42 20 h2 v1 h-2Z M46 20 h3 v1 h-3Z M4 21 h2 v1 h-2Z M8 21 h2 v1 h-2Z M11 21 h2 v1 h-2Z M14 21 h1 v1 h-1Z M16 21 h1 v1 h-1Z M19 21 h1 v1 h-1Z M23 21 h1 v1 h-1Z M27 21 h3 v1 h-3Z M32 21 h1 v1 h-1Z M34 21 h4 v1 h-4Z M41 21 h2 v1 h-2Z M46 21 h2 v1 h-2Z M6 22 h2 v1 h-2Z M9 22 h1 v1 h-1Z M12 22 h1 v1 h-1Z M14 22 h4 v1 h-4Z M20 22 h2 v1 h-2Z M25 22 h2 v1 h-2Z M29 22 h1 v1 h-1Z M33 22 h1 v1 h-1Z M36 22 h1 v1 h-1Z M38 22 h2 v1 h-2Z M41 22 h1 v1 h-1Z M43 22 h1 v1 h-1Z M45 22 h4 v1 h-4Z M4 23 h1 v1 h-1Z M6 23 h2 v1 h-2Z M9 23 h1 v1 h-1Z M11 23 h2 v1 h-2Z M14 23 h1 v1 h-1Z M16 23 h1 v1 h-1Z M20 23 h3 v1 h-3Z M24 23 h4 v1 h-4Z M29 23 h3 v1 h-3Z M33 23 h1 v1 h-1Z M35 23 h1 v1 h-1Z M38 23 h5 v1 h-5Z M48 23 h1 v1 h-1Z M4 24 h2 v1 h-2Z M13 24 h2 v1 h-2Z M18 24 h1 v1 h-1Z M20 24 h1 v1 h-1Z M35 24 h5 v1 h-5Z M45 24 h3 v1 h-3Z M4 25 h4 v1 h-4Z M17 25 h2 v1 h-2Z M20 25 h1 v1 h-1Z M22 25 h1 v1 h-1Z M33 25 h1 v1 h-1Z M38 25 h1 v1 h-1Z M46 25 h2 v1 h-2Z M6 26 h2 v1 h-2Z M14 26 h1 v1 h-1Z M20 26 h1 v1 h-1Z M29 26 h1 v1 h-1Z M37 26 h3 v1 h-3Z M45 26 h2 v1 h-2Z M48 26 h1 v1 h-1Z M5 27 h1 v1 h-1Z M14 27 h9 v1 h-9Z M30 27 h1 v1 h-1Z M33 27 h1 v1 h-1Z M35 27 h3 v1 h-3Z M39 27 h1 v1 h-1Z M46 27 h3 v1 h-3Z M5 28 h1 v1 h-1Z M7 28 h1 v1 h-1Z M13 28 h4 v1 h-4Z M21 28 h1 v1 h-1Z M29 28 h3 v1 h-3Z M39 28 h1 v1 h-1Z M45 28 h1 v1 h-1Z M47 28 h1 v1 h-1Z M8 29 h1 v1 h-1Z M11 29 h1 v1 h-1Z M13 29 h1 v1 h-1Z M16 29 h1 v1 h-1Z M18 29 h3 v1 h-3Z M22 29 h1 v1 h-1Z M26 29 h1 v1 h-1Z M28 29 h8 v1 h-8Z M37 29 h1 v1 h-1Z M42 29 h4 v1 h-4Z M47 29 h2 v1 h-2Z M7 30 h3 v1 h-3Z M13 30 h3 v1 h-3Z M18 30 h3 v1 h-3Z M24 30 h2 v1 h-2Z M27 30 h2 v1 h-2Z M30 30 h3 v1 h-3Z M38 30 h1 v1 h-1Z M41 30 h3 v1 h-3Z M5 31 h2 v1 h-2Z M11 31 h1 v1 h-1Z M13 31 h4 v1 h-4Z M20 31 h1 v1 h-1Z M23 31 h6 v1 h-6Z M30 31 h1 v1 h-1Z M33 31 h2 v1 h-2Z M36 31 h2 v1 h-2Z M39 31 h2 v1 h-2Z M42 31 h2 v1 h-2Z M45 31 h1 v1 h-1Z M47 31 h1 v1 h-1Z M5 32 h1 v1 h-1Z M8 32 h2 v1 h-2Z M12 32 h7 v1 h-7Z M20 32 h1 v1 h-1Z M22 32 h4 v1 h-4Z M27 32 h1 v1 h-1Z M32 32 h1 v1 h-1Z M34 32 h4 v1 h-4Z M43 32 h1 v1 h-1Z M8 33 h2 v1 h-2Z M11 33 h4 v1 h-4Z M16 33 h2 v1 h-2Z M22 33 h2 v1 h-2Z M25 33 h1 v1 h-1Z M27 33 h2 v1 h-2Z M31 33 h4 v1 h-4Z M36 33 h3 v1 h-3Z M40 33 h2 v1 h-2Z M43 33 h2 v1 h-2Z M46 33 h1 v1 h-1Z M48 33 h1 v1 h-1Z M4 34 h2 v1 h-2Z M7 34 h3 v1 h-3Z M12 34 h3 v1 h-3Z M18 34 h2 v1 h-2Z M21 34 h1 v1 h-1Z M23 34 h1 v1 h-1Z M27 34 h1 v1 h-1Z M30 34 h3 v1 h-3Z M35 34 h2 v1 h-2Z M40 34 h1 v1 h-1Z M44 34 h5 v1 h-5Z M4 35 h6 v1 h-6Z M11 35 h1 v1 h-1Z M14 35 h1 v1 h-1Z M16 35 h1 v1 h-1Z M18 35 h2 v1 h-2Z M22 35 h1 v1 h-1Z M24 35 h2 v1 h-2Z M28 35 h1 v1 h-1Z M30 35 h1 v1 h-1Z M32 35 h5 v1 h-5Z M38 35 h2 v1 h-2Z M41 35 h4 v1 h-4Z M46 35 h1 v1 h-1Z M48 35 h1 v1 h-1Z M6 36 h4 v1 h-4Z M12 36 h1 v1 h-1Z M16 36 h2 v1 h-2Z M19 36 h1 v1 h-1Z M21 36 h4 v1 h-4Z M28 36 h4 v1 h-4Z M33 36 h2 v1 h-2Z M37 36 h1 v1 h-1Z M39 36 h7 v1 h-7Z M47 36 h2 v1 h-2Z M5 37 h1 v1 h-1Z M7 37 h1 v1 h-1Z M9 37 h1 v1 h-1Z M11 37 h1 v1 h-1Z M13 37 h1 v1 h-1Z M15 37 h1 v1 h-1Z M19 37 h2 v1 h-2Z M23 37 h2 v1 h-2Z M26 37 h2 v1 h-2Z M29 37 h2 v1 h-2Z M33 37 h1 v1 h-1Z M35 37 h1 v1 h-1Z M37 37 h3 v1 h-3Z M42 37 h1 v1 h-1Z M44 37 h1 v1 h-1Z M47 37 h2 v1 h-2Z M13 38 h1 v1 h-1Z M18 38 h1 v1 h-1Z M20 38 h1 v1 h-1Z M26 38 h1 v1 h-1Z M28 38 h7 v1 h-7Z M37 38 h1 v1 h-1Z M39 38 h1 v1 h-1Z M41 38 h5 v1 h-5Z M11 39 h1 v1 h-1Z M15 39 h1 v1 h-1Z M17 39 h2 v1 h-2Z M22 39 h3 v1 h-3Z M27 39 h4 v1 h-4Z M32 39 h3 v1 h-3Z M38 39 h3 v1 h-3Z M42 39 h1 v1 h-1Z M44 39 h1 v1 h-1Z M47 39 h1 v1 h-1Z M13 40 h1 v1 h-1Z M16 40 h1 v1 h-1Z M19 40 h2 v1 h-2Z M22 40 h1 v1 h-1Z M29 40 h3 v1 h-3Z M34 40 h1 v1 h-1Z M36 40 h3 v1 h-3Z M46 40 h1 v1 h-1Z M13 41 h1 v1 h-1Z M15 41 h2 v1 h-2Z M20 41 h4 v1 h-4Z M29 41 h2 v1 h-2Z M38 41 h2 v1 h-2Z M45 41 h1 v1 h-1Z M47 41 h1 v1 h-1Z M13 42 h1 v1 h-1Z M16 42 h2 v1 h-2Z M19 42 h1 v1 h-1Z M22 42 h2 v1 h-2Z M30 42 h3 v1 h-3Z M35 42 h4 v1 h-4Z M46 42 h1 v1 h-1Z M48 42 h1 v1 h-1Z M14 43 h1 v1 h-1Z M18 43 h2 v1 h-2Z M33 43 h3 v1 h-3Z M37 43 h1 v1 h-1Z M47 43 h1 v1 h-1Z M13 44 h4 v1 h-4Z M18 44 h4 v1 h-4Z M29 44 h2 v1 h-2Z M32 44 h2 v1 h-2Z M36 44 h1 v1 h-1Z M45 44 h2 v1 h-2Z M48 44 h1 v1 h-1Z M15 45 h7 v1 h-7Z M24 45 h3 v1 h-3Z M28 45 h1 v1 h-1Z M31 45 h2 v1 h-2Z M34 45 h1 v1 h-1Z M37 45 h1 v1 h-1Z M39 45 h4 v1 h-4Z M44 45 h2 v1 h-2Z M48 45 h1 v1 h-1Z M15 46 h2 v1 h-2Z M21 46 h1 v1 h-1Z M23 46 h1 v1 h-1Z M29 46 h1 v1 h-1Z M31 46 h2 v1 h-2Z M35 46 h1 v1 h-1Z M38 46 h1 v1 h-1Z M43 46 h1 v1 h-1Z M47 46 h2 v1 h-2Z M13 47 h1 v1 h-1Z M16 47 h5 v1 h-5Z M22 47 h2 v1 h-2Z M25 47 h6 v1 h-6Z M32 47 h1 v1 h-1Z M36 47 h1 v1 h-1Z M38 47 h1 v1 h-1Z M40 47 h3 v1 h-3Z M45 47 h1 v1 h-1Z M47 47 h2 v1 h-2Z M13 48 h1 v1 h-1Z M15 48 h5 v1 h-5Z M23 48 h1 v1 h-1Z M25 48 h1 v1 h-1Z M27 48 h2 v1 h-2Z M30 48 h1 v1 h-1Z M32 48 h1 v1 h-1Z M34 48 h5 v1 h-5Z M40 48 h1 v1 h-1Z M43 48 h1 v1 h-1Z M48 48 h1 v1 h-1Z " /><path class="qr-6 " stroke="transparent" fill="#fff" fill-opacity="1" d="M5 5 h5 v1 h-5Z M43 5 h5 v1 h-5Z M5 6 h1 v1 h-1Z M9 6 h1 v1 h-1Z M43 6 h1 v1 h-1Z M47 6 h1 v1 h-1Z M5 7 h1 v1 h-1Z M9 7 h1 v1 h-1Z M43 7 h1 v1 h-1Z M47 7 h1 v1 h-1Z M5 8 h1 v1 h-1Z M9 8 h1 v1 h-1Z M43 8 h1 v1 h-1Z M47 8 h1 v1 h-1Z M5 9 h5 v1 h-5Z M43 9 h5 v1 h-5Z M5 43 h5 v1 h-5Z M5 44 h1 v1 h-1Z M9 44 h1 v1 h-1Z M5 45 h1 v1 h-1Z M9 45 h1 v1 h-1Z M5 46 h1 v1 h-1Z M9 46 h1 v1 h-1Z M5 47 h5 v1 h-5Z " /><path class="qr-8 " stroke="transparent" fill="#fff" fill-opacity="1" d="M11 4 h1 v1 h-1Z M41 4 h1 v1 h-1Z M11 5 h1 v1 h-1Z M41 5 h1 v1 h-1Z M11 6 h1 v1 h-1Z M41 6 h1 v1 h-1Z M11 7 h1 v1 h-1Z M41 7 h1 v1 h-1Z M11 8 h1 v1 h-1Z M41 8 h1 v1 h-1Z M11 9 h1 v1 h-1Z M41 9 h1 v1 h-1Z M11 10 h1 v1 h-1Z M41 10 h1 v1 h-1Z M4 11 h8 v1 h-8Z M41 11 h8 v1 h-8Z M4 41 h8 v1 h-8Z M11 42 h1 v1 h-1Z M11 43 h1 v1 h-1Z M11 44 h1 v1 h-1Z M11 45 h1 v1 h-1Z M11 46 h1 v1 h-1Z M11 47 h1 v1 h-1Z M11 48 h1 v1 h-1Z " /><path class="qr-10 " stroke="transparent" fill="#fff" fill-opacity="1" d="M25 9 h3 v1 h-3Z M25 10 h1 v1 h-1Z M27 10 h1 v1 h-1Z M25 11 h3 v1 h-3Z M9 25 h3 v1 h-3Z M25 25 h3 v1 h-3Z M41 25 h3 v1 h-3Z M9 26 h1 v1 h-1Z M11 26 h1 v1 h-1Z M25 26 h1 v1 h-1Z M27 26 h1 v1 h-1Z M41 26 h1 v1 h-1Z M43 26 h1 v1 h-1Z M9 27 h3 v1 h-3Z M25 27 h3 v1 h-3Z M41 27 h3 v1 h-3Z M25 41 h3 v1 h-3Z M41 41 h3 v1 h-3Z M25 42 h1 v1 h-1Z M27 42 h1 v1 h-1Z M41 42 h1 v1 h-1Z M43 42 h1 v1 h-1Z M25 43 h3 v1 h-3Z M41 43 h3 v1 h-3Z " /><path class="qr-12 " stroke="transparent" fill="#fff" fill-opacity="1" d="M13 10 h1 v1 h-1Z M15 10 h1 v1 h-1Z M17 10 h1 v1 h-1Z M19 10 h1 v1 h-1Z M21 10 h1 v1 h-1Z M23 10 h1 v1 h-1Z M29 10 h1 v1 h-1Z M31 10 h1 v1 h-1Z M33 10 h1 v1 h-1Z M35 10 h1 v1 h-1Z M37 10 h1 v1 h-1Z M39 10 h1 v1 h-1Z M10 13 h1 v1 h-1Z M10 15 h1 v1 h-1Z M10 17 h1 v1 h-1Z M10 19 h1 v1 h-1Z M10 21 h1 v1 h-1Z M10 23 h1 v1 h-1Z M10 29 h1 v1 h-1Z M10 31 h1 v1 h-1Z M10 33 h1 v1 h-1Z M10 35 h1 v1 h-1Z M10 37 h1 v1 h-1Z M10 39 h1 v1 h-1Z " /><path class="qr-14 " stroke="transparent" fill="#fff" fill-opacity="1" d="M12 7 h1 v1 h-1Z M12 8 h1 v1 h-1Z M4 12 h2 v1 h-2Z M9 12 h1 v1 h-1Z M11 12 h1 v1 h-1Z M44 12 h2 v1 h-2Z M12 42 h1 v1 h-1Z M12 43 h1 v1 h-1Z M12 47 h1 v1 h-1Z M12 48 h1 v1 h-1Z " /><path class="qr-16 " stroke="transparent" fill="#fff" fill-opacity="1" d="M38 4 h2 v1 h-2Z M38 5 h1 v1 h-1Z M40 5 h1 v1 h-1Z M38 6 h1 v1 h-1Z M40 6 h1 v1 h-1Z M38 7 h1 v1 h-1Z M38 9 h3 v1 h-3Z M4 38 h4 v1 h-4Z M9 38 h1 v1 h-1Z M4 39 h1 v1 h-1Z M9 39 h1 v1 h-1Z M5 40 h2 v1 h-2Z M9 40 h1 v1 h-1Z " /><path class="qr-18 " stroke="transparent" fill="#fff" fill-opacity="1" d="M0 0 h53 v1 h-53Z M0 1 h53 v1 h-53Z M0 2 h53 v1 h-53Z M0 3 h53 v1 h-53Z M0 4 h4 v1 h-4Z M49 4 h4 v1 h-4Z M0 5 h4 v1 h-4Z M49 5 h4 v1 h-4Z M0 6 h4 v1 h-4Z M49 6 h4 v1 h-4Z M0 7 h4 v1 h-4Z M49 7 h4 v1 h-4Z M0 8 h4 v1 h-4Z M49 8 h4 v1 h-4Z M0 9 h4 v1 h-4Z M49 9 h4 v1 h-4Z M0 10 h4 v1 h-4Z M49 10 h4 v1 h-4Z M0 11 h4 v1 h-4Z M49 11 h4 v1 h-4Z M0 12 h4 v1 h-4Z M49 12 h4 v1 h-4Z M0 13 h4 v1 h-4Z M49 13 h4 v1 h-4Z M0 14 h4 v1 h-4Z M49 14 h4 v1 h-4Z M0 15 h4 v1 h-4Z M49 15 h4 v1 h-4Z M0 16 h4 v1 h-4Z M49 16 h4 v1 h-4Z M0 17 h4 v1 h-4Z M49 17 h4 v1 h-4Z M0 18 h4 v1 h-4Z M49 18 h4 v1 h-4Z M0 19 h4 v1 h-4Z M49 19 h4 v1 h-4Z M0 20 h4 v1 h-4Z M49 20 h4 v1 h-4Z M0 21 h4 v1 h-4Z M49 21 h4 v1 h-4Z M0 22 h4 v1 h-4Z M49 22 h4 v1 h-4Z M0 23 h4 v1 h-4Z M49 23 h4 v1 h-4Z M0 24 h4 v1 h-4Z M49 24 h4 v1 h-4Z M0 25 h4 v1 h-4Z M49 25 h4 v1 h-4Z M0 26 h4 v1 h-4Z M49 26 h4 v1 h-4Z M0 27 h4 v1 h-4Z M49 27 h4 v1 h-4Z M0 28 h4 v1 h-4Z M49 28 h4 v1 h-4Z M0 29 h4 v1 h-4Z M49 29 h4 v1 h-4Z M0 30 h4 v1 h-4Z M49 30 h4 v1 h-4Z M0 31 h4 v1 h-4Z M49 31 h4 v1 h-4Z M0 32 h4 v1 h-4Z M49 32 h4 v1 h-4Z M0 33 h4 v1 h-4Z M49 33 h4 v1 h-4Z M0 34 h4 v1 h-4Z M49 34 h4 v1 h-4Z M0 35 h4 v1 h-4Z M49 35 h4 v1 h-4Z M0 36 h4 v1 h-4Z M49 36 h4 v1 h-4Z M0 37 h4 v1 h-4Z M49 37 h4 v1 h-4Z M0 38 h4 v1 h-4Z M49 38 h4 v1 h-4Z M0 39 h4 v1 h-4Z M49 39 h4 v1 h-4Z M0 40 h4 v1 h-4Z M49 40 h4 v1 h-4Z M0 41 h4 v1 h-4Z M49 41 h4 v1 h-4Z M0 42 h4 v1 h-4Z M49 42 h4 v1 h-4Z M0 43 h4 v1 h-4Z M49 43 h4 v1 h-4Z M0 44 h4 v1 h-4Z M49 44 h4 v1 h-4Z M0 45 h4 v1 h-4Z M49 45 h4 v1 h-4Z M0 46 h4 v1 h-4Z M49 46 h4 v1 h-4Z M0 47 h4 v1 h-4Z M49 47 h4 v1 h-4Z M0 48 h4 v1 h-4Z M49 48 h4 v1 h-4Z M0 49 h53 v1 h-53Z M0 50 h53 v1 h-53Z M0 51 h53 v1 h-53Z M0 52 h53 v1 h-53Z " /><path class="qr-512 " stroke="transparent" fill="#000" fill-opacity="1" d="M12 41 h1 v1 h-1Z " /><path class="qr-1024 " stroke="transparent" fill="#000" fill-opacity="1" d="M13 4 h3 v1 h-3Z M18 4 h1 v1 h-1Z M20 4 h4 v1 h-4Z M25 4 h3 v1 h-3Z M29 4 h1 v1 h-1Z M32 4 h4 v1 h-4Z M37 4 h1 v1 h-1Z M17 5 h3 v1 h-3Z M22 5 h1 v1 h-1Z M24 5 h1 v1 h-1Z M27 5 h2 v1 h-2Z M30 5 h1 v1 h-1Z M35 5 h2 v1 h-2Z M13 6 h1 v1 h-1Z M17 6 h2 v1 h-2Z M20 6 h1 v1 h-1Z M23 6 h1 v1 h-1Z M27 6 h2 v1 h-2Z M33 6 h3 v1 h-3Z M37 6 h1 v1 h-1Z M16 7 h1 v1 h-1Z M20 7 h1 v1 h-1Z M25 7 h1 v1 h-1Z M29 7 h1 v1 h-1Z M31 7 h1 v1 h-1Z M33 7 h2 v1 h-2Z M37 7 h1 v1 h-1Z M14 8 h5 v1 h-5Z M20 8 h1 v1 h-1Z M23 8 h1 v1 h-1Z M34 8 h2 v1 h-2Z M37 8 h1 v1 h-1Z M13 9 h1 v1 h-1Z M15 9 h2 v1 h-2Z M21 9 h1 v1 h-1Z M23 9 h1 v1 h-1Z M30 9 h3 v1 h-3Z M34 9 h1 v1 h-1Z M13 11 h1 v1 h-1Z M17 11 h3 v1 h-3Z M29 11 h2 v1 h-2Z M32 11 h2 v1 h-2Z M38 11 h1 v1 h-1Z M40 11 h1 v1 h-1Z M13 12 h1 v1 h-1Z M15 12 h2 v1 h-2Z M20 12 h4 v1 h-4Z M29 12 h4 v1 h-4Z M35 12 h2 v1 h-2Z M38 12 h1 v1 h-1Z M40 12 h1 v1 h-1Z M4 13 h1 v1 h-1Z M8 13 h2 v1 h-2Z M12 13 h1 v1 h-1Z M16 13 h4 v1 h-4Z M24 13 h1 v1 h-1Z M26 13 h4 v1 h-4Z M33 13 h1 v1 h-1Z M36 13 h2 v1 h-2Z M39 13 h1 v1 h-1Z M41 13 h4 v1 h-4Z M46 13 h1 v1 h-1Z M6 14 h2 v1 h-2Z M11 14 h2 v1 h-2Z M17 14 h1 v1 h-1Z M20 14 h6 v1 h-6Z M28 14 h5 v1 h-5Z M34 14 h5 v1 h-5Z M44 14 h5 v1 h-5Z M6 15 h1 v1 h-1Z M8 15 h2 v1 h-2Z M11 15 h1 v1 h-1Z M16 15 h5 v1 h-5Z M23 15 h1 v1 h-1Z M26 15 h2 v1 h-2Z M30 15 h3 v1 h-3Z M34 15 h2 v1 h-2Z M39 15 h1 v1 h-1Z M46 15 h1 v1 h-1Z M48 15 h1 v1 h-1Z M4 16 h2 v1 h-2Z M7 16 h1 v1 h-1Z M9 16 h1 v1 h-1Z M11 16 h1 v1 h-1Z M13 16 h3 v1 h-3Z M18 16 h4 v1 h-4Z M27 16 h8 v1 h-8Z M39 16 h2 v1 h-2Z M43 16 h1 v1 h-1Z M45 16 h4 v1 h-4Z M4 17 h1 v1 h-1Z M9 17 h1 v1 h-1Z M11 17 h1 v1 h-1Z M13 17 h4 v1 h-4Z M18 17 h1 v1 h-1Z M21 17 h1 v1 h-1Z M23 17 h2 v1 h-2Z M26 17 h2 v1 h-2Z M29 17 h1 v1 h-1Z M31 17 h1 v1 h-1Z M34 17 h2 v1 h-2Z M40 17 h2 v1 h-2Z M47 17 h1 v1 h-1Z M5 18 h3 v1 h-3Z M11 18 h1 v1 h-1Z M17 18 h2 v1 h-2Z M21 18 h1 v1 h-1Z M27 18 h1 v1 h-1Z M29 18 h2 v1 h-2Z M32 18 h3 v1 h-3Z M37 18 h7 v1 h-7Z M46 18 h1 v1 h-1Z M4 19 h1 v1 h-1Z M6 19 h2 v1 h-2Z M12 19 h1 v1 h-1Z M14 19 h2 v1 h-2Z M20 19 h2 v1 h-2Z M25 19 h3 v1 h-3Z M29 19 h5 v1 h-5Z M36 19 h1 v1 h-1Z M38 19 h1 v1 h-1Z M40 19 h4 v1 h-4Z M45 19 h3 v1 h-3Z M7 20 h3 v1 h-3Z M13 20 h6 v1 h-6Z M22 20 h1 v1 h-1Z M27 20 h3 v1 h-3Z M35 20 h1 v1 h-1Z M37 20 h3 v1 h-3Z M41 20 h1 v1 h-1Z M44 20 h2 v1 h-2Z M6 21 h2 v1 h-2Z M13 21 h1 v1 h-1Z M15 21 h1 v1 h-1Z M17 21 h2 v1 h-2Z M20 21 h3 v1 h-3Z M24 21 h3 v1 h-3Z M30 21 h2 v1 h-2Z M33 21 h1 v1 h-1Z M38 21 h3 v1 h-3Z M43 21 h3 v1 h-3Z M48 21 h1 v1 h-1Z M4 22 h2 v1 h-2Z M8 22 h1 v1 h-1Z M11 22 h1 v1 h-1Z M13 22 h1 v1 h-1Z M18 22 h2 v1 h-2Z M22 22 h3 v1 h-3Z M27 22 h2 v1 h-2Z M30 22 h3 v1 h-3Z M34 22 h2 v1 h-2Z M37 22 h1 v1 h-1Z M40 22 h1 v1 h-1Z M42 22 h1 v1 h-1Z M44 22 h1 v1 h-1Z M5 23 h1 v1 h-1Z M8 23 h1 v1 h-1Z M13 23 h1 v1 h-1Z M15 23 h1 v1 h-1Z M17 23 h3 v1 h-3Z M23 23 h1 v1 h-1Z M28 23 h1 v1 h-1Z M32 23 h1 v1 h-1Z M34 23 h1 v1 h-1Z M36 23 h2 v1 h-2Z M43 23 h5 v1 h-5Z M6 24 h2 v1 h-2Z M15 24 h3 v1 h-3Z M19 24 h1 v1 h-1Z M21 24 h3 v1 h-3Z M29 24 h6 v1 h-6Z M48 24 h1 v1 h-1Z M13 25 h4 v1 h-4Z M19 25 h1 v1 h-1Z M21 25 h1 v1 h-1Z M23 25 h1 v1 h-1Z M29 25 h4 v1 h-4Z M34 25 h4 v1 h-4Z M39 25 h1 v1 h-1Z M45 25 h1 v1 h-1Z M48 25 h1 v1 h-1Z M4 26 h2 v1 h-2Z M13 26 h1 v1 h-1Z M15 26 h5 v1 h-5Z M21 26 h3 v1 h-3Z M30 26 h7 v1 h-7Z M47 26 h1 v1 h-1Z M4 27 h1 v1 h-1Z M6 27 h2 v1 h-2Z M13 27 h1 v1 h-1Z M23 27 h1 v1 h-1Z M29 27 h1 v1 h-1Z M31 27 h2 v1 h-2Z M34 27 h1 v1 h-1Z M38 27 h1 v1 h-1Z M45 27 h1 v1 h-1Z M4 28 h1 v1 h-1Z M6 28 h1 v1 h-1Z M17 28 h4 v1 h-4Z M22 28 h2 v1 h-2Z M32 28 h7 v1 h-7Z M46 28 h1 v1 h-1Z M48 28 h1 v1 h-1Z M4 29 h4 v1 h-4Z M9 29 h1 v1 h-1Z M12 29 h1 v1 h-1Z M14 29 h2 v1 h-2Z M17 29 h1 v1 h-1Z M21 29 h1 v1 h-1Z M23 29 h3 v1 h-3Z M27 29 h1 v1 h-1Z M36 29 h1 v1 h-1Z M38 29 h4 v1 h-4Z M46 29 h1 v1 h-1Z M4 30 h3 v1 h-3Z M11 30 h2 v1 h-2Z M16 30 h2 v1 h-2Z M21 30 h3 v1 h-3Z M26 30 h1 v1 h-1Z M29 30 h1 v1 h-1Z M33 30 h5 v1 h-5Z M39 30 h2 v1 h-2Z M44 30 h5 v1 h-5Z M4 31 h1 v1 h-1Z M7 31 h3 v1 h-3Z M12 31 h1 v1 h-1Z M17 31 h3 v1 h-3Z M21 31 h2 v1 h-2Z M29 31 h1 v1 h-1Z M31 31 h2 v1 h-2Z M35 31 h1 v1 h-1Z M38 31 h1 v1 h-1Z M41 31 h1 v1 h-1Z M44 31 h1 v1 h-1Z M46 31 h1 v1 h-1Z M48 31 h1 v1 h-1Z M4 32 h1 v1 h-1Z M6 32 h2 v1 h-2Z M11 32 h1 v1 h-1Z M19 32 h1 v1 h-1Z M21 32 h1 v1 h-1Z M26 32 h1 v1 h-1Z M28 32 h4 v1 h-4Z M33 32 h1 v1 h-1Z M38 32 h5 v1 h-5Z M44 32 h5 v1 h-5Z M4 33 h4 v1 h-4Z M15 33 h1 v1 h-1Z M18 33 h4 v1 h-4Z M24 33 h1 v1 h-1Z M26 33 h1 v1 h-1Z M29 33 h2 v1 h-2Z M35 33 h1 v1 h-1Z M39 33 h1 v1 h-1Z M42 33 h1 v1 h-1Z M45 33 h1 v1 h-1Z M47 33 h1 v1 h-1Z M6 34 h1 v1 h-1Z M11 34 h1 v1 h-1Z M15 34 h3 v1 h-3Z M20 34 h1 v1 h-1Z M22 34 h1 v1 h-1Z M24 34 h3 v1 h-3Z M28 34 h2 v1 h-2Z M33 34 h2 v1 h-2Z M37 34 h3 v1 h-3Z M41 34 h3 v1 h-3Z M12 35 h2 v1 h-2Z M15 35 h1 v1 h-1Z M17 35 h1 v1 h-1Z M20 35 h2 v1 h-2Z M23 35 h1 v1 h-1Z M26 35 h2 v1 h-2Z M29 35 h1 v1 h-1Z M31 35 h1 v1 h-1Z M37 35 h1 v1 h-1Z M40 35 h1 v1 h-1Z M45 35 h1 v1 h-1Z M47 35 h1 v1 h-1Z M4 36 h2 v1 h-2Z M11 36 h1 v1 h-1Z M13 36 h3 v1 h-3Z M18 36 h1 v1 h-1Z M20 36 h1 v1 h-1Z M25 36 h3 v1 h-3Z M32 36 h1 v1 h-1Z M35 36 h2 v1 h-2Z M38 36 h1 v1 h-1Z M46 36 h1 v1 h-1Z M4 37 h1 v1 h-1Z M6 37 h1 v1 h-1Z M8 37 h1 v1 h-1Z M12 37 h1 v1 h-1Z M14 37 h1 v1 h-1Z M16 37 h3 v1 h-3Z M21 37 h2 v1 h-2Z M25 37 h1 v1 h-1Z M28 37 h1 v1 h-1Z M31 37 h2 v1 h-2Z M34 37 h1 v1 h-1Z M36 37 h1 v1 h-1Z M40 37 h2 v1 h-2Z M43 37 h1 v1 h-1Z M45 37 h2 v1 h-2Z M11 38 h2 v1 h-2Z M14 38 h4 v1 h-4Z M19 38 h1 v1 h-1Z M21 38 h5 v1 h-5Z M27 38 h1 v1 h-1Z M35 38 h2 v1 h-2Z M38 38 h1 v1 h-1Z M40 38 h1 v1 h-1Z M46 38 h3 v1 h-3Z M12 39 h3 v1 h-3Z M16 39 h1 v1 h-1Z M19 39 h3 v1 h-3Z M25 39 h2 v1 h-2Z M31 39 h1 v1 h-1Z M35 39 h3 v1 h-3Z M41 39 h1 v1 h-1Z M43 39 h1 v1 h-1Z M45 39 h2 v1 h-2Z M48 39 h1 v1 h-1Z M11 40 h2 v1 h-2Z M14 40 h2 v1 h-2Z M17 40 h2 v1 h-2Z M21 40 h1 v1 h-1Z M23 40 h1 v1 h-1Z M32 40 h2 v1 h-2Z M35 40 h1 v1 h-1Z M39 40 h1 v1 h-1Z M45 40 h1 v1 h-1Z M47 40 h2 v1 h-2Z M14 41 h1 v1 h-1Z M17 41 h3 v1 h-3Z M31 41 h7 v1 h-7Z M46 41 h1 v1 h-1Z M48 41 h1 v1 h-1Z M14 42 h2 v1 h-2Z M18 42 h1 v1 h-1Z M20 42 h2 v1 h-2Z M29 42 h1 v1 h-1Z M33 42 h2 v1 h-2Z M39 42 h1 v1 h-1Z M45 42 h1 v1 h-1Z M47 42 h1 v1 h-1Z M13 43 h1 v1 h-1Z M15 43 h3 v1 h-3Z M20 43 h4 v1 h-4Z M29 43 h4 v1 h-4Z M36 43 h1 v1 h-1Z M38 43 h2 v1 h-2Z M45 43 h2 v1 h-2Z M48 43 h1 v1 h-1Z M17 44 h1 v1 h-1Z M22 44 h2 v1 h-2Z M31 44 h1 v1 h-1Z M34 44 h2 v1 h-2Z M37 44 h3 v1 h-3Z M47 44 h1 v1 h-1Z M13 45 h2 v1 h-2Z M22 45 h2 v1 h-2Z M27 45 h1 v1 h-1Z M29 45 h2 v1 h-2Z M33 45 h1 v1 h-1Z M35 45 h2 v1 h-2Z M38 45 h1 v1 h-1Z M43 45 h1 v1 h-1Z M46 45 h2 v1 h-2Z M13 46 h2 v1 h-2Z M17 46 h4 v1 h-4Z M22 46 h1 v1 h-1Z M24 46 h5 v1 h-5Z M30 46 h1 v1 h-1Z M33 46 h2 v1 h-2Z M36 46 h2 v1 h-2Z M39 46 h4 v1 h-4Z M44 46 h3 v1 h-3Z M14 47 h2 v1 h-2Z M21 47 h1 v1 h-1Z M24 47 h1 v1 h-1Z M31 47 h1 v1 h-1Z M33 47 h3 v1 h-3Z M37 47 h1 v1 h-1Z M39 47 h1 v1 h-1Z M43 47 h2 v1 h-2Z M46 47 h1 v1 h-1Z M14 48 h1 v1 h-1Z M20 48 h3 v1 h-3Z M24 48 h1 v1 h-1Z M26 48 h1 v1 h-1Z M29 48 h1 v1 h-1Z M31 48 h1 v1 h-1Z M33 48 h1 v1 h-1Z M39 48 h1 v1 h-1Z M41 48 h2 v1 h-2Z M44 48 h4 v1 h-4Z " /><path class="qr-1536 " stroke="transparent" fill="#000" fill-opacity="1" d="M4 4 h7 v1 h-7Z M42 4 h7 v1 h-7Z M4 5 h1 v1 h-1Z M10 5 h1 v1 h-1Z M42 5 h1 v1 h-1Z M48 5 h1 v1 h-1Z M4 6 h1 v1 h-1Z M10 6 h1 v1 h-1Z M42 6 h1 v1 h-1Z M48 6 h1 v1 h-1Z M4 7 h1 v1 h-1Z M10 7 h1 v1 h-1Z M42 7 h1 v1 h-1Z M48 7 h1 v1 h-1Z M4 8 h1 v1 h-1Z M10 8 h1 v1 h-1Z M42 8 h1 v1 h-1Z M48 8 h1 v1 h-1Z M4 9 h1 v1 h-1Z M10 9 h1 v1 h-1Z M42 9 h1 v1 h-1Z M48 9 h1 v1 h-1Z M4 10 h7 v1 h-7Z M42 10 h7 v1 h-7Z M4 42 h7 v1 h-7Z M4 43 h1 v1 h-1Z M10 43 h1 v1 h-1Z M4 44 h1 v1 h-1Z M10 44 h1 v1 h-1Z M4 45 h1 v1 h-1Z M10 45 h1 v1 h-1Z M4 46 h1 v1 h-1Z M10 46 h1 v1 h-1Z M4 47 h1 v1 h-1Z M10 47 h1 v1 h-1Z M4 48 h7 v1 h-7Z " /><path class="qr-2560 " stroke="transparent" fill="#000" fill-opacity="1" d="M24 8 h5 v1 h-5Z M24 9 h1 v1 h-1Z M28 9 h1 v1 h-1Z M24 10 h1 v1 h-1Z M26 10 h1 v1 h-1Z M28 10 h1 v1 h-1Z M24 11 h1 v1 h-1Z M28 11 h1 v1 h-1Z M24 12 h5 v1 h-5Z M8 24 h5 v1 h-5Z M24 24 h5 v1 h-5Z M40 24 h5 v1 h-5Z M8 25 h1 v1 h-1Z M12 25 h1 v1 h-1Z M24 25 h1 v1 h-1Z M28 25 h1 v1 h-1Z M40 25 h1 v1 h-1Z M44 25 h1 v1 h-1Z M8 26 h1 v1 h-1Z M10 26 h1 v1 h-1Z M12 26 h1 v1 h-1Z M24 26 h1 v1 h-1Z M26 26 h1 v1 h-1Z M28 26 h1 v1 h-1Z M40 26 h1 v1 h-1Z M42 26 h1 v1 h-1Z M44 26 h1 v1 h-1Z M8 27 h1 v1 h-1Z M12 27 h1 v1 h-1Z M24 27 h1 v1 h-1Z M28 27 h1 v1 h-1Z M40 27 h1 v1 h-1Z M44 27 h1 v1 h-1Z M8 28 h5 v1 h-5Z M24 28 h5 v1 h-5Z M40 28 h5 v1 h-5Z M24 40 h5 v1 h-5Z M40 40 h5 v1 h-5Z M24 41 h1 v1 h-1Z M28 41 h1 v1 h-1Z M40 41 h1 v1 h-1Z M44 41 h1 v1 h-1Z M24 42 h1 v1 h-1Z M26 42 h1 v1 h-1Z M28 42 h1 v1 h-1Z M40 42 h1 v1 h-1Z M42 42 h1 v1 h-1Z M44 42 h1 v1 h-1Z M24 43 h1 v1 h-1Z M28 43 h1 v1 h-1Z M40 43 h1 v1 h-1Z M44 43 h1 v1 h-1Z M24 44 h5 v1 h-5Z M40 44 h5 v1 h-5Z " /><path class="qr-3072 " stroke="transparent" fill="#000" fill-opacity="1" d="M12 10 h1 v1 h-1Z M14 10 h1 v1 h-1Z M16 10 h1 v1 h-1Z M18 10 h1 v1 h-1Z M20 10 h1 v1 h-1Z M22 10 h1 v1 h-1Z M30 10 h1 v1 h-1Z M32 10 h1 v1 h-1Z M34 10 h1 v1 h-1Z M36 10 h1 v1 h-1Z M38 10 h1 v1 h-1Z M40 10 h1 v1 h-1Z M10 12 h1 v1 h-1Z M10 14 h1 v1 h-1Z M10 16 h1 v1 h-1Z M10 18 h1 v1 h-1Z M10 20 h1 v1 h-1Z M10 22 h1 v1 h-1Z M10 30 h1 v1 h-1Z M10 32 h1 v1 h-1Z M10 34 h1 v1 h-1Z M10 36 h1 v1 h-1Z M10 38 h1 v1 h-1Z M10 40 h1 v1 h-1Z " /><path class="qr-3584 " stroke="transparent" fill="#000" fill-opacity="1" d="M12 4 h1 v1 h-1Z M12 5 h1 v1 h-1Z M12 6 h1 v1 h-1Z M12 9 h1 v1 h-1Z M12 11 h1 v1 h-1Z M6 12 h3 v1 h-3Z M12 12 h1 v1 h-1Z M41 12 h3 v1 h-3Z M46 12 h3 v1 h-3Z M12 44 h1 v1 h-1Z M12 45 h1 v1 h-1Z M12 46 h1 v1 h-1Z " /><path class="qr-4096 " stroke="transparent" fill="#000" fill-opacity="1" d="M40 4 h1 v1 h-1Z M39 5 h1 v1 h-1Z M39 6 h1 v1 h-1Z M39 7 h2 v1 h-2Z M38 8 h3 v1 h-3Z M8 38 h1 v1 h-1Z M5 39 h4 v1 h-4Z M4 40 h1 v1 h-1Z M7 40 h2 v1 h-2Z " /><path class="qr-5632 " stroke="transparent" fill="#000" fill-opacity="1" d="M6 6 h3 v1 h-3Z M44 6 h3 v1 h-3Z M6 7 h3 v1 h-3Z M44 7 h3 v1 h-3Z M6 8 h3 v1 h-3Z M44 8 h3 v1 h-3Z M6 44 h3 v1 h-3Z M6 45 h3 v1 h-3Z M6 46 h3 v1 h-3Z " /></svg>

    </a>
    <figcaption aria-hidden="true" class="hidden" hidden>One Ko-fi for Stéphane HUC</figcaption>
</figure>


<h3 id="liberapay">Liberapay</h3>
<ul>
<li><a href="https://fr.liberapay.com/HucSte/donate" rel="external">https://fr.liberapay.com/HucSte/donate</a></li>
</ul>


<figure class="pure-img">
    <a href="/svg/qrcode/liberapay.svg" title="Donate for Stéphane HUC by Liberapay">
    <svg xmlns="http://www.w3.org/2000/svg" class="qr-svg " height="128" viewBox="0 0 53 53" width="128">
<defs><style>rect{shape-rendering:crispEdges}</style></defs>
<path class="qr-4 " stroke="transparent" fill="#fff" fill-opacity="1" d="M14 4 h2 v1 h-2Z M18 4 h1 v1 h-1Z M22 4 h5 v1 h-5Z M28 4 h1 v1 h-1Z M30 4 h2 v1 h-2Z M35 4 h1 v1 h-1Z M13 5 h1 v1 h-1Z M15 5 h2 v1 h-2Z M18 5 h1 v1 h-1Z M20 5 h1 v1 h-1Z M23 5 h1 v1 h-1Z M26 5 h3 v1 h-3Z M30 5 h2 v1 h-2Z M36 5 h1 v1 h-1Z M17 6 h1 v1 h-1Z M26 6 h1 v1 h-1Z M28 6 h2 v1 h-2Z M31 6 h2 v1 h-2Z M35 6 h3 v1 h-3Z M13 7 h3 v1 h-3Z M17 7 h3 v1 h-3Z M21 7 h8 v1 h-8Z M30 7 h1 v1 h-1Z M35 7 h2 v1 h-2Z M13 8 h1 v1 h-1Z M15 8 h2 v1 h-2Z M18 8 h3 v1 h-3Z M22 8 h2 v1 h-2Z M29 8 h2 v1 h-2Z M32 8 h1 v1 h-1Z M34 8 h1 v1 h-1Z M37 8 h1 v1 h-1Z M13 9 h1 v1 h-1Z M16 9 h2 v1 h-2Z M20 9 h1 v1 h-1Z M23 9 h1 v1 h-1Z M29 9 h1 v1 h-1Z M33 9 h1 v1 h-1Z M36 9 h1 v1 h-1Z M13 11 h1 v1 h-1Z M20 11 h4 v1 h-4Z M29 11 h1 v1 h-1Z M33 11 h3 v1 h-3Z M40 11 h1 v1 h-1Z M13 12 h1 v1 h-1Z M15 12 h4 v1 h-4Z M20 12 h1 v1 h-1Z M22 12 h2 v1 h-2Z M29 12 h1 v1 h-1Z M31 12 h5 v1 h-5Z M38 12 h3 v1 h-3Z M4 13 h3 v1 h-3Z M9 13 h1 v1 h-1Z M11 13 h2 v1 h-2Z M14 13 h2 v1 h-2Z M18 13 h2 v1 h-2Z M21 13 h1 v1 h-1Z M23 13 h1 v1 h-1Z M25 13 h1 v1 h-1Z M27 13 h3 v1 h-3Z M31 13 h2 v1 h-2Z M35 13 h1 v1 h-1Z M38 13 h1 v1 h-1Z M40 13 h1 v1 h-1Z M45 13 h1 v1 h-1Z M47 13 h2 v1 h-2Z M5 14 h4 v1 h-4Z M11 14 h1 v1 h-1Z M13 14 h4 v1 h-4Z M19 14 h1 v1 h-1Z M21 14 h2 v1 h-2Z M24 14 h1 v1 h-1Z M26 14 h1 v1 h-1Z M29 14 h1 v1 h-1Z M31 14 h1 v1 h-1Z M36 14 h2 v1 h-2Z M41 14 h1 v1 h-1Z M45 14 h2 v1 h-2Z M48 14 h1 v1 h-1Z M7 15 h1 v1 h-1Z M9 15 h1 v1 h-1Z M12 15 h2 v1 h-2Z M16 15 h4 v1 h-4Z M21 15 h1 v1 h-1Z M23 15 h3 v1 h-3Z M27 15 h2 v1 h-2Z M31 15 h5 v1 h-5Z M37 15 h2 v1 h-2Z M42 15 h1 v1 h-1Z M45 15 h2 v1 h-2Z M7 16 h1 v1 h-1Z M11 16 h3 v1 h-3Z M17 16 h1 v1 h-1Z M19 16 h1 v1 h-1Z M22 16 h3 v1 h-3Z M26 16 h2 v1 h-2Z M31 16 h2 v1 h-2Z M36 16 h7 v1 h-7Z M44 16 h1 v1 h-1Z M4 17 h3 v1 h-3Z M8 17 h1 v1 h-1Z M11 17 h1 v1 h-1Z M13 17 h1 v1 h-1Z M15 17 h2 v1 h-2Z M18 17 h4 v1 h-4Z M24 17 h4 v1 h-4Z M31 17 h2 v1 h-2Z M34 17 h1 v1 h-1Z M37 17 h4 v1 h-4Z M44 17 h1 v1 h-1Z M48 17 h1 v1 h-1Z M4 18 h2 v1 h-2Z M8 18 h2 v1 h-2Z M11 18 h1 v1 h-1Z M16 18 h2 v1 h-2Z M19 18 h3 v1 h-3Z M23 18 h3 v1 h-3Z M27 18 h3 v1 h-3Z M31 18 h1 v1 h-1Z M34 18 h1 v1 h-1Z M36 18 h3 v1 h-3Z M41 18 h1 v1 h-1Z M43 18 h1 v1 h-1Z M45 18 h4 v1 h-4Z M8 19 h2 v1 h-2Z M11 19 h1 v1 h-1Z M13 19 h1 v1 h-1Z M15 19 h1 v1 h-1Z M17 19 h1 v1 h-1Z M19 19 h1 v1 h-1Z M21 19 h1 v1 h-1Z M24 19 h1 v1 h-1Z M32 19 h1 v1 h-1Z M34 19 h2 v1 h-2Z M37 19 h2 v1 h-2Z M40 19 h4 v1 h-4Z M47 19 h2 v1 h-2Z M5 20 h2 v1 h-2Z M9 20 h1 v1 h-1Z M12 20 h2 v1 h-2Z M16 20 h2 v1 h-2Z M20 20 h1 v1 h-1Z M24 20 h2 v1 h-2Z M27 20 h4 v1 h-4Z M37 20 h3 v1 h-3Z M44 20 h2 v1 h-2Z M47 20 h2 v1 h-2Z M4 21 h1 v1 h-1Z M6 21 h2 v1 h-2Z M9 21 h1 v1 h-1Z M13 21 h1 v1 h-1Z M18 21 h1 v1 h-1Z M20 21 h1 v1 h-1Z M23 21 h1 v1 h-1Z M25 21 h1 v1 h-1Z M27 21 h3 v1 h-3Z M31 21 h1 v1 h-1Z M35 21 h1 v1 h-1Z M40 21 h3 v1 h-3Z M44 21 h3 v1 h-3Z M4 22 h1 v1 h-1Z M7 22 h1 v1 h-1Z M9 22 h1 v1 h-1Z M11 22 h8 v1 h-8Z M20 22 h1 v1 h-1Z M22 22 h1 v1 h-1Z M24 22 h2 v1 h-2Z M32 22 h2 v1 h-2Z M44 22 h3 v1 h-3Z M48 22 h1 v1 h-1Z M8 23 h2 v1 h-2Z M11 23 h1 v1 h-1Z M14 23 h2 v1 h-2Z M18 23 h4 v1 h-4Z M23 23 h2 v1 h-2Z M26 23 h1 v1 h-1Z M28 23 h5 v1 h-5Z M34 23 h5 v1 h-5Z M40 23 h1 v1 h-1Z M43 23 h1 v1 h-1Z M45 23 h2 v1 h-2Z M5 24 h2 v1 h-2Z M16 24 h3 v1 h-3Z M20 24 h1 v1 h-1Z M22 24 h2 v1 h-2Z M29 24 h1 v1 h-1Z M31 24 h1 v1 h-1Z M34 24 h1 v1 h-1Z M36 24 h1 v1 h-1Z M39 24 h1 v1 h-1Z M45 24 h1 v1 h-1Z M4 25 h2 v1 h-2Z M7 25 h1 v1 h-1Z M13 25 h7 v1 h-7Z M21 25 h3 v1 h-3Z M29 25 h2 v1 h-2Z M33 25 h1 v1 h-1Z M35 25 h1 v1 h-1Z M38 25 h1 v1 h-1Z M47 25 h1 v1 h-1Z M4 26 h1 v1 h-1Z M13 26 h4 v1 h-4Z M18 26 h1 v1 h-1Z M20 26 h1 v1 h-1Z M23 26 h1 v1 h-1Z M30 26 h2 v1 h-2Z M33 26 h3 v1 h-3Z M38 26 h1 v1 h-1Z M45 26 h2 v1 h-2Z M6 27 h1 v1 h-1Z M13 27 h1 v1 h-1Z M15 27 h1 v1 h-1Z M18 27 h1 v1 h-1Z M21 27 h2 v1 h-2Z M30 27 h1 v1 h-1Z M33 27 h2 v1 h-2Z M36 27 h1 v1 h-1Z M38 27 h2 v1 h-2Z M46 27 h1 v1 h-1Z M4 28 h1 v1 h-1Z M7 28 h1 v1 h-1Z M15 28 h2 v1 h-2Z M20 28 h1 v1 h-1Z M23 28 h1 v1 h-1Z M30 28 h1 v1 h-1Z M32 28 h3 v1 h-3Z M39 28 h1 v1 h-1Z M45 28 h2 v1 h-2Z M48 28 h1 v1 h-1Z M5 29 h4 v1 h-4Z M11 29 h5 v1 h-5Z M19 29 h2 v1 h-2Z M23 29 h1 v1 h-1Z M25 29 h1 v1 h-1Z M28 29 h3 v1 h-3Z M32 29 h2 v1 h-2Z M35 29 h2 v1 h-2Z M39 29 h3 v1 h-3Z M44 29 h1 v1 h-1Z M46 29 h2 v1 h-2Z M9 30 h1 v1 h-1Z M11 30 h1 v1 h-1Z M13 30 h1 v1 h-1Z M15 30 h3 v1 h-3Z M23 30 h2 v1 h-2Z M26 30 h3 v1 h-3Z M30 30 h1 v1 h-1Z M32 30 h1 v1 h-1Z M35 30 h1 v1 h-1Z M37 30 h1 v1 h-1Z M40 30 h5 v1 h-5Z M46 30 h2 v1 h-2Z M5 31 h2 v1 h-2Z M11 31 h1 v1 h-1Z M14 31 h5 v1 h-5Z M20 31 h1 v1 h-1Z M22 31 h1 v1 h-1Z M25 31 h4 v1 h-4Z M33 31 h1 v1 h-1Z M36 31 h2 v1 h-2Z M39 31 h3 v1 h-3Z M44 31 h2 v1 h-2Z M47 31 h1 v1 h-1Z M5 32 h1 v1 h-1Z M7 32 h3 v1 h-3Z M12 32 h2 v1 h-2Z M16 32 h1 v1 h-1Z M22 32 h1 v1 h-1Z M28 32 h1 v1 h-1Z M31 32 h3 v1 h-3Z M35 32 h1 v1 h-1Z M39 32 h2 v1 h-2Z M42 32 h1 v1 h-1Z M45 32 h2 v1 h-2Z M48 32 h1 v1 h-1Z M7 33 h2 v1 h-2Z M13 33 h1 v1 h-1Z M17 33 h2 v1 h-2Z M20 33 h1 v1 h-1Z M22 33 h1 v1 h-1Z M24 33 h1 v1 h-1Z M26 33 h2 v1 h-2Z M34 33 h3 v1 h-3Z M48 33 h1 v1 h-1Z M4 34 h6 v1 h-6Z M11 34 h4 v1 h-4Z M16 34 h4 v1 h-4Z M21 34 h1 v1 h-1Z M23 34 h1 v1 h-1Z M25 34 h3 v1 h-3Z M31 34 h3 v1 h-3Z M35 34 h2 v1 h-2Z M40 34 h1 v1 h-1Z M44 34 h5 v1 h-5Z M5 35 h2 v1 h-2Z M8 35 h1 v1 h-1Z M11 35 h2 v1 h-2Z M16 35 h1 v1 h-1Z M19 35 h1 v1 h-1Z M21 35 h1 v1 h-1Z M23 35 h5 v1 h-5Z M31 35 h2 v1 h-2Z M34 35 h3 v1 h-3Z M40 35 h2 v1 h-2Z M44 35 h2 v1 h-2Z M4 36 h4 v1 h-4Z M9 36 h1 v1 h-1Z M15 36 h4 v1 h-4Z M20 36 h2 v1 h-2Z M24 36 h1 v1 h-1Z M30 36 h2 v1 h-2Z M35 36 h5 v1 h-5Z M42 36 h1 v1 h-1Z M45 36 h4 v1 h-4Z M5 37 h1 v1 h-1Z M9 37 h1 v1 h-1Z M12 37 h2 v1 h-2Z M15 37 h1 v1 h-1Z M17 37 h2 v1 h-2Z M20 37 h1 v1 h-1Z M23 37 h2 v1 h-2Z M26 37 h2 v1 h-2Z M29 37 h2 v1 h-2Z M32 37 h2 v1 h-2Z M35 37 h1 v1 h-1Z M37 37 h3 v1 h-3Z M42 37 h1 v1 h-1Z M44 37 h1 v1 h-1Z M47 37 h2 v1 h-2Z M12 38 h1 v1 h-1Z M17 38 h1 v1 h-1Z M20 38 h1 v1 h-1Z M22 38 h1 v1 h-1Z M24 38 h1 v1 h-1Z M26 38 h4 v1 h-4Z M32 38 h1 v1 h-1Z M36 38 h2 v1 h-2Z M40 38 h2 v1 h-2Z M44 38 h1 v1 h-1Z M46 38 h1 v1 h-1Z M11 39 h1 v1 h-1Z M13 39 h2 v1 h-2Z M17 39 h1 v1 h-1Z M19 39 h4 v1 h-4Z M24 39 h1 v1 h-1Z M28 39 h1 v1 h-1Z M30 39 h3 v1 h-3Z M38 39 h1 v1 h-1Z M40 39 h4 v1 h-4Z M46 39 h2 v1 h-2Z M13 40 h1 v1 h-1Z M15 40 h3 v1 h-3Z M19 40 h3 v1 h-3Z M29 40 h3 v1 h-3Z M36 40 h2 v1 h-2Z M39 40 h1 v1 h-1Z M46 40 h1 v1 h-1Z M15 41 h7 v1 h-7Z M23 41 h1 v1 h-1Z M29 41 h1 v1 h-1Z M32 41 h1 v1 h-1Z M36 41 h1 v1 h-1Z M38 41 h2 v1 h-2Z M45 41 h4 v1 h-4Z M13 42 h1 v1 h-1Z M16 42 h1 v1 h-1Z M20 42 h4 v1 h-4Z M32 42 h3 v1 h-3Z M36 42 h4 v1 h-4Z M46 42 h3 v1 h-3Z M16 43 h2 v1 h-2Z M19 43 h1 v1 h-1Z M23 43 h1 v1 h-1Z M29 43 h2 v1 h-2Z M32 43 h3 v1 h-3Z M37 43 h1 v1 h-1Z M47 43 h2 v1 h-2Z M14 44 h1 v1 h-1Z M17 44 h4 v1 h-4Z M23 44 h1 v1 h-1Z M29 44 h1 v1 h-1Z M31 44 h1 v1 h-1Z M34 44 h1 v1 h-1Z M37 44 h1 v1 h-1Z M45 44 h1 v1 h-1Z M48 44 h1 v1 h-1Z M14 45 h2 v1 h-2Z M17 45 h1 v1 h-1Z M19 45 h1 v1 h-1Z M23 45 h6 v1 h-6Z M30 45 h3 v1 h-3Z M38 45 h2 v1 h-2Z M42 45 h2 v1 h-2Z M45 45 h2 v1 h-2Z M13 46 h1 v1 h-1Z M19 46 h4 v1 h-4Z M25 46 h3 v1 h-3Z M29 46 h1 v1 h-1Z M31 46 h2 v1 h-2Z M36 46 h1 v1 h-1Z M38 46 h1 v1 h-1Z M43 46 h1 v1 h-1Z M46 46 h3 v1 h-3Z M14 47 h1 v1 h-1Z M16 47 h2 v1 h-2Z M21 47 h1 v1 h-1Z M27 47 h7 v1 h-7Z M37 47 h2 v1 h-2Z M40 47 h2 v1 h-2Z M43 47 h1 v1 h-1Z M45 47 h3 v1 h-3Z M13 48 h1 v1 h-1Z M15 48 h1 v1 h-1Z M18 48 h1 v1 h-1Z M20 48 h1 v1 h-1Z M22 48 h3 v1 h-3Z M29 48 h2 v1 h-2Z M32 48 h1 v1 h-1Z M34 48 h1 v1 h-1Z M36 48 h1 v1 h-1Z M39 48 h3 v1 h-3Z M44 48 h1 v1 h-1Z M46 48 h3 v1 h-3Z " /><path class="qr-6 " stroke="transparent" fill="#fff" fill-opacity="1" d="M5 5 h5 v1 h-5Z M43 5 h5 v1 h-5Z M5 6 h1 v1 h-1Z M9 6 h1 v1 h-1Z M43 6 h1 v1 h-1Z M47 6 h1 v1 h-1Z M5 7 h1 v1 h-1Z M9 7 h1 v1 h-1Z M43 7 h1 v1 h-1Z M47 7 h1 v1 h-1Z M5 8 h1 v1 h-1Z M9 8 h1 v1 h-1Z M43 8 h1 v1 h-1Z M47 8 h1 v1 h-1Z M5 9 h5 v1 h-5Z M43 9 h5 v1 h-5Z M5 43 h5 v1 h-5Z M5 44 h1 v1 h-1Z M9 44 h1 v1 h-1Z M5 45 h1 v1 h-1Z M9 45 h1 v1 h-1Z M5 46 h1 v1 h-1Z M9 46 h1 v1 h-1Z M5 47 h5 v1 h-5Z " /><path class="qr-8 " stroke="transparent" fill="#fff" fill-opacity="1" d="M11 4 h1 v1 h-1Z M41 4 h1 v1 h-1Z M11 5 h1 v1 h-1Z M41 5 h1 v1 h-1Z M11 6 h1 v1 h-1Z M41 6 h1 v1 h-1Z M11 7 h1 v1 h-1Z M41 7 h1 v1 h-1Z M11 8 h1 v1 h-1Z M41 8 h1 v1 h-1Z M11 9 h1 v1 h-1Z M41 9 h1 v1 h-1Z M11 10 h1 v1 h-1Z M41 10 h1 v1 h-1Z M4 11 h8 v1 h-8Z M41 11 h8 v1 h-8Z M4 41 h8 v1 h-8Z M11 42 h1 v1 h-1Z M11 43 h1 v1 h-1Z M11 44 h1 v1 h-1Z M11 45 h1 v1 h-1Z M11 46 h1 v1 h-1Z M11 47 h1 v1 h-1Z M11 48 h1 v1 h-1Z " /><path class="qr-10 " stroke="transparent" fill="#fff" fill-opacity="1" d="M25 9 h3 v1 h-3Z M25 10 h1 v1 h-1Z M27 10 h1 v1 h-1Z M25 11 h3 v1 h-3Z M9 25 h3 v1 h-3Z M25 25 h3 v1 h-3Z M41 25 h3 v1 h-3Z M9 26 h1 v1 h-1Z M11 26 h1 v1 h-1Z M25 26 h1 v1 h-1Z M27 26 h1 v1 h-1Z M41 26 h1 v1 h-1Z M43 26 h1 v1 h-1Z M9 27 h3 v1 h-3Z M25 27 h3 v1 h-3Z M41 27 h3 v1 h-3Z M25 41 h3 v1 h-3Z M41 41 h3 v1 h-3Z M25 42 h1 v1 h-1Z M27 42 h1 v1 h-1Z M41 42 h1 v1 h-1Z M43 42 h1 v1 h-1Z M25 43 h3 v1 h-3Z M41 43 h3 v1 h-3Z " /><path class="qr-12 " stroke="transparent" fill="#fff" fill-opacity="1" d="M13 10 h1 v1 h-1Z M15 10 h1 v1 h-1Z M17 10 h1 v1 h-1Z M19 10 h1 v1 h-1Z M21 10 h1 v1 h-1Z M23 10 h1 v1 h-1Z M29 10 h1 v1 h-1Z M31 10 h1 v1 h-1Z M33 10 h1 v1 h-1Z M35 10 h1 v1 h-1Z M37 10 h1 v1 h-1Z M39 10 h1 v1 h-1Z M10 13 h1 v1 h-1Z M10 15 h1 v1 h-1Z M10 17 h1 v1 h-1Z M10 19 h1 v1 h-1Z M10 21 h1 v1 h-1Z M10 23 h1 v1 h-1Z M10 29 h1 v1 h-1Z M10 31 h1 v1 h-1Z M10 33 h1 v1 h-1Z M10 35 h1 v1 h-1Z M10 37 h1 v1 h-1Z M10 39 h1 v1 h-1Z " /><path class="qr-14 " stroke="transparent" fill="#fff" fill-opacity="1" d="M12 4 h1 v1 h-1Z M12 5 h1 v1 h-1Z M12 6 h1 v1 h-1Z M12 7 h1 v1 h-1Z M12 9 h1 v1 h-1Z M4 12 h2 v1 h-2Z M8 12 h2 v1 h-2Z M43 12 h1 v1 h-1Z M45 12 h4 v1 h-4Z M12 43 h1 v1 h-1Z M12 44 h1 v1 h-1Z M12 47 h1 v1 h-1Z M12 48 h1 v1 h-1Z " /><path class="qr-16 " stroke="transparent" fill="#fff" fill-opacity="1" d="M38 4 h2 v1 h-2Z M38 5 h1 v1 h-1Z M40 5 h1 v1 h-1Z M38 6 h1 v1 h-1Z M40 6 h1 v1 h-1Z M38 7 h1 v1 h-1Z M38 9 h3 v1 h-3Z M4 38 h4 v1 h-4Z M9 38 h1 v1 h-1Z M4 39 h1 v1 h-1Z M9 39 h1 v1 h-1Z M5 40 h2 v1 h-2Z M9 40 h1 v1 h-1Z " /><path class="qr-18 " stroke="transparent" fill="#fff" fill-opacity="1" d="M0 0 h53 v1 h-53Z M0 1 h53 v1 h-53Z M0 2 h53 v1 h-53Z M0 3 h53 v1 h-53Z M0 4 h4 v1 h-4Z M49 4 h4 v1 h-4Z M0 5 h4 v1 h-4Z M49 5 h4 v1 h-4Z M0 6 h4 v1 h-4Z M49 6 h4 v1 h-4Z M0 7 h4 v1 h-4Z M49 7 h4 v1 h-4Z M0 8 h4 v1 h-4Z M49 8 h4 v1 h-4Z M0 9 h4 v1 h-4Z M49 9 h4 v1 h-4Z M0 10 h4 v1 h-4Z M49 10 h4 v1 h-4Z M0 11 h4 v1 h-4Z M49 11 h4 v1 h-4Z M0 12 h4 v1 h-4Z M49 12 h4 v1 h-4Z M0 13 h4 v1 h-4Z M49 13 h4 v1 h-4Z M0 14 h4 v1 h-4Z M49 14 h4 v1 h-4Z M0 15 h4 v1 h-4Z M49 15 h4 v1 h-4Z M0 16 h4 v1 h-4Z M49 16 h4 v1 h-4Z M0 17 h4 v1 h-4Z M49 17 h4 v1 h-4Z M0 18 h4 v1 h-4Z M49 18 h4 v1 h-4Z M0 19 h4 v1 h-4Z M49 19 h4 v1 h-4Z M0 20 h4 v1 h-4Z M49 20 h4 v1 h-4Z M0 21 h4 v1 h-4Z M49 21 h4 v1 h-4Z M0 22 h4 v1 h-4Z M49 22 h4 v1 h-4Z M0 23 h4 v1 h-4Z M49 23 h4 v1 h-4Z M0 24 h4 v1 h-4Z M49 24 h4 v1 h-4Z M0 25 h4 v1 h-4Z M49 25 h4 v1 h-4Z M0 26 h4 v1 h-4Z M49 26 h4 v1 h-4Z M0 27 h4 v1 h-4Z M49 27 h4 v1 h-4Z M0 28 h4 v1 h-4Z M49 28 h4 v1 h-4Z M0 29 h4 v1 h-4Z M49 29 h4 v1 h-4Z M0 30 h4 v1 h-4Z M49 30 h4 v1 h-4Z M0 31 h4 v1 h-4Z M49 31 h4 v1 h-4Z M0 32 h4 v1 h-4Z M49 32 h4 v1 h-4Z M0 33 h4 v1 h-4Z M49 33 h4 v1 h-4Z M0 34 h4 v1 h-4Z M49 34 h4 v1 h-4Z M0 35 h4 v1 h-4Z M49 35 h4 v1 h-4Z M0 36 h4 v1 h-4Z M49 36 h4 v1 h-4Z M0 37 h4 v1 h-4Z M49 37 h4 v1 h-4Z M0 38 h4 v1 h-4Z M49 38 h4 v1 h-4Z M0 39 h4 v1 h-4Z M49 39 h4 v1 h-4Z M0 40 h4 v1 h-4Z M49 40 h4 v1 h-4Z M0 41 h4 v1 h-4Z M49 41 h4 v1 h-4Z M0 42 h4 v1 h-4Z M49 42 h4 v1 h-4Z M0 43 h4 v1 h-4Z M49 43 h4 v1 h-4Z M0 44 h4 v1 h-4Z M49 44 h4 v1 h-4Z M0 45 h4 v1 h-4Z M49 45 h4 v1 h-4Z M0 46 h4 v1 h-4Z M49 46 h4 v1 h-4Z M0 47 h4 v1 h-4Z M49 47 h4 v1 h-4Z M0 48 h4 v1 h-4Z M49 48 h4 v1 h-4Z M0 49 h53 v1 h-53Z M0 50 h53 v1 h-53Z M0 51 h53 v1 h-53Z M0 52 h53 v1 h-53Z " /><path class="qr-512 " stroke="transparent" fill="#000" fill-opacity="1" d="M12 41 h1 v1 h-1Z " /><path class="qr-1024 " stroke="transparent" fill="#000" fill-opacity="1" d="M13 4 h1 v1 h-1Z M16 4 h2 v1 h-2Z M19 4 h3 v1 h-3Z M27 4 h1 v1 h-1Z M29 4 h1 v1 h-1Z M32 4 h3 v1 h-3Z M36 4 h2 v1 h-2Z M14 5 h1 v1 h-1Z M17 5 h1 v1 h-1Z M19 5 h1 v1 h-1Z M21 5 h2 v1 h-2Z M24 5 h2 v1 h-2Z M29 5 h1 v1 h-1Z M32 5 h4 v1 h-4Z M37 5 h1 v1 h-1Z M13 6 h4 v1 h-4Z M18 6 h8 v1 h-8Z M27 6 h1 v1 h-1Z M30 6 h1 v1 h-1Z M33 6 h2 v1 h-2Z M16 7 h1 v1 h-1Z M20 7 h1 v1 h-1Z M29 7 h1 v1 h-1Z M31 7 h4 v1 h-4Z M37 7 h1 v1 h-1Z M14 8 h1 v1 h-1Z M17 8 h1 v1 h-1Z M21 8 h1 v1 h-1Z M31 8 h1 v1 h-1Z M33 8 h1 v1 h-1Z M35 8 h2 v1 h-2Z M14 9 h2 v1 h-2Z M18 9 h2 v1 h-2Z M21 9 h2 v1 h-2Z M30 9 h3 v1 h-3Z M34 9 h2 v1 h-2Z M37 9 h1 v1 h-1Z M14 11 h6 v1 h-6Z M30 11 h3 v1 h-3Z M36 11 h4 v1 h-4Z M14 12 h1 v1 h-1Z M19 12 h1 v1 h-1Z M21 12 h1 v1 h-1Z M30 12 h1 v1 h-1Z M36 12 h2 v1 h-2Z M7 13 h2 v1 h-2Z M13 13 h1 v1 h-1Z M16 13 h2 v1 h-2Z M20 13 h1 v1 h-1Z M22 13 h1 v1 h-1Z M24 13 h1 v1 h-1Z M26 13 h1 v1 h-1Z M30 13 h1 v1 h-1Z M33 13 h2 v1 h-2Z M36 13 h2 v1 h-2Z M39 13 h1 v1 h-1Z M41 13 h4 v1 h-4Z M46 13 h1 v1 h-1Z M4 14 h1 v1 h-1Z M9 14 h1 v1 h-1Z M12 14 h1 v1 h-1Z M17 14 h2 v1 h-2Z M20 14 h1 v1 h-1Z M23 14 h1 v1 h-1Z M25 14 h1 v1 h-1Z M27 14 h2 v1 h-2Z M30 14 h1 v1 h-1Z M32 14 h4 v1 h-4Z M38 14 h3 v1 h-3Z M42 14 h3 v1 h-3Z M47 14 h1 v1 h-1Z M4 15 h3 v1 h-3Z M8 15 h1 v1 h-1Z M11 15 h1 v1 h-1Z M14 15 h2 v1 h-2Z M20 15 h1 v1 h-1Z M22 15 h1 v1 h-1Z M26 15 h1 v1 h-1Z M29 15 h2 v1 h-2Z M36 15 h1 v1 h-1Z M39 15 h3 v1 h-3Z M43 15 h2 v1 h-2Z M47 15 h2 v1 h-2Z M4 16 h3 v1 h-3Z M8 16 h2 v1 h-2Z M14 16 h3 v1 h-3Z M18 16 h1 v1 h-1Z M20 16 h2 v1 h-2Z M25 16 h1 v1 h-1Z M28 16 h3 v1 h-3Z M33 16 h3 v1 h-3Z M43 16 h1 v1 h-1Z M45 16 h4 v1 h-4Z M7 17 h1 v1 h-1Z M9 17 h1 v1 h-1Z M12 17 h1 v1 h-1Z M14 17 h1 v1 h-1Z M17 17 h1 v1 h-1Z M22 17 h2 v1 h-2Z M28 17 h3 v1 h-3Z M33 17 h1 v1 h-1Z M35 17 h2 v1 h-2Z M41 17 h3 v1 h-3Z M45 17 h3 v1 h-3Z M6 18 h2 v1 h-2Z M12 18 h4 v1 h-4Z M18 18 h1 v1 h-1Z M22 18 h1 v1 h-1Z M26 18 h1 v1 h-1Z M30 18 h1 v1 h-1Z M32 18 h2 v1 h-2Z M35 18 h1 v1 h-1Z M39 18 h2 v1 h-2Z M42 18 h1 v1 h-1Z M44 18 h1 v1 h-1Z M4 19 h4 v1 h-4Z M12 19 h1 v1 h-1Z M14 19 h1 v1 h-1Z M16 19 h1 v1 h-1Z M18 19 h1 v1 h-1Z M20 19 h1 v1 h-1Z M22 19 h2 v1 h-2Z M25 19 h7 v1 h-7Z M33 19 h1 v1 h-1Z M36 19 h1 v1 h-1Z M39 19 h1 v1 h-1Z M44 19 h3 v1 h-3Z M4 20 h1 v1 h-1Z M7 20 h2 v1 h-2Z M11 20 h1 v1 h-1Z M14 20 h2 v1 h-2Z M18 20 h2 v1 h-2Z M21 20 h3 v1 h-3Z M26 20 h1 v1 h-1Z M31 20 h6 v1 h-6Z M40 20 h4 v1 h-4Z M46 20 h1 v1 h-1Z M5 21 h1 v1 h-1Z M8 21 h1 v1 h-1Z M11 21 h2 v1 h-2Z M14 21 h4 v1 h-4Z M19 21 h1 v1 h-1Z M21 21 h2 v1 h-2Z M24 21 h1 v1 h-1Z M26 21 h1 v1 h-1Z M30 21 h1 v1 h-1Z M32 21 h3 v1 h-3Z M36 21 h4 v1 h-4Z M43 21 h1 v1 h-1Z M47 21 h2 v1 h-2Z M5 22 h2 v1 h-2Z M8 22 h1 v1 h-1Z M19 22 h1 v1 h-1Z M21 22 h1 v1 h-1Z M23 22 h1 v1 h-1Z M26 22 h6 v1 h-6Z M34 22 h10 v1 h-10Z M47 22 h1 v1 h-1Z M4 23 h4 v1 h-4Z M12 23 h2 v1 h-2Z M16 23 h2 v1 h-2Z M22 23 h1 v1 h-1Z M25 23 h1 v1 h-1Z M27 23 h1 v1 h-1Z M33 23 h1 v1 h-1Z M39 23 h1 v1 h-1Z M41 23 h2 v1 h-2Z M44 23 h1 v1 h-1Z M47 23 h2 v1 h-2Z M4 24 h1 v1 h-1Z M7 24 h1 v1 h-1Z M13 24 h3 v1 h-3Z M19 24 h1 v1 h-1Z M21 24 h1 v1 h-1Z M30 24 h1 v1 h-1Z M32 24 h2 v1 h-2Z M35 24 h1 v1 h-1Z M37 24 h2 v1 h-2Z M46 24 h3 v1 h-3Z M6 25 h1 v1 h-1Z M20 25 h1 v1 h-1Z M31 25 h2 v1 h-2Z M34 25 h1 v1 h-1Z M36 25 h2 v1 h-2Z M39 25 h1 v1 h-1Z M45 25 h2 v1 h-2Z M48 25 h1 v1 h-1Z M5 26 h3 v1 h-3Z M17 26 h1 v1 h-1Z M19 26 h1 v1 h-1Z M21 26 h2 v1 h-2Z M29 26 h1 v1 h-1Z M32 26 h1 v1 h-1Z M36 26 h2 v1 h-2Z M39 26 h1 v1 h-1Z M47 26 h2 v1 h-2Z M4 27 h2 v1 h-2Z M7 27 h1 v1 h-1Z M14 27 h1 v1 h-1Z M16 27 h2 v1 h-2Z M19 27 h2 v1 h-2Z M23 27 h1 v1 h-1Z M29 27 h1 v1 h-1Z M31 27 h2 v1 h-2Z M35 27 h1 v1 h-1Z M37 27 h1 v1 h-1Z M45 27 h1 v1 h-1Z M47 27 h2 v1 h-2Z M5 28 h2 v1 h-2Z M13 28 h2 v1 h-2Z M17 28 h3 v1 h-3Z M21 28 h2 v1 h-2Z M29 28 h1 v1 h-1Z M31 28 h1 v1 h-1Z M35 28 h4 v1 h-4Z M47 28 h1 v1 h-1Z M4 29 h1 v1 h-1Z M9 29 h1 v1 h-1Z M16 29 h3 v1 h-3Z M21 29 h2 v1 h-2Z M24 29 h1 v1 h-1Z M26 29 h2 v1 h-2Z M31 29 h1 v1 h-1Z M34 29 h1 v1 h-1Z M37 29 h2 v1 h-2Z M42 29 h2 v1 h-2Z M45 29 h1 v1 h-1Z M48 29 h1 v1 h-1Z M4 30 h5 v1 h-5Z M12 30 h1 v1 h-1Z M14 30 h1 v1 h-1Z M18 30 h5 v1 h-5Z M25 30 h1 v1 h-1Z M29 30 h1 v1 h-1Z M31 30 h1 v1 h-1Z M33 30 h2 v1 h-2Z M36 30 h1 v1 h-1Z M38 30 h2 v1 h-2Z M45 30 h1 v1 h-1Z M48 30 h1 v1 h-1Z M4 31 h1 v1 h-1Z M7 31 h3 v1 h-3Z M12 31 h2 v1 h-2Z M19 31 h1 v1 h-1Z M21 31 h1 v1 h-1Z M23 31 h2 v1 h-2Z M29 31 h4 v1 h-4Z M34 31 h2 v1 h-2Z M38 31 h1 v1 h-1Z M42 31 h2 v1 h-2Z M46 31 h1 v1 h-1Z M48 31 h1 v1 h-1Z M4 32 h1 v1 h-1Z M6 32 h1 v1 h-1Z M11 32 h1 v1 h-1Z M14 32 h2 v1 h-2Z M17 32 h5 v1 h-5Z M23 32 h5 v1 h-5Z M29 32 h2 v1 h-2Z M34 32 h1 v1 h-1Z M36 32 h3 v1 h-3Z M41 32 h1 v1 h-1Z M43 32 h2 v1 h-2Z M47 32 h1 v1 h-1Z M4 33 h3 v1 h-3Z M9 33 h1 v1 h-1Z M11 33 h2 v1 h-2Z M14 33 h3 v1 h-3Z M19 33 h1 v1 h-1Z M21 33 h1 v1 h-1Z M23 33 h1 v1 h-1Z M25 33 h1 v1 h-1Z M28 33 h6 v1 h-6Z M37 33 h11 v1 h-11Z M15 34 h1 v1 h-1Z M20 34 h1 v1 h-1Z M22 34 h1 v1 h-1Z M24 34 h1 v1 h-1Z M28 34 h3 v1 h-3Z M34 34 h1 v1 h-1Z M37 34 h3 v1 h-3Z M41 34 h3 v1 h-3Z M4 35 h1 v1 h-1Z M7 35 h1 v1 h-1Z M9 35 h1 v1 h-1Z M13 35 h3 v1 h-3Z M17 35 h2 v1 h-2Z M20 35 h1 v1 h-1Z M22 35 h1 v1 h-1Z M28 35 h3 v1 h-3Z M33 35 h1 v1 h-1Z M37 35 h3 v1 h-3Z M42 35 h2 v1 h-2Z M46 35 h3 v1 h-3Z M8 36 h1 v1 h-1Z M11 36 h4 v1 h-4Z M19 36 h1 v1 h-1Z M22 36 h2 v1 h-2Z M25 36 h5 v1 h-5Z M32 36 h3 v1 h-3Z M40 36 h2 v1 h-2Z M43 36 h2 v1 h-2Z M4 37 h1 v1 h-1Z M6 37 h3 v1 h-3Z M11 37 h1 v1 h-1Z M14 37 h1 v1 h-1Z M16 37 h1 v1 h-1Z M19 37 h1 v1 h-1Z M21 37 h2 v1 h-2Z M25 37 h1 v1 h-1Z M28 37 h1 v1 h-1Z M31 37 h1 v1 h-1Z M34 37 h1 v1 h-1Z M36 37 h1 v1 h-1Z M40 37 h2 v1 h-2Z M43 37 h1 v1 h-1Z M45 37 h2 v1 h-2Z M11 38 h1 v1 h-1Z M13 38 h4 v1 h-4Z M18 38 h2 v1 h-2Z M21 38 h1 v1 h-1Z M23 38 h1 v1 h-1Z M25 38 h1 v1 h-1Z M30 38 h2 v1 h-2Z M33 38 h3 v1 h-3Z M38 38 h2 v1 h-2Z M42 38 h2 v1 h-2Z M45 38 h1 v1 h-1Z M47 38 h2 v1 h-2Z M12 39 h1 v1 h-1Z M15 39 h2 v1 h-2Z M18 39 h1 v1 h-1Z M23 39 h1 v1 h-1Z M25 39 h3 v1 h-3Z M29 39 h1 v1 h-1Z M33 39 h5 v1 h-5Z M39 39 h1 v1 h-1Z M44 39 h2 v1 h-2Z M48 39 h1 v1 h-1Z M11 40 h2 v1 h-2Z M14 40 h1 v1 h-1Z M18 40 h1 v1 h-1Z M22 40 h2 v1 h-2Z M32 40 h4 v1 h-4Z M38 40 h1 v1 h-1Z M45 40 h1 v1 h-1Z M47 40 h2 v1 h-2Z M13 41 h2 v1 h-2Z M22 41 h1 v1 h-1Z M30 41 h2 v1 h-2Z M33 41 h3 v1 h-3Z M37 41 h1 v1 h-1Z M14 42 h2 v1 h-2Z M17 42 h3 v1 h-3Z M29 42 h3 v1 h-3Z M35 42 h1 v1 h-1Z M45 42 h1 v1 h-1Z M13 43 h3 v1 h-3Z M18 43 h1 v1 h-1Z M20 43 h3 v1 h-3Z M31 43 h1 v1 h-1Z M35 43 h2 v1 h-2Z M38 43 h2 v1 h-2Z M45 43 h2 v1 h-2Z M13 44 h1 v1 h-1Z M15 44 h2 v1 h-2Z M21 44 h2 v1 h-2Z M30 44 h1 v1 h-1Z M32 44 h2 v1 h-2Z M35 44 h2 v1 h-2Z M38 44 h2 v1 h-2Z M46 44 h2 v1 h-2Z M13 45 h1 v1 h-1Z M16 45 h1 v1 h-1Z M18 45 h1 v1 h-1Z M20 45 h3 v1 h-3Z M29 45 h1 v1 h-1Z M33 45 h5 v1 h-5Z M40 45 h2 v1 h-2Z M44 45 h1 v1 h-1Z M47 45 h2 v1 h-2Z M14 46 h5 v1 h-5Z M23 46 h2 v1 h-2Z M28 46 h1 v1 h-1Z M30 46 h1 v1 h-1Z M33 46 h3 v1 h-3Z M37 46 h1 v1 h-1Z M39 46 h4 v1 h-4Z M44 46 h2 v1 h-2Z M13 47 h1 v1 h-1Z M15 47 h1 v1 h-1Z M18 47 h3 v1 h-3Z M22 47 h5 v1 h-5Z M34 47 h3 v1 h-3Z M39 47 h1 v1 h-1Z M42 47 h1 v1 h-1Z M44 47 h1 v1 h-1Z M48 47 h1 v1 h-1Z M14 48 h1 v1 h-1Z M16 48 h2 v1 h-2Z M19 48 h1 v1 h-1Z M21 48 h1 v1 h-1Z M25 48 h4 v1 h-4Z M31 48 h1 v1 h-1Z M33 48 h1 v1 h-1Z M35 48 h1 v1 h-1Z M37 48 h2 v1 h-2Z M42 48 h2 v1 h-2Z M45 48 h1 v1 h-1Z " /><path class="qr-1536 " stroke="transparent" fill="#000" fill-opacity="1" d="M4 4 h7 v1 h-7Z M42 4 h7 v1 h-7Z M4 5 h1 v1 h-1Z M10 5 h1 v1 h-1Z M42 5 h1 v1 h-1Z M48 5 h1 v1 h-1Z M4 6 h1 v1 h-1Z M10 6 h1 v1 h-1Z M42 6 h1 v1 h-1Z M48 6 h1 v1 h-1Z M4 7 h1 v1 h-1Z M10 7 h1 v1 h-1Z M42 7 h1 v1 h-1Z M48 7 h1 v1 h-1Z M4 8 h1 v1 h-1Z M10 8 h1 v1 h-1Z M42 8 h1 v1 h-1Z M48 8 h1 v1 h-1Z M4 9 h1 v1 h-1Z M10 9 h1 v1 h-1Z M42 9 h1 v1 h-1Z M48 9 h1 v1 h-1Z M4 10 h7 v1 h-7Z M42 10 h7 v1 h-7Z M4 42 h7 v1 h-7Z M4 43 h1 v1 h-1Z M10 43 h1 v1 h-1Z M4 44 h1 v1 h-1Z M10 44 h1 v1 h-1Z M4 45 h1 v1 h-1Z M10 45 h1 v1 h-1Z M4 46 h1 v1 h-1Z M10 46 h1 v1 h-1Z M4 47 h1 v1 h-1Z M10 47 h1 v1 h-1Z M4 48 h7 v1 h-7Z " /><path class="qr-2560 " stroke="transparent" fill="#000" fill-opacity="1" d="M24 8 h5 v1 h-5Z M24 9 h1 v1 h-1Z M28 9 h1 v1 h-1Z M24 10 h1 v1 h-1Z M26 10 h1 v1 h-1Z M28 10 h1 v1 h-1Z M24 11 h1 v1 h-1Z M28 11 h1 v1 h-1Z M24 12 h5 v1 h-5Z M8 24 h5 v1 h-5Z M24 24 h5 v1 h-5Z M40 24 h5 v1 h-5Z M8 25 h1 v1 h-1Z M12 25 h1 v1 h-1Z M24 25 h1 v1 h-1Z M28 25 h1 v1 h-1Z M40 25 h1 v1 h-1Z M44 25 h1 v1 h-1Z M8 26 h1 v1 h-1Z M10 26 h1 v1 h-1Z M12 26 h1 v1 h-1Z M24 26 h1 v1 h-1Z M26 26 h1 v1 h-1Z M28 26 h1 v1 h-1Z M40 26 h1 v1 h-1Z M42 26 h1 v1 h-1Z M44 26 h1 v1 h-1Z M8 27 h1 v1 h-1Z M12 27 h1 v1 h-1Z M24 27 h1 v1 h-1Z M28 27 h1 v1 h-1Z M40 27 h1 v1 h-1Z M44 27 h1 v1 h-1Z M8 28 h5 v1 h-5Z M24 28 h5 v1 h-5Z M40 28 h5 v1 h-5Z M24 40 h5 v1 h-5Z M40 40 h5 v1 h-5Z M24 41 h1 v1 h-1Z M28 41 h1 v1 h-1Z M40 41 h1 v1 h-1Z M44 41 h1 v1 h-1Z M24 42 h1 v1 h-1Z M26 42 h1 v1 h-1Z M28 42 h1 v1 h-1Z M40 42 h1 v1 h-1Z M42 42 h1 v1 h-1Z M44 42 h1 v1 h-1Z M24 43 h1 v1 h-1Z M28 43 h1 v1 h-1Z M40 43 h1 v1 h-1Z M44 43 h1 v1 h-1Z M24 44 h5 v1 h-5Z M40 44 h5 v1 h-5Z " /><path class="qr-3072 " stroke="transparent" fill="#000" fill-opacity="1" d="M12 10 h1 v1 h-1Z M14 10 h1 v1 h-1Z M16 10 h1 v1 h-1Z M18 10 h1 v1 h-1Z M20 10 h1 v1 h-1Z M22 10 h1 v1 h-1Z M30 10 h1 v1 h-1Z M32 10 h1 v1 h-1Z M34 10 h1 v1 h-1Z M36 10 h1 v1 h-1Z M38 10 h1 v1 h-1Z M40 10 h1 v1 h-1Z M10 12 h1 v1 h-1Z M10 14 h1 v1 h-1Z M10 16 h1 v1 h-1Z M10 18 h1 v1 h-1Z M10 20 h1 v1 h-1Z M10 22 h1 v1 h-1Z M10 30 h1 v1 h-1Z M10 32 h1 v1 h-1Z M10 34 h1 v1 h-1Z M10 36 h1 v1 h-1Z M10 38 h1 v1 h-1Z M10 40 h1 v1 h-1Z " /><path class="qr-3584 " stroke="transparent" fill="#000" fill-opacity="1" d="M12 8 h1 v1 h-1Z M12 11 h1 v1 h-1Z M6 12 h2 v1 h-2Z M11 12 h2 v1 h-2Z M41 12 h2 v1 h-2Z M44 12 h1 v1 h-1Z M12 42 h1 v1 h-1Z M12 45 h1 v1 h-1Z M12 46 h1 v1 h-1Z " /><path class="qr-4096 " stroke="transparent" fill="#000" fill-opacity="1" d="M40 4 h1 v1 h-1Z M39 5 h1 v1 h-1Z M39 6 h1 v1 h-1Z M39 7 h2 v1 h-2Z M38 8 h3 v1 h-3Z M8 38 h1 v1 h-1Z M5 39 h4 v1 h-4Z M4 40 h1 v1 h-1Z M7 40 h2 v1 h-2Z " /><path class="qr-5632 " stroke="transparent" fill="#000" fill-opacity="1" d="M6 6 h3 v1 h-3Z M44 6 h3 v1 h-3Z M6 7 h3 v1 h-3Z M44 7 h3 v1 h-3Z M6 8 h3 v1 h-3Z M44 8 h3 v1 h-3Z M6 44 h3 v1 h-3Z M6 45 h3 v1 h-3Z M6 46 h3 v1 h-3Z " /></svg>

    </a>
    <figcaption aria-hidden="true" class="hidden" hidden>Donate for Stéphane HUC by Liberapay</figcaption>
</figure>


<h3 id="paypal">Paypal</h3>
<ul>
<li><a href="https://paypal.me/hucste" rel="external">https://paypal.me/hucste</a></li>
</ul>


<figure class="pure-img">
    <a href="/svg/qrcode/paypal.svg" title="Donate for Stéphane HUC by Paypal">
    <svg xmlns="http://www.w3.org/2000/svg" class="qr-svg " height="128" viewBox="0 0 53 53" width="128">
<defs><style>rect{shape-rendering:crispEdges}</style></defs>
<path class="qr-4 " stroke="transparent" fill="#fff" fill-opacity="1" d="M15 4 h1 v1 h-1Z M18 4 h3 v1 h-3Z M24 4 h1 v1 h-1Z M27 4 h7 v1 h-7Z M35 4 h1 v1 h-1Z M16 5 h6 v1 h-6Z M25 5 h2 v1 h-2Z M29 5 h4 v1 h-4Z M34 5 h1 v1 h-1Z M36 5 h1 v1 h-1Z M13 6 h5 v1 h-5Z M19 6 h7 v1 h-7Z M30 6 h2 v1 h-2Z M35 6 h2 v1 h-2Z M13 7 h1 v1 h-1Z M15 7 h1 v1 h-1Z M17 7 h1 v1 h-1Z M20 7 h3 v1 h-3Z M25 7 h4 v1 h-4Z M32 7 h1 v1 h-1Z M35 7 h1 v1 h-1Z M37 7 h1 v1 h-1Z M13 8 h1 v1 h-1Z M15 8 h1 v1 h-1Z M18 8 h2 v1 h-2Z M22 8 h1 v1 h-1Z M29 8 h1 v1 h-1Z M31 8 h2 v1 h-2Z M13 9 h1 v1 h-1Z M15 9 h1 v1 h-1Z M21 9 h2 v1 h-2Z M29 9 h1 v1 h-1Z M31 9 h1 v1 h-1Z M35 9 h2 v1 h-2Z M13 11 h4 v1 h-4Z M19 11 h4 v1 h-4Z M29 11 h2 v1 h-2Z M34 11 h1 v1 h-1Z M39 11 h1 v1 h-1Z M17 12 h1 v1 h-1Z M19 12 h1 v1 h-1Z M29 12 h1 v1 h-1Z M32 12 h4 v1 h-4Z M37 12 h3 v1 h-3Z M5 13 h1 v1 h-1Z M8 13 h1 v1 h-1Z M11 13 h2 v1 h-2Z M15 13 h1 v1 h-1Z M17 13 h2 v1 h-2Z M21 13 h3 v1 h-3Z M34 13 h4 v1 h-4Z M40 13 h1 v1 h-1Z M42 13 h4 v1 h-4Z M47 13 h1 v1 h-1Z M4 14 h3 v1 h-3Z M8 14 h1 v1 h-1Z M12 14 h3 v1 h-3Z M16 14 h1 v1 h-1Z M18 14 h2 v1 h-2Z M21 14 h1 v1 h-1Z M24 14 h1 v1 h-1Z M30 14 h1 v1 h-1Z M36 14 h1 v1 h-1Z M40 14 h2 v1 h-2Z M43 14 h1 v1 h-1Z M45 14 h1 v1 h-1Z M48 14 h1 v1 h-1Z M4 15 h2 v1 h-2Z M8 15 h2 v1 h-2Z M12 15 h1 v1 h-1Z M22 15 h1 v1 h-1Z M24 15 h2 v1 h-2Z M27 15 h3 v1 h-3Z M31 15 h2 v1 h-2Z M36 15 h1 v1 h-1Z M39 15 h4 v1 h-4Z M47 15 h1 v1 h-1Z M5 16 h1 v1 h-1Z M9 16 h1 v1 h-1Z M11 16 h2 v1 h-2Z M14 16 h3 v1 h-3Z M18 16 h5 v1 h-5Z M25 16 h1 v1 h-1Z M27 16 h1 v1 h-1Z M29 16 h2 v1 h-2Z M32 16 h2 v1 h-2Z M37 16 h1 v1 h-1Z M39 16 h1 v1 h-1Z M45 16 h1 v1 h-1Z M47 16 h2 v1 h-2Z M8 17 h1 v1 h-1Z M11 17 h1 v1 h-1Z M13 17 h1 v1 h-1Z M17 17 h1 v1 h-1Z M19 17 h1 v1 h-1Z M22 17 h3 v1 h-3Z M28 17 h2 v1 h-2Z M31 17 h3 v1 h-3Z M35 17 h1 v1 h-1Z M38 17 h2 v1 h-2Z M41 17 h1 v1 h-1Z M44 17 h4 v1 h-4Z M5 18 h1 v1 h-1Z M9 18 h1 v1 h-1Z M12 18 h2 v1 h-2Z M15 18 h3 v1 h-3Z M20 18 h3 v1 h-3Z M24 18 h2 v1 h-2Z M28 18 h2 v1 h-2Z M31 18 h2 v1 h-2Z M36 18 h1 v1 h-1Z M38 18 h1 v1 h-1Z M41 18 h1 v1 h-1Z M45 18 h1 v1 h-1Z M48 18 h1 v1 h-1Z M6 19 h2 v1 h-2Z M9 19 h1 v1 h-1Z M11 19 h1 v1 h-1Z M14 19 h1 v1 h-1Z M16 19 h2 v1 h-2Z M20 19 h2 v1 h-2Z M23 19 h1 v1 h-1Z M25 19 h2 v1 h-2Z M28 19 h1 v1 h-1Z M31 19 h2 v1 h-2Z M34 19 h3 v1 h-3Z M38 19 h2 v1 h-2Z M43 19 h1 v1 h-1Z M4 20 h1 v1 h-1Z M6 20 h2 v1 h-2Z M9 20 h1 v1 h-1Z M11 20 h1 v1 h-1Z M16 20 h1 v1 h-1Z M18 20 h6 v1 h-6Z M25 20 h3 v1 h-3Z M29 20 h4 v1 h-4Z M34 20 h1 v1 h-1Z M39 20 h2 v1 h-2Z M43 20 h1 v1 h-1Z M45 20 h3 v1 h-3Z M4 21 h2 v1 h-2Z M11 21 h1 v1 h-1Z M13 21 h1 v1 h-1Z M20 21 h1 v1 h-1Z M23 21 h1 v1 h-1Z M25 21 h2 v1 h-2Z M28 21 h1 v1 h-1Z M30 21 h2 v1 h-2Z M33 21 h4 v1 h-4Z M38 21 h2 v1 h-2Z M41 21 h7 v1 h-7Z M4 22 h1 v1 h-1Z M6 22 h3 v1 h-3Z M11 22 h1 v1 h-1Z M15 22 h2 v1 h-2Z M18 22 h1 v1 h-1Z M21 22 h1 v1 h-1Z M23 22 h3 v1 h-3Z M30 22 h1 v1 h-1Z M32 22 h1 v1 h-1Z M35 22 h1 v1 h-1Z M42 22 h3 v1 h-3Z M47 22 h1 v1 h-1Z M5 23 h1 v1 h-1Z M7 23 h3 v1 h-3Z M13 23 h2 v1 h-2Z M16 23 h5 v1 h-5Z M23 23 h1 v1 h-1Z M26 23 h1 v1 h-1Z M29 23 h3 v1 h-3Z M33 23 h1 v1 h-1Z M35 23 h6 v1 h-6Z M43 23 h1 v1 h-1Z M45 23 h1 v1 h-1Z M47 23 h1 v1 h-1Z M4 24 h2 v1 h-2Z M7 24 h1 v1 h-1Z M13 24 h1 v1 h-1Z M15 24 h1 v1 h-1Z M17 24 h2 v1 h-2Z M23 24 h1 v1 h-1Z M29 24 h1 v1 h-1Z M32 24 h1 v1 h-1Z M35 24 h3 v1 h-3Z M39 24 h1 v1 h-1Z M45 24 h2 v1 h-2Z M48 24 h1 v1 h-1Z M6 25 h1 v1 h-1Z M13 25 h2 v1 h-2Z M16 25 h2 v1 h-2Z M19 25 h1 v1 h-1Z M21 25 h1 v1 h-1Z M29 25 h1 v1 h-1Z M31 25 h3 v1 h-3Z M37 25 h1 v1 h-1Z M46 25 h3 v1 h-3Z M6 26 h2 v1 h-2Z M13 26 h3 v1 h-3Z M18 26 h1 v1 h-1Z M20 26 h2 v1 h-2Z M31 26 h1 v1 h-1Z M33 26 h1 v1 h-1Z M35 26 h1 v1 h-1Z M37 26 h2 v1 h-2Z M46 26 h1 v1 h-1Z M5 27 h3 v1 h-3Z M16 27 h3 v1 h-3Z M22 27 h1 v1 h-1Z M30 27 h2 v1 h-2Z M33 27 h4 v1 h-4Z M38 27 h1 v1 h-1Z M45 27 h4 v1 h-4Z M6 28 h2 v1 h-2Z M14 28 h1 v1 h-1Z M16 28 h3 v1 h-3Z M20 28 h1 v1 h-1Z M23 28 h1 v1 h-1Z M31 28 h1 v1 h-1Z M34 28 h3 v1 h-3Z M38 28 h1 v1 h-1Z M48 28 h1 v1 h-1Z M5 29 h3 v1 h-3Z M9 29 h1 v1 h-1Z M12 29 h1 v1 h-1Z M14 29 h1 v1 h-1Z M16 29 h2 v1 h-2Z M20 29 h1 v1 h-1Z M22 29 h2 v1 h-2Z M25 29 h2 v1 h-2Z M28 29 h1 v1 h-1Z M31 29 h2 v1 h-2Z M34 29 h1 v1 h-1Z M36 29 h1 v1 h-1Z M41 29 h1 v1 h-1Z M44 29 h2 v1 h-2Z M5 30 h1 v1 h-1Z M7 30 h3 v1 h-3Z M11 30 h1 v1 h-1Z M13 30 h1 v1 h-1Z M15 30 h1 v1 h-1Z M18 30 h2 v1 h-2Z M25 30 h6 v1 h-6Z M32 30 h1 v1 h-1Z M35 30 h1 v1 h-1Z M42 30 h2 v1 h-2Z M47 30 h1 v1 h-1Z M5 31 h1 v1 h-1Z M7 31 h3 v1 h-3Z M11 31 h2 v1 h-2Z M15 31 h2 v1 h-2Z M19 31 h1 v1 h-1Z M24 31 h1 v1 h-1Z M31 31 h2 v1 h-2Z M38 31 h3 v1 h-3Z M44 31 h2 v1 h-2Z M47 31 h2 v1 h-2Z M5 32 h2 v1 h-2Z M8 32 h1 v1 h-1Z M13 32 h2 v1 h-2Z M16 32 h1 v1 h-1Z M19 32 h5 v1 h-5Z M25 32 h1 v1 h-1Z M27 32 h1 v1 h-1Z M30 32 h1 v1 h-1Z M32 32 h4 v1 h-4Z M37 32 h1 v1 h-1Z M39 32 h1 v1 h-1Z M42 32 h2 v1 h-2Z M45 32 h1 v1 h-1Z M48 32 h1 v1 h-1Z M7 33 h1 v1 h-1Z M9 33 h1 v1 h-1Z M11 33 h2 v1 h-2Z M15 33 h2 v1 h-2Z M18 33 h6 v1 h-6Z M26 33 h1 v1 h-1Z M28 33 h1 v1 h-1Z M36 33 h1 v1 h-1Z M39 33 h3 v1 h-3Z M45 33 h2 v1 h-2Z M48 33 h1 v1 h-1Z M4 34 h1 v1 h-1Z M6 34 h4 v1 h-4Z M11 34 h1 v1 h-1Z M13 34 h1 v1 h-1Z M15 34 h1 v1 h-1Z M19 34 h2 v1 h-2Z M29 34 h1 v1 h-1Z M31 34 h1 v1 h-1Z M33 34 h1 v1 h-1Z M37 34 h6 v1 h-6Z M46 34 h1 v1 h-1Z M4 35 h1 v1 h-1Z M8 35 h1 v1 h-1Z M12 35 h3 v1 h-3Z M16 35 h2 v1 h-2Z M20 35 h1 v1 h-1Z M22 35 h1 v1 h-1Z M24 35 h3 v1 h-3Z M28 35 h2 v1 h-2Z M31 35 h4 v1 h-4Z M37 35 h3 v1 h-3Z M44 35 h1 v1 h-1Z M46 35 h2 v1 h-2Z M5 36 h3 v1 h-3Z M9 36 h1 v1 h-1Z M11 36 h2 v1 h-2Z M14 36 h1 v1 h-1Z M16 36 h2 v1 h-2Z M19 36 h1 v1 h-1Z M21 36 h2 v1 h-2Z M24 36 h3 v1 h-3Z M28 36 h1 v1 h-1Z M30 36 h6 v1 h-6Z M37 36 h4 v1 h-4Z M42 36 h2 v1 h-2Z M45 36 h1 v1 h-1Z M48 36 h1 v1 h-1Z M5 37 h2 v1 h-2Z M8 37 h2 v1 h-2Z M11 37 h2 v1 h-2Z M14 37 h2 v1 h-2Z M17 37 h1 v1 h-1Z M20 37 h1 v1 h-1Z M23 37 h1 v1 h-1Z M26 37 h2 v1 h-2Z M29 37 h1 v1 h-1Z M31 37 h3 v1 h-3Z M35 37 h2 v1 h-2Z M39 37 h1 v1 h-1Z M43 37 h1 v1 h-1Z M47 37 h1 v1 h-1Z M12 38 h2 v1 h-2Z M15 38 h1 v1 h-1Z M19 38 h2 v1 h-2Z M22 38 h1 v1 h-1Z M24 38 h1 v1 h-1Z M26 38 h4 v1 h-4Z M31 38 h2 v1 h-2Z M34 38 h1 v1 h-1Z M36 38 h2 v1 h-2Z M41 38 h1 v1 h-1Z M43 38 h2 v1 h-2Z M48 38 h1 v1 h-1Z M11 39 h1 v1 h-1Z M13 39 h2 v1 h-2Z M17 39 h4 v1 h-4Z M22 39 h3 v1 h-3Z M26 39 h1 v1 h-1Z M28 39 h4 v1 h-4Z M34 39 h1 v1 h-1Z M37 39 h1 v1 h-1Z M40 39 h1 v1 h-1Z M42 39 h2 v1 h-2Z M45 39 h1 v1 h-1Z M47 39 h1 v1 h-1Z M12 40 h4 v1 h-4Z M17 40 h3 v1 h-3Z M23 40 h1 v1 h-1Z M30 40 h6 v1 h-6Z M37 40 h1 v1 h-1Z M39 40 h1 v1 h-1Z M45 40 h4 v1 h-4Z M17 41 h6 v1 h-6Z M29 41 h3 v1 h-3Z M35 41 h5 v1 h-5Z M46 41 h1 v1 h-1Z M48 41 h1 v1 h-1Z M13 42 h1 v1 h-1Z M16 42 h1 v1 h-1Z M19 42 h4 v1 h-4Z M29 42 h1 v1 h-1Z M31 42 h1 v1 h-1Z M36 42 h2 v1 h-2Z M45 42 h4 v1 h-4Z M20 43 h3 v1 h-3Z M29 43 h1 v1 h-1Z M33 43 h4 v1 h-4Z M38 43 h1 v1 h-1Z M47 43 h1 v1 h-1Z M13 44 h2 v1 h-2Z M16 44 h1 v1 h-1Z M19 44 h3 v1 h-3Z M29 44 h1 v1 h-1Z M31 44 h2 v1 h-2Z M39 44 h1 v1 h-1Z M46 44 h2 v1 h-2Z M13 45 h2 v1 h-2Z M16 45 h3 v1 h-3Z M21 45 h1 v1 h-1Z M24 45 h1 v1 h-1Z M27 45 h2 v1 h-2Z M31 45 h6 v1 h-6Z M38 45 h1 v1 h-1Z M40 45 h4 v1 h-4Z M48 45 h1 v1 h-1Z M13 46 h2 v1 h-2Z M17 46 h2 v1 h-2Z M20 46 h1 v1 h-1Z M24 46 h2 v1 h-2Z M27 46 h1 v1 h-1Z M29 46 h1 v1 h-1Z M31 46 h3 v1 h-3Z M39 46 h1 v1 h-1Z M41 46 h5 v1 h-5Z M14 47 h2 v1 h-2Z M20 47 h1 v1 h-1Z M22 47 h1 v1 h-1Z M24 47 h1 v1 h-1Z M26 47 h3 v1 h-3Z M31 47 h5 v1 h-5Z M37 47 h2 v1 h-2Z M40 47 h1 v1 h-1Z M43 47 h1 v1 h-1Z M45 47 h1 v1 h-1Z M13 48 h1 v1 h-1Z M15 48 h2 v1 h-2Z M18 48 h3 v1 h-3Z M25 48 h6 v1 h-6Z M32 48 h3 v1 h-3Z M36 48 h2 v1 h-2Z M40 48 h2 v1 h-2Z M43 48 h2 v1 h-2Z M47 48 h2 v1 h-2Z " /><path class="qr-6 " stroke="transparent" fill="#fff" fill-opacity="1" d="M5 5 h5 v1 h-5Z M43 5 h5 v1 h-5Z M5 6 h1 v1 h-1Z M9 6 h1 v1 h-1Z M43 6 h1 v1 h-1Z M47 6 h1 v1 h-1Z M5 7 h1 v1 h-1Z M9 7 h1 v1 h-1Z M43 7 h1 v1 h-1Z M47 7 h1 v1 h-1Z M5 8 h1 v1 h-1Z M9 8 h1 v1 h-1Z M43 8 h1 v1 h-1Z M47 8 h1 v1 h-1Z M5 9 h5 v1 h-5Z M43 9 h5 v1 h-5Z M5 43 h5 v1 h-5Z M5 44 h1 v1 h-1Z M9 44 h1 v1 h-1Z M5 45 h1 v1 h-1Z M9 45 h1 v1 h-1Z M5 46 h1 v1 h-1Z M9 46 h1 v1 h-1Z M5 47 h5 v1 h-5Z " /><path class="qr-8 " stroke="transparent" fill="#fff" fill-opacity="1" d="M11 4 h1 v1 h-1Z M41 4 h1 v1 h-1Z M11 5 h1 v1 h-1Z M41 5 h1 v1 h-1Z M11 6 h1 v1 h-1Z M41 6 h1 v1 h-1Z M11 7 h1 v1 h-1Z M41 7 h1 v1 h-1Z M11 8 h1 v1 h-1Z M41 8 h1 v1 h-1Z M11 9 h1 v1 h-1Z M41 9 h1 v1 h-1Z M11 10 h1 v1 h-1Z M41 10 h1 v1 h-1Z M4 11 h8 v1 h-8Z M41 11 h8 v1 h-8Z M4 41 h8 v1 h-8Z M11 42 h1 v1 h-1Z M11 43 h1 v1 h-1Z M11 44 h1 v1 h-1Z M11 45 h1 v1 h-1Z M11 46 h1 v1 h-1Z M11 47 h1 v1 h-1Z M11 48 h1 v1 h-1Z " /><path class="qr-10 " stroke="transparent" fill="#fff" fill-opacity="1" d="M25 9 h3 v1 h-3Z M25 10 h1 v1 h-1Z M27 10 h1 v1 h-1Z M25 11 h3 v1 h-3Z M9 25 h3 v1 h-3Z M25 25 h3 v1 h-3Z M41 25 h3 v1 h-3Z M9 26 h1 v1 h-1Z M11 26 h1 v1 h-1Z M25 26 h1 v1 h-1Z M27 26 h1 v1 h-1Z M41 26 h1 v1 h-1Z M43 26 h1 v1 h-1Z M9 27 h3 v1 h-3Z M25 27 h3 v1 h-3Z M41 27 h3 v1 h-3Z M25 41 h3 v1 h-3Z M41 41 h3 v1 h-3Z M25 42 h1 v1 h-1Z M27 42 h1 v1 h-1Z M41 42 h1 v1 h-1Z M43 42 h1 v1 h-1Z M25 43 h3 v1 h-3Z M41 43 h3 v1 h-3Z " /><path class="qr-12 " stroke="transparent" fill="#fff" fill-opacity="1" d="M13 10 h1 v1 h-1Z M15 10 h1 v1 h-1Z M17 10 h1 v1 h-1Z M19 10 h1 v1 h-1Z M21 10 h1 v1 h-1Z M23 10 h1 v1 h-1Z M29 10 h1 v1 h-1Z M31 10 h1 v1 h-1Z M33 10 h1 v1 h-1Z M35 10 h1 v1 h-1Z M37 10 h1 v1 h-1Z M39 10 h1 v1 h-1Z M10 13 h1 v1 h-1Z M10 15 h1 v1 h-1Z M10 17 h1 v1 h-1Z M10 19 h1 v1 h-1Z M10 21 h1 v1 h-1Z M10 23 h1 v1 h-1Z M10 29 h1 v1 h-1Z M10 31 h1 v1 h-1Z M10 33 h1 v1 h-1Z M10 35 h1 v1 h-1Z M10 37 h1 v1 h-1Z M10 39 h1 v1 h-1Z " /><path class="qr-14 " stroke="transparent" fill="#fff" fill-opacity="1" d="M12 4 h1 v1 h-1Z M12 5 h1 v1 h-1Z M12 8 h1 v1 h-1Z M12 9 h1 v1 h-1Z M12 11 h1 v1 h-1Z M4 12 h3 v1 h-3Z M9 12 h1 v1 h-1Z M12 12 h1 v1 h-1Z M41 12 h4 v1 h-4Z M47 12 h2 v1 h-2Z M12 43 h1 v1 h-1Z M12 46 h1 v1 h-1Z M12 47 h1 v1 h-1Z M12 48 h1 v1 h-1Z " /><path class="qr-16 " stroke="transparent" fill="#fff" fill-opacity="1" d="M38 4 h2 v1 h-2Z M38 5 h1 v1 h-1Z M40 5 h1 v1 h-1Z M38 6 h1 v1 h-1Z M40 6 h1 v1 h-1Z M38 7 h1 v1 h-1Z M38 9 h3 v1 h-3Z M4 38 h4 v1 h-4Z M9 38 h1 v1 h-1Z M4 39 h1 v1 h-1Z M9 39 h1 v1 h-1Z M5 40 h2 v1 h-2Z M9 40 h1 v1 h-1Z " /><path class="qr-18 " stroke="transparent" fill="#fff" fill-opacity="1" d="M0 0 h53 v1 h-53Z M0 1 h53 v1 h-53Z M0 2 h53 v1 h-53Z M0 3 h53 v1 h-53Z M0 4 h4 v1 h-4Z M49 4 h4 v1 h-4Z M0 5 h4 v1 h-4Z M49 5 h4 v1 h-4Z M0 6 h4 v1 h-4Z M49 6 h4 v1 h-4Z M0 7 h4 v1 h-4Z M49 7 h4 v1 h-4Z M0 8 h4 v1 h-4Z M49 8 h4 v1 h-4Z M0 9 h4 v1 h-4Z M49 9 h4 v1 h-4Z M0 10 h4 v1 h-4Z M49 10 h4 v1 h-4Z M0 11 h4 v1 h-4Z M49 11 h4 v1 h-4Z M0 12 h4 v1 h-4Z M49 12 h4 v1 h-4Z M0 13 h4 v1 h-4Z M49 13 h4 v1 h-4Z M0 14 h4 v1 h-4Z M49 14 h4 v1 h-4Z M0 15 h4 v1 h-4Z M49 15 h4 v1 h-4Z M0 16 h4 v1 h-4Z M49 16 h4 v1 h-4Z M0 17 h4 v1 h-4Z M49 17 h4 v1 h-4Z M0 18 h4 v1 h-4Z M49 18 h4 v1 h-4Z M0 19 h4 v1 h-4Z M49 19 h4 v1 h-4Z M0 20 h4 v1 h-4Z M49 20 h4 v1 h-4Z M0 21 h4 v1 h-4Z M49 21 h4 v1 h-4Z M0 22 h4 v1 h-4Z M49 22 h4 v1 h-4Z M0 23 h4 v1 h-4Z M49 23 h4 v1 h-4Z M0 24 h4 v1 h-4Z M49 24 h4 v1 h-4Z M0 25 h4 v1 h-4Z M49 25 h4 v1 h-4Z M0 26 h4 v1 h-4Z M49 26 h4 v1 h-4Z M0 27 h4 v1 h-4Z M49 27 h4 v1 h-4Z M0 28 h4 v1 h-4Z M49 28 h4 v1 h-4Z M0 29 h4 v1 h-4Z M49 29 h4 v1 h-4Z M0 30 h4 v1 h-4Z M49 30 h4 v1 h-4Z M0 31 h4 v1 h-4Z M49 31 h4 v1 h-4Z M0 32 h4 v1 h-4Z M49 32 h4 v1 h-4Z M0 33 h4 v1 h-4Z M49 33 h4 v1 h-4Z M0 34 h4 v1 h-4Z M49 34 h4 v1 h-4Z M0 35 h4 v1 h-4Z M49 35 h4 v1 h-4Z M0 36 h4 v1 h-4Z M49 36 h4 v1 h-4Z M0 37 h4 v1 h-4Z M49 37 h4 v1 h-4Z M0 38 h4 v1 h-4Z M49 38 h4 v1 h-4Z M0 39 h4 v1 h-4Z M49 39 h4 v1 h-4Z M0 40 h4 v1 h-4Z M49 40 h4 v1 h-4Z M0 41 h4 v1 h-4Z M49 41 h4 v1 h-4Z M0 42 h4 v1 h-4Z M49 42 h4 v1 h-4Z M0 43 h4 v1 h-4Z M49 43 h4 v1 h-4Z M0 44 h4 v1 h-4Z M49 44 h4 v1 h-4Z M0 45 h4 v1 h-4Z M49 45 h4 v1 h-4Z M0 46 h4 v1 h-4Z M49 46 h4 v1 h-4Z M0 47 h4 v1 h-4Z M49 47 h4 v1 h-4Z M0 48 h4 v1 h-4Z M49 48 h4 v1 h-4Z M0 49 h53 v1 h-53Z M0 50 h53 v1 h-53Z M0 51 h53 v1 h-53Z M0 52 h53 v1 h-53Z " /><path class="qr-512 " stroke="transparent" fill="#000" fill-opacity="1" d="M12 41 h1 v1 h-1Z " /><path class="qr-1024 " stroke="transparent" fill="#000" fill-opacity="1" d="M13 4 h2 v1 h-2Z M16 4 h2 v1 h-2Z M21 4 h3 v1 h-3Z M25 4 h2 v1 h-2Z M34 4 h1 v1 h-1Z M36 4 h2 v1 h-2Z M13 5 h3 v1 h-3Z M22 5 h3 v1 h-3Z M27 5 h2 v1 h-2Z M33 5 h1 v1 h-1Z M35 5 h1 v1 h-1Z M37 5 h1 v1 h-1Z M18 6 h1 v1 h-1Z M26 6 h4 v1 h-4Z M32 6 h3 v1 h-3Z M37 6 h1 v1 h-1Z M14 7 h1 v1 h-1Z M16 7 h1 v1 h-1Z M18 7 h2 v1 h-2Z M23 7 h2 v1 h-2Z M29 7 h3 v1 h-3Z M33 7 h2 v1 h-2Z M36 7 h1 v1 h-1Z M14 8 h1 v1 h-1Z M16 8 h2 v1 h-2Z M20 8 h2 v1 h-2Z M23 8 h1 v1 h-1Z M30 8 h1 v1 h-1Z M33 8 h5 v1 h-5Z M14 9 h1 v1 h-1Z M16 9 h5 v1 h-5Z M23 9 h1 v1 h-1Z M30 9 h1 v1 h-1Z M32 9 h3 v1 h-3Z M37 9 h1 v1 h-1Z M17 11 h2 v1 h-2Z M23 11 h1 v1 h-1Z M31 11 h3 v1 h-3Z M35 11 h4 v1 h-4Z M40 11 h1 v1 h-1Z M13 12 h4 v1 h-4Z M18 12 h1 v1 h-1Z M20 12 h4 v1 h-4Z M30 12 h2 v1 h-2Z M36 12 h1 v1 h-1Z M40 12 h1 v1 h-1Z M4 13 h1 v1 h-1Z M6 13 h2 v1 h-2Z M9 13 h1 v1 h-1Z M13 13 h2 v1 h-2Z M16 13 h1 v1 h-1Z M19 13 h2 v1 h-2Z M24 13 h10 v1 h-10Z M38 13 h2 v1 h-2Z M41 13 h1 v1 h-1Z M46 13 h1 v1 h-1Z M48 13 h1 v1 h-1Z M7 14 h1 v1 h-1Z M9 14 h1 v1 h-1Z M11 14 h1 v1 h-1Z M15 14 h1 v1 h-1Z M17 14 h1 v1 h-1Z M20 14 h1 v1 h-1Z M22 14 h2 v1 h-2Z M25 14 h5 v1 h-5Z M31 14 h5 v1 h-5Z M37 14 h3 v1 h-3Z M42 14 h1 v1 h-1Z M44 14 h1 v1 h-1Z M46 14 h2 v1 h-2Z M6 15 h2 v1 h-2Z M11 15 h1 v1 h-1Z M13 15 h9 v1 h-9Z M23 15 h1 v1 h-1Z M26 15 h1 v1 h-1Z M30 15 h1 v1 h-1Z M33 15 h3 v1 h-3Z M37 15 h2 v1 h-2Z M43 15 h4 v1 h-4Z M48 15 h1 v1 h-1Z M4 16 h1 v1 h-1Z M6 16 h3 v1 h-3Z M13 16 h1 v1 h-1Z M17 16 h1 v1 h-1Z M23 16 h2 v1 h-2Z M26 16 h1 v1 h-1Z M28 16 h1 v1 h-1Z M31 16 h1 v1 h-1Z M34 16 h3 v1 h-3Z M38 16 h1 v1 h-1Z M40 16 h5 v1 h-5Z M46 16 h1 v1 h-1Z M4 17 h4 v1 h-4Z M9 17 h1 v1 h-1Z M12 17 h1 v1 h-1Z M14 17 h3 v1 h-3Z M18 17 h1 v1 h-1Z M20 17 h2 v1 h-2Z M25 17 h3 v1 h-3Z M30 17 h1 v1 h-1Z M34 17 h1 v1 h-1Z M36 17 h2 v1 h-2Z M40 17 h1 v1 h-1Z M42 17 h2 v1 h-2Z M48 17 h1 v1 h-1Z M4 18 h1 v1 h-1Z M6 18 h3 v1 h-3Z M11 18 h1 v1 h-1Z M14 18 h1 v1 h-1Z M18 18 h2 v1 h-2Z M23 18 h1 v1 h-1Z M26 18 h2 v1 h-2Z M30 18 h1 v1 h-1Z M33 18 h3 v1 h-3Z M37 18 h1 v1 h-1Z M39 18 h2 v1 h-2Z M42 18 h3 v1 h-3Z M46 18 h2 v1 h-2Z M4 19 h2 v1 h-2Z M8 19 h1 v1 h-1Z M12 19 h2 v1 h-2Z M15 19 h1 v1 h-1Z M18 19 h2 v1 h-2Z M22 19 h1 v1 h-1Z M24 19 h1 v1 h-1Z M27 19 h1 v1 h-1Z M29 19 h2 v1 h-2Z M33 19 h1 v1 h-1Z M37 19 h1 v1 h-1Z M40 19 h3 v1 h-3Z M44 19 h5 v1 h-5Z M5 20 h1 v1 h-1Z M8 20 h1 v1 h-1Z M12 20 h4 v1 h-4Z M17 20 h1 v1 h-1Z M24 20 h1 v1 h-1Z M28 20 h1 v1 h-1Z M33 20 h1 v1 h-1Z M35 20 h4 v1 h-4Z M41 20 h2 v1 h-2Z M44 20 h1 v1 h-1Z M48 20 h1 v1 h-1Z M6 21 h4 v1 h-4Z M12 21 h1 v1 h-1Z M14 21 h6 v1 h-6Z M21 21 h2 v1 h-2Z M24 21 h1 v1 h-1Z M27 21 h1 v1 h-1Z M29 21 h1 v1 h-1Z M32 21 h1 v1 h-1Z M37 21 h1 v1 h-1Z M40 21 h1 v1 h-1Z M48 21 h1 v1 h-1Z M5 22 h1 v1 h-1Z M9 22 h1 v1 h-1Z M12 22 h3 v1 h-3Z M17 22 h1 v1 h-1Z M19 22 h2 v1 h-2Z M22 22 h1 v1 h-1Z M26 22 h4 v1 h-4Z M31 22 h1 v1 h-1Z M33 22 h2 v1 h-2Z M36 22 h6 v1 h-6Z M45 22 h2 v1 h-2Z M48 22 h1 v1 h-1Z M4 23 h1 v1 h-1Z M6 23 h1 v1 h-1Z M11 23 h2 v1 h-2Z M15 23 h1 v1 h-1Z M21 23 h2 v1 h-2Z M24 23 h2 v1 h-2Z M27 23 h2 v1 h-2Z M32 23 h1 v1 h-1Z M34 23 h1 v1 h-1Z M41 23 h2 v1 h-2Z M44 23 h1 v1 h-1Z M46 23 h1 v1 h-1Z M48 23 h1 v1 h-1Z M6 24 h1 v1 h-1Z M14 24 h1 v1 h-1Z M16 24 h1 v1 h-1Z M19 24 h4 v1 h-4Z M30 24 h2 v1 h-2Z M33 24 h2 v1 h-2Z M38 24 h1 v1 h-1Z M47 24 h1 v1 h-1Z M4 25 h2 v1 h-2Z M7 25 h1 v1 h-1Z M15 25 h1 v1 h-1Z M18 25 h1 v1 h-1Z M20 25 h1 v1 h-1Z M22 25 h2 v1 h-2Z M30 25 h1 v1 h-1Z M34 25 h3 v1 h-3Z M38 25 h2 v1 h-2Z M45 25 h1 v1 h-1Z M4 26 h2 v1 h-2Z M16 26 h2 v1 h-2Z M19 26 h1 v1 h-1Z M22 26 h2 v1 h-2Z M29 26 h2 v1 h-2Z M32 26 h1 v1 h-1Z M34 26 h1 v1 h-1Z M36 26 h1 v1 h-1Z M39 26 h1 v1 h-1Z M45 26 h1 v1 h-1Z M47 26 h2 v1 h-2Z M4 27 h1 v1 h-1Z M13 27 h3 v1 h-3Z M19 27 h3 v1 h-3Z M23 27 h1 v1 h-1Z M29 27 h1 v1 h-1Z M32 27 h1 v1 h-1Z M37 27 h1 v1 h-1Z M39 27 h1 v1 h-1Z M4 28 h2 v1 h-2Z M13 28 h1 v1 h-1Z M15 28 h1 v1 h-1Z M19 28 h1 v1 h-1Z M21 28 h2 v1 h-2Z M29 28 h2 v1 h-2Z M32 28 h2 v1 h-2Z M37 28 h1 v1 h-1Z M39 28 h1 v1 h-1Z M45 28 h3 v1 h-3Z M4 29 h1 v1 h-1Z M8 29 h1 v1 h-1Z M11 29 h1 v1 h-1Z M13 29 h1 v1 h-1Z M15 29 h1 v1 h-1Z M18 29 h2 v1 h-2Z M21 29 h1 v1 h-1Z M24 29 h1 v1 h-1Z M27 29 h1 v1 h-1Z M29 29 h2 v1 h-2Z M33 29 h1 v1 h-1Z M35 29 h1 v1 h-1Z M37 29 h4 v1 h-4Z M42 29 h2 v1 h-2Z M46 29 h3 v1 h-3Z M4 30 h1 v1 h-1Z M6 30 h1 v1 h-1Z M12 30 h1 v1 h-1Z M14 30 h1 v1 h-1Z M16 30 h2 v1 h-2Z M20 30 h5 v1 h-5Z M31 30 h1 v1 h-1Z M33 30 h2 v1 h-2Z M36 30 h6 v1 h-6Z M44 30 h3 v1 h-3Z M48 30 h1 v1 h-1Z M4 31 h1 v1 h-1Z M6 31 h1 v1 h-1Z M13 31 h2 v1 h-2Z M17 31 h2 v1 h-2Z M20 31 h4 v1 h-4Z M25 31 h6 v1 h-6Z M33 31 h5 v1 h-5Z M41 31 h3 v1 h-3Z M46 31 h1 v1 h-1Z M4 32 h1 v1 h-1Z M7 32 h1 v1 h-1Z M9 32 h1 v1 h-1Z M11 32 h2 v1 h-2Z M15 32 h1 v1 h-1Z M17 32 h2 v1 h-2Z M24 32 h1 v1 h-1Z M26 32 h1 v1 h-1Z M28 32 h2 v1 h-2Z M31 32 h1 v1 h-1Z M36 32 h1 v1 h-1Z M38 32 h1 v1 h-1Z M40 32 h2 v1 h-2Z M44 32 h1 v1 h-1Z M46 32 h2 v1 h-2Z M4 33 h3 v1 h-3Z M8 33 h1 v1 h-1Z M13 33 h2 v1 h-2Z M17 33 h1 v1 h-1Z M24 33 h2 v1 h-2Z M27 33 h1 v1 h-1Z M29 33 h7 v1 h-7Z M37 33 h2 v1 h-2Z M42 33 h3 v1 h-3Z M47 33 h1 v1 h-1Z M5 34 h1 v1 h-1Z M12 34 h1 v1 h-1Z M14 34 h1 v1 h-1Z M16 34 h3 v1 h-3Z M21 34 h8 v1 h-8Z M30 34 h1 v1 h-1Z M32 34 h1 v1 h-1Z M34 34 h3 v1 h-3Z M43 34 h3 v1 h-3Z M47 34 h2 v1 h-2Z M5 35 h3 v1 h-3Z M9 35 h1 v1 h-1Z M11 35 h1 v1 h-1Z M15 35 h1 v1 h-1Z M18 35 h2 v1 h-2Z M21 35 h1 v1 h-1Z M23 35 h1 v1 h-1Z M27 35 h1 v1 h-1Z M30 35 h1 v1 h-1Z M35 35 h2 v1 h-2Z M40 35 h4 v1 h-4Z M45 35 h1 v1 h-1Z M48 35 h1 v1 h-1Z M4 36 h1 v1 h-1Z M8 36 h1 v1 h-1Z M13 36 h1 v1 h-1Z M15 36 h1 v1 h-1Z M18 36 h1 v1 h-1Z M20 36 h1 v1 h-1Z M23 36 h1 v1 h-1Z M27 36 h1 v1 h-1Z M29 36 h1 v1 h-1Z M36 36 h1 v1 h-1Z M41 36 h1 v1 h-1Z M44 36 h1 v1 h-1Z M46 36 h2 v1 h-2Z M4 37 h1 v1 h-1Z M7 37 h1 v1 h-1Z M13 37 h1 v1 h-1Z M16 37 h1 v1 h-1Z M18 37 h2 v1 h-2Z M21 37 h2 v1 h-2Z M24 37 h2 v1 h-2Z M28 37 h1 v1 h-1Z M30 37 h1 v1 h-1Z M34 37 h1 v1 h-1Z M37 37 h2 v1 h-2Z M40 37 h3 v1 h-3Z M44 37 h3 v1 h-3Z M48 37 h1 v1 h-1Z M11 38 h1 v1 h-1Z M14 38 h1 v1 h-1Z M16 38 h3 v1 h-3Z M21 38 h1 v1 h-1Z M23 38 h1 v1 h-1Z M25 38 h1 v1 h-1Z M30 38 h1 v1 h-1Z M33 38 h1 v1 h-1Z M35 38 h1 v1 h-1Z M38 38 h3 v1 h-3Z M42 38 h1 v1 h-1Z M45 38 h3 v1 h-3Z M12 39 h1 v1 h-1Z M15 39 h2 v1 h-2Z M21 39 h1 v1 h-1Z M25 39 h1 v1 h-1Z M27 39 h1 v1 h-1Z M32 39 h2 v1 h-2Z M35 39 h2 v1 h-2Z M38 39 h2 v1 h-2Z M41 39 h1 v1 h-1Z M44 39 h1 v1 h-1Z M46 39 h1 v1 h-1Z M48 39 h1 v1 h-1Z M11 40 h1 v1 h-1Z M16 40 h1 v1 h-1Z M20 40 h3 v1 h-3Z M29 40 h1 v1 h-1Z M36 40 h1 v1 h-1Z M38 40 h1 v1 h-1Z M13 41 h4 v1 h-4Z M23 41 h1 v1 h-1Z M32 41 h3 v1 h-3Z M45 41 h1 v1 h-1Z M47 41 h1 v1 h-1Z M14 42 h2 v1 h-2Z M17 42 h2 v1 h-2Z M23 42 h1 v1 h-1Z M30 42 h1 v1 h-1Z M32 42 h4 v1 h-4Z M38 42 h2 v1 h-2Z M13 43 h7 v1 h-7Z M23 43 h1 v1 h-1Z M30 43 h3 v1 h-3Z M37 43 h1 v1 h-1Z M39 43 h1 v1 h-1Z M45 43 h2 v1 h-2Z M48 43 h1 v1 h-1Z M15 44 h1 v1 h-1Z M17 44 h2 v1 h-2Z M22 44 h2 v1 h-2Z M30 44 h1 v1 h-1Z M33 44 h6 v1 h-6Z M45 44 h1 v1 h-1Z M48 44 h1 v1 h-1Z M15 45 h1 v1 h-1Z M19 45 h2 v1 h-2Z M22 45 h2 v1 h-2Z M25 45 h2 v1 h-2Z M29 45 h2 v1 h-2Z M37 45 h1 v1 h-1Z M39 45 h1 v1 h-1Z M44 45 h4 v1 h-4Z M15 46 h2 v1 h-2Z M19 46 h1 v1 h-1Z M21 46 h3 v1 h-3Z M26 46 h1 v1 h-1Z M28 46 h1 v1 h-1Z M30 46 h1 v1 h-1Z M34 46 h5 v1 h-5Z M40 46 h1 v1 h-1Z M46 46 h3 v1 h-3Z M13 47 h1 v1 h-1Z M16 47 h4 v1 h-4Z M21 47 h1 v1 h-1Z M23 47 h1 v1 h-1Z M25 47 h1 v1 h-1Z M29 47 h2 v1 h-2Z M36 47 h1 v1 h-1Z M39 47 h1 v1 h-1Z M41 47 h2 v1 h-2Z M44 47 h1 v1 h-1Z M46 47 h3 v1 h-3Z M14 48 h1 v1 h-1Z M17 48 h1 v1 h-1Z M21 48 h4 v1 h-4Z M31 48 h1 v1 h-1Z M35 48 h1 v1 h-1Z M38 48 h2 v1 h-2Z M42 48 h1 v1 h-1Z M45 48 h2 v1 h-2Z " /><path class="qr-1536 " stroke="transparent" fill="#000" fill-opacity="1" d="M4 4 h7 v1 h-7Z M42 4 h7 v1 h-7Z M4 5 h1 v1 h-1Z M10 5 h1 v1 h-1Z M42 5 h1 v1 h-1Z M48 5 h1 v1 h-1Z M4 6 h1 v1 h-1Z M10 6 h1 v1 h-1Z M42 6 h1 v1 h-1Z M48 6 h1 v1 h-1Z M4 7 h1 v1 h-1Z M10 7 h1 v1 h-1Z M42 7 h1 v1 h-1Z M48 7 h1 v1 h-1Z M4 8 h1 v1 h-1Z M10 8 h1 v1 h-1Z M42 8 h1 v1 h-1Z M48 8 h1 v1 h-1Z M4 9 h1 v1 h-1Z M10 9 h1 v1 h-1Z M42 9 h1 v1 h-1Z M48 9 h1 v1 h-1Z M4 10 h7 v1 h-7Z M42 10 h7 v1 h-7Z M4 42 h7 v1 h-7Z M4 43 h1 v1 h-1Z M10 43 h1 v1 h-1Z M4 44 h1 v1 h-1Z M10 44 h1 v1 h-1Z M4 45 h1 v1 h-1Z M10 45 h1 v1 h-1Z M4 46 h1 v1 h-1Z M10 46 h1 v1 h-1Z M4 47 h1 v1 h-1Z M10 47 h1 v1 h-1Z M4 48 h7 v1 h-7Z " /><path class="qr-2560 " stroke="transparent" fill="#000" fill-opacity="1" d="M24 8 h5 v1 h-5Z M24 9 h1 v1 h-1Z M28 9 h1 v1 h-1Z M24 10 h1 v1 h-1Z M26 10 h1 v1 h-1Z M28 10 h1 v1 h-1Z M24 11 h1 v1 h-1Z M28 11 h1 v1 h-1Z M24 12 h5 v1 h-5Z M8 24 h5 v1 h-5Z M24 24 h5 v1 h-5Z M40 24 h5 v1 h-5Z M8 25 h1 v1 h-1Z M12 25 h1 v1 h-1Z M24 25 h1 v1 h-1Z M28 25 h1 v1 h-1Z M40 25 h1 v1 h-1Z M44 25 h1 v1 h-1Z M8 26 h1 v1 h-1Z M10 26 h1 v1 h-1Z M12 26 h1 v1 h-1Z M24 26 h1 v1 h-1Z M26 26 h1 v1 h-1Z M28 26 h1 v1 h-1Z M40 26 h1 v1 h-1Z M42 26 h1 v1 h-1Z M44 26 h1 v1 h-1Z M8 27 h1 v1 h-1Z M12 27 h1 v1 h-1Z M24 27 h1 v1 h-1Z M28 27 h1 v1 h-1Z M40 27 h1 v1 h-1Z M44 27 h1 v1 h-1Z M8 28 h5 v1 h-5Z M24 28 h5 v1 h-5Z M40 28 h5 v1 h-5Z M24 40 h5 v1 h-5Z M40 40 h5 v1 h-5Z M24 41 h1 v1 h-1Z M28 41 h1 v1 h-1Z M40 41 h1 v1 h-1Z M44 41 h1 v1 h-1Z M24 42 h1 v1 h-1Z M26 42 h1 v1 h-1Z M28 42 h1 v1 h-1Z M40 42 h1 v1 h-1Z M42 42 h1 v1 h-1Z M44 42 h1 v1 h-1Z M24 43 h1 v1 h-1Z M28 43 h1 v1 h-1Z M40 43 h1 v1 h-1Z M44 43 h1 v1 h-1Z M24 44 h5 v1 h-5Z M40 44 h5 v1 h-5Z " /><path class="qr-3072 " stroke="transparent" fill="#000" fill-opacity="1" d="M12 10 h1 v1 h-1Z M14 10 h1 v1 h-1Z M16 10 h1 v1 h-1Z M18 10 h1 v1 h-1Z M20 10 h1 v1 h-1Z M22 10 h1 v1 h-1Z M30 10 h1 v1 h-1Z M32 10 h1 v1 h-1Z M34 10 h1 v1 h-1Z M36 10 h1 v1 h-1Z M38 10 h1 v1 h-1Z M40 10 h1 v1 h-1Z M10 12 h1 v1 h-1Z M10 14 h1 v1 h-1Z M10 16 h1 v1 h-1Z M10 18 h1 v1 h-1Z M10 20 h1 v1 h-1Z M10 22 h1 v1 h-1Z M10 30 h1 v1 h-1Z M10 32 h1 v1 h-1Z M10 34 h1 v1 h-1Z M10 36 h1 v1 h-1Z M10 38 h1 v1 h-1Z M10 40 h1 v1 h-1Z " /><path class="qr-3584 " stroke="transparent" fill="#000" fill-opacity="1" d="M12 6 h1 v1 h-1Z M12 7 h1 v1 h-1Z M7 12 h2 v1 h-2Z M11 12 h1 v1 h-1Z M45 12 h2 v1 h-2Z M12 42 h1 v1 h-1Z M12 44 h1 v1 h-1Z M12 45 h1 v1 h-1Z " /><path class="qr-4096 " stroke="transparent" fill="#000" fill-opacity="1" d="M40 4 h1 v1 h-1Z M39 5 h1 v1 h-1Z M39 6 h1 v1 h-1Z M39 7 h2 v1 h-2Z M38 8 h3 v1 h-3Z M8 38 h1 v1 h-1Z M5 39 h4 v1 h-4Z M4 40 h1 v1 h-1Z M7 40 h2 v1 h-2Z " /><path class="qr-5632 " stroke="transparent" fill="#000" fill-opacity="1" d="M6 6 h3 v1 h-3Z M44 6 h3 v1 h-3Z M6 7 h3 v1 h-3Z M44 7 h3 v1 h-3Z M6 8 h3 v1 h-3Z M44 8 h3 v1 h-3Z M6 44 h3 v1 h-3Z M6 45 h3 v1 h-3Z M6 46 h3 v1 h-3Z " /></svg>

    </a>
    <figcaption aria-hidden="true" class="hidden" hidden>Donate for Stéphane HUC by Paypal</figcaption>
</figure>


<h3 id="tipeee">Tip<em>eee</em></h3>
<ul>
<li><a href="https://fr.tipeee.com/hucste" rel="external">https://fr.tipeee.com/hucste</a></li>
</ul>


<figure class="pure-img">
    <a href="/svg/qrcode/tipee.svg" title="Reward Stéphane HUC">
    <svg xmlns="http://www.w3.org/2000/svg" height="128" viewBox="0 0 53 53" width="128">
<defs><style>rect{shape-rendering:crispEdges}</style></defs>
<path class="qr-4 " stroke="transparent" fill="#fff" fill-opacity="1" d="M14 4 h1 v1 h-1Z M16 4 h1 v1 h-1Z M18 4 h1 v1 h-1Z M20 4 h1 v1 h-1Z M22 4 h2 v1 h-2Z M25 4 h1 v1 h-1Z M27 4 h4 v1 h-4Z M35 4 h2 v1 h-2Z M17 5 h5 v1 h-5Z M23 5 h1 v1 h-1Z M27 5 h1 v1 h-1Z M32 5 h2 v1 h-2Z M35 5 h1 v1 h-1Z M13 6 h1 v1 h-1Z M15 6 h3 v1 h-3Z M19 6 h1 v1 h-1Z M22 6 h2 v1 h-2Z M25 6 h1 v1 h-1Z M29 6 h1 v1 h-1Z M31 6 h1 v1 h-1Z M35 6 h1 v1 h-1Z M13 7 h1 v1 h-1Z M15 7 h1 v1 h-1Z M17 7 h1 v1 h-1Z M19 7 h1 v1 h-1Z M21 7 h2 v1 h-2Z M26 7 h3 v1 h-3Z M31 7 h1 v1 h-1Z M33 7 h3 v1 h-3Z M37 7 h1 v1 h-1Z M13 8 h3 v1 h-3Z M17 8 h1 v1 h-1Z M23 8 h1 v1 h-1Z M30 8 h2 v1 h-2Z M35 8 h3 v1 h-3Z M14 9 h3 v1 h-3Z M19 9 h1 v1 h-1Z M22 9 h2 v1 h-2Z M29 9 h2 v1 h-2Z M32 9 h1 v1 h-1Z M35 9 h1 v1 h-1Z M13 11 h1 v1 h-1Z M15 11 h2 v1 h-2Z M20 11 h1 v1 h-1Z M23 11 h1 v1 h-1Z M30 11 h1 v1 h-1Z M32 11 h1 v1 h-1Z M34 11 h4 v1 h-4Z M39 11 h1 v1 h-1Z M13 12 h1 v1 h-1Z M16 12 h1 v1 h-1Z M19 12 h1 v1 h-1Z M21 12 h3 v1 h-3Z M31 12 h2 v1 h-2Z M35 12 h1 v1 h-1Z M38 12 h1 v1 h-1Z M4 13 h1 v1 h-1Z M6 13 h2 v1 h-2Z M11 13 h3 v1 h-3Z M15 13 h2 v1 h-2Z M23 13 h1 v1 h-1Z M26 13 h2 v1 h-2Z M30 13 h1 v1 h-1Z M34 13 h3 v1 h-3Z M38 13 h1 v1 h-1Z M40 13 h1 v1 h-1Z M42 13 h4 v1 h-4Z M47 13 h2 v1 h-2Z M4 14 h4 v1 h-4Z M9 14 h1 v1 h-1Z M12 14 h2 v1 h-2Z M15 14 h3 v1 h-3Z M19 14 h3 v1 h-3Z M23 14 h3 v1 h-3Z M28 14 h3 v1 h-3Z M32 14 h1 v1 h-1Z M35 14 h1 v1 h-1Z M37 14 h2 v1 h-2Z M43 14 h1 v1 h-1Z M45 14 h3 v1 h-3Z M5 15 h1 v1 h-1Z M9 15 h1 v1 h-1Z M14 15 h2 v1 h-2Z M17 15 h2 v1 h-2Z M20 15 h2 v1 h-2Z M24 15 h4 v1 h-4Z M30 15 h1 v1 h-1Z M33 15 h1 v1 h-1Z M36 15 h2 v1 h-2Z M40 15 h1 v1 h-1Z M42 15 h1 v1 h-1Z M44 15 h2 v1 h-2Z M47 15 h2 v1 h-2Z M4 16 h2 v1 h-2Z M7 16 h1 v1 h-1Z M13 16 h1 v1 h-1Z M20 16 h1 v1 h-1Z M22 16 h2 v1 h-2Z M25 16 h2 v1 h-2Z M29 16 h1 v1 h-1Z M33 16 h2 v1 h-2Z M36 16 h1 v1 h-1Z M38 16 h2 v1 h-2Z M41 16 h1 v1 h-1Z M44 16 h2 v1 h-2Z M47 16 h1 v1 h-1Z M4 17 h1 v1 h-1Z M9 17 h1 v1 h-1Z M12 17 h3 v1 h-3Z M16 17 h1 v1 h-1Z M18 17 h2 v1 h-2Z M24 17 h2 v1 h-2Z M29 17 h2 v1 h-2Z M32 17 h2 v1 h-2Z M37 17 h3 v1 h-3Z M41 17 h2 v1 h-2Z M47 17 h1 v1 h-1Z M6 18 h1 v1 h-1Z M9 18 h1 v1 h-1Z M12 18 h1 v1 h-1Z M14 18 h1 v1 h-1Z M16 18 h1 v1 h-1Z M18 18 h2 v1 h-2Z M21 18 h2 v1 h-2Z M24 18 h2 v1 h-2Z M27 18 h3 v1 h-3Z M31 18 h3 v1 h-3Z M36 18 h5 v1 h-5Z M42 18 h1 v1 h-1Z M44 18 h2 v1 h-2Z M5 19 h2 v1 h-2Z M11 19 h1 v1 h-1Z M13 19 h1 v1 h-1Z M16 19 h5 v1 h-5Z M23 19 h6 v1 h-6Z M30 19 h1 v1 h-1Z M34 19 h2 v1 h-2Z M38 19 h2 v1 h-2Z M41 19 h2 v1 h-2Z M44 19 h4 v1 h-4Z M5 20 h1 v1 h-1Z M11 20 h1 v1 h-1Z M13 20 h1 v1 h-1Z M15 20 h3 v1 h-3Z M20 20 h1 v1 h-1Z M22 20 h1 v1 h-1Z M24 20 h2 v1 h-2Z M28 20 h4 v1 h-4Z M39 20 h2 v1 h-2Z M43 20 h1 v1 h-1Z M46 20 h2 v1 h-2Z M6 21 h2 v1 h-2Z M11 21 h4 v1 h-4Z M16 21 h1 v1 h-1Z M20 21 h1 v1 h-1Z M22 21 h2 v1 h-2Z M25 21 h1 v1 h-1Z M27 21 h1 v1 h-1Z M29 21 h3 v1 h-3Z M34 21 h1 v1 h-1Z M36 21 h1 v1 h-1Z M38 21 h3 v1 h-3Z M42 21 h2 v1 h-2Z M46 21 h2 v1 h-2Z M5 22 h1 v1 h-1Z M8 22 h2 v1 h-2Z M12 22 h2 v1 h-2Z M15 22 h1 v1 h-1Z M18 22 h1 v1 h-1Z M21 22 h4 v1 h-4Z M27 22 h1 v1 h-1Z M29 22 h1 v1 h-1Z M35 22 h2 v1 h-2Z M40 22 h3 v1 h-3Z M44 22 h2 v1 h-2Z M9 23 h1 v1 h-1Z M16 23 h1 v1 h-1Z M18 23 h2 v1 h-2Z M21 23 h1 v1 h-1Z M23 23 h2 v1 h-2Z M27 23 h2 v1 h-2Z M32 23 h2 v1 h-2Z M37 23 h1 v1 h-1Z M40 23 h2 v1 h-2Z M45 23 h4 v1 h-4Z M7 24 h1 v1 h-1Z M15 24 h1 v1 h-1Z M18 24 h5 v1 h-5Z M30 24 h1 v1 h-1Z M33 24 h3 v1 h-3Z M37 24 h3 v1 h-3Z M45 24 h4 v1 h-4Z M5 25 h1 v1 h-1Z M7 25 h1 v1 h-1Z M17 25 h1 v1 h-1Z M19 25 h2 v1 h-2Z M23 25 h1 v1 h-1Z M29 25 h3 v1 h-3Z M33 25 h1 v1 h-1Z M37 25 h1 v1 h-1Z M39 25 h1 v1 h-1Z M45 25 h2 v1 h-2Z M4 26 h1 v1 h-1Z M7 26 h1 v1 h-1Z M14 26 h1 v1 h-1Z M23 26 h1 v1 h-1Z M30 26 h1 v1 h-1Z M33 26 h1 v1 h-1Z M35 26 h1 v1 h-1Z M37 26 h1 v1 h-1Z M39 26 h1 v1 h-1Z M45 26 h1 v1 h-1Z M6 27 h1 v1 h-1Z M13 27 h1 v1 h-1Z M16 27 h1 v1 h-1Z M20 27 h4 v1 h-4Z M29 27 h1 v1 h-1Z M33 27 h1 v1 h-1Z M35 27 h2 v1 h-2Z M38 27 h1 v1 h-1Z M45 27 h4 v1 h-4Z M4 28 h4 v1 h-4Z M13 28 h5 v1 h-5Z M20 28 h2 v1 h-2Z M30 28 h2 v1 h-2Z M35 28 h1 v1 h-1Z M39 28 h1 v1 h-1Z M45 28 h2 v1 h-2Z M48 28 h1 v1 h-1Z M4 29 h1 v1 h-1Z M6 29 h2 v1 h-2Z M9 29 h1 v1 h-1Z M14 29 h2 v1 h-2Z M17 29 h2 v1 h-2Z M24 29 h6 v1 h-6Z M31 29 h6 v1 h-6Z M38 29 h3 v1 h-3Z M43 29 h3 v1 h-3Z M47 29 h2 v1 h-2Z M7 30 h2 v1 h-2Z M11 30 h1 v1 h-1Z M13 30 h1 v1 h-1Z M15 30 h1 v1 h-1Z M19 30 h2 v1 h-2Z M23 30 h3 v1 h-3Z M27 30 h2 v1 h-2Z M30 30 h3 v1 h-3Z M35 30 h1 v1 h-1Z M40 30 h1 v1 h-1Z M42 30 h1 v1 h-1Z M45 30 h3 v1 h-3Z M4 31 h1 v1 h-1Z M7 31 h1 v1 h-1Z M9 31 h1 v1 h-1Z M13 31 h1 v1 h-1Z M17 31 h1 v1 h-1Z M19 31 h1 v1 h-1Z M23 31 h1 v1 h-1Z M26 31 h1 v1 h-1Z M28 31 h4 v1 h-4Z M33 31 h1 v1 h-1Z M36 31 h2 v1 h-2Z M40 31 h1 v1 h-1Z M42 31 h4 v1 h-4Z M47 31 h2 v1 h-2Z M5 32 h1 v1 h-1Z M8 32 h2 v1 h-2Z M13 32 h1 v1 h-1Z M16 32 h1 v1 h-1Z M18 32 h1 v1 h-1Z M21 32 h1 v1 h-1Z M23 32 h2 v1 h-2Z M26 32 h4 v1 h-4Z M33 32 h2 v1 h-2Z M36 32 h1 v1 h-1Z M38 32 h4 v1 h-4Z M44 32 h2 v1 h-2Z M47 32 h1 v1 h-1Z M4 33 h2 v1 h-2Z M7 33 h1 v1 h-1Z M9 33 h1 v1 h-1Z M13 33 h2 v1 h-2Z M16 33 h2 v1 h-2Z M19 33 h1 v1 h-1Z M21 33 h1 v1 h-1Z M23 33 h2 v1 h-2Z M26 33 h1 v1 h-1Z M28 33 h1 v1 h-1Z M30 33 h2 v1 h-2Z M33 33 h1 v1 h-1Z M37 33 h2 v1 h-2Z M40 33 h5 v1 h-5Z M46 33 h1 v1 h-1Z M48 33 h1 v1 h-1Z M5 34 h5 v1 h-5Z M12 34 h1 v1 h-1Z M19 34 h2 v1 h-2Z M23 34 h1 v1 h-1Z M25 34 h1 v1 h-1Z M28 34 h1 v1 h-1Z M31 34 h1 v1 h-1Z M33 34 h1 v1 h-1Z M36 34 h4 v1 h-4Z M41 34 h1 v1 h-1Z M43 34 h1 v1 h-1Z M48 34 h1 v1 h-1Z M4 35 h1 v1 h-1Z M6 35 h1 v1 h-1Z M8 35 h2 v1 h-2Z M13 35 h2 v1 h-2Z M16 35 h5 v1 h-5Z M23 35 h5 v1 h-5Z M30 35 h1 v1 h-1Z M32 35 h6 v1 h-6Z M41 35 h4 v1 h-4Z M46 35 h1 v1 h-1Z M5 36 h2 v1 h-2Z M8 36 h2 v1 h-2Z M12 36 h1 v1 h-1Z M15 36 h1 v1 h-1Z M20 36 h1 v1 h-1Z M22 36 h3 v1 h-3Z M27 36 h2 v1 h-2Z M32 36 h2 v1 h-2Z M35 36 h1 v1 h-1Z M42 36 h2 v1 h-2Z M48 36 h1 v1 h-1Z M5 37 h2 v1 h-2Z M11 37 h1 v1 h-1Z M13 37 h2 v1 h-2Z M17 37 h4 v1 h-4Z M24 37 h1 v1 h-1Z M26 37 h2 v1 h-2Z M30 37 h1 v1 h-1Z M33 37 h1 v1 h-1Z M35 37 h2 v1 h-2Z M38 37 h2 v1 h-2Z M43 37 h1 v1 h-1Z M45 37 h3 v1 h-3Z M11 38 h9 v1 h-9Z M23 38 h3 v1 h-3Z M27 38 h4 v1 h-4Z M33 38 h3 v1 h-3Z M37 38 h2 v1 h-2Z M40 38 h1 v1 h-1Z M42 38 h4 v1 h-4Z M11 39 h1 v1 h-1Z M13 39 h3 v1 h-3Z M18 39 h5 v1 h-5Z M24 39 h3 v1 h-3Z M30 39 h1 v1 h-1Z M37 39 h1 v1 h-1Z M40 39 h1 v1 h-1Z M42 39 h2 v1 h-2Z M45 39 h3 v1 h-3Z M12 40 h4 v1 h-4Z M18 40 h1 v1 h-1Z M20 40 h3 v1 h-3Z M32 40 h3 v1 h-3Z M37 40 h3 v1 h-3Z M46 40 h2 v1 h-2Z M13 41 h5 v1 h-5Z M32 41 h1 v1 h-1Z M34 41 h2 v1 h-2Z M37 41 h1 v1 h-1Z M39 41 h1 v1 h-1Z M45 41 h2 v1 h-2Z M13 42 h1 v1 h-1Z M15 42 h2 v1 h-2Z M20 42 h2 v1 h-2Z M29 42 h6 v1 h-6Z M36 42 h2 v1 h-2Z M39 42 h1 v1 h-1Z M18 43 h5 v1 h-5Z M30 43 h1 v1 h-1Z M33 43 h1 v1 h-1Z M35 43 h1 v1 h-1Z M38 43 h1 v1 h-1Z M45 43 h2 v1 h-2Z M48 43 h1 v1 h-1Z M13 44 h2 v1 h-2Z M16 44 h1 v1 h-1Z M18 44 h1 v1 h-1Z M20 44 h3 v1 h-3Z M29 44 h2 v1 h-2Z M32 44 h3 v1 h-3Z M39 44 h1 v1 h-1Z M45 44 h2 v1 h-2Z M13 45 h3 v1 h-3Z M17 45 h1 v1 h-1Z M19 45 h2 v1 h-2Z M22 45 h2 v1 h-2Z M26 45 h5 v1 h-5Z M32 45 h1 v1 h-1Z M38 45 h1 v1 h-1Z M42 45 h7 v1 h-7Z M13 46 h2 v1 h-2Z M18 46 h1 v1 h-1Z M20 46 h1 v1 h-1Z M22 46 h1 v1 h-1Z M25 46 h1 v1 h-1Z M27 46 h1 v1 h-1Z M29 46 h2 v1 h-2Z M42 46 h2 v1 h-2Z M47 46 h1 v1 h-1Z M13 47 h1 v1 h-1Z M15 47 h1 v1 h-1Z M18 47 h1 v1 h-1Z M20 47 h1 v1 h-1Z M22 47 h4 v1 h-4Z M29 47 h3 v1 h-3Z M33 47 h2 v1 h-2Z M36 47 h2 v1 h-2Z M42 47 h3 v1 h-3Z M46 47 h1 v1 h-1Z M48 47 h1 v1 h-1Z M13 48 h5 v1 h-5Z M19 48 h2 v1 h-2Z M22 48 h1 v1 h-1Z M25 48 h3 v1 h-3Z M30 48 h5 v1 h-5Z M36 48 h3 v1 h-3Z M40 48 h1 v1 h-1Z M42 48 h2 v1 h-2Z M45 48 h2 v1 h-2Z " /><path class="qr-6 " stroke="transparent" fill="#fff" fill-opacity="1" d="M5 5 h5 v1 h-5Z M43 5 h5 v1 h-5Z M5 6 h1 v1 h-1Z M9 6 h1 v1 h-1Z M43 6 h1 v1 h-1Z M47 6 h1 v1 h-1Z M5 7 h1 v1 h-1Z M9 7 h1 v1 h-1Z M43 7 h1 v1 h-1Z M47 7 h1 v1 h-1Z M5 8 h1 v1 h-1Z M9 8 h1 v1 h-1Z M43 8 h1 v1 h-1Z M47 8 h1 v1 h-1Z M5 9 h5 v1 h-5Z M43 9 h5 v1 h-5Z M5 43 h5 v1 h-5Z M5 44 h1 v1 h-1Z M9 44 h1 v1 h-1Z M5 45 h1 v1 h-1Z M9 45 h1 v1 h-1Z M5 46 h1 v1 h-1Z M9 46 h1 v1 h-1Z M5 47 h5 v1 h-5Z " /><path class="qr-8 " stroke="transparent" fill="#fff" fill-opacity="1" d="M11 4 h1 v1 h-1Z M41 4 h1 v1 h-1Z M11 5 h1 v1 h-1Z M41 5 h1 v1 h-1Z M11 6 h1 v1 h-1Z M41 6 h1 v1 h-1Z M11 7 h1 v1 h-1Z M41 7 h1 v1 h-1Z M11 8 h1 v1 h-1Z M41 8 h1 v1 h-1Z M11 9 h1 v1 h-1Z M41 9 h1 v1 h-1Z M11 10 h1 v1 h-1Z M41 10 h1 v1 h-1Z M4 11 h8 v1 h-8Z M41 11 h8 v1 h-8Z M4 41 h8 v1 h-8Z M11 42 h1 v1 h-1Z M11 43 h1 v1 h-1Z M11 44 h1 v1 h-1Z M11 45 h1 v1 h-1Z M11 46 h1 v1 h-1Z M11 47 h1 v1 h-1Z M11 48 h1 v1 h-1Z " /><path class="qr-10 " stroke="transparent" fill="#fff" fill-opacity="1" d="M25 9 h3 v1 h-3Z M25 10 h1 v1 h-1Z M27 10 h1 v1 h-1Z M25 11 h3 v1 h-3Z M9 25 h3 v1 h-3Z M25 25 h3 v1 h-3Z M41 25 h3 v1 h-3Z M9 26 h1 v1 h-1Z M11 26 h1 v1 h-1Z M25 26 h1 v1 h-1Z M27 26 h1 v1 h-1Z M41 26 h1 v1 h-1Z M43 26 h1 v1 h-1Z M9 27 h3 v1 h-3Z M25 27 h3 v1 h-3Z M41 27 h3 v1 h-3Z M25 41 h3 v1 h-3Z M41 41 h3 v1 h-3Z M25 42 h1 v1 h-1Z M27 42 h1 v1 h-1Z M41 42 h1 v1 h-1Z M43 42 h1 v1 h-1Z M25 43 h3 v1 h-3Z M41 43 h3 v1 h-3Z " /><path class="qr-12 " stroke="transparent" fill="#fff" fill-opacity="1" d="M13 10 h1 v1 h-1Z M15 10 h1 v1 h-1Z M17 10 h1 v1 h-1Z M19 10 h1 v1 h-1Z M21 10 h1 v1 h-1Z M23 10 h1 v1 h-1Z M29 10 h1 v1 h-1Z M31 10 h1 v1 h-1Z M33 10 h1 v1 h-1Z M35 10 h1 v1 h-1Z M37 10 h1 v1 h-1Z M39 10 h1 v1 h-1Z M10 13 h1 v1 h-1Z M10 15 h1 v1 h-1Z M10 17 h1 v1 h-1Z M10 19 h1 v1 h-1Z M10 21 h1 v1 h-1Z M10 23 h1 v1 h-1Z M10 29 h1 v1 h-1Z M10 31 h1 v1 h-1Z M10 33 h1 v1 h-1Z M10 35 h1 v1 h-1Z M10 37 h1 v1 h-1Z M10 39 h1 v1 h-1Z " /><path class="qr-14 " stroke="transparent" fill="#fff" fill-opacity="1" d="M12 5 h1 v1 h-1Z M12 6 h1 v1 h-1Z M12 8 h1 v1 h-1Z M12 9 h1 v1 h-1Z M12 11 h1 v1 h-1Z M4 12 h2 v1 h-2Z M7 12 h1 v1 h-1Z M11 12 h1 v1 h-1Z M42 12 h3 v1 h-3Z M46 12 h2 v1 h-2Z M12 42 h1 v1 h-1Z M12 45 h1 v1 h-1Z M12 47 h1 v1 h-1Z M12 48 h1 v1 h-1Z " /><path class="qr-16 " stroke="transparent" fill="#fff" fill-opacity="1" d="M38 4 h2 v1 h-2Z M38 5 h1 v1 h-1Z M40 5 h1 v1 h-1Z M38 6 h1 v1 h-1Z M40 6 h1 v1 h-1Z M38 7 h1 v1 h-1Z M38 9 h3 v1 h-3Z M4 38 h4 v1 h-4Z M9 38 h1 v1 h-1Z M4 39 h1 v1 h-1Z M9 39 h1 v1 h-1Z M5 40 h2 v1 h-2Z M9 40 h1 v1 h-1Z " /><path class="qr-18 " stroke="transparent" fill="#fff" fill-opacity="1" d="M0 0 h53 v1 h-53Z M0 1 h53 v1 h-53Z M0 2 h53 v1 h-53Z M0 3 h53 v1 h-53Z M0 4 h4 v1 h-4Z M49 4 h4 v1 h-4Z M0 5 h4 v1 h-4Z M49 5 h4 v1 h-4Z M0 6 h4 v1 h-4Z M49 6 h4 v1 h-4Z M0 7 h4 v1 h-4Z M49 7 h4 v1 h-4Z M0 8 h4 v1 h-4Z M49 8 h4 v1 h-4Z M0 9 h4 v1 h-4Z M49 9 h4 v1 h-4Z M0 10 h4 v1 h-4Z M49 10 h4 v1 h-4Z M0 11 h4 v1 h-4Z M49 11 h4 v1 h-4Z M0 12 h4 v1 h-4Z M49 12 h4 v1 h-4Z M0 13 h4 v1 h-4Z M49 13 h4 v1 h-4Z M0 14 h4 v1 h-4Z M49 14 h4 v1 h-4Z M0 15 h4 v1 h-4Z M49 15 h4 v1 h-4Z M0 16 h4 v1 h-4Z M49 16 h4 v1 h-4Z M0 17 h4 v1 h-4Z M49 17 h4 v1 h-4Z M0 18 h4 v1 h-4Z M49 18 h4 v1 h-4Z M0 19 h4 v1 h-4Z M49 19 h4 v1 h-4Z M0 20 h4 v1 h-4Z M49 20 h4 v1 h-4Z M0 21 h4 v1 h-4Z M49 21 h4 v1 h-4Z M0 22 h4 v1 h-4Z M49 22 h4 v1 h-4Z M0 23 h4 v1 h-4Z M49 23 h4 v1 h-4Z M0 24 h4 v1 h-4Z M49 24 h4 v1 h-4Z M0 25 h4 v1 h-4Z M49 25 h4 v1 h-4Z M0 26 h4 v1 h-4Z M49 26 h4 v1 h-4Z M0 27 h4 v1 h-4Z M49 27 h4 v1 h-4Z M0 28 h4 v1 h-4Z M49 28 h4 v1 h-4Z M0 29 h4 v1 h-4Z M49 29 h4 v1 h-4Z M0 30 h4 v1 h-4Z M49 30 h4 v1 h-4Z M0 31 h4 v1 h-4Z M49 31 h4 v1 h-4Z M0 32 h4 v1 h-4Z M49 32 h4 v1 h-4Z M0 33 h4 v1 h-4Z M49 33 h4 v1 h-4Z M0 34 h4 v1 h-4Z M49 34 h4 v1 h-4Z M0 35 h4 v1 h-4Z M49 35 h4 v1 h-4Z M0 36 h4 v1 h-4Z M49 36 h4 v1 h-4Z M0 37 h4 v1 h-4Z M49 37 h4 v1 h-4Z M0 38 h4 v1 h-4Z M49 38 h4 v1 h-4Z M0 39 h4 v1 h-4Z M49 39 h4 v1 h-4Z M0 40 h4 v1 h-4Z M49 40 h4 v1 h-4Z M0 41 h4 v1 h-4Z M49 41 h4 v1 h-4Z M0 42 h4 v1 h-4Z M49 42 h4 v1 h-4Z M0 43 h4 v1 h-4Z M49 43 h4 v1 h-4Z M0 44 h4 v1 h-4Z M49 44 h4 v1 h-4Z M0 45 h4 v1 h-4Z M49 45 h4 v1 h-4Z M0 46 h4 v1 h-4Z M49 46 h4 v1 h-4Z M0 47 h4 v1 h-4Z M49 47 h4 v1 h-4Z M0 48 h4 v1 h-4Z M49 48 h4 v1 h-4Z M0 49 h53 v1 h-53Z M0 50 h53 v1 h-53Z M0 51 h53 v1 h-53Z M0 52 h53 v1 h-53Z " /><path class="qr-512 " stroke="transparent" fill="#000" fill-opacity="1" d="M12 41 h1 v1 h-1Z " /><path class="qr-1024 " stroke="transparent" fill="#000" fill-opacity="1" d="M13 4 h1 v1 h-1Z M15 4 h1 v1 h-1Z M17 4 h1 v1 h-1Z M19 4 h1 v1 h-1Z M21 4 h1 v1 h-1Z M24 4 h1 v1 h-1Z M26 4 h1 v1 h-1Z M31 4 h4 v1 h-4Z M37 4 h1 v1 h-1Z M13 5 h4 v1 h-4Z M22 5 h1 v1 h-1Z M24 5 h3 v1 h-3Z M28 5 h4 v1 h-4Z M34 5 h1 v1 h-1Z M36 5 h2 v1 h-2Z M14 6 h1 v1 h-1Z M18 6 h1 v1 h-1Z M20 6 h2 v1 h-2Z M24 6 h1 v1 h-1Z M26 6 h3 v1 h-3Z M30 6 h1 v1 h-1Z M32 6 h3 v1 h-3Z M36 6 h2 v1 h-2Z M14 7 h1 v1 h-1Z M16 7 h1 v1 h-1Z M18 7 h1 v1 h-1Z M20 7 h1 v1 h-1Z M23 7 h3 v1 h-3Z M29 7 h2 v1 h-2Z M32 7 h1 v1 h-1Z M36 7 h1 v1 h-1Z M16 8 h1 v1 h-1Z M18 8 h5 v1 h-5Z M29 8 h1 v1 h-1Z M32 8 h3 v1 h-3Z M13 9 h1 v1 h-1Z M17 9 h2 v1 h-2Z M20 9 h2 v1 h-2Z M31 9 h1 v1 h-1Z M33 9 h2 v1 h-2Z M36 9 h2 v1 h-2Z M14 11 h1 v1 h-1Z M17 11 h3 v1 h-3Z M21 11 h2 v1 h-2Z M29 11 h1 v1 h-1Z M31 11 h1 v1 h-1Z M33 11 h1 v1 h-1Z M38 11 h1 v1 h-1Z M40 11 h1 v1 h-1Z M14 12 h2 v1 h-2Z M17 12 h2 v1 h-2Z M20 12 h1 v1 h-1Z M29 12 h2 v1 h-2Z M33 12 h2 v1 h-2Z M36 12 h2 v1 h-2Z M39 12 h2 v1 h-2Z M5 13 h1 v1 h-1Z M8 13 h2 v1 h-2Z M14 13 h1 v1 h-1Z M17 13 h6 v1 h-6Z M24 13 h2 v1 h-2Z M28 13 h2 v1 h-2Z M31 13 h3 v1 h-3Z M37 13 h1 v1 h-1Z M39 13 h1 v1 h-1Z M41 13 h1 v1 h-1Z M46 13 h1 v1 h-1Z M8 14 h1 v1 h-1Z M11 14 h1 v1 h-1Z M14 14 h1 v1 h-1Z M18 14 h1 v1 h-1Z M22 14 h1 v1 h-1Z M26 14 h2 v1 h-2Z M31 14 h1 v1 h-1Z M33 14 h2 v1 h-2Z M36 14 h1 v1 h-1Z M39 14 h4 v1 h-4Z M44 14 h1 v1 h-1Z M48 14 h1 v1 h-1Z M4 15 h1 v1 h-1Z M6 15 h3 v1 h-3Z M11 15 h3 v1 h-3Z M16 15 h1 v1 h-1Z M19 15 h1 v1 h-1Z M22 15 h2 v1 h-2Z M28 15 h2 v1 h-2Z M31 15 h2 v1 h-2Z M34 15 h2 v1 h-2Z M38 15 h2 v1 h-2Z M41 15 h1 v1 h-1Z M43 15 h1 v1 h-1Z M46 15 h1 v1 h-1Z M6 16 h1 v1 h-1Z M8 16 h2 v1 h-2Z M11 16 h2 v1 h-2Z M14 16 h6 v1 h-6Z M21 16 h1 v1 h-1Z M24 16 h1 v1 h-1Z M27 16 h2 v1 h-2Z M30 16 h3 v1 h-3Z M35 16 h1 v1 h-1Z M37 16 h1 v1 h-1Z M40 16 h1 v1 h-1Z M42 16 h2 v1 h-2Z M46 16 h1 v1 h-1Z M48 16 h1 v1 h-1Z M5 17 h4 v1 h-4Z M11 17 h1 v1 h-1Z M15 17 h1 v1 h-1Z M17 17 h1 v1 h-1Z M20 17 h4 v1 h-4Z M26 17 h3 v1 h-3Z M31 17 h1 v1 h-1Z M34 17 h3 v1 h-3Z M40 17 h1 v1 h-1Z M43 17 h4 v1 h-4Z M48 17 h1 v1 h-1Z M4 18 h2 v1 h-2Z M7 18 h2 v1 h-2Z M11 18 h1 v1 h-1Z M13 18 h1 v1 h-1Z M15 18 h1 v1 h-1Z M17 18 h1 v1 h-1Z M20 18 h1 v1 h-1Z M23 18 h1 v1 h-1Z M26 18 h1 v1 h-1Z M30 18 h1 v1 h-1Z M34 18 h2 v1 h-2Z M41 18 h1 v1 h-1Z M43 18 h1 v1 h-1Z M46 18 h3 v1 h-3Z M4 19 h1 v1 h-1Z M7 19 h3 v1 h-3Z M12 19 h1 v1 h-1Z M14 19 h2 v1 h-2Z M21 19 h2 v1 h-2Z M29 19 h1 v1 h-1Z M31 19 h3 v1 h-3Z M36 19 h2 v1 h-2Z M40 19 h1 v1 h-1Z M43 19 h1 v1 h-1Z M48 19 h1 v1 h-1Z M4 20 h1 v1 h-1Z M6 20 h4 v1 h-4Z M12 20 h1 v1 h-1Z M14 20 h1 v1 h-1Z M18 20 h2 v1 h-2Z M21 20 h1 v1 h-1Z M23 20 h1 v1 h-1Z M26 20 h2 v1 h-2Z M32 20 h7 v1 h-7Z M41 20 h2 v1 h-2Z M44 20 h2 v1 h-2Z M48 20 h1 v1 h-1Z M4 21 h2 v1 h-2Z M8 21 h2 v1 h-2Z M15 21 h1 v1 h-1Z M17 21 h3 v1 h-3Z M21 21 h1 v1 h-1Z M24 21 h1 v1 h-1Z M26 21 h1 v1 h-1Z M28 21 h1 v1 h-1Z M32 21 h2 v1 h-2Z M35 21 h1 v1 h-1Z M37 21 h1 v1 h-1Z M41 21 h1 v1 h-1Z M44 21 h2 v1 h-2Z M48 21 h1 v1 h-1Z M4 22 h1 v1 h-1Z M6 22 h2 v1 h-2Z M11 22 h1 v1 h-1Z M14 22 h1 v1 h-1Z M16 22 h2 v1 h-2Z M19 22 h2 v1 h-2Z M25 22 h2 v1 h-2Z M28 22 h1 v1 h-1Z M30 22 h5 v1 h-5Z M37 22 h3 v1 h-3Z M43 22 h1 v1 h-1Z M46 22 h3 v1 h-3Z M4 23 h5 v1 h-5Z M11 23 h5 v1 h-5Z M17 23 h1 v1 h-1Z M20 23 h1 v1 h-1Z M22 23 h1 v1 h-1Z M25 23 h2 v1 h-2Z M29 23 h3 v1 h-3Z M34 23 h3 v1 h-3Z M38 23 h2 v1 h-2Z M42 23 h3 v1 h-3Z M4 24 h3 v1 h-3Z M13 24 h2 v1 h-2Z M16 24 h2 v1 h-2Z M23 24 h1 v1 h-1Z M29 24 h1 v1 h-1Z M31 24 h2 v1 h-2Z M36 24 h1 v1 h-1Z M4 25 h1 v1 h-1Z M6 25 h1 v1 h-1Z M13 25 h4 v1 h-4Z M18 25 h1 v1 h-1Z M21 25 h2 v1 h-2Z M32 25 h1 v1 h-1Z M34 25 h3 v1 h-3Z M38 25 h1 v1 h-1Z M47 25 h2 v1 h-2Z M5 26 h2 v1 h-2Z M13 26 h1 v1 h-1Z M15 26 h8 v1 h-8Z M29 26 h1 v1 h-1Z M31 26 h2 v1 h-2Z M34 26 h1 v1 h-1Z M36 26 h1 v1 h-1Z M38 26 h1 v1 h-1Z M46 26 h3 v1 h-3Z M4 27 h2 v1 h-2Z M7 27 h1 v1 h-1Z M14 27 h2 v1 h-2Z M17 27 h3 v1 h-3Z M30 27 h3 v1 h-3Z M34 27 h1 v1 h-1Z M37 27 h1 v1 h-1Z M39 27 h1 v1 h-1Z M18 28 h2 v1 h-2Z M22 28 h2 v1 h-2Z M29 28 h1 v1 h-1Z M32 28 h3 v1 h-3Z M36 28 h3 v1 h-3Z M47 28 h1 v1 h-1Z M5 29 h1 v1 h-1Z M8 29 h1 v1 h-1Z M11 29 h3 v1 h-3Z M16 29 h1 v1 h-1Z M19 29 h5 v1 h-5Z M30 29 h1 v1 h-1Z M37 29 h1 v1 h-1Z M41 29 h2 v1 h-2Z M46 29 h1 v1 h-1Z M4 30 h3 v1 h-3Z M9 30 h1 v1 h-1Z M12 30 h1 v1 h-1Z M14 30 h1 v1 h-1Z M16 30 h3 v1 h-3Z M21 30 h2 v1 h-2Z M26 30 h1 v1 h-1Z M29 30 h1 v1 h-1Z M33 30 h2 v1 h-2Z M36 30 h4 v1 h-4Z M41 30 h1 v1 h-1Z M43 30 h2 v1 h-2Z M48 30 h1 v1 h-1Z M5 31 h2 v1 h-2Z M8 31 h1 v1 h-1Z M11 31 h2 v1 h-2Z M14 31 h3 v1 h-3Z M18 31 h1 v1 h-1Z M20 31 h3 v1 h-3Z M24 31 h2 v1 h-2Z M27 31 h1 v1 h-1Z M32 31 h1 v1 h-1Z M34 31 h2 v1 h-2Z M38 31 h2 v1 h-2Z M41 31 h1 v1 h-1Z M46 31 h1 v1 h-1Z M4 32 h1 v1 h-1Z M6 32 h2 v1 h-2Z M11 32 h2 v1 h-2Z M14 32 h2 v1 h-2Z M17 32 h1 v1 h-1Z M19 32 h2 v1 h-2Z M22 32 h1 v1 h-1Z M25 32 h1 v1 h-1Z M30 32 h3 v1 h-3Z M35 32 h1 v1 h-1Z M37 32 h1 v1 h-1Z M42 32 h2 v1 h-2Z M46 32 h1 v1 h-1Z M48 32 h1 v1 h-1Z M6 33 h1 v1 h-1Z M8 33 h1 v1 h-1Z M11 33 h2 v1 h-2Z M15 33 h1 v1 h-1Z M18 33 h1 v1 h-1Z M20 33 h1 v1 h-1Z M22 33 h1 v1 h-1Z M25 33 h1 v1 h-1Z M27 33 h1 v1 h-1Z M29 33 h1 v1 h-1Z M32 33 h1 v1 h-1Z M34 33 h3 v1 h-3Z M39 33 h1 v1 h-1Z M45 33 h1 v1 h-1Z M47 33 h1 v1 h-1Z M4 34 h1 v1 h-1Z M11 34 h1 v1 h-1Z M13 34 h6 v1 h-6Z M21 34 h2 v1 h-2Z M24 34 h1 v1 h-1Z M26 34 h2 v1 h-2Z M29 34 h2 v1 h-2Z M32 34 h1 v1 h-1Z M34 34 h2 v1 h-2Z M40 34 h1 v1 h-1Z M42 34 h1 v1 h-1Z M44 34 h4 v1 h-4Z M5 35 h1 v1 h-1Z M7 35 h1 v1 h-1Z M11 35 h2 v1 h-2Z M15 35 h1 v1 h-1Z M21 35 h2 v1 h-2Z M28 35 h2 v1 h-2Z M31 35 h1 v1 h-1Z M38 35 h3 v1 h-3Z M45 35 h1 v1 h-1Z M47 35 h2 v1 h-2Z M4 36 h1 v1 h-1Z M7 36 h1 v1 h-1Z M11 36 h1 v1 h-1Z M13 36 h2 v1 h-2Z M16 36 h4 v1 h-4Z M21 36 h1 v1 h-1Z M25 36 h2 v1 h-2Z M29 36 h3 v1 h-3Z M34 36 h1 v1 h-1Z M36 36 h6 v1 h-6Z M44 36 h4 v1 h-4Z M4 37 h1 v1 h-1Z M7 37 h3 v1 h-3Z M12 37 h1 v1 h-1Z M15 37 h2 v1 h-2Z M21 37 h3 v1 h-3Z M25 37 h1 v1 h-1Z M28 37 h2 v1 h-2Z M31 37 h2 v1 h-2Z M34 37 h1 v1 h-1Z M37 37 h1 v1 h-1Z M40 37 h3 v1 h-3Z M44 37 h1 v1 h-1Z M48 37 h1 v1 h-1Z M20 38 h3 v1 h-3Z M26 38 h1 v1 h-1Z M31 38 h2 v1 h-2Z M36 38 h1 v1 h-1Z M39 38 h1 v1 h-1Z M41 38 h1 v1 h-1Z M46 38 h3 v1 h-3Z M12 39 h1 v1 h-1Z M16 39 h2 v1 h-2Z M23 39 h1 v1 h-1Z M27 39 h3 v1 h-3Z M31 39 h6 v1 h-6Z M38 39 h2 v1 h-2Z M41 39 h1 v1 h-1Z M44 39 h1 v1 h-1Z M48 39 h1 v1 h-1Z M11 40 h1 v1 h-1Z M16 40 h2 v1 h-2Z M19 40 h1 v1 h-1Z M23 40 h1 v1 h-1Z M29 40 h3 v1 h-3Z M35 40 h2 v1 h-2Z M45 40 h1 v1 h-1Z M48 40 h1 v1 h-1Z M18 41 h6 v1 h-6Z M29 41 h3 v1 h-3Z M33 41 h1 v1 h-1Z M36 41 h1 v1 h-1Z M38 41 h1 v1 h-1Z M47 41 h2 v1 h-2Z M14 42 h1 v1 h-1Z M17 42 h3 v1 h-3Z M22 42 h2 v1 h-2Z M35 42 h1 v1 h-1Z M38 42 h1 v1 h-1Z M45 42 h4 v1 h-4Z M13 43 h5 v1 h-5Z M23 43 h1 v1 h-1Z M29 43 h1 v1 h-1Z M31 43 h2 v1 h-2Z M34 43 h1 v1 h-1Z M36 43 h2 v1 h-2Z M39 43 h1 v1 h-1Z M47 43 h1 v1 h-1Z M15 44 h1 v1 h-1Z M17 44 h1 v1 h-1Z M19 44 h1 v1 h-1Z M23 44 h1 v1 h-1Z M31 44 h1 v1 h-1Z M35 44 h4 v1 h-4Z M47 44 h2 v1 h-2Z M16 45 h1 v1 h-1Z M18 45 h1 v1 h-1Z M21 45 h1 v1 h-1Z M24 45 h2 v1 h-2Z M31 45 h1 v1 h-1Z M33 45 h5 v1 h-5Z M39 45 h3 v1 h-3Z M15 46 h3 v1 h-3Z M19 46 h1 v1 h-1Z M21 46 h1 v1 h-1Z M23 46 h2 v1 h-2Z M26 46 h1 v1 h-1Z M28 46 h1 v1 h-1Z M31 46 h11 v1 h-11Z M44 46 h3 v1 h-3Z M48 46 h1 v1 h-1Z M14 47 h1 v1 h-1Z M16 47 h2 v1 h-2Z M19 47 h1 v1 h-1Z M21 47 h1 v1 h-1Z M26 47 h3 v1 h-3Z M32 47 h1 v1 h-1Z M35 47 h1 v1 h-1Z M38 47 h4 v1 h-4Z M45 47 h1 v1 h-1Z M47 47 h1 v1 h-1Z M18 48 h1 v1 h-1Z M21 48 h1 v1 h-1Z M23 48 h2 v1 h-2Z M28 48 h2 v1 h-2Z M35 48 h1 v1 h-1Z M39 48 h1 v1 h-1Z M41 48 h1 v1 h-1Z M44 48 h1 v1 h-1Z M47 48 h2 v1 h-2Z " /><path class="qr-1536 " stroke="transparent" fill="#000" fill-opacity="1" d="M4 4 h7 v1 h-7Z M42 4 h7 v1 h-7Z M4 5 h1 v1 h-1Z M10 5 h1 v1 h-1Z M42 5 h1 v1 h-1Z M48 5 h1 v1 h-1Z M4 6 h1 v1 h-1Z M10 6 h1 v1 h-1Z M42 6 h1 v1 h-1Z M48 6 h1 v1 h-1Z M4 7 h1 v1 h-1Z M10 7 h1 v1 h-1Z M42 7 h1 v1 h-1Z M48 7 h1 v1 h-1Z M4 8 h1 v1 h-1Z M10 8 h1 v1 h-1Z M42 8 h1 v1 h-1Z M48 8 h1 v1 h-1Z M4 9 h1 v1 h-1Z M10 9 h1 v1 h-1Z M42 9 h1 v1 h-1Z M48 9 h1 v1 h-1Z M4 10 h7 v1 h-7Z M42 10 h7 v1 h-7Z M4 42 h7 v1 h-7Z M4 43 h1 v1 h-1Z M10 43 h1 v1 h-1Z M4 44 h1 v1 h-1Z M10 44 h1 v1 h-1Z M4 45 h1 v1 h-1Z M10 45 h1 v1 h-1Z M4 46 h1 v1 h-1Z M10 46 h1 v1 h-1Z M4 47 h1 v1 h-1Z M10 47 h1 v1 h-1Z M4 48 h7 v1 h-7Z " /><path class="qr-2560 " stroke="transparent" fill="#000" fill-opacity="1" d="M24 8 h5 v1 h-5Z M24 9 h1 v1 h-1Z M28 9 h1 v1 h-1Z M24 10 h1 v1 h-1Z M26 10 h1 v1 h-1Z M28 10 h1 v1 h-1Z M24 11 h1 v1 h-1Z M28 11 h1 v1 h-1Z M24 12 h5 v1 h-5Z M8 24 h5 v1 h-5Z M24 24 h5 v1 h-5Z M40 24 h5 v1 h-5Z M8 25 h1 v1 h-1Z M12 25 h1 v1 h-1Z M24 25 h1 v1 h-1Z M28 25 h1 v1 h-1Z M40 25 h1 v1 h-1Z M44 25 h1 v1 h-1Z M8 26 h1 v1 h-1Z M10 26 h1 v1 h-1Z M12 26 h1 v1 h-1Z M24 26 h1 v1 h-1Z M26 26 h1 v1 h-1Z M28 26 h1 v1 h-1Z M40 26 h1 v1 h-1Z M42 26 h1 v1 h-1Z M44 26 h1 v1 h-1Z M8 27 h1 v1 h-1Z M12 27 h1 v1 h-1Z M24 27 h1 v1 h-1Z M28 27 h1 v1 h-1Z M40 27 h1 v1 h-1Z M44 27 h1 v1 h-1Z M8 28 h5 v1 h-5Z M24 28 h5 v1 h-5Z M40 28 h5 v1 h-5Z M24 40 h5 v1 h-5Z M40 40 h5 v1 h-5Z M24 41 h1 v1 h-1Z M28 41 h1 v1 h-1Z M40 41 h1 v1 h-1Z M44 41 h1 v1 h-1Z M24 42 h1 v1 h-1Z M26 42 h1 v1 h-1Z M28 42 h1 v1 h-1Z M40 42 h1 v1 h-1Z M42 42 h1 v1 h-1Z M44 42 h1 v1 h-1Z M24 43 h1 v1 h-1Z M28 43 h1 v1 h-1Z M40 43 h1 v1 h-1Z M44 43 h1 v1 h-1Z M24 44 h5 v1 h-5Z M40 44 h5 v1 h-5Z " /><path class="qr-3072 " stroke="transparent" fill="#000" fill-opacity="1" d="M12 10 h1 v1 h-1Z M14 10 h1 v1 h-1Z M16 10 h1 v1 h-1Z M18 10 h1 v1 h-1Z M20 10 h1 v1 h-1Z M22 10 h1 v1 h-1Z M30 10 h1 v1 h-1Z M32 10 h1 v1 h-1Z M34 10 h1 v1 h-1Z M36 10 h1 v1 h-1Z M38 10 h1 v1 h-1Z M40 10 h1 v1 h-1Z M10 12 h1 v1 h-1Z M10 14 h1 v1 h-1Z M10 16 h1 v1 h-1Z M10 18 h1 v1 h-1Z M10 20 h1 v1 h-1Z M10 22 h1 v1 h-1Z M10 30 h1 v1 h-1Z M10 32 h1 v1 h-1Z M10 34 h1 v1 h-1Z M10 36 h1 v1 h-1Z M10 38 h1 v1 h-1Z M10 40 h1 v1 h-1Z " /><path class="qr-3584 " stroke="transparent" fill="#000" fill-opacity="1" d="M12 4 h1 v1 h-1Z M12 7 h1 v1 h-1Z M6 12 h1 v1 h-1Z M8 12 h2 v1 h-2Z M12 12 h1 v1 h-1Z M41 12 h1 v1 h-1Z M45 12 h1 v1 h-1Z M48 12 h1 v1 h-1Z M12 43 h1 v1 h-1Z M12 44 h1 v1 h-1Z M12 46 h1 v1 h-1Z " /><path class="qr-4096 " stroke="transparent" fill="#000" fill-opacity="1" d="M40 4 h1 v1 h-1Z M39 5 h1 v1 h-1Z M39 6 h1 v1 h-1Z M39 7 h2 v1 h-2Z M38 8 h3 v1 h-3Z M8 38 h1 v1 h-1Z M5 39 h4 v1 h-4Z M4 40 h1 v1 h-1Z M7 40 h2 v1 h-2Z " /><path class="qr-5632 " stroke="transparent" fill="#000" fill-opacity="1" d="M6 6 h3 v1 h-3Z M44 6 h3 v1 h-3Z M6 7 h3 v1 h-3Z M44 7 h3 v1 h-3Z M6 8 h3 v1 h-3Z M44 8 h3 v1 h-3Z M6 44 h3 v1 h-3Z M6 45 h3 v1 h-3Z M6 46 h3 v1 h-3Z " /></svg>

    </a>
    <figcaption aria-hidden="true" class="hidden" hidden>Reward Stéphane HUC</figcaption>
</figure>


<h2 id="who">Who</h2>
<h3 id="2020">2020</h3>
<p>⇒ In October:</p>
<ul>
<li>@scorpus</li>
</ul>
<h3 id="2022">2022</h3>
<p>⇒ In November:</p>
<ul>
<li>@Cascador</li>
</ul>
<h2 id="what">What</h2>
<h3 id="2020-1">2020</h3>
<ul>
<li>one <strong>trappiste rochefort 10</strong> beer: 5€</li>
</ul>
<h3 id="2022-1">2022</h3>
<ul>
<li>5 dozens of €</li>
</ul>
<hr>
]]></content><summary>About donations</summary><published>2020-02-21T19:59:41+01:00</published><updated>2026-10-02T15:49:57+02:00</updated></entry><entry><id>tag:doc.huc.fr.eu.org,2020-01-02:/en/web/hugo/hugo-openbsd</id><link href="https://it-log.fr.eu.org/en/web/hugo/hugo-openbsd/" rel="alternate" type="text/html"/><title>Hugo: Use the tool build by the project on OpenBSD</title><author><name>Stéphane HUC</name></author><category term="Hugo" scheme="https://it-log.fr.eu.org/en/tags/hugo/"/><category term="OpenBSD" scheme="https://it-log.fr.eu.org/en/tags/openbsd/"/><content type="html"><![CDATA[<h2 id="description">Description</h2>
<p>It&rsquo;s really easy to use, without troubles, Hugo on OpenBSD.</p>
<p>To install the package: <br>
<code>:# pkg_add hugo</code></p>
<ul>
<li>Hugo version: <strong>0.53</strong> : <code>Hugo Static Site Generator v0.53 openbsd/amd64 BuildDate: unknown</code></li>
<li>OpenBSD: <strong>6.6</strong></li>
<li>Architecture: <strong>amd64</strong></li>
</ul>
<p>But, this version is more year old, and has a lot of bugs.</p>
<h2 id="utilisation">Utilisation</h2>
<p>The Hugo project build releases to download and uncompress; there are 3 files,
the binary <code>hugo</code>, and files <code>LICENSE</code>, <code>README.md</code>.</p>
<p>The archives are intended for 32-bits <em>(i386)</em>, 64-bits <em>(amd64)</em>, and ARM
architectures.</p>

<div class="tab-info i-tip">Tip</div><div class="alert alert-tip" role="alert">Add your personal folder <code>bin/</code> at the environment variable <code>PATH</code>, and put
hugo binary in this folder, or symlink-it!</div>

<p>The purpose of this article is to &ldquo;show up&rdquo; the various pitfalls related to t
hese official binaries, which sometimes generate changes in Hugo&rsquo;s configuration,
or even malfunctions.</p>
<p>The ultimage version really functionnal is: <strong>0.59.1</strong>.</p>
<h2 id="importants-changes">Importants Changes</h2>
<h3 id="v0540">v0.54.0</h3>
<ul>
<li>version: <code>Hugo Static Site Generator v0.54.0-B1A82C61 openbsd/amd64 BuildDate: 2019-02-01T09:41:10Z</code></li>
</ul>
<p>In fact, <code>hugo server</code> not run, and exit with error: <code>Error: Error building site: EOF</code></p>
<p>Bye-bye!</p>
<h3 id="v0550">v0.55.0</h3>
<ul>
<li>version: <code>Hugo Static Site Generator v0.55.0-4333CC77 openbsd/amd64 BuildDate: 2019-04-08T16:41:18Z</code></li>
</ul>

<div class="tab-info i-warning">Warning</div><div class="alert alert-warning" role="alert">This version brings changes in the execution of <a href="/en/web/hugo/hugo-openbsd/#shortcodes">shortcodes</a>,
<a href="/en/web/hugo/hugo-openbsd/#taxonomy">taxonomy</a>, …</div>

<h3 id="v06x">v0.6x</h3>
<ul>
<li>versions 0.60.(x), 0.61.0, 0.62.(x)</li>
</ul>
<p>Since version 0.60.0, there is a new engine: the <strong>goldmark</strong>.</p>
<p>It&rsquo;s necessary to change your file configuration, as (for the toml format):</p>
<pre tabindex="0"><code>[markup.goldmark.renderer]
    unsafe = true
</code></pre><p>But, it exists this <a href="https://github.com/gohugoio/hugo/issues/6553" rel="external">bug</a>, in the
rendering of HTML code within the shortcodes.</p>
<p>For the moment, prefer to use v0.59.1!</p>
<h2 id="deprecated">Deprecated</h2>
<h3 id="pagehugo-is-deprecated">Page.Hugo is deprecated</h3>
<p>This message <code>Page.Hugo is deprecated and will be removed in a future release. Use the global hugo function.</code> says <code>.Hugo</code> variable is deprecated.</p>
<p>You need to replace by the global <code>hugo</code> function.</p>
<p>See: <a href="https://gohugo.io/variables/hugo/" title="Link to the official site Hugo: Variables &gt; Hugo">Hugo Documentation: Variables &gt; Hugo</a>
</p>
<h3 id="pages-rsslink-is-deprecated">Page&rsquo;s .RSSLink is deprecated</h3>
<p>This message <code>Page's .RSSLink is deprecated and will be removed in a future release. Use the Output Format's link</code> informs <code>.RSSLink</code> variable is deprecated.</p>
<p>Prefer to use: <code>{{`` with .OutputFormats.Get &quot;RSS&quot; }}{{ .RelPermalink }}{{ end }}</code></p>
<p>See: <a href="https://gohugo.io/templates/output-formats/" title="Link to the official site Hugo: Templates &gt; Output formats">Hugo Documentation: Templates &gt; Output formats</a>
</p>
<h3 id="pages-url-is-deprecated">Page&rsquo;s .URL is deprecated</h3>
<p>The message <code>Page's .URL is deprecated and will be removed in a future release. Use .Permalink or .RelPermalink.</code> notifies to stop using the <code>.URL</code> variable.</p>
<p>You need to replace by <code>.Permalink</code>.</p>

<div class="tab-info i-info">Info</div><div class="alert alert-info" role="alert"><p>Not confuse with the <code>.URL</code> variable into menu or pagination contexts!</p>
<p>(cf: <a href="https://gohugo.io/variables/menus/#menu-entry-variables" title="Link to the official site Hugo: Variables &gt; Menus">Hugo Documentation: Variables &gt; Menus</a>
)</p>
</div>

<h2 id="recommandations">Recommandations</h2>
<h3 id="shortcodes">Shortcodes</h3>
<p>It is therefore recommended that you no longer use the <code>{{``% shortcode %}}</code>
syntax, but prefer <code>{{``&lt; shortcode &gt;}}</code> syntax and use the <code>markdownify</code>
function.</p>
<p>See: <a href="https://gohugo.io/functions/markdownify/" title="Link to the official site Hugo: Functions &gt; Markdownify">Hugo Documentation: Functions &gt; Markdownify</a>
.</p>
<h3 id="taxonomy">Taxonomy</h3>
<p>Taxonomy nodes have a new accessor named <code>.Page</code>. It simplifies the use of
differents variables, as <code>.Titre</code>.</p>
<p>Instead of using <code>{{ range .Data.Terms.Alphabetical }}</code>, use
<code>{{ range .Site.Taxonomies.tags }}</code>.</p>
<hr>
]]></content><summary>Review about differents versions of Hugo build by the project on OpenBSD stable</summary><published>2020-01-02T16:02:59+01:00</published><updated>2026-10-02T15:49:57+02:00</updated></entry><entry><id>tag:doc.huc.fr.eu.org,2019-12-23:/en/web/nextcloud/nextcloud-loop-login</id><link href="https://it-log.fr.eu.org/en/web/nextcloud/nextcloud-loop-login/" rel="alternate" type="text/html"/><title>(tip) Nextcloud : loop login</title><author><name>Stéphane HUC</name></author><category term="Nextcloud" scheme="https://it-log.fr.eu.org/en/tags/nextcloud/"/><category term="login" scheme="https://it-log.fr.eu.org/en/tags/login/"/><category term="tip" scheme="https://it-log.fr.eu.org/en/tags/tip/"/><content type="html"><![CDATA[<h2 id="description">Description</h2>
<p>&ldquo;Once upon a time…&rdquo;, you need to connect at your WebUI Nextcloud, with your ids.
Normal!</p>
<p>But, this day, you cant: impossible to connect. You&rsquo;re redirected on
<code>login?redirect_url=/apps/files/</code> and your ids are asked again! Booo.</p>
<p>&ldquo;You&rsquo;re under a loop login!&rdquo;</p>
<h2 id="resolution">Resolution</h2>
<p><span class="red">Check</span>
 :</p>
<ul>
<li><strong>read an write permissions</strong> on thoses folders:
<ul>
<li><code>netcloud</code> : <code>0750</code></li>
<li><code>cache</code> : <code>0755</code></li>
<li>and, for the sessions PHP: <code>0750</code> seems to be functional, else <code>0755</code>.</li>
</ul>
</li>
<li><strong>user rights</strong> on same folders: those of your web user and group; default,
on OpenBSD <code>www</code>, but this depends on your web architecture <em>(i.e, Apache, Nginx, etc)</em>
and your <abbr title="Operating System">OS</abbr>
.</li>
</ul>
<h3 id="openbsd">OpenBSD</h3>
<p>On OpenBSD, I noticied this little problem: after a PHP upgrade, user rights on
folders <code>cache</code>, <code>tmp</code> in the chroot are reset for <code>root:daemon</code> and <code>0700</code>
with <code>sticky bit</code>.</p>
<p>It seems necessary to set at the web user, web group and change again read and
write permissions to <code>0755</code>.</p>
<h2 id="acknowledgement">Acknowledgement</h2>
<ul>
<li><em><a href="https://www.ryadel.com/en/nextcloud-13-login-page-redirect-loop-how-to-fix-it/" rel="external">source</a></em></li>
</ul>
<hr>
]]></content><summary>Nextcloud : How to resolve the loop login problem…</summary><published>2019-12-23T18:27:34+01:00</published><updated>2026-10-02T15:49:57+02:00</updated></entry><entry><id>tag:doc.huc.fr.eu.org,2019-12-06:/en/web/hugo/hugo-search-jqueryui-autocomplete</id><link href="https://it-log.fr.eu.org/en/web/hugo/hugo-search-jqueryui-autocomplete/" rel="alternate" type="text/html"/><title>Hugo Search: an internal search engine (JQueryUI autocomplete)</title><author><name>Stéphane HUC</name></author><category term="Hugo" scheme="https://it-log.fr.eu.org/en/tags/hugo/"/><category term="search" scheme="https://it-log.fr.eu.org/en/tags/search/"/><category term="JQuery" scheme="https://it-log.fr.eu.org/en/tags/jquery/"/><content type="html"><![CDATA[<h2 id="description">Description</h2>
<p>Adding a function <code>search</code> into static website made with Hugo can be done in differents ways.</p>
<p>We will code this simply with JQuery+UI, in few minutes.</p>
<p>We will use the Hugo <code>site.Pages</code> variable, and the JQueryUI <code>autocomplete()</code> method.</p>
<p>I assume you known how to add correctly the both JQuery and JQueryUI librairies on your site.</p>
<h2 id="codes">Codes</h2>
<h3 id="jqueryui">JQueryUI</h3>
<p>As explain into the description section, we use the events of the method <code>autocomplete()</code>.
We build the <code>$projects</code> variable to iterate over the Hugo <code>$pages</code> variable
with the Hugo <code>range</code> function.</p>
<p>The JQuery code:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-js" data-lang="js"><span style="display:flex;"><span><span style="color:#5bc4bf">&lt;</span><span style="color:#06b6ef">script</span><span style="color:#5bc4bf">&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">$</span>(<span style="color:#815ba4">function</span>() {
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">var</span> <span style="color:#06b6ef">projects</span> <span style="color:#5bc4bf">=</span> [
</span></span><span style="display:flex;"><span>        {{<span style="color:#5bc4bf">-</span> <span style="color:#06b6ef">range</span> <span style="color:#06b6ef">site</span>.<span style="color:#06b6ef">Pages</span> <span style="color:#5bc4bf">-</span>}}
</span></span><span style="display:flex;"><span>            {{<span style="color:#5bc4bf">-</span> <span style="color:#06b6ef">$url</span> <span style="color:#5bc4bf">:=</span> .<span style="color:#06b6ef">RelPermalink</span> <span style="color:#5bc4bf">-</span>}}
</span></span><span style="display:flex;"><span>            {{<span style="color:#5bc4bf">-</span> <span style="color:#06b6ef">$title</span> <span style="color:#5bc4bf">:=</span> .<span style="color:#06b6ef">LinkTitle</span> <span style="color:#5bc4bf">-</span>}}
</span></span><span style="display:flex;"><span>        {
</span></span><span style="display:flex;"><span>            <span style="color:#06b6ef">value</span><span style="color:#5bc4bf">:</span> <span style="color:#48b685">&#34;{{ $title }}&#34;</span>,
</span></span><span style="display:flex;"><span>			<span style="color:#06b6ef">label</span><span style="color:#5bc4bf">:</span> <span style="color:#48b685">&#34;{{- if eq $url $baseURL }}{{ site.Params.description }}{{ else if in $url &#34;</span><span style="color:#06b6ef">tags</span><span style="color:#48b685">&#34; }}{{- T &#34;</span><span style="color:#06b6ef">pageListTitle</span><span style="color:#48b685">&#34; }}{{ $title }}{{ else }}{{- safeHTML .Params.description -}}{{ end -}}&#34;</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#06b6ef">url</span><span style="color:#5bc4bf">:</span><span style="color:#48b685">&#34;{{ $url }}&#34;</span>
</span></span><span style="display:flex;"><span>        },
</span></span><span style="display:flex;"><span>        {{<span style="color:#5bc4bf">-</span> <span style="color:#06b6ef">end</span> <span style="color:#5bc4bf">-</span>}}
</span></span><span style="display:flex;"><span>    ];
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">$</span>(<span style="color:#48b685">&#34;#search&#34;</span>).<span style="color:#06b6ef">autocomplete</span>({
</span></span><span style="display:flex;"><span>		<span style="color:#06b6ef">minLength</span><span style="color:#5bc4bf">:</span> <span style="color:#f99b15">0</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#06b6ef">source</span><span style="color:#5bc4bf">:</span> <span style="color:#06b6ef">projects</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#06b6ef">focus</span><span style="color:#5bc4bf">:</span> <span style="color:#815ba4">function</span>( <span style="color:#06b6ef">event</span>, <span style="color:#06b6ef">ui</span> ) {
</span></span><span style="display:flex;"><span>			<span style="color:#06b6ef">$</span>(<span style="color:#48b685">&#34;#search&#34;</span>).<span style="color:#06b6ef">val</span>( <span style="color:#06b6ef">ui</span>.<span style="color:#06b6ef">item</span>.<span style="color:#06b6ef">label</span> );
</span></span><span style="display:flex;"><span>			<span style="color:#815ba4">return</span> <span style="color:#815ba4">false</span>;
</span></span><span style="display:flex;"><span>        },
</span></span><span style="display:flex;"><span>        <span style="color:#06b6ef">select</span><span style="color:#5bc4bf">:</span> <span style="color:#815ba4">function</span>( <span style="color:#06b6ef">event</span>, <span style="color:#06b6ef">ui</span> ) {
</span></span><span style="display:flex;"><span>			<span style="color:#06b6ef">$</span>(<span style="color:#48b685">&#34;#search&#34;</span>).<span style="color:#06b6ef">val</span>( <span style="color:#06b6ef">ui</span>.<span style="color:#06b6ef">item</span>.<span style="color:#06b6ef">label</span> );
</span></span><span style="display:flex;"><span>			<span style="color:#06b6ef">$</span>(<span style="color:#48b685">&#34;#replyer&#34;</span>).<span style="color:#06b6ef">val</span>( <span style="color:#06b6ef">ui</span>.<span style="color:#06b6ef">item</span>.<span style="color:#06b6ef">value</span> );
</span></span><span style="display:flex;"><span>			<span style="color:#815ba4">return</span> <span style="color:#815ba4">false</span>;
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>    })
</span></span><span style="display:flex;"><span>    .<span style="color:#06b6ef">data</span>(<span style="color:#48b685">&#39;ui-autocomplete&#39;</span>).<span style="color:#06b6ef">_renderItem</span> <span style="color:#5bc4bf">=</span> <span style="color:#815ba4">function</span>(<span style="color:#06b6ef">ul</span>, <span style="color:#06b6ef">item</span>) {
</span></span><span style="display:flex;"><span>        <span style="color:#815ba4">return</span> <span style="color:#06b6ef">$</span>(<span style="color:#48b685">&#39;&lt;li&gt;&#39;</span>)
</span></span><span style="display:flex;"><span>        .<span style="color:#06b6ef">append</span>(<span style="color:#48b685">&#39;&lt;a href=&#34;&#39;</span> <span style="color:#5bc4bf">+</span> <span style="color:#06b6ef">item</span>.<span style="color:#06b6ef">url</span> <span style="color:#5bc4bf">+</span> <span style="color:#48b685">&#39;&#34; alt=&#34;&#39;</span><span style="color:#5bc4bf">+</span> <span style="color:#06b6ef">item</span>.<span style="color:#06b6ef">label</span> <span style="color:#5bc4bf">+</span> <span style="color:#48b685">&#39;&#34;&gt;&#39;</span> <span style="color:#5bc4bf">+</span> <span style="color:#06b6ef">item</span>.<span style="color:#06b6ef">value</span> <span style="color:#5bc4bf">+</span> <span style="color:#48b685">&#39;&lt;/a&gt;&#39;</span> )
</span></span><span style="display:flex;"><span>        .<span style="color:#06b6ef">appendTo</span>(<span style="color:#06b6ef">ul</span>);
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>});
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">&lt;</span><span style="color:#ef6155">/script&gt;</span>
</span></span></code></pre></div><h3 id="html">HTML</h3>
<p>And for the simplest code HTML, we use two elements <code>input</code> as:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-html" data-lang="html"><span style="display:flex;"><span>&lt;<span style="color:#5bc4bf">input</span> <span style="color:#06b6ef">class</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;form-control&#34;</span> <span style="color:#06b6ef">id</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;search&#34;</span> <span style="color:#06b6ef">placeholder</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;{{ T &#34;</span><span style="color:#06b6ef">searchHolderTitle</span><span style="color:#ef6155">&#34;</span> <span style="color:#ef6155">}}&#34;</span>&gt;
</span></span><span style="display:flex;"><span>&lt;<span style="color:#5bc4bf">input</span> <span style="color:#06b6ef">aria-hidden</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;true&#34;</span> <span style="color:#06b6ef">id</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;replyer&#34;</span> <span style="color:#06b6ef">class</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;hidden&#34;</span>&gt;
</span></span></code></pre></div><ul>
<li>the first catch the searched text</li>
<li>the second return all found titles, and in the background the equivalent URL.</li>
<li>the syntax <code>{{ i18n &quot;searchHolderTitle&quot; }}</code> exists for the multilanguage
context on this website; You can replace with your personal text.</li>
</ul>
<h3 id="tldr">TL;DR</h3>
<p>The fully code:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-html" data-lang="html"><span style="display:flex;"><span>&lt;<span style="color:#5bc4bf">div</span> <span style="color:#06b6ef">id</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;search&#34;</span>&gt;
</span></span><span style="display:flex;"><span>    &lt;<span style="color:#5bc4bf">input</span> <span style="color:#06b6ef">class</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;form-control&#34;</span> <span style="color:#06b6ef">id</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;search&#34;</span> <span style="color:#06b6ef">placeholder</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;{{ T &#34;</span><span style="color:#06b6ef">searchHolderTitle</span><span style="color:#ef6155">&#34;</span> <span style="color:#ef6155">}}&#34;</span>&gt;
</span></span><span style="display:flex;"><span>    &lt;<span style="color:#5bc4bf">input</span> <span style="color:#06b6ef">aria-hidden</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;true&#34;</span> <span style="color:#06b6ef">id</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;replyer&#34;</span> <span style="color:#06b6ef">class</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;hidden&#34;</span>&gt;
</span></span><span style="display:flex;"><span>    {{- $baseURL := site.BaseURL | absLangURL -}}
</span></span><span style="display:flex;"><span>    <span style="color:#776e71">&lt;!-- Javascript --&gt;</span>
</span></span><span style="display:flex;"><span>&lt;<span style="color:#5bc4bf">script</span>&gt;
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">$</span>(<span style="color:#815ba4">function</span>() {
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">var</span> <span style="color:#06b6ef">projects</span> <span style="color:#5bc4bf">=</span> [
</span></span><span style="display:flex;"><span>        {{<span style="color:#5bc4bf">-</span> <span style="color:#06b6ef">range</span> <span style="color:#06b6ef">site</span>.<span style="color:#06b6ef">Pages</span> <span style="color:#5bc4bf">-</span>}}
</span></span><span style="display:flex;"><span>            {{<span style="color:#5bc4bf">-</span> <span style="color:#06b6ef">$url</span> <span style="color:#5bc4bf">:=</span> .<span style="color:#06b6ef">RelPermalink</span> <span style="color:#5bc4bf">-</span>}}
</span></span><span style="display:flex;"><span>            {{<span style="color:#5bc4bf">-</span> <span style="color:#06b6ef">$title</span> <span style="color:#5bc4bf">:=</span> .<span style="color:#06b6ef">LinkTitle</span> <span style="color:#5bc4bf">-</span>}}
</span></span><span style="display:flex;"><span>        {
</span></span><span style="display:flex;"><span>            <span style="color:#06b6ef">value</span><span style="color:#5bc4bf">:</span> <span style="color:#48b685">&#34;{{ $title }}&#34;</span>,
</span></span><span style="display:flex;"><span>			<span style="color:#06b6ef">label</span><span style="color:#5bc4bf">:</span> <span style="color:#48b685">&#34;{{- if eq $url $baseURL }}{{ site.Params.description }}{{ else if in $url &#34;</span><span style="color:#06b6ef">tags</span><span style="color:#48b685">&#34; }}{{- T &#34;</span><span style="color:#06b6ef">pageListTitle</span><span style="color:#48b685">&#34; }}{{ $title }}{{ else }}{{- safeHTML .Params.description -}}{{ end -}}&#34;</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#06b6ef">url</span><span style="color:#5bc4bf">:</span><span style="color:#48b685">&#34;{{ $url }}&#34;</span>
</span></span><span style="display:flex;"><span>        },
</span></span><span style="display:flex;"><span>        {{<span style="color:#5bc4bf">-</span> <span style="color:#06b6ef">end</span> <span style="color:#5bc4bf">-</span>}}
</span></span><span style="display:flex;"><span>    ];
</span></span><span style="display:flex;"><span>    <span style="color:#06b6ef">$</span>(<span style="color:#48b685">&#34;#search&#34;</span>).<span style="color:#06b6ef">autocomplete</span>({
</span></span><span style="display:flex;"><span>		<span style="color:#06b6ef">minLength</span><span style="color:#5bc4bf">:</span> <span style="color:#f99b15">0</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#06b6ef">source</span><span style="color:#5bc4bf">:</span> <span style="color:#06b6ef">projects</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#06b6ef">focus</span><span style="color:#5bc4bf">:</span> <span style="color:#815ba4">function</span>( <span style="color:#06b6ef">event</span>, <span style="color:#06b6ef">ui</span> ) {
</span></span><span style="display:flex;"><span>			<span style="color:#06b6ef">$</span>(<span style="color:#48b685">&#34;#search&#34;</span>).<span style="color:#06b6ef">val</span>( <span style="color:#06b6ef">ui</span>.<span style="color:#06b6ef">item</span>.<span style="color:#06b6ef">label</span> );
</span></span><span style="display:flex;"><span>			<span style="color:#815ba4">return</span> <span style="color:#815ba4">false</span>;
</span></span><span style="display:flex;"><span>        },
</span></span><span style="display:flex;"><span>        <span style="color:#06b6ef">select</span><span style="color:#5bc4bf">:</span> <span style="color:#815ba4">function</span>( <span style="color:#06b6ef">event</span>, <span style="color:#06b6ef">ui</span> ) {
</span></span><span style="display:flex;"><span>			<span style="color:#06b6ef">$</span>(<span style="color:#48b685">&#34;#search&#34;</span>).<span style="color:#06b6ef">val</span>( <span style="color:#06b6ef">ui</span>.<span style="color:#06b6ef">item</span>.<span style="color:#06b6ef">label</span> );
</span></span><span style="display:flex;"><span>			<span style="color:#06b6ef">$</span>(<span style="color:#48b685">&#34;#replyer&#34;</span>).<span style="color:#06b6ef">val</span>( <span style="color:#06b6ef">ui</span>.<span style="color:#06b6ef">item</span>.<span style="color:#06b6ef">value</span> );
</span></span><span style="display:flex;"><span>			<span style="color:#815ba4">return</span> <span style="color:#815ba4">false</span>;
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>    })
</span></span><span style="display:flex;"><span>    .<span style="color:#06b6ef">data</span>(<span style="color:#48b685">&#39;ui-autocomplete&#39;</span>).<span style="color:#06b6ef">_renderItem</span> <span style="color:#5bc4bf">=</span> <span style="color:#815ba4">function</span>(<span style="color:#06b6ef">ul</span>, <span style="color:#06b6ef">item</span>) {
</span></span><span style="display:flex;"><span>        <span style="color:#815ba4">return</span> <span style="color:#06b6ef">$</span>(<span style="color:#48b685">&#39;&lt;li&gt;&#39;</span>)
</span></span><span style="display:flex;"><span>        .<span style="color:#06b6ef">append</span>(<span style="color:#48b685">&#39;&lt;a href=&#34;&#39;</span> <span style="color:#5bc4bf">+</span> <span style="color:#06b6ef">item</span>.<span style="color:#06b6ef">url</span> <span style="color:#5bc4bf">+</span> <span style="color:#48b685">&#39;&#34; alt=&#34;&#39;</span><span style="color:#5bc4bf">+</span> <span style="color:#06b6ef">item</span>.<span style="color:#06b6ef">label</span> <span style="color:#5bc4bf">+</span> <span style="color:#48b685">&#39;&#34;&gt;&#39;</span> <span style="color:#5bc4bf">+</span> <span style="color:#06b6ef">item</span>.<span style="color:#06b6ef">value</span> <span style="color:#5bc4bf">+</span> <span style="color:#48b685">&#39;&lt;/a&gt;&#39;</span> )
</span></span><span style="display:flex;"><span>        .<span style="color:#06b6ef">appendTo</span>(<span style="color:#06b6ef">ul</span>);
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>});
</span></span><span style="display:flex;"><span>&lt;/<span style="color:#5bc4bf">script</span>&gt;
</span></span><span style="display:flex;"><span>&lt;/<span style="color:#5bc4bf">div</span>&gt;
</span></span></code></pre></div><hr>
<h2 id="demo">Demo</h2>
<p>Voilà ! <br>
In few minutes, an &ldquo;internal search engine&rdquo; is born on your static website Hugo.</p>
<p>See, the search holder on the menu navigation, at top right side ;)</p>
<hr>
<h2 id="documentation">Documentation</h2>
<ul>
<li><a href="https://gohugo.io/tools/search/" title="Link to the official site Hugo: Tools &gt; Search">Hugo Documentation: Tools &gt; Search</a>
</li>
<li><a href="https://gohugo.io/functions/range/" title="Link to the official site Hugo: Functions &gt; Range">Hugo Documentation: Functions &gt; Range</a>
</li>
<li><a href="https://gohugo.io/functions/i18n/" title="Link to the official site Hugo: Functions &gt; I18n">Hugo Documentation: Functions &gt; I18n</a>
</li>
</ul>
<h3 id="others-documentations">Others Documentations</h3>
<ul>
<li>Inspired by <a href="https://themes.gohugo.io/theme/dot-hugo-documentation-theme/" rel="external">Dot theme</a> - <em>(cf : <a href="https://github.com/themefisher/dot/blob/master/layouts/partials/banner.html" rel="external">banner.html</a>)</em></li>
<li>JQuery UI <code>autocomplete()</code> method: <a href="https://jqueryui.com/autocomplete" rel="external">https://jqueryui.com/autocomplete</a></li>
<li>More explains about JQueryUI <code>Autocomplete()</code> method: See the <a href="https://www.tutorialspoint.com/jqueryui/jqueryui_autocomplete.htm" rel="external">documentation</a></li>
<li>Another method to <a href="https://en.jeffprod.com/blog/2018/build-your-own-hugo-website-search-engine/" rel="external">build internal search engine</a>, with VueJS + Axios librairies</li>
</ul>
<hr>
]]></content><summary>Howto add an 'internal search engine' into the static website, made with Hugo, and JQueryUI</summary><published>2019-12-06T01:21:00+01:00</published><updated>2026-10-02T15:49:57+02:00</updated></entry><entry><id>tag:doc.huc.fr.eu.org,2019-11-29:/en/web/hugo/hugo-shortcodes</id><link href="https://it-log.fr.eu.org/en/web/hugo/hugo-shortcodes/" rel="alternate" type="text/html"/><title>Hugo: Shortcodes</title><author><name>Stéphane HUC</name></author><category term="Hugo" scheme="https://it-log.fr.eu.org/en/tags/hugo/"/><category term="Shortcode" scheme="https://it-log.fr.eu.org/en/tags/shortcode/"/><content type="html"><![CDATA[<h2 id="description">Description</h2>
<p>As you see on Hugo&rsquo;s page shortcodes,
<quote>a shortcode is a simple snippet inside a content file that Hugo will render using a predefined template.</quote></p>
<p>Some times, you need to include/add raw <abbr title="HyperText Markup Language">HTML</abbr>

into the <abbr title="MarkDown">MD</abbr>
 content. The shortcode add correctly this.
By this way, you can include too MD syntax.</p>
<p>Put your shortcodes into  <code>layout/shortcodes/</code>.</p>
<hr>
<p>Actually, I use the official third package  providen by the team OpenBSD:</p>
<ul>
<li>OpenBSD : <strong>6.6</strong></li>
<li>Version d&rsquo;Hugo : <strong>0.53</strong> : <code>Hugo Static Site Generator v0.53 openbsd/amd64 BuildDate: unknown</code></li>
</ul>
<h2 id="documentation">Documentation</h2>
<ul>
<li>official : <a href="https://gohugo.io/content-management/shortcodes/" title="Link to the official site Hugo: Content management &gt; Shortcodes">Hugo Documentation: Content management &gt; Shortcodes</a>
</li>
</ul>
<h2 id="my-shortcodes">My shortcodes</h2>
<h3 id="abbr">abbr</h3>
<ul>
<li>To manage element HTML <code>abbr</code></li>
</ul>
<p><div class="is-right">
    <p class="is-italic is-white-50">RAW source of the shortcode: <a class="raw-src" href="abbr.html" title="">abbr</a></p>
</div>

The shortcode:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-html" data-lang="html"><span style="display:flex;"><span>&lt;<span style="color:#5bc4bf">abbr</span> <span style="color:#ef6155">{{</span> <span style="color:#ef6155">.</span><span style="color:#06b6ef">Get</span> <span style="color:#06b6ef">1</span> <span style="color:#ef6155">|</span> <span style="color:#06b6ef">printf</span> <span style="color:#ef6155">`</span><span style="color:#06b6ef">title</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">%q`</span> <span style="color:#ef6155">|</span> <span style="color:#06b6ef">safeHTMLAttr</span> <span style="color:#ef6155">}}</span>&gt;{{ .Get 0 | safeHTML }}&lt;/<span style="color:#5bc4bf">abbr</span>&gt;
</span></span></code></pre></div><hr>
<p>Call the shortcode as:
<div class="info-code">
    <p>Code:&nbsp;<em>shortcode</em></p>
</div>
<div class="code"><pre tabindex="0"><code class="language-shortcode" data-lang="shortcode">
{{&lt; abbr accronym &#34;Meaning of Acronym&#34; &gt;}}
</code></pre></div>
</p>
<hr>
<p>Example: <abbr title="HyperText Markup Language">HTML</abbr>
 is written as:
<div class="info-code">
    <p>Code:&nbsp;<em>shortcode</em></p>
</div>
<div class="code"><pre tabindex="0"><code class="language-shortcode" data-lang="shortcode">
{{&lt; abbr HTML &#34;HyperText Markup Language&#34; &gt;}}
</code></pre></div>
</p>
<h3 id="anchor">anchor</h3>
<p>To manage the anchor into one page is a little complex:</p>
<div class="is-right">
    <p class="is-italic is-white-50">RAW source of the shortcode: <a class="raw-src" href="anchor.html" title="">anchor</a></p>
</div>

<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-html" data-lang="html"><span style="display:flex;"><span>{{ $txt := .Get 0 | safeHTML }}{{ $name := .Get 1 | lower | safeHTML }}{{ $anchor := anchorize $name }}
</span></span><span style="display:flex;"><span>&lt;<span style="color:#5bc4bf">a</span> <span style="color:#06b6ef">href</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;{{ printf &#34;</span><span style="color:#ef6155">%</span><span style="color:#06b6ef">s</span><span style="color:#ef6155">&#34;</span> <span style="color:#ef6155">.</span><span style="color:#06b6ef">Page</span><span style="color:#ef6155">.</span><span style="color:#06b6ef">RelPermalink</span> <span style="color:#ef6155">}}#{{</span> <span style="color:#ef6155">$</span><span style="color:#06b6ef">anchor</span> <span style="color:#ef6155">}}&#34;</span> <span style="color:#06b6ef">title</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;{{ i18n &#34;</span><span style="color:#06b6ef">shortcodeAnchorTitle</span><span style="color:#ef6155">&#34;</span> <span style="color:#ef6155">}}{{</span> <span style="color:#ef6155">$</span><span style="color:#06b6ef">name</span> <span style="color:#ef6155">}}&#34;</span>&gt;{{ $txt }}&lt;/<span style="color:#5bc4bf">a</span>&gt;
</span></span></code></pre></div><hr>
<p>Call the shortcode as: <br>
<div class="info-code">
    <p>Code:&nbsp;<em>shortcode</em></p>
</div>
<div class="code"><pre tabindex="0"><code class="language-shortcode" data-lang="shortcode">
{{&lt; anchor &#34;Texte&#34; &#34;Cible&#34; &gt;}}
</code></pre></div>
</p>
<hr>
<p>Example: this <a href="/en/web/hugo/hugo-shortcodes/#description" title="Go to the anchor: description">link</a>
 refers to the section
Description; his writing is: <br>
<div class="info-code">
    <p>Code:&nbsp;<em>shortcode</em></p>
</div>
<div class="code"><pre tabindex="0"><code class="language-shortcode" data-lang="shortcode">
{{&lt; anchor &#34;link&#34; &#34;description&#34; &gt;}}
</code></pre></div>
</p>
<h3 id="blockquote">blockquote</h3>
<p>Writing a basic element HTML <code>blockquote</code>, you need only:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-html" data-lang="html"><span style="display:flex;"><span>&lt;<span style="color:#5bc4bf">blockquote</span>&gt;{{ $file := .Get 0 | readFile | htmlUnescape | safeHTML }}{{ $file }}&lt;/<span style="color:#5bc4bf">blockquote</span>&gt;
</span></span></code></pre></div><p>But, my shorcode is more evolved, because as you see, this site is multilanguage. Also:</p>
<div class="is-right">
    <p class="is-italic is-white-50">RAW source of the shortcode: <a class="raw-src" href="blockquote.html" title="">blockquote</a></p>
</div>

<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-html" data-lang="html"><span style="display:flex;"><span>&lt;<span style="color:#5bc4bf">div</span> <span style="color:#06b6ef">class</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;info-quote&#34;</span>&gt;&lt;<span style="color:#5bc4bf">p</span> <span style="color:#06b6ef">class</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;text-white-50&#34;</span>&gt;{{ T &#34;quoteTitle&#34; }}{{ if .Get 1 }} &lt;<span style="color:#5bc4bf">em</span>&gt;{{ .Get 1 | safeHTML }}&lt;/<span style="color:#5bc4bf">em</span>&gt;{{ end }}&lt;/<span style="color:#5bc4bf">p</span>&gt;&lt;/<span style="color:#5bc4bf">div</span>&gt;&lt;<span style="color:#5bc4bf">div</span> <span style="color:#06b6ef">class</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;quote&#34;</span>&gt;&lt;<span style="color:#5bc4bf">blockquote</span>&gt;{{ $name := .Get 0 }}{{ $file := urlize (print &#34;/content/inc/&#34; $name) | readFile | htmlUnescape | safeHTML }}{{ $file }}&lt;/<span style="color:#5bc4bf">blockquote</span>&gt;&lt;/<span style="color:#5bc4bf">div</span>&gt;
</span></span></code></pre></div><hr>
<p>Call the shortcode as: <br>
<div class="info-code">
    <p>Code:&nbsp;<em>shortcode</em></p>
</div>
<div class="code"><pre tabindex="0"><code class="language-shortcode" data-lang="shortcode">
{{&lt; blockquote &#34;blockquote-filename&#34; lang &gt;}}
</code></pre></div>
</p>
<ul>
<li><code>blockquote-filename</code>: the file to call where the blockquote is written</li>
<li><code>lang</code>: the lang, i.e <code>en</code>, <code>fr</code>, etc. - <em>To avoid specifying an code, use <code>&quot;&quot;</code></em>.</li>
</ul>
<hr>
<p>Example:
<div class="info-quote">
    <p>Quotes: <em>fr</em></p>
</div>
<div class="quote">
    <figure>
        <blockquote lang="fr"></blockquote>
    </figure>
</div>
</p>
<h3 id="code">Code</h3>
<p>To include some example code, I created into <code>content/</code> folder a directory named <code>inc</code>. <em>You can named as you want; it&rsquo;s up to you!</em></p>
<p>And after, create needed files, and call them as <code>/content/folder_name/file_name</code>.</p>
<p>By default:
<div class="info-code">
    <p>Code:&nbsp;<em>html</em></p>
</div>
<div class="code"><div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-html" data-lang="html"><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>{{ $file := .Get 0 | readFile }}{{ $lang := .Get 1 }}{{ $opt := &#34;&#34; }}&lt;<span style="color:#5bc4bf">div</span> <span style="color:#06b6ef">class</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;code&#34;</span>&gt;{{ highlight $file $lang $opt }}&lt;/<span style="color:#5bc4bf">div</span>&gt;
</span></span></code></pre></div></div>
</p>
<p>For my needs, my shortcode is &ldquo;a little more&rdquo; advanced:</p>
<div class="is-right">
    <p class="is-italic is-white-50">RAW source of the shortcode: <a class="raw-src" href="code.html" title="">code</a></p>
</div>

<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-html" data-lang="html"><span style="display:flex;"><span>{{ $name := .Get 0 }}{{ $file := urlize (print &#34;/content/inc/&#34; $name) | readFile }}{{ $lang := .Get 1 }}{{ $opt := &#34;&#34; }}
</span></span><span style="display:flex;"><span>&lt;<span style="color:#5bc4bf">div</span> <span style="color:#06b6ef">class</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;info-code&#34;</span>&gt;&lt;<span style="color:#5bc4bf">p</span> <span style="color:#06b6ef">class</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;text-white-50&#34;</span>&gt;{{ i18n &#34;codeTitle&#34; }}&amp;nbsp;&lt;<span style="color:#5bc4bf">em</span>&gt;{{ $lang }}&lt;/<span style="color:#5bc4bf">em</span>&gt;&lt;/<span style="color:#5bc4bf">p</span>&gt;&lt;/<span style="color:#5bc4bf">div</span>&gt;&lt;<span style="color:#5bc4bf">div</span> <span style="color:#06b6ef">class</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;code&#34;</span>&gt;{{ highlight $file $lang $opt }}&lt;/<span style="color:#5bc4bf">div</span>&gt;
</span></span></code></pre></div><hr>
<p>Call the shortcode as:
<div class="info-code">
    <p>Code:&nbsp;<em>shortcode</em></p>
</div>
<div class="code"><pre tabindex="0"><code class="language-shortcode" data-lang="shortcode">
{{&lt; code &#34;code-filename&#34; language &gt;}}
</code></pre></div>
</p>
<ul>
<li><code>code-filename</code>: the file to call</li>
<li><code>language</code>: the language, i.e <code>sh</code>, <code>PHP</code>, <code>python</code>, etc. <em>To avoid specifying an code, use <code>&quot;&quot;</code></em>.</li>
</ul>
<hr>
<p>Example: Look, you have one just above it!</p>
<h3 id="color">Color</h3>
<p>A very small shortcode to add color on text.</p>
<p>Into my <abbr title="Cascaded Style Sheet">CSS</abbr>
, I had some definitions with named colors.</p>
<p><div class="is-right">
    <p class="is-italic is-white-50">RAW source of the shortcode: <a class="raw-src" href="color.html" title="">color</a></p>
</div>

The shortcode:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-html" data-lang="html"><span style="display:flex;"><span>&lt;<span style="color:#5bc4bf">span</span> <span style="color:#ef6155">{{</span> <span style="color:#ef6155">.</span><span style="color:#06b6ef">Get</span> <span style="color:#06b6ef">0</span> <span style="color:#ef6155">|</span> <span style="color:#06b6ef">printf</span> <span style="color:#ef6155">`</span><span style="color:#06b6ef">class</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">%q`</span> <span style="color:#ef6155">|</span> <span style="color:#06b6ef">safeHTMLAttr</span> <span style="color:#ef6155">}}</span>&gt;{{ .Inner }}&lt;/<span style="color:#5bc4bf">span</span>&gt;
</span></span></code></pre></div><hr>
<p>Call the shortcode as:
<div class="info-code">
    <p>Code:&nbsp;<em>shortcode</em></p>
</div>
<div class="code"><pre tabindex="0"><code class="language-shortcode" data-lang="shortcode">
{{&lt; color &#34;css-name&#34; &gt;}}text{{&lt; /color &gt;}}
</code></pre></div>
</p>
<ul>
<li><code>css-name</code>: the CSS name</li>
<li><code>text</code>: the text</li>
</ul>
<hr>
<p>Example: This is <span class="dark-green">green text</span>
, or <span class="orange">orange</span>
, and this other is <span class="red">red</span>
, etc…</p>
<h3 id="file">File</h3>
<p>To include a file content example, I fork the shortcode <a href="/en/web/hugo/hugo-shortcodes/#code" title="Go to the anchor: code">code</a>
. It&rsquo;s quasy-same code.</p>
<p>But, for my need, I wrote an advanced as:
<div class="is-right">
    <p class="is-italic is-white-50">RAW source of the shortcode: <a class="raw-src" href="file.html" title="">file</a></p>
</div>
</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-html" data-lang="html"><span style="display:flex;"><span>{{ $name := .Get 0 | safeHTML }}{{ $file := urlize (print &#34;/content/inc/&#34; $name) | readFile }}{{ $lang := .Get 1}}{{ $filename := .Get 2 }}{{  $opt := &#34;linenos=table&#34; }}
</span></span><span style="display:flex;"><span>&lt;<span style="color:#5bc4bf">div</span> <span style="color:#06b6ef">class</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;info-file&#34;</span>&gt;&lt;<span style="color:#5bc4bf">p</span> <span style="color:#06b6ef">class</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;text-white-50&#34;</span>&gt;{{ i18n &#34;fileTitle&#34; }}&lt;<span style="color:#5bc4bf">em</span>&gt;{{ $filename }}&lt;/<span style="color:#5bc4bf">em</span>&gt;&lt;/<span style="color:#5bc4bf">p</span>&gt;&lt;/<span style="color:#5bc4bf">div</span>&gt;&lt;<span style="color:#5bc4bf">div</span> <span style="color:#06b6ef">class</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;code&#34;</span>&gt;{{ highlight $file $lang $opt }}&lt;/<span style="color:#5bc4bf">div</span>&gt;
</span></span></code></pre></div><hr>
<p>Call the shortcode as: <br>
<div class="info-code">
    <p>Code:&nbsp;<em>shortcode</em></p>
</div>
<div class="code"><pre tabindex="0"><code class="language-shortcode" data-lang="shortcode">
{{&lt; file &#34;example-file&#34; language &#34;filename&#34; &gt;}}
</code></pre></div>
</p>
<ul>
<li><code>/example-file</code>: file to call</li>
<li><code>language</code>: language, i.e. <code>sh</code>, <code>PHP</code>, <code>python</code>, etc… <em>To avoid specifying an code, use <code>&quot;&quot;</code></em>.</li>
<li><code>filename</code>: filename to display ;)</li>
</ul>
<hr>
<p>Example: Look above to see!</p>
<h3 id="image">Image</h3>
<p>Yes, I known Markdown had his code to include basically image.</p>
<hr>
<h4 id="pngjpgtiff">PNG/JPG/Tiff</h4>
<p>This shortcode exists to specify width of image, and link to the raw image.</p>
<div class="is-right">
    <p class="is-italic is-white-50">RAW source of the shortcode: <a class="raw-src" href="img.html" title="">img</a></p>
</div>

<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-html" data-lang="html"><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1</span><span>{{/* runner for assets/image */}}
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2</span><span>{{- $src := resources.Get (printf &#34;%s%s&#34; &#34;/images/&#34; (.Get &#34;s&#34;)) -}}{{- $alt := .Get &#34;a&#34; | safeHTML -}}{{- $width := printf &#34;%s&#34; (.Get &#34;w&#34;) -}}
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3</span><span>{{- $img := $src -}}
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4</span><span>{{- with $width -}}{{- $img = $src.Resize (printf &#34;%sx&#34; $width) -}}{{- end -}}
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5</span><span>{{- with $img -}}
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6</span><span>&lt;<span style="color:#5bc4bf">figure</span>&gt;
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7</span><span>    &lt;<span style="color:#5bc4bf">a</span> <span style="color:#06b6ef">href</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;{{ $src.RelPermalink }}&#34;</span> <span style="color:#06b6ef">title</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;{{ $alt }}&#34;</span>&gt;
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8</span><span>    &lt;<span style="color:#5bc4bf">picture</span>&gt;
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9</span><span>        <span style="color:#776e71">&lt;!-- &lt;source srcset=&#34;/img/.avif&#34; type=&#34;image/avif&#34;&gt; --&gt;</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10</span><span>        {{- with .Resize (printf &#34;%dx%d webp&#34; .Width .Height) }}
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11</span><span>        &lt;<span style="color:#5bc4bf">source</span> <span style="color:#06b6ef">srcset</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;{{ .RelPermalink }}&#34;</span> <span style="color:#06b6ef">type</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;image/webp&#34;</span>&gt;
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12</span><span>        {{ end }}
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13</span><span>        &lt;<span style="color:#5bc4bf">img</span> <span style="color:#06b6ef">alt</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;{{ $alt }}&#34;</span> <span style="color:#06b6ef">loading</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;lazy&#34;</span> <span style="color:#06b6ef">src</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;{{ .RelPermalink }}&#34;</span> <span style="color:#06b6ef">type</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;{{ .MediaType }}&#34;</span> <span style="color:#06b6ef">height</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;{{ .Height }}&#34;</span> <span style="color:#06b6ef">width</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;{{ .Width }}&#34;</span>&gt;
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">14</span><span>    &lt;/<span style="color:#5bc4bf">picture</span>&gt;
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">15</span><span>    &lt;/<span style="color:#5bc4bf">a</span>&gt;
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">16</span><span>    &lt;<span style="color:#5bc4bf">figcaption</span>&gt;{{ $alt }}&lt;/<span style="color:#5bc4bf">figcaption</span>&gt;
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">17</span><span>&lt;/<span style="color:#5bc4bf">figure</span>&gt;
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">18</span><span>{{- end -}}
</span></span></code></pre></div><hr>
<p>Call the shortcode as:
<div class="info-code">
    <p>Code:&nbsp;<em>shortcode</em></p>
</div>
<div class="code"><pre tabindex="0"><code class="language-shortcode" data-lang="shortcode">
{{&lt; img a=&#34;alt&#34; s=&#34;src&#34; w=&#34;width&#34; &gt;}}
</code></pre></div>
</p>
<p>The named parameters are:</p>
<ul>
<li><code>a</code>: equivalent for attribute <code>alt</code></li>
<li><code>s</code>: equivalent for attribute <code>src</code></li>
<li><code>w</code>: equivalent for attribute <code>width</code></li>
</ul>
<hr>
<p>Example:</p>
<figure>
    <a href="/images/Logo_full_192px.png" title="My Logo">
    <picture>
        
        <source srcset="/images/Logo_full_192px_hu_e0b3cd9c38226f1f.webp" type="image/webp">
        
        <img alt="My Logo" height="124" loading="lazy" src="/images/Logo_full_192px_hu_bfb19336d47c760c.png" type="image/png" width="124">
    </picture>
    </a>
    <figcaption>My Logo</figcaption>
</figure>
<p>This image is my logo, named &ldquo;My Logo&rdquo;, with an original width at 192
<abbr title="pixels">px</abbr>
, resized at 124 px, into
<abbr title="Portable Network Graphics">PNG</abbr>
 format.</p>
<h4 id="svg">SVG</h4>
<p>About the SVG picture, I manage them like as:</p>
<div class="is-right">
    <p class="is-italic is-white-50">RAW source of the shortcode: <a class="raw-src" href="figure-svg.html" title="">figure-svg</a></p>
</div>

<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-html" data-lang="html"><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1</span><span>{{/* runner for assets/svg */}}
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2</span><span>{{- $class := .Get &#34;class&#34; -}}{{- $src := resources.Get (printf &#34;%s%s&#34; &#34;/svg/&#34; (.Get &#34;src&#34;)) -}}{{ $title := .Get &#34;title&#34; }}
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3</span><span>{{ with $src }}
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4</span><span>&lt;<span style="color:#5bc4bf">figure</span> <span style="color:#06b6ef">class</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;{{ if $class }}{{ $class }}{{ end }}&#34;</span>&gt;
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5</span><span>    &lt;<span style="color:#5bc4bf">a</span> <span style="color:#06b6ef">href</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;{{ .RelPermalink }}&#34;</span> <span style="color:#06b6ef">title</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;{{ $title }}&#34;</span>&gt;
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6</span><span>    {{ .Content | safeHTML }}
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7</span><span>    &lt;/<span style="color:#5bc4bf">a</span>&gt;
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8</span><span>    {{ if $title }}&lt;<span style="color:#5bc4bf">figcaption</span> <span style="color:#06b6ef">aria-hidden</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;true&#34;</span> <span style="color:#06b6ef">class</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;hidden&#34;</span> <span style="color:#06b6ef">hidden</span>&gt;{{ $title }}&lt;/<span style="color:#5bc4bf">figcaption</span>&gt;{{ end }}
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9</span><span>&lt;/<span style="color:#5bc4bf">figure</span>&gt;
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10</span><span>{{ end }}
</span></span></code></pre></div><hr>
<p>Call the shortcode:
<div class="info-code">
    <p>Code:&nbsp;<em>shortcode</em></p>
</div>
<div class="code"><pre tabindex="0"><code class="language-shortcode" data-lang="shortcode">
{{&lt; figure-svg class=&#34;class-name&#34; src=&#34;image.svg&#34; title=&#34;the title&#34; &gt;}}
</code></pre></div>
</p>
<hr>
<p>Example :


<figure class="pure-img">
    <a href="/svg/Logo_final.svg" title="My Logo">
    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
   id="svg3108"
   version="1.1"
   inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
   sodipodi:docname="Logo_final.svg"
   width="64"
   height="64"
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
   xmlns="http://www.w3.org/2000/svg"
   xmlns:svg="http://www.w3.org/2000/svg"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:cc="http://creativecommons.org/ns#"
   xmlns:dc="http://purl.org/dc/elements/1.1/">
  <sodipodi:namedview
     id="namedview30"
     pagecolor="#ffffff"
     bordercolor="#000000"
     borderopacity="0.25"
     inkscape:showpageshadow="2"
     inkscape:pageopacity="0.0"
     inkscape:pagecheckerboard="0"
     inkscape:deskcolor="#d1d1d1"
     showgrid="false"
     inkscape:zoom="3.0570583"
     inkscape:cx="30.421402"
     inkscape:cy="58.225909"
     inkscape:window-width="1920"
     inkscape:window-height="1031"
     inkscape:window-x="0"
     inkscape:window-y="25"
     inkscape:window-maximized="1"
     inkscape:current-layer="layer1" />
  <title
     id="title853">Logo Emblème Stéphane HUC</title>
  <defs
     id="defs3110" />
  <metadata
     id="metadata3113">
    <rdf:RDF>
      <cc:Work
         rdf:about="">
        <dc:title>Logo Emblème Stéphane HUC</dc:title>
      </cc:Work>
    </rdf:RDF>
  </metadata>
  <g
     inkscape:label="Calque 1"
     inkscape:groupmode="layer"
     id="layer1"
     transform="translate(0.00367771,-0.00353708)">
    <g
       transform="matrix(0.02413578,0,0,0.02334611,-0.05137015,-0.00127009)"
       style="display:inline"
       id="g4250"
       inkscape:export-filename="/home/zou/Documents/Projets_sur_images/Stephane-huc.net/Logo_original.png"
       inkscape:export-xdpi="300"
       inkscape:export-ydpi="300">
      <g
         id="g3893"
         style="display:inline;fill:#4d4d4d"
         transform="matrix(0.06444778,0,0,0.06450434,865.42675,1541.6735)">
        <path
           inkscape:connector-curvature="0"
           sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccsssc"
           id="path2385-6-1-2"
           d="m 23774.425,-13094.781 c -407.725,2.746 -749.397,40.026 -972.445,28.012 -4599.937,59.837 -9024.559,3454.6637 -10088.773,4551.7613 -1032.632,1431.3562 -1902.759,4120.4375 -3414.3254,6116.3965 C 7040.4567,1715.9353 4369.202,5321.9681 986.55523,8407.9766 -4389.5849,12448.032 -8602.0428,12402.637 -12768.187,12194.347 c -252.964,17.663 -415.823,306.287 -501.736,508.146 274.498,360.798 549.024,468.121 823.522,457.374 l 2991.3542,-94.976 c 3456.504,-296.023 6332.5254,-987.067 8247.1738,-2331.958 -1416.3389,1353.905 -8714.7449,3661.386 -9866.29,3397.271 -283.94,94.386 -9.166,418.668 -14.627,627.634 443.726,168.12 891.426,312.023 1382.8762,197.395 3340.0325,-1065.466 6699.0628,-1956.661 9899.08747,-4312.462 L -6089.161,17754.195 c -98.5516,407.272 -100.4203,652.783 -4.8749,736.614 l 355.0258,94.104 c 229.6322,33.856 492.0244,-81.828 782.3016,-323.448 L 2012.6316,9672.4329 C 2658.8638,14594.17 7818.5983,15351.227 11738.861,12799.22 l 127.65,-1168.167 C 7834.5326,14914.263 2650.1202,12909.869 3004.5788,9106.5143 L 5888.675,5359.9752 C 6887.5627,4011.8679 8068.294,2775.8085 9455.3418,1667.2698 h 8.8646 C 10742.256,691.78922 12091.181,-25.504325 13349.115,-1036.7181 c 1520.143,-1055.4722 4302.351,-1145.0617 5286.398,-2327.1449 1177.704,-1664.9321 2145.664,-3667.8767 2974.957,-5435.546 1020.536,-2296.596 2897.375,-2743.981 6123.216,-278.3644 -109.42,-1287.3486 -1023.595,-2502.5416 -1546.427,-3009.9256 -1021.529,-829.12 -1603.165,-855.9 -2412.834,-1007.082 z m -34848.588,27224.985 c 1.234,-0.42 2.29,-0.913 3.545,-1.315 h -9.309 c 1.838,0.451 3.895,0.882 5.764,1.315 z m 36292.522,-26286.618 c 206.696,0 374.086,206.617 374.086,461.752 0,255.135 -167.39,462.19 -374.086,462.19 -206.695,0 -374.529,-207.055 -374.529,-462.19 0,-255.135 167.834,-461.752 374.529,-461.752 z"
           style="display:inline;fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:#990000;stroke-width:21.9289px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
        <g
           transform="matrix(14.180303,0.29145382,-0.29145382,14.180303,39070.285,-17179.84)"
           id="g3323-6-2"
           style="fill:#999999;fill-opacity:1;stroke:#990000;stroke-opacity:1">
          <path
             inkscape:connector-curvature="0"
             style="display:inline;fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:#990000;stroke-width:1.55587px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
             d="m -1938.7905,1344.2995 15.3955,-1.283 7.0562,-10.2637 -3.8488,-8.9807 3.8488,-8.9808 c 26.901,-8.9122 44.2829,-1.9591 55.8088,14.754 -0.1027,10.6945 -8.3234,15.9763 -18.6029,19.8859 -6.7082,-0.016 -14.6164,2.0346 -17.3412,-4.8053 v 0 c -16.1045,-1.7244 -11.7855,6.9433 -12.7007,9.072 3.8166,4.6142 10.3634,8.3754 23.8137,9.979 -7.6533,3.5761 -11.6619,14.8063 -24.7209,7.0307 -5.8792,-4.5108 -13.9229,-4.3322 -16.5562,-15.8758 -13.5829,-3.7285 -14.572,5.856 -14.515,11.1131 -0.352,5.6108 2.6918,10.0899 5.8967,14.5151 18.6918,9.7777 28.4118,11.6393 36.968,12.4739 11.2194,0.8225 24.7349,-15.9588 37.6483,-28.123 11.7646,0.4051 16.4086,-11.0571 23.1335,-19.0511 6.177,-27.5232 -20.7198,-44.6944 -30.8445,-51.7098 -19.6553,-8.2012 -39.8866,-7.5233 -50.5759,-3.6288 -9.4566,6.292 -15.9533,13.324 -23.1334,20.1851 -3.7507,11.7151 -4.9786,23.178 3.27,33.6932 z"
             id="path3190-2-0-4"
             sodipodi:nodetypes="cccccccccccccccccccccc" />
          <path
             inkscape:connector-curvature="0"
             style="display:inline;fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:#990000;stroke-width:1.55587px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
             d="m -1766.1814,1226.0731 15.3955,-1.283 7.0562,-10.2637 -3.8488,-8.9807 3.8488,-8.9808 c 26.901,-8.9122 44.2829,-1.9591 55.8088,14.754 -0.1027,10.6945 -8.3234,15.9763 -18.6029,19.8859 -6.7082,-0.016 -14.6164,2.0346 -17.3412,-4.8053 v 0 c -16.1045,-1.7244 -11.7855,6.9433 -12.7007,9.072 3.8166,4.6142 10.3634,8.3754 23.8137,9.979 -7.6533,3.5761 -11.6619,14.8063 -24.7209,7.0307 -5.8792,-4.5108 -13.9229,-4.3322 -16.5562,-15.8758 -13.5829,-3.7285 -14.572,5.856 -14.515,11.1131 -0.352,5.6108 2.6918,10.0899 5.8967,14.5151 18.6918,9.7777 28.4118,11.6393 36.968,12.4739 11.2194,0.8225 24.7349,-15.9588 37.6483,-28.123 11.7646,0.4051 16.4086,-11.0571 23.1335,-19.0511 6.177,-27.5232 -20.7198,-44.6944 -30.8445,-51.7098 -19.6553,-8.2012 -39.8866,-7.5233 -50.5759,-3.6288 -9.4566,6.292 -15.9533,13.324 -23.1334,20.1851 -3.7507,11.7151 -4.9786,23.178 3.27,33.6932 z"
             id="path3190-0-8-2-9"
             sodipodi:nodetypes="cccccccccccccccccccccc" />
        </g>
        <g
           id="g3607-7"
           style="fill:#999999;fill-opacity:1;stroke:#990000;stroke-opacity:1"
           transform="matrix(10.256384,0,0,10.256384,27740.017,-9419.2772)">
          <path
             inkscape:connector-curvature="0"
             sodipodi:nodetypes="ccccccccccccsccccccccccccccccccccccc"
             id="path2853-1-2-3"
             d="m -3334.7852,-1248.287 c 51.9752,263.91148 364.552,597.09982 649.489,723.58561 186.8994,102.74774 436.9783,80.34473 628.0009,153.0754 176.754,59.99791 336.6065,134.19234 455.7429,223.77162 v 0 c 95.6093,72.55212 166.8615,174.225196 178.8187,313.54167 -21.1645,58.71298 -67.8029,109.93553 -112.5308,161.38138 -108.9474,42.30362 -193.7664,43.94287 -273.1033,40.38991 v 0 c -289.559,-41.98012 -408.6126,-122.75609 -537.4682,-237.26062 -138.9061,-154.600767 -217.6672,-263.90172 -373.9094,-355.18101 -178.3851,-112.57744 -359.9805,-46.07103 -531.5855,-101.08503 -15.4761,-3.45827 -6.3053,-53.81809 36.6639,-43.63616 64.7876,15.3519 174.3223,-1.04389 174.3223,-1.04389 l -79.9048,-49.14253 v 0 l 36.7606,-7.32283 v 0 l 89.4837,49.88512 v 0 l 180.7667,8.58049 v 0 l -95.19,-169.30622 v 0 0 l -44.2175,-2.75208 v 0 l 1.9939,-18.56317 31.584,1.9656 c -91.0217,-150.25746 -222.4184,-249.74105 -339.9897,-366.61111 l 33.2464,-1.66844 v 0 l 33.3433,34.64483 v 0 c -87.3435,-107.03536 -156.5494,-220.39644 -185.2023,-347.90084 5.407,-25.6798 28.4059,-33.5554 42.8852,-9.3477 z"
             style="display:inline;fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:#990000;stroke-width:3.14969px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
          <path
             inkscape:connector-curvature="0"
             sodipodi:nodetypes="ccccccccccccsccccccccccccccccccccccc"
             id="path2853-1-8-2-7"
             d="m -3964.5819,579.94648 c 232.1778,142.02444 696.5351,140.75989 988.106,18.70266 205.9526,-66.5673 362.6995,-264.70185 549.2022,-354.76022 167.1463,-88.31108 333.1245,-154.57977 482.3054,-180.583195 v 0 c 120.2135,-20.415854 245.1813,-3.15744 357.0123,83.134705 28.9606,55.52615 34.6919,124.56859 41.9136,192.36665 -44.1007,108.51739 -101.6932,171.65364 -159.3434,227.23914 v 0 c -231.9712,183.0827 -374.5522,215.03066 -548.9965,231.13768 -211.2129,-3.89591 -347.056,-20.86741 -523.2284,31.10727 -207.3545,53.63654 -283.8394,231.78243 -443.7115,319.72853 -13.3008,8.9568 -44.3697,-32.1019 -7.0087,-56.5744 56.3312,-36.899 120.0937,-128.17265 120.0937,-128.17265 l -91.9262,24.90186 v 0 l 20.0462,-31.87375 v 0 l 99.1198,-31.39936 v 0 l 131.7153,-126.31933 v 0 l -191.8305,-45.89202 v 0 0 l -32.7044,30.45368 v 0 l -12.4139,-14.12077 23.3603,-21.75279 c -174.7833,-35.94516 -339.8259,-7.73356 -508.2045,-1.49116 l 21.8121,-25.44723 v 0 l 48.8674,-0.74684 v 0 c -140.1103,-9.1506 -272.3455,-35.87817 -386.9742,-101.90494 -15.3362,-21.4712 -5.2426,-43.65993 22.7879,-37.73352 z"
             style="display:inline;fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:#990000;stroke-width:3.1754px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
        </g>
      </g>
      <path
         style="display:inline;fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:#990000;stroke-width:1.41389px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
         d="m 2394.9999,689.06305 c -26.2769,0.17713 -48.2969,2.58185 -62.6719,1.8069 -296.4557,3.85975 -581.6127,222.84081 -650.199,293.60838 -66.5508,92.32867 -122.6286,265.78617 -220.0457,394.53417 -145.5504,265.4061 -317.7069,498.0109 -535.71096,697.0718 -346.48036,260.6012 -617.96395,257.673 -886.462661,244.2374 -16.303005,1.1393 -26.798914,19.7568 -32.3357924,32.7776 17.6907774,23.2731 35.3833394,30.1959 53.0741824,29.5026 l 192.786151,-6.1263 c 222.76402,-19.0948 408.11723,-63.6701 531.51204,-150.4215 -91.27986,87.3328 -561.64597,236.1754 -635.8605,219.1388 -18.29929,6.0883 -0.59073,27.0059 -0.94272,40.4851 28.59717,10.8445 57.45048,20.1269 89.12335,12.7328 215.25769,-68.7271 431.73976,-126.2131 637.97425,-278.1725 L 470.3581,2678.956 c -6.35143,26.2709 -6.47187,42.1074 -0.31418,47.5149 l 22.88063,6.0701 c 14.79923,2.1838 31.70983,-5.2783 50.41755,-20.8638 l 449.15854,-554.0299 c 41.64826,317.4734 374.18176,366.3069 626.83396,201.6913 l 8.2267,-75.3518 c -259.852,211.7813 -593.9759,82.4892 -571.1318,-162.8437 l 185.8736,-241.6681 c 64.3761,-86.9587 140.4715,-166.6899 229.8637,-238.1955 h 0.5713 c 82.3675,-62.9228 169.3027,-109.1913 250.3737,-174.419 97.9699,-68.0825 277.277,-73.8615 340.6967,-150.111 75.9004,-107.3953 138.2833,-236.5939 191.7294,-350.61629 65.7712,-148.14043 186.7294,-176.9987 394.6277,-17.95572 -7.0519,-83.03958 -65.9685,-161.4248 -99.6638,-194.15328 -65.8353,-53.48184 -103.3205,-55.20926 -155.5019,-64.96116 z M 149.08576,2445.1929 c 0.0795,-0.027 0.14754,-0.059 0.22845,-0.085 h -0.59993 c 0.11845,0.029 0.25098,0.057 0.37148,0.085 z M 2488.0583,749.5918 c 13.3211,0 24.109,13.32769 24.109,29.78501 0,16.45732 -10.7879,29.81326 -24.109,29.81326 -13.321,0 -24.1375,-13.35594 -24.1375,-29.81326 0,-16.45732 10.8165,-29.78501 24.1375,-29.78501 z"
         id="path2385-6-1-2-3"
         sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccsssc"
         inkscape:connector-curvature="0" />
      <g
         style="display:inline;fill:#999999;fill-opacity:1;stroke:#990000;stroke-opacity:1"
         id="g3323-6-2-4"
         transform="matrix(0.91388911,0.01880004,-0.01878355,0.91469117,3380.7843,425.559)">
        <path
           sodipodi:nodetypes="cccccccccccccccccccccc"
           id="path3190-2-0-4-2"
           d="m -1938.7905,1344.2995 15.3955,-1.283 7.0562,-10.2637 -3.8488,-8.9807 3.8488,-8.9808 c 26.901,-8.9122 44.2829,-1.9591 55.8088,14.754 -0.1027,10.6945 -8.3234,15.9763 -18.6029,19.8859 -6.7082,-0.016 -14.6164,2.0346 -17.3412,-4.8053 v 0 c -16.1045,-1.7244 -11.7855,6.9433 -12.7007,9.072 3.8166,4.6142 10.3634,8.3754 23.8137,9.979 -7.6533,3.5761 -11.6619,14.8063 -24.7209,7.0307 -5.8792,-4.5108 -13.9229,-4.3322 -16.5562,-15.8758 -13.5829,-3.7285 -14.572,5.856 -14.515,11.1131 -0.352,5.6108 2.6918,10.0899 5.8967,14.5151 18.6918,9.7777 28.4118,11.6393 36.968,12.4739 11.2194,0.8225 24.7349,-15.9588 37.6483,-28.123 11.7646,0.4051 16.4086,-11.0571 23.1335,-19.0511 6.177,-27.5232 -20.7198,-44.6944 -30.8445,-51.7098 -19.6553,-8.2012 -39.8866,-7.5233 -50.5759,-3.6288 -9.4566,6.292 -15.9533,13.324 -23.1334,20.1851 -3.7507,11.7151 -4.9786,23.178 3.27,33.6932 z"
           style="display:inline;fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:#990000;stroke-width:1.55587px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
           inkscape:connector-curvature="0" />
        <path
           sodipodi:nodetypes="cccccccccccccccccccccc"
           id="path3190-0-8-2-9-5"
           d="m -1766.1814,1226.0731 15.3955,-1.283 7.0562,-10.2637 -3.8488,-8.9807 3.8488,-8.9808 c 26.901,-8.9122 44.2829,-1.9591 55.8088,14.754 -0.1027,10.6945 -8.3234,15.9763 -18.6029,19.8859 -6.7082,-0.016 -14.6164,2.0346 -17.3412,-4.8053 v 0 c -16.1045,-1.7244 -11.7855,6.9433 -12.7007,9.072 3.8166,4.6142 10.3634,8.3754 23.8137,9.979 -7.6533,3.5761 -11.6619,14.8063 -24.7209,7.0307 -5.8792,-4.5108 -13.9229,-4.3322 -16.5562,-15.8758 -13.5829,-3.7285 -14.572,5.856 -14.515,11.1131 -0.352,5.6108 2.6918,10.0899 5.8967,14.5151 18.6918,9.7777 28.4118,11.6393 36.968,12.4739 11.2194,0.8225 24.7349,-15.9588 37.6483,-28.123 11.7646,0.4051 16.4086,-11.0571 23.1335,-19.0511 6.177,-27.5232 -20.7198,-44.6944 -30.8445,-51.7098 -19.6553,-8.2012 -39.8866,-7.5233 -50.5759,-3.6288 -9.4566,6.292 -15.9533,13.324 -23.1334,20.1851 -3.7507,11.7151 -4.9786,23.178 3.27,33.6932 z"
           style="display:inline;fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:#990000;stroke-width:1.55587px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
           inkscape:connector-curvature="0" />
      </g>
      <path
         inkscape:connector-curvature="0"
         sodipodi:nodetypes="ccccccccccccsccccccccccccccccccccccc"
         id="path2853-1-2-3-9"
         d="m 1071.448,12.565243 c -15.3369,146.179207 73.828,372.947977 180.7482,487.459287 67.2709,85.4026 180.411,116.49879 253.836,186.99056 68.9967,61.4286 128.5121,127.35333 167.9088,194.3213 v 0 c 31.5208,54.088 48.125,119.16171 33.2259,193.68211 -17.7944,26.9261 -45.6999,45.6007 -72.7982,64.718 -53.9976,3.3831 -91.5092,-10.2639 -125.8605,-25.6749 v 0 C 1387.3321,1042.7224 1346.6981,980.34835 1306.6359,898.75209 1267.9574,794.5785 1249.1568,724.2529 1193.6994,650.05735 1131.5923,560.99655 1042.1677,564.5514 974.71289,506.59578 c -6.30086,-4.44472 5.01449,-29.07557 22.42474,-16.43307 26.25067,19.06189 76.75837,29.25724 76.75837,29.25724 l -28.0058,-39.22499 v 0 l 17.2141,2.47464 v 0 l 32.108,41.24885 v 0 l 78.1981,35.36579 v 0 l -17.3399,-104.35052 v 0 0 l -19.0336,-8.99068 v 0 l 3.5616,-9.31623 13.5954,6.42185 c -18.2636,-93.72824 -61.6156,-167.94463 -96.3766,-248.84241 l 14.8517,4.81539 v 0 l 9.6413,23.72335 v 0 c -22.9001,-70.61432 -36.914,-141.418612 -31.0608,-212.64819 6.091,-12.4349571 17.3374,-12.6004057 20.1985,2.468443 z"
         style="display:inline;fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:#990000;stroke-width:1.58535px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
      <path
         inkscape:connector-curvature="0"
         sodipodi:nodetypes="ccccccccccccsccccccccccccccccccccccc"
         id="path2853-1-8-2-7-4"
         d="m 346.99101,968.42886 c 122.89969,124.43284 416.59744,198.91414 621.36814,171.56464 141.34235,-7.3092 273.67225,-103.0072 406.66535,-127.8264 120.466,-26.88812 236.4935,-40.49317 335.1448,-32.21014 v 0 c 79.4054,7.00369 155.4909,37.80454 211.6845,108.67004 8.9823,38.6312 1.014,81.759 -5.8034,124.3677 -46.0902,59.1793 -93.0891,88.4349 -138.8571,113.0661 v 0 c -177.3468,74.3073 -272.8249,70.7271 -385.7821,52.3012 -132.8378,-36.6106 -215.845,-68.9985 -335.9157,-65.7821 -140.05758,-0.8213 -218.30441,95.6669 -334.11166,123.5108 -9.91006,3.3189 -22.65364,-26.8114 5.06783,-35.7143 41.79723,-13.4237 97.41938,-58.8771 97.41938,-58.8771 l -62.28015,0.3225 v 0 l 18.02055,-16.2327 v 0 l 67.9175,-3.1279 v 0 l 104.45336,-55.8609 v 0 l -113.53757,-59.1376 v 0 0 l -25.78236,13.3133 v 0 l -5.4754,-10.6425 18.41603,-9.5096 c -104.43314,-50.2954 -213.48017,-59.7993 -320.94769,-83.2716 l 18.0578,-12.0185 v 0 l 31.01082,7.463 v 0 c -87.0171,-28.2993 -166.10614,-66.0655 -227.47003,-124.99811 -6.08836,-15.60868 4.01601,-27.53473 20.7371,-19.36983 z"
         style="display:inline;fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:#990000;stroke-width:2.04192px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
      <g
         id="g2901"
         style="display:inline;fill:#990000;fill-opacity:1;stroke:#800000"
         inkscape:export-filename="/home/zou/Documents/Projets_sur_images/Stephane-huc.net/Logo_gris_999999_390px.png"
         inkscape:export-xdpi="90"
         inkscape:export-ydpi="90"
         transform="matrix(0.66100118,0,0,0.66158128,2645.7866,917.11829)">
        <path
           style="display:inline;fill:#990000;fill-opacity:1;fill-rule:evenodd;stroke:#800000;stroke-width:2.13807px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
           d="m -386.64618,-358.3625 c -39.7533,0.2677 -73.0664,3.9025 -94.8137,2.7311 -448.495,5.8342 -879.89672,336.83061 -983.65782,443.797906 -100.6819,139.557584 -185.5195,401.743684 -332.8976,596.350184 -220.197,401.16931 -480.645,752.75841 -810.4539,1053.64501 -524.175,393.9064 -934.8907,389.4804 -1341.0908,369.1721 -24.6641,1.7221 -40.5428,29.863 -48.9194,49.5443 26.7636,35.1779 53.53,45.6419 80.2936,44.5941 l 291.6578,-9.2602 c 337.01,-28.8623 617.4228,-96.2393 804.1015,-227.3665 -138.0934,132.0061 -849.6898,356.9861 -961.9657,331.2348 -27.6843,9.2027 -0.8937,40.8202 -1.4262,61.1945 43.2634,16.3917 86.9143,30.4223 134.8308,19.246 325.654,-103.8832 653.1603,-190.7749 965.1635,-420.4661 l -612.5292,693.3656 c -9.6088,39.7091 -9.791,63.6465 -0.4753,71.8201 l 34.6151,9.1751 c 22.3892,3.301 47.9725,-7.9782 76.2746,-31.5362 l 679.5124,-837.4328 c 63.0078,479.8706 566.0832,553.6838 948.3098,304.8625 l 12.4459,-113.8966 c -393.1189,320.1138 -898.6004,124.6849 -864.0406,-246.1431 l 281.2001,-365.2885 c 97.3918,-131.4408 212.5134,-251.9569 347.7509,-360.0397 h 0.8643 c 124.6102,-95.1096 256.1307,-165.0459 378.7796,-263.6395 148.2143,-102.9088 419.48022,-111.6438 515.42512,-226.8972 114.8264,-162.3313 209.2027,-357.6189 290.059,-529.967097 99.5025,-223.918703 282.4948,-267.538803 597.0151,-27.1406 -10.6685,-125.5168 -99.8008,-243.998403 -150.777,-293.468503 -99.5993,-80.8394 -156.309,-83.4505 -235.2519,-98.1907 z M -3784.3922,2296.0803 c 0.1203,-0.041 0.2232,-0.089 0.3456,-0.1282 h -0.9076 c 0.1792,0.044 0.3797,0.086 0.562,0.1282 z M -245.86228,-266.8715 c 20.1529,0 36.4735,20.1452 36.4735,45.0209 0,24.8757 -16.3206,45.0637 -36.4735,45.0637 -20.1528,0 -36.5167,-20.188 -36.5167,-45.0637 0,-24.8757 16.3639,-45.0209 36.5167,-45.0209 z"
           id="path2385-6-1"
           sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccsssc"
           inkscape:connector-curvature="0" />
        <g
           style="fill:#990000;fill-opacity:1;stroke:#800000"
           id="g3323-6"
           transform="matrix(1.3825831,0.02841682,-0.02841682,1.3825831,1104.704,-756.6568)">
          <path
             sodipodi:nodetypes="cccccccccccccccccccccc"
             id="path3190-2-0"
             d="m -1938.7905,1344.2995 15.3955,-1.283 7.0562,-10.2637 -3.8488,-8.9807 3.8488,-8.9808 c 26.901,-8.9122 44.2829,-1.9591 55.8088,14.754 -0.1027,10.6945 -8.3234,15.9763 -18.6029,19.8859 -6.7082,-0.016 -14.6164,2.0346 -17.3412,-4.8053 v 0 c -16.1045,-1.7244 -11.7855,6.9433 -12.7007,9.072 3.8166,4.6142 10.3634,8.3754 23.8137,9.979 -7.6533,3.5761 -11.6619,14.8063 -24.7209,7.0307 -5.8792,-4.5108 -13.9229,-4.3322 -16.5562,-15.8758 -13.5829,-3.7285 -14.572,5.856 -14.515,11.1131 -0.352,5.6108 2.6918,10.0899 5.8967,14.5151 18.6918,9.7777 28.4118,11.6393 36.968,12.4739 11.2194,0.8225 24.7349,-15.9588 37.6483,-28.123 11.7646,0.4051 16.4086,-11.0571 23.1335,-19.0511 6.177,-27.5232 -20.7198,-44.6944 -30.8445,-51.7098 -19.6553,-8.2012 -39.8866,-7.5233 -50.5759,-3.6288 -9.4566,6.292 -15.9533,13.324 -23.1334,20.1851 -3.7507,11.7151 -4.9786,23.178 3.27,33.6932 z"
             style="display:inline;fill:#990000;fill-opacity:1;fill-rule:evenodd;stroke:#800000;stroke-width:1.55587px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
             inkscape:connector-curvature="0" />
          <path
             sodipodi:nodetypes="cccccccccccccccccccccc"
             id="path3190-0-8-2"
             d="m -1766.1814,1226.0731 15.3955,-1.283 7.0562,-10.2637 -3.8488,-8.9807 3.8488,-8.9808 c 26.901,-8.9122 44.2829,-1.9591 55.8088,14.754 -0.1027,10.6945 -8.3234,15.9763 -18.6029,19.8859 -6.7082,-0.016 -14.6164,2.0346 -17.3412,-4.8053 v 0 c -16.1045,-1.7244 -11.7855,6.9433 -12.7007,9.072 3.8166,4.6142 10.3634,8.3754 23.8137,9.979 -7.6533,3.5761 -11.6619,14.8063 -24.7209,7.0307 -5.8792,-4.5108 -13.9229,-4.3322 -16.5562,-15.8758 -13.5829,-3.7285 -14.572,5.856 -14.515,11.1131 -0.352,5.6108 2.6918,10.0899 5.8967,14.5151 18.6918,9.7777 28.4118,11.6393 36.968,12.4739 11.2194,0.8225 24.7349,-15.9588 37.6483,-28.123 11.7646,0.4051 16.4086,-11.0571 23.1335,-19.0511 6.177,-27.5232 -20.7198,-44.6944 -30.8445,-51.7098 -19.6553,-8.2012 -39.8866,-7.5233 -50.5759,-3.6288 -9.4566,6.292 -15.9533,13.324 -23.1334,20.1851 -3.7507,11.7151 -4.9786,23.178 3.27,33.6932 z"
             style="display:inline;fill:#990000;fill-opacity:1;fill-rule:evenodd;stroke:#800000;stroke-width:1.55587px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
             inkscape:connector-curvature="0" />
        </g>
        <g
           style="fill:#990000;fill-opacity:1;stroke:#800000"
           id="g3607">
          <path
             style="display:inline;fill:#990000;fill-opacity:1;fill-rule:evenodd;stroke:#800000;stroke-width:3.14969px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
             d="m -3334.7852,-1248.287 c 51.9752,263.91148 364.552,597.09982 649.489,723.58561 186.8994,102.74774 436.9783,80.34473 628.0009,153.0754 176.754,59.99791 336.6065,134.19234 455.7429,223.77162 v 0 c 95.6093,72.55212 166.8615,174.225196 178.8187,313.54167 -21.1645,58.71298 -67.8029,109.93553 -112.5308,161.38138 -108.9474,42.30362 -193.7664,43.94287 -273.1033,40.38991 v 0 c -289.559,-41.98012 -408.6126,-122.75609 -537.4682,-237.26062 -138.9061,-154.600767 -217.6672,-263.90172 -373.9094,-355.18101 -178.3851,-112.57744 -359.9805,-46.07103 -531.5855,-101.08503 -15.4761,-3.45827 -6.3053,-53.81809 36.6639,-43.63616 64.7876,15.3519 174.3223,-1.04389 174.3223,-1.04389 l -79.9048,-49.14253 v 0 l 36.7606,-7.32283 v 0 l 89.4837,49.88512 v 0 l 180.7667,8.58049 v 0 l -95.19,-169.30622 v 0 0 l -44.2175,-2.75208 v 0 l 1.9939,-18.56317 31.584,1.9656 c -91.0217,-150.25746 -222.4184,-249.74105 -339.9897,-366.61111 l 33.2464,-1.66844 v 0 l 33.3433,34.64483 v 0 c -87.3435,-107.03536 -156.5494,-220.39644 -185.2023,-347.90084 5.407,-25.6798 28.4059,-33.5554 42.8852,-9.3477 z"
             id="path2853-1-2"
             sodipodi:nodetypes="ccccccccccccsccccccccccccccccccccccc"
             inkscape:connector-curvature="0" />
          <path
             style="display:inline;fill:#990000;fill-opacity:1;fill-rule:evenodd;stroke:#800000;stroke-width:3.1754px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
             d="m -3964.5819,579.94648 c 232.1778,142.02444 696.5351,140.75989 988.106,18.70266 205.9526,-66.5673 362.6995,-264.70185 549.2022,-354.76022 167.1463,-88.31108 333.1245,-154.57977 482.3054,-180.583195 v 0 c 120.2135,-20.415854 245.1813,-3.15744 357.0123,83.134705 28.9606,55.52615 34.6919,124.56859 41.9136,192.36665 -44.1007,108.51739 -101.6932,171.65364 -159.3434,227.23914 v 0 c -231.9712,183.0827 -374.5522,215.03066 -548.9965,231.13768 -211.2129,-3.89591 -347.056,-20.86741 -523.2284,31.10727 -207.3545,53.63654 -283.8394,231.78243 -443.7115,319.72853 -13.3008,8.9568 -44.3697,-32.1019 -7.0087,-56.5744 56.3312,-36.899 120.0937,-128.17265 120.0937,-128.17265 l -91.9262,24.90186 v 0 l 20.0462,-31.87375 v 0 l 99.1198,-31.39936 v 0 l 131.7153,-126.31933 v 0 l -191.8305,-45.89202 v 0 0 l -32.7044,30.45368 v 0 l -12.4139,-14.12077 23.3603,-21.75279 c -174.7833,-35.94516 -339.8259,-7.73356 -508.2045,-1.49116 l 21.8121,-25.44723 v 0 l 48.8674,-0.74684 v 0 c -140.1103,-9.1506 -272.3455,-35.87817 -386.9742,-101.90494 -15.3362,-21.4712 -5.2426,-43.65993 22.7879,-37.73352 z"
             id="path2853-1-8-2"
             sodipodi:nodetypes="ccccccccccccsccccccccccccccccccccccc"
             inkscape:connector-curvature="0" />
        </g>
      </g>
    </g>
  </g>
</svg>

    </a>
    <figcaption aria-hidden="true" class="hidden" hidden>My Logo</figcaption>
</figure>

</p>
<hr>
<h3 id="kbd">kbd</h3>
<p>This shorcode manage HTML item <code>kbd</code>.</p>
<p><div class="is-right">
    <p class="is-italic is-white-50">RAW source of the shortcode: <a class="raw-src" href="kbd.html" title="">kbd</a></p>
</div>

The shortcode is:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-html" data-lang="html"><span style="display:flex;"><span>{{ $k := .Get 0 | safeHTML }}&lt;<span style="color:#5bc4bf">kbd</span>&gt;{{ $k }}&lt;/<span style="color:#5bc4bf">kbd</span>&gt;
</span></span></code></pre></div><hr>
<p>Call shortcode as:
<div class="info-code">
    <p>Code:&nbsp;<em>shortcode</em></p>
</div>
<div class="code"><pre tabindex="0"><code class="language-shortcode" data-lang="shortcode">
{{&lt; kbd key &gt;}}
</code></pre></div>
</p>
<ul>
<li><code>key</code>: the key name into the keyboard!</li>
</ul>
<hr>
<p>Example : this is for the  <kbd>s</kbd>
 key!</p>
<h3 id="inside-link">Inside link</h3>
<p>This shortcode, now, had two versions. I started with
<a href="/en/web/hugo/hugo-shortcodes/#inside-v1" title="Go to the anchor: inside-v1">the first</a>
, and one day, I wonder how add
anchor too; <a href="/en/web/hugo/hugo-shortcodes/#inside-v2" title="Go to the anchor: inside-v2">the v2</a>
 was born!</p>
<h4 id="inside-v1">Inside v1</h4>
<p>To manage inside link between pages of this site, I wrote this shortcode:</p>
<div class="is-right">
    <p class="is-italic is-white-50">RAW source of the shortcode: <a class="raw-src" href="inside.html" title="">inside</a></p>
</div>

<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-html" data-lang="html"><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">1</span><span>{{ $link := .Get 0 }}{{ $link := replace $link &#34;:&#34; &#34;/&#34; }}{{ $url := (print ( relLangURL $link ) &#34;/&#34;) }}
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">2</span><span>{{ if .Get 1 }}{{ $txt := .Get 1 }}
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">3</span><span>&lt;<span style="color:#5bc4bf">a</span> <span style="color:#06b6ef">class</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;inside&#34;</span> <span style="color:#06b6ef">href</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;{{ $url }}&#34;</span> <span style="color:#06b6ef">title</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;{{ i18n &#34;</span><span style="color:#06b6ef">lnkInsideTitle</span><span style="color:#ef6155">&#34;</span> <span style="color:#ef6155">}}{{</span> <span style="color:#06b6ef">with</span> <span style="color:#ef6155">.</span><span style="color:#06b6ef">Site</span><span style="color:#ef6155">.</span><span style="color:#06b6ef">GetPage</span> <span style="color:#ef6155">$</span><span style="color:#06b6ef">link</span> <span style="color:#ef6155">}}{{</span> <span style="color:#ef6155">.</span><span style="color:#06b6ef">Title</span> <span style="color:#ef6155">}}{{</span> <span style="color:#06b6ef">end</span> <span style="color:#ef6155">}}&#34;</span>&gt;{{ $txt }}&lt;/<span style="color:#5bc4bf">a</span>&gt;
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">4</span><span>{{ else }}
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">5</span><span>{{ with .Site.GetPage $link }}{{ $title := .Title }}&lt;<span style="color:#5bc4bf">a</span> <span style="color:#06b6ef">class</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;inside&#34;</span> <span style="color:#06b6ef">href</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;{{ $url }}&#34;</span> <span style="color:#06b6ef">title</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;{{ i18n &#34;</span><span style="color:#06b6ef">lnkInsideTitle</span><span style="color:#ef6155">&#34;</span> <span style="color:#ef6155">}}{{</span> <span style="color:#ef6155">$</span><span style="color:#06b6ef">title</span> <span style="color:#ef6155">}}&#34;</span>&gt;{{ $title }}&lt;/<span style="color:#5bc4bf">a</span>&gt;{{ end }}
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">6</span><span>{{ end }}
</span></span></code></pre></div><p>And, I created into my CSS, a named <code>inside</code> definition.</p>
<hr>
<p>Call the shortcode as:
<div class="info-code">
    <p>Code:&nbsp;<em>shortcode</em></p>
</div>
<div class="code"><pre tabindex="0"><code class="language-shortcode" data-lang="shortcode">
{{&lt; inside &#34;section:subsection:pagename&#34; &#34;Title&#34; &gt;}}
</code></pre></div>
</p>
<ul>
<li>sections and pages names are separated by the symbol <code>:</code></li>
<li>the title can be avoid. In this case, it will display the title of called page.</li>
</ul>
<hr>
<p>Examples:</p>
<ul>
<li>In this exemple, I call the page 

<a class="inside" href="/en/web/hugo/hugo-deploy/" title="Internal link to the article: 'Hugo: Deploy SFTP'">Hugo: Deploy SFTP</a>

; this is its title that is displayed.</li>
<li>With this other example, I override the title when I call the same page 
<a class="inside" href="/en/web/hugo/hugo-deploy/" title="Internal link to the article: 'Hugo: Deploy SFTP'">Static deploy with Hugo</a>
</li>
</ul>
<h4 id="inside-v2">Inside v2</h4>
<p>This version is subtle different:</p>
<div class="is-right">
    <p class="is-italic is-white-50">RAW source of the shortcode: <a class="raw-src" href="inside2.html" title="">inside2</a></p>
</div>

<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-html" data-lang="html"><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">1</span><span>{{ $link := .Get &#34;l&#34; }}{{ $link := replace $link &#34;:&#34; &#34;/&#34; }}{{ $url := (print ( relLangURL $link ) &#34;/&#34;) }}{{ $anchor := .Get &#34;a&#34; }}
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">2</span><span>{{ if .Get &#34;t&#34; }}{{ $txt := .Get &#34;t&#34; }}&lt;<span style="color:#5bc4bf">a</span> <span style="color:#06b6ef">class</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;inside&#34;</span> <span style="color:#06b6ef">href</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;{{ $url }}{{ if $anchor }}#{{ $anchor }}{{ end }}&#34;</span> <span style="color:#06b6ef">title</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;{{ i18n &#34;</span><span style="color:#06b6ef">lnkInsideTitle</span><span style="color:#ef6155">&#34;</span> <span style="color:#ef6155">}}&#39;{{</span> <span style="color:#06b6ef">with</span> <span style="color:#ef6155">.</span><span style="color:#06b6ef">Site</span><span style="color:#ef6155">.</span><span style="color:#06b6ef">GetPage</span> <span style="color:#ef6155">$</span><span style="color:#06b6ef">link</span> <span style="color:#ef6155">}}{{</span> <span style="color:#ef6155">.</span><span style="color:#06b6ef">Title</span> <span style="color:#ef6155">}}{{</span> <span style="color:#06b6ef">end</span> <span style="color:#ef6155">}}&#39;&#34;</span>&gt;{{ $txt }}&lt;/<span style="color:#5bc4bf">a</span>&gt;
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">3</span><span>{{ else }}
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">4</span><span>{{ with .Site.GetPage $link }}{{ $title := .Title }}&lt;<span style="color:#5bc4bf">a</span> <span style="color:#06b6ef">class</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;inside&#34;</span> <span style="color:#06b6ef">href</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;{{ $url }}{{ if $anchor }}#{{ $anchor }}{{ end }}&#34;</span> <span style="color:#06b6ef">title</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;{{ i18n &#34;</span><span style="color:#06b6ef">lnkInsideTitle</span><span style="color:#ef6155">&#34;</span> <span style="color:#ef6155">}}&#39;{{</span> <span style="color:#ef6155">$</span><span style="color:#06b6ef">title</span> <span style="color:#ef6155">}}&#39;&#34;</span>&gt;{{ $title }}&lt;/<span style="color:#5bc4bf">a</span>&gt;{{ end }}
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">5</span><span>{{ end }}
</span></span></code></pre></div><hr>
<p>Call the shortcode as:
<div class="info-code">
    <p>Code:&nbsp;<em>shortcode</em></p>
</div>
<div class="code"><pre tabindex="0"><code class="language-shortcode" data-lang="shortcode">
{{&lt; inside2 l=&#34;section:subsection:pagename&#34; t=&#34;title&#34; a=&#34;anchor-name&#34; &gt;}}
</code></pre></div>
</p>
<p>The named parameters are:</p>
<ul>
<li><code>a</code>: target an anchor into called page. <em>this anchor need to exists into the page</em>. May be omitted!</li>
<li><code>l</code>: name of internal link; sections and pages names are separated by the symbol <code>:</code>.</li>
<li><code>t</code>: the title. May be omitted. In this case, it will display tye title of the called page.</li>
</ul>
<hr>
<p>Example:</p>
<ul>
<li>Here, I call the page <a class="inside" href="/en/web/hugo/hugo-deploy/#rsync" title="Internal link to the article: 'Hugo: Deploy SFTP'">Hugo: Deploy SFTP</a>. Her title is displayed, but it links to the section named <strong>rsync</strong>, targeted anchor.</li>
<li>And this example, I override the title as <a class="inside" href="/en/web/hugo/hugo-deploy/" title="Internal link to the article: 'Hugo: Deploy SFTP'">Static deploy with Hugo</a>
 but I not wrote anchor param.</li>
</ul>
<h3 id="note">Note</h3>
<p>The blocs of alert or note are HTML blocs to display a text, with an identifiant, translated segun the used lang.</p>
<p>The possible values of this identifiant may be:</p>
<ul>
<li><code>danger</code>: to display an alert &lsquo;danger&rsquo;, with a red background.</li>
<li><code>info</code>: to display an informational note, with a blue background.</li>
<li><code>success</code>: to display a success message, with a green background.</li>
<li><code>tip</code>: to display a tip note, with a yellow background.</li>
<li><code>warning</code>: to display a warning message/alert, with an amber background.</li>
</ul>
<p>And, all thoses background colors <code>alert-$id</code> are written on CSS file.</p>
<p>The shortcode:</p>
<div class="is-right">
    <p class="is-italic is-white-50">RAW source of the shortcode: <a class="raw-src" href="note.html" title="">note</a></p>
</div>

<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-html" data-lang="html"><span style="display:flex;"><span>{{ $class := .Get 0 }}{{ $wrd := T (printf &#34;alert-%s&#34; $class) }}
</span></span><span style="display:flex;"><span>&lt;<span style="color:#5bc4bf">div</span> <span style="color:#06b6ef">class</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;info-tab {{ $class }}-icon&#34;</span>&gt;{{ $wrd }}&lt;/<span style="color:#5bc4bf">div</span>&gt;&lt;<span style="color:#5bc4bf">div</span> <span style="color:#06b6ef">class</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;alert alert-{{ $class }}&#34;</span> <span style="color:#06b6ef">role</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;alert&#34;</span>&gt;{{ .Inner | .Page.RenderString }}&lt;/<span style="color:#5bc4bf">div</span>&gt;
</span></span></code></pre></div><hr>
<p>The shortcode is:
<div class="info-code">
    <p>Code:&nbsp;<em>shortcode</em></p>
</div>
<div class="code"><pre tabindex="0"><code class="language-shortcode" data-lang="shortcode">
{{&lt; note id &gt;}}
This is your message
{{&lt; /note &gt;}}
</code></pre></div>
</p>
<hr>
<p>Examples:</p>
<p>
<div class="tab-info i-danger">Danger</div><div class="alert alert-danger" role="alert"><strong>ATTENTION</strong>: this message display a risk or danger for you!</div>

<em>This example includes MD code to strong the word &lsquo;ATTENTION&rsquo;.</em></p>

<div class="tab-info i-info">Info</div><div class="alert alert-info" role="alert">A little <strong>information</strong>. Keep this in your mind! :D</div>


<div class="tab-info i-success">Success</div><div class="alert alert-success" role="alert">You succeeded the test! Be happy.</div>


<div class="tab-info i-tip">Tip</div><div class="alert alert-tip" role="alert">This is a tip. Yeah, man, interesting!</div>


<div class="tab-info i-warning">Warning</div><div class="alert alert-warning" role="alert">Please, be careful at the message: it seems a malfunction exists. See more attentive!</div>

<h3 id="tag">Tag</h3>
<p>This shortcode not exists to manage Hugo tags, but to manage tag into MD file.</p>
<p>Into CSS, I defined attribute <code>.tag::after</code> to display <code>(tag)</code>.</p>
<p><div class="is-right">
    <p class="is-italic is-white-50">RAW source of the shortcode: <a class="raw-src" href="tag.html" title="">tag</a></p>
</div>

The shortcode:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-html" data-lang="html"><span style="display:flex;"><span>{{ $txt := .Get 0 }}{{ $href := &#34;/&#34; | relLangURL}}{{ $href := (printf &#34;%s%s%s&#34; $href &#34;/tags/&#34; $txt) | urlize }}&lt;<span style="color:#5bc4bf">a</span> <span style="color:#06b6ef">class</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;tag&#34;</span> <span style="color:#06b6ef">href</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;{{ $href }}&#34;</span>&gt;{{ $txt }}&lt;/<span style="color:#5bc4bf">a</span>&gt;
</span></span></code></pre></div><hr>
<p>Call the shortcode as:
<div class="info-code">
    <p>Code:&nbsp;<em>shortcode</em></p>
</div>
<div class="code"><pre tabindex="0"><code class="language-shortcode" data-lang="shortcode">
{{&lt; tag tag-name &gt;}}
</code></pre></div>
</p>
<hr>
<p>Example: <br>
This word <a class="tag" href="/en/tags/hugo">Hugo</a>
 is a link to the tag page with &ldquo;Hugo&rdquo; name.</p>
<h2 id="others-shortcodes">Others shortcodes</h2>
<h3 id="gohugo">GoHugo</h3>
<p>Just to link to official documentation Hugo, I wrote this shortcode:
<div class="info-code">
    <p>Code:&nbsp;<em>shortcode</em></p>
</div>
<div class="code"><pre tabindex="0"><code class="language-shortcode" data-lang="shortcode">
{{&lt; gohugo n=&#34;pagename&#34; s=&#34;section&#34; a=&#34;anchor-name&#34; &gt;}}
</code></pre></div>
</p>
<hr>
<p><div class="is-right">
    <p class="is-italic is-white-50">RAW source of the shortcode: <a class="raw-src" href="gohugo.html" title="">gohugo</a></p>
</div>

The shortcode:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-html" data-lang="html"><span style="display:flex;"><span>{{ $section := .Get &#34;s&#34; }}{{ $name := .Get &#34;n&#34; }}{{ $anchor := .Get &#34;a&#34; }}&lt;<span style="color:#5bc4bf">a</span> <span style="color:#06b6ef">href</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;https://gohugo.io/{{ $section }}/{{ $name }}/{{ if $anchor }}#{{ $anchor}}{{ end }}&#34;</span> <span style="color:#06b6ef">title</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;{{ i18n &#34;</span><span style="color:#06b6ef">shortcodeGoHugoTitle</span><span style="color:#ef6155">&#34;</span> <span style="color:#ef6155">}}{{</span> <span style="color:#06b6ef">humanize</span> <span style="color:#ef6155">$</span><span style="color:#06b6ef">section</span> <span style="color:#ef6155">}}</span> <span style="color:#ef6155">&amp;</span><span style="color:#06b6ef">gt</span><span style="color:#ef6155">;</span> <span style="color:#ef6155">{{</span> <span style="color:#06b6ef">humanize</span> <span style="color:#ef6155">$</span><span style="color:#06b6ef">name</span> <span style="color:#ef6155">}}&#34;</span>&gt;{{ i18n &#34;shortcodeGoHugoDocTitle&#34; }}{{ humanize $section }} &amp;gt; {{ humanize $name }}&lt;/<span style="color:#5bc4bf">a</span>&gt;
</span></span></code></pre></div><hr>
<p>Example: Link to <a href="https://gohugo.io/content-management/shortcodes/" title="Link to the official site Hugo: Content management &gt; Shortcodes">Hugo Documentation: Content management &gt; Shortcodes</a>

Hugo page with:
<div class="info-code">
    <p>Code:&nbsp;<em>shortcode</em></p>
</div>
<div class="code"><pre tabindex="0"><code class="language-shortcode" data-lang="shortcode">
{{&lt; gohugo n=&#34;shortcodes&#34; s=&#34;content-management&#34; &gt;}}
</code></pre></div>
</p>
<h3 id="manpage">Manpage</h3>
<p>As I use many times links to official manpage OpenBSD, I wrote this shortcode:
<div class="info-code">
    <p>Code:&nbsp;<em>shortcode</em></p>
</div>
<div class="code"><pre tabindex="0"><code class="language-shortcode" data-lang="shortcode">
{{&lt; man title digit &gt;}}
</code></pre></div>
</p>
<ul>
<li>If a <code>digit</code> is written, the shortcode build the URL as <code>title.digit</code>
and the text as <code>txt(digit)</code>.</li>
</ul>
<hr>
<p><div class="is-right">
    <p class="is-italic is-white-50">RAW source of the shortcode: <a class="raw-src" href="man.html" title="">man</a></p>
</div>

The shortcode:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-html" data-lang="html"><span style="display:flex;"><span>{{ $txt := .Get 0 }}{{ $nb := .Get 1}}
</span></span><span style="display:flex;"><span>&lt;<span style="color:#5bc4bf">a</span> <span style="color:#06b6ef">class</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;man&#34;</span> <span style="color:#06b6ef">href</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;https://man.openbsd.org/{{ $txt }}{{ if $nb }}{{ print &#34;</span><span style="color:#ef6155">.&#34;</span> <span style="color:#ef6155">$</span><span style="color:#06b6ef">nb</span> <span style="color:#ef6155">}}{{</span> <span style="color:#06b6ef">end</span> <span style="color:#ef6155">}}&#34;</span> <span style="color:#06b6ef">title</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;{{ i18n &#34;</span><span style="color:#06b6ef">manpageTitle</span><span style="color:#ef6155">&#34;</span> <span style="color:#ef6155">}}{{</span> <span style="color:#ef6155">$</span><span style="color:#06b6ef">txt</span> <span style="color:#ef6155">}}&#34;</span>&gt;{{ $txt }}{{ if $nb }}{{ print &#34;(&#34; $nb &#34;)&#34; }}{{ end }}&lt;/<span style="color:#5bc4bf">a</span>&gt;
</span></span></code></pre></div><hr>
<p>Examples:</p>
<ul>
<li>Link to the manpage <strong>Packet Filter</strong>: 
<a class="man" href="https://man.openbsd.org/pf.4" title="OpenBSD Manual Page Server for: pf">pf(4)</a>
</li>
<li>Other link: 
<a class="man" href="https://man.openbsd.org/httpd.8" title="OpenBSD Manual Page Server for: httpd">httpd(8)</a>
</li>
<li>And, the last but not the least: 
<a class="man" href="https://man.openbsd.org/man" title="OpenBSD Manual Page Server for: man">man</a>
</li>
</ul>
<h3 id="wikipedia">Wikipedia</h3>
<p>Egual, for the Wikipedia, the shortcode is:
<div class="info-code">
    <p>Code:&nbsp;<em>shortcode</em></p>
</div>
<div class="code"><pre tabindex="0"><code class="language-shortcode" data-lang="shortcode">
{{&lt; wp &#34;url-article&#34; &gt;}}
</code></pre></div>
</p>
<hr>
<p><div class="is-right">
    <p class="is-italic is-white-50">RAW source of the shortcode: <a class="raw-src" href="wp.html" title="">wp</a></p>
</div>

The shortcode:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-html" data-lang="html"><span style="display:flex;"><span>{{ $txt := .Get 0 }}{{ $title := print (i18n &#34;wpTitleArticle&#34;) $txt }}&lt;<span style="color:#5bc4bf">a</span> <span style="color:#06b6ef">href</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;https://{{ .Site.Language.Lang }}.wikipedia.org/wiki/{{ $txt }}&#34;</span> <span style="color:#06b6ef">title</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;{{ $title }}&#34;</span>&gt;Wikipedia :: {{ $txt }}&lt;/<span style="color:#5bc4bf">a</span>&gt;
</span></span></code></pre></div><hr>
<p>Examples:</p>
<ul>
<li>This is an article to promote OpenBSD: <a href="https://en.wikipedia.org/wiki/OpenBSD" title="Wikipedia Article: OpenBSD">
    OpenBSD
    <sup><abbr class="is-italic" title="Wikipedia">WP</abbr></sup>
</a>
</li>
<li>This other is for Debian: <a href="https://en.wikipedia.org/wiki/Debian" title="Wikipedia Article: Debian">
    Debian
    <sup><abbr class="is-italic" title="Wikipedia">WP</abbr></sup>
</a>
</li>
<li>And, a third more complex: <a href="https://en.wikipedia.org/wiki/Firewall_%28computing%29" title="Wikipedia Article: Firewall_(computing)">
    Firewall_(computing)
    <sup><abbr class="is-italic" title="Wikipedia">WP</abbr></sup>
</a>
</li>
</ul>
<h2 id="somewhere">Somewhere</h2>
<p>Finally, do not hesitate to have fun with the shortcodes; get help on <a href="https://discourse.gohugo.io/" rel="external">the commmunity forum</a>.</p>
<ul>
<li><a href="https://after-dark.habd.as/shortcode/" rel="external">https://after-dark.habd.as/shortcode/</a></li>
</ul>
<hr>
]]></content><summary>My different Hugo shortcodes's presentation</summary><published>2019-11-29T15:29:59+01:00</published><updated>2026-10-02T15:49:57+02:00</updated></entry><entry><id>tag:doc.huc.fr.eu.org,2019-11-29:/en/web/hugo/hugo-deploy</id><link href="https://it-log.fr.eu.org/en/web/hugo/hugo-deploy/" rel="alternate" type="text/html"/><title>Hugo: Deploy SFTP</title><author><name>Stéphane HUC</name></author><category term="Hugo" scheme="https://it-log.fr.eu.org/en/tags/hugo/"/><category term="deploy" scheme="https://it-log.fr.eu.org/en/tags/deploy/"/><category term="chroot" scheme="https://it-log.fr.eu.org/en/tags/chroot/"/><category term="lftp" scheme="https://it-log.fr.eu.org/en/tags/lftp/"/><category term="rclone" scheme="https://it-log.fr.eu.org/en/tags/rclone/"/><category term="rsync" scheme="https://it-log.fr.eu.org/en/tags/rsync/"/><category term="SSH" scheme="https://it-log.fr.eu.org/en/tags/ssh/"/><category term="SFTP" scheme="https://it-log.fr.eu.org/en/tags/sftp/"/><content type="html"><![CDATA[<h2 id="description">Description</h2>
<p>To deploy a static website, made with Hugo, some solutions exist:</p>
<ul>
<li>the easy is with the tool <a href="/en/web/hugo/hugo-deploy/#rsync">rsync</a>.</li>
<li>automated deployment solutions.</li>
<li>I review a third for users SSH, under chroot contraints.</li>
</ul>
<p>Into the simple context deployment, you need to create a file named <code>deploy</code>
at the root of your Hugo project.</p>
<h2 id="utilisation">Utilisation</h2>
<h3 id="rsync">rsync</h3>
<p>To deploy a site with <code>rsync</code> is really simple. <strong>rsync</strong> is the tool to
synchronize datas; it&rsquo;s just do it!</p>
<p>Install the tool:</p>
<ul>
<li>on Debian/*Buntu : <code>:# apt install rsync</code></li>
<li>on OpenBSD : <code>:# pkg_add rsync</code> - 

























<span lang="en">FYI <em>(for your information)</em></span>





















































































, since OpenBSD 6.5, it
exists the tool <code>openrsync</code>;
<em>it&rsquo;s subject to the same problem described below!</em></li>
</ul>
<p>I presume you had an authentification SSH, <em>with key is better</em>.</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#776e71">#!/bin/sh
</span></span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ef6155">user</span><span style="color:#5bc4bf">=</span>userid
</span></span><span style="display:flex;"><span><span style="color:#ef6155">host</span><span style="color:#5bc4bf">=</span>servername
</span></span><span style="display:flex;"><span><span style="color:#ef6155">port</span><span style="color:#5bc4bf">=</span><span style="color:#f99b15">22</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ef6155">dir_dist</span><span style="color:#5bc4bf">=</span>/remote_folder/
</span></span><span style="display:flex;"><span><span style="color:#ef6155">file_id</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#ef6155">$HOME</span><span style="color:#48b685">/.ssh/id_ed25519&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>hugo <span style="color:#5bc4bf">&amp;&amp;</span> rsync -avz --delete -e <span style="color:#48b685">&#34;ssh -i </span><span style="color:#f99b15">${</span><span style="color:#ef6155">file_id</span><span style="color:#f99b15">}</span><span style="color:#48b685"> -p </span><span style="color:#f99b15">${</span><span style="color:#ef6155">port</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> public/ <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">user</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>@<span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">host</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>:<span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">dir_dist</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span></code></pre></div><p>This example show the deployment with rsync using a SSH connection.</p>

<div class="tab-info i-info">Info</div><div class="alert alert-info" role="alert">Executing the command <code>hugo</code> regenerate all page. This results <code>rsync</code>
download again all page, and not only the modified.</div>


<div class="tab-info i-warning">Warning</div><div class="alert alert-warning" role="alert"><p>The problem: if the SSH user is under contraint chroot SSH, he can only
connect by</p>
<p><span lang="en">SFTP <em>(SSH File Transfer Protocol)</em></span></p>
<p>; he cant use <strong>rsync</strong> because the tool cant
communicate on this protocol.</p>
<p>To bypass this problem, you need to use :</p>
<ul>
<li><a href="/en/web/hugo/hugo-deploy/#sshfs">sshfs</a> solution, before using <code>rsync</code>, or</li>
<li>the thin <a href="/en/web/hugo/hugo-deploy/#lftp">lftp</a>,</li>
<li>or the powerfull <a href="/en/web/hugo/hugo-deploy/#rclone">rclone</a>.</li>
</ul>
</div>

<h3 id="sshfs">SshFS</h3>
<p><strong>SshFS</strong> can be install with the package manager:</p>
<ul>
<li>on Debian/*Buntu : <code>:# apt install sshfs</code></li>
<li>on OpenBSD : <code>:# pkg_add sshfs</code></li>
</ul>

<div class="tab-info i-info">Info</div><div class="alert alert-info" role="alert"><p>Under OpenBSD, you need to run SshFS with rights admins; use
<a class="man" href="https://man.openbsd.org/doas" title="OpenBSD Manual Page Server for: doas">doas</a>
.</p>
<p>To mount the filesystem: <br>
<code>:$ doas sshfs -C -p $port -o allow_other -o uid=$(id -u $USER) -o gid=$(id -g $USER) ${id}@${host}:${dir_dist} &quot;${dir_mount}&quot;</code></p>
</div>

<p>Once the connection is established, the remote folder is mounted locally
where you desired.</p>
<p>Now, it&rsquo;s time to use <code>rsync</code> as: <br>
<code>:$ cd &quot;${dir_local}&quot; &amp;&amp; rsync -av --delete --human-readable --progress --stats  &quot;.&quot; &quot;${dir_mount}&quot;</code></p>
<p>To unmount correctly: <br>
<code>:$ doas umount &quot;${dir_mount}&quot;</code></p>
<p>With this in mind, see the file <code>deploy</code> under this SshFS+rsync context:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#776e71">#!/bin/sh
</span></span></span><span style="display:flex;"><span><span style="color:#776e71">#set -x</span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">[</span> -n <span style="color:#48b685">&#34;</span><span style="color:#ef6155">$TERM</span><span style="color:#48b685">&#34;</span> <span style="color:#5bc4bf">]</span> <span style="color:#5bc4bf">&amp;&amp;</span> clear
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ef6155">ROOT</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#815ba4">$(</span>dirname <span style="color:#48b685">&#34;</span><span style="color:#815ba4">$(</span>readlink -f -- <span style="color:#48b685">&#34;</span><span style="color:#ef6155">$0</span><span style="color:#48b685">&#34;</span><span style="color:#815ba4">)</span><span style="color:#48b685">&#34;</span><span style="color:#815ba4">)</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ef6155">id</span><span style="color:#5bc4bf">=</span>userid
</span></span><span style="display:flex;"><span><span style="color:#ef6155">host</span><span style="color:#5bc4bf">=</span>servername
</span></span><span style="display:flex;"><span><span style="color:#ef6155">port</span><span style="color:#5bc4bf">=</span><span style="color:#f99b15">22</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">### the directory where your web site files should go</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">## dir_dist: relative to chroot SSH</span>
</span></span><span style="display:flex;"><span><span style="color:#ef6155">dir_dist</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;/www/&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#ef6155">dir_local</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#ef6155">$ROOT</span><span style="color:#48b685">/public/&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#ef6155">dir_mount</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#ef6155">$HOME</span><span style="color:#48b685">/servers/</span><span style="color:#f99b15">${</span><span style="color:#ef6155">id</span><span style="color:#f99b15">}</span><span style="color:#48b685">/&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ef6155">file_id</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#ef6155">$HOME</span><span style="color:#48b685">/.ssh/id_ed25519&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ef6155">rsync_opts</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;--human-readable --progress --stats &#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">################################################################################</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">###</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">##</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#   Fonctions</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">##</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">###</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">################################################################################</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>_mount<span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#5bc4bf">[</span> ! -d <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">dir_mount</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> <span style="color:#5bc4bf">]</span> <span style="color:#5bc4bf">&amp;&amp;</span> mkdir -p <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">dir_mount</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#776e71"># for Debian</span>
</span></span><span style="display:flex;"><span>    <span style="color:#5bc4bf">[</span> -d <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">dir_mount</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> <span style="color:#5bc4bf">]</span> <span style="color:#5bc4bf">&amp;&amp;</span> sshfs -C -p <span style="color:#ef6155">$port</span> -o <span style="color:#ef6155">uid</span><span style="color:#5bc4bf">=</span><span style="color:#815ba4">$(</span>id -u <span style="color:#ef6155">$USER</span><span style="color:#815ba4">)</span> -o <span style="color:#ef6155">gid</span><span style="color:#5bc4bf">=</span><span style="color:#815ba4">$(</span>id -g <span style="color:#ef6155">$USER</span><span style="color:#815ba4">)</span> -o <span style="color:#ef6155">IdentityFile</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">file_id</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> <span style="color:#f99b15">${</span><span style="color:#ef6155">id</span><span style="color:#f99b15">}</span>@<span style="color:#f99b15">${</span><span style="color:#ef6155">host</span><span style="color:#f99b15">}</span>:<span style="color:#f99b15">${</span><span style="color:#ef6155">dir_dist</span><span style="color:#f99b15">}</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">dir_mount</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#776e71"># for OpenBSD</span>
</span></span><span style="display:flex;"><span>    <span style="color:#5bc4bf">[</span> -d <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">dir_mount</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> <span style="color:#5bc4bf">]</span> <span style="color:#5bc4bf">&amp;&amp;</span> doas sshfs -C -p <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">port</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> -o allow_other -o <span style="color:#ef6155">uid</span><span style="color:#5bc4bf">=</span><span style="color:#815ba4">$(</span>id -u <span style="color:#ef6155">$USER</span><span style="color:#815ba4">)</span> -o <span style="color:#ef6155">gid</span><span style="color:#5bc4bf">=</span><span style="color:#815ba4">$(</span>id -g <span style="color:#ef6155">$USER</span><span style="color:#815ba4">)</span> -o <span style="color:#ef6155">IdentityFile</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">file_id</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">id</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>@<span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">host</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>:<span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">dir_dist</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">dir_mount</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>_rsync<span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    cd <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">dir_local</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> <span style="color:#5bc4bf">||</span> exit
</span></span><span style="display:flex;"><span>    rsync -av --delete <span style="color:#ef6155">$rsync_opts</span> <span style="color:#48b685">&#34;.&#34;</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">dir_mount</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>_umount<span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>    fusermount -u <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">dir_mount</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>    <span style="color:#776e71"># for Debian</span>
</span></span><span style="display:flex;"><span>    doas umount <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">dir_mount</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> <span style="color:#776e71"># for OpenBSD</span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">################################################################################</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">###</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">##</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#   Execution</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">##</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">###</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">################################################################################</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>hugo
</span></span><span style="display:flex;"><span><span style="color:#ef6155">status</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#ef6155">$?</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#815ba4">if</span> <span style="color:#5bc4bf">[</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">status</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> -eq <span style="color:#f99b15">0</span> <span style="color:#5bc4bf">]</span>; <span style="color:#815ba4">then</span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">if</span> _mount; <span style="color:#815ba4">then</span>
</span></span><span style="display:flex;"><span>        _rsync
</span></span><span style="display:flex;"><span>        _umount
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span><span style="color:#815ba4">fi</span>
</span></span></code></pre></div>
<div class="tab-info i-warning">Warning</div><div class="alert alert-warning" role="alert">Be carefull: DO NOT USE directly this script without comment lines, segun
your OS!</div>

<h3 id="lftp">lftp</h3>
<p><strong>lftp</strong> is a &ldquo;Swiss Army knife&rdquo; for the network connection. It run FTP(S),
HTTP(S) protocols, on IPv4, IPv6; and too, bittorent and partial WebDAV.
It can be mirroring documents and folders. And: SFTP!</p>
<p>Yes, you can mirror datas on SFTP!</p>
<hr>
<p>To install by the package manager:</p>
<ul>
<li>on Debian/*Buntu : <code>:# apt install lftp</code></li>
<li>on OpenBSD : <code>:# pkg_add lftp</code></li>
</ul>
<p>See, this instance deployment:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#776e71">#!/bin/sh
</span></span></span><span style="display:flex;"><span><span style="color:#776e71">#set -x</span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">[</span> -n <span style="color:#48b685">&#34;</span><span style="color:#ef6155">$TERM</span><span style="color:#48b685">&#34;</span> <span style="color:#5bc4bf">]</span> <span style="color:#5bc4bf">&amp;&amp;</span> clear
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ef6155">ROOT</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#815ba4">$(</span>dirname <span style="color:#48b685">&#34;</span><span style="color:#815ba4">$(</span>readlink -f -- <span style="color:#48b685">&#34;</span><span style="color:#ef6155">$0</span><span style="color:#48b685">&#34;</span><span style="color:#815ba4">)</span><span style="color:#48b685">&#34;</span><span style="color:#815ba4">)</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ef6155">id</span><span style="color:#5bc4bf">=</span>userid
</span></span><span style="display:flex;"><span><span style="color:#ef6155">host</span><span style="color:#5bc4bf">=</span>servername
</span></span><span style="display:flex;"><span><span style="color:#ef6155">port</span><span style="color:#5bc4bf">=</span><span style="color:#f99b15">22</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">### the directory where your web site files should go</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">## dir_dist: relative to chroot SSH</span>
</span></span><span style="display:flex;"><span><span style="color:#ef6155">dir_dist</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;/www/&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#ef6155">dir_local</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#ef6155">$ROOT</span><span style="color:#48b685">/public/&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ef6155">file_id</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#ef6155">$HOME</span><span style="color:#48b685">/.ssh/id_ed25519&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>hugo
</span></span><span style="display:flex;"><span>lftp -e <span style="color:#48b685">&#34;set ftp:ssl-allow no; set sftp:connect-program ssh -a -x -i </span><span style="color:#f99b15">${</span><span style="color:#ef6155">file_id</span><span style="color:#f99b15">}</span><span style="color:#48b685">; mirror -e -R </span><span style="color:#f99b15">${</span><span style="color:#ef6155">dir_local</span><span style="color:#f99b15">}</span><span style="color:#48b685"> </span><span style="color:#f99b15">${</span><span style="color:#ef6155">dir_dist</span><span style="color:#f99b15">}</span><span style="color:#48b685">; quit;&#34;</span> -p <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">port</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> sftp://<span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">id</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>:<span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">passwd</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>@<span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">host</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span></code></pre></div><h3 id="rclone">rclone</h3>
<p><strong>rclone</strong> is a very powerfull CLI tool to duplicate on stockage solution,
as Cloud, differents filesystems, but too with SFTP.</p>
<p>Install by the package manager:</p>
<ul>
<li>on Debian/*Buntu: <code># apt install rclone</code></li>
<li>on OpenBSD: <code># pkg_add rclone</code></li>
</ul>
<p>In first, you need to configure by using the option <code>config</code>: <code>$ rclone config</code></p>
<ol>
<li>Name your <strong>remote</strong> access, as you wish. This will be use as remote
name connexion.</li>
<li>Choose absolutly SFTP connexion, to write <code>sftp</code> when the invite asks.</li>
</ol>
<p><em>See the <a href="/en/web/hugo/hugo-deploy/#documentation">documentation</a> Rclone:SFTP!</em></p>
<p>File config: <code>~/.config/rclone/rclone.conf</code><em>, by default.</em></p>
<p>Here this instance configuration:</p>
<pre tabindex="0"><code class="language-conf" data-lang="conf">[nom_remote]
type = sftp
host = adresse_ip ou FQDN
user = id_ssh
port = 22
key_file = ~/.ssh/id_ed25519
key_use_agent = true
pubkey_file = ~/.ssh/id_ed25519.pub
use_insecure_cipher = false
md5sum_command = none
sha1sum_command = none
</code></pre><p>And here, this instance deployment:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#776e71">#!/bin/sh
</span></span></span><span style="display:flex;"><span><span style="color:#776e71">#set -x</span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">[</span> -n <span style="color:#48b685">&#34;</span><span style="color:#ef6155">$TERM</span><span style="color:#48b685">&#34;</span> <span style="color:#5bc4bf">]</span> <span style="color:#5bc4bf">&amp;&amp;</span> clear
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ef6155">ROOT</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#815ba4">$(</span>dirname <span style="color:#48b685">&#34;</span><span style="color:#815ba4">$(</span>readlink -f -- <span style="color:#48b685">&#34;</span><span style="color:#ef6155">$0</span><span style="color:#48b685">&#34;</span><span style="color:#815ba4">)</span><span style="color:#48b685">&#34;</span><span style="color:#815ba4">)</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ef6155">id</span><span style="color:#5bc4bf">=</span>userid
</span></span><span style="display:flex;"><span><span style="color:#ef6155">host</span><span style="color:#5bc4bf">=</span>servername
</span></span><span style="display:flex;"><span><span style="color:#ef6155">port</span><span style="color:#5bc4bf">=</span><span style="color:#f99b15">22</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">### the directory where your web site files should go</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">## dir_dist: relative to chroot SSH</span>
</span></span><span style="display:flex;"><span><span style="color:#ef6155">dir_dist</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;/www/&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#ef6155">dir_local</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#ef6155">$ROOT</span><span style="color:#48b685">/public/&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ef6155">file_id</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#ef6155">$HOME</span><span style="color:#48b685">/.ssh/id_ed25519&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ef6155">rclone_remote</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;nom_remote&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>hugo
</span></span><span style="display:flex;"><span>rclone sync -i <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">dir_local</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">rclone_remote</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>:<span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">dir_dist</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span></code></pre></div><h2 id="fin">FIN</h2>
<p>Voila: This is the end!</p>
<p>Now, you known how to deploy your static website Hugo, with <code>rsync/ssh</code>,
<code>sshfs+rsync</code>, <code>lftp</code>, or even by <code>rclone</code>.</p>
<h2 id="documentation">Documentation</h2>
<ul>
<li><a href="https://gohugo.io/hosting-and-deployment/deployment-with-rsync/" title="Link to the official site Hugo: Hosting and deployment &gt; Deployment with rsync">Hugo Documentation: Hosting and deployment &gt; Deployment with rsync</a>
</li>
<li><a href="https://gohugo.io/hosting-and-deployment//" title="Link to the official site Hugo: Hosting and deployment &gt; ">Hugo Documentation: Hosting and deployment &gt; </a>
</li>
<li>the <a href="https://lftp.yar.ru/" rel="external">lftp</a> website.</li>
<li>the <a href="https://rclone.org/" rel="external">rclone</a>, and <a href="https://rclone.org/sftp/" rel="external">rclone:sftp</a> documentation page.</li>
</ul>
<hr>
]]></content><summary>Deploy a site, made with the generator Hugo, by rsync/ssh, SFTP+rsync, lftp client, or the powerfull rclone.</summary><published>2019-11-29T14:45:12+01:00</published><updated>2026-10-02T15:49:57+02:00</updated></entry><entry><id>tag:doc.huc.fr.eu.org,2019-11-23:/en/web/nextcloud/occ</id><link href="https://it-log.fr.eu.org/en/web/nextcloud/occ/" rel="alternate" type="text/html"/><title>Nextcloud : manpage occ</title><author><name>Stéphane HUC</name></author><category term="Nextcloud" scheme="https://it-log.fr.eu.org/en/tags/nextcloud/"/><category term="occ" scheme="https://it-log.fr.eu.org/en/tags/occ/"/><content type="html"><![CDATA[<h2 id="occ">occ</h2>
<p>Usage:
<code>command [options] [arguments]</code></p>
<p>Options:</p>
<ul>
<li><code>-h</code>, <code>--help</code>            Display this help message</li>
<li><code>-q</code>, <code>--quiet</code>           Do not output any message</li>
<li><code>-V</code>, <code>--version</code>         Display this application version
<ul>
<li><code>--ansi</code>              Force ANSI output</li>
<li><code>--no-ansi</code>           Disable ANSI output</li>
</ul>
</li>
<li><code>-n</code>, <code>--no-interaction</code>  Do not ask any interactive question
<ul>
<li><code>--no-warnings</code>       Skip global warnings, show command output only</li>
</ul>
</li>
<li><code>-v</code>|<code>vv</code>|<code>vvv</code>, <code>--verbose</code>  Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug</li>
</ul>
<p>Available commands:</p>
<ul>
<li><code>check</code>                   check dependencies of the server environment</li>
<li><code>help</code>                    displays help for a command</li>
<li><code>list</code>                    Lists commands</li>
<li><code>status</code>                  show some status information</li>
<li><code>upgrade</code>                 run upgrade routines after installation of a new release. The release has to be installed before.</li>
</ul>
<h3 id="manage-configuration">Manage configuration</h3>
<p><code>config</code></p>
<ul>
<li><code>config:app:delete</code>                   Delete an app config value</li>
<li><code>config:app:get</code>                      Get an app config value</li>
<li><code>config:app:set</code>                      Set an app config value</li>
<li><code>config:import</code>                       Import a list of configs</li>
<li><code>config:list</code>                         List all configs</li>
<li><code>config:system:delete</code>                Delete a system config value</li>
<li><code>config:system:get</code>                   Get a system config value</li>
<li><code>config:system:set</code>                   Set a system config value</li>
</ul>
<h3 id="manage-database">Manage Database</h3>
<p><code>db</code></p>
<ul>
<li><code>db:add-missing-indices</code>              Add missing indices to the database tables</li>
<li><code>db:convert-filecache-bigint</code>         Convert the ID columns of the filecache to BigInt</li>
<li><code>db:convert-mysql-charset</code>            Convert charset of MySQL/MariaDB to use utf8mb4</li>
<li><code>db:convert-type</code>                     Convert the Nextcloud database to the newly configured one</li>
</ul>
<h3 id="encryption-management">Encryption Management</h3>
<p><code>encryption</code></p>
<ul>
<li><code>encryption:change-key-storage-root</code>  Change key storage root</li>
<li><code>encryption:decrypt-all</code>              Disable server-side encryption and decrypt all files</li>
<li><code>encryption:disable</code>                  Disable encryption</li>
<li><code>encryption:enable</code>                   Enable encryption</li>
<li><code>encryption:encrypt-all</code>              Encrypt all files for all users</li>
<li><code>encryption:list-modules</code>             List all available encryption modules</li>
<li><code>encryption:set-default-module</code>       Set the encryption default module</li>
<li><code>encryption:show-key-storage-root</code>    Show current key storage root</li>
<li><code>encryption:status</code>                   Lists the current status of encryption</li>
</ul>
<h3 id="federation-management">Federation Management</h3>
<p><code>federation</code></p>
<ul>
<li><code>federation:sync-addressbooks</code>        Synchronizes addressbooks of all federated clouds</li>
</ul>
<h3 id="files-management">Files Management</h3>
<p><code>files</code></p>
<ul>
<li><code>files:cleanup</code>                       cleanup filecache</li>
<li><code>files:recommendations:recommend</code></li>
<li><code>files:scan</code>                         rescan filesystem</li>
<li><code>files:scan-app-data</code>                rescan the AppData folder</li>
<li><code>files:transfer-ownership</code>           All files and folders are moved to another user - shares are moved as well.</li>
</ul>
<h3 id="groups-management">Groups Management</h3>
<p><code>roup</code></p>
<ul>
<li><code>group:add</code>                           Add a group</li>
<li><code>group:adduser</code>                       add a user to a group</li>
<li><code>group:delete</code>                        Remove a group</li>
<li><code>group:list</code>                          list configured groups</li>
<li><code>group:removeuser</code>                    remove a user from a group</li>
</ul>
<h3 id="integrity-app-core">Integrity App, Core</h3>
<p><code>integrity</code></p>
<ul>
<li><code>integrity:check-app</code>                 Check integrity of an app using a signature.</li>
<li><code>integrity:check-core</code>                Check integrity of core code using a signature.</li>
<li><code>integrity:sign-app</code>                  Signs an app using a private key.</li>
<li><code>integrity:sign-core</code>                 Sign core using a private key.</li>
</ul>
<h3 id="logs-management">Logs Management</h3>
<p><code>log</code></p>
<ul>
<li><code>log:file</code>                           manipulate logging backend</li>
<li><code>log:manage</code>                          manage logging configuration</li>
<li><code>log:tail</code>                            Tail the nextcloud logfile</li>
<li><code>log:watch</code>                           Watch the nextcloud logfile</li>
</ul>
<h3 id="nc-background-jobs">NC Background jobs</h3>
<p><code>background</code></p>
<ul>
<li><code>background:ajax</code>                     Use ajax to run background jobs</li>
<li><code>background:cron</code>                     Use cron to run background jobs</li>
<li><code>background:webcron</code>                  Use webcron to run background jobs</li>
</ul>
<h3 id="nc-maintenance">NC Maintenance</h3>
<p><code>maintenance</code></p>
<ul>
<li><code>maintenance:data-fingerprint</code>        update the systems data-fingerprint after a backup is restored</li>
<li><code>maintenance:mimetype:update-db</code>      Update database mimetypes and update filecache</li>
<li><code>maintenance:mimetype:update-js</code>      Update mimetypelist.js</li>
<li><code>maintenance:mode</code>                    set maintenance mode</li>
<li><code>maintenance:repair</code>                  repair this installation</li>
<li><code>maintenance:theme:update</code>            Apply custom theme changes</li>
<li><code>maintenance:update:htaccess</code>         Updates the .htaccess file</li>
</ul>
<h3 id="nc-migration">NC Migration</h3>
<p><code>migrations</code></p>
<ul>
<li><code>migrations:execute</code>                  Execute a single migration version manually.</li>
<li><code>migrations:generate</code></li>
<li><code>migrations:generate-from-schema</code></li>
<li><code>migrations:migrate</code>                  Execute a migration to a specified version or the latest available version.</li>
<li><code>migrations:status</code>                   View the status of a set of migrations.</li>
</ul>
<h3 id="nc-security">NC Security</h3>
<p><code>security</code></p>
<ul>
<li><code>security:certificates</code>               list trusted certificates</li>
<li><code>security:certificates:import</code>        import trusted certificate</li>
<li><code>security:certificates:remove</code>        remove trusted certificate</li>
</ul>
<h3 id="nc-update">NC Update</h3>
<p><code>update</code></p>
<ul>
<li><code>update:check</code>                        Check for server and app updates</li>
</ul>
<h3 id="user-management">User management</h3>
<p><code>user</code></p>
<ul>
<li><code>user:add</code>                            adds a user</li>
<li><code>user:delete</code>                         deletes the specified user and all datas user</li>
<li><code>user:disable</code>                        disables the specified user</li>
<li><code>user:enable</code>                         enables the specified user</li>
<li><code>user:info</code>                           show user info</li>
<li><code>user:lastseen</code>                       shows when the user was logged in last time</li>
<li><code>user:list</code>                           list configured users</li>
<li><code>user:report</code>                         shows how many users have access</li>
<li><code>user:resetpassword</code>                  Resets the password of the named user</li>
<li><code>user:setting</code>                        Read and modify user settings</li>
</ul>
<p><code>notification</code></p>
<ul>
<li><code>notification:generate</code>               Generate a notification for the given user</li>
</ul>
<p><code>versions</code></p>
<ul>
<li><code>versions:cleanup</code>                    Delete versions: delete versions of the given user(s), if no user is given all versions will be deleted</li>
<li><code>versions:expire</code>                     Expires the users file versions: expire file versions of the given user(s), if no user is given file versions for all users will be expired.</li>
</ul>
<h3 id="manage-applications">Manage applications</h3>
<p><code>app</code></p>
<ul>
<li><code>app:check-code</code>                      check code to be compliant</li>
<li><code>app:disable</code>                         disable an app</li>
<li><code>app:enable</code>                          enable an app</li>
<li><code>app:getpath</code>                         Get an absolute path to the app directory</li>
<li><code>app:install</code>                         install an app</li>
<li><code>app:list</code>                            List all available apps</li>
<li><code>app:remove</code>                          remove an app</li>
<li><code>app:update</code>                          update an app or all apps</li>
</ul>
<h4 id="mail">Mail</h4>
<p><code>mail</code></p>
<ul>
<li><code>mail:account:create</code>                 creates IMAP account</li>
<li><code>mail:account:export</code>                 Exports a user&rsquo;s IMAP account(s)</li>
</ul>
<h4 id="circles">Circles</h4>
<p><code>circles</code></p>
<ul>
<li><code>circles:clean</code>                       remove all extra data from database</li>
<li><code>circles:fixuniqueid</code>                 fix Unique Id issue.</li>
</ul>
<h4 id="deck">Deck</h4>
<p><code>deck</code></p>
<ul>
<li><code>deck:export</code>                         Export a JSON dump of user data</li>
</ul>
<h4 id="talk">Talk</h4>
<p><code>talk</code></p>
<ul>
<li><code>talk:command:add</code>                    Add a new command</li>
<li><code>talk:command:add-samples</code>            Adds some sample commands: /wiki, …</li>
<li><code>talk:command:delete</code>                 Remove an existing command</li>
<li><code>talk:command:list</code>                   List all available commands</li>
<li><code>talk:command:update</code>                 Add a new command</li>
<li><code>talk:signaling:add</code>                  Add an external signaling server.</li>
<li><code>talk:signaling:delete</code>               Remove an existing signaling server.</li>
<li><code>talk:signaling:list</code>                 List external signaling servers.</li>
<li><code>talk:stun:add</code>                       Add a new STUN server.</li>
<li><code>talk:stun:delete</code>                    Remove an existing STUN server.</li>
<li><code>talk:stun:list</code>                      List STUN servers.</li>
<li><code>talk:turn:add</code>                       Add a TURN server.</li>
<li><code>talk:turn:delete</code>                    Remove an existing TURN server.</li>
<li><code>talk:turn:list</code>                      List TURN servers.</li>
</ul>
<h4 id="2fa-two-factor-auth">2FA: Two Factor Auth</h4>
<p><code>twofactorauth</code></p>
<ul>
<li><code>twofactorauth:cleanup</code>               Clean up the two-factor user-provider association of an uninstalled/removed provider</li>
<li><code>twofactorauth:disable</code>               Disable two-factor authentication for a user</li>
<li><code>twofactorauth:enable</code>                Enable two-factor authentication for a user</li>
<li><code>twofactorauth:enforce</code>               Enabled/disable enforced two-factor authentication</li>
<li><code>twofactorauth:state</code>                 Get the two-factor authentication (2FA) state of a user</li>
</ul>
<h4 id="webdav">WebDAV</h4>
<p><code>dav</code></p>
<ul>
<li><code>dav:create-addressbook</code>              Create a dav addressbook</li>
<li><code>dav:create-calendar</code>                 Create a dav calendar</li>
<li><code>dav:list-calendars</code>                  List all calendars of a user</li>
<li><code>dav:move-calendar</code>                   Move a calendar from an user to another</li>
<li><code>dav:remove-invalid-shares</code>           Remove invalid dav shares</li>
<li><code>dav:send-event-reminders</code>            Sends event reminders</li>
<li><code>dav:sync-birthday-calendar</code>          Synchronizes the birthday calendar</li>
<li><code>dav:sync-system-addressbook</code>         Synchronizes users to the system addressbook</li>
</ul>
<hr>
]]></content><summary>Nextcloud: manpage occ commander</summary><published>2019-11-23T21:59:23+01:00</published><updated>2026-10-02T15:49:57+02:00</updated></entry><entry><id>tag:doc.huc.fr.eu.org,2019-11-23:/en/web/nextcloud/nextcloud-upgrade</id><link href="https://it-log.fr.eu.org/en/web/nextcloud/nextcloud-upgrade/" rel="alternate" type="text/html"/><title>(tip) Nextcloud: Manual upgrade on OpenBSD</title><author><name>Stéphane HUC</name></author><category term="Nextcloud" scheme="https://it-log.fr.eu.org/en/tags/nextcloud/"/><category term="OpenBSD" scheme="https://it-log.fr.eu.org/en/tags/openbsd/"/><category term="upgrade" scheme="https://it-log.fr.eu.org/en/tags/upgrade/"/><category term="tip" scheme="https://it-log.fr.eu.org/en/tags/tip/"/><content type="html"><![CDATA[<h2 id="description">Description</h2>
<p>Upgrade <abbr title="Nextcloud">NC</abbr>
 <em>(Nextcloud )</em> is very easy… Either you do it:</p>
<ul>
<li>With the web updater.</li>
<li>Manually, as me.</li>
<li>Via the packages management.</li>
</ul>
<p><abbr title="For Your Information">FYI</abbr>
: This article explains the manual process under OpenBSD, with nginx, PHP 7.3.</p>
<h2 id="upgrading-process">Upgrading Process</h2>
<p>This process used few years ago, since v 15.*, as KISS.</p>
<h3 id="stop-web-service">Stop Web Service</h3>
<p>The first action disables domain:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#776e71"># rm -f /etc/nginx/sites-enabled/mon-domaine.net</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># nginx -t &amp;&amp; rcctl restart nginx</span>
</span></span></code></pre></div><h3 id="preparations">Preparations</h3>
<p>Presume user web is <code>www</code>.</p>
<p>Need to log as: <code>$ su -l www</code></p>
<ol>
<li>Go to the nextcloud folder: <code>cd www/nextcloud</code></li>
<li><a href="/en/web/nextcloud/nextcloud-php-chroot/">Need to modify</a> the config file: <code>sed -i -e 's#/htdocs#/var/www/htdocs#' config/config.php</code></li>
<li>And enable the maintenance mode: <code>php-7.3 occ maintenance:mode --on</code></li>
</ol>
<h4 id="download">Download</h4>
<ol>
<li>Go to the parent folder <code>www\</code> :</li>
<li>Create an usefull version variable named <code>v</code>.</li>
<li>Download the actual archive and her checksum sha256 file.</li>
<li>Check the checksum</li>
</ol>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>$ cd ../
</span></span><span style="display:flex;"><span>$ <span style="color:#ef6155">v</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;17.0.1&#34;</span>
</span></span><span style="display:flex;"><span>$ <span style="color:#815ba4">for</span> ext in bz2 bz2.sha256; <span style="color:#815ba4">do</span> curl -O https://download.nextcloud.com/server/releases/nextcloud-<span style="color:#ef6155">$v</span>.tar.<span style="color:#ef6155">$ext</span>; <span style="color:#815ba4">done</span>
</span></span><span style="display:flex;"><span>$ sha256 -c nextcloud-<span style="color:#ef6155">$v</span>.tar.bz2.sha256
</span></span></code></pre></div><p>If the result of SHA is <code>(SHA256) nextcloud-$v.tar.bz2: OK</code>, it&rsquo;s good; if not, re-download-it!</p>
<h4 id="installation">Installation</h4>
<ul>
<li>moving actuel folder <code>nextcloud</code> with date and old number version.</li>
<li>untar the archive.</li>
<li>delete file <code>CAN_INSTALL</code>; <em>(we&rsquo;re not looking to reinstall)!</em></li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>$ <span style="color:#ef6155">oldvers</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;16.0.6&#34;</span>
</span></span><span style="display:flex;"><span>$ <span style="color:#ef6155">date</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#815ba4">$(</span>date <span style="color:#48b685">&#39;+%Y%m%d%H%M%S&#39;</span><span style="color:#815ba4">)</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>$ <span style="color:#ef6155">oldnc</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;nextcloud-</span><span style="color:#f99b15">${</span><span style="color:#ef6155">date</span><span style="color:#f99b15">}</span><span style="color:#48b685">-</span><span style="color:#f99b15">${</span><span style="color:#ef6155">oldvers</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>$ mv nextcloud <span style="color:#f99b15">${</span><span style="color:#ef6155">oldnc</span><span style="color:#f99b15">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>$ tar xjvf nextcloud-<span style="color:#ef6155">$v</span>.tar.bz2
</span></span><span style="display:flex;"><span>$ rm -fP config/CAN_INSTALL
</span></span></code></pre></div><h4 id="first-checks">First Checks</h4>
<p>Here, you must be careful:</p>
<ul>
<li>copy old config file to new folder config: <code>cp ${oldnc}/config/config.php nextcloud/config/</code></li>
<li>Now, diff the oldier app folder with new folder to copy all not natives apps.</li>
<li>Egual, with themes, if necessary.</li>
</ul>
<h4 id="permissions">Permissions</h4>
<ul>
<li>Put the rights users on all files and folders into the folder <code>nextcloud/</code></li>
<li>And, others rights systems.</li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>$ <span style="color:#ef6155">webuser</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;www&#34;</span>
</span></span><span style="display:flex;"><span>$ chown -R <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">webuser</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>:www nextcloud
</span></span><span style="display:flex;"><span>$ find nextcloud/ -type d -exec chmod <span style="color:#f99b15">750</span> <span style="color:#5bc4bf">{}</span> <span style="color:#f99b15">\;</span>
</span></span><span style="display:flex;"><span>$ find nextcloud/ -type f -exec chmod <span style="color:#f99b15">640</span> <span style="color:#5bc4bf">{}</span> <span style="color:#f99b15">\;</span>
</span></span></code></pre></div><h3 id="upgrade-nc-himself">Upgrade NC himself</h3>
<ul>
<li>Just go to the right folder: <code>cd nextcloud/</code></li>
<li>Use the tool <code>occ</code>, as: <code>php-7.3 occ upgrade</code>
<ul>
<li>if success, go out the maintenance mode: <code>php-7.3 occ maintenance:mode --off</code></li>
</ul>
</li>
</ul>
<p>And, at the final, re-sed the config file to delete <code>/var/www</code> :
<code>sed -i -e 's#/var/www/htdocs#/htdocs#' config/config.php</code></p>
<h3 id="restart-web-service">Restart Web Service</h3>
<ul>
<li>Enable domain and restart web server, as:</li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#776e71"># cd /etc/nginx/sites-available/</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># ln -s mon-domaine.net ../sites-enabled/</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># nginx -t &amp;&amp; rcctl restart nginx</span>
</span></span></code></pre></div><ul>
<li>Now, connect you at the WebAdmin as admin user, et apply all updates for the apps.</li>
</ul>
<p>And, voilà!</p>
<h3 id="tldr">TL;DR</h3>
<span class="error">
BE CAREFULL: If you copy this TL;DR as-is, you will crash your install!
</span>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>// stop web services
</span></span><span style="display:flex;"><span><span style="color:#776e71"># rm -f /etc/nginx/sites-enabled/mon-domaine.net</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># nginx -t &amp;&amp; rcctl restart nginx</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>// connexion as user web
</span></span><span style="display:flex;"><span><span style="color:#776e71"># webuser=&#34;www&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># su -l $webuser</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>$ cd /var/www/htdocs/mon-domaine.net/www/nextcloud/
</span></span><span style="display:flex;"><span>$ sed -i -e <span style="color:#48b685">&#39;s#/htdocs#/var/www/htdocs#&#39;</span> config/config.php
</span></span><span style="display:flex;"><span>$ php-7.3 occ maintenance:mode --on
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>// downlad archives, and checksum
</span></span><span style="display:flex;"><span>$ cd ../
</span></span><span style="display:flex;"><span>$ <span style="color:#ef6155">v</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;17.0.1&#34;</span>
</span></span><span style="display:flex;"><span>$ <span style="color:#815ba4">for</span> ext in bz2 bz2.sha256; <span style="color:#815ba4">do</span> curl -O https://download.nextcloud.com/server/releases/nextcloud-<span style="color:#ef6155">$v</span>.tar.<span style="color:#ef6155">$ext</span>; <span style="color:#815ba4">done</span>
</span></span><span style="display:flex;"><span>$ sha256 -c nextcloud-<span style="color:#ef6155">$v</span>.tar.bz2.sha256
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>// Untar
</span></span><span style="display:flex;"><span>$ <span style="color:#ef6155">oldvers</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;16.0.6&#34;</span>
</span></span><span style="display:flex;"><span>$ <span style="color:#ef6155">date</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#815ba4">$(</span>date <span style="color:#48b685">&#39;+%Y%m%d%H%M%S&#39;</span><span style="color:#815ba4">)</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>$ <span style="color:#ef6155">oldnc</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;nextcloud-</span><span style="color:#f99b15">${</span><span style="color:#ef6155">date</span><span style="color:#f99b15">}</span><span style="color:#48b685">-</span><span style="color:#f99b15">${</span><span style="color:#ef6155">oldvers</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>$ mv nextcloud <span style="color:#f99b15">${</span><span style="color:#ef6155">oldnc</span><span style="color:#f99b15">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>$ tar xjvf nextcloud-<span style="color:#ef6155">$v</span>.tar.bz2
</span></span><span style="display:flex;"><span>$ rm -fP config/CAN_INSTALL
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>// cp config
</span></span><span style="display:flex;"><span>$ cp <span style="color:#f99b15">${</span><span style="color:#ef6155">oldnc</span><span style="color:#f99b15">}</span>/config/config.php nextcloud/config/
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>// cp only apps not native; dont recopy this command as-is:
</span></span><span style="display:flex;"><span>$ cp all <span style="color:#f99b15">${</span><span style="color:#ef6155">oldnc</span><span style="color:#f99b15">}</span>/apps diff to new nextcloud/apps
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>// egual <span style="color:#815ba4">for</span> themes, <span style="color:#815ba4">if</span> need
</span></span><span style="display:flex;"><span>$ cp all <span style="color:#f99b15">${</span><span style="color:#ef6155">oldnc</span><span style="color:#f99b15">}</span>/themes to new nextcloud/themes
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>$ chown -R <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">webuser</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>:www nextcloud
</span></span><span style="display:flex;"><span>$ find nextcloud/ -type d -exec chmod <span style="color:#f99b15">750</span> <span style="color:#5bc4bf">{}</span> <span style="color:#f99b15">\;</span>
</span></span><span style="display:flex;"><span>$ find nextcloud/ -type f -exec chmod <span style="color:#f99b15">640</span> <span style="color:#5bc4bf">{}</span> <span style="color:#f99b15">\;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>// occ upgrage process
</span></span><span style="display:flex;"><span>$ cd nextcloud/
</span></span><span style="display:flex;"><span>$ php-7.3 occ upgrade
</span></span><span style="display:flex;"><span>$ php-7.3 occ maintenance:mode --off
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>$ sed -i -e <span style="color:#48b685">&#39;s#/var/www/htdocs#/htdocs#&#39;</span> config/config.php
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>// exit
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>// restart web services
</span></span><span style="display:flex;"><span><span style="color:#776e71"># cd /etc/nginx/sites-available/</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># ln -s mon-domaine.net ../sites-enabled/</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># nginx -t &amp;&amp; rcctl restart nginx</span>
</span></span></code></pre></div><h3 id="caveats">Caveats</h3>
<p>If the upgrade process fails with one of thoses errors messages:</p>
<h4 id="error-nextcloud-is-not-installed">Error: Nextcloud is not installed</h4>
<p>Example:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>$ php-7.3 occ help upgrade
</span></span><span style="display:flex;"><span>Nextcloud is not installed - only a limited number of commands are available
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  Command <span style="color:#48b685">&#34;upgrade&#34;</span> is not defined.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>help <span style="color:#5bc4bf">[</span>--format FORMAT<span style="color:#5bc4bf">]</span> <span style="color:#5bc4bf">[</span>--raw<span style="color:#5bc4bf">]</span> <span style="color:#5bc4bf">[</span>--<span style="color:#5bc4bf">]</span> <span style="color:#5bc4bf">[</span>&lt;command_name&gt;<span style="color:#5bc4bf">]</span>
</span></span></code></pre></div><ul>
<li>Have you really copy the oldier config file to the new folder config?</li>
<li>Try this tip: <code>php-7.3 occ maintenance:repair</code></li>
</ul>
<h4 id="error-you-are-trying-to-reinstall-your-nextcloud">Error: you are trying to reinstall your Nextcloud</h4>
<p>When you connect to the WebUI, you had this message:</p>

<div class="tab-info i-warning">Warning</div><div class="alert alert-warning" role="alert"><p><strong>Error</strong></p>
<p>It looks like you are trying to reinstall your Nextcloud. However the file
CAN_INSTALL is missing from your config directory. Please create the file
CAN_INSTALL in your config folder to continue.</p>
</div>

<ul>
<li>Go to delete the file <code>CAN_INSTALL</code> under the new folder config.</li>
</ul>
<h4 id="the-files-are-not-visibles">the files are not visibles</h4>
<ul>
<li>Try: <code>php-7.3 console.php files:scan --all</code></li>
</ul>
<hr>
<h2 id="occ-commands">OCC Commands</h2>
<p>As a reminder, this usefull command occ: <code>php occ list</code></p>
<p>And see this &ldquo;manpage&rdquo;: <a href="/en/web/nextcloud/occ/">occ</a>.</p>
<hr>
]]></content><summary>Howto upgrade manually Nextcloud under OpenBSD server</summary><published>2019-11-23T20:45:23+01:00</published><updated>2026-10-02T15:49:57+02:00</updated></entry><entry><id>tag:doc.huc.fr.eu.org,2019-10-31:/en/sec/firewall/pf-icmp</id><link href="https://it-log.fr.eu.org/en/sec/firewall/pf-icmp/" rel="alternate" type="text/html"/><title>Manage ICMP through PF (Packet-Filter)</title><author><name>Stéphane HUC</name></author><category term="firewall" scheme="https://it-log.fr.eu.org/en/tags/firewall/"/><category term="PF" scheme="https://it-log.fr.eu.org/en/tags/pf/"/><category term="Packet-Filter" scheme="https://it-log.fr.eu.org/en/tags/packet-filter/"/><category term="ICMP" scheme="https://it-log.fr.eu.org/en/tags/icmp/"/><content type="html"><![CDATA[<h2 id="description">Description</h2>

<div class="tab-info i-tip">Tip</div><div class="alert alert-tip" role="alert">This article can be usefull for the embedded PF on  <a href="https://wiki.debian.org/fr/Debian_GNU/kFreeBSD" rel="external">Debian GNU/kFreeBSD</a> !</div>

<p>Following the recommendations from my <a href="/en/sec/firewall/linux-firewall-icmp/">Linux firewalling ICMP</a> about the rules to be put in place to allow or block ICMP messages, here are the adequate rules for PF, for *BSD that use Packet Filter, including
OpenBSD:</p>
<h2 id="manage-icmp">Manage ICMP</h2>
<h3 id="drop">Drop</h3>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#5bc4bf">(</span>…<span style="color:#5bc4bf">)</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ef6155">icmp_block_types</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;{ 4 6 15 16 17 18 31 32 33 34 35 36 37 38 39 }&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">(</span>…<span style="color:#5bc4bf">)</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>block drop quick on egress inet proto icmp icmp-type <span style="color:#f99b15">3</span> code <span style="color:#f99b15">6</span>
</span></span><span style="display:flex;"><span>block drop in quick on egress inet proto icmp icmp-type <span style="color:#f99b15">3</span> code <span style="color:#f99b15">7</span>
</span></span><span style="display:flex;"><span>block drop quick on egress inet proto icmp icmp-type <span style="color:#f99b15">3</span> code <span style="color:#f99b15">8</span>
</span></span><span style="display:flex;"><span>block drop quick on egress inet proto icmp icmp-type <span style="color:#ef6155">$icmp_block_types</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">(</span>…<span style="color:#5bc4bf">)</span>
</span></span></code></pre></div>
<div class="tab-info i-warning">Warning</div><div class="alert alert-warning" role="alert">It seems that PF does not manage <strong>37</strong> and <strong>38</strong> <em>(respectly
<strong>Domain Name Request</strong>, and <strong>Domain Name Reply</strong>)</em>…</div>

<h3 id="pass">Pass</h3>

<div class="tab-info i-info">Info</div><div class="alert alert-info" role="alert">There is no <code>limit</code> equivalent for PF!<br>
It seems that it&rsquo;s finely managed by the kernel on OpenBSD.</div>

<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#5bc4bf">(</span>…<span style="color:#5bc4bf">)</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ef6155">icmp_types</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;{ 8 11 12 }&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">(</span>…<span style="color:#5bc4bf">)</span>
</span></span><span style="display:flex;"><span>block log
</span></span><span style="display:flex;"><span>pass out
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">(</span>…<span style="color:#5bc4bf">)</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>pass in quick on egress inet proto icmp from any to egress icmp-type <span style="color:#5bc4bf">{</span> <span style="color:#f99b15">3</span> code 3, <span style="color:#f99b15">3</span> code <span style="color:#f99b15">4</span> <span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>pass in quick on egress inet proto icmp from any to egress icmp-type <span style="color:#ef6155">$icmp_types</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>pass out quick on egress inet proto icmp from egress to any icmp-type <span style="color:#5bc4bf">{</span> <span style="color:#f99b15">3</span> code 3, <span style="color:#f99b15">3</span> code <span style="color:#f99b15">4</span> <span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>pass out quick on egress inet proto icmp from egress to any icmp-type <span style="color:#ef6155">$icmp_types</span>
</span></span></code></pre></div><p>Or course, you can authorize all other codes that can be passed, and whose
recommendations are to limit. The 3 highlighted codes are a minimum!</p>
<hr>
]]></content><summary>Example of rules to manage ICMP with the firewall Packet-Filter (PF)</summary><published>2019-10-31T12:38:55+02:00</published><updated>2026-10-02T15:49:57+02:00</updated></entry><entry><id>tag:doc.huc.fr.eu.org,2019-10-31:/en/sec/firewall/pf-icmpv6</id><link href="https://it-log.fr.eu.org/en/sec/firewall/pf-icmpv6/" rel="alternate" type="text/html"/><title>Manage ICMPv6 through PF (Packet-Filter)</title><author><name>Stéphane HUC</name></author><category term="firewall" scheme="https://it-log.fr.eu.org/en/tags/firewall/"/><category term="PF" scheme="https://it-log.fr.eu.org/en/tags/pf/"/><category term="Packet-Filter" scheme="https://it-log.fr.eu.org/en/tags/packet-filter/"/><category term="ICMPv6" scheme="https://it-log.fr.eu.org/en/tags/icmpv6/"/><content type="html"><![CDATA[<h2 id="description">Description</h2>

<div class="tab-info i-tip">Tip</div><div class="alert alert-tip" role="alert">This article can be usefull for the embedded PF on <a href="https://wiki.debian.org/fr/Debian_GNU/kFreeBSD" rel="external">Debian GNU/kFreeBSD</a> !</div>

<p>Following the recommendations from my <a href="/en/sec/firewall/linux-firewall-icmpv6/">article</a> about
the rules to be put in place to allow or block ICMPv6 messages, here are the adequate rules for PF, for *BSD that use Packet Filter, including OpenBSD:</p>

<div class="tab-info i-warning">Warning</div><div class="alert alert-warning" role="alert">NEVER forget that the entire IPv6 stack, unlike IPv4, really relies on ICMPv6; thus, a bad configuration of ICMPv6 will certainly prevent all or part of the IPv6 stream from working correctly, or as expected!</div>

<h2 id="manage-icmpv6">Manage ICMPv6</h2>
<h3 id="drop">Drop</h3>
<p>These ICMPv6 types are to be rejected absolutely:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">icmp6_block</span> <span style="color:#5bc4bf">=</span> <span style="color:#48b685">&#34;{ 100 101 127 138 139 140 144 145 146 147 150 200 201 }&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">block drop quick log on egress inet6 proto icmp6 icmp6-type $icmp6_block</span>
</span></span></code></pre></div>
<div class="tab-info i-info">Info</div><div class="alert alert-info" role="alert"><p><strong>Be Carefull:</strong> About Mobile IPv6 messages types (144 → 147), there are needed to assist mobility, depending mobile nodes normally on the site, or foreign mobile nodes roaming <em>(tablets, laptops, …)</em>…</p>
<p>If necessary, you may need to pass and limit them.</p>
</div>

<hr>
<h3 id="pass">Pass</h3>
<p>⇒ For a station:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">icmp6_auth</span> <span style="color:#5bc4bf">=</span> <span style="color:#48b685">&#34;{ unreach toobig timex paramprob echoreq echoreq neighbradv neighbrsol }&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">pass out quick on egress inet6 proto icmp6 from any       to ff02::2 icmp6-type { routersol, listenrepv2 }</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">pass in  quick on egress inet6 proto icmp6 from fe80::/64 to ff02::1 icmp6-type { routeradv }</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">pass     quick on egress inet6 proto icmp6 icmp6-type $icmp6_auth allow-opts</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">pass in  quick on egress inet6 proto icmp6 from any to egress icmp6-type redir allow-opts</span>
</span></span></code></pre></div><p><strong>Explainations</strong></p>
<ul>
<li>
<p>The first rule define all authorized ICMPv6 types required, a minimum.</p>
</li>
<li>
<p>The second rule authorize only in output:</p>
<ul>
<li>solicitations messages from the station to the routeur — <code>ff02::2</code> is the local multicast address of any router</li>
<li>and the &ldquo;Multicast Listener Report Message v2&rdquo; messages, <code>listenrepv2</code> - both ICMPv6 types are needed to communicate locally</li>
<li>this rule is the first because the station announce that it needs a routable address to communicate with others.</li>
</ul>
</li>
<li>
<p>The third rule authorize only in input messages from router  — type 143 — to the station&rsquo;s local node — <code>ff02::1</code>.</p>
<ul>
<li>this is the router&rsquo;s reply to the previous request from the station</li>
</ul>
</li>
<li>
<p>The 4th rule autorise in input, and output all defined types from the first rule — the macro <code>$icmp6_auth</code>.</p>
</li>
<li>
<p>The 5 rule authorize only in input the redirection ICMPv6 message.</p>
</li>
</ul>
<p>⇒ Router case:</p>
<p>Pour débuter, faisons simplement :</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">icmp6_auth</span> <span style="color:#5bc4bf">=</span> <span style="color:#48b685">&#34;{ echoreq echoreq neighbradv neighbrsol }&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">pass in  quick on egress inet6 proto icmp6 icmp6-type { routersol, listenrepv2 }</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">pass out quick on egress inet6 proto icmp6 icmp6-type routeradv</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">pass     quick on egress inet6 proto icmp6 icmp6-type $icmp6_auth</span>
</span></span></code></pre></div><h4 id="limit">Limit</h4>
<p>To limit ICMPv6 traffic, PF can be use
<abbr title="Stateful Tracking Options">STO</abbr>
.</p>
<p>To continue the example above, using the <code>max-src-conn-rate</code> option:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">icmp6_auth</span> <span style="color:#5bc4bf">=</span> <span style="color:#48b685">&#34;{ unreach toobig timex paramprob echoreq neighbradv neighbrsol }&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">icmp6_sto</span>  <span style="color:#5bc4bf">=</span> <span style="color:#48b685">&#34;( max-src-conn-rate 100/10 )&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">pass out quick on egress inet6 proto icmp6 from any       to ff02::2 icmp6-type { routersol, listenrepv2 }</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">pass in  quick on egress inet6 proto icmp6 from fe80::/64 to ff02::1 icmp6-type { routeradv }</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">pass     quick on egress inet6 proto icmp6 icmp6-type $icmp6_auth allow-opts $icmp6_sto</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">pass in  quick on egress inet6 proto icmp6 from any to egress icmp6-type redir allow-opts $icmp6_sto</span>
</span></span></code></pre></div><h4 id="more-paranoid">More paranoid</h4>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">icmp6_auth</span> <span style="color:#5bc4bf">=</span> <span style="color:#48b685">&#34;{ unreach, toobig, timex code 0, timex code 1, paramprob code 1, paramprob code 2, echorep, echoreq, neighbradv, neighbrsol }&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">icmp6_out</span>  <span style="color:#5bc4bf">=</span> <span style="color:#48b685">&#34;{ echorep, echoreq, neighbradv, neighbrsol }&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">icmp6_sto</span>  <span style="color:#5bc4bf">=</span> <span style="color:#48b685">&#34;( max-src-conn-rate 100/10 )&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">pass out quick on egress inet6 proto icmp6 from any       to ff02::2 icmp6-type { routersol, listenrepv2 }</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">pass in  quick on egress inet6 proto icmp6 from fe80::/64 to ff02::1 icmp6-type { routeradv, redir }</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">pass     quick on egress inet6 proto icmp6 icmp6-type $icmp6_auth allow-opts $icmp6_sto</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">pass out quick on egress inet6 proto from egress to any icmp6 icmp6-type $icmp6_out allow-opts $icmp6_sto</span>
</span></span></code></pre></div><p><strong>Explainations</strong></p>
<ul>
<li>
<p><code>icmp6_auth</code>: manage only what it&rsquo;s absolutely necessary.</p>
</li>
<li>
<p><code>icmp6_out</code>: to manage echoes replies — the &ldquo;Pong&rdquo; ­— from routeur and
neighbours messages</p>
</li>
<li>
<p>in the first <code>in</code> rule, we have added management of redirection messages to a shorter route, only from a router to our machine. to our machine. <br>
<strong>WARNING</strong>: allowing redirection messages message in any other way will cause security problems, to the extent that that it seems advisable to remove them from the firewall context!</p>
</li>
</ul>
<hr>
<p>⇒ Router case:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">icmp6_auth</span> <span style="color:#5bc4bf">=</span> <span style="color:#48b685">&#34;{ unreach toobig timex paramprob echoreq echoreq neighbradv neighbrsol }&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">icmp6_sto</span>  <span style="color:#5bc4bf">=</span> <span style="color:#48b685">&#34;( max-src-conn-rate 100/10 )&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">pass in  quick on egress inet6 proto icmp6 icmp6-type { routersol, listenrepv2 }</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">pass out quick on egress inet6 proto icmp6 icmp6-type { routeradv, redir }</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">pass     quick on egress inet6 proto icmp6 icmp6-type $icmp6_auth allow-opts $icmp6_sto</span>
</span></span></code></pre></div><h2 id="documentation">Documentation</h2>
<ul>
<li><a href="https://en.wikipedia.org/wiki/Link-local_address" title="Wikipedia Article: Link-local_address">
    Link-local_address
    <sup><abbr class="is-italic" title="Wikipedia">WP</abbr></sup>
</a>
</li>
</ul>
<hr>
]]></content><summary>Example of rules to manage ICMPv6 with the firewall Packet-Filter (PF)</summary><published>2019-10-31T12:38:55+02:00</published><updated>2026-10-02T15:49:57+02:00</updated></entry><entry><id>tag:doc.huc.fr.eu.org,2019-06-19:/en/dev/python/env-python-openbsd</id><link href="https://it-log.fr.eu.org/en/dev/python/env-python-openbsd/" rel="alternate" type="text/html"/><title>Python: virtual environment on OpenBSD</title><author><name>Stéphane HUC</name></author><category term="Python" scheme="https://it-log.fr.eu.org/en/tags/python/"/><category term="Environnement" scheme="https://it-log.fr.eu.org/en/tags/environnement/"/><category term="OpenBSD" scheme="https://it-log.fr.eu.org/en/tags/openbsd/"/><content type="html"><![CDATA[<h2 id="description">Description</h2>
<ul>
<li>OS : OpenBSD 6.x</li>
</ul>
<p>Since OpenBSD 6.0, <code>wxallowed</code> is a mount option, by default on <code>/usr/local</code>.</p>
<p>If the partition has this option, the software is allowed to run from that
partition, otherwise it won&rsquo;t be able to run and will issue a <code>W^X</code> violation
message:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:$ dmesg | grep wxallowed
</span></span><span style="display:flex;"><span>/home/hs/.local/share/virtualenvs/mybeautifullproject-q1koN8ay/bin/python3<span style="color:#5bc4bf">(</span>26392<span style="color:#5bc4bf">)</span>: W^X binary outside wxallowed mountpoint
</span></span></code></pre></div><p>In fact, since only <code>/usr/local</code> had this actived option, if you attempt
to run one program, by example on your <code>$HOME</code>, this one will not execute.<br>
That&rsquo;s the whole problem with Python environments that need to work in
your home directory.</p>
<p>Here the problem with <code>virtualenv</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>:<span style="color:#ef6155">$</span> virtualenv mybeautifullproject
</span></span><span style="display:flex;"><span>Using base prefix <span style="color:#48b685">&#39;/usr/local&#39;</span>
</span></span><span style="display:flex;"><span>New python executable <span style="color:#5bc4bf">in</span> <span style="color:#ef6155">$</span>HOME<span style="color:#5bc4bf">/</span>python<span style="color:#5bc4bf">/</span>mybeautifullproject<span style="color:#5bc4bf">.</span>py<span style="color:#5bc4bf">/</span>mybeautifullproject<span style="color:#5bc4bf">/</span>bin<span style="color:#5bc4bf">/</span>python3
</span></span><span style="display:flex;"><span>Also creating executable <span style="color:#5bc4bf">in</span> <span style="color:#ef6155">$</span>HOME<span style="color:#5bc4bf">/</span>python<span style="color:#5bc4bf">/</span>mybeautifullproject<span style="color:#5bc4bf">.</span>py<span style="color:#5bc4bf">/</span>mybeautifullproject<span style="color:#5bc4bf">/</span>bin<span style="color:#5bc4bf">/</span>python
</span></span><span style="display:flex;"><span>ERROR: The executable <span style="color:#ef6155">$</span>HOME<span style="color:#5bc4bf">/</span>python<span style="color:#5bc4bf">/</span>mybeautifullproject<span style="color:#5bc4bf">.</span>py<span style="color:#5bc4bf">/</span>mybeautifullproject<span style="color:#5bc4bf">/</span>bin<span style="color:#5bc4bf">/</span>python3 could <span style="color:#5bc4bf">not</span> be run: [Errno <span style="color:#f99b15">13</span>] Permission denied: <span style="color:#48b685">&#39;$HOME/python/mybeautifullproject.py/mybeautifullproject/bin/python</span>
</span></span></code></pre></div><p>Egual for <code>pipenv</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>:<span style="color:#ef6155">$</span> pipenv install requests
</span></span><span style="display:flex;"><span><span style="color:#ef6155">Warning</span>: the environment variable LANG <span style="color:#5bc4bf">is</span> <span style="color:#5bc4bf">not</span> set<span style="color:#ef6155">!</span>
</span></span><span style="display:flex;"><span>We recommend setting this <span style="color:#5bc4bf">in</span> <span style="color:#5bc4bf">~/.</span>profile (<span style="color:#5bc4bf">or</span> equivalent) <span style="color:#815ba4">for</span> proper expected behavior<span style="color:#5bc4bf">.</span>
</span></span><span style="display:flex;"><span>Creating a virtualenv <span style="color:#815ba4">for</span> this project<span style="color:#ef6155">…</span>
</span></span><span style="display:flex;"><span>Pipfile: <span style="color:#ef6155">$</span>HOME<span style="color:#5bc4bf">/</span>python<span style="color:#5bc4bf">/</span>mybeautifullproject<span style="color:#5bc4bf">.</span>py<span style="color:#5bc4bf">/</span>Pipfile
</span></span><span style="display:flex;"><span>Using <span style="color:#5bc4bf">/</span>usr<span style="color:#5bc4bf">/</span>local<span style="color:#5bc4bf">/</span>bin<span style="color:#5bc4bf">/</span>python3 (<span style="color:#f99b15">3.6.8</span>) to create virtualenv<span style="color:#ef6155">…</span>
</span></span><span style="display:flex;"><span><span style="color:#ef6155">⠇</span> Creating virtual environment<span style="color:#5bc4bf">...</span>Already using interpreter <span style="color:#5bc4bf">/</span>usr<span style="color:#5bc4bf">/</span>local<span style="color:#5bc4bf">/</span>bin<span style="color:#5bc4bf">/</span>python3
</span></span><span style="display:flex;"><span>Using base prefix <span style="color:#48b685">&#39;/usr/local&#39;</span>
</span></span><span style="display:flex;"><span>New python executable <span style="color:#5bc4bf">in</span> <span style="color:#ef6155">$</span>HOME<span style="color:#5bc4bf">/.</span>local<span style="color:#5bc4bf">/</span>share<span style="color:#5bc4bf">/</span>virtualenvs<span style="color:#5bc4bf">/</span>mybeautifullproject<span style="color:#5bc4bf">.</span>py<span style="color:#5bc4bf">-</span>oFlnu9vD<span style="color:#5bc4bf">/</span>bin<span style="color:#5bc4bf">/</span>python3
</span></span><span style="display:flex;"><span>Also creating executable <span style="color:#5bc4bf">in</span> <span style="color:#ef6155">$</span>HOME<span style="color:#5bc4bf">/.</span>local<span style="color:#5bc4bf">/</span>share<span style="color:#5bc4bf">/</span>virtualenvs<span style="color:#5bc4bf">/</span>mybeautifullproject<span style="color:#5bc4bf">.</span>py<span style="color:#5bc4bf">-</span>oFlnu9vD<span style="color:#5bc4bf">/</span>bin<span style="color:#5bc4bf">/</span>python
</span></span><span style="display:flex;"><span>ERROR: The executable <span style="color:#ef6155">$</span>HOME<span style="color:#5bc4bf">/.</span>local<span style="color:#5bc4bf">/</span>share<span style="color:#5bc4bf">/</span>virtualenvs<span style="color:#5bc4bf">/</span>mybeautifullproject<span style="color:#5bc4bf">.</span>py<span style="color:#5bc4bf">-</span>oFlnu9vD<span style="color:#5bc4bf">/</span>bin<span style="color:#5bc4bf">/</span>python3 could <span style="color:#5bc4bf">not</span> be run: [Errno <span style="color:#f99b15">13</span>] Permission denied: <span style="color:#48b685">&#39;$HOME/.local/share/virtualenvs/mybeautifullproject.py-oFlnu9vD/bin/python3&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ef6155">✘</span> Failed creating virtual environment
</span></span><span style="display:flex;"><span>[pipenv<span style="color:#5bc4bf">.</span>exceptions<span style="color:#5bc4bf">.</span>VirtualenvCreationException]:   File <span style="color:#48b685">&#34;$HOME/.local/lib/python3.6/site-packages/pipenv/cli/command.py&#34;</span>, line <span style="color:#f99b15">254</span>, <span style="color:#5bc4bf">in</span> install
</span></span><span style="display:flex;"><span>[pipenv<span style="color:#5bc4bf">.</span>exceptions<span style="color:#5bc4bf">.</span>VirtualenvCreationException]:       editable_packages<span style="color:#5bc4bf">=</span>state<span style="color:#5bc4bf">.</span>installstate<span style="color:#5bc4bf">.</span>editables,
</span></span><span style="display:flex;"><span>[pipenv<span style="color:#5bc4bf">.</span>exceptions<span style="color:#5bc4bf">.</span>VirtualenvCreationException]:   File <span style="color:#48b685">&#34;$HOME/.local/lib/python3.6/site-packages/pipenv/core.py&#34;</span>, line <span style="color:#f99b15">1741</span>, <span style="color:#5bc4bf">in</span> do_install
</span></span><span style="display:flex;"><span>[pipenv<span style="color:#5bc4bf">.</span>exceptions<span style="color:#5bc4bf">.</span>VirtualenvCreationException]:       pypi_mirror<span style="color:#5bc4bf">=</span>pypi_mirror,
</span></span><span style="display:flex;"><span>[pipenv<span style="color:#5bc4bf">.</span>exceptions<span style="color:#5bc4bf">.</span>VirtualenvCreationException]:   File <span style="color:#48b685">&#34;$HOME/.local/lib/python3.6/site-packages/pipenv/core.py&#34;</span>, line <span style="color:#f99b15">574</span>, <span style="color:#5bc4bf">in</span> ensure_project
</span></span><span style="display:flex;"><span>[pipenv<span style="color:#5bc4bf">.</span>exceptions<span style="color:#5bc4bf">.</span>VirtualenvCreationException]:       pypi_mirror<span style="color:#5bc4bf">=</span>pypi_mirror,
</span></span><span style="display:flex;"><span>[pipenv<span style="color:#5bc4bf">.</span>exceptions<span style="color:#5bc4bf">.</span>VirtualenvCreationException]:   File <span style="color:#48b685">&#34;$HOME/.local/lib/python3.6/site-packages/pipenv/core.py&#34;</span>, line <span style="color:#f99b15">506</span>, <span style="color:#5bc4bf">in</span> ensure_virtualenv
</span></span><span style="display:flex;"><span>[pipenv<span style="color:#5bc4bf">.</span>exceptions<span style="color:#5bc4bf">.</span>VirtualenvCreationException]:       python<span style="color:#5bc4bf">=</span>python, site_packages<span style="color:#5bc4bf">=</span>site_packages, pypi_mirror<span style="color:#5bc4bf">=</span>pypi_mirror
</span></span><span style="display:flex;"><span>[pipenv<span style="color:#5bc4bf">.</span>exceptions<span style="color:#5bc4bf">.</span>VirtualenvCreationException]:   File <span style="color:#48b685">&#34;$HOME/.local/lib/python3.6/site-packages/pipenv/core.py&#34;</span>, line <span style="color:#f99b15">935</span>, <span style="color:#5bc4bf">in</span> do_create_virtualenv
</span></span><span style="display:flex;"><span>[pipenv<span style="color:#5bc4bf">.</span>exceptions<span style="color:#5bc4bf">.</span>VirtualenvCreationException]:       extra<span style="color:#5bc4bf">=</span>[crayons<span style="color:#5bc4bf">.</span>blue(<span style="color:#48b685">&#34;</span><span style="color:#f99b15">{0}</span><span style="color:#48b685">&#34;</span><span style="color:#5bc4bf">.</span>format(c<span style="color:#5bc4bf">.</span>err)),]
</span></span><span style="display:flex;"><span>[pipenv<span style="color:#5bc4bf">.</span>exceptions<span style="color:#5bc4bf">.</span>VirtualenvCreationException]:
</span></span><span style="display:flex;"><span>Failed to create virtual environment<span style="color:#5bc4bf">.</span>
</span></span></code></pre></div><h2 id="configuration">Configuration</h2>
<p>One only little system change will make our lives easier:</p>
<ul>
<li>create a folder user into <code>/usr/local</code>, i.e.:<br>
<code>:# mkdir -p /usr/local/${my_user}/python</code></li>
<li>chown user and group rights:<br>
<code>:# chown -R ${my_user}:wheel /usr/local/${my_user}</code></li>
<li>create symbolic link:<br>
<code>:# ln -s /usr/local/${my_user}/python $home/python</code></li>
</ul>
<p><em>Of course, replace <code>${my_user}</code> by your id!</em> ;-)</p>
<p>If you use <code>pipenv</code>, you need to create a new folder and symlink; read the
<a href="/en/dev/python/env-python-openbsd/#tldr">TL;DR</a> below.</p>
<h2 id="tldr">TL;DR</h2>
<p>Replace <code>${my_user}</code> by your session id!</p>
<p>⇒ For <strong>virtualenv</strong>:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:# mkdir -p /usr/local/<span style="color:#f99b15">${</span><span style="color:#ef6155">my_user</span><span style="color:#f99b15">}</span>/python
</span></span><span style="display:flex;"><span>:# chown -R <span style="color:#f99b15">${</span><span style="color:#ef6155">my_user</span><span style="color:#f99b15">}</span>:wheel /usr/local/<span style="color:#f99b15">${</span><span style="color:#ef6155">my_user</span><span style="color:#f99b15">}</span>
</span></span><span style="display:flex;"><span>:# ln -s /usr/local/<span style="color:#f99b15">${</span><span style="color:#ef6155">my_user</span><span style="color:#f99b15">}</span>/python <span style="color:#ef6155">$home</span>/python
</span></span></code></pre></div><p>⇒ For <strong>pipenv</strong>, you need to add more:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:$ mkdir /usr/local/<span style="color:#ef6155">$USER</span>/python/virtualenvs
</span></span><span style="display:flex;"><span>:$ ln -s /usr/local/<span style="color:#ef6155">$USER</span>/python/virtualenvs <span style="color:#ef6155">$HOME</span>/.local/share/virtualenvs
</span></span></code></pre></div><h2 id="documentations">Documentations</h2>
<ul>
<li>The <strong>pipenv</strong>: <a href="https://pipenv.readthedocs.io/en/latest/" rel="external">https://pipenv.readthedocs.io/en/latest/</a></li>
<li>About the mount option <strong>wxallowed</strong>: <a href="https://www.openbsd.org/faq/upgrade60.html" rel="external">EN</a></li>
</ul>
<h2 id="aknowledgements">Aknowledgements</h2>
<ul>
<li>This article would not exists without <a href="https://ybad.name/sdj.html" rel="external">Xavier</a>…</li>
<li>and, this other <a href="https://deftly.net/posts/2017-10-12-using-cabal-on-openbsd.html" rel="external">article</a>: &ldquo;<em><strong>Using cabal on OpenBSD</strong></em>&rdquo;</li>
</ul>
<hr>
<hr>
]]></content><summary>How to use virtuals environments Python on OpenBSD with W^X security.</summary><published>2019-06-19T12:03:33+02:00</published><updated>2026-10-02T15:49:57+02:00</updated></entry><entry><id>tag:doc.huc.fr.eu.org,2019-06-19:/en/sys/openbsd/env-python-openbsd</id><link href="https://it-log.fr.eu.org/en/sys/openbsd/env-python-openbsd/" rel="alternate" type="text/html"/><title>Python: virtual environment on OpenBSD</title><author><name>Stéphane HUC</name></author><category term="Python" scheme="https://it-log.fr.eu.org/en/tags/python/"/><category term="Environment" scheme="https://it-log.fr.eu.org/en/tags/environment/"/><category term="OpenBSD" scheme="https://it-log.fr.eu.org/en/tags/openbsd/"/><content type="html"><![CDATA[<h2 id="description">Description</h2>
<ul>
<li>OS : OpenBSD 6.x</li>
</ul>
<p>Since OpenBSD 6.0, <code>wxallowed</code> is a mount option, by default on <code>/usr/local</code>.</p>
<p>If the partition has this option, the software is allowed to run from that
partition, otherwise it won&rsquo;t be able to run and will issue a <code>W^X</code> violation
message:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:$ dmesg | grep wxallowed
</span></span><span style="display:flex;"><span>/home/hs/.local/share/virtualenvs/mybeautifullproject-q1koN8ay/bin/python3<span style="color:#5bc4bf">(</span>26392<span style="color:#5bc4bf">)</span>: W^X binary outside wxallowed mountpoint
</span></span></code></pre></div><p>In fact, since only <code>/usr/local</code> had this actived option, if you attempt
to run one program, by example on your <code>$HOME</code>, this one will not execute.<br>
That&rsquo;s the whole problem with Python environments that need to work in
your home directory.</p>
<p>Here the problem with <code>virtualenv</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:$ virtualenv mybeautifullproject
</span></span><span style="display:flex;"><span>Using base prefix <span style="color:#48b685">&#39;/usr/local&#39;</span>
</span></span><span style="display:flex;"><span>New python executable in <span style="color:#ef6155">$HOME</span>/python/mybeautifullproject.py/mybeautifullproject/bin/python3
</span></span><span style="display:flex;"><span>Also creating executable in <span style="color:#ef6155">$HOME</span>/python/mybeautifullproject.py/mybeautifullproject/bin/python
</span></span><span style="display:flex;"><span>ERROR: The executable <span style="color:#ef6155">$HOME</span>/python/mybeautifullproject.py/mybeautifullproject/bin/python3 could not be run: <span style="color:#5bc4bf">[</span>Errno 13<span style="color:#5bc4bf">]</span> Permission denied: <span style="color:#ef6155">&#39;</span><span style="color:#ef6155">$HOME</span>/python/mybeautifullproject.py/mybeautifullproject/bin/python
</span></span></code></pre></div><p>Egual for <code>pipenv</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:$ pipenv install requests
</span></span><span style="display:flex;"><span>Warning: the environment variable LANG is not set!
</span></span><span style="display:flex;"><span>We recommend setting this in ~/.profile <span style="color:#5bc4bf">(</span>or equivalent<span style="color:#5bc4bf">)</span> <span style="color:#815ba4">for</span> proper expected behavior.
</span></span><span style="display:flex;"><span>Creating a virtualenv <span style="color:#815ba4">for</span> this project…
</span></span><span style="display:flex;"><span>Pipfile: <span style="color:#ef6155">$HOME</span>/python/mybeautifullproject.py/Pipfile
</span></span><span style="display:flex;"><span>Using /usr/local/bin/python3 <span style="color:#5bc4bf">(</span>3.6.8<span style="color:#5bc4bf">)</span> to create virtualenv…
</span></span><span style="display:flex;"><span>⠇ Creating virtual environment...Already using interpreter /usr/local/bin/python3
</span></span><span style="display:flex;"><span>Using base prefix <span style="color:#48b685">&#39;/usr/local&#39;</span>
</span></span><span style="display:flex;"><span>New python executable in <span style="color:#ef6155">$HOME</span>/.local/share/virtualenvs/mybeautifullproject.py-oFlnu9vD/bin/python3
</span></span><span style="display:flex;"><span>Also creating executable in <span style="color:#ef6155">$HOME</span>/.local/share/virtualenvs/mybeautifullproject.py-oFlnu9vD/bin/python
</span></span><span style="display:flex;"><span>ERROR: The executable <span style="color:#ef6155">$HOME</span>/.local/share/virtualenvs/mybeautifullproject.py-oFlnu9vD/bin/python3 could not be run: <span style="color:#5bc4bf">[</span>Errno 13<span style="color:#5bc4bf">]</span> Permission denied: <span style="color:#48b685">&#39;$HOME/.local/share/virtualenvs/mybeautifullproject.py-oFlnu9vD/bin/python3&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>✘ Failed creating virtual environment
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">[</span>pipenv.exceptions.VirtualenvCreationException<span style="color:#5bc4bf">]</span>:   File <span style="color:#48b685">&#34;</span><span style="color:#ef6155">$HOME</span><span style="color:#48b685">/.local/lib/python3.6/site-packages/pipenv/cli/command.py&#34;</span>, line 254, in install
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">[</span>pipenv.exceptions.VirtualenvCreationException<span style="color:#5bc4bf">]</span>:       <span style="color:#ef6155">editable_packages</span><span style="color:#5bc4bf">=</span>state.installstate.editables,
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">[</span>pipenv.exceptions.VirtualenvCreationException<span style="color:#5bc4bf">]</span>:   File <span style="color:#48b685">&#34;</span><span style="color:#ef6155">$HOME</span><span style="color:#48b685">/.local/lib/python3.6/site-packages/pipenv/core.py&#34;</span>, line 1741, in do_install
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">[</span>pipenv.exceptions.VirtualenvCreationException<span style="color:#5bc4bf">]</span>:       <span style="color:#ef6155">pypi_mirror</span><span style="color:#5bc4bf">=</span>pypi_mirror,
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">[</span>pipenv.exceptions.VirtualenvCreationException<span style="color:#5bc4bf">]</span>:   File <span style="color:#48b685">&#34;</span><span style="color:#ef6155">$HOME</span><span style="color:#48b685">/.local/lib/python3.6/site-packages/pipenv/core.py&#34;</span>, line 574, in ensure_project
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">[</span>pipenv.exceptions.VirtualenvCreationException<span style="color:#5bc4bf">]</span>:       <span style="color:#ef6155">pypi_mirror</span><span style="color:#5bc4bf">=</span>pypi_mirror,
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">[</span>pipenv.exceptions.VirtualenvCreationException<span style="color:#5bc4bf">]</span>:   File <span style="color:#48b685">&#34;</span><span style="color:#ef6155">$HOME</span><span style="color:#48b685">/.local/lib/python3.6/site-packages/pipenv/core.py&#34;</span>, line 506, in ensure_virtualenv
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">[</span>pipenv.exceptions.VirtualenvCreationException<span style="color:#5bc4bf">]</span>:       <span style="color:#ef6155">python</span><span style="color:#5bc4bf">=</span>python, <span style="color:#ef6155">site_packages</span><span style="color:#5bc4bf">=</span>site_packages, <span style="color:#ef6155">pypi_mirror</span><span style="color:#5bc4bf">=</span>pypi_mirror
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">[</span>pipenv.exceptions.VirtualenvCreationException<span style="color:#5bc4bf">]</span>:   File <span style="color:#48b685">&#34;</span><span style="color:#ef6155">$HOME</span><span style="color:#48b685">/.local/lib/python3.6/site-packages/pipenv/core.py&#34;</span>, line 935, in do_create_virtualenv
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">[</span>pipenv.exceptions.VirtualenvCreationException<span style="color:#5bc4bf">]</span>:       <span style="color:#ef6155">extra</span><span style="color:#5bc4bf">=[</span>crayons.blue<span style="color:#5bc4bf">(</span><span style="color:#48b685">&#34;{0}&#34;</span>.format<span style="color:#5bc4bf">(</span>c.err<span style="color:#5bc4bf">))</span>,<span style="color:#5bc4bf">]</span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">[</span>pipenv.exceptions.VirtualenvCreationException<span style="color:#5bc4bf">]</span>:
</span></span><span style="display:flex;"><span>Failed to create virtual environment.
</span></span></code></pre></div><h2 id="configuration">Configuration</h2>
<p>One only little system change will make our lives easier:</p>
<ul>
<li>create a folder user into <code>/usr/local</code>, i.e.:<br>
<code># mkdir -p /usr/local/${my_user}/python</code></li>
<li>chown user and group rights:<br>
<code># chown -R ${my_user}:wheel /usr/local/${my_user}</code></li>
<li>create symbolic link:<br>
<code># ln -s /usr/local/${my_user}/python $home/python</code></li>
</ul>
<p><em>Of course, replace <code>${my_user}</code> by your id!</em> ;-)</p>
<p>If you use <code>pipenv</code>, you need to create a new folder and symlink; read the
<a href="/en/sys/openbsd/env-python-openbsd/#tldr">TL;DR</a> below.</p>
<h2 id="tldr">TL;DR</h2>
<p>Replace <code>${my_user}</code> by your session id!</p>
<p>⇒ For <strong>virtualenv</strong>:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:# mkdir -p /usr/local/<span style="color:#f99b15">${</span><span style="color:#ef6155">my_user</span><span style="color:#f99b15">}</span>/python
</span></span><span style="display:flex;"><span>:# chown -R <span style="color:#f99b15">${</span><span style="color:#ef6155">my_user</span><span style="color:#f99b15">}</span>:wheel /usr/local/<span style="color:#f99b15">${</span><span style="color:#ef6155">my_user</span><span style="color:#f99b15">}</span>
</span></span><span style="display:flex;"><span>:# ln -s /usr/local/<span style="color:#f99b15">${</span><span style="color:#ef6155">my_user</span><span style="color:#f99b15">}</span>/python <span style="color:#ef6155">$home</span>/python
</span></span></code></pre></div><p>⇒ For <strong>pipenv</strong>, you need to add more:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:$ mkdir /usr/local/<span style="color:#ef6155">$USER</span>/python/virtualenvs
</span></span><span style="display:flex;"><span>:$ ln -s /usr/local/<span style="color:#ef6155">$USER</span>/python/virtualenvs <span style="color:#ef6155">$HOME</span>/.local/share/virtualenvs
</span></span></code></pre></div><h2 id="documentations">Documentations</h2>
<ul>
<li>The <strong>pipenv</strong>: <a href="https://pipenv.readthedocs.io/en/latest/" rel="external">https://pipenv.readthedocs.io/en/latest/</a></li>
<li>About the mount option <strong>wxallowed</strong>: <a href="https://www.openbsd.org/faq/upgrade60.html" rel="external">EN</a></li>
</ul>
<h2 id="aknowledgements">Aknowledgements</h2>
<ul>
<li>This article would not exists without <a href="https://ybad.name/sdj.html" rel="external">Xavier</a>…</li>
<li>and, this other <a href="https://deftly.net/posts/2017-10-12-using-cabal-on-openbsd.html" rel="external">article</a>: &ldquo;<em><strong>Using cabal on OpenBSD</strong></em>&rdquo;</li>
</ul>
<hr>
<hr>
]]></content><summary>How to use virtuals environments Python on OpenBSD with W^X security.</summary><published>2019-06-19T12:03:33+02:00</published><updated>2026-10-02T15:49:57+02:00</updated></entry><entry><id>tag:doc.huc.fr.eu.org,2019-05-02:/en/web/nextcloud/nextcloud-php-chroot</id><link href="https://it-log.fr.eu.org/en/web/nextcloud/nextcloud-php-chroot/" rel="alternate" type="text/html"/><title>(tip) Nextcloud PHP Chroot OpenBSD</title><author><name>Stéphane HUC</name></author><category term="Nextcloud" scheme="https://it-log.fr.eu.org/en/tags/nextcloud/"/><category term="chroot" scheme="https://it-log.fr.eu.org/en/tags/chroot/"/><category term="OpenBSD" scheme="https://it-log.fr.eu.org/en/tags/openbsd/"/><category term="tip" scheme="https://it-log.fr.eu.org/en/tags/tip/"/><content type="html"><![CDATA[<h2 id="error-invalid-data-directory">Error: Invalid data directory</h2>
<p>Under OpenBSD, Web service and PHP are under chroot. In fact, the command <code>occ</code> can not run!</p>
<p>When you try, we get this message:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>Your data directory is invalid
</span></span><span style="display:flex;"><span>Ensure there is a file called <span style="color:#48b685">&#34;.ocdata&#34;</span> in the root of the data directory.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>Cannot create <span style="color:#48b685">&#34;data&#34;</span> directory
</span></span><span style="display:flex;"><span>This can usually be fixed by giving the webserver write access to the root
</span></span><span style="display:flex;"><span>directory.
</span></span><span style="display:flex;"><span>See https://docs.nextcloud.com/server/16/go.php?to<span style="color:#5bc4bf">=</span>admin-dir_permissions
</span></span></code></pre></div><p><strong>To resolve this problem is very easy!</strong></p>
<p>Edit the file config <code>nextcloud/config/config.php</code>, to modify the value of
<code>datadirectory</code>, as:</p>
<p><code>'datadirectory' =&gt; ((php_sapi_name() == 'cli') ? '/var/www' : '') . '/htdocs/data',</code></p>
<p>Of course, the <code>/htdocs/data</code> directory must correspond to your real case.</p>
<p>Now, you can use without problem the <code>occ</code> command.</p>
<p>After, dont forget to delete yours modifications before going to the web
interface, otherwise you will not to be able to connect!</p>
<h3 id="tldr">TL;DR</h3>
<p>KiSS:</p>
<ul>
<li>To &ldquo;enable&rdquo; occ: <code>sed -i -e 's#/htdocs#/var/www/htdocs#' nextcloud/config/config.php</code></li>
<li>To &ldquo;disable&rdquo; occ: <code>sed -i -e 's#/var/www/htdocs#/htdocs#' nextcloud/config/config.php</code></li>
</ul>
<hr>
<h2 id="acknowledgement">Acknowledgement</h2>
<p>I would liket to thank <a href="https://chargen.one/h3artbl33d/fixing-nextcloud-on-openbsd-with-a-chroot" rel="external">@h3artbl33d</a>
who found this tips…</p>
<hr>
]]></content><summary>Howto resolve the problem for occ command Nextcloud, under chroot OpenBSD</summary><published>2019-05-02T23:11:15+01:00</published><updated>2026-10-02T15:49:57+02:00</updated></entry><entry><id>tag:doc.huc.fr.eu.org,2018-11-03:/en/sys/openbsd/smtpd-config-auth</id><link href="https://it-log.fr.eu.org/en/sys/openbsd/smtpd-config-auth/" rel="alternate" type="text/html"/><title>OpenBSD: configure smtpd.conf to auth email client (≥ v6.4)</title><author><name>Stéphane HUC</name></author><category term="OpenBSD" scheme="https://it-log.fr.eu.org/en/tags/openbsd/"/><category term="smtpd" scheme="https://it-log.fr.eu.org/en/tags/smtpd/"/><category term="auth" scheme="https://it-log.fr.eu.org/en/tags/auth/"/><category term="client" scheme="https://it-log.fr.eu.org/en/tags/client/"/><category term="mail" scheme="https://it-log.fr.eu.org/en/tags/mail/"/><content type="html"><![CDATA[<h2 id="description">Description</h2>
<p><strong>How to config your machine to send mail by terminal/console, on OpenBSD,
on SMTP server with a required authentication?</strong></p>
<h2 id="introduction">Introduction</h2>
<p><strong>OpenSMTPD</strong> is a free implementation of the SMTP protocol, as
defined in <a href="https://www.rfc-editor.org/info/rfc5321" title="RFC Editor: Information on RFC 5321">RFC 5321</a>
, with some additional standard extensions.
It allows the machines to exchange mail.</p>
<p>Informations:</p>
<ul>
<li>Website: <a href="https://www.opensmtpd.org" rel="external">https://www.opensmtpd.org</a></li>
<li>OS: OpenBSD <del>6.4</del> → <strong>7.8</strong></li>
</ul>
<p><em>Effectively tested with <a href="https://gandi.net" rel="external">Gandi</a>, and the association <a href="https://lautre.net" rel="external">L&rsquo;autre.net</a>,
and finally on my &ldquo;owners&rdquo; MX</em>.</p>
<h2 id="installation">Installation</h2>
<p>Since OpenBSD 6.4, inton the base system, we have the new version of
OpenSMTPD.</p>
<p>To start the service: <code>:# rcctl start smtpd</code></p>
<p>A small clarification on files:</p>
<ul>
<li>the config file is: <code>/etc/mail/smtpd.conf</code>.</li>
<li>the logfile is: <code>/var/log/maillog</code>.</li>
</ul>
<h2 id="configuration">Configuration</h2>
<p>To send an email at one SMTP server require an authentication, as Gandi,
it&rsquo;s necessary to first create a secret file with the good rights on your
system, and to set the config file.</p>
<p>The manpage show us on <a href="https://man.openbsd.org/smtpd.conf#EXAMPLES" rel="external">example</a>:</p>
<h3 id="file-secrets">File secrets</h3>
<p>Create the needed secret file: <code>:# touch /etc/mail/secrets</code></p>
<p>Put the secured rights:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:# chmod <span style="color:#f99b15">640</span> /etc/mail/secrets
</span></span><span style="display:flex;"><span>:# chown root:_smtpd /etc/mail/secrets
</span></span></code></pre></div><p>Now, it&rsquo;s necessary to write those informations: <br>
<code>identifiant username:password</code> <br>
<span class="red">Do Not Write TEXTUALLY this information</span>
,
replace with:</p>
<ul>
<li><code>identifiant</code>: your choosed id — <em>this will use later on your config file</em>.
<em>(e.g.: as <strong>perso</strong>)</em></li>
<li><code>username</code>: usually, your email.</li>
<li><code>password</code>: the password for your email identification.</li>
</ul>

<div class="tab-info i-warning">Warning</div><div class="alert alert-warning" role="alert"><p>It&rsquo;s possible to (re?)name the secrets file as you want, and put in other
place on your system.</p>
<p>It&rsquo;s better put rights <code>0400</code> on this secrets file.</p>
<p>Even, it&rsquo;s possible for the service to access at your secrets file, with
your personal rights as <code>$USER:$USER</code>, it&rsquo;s better to put the right group
<code>_smtpd</code>.</p>
</div>

<h3 id="file-smtpdconf">File <code>smtpd.conf</code></h3>
<p>Now, we modify the config file <code>/etc/mail/smtpd.conf</code>.</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#776e71">#   $OpenBSD: smtpd.conf,v 1.14 2019/11/26 20:14:38 gilles Exp $</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># This is the smtpd server system-wide configuration file.</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># See smtpd.conf(5) for more information.</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">table aliases file:/etc/mail/aliases</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">table secrets file:/etc/mail/secrets</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">queue compression</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># To accept external mail, replace with: listen on all</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">## add on 6.7</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">listen on socket</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">listen on lo0</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">action &#34;local_mail&#34; mbox alias &lt;aliases&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">action &#34;unbound&#34; relay host smtp+tls://identifiant@server auth &lt;secrets&gt; mail-from &#34;@your-domain.tld&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># Uncomment the following to accept external mail for domain &#34;example.org&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># match from any for domain &#34;example.org&#34; action &#34;local&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">### 6.6 writings</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#match for local action &#34;local_mail&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#match for any action &#34;unbound&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">### 6.7 writings</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">match from local for local action &#34;local_mail&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">match from local for any action &#34;outbound&#34;</span>
</span></span></code></pre></div><hr>
<p><strong>Explainations</strong></p>
<p>So compared to the original version, we added:</p>
<ul>
<li>the line <code>table secrets</code>: it call the secrets file
— <em>write your custom filename</em>.</li>
<li>the line <code>action unbound</code>: to define the necessary action to send emails
to the SMTP server.
<ul>
<li>NOTE about <code>identifiant@serveur</code>:
<ul>
<li>you have to replace the string <code>identifiant</code> by your created.
<em>(as wroted above: <strong>perso</strong>)</em>.</li>
<li>and too, to replace the <code>serveur</code> by the name of SMTP server.</li>
</ul>
</li>
<li>the string <a href="https://man.openbsd.org/smtpd.conf#host" rel="external"><code>smtp+tls</code></a> is
the used protocol to connect at the SMTP server. <br>
others protocols are:
<ul>
<li><code>lmtp</code>: to connect on a
<abbr title="Local Mail Transfer Protocol">LMTP</abbr>
 session.</li>
<li><code>smtp</code>: to attempt a connection with a STARTTLS session, if
possible.</li>
<li><code>smtp+tls</code>: to force the connection on a STARTTLS session.</li>
<li><code>smtp+notls</code>: to use a plain text SMTP session without TLS.</li>
<li><code>smtps</code>: to force the connexion via
<abbr title="Transport Layer Secure">TLS</abbr>

— <em>default port: 465</em></li>
<li>with no specified protocol, the connection will be done on the
default port: 25.</li>
</ul>
</li>
<li>the string <a href="https://man.openbsd.org/smtpd.conf#auth" rel="external"><code>auth</code></a>: to
specify the secret table.</li>
<li>the string <a href="https://man.openbsd.org/smtpd.conf#mail_-from" rel="external"><code>mail-from</code></a>:
to specify the domain name to use.</li>
<li>the line <code>match … action &quot;relay&quot;</code>: this is the action that will be
triggered to send the emails.</li>
</ul>
</li>
</ul>
<h4 id="changes-on-67">Changes on 6.7</h4>
<p>OpenBSD 6.7 makes minor syntax changes:</p>
<ul>
<li>add <code>listen on socket</code> <em>
<a class="" href="https://man.openbsd.org/smtpd.conf.5#listen~2" title="OpenBSD Manual Page Server for: smtpd.conf">smtpd.conf(5)#listen~2</a>
</em></li>
<li>modification of match actions for the <strong>local</strong> queue manager
<em>
<a class="" href="https://man.openbsd.org/smtpd.conf.5#match" title="OpenBSD Manual Page Server for: smtpd.conf">smtpd.conf(5)#match</a>
</em>: <br>
<code>match from local for local action &quot;local_mail&quot;</code> <br>
<code>match from local for any action &quot;outbound&quot;</code> \</li>
</ul>
<h4 id="changes-on-66">Changes on 6.6</h4>
<p>The syntax of the action names has changed slightly between versions 6.4
and 6.6:</p>
<ul>
<li><code>local</code> becomes <code>local_mail</code></li>
<li><code>relay</code> becomes <code>unbound</code></li>
</ul>
<h3 id="aliases">aliases</h3>
<p>About aliases system:</p>
<p>It is interesting to manage the related alias <code>root</code> account or
even that of your main user…</p>
<p>Edit the file <code>/etc/mail/aliases</code>, with rights admin. <br>
At the end of file, modify <code>root</code> with your desired address email. <br>
Do the same for your system user. ;)</p>
<p>And, do not forget to reload the aliases base, with the command
<code>newaliases</code>!</p>
<h2 id="utilisation">Utilisation</h2>

<div class="tab-info i-warning">Warning</div><div class="alert alert-warning" role="alert"><p>Before restart the <strong>opensmtpd</strong> service, we need to test the config file:
<br> <code># smtpd -n</code> \</p>
<p>If the result is: <code>configuration OK</code> <br>
that&rsquo;s folk!</p>
<p>Otherwise, re-edit the file, at the line indicated first!</p>
</div>

<p>Now, restart the service:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#776e71"># rcctl restart smtpd</span>
</span></span><span style="display:flex;"><span>smtpd<span style="color:#5bc4bf">(</span>ok<span style="color:#5bc4bf">)</span>
</span></span><span style="display:flex;"><span>smtpd<span style="color:#5bc4bf">(</span>ok<span style="color:#5bc4bf">)</span>
</span></span></code></pre></div><p>The log will display messages, as-is: <br>
<code>Apr  3 07:17:05 sh1 smtpd[68810]: info: OpenSMTPD 7.0.0 starting</code></p>
<p>Too, think to use the controller <code>smtpctl</code>… see the manpage <strong>smtpctl.8</strong>.</p>
<h3 id="send">Send</h3>
<p>So:</p>
<ul>
<li><code>echo &quot;Test to send email on $(hostname); date: $(date)&quot; | mail -s &quot;Email test&quot; email</code></li>
<li>or, <code>echo &quot;Test to send email on $(hostname); date: $(date)&quot; | mail -s &quot;Email test&quot; root</code></li>
</ul>
<p>For all cases, the log will display messages, as instance:</p>
<pre tabindex="0"><code class="language-log" data-lang="log">Apr  3 07:20:20 sh1 smtpd[56183]: 2cda1df4efff97f2 mta connecting address=smtp+tls://89.234.141.148:587 host=mail2.automario.eu
Apr  3 07:20:20 sh1 smtpd[56183]: 2cda1df4efff97f2 mta connected
Apr  3 07:20:21 sh1 smtpd[56183]: 2cda1df4efff97f2 mta tls ciphers=TLSv1.3:AEAD-CHACHA20-POLY1305-SHA256:256
Apr  3 07:20:21 sh1 smtpd[56183]: 2cda1df4efff97f2 mta cert-check result=&#34;valid&#34; fingerprint=&#34;SHA256:17af91bcb27a530cc278cd8be90551593bee38ebaf6ade68053a508b14a8f817&#34;
Apr  3 07:20:21 sh1 smtpd[56183]: 2cda1df4efff97f2 mta delivery evpid=4138560f4bd626cf from=&lt;***@huc.fr.eu.org&gt; to=&lt;***@stephane-huc.net&gt; rcpt=&lt;-&gt; source=&#34;46.23.90.29&#34; relay=&#34;89.234.141.148 (mail2.automario.eu)&#34; delay=1s result=&#34;Ok&#34; stat=&#34;250 2.0.0 eb1a48cf Message accepted for delivery&#34;
</code></pre><h2 id="errors">Errors</h2>
<p>See, below, the possible commons errors:</p>
<h3 id="error-authentication-failed">Error: authentication failed</h3>
<p>Check again your <code>username</code>, <code>password</code> id wrote on your
<a href="/en/sys/openbsd/smtpd-config-auth/#file-secrets">secret file</a>!</p>
<h3 id="error-cannot-parse-smarthost">Error: Cannot parse smarthost</h3>
<p>This message means the SMTP service can&rsquo;t figure out the strings <code>identifiant@serveur</code>
on your action rule.</p>
<p>Check your entries:</p>
<ul>
<li>your string <code>table secrets</code> need to match with the good secret filename!</li>
<li>your strings <code>identifiant username:password</code> in your secret file.</li>
<li>have you replace correctly the string <code>identifiant</code> on the config file?</li>
<li>too, for the string <code>serveur</code>: make sure the SMTP server name exists!</li>
</ul>
<h3 id="error-sender-address-rejected-domain-not-found">Error: Sender address rejected: Domain not found</h3>
<p>This message means the SMTP service can&rsquo;t match with the desired domain name.</p>
<p>The tips: use the param <a href="https://man.openbsd.org/smtpd.conf#mail_-from" rel="external">mail-from</a> in
your action rule, to target the good domain name, as:  <br>
<code>mail-from &quot;@votre-domaine.tld&quot;</code> <br>
<strong>Do Not forget the symbol <code>@</code>.</strong></p>
<h2 id="documentations">Documentations</h2>
<p>The SMTP protocol is define by RFC 5321 :</p>

<h3 id="rfc-5321">RFC 5321</h3>
<dl class="rfc">
	<dt>IETF Tools</dt>
	<dd>
		<a href="https://tools.ietf.org/html/rfc5321" title="RFC 5321: HTML format">HTML</a>,
		<a href="https://tools.ietf.org/pdf/rfc5321" title="RFC 5321: PDF format">PDF</a>,
		<a href="https://tools.ietf.org/rfc/rfc5321.txt" title="RFC 5321: TXT format">TXT</a>
	</dd>
	<dt>RFC Editor</dt>
	<dd>
		<a href="https://www.rfc-editor.org/rfc/rfc5321.html" title="RFC 5321: HTML format">HTML</a>,
		<a href="https://www.rfc-editor.org/rfc/pdfrfc/rfc5321.txt.pdf" title="RFC 5321: PDF format">PDF</a>,
		<a href="https://www.rfc-editor.org/rfc/rfc5321.txt" title="RFC 5321: TXT format">TXT</a>
	</dd>
</dl>

<h3 id="manpages">Manpages</h3>
<ul>
<li>
<a class="man" href="https://man.openbsd.org/smtpd.conf.5" title="OpenBSD Manual Page Server for: smtpd.conf">smtpd.conf(5)</a>
, 
<a class="man" href="https://man.openbsd.org/smtpctl.8" title="OpenBSD Manual Page Server for: smtpctl">smtpctl(8)</a>
</li>
</ul>
<h3 id="others-informations">Others informations</h3>
<ul>
<li>See the <a href="https://www.openbsd.org/faq/upgrade64.html" rel="external">new changes syntaxe with the OpenSMTPD v6.4</a></li>
</ul>
<hr>
<hr>
]]></content><summary>Howto config the SMTPD service for a required authentication mail on OpenBSD (≥ v6.4)</summary><published>2018-11-03T21:38:54+01:00</published><updated>2026-10-02T15:49:57+02:00</updated></entry><entry><id>tag:doc.huc.fr.eu.org,2018-03-22:/en/sys/openbsd/stubby</id><link href="https://it-log.fr.eu.org/en/sys/openbsd/stubby/" rel="alternate" type="text/html"/><title>Stubby: DoT DNS client on OpenBSD (EXPERIMENTAL)</title><author><name>Stéphane HUC</name></author><category term="OpenBSD" scheme="https://it-log.fr.eu.org/en/tags/openbsd/"/><category term="stubby" scheme="https://it-log.fr.eu.org/en/tags/stubby/"/><category term="experimental" scheme="https://it-log.fr.eu.org/en/tags/experimental/"/><category term="DNS" scheme="https://it-log.fr.eu.org/en/tags/dns/"/><category term="DoT" scheme="https://it-log.fr.eu.org/en/tags/dot/"/><category term="DNSSEC" scheme="https://it-log.fr.eu.org/en/tags/dnssec/"/><content type="html"><![CDATA[<h2 id="description">Description</h2>
<p><a href="https://github.com/getdnsapi/stubby" rel="external">Stubby</a> is a DNS client, using secure
protocol <em>(<abbr title="DNS-over-TLS">DoT</abbr>
)</em>.
This encrypts DNS queries sent from your machine to a DNS resolver, or an
authoritative DNS server to increase the confidentiality.
It can request queries according DNSSEC protocol, too.</p>

<div class="tab-info i-warning">Warning</div><div class="alert alert-warning" role="alert"><p>Warning: it does not act as DNS cache resolver, nor as an authoritative DNS
server; it&rsquo;s only a DNS client!</p>
<p>In addition, there is no package, nor port on OpenBSD stable.
Hence is the reason of title &ldquo;EXPERIMENTAL&rdquo;. We&rsquo;re going to retrieve sources,
compil, install and configure them.</p>
</div>

<h2 id="installation">Installation</h2>
<p>The <strong>stubby</strong> client is/will be installed on OpenBSD stable.</p>
<ul>
<li>at this day, now: 6.3</li>
</ul>
<h3 id="prerequisite">Prerequisite</h3>
<ul>
<li><code>OpenSSL</code> : install by default</li>
<li><code>Libyaml</code> : to install…</li>
<li><code>autoconf</code>, <code>automake</code> : to install to configure, and build before installation.</li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:# pkg_add autoconf automake libyaml
</span></span><span style="display:flex;"><span>quirks-2.414 signed on 2018-03-28T14:24:37Z
</span></span><span style="display:flex;"><span>Ambiguous: choose package <span style="color:#815ba4">for</span> autoconf
</span></span><span style="display:flex;"><span>a       0: &lt;None&gt;
</span></span><span style="display:flex;"><span>        1: autoconf-2.13p4
</span></span><span style="display:flex;"><span>        2: autoconf-2.52p6
</span></span><span style="display:flex;"><span>        3: autoconf-2.54p5
</span></span><span style="display:flex;"><span>        4: autoconf-2.56p4
</span></span><span style="display:flex;"><span>        5: autoconf-2.57p4
</span></span><span style="display:flex;"><span>        6: autoconf-2.58p5
</span></span><span style="display:flex;"><span>        7: autoconf-2.59p5
</span></span><span style="display:flex;"><span>        8: autoconf-2.60p5
</span></span><span style="display:flex;"><span>        9: autoconf-2.61p5
</span></span><span style="display:flex;"><span>        10: autoconf-2.62p2
</span></span><span style="display:flex;"><span>        11: autoconf-2.63p1
</span></span><span style="display:flex;"><span>        12: autoconf-2.64p1
</span></span><span style="display:flex;"><span>        13: autoconf-2.65p1
</span></span><span style="display:flex;"><span>        14: autoconf-2.67p1
</span></span><span style="display:flex;"><span>        15: autoconf-2.68p1
</span></span><span style="display:flex;"><span>        16: autoconf-2.69p2
</span></span><span style="display:flex;"><span>Your choice: <span style="color:#f99b15">16</span>
</span></span><span style="display:flex;"><span>Ambiguous: choose package <span style="color:#815ba4">for</span> automake
</span></span><span style="display:flex;"><span>a       0: &lt;None&gt;
</span></span><span style="display:flex;"><span>        1: automake-1.10.3p8
</span></span><span style="display:flex;"><span>        2: automake-1.11.6p2
</span></span><span style="display:flex;"><span>        3: automake-1.12.6p1
</span></span><span style="display:flex;"><span>        4: automake-1.13.4p1
</span></span><span style="display:flex;"><span>        5: automake-1.14.1p0
</span></span><span style="display:flex;"><span>        6: automake-1.15.1
</span></span><span style="display:flex;"><span>        7: automake-1.4.6p5
</span></span><span style="display:flex;"><span>        8: automake-1.8.5p9
</span></span><span style="display:flex;"><span>        9: automake-1.9.6p12
</span></span><span style="display:flex;"><span>Your choice: <span style="color:#f99b15">6</span>
</span></span></code></pre></div><p>Then, we will follow the official installation recommandations from <a href="https://dnsprivacy.org/wiki/pages/viewpage.action?pageId=3145786" rel="external">sources</a>, by adapting them to OpenBSD, step by step.</p>
<h3 id="download">Download</h3>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:$ git clone https://github.com/getdnsapi/getdns.git
</span></span><span style="display:flex;"><span>:$ cd getdns
</span></span><span style="display:flex;"><span>:$ git checkout develop
</span></span></code></pre></div><p>The second command <code>git</code> permits us to get/obtain the most recent sources .</p>
<h3 id="configuration">Configuration</h3>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:$ git submodule update --init
</span></span><span style="display:flex;"><span>:$ libtoolize -ci
</span></span><span style="display:flex;"><span>:$ export <span style="color:#ef6155">AUTOCONF_VERSION</span><span style="color:#5bc4bf">=</span>2.69
</span></span><span style="display:flex;"><span>:$ export <span style="color:#ef6155">AUTOMAKE_VERSION</span><span style="color:#5bc4bf">=</span>1.15
</span></span><span style="display:flex;"><span>:$ autoreconf -fi
</span></span><span style="display:flex;"><span>:$ mkdir build <span style="color:#5bc4bf">&amp;&amp;</span> cd build
</span></span><span style="display:flex;"><span>:$ ../configure --prefix<span style="color:#5bc4bf">=</span>/usr/local --without-libidn --enable-stub-only --with-stubby
</span></span></code></pre></div><h3 id="compilation">Compilation</h3>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#48b685">`</span>:$ make
</span></span><span style="display:flex;"><span><span style="color:#48b685">`</span>:# make install
</span></span></code></pre></div><p>Of course, if you had configured <em>
<a class="man" href="https://man.openbsd.org/doas" title="OpenBSD Manual Page Server for: doas">doas</a>
</em>, you can executed the
ultimate command, as:<br>
<code>:$ doas make install</code></p>
<h3 id="resolvconf">resolv.conf</h3>
<p>It&rsquo;s necessary to modify your <code>/etc/resolv.conf</code> file in order to communicate
directly with stubby:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#06b6ef">nameserver 127.0.0.1</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">nameserver ::1</span>
</span></span></code></pre></div><h3 id="stubbyyml">stubby.yml</h3>
<p>The stubby&rsquo;s configuration file is: <code>/usr/local/etc/stubby/stubby.yml</code>.</p>
<p>You can create your personal, as <code>~/.stubby.yml</code>. It will be read in first.</p>
<h2 id="execution">Execution</h2>
<p>To execute <strong>stubby</strong>, run as:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:# stubby
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">[</span>12:57:39.896254<span style="color:#5bc4bf">]</span> STUBBY: Read config from file /usr/local/etc/stubby/stubby.yml
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">[</span>12:57:39.898479<span style="color:#5bc4bf">]</span> STUBBY: DNSSEC Validation is OFF
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">[</span>12:57:39.898585<span style="color:#5bc4bf">]</span> STUBBY: Transport list is:
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">[</span>12:57:39.898617<span style="color:#5bc4bf">]</span> STUBBY:   - TLS
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">[</span>12:57:39.898681<span style="color:#5bc4bf">]</span> STUBBY: Privacy Usage Profile is Strict <span style="color:#5bc4bf">(</span>Authentication required<span style="color:#5bc4bf">)</span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">[</span>12:57:39.898713<span style="color:#5bc4bf">]</span> STUBBY: <span style="color:#5bc4bf">(</span>NOTE a Strict Profile only applies when TLS is the ONLY transport!!<span style="color:#5bc4bf">)</span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">[</span>12:57:39.898749<span style="color:#5bc4bf">]</span> STUBBY: Starting DAEMON....
</span></span></code></pre></div><p>Some interesting informations, about flags:</p>
<ul>
<li><code>-C</code>: to specify other configuration file.</li>
<li><code>-g</code>: to run in background mode.</li>
<li><code>-i</code>: to check the configuration!</li>
<li><code>-l</code>: to log. Actually, the output is only on the standard <code>stdout</code>!</li>
</ul>
<h3 id="test">Test</h3>
<p>We use <code>dig</code>:</p>
<p>⇒ IPv4:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:$ dig @127.0.0.1 www.gandi.net
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>; &lt;&lt;&gt;&gt; DiG 9.4.2-P2 &lt;&lt;&gt;&gt; @127.0.0.1 www.gandi.net
</span></span><span style="display:flex;"><span>; <span style="color:#5bc4bf">(</span><span style="color:#f99b15">1</span> server found<span style="color:#5bc4bf">)</span>
</span></span><span style="display:flex;"><span>;; global options:  printcmd
</span></span><span style="display:flex;"><span>;; Got answer:
</span></span><span style="display:flex;"><span>;; -&gt;&gt;HEADER<span style="color:#48b685">&lt;&lt;- opco</span>de: QUERY, status: NOERROR, id: <span style="color:#f99b15">40041</span>
</span></span><span style="display:flex;"><span>;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 4, ADDITIONAL: <span style="color:#f99b15">0</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>;; QUESTION SECTION:
</span></span><span style="display:flex;"><span>;www.gandi.net.                 IN      A
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>;; ANSWER SECTION:
</span></span><span style="display:flex;"><span>www.gandi.net.          <span style="color:#f99b15">21583</span>   IN      CNAME   prod.gandi.map.fastly.net.
</span></span><span style="display:flex;"><span>prod.gandi.map.fastly.net. <span style="color:#f99b15">3600</span> IN      A       151.101.37.103
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>;; AUTHORITY SECTION:
</span></span><span style="display:flex;"><span>fastly.net.             <span style="color:#f99b15">3600</span>    IN      NS      ns1.fastly.net.
</span></span><span style="display:flex;"><span>fastly.net.             <span style="color:#f99b15">3600</span>    IN      NS      ns2.fastly.net.
</span></span><span style="display:flex;"><span>fastly.net.             <span style="color:#f99b15">3600</span>    IN      NS      ns3.fastly.net.
</span></span><span style="display:flex;"><span>fastly.net.             <span style="color:#f99b15">3600</span>    IN      NS      ns4.fastly.net.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>;; Query time: <span style="color:#f99b15">1888</span> msec
</span></span><span style="display:flex;"><span>;; SERVER: 127.0.0.1#53<span style="color:#5bc4bf">(</span>127.0.0.1<span style="color:#5bc4bf">)</span>
</span></span><span style="display:flex;"><span>;; WHEN: Thu Mar <span style="color:#f99b15">22</span> 14:15:51 <span style="color:#f99b15">2018</span>
</span></span><span style="display:flex;"><span>;; MSG SIZE  rcvd: <span style="color:#f99b15">155</span>
</span></span></code></pre></div><p>⇒ IPv6:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>:$ dig @::1 www.gandi.net
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>; &lt;&lt;&gt;&gt; DiG 9.4.2-P2 &lt;&lt;&gt;&gt; @::1 www.gandi.net
</span></span><span style="display:flex;"><span>; <span style="color:#5bc4bf">(</span><span style="color:#f99b15">1</span> server found<span style="color:#5bc4bf">)</span>
</span></span><span style="display:flex;"><span>;; global options:  printcmd
</span></span><span style="display:flex;"><span>;; Got answer:
</span></span><span style="display:flex;"><span>;; -&gt;&gt;HEADER<span style="color:#48b685">&lt;&lt;- opco</span>de: QUERY, status: NOERROR, id: <span style="color:#f99b15">24688</span>
</span></span><span style="display:flex;"><span>;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 4, ADDITIONAL: <span style="color:#f99b15">4</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>;; QUESTION SECTION:
</span></span><span style="display:flex;"><span>;www.gandi.net.                 IN      A
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>;; ANSWER SECTION:
</span></span><span style="display:flex;"><span>www.gandi.net.          <span style="color:#f99b15">84574</span>   IN      CNAME   prod.gandi.map.fastly.net.
</span></span><span style="display:flex;"><span>prod.gandi.map.fastly.net. <span style="color:#f99b15">3600</span> IN      A       151.101.85.103
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>;; AUTHORITY SECTION:
</span></span><span style="display:flex;"><span>fastly.net.             <span style="color:#f99b15">168207</span>  IN      NS      ns4.fastly.net.
</span></span><span style="display:flex;"><span>fastly.net.             <span style="color:#f99b15">168207</span>  IN      NS      ns2.fastly.net.
</span></span><span style="display:flex;"><span>fastly.net.             <span style="color:#f99b15">168207</span>  IN      NS      ns1.fastly.net.
</span></span><span style="display:flex;"><span>fastly.net.             <span style="color:#f99b15">168207</span>  IN      NS      ns3.fastly.net.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>;; ADDITIONAL SECTION:
</span></span><span style="display:flex;"><span>ns1.fastly.net.         <span style="color:#f99b15">3600</span>    IN      A       23.235.32.32
</span></span><span style="display:flex;"><span>ns2.fastly.net.         <span style="color:#f99b15">3600</span>    IN      A       104.156.80.32
</span></span><span style="display:flex;"><span>ns3.fastly.net.         <span style="color:#f99b15">3600</span>    IN      A       23.235.36.32
</span></span><span style="display:flex;"><span>ns4.fastly.net.         <span style="color:#f99b15">3600</span>    IN      A       104.156.84.32
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>;; Query time: <span style="color:#f99b15">1614</span> msec
</span></span><span style="display:flex;"><span>;; SERVER: ::1#53<span style="color:#5bc4bf">(</span>::1<span style="color:#5bc4bf">)</span>
</span></span><span style="display:flex;"><span>;; WHEN: Thu Mar <span style="color:#f99b15">22</span> 14:16:40 <span style="color:#f99b15">2018</span>
</span></span><span style="display:flex;"><span>;; MSG SIZE  rcvd: <span style="color:#f99b15">219</span>
</span></span></code></pre></div><hr>
]]></content><summary>Stubby installation experimentation, a DoT and DNSSEC client, on OpenBSD (6.3).</summary><published>2018-03-22T14:21:09+01:00</published><updated>2026-10-02T15:49:57+02:00</updated></entry><entry><id>tag:doc.huc.fr.eu.org,2017-07-29:/en/dev/bash/function-array-key-exists</id><link href="https://it-log.fr.eu.org/en/dev/bash/function-array-key-exists/" rel="alternate" type="text/html"/><title>Bash: function array_key_exists()</title><author><name>Stéphane HUC</name></author><category term="Bash" scheme="https://it-log.fr.eu.org/en/tags/bash/"/><category term="array" scheme="https://it-log.fr.eu.org/en/tags/array/"/><content type="html"><![CDATA[<h2 id="description">Description</h2>
<p><code>array_key_exists()</code>: check if key exists into array!</p>
<p><em>Equivalent to the PHP Function <a href="http://php.net/manual/en/function.array-key-exists.php" rel="external">PHP array_key_exists</a>()</em></p>
<h2 id="source-code">Source Code</h2>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#815ba4">function</span> array_key_exists<span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>   <span style="color:#776e71"># equivalent to PHP array_key_exists</span>
</span></span><span style="display:flex;"><span>   <span style="color:#776e71"># call: array_key_exists key array</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>   local <span style="color:#ef6155">key</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#ef6155">$1</span><span style="color:#48b685">&#34;</span> <span style="color:#ef6155">IFS</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34; &#34;</span>; shift; read -a array <span style="color:#5bc4bf">&lt;&lt;&lt;</span> <span style="color:#48b685">&#34;</span><span style="color:#ef6155">$@</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>   <span style="color:#815ba4">if</span> <span style="color:#5bc4bf">[[</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">array</span>[<span style="color:#ef6155">$key</span>]<span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> <span style="color:#5bc4bf">]]</span>; <span style="color:#815ba4">then</span> <span style="color:#815ba4">return</span> 0; <span style="color:#815ba4">else</span> <span style="color:#815ba4">return</span> 1; <span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>   unset array key IFS
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span></code></pre></div><h3 id="parameters">Parameters</h3>
<ul>
<li><code>key</code> is the searched key</li>
<li><code>haystack</code> is the array where to search</li>
</ul>
<h3 id="return-values">Return Values</h3>
<ul>
<li>Returns <code>0</code> if the <code>key</code> found into <code>haystack</code>; considere this value as <code>TRUE</code></li>
<li>Otherwise, returns <code>1</code>: considere this value as <code>FALSE</code></li>
</ul>
<h2 id="example">Example</h2>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>declare -a <span style="color:#ef6155">color</span><span style="color:#5bc4bf">=(</span><span style="color:#48b685">&#34;blue&#34;</span>, <span style="color:#48b685">&#34;red&#34;</span>, <span style="color:#48b685">&#34;green&#34;</span>, <span style="color:#48b685">&#34;grey&#34;</span><span style="color:#5bc4bf">)</span>;
</span></span><span style="display:flex;"><span><span style="color:#ef6155">key</span><span style="color:#5bc4bf">=</span><span style="color:#f99b15">1</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#815ba4">if</span> array_key_exists <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">key</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">color</span>[@]<span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>; <span style="color:#815ba4">then</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>   echo <span style="color:#48b685">&#34;key: </span><span style="color:#f99b15">${</span><span style="color:#ef6155">key</span><span style="color:#f99b15">}</span><span style="color:#48b685"> exists!&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#815ba4">else</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>   echo <span style="color:#48b685">&#34;This key: </span><span style="color:#f99b15">${</span><span style="color:#ef6155">key</span><span style="color:#f99b15">}</span><span style="color:#48b685"> not exists!&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#815ba4">fi</span>
</span></span></code></pre></div><hr>
]]></content><summary>Function bash array_key_exists(), equivalent to PHP</summary><published>2017-07-29T18:56:36+01:00</published><updated>2026-10-02T15:49:57+02:00</updated></entry><entry><id>tag:doc.huc.fr.eu.org,2017-07-29:/en/dev/bash/function-array-search</id><link href="https://it-log.fr.eu.org/en/dev/bash/function-array-search/" rel="alternate" type="text/html"/><title>Bash : function array_search()</title><author><name>Stéphane HUC</name></author><category term="Bash" scheme="https://it-log.fr.eu.org/en/tags/bash/"/><category term="array" scheme="https://it-log.fr.eu.org/en/tags/array/"/><content type="html"><![CDATA[<h2 id="description">Description</h2>
<p><code>array_search()</code>: Searches the array for a given value and returns the
corresponding key if successful</p>
<p><em>Equivalent to the
<a href="http://php.net/manual/en/function.array-search.php" rel="external">PHP array_search</a> function.</em></p>
<h2 id="source-code">Source Code</h2>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#815ba4">function</span> array_search<span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#776e71"># equivalent to PHP array_search</span>
</span></span><span style="display:flex;"><span>    <span style="color:#776e71"># call: array_search needle array</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    local <span style="color:#ef6155">needle</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;</span><span style="color:#ef6155">$1</span><span style="color:#48b685">&#34;</span> <span style="color:#ef6155">IFS</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34; &#34;</span>; shift; read -a array <span style="color:#5bc4bf">&lt;&lt;&lt;</span> <span style="color:#48b685">&#34;</span><span style="color:#ef6155">$@</span><span style="color:#48b685">&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">for</span> <span style="color:#5bc4bf">((</span> <span style="color:#ef6155">i</span><span style="color:#5bc4bf">=</span>0; i &lt; <span style="color:#f99b15">${#</span><span style="color:#ef6155">array</span>[*]<span style="color:#f99b15">}</span>; i++ <span style="color:#5bc4bf">))</span>; <span style="color:#815ba4">do</span>
</span></span><span style="display:flex;"><span>        <span style="color:#815ba4">if</span> <span style="color:#5bc4bf">[[</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">array</span>[<span style="color:#ef6155">$i</span>]<span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> <span style="color:#5bc4bf">==</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">needle</span><span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> <span style="color:#5bc4bf">]]</span>; <span style="color:#815ba4">then</span> echo <span style="color:#48b685">&#34;</span><span style="color:#ef6155">$i</span><span style="color:#48b685">&#34;</span>; <span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">done</span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">return</span> <span style="color:#f99b15">1</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    unset array needle IFS
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span></code></pre></div><h3 id="parameters">Parameters</h3>
<ul>
<li><code>needle</code> is the searched value</li>
<li><code>haystack</code> is the array where to search</li>
</ul>
<h3 id="return-values">Return Values</h3>
<ul>
<li>Returns the key for <code>needle</code>, if is found into the array <code>haystack</code></li>
<li>Otherwise, returns <code>1</code>: considere this value as <code>FALSE</code>.</li>
</ul>
<h2 id="example">Example</h2>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>declare -a <span style="color:#ef6155">color</span><span style="color:#5bc4bf">=(</span><span style="color:#48b685">&#34;blue&#34;</span>, <span style="color:#48b685">&#34;red&#34;</span>, <span style="color:#48b685">&#34;green&#34;</span>, <span style="color:#48b685">&#34;grey&#34;</span><span style="color:#5bc4bf">)</span>;
</span></span><span style="display:flex;"><span>echo <span style="color:#48b685">&#34;</span><span style="color:#815ba4">$(</span>array_search <span style="color:#48b685">&#34;red&#34;</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">color</span>[@]<span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span><span style="color:#815ba4">)</span><span style="color:#48b685">&#34;</span>
</span></span></code></pre></div><hr>
]]></content><summary>Function bash array_search(), equivalent to PHP</summary><published>2017-07-29T18:19:29+01:00</published><updated>2026-10-02T15:49:57+02:00</updated></entry><entry><id>tag:doc.huc.fr.eu.org,2017-07-26:/en/sec/firewall/linux-firewall-icmpv6</id><link href="https://it-log.fr.eu.org/en/sec/firewall/linux-firewall-icmpv6/" rel="alternate" type="text/html"/><title>Linux: firewall ICMPv6</title><author><name>Stéphane HUC</name></author><category term="Linux" scheme="https://it-log.fr.eu.org/en/tags/linux/"/><category term="firewall" scheme="https://it-log.fr.eu.org/en/tags/firewall/"/><category term="ICMPv6" scheme="https://it-log.fr.eu.org/en/tags/icmpv6/"/><category term="Ip6tables" scheme="https://it-log.fr.eu.org/en/tags/ip6tables/"/><content type="html"><![CDATA[<h2 id="description">Description</h2>
<p><strong>Filtering ICMPv6 on Linux!</strong></p>
<p>A few hours ago, I wrote this other <a href="/en/sec/firewall/linux-firewall-icmp/">article</a>… <br>
now, it&rsquo;s time to discuss about the filtering measures to be put in place around ICMPv6.</p>
<p>I am not going to remind you why this protocol exists, nor the fact that it can be dangerous if misused; and, of course, unfortunately there will always be people who misuse it!</p>
<h2 id="manage-icmpv6">Manage ICMPv6</h2>
<h3 id="refuse">Refuse</h3>
<p>As a precaution, it is advisable to filter out all experimental codes, such as <code>100</code>, <code>101</code>, <code>200</code>, and <code>201</code>, as well as codes reserved for the future, namely codes <code>127</code> and <code>255</code>.</p>
<p>It is recommended to block the following codes:</p>
<ul>
<li><code>5</code> ⇒ <code>99</code>: unallocated error messages</li>
<li><code>100</code>, <code>101</code>: experimentals</li>
<li><code>102</code> ⇒ <code>126</code>: unallocated error messages</li>
<li><code>137</code> - Redirect Message — except in case of necessity</li>
<li><code>138</code> - Router Renumbering</li>
<li><code>139</code> - ICMP Node Information Query</li>
<li><code>140</code> - ICMP Node Information Response</li>
<li><code>144</code> - Home Agent Address Discovery Request Message</li>
<li><code>145</code> - Home Agent Address Discovery Reply Message</li>
<li><code>146</code> - Mobile Prefix Solicitation</li>
<li><code>147</code> - Mobile Prefix Advertisement</li>
<li><code>150</code> - Seamoby Experimental — except in case of necessity</li>
<li><code>154</code> ⇒ <code>199</code>: non assigned</li>
<li><code>200</code>, <code>201</code>: experimentals</li>
<li><code>202</code> ⇒ <code>254</code>: non assigned</li>
</ul>
<h3 id="limit">Limit</h3>
<p>The recommendations are to limit, in input AND in input, all those codes:</p>
<ul>
<li><code>1</code> - Destination Unreachable</li>
<li><code>4</code> - Parameter Problem Message</li>
</ul>
<p>And to limit in input only those following codes:</p>
<ul>
<li><code>2/0</code> - Packet Too Big Message</li>
<li><code>3</code> - Time Exceeded Message</li>
<li>and all other existing codes, especially:
<ul>
<li><code>128/0</code> - Echo Request message <em>(le ping)</em> -</li>
<li><code>129/0</code> - Echo reply message <em>(le pong)</em>.</li>
</ul>
</li>
</ul>
<h3 id="useful-details">Useful details</h3>
<p>For the following codes, in the corresponding RFC, the message format is specified as:</p>
<ul>
<li>
<p>all <strong>























































<span lang="en">MLD <em>(Multicast Listener Discovery)</em></span>























































</strong> codes — <code>130</code>, <code>131</code>, <code>132</code>, <code>143</code> - and <strong>MLDv2</strong> must be sent from an address whose source is an IPv6 local link, with an <code>hop limit</code> of <code>1</code></p>
<ul>
<li><em>see: <a href="/en/sec/firewall/linux-firewall-icmpv6/#rfc-2710">RFC 2710</a></em> ;
<em><code>143</code> is defined by <a href="/en/sec/firewall/linux-firewall-icmpv6/#rfc-3810">RFC 3810</a></em>.</li>
</ul>
</li>
<li>
<p>all <strong>





























































<span lang="en">ND <em>(Neighbor Discovery)</em></span>

















































</strong> codes — from <code>133</code> to <code>137</code> — must be sent with an <code>hop-limit</code> to <code>255</code></p>
<ul>
<li><em>see <a href="/en/sec/firewall/linux-firewall-icmpv6/#rfc-4861">RFC 4861</a></em>. <br>
About those codes, here are useful informations:</li>
</ul>
<ul>
<li><code>133</code> - <strong>Router Solicitation</strong> - must be sent from a source that must have an assigned IP address, or from an unspecified address if the network interface does not yet have an assigned IP address, to any router.</li>
<li><code>134</code> - <strong>Router Advertisement</strong> - must ABSOLUTELY be sent by a router, issuing a periodic router notification, or response to a router solicitation, to any multicast node or to the source address invoking the router.</li>
<li><code>135</code> - <strong>Neighbor Solicitation</strong> - must be sent from a source that must have an assigned IP address, or from an unspecified address if the network interface does not yet have an assigned IP address, to any multicast node.</li>
<li><code>136</code> - <strong>Neighbor Advertisement</strong> - must ABSOLUTELY be sent by an assigned IP address, to the source address invoking the <code>135</code> code, or to any multicast node, if there is no assigned address.</li>
<li><code>137</code> - <strong>Redirect Message</strong> - must ABSOLUTELY be sent by an assigned IP address, an IPv6 link-local, by a router to the source address that requested the redirection of the message.</li>
</ul>
</li>
<li>
<p>all <strong>

































































<span lang="en">NIQ <em>(Node Information Queries)</em></span>













































</strong> codes - <code>139</code>: <br>
<strong>ICMP Node Information Query</strong> and <code>140</code>: <strong>ICMP Node Information Response</strong> - must refuse all requests from IPv6 global addresses and should apply the use of the <code>limit</code> option. <br>
Note that there are more complex security measures…</p>
<ul>
<li><em>see: <a href="/en/sec/firewall/linux-firewall-icmpv6/#rfc-4620">RFC 4620</a></em></li>
</ul>
</li>
<li>
<p>all <strong>






























































<span lang="en">ND ID <em>(Neighbor Discovery Inverse Discovery)</em></span>
















































</strong> codes -
<code>141</code>: <strong>Inverse Neighbor Discovery Solicitation Message</strong> and
<code>142</code>: <strong>Inverse Neighbor Discovery Advertisement Message</strong> - both must have an assigned IP address as source;</p>
<ul>
<li><code>141</code> must be sent to any multicast node, whose format is <code>FF02::1</code>.</li>
<li><code>142</code> must respond only to a request of type <code>141</code>.</li>
</ul>
<ul>
<li><em>see: <a href="/en/sec/firewall/linux-firewall-icmpv6/#rfc-3122">RFC 3122</a></em></li>
</ul>
</li>
<li>
<p>all <strong>

















































































<span lang="en">SEND <em>(SEcure Neighbor Discovery)</em></span>





























</strong> codes - <code>148</code>: <strong>Certification Path Solicitation Message</strong> and <code>149</code>: <strong>Certification Path Advertisement Message</strong> - must be sent with an <code>hop-limit</code> to <code>255</code></p>
<ul>
<li><em>see: <a href="/en/sec/firewall/linux-firewall-icmpv6/#rfc-3971">RFC 3971</a></em>.</li>
</ul>
</li>
<li>
<p>all <strong>


























































<span lang="en">MRD <em>(Multicast Router Discovery)</em></span>




















































</strong> codes - from <code>151</code> to <code>153</code> must be sent from an assigned address, an IPv6 local-link, and have an <code>hop-limit</code> to <code>255</code>.</p>
<ul>
<li><em>see <a href="/en/sec/firewall/linux-firewall-icmpv6/#rfc-4286">RFC 4286</a></em></li>
</ul>
</li>
</ul>
<h2 id="examples">Examples</h2>
<h3 id="paranoid-icmpv6">Paranoid ICMPv6</h3>
<p>In paranoid mode, here are this kind of rules:</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#776e71">##ip6tables -A INPUT -p icmpv6 -m conntrack --ctstate INVALID -j DROP</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A INPUT -p icmpv6 -m conntrack --ctstate RELATED,ESTABLISHED,UNTRACKED -j ACCEPT</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A INPUT -p icmpv6 -m limit --limit 3/s --limit-burst 7 -j ACCEPT</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A INPUT -p icmpv6 --icmpv6-type echo-request -m conntrack --ctstate NEW -j ACCEPT</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A INPUT -p icmpv6 --icmpv6-type echo-request -m conntrack --ctstate NEW -j ACCEPT</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A INPUT -s fe80::/64 -p icmpv6 --icmpv6-type router-advertisement -m hl --hl-eq 255 -j ACCEPT # Type: 134</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A INPUT -p icmpv6 --icmpv6-type neighbour-solicitation -m hl --hl-eq 255 -j ACCEPT # Type: 135</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A INPUT -p icmpv6 --icmpv6-type neighbour-advertisement -m hl --hl-eq 255 -j ACCEPT # Type: 136</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A INPUT -p icmpv6 -j DROP</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">##ip6tables -A OUTPUT -p icmpv6 -m conntrack --ctstate INVALID -j DROP</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A OUTPUT -p icmpv6 -m conntrack --ctstate RELATED,ESTABLISHED,UNTRACKED -j ACCEPT</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A OUTPUT -p icmpv6 --icmpv6-type echo-request -m conntrack --ctstate NEW -j ACCEPT</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A OUTPUT -p icmpv6 --icmpv6-type echo-reply -m conntrack --ctstate NEW -j ACCEPT</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A OUTPUT -d ff02::/16 -p icmpv6 --icmpv6-type router-solicitation -j ACCEPT # Type: 133</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A OUTPUT -p icmpv6 --icmpv6-type neighbour-solicitation -j ACCEPT # Type: 135</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A OUTPUT -p icmpv6 --icmpv6-type neighbour-advertisement -j ACCEPT # Type: 136</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A OUTPUT -d ff02::/16 -p icmpv6 --icmpv6-type 143/0 -j ACCEPT # Type: 143/0</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A OUTPUT -p icmpv6 -j DROP</span>
</span></span></code></pre></div><h3 id="limit-icmp">Limit ICMP</h3>
<p>Here is an example, based on the understanding of the IETF recommendations, of ICMP limited rules, and reject all others codes with the <code>icmp6-adm-prohibited</code> messages.</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#776e71"># INPUT RULES</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -N INPUT_ICMPV6</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">##ip6tables -A INPUT_ICMPV6 -p icmpv6 -m conntrack --ctstate INVALID -j DROP</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A INPUT_ICMPV6 -p icmpv6 -m limit --limit 3/s --limit-burst 7 -j ACCEPT</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A INPUT_ICMPV6 -p icmpv6 -m conntrack --ctstate RELATED,ESTABLISHED,UNTRACKED -j ACCEPT</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A INPUT_ICMPV6 -p icmpv6 --icmpv6-type 1 -m conntrack --ctstate NEW -j ACCEPT   # destination-unreachable; Must Not Be Dropped</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A INPUT_ICMPV6 -p icmpv6 --icmpv6-type 2/0 -m conntrack --ctstate NEW -j ACCEPT   # packet too big; Must Not Be Dropped</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A INPUT_ICMPV6 -p icmpv6 --icmpv6-type 3/0 -m conntrack --ctstate NEW -j ACCEPT # time exceeded; Must Not Be Dropped</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A INPUT_ICMPV6 -p icmpv6 --icmpv6-type 3/1 -m conntrack --ctstate NEW -j ACCEPT # time exceeded; Should Not Be Dropped</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A INPUT_ICMPV6 -p icmpv6 --icmpv6-type 4/0 -m conntrack --ctstate NEW -j ACCEPT   # parameter pb: Erroneous header field encountered; Should Not Be Dropped</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A INPUT_ICMPV6 -p icmpv6 --icmpv6-type 4/1 -m conntrack --ctstate NEW -j ACCEPT   # parameter pb: Unrecognized Next Header Type encountered; Must Not Be Dropped</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A INPUT_ICMPV6 -p icmpv6 --icmpv6-type 4/2 -m conntrack --ctstate NEW -j ACCEPT   # parameter pb: Unrecognized IPv6 option encountered; Must Not Be Dropped</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A INPUT_ICMPV6 -p icmpv6 --icmpv6-type 100 -j DROP   # private experimentation</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A INPUT_ICMPV6 -p icmpv6 --icmpv6-type 101 -j DROP   # private experimentation</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A INPUT_ICMPV6 -p icmpv6 --icmpv6-type 127 -j DROP   # error messages ICMPv6</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A INPUT_ICMPV6 -p icmpv6 --icmpv6-type 128/0 -m conntrack --ctstate NEW -j ACCEPT   # ping tool: echo request message; Must Not Be Dropped</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A INPUT_ICMPV6 -p icmpv6 --icmpv6-type 129/0 -m conntrack --ctstate NEW -j ACCEPT  # ping tool: echo reply message; Must Not Be Dropped</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># link-local multicast receive notification mssg (need link-local src address, with hop-limit: 1)</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A INPUT_ICMPV6 -p icmpv6 --icmpv6-type 130/0 -s fe80::/64 -m conntrack --ctstate NEW -m hl --hl-eq 1 -j ACCEPT   # Must Not Be Dropped</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A INPUT_ICMPV6 -p icmpv6 --icmpv6-type 131/0 -s fe80::/64 -m conntrack --ctstate NEW -m hl --hl-eq 1 -j ACCEPT   # Must Not Be Dropped</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A INPUT_ICMPV6 -p icmpv6 --icmpv6-type 132/0 -s fe80::/64 -m conntrack --ctstate NEW -m hl --hl-eq 1 -j ACCEPT   # Must Not Be Dropped</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># address configuration and routeur selection mssg (received with hop limit = 255)</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">##ip6tables -A INPUT_ICMPV6 -p icmpv6 --icmpv6-type 133/0 -m hl --hl-eq 255 -j ACCEPT   # Must Not Be Dropped (only RELATED,ESTABLISHED,UNTRACKED)</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A INPUT_ICMPV6 -s fe80::/64 -p icmpv6 --icmpv6-type 134/0 -m hl --hl-eq 255 -j ACCEPT   # Must Not Be Dropped (only RELATED,ESTABLISHED,UNTRACKED)</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A INPUT_ICMPV6 -p icmpv6 --icmpv6-type 135/0 -m hl --hl-eq 255 -j ACCEPT   # Must Not Be Dropped (only RELATED,ESTABLISHED,UNTRACKED)</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A INPUT_ICMPV6 -p icmpv6 --icmpv6-type 136/0 -m hl --hl-eq 255 -j ACCEPT   # Must Not Be Dropped (only RELATED,ESTABLISHED,UNTRACKED)</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A INPUT_ICMPV6 -p icmpv6 --icmpv6-type 137/0 -j DROP   # Will Be Dropped Anyway</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A INPUT_ICMPV6 -p icmpv6 --icmpv6-type 138/0 -j DROP   # Will Be Dropped Anyway</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A INPUT_ICMPV6 -p icmpv6 --icmpv6-type 139/0 -j DROP   # Should Be Dropped Unless a Good Case Can Be Made</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A INPUT_ICMPV6 -p icmpv6 --icmpv6-type 140/0 -j DROP   # Should Be Dropped Unless a Good Case Can Be Made</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A INPUT_ICMPV6 -p icmpv6 --icmpv6-type 141/0 -d ff02::1 -m hl --hl-eq 255 -j ACCEPT   # Must Not Be Dropped (only RELATED,ESTABLISHED,UNTRACKED)</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A INPUT_ICMPV6 -p icmpv6 --icmpv6-type 142/0 -m hl --hl-eq 255 -j ACCEPT   # Must Not Be Dropped (only RELATED,ESTABLISHED,UNTRACKED)</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># link-local multicast receive notification mssg (need link-local src address, with hop-limit: 1)</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A INPUT_ICMPV6 -p icmpv6 --icmpv6-type 143 -s fe80::/64 -m conntrack --ctstate NEW -m hl --hl-eq 1 -j ACCEPT   # Must Not Be Dropped</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># needed for mobylity</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A INPUT_ICMPV6 -p icmpv6 --icmpv6-type 144/0 -j DROP  # Will Be Dropped Anyway</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A INPUT_ICMPV6 -p icmpv6 --icmpv6-type 145/0 -j DROP  # Will Be Dropped Anyway</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A INPUT_ICMPV6 -p icmpv6 --icmpv6-type 146/0 -j DROP  # Will Be Dropped Anyway</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A INPUT_ICMPV6 -p icmpv6 --icmpv6-type 147 -j DROP  # Will Be Dropped Anyway</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># SEND certificate path notification mssg (received with hop limit = 255)</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A INPUT_ICMPV6 -p icmpv6 --icmpv6-type 148 -m hl --hl-eq 255 -j ACCEPT   # Must Not Be Dropped (only RELATED,ESTABLISHED,UNTRACKED)</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A INPUT_ICMPV6 -p icmpv6 --icmpv6-type 149 -m hl --hl-eq 255 -j ACCEPT   # Must Not Be Dropped (only RELATED,ESTABLISHED,UNTRACKED)</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># multicast routeur discovery mssg (need link-local src address and hop limit = 1)</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A INPUT_ICMPV6 -p icmpv6 --icmpv6-type 151 -s fe80::/64 -m conntrack --ctstate NEW -m hl --hl-eq 1 -j ACCEPT   # Must Not Be Dropped</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A INPUT_ICMPV6 -p icmpv6 --icmpv6-type 152 -s fe80::/64 -m conntrack --ctstate NEW -m hl --hl-eq 1 -j ACCEPT   # Must Not Be Dropped</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A INPUT_ICMPV6 -p icmpv6 --icmpv6-type 153 -s fe80::/64 -m conntrack --ctstate NEW -m hl --hl-eq 1 -j ACCEPT   # Must Not Be Dropped</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A INPUT_ICMPV6 -p icmpv6 --icmpv6-type 200 -j DROP   # private experimentation</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A INPUT_ICMPV6 -p icmpv6 --icmpv6-type 201 -j DROP   # private experimentation</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A INPUT_ICMPV6 -p icmpv6 --icmpv6-type 255 -j DROP   # error messages ICMPv6</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># all others are dropped</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#ip6tables -A INPUT_ICMPV6 -p icmpv6 ! --icmpv6-type -j DROP or -j REJECT --reject-with icmp6-adm-prohibited ⇐ this type seems not correctly supported!</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A INPUT_ICMPV6 -p icmpv6 -j REJECT --reject-with no-route</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># OUTPUT RULES</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -N OUTPUT_ICMPV6</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">##ip6tables -A OUTPUT_ICMPV6 -p icmpv6 -m conntrack --ctstate INVALID -j DROP</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A OUTPUT_ICMPV6 -p icmpv6 -m conntrack --ctstate RELATED,ESTABLISHED,UNTRACKED -j ACCEPT</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A OUTPUT_ICMPV6 -p icmpv6 --icmpv6-type 1 -m conntrack --ctstate NEW -m limit --limit 3/s --limit-burst 7 -j ACCEPT   # destination-unreachable; Must Not Be Dropped</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A OUTPUT_ICMPV6 -p icmpv6 --icmpv6-type 2/0 -m conntrack --ctstate NEW -j ACCEPT   # packet too big; Must Not Be Dropped</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A OUTPUT_ICMPV6 -p icmpv6 --icmpv6-type 3/0 -m conntrack --ctstate NEW -j ACCEPT # time exceeded; Must Not Be Dropped</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A OUTPUT_ICMPV6 -p icmpv6 --icmpv6-type 3/1 -m conntrack --ctstate NEW -j ACCEPT # time exceeded; Should Not Be Dropped</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A OUTPUT_ICMPV6 -p icmpv6 --icmpv6-type 4/0 -m conntrack --ctstate NEW -m limit --limit 3/s --limit-burst 7 -j ACCEPT   # parameter pb: Erroneous header field encountered; Should Not Be Dropped</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A OUTPUT_ICMPV6 -p icmpv6 --icmpv6-type 4/1 -m conntrack --ctstate NEW -m limit --limit 3/s --limit-burst 7 -j ACCEPT   # parameter pb: Unrecognized Next Header Type encountered; Must Not Be Dropped</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A OUTPUT_ICMPV6 -p icmpv6 --icmpv6-type 4/2 -m conntrack --ctstate NEW -m limit --limit 3/s --limit-burst 7 -j ACCEPT   # parameter pb: Unrecognized IPv6 option encountered; Must Not Be Dropped</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A OUTPUT_ICMPV6 -p icmpv6 --icmpv6-type 100 -j DROP   # private experimentation</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A OUTPUT_ICMPV6 -p icmpv6 --icmpv6-type 101 -j DROP   # private experimentation</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A OUTPUT_ICMPV6 -p icmpv6 --icmpv6-type 127 -j DROP   # error messages ICMPv6</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A OUTPUT_ICMPV6 -p icmpv6 --icmpv6-type 128/0 -m conntrack --ctstate NEW -j ACCEPT   # ping tool: echo request message; Must Not Be Dropped</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A OUTPUT_ICMPV6 -p icmpv6 --icmpv6-type 129/0 -m conntrack --ctstate NEW -j ACCEPT  # ping tool: echo reply message; Must Not Be Dropped</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># link-local multicast receive notification mssg (need link-local src address, with hop-limit: 1)</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A OUTPUT_ICMPV6 -p icmpv6 --icmpv6-type 130/0 -m conntrack --ctstate NEW -m hl --hl-eq 1 -j ACCEPT   # Must Not Be Dropped</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A OUTPUT_ICMPV6 -p icmpv6 --icmpv6-type 131/0 -m conntrack --ctstate NEW -m hl --hl-eq 1 -j ACCEPT   # Must Not Be Dropped</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A OUTPUT_ICMPV6 -p icmpv6 --icmpv6-type 132/0 -m conntrack --ctstate NEW -m hl --hl-eq 1 -j ACCEPT   # Must Not Be Dropped</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># address configuration and routeur selection mssg (received with hop limit = 255)</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A OUTPUT_ICMPV6 -p icmpv6 --icmpv6-type 133/0 -d ff02::/16 -m conntrack --ctstate NEW -m hl --hl-eq 255 -j ACCEPT   # Must Not Be Dropped</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">##ip6tables -A OUTPUT_ICMPV6 -p icmpv6 --icmpv6-type 134/0 -d fe80::/64 -m hl --hl-eq 255 -j ACCEPT   # Must Not Be Dropped</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A OUTPUT_ICMPV6 -p icmpv6 --icmpv6-type 135/0 -m conntrack --ctstate NEW -m hl --hl-eq 255 -j ACCEPT   # Must Not Be Dropped</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A OUTPUT_ICMPV6 -p icmpv6 --icmpv6-type 136/0 -m conntrack --ctstate NEW -m hl --hl-eq 255 -j ACCEPT   # Must Not Be Dropped</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A OUTPUT_ICMPV6 -p icmpv6 --icmpv6-type 137/0 -j DROP   # Will Be Dropped Anyway</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A OUTPUT_ICMPV6 -p icmpv6 --icmpv6-type 138/0 -j DROP   # Will Be Dropped Anyway</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A OUTPUT_ICMPV6 -p icmpv6 --icmpv6-type 139/0 -j DROP   # Should Be Dropped Unless a Good Case Can Be Made</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A OUTPUT_ICMPV6 -p icmpv6 --icmpv6-type 140/0 -j DROP   # Should Be Dropped Unless a Good Case Can Be Made</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A OUTPUT_ICMPV6 -p icmpv6 --icmpv6-type 141/0 -d ff02::1 -m conntrack --ctstate NEW -m hl --hl-eq 255 -j ACCEPT   # Must Not Be Dropped</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A OUTPUT_ICMPV6 -p icmpv6 --icmpv6-type 142/0 -m hl --hl-eq 255 -j ACCEPT   # Must Not Be Dropped</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># link-local multicast receive notification mssg (need link-local src address, with hop-limit: 1)</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A OUTPUT_ICMPV6 -p icmpv6 --icmpv6-type 143 -d ff02::/16 -m conntrack --ctstate NEW -m hl --hl-eq 1 -j ACCEPT   # Must Not Be Dropped</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># needed for mobylity: except if the context requires it, then it will be necessary to limit them</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A OUTPUT_ICMPV6 -p icmpv6 --icmpv6-type 144/0 -j DROP  # Will Be Dropped Anyway</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A OUTPUT_ICMPV6 -p icmpv6 --icmpv6-type 145/0 -j DROP  # Will Be Dropped Anyway</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A OUTPUT_ICMPV6 -p icmpv6 --icmpv6-type 146/0 -j DROP  # Will Be Dropped Anyway</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A OUTPUT_ICMPV6 -p icmpv6 --icmpv6-type 147 -j DROP  # Will Be Dropped Anyway</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># SEND certificate path notification mssg (received with hop limit = 255)</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A OUTPUT_ICMPV6 -p icmpv6 --icmpv6-type 148 -m conntrack --ctstate NEW -m hl --hl-eq 255 -j ACCEPT   # Must Not Be Dropped</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A OUTPUT_ICMPV6 -p icmpv6 --icmpv6-type 149 -m conntrack --ctstate NEW -m hl --hl-eq 255 -j ACCEPT   # Must Not Be Dropped</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># multicast routeur discovery mssg (need link-local src address and hop limit = 1)</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A OUTPUT_ICMPV6 -p icmpv6 --icmpv6-type 151 -m conntrack --ctstate NEW -m hl --hl-eq 1 -j ACCEPT   # Must Not Be Dropped</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A OUTPUT_ICMPV6 -p icmpv6 --icmpv6-type 152 -m conntrack --ctstate NEW -m hl --hl-eq 1 -j ACCEPT   # Must Not Be Dropped</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A OUTPUT_ICMPV6 -p icmpv6 --icmpv6-type 153 -m conntrack --ctstate NEW -m hl --hl-eq 1 -j ACCEPT   # Must Not Be Dropped</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A OUTPUT_ICMPV6 -p icmpv6 --icmpv6-type 200 -j DROP   # private experimentation</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A OUTPUT_ICMPV6 -p icmpv6 --icmpv6-type 201 -j DROP   # private experimentation</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A OUTPUT_ICMPV6 -p icmpv6 --icmpv6-type 255 -j DROP   # error messages ICMPv6</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># all others are dropped</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#ip6tables -A OUTPUT_ICMPV6 -p icmpv6 ! --icmpv6-type -j DROP or -j REJECT --reject-with icmp6-adm-prohibited # ⇐ this type seems not correctly supported!</span>
</span></span><span style="display:flex;"><span><span style="color:#06b6ef">ip6tables -A OUTPUT_ICMPV6 -p icmpv6 -j REJECT --reject-with no-route</span>
</span></span></code></pre></div><h2 id="documentations">Documentations</h2>
<ul>
<li>the <a href="https://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xhtml" rel="external">ICMPv6 parameters</a></li>
<li><strong><a href="/en/sec/firewall/linux-firewall-icmpv6/#rfc-4890">RFC 4890</a></strong></li>
<li><strong><a href="/en/sec/firewall/linux-firewall-icmpv6/#rfc-5927">RFC 5927</a></strong></li>
<li><a href="https://tools.ietf.org/html/draft-ietf-opsec-icmp-filtering-04" rel="external">draft ICMP filtering</a></li>
<li><a href="https://tools.ietf.org/id/draft-ietf-v6ops-icmpv6-filtering-recs-02.txt" rel="external">draft ICMPv6 filtering</a></li>
</ul>
<hr>
<p>
<h3 id="rfc-2710">RFC 2710</h3>
<dl class="rfc">
	<dt>IETF Tools</dt>
	<dd>
		<a href="https://tools.ietf.org/html/rfc2710" title="RFC 2710: HTML format">HTML</a>,
		<a href="https://tools.ietf.org/pdf/rfc2710" title="RFC 2710: PDF format">PDF</a>,
		<a href="https://tools.ietf.org/rfc/rfc2710.txt" title="RFC 2710: TXT format">TXT</a>
	</dd>
	<dt>RFC Editor</dt>
	<dd>
		<a href="https://www.rfc-editor.org/rfc/rfc2710.html" title="RFC 2710: HTML format">HTML</a>,
		<a href="https://www.rfc-editor.org/rfc/pdfrfc/rfc2710.txt.pdf" title="RFC 2710: PDF format">PDF</a>,
		<a href="https://www.rfc-editor.org/rfc/rfc2710.txt" title="RFC 2710: TXT format">TXT</a>
	</dd>
</dl>


<h3 id="rfc-3122">RFC 3122</h3>
<dl class="rfc">
	<dt>IETF Tools</dt>
	<dd>
		<a href="https://tools.ietf.org/html/rfc3122" title="RFC 3122: HTML format">HTML</a>,
		<a href="https://tools.ietf.org/pdf/rfc3122" title="RFC 3122: PDF format">PDF</a>,
		<a href="https://tools.ietf.org/rfc/rfc3122.txt" title="RFC 3122: TXT format">TXT</a>
	</dd>
	<dt>RFC Editor</dt>
	<dd>
		<a href="https://www.rfc-editor.org/rfc/rfc3122.html" title="RFC 3122: HTML format">HTML</a>,
		<a href="https://www.rfc-editor.org/rfc/pdfrfc/rfc3122.txt.pdf" title="RFC 3122: PDF format">PDF</a>,
		<a href="https://www.rfc-editor.org/rfc/rfc3122.txt" title="RFC 3122: TXT format">TXT</a>
	</dd>
</dl>


<h3 id="rfc-3810">RFC 3810</h3>
<dl class="rfc">
	<dt>IETF Tools</dt>
	<dd>
		<a href="https://tools.ietf.org/html/rfc3810" title="RFC 3810: HTML format">HTML</a>,
		<a href="https://tools.ietf.org/pdf/rfc3810" title="RFC 3810: PDF format">PDF</a>,
		<a href="https://tools.ietf.org/rfc/rfc3810.txt" title="RFC 3810: TXT format">TXT</a>
	</dd>
	<dt>RFC Editor</dt>
	<dd>
		<a href="https://www.rfc-editor.org/rfc/rfc3810.html" title="RFC 3810: HTML format">HTML</a>,
		<a href="https://www.rfc-editor.org/rfc/pdfrfc/rfc3810.txt.pdf" title="RFC 3810: PDF format">PDF</a>,
		<a href="https://www.rfc-editor.org/rfc/rfc3810.txt" title="RFC 3810: TXT format">TXT</a>
	</dd>
</dl>


<h3 id="rfc-3971">RFC 3971</h3>
<dl class="rfc">
	<dt>IETF Tools</dt>
	<dd>
		<a href="https://tools.ietf.org/html/rfc3971" title="RFC 3971: HTML format">HTML</a>,
		<a href="https://tools.ietf.org/pdf/rfc3971" title="RFC 3971: PDF format">PDF</a>,
		<a href="https://tools.ietf.org/rfc/rfc3971.txt" title="RFC 3971: TXT format">TXT</a>
	</dd>
	<dt>RFC Editor</dt>
	<dd>
		<a href="https://www.rfc-editor.org/rfc/rfc3971.html" title="RFC 3971: HTML format">HTML</a>,
		<a href="https://www.rfc-editor.org/rfc/pdfrfc/rfc3971.txt.pdf" title="RFC 3971: PDF format">PDF</a>,
		<a href="https://www.rfc-editor.org/rfc/rfc3971.txt" title="RFC 3971: TXT format">TXT</a>
	</dd>
</dl>


<h3 id="rfc-4286">RFC 4286</h3>
<dl class="rfc">
	<dt>IETF Tools</dt>
	<dd>
		<a href="https://tools.ietf.org/html/rfc4286" title="RFC 4286: HTML format">HTML</a>,
		<a href="https://tools.ietf.org/pdf/rfc4286" title="RFC 4286: PDF format">PDF</a>,
		<a href="https://tools.ietf.org/rfc/rfc4286.txt" title="RFC 4286: TXT format">TXT</a>
	</dd>
	<dt>RFC Editor</dt>
	<dd>
		<a href="https://www.rfc-editor.org/rfc/rfc4286.html" title="RFC 4286: HTML format">HTML</a>,
		<a href="https://www.rfc-editor.org/rfc/pdfrfc/rfc4286.txt.pdf" title="RFC 4286: PDF format">PDF</a>,
		<a href="https://www.rfc-editor.org/rfc/rfc4286.txt" title="RFC 4286: TXT format">TXT</a>
	</dd>
</dl>


<h3 id="rfc-4620">RFC 4620</h3>
<dl class="rfc">
	<dt>IETF Tools</dt>
	<dd>
		<a href="https://tools.ietf.org/html/rfc4620" title="RFC 4620: HTML format">HTML</a>,
		<a href="https://tools.ietf.org/pdf/rfc4620" title="RFC 4620: PDF format">PDF</a>,
		<a href="https://tools.ietf.org/rfc/rfc4620.txt" title="RFC 4620: TXT format">TXT</a>
	</dd>
	<dt>RFC Editor</dt>
	<dd>
		<a href="https://www.rfc-editor.org/rfc/rfc4620.html" title="RFC 4620: HTML format">HTML</a>,
		<a href="https://www.rfc-editor.org/rfc/pdfrfc/rfc4620.txt.pdf" title="RFC 4620: PDF format">PDF</a>,
		<a href="https://www.rfc-editor.org/rfc/rfc4620.txt" title="RFC 4620: TXT format">TXT</a>
	</dd>
</dl>


<h3 id="rfc-4861">RFC 4861</h3>
<dl class="rfc">
	<dt>IETF Tools</dt>
	<dd>
		<a href="https://tools.ietf.org/html/rfc4861" title="RFC 4861: HTML format">HTML</a>,
		<a href="https://tools.ietf.org/pdf/rfc4861" title="RFC 4861: PDF format">PDF</a>,
		<a href="https://tools.ietf.org/rfc/rfc4861.txt" title="RFC 4861: TXT format">TXT</a>
	</dd>
	<dt>RFC Editor</dt>
	<dd>
		<a href="https://www.rfc-editor.org/rfc/rfc4861.html" title="RFC 4861: HTML format">HTML</a>,
		<a href="https://www.rfc-editor.org/rfc/pdfrfc/rfc4861.txt.pdf" title="RFC 4861: PDF format">PDF</a>,
		<a href="https://www.rfc-editor.org/rfc/rfc4861.txt" title="RFC 4861: TXT format">TXT</a>
	</dd>
</dl>


<h3 id="rfc-4890">RFC 4890</h3>
<dl class="rfc">
	<dt>IETF Tools</dt>
	<dd>
		<a href="https://tools.ietf.org/html/rfc4890" title="RFC 4890: HTML format">HTML</a>,
		<a href="https://tools.ietf.org/pdf/rfc4890" title="RFC 4890: PDF format">PDF</a>,
		<a href="https://tools.ietf.org/rfc/rfc4890.txt" title="RFC 4890: TXT format">TXT</a>
	</dd>
	<dt>RFC Editor</dt>
	<dd>
		<a href="https://www.rfc-editor.org/rfc/rfc4890.html" title="RFC 4890: HTML format">HTML</a>,
		<a href="https://www.rfc-editor.org/rfc/pdfrfc/rfc4890.txt.pdf" title="RFC 4890: PDF format">PDF</a>,
		<a href="https://www.rfc-editor.org/rfc/rfc4890.txt" title="RFC 4890: TXT format">TXT</a>
	</dd>
</dl>


<h3 id="rfc-5927">RFC 5927</h3>
<dl class="rfc">
	<dt>IETF Tools</dt>
	<dd>
		<a href="https://tools.ietf.org/html/rfc5927" title="RFC 5927: HTML format">HTML</a>,
		<a href="https://tools.ietf.org/pdf/rfc5927" title="RFC 5927: PDF format">PDF</a>,
		<a href="https://tools.ietf.org/rfc/rfc5927.txt" title="RFC 5927: TXT format">TXT</a>
	</dd>
	<dt>RFC Editor</dt>
	<dd>
		<a href="https://www.rfc-editor.org/rfc/rfc5927.html" title="RFC 5927: HTML format">HTML</a>,
		<a href="https://www.rfc-editor.org/rfc/pdfrfc/rfc5927.txt.pdf" title="RFC 5927: PDF format">PDF</a>,
		<a href="https://www.rfc-editor.org/rfc/rfc5927.txt" title="RFC 5927: TXT format">TXT</a>
	</dd>
</dl>
</p>
<hr>
]]></content><summary>Securely filtering the ICMP protocol under Linux: examples with ip6tables</summary><published>2017-07-26T22:22:02+02:00</published><updated>2026-10-02T15:49:57+02:00</updated></entry><entry><id>tag:doc.huc.fr.eu.org,2017-07-26:/en/sec/firewall/linux-firewall-icmp</id><link href="https://it-log.fr.eu.org/en/sec/firewall/linux-firewall-icmp/" rel="alternate" type="text/html"/><title>Linux: firewall ICMP</title><author><name>Stéphane HUC</name></author><category term="Linux" scheme="https://it-log.fr.eu.org/en/tags/linux/"/><category term="firewall" scheme="https://it-log.fr.eu.org/en/tags/firewall/"/><category term="ICMP" scheme="https://it-log.fr.eu.org/en/tags/icmp/"/><category term="Iptables" scheme="https://it-log.fr.eu.org/en/tags/iptables/"/><content type="html"><![CDATA[<h2 id="description">Description</h2>
<p><strong>Filtering ICMP on Linux!</strong></p>
<p>Someone say that it&rsquo;s absolutely necessary to block all ICMP, and bye-bye all needed commands, like <code>traceroute</code>, <code>ping</code>…</p>
<p>Others replies:</p>
<blockquote>
<p>yes, but… it&rsquo;s still convenient to use such commands except that…</p>
</blockquote>
<p>The obvious purpose of ICMP is to report error messages, status informations, related to the IP protocol (including Internet), to the delivery of the IP packets.</p>
<p>This interesting goal has its flaws:</p>
<ul>
<li>map your entire network,</li>
<li>seek to attack your network, through some well-known attacks — such as <abbr title="Denial of Service">DOS</abbr>
; see <strong>Smurf</strong>, the famous <strong>Ping of the Death</strong>, … —</li>
</ul>
<p>Few attacks allow to attack others network protocols, such <strong>SlowLoris</strong> againt the TCP protocol, and the HTTP service…</p>
<p><q>Frozen?<br>standard reaction…</q></p>
<hr>
<p>In this article, we will learn how to handle ICMP correctly, taking into account the recommendations made by recognized organizations, such as the IETF, the IANA, through different RFCs, which will all be named.</p>
<h2 id="manage-icmp">Manage ICMP</h2>
<h3 id="refuse">Refuse</h3>
<p>The following codes are known to be deprecated, dangerous to use, and therefore <strong>not to be used</strong>:</p>
<ul>
<li><code>3/6</code> - Destination Network Unknown</li>
<li><code>3/8</code> - Source Host Isolated</li>
<li><code>4/0</code> - Source Quench</li>
<li><code>15/0</code> - Information Request Message</li>
<li><code>16/0</code> - Information Reply Message</li>
</ul>

<div class="tab-info i-warning">Warning</div><div class="alert alert-warning" role="alert"><p><strong>ATTENTION</strong>: IANA, about the <strong>depreciation of Source Quench</strong>, recommends to log such packets and to remove them without warnings (<code>DROP</code>)</p>
<p>See: <a href="https://www.iana.org/assignments/icmp-parameters/icmp-parameters.xhtml" rel="external">reference</a></p>
</div>

<p><strong>Let&rsquo;s not even hesitate: the corresponding messages must ABSOLUTELY be refused!</strong></p>
<hr>
<p>Egual, IANA considers the following codes to be deprecated and to be filtered — <em>all discretion is left to the administrators to choose his filtering mode</em>. See: <a href="https://www.iana.org/assignments/icmp-parameters/icmp-parameters.xhtml" rel="external">reference</a></p>
<ul>
<li>
<p><code>6/0</code> - Alternate Host Address</p>
</li>
<li>
<p><code>15</code> - Information Request</p>
</li>
<li>
<p><code>16</code> - Information Reply</p>
</li>
<li>
<p><code>17</code> - Address Mask Request</p>
</li>
<li>
<p><code>18</code> - Address Mask Reply</p>
</li>
<li>
<p><code>30</code> - Traceroute</p>
</li>
<li>
<p><code>31</code> - Datagram Conversion Error</p>
</li>
<li>
<p><code>32</code> - Mobile Host Redirect</p>
</li>
<li>
<p><code>33</code> - IPv6 Where-Are-You</p>
</li>
<li>
<p><code>34</code> - IPv6 I-Am-Here</p>
</li>
<li>
<p><code>35</code> - Mobile Registration Request</p>
</li>
<li>
<p><code>36</code> - Mobile Registration Reply</p>
</li>
<li>
<p><code>37</code> - Domain Name Request</p>
</li>
<li>
<p><code>38</code> - Domain Name Reply</p>
</li>
<li>
<p><code>39</code> - SKIP</p>
</li>
</ul>
<p>It&rsquo;s your choice: <em>will you destroy them in paranoid mode‽</em></p>
<blockquote>
<p>Extermination, extermination, extermination…</p>
</blockquote>

<div class="tab-info i-info">Info</div><div class="alert alert-info" role="alert">Anyway, if you decide to filter the code 30, do not forget that <code>traceroute</code> is able to work on <code>UDP:53</code>, <code>TCP:80</code>… and even imitate <code>ICMP:8/0</code>!</div>

<h3 id="limit">Limit</h3>
<p>The recommendations are to limit, in input AND output:</p>
<ul>
<li><code>0/0</code> - Echo Reply Message - <em>(the famous Ping reply: THE Pong, what else :p)</em></li>
<li>all <code>type 3</code> - Destination Unreachable -
<ul>
<li><strong>except</strong> a slightly special treatment for <code>3/7</code> - Destination Host Unknown - just to limit in ouput and ignore in input.</li>
</ul>
</li>
<li>all <code>5</code> - Redirect</li>
<li><code>8/0</code> - Echo Message - <em>(the famous Ping)</em></li>
<li><code>9/0</code> - Router Advertisement Message</li>
<li><code>10/0</code> - Router Solicitation Message</li>
<li>all <code>11</code> - Time Exceeded -
<ul>
<li><em>Useful for <code>traceroute</code>, as well as the <code>30/0</code> code.</em></li>
</ul>
</li>
<li>all <code>12</code> - Parameter Problem</li>
<li><code>13/0</code> - Timestamp Message</li>
<li><code>14/0</code> - Timestamp Reply Message</li>
<li><code>17/0</code> - Address Mask Request</li>
<li><code>18/0</code> - Address Mask Reply</li>
</ul>
<p>As instance, in the context of Linux, use the Iptables <code>match limit</code> option…</p>
<h2 id="examples">Examples</h2>
<h3 id="paranoid-icmp">Paranoid ICMP</h3>
<p>In paranoid mode, you can open:</p>
<ul>
<li>in output: <code>8/0</code>,</li>
<li>and in input, the relative <code>0/0</code> code — so you can ping yourself…</li>
<li>and, prevent others doing same!</li>
<li>and finally, drop all others code</li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>iptables -A INPUT -p icmp --icmp-type echo-reply -m conntrack --ctstate RELATED,ESTABLISHED,UNTRACKED -m limit --limit 3/s --limit-burst <span style="color:#f99b15">7</span> -j ACCEPT
</span></span><span style="display:flex;"><span>iptables -A OUTPUT -p icmp --icmp-type echo-request -m conntrack --ctstate NEW,RELATED,ESTABLISHED,UNTRACKED -m limit --limit 3/s --limit-burst <span style="color:#f99b15">7</span> -j ACCEPT
</span></span><span style="display:flex;"><span>iptables -A INPUT -p icmp -j DROP
</span></span><span style="display:flex;"><span>iptables -A OUTPUT -p icmp -j DROP
</span></span></code></pre></div><h3 id="limit-icmp">Limit ICMP</h3>
<p>Here is an example, based on the understanding of the IETF recommendations, of ICMP limited rules, and reject all others codes with the <code>icmp-host-prohibited</code> messages.</p>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>/sbin/iptables -A INPUT -i ethX -p icmp -m limit --limit 3/s --limit-burst <span style="color:#f99b15">7</span> -j icmp4in
</span></span><span style="display:flex;"><span>/sbin/iptables -A icmp4in -p icmp -m conntrack --ctstate INVALID -j DROP
</span></span><span style="display:flex;"><span>/sbin/iptables -A icmp4in -p icmp -m icmp --icmp-type <span style="color:#f99b15">0</span> -m conntrack --ctstate RELATED,ESTABLISHED,UNTRACKED -j ACCEPT -m comment --comment <span style="color:#48b685">&#34;ICMP Echo reply&#34;</span>
</span></span><span style="display:flex;"><span>/sbin/iptables -A icmp4in -p icmp -m icmp --icmp-type 3/0 -m conntrack --ctstate RELATED,ESTABLISHED,UNTRACKED -j ACCEPT -m comment --comment <span style="color:#48b685">&#34;ICMP Destination Net Unreachable&#34;</span>
</span></span><span style="display:flex;"><span>/sbin/iptables -A icmp4in -p icmp -m icmp --icmp-type 3/1 -m conntrack --ctstate RELATED,ESTABLISHED,UNTRACKED -j ACCEPT -m comment --comment <span style="color:#48b685">&#34;ICMP Destination Host Unreachable&#34;</span>
</span></span><span style="display:flex;"><span>/sbin/iptables -A icmp4in -p icmp -m icmp --icmp-type 3/3 -m conntrack --ctstate RELATED,ESTABLISHED,UNTRACKED -j ACCEPT -m comment --comment <span style="color:#48b685">&#34;ICMP Destination Port Unreachable&#34;</span>
</span></span><span style="display:flex;"><span>/sbin/iptables -A icmp4in -p icmp -m icmp --icmp-type 3/4 -m conntrack --ctstate RELATED,ESTABLISHED,UNTRACKED -j ACCEPT -m comment --comment <span style="color:#48b685">&#34;ICMP PathMTU Discovery&#34;</span>
</span></span><span style="display:flex;"><span>/sbin/iptables -A icmp4in -p icmp -m icmp --icmp-type 3/6 -j DROP
</span></span><span style="display:flex;"><span>/sbin/iptables -A icmp4in -p icmp -m icmp --icmp-type 3/8 -j DROP
</span></span><span style="display:flex;"><span>/sbin/iptables -A icmp4in -p icmp -m icmp --icmp-type <span style="color:#f99b15">4</span> -j DROP
</span></span><span style="display:flex;"><span>/sbin/iptables -A icmp4in -p icmp -m icmp --icmp-type <span style="color:#f99b15">5</span> -m conntrack --ctstate NEW,RELATED,ESTABLISHED,UNTRACKED -j ACCEPT -m comment --comment <span style="color:#48b685">&#34;ICMP Redirect mssg&#34;</span>
</span></span><span style="display:flex;"><span>/sbin/iptables -A icmp4in -p icmp -m icmp --icmp-type 8/0 -m conntrack --ctstate NEW,RELATED,ESTABLISHED,UNTRACKED -j ACCEPT -m comment --comment <span style="color:#48b685">&#34;ICMP Echo mssg&#34;</span>
</span></span><span style="display:flex;"><span>/sbin/iptables -A icmp4in -p icmp -m icmp --icmp-type 9/0 -m conntrack --ctstate RELATED,ESTABLISHED,UNTRACKED -j ACCEPT -m comment --comment <span style="color:#48b685">&#34;ICMP Router Advertisement Message&#34;</span>
</span></span><span style="display:flex;"><span>/sbin/iptables -A icmp4in -p icmp -m icmp --icmp-type 10/0 -m conntrack --ctstate NEW,RELATED,ESTABLISHED,UNTRACKED -j ACCEPT -m comment --comment <span style="color:#48b685">&#34;ICMP Router Solicitation Message&#34;</span>
</span></span><span style="display:flex;"><span>/sbin/iptables -A icmp4in -p icmp -m icmp --icmp-type <span style="color:#f99b15">11</span> -m conntrack --ctstate NEW,RELATED,ESTABLISHED,UNTRACKED -j ACCEPT -m comment --comment <span style="color:#48b685">&#34;ICMP Time exceeded&#34;</span>
</span></span><span style="display:flex;"><span>/sbin/iptables -A icmp4in -p icmp -m icmp --icmp-type <span style="color:#f99b15">12</span> -m conntrack --ctstate NEW,RELATED,ESTABLISHED,UNTRACKED -j ACCEPT -m comment --comment <span style="color:#48b685">&#34;ICMP Param pb&#34;</span>
</span></span><span style="display:flex;"><span>/sbin/iptables -A icmp4in -p icmp -m icmp --icmp-type 13/0 -m conntrack --ctstate NEW,RELATED,ESTABLISHED,UNTRACKED -j ACCEPT -m comment --comment <span style="color:#48b685">&#34;ICMP Timestamp Message&#34;</span>
</span></span><span style="display:flex;"><span>/sbin/iptables -A icmp4in -p icmp -m icmp --icmp-type 14/0 -m conntrack --ctstate RELATED,ESTABLISHED,UNTRACKED -j ACCEPT -m comment --comment <span style="color:#48b685">&#34;ICMP Timestamp Reply Message&#34;</span>
</span></span><span style="display:flex;"><span>/sbin/iptables -A icmp4in -p icmp -m icmp --icmp-type <span style="color:#f99b15">15</span> -j DROP
</span></span><span style="display:flex;"><span>/sbin/iptables -A icmp4in -p icmp -m icmp --icmp-type <span style="color:#f99b15">16</span> -j DROP
</span></span><span style="display:flex;"><span>/sbin/iptables -A icmp4in -p icmp -m icmp --icmp-type 17/0 -m conntrack --ctstate NEW,RELATED,ESTABLISHED,UNTRACKED -j ACCEPT -m comment --comment <span style="color:#48b685">&#34;ICMP Address Mask Request&#34;</span>
</span></span><span style="display:flex;"><span>/sbin/iptables -A icmp4in -p icmp -m icmp --icmp-type 18/0 -m conntrack --ctstate RELATED,ESTABLISHED,UNTRACKED -j ACCEPT -m comment --comment <span style="color:#48b685">&#34;ICMP Address Mask Reply&#34;</span>
</span></span><span style="display:flex;"><span>/sbin/iptables -A icmp4in -p icmp -m icmp --icmp-type <span style="color:#f99b15">30</span> -m conntrack --ctstate NEW,RELATED,ESTABLISHED,UNTRACKED -j ACCEPT -m comment --comment <span style="color:#48b685">&#34;ICMP Traceroute&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># REJECT Others</span>
</span></span><span style="display:flex;"><span>/sbin/iptables -A icmp4in -p icmp -j REJECT --reject-with icmp-host-prohibited
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>/sbin/iptables -A OUTPUT -o ethX -p icmp -m limit --limit 3/s --limit-burst <span style="color:#f99b15">7</span> -j icmp4out
</span></span><span style="display:flex;"><span>/sbin/iptables -A icmp4out -p icmp -m conntrack --ctstate INVALID -j DROP
</span></span><span style="display:flex;"><span>/sbin/iptables -A icmp4out -p icmp -m icmp --icmp-type <span style="color:#f99b15">0</span> -m conntrack --ctstate RELATED,ESTABLISHED,UNTRACKED -j ACCEPT
</span></span><span style="display:flex;"><span>/sbin/iptables -A icmp4out -p icmp -m icmp --icmp-type 3/0 -m conntrack --ctstate RELATED,ESTABLISHED,UNTRACKED -j ACCEPT
</span></span><span style="display:flex;"><span>/sbin/iptables -A icmp4out -p icmp -m icmp --icmp-type 3/1 -m conntrack --ctstate RELATED,ESTABLISHED,UNTRACKED -j ACCEPT
</span></span><span style="display:flex;"><span>/sbin/iptables -A icmp4out -p icmp -m icmp --icmp-type 3/3 -m conntrack --ctstate RELATED,ESTABLISHED,UNTRACKED -j ACCEPT
</span></span><span style="display:flex;"><span>/sbin/iptables -A icmp4out -p icmp -m icmp --icmp-type 3/4 -m conntrack --ctstate RELATED,ESTABLISHED,UNTRACKED -j ACCEPT
</span></span><span style="display:flex;"><span>/sbin/iptables -A icmp4out -p icmp -m icmp --icmp-type 3/6 -j DROP
</span></span><span style="display:flex;"><span>/sbin/iptables -A icmp4out -p icmp -m icmp --icmp-type 3/7 -m conntrack --ctstate RELATED,ESTABLISHED,UNTRACKED -j ACCEPT
</span></span><span style="display:flex;"><span>/sbin/iptables -A icmp4out -p icmp -m icmp --icmp-type 3/8 -j DROP
</span></span><span style="display:flex;"><span>/sbin/iptables -A icmp4out -p icmp -m icmp --icmp-type 4/0 -j DROP
</span></span><span style="display:flex;"><span>/sbin/iptables -A icmp4out -p icmp -m icmp --icmp-type <span style="color:#f99b15">5</span> -m conntrack --ctstate NEW,RELATED,ESTABLISHED,UNTRACKED -j ACCEPT
</span></span><span style="display:flex;"><span>/sbin/iptables -A icmp4out -p icmp -m icmp --icmp-type 8/0 -m conntrack --ctstate NEW,RELATED,ESTABLISHED,UNTRACKED -j ACCEPT
</span></span><span style="display:flex;"><span>/sbin/iptables -A icmp4out -p icmp -m icmp --icmp-type 9/0 -m conntrack --ctstate RELATED,ESTABLISHED,UNTRACKED -j ACCEPT
</span></span><span style="display:flex;"><span>/sbin/iptables -A icmp4out -p icmp -m icmp --icmp-type 10/0 -m conntrack --ctstate NEW,RELATED,ESTABLISHED,UNTRACKED -j ACCEPT
</span></span><span style="display:flex;"><span>/sbin/iptables -A icmp4out -p icmp -m icmp --icmp-type <span style="color:#f99b15">11</span> -m conntrack --ctstate NEW,RELATED,ESTABLISHED,UNTRACKED -j ACCEPT
</span></span><span style="display:flex;"><span>/sbin/iptables -A icmp4out -p icmp -m icmp --icmp-type <span style="color:#f99b15">12</span> -m conntrack --ctstate NEW,RELATED,ESTABLISHED,UNTRACKED -j ACCEPT
</span></span><span style="display:flex;"><span>/sbin/iptables -A icmp4out -p icmp -m icmp --icmp-type 13/0 -m conntrack --ctstate NEW,RELATED,ESTABLISHED,UNTRACKED -j ACCEPT
</span></span><span style="display:flex;"><span>/sbin/iptables -A icmp4out -p icmp -m icmp --icmp-type 14/0 -m conntrack --ctstate RELATED,ESTABLISHED,UNTRACKED -j ACCEPT
</span></span><span style="display:flex;"><span>/sbin/iptables -A icmp4out -p icmp -m icmp --icmp-type <span style="color:#f99b15">15</span> -j DROP
</span></span><span style="display:flex;"><span>/sbin/iptables -A icmp4out -p icmp -m icmp --icmp-type <span style="color:#f99b15">16</span> -j DROP
</span></span><span style="display:flex;"><span>/sbin/iptables -A icmp4out -p icmp -m icmp --icmp-type 17/0 -m conntrack --ctstate NEW,RELATED,ESTABLISHED,UNTRACKED -j ACCEPT
</span></span><span style="display:flex;"><span>/sbin/iptables -A icmp4out -p icmp -m icmp --icmp-type 18/0 -m conntrack --ctstate RELATED,ESTABLISHED,UNTRACKED -j ACCEPT
</span></span><span style="display:flex;"><span>/sbin/iptables -A icmp4out -p icmp -m icmp --icmp-type <span style="color:#f99b15">30</span> -m conntrack --ctstate NEW,RELATED,ESTABLISHED,UNTRACKED -j ACCEPT
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>/sbin/iptables -A icmp4out -p icmp -j REJECT --reject-with icmp-host-prohibited
</span></span></code></pre></div><h2 id="documentation">Documentation</h2>
<h3 id="ietf">IETF</h3>
<p>IETF is a well-known recognized organization that writes many technical documents whose purpose is to improve the technicality, the security to use the network protocols.</p>
<p>Some existing documents insist on filtering ICMP, even ICMPv6, as:</p>
<ul>
<li><strong><a href="/en/sec/firewall/linux-firewall-icmp/#rfc-4890">RFC 4890</a></strong></li>
<li><strong><a href="/en/sec/firewall/linux-firewall-icmp/#rfc-5927">RFC 5927</a></strong></li>
<li><a href="https://tools.ietf.org/html/draft-ietf-opsec-icmp-filtering-04" rel="external">draft ICMP filtering</a></li>
<li><a href="https://tools.ietf.org/id/draft-ietf-v6ops-icmpv6-filtering-recs-02.txt" rel="external">draft ICMPv6 filtering</a></li>
</ul>
<p>These documents are all interesting, some are old, others more recent, and have the goal to think seriously about the security, to set up around ICMP.</p>
<p>The &ldquo;ICMP filtering&rdquo; draft paper discuss about IPv4 and IPv6 protocols, and explains what attacks are possible, give useful recommendations, which range from refuse some packets to limit others.</p>
<p>Clearly, certain messages codes are absolutely to be block, to refuse, like ICMP <code>4/0</code>, alias &ldquo;<strong>Source Quench</strong>&rdquo;, wich is explicetely deprecated, not to be used anymore… but it&rsquo;s not the only one!</p>
<hr>
<p>
<h3 id="rfc-4890">RFC 4890</h3>
<dl class="rfc">
	<dt>IETF Tools</dt>
	<dd>
		<a href="https://tools.ietf.org/html/rfc4890" title="RFC 4890: HTML format">HTML</a>,
		<a href="https://tools.ietf.org/pdf/rfc4890" title="RFC 4890: PDF format">PDF</a>,
		<a href="https://tools.ietf.org/rfc/rfc4890.txt" title="RFC 4890: TXT format">TXT</a>
	</dd>
	<dt>RFC Editor</dt>
	<dd>
		<a href="https://www.rfc-editor.org/rfc/rfc4890.html" title="RFC 4890: HTML format">HTML</a>,
		<a href="https://www.rfc-editor.org/rfc/pdfrfc/rfc4890.txt.pdf" title="RFC 4890: PDF format">PDF</a>,
		<a href="https://www.rfc-editor.org/rfc/rfc4890.txt" title="RFC 4890: TXT format">TXT</a>
	</dd>
</dl>


<h3 id="rfc-5927">RFC 5927</h3>
<dl class="rfc">
	<dt>IETF Tools</dt>
	<dd>
		<a href="https://tools.ietf.org/html/rfc5927" title="RFC 5927: HTML format">HTML</a>,
		<a href="https://tools.ietf.org/pdf/rfc5927" title="RFC 5927: PDF format">PDF</a>,
		<a href="https://tools.ietf.org/rfc/rfc5927.txt" title="RFC 5927: TXT format">TXT</a>
	</dd>
	<dt>RFC Editor</dt>
	<dd>
		<a href="https://www.rfc-editor.org/rfc/rfc5927.html" title="RFC 5927: HTML format">HTML</a>,
		<a href="https://www.rfc-editor.org/rfc/pdfrfc/rfc5927.txt.pdf" title="RFC 5927: PDF format">PDF</a>,
		<a href="https://www.rfc-editor.org/rfc/rfc5927.txt" title="RFC 5927: TXT format">TXT</a>
	</dd>
</dl>


<h3 id="rfc-6633">RFC 6633</h3>
<dl class="rfc">
	<dt>IETF Tools</dt>
	<dd>
		<a href="https://tools.ietf.org/html/rfc6633" title="RFC 6633: HTML format">HTML</a>,
		<a href="https://tools.ietf.org/pdf/rfc6633" title="RFC 6633: PDF format">PDF</a>,
		<a href="https://tools.ietf.org/rfc/rfc6633.txt" title="RFC 6633: TXT format">TXT</a>
	</dd>
	<dt>RFC Editor</dt>
	<dd>
		<a href="https://www.rfc-editor.org/rfc/rfc6633.html" title="RFC 6633: HTML format">HTML</a>,
		<a href="https://www.rfc-editor.org/rfc/pdfrfc/rfc6633.txt.pdf" title="RFC 6633: PDF format">PDF</a>,
		<a href="https://www.rfc-editor.org/rfc/rfc6633.txt" title="RFC 6633: TXT format">TXT</a>
	</dd>
</dl>


<h3 id="rfc-6918">RFC 6918</h3>
<dl class="rfc">
	<dt>IETF Tools</dt>
	<dd>
		<a href="https://tools.ietf.org/html/rfc6918" title="RFC 6918: HTML format">HTML</a>,
		<a href="https://tools.ietf.org/pdf/rfc6918" title="RFC 6918: PDF format">PDF</a>,
		<a href="https://tools.ietf.org/rfc/rfc6918.txt" title="RFC 6918: TXT format">TXT</a>
	</dd>
	<dt>RFC Editor</dt>
	<dd>
		<a href="https://www.rfc-editor.org/rfc/rfc6918.html" title="RFC 6918: HTML format">HTML</a>,
		<a href="https://www.rfc-editor.org/rfc/pdfrfc/rfc6918.txt.pdf" title="RFC 6918: PDF format">PDF</a>,
		<a href="https://www.rfc-editor.org/rfc/rfc6918.txt" title="RFC 6918: TXT format">TXT</a>
	</dd>
</dl>
</p>
<h3 id="wikipedia">Wikipedia</h3>
<ul>
<li><a href="https://en.wikipedia.org/wiki/Denial-of-service_attack#Attack_techniques" title="Wikipedia Article: Denial-of-service_attack#Attack_techniques">
    Denial-of-service_attack#Attack_techniques
    <sup><abbr class="is-italic" title="Wikipedia">WP</abbr></sup>
</a>
</li>
<li><a href="https://en.wikipedia.org/wiki/Ping_of_death" title="Wikipedia Article: Ping_of_death">
    Ping_of_death
    <sup><abbr class="is-italic" title="Wikipedia">WP</abbr></sup>
</a>
</li>
<li><a href="https://en.wikipedia.org/wiki/Slowloris_%28computer_security%29" title="Wikipedia Article: Slowloris_(computer_security)">
    Slowloris_(computer_security)
    <sup><abbr class="is-italic" title="Wikipedia">WP</abbr></sup>
</a>
</li>
</ul>
<hr>
]]></content><summary>Securely filtering the ICMP protocol under Linux: examples with iptables</summary><published>2017-07-26T21:03:54+02:00</published><updated>2026-10-02T15:49:57+02:00</updated></entry><entry><id>tag:doc.huc.fr.eu.org,2017-07-24:/en/dev/bash/script-convert-optimize-image</id><link href="https://it-log.fr.eu.org/en/dev/bash/script-convert-optimize-image/" rel="alternate" type="text/html"/><title>Bash: Convert, optimize image jpeg/png</title><author><name>Stéphane HUC</name></author><category term="Bash" scheme="https://it-log.fr.eu.org/en/tags/bash/"/><category term="convert" scheme="https://it-log.fr.eu.org/en/tags/convert/"/><category term="optimize" scheme="https://it-log.fr.eu.org/en/tags/optimize/"/><category term="image" scheme="https://it-log.fr.eu.org/en/tags/image/"/><content type="html"><![CDATA[<h2 id="description">Description</h2>
<p>The script helps you to convert easy and optimize images jpg/png.</p>
<p>Three options:</p>
<ul>
<li><code>jpg2jpg</code>: to optimize an image jpeg with a ratio to 70%.</li>
<li><code>jpg2png</code>: to convert an image jpg to an optimized image png. &lt;span class&quot;red&quot;&gt;Be carefull: the weigth grows up!</span>.</li>
<li><code>png2png</code>: to optimize an image png.</li>
</ul>
<p>Please, install before using thoses tools:</p>
<ul>
<li><code>mogrify</code>, by the package <strong>ImageMagick</strong></li>
<li><code>jpegtran</code>, by the librarie <strong>libjpeg</strong></li>
<li><code>pngnq</code></li>
<li><code>gvfs-info</code>, by the package <strong>gvfs-bin</strong></li>
</ul>
<h2 id="the-script--convert_image">The script : convert_image()</h2>
<div class="highlight"><pre tabindex="0" style="color:#e7e9db;background-color:#2f1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#776e71">#!/bin/bash
</span></span></span><span style="display:flex;"><span><span style="color:#776e71"># ./convert_image /name_dir/ options</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># options are: &#39;jpg2jpg&#39;, &#39;jpg2png&#39;, &#39;png2png&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># you need ImageMagick tools, libjpeg (jpegtran), gvfs-bin</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#  Convert image jpg</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#  1/ jpg to jpg, quality 70 and optimize : option jpg2jpg</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#  2/ jpg to png : option jp2png</span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#  3/ png to optimize png : option png2png</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>clear
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#  define variables needed</span>
</span></span><span style="display:flex;"><span>declare -a <span style="color:#ef6155">EXTS</span><span style="color:#5bc4bf">=(</span> jpg JPG <span style="color:#5bc4bf">)</span> <span style="color:#776e71"># extension accepted</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>declare -i <span style="color:#ef6155">ARGS</span><span style="color:#5bc4bf">=</span><span style="color:#f99b15">2</span> <span style="color:#776e71"># number of arguments accepted declare -i mssg=1 #</span>
</span></span><span style="display:flex;"><span>to display message declare -i <span style="color:#ef6155">cmptr</span><span style="color:#5bc4bf">=</span><span style="color:#f99b15">0</span> <span style="color:#776e71"># compteur declare -a</span>
</span></span><span style="display:flex;"><span>MIME<span style="color:#5bc4bf">[</span>1<span style="color:#5bc4bf">]=</span><span style="color:#48b685">&#34;image/jpeg&#34;</span> <span style="color:#776e71"># mime type jpg declare -a</span>
</span></span><span style="display:flex;"><span>MIME<span style="color:#5bc4bf">[</span>2<span style="color:#5bc4bf">]=</span><span style="color:#48b685">&#34;image/png&#34;</span> <span style="color:#776e71"># mime type png declare -a option=( jpg2jpg</span>
</span></span><span style="display:flex;"><span>jpg2png png2png <span style="color:#5bc4bf">)</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ef6155">IFS</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">$&#39;n&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#776e71">#  functions needed !</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#815ba4">function</span> convert_image <span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    verify_args <span style="color:#ef6155">$1</span> <span style="color:#ef6155">$2</span>
</span></span><span style="display:flex;"><span>    verify_bin
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    create_vars_dir <span style="color:#ef6155">$1</span> <span style="color:#ef6155">$2</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#776e71">#empty_dir $dir_out</span>
</span></span><span style="display:flex;"><span>    empty_dir <span style="color:#ef6155">$dir_out2</span>
</span></span><span style="display:flex;"><span>      
</span></span><span style="display:flex;"><span>    create_dir <span style="color:#ef6155">$dir_out</span>
</span></span><span style="display:flex;"><span>    create_dir <span style="color:#ef6155">$dir_out2</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>     <span style="color:#815ba4">for</span> f in find <span style="color:#ef6155">$1</span> -type f;
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">do</span>
</span></span><span style="display:flex;"><span>         create_vars_image
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>         <span style="color:#815ba4">case</span> <span style="color:#ef6155">$mime</span> in
</span></span><span style="display:flex;"><span>              <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">MIME</span>[1]<span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span><span style="color:#5bc4bf">)</span>
</span></span><span style="display:flex;"><span>                  
</span></span><span style="display:flex;"><span>                   <span style="color:#815ba4">case</span> <span style="color:#ef6155">$2</span> in
</span></span><span style="display:flex;"><span>                        <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">option</span>[0]<span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span><span style="color:#5bc4bf">)</span>
</span></span><span style="display:flex;"><span>                             increment
</span></span><span style="display:flex;"><span>                             jpg2jpg
</span></span><span style="display:flex;"><span>                             optimize_jpg
</span></span><span style="display:flex;"><span>                             empty_img_converted <span style="color:#ef6155">$dir_out</span> <span style="color:#ef6155">$ff</span>
</span></span><span style="display:flex;"><span>                        ;;
</span></span><span style="display:flex;"><span>                        <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">option</span>[1]<span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span><span style="color:#5bc4bf">)</span>
</span></span><span style="display:flex;"><span>                             increment
</span></span><span style="display:flex;"><span>                             jpg2png
</span></span><span style="display:flex;"><span>                             optimize_png
</span></span><span style="display:flex;"><span>                        ;;
</span></span><span style="display:flex;"><span>                        *<span style="color:#5bc4bf">)</span>
</span></span><span style="display:flex;"><span>                             exit
</span></span><span style="display:flex;"><span>                        ;;
</span></span><span style="display:flex;"><span>                   <span style="color:#815ba4">esac</span>
</span></span><span style="display:flex;"><span>      
</span></span><span style="display:flex;"><span>              ;;
</span></span><span style="display:flex;"><span>      
</span></span><span style="display:flex;"><span>              <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">MIME</span>[2]<span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span><span style="color:#5bc4bf">)</span>
</span></span><span style="display:flex;"><span>                   <span style="color:#815ba4">case</span> <span style="color:#ef6155">$2</span> in
</span></span><span style="display:flex;"><span>                        <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">option</span>[2]<span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span><span style="color:#5bc4bf">)</span>
</span></span><span style="display:flex;"><span>                             optimize_png
</span></span><span style="display:flex;"><span>                        ;;
</span></span><span style="display:flex;"><span>                        *<span style="color:#5bc4bf">)</span>
</span></span><span style="display:flex;"><span>                             exit
</span></span><span style="display:flex;"><span>                        ;;
</span></span><span style="display:flex;"><span>                   <span style="color:#815ba4">esac</span>
</span></span><span style="display:flex;"><span>              ;;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>              *<span style="color:#5bc4bf">)</span>
</span></span><span style="display:flex;"><span>                   exit
</span></span><span style="display:flex;"><span>              ;;
</span></span><span style="display:flex;"><span>         <span style="color:#815ba4">esac</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">done</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#815ba4">function</span> create_dir <span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">if</span> <span style="color:#5bc4bf">[</span>! -d <span style="color:#ef6155">$1</span><span style="color:#5bc4bf">](</span>!_-d_<span style="color:#ef6155">$1</span><span style="color:#5bc4bf">)</span>; <span style="color:#815ba4">then</span>
</span></span><span style="display:flex;"><span>         <span style="color:#815ba4">if</span> <span style="color:#5bc4bf">((</span> <span style="color:#ef6155">mssg</span> <span style="color:#5bc4bf">==</span> 1 <span style="color:#5bc4bf">))</span>; <span style="color:#815ba4">then</span> echo <span style="color:#48b685">&#34;*** Create directory </span><span style="color:#ef6155">$1</span><span style="color:#48b685"> ***&#34;</span>; <span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>         mkdir <span style="color:#ef6155">$1</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#815ba4">function</span> create_vars_dir <span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#ef6155">dir_out</span><span style="color:#5bc4bf">=</span><span style="color:#ef6155">$1</span><span style="color:#48b685">&#34;converted/&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">if</span> <span style="color:#5bc4bf">((</span> <span style="color:#ef6155">mssg</span> <span style="color:#5bc4bf">==</span> 1 <span style="color:#5bc4bf">))</span>; <span style="color:#815ba4">then</span> echo <span style="color:#48b685">&#34;*** Create variables needed for </span><span style="color:#ef6155">$2</span><span style="color:#48b685"> : dir_out ***&#34;</span>; <span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ef6155">dir_out2</span><span style="color:#5bc4bf">=</span><span style="color:#ef6155">$1</span><span style="color:#48b685">&#34;optim_jpg/&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">if</span> <span style="color:#5bc4bf">((</span> <span style="color:#ef6155">mssg</span> <span style="color:#5bc4bf">==</span> 1 <span style="color:#5bc4bf">))</span>; <span style="color:#815ba4">then</span> echo <span style="color:#48b685">&#34;*** Create variables needed for </span><span style="color:#ef6155">$2</span><span style="color:#48b685"> : dir_out2 ***&#34;</span>; <span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#815ba4">function</span> create_vars_image <span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>     <span style="color:#ef6155">dir</span><span style="color:#5bc4bf">=</span>dirname <span style="color:#ef6155">$f</span>
</span></span><span style="display:flex;"><span>     <span style="color:#ef6155">ff</span><span style="color:#5bc4bf">=</span>basename <span style="color:#ef6155">$f</span>
</span></span><span style="display:flex;"><span>    <span style="color:#ef6155">ext</span><span style="color:#5bc4bf">=</span><span style="color:#f99b15">${</span><span style="color:#ef6155">ff</span>:(-3)<span style="color:#f99b15">}</span>;
</span></span><span style="display:flex;"><span>     <span style="color:#ef6155">name</span><span style="color:#5bc4bf">=</span>basename <span style="color:#ef6155">$f</span> .<span style="color:#ef6155">$ext</span>
</span></span><span style="display:flex;"><span>    <span style="color:#776e71">#length=${#ff}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#776e71">#name=${ff:0:$length-4};</span>
</span></span><span style="display:flex;"><span>     <span style="color:#ef6155">mime</span><span style="color:#5bc4bf">=</span>gvfs-info --attributes<span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;standard::content-type&#34;</span> <span style="color:#ef6155">$f</span> | grep <span style="color:#48b685">&#34;standard::content-type&#34;</span> | cut -c27-
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#815ba4">function</span> empty_dir <span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">if</span> <span style="color:#5bc4bf">[</span> <span style="color:#ef6155">$1</span> <span style="color:#5bc4bf">]</span>; <span style="color:#815ba4">then</span>
</span></span><span style="display:flex;"><span>         <span style="color:#815ba4">if</span> <span style="color:#5bc4bf">[</span>-d <span style="color:#ef6155">$1</span><span style="color:#5bc4bf">](</span>-d_<span style="color:#ef6155">$1</span><span style="color:#5bc4bf">)</span>; <span style="color:#815ba4">then</span>
</span></span><span style="display:flex;"><span>              cd <span style="color:#ef6155">$1</span>
</span></span><span style="display:flex;"><span>              rm *
</span></span><span style="display:flex;"><span>              <span style="color:#815ba4">if</span> <span style="color:#5bc4bf">((</span> <span style="color:#ef6155">mssg</span> <span style="color:#5bc4bf">==</span> 1 <span style="color:#5bc4bf">))</span>; <span style="color:#815ba4">then</span> echo <span style="color:#48b685">&#34;~~~ Dir </span><span style="color:#ef6155">$1</span><span style="color:#48b685"> empty! ~~~&#34;</span>; <span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>              cd ..
</span></span><span style="display:flex;"><span>         <span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#815ba4">function</span> empty_img_converted <span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">if</span> <span style="color:#5bc4bf">[</span> <span style="color:#ef6155">$1</span> <span style="color:#5bc4bf">]</span>; <span style="color:#815ba4">then</span>
</span></span><span style="display:flex;"><span>         <span style="color:#815ba4">if</span> <span style="color:#5bc4bf">[</span>-d <span style="color:#ef6155">$1</span><span style="color:#5bc4bf">](</span>-d_<span style="color:#ef6155">$1</span><span style="color:#5bc4bf">)</span>; <span style="color:#815ba4">then</span>
</span></span><span style="display:flex;"><span>              <span style="color:#815ba4">if</span> <span style="color:#5bc4bf">[</span><span style="color:#ef6155">$2</span><span style="color:#5bc4bf">](</span><span style="color:#ef6155">$2</span><span style="color:#5bc4bf">)</span>; <span style="color:#815ba4">then</span>
</span></span><span style="display:flex;"><span>                   unlink <span style="color:#ef6155">$1$2</span>;
</span></span><span style="display:flex;"><span>                   <span style="color:#815ba4">if</span> <span style="color:#5bc4bf">((</span> <span style="color:#ef6155">mssg</span> <span style="color:#5bc4bf">==</span> 1 <span style="color:#5bc4bf">))</span>; <span style="color:#815ba4">then</span> echo <span style="color:#48b685">&#34;=&gt; 3/ Img </span><span style="color:#ef6155">$ff</span><span style="color:#48b685"> deleted in dir </span><span style="color:#ef6155">$1</span><span style="color:#48b685"> !&#34;</span>; <span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>              <span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>         <span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#815ba4">function</span> increment <span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#5bc4bf">((</span> cptr++ <span style="color:#5bc4bf">))</span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">if</span> <span style="color:#5bc4bf">((</span> <span style="color:#ef6155">mssg</span> <span style="color:#5bc4bf">==</span> 1 <span style="color:#5bc4bf">))</span>; <span style="color:#815ba4">then</span> echo <span style="color:#48b685">&#34;</span><span style="color:#ef6155">$cptr</span><span style="color:#48b685"> :: Image </span><span style="color:#ef6155">$ff</span><span style="color:#48b685"> { Mime Type: </span><span style="color:#ef6155">$mime</span><span style="color:#48b685"> } to convert&#34;</span>; <span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#815ba4">function</span> jpg2jpg <span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    cp <span style="color:#ef6155">$f</span> <span style="color:#ef6155">$dir_out</span>
</span></span><span style="display:flex;"><span>    cd <span style="color:#ef6155">$dir_out</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">if</span> <span style="color:#5bc4bf">((</span> <span style="color:#ef6155">mssg</span> <span style="color:#5bc4bf">==</span> 1 <span style="color:#5bc4bf">))</span>; <span style="color:#815ba4">then</span> echo <span style="color:#48b685">&#34;=&gt; 1/ Convert image </span><span style="color:#ef6155">$ff</span><span style="color:#48b685"> to quality 70 ...&#34;</span>; <span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>    mogrify -quality 70 <span style="color:#ef6155">$ff</span>
</span></span><span style="display:flex;"><span>             
</span></span><span style="display:flex;"><span>    cd <span style="color:#48b685">&#34;..&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#815ba4">function</span> jpg2png <span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">if</span> <span style="color:#5bc4bf">((</span> <span style="color:#ef6155">mssg</span> <span style="color:#5bc4bf">==</span> 1 <span style="color:#5bc4bf">))</span>; <span style="color:#815ba4">then</span> echo <span style="color:#48b685">&#34;=&gt; Convert image </span><span style="color:#ef6155">$ff</span><span style="color:#48b685"> to PNG ...&#34;</span>; <span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>    mogrify -format png <span style="color:#ef6155">$f</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#815ba4">function</span> optimize_jpg <span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">if</span> <span style="color:#5bc4bf">((</span> <span style="color:#ef6155">mssg</span> <span style="color:#5bc4bf">==</span> 1 <span style="color:#5bc4bf">))</span>; <span style="color:#815ba4">then</span> echo <span style="color:#48b685">&#34;=&gt; 2/ Optimize image </span><span style="color:#ef6155">$ff</span><span style="color:#48b685"> with jpegtran ...&#34;</span>; <span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>    jpegtran -optimize -progressive -perfect -copy all <span style="color:#ef6155">$dir_out$ff</span> &gt; <span style="color:#ef6155">$dir_out2$ff</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#815ba4">function</span> optimize_png <span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">if</span> <span style="color:#5bc4bf">((</span> <span style="color:#ef6155">mssg</span> <span style="color:#5bc4bf">==</span> 1 <span style="color:#5bc4bf">))</span>; <span style="color:#815ba4">then</span> echo <span style="color:#48b685">&#34;=&gt; Deplace image </span><span style="color:#ef6155">$name</span><span style="color:#48b685">.png to optimize-it! ...&#34;</span>; <span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">case</span> <span style="color:#ef6155">$mime</span> in
</span></span><span style="display:flex;"><span>         <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">MIME</span>[1]<span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span><span style="color:#5bc4bf">)</span>
</span></span><span style="display:flex;"><span>              mv <span style="color:#ef6155">$1$name</span><span style="color:#48b685">&#34;.png&#34;</span> <span style="color:#ef6155">$dir_out</span>
</span></span><span style="display:flex;"><span>         ;;
</span></span><span style="display:flex;"><span>         <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">MIME</span>[2]<span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span><span style="color:#5bc4bf">)</span>
</span></span><span style="display:flex;"><span>              cp <span style="color:#ef6155">$1$name</span><span style="color:#48b685">&#34;.png&#34;</span> <span style="color:#ef6155">$dir_out</span>
</span></span><span style="display:flex;"><span>         ;;
</span></span><span style="display:flex;"><span>         *<span style="color:#5bc4bf">)</span>
</span></span><span style="display:flex;"><span>              exit
</span></span><span style="display:flex;"><span>         ;;
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">esac</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    cd <span style="color:#ef6155">$dir_out</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">if</span> <span style="color:#5bc4bf">((</span> <span style="color:#ef6155">mssg</span> <span style="color:#5bc4bf">==</span> 1 <span style="color:#5bc4bf">))</span>; <span style="color:#815ba4">then</span> echo <span style="color:#48b685">&#34;=&gt; Optimize image </span><span style="color:#ef6155">$name</span><span style="color:#48b685">.png with pngnq ...&#34;</span>; <span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>    pngnq -vf -s1 <span style="color:#48b685">&#34;</span><span style="color:#ef6155">$name</span><span style="color:#48b685">.png&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">if</span> <span style="color:#5bc4bf">((</span> <span style="color:#ef6155">mssg</span> <span style="color:#5bc4bf">==</span> 1 <span style="color:#5bc4bf">))</span>; <span style="color:#815ba4">then</span> echo <span style="color:#48b685">&#34;=&gt; delete </span><span style="color:#ef6155">$name</span><span style="color:#48b685">.png ...&#34;</span>; <span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>    unlink <span style="color:#48b685">&#34;</span><span style="color:#ef6155">$name</span><span style="color:#48b685">.png&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">if</span> <span style="color:#5bc4bf">((</span> <span style="color:#ef6155">mssg</span> <span style="color:#5bc4bf">==</span> 1 <span style="color:#5bc4bf">))</span>; <span style="color:#815ba4">then</span> echo <span style="color:#48b685">&#34;=&gt; Rename image PNG temporary in name </span><span style="color:#ef6155">$name</span><span style="color:#48b685">.png ...&#34;</span>; <span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>    mv <span style="color:#48b685">&#34;</span><span style="color:#ef6155">$name</span><span style="color:#48b685">-nq8.png&#34;</span> <span style="color:#48b685">&#34;</span><span style="color:#ef6155">$name</span><span style="color:#48b685">.png&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#776e71">#echo &#34;=&gt; Optimize image PNG {$name.png} with optipng ...&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#776e71">#optipng -o7 &#34;$name.png&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    cd <span style="color:#48b685">&#34;..&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#815ba4">function</span> status <span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">case</span> <span style="color:#ef6155">$1</span> in
</span></span><span style="display:flex;"><span>         0<span style="color:#5bc4bf">)</span> <span style="color:#ef6155">txt</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;*** More argument; just call the script as: ./convert_image /name_dir/ &#39;jpg2jpg|jpg2png|png2png&#39; ***&#34;</span> ;;
</span></span><span style="display:flex;"><span>         1<span style="color:#5bc4bf">)</span> <span style="color:#ef6155">txt</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;*** Directory needed! ***&#34;</span> ;;
</span></span><span style="display:flex;"><span>         2<span style="color:#5bc4bf">)</span> <span style="color:#ef6155">txt</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;*** argument &#39;jpg2jpg&#39;, &#39;jpg2png&#39; or &#39;png2png&#39; needed! ***&#34;</span> ;;
</span></span><span style="display:flex;"><span>         3<span style="color:#5bc4bf">)</span> <span style="color:#ef6155">txt</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;*** bad argument: argument is &#39;jpg2jpg&#39;, &#39;jpg2png&#39; or &#39;png2png&#39;! ***&#34;</span> ;;
</span></span><span style="display:flex;"><span>         4<span style="color:#5bc4bf">)</span> <span style="color:#ef6155">txt</span><span style="color:#5bc4bf">=</span><span style="color:#48b685">&#34;*** ERROR: Script stop here because the bin ***</span><span style="color:#ef6155">$2</span><span style="color:#48b685">*** is not installed; in </span><span style="color:#ef6155">$3</span><span style="color:#48b685">... ***&#34;</span> ;;
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">esac</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">if</span> test -n <span style="color:#48b685">&#34;</span><span style="color:#ef6155">$txt</span><span style="color:#48b685">&#34;</span>; <span style="color:#815ba4">then</span> echo <span style="color:#48b685">&#34;</span><span style="color:#ef6155">$txt</span><span style="color:#48b685">&#34;</span>; <span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    exit
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#815ba4">function</span> verify_args <span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">if</span> test -z <span style="color:#48b685">&#34;</span><span style="color:#ef6155">$1</span><span style="color:#48b685">&#34;</span>; <span style="color:#815ba4">then</span> status 1; <span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">if</span> <span style="color:#5bc4bf">[</span>! -d <span style="color:#ef6155">$1</span><span style="color:#5bc4bf">](</span>!_-d_<span style="color:#ef6155">$1</span><span style="color:#5bc4bf">)</span>; <span style="color:#815ba4">then</span> exit; <span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">if</span> test -z <span style="color:#48b685">&#34;</span><span style="color:#ef6155">$2</span><span style="color:#48b685">&#34;</span>; <span style="color:#815ba4">then</span> status 2; <span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">if</span> <span style="color:#5bc4bf">((</span> <span style="color:#ef6155">$2</span> !<span style="color:#5bc4bf">=</span> <span style="color:#48b685">&#34;jpg2jpg&#34;</span> <span style="color:#5bc4bf">||</span> <span style="color:#ef6155">$2</span> !<span style="color:#5bc4bf">=</span> <span style="color:#48b685">&#34;jpg2png&#34;</span> <span style="color:#5bc4bf">||</span> <span style="color:#ef6155">$2</span> !<span style="color:#5bc4bf">=</span> <span style="color:#48b685">&#34;png2png&#34;</span> <span style="color:#5bc4bf">))</span>; <span style="color:#815ba4">then</span> status 3; <span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#815ba4">function</span> verify_bin <span style="color:#5bc4bf">()</span> <span style="color:#5bc4bf">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    bin<span style="color:#5bc4bf">[</span>1<span style="color:#5bc4bf">]=</span><span style="color:#48b685">&#34;jpegtran&#34;</span>
</span></span><span style="display:flex;"><span>    bin<span style="color:#5bc4bf">[</span>2<span style="color:#5bc4bf">]=</span><span style="color:#48b685">&#34;mogrify&#34;</span>
</span></span><span style="display:flex;"><span>    bin<span style="color:#5bc4bf">[</span>3<span style="color:#5bc4bf">]=</span><span style="color:#48b685">&#34;gvfs-info&#34;</span>
</span></span><span style="display:flex;"><span>    get<span style="color:#5bc4bf">[</span>1<span style="color:#5bc4bf">]=</span><span style="color:#48b685">&#34;libjpeg&#34;</span>
</span></span><span style="display:flex;"><span>    get<span style="color:#5bc4bf">[</span>2<span style="color:#5bc4bf">]=</span><span style="color:#48b685">&#34;ImageMagick Tools&#34;</span>
</span></span><span style="display:flex;"><span>    get<span style="color:#5bc4bf">[</span>3<span style="color:#5bc4bf">]=</span><span style="color:#48b685">&#34;gvfs-bin&#34;</span>
</span></span><span style="display:flex;"><span>      
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">for</span> <span style="color:#5bc4bf">((</span> <span style="color:#ef6155">i</span><span style="color:#5bc4bf">=</span>1 ; i&lt;<span style="color:#5bc4bf">=</span>3 ; i++ <span style="color:#5bc4bf">))</span> <span style="color:#815ba4">do</span>
</span></span><span style="display:flex;"><span>         <span style="color:#815ba4">if</span> <span style="color:#5bc4bf">[[</span> ! -e <span style="color:#48b685">&#34;/usr/bin/</span><span style="color:#f99b15">${</span><span style="color:#ef6155">bin</span>[<span style="color:#ef6155">$i</span>]<span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> <span style="color:#5bc4bf">]]</span>; <span style="color:#815ba4">then</span> status 4 <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">bin</span>[<span style="color:#ef6155">$i</span>]<span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span> <span style="color:#48b685">&#34;</span><span style="color:#f99b15">${</span><span style="color:#ef6155">get</span>[<span style="color:#ef6155">$i</span>]<span style="color:#f99b15">}</span><span style="color:#48b685">&#34;</span>; <span style="color:#815ba4">fi</span>
</span></span><span style="display:flex;"><span>    <span style="color:#815ba4">done</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#5bc4bf">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#776e71"># appel to the function convert_image</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#815ba4">if</span> <span style="color:#5bc4bf">[</span> <span style="color:#ef6155">$#</span> -ne <span style="color:#48b685">&#34;</span><span style="color:#ef6155">$ARGS</span><span style="color:#48b685">&#34;</span> <span style="color:#5bc4bf">]</span>; <span style="color:#815ba4">then</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    status <span style="color:#f99b15">0</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#815ba4">else</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    convert_image <span style="color:#ef6155">$1</span> <span style="color:#ef6155">$2</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#815ba4">fi</span>
</span></span></code></pre></div><h2 id="utilisation">Utilisation</h2>
<p>Use as exemple:</p>
<p><code>$ chmod 0700 convert_image $ ./convert_image /name_dir/ option</code></p>
<hr>
]]></content><summary>Script bash to convert, optimize and minimize jpg or png image</summary><published>2017-07-24T16:56:42+01:00</published><updated>2017-07-28T12:34:17+01:00</updated></entry></feed>