From 4364190e6d8f644c20228d5d2e1fa6488be13577 Mon Sep 17 00:00:00 2001 From: ginuerzh Date: Wed, 9 Mar 2022 18:29:45 +0800 Subject: [PATCH] fix icmp tunnel --- pkg/dialer/icmp/dialer.go | 2 +- pkg/{common => internal}/util/icmp/conn.go | 110 +++++++++++++++++---- pkg/listener/icmp/listener.go | 2 +- 3 files changed, 93 insertions(+), 21 deletions(-) rename pkg/{common => internal}/util/icmp/conn.go (60%) diff --git a/pkg/dialer/icmp/dialer.go b/pkg/dialer/icmp/dialer.go index d4b5a5e..5ea0bcd 100644 --- a/pkg/dialer/icmp/dialer.go +++ b/pkg/dialer/icmp/dialer.go @@ -8,8 +8,8 @@ import ( "sync" "time" - icmp_pkg "github.com/go-gost/gost/pkg/common/util/icmp" "github.com/go-gost/gost/pkg/dialer" + icmp_pkg "github.com/go-gost/gost/pkg/internal/util/icmp" "github.com/go-gost/gost/pkg/logger" md "github.com/go-gost/gost/pkg/metadata" "github.com/go-gost/gost/pkg/registry" diff --git a/pkg/common/util/icmp/conn.go b/pkg/internal/util/icmp/conn.go similarity index 60% rename from pkg/common/util/icmp/conn.go rename to pkg/internal/util/icmp/conn.go index 0b1167d..fb91c88 100644 --- a/pkg/common/util/icmp/conn.go +++ b/pkg/internal/util/icmp/conn.go @@ -20,11 +20,64 @@ const ( magicNumber = 0x474F5354 ) +const ( + messageHeaderLen = 10 +) + +const ( + FlagAck = 1 +) + var ( ErrInvalidPacket = errors.New("icmp: invalid packet") ErrInvalidType = errors.New("icmp: invalid type") + ErrShortBuffer = errors.New("icmp: short buffer") ) +type message struct { + // magic uint32 // magic number + flags uint16 // flags + // rsv uint16 // reserved field + // len uint16 // length of data + data []byte +} + +func (m *message) Encode(b []byte) (n int, err error) { + if len(b) < messageHeaderLen+len(m.data) { + err = ErrShortBuffer + return + } + binary.BigEndian.PutUint32(b[:4], magicNumber) // magic number + binary.BigEndian.PutUint16(b[4:6], m.flags) // flags + binary.BigEndian.PutUint16(b[6:8], 0) // reserved + binary.BigEndian.PutUint16(b[8:10], uint16(len(m.data))) + copy(b[messageHeaderLen:], m.data) + + n = messageHeaderLen + len(m.data) + return +} + +func (m *message) Decode(b []byte) (n int, err error) { + if len(b) < messageHeaderLen { + err = ErrShortBuffer + return + } + if binary.BigEndian.Uint32(b[:4]) != magicNumber { + err = ErrInvalidPacket + return + } + m.flags = binary.BigEndian.Uint16(b[4:6]) + length := binary.BigEndian.Uint16(b[8:10]) + if len(b[messageHeaderLen:]) < int(length) { + err = ErrShortBuffer + return + } + m.data = b[messageHeaderLen : messageHeaderLen+length] + + n = messageHeaderLen + int(length) + return +} + type clientConn struct { net.PacketConn id int @@ -50,26 +103,31 @@ func (c *clientConn) ReadFrom(b []byte) (n int, addr net.Addr, err error) { m, err := icmp.ParseMessage(1, (*buf)[:n]) if err != nil { - logger.Default().Error("icmp: parse message %v", err) + // logger.Default().Error("icmp: parse message %v", err) return 0, addr, err } echo, ok := m.Body.(*icmp.Echo) if !ok || m.Type != ipv4.ICMPTypeEchoReply { - logger.Default().Warnf("icmp: invalid type %s (discarded)", m.Type) + // logger.Default().Warnf("icmp: invalid type %s (discarded)", m.Type) continue // discard } if echo.ID != c.id { - logger.Default().Warnf("icmp: id mismatch got %d, should be %d (discarded)", echo.ID, c.id) + // logger.Default().Warnf("icmp: id mismatch got %d, should be %d (discarded)", echo.ID, c.id) continue } - if len(echo.Data) < 4 || - binary.BigEndian.Uint32(echo.Data[:4]) != magicNumber { - logger.Default().Warn("icmp: invalid message (discarded)") + msg := message{} + if _, err := msg.Decode(echo.Data); err != nil { + logger.Default().Warn(err) continue } - n = copy(b, echo.Data[4:]) + + if msg.flags&FlagAck == 0 { + // logger.Default().Warn("icmp: invalid message (discarded)") + continue + } + n = copy(b, msg.data) break } @@ -94,13 +152,18 @@ func (c *clientConn) WriteTo(b []byte, addr net.Addr) (n int, err error) { buf := bufpool.Get(writeBufferSize) defer bufpool.Put(buf) - binary.BigEndian.PutUint32((*buf)[:4], magicNumber) - copy((*buf)[4:], b) + msg := message{ + data: b, + } + nn, err := msg.Encode(*buf) + if err != nil { + return + } echo := icmp.Echo{ ID: c.id, Seq: int(atomic.AddUint32(&c.seq, 1)), - Data: (*buf)[:len(b)+4], + Data: (*buf)[:nn], } m := icmp.Message{ Type: ipv4.ICMPTypeEcho, @@ -139,25 +202,28 @@ func (c *serverConn) ReadFrom(b []byte) (n int, addr net.Addr, err error) { m, err := icmp.ParseMessage(1, (*buf)[:n]) if err != nil { - logger.Default().Error("icmp: parse message %v", err) + // logger.Default().Error("icmp: parse message %v", err) return 0, addr, err } echo, ok := m.Body.(*icmp.Echo) if !ok || m.Type != ipv4.ICMPTypeEcho || echo.ID <= 0 { - logger.Default().Warnf("icmp: invalid type %s (discarded)", m.Type) + // logger.Default().Warnf("icmp: invalid type %s (discarded)", m.Type) continue } atomic.StoreUint32(&c.seqs[uint16(echo.ID-1)], uint32(echo.Seq)) - if len(echo.Data) < 4 || - binary.BigEndian.Uint32(echo.Data[:4]) != magicNumber { - logger.Default().Warn("icmp: invalid message (discarded)") + msg := message{} + if _, err := msg.Decode(echo.Data); err != nil { continue } - n = copy(b, echo.Data[4:]) + if msg.flags&FlagAck > 0 { + continue + } + + n = copy(b, msg.data) if v, ok := addr.(*net.IPAddr); ok { addr = &net.UDPAddr{ @@ -190,13 +256,19 @@ func (c *serverConn) WriteTo(b []byte, addr net.Addr) (n int, err error) { buf := bufpool.Get(writeBufferSize) defer bufpool.Put(buf) - binary.BigEndian.PutUint32((*buf)[:4], magicNumber) - copy((*buf)[4:], b) + msg := message{ + flags: FlagAck, + data: b, + } + nn, err := msg.Encode(*buf) + if err != nil { + return + } echo := icmp.Echo{ ID: id, Seq: int(atomic.LoadUint32(&c.seqs[id-1])), - Data: (*buf)[:len(b)+4], + Data: (*buf)[:nn], } m := icmp.Message{ Type: ipv4.ICMPTypeEchoReply, diff --git a/pkg/listener/icmp/listener.go b/pkg/listener/icmp/listener.go index 7a1a832..a978076 100644 --- a/pkg/listener/icmp/listener.go +++ b/pkg/listener/icmp/listener.go @@ -5,7 +5,7 @@ import ( "net" "github.com/go-gost/gost/pkg/common/metrics" - icmp_pkg "github.com/go-gost/gost/pkg/common/util/icmp" + icmp_pkg "github.com/go-gost/gost/pkg/internal/util/icmp" "github.com/go-gost/gost/pkg/listener" "github.com/go-gost/gost/pkg/logger" md "github.com/go-gost/gost/pkg/metadata"