i2plib

package module
v0.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 14, 2025 License: MIT Imports: 20 Imported by: 0

README

i2plib

Go library for working with I2P via the SAM v3.1 API.

What’s included

  • SAM message helpers and I2P base64/base32 (sam.go)
  • SAM client primitives (HELLO, DEST GENERATE, SESSION CREATE, NAMING LOOKUP, STREAM CONNECT/ACCEPT) (aiosam.go)
  • Stream tunnels (client/server) (tunnel.go)

Install

go get github.com/svanichkin/i2plib

Configuration

The default SAM address is 127.0.0.1:7656.

You can override it via:

export I2P_SAM_ADDRESS=127.0.0.1:7656

Usage

Create destination + session
package main

import (
	"context"
	"log"
	"time"

	"github.com/svanichkin/i2plib"
)

func main() {
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	samAddr := i2plib.GetSAMAddress()
	sess, err := i2plib.CreateSession(ctx, "test", samAddr, "STREAM", i2plib.DefaultSigType, nil, nil)
	if err != nil {
		log.Fatal(err)
	}
	defer sess.Close()

	log.Printf("session=%s dest=%s.b32.i2p", sess.Name(), sess.Destination.Base32())
}
Client tunnel (local TCP -> remote I2P destination)
samAddr := i2plib.GetSAMAddress()
samClient := i2plib.NewDefaultSAMClient(samAddr)

tun := i2plib.NewClientTunnel(
	i2plib.Address{Host: "127.0.0.1", Port: 6668},
	"irc.echelon.i2p",
	samAddr,
	samClient,
	nil,    // destination (nil => create new)
	"",     // session name ("" => auto)
	nil,    // SAM options
)

ctx := context.Background()
if err := tun.Run(ctx); err != nil {
	log.Fatal(err)
}
defer tun.Stop()
Server tunnel (accept from I2P -> local TCP)
samAddr := i2plib.GetSAMAddress()
samClient := i2plib.NewDefaultSAMClient(samAddr)

tun := i2plib.NewServerTunnel(
	i2plib.Address{Host: "127.0.0.1", Port: 8080},
	samAddr,
	samClient,
	nil, // destination (nil => transient)
	"",
	nil,
)

ctx := context.Background()
if err := tun.Run(ctx); err != nil {
	log.Fatal(err)
}
defer tun.Stop()

Tests

GOCACHE="$PWD/.gocache" go test ./...

tunnel_mock_sam_test.go includes a mock SAM server. In restricted sandboxes that disallow listen(2), these tests will be skipped.

Documentation

Index

Constants

View Source
const (
	SAMErrCantReachPeer  = "CANT_REACH_PEER"
	SAMErrDuplicatedDest = "DUPLICATED_DEST"
	SAMErrDuplicatedID   = "DUPLICATED_ID"
	SAMErrI2PError       = "I2P_ERROR"
	SAMErrInvalidID      = "INVALID_ID"
	SAMErrInvalidKey     = "INVALID_KEY"
	SAMErrKeyNotFound    = "KEY_NOT_FOUND"
	SAMErrPeerNotFound   = "PEER_NOT_FOUND"
	SAMErrTimeout        = "TIMEOUT"
)
View Source
const (
	I2PAltChars    = "-~"
	SAMBufSize     = 4096
	DefaultSAMHost = "127.0.0.1"
	DefaultSAMPort = 7656
	DefaultMinVer  = "3.1"
	DefaultMaxVer  = "3.1"
	TransientDest  = "TRANSIENT"

	SigTypeEd25519 = 7
	DefaultSigType = SigTypeEd25519
)
View Source
const BufferSize = 65536

Variables

View Source
var (
	ValidBase32Address = regexp.MustCompile(`^([a-zA-Z0-9]{52}).b32\.i2p$`)
	ValidBase64Address = regexp.MustCompile(`^([a-zA-Z0-9\-~=]{516,528})$`)
)
View Source
var DefaultSAMAddress = Address{
	Host: "127.0.0.1",
	Port: 7656,
}

DefaultSAMAddress — аналог sam.DEFAULT_ADDRESS ("127.0.0.1", 7656)

Lookup table — аналог SAM_EXCEPTIONS in Python

Functions

func DestGenerateMsg

func DestGenerateMsg(sigType int) []byte

func ErrCantReachPeer

