ddn.api.net.dtls

DDN DTLS API.

This module provides interfaces for DTLS (Datagram Transport Layer Security) connections over UDP or other datagram transports. DTLS provides the same security guarantees as TLS but for unreliable datagram transports.

Key differences from TLS:

  • Flight-based handshake with retransmission
  • Message fragmentation for MTU compliance
  • Anti-replay protection via sliding window
  • Cookie exchange for DoS mitigation
  • One-to-many peer model (one UDP socket, many peers)

Implementations may be provided by:

  • Pure D implementation (ddn-net-tls)
  • OpenSSL backend (ddn-net-tls-openssl)
  • GnuTLS backend (ddn-net-tls-gnutls)

Example (client):

import ddn.api.net.dtls;

auto transport = new SocketDtlsTransport(udpSocket);
auto timer = new PollDtlsTimer();
auto dtls = createDtlsEngine(transport, timer, "example.com");
dtls.setMinVersion(DtlsVersion.DTLS_1_2);

while (dtls.handshake() != TlsProgress.DONE) {
   // poll and process I/O
}

auto peer = dtls.getPeer(serverAddr);
peer.write(cast(ubyte[])"Hello DTLS!");

Example (server):

import ddn.api.net.dtls;

auto dtls = createDtlsEngine(transport, timer);
dtls.setCertificateChain(certChain);
dtls.setPrivateKey(privateKey);

// Process incoming datagrams
dtls.processDatagram(data, senderAddr);

// Check for established peers
foreach (peer; dtls.peers()) {
   if (peer.isConnected) {
       ubyte[4096] buf;
       auto result = peer.read(buf[]);
       // handle data
   }
}

Types 26

enumDtlsVersion : ushort

DTLS protocol version identifiers.

Note

DTLS version numbers are the bitwise complement of TLS version numbers.

TLS 1.2 = 0x0303, DTLS 1.2 = 0xFEFD. There is no DTLS 1.1. The enum uses ushort because version numbers are 16-bit values on the wire.

DTLS_1_2 = 0xFEFDDTLS 1.2 (RFC 6347) — widely deployed.
DTLS_1_3 = 0xFEFCDTLS 1.3 (RFC 9147) — newest version.

Reasons for DTLS peer eviction.

When a peer is removed from the connection table, this enum indicates why the eviction occurred. Used in the eviction callback.

HANDSHAKE_TIMEOUTHandshake did not complete within the timeout period.
IDLE_TIMEOUTNo activity from the peer for too long.
CAPACITY_LIMITMaximum peer capacity reached, LRU peer evicted.
HANDSHAKE_ERRORFatal error during handshake.
ALERT_RECEIVEDPeer sent close_notify or fatal alert.
MANUALApplication explicitly called evictPeer().

Network address for datagram endpoints.

Represents an IPv4 or IPv6 address with port number. Used to identify DTLS peers since datagrams don't have persistent connections.

Fields
private ubyte[16] addr_
private ushort port_
private Family family_
Methods
DatagramEndpoint ipv4(ubyte[4] addr, ushort port) @safe pure nothrow @nogcCreates an IPv4 socket address.
DatagramEndpoint ipv6(ubyte[16] addr, ushort port) @safe pure nothrow @nogcCreates an IPv6 socket address.
Family family() @property const @safe pure nothrow @nogcReturns the address family.
ushort port() @property const @safe pure nothrow @nogcReturns the port number.
const(ubyte)[] toBytes() const return @safe pure nothrow @nogcReturns the address bytes.
bool opEquals(ref const DatagramEndpoint other) const @safe pure nothrow @nogcCompares two socket addresses for equality.
size_t toHash() const @safe pure nothrow @nogcComputes a hash for use in associative arrays.
bool isValid() const @safe pure nothrow @nogcReturns true if this is a valid (non-UNSPEC) address.
Nested Templates
FamilyAddress family.
interfaceDtlsTransport

Datagram transport interface for DTLS.

Abstracts the underlying datagram socket (UDP, etc.) so that DTLS implementations can work with any transport. Implementations are provided by the application (e.g., wrapping a UDP socket).

Thread safety: Implementations should document their thread-safety guarantees. The DTLS engine assumes single-threaded access.

Methods
ptrdiff_t recvFrom(ubyte[] buffer, out DatagramEndpoint sender)Receives a single datagram.
ptrdiff_t sendTo(const(ubyte)[] data, DatagramEndpoint dest)Sends a single datagram to the given address.
PollHandle pollHandle() @propertyReturns a handle for event loop registration.
bool isOpen() @propertyReturns true if the transport is open and usable.
void close()Closes the transport.
interfaceDtlsTimerSink

Timer interface for DTLS retransmission.

DTLS requires flight retransmission timers with exponential backoff. This interface allows the DTLS engine to schedule timeouts without being coupled to a specific event loop.

Implementations should integrate with the application's event loop (EVE, libevent, etc.) or use manual polling with nextTimeoutMs().

Methods
void scheduleTimeout(Duration delay, void delegate() onTimeout)Schedules a timeout callback.
void cancelTimeout()Cancels any previously scheduled timeout.
interfaceDtlsPeer

Represents an established DTLS connection to a single peer.

Each peer has independent encryption state, sequence numbers, and anti-replay windows. The DtlsPeer object is obtained from DtlsEngine after a successful handshake.

Thread safety: NOT thread-safe. All calls must be serialized with the owning DtlsEngine's operations.

Methods
TlsResult read(ubyte[] buffer)Reads decrypted application data from this peer.
TlsResult write(const(ubyte)[] data)Writes application data to be encrypted and sent to this peer.
TlsProgress shutdown()Initiates graceful shutdown (sends close_notify).
DatagramEndpoint address() @propertyReturns the peer's network address.
DtlsVersion negotiatedVersion() @propertyReturns the negotiated DTLS version.
string cipherSuite() @propertyReturns the negotiated cipher suite name.
string alpnProtocol() @propertyReturns the negotiated ALPN protocol.
TlsCertificateChain peerCertificates() @propertyReturns the peer's certificate chain.
bool isConnected() @propertyReturns true if the handshake is complete and connection is established.
DtlsConnectionId connectionId() @propertyReturns the peer's Connection ID, if negotiated.
void requestNewConnectionId()Requests a new Connection ID from the peer.
TlsResult writeEarlyData(const(ubyte)[] data)Writes early data before the handshake completes.
bool usedEarlyData() @propertyReturns true if this connection used 0-RTT early data.
SrtpProfile negotiatedSrtpProfile() @propertyReturns the negotiated SRTP profile, if DTLS-SRTP was negotiated.
SrtpKeyingMaterial exportSrtpKeyingMaterial()Exports SRTP keying material after DTLS-SRTP handshake.

Information provided to the DTLS verification callback during handshake.

Parallel to TlsVerifyInfo from the TLS API, but uses DtlsVersion instead of TlsVersion since DTLS has different version numbering.

Fields
TlsCertificateChain chainThe peer's certificate chain.
string hostnameThe hostname being verified (from SNI or client engine argument).
DtlsVersion negotiatedVersionThe negotiated DTLS version.
string cipherSuiteThe negotiated cipher suite name.
aliasDtlsVerifyCallback = bool delegate(scope ref const DtlsVerifyInfo info)

Callback type for custom certificate verification.

Called after standard verification (if any) completes. Return true to accept the connection, false to reject.

Parameters

infoVerification context including certificate chain, hostname, negotiated version, and cipher suite.

Returns

true to accept the certificate, false to reject.
aliasDtlsEvictCallback = void delegate(DatagramEndpoint address, DtlsEvictReason reason) @safe

Callback type for peer eviction notifications.

Parameters

addressThe address of the evicted peer.
reasonThe reason for eviction.
interfaceDtlsEngine

Main DTLS engine interface.

Supports both client and server roles. For servers, one engine handles multiple peers on a single UDP socket. For clients, typically one engine per connection.

