tsunami

package module
v0.1.2 Latest Latest
Warning

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

Go to latest
Published: Nov 3, 2026 License: GPL-2.0 Imports: 14 Imported by: 0

README

sing-tsunami

TSUNAMI proxy protocol client/server library, extracted from the TSUNAMI implementation (https://github.com/RavenholmAlpha/tsunami, MIT) so it can be embedded in sing-box and other Go programs.

The library implements the wire protocol only. Transport concerns (TCP, TLS, uTLS fingerprints, sing-box routing/accounting) belong to the caller:

  • PROTOCOL.md — the public wire specification (framing, authentication, settings, padding v2, HTTPS fronting, UoT, versioning, and the differences from AnyTLS).
  • protocol/ — frame format, commands, authentication, settings, session multiplexing and streams.
  • padding/ — TSUNAMI padding scheme v2 parser and per-stream padding writer.
  • fronting/ — HTTPS/HTTP2 (and WebSocket) fronting: request signing and verification, client tunnel conn, server-side HTTP/2 handler, and the decoy site handler (builtin, local, remote camouflage modes).
  • root package tsunami — Client (session pool, Dial/CreateStream) and Service (server-side authentication and per-stream handler).

License

This module is licensed under the GNU General Public License, version 3 or later (see LICENSE). Portions are derived from the MIT-licensed TSUNAMI reference implementation; see NOTICE for the attribution and the MIT text.

Usage sketch

client, err := tsunami.NewClient(ctx, tsunami.ClientConfig{
    Password: "secret",
    DialOut: func(ctx context.Context) (net.Conn, error) {
        conn, err := tlsDialer.DialContext(ctx, "tcp", serverAddr)
        if err != nil {
            return nil, err
        }
        if frontingEnabled {
            return fronting.NewClientConn(conn, fronting.Config{...})
        }
        return conn, nil
    },
})
conn, err := client.Dial(ctx, "example.com:443")
service, err := tsunami.NewService(tsunami.ServiceConfig{
    Users: []tsunami.User{{Name: "alice", Password: "secret"}},
    Handler: func(ctx context.Context, conn net.Conn, source net.Addr, destination string) {
        // route conn to destination
    },
})
err = service.NewConnection(ctx, conn, remoteAddr)

See DESIGN.md for the full API and sing-box integration contract.

Documentation

Overview

Package tsunami implements the TSUNAMI proxy protocol: the client side (session pool, muxed streams, authentication, padding) and the service side (authentication, settings exchange, per-stream handler callback).

The package implements the wire protocol only. Transport concerns - TCP, TLS, uTLS fingerprints, fronting tunnels, routing and accounting - belong to the caller. The protocol, padding and fronting details live in the sibling packages protocol, padding and fronting.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ReadAddr

func ReadAddr(r io.Reader) (string, error)

ReadAddr reads one SOCKS5-encoded destination written by WriteAddr and returns it as "host:port".

IPv6 hosts are returned in bracketed form ("[2001:db8::1]:443", via net.JoinHostPort), so callers that need a bare host should split the result with net.SplitHostPort.

func WriteAddr

func WriteAddr(w io.Writer, destination string) error

WriteAddr writes destination to w using the SOCKS5 address encoding the TSUNAMI protocol uses for stream targets (ATYP byte, address, port).

destination must be "host:port"; an IPv6 host needs the usual brackets ("[2001:db8::1]:443"). Hosts are sent as IPv4, IPv6, or a domain name, whichever form the text takes.

Types

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client is a TSUNAMI client. It maintains a pool of multiplexed sessions and opens one stream per proxied connection.

func NewClient

func NewClient(ctx context.Context, cfg ClientConfig) (*Client, error)

NewClient creates a TSUNAMI client. It does not dial: sessions are created lazily by the pool when CreateStream/Dial needs one. ctx is accepted for symmetry with the rest of the API; per-session contexts are taken from CreateStream/Dial.

func (*Client) Close

func (c *Client) Close() error

Close shuts down the client and all sessions.

func (*Client) CreateStream

func (c *Client) CreateStream(ctx context.Context) (net.Conn, error)

CreateStream opens a new multiplexed stream. The returned connection carries raw tunnel bytes; the caller must write the destination address itself (Dial does that) and must close the connection when done.

func (*Client) Dial

func (c *Client) Dial(ctx context.Context, destination string) (net.Conn, error)

Dial opens a new stream to destination ("host:port") by creating a stream and writing the target address as its first payload.

type ClientConfig

type ClientConfig struct {
	// Password is the TSUNAMI user password; auth sends SHA-256(password).
	Password string
	// DialOut returns a transport connection ready for the TSUNAMI handshake:
	// plain TLS, or a fronting tunnel returned by fronting.NewClientConn.
	// Called by the session pool when it needs a new session.
	DialOut func(ctx context.Context) (net.Conn, error)
	// PaddingScheme is the initial scheme text; nil uses padding.DefaultScheme().
	PaddingScheme []byte
	// IdleSessionCheckInterval is how often the pool scans for idle sessions.
	// Default 30s.
	IdleSessionCheckInterval time.Duration
	// IdleSessionTimeout is the nominal idle timeout per session. The effective
	// deadline is jittered by [0.7, 1.3) on every check. Default 5m.
	IdleSessionTimeout time.Duration
	// MinIdleSession is the minimum number of idle sessions to keep alive.
	// Default 0: an idle client drains to zero sessions.
	MinIdleSession int
	// MaxStreams bounds concurrent streams per session. Defaults to 0
	// (unlimited): the client is the stream opener, while the server enforces
	// its own per-session limit. A positive value makes the client fail fast
	// with protocol.ErrTooManyStreams instead of over-subscribing a session.
	MaxStreams int
}

ClientConfig configures a Client.

type Service

type Service struct {
	// contains filtered or unexported fields
}

Service is the server side of the TSUNAMI protocol: it authenticates connections, negotiates settings and padding, and dispatches opened streams to the configured Handler.

func NewService

func NewService(cfg ServiceConfig) (*Service, error)

NewService creates a TSUNAMI service.

func (*Service) NewConnection

func (s *Service) NewConnection(ctx context.Context, conn net.Conn, source net.Addr) error

NewConnection runs the server side of one TSUNAMI session on conn. conn must already be past the transport handshake (plain TLS, or a fronting tunnel from fronting.ServeHTTP2/ServeHTTP1). source is the client's transport address; nil falls back to conn.RemoteAddr().

NewConnection blocks until the session ends and closes conn before returning. A clean peer disconnect ends the session with a nil error; only framing and write failures are reported.

type ServiceConfig

type ServiceConfig struct {
	// Users is the static credential list. Passwords are hashed with SHA-256
	// at construction time.
	Users []User
	// PaddingScheme is the server's scheme text; nil uses
	// padding.DefaultScheme().
	PaddingScheme []byte
	// Handler runs once per opened stream, in its own goroutine. destination
	// is the SOCKS5 address the client wrote first ("host:port", IPv6 hosts
	// are bracketed unless the peer encoded a bare address; use
	// net.SplitHostPort-style consumers). The handler owns conn and must close
	// it.
	Handler func(ctx context.Context, conn net.Conn, source net.Addr, destination string)
	// MaxStreams bounds concurrent streams per session. Defaults to
	// protocol.DefaultMaxStreams. A malicious peer that opens streams without
	// using them cannot exhaust memory/goroutines beyond this bound.
	MaxStreams int
}

ServiceConfig configures a Service.

type User

type User struct {
	Name     string
	Password string
}

User is a static TSUNAMI credential. The password itself never crosses the wire: the client authenticates with SHA-256(password).

Directories

Path Synopsis
Package fronting implements the TSUNAMI HTTPS/HTTP2/WebSocket fronting layer: HTTP-layer request signing and replay protection, client and server side net.Conn adapters for the authenticated tunnel, and the decoy site handler that answers unauthenticated traffic.
Package fronting implements the TSUNAMI HTTPS/HTTP2/WebSocket fronting layer: HTTP-layer request signing and replay protection, client and server side net.Conn adapters for the authenticated tunnel, and the decoy site handler that answers unauthenticated traffic.
Package padding implements the TSUNAMI programmable padding system.
Package padding implements the TSUNAMI programmable padding system.
Package protocol defines the TSUNAMI proxy protocol wire format and commands.
Package protocol defines the TSUNAMI proxy protocol wire format and commands.

Jump to

Keyboard shortcuts

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