func ErrCantReachPeer(msg string) error

func ErrDuplicatedDest

func ErrDuplicatedDest(msg string) error

func ErrDuplicatedID

func ErrDuplicatedID(msg string) error

func ErrI2PError

func ErrI2PError(msg string) error

func ErrInvalidID

func ErrInvalidID(msg string) error

func ErrInvalidKey

func ErrInvalidKey(msg string) error

func ErrKeyNotFound

func ErrKeyNotFound(msg string) error

func ErrPeerNotFound

func ErrPeerNotFound(msg string) error

func ErrTimeout

func ErrTimeout(msg string) error

func GenerateSessionID

func GenerateSessionID(length int) string

GenerateSessionID — аналог generate_session_id(), length по умолчанию 6

func GetFreePort

func GetFreePort() (int, error)

GetFreePort — аналог get_free_port()

func HelloMsg

func HelloMsg(minVer, maxVer string) []byte

func I2PBase64Decode

func I2PBase64Decode(s string) ([]byte, error)

func I2PBase64Encode

func I2PBase64Encode(b []byte) string

func IsAddressAccessible

func IsAddressAccessible(addr Address) bool

IsAddressAccessible — аналог is_address_accessible()

func NamingLookupMsg

func NamingLookupMsg(name string) []byte

func SessionCreateMsg

func SessionCreateMsg(style, id, dest, opts string) []byte

func StreamAcceptMsg

func StreamAcceptMsg(id, silent string) []byte

func StreamConnect

func StreamConnect(
	ctx context.Context,
	sessionName string,
	destStr string,
	samAddr Address,
) (*SAMSocket, *Destination, error)

StreamConnect — аналог stream_connect()

func StreamConnectMsg

func StreamConnectMsg(id, dest, silent string) []byte

func StreamForwardMsg

func StreamForwardMsg(id string, port int, opts string) []byte

Types

type Address

type Address struct {
	Host string
	Port int
}

func AddressFromString

func AddressFromString(s string) (Address, error)

AddressFromString — аналог address_from_string("host:port")

func GetSAMAddress

func GetSAMAddress() Address

GetSAMAddress — аналог get_sam_address()

type ClientTunnel

type ClientTunnel struct {
	*I2PTunnel
	RemoteDestination string

	Status TunnelStatus
	// contains filtered or unexported fields
}

func NewClientTunnel

func NewClientTunnel(local Address, remoteDest string, samAddr Address, samClient SAMClient, dest *Destination, sessionName string, opts map[string]string) *ClientTunnel

func (*ClientTunnel) Run

func (t *ClientTunnel) Run(ctx context.Context) error

Run — аналог async def run(self) у ClientTunnel.

func (*ClientTunnel) Stop

func (t *ClientTunnel) Stop()

type DefaultSAMClient

type DefaultSAMClient struct {
	Address Address
	SigType int
}

DefaultSAMClient реализует SAMClient поверх функций из aiosam.go.

func NewDefaultSAMClient

func NewDefaultSAMClient(addr Address) *DefaultSAMClient

func (*DefaultSAMClient) CreateStreamSession

func (c *DefaultSAMClient) CreateStreamSession(ctx context.Context, name, style string, opts map[string]string, dest *Destination, samAddr Address) (StreamSession, error)

func (*DefaultSAMClient) NewDestination

func (c *DefaultSAMClient) NewDestination(ctx context.Context, dest *Destination) (*Destination, error)

func (*DefaultSAMClient) StreamAccept

func (c *DefaultSAMClient) StreamAccept(ctx context.Context, sess StreamSession, samAddr Address) (*IncomingStream, error)

func (*DefaultSAMClient) StreamConnect

func (c *DefaultSAMClient) StreamConnect(ctx context.Context, sess StreamSession, remoteDest string, samAddr Address) (net.Conn, error)

type Destination

type Destination struct {
	Data    []byte
	Base64  string
	PrivKey *PrivateKey
}

func DestLookup

func DestLookup(ctx context.Context, domain string, samAddr Address) (*Destination, error)

DestLookup — аналог dest_lookup()

func DestinationFromBase64

func DestinationFromBase64(b64 string, hasPriv bool) (*Destination, error)

func NewDestination

func NewDestination(data []byte, hasPriv bool) (*Destination, error)

func NewDestinationSAM

