My main complaint about implementing all of these things in kernel space is that it's simply not necessary -- with netfilter_queue and connmark you can relay all decision making to userspace without losing any generality. The only thing that you might argue is a benefit of using a kernel module is that figuring out the "path" for an application might be easier but I'm not sure I agree. Also Douane simply will not work properly with containers because of how it assumes that everything is in the host namespace.
As an aside, I decided to write my own application-level firewall for GNU/Linux[3] (mainly as an exercise to myself to learn Rust as well as learn more about low-level network programming in Linux). My plan is to make it far more modular than OpenSnitch with an client API so the GUI can be completely separate (and also perhaps allowing different clients to have different policies).
[1]: https://github.com/Douane/douane-dkms/blob/master/douane.c#L... [2]: https://github.com/Douane/douane-dkms/blob/master/douane.c#L... [3]: https://github.com/cyphar/whistled