fix icmp tunnel

This commit is contained in:
ginuerzh
2022-03-09 18:29:45 +08:00
parent be374b6488
commit 4364190e6d
3 changed files with 93 additions and 21 deletions

View File

@ -8,8 +8,8 @@ import (
"sync" "sync"
"time" "time"
icmp_pkg "github.com/go-gost/gost/pkg/common/util/icmp"
"github.com/go-gost/gost/pkg/dialer" "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" "github.com/go-gost/gost/pkg/logger"
md "github.com/go-gost/gost/pkg/metadata" md "github.com/go-gost/gost/pkg/metadata"
"github.com/go-gost/gost/pkg/registry" "github.com/go-gost/gost/pkg/registry"

View File

@ -20,11 +20,64 @@ const (
magicNumber = 0x474F5354 magicNumber = 0x474F5354
) )
const (
messageHeaderLen = 10
)
const (
FlagAck = 1
)
var ( var (
ErrInvalidPacket = errors.New("icmp: invalid packet") ErrInvalidPacket = errors.New("icmp: invalid packet")
ErrInvalidType = errors.New("icmp: invalid type") 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 { type clientConn struct {
net.PacketConn net.PacketConn
id int 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]) m, err := icmp.ParseMessage(1, (*buf)[:n])
if err != nil { if err != nil {
logger.Default().Error("icmp: parse message %v", err) // logger.Default().Error("icmp: parse message %v", err)
return 0, addr, err return 0, addr, err
} }
echo, ok := m.Body.(*icmp.Echo) echo, ok := m.Body.(*icmp.Echo)
if !ok || m.Type != ipv4.ICMPTypeEchoReply { 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 continue // discard
} }
if echo.ID != c.id { 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 continue
} }
if len(echo.Data) < 4 || msg := message{}
binary.BigEndian.Uint32(echo.Data[:4]) != magicNumber { if _, err := msg.Decode(echo.Data); err != nil {
logger.Default().Warn("icmp: invalid message (discarded)") logger.Default().Warn(err)
continue 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 break
} }
@ -94,13 +152,18 @@ func (c *clientConn) WriteTo(b []byte, addr net.Addr) (n int, err error) {
buf := bufpool.Get(writeBufferSize) buf := bufpool.Get(writeBufferSize)
defer bufpool.Put(buf) defer bufpool.Put(buf)
binary.BigEndian.PutUint32((*buf)[:4], magicNumber) msg := message{
copy((*buf)[4:], b) data: b,
}
nn, err := msg.Encode(*buf)
if err != nil {
return
}
echo := icmp.Echo{ echo := icmp.Echo{
ID: c.id, ID: c.id,
Seq: int(atomic.AddUint32(&c.seq, 1)), Seq: int(atomic.AddUint32(&c.seq, 1)),
Data: (*buf)[:len(b)+4], Data: (*buf)[:nn],
} }
m := icmp.Message{ m := icmp.Message{
Type: ipv4.ICMPTypeEcho, 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]) m, err := icmp.ParseMessage(1, (*buf)[:n])
if err != nil { if err != nil {
logger.Default().Error("icmp: parse message %v", err) // logger.Default().Error("icmp: parse message %v", err)
return 0, addr, err return 0, addr, err
} }
echo, ok := m.Body.(*icmp.Echo) echo, ok := m.Body.(*icmp.Echo)
if !ok || m.Type != ipv4.ICMPTypeEcho || echo.ID <= 0 { 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 continue
} }
atomic.StoreUint32(&c.seqs[uint16(echo.ID-1)], uint32(echo.Seq)) atomic.StoreUint32(&c.seqs[uint16(echo.ID-1)], uint32(echo.Seq))
if len(echo.Data) < 4 || msg := message{}
binary.BigEndian.Uint32(echo.Data[:4]) != magicNumber { if _, err := msg.Decode(echo.Data); err != nil {
logger.Default().Warn("icmp: invalid message (discarded)")
continue 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 { if v, ok := addr.(*net.IPAddr); ok {
addr = &net.UDPAddr{ addr = &net.UDPAddr{
@ -190,13 +256,19 @@ func (c *serverConn) WriteTo(b []byte, addr net.Addr) (n int, err error) {
buf := bufpool.Get(writeBufferSize) buf := bufpool.Get(writeBufferSize)
defer bufpool.Put(buf) defer bufpool.Put(buf)
binary.BigEndian.PutUint32((*buf)[:4], magicNumber) msg := message{
copy((*buf)[4:], b) flags: FlagAck,
data: b,
}
nn, err := msg.Encode(*buf)
if err != nil {
return
}
echo := icmp.Echo{ echo := icmp.Echo{
ID: id, ID: id,
Seq: int(atomic.LoadUint32(&c.seqs[id-1])), Seq: int(atomic.LoadUint32(&c.seqs[id-1])),
Data: (*buf)[:len(b)+4], Data: (*buf)[:nn],
} }
m := icmp.Message{ m := icmp.Message{
Type: ipv4.ICMPTypeEchoReply, Type: ipv4.ICMPTypeEchoReply,

View File

@ -5,7 +5,7 @@ import (
"net" "net"
"github.com/go-gost/gost/pkg/common/metrics" "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/listener"
"github.com/go-gost/gost/pkg/logger" "github.com/go-gost/gost/pkg/logger"
md "github.com/go-gost/gost/pkg/metadata" md "github.com/go-gost/gost/pkg/metadata"