dial

package
v0.4.1 Latest Latest
Warning

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

Go to latest
Published: Jun 23, 2026 License: MIT Imports: 23 Imported by: 0

Documentation

Overview

Package dial provides SSH tunnel dialing. It establishes connections to remote network addresses by routing through an SSH server, with optional connection pooling and keep-alive support.

Index

Examples

Constants

View Source
const DefaultPort = "22"

DefaultPort is the SSH port used when Config.Port is empty.

Variables

View Source
var (
	// ErrUserRequired is returned by [Config.Validate] when Username is empty.
	ErrUserRequired = errors.New("username is required")
	// ErrHostRequired is returned by [Config.Validate] when Host is empty.
	ErrHostRequired = errors.New("host is required")
	// ErrAddrRequired is returned by [Config.Validate] when Net or Addr is empty.
	ErrAddrRequired = errors.New("addr is required")
)

Functions

func DialContext

func DialContext(ctx context.Context, addr string) (net.Conn, error)

DialContext opens a connection to the remote address encoded in addr, tunneling through the SSH server described by that address. The addr format is the same as accepted by ParseAddr.

By default a pooled SSH client is reused for concurrent calls to the same server (connection multiplexing), equivalent to a persistent tunnel. Set ConnMux=false in the query string to open a fresh SSH connection per call.

The returned net.Conn is ready for use. Calling Close releases the connection; the underlying SSH client is closed automatically when the last multiplexed connection is released.

Example
package main

import (
	"context"

	"github.com/TelpeNight/mytunnel/dial"
)

func main() {
	// Dial a Unix socket on the remote host through SSH.
	// Keep-alive probes run every 30 seconds; the connection is closed after
	// 3 unanswered probes.
	conn, err := dial.DialContext(context.Background(),
		"alice@bastion.example.com/var/run/app.sock?ServerAliveInterval=30&ServerAliveCountMax=3")
	if err != nil {
		// handle error
		return
	}
	defer conn.Close()

	// conn is a plain net.Conn ready for use.
	_ = conn
}

Types

type Config

type Config struct {
	// Username is the SSH login name.
	Username string
	// Password is the SSH password. If nil, only public-key auth is attempted.
	Password *string
	// Host is the SSH server hostname or IP address, stored as provided.
	// An IPv6 literal may or may not include surrounding brackets depending
	// on whether the caller included them.
	Host string
	// Port is the SSH server port as a string, stored as provided.
	// Empty means [DefaultPort] (22). Any non-numeric value is passed through
	// and will produce an error at dial time.
	Port string
	// Net is the network type of the destination ("tcp" or "unix").
	Net string
	// Addr is the address of the destination on the remote host.
	Addr string
	// Params holds optional query parameters controlling keep-alive and
	// connection behaviour. See [ParseAddr] for supported keys.
	Params url.Values
}

Config holds the parsed parameters for an SSH tunnel connection. Use ParseAddr to construct a Config from an address string.

Field values are stored exactly as provided by the caller — no normalisation is applied. For example, Host may be a plain hostname, an IPv4 address, or a bracketed IPv6 literal such as "[::1]", whichever form appeared in the address string. Config.Validate checks that the fields required for a successful dial are present; everything else (port validity, host resolvability, …) is left to the underlying network stack.

func ParseAddr

func ParseAddr(addr string) (Config, error)

ParseAddr parses an SSH tunnel address string into a Config.

The address format is:

[username[:password]@]host[:port][/destination][?params]

Parsing is purely structural: each token is split out and stored as-is, without validating its value. Use Config.Validate to check that the result is complete enough to dial. Malformed values (bad port, unresolvable host, …) are not rejected here — they will produce errors at dial time.

The only error ParseAddr returns is a malformed query string in the params component.

The destination component is resolved as follows: if it looks like host:port or a bare IP address, Net is set to "tcp"; otherwise it is treated as a Unix socket path and Net is set to "unix".

When the address contains no "@", it is in MySQL-DSN-escaped form and is decoded greedily left-to-right: "((" becomes a literal "(", and "(a)" becomes "@". This is the escape for embedding the address in a MySQL DSN, where a bare "@" is a field delimiter, so the embedded address must contain none. In an address that already contains a bare "@", no decoding happens and "(" / "(a)" are literal.

Supported query parameters:

  • ServerAliveInterval — keep-alive probe interval in seconds
  • ServerAliveCountMax — unanswered probes before closing (default 3)
  • ServerAliveTimeout — per-probe response timeout (default = ServerAliveInterval)
  • ServerAliveLagMax — debugger-pause grace period added to the timeout (default 2s)
  • ConnMux — "true" (default) to share one SSH client per server; "false" for a new connection per Dial
Example
package main

import (
	"fmt"

	"github.com/TelpeNight/mytunnel/dial"
)

func main() {
	config, err := dial.ParseAddr("alice@bastion.example.com/tmp/mysql.sock")
	if err != nil {
		panic(err)
	}
	fmt.Println(config.Host)
	fmt.Println(config.Net)
	fmt.Println(config.Addr)
}
Output:
bastion.example.com
unix
/tmp/mysql.sock

func (Config) String

func (c Config) String() string

String serialises the config back into an address string accepted by ParseAddr. The only transformation applied is bracketing a bare IPv6 host when a port is also present — without brackets the colon would be ambiguous as a port separator. All other field values are written exactly as stored.

func (Config) Validate added in v0.3.0

func (c Config) Validate() error

Validate checks that the fields required for a correct dial and SSH authentication are present: Username, Host, and the destination Net+Addr. It does not validate field values — port format, host resolvability, and similar concerns are left to the underlying dialer and SSH library, which will produce actionable errors if anything is wrong.

DialContext calls Validate automatically. Call it explicitly when constructing a Config by hand rather than via ParseAddr.

Jump to

Keyboard shortcuts

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