From b9fae52275b3ce42ee7366875873c8d94b33ff89 Mon Sep 17 00:00:00 2001 From: null Date: Sun, 1 Feb 2026 16:07:18 +0800 Subject: [PATCH 1/9] icmp --- infra/conf/transport_internet.go | 20 + transport/internet/finalmask/xdns/client.go | 2 +- transport/internet/finalmask/xicmp/client.go | 309 ++++++++++++++++ transport/internet/finalmask/xicmp/config.go | 16 + .../internet/finalmask/xicmp/config.pb.go | 132 +++++++ .../internet/finalmask/xicmp/config.proto | 13 + transport/internet/finalmask/xicmp/server.go | 349 ++++++++++++++++++ .../internet/finalmask/xicmp/xicmp_test.go | 73 ++++ 8 files changed, 913 insertions(+), 1 deletion(-) create mode 100644 transport/internet/finalmask/xicmp/client.go create mode 100644 transport/internet/finalmask/xicmp/config.go create mode 100644 transport/internet/finalmask/xicmp/config.pb.go create mode 100644 transport/internet/finalmask/xicmp/config.proto create mode 100644 transport/internet/finalmask/xicmp/server.go create mode 100644 transport/internet/finalmask/xicmp/xicmp_test.go diff --git a/infra/conf/transport_internet.go b/infra/conf/transport_internet.go index 716faae6ceaa..32acd4fcd0b8 100644 --- a/infra/conf/transport_internet.go +++ b/infra/conf/transport_internet.go @@ -26,6 +26,7 @@ import ( "github.com/xtls/xray-core/transport/internet/finalmask/mkcp/original" "github.com/xtls/xray-core/transport/internet/finalmask/salamander" "github.com/xtls/xray-core/transport/internet/finalmask/xdns" + "github.com/xtls/xray-core/transport/internet/finalmask/xicmp" "github.com/xtls/xray-core/transport/internet/httpupgrade" "github.com/xtls/xray-core/transport/internet/hysteria" "github.com/xtls/xray-core/transport/internet/kcp" @@ -1239,6 +1240,7 @@ var ( "mkcp-aes128gcm": func() interface{} { return new(Aes128Gcm) }, "salamander": func() interface{} { return new(Salamander) }, "xdns": func() interface{} { return new(Xdns) }, + "xicmp": func() interface{} { return new(Xicmp) }, }, "type", "settings") ) @@ -1327,6 +1329,24 @@ func (c *Xdns) Build() (proto.Message, error) { }, nil } +type Xicmp struct { + ListenIp string `json:"listenIp"` + Id int `json:"id"` +} + +func (c *Xicmp) Build() (proto.Message, error) { + config := &xicmp.Config{ + Ip: c.ListenIp, + Id: int32(c.Id), + } + + if config.Ip == "" { + config.Ip = "0.0.0.0" + } + + return config, nil +} + type Mask struct { Type string `json:"type"` Settings *json.RawMessage `json:"settings"` diff --git a/transport/internet/finalmask/xdns/client.go b/transport/internet/finalmask/xdns/client.go index c8b815d37bf8..9d80bc225762 100644 --- a/transport/internet/finalmask/xdns/client.go +++ b/transport/internet/finalmask/xdns/client.go @@ -209,7 +209,7 @@ func (c *xdnsConnClient) WriteTo(p []byte, addr net.Addr) (n int, err error) { encoded, err := encode(p, c.clientID, c.domain) if err != nil { - errors.LogDebug(context.Background(), "xdns encode err", err) + errors.LogDebug(context.Background(), "xdns encode err ", err) return 0, errors.New("xdns encode").Base(err) } diff --git a/transport/internet/finalmask/xicmp/client.go b/transport/internet/finalmask/xicmp/client.go new file mode 100644 index 000000000000..a353f6014325 --- /dev/null +++ b/transport/internet/finalmask/xicmp/client.go @@ -0,0 +1,309 @@ +package xicmp + +import ( + "context" + "encoding/binary" + "io" + "math/rand" + "net" + "strings" + "sync" + "time" + + "github.com/xtls/xray-core/common/errors" + "golang.org/x/net/icmp" + "golang.org/x/net/ipv4" + "golang.org/x/net/ipv6" +) + +const ( + initPollDelay = 500 * time.Millisecond + maxPollDelay = 10 * time.Second + pollDelayMultiplier = 2.0 + pollLimit = 16 +) + +type packet struct { + p []byte + addr net.Addr +} + +type xicmpConnClient struct { + conn net.PacketConn + icmpConn *icmp.PacketConn + + typ icmp.Type + id int + seq int + proto int + + pollChan chan struct{} + readQueue chan *packet + writeQueue chan *packet + + closed bool + mutex sync.Mutex +} + +func NewConnClient(c *Config, raw net.PacketConn, end bool) (net.PacketConn, error) { + if !end { + return nil, errors.New("xicmp requires being at the outermost level") + } + + network := "ip4:icmp" + typ := icmp.Type(ipv4.ICMPTypeEcho) + proto := 1 + if strings.Contains(c.Ip, ":") { + network = "ip6:ipv6-icmp" + typ = ipv6.ICMPTypeEchoRequest + proto = 58 + } + + icmpConn, err := icmp.ListenPacket(network, c.Ip) + if err != nil { + return nil, errors.New("xicmp listen err").Base(err) + } + + id := int(c.Id) + if id == 0 { + id = rand.Int() + } + + conn := &xicmpConnClient{ + conn: raw, + icmpConn: icmpConn, + + typ: typ, + id: id, + seq: 1, + proto: proto, + + pollChan: make(chan struct{}, pollLimit), + readQueue: make(chan *packet, 128), + writeQueue: make(chan *packet, 128), + } + + go conn.recvLoop() + go conn.sendLoop() + + return conn, nil +} + +func (c *xicmpConnClient) encode(p []byte) ([]byte, error) { + c.mutex.Lock() + defer c.mutex.Unlock() + + msg := icmp.Message{ + Type: c.typ, + Code: 0, + Body: &icmp.Echo{ + ID: c.id, + Seq: c.seq, + Data: p, + }, + } + + buf, err := msg.Marshal(nil) + if err != nil { + return nil, err + } + + if len(buf) > 8192 { + return nil, errors.New("xicmp len(buf) > 8192") + } + + c.seq++ + + return buf, nil +} + +func (c *xicmpConnClient) recvLoop() { + seqMap := make(map[int]struct{}) + + for { + if c.closed { + break + } + + var buf [8192]byte + + n, addr, err := c.icmpConn.ReadFrom(buf[:]) + if err != nil { + continue + } + + msg, err := icmp.ParseMessage(c.proto, buf[:n]) + if err != nil { + continue + } + + if msg.Type != ipv4.ICMPTypeEchoReply && msg.Type != ipv6.ICMPTypeEchoReply { + continue + } + + echo, ok := msg.Body.(*icmp.Echo) + if !ok { + continue + } + + if _, ok := seqMap[echo.Seq]; ok { + continue + } + + if len(echo.Data) > 4 { + if binary.BigEndian.Uint32(echo.Data) == uint32(c.id) { + seqMap[echo.Seq] = struct{}{} + + buf := make([]byte, len(echo.Data)-4) + copy(buf, echo.Data[4:]) + select { + case c.readQueue <- &packet{ + p: buf, + addr: &net.UDPAddr{IP: addr.(*net.IPAddr).IP}, + }: + default: + } + + select { + case c.pollChan <- struct{}{}: + default: + } + } + } + } + + close(c.pollChan) + close(c.readQueue) +} + +func (c *xicmpConnClient) sendLoop() { + var addr net.Addr + + pollDelay := initPollDelay + pollTimer := time.NewTimer(pollDelay) + for { + var p *packet + pollTimerExpired := false + + select { + case p = <-c.writeQueue: + default: + select { + case p = <-c.writeQueue: + case <-c.pollChan: + case <-pollTimer.C: + pollTimerExpired = true + } + } + + if p != nil { + addr = p.addr + + select { + case <-c.pollChan: + default: + } + } else if addr != nil { + encoded, _ := c.encode(nil) + p = &packet{ + p: encoded, + addr: addr, + } + } + + if pollTimerExpired { + pollDelay = time.Duration(float64(pollDelay) * pollDelayMultiplier) + if pollDelay > maxPollDelay { + pollDelay = maxPollDelay + } + } else { + if !pollTimer.Stop() { + <-pollTimer.C + } + pollDelay = initPollDelay + } + pollTimer.Reset(pollDelay) + + if c.closed { + return + } + + if p != nil { + _, err := c.icmpConn.WriteTo(p.p, p.addr) + if err != nil { + errors.LogDebug(context.Background(), "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 + } + n = copy(p, packet.p) + if n != len(packet.p) { + return 0, nil, io.ErrShortBuffer + } + return n, 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) + } + + c.mutex.Lock() + defer c.mutex.Unlock() + + if c.closed { + return 0, errors.New("xicmp closed") + } + + select { + case c.writeQueue <- &packet{ + p: encoded, + addr: &net.IPAddr{IP: addr.(*net.UDPAddr).IP}, + }: + return len(p), nil + default: + return 0, errors.New("xicmp queue full") + } +} + +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() +} + +func (c *xicmpConnClient) LocalAddr() net.Addr { + return &net.UDPAddr{IP: c.icmpConn.LocalAddr().(*net.IPAddr).IP} +} + +func (c *xicmpConnClient) SetDeadline(t time.Time) error { + return c.icmpConn.SetDeadline(t) +} + +func (c *xicmpConnClient) SetReadDeadline(t time.Time) error { + return c.icmpConn.SetReadDeadline(t) +} + +func (c *xicmpConnClient) SetWriteDeadline(t time.Time) error { + return c.icmpConn.SetWriteDeadline(t) +} diff --git a/transport/internet/finalmask/xicmp/config.go b/transport/internet/finalmask/xicmp/config.go new file mode 100644 index 000000000000..81a483af8539 --- /dev/null +++ b/transport/internet/finalmask/xicmp/config.go @@ -0,0 +1,16 @@ +package xicmp + +import ( + "net" +) + +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) WrapPacketConnServer(raw net.PacketConn, first bool, leaveSize int32, end bool) (net.PacketConn, error) { + return NewConnServer(c, raw, end) +} diff --git a/transport/internet/finalmask/xicmp/config.pb.go b/transport/internet/finalmask/xicmp/config.pb.go new file mode 100644 index 000000000000..290b508525e4 --- /dev/null +++ b/transport/internet/finalmask/xicmp/config.pb.go @@ -0,0 +1,132 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.10 +// protoc v6.33.1 +// source: transport/internet/finalmask/xicmp/config.proto + +package xicmp + +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 Config struct { + state protoimpl.MessageState `protogen:"open.v1"` + Ip string `protobuf:"bytes,1,opt,name=ip,proto3" json:"ip,omitempty"` + Id int32 `protobuf:"varint,2,opt,name=id,proto3" json:"id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Config) Reset() { + *x = Config{} + mi := &file_transport_internet_finalmask_xicmp_config_proto_msgTypes[0] + 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_transport_internet_finalmask_xicmp_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 Config.ProtoReflect.Descriptor instead. +func (*Config) Descriptor() ([]byte, []int) { + return file_transport_internet_finalmask_xicmp_config_proto_rawDescGZIP(), []int{0} +} + +func (x *Config) GetIp() string { + if x != nil { + return x.Ip + } + return "" +} + +func (x *Config) GetId() int32 { + if x != nil { + return x.Id + } + return 0 +} + +var File_transport_internet_finalmask_xicmp_config_proto protoreflect.FileDescriptor + +const file_transport_internet_finalmask_xicmp_config_proto_rawDesc = "" + + "\n" + + "/transport/internet/finalmask/xicmp/config.proto\x12'xray.transport.internet.finalmask.xicmp\"(\n" + + "\x06Config\x12\x0e\n" + + "\x02ip\x18\x01 \x01(\tR\x02ip\x12\x0e\n" + + "\x02id\x18\x02 \x01(\x05R\x02idB\x97\x01\n" + + "+com.xray.transport.internet.finalmask.xicmpP\x01Z= idleTimeout { + close(q.queue) + delete(c.writeQueueMap, key) + } + } + + return false + } + + for { + time.Sleep(idleTimeout / 2) + if f() { + return + } + } +} + +func (c *xicmpConnServer) ensureQueue(addr net.Addr) *queue { + c.mutex.Lock() + defer c.mutex.Unlock() + + if c.closed { + return nil + } + + q, ok := c.writeQueueMap[addr.String()] + if !ok { + q = &queue{ + queue: make(chan []byte, 128), + } + c.writeQueueMap[addr.String()] = q + } + q.lash = time.Now() + + return q +} + +func (c *xicmpConnServer) encode(p []byte, id int, seq int) ([]byte, error) { + data := make([]byte, 4) + binary.BigEndian.PutUint32(data, uint32(id)) + data = append(data, p...) + + msg := icmp.Message{ + Type: c.typ, + Code: 0, + Body: &icmp.Echo{ + ID: id, + Seq: seq, + Data: data, + }, + } + + buf, err := msg.Marshal(nil) + if err != nil { + return nil, err + } + + if len(buf) > 8192 { + return nil, errors.New("xicmp len(buf) > 8192") + } + + return buf, nil +} + +func (c *xicmpConnServer) recvLoop() { + for { + if c.closed { + break + } + + var buf [8192]byte + + n, addr, err := c.icmpConn.ReadFrom(buf[:]) + if err != nil { + continue + } + + msg, err := icmp.ParseMessage(c.proto, buf[:n]) + if err != nil { + continue + } + + if msg.Type != ipv4.ICMPTypeEcho && msg.Type != ipv6.ICMPTypeEchoRequest { + continue + } + + echo, ok := msg.Body.(*icmp.Echo) + if !ok { + continue + } + + if c.config.Id != 0 && echo.ID != int(c.config.Id) { + continue + } + + if len(echo.Data) > 0 { + buf := make([]byte, len(echo.Data)) + copy(buf, echo.Data) + select { + case c.readQueue <- &packet{ + p: buf, + addr: &net.UDPAddr{IP: addr.(*net.IPAddr).IP}, + }: + default: + } + } + + select { + case c.ch <- &record{ + id: echo.ID, + seq: echo.Seq, + addr: addr, + }: + default: + } + } + + close(c.ch) + close(c.readQueue) +} + +func (c *xicmpConnServer) sendLoop() { + var nextRec *record + for { + rec := nextRec + nextRec = nil + + if rec == nil { + var ok bool + rec, ok = <-c.ch + if !ok { + break + } + } + + queue := c.ensureQueue(rec.addr) + if queue == nil { + return + } + + var p []byte + + timer := time.NewTimer(maxResponseDelay) + + select { + case p = <-queue.queue: + default: + select { + case p = <-queue.queue: + case <-timer.C: + case nextRec = <-c.ch: + } + } + + timer.Stop() + + if len(p) == 0 { + continue + } + + buf, err := c.encode(p, rec.id, rec.seq) + if err != nil { + continue + } + + if c.closed { + return + } + + _, err = c.icmpConn.WriteTo(buf, rec.addr) + if err != nil { + errors.LogDebug(context.Background(), "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 + } + n = copy(p, packet.p) + if n != len(packet.p) { + return 0, nil, io.ErrShortBuffer + } + return n, packet.addr, nil +} + +func (c *xicmpConnServer) WriteTo(p []byte, addr net.Addr) (n int, err error) { + q := c.ensureQueue(&net.IPAddr{IP: addr.(*net.UDPAddr).IP}) + if q == nil { + return 0, errors.New("xicmp closed") + } + + c.mutex.Lock() + defer c.mutex.Unlock() + + if c.closed { + return 0, errors.New("xicmp closed") + } + + buf := make([]byte, len(p)) + copy(buf, p) + + select { + case q.queue <- buf: + return len(p), nil + default: + return 0, errors.New("xicmp queue full") + } +} + +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() +} + +func (c *xicmpConnServer) LocalAddr() net.Addr { + return &net.UDPAddr{IP: c.icmpConn.LocalAddr().(*net.IPAddr).IP} +} + +func (c *xicmpConnServer) SetDeadline(t time.Time) error { + return c.icmpConn.SetDeadline(t) +} + +func (c *xicmpConnServer) SetReadDeadline(t time.Time) error { + return c.icmpConn.SetReadDeadline(t) +} + +func (c *xicmpConnServer) SetWriteDeadline(t time.Time) error { + return c.icmpConn.SetWriteDeadline(t) +} diff --git a/transport/internet/finalmask/xicmp/xicmp_test.go b/transport/internet/finalmask/xicmp/xicmp_test.go new file mode 100644 index 000000000000..be0f4a0323a1 --- /dev/null +++ b/transport/internet/finalmask/xicmp/xicmp_test.go @@ -0,0 +1,73 @@ +package xicmp_test + +import ( + "fmt" + "testing" + + "golang.org/x/net/icmp" + "golang.org/x/net/ipv4" + "golang.org/x/net/ipv6" +) + +func TestICMPEchoMarshal(t *testing.T) { + msg := icmp.Message{ + Type: ipv4.ICMPTypeEcho, + Code: 0, + Body: &icmp.Echo{ + ID: 0, + Seq: 1, + Data: nil, + }, + } + ICMPTypeEcho, _ := msg.Marshal(nil) + fmt.Println("ICMPTypeEcho", len(ICMPTypeEcho), ICMPTypeEcho) + + msg = icmp.Message{ + Type: ipv4.ICMPTypeEchoReply, + Code: 0, + Body: &icmp.Echo{ + ID: 0, + Seq: 1, + Data: nil, + }, + } + ICMPTypeEchoReply, _ := msg.Marshal(nil) + fmt.Println("ICMPTypeEchoReply", len(ICMPTypeEchoReply), ICMPTypeEchoReply) + + msg = icmp.Message{ + Type: ipv6.ICMPTypeEchoRequest, + Code: 0, + Body: &icmp.Echo{ + ID: 0, + Seq: 1, + Data: nil, + }, + } + ICMPTypeEchoRequest, _ := msg.Marshal(nil) + fmt.Println("ICMPTypeEchoRequest", len(ICMPTypeEchoRequest), ICMPTypeEchoRequest) + + msg = icmp.Message{ + Type: ipv6.ICMPTypeEchoReply, + Code: 0, + Body: &icmp.Echo{ + ID: 0, + Seq: 1, + Data: nil, + }, + } + V6ICMPTypeEchoReply, _ := msg.Marshal(nil) + fmt.Println("V6ICMPTypeEchoReply", len(V6ICMPTypeEchoReply), V6ICMPTypeEchoReply) + + if len(ICMPTypeEcho) != 8 { + t.Fatalf("ICMPTypeEcho len=%d", len(ICMPTypeEcho)) + } + if len(ICMPTypeEchoReply) != 8 { + t.Fatalf("ICMPTypeEchoReply len=%d", len(ICMPTypeEchoReply)) + } + if len(ICMPTypeEchoRequest) != 8 { + t.Fatalf("ICMPTypeEchoRequest len=%d", len(ICMPTypeEchoRequest)) + } + if len(V6ICMPTypeEchoReply) != 8 { + t.Fatalf("V6ICMPTypeEchoReply len=%d", len(V6ICMPTypeEchoReply)) + } +} From 5524424d7ef00a7553a993f6616311614d2ac30f Mon Sep 17 00:00:00 2001 From: null Date: Sun, 1 Feb 2026 19:53:01 +0800 Subject: [PATCH 2/9] uint16 id seq --- infra/conf/transport_internet.go | 2 +- transport/internet/finalmask/xicmp/client.go | 20 +++++------ transport/internet/finalmask/xicmp/server.go | 18 +++++----- .../internet/finalmask/xicmp/xicmp_test.go | 33 ++++++++++--------- 4 files changed, 37 insertions(+), 36 deletions(-) diff --git a/infra/conf/transport_internet.go b/infra/conf/transport_internet.go index 32acd4fcd0b8..b8a437d0566c 100644 --- a/infra/conf/transport_internet.go +++ b/infra/conf/transport_internet.go @@ -1331,7 +1331,7 @@ func (c *Xdns) Build() (proto.Message, error) { type Xicmp struct { ListenIp string `json:"listenIp"` - Id int `json:"id"` + Id uint16 `json:"id"` } func (c *Xicmp) Build() (proto.Message, error) { diff --git a/transport/internet/finalmask/xicmp/client.go b/transport/internet/finalmask/xicmp/client.go index a353f6014325..40b48507a514 100644 --- a/transport/internet/finalmask/xicmp/client.go +++ b/transport/internet/finalmask/xicmp/client.go @@ -33,8 +33,8 @@ type xicmpConnClient struct { icmpConn *icmp.PacketConn typ icmp.Type - id int - seq int + id uint16 + seq uint16 proto int pollChan chan struct{} @@ -64,9 +64,9 @@ func NewConnClient(c *Config, raw net.PacketConn, end bool) (net.PacketConn, err return nil, errors.New("xicmp listen err").Base(err) } - id := int(c.Id) + id := uint16(c.Id) if id == 0 { - id = rand.Int() + id = uint16(rand.Int()) } conn := &xicmpConnClient{ @@ -97,8 +97,8 @@ func (c *xicmpConnClient) encode(p []byte) ([]byte, error) { Type: c.typ, Code: 0, Body: &icmp.Echo{ - ID: c.id, - Seq: c.seq, + ID: int(c.id), + Seq: int(c.seq), Data: p, }, } @@ -150,12 +150,12 @@ func (c *xicmpConnClient) recvLoop() { continue } - if len(echo.Data) > 4 { - if binary.BigEndian.Uint32(echo.Data) == uint32(c.id) { + if len(echo.Data) > 2 { + if binary.BigEndian.Uint16(echo.Data) == c.id { seqMap[echo.Seq] = struct{}{} - buf := make([]byte, len(echo.Data)-4) - copy(buf, echo.Data[4:]) + buf := make([]byte, len(echo.Data)-2) + copy(buf, echo.Data[2:]) select { case c.readQueue <- &packet{ p: buf, diff --git a/transport/internet/finalmask/xicmp/server.go b/transport/internet/finalmask/xicmp/server.go index 7b32309760e2..c1352d594185 100644 --- a/transport/internet/finalmask/xicmp/server.go +++ b/transport/internet/finalmask/xicmp/server.go @@ -21,8 +21,8 @@ const ( ) type record struct { - id int - seq int + id uint16 + seq uint16 addr net.Addr } @@ -135,17 +135,17 @@ func (c *xicmpConnServer) ensureQueue(addr net.Addr) *queue { return q } -func (c *xicmpConnServer) encode(p []byte, id int, seq int) ([]byte, error) { - data := make([]byte, 4) - binary.BigEndian.PutUint32(data, uint32(id)) +func (c *xicmpConnServer) encode(p []byte, id uint16, seq uint16) ([]byte, error) { + data := make([]byte, 2) + binary.BigEndian.PutUint16(data, id) data = append(data, p...) msg := icmp.Message{ Type: c.typ, Code: 0, Body: &icmp.Echo{ - ID: id, - Seq: seq, + ID: int(id), + Seq: int(seq), Data: data, }, } @@ -207,8 +207,8 @@ func (c *xicmpConnServer) recvLoop() { select { case c.ch <- &record{ - id: echo.ID, - seq: echo.Seq, + id: uint16(echo.ID), + seq: uint16(echo.Seq), addr: addr, }: default: diff --git a/transport/internet/finalmask/xicmp/xicmp_test.go b/transport/internet/finalmask/xicmp/xicmp_test.go index be0f4a0323a1..1ac921819bea 100644 --- a/transport/internet/finalmask/xicmp/xicmp_test.go +++ b/transport/internet/finalmask/xicmp/xicmp_test.go @@ -1,6 +1,7 @@ package xicmp_test import ( + "bytes" "fmt" "testing" @@ -14,8 +15,8 @@ func TestICMPEchoMarshal(t *testing.T) { Type: ipv4.ICMPTypeEcho, Code: 0, Body: &icmp.Echo{ - ID: 0, - Seq: 1, + ID: 65535, + Seq: 65537, Data: nil, }, } @@ -26,8 +27,8 @@ func TestICMPEchoMarshal(t *testing.T) { Type: ipv4.ICMPTypeEchoReply, Code: 0, Body: &icmp.Echo{ - ID: 0, - Seq: 1, + ID: 65535, + Seq: 65537, Data: nil, }, } @@ -38,8 +39,8 @@ func TestICMPEchoMarshal(t *testing.T) { Type: ipv6.ICMPTypeEchoRequest, Code: 0, Body: &icmp.Echo{ - ID: 0, - Seq: 1, + ID: 65535, + Seq: 65537, Data: nil, }, } @@ -50,24 +51,24 @@ func TestICMPEchoMarshal(t *testing.T) { Type: ipv6.ICMPTypeEchoReply, Code: 0, Body: &icmp.Echo{ - ID: 0, - Seq: 1, + ID: 65535, + Seq: 65537, Data: nil, }, } V6ICMPTypeEchoReply, _ := msg.Marshal(nil) fmt.Println("V6ICMPTypeEchoReply", len(V6ICMPTypeEchoReply), V6ICMPTypeEchoReply) - if len(ICMPTypeEcho) != 8 { - t.Fatalf("ICMPTypeEcho len=%d", len(ICMPTypeEcho)) + if !bytes.Equal(ICMPTypeEcho[0:2], []byte{8, 0}) || !bytes.Equal(ICMPTypeEcho[4:], []byte{255, 255, 0, 1}) { + t.Fatalf("ICMPTypeEcho Type/Code or ID/Seq mismatch: %v", ICMPTypeEcho) } - if len(ICMPTypeEchoReply) != 8 { - t.Fatalf("ICMPTypeEchoReply len=%d", len(ICMPTypeEchoReply)) + if !bytes.Equal(ICMPTypeEchoReply[0:2], []byte{0, 0}) || !bytes.Equal(ICMPTypeEchoReply[4:], []byte{255, 255, 0, 1}) { + t.Fatalf("ICMPTypeEchoReply Type/Code or ID/Seq mismatch: %v", ICMPTypeEchoReply) } - if len(ICMPTypeEchoRequest) != 8 { - t.Fatalf("ICMPTypeEchoRequest len=%d", len(ICMPTypeEchoRequest)) + if !bytes.Equal(ICMPTypeEchoRequest[0:2], []byte{128, 0}) || !bytes.Equal(ICMPTypeEchoRequest[4:], []byte{255, 255, 0, 1}) { + t.Fatalf("ICMPTypeEchoRequest Type/Code or ID/Seq mismatch: %v", ICMPTypeEchoRequest) } - if len(V6ICMPTypeEchoReply) != 8 { - t.Fatalf("V6ICMPTypeEchoReply len=%d", len(V6ICMPTypeEchoReply)) + if !bytes.Equal(V6ICMPTypeEchoReply[0:2], []byte{129, 0}) || !bytes.Equal(V6ICMPTypeEchoReply[4:], []byte{255, 255, 0, 1}) { + t.Fatalf("V6ICMPTypeEchoReply Type/Code or ID/Seq mismatch: %v", V6ICMPTypeEchoReply) } } From 38064e695887094042d499bf7eb941dd6fbd5638 Mon Sep 17 00:00:00 2001 From: null Date: Mon, 2 Feb 2026 01:12:11 +0800 Subject: [PATCH 3/9] random seqByte --- transport/internet/finalmask/xicmp/client.go | 79 +++++++++++--------- transport/internet/finalmask/xicmp/server.go | 47 ++++++++---- 2 files changed, 76 insertions(+), 50 deletions(-) diff --git a/transport/internet/finalmask/xicmp/client.go b/transport/internet/finalmask/xicmp/client.go index 40b48507a514..e31208f404c8 100644 --- a/transport/internet/finalmask/xicmp/client.go +++ b/transport/internet/finalmask/xicmp/client.go @@ -2,14 +2,13 @@ package xicmp import ( "context" - "encoding/binary" "io" - "math/rand" "net" "strings" "sync" "time" + "github.com/xtls/xray-core/common/crypto" "github.com/xtls/xray-core/common/errors" "golang.org/x/net/icmp" "golang.org/x/net/ipv4" @@ -32,10 +31,11 @@ type xicmpConnClient struct { conn net.PacketConn icmpConn *icmp.PacketConn - typ icmp.Type - id uint16 - seq uint16 - proto int + typ icmp.Type + id int + seq int + proto int + seqByte map[int]byte pollChan chan struct{} readQueue chan *packet @@ -64,19 +64,19 @@ func NewConnClient(c *Config, raw net.PacketConn, end bool) (net.PacketConn, err return nil, errors.New("xicmp listen err").Base(err) } - id := uint16(c.Id) - if id == 0 { - id = uint16(rand.Int()) + if c.Id == 0 { + c.Id = int32(crypto.RandBetween(0, 65535)) } conn := &xicmpConnClient{ conn: raw, icmpConn: icmpConn, - typ: typ, - id: id, - seq: 1, - proto: proto, + typ: typ, + id: int(c.Id), + seq: 1, + proto: proto, + seqByte: make(map[int]byte), pollChan: make(chan struct{}, pollLimit), readQueue: make(chan *packet, 128), @@ -93,13 +93,15 @@ func (c *xicmpConnClient) encode(p []byte) ([]byte, error) { c.mutex.Lock() defer c.mutex.Unlock() + seqByte := byte(crypto.RandBetween(0, 255)) + msg := icmp.Message{ Type: c.typ, Code: 0, Body: &icmp.Echo{ - ID: int(c.id), - Seq: int(c.seq), - Data: p, + ID: c.id, + Seq: c.seq, + Data: append([]byte{seqByte}, p...), }, } @@ -112,6 +114,8 @@ func (c *xicmpConnClient) encode(p []byte) ([]byte, error) { return nil, errors.New("xicmp len(buf) > 8192") } + c.seqByte[c.seq] = seqByte + c.seq++ return buf, nil @@ -150,24 +154,31 @@ func (c *xicmpConnClient) recvLoop() { continue } - if len(echo.Data) > 2 { - if binary.BigEndian.Uint16(echo.Data) == c.id { - seqMap[echo.Seq] = struct{}{} - - buf := make([]byte, len(echo.Data)-2) - copy(buf, echo.Data[2:]) - select { - case c.readQueue <- &packet{ - p: buf, - addr: &net.UDPAddr{IP: addr.(*net.IPAddr).IP}, - }: - default: - } - - select { - case c.pollChan <- struct{}{}: - default: - } + if _, ok := c.seqByte[echo.Seq]; !ok { + continue + } + + if len(echo.Data) > 1 { + if echo.Data[0] == c.seqByte[echo.Seq] { + continue + } + echo.Data = echo.Data[1:] + + seqMap[echo.Seq] = struct{}{} + + buf := make([]byte, len(echo.Data)) + copy(buf, echo.Data) + select { + case c.readQueue <- &packet{ + p: buf, + addr: &net.UDPAddr{IP: addr.(*net.IPAddr).IP}, + }: + default: + } + + select { + case c.pollChan <- struct{}{}: + default: } } } diff --git a/transport/internet/finalmask/xicmp/server.go b/transport/internet/finalmask/xicmp/server.go index c1352d594185..3887b6021ec2 100644 --- a/transport/internet/finalmask/xicmp/server.go +++ b/transport/internet/finalmask/xicmp/server.go @@ -2,13 +2,13 @@ package xicmp import ( "context" - "encoding/binary" "io" "net" "strings" "sync" "time" + "github.com/xtls/xray-core/common/crypto" "github.com/xtls/xray-core/common/errors" "golang.org/x/net/icmp" "golang.org/x/net/ipv4" @@ -21,9 +21,10 @@ const ( ) type record struct { - id uint16 - seq uint16 - addr net.Addr + id int + seq int + seqByte byte + addr net.Addr } type queue struct { @@ -135,18 +136,16 @@ func (c *xicmpConnServer) ensureQueue(addr net.Addr) *queue { return q } -func (c *xicmpConnServer) encode(p []byte, id uint16, seq uint16) ([]byte, error) { - data := make([]byte, 2) - binary.BigEndian.PutUint16(data, id) - data = append(data, p...) +func (c *xicmpConnServer) encode(p []byte, id int, seq int, seqByte byte) ([]byte, error) { + b2 := c.randUntil(seqByte) msg := icmp.Message{ Type: c.typ, Code: 0, Body: &icmp.Echo{ - ID: int(id), - Seq: int(seq), - Data: data, + ID: id, + Seq: seq, + Data: append([]byte{b2}, p...), }, } @@ -162,6 +161,16 @@ func (c *xicmpConnServer) encode(p []byte, id uint16, seq uint16) ([]byte, error return buf, nil } +func (c *xicmpConnServer) randUntil(b1 byte) byte { + b2 := byte(crypto.RandBetween(0, 255)) + for { + if b2 != b1 { + return b2 + } + b2 = byte(crypto.RandBetween(0, 255)) + } +} + func (c *xicmpConnServer) recvLoop() { for { if c.closed { @@ -193,7 +202,12 @@ func (c *xicmpConnServer) recvLoop() { continue } - if len(echo.Data) > 0 { + var seqByte byte + + if len(echo.Data) > 1 { + seqByte = echo.Data[0] + echo.Data = echo.Data[1:] + buf := make([]byte, len(echo.Data)) copy(buf, echo.Data) select { @@ -207,9 +221,10 @@ func (c *xicmpConnServer) recvLoop() { select { case c.ch <- &record{ - id: uint16(echo.ID), - seq: uint16(echo.Seq), - addr: addr, + id: echo.ID, + seq: echo.Seq, + seqByte: seqByte, + addr: addr, }: default: } @@ -258,7 +273,7 @@ func (c *xicmpConnServer) sendLoop() { continue } - buf, err := c.encode(p, rec.id, rec.seq) + buf, err := c.encode(p, rec.id, rec.seq, rec.seqByte) if err != nil { continue } From fa08e82cba35f27f2aa80717b4738991d482239a Mon Sep 17 00:00:00 2001 From: null Date: Mon, 2 Feb 2026 01:18:26 +0800 Subject: [PATCH 4/9] fix logic --- transport/internet/finalmask/xicmp/server.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/transport/internet/finalmask/xicmp/server.go b/transport/internet/finalmask/xicmp/server.go index 3887b6021ec2..41235222b048 100644 --- a/transport/internet/finalmask/xicmp/server.go +++ b/transport/internet/finalmask/xicmp/server.go @@ -217,16 +217,16 @@ func (c *xicmpConnServer) recvLoop() { }: default: } - } - select { - case c.ch <- &record{ - id: echo.ID, - seq: echo.Seq, - seqByte: seqByte, - addr: addr, - }: - default: + select { + case c.ch <- &record{ + id: echo.ID, + seq: echo.Seq, + seqByte: seqByte, + addr: addr, + }: + default: + } } } From aa240f437634885a260da5a49acdb926a11e061f Mon Sep 17 00:00:00 2001 From: null Date: Mon, 2 Feb 2026 01:23:25 +0800 Subject: [PATCH 5/9] fix logic --- transport/internet/finalmask/xicmp/server.go | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/transport/internet/finalmask/xicmp/server.go b/transport/internet/finalmask/xicmp/server.go index 41235222b048..f054927841ff 100644 --- a/transport/internet/finalmask/xicmp/server.go +++ b/transport/internet/finalmask/xicmp/server.go @@ -204,18 +204,20 @@ func (c *xicmpConnServer) recvLoop() { var seqByte byte - if len(echo.Data) > 1 { + if len(echo.Data) >= 1 { seqByte = echo.Data[0] echo.Data = echo.Data[1:] - buf := make([]byte, len(echo.Data)) - copy(buf, echo.Data) - select { - case c.readQueue <- &packet{ - p: buf, - addr: &net.UDPAddr{IP: addr.(*net.IPAddr).IP}, - }: - default: + if len(echo.Data) > 0 { + buf := make([]byte, len(echo.Data)) + copy(buf, echo.Data) + select { + case c.readQueue <- &packet{ + p: buf, + addr: &net.UDPAddr{IP: addr.(*net.IPAddr).IP}, + }: + default: + } } select { From 65a91b158040d4dd093d191e849783efd1a03b9d Mon Sep 17 00:00:00 2001 From: null Date: Mon, 2 Feb 2026 10:06:35 +0800 Subject: [PATCH 6/9] seqStatus & recycle seq --- transport/internet/finalmask/xicmp/client.go | 62 +++++++++++++------- transport/internet/finalmask/xicmp/server.go | 42 +++++++------ 2 files changed, 67 insertions(+), 37 deletions(-) diff --git a/transport/internet/finalmask/xicmp/client.go b/transport/internet/finalmask/xicmp/client.go index e31208f404c8..ceb2f40f3b9e 100644 --- a/transport/internet/finalmask/xicmp/client.go +++ b/transport/internet/finalmask/xicmp/client.go @@ -27,15 +27,21 @@ type packet struct { addr net.Addr } +type seqStatus struct { + needSeqByte bool + seqByte byte + received bool +} + type xicmpConnClient struct { conn net.PacketConn icmpConn *icmp.PacketConn - typ icmp.Type - id int - seq int - proto int - seqByte map[int]byte + typ icmp.Type + id int + seq int + proto int + seqStatus map[int]*seqStatus pollChan chan struct{} readQueue chan *packet @@ -72,11 +78,11 @@ func NewConnClient(c *Config, raw net.PacketConn, end bool) (net.PacketConn, err conn: raw, icmpConn: icmpConn, - typ: typ, - id: int(c.Id), - seq: 1, - proto: proto, - seqByte: make(map[int]byte), + typ: typ, + id: int(c.Id), + seq: 1, + proto: proto, + seqStatus: make(map[int]*seqStatus), pollChan: make(chan struct{}, pollLimit), readQueue: make(chan *packet, 128), @@ -93,7 +99,14 @@ func (c *xicmpConnClient) encode(p []byte) ([]byte, error) { c.mutex.Lock() defer c.mutex.Unlock() - seqByte := byte(crypto.RandBetween(0, 255)) + needSeqByte := false + var seqByte byte + data := p + if len(p) > 0 { + needSeqByte = true + seqByte = byte(crypto.RandBetween(0, 255)) + data = append([]byte{seqByte}, p...) + } msg := icmp.Message{ Type: c.typ, @@ -101,7 +114,7 @@ func (c *xicmpConnClient) encode(p []byte) ([]byte, error) { Body: &icmp.Echo{ ID: c.id, Seq: c.seq, - Data: append([]byte{seqByte}, p...), + Data: data, }, } @@ -114,7 +127,11 @@ func (c *xicmpConnClient) encode(p []byte) ([]byte, error) { return nil, errors.New("xicmp len(buf) > 8192") } - c.seqByte[c.seq] = seqByte + c.seqStatus[c.seq] = &seqStatus{ + needSeqByte: needSeqByte, + seqByte: seqByte, + received: false, + } c.seq++ @@ -122,8 +139,6 @@ func (c *xicmpConnClient) encode(p []byte) ([]byte, error) { } func (c *xicmpConnClient) recvLoop() { - seqMap := make(map[int]struct{}) - for { if c.closed { break @@ -150,21 +165,28 @@ func (c *xicmpConnClient) recvLoop() { continue } - if _, ok := seqMap[echo.Seq]; ok { + seqStatus, ok := c.seqStatus[echo.Seq] + + if !ok { continue } - if _, ok := c.seqByte[echo.Seq]; !ok { + if seqStatus.received { continue } - if len(echo.Data) > 1 { - if echo.Data[0] == c.seqByte[echo.Seq] { + if seqStatus.needSeqByte { + if len(echo.Data) <= 1 { + continue + } + if echo.Data[0] == seqStatus.seqByte { continue } echo.Data = echo.Data[1:] + } - seqMap[echo.Seq] = struct{}{} + if len(echo.Data) > 0 { + seqStatus.received = true buf := make([]byte, len(echo.Data)) copy(buf, echo.Data) diff --git a/transport/internet/finalmask/xicmp/server.go b/transport/internet/finalmask/xicmp/server.go index f054927841ff..57f536f63d1f 100644 --- a/transport/internet/finalmask/xicmp/server.go +++ b/transport/internet/finalmask/xicmp/server.go @@ -21,10 +21,11 @@ const ( ) type record struct { - id int - seq int - seqByte byte - addr net.Addr + id int + seq int + needSeqByte bool + seqByte byte + addr net.Addr } type queue struct { @@ -136,8 +137,12 @@ func (c *xicmpConnServer) ensureQueue(addr net.Addr) *queue { return q } -func (c *xicmpConnServer) encode(p []byte, id int, seq int, seqByte byte) ([]byte, error) { - b2 := c.randUntil(seqByte) +func (c *xicmpConnServer) encode(p []byte, id int, seq int, needSeqByte bool, seqByte byte) ([]byte, error) { + data := p + if needSeqByte { + b2 := c.randUntil(seqByte) + data = append([]byte{b2}, p...) + } msg := icmp.Message{ Type: c.typ, @@ -145,7 +150,7 @@ func (c *xicmpConnServer) encode(p []byte, id int, seq int, seqByte byte) ([]byt Body: &icmp.Echo{ ID: id, Seq: seq, - Data: append([]byte{b2}, p...), + Data: data, }, } @@ -202,9 +207,11 @@ func (c *xicmpConnServer) recvLoop() { continue } + needSeqByte := false var seqByte byte if len(echo.Data) >= 1 { + needSeqByte = true seqByte = echo.Data[0] echo.Data = echo.Data[1:] @@ -219,16 +226,17 @@ func (c *xicmpConnServer) recvLoop() { default: } } + } - select { - case c.ch <- &record{ - id: echo.ID, - seq: echo.Seq, - seqByte: seqByte, - addr: addr, - }: - default: - } + select { + case c.ch <- &record{ + id: echo.ID, + seq: echo.Seq, + needSeqByte: needSeqByte, + seqByte: seqByte, + addr: addr, + }: + default: } } @@ -275,7 +283,7 @@ func (c *xicmpConnServer) sendLoop() { continue } - buf, err := c.encode(p, rec.id, rec.seq, rec.seqByte) + buf, err := c.encode(p, rec.id, rec.seq, rec.needSeqByte, rec.seqByte) if err != nil { continue } From ba055e0f6f1185747a1707cc813897f8b0d7d358 Mon Sep 17 00:00:00 2001 From: null Date: Mon, 2 Feb 2026 10:16:31 +0800 Subject: [PATCH 7/9] seq cycle --- transport/internet/finalmask/xicmp/client.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/transport/internet/finalmask/xicmp/client.go b/transport/internet/finalmask/xicmp/client.go index ceb2f40f3b9e..bfb984820140 100644 --- a/transport/internet/finalmask/xicmp/client.go +++ b/transport/internet/finalmask/xicmp/client.go @@ -135,6 +135,10 @@ func (c *xicmpConnClient) encode(p []byte) ([]byte, error) { c.seq++ + if c.seq == 65536 { + c.seq = 1 + } + return buf, nil } From fb9de11d84eef00f35460a5ca292584a52bbdc3a Mon Sep 17 00:00:00 2001 From: null Date: Mon, 2 Feb 2026 11:53:16 +0800 Subject: [PATCH 8/9] better logic --- transport/internet/finalmask/xicmp/client.go | 3 +-- transport/internet/finalmask/xicmp/server.go | 23 +++++++++----------- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/transport/internet/finalmask/xicmp/client.go b/transport/internet/finalmask/xicmp/client.go index bfb984820140..a0009651a13b 100644 --- a/transport/internet/finalmask/xicmp/client.go +++ b/transport/internet/finalmask/xicmp/client.go @@ -104,8 +104,7 @@ func (c *xicmpConnClient) encode(p []byte) ([]byte, error) { data := p if len(p) > 0 { needSeqByte = true - seqByte = byte(crypto.RandBetween(0, 255)) - data = append([]byte{seqByte}, p...) + seqByte = p[0] } msg := icmp.Message{ diff --git a/transport/internet/finalmask/xicmp/server.go b/transport/internet/finalmask/xicmp/server.go index 57f536f63d1f..c2328ed0219b 100644 --- a/transport/internet/finalmask/xicmp/server.go +++ b/transport/internet/finalmask/xicmp/server.go @@ -210,21 +210,18 @@ func (c *xicmpConnServer) recvLoop() { needSeqByte := false var seqByte byte - if len(echo.Data) >= 1 { + if len(echo.Data) > 0 { needSeqByte = true seqByte = echo.Data[0] - echo.Data = echo.Data[1:] - - if len(echo.Data) > 0 { - buf := make([]byte, len(echo.Data)) - copy(buf, echo.Data) - select { - case c.readQueue <- &packet{ - p: buf, - addr: &net.UDPAddr{IP: addr.(*net.IPAddr).IP}, - }: - default: - } + + buf := make([]byte, len(echo.Data)) + copy(buf, echo.Data) + select { + case c.readQueue <- &packet{ + p: buf, + addr: &net.UDPAddr{IP: addr.(*net.IPAddr).IP}, + }: + default: } } From 9be41f43bfc920f7c3174589de3d8ecf9da126d0 Mon Sep 17 00:00:00 2001 From: null Date: Mon, 2 Feb 2026 12:26:53 +0800 Subject: [PATCH 9/9] use echo.ID as the port to distinguish KCP sessions --- transport/internet/finalmask/xicmp/client.go | 5 ++++- transport/internet/finalmask/xicmp/server.go | 16 +++++++++++----- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/transport/internet/finalmask/xicmp/client.go b/transport/internet/finalmask/xicmp/client.go index a0009651a13b..fa7c6a4fb4c1 100644 --- a/transport/internet/finalmask/xicmp/client.go +++ b/transport/internet/finalmask/xicmp/client.go @@ -329,7 +329,10 @@ func (c *xicmpConnClient) Close() error { } func (c *xicmpConnClient) LocalAddr() net.Addr { - return &net.UDPAddr{IP: c.icmpConn.LocalAddr().(*net.IPAddr).IP} + return &net.UDPAddr{ + IP: c.icmpConn.LocalAddr().(*net.IPAddr).IP, + Port: c.id, + } } func (c *xicmpConnClient) SetDeadline(t time.Time) error { diff --git a/transport/internet/finalmask/xicmp/server.go b/transport/internet/finalmask/xicmp/server.go index c2328ed0219b..8d2ee256ef74 100644 --- a/transport/internet/finalmask/xicmp/server.go +++ b/transport/internet/finalmask/xicmp/server.go @@ -218,8 +218,11 @@ func (c *xicmpConnServer) recvLoop() { copy(buf, echo.Data) select { case c.readQueue <- &packet{ - p: buf, - addr: &net.UDPAddr{IP: addr.(*net.IPAddr).IP}, + p: buf, + addr: &net.UDPAddr{ + IP: addr.(*net.IPAddr).IP, + Port: echo.ID, + }, }: default: } @@ -231,7 +234,10 @@ func (c *xicmpConnServer) recvLoop() { seq: echo.Seq, needSeqByte: needSeqByte, seqByte: seqByte, - addr: addr, + addr: &net.UDPAddr{ + IP: addr.(*net.IPAddr).IP, + Port: echo.ID, + }, }: default: } @@ -289,7 +295,7 @@ func (c *xicmpConnServer) sendLoop() { return } - _, err = c.icmpConn.WriteTo(buf, rec.addr) + _, err = c.icmpConn.WriteTo(buf, &net.IPAddr{IP: rec.addr.(*net.UDPAddr).IP}) if err != nil { errors.LogDebug(context.Background(), "xicmp writeto err ", err) } @@ -313,7 +319,7 @@ func (c *xicmpConnServer) ReadFrom(p []byte) (n int, addr net.Addr, err error) { } func (c *xicmpConnServer) WriteTo(p []byte, addr net.Addr) (n int, err error) { - q := c.ensureQueue(&net.IPAddr{IP: addr.(*net.UDPAddr).IP}) + q := c.ensureQueue(addr) if q == nil { return 0, errors.New("xicmp closed") }