more compatibility

This commit is contained in:
Meo597
2026-05-04 15:20:14 +08:00
parent 505fa325e4
commit 940de4a789
2 changed files with 113 additions and 55 deletions

View File

@@ -274,6 +274,13 @@ func (h *Handler) SocketSettings() *internet.SocketConfig {
return h.streamSettings.SocketSettings return h.streamSettings.SocketSettings
} }
func (h *Handler) UsesProxySettings() bool {
if h.senderSettings != nil && h.senderSettings.ProxySettings.HasTag() {
return true
}
return h.streamSettings != nil && h.streamSettings.SocketSettings != nil && len(h.streamSettings.SocketSettings.DialerProxy) > 0
}
// Dial implements internet.Dialer. // Dial implements internet.Dialer.
func (h *Handler) Dial(ctx context.Context, dest net.Destination) (stat.Connection, error) { func (h *Handler) Dial(ctx context.Context, dest net.Destination) (stat.Connection, error) {
if h.senderSettings != nil { if h.senderSettings != nil {

View File

@@ -43,6 +43,9 @@ func init() {
h.socketStrategy = sockopt.DomainStrategy h.socketStrategy = sockopt.DomainStrategy
} }
} }
if handler, ok := session.FullHandlerFromContext(ctx).(handlerWithProxySettings); ok {
h.usesProxySettings = handler.UsesProxySettings()
}
if err := core.RequireFeatures(ctx, func(pm policy.Manager) error { if err := core.RequireFeatures(ctx, func(pm policy.Manager) error {
return h.Init(config.(*Config), pm) return h.Init(config.(*Config), pm)
}); err != nil { }); err != nil {
@@ -97,6 +100,10 @@ type handlerWithSocketSettings interface {
SocketSettings() *internet.SocketConfig SocketSettings() *internet.SocketConfig
} }
type handlerWithProxySettings interface {
UsesProxySettings() bool
}
type FinalRule struct { type FinalRule struct {
action RuleAction action RuleAction
network [8]bool network [8]bool
@@ -107,10 +114,11 @@ type FinalRule struct {
// Handler handles Freedom connections. // Handler handles Freedom connections.
type Handler struct { type Handler struct {
policyManager policy.Manager policyManager policy.Manager
config *Config config *Config
finalRules []*FinalRule finalRules []*FinalRule
socketStrategy internet.DomainStrategy socketStrategy internet.DomainStrategy
usesProxySettings bool
} }
func buildFinalRule(config *FinalRuleConfig) (*FinalRule, error) { func buildFinalRule(config *FinalRuleConfig) (*FinalRule, error) {
@@ -249,11 +257,25 @@ func (h *Handler) blockDelay(rule *FinalRule) time.Duration {
min = rule.blockDelay.Min min = rule.blockDelay.Min
max = rule.blockDelay.Max max = rule.blockDelay.Max
} }
abs := max - min span := max - min
if max < min { if max < min {
abs = min - max span = min - max
} }
return time.Duration(min+uint64(dice.Roll(int(abs+1)))) * time.Second return time.Duration(min+uint64(dice.Roll(int(span+1)))) * time.Second
}
func (h *Handler) blackhole(ctx context.Context, input buf.Reader, output buf.Writer, rule *FinalRule, dest *net.Destination) error {
delay := h.blockDelay(rule)
errors.LogInfo(ctx, "blocked target: ", *dest, ", blackholing connection for ", delay)
timer := time.AfterFunc(delay, func() {
common.Interrupt(input)
common.Interrupt(output)
errors.LogInfo(ctx, "closed blackholed connection to blocked target: ", *dest)
})
defer timer.Stop()
defer common.Close(output)
_ = buf.Copy(input, buf.Discard)
return nil
} }
func (h *Handler) udpDomainStrategy() internet.DomainStrategy { func (h *Handler) udpDomainStrategy() internet.DomainStrategy {
@@ -312,40 +334,73 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
var blockedRule *FinalRule var blockedRule *FinalRule
err := retry.ExponentialBackoff(5, 100).On(func() error { err := retry.ExponentialBackoff(5, 100).On(func() error {
dialDest := destination dialDest := destination
if h.config.DomainStrategy.HasStrategy() && dialDest.Address.Family().IsDomain() {
strategy := h.config.DomainStrategy if dialDest.Address.Family().IsDomain() {
if destination.Network == net.Network_UDP && origTargetAddr != nil && outGateway == nil { if strategy := h.config.DomainStrategy; strategy.HasStrategy() {
strategy = strategy.GetDynamicStrategy(origTargetAddr.Family()) if destination.Network == net.Network_UDP && origTargetAddr != nil && outGateway == nil {
} strategy = strategy.GetDynamicStrategy(origTargetAddr.Family())
ips, err := internet.LookupForIP(dialDest.Address.Domain(), strategy, outGateway)
if err != nil {
errors.LogInfoInner(ctx, err, "failed to get IP address for domain ", dialDest.Address.Domain())
if h.config.DomainStrategy.ForceIP() {
return err
} }
} else { ips, err := internet.LookupForIP(dialDest.Address.Domain(), strategy, outGateway)
dialDest = net.Destination{ if err != nil { // SRV/TXT
Network: dialDest.Network, errors.LogInfoInner(ctx, err, "failed to get IP address for domain ", dialDest.Address.Domain())
Address: net.IPAddress(ips[dice.Roll(len(ips))]), if h.config.DomainStrategy.ForceIP() || defaultRule != nil || len(h.finalRules) > 0 {
Port: dialDest.Port, return err // retry
} }
errors.LogInfo(ctx, "dialing to ", dialDest) } else { // to ip
} dialDest = net.Destination{
} else if h.shouldResolveDomainBeforeFinalRules(dialDest, defaultRule) { // asis + domain + hasrules Network: dialDest.Network,
addrs, err := net.DefaultResolver.LookupIPAddr(ctx, dialDest.Address.Domain()) Address: net.IPAddress(ips[dice.Roll(len(ips))]),
if err != nil { Port: dialDest.Port,
errors.LogInfoInner(ctx, err, "failed to get IP address for domain ", dialDest.Address.Domain()) }
} else if len(addrs) > 0 {
if addr := net.IPAddress(addrs[dice.Roll(len(addrs))].IP); addr != nil {
dialDest.Address = addr
errors.LogInfo(ctx, "dialing to ", dialDest) errors.LogInfo(ctx, "dialing to ", dialDest)
if rule := h.matchFinalRule(dialDest.Network, dialDest.Address, dialDest.Port, defaultRule); rule != nil && rule.action == RuleAction_Block {
blockedDest = &dialDest
blockedRule = rule
return nil
}
}
} else if defaultRule != nil || len(h.finalRules) > 0 { // freedom asis + hasrules
if strategy := h.socketStrategy; strategy.HasStrategy() {
ips, err := internet.LookupForIP(dialDest.Address.Domain(), strategy, outGateway)
if err != nil { // SRV/TXT
errors.LogInfoInner(ctx, err, "failed to get IP address for domain ", dialDest.Address.Domain())
if strategy.ForceIP() {
return err // retry
}
}
for _, ip := range ips {
if addr := net.IPAddress(ip); addr != nil {
if rule := h.matchFinalRule(dialDest.Network, addr, dialDest.Port, defaultRule); rule != nil && rule.action == RuleAction_Block {
blockedDest = &dialDest
blockedDest.Address = addr
blockedRule = rule
return nil
}
}
}
} else { // sockopt asis
addrs, err := net.DefaultResolver.LookupIPAddr(ctx, dialDest.Address.Domain())
if err != nil { // SRV/TXT
errors.LogInfoInner(ctx, err, "failed to get IP address for domain ", dialDest.Address.Domain())
}
for _, addr := range addrs {
if ipAddr := net.IPAddress(addr.IP); ipAddr != nil {
if rule := h.matchFinalRule(dialDest.Network, ipAddr, dialDest.Port, defaultRule); rule != nil && rule.action == RuleAction_Block {
blockedDest = &dialDest
blockedDest.Address = ipAddr
blockedRule = rule
return nil
}
}
}
} }
} }
} } else {
if rule := h.matchFinalRule(dialDest.Network, dialDest.Address, dialDest.Port, defaultRule); rule != nil && rule.action == RuleAction_Block { if rule := h.matchFinalRule(dialDest.Network, dialDest.Address, dialDest.Port, defaultRule); rule != nil && rule.action == RuleAction_Block {
blockedDest = &dialDest blockedDest = &dialDest
blockedRule = rule blockedRule = rule
return nil return nil
}
} }
rawConn, err := dialer.Dial(ctx, dialDest) rawConn, err := dialer.Dial(ctx, dialDest)
@@ -360,25 +415,21 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
return errors.New("failed to open connection to ", destination).Base(err) return errors.New("failed to open connection to ", destination).Base(err)
} }
if blockedDest != nil { if blockedDest != nil {
delay := h.blockDelay(blockedRule) return h.blackhole(ctx, input, output, blockedRule, blockedDest)
errors.LogInfo(ctx, "blocked target: ", *blockedDest, ", blackholing connection for ", delay)
timer := time.AfterFunc(delay, func() {
common.Interrupt(input)
common.Interrupt(output)
errors.LogInfo(ctx, "closed blackholed connection to blocked target: ", *blockedDest)
})
defer timer.Stop()
defer common.Close(output)
if err := buf.Copy(input, buf.Discard); err != nil {
return nil
}
return nil
} }
// TODO: SRV/TXT if defaultRule != nil || len(h.finalRules) > 0 {
// if remoteDest := net.DestinationFromAddr(conn.RemoteAddr()); h.applyFinalRules(remoteDest.Network, remoteDest.Address, remoteDest.Port, defaultRule) == RuleAction_Block { if h.usesProxySettings {
// conn.Close() errors.LogInfo(ctx, "skipping final rule check for proxied remote endpoint, original target: ", destination)
// return blackhole(remoteDest) } else {
// } // SRV/TXT, lookup failed
remoteDest := net.DestinationFromAddr(conn.RemoteAddr())
if rule := h.matchFinalRule(remoteDest.Network, remoteDest.Address, remoteDest.Port, defaultRule); rule != nil && rule.action == RuleAction_Block {
conn.Close()
return h.blackhole(ctx, input, output, rule, &remoteDest)
}
}
}
if h.config.ProxyProtocol > 0 && h.config.ProxyProtocol <= 2 { if h.config.ProxyProtocol > 0 && h.config.ProxyProtocol <= 2 {
version := byte(h.config.ProxyProtocol) version := byte(h.config.ProxyProtocol)
srcAddr := inbound.Source.RawNetAddr() srcAddr := inbound.Source.RawNetAddr()