Meow
2026-05-03 04:40:46 +08:00
committed by GitHub
parent 8381a5a8a6
commit 958eb9ea8f
5 changed files with 173 additions and 49 deletions
+51 -13
View File
@@ -89,10 +89,11 @@ func init() {
}
type FinalRule struct {
action RuleAction
network [8]bool
port net.MemoryPortList
ip geodata.IPMatcher
action RuleAction
network [8]bool
port net.MemoryPortList
ip geodata.IPMatcher
blockDelay *Range
}
// Handler handles Freedom connections.
@@ -104,7 +105,8 @@ type Handler struct {
func buildFinalRule(config *FinalRuleConfig) (*FinalRule, error) {
rule := &FinalRule{
action: config.GetAction(),
action: config.GetAction(),
blockDelay: config.GetBlockDelay(),
}
if len(config.Networks) == 0 {
@@ -176,7 +178,7 @@ func getDefaultFinalRule(inbound *session.Inbound) *FinalRule {
}
func (h *Handler) shouldResolveDomainBeforeFinalRules(dialDest net.Destination, defaultRule *FinalRule) bool {
if dialDest.Network != net.Network_TCP || !dialDest.Address.Family().IsDomain() {
if !dialDest.Address.Family().IsDomain() {
return false
}
if len(h.finalRules) > 0 {
@@ -191,14 +193,21 @@ func (h *Handler) shouldResolveDomainBeforeFinalRules(dialDest net.Destination,
return false
}
func (h *Handler) applyFinalRules(network net.Network, address net.Address, port net.Port, defaultRule *FinalRule) RuleAction {
func (h *Handler) matchFinalRule(network net.Network, address net.Address, port net.Port, defaultRule *FinalRule) *FinalRule {
for _, rule := range h.finalRules {
if rule.Apply(network, address, port) {
return rule.action
return rule
}
}
if defaultRule != nil && defaultRule.Apply(network, address, port) {
return defaultRule.action
return defaultRule
}
return nil
}
func (h *Handler) applyFinalRules(network net.Network, address net.Address, port net.Port, defaultRule *FinalRule) RuleAction {
if rule := h.matchFinalRule(network, address, port, defaultRule); rule != nil {
return rule.action
}
return RuleAction_Allow
}
@@ -223,6 +232,20 @@ func (h *Handler) policy() policy.Session {
return p
}
func (h *Handler) blockDelay(rule *FinalRule) time.Duration {
min := uint64(30)
max := uint64(90)
if rule.blockDelay != nil {
min = rule.blockDelay.Min
max = rule.blockDelay.Max
}
abs := max - min
if max < min {
abs = min - max
}
return time.Duration(min+uint64(dice.Roll(int(abs+1)))) * time.Second
}
func isValidAddress(addr *net.IPOrDomain) bool {
if addr == nil {
return false
@@ -269,6 +292,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
var conn stat.Connection
var blockedDest *net.Destination
var blockedRule *FinalRule
err := retry.ExponentialBackoff(5, 100).On(func() error {
dialDest := destination
if h.config.DomainStrategy.HasStrategy() && dialDest.Address.Family().IsDomain() {
@@ -290,7 +314,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
}
errors.LogInfo(ctx, "dialing to ", dialDest)
}
} else if h.shouldResolveDomainBeforeFinalRules(dialDest, defaultRule) {
} else if h.shouldResolveDomainBeforeFinalRules(dialDest, defaultRule) { // asis + domain + hasrules
addrs, err := net.DefaultResolver.LookupIPAddr(ctx, dialDest.Address.Domain())
if err != nil {
errors.LogInfoInner(ctx, err, "failed to get IP address for domain ", dialDest.Address.Domain())
@@ -301,8 +325,9 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
}
}
}
if dialDest.Network == net.Network_TCP && h.applyFinalRules(dialDest.Network, dialDest.Address, dialDest.Port, defaultRule) == RuleAction_Block {
if rule := h.matchFinalRule(dialDest.Network, dialDest.Address, dialDest.Port, defaultRule); rule != nil && rule.action == RuleAction_Block {
blockedDest = &dialDest
blockedRule = rule
return nil
}
@@ -318,11 +343,24 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
return errors.New("failed to open connection to ", destination).Base(err)
}
if blockedDest != nil {
return errors.New("blocked target: ", *blockedDest).AtInfo()
delay := h.blockDelay(blockedRule)
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 remoteDest := net.DestinationFromAddr(conn.RemoteAddr()); h.applyFinalRules(remoteDest.Network, remoteDest.Address, remoteDest.Port, defaultRule) == RuleAction_Block {
// conn.Close()
// return errors.New("blocked target: ", remoteDest).AtInfo()
// return blackhole(remoteDest)
// }
if h.config.ProxyProtocol > 0 && h.config.ProxyProtocol <= 2 {
version := byte(h.config.ProxyProtocol)