Mult Port + TCP Calibration (SSH DEAD)
This commit is contained in:
@@ -0,0 +1,222 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
type sshTunnelManager struct {
|
||||
wires *wireSelector
|
||||
username string
|
||||
password string
|
||||
internalHost string
|
||||
internalPort int
|
||||
pinFile string
|
||||
udpgwHost string
|
||||
udpgwPort int
|
||||
|
||||
mu sync.Mutex
|
||||
client *ssh.Client
|
||||
closed bool
|
||||
|
||||
firstTCPLogged atomic.Bool
|
||||
udpLogged atomic.Bool
|
||||
}
|
||||
|
||||
func newSSHTunnelManager(wires *wireSelector, username, password, internalHost string, internalPort int, pinFile, udpgwHost string, udpgwPort int) (*sshTunnelManager, error) {
|
||||
username = strings.TrimSpace(username)
|
||||
if username == "" {
|
||||
return nil, errors.New("SSH username is required")
|
||||
}
|
||||
if password == "" {
|
||||
return nil, errors.New("SSH password is required")
|
||||
}
|
||||
if internalHost == "" {
|
||||
internalHost = defaultSSHInternalHostClient
|
||||
}
|
||||
if internalPort < 1 || internalPort > 65535 {
|
||||
return nil, errors.New("invalid SSH internal port")
|
||||
}
|
||||
if udpgwHost == "" {
|
||||
udpgwHost = "dragontcp-udpgw.internal"
|
||||
}
|
||||
if udpgwPort < 1 || udpgwPort > 65535 {
|
||||
return nil, errors.New("invalid UDPGW port")
|
||||
}
|
||||
return &sshTunnelManager{
|
||||
wires: wires, username: username, password: password,
|
||||
internalHost: internalHost, internalPort: internalPort,
|
||||
pinFile: pinFile, udpgwHost: udpgwHost, udpgwPort: udpgwPort,
|
||||
}, nil
|
||||
}
|
||||
|
||||
const (
|
||||
defaultSSHInternalHostClient = "dragontcp-ssh.internal"
|
||||
sshCarrierWriteBatch = 1024 * 1024
|
||||
sshCarrierMaxBuffered = 4 * 1024 * 1024
|
||||
sshCarrierFlushDelay = 2 * time.Millisecond
|
||||
)
|
||||
|
||||
func (m *sshTunnelManager) hostKeyCallback() ssh.HostKeyCallback {
|
||||
return func(hostname string, remote net.Addr, key ssh.PublicKey) error {
|
||||
fingerprint := ssh.FingerprintSHA256(key)
|
||||
if strings.TrimSpace(m.pinFile) == "" {
|
||||
return nil
|
||||
}
|
||||
data, err := os.ReadFile(m.pinFile)
|
||||
if err == nil {
|
||||
expected := strings.TrimSpace(string(data))
|
||||
if expected == fingerprint {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("SSH host key changed: expected %s got %s", expected, fingerprint)
|
||||
}
|
||||
if !os.IsNotExist(err) {
|
||||
return fmt.Errorf("read SSH host key pin: %w", err)
|
||||
}
|
||||
if err := os.WriteFile(m.pinFile, []byte(fingerprint+"\n"), 0600); err != nil {
|
||||
return fmt.Errorf("save SSH host key pin: %w", err)
|
||||
}
|
||||
fmt.Printf("ssh host key pinned: %s\n", fingerprint)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (m *sshTunnelManager) connectLocked() (*ssh.Client, error) {
|
||||
if m.closed {
|
||||
return nil, net.ErrClosed
|
||||
}
|
||||
if m.client != nil {
|
||||
return m.client, nil
|
||||
}
|
||||
|
||||
fmt.Printf("ssh carrier: opening DragonTCP stream to %s:%d\n", m.internalHost, m.internalPort)
|
||||
transport, err := m.wires.dial(m.internalHost, m.internalPort)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("DragonTCP SSH carrier failed: %w", err)
|
||||
}
|
||||
// SSH emits encrypted packets in ~tens-of-KiB writes. Feeding each one
|
||||
// directly into the transactional DragonTCP transport creates a full RTT per
|
||||
// SSH packet. Combine them behind bounded backpressure so a busy SSH stream
|
||||
// reaches DragonTCP's discovered 256 KiB-1 MiB chunk sizes instead.
|
||||
transport = newSSHCarrierConn(transport, sshCarrierWriteBatch, sshCarrierMaxBuffered, sshCarrierFlushDelay)
|
||||
fmt.Printf("ssh carrier: DragonTCP stream connected write_batch=%d max_buffer=%d flush_delay=%s\n", sshCarrierWriteBatch, sshCarrierMaxBuffered, sshCarrierFlushDelay)
|
||||
cfg := &ssh.ClientConfig{
|
||||
User: m.username,
|
||||
Auth: []ssh.AuthMethod{ssh.Password(m.password)},
|
||||
HostKeyCallback: m.hostKeyCallback(),
|
||||
ClientVersion: "SSH-2.0-DragonTCP",
|
||||
}
|
||||
addr := net.JoinHostPort(m.internalHost, fmt.Sprintf("%d", m.internalPort))
|
||||
cc, chans, reqs, err := ssh.NewClientConn(transport, addr, cfg)
|
||||
if err != nil {
|
||||
_ = transport.Close()
|
||||
return nil, fmt.Errorf("SSH handshake/auth failed: %w", err)
|
||||
}
|
||||
client := ssh.NewClient(cc, chans, reqs)
|
||||
m.client = client
|
||||
fmt.Printf("ssh authenticated: user=%s transport=DragonTCP mode=tunnel-only\n", m.username)
|
||||
go m.keepalive(client)
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func (m *sshTunnelManager) getClient() (*ssh.Client, error) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
return m.connectLocked()
|
||||
}
|
||||
|
||||
func (m *sshTunnelManager) invalidate(client *ssh.Client) {
|
||||
m.mu.Lock()
|
||||
if m.client == client {
|
||||
m.client = nil
|
||||
_ = client.Close()
|
||||
}
|
||||
m.mu.Unlock()
|
||||
}
|
||||
|
||||
func (m *sshTunnelManager) keepalive(client *ssh.Client) {
|
||||
ticker := time.NewTicker(20 * time.Second)
|
||||
defer ticker.Stop()
|
||||
for range ticker.C {
|
||||
_, _, err := client.SendRequest("keepalive@dragontcp", true, nil)
|
||||
if err != nil {
|
||||
m.invalidate(client)
|
||||
return
|
||||
}
|
||||
m.mu.Lock()
|
||||
same := m.client == client && !m.closed
|
||||
m.mu.Unlock()
|
||||
if !same {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *sshTunnelManager) Warmup() error {
|
||||
_, err := m.getClient()
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *sshTunnelManager) DialTCP(host string, port int) (net.Conn, error) {
|
||||
target := net.JoinHostPort(host, fmt.Sprintf("%d", port))
|
||||
var lastErr error
|
||||
for attempt := 0; attempt < 2; attempt++ {
|
||||
client, err := m.getClient()
|
||||
if err != nil {
|
||||
// Authentication, handshake, or physical-carrier failures are hard
|
||||
// boundaries. Retrying them immediately would duplicate expensive
|
||||
// DragonTCP/SSH connection attempts and can overload the server.
|
||||
return nil, err
|
||||
}
|
||||
conn, err := client.Dial("tcp", target)
|
||||
if err == nil {
|
||||
if m.firstTCPLogged.CompareAndSwap(false, true) {
|
||||
fmt.Printf("ssh traffic: direct-tcpip active\n")
|
||||
}
|
||||
return conn, nil
|
||||
}
|
||||
lastErr = err
|
||||
// A direct-tcpip channel rejection means the SSH transport is healthy
|
||||
// and only this destination failed (for example ECONNREFUSED or a
|
||||
// server-side target-policy rejection). Do not tear down the persistent
|
||||
// SSH carrier or redial the destination in that case.
|
||||
var openErr *ssh.OpenChannelError
|
||||
if errors.As(err, &openErr) {
|
||||
return nil, err
|
||||
}
|
||||
m.invalidate(client)
|
||||
}
|
||||
if lastErr == nil {
|
||||
lastErr = errors.New("SSH target dial failed")
|
||||
}
|
||||
return nil, lastErr
|
||||
}
|
||||
|
||||
func (m *sshTunnelManager) DialUDPGW() (net.Conn, error) {
|
||||
conn, err := m.DialTCP(m.udpgwHost, m.udpgwPort)
|
||||
if err == nil && m.udpLogged.CompareAndSwap(false, true) {
|
||||
fmt.Printf("ssh traffic: UDPGW active target=%s:%d\n", m.udpgwHost, m.udpgwPort)
|
||||
}
|
||||
return conn, err
|
||||
}
|
||||
|
||||
func (m *sshTunnelManager) Close() error {
|
||||
m.mu.Lock()
|
||||
m.closed = true
|
||||
client := m.client
|
||||
m.client = nil
|
||||
m.mu.Unlock()
|
||||
if client != nil {
|
||||
return client.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user