crush depth

No More OpenGL

I'm dropping OpenGL in favour of Vulkan.

No more broken drivers (probably). No more dealing with source code level management of shader code at runtime (no more sombrero). No more broken GLSL shader compilers, for that matter. No more weak typing (no more jcanephora). No more logarithmic depth buffer - Vulkan has reversed floating-point depth buffers accessible without extensions.

Planning to rewrite r2 using Vulkan, yielding r3. A few design issues that were imposed by the OpenGL 3.3 core requirement can be corrected.

Still need to give the Vulkan API a friendly face though, to make it feel like a Java API instead of a C++ API.

Maven Central Signing

A while ago I started having a problem with signature verification when trying to upload to Maven Central.

After three months of intense debugging and a rather long conversation with Sonatype, it turned out that the issue was actually with the signing key.

At the start of 2018, I'd switched to ed25519 signing keys. It turned out that the version of Nexus running on Maven Central didn't support ed25519. To work around this, I created a new RSA key solely intended for signing Maven packages. Bizarrely, this key didn't work either. Nobody could work out why the signatures were failing, and the problem was escalated twice to Sonatype's internal support people.

It turned out that the problem was an ed25519 signature on the new RSA key!

The moral of the story: If you want to deploy to Maven Central, use only RSA keys and make sure that the signatures on those RSA keys only come from other RSA keys. If you fail to do this, you won't get an actionable error message when you try to deploy packages, you'll just get a "Signature verification failed" message. Sonatype are updating their documentation to ensure that nobody else has to lose time to this.

Thanks to Joel Orlina for being patient during those three months and for handling the support teams.

Competing Module Systems

It's been about eight months since the release of Java 9.

I won't bore anyone with the details of everything it introduced as that information is available just about anywhere you care to look. The main thing it added, however, is the subject of this post: The Java Platform Module System.

The JPMS was introduced, and programmers reacted in the normal way that people working in a field that's supposed to demand a rational and critical mind react: They started frothing at the mouth, claiming that Oracle were trying to kill Java, and planning a mass exodus to other more hip languages. Kotlin or Rust, probably. Needless to say, Oracle weren't trying to kill Java. If Oracle wanted to kill Java, they could certainly find a way to do it that didn't require seven expensive years of intense, careful, and painful software engineering. So far, the exodus appears to have been quietly called off.

I'm guessing the people that complained the loudest are the sort of people that write a ton of fragile, error-prone, unsupported reflection hacks and then spew bile when some tiny aspect of the platform changes and their code breaks.

I have a ton of code, none of which I'd describe as legacy. I'm somewhat invested in OSGi for reasons I'll go into shortly.

Today: I'm conflicted and slightly nervous!

I decided when Java 9 came out that I was going to pursue full modularization for all of my projects. As I've said before, my code is already modular because I've been designing it around OSGi. However, in order for it to become modular in the JPMS sense, I'd have to write module descriptors for each project.

I'm developing a commercial (but open-source) game, where the game itself and third party modifications are handled by a well-specified, strongly-versioned module system. Consider something that (from the user's perspective) behaves a bit like the system in OpenTTD (except with the entire game delivered this way, not just third-party addons):


I briefly considered stopping using OSGi and using the JPMS to power the whole system. That experiment fairly quickly ended, though. Let's look at some of the things that OSGi does or has that are important to me:

  1. OSGi has a full repository specification that gives applications the ability to download and install packages at run-time. You tell the system what packages you want, and it fetches those and all of their dependencies. Everything is standardized, from the API to the actual metadata served by repository implementations. Here's an example of a standard repository index (albeit styled with an XSL stylesheet).

  2. OSGi bundles have rich metadata associated with them, including very fine-grained and versioned dependency metadata. If you have a bundle, you can find out very easily what else you need in order to be able to use it. The metadata can also express things beyond simple package dependencies.

  3. OSGi can load and unload modules at run-time, and has standard APIs to do so (and standard APIs that application code can implement in order to react to modules being loaded and unloaded).

  4. OSGi has wide support; it's fairly rare these days to find a Java project that isn't also implicitly an OSGi project. Making something OSGi-compatible is often just a case of adding a single Maven plugin invocation (assuming that the code doesn't make a lot of unfounded assumptions about class loaders).

Let's see what the JPMS has (or hasn't), in comparison:

  1. The JPMS doesn't have anything like a repository specification. The closest analogy is probably fetching things off of Maven Central, but there's no standard API for doing this. Essentially, obtaining modules is Someone Else's Problem.

  2. JPMS modules don't have much metadata associated with them. A module says what packages it exports and upon which other modules it depends. However, it doesn't say anything about which versions of those modules are required. Essentially, you're expected to use a system like Maven. This is Someone Else's Problem.

  3. The JPMS can, in some sense, load modules at run-time via ModuleLayers. There's no support for explicitly unloading a module. There are no standard APIs that code can use to be notified that a module has been loaded. Essentially, you're expected to build your own ad-hoc OSGi-like system on top of module layers. This is Someone Else's Problem.

  4. Most projects haven't even begun to modularize their code. Even in a well-staffed and extremely fundamental project like Google Protobuf, I'm still waiting after six months for them to make a harmless one-line JAR manifest update. I cannot begin to imagine what it would take to push full modularization through a system that slow moving. If a project you depend on hasn't modularized, you're not going to be modularizing either.

