This commit is contained in:
Meo597 committed 2026-10-28 23:04:50 +08:00
1 parent 31c4d09d09
commit 89be28c86c
14 files changed
+12 -466

No files matched your search

+1 -2
View File
@@ -24,7 +24,6 @@ import (
"github.com/xtls/xray-core/features/outbound"
"github.com/xtls/xray-core/features/routing"
routing_session "github.com/xtls/xray-core/features/routing/session"
"github.com/xtls/xray-core/proxy/blackhole"
"github.com/xtls/xray-core/proxy/freedom"
)
@@ -397,7 +396,7 @@ end`)
serial.ToTypedMessage(&proxyman.OutboundConfig{}),
},
Outbound: []*core.OutboundHandlerConfig{
{Tag: "default", ProxySettings: serial.ToTypedMessage(&blackhole.Config{})},
{Tag: "default", ProxySettings: serial.ToTypedMessage(&freedom.Config{FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Block}}})},
{Tag: "direct", ProxySettings: serial.ToTypedMessage(&freedom.Config{
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
})},
+5 -16
View File
@@ -1,11 +1,10 @@
package conf
import (
"encoding/base64"
"strings"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/proxy/blackhole"
"github.com/xtls/xray-core/proxy/freedom"
"google.golang.org/protobuf/proto"
)
@@ -19,24 +18,14 @@ type BlackholeConfig struct {
}
func (v *BlackholeConfig) Build() (proto.Message, error) {
config := new(blackhole.Config)
if v.Response != nil {
responseName := strings.ToLower(v.Response.Type)
switch responseName {
switch strings.ToLower(v.Response.Type) {
case "none", "":
config.Response = &blackhole.Response{Type: "none"}
case "http":
config.Response = &blackhole.Response{Type: "http"}
case "custom":
data, err := base64.StdEncoding.DecodeString(v.Response.CustomResponseData)
if err != nil {
return nil, errors.New("failed to decode custom response data: " + err.Error())
}
config.Response = &blackhole.Response{Type: "custom", CustomResponseData: data}
default:
return nil, errors.New("unknown blackhole response: " + responseName)
errors.PrintDeprecatedFeatureWarning(`"blackhole" outbound response`, `the "responder" outbound`)
return (&ResponderConfig{Type: v.Response.Type, Response: v.Response.CustomResponseData}).Build()
}
}
return config, nil
return &freedom.Config{FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Block}}}, nil
}
-57
View File
@@ -1,57 +0,0 @@
package conf_test
import (
"testing"
. "github.com/xtls/xray-core/infra/conf"
"github.com/xtls/xray-core/proxy/blackhole"
)
func TestHTTPResponseJSON(t *testing.T) {
creator := func() Buildable {
return new(BlackholeConfig)
}
runMultiTestCase(t, []TestCase{
{
Input: `{
"response": {
"type": "http"
}
}`,
Parser: loadJSON(creator),
Output: &blackhole.Config{
Response: &blackhole.Response{Type: "http"},
},
},
{
Input: `{}`,
Parser: loadJSON(creator),
Output: &blackhole.Config{},
},
})
}
func TestCustomResponseJSON(t *testing.T) {
creator := func() Buildable {
return new(BlackholeConfig)
}
runMultiTestCase(t, []TestCase{
{
Input: `{
"response": {
"type": "custom",
"customResponseData": "Y3VzdG9tIHJlc3BvbnNl"
}
}`,
Parser: loadJSON(creator),
Output: &blackhole.Config{
Response: &blackhole.Response{
Type: "custom",
CustomResponseData: []byte("custom response"),
},
},
},
})
}
-1
View File
@@ -35,7 +35,6 @@ import (
_ "github.com/xtls/xray-core/app/observatory"
// Inbound and outbound proxies.
_ "github.com/xtls/xray-core/proxy/blackhole"
_ "github.com/xtls/xray-core/proxy/dns"
_ "github.com/xtls/xray-core/proxy/dokodemo"
_ "github.com/xtls/xray-core/proxy/freedom"
-88
View File
@@ -1,88 +0,0 @@
// Package blackhole is an outbound handler that blocks all connections.
package blackhole
import (
"bytes"
"context"
"net/http"
"time"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/dice"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/common/signal"
"github.com/xtls/xray-core/transport"
"github.com/xtls/xray-core/transport/internet"
)
// Handler is an outbound connection that silently swallow the entire payload.
type Handler struct {
response []byte
}
var http403response = http.Response{
StatusCode: 403,
ProtoMajor: 1,
ProtoMinor: 1,
Header: http.Header{
"Connection": {"close"},
"Cache-Control": {"max-age=3600, public"},
},
}
// New creates a new blackhole handler.
func New(ctx context.Context, config *Config) (*Handler, error) {
response := []byte{}
if config.Response != nil {
switch config.Response.Type {
case "", "none":
case "http":
var data bytes.Buffer
common.Must(http403response.Write(&data))
response = data.Bytes()
case "custom":
response = config.Response.CustomResponseData
default:
return nil, errors.New("unknown blackhole response: " + config.Response.Type)
}
}
return &Handler{
response: response,
}, nil
}
// Process implements OutboundHandler.Dispatch().
func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error {
outbounds := session.OutboundsFromContext(ctx)
ob := outbounds[len(outbounds)-1]
ob.Name = "blackhole"
if len(h.response) > 0 {
mbc := buf.MultiBufferContainer{}
common.Must2(mbc.Write(h.response))
link.Writer.WriteMultiBuffer(mbc.MultiBuffer)
// Sleep a little here to make sure the response is sent to client.
time.Sleep(time.Second)
}
defer common.Interrupt(link.Writer)
defer common.Interrupt(link.Reader)
// wait to drain all the possible incoming UDP data
if ob.Target.Network == net.Network_UDP {
ctx, cancel := context.WithCancel(ctx)
timer := signal.CancelAfterInactivity(ctx, func() {
cancel()
}, time.Duration(30+dice.Roll(61))*time.Second)
go buf.Copy(link.Reader, buf.Discard, buf.UpdateActivity(timer))
<-ctx.Done()
}
return nil
}
func init() {
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return New(ctx, config.(*Config))
}))
}
-76
View File
@@ -1,76 +0,0 @@
package blackhole_test
import (
"bufio"
"bytes"
"context"
"crypto/rand"
"net/http"
"testing"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/proxy/blackhole"
"github.com/xtls/xray-core/transport"
"github.com/xtls/xray-core/transport/pipe"
)
func TestBlackholeHTTPResponse(t *testing.T) {
ctx := session.ContextWithOutbounds(context.Background(), []*session.Outbound{{}})
handler, err := blackhole.New(ctx, &blackhole.Config{
Response: &blackhole.Response{Type: "http"},
})
common.Must(err)
reader, writer := pipe.New(pipe.WithoutSizeLimit())
dataCh := make(chan buf.MultiBuffer, 1)
go func() {
mb := common.Must2(reader.ReadMultiBuffer())
dataCh <- mb
}()
link := transport.Link{
Reader: reader,
Writer: writer,
}
common.Must(handler.Process(ctx, &link, nil))
mb := <-dataCh
data := make([]byte, mb.Len())
mb.Copy(data)
resp := common.Must2(http.ReadResponse(bufio.NewReader(bytes.NewBuffer(data)), nil))
if resp.StatusCode != 403 {
t.Errorf("expected 403 response, got %d", resp.StatusCode)
}
}
func TestBlackholeCustomResponse(t *testing.T) {
ctx := session.ContextWithOutbounds(context.Background(), []*session.Outbound{{}})
// slightly bigger than a buffer
expected := make([]byte, buf.Size+1000)
if _, err := rand.Read(expected); err != nil {
t.Fatal(err)
}
handler, err := blackhole.New(ctx, &blackhole.Config{
Response: &blackhole.Response{
Type: "custom",
CustomResponseData: expected,
},
})
common.Must(err)
reader, writer := pipe.New(pipe.WithoutSizeLimit())
var actual buf.MultiBuffer
var rerr error
go func() {
actual, rerr = reader.ReadMultiBuffer()
}()
link := transport.Link{Reader: reader, Writer: writer}
common.Must(handler.Process(ctx, &link, nil))
common.Must(rerr)
if actual.String() != string(expected) {
t.Errorf("custom response mismatch")
}
}
-180
View File
@@ -1,180 +0,0 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.11
// protoc v6.33.5
// source: proxy/blackhole/config.proto
package blackhole
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type Response struct {
state protoimpl.MessageState `protogen:"open.v1"`
Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"`
CustomResponseData []byte `protobuf:"bytes,2,opt,name=custom_response_data,json=customResponseData,proto3" json:"custom_response_data,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Response) Reset() {
*x = Response{}
mi := &file_proxy_blackhole_config_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Response) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Response) ProtoMessage() {}
func (x *Response) ProtoReflect() protoreflect.Message {
mi := &file_proxy_blackhole_config_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Response.ProtoReflect.Descriptor instead.
func (*Response) Descriptor() ([]byte, []int) {
return file_proxy_blackhole_config_proto_rawDescGZIP(), []int{0}
}
func (x *Response) GetType() string {
if x != nil {
return x.Type
}
return ""
}
func (x *Response) GetCustomResponseData() []byte {
if x != nil {
return x.CustomResponseData
}
return nil
}
type Config struct {
state protoimpl.MessageState `protogen:"open.v1"`
Response *Response `protobuf:"bytes,1,opt,name=response,proto3" json:"response,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Config) Reset() {
*x = Config{}
mi := &file_proxy_blackhole_config_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Config) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Config) ProtoMessage() {}
func (x *Config) ProtoReflect() protoreflect.Message {
mi := &file_proxy_blackhole_config_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
func (*Config) Descriptor() ([]byte, []int) {
return file_proxy_blackhole_config_proto_rawDescGZIP(), []int{1}
}
func (x *Config) GetResponse() *Response {
if x != nil {
return x.Response
}
return nil
}
var File_proxy_blackhole_config_proto protoreflect.FileDescriptor
const file_proxy_blackhole_config_proto_rawDesc = "" +
"\n" +
"\x1cproxy/blackhole/config.proto\x12\x14xray.proxy.blackhole\"P\n" +
"\bResponse\x12\x12\n" +
"\x04type\x18\x01 \x01(\tR\x04type\x120\n" +
"\x14custom_response_data\x18\x02 \x01(\fR\x12customResponseData\"D\n" +
"\x06Config\x12:\n" +
"\bresponse\x18\x01 \x01(\v2\x1e.xray.proxy.blackhole.ResponseR\bresponseB^\n" +
"\x18com.xray.proxy.blackholeP\x01Z)github.com/xtls/xray-core/proxy/blackhole\xaa\x02\x14Xray.Proxy.Blackholeb\x06proto3"
var (
file_proxy_blackhole_config_proto_rawDescOnce sync.Once
file_proxy_blackhole_config_proto_rawDescData []byte
)
func file_proxy_blackhole_config_proto_rawDescGZIP() []byte {
file_proxy_blackhole_config_proto_rawDescOnce.Do(func() {
file_proxy_blackhole_config_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_proxy_blackhole_config_proto_rawDesc), len(file_proxy_blackhole_config_proto_rawDesc)))
})
return file_proxy_blackhole_config_proto_rawDescData
}
var file_proxy_blackhole_config_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_proxy_blackhole_config_proto_goTypes = []any{
(*Response)(nil), // 0: xray.proxy.blackhole.Response
(*Config)(nil), // 1: xray.proxy.blackhole.Config
}
var file_proxy_blackhole_config_proto_depIdxs = []int32{
0, // 0: xray.proxy.blackhole.Config.response:type_name -> xray.proxy.blackhole.Response
1, // [1:1] is the sub-list for method output_type
1, // [1:1] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension type_name
1, // [1:1] is the sub-list for extension extendee
0, // [0:1] is the sub-list for field type_name
}
func init() { file_proxy_blackhole_config_proto_init() }
func file_proxy_blackhole_config_proto_init() {
if File_proxy_blackhole_config_proto != nil {
return
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_proxy_blackhole_config_proto_rawDesc), len(file_proxy_blackhole_config_proto_rawDesc)),
NumEnums: 0,
NumMessages: 2,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_proxy_blackhole_config_proto_goTypes,
DependencyIndexes: file_proxy_blackhole_config_proto_depIdxs,
MessageInfos: file_proxy_blackhole_config_proto_msgTypes,
}.Build()
File_proxy_blackhole_config_proto = out.File
file_proxy_blackhole_config_proto_goTypes = nil
file_proxy_blackhole_config_proto_depIdxs = nil
}
-16
View File
@@ -1,16 +0,0 @@
syntax = "proto3";
package xray.proxy.blackhole;
option csharp_namespace = "Xray.Proxy.Blackhole";
option go_package = "github.com/xtls/xray-core/proxy/blackhole";
option java_package = "com.xray.proxy.blackhole";
option java_multiple_files = true;
message Response {
string type = 1;
bytes custom_response_data = 2;
}
message Config {
Response response = 1;
}
-19
View File
@@ -1,19 +0,0 @@
package blackhole_test
import (
"context"
"testing"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/proxy/blackhole"
)
func TestHTTPResponse(t *testing.T) {
handler, err := blackhole.New(context.Background(), &blackhole.Config{
Response: &blackhole.Response{Type: "http"},
})
common.Must(err)
if handler == nil {
t.Error("expected HTTP response handler")
}
}
+1 -2
View File
@@ -17,7 +17,6 @@ import (
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/proxy/blackhole"
proxydns "github.com/xtls/xray-core/proxy/dns"
"github.com/xtls/xray-core/proxy/freedom"
)
@@ -73,7 +72,7 @@ func newRouteTestContext(t *testing.T, withDNSApp bool, nameServers []*appdns.Na
Outbound: []*core.OutboundHandlerConfig{
{Tag: "direct", ProxySettings: serial.ToTypedMessage(&freedom.Config{})},
{Tag: "dns", ProxySettings: serial.ToTypedMessage(&proxydns.Config{})},
{Tag: "block", ProxySettings: serial.ToTypedMessage(&blackhole.Config{})},
{Tag: "block", ProxySettings: serial.ToTypedMessage(&freedom.Config{FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Block}}})},
},
})
if err != nil {
+1 -2
View File
@@ -13,7 +13,6 @@ import (
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/proxy/blackhole"
"github.com/xtls/xray-core/proxy/freedom"
"github.com/xtls/xray-core/proxy/socks"
"github.com/xtls/xray-core/testing/servers/tcp"
@@ -78,7 +77,7 @@ func TestResolveIP(t *testing.T) {
},
Outbound: []*core.OutboundHandlerConfig{
{
ProxySettings: serial.ToTypedMessage(&blackhole.Config{}),
ProxySettings: serial.ToTypedMessage(&freedom.Config{FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Block}}}),
},
{
Tag: "direct",
+1 -2
View File
@@ -21,7 +21,6 @@ import (
"github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/common/uuid"
core "github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/proxy/blackhole"
"github.com/xtls/xray-core/proxy/dokodemo"
"github.com/xtls/xray-core/proxy/freedom"
v2http "github.com/xtls/xray-core/proxy/http"
@@ -406,7 +405,7 @@ func TestBlackhole(t *testing.T) {
},
{
Tag: "blocked",
ProxySettings: serial.ToTypedMessage(&blackhole.Config{}),
ProxySettings: serial.ToTypedMessage(&freedom.Config{FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Block}}}),
},
},
App: []*serial.TypedMessage{
+2 -3
View File
@@ -17,7 +17,6 @@ import (
"github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/common/uuid"
core "github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/proxy/blackhole"
"github.com/xtls/xray-core/proxy/dokodemo"
"github.com/xtls/xray-core/proxy/freedom"
"github.com/xtls/xray-core/proxy/vmess"
@@ -100,7 +99,7 @@ func TestReverseProxy(t *testing.T) {
},
Outbound: []*core.OutboundHandlerConfig{
{
ProxySettings: serial.ToTypedMessage(&blackhole.Config{}),
ProxySettings: serial.ToTypedMessage(&freedom.Config{FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Block}}}),
},
},
}
@@ -275,7 +274,7 @@ func TestReverseProxyLongRunning(t *testing.T) {
},
Outbound: []*core.OutboundHandlerConfig{
{
ProxySettings: serial.ToTypedMessage(&blackhole.Config{}),
ProxySettings: serial.ToTypedMessage(&freedom.Config{FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Block}}}),
},
},
}
+1 -2
View File
@@ -11,7 +11,6 @@ import (
"github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/proxy/blackhole"
"github.com/xtls/xray-core/proxy/dokodemo"
"github.com/xtls/xray-core/proxy/freedom"
"github.com/xtls/xray-core/proxy/http"
@@ -331,7 +330,7 @@ func TestSocksBridageUDPWithRouting(t *testing.T) {
},
Outbound: []*core.OutboundHandlerConfig{
{
ProxySettings: serial.ToTypedMessage(&blackhole.Config{}),
ProxySettings: serial.ToTypedMessage(&freedom.Config{FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Block}}}),
},
{
Tag: "out",