Finalmask: Add header-custom (TCP & UDP), fragment (TCP), noise (UDP); Support dialer-proxy, XHTTP/3; Fix XDNS, XICMP potential panic (#5657)

https://github.com/XTLS/Xray-core/pull/5657#issuecomment-4016609446
This commit is contained in:
LjhAUMEM authored and GitHub committed 2026-03-07 15:42:18 +00:00
1 parent ea87941b77
commit a204873d79
62 files changed
+3045 -1367

No files matched your search

+34 -30
View File
@@ -10,6 +10,9 @@ import (
"github.com/xtls/xray-core/common/crypto"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/finalmask"
"github.com/xtls/xray-core/transport/internet/hysteria/udphop"
"golang.org/x/net/icmp"
"golang.org/x/net/ipv4"
"golang.org/x/net/ipv6"
@@ -51,8 +54,10 @@ type xicmpConnClient struct {
mutex sync.Mutex
}
func NewConnClient(c *Config, raw net.PacketConn, end bool) (net.PacketConn, error) {
if !end {
func NewConnClient(c *Config, raw net.PacketConn, level int) (net.PacketConn, error) {
_, ok1 := raw.(*internet.FakePacketConn)
_, ok2 := raw.(*udphop.UdpHopPacketConn)
if level != 0 || ok1 || ok2 {
return nil, errors.New("xicmp requires being at the outermost level")
}
@@ -85,8 +90,8 @@ func NewConnClient(c *Config, raw net.PacketConn, end bool) (net.PacketConn, err
seqStatus: make(map[int]*seqStatus),
pollChan: make(chan struct{}, pollLimit),
readQueue: make(chan *packet, 128),
writeQueue: make(chan *packet, 128),
readQueue: make(chan *packet, 256),
writeQueue: make(chan *packet, 256),
}
go conn.recvLoop()
@@ -122,8 +127,8 @@ func (c *xicmpConnClient) encode(p []byte) ([]byte, error) {
return nil, err
}
if len(buf) > 8192 {
return nil, errors.New("xicmp len(buf) > 8192")
if len(buf) > finalmask.UDPSize {
return nil, errors.New("xicmp len(buf) > finalmask.UDPSize")
}
c.seqStatus[c.seq] = &seqStatus{
@@ -144,13 +149,13 @@ func (c *xicmpConnClient) encode(p []byte) ([]byte, error) {
}
func (c *xicmpConnClient) recvLoop() {
var buf [finalmask.UDPSize]byte
for {
if c.closed {
break
}
var buf [8192]byte
n, addr, err := c.icmpConn.ReadFrom(buf[:])
if err != nil {
continue
@@ -201,6 +206,7 @@ func (c *xicmpConnClient) recvLoop() {
addr: &net.UDPAddr{IP: addr.(*net.IPAddr).IP},
}:
default:
errors.LogDebug(context.Background(), addr, " ", echo.Seq, " ", echo.ID, " mask read err queue full")
}
select {
@@ -210,8 +216,16 @@ func (c *xicmpConnClient) recvLoop() {
}
}
errors.LogDebug(context.Background(), "xicmp closed")
close(c.pollChan)
close(c.readQueue)
c.mutex.Lock()
defer c.mutex.Unlock()
c.closed = true
close(c.writeQueue)
}
func (c *xicmpConnClient) sendLoop() {
@@ -269,39 +283,37 @@ func (c *xicmpConnClient) sendLoop() {
if p != nil {
_, err := c.icmpConn.WriteTo(p.p, p.addr)
if err != nil {
errors.LogDebug(context.Background(), "xicmp writeto err ", err)
errors.LogDebug(context.Background(), p.addr, " xicmp writeto err ", err)
}
}
}
}
func (c *xicmpConnClient) Size() int32 {
return 0
}
func (c *xicmpConnClient) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
packet, ok := <-c.readQueue
if !ok {
return 0, nil, io.EOF
return 0, nil, net.ErrClosed
}
n = copy(p, packet.p)
if n != len(packet.p) {
return 0, nil, io.ErrShortBuffer
if len(p) < len(packet.p) {
errors.LogDebug(context.Background(), packet.addr, " mask read err short buffer ", len(p), " ", len(packet.p))
return 0, packet.addr, nil
}
return n, packet.addr, nil
copy(p, packet.p)
return len(packet.p), packet.addr, nil
}
func (c *xicmpConnClient) WriteTo(p []byte, addr net.Addr) (n int, err error) {
encoded, err := c.encode(p)
if err != nil {
return 0, errors.New("xicmp encode").Base(err)
errors.LogDebug(context.Background(), addr, " xicmp wireformat err ", err)
return 0, nil
}
c.mutex.Lock()
defer c.mutex.Unlock()
if c.closed {
return 0, errors.New("xicmp closed")
return 0, io.ErrClosedPipe
}
select {
@@ -311,21 +323,13 @@ func (c *xicmpConnClient) WriteTo(p []byte, addr net.Addr) (n int, err error) {
}:
return len(p), nil
default:
return 0, errors.New("xicmp queue full")
errors.LogDebug(context.Background(), addr, " mask write err queue full")
return 0, nil
}
}
func (c *xicmpConnClient) Close() error {
c.mutex.Lock()
defer c.mutex.Unlock()
if c.closed {
return nil
}
c.closed = true
close(c.writeQueue)
_ = c.icmpConn.Close()
return c.conn.Close()
}
+4 -4
View File
@@ -7,10 +7,10 @@ import (
func (c *Config) UDP() {
}
func (c *Config) WrapPacketConnClient(raw net.PacketConn, first bool, leaveSize int32, end bool) (net.PacketConn, error) {
return NewConnClient(c, raw, end)
func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
return NewConnClient(c, raw, level)
}
func (c *Config) WrapPacketConnServer(raw net.PacketConn, first bool, leaveSize int32, end bool) (net.PacketConn, error) {
return NewConnServer(c, raw, end)
func (c *Config) WrapPacketConnServer(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
return NewConnServer(c, raw, level)
}
+50 -48
View File
@@ -10,13 +10,14 @@ import (
"github.com/xtls/xray-core/common/crypto"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/transport/internet/finalmask"
"golang.org/x/net/icmp"
"golang.org/x/net/ipv4"
"golang.org/x/net/ipv6"
)
const (
idleTimeout = 2 * time.Minute
idleTimeout = 10 * time.Second
maxResponseDelay = 1 * time.Second
)
@@ -29,7 +30,7 @@ type record struct {
}
type queue struct {
lash time.Time
last time.Time
queue chan []byte
}
@@ -49,8 +50,8 @@ type xicmpConnServer struct {
mutex sync.Mutex
}
func NewConnServer(c *Config, raw net.PacketConn, end bool) (net.PacketConn, error) {
if !end {
func NewConnServer(c *Config, raw net.PacketConn, level int) (net.PacketConn, error) {
if level != 0 {
return nil, errors.New("xicmp requires being at the outermost level")
}
@@ -76,8 +77,8 @@ func NewConnServer(c *Config, raw net.PacketConn, end bool) (net.PacketConn, err
proto: proto,
config: c,
ch: make(chan *record, 100),
readQueue: make(chan *packet, 128),
ch: make(chan *record, 500),
readQueue: make(chan *packet, 512),
writeQueueMap: make(map[string]*queue),
}
@@ -100,7 +101,7 @@ func (c *xicmpConnServer) clean() {
now := time.Now()
for key, q := range c.writeQueueMap {
if now.Sub(q.lash) >= idleTimeout {
if now.Sub(q.last) >= idleTimeout {
close(q.queue)
delete(c.writeQueueMap, key)
}
@@ -118,9 +119,6 @@ func (c *xicmpConnServer) clean() {
}
func (c *xicmpConnServer) ensureQueue(addr net.Addr) *queue {
c.mutex.Lock()
defer c.mutex.Unlock()
if c.closed {
return nil
}
@@ -128,11 +126,11 @@ func (c *xicmpConnServer) ensureQueue(addr net.Addr) *queue {
q, ok := c.writeQueueMap[addr.String()]
if !ok {
q = &queue{
queue: make(chan []byte, 128),
queue: make(chan []byte, 512),
}
c.writeQueueMap[addr.String()] = q
}
q.lash = time.Now()
q.last = time.Now()
return q
}
@@ -159,8 +157,8 @@ func (c *xicmpConnServer) encode(p []byte, id int, seq int, needSeqByte bool, se
return nil, err
}
if len(buf) > 8192 {
return nil, errors.New("xicmp len(buf) > 8192")
if len(buf) > finalmask.UDPSize {
return nil, errors.New("xicmp len(buf) > finalmask.UDPSize")
}
return buf, nil
@@ -177,13 +175,13 @@ func (c *xicmpConnServer) randUntil(b1 byte) byte {
}
func (c *xicmpConnServer) recvLoop() {
var buf [finalmask.UDPSize]byte
for {
if c.closed {
break
}
var buf [8192]byte
n, addr, err := c.icmpConn.ReadFrom(buf[:])
if err != nil {
continue
@@ -225,6 +223,7 @@ func (c *xicmpConnServer) recvLoop() {
},
}:
default:
errors.LogDebug(context.Background(), addr, " ", echo.ID, " ", echo.Seq, " mask read err queue full")
}
}
@@ -240,11 +239,23 @@ func (c *xicmpConnServer) recvLoop() {
},
}:
default:
errors.LogDebug(context.Background(), addr, " ", echo.ID, " ", echo.Seq, " mask read err record queue full")
}
}
errors.LogDebug(context.Background(), "xicmp closed")
close(c.ch)
close(c.readQueue)
c.mutex.Lock()
defer c.mutex.Unlock()
c.closed = true
for key, q := range c.writeQueueMap {
close(q.queue)
delete(c.writeQueueMap, key)
}
}
func (c *xicmpConnServer) sendLoop() {
@@ -261,20 +272,23 @@ func (c *xicmpConnServer) sendLoop() {
}
}
queue := c.ensureQueue(rec.addr)
if queue == nil {
c.mutex.Lock()
q := c.ensureQueue(rec.addr)
if q == nil {
c.mutex.Unlock()
return
}
c.mutex.Unlock()
var p []byte
timer := time.NewTimer(maxResponseDelay)
select {
case p = <-queue.queue:
case p = <-q.queue:
default:
select {
case p = <-queue.queue:
case p = <-q.queue:
case <-timer.C:
case nextRec = <-c.ch:
}
@@ -288,6 +302,7 @@ func (c *xicmpConnServer) sendLoop() {
buf, err := c.encode(p, rec.id, rec.seq, rec.needSeqByte, rec.seqByte)
if err != nil {
errors.LogDebug(context.Background(), rec.addr, " ", rec.id, " ", rec.seq, " xicmp wireformat err ", err)
continue
}
@@ -297,38 +312,36 @@ func (c *xicmpConnServer) sendLoop() {
_, err = c.icmpConn.WriteTo(buf, &net.IPAddr{IP: rec.addr.(*net.UDPAddr).IP})
if err != nil {
errors.LogDebug(context.Background(), "xicmp writeto err ", err)
errors.LogDebug(context.Background(), rec.addr, " ", rec.id, " ", rec.seq, " xicmp writeto err ", err)
}
}
}
func (c *xicmpConnServer) Size() int32 {
return 0
}
func (c *xicmpConnServer) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
packet, ok := <-c.readQueue
if !ok {
return 0, nil, io.EOF
return 0, nil, net.ErrClosed
}
n = copy(p, packet.p)
if n != len(packet.p) {
return 0, nil, io.ErrShortBuffer
if len(p) < len(packet.p) {
errors.LogDebug(context.Background(), packet.addr, " mask read err short buffer ", len(p), " ", len(packet.p))
return 0, packet.addr, nil
}
return n, packet.addr, nil
copy(p, packet.p)
return len(packet.p), packet.addr, nil
}
func (c *xicmpConnServer) WriteTo(p []byte, addr net.Addr) (n int, err error) {
q := c.ensureQueue(addr)
if q == nil {
return 0, errors.New("xicmp closed")
if len(p)+8+1 > finalmask.UDPSize {
errors.LogDebug(context.Background(), addr, " mask write err short write ", len(p), "+8+1 > ", finalmask.UDPSize)
return 0, nil
}
c.mutex.Lock()
defer c.mutex.Unlock()
if c.closed {
return 0, errors.New("xicmp closed")
q := c.ensureQueue(addr)
if q == nil {
return 0, io.ErrClosedPipe
}
buf := make([]byte, len(p))
@@ -338,24 +351,13 @@ func (c *xicmpConnServer) WriteTo(p []byte, addr net.Addr) (n int, err error) {
case q.queue <- buf:
return len(p), nil
default:
return 0, errors.New("xicmp queue full")
// errors.LogDebug(context.Background(), addr, " mask write err queue full")
return 0, nil
}
}
func (c *xicmpConnServer) Close() error {
c.mutex.Lock()
defer c.mutex.Unlock()
if c.closed {
return nil
}
c.closed = true
for key, q := range c.writeQueueMap {
close(q.queue)
delete(c.writeQueueMap, key)
}
_ = c.icmpConn.Close()
return c.conn.Close()
}