From dd51f9f26f7afe189243d4d59362b3ec12e1832f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=BA=90=E6=96=87=E9=9B=A8?= <41315874+fumiama@users.noreply.github.com> Date: Wed, 31 Jul 2024 15:21:02 +0800 Subject: [PATCH] feat: add param `DoublePacket` --- config/cfg.go | 1 + gold/head/packet.go | 14 +++++++------- gold/link/crypto.go | 13 +++++++++---- gold/link/link.go | 2 ++ gold/link/peer.go | 2 ++ gold/link/recv.go | 2 ++ gold/link/send.go | 22 ++++++++++++++++++---- upper/services/tunnel/tunnel_test.go | 1 + upper/services/wg/wg.go | 1 + 9 files changed, 43 insertions(+), 15 deletions(-) diff --git a/config/cfg.go b/config/cfg.go index dfac4ae..8aabe51 100644 --- a/config/cfg.go +++ b/config/cfg.go @@ -33,6 +33,7 @@ type Peer struct { QuerySeconds int64 `yaml:"QuerySeconds"` AllowTrans bool `yaml:"AllowTrans"` UseZstd bool `yaml:"UseZstd"` + DoublePacket bool `yaml:"DoublePacket"` MTU int64 `yaml:"MTU"` MTURandomRange int64 `yaml:"MTURandomRange"` } diff --git a/gold/head/packet.go b/gold/head/packet.go index 7557e29..a7cd826 100644 --- a/gold/head/packet.go +++ b/gold/head/packet.go @@ -155,14 +155,15 @@ func (p *Packet) Unmarshal(data []byte) (complete bool, err error) { return } +// DecreaseAndGetTTL TTL 自减后返回 +func (p *Packet) DecreaseAndGetTTL() uint8 { + p.TTL-- + return p.TTL +} + // Marshal 将自身数据编码为 []byte // offset 必须为 8 的倍数,表示偏移的 8 位 func (p *Packet) Marshal(src net.IP, teatype uint8, additional uint16, datasz uint32, offset uint16, dontfrag, hasmore bool) ([]byte, func()) { - p.TTL-- - if p.TTL == 0 { - return nil, nil - } - if src != nil { p.Src = src p.idxdatsz = (uint32(teatype) << 27) | (uint32(additional&0x07ff) << 16) | datasz&0xffff @@ -175,14 +176,13 @@ func (p *Packet) Marshal(src net.IP, teatype uint8, additional uint16, datasz ui if hasmore { offset |= 0x2000 } - p.Flags = PacketFlags(offset) return helper.OpenWriterF(func(w *helper.Writer) { w.WriteUInt32(p.idxdatsz) w.WriteUInt16((uint16(p.TTL) << 8) | uint16(p.Proto)) w.WriteUInt16(p.SrcPort) w.WriteUInt16(p.DstPort) - w.WriteUInt16(uint16(p.Flags)) + w.WriteUInt16(uint16(PacketFlags(offset))) w.Write(p.Src.To4()) w.Write(p.Dst.To4()) w.Write(p.Hash[:]) diff --git a/gold/link/crypto.go b/gold/link/crypto.go index a393397..1912240 100644 --- a/gold/link/crypto.go +++ b/gold/link/crypto.go @@ -125,25 +125,30 @@ func (m *Me) xorenc(data []byte) []byte { batchsz := len(data) / 8 remain := len(data) % 8 sum := m.mask + newdat := helper.MakeBytes(len(data) + 8) + _, _ = rand.Read(newdat[:8]) if remain > 0 { var buf [8]byte p := batchsz * 8 copy(buf[:], data[p:]) sum ^= binary.LittleEndian.Uint64(buf[:]) binary.LittleEndian.PutUint64(buf[:], sum) - copy(data[p:], buf[:]) + copy(newdat[8+p:], buf[:]) } for i := batchsz - 1; i >= 0; i-- { a := i * 8 b := (i + 1) * 8 sum ^= binary.LittleEndian.Uint64(data[a:b]) - binary.LittleEndian.PutUint64(data[a:b], sum) + binary.LittleEndian.PutUint64(newdat[a+8:b+8], sum) } - return data + return newdat } // xordec 按 8 字节, 以初始 m.mask 循环异或解码 data func (m *Me) xordec(data []byte) []byte { + if len(data) <= 8 { + return nil + } batchsz := len(data) / 8 remain := len(data) % 8 this := uint64(0) @@ -173,5 +178,5 @@ func (m *Me) xordec(data []byte) []byte { } else { binary.LittleEndian.PutUint64(data[len(data)-8:], next^m.mask) } - return data + return data[8:] } diff --git a/gold/link/link.go b/gold/link/link.go index 0a53aff..3692562 100644 --- a/gold/link/link.go +++ b/gold/link/link.go @@ -44,6 +44,8 @@ type Link struct { allowtrans bool // 是否对数据进行 zstd 压缩 usezstd bool + // 是否采用双倍发包对抗强丢包 + doublepacket bool // udp 数据包的最大大小 mtu uint16 // 随机放缩 mtu 范围 (只减不增) diff --git a/gold/link/peer.go b/gold/link/peer.go index 30ea813..aae95df 100644 --- a/gold/link/peer.go +++ b/gold/link/peer.go @@ -22,6 +22,7 @@ type PeerConfig struct { MTURandomRange uint16 AllowTrans, NoPipe bool UseZstd bool + DoublePacket bool } // AddPeer 添加一个 peer @@ -41,6 +42,7 @@ func (m *Me) AddPeer(cfg *PeerConfig) (l *Link) { rawep: cfg.EndPoint, allowtrans: cfg.AllowTrans, usezstd: cfg.UseZstd, + doublepacket: cfg.DoublePacket, me: m, mtu: cfg.MTU, mturandomrange: cfg.MTURandomRange, diff --git a/gold/link/recv.go b/gold/link/recv.go index c19ee26..52ee00e 100644 --- a/gold/link/recv.go +++ b/gold/link/recv.go @@ -34,6 +34,7 @@ func (m *Me) wait(data []byte) *head.Packet { return nil } crc := binary.LittleEndian.Uint64(data[52:head.PacketHeadLen]) + logrus.Debugf("[recv] packet crc %016x", crc) if m.recved.Get(crc) { // 是重放攻击 logrus.Warnln("[recv] ignore duplicated crc packet", strconv.FormatUint(crc, 16)) return nil @@ -78,5 +79,6 @@ func (m *Me) wait(data []byte) *head.Packet { return nil } m.recving.Set(hsh, h) + m.recved.Set(crc, true) return nil } diff --git a/gold/link/send.go b/gold/link/send.go index 9b33f09..c76fbc2 100644 --- a/gold/link/send.go +++ b/gold/link/send.go @@ -7,6 +7,7 @@ import ( "fmt" "io" "math/rand" + "time" "github.com/fumiama/WireGold/gold/head" "github.com/fumiama/WireGold/helper" @@ -88,8 +89,23 @@ func (l *Link) encrypt(p *head.Packet, sndcnt uint16, teatype uint8) { logrus.Debugln("[send] data len after xchacha20:", p.BodyLen(), "addt:", sndcnt) } -// write 向 peer 发一个包 +// write 向 peer 发包 func (l *Link) write(p *head.Packet, teatype uint8, additional uint16, datasz uint32, offset uint16, istransfer, hasmore bool) (int, error) { + if p.DecreaseAndGetTTL() <= 0 { + return 0, ErrTTL + } + if l.doublepacket { + cpp := p.Copy() + time.AfterFunc(time.Millisecond*(10+time.Duration(rand.Intn(10))), func() { + defer cpp.Put() + _, _ = l.writeonce(cpp, teatype, additional, datasz, offset, istransfer, hasmore) + }) + } + return l.writeonce(p, teatype, additional, datasz, offset, istransfer, hasmore) +} + +// write 向 peer 发一个包 +func (l *Link) writeonce(p *head.Packet, teatype uint8, additional uint16, datasz uint32, offset uint16, istransfer, hasmore bool) (int, error) { peerep := l.endpoint if peerep == nil { return 0, errors.New("nil endpoint of " + p.Dst.String()) @@ -103,9 +119,6 @@ func (l *Link) write(p *head.Packet, teatype uint8, additional uint16, datasz ui } else { d, cl = p.Marshal(l.me.me, teatype, additional, datasz, offset, false, hasmore) } - if d == nil { - return 0, ErrTTL - } defer cl() bound := 64 @@ -118,5 +131,6 @@ func (l *Link) write(p *head.Packet, teatype uint8, additional uint16, datasz ui logrus.Debugln("[send] data bytes", hex.EncodeToString(d[:bound]), endl) d = l.me.xorenc(d) logrus.Debugln("[send] data xored", hex.EncodeToString(d[:bound]), endl) + defer helper.PutBytes(d) return l.me.conn.WriteToPeer(d, peerep) } diff --git a/upper/services/tunnel/tunnel_test.go b/upper/services/tunnel/tunnel_test.go index 9fb415d..e5742ef 100644 --- a/upper/services/tunnel/tunnel_test.go +++ b/upper/services/tunnel/tunnel_test.go @@ -81,6 +81,7 @@ func testTunnel(t *testing.T, nw string, isplain bool, pshk *[32]byte, mtu uint1 MTU: mtu, MTURandomRange: mtu / 2, UseZstd: true, + DoublePacket: true, }) p.AddPeer(&link.PeerConfig{ PeerIP: "192.168.1.2", diff --git a/upper/services/wg/wg.go b/upper/services/wg/wg.go index deffc18..1cf81df 100644 --- a/upper/services/wg/wg.go +++ b/upper/services/wg/wg.go @@ -154,6 +154,7 @@ func (wg *WG) init(srcport, dstport uint16) { AllowTrans: peer.AllowTrans, NoPipe: true, UseZstd: peer.UseZstd, + DoublePacket: peer.DoublePacket, }) } }