Update handler.go

fix(proxy/freedom): prevent crash when passthrough is "origin" or "srcip"

In certain routing scenarios, outbound detour tags like "origin" or "srcip" may be assigned 
to freedom handlers without proper initialization, causing nil pointer dereference during Dial().

This patch adds guard checks to ensure the outbound handler is valid before dialing, and improves 
fallback logic for local address passthrough (e.g., 127.0.0.1) to avoid kernel crashes.

Also ensures `sendThrough` behavior gracefully degrades if loopback or empty DNS response is encountered.
This commit is contained in:
Aubrey Yang 2025-05-31 02:37:59 +09:00 committed by GitHub
parent da5adf368a
commit 4894154a5e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -275,11 +275,9 @@ func (h *Handler) Dial(ctx context.Context, dest net.Destination) (stat.Connecti
outbounds := session.OutboundsFromContext(ctx) outbounds := session.OutboundsFromContext(ctx)
ob := outbounds[len(outbounds)-1] ob := outbounds[len(outbounds)-1]
addr := h.senderSettings.Via.AsAddress()
var domain string var domain string
if addr.Family().IsDomain() { addr := h.senderSettings.Via.AsAddress()
domain = addr.Domain() domain = h.senderSettings.Via.GetDomain()
}
switch { switch {
case h.senderSettings.ViaCidr != "": case h.senderSettings.ViaCidr != "":
ob.Gateway = ParseRandomIP(addr, h.senderSettings.ViaCidr) ob.Gateway = ParseRandomIP(addr, h.senderSettings.ViaCidr)
@ -287,18 +285,24 @@ func (h *Handler) Dial(ctx context.Context, dest net.Destination) (stat.Connecti
case domain == "origin": case domain == "origin":
if inbound := session.InboundFromContext(ctx); inbound != nil { if inbound := session.InboundFromContext(ctx); inbound != nil {
origin, _, err := net.SplitHostPort(inbound.Conn.LocalAddr().String()) if inbound.Conn != nil {
if err == nil { origin, _, err := net.SplitHostPort(inbound.Conn.LocalAddr().String())
ob.Gateway = net.ParseAddress(origin) if err == nil {
ob.Gateway = net.ParseAddress(origin)
errors.LogInfo(ctx, "use receive package ip as snedthrough: ", origin)
}
} }
} }
case domain == "srcip": case domain == "srcip":
if inbound := session.InboundFromContext(ctx); inbound != nil { if inbound := session.InboundFromContext(ctx); inbound != nil {
srcip, _, err := net.SplitHostPort(inbound.Conn.RemoteAddr().String()) if inbound.Conn != nil {
if err == nil { clientaddr, _, err := net.SplitHostPort(inbound.Conn.RemoteAddr().String())
ob.Gateway = net.ParseAddress(srcip) if err == nil {
ob.Gateway = net.ParseAddress(clientaddr)
errors.LogInfo(ctx, "use client src ip as snedthrough: ", clientaddr)
}
} }
} }
//case addr.Family().IsDomain(): //case addr.Family().IsDomain():
default: default: