Visual Studio Code Extensions

I switched to Visual Studio Code for my text editing needs a while ago. While not perfect (still no darn CR support), I find it working well for me. However, considering it has a really nice extension model, it would be shame not to improve it a bit. So I made a few extensions of my own.

Render Line Endings

One thing I missed the most was to see line endings. Call it a habit from old python days or call it the craziness, but I often work with all whitespaces shown. And VSCode has a beautiful support for showing whitespaces within the line. But somehow, it won’t show line endings which are whitespace characters too in my book.

Idea of this extension is to work in tandem with the default rendering of whitespace characters and simply add the appropriate character at the end. Now, due to some design decisions in VSCode, extension will never be perfect. For example, VSCode normalizes the file upon loading to use only a single line ending. By the time my extension gets a stab at parsing, the original line ending is already gone. Even worse, CR line ending is still not supported and ticket is going nowhere.

That said, in 95% of cases, one is only dealing with a single line ending anyhow and extension can not only show it but it can also highlight errors (e.g. non-default line ending; i.e. CRLF when LF is expected) or extra trailing whitespaces.

It wasn’t the first extension of this type and it probably won’t be the last one. But it is (currently) the most popular and I’ve gone through a lot of efforts to make it the fastest too. Yes, it might be the same speed (or maybe even a bit slower) on small files but if you load a big file, all changes. My extension is pretty much the only line ending highlighter that doesn’t load the whole darn file in one go but does its work incrementally.

Unicode Code Point

When working with international data, I sometime need to know what character I am exactly looking at. Is it Ohm or is it Omega? To get an answer to this and many other Unicode naming questions, I present you this extension.

It’s not the most popular one nor it’s the most capable one (e.g. you cannot use it to insert Unicode). However, it does what name says, it supports many character combinations other extensions ignore (skin codes, for example), and it supports the latest Unicode 15 draft.

As an interesting tidbit, it’s probably the only status bar extension that also supports double-click - something that VSCode actually is not officially exposing to extensions.

Highlight IP

This is yet another one that solves a problem for me and pretty much only me. At work I quite often end up going over configuration files with IP addresses intermingled with other text. Whether it’s YAML, JSON, or just a text file, I like those IP addresses to pop out.

This extension is going to do exactly that, it will find and highlight IP addresses or subnet definitions wherever in text file they might be. As bonus, it will also check validity of each subnet and highlight as error those that are a bit “wonky”, e.g. 192.168.1.1/24.

This extension will happily churn IPs in background and make you forget its even there.

Color Me Error

The only task of this extension is to highlight any instance of TODO, FIXME, or any other configured word as an error. Reason for this is that I like to have my eyes drawn to such text in my code but I don’t necessarily want to have it in “Problems” tab where every other similar extension likes to place it.

If you really need to track those pesky TODOs, this extension is not for you. This extension is for those who like to have them highlighted but don’t like to be reminded about them too much.

Hourly Beep

I like to be reminded about start of an hour. Be it a coocoo clock, my Casio watch, or this extension. Its only function is to beep upon start of each hour.

Mikrotik Configuration Backup

Backing up Mikrotik configuration is easy. Just save the backup and copy it to your machine.

ssh router.local '/export file=mybackup' $ scp router.local:/mybackup.rsc /backup/mybackup.rsc

This results in a binary file you can directly load upon restore. And that’s ok for the backup. But what if you want to track changes over time? Binary file won’t do. Welcome text export.

Fortunately, we can also get /export to output the data in textual format. Since this data will include things like dates and similar things that change with every execution, we use awk and sed to remove those.

ssh router.local '/export' \
  | tr -d '\r' \
  | awk '{sub(/^ +/, "", $0); if (sub(/\\$/,"")) printf "%s", $0; else print $0}' \
  | sed "s/^# .* by RouterOS/# RouterOS/" \
  | sed "/^# managed by CAPsMAN$/d" \
  | sed "/^# channel: .*, CAPsMAN forwarding$/d" \
  | sed "/^# $/d" \
  > /backup/mybackup.txt

The result is reasonably clean file that can be committed to Git or any version control software of your choice.

Overthinking UART Pinout

Quite a few of my boards have a 4-pin UART output. And it’s always the same: [TXD GND RXD VCC]. But this pinout seems strange to quite a few people. I promise, there’s a method to the madness.

First of all, what is the most common UART pinout and why don’t use it? Well, the most common output I’ve seen on other people boards is [VCC RXD TXD GND] and I hate it because it’s really unforgiving if you accidentally plug it the wrong way. When I started playing with electronics, I used to use this pinout and, after frying a couple of boards, I’ve learned to triple-check that I don’t plug it rotated 180°. Even so, it still makes me nervous.

The other common pinout I’ve seen around is [VCC GND RXD TXD] and this one is slightly better as you can safely rotate it 180°. When it comes to common accidents (180° or off-by-one), it’s really hard to fry the board using this one. But this pinout also has its twin brother [VCC GND TXD RXD] thus ensuring you need 1x1 Dupont connector for each wire.

For my “standard” pinout I wanted to be able to easily switch TXD and RXD lines. Since UART really needs only three pins, it was clear that the first three pins had to be [TXD GND RXD]. This way rotating 180° allows you to connect two cables together allowing for point-to-point connection.

In order to provide power, I just added the extra pin for the final [TXD GND RXD VCC] pinout. If you accidently rotate it 180°, nothing happens. If you plug it off-by-one, nothing happens. And, if you don’t need power, you can plug only the first 3 pins and everything still works.

It’s as full-proof as it gets for me.

My ZFS Settings

In multiple posts so far I’ve created a ZFS pool using pretty much the same parameters. But I never bothered to explain why I chose them. Until now…

From my latest ZFS-related post, I have the following pool creation command:

zpool create -o ashift=12 -o autotrim=on \
    -O compression=lz4 -O normalization=formD \
    -O acltype=posixacl -O xattr=sa -O dnodesize=auto -O atime=off \
    -O encryption=aes-256-gcm -O keylocation=prompt -O keyformat=passphrase \
    -O canmount=off -O mountpoint=none $POOL $DISK

ashift=12

This setting controls the block size of your pool and should match whatever your (spinning) disk uses. Realistically, you’ll probably use 4K sectors thus 12 is a good starting value. Why the heck 12? Well, this is expressed as 2ⁿ and 2¹² is 4 KB. I like to force it because often ZFS might wrongly auto-detect value 9 (512 bytes) which shouldn’t be really used these days. This is not really ZFS’ fault but consequence of some disks being darn liars to preserve compatibility.

Even if you do have 512-byte disks today, any replacement down the road will be at least 4K. Since the only way to change this option is to recreate the pool one should think ahead and go with 4K immediately.

When it comes to SSD setups there might be some benefit in going even higher since SSD usually use 8K or even larger erase blocks. However, since SSDs are much more forgiving when it comes to the random access, most of time it’s simply not worth it because large block sizes will cause other issues (e.g. slack space).

autotrim=on

Support for trim is really important for SSD and completely irrelevant when it comes to the spinning rust. Since my NAS uses good-old hard drives, this setting really doesn’t apply. But I also use ZFS on my laptop and there it makes a huge difference. So I include it always just not to forget it by accident when it matters.

compression=lz4

While zstd seems to be a compression darling, I still prefer lz4 for my local datasets because it’s much easier on the CPU. There’s also an option to turn off compression completely, but I honestly cannot determine any speed improvement in a general case. Using compression is like receiving free space, so why not?

normalization=formD

As ZFS uses Unicode (UTF-8 more specifically), it has an interesting problem that two filenames might look the same but they might have two different expressions. Most known example might be Å which can be expressed either as Å or as combination of A and a separate ring mark. From the point of user, both these are the same. But they have a different binary expression (U+00C5 vs U0041 U+030A).

Setting normalization explicitly just ensures each file name is stored in its canonical Unicode representation and thus things that look the same are going to be the same. I personally like formD on a philosophical level but any normalization will do the same. Just don’t stick with default value of none.