The first three points mean that I'd have to invent my own OSGi-like system. I'd have to come up with a uniform, platform-agnostic metadata standard that could be inserted into JAR files in order to specify dependency information. Third party projects (at least those that aren't written specifically for my game engine) aren't going to be interested in adding metadata for the sake of one man's low budget module system. I can't trust JAR files to contain Maven pom.xml files (although many do), as there are plenty of other build systems in use that don't include that information. Even then, you can't just parse a Maven pom.xml, you need to evaluate it. This would mean pulling in Maven APIs as a dependency, and those neither work in a JPMS modular context (because they're not modularized and never will be) nor an OSGi context (because they use their own incompatible module system called Plexus).

Let's assume by some miracle that I get a good percentage of the Java ecosystem to include dependency metadata in a format I can consume. I now need to come up with an API and tools to fetch modules from a repository. That's not hard, but it's still more than not having to do it at all. I'd want version ranges, so I'd also need to write code to solve the versioning problem which is NP-complete. Tricky.

So let's assume by now that I can, given the name of a module, fetch the dependencies at run-time using my shiny new API and metadata. I still need to be able to load and unload that set of modules at run-time, and have code in other modules react properly to that occurring. There aren't any standard APIs to do this in the JPMS, and so I'd have to write my own. Right now, the JPMS is not actually capable of expressing the kind of things that are possible with OSGi bundles, so any system I built would be strictly less capable than the existing OSGi system. At least part of the problem appears to come down to missing APIs in the JPMS, so at least some of this might be less of an issue in the future. Still, it's work I'd have to do.

So let's assume that I can fetch, load, and unload modules at run-time, and code in modules can react to this happening. I still need modules to put in the system, and not many Java projects are modularized. I tried, for a few months, to use only projects that have either added Automatic-Module-Name entries to their JAR manifests, or have fully modularized. It was fairly painful. I'd be limiting myself to a tiny percentage of the vast Java ecosystem if I did this. This, however, is something that OSGi also went through in the early days and is no longer a problem. It's just a matter of time.

So why am I nervous and still conflicted?

The default effect suggests that, just because the JPMS is the default Java module system, the JPMS is the one that developers will turn to. Tool support for JPMS modules is already vastly better in Intellij IDEA than it is for OSGi. In Eclipse, the support is about equal.

The OSGi R7 JAR files will not contain Automatic-Module-Name entries which means that if you have any dependency on any part of OSGi (including parts that are not even used at run-time, like the annotations), your code cannot be fully modularized. If developers are forced to choose between supporting that old module system that nobody uses or that shiny new default module system that everyone's talking (or possibly frothing) about, which one do you think they'll pick?

I'm also aware that this kind of dynamic module loading and unloading is not something that most applications need. For years people were happy with a static (although extremely error-prone) class path mechanism, and the majority of applications are just recompiled and re-deployed when updated. The JPMS can support this kind of deployment sufficiently. Previously, if developers wanted any kind of safe module system at all, they had to turn to OSGi. They might only use it in the context of a static application that is not dynamically updated, but they'd still use it. Why would those same developers still turn to OSGi when the JPMS exists?

Finally, I pay attention to the various new developments to the Java language and JVM and, fairly often, new features are proposed that have subtle (or not-so-subtle) dependencies on the new module system. There are various optimization strategies, for example, that can be enabled if you know that instances of a given type are completely confined to a single module. Unless the VM can be magically persuaded that OSGi bundles are JPMS modules (this is unlikely to happen), then code running in OSGi is very much going to become a second-class citizen.

So, I'm nervous and conflicted. I don't want to build some sort of ad-hoc OSGi-lite system on the JPMS. I don't want to do the work, I don't want to maintain it, and I don't think the result would be very good anyway. I also, however, am unsure about continuing to base my code on a system that's going to have to work hard not to be considered irrelevant. I believe OSGi is the superior choice, but it's not the default choice, and I think that's going to matter more than it should.

I suspect I'm going to finish assisting any remaining projects that I've started helping to modularize, and not do any more. I had decided that I was going to push hard to move all of my projects to requiring Java 9 as part of the modularization effort, but unfortunately this would leave me unable to deploy code on FreeBSD as there's no JDK 9 there and likely won't be. With the new six-month release cycle (and 18-month long-term release cycle), porting efforts will likely be directed towards JDK 11. This means that I won't be able to deploy anything newer than Java 8 bytecode on FreeBSD for at least another six months.

IPv6 And Linux

I wrote a while back about issues with IPv6 on Linux. It turns out that most of the pain occurs for two reasons:

  1. Linux doesn't accept router advertisements by default. If you configure your router to tell everyone on the network that it has a nonstandard MTU, Linux will ignore the advertisements.

  2. Linux will act upon any Packet Too Large messages it receives and in fact will create a temporary route (visible from the ip route command) that has the correct reduced MTU but, for whatever reason, most programs won't use the new route without a restart. That is, if my mail client hangs due to a Packet Too Large message, it won't be able to send any mail until I restart the program.

The first point can be addressed by adding the following to /etc/sysctl.conf:


Usually, net.ipv6.conf.default.accept_ra_mtu is already set to 1, but it's worth being explicit about it.

I also add net.ipv6.conf.default.autoconf=0 because I statically assign addresses.

The second point can be addressed by restarting the program, as sad as that is.

Module Chasing


I'm trying to get to the point where all of my projects are fully modularized as JPMS modules. My code already follows a very modular architecture thanks to designing it around OSGi, but it's necessary to write module descriptors to complete the picture. To write module descriptors, the projects upon which a project depends must first be modularized. This can either mean writing module descriptors for those projects, or it can simply mean assigning an Automatic-Module-Name. Writing a full module descriptor is better, because this means that the project can be used in combination with jlink to produce tiny custom JVM distributions.

My problem is that I have rather a large number of dependencies across all of my projects, and I need to know the most efficient order in which to approach maintainers in order to get them to modularize their projects. If a project A depends on project B, then project A can't be modularized before project B so it's a waste of my time to go asking project A's maintainers before B is modularized.

I wrote a Maven plugin to assist with this problem. It produces reports like this.

The plugin tells me if the current version of a dependency is modularized, if the latest version of the dependency on Maven Central is modularized, and whether the dependency has been fully modularized or simply assigned a name. The table of dependencies is shown in reverse topological order: Start at the top of the table and work downwards, contacting each project maintainer as you go.

Some dependencies will, of course, never be modularized. Whomever published the javax.inject jar, for example, didn't even bother to create a manifest in the jar file. I'm not sure that even constitutes a valid jar file according to the specification. Some dependencies, like javaslang, were renamed (javaslang became vavr) and so code should move to using the newer names instead. Some projects can barely manage to publish to Maven Central (like Xerces) and still appear to use tools and processes from the previous century, so are unlikely to be modularizing any time soon.

Let's Encrypt For Woe And Loss

In a crippling bout of sinusitis, and after reading that Chrome is going to mark http sites as insecure, I decided to put good sense aside and deploy Let's Encrypt certificates on the io7m servers.

I've complained about the complexity of this before, so I started thinking about how to reduce the number of moving parts, and the number of protection boundary violations implied by the average ACME setup.

I decided the following invariants must hold:

  • The web server must not have write access to its own configuration, certificates, or logs. This is generally a given in any server setup. Logging is actually achieved by piping log messages to a log program such as svlogd which is running as a different user. In my case, I can actually go much further and state that the web server must not have write access to anything in the filesystem. This means that if the web server is compromised (by a buffer overflow in the TLS library, for example), it's not possible for an attacker to write to any data or code without first having to find a way to escalate privileges.

  • The web server must have read access to a challenge directory. This is the directory containing files created in response to a Let's Encrypt (LE) challenge.

  • The acme client must have read and write access to the certificates, and it must have write access to a challenge directory, but nothing else in the filesystem. Specifically, the client must not have write access to the LE account key or the directory that the web server is serving. This means that if the client is compromised, it can corrupt or reissue certificates but it can't substitute its own account key and request certificates on behalf of someone else.

  • The acme client must not have any kind of administrative access to the web server. I don't want the acme client helpfully restarting the web server because it thinks it's time to do so.

There are some contradictions here: The acme client must not be able to write to the directory that the web server is serving, and yet the web server must be able to serve challenge responses to the LE server. The acme client must not be able to restart the web server, and yet the web server must be restarted in order to pick up new certificates when they're issued.

I came up with the following:

  • An httpd-reloader service sends a SIGHUP signal to the web server every 30 minutes. This causes the web server to re-read its own configuration data and reload certificates, but does not kill any requests that are in the process of being served and specifically does not actually restart the web server.

  • The acme client writes to a private challenge directory, and a private certificates directory. It doesn't know anything about the web server and is prevented from accessing anything other than those directories via a combination of access controls and chrooting.

  • The web server reads from a read-only nullfs mount of a wwwdata directory, and the challenge directory above is placed in wwwdata/.well-known/acme-challenge via another read-only nullfs mount. The web server also reads from a read-only nullfs mount of the certificates directory above in order to access the certificates that the acme client creates.

  • The acme client is told to update certificates hourly, but the acme client itself decides if it's really necessary to update the certificates each time (based on the time remaining before the certificates expire).

  • The intrusion detection system has to be told that the web server's certificates are permitted to change. The account key is never permitted to change. I don't want notifications every ~90 days telling me the certificates have been modified.

Data flow

I set up all of the above and also took some time to harden the configuration by enabling various HTTP headers such as Strict-Transport-Security, Content-Security-Policy, Referrer-Policy, etc. I'm not going to require https to read and I'm not going to automatically redirect traffic from the http site to the https site. As far as I'm concerned, it's up to the people reading the site to decide whether or not they want https. There are plenty of browser addons that can tell the browser to try https first, and I imagine Chrome is already doing this without addons.

The Qualys SSL Labs result:


Now we can all sleep soundly in the knowledge that a third party that we have no reason whatsoever to trust is telling us that is safe.

Checkstyle Rules

I'm going to start making all projects use a common set of Checkstyle rules rather than having each project carry its own rules around. I can't remember exactly why I avoided doing this in the beginning. I think it may've been that I wasn't confident that I could write one set of rules that would work everywhere. I've decided instead that I'll beat code with a shovel until it follows the rules, rather than beat the rules with a shovel until they follow the code.

Chasing Modules

I've been moving all of the projects I still maintain to Java 9 modules. In order to do this, however, I've needed to assist third party projects upon which I have dependencies to either modularize their projects or publish Automatic-Module-Name entries in their jar manifests. If you try to specify a dependency on a project that either hasn't been modularized or hasn't published an Automatic-Module-Name entry, you'll see this when building with Maven:

[WARNING] ********************************************************************************************************************
[WARNING] * Required filename-based automodules detected. Please don't publish this project to a public artifact repository! *
[WARNING] ********************************************************************************************************************

The reasons for this are documented on Stephen Colebourne's blog.

Here's a table of all of the third party projects upon which I depend, and an indication of the current state of modularization (I'll try to keep this updated as projects are updated):

Project State Updated
fastutil Considering 2018-02-07
jcpp Considering 2018-02-08
ed25519-java Considering 2018-02-09
LWJGL Fully Modularized 2018-02-07
Dyn4j Fully Modularized 2018-02-07
protobuf Ignored? 2018-02-07
antlr In Progress 2018-02-11
autovalue In Progress 2018-02-07
rome In Progress 2018-02-07
JGraphT Automatic Module Names (Full modularization in progress) 2018-02-11
Vavr Automatic Module Names 2018-02-07
commonmark-java Automatic Module Names 2018-02-07
javapoet Automatic Module Names 2018-02-07
xom Unclear 2018-02-07

Generally, if a project isn't planning to either modularize or publish automatic module names, then I'm looking for a replacement for that project.

Signing Issues

I'm having trouble deploying packages to Maven Central. The repository claims that it cannot validate the signatures I provide. I've filed a bug but haven't gotten a response. I'm wondering if it's down to me switching to Curve25519 PGP keys...

New PGP Keys

New PGP keys have been published.

Fingerprint                                       | UID
B84E 1774 7616 C617 4C68 D5E5 5C1A 7B71 2812 CC05 | Mark Raynsford (2018 personal)
F8C3 C5B8 C86A 95F7 42B9 36D2 97E0 2011 0410 DFAF | (2018 release-signing)
Verifying Again

See the the previous blog post:

$ gpg --recv-keys 8168DAE22B15D3EDC722C23D0F15B7D06FA80CB8
$ wget -r
$ cd
$ gpg < checksum.asc | sha512sum --check


How To Verify

This blog was designed to be verifiable:

$ gpg --recv-keys 8168DAE22B15D3EDC722C23D0F15B7D06FA80CB8
$ wget -r
$ find -name '*.asc' -exec gpg --verify {} \;

Note that the 8168DAE22B15D3EDC722C23D0F15B7D06FA80CB8 key ID assumes you're reading this in 2017. By the time 2018 comes around, this blog will be signed with a new key (and a new one for each passing year).

Possible points of failure:

  1. A malicious actor gets the remote keyserver to serve a different key than the one with fingerprint 8168DAE22B15D3EDC722C23D0F15B7D06FA80CB8. Does gnupg verify that a received key had the fingerprint that the user specified on the command line? What if the user specified my name and key comment instead of a fingerprint? The actor at this point might be able to convince you that the signatures on files on are invalid. It might be able to convince you that its own key is mine.

  2. A malicious actor modifies the files and signatures when wget downloads them. The actor can't generate valid signatures for the key 8168DAE22B15D3EDC722C23D0F15B7D06FA80CB8 (unless it can break RSA), but it can try to convince you that its own key is actually my key and therefore have you trust that the data you're seeing is unmodified and was signed by me. If the actor managed to perform step 1 above, then you're completely compromised.

  3. A malicious actor removes some of the signatures. If you didn't know exactly how many pages there should be, you'd not notice if gpg didn't verify one of them.

Step 1 has no technical solution; you need to verify the keys you receive and check the signatures on those keys assuming they come from other keys that you trust. If you're lucky, there is a chain of signatures leading to a key that you do trust with certainty. I have yearly expiring keys, and I sign each new year's keys with the old keys. Unless my keys have been compromised yearly, there's a reasonable chance that the keys you see are mine!

Step 2 is partially mitigated by https, assuming that the actor doesn't have backdoor access to the CA issuing the certificate. The actor can have the CA issue a new certificate, redirect you to a server that the actor controls, decrypt the traffic, modify it, and then re-encrypt it. You'd never know anything was wrong.

Step 3 is manually mitigated by reading the posts by year page and checking that you have at least as many signatures as pages. I may start publishing a CHECKSUMS file that just contains signed SHA512 hashes of every file on the site.

I'm considering using keybase in addition to publishing PGP keys on the public keyservers. I don't do social media, so I'm not sure how much it'd apply to me. I do use GitHub heavily though.

New PGP Key
Hash: SHA512


Pushed a new key for signing commits in Android work. I'll still be
releasing new personal and release signing keys in January (and I'll
be switching to ed25519 keys from RSA).

E134 3512 A805 115A C1A0 1D15 C578 C3C0 C9B1 2BFF
Mark Raynsford (2018 android commit signing)


Back To Java

I initially wrote jstructural as a set of XSLT stylesheets. That quickly became unmaintainable as the complexity of the stylesheets increased. I rewrote them in Java. I eventually got tired of writing documentation in XML (I didn't know that better XML editors existed) so I ended up wanting to add the ability to write documents as S-expressions.

The right way to do this was to redesign jstructural so that it defined a core AST type and added multiple parsers that all produced values of this core type. Converting between documents of different types would then be a matter of parsing using one syntax, and then serializing the AST using another.

The most natural way to express an AST is as a large algebraic data type. Java doesn't have direct support for these yet (although it's slowly getting them via Project Amber). I therefore looked at other JVM languages that did support them, and the choice was either Scala or Kotlin. I chose Kotlin, after multiple nasty experiences with Scala. kstructural was born.

Fast forward to the present day, and I'm utterly sick of working on Kotlin code. The tools are slow. Compilation is slow. The people in charge of the ecosystem think devolving to special snowflake imperative build tools like Gradle is a good idea.

I'm going to do a new Java implementation of the structural language, and I'm probably going to redesign the language to make it even easier to implement. Nowadays, XML editing is fast and painless thanks to various tools (with real-time validation errors). XOM is essentially unmaintained, so I'll replace the XML parsing code with an efficient SAX parser (and actually get lexical information in the parsed AST, unlike with XOM).


Deployed DKIM on the mail server today. All mail that originates from will be signed, and I've published DMARC and ADSP policies that tell other servers to be suspicious of any mail that isn't signed. Seems to be working well.


I've enabled TLS on all domains.

I'm using certificates from These aren't trusted by all browsers, but I don't care all that much. If trust becomes a serious issue at some point, I'll buy real TLS certs. I PGP sign all text on the server anyway, so anyone that really cares about checking to see if some nefarious third party has changed the data in transit can do so, albeit manually.

No, I'm not using Let's Encrypt. I've looked into it several times and I just can't get around the fact that it requires a huge number of moving parts and that the average ACME client requires a ridiculous level of privileges to work properly: If you want any possibility of security, this is what it takes to get it.

At a minimum:

  • The client has to be able to make connections to a remote server in order to download an extremely security-critical bit of data (the certificate). If this step fails for any reason (the remote side being unavailable, breakage in the client), the existing certificate expires and the https service is dead.

  • The client has to be intelligent enough to know when to try to get a new certificate. When is the right time? Who knows. Trying to request a new certificate a minute before the current one expires is suicidally reckless. Trying to do it the day before might be acceptable, but what if it goes wrong? Is a day long enough to try to fix a problem in something as gruesomely complex as the average ACME client? The availability of your https service essentially becomes tied to the availability of the ACME server. This wouldn't be so bad if the update was a yearly thing and could be planned for, but LE certificates are valid for 90 days.

  • The client has to be able to write to the directory being served by the http server in order to be able to respond to challenges. If the client is compromised, it has the ability to trash the served web site(s). I run my services in a highly compartmentalized manner, and having to allow this would be horrible. There are other challenge types, such as publishing a DNS record containing a response to a challenge, but those have the same problem of what should be an unprivileged program having to cross a security boundary and threatening the integrity of another service's data.

  • The client has to be able to write to the http server's configuration data (in order to publish the new certificate). Again, if the client is compromised, it can trash the http server's configuration. If the update fails here, the existing certificate expires and the https service is dead.

  • Assuming that the client actually does manage to respond to a challenge and get a certificate issued, and does actually manage to write that certificate to the filesystem, the problem then becomes getting the https server to use it. Most servers read certificates once on startup and don't reread them. Therefore, the client needs privileges to restart the server. This is totally unacceptable; no service should ever be able to forcefully restart another.

There are so many possible points of failure and every single one results in a broken https service at best, or a system compromise at worst. I'm vaguely surprised at how little in the way of criticism I've seen online of the complexity of Let's Encrypt given the usual reaction of information security experts to any new software system. To paraphrase Neal Stephenson, the usual reaction is to crouch in a fetal position under a blanket, screaming hoarsely that the new system is way too complex and is a security disaster. I have to wonder how many unpublished attacks against the ACME protocol there are out there.

Contrast this to a typical TLS certificate provider: I download a text file once a year and put it on the server. I then restart the https service. Done. No extra software running, no other points of failure.

Maven JavaDoc Plugin Fixed

The Maven JavaDoc plugin 3.0.0 is finally ready for release. This means that I can migrate 60+ projects to Java 9 and finally get the new versions pushed to Central.

Big thanks to Robert Scholte who worked hard to ensure that everything worked properly, and even got my rather unusual usage of the plugin (aggregating documentation into a single module) working as well.

Obstructing JavaDoc

I've been anxiously awaiting the 3.0.0 release of the maven-javadoc-plugin for weeks, and in an ironic twist of fate, I'm now responsible for delaying the release even further.

I found two rather nasty bugs in the version that was to become 3.0.0, but submitted a fix for the first and had it merged. The second problem seems like it's going to take rather more work to fix though, and my message asking for implementation advice to the javadoc-dev list is currently sitting in a moderation queue.

Expected But Got


What To Save And Throw Away

What to save and throw away?

pr?The last hour is on us both?mr.s?tuck this little kitty into the impenetrable brainpan?

pr?Contents under pressure?Do not expose to excessive heat, vacuum, blunt trauma, immersion in liquids, disintegration, reintegration, hypersleep, humiliation, sorrow or harsh language?

pr?When the time comes, whose life will flash before yours?

pr?A billion paths are here inside me? pr?yes, yes, yes, Bernhard, 110? pr?potential, jewels, jewels, yes, jewels? %

Decided to kill off some old packages. jnull and jfunctional in particular I've used in just about every project I've ever worked on. There's really very little reason for them to exist anymore though. Java 8 added Objects.requireNotNull which standardized terse null checking. Noone cares about the @NonNull annotations (including myself). The entire contents of jfunctional were made redundant by Java 8. Both of these packages served their purposes well back in the days of Java 6 when they were first designed, but now they're just a burden.

It's good to throw away code.

Maven Java 9 Bugs

I'm still waiting on a set of issues to be resolved in order to push modules to all of my projects.

  • MJAVADOC-489 causes JavaDoc generation to fail when one module requires another.

  • MDEP-559 causes the dependency:analyze goal to fail. I use this goal as part of all my builds in order to keep dependencies clean and correct. Getting this fixed depends on MSHARED-660.

I've also removed japicmp from all of my builds. I don't want to disparage the project at all; it's good at what it does, but using it would require using custom MAVEN_OPTS on JDK 9, and that's just not good enough. I'm in the process of writing a replacement for japicmp and will announce it within the next few weeks.

TCP MSS Clamping

Instead of using a non-default MTU on my network, I've instead implemented TCP MSS clamping.

Specifically, I reset all of the interfaces on my networks back to using an MTU of 1500 (including those on the router), and added the following pf rule:

scrub on $nic_ppp max-mss 1440

That rule clamps the maximum TCP segment length on the PPP interface to 1440. Why 1440? It's essentially down to the per-packet overhead of each protocol that's involved. Typically, that'll be 40 or so bytes for an IPv6 packet header, 8 bytes for PPPoE, and some loose change.

So far, nothing has broken with the new settings. No TLS handshake failures, no sudden broken pipes on SSH sessions, no issues sending mail.

IPv6 And MTU Woes

I've just recently deployed IPv6. Everything went well except for one painful issue that is still not really resolved my satisfaction. To recount the story requires covering quite a bit of ground and digging through a pile of acronyms. Hold on tight!

My ISP provides a native /48 network per customer. That means that I get a mere 1208925819614629174706176 public IP addresses spread over 65536 /64 networks to use as I please.

I want to use my existing FreeBSD router to do the routing for the individual networks. I want to do this for several reasons:

  1. The ISP-provided box is a standard consumer router and is fairly limited in what it can do. It's not actively harmful; it's a respectable brand and fairly powerful hardware, but it's still only a consumer-grade box with a web interface.

  2. I'd rather have the intricate configuration details of my network be stored in text configuration files on commodity hardware and on an operating system that I mostly trust. The ISP-provided box runs Linux on proprietary hardware and only provides shell access via an undocumented (authenticated) backdoor (side-door?).

  3. I trust myself to write safe pf rules.

  4. Exposing the FreeBSD machine directly to the WAN eliminates one routing hop.

However, in order to allow my FreeBSD machine to do the routing of the individual networks (as opposed to letting the entirely optional ISP-provided box do it), I had to get it to handle the PPP connection. The machine doesn't have a modem, so instead I have to run the ISP-provided modem/router in bridging mode and get the FreeBSD machine to send PPP commands using the PPPoE protocol. Encouragingly, my ISP suggested that yes, I should be using FreeBSD for this. It's a testament to the quality of IDNet: They are a serious technical ISP, they don't treat their customers like idiots, and they respect the freedom of choice of their customers to use whatever hardware and software they want.

For those that don't know, limitations in PPPoE mean that the MTU of the link is limited to at most 1492. For reference, most networks on the internet are using an MTU of 1500. In IPv4, if you send a packet that's larger than your router's MTU, the packet will be fragmented into separate pieces and then reassembled at the destination. This has, historically, turned out to be a rather nasty way to deal with oversized packets and therefore, in IPv6, packets that are larger than the MTU will be rejected by routers and will result in Packet Too Large ICMPv6 messages being returned to the sender.

In effect, this means that IPv6 networks are somewhat less tolerant of misconfigured MTU values than IPv4 networks. Various companies have written extensively about fragmentation issues.

So why am I mentioning this? Well, shortly after I'd enabled IPv6 for the network and all services, I suddenly ran into a problem where I couldn't send mail. The symptom was that my mail client would connect to the SMTP server, authenticate successfully, send an initial DATA command, and then sit there doing nothing. Eventually, the server would kick the client due to lack of activity. After asking on the mailing list for my mail client, Andrej Kacian pointed me at a thread that documented someone dealing with MTU issues. After some examination with Wireshark, I realized that my workstation was sending packets that were larger than the PPPoE link's MTU of 1492. My FreeBSD machine was dilligently responding with Packet Too Large errors, but for whatever reason, my Linux workstation was essentially ignoring them. Some conversations on the #ipv6 Freenode IRC channel have suggested that Linux handles this very badly. Worse, it seems that the MTU related issues are sporadic: Sometimes it works without issue, other times not.

The "solution" seems to be this: Set the MTUs of all interfaces on all machines in my network to 1492. If I, for example, set the MTU of my workstation's network interface to 1500 and set the FreeBSD router's interfaces to 1492, I can no longer SSH reliably into remote sites, and the majority of TLS handshakes fail. No Packet Too Large errors are generated, which seems counter to my understanding of how this stuff is supposed to work. I very much dislike having to use a non-default MTU on my network: It seems like I will inevitably forget to set it on one or more machines and will run into bizarre and intermittent network issues on that machine.

Some further conversation on the #ipv6 IRC channel suggests that I should not have to do this at all. However, I've so far spent roughly ten hours trying to debug the problem and am exhausted. Using a non-standard MTU in my LAN(s) works around the issue for now, and I'll re-examine the problem after my capacity for suffering has been replenished.

2018-02-23: Update: IPv6 And Linux

Maven Plugins Are Not Ripe Yet

I wanted to start moving all my projects to Java 9, but quickly discovered that a lot of Maven plugins I depend on aren't ready for Java 9 yet.


Chemriver/A on Vimeo


Chemriver/B on Vimeo


Sources available at GitHub.

Reproducible Builds

Considering moving to producing 100% reproducible builds for all of my packages.

It seems fairly easy. The following changes are required for the primogenitor:

  • Stop using The commit ID is enough!

  • Use the reproducible-build-maven-plugin to strip manifest headers such as Built-By, Build-JDK, etc, and repack jar files such that the timestamps of entries are set to known constant values and the entries are placed into the jar in a deterministic order.

  • Strip Bnd-LastModified and Tool headers from bundle manifests using the <_removeheaders> instruction in the maven-bundle-plugin configuration.

  • Stop using version ranges. This may be too painful.

Some early experiments show that this yields byte-for-byte identical jar files on each compile. This is pretty impressive.

The one open issue: Oracle (or OpenJDK's) javac appears to produce completely deterministic output; there aren't any embedded timestamps or other nonsense. However, someone building the packages from source isn't guaranteed to be using an Oracle JDK. I could use the Enforcer plugin to check that the user is using a known-deterministic JDK, but it would be pretty obnoxious to break builds if they aren't. Perhaps a warning message ("JDK is not known to produce deterministic output: Build may not be reproducible!") is enough.

Simulating Packet Loss And Damage

I'm currently working on some code that implements a simple reliable delivery protocol on top of UDP. UDP is used because latency must be minimized as much as possible.

In order to test that the protocol works properly in bad network conditions, I need a way to simulate bad network conditions. For example, I'd like to see how the protocol implementation copes when 50% of packets are lost, or when packets arrive out of order.

The Linux kernel contains various subsystems related to networking, and I found that a combination of network namespaces and network emulation was sufficient to achieve this.

The netem page states that you can use the tc command to set queuing disciplines on a network interface. For example, if your computer's primary network interface is called eth0, the following command would add a queueing discipline that would cause the eth0 interface to start dropping 50% of all traffic sent:

# tc qdisc add dev eth0 root netem loss 50%

This is fine, but it does create a bit of a problem; I want to use my network interface for other things during development, and imposing an unconditional 50% packet loss for my main development machine would be painful. Additionally, if I'm running a client and server on the same machine, the kernel will route network traffic over the loopback interface rather than sending packets to the network interface. Forcing the loopback interface to have severe packet loss and/or corruption would without a doubt break a lot of software I'd be using during development. A lot of software communicates with itself by sending messages over the loopback interface, and disrupting those messages would almost certainly lead to breakages.

Instead, it'd be nice if I could create some sort of virtual network interface, assign IP addresses to it, set various netem options on that interface, and then have my client and server programs use that interface. This would leave my primary network interface (and loopback interface) free of interference.

This turns out to be surprisingly easy to achieve using the Linux kernel's network namespaces feature.

First, it's necessary to create a new namespace. You can think of a namespace as being a named container for network interfaces. Any network interface placed into a namespace n can only see interfaces that are also in n. Interfaces outside of n cannot see the interfaces inside n. Additionally, each namespace is given its own private loopback interface. For the sake of example, I'll call the new namespace virtual_net0. The namespace can be created with the following command:

# ip netns add virtual_net0

The list of current network namespaces can be listed:

# ip netns show

Then, in order to configure interfaces inside the created namespace, it's necessary to use the ip netns exec command. The exec command takes a namespace n and a command c (with optional arguments) as arguments, and executes c inside the namespace n. To see how this works, let's examine the output of the ip link show command when executed outside of a namespace:

# ip link show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: enp3s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
    link/ether f0:de:f1:7d:2a:02 brd ff:ff:ff:ff:ff:ff

You can see that it shows the lo loopback interface, and my desktop machine's primary network interface enp3s0. If the same command is executed inside the virtual_net0 namespace:

# ip netns exec virtual_net0 ip link show
1: lo: <LOOPBACK> mtu 65536 qdisc noqueue state DOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

The only interface inside the virtual_net0 is lo, and that lo is not the same lo from the previous list - remember that namespaces get their own private lo interface. One obvious indicator that this is not the same lo interface is that the lo outside of the main system is in the UP state (in other words, active and ready to send/receive traffic). This namespace-private lo is DOWN. In order to do useful work, it has to be brought up:

# ip netns exec virtual_net0 ip link set dev lo up
# ip netns exec virtual_net0 ip link show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

We can then create virtual "dummy" interfaces inside the namespace. These look and behave (mostly) like real network interfaces. The following commands create a dummy interface virtual0 inside the virtual_net0 namespace, and assign it an IPv6 address fd38:73b9:8748:8f82::1/64:

# ip netns exec virtual_net0 ip link add name virtual0 type dummy
# ip netns exec virtual_net0 ip addr add fd38:73b9:8748:8f82::1/64 dev virtual0
# ip netns exec virtual_net0 ip link set dev virtual0 up

# ip netns exec virtual_net0 ip addr show virtual0
2: virtual0: <BROADCAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default qlen 1000
    link/ether aa:5f:05:93:5c:1b brd ff:ff:ff:ff:ff:ff
    inet6 fd38:73b9:8748:8f82::1/64 scope global
       valid_lft forever preferred_lft forever

In my case, I also created a second virtual1 interface and assigned it a different IPv6 address. It's then possible to, for example, run a client and server program inside that network namespace:

# ip netns exec virtual_net0 ./server
server: bound to [fd38:73b9:8748:8f82::1]:9999

# ip netns exec virtual_net0 ./client
client: connected to [fd38:73b9:8748:8f82::1]:9999

The server and client programs will do all of their networking in the virtual_net0 namespace and, because the Linux kernel knows that the addresses of the network interfaces are both on the same machine, the actual traffic sent between them will travel over the virtual_net0 namespace's lo interface.

A program like Wireshark can be executed in the virtual_net0 namespace and used to observe the traffic between the client and server by capturing packets on the lo interface.

Now, we want to simulate packet loss, corruption, and reordering. Well, unsurprisingly, the tc command from netem can be executed in the virtual_net0 namespace, meaning that its effects are confined to interfaces within that namespace. For example, to lose half of the packets that are sent between the client and server:

# ip netns exec virtual_net0 tc qdisc add dev lo root netem loss 50%

Finally, all of the above can be cleaned up by simply deleting the namespace:

# ip netns del virtual_net0

This destroys all of the interfaces within the namespace.

Bhante Henepola Gunaratana

“Discipline” is a difficult word for most of us. It conjures up images of somebody standing over you with a stick, telling you that you’re wrong. But self-discipline is different. It’s the skill of seeing through the hollow shouting of your own impulses and piercing their secret. They have no power over you. It’s all a show, a deception. Your urges scream and bluster at you; they cajole; they coax; they threaten; but they really carry no stick at all. You give in out of habit. You give in because you never really bother to look beyond the threat. It is all empty back there. There is only one way to learn this lesson, though. The words on this page won’t do it. But look within and watch the stuff coming up—restlessness, anxiety, impatience, pain—just watch it come up and don’t get involved. Much to your surprise, it will simply go away. It rises, it passes away. As simple as that. There is another word for self-discipline. It is patience.

-- Bhante Henepola Gunaratana


If you're reading this, then the migration to Vultr was successful. Additionally, this site should now be accessible to IPv6 users.

Host          | IPv4         | IPv6
------------------------------------------------------------------------      | | 2001:19f0:0005:061d:f000:0000:0000:0000/64 |  | 2001:19f0:0005:0752:f000:0000:0000:0000/64
A Change Of Scenery

I'm looking at changing my VPS provider from DigitalOcean to Vultr. These were the top two contenders when I initially chose a provider. I can't fault DigitalOcean's service, but Vultr have better pricing and give more control over DNS details such as PTR records.

I have the configurations ready to go, so I suspect I'll make the move over the next few days. I'll be taking this opportunity to enable IPv6 for the http and smtp services. Expect outages!