セキュリティ
NetBSDにおけるracoon2 IKEデーモンの改善と安定化
Improving and Stabilizing the Racoon2 IKE Daemon in NetBSD (blog.netbsd.org)
要約
Google Summer of Code 2026のプロジェクトとして、NetBSDのracoon2 IKEデーモンの改善と安定化が行われました。主な成果は、IKEv1/IKEv2におけるNATトラバーサル(RFC 3947, 7296)の正確な実装、IPv6サポートの改善とデフォルト化、アドレスマクロの統一、そして自動テストフレームワークの導入です。これにより、racoon2はNAT環境下でもモダンなVPNクライアント(Windows, iOS, Android)をサポートし、より信頼性の高いL2TP/IPsecまたはIKEv2 VPNサーバーとして機能するようになりました。
全文翻訳
The NetBSD Project
NetBSD Wiki Feeds All /Release engineering /Development /The NetBSD Foundation /Networking /General /Ports /Security /Events /Packages Comments
Google Summer of Code 2026 Reports: Improving and Stabilizing the racoon2 IKE Daemon in NetBSD
October 03, 2026 posted by Leonardo Taccari
This report was written by Artem Belan as part of Google Summer of Code 2026.
Introduction & Description
racoon2 is a system to exchange and install security parameters for IPsec. It consists of an IKEv1/IKEv2 key exchange daemon, a security policy management daemon, and a Kerberos-based key exchange daemon. The project lives at zoulasc/racoon2 and is being modernized so that it can serve as a reliable L2TP/IPsec or IKEv2 VPN server on NetBSD and Linux for built-in Windows, iOS and Android VPN clients.
The goal of this GSoC project was to work through that TODO list: implement NAT traversal properly for both IKEv1 and IKEv2 according to the relevant RFCs, make IPv6 works well so racoon2 can be tested with both IPv4 IPv6 properly, clean up the address-macro mess, and build a unit test framework so that the fixes stay fixed. In the end, the daemon can sit behind a NAT device and serve modern VPN clients without any workaround selectors in its configuration, IPv6 works out of the box, and the changes are protected by an automated test suite. All work was done on the gsoc2026 branch and merged upstream through pull requests #13–#39 between June and September 2026.
What was done
IKE fragmentation (RFC 7383)
The fragmentation code was, in the words of the TODO, "old/incomplete": reassembled messages could be misrecognized by the daemon, and oversized packets could crash it. The result of the project is reliable RFC 7383 fragmentation for both IKEv1/IKEv2 on both the sending and the receiving side: large IKE messages are split and put back together correctly, packets that exceed the allowed fragment size are rejected with a clear log message instead of a crash, and exchanging big messages — certificates, large proposals — between the peers no longer silently fails or takes the daemon down.
NAT-OA payloads in IKEv1 Quick Mode (RFC 3947)
At the beginning of the summer the daemon ignored NAT original address payloads on input and never sent them to the peer. The consequence was that the kernel had no idea which addresses the client actually used behind the NAT, so it had to recompute checksums over entire packets — slow, and not what RFC 3947 prescribes. Now the NAT-OA payloads match the RFC's structure, are constructed and sent in Quick Mode, and are parsed positionally on receipt (local address first, peer address second), with a missing payload from the peer tolerated rather than treated as an error. The original addresses are also passed down to the kernel so it can do incremental checksum fixup instead of full recomputation.
Address substitution in NAT-T transport mode (RFC 7296 §2.23.1)
This was the heart of the project and the direct answer to a long-standing TODO item: when a NAT device was in the path, the addresses the peer proposed in phase 2 did not match the responder's configured selectors, so responders needed extra selectors that were valid only on the initiator's side just to pass the selector check — configurations like transport_ike_natt.conf carried them as a workaround, and connections from real clients stayed fragile. The final behaviour follows RFC 7296 §2.23.1: when NAT-T is enabled and the addresses observed on the wire do not match the configured selectors, the observed addresses are substituted into the negotiated selectors, on both IKEv1 and IKEv2. The workaround selectors are no longer needed, and the daemon now properly handles NAT-T traffic on the dedicated UDP port instead of only the initial one.
Address macros in configurations
The wildcard address macros were, in the TODO's words, "the cause of many configuration-related bugs": what worked in an IKEv1 configuration could silently misbehave in IKEv2, one macro behaved as a wildcard in some code paths and as "unknown, wait until we know" in others, and misconfigurations were ignored rather than reported. The project unified them into a single consistent wildcard notion that behaves the same way everywhere, works for both IKEv1 and IKEv2 configurations, and produces clear diagnostics when an address lookup or expansion fails, instead of failing silently and leaving the user to guess why the policy never got installed.
IPv6 support fixed and enabled by default
IPv6 support had existed in racoon2 for years, but it worked crooked: when the interface was configured to use all addresses, the daemon still behaved as if only IPv4 addresses existed — as though the interface were set to use IPv4 only — and prefix-length edge cases were broken, so in practice racoon2 could not be tested with IPv6 at all. During the project these bugs were fixed — address matching, interface address validation on Linux, prefix-length handling — and IPv6 became what a modern daemon should have been: used by default, with no configuration switch to remember. After the project, the same configuration files simply work with IPv6 addresses, and the TODO item about IPv6 is closed on the configuration side; only end-to-end testing with real IPv6 traffic remains.
Policy and proposal negotiation
Before the project, transport mode policies were generated from the generic SA endpoints rather than the addresses configured for the SA, tunnel mode policies could reference the wrong endpoints, and the daemon assembled the negotiated IPsec proposal itself instead of accepting what the peer actually proposed — a frequent source of failed negotiations with real clients, which all bring their own proposals. Now policies in both transport and tunnel modes are generated from the configured SA addresses, and the negotiated proposal is built from the peer's proposal, so interoperability with stock Windows, iOS and Android clients no longer depends on the local configuration guessing everything right.
A unit test framework for the IKE daemon
The project had no automated tests at all; every change had to be validated by reading code and running the daemon by hand. The last part of the summer went into changing that: a small self-contained test framework with no external dependencies is now integrated into the standard build and its tests run under sanitizers. On top of it, four new test programs cover exactly the logic this project introduced — NAT original address payload handling, traffic selector address substitution, wildcard address handling in configurations, and the address matching used when a peer is purged — and the pre-existing crypto self-test was fixed so the whole suite passes cleanly. This matters beyond the project itself: the framework makes it straightforward to add regression tests for the parts of the daemon that still have none, whoever tackles them next.
Documentation, samples and NEWS
Documentation and sample configurations still described the old defaults, so the manual contradicted the shipped behaviour: it still described the old IPv6 behaviour and the pre-substitution selector workarounds. The project synced the docs and samples with the new defaults — IPv6 used by default, fragmentation handled automatically, tunnel endpoints and wildcard addresses used consistently — and added a NEWS entry summarizing all of the GSoC 2026 work for users and downstream packagers.
How to Use
Everything described above is on the gsoc2026 branch of ssszcmawo/racoon2 (merged upstream into zoulasc/racoon2). A quick tour for anyone who wants to try it: Build and install. The repository ships only the autotools sources, so the configure script has to be regenerated