acltype=posixacl

This option allows you to store extra access attributes not covered by a “standard” user/group/world affair. The most common need for these attributes is with SELinux. However, even if you’re not using SELinux, you should enable it as it doesn’t really impact anything if not used. And you might consider using SELinux in the future.

xattr=sa

This option will tell ZFS to store extra access attributes (see above) with the metadata. This is a huge performance boost if you use them. If you don’t use them it has no effect so you might as well future-proof your setup.

dnodesize=auto

Assuming you already save all these extra attributes, it’s obvious they cannot really fit nicely in one metadata node. Unless it’s a big one. Once set, this option (assuming feature@large_dnode=enabled) will allow larger than normal metadata at the cost of some compatibility. Assuming you have ZFS 0.8.4 or above, you really have nothing to worry about.

atime=off

Posix standard specifies that one should always update access time whenever file or directory is accessed. You went into your home directory - update. You opened a file without changing anything - update. These darn updates really stack up and there is really no general use case where you would need to know when the file was read. This flag will turn off these updates.

encryption=aes-256-gcm

I like my datasets encrypted. Ideally one would use full disk encryption but using ZFS native encryption is a close second with unique benefits at a cost of minor data leaks (essentially only ZFS dataset names). And GCM encryption is usually the fastest here.

keyformat=passphrase

Call me old-fashioned but I prefer a passphrase to a binary key. Reason is that I can enter passphrase more easily in a pinch.

keylocation=prompt

For my laptop I keep prompt as a key source so I can easily type it. For servers, I use file:// syntax here since I keep my passphrase on a TmpUsb USB drive. This allows me to reboot server without entering key every time but in the case it’s ever stolen my data is inaccessible.

canmount=off, mountpoint=none

As a rule, I try not to have top-level dataset mountable. I just use it to set defaults and data goes only in sub-datasets.

And that’s all the explanation I’m ready to offer.

Rabbit Managed

One of my first vivid memories when it comes to having fun while programming definitely contains me implementing RC4 encryption in QBasic. Algorithm was perfect. It worked on per-byte text, was simple enough to have at least basic understanding what the heck was happening, and it gave me a bit of “el bandito” feeling as algorithm was leaked. Going over RC4 encouraged me to reinvent the wheel and was a direct cause of my love into creating own encryption algorithms. And I’ve created quite a few…

In time I learned a bit more about encryption. Or at least enough to understand why “rolling your own” is generally a bad idea. With time my beloved RC4 got its ass kicked by cryptoanalysis to be finally deprecated in 2015. My focus meantime went toward block algorithms, most notably Twofish and later AES version of Rijndael. My mind decided to go block cipher route but my heart still longed for good old stream cipher times.

As someone following crypto-world as a hobby, I was surprised I missed a whole stream cipher competition - eSTREAM. At this time it’s already an ancient news but results of that competition are still available in the form of 4 secure software stream ciphers: HC-128, Rabbit, Salsa20/12, and SOSEMANUK. All these eSTREAM finalists are still secure, completely free, and really nostalgia inducing for those with a soft spot for stream ciphers.

One that immediately drew my attention was Rabbit. As name suggests, this one was really fast. Additionally, it has quite understandable method of operation, uses no “exotic” operations, it has a reasonably small state (513 bits), and it’s specified in RFC4503. The only thing I couldn’t find was a C# implementation wrapping it into a SymmetricAlgorithm so it can be easily used with CryptoStream. Well, now there’s one…

If you want to use the Rabbit from C#, take a look at my RabbitManaged class. It derives from SymmetricAlgorithm and exposes ICryptoTransform interface so it can be used with CryptoStream. While it uses 128-bit blocks internally, it also allows usage without padding (i.e. more like a traditional stream algorithm). It also allows for all standard paddings.

Considering wide prevalence of AES, its usage will be limited at best but I believe into not having all eggs in one basket and you might find usage for it still. But damn, it was fun to implement this little gem.

PS: For nostalgia, I also have a SymmetricAlgorithm implementation of RC4.