func NewDestinationSAM(ctx context.Context, samAddr Address, sigType int) (*Destination, error)

NewDestinationSAM — аналог new_destination()

func (*Destination) Base32

func (d *Destination) Base32() string

func (*Destination) String

func (d *Destination) String() string

type I2PTunnel

type I2PTunnel struct {
	LocalAddress Address

	Destination *Destination
	SessionName string
	Options     map[string]string

	SAMAddress Address
	SAM        SAMClient

	Session StreamSession
}

func NewI2PTunnel

func NewI2PTunnel(local Address, samAddr Address, samClient SAMClient, dest *Destination, sessionName string, opts map[string]string) *I2PTunnel

func (*I2PTunnel) Stop

func (t *I2PTunnel) Stop()

type IncomingStream

type IncomingStream struct {
	Conn      net.Conn
	DestB64   string // исходный dest как строка
	FirstData []byte // первые считанные байты (data после dest\n)
}

IncomingStream — входящее соединение с I2P.

type PrivateKey

type PrivateKey struct {
	Data   []byte
	Base64 string
}

func NewPrivateKey

func NewPrivateKey(data []byte) (*PrivateKey, error)

type SAMClient

type SAMClient interface {
	NewDestination(ctx context.Context, dest *Destination) (*Destination, error)
	CreateStreamSession(ctx context.Context, name, style string, opts map[string]string, dest *Destination, samAddr Address) (StreamSession, error)
	StreamConnect(ctx context.Context, sess StreamSession, remoteDest string, samAddr Address) (net.Conn, error)

	// для серверного туннеля: принять входящее соединение
	StreamAccept(ctx context.Context, sess StreamSession, samAddr Address) (*IncomingStream, error)
}

SAMClient — абстракция поверх SAM API. Реализацию делаешь отдельно.

type SAMError

type SAMError struct {
	Code string
	Msg  string
}

Base SAM error type

func (*SAMError) Error

func (e *SAMError) Error() string

func (*SAMError) Is

func (e *SAMError) Is(target error) bool

type SAMMessage

type SAMMessage struct {
	Cmd    string
	Action string
	Opts   map[string]string
	Raw    string
}

func ParseSAMMessage

func ParseSAMMessage(b []byte) (*SAMMessage, error)

func (*SAMMessage) OK

func (m *SAMMessage) OK() bool

func (*SAMMessage) String

func (m *SAMMessage) String() string

type SAMSession

type SAMSession struct {
	ID          string
	Socket      *SAMSocket
	Destination *Destination
}

SAMSession — аналог create_session() + Session context manager

func CreateSession

func CreateSession(
	ctx context.Context,
	sessionName string,
	samAddr Address,
	style string,
	sigType int,
	dest *Destination,
	options map[string]string,
) (*SAMSession, error)

CreateSession — аналог create_session()

func (*SAMSession) Close

func (s *SAMSession) Close() error

func (*SAMSession) Name

func (s *SAMSession) Name() string

type SAMSocket

type SAMSocket struct {
	Conn   net.Conn
	Reader *bufio.Reader
	Writer *bufio.Writer
}

SAMSocket — аналог (reader, writer)

func GetSAMSocket

func GetSAMSocket(ctx context.Context, samAddr Address) (*SAMSocket, error)

GetSAMSocket — аналог get_sam_socket()

func StreamAccept

func StreamAccept(
	ctx context.Context,
	sessionName string,
	samAddr Address,
) (*SAMSocket, error)

StreamAccept — аналог stream_accept()

type ServerTunnel

type ServerTunnel struct {
	*I2PTunnel

	Status TunnelStatus
	// contains filtered or unexported fields
}

func NewServerTunnel

func NewServerTunnel(local Address, samAddr Address, samClient SAMClient, dest *Destination, sessionName string, opts map[string]string) *ServerTunnel

func (*ServerTunnel) Run

func (t *ServerTunnel) Run(ctx context.Context) error

func (*ServerTunnel) Stop

func (t *ServerTunnel) Stop()

type StreamSession

type StreamSession interface {
	Name() string
	Close() error
}

StreamSession — сессия STREAM в SAM.

type TunnelStatus

type TunnelStatus struct {
	SetupRan    bool
	SetupFailed bool
	Err         error
}

TunnelStatus — аналог self.status из Python.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL