{"@attributes":{"version":"2.0"},"channel":{"title":"Ryan Kavanagh's \/dev\/brain","link":"\/feeds\/planet-debian.xml","description":"Recent content for Ryan Kavanagh's \/dev\/brain","language":"en-CA","item":[{"title":"Battery charge start and stop threshold on OpenBSD","link":"\/blog\/2023-12-20-battery-charge-start-stop-threshold-on-openbsd\/","pubDate":"Wed, 20 Dec 2023 11:11:59 -0500","guid":"\/blog\/2023-12-20-battery-charge-start-stop-threshold-on-openbsd\/","description":"<p>I often use my laptops as portable desktops: they are plugged into AC\npower and an external monitor\/keyboard 95% of time. Unfortunately,\ncontinuous charging is hard on the battery. To mitigate this,\nThinkPads have customizable start and stop charging thresholds, such\nthat the battery will only start charging if its level falls below the\nstart threshold, and it will stop charging as soon as it reaches the\nstop threshold.  Suggested thresholds from Lenovo&rsquo;s battery team can\nbe found in this <a href=\"https:\/\/pointieststick.com\/2020\/06\/08\/lenovo-thinkpad-x1-yoga-impressions-bugs-workarounds-and-thoughts-about-the-future\/#comment-22688\">comment<\/a>.<\/p>\n<p>You can set these thresholds on Linux using\n<a href=\"https:\/\/manpages.debian.org\/unstable\/tlp\/tlp-stat.8.en.html\">tlp-stat(8)<\/a>, and you can make the values persist across\nreboots by setting <code>START_CHARGE_THRESH_BAT0<\/code> and\n<code>STOP_CHARGE_THERSH_BAT0<\/code> in <code>\/etc\/tlp.conf<\/code>.<\/p>\n<p>I recently installed OpenBSD on my work ThinkPad, but struggled to\nfind any information on how to set the thresholds under OpenBSD. After\nonly finding a <a href=\"https:\/\/www.mail-archive.com\/search?l=misc@openbsd.org&q=subject:%22Re%5C%3A+How+to+set+ThinkPad+battery+charge+thresholds%5C%3F%22&o=newest&f=1\">dead-end thread<\/a> from 2021 on misc@, I started\ndigging around on how to implement it myself. The <code>acpithinkpad<\/code> and\n<code>acpibat<\/code> drivers looked promising, and a bit of Google-fu lead me to\nthe following small announcement in the <a href=\"https:\/\/www.openbsd.org\/74.html\">OpenBSD 7.4 release\nnotes<\/a>:<\/p>\n<blockquote>\n<p>New sysctl(2) nodes for battery management,\nhw.battery.charge*. Support them with acpithinkpad(4) and aplsmc(4).<\/p>\n<\/blockquote>\n<p>Lo and behold, setting the start and stop threshold in OpenBSD is\nsimply a matter of setting <code>hw.battery.chargestart<\/code> and\n<code>hw.battery.chargestop<\/code> with <code>sysctl<\/code>. The documentation was not\n<a href=\"https:\/\/marc.info\/?l=openbsd-cvs&m=169730997126948\">committed<\/a> in time for the 7.4 release, but you can read it in\n-CURRENT&rsquo;s <a href=\"https:\/\/man.openbsd.org\/sysctl.2#HW_BATTERY~2\"><code>sysctl(2)<\/code><\/a>. I personally set the following values\nin <code>\/etc\/sysctl.conf<\/code>:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-fallback\" data-lang=\"fallback\"><span class=\"line\"><span class=\"cl\">hw.battery.chargestart=40\n<\/span><\/span><span class=\"line\"><span class=\"cl\">hw.battery.chargestop=60\n<\/span><\/span><\/code><\/pre><\/div>"},{"title":"Routable network addresses with OpenIKED and systemd-networkd","link":"\/blog\/2022-06-25-routable-network-addresses-openiked-systemd-networkd\/","pubDate":"Sat, 25 Jun 2022 07:41:37 -0400","guid":"\/blog\/2022-06-25-routable-network-addresses-openiked-systemd-networkd\/","description":"<p>I&rsquo;ve been using OpenIKED for some time now to configure my VPN.\nOne of its features is that it can dynamically assign addresses on the internal network to clients, and clients can assign these addresses and routes to interfaces.\nHowever, these interfaces must exist before <code>iked<\/code> can start.\nSome months ago I switched my Debian laptop&rsquo;s configuration from the traditional ifupdown to <code>systemd-networkd<\/code>.\nIt took me some time to figure out how to have <code>systemd-networkd<\/code> create dummy interfaces on which <code>iked<\/code> can install addresses, but also not interfere with <code>iked<\/code> by trying to manage these interfaces.\nHere is my working configuration.<\/p>\n<p>First, I have systemd create the interface <code>dummy1<\/code> by creating a <code>systemd.netdev(5)<\/code> configuration file at <code>\/etc\/systemd\/network\/20-dummy1.netdev<\/code>:<\/p>\n<pre><code>[NetDev]\nName=dummy1\nKind=dummy \n<\/code><\/pre>\n<p>Then I tell systemd not to manage this interface by creating a <code>systemd.network(5)<\/code> configuration file at <code>\/etc\/systemd\/network\/20-dummy1.network<\/code>:<\/p>\n<pre><code>[Match]\nName=dummy1\nUnmanaged=yes\n<\/code><\/pre>\n<p>Restarting systemd-networkd causes these interfaces to get created, and we can then check their status using <code>networkctl(8)<\/code>:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-shell\" data-lang=\"shell\"><span class=\"line\"><span class=\"cl\">$ systemctl restart systemd-networkd.service\n<\/span><\/span><span class=\"line\"><span class=\"cl\">$ networkctl\n<\/span><\/span><span class=\"line\"><span class=\"cl\">IDX LINK     TYPE     OPERATIONAL SETUP\n<\/span><\/span><span class=\"line\"><span class=\"cl\">  <span class=\"m\">1<\/span> lo       loopback carrier     unmanaged\n<\/span><\/span><span class=\"line\"><span class=\"cl\">  <span class=\"m\">2<\/span> enp2s0f0 ether    off         unmanaged\n<\/span><\/span><span class=\"line\"><span class=\"cl\">  <span class=\"m\">3<\/span> enp5s0   ether    off         unmanaged\n<\/span><\/span><span class=\"line\"><span class=\"cl\">  <span class=\"m\">4<\/span> dummy1   ether    degraded    configuring\n<\/span><\/span><span class=\"line\"><span class=\"cl\">  <span class=\"m\">5<\/span> dummy3   ether    degraded    configuring\n<\/span><\/span><span class=\"line\"><span class=\"cl\">  <span class=\"m\">6<\/span> sit0     sit      off         unmanaged\n<\/span><\/span><span class=\"line\"><span class=\"cl\">  <span class=\"m\">8<\/span> wlp3s0   wlan     routable    configured\n<\/span><\/span><span class=\"line\"><span class=\"cl\">  <span class=\"m\">9<\/span> he-ipv6  sit      routable    configured\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"m\">8<\/span> links listed.\n<\/span><\/span><\/code><\/pre><\/div><p>Finally, I configure my flows in <code>\/etc\/iked.conf<\/code>, making sure to assign the received address to the interface <code>dummy1<\/code>.<\/p>\n<pre><code>ikev2 'hades' active esp \\\n        from dynamic to 10.0.1.0\/24 \\\n        peer hades.rak.ac \\\n        srcid '\/CN=asteria.rak.ac' \\\n        dstid '\/CN=hades.rak.ac' \\\n        request address 10.0.1.103 \\\n        iface dummy1\n<\/code><\/pre>\n<p>Restarting openiked and checking the status of the interface reveals that it has been assigned an address on the internal network and that it is routable:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-shell\" data-lang=\"shell\"><span class=\"line\"><span class=\"cl\">$ systemctl restart openiked.service\n<\/span><\/span><span class=\"line\"><span class=\"cl\">$ networkctl status dummy1\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\u25cf 4: dummy1\n<\/span><\/span><span class=\"line\"><span class=\"cl\">                     Link File: \/usr\/lib\/systemd\/network\/99-default.link\n<\/span><\/span><span class=\"line\"><span class=\"cl\">                  Network File: \/etc\/systemd\/network\/20-dummy1.network\n<\/span><\/span><span class=\"line\"><span class=\"cl\">                          Type: ether\n<\/span><\/span><span class=\"line\"><span class=\"cl\">                          Kind: dummy\n<\/span><\/span><span class=\"line\"><span class=\"cl\">                         State: routable <span class=\"o\">(<\/span>configured<span class=\"o\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">                  Online state: online\n<\/span><\/span><span class=\"line\"><span class=\"cl\">                        Driver: dummy\n<\/span><\/span><span class=\"line\"><span class=\"cl\">              Hardware Address: 22:50:5f:98:a1:a9\n<\/span><\/span><span class=\"line\"><span class=\"cl\">                           MTU: <span class=\"m\">1500<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">                         QDisc: noqueue\n<\/span><\/span><span class=\"line\"><span class=\"cl\">  IPv6 Address Generation Mode: eui64\n<\/span><\/span><span class=\"line\"><span class=\"cl\">          Queue Length <span class=\"o\">(<\/span>Tx\/Rx<span class=\"o\">)<\/span>: 1\/1\n<\/span><\/span><span class=\"line\"><span class=\"cl\">                       Address: 10.0.1.103\n<\/span><\/span><span class=\"line\"><span class=\"cl\">                                fe80::2050:5fff:fe98:a1a9\n<\/span><\/span><span class=\"line\"><span class=\"cl\">                           DNS: 10.0.1.1\n<\/span><\/span><span class=\"line\"><span class=\"cl\">                 Route Domains: .\n<\/span><\/span><span class=\"line\"><span class=\"cl\">             Activation Policy: up\n<\/span><\/span><span class=\"line\"><span class=\"cl\">           Required For Online: yes\n<\/span><\/span><span class=\"line\"><span class=\"cl\">             DHCP6 Client DUID: DUID-EN\/Vendor:0000ab11aafa4f02d6ac68d40000\n<\/span><\/span><\/code><\/pre><\/div><p>I&rsquo;d be happy to hear if there are simpler or more idiomatic ways to configure this under systemd.<\/p>\n"},{"title":"Writing BASIC-8 on the TSS\/8","link":"\/blog\/2021-04-07-writing-basic-8-on-the-tss-8\/","pubDate":"Wed, 07 Apr 2021 20:08:52 -0400","guid":"\/blog\/2021-04-07-writing-basic-8-on-the-tss-8\/","description":"<p>I recently discovered <a href=\"https:\/\/sdf.org\">SDF<\/a>&rsquo;s <a href=\"https:\/\/tss8.sdf.org\/\">PiDP-8<\/a>.\nYou can access it over SSH and watch the blinkenlights over its <a href=\"https:\/\/twitch.tv\/sdfpubnix\">twitch stream<\/a>.\nIt runs TSS\/8, a time-sharing operating system written in 1967 by Adrian van de Goor while a grad student here at CMU.\nI&rsquo;ve been having fun tinkering with it, and I just wrote my first BASIC program<sup id=\"fnref:1\"><a href=\"#fn:1\" class=\"footnote-ref\" role=\"doc-noteref\">1<\/a><\/sup> since high school.\nIt plots the graph of some user-specified univariate function.\nI don&rsquo;t claim that it&rsquo;s elegant or well-engineered, but it works!<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-basic\" data-lang=\"basic\"><span class=\"line\"><span class=\"cl\"><span class=\"nl\">10<\/span><span class=\"w\">  <\/span><span class=\"kr\">DEF<\/span><span class=\"w\"> <\/span><span class=\"vg\">FNC<\/span><span class=\"p\">(<\/span><span class=\"vg\">X<\/span><span class=\"p\">)<\/span><span class=\"w\"> <\/span><span class=\"o\">=<\/span><span class=\"w\"> <\/span><span class=\"il\">19<\/span><span class=\"w\"> <\/span><span class=\"o\">*<\/span><span class=\"w\"> <\/span><span class=\"kr\">COS<\/span><span class=\"p\">(<\/span><span class=\"vg\">X<\/span><span class=\"o\">\/<\/span><span class=\"il\">2<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nl\">20<\/span><span class=\"w\">  <\/span><span class=\"kr\">FOR<\/span><span class=\"w\"> <\/span><span class=\"vg\">Y<\/span><span class=\"w\"> <\/span><span class=\"o\">=<\/span><span class=\"w\"> <\/span><span class=\"il\">20<\/span><span class=\"w\"> <\/span><span class=\"k\">TO<\/span><span class=\"w\"> <\/span><span class=\"il\">-20<\/span><span class=\"w\"> <\/span><span class=\"k\">STEP<\/span><span class=\"w\"> <\/span><span class=\"il\">-1<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nl\">30<\/span><span class=\"w\">     <\/span><span class=\"kr\">FOR<\/span><span class=\"w\"> <\/span><span class=\"vg\">X<\/span><span class=\"w\"> <\/span><span class=\"o\">=<\/span><span class=\"w\"> <\/span><span class=\"il\">-25<\/span><span class=\"w\"> <\/span><span class=\"k\">TO<\/span><span class=\"w\"> <\/span><span class=\"il\">24<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nl\">40<\/span><span class=\"w\">     <\/span><span class=\"kd\">LET<\/span><span class=\"w\"> <\/span><span class=\"vg\">V<\/span><span class=\"w\"> <\/span><span class=\"o\">=<\/span><span class=\"w\"> <\/span><span class=\"vg\">FNC<\/span><span class=\"p\">(<\/span><span class=\"vg\">X<\/span><span class=\"p\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nl\">50<\/span><span class=\"w\">     <\/span><span class=\"kr\">GOSUB<\/span><span class=\"w\"> <\/span><span class=\"nl\">90<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nl\">60<\/span><span class=\"w\">  <\/span><span class=\"kr\">NEXT<\/span><span class=\"w\"> <\/span><span class=\"vg\">X<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nl\">70<\/span><span class=\"w\">  <\/span><span class=\"kr\">PRINT<\/span><span class=\"w\"> <\/span><span class=\"s2\">&#34;&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nl\">80<\/span><span class=\"w\">  <\/span><span class=\"kr\">NEXT<\/span><span class=\"w\"> <\/span><span class=\"vg\">Y<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nl\">85<\/span><span class=\"w\">  <\/span><span class=\"kr\">STOP<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nl\">90<\/span><span class=\"w\">  <\/span><span class=\"c1\">REM SUBROUTINE PRINTS AXES AND PLOT<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nl\">100<\/span><span class=\"w\"> <\/span><span class=\"kr\">IF<\/span><span class=\"w\"> <\/span><span class=\"vg\">X<\/span><span class=\"w\"> <\/span><span class=\"o\">=<\/span><span class=\"w\"> <\/span><span class=\"il\">0<\/span><span class=\"w\"> <\/span><span class=\"kr\">THEN<\/span><span class=\"w\"> <\/span><span class=\"il\">150<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nl\">110<\/span><span class=\"w\"> <\/span><span class=\"kr\">IF<\/span><span class=\"w\"> <\/span><span class=\"vg\">Y<\/span><span class=\"w\"> <\/span><span class=\"o\">=<\/span><span class=\"w\"> <\/span><span class=\"il\">0<\/span><span class=\"w\"> <\/span><span class=\"kr\">THEN<\/span><span class=\"w\"> <\/span><span class=\"il\">150<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nl\">120<\/span><span class=\"w\"> <\/span><span class=\"c1\">REM X != 0 AND Y != 0 SO IN QUADRANT<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nl\">130<\/span><span class=\"w\"> <\/span><span class=\"kr\">GOSUB<\/span><span class=\"w\"> <\/span><span class=\"nl\">290<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nl\">140<\/span><span class=\"w\"> <\/span><span class=\"kr\">RETURN<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nl\">150<\/span><span class=\"w\"> <\/span><span class=\"kr\">GOSUB<\/span><span class=\"w\"> <\/span><span class=\"nl\">170<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nl\">160<\/span><span class=\"w\"> <\/span><span class=\"kr\">RETURN<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nl\">170<\/span><span class=\"w\"> <\/span><span class=\"c1\">REM SUBROUTINE PRINTS AXES (X = 0 OR Y = 0)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nl\">180<\/span><span class=\"w\"> <\/span><span class=\"kr\">IF<\/span><span class=\"w\"> <\/span><span class=\"vg\">X<\/span><span class=\"w\"> <\/span><span class=\"o\">+<\/span><span class=\"w\"> <\/span><span class=\"vg\">Y<\/span><span class=\"w\"> <\/span><span class=\"o\">=<\/span><span class=\"w\"> <\/span><span class=\"il\">0<\/span><span class=\"w\"> <\/span><span class=\"kr\">THEN<\/span><span class=\"w\"> <\/span><span class=\"il\">230<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nl\">190<\/span><span class=\"w\"> <\/span><span class=\"kr\">IF<\/span><span class=\"w\"> <\/span><span class=\"vg\">X<\/span><span class=\"w\"> <\/span><span class=\"o\">=<\/span><span class=\"w\"> <\/span><span class=\"il\">0<\/span><span class=\"w\"> <\/span><span class=\"kr\">THEN<\/span><span class=\"w\"> <\/span><span class=\"il\">250<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nl\">200<\/span><span class=\"w\"> <\/span><span class=\"kr\">IF<\/span><span class=\"w\"> <\/span><span class=\"vg\">Y<\/span><span class=\"w\"> <\/span><span class=\"o\">=<\/span><span class=\"w\"> <\/span><span class=\"il\">0<\/span><span class=\"w\"> <\/span><span class=\"kr\">THEN<\/span><span class=\"w\"> <\/span><span class=\"il\">270<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nl\">210<\/span><span class=\"w\"> <\/span><span class=\"kr\">PRINT<\/span><span class=\"w\"> <\/span><span class=\"s2\">&#34;AXES INVARIANT VIOLATED&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nl\">220<\/span><span class=\"w\"> <\/span><span class=\"kr\">STOP<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nl\">230<\/span><span class=\"w\"> <\/span><span class=\"kr\">PRINT<\/span><span class=\"w\"> <\/span><span class=\"s2\">&#34;+&#34;<\/span><span class=\"p\">;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nl\">240<\/span><span class=\"w\"> <\/span><span class=\"kr\">GOTO<\/span><span class=\"w\"> <\/span><span class=\"nl\">280<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nl\">250<\/span><span class=\"w\"> <\/span><span class=\"kr\">PRINT<\/span><span class=\"w\"> <\/span><span class=\"s2\">&#34;I&#34;<\/span><span class=\"p\">;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nl\">260<\/span><span class=\"w\"> <\/span><span class=\"kr\">GOTO<\/span><span class=\"w\"> <\/span><span class=\"nl\">280<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nl\">270<\/span><span class=\"w\"> <\/span><span class=\"kr\">PRINT<\/span><span class=\"w\"> <\/span><span class=\"s2\">&#34;-&#34;<\/span><span class=\"p\">;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nl\">280<\/span><span class=\"w\"> <\/span><span class=\"kr\">RETURN<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nl\">290<\/span><span class=\"w\"> <\/span><span class=\"c1\">REM SUBROUTINE PRINTS FUNCTION GRAPH (X != 0 AND Y != 0)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nl\">300<\/span><span class=\"w\"> <\/span><span class=\"kr\">IF<\/span><span class=\"w\"> <\/span><span class=\"il\">0<\/span><span class=\"w\"> <\/span><span class=\"o\">&lt;=<\/span><span class=\"w\"> <\/span><span class=\"vg\">Y<\/span><span class=\"w\"> <\/span><span class=\"kr\">THEN<\/span><span class=\"w\"> <\/span><span class=\"il\">350<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nl\">310<\/span><span class=\"w\"> <\/span><span class=\"c1\">REM Y &lt; 0<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nl\">320<\/span><span class=\"w\"> <\/span><span class=\"kr\">IF<\/span><span class=\"w\"> <\/span><span class=\"vg\">V<\/span><span class=\"w\"> <\/span><span class=\"o\">&lt;=<\/span><span class=\"w\"> <\/span><span class=\"vg\">Y<\/span><span class=\"w\"> <\/span><span class=\"kr\">THEN<\/span><span class=\"w\"> <\/span><span class=\"il\">410<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nl\">330<\/span><span class=\"w\"> <\/span><span class=\"c1\">REM Y &lt; 0 AND Y &lt; V SO OUTSIDE OF PLOT AREA<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nl\">340<\/span><span class=\"w\"> <\/span><span class=\"kr\">GOTO<\/span><span class=\"w\"> <\/span><span class=\"nl\">390<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nl\">350<\/span><span class=\"w\"> <\/span><span class=\"c1\">REM 0 &lt;= Y<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nl\">360<\/span><span class=\"w\"> <\/span><span class=\"kr\">IF<\/span><span class=\"w\"> <\/span><span class=\"vg\">Y<\/span><span class=\"w\"> <\/span><span class=\"o\">&lt;=<\/span><span class=\"w\"> <\/span><span class=\"vg\">V<\/span><span class=\"w\"> <\/span><span class=\"kr\">THEN<\/span><span class=\"w\"> <\/span><span class=\"il\">410<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nl\">370<\/span><span class=\"w\"> <\/span><span class=\"c1\">REM 0 &lt;= Y  AND V &lt; Y SO OUTSIDE OF PLOT AREA<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nl\">380<\/span><span class=\"w\"> <\/span><span class=\"kr\">GOTO<\/span><span class=\"w\"> <\/span><span class=\"nl\">390<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nl\">390<\/span><span class=\"w\"> <\/span><span class=\"kr\">PRINT<\/span><span class=\"w\"> <\/span><span class=\"s2\">&#34; &#34;<\/span><span class=\"p\">;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nl\">400<\/span><span class=\"w\"> <\/span><span class=\"kr\">RETURN<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nl\">410<\/span><span class=\"w\"> <\/span><span class=\"kr\">PRINT<\/span><span class=\"w\"> <\/span><span class=\"s2\">&#34;*&#34;<\/span><span class=\"p\">;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nl\">420<\/span><span class=\"w\"> <\/span><span class=\"kr\">RETURN<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nl\">430<\/span><span class=\"w\"> <\/span><span class=\"c1\">REM COPYRIGHT 2021 RYAN KAVANAGH RAK AT RAK.AC<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nl\">440<\/span><span class=\"w\"> <\/span><span class=\"kr\">END<\/span>\n<\/span><\/span><\/code><\/pre><\/div><p>It produces the following output:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-fallback\" data-lang=\"fallback\"><span class=\"line\"><span class=\"cl\">                         I\n<\/span><\/span><span class=\"line\"><span class=\"cl\">                         I\n<\/span><\/span><span class=\"line\"><span class=\"cl\">*           **           I           **\n<\/span><\/span><span class=\"line\"><span class=\"cl\">*           **           I           **\n<\/span><\/span><span class=\"line\"><span class=\"cl\">**          **          *I*          **          *\n<\/span><\/span><span class=\"line\"><span class=\"cl\">**          **          *I*          **          *\n<\/span><\/span><span class=\"line\"><span class=\"cl\">**         ***          *I*          ***         *\n<\/span><\/span><span class=\"line\"><span class=\"cl\">**         ****         *I*         ****         *\n<\/span><\/span><span class=\"line\"><span class=\"cl\">**         ****         *I*         ****         *\n<\/span><\/span><span class=\"line\"><span class=\"cl\">**         ****         *I*         ****         *\n<\/span><\/span><span class=\"line\"><span class=\"cl\">**         ****        **I**        ****         *\n<\/span><\/span><span class=\"line\"><span class=\"cl\">***        ****        **I**        ****        **\n<\/span><\/span><span class=\"line\"><span class=\"cl\">***        ****        **I**        ****        **\n<\/span><\/span><span class=\"line\"><span class=\"cl\">***        ****        **I**        ****        **\n<\/span><\/span><span class=\"line\"><span class=\"cl\">***       *****        **I**        *****       **\n<\/span><\/span><span class=\"line\"><span class=\"cl\">***       ******       **I**       ******       **\n<\/span><\/span><span class=\"line\"><span class=\"cl\">***       ******       **I**       ******       **\n<\/span><\/span><span class=\"line\"><span class=\"cl\">***       ******       **I**       ******       **\n<\/span><\/span><span class=\"line\"><span class=\"cl\">***       ******       **I**       ******       **\n<\/span><\/span><span class=\"line\"><span class=\"cl\">***       ******      ***I***      ******       **\n<\/span><\/span><span class=\"line\"><span class=\"cl\">-------------------------+------------------------\n<\/span><\/span><span class=\"line\"><span class=\"cl\">    ******      ******   I   ******      ******\n<\/span><\/span><span class=\"line\"><span class=\"cl\">    ******      ******   I   ******      ******\n<\/span><\/span><span class=\"line\"><span class=\"cl\">    *****       ******   I   ******       *****\n<\/span><\/span><span class=\"line\"><span class=\"cl\">    *****       ******   I   ******       *****\n<\/span><\/span><span class=\"line\"><span class=\"cl\">    *****        *****   I   *****        *****\n<\/span><\/span><span class=\"line\"><span class=\"cl\">    *****        *****   I   *****        *****\n<\/span><\/span><span class=\"line\"><span class=\"cl\">    *****        *****   I   *****        *****\n<\/span><\/span><span class=\"line\"><span class=\"cl\">    *****        ****    I    ****        *****\n<\/span><\/span><span class=\"line\"><span class=\"cl\">    *****        ****    I    ****        *****\n<\/span><\/span><span class=\"line\"><span class=\"cl\">     ****        ****    I    ****        ****\n<\/span><\/span><span class=\"line\"><span class=\"cl\">     ****        ****    I    ****        ****\n<\/span><\/span><span class=\"line\"><span class=\"cl\">     ***         ****    I    ****         ***\n<\/span><\/span><span class=\"line\"><span class=\"cl\">     ***          ***    I    ***          ***\n<\/span><\/span><span class=\"line\"><span class=\"cl\">     ***          ***    I    ***          ***\n<\/span><\/span><span class=\"line\"><span class=\"cl\">     ***          ***    I    ***          ***\n<\/span><\/span><span class=\"line\"><span class=\"cl\">      **          **     I     **          **\n<\/span><\/span><span class=\"line\"><span class=\"cl\">      **          **     I     **          **\n<\/span><\/span><span class=\"line\"><span class=\"cl\">      *            *     I     *            *\n<\/span><\/span><span class=\"line\"><span class=\"cl\">                         I\n<\/span><\/span><span class=\"line\"><span class=\"cl\">                         I\n<\/span><\/span><\/code><\/pre><\/div><p>Next up, I am going to try my hand at writing some FORTRAN or some FOCAL69.\nIf you like tinkering with old systems, then you should give the TSS\/8 a try.<\/p>\n<div class=\"footnotes\" role=\"doc-endnotes\">\n<hr>\n<ol>\n<li id=\"fn:1\">\n<p>It&rsquo;s written in the <a href=\"https:\/\/tss8.sdf.org\/docu\/DEC-T8-KJZA-D-TSS-8_BASIC_8_Programming_Manual_Mar1969.pdf\">BASIC-8<\/a> dialect.&#160;<a href=\"#fnref:1\" class=\"footnote-backref\" role=\"doc-backlink\">&#x21a9;&#xfe0e;<\/a><\/p>\n<\/li>\n<\/ol>\n<\/div>\n"},{"title":"Static Comments in Hugo","link":"\/blog\/2021-03-12-static-comments-in-hugo\/","pubDate":"Fri, 12 Mar 2021 13:32:34 -0500","guid":"\/blog\/2021-03-12-static-comments-in-hugo\/","description":"<p>I switched from <a href=\"https:\/\/jekyllrb.com\/\">Jekyll<\/a> to <a href=\"https:\/\/gohugo.io\/\">Hugo<\/a> last week for a variety of reasons.\nOne thing that was missing was a port of the &ldquo;<a href=\"https:\/\/github.com\/mpalmer\/jekyll-static-comments\">jekyll-static-comments<\/a>&rdquo; plugin that I used to use.\nI liked it because it saved readers from being tracked by Disqus or other comments solutions, and it required no javascript.<\/p>\n<p>To comment, users would email me their comment following a template attached to the bottom of each post.\nI then piped their email through a script to add it to the right post.\nAs an added benefit, I could delegate comment spam detection to my mail server.<\/p>\n<p>I&rsquo;ve managed to reimplement this setup using Hugo.\nFor those who are interested in a similar setup, here is what you need to do.<\/p>\n<h2 id=\"pages-with-comments\">Pages with comments<\/h2>\n<p>Instead of being single files, pages need to be <a href=\"https:\/\/gohugo.io\/content-management\/page-bundles\/\">leaf bundles<\/a>.\nFor example, this means that your blog post must be located at <code>\/content\/blog\/2021-03-12-static-comments-in-hugo\/index.md<\/code> instead of <code>\/content\/blog\/2021-03-12-static-comments-in-hugo.md<\/code>.\nThis lets you store the comments as page resources in the subdirectory <code>\/content\/blog\/2021-03-12-static-comments-in-hugo\/comments\/<\/code>.<\/p>\n<h2 id=\"partials\">Partials<\/h2>\n<p>You should create a <code>comments.html<\/code> partial and include it in the layout for the pages which should get comments:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-html\" data-lang=\"html\"><span class=\"line\"><span class=\"cl\"><span class=\"p\">&lt;<\/span><span class=\"nt\">div<\/span> <span class=\"na\">class<\/span><span class=\"o\">=<\/span><span class=\"s\">&#34;post-comments&#34;<\/span><span class=\"p\">&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">  <span class=\"p\">&lt;<\/span><span class=\"nt\">p<\/span> <span class=\"na\">class<\/span><span class=\"o\">=<\/span><span class=\"s\">&#34;comment-notice&#34;<\/span><span class=\"p\">&gt;&lt;<\/span><span class=\"nt\">b<\/span><span class=\"p\">&gt;<\/span>Comments<span class=\"p\">&lt;\/<\/span><span class=\"nt\">b<\/span><span class=\"p\">&gt;<\/span>: To comment on this post,\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\tsend me an email following the template below. Your email address\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\twill not be posted, unless you choose to include it in\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\tthe <span class=\"p\">&lt;<\/span><span class=\"nt\">span<\/span> <span class=\"na\">style<\/span><span class=\"o\">=<\/span><span class=\"s\">&#34;font-family: monospace;&#34;<\/span><span class=\"p\">&gt;<\/span>link:<span class=\"p\">&lt;\/<\/span><span class=\"nt\">span<\/span><span class=\"p\">&gt;<\/span> field.<span class=\"p\">&lt;\/<\/span><span class=\"nt\">p<\/span><span class=\"p\">&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">  <span class=\"p\">&lt;<\/span><span class=\"nt\">pre<\/span> <span class=\"na\">class<\/span><span class=\"o\">=<\/span><span class=\"s\">&#34;comment-notice&#34;<\/span><span class=\"p\">&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">To: Your Name <span class=\"ni\">&amp;lt;<\/span>your.email<span class=\"p\">&lt;<\/span><span class=\"nt\">span<\/span><span class=\"p\">&gt;<\/span>@<span class=\"p\">&lt;\/<\/span><span class=\"nt\">span<\/span><span class=\"p\">&gt;<\/span>example.org<span class=\"ni\">&amp;gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">Subject: [blog-comment] {{ .Page.RelPermalink }}\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\">post_id: {{ .Page.RelPermalink }}\n<\/span><\/span><span class=\"line\"><span class=\"cl\">author: [How should you be identified? Usually your name or &#34;Anonymous&#34;]\n<\/span><\/span><span class=\"line\"><span class=\"cl\">link: [optional link to your website]\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\">Your comments here. Markdown syntax accepted.<span class=\"p\">&lt;\/<\/span><span class=\"nt\">pre<\/span><span class=\"p\">&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\">  {{ $scratch := newScratch }}\n<\/span><\/span><span class=\"line\"><span class=\"cl\">  {{ $scratch.Set &#34;comments&#34; (.Resources.Match &#34;comments\/*yml&#34;) }}\n<\/span><\/span><span class=\"line\"><span class=\"cl\">  {{ if eq 1 (len ($scratch.Get &#34;comments&#34;)) }}\n<\/span><\/span><span class=\"line\"><span class=\"cl\">  <span class=\"p\">&lt;<\/span><span class=\"nt\">h2<\/span><span class=\"p\">&gt;<\/span>1 Comment<span class=\"p\">&lt;\/<\/span><span class=\"nt\">h2<\/span><span class=\"p\">&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">  {{ else }}\n<\/span><\/span><span class=\"line\"><span class=\"cl\">  <span class=\"p\">&lt;<\/span><span class=\"nt\">h2<\/span><span class=\"p\">&gt;<\/span>{{ len ($scratch.Get &#34;comments&#34;) }} Comments<span class=\"p\">&lt;\/<\/span><span class=\"nt\">h2<\/span><span class=\"p\">&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">  {{ end }}\n<\/span><\/span><span class=\"line\"><span class=\"cl\">  {{ range ($scratch.Get &#34;comments&#34;) }}\n<\/span><\/span><span class=\"line\"><span class=\"cl\">  <span class=\"p\">&lt;<\/span><span class=\"nt\">div<\/span> <span class=\"na\">class<\/span><span class=\"o\">=<\/span><span class=\"s\">&#34;post-comment {% cycle &#39;odd&#39;, &#39;even&#39; %}&#34;<\/span><span class=\"p\">&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\t{{ $comment := (.Content | transform.Unmarshal) }}\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\t<span class=\"p\">&lt;<\/span><span class=\"nt\">span<\/span> <span class=\"na\">class<\/span><span class=\"o\">=<\/span><span class=\"s\">&#34;post-meta&#34;<\/span><span class=\"p\">&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\t\t{{- $comment.date | dateFormat &#34;Jan 2, 2006 at 15:04&#34; -}}\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\t<span class=\"p\">&lt;\/<\/span><span class=\"nt\">span<\/span><span class=\"p\">&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\t<span class=\"p\">&lt;<\/span><span class=\"nt\">h3<\/span> <span class=\"na\">class<\/span><span class=\"o\">=<\/span><span class=\"s\">&#34;comment-header&#34;<\/span><span class=\"p\">&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\t  {{ if $comment.link }}\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\t  <span class=\"p\">&lt;<\/span><span class=\"nt\">a<\/span> <span class=\"na\">href<\/span><span class=\"o\">=<\/span><span class=\"s\">&#34;{{ $comment.link }}&#34;<\/span><span class=\"p\">&gt;<\/span>{{ $comment.author }}<span class=\"p\">&lt;\/<\/span><span class=\"nt\">a<\/span><span class=\"p\">&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\t  {{ else }}\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\t  {{ $comment.author }}\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\t  {{ end }}\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\t  <span class=\"p\">&lt;<\/span><span class=\"nt\">br<\/span> <span class=\"p\">\/&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\t<span class=\"p\">&lt;\/<\/span><span class=\"nt\">h3<\/span><span class=\"p\">&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\t{{ $comment.comment | markdownify }}\n<\/span><\/span><span class=\"line\"><span class=\"cl\">  <span class=\"p\">&lt;\/<\/span><span class=\"nt\">div<\/span><span class=\"p\">&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">  {{ end }}\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"p\">&lt;\/<\/span><span class=\"nt\">div<\/span><span class=\"p\">&gt;<\/span>\n<\/span><\/span><\/code><\/pre><\/div><h2 id=\"comments\">Comments<\/h2>\n<p>To associate comments received by email to posts, I pipe them from mutt (using the <code>|<\/code> keybinding) to the following (admittedly janky) shell script.\nIt takes the comment, reformats it appropriately, and puts it in the post&rsquo;s <code>comments<\/code> subdirectory.\nNote that it determines which filename to use based on the email&rsquo;s contents, so make sure to check that the email doesn&rsquo;t contain anything nefarious before you pipe it into the script!<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-sh\" data-lang=\"sh\"><span class=\"line\"><span class=\"cl\"><span class=\"cp\">#!\/bin\/sh\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"cp\"><\/span><span class=\"c1\"># Copyright (C) 2016-2021 Ryan Kavanagh &lt;rak@rak.ac&gt;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># Distributed under the ISC license<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nv\">BLOG_BASE<\/span><span class=\"o\">=<\/span><span class=\"s2\">&#34;\/media\/t\/work\/blog&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nv\">MESSAGE<\/span><span class=\"o\">=<\/span><span class=\"k\">$(<\/span>cat<span class=\"k\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nv\">EMAIL<\/span><span class=\"o\">=<\/span><span class=\"k\">$(<\/span><span class=\"nb\">echo<\/span> <span class=\"s2\">&#34;<\/span><span class=\"si\">${<\/span><span class=\"nv\">MESSAGE<\/span><span class=\"si\">}<\/span><span class=\"s2\">&#34;<\/span> <span class=\"p\">|<\/span> grep <span class=\"s2\">&#34;From:&#34;<\/span> <span class=\"p\">|<\/span> sed -e <span class=\"s1\">&#39;s\/From[^&lt;]*&lt;\\?\\([^&gt;]*\\)&gt;\\?.*\/\\1\/g;s\/@\/-at-\/g&#39;<\/span><span class=\"k\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nv\">DATE<\/span><span class=\"o\">=<\/span><span class=\"k\">$(<\/span><span class=\"nb\">echo<\/span> <span class=\"s2\">&#34;<\/span><span class=\"si\">${<\/span><span class=\"nv\">MESSAGE<\/span><span class=\"si\">}<\/span><span class=\"s2\">&#34;<\/span> <span class=\"p\">|<\/span> grep <span class=\"s2\">&#34;Date:&#34;<\/span> <span class=\"p\">|<\/span> sed -e <span class=\"s1\">&#39;s\/Date:\\s*\/\/g&#39;<\/span> <span class=\"p\">|<\/span> xargs -0 date -Iseconds -u -d<span class=\"k\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nv\">POST_ID<\/span><span class=\"o\">=<\/span><span class=\"k\">$(<\/span><span class=\"nb\">echo<\/span> <span class=\"s2\">&#34;<\/span><span class=\"si\">${<\/span><span class=\"nv\">MESSAGE<\/span><span class=\"si\">}<\/span><span class=\"s2\">&#34;<\/span> <span class=\"p\">|<\/span> grep <span class=\"s2\">&#34;post_id:&#34;<\/span> <span class=\"p\">|<\/span> sed -e <span class=\"s1\">&#39;s\/post_id: \/\/g&#39;<\/span><span class=\"k\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nv\">COMMENTS_DIR<\/span><span class=\"o\">=<\/span><span class=\"s2\">&#34;<\/span><span class=\"si\">${<\/span><span class=\"nv\">BLOG_BASE<\/span><span class=\"si\">}<\/span><span class=\"s2\">\/content\/<\/span><span class=\"si\">${<\/span><span class=\"nv\">POST_ID<\/span><span class=\"si\">}<\/span><span class=\"s2\">\/comments\/&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nv\">COMMENT_FILE<\/span><span class=\"o\">=<\/span><span class=\"s2\">&#34;<\/span><span class=\"si\">${<\/span><span class=\"nv\">COMMENTS_DIR<\/span><span class=\"si\">}<\/span><span class=\"s2\">\/<\/span><span class=\"si\">${<\/span><span class=\"nv\">DATE<\/span><span class=\"si\">}<\/span><span class=\"s2\">_<\/span><span class=\"si\">${<\/span><span class=\"nv\">EMAIL<\/span><span class=\"si\">}<\/span><span class=\"s2\">.yml&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># Strip out the email headers and whitespace until the start of the comment<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nv\">COMMENT_WHOLE<\/span><span class=\"o\">=<\/span><span class=\"k\">$(<\/span><span class=\"nb\">echo<\/span> <span class=\"s2\">&#34;<\/span><span class=\"si\">${<\/span><span class=\"nv\">MESSAGE<\/span><span class=\"si\">}<\/span><span class=\"s2\">&#34;<\/span> <span class=\"p\">|<\/span> sed -e <span class=\"s1\">&#39;\/^\\s*$\/,$!d;\/^[^\\s]\/,$!d&#39;<\/span><span class=\"k\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># Indent everything after the comment header<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nv\">COMMENT_INDENTED<\/span><span class=\"o\">=<\/span><span class=\"k\">$(<\/span><span class=\"nb\">echo<\/span> <span class=\"s2\">&#34;<\/span><span class=\"si\">${<\/span><span class=\"nv\">COMMENT_WHOLE<\/span><span class=\"si\">}<\/span><span class=\"s2\">&#34;<\/span> <span class=\"p\">|<\/span> sed -e <span class=\"s1\">&#39;\/^\\s*$\/,${s\/.*\/  &amp;\/g}&#39;<\/span><span class=\"k\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># And add the comment header<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nv\">COMMENT_PREFIXED<\/span><span class=\"o\">=<\/span><span class=\"k\">$(<\/span><span class=\"nb\">echo<\/span> <span class=\"s2\">&#34;<\/span><span class=\"si\">${<\/span><span class=\"nv\">COMMENT_INDENTED<\/span><span class=\"si\">}<\/span><span class=\"s2\">&#34;<\/span> <span class=\"p\">|<\/span> sed -e <span class=\"s1\">&#39;0,\/^\\s*$\/{s\/^\\s*$\/comment: |\/}&#39;<\/span><span class=\"k\">)<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"o\">[<\/span> -d <span class=\"s2\">&#34;<\/span><span class=\"si\">${<\/span><span class=\"nv\">COMMENTS_DIR<\/span><span class=\"si\">}<\/span><span class=\"s2\">&#34;<\/span> <span class=\"o\">]<\/span> <span class=\"o\">||<\/span> mkdir -p <span class=\"s2\">&#34;<\/span><span class=\"si\">${<\/span><span class=\"nv\">COMMENTS_DIR<\/span><span class=\"si\">}<\/span><span class=\"s2\">&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nb\">echo<\/span> <span class=\"s2\">&#34;Saving the comment to <\/span><span class=\"si\">${<\/span><span class=\"nv\">COMMENT_FILE<\/span><span class=\"si\">}<\/span><span class=\"s2\">&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nb\">echo<\/span> <span class=\"s2\">&#34;date: <\/span><span class=\"si\">${<\/span><span class=\"nv\">DATE<\/span><span class=\"si\">}<\/span><span class=\"s2\">&#34;<\/span> <span class=\"p\">|<\/span> tee <span class=\"s2\">&#34;<\/span><span class=\"si\">${<\/span><span class=\"nv\">COMMENT_FILE<\/span><span class=\"si\">}<\/span><span class=\"s2\">&#34;<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"nb\">echo<\/span> <span class=\"s2\">&#34;<\/span><span class=\"si\">${<\/span><span class=\"nv\">COMMENT_PREFIXED<\/span><span class=\"si\">}<\/span><span class=\"s2\">&#34;<\/span> <span class=\"p\">|<\/span> tee -a <span class=\"s2\">&#34;<\/span><span class=\"si\">${<\/span><span class=\"nv\">COMMENT_FILE<\/span><span class=\"si\">}<\/span><span class=\"s2\">&#34;<\/span>\n<\/span><\/span><\/code><\/pre><\/div><p>For example, the following comment in an email body:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-mysql\" data-lang=\"mysql\"><span class=\"line\"><span class=\"cl\"><span class=\"n\">post_id<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"o\">\/<\/span><span class=\"n\">blog<\/span><span class=\"o\">\/<\/span><span class=\"mi\">2021<\/span><span class=\"o\">-<\/span><span class=\"mi\">03<\/span><span class=\"o\">-<\/span><span class=\"mi\">12<\/span><span class=\"o\">-<\/span><span class=\"n\">static<\/span><span class=\"o\">-<\/span><span class=\"n\">comments<\/span><span class=\"o\">-<\/span><span class=\"k\">in<\/span><span class=\"o\">-<\/span><span class=\"n\">hugo<\/span><span class=\"o\">\/<\/span><span class=\"w\">\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"w\"><\/span><span class=\"n\">author<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"n\">Ryan<\/span><span class=\"w\"> <\/span><span class=\"n\">Kavanagh<\/span><span class=\"w\">\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"w\"><\/span><span class=\"n\">link<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"n\">https<\/span><span class=\"p\">:<\/span><span class=\"o\">\/\/<\/span><span class=\"n\">rak<\/span><span class=\"p\">.<\/span><span class=\"n\">ac<\/span><span class=\"o\">\/<\/span><span class=\"w\">\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"w\">\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"w\"><\/span><span class=\"n\">Dear<\/span><span class=\"w\"> <\/span><span class=\"n\">self<\/span><span class=\"p\">,<\/span><span class=\"w\">\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"w\">\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"w\"><\/span><span class=\"n\">Here<\/span><span class=\"w\"> <\/span><span class=\"k\">is<\/span><span class=\"w\"> <\/span><span class=\"n\">a<\/span><span class=\"w\"> <\/span><span class=\"n\">test<\/span><span class=\"w\"> <\/span><span class=\"n\">comment<\/span><span class=\"w\"> <\/span><span class=\"k\">for<\/span><span class=\"w\"> <\/span><span class=\"n\">your<\/span><span class=\"w\"> <\/span><span class=\"n\">blog<\/span><span class=\"w\"> <\/span><span class=\"n\">post<\/span><span class=\"p\">.<\/span><span class=\"w\">\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"w\"><\/span><span class=\"n\">It<\/span><span class=\"w\"> <\/span><span class=\"n\">supports<\/span><span class=\"w\"> <\/span><span class=\"o\">*<\/span><span class=\"n\">markdown<\/span><span class=\"o\">*<\/span><span class=\"w\"> <\/span><span class=\"o\">**<\/span><span class=\"n\">syntax<\/span><span class=\"o\">**<\/span><span class=\"w\"> <\/span><span class=\"k\">and<\/span><span class=\"w\"> <\/span><span class=\"o\">`<\/span><span class=\"n\">stuff<\/span><span class=\"o\">`<\/span><span class=\"p\">.<\/span><span class=\"w\">\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"w\">\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"w\"><\/span><span class=\"n\">Best<\/span><span class=\"p\">,<\/span><span class=\"w\">\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"w\"><\/span><span class=\"n\">Yourself<\/span><span class=\"w\">\n<\/span><\/span><\/span><\/code><\/pre><\/div><p>results in a file <code>content\/blog\/2021-03-12-static-comments-in-hugo\/comments\/2021-03-12T18:47:25+00:00_rak-at-example.org.yml<\/code> containing:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-yaml\" data-lang=\"yaml\"><span class=\"line\"><span class=\"cl\"><span class=\"nt\">date<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"ld\">2021-03-12T18:47:25<\/span><span class=\"m\">+00<\/span><span class=\"p\">:<\/span><span class=\"m\">00<\/span><span class=\"w\">\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"w\"><\/span><span class=\"nt\">post_id<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"l\">\/blog\/2021-03-12-static-comments-in-hugo\/<\/span><span class=\"w\">\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"w\"><\/span><span class=\"nt\">author<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"l\">Ryan Kavanagh<\/span><span class=\"w\">\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"w\"><\/span><span class=\"nt\">link<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"l\">https:\/\/rak.ac\/<\/span><span class=\"w\">\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"w\"><\/span><span class=\"nt\">comment<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p\">|<\/span><span class=\"sd\">\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"sd\">  Dear self,\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"sd\">\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"sd\">  Here is a test comment for your blog post.\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"sd\">  It supports *markdown* **syntax** and `stuff`.\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"sd\">\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"sd\">  Best,\n<\/span><\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"sd\">  Yourself<\/span><span class=\"w\">  \n<\/span><\/span><\/span><\/code><\/pre><\/div><p>You can see the rendered output at the bottom of this page.<\/p>\n"},{"title":"Configuring OpenIKED VPNs for StrongSwan Clients","link":"\/blog\/2020-09-12-configuring-openiked-vpns-for-strongswan-clients\/","pubDate":"Sat, 12 Sep 2020 17:42:00 -0400","guid":"\/blog\/2020-09-12-configuring-openiked-vpns-for-strongswan-clients\/","description":"<p>A few weeks ago I configured a road warrior VPN setup. The\nremote end is on a VPS running OpenBSD and OpenIKED, the VPN is\nan IKEv2 VPN using x509 authentication, and the local end is\nStrongSwan. I also configured an IKEv2 VPN between my VPSs. Here\nare the notes for how to do so.<\/p>\n<p>In all cases, to use x509 authentication, you will need to\ngenerate a bunch of certificates and keys:<\/p>\n<ul>\n<li>a CA certificate<\/li>\n<li>a key\/certificate pair for each client<\/li>\n<\/ul>\n<p>Fortunately, OpenIKED provides the <code>ikectl<\/code> utility to help you do\nso. Before going any further, you might find it useful to edit\n<code>\/etc\/ssl\/ikeca.cnf<\/code> to set some reasonable defaults for your\ncertificates.<\/p>\n<p>Begin by creating and installing a CA certificate:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-fallback\" data-lang=\"fallback\"><span class=\"line\"><span class=\"cl\"># ikectl ca vpn create\n<\/span><\/span><span class=\"line\"><span class=\"cl\"># ikectl ca vpn install\n<\/span><\/span><\/code><\/pre><\/div><p>For simplicity, I am going to assume that the you are managing\nyour CA on the same host as one of the hosts that you want to\nconfigure for the VPN. If not, see the bit about exporting\ncertificates at the beginning of the section on persistent\nhost-host VPNs.<\/p>\n<p>Create and install a key\/certificate pair for your server.\nSuppose for example your first server is called\nserver1.example.org:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-fallback\" data-lang=\"fallback\"><span class=\"line\"><span class=\"cl\"># ikectl ca vpn certificate server1.example.org create\n<\/span><\/span><span class=\"line\"><span class=\"cl\"># ikectl ca vpn certificate server1.example.org install\n<\/span><\/span><\/code><\/pre><\/div><h2 id=\"persistent-host-host-vpns\">Persistent host-host VPNs<\/h2>\n<p>For each other server that you want to use, you need to also\ncreate a key\/certificate pair on the same host as the CA\ncertificate, and then copy them over to the other server.\nAssuming the other server is called server2.example.org:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-gdscript3\" data-lang=\"gdscript3\"><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># ikectl ca vpn certificate server2.example.org create<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># ikectl ca vpn certificate server2.example.org export<\/span>\n<\/span><\/span><\/code><\/pre><\/div><p>This last command will produce a tarball\nserver2.example.org.tgz. Copy it over to server2.example.org and\ninstall it:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-fallback\" data-lang=\"fallback\"><span class=\"line\"><span class=\"cl\"># tar -C \/etc\/iked -xzpvf server2.example.org.tgz\n<\/span><\/span><\/code><\/pre><\/div><p>Next, it is time to configure iked. To do so, you will need to\nfind some information about the certificates you just generated.\nOn the host with the CA, run<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-fallback\" data-lang=\"fallback\"><span class=\"line\"><span class=\"cl\">$ cat \/etc\/ssl\/vpn\/index.txt\n<\/span><\/span><span class=\"line\"><span class=\"cl\">V       210825142056Z           01      unknown \/C=US\/ST=Pennsylvania\/L=Pittsburgh\/CN=server1.example.org\/emailAddress=rak@example.org\n<\/span><\/span><span class=\"line\"><span class=\"cl\">V       210825142208Z           02      unknown \/C=US\/ST=Pennsylvania\/L=Pittsburgh\/CN=server2.example.org\/emailAddress=rak@example.org\n<\/span><\/span><\/code><\/pre><\/div><p>Pick one of the two hosts to play the &ldquo;active&rdquo; role (in this\ncase, server1.example.org). Using the information you gleaned\nfrom index.txt, add the following to <code>\/etc\/iked.conf<\/code>, filling in\nthe srcid and dstid fields appropriately.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-fallback\" data-lang=\"fallback\"><span class=\"line\"><span class=\"cl\">ikev2 &#39;server1_server2_active&#39; active esp from server1.example.org to server2.example.org \\\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\tlocal server1.example.org peer server2.example.org \\\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\tsrcid &#39;\/C=US\/ST=Pennsylvania\/L=Pittsburgh\/CN=server1.example.org\/emailAddress=rak@example.org&#39; \\\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\tdstid &#39;\/C=US\/ST=Pennsylvania\/L=Pittsburgh\/CN=server2.example.org\/emailAddress=rak@example.org&#39;\n<\/span><\/span><\/code><\/pre><\/div><p>On the other host, add the following to \/etc\/iked.conf<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-fallback\" data-lang=\"fallback\"><span class=\"line\"><span class=\"cl\">ikev2 &#39;server2_server1_passive&#39; passive esp from server2.example.org to server1.example.org \\\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\tlocal server2.example.org peer server1.example.org \\\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\tsrcid &#39;\/C=US\/ST=Pennsylvania\/L=Pittsburgh\/CN=server2.example.org\/emailAddress=rak@example.org&#39; \\\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\tdstid &#39;\/C=US\/ST=Pennsylvania\/L=Pittsburgh\/CN=server1.example.org\/emailAddress=rak@example.org&#39;\n<\/span><\/span><\/code><\/pre><\/div><p>Note that the names <code>'server1_server2_active'<\/code> and\n<code>'server2_server1_passive'<\/code> in the two stanzas do not matter and\ncan be omitted. Reload iked on both hosts:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-gdscript3\" data-lang=\"gdscript3\"><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># ikectl reload<\/span>\n<\/span><\/span><\/code><\/pre><\/div><p>If everything worked out, you should see the negotiated security\nassociations (SAs) in the output of<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-fallback\" data-lang=\"fallback\"><span class=\"line\"><span class=\"cl\"># ikectl show sa\n<\/span><\/span><\/code><\/pre><\/div><p>On OpenBSD, you should also see some output on success or errors\nin the file <code>\/var\/log\/daemon<\/code>.<\/p>\n<h2 id=\"for-a-road-warrior\">For a road warrior<\/h2>\n<p>Add the following to <code>\/etc\/iked.conf<\/code> on the remote end:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-fallback\" data-lang=\"fallback\"><span class=\"line\"><span class=\"cl\">ikev2 &#39;responder_x509&#39; passive esp \\\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\tfrom 0.0.0.0\/0 to 10.0.1.0\/24 \\\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\tlocal server1.example.org peer any \\\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\tsrcid server1.example.org \\\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\tconfig address 10.0.1.0\/24 \\\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\tconfig name-server 10.0.1.1 \\\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\ttag &#34;ROADW&#34;\n<\/span><\/span><\/code><\/pre><\/div><p>Configure or omit the address range and the name-server\nconfigurations to suit your needs. See <code>iked.conf(5)<\/code> for details.\nReload iked:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-gdscript3\" data-lang=\"gdscript3\"><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># ikectl reload<\/span>\n<\/span><\/span><\/code><\/pre><\/div><p>If you are on OpenBSD and want the remote end to have an IP\naddress, add the following to <code>\/etc\/hostname.vether0<\/code>, again\nconfiguring the address to suit your needs:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-fallback\" data-lang=\"fallback\"><span class=\"line\"><span class=\"cl\">inet 10.0.1.1 255.255.255.0\n<\/span><\/span><\/code><\/pre><\/div><p>Put the interface up:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-fallback\" data-lang=\"fallback\"><span class=\"line\"><span class=\"cl\"># ifconfig vether0 up\n<\/span><\/span><\/code><\/pre><\/div><p>Now create a client certificate for authentication. In my case,\nmy road-warrior client was client.example.org:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-gdscript3\" data-lang=\"gdscript3\"><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># ikectl ca vpn certificate client.example.org create<\/span>\n<\/span><\/span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># ikectl ca vpn certificate client.example.org export<\/span>\n<\/span><\/span><\/code><\/pre><\/div><p>Copy client.example.org.tgz to client and run<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-fallback\" data-lang=\"fallback\"><span class=\"line\"><span class=\"cl\"># tar -C \/etc\/ipsec.d\/ -xzf client.example.org.tgz -- \\\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\t.\/private\/client.example.org.key \\\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\t.\/certs\/client.example.org.crt .\/ca\/ca.crt\n<\/span><\/span><\/code><\/pre><\/div><p>Install StrongSwan and add the following to <code>\/etc\/ipsec.conf<\/code>,\nconfiguring appropriately:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-fallback\" data-lang=\"fallback\"><span class=\"line\"><span class=\"cl\">ca example.org\n<\/span><\/span><span class=\"line\"><span class=\"cl\">  cacert=ca.crt\n<\/span><\/span><span class=\"line\"><span class=\"cl\">  auto=add\n<\/span><\/span><span class=\"line\"><span class=\"cl\">\n<\/span><\/span><span class=\"line\"><span class=\"cl\">conn server1\n<\/span><\/span><span class=\"line\"><span class=\"cl\">  keyexchange=ikev2\n<\/span><\/span><span class=\"line\"><span class=\"cl\">  right=server1.example.org\n<\/span><\/span><span class=\"line\"><span class=\"cl\">  rightid=%server1.example.org\n<\/span><\/span><span class=\"line\"><span class=\"cl\">  rightsubnet=0.0.0.0\/0\n<\/span><\/span><span class=\"line\"><span class=\"cl\">  rightauth=pubkey\n<\/span><\/span><span class=\"line\"><span class=\"cl\">  leftsourceip=%config\n<\/span><\/span><span class=\"line\"><span class=\"cl\">  leftauth=pubkey\n<\/span><\/span><span class=\"line\"><span class=\"cl\">  leftcert=client.example.org.crt\n<\/span><\/span><span class=\"line\"><span class=\"cl\">  auto=route\n<\/span><\/span><\/code><\/pre><\/div><p>Add the following to <code>\/etc\/ipsec.secrets<\/code>:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-fallback\" data-lang=\"fallback\"><span class=\"line\"><span class=\"cl\"># space is important\n<\/span><\/span><span class=\"line\"><span class=\"cl\">server1.example.org : RSA client.example.org.key\n<\/span><\/span><\/code><\/pre><\/div><p>Restart StrongSwan, put the connection up, and check its status:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-fallback\" data-lang=\"fallback\"><span class=\"line\"><span class=\"cl\"># ipsec restart\n<\/span><\/span><span class=\"line\"><span class=\"cl\"># ipsec up server1\n<\/span><\/span><span class=\"line\"><span class=\"cl\"># ipsec status\n<\/span><\/span><\/code><\/pre><\/div><p>That should be it.<\/p>\n<p>Sources:<\/p>\n<ul>\n<li><a href=\"https:\/\/wiki.strongswan.org\/projects\/strongswan\/wiki\/IKEv2ClientConfig\">https:\/\/wiki.strongswan.org\/projects\/strongswan\/wiki\/IKEv2ClientConfig<\/a><\/li>\n<li><a href=\"https:\/\/www.openbsd.org\/faq\/faq17.html\">https:\/\/www.openbsd.org\/faq\/faq17.html<\/a><\/li>\n<li><code>ikectl(8)<\/code><\/li>\n<li><code>iked.conf(5)<\/code><\/li>\n<\/ul>\n"},{"title":"Specifying a custom MTA path in caff","link":"\/blog\/2016-04-16-specifying-a-custom-mta-path-in-caff\/","pubDate":"Sat, 16 Apr 2016 12:19:53 +0000","guid":"\/blog\/2016-04-16-specifying-a-custom-mta-path-in-caff\/","description":"<p>I recently had to sign someone&rsquo;s GPG key. I&rsquo;ve long used the <code>caff<\/code>\ntool from the <code>signing-party<\/code> package to help me with\nthis. Unfortunately, I&rsquo;m using a new laptop and hadn&rsquo;t yet configured\n<code>caff<\/code> on it. Moreover, <code>caff<\/code> uses the system MTA by default,\nnormally found at <code>\/usr\/sbin\/sendmail<\/code>, and I hadn&rsquo;t yet properly\nconfigured it to send mail to the outside world. Since I have multiple\nemail accounts and use <code>mutt<\/code> as my mail client, I use <code>msmtp<\/code> as my\nSMTP client \/ sendmail drop-in. This post describes how to configure\n<code>caff<\/code> to use <code>msmtp<\/code>.<\/p>\n<p>Reading the <code>caff<\/code> man page, one sees the following tantalising hint,\nwhich leads you to believe it&rsquo;s completely trivial to specify your own\nMTA:<\/p>\n<pre><code>$CONFIG{'mailer-send'} = [ 'sendmail', '-f', $CONFIG{'email'}, '-it' ];\n<\/code><\/pre>\n<p>Unfortunately, substituting in a custom path, e.g.,\n<code>\/home\/rak\/bin\/msmtp\/msmtp-default<\/code>, for <code>sendmail<\/code> in the above line\nresults in a long sequence of errors when <code>caff<\/code> tries to mail the\nsigned keys:<\/p>\n<pre><code>Bareword &quot;home&quot; not allowed while &quot;strict subs&quot; in use at (eval 218) line 1.\nBareword &quot;rak&quot; not allowed while &quot;strict subs&quot; in use at (eval 218) line 1.\nBareword &quot;bin&quot; not allowed while &quot;strict subs&quot; in use at (eval 218) line 1.\nBareword &quot;msmtp&quot; not allowed while &quot;strict subs&quot; in use at (eval 218) line 1.\nBareword &quot;msmtp&quot; not allowed while &quot;strict subs&quot; in use at (eval 218) line 1.\nBareword &quot;default&quot; not allowed while &quot;strict subs&quot; in use at (eval 218) line 1.\n<\/code><\/pre>\n<p>Fortunately, it&rsquo;s still straightforward to accomplish after reading the perldoc for\n<a href=\"http:\/\/search.cpan.org\/~markov\/MailTools-2.14\/lib\/Mail\/Mailer.pod\">Mail::Mailer<\/a>.\nIn my case, it was sufficient to add the following to my <code>~\/.caffrc<\/code>:<\/p>\n<pre><code>$ENV{'PERL_MAILERS'} = 'sendmail:'.$ENV{'HOME'}.'\/bin\/msmtp\/msmtp-default';\n$CONFIG{'mailer-send'} = [ 'sendmail' ];\n<\/code><\/pre>\n<p>To specify alternate paths to your sendmail-style MTA, simply modify\nthe value of <code>$ENV{'PERL_MAILERS'}<\/code> after the initial <code>sendmail:<\/code>\nbit. If you&rsquo;re using stock <code>msmtp<\/code>, I believe the following pair of\nlines will work, though I haven&rsquo;t tested it:<\/p>\n<pre><code>$ENV{'PERL_MAILERS'} = 'sendmail:\/usr\/bin\/msmtp';\n$CONFIG{'mailer-send'} = [ 'sendmail' ];\n<\/code><\/pre>\n<p>If there&rsquo;s a more elegant way to accomplish this, I&rsquo;d be happy to hear\nabout it!<\/p>\n"},{"title":"mutt-fetchbug&#58; fetch BTS bug reports from mutt","link":"\/blog\/2012-01-05-mutt-fetchbug\/","pubDate":"Thu, 05 Jan 2012 15:58:00 +0000","guid":"\/blog\/2012-01-05-mutt-fetchbug\/","description":"<p>I&rsquo;ve been a longtime mutt user, but have gotten somewhat annoyed of having to open a new terminal when I want to read or reply to a Debian bug with mutt (using &lsquo;<code>bts show 123456<\/code>&rsquo;).\nHow nice it would be to be able to fetch a bug report from within mutt!\nAnd so, ladies and gentlemen, I present to you <code>mutt-fetchbug<\/code>.\nIt&rsquo;s extensively based on Zack&rsquo;s <a href=\"http:\/\/upsilon.cc\/~zack\/blog\/posts\/2011\/01\/how_to_use_Notmuch_with_Mutt\/\"><code>mutt-notmuch<\/code><\/a> script (a nice interface between mutt and notmuch for searching mail, I highly recommend it).<\/p>\n<p>By adding a line like the following to your <code>~\/.muttrc<\/code>, you can simply press &ldquo;<code>F7<\/code>&rdquo; and enter a bug number from your mutt index in order to fetch and display a bug report&rsquo;s mbox file:<\/p>\n<pre><code>macro index &lt;F7&gt; \\\n    &quot;&lt;enter-command&gt;unset wait_key&lt;enter&gt;&lt;shell-escape&gt;~\/bin\/mutt-fetchbug --prompt search&lt;enter&gt;&lt;change-folder-readonly&gt;~\/.cache\/mutt_btsresults&lt;enter&gt;&lt;enter-command&gt;set wait_key&lt;enter&gt;&quot; \\\n    &quot;fetch bug(s) (using bts show)&quot;\n<\/code><\/pre>\n<p>The above presupposes you&rsquo;ve downloaded <a href=\"\/blog\/2012-01-05-mutt-fetchbug\/mutt-fetchbug\n\"><code>mutt-fetchbug<\/code><\/a> and placed it with executable permissions in <code>~\/bin<\/code>.<\/p>\n<p>Those interested in making improvements or extending <code>mutt-fetchbug<\/code> are more than welcome to do so, it&rsquo;s licensed under the GPLv3+.\nIt can be fetched from my <a href=\"https:\/\/github.com\/ryanakca\/ryanakca-dotfiles\/blob\/master\/bin\/mutt-fetchbug\">git branch<\/a>.<\/p>\n<p><em>Update:<\/em> Fixed the broken link to mutt-fetchbug, thanks Christian for the heads up.<\/p>\n"}]}}