Fix IPv6 literal host handling

This commit is contained in:
世界 2026-10-22 00:12:43 +08:00
parent 9c24112d12
commit 42f487bd0d
No known key found for this signature in database
GPG key ID: CD109927C34A63C4
6 changed files with 45 additions and 30 deletions

View file

@ -34,6 +34,7 @@ import (
"github.com/sagernet/sing/common/debug"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/logger"
M "github.com/sagernet/sing/common/metadata"
"github.com/sagernet/sing/common/ntp"
aTLS "github.com/sagernet/sing/common/tls"
@ -254,7 +255,15 @@ func realityClientFallback(ctx context.Context, uConn net.Conn, serverName strin
},
},
}
request, _ := http.NewRequest("GET", "https://"+serverName, nil)
serverAddress := M.ParseSocksaddrHostPort(serverName, 0)
host := serverAddress.AddrString()
if serverAddress.IsIPv6() {
host = "[" + host + "]"
}
request, err := http.NewRequest("GET", "https://"+host, nil)
if err != nil {
return
}
request.Header.Set("User-Agent", fingerprint.Client)
request.AddCookie(&http.Cookie{Name: "padding", Value: strings.Repeat("0", mRand.Intn(32)+30)})
response, err := client.Do(request)

View file

@ -5,10 +5,8 @@ import (
"context"
"errors"
"io"
"net"
"net/http"
"net/url"
"strconv"
"sync"
"sync/atomic"
"time"
@ -82,15 +80,14 @@ func NewHTTPS(ctx context.Context, logger log.ContextLogger, tag string, options
host = options.Server
}
}
destinationURL := url.URL{
Scheme: "https",
Host: host,
}
if destinationURL.Host == "" {
destinationURL.Host = options.Server
}
destinationAddress := M.ParseSocksaddrHostPort(host, options.ServerPort)
destinationURL := url.URL{Scheme: "https"}
if options.ServerPort != 0 && options.ServerPort != 443 {
destinationURL.Host = net.JoinHostPort(destinationURL.Host, strconv.Itoa(int(options.ServerPort)))
destinationURL.Host = destinationAddress.String()
} else if destinationAddress.IsIPv6() {
destinationURL.Host = "[" + destinationAddress.AddrString() + "]"
} else {
destinationURL.Host = destinationAddress.AddrString()
}
path := options.Path
if path == "" {

View file

@ -4,10 +4,8 @@ import (
"bytes"
"context"
"io"
"net"
"net/http"
"net/url"
"strconv"
"sync"
"github.com/sagernet/quic-go"
@ -60,6 +58,7 @@ func NewHTTP3(ctx context.Context, logger log.ContextLogger, tag string, options
if err != nil {
return nil, err
}
tlsConfig.SetNextProtos([]string{http3.NextProtoH3})
stdConfig, err := tlsConfig.STDConfig()
if err != nil {
return nil, err
@ -75,15 +74,14 @@ func NewHTTP3(ctx context.Context, logger log.ContextLogger, tag string, options
host = options.Server
}
}
destinationURL := url.URL{
Scheme: "https",
Host: host,
}
if destinationURL.Host == "" {
destinationURL.Host = options.Server
}
destinationAddress := M.ParseSocksaddrHostPort(host, options.ServerPort)
destinationURL := url.URL{Scheme: "https"}
if options.ServerPort != 0 && options.ServerPort != 443 {
destinationURL.Host = net.JoinHostPort(destinationURL.Host, strconv.Itoa(int(options.ServerPort)))
destinationURL.Host = destinationAddress.String()
} else if destinationAddress.IsIPv6() {
destinationURL.Host = "[" + destinationAddress.AddrString() + "]"
} else {
destinationURL.Host = destinationAddress.AddrString()
}
path := options.Path
if path == "" {
@ -115,12 +113,12 @@ func NewHTTP3(ctx context.Context, logger log.ContextLogger, tag string, options
func (t *HTTP3Transport) newTransport() *http3.Transport {
return &http3.Transport{
Dial: func(ctx context.Context, addr string, tlsCfg *tls.STDConfig, cfg *quic.Config) (*quic.Conn, error) {
Dial: func(ctx context.Context, _ string, _ *tls.STDConfig, cfg *quic.Config) (*quic.Conn, error) {
conn, dialErr := t.dialer.DialContext(ctx, N.NetworkUDP, t.serverAddr)
if dialErr != nil {
return nil, dialErr
}
quicConn, dialErr := quic.DialEarlyConn(ctx, conn, tlsCfg, cfg)
quicConn, dialErr := quic.DialEarlyConn(ctx, conn, t.tlsConfig, cfg)
if dialErr != nil {
conn.Close()
return nil, dialErr
@ -133,7 +131,6 @@ func (t *HTTP3Transport) newTransport() *http3.Transport {
}()
return quicConn, nil
},
TLSClientConfig: t.tlsConfig,
}
}

View file

@ -308,11 +308,14 @@ func (d *Service) startMeshWithHost(derpServer *derpserver.Server, server *optio
logf := func(format string, args ...any) {
d.logger.Debug(F.ToString("mesh(", hostname, "): ", fmt.Sprintf(format, args...)))
}
meshAddress := M.ParseSocksaddrHostPort(hostname, server.ServerPort)
var meshHost string
if server.ServerPort == 0 || server.ServerPort == 443 {
meshHost = hostname
if server.ServerPort != 0 && server.ServerPort != 443 {
meshHost = meshAddress.String()
} else if meshAddress.IsIPv6() {
meshHost = "[" + meshAddress.AddrString() + "]"
} else {
meshHost = M.ParseSocksaddrHostPort(hostname, server.ServerPort).String()
meshHost = meshAddress.AddrString()
}
var serverURL string
if stdConfig != nil {
@ -328,7 +331,7 @@ func (d *Service) startMeshWithHost(derpServer *derpserver.Server, server *optio
meshClient.MeshKey = derpServer.MeshKey()
meshClient.WatchConnectionChanges = true
meshClient.SetURLDialer(func(ctx context.Context, network, addr string) (net.Conn, error) {
return meshDialer.DialContext(ctx, network, M.ParseSocksaddr(addr))
return meshDialer.DialContext(ctx, network, M.ParseSocksaddrHostPort(server.Server, M.ParseSocksaddr(addr).Port))
})
add := func(m derp.PeerPresentMessage) { derpServer.AddPacketForwarder(m.Key, meshClient) }
remove := func(m derp.PeerGoneMessage) { derpServer.RemovePacketForwarder(m.Peer, meshClient) }

View file

@ -114,7 +114,11 @@ func (c *Client) dialHTTP(ctx context.Context) (net.Conn, error) {
}
switch hostLen := len(c.host); hostLen {
case 0:
request.Host = c.serverAddr.AddrString()
if c.serverAddr.IsIPv6() {
request.Host = "[" + c.serverAddr.AddrString() + "]"
} else {
request.Host = c.serverAddr.AddrString()
}
case 1:
request.Host = c.host[0]
default:

View file

@ -40,7 +40,12 @@ func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, opt
if options.Host != "" {
host = options.Host
} else if tlsConfig != nil && tlsConfig.ServerName() != "" {
host = tlsConfig.ServerName()
serverName := M.ParseSocksaddrHostPort(tlsConfig.ServerName(), 0)
if serverName.IsIPv6() {
host = "[" + serverName.AddrString() + "]"
} else {
host = serverName.AddrString()
}
} else {
host = serverAddr.String()
}