mirror of
https://github.com/MetaCubeX/mihomo.git
synced 2026-02-26 08:47:09 +00:00
draft: Tun respond ICMP port unreachable when rejecting UDP packets
This commit is contained in:
@@ -34,7 +34,10 @@ func (r *Reject) ListenPacketContext(ctx context.Context, metadata *C.Metadata)
|
||||
if err := r.ResolveUDP(ctx, metadata); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newPacketConn(&nopPacketConn{}, r), nil
|
||||
if r.drop {
|
||||
return newPacketConn(dropPacketConn{}, r), nil
|
||||
}
|
||||
return newPacketConn(nopPacketConn{}, r), C.ErrResetByRule
|
||||
}
|
||||
|
||||
func (r *Reject) ResolveUDP(ctx context.Context, metadata *C.Metadata) error {
|
||||
@@ -90,12 +93,10 @@ func NewPass() *Reject {
|
||||
|
||||
type nopConn struct{}
|
||||
|
||||
func (rw nopConn) Read(b []byte) (int, error) { return 0, io.EOF }
|
||||
|
||||
func (rw nopConn) ReadBuffer(buffer *buf.Buffer) error { return io.EOF }
|
||||
|
||||
func (rw nopConn) Write(b []byte) (int, error) { return 0, io.EOF }
|
||||
func (rw nopConn) WriteBuffer(buffer *buf.Buffer) error { return io.EOF }
|
||||
func (rw nopConn) Read(b []byte) (int, error) { return 0, C.ErrResetByRule }
|
||||
func (rw nopConn) ReadBuffer(buffer *buf.Buffer) error { return C.ErrResetByRule }
|
||||
func (rw nopConn) Write(b []byte) (int, error) { return 0, C.ErrResetByRule }
|
||||
func (rw nopConn) WriteBuffer(buffer *buf.Buffer) error { return C.ErrResetByRule }
|
||||
func (rw nopConn) Close() error { return nil }
|
||||
func (rw nopConn) LocalAddr() net.Addr { return nil }
|
||||
func (rw nopConn) RemoteAddr() net.Addr { return nil }
|
||||
@@ -110,11 +111,9 @@ type nopPacketConn struct{}
|
||||
func (npc nopPacketConn) WriteTo(b []byte, addr net.Addr) (n int, err error) {
|
||||
return len(b), nil
|
||||
}
|
||||
func (npc nopPacketConn) ReadFrom(b []byte) (int, net.Addr, error) {
|
||||
return 0, nil, io.EOF
|
||||
}
|
||||
func (npc nopPacketConn) ReadFrom(b []byte) (int, net.Addr, error) { return 0, nil, C.ErrResetByRule }
|
||||
func (npc nopPacketConn) WaitReadFrom() ([]byte, func(), net.Addr, error) {
|
||||
return nil, nil, nil, io.EOF
|
||||
return nil, nil, nil, C.ErrResetByRule
|
||||
}
|
||||
func (npc nopPacketConn) Close() error { return nil }
|
||||
func (npc nopPacketConn) LocalAddr() net.Addr { return udpAddrIPv4Unspecified }
|
||||
@@ -137,3 +136,18 @@ func (rw dropConn) RemoteAddr() net.Addr { return nil }
|
||||
func (rw dropConn) SetDeadline(time.Time) error { return nil }
|
||||
func (rw dropConn) SetReadDeadline(time.Time) error { return nil }
|
||||
func (rw dropConn) SetWriteDeadline(time.Time) error { return nil }
|
||||
|
||||
type dropPacketConn struct{}
|
||||
|
||||
func (npc dropPacketConn) WriteTo(b []byte, addr net.Addr) (n int, err error) {
|
||||
return len(b), nil
|
||||
}
|
||||
func (npc dropPacketConn) ReadFrom(b []byte) (int, net.Addr, error) { return 0, nil, io.EOF }
|
||||
func (npc dropPacketConn) WaitReadFrom() ([]byte, func(), net.Addr, error) {
|
||||
return nil, nil, nil, io.EOF
|
||||
}
|
||||
func (npc dropPacketConn) Close() error { return nil }
|
||||
func (npc dropPacketConn) LocalAddr() net.Addr { return udpAddrIPv4Unspecified }
|
||||
func (npc dropPacketConn) SetDeadline(time.Time) error { return nil }
|
||||
func (npc dropPacketConn) SetReadDeadline(time.Time) error { return nil }
|
||||
func (npc dropPacketConn) SetWriteDeadline(time.Time) error { return nil }
|
||||
|
||||
@@ -33,6 +33,9 @@ type WriterWithUpstream = network.WriterWithUpstream
|
||||
type WithUpstreamWriter = network.WithUpstreamWriter
|
||||
type WithUpstream = common.WithUpstream
|
||||
|
||||
type HandshakeSuccess = network.HandshakeSuccess
|
||||
type HandshakeFailure = network.HandshakeFailure
|
||||
|
||||
var UnwrapReader = network.UnwrapReader
|
||||
var UnwrapWriter = network.UnwrapWriter
|
||||
|
||||
|
||||
31
common/utils/cast.go
Normal file
31
common/utils/cast.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
)
|
||||
|
||||
type WithUpstream interface {
|
||||
Upstream() any
|
||||
}
|
||||
|
||||
type stdWithUpstreamNetConn interface {
|
||||
NetConn() net.Conn
|
||||
}
|
||||
|
||||
func Cast[T any](obj any) (_ T, _ bool) {
|
||||
if c, ok := obj.(T); ok {
|
||||
fmt.Printf("Got 1: %T\n", obj) // TODO
|
||||
return c, true
|
||||
}
|
||||
if u, ok := obj.(WithUpstream); ok {
|
||||
fmt.Printf("Upstream 2: %T\n", obj) // TODO
|
||||
return Cast[T](u.Upstream())
|
||||
}
|
||||
if u, ok := obj.(stdWithUpstreamNetConn); ok {
|
||||
fmt.Printf("Std 3: %T\n", obj) // TODO
|
||||
return Cast[T](u.NetConn())
|
||||
}
|
||||
fmt.Printf("Failed: %T\n", obj) // TODO
|
||||
return
|
||||
}
|
||||
@@ -274,6 +274,10 @@ func (s *packetAdapter) Key() string {
|
||||
return s.key
|
||||
}
|
||||
|
||||
func (s *packetAdapter) Upstream() any {
|
||||
return s.UDPPacket
|
||||
}
|
||||
|
||||
func NewPacketAdapter(packet UDPPacket, metadata *Metadata) PacketAdapter {
|
||||
return &packetAdapter{
|
||||
packet,
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
package constant
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/metacubex/sing/common/exceptions"
|
||||
)
|
||||
|
||||
// Rule Type
|
||||
const (
|
||||
Domain RuleType = iota
|
||||
@@ -129,3 +135,7 @@ type RuleGroup interface {
|
||||
Rule
|
||||
GetRecodeSize() int
|
||||
}
|
||||
|
||||
var (
|
||||
ErrResetByRule = exceptions.Cause(io.EOF, "reset by rule") // TODO: replace function from sing
|
||||
)
|
||||
|
||||
2
go.mod
2
go.mod
@@ -35,7 +35,7 @@ require (
|
||||
github.com/metacubex/sing-shadowsocks v0.2.12
|
||||
github.com/metacubex/sing-shadowsocks2 v0.2.7
|
||||
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2
|
||||
github.com/metacubex/sing-tun v0.4.11
|
||||
github.com/metacubex/sing-tun v0.4.12-0.20251231220427-f11396db2fa1
|
||||
github.com/metacubex/sing-vmess v0.2.4
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f
|
||||
github.com/metacubex/smux v0.0.0-20251111013112-03f8d12dafc1
|
||||
|
||||
4
go.sum
4
go.sum
@@ -133,8 +133,8 @@ github.com/metacubex/sing-shadowsocks2 v0.2.7 h1:hSuuc0YpsfiqYqt1o+fP4m34BQz4e6w
|
||||
github.com/metacubex/sing-shadowsocks2 v0.2.7/go.mod h1:vOEbfKC60txi0ca+yUlqEwOGc3Obl6cnSgx9Gf45KjE=
|
||||
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2 h1:gXU+MYPm7Wme3/OAY2FFzVq9d9GxPHOqu5AQfg/ddhI=
|
||||
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2/go.mod h1:mbfboaXauKJNIHJYxQRa+NJs4JU9NZfkA+I33dS2+9E=
|
||||
github.com/metacubex/sing-tun v0.4.11 h1:NG5zpvYPbBXf+9GSUmDaGCDwl3hZXV677tbRAw0QtCM=
|
||||
github.com/metacubex/sing-tun v0.4.11/go.mod h1:L/TjQY5JEGy8nvsuYmy/XgMFMCPiF0+AWSFCYfS6r9w=
|
||||
github.com/metacubex/sing-tun v0.4.12-0.20251231220427-f11396db2fa1 h1:eaQCkCI2STxaGiVK35huV9TjUu3QDo3LiS/LKO5n1Z8=
|
||||
github.com/metacubex/sing-tun v0.4.12-0.20251231220427-f11396db2fa1/go.mod h1:L/TjQY5JEGy8nvsuYmy/XgMFMCPiF0+AWSFCYfS6r9w=
|
||||
github.com/metacubex/sing-vmess v0.2.4 h1:Tx6AGgCiEf400E/xyDuYyafsel6sGbR8oF7RkAaus6I=
|
||||
github.com/metacubex/sing-vmess v0.2.4/go.mod h1:21R5R1u90uUvBQF0owoooEu96/SAYYD56nDrwm6nFaM=
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f h1:Sr/DYKYofKHKc4GF3qkRGNuj6XA6c0eqPgEDN+VAsYU=
|
||||
|
||||
@@ -296,8 +296,19 @@ func (c *packet) LocalAddr() net.Addr {
|
||||
|
||||
func (c *packet) Drop() {
|
||||
c.buff.Release()
|
||||
// always try to report success to ensure that the memory is freed up
|
||||
if handshake, isHandshake := common.Cast[network.HandshakeSuccess](c); isHandshake {
|
||||
_ = handshake.HandshakeSuccess()
|
||||
}
|
||||
}
|
||||
|
||||
func (c *packet) InAddr() net.Addr {
|
||||
return c.lAddr
|
||||
}
|
||||
|
||||
func (c *packet) Upstream() any {
|
||||
if c.writer == nil {
|
||||
return nil
|
||||
}
|
||||
return *c.writer
|
||||
}
|
||||
|
||||
@@ -463,9 +463,17 @@ func handleUDPConn(packet C.PacketAdapter) {
|
||||
rawPc, err := retry(ctx, func(ctx context.Context) (C.PacketConn, error) {
|
||||
return proxy.ListenPacketContext(ctx, dialMetadata)
|
||||
}, func(err error) {
|
||||
logMetadataErr(metadata, rule, proxy, err)
|
||||
if !errors.Is(err, C.ErrResetByRule) {
|
||||
logMetadataErr(metadata, rule, proxy, err)
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
if errors.Is(err, C.ErrResetByRule) {
|
||||
logMetadata(metadata, rule, rawPc)
|
||||
if handshake, isHandshake := utils.Cast[N.HandshakeFailure](packet); isHandshake {
|
||||
_ = handshake.HandshakeFailure(err)
|
||||
}
|
||||
}
|
||||
return nil, nil, err
|
||||
}
|
||||
logMetadata(metadata, rule, rawPc)
|
||||
@@ -490,7 +498,7 @@ func handleUDPConn(packet C.PacketAdapter) {
|
||||
sender.Process(pc, proxy)
|
||||
}()
|
||||
}
|
||||
sender.Send(packet) // nonblocking
|
||||
sender.Send(packet) // will not block
|
||||
}
|
||||
|
||||
func handleTCPConn(connCtx C.ConnContext) {
|
||||
@@ -700,6 +708,9 @@ func shouldStopRetry(err error) bool {
|
||||
if errors.Is(err, resolver.ErrIPv6Disabled) {
|
||||
return true
|
||||
}
|
||||
if errors.Is(err, C.ErrResetByRule) {
|
||||
return true
|
||||
}
|
||||
if errors.Is(err, loopback.ErrReject) {
|
||||
return true
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user