ingress: add unix+tcp:// service for raw stream forwarding over unix sockets
Introduce unixSocketTCPService, a new OriginService that dials a unix
socket and forwards raw bytes bidirectionally via WebSocket, without any
HTTP wrapping. This is the unix-socket analogue of tcpOverWSService.
A new ingress URL scheme unix+tcp:<path> is recognised during ingress
validation and maps to this service type. Example config:
ingress:
- hostname: ssh.example.com
service: unix+tcp:/run/sshd.sock
The scheme name unix+tcp mirrors the existing unix+tls modifier pattern:
the suffix describes the transport style, not the application protocol,
so the service works equally well for SSH, RDP, or any other stream-based
protocol whose daemon listens on a unix socket.
The implementation reuses the existing tcpOverWSConnection and
DefaultStreamHandler machinery; the only difference from ssh:// (TCP) is
that the underlying net.Conn is obtained via net.Dial("unix", path).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
d2a87e9b93
commit
07c2516b3c
|
|
@ -255,6 +255,10 @@ func validateIngress(ingress []config.UnvalidatedIngressRule, defaults OriginReq
|
|||
} else if prefix := "unix+tls:"; strings.HasPrefix(r.Service, prefix) {
|
||||
path := strings.TrimPrefix(r.Service, prefix)
|
||||
service = &unixSocketPath{path: path, scheme: "https"}
|
||||
} else if prefix := "unix+tcp:"; strings.HasPrefix(r.Service, prefix) {
|
||||
// Stream raw bytes (e.g. SSH, RDP protocol) directly into a unix socket without HTTP wrapping
|
||||
path := strings.TrimPrefix(r.Service, prefix)
|
||||
service = &unixSocketTCPService{path: path}
|
||||
} else if prefix := "http_status:"; strings.HasPrefix(r.Service, prefix) {
|
||||
statusCode, err := strconv.Atoi(strings.TrimPrefix(r.Service, prefix))
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -119,3 +119,14 @@ func (o *tcpOverWSService) EstablishConnection(ctx context.Context, dest string,
|
|||
func (o *socksProxyOverWSService) EstablishConnection(_ context.Context, _ string, _ *zerolog.Logger) (OriginConnection, error) {
|
||||
return o.conn, nil
|
||||
}
|
||||
|
||||
func (o *unixSocketTCPService) EstablishConnection(ctx context.Context, _ string, _ *zerolog.Logger) (OriginConnection, error) {
|
||||
conn, err := o.dialer.DialContext(ctx, "unix", o.path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &tcpOverWSConnection{
|
||||
conn: conn,
|
||||
streamHandler: o.streamHandler,
|
||||
}, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,6 +46,14 @@ type unixSocketPath struct {
|
|||
transport *http.Transport
|
||||
}
|
||||
|
||||
// unixSocketTCPService is an OriginService that streams raw bytes (e.g. SSH, RDP) directly into a
|
||||
// unix socket, bypassing HTTP entirely. It is the unix-socket analogue of tcpOverWSService.
|
||||
type unixSocketTCPService struct {
|
||||
path string
|
||||
streamHandler streamHandlerFunc
|
||||
dialer net.Dialer
|
||||
}
|
||||
|
||||
func (o *unixSocketPath) String() string {
|
||||
scheme := ""
|
||||
if o.scheme == "https" {
|
||||
|
|
@ -67,6 +75,21 @@ func (o unixSocketPath) MarshalJSON() ([]byte, error) {
|
|||
return json.Marshal(o.String())
|
||||
}
|
||||
|
||||
func (o *unixSocketTCPService) String() string {
|
||||
return "unix+tcp:" + o.path
|
||||
}
|
||||
|
||||
func (o *unixSocketTCPService) start(_ *zerolog.Logger, _ <-chan struct{}, cfg OriginRequestConfig) error {
|
||||
o.streamHandler = DefaultStreamHandler
|
||||
o.dialer.Timeout = cfg.ConnectTimeout.Duration
|
||||
o.dialer.KeepAlive = cfg.TCPKeepAlive.Duration
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o unixSocketTCPService) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(o.String())
|
||||
}
|
||||
|
||||
type httpService struct {
|
||||
url *url.URL
|
||||
hostHeader string
|
||||
|
|
|
|||
Loading…
Reference in New Issue