From 4894154a5e9c37b05d640612c733c3b468a772e4 Mon Sep 17 00:00:00 2001
From: Aubrey Yang <i@aub.ooo>
Date: Sat, 31 May 2025 02:37:59 +0900
Subject: [PATCH] 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.
---
 app/proxyman/outbound/handler.go | 26 +++++++++++++++-----------
 1 file changed, 15 insertions(+), 11 deletions(-)

diff --git a/app/proxyman/outbound/handler.go b/app/proxyman/outbound/handler.go
index 9a91480f..341d78a9 100644
--- a/app/proxyman/outbound/handler.go
+++ b/app/proxyman/outbound/handler.go
@@ -275,11 +275,9 @@ func (h *Handler) Dial(ctx context.Context, dest net.Destination) (stat.Connecti
 
 			outbounds := session.OutboundsFromContext(ctx)
 			ob := outbounds[len(outbounds)-1]
-			addr := h.senderSettings.Via.AsAddress()
 			var domain string
-			if addr.Family().IsDomain() {
-				domain = addr.Domain()
-			}
+			addr := h.senderSettings.Via.AsAddress()
+			domain = h.senderSettings.Via.GetDomain()
 			switch {
 			case 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":
 
 				if inbound := session.InboundFromContext(ctx); inbound != nil {
-					origin, _, err := net.SplitHostPort(inbound.Conn.LocalAddr().String())
-					if err == nil {
-						ob.Gateway = net.ParseAddress(origin)
+					if inbound.Conn != nil {
+						origin, _, err := net.SplitHostPort(inbound.Conn.LocalAddr().String())
+						if err == nil {
+							ob.Gateway = net.ParseAddress(origin)
+							errors.LogInfo(ctx, "use receive package ip as snedthrough: ", origin)
+						}
 					}
-
 				}
 			case domain == "srcip":
 				if inbound := session.InboundFromContext(ctx); inbound != nil {
-					srcip, _, err := net.SplitHostPort(inbound.Conn.RemoteAddr().String())
-					if err == nil {
-						ob.Gateway = net.ParseAddress(srcip)
+					if inbound.Conn != nil {
+						clientaddr, _, err := net.SplitHostPort(inbound.Conn.RemoteAddr().String())
+						if err == nil {
+							ob.Gateway = net.ParseAddress(clientaddr)
+							errors.LogInfo(ctx, "use client src ip as snedthrough: ", clientaddr)
+						}
 					}
+
 				}
 			//case addr.Family().IsDomain():
 			default: