{"title":"stosb","link":[{"@attributes":{"href":"https:\/\/stosb.com\/","rel":"alternate"}},{"@attributes":{"href":"https:\/\/stosb.com\/feeds\/all.atom.xml","rel":"self"}}],"id":"https:\/\/stosb.com\/","updated":"2018-02-07T12:00:00+00:00","entry":[{"title":"Recovering Data From A Corrupt tar Archive","link":{"@attributes":{"href":"https:\/\/stosb.com\/blog\/recovering-data-from-a-corrupt-tar-archive\/","rel":"alternate"}},"published":"2018-02-07T12:00:00+00:00","updated":"2018-02-07T12:00:00+00:00","author":{"name":"Tom Hacohen"},"id":"tag:stosb.com,2018-02-07:\/blog\/recovering-data-from-a-corrupt-tar-archive\/","summary":"<p>A few days ago, <a href=\"https:\/\/github.com\/orgzly\/orgzly-android\/issues\/291\">a bug<\/a> in the task list app I use on my phone, <a href=\"http:\/\/www.orgzly.com\/\">Orgzly<\/a>, wiped all of my tasks. This was terribly annoying, but I wasn't too concerned because I knew I had backups. Well, at least I thought I had.<\/p>\n<p>I intend to write a post \u2026<\/p>","content":"<p>A few days ago, <a href=\"https:\/\/github.com\/orgzly\/orgzly-android\/issues\/291\">a bug<\/a> in the task list app I use on my phone, <a href=\"http:\/\/www.orgzly.com\/\">Orgzly<\/a>, wiped all of my tasks. This was terribly annoying, but I wasn't too concerned because I knew I had backups. Well, at least I thought I had.<\/p>\n<p>I intend to write a post about my phone's backup setup in the future, but in short, it's something like this: I turn on \"backup to file\" in apps that support it, use <a href=\"https:\/\/syncthing.net\/\">syncthing<\/a> to copy the files to my home server, and then use <a href=\"http:\/\/duplicity.nongnu.org\/\">duplicity<\/a> to securely back everything up to a remote location. I have yet to find a simpler, secure, and privacy respecting backup solution for Android. If you have any suggestions, please let me know.<\/p>\n<p>After realising my task app wiped everything, I quickly checked the local file backup on my phone. Unfortunately, this had already synced and also got wiped.<\/p>\n<p>My syncthing is configured to only sync when charging, so I tried checking my home server, though unfortunately I was too late, and it was already synced and thus was empty as well.<\/p>\n<p>At least, I thought to myself, I have my duplicity backups, I can just restore the backup from there. I opened duplicity only to find out that it was not configured to backup the syncthing directory, meaning I had no backups there too!\nI occasionally verify my backups actually work (can restore from them), though I haven't noticed that this important directory was not included in the backup.<\/p>\n<p>At this point I was starting to get worried, thinking I'd lose all of my (many!) tasks, though then I realised that I upgraded my phone's firmware a few days before, and had a full <a href=\"https:\/\/forum.xda-developers.com\/wiki\/NANDroid\">NANDroid backup<\/a>. However, the files I was looking for were not showing up, and <code>tar<\/code> was reporting an error. This is where our story begins.<\/p>\n<h2>The Issue<\/h2>\n<p>As I said above, the files I was looking for weren't showing up (though some other files were), and <code>tar<\/code> was reporting the following error:<\/p>\n<p><samp>\ntar: Malformed extended header: missing equal sign\n<\/samp><\/p>\n<p>I tried searching the internet for this error message, but found no solutions, only what seems to be <a href=\"https:\/\/forum.xda-developers.com\/galaxy-s8\/samsung-galaxy-s8--s8-cross-device-development\/recovery-twrp-galaxy-s8-exynos-t3595102\/page32\">the same issue<\/a> reported by another user. After reading a bit more, it looks like <a href=\"https:\/\/twrp.me\/\">TWRP<\/a> (the Android recovery I made the backup with), had a bug with creating backups in some cases. In my case it wasn't even affecting all of the files, just some, though the ones I cared about were among those.<\/p>\n<p>I then tried searching the web for <q>corrupted tar recovery<\/q> and such similar terms. I found some suggestions and ideas on how to solve it, but nothing worked. I tried opening it with <code>gnu tar<\/code>, <code>bsdtar<\/code>, <code>busybox<\/code> and <code>cpio<\/code> to no avail. At this point I got a bit desperate and decided it's time to check if there's even data there. To do that, I used grep on my 2GB backup file (<samp>data.tar<\/samp>).<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span>grep \/data\/data\/com.orgzly data.tar\n<span class=\"go\">Binary file data.tar matches<\/span>\n<\/code><\/pre><\/div>\n\n<p>I was excited to see that the files seem to be there, and to verify they actually contained my data, I opened the file with <code>less<\/code>, searched the above string and looked around. My data was there!<\/p>\n<h2>The Solution<\/h2>\n<p>I remembered that the tar archive format was quite simple, so I was initially planning on writing a small python program that would parse the tar archive and will help me extract my file. However, I then realised that it's actually not necessary, and I can just achieve everything I want from the shell.<\/p>\n<p>Let's start by finding my data in the file. As you remember, earlier I used <code>less<\/code> to check if my data was there. When I searched there I noticed my file (<samp>\/data\/data\/com.orgzly\/backups\/orgzly.db<\/samp>) was the second match, and that the next match was just after what seemed to be the end of my file. Based on these assumptions, I ran grep to find the offsets, and got the following:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span>grep --byte-offset --only-matching --text \/data\/data\/com.orgzly\/databases\/orgzly.db data.tar\n<span class=\"go\">2095003651:\/data\/data\/com.orgzly\/databases\/orgzly.db<\/span>\n<span class=\"go\">2095004675:\/data\/data\/com.orgzly\/databases\/orgzly.db<\/span>\n<span class=\"go\">2095349251:\/data\/data\/com.orgzly\/databases\/orgzly.db<\/span>\n<span class=\"go\">2095350275:\/data\/data\/com.orgzly\/databases\/orgzly.db<\/span>\n<span class=\"go\">... snip ...<\/span>\n<\/code><\/pre><\/div>\n\n<p>Based on this, I concluded that the relevant tar entry starts at <samp>2095004675<\/samp> and ends at <samp>2095349251<\/samp>. I then used <code>dd<\/code> to extract this chunk to make the file easier to work with.<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span>dd <span class=\"nv\">skip<\/span><span class=\"o\">=<\/span><span class=\"m\">2095004675<\/span> <span class=\"nv\">count<\/span><span class=\"o\">=<\/span><span class=\"m\">344576<\/span> <span class=\"nv\">bs<\/span><span class=\"o\">=<\/span><span class=\"m\">1<\/span> <span class=\"k\">if<\/span><span class=\"o\">=<\/span>data.tar <span class=\"nv\">of<\/span><span class=\"o\">=<\/span>orgzly.db\n<span class=\"go\">344576+0 records in<\/span>\n<span class=\"go\">344576+0 records out<\/span>\n<span class=\"go\">344576 bytes (345 kB, 336 KiB) copied, 0.393915 s, 875 kB\/s<\/span>\n<\/code><\/pre><\/div>\n\n<p>I now needed to remove the tar headers. One way of doing it is to search for the tar header format, parse it, extract the file's length, and use that. However, I had a better idea: I figured out I could just find the beginning of the file using its <a href=\"https:\/\/en.wikipedia.org\/wiki\/File_format#Magic_number\">magic number<\/a>.<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span>grep --byte-offset --only-matching --text SQLite orgzly.db\n<span class=\"go\">509:SQLite<\/span>\n<\/code><\/pre><\/div>\n\n<p>I then trimmed the file accordingly, and tried opening it with sqlite:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span>dd <span class=\"nv\">skip<\/span><span class=\"o\">=<\/span><span class=\"m\">509<\/span> <span class=\"nv\">bs<\/span><span class=\"o\">=<\/span><span class=\"m\">1<\/span> <span class=\"k\">if<\/span><span class=\"o\">=<\/span>orgzly.db <span class=\"nv\">of<\/span><span class=\"o\">=<\/span>orgzly.fixed.db\n<span class=\"go\">344067+0 records in<\/span>\n<span class=\"go\">344067+0 records out<\/span>\n<span class=\"go\">344067 bytes (344 kB, 336 KiB) copied, 0.397661 s, 865 kB\/s<\/span>\n\n<span class=\"gp\">$ <\/span>sqlite3 orgzly.fixed.db\n<span class=\"go\">SQLite version 3.22.0 2018-01-22 18:45:57<\/span>\n<span class=\"go\">Enter &quot;.help&quot; for usage hints.<\/span>\n<span class=\"go\">sqlite&gt; .tables<\/span>\n<span class=\"go\">android_metadata         note_properties          repos<\/span>\n<span class=\"go\">book_links               notes                    rook_urls<\/span>\n<span class=\"go\">book_syncs               notes_view               rooks<\/span>\n<span class=\"go\">books                    org_ranges               searches<\/span>\n<span class=\"go\">books_view               org_timestamps           times_view<\/span>\n<span class=\"go\">current_versioned_rooks  properties               versioned_rooks<\/span>\n<span class=\"go\">db_repos                 property_names<\/span>\n<span class=\"go\">note_ancestors           property_values<\/span>\n<\/code><\/pre><\/div>\n\n<p>And it worked!<\/p>\n<p>Now that I managed to recover the database, I copied it to my phone, fixed the permissions and SELinux attributes and started orgzly. Everything worked, and my tasks were saved!<\/p>","category":[{"@attributes":{"term":"misc"}},{"@attributes":{"term":"backup"}},{"@attributes":{"term":"linux"}}]},{"title":"Signed Web Pages","link":{"@attributes":{"href":"https:\/\/stosb.com\/blog\/signed-web-pages\/","rel":"alternate"}},"published":"2017-12-28T14:00:00+00:00","updated":"2017-12-28T14:00:00+00:00","author":{"name":"Tom Hacohen"},"id":"tag:stosb.com,2017-12-28:\/blog\/signed-web-pages\/","summary":"<p>As some of you already know, I've recently released the <a href=\"https:\/\/client.etesync.com\">EteSync Web App<\/a>. It's a fully blown EteSync client that lets you access all of your data while maintaining the End-to-End encryption assurances you've come to expect from EteSync.<\/p>\n<p>There is one caveat though. The above describes the code in \u2026<\/p>","content":"<p>As some of you already know, I've recently released the <a href=\"https:\/\/client.etesync.com\">EteSync Web App<\/a>. It's a fully blown EteSync client that lets you access all of your data while maintaining the End-to-End encryption assurances you've come to expect from EteSync.<\/p>\n<p>There is one caveat though. The above describes the code in the EteSync repos, not necessarily the code on the server or the code being served by the server.<\/p>\n<p>One way to solve it, is to clone the EteSync Web App's repo, verify it locally using the signed tags, and then run a local version. This will give you the same assurances as a native app. The other, more convenient solution, is using the new web extension I just released: <a href=\"https:\/\/github.com\/tasn\/webext-signed-pages\">Signed Pages<\/a>.<\/p>\n<h2>The Problem<\/h2>\n<p>Unlike with native applications, where you can install a version you can verify (or even build yourself), with web apps, you are served the app every time you enter the website.\nThis means, that the server could all of a sudden serve malicious code to everyone, a small group of users or a specific targeted user. Even worse, a state-sponsored attacker could issue a certificate for a certain domain, man-in-the-middle the connection to the server and serve malicious code to the user. This is slightly mitigated by <a href=\"https:\/\/en.wikipedia.org\/wiki\/Certificate_Transparency\">certificate transparency<\/a>, but the issue still remains.<\/p>\n<h2>The Solution<\/h2>\n<p>One solution to this problem is signing web pages using PGP and using trusted code (a browser extension) to verify it.<\/p>\n<p>As a user, all you need to do is install <a href=\"https:\/\/github.com\/tasn\/webext-signed-pages\">Signed Pages<\/a> and add the websites you want. At the moment, you need to manually add the pattern and the expected public key of the signer as provided by the developer, though I plan on making it more user friendly in the future.<\/p>\n<h2>How it Works<\/h2>\n<p>Developers sign their pages using a detached PGP signature, and put the signature as the first comment in the page after the doctype. That's it.\nThere's even a script that does that for you, which you can get from <a href=\"https:\/\/github.com\/tasn\/webext-signed-pages\/blob\/master\/page-signer.js\">here<\/a>.<\/p>\n<p>Users with the browser extension configured will then see a shield in their address bar (or tool bar, based on browser) based on the validity of the signature. If a signature is valid, a green shield with a black tick will be shown, and if it's invalid or missing (but expected for a page) a red shield with a big black <em>X<\/em> will be shown.<\/p>\n<p><img alt=\"Valid Signature\" class=\"img-thumbnail\" src=\"https:\/\/stosb.com\/blog\/signed-web-pages\/images\/signed-pages\/screenshot-good.png\"><\/p>\n<p>We however only solved part of the problem. We now verify that the page we are accessing is indeed what we expect, but what about its external scripts and CSS? Luckily, this is already a solved problem. All you need to do is enable <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/Security\/Subresource_Integrity\">subresource integrity<\/a> for all of external resources in the page (event if served from the same server!), and the browser will verify them automatically.<\/p>\n<p>For example, to include jquery:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"nt\">&lt;script<\/span> <span class=\"na\">src=<\/span><span class=\"s\">&quot;\/assets\/jquery-2.1.4.min.js&quot;<\/span>\n    <span class=\"na\">integrity=<\/span><span class=\"s\">&quot;sha384-R4\/ztc4ZlRqWjqIuvf6RX5yb\/v90qNGx6fS48N0tRxiGkqveZETq72KgDVJCp2TC&quot;<\/span>\n    <span class=\"na\">crossorigin=<\/span><span class=\"s\">&quot;anonymous&quot;<\/span><span class=\"nt\">&gt;<\/span>\n<span class=\"nt\">&lt;\/script&gt;<\/span>\n<\/code><\/pre><\/div>\n\n<p>You can also include jquery from a CDN and you'll have the same integrity assurances.<\/p>\n<h2>More Information<\/h2>\n<p>For more information please refer to the <a href=\"https:\/\/github.com\/tasn\/webext-signed-pages\">README<\/a> and the source code, or let me know if you have any questions.<\/p>","category":[{"@attributes":{"term":"misc"}},{"@attributes":{"term":"pgp"}},{"@attributes":{"term":"encryption"}},{"@attributes":{"term":"web"}},{"@attributes":{"term":"security"}}]},{"title":"Advanced Git Commands You Will Actually Use","link":{"@attributes":{"href":"https:\/\/stosb.com\/blog\/advanced-git-commands-you-will-actually-use\/","rel":"alternate"}},"published":"2017-12-25T13:00:00+00:00","updated":"2017-12-25T13:00:00+00:00","author":{"name":"Tom Hacohen"},"id":"tag:stosb.com,2017-12-25:\/blog\/advanced-git-commands-you-will-actually-use\/","summary":"<p>This is the blog version of the <a href=\"https:\/\/stosb.com\/talks\/\">talk I gave<\/a> at Samsung's UK office. People have been asking for a blog version, so here it is. While it covers mostly the same topic as the talk, it's not exactly the same. If you are only going to look at one \u2026<\/p>","content":"<p>This is the blog version of the <a href=\"https:\/\/stosb.com\/talks\/\">talk I gave<\/a> at Samsung's UK office. People have been asking for a blog version, so here it is. While it covers mostly the same topic as the talk, it's not exactly the same. If you are only going to look at one of them, it's better to read this post.<\/p>\n<p>I'm intentionally brief throughout this post. The goal of this post is to expose you to new commands you may have not known. However, it should only serve as a starting point, and it's up to you to further explore those you found useful.<\/p>\n<p>This post assumes some basic working knowledge of git, though still covers some basics.\nIf you feel like you're already familiar with git, you can skip <a href=\"#past-introduction\">past the introduction<\/a><\/p>\n<h2>Quick Setup Before We Begin<\/h2>\n<p>In case you don't already have these set, you should set your name and email. I set\nthe globally to all repos, but if you omit the <code>--global--<\/code> directive, you can set them locally per repo.<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span>git config --global user.name <span class=\"s2\">&quot;Tom Hacohen&quot;<\/span>\n<span class=\"gp\">$ <\/span>git config --global user.email <span class=\"s2\">&quot;tom.git@stosb.com&quot;<\/span>\n<\/code><\/pre><\/div>\n\n<p>You should also enable colours, set your default editor (what git will use for\nediting commit messages, for example) and an external tool that can be used to view diffs\nwhen running <code>git difftool<\/code><\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span>git config --global color.ui <span class=\"nb\">true<\/span> <span class=\"c1\"># Default since git 1.8.4<\/span>\n<span class=\"gp\">$ <\/span><span class=\"nb\">export<\/span> <span class=\"nv\">EDITOR<\/span><span class=\"o\">=<\/span><span class=\"s2\">&quot;vim&quot;<\/span> <span class=\"c1\"># Optional<\/span>\n<span class=\"gp\">$ <\/span>git config --global diff.tool <span class=\"s2\">&quot;vimdiff&quot;<\/span> <span class=\"c1\"># Extra optional<\/span>\n<\/code><\/pre><\/div>\n\n<p>You should also enable git command autocompletion (system dependant).<\/p>\n<p>At this point it's also worth mentioning that git has built-in support for aliases.\nSome of the commands presented here will be rather long, so it may be useful to alias some of the more commonly used ones.<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span>git config --global alias.unstage <span class=\"s1\">&#39;reset HEAD --&#39;<\/span> <span class=\"c1\"># Set it up<\/span>\n<span class=\"gp\">$ <\/span>git unstage <span class=\"c1\"># Use it<\/span>\n<\/code><\/pre><\/div>\n\n<h2>A Few Useful Properties of Git<\/h2>\n<h3>Branches and Tags are References<\/h3>\n<p><img alt=\"Commit graph\" src=\"https:\/\/stosb.com\/blog\/advanced-git-commands-you-will-actually-use\/images\/advanced-git\/branch_history.png\"><\/p>\n<p>Branches and tags are just references to commits, and master is just a normal branch, so a reference too.\nThis means you can make branches and tags point to any commit in your history, or use them like you would any commit hash.<\/p>\n<h3>Nearly Every Operation is Local<\/h3>\n<p>Because of git's decentralised nature, all the operations other than the ones that sync with a remote (either push or pull\/fetch) are local. This means that:<\/p>\n<ul>\n<li>Operations are usually very fast<\/li>\n<li>You can wore offline, while for example on a plane<\/li>\n<li>You can be sloppy and clean up after yourself before pushing your changes.<\/li>\n<\/ul>\n<h3>A Few More Useful Properties&hellip;<\/h3>\n<ul>\n<li>Has a staging area, so you can add only some of your changes and commit when ready.<\/li>\n<li>You can rewrite history by rearranging and amending commits.<\/li>\n<li>History is immutable, so all of your commits are recoverable, even if you rewrote history (unless you ran garbage collection).<\/li>\n<li>Everything is referenced by its cryptographic hash, so you can be certain your commit history or files have not bee corrupted or <a href=\"https:\/\/lwn.net\/Articles\/57135\/\">maliciously modified<\/a>.<\/li>\n<\/ul>\n<p><a id=\"past-introduction\"><\/a><\/p>\n<h2>Referencing Commits<\/h2>\n<p>As mentioned above, branches, tags and commit hashes can be used interchangeably. There is also a special pointer called <samp>HEAD<\/samp> that always points to the current commit\/state we are on.<\/p>\n<p>In addition, git supports a few modifiers that make referencing your commits very easy.<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span>git show 7c1c793fe8769980823bfbfcf80396486c6163d7 <span class=\"c1\"># Full commit hash<\/span>\n<span class=\"gp\">$ <\/span>git show 7c1c793fe87 <span class=\"c1\"># Shorter hash<\/span>\n<span class=\"gp\">$ <\/span>git show 7c1c793 <span class=\"c1\"># Even shorter hash (can be any length as long as not ambiguous)<\/span>\n\n<span class=\"gp\">$ <\/span>git show HEAD <span class=\"c1\"># Current head<\/span>\n<span class=\"gp\">$ <\/span>git show master <span class=\"c1\"># The commit master points to<\/span>\n<span class=\"gp\">$ <\/span>git show some_tag <span class=\"c1\"># The commit some_tag points to<\/span>\n\n<span class=\"gp\">#<\/span><span class=\"c1\"># Reminder: all reference types can be used interchangeably<\/span>\n<span class=\"gp\">$ <\/span>git show HEAD^ <span class=\"c1\"># HEAD&#39;s parent<\/span>\n<span class=\"gp\">$ <\/span>git show master^^ <span class=\"c1\"># master&#39;s grandparent<\/span>\n<span class=\"gp\">$ <\/span>git show some_tag~3 <span class=\"c1\"># some_tags&#39;s great-grandparent<\/span>\n<span class=\"gp\">$ <\/span>git show 7c1c793~4 <span class=\"c1\"># This commit&#39;s great-great-grandparent<\/span>\n\n<span class=\"gp\">$ <\/span>git show master@<span class=\"o\">{<\/span>yesterday<span class=\"o\">}<\/span> <span class=\"c1\"># The commit master pointed to yesterday<\/span>\n<\/code><\/pre><\/div>\n\n<h2>Reading the Log<\/h2>\n<h3>Cleaner Tree Log Overview<\/h3>\n<pre class=\"ansi2html highlight no-link-decorations\">\n$ git log --oneline --graph\n* <span class=\"ansi33\">7b3fa8a<\/span> Migrate elementary to the new Eo4 syntax\n<span class=\"ansi32\">|<\/span><span class=\"ansi33\">\\<\/span>\n<span class=\"ansi32\">|<\/span> * <span class=\"ansi33\">02e87e8<\/span> Fix warnings following migration to Eo4.\n<span class=\"ansi32\">|<\/span> * <span class=\"ansi33\">7bd1d48<\/span> Map: Correct broken migration.\n<span class=\"ansi32\">|<\/span> * <span class=\"ansi33\">e74ec8c<\/span> Automatic migration to Eo4.\n<span class=\"ansi32\">|<\/span> * <span class=\"ansi33\">9274efb<\/span> Remove redundant defines.\n<span class=\"ansi32\">|<\/span><span class=\"ansi32\">\/<\/span>\n* <span class=\"ansi33\">36669f1<\/span> Scaling test: reorder instructions to set the correct scale\n* <span class=\"ansi33\">b9c912f<\/span> radio: inherit from elm check\n<\/pre>\n\n<h3>Listing a Change Summary<\/h3>\n<pre class=\"ansi2html highlight no-link-decorations\">\n<span class=\"gp\">$<\/span> git log --stat\n<span class=\"ansi33\">commit a31f399857ecf9409e6aa6fb8effe9477ee47fe2<\/span>\nAuthor: Tom Hacohen &lt;tom@stosb.com&gt;\nDate:   Wed Jun 22 16:52:05 2016 +0100\n\n    Edje object: Add API for replacing the internal text object\n\n src\/lib\/edje\/edje_load.c    | 34 <span class=\"ansi32\">++++++<\/span><span class=\"ansi31\">--------------------<\/span>\n src\/lib\/edje\/edje_object.eo | 17 <span class=\"ansi32\">++++++++++++++<\/span>\n src\/lib\/edje\/edje_private.h |  1 <span class=\"ansi32\">+<\/span>\n src\/lib\/edje\/edje_util.c    | 32 <span class=\"ansi32\">+++++++++++++++++++++++++++<\/span>\n 4 files changed, 60 insertions(+), 24 deletions(-)\n<\/pre>\n\n<h3>Seeing Actual Code Changes<\/h3>\n<pre class=\"ansi2html highlight no-link-decorations\">\n<span class=\"gp\">$<\/span> git log -p\n<span class=\"ansi33\">commit c66d478ebb2c1a0aff52571467d7a6b87a533382<\/span>\nAuthor: Ji-Youn Park &lt;jy0703.park@samsung.com&gt;\nDate:   Thu Mar 24 17:54:05 2016 +0830\n\n    Elm_image: remove Elm_Image_Orient.\n\n<span class=\"ansi1\">diff --git a\/src\/lib\/elm_image.c b\/src\/lib\/elm_image.c<\/span>\n********** Snip Snip *********\n }\n\n EOLIAN static void\n<span class=\"ansi31\">-_elm_image_orient_set(Eo *obj, Elm_Image_Data *sd, Elm_Image_Orient orient)<\/span>\n<span class=\"ansi32\">+<\/span><span class=\"ansi32\">_elm_image_efl_image_orientation_set(Eo *obj, Elm_Image_Data *sd, Efl_Gfx_Orientation orient)<\/span>\n {\n    if (sd-&gt;edje) return;\n<\/pre>\n\n<h3>Limiting Commits<\/h3>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">#<\/span><span class=\"c1\"># Commits changing file\/function in file<\/span>\n<span class=\"gp\">$ <\/span>git log main.c\n<span class=\"gp\">$ <\/span>git log -L :list_find:main.c\n\n<span class=\"gp\">#<\/span><span class=\"c1\"># Commits containing string<\/span>\n<span class=\"gp\">$ <\/span>git log --grep FOOBAR <span class=\"c1\"># Messages containing string<\/span>\n<span class=\"gp\">$ <\/span>git log -S FOOBAR <span class=\"c1\"># Lines containing string<\/span>\n\n<span class=\"gp\">#<\/span><span class=\"c1\"># Commits in HEAD, not in master<\/span>\n<span class=\"gp\">$ <\/span>git log master..\n\n<span class=\"gp\">#<\/span><span class=\"c1\"># Commits that are in either &quot;foo&quot; or &quot;bar&quot; (not both)<\/span>\n<span class=\"gp\">$ <\/span>git log foo...bar\n\n<span class=\"gp\">#<\/span><span class=\"c1\"># Only show the first parent (don&#39;t show commits in merged branches)<\/span>\n<span class=\"gp\">$ <\/span>git log --first-parent\n<\/code><\/pre><\/div>\n\n<h3>Finding Out What You Have Been Up To<\/h3>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">#<\/span><span class=\"c1\"># The total number of commits by an author<\/span>\n<span class=\"gp\">$ <\/span>git shortlog -nse --author<span class=\"o\">=<\/span>tom.git@stosb.com\n\n<span class=\"gp\">#<\/span><span class=\"c1\"># The total number of commits by an author in the last year<\/span>\n<span class=\"gp\">$ <\/span>git shortlog -nse --author<span class=\"o\">=<\/span>tom --since<span class=\"o\">=<\/span><span class=\"s2\">&quot;1 year ago&quot;<\/span>\n\n<span class=\"gp\">#<\/span><span class=\"c1\"># A list of commits by an author in the last year<\/span>\n<span class=\"gp\">$ <\/span>git log --author<span class=\"o\">=<\/span>tom --since<span class=\"o\">=<\/span><span class=\"s2\">&quot;1 year ago&quot;<\/span>\n<\/code><\/pre><\/div>\n\n<h3>Getting a Version Description<\/h3>\n<p>While git's hashes are useful for pointing to specific commits, they are not very convenient as version identifiers as it's not possible to know which commit is newer just by looking at it.<\/p>\n<p>There are two ways to go around this. The first is using <code>git decsribe<\/code>, a built in git command that prints out a usable description for a commit. For example, the commit below was 236 commits after the tag v1.17.0 and its short hash was <samp>gc66d478<\/samp>. Or alternatively, it was 12514 commits since the origin of the repo.<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">#<\/span><span class=\"c1\"># Get a standard version description (requires at least one tag)<\/span>\n<span class=\"gp\">$ <\/span>git describe --long\n<span class=\"go\">v1.17.0-236-gc66d478<\/span>\n\n<span class=\"gp\">#<\/span><span class=\"c1\"># Get the SVN-like monotonic revision number<\/span>\n<span class=\"gp\">$ <\/span>git rev-list --count HEAD\n<span class=\"go\">12514<\/span>\n<\/code><\/pre><\/div>\n\n<h2>Inspecting Commits and State<\/h2>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">#<\/span><span class=\"c1\"># Showing the changes in a commit<\/span>\n<span class=\"gp\">$ <\/span>git show 80f14e8fea0057ee950f0778dd51b096ca9850a4\n<span class=\"gp\">$ <\/span>git show my_branch <span class=\"c1\"># Can be branch, tag or whatever.<\/span>\n\n<span class=\"gp\">#<\/span><span class=\"c1\"># Showing a file from a different state<\/span>\n<span class=\"gp\">$ <\/span>git show v1.7.0:main.c\n\n<span class=\"gp\">#<\/span><span class=\"c1\"># Switching working directory to a different reference<\/span>\n<span class=\"gp\">$ <\/span>git checkout c9b306777 <span class=\"c1\"># Or any other reference<\/span>\n<\/code><\/pre><\/div>\n\n<h2>Branches<\/h2>\n<h3>Viewing<\/h3>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">#<\/span><span class=\"c1\"># All the branches (including remote)<\/span>\n<span class=\"gp\">$ <\/span>git branch -a\n<span class=\"gp\">#<\/span><span class=\"c1\"># Use &quot;git fetch -p&quot; to clean up stale remote branches<\/span>\n\n<span class=\"gp\">#<\/span><span class=\"c1\"># All branches that are fully contained in HEAD<\/span>\n<span class=\"gp\">$ <\/span>git branch -a --merged\n\n<span class=\"gp\">#<\/span><span class=\"c1\"># All branches that are not full contained in HEAD<\/span>\n<span class=\"gp\">$ <\/span>git branch -a --no-merged\n<\/code><\/pre><\/div>\n\n<h3>Manipulating<\/h3>\n<p>I think it's very important to maintain a <a href=\"http:\/\/www.bitsnbites.eu\/a-tidy-linear-git-history\/\">linear history<\/a>. Most of the commands here help you maintain that.<\/p>\n<p>Rebase reorders your current branch over another, and <code>git merge --no-ff<\/code> makes sure that merges always create a merge commit, even if not necessary (which it never is when you have linear history). This helps you group changes together like you would with any other merge.<\/p>\n<p>Last, but not least is the <code>--preserve<\/code> flag which makes sure the aforementioned redundant merge commits are not discarded when rebasing.<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">#<\/span><span class=\"c1\"># Rebase branch over the upstream version<\/span>\n<span class=\"gp\">$ <\/span>git pull --rebase <span class=\"c1\"># Can be set in config<\/span>\n\n<span class=\"gp\">#<\/span><span class=\"c1\"># Rebase branch over a specific branch<\/span>\n<span class=\"gp\">$ <\/span>git rebase origin\/master\n\n<span class=\"gp\">#<\/span><span class=\"c1\"># Merge a branch and always create a merge commit<\/span>\n<span class=\"gp\">$ <\/span>git merge --no-ff\n\n<span class=\"gp\">#<\/span><span class=\"c1\"># Rebase and keep the branch structure<\/span>\n<span class=\"gp\">$ <\/span>git pull --rebase<span class=\"o\">=<\/span>preserve\n<span class=\"gp\">$ <\/span>git rebase --preserve-merges origin\/master\n\n<span class=\"gp\">#<\/span><span class=\"c1\"># Applying a commit from a different branch<\/span>\n<span class=\"gp\">$ <\/span>git cherry-pick 80f122437d\n<\/code><\/pre><\/div>\n\n<h2>Making Changes<\/h2>\n<h3>Inspecting Workspace State<\/h3>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">#<\/span><span class=\"c1\"># A more condensed status<\/span>\n<span class=\"gp\">$ <\/span>git status -s\n\n<span class=\"gp\">#<\/span><span class=\"c1\"># Changes compare to upsteram<\/span>\n<span class=\"gp\">$ <\/span>git diff origin\/master\n\n<span class=\"gp\">#<\/span><span class=\"c1\"># Seeing the diff of the staging area<\/span>\n<span class=\"gp\">$ <\/span>git diff --cached\n\n<span class=\"gp\">#<\/span><span class=\"c1\"># Ignore whitespace changes in diff<\/span>\n<span class=\"gp\">$ <\/span>git diff -w\n<\/code><\/pre><\/div>\n\n<h3>Adding Files to the Staging Area<\/h3>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">#<\/span><span class=\"c1\"># Adding parts of a file<\/span>\n<span class=\"gp\">$ <\/span>git add -p file <span class=\"c1\"># File can also be a dir, or ommitted<\/span>\n\n<span class=\"gp\">#<\/span><span class=\"c1\"># Adding all of the changed files in a directory<\/span>\n<span class=\"gp\">#<\/span><span class=\"c1\"># Very useful when resolving conflicts<\/span>\n<span class=\"gp\">$ <\/span>git add -u src\/\n<\/code><\/pre><\/div>\n\n<h3>Using the Stash<\/h3>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">#<\/span><span class=\"c1\"># Stashing all of the changes<\/span>\n<span class=\"gp\">$ <\/span>git stash\n\n<span class=\"gp\">#<\/span><span class=\"c1\"># Stashing some of the changes<\/span>\n<span class=\"gp\">$ <\/span>git stash -p\n\n<span class=\"gp\">#<\/span><span class=\"c1\"># Applying back the stash<\/span>\n<span class=\"gp\">$ <\/span>git stash apply\n\n<span class=\"gp\">#<\/span><span class=\"c1\"># Stash has many more features I do not use<\/span>\n<span class=\"gp\">$ <\/span>git stash --help\n<\/code><\/pre><\/div>\n\n<h2>Rewriting History<\/h2>\n<p>It is a very bad idea to rewrite published history. That is, history that has been shared with the world (by for example, <code>git push<\/code>) to a shared branch. It's OK to change the history of a temporary feature branch, and is for example how you update a PR on GitHub and GitLab.<\/p>\n<p>This section is therefore here to help you rewriting your local history <strong>before<\/strong> you publish, so the published commit history is clean and easy to follow.<\/p>\n<h3>Un-staging Files<\/h3>\n<pre class=\"ansi2html highlight no-link-decorations\">\n<span class=\"gp\">$<\/span> git status -s\n<span class=\"ansi32\">M<\/span>  README\n\n<span class=\"gp\">$<\/span> git reset README\n<span class=\"c1\"># git reset # for all the files<\/span>\n<span class=\"gp\">$<\/span> git status -s\n<span class=\"ansi31\">M<\/span> README\n\n<span class=\"gp\">$<\/span> git checkout README\n<span class=\"c1\"># Use \"git checkout -f\" for all of the files<\/span>\n<span class=\"gp\">$<\/span> git status -s\n<span class=\"c1\"># Nothing<\/span>\n<\/pre>\n\n<h3>Editing the Most Recent Commits<\/h3>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">#<\/span><span class=\"c1\"># Remove the most recent commits and their changes<\/span>\n<span class=\"gp\">$ <\/span>git reset --hard HEAD^\n<span class=\"gp\">$ <\/span>git reset --hard HEAD~3 <span class=\"c1\"># Or any other pointer (for a range)<\/span>\n<span class=\"gp\">$ <\/span>git reset --hard origin\/master <span class=\"c1\"># Reset the state to upsteam<\/span>\n\n<span class=\"gp\">#<\/span><span class=\"c1\"># Keep the changes uncommitted<\/span>\n<span class=\"gp\">$ <\/span>git reset HEAD^\n<span class=\"gp\">$ <\/span>git reset c9b306777 <span class=\"c1\"># Or any other pointer<\/span>\n\n<span class=\"gp\">#<\/span><span class=\"c1\"># Unstage changes<\/span>\n<span class=\"gp\">$ <\/span>get reset\n\n<span class=\"gp\">#<\/span><span class=\"c1\"># Merging index into the most recent commit<\/span>\n<span class=\"gp\">$ <\/span>git add NEWS\n<span class=\"gp\">$ <\/span>git commit --amend <span class=\"c1\"># Also lets you edit the commit message<\/span>\n<span class=\"gp\">#<\/span><span class=\"c1\"># Add -v to git commit to also see the diff<\/span>\n\n<span class=\"gp\">#<\/span><span class=\"c1\"># Edit the author<\/span>\n<span class=\"gp\">$ <\/span>git commit --author <span class=\"s2\">&quot;007 &lt;jb@mi6.gov.uk&gt;&quot;<\/span> --amend\n<\/code><\/pre><\/div>\n\n<h3>The Most Useful Command in The World<\/h3>\n<p>This is hands down the most useful command. I use it a lot! This command lets you edit all of the commits in a certain range, and I use it to rearrange and clean up my commits.<\/p>\n<pre class=\"ansi2html highlight no-link-decorations\">\n<span class=\"c1\"># Will open in your default editor set in EDITOR<\/span>\n$ git rebase -i HEAD~5\n<span class=\"ansi38-3\">pick<\/span> <span class=\"ansi38-6\">7b07b03<\/span> track\/manage size hints for zoomap child objects\n<span class=\"ansi38-3\">pick<\/span> <span class=\"ansi38-6\">71a85b7<\/span> update winlist ui when using directional selection\n<span class=\"ansi38-3\">pick<\/span> <span class=\"ansi38-6\">bbd4d2f<\/span> force changed when adding keyboards\n<span class=\"ansi38-3\">pick<\/span> <span class=\"ansi38-6\">a424542<\/span> disable emotion_shutdown during shutdown procedure\n<span class=\"c1\">\n# Commands:\n# p, pick = use commit\n# r, reword = use commit, but edit the commit message\n# e, edit = use commit, but stop for amending\n# s, squash = use commit, but meld into previous commit\n# f, fixup = like \"squash\", but discard this commit's log message\n# x, exec = run command (the rest of the line) using shell\n# d, drop = remove commit\n#\n# These lines can be re-ordered; executed from top to bottom.\n# If you remove a line here THAT COMMIT WILL BE LOST.\n<\/span><\/pre>\n\n<h3>Recovering Lost Commits<\/h3>\n<p>The problem with changing history is that history can be lost.\nIt's very common to want to revert to a previous state or recover an accidentally lost or modified commit.<\/p>\n<p>Since git's history is immutable, commits are never lost (unless <a href=\"https:\/\/git-scm.com\/docs\/git-gc\">garbage collected<\/a> and can still be referenced by their hash, or if the hash is unknown, can be found using the method below.<\/p>\n<pre class=\"ansi2html highlight no-link-decorations\">\n<span class=\"c1\"># Jump to a hash state if you know it<\/span>\n<span class=\"gp\">$<\/span> git checkout c9b306777\n\n<span class=\"c1\"># Find unreferenced (missing) commits<\/span>\n<span class=\"gp\">$<\/span> git reflog\n<span class=\"ansi33\">cebf78d<\/span> HEAD@{0}: rebase -i (finish): returning to refs\/heads\/master\n<span class=\"ansi33\">cebf78d<\/span> HEAD@{1}: rebase -i (start): checkout HEAD^^^^\n<span class=\"ansi33\">c6e355f<\/span> HEAD@{2}: rebase finished: returning to refs\/heads\/master\n<span class=\"ansi33\">c6e355f<\/span> HEAD@{3}: pull --rebase: Elementary test entry: Create an editable test object.\n<span class=\"ansi33\">83b0592<\/span> HEAD@{4}: commit: Elementary test entry: Create an editable test object.\n<span class=\"ansi33\">2fd8861<\/span> HEAD@{5}: commit (amend): Ui text: Add an editable variant (tiny wrapper).\n<\/pre>\n\n<p>Afterwards you can just cherry-pick, reset, checkout or whatever method to recover those commits.<\/p>\n<h3>Removing Parts of a Commit<\/h3>\n<p>It's also very common to accidentally commit a file or a line that you didn't intend to. Especially when using <code>git commit -a<\/code>. This too can be easily fixed.<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">#<\/span><span class=\"c1\"># Commit c42bc3a535 (can be anywhere in history)<\/span>\n<span class=\"gp\">$ <\/span>git revert -n c42bc3a535\n<span class=\"gp\">$ <\/span>git reset <span class=\"c1\"># Remove everything from staging<\/span>\n\n<span class=\"gp\">#<\/span><span class=\"c1\"># Add back the wanted changes<\/span>\n<span class=\"gp\">$ <\/span>git add NEWS <span class=\"c1\"># All of this file<\/span>\n<span class=\"gp\">$ <\/span>git add -p <span class=\"c1\"># Some parts of the rest<\/span>\n\n<span class=\"gp\">#<\/span><span class=\"c1\"># Merge the commit into the original commit<\/span>\n<span class=\"gp\">#<\/span><span class=\"c1\"># Either amend if it is the HEAD<\/span>\n<span class=\"gp\">$ <\/span>git commit --amend\n<span class=\"gp\">$ <\/span>git checkout -f <span class=\"c1\"># Remove the rest of the changes<\/span>\n<span class=\"gp\">#<\/span><span class=\"c1\"># Or fixup if anywhere else<\/span>\n<span class=\"gp\">$ <\/span>git commit -m <span class=\"s2\">&quot;Temp&quot;<\/span>\n<span class=\"gp\">$ <\/span>git checkout -f <span class=\"c1\"># Remove the rest of the changes<\/span>\n<span class=\"gp\">$ <\/span>git rebase -i c42bc3a535^ <span class=\"c1\"># Mind the ^ (caret)<\/span>\n<\/code><\/pre><\/div>\n\n<h2>Delivering Changes<\/h2>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">#<\/span><span class=\"c1\"># Change the url of the repository<\/span>\n<span class=\"gp\">$ <\/span>git remote set-url origin ssh:\/\/git@newserver.com\/repo.git\n\n<span class=\"gp\">#<\/span><span class=\"c1\"># Adding a new remote<\/span>\n<span class=\"gp\">$ <\/span>git remote add new ssh:\/\/git@alt.newserver.com\/repo.git\n\n<span class=\"gp\">#<\/span><span class=\"c1\"># Using the new remote<\/span>\n<span class=\"gp\">$ <\/span>git fetch new\n<span class=\"gp\">$ <\/span>git rebase new\/master\n<span class=\"gp\">$ <\/span>git push new master\n\n<span class=\"gp\">#<\/span><span class=\"c1\"># Generate patch files for a series of commits<\/span>\n<span class=\"gp\">$ <\/span>git format-patch HEAD~5 <span class=\"c1\"># Or any other reference<\/span>\n<\/code><\/pre><\/div>\n\n<h2>Investigating Bugs<\/h2>\n<h3>Finding Who Added a Line and Why<\/h3>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">#<\/span><span class=\"c1\"># Check who changed the file<\/span>\n<span class=\"gp\">$ <\/span>git blame eo.c <span class=\"c1\"># Add &quot;-w&quot; to ignore white-space<\/span>\n\n<span class=\"go\">06f65ab2 eo.c (Tom Hacohen       2016-05-19 11:33:17 +0100<\/span>\n<span class=\"go\">    321)         vtable = &amp;amp;klass-&amp;gt;vtable;<\/span>\n<span class=\"go\">fc880379 eo.c (Tom Hacohen       2015-11-09 11:45:04 +0000<\/span>\n<span class=\"go\">    322)    inputklass = main_klass = klass;<\/span>\n<span class=\"go\">7be0748b eo.c (J\u00e9r\u00e9my Zurcher    2013-07-30 15:02:35 +0200<\/span>\n<span class=\"go\">    323) <\/span>\n<span class=\"go\">c2b4137f eo.c (Carsten Haitzler  2015-10-24 12:23:53 +0900<\/span>\n<span class=\"go\">    324)    if (!cache-&amp;gt;op)<\/span>\n\n<span class=\"gp\">#<\/span><span class=\"c1\"># At an earlier revision<\/span>\n<span class=\"gp\">$ <\/span>git blame fc880379^ -- eo.c\n<\/code><\/pre><\/div>\n\n<h3>Finding When a Bug Was Introduced<\/h3>\n<p>This command helps you run a binary search on the commit history efficiently finding a bad commit.<\/p>\n<p>All you need to do is run bisect, evaluate a commit to see if it was broken or not, and then report the result to git. You can even skip commits by passing <code>skip<\/code> instead of <code>good<\/code> or <code>bad<\/code>.<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span>git bisect start\n<span class=\"gp\">#<\/span><span class=\"c1\"># To limit bisect to a directory: &quot;git bisect start -- src\/&quot;<\/span>\n<span class=\"gp\">#<\/span><span class=\"c1\"># Set the initial known good and bad commits<\/span>\n<span class=\"gp\">$ <\/span>git bisect bad COMMIT\n<span class=\"gp\">$ <\/span>git bisect good COMMIT\n<span class=\"go\">Bisecting: 417 revisions left to test after this (roughly 9 steps)<\/span>\n<span class=\"go\">[7352bcff98fc65a08edcd505b872403af8d821a7] edje_external: fix external icon handling<\/span>\n\n<span class=\"gp\">$ <\/span>git bisect good  <span class=\"c1\"># Or bad if bad<\/span>\n<span class=\"go\">Bisecting: 208 revisions left to test after this (roughly 8 steps)<\/span>\n<span class=\"go\">[9f5d27972252d67fe92ca44a1c610da4ed531b86] Evas events: Implement support for hold event<\/span>\n\n<span class=\"gp\">#<\/span><span class=\"c1\"># ... SNIP ...<\/span>\n\n<span class=\"go\">a31f399857ecf9409e6aa6fb8effe9477ee47fe2 is the first bad commit<\/span>\n<\/code><\/pre><\/div>\n\n<h3>Automatic Bisect<\/h3>\n<p>While <code>git bisect<\/code> saves you a lot of time and effort, it still involves manually testing commits and reporting the results back to git. You can alternatively write a script that will automatically evaluate commits for you.<\/p>\n<p>For example consider this script:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"ch\">#!\/bin\/sh<\/span>\nmake <span class=\"o\">||<\/span> <span class=\"nb\">exit<\/span> <span class=\"m\">125<\/span>                     <span class=\"c1\"># this skips broken builds<\/span>\n~\/check_issue.sh                     <span class=\"c1\"># does the test case pass?<\/span>\n<\/code><\/pre><\/div>\n\n<p>It compiles the code, and runs <code>~\/check_issue.sh<\/code>, our small test program that returns 0 on success, and anything else on failure. Then all you need to do is run:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span>git bisect start HEAD HEAD~10 --   <span class=\"c1\"># Last 10 commits, short-hand form for start<\/span>\n<span class=\"gp\">$ <\/span>git bisect run ~\/test.sh\n<span class=\"gp\">$ <\/span>git bisect reset                   <span class=\"c1\"># quit the bisect session<\/span>\n\n<span class=\"go\">a31f399857ecf9409e6aa6fb8effe9477ee47fe2 is the first bad commit<\/span>\n<\/code><\/pre><\/div>\n\n<h2>Releasing Versions<\/h2>\n<p>We have now finally fixed all the bugs, merged all the feature branches, cleaned up the change history, and pushed our changes to our remote repository. There is only one thing left, tagging the release.<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">#<\/span><span class=\"c1\"># Bare tag, just hold a reference to a commit: not recommended.<\/span>\n<span class=\"gp\">$ <\/span>git tag v1.0.0 <span class=\"c1\"># You can also pass an optional commit reference<\/span>\n\n<span class=\"gp\">#<\/span><span class=\"c1\"># Annotated tag, also add a message to the commit, for example, a changelog: recommended<\/span>\n<span class=\"gp\">$ <\/span>git tag -a v1.0.0 <span class=\"c1\"># Again, you can also pass an optional commit reference<\/span>\n\n<span class=\"gp\">#<\/span><span class=\"c1\"># Cryptographically igned tags: assuring your users this tag really came from you: recommended<\/span>\n<span class=\"gp\">$ <\/span>git tag -s v1.0.0 <span class=\"c1\"># Again, you can also pass an optional commit reference<\/span>\n<\/code><\/pre><\/div>\n\n<h2>A Few More Commands Worth Checking Out<\/h2>\n<ul>\n<li><code>git submodule<\/code><\/li>\n<li><code>git send-email<\/code><\/li>\n<li><code>git checkout -b<\/code><\/li>\n<li>Use git with other VCS: <code>git-svn<\/code>, <code>git-hg<\/code> and more<\/li>\n<li>CLI viewer: <code>tig<\/code><\/li>\n<li>GUI viewers: <code>gitg<\/code> and <code>gitk<\/code><\/li>\n<\/ul>\n<h2>Finishing Notes<\/h2>\n<p>Git is a powerful tool, and this post only scratches the tip of the iceberg. I highly recommend you take the time to read the wonderful <a href=\"https:\/\/git-scm.com\/book\/en\/v2\">git book<\/a>. It's not a very long read, and is well worth it.<\/p>","category":[{"@attributes":{"term":"misc"}},{"@attributes":{"term":"git"}},{"@attributes":{"term":"programming"}}]},{"title":"Introducing EteSync: Secure Journaled Sync","link":{"@attributes":{"href":"https:\/\/stosb.com\/blog\/introducing-etesync\/","rel":"alternate"}},"published":"2017-04-05T13:00:00+01:00","updated":"2017-04-05T13:00:00+01:00","author":{"name":"Tom Hacohen"},"id":"tag:stosb.com,2017-04-05:\/blog\/introducing-etesync\/","summary":"<p>It's been a long time since I last posted here, almost three months. Though don't worry, I haven't been slacking off, I've been busy\nworking on my new project:<\/p>\n<p><a href=\"https:\/\/www.etesync.com\"><img alt=\"EteSync Logo\" src=\"https:\/\/stosb.com\/blog\/introducing-etesync\/images\/brand.svg\"><\/a><\/p>\n<p>So what is EteSync? As it says on the website, it's a solution for secure, end-to-end encrypted and journaled personal information \u2026<\/p>","content":"<p>It's been a long time since I last posted here, almost three months. Though don't worry, I haven't been slacking off, I've been busy\nworking on my new project:<\/p>\n<p><a href=\"https:\/\/www.etesync.com\"><img alt=\"EteSync Logo\" src=\"https:\/\/stosb.com\/blog\/introducing-etesync\/images\/brand.svg\"><\/a><\/p>\n<p>So what is EteSync? As it says on the website, it's a solution for secure, end-to-end encrypted and journaled personal information synchronization. It currently supports contacts and calendars on Android, and there's already a <a href=\"https:\/\/github.com\/etesync\/pyetesync\">Python API<\/a>, which is being used to add EteSync support to <a href=\"https:\/\/github.com\/pimutils\/vdirsyncer\">vdirsyncer<\/a>. This means it will soon be available on the desktop too. I also plan on implementing tasks (to-do list), bookmarks and other personal information sync solutions, making more of our data private and journaled.<\/p>\n<p>This means <a href=\"https:\/\/www.etesync.com\/faq\/#can-anyone-access\">only you are able to access your data<\/a>, your data is safe, and you can access to your data's full change history. You accidentally deleted a calendar event with important information a month ago? No problem, you can just look the event up in your change history and restore it. You have a contact and you don't know who it may be, get some context from checking the date it was created.<\/p>\n<p>If you would like to see some screenshots, please take a look at the <a href=\"https:\/\/www.etesync.com\/user-guide\/\">user guide<\/a>, though EteSync runs in the background and seamlessly integrates with the Android system, so you won't be seeing its UI very often, you would just be using the same contacts and calendar apps you've been using all along.<\/p>\n<p>Client, server and API bindings are all open source, with the source code available <a href=\"https:\/\/github.com\/etesync\">here<\/a>. I wouldn't trust closed source solutions when it comes to security, privacy and personal information, and I don't expect you to either.<\/p>\n<p>For more information, please take a look at <a href=\"https:\/\/www.etesync.com\">the website<\/a>, <a href=\"https:\/\/www.etesync.com\/faq\/\">FAQ<\/a>, or just <a href=\"https:\/\/stosb.com\/about\/\">contact me directly<\/a>.<\/p>","category":[{"@attributes":{"term":"misc"}},{"@attributes":{"term":"security"}},{"@attributes":{"term":"encryption"}},{"@attributes":{"term":"etesync"}}]},{"title":"Explaining My Configs: OpenVPN","link":{"@attributes":{"href":"https:\/\/stosb.com\/blog\/explaining-my-configs-openvpn\/","rel":"alternate"}},"published":"2017-01-10T14:00:00+00:00","updated":"2017-01-10T14:00:00+00:00","author":{"name":"Tom Hacohen"},"id":"tag:stosb.com,2017-01-10:\/blog\/explaining-my-configs-openvpn\/","summary":"<p>This post is part of my <a href=\"https:\/\/stosb.com\/tag\/explaining-configs\/\"><em>Explaining My Configs<\/em> series<\/a> where I explain the configuration files (and options) I use in detail.<\/p>\n<p>This post could either be read as a whole, or as a reference (click on a line to jump to its explanation).<\/p>\n<p>Usually I prefer explaining the client \u2026<\/p>","content":"<p>This post is part of my <a href=\"https:\/\/stosb.com\/tag\/explaining-configs\/\"><em>Explaining My Configs<\/em> series<\/a> where I explain the configuration files (and options) I use in detail.<\/p>\n<p>This post could either be read as a whole, or as a reference (click on a line to jump to its explanation).<\/p>\n<p>Usually I prefer explaining the client and the server configurations in separate posts, however, with OpenVPN, there is significant overlap between the two, and they need to match in order for it to work. Therefore, this post will explain both.<\/p>\n<p>I have my configuration files in the system's OpenVpn directory (<code>\/etc\/openvpn\/server<\/code> for me), and for\neach configuration file, I have a directory with its keys, so for example, this\nis the layout for the server's config:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code>server.conf\nserver\/dh.pem\nserver\/ipp\nserver\/ta.key\nserver\/key.key\nserver\/cert.crt\nserver\/ca.crt\n<\/code><\/pre><\/div>\n\n<h1>What is this config for?<\/h1>\n<p>I use my VPN to have remote access into my network, and sometimes also to route all traffic through it, in order to escape some forms of connection filtering. While my base configuration is hardened (strong encryption and secure settings), my route-all-traffic configuration is not. That requires some settings that are annoying to use and setting up a firewall to block mistakes.<\/p>\n<h1>The config file<\/h1>\n<p>Click on a line to jump to its explanation.<\/p>\n<p>\/etc\/openvpn\/server.conf:<\/p>\n<pre class=\"highlight no-link-decorations\">\n<a href=\"#Server\"><span class=\"Statement\">server <\/span><span class=\"Constant\">192.168.87.0<\/span> <span class=\"Special\">255.255.255.0<\/span><\/a>\n<a href=\"#Port\"><span class=\"Statement\">port<\/span> <span class=\"Constant\">1194<\/span><\/a>\n<a href=\"#Proto\"><span class=\"Statement\">proto<\/span> <span class=\"Identifier\">udp6<\/span><\/a>\n<a href=\"#Dev\"><span class=\"Statement\">dev<\/span> <span class=\"Identifier\">tun0<\/span><\/a>\n\n<a href=\"#ClientToClient\"><span class=\"Statement\">client-to-client<\/span><\/a>\n\n<a href=\"#Cipher\"><span class=\"Statement\">cipher<\/span> AES-256-CBC\n<span class=\"Statement\">auth<\/span> SHA512\n<span class=\"Statement\">tls-cipher<\/span> TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-256-CBC-SHA256:TLS-DHE-RSA-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-128-CBC-SHA256<\/a>\n\n<a href=\"#Comp\"><span class=\"Statement\">comp-lzo<\/span> <span class=\"Identifier\">no<\/span><\/a>\n\n<a href=\"#Keepalive\"><span class=\"Statement\">keepalive<\/span> <span class=\"Constant\">15<\/span> <span class=\"Constant\">60<\/span><\/a>\n\n<a href=\"#PingTimer\"><span class=\"Statement\">ping-timer-rem<\/span><\/a>\n\n<a href=\"#Ipp\"><span class=\"Statement\">ifconfig-pool-persist<\/span> server\/ipp<\/a>\n\n<a href=\"#Verb\"><span class=\"Statement\">verb<\/span> <span class=\"Constant\">3<\/span><\/a>\n\n<a href=\"#Persist\"><span class=\"Statement\">persist-tun<\/span>\n<span class=\"Statement\">persist-key<\/span><\/a>\n\n<a href=\"#DropPrivs\"><span class=\"Comment\"># Drop privs<\/span>\n<span class=\"Statement\">user<\/span> nobody\n<span class=\"Statement\">group<\/span> nobody<\/a>\n\n<a href=\"#Keys\"><span class=\"Comment\"># Keys<\/span>\n<span class=\"Statement\">tls-auth<\/span> server\/ta.key <span class=\"Constant\">0<\/span>\n<span class=\"Statement\">cert<\/span> server\/cert.crt\n<span class=\"Statement\">key<\/span> server\/key.key\n<span class=\"Statement\">ca<\/span> server\/ca.crt\n<span class=\"Statement\">dh<\/span> server\/dh.pem<\/a>\n<\/pre>\n\n<p>\/etc\/openvpn\/client.conf:<\/p>\n<pre class=\"highlight no-link-decorations\">\n<a href=\"#Client\"><span class=\"Statement\">client<\/span><\/a>\n<a href=\"#Remote\"><span class=\"Statement\">remote<\/span> vpn.stosb.com <span class=\"Constant\">1194<\/span> <span class=\"Identifier\">udp<\/span><\/a>\n<a href=\"#Dev\"><span class=\"Statement\">dev<\/span> <span class=\"Identifier\">tun<\/span><\/a>\n\n<a href=\"#RedirectGateway\"><span class=\"Comment\"># Uncomment the next line to redirect all traffic through the VPN<\/span>\n<span class=\"Comment\"># redirect-gateway def1<\/span><\/a>\n\n<a href=\"#RemoteCert\"><span class=\"Statement\">remote-cert-tls<\/span> <span class=\"Identifier\">server<\/span><\/a>\n\n<a href=\"#Cipher\"><span class=\"Statement\">cipher<\/span> AES-256-CBC\n<span class=\"Statement\">auth<\/span> SHA512\n<span class=\"Statement\">tls-cipher<\/span> TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-256-CBC-SHA256:TLS-DHE-RSA-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-128-CBC-SHA256<\/a>\n\n<a href=\"#Comp\"><span class=\"Statement\">comp-lzo<\/span> <span class=\"Identifier\">no<\/span><\/a>\n\n<a href=\"#Verb\"><span class=\"Statement\">verb<\/span> <span class=\"Constant\">3<\/span><\/a>\n\n<a href=\"#Persist\"><span class=\"Statement\">persist-tun<\/span>\n<span class=\"Statement\">persist-key<\/span><\/a>\n\n<a href=\"#Keys\"><span class=\"Comment\"># Keys<\/span>\n<span class=\"Statement\">key-direction<\/span> <span class=\"Constant\">1<\/span>\n<span class=\"Statement\">tls-auth<\/span> client\/ta.key\n<span class=\"Statement\">cert<\/span> client\/cert.crt\n<span class=\"Statement\">key<\/span> client\/key.key<\/a>\n\n<a href=\"#KeysCa\">&lt;<span class=\"Statement\">ca<\/span>&gt;\n-----BEGIN CERTIFICATE-----\n... SNIP ...\n-----END CERTIFICATE-----\n&lt;\/<span class=\"Statement\">ca<\/span>&gt;<\/a>\n<\/pre>\n<p>&nbsp;<\/p>\n<h1>Reviewing the config<\/h1>\n<pre id=\"Server\" class=\"highlight\">\n<span class=\"Statement\">server <\/span><span class=\"Constant\">192.168.87.0<\/span> <span class=\"Special\">255.255.255.0<\/span>\n<\/pre>\n\n<p>The <code>server<\/code> puts OpenVPN in server mode, and supplies it with a subnet of IPs to\nallocate by specifying an address and a netmask. In the example above, OpenVPN\nwill take <code>192.186.87.1<\/code> for itself, and allocate the rest of the subnet for\nclients.<\/p>\n<p>Choose a subnet that's unlikely to create clashes with your other networks.<\/p>\n<pre id=\"Port\" class=\"highlight\">\n<span class=\"Statement\">port<\/span> <span class=\"Constant\">1194<\/span>\n<\/pre>\n\n<p>This directive sets which port the server should listen on. I chose the standard\nOpenVPN port.<\/p>\n<pre id=\"Proto\" class=\"highlight\">\n<span class=\"Statement\">proto<\/span> <span class=\"Identifier\">udp6<\/span>\n<\/pre>\n\n<p>This sets the transport protocol to use. UDP is more efficient and will perform\nmuch better while using less data. However, if for some reason you can't use\nUDP, you can set this to TCP instead.<\/p>\n<p>On the server I set it to <code>udp6<\/code> which tells it to listen to both IPv4 and IPv6\nconnections.<\/p>\n<p>On the client I set it to <code>udp<\/code>, because <code>udp6<\/code> will force it to only try IPv6,\nand made OpenVPN not work for me (I don't always have IPv6).<\/p>\n<pre id=\"Dev\" class=\"highlight\">\n<span class=\"Statement\">dev<\/span> <span class=\"Identifier\">tun0<\/span>\n<\/pre>\n\n<p>Sets the name of the virtual network device to use. On the server, I forced it\nto <code>tun0<\/code>, so I can more easily set firewall rules knowing it'll always be the\nsame device. On the client I let it choose the exact device on its own.<\/p>\n<p>Since the device name starts with <code>tun<\/code>, OpenVPN automatically sets the device\ntype to it. Otherwise I would have had to set <code>dev-type<\/code> explicitly.<\/p>\n<pre id=\"ClientToClient\" class=\"highlight\">\n<span class=\"Statement\">client-to-client<\/span>\n<\/pre>\n\n<p>Normally, OpenVPN would pass all packets to the tun device on the server. This\nmeans that all packets, even between clients in the VPN network will be handled\nby the server's firewall, so if you want client to client traffic, you need to\nexplicitly enable it in the firewall and add all the rules to do it.<\/p>\n<p>Alternatively, you can set this directive that automatically does all of that\nfor you. Be advised that with this enabled, the server's firewall will never\nget the packets, so don't enable it if you want fine-grained control.<\/p>\n<pre id=\"Cipher\" class=\"highlight\">\n<span class=\"Statement\">cipher<\/span> AES-256-CBC\n<span class=\"Statement\">auth<\/span> SHA512\n<span class=\"Statement\">tls-cipher<\/span> TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-256-CBC-SHA256:TLS-DHE-RSA-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-128-CBC-SHA256\n<\/pre>\n\n<p>These statements harden the server with stronger crypto. However, some of them\nare only available from OpenVpn 2.3.3. If you are having trouble, <a href=\"https:\/\/community.openvpn.net\/openvpn\/wiki\/Hardening\">choose\ndifferent values<\/a>.<\/p>\n<p>The <code>cipher<\/code> directive controls which cipher would be used for the data channel,\nthat is, all the data transferred through the VPN.<\/p>\n<p>The <code>auth<\/code> directive controls the HMAC algorithm used for the control channel.\nMore on that in the <a href=\"#Keys\">keys section<\/a>.<\/p>\n<p>The <code>tls-cipher<\/code> directive controls the cipher suite used by the VPNs control\nchannel.<\/p>\n<pre id=\"Comp\" class=\"highlight\">\n<span class=\"Statement\">comp-lzo<\/span> <span class=\"Identifier\">no<\/span>\n<\/pre>\n\n<p>Disable compression. Most, if not all, of my traffic is either encrypted (e.g.\nSSH and HTTPS) or already compressed (e.g. HTTP in most cases), so adding\ncompression on top will not add any benefits. If you think you may want\ncompression after all, set it to <code>adaptive<\/code> which automatically decides if to\nput compression on or not, though even when not compressing, this is not free.<\/p>\n<pre id=\"Keepalive\" class=\"highlight\">\n<span class=\"Statement\">keepalive<\/span> <span class=\"Constant\">15<\/span> <span class=\"Constant\">60<\/span>\n<\/pre>\n\n<p>This is a helper directive that automatically sets the <code>ping<\/code> and <code>ping-restart<\/code>\nvalues on both the client and the server (when set on the server). This is why\nwe don't have it in the client.<\/p>\n<p>With this setting, a ping will be sent every 15 seconds (if no other data has\nbeen sent). This is useful to keep stateful firewalls will not drop or UDP\nconnection after some time of inactivity.<\/p>\n<p>The second part of this directive will try to restart the connection after <samp>60<\/samp>\nseconds of inactivity (on the client) and <samp>60 * 2 = 120<\/samp> seconds\n(on the server). This ensures that the client will detect the timeout before the\nserver.<\/p>\n<p><strong>Note<\/strong>: be aware, that this setting can cause increased battery usage on mobile\ndevices due to the radio being woken up to send data all the time.<\/p>\n<pre id=\"PingTimer\" class=\"highlight\">\n<span class=\"Statement\">ping-timer-rem<\/span>\n<\/pre>\n\n<p>This only runs the <code>ping-restart<\/code> (previous) timeout timer when there is a client\nconnected to the server, so to prevent the server from timing out all the time\nwhen there isn't even a client connected.<\/p>\n<pre id=\"Ipp\" class=\"highlight\">\n<span class=\"Statement\">ifconfig-pool-persist<\/span> server\/ipp\n<\/pre>\n\n<p>This makes the IP addresses given to clients persistent, and the persistence\nfile to be saved in the location <code>server\/ipp<\/code> relative to the main config file.<\/p>\n<pre id=\"Verb\" class=\"highlight\">\n<span class=\"Statement\">verb<\/span> <span class=\"Constant\">3<\/span>\n<\/pre>\n\n<p>Increase the verbosity of OpenVPN. The default is 1, but 3 is the recommended\nvalue. Shows a bit more information in the logs.<\/p>\n<pre id=\"Persist\" class=\"highlight\">\n<span class=\"Statement\">persist-tun<\/span>\n<span class=\"Statement\">persist-key<\/span>\n<\/pre>\n\n<p>These options persist the tun device and the authentication keys across restarts\n(either caused by user or ping-restarts). This makes it possible to drop\nprivileges (see the next section) and regardless, I couldn't think of a good\nreason why not to have these.<\/p>\n<pre id=\"DropPrivs\" class=\"highlight\">\n<span class=\"Comment\"># Drop privs<\/span>\n<span class=\"Statement\">user<\/span> nobody\n<span class=\"Statement\">group<\/span> nobody\n<\/pre>\n\n<p>This drop the privileges of the daemon to the user and group <code>nobody<\/code>, so if\nthere's ever a bug in OpenVPN, at least the hacker won't get root privileges.\nYou could further harden it as explained on the <a href=\"https:\/\/openvpn.net\/index.php\/open-source\/documentation\/howto.html#security\">OpenVPN website<\/a>,\nhowever, it was too much of a hassle for not a lot of benefit.<\/p>\n<p>Because of the lower privileges, the server can no longer clean up after itself\nby for example closing the tun device, or removing routes. It's a non-issue for\na server config because OpenVPN should never be stopped, but it is for a client,\nand that's why I only have this setting on the client machine.<\/p>\n<pre id=\"Keys\" class=\"highlight\">\n<span class=\"Comment\"># Keys<\/span>\n<span class=\"Statement\">tls-auth<\/span> server\/ta.key <span class=\"Constant\">0<\/span>\n<span class=\"Statement\">cert<\/span> server\/cert.crt\n<span class=\"Statement\">key<\/span> server\/key.key\n<span class=\"Statement\">ca<\/span> server\/ca.crt\n<span class=\"Statement\">dh<\/span> server\/dh.pem\n<\/pre>\n\n<p>These tell OpenVPN to look for the keys (and dh params) in the noted locations.\nPlease note that the number at the end of <code>tls-auth<\/code> is the <code>key-direction<\/code>, and  needs to be 0 for server and 1 for client.<\/p>\n<p>You can also embed the keys\/certificates in the file itself if you prefer (demonstrated in the next section), and if you do it for the <code>tls-auth<\/code> directive too, you'd need to specify the <code>key-direction<\/code> separately using the <code>key-direction<\/code> directive.<\/p>\n<p>Please look online to see how to manage your own PKI for OpenVPN, this is beyond the scope of this post. However, one note on <code>tls-auth<\/code> as promised earlier. This is the key used for HMAC. While this is not essential, it adds another layer of security by adding an easy to verify authentication code to all the control messages. This protects against some kinds of DoS and could even protect against issues with TLS, like for example, the recently notorious <q>heartbleed<\/q>.<\/p>\n<pre id=\"KeysCa\" class=\"highlight\">\n&lt;<span class=\"Statement\">ca<\/span>&gt;\n-----BEGIN CERTIFICATE-----\n... SNIP ...\n-----END CERTIFICATE-----\n&lt;\/<span class=\"Statement\">ca<\/span>&gt;\n<\/pre>\n\n<p>I redacted my actual certificate for brevity, but this is how you embed a key or certificate in the config file. I found it very useful when providing the <a href=\"http:\/\/ics-openvpn.blinkt.de\/\">OpenVPN Android client<\/a> with a config. When I did that, I embedded all of the keys.<\/p>\n<pre id=\"Client\" class=\"highlight\">\n<span class=\"Statement\">client<\/span>\n<\/pre>\n\n<p>This is a helper indicating that this is a client. This means that the client assumes the position of \"client\" in the TLS negotiation. It also sets the <code>pull<\/code> directive, which allows the server to push some (white-listed) configurations to the client like setting the IP address and routing.<\/p>\n<pre id=\"Remote\" class=\"highlight\">\n<span class=\"Statement\">remote<\/span> vpn.stosb.com <span class=\"Constant\">1194<\/span> <span class=\"Identifier\">udp<\/span>\n<\/pre>\n\n<p>This tells OpenVPN where to connect to. In this example it's connecting to <code>vpn.stosb.com<\/code> and port <code>1194<\/code> using UDP, which is what we have set on the server.<\/p>\n<p>You can put multiple remote directives for redundancy. For example, you could have OpenVPN running on a list of ports you expect to be white-listed in networks, like udp:53 (DNS) or tcp:993 (POP3) and then have OpenVPN automatically try them. Alternatively you can use it for real redundancy, so if one\nserver fails, the others are automatically tried.<\/p>\n<pre id=\"RedirectGateway\" class=\"highlight\">\n<span class=\"Comment\"># Uncomment the next line to redirect all traffic through the VPN<\/span>\n<span class=\"Comment\"># redirect-gateway def1<\/span>\n<\/pre>\n\n<p>This directive redirects all of the client's traffic through the VPN by adding the needed routing rules. This is the bare minimum that's needed, but you could also append other flags to this command, for example <code>block-local<\/code> to block traffic to the local (non-VPN) LAN in order to make sure no traffic leaks. This is another level of hardening, but as I said before, it's better handled by proper firewall rules.<\/p>\n<p>One thing to remember when using <code>block-local<\/code>, is that in many cases your DNS server would be in the local network and with <code>block-local<\/code> it will no longer be reachable. To solve it you should either set an alternative DNS in the client, by using for example <code>dhcp-option DNS 8.8.8.8<\/code>, or pushing it from the server.<\/p>\n<pre id=\"RemoteCert\" class=\"highlight\">\n<span class=\"Statement\">remote-cert-tls<\/span> <span class=\"Identifier\">server<\/span>\n<\/pre>\n\n<p>This forces the certificate of the other end to be a server certificate. Before explaining what it does, I need to explain a bit about PKI and OpenVPN. When a client connects to the server using TLS, it checks to see if the certificate of the server is signed by the certificate authority and not revoked, and if everything is OK, it allows the connection. This sounds good, but because of how OpenVPN works client certificates are also signed by the certificate authority, so a client could potentially impersonate the server, which is unacceptable.<\/p>\n<p>One way to solve it, is to use the <code>tls-verify<\/code> directive. This directive lets you run a command to verify the server is who it says it is by checking the public key (public key pinning), CN and whatever else you may feel like. However, t's annoying to set-up because you need to create and deploy and extra script.<\/p>\n<p>Another way to solve it, which is less secure but much simple, and can be used in addition to the first method is to mark server certificates as such and verify it in the client. When creating the server certificate you just need to mark it as a server certificate, and then in the client add the <code>remote-cert-tls server<\/code> directive to enforce that. I find this solution sufficient, and it's what I use.<\/p>","category":[{"@attributes":{"term":"misc"}},{"@attributes":{"term":"explaining configs"}},{"@attributes":{"term":"security"}},{"@attributes":{"term":"OpenVPN"}}]},{"title":"Explaining My Configs: ssh client","link":{"@attributes":{"href":"https:\/\/stosb.com\/blog\/explaining-my-configs-ssh-client\/","rel":"alternate"}},"published":"2016-12-20T15:00:00+00:00","updated":"2016-12-20T15:00:00+00:00","author":{"name":"Tom Hacohen"},"id":"tag:stosb.com,2016-12-20:\/blog\/explaining-my-configs-ssh-client\/","summary":"<p>This post is part of my <a href=\"https:\/\/stosb.com\/tag\/explaining-configs\/\"><em>Explaining My Configs<\/em> series<\/a> where I explain the configuration files (and options) I use in detail. This post is the client version of my previous <a href=\"https:\/\/stosb.com\/blog\/explaining-my-configs-sshd_config\/\">sshd_config post<\/a>.<\/p>\n<p>This post could either be read as a whole, or as a reference (click on a \u2026<\/p>","content":"<p>This post is part of my <a href=\"https:\/\/stosb.com\/tag\/explaining-configs\/\"><em>Explaining My Configs<\/em> series<\/a> where I explain the configuration files (and options) I use in detail. This post is the client version of my previous <a href=\"https:\/\/stosb.com\/blog\/explaining-my-configs-sshd_config\/\">sshd_config post<\/a>.<\/p>\n<p>This post could either be read as a whole, or as a reference (click on a line to jump to its explanation).<\/p>\n<h1>What is this config for?<\/h1>\n<p>The goal of these configuration changes is to harden the security and ease the usage of the ssh client.<\/p>\n<h1>The config file<\/h1>\n<p>Click on a line to jump to its explanation.<\/p>\n<pre class=\"highlight no-link-decorations\">\n<a href=\"#HostKeyAlgorithms\"><span class=\"Statement\">HostKeyAlgorithms<\/span> <span class=\"Identifier\">ssh-ed25519-cert-v01@openssh.com<\/span>,<span class=\"Identifier\">ssh-rsa-cert-v01@openssh.com<\/span>,<span class=\"Identifier\">ssh-ed25519<\/span>,<span class=\"Identifier\">ssh-rsa<\/span>,<span class=\"Identifier\">ecdsa-sha2-nistp521-cert-v01@openssh.com<\/span>,<span class=\"Identifier\">ecdsa-sha2-nistp384-cert-v01@openssh.com<\/span>,<span class=\"Identifier\">ecdsa-sha2-nistp256-cert-v01@openssh.com<\/span>,<span class=\"Identifier\">ecdsa-sha2-nistp521<\/span>,<span class=\"Identifier\">ecdsa-sha2-nistp384<\/span>,<span class=\"Identifier\">ecdsa-sha2-nistp256<\/span><\/a>\n\n<a href=\"#KexAlgorithms\"><span class=\"Statement\">KexAlgorithms<\/span> <span class=\"Identifier\">curve25519-sha256@libssh.org<\/span>,<span class=\"Identifier\">ecdh-sha2-nistp521<\/span>,<span class=\"Identifier\">ecdh-sha2-nistp384<\/span>,<span class=\"Identifier\">ecdh-sha2-nistp256<\/span>,<span class=\"Identifier\">diffie-hellman-group-exchange-sha256<\/span>\n<span class=\"Statement\">MACs<\/span> <span class=\"Identifier\">hmac-sha2-512-etm@openssh.com<\/span>,<span class=\"Identifier\">hmac-sha2-256-etm@openssh.com<\/span>,<span class=\"Identifier\">umac-128-etm@openssh.com<\/span>,hmac-sha<span class=\"Constant\">2<\/span>-<span class=\"Constant\">512<\/span>,hmac-sha<span class=\"Constant\">2<\/span>-<span class=\"Constant\">256<\/span>,<span class=\"Identifier\">umac-128@openssh.com<\/span>\n<span class=\"Statement\">Ciphers<\/span> <span class=\"Identifier\">chacha20-poly1305@openssh.com<\/span>,<span class=\"Identifier\">aes256-gcm@openssh.com<\/span>,<span class=\"Identifier\">aes128-gcm@openssh.com<\/span>,<span class=\"Identifier\">aes256-ctr<\/span>,<span class=\"Identifier\">aes192-ctr<\/span>,<span class=\"Identifier\">aes128-ctr<\/span><\/a>\n\n<span class=\"Comment\"># E servers<\/span>\n<a href=\"#HostE\"><span class=\"Type\">Host<\/span> <span class=\"Constant\">*.enlightenment.org !e?.enlightenment.org !e?v*.enlightenment.org !git.enlightenment.org !devs.enlightenment.org<\/span><\/a>\n<a href=\"#ProxyCommand\">  <span class=\"Statement\">ProxyCommand<\/span> ssh -q <span class=\"Constant\">tasn@e5v1.enlightenment.org<\/span> -W <span class=\"Identifier\">%h<\/span>:<span class=\"Identifier\">%p<\/span><\/a>\n<\/pre>\n<p>&nbsp;<\/p>\n<h1>Reviewing the config<\/h1>\n<pre id=\"HostKeyAlgorithms\" class=\"highlight\">\n<span class=\"Statement\">HostKeyAlgorithms<\/span> <span class=\"Identifier\">ssh-ed25519-cert-v01@openssh.com<\/span>,<span class=\"Identifier\">ssh-rsa-cert-v01@openssh.com<\/span>,<span class=\"Identifier\">ssh-ed25519<\/span>,<span class=\"Identifier\">ssh-rsa<\/span>,<span class=\"Identifier\">ecdsa-sha2-nistp521-cert-v01@openssh.com<\/span>,<span class=\"Identifier\">ecdsa-sha2-nistp384-cert-v01@openssh.com<\/span>,<span class=\"Identifier\">ecdsa-sha2-nistp256-cert-v01@openssh.com<\/span>,<span class=\"Identifier\">ecdsa-sha2-nistp521<\/span>,<span class=\"Identifier\">ecdsa-sha2-nistp384<\/span>,<span class=\"Identifier\">ecdsa-sha2-nistp256<\/span>\n<\/pre>\n\n<p>This sets the order of preference and allowed list for server key algorithms. I used this to restrict the allowed key algorithms of servers to make sure the servers I connect to are not using outdated crypto.<\/p>\n<p>While writing this post, I updated this and the next section to follow <a href=\"https:\/\/wiki.mozilla.org\/Security\/Guidelines\/OpenSSH#Modern_.28OpenSSH_6.7.2B.29\">Mozilla guidelines<\/a>, though I already had very similar lists before.<\/p>\n<pre id=\"KexAlgorithms\" class=\"highlight\">\n<span class=\"Statement\">KexAlgorithms<\/span> <span class=\"Identifier\">curve25519-sha256@libssh.org<\/span>,<span class=\"Identifier\">ecdh-sha2-nistp521<\/span>,<span class=\"Identifier\">ecdh-sha2-nistp384<\/span>,<span class=\"Identifier\">ecdh-sha2-nistp256<\/span>,<span class=\"Identifier\">diffie-hellman-group-exchange-sha256<\/span>\n<span class=\"Statement\">MACs<\/span> <span class=\"Identifier\">hmac-sha2-512-etm@openssh.com<\/span>,<span class=\"Identifier\">hmac-sha2-256-etm@openssh.com<\/span>,<span class=\"Identifier\">umac-128-etm@openssh.com<\/span>,hmac-sha<span class=\"Constant\">2<\/span>-<span class=\"Constant\">512<\/span>,hmac-sha<span class=\"Constant\">2<\/span>-<span class=\"Constant\">256<\/span>,<span class=\"Identifier\">umac-128@openssh.com<\/span>\n<span class=\"Statement\">Ciphers<\/span> <span class=\"Identifier\">chacha20-poly1305@openssh.com<\/span>,<span class=\"Identifier\">aes256-gcm@openssh.com<\/span>,<span class=\"Identifier\">aes128-gcm@openssh.com<\/span>,<span class=\"Identifier\">aes256-ctr<\/span>,<span class=\"Identifier\">aes192-ctr<\/span>,<span class=\"Identifier\">aes128-ctr<\/span>\n<\/pre>\n\n<p>These directives restrict the key-exchange algorithm, ciphers and MACs sshd will be allowed to choose. This makes sure we are not connecting to insecure servers and can help prevent against downgrade attacks.<\/p>\n<p><strong>Note:<\/strong> it may be possible that you won't be able to connect to some servers with these settings, mainly on out-of-date embedded devices. You can change the list to allow obsolete ciphers (check the Mozilla link above) based on host (more on that later).<\/p>\n<pre id=\"HostE\" class=\"highlight\">\n<span class=\"Type\">Host<\/span> <span class=\"Constant\">*.enlightenment.org !e?.enlightenment.org !e?v*.enlightenment.org !git.enlightenment.org !devs.enlightenment.org<\/span>\n<\/pre>\n\n<p>The <code>Host<\/code> directive restricts the following declarations (until the next <code>Host<\/code> or <code>Match<\/code> keyword) only to hosts matching one of the patterns after the keyword. From the <samp>ssh_config<\/samp> manual: <q>A pattern consists of zero or more non-whitespace characters, \u2018*\u2019 (a wildcard that matches zero or more characters), or \u2018?\u2019 (a wildcard that matches exactly one character).<\/q> In addition, patterns starting with \u2018!\u2019 means negation, and such matched patterns will be excluded.<\/p>\n<p>This configuration line essentially means that all of the subdomains of enlightenment.org except for some specific patterns will have the following declarations applied to them. I excluded these domains because the following directive would either make ssh break or inefficient. More on that in the next section.<\/p>\n<pre id=\"ProxyCommand\" class=\"highlight\">\n  <span class=\"Statement\">ProxyCommand<\/span> ssh -q <span class=\"Constant\">tasn@e5v1.enlightenment.org<\/span> -W <span class=\"Identifier\">%h<\/span>:<span class=\"Identifier\">%p<\/span>\n<\/pre>\n\n<p>This line makes it so all the connections (to hosts matched my <code>Host<\/code>) will be tunnelled by the command listed after <code>ProxyCommand<\/code>. This is useful when connecting to servers behind a firewall. For example, in enlightenment.org we have many VMs that are not exposed to the world but we still need to connect to them sometimes (e.g. CI build machines). This command lets me tunnel my traffic through <samp>e5v1.enlightenment.org<\/samp> so I can pass through the firewall. I use <code>ssh<\/code> as the proxy command, but I could have used other tools for the task.<\/p>\n<p>Now let's break down <code>ssh -q tasn@e5v1.enlightenment.org -W %h:%p<\/code>. This calls ssh and tells it to connect to <samp>tasn@e5v1.enlightenment.org<\/samp> and suppresses warning and diagnostic messages (-q). It also tunnels input and output (-W) to the host and port (%h:%p) of the surrounding command. Essentially creating a tunnel through ssh.<\/p>","category":[{"@attributes":{"term":"misc"}},{"@attributes":{"term":"explaining configs"}},{"@attributes":{"term":"ssh"}},{"@attributes":{"term":"security"}}]},{"title":"Explaining My Configs: nftables","link":{"@attributes":{"href":"https:\/\/stosb.com\/blog\/explaining-my-configs-nftables\/","rel":"alternate"}},"published":"2016-12-13T14:00:00+00:00","updated":"2016-12-13T14:00:00+00:00","author":{"name":"Tom Hacohen"},"id":"tag:stosb.com,2016-12-13:\/blog\/explaining-my-configs-nftables\/","summary":"<p>This post is part of my <a href=\"https:\/\/stosb.com\/tag\/explaining-configs\/\"><em>Explaining My Configs<\/em> series<\/a> where I explain the configuration files (and options) I use in detail.<\/p>\n<p>This post could either be read as a whole, or as a reference (click on a line to jump to its explanation).<\/p>\n<p>This post covers <code>nftables<\/code> the next \u2026<\/p>","content":"<p>This post is part of my <a href=\"https:\/\/stosb.com\/tag\/explaining-configs\/\"><em>Explaining My Configs<\/em> series<\/a> where I explain the configuration files (and options) I use in detail.<\/p>\n<p>This post could either be read as a whole, or as a reference (click on a line to jump to its explanation).<\/p>\n<p>This post covers <code>nftables<\/code> the next generation packet filtering subsystem of the Linux kernel. It's meant to replace the <code>netfilter<\/code> (<code>iptables<\/code>) subsystem in the kernel, and has many advantages. Not long ago I decided to decipher my <code>iptables<\/code> rules and migrate to <code>nftables<\/code>. This configuration is the result of that effort. The resulting <code>nftables<\/code> rules are more readable, maintainable and less redundant than the previous IPv4 and IPv6 <code>iptables<\/code> equivalent, and if only because of that, I feel like the migration was worth it.<\/p>\n<p>I implemented a rather basic firewall. I use it to protect my servers, and I think it suffices. If you feel otherwise, please let me know. I hope to make these posts live examples of my configurations and would adjust as I encounter new scenarios that I need to protect against.<\/p>\n<p>Keep in mind, since this is a firewall configuration, in this post I assume some basic understanding of networking and firewalls.<\/p>\n<p><strong>Edit<\/strong>: this config has evolved since it was first published. While investigating nftables related issues I also came across new resources and got useful suggestions from people on the nftables IRC channel, namely: arturo and evilman.<\/p>\n<h1>What is this config for?<\/h1>\n<p>Unlike many other configurations, a firewall usually has many goals and touches many areas. For example, my firewall is configured to make my server more secure by filtering some kinds of traffic, but also implements port forwarding (see <a href=\"https:\/\/stosb.com\/blog\/using-an-external-server-and-a-vpn-to-escape-nats\/\">my previous post about VPN port forwarding<\/a>) and a NAT gateway for my VPN server. Therefore the <q>why<\/q> of this configuration is less clear, but I hope my usecases become more clear as I go through the config.<\/p>\n<h1>The config file<\/h1>\n<p>Click on a line to jump to its explanation.<\/p>\n<pre class=\"highlight no-link-decorations\">\n<a href=\"#FlushRuleset\"><span class=\"Identifier\">flush<\/span> ruleset<\/a>\n\n<a href=\"#TableInetFilter\"><span class=\"Identifier\">table<\/span> <span class=\"Type\">inet<\/span> <span class=\"Type\">filter<\/span> {<\/a>\n<a href=\"#Set\">    <span class=\"Identifier\">set<\/span> tcp_accepted {\n        <span class=\"Statement\">type<\/span> <span class=\"Type\">inet_service<\/span>; <span class=\"Statement\">flags<\/span> interval;\n        elements = {\n            http, https,\n            ssh,\n            xmpp-client, xmpp-server,\n        }\n    }\n    <span class=\"Identifier\">set<\/span> udp_accepted {\n        <span class=\"Statement\">type<\/span> <span class=\"Type\">inet_service<\/span>; <span class=\"Statement\">flags<\/span> interval;\n        elements = {\n            openvpn,\n            <span class=\"Constant\">60000<\/span>-<span class=\"Constant\">61000<\/span>, <span class=\"Comment\"># mosh<\/span>\n        }\n    }<\/a>\n\n<a href=\"#ChainBaseChecks\">    <span class=\"Identifier\">chain<\/span> base_checks {<\/a>\n<a href=\"#AllowEstablished\"><span class=\"Comment\">        # allow established\/related connections<\/span>\n        <span class=\"Type\">ct<\/span> state <span class=\"Statement\">{<\/span><span class=\"Statement\">established<\/span><span class=\"Statement\">, <\/span><span class=\"Statement\">related<\/span><span class=\"Statement\">}<\/span> <span class=\"Special\">accept<\/span><\/a>\n\n<a href=\"#DropInvalid\"><span class=\"Comment\">        # early drop of invalid connections<\/span>\n        <span class=\"Type\">ct<\/span> state invalid <span class=\"Special\">drop<\/span><\/a>\n<a href=\"#Curly\">    }<\/a>\n<a href=\"#ChainInput\">    <span class=\"Identifier\">chain<\/span> <span class=\"Constant\">input<\/span> {\n        <span class=\"Statement\">type<\/span> <span class=\"Type\">filter<\/span> <span class=\"Statement\">hook<\/span> <span class=\"Constant\">input<\/span> <span class=\"Type\">priority<\/span> <span class=\"Constant\">0<\/span>; policy <span class=\"Special\">drop<\/span>;<\/a>\n\n<a href=\"#AllowLoopback\"><span class=\"Comment\">        # allow from loopback<\/span>\n        <span class=\"Type\">iifname<\/span> lo <span class=\"Special\">accept<\/span><\/a>\n\n<a href=\"#JumpBaseChecks\">        <span class=\"Statement\">jump<\/span> base_checks<\/a>\n\n<a href=\"#AllowIcmp\"><span class=\"Comment\">        # allow icmp and igmp<\/span>\n        <span class=\"Type\">ip6 nexthdr icmpv6 icmpv6<\/span> <span class=\"Statement\">type<\/span> <span class=\"Keyword\">{ <\/span><span class=\"Keyword\">echo<\/span><span class=\"Keyword\">-<\/span><span class=\"Keyword\">request<\/span><span class=\"Keyword\">, <\/span><span class=\"Keyword\">echo<\/span><span class=\"Keyword\">-<\/span><span class=\"Keyword\">reply<\/span><span class=\"Keyword\">, <\/span><span class=\"Keyword\">packet<\/span><span class=\"Keyword\">-<\/span><span class=\"Keyword\">too<\/span><span class=\"Keyword\">-<\/span><span class=\"Keyword\">big<\/span><span class=\"Keyword\">, <\/span><span class=\"Keyword\">time<\/span><span class=\"Keyword\">-<\/span><span class=\"Keyword\">exceeded<\/span><span class=\"Keyword\">, <\/span><span class=\"Keyword\">parameter<\/span><span class=\"Keyword\">-<\/span><span class=\"Keyword\">problem<\/span><span class=\"Keyword\">, <\/span><span class=\"Keyword\">destination<\/span><span class=\"Keyword\">-<\/span><span class=\"Keyword\">unreachable<\/span><span class=\"Keyword\">, <\/span><span class=\"Keyword\">packet<\/span><span class=\"Keyword\">-<\/span><span class=\"Keyword\">too<\/span><span class=\"Keyword\">-<\/span><span class=\"Keyword\">big<\/span><span class=\"Keyword\">, <\/span><span class=\"Keyword\">mld<\/span><span class=\"Keyword\">-<\/span><span class=\"Keyword\">listener<\/span><span class=\"Keyword\">-<\/span><span class=\"Keyword\">query<\/span><span class=\"Keyword\">, <\/span><span class=\"Keyword\">mld<\/span><span class=\"Keyword\">-<\/span><span class=\"Keyword\">listener<\/span><span class=\"Keyword\">-<\/span><span class=\"Keyword\">report<\/span><span class=\"Keyword\">, <\/span><span class=\"Keyword\">mld<\/span><span class=\"Keyword\">-<\/span><span class=\"Keyword\">listener<\/span><span class=\"Keyword\">-<\/span><span class=\"Keyword\">reduction<\/span><span class=\"Keyword\">, <\/span><span class=\"Keyword\">nd<\/span><span class=\"Keyword\">-<\/span><span class=\"Keyword\">router<\/span><span class=\"Keyword\">-<\/span><span class=\"Keyword\">solicit<\/span><span class=\"Keyword\">, <\/span><span class=\"Keyword\">nd<\/span><span class=\"Keyword\">-<\/span><span class=\"Keyword\">router<\/span><span class=\"Keyword\">-<\/span><span class=\"Keyword\">advert<\/span><span class=\"Keyword\">, <\/span><span class=\"Keyword\">nd<\/span><span class=\"Keyword\">-<\/span><span class=\"Keyword\">neighbor<\/span><span class=\"Keyword\">-<\/span><span class=\"Keyword\">solicit<\/span><span class=\"Keyword\">, <\/span><span class=\"Keyword\">nd<\/span><span class=\"Keyword\">-<\/span><span class=\"Keyword\">neighbor<\/span><span class=\"Keyword\">-<\/span><span class=\"Keyword\">advert<\/span><span class=\"Keyword\">, <\/span><span class=\"Keyword\">ind<\/span><span class=\"Keyword\">-<\/span><span class=\"Keyword\">neighbor<\/span><span class=\"Keyword\">-<\/span><span class=\"Keyword\">solicit<\/span><span class=\"Keyword\">, <\/span><span class=\"Keyword\">ind<\/span><span class=\"Keyword\">-<\/span><span class=\"Keyword\">neighbor<\/span><span class=\"Keyword\">-<\/span><span class=\"Keyword\">advert<\/span><span class=\"Keyword\">, <\/span><span class=\"Keyword\">mld2<\/span><span class=\"Keyword\">-<\/span><span class=\"Keyword\">listener<\/span><span class=\"Keyword\">-<\/span><span class=\"Keyword\">report<\/span><span class=\"Keyword\"> }<\/span> <span class=\"Special\">accept<\/span>\n        <span class=\"Type\">ip<\/span> <span class=\"Type\">protocol<\/span> <span class=\"Type\">icmp<\/span> <span class=\"Type\">icmp<\/span> <span class=\"Statement\">type<\/span> <span class=\"Keyword\">{ <\/span><span class=\"Keyword\">echo<\/span><span class=\"Keyword\">-<\/span><span class=\"Keyword\">request<\/span><span class=\"Keyword\">, <\/span><span class=\"Keyword\">echo<\/span><span class=\"Keyword\">-<\/span><span class=\"Keyword\">reply<\/span><span class=\"Keyword\">, <\/span><span class=\"Keyword\">destination<\/span><span class=\"Keyword\">-<\/span><span class=\"Keyword\">unreachable<\/span><span class=\"Keyword\">, <\/span><span class=\"Keyword\">router<\/span><span class=\"Keyword\">-<\/span><span class=\"Keyword\">solicitation<\/span><span class=\"Keyword\">, <\/span><span class=\"Keyword\">router<\/span><span class=\"Keyword\">-<\/span><span class=\"Keyword\">advertisement<\/span><span class=\"Keyword\">, <\/span><span class=\"Keyword\">time<\/span><span class=\"Keyword\">-<\/span><span class=\"Keyword\">exceeded<\/span><span class=\"Keyword\">, <\/span><span class=\"Keyword\">parameter<\/span><span class=\"Keyword\">-<\/span><span class=\"Keyword\">problem<\/span><span class=\"Keyword\"> }<\/span> <span class=\"Special\">accept<\/span>\n        <span class=\"Type\">ip<\/span> <span class=\"Type\">protocol<\/span> igmp <span class=\"Special\">accept<\/span>\n\n<a href=\"#AllowPorts\"><span class=\"Comment\">        # allow ports<\/span>\n        <span class=\"Type\">tcp<\/span> dport @tcp_accepted <span class=\"Special\">accept<\/span>\n        <span class=\"Type\">udp<\/span> dport @udp_accepted <span class=\"Special\">accept<\/span><\/a>\n<a href=\"#Curly\">    }<\/a>\n<a href=\"#ChainForward\">    <span class=\"Identifier\">chain<\/span> <span class=\"Constant\">forward<\/span> {\n        <span class=\"Statement\">type<\/span> <span class=\"Type\">filter<\/span> <span class=\"Statement\">hook<\/span> <span class=\"Constant\">forward<\/span> <span class=\"Type\">priority<\/span> <span class=\"Constant\">0<\/span>; policy <span class=\"Special\">drop<\/span>;<\/a>\n\n<a href=\"#JumpBaseChecks\">        <span class=\"Statement\">jump<\/span> base_checks<\/a>\n\n<a href=\"#VpnOut\"><span class=\"Comment\">        # Allow coming out of the vpn<\/span>\n        <span class=\"Type\">ip<\/span> saddr <span class=\"Constant\">192<\/span><span class=\"Statement\">.<\/span><span class=\"Constant\">168<\/span><span class=\"Statement\">.<\/span><span class=\"Constant\">87<\/span><span class=\"Statement\">.<\/span><span class=\"Constant\">0<\/span><span class=\"Statement\">\/<\/span><span class=\"Statement\">24<\/span> <span class=\"Type\">iifname<\/span> tun0 <span class=\"Special\">accept<\/span><\/a>\n\n<a href=\"#AllowHomeSrv\"><span class=\"Comment\">        # Allow connecting to home_srv.<\/span>\n        <span class=\"Type\">ip<\/span> daddr home_srv <span class=\"Type\">ct<\/span> status <span class=\"Special\">dnat<\/span> <span class=\"Special\">accept<\/span><\/a>\n<a href=\"#Curly\">    }<\/a>\n<a href=\"#ChainOutput\">    <span class=\"Identifier\">chain<\/span> <span class=\"Constant\">output<\/span> {\n        <span class=\"Statement\">type<\/span> <span class=\"Type\">filter<\/span> <span class=\"Statement\">hook<\/span> <span class=\"Constant\">output<\/span> <span class=\"Type\">priority<\/span> <span class=\"Constant\">0<\/span>; policy <span class=\"Special\">accept<\/span>;<\/a>\n<a href=\"#Curly\">    }<\/a>\n<a href=\"#Curly\">}<\/a>\n\n<a href=\"#TableIpNat\"><span class=\"Identifier\">table<\/span> <span class=\"Type\">ip<\/span> <span class=\"Type\">nat<\/span> {<\/a>\n<a href=\"#ChainPrerouting\">    <span class=\"Identifier\">chain<\/span> <span class=\"Constant\">prerouting<\/span> {\n        <span class=\"Statement\">type<\/span> <span class=\"Type\">nat<\/span> <span class=\"Statement\">hook<\/span> <span class=\"Constant\">prerouting<\/span> <span class=\"Type\">priority<\/span> <span class=\"Constant\">0<\/span>;<\/a>\n\n<a href=\"#NatHomeSrv\">        <span class=\"Type\">tcp<\/span> dport <span class=\"Constant\">2222<\/span> <span class=\"Special\">dnat<\/span> home_srv <span class=\"Comment\"># ssh<\/span>\n        <span class=\"Type\">udp<\/span> dport <span class=\"Constant\">61001<\/span>-<span class=\"Constant\">62000<\/span> <span class=\"Special\">dnat<\/span> home_srv <span class=\"Comment\"># mosh<\/span><\/a>\n<a href=\"#Curly\">    }<\/a>\n<a href=\"#ChainPostrouting\">    <span class=\"Identifier\">chain<\/span> <span class=\"Constant\">postrouting<\/span> {\n        <span class=\"Statement\">type<\/span> <span class=\"Type\">nat<\/span> <span class=\"Statement\">hook<\/span> <span class=\"Constant\">postrouting<\/span> <span class=\"Type\">priority<\/span> <span class=\"Constant\">100<\/span>;<\/a>\n\n<a href=\"#Masquerade\">        <span class=\"Type\">oifname<\/span> <span class=\"Statement\">{<\/span><span class=\"Statement\">ens3<\/span><span class=\"Statement\">, <\/span><span class=\"Statement\">tun0<\/span><span class=\"Statement\">}<\/span> <span class=\"Special\">masquerade<\/span><\/a>\n<a href=\"#Curly\">    }<\/a>\n<a href=\"#Curly\">}<\/a>\n<\/pre>\n<p>&nbsp;<\/p>\n<h1>Reviewing the config<\/h1>\n<pre id=\"FlushRuleset\" class=\"highlight\">\n<span class=\"Identifier\">flush<\/span> ruleset\n<\/pre>\n\n<p>Clears the previous ruleset. This flushes out all the tables, chains and rules so we can start clean. This is not done automatically so without this, previously added rules would still be in effect.<\/p>\n<pre id=\"TableInetFilter\" class=\"highlight\">\n<span class=\"Identifier\">table<\/span> <span class=\"Type\">inet<\/span> <span class=\"Type\">filter<\/span> {\n<\/pre>\n\n<p>This defines a table. A table is a container for chains (and sets). This line defines a table with the family <code>inet<\/code> and name <code>filter<\/code>.\n<code>inet<\/code> is a dummy family that means internet address (both IPv4 and IPv6). I wanted a shared config between the two so I chose this one, alternatively I could have restricted it to either by using <code>ip<\/code> or <code>ip6<\/code>.<\/p>\n<pre id=\"Set\" class=\"highlight\">\n    <span class=\"Identifier\">set<\/span> tcp_accepted {\n        <span class=\"Statement\">type<\/span> <span class=\"Type\">inet_service<\/span>; <span class=\"Statement\">flags<\/span> interval;\n        elements = {\n            http, https,\n            ssh,\n            xmpp-client, xmpp-server,\n        }\n    }\n    <span class=\"Identifier\">set<\/span> udp_accepted {\n        <span class=\"Statement\">type<\/span> <span class=\"Type\">inet_service<\/span>; <span class=\"Statement\">flags<\/span> interval;\n        elements = {\n            openvpn,\n            <span class=\"Constant\">60000<\/span>-<span class=\"Constant\">61000<\/span>, <span class=\"Comment\"># mosh<\/span>\n        }\n    }\n<\/pre>\n\n<p>This creates two sets of type <code>inet_service<\/code> (port number or range). The <code>flags interval<\/code> directive enables ranges (like the mosh one). After that, you just set <code>elements<\/code> to add members to the set. Having a set is a clean and efficient way to later reference all of these values in the rules. We can use port numbers, service names and port ranges.<\/p>\n<p>Sets provide a performant way to use generic sets of data, that can be dynamically manipulated, so they are very suitable for tasks like IP blocking. More about sets on the <a href=\"https:\/\/wiki.nftables.org\/wiki-nftables\/index.php\/Sets\">nftables wiki page<\/a>.<\/p>\n<p>These two are the lists of allowed ports that will be <a href=\"#AllowPorts\">used later<\/a>.<\/p>\n<pre id=\"ChainBaseChecks\" class=\"highlight\">\n    <span class=\"Identifier\">chain<\/span> base_checks {\n<\/pre>\n\n<p>This directive creates a chain called <code>base_checks<\/code>. A chain is a container for rules.<\/p>\n<p>This chain does a few basic checks I wanted to reuse without having to repeat myself. Unlike, for example, <a href=\"#ChainInput\">the input chain<\/a>, this chain doesn't naturally receive packets for processing, it has to be called explicitly with either <a href=\"#JumpBaseChecks\"><code>jump<\/code><\/a> or <code>goto<\/code>.<\/p>\n<pre id=\"AllowEstablished\" class=\"highlight\">\n<span class=\"Comment\">        # allow established\/related connections<\/span>\n        <span class=\"Type\">ct<\/span> state <span class=\"Statement\">{<\/span><span class=\"Statement\">established<\/span><span class=\"Statement\">, <\/span><span class=\"Statement\">related<\/span><span class=\"Statement\">}<\/span> <span class=\"Special\">accept<\/span>\n<\/pre>\n\n<p>This is our first rule, and it includes a lot of new syntax to review.\nLet's first start with what it does. This rule is here to allow already established or related connections through. If the connection has already been established, it probably means it was already allowed by us earlier and we can just continue allowing it.<\/p>\n<p><code>ct<\/code> is used to tap into the connection tracking entry associated with the packet. In this case, we are accessing the <code>state<\/code> of the connection, and checking if it's in the set <code>{established, related}<\/code>. If it is in it, accept the packet, otherwise, continue to the next rule.<\/p>\n<pre id=\"DropInvalid\" class=\"highlight\">\n<span class=\"Comment\">        # early drop of invalid connections<\/span>\n        <span class=\"Type\">ct<\/span> state invalid <span class=\"Special\">drop<\/span>\n<\/pre>\n\n<p>This is similar to the previous line, but this time, instead of checking if the state is within a set, we only check if the connection state is <code>invalid<\/code> and if so, we drop the connection. That is, we just ignore the packet as if it never came in.<\/p>\n<pre id=\"Curly\" class=\"highlight\">\n    }\n<\/pre>\n\n<p>This is a curly bracket. You know what it does. I had to put it here because I promised to explain every line.<\/p>\n<pre id=\"ChainInput\" class=\"highlight\">\n    <span class=\"Identifier\">chain<\/span> <span class=\"Constant\">input<\/span> {\n        <span class=\"Statement\">type<\/span> <span class=\"Type\">filter<\/span> <span class=\"Statement\">hook<\/span> <span class=\"Constant\">input<\/span> <span class=\"Type\">priority<\/span> <span class=\"Constant\">0<\/span>; policy <span class=\"Special\">drop<\/span>;\n<\/pre>\n\n<p>Like with the <a href=\"#ChainBaseChecks\">base checks chain<\/a>, this defines a chain with the name <code>input<\/code>. The name doesn't matter, but I chose input to stick with the already familiar <code>iptables<\/code> convention.<\/p>\n<p>Unlike the base checks chain, in this one we tell <code>nftables<\/code> what kind of packets we would like to accept and what we would like to do with them by default.<\/p>\n<p>With the type statement, we tell <code>nftables<\/code> our chain will be of type <code>filter<\/code> (filtering packets), and it will do so on <code>input<\/code> packets (incoming packets). We also set a priority of zero, although I read that priorities aren't currently used, so I will skip explaining them for now.<\/p>\n<p>The last thing that we do in this line is declare the default policy for this chain. That means all packets that are not handled are dropped by default.<\/p>\n<pre id=\"AllowLoopback\" class=\"highlight\">\n<span class=\"Comment\">        # allow from loopback<\/span>\n        <span class=\"Type\">iifname<\/span> lo <span class=\"Special\">accept<\/span>\n<\/pre>\n\n<p>Packets from the loopback interface are generally safe, so just accept everything coming from there.<\/p>\n<pre id=\"JumpBaseChecks\" class=\"highlight\">\n        <span class=\"Statement\">jump<\/span> base_checks\n<\/pre>\n\n<p>There are two ways to move the flow of the rule processing to another chain: <code>jump<\/code> and <code>goto<\/code>. The only difference between them is that in case the target chain doesn't decide what to do with the packet (e.g. accept), <code>jump<\/code> will return to the previous position and continue processing, while <code>goto<\/code> will just decide based on the chain's default policy.<\/p>\n<p>I use <code>jump<\/code> here because I want to continue processing after the base checks.<\/p>\n<pre id=\"AllowIcmp\" class=\"highlight\">\n<span class=\"Comment\">        # allow icmp and igmp<\/span>\n        <span class=\"Type\">ip<\/span> <span class=\"Type\">protocol<\/span> <span class=\"Type\">icmp<\/span> <span class=\"Type\">icmp<\/span> <span class=\"Statement\">type<\/span> <span class=\"Statement\">{ <\/span><span class=\"Statement\">echo<\/span><span class=\"Statement\">-<\/span><span class=\"Statement\">request<\/span><span class=\"Statement\">, <\/span><span class=\"Statement\">echo<\/span><span class=\"Statement\">-<\/span><span class=\"Statement\">reply<\/span><span class=\"Statement\">, <\/span><span class=\"Statement\">time<\/span><span class=\"Statement\">-<\/span><span class=\"Statement\">exceeded<\/span><span class=\"Statement\">, <\/span><span class=\"Statement\">parameter<\/span><span class=\"Statement\">-<\/span><span class=\"Statement\">problem<\/span><span class=\"Statement\">, <\/span><span class=\"Statement\">destination<\/span><span class=\"Statement\">-<\/span><span class=\"Statement\">unreachable<\/span><span class=\"Statement\"> }<\/span> <span class=\"Special\">accept<\/span>\n        <span class=\"Type\">ip6<\/span> nexthdr icmpv6 icmpv6 <span class=\"Statement\">type<\/span> <span class=\"Statement\">{ <\/span><span class=\"Statement\">echo<\/span><span class=\"Statement\">-<\/span><span class=\"Statement\">request<\/span><span class=\"Statement\">, <\/span><span class=\"Statement\">echo<\/span><span class=\"Statement\">-<\/span><span class=\"Statement\">reply<\/span><span class=\"Statement\">, <\/span><span class=\"Statement\">time<\/span><span class=\"Statement\">-<\/span><span class=\"Statement\">exceeded<\/span><span class=\"Statement\">, <\/span><span class=\"Statement\">parameter<\/span><span class=\"Statement\">-<\/span><span class=\"Statement\">problem<\/span><span class=\"Statement\">, <\/span><span class=\"Statement\">destination<\/span><span class=\"Statement\">-<\/span><span class=\"Statement\">unreachable<\/span><span class=\"Statement\">, <\/span><span class=\"Statement\">packet<\/span><span class=\"Statement\">-<\/span><span class=\"Statement\">too<\/span><span class=\"Statement\">-<\/span><span class=\"Statement\">big<\/span><span class=\"Statement\">, <\/span><span class=\"Statement\">nd<\/span><span class=\"Statement\">-<\/span><span class=\"Statement\">router<\/span><span class=\"Statement\">-<\/span><span class=\"Statement\">advert<\/span><span class=\"Statement\">, <\/span><span class=\"Statement\">nd<\/span><span class=\"Statement\">-<\/span><span class=\"Statement\">router<\/span><span class=\"Statement\">-<\/span><span class=\"Statement\">solicit<\/span><span class=\"Statement\">, <\/span><span class=\"Statement\">nd<\/span><span class=\"Statement\">-<\/span><span class=\"Statement\">neighbor<\/span><span class=\"Statement\">-<\/span><span class=\"Statement\">solicit<\/span><span class=\"Statement\">, <\/span><span class=\"Statement\">nd<\/span><span class=\"Statement\">-<\/span><span class=\"Statement\">neighbor<\/span><span class=\"Statement\">-<\/span><span class=\"Statement\">advert<\/span><span class=\"Statement\">, <\/span><span class=\"Statement\">mld<\/span><span class=\"Statement\">-<\/span><span class=\"Statement\">listener<\/span><span class=\"Statement\">-<\/span><span class=\"Statement\">query<\/span><span class=\"Statement\"> }<\/span> <span class=\"Special\">accept<\/span>\n<\/pre>\n\n<p>These three commands let some ICMP and all IGMP packets go through. This list may not be complete, but it has served me well so far.<\/p>\n<p>As you may remember, our table type is <code>inet<\/code> which means IPv4 or IPv6. However, ICMP is different to ICMPv6. This means that we have to do our checks in with version specific directives. The <code>ip<\/code> and <code>ip6<\/code> directives do that. After more version specific checks, we match the version specific types.<\/p>\n<p>If everything matches, we accept, otherwise, we move on.<\/p>\n<pre id=\"AllowPorts\" class=\"highlight\">\n<span class=\"Comment\">        # allow ports<\/span>\n        <span class=\"Type\">tcp<\/span> dport @tcp_accepted <span class=\"Special\">accept<\/span>\n        <span class=\"Type\">udp<\/span> dport @udp_accepted <span class=\"Special\">accept<\/span>\n<\/pre>\n\n<p>These two rules are in charge of accepting incoming connections. One starts with <code>tcp<\/code> and one starts with <code>udp<\/code> to restrict based on the protocol. We then match the <code>dport<\/code> (destination port) against the <a href=\"#Set\">sets<\/a> we defined earlier to check if we would like to allow it.<\/p>\n<pre id=\"ChainForward\" class=\"highlight\">\n    <span class=\"Identifier\">chain<\/span> <span class=\"Constant\">forward<\/span> {\n        <span class=\"Statement\">type<\/span> <span class=\"Type\">filter<\/span> <span class=\"Statement\">hook<\/span> <span class=\"Constant\">forward<\/span> <span class=\"Type\">priority<\/span> <span class=\"Constant\">0<\/span>; policy <span class=\"Special\">drop<\/span>;\n<\/pre>\n\n<p>This is very similar to <a href=\"#ChainInput\">the input chain<\/a>, however this time we will be filtering packets with the <code>forward<\/code> hook, that is, packets that are going to be forwarded by our firewall. This is only useful if your firewall is meant to be forwarding packets, like if for example it's used as a gateway.<\/p>\n<p>Please take a look at <a href=\"#PacketForwarding\">the packet forwarding extra note<\/a>. It contains more actions needed for this to work.<\/p>\n<pre id=\"VpnOut\" class=\"highlight\">\n<span class=\"Comment\">        # Allow coming out of the vpn<\/span>\n        <span class=\"Type\">ip<\/span> saddr <span class=\"Constant\">192<\/span><span class=\"Statement\">.<\/span><span class=\"Constant\">168<\/span><span class=\"Statement\">.<\/span><span class=\"Constant\">87<\/span><span class=\"Statement\">.<\/span><span class=\"Constant\">0<\/span><span class=\"Statement\">\/<\/span><span class=\"Statement\">24<\/span> <span class=\"Type\">iifname<\/span> tun0 <span class=\"Special\">accept<\/span>\n<\/pre>\n\n<p>Here we allow packets to be forwarded from the VPN to the rest of the network.\nMy VPN device is called <code>tun0<\/code> and <code>192.168.87.0\/24<\/code> is my VPN's netmask.<\/p>\n<p>First of all, because <a href=\"#AllowIcmp\">again<\/a> I'm dealing with IPv4 specific information (the netmask) in an <code>inet<\/code> table, I have to prefix the directive with <code>ip<\/code>. Then I check if the IP is in the VPN range and the packet came from the VPN interface, if so, I will accept it for forwarding.<\/p>\n<pre id=\"AllowHomeSrv\" class=\"highlight\">\n<span class=\"Comment\">        # Allow connecting to home_srv.<\/span>\n        <span class=\"Type\">ip<\/span> daddr home_srv <span class=\"Type\">ct<\/span> status <span class=\"Special\">dnat<\/span> <span class=\"Special\">accept<\/span>\n<\/pre>\n\n<p>Here I allow forwarding all the traffic directed to my home server. We rely on DNS (at the time of rule loading). Make sure to hardcode this hostname in your <code>\/etc\/hosts<\/code> or have another way to ensure that the DNS can't be manipulated by an attacker. The name is resolved at the time of rule loading.<\/p>\n<p><code>ct status dnat<\/code> makes sure we only allow packets that have had <code>dnat<\/code> done on them. We use that because we want to only forward packets that have been <a href=\"#NatHomeSrv\">NATed by us<\/a>.<\/p>\n<pre id=\"ChainOutput\" class=\"highlight\">\n    <span class=\"Identifier\">chain<\/span> <span class=\"Constant\">output<\/span> {\n        <span class=\"Statement\">type<\/span> <span class=\"Type\">filter<\/span> <span class=\"Statement\">hook<\/span> <span class=\"Constant\">output<\/span> <span class=\"Type\">priority<\/span> <span class=\"Constant\">0<\/span>; policy <span class=\"Special\">accept<\/span>;\n<\/pre>\n\n<p>I think this behaviour is already the default, but I include it here for completeness. This chain accepts all outgoing packets.<\/p>\n<pre id=\"TableIpNat\" class=\"highlight\">\n<span class=\"Identifier\">table<\/span> <span class=\"Type\">ip<\/span> <span class=\"Type\">nat<\/span> {\n<\/pre>\n\n<p>This table will take care of all of the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Network_address_translation\">NAT<\/a>. Since this is an IPv4 NAT, this table's family is set to <code>ip<\/code>.<\/p>\n<pre id=\"ChainPrerouting\" class=\"highlight\">\n    <span class=\"Identifier\">chain<\/span> <span class=\"Constant\">prerouting<\/span> {\n        <span class=\"Statement\">type<\/span> <span class=\"Type\">nat<\/span> <span class=\"Statement\">hook<\/span> <span class=\"Constant\">prerouting<\/span> <span class=\"Type\">priority<\/span> <span class=\"Constant\">0<\/span>;\n<\/pre>\n\n<p>Yet another chain, this time called prerouting. Unlike <a href=\"#ChainInput\">the chains before<\/a>, this chain is of type <code>nat<\/code> and not <code>filter<\/code>. This type means we will be changing packets instead of deciding their fate like we did before. Also, this time, we are using the <code>prerouting<\/code> hook. All packets entering the system are processed by this hook and it's invoked before everything else. We are using this because we would like to modify the packets, and only then pass them on to the rest of the rules for processing.<\/p>\n<pre id=\"NatHomeSrv\" class=\"highlight\">\n        <span class=\"Type\">tcp<\/span> dport <span class=\"Constant\">2222<\/span> <span class=\"Special\">dnat<\/span> home_srv <span class=\"Comment\"># ssh<\/span>\n        <span class=\"Type\">udp<\/span> dport <span class=\"Constant\">61001<\/span>-<span class=\"Constant\">62000<\/span> <span class=\"Special\">dnat<\/span> home_srv <span class=\"Comment\"># mosh<\/span>\n<\/pre>\n\n<p>These two lines take care of port forwarding. Like in the filter rules, we check if the packet is of a specific protocol and destination port, but this time, instead of accepting, dropping or rejecting, we <code>dnat<\/code> (destination nat), where we change the destination address from the server's address to the home server's one (see <a href=\"#AllowHomeSrv\">comment about name resolution<\/a>) so the packet is forwarded there.<\/p>\n<pre id=\"ChainPostrouting\" class=\"highlight\">\n    <span class=\"Identifier\">chain<\/span> <span class=\"Constant\">postrouting<\/span> {\n        <span class=\"Statement\">type<\/span> <span class=\"Type\">nat<\/span> <span class=\"Statement\">hook<\/span> <span class=\"Constant\">postrouting<\/span> <span class=\"Type\">priority<\/span> <span class=\"Constant\">100<\/span>;\n<\/pre>\n\n<p>This chain is very similar to <a href=\"#ChainPrerouting\">the prerouting chain<\/a>, but it instead hooks on <code>postrouting<\/code>. This is the hook on the other end of <code>prerouting<\/code>, this processes all packets that leave the system, after all the decisions have been made.<\/p>\n<pre id=\"Masquerade\" class=\"highlight\">\n        <span class=\"Type\">oifname<\/span> <span class=\"Statement\">{<\/span><span class=\"Statement\">ens3<\/span><span class=\"Statement\">, <\/span><span class=\"Statement\">tun0<\/span><span class=\"Statement\">}<\/span> <span class=\"Special\">masquerade<\/span>\n<\/pre>\n\n<p>Before I explain this line, let me explain what it solves. Computers behind a NAT, for example <code>home_srv<\/code>, are not aware of the NAT or their internet facing IP address, so when they send packets, the source IP is their IP. For example, when <code>home_srv<\/code> sends a packet to <code>8.8.8.8<\/code>, the source address will be <code>192.168.87.10<\/code> and the destination will be <code>8.8.8.8<\/code>. The main problem with that, is that when <code>8.8.8.8<\/code> replies, it will reply to <code>192.168.87.10<\/code> which won't be routed back to <code>home_srv<\/code> because it's a private address.<\/p>\n<p>To solve this problem you would want to use something called source NAT. In the previous section we modified the destination address (destination NAT), in this one, we want to change the source address to be that of our external, internet routeable, ip address so in my case <code>149.154.152.35<\/code>.<\/p>\n<p>This means we could have just used <code>oifname ens3 snat 149.154.152.35<\/code> to make it work. However, sometimes computers have multiple interfaces, or changing IP addresses, so this can become really annoying to maintain.<\/p>\n<p>This is what <code>masquerade<\/code> is for. It automatically rewrites the source IP of forwarded packets to the one of the output interface.<\/p>\n<p><strong>Note:<\/strong> I expected just having <code>masquerade<\/code> here to work, just like it used to with <code>iptables<\/code>. However it broke connections through the <code>lo<\/code> interface. I had to add the <code>oifname<\/code> condition to filter <code>lo<\/code> out. I started <a href=\"http:\/\/marc.info\/?l=netfilter&amp;m=148163574924083&amp;w=2\">a discussion about it<\/a> on the nftables mailing list.<\/p>\n<h1>Extra notes<\/h1>\n<h2>Rule debugging<\/h2>\n<p><code>nftables<\/code> supports <a href=\"https:\/\/wiki.nftables.org\/wiki-nftables\/index.php\/Ruleset_debug\/tracing\">tracing<\/a> which lets you see all the rules a packet has been evaluated against and the resulting decision.<\/p>\n<p>Unfortunately I only managed to get it to work on my laptop, and not on my server. I'm still investigating.<\/p>\n<p><strong>Edit<\/strong>: corrected a mistake and note that I now got it to work on one of my machines.<\/p>\n<h2 id=\"PacketForwarding\">Packet forwarding<\/h2>\n<p>Don't forget to set the following kernel parameters (using <code>sysctl<\/code>) to enable packet forwarding in the kernel (if you need it). Also, don't forget to make these changes permanent.<\/p>\n<div class=\"highlight\"><pre><span><\/span><code>net.ipv4.ip_forward = 1\nnet.ipv6.conf.all.forwarding = 1\n<\/code><\/pre><\/div>\n\n<h2>Useful reference<\/h2>\n<p>I recently found a useful reference: <a href=\"https:\/\/wiki.nftables.org\/wiki-nftables\/index.php\/Quick_reference-nftables_in_10_minutes\">link<\/a>.<\/p>","category":[{"@attributes":{"term":"misc"}},{"@attributes":{"term":"explaining configs"}},{"@attributes":{"term":"security"}},{"@attributes":{"term":"nftables"}},{"@attributes":{"term":"firewall"}}]},{"title":"Explaining My Configs: sshd_config","link":{"@attributes":{"href":"https:\/\/stosb.com\/blog\/explaining-my-configs-sshd_config\/","rel":"alternate"}},"published":"2016-12-07T14:00:00+00:00","updated":"2016-12-07T14:00:00+00:00","author":{"name":"Tom Hacohen"},"id":"tag:stosb.com,2016-12-07:\/blog\/explaining-my-configs-sshd_config\/","summary":"<p>This is the first post of what I hope will be a <a href=\"https:\/\/stosb.com\/tag\/explaining-configs\/\">series<\/a>. In each post I will explain my configuration files in detail. Specifically, I will explain what were my goals when configuring that exact service, and why I set each configuration to its current value. These should not \u2026<\/p>","content":"<p>This is the first post of what I hope will be a <a href=\"https:\/\/stosb.com\/tag\/explaining-configs\/\">series<\/a>. In each post I will explain my configuration files in detail. Specifically, I will explain what were my goals when configuring that exact service, and why I set each configuration to its current value. These should not be considered as definite guides to these services, just real-world configuration examples and the reasoning behind them.<\/p>\n<p>By writing these, I hope to provide useful real-world configuration examples that are easy to understand and thus easy to adjust, instead of the usual <em><q>copy this configuration if you want to do X<\/q><\/em>.<\/p>\n<p>This post could either be read as a whole, or as a reference (click on a line to jump to its explanation).<\/p>\n<h1>What is this config for?<\/h1>\n<p>The goal of these configuration changes is to harden the security and ease the management of <code>sshd<\/code>. Another nice-to-have goal is to make the configuration generic enough so it could be reused among servers without sacrificing security or configurability.<\/p>\n<p>The configuration below only includes values that I have changed, so default values are omitted.<\/p>\n<h1>The config file<\/h1>\n<p>Click on a line to jump to its explanation.<\/p>\n<pre class=\"highlight no-link-decorations\">\n<a href=\"#PermitRootLogin\"><span class=\"Statement\">PermitRootLogin<\/span> <span class=\"Identifier\">no<\/span><\/a>\n\n<a href=\"#AuthorizedKeysFile\"><span class=\"Statement\">AuthorizedKeysFile<\/span> \/etc\/ssh\/authorized_keys\/<span class=\"Identifier\">%u<\/span><\/a>\n\n<a href=\"#PasswordAuthentication\"><span class=\"Statement\">PasswordAuthentication<\/span> <span class=\"Identifier\">no<\/span>\n<span class=\"Statement\">PermitEmptyPasswords<\/span> <span class=\"Identifier\">no<\/span>\n<span class=\"Statement\">ChallengeResponseAuthentication<\/span> <span class=\"Identifier\">no<\/span>\n<span class=\"Statement\">AuthenticationMethods<\/span> publickey<\/a>\n\n<a href=\"#AllowGroups\"><span class=\"Statement\">AllowGroups<\/span> wheel ssh-user ssh-sftp-user<\/a>\n\n<a href=\"#UsePAM\"><span class=\"Statement\">UsePAM<\/span> <span class=\"Identifier\">yes<\/span><\/a>\n\n<a href=\"#X11Forwarding\"><span class=\"Statement\">X11Forwarding<\/span> <span class=\"Identifier\">yes<\/span><\/a>\n<a href=\"#PrintMotd\"><span class=\"Statement\">PrintMotd<\/span> <span class=\"Identifier\">no<\/span><span class=\"Comment\"> # pam does that<\/span><\/a>\n\n<a href=\"#KexAlgorithms\"><span class=\"Comment\"># Harden crypto<\/span>\n<span class=\"Statement\">KexAlgorithms<\/span> <span class=\"Identifier\">curve25519-sha256@libssh.org<\/span>,<span class=\"Identifier\">ecdh-sha2-nistp521<\/span>,<span class=\"Identifier\">ecdh-sha2-nistp384<\/span>,<span class=\"Identifier\">ecdh-sha2-nistp256<\/span>,<span class=\"Identifier\">diffie-hellman-group-exchange-sha256<\/span>\n<span class=\"Statement\">Ciphers<\/span> <span class=\"Identifier\">chacha20-poly1305@openssh.com<\/span>,<span class=\"Identifier\">aes256-gcm@openssh.com<\/span>,<span class=\"Identifier\">aes128-gcm@openssh.com<\/span>,<span class=\"Identifier\">aes256-ctr<\/span>,<span class=\"Identifier\">aes192-ctr<\/span>,<span class=\"Identifier\">aes128-ctr<\/span>\n<span class=\"Statement\">MACs<\/span> <span class=\"Identifier\">hmac-sha2-512-etm@openssh.com<\/span>,<span class=\"Identifier\">hmac-sha2-256-etm@openssh.com<\/span>,<span class=\"Identifier\">umac-128-etm@openssh.com<\/span>,hmac-sha<span class=\"Constant\">2<\/span>-<span class=\"Constant\">512<\/span>,hmac-sha<span class=\"Constant\">2<\/span>-<span class=\"Constant\">256<\/span>,<span class=\"Identifier\">umac-128@openssh.com<\/span><\/a>\n\n\n<a href=\"#Subsystem\"><span class=\"Statement\">Subsystem<\/span>   sftp    <span class=\"Identifier\">internal-sftp<\/span><\/a>\n\n<a href=\"#Match\"><span class=\"Statement\">Match<\/span> <span class=\"Type\">Group<\/span> ssh-sftp-user\n    <span class=\"Statement\">X11Forwarding<\/span> <span class=\"Identifier\">no<\/span>\n\n    <span class=\"Statement\">AllowTcpForwarding<\/span> <span class=\"Identifier\">no<\/span>\n    <span class=\"Statement\">PermitTTY<\/span> <span class=\"Identifier\">no<\/span>\n    <span class=\"Statement\">ChrootDirectory<\/span> <span class=\"Identifier\">%h<\/span>\n    <span class=\"Statement\">ForceCommand<\/span> <span class=\"Identifier\">internal-sftp<\/span><\/a>\n<\/pre>\n<p>&nbsp;<\/p>\n<h1>Reviewing the config<\/h1>\n<pre id=\"PermitRootLogin\" class=\"highlight\">\n<span class=\"Statement\">PermitRootLogin<\/span> <span class=\"Identifier\">no<\/span>\n<\/pre>\n\n<p>Disable root login. I don't allow directly logging in as the root user, only through <code>sudo<\/code>.<\/p>\n<pre id=\"AuthorizedKeysFile\" class=\"highlight\">\n<span class=\"Statement\">AuthorizedKeysFile<\/span> \/etc\/ssh\/authorized_keys\/<span class=\"Identifier\">%u<\/span>\n<\/pre>\n\n<p>Usually, authorised keys are located in each user's home directory at: <samp>~\/.ssh\/authorized_keys<\/samp>. This config changes it to be in a system directory. I also restrict the permissions of each file to be only writeable by <samp>root<\/samp>. This prevents an attacker compromising a user from adding his own pubkey to the list of authorised keys, and let me manage the users on the server in a centralised way. For example using a git repository that sends emails to all the admins.<\/p>\n<pre id=\"PasswordAuthentication\" class=\"highlight\">\n<span class=\"Statement\">PasswordAuthentication<\/span> <span class=\"Identifier\">no<\/span>\n<span class=\"Statement\">PermitEmptyPasswords<\/span> <span class=\"Identifier\">no<\/span>\n<span class=\"Statement\">ChallengeResponseAuthentication<\/span> <span class=\"Identifier\">no<\/span>\n<span class=\"Statement\">AuthenticationMethods<\/span> publickey\n<\/pre>\n\n<p>These directives control how one is allowed to authenticate to the server. I'm not interested in challenge-response, so that's off. I also don't trust users with setting secure passwords, so that's disabled. I also don't allow empty passwords, but since I don't allow passwords at all, this line is redundant. <code>AuthenticationMethods<\/code> controls which methods are allowed to be used to connect to the server. This makes sure we only allow public key authentication.<\/p>\n<p>One added benefit to disabling password authentication is that bots don't try to bruteforce passwords on the server.<\/p>\n<pre id=\"AllowGroups\" class=\"highlight\">\n<span class=\"Statement\">AllowGroups<\/span> wheel ssh-user ssh-sftp-user\n<\/pre>\n\n<p>This line only allows users of the <samp>wheel<\/samp> (admins), <samp>ssh-user<\/samp> (any ssh user), and <samp>ssh-sftp-user<\/samp> (sftp only) groups to login. This makes administration easier and thus safer because it essentially makes ssh authentication into a normal UNIX group.<\/p>\n<pre id=\"UsePAM\" class=\"highlight\">\n<span class=\"Statement\">UsePAM<\/span> <span class=\"Identifier\">yes<\/span>\n<\/pre>\n\n<p>Enabling PAM does two major things. The first is handling authentication, though that is disabled because we explicitly disabled password and challenge-response above. The second is handling account checks (e.g. if the account allowed in PAM) and establishing the environment (e.g. print the MOTD), which is why this is turned on.<\/p>\n<pre id=\"X11Forwarding\" class=\"highlight\">\n<span class=\"Statement\">X11Forwarding<\/span> <span class=\"Identifier\">yes<\/span>\n<\/pre>\n\n<p>This allows running X applications on the server with the GUI forwarded to my laptop. I sometimes use this.<\/p>\n<pre id=\"PrintMotd\" class=\"highlight\">\n<span class=\"Statement\">PrintMotd<\/span> <span class=\"Identifier\">no<\/span><span class=\"Comment\"> # pam does that<\/span>\n<\/pre>\n\n<p>As the comment says, PAM already handles sessions and prints the Motd.<\/p>\n<pre id=\"KexAlgorithms\" class=\"highlight\">\n<span class=\"Comment\"># Harden crypto<\/span>\n<span class=\"Statement\">KexAlgorithms<\/span> <span class=\"Identifier\">curve25519-sha256@libssh.org<\/span>,<span class=\"Identifier\">ecdh-sha2-nistp521<\/span>,<span class=\"Identifier\">ecdh-sha2-nistp384<\/span>,<span class=\"Identifier\">ecdh-sha2-nistp256<\/span>,<span class=\"Identifier\">diffie-hellman-group-exchange-sha256<\/span>\n<span class=\"Statement\">Ciphers<\/span> <span class=\"Identifier\">chacha20-poly1305@openssh.com<\/span>,<span class=\"Identifier\">aes256-gcm@openssh.com<\/span>,<span class=\"Identifier\">aes128-gcm@openssh.com<\/span>,<span class=\"Identifier\">aes256-ctr<\/span>,<span class=\"Identifier\">aes192-ctr<\/span>,<span class=\"Identifier\">aes128-ctr<\/span>\n<span class=\"Statement\">MACs<\/span> <span class=\"Identifier\">hmac-sha2-512-etm@openssh.com<\/span>,<span class=\"Identifier\">hmac-sha2-256-etm@openssh.com<\/span>,<span class=\"Identifier\">umac-128-etm@openssh.com<\/span>,hmac-sha<span class=\"Constant\">2<\/span>-<span class=\"Constant\">512<\/span>,hmac-sha<span class=\"Constant\">2<\/span>-<span class=\"Constant\">256<\/span>,<span class=\"Identifier\">umac-128@openssh.com<\/span>\n<\/pre>\n\n<p>These directives restrict the key-exchange algorithm, ciphers and MACs sshd will be allowed to choose. This prevents outdated and insecure clients from connecting. While writing this post, I updated these to follow <a href=\"https:\/\/wiki.mozilla.org\/Security\/Guidelines\/OpenSSH#Modern_.28OpenSSH_6.7.2B.29\">Mozilla guidelines<\/a>, though I already had very similar lists before.<\/p>\n<p><strong>Note:<\/strong> I no longer ssh into my server from Android, but in the past I had issues because the client i was using didn't support recent enough Ciphers, so watch out with this one.<\/p>\n<pre id=\"Subsystem\" class=\"highlight\">\n<span class=\"Statement\">Subsystem<\/span>   sftp    <span class=\"Identifier\">internal-sftp<\/span>\n<\/pre>\n\n<p>This directive configures sshd to use the built-in sftp daemon. This is required for the ChrootDirectory configuration used below.<\/p>\n<pre id=\"Match\" class=\"highlight\">\n<span class=\"Statement\">Match<\/span> <span class=\"Type\">Group<\/span> ssh-sftp-user\n<\/pre>\n\n<p>This directive means that the rest of the file (until the next <code>Match<\/code> directive) will only apply to users of the group ssh-sftp-user. I use it to better lock-down users that should only have sftp (file transfer) access.<\/p>\n<p><strong>Important:<\/strong> the <code>Match<\/code> directive takes effect until the end of the file, the next <code>Match<\/code> or the next <code>Host<\/code>. Do not get confused by the indentation, because it doesn't affect the scope!<\/p>\n<pre class=\"highlight\">\n    <span class=\"Statement\">X11Forwarding<\/span> <span class=\"Identifier\">no<\/span>\n    <span class=\"Statement\">AllowTcpForwarding<\/span> <span class=\"Identifier\">no<\/span>\n    <span class=\"Statement\">PermitTTY<\/span> <span class=\"Identifier\">no<\/span>\n<\/pre>\n\n<p>Disable X11 (discussed above) and TCP forwarding. TCP forwarding let users tunnel traffic through the server, for example using the <code>-D<\/code>, <code>-L<\/code> and <code>-R<\/code> flags to the <code>ssh<\/code> client.<\/p>\n<pre class=\"highlight\">\n    <span class=\"Statement\">ChrootDirectory<\/span> <span class=\"Identifier\">%h<\/span>\n<\/pre>\n\n<p>Lock these users to their home directories for extra safety. This requires the lock directory to be owned by root and not writable by anyone else.\nFor example:\n<samp>drwxr-x---  7 root         backup        4096 Feb  9 11:49 backup<\/samp><\/p>\n<pre class=\"highlight\">\n    <span class=\"Statement\">ForceCommand<\/span> <span class=\"Identifier\">internal-sftp<\/span>\n<\/pre>\n\n<p>Don't allow these users to run any commands other than the internal sftp implementation, again, to further restrict their access.<\/p>","category":[{"@attributes":{"term":"misc"}},{"@attributes":{"term":"explaining configs"}},{"@attributes":{"term":"ssh"}},{"@attributes":{"term":"security"}}]},{"title":"Reducing the Performance Impact of Debug Code in C Libraries","link":{"@attributes":{"href":"https:\/\/stosb.com\/blog\/reducing-the-performance-impact-of-debug-code-in-c-libraries\/","rel":"alternate"}},"published":"2016-10-28T14:00:00+01:00","updated":"2016-10-28T14:00:00+01:00","author":{"name":"Tom Hacohen"},"id":"tag:stosb.com,2016-10-28:\/blog\/reducing-the-performance-impact-of-debug-code-in-c-libraries\/","summary":"<p>I work on the <a href=\"https:\/\/www.enlightenment.org\">EFL<\/a>, a cross-platform graphical toolkit written in C. I recently decided to improve one aspect of our users' (developers using our API) experience by making the EFL provide them with more information and stricter sanity checks when developing and debugging their applications. A key requirement was \u2026<\/p>","content":"<p>I work on the <a href=\"https:\/\/www.enlightenment.org\">EFL<\/a>, a cross-platform graphical toolkit written in C. I recently decided to improve one aspect of our users' (developers using our API) experience by making the EFL provide them with more information and stricter sanity checks when developing and debugging their applications. A key requirement was ease of use. With these requirements, the solution was obvious, unfortunately obvious doesn't always work as well as you expect.<\/p>\n<h1>The obvious solution: an environment variable<\/h1>\n<p>This sounds like a good idea, but it comes with one major, unacceptable, flaw: a significant performance impact. Unfortunately, one of the places where we wanted to collect debug information in was Eo, a hot-path in the EFL. Believe it or not, adding a simple check if debug-mode is enabled was enough to degrade performance. To illustrate, consider the following code:<\/p>\n<p><strong>Note:<\/strong> thanks to <a href=\"https:\/\/kristerw.blogspot.se\/\">Krister Walfridsson<\/a> for pointing out a mistake in the following example.<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"cp\">#include<\/span><span class=\"w\"> <\/span><span class=\"cpf\">&lt;stdio.h&gt;<\/span><span class=\"cp\"><\/span>\n<span class=\"cp\">#include<\/span><span class=\"w\"> <\/span><span class=\"cpf\">&lt;stdlib.h&gt;<\/span><span class=\"cp\"><\/span>\n\n<span class=\"cp\">#define N 100000000 <\/span><span class=\"c1\">\/\/ Adjust for your machine<\/span>\n\n<span class=\"kt\">int<\/span><span class=\"w\"> <\/span><span class=\"nf\">main<\/span><span class=\"p\">(<\/span><span class=\"kt\">int<\/span><span class=\"w\"> <\/span><span class=\"n\">argc<\/span><span class=\"p\">,<\/span><span class=\"w\"> <\/span><span class=\"kt\">char<\/span><span class=\"w\"> <\/span><span class=\"o\">*<\/span><span class=\"n\">argv<\/span><span class=\"p\">[])<\/span><span class=\"w\"><\/span>\n<span class=\"p\">{<\/span><span class=\"w\"><\/span>\n<span class=\"w\">   <\/span><span class=\"kt\">int<\/span><span class=\"w\"> <\/span><span class=\"n\">debug_on<\/span><span class=\"w\"> <\/span><span class=\"o\">=<\/span><span class=\"w\"> <\/span><span class=\"o\">!!<\/span><span class=\"n\">getenv<\/span><span class=\"p\">(<\/span><span class=\"s\">&quot;DEBUG&quot;<\/span><span class=\"p\">);<\/span><span class=\"w\"><\/span>\n<span class=\"w\">   <\/span><span class=\"kt\">unsigned<\/span><span class=\"w\"> <\/span><span class=\"kt\">long<\/span><span class=\"w\"> <\/span><span class=\"n\">sum<\/span><span class=\"w\"> <\/span><span class=\"o\">=<\/span><span class=\"w\"> <\/span><span class=\"mi\">0<\/span><span class=\"p\">;<\/span><span class=\"w\"><\/span>\n<span class=\"w\">   <\/span><span class=\"kt\">unsigned<\/span><span class=\"w\"> <\/span><span class=\"kt\">int<\/span><span class=\"w\"> <\/span><span class=\"n\">i<\/span><span class=\"p\">;<\/span><span class=\"w\"><\/span>\n\n<span class=\"w\">   <\/span><span class=\"k\">for<\/span><span class=\"w\"> <\/span><span class=\"p\">(<\/span><span class=\"n\">i<\/span><span class=\"w\"> <\/span><span class=\"o\">=<\/span><span class=\"w\"> <\/span><span class=\"mi\">0<\/span><span class=\"w\"> <\/span><span class=\"p\">;<\/span><span class=\"w\"> <\/span><span class=\"n\">i<\/span><span class=\"w\"> <\/span><span class=\"o\">&lt;<\/span><span class=\"w\"> <\/span><span class=\"n\">N<\/span><span class=\"w\"> <\/span><span class=\"p\">;<\/span><span class=\"w\"> <\/span><span class=\"n\">i<\/span><span class=\"o\">++<\/span><span class=\"p\">)<\/span><span class=\"w\"><\/span>\n<span class=\"w\">     <\/span><span class=\"p\">{<\/span><span class=\"w\"><\/span>\n<span class=\"w\">        <\/span><span class=\"kt\">unsigned<\/span><span class=\"w\"> <\/span><span class=\"kt\">int<\/span><span class=\"w\"> <\/span><span class=\"n\">j<\/span><span class=\"p\">;<\/span><span class=\"w\"><\/span>\n<span class=\"w\">        <\/span><span class=\"k\">for<\/span><span class=\"w\"> <\/span><span class=\"p\">(<\/span><span class=\"n\">j<\/span><span class=\"w\"> <\/span><span class=\"o\">=<\/span><span class=\"w\"> <\/span><span class=\"mi\">0<\/span><span class=\"w\"> <\/span><span class=\"p\">;<\/span><span class=\"w\"> <\/span><span class=\"n\">j<\/span><span class=\"w\"> <\/span><span class=\"o\">&lt;<\/span><span class=\"w\"> <\/span><span class=\"n\">N<\/span><span class=\"w\"> <\/span><span class=\"p\">;<\/span><span class=\"w\"> <\/span><span class=\"n\">j<\/span><span class=\"o\">++<\/span><span class=\"p\">)<\/span><span class=\"w\"><\/span>\n<span class=\"w\">          <\/span><span class=\"p\">{<\/span><span class=\"w\"><\/span>\n<span class=\"cp\">#ifdef WITH_DEBUG<\/span>\n<span class=\"w\">             <\/span><span class=\"k\">if<\/span><span class=\"w\"> <\/span><span class=\"p\">(<\/span><span class=\"n\">debug_on<\/span><span class=\"p\">)<\/span><span class=\"w\"><\/span>\n<span class=\"w\">                <\/span><span class=\"n\">printf<\/span><span class=\"p\">(<\/span><span class=\"s\">&quot;Debug print.<\/span><span class=\"se\">\\n<\/span><span class=\"s\">&quot;<\/span><span class=\"p\">);<\/span><span class=\"w\"><\/span>\n<span class=\"cp\">#endif<\/span>\n\n<span class=\"w\">             <\/span><span class=\"n\">sum<\/span><span class=\"w\"> <\/span><span class=\"o\">+=<\/span><span class=\"w\"> <\/span><span class=\"n\">i<\/span><span class=\"p\">;<\/span><span class=\"w\"><\/span>\n<span class=\"w\">          <\/span><span class=\"p\">}<\/span><span class=\"w\"><\/span>\n<span class=\"w\">     <\/span><span class=\"p\">}<\/span><span class=\"w\"><\/span>\n<span class=\"w\">   <\/span><span class=\"n\">printf<\/span><span class=\"p\">(<\/span><span class=\"s\">&quot;Sum: %lu<\/span><span class=\"se\">\\n<\/span><span class=\"s\">&quot;<\/span><span class=\"p\">,<\/span><span class=\"w\"> <\/span><span class=\"n\">sum<\/span><span class=\"p\">);<\/span><span class=\"w\"><\/span>\n\n<span class=\"w\">   <\/span><span class=\"k\">return<\/span><span class=\"w\"> <\/span><span class=\"mi\">0<\/span><span class=\"p\">;<\/span><span class=\"w\"><\/span>\n<span class=\"p\">}<\/span><span class=\"w\"><\/span>\n<\/code><\/pre><\/div>\n\n<p>Which when executed would result in:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span><span class=\"c1\"># Debug disabled<\/span>\n<span class=\"gp\">$ <\/span>gcc -O3 sum.c -o sum\n<span class=\"gp\">$ <\/span><span class=\"nb\">time<\/span> .\/sum\n<span class=\"go\">Sum: 996882102603448320<\/span>\n<span class=\"go\">.\/sum  0.18s user 0.00s system 95% cpu 0.186 total<\/span>\n\n<span class=\"gp\">$ <\/span><span class=\"c1\"># Debug enabled<\/span>\n<span class=\"gp\">$ <\/span>gcc -O3 -DWITH_DEBUG<span class=\"o\">=<\/span><span class=\"m\">1<\/span> sum.c -o sum\n<span class=\"gp\">$ <\/span><span class=\"nb\">time<\/span> .\/sum\n<span class=\"go\">Sum: 996882102603448320<\/span>\n<span class=\"go\">.\/sum 0.26s user 0.00s system 98% cpu 0.267 total<\/span>\n<\/code><\/pre><\/div>\n\n<p>This is almost a 50% performance penalty to just have it compiled in, not even enabled! While this is an extreme example, code-paths with a similar impact do exist in our codebase.<\/p>\n<p>This performance penalty was unacceptable, so I went back to the drawing board.<\/p>\n<h1>An alternative solution: a compilation option when compiling the library<\/h1>\n<p>This idea is to add an option to compile the library in debug mode, so whenever it is used, it will always collect the data. In the EFL source code we would have something like:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"n\">EAPI<\/span><span class=\"w\"> <\/span><span class=\"n\">Eo<\/span><span class=\"w\"> <\/span><span class=\"o\">*<\/span><span class=\"n\">efl_ref<\/span><span class=\"p\">(<\/span><span class=\"n\">Eo<\/span><span class=\"w\"> <\/span><span class=\"o\">*<\/span><span class=\"n\">obj<\/span><span class=\"p\">)<\/span><span class=\"w\"><\/span>\n<span class=\"p\">{<\/span><span class=\"w\"><\/span>\n<span class=\"w\">   <\/span><span class=\"c1\">\/\/ snip ...<\/span>\n<span class=\"cp\">#ifdef EFL_DEBUG<\/span>\n<span class=\"w\">   <\/span><span class=\"n\">collect_debug_info<\/span><span class=\"p\">();<\/span><span class=\"w\"><\/span>\n<span class=\"cp\">#endif<\/span>\n<span class=\"w\">   <\/span><span class=\"c1\">\/\/ snip ...<\/span>\n<span class=\"p\">}<\/span><span class=\"w\"><\/span>\n<\/code><\/pre><\/div>\n\n<p>Users of the API will have to recompile the library with debugging on and use it instead of the distro provided version. This introduces a few issues, some of which are solvable, some are not. The main remaining issue is that the user would have to download and compile the library. A big enough hurdle to render this solution almost useless.<\/p>\n<p>We had this implemented for quite some time because it was good enough for the most of us, but recently I decided to finally implement the better user-friendly solution I had in mind.<\/p>\n<h1>A better solution: automatically providing both versions<\/h1>\n<p>Eo is small, so compiling it twice wouldn't have a significant impact on neither the build time nor the deliverable size. I therefore modified our build-system to build Eo twice, once as <code>libeo.so<\/code> and once as <code>libeo_dbg.so<\/code>: the first version compiled as normal, and the second with <code>EFL_DEBUG<\/code> set.<\/p>\n<p>This was already a better solution. It meant users of our API could just link against the new library when compiling their applications to use the debug version, and when they are ready to release, link against the non-debug one. This, while much better, still requires some advanced know-how from the users that I wanted to eliminate.<\/p>\n<h2>An even better solution: using DLL injection to ease usage<\/h2>\n<p>I wanted to create an easy way for users to toggle between the two on runtime, without having to relink their applications. I then realised I could use <code>LD_PRELOAD<\/code> (<a href=\"https:\/\/en.wikipedia.org\/wiki\/DLL_injection#Approaches_on_Unix-like_systems\">more info<\/a>) in order to force the debug version of the library to be loaded first. Problem solved.<\/p>\n<p>I therefore wrote a small script to ease usage:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"ch\">#!\/bin\/sh<\/span>\n<span class=\"c1\"># The variables surrounded by @ are replaced by autotools<\/span>\n<span class=\"nv\">prefix<\/span><span class=\"o\">=<\/span><span class=\"s2\">&quot;@prefix@&quot;<\/span>\n<span class=\"nv\">exec_prefix<\/span><span class=\"o\">=<\/span><span class=\"s2\">&quot;@exec_prefix@&quot;<\/span>\n<span class=\"k\">if<\/span> <span class=\"o\">[<\/span> <span class=\"nv\">$#<\/span> -lt <span class=\"m\">1<\/span> <span class=\"o\">]<\/span>\n<span class=\"k\">then<\/span>\n   <span class=\"nb\">echo<\/span> <span class=\"s2\">&quot;Usage: <\/span><span class=\"nv\">$0<\/span><span class=\"s2\"> &lt;executable&gt; [executable parameters]&quot;<\/span>\n<span class=\"k\">else<\/span>\n   <span class=\"nv\">LD_PRELOAD<\/span><span class=\"o\">=<\/span><span class=\"s2\">&quot;@libdir@\/libeo_dbg.so&quot;<\/span> <span class=\"s2\">&quot;<\/span><span class=\"nv\">$@<\/span><span class=\"s2\">&quot;<\/span>\n<span class=\"k\">fi<\/span>\n<\/code><\/pre><\/div>\n\n<p>Usage is now as simple as wrapping execution with the script above:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span><span class=\"c1\"># Debug off<\/span>\n<span class=\"gp\">$ <\/span>.\/myapp param1 param2\n\n<span class=\"gp\">$ <\/span><span class=\"c1\"># Debug on<\/span>\n<span class=\"gp\">$ <\/span>eo_debug .\/myapp param1 param2\n<\/code><\/pre><\/div>\n\n<p>Mission accomplished!<\/p>\n<p><strong>Note:<\/strong> The script and <code>libeo_dbg.so<\/code> are automatically built and installed with the rest of the EFL. This means that they will be available for everyone installing the <samp>efl<\/samp> package, or in some distributions the <samp>efl-dev<\/samp> package.<\/p>\n<h1>Conclusion<\/h1>\n<p>We now have an easy-to-use tool for users of our API to debug and check correctness of their applications. As a side effect, we also earned a useful tool for end users (users using applications written with the EFL) for providing better information when reporting bugs. All of this without any impact on normal execution.<\/p>","category":[{"@attributes":{"term":"misc"}},{"@attributes":{"term":"C"}},{"@attributes":{"term":"programming"}},{"@attributes":{"term":"low-level"}},{"@attributes":{"term":"debug"}}]},{"title":"Hunting Down Dirty Memory Pages","link":{"@attributes":{"href":"https:\/\/stosb.com\/blog\/hunting-down-dirty-memory-pages\/","rel":"alternate"}},"published":"2016-08-24T14:00:00+01:00","updated":"2016-08-24T14:00:00+01:00","author":{"name":"Tom Hacohen"},"id":"tag:stosb.com,2016-08-24:\/blog\/hunting-down-dirty-memory-pages\/","summary":"<p>Today's post is about an issue you have probably never encountered or even considered.\nIt is only relevant for shared libraries developers, and even then, not always.\nHowever, I think it is beneficial for everyone to be familiar with how\nthings work at a lower level, so I decided to \u2026<\/p>","content":"<p>Today's post is about an issue you have probably never encountered or even considered.\nIt is only relevant for shared libraries developers, and even then, not always.\nHowever, I think it is beneficial for everyone to be familiar with how\nthings work at a lower level, so I decided to write this post.<\/p>\n<p>A few weeks ago I got a report about an increase private dirty pages from our\nlibraries that essentially caused increased memory consumption for every application\nlinking to the <a href=\"https:\/\/www.enlightenment.org\">EFL<\/a>. The main culprit was the\nobject system (Eo), which I maintain, so I decided to take a look.<\/p>\n<p>As the first step I manually reviewed the code. This led me to a mistake in related\ncode which I eventually fixed. My fixes improved the situation a bit, but\nthe main issue was still there.  So I started investigating...<\/p>\n<p><strong>Note<\/strong>: unless specifically mentioned otherwise, all of this post assumes Linux on\nIntel hardware, though while the details may vary, the concepts should apply\nalmost everywhere.<\/p>\n<h1>Introduction to Memory Pages in Linux<\/h1>\n<p>First, if you are not familiar with the concept, read about the topic on\n<a href=\"https:\/\/en.wikipedia.org\/wiki\/Page_%28computer_memory%29\">Wikipedia<\/a>.\nPages are essentially blocks of virtual memory, and are the smallest unit of data\nbeing managed by the OS, in our case Linux. The page size is usually 4KiB, and\nis the case here.<\/p>\n<p>When an executable is being compiled, all of the information in it\nis being mapped to different sections depending on usage. For example with <code>clang<\/code> (may change based on compiler):<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"k\">static<\/span><span class=\"w\"> <\/span><span class=\"k\">const<\/span><span class=\"w\"> <\/span><span class=\"kt\">int<\/span><span class=\"w\"> <\/span><span class=\"n\">a<\/span><span class=\"w\"> <\/span><span class=\"o\">=<\/span><span class=\"w\"> <\/span><span class=\"mi\">5<\/span><span class=\"p\">;<\/span><span class=\"w\"><\/span>\n<\/code><\/pre><\/div>\n\n<p>will be mapped to <samp>.rodata<\/samp>, that is \"read-only data\". Another example\nis executable code (actual instructions) that would be mapped to <samp>.text<\/samp>. Then the\nlinker decides how to map all of this into actual memory, and thus, into pages.\nPages have permissions associated to them: read (R), write (W) and execute (X).\nFor example, for security reasons, the stack is marked as RW, because you want\nto be able to read and write to the stack, but not executable in order to protect from\na certain class of attacks. The actual executable code, is marked as RX, that is, you\ncan read it, and execute it, but not modify it. A nice feature of non-writeable\npages is that they never change (duh...), so the OS can reuse them and thus save\nmemory. So for example, if your executable size is 2MiB, it'll be loaded into the\nmemory once, it won't be loaded for every instance of the application. The OS is\nsmart enough to share these pages.<\/p>\n<p>As a side note, Linux also implements Copy-on-Write for RW pages, so even if a page is RW, it\nmay be shared across different instances assuming the data hasn't been written to.\nPages that can be shared are called <em>clean<\/em>, and ones that have been written to\nare called <em>dirty<\/em>.<\/p>\n<p>There is more to be said about pages, but we've covered all we need in order to\ninvestigate the issue, so we will stop here.<\/p>\n<h1>The Issue Reported<\/h1>\n<p>Now that we know a bit more about pages we can more intelligently discuss the issue\nreported. The problem was that the EFL in general, and heavy users of Eo in particular,\nall of a sudden had a lot of private dirty pages. This means, a lot of pages of memory\nthat are mapped from the library itself (in the executable, not allocated on runtime) that are\nbeing written to and thus can't be shared and have to be duplicated for each running\nprocess; a big issue for heavily used libraries.<\/p>\n<p>RW pages exist for a reason, so it could just be that these were legitimate usages,\nthough judging by the amount of pages, this seemed unlikely. The first step was\nto find what is mapped to these pages, so I started there.<\/p>\n<h1>Finding the Memory Users<\/h1>\n<p>Unfortunately, while <code>nm<\/code> is a very useful command to mapping symbols to memory\nregions, so I know which symbols are mapped to RW pages (most likely); it doesn't\n(and can't) indicate which symbols map to dirty pages. Even more unfortunate is\nthat I am not aware of any tool that provides that information (please let me\nknow if you know of one!). I was just about to write one, when I saw that all of\nthe relevant RW pages in my test case were dirty, so any memory in those would\nbe relevant.<\/p>\n<div class=\"alert alert-info\" role=\"alert\">\n<p><strong>Note:<\/strong> in order to check which variables got mapped to RW pages I used <code>pmap<\/code>.\nUsing this tool I was able to see the address range for each page, and using\nsome debug output I was able to get the addresses of the symbols in question\nand so was able to know which was stored in RW pages. Using <code>pmap<\/code> is very easy;\nmore on that in the next section.<\/p>\n<\/div>\n<p>I already knew which structures were the largest in Eo, so I decided to guess and\nsee if they were mapped to RW pages or RO. My guess was spot on, and I found a\nfew symbols that should be RO, but were actually RW. For example:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"w\"> <\/span><span class=\"k\">static<\/span><span class=\"w\"> <\/span><span class=\"k\">const<\/span><span class=\"w\"> <\/span><span class=\"n\">Efl_Event_Description<\/span><span class=\"w\"> <\/span><span class=\"o\">*<\/span><span class=\"n\">_event_desc<\/span><span class=\"p\">[]<\/span><span class=\"w\"> <\/span><span class=\"o\">=<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\"><\/span>\n<span class=\"w\">      <\/span><span class=\"c1\">\/\/ SNIP ...<\/span>\n<span class=\"w\"> <\/span><span class=\"p\">};<\/span><span class=\"w\"><\/span>\n<\/code><\/pre><\/div>\n\n<p>This is a common mistake due to the confusing syntax C uses for <code>const<\/code>. This is\nan array of pointers to <code>const Efl_Event_Description<\/code>. This may look correct at\nfirst glance, until you realise the array itself is not constant. It should be:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"w\"> <\/span><span class=\"k\">static<\/span><span class=\"w\"> <\/span><span class=\"k\">const<\/span><span class=\"w\"> <\/span><span class=\"n\">Efl_Event_Description<\/span><span class=\"w\"> <\/span><span class=\"o\">*<\/span><span class=\"w\"> <\/span><span class=\"k\">const<\/span><span class=\"w\"> <\/span><span class=\"n\">_event_desc<\/span><span class=\"p\">[]<\/span><span class=\"w\"> <\/span><span class=\"o\">=<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\"><\/span>\n<span class=\"w\">      <\/span><span class=\"c1\">\/\/ SNIP ...<\/span>\n<span class=\"w\"> <\/span><span class=\"p\">};<\/span><span class=\"w\"><\/span>\n<\/code><\/pre><\/div>\n\n<p>This change saved us a few pages in the more event heavy areas, which is a first\nstep, but the problem was still there, so the search recommenced.<\/p>\n<p>I then stumbled upon<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"k\">static<\/span><span class=\"w\"> <\/span><span class=\"k\">const<\/span><span class=\"w\"> <\/span><span class=\"n\">Efl_Class_Description<\/span><span class=\"w\"> <\/span><span class=\"n\">_class_desc<\/span><span class=\"w\"> <\/span><span class=\"o\">=<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\"><\/span>\n<span class=\"w\">    <\/span><span class=\"c1\">\/\/ SNIP ...<\/span>\n<span class=\"p\">};<\/span><span class=\"w\"><\/span>\n<\/code><\/pre><\/div>\n\n<p>This looks innocent. The <code>Efl_Class_Description<\/code> type is a <code>struct<\/code>, and <code>const<\/code>\nwas correctly applied. This should have definitely been RO, but for some reason\nit was put in a RW page. Seeing this, and other similar structures, I knew I found\nwhat I was looking for, now I just needed to figure out why it was happening.<\/p>\n<p>After thinking about it for a bit, and considering a few different ideas,\nI suspected it was related to the fact that while these structures were constant,\nsome of the fields were referring to other symbols, and in some cases, due to\nrelocation, the linker would have to figure out the address at runtime, and thus\nwon't be able to mark the pages as RO. This could be easily checked with <code>nm<\/code>,\nthough I haven't thought about it at the time, so I went on investigating by\nother means. I ended up writing a small contained example, so I know if I was\nright or not.<\/p>\n<p>I ran my example in both <code>gcc<\/code> and <code>clang<\/code>. Unfortunately <code>gcc<\/code> gave me some less than optimal\nresults, so I will use <code>clang<\/code> in my examples.<\/p>\n<h1>Checking my Hypothesis<\/h1>\n<p>In order to check my hypothesis I wrote a small program (<samp>issue.c<\/samp>):<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"cp\">#include<\/span><span class=\"w\"> <\/span><span class=\"cpf\">&lt;stdio.h&gt;<\/span><span class=\"cp\"><\/span>\n<span class=\"cp\">#include<\/span><span class=\"w\"> <\/span><span class=\"cpf\">&lt;string.h&gt;<\/span><span class=\"cp\"><\/span>\n<span class=\"cp\">#include<\/span><span class=\"w\"> <\/span><span class=\"cpf\">&lt;unistd.h&gt;<\/span><span class=\"cp\"><\/span>\n\n<span class=\"cp\">#define PAGE_SIZE 4096<\/span>\n<span class=\"cp\">#define ALLOC_SIZE (PAGE_SIZE * 1000)<\/span>\n\n<span class=\"k\">typedef<\/span><span class=\"w\"> <\/span><span class=\"k\">struct<\/span><span class=\"w\"><\/span>\n<span class=\"p\">{<\/span><span class=\"w\"><\/span>\n<span class=\"w\">   <\/span><span class=\"k\">const<\/span><span class=\"w\"> <\/span><span class=\"kt\">void<\/span><span class=\"w\"> <\/span><span class=\"o\">*<\/span><span class=\"n\">invalidater<\/span><span class=\"p\">;<\/span><span class=\"w\"><\/span>\n<span class=\"w\">   <\/span><span class=\"k\">const<\/span><span class=\"w\"> <\/span><span class=\"kt\">char<\/span><span class=\"w\"> <\/span><span class=\"n\">data<\/span><span class=\"p\">[<\/span><span class=\"n\">ALLOC_SIZE<\/span><span class=\"p\">];<\/span><span class=\"w\"><\/span>\n<span class=\"p\">}<\/span><span class=\"w\"> <\/span><span class=\"n\">Invalid<\/span><span class=\"p\">;<\/span><span class=\"w\"><\/span>\n\n<span class=\"k\">static<\/span><span class=\"w\"> <\/span><span class=\"k\">const<\/span><span class=\"w\"> <\/span><span class=\"kt\">char<\/span><span class=\"w\"> <\/span><span class=\"n\">ro<\/span><span class=\"p\">[<\/span><span class=\"n\">ALLOC_SIZE<\/span><span class=\"p\">];<\/span><span class=\"w\"><\/span>\n<span class=\"k\">static<\/span><span class=\"w\"> <\/span><span class=\"k\">const<\/span><span class=\"w\"> <\/span><span class=\"n\">Invalid<\/span><span class=\"w\"> <\/span><span class=\"n\">rw<\/span><span class=\"w\"> <\/span><span class=\"o\">=<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\"> <\/span><span class=\"nb\">NULL<\/span><span class=\"p\">,<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\"> <\/span><span class=\"mi\">0<\/span><span class=\"w\"> <\/span><span class=\"p\">}};<\/span><span class=\"w\"><\/span>\n\n<span class=\"kt\">int<\/span><span class=\"w\"> <\/span><span class=\"nf\">main<\/span><span class=\"p\">()<\/span><span class=\"w\"><\/span>\n<span class=\"p\">{<\/span><span class=\"w\"><\/span>\n<span class=\"w\">   <\/span><span class=\"n\">printf<\/span><span class=\"p\">(<\/span><span class=\"s\">&quot;%zd<\/span><span class=\"se\">\\n<\/span><span class=\"s\">&quot;<\/span><span class=\"p\">,<\/span><span class=\"w\"> <\/span><span class=\"p\">(<\/span><span class=\"kt\">size_t<\/span><span class=\"p\">)<\/span><span class=\"w\"> <\/span><span class=\"n\">getpid<\/span><span class=\"p\">());<\/span><span class=\"w\"><\/span>\n<span class=\"w\">   <\/span><span class=\"n\">printf<\/span><span class=\"p\">(<\/span><span class=\"s\">&quot;%p %p<\/span><span class=\"se\">\\n<\/span><span class=\"s\">&quot;<\/span><span class=\"p\">,<\/span><span class=\"w\"> <\/span><span class=\"n\">ro<\/span><span class=\"p\">,<\/span><span class=\"w\"> <\/span><span class=\"o\">&amp;<\/span><span class=\"n\">rw<\/span><span class=\"p\">);<\/span><span class=\"w\"> <\/span><span class=\"c1\">\/\/ So they are not optimised out<\/span>\n<span class=\"w\">   <\/span><span class=\"n\">scanf<\/span><span class=\"p\">(<\/span><span class=\"s\">&quot;<\/span><span class=\"se\">\\n<\/span><span class=\"s\">&quot;<\/span><span class=\"p\">);<\/span><span class=\"w\"> <\/span><span class=\"c1\">\/\/ Keep the program running<\/span>\n<span class=\"w\">   <\/span><span class=\"k\">return<\/span><span class=\"w\"> <\/span><span class=\"mi\">0<\/span><span class=\"p\">;<\/span><span class=\"w\"><\/span>\n<span class=\"p\">}<\/span><span class=\"w\"><\/span>\n<\/code><\/pre><\/div>\n\n<p>This program attempts to allocate two variables:<\/p>\n<ul>\n<li><code>ro<\/code>: 1000 pages of read only memory.<\/li>\n<li><code>rw<\/code>: 1000 pages (and one pointer) of read only memory that I suspected was going to be RW.<\/li>\n<\/ul>\n<p>Upon running it prints its <samp>PID<\/samp> and then waits.<\/p>\n<p>Now I can run it and inspect exactly what's going on. For that I will use <code>pmap<\/code>\n(and redact some of the non-relevant output).<\/p>\n<p>Let's compile and run our program:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span>clang issue.c\n<span class=\"gp\">$ <\/span>.\/a.out\n<span class=\"go\">11835<\/span>\n<span class=\"go\">0x4006a0 0x7e86a0<\/span>\n<\/code><\/pre><\/div>\n\n<p>And then in another terminal:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span>pmap <span class=\"m\">11835<\/span>\n<span class=\"go\">11835:   .\/a.out<\/span>\n<span class=\"go\">0000000000400000   8004K r-x-- a.out<\/span>\n<span class=\"go\">0000000000dd0000      4K rw--- a.out<\/span>\n<\/code><\/pre><\/div>\n\n<p>As you can see, both variables have been mapped to RO pages (the first). This is\nwhat we expected (which wasn't the case with GCC), because we don't rely on anything\nthat we don't know on compile time. This was just a test to see everything works.<\/p>\n<p>Now we are going to change the program to check my hypothesis. We will change the\n<code>NULL<\/code> in the declaration of <code>rw<\/code> to some symbol which may be relocated, for\nexample <code>strlen<\/code>, and then compile and run again:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span>clang issue.c\n<span class=\"gp\">$ <\/span>.\/a.out\n<span class=\"go\">11941<\/span>\n<span class=\"go\">0x4006e0 0x7e86e0<\/span>\n<\/code><\/pre><\/div>\n\n<p>And then in another terminal:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span>pmap <span class=\"m\">11941<\/span>\n<span class=\"go\">11941:   .\/a.out<\/span>\n<span class=\"go\">0000000000400000   8004K r-x-- a.out<\/span>\n<span class=\"go\">0000000000dd0000      4K rw--- a.out<\/span>\n<\/code><\/pre><\/div>\n\n<p>And... It still works. At this point I started to question myself, maybe I was\nwrong and something was going on.<\/p>\n<p>Then I realised there is still one thing that is different between my test case\nand libraries that exhibit the issue that may be related. They are libraries,\nand thus have position independent code, so I tested once more, this time with\nPIC enabled:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span>clang issue.c -fPIC\n<span class=\"gp\">$ <\/span>.\/a.out\n<span class=\"go\">12002<\/span>\n<span class=\"go\">0x4006d0 0x9e8818<\/span>\n<\/code><\/pre><\/div>\n\n<p>And then in another terminal:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span>pmap <span class=\"m\">12002<\/span>\n<span class=\"go\">12002:   .\/a.out<\/span>\n<span class=\"go\">0000000000400000   4004K r-x-- a.out<\/span>\n<span class=\"go\">00000000009e8000   4004K rw--- a.out<\/span>\n<\/code><\/pre><\/div>\n\n<p>Voila! We managed to replicate the issue.<\/p>\n<h2>Verifying with <code>nm<\/code><\/h2>\n<p>As I mentioned before, this would have been easy to verify with <code>nm<\/code>, so\nI'll also show that for completeness. Though even with <code>nm<\/code>, I would have needed\nto enable PIC to trigger the issue.<\/p>\n<p>Relevant <code>nm<\/code> output for the RO (issue not present) case:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span>nm -f sysv .\/a.out\n<span class=\"go\">rw |07e86e0| r | OBJECT|03e8008| |.rodata<\/span>\n<\/code><\/pre><\/div>\n\n<p>As you can see, <code>rw<\/code> is put into the <samp>.rodata<\/samp> section, that is read-only\ndata.<\/p>\n<p>Relevant <code>nm<\/code> output for the RW (issue present) case:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span>nm -f sysv .\/a.out\n<span class=\"go\">rw |09e8818| d | OBJECT|03e8008| |.data.rel.ro<\/span>\n<\/code><\/pre><\/div>\n\n<p>Here, <code>rw<\/code> is put into the <samp>.data.rel.ro<\/samp> section, which is a section\nthat is read-only <em>after<\/em> relocation, which means, <em>not<\/em> read-only.<\/p>\n<h2>My Pages are RO and not RW<\/h2>\n<p>I got reports from two different people (thanks Daniel Hirt and <a href=\"https:\/\/twitter.com\/markmossberg\">Mark Mossberg<\/a>!) that their <code>pmap<\/code>\noutput looked something like this:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span>pmap <span class=\"m\">10214<\/span>\n<span class=\"go\">10214:   .\/a.out<\/span>\n<span class=\"go\">0000000000400000   4004K r-x-- a.out<\/span>\n<span class=\"go\">00000000009e8000   4004K r---- a.out<\/span>\n<span class=\"go\">0000000000dd1000      4K rw--- a.out<\/span>\n<\/code><\/pre><\/div>\n\n<p>The reason for that is most likely linker differences.<\/p>\n<p>One way to verify this is indeed the case:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span>strace .\/a.out\n<span class=\"go\">... SNIP ...<\/span>\n<span class=\"go\">mprotect(0x9e8000, 4100096, PROT_READ)  = 0<\/span>\n<span class=\"go\">... SNIP ...<\/span>\n<\/code><\/pre><\/div>\n\n<p>As you can see, the program is calling <code>mprotect<\/code> to change the page (look at the\naddress) to be RO. If you read the previous section about <code>nm<\/code>, you probably saw\n<code>rw<\/code> was put into the \"read-only after relocation\" section, which means the linker\nwas allowed and encouraged to mark the pages read-only after it has finished the\nrelocation updates.<\/p>\n<p>As mentioned above, I took a short-cut checking for RW pages instead of private\ndirty pages because I had complete overlap between the two. This short-cut may\nnot work for your case, though the <code>nm<\/code> output should still give you the information\nyou need.<\/p>\n<h1>Solving the Issue<\/h1>\n<p>Two solutions come to mind. Either separate the \"truly constant\" values from the\nrelocatable values. So for example, if we had a <code>struct<\/code> like:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"k\">struct<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\"><\/span>\n<span class=\"w\">     <\/span><span class=\"kt\">int<\/span><span class=\"w\"> <\/span><span class=\"n\">ro<\/span><span class=\"p\">;<\/span><span class=\"w\"><\/span>\n<span class=\"w\">     <\/span><span class=\"kt\">void<\/span><span class=\"w\"> <\/span><span class=\"o\">*<\/span><span class=\"n\">symbol<\/span><span class=\"p\">;<\/span><span class=\"w\"><\/span>\n<span class=\"p\">};<\/span><span class=\"w\"><\/span>\n<\/code><\/pre><\/div>\n\n<p>Split it to two separate <code>struct<\/code>s.<\/p>\n<p>Or alternatively, reconsider parts of the design, maybe using the pointers in the\n<code>struct<\/code> is not even needed and it's enough to pass them to a function.\nThis way the structures won't be mapped to RW memory, but would be temporarily stored\non the stack before the function invocation, reducing the memory usage.<\/p>\n<p>I have already reduced some memory in Eo users by using the second method. I will\nsoon complement that with the first method to reduce it even further. Preliminary\ntests show significant reduction in memory usage, so a big win.<\/p>\n<h1>Lessons Learned<\/h1>\n<p>While I knew the theory behind it, I was surprised to see how code I assumed would\nbe mapped to RO pages ended up in RW pages that get dirty immediately.\nMore specifically, that any structure that has a pointer to anything, even to a\nconstant string, like:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"k\">static<\/span><span class=\"w\"> <\/span><span class=\"k\">const<\/span><span class=\"w\"> <\/span><span class=\"kt\">char<\/span><span class=\"w\"> <\/span><span class=\"o\">*<\/span><span class=\"w\"> <\/span><span class=\"k\">const<\/span><span class=\"w\"> <\/span><span class=\"n\">rw<\/span><span class=\"w\"> <\/span><span class=\"o\">=<\/span><span class=\"w\"> <\/span><span class=\"s\">&quot;test&quot;<\/span><span class=\"p\">;<\/span><span class=\"w\"><\/span>\n<\/code><\/pre><\/div>\n\n<p>would end up in RW pages. Review your libraries and make sure you are not wasting\nmemory, and remember that heap memory is not the only memory that can be wasted.<\/p>","category":[{"@attributes":{"term":"misc"}},{"@attributes":{"term":"low-level"}},{"@attributes":{"term":"debug"}},{"@attributes":{"term":"memory"}}]},{"title":"Using an External Server and a VPN to Escape NATs","link":{"@attributes":{"href":"https:\/\/stosb.com\/blog\/using-an-external-server-and-a-vpn-to-escape-nats\/","rel":"alternate"}},"published":"2016-07-20T13:00:00+01:00","updated":"2016-07-20T13:00:00+01:00","author":{"name":"Tom Hacohen"},"id":"tag:stosb.com,2016-07-20:\/blog\/using-an-external-server-and-a-vpn-to-escape-nats\/","summary":"<p>I have recently moved to a new flat and I love it, though unfortunately, not all is perfect. One would expect central London (literally 500m away from the actual geographical centre) would have the best internet connection London has to offer. Well, one would be wrong; I am no longer \u2026<\/p>","content":"<p>I have recently moved to a new flat and I love it, though unfortunately, not all is perfect. One would expect central London (literally 500m away from the actual geographical centre) would have the best internet connection London has to offer. Well, one would be wrong; I am no longer able to get anything better than lousy ADSL2+, and this amazing offering comes at a high price point, a long contract and a month's wait for the installation.<\/p>\n<p>This has led me to choose a 4G internet provider. The connection is mostly better than what I would have expected to get with any of the landline providers, is much cheaper and I had it up and running less than 24hrs after I joined.<\/p>\n<p>There is a problem though: they use a carrier-grade NAT which means I was no longer able to access my home server from outside my home network. Luckily I have a VPS that is not behind a NAT, so a solution was obvious, tunnel everything through there.<\/p>\n<h1>The solution<\/h1>\n<p>One easy solution to my problem would be to just run a VPN, connect my home server to it, and then connect to the VPN every time I want to access my home server. This solution works, but it is very annoying to have to connect to the VPN every time, and even more annoying to have to give access to my VPN to anyone who needs access to my private Git server.<\/p>\n<p>This made me choose a slightly more complex solution that solves the above issues: port forwarding some ports from another member of the VPN that has a unique external IP to my home server.<\/p>\n<h1>Setting up OpenVPN<\/h1>\n<p>From now on we will call the externally available server EXT and the one we would like to expose: HOME.<\/p>\n<p>We now need to setup an OpenVPN server on EXT, however, setting up OpenVPN is beyond the scope of this post. I recommend following the <a href=\"https:\/\/wiki.archlinux.org\/index.php\/OpenVPN#The_server_configuration_file\">Arch Linux guide<\/a>, and the <a href=\"http:\/\/openvpn.net\/index.php\/open-source\/documentation\">OpenVPN official documentation<\/a>.<\/p>\n<p>With that being said, there are a few important OpenVPN configurations you should make sure to have in your OpenVPN server (EXT):<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"c1\"># ... SNIP ...<\/span>\n<span class=\"c1\"># Allow client to client communication<\/span>\nclient-to-client\n<span class=\"c1\"># Send pings to keep connection alive<\/span>\nkeepalive <span class=\"m\">15<\/span> <span class=\"m\">60<\/span>\nping-timer-rem\n<span class=\"c1\"># Persistent ip addresses<\/span>\nifconfig-pool-persist \/etc\/openvpn\/ipp\n<\/code><\/pre><\/div>\n\n<p>At this point you should make sure you can connect to the VPN and access services running on HOME from EXT.<\/p>\n<h1>Setting up port forwarding<\/h1>\n<p>The first thing to do when setting up port forwarding, is enabling it in the kernel (on EXT). Since we sadly still live in an IPv4 world (this is why we have CGNAT in the first place), we will only deal with the IPv4 case.<\/p>\n<p>As root:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\"># <\/span><span class=\"c1\"># Enable on the running system (temporary)<\/span>\n<span class=\"gp\"># <\/span>sysctl -w net.ipv4.ip_forward<span class=\"o\">=<\/span><span class=\"m\">1<\/span>\n<span class=\"gp\"># <\/span><span class=\"c1\"># Enable on boot (depends on your distribution)<\/span>\n<span class=\"gp\"># <\/span><span class=\"nb\">echo<\/span> <span class=\"s2\">&quot;net.ipv4.ip_forward = 1&quot;<\/span> &gt;&gt; \/etc\/sysctl.d\/51-ip.conf\n<\/code><\/pre><\/div>\n\n<p>Now we just need to tell <code>iptables<\/code> which ports we would like to forward, and we should be done. <strong>Keep in mind:<\/strong> like <code>sysctl<\/code>, <code>iptables<\/code> commands only last until the next boot, so do not forget to make them persistent in whatever way is recommended for your distribution.<\/p>\n<p>Now we need to decide which ports you would like to forward. For the sake of the example, we will forward TCP port 2222 for <code>ssh<\/code> and UDP ports 61001-62000 for <code>mosh<\/code>.<\/p>\n<p>First we need to check HOME's address inside the VPN. This depends on your VPN setup, but it usually should be obvious from the <code>ip<\/code> command.<\/p>\n<p>As root, assuming HOME's ip address is 192.168.87.10:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\"># <\/span><span class=\"c1\"># Allow IP forwarding<\/span>\n<span class=\"gp\"># <\/span>iptables -A POSTROUTING -j MASQUERADE\n<span class=\"gp\"># <\/span><span class=\"c1\"># Forward the relevant ports to HOME<\/span>\n<span class=\"gp\"># <\/span>iptables -A PREROUTING -p tcp --dport <span class=\"m\">2222<\/span> -j DNAT --to-destination <span class=\"m\">192<\/span>.168.87.10:22\n<span class=\"gp\"># <\/span>iptables -A PREROUTING -p udp --dport <span class=\"m\">61001<\/span> -j DNAT --to-destination <span class=\"m\">192<\/span>.168.87.10:61001-62000\n\n<span class=\"gp\"># <\/span><span class=\"c1\"># Enable connections to and from the machine (in case restricted)<\/span>\n<span class=\"gp\"># <\/span>iptables -A FORWARD -d <span class=\"m\">192<\/span>.168.87.10 -p tcp --dport <span class=\"m\">22<\/span> -j ACCEPT\n<span class=\"gp\"># <\/span>iptables -A FORWARD -s <span class=\"m\">192<\/span>.168.87.10 -p tcp --sport <span class=\"m\">22<\/span> -j ACCEPT\n<span class=\"gp\"># <\/span>iptables -A FORWARD -s <span class=\"m\">192<\/span>.168.87.10 -p udp -m state --state RELATED,ESTABLISHED --sport <span class=\"m\">61001<\/span>:62000 -j ACCEPT\n<span class=\"gp\"># <\/span>iptables -A FORWARD -d <span class=\"m\">192<\/span>.168.87.10 -p udp --dport <span class=\"m\">61001<\/span>:62000 -j ACCEPT\n<\/code><\/pre><\/div>\n\n<p><strong>Another reminder:<\/strong> make sure to make the <code>iptables<\/code> rules persistent.<\/p>\n<h1>Verifying it works<\/h1>\n<p>Connect to a different network than the one your home server is on and try to connect to <code>ssh<\/code> using port 2222 with EXT's ip\/hostname.\nFor example:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span>ssh -p <span class=\"m\">2222<\/span> user@EXT\n<\/code><\/pre><\/div>\n\n<p>You should now be successfully logged into HOME.<\/p>\n<h1>One additional trick<\/h1>\n<p>One annoyance that comes with this method is that now all of your traffic to HOME is passed through EXT, even if you have direct access (same LAN) to HOME from your computer. This is due to the fact that the DNS name\/ip address you are now using to connect to HOME is actually EXT's.<\/p>\n<p>One simple solution would be to use a different DNS name depending if you have direct access or not. This is awfully annoying and manual in general, and even more annoying when using git.<\/p>\n<p>A better solution, which is what I chose for my setup, is to configure your DNS to resolve differently inside your home network (configure your router if it supports it, it should). So for example, I use <samp>git.stosb.com<\/samp> for my git server. The public DNS is a CNAME to <samp>stosb.com<\/samp>, but inside my network, it resolves to HOME's local address, which means everything will just connect to it directly.<\/p>\n<h1>Finishing notes<\/h1>\n<p>I would love to hear if you have any corrections or better ideas on how to implement this. I would especially love to hear if you have any comments on how to harden this setup even further. I have a feeling the <code>iptables<\/code> rules could be a bit more strict. Please <a href=\"https:\/\/stosb.com\/about\/\">let me know<\/a>.<\/p>","category":[{"@attributes":{"term":"misc"}},{"@attributes":{"term":"security"}},{"@attributes":{"term":"server"}},{"@attributes":{"term":"vpn"}},{"@attributes":{"term":"firewall"}}]},{"title":"Retaining History When Moving Files Across Repositories in Git","link":{"@attributes":{"href":"https:\/\/stosb.com\/blog\/retaining-history-when-moving-files-across-repositories-in-git\/","rel":"alternate"}},"published":"2016-04-20T18:30:00+01:00","updated":"2016-04-20T18:30:00+01:00","author":{"name":"Tom Hacohen"},"id":"tag:stosb.com,2016-04-20:\/blog\/retaining-history-when-moving-files-across-repositories-in-git\/","summary":"<p>As my friends and colleagues know, I think the history of a project is very important for development.\nBeing able to <code>bisect<\/code>, <code>blame<\/code> or read the log have proven very useful for finding bugs and understanding why a piece of code was written the way it was.\nTherefore, it makes \u2026<\/p>","content":"<p>As my friends and colleagues know, I think the history of a project is very important for development.\nBeing able to <code>bisect<\/code>, <code>blame<\/code> or read the log have proven very useful for finding bugs and understanding why a piece of code was written the way it was.\nTherefore, it makes sense that I would do whatever I can to make sure history is preserved when moving files across repositories.<\/p>\n<p>Luckily for us, git has made it extremely easy.<\/p>\n<h1>Merging repositories<\/h1>\n<p>Merging a repository (<samp>bar<\/samp>) into another repository (<samp>foo<\/samp>) is easy.<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span><span class=\"nb\">cd<\/span> \/path\/to\/foo\n<span class=\"gp\">$ <\/span><span class=\"c1\"># To use a local copy, replay the url with: file:\/\/\/path\/to\/bar\/.git<\/span>\n<span class=\"gp\">$ <\/span>git remote add bar https:\/\/git.domain.com\/bar.git\n<span class=\"gp\">$ <\/span>git fetch bar\n<span class=\"gp\">$ <\/span>git merge --allow-unrelated-histories bar\/master\n<\/code><\/pre><\/div>\n\n<p>This is it. It is very simple and retains all of the history from <samp>bar<\/samp> while maintaining the same commit hashes!\nThis means that for example <samp>daed567e<\/samp> will point to the same commit in both <samp>foo<\/samp> and <samp>bar<\/samp>.<\/p>\n<p>Unfortunately it is not always that simple. Sometimes you may face conflicts, if for example you had a <samp>README<\/samp> file in both repositories, the merge operation will fail. Luckily, this is also easy to solve.<\/p>\n<p>First, abort the failed merge (if you already tried to merge):<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span>git merge --abort\n<\/code><\/pre><\/div>\n\n<p>Now switch to a temporary branch that holds <samp>bar<\/samp>:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span>git checkout -b barmaster bar\/master\n<\/code><\/pre><\/div>\n\n<p>Now you can deal with the conflicting files by either removing them, moving all of bar into a directory such as <samp>bar_directory<\/samp> or renaming them individually.<\/p>\n<p>We can finally switch back to master and merge our branch again:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span>git checkout master\n<span class=\"gp\">$ <\/span>git merge --allow-unrelated-histories barmaster\n<\/code><\/pre><\/div>\n\n<p>We are done. Do not forget to push your changes.<\/p>\n<p><strong>Update<\/strong>: Starting from version 2.9, git requires <code>--allow-unrelated-histories<\/code> for the above merges. Thanks a lot to <a href=\"https:\/\/github.com\/jeff303\">Jeff Evans<\/a> for the correction.<\/p>\n<h1>Splitting repositories<\/h1>\n<p>Splitting repositories is slightly more involved compared to merging them, because in this case we would like to remove all of the unrelated files and commits from history so our new repository is clean.<\/p>\n<p>There are two approaches for this stage. The whitelist (we only keep a list of files) and the blacklist (we keep everything except for the list of files). I prefer the whitelist approach, so I will only cover that one.<\/p>\n<p>For this example we will split <samp>bar<\/samp> out of <samp>foobar<\/samp>.<\/p>\n<p>Let us first start by switching to a temporary branch we can work on.<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span>git checkout -b tmp\n<\/code><\/pre><\/div>\n\n<p>Now we need to decide which files we would like to preserve.<\/p>\n<div class=\"alert alert-info\" role=\"alert\">\n<p><strong>Optional:<\/strong> Retain files that have been renamed throughout history.<\/p>\n<p>If for example we have a file called <samp>a<\/samp> that has been renamed to <samp>b<\/samp> at some point in history, we would like to preserve both <samp>a<\/samp> and <samp>b<\/samp>. A useful command to find all of the past names of a file is:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span>git log --name-only --format<span class=\"o\">=<\/span>format: --follow -- path\/to\/file <span class=\"p\">|<\/span> sort -u\n<\/code><\/pre><\/div>\n\n<p>Just add both names of the file into the script we will create below.<\/p>\n<\/div>\n<p>Now we will create a script that moves the correct files into a new temporary directory and run it on all of our repository's history.<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"ch\">#!\/bin\/bash<\/span>\n\nmkdir -p newroot\/\n\n<span class=\"c1\"># Redirect output to silence &quot;file not found&quot; warnings.<\/span>\nmv README.md newroot\/ <span class=\"m\">2<\/span>&gt;\/dev\/null\nmv src newroot\/ <span class=\"m\">2<\/span>&gt;\/dev\/null\n\n<span class=\"nb\">true<\/span>\n<\/code><\/pre><\/div>\n\n<p>Now run the script on our history:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span>git filter-branch -f --prune-empty --tree-filter \/path\/to\/script HEAD\n<\/code><\/pre><\/div>\n\n<p>After that we should have a new repository with a directory called <samp>newroot<\/samp> that contains all of the files we wish to preserve. If we spotted an issue, we can just reset our branch to the initial state (<code>git reset --hard master<\/code>) and try again, otherwise, we can move to the next step: filtering the repository to be only this directory.<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span>git filter-branch --prune-empty -f --subdirectory-filter newroot\n<\/code><\/pre><\/div>\n\n<p>Assuming everything is correct we can go on and push it to our new repository as <samp>master<\/samp>.<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span>git remote add bar git+ssh:\/\/git@git.domain.com\/bar.git\n<span class=\"gp\">$ <\/span>git push bar tmp:master\n<\/code><\/pre><\/div>\n\n<p>That is it. You have now split <samp>bar<\/samp> out of <samp>foo<\/samp>. The last remaining thing to do is to delete the remaining <samp>bar<\/samp> related files from our <samp>foobar<\/samp> repository and commit the changes.<\/p>\n<h1>Moving arbitrary files between repositories<\/h1>\n<p>Moving arbitrary files is very easy when you consider it is just a split from one repository followed by a merge to another. For this reason I will not elaborate further, just follow the two sections above.<\/p>\n<h1>Finishing notes<\/h1>\n<p>This is a very simple guide. In some more complex cases you will probably have to write more complex scripts or use some optimisation techniques. I suggest you also take a look at my <a href=\"\/static\/talks\/git_soscon_14.pdf\">slides<\/a> from a talk I gave about migrating the <a href=\"https:\/\/www.enlightenment.org\">Enlightenment<\/a> project from SVN to git. They contain some useful tips and tricks. Especially if you have a big project with a very rich history.<\/p>\n<p>Please <a href=\"https:\/\/stosb.com\/about\/\">let me know<\/a> if you encountered any issues or have any suggestions.<\/p>","category":[{"@attributes":{"term":"misc"}},{"@attributes":{"term":"git"}},{"@attributes":{"term":"programming"}}]},{"title":"Secure Your letsencrypt Setup With acme-tiny","link":{"@attributes":{"href":"https:\/\/stosb.com\/blog\/secure-your-letsencrypt-setup-with-acme-tiny\/","rel":"alternate"}},"published":"2016-03-08T18:30:00+00:00","updated":"2016-03-08T18:30:00+00:00","author":{"name":"Tom Hacohen"},"id":"tag:stosb.com,2016-03-08:\/blog\/secure-your-letsencrypt-setup-with-acme-tiny\/","summary":"<p>In my <a href=\"https:\/\/stosb.com\/blog\/running-letsencrypt-as-an-unprivileged-user\/\">previous post<\/a> about <a href=\"https:\/\/letsencrypt.org\">letsencrypt<\/a> I explained how to run the official client as an unprivileged user.\nWhile this is a major security improvement over the default setup it is insufficient.<\/p>\n<p>As was mentioned in the previous post I have since switched to <a href=\"https:\/\/github.com\/diafygi\/acme-tiny\">acme-tiny<\/a> (and created an <a href=\"https:\/\/aur.archlinux.org\/packages\/acme-tiny\/\">AUR package \u2026<\/a><\/p>","content":"<p>In my <a href=\"https:\/\/stosb.com\/blog\/running-letsencrypt-as-an-unprivileged-user\/\">previous post<\/a> about <a href=\"https:\/\/letsencrypt.org\">letsencrypt<\/a> I explained how to run the official client as an unprivileged user.\nWhile this is a major security improvement over the default setup it is insufficient.<\/p>\n<p>As was mentioned in the previous post I have since switched to <a href=\"https:\/\/github.com\/diafygi\/acme-tiny\">acme-tiny<\/a> (and created an <a href=\"https:\/\/aur.archlinux.org\/packages\/acme-tiny\/\">AUR package<\/a> for it). In this post I will explain how to set up letsencrypt in an even more secure manner using that.<\/p>\n<p>Parts of this tutorial are based on the acme-tiny <a href=\"https:\/\/github.com\/diafygi\/acme-tiny#use-existing-lets-encrypt-key\">README<\/a>. Many thanks to the original author for both the software and the readme.<\/p>\n<p>This post supersedes the previous one, you only need to follow one of them.<\/p>\n<h1>Why bother?<\/h1>\n<p>Security.<\/p>\n<p>You should strive to run every process with the lowest privileges possible. This both reduces the chances of a bug causing data loss, and more importantly, a security issue leading to a compromise.<\/p>\n<p>Using acme-tiny enables you to limit access to your private keys in addition to running the process as a unprivileged user.<\/p>\n<h1>How is this better than unprivileged letsencrypt (previous post)?<\/h1>\n<p>Running the official client as an unprivileged user protects your system from compromise, but it falls short in protecting your private key. Because the official client also generates your private keys, it, by definition, has access to them. While your server may not get compromised, your private keys might, which is also very bad.<\/p>\n<h1>Preface<\/h1>\n<p>In this tutorial we will setup acme-tiny to run as an unprivileged user and properly configure permissions so it does not have access to our private key.<\/p>\n<p>Definitions and assumptions:<\/p>\n<ul>\n<li>The domain: <samp>example.com<\/samp><\/li>\n<li>The web server's web root: <samp>\/srv\/http\/letsencrypt<\/samp><\/li>\n<li>The acme-tiny directory: <samp>\/etc\/acme-tiny<\/samp><\/li>\n<li>The private keys directory: <samp>\/etc\/ssl\/keys<\/samp><\/li>\n<li>Commands preceded by # should be run as root.<\/li>\n<li>Commands preceded by $ should be run as the letsencrypt user.<\/li>\n<\/ul>\n<h1>Preparing the environment<\/h1>\n<p>First we need to create an unprivileged user for letsencrypt. I chose <samp>letsencrypt<\/samp>. The following command will create a new system user without a login shell or a home directory.<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\"># <\/span>useradd --shell \/bin\/false --system letsencrypt\n<\/code><\/pre><\/div>\n\n<p>Now we will create the private keys directory, and make it only accessible to root. Feel free to change the location and user to whatever suits your setup.<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\"># <\/span>mkdir -p \/etc\/ssl\/keys\n<span class=\"gp\"># <\/span>chmod <span class=\"m\">700<\/span> \/etc\/ssl\/keys\n<\/code><\/pre><\/div>\n\n<p>Put the <a href=\"https:\/\/github.com\/diafygi\/acme-tiny\">acme-tiny<\/a> script in your path as <code>acme-tiny<\/code> (or use the <a href=\"https:\/\/aur.archlinux.org\/packages\/acme-tiny\/\">AUR package<\/a> if on Arch) and make sure it's executable.<\/p>\n<p>Put the <a href=\"https:\/\/github.com\/tasn\/acme-tiny-wrapper\">acme-tiny-wrapper<\/a> script in your path (or use the <a href=\"https:\/\/aur.archlinux.org\/packages\/acme-tiny-wrapper\/\">AUR package<\/a> if on Arch) and make sure it's executable.<\/p>\n<p>Finally, we will create the needed directory for the domain validation, and set the correct permissions.<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\"># <\/span>mkdir -p \/srv\/http\/letsencrypt\/.well-known\/acme-challenge\n<span class=\"gp\"># <\/span>chown -R letsencrypt: \/srv\/http\/letsencrypt\n<\/code><\/pre><\/div>\n\n<p>You need to setup your web server to serve this for any of your domains, for example for Nginx you can accomplish this by adding the following <code>location<\/code> directive at the top of your server block.<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"k\">server<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\"><\/span>\n<span class=\"w\">     <\/span><span class=\"kn\">server_name<\/span><span class=\"w\">  <\/span><span class=\"s\">example.com<\/span><span class=\"p\">;<\/span><span class=\"w\"><\/span>\n\n<span class=\"w\">     <\/span><span class=\"kn\">location<\/span><span class=\"w\"> <\/span><span class=\"s\">\/.well-known\/acme-challenge\/<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\"><\/span>\n<span class=\"w\">          <\/span><span class=\"kn\">root<\/span><span class=\"w\"> <\/span><span class=\"s\">\/srv\/http\/letsencrypt\/<\/span><span class=\"p\">;<\/span><span class=\"w\"><\/span>\n<span class=\"w\">          <\/span><span class=\"kn\">try_files<\/span><span class=\"w\"> <\/span><span class=\"nv\">$uri<\/span><span class=\"w\"> <\/span><span class=\"p\">=<\/span><span class=\"mi\">404<\/span><span class=\"p\">;<\/span><span class=\"w\"><\/span>\n<span class=\"w\">     <\/span><span class=\"p\">}<\/span><span class=\"w\"><\/span>\n\n<span class=\"w\">     <\/span><span class=\"c1\"># Snip ...<\/span>\n<span class=\"p\">}<\/span><span class=\"w\"><\/span>\n<\/code><\/pre><\/div>\n\n<div class=\"alert alert-info\" role=\"alert\">\n<p><strong>Optional:<\/strong> verify the web server can serve files created by our user:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span><span class=\"nb\">echo<\/span> works &gt; \/srv\/http\/letsencrypt\/.well-known\/acme-challenge\/test.txt\n<span class=\"gp\">$ <\/span>curl example.com\/.well-known\/acme-challenge\/test.txt\n<\/code><\/pre><\/div>\n\n<p>If the last command printed \"works\", everything works. Otherwise, something is wrong with your configuration. This is unfortunately out of scope for this tutorial, though feel free to <a href=\"https:\/\/stosb.com\/about\/\">contact me<\/a>, maybe I can help.<\/p>\n<\/div>\n<h1>Preparing acme-tiny<\/h1>\n<p>First we need to create a directory for our certificates to live in and set the proper permissions. I chose <samp>\/etc\/acme-tiny<\/samp>.<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\"># <\/span>mkdir -p \/etc\/acme-tiny\/csr\n<span class=\"gp\"># <\/span>chown -R letsencrypt: \/etc\/acme-tiny\n<\/code><\/pre><\/div>\n\n<h2>Create an account key<\/h2>\n<p>In order to use letsencrypt, we need a private key for the account.<\/p>\n<p>The rest of the commands will be called from withing the <samp>\/etc\/acme-tiny<\/samp> directory.<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span><span class=\"nb\">cd<\/span> \/etc\/acme-tiny\n<\/code><\/pre><\/div>\n\n<h3>Option 1: Create a new account key<\/h3>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span>openssl genrsa <span class=\"m\">4096<\/span> &gt; account.key\n<\/code><\/pre><\/div>\n\n<h3>Option 2: Use existing letsencrypt account key<\/h3>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span>wget -O - <span class=\"s2\">&quot;https:\/\/gist.githubusercontent.com\/JonLundy\/f25c99ee0770e19dc595\/raw\/6035c1c8938fae85810de6aad1ecf6e2db663e26\/conv.py&quot;<\/span> &gt; conv.py\n<span class=\"gp\">$ <\/span>cp \/etc\/letsencrypt\/accounts\/acme-v01.api.letsencrypt.org\/directory\/&lt;id&gt;\/private_key.json private_key.json\n<span class=\"gp\">$ <\/span>openssl asn1parse -noout -out private_key.der -genconf &lt;<span class=\"o\">(<\/span>python conv.py private_key.json<span class=\"o\">)<\/span>\n<span class=\"gp\">$ <\/span>openssl rsa -in private_key.der -inform der &gt; account.key\n<span class=\"gp\">$ <\/span>rm conv.py private_key.json private_key.der\n<\/code><\/pre><\/div>\n\n<h2>Create a certificate signing request and key (per domain)<\/h2>\n<p>Create your private key as root. No need to further restrict access to it, because we already restricted access to the directory.<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\"># <\/span>openssl genrsa <span class=\"m\">4096<\/span> &gt; \/etc\/ssl\/keys\/example.com.key\n<\/code><\/pre><\/div>\n\n<p>There are two options for the certificate signing request, a certificate for a single domain, for example <samp>example.com<\/samp>, or a certificate for multiple domains, for example <samp>example.com<\/samp> and <samp>www.example.com<\/samp> in the same certificate.<\/p>\n<p>You can put whatever domains you want on the certificate, but be aware that anyone accessing any of the domains will be able to see the whole list.<\/p>\n<h3>Option 1: Single domain certificate<\/h3>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\"># <\/span>openssl req -new -sha256 -key \/etc\/ssl\/keys\/example.com.key -subj <span class=\"s2\">&quot;\/CN=example.com&quot;<\/span> &gt; \/etc\/acme-tiny\/csr\/example.com.csr\n<\/code><\/pre><\/div>\n\n<h3>Option 2: Multiple domains certificate<\/h3>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\"># <\/span>openssl req -new -sha256 -key \/etc\/ssl\/keys\/example.com.key -subj <span class=\"s2\">&quot;\/&quot;<\/span> -reqexts SAN -config &lt;<span class=\"o\">(<\/span>cat \/etc\/ssl\/openssl.cnf &lt;<span class=\"o\">(<\/span><span class=\"nb\">printf<\/span> <span class=\"s2\">&quot;[SAN]\\nsubjectAltName=DNS:example.com,DNS:www.example.com&quot;<\/span><span class=\"o\">))<\/span> &gt; \/etc\/acme-tiny\/csr\/example.com.csr\n<\/code><\/pre><\/div>\n\n<h1>Running acme-tiny<\/h1>\n<p>Create as many certificate signing requests as you want, and put them in the csr directory, the script will automatically generate certificates for all of them.<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span>acme-tiny-wrapper \/srv\/http\/letsencrypt\/.well-known\/acme-challenge\/\n<\/code><\/pre><\/div>\n\n<p>Now you will have a directory created in <samp>\/etc\/acme-tiny\/live<\/samp> for every csr you had in the csr directory.<\/p>\n<p><strong>Note:<\/strong> You can set an alternative path to the acme-tiny binary by setting the <samp>ACME_TINY_BIN<\/samp> environment variable.<\/p>\n<h2>Verify everything worked<\/h2>\n<p>If you got here, you should already have your certificate issued.\nYou can verify this by running:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span>ls \/etc\/acme-tiny\/live\/example.com\n<\/code><\/pre><\/div>\n\n<p>This should output <samp>cert.pem  fullchain.pem<\/samp><\/p>\n<h1>Certificate renewal<\/h1>\n<p>This section is here just for completeness. You should run the script in a <code>cron<\/code> job so the certificate is renewed before it expires (at the time of writing, 3 months). I have a cron job running once a month.\nThe <code>cron<\/code> job should run:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span>acme-tiny-wrapper \/srv\/http\/letsencrypt\/.well-known\/acme-challenge\/\n<\/code><\/pre><\/div>\n\n<p><strong>Important:<\/strong> do not forget to make the server reload the certificates after they are renewed. Nginx for example, does not do this automatically.<\/p>\n<h1>Finishing notes<\/h1>\n<p>This tutorial does not cover setting up your web server to use the new certificates. This is very simple and covered at length elsewhere.<\/p>\n<p>However, here is an example for nginx:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"k\">server<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\"><\/span>\n<span class=\"w\">     <\/span><span class=\"kn\">server_name<\/span><span class=\"w\">  <\/span><span class=\"s\">example.com<\/span><span class=\"p\">;<\/span><span class=\"w\"><\/span>\n<span class=\"w\">     <\/span><span class=\"c1\"># Snip ...<\/span>\n\n<span class=\"w\">     <\/span><span class=\"kn\">ssl_certificate<\/span><span class=\"w\"> <\/span><span class=\"s\">\/etc\/acme-tiny\/live\/example.com\/fullchain.pem<\/span><span class=\"p\">;<\/span><span class=\"w\"><\/span>\n<span class=\"w\">     <\/span><span class=\"kn\">ssl_certificate_key<\/span><span class=\"w\"> <\/span><span class=\"s\">\/etc\/ssl\/keys\/example.com.key<\/span><span class=\"p\">;<\/span><span class=\"w\"><\/span>\n\n<span class=\"w\">     <\/span><span class=\"c1\"># Snip ...<\/span>\n<span class=\"p\">}<\/span><span class=\"w\"><\/span>\n<\/code><\/pre><\/div>\n\n<p>Please <a href=\"https:\/\/stosb.com\/about\/\">let me know<\/a> if you encountered any issues or have any suggestions.<\/p>","category":[{"@attributes":{"term":"misc"}},{"@attributes":{"term":"letsencrypt"}},{"@attributes":{"term":"security"}},{"@attributes":{"term":"server"}}]},{"title":"Running letsencrypt as an Unprivileged User","link":{"@attributes":{"href":"https:\/\/stosb.com\/blog\/running-letsencrypt-as-an-unprivileged-user\/","rel":"alternate"}},"published":"2016-02-11T12:00:00+00:00","updated":"2016-02-11T12:00:00+00:00","author":{"name":"Tom Hacohen"},"id":"tag:stosb.com,2016-02-11:\/blog\/running-letsencrypt-as-an-unprivileged-user\/","summary":"<p><strong>Update:<\/strong> I published a <a href=\"https:\/\/stosb.com\/blog\/secure-your-letsencrypt-setup-with-acme-tiny\/\">new post<\/a> explaining how to use <a href=\"https:\/\/github.com\/diafygi\/acme-tiny\">acme-tiny<\/a> for even better security. Check it out, it is a bit more advanced, but also more secure.<\/p>\n<p>Running <a href=\"https:\/\/letsencrypt.org\">letsencrypt<\/a> as an unprivileged user (non-root) is surprisingly easy, and even more surprisingly undocumented. There is no mention in the <a href=\"http:\/\/letsencrypt.readthedocs.org\/en\/latest\/using.html\">official \u2026<\/a><\/p>","content":"<p><strong>Update:<\/strong> I published a <a href=\"https:\/\/stosb.com\/blog\/secure-your-letsencrypt-setup-with-acme-tiny\/\">new post<\/a> explaining how to use <a href=\"https:\/\/github.com\/diafygi\/acme-tiny\">acme-tiny<\/a> for even better security. Check it out, it is a bit more advanced, but also more secure.<\/p>\n<p>Running <a href=\"https:\/\/letsencrypt.org\">letsencrypt<\/a> as an unprivileged user (non-root) is surprisingly easy, and even more surprisingly undocumented. There is no mention in the <a href=\"http:\/\/letsencrypt.readthedocs.org\/en\/latest\/using.html\">official documentation<\/a>, nor was I able to find anything online.<\/p>\n<p>There are alternative clients that were designed to be run as unprivileged, but they are not as beginner-friendly as the official one. I, for one, have switched to <a href=\"https:\/\/github.com\/diafygi\/acme-tiny\">acme-tiny<\/a> (and created an <a href=\"https:\/\/aur.archlinux.org\/packages\/acme-tiny\/\">AUR package<\/a> for it). Its much smaller and lets me have an even more secure setup.<\/p>\n<h1>Why bother?<\/h1>\n<p>Security.<\/p>\n<p>You should strive to run every process with the lowest privileges possible. This both reduces the chances of a bug causing data loss, and more importantly, a security issue leading to a compromise.<\/p>\n<h1>Summary<\/h1>\n<p>In this tutorial we will setup letsencrypt to run as an unprivileged user using the <samp>webroot<\/samp> plugin.<\/p>\n<p>This tutorial uses basic letsencrypt commands for simplicity. Refer to the <a href=\"http:\/\/letsencrypt.readthedocs.org\/en\/latest\/using.html\">official documentation<\/a> for more advance usage.<\/p>\n<p>Definitions and assumptions:<\/p>\n<ul>\n<li>The domain: <samp>example.com<\/samp><\/li>\n<li>The web server's web root: <samp>\/srv\/http\/example.com<\/samp><\/li>\n<li>Commands preceded by # should be run as root.<\/li>\n<li>Commands preceded by $ should be run as the letsencrypt user.<\/li>\n<\/ul>\n<h1>Preparing the environment<\/h1>\n<p>First we need to create an unprivileged user for letsencrypt. I chose <samp>letsencrypt<\/samp>. The following command will create a new system user without a login shell or a home directory.<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\"># <\/span>useradd --shell \/bin\/false --system letsencrypt\n<\/code><\/pre><\/div>\n\n<p>Now we will create the needed directory for the <samp>webroot<\/samp> plugin, and set the correct permissions.<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\"># <\/span>mkdir -p \/srv\/http\/example.com\/.well-known\/acme-challenge\n<span class=\"gp\"># <\/span>chown -R letsencrypt: \/srv\/http\/example.com\/.well-known\n<\/code><\/pre><\/div>\n\n<div class=\"alert alert-info\" role=\"alert\">\n<p><strong>Optional:<\/strong> verify the web server can serve files created by our user:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span><span class=\"nb\">echo<\/span> works &gt; \/srv\/http\/example.com\/.well-known\/acme-challenge\/test.txt\n<span class=\"gp\">$ <\/span>curl example.com\/.well-known\/acme-challenge\/test.txt\n<\/code><\/pre><\/div>\n\n<p>If the last command printed \"works\", everything works. Otherwise, something is wrong with your configuration. This is unfortunately out of scope for this tutorial, though feel free to <a href=\"https:\/\/stosb.com\/about\/\">contact me<\/a>, maybe I can help.<\/p>\n<\/div>\n<h1>Preparing and running letsencrypt<\/h1>\n<p>There are two options for this step. The first option is easier and preferred if you already have a working letsencrypt. The second option is more correct and is preferred if you are starting fresh.<\/p>\n<h2>Option 1: Update the permissions of the default paths<\/h2>\n<p>By default letsencrypt (at least on <a href=\"https:\/\/www.archlinux.org\">Arch Linux<\/a>) uses these three paths:<\/p>\n<ul>\n<li>logs-dir: <samp>\/var\/log\/letsencrypt<\/samp><\/li>\n<li>config-dir: <samp>\/etc\/letsencrypt<\/samp><\/li>\n<li>work-dir: <samp>\/var\/lib\/letsencrypt<\/samp><\/li>\n<\/ul>\n<p>We need to change these directories to be owned by our user and group:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\"># <\/span>chown -R letsencrypt: \/var\/log\/letsencrypt \/etc\/letsencrypt \/var\/lib\/letsencrypt\n<\/code><\/pre><\/div>\n\n<p>Now we need to run letsencrypt so it creates the initial configuration and our first certificate.<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span>letsencrypt certonly --webroot -w \/srv\/http\/example.com -d example.com -d www.example.com\n<\/code><\/pre><\/div>\n\n<p>At this stage letsencrypt will complain about not running as root, that is fine. Ignore it. Just follow the steps and answer the questions.<\/p>\n<h2>Option 2: Create new directories for letsencrypt<\/h2>\n<p>letsencrypt supports a few undocumented flags that let you change the running environment.<\/p>\n<p>First we need to create the relevant directory structure, for simplicity I chose <samp>\/home\/letsencrypt<\/samp> as the base directory and the rest as subdirectories:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\"># <\/span>mkdir \/home\/letsencrypt\n<span class=\"gp\"># <\/span>chown letsencrypt: \/home\/letsencrypt\n<\/code><\/pre><\/div>\n\n<p>And as the user:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span><span class=\"nb\">cd<\/span> \/home\/letsencrypt\n<span class=\"gp\">$ <\/span>mkdir logs config work\n<\/code><\/pre><\/div>\n\n<p>Now we can run letsencrypt as we normally do, just with the addition of the <code>--logs-dir<\/code>, <code>--config-dir<\/code> and the <code>--work-dir<\/code> flags.<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span>letsencrypt certonly --config-dir \/home\/letsencrypt\/config --work-dir \/home\/letsencrypt\/work --logs-dir \/home\/letsencrypt\/logs\/ --webroot -w \/srv\/http\/example.com -d example.com -d www.example.com\n<\/code><\/pre><\/div>\n\n<p>At this stage letsencrypt will complain about not running as root, that is fine. Ignore it. Just follow the steps and answer the questions.<\/p>\n<h2>Both: verify everything worked<\/h2>\n<p>If you got here, you should already have your certificate issued.<\/p>\n<p>You can verify this by running:<\/p>\n<h3>Verify option 1:<\/h3>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span>ls \/etc\/letsencrypt\/live\/example.com\n<\/code><\/pre><\/div>\n\n<h3>Verify option 2:<\/h3>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span>ls \/home\/letsencrypt\/config\/live\/example.com\n<\/code><\/pre><\/div>\n\n<p>This should output <samp>cert.pem  chain.pem  fullchain.pem  privkey.pem<\/samp><\/p>\n<h1>Certificate renewal<\/h1>\n<p>This section is here just for completeness. You should run letsencrypt in a <code>cron<\/code> job so the certificate is renewed before it expires (at the time of writing, 3 months). I have a cron job running once a month.<\/p>\n<p>When renewing, you should run:<\/p>\n<h2>Renew option 1:<\/h2>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span>letsencrypt certonly --agree-tos --renew-by-default --webroot -w \/srv\/http\/example.com -d example.com -d www.example.com\n<\/code><\/pre><\/div>\n\n<h2>Renew option 2:<\/h2>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span>letsencrypt certonly --agree-tos --renew-by-default --config-dir \/home\/letsencrypt\/config --work-dir \/home\/letsencrypt\/work --logs-dir \/home\/letsencrypt\/logs\/ --webroot -w \/srv\/http\/example.com -d example.com -d www.example.com\n<\/code><\/pre><\/div>\n\n<p><strong>Important:<\/strong> do not forget to make the server reload the certificates after they are renewed. Nginx for example, does not do this automatically.<\/p>\n<h1>Finishing notes<\/h1>\n<p>For more information about letsencrypt, please refer to the <a href=\"http:\/\/letsencrypt.readthedocs.org\/en\/latest\/using.html\">official documentation<\/a>.<\/p>\n<p>This tutorial does not cover setting up your web server to use the new certificates. This is very simple and covered at length elsewhere.<\/p>\n<p>However, here is an example for nginx:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"k\">server<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\"><\/span>\n<span class=\"w\">     <\/span><span class=\"kn\">server_name<\/span><span class=\"w\">  <\/span><span class=\"s\">example.com<\/span><span class=\"p\">;<\/span><span class=\"w\"><\/span>\n<span class=\"w\">     <\/span><span class=\"c1\"># Snip ...<\/span>\n\n<span class=\"w\">     <\/span><span class=\"kn\">ssl_certificate<\/span><span class=\"w\"> <\/span><span class=\"s\">\/etc\/letsencrypt\/live\/example.com\/fullchain.pem<\/span><span class=\"p\">;<\/span><span class=\"w\"><\/span>\n<span class=\"w\">     <\/span><span class=\"kn\">ssl_certificate_key<\/span><span class=\"w\"> <\/span><span class=\"s\">\/etc\/letsencrypt\/live\/example.com\/privkey.pem<\/span><span class=\"p\">;<\/span><span class=\"w\"><\/span>\n\n<span class=\"w\">     <\/span><span class=\"c1\"># Snip ...<\/span>\n<span class=\"p\">}<\/span><span class=\"w\"><\/span>\n<\/code><\/pre><\/div>\n\n<p>Please <a href=\"https:\/\/stosb.com\/about\/\">let me know<\/a> if you encountered any issues or have any suggestions.<\/p>","category":[{"@attributes":{"term":"misc"}},{"@attributes":{"term":"letsencrypt"}},{"@attributes":{"term":"security"}},{"@attributes":{"term":"server"}}]},{"title":"Using OpenPGP Keys For SSH Authentication","link":{"@attributes":{"href":"https:\/\/stosb.com\/blog\/using-openpgp-keys-for-ssh-authentication\/","rel":"alternate"}},"published":"2015-09-15T19:00:00+01:00","updated":"2015-09-15T19:00:00+01:00","author":{"name":"Tom Hacohen"},"id":"tag:stosb.com,2015-09-15:\/blog\/using-openpgp-keys-for-ssh-authentication\/","summary":"<p>If you already use OpenPGP, there is no need for you to create an additional SSH key.\nYou can just consolidate your identity and use the same key for SSH authentication.\nThe main benefits that come to mind are:<\/p>\n<ol>\n<li>Preparing yourself for your eventual migration to using an OpenPGP smart \u2026<\/li><\/ol>","content":"<p>If you already use OpenPGP, there is no need for you to create an additional SSH key.\nYou can just consolidate your identity and use the same key for SSH authentication.\nThe main benefits that come to mind are:<\/p>\n<ol>\n<li>Preparing yourself for your eventual migration to using an OpenPGP smart card (hereby: SmartCard) like the <a href=\"https:\/\/www.yubico.com\/products\/yubikey-hardware\/yubikey-neo\/\">YubiKey NEO<\/a>.<\/li>\n<li>Having one less key to worry about.<\/li>\n<\/ol>\n<p>The rest of this post assumes:<\/p>\n<ol>\n<li>You use GnuPG version 2.1 or later (run <code>gpg --version<\/code> to verify).<\/li>\n<li>You already have an OpenPGP key (plenty of tutorials online).<\/li>\n<li>You already use <code>gpg-agent<\/code> as your SSH agent (plenty of tutorials online).<\/li>\n<\/ol>\n<h1>Create an Authentication subkey<\/h1>\n<p>We first need to open the relevant key for editing in expert mode:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span>gpg --expert --edit-key 7C477933\n<span class=\"go\">Secret key is available.<\/span>\n\n<span class=\"go\">pub  rsa4096\/7C477933<\/span>\n<span class=\"go\">     created: 2011-12-20  expires: never       usage: SC<\/span>\n<span class=\"go\">     trust: ultimate      validity: ultimate<\/span>\n<span class=\"go\">sub  rsa2048\/03879636<\/span>\n<span class=\"go\">     created: 2015-09-15  expires: never       usage: S<\/span>\n<span class=\"go\">sub  rsa2048\/DCAAEEF7<\/span>\n<span class=\"go\">     created: 2015-09-15  expires: never       usage: E<\/span>\n<span class=\"go\">[ultimate] (1). Tom &lt;tom@example.org&gt;<\/span>\n<\/code><\/pre><\/div>\n\n<p>Now we are going to add a new authentication key:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code>gpg&gt; addkey\nPlease select what kind of key you want:\n   (3) DSA (sign only)\n   (4) RSA (sign only)\n   (5) Elgamal (encrypt only)\n   (6) RSA (encrypt only)\n   (7) DSA (set your own capabilities)\n   (8) RSA (set your own capabilities)\n  (10) ECC (sign only)\n  (11) ECC (set your own capabilities)\n  (12) ECC (encrypt only)\n  (13) Existing key\nYour selection?\n<\/code><\/pre><\/div>\n\n<p>Select <samp>(8) RSA (set your own capabilities)<\/samp>.<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"nv\">Possible<\/span> <span class=\"nv\">actions<\/span> <span class=\"k\">for<\/span> <span class=\"nv\">a<\/span> <span class=\"nv\">RSA<\/span> <span class=\"nv\">key<\/span>: <span class=\"nv\">Sign<\/span> <span class=\"nv\">Encrypt<\/span> <span class=\"nv\">Authenticate<\/span>\n<span class=\"nv\">Current<\/span> <span class=\"nv\">allowed<\/span> <span class=\"nv\">actions<\/span>: <span class=\"nv\">Authenticate<\/span>\n\n <span class=\"ss\">(<\/span><span class=\"nv\">S<\/span><span class=\"ss\">)<\/span> <span class=\"nv\">Toggle<\/span> <span class=\"nv\">the<\/span> <span class=\"nv\">sign<\/span> <span class=\"nv\">capability<\/span>\n <span class=\"ss\">(<\/span><span class=\"nv\">E<\/span><span class=\"ss\">)<\/span> <span class=\"nv\">Toggle<\/span> <span class=\"nv\">the<\/span> <span class=\"nv\">encrypt<\/span> <span class=\"nv\">capability<\/span>\n <span class=\"ss\">(<\/span><span class=\"nv\">A<\/span><span class=\"ss\">)<\/span> <span class=\"nv\">Toggle<\/span> <span class=\"nv\">the<\/span> <span class=\"nv\">authenticate<\/span> <span class=\"nv\">capability<\/span>\n <span class=\"ss\">(<\/span><span class=\"nv\">Q<\/span><span class=\"ss\">)<\/span> <span class=\"nv\">Finished<\/span>\n\n<span class=\"nv\">Your<\/span> <span class=\"nv\">selection<\/span>?\n<\/code><\/pre><\/div>\n\n<p>Select <samp>(S)<\/samp>, <samp>(E)<\/samp> and <samp>(A)<\/samp> until the current allowed actions contains only <samp>Authenticate<\/samp>, and then select <samp>(Q)<\/samp> to finish.<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"nv\">RSA<\/span> <span class=\"nv\">keys<\/span> <span class=\"nv\">may<\/span> <span class=\"nv\">be<\/span> <span class=\"nv\">between<\/span> <span class=\"mi\">1024<\/span> <span class=\"nv\">and<\/span> <span class=\"mi\">4096<\/span> <span class=\"nv\">bits<\/span> <span class=\"nv\">long<\/span>.\n<span class=\"nv\">What<\/span> <span class=\"nv\">keysize<\/span> <span class=\"k\">do<\/span> <span class=\"nv\">you<\/span> <span class=\"nv\">want<\/span>? <span class=\"ss\">(<\/span><span class=\"mi\">2048<\/span><span class=\"ss\">)<\/span>\n<\/code><\/pre><\/div>\n\n<p>Select <samp>2048<\/samp>, because as of now, this is the largest key size supported by the YubiKey and many other SmartCards, and is safe enough anyway.<\/p>\n<p>Continue with setting expiration and following instructions. After the key has been generated run:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code>gpg&gt; save\n<\/code><\/pre><\/div>\n\n<p>You will now see the same output as when we first ran <code>gpg --expert --edit-key 7C477933<\/code> with the newly added key included:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code>sub  rsa2048\/D184E14E\n     created: 2015-09-15  expires: never       usage: A\n<\/code><\/pre><\/div>\n\n<p>Where <samp>A<\/samp> indicates this subkey is used for authentication.<\/p>\n<h1>Adding the key to the agent<\/h1>\n<p>There are two possible alternatives for using the newly generated key. Using a SmartCard or not.<\/p>\n<h2>Without a SmartCard<\/h2>\n<p>First we need to find our key's <em>keygrip<\/em>, this can be done by running <code>gpg -K --with-keygrip<\/code> and locating our key:\nSo for the new key in our example, this should look something like:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code>sub   rsa2048\/D184E14E 2015-09-15\n      Keygrip = 58E0D19FEDB89C6659903C9CC1ADCC7801022844\n<\/code><\/pre><\/div>\n\n<p>After that open <code>~\/.gnupg\/sshcontrol<\/code> with your favourite editor, and append the <em>keygrip<\/em> found, as follows:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"mf\">07<\/span><span class=\"n\">D52A07249804D0D91C43400B3DA881F048512D<\/span><span class=\"w\"><\/span>\n<\/code><\/pre><\/div>\n\n<h2>With a SmartCard<\/h2>\n<p><strong>Important<\/strong>: This section explains how to <em>move<\/em> your private key to the SmartCard.\nThis is not reversible, so please make sure you have a valid backup of the key before continuing.<\/p>\n<p>This is very easy. First, let's open the key for editing:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span>gpg --edit-key 7C477933\n<span class=\"go\">Secret key is available.<\/span>\n\n<span class=\"go\">pub  rsa4096\/7C477933<\/span>\n<span class=\"go\">     created: 2011-12-20  expires: never       usage: SC<\/span>\n<span class=\"go\">     trust: ultimate      validity: ultimate<\/span>\n<span class=\"go\">sub  rsa2048\/03879636<\/span>\n<span class=\"go\">     created: 2015-09-15  expires: never       usage: S<\/span>\n<span class=\"go\">sub  rsa2048\/DCAAEEF7<\/span>\n<span class=\"go\">     created: 2015-09-15  expires: never       usage: E<\/span>\n<span class=\"go\">sub  rsa2048\/D184E14E<\/span>\n<span class=\"go\">     created: 2015-09-15  expires: never       usage: A<\/span>\n<span class=\"go\">[ultimate] (1). Tom &lt;tom@example.org&gt;<\/span>\n<\/code><\/pre><\/div>\n\n<p>Run <samp>toggle<\/samp> to switch to secret key mode:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code>gpg&gt; toggle\n<\/code><\/pre><\/div>\n\n<p>Choose the authentication key:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"n\">gpg<\/span><span class=\"o\">&gt;<\/span><span class=\"w\"> <\/span><span class=\"k\">key<\/span><span class=\"w\"> <\/span><span class=\"mi\">3<\/span><span class=\"w\"><\/span>\n\n<span class=\"n\">pub<\/span><span class=\"w\">  <\/span><span class=\"n\">rsa4096<\/span><span class=\"o\">\/<\/span><span class=\"mi\">7<\/span><span class=\"n\">C477933<\/span><span class=\"w\"><\/span>\n<span class=\"w\">     <\/span><span class=\"nl\">created<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"mi\">2011<\/span><span class=\"o\">-<\/span><span class=\"mi\">12<\/span><span class=\"o\">-<\/span><span class=\"mi\">20<\/span><span class=\"w\">  <\/span><span class=\"nl\">expires<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"n\">never<\/span><span class=\"w\">       <\/span><span class=\"k\">usage<\/span><span class=\"err\">:<\/span><span class=\"w\"> <\/span><span class=\"n\">SC<\/span><span class=\"w\"><\/span>\n<span class=\"w\">     <\/span><span class=\"nl\">trust<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"n\">ultimate<\/span><span class=\"w\">      <\/span><span class=\"nl\">validity<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"n\">ultimate<\/span><span class=\"w\"><\/span>\n<span class=\"n\">ssb<\/span><span class=\"w\">  <\/span><span class=\"n\">rsa2048<\/span><span class=\"o\">\/<\/span><span class=\"mi\">03879636<\/span><span class=\"w\"><\/span>\n<span class=\"w\">     <\/span><span class=\"nl\">created<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"mi\">2015<\/span><span class=\"o\">-<\/span><span class=\"mi\">09<\/span><span class=\"o\">-<\/span><span class=\"mi\">15<\/span><span class=\"w\">  <\/span><span class=\"nl\">expires<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"n\">never<\/span><span class=\"w\">       <\/span><span class=\"k\">usage<\/span><span class=\"err\">:<\/span><span class=\"w\"> <\/span><span class=\"n\">S<\/span><span class=\"w\"><\/span>\n<span class=\"n\">ssb<\/span><span class=\"w\">  <\/span><span class=\"n\">rsa2048<\/span><span class=\"o\">\/<\/span><span class=\"n\">DCAAEEF7<\/span><span class=\"w\"><\/span>\n<span class=\"w\">     <\/span><span class=\"nl\">created<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"mi\">2015<\/span><span class=\"o\">-<\/span><span class=\"mi\">09<\/span><span class=\"o\">-<\/span><span class=\"mi\">15<\/span><span class=\"w\">  <\/span><span class=\"nl\">expires<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"n\">never<\/span><span class=\"w\">       <\/span><span class=\"k\">usage<\/span><span class=\"err\">:<\/span><span class=\"w\"> <\/span><span class=\"n\">E<\/span><span class=\"w\"><\/span>\n<span class=\"n\">ssb<\/span><span class=\"o\">*<\/span><span class=\"w\"> <\/span><span class=\"n\">rsa2048<\/span><span class=\"o\">\/<\/span><span class=\"n\">D184E14E<\/span><span class=\"w\"><\/span>\n<span class=\"w\">     <\/span><span class=\"nl\">created<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"mi\">2015<\/span><span class=\"o\">-<\/span><span class=\"mi\">09<\/span><span class=\"o\">-<\/span><span class=\"mi\">15<\/span><span class=\"w\">  <\/span><span class=\"nl\">expires<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"n\">never<\/span><span class=\"w\">       <\/span><span class=\"k\">usage<\/span><span class=\"err\">:<\/span><span class=\"w\"> <\/span><span class=\"n\">A<\/span><span class=\"w\"><\/span>\n<span class=\"o\">[<\/span><span class=\"n\">ultimate<\/span><span class=\"o\">]<\/span><span class=\"w\"> <\/span><span class=\"p\">(<\/span><span class=\"mi\">1<\/span><span class=\"p\">).<\/span><span class=\"w\"> <\/span><span class=\"n\">Tom<\/span><span class=\"w\"> <\/span><span class=\"o\">&lt;<\/span><span class=\"n\">tom<\/span><span class=\"nv\">@example<\/span><span class=\"p\">.<\/span><span class=\"n\">org<\/span><span class=\"o\">&gt;<\/span><span class=\"w\"><\/span>\n<\/code><\/pre><\/div>\n\n<p>Move it to the card:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code>gpg&gt; keytocard\nPlease select where to store the key:\n   (1) Signature key\n   (2) Encryption key\n   (3) Authentication key\nYour selection?\n<\/code><\/pre><\/div>\n\n<p>Select <samp>3<\/samp>, because the key we chose is an authentication key, as denoted by the <samp>A<\/samp> in the usage field.<\/p>\n<p>If you wish to also move the encryption key and signature key to the card, please repeat the previous stages for those too.<\/p>\n<p>To finish, enter <samp>quit<\/samp>:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code>gpg&gt; quit\nSave changes? (y\/N) y\n<\/code><\/pre><\/div>\n\n<p>This is it, you now have your keys on your SmartCard, and they are ready to be used.<\/p>\n<h1>Using the key<\/h1>\n<p>Now we should have everything set up correctly. The only thing left to do is finding our public-key.\nAssuming everything works as expected, this is very easy:<\/p>\n<div class=\"highlight\"><pre><span><\/span><code><span class=\"gp\">$ <\/span>ssh-add -L\n<span class=\"go\">ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCg7H7iQVOXeHCWefQv1UH97Ow78KK7qZoRwKBLLOh1gJEDnFGhIbTnxdpMJUzj\/4TE+V\/D06iFO22+Ohn0MY3GP91V9\/XXXjvEDCYpRR3ftzhr1+AibDAJK3XFKcq6TQeag1Ib+4zSwsDxUs4Sei9YF40hO8pqfmqhRaW3YUJBdj8vVOCatm6IaLUfSIjzLHY9WggA3aeR48UMSl7DT4EdeqHjtZHxXKYdOw3ymt\/zyGfwuc9MNlzcmixINZSmW4jZTLXlTxhbCFlpp77ksuV605xUgl6+kgYNnni2t4VztwP9AH8yEjcdopasm1sObHcyEpq1BVxJtlShVDNl8ufb cardno:000603638479<\/span>\n<\/code><\/pre><\/div>\n\n<p>This will list all of the keys loaded in your agent.\nIf you use a SmartCard, look for the one with the comment that starts with <samp>cardno:<\/samp>,\nor if you don't use a SmartCard, for the one with the comment <samp>(none)<\/samp>.\nThis is your public-key and you can use it like you would normally.<\/p>\n<h1>Conclusion<\/h1>\n<p>As you can see, this is useful, very easy to do and is required for using a SmartCard, a highly recommended practice.<\/p>\n<p>Please let me know if you have spotted any mistakes or have any suggestions.<\/p>","category":[{"@attributes":{"term":"misc"}},{"@attributes":{"term":"security"}},{"@attributes":{"term":"pgp"}},{"@attributes":{"term":"ssh"}}]},{"title":"New Website!","link":{"@attributes":{"href":"https:\/\/stosb.com\/blog\/new-website\/","rel":"alternate"}},"published":"2015-04-24T19:00:00+01:00","updated":"2015-04-24T19:00:00+01:00","author":{"name":"Tom Hacohen"},"id":"tag:stosb.com,2015-04-24:\/blog\/new-website\/","summary":"<p>After more work than I would like to admit, the new redesigned website is finally up. This iteration of the website is statically generated using <a href=\"http:\/\/getpelican.com\">Pelican<\/a>, which seems to be working great so far. I think I am going to play with the design a bit more once I get \u2026<\/p>","content":"<p>After more work than I would like to admit, the new redesigned website is finally up. This iteration of the website is statically generated using <a href=\"http:\/\/getpelican.com\">Pelican<\/a>, which seems to be working great so far. I think I am going to play with the design a bit more once I get the time, but until then, this is it.<\/p>\n<p>As for the content: I have no idea what I am going to write about; probably tech, open source and other things that pique my interest, but who knows.<\/p>\n<p>I hope I will manage to find the time to write here, and I'd appreciate feedback on whichever medium you prefer. I don't plan on adding a comment system anytime soon, but you can still find ways to reach me in the <a href=\"https:\/\/stosb.com\/about\/\">about page<\/a>.<\/p>\n<p>Until next time&hellip;<\/p>","category":{"@attributes":{"term":"misc"}}}]}