mirror of
https://github.com/XTLS/Xray-core.git
synced 2026-05-08 14:13:22 +00:00
Direct/Freedom outbound: Add ipsBlocked (supports IP, CIDR, "geoip:", "ext:") and apply a default safe policy (#5947)
https://github.com/XTLS/Xray-core/pull/5892#issuecomment-4254056911 --------- Co-authored-by: 风扇滑翔翼 <Fangliding.fshxy@outlook.com>
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
package freedom
|
||||
|
||||
import (
|
||||
geodata "github.com/xtls/xray-core/common/geodata"
|
||||
protocol "github.com/xtls/xray-core/common/protocol"
|
||||
internet "github.com/xtls/xray-core/transport/internet"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
@@ -251,6 +252,50 @@ func (x *Noise) GetApplyTo() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
type IPRules struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Rules []*geodata.IPRule `protobuf:"bytes,1,rep,name=rules,proto3" json:"rules,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *IPRules) Reset() {
|
||||
*x = IPRules{}
|
||||
mi := &file_proxy_freedom_config_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *IPRules) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*IPRules) ProtoMessage() {}
|
||||
|
||||
func (x *IPRules) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proxy_freedom_config_proto_msgTypes[3]
|
||||
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 IPRules.ProtoReflect.Descriptor instead.
|
||||
func (*IPRules) Descriptor() ([]byte, []int) {
|
||||
return file_proxy_freedom_config_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
func (x *IPRules) GetRules() []*geodata.IPRule {
|
||||
if x != nil {
|
||||
return x.Rules
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
DomainStrategy internet.DomainStrategy `protobuf:"varint,1,opt,name=domain_strategy,json=domainStrategy,proto3,enum=xray.transport.internet.DomainStrategy" json:"domain_strategy,omitempty"`
|
||||
@@ -259,13 +304,14 @@ type Config struct {
|
||||
Fragment *Fragment `protobuf:"bytes,5,opt,name=fragment,proto3" json:"fragment,omitempty"`
|
||||
ProxyProtocol uint32 `protobuf:"varint,6,opt,name=proxy_protocol,json=proxyProtocol,proto3" json:"proxy_protocol,omitempty"`
|
||||
Noises []*Noise `protobuf:"bytes,7,rep,name=noises,proto3" json:"noises,omitempty"`
|
||||
IpsBlocked *IPRules `protobuf:"bytes,8,opt,name=ips_blocked,json=ipsBlocked,proto3,oneof" json:"ips_blocked,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *Config) Reset() {
|
||||
*x = Config{}
|
||||
mi := &file_proxy_freedom_config_proto_msgTypes[3]
|
||||
mi := &file_proxy_freedom_config_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -277,7 +323,7 @@ func (x *Config) String() string {
|
||||
func (*Config) ProtoMessage() {}
|
||||
|
||||
func (x *Config) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proxy_freedom_config_proto_msgTypes[3]
|
||||
mi := &file_proxy_freedom_config_proto_msgTypes[4]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -290,7 +336,7 @@ func (x *Config) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
|
||||
func (*Config) Descriptor() ([]byte, []int) {
|
||||
return file_proxy_freedom_config_proto_rawDescGZIP(), []int{3}
|
||||
return file_proxy_freedom_config_proto_rawDescGZIP(), []int{4}
|
||||
}
|
||||
|
||||
func (x *Config) GetDomainStrategy() internet.DomainStrategy {
|
||||
@@ -335,11 +381,18 @@ func (x *Config) GetNoises() []*Noise {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Config) GetIpsBlocked() *IPRules {
|
||||
if x != nil {
|
||||
return x.IpsBlocked
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_proxy_freedom_config_proto protoreflect.FileDescriptor
|
||||
|
||||
const file_proxy_freedom_config_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"\x1aproxy/freedom/config.proto\x12\x12xray.proxy.freedom\x1a!common/protocol/server_spec.proto\x1a\x1ftransport/internet/config.proto\"S\n" +
|
||||
"\x1aproxy/freedom/config.proto\x12\x12xray.proxy.freedom\x1a!common/protocol/server_spec.proto\x1a\x1ftransport/internet/config.proto\x1a\x1bcommon/geodata/geodat.proto\"S\n" +
|
||||
"\x13DestinationOverride\x12<\n" +
|
||||
"\x06server\x18\x01 \x01(\v2$.xray.common.protocol.ServerEndpointR\x06server\"\x98\x02\n" +
|
||||
"\bFragment\x12!\n" +
|
||||
@@ -362,7 +415,9 @@ const file_proxy_freedom_config_proto_rawDesc = "" +
|
||||
"\tdelay_min\x18\x03 \x01(\x04R\bdelayMin\x12\x1b\n" +
|
||||
"\tdelay_max\x18\x04 \x01(\x04R\bdelayMax\x12\x16\n" +
|
||||
"\x06packet\x18\x05 \x01(\fR\x06packet\x12\x19\n" +
|
||||
"\bapply_to\x18\x06 \x01(\tR\aapplyTo\"\xe9\x02\n" +
|
||||
"\bapply_to\x18\x06 \x01(\tR\aapplyTo\"<\n" +
|
||||
"\aIPRules\x121\n" +
|
||||
"\x05rules\x18\x01 \x03(\v2\x1b.xray.common.geodata.IPRuleR\x05rules\"\xbc\x03\n" +
|
||||
"\x06Config\x12P\n" +
|
||||
"\x0fdomain_strategy\x18\x01 \x01(\x0e2'.xray.transport.internet.DomainStrategyR\x0edomainStrategy\x12Z\n" +
|
||||
"\x14destination_override\x18\x03 \x01(\v2'.xray.proxy.freedom.DestinationOverrideR\x13destinationOverride\x12\x1d\n" +
|
||||
@@ -370,7 +425,10 @@ const file_proxy_freedom_config_proto_rawDesc = "" +
|
||||
"user_level\x18\x04 \x01(\rR\tuserLevel\x128\n" +
|
||||
"\bfragment\x18\x05 \x01(\v2\x1c.xray.proxy.freedom.FragmentR\bfragment\x12%\n" +
|
||||
"\x0eproxy_protocol\x18\x06 \x01(\rR\rproxyProtocol\x121\n" +
|
||||
"\x06noises\x18\a \x03(\v2\x19.xray.proxy.freedom.NoiseR\x06noisesBX\n" +
|
||||
"\x06noises\x18\a \x03(\v2\x19.xray.proxy.freedom.NoiseR\x06noises\x12A\n" +
|
||||
"\vips_blocked\x18\b \x01(\v2\x1b.xray.proxy.freedom.IPRulesH\x00R\n" +
|
||||
"ipsBlocked\x88\x01\x01B\x0e\n" +
|
||||
"\f_ips_blockedBX\n" +
|
||||
"\x16com.xray.proxy.freedomP\x01Z'github.com/xtls/xray-core/proxy/freedom\xaa\x02\x12Xray.Proxy.Freedomb\x06proto3"
|
||||
|
||||
var (
|
||||
@@ -385,26 +443,30 @@ func file_proxy_freedom_config_proto_rawDescGZIP() []byte {
|
||||
return file_proxy_freedom_config_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_proxy_freedom_config_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
|
||||
var file_proxy_freedom_config_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
|
||||
var file_proxy_freedom_config_proto_goTypes = []any{
|
||||
(*DestinationOverride)(nil), // 0: xray.proxy.freedom.DestinationOverride
|
||||
(*Fragment)(nil), // 1: xray.proxy.freedom.Fragment
|
||||
(*Noise)(nil), // 2: xray.proxy.freedom.Noise
|
||||
(*Config)(nil), // 3: xray.proxy.freedom.Config
|
||||
(*protocol.ServerEndpoint)(nil), // 4: xray.common.protocol.ServerEndpoint
|
||||
(internet.DomainStrategy)(0), // 5: xray.transport.internet.DomainStrategy
|
||||
(*IPRules)(nil), // 3: xray.proxy.freedom.IPRules
|
||||
(*Config)(nil), // 4: xray.proxy.freedom.Config
|
||||
(*protocol.ServerEndpoint)(nil), // 5: xray.common.protocol.ServerEndpoint
|
||||
(*geodata.IPRule)(nil), // 6: xray.common.geodata.IPRule
|
||||
(internet.DomainStrategy)(0), // 7: xray.transport.internet.DomainStrategy
|
||||
}
|
||||
var file_proxy_freedom_config_proto_depIdxs = []int32{
|
||||
4, // 0: xray.proxy.freedom.DestinationOverride.server:type_name -> xray.common.protocol.ServerEndpoint
|
||||
5, // 1: xray.proxy.freedom.Config.domain_strategy:type_name -> xray.transport.internet.DomainStrategy
|
||||
0, // 2: xray.proxy.freedom.Config.destination_override:type_name -> xray.proxy.freedom.DestinationOverride
|
||||
1, // 3: xray.proxy.freedom.Config.fragment:type_name -> xray.proxy.freedom.Fragment
|
||||
2, // 4: xray.proxy.freedom.Config.noises:type_name -> xray.proxy.freedom.Noise
|
||||
5, // [5:5] is the sub-list for method output_type
|
||||
5, // [5:5] is the sub-list for method input_type
|
||||
5, // [5:5] is the sub-list for extension type_name
|
||||
5, // [5:5] is the sub-list for extension extendee
|
||||
0, // [0:5] is the sub-list for field type_name
|
||||
5, // 0: xray.proxy.freedom.DestinationOverride.server:type_name -> xray.common.protocol.ServerEndpoint
|
||||
6, // 1: xray.proxy.freedom.IPRules.rules:type_name -> xray.common.geodata.IPRule
|
||||
7, // 2: xray.proxy.freedom.Config.domain_strategy:type_name -> xray.transport.internet.DomainStrategy
|
||||
0, // 3: xray.proxy.freedom.Config.destination_override:type_name -> xray.proxy.freedom.DestinationOverride
|
||||
1, // 4: xray.proxy.freedom.Config.fragment:type_name -> xray.proxy.freedom.Fragment
|
||||
2, // 5: xray.proxy.freedom.Config.noises:type_name -> xray.proxy.freedom.Noise
|
||||
3, // 6: xray.proxy.freedom.Config.ips_blocked:type_name -> xray.proxy.freedom.IPRules
|
||||
7, // [7:7] is the sub-list for method output_type
|
||||
7, // [7:7] is the sub-list for method input_type
|
||||
7, // [7:7] is the sub-list for extension type_name
|
||||
7, // [7:7] is the sub-list for extension extendee
|
||||
0, // [0:7] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_proxy_freedom_config_proto_init() }
|
||||
@@ -412,13 +474,14 @@ func file_proxy_freedom_config_proto_init() {
|
||||
if File_proxy_freedom_config_proto != nil {
|
||||
return
|
||||
}
|
||||
file_proxy_freedom_config_proto_msgTypes[4].OneofWrappers = []any{}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_proxy_freedom_config_proto_rawDesc), len(file_proxy_freedom_config_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 4,
|
||||
NumMessages: 5,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
|
||||
@@ -8,6 +8,7 @@ option java_multiple_files = true;
|
||||
|
||||
import "common/protocol/server_spec.proto";
|
||||
import "transport/internet/config.proto";
|
||||
import "common/geodata/geodat.proto";
|
||||
|
||||
message DestinationOverride {
|
||||
xray.common.protocol.ServerEndpoint server = 1;
|
||||
@@ -32,6 +33,10 @@ message Noise {
|
||||
string apply_to = 6;
|
||||
}
|
||||
|
||||
message IPRules {
|
||||
repeated xray.common.geodata.IPRule rules = 1;
|
||||
}
|
||||
|
||||
message Config {
|
||||
xray.transport.internet.DomainStrategy domain_strategy = 1;
|
||||
DestinationOverride destination_override = 3;
|
||||
@@ -39,4 +44,5 @@ message Config {
|
||||
Fragment fragment = 5;
|
||||
uint32 proxy_protocol = 6;
|
||||
repeated Noise noises = 7;
|
||||
optional IPRules ips_blocked = 8;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"io"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/pires/go-proxyproto"
|
||||
@@ -12,6 +13,7 @@ import (
|
||||
"github.com/xtls/xray-core/common/crypto"
|
||||
"github.com/xtls/xray-core/common/dice"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/geodata"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/platform"
|
||||
"github.com/xtls/xray-core/common/retry"
|
||||
@@ -30,6 +32,32 @@ import (
|
||||
|
||||
var useSplice bool
|
||||
|
||||
var defaultPrivateBlockIP = []string{
|
||||
"0.0.0.0/8",
|
||||
"10.0.0.0/8",
|
||||
"100.64.0.0/10",
|
||||
"127.0.0.0/8",
|
||||
"169.254.0.0/16",
|
||||
"172.16.0.0/12",
|
||||
"192.0.0.0/24",
|
||||
"192.0.2.0/24",
|
||||
"192.88.99.0/24",
|
||||
"192.168.0.0/16",
|
||||
"198.18.0.0/15",
|
||||
"198.51.100.0/24",
|
||||
"203.0.113.0/24",
|
||||
"224.0.0.0/3",
|
||||
"::/127",
|
||||
"fc00::/7",
|
||||
"fe80::/10",
|
||||
"ff00::/8",
|
||||
}
|
||||
|
||||
var defaultPrivateBlockIPMatcher = func() geodata.IPMatcher {
|
||||
rules := common.Must2(geodata.ParseIPRules(defaultPrivateBlockIP))
|
||||
return common.Must2(geodata.IPReg.BuildIPMatcher(rules))
|
||||
}()
|
||||
|
||||
func init() {
|
||||
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
|
||||
h := new(Handler)
|
||||
@@ -50,14 +78,22 @@ func init() {
|
||||
|
||||
// Handler handles Freedom connections.
|
||||
type Handler struct {
|
||||
policyManager policy.Manager
|
||||
config *Config
|
||||
policyManager policy.Manager
|
||||
config *Config
|
||||
blockedIPMatcher geodata.IPMatcher
|
||||
}
|
||||
|
||||
// Init initializes the Handler with necessary parameters.
|
||||
func (h *Handler) Init(config *Config, pm policy.Manager) error {
|
||||
h.config = config
|
||||
h.policyManager = pm
|
||||
if config.IpsBlocked != nil && len(config.IpsBlocked.Rules) > 0 {
|
||||
m, err := geodata.IPReg.BuildIPMatcher(config.IpsBlocked.Rules)
|
||||
if err != nil {
|
||||
return errors.New("failed to build blocked ip matcher").Base(err)
|
||||
}
|
||||
h.blockedIPMatcher = m
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -75,6 +111,32 @@ func isValidAddress(addr *net.IPOrDomain) bool {
|
||||
return a != net.AnyIP && a != net.AnyIPv6
|
||||
}
|
||||
|
||||
func (h *Handler) getBlockedIPMatcher(ctx context.Context, inbound *session.Inbound) geodata.IPMatcher {
|
||||
if h.blockedIPMatcher != nil {
|
||||
return h.blockedIPMatcher
|
||||
}
|
||||
if h.config.IpsBlocked != nil && len(h.config.IpsBlocked.Rules) == 0 { // "ipsBlocked": []
|
||||
return nil
|
||||
}
|
||||
if inbound == nil {
|
||||
return nil
|
||||
}
|
||||
switch inbound.Name {
|
||||
case "vmess", "trojan", "hysteria", "wireguard":
|
||||
errors.LogInfo(ctx, "applying default private IP blocking policy for inbound ", inbound.Name)
|
||||
return defaultPrivateBlockIPMatcher
|
||||
}
|
||||
if strings.HasPrefix(inbound.Name, "vless") || strings.HasPrefix(inbound.Name, "shadowsocks") {
|
||||
errors.LogInfo(ctx, "applying default private IP blocking policy for inbound ", inbound.Name)
|
||||
return defaultPrivateBlockIPMatcher
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func isBlockedAddress(matcher geodata.IPMatcher, addr net.Address) bool {
|
||||
return matcher != nil && addr != nil && addr.Family().IsIP() && matcher.Match(addr.IP())
|
||||
}
|
||||
|
||||
// Process implements proxy.Outbound.
|
||||
func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error {
|
||||
outbounds := session.OutboundsFromContext(ctx)
|
||||
@@ -85,6 +147,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
||||
ob.Name = "freedom"
|
||||
ob.CanSpliceCopy = 1
|
||||
inbound := session.InboundFromContext(ctx)
|
||||
blockedIPMatcher := h.getBlockedIPMatcher(ctx, inbound)
|
||||
|
||||
destination := ob.Target
|
||||
origTargetAddr := ob.OriginalTarget.Address
|
||||
@@ -138,23 +201,26 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
||||
return err
|
||||
}
|
||||
|
||||
if h.config.ProxyProtocol > 0 && h.config.ProxyProtocol <= 2 {
|
||||
version := byte(h.config.ProxyProtocol)
|
||||
srcAddr := inbound.Source.RawNetAddr()
|
||||
dstAddr := rawConn.RemoteAddr()
|
||||
header := proxyproto.HeaderProxyFromAddrs(version, srcAddr, dstAddr)
|
||||
if _, err = header.WriteTo(rawConn); err != nil {
|
||||
rawConn.Close()
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
conn = rawConn
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return errors.New("failed to open connection to ", destination).Base(err)
|
||||
}
|
||||
if remoteAddr := net.DestinationFromAddr(conn.RemoteAddr()).Address; isBlockedAddress(blockedIPMatcher, remoteAddr) {
|
||||
conn.Close()
|
||||
return errors.New("blocked target IP: ", remoteAddr).AtInfo()
|
||||
}
|
||||
if h.config.ProxyProtocol > 0 && h.config.ProxyProtocol <= 2 {
|
||||
version := byte(h.config.ProxyProtocol)
|
||||
srcAddr := inbound.Source.RawNetAddr()
|
||||
dstAddr := conn.RemoteAddr()
|
||||
header := proxyproto.HeaderProxyFromAddrs(version, srcAddr, dstAddr)
|
||||
if _, err = header.WriteTo(conn); err != nil {
|
||||
conn.Close()
|
||||
return errors.New("failed to set PROXY protocol v", version).Base(err)
|
||||
}
|
||||
}
|
||||
defer conn.Close()
|
||||
errors.LogInfo(ctx, "connection opened to ", destination, ", local endpoint ", conn.LocalAddr(), ", remote endpoint ", conn.RemoteAddr())
|
||||
|
||||
@@ -189,7 +255,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
||||
writer = buf.NewWriter(conn)
|
||||
}
|
||||
} else {
|
||||
writer = NewPacketWriter(conn, h, UDPOverride, destination)
|
||||
writer = NewPacketWriter(conn, h, UDPOverride, destination, blockedIPMatcher)
|
||||
if h.config.Noises != nil {
|
||||
errors.LogDebug(ctx, "NOISE", h.config.Noises)
|
||||
writer = &NoisePacketWriter{
|
||||
@@ -307,7 +373,7 @@ func (r *PacketReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
|
||||
}
|
||||
|
||||
// DialDest means the dial target used in the dialer when creating conn
|
||||
func NewPacketWriter(conn net.Conn, h *Handler, UDPOverride net.Destination, DialDest net.Destination) buf.Writer {
|
||||
func NewPacketWriter(conn net.Conn, h *Handler, UDPOverride net.Destination, DialDest net.Destination, blockedIPMatcher geodata.IPMatcher) buf.Writer {
|
||||
iConn := conn
|
||||
statConn, ok := iConn.(*stat.CounterConnection)
|
||||
if ok {
|
||||
@@ -328,6 +394,7 @@ func NewPacketWriter(conn net.Conn, h *Handler, UDPOverride net.Destination, Dia
|
||||
PacketConnWrapper: c,
|
||||
Counter: counter,
|
||||
Handler: h,
|
||||
BlockedIPMatcher: blockedIPMatcher,
|
||||
UDPOverride: UDPOverride,
|
||||
ResolvedUDPAddr: resolvedUDPAddr,
|
||||
LocalAddr: net.DestinationFromAddr(conn.LocalAddr()).Address,
|
||||
@@ -341,7 +408,8 @@ type PacketWriter struct {
|
||||
*internet.PacketConnWrapper
|
||||
stats.Counter
|
||||
*Handler
|
||||
UDPOverride net.Destination
|
||||
BlockedIPMatcher geodata.IPMatcher
|
||||
UDPOverride net.Destination
|
||||
|
||||
// Dest of udp packets might be a domain, we will resolve them to IP
|
||||
// But resolver will return a random one if the domain has many IPs
|
||||
@@ -399,6 +467,12 @@ func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
||||
}
|
||||
}
|
||||
}
|
||||
if isBlockedAddress(w.BlockedIPMatcher, b.UDP.Address) {
|
||||
blockedAddr := b.UDP.Address
|
||||
b.Release()
|
||||
buf.ReleaseMulti(mb)
|
||||
return errors.New("blocked target IP: ", blockedAddr).AtDebug()
|
||||
}
|
||||
destAddr := b.UDP.RawNetAddr()
|
||||
if destAddr == nil {
|
||||
b.Release()
|
||||
|
||||
@@ -100,6 +100,7 @@ func New(ctx context.Context, config *Config) (*Handler, error) {
|
||||
if a.Reverse != nil {
|
||||
rvsCtx := session.ContextWithInbound(ctx, &session.Inbound{
|
||||
Tag: a.Reverse.Tag,
|
||||
Name: "vless-reverse",
|
||||
User: handler.server.User, // TODO: email
|
||||
})
|
||||
if sc := a.Reverse.Sniffing; sc != nil && sc.Enabled {
|
||||
|
||||
Reference in New Issue
Block a user