Files
privatae-bastion/client-go/lanedial.go
T
Privatae 48899b41a9
ci / personal-data (push) Successful in 4s
ci / test (push) Successful in 4m58s
ci / fuzz (push) Successful in 3m33s
bastion 0.63.1
2026-11-03 22:56:18 +00:00

82 lines
2.8 KiB
Go

package main
// lanedial.go: the one place a lane turns the connection its pairing's
// transport hands it into the mutual TLS the lane runs inside.
//
// Every transport but one hands a lane a plain connection (the tunnel, the
// lane socket, a Host's lane port), and the TLS is done here exactly as the
// WebSocket library did it before: the pairing's lane configuration, the
// server name it names, the handshake under the dial's context, and the name
// checked once more. A Host that connects to this server (hostdoor.go) hands
// the lane a connection whose TLS the door already did, under the same
// configuration (the Host's CA pinned, host.cseries.internal, this bastion's
// operator certificate): that one is passed on as it is. So the lane code is
// the same for every pairing; only the dial differs.
import (
"context"
"crypto/tls"
"net"
"net/http"
"time"
"github.com/gorilla/websocket"
)
// laneTLSDial is the TLS dial every lane uses: dialHost's connection with the
// lane's TLS done on it, or a Host-opened connection as the door left it.
func laneTLSDial(dialHost func(ctx context.Context) (net.Conn, error), tlsCfg *tls.Config) func(ctx context.Context, network, addr string) (net.Conn, error) {
return func(ctx context.Context, _, addr string) (net.Conn, error) {
c, err := dialHost(ctx)
if err != nil {
return nil, err
}
if hc, ok := c.(*hostOpenedConn); ok {
return hc, nil
}
cfg := tlsCfg.Clone()
if cfg == nil {
cfg = &tls.Config{}
}
if cfg.ServerName == "" {
if h, _, err := net.SplitHostPort(addr); err == nil {
cfg.ServerName = h
} else {
cfg.ServerName = addr
}
}
tc := tls.Client(c, cfg)
if err := tc.HandshakeContext(ctx); err != nil {
_ = c.Close()
return nil, err
}
if !cfg.InsecureSkipVerify {
if err := tc.VerifyHostname(cfg.ServerName); err != nil {
_ = tc.Close()
return nil, err
}
}
return tc, nil
}
}
// laneWSDialer is the WebSocket dialer every lane worker pool uses.
func laneWSDialer(tlsCfg *tls.Config, dialHost func(ctx context.Context) (net.Conn, error)) *websocket.Dialer {
return &websocket.Dialer{
NetDialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { return dialHost(ctx) },
NetDialTLSContext: laneTLSDial(dialHost, tlsCfg),
TLSClientConfig: tlsCfg,
HandshakeTimeout: 20 * time.Second,
}
}
// laneHTTPTransport is the HTTP transport of a local pairing's requests (the
// heartbeat, git credentials, store proposals, context pulls).
func laneHTTPTransport(dialHost func(ctx context.Context) (net.Conn, error), tlsCfg *tls.Config) *http.Transport {
return &http.Transport{
DialContext: func(ctx context.Context, _, _ string) (net.Conn, error) { return dialHost(ctx) },
DialTLSContext: laneTLSDial(dialHost, tlsCfg),
TLSClientConfig: tlsCfg.Clone(),
}
}