Documentation
¶
Overview ¶
Package embedded provides an embeddable i2plan VPN API for third-party applications.
Package embedded provides an embeddable i2plan VPN API for third-party applications.
This package wraps the core i2plan mesh VPN functionality in a simple, developer-friendly API suitable for embedding in desktop applications, mobile apps, daemons, or any Go program that needs VPN capabilities.
Quick Start ¶
Basic usage requires just a few lines of code:
vpn, err := embedded.New(embedded.Config{
NodeName: "my-app-vpn",
DataDir: "/path/to/data",
})
if err != nil {
log.Fatal(err)
}
defer vpn.Close()
if err := vpn.Start(context.Background()); err != nil {
log.Fatal(err)
}
// VPN is now running
fmt.Println("Tunnel IP:", vpn.TunnelIP())
fmt.Println("I2P Address:", vpn.I2PAddress())
Configuration ¶
The Config struct provides all configuration options with sensible defaults. Zero values are replaced with defaults, so minimal configuration is needed:
// Minimal config - uses all defaults
vpn, _ := embedded.New(embedded.Config{})
// Custom config
vpn, _ := embedded.New(embedded.Config{
NodeName: "custom-node",
DataDir: "/var/lib/my-vpn",
SAMAddress: "127.0.0.1:7656",
TunnelSubnet: "10.42.0.0/16",
MaxPeers: 100,
EnableRPC: true,
Logger: slog.Default(),
})
Alternatively, use functional options for a fluent API:
vpn, _ := embedded.NewWithOptions(
embedded.WithNodeName("my-node"),
embedded.WithDataDir("/path/to/data"),
embedded.WithLogger(logger),
)
Lifecycle Management ¶
The VPN follows a simple lifecycle: Initial → Starting → Running → Stopping → Stopped.
- Call VPN.Start to begin the startup sequence
- Call VPN.Stop or VPN.Close for graceful shutdown
- Use VPN.State or VPN.Status to check current state
- Use VPN.Done channel to wait for shutdown
Events ¶
Subscribe to VPN events for real-time status updates:
go func() {
for event := range vpn.Events() {
switch event.Type {
case embedded.EventPeerConnected:
fmt.Printf("Peer connected: %s\n", event.Peer.NodeID)
case embedded.EventError:
fmt.Printf("Error: %v\n", event.Error)
}
}
}()
Events are delivered on a buffered channel. If the channel fills up (consumer is slow), newer events are dropped. Use VPN.DroppedEventCount to check if any events have been dropped.
Peer Management ¶
List connected peers and their status:
for _, peer := range vpn.Peers() {
fmt.Printf("%s: %s (%s)\n", peer.NodeID, peer.TunnelIP, peer.State)
}
Invites ¶
Create invite codes to allow others to join your network:
code, err := vpn.CreateInvite(24*time.Hour, 1) // expires in 24h, single use
if err != nil {
log.Fatal(err)
}
fmt.Println("Share this invite code:", code)
Accept an invite to join another network:
err := vpn.AcceptInvite(ctx, inviteCode)
Thread Safety ¶
All methods on VPN are safe for concurrent use.
Integration with CLI ¶
The i2plan CLI tool uses this package internally. If you're building a custom interface, you can use VPN.Node to access lower-level functionality when needed.
Package embedded logging configuration
Index ¶
- Constants
- type Config
- type Event
- type EventType
- type InviteInfo
- type Option
- func WithDataDir(dir string) Option
- func WithEventBufferSize(size int) Option
- func WithMaxPeers(max int) Option
- func WithNodeName(name string) Option
- func WithRPC(enabled bool) Option
- func WithSAMAddress(addr string) Option
- func WithTunnelLength(length int) Option
- func WithTunnelSubnet(subnet string) Option
- func WithWeb(enabled bool, listenAddr string) Option
- type PeerInfo
- type RouteInfo
- type State
- type Status
- type VPN
- func (v *VPN) AcceptInvite(ctx context.Context, inviteCode string) error
- func (v *VPN) BanPeer(nodeID, reason string, duration time.Duration) error
- func (v *VPN) Close() error
- func (v *VPN) Config() Config
- func (v *VPN) CreateInvite(expiry time.Duration, maxUses int) (string, error)
- func (v *VPN) Done() <-chan struct{}
- func (v *VPN) DroppedEventCount() uint64
- func (v *VPN) Events() <-chan Event
- func (v *VPN) GetPeer(nodeID string) *PeerInfo
- func (v *VPN) I2PAddress() string
- func (v *VPN) I2PDestination() string
- func (v *VPN) ListInvites() []InviteInfo
- func (v *VPN) Node() *core.Node
- func (v *VPN) NodeID() string
- func (v *VPN) PeerCount() int
- func (v *VPN) Peers() []PeerInfo
- func (v *VPN) RevokeInvite(inviteCode string) error
- func (v *VPN) RouteCount() int
- func (v *VPN) Routes() []RouteInfo
- func (v *VPN) Start(ctx context.Context) error
- func (v *VPN) State() State
- func (v *VPN) Status() Status
- func (v *VPN) Stop(ctx context.Context) error
- func (v *VPN) TunnelIP() netip.Addr
- func (v *VPN) UnbanPeer(nodeID string) error
Constants ¶
const ( DefaultSAMAddress = "127.0.0.1:7656" DefaultTunnelSubnet = "10.42.0.0/16" DefaultWebListen = "127.0.0.1:8080" )
Default configuration values for embedded VPN.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Config ¶
type Config struct {
// NodeName is a human-readable identifier for this node.
// Default: hostname or "embedded-node"
NodeName string
// DataDir is where persistent data (identity, config) is stored.
// Default: OS-specific temp directory with unique suffix
DataDir string
// SAMAddress is the I2P SAM bridge address.
// Default: "127.0.0.1:7656"
SAMAddress string
// TunnelSubnet is the mesh IP range (CIDR notation).
// Default: "10.42.0.0/16"
TunnelSubnet string
// TunnelLength is the number of I2P tunnel hops (0-7).
// Lower values are faster but less anonymous.
// Default: 1 (optimized for trusted mesh networks)
// Use 2-3 if anonymity between mesh peers is required.
TunnelLength int
// MaxPeers is the maximum number of peers to connect with.
// Default: 50
MaxPeers int
// EnableRPC starts the RPC server for external control.
// Default: false (embedded apps typically control directly)
EnableRPC bool
// RPCSocket is the path to the Unix socket for RPC (relative to DataDir).
// Default: "rpc.sock"
RPCSocket string
// EnableWeb starts the web UI server.
// Default: false
EnableWeb bool
// WebListenAddr is the address for the web server if enabled.
// Default: "127.0.0.1:8080"
WebListenAddr string
// EventBufferSize is the size of the event channel buffer.
// Default: 100
EventBufferSize int
}
Config configures an embedded VPN instance. Fields with zero values use sensible defaults.
func DefaultConfig ¶
func DefaultConfig() Config
DefaultConfig returns a Config with sensible defaults.
type Event ¶
type Event struct {
// Type is the category of this event.
Type EventType
// Timestamp is when the event occurred.
Timestamp time.Time
// Peer contains peer information for peer-related events.
// Nil for non-peer events.
Peer *PeerInfo
// Error contains the error for EventError events.
// Nil for non-error events.
Error error
// Message is a human-readable description of the event.
Message string
// Data contains event-specific additional data.
// For EventStateChanged: map[string]any{"old": State, "new": State}
// For EventRouteAdded/Removed: RouteInfo
// For EventInviteUsed: map[string]any{"peer_id": string}
Data any
}
Event represents a VPN lifecycle or network event.
type EventType ¶
type EventType int
EventType categorizes VPN events.
const ( // EventStarted is emitted when the VPN starts successfully. EventStarted EventType = iota // EventStopped is emitted when the VPN stops. EventStopped // EventPeerConnected is emitted when a peer handshake completes. EventPeerConnected // EventPeerDisconnected is emitted when a peer connection is lost. EventPeerDisconnected // EventPeerDiscovered is emitted when a new peer is discovered via gossip. EventPeerDiscovered // EventInviteAccepted is emitted when we successfully join via an invite. EventInviteAccepted // EventInviteUsed is emitted when someone uses our invite to join. EventInviteUsed // EventInviteCreated is emitted when we create a new invite code. EventInviteCreated // EventInviteRevoked is emitted when we revoke an invite code. EventInviteRevoked // EventRouteAdded is emitted when a new route is learned. EventRouteAdded // EventRouteRemoved is emitted when a route expires or is removed. EventRouteRemoved // EventError is emitted when a recoverable error occurs. EventError // EventStateChanged is emitted when the VPN state changes. EventStateChanged )
type InviteInfo ¶
type InviteInfo struct {
// Code is the full invite code string.
Code string
// ExpiresAt is when the invite expires.
ExpiresAt time.Time
// MaxUses is the maximum number of times this invite can be used.
MaxUses int
// UsesRemaining is how many times the invite can still be used.
UsesRemaining int
// NetworkID is the network this invite is for.
NetworkID string
}
InviteInfo contains information about an invite code.
type Option ¶
type Option func(*Config)
Option is a functional option for configuring a VPN.
func WithEventBufferSize ¶
WithEventBufferSize sets the event channel buffer size.
func WithSAMAddress ¶
WithSAMAddress sets the SAM bridge address.
func WithTunnelLength ¶
WithTunnelLength sets the I2P tunnel hop count.
func WithTunnelSubnet ¶
WithTunnelSubnet sets the mesh tunnel subnet.
type PeerInfo ¶
type PeerInfo struct {
// NodeID is the unique identifier for this peer.
NodeID string
// TunnelIP is the peer's mesh tunnel IP address.
TunnelIP netip.Addr
// I2PDest is the peer's I2P destination (base32).
I2PDest string
// State is the peer's connection state (connected, disconnected, etc.).
State string
// LastSeen is when we last received data from this peer.
LastSeen time.Time
// ConnectedAt is when the peer connection was established.
ConnectedAt time.Time
// Latency is the estimated round-trip time to this peer.
Latency time.Duration
}
PeerInfo contains information about a connected or known peer.
type RouteInfo ¶
type RouteInfo struct {
// TunnelIP is the destination IP for this route.
TunnelIP netip.Addr
// NodeID is the node ID of the destination.
NodeID string
// ViaNodeID is the next-hop node ID (empty for direct routes).
ViaNodeID string
// HopCount is the number of hops to reach this destination.
HopCount int
// LastSeen is when this route was last verified.
LastSeen time.Time
}
RouteInfo contains information about a mesh route.
type State ¶
type State string
State represents the VPN lifecycle state.
const ( // StateInitial is the state before Start is called. StateInitial State = "initial" // StateStarting means the VPN is initializing. StateStarting State = "starting" // StateRunning means the VPN is fully operational. StateRunning State = "running" // StateStopping means the VPN is shutting down. StateStopping State = "stopping" // StateStopped means the VPN has been stopped. StateStopped State = "stopped" )
type Status ¶
type Status struct {
// State is the current VPN lifecycle state.
State State
// NodeID is the unique identifier for this node.
NodeID string
// NodeName is the human-readable node name.
NodeName string
// TunnelIP is this node's mesh tunnel IP address.
TunnelIP netip.Addr
// I2PDestination is the full I2P destination (base64).
I2PDestination string
// I2PAddress is the short I2P address (base32.b32.i2p).
I2PAddress string
// PeerCount is the number of connected peers.
PeerCount int
// Uptime is how long the VPN has been running.
Uptime time.Duration
// StartedAt is when the VPN was started.
StartedAt time.Time
// Version is the software version.
Version string
}
Status contains current VPN status information.
type VPN ¶
type VPN struct {
// contains filtered or unexported fields
}
VPN is the main embedded VPN controller. It provides a high-level API for VPN lifecycle and operations.
func New ¶
New creates a new embedded VPN instance with the given configuration. The VPN is not started until Start() is called.
func NewWithOptions ¶
NewWithOptions creates a VPN with functional options. This is an alternative to New(Config{...}) for more ergonomic usage.
func (*VPN) AcceptInvite ¶
AcceptInvite connects to a network using an invite code. This will establish a connection to the inviting peer and join their mesh network.
func (*VPN) Close ¶
Close is an alias for Stop with a default 30-second timeout. Suitable for use with defer.
func (*VPN) CreateInvite ¶
CreateInvite generates an invite code for a new peer to join the network. The invite expires after the specified duration and can be used up to maxUses times. Use identity.UnlimitedUses (-1) for unlimited uses (not recommended for security). maxUses=0 is invalid and will return an error.
func (*VPN) Done ¶
func (v *VPN) Done() <-chan struct{}
Done returns a channel that is closed when the VPN stops.
func (*VPN) DroppedEventCount ¶
DroppedEventCount returns the total number of events dropped due to a full buffer. If this value is non-zero, the event consumer is not keeping up with event emission. This can help detect missed critical events.
func (*VPN) Events ¶
Events returns a channel that receives VPN events. The channel is buffered and may drop events if not consumed. Use DroppedEventCount() to check if events have been dropped. Close the VPN to close this channel.
func (*VPN) I2PAddress ¶
I2PAddress returns this node's short I2P address (base32.b32.i2p). Returns empty string if the VPN is not running.
func (*VPN) I2PDestination ¶
I2PDestination returns this node's full I2P destination. Returns empty string if the VPN is not running.
func (*VPN) ListInvites ¶
func (v *VPN) ListInvites() []InviteInfo
ListInvites returns a list of active invites created by this node.
func (*VPN) Node ¶
Node returns the underlying core.Node for advanced operations. Returns nil if the VPN is not started. Use with caution - direct manipulation may cause unexpected behavior.
func (*VPN) NodeID ¶
NodeID returns this node's unique identifier. Returns empty string if the VPN is not running.
func (*VPN) RevokeInvite ¶
RevokeInvite revokes an invite code so it can no longer be used.
func (*VPN) RouteCount ¶
RouteCount returns the number of known routes.
func (*VPN) Start ¶
Start initializes and starts the VPN. This includes:
- Creating/loading identity
- Opening I2P transport
- Starting WireGuard device
- Joining mesh network (if previously connected)
The context controls the startup timeout, not the VPN lifetime.
func (*VPN) Stop ¶
Stop gracefully shuts down the VPN. It notifies peers, saves state, and closes connections. The context controls the shutdown timeout.