problem wireguard + ospf + unconnected tunnels
Jason A. Donenfeld
Jason at zx2c4.com
Mon Jul 10 02:46:40 CEST 2017
Thanks for your detailed reports, especially the nice Python
reproducer you sent. And sorry for the delay in getting back to you
and investigating this. I actually don't receive any of your emails. I
don't know if it's because mail.ru has a bad spam score, or because
something sufficiently sketchy that precludes them from being
delivered to my mailbox. Luckily others on the list brought this
thread to my attention.
I successfully debugged and fixed the Python reproducer you sent me.
Could you try the following patch, and see if applying it results in
ospfd working properly?
After you apply that and rebuild the module, be sure to rmmod the old
module and modprobe the new one. Then repeat your tests and see if it
For interested readers on the list, here's what's happening:
* A packet inside the kernel is represented as an sk_buff, or an skb.
* Each socket inside the kernel has a budget of how many skbs it can
allocate for itself.
* When a socket reaches the limit of skbs it can allocate for itself,
it blocks until those skbs are freed.
Meanwhile in WireGuard:
* When a handshake has not been established, packets are queued up to
be sent immediately after a handshake is established.
* There is a maximum of 1024 packets allowed in this queue. Newer
packets push out older packets.
* After 20 unsuccessful attempts to establish a handshake, this queue
In your Python example, you used the same socket to send packets to
both lo and to wg0. lo immediately dropped the packets it couldn't
deliver, whereas wg0 did not, due to the above. After reaching a
per-socket limit on skbs allocated, sendto() simply blocks, thus
preventing packets being sent anywhere using that same socket. Herein
lies the problem.
The solution is to "orphan" packets that WireGuard buffers longterm,
so that they're no longer charged to the socket's maximum limit. Since
the interface maximum is capped (1024) and new packets replace old
packets and the fact that they are all freed after 20 unsuccessful
attempts, this does not cause any sort of unbounded memory growth.
So, the aforementioned problem successfully fixes your Python
reproducer code. Please try it on your routing daemon and let me know
if it also fixes the problem there too?
Thanks again for your help,
More information about the WireGuard