Merge tag 'v1.13.14' into extended

Integrate upstream sing-box v1.13.14 (18 commits, v1.13.12..v1.13.14).

Conflict resolutions:
- Makefile: keep fork's upload_android (no otherLegacy, codeberg-release.sh),
  add upstream's SFA-version-metadata.json step.
- go.sum: regenerated via go mod tidy from merged go.mod.
- transport/wireguard/endpoint_options.go: keep fork fields, add ICMPTimeout.
- clients/android, clients/apple: keep fork's submodule pointers.
This commit is contained in:
Shtorm
2026-06-26 01:28:40 +03:00
31 changed files with 265 additions and 170 deletions

View File

@@ -20,6 +20,7 @@ import (
"github.com/sagernet/sing/common/logger"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
"github.com/sagernet/sing/service"
)
func RegisterOutbound(registry *outbound.Registry) {
@@ -37,10 +38,12 @@ type Outbound struct {
outbound.Adapter
ctx context.Context
logger logger.ContextLogger
network adapter.NetworkManager
dialer dialer.ParallelInterfaceDialer
domainStrategy C.DomainStrategy
fallbackDelay time.Duration
isEmpty bool
myAddresses common.TypedValue[[]netip.Prefix]
}
func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.DirectOutboundOptions) (adapter.Outbound, error) {
@@ -61,6 +64,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
Adapter: outbound.NewAdapterWithDialerOptions(C.TypeDirect, tag, []string{N.NetworkTCP, N.NetworkUDP, N.NetworkICMP}, options.DialerOptions),
ctx: ctx,
logger: logger,
network: service.FromContext[adapter.NetworkManager](ctx),
//nolint:staticcheck
domainStrategy: C.DomainStrategy(options.DomainStrategy),
fallbackDelay: time.Duration(options.FallbackDelay),
@@ -74,7 +78,48 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
return outbound, nil
}
func (h *Outbound) Start(stage adapter.StartStage) error {
switch stage {
case adapter.StartStatePostStart, adapter.StartStateStarted:
h.fetchMyAddresses()
}
return nil
}
func (h *Outbound) fetchMyAddresses() {
if len(h.myAddresses.Load()) > 0 {
return
}
myInterfaceNames := h.network.InterfaceMonitor().MyInterfaces()
if len(myInterfaceNames) == 0 {
return
}
var myAddresses []netip.Prefix
for _, myInterfaceName := range myInterfaceNames {
myInterface, err := h.network.InterfaceFinder().ByName(myInterfaceName)
if err != nil {
continue
}
myAddresses = append(myAddresses, myInterface.Addresses...)
}
h.myAddresses.Store(myAddresses)
}
func (h *Outbound) isMyLoopbackAddress(addresses ...netip.Addr) bool {
for _, prefix := range h.myAddresses.Load() {
for _, address := range addresses {
if prefix.Addr() != address && prefix.Contains(address) {
return true
}
}
}
return false
}
func (h *Outbound) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
if h.isMyLoopbackAddress(destination.Addr) {
return nil, E.New("loopback connection to TUN range")
}
ctx, metadata := adapter.ExtendContext(ctx)
metadata.Outbound = h.Tag()
metadata.Destination = destination
@@ -89,6 +134,9 @@ func (h *Outbound) DialContext(ctx context.Context, network string, destination
}
func (h *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
if h.isMyLoopbackAddress(destination.Addr) {
return nil, E.New("loopback connection to TUN range")
}
ctx, metadata := adapter.ExtendContext(ctx)
metadata.Outbound = h.Tag()
metadata.Destination = destination
@@ -111,6 +159,9 @@ func (h *Outbound) NewDirectRouteConnection(metadata adapter.InboundContext, rou
}
func (h *Outbound) DialParallel(ctx context.Context, network string, destination M.Socksaddr, destinationAddresses []netip.Addr) (net.Conn, error) {
if h.isMyLoopbackAddress(destinationAddresses...) {
return nil, E.New("loopback connection to TUN range")
}
ctx, metadata := adapter.ExtendContext(ctx)
metadata.Outbound = h.Tag()
metadata.Destination = destination
@@ -125,6 +176,9 @@ func (h *Outbound) DialParallel(ctx context.Context, network string, destination
}
func (h *Outbound) DialParallelNetwork(ctx context.Context, network string, destination M.Socksaddr, destinationAddresses []netip.Addr, networkStrategy *C.NetworkStrategy, networkType []C.InterfaceType, fallbackNetworkType []C.InterfaceType, fallbackDelay time.Duration) (net.Conn, error) {
if h.isMyLoopbackAddress(destinationAddresses...) {
return nil, E.New("loopback connection to TUN range")
}
ctx, metadata := adapter.ExtendContext(ctx)
metadata.Outbound = h.Tag()
metadata.Destination = destination
@@ -139,6 +193,9 @@ func (h *Outbound) DialParallelNetwork(ctx context.Context, network string, dest
}
func (h *Outbound) ListenSerialNetworkPacket(ctx context.Context, destination M.Socksaddr, destinationAddresses []netip.Addr, networkStrategy *C.NetworkStrategy, networkType []C.InterfaceType, fallbackNetworkType []C.InterfaceType, fallbackDelay time.Duration) (net.PacketConn, netip.Addr, error) {
if h.isMyLoopbackAddress(destinationAddresses...) {
return nil, netip.Addr{}, E.New("loopback connection to TUN range")
}
ctx, metadata := adapter.ExtendContext(ctx)
metadata.Outbound = h.Tag()
metadata.Destination = destination

View File

@@ -107,16 +107,16 @@ func (n *Inbound) Start(stage adapter.StartStage) error {
return n.ctx
},
}
go func() {
listener := net.Listener(tcpListener)
if n.tlsConfig != nil {
if len(n.tlsConfig.NextProtos()) == 0 {
n.tlsConfig.SetNextProtos([]string{http2.NextProtoTLS, "http/1.1"})
} else if !common.Contains(n.tlsConfig.NextProtos(), http2.NextProtoTLS) {
n.tlsConfig.SetNextProtos(append([]string{http2.NextProtoTLS}, n.tlsConfig.NextProtos()...))
}
listener = aTLS.NewListener(tcpListener, n.tlsConfig)
listener := net.Listener(tcpListener)
if n.tlsConfig != nil {
if len(n.tlsConfig.NextProtos()) == 0 {
n.tlsConfig.SetNextProtos([]string{http2.NextProtoTLS, "http/1.1"})
} else if !common.Contains(n.tlsConfig.NextProtos(), http2.NextProtoTLS) {
n.tlsConfig.SetNextProtos(append([]string{http2.NextProtoTLS}, n.tlsConfig.NextProtos()...))
}
listener = aTLS.NewListener(tcpListener, n.tlsConfig)
}
go func() {
sErr := n.httpServer.Serve(listener)
if sErr != nil && !errors.Is(sErr, http.ErrServerClosed) {
n.logger.Error("http server serve error: ", sErr)

View File

@@ -19,6 +19,7 @@ import (
"github.com/sagernet/sing-quic/congestion_bbr2"
congestion_meta1 "github.com/sagernet/sing-quic/congestion_meta1"
congestion_meta2 "github.com/sagernet/sing-quic/congestion_meta2"
"github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/logger"
"github.com/sagernet/sing/common/ntp"
@@ -30,6 +31,9 @@ func init() {
if err != nil {
return nil, err
}
if !common.Contains(tlsConfig.NextProtos(), http3.NextProtoH3) {
tlsConfig.SetNextProtos(append(append([]string{}, tlsConfig.NextProtos()...), http3.NextProtoH3))
}
udpConn, err := listener.ListenUDP()
if err != nil {

View File

@@ -44,6 +44,7 @@ import (
"github.com/sagernet/sing/common/ntp"
"github.com/sagernet/sing/service"
"github.com/sagernet/sing/service/filemanager"
tailscaleroot "github.com/sagernet/tailscale"
_ "github.com/sagernet/tailscale/feature/relayserver"
"github.com/sagernet/tailscale/ipn"
tsDNS "github.com/sagernet/tailscale/net/dns"
@@ -70,7 +71,7 @@ var (
)
func init() {
version.SetVersion("sing-box " + C.Version)
version.SetVersion(tailscaleroot.VersionDotTxt + " (sing-box " + C.Version + ")")
}
func RegisterEndpoint(registry *endpoint.Registry) {
@@ -105,7 +106,8 @@ type Endpoint struct {
relayServerPort *uint16
relayServerStaticEndpoints []netip.AddrPort
udpTimeout time.Duration
udpTimeout time.Duration
icmpTimeout time.Duration
systemInterface bool
systemInterfaceName string
@@ -257,6 +259,7 @@ func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextL
relayServerPort: options.RelayServerPort,
relayServerStaticEndpoints: options.RelayServerStaticEndpoints,
udpTimeout: udpTimeout,
icmpTimeout: C.ICMPTimeout,
systemInterface: options.SystemInterface,
systemInterfaceName: options.SystemInterfaceName,
systemInterfaceMTU: options.SystemInterfaceMTU,
@@ -389,7 +392,7 @@ func (t *Endpoint) postStart() error {
if gErr != nil {
return gonet.TranslateNetstackError(gErr)
}
icmpForwarder := tun.NewICMPForwarder(t.ctx, ipStack, t, t.udpTimeout)
icmpForwarder := tun.NewICMPForwarder(t.ctx, ipStack, t, t.icmpTimeout)
ipStack.SetTransportProtocolHandler(icmp.ProtocolNumber4, icmpForwarder.HandlePacket)
ipStack.SetTransportProtocolHandler(icmp.ProtocolNumber6, icmpForwarder.HandlePacket)
t.stack = ipStack

View File

@@ -378,6 +378,7 @@ func (t *Inbound) Start(stage adapter.StartStage) error {
Tun: tunInterface,
TunOptions: t.tunOptions,
UDPTimeout: t.udpTimeout,
ICMPTimeout: C.ICMPTimeout,
Handler: t,
Logger: t.logger,
ForwarderBindInterface: forwarderBindInterface,

View File

@@ -92,7 +92,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
case "xudp":
outbound.xudp = true
default:
return nil, E.New("unknown packet encoding: ", options.PacketEncoding)
return nil, E.New("unknown packet encoding: ", *options.PacketEncoding)
}
}
muxOpts := common.PtrValueOrDefault(options.Multiplex)

View File

@@ -100,12 +100,13 @@ func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextL
}
}
wgEndpoint, err := wireguard.NewEndpoint(wireguard.EndpointOptions{
Context: ctx,
Logger: logger,
System: options.System,
Handler: ep,
UDPTimeout: udpTimeout,
Dialer: outboundDialer,
Context: ctx,
Logger: logger,
System: options.System,
Handler: ep,
UDPTimeout: udpTimeout,
ICMPTimeout: C.ICMPTimeout,
Dialer: outboundDialer,
CreateDialer: func(interfaceName string) N.Dialer {
return common.Must1(dialer.NewDefault(ctx, option.DialerOptions{
BindInterface: interfaceName,