Thread safety: NOT thread-safe. All method calls must be serialized by the caller. For multi-threaded servers, use one of:

  1. Single thread for all DTLS operations (recommended for event-loop designs)
  2. External synchronization (mutex) around all engine method calls
  3. Separate DtlsEngine instances per thread, each with different UDP sockets
Methods
void setCertificateChain(const(ubyte[])[] derCerts)Sets the certificate chain (DER-encoded).
void setPrivateKey(string pemKey)Sets the private key (PEM-encoded).
void setTrustStore(TlsTrustStore trustStore)Sets the trust store for certificate verification.
void setMinVersion(DtlsVersion ver)Sets the minimum DTLS version.
void setMaxVersion(DtlsVersion ver)Sets the maximum DTLS version.
void setMtu(size_t mtu)Sets the MTU for handshake fragmentation.
void setAlpnProtocols(string[] protocols)Sets the ALPN protocols to offer/accept.
void setVerifyCallback(DtlsVerifyCallback callback)Sets a custom certificate verification callback.
void setVerifyMode(TlsVerifyMode mode)Sets the certificate verification mode.
TlsProgress handshake()Drives the DTLS client handshake.
TlsProgress processDatagram(const(ubyte)[] data, DatagramEndpoint from)Processes a received datagram.
TlsProgress checkTimers()Checks all peers for retransmission timeouts and performs cleanup.
DtlsPeer getPeer(DatagramEndpoint addr)Gets a connected peer by address.
DtlsPeer[] peers()Gets all connected peers.
void setHandshakeTimeout(Duration timeout)Sets the handshake timeout.
void setIdleTimeout(Duration timeout)Sets the idle timeout for established connections.
void setMaxPeers(size_t limit)Sets the maximum number of concurrent peers (server only).
void setMaxHandshakingPeers(size_t limit)Sets the maximum peers in handshake state.
size_t peerCount() @propertyGets the number of active peers (including those mid-handshake).
void evictPeer(DatagramEndpoint addr)Manually evicts a peer.
size_t pruneIdlePeers(Duration idleTimeout)Removes all peers idle longer than the given duration.
void setOnPeerEvicted(DtlsEvictCallback callback)Sets a callback invoked when a peer is evicted.
void enablePmtuDiscovery(bool enable)Enables or disables Path MTU Discovery.
size_t getEffectiveMtu(DatagramEndpoint peer)Gets the current effective MTU for a peer.
void setOnMtuChanged(DtlsMtuChangedCallback callback)Sets a callback invoked when a peer's path MTU changes.
void enableConnectionId(bool enable)Enables or disables Connection ID support.
void setConnectionIdLength(ubyte length)Sets the local Connection ID length.
void setOnPeerMigrated(DtlsPeerMigratedCallback callback)Sets a callback invoked when a peer's address changes (migration detected).
void enableSessionResumption(bool enable)Enables or disables session resumption.
void setSessionTicketLifetime(Duration lifetime)Sets the session ticket lifetime.
void setMaxEarlyDataSize(size_t bytes)Sets the maximum early data size the server will accept.
void setEarlyDataReplayProtection(EarlyDataReplayProtection mode)Sets the replay protection strategy for early data.
void setEarlyDataTimeWindow(Duration window)Sets the time window for TIME_WINDOWED replay protection.
void setOnSessionTicket(DtlsSessionCallback callback)Sets a callback invoked when the client receives a session ticket.
void setOnEarlyData(DtlsEarlyDataCallback callback)Sets a callback invoked when the server receives early data.
void resumeWithSession(scope ref const DtlsSessionInfo session)Initiates a session resumption handshake using a stored session.
void setSrtpProfiles(const(SrtpProfile[]) profiles)Sets supported SRTP protection profiles for DTLS-SRTP.
TlsProgress flush()Flushes any pending outgoing datagrams.

Connection ID for DTLS 1.3 peer identification.

When Connection ID is negotiated, peers include the peer's CID in the record header instead of relying on the 4-tuple (src/dst IP+port). This allows connections to survive NAT rebinding, mobile roaming, and multi-path changes.

A CID of length 0 means "no CID" (disabled).

Fields
private ubyte[] id_
Methods
DtlsConnectionId create(ubyte[] id) @safe pure nothrow @nogcCreates a Connection ID from raw bytes.
DtlsConnectionId none() @safe pure nothrow @nogcCreates an empty (disabled) Connection ID.
const(ubyte)[] bytes() const return @safe pure nothrow @nogcReturns the raw CID bytes.
ubyte length() @property const @safe pure nothrow @nogcReturns the CID length in bytes (0 = disabled).
bool isEnabled() @property const @safe pure nothrow @nogcReturns true if a CID is present (non-zero length).
bool opEquals(ref const DtlsConnectionId other) const @safe pure nothrow @nogcCompares two CIDs for equality.
size_t toHash() const @safe pure nothrow @nogcComputes a hash for use in associative arrays.

DTLS session information for resumption.

Contains the opaque session ticket and metadata needed to resume a DTLS 1.3 session without a full handshake.

Fields
ubyte[] ticketOpaque session ticket bytes (issued by server).
Duration lifetimeTicket lifetime hint in milliseconds (server-provided).
Duration ticketAgeTicket age (time since ticket was issued, for age obfuscation).
ubyte[] resumptionPskTLS 1.3 resumption PSK derived from the original handshake.
string serverNameServer hostname (for SNI on resumption).
ushort cipherSuiteCipher suite negotiated in the original session.
size_t maxEarlyDataSizeMaximum early data size advertised by the server (0 = not supported).
DatagramEndpoint serverAddressNetwork address of the server (for reconnection).

Replay protection strategy for 0-RTT early data.

Different applications have different tolerance for replay risk. The chosen strategy determines how the server detects and rejects replayed early data.

SINGLE_USE_TICKETSEach session ticket can only be used once. Most secure.
TIME_WINDOWEDAccept early data within a short time window.
APPLICATION_MANAGEDApplication handles replay detection via idempotency keys.
enumSrtpProfile : ushort

SRTP protection profiles (RFC 5764).

Negotiated during DTLS-SRTP handshake to establish keying material for Secure RTP media streams.

SRTP_AES128_CM_HMAC_SHA1_80 = 0x0001SRTPAES128CMHMACSHA1_80 (RFC 5764 §4.1.2).
SRTP_AES128_CM_HMAC_SHA1_32 = 0x0002SRTPAES128CMHMACSHA1_32 (RFC 5764 §4.1.2).
SRTP_AEAD_AES_128_GCM = 0x0007SRTPAEADAES128GCM (RFC 7714).
SRTP_AEAD_AES_256_GCM = 0x0008SRTPAEADAES256GCM (RFC 7714).

SRTP keying material exported from a DTLS-SRTP handshake.

Contains the master key and salt for both client and server directions. The actual SRTP encryption/decryption is performed by a separate SRTP library.

Fields
ubyte[] clientMasterKeyClient-to-server master key.
ubyte[] serverMasterKeyServer-to-client master key.
ubyte[] clientMasterSaltClient-to-server master salt.
ubyte[] serverMasterSaltServer-to-client master salt.
aliasDtlsMtuChangedCallback = void delegate(DatagramEndpoint peer, size_t oldMtu, size_t newMtu)

Callback type for MTU change notifications.

Parameters

peerThe peer whose path MTU changed.
oldMtuPrevious MTU value.
newMtuNew MTU value.
aliasDtlsPeerMigratedCallback = void delegate(DatagramEndpoint peer, DatagramEndpoint oldAddr, DatagramEndpoint newAddr)

Callback type for peer migration notifications.

Parameters

peerThe peer that migrated.
oldAddrPrevious address.
newAddrNew address.
aliasDtlsEarlyDataCallback = bool delegate(DatagramEndpoint peer, const(ubyte)[] data)

Callback type for early data received (server-side).

Parameters

peerThe peer that sent early data.
dataThe early data bytes.

Returns

true to accept the early data, false to reject it.
aliasDtlsSessionCallback = void delegate(scope ref const DtlsSessionInfo session)

Callback type for session ticket received (client-side).

Parameters

sessionSession info suitable for resumption.
interfaceDtlsContext

Factory for creating configured DTLS engines.

A context holds reusable configuration (certificates, trust store, etc.) and can create multiple engines with the same settings.

Methods
void setCertificateChain(const(char)[] pemData)Sets the certificate chain (PEM-encoded).
void setCertificateChainDer(const(ubyte[])[] derCertificates)Sets the certificate chain (DER-encoded).
void setPrivateKey(const(char)[] pemData, const(char)[] password = null)Sets the private key (PEM-encoded).
void setPrivateKeyDer(const(ubyte)[] derData, const(char)[] password = null)Sets the private key (DER-encoded).
TlsTrustStore trustStore() @propertyGets the trust store for adding CA certificates.
void setVerifyMode(TlsVerifyMode mode)Sets the certificate verification mode.
void setVerifyCallback(DtlsVerifyCallback callback)Sets a custom certificate verification callback.
void setMinVersion(DtlsVersion ver)Sets the minimum DTLS version.
void setMaxVersion(DtlsVersion ver)Sets the maximum DTLS version.
void setAlpnProtocols(const(string)[] protocols)Sets the ALPN protocols to offer/accept.
void setConnectionId(bool enable, ubyte cidLength = 8)Enables or disables Connection ID support (DTLS 1.3).
void setSessionResumption(bool enable, size_t maxEarlyData = 16384)Enables or disables session resumption (DTLS 1.3).
void setSrtpProfiles(const(SrtpProfile[]) profiles)Sets supported SRTP protection profiles (DTLS-SRTP).
DtlsEngine clientEngine(DtlsTransport transport, DtlsTimerSink timer, string serverName)Creates a DTLS client engine.
DtlsEngine serverEngine(DtlsTransport transport, DtlsTimerSink timer)Creates a DTLS server engine.
enumDtlsMtu : size_t

DTLS Maximum Transmission Unit constants.

DEFAULT = 1200Default path MTU assumption (conservative for most networks).
MINIMUM = 576Minimum MTU (IPv6 minimum minus headers).
MAX_HANDSHAKE_MESSAGE = 64 * 1024Maximum handshake message size (64 KiB).

DTLS retransmission timer constants (RFC 6347 §4.2.4.1).

INITIAL_TIMEOUT_MS = 1000Initial retransmit timeout in milliseconds (1 second).
MAX_TIMEOUT_MS = 60000Maximum retransmit timeout in milliseconds (60 seconds).
MAX_RETRIES = 10Maximum number of retransmissions before giving up.
enumDtlsPeerLimits : size_t

Default peer lifecycle limits.

MAX_PEERS = 10000Default maximum concurrent peers per engine.
MAX_HANDSHAKING_PEERS = 1000Default maximum peers in handshake state.

PLPMTUD (RFC 8899) constants for Path MTU Discovery.

MIN_PROBE_SIZE = 1200Minimum PLPMTUD probe size (RFC 8899 §5.1).
MAX_PROBE_SIZE = 1452Maximum PLPMTUD probe size (typical Ethernet MTU minus headers).
PROBE_COUNT = 3Number of successful probes at a size before confirming MTU.
PROBE_TIMEOUT_MS = 5000Initial probe timeout in milliseconds.
MAX_PROBE_ATTEMPTS = 5Maximum number of probe attempts at a given size.

Session ticket constants (DTLS 1.3 NewSessionTicket).

DEFAULT_TICKET_LIFETIME_S = 86400Default ticket lifetime in seconds (24 hours).
DEFAULT_MAX_EARLY_DATA = 16384Default maximum early data size (16 KB).
DEFAULT_EARLY_DATA_WINDOW_S = 10Default early data time window for replay protection.
TICKET_NONCE_SIZE = 32Ticket nonce size in bytes.

Connection ID constants (RFC 9147 §5.6).

DEFAULT_CID_LENGTH = 8Default local CID length in bytes.
MAX_CID_LENGTH = 255Maximum CID length in bytes.
MAX_PENDING_CID_REQUESTS = 4Maximum number of outstanding CID requests.