Documentation
¶
Overview ¶
Package datagrams provides stateless, port-based messaging over I2P.
This library wraps I2CP datagram sessions, implementing Go's standard net.PacketConn interface for compatibility with existing networking code.
I2P Datagram Types ¶
I2P supports four datagram types with different trade-offs:
Raw (Protocol 18): Non-repliable, no authentication, 0 bytes overhead Use for: Performance-critical applications with trusted peers
Datagram1 (Protocol 17): Repliable, authenticated, ~455 bytes overhead (Ed25519) Use for: Legacy compatibility with older I2P applications
Datagram2 (Protocol 19): Repliable, authenticated with replay prevention, ~457+ bytes overhead (Ed25519) Use for: Modern authenticated messaging requiring replay attack prevention
Datagram3 (Protocol 20): Repliable, no authentication, ~34 bytes overhead Use for: Lightweight repliable messages with minimal overhead
Size Limits ¶
The practical size limit for reliable delivery is 8-10KB. While I2CP supports up to ~64KB datagrams, larger messages are fragmented into 1KB tunnel messages with exponentially increasing drop probability.
Stateless Design ¶
Unlike TCP connections, I2P datagrams are stateless. Each message is independent with no automatic retransmission, ordering, or connection state. Applications requiring reliability must implement it at the application layer using sequence numbers, ACKs, and retransmission logic.
Basic Usage ¶
Create a datagram connection and send/receive messages:
session, _ := i2cp.NewSession(config)
conn, _ := datagrams.NewDatagramConn(session, 8080)
defer conn.Close()
// Send a message
addr := &datagrams.I2PAddr{
Destination: "example.i2p.destination.string",
Port: 8081,
}
conn.WriteTo([]byte("Hello"), addr)
// Receive a message
buf := make([]byte, 8192)
n, addr, _ := conn.ReadFrom(buf)
fmt.Printf("Received: %s\n", buf[:n])
Port-Based Routing ¶
This library provides port-based message routing to allow multiple services to share a single I2CP session. Each DatagramConn is bound to a local port, enabling:
- Multiple application protocols per I2CP session
- Port-based message filtering and dispatch
- Familiar networking semantics for Go developers
Applications that don't need port-based routing can use Raw datagrams with minimal overhead.
Index ¶
- Constants
- type DatagramConn
- func (d *DatagramConn) Close() error
- func (d *DatagramConn) HasSenderDestination() bool
- func (d *DatagramConn) IsClosed() bool
- func (d *DatagramConn) LocalAddr() net.Addr
- func (d *DatagramConn) MaxPayloadSize() int
- func (d *DatagramConn) Protocol() uint8
- func (d *DatagramConn) ReadFrom(p []byte) (n int, addr net.Addr, err error)
- func (d *DatagramConn) ReceiveFrom() ([]byte, *i2cp.Destination, uint16, error)
- func (d *DatagramConn) ReceiveFromWithAddr() ([]byte, *I2PAddr, error)
- func (d *DatagramConn) ReceiveFromWithOptions() (*ReceiveResult, error)
- func (d *DatagramConn) RegisterPort(port uint16, handler func([]byte, *i2cp.Destination)) error
- func (d *DatagramConn) SendTo(payload []byte, destinationB64 string, port uint16) error
- func (d *DatagramConn) SendToWithOptions(payload []byte, destinationB64 string, port uint16, options *Options) error
- func (d *DatagramConn) Session() I2CPSession
- func (d *DatagramConn) SetDeadline(t time.Time) error
- func (d *DatagramConn) SetReadDeadline(t time.Time) error
- func (d *DatagramConn) SetWriteDeadline(t time.Time) error
- func (d *DatagramConn) UnregisterPort(port uint16) error
- func (d *DatagramConn) WriteTo(p []byte, addr net.Addr) (n int, err error)
- type I2CPSession
- type I2PAddr
- type OfflineSignature
- type Options
- type ReceiveResult
Constants ¶
const ( // ProtocolStreaming (6) is reserved for I2P streaming protocol. // This protocol number MUST NOT be used for datagrams. ProtocolStreaming = i2cp.ProtoStreaming // ProtocolRaw (18) is for non-repliable, non-authenticated datagrams. // Zero overhead, highest performance. Use for trusted peers or when // authentication is handled at the application layer. ProtocolRaw = i2cp.ProtoDatagramRaw // ProtocolDatagram1 (17) is for repliable, authenticated datagrams (legacy). // ~455 bytes overhead (Ed25519). Use for compatibility with older I2P applications. // WARNING: Does NOT support offline signatures (LS2 offline keys). ProtocolDatagram1 = i2cp.ProtoDatagram // ProtocolDatagram2 (19) is for repliable, authenticated datagrams with replay prevention. // ~457+ bytes overhead (Ed25519). Use for modern authenticated messaging requiring // protection against replay attacks. Supports offline signatures. ProtocolDatagram2 = i2cp.ProtoDatagram2 // ProtocolDatagram3 (20) is for repliable, non-authenticated datagrams. // ~34 bytes overhead. Use when repliability is needed with minimal overhead // and authentication is not required. ProtocolDatagram3 = i2cp.ProtoDatagram3 )
Protocol numbers for I2P datagram types. These are aliases to the constants defined in go-i2cp for convenience. See SPEC.md for detailed format specifications.
const ( // MaxI2NPSize is the nominal maximum size for I2NP messages including datagrams. // Per I2P specification, this is 64KB but actual limits may be slightly less // due to I2CP gzip header (~10 bytes) and garlic message overhead. MaxI2NPSize = 64 * 1024 // 64 KB // RecommendedMaxSize is the recommended maximum payload size for reliable delivery. // I2NP messages fragment into 1KB tunnel messages, and drop probability increases // exponentially with size. This limit ensures good reliability. RecommendedMaxSize = 10 * 1024 // 10 KB // OptimalMaxSize is the optimal payload size for best reliability. // Keeping messages small reduces fragmentation and improves delivery probability. OptimalMaxSize = 4 * 1024 // 4 KB // Ed25519SignatureLength is the fixed signature length for Ed25519 (64 bytes). // go-i2cp exclusively uses Ed25519, so this is constant. Ed25519SignatureLength = 64 // Ed25519DestinationSize is the wire format size for an Ed25519 destination. // Wire format: pubKey(256) + signingPubKey(128) + certificate(7) = 391 bytes // // Note: The I2P spec says "387+" for serialized format because DSA-SHA1 destinations // fit in 387 bytes. Ed25519 with KEY certificates requires 391 bytes due to the // certificate structure. This value is constant for go-i2cp's Ed25519-only destinations. Ed25519DestinationSize = 391 // MinDatagram1Overhead is the minimum envelope overhead for Datagram1 with Ed25519. // destination(391) + signature(64) = 455 bytes // // This is the minimum because the destination size can vary with certificate type. // For go-i2cp's Ed25519-only destinations, this is also the exact overhead. MinDatagram1Overhead = Ed25519DestinationSize + Ed25519SignatureLength // 455 // MinDatagram2Overhead is the minimum envelope overhead for Datagram2 with Ed25519. // destination(391) + flags(2) + signature(64) = 457 bytes (without options or offline sig) // // Actual overhead may be larger when: // - Options field is present (adds 2+ bytes for mapping) // - Offline signature is present (adds ~102 bytes for Ed25519) MinDatagram2Overhead = Ed25519DestinationSize + 2 + Ed25519SignatureLength // 457 // MinDatagram3Overhead is the minimum envelope overhead for Datagram3. // fromhash(32) + flags(2) = 34 bytes (without options) // // Actual overhead may be larger when: // - Options field is present (adds 2+ bytes for mapping) MinDatagram3Overhead = 32 + 2 // 34 )
Size constants for I2P datagrams.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type DatagramConn ¶
type DatagramConn struct {
// contains filtered or unexported fields
}
DatagramConn represents a stateless I2P datagram connection that wraps an I2CP session. It implements net.PacketConn for compatibility with standard Go networking code.
DatagramConn supports port-based message routing, allowing multiple application protocols to share a single I2CP session. Each connection is bound to a local port and can send/receive datagrams to/from remote I2P destinations and ports.
Design decisions:
- Stateless: No connection tracking between sends, matching I2CP semantics
- Thread-safe: All methods safe for concurrent use via internal mutex
- Protocol-aware: Supports Raw (18), Datagram1 (17), Datagram2 (19), Datagram3 (20)
- Port-based: Port multiplexing on a single I2CP session
Port-based routing: I2CP datagrams are raw byte payloads without built-in addressing. This library provides port-based routing to allow multiple services to share a single I2CP session. Applications that don't need ports can use Raw datagrams with zero overhead.
func NewDatagramConn ¶
func NewDatagramConn(session I2CPSession, localPort uint16) (*DatagramConn, error)
NewDatagramConn creates a new DatagramConn bound to the specified local port. The connection uses ProtocolRaw (18) by default for zero overhead.
The session parameter must be a valid, open I2CP session. The caller is responsible for session lifecycle management. DatagramConn will not close the session.
The localPort parameter specifies the UDP port number for this connection. Port 0 is allowed but not recommended - it won't filter incoming packets by port.
Design rationale:
- Default to Raw protocol for performance and simplicity
- Let caller manage session lifecycle (follows Go convention of explicit ownership)
- Require explicit port binding (no auto-assignment) for clarity
Example:
session, _ := i2cp.NewSession(client, callbacks)
conn, err := datagrams.NewDatagramConn(session, 8080)
if err != nil {
log.Fatal(err)
}
defer conn.Close()
func NewDatagramConnWithProtocol ¶
func NewDatagramConnWithProtocol(session I2CPSession, localPort uint16, protocol uint8) (*DatagramConn, error)
NewDatagramConnWithProtocol creates a new DatagramConn with a specific protocol type.
The protocol parameter must be one of:
- ProtocolRaw (18): Non-repliable, no authentication, 0 bytes overhead
- ProtocolDatagram1 (17): Repliable, authenticated, ~455 bytes overhead (Ed25519)
- ProtocolDatagram2 (19): Repliable, authenticated with replay prevention, ~457+ bytes overhead (Ed25519)
- ProtocolDatagram3 (20): Repliable, non-authenticated, ~34 bytes overhead
Protocol selection guide:
- Use Raw for high-performance, trusted communication
- Use Datagram3 for repliability with minimal overhead
- Use Datagram2 for authentication with replay attack prevention
- Use Datagram1 only for legacy compatibility
Returns an error if:
- session is nil
- session is closed
- session destination cannot be retrieved
- protocol is ProtocolStreaming (6) which is reserved for streaming
func (*DatagramConn) Close ¶
func (d *DatagramConn) Close() error
Close closes the datagram connection and releases associated resources. It cancels any background operations (like the receive loop) and marks the connection as closed.
Close does NOT close the underlying I2CP session - the caller must manage session lifecycle independently. This design allows multiple DatagramConns to share a single session (though currently only one is typical).
After Close() is called, all subsequent operations on the connection will return net.ErrClosed. Close() is idempotent - calling it multiple times is safe and only the first call has effect.
Close() is safe to call concurrently with other operations.
func (*DatagramConn) HasSenderDestination ¶
func (d *DatagramConn) HasSenderDestination() bool
HasSenderDestination returns true if ReceiveFrom() will return a usable sender destination.
For Datagram3 (protocol 20), this returns false because the protocol only includes the sender's 32-byte hash, not the full destination. In this case, applications should use ReceiveFromWithAddr() instead to get the sender's hash via I2PAddr.DestinationHash.
For all other protocols (Raw, Datagram1, Datagram2), this returns true.
Example usage:
if conn.HasSenderDestination() {
payload, from, port, err := conn.ReceiveFrom()
// from is a valid destination
} else {
payload, addr, err := conn.ReceiveFromWithAddr()
// Use addr.DestinationHash to identify the sender
}
func (*DatagramConn) IsClosed ¶
func (d *DatagramConn) IsClosed() bool
IsClosed returns true if Close() has been called on this connection. This is a convenience method for checking connection state.
func (*DatagramConn) LocalAddr ¶
func (d *DatagramConn) LocalAddr() net.Addr
LocalAddr returns the local network address. For I2P, this is an I2PAddr containing our destination and port.
This implements the net.PacketConn interface.
func (*DatagramConn) MaxPayloadSize ¶
func (d *DatagramConn) MaxPayloadSize() int
MaxPayloadSize returns the maximum payload size for this connection's protocol type. This accounts for protocol-specific overhead in the I2NP message.
Protocol-specific limits (for Ed25519 destinations):
- Raw (18): 64KB - no envelope overhead
- Datagram3 (20): 64KB - 34 bytes (fromhash + flags)
- Datagram1 (17): 64KB - 455 bytes (dest(391) + signature(64))
- Datagram2 (19): 64KB - 457 bytes (dest(391) + flags(2) + signature(64))
Note: The I2P spec uses "387+" for destination size (serialized format) and "40+" for signature (DSA_SHA1). This library uses Ed25519 exclusively, so:
- Destination wire format: 391 bytes (pubKey(256) + signingPubKey(128) + cert(7))
- Signature: 64 bytes (Ed25519)
For reliable delivery, limit payloads to RecommendedMaxSize (~10KB) or less due to I2NP fragmentation into 1KB tunnel messages. Drop probability increases exponentially with message size.
func (*DatagramConn) Protocol ¶
func (d *DatagramConn) Protocol() uint8
Protocol returns the I2P datagram protocol type (17, 18, 19, or 20). This allows inspecting which protocol the connection is using.
func (*DatagramConn) ReadFrom ¶
ReadFrom reads a packet from the connection, copying the payload into p. It returns the number of bytes copied into p and the return address that sent the packet.
This implements the net.PacketConn interface by wrapping ReceiveFrom().
ReadFrom can be made to time out and return an error after a fixed time limit; see SetDeadline and SetReadDeadline.
Design notes:
- Wraps ReceiveFrom() to provide standard net.PacketConn semantics
- Converts I2P destination + port to I2PAddr for interface compliance
- Copies payload into provided buffer (standard Go networking pattern)
- Returns short read if buffer is too small (no error, matches UDP behavior)
Returns an error if:
- The connection is closed (net.ErrClosed)
- The read deadline has expired
- The underlying receive operation fails
func (*DatagramConn) ReceiveFrom ¶
func (d *DatagramConn) ReceiveFrom() ([]byte, *i2cp.Destination, uint16, error)
ReceiveFrom receives a datagram and returns the payload, sender destination, and source port.
This method blocks until a datagram is received or an error occurs. It respects the read deadline set by SetReadDeadline() or SetDeadline().
The method parses protocol-specific envelopes:
- Raw (18): Payload is returned directly (no envelope)
- Datagram1 (17): Extracts from destination + signature, verifies signature, then payload
- Datagram2 (19): Extracts from + flags + signature, verifies with replay prevention, then payload
- Datagram3 (20): Extracts fromhash(32) + flags(2), then payload (see WARNING below)
WARNING: Datagram3 Sender Identification ¶
For Datagram3 (protocol 20), the returned sender destination is EMPTY because the protocol only includes a 32-byte hash of the sender's destination, not the full destination itself. If you need to identify the sender when using Datagram3:
- Use DatagramConn.ReceiveFromWithAddr instead - it returns an I2PAddr containing the sender's hash in DestinationHash field
- Use DatagramConn.HasSenderDestination to check if this method will return a valid destination before calling
To reply to a Datagram3 sender, applications must look up the full destination from a cache or the I2P network database using the hash.
Returns an error if:
- The connection is closed
- The read deadline has expired
- The envelope is malformed
- Signature verification fails (Datagram1/2)
func (*DatagramConn) ReceiveFromWithAddr ¶
func (d *DatagramConn) ReceiveFromWithAddr() ([]byte, *I2PAddr, error)
ReceiveFromWithAddr receives a datagram and returns the payload, sender address, and an error. This method provides more complete sender information than ReceiveFrom, including the destination hash for Datagram3 protocol messages.
For Datagram3 (protocol 20), only the sender's destination hash is available in the protocol, not the full destination. Use addr.IsHashOnly() to check this condition. To reply to a Datagram3 sender, applications need to look up the full destination from a cache or the network database using addr.DestinationHash.
This method blocks until a datagram is received or an error occurs. It respects the read deadline set by SetReadDeadline() or SetDeadline().
Returns an error if:
- The connection is closed
- The read deadline has expired
- The envelope is malformed
func (*DatagramConn) ReceiveFromWithOptions ¶
func (d *DatagramConn) ReceiveFromWithOptions() (*ReceiveResult, error)
ReceiveFromWithOptions receives a datagram and returns a ReceiveResult containing the payload, sender information, and parsed options.
This method provides complete access to all datagram fields, including the options field which is supported by Datagram2 (protocol 19) and Datagram3 (protocol 20).
For protocols that don't support options (Raw, Datagram1), the Options field in the result will be nil. For protocols that support options but didn't include any in the received datagram, the Options field will also be nil.
For Datagram3 (protocol 20), the From field in the result will be nil because only the sender's hash is available. Use FromHash or FromAddr.DestinationHash instead.
This method blocks until a datagram is received or an error occurs. It respects the read deadline set by SetReadDeadline() or SetDeadline().
Example:
result, err := conn.ReceiveFromWithOptions()
if err != nil {
log.Fatal(err)
}
if result.Options != nil {
version := result.Options.Get("version")
log.Printf("Received from peer with version: %s", version)
}
Returns an error if:
- The connection is closed
- The read deadline has expired
- The envelope is malformed
- Signature verification fails (Datagram1/2)
func (*DatagramConn) RegisterPort ¶
func (d *DatagramConn) RegisterPort(port uint16, handler func([]byte, *i2cp.Destination)) error
RegisterPort registers a handler function for datagrams received on a specific port.
When a datagram arrives with the given destination port number, the handler will be called with the payload and sender's destination. This enables port-based multiplexing of datagram streams over a single I2CP session.
The handler is dispatched in a new goroutine to avoid blocking the receive loop. Handlers should be lightweight and avoid long-running operations.
Parameters:
- port: The destination port number to listen on (0-65535)
- handler: Function called when a datagram arrives on this port
- payload: The datagram payload bytes (after envelope parsing)
- from: The I2P destination of the sender (may be nil for Raw datagrams)
Returns an error if:
- The connection is closed
- The port is already registered
- The handler function is nil
Example:
conn.RegisterPort(8080, func(payload []byte, from *i2cp.Destination) {
fmt.Printf("Received %d bytes from %s\n", len(payload), from)
})
func (*DatagramConn) SendTo ¶
func (d *DatagramConn) SendTo(payload []byte, destinationB64 string, port uint16) error
SendTo sends a datagram to the specified I2P destination and port.
The payload is wrapped in a protocol-specific envelope based on the connection's protocol type:
- Raw (18): payload sent directly, no envelope
- Datagram3 (20): fromhash + flags + payload
- Datagram1 (17): from destination + signature + payload
- Datagram2 (19): from destination + flags + options + signature + payload
The destination parameter should be a valid I2P destination string (base64 encoded). The port parameter is used for application-level routing within I2P.
Returns an error if:
- The connection is closed
- The payload exceeds MaxPayloadSize()
- The write deadline has expired
- The underlying I2CP session fails to send
func (*DatagramConn) SendToWithOptions ¶
func (d *DatagramConn) SendToWithOptions(payload []byte, destinationB64 string, port uint16, options *Options) error
SendToWithOptions sends a datagram with optional I2P Mapping options.
This method extends DatagramConn.SendTo by allowing the inclusion of options in the datagram envelope. Options are only supported by Datagram2 (protocol 19) and Datagram3 (protocol 20). For other protocols, the options parameter is ignored.
Options can contain arbitrary key/value pairs encoded as an I2P Mapping structure. Common use cases include application-specific metadata, routing hints, or version info.
The options parameter may be nil or empty to send a datagram without options (equivalent to calling DatagramConn.SendTo).
Example:
opts := datagrams.NewOptions(map[string]string{
"version": "1.0",
"app": "myapp",
})
err := conn.SendToWithOptions(payload, destB64, port, opts)
Returns an error if:
- The connection is closed
- The payload exceeds the maximum size for the protocol type
- The destination string is invalid
- The write deadline has expired
- The underlying I2CP session fails to send
func (*DatagramConn) Session ¶
func (d *DatagramConn) Session() I2CPSession
Session returns the underlying I2CP session. This allows advanced users to access session-level operations if needed.
func (*DatagramConn) SetDeadline ¶
func (d *DatagramConn) SetDeadline(t time.Time) error
SetDeadline sets both read and write deadlines for the connection. This implements the net.PacketConn interface.
A zero value for t means no deadline. After a deadline has been reached, operations will fail with a timeout error.
Note: Deadline support is currently basic - it sets both read and write deadlines to the same value. Use SetReadDeadline/SetWriteDeadline for independent control.
func (*DatagramConn) SetReadDeadline ¶
func (d *DatagramConn) SetReadDeadline(t time.Time) error
SetReadDeadline sets the deadline for future Read operations. A zero value for t means no deadline.
This implements the net.PacketConn interface.
func (*DatagramConn) SetWriteDeadline ¶
func (d *DatagramConn) SetWriteDeadline(t time.Time) error
SetWriteDeadline sets the deadline for future Write operations. A zero value for t means no deadline.
This implements the net.PacketConn interface.
func (*DatagramConn) UnregisterPort ¶
func (d *DatagramConn) UnregisterPort(port uint16) error
UnregisterPort removes the handler for the specified port.
After unregistration, datagrams received on this port will no longer trigger the handler callback. This is useful for graceful shutdown or dynamic port management.
Design notes:
- Thread-safe: Uses RWMutex to protect the handlers map
- No-op if not registered: Does not return error if port not registered
- Immediate effect: Handler won't be called for subsequent receives
Returns an error if:
- The connection is closed
Example:
conn.UnregisterPort(8080)
func (*DatagramConn) WriteTo ¶
WriteTo writes a packet with payload p to addr. WriteTo can be made to time out and return an error after a fixed time limit; see SetDeadline and SetWriteDeadline.
This implements the net.PacketConn interface by wrapping SendTo().
On packet-oriented connections, write timeouts are rare because writes are atomic operations. However, I2P datagrams may experience write delays due to router congestion or tunnel building.
Design notes:
- Wraps SendTo() to provide standard net.PacketConn semantics
- Type-asserts net.Addr to I2PAddr for destination extraction
- Returns full payload length on success (atomic write)
- Validates address type before attempting send
Returns an error if:
- addr is not of type *I2PAddr
- addr has an empty destination string
- The connection is closed (net.ErrClosed)
- The write deadline has expired
- The underlying send operation fails
type I2CPSession ¶
type I2CPSession interface {
// Destination returns the I2P destination for this session.
Destination() *i2cp.Destination
// IsClosed returns true if the session has been closed.
IsClosed() bool
// IsOffline returns true if this session uses offline keys (LS2).
// Sessions with offline keys should use Datagram2 instead of Datagram1.
// Per I2P specification, Datagram1 does NOT support offline signatures.
IsOffline() bool
// SendMessage sends a datagram message to the specified destination.
// This will be used by the SendTo implementation.
SendMessage(destination *i2cp.Destination, protocol uint8, srcPort, destPort uint16, payload *i2cp.Stream, nonce uint32) error
// SendMessageWithContext sends a message with context for cancellation.
SendMessageWithContext(ctx context.Context, destination *i2cp.Destination, protocol uint8, srcPort, destPort uint16, payload *i2cp.Stream, nonce uint32) error
// SigningKeyPair returns the Ed25519 signing key pair for this session.
// This is used to sign authenticated datagrams (Datagram1, Datagram2).
// Returns error if no signing key pair is available.
SigningKeyPair() (*i2cp.Ed25519KeyPair, error)
}
I2CPSession is an interface that abstracts the I2CP session operations needed by DatagramConn. This allows for testing without requiring a real I2P router.
The interface includes only the methods DatagramConn actually uses, following the Interface Segregation Principle. This makes testing easier and documents the actual dependencies.
type I2PAddr ¶
type I2PAddr struct {
// Destination is the I2P destination string (base64-encoded)
// Empty string represents an unknown or anonymous sender (e.g., Raw datagrams)
// or a Datagram3 sender where only the hash is known.
Destination string
// DestinationHash is the SHA-256 hash of the sender's destination (32 bytes).
// This is populated for Datagram3 messages where only the hash is included
// in the protocol. For other protocol types, this may be computed from the
// Destination field or left as zero.
// Use HasDestinationHash() to check if this field is populated.
DestinationHash [32]byte
// Port is the UDP port number for application-level routing (1-65535)
Port uint16
}
I2PAddr represents an I2P destination with a port number. It implements the net.Addr interface for compatibility with Go's networking APIs.
I2P destinations are base64-encoded strings that uniquely identify an endpoint in the I2P network. Ports provide application-level multiplexing on top of a single I2CP session.
For Datagram3 (protocol 20), only the DestinationHash is available since the protocol only includes a 32-byte hash of the sender's destination, not the full destination. Applications can use HasDestinationHash() to check if the hash is populated and HasFullDestination() to check if the full destination is available. To reply to a Datagram3 sender, applications need to look up the full destination from a cache or the network database using the hash.
func ParseI2PAddr ¶
ParseI2PAddr parses a string into an I2PAddr. Accepts formats:
- "destination:port" - full address with destination and port
- ":port" - port only (destination left empty)
- "destination" - destination only (port defaults to 0)
Returns an error if the port is invalid or out of range.
func (*I2PAddr) AsNetAddr ¶
AsNetAddr returns the I2PAddr as a net.Addr interface. This is a convenience method for type assertion-free usage.
func (*I2PAddr) Equal ¶
Equal returns true if two I2P addresses are equal. Compares destination string, destination hash, and port number.
func (*I2PAddr) HasDestinationHash ¶
HasDestinationHash returns true if this address has a populated destination hash. This is always true for Datagram3 senders and may be true for other protocols if the hash was computed from the full destination.
func (*I2PAddr) HasFullDestination ¶
HasFullDestination returns true if this address has a full destination string. When false, the address may have only a hash (for Datagram3) or be empty (for Raw).
func (*I2PAddr) IsHashOnly ¶
IsHashOnly returns true if only the hash is available without a full destination. This is the case for Datagram3 senders where the protocol only includes the hash.
type OfflineSignature ¶
type OfflineSignature struct {
// Expires is the expiration time of this offline signature authorization.
// After this time, the transient key should no longer be accepted.
Expires time.Time
// TransientSigType is the signature type code for the transient key.
// This determines the length of TransientPublicKey.
TransientSigType uint16
// TransientPublicKey is the public key authorized to sign messages.
// Length depends on TransientSigType.
TransientPublicKey []byte
// Signature is the authorization signature from the destination's key.
// This proves the destination authorized the transient key.
// Length depends on the destination's signature type.
Signature []byte
}
OfflineSignature represents an I2P Offline Signature block used in Datagram2. This allows a transient key to sign messages on behalf of the destination, enabling offline destinations to pre-authorize signing.
Format:
+----+----+----+----+----+----+----+----+ | expires | sigtype | ... +----+----+----+----+----+----+----+----+ | transient_public_key (variable) | +----+----+----+----+----+----+----+----+ | signature of above (variable) | +----+----+----+----+----+----+----+----+
expires: 4 bytes, seconds since epoch (unsigned big-endian) sigtype: 2 bytes, signature type of transient key transient_public_key: variable length based on sigtype signature: variable length, signed by destination's key
func OfflineSignatureFromBytes ¶
func OfflineSignatureFromBytes(data []byte, destSigType uint16) (*OfflineSignature, int, error)
OfflineSignatureFromBytes parses an Offline Signature block from binary data. Returns the OfflineSignature, number of bytes consumed, and any error.
Parameters:
- data: raw bytes containing the offline signature block
- destSigType: signature type of the destination (determines auth signature length)
func (*OfflineSignature) Bytes ¶
func (o *OfflineSignature) Bytes() []byte
Bytes encodes the OfflineSignature to binary format.
func (*OfflineSignature) IsExpired ¶
func (o *OfflineSignature) IsExpired() bool
IsExpired returns true if the offline signature has expired.
func (*OfflineSignature) Len ¶
func (o *OfflineSignature) Len() int
Len returns the encoded length of the OfflineSignature in bytes.
func (*OfflineSignature) Verify ¶
func (o *OfflineSignature) Verify(dest *i2cp.Destination) error
Verify verifies that the offline signature was signed by the destination's key. This proves the destination authorized the transient key to sign on its behalf.
Per I2P specification, the offline signature is over:
- expires: 4 bytes (big-endian unsigned seconds since epoch)
- sigtype: 2 bytes (signature type of transient key)
- transient_public_key: variable length based on sigtype
Parameters:
- dest: The destination whose key should have signed this offline signature
Returns nil if verification succeeds, error otherwise.
Note: This library only supports Ed25519 signatures (sigtype 7). Other signature types will return an error.
func (*OfflineSignature) VerifyPayloadSignature ¶
func (o *OfflineSignature) VerifyPayloadSignature(message, signature []byte) bool
VerifyPayloadSignature verifies a payload signature using the transient public key. This should be used for Datagram2 payload verification when an offline signature is present.
Per I2P specification, when offline signatures are used, the payload is signed by the transient key (not the destination's key), allowing offline destinations to pre-authorize signing.
Parameters:
- message: The data that was signed (for Datagram2: target_hash + flags + options + offline_sig + payload)
- signature: The signature to verify
Returns true if the signature is valid, false otherwise.
Note: This library only supports Ed25519 transient keys (sigtype 7). Other signature types will return false.
type Options ¶
type Options struct {
// contains filtered or unexported fields
}
Options represents an I2P Mapping structure for datagram options. This is a wrapper around github.com/go-i2p/common/data.Mapping that provides a simpler interface for datagram-specific use cases.
A Mapping is a set of key/value pairs encoded as:
- 2-byte size integer (total bytes that follow)
- Series of String=String; pairs
Each String is 1-byte length followed by UTF-8 data (max 255 bytes). Keys and values should not exceed 255 bytes each.
Per I2P spec: Mappings in signed structures must be sorted by key.
func EmptyOptions ¶
func EmptyOptions() *Options
EmptyOptions returns an empty Options Mapping. When encoded, this produces a 2-byte zero size field.
func NewOptions ¶
NewOptions creates Options from a Go map.
func OptionsFromBytes ¶
OptionsFromBytes parses an I2P Mapping from binary data using common/data.Mapping. Returns the Options, number of bytes consumed, and any error.
Format:
+----+----+----+----+----+----+----+----+ | size | key_string (len + data)| = | +----+----+----+----+----+----+----+----+ | val_string (len + data) | ; | ... +----+----+----+----+----+----+----+
func (*Options) Bytes ¶
Bytes encodes the Options as an I2P Mapping. Keys are sorted for signature stability (handled by common/data.Mapping).
Format:
+----+----+----+----+----+----+----+----+ | size | key_string (len + data)| = | +----+----+----+----+----+----+----+----+ | val_string (len + data) | ; | ... +----+----+----+----+----+----+----+----+
func (*Options) Len ¶
Len returns the encoded length of the Options in bytes. This includes the 2-byte size field plus the content.
type ReceiveResult ¶
type ReceiveResult struct {
// Payload is the application data extracted from the datagram.
Payload []byte
// From is the sender's full I2P destination for authenticated protocols.
// For Datagram3 (protocol 20), this is nil because only the sender's hash
// is available. Use FromHash or FromAddr.DestinationHash instead.
From *i2cp.Destination
// FromHash is the SHA-256 hash of the sender's destination.
// Available for Datagram3 and computed from From for other protocols.
FromHash [32]byte
// FromAddr is the sender address as an I2PAddr for net.Addr compatibility.
FromAddr *I2PAddr
// SrcPort is the source port from the datagram header.
SrcPort uint16
// Options contains the I2P Mapping options if present in the datagram.
// Only Datagram2 (19) and Datagram3 (20) support options.
// This is nil for protocols that don't support options or when no options
// were included in the received datagram.
Options *Options
}
ReceiveResult contains the complete result of receiving a datagram, including optional fields like protocol-specific options.
This struct is returned by DatagramConn.ReceiveFromWithOptions to provide access to all datagram information including the options field which is supported by Datagram2 (protocol 19) and Datagram3 (protocol 20).
For protocols that don't support options (Raw, Datagram1), the Options field will be nil.
Directories
¶
| Path | Synopsis |
|---|---|
|
examples
|
|
|
echo-client
command
Echo client demonstrates sending datagrams and receiving responses.
|
Echo client demonstrates sending datagrams and receiving responses. |
|
echo-server
command
Echo server demonstrates basic datagram send/receive using port-based routing.
|
Echo server demonstrates basic datagram send/receive using port-based routing. |
|
scripts
|
|
|
container
command
|