Commit Diff
Diff:
/dev/null
64f425c87790ba1c8caf16383437f8c848e05a5f
Commit:
64f425c87790ba1c8caf16383437f8c848e05a5f
Tree:
6598330233e540b722f36394a8455028f5356916
Author:
Daniel Jakots <danj@chown.me>
Committer:
Daniel Jakots <danj@chown.me>
Date:
Wed Apr 1 18:30:07 2020 UTC
Message:
Initial commit
blob - /dev/null
blob + c286ad0c15dff1a3fcd779d0b0e220b6b7455185 (mode 644)
--- /dev/null
+++ .flake8
@@ -0,0 +1,8 @@
+# This is an example .flake8 config, used when developing *Black* itself.
+# Keep in sync with setup.cfg which is used for source packages.
+
+[flake8]
+ignore = E203, E266, E501, W503
+max-line-length = 80
+max-complexity = 18
+select = B,C,E,F,W,T4,B9
blob - /dev/null
blob + 366514cfcac6969d4cadfc1a951b1a1bca6cb15a (mode 644)
--- /dev/null
+++ chownmeblog.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python3
+
+import glob
+
+import markdown
+
+CONTENT_PATH = "content/*"
+SITE = {}
+SITE["author"] = "Daniel Jakots"
+SITE["url"] = "chown.me"
+
+
+def md2html(md):
+ html = markdown.markdown(md)
+ return html
+
+
+def get_metadata(article):
+ with open(article, "r") as f:
+ for line in f:
+ if line.startswith("Title: "):
+ title = line[7:].strip()
+ elif line.startswith("Date: "):
+ date = line[6:].strip()
+ elif line.startswith("Category: "):
+ category = line[10:].strip()
+ elif line.startswith("Summary: "):
+ summary = line[9:].strip()
+ return title, date, category, summary
+
+
+def main():
+ for article in glob.glob(CONTENT_PATH):
+ title, date, category, summary = get_metadata(article)
+ print(title, date, category, summary, sep="\n")
+ print()
+ # with open("./photography.md", "r") as f:
+ # md = f.read()
+
+ # print(md2html(md))
+
+
+if __name__ == "__main__":
+ main()
blob - /dev/null
blob + f42f6cae8b3cb3745cb947f4fe21ec326f508755 (mode 644)
--- /dev/null
+++ content/2FA-with-ssh-on-OpenBSD.md
@@ -0,0 +1,240 @@
+Title: 2FA with ssh on OpenBSD
+Date: 2018-08-31 10:20
+Category: Tech
+Summary: How I locked down my ssh connection
+
+Five years ago I wrote about [using a yubikey](./yubikey.html) on OpenBSD. The
+only problem with doing this is that there's no validation server available on
+OpenBSD, so you need to use a different OTP slot for each machine. (You don't
+want to risk a [replay attack](https://en.wikipedia.org/wiki/Replay_attack) if
+someone succeeds in capturing an OTP on one machine, right?) Yubikey has two
+OTP slots per device, so you would need a yubikey for every two machines with
+which you'd like to use it. You could use a
+[bastion](https://en.wikipedia.org/wiki/Bastion_host)—and use only one
+yubikey—but I don't like the SPOF aspect of a bastion. YMMV.
+
+After [I played with TOTP](./my-recent-journey-with-2FA.html), I wanted to use
+them as a 2FA for ssh. At the time of writing, we can't do that using only the
+tools in base. This article focuses on OpenBSD; if you use another operating
+system, here are two [handy](https://www.openbsd.org/faq/faq4.html)
+[links](https://ftp.openbsd.org/pub/OpenBSD/6.3/amd64/INSTALL.amd64).
+
+# Seed configuration
+
+The first thing we need to do is to install the software which will be used to
+verify the OTPs we submit.
+
+~~~
+# pkg_add login_oath
+~~~
+
+We need to create a *secret* - aka, the *seed* - that will be used to calculate
+the Time-based One-Time Passwords. We should make sure no one can read or
+change it.
+
+~~~
+$ openssl rand -hex 20 > ~/.totp-key
+$ chmod 400 ~/.totp-key
+~~~
+
+Now we have a hexadecimal key, but apps usually [want a base32
+secret](https://github.com/mattrubin/Authenticator/blob/develop/Authenticator/Source/TokenEntryForm.swift#L214).
+I initially wrote a small script to do the conversion.
+
+While writing this article, I took the opportunity to improve it. When I
+initially wrote this utility for my use,
+[python-qrcode](https://github.com/lincolnloop/python-qrcode) hadn't yet been
+imported to the OpenBSD ports/packages system. It's easy to install now, so
+let's use it.
+
+Here's the improved version. It will ask for the hex key and output the secret
+as a base32-encoded string, both with and without spacing so you can copy-paste
+it into your password manager or easily retype it. It will then ask for the
+information needed to generate a *QR code*. Adding our new OTP secret to any
+mobile app using the QR code will be super easy!
+
+~~~
+#!/usr/bin/env python
+
+# DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
+# Version 2, December 2004
+
+# Copyright (C) 2018 Daniel Jakots
+
+
+import binascii
+import base64
+import sys
+
+try:
+ import qrcode
+except ModuleNotFoundError:
+ print("pkg_add py3-qrcode")
+ sys.exit(1)
+
+seed_hex = input("Key in hex format ")
+
+binary_string = binascii.unhexlify(seed_hex)
+seed_b32 = base64.b32encode(binary_string).decode('utf-8')
+
+print("The secret in a base32 encoded format")
+print(seed_b32)
+
+print("The same, but with a space every three letters for readability")
+print(' '.join([seed_b32[i:i+3] for i in range(0, len(seed_b32), 3)]))
+
+print("Let's create a QR code to import it into an app")
+issuer = input("'Issuer' (can be the server name) ")
+username = input("Username ")
+
+uri = f"otpauth://totp/{username}?secret={seed_b32}&issuer={issuer}"
+img = qrcode.make(uri)
+image_file = open(f"qrcode-otp-{issuer}.jpg", "wb")
+img.save(image_file)
+~~~
+
+You can fetch this script using `ftp
+https://chown.me/iota/blog/totp-hex-to-qrcode.py`. (The code isn't in any of
+my public repositories for
+[reasons](https://chown.me/iota/blog/issues-public-repo.jpg)).
+
+We can check to make sure everything went smoothly by comparing the code
+provided by your mobile app to one generated by *oathtool* at the same time.
+The *oathtool* binary is provided by the package *oath-toolkit* (which is the
+dependency needed by *login_oath*). *oathtool* accepts the seed in either
+hexadecimal or base32 format.
+
+~~~
+$ oathtool --totp 0123456789abcdef0123
+054640
+$ oathtool --totp -b AERUKZ4JVPG66AJD
+054640
+~~~
+
+*0123456789abcdef0123* is the *seed* in hexadecimal format (as in
+`~/.totp-key`) and *AERUKZ4JVPG66AJD* is the same data, but base32-encoded.
+
+Alternatively, if you just want to do the hex -> b32 conversion, *login_oath*'s
+README gives a Perl example (but it is not an unreadable one-liner, so you may
+not want to use it):
+
+~~~
+Some tokens (e.g. Google Authenticator) require secrets in base32 format;
+you can convert them with p5-Convert-Base32:
+
+use Convert::Base32;
+my $s = pack('H*', '99d12448129d1e8192e063d64714209137a13864');
+print encode_base32($s)."\n";
+~~~
+
+# System configuration
+
+We can now move to the configuration of the system to put our new TOTP to use.
+As you might guess, it's going to be quite close to what we did with the
+yubikey.
+
+We need to tweak `login.conf`. **Be careful** and keep a root shell open at all
+times. The few times I broke my OpenBSD were because I messed with login.conf
+without showing enough care.
+
+After the lines:
+
+~~~
+# Default allowed authentication styles for authentication type ftp
+auth-ftp-defaults:auth-ftp=passwd:
+~~~
+
+we add:
+
+~~~
+# Default allowed authentication styles for authentication type ssh
+auth-ssh-defaults:auth-ssh=-totp:
+~~~
+
+and inside the class of the user account for which TOTP is being set, we add
+the line `:tc=auth-ssh-defaults:\`. For instance, in my case it's:
+
+~~~
+staff:\
+ :datasize-cur=1536M:\
+ :datasize-max=infinity:\
+ :maxproc-max=512:\
+ :maxproc-cur=256:\
+ :ignorenologin:\
+ :requirehome@:\
+ :tc=auth-ssh-defaults:\
+ :tc=default:
+~~~
+
+(Hint: it's the penultimate line). You can check the class of your user using
+`id -c`.
+
+# sshd configuration
+
+Again, keeping a root shell around decreases the risk of losing access to the
+system and being locked outside.
+
+A good standard is to use `PasswordAuthentication no` and to use public key
+only. Except... have a guess what the *P* stands for in *TOTP*. Yes, congrats,
+you guessed it!
+
+We need to switch to `PasswordAuthentication yes`. However, if we made this
+change alone, sshd would then accept a public key OR a password (which are TOTP
+because of our *login.conf*). 2FA uses both at the same time.
+
+To inform sshd we intend to use both, we need to set `AuthenticationMethods
+publickey,password`. This way, the user trying to login will first need to
+perform the traditional publickey authentication. Once that's done, ssh will
+prompt for a password and the user will need to submit a valid TOTP for the
+system.
+
+We could do this the other way around, but I think bots could try passwords,
+wasting resources. Evaluated in this order, failing to provide a public key leads to
+sshd immediately declining your attempt.
+
+Here's the diff of the output when testing with `ssh -v` using both public-key-only authentication and two-factor authentication:
+
+~~~
+-debug1: Authentication succeeded (publickey).
++Authenticated with partial success.
++debug1: Authentications that can continue: password
++debug1: Next authentication method: password
++danj@198.51.100.12's password:
++debug1: Authentication succeeded (password).
+~~~
+
+# Improving security without impacting UX
+
+My phone has a long enough password that most of the time, I fail to type it
+correctly on the first try. Of course, if I had to unlock my phone, launch my
+TOTP app and use my keyboard to enter what I see on my phone's screen, I would
+quickly disable 2FA.
+
+To find a balance, I have whitelisted certain IP addresses and users. If I
+connect from a particular IP address or as a specific user, I don't want to go
+through 2FA. For some users, I might not even enable 2FA.
+
+To whitelist, we can use the *Match* keyword. Here are two basic examples:
+
+~~~
+Match User git
+ AuthenticationMethods publickey
+~~~
+
+~~~
+Match Address 203.0.113.47 # VPN
+ AuthenticationMethods publickey
+~~~
+
+<br/>
+
+To sum up, we covered how to create a seed, how to perform a hexadecimal to
+base32 conversion and how to create a *QR code* for mobile applications. We
+configured the login system with *login.conf* so that ssh authentication uses
+the TOTP login system, and we told sshd to ask for both the public key and the
+Time-based One-Time Password. Now you should be all set to use two-factor
+ssh authentication on OpenBSD!
+
+<br/>
+
+*Thanks [Pamela](https://bsd.network/@pamela) for the proof-reading!*
blob - /dev/null
blob + 2ce9babaca4e4e7f9be1003cb6bca673b5e1cde3 (mode 644)
--- /dev/null
+++ content/dumping-pics.md
@@ -0,0 +1,28 @@
+Title: Dumping pics
+Date: 2017-11-04 10:20
+Category: Mylife
+Summary: I finally dumped the pics I took with my phone
+
+A few years ago I bought a camera (a Canon 100D) and since that I take
+pictures from time to time. I go through all the pics I take and I
+pick the best then I enhance them a bit with rawtherapee and finally I
+post them on [500px](http://piks.chown.me). This process is a bit
+*relou* so I don't often do it. Of course I don't always have my camera
+with me, but I do have my phone most of the time.
+
+I take a lot of pictures with my phone and I sometimes post them on
+some social networks. All these social networks I'm on, are based on
+ephemeral publications so after a **short** while, the stuff goes out
+of your mind and you never see it again.
+
+I looked for a self-hostable solution. I found PHP-based software like
+leetchi and piwigo but I wasn't fond of these. I looked at static
+generators as I already use one (pelican) for this blog. Sadly, there
+are maaaanyyyy of them for blogs and text-based publications but for
+gallery there very few static generators. Finally I found
+[sigal](https://github.com/saimn/sigal) which is maintained, written
+in python, quite nice and very straight forward to use.
+
+Here's the result: <https://pics.chown.me/> (with among other themes,
+as of now, 229 pics of my delicious kitten *Jean Canard*).
+
blob - /dev/null
blob + d3467190a3649993f153195809db30962057ff51 (mode 644)
--- /dev/null
+++ content/infrastructure-2019.md
@@ -0,0 +1,244 @@
+Title: My infrastructure as of 2019
+Date: 2020-03-06 10:20
+Category: Tech
+Summary: My infrastructure as of 2019
+
+I've wanted to write about my infrastructure for a while, but I kept thinking,
+"I'll wait until after I've done $next_thing_on_my_todo." Of course this cycle
+never ends, so I decided to write about its state at the end of 2019. Maybe
+I'll write an update on it in a couple of moons; who knows?
+
+## Goal for this infrastructure
+
+The goal for my infrastructure is to run the services I need. While a lot of
+people in the homelab community experiment and play with software for its own
+sake, I actively use the stuff I host. When I stop, I kill the service (though
+I'm not as proficient at this as [Google](https://killedbygoogle.com/)). These
+are my production systems, and when one of them is down, I do miss it.
+
+I kind of enjoy working on this infrastructure, but not that much (I used to
+enjoy it more), so I'm careful with the software I choose. I want to spend time
+on it when *I want to*, not because *I have to* (e.g. because something broke).
+Consequently, I do my best to pick reliable, boring and easy software. Those
+are my kinks.
+
+Why do I host this myself? Mostly trust issues, and the fact that I care about
+sovereignty.
+
+I tend to lock down services as much as I can, either cutting them off
+completely from the Internet (e.g. for *imap*) or running them on a
+non-standard port and [enabling 2FA](./2FA-with-ssh-on-OpenBSD.html). I don't
+use a VPN (mostly because I haven't come up with a nice, clean option yet), so
+I restrict access to my services in different ways.
+
+For most things, I'm the only user, which is both sad (as it's a waste of
+resources) and great (as I can be more nimble). A notable exception is my
+mastodon instance which is also used by [my
+cat](https://awoo.chown.me/@jeancanard).
+
+## Machines
+
+My machines are hosted in 3 different places. First is at
+[Exoscale](https://www.exoscale.com/), second is
+[Vultr](https://www.vultr.com/) and the third is... my flat.
+
+All of them run either OpenBSD on its -current branch, or the latest version of
+Ubuntu. At this time, that's Ubuntu 19.10. After a couple of years working on
+OpenBSD ports (i.e. packaging), I believe fresh software is better,
+security-wise.
+
+They're managed with Ansible. I began my Ansible repository 4 years ago and it
+has about 1500 commits in it. I wrote the Ansible to fit my needs rather than
+making generic (and therefore reusable) roles, so it's not public.
+
+I update the OpenBSD machines regularly to a newer OpenBSD snapshot (so of
+course the process has been
+[automated](./upgrading-openbsd-with-ansible.html)). For Ubuntu, I prefer to
+reinstall them, since they're managed by Ansible and they don't have any data
+on them. Reinstalling machines regularly helps spot missing pieces in Ansible.
+:P
+
+All the three sites are as
+[standalone](https://en.wikipedia.org/wiki/Loose_coupling) as possible. This is
+both so that in the case that one gets pwned it won't help the attacker to
+[move laterally](https://en.wikipedia.org/wiki/Network_Lateral_Movement), and
+so that if one is unavailable it shouldn't impact anything else.
+
+### ns3.chown.me (OpenBSD)
+
+It's my secondary name server and as you can guess, it replaced ns2. It's the
+only machine that I don't back up, since I can replace it with my Ansible
+without losing data.
+
+It's hosted by *Vultr*. I mostly picked them because they offer OpenBSD
+hosting. This virtual machine is in Toronto and has 1 CPU and 512M of ram.
+(Disk space is not relevant here).
+
+I wanted a different hosting provider/AS than my main name server for obvious
+reasons of resiliency. Every now and then I think about using another name
+server (whether instead of this machine or in addition to it, I don't know)
+provided by my registrar (Gandi), but it has a low priority on my todo list.
+
+The name server I use is *NSD*. I could use another one (like *knot*) as my
+main name server also uses *NSD*, but the issues related to running the same
+software on both aren't that serious in my case.
+
+Since this machine doesn't do much otherwise, it's running
+[mownitoring](https://github.com/danieljakots/mownitoring) to check that
+everything works.
+
+### virtie.chown.me (OpenBSD)
+
+This virtual machine is the main one in my infrastructure. A moment ago your
+browser connected to it to get this page. :)
+
+It's hosted by Exoscale (with whom my experiences have been nothing less than
+perfect). It's my oldest VM (4 or 5 years old). It has 1 CPU, 1G of ram and 50G
+of disk space.
+
+To host my blog I use OpenBSD's httpd which is fronted by *HAProxy*. While I
+could remove *HAProxy*, I like this software and I trust it [more
+than](https://ftp.openbsd.org/pub/OpenBSD/patches/5.6/common/022_httpd.patch.sig)
+[httpd](https://github.com/openbsd/src/commit/49b1a9b154081c713af219b2422adaf51ca2584d).
+
+In addition to hosting my blog, it hosts my email. I switched to *postfix* in
+the beginning of 2019 after a couple of years running *OpenSMTPD*. Since I
+switched to *postfix* I also dropped *spamd* (the OpenBSD greylisting daemon).
+I enabled [FCrDNS](https://en.wikipedia.org/wiki/Forward-confirmed_reverse_DNS)
+on *postfix* when I switched (at the time it was not available on *OpenSMTPD*)
+and I didn't notice more spam. I use *Dovecot* for imap with only my IP
+allowed. I can easily allow another IP address with `pfctl -t imap_allowed -Ta
+203.0.113.47`.
+
+I've never really had deliverability problems (except with Microsoft, but who
+can say they haven't?) I assume my IP has a good reputation, which is why this
+VM is the oldest, as I've been reluctant to lose it.
+
+This machine also hosts a *gitolite* for a couple of different internal git
+repositories.
+
+### pancake.chown.me (OpenBSD)
+
+This machine is an [APU2](https://pcengines.ch/apu2.htm). It acts as a router
+for my flat. Since it's way more powerful than necessary for this task, I put
+some other stuff on it. It's a trade-off between increasing the attack surface
+of a critical machine and leaving a lot of CPU/RAM/SSD unused.
+
+I collect [flows](https://en.wikipedia.org/wiki/NetFlow) on it, which in my
+opinion are super cool!
+
+It also hosts influxdb + grafana and some machines send their metrics with
+collectd ([which allow signing/encrypting the network
+traffic](https://collectd.org/wiki/index.php/Networking_introduction#Cryptographic_setup)).
+This doesn't work well for a couple of reasons, so it's waiting to be replaced.
+
+### kvm1, and sometimes kvm2 (Ubuntu)
+
+These machines are hosted at home. kvm1 is the main machine, and kvm2 is the
+machine I use to play Windows games on another SSD. I boot on the Ubuntu SSD
+whenever I want to do something on kvm1 and then I live-migrate guests on it so
+I don't experience any downtime. I use full disk encryption on the guests, so
+live-migrating (instead of rebooting them) allows me to avoid having to
+manually unlock each guest. I encrypt the guests and not the kvm because in the
+event of a power outage, machines may come back on, in which case I don't want
+them to wait for the passphrase if I'm away. Some hacks could be done to
+encrypt them as well, but I'm not willing to do them since they're overkill for
+my threat model.
+
+Both machines have an i5-4590. kvm2 has 4x4G of ram with a 256G SSD (which is
+enough for the kvm system and all the guests). kvm1 also has a 256G SSD but
+while its ram layout would make anyone sensible cringe, it amounts to 20G of
+ram! I don't use RAID. kvm0 (the machine they replaced) used to and I wasn't
+sure it would work (and I couldn't test it safely since it was my only
+machine).
+
+To manage this part of the infrastructure I wrote a [python
+script](https://github.com/danieljakots/uv). This script is kind of a wrapper
+around libvirt, which itself is kind of a wrapper around qemu, which itself
+[wrangles turtles](https://en.wikipedia.org/wiki/Turtles_all_the_way_down).
+Contrary to what other people run, I think, a guest disk isn't a qcow2/raw
+file. I don't want to pile filesystems on one another, so I manage guests'
+disks on the hypervisor with LVM directly. I tend to have multiple disks to
+bring more flexibility to the disk layout/partitioning than OpenBSD would,
+thanks to LVM.
+
+It hosts all the following virtual machines:
+
+### manicouagan1 (OpenBSD)
+
+This machine's name dates from back when I used names from Québec to name my
+machines. The name comes from the [Manicouagan
+Reservoir](https://en.wikipedia.org/wiki/Manicouagan_Reservoir), as this
+machine is where I put my backups.
+
+My backups are in three different places:
+- locally, i.e. each machine stores its backup on itself
+- *manicouagan* copies all the backups onto itself
+- *manicouagan* ships the backups to an s3-like provider
+
+I use *BorgBackup* for the backup, *rsync* to copy them onto *manicouagan* and
+*s3cmd* to ship them away. I tried to use *rclone* but it used more ram. Once,
+I was away from my place for a long time, and my whole infra there became
+unreachable, so I decided to temporarily host stuff on the cloud in the
+meantime. I had to restore those backups and it went so nicely that I'm not
+looking to change anything. Borg is awesome!
+
+This machine is also a syslog server to which all my OpenBSD machines ship
+their logs. Thanks to OpenBSD syslogd (bluhm@ <3), it uses TCP+TLS with a
+private PKI. This is mostly in case one machine gets hacked, to help with
+[forensics](https://en.wikipedia.org/wiki/Forensic_science).
+
+I wrote a short script that shows me the largest data transfers on my router. I
+use this to check that the backups are alive (I receive emails if the
+*BorgBackup* script fails, but isn't that less fun? :))
+
+### db1 (OpenBSD)
+
+This machine hosts postgresql and redis. Two boring pieces of software which I
+love. Redis requires so little care that when I moved from db0, I forgot I had
+it!
+
+### web1 (OpenBSD)
+
+This machine runs nginx for my whole web presence excluding my blog. It hosts
+*nextcloud*, *tt-rss*, *shaarli* and pics.chown.me (whose content I should
+update).
+
+Have you ever thought, "naah I'm too much paranoid"? Yeah, me neither. A few
+months ago, I restricted all the non-static websites (with the exception of
+Mastodon) behind an *htpasswd*. There was some value in having them publicly
+accessible, but at the time I thought it was not worth the risk. The php-fpm
+pools should be secure (they have their own users, they're chrooted and so on)
+but I'm not entirely sure I'm doing this stuff properly and it is such a pain
+to get it working that I'm not willing to look into it more than that.
+
+Nginx also acts as a reverse proxy for the docker containers that run on
+another machine. Finally, it hosts *minio* for *mastodon*.
+
+### docker2 (Ubuntu, obviously)
+
+This machine runs a few docker containers through *docker-compose*:
+- 3 containers for *mastodon* (*ruby on rails* stuff, a node api and *sidekiq*)
+- container running the code I wrote for api.chown.me; it's a *flask*
+ application
+- registry:v2 that I have simply to ease the transfer of docker images
+
+I build all the docker images I run myself (except for the registry one).
+
+My policy regarding those containers is that they must not store any data
+locally (i.e. they don't have a *docker volume*). This allows me not to care
+about backups. The *docker-compose.yml* is tracked in my personal git, so I can
+trash the VM any time.
+
+api.chown.me is for now mostly a way to sync a list of IPs to block on my whole
+infra. This way, if an IP is acting badly on one machine, it doesn't get to try
+its luck on another of my machines. This list is also supplemented by public
+lists of threats.
+
+## That's it for now
+
+Currently, my infrastructure is good at meeting my needs. It's not perfect, of
+course, and it's a perpetual work in progress. But it's stable, and usually the
+most I need to do is quickly patch some security vulnerabilities. Since most
+of the resources I use come from reused computers hosted at my place, I'm able
+to keep the cost (both financial and ecological) really low.
blob - /dev/null
blob + 709989c4e5e0f9fc482846abdc7080f4e5471c10 (mode 644)
--- /dev/null
+++ content/locking-openbsd-when-sleeping.md
@@ -0,0 +1,67 @@
+Title: Locking OpenBSD when it's sleeping
+Date: 2018-10-08 10:20
+Category: Tech
+Summary: A frequently asked question: how do you lock your machine?
+
+I frequent the #openbsd IRC channel in order to help people. A question
+commonly asked is how to automatically lock your machine when
+putting it to sleep with zzz(1). I answered this question in a
+previous article (which was actually written four years ago; time flies!) but
+it was written in French, so here's a new one, also covering additional related topics.
+
+# Locking the machine when it is put to sleep
+
+If you read [apmd(8)](https://man.openbsd.org/apmd.8):
+
+~~~
+FILES
+ /etc/apm/suspend
+ /etc/apm/hibernate
+ /etc/apm/standby
+ /etc/apm/resume
+ /etc/apm/powerup
+ /etc/apm/powerdown These files contain the host's customized actions.
+ Each file must be an executable binary or shell
+ script. A single program or script can be used to
+ control all transitions by examining the name by
+ which it was called, which is one of suspend,
+ hibernate, standby, resume, powerup, or powerdown.
+~~~
+
+The trick is to write a script for 'etc/apm/suspend' to run when zzz is called
+(either directly or by [closing the
+lid](https://github.com/openbsd/src/blob/master/etc/etc.amd64/sysctl.conf#L3)).
+For instance, the script I'm using is:
+
+~~~
+#!/bin/sh
+doas -u danj env DISPLAY=:0 XAUTHORITY=/home/danj/.Xauthority xlock &
+~~~
+
+It requires:
+
+- configuring doas, *left as an exercise to the reader* ;)
+- running apmd (hashtag rcctl)
+- an executable script
+
+# Locking it further
+
+This is off to a good start, but if you are a *startx* user (versus using xenodm), be sure to run `exec startx` and not just `startx`. Otherwise, it is possible to kill X and then access the shell.
+
+If you don't set a maximum lifetime for your `ssh-agent`, you should clear your identities using `ssh-add -D`. You should also revoke any `sudo` permissions with `sudo -K`. `doas` doesn't work the same way, so `doas -L` won't help you much. (You have elevated permissions only in the current shell, not account-wide).
+
+You might want to clear your clipboards, as well. Use something like: `xsel -c -p; xsel -c -s; xsel -c -b`.
+
+Of course, if you use other authentication mechanisms (GNOME keyring, ssh's
+Control\*, etc.), you should handle those as well.
+
+# Beware of the cat
+
+Now that I have a [Captive Advanced
+Threat](https://awoo.chown.me/@jeancanard), I feel the need to automatically lock the screen after it has been idle for a short while. You can achieve this using `xidle`. The [man
+page](https://man.openbsd.org/xidle.1) is sufficiently descriptive that I won't talk about that further.
+
+
+<br/>
+
+*Thanks [semarie](https://maly.io/@semarie) for the technical proof-reading and [Pamela](https://bsd.network/@pamela) for the English proof-reading!*
blob - /dev/null
blob + 7f877fc24065c17dcb5b39eb30c67699fd42520d (mode 644)
--- /dev/null
+++ content/my-recent-journey-with-2FA.md
@@ -0,0 +1,157 @@
+Title: My recent journey with 2FA
+Date: 2017-02-26 10:20
+Category: Tech
+Summary: I recently begin to increase my use of 2FA so here's my report about it.
+
+## 2FA
+
+Of course by 2FA I mean
+[two-factor authentication](https://en.wikipedia.org/wiki/Multi-factor_authentication).
+
+I've been using that for a long time for ssh with
+[my yubikey on OpenBSD](./yubikey-en.html) but I've never enabled 2FA
+on the online services I use. The main reason for not doing it before was
+that I thought that my phone had to play a central role (which in fact
+is not much the case). While it's the most critical device I have, my
+phone is the device I trust the least.
+
+However, yesterday I saw a comment on lobste.rs asking about
+[how to use TOTP on OpenBSD](https://lobste.rs/s/1cyltz/two_factor_authentication_now_available/comments/a9xvvg#c_a9xvvg).
+In addition to that, I guess seeing
+[what happened to cloudflare](https://blog.cloudflare.com/incident-report-on-memory-leak-caused-by-cloudflare-parser-bug/)
+and everything what's happening if you want to cross the US border
+made me more interested in 2FA than before.
+
+So I began to look into how it works.
+
+## How it works
+
+The concept of 2FA is that you may lose your password (or your ssh
+key) and in that case the person who takes control of it can
+successfully impersonate you. The goal is that a login system will
+require something else to verify that it's really you.
+
+One way to achieve this is to use SMS but that sucks: [circumventing it
+is not even restricted to Nation State Actors](http://www.baltimoresun.com/features/baltimore-insider-blog/bal-black-lives-matter-activist-deray-mckesson-s-twitter-hacked-friday-morning-20160610-story.html).
+
+Another can be something biometric but then users need to access to a
+scanner which is quite impractical in every day life. Even if iPhones
+have a fingerprint reader, it's not usable by third parties.
+
+It must be something that keeps changing otherwise it's both
+subject to replay attack and it's just another password.
+
+Here comes the OTP.
+
+## One Time Password
+
+One Time Password was defined in
+[RFC2289](https://tools.ietf.org/html/rfc2289) (which is quite old:
+February 1998). Then they made HOTP (H is for *HMAC-Based*) in
+[RFC4226](https://tools.ietf.org/html/rfc4226) and finally the TOTP (T
+is for *Time-Based*) in [RFC](https://tools.ietf.org/html/rfc6238)
+which is an extension of the HOTP to support the time-based moving
+factor.
+
+To understand in more details you can either read in the RFC4226
+[5.4. Example of HOTP Computation for Digit = 6](https://tools.ietf.org/html/rfc4226#page-7)
+and then the short RFC6238 or you can just read this [random blog
+article on the Internet which explains clearly the same thing](https://pthree.org/2014/04/15/time-based-one-time-passwords-how-it-works/).
+
+### tl;dr
+
+There's a secret shared and then you compute the HMAC-SHA1 of the
+shared secret and epoch.
+
+### Wait, did you just say sha1?!?1?
+
+Even if there's now a sha1 collision, it's not really a problem. To
+quote Schneier: "[collision] pretty much puts a bullet into
+SHA-1 as a hash function for digital signatures (although it doesn't
+affect applications such as HMAC where collisions aren't important)."
+([source](https://www.schneier.com/blog/archives/2005/02/sha1_broken.html))
+
+And for a more complete answer, see this
+[answer](http://crypto.stackexchange.com/questions/26510/why-is-hmac-sha1-still-considered-secure).
+
+## How to use it
+
+### Don't be locked out
+
+I wanted to use my phone (something distinct that my computer to
+compartment things a bit). Obviously the goal is to secure your
+account without losing it so that means that losing your phone
+shouldn't prevent you to retrieve access to your accounts. Unusable
+security is unusable.
+
+If you read about 2FA, you'll see that some services that provide it,
+give you some backup code to not to be locked out. But I don't want to
+locked out from services don't provide backup codes either.
+
+So my phone must not be a single point of failure.
+
+We saw earlier that {T,H}OTP are based on a shared secret so let's
+backup it.
+
+### Backuping shared secrets and backup codes
+
+For my regular passwords, I use keepassx which is shared/backuped across my
+different computers. I created another database to store those. Of
+course you shouldn't use the same database to keep your passwords and the
+other secrets in case of you leak one of the two database's password.
+
+### Clients
+
+#### Android phone
+
+Now that I'm ready to activate 2FA, let's see how to use it. The plan
+is to use my android phone. On the
+[Time-based One-time Password Algorithm Wikipedia page](https://en.wikipedia.org/wiki/Time-based_One-time_Password_Algorithm)
+there was a list of clients but sadly it was deleted.
+You can still find it
+[in the history](https://en.wikipedia.org/w/index.php?title=Time-based_One-time_Password_Algorithm&oldid=724156353#Client_implementations).
+
+I wanted a FOSS application and Google Authenticator is now closed
+source so I went with FreeOTP which is not completely dead compared to
+others (but it's not thriving either), so far it works good.
+
+#### OpenBSD
+
+In the case I don't have a phone, I still want to be able to
+log in my different accounts. In the lobste.rs' link that I gave at the
+beginning of this article, someone mentioned oath-toolkit which works
+very easily:
+
+ $ oathtool --totp -b deafcafe
+ 405723
+
+(with deafcafe being the shared secret).
+
+## Activating it
+
+Now that we're ready to use it, let's do it. So where to activate
+it? Actually, there's [a cool site](https://twofactorauth.org/) that
+lists services that provide or not (and then you can shame them on
+twitter) 2FA with a link to the service's documentation.
+
+### My Feedback
+
+So far I activated 2FA on about half a dozen of website. The first one was
+the [RIPE NCC](https://www.ripe.net/) (if you don't want people to
+steal your precious IP addresses and/or your atlas credit) and it was
+actually a good one to try it.
+
+To activate it usually the website gives you a qrcode which is in fact
+just a URL looking like:
+
+ otpauth://totp/Example:foo@example.com?secret=DEAFCAFE&issuer=Example
+
+which is fine for my phone but sadly my eyes can't decode qrcode and I
+need the shared secret to put it my keepassx. Most of the time
+websites gives you by default the qrcode but also gives you the
+possibility to access the shared secret.
+
+For now, everything works fine, I use my phone to unlock my different
+accounts and if anything happens to it, I can just unlock my second
+keepassx database and use oathtool (or use a backup code) to get my
+account back.
blob - /dev/null
blob + 5232e27f05ad7d2608e652427fa5999022d1cafe (mode 644)
--- /dev/null
+++ content/new-design.md
@@ -0,0 +1,40 @@
+Title: New design
+Date: 2018-04-13 10:20
+Category: Tech
+Summary: The blog has a new design!
+
+
+In June this blog will be five years old. Since [I created it](./blog.html), it
+has had the same design. A few weeks ago I looked for a new theme. I found
+[pelican-blue](https://github.com/Parbhat/pelican-blue) which I liked. For my
+first theme, I took it from someone and shortly after someone took it from me.
+This time I wanted something more unique.
+
+I took pelican-blue and hammered the CSS so people would notice I love the
+color [*red*](https://en.wikipedia.org/wiki/Red). At home, my sheets are red, my bath towel is red, my couch is
+red, my curtains are red. Even the ribbon Jean Canard plays with is [red](https://pics.chown.me/Jean-Canard/IMG_0675.JPG).
+
+I noticed a couple of things that were broken with the theme so I had to fix
+them. Now I have to go back to my commit log to tell the original author as a
+way to contribute back.
+
+At first, my blog URL was `blog.chown.me`. Then I wanted https but I couldn't
+have another domain because back then free (and valid—hi cacert) certificates
+weren't a thing, I moved it to `chown.me/blog`. To welcome stalk^Wvisitors I
+had a landing page on `chown.me`. Now, however, I changed my mind and I prefer
+to have my blog index page directly on `chown.me`.
+
+I wanted to break as few links as possible—ain't nobody got time to write the
+otherwise needed haproxy redirection. I think I tweaked enough of my
+[pelican](https://blog.getpelican.com/) config file so that most of them are fine.
+Not all of them are; I had to break one or two because of translations.
+Fortunately, I was lazy enough to translate only a handful of articles so the
+breakage is minimal.
+
+To fix some past mistakes I had to go through old articles. It was a weird
+feeling to read my younger self. I wouldn't advise to read them haha. They're in
+French anyway.
+
+One of my 2018 New Year's resolution was to write more blog articles. With not a
+single one for the first quarter, you can guess it's not my best
+accomplishment. But hopefully, I'll finally do it.
blob - /dev/null
blob + 2197a61cd0ca2f1e3445b1aa3e46d9ec42b82598 (mode 644)
--- /dev/null
+++ content/p2k16.md
@@ -0,0 +1,90 @@
+Title: Hackathon report - p2k16
+Date: 2016-08-11 10:20
+Category: Tech
+Summary: A few months ago I was at an OpenBSD hackathon, here's my ((very) late) report for it.
+
+## Getting an account
+
+Since end of March I have had an OpenBSD account which means that I can do
+some commits on my own, the login I use is *danj*. I was then invited
+to [p2k16](https://www.openbsd.org/images/hackathons/p2k16.gif) which
+took place in Nantes, about 100kms from where I live (Rennes).
+
+## Planning
+
+I read most of hackathons report (if not all) on undeadly, and people
+often says that they had plans. So I thought I was going to do the
+same. Finally I did only a few things that I planned and other things
+I didn't plan at all :)
+
+## Meeting people
+
+Since 2013 I've been talking with jca@ (mainly about OpenBSD but not only),
+though I never had the chance to meet him. Finally at p2k16 I could
+finally meet him.
+
+I've also been talking on irc with landry@ for quite a long time, I
+was eager to meet him as I really appreciate him because we laugh
+together.
+
+I could also see again mpi@, who I didn't saw since my
+[internship](./some-news-from-my-internship.html).
+
+During the hackathon I could also talk with people that I had never
+talked to, before like espie@ or eric@. It was both funny and
+interesting as I learnt a couple of things while I was chatting with
+them.
+
+## Even teaching people
+
+I was still heavily learning at lot of things, whatever I was doing,
+though I was looking forward to share my (little) knowledge. I could
+show some tricks to tsg@ who was porting some python ports and at the
+same time working on
+[portgen](http://man.openbsd.org/OpenBSD-current/man1/portgen.1) to
+teach it to handle python ports. I was really happy/proud to be able to
+help him.
+
+I even could teach eric@ how to use cvs again :D. He didn't touch cvs
+for a while and in the mean time, new tools were created to help us like
+[portimport](http://man.openbsd.org/OpenBSD-current/man1/portimport.1)
+and he didn't know its existence so I showed him thus he could use it
+rather than importing his port (that I reviewed as it was a python
+port :3) manually.
+
+## The work
+
+I begun the week with committing an update to legit and its chains of
+\*_DEPS, it was quite a pain so I was happy to be over. After that, I
+updated a bunch of little ports. I reviewed a few ports for
+shadchin@. Python ports are usually easy (IMO) but the problem is
+that there are always tons of \*_DEPS which quickly sums up.
+
+I left a bit the python ports to update osm2pgsql. They switched their
+build system from autotools to cmake. Some people don't like
+autotools, other don't like cmake and many hate both but in my case I
+don't know them well so it doesn't make a lot of difference. At first
+I didn't succeed to make the test pass (but of course osm2pgsql was
+tested to be working), but after being home I worked on it again, and
+I was glad of my work.
+
+One of my plan was to port py-tox as it's used by nearly all python
+software for the tests. jca@ told me to look into
+[openbsd-wip](https://github.com/jasperla/openbsd-wip) and indeed it
+was already done by shadchin@, I bring it to ports@ and ok'ed it so he
+imported it.
+
+Finally, I begin to work on poezio, a python3 xmpp client. I needed
+some directions as some of its \*_DEPS were python3-only and currently
+the port infrastructure for python ports is mainly axed towards
+python2, and sthen@ kindly helped me.
+
+## The end
+
+Of course, I was sad when it ended, seeing people leaving
+gradually. I was really happy of the whole week, meeting people I was
+quite fond of. The meals were goods, with lots of
+[galettes](https://fr.wikipedia.org/wiki/Galette_de_sarrasin) and
+[crepes](https://en.wikipedia.org/wiki/Cr%C3%AApe) (even though we
+were not in Brittany). Thanks to all who made it possible! Would
+definitely do again.
blob - /dev/null
blob + 778864e178de79355f38d0b856da7b2722cf75aa (mode 644)
--- /dev/null
+++ content/p2k18.md
@@ -0,0 +1,112 @@
+Title: Hackathon report - p2k18
+Date: 2018-05-03 10:20
+Category: Tech
+Summary: Another ports hackathon in Nantes, France
+
+After two mostly boring flights, I was in Nantes on Sunday. I didn't do much
+because I wanted to get some rest after an exhausting week and tried to get my
+body into this new timezone. After a long night of sleep, I went to the hackroom.
+It was already well crowded for the first morning.
+
+On Friday the week before, I asked my boss at 5 pm if I had to take days off. He said
+"no" as a way to support my work on Open Source—it had been the same for
+[t2k17](./t2k17.html). I made a deal with myself that I would finish what I was
+working on for a customer instead of asking my coworker. So a large part of my
+Monday was finishing that stuff. Still, [I updated a port I maintain,
+pqiv](https://github.com/openbsd/ports/commit/a322d2ddc88df925eb9c719578e9f6aca0096298).
+I received a [generous donation](https://chown.me/iota/dmesg/dmesg-x1.txt) from [Mischa
+Peters](https://twitter.com/mischapeters) so I installed OpenBSD on it (thanks
+to jasper@ for carrying it!).
+
+Installing OpenBSD was not that trivial because I didn't have any USB key and
+the wired NIC required an adapter which I didn't have and the wifi NIC required
+a firmware to work. Thanks to [our marvelous
+organizer](https://twitter.com/poolporg) for providing me a USB key and stsp@ for
+lending me a USB NIC (which later [krw@ used to debug a dhclient
+bug](https://undeadly.org/cgi?action=article;sid=20180430190108)!). After that,
+I installed the packages I use, rsync'ed my home from my work laptop I was
+using until then like a lil' pig and felt immediately at home!
+
+I really begin the ports hackathon on Tuesday when I committed an update for
+py-setuptools. I had already [updated them](./b2k16.html) 18 months ago. It was
+easy to do it because I already did all the work a few weeks ago. My plan was
+to commit it before the hackathon but the clang6 fallout decided otherwise. I
+needed this setuptools to port upt. [upt](https://framagit.org/upt) is a
+"modular tool that helps people package software from PyPI/CPAN/etc. to
+OpenBSD/GNU Guix/etc". It's made by a [very good friend of
+mine](https://perso.aquilenet.fr/~steap/) so I sent him a bunch of [really
+nice](https://framagit.org/upt/upt-rubygems/commit/ccb5c2c1f9df2c383a02b2297f0354c3692757b4)
+[diffs](https://framagit.org/upt/upt-cpan/commit/893ef4aed42a121fb2adb6412dd9c91f81a8e8f0).
+
+I imported spdx and spdx-lookup which are a database of licenses and a tool to
+query it. That's the tool upt is using to
+[guess](https://framagit.org/upt/upt/blob/master/upt/licenses.py#L702) the
+license used. Then, I decided to call it a day. The morning was stressful, and rain was forecasted for the next few days. This pushed me to go see the city. I went to
+see [*Les Machines De L'Île*](https://www.lesmachines-nantes.fr/en/). Sadly the
+Elephant was sick so I couldn't ride him. He was fine enough to spit water on
+kids though. What makes me even sadder is that I didn't photograph the
+billboard saying it was sick. It would have been such a cool error page
+for when PostgreSQL is down!
+
+I also visited *Le Chateau des Ducs de Bretagne* and *Le Jardin des Plantes*
+which both were awesome with the nice blue sky I had. It was also funny to
+notice that the people of Nantes try to trick people, with putting "de Bretagne"
+in various names, into thinking that Nantes is in Bretagne while it is not.
+Yup, I'm pretty happy to have a static blog without any comments system so
+there won't be any hateful reactions visible here :-)
+
+Once I got back to the hackroom, I review-n-committed a couple of diffs for
+python ports. I updated again pqiv as they released another bugfix release and
+did some reviews for the [boar port from solene@](https://undeadly.org/cgi?action=article;sid=20180429101745).
+
+I spent Wednesday only doing reviews for other devs—facette, influxdb for
+landry@, and several python ports for pvk@. At 5 pm I was fed up, so I went to
+the supermarket and bought some Belgian beers (*Trappe Quadrupel* and
+*Westmalle* mainly but also some *Chimay*). Once drunk I went to play ping-pong
+with other French hackers. A few hours—and less alcohol in my blood—later, I
+finally updated my main server to OpenBSD 6.3 which went fine.
+
+I also looked at setting `PORTS_PRIVSEP=Yes` being one of the ["new
+converts"](https://undeadly.org/cgi?action=article;sid=20180429190200), but I
+had some [problems](https://marc.info/?l=openbsd-ports-cvs&m=152466817003263&w=2)
+(this commit message actually makes me laugh so much) so I eventually decided to
+rollback. Now, however, I know which permissions to set if I want to enable it
+again so that's cool!
+
+Thursday was low-hanging-fruit day. One of the commits renamed a package and so
+I needed to add a quirks entry. I did all of it on my own and I was glad to see
+how much more comfortable I was after two years (I got my *commit bit* shortly
+before p2k16 which happened 2 years ago).
+
+Until Friday, I didn't submit upt because I was waiting for Cyril to send an
+email about it. He finally sent
+[it](https://marc.info/?l=openbsd-ports&m=152478073001511&w=2) so I submitted
+it while replying to his email. I had already talked about it to landry@
+because he wanted to port a dozen of python ports. I told him this tool
+could help him so he was eager to try it. I finally imported it after a couple
+of back and forth between landry@ and I.
+
+Saturday was my last day as I was traveling on Sunday. I reviewed
+collectd/liboping for landry@, looked at the new
+[Flask](https://www.palletsprojects.com/blog/flask-1-0-released/). During
+p2k16, I talked with eric@ about ports where he was listed as maintainer. This
+time I succeeded in convincing him that his time was better spent on OpenSMTPD so
+there was no need to for him to be listed as maintainer. My final commit for
+p2k18 was freeing him from the ports tree :-)
+
+A while ago, I bought two [pine64](./playing-with-the-pine64.html) but they
+were not that useful for my use cases—too slow and unreliable. For a few weeks,
+semarie was using one of them remotely to work on rust/arm64. But when it
+stopped working, I had to investigate which didn't please my laziness. I offered
+him to take one and give it to him. He gladly accepted and then it was quickly [put to
+use](https://marc.info/?l=openbsd-bugs&m=152526381422932&w=2)!
+
+It was very nice to see Nantes and my fellow OpenBSD hackers again. I could commit
+the diffs I had for a few weeks and reviewed some submissions that enhance what
+you can `pkg_add` on OpenBSD. Thanks to gilles@ for all the organization and to
+Epitech for hosting us again and to the OpenBSD Foundation for the fundings!
+
+
+
+
+
blob - /dev/null
blob + 89c4df3a91e57a60f7bec118ce73e58146a5a7d1 (mode 644)
--- /dev/null
+++ content/pics2html.md
@@ -0,0 +1,128 @@
+Title: How I accidentally wrote a static site generator
+Date: 2020-04-15 10:20
+Category: Tech
+Summary: How I accidentally wrote a static site generator
+
+# Some context first
+
+I bought my
+[DSLR](https://en.wikipedia.org/wiki/Digital_single-lens_reflex_camera) at the
+end of 2014. I wanted to host the resulting pictures somewhere. I never liked
+much Flickr so I went with 500px. I liked the website, the UI/UX was pretty
+nice. The community was pretty cool. Having around skilled photographers is
+really valuable as you may learn and find inspiration. It may also hurt (it
+definitely did sometime) to see photographs much better than yours!
+
+For some unrelated reason, I kinda stopped photography in 2017. I took a few
+pictures here and there but didn't do anything with them. Basically the cost
+(i.e. the time the whole thing took) was way higher than what I felt I got from
+it (emotions or whatever).
+
+At the beginning of 2020, I went through all my data on my personal storage
+(which included my pictures) to sort and rearrange it. It made me happy to
+have all those *souvenirs* and I thought I should really go shoot again.
+
+This narrative is not entirely true though. ;)
+
+While it did happen, it didn't happen first. I bought [a case for my
+photography
+gear](https://dumpster.chown.me/mastodon/media_attachments/files/000/050/759/original/18e91ddf4f0c6ce4.jpeg)
+for some unrelated reasons (compulsive buying) and thought if I was spending
+money on it again, I should make good use of it. Nevertheless, the souvenirs
+really nailed my motivation!
+
+Initially I thought I could keep using 500px but I realized I lost my access
+and that during my hiatus [they had been
+pwned](https://support.500px.com/hc/en-us/articles/360017752493-Security-Issue-February-2019-FAQ).
+Now that I had more experience about publishing pictures on the Internet, I had
+a better idea of what I wanted, or cared about. During those years, I also acquired
+much more experience in [hosting my services](./infrastructure-2019.html) which
+I try to do for everything I use.
+
+# Looking for some FOSS
+
+I thought writing my own would be difficult/time consuming, so I went for doing
+what I do best: use an existing Free Software. I carefully thought my
+requirements. And here they are.
+
+A quality project is both subjective, and an obvious requirement so I won't
+talk more about it. But PHP apps written by someone who wanted a first project,
+I'll pass :)
+
+I really care about showing [EXIF](https://en.wikipedia.org/wiki/Exif) for
+pictures. Like for software, being able to study how it's made is really
+helpful. I feel like pictures without EXIF are as interesting as closed source
+software so I tend to ignore both. (In a photography context of course, I won't
+look at what phone model took that cat picture.)
+
+On a side note, I surprisingly found that some people recently created
+galleries software and plugged machine learning into them. Well I've better use
+for my computing power and I prefer simpler things.
+
+AND SHOW THOSE DAMN EXIF!
+
+# Writing my own - the process
+
+Sadly, I didn't find anything that met those two simple requirements.
+
+Because of that, I thought I would either write something myself or put them
+into my blog. I was not very fond of putting my pictures on my blog (as a weird
+application of the "do one thing and do it well" rule) but even if I did, I
+wouldn't want to extract the EXIF myself/manually for each picture.
+
+I began a python script which parsed the EXIF, which was kind of funny. For
+instance the library I use gives a tuple for the exposure and depending on each
+field's value, [it has a different
+meaning](https://github.com/danieljakots/pics2html/blob/c08e2b17476e28e8304bfaadc94f76d77d4c74df/pics2html.py#L62-L74).
+
+I had already used jinja2 in my [uv](https://github.com/danieljakots/uv)
+script, so I thought "let's generate a basic html page!" since it was easy.
+That was my other plan than using my blog. Since I know nothing about web
+design/frontend and I wasn't much enthusiastic, I thought maybe I would later
+hire someone to do it.
+
+I began to add some very basic CSS to experiment. I had scavenged it from some
+random website which had the nice quality of being very simple! I was happy
+with the result so I tried to improve it further. I thought "if I'm stuck or
+stop having fun, then I'll look into hiring" which eased me a lot!
+
+As surprising as it can be, I didn't struggle that much and I did have fun!
+Tackling one small issue at a time made it a breeze.
+
+Finally I thought that using icons were better than text since it conveys as
+much information while being much much shorter. I had bookmarked a few days
+before a [set of icons](https://github.com/tabler/tabler-icons) (because
+they're MIT licensed) thinking "I doubt I'll ever need these but who knows".
+The set didn't have an icon for the *lens* so I used the *lego* icon. It looks
+quite the same and it has a smile on it! What's not to love!
+
+During the whole process I went to look at how I did stuff with my blog and I
+noticed the complete mess it was. Seeing how easy writing a static site
+generator was, made me want to write one for my blog. So stay tuned! ;)
+
+# The result
+
+The result is available there: <https://px.chown.me/>. The [code is of course
+available](https://github.com/danieljakots/pics2html) as well.
+
+I would not necessarily advise someone to reuse the code as is (even though
+you definitely can since it's Free Software). It's pretty tailored for my
+need. For instance the red color used is the same than on my
+[blog](./new-design.html) (coherency FTW). I made no effort to make it easily
+customizable, more than what I needed to make the code maintainable (up to a
+certain point since I have exactly 0 test, I already feel my future self's
+frustration, *oops!*).
+
+That said, if you're thinking about building something similar, you're totally
+free (well as long as you abide by the license terms ;)) to study/take some
+part from it!
+
+I'm really glad with the result, the code is pretty simple (though some hacks
+lie here and there) as you would expect from a less-than-300-line python
+script. I learned quite a few things (e.g. improved my skill with jinja2,
+creating a RSS feed is actually not that hard, etc). I'm really happy with what
+the website looks like. Doing web design was completely unusual for me so it was
+nice to do something different!
+
+And it's funny, I do things that are 1000x times more complicated, but
+generating 200 html files with a single command feels really like magic!
blob - /dev/null
blob + be5b256ad4fad97a72547c3d0333ea2a8618f5a0 (mode 644)
--- /dev/null
+++ content/playing-with-the-pine64.md
@@ -0,0 +1,612 @@
+Title: Playing with the pine64
+Date: 2017-10-19 10:20
+Category: Tech
+Summary: Some notes about how to get started with OpenBSD on the pine64
+
+## Finding something to install on it
+
+6 weeks ago, I ordered two pine64 units. I didn't (and still don't)
+have much plan for them, but I wanted to play with some cheap
+boards. I finally received them this week. Initially I wanted to
+install some Linux stuff on it, I didn't have much requirement so I
+thought I would just look what seems to be easy and/or the best
+supported systemd flavour. I headed over their
+[wiki](http://wiki.pine64.org/index.php/Pine_A64_Software_Release). Everything
+seems either not really maintained, done by some random people or
+both. I am not saying random people do bad things, just that
+installing some random things from the Internet is not really my cup
+of tea.
+
+I heard about [Armbian](https://www.armbian.com/pine64/) but the
+server flavour seems to be experimental so I got scared of it. And
+sadly, the whole things looks like to be alot undermanned.
+
+So I went for OpenBSD because I know the stuff and who to har^Wkindly
+ask for help. Spoiler alert, it's boring because it just works.
+
+## Getting OpenBSD on it
+
+I downloaded miniroot62.fs, dd'ed it on the micro SD card. I was
+afraid I'd need to fiddle with some things like sysutils/dtb because I
+don't know what I would have needed to do. That's because I don't know
+what it does and for this precise reason I was wrong and I didn't need
+to do anything. So just dd the miniroot62.fs and you can go to next
+checkpoint.
+
+I plugged an HDMI cable, ethernet cable and the power, it booted, I
+could read for 10 seconds but then it got dark. Of course it's because
+you need a serial console. Of course I didn't have one.
+
+I thought about trying to install OpenBSD blindly, I could have
+probably succeeded with autoinstall buuuuuut...
+
+Following some good pieces of advice from OpenBSD people I bought some
+cp2102 (I didn't try to understand what it was or what were the other
+possibilities, I just wanted something that would work :D).
+
+I looked how to plug the thing. It appears you can plug it on [two
+different places](http://linux-sunxi.org/File:Pine64_UART0.jpg) but
+if you plug it on the *Euler bus* it could power a bit the board so if
+you try to reboot it, it would then mess with the power disruption and
+could lead a unclean reboot.
+
+You just need to plug three cables: GND, TXD and RXD. Of course, the
+TXD goes on the RXD pin from the picture and the RXD goes on the TXD
+pin. Guess why I'm telling you that!
+
+## That's it
+
+Then you can connect with the usual
+
+ $ cu -dl /dev/cuaU0 -s 115200
+
+You can now install it and the reboot it:
+
+ INFO: PSCI Affinity Map:
+ INFO: AffInst: Level 0, MPID 0x0, State ON
+ INFO: AffInst: Level 0, MPID 0x1, State OFF
+ INFO: AffInst: Level 0, MPID 0x2, State OFF
+ INFO: AffInst: Level 0, MPID 0x3, State OFF
+
+ U-Boot SPL 2017.09 (Sep 13 2017 - 04:48:58)
+ DRAM: 2048 MiB
+ Trying to boot from MMC1
+ NOTICE: BL3-1: Running on A64/H64 (1689) in SRAM A2 (@0x44000)
+ NOTICE: Configuring SPC Controller
+ NOTICE: BL3-1: v1.0(debug):20170702
+ NOTICE: BL3-1: Built : 04:34:32, Sep 13 2017
+ NOTICE: Configuring AXP PMIC
+ NOTICE: PMIC: setup successful
+ NOTICE: SCPI: dummy stub handler, implementation level: 000000
+ INFO: BL3-1: Initializing runtime services
+ INFO: BL3-1: Preparing for EL3 exit to normal world
+ INFO: BL3-1: Next image address: 0x4a000000, SPSR: 0x3c9
+
+
+ U-Boot 2017.09 (Sep 13 2017 - 04:48:58 -0600) Allwinner Technology
+
+ CPU: Allwinner A64 (SUN50I)
+ Model: Pine64+
+ DRAM: 2 GiB
+ MMC: SUNXI SD/MMC: 0
+ *** Warning - bad CRC, using default environment
+
+ In: serial
+ Out: serial
+ Err: serial
+ Net: phy interface7
+ eth0: ethernet@01c30000
+ starting USB...
+ USB0: USB EHCI 1.00
+ USB1: USB OHCI 1.0
+ scanning bus 0 for devices... 1 USB Device(s) found
+ scanning usb for storage devices... 0 Storage Device(s) found
+ Hit any key to stop autoboot: 0
+ switch to partitions #0, OK
+ mmc0 is current device
+ Scanning mmc 0:1...
+ Found EFI removable media binary efi/boot/bootaa64.efi
+ reading efi/boot/bootaa64.efi
+ 78335 bytes read in 36 ms (2.1 MiB/s)
+ libfdt fdt_check_header(): FDT_ERR_BADMAGIC
+ ## Starting EFI application at 40080000 ...
+ Scanning disks on usb...
+ Scanning disks on mmc...
+ MMC Device 1 not found
+ MMC Device 2 not found
+ MMC Device 3 not found
+ Found 5 disks
+ >> OpenBSD/arm64 BOOTAA64 0.8
+ boot>
+ booting sd0a:/bsd: 3861360+574928+511472+807968 [285863+96+451944+239980]=0x831130
+ type 0x2 pa 0x40000000 va 0x40000000 pages 0x4000 attr 0x8
+ type 0x7 pa 0x44000000 va 0x40000000 pages 0x4000 attr 0x8
+ type 0x4 pa 0x48000000 va 0x48000000 pages 0x4 attr 0x8
+ type 0x7 pa 0x48005000 va 0x40000000 pages 0x70832 attr 0x8
+ type 0x2 pa 0xb8837000 va 0xb8837000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb883b000 va 0xb883b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb883f000 va 0xb883f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8843000 va 0xb8843000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8847000 va 0xb8847000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb884b000 va 0xb884b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb884f000 va 0xb884f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8853000 va 0xb8853000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8857000 va 0xb8857000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb885b000 va 0xb885b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb885f000 va 0xb885f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8863000 va 0xb8863000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8867000 va 0xb8867000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb886b000 va 0xb886b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb886f000 va 0xb886f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8873000 va 0xb8873000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8877000 va 0xb8877000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb887b000 va 0xb887b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb887f000 va 0xb887f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8883000 va 0xb8883000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8887000 va 0xb8887000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb888b000 va 0xb888b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb888f000 va 0xb888f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8893000 va 0xb8893000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8897000 va 0xb8897000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb889b000 va 0xb889b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb889f000 va 0xb889f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb88a3000 va 0xb88a3000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb88a7000 va 0xb88a7000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb88ab000 va 0xb88ab000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb88af000 va 0xb88af000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb88b3000 va 0xb88b3000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb88b7000 va 0xb88b7000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb88bb000 va 0xb88bb000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb88bf000 va 0xb88bf000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb88c3000 va 0xb88c3000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb88c7000 va 0xb88c7000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb88cb000 va 0xb88cb000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb88cf000 va 0xb88cf000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb88d3000 va 0xb88d3000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb88d7000 va 0xb88d7000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb88db000 va 0xb88db000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb88df000 va 0xb88df000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb88e3000 va 0xb88e3000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb88e7000 va 0xb88e7000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb88eb000 va 0xb88eb000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb88ef000 va 0xb88ef000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb88f3000 va 0xb88f3000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb88f7000 va 0xb88f7000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb88fb000 va 0xb88fb000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb88ff000 va 0xb88ff000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8903000 va 0xb8903000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8907000 va 0xb8907000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb890b000 va 0xb890b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb890f000 va 0xb890f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8913000 va 0xb8913000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8917000 va 0xb8917000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb891b000 va 0xb891b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb891f000 va 0xb891f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8923000 va 0xb8923000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8927000 va 0xb8927000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb892b000 va 0xb892b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb892f000 va 0xb892f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8933000 va 0xb8933000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8937000 va 0xb8937000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb893b000 va 0xb893b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb893f000 va 0xb893f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8943000 va 0xb8943000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8947000 va 0xb8947000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb894b000 va 0xb894b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb894f000 va 0xb894f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8953000 va 0xb8953000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8957000 va 0xb8957000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb895b000 va 0xb895b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb895f000 va 0xb895f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8963000 va 0xb8963000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8967000 va 0xb8967000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb896b000 va 0xb896b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb896f000 va 0xb896f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8973000 va 0xb8973000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8977000 va 0xb8977000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb897b000 va 0xb897b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb897f000 va 0xb897f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8983000 va 0xb8983000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8987000 va 0xb8987000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb898b000 va 0xb898b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb898f000 va 0xb898f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8993000 va 0xb8993000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8997000 va 0xb8997000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb899b000 va 0xb899b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb899f000 va 0xb899f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb89a3000 va 0xb89a3000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb89a7000 va 0xb89a7000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb89ab000 va 0xb89ab000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb89af000 va 0xb89af000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb89b3000 va 0xb89b3000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb89b7000 va 0xb89b7000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb89bb000 va 0xb89bb000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb89bf000 va 0xb89bf000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb89c3000 va 0xb89c3000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb89c7000 va 0xb89c7000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb89cb000 va 0xb89cb000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb89cf000 va 0xb89cf000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb89d3000 va 0xb89d3000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb89d7000 va 0xb89d7000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb89db000 va 0xb89db000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb89df000 va 0xb89df000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb89e3000 va 0xb89e3000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb89e7000 va 0xb89e7000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb89eb000 va 0xb89eb000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb89ef000 va 0xb89ef000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb89f3000 va 0xb89f3000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb89f7000 va 0xb89f7000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb89fb000 va 0xb89fb000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb89ff000 va 0xb89ff000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8a03000 va 0xb8a03000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8a07000 va 0xb8a07000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8a0b000 va 0xb8a0b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8a0f000 va 0xb8a0f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8a13000 va 0xb8a13000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8a17000 va 0xb8a17000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8a1b000 va 0xb8a1b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8a1f000 va 0xb8a1f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8a23000 va 0xb8a23000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8a27000 va 0xb8a27000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8a2b000 va 0xb8a2b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8a2f000 va 0xb8a2f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8a33000 va 0xb8a33000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8a37000 va 0xb8a37000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8a3b000 va 0xb8a3b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8a3f000 va 0xb8a3f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8a43000 va 0xb8a43000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8a47000 va 0xb8a47000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8a4b000 va 0xb8a4b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8a4f000 va 0xb8a4f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8a53000 va 0xb8a53000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8a57000 va 0xb8a57000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8a5b000 va 0xb8a5b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8a5f000 va 0xb8a5f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8a63000 va 0xb8a63000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8a67000 va 0xb8a67000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8a6b000 va 0xb8a6b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8a6f000 va 0xb8a6f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8a73000 va 0xb8a73000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8a77000 va 0xb8a77000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8a7b000 va 0xb8a7b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8a7f000 va 0xb8a7f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8a83000 va 0xb8a83000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8a87000 va 0xb8a87000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8a8b000 va 0xb8a8b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8a8f000 va 0xb8a8f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8a93000 va 0xb8a93000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8a97000 va 0xb8a97000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8a9b000 va 0xb8a9b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8a9f000 va 0xb8a9f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8aa3000 va 0xb8aa3000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8aa7000 va 0xb8aa7000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8aab000 va 0xb8aab000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8aaf000 va 0xb8aaf000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8ab3000 va 0xb8ab3000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8ab7000 va 0xb8ab7000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8abb000 va 0xb8abb000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8abf000 va 0xb8abf000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8ac3000 va 0xb8ac3000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8ac7000 va 0xb8ac7000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8acb000 va 0xb8acb000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8acf000 va 0xb8acf000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8ad3000 va 0xb8ad3000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8ad7000 va 0xb8ad7000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8adb000 va 0xb8adb000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8adf000 va 0xb8adf000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8ae3000 va 0xb8ae3000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8ae7000 va 0xb8ae7000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8aeb000 va 0xb8aeb000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8aef000 va 0xb8aef000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8af3000 va 0xb8af3000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8af7000 va 0xb8af7000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8afb000 va 0xb8afb000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8aff000 va 0xb8aff000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8b03000 va 0xb8b03000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8b07000 va 0xb8b07000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8b0b000 va 0xb8b0b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8b0f000 va 0xb8b0f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8b13000 va 0xb8b13000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8b17000 va 0xb8b17000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8b1b000 va 0xb8b1b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8b1f000 va 0xb8b1f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8b23000 va 0xb8b23000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8b27000 va 0xb8b27000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8b2b000 va 0xb8b2b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8b2f000 va 0xb8b2f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8b33000 va 0xb8b33000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8b37000 va 0xb8b37000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8b3b000 va 0xb8b3b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8b3f000 va 0xb8b3f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8b43000 va 0xb8b43000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8b47000 va 0xb8b47000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8b4b000 va 0xb8b4b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8b4f000 va 0xb8b4f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8b53000 va 0xb8b53000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8b57000 va 0xb8b57000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8b5b000 va 0xb8b5b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8b5f000 va 0xb8b5f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8b63000 va 0xb8b63000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8b67000 va 0xb8b67000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8b6b000 va 0xb8b6b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8b6f000 va 0xb8b6f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8b73000 va 0xb8b73000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8b77000 va 0xb8b77000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8b7b000 va 0xb8b7b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8b7f000 va 0xb8b7f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8b83000 va 0xb8b83000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8b87000 va 0xb8b87000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8b8b000 va 0xb8b8b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8b8f000 va 0xb8b8f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8b93000 va 0xb8b93000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8b97000 va 0xb8b97000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8b9b000 va 0xb8b9b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8b9f000 va 0xb8b9f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8ba3000 va 0xb8ba3000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8ba7000 va 0xb8ba7000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8bab000 va 0xb8bab000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8baf000 va 0xb8baf000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8bb3000 va 0xb8bb3000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8bb7000 va 0xb8bb7000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8bbb000 va 0xb8bbb000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8bbf000 va 0xb8bbf000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8bc3000 va 0xb8bc3000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8bc7000 va 0xb8bc7000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8bcb000 va 0xb8bcb000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8bcf000 va 0xb8bcf000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8bd3000 va 0xb8bd3000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8bd7000 va 0xb8bd7000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8bdb000 va 0xb8bdb000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8bdf000 va 0xb8bdf000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8be3000 va 0xb8be3000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8be7000 va 0xb8be7000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8beb000 va 0xb8beb000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8bef000 va 0xb8bef000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8bf3000 va 0xb8bf3000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8bf7000 va 0xb8bf7000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8bfb000 va 0xb8bfb000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8bff000 va 0xb8bff000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8c03000 va 0xb8c03000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8c07000 va 0xb8c07000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8c0b000 va 0xb8c0b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8c0f000 va 0xb8c0f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8c13000 va 0xb8c13000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8c17000 va 0xb8c17000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8c1b000 va 0xb8c1b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8c1f000 va 0xb8c1f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8c23000 va 0xb8c23000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8c27000 va 0xb8c27000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8c2b000 va 0xb8c2b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8c2f000 va 0xb8c2f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8c33000 va 0xb8c33000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8c37000 va 0xb8c37000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8c3b000 va 0xb8c3b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8c3f000 va 0xb8c3f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8c43000 va 0xb8c43000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8c47000 va 0xb8c47000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8c4b000 va 0xb8c4b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8c4f000 va 0xb8c4f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8c53000 va 0xb8c53000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8c57000 va 0xb8c57000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8c5b000 va 0xb8c5b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8c5f000 va 0xb8c5f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8c63000 va 0xb8c63000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8c67000 va 0xb8c67000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8c6b000 va 0xb8c6b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8c6f000 va 0xb8c6f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8c73000 va 0xb8c73000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8c77000 va 0xb8c77000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8c7b000 va 0xb8c7b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8c7f000 va 0xb8c7f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8c83000 va 0xb8c83000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8c87000 va 0xb8c87000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8c8b000 va 0xb8c8b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8c8f000 va 0xb8c8f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8c93000 va 0xb8c93000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8c97000 va 0xb8c97000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8c9b000 va 0xb8c9b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8c9f000 va 0xb8c9f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8ca3000 va 0xb8ca3000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8ca7000 va 0xb8ca7000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8cab000 va 0xb8cab000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8caf000 va 0xb8caf000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8cb3000 va 0xb8cb3000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8cb7000 va 0xb8cb7000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8cbb000 va 0xb8cbb000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8cbf000 va 0xb8cbf000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8cc3000 va 0xb8cc3000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8cc7000 va 0xb8cc7000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8ccb000 va 0xb8ccb000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8ccf000 va 0xb8ccf000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8cd3000 va 0xb8cd3000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8cd7000 va 0xb8cd7000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8cdb000 va 0xb8cdb000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8cdf000 va 0xb8cdf000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8ce3000 va 0xb8ce3000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8ce7000 va 0xb8ce7000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8ceb000 va 0xb8ceb000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8cef000 va 0xb8cef000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8cf3000 va 0xb8cf3000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8cf7000 va 0xb8cf7000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8cfb000 va 0xb8cfb000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8cff000 va 0xb8cff000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8d03000 va 0xb8d03000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8d07000 va 0xb8d07000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8d0b000 va 0xb8d0b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8d0f000 va 0xb8d0f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8d13000 va 0xb8d13000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8d17000 va 0xb8d17000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8d1b000 va 0xb8d1b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8d1f000 va 0xb8d1f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8d23000 va 0xb8d23000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8d27000 va 0xb8d27000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8d2b000 va 0xb8d2b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8d2f000 va 0xb8d2f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8d33000 va 0xb8d33000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8d37000 va 0xb8d37000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8d3b000 va 0xb8d3b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8d3f000 va 0xb8d3f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8d43000 va 0xb8d43000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8d47000 va 0xb8d47000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8d4b000 va 0xb8d4b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8d4f000 va 0xb8d4f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8d53000 va 0xb8d53000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8d57000 va 0xb8d57000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8d5b000 va 0xb8d5b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8d5f000 va 0xb8d5f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8d63000 va 0xb8d63000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8d67000 va 0xb8d67000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8d6b000 va 0xb8d6b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8d6f000 va 0xb8d6f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8d73000 va 0xb8d73000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8d77000 va 0xb8d77000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8d7b000 va 0xb8d7b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8d7f000 va 0xb8d7f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8d83000 va 0xb8d83000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8d87000 va 0xb8d87000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8d8b000 va 0xb8d8b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8d8f000 va 0xb8d8f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8d93000 va 0xb8d93000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8d97000 va 0xb8d97000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8d9b000 va 0xb8d9b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8d9f000 va 0xb8d9f000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8da3000 va 0xb8da3000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8da7000 va 0xb8da7000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8dab000 va 0xb8dab000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8daf000 va 0xb8daf000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8db3000 va 0xb8db3000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8db7000 va 0xb8db7000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8dbb000 va 0xb8dbb000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8dbf000 va 0xb8dbf000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8dc3000 va 0xb8dc3000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8dc7000 va 0xb8dc7000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8dcb000 va 0xb8dcb000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8dcf000 va 0xb8dcf000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8dd3000 va 0xb8dd3000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8dd7000 va 0xb8dd7000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8ddb000 va 0xb8ddb000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8ddf000 va 0xb8ddf000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8de3000 va 0xb8de3000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8de7000 va 0xb8de7000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8deb000 va 0xb8deb000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8def000 va 0xb8def000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8df3000 va 0xb8df3000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8df7000 va 0xb8df7000 pages 0x1 attr 0x8
+ type 0x2 pa 0xb8df8000 va 0xb8df8000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8dfc000 va 0xb8dfc000 pages 0x2 attr 0x8
+ type 0x2 pa 0xb8dfe000 va 0xb8dfe000 pages 0x1 attr 0x8
+ type 0x2 pa 0xb8dff000 va 0xb8dff000 pages 0x1 attr 0x8
+ type 0x2 pa 0xb8e00000 va 0xb8e00000 pages 0x1 attr 0x8
+ type 0x2 pa 0xb8e01000 va 0xb8e01000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8e05000 va 0xb8e05000 pages 0x1 attr 0x8
+ type 0x2 pa 0xb8e06000 va 0xb8e06000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8e0a000 va 0xb8e0a000 pages 0x1 attr 0x8
+ type 0x2 pa 0xb8e0b000 va 0xb8e0b000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8e0f000 va 0xb8e0f000 pages 0x2 attr 0x8
+ type 0x2 pa 0xb8e11000 va 0xb8e11000 pages 0x1 attr 0x8
+ type 0x2 pa 0xb8e12000 va 0xb8e12000 pages 0x1 attr 0x8
+ type 0x2 pa 0xb8e13000 va 0xb8e13000 pages 0x1 attr 0x8
+ type 0x2 pa 0xb8e14000 va 0xb8e14000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8e18000 va 0xb8e18000 pages 0x1 attr 0x8
+ type 0x2 pa 0xb8e19000 va 0xb8e19000 pages 0x4 attr 0x8
+ type 0x2 pa 0xb8e1d000 va 0xb8e1d000 pages 0x2 attr 0x8
+ type 0x2 pa 0xb8e1f000 va 0xb8e1f000 pages 0x1 attr 0x8
+ type 0x2 pa 0xb8e20000 va 0xb8e20000 pages 0x1 attr 0x8
+ type 0x2 pa 0xb8e21000 va 0xb8e21000 pages 0x100 attr 0x8
+ type 0x6 pa 0xb8f21000 va 0xb8f21000 pages 0x1 attr 0x8000000000000008
+ type 0x2 pa 0xb8f22000 va 0xb8f22000 pages 0x13 attr 0x8
+ type 0x2 pa 0xb8f35000 va 0xb8f35000 pages 0x5085 attr 0x8
+ type 0x5 pa 0xbdfba000 va 0xbdfba000 pages 0x1 attr 0x8000000000000008
+ type 0x2 pa 0xbdfbb000 va 0xb8f35000 pages 0x2045 attr 0x8
+ [ using 978720 bytes of bsd ELF symbol table ]
+ Copyright (c) 1982, 1986, 1989, 1991, 1993
+ The Regents of the University of California. All rights reserved.
+ Copyright (c) 1995-2017 OpenBSD. All rights reserved. https://www.OpenBSD.org
+
+ OpenBSD 6.2-current (GENERIC) #47: Wed Oct 18 11:56:57 MDT 2017
+ deraadt@arm64.openbsd.org:/usr/src/sys/arch/arm64/compile/GENERIC
+ real mem = 2021859328 (1928MB)
+ avail mem = 1935818752 (1846MB)
+ mainbus0 at root: Pine64+
+ cpu0 at mainbus0: ARM Cortex-A53 r0p4
+ psci0 at mainbus0
+ agtimer0 at mainbus0: tick rate 24000 KHz
+ simplebus0 at mainbus0: "soc"
+ sxiccmu0 at simplebus0
+ sxipio0 at simplebus0: 103 pins
+ sximmc0 at simplebus0
+ sdmmc0 at sximmc0: 4-bit, sd high-speed, mmc high-speed, dma
+ ehci0 at simplebus0
+ usb0 at ehci0: USB revision 2.0
+ uhub0 at usb0 configuration 1 interface 0 "Generic EHCI root hub" rev 2.00/1.00 addr 1
+ com0 at simplebus0: ns16550, no working fifo
+ com0: console
+ ampintc0 at simplebus0 nirq 224, ncpu 4: "interrupt-controller"
+ sxirtc0 at simplebus0
+ dwxe0 at simplebus0: address 02:ba:b0:1b:de:88
+ rgephy0 at dwxe0 phy 0: RTL8169S/8110S/8211 PHY, rev. 5
+ rgephy1 at dwxe0 phy 1: RTL8169S/8110S/8211 PHY, rev. 5
+ gpio0 at sxipio0: 32 pins
+ gpio1 at sxipio0: 32 pins
+ gpio2 at sxipio0: 32 pins
+ gpio3 at sxipio0: 32 pins
+ gpio4 at sxipio0: 32 pins
+ gpio5 at sxipio0: 32 pins
+ gpio6 at sxipio0: 32 pins
+ gpio7 at sxipio0: 32 pins
+ scsibus0 at sdmmc0: 2 targets, initiator 0
+ sd0 at scsibus0 targ 1 lun 0: <SD/MMC, USD00, 0010> SCSI2 0/direct removable
+ sd0: 15080MB, 512 bytes/sector, 30883840 sectors
+ vscsi0 at root
+ scsibus1 at vscsi0: 256 targets
+ softraid0 at root
+ scsibus2 at softraid0: 256 targets
+ bootfile: sd0a:/bsd
+ boot device: sd0
+ root on sd0a (aad98897a9859bd0.a) swap on sd0b dump on sd0b
+ Automatic boot in progress: starting file system checks.
+ /dev/sd0a (aad98897a9859bd0.a): file system is clean; not checking
+ /dev/sd0l (aad98897a9859bd0.l): file system is clean; not checking
+ /dev/sd0d (aad98897a9859bd0.d): file system is clean; not checking
+ /dev/sd0f (aad98897a9859bd0.f): file system is clean; not checking
+ /dev/sd0g (aad98897a9859bd0.g): file system is clean; not checking
+ /dev/sd0h (aad98897a9859bd0.h): file system is clean; not checking
+ /dev/sd0k (aad98897a9859bd0.k): file system is clean; not checking
+ /dev/sd0j (aad98897a9859bd0.j): file system is clean; not checking
+ /dev/sd0e (aad98897a9859bd0.e): file system is clean; not checking
+ setting tty flags
+ pf enabled
+ starting network
+ dwxe0: DHCPREQUEST to 255.255.255.255
+ dwxe0: DHCPNACK from 10.20.20.254 (00:0d:b9:43:9f:fc)
+ dwxe0: DHCPDISCOVER - interval 1
+ dwxe0: DHCPOFFER from 10.20.20.254 (00:0d:b9:43:9f:fc)
+ dwxe0: DHCPREQUEST to 255.255.255.255
+ dwxe0: DHCPACK from 10.20.20.254 (00:0d:b9:43:9f:fc)
+ dwxe0: bound to 10.20.20.15 -- renewal in 21600 seconds
+ reordering libraries: done.
+ openssl: generating isakmpd/iked RSA keys... done.
+ ssh-keygen: generating new host keys: RSA DSA ECDSA ED25519
+ starting early daemons: syslogd pflogd ntpd.
+ starting RPC daemons:.
+ savecore: no core dump
+ checking quotas: done.
+ clearing /tmp
+ kern.securelevel: 0 -> 1
+ creating runtime link editor directory cache.
+ preserving editor files.
+ starting network daemons: sshd smtpd sndiod.
+ running rc.firsttime
+ Path to firmware: http://firmware.openbsd.org/firmware/snapshots/
+ No devices found which need firmware files to be downloaded.
+ starting local daemons: cron.
+ Wed Oct 18 17:52:37 MDT 2017
+
+ OpenBSD/arm64 (alpaga.chown.me) (console)
+
+ login:
+
+
+And now, I just have to wait for
+[Jean Canard](https://chown.me/iota/pics/IMG_0675.JPG) to destroy the
+whole thing.
blob - /dev/null
blob + 439d3e12ad84ee20605144862fca8486dc19cbcb (mode 644)
--- /dev/null
+++ content/routing-traffic-with-multiple-openvpn.md
@@ -0,0 +1,191 @@
+Title: Routing traffic with multiple OpenVPN
+Date: 2017-11-21 10:20
+Category: Tech
+Summary: On my home router, I have multiple instances of OpenVPN, and here I describe how I route my traffic
+
+
+## Why OpenVPN?
+
+For [my dayjob](https://evolix.ca/en) we access the servers we manage
+through OpenVPN. Of course it's not the only security measure, it's
+yet another layer and it helps to cut a part of the
+[IBN](https://en.wikipedia.org/wiki/Internet_background_noise). All of
+our servers are registered in
+[LDAP](https://en.wikipedia.org/wiki/Lightweight_Directory_Access_Protocol)
+and from this system we create some routes that the OpenVPN server
+pushes to the OpenVPN clients.
+
+## What did I need?
+
+### Follow the pushed routes, not always and not for all the hosts
+
+I work sometimes from home (for on-call or just remote work). I have a
+IP phone which needs the VPN but of course I can't setup OpenVPN on
+the phone directly, so the VPN has to go on my router. But let's say
+some android phone (without security updates) connects to my wifi, I
+don't want its traffic to go through the VPN.
+
+But I also have my own desktop that I don't want any of its traffic to
+go through the VPN, but sometimes I want it to use the routes if I
+want to quickly check something on a server.
+
+### Default route sometimes, sometimes not
+
+By default, clients don't set the gateway to the vpn, because we
+have the routes. But sometimes, we need to access a host through the
+VPN without having a route to it being pushed by the server. Hence I
+need to be able to route all the traffic through the vpn if
+needed. But not always because the vpn endpoint is 105ms away and
+browsing with this increased latency is obviously a bit slower.
+
+### Even with a default route, bypassing the VPN for some servers
+
+I have a VM in Montreal, 10ms away, and there's no reason that the
+traffic should go through the VPN. Same goes for my OpenBSD mirror.
+
+### Multiple VPN
+
+I also have another VPN which endpoints is in Montreal and I may want
+to route some host from my lan through it. It must independant from
+the other VPN.
+
+### Don't touch the server side
+
+My coworkers use the VPN as well so I can't change the server
+configuration just to suit my own need.
+
+## Suiting all the needs \o/
+
+I will only talk about the client as there's nothing special on the
+server side
+
+### OpenVPN infrastructure
+
+~~~
+danj@pancake:/etc/openvpn$ ls
+client-ca.conf client-fr.conf private-stuff/
+~~~
+
+Config files are as usual, the only special thing is that I force
+the tun device used by the VPN (so I can use it in pf.conf):
+
+~~~
+danj@pancake:/etc/openvpn$ grep dev *.conf
+client-ca.conf:dev tun1
+client-fr.conf:dev tun0
+~~~
+
+In `rc.conf.local`, I set the correct config file:
+
+~~~
+openvpn_fr_flags="--config /etc/openvpn/client-fr.conf"
+openvpn_ca_flags="--config /etc/openvpn/client-ca.conf"
+~~~
+
+now I can `rcctl start openvpn_fr` and `rcctl start openvpn_ca`
+
+### routing
+
+Spoiler alert, everything is done with pf.
+
+I won't put my whole pf.conf but only the needed parts. First let's
+describe the interface.
+
+~~~
+vpnfr_if = "tun0"
+vpnca_if = "tun1"
+~~~
+
+I have vlan-capable switch and wifi AP, so I have multiple networks.
+
+~~~
+lan_net = $lan_if:network
+wifilap_net = $wifilap_if:network
+wifitel_net = $wifitel_if:network
+windows_net = $windows_if:network
+tel_net = $tel_if:network
+~~~
+
+I need some tables (don't worry, you'll understand later what purpose
+they have).
+
+~~~
+table <softvpnfr> { 10.20.20.20 } persist
+table <vpnfr> { $phone } persist
+table <vpnca> { 10.10.10.60 } persist
+table <bypassfr> { 129.128.197.20, 129.128.5.191, 185.19.29.62, 167.114.216.84 } persist
+table <forcevpnfr> { $mrs-fw2 }
+table <nousautres> { 10.0.0.0/8, $home_ip } persist
+~~~
+
+Now we can see the ruleset. I let everything from the lan, that doesn't
+go on the router itself or to another lan (so the traffic will need
+another rules to be allowed) come through.
+
+~~~
+pass in on $lan_if from $lan_net to ! <nousautres>
+pass in on $wifilap_if from $wifilap_net to ! <nousautres>
+pass in on $wifitel_if from $wifitel_net to ! <nousautres>
+pass in on $tel_if from $tel to ! <nousautres>
+pass in log on $windows_if proto { tcp, udp } from $windows_net to ! <nousautres>
+~~~
+
+I let everything going out
+
+~~~
+pass out log on $ext_if proto { tcp, udp } all modulate state
+pass out on $vpnfr_if proto { tcp, udp } all modulate state
+pass out on $vpnca_if proto { tcp, udp } all modulate state
+~~~
+
+Now's the fun part.
+
+* `<softvpn>` is the hosts that can you the routes pushed by the VPN but
+it doesn't use the VPN as the gw
+* `<vpnfr>` and `<vpnca>` everything from the hosts in it goes through
+the VPN (French or Canadian)
+* `<bypassfr>` any traffic to host in the table won't go through the VPN
+* `<forcevpnfr>` host that must be accessed through the VPN
+
+
+~~~
+# disable the use of the routes if you're not in <softvpn>
+pass in on { $lan_if, $wifilap_if, $wifitel_if, $atlas_if } \
+ from !<softvpnfr> to ! <nousautres> route-to ($ext_if $home_ip)
+
+# force traffic through the French VPN
+pass in on { $lan_if, $wifilap_if, $wifitel_if, $tel_if } \
+ from <vpnfr> to ! <nousautres> route-to ($vpnfr_if 192.168.125.61)
+
+# traffic to hosts in <bypass> must not go through the VPN
+pass in on { $lan_if, $wifilap_if, $wifitel_if, $tel_if } \
+ from <vpnfr> to <bypassfr> route-to ($ext_if $home_ip)
+
+# force traffic through the Canadian VPN
+pass in on { $lan_if, $wifilap_if, $wifitel_if, $tel_if } \
+ from <vpnca> to ! <nousautres> route-to ($vpnca_if 192.168.251.10)
+
+# traffic from <softvpnfr> to hosts in <forcevpnfr> should really go through the VPN
+pass in on { $lan_if, $wifilap_if, $wifitel_if } \
+ from <softvpnfr> to <forcevpnfr> route-to ($vpnfr_if 192.168.125.61)
+
+~~~
+
+But the real magic with pf, is that I can **very easily** change the
+routing for any host :
+
+~~~
+# if I want everything to go through the Canadian VPN
+root@pancake:~# pfctl -t vpnca -Ta 10.1.2.3
+# or not
+root@pancake:~# pfctl -t vpnca -Td 10.1.2.3
+# through the French VPN
+root@pancake:~# pfctl -t vpnfr -Ta 10.1.2.3
+# ok not everything, just use the route pushed by the VPN
+root@pancake:~# pfctl -t vpnfr -Td 10.1.2.3
+root@pancake:~# pfctl -t softvpn -Ta 10.1.2.3
+~~~
+
+That's all! Of course, if anything goes wrong, I have
+[Jean Canard's Advanced Paws System (APS)](https://chown.me/iota/pics/IMG_0551.JPG)
+that checks for anything.
blob - /dev/null
blob + 2ca5fc3a36fd1d1509a8a6716825c4becf1e8fe7 (mode 644)
--- /dev/null
+++ content/t2k17.md
@@ -0,0 +1,77 @@
+Title: Hackathon report - t2k17
+Date: 2017-08-21 10:20
+Category: Tech
+Summary: I slacked so much that even [portroach](https://portroach.openbsd.org/) stopped mailing the outdated ports I maintained as it noticed how pointless it was :-)
+
+I also wrote [a shorter and less personal report on undeadly](http://undeadly.org/cgi?action=article&sid=20170821231153), feel free
+to read it rather than this one if you don't want to know about other things than
+the hackathon.
+
+August was a busy month events-wise. I had the visit of coworkers who
+work in France, because [this year's Debconf](https://debconf17.debconf.org/) took place here, in Montreal.
+
+After a week of fun activities,
+[I went to debconf](https://twitter.com/Vigdis_/status/894318053093146624)
+with them.
+[With my badge](https://twitter.com/Vigdis_/status/893877976235991042),
+people noticed I liked OpenBSD and during the 'Wine and Cheese' event,
+someone came to me to talk about OpenBSD. In fact he was
+[sf@debian.org](https://qa.debian.org/developer.php?login=sf) who is also
+[sf@openbsd.org](https://v4.freshbsd.org/search?committer=sf&project=openbsd). I
+was very surprised to meet another OpenBSD developer at debconf!
+
+I finally left debconf on Tuesday evening because I had to take the
+train on Wednesday morning with mpi@ to go to Toronto. In the train I
+was slacking on the Internet when I noticed mpi@ was already hacking
+with his $EDITOR. I felt guilty so I began to update
+graphics/pqiv. Fortunately, jca@ was already in the hackroom so he was
+available to help/review. It was cool to begin with that port because
+it's a very simple port and I had to learn about the new COMPILER
+variable, thus I could easily focus just on that.
+
+I also took the opportunity of the train journey to ask mpi@ questions
+about networking stuff which leaded to more things I want to dig in.
+
+Once I arrived in the hackroom, I committed a duplicity update I had
+in my tree for a long time. I also looked at a submission on ports@
+which needed some help because of libressl vs openssl and once I
+received some ok I put it in the tree.
+
+Over the last few weeks I've been looking at porting some OpenBGPD
+check for nagios-like monitoring system to improve my [dayjob](https://evolix.ca/)'s
+monitoring system. I realized then that I didn't even check what we
+already had in the ports tree. We had a check that I quickly tested
+and it appeared to be broken. afresh1@, who is the check maintainer
+and upstream hadn't arrived yet, I asked other developers that I know
+they run BGPd in production what they use. I got to know about how
+they did their monitoring which was pretty interesting!
+
+To look at something else than the ports tree, I began to look at
+updating xkeyboard-config which is one of the tool used by xenocara. I
+already did the last update but at the time I didn't notice we had
+some local patches so I wanted to do it more carefully this time. I
+had some troubles doing this update so I took care of writing some
+notes about how I did it so next time should be easier.
+
+Finally afresh1@ arrived and I told him about the bgpd check problem
+and in fact he had fixed it two years ago but forgot to update the
+port. He quickly committed an update to close the case.
+
+One thing I wanted to do during this hackathon was updating
+haproxy. A few months ago when they release the latest branch, I
+didn't succeed to update our port to it because of libressl vs
+openssl. It wasn't such a big deal because old-stable branch was still
+supported. After waiting 9 months, I just grabbed
+[the patch Bernard Spil did for TrueOS](https://github.com/trueos/freebsd-ports/blob/3745ead2e0f43985c3647e1e3aecae2751decfda/net/haproxy/files/patch-src_ssl__sock.c)
+and it just worked so I was really happy!
+
+In addition of that, I updated the other ports I maintained and I
+finally reached a state where all the ports I maintained were up to
+date \o/
+
+To sum up, I did everything I wanted during this hackaton, with more
+ease than I thought. I had the opportunity to have really interesting
+discussions with a lot of other developers (during [our social event](https://twitter.com/Vigdis_/status/895794041450897408) but not only). Thanks a lot to the
+University of Toronto for hosting us (in a
+[very nice part of the city](https://twitter.com/Vigdis_/status/896356797988167681)
+and krw@ for organizing!
blob - /dev/null
blob + 66e9d3843a8a1960fe0874ddf3cfd795327ae234 (mode 644)
--- /dev/null
+++ content/the-checklist-manifesto.md
@@ -0,0 +1,56 @@
+Title: The Checklist Manifesto
+Date: 2018-06-01 10:20
+Category: Books
+Summary: I read The Checklist Manifesto
+
+What is the best way to improve the quality of your actions? According to the
+author of the book [*The Checklist
+Manifesto*](https://en.wikipedia.org/wiki/The_Checklist_Manifesto), it's with
+checklists.
+
+A few months ago, a [friend](https://instinctive.eu/) wrote [a blog
+article](https://instinctive.eu/weblog/0AC-perte-de-memoire-II) about how her
+memory began to fail her. [Another friend](https://blog.pasithee.fr/)
+[commented](https://instinctive.eu/weblog/0AC-perte-de-memoire-II#VXBU66HpV1Ds) that
+she wrote a checklist to avoid forgetting anything before a commit, after
+having read *The Checklist Manifesto*. Another passion of mine is airplanes.
+In the aviation world, there are checklists for everything. I was curious
+what this book could say about this subject so I read it.
+
+While reading the book was pleasant, if the author talked only about checklists,
+I think it could have been only one chapter. The other things he wrote about
+are communications and sharing—or spreading—responsibilities. These topics are also
+very important but out of the scope in my opinion.
+
+[Atul Gawande](https://en.wikipedia.org/wiki/Atul_Gawande) (the author)
+is a surgeon, so obviously he talks about surgery but not only. For instance,
+he talks about how aviation and construction firms started using checklists, who
+writes them, and what they cover.
+
+But why make checklists? The author
+explains that over the last centuries we have learned many many things, but we
+sometimes fail at doing them. Checklists are there to lower our fail rate.
+They also help to be faster and more methodical.
+
+Checklists don't improve our skills, they improve results. They are guards
+against basic errors and oversights.
+
+That sounds good, doesn't it? So how does one a do a good checklist? The author
+gives a *rule of thumb*. The checklist must:
+
+* be between 5 and 9 elements—it should take between 60 and 90 seconds to complete
+* have a clear *pause point* i.e. when to go through the checklist
+* be short and precise, they're not a how-to
+* have a publication date and be occasionally revised
+
+Atul Gawande lists two kinds of checklist:
+
+* do-confirm: you do your stuff and once you think you're good, you go
+through the checklist to verify you didn't forget anything
+* read-do: you do what the checklist says you have to do while reading it
+
+Checklists can be done during team briefing and it has the added benefit that it
+improves communication among the team.
+
+I liked this book and if you're curious about stories behind checklists, you
+should definitely read it!
blob - /dev/null
blob + 25793115f51d3b0c8a3afa905ba8454670aeafcf (mode 644)
--- /dev/null
+++ content/the-effective-manager.md
@@ -0,0 +1,100 @@
+Title: The Effective Manager
+Date: 2018-08-13 10:20
+Category: Books
+Summary: I read The Effective Manager by Mark Horstman; here's my summary.
+
+*Note: this is also available in audio format: 3:49
+[(1.6MB mp3)](https://chown.me/iota/blog/the-effective-manager.mp3)
+[(1.3MB ogg)](https://chown.me/iota/blog/the-effective-manager.ogg)*
+
+<br/>
+
+A few months ago, I stumbled across [A reading list for new engineering
+managers](https://jacobian.org/writing/engmanager-reading-list/). I'm not sure
+that I want to become a manager, but even so, knowing how management tasks
+should be approached is valuable. Knowing how things work from the other side
+helps me to understand the bigger picture, so I try to do that with most things
+in life.
+
+I began by reading the first book on the list, *The Effective Manager* by Mark
+Horstman. Here's what I found interesting:
+
+Firstly, employees should be able to list their goals. If they can't, they
+should ask "what results do you expect from me?" and "how will you measure my
+performance?"
+
+For the manager, the two main goals are:
+
+1. Achieve Results
+2. Retain Employees
+
+To help the manager succeed in these goals, the book first gives some general
+advice:
+
+1. Get to know your people
+2. Communicate about performance
+3. Ask for more
+4. Push work down
+
+Their respective importance is set to 40%, 30%, 20% and 10%. (Isn't it great
+when you add percentages and their sum is, indeed, 100%?)
+
+When goals are clearly defined and the manager communicates about their
+employee's performance, both are off to a good start!
+
+"Generally, the more a team trusts its manager, the better the results will be,
+and the better the retention as well."
+
+The author advises managers to talk to their subordinates frequently about things
+that are important to them. For those frequent discussions, his recommended
+format is the *One-on-One*. One-on-ones are scheduled, weekly, 30-minute
+meetings that managers have with each of their employees.
+
+One-on-ones last thirty minutes at the most, but can end early if neither has
+more to say. The thirty minutes are split into three ten-minute segments. The
+first third is for what the subordinate wishes to discuss. The second third allows
+the manager to provide feedback and instruction. The final third (hopefully
+there's still some time left :-)) is designated for discussion about the future
+... as it's not particularly useful to talk about the past.
+
+The book has some tips for addressing the reasons why some might be reluctant
+to attend one-on-ones. If they say their schedule is already fully booked, the
+key is to say "ok, but look at your schedule. If in one month it's mostly free,
+let's add a few weekly 30-minute slots then, to see how it goes."
+
+Another problem that could arise is the employee being unwilling to talk or
+dominating the conversation. Again, the book has some tips for that and in both
+cases, it comes down to **gently** encouraging the behavior you want to see
+**without forcing** the employee (at least, in the beginning).
+
+For giving feedback, Horstman provides the following model:
+
+1. Ask if the person is open to receiving feedback. It's useless to give
+ feedback if one's not open to it. Also, hashtag consent.
+2. Identify the behavior you've noticed.
+3. Describe the impact of the behavior (positive or negative).
+4. Encourage effective future behavior. If the feedback is positive, say "keep
+ up the good work!" and if it isn't, ask questions and work out a plan.
+
+One important thing about feedback is that you shouldn't be angry when you
+deliver it. Bearing that in mind, you should still give it as soon as you can.
+
+I didn't take any notes for the points "Ask for more" and "Push work down"
+because I didn't feel I was learning anything. Of course, this is specific to
+me. I'm sure plenty of people will find valuable advice in these sections.
+
+I quite liked the book; it was full of interesting points. What I didn't like
+was that sometimes the author repeated points that felt obvious to me. Also, I
+felt like the author was a bit full of himself (though that may simply reflect
+cultural differences).
+
+Reading *The Effective Manager* will provide you with a lot of techniques as a
+manager to complete your daily tasks. Even as someone without subordinates, I
+found this a valuable read, as it allows for some management in reverse.
+
+Finally, remember the saying: "people don't quit their jobs; they quit their
+managers." ;)
+
+<br/>
+
+*Thanks [Pamela](https://bsd.network/@pamela) for the proof-reading and the audio recording!*
blob - /dev/null
blob + 3892ae8d9296ecf5a0cf3e7c351045bb4862e6bd (mode 644)
--- /dev/null
+++ content/upgrading-openbsd-with-ansible.md
@@ -0,0 +1,206 @@
+Title: Upgrading OpenBSD with Ansible
+Date: 2018-10-19 08:30
+Category: Tech
+Summary: How to upgrade an OpenBSD machine with Ansible
+
+This article is best enjoyed with basic knowledge of [OpenBSD
+autoinstall](https://man.openbsd.org/autoinstall) and [Ansible](https://www.ansible.com/)
+
+## My router runs OpenBSD -current
+
+A few months ago, I needed software that had just hit the ports tree. I didn't
+want to wait for the next release, so I upgraded my router to use -current.
+Since then, I've continued running -current, which means upgrading to a newer
+snapshot every so often. Running -current is great, but the process of updating
+to a newer snapshot was cumbersome. Initially, I had to plug in a serial cable
+and then reboot into *bsd.rd*, hit enter ten times, then reboot, run `sysmerge`
+and update packages.
+
+I eventually switched to [upobsd](https://bitbucket.org/semarie/upobsd) to be
+able to upgrade without the need for a serial connection. The process was
+better, but still tiresome. Usually, I would prepare the special version of
+*bsd.rd*, boot on *bsd.rd*, and do something like wash the dishes in the
+meantime. After about ten minutes, I would dry my hands and then go back to my
+workstation to see whether the *bsd.rd* part had finished so I could run
+`sysmerge` and `pkg_add`, and then return to the dishes while it upgraded
+packages.
+
+Out of laziness, I thought: "I should automate this," but what happened instead
+is that I simply didn't upgrade that machine very often. (Yes, laziness). With
+my router out of commission, life is very dull, because it is my gateway to the
+Internet. Even services hosted at my place (like my Mastodon instance) are not
+reachable when the router is down because I use multiple VLANs (so I need the
+router to *jump* across VLANs).
+
+## Ansible Reboot Module
+
+I recently got a new job, and one of my first tasks was auditing the *Ansible*
+roles written by my predecessors. In one role, the machine rebooted and they
+used the
+[*wait_for_connection*](https://docs.ansible.com/ansible/2.5/modules/wait_for_module.html)
+module to wait for it to come back up. That sounded quite hackish to me, so out
+of curiosity, I tried to determine whether there was a better way. I also
+thought I might be able to use something similar to further automate my OpenBSD
+upgrades, and wanted to assess the cleanliness of this method. ;-)
+
+I learned that with the then-upcoming 2.7 Ansible release, a proper *reboot*
+module would be included. I went to the docs, which stated that for a certain
+parameter:
+
+~~~
+- On Linux and macOS, this is converted to minutes and
+ rounded down. If less than 60, it will be set to 0.
+- On Solaris and FreeBSD, this will be seconds.
+~~~
+
+I took this to mean that there was no support for OpenBSD. I looked at the code
+and, indeed, there was not. However, I believed that it wouldn't be too hard
+to add it. I added the missing pieces for OpenBSD, tested it on my poor Pine64
+and then submitted it upstream. After a quick back and forth, the module's
+author [merged it into
+devel](https://github.com/ansible/ansible/commit/2769a4e2cc3aadbf91e7f4f83ef57b7ebe43442a)
+(having a friend working at Red Hat helped the process, merci Cyril !) A couple
+days later, the release engineer [merged it into
+stable-2.7](https://github.com/ansible/ansible/commit/26de4f97493adeb388c1c8fad7a266bb7652bac6).
+
+I proceeded to actually write the playbook, and then I hit a bug. The parameter
+*reboot_timeout* was not recognized by Ansible. This feature would definitely
+be useful on a slow machine (such as the Pine64 and its dying SD card). Again,
+my fix was [merged into
+master](https://github.com/ansible/ansible/commit/0105b4aeadb94dd12b921ed6c427b21cd31182fa)
+by the module's author and then [merged into
+stable-2.7](https://github.com/ansible/ansible/commit/a0f38bdab5ae0e183cb960fe9e964bf1edf7c326).
+2.7.1 will be the first release to feature these fixes, but if you use OpenBSD
+-current, you already have access to them. I backported the patches when I
+[updated
+ansible](https://marc.info/?l=openbsd-ports-cvs&m=153994960724056&w=2).
+
+Fun fact about Ansible and reboots: "The win_reboot module was [...] included
+with Ansible 2.1," while for unix systems it wasn't added until 2.7. :D For
+more details, you can read the [module's author blog
+article](http://samdoran.com/ansible-reboot-plugin/).
+
+## The Playbook
+
+Initially, my playbook did the upgrade as usual (i.e., it fetched the sets in
+*bsd.rd*). During this process, of course, my machine is not performing its
+function as a router. My Internet access is not super great, so fetching the
+sets takes awhile. I got frustrated while I was testing it and looked into
+lessening the amount of time spent inside *bsd.rd*.
+
+To speed up the process, I wrote [a basic shell
+script](https://chown.me/iota/blog/fetch-sets) to fetch the sets **before**
+rebooting into *bsd.rd*. It enabled me to remove some *tasks* I had to do in
+order to get working Internet access in *bsd.rd*. (This is specific to my
+case).
+
+### The playbook itself
+
+~~~
+---
+- name: Upgrade OpenBSD
+ hosts: apu-root
+ vars:
+ arch: amd64
+ date: "{{ lookup('pipe', 'date +%Y-%m-%d') }}"
+ disk: "sd0"
+ mirror: "fastly.cdn.openbsd.org"
+ path_sets: "/home/danj/sets"
+
+ tasks:
+ - name: fetch sets
+ command: /home/danj/bin/fetch-sets
+ when: path_sets is defined
+ - name: create answer file for upobsd
+ template:
+ src: answer.j2
+ dest: answer
+ delegate_to: localhost
+ - name: create kernel with upobsd
+ command: "upobsd -v -a {{ arch }} -u ./answer -m https://{{ mirror }}/pub/OpenBSD -V snapshots"
+ delegate_to: localhost
+ - name: copy bsd.rd created by upobsd
+ copy:
+ src: bsd.rd
+ dest: /bsd
+ - name: reboot host
+ reboot:
+ msg: "rebooting into bsd.rd to upgrade"
+ reboot_timeout: 900
+ - name: archive kernel
+ copy:
+ src: "/bsd"
+ dest: "/bsd-{{ date }}"
+ mode: 0700
+ remote_src: "yes"
+ - name: upgrade all packages
+ command: "pkg_add -u -Dsnap"
+~~~
+
+### The answer file
+
+The answer file is automatically [mailed to root at the end of the
+upgrade](https://github.com/openbsd/src/blob/master/distrib/miniroot/install.sub#L2811-L2812),
+so it's easy to get it!
+
+In my case, the answer file transformed into a jinja2 template is:
+
+~~~
+Which disk is the root disk = sd0
+Force checking of clean non-root filesystems = no
+{% if path_sets is defined %}
+Location of sets = disk
+Is the disk partition already mounted = yes
+Pathname to the sets = {{ path_sets }}
+{% else %}
+Location of sets = http
+HTTP proxy URL = none
+HTTP Server = {{ mirror }}
+Server directory = pub/OpenBSD/snapshots/{{ arch }}
+{% endif %}
+Set name(s) = done
+Location of sets = done
+~~~
+
+### The explanations
+
+Ansible runs my script on the remote host to fetch the sets. It creates an
+answer file from the template and then gives it to *upobsd*. Once *upobsd* has
+created the kernel, Ansible copies it in place of `/bsd` on the host. The
+router reboots and boots on `/bsd`, which is upobsd's *bsd.rd*. The *installer*
+runs in *auto_update* mode. Once it comes back from *bsd.rd* land, it archives
+the kernel and finishes by upgrading all the packages.
+
+It also supports upgrading without fetching the sets ahead of time. For
+instance, I upgrade this way on my Pine64 because if I cared about speed, I
+wouldn't use this weak computer with its dying SD card. For this case, I just
+comment out the *path_sets* variable and Ansible instead creates an answer file
+that will instruct the installer to fetch the sets from the designated mirror.
+
+I've been archiving my kernels for a few years. It's a nice way to <strike>fill
+up /</strike> keep a history of my upgrades. If I spot a regression, I can
+try a previous kernel ... which may not work with the then-desynchronized
+*userland*, but that's another story.
+
+`sysmerge` already runs with
+[rc.sysmerge](https://github.com/openbsd/src/blob/master/etc/rc#L579-L580) in
+batch mode and sends the result by email. I don't think there's merit to
+running it again in the playbook. The only perk would be discovering **in the
+terminal** whether any files need to be manually merged, rather than reading
+exactly the same output in the email.
+
+Initially, I used the *openbsd_pkg* module, but it doesn't work on -current
+just **before** a release because `pkg_add` automatically looks for
+*pub/OpenBSD/${release}/packages/${arch}* (which is empty). I wrote and tested
+this playbook while 6.4 was around the corner, so I switched to *command* to be
+able to pass the `-Dsnap` parameter.
+
+## The result
+
+I'm very happy with the playbook! It performs the upgrade with as little
+intervention as possible and minimal downtime. \o/
+
+<br/>
+
+*Thanks [Pamela](https://bsd.network/@pamela) for the proof-reading!*
+
Frédéric Galusik