solodecode
2026-10-28 11:02:55 +00:00
committed by GitHub
parent 3071fbfa25
commit 229799a7a3
2 changed files with 92 additions and 5 deletions
+10 -5
View File
@@ -229,14 +229,19 @@ func (h *Handler) blockDelay(rule *FinalRule) time.Duration {
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() {
defer common.Close(output)
done := make(chan struct{})
go func() { // a DispatchLink inbound's reader ignores Interrupt, so don't wait for this copy
_ = buf.Copy(input, buf.Discard)
close(done)
}()
select {
case <-done:
case <-time.After(delay):
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
}
+82
View File
@@ -3,6 +3,8 @@ package scenarios
import (
"encoding/base64"
"encoding/hex"
"fmt"
"io"
"sync"
"testing"
"time"
@@ -20,6 +22,7 @@ import (
"github.com/xtls/xray-core/proxy/dokodemo"
"github.com/xtls/xray-core/proxy/freedom"
"github.com/xtls/xray-core/proxy/vless"
"github.com/xtls/xray-core/proxy/vless/encoding"
"github.com/xtls/xray-core/proxy/vless/inbound"
"github.com/xtls/xray-core/proxy/vless/outbound"
"github.com/xtls/xray-core/testing/servers/tcp"
@@ -657,3 +660,82 @@ func TestVlessRealityFingerprints(t *testing.T) {
}
wg.Wait()
}
// A blocked connection must be closed after blockDelay even while the client keeps it open and sends nothing.
func TestVlessBlockDelay(t *testing.T) {
tcpServer := tcp.Server{
MsgProcessor: xor,
}
dest, err := tcpServer.Start()
common.Must(err)
defer tcpServer.Close()
for _, delay := range []uint64{0, 1} {
t.Run(fmt.Sprint("blockDelay=", delay), func(t *testing.T) {
userID := protocol.NewID(uuid.New())
serverPort := tcp.PickPort()
serverConfig := &core.Config{
Inbound: []*core.InboundHandlerConfig{
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(serverPort)}},
Listen: net.NewIPOrDomain(net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&inbound.Config{
Users: []*protocol.User{
{
Account: serial.ToTypedMessage(&vless.Account{
Id: userID.String(),
}),
},
},
}),
},
},
Outbound: []*core.OutboundHandlerConfig{
{
ProxySettings: serial.ToTypedMessage(&freedom.Config{
FinalRules: []*freedom.FinalRuleConfig{
{
Action: freedom.RuleAction_Block,
BlockDelay: &freedom.Range{Min: delay, Max: delay},
},
},
}),
},
},
}
servers, err := InitializeServerConfigs(serverConfig)
common.Must(err)
defer CloseAllServers(servers)
conn, err := net.DialTCP("tcp", nil, &net.TCPAddr{
IP: []byte{127, 0, 0, 1},
Port: int(serverPort),
})
common.Must(err)
defer conn.Close()
start := time.Now()
common.Must(encoding.EncodeRequestHeader(conn, &protocol.RequestHeader{
Version: encoding.Version,
User: &protocol.MemoryUser{Account: &vless.MemoryAccount{ID: userID}},
Command: protocol.RequestCommandTCP,
Address: dest.Address,
Port: dest.Port,
}, &encoding.Addons{}))
blockDelay := time.Duration(delay) * time.Second
common.Must(conn.SetReadDeadline(time.Now().Add(blockDelay + 5*time.Second)))
_, err = io.Copy(io.Discard, conn)
elapsed := time.Since(start)
if err, ok := err.(net.Error); ok && err.Timeout() {
t.Fatalf("connection is still open after %v", elapsed)
}
if elapsed < blockDelay {
t.Fatalf("connection is closed after %v, before blockDelay", elapsed)
}
})
}
}