When reading the drafts (later RFCs) on IKE, it became clear the protocol was complex, with many degrees of freedom. It was also known that isakmpd would be ported to several platforms, each with different APIs to the IPsec stack. There were also a number of proposals for IKE extensions in varying stages of completion. All these facts pointed towards a very modular architecture with distinct APIs between the subsystems. To avoid development complexity, we also decided to map the concepts of the standards fairly directly onto internal data structures.
Given how isakmpd would work (accepting inbound packets, doing some processing in the packet-prescribed context, sending a reply), it felt natural to build a message-based event-driven application. Thus isakmpd looks like most Unix UDP servers, with a main loop consisting of a select call followed by a multiplexor calling the right handlers for the occurring events.
The most common event is packet arrival, handled by the message module which is also responsible for packet validation and context lookup. Another fairly common event is the timeout, dealt with by the timer module. There are also application events, which are upcalls from the controlled application, in our case the IPsec stack. The design of isakmpd allows for other such ``applications'' in the future. This is the reason why it is called isakmpd, instead of iked. IKE is just one possible instantiation of the ISAKMP framework. The upcalls are dealt with by the application module, which to a great extent consists of system-dependent code dealing with the IPsec stack at hand. Currently, there exist three application back-ends, PF_KEY, PF_ENCAP and FreeS/WAN's NetLink API.
For controlling isakmpd there are a couple of modules worth mentioning. The ``user interface'' (UI) module listens for asynchronous events that control different aspects of isakmpd, like debugging level, active connections etc. This is currently done through a FIFO, but the design allows use of sockets or some other IPC mechanism. There is also a configuration module dealing with configuration file parsing, as well as lookups and overrides (via UI) of configuration entries. Last but not least, there is a policy module controlling what kind of SAs are allowed to be negotiated and by whom (see Section 5).
As ISAKMP is a transport-neutral protocol, there is also a transport module, which is actually an abstract class in an object-oriented view. Since IKE only requires UDP as the transport mechanism, there is just one derived class, the udp class. Finally, there is also a low-level network interface module which provides interface-walking, etc.
As all ISAKMP packets belong to ``exchanges,'' we chose to create an exchange abstraction which was mainly a script engine and a data structure accumulating context state to later be carried over into SAs. Therefore, there are exchange and SA modules. They deal with creation, lookup, maintenance, aging, and destruction of these structures. Each exchange has a ``script,'' which is walked for every packet received or transmitted. This makes it easy to create a source file per exchange type, making the code well modularized.
Independent of what exchange is used, there are a lot of common operations that need to be carried out during a negotiation. For this purpose we created separate modules for authentication, encryption, hash computation, and Diffie-Hellman computation. These in turn need more basic modules, like random number generation, long integer math, group math of both modP and elliptic curve kinds, and X.509 certificate management [7].
Lastly, there are miscellaneous modules dealing with things like dynamic loading of code, logging, etc.