Skip to content

Hysteria: Fix Unix masquerade socket path - #6705

Open
XXcipherX wants to merge 1 commit into
XTLS:mainfrom
XXcipherX:fix/hysteria-unix-masquerade-path
Open

Hysteria: Fix Unix masquerade socket path#6705
XXcipherX wants to merge 1 commit into
XTLS:mainfrom
XXcipherX:fix/hysteria-unix-masquerade-path

Conversation

@XXcipherX

@XXcipherX XXcipherX commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Problem

The current Xray code handles Unix-socket targets in the following order:

case "", "unix":
    u = &url.URL{Scheme: "http", Host: "localhost"}
    path := u.Path

    dialer := &net.Dialer{Timeout: 30 * time.Second}
    transport = transport.Clone()
    transport.Proxy = nil
    transport.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) {
        return dialer.DialContext(ctx, "unix", path)
    }

The original parsed URL is overwritten before its path is saved:

u = &url.URL{Scheme: "http", Host: "localhost"}

The replacement URL has an empty Path, so the next assignment always produces:

path == ""

Consequently, the custom transport effectively attempts:

dialer.DialContext(ctx, "unix", "")

On Linux, this fails with an error similar to:

dial unix: missing address

The Hysteria masquerade handler then returns 502 Bad Gateway, while Xray logs:

HTTP reverse proxy error

This affects all supported Unix-socket target formats, not just one particular URL form, because the parsed socket path is discarded in every case.

Upstream behavior

In the upstream Hysteria implementation, the socket path is saved before constructing the synthetic HTTP target:

socketPath := parsedURL.Path

Only after that does it return the target used by httputil.ReverseProxy:

return &url.URL{
    Scheme: "http",
    Host:   "localhost",
}, transport, nil

The custom transport therefore captures the original socket path:

transport.DialContext = func(ctx context.Context, _, _ string) (net.Conn, error) {
    return dialer.DialContext(ctx, "unix", socketPath)
}

The incorrect ordering was introduced while adapting this logic in #6565 it is not caused by the upstream Hysteria implementation.

Fix

Save u.Path before replacing u with the synthetic http://localhost target:

case "", "unix":
    path := u.Path
    u = &url.URL{Scheme: "http", Host: "localhost"}

This preserves the original Unix socket address while leaving HTTP and HTTPS masquerade behavior unchanged.

@LjhAUMEM

LjhAUMEM commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

这里确实同步错了,感谢修复

改的代码行数少的话也不用写这么多描述,看代码就可以知道意图

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants