mirror of
https://github.com/XTLS/Xray-core.git
synced 2026-07-03 10:18:42 +00:00
Direct/Freedom outbound: Add blockDelay to finalRules (30~90s by default) (#6060)
Document: https://xtls.github.io/config/outbounds/freedom.html#finalruleobject https://github.com/XTLS/Xray-core/pull/6058#issuecomment-4363489838 https://github.com/XTLS/Xray-core/pull/6058#issuecomment-4363522836 https://github.com/XTLS/Xray-core/pull/6060#issuecomment-4363675060 https://github.com/XTLS/Xray-core/pull/6060#issuecomment-4364587508
This commit is contained in:
+51
-13
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user