mirror of
https://github.com/fumiama/WireGold.git
synced 2026-06-07 17:00:24 +08:00
feat: split udp protocol to folder p2p
This commit is contained in:
@@ -44,7 +44,6 @@ Mask: 0x1234567890abcdef
|
||||
Peers:
|
||||
-
|
||||
IP: "192.168.233.2"
|
||||
SubNet: 192.168.233.0/24
|
||||
PublicKey: 徯萃嵾爻燸攗窍褃冔蒔犡緇袿屿組待族砇嘀
|
||||
PresharedKey: 瀸敀爅崾嘊嵜紼樴稍毯攣矐訷蟷扛嬋庩崛昀
|
||||
EndPoint: 1.2.3.4:56789
|
||||
@@ -58,7 +57,6 @@ Peers:
|
||||
AllowTrans: true
|
||||
-
|
||||
IP: "192.168.233.3"
|
||||
SubNet: 192.168.233.0/24
|
||||
PublicKey: 牢喨粷詸衭譛浾蘹櫠砙杹蟫瑳叩刋橋経挵蘀
|
||||
PresharedKey: 竅琚喫従痸告烈兇厕趭萨假蔛瀇譄施烸蝫瘀
|
||||
EndPoint: ""
|
||||
|
||||
@@ -8,20 +8,12 @@ import (
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// EndPoint 一个终结点的信息
|
||||
type EndPoint struct {
|
||||
Host string `yaml:"Host"`
|
||||
Port int64 `yaml:"Port"`
|
||||
Poly uint64 `yaml:"Poly"` // Poly 是 port 随机切换算法的生成多项式, 0 为禁用
|
||||
ReconnectSeconds int64 `yaml:"ReconnectSeconds"` // ReconnectSeconds 断开重连间隔, 每次到时即向对端通报并切换到新的端口, 0 为禁用
|
||||
FECMethod string `yaml:"FECMethod"` // FECMethod 可选 1/2 2/3
|
||||
}
|
||||
|
||||
// Config WireGold 配置文件
|
||||
type Config struct {
|
||||
IP string `yaml:"IP"`
|
||||
SubNet string `yaml:"SubNet"`
|
||||
PrivateKey string `yaml:"PrivateKey"`
|
||||
Network string `yaml:"Network"` // Network udp or ws (WIP)
|
||||
EndPoint string `yaml:"EndPoint"`
|
||||
MTU int64 `yaml:"MTU"`
|
||||
SpeedLoop uint16 `yaml:"SpeedLoop"`
|
||||
@@ -32,7 +24,6 @@ type Config struct {
|
||||
// Peer 对端信息
|
||||
type Peer struct {
|
||||
IP string `yaml:"IP"`
|
||||
SubNet string `yaml:"SubNet"`
|
||||
PublicKey string `yaml:"PublicKey"`
|
||||
PresharedKey string `yaml:"PresharedKey"`
|
||||
EndPoint string `yaml:"EndPoint"`
|
||||
|
||||
1
go.mod
1
go.mod
@@ -4,6 +4,7 @@ go 1.20
|
||||
|
||||
require (
|
||||
github.com/FloatTech/ttl v0.0.0-20230307105452-d6f7b2b647d1
|
||||
github.com/RomiChan/syncx v0.0.0-20240418144900-b7402ffdebc7
|
||||
github.com/fumiama/blake2b-simd v0.0.0-20220412110131-4481822068bb
|
||||
github.com/fumiama/go-base16384 v1.7.0
|
||||
github.com/fumiama/go-x25519 v1.0.0
|
||||
|
||||
2
go.sum
2
go.sum
@@ -1,5 +1,7 @@
|
||||
github.com/FloatTech/ttl v0.0.0-20230307105452-d6f7b2b647d1 h1:g4pTnDJUW4VbJ9NvoRfUvdjDrHz/6QhfN/LoIIpICbo=
|
||||
github.com/FloatTech/ttl v0.0.0-20230307105452-d6f7b2b647d1/go.mod h1:fHZFWGquNXuHttu9dUYoKuNbm3dzLETnIOnm1muSfDs=
|
||||
github.com/RomiChan/syncx v0.0.0-20240418144900-b7402ffdebc7 h1:S/ferNiehVjNaBMNNBxUjLtVmP/YWD6Yh79RfPv4ehU=
|
||||
github.com/RomiChan/syncx v0.0.0-20240418144900-b7402ffdebc7/go.mod h1:vD7Ra3Q9onRtojoY5sMCLQ7JBgjUsrXDnDKyFxqpf9w=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package head
|
||||
|
||||
// Notify 是 map[peerip]endpoint
|
||||
type Notify = map[string]string
|
||||
// Notify 是 map[peerip]{network, endpoint}
|
||||
type Notify = map[string][2]string
|
||||
|
||||
// Query 是 peerips 组成的数组
|
||||
type Query = []string
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/fumiama/WireGold/gold/head"
|
||||
"github.com/fumiama/WireGold/gold/p2p"
|
||||
"github.com/fumiama/WireGold/helper"
|
||||
base14 "github.com/fumiama/go-base16384"
|
||||
)
|
||||
@@ -24,7 +25,7 @@ type Link struct {
|
||||
// peer 的虚拟 ip
|
||||
peerip net.IP
|
||||
// peer 的公网 endpoint
|
||||
endpoint *net.UDPAddr
|
||||
endpoint p2p.EndPoint
|
||||
// 本机允许接收/发送的 ip 网段
|
||||
allowedips []*net.IPNet
|
||||
// 连接所用对称加密密钥集
|
||||
|
||||
@@ -5,28 +5,26 @@ import (
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
"net/netip"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/klauspost/compress/zstd"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/fumiama/WireGold/gold/head"
|
||||
"github.com/fumiama/WireGold/gold/p2p"
|
||||
)
|
||||
|
||||
// 监听本机 UDP endpoint
|
||||
func (m *Me) listenudp() (conn *net.UDPConn, err error) {
|
||||
conn, err = net.ListenUDP("udp", net.UDPAddrFromAddrPort(netip.MustParseAddrPort(m.udpep.String())))
|
||||
// 监听本机 endpoint
|
||||
func (m *Me) listen() (conn p2p.Conn, err error) {
|
||||
conn, err = m.ep.Listen()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
m.udpep = conn.LocalAddr()
|
||||
logrus.Infoln("[listen] at", m.udpep)
|
||||
m.ep = conn.LocalAddr()
|
||||
logrus.Infoln("[listen] at", m.ep)
|
||||
go func() {
|
||||
recvtotlcnt := uint64(0)
|
||||
recvloopcnt := uint16(0)
|
||||
@@ -49,14 +47,14 @@ func (m *Me) listenudp() (conn *net.UDPConn, err error) {
|
||||
}
|
||||
logrus.Debugln("[listen] lock index", i)
|
||||
lbf := listenbuff[i*65536 : (i+1)*65536]
|
||||
n, addr, err := conn.ReadFromUDP(lbf)
|
||||
n, addr, err := conn.ReadFromPeer(lbf)
|
||||
if m.loop == nil || errors.Is(err, net.ErrClosed) {
|
||||
logrus.Warnln("[listen] quit listening")
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
logrus.Warnln("[listen] read from udp err, reconnect:", err)
|
||||
conn, err = net.ListenUDP("udp", net.UDPAddrFromAddrPort(netip.MustParseAddrPort(m.udpep.String())))
|
||||
conn, err = m.ep.Listen()
|
||||
if err != nil {
|
||||
logrus.Errorln("[listen] reconnect udp err:", err)
|
||||
return
|
||||
@@ -81,13 +79,13 @@ func (m *Me) listenudp() (conn *net.UDPConn, err error) {
|
||||
i--
|
||||
continue
|
||||
}
|
||||
go m.listenthread(packet, addr, i, hasntfinished[i].Unlock)
|
||||
go m.dispatch(packet, addr, i, hasntfinished[i].Unlock)
|
||||
}
|
||||
}()
|
||||
return
|
||||
}
|
||||
|
||||
func (m *Me) listenthread(packet *head.Packet, addr *net.UDPAddr, index int, finish func()) {
|
||||
func (m *Me) dispatch(packet *head.Packet, addr p2p.EndPoint, index int, finish func()) {
|
||||
defer finish()
|
||||
defer logrus.Debugln("[listen] unlock index", index)
|
||||
r := packet.Len() - len(packet.Data)
|
||||
@@ -103,9 +101,9 @@ func (m *Me) listenthread(packet *head.Packet, addr *net.UDPAddr, index int, fin
|
||||
packet.Put()
|
||||
return
|
||||
}
|
||||
if p.endpoint == nil || p.endpoint.String() != addr.String() {
|
||||
if p.endpoint == nil || !p.endpoint.Euqal(addr) {
|
||||
logrus.Infoln("[listen] @", index, "set endpoint of peer", p.peerip, "to", addr.String())
|
||||
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&p.endpoint)), unsafe.Pointer(addr))
|
||||
p.endpoint = addr
|
||||
}
|
||||
switch {
|
||||
case p.IsToMe(packet.Dst):
|
||||
|
||||
@@ -10,10 +10,12 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/FloatTech/ttl"
|
||||
"github.com/fumiama/WireGold/gold/head"
|
||||
"github.com/fumiama/WireGold/lower"
|
||||
"github.com/fumiama/water/waterutil"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/fumiama/WireGold/gold/head"
|
||||
"github.com/fumiama/WireGold/gold/p2p"
|
||||
"github.com/fumiama/WireGold/lower"
|
||||
)
|
||||
|
||||
// Me 是本机的抽象
|
||||
@@ -27,16 +29,16 @@ type Me struct {
|
||||
me net.IP
|
||||
// 本机子网
|
||||
subnet net.IPNet
|
||||
// 本机 UDP endpoint
|
||||
udpep net.Addr
|
||||
// 本机 endpoint
|
||||
ep p2p.EndPoint
|
||||
// 本机环回 link
|
||||
loop *Link
|
||||
// 本机活跃的所有连接
|
||||
connections map[string]*Link
|
||||
// 读写同步锁
|
||||
connmapmu sync.RWMutex
|
||||
// 本机监听的 udp 连接, 用于向对端直接发送报文
|
||||
udpconn *net.UDPConn
|
||||
// 本机监听的连接端点, 也用于向对端直接发送报文
|
||||
conn p2p.Conn
|
||||
// 本机网卡
|
||||
nic lower.NICIO
|
||||
// 本机路由表
|
||||
@@ -54,6 +56,7 @@ type Me struct {
|
||||
type MyConfig struct {
|
||||
MyIPwithMask string
|
||||
MyEndpoint string
|
||||
Network string
|
||||
PrivateKey *[32]byte
|
||||
NIC lower.NICIO
|
||||
SrcPort, DstPort, MTU, SpeedLoop uint16
|
||||
@@ -64,7 +67,11 @@ type MyConfig struct {
|
||||
func NewMe(cfg *MyConfig) (m Me) {
|
||||
m.privKey = *cfg.PrivateKey
|
||||
var err error
|
||||
m.udpep, err = net.ResolveUDPAddr("udp", cfg.MyEndpoint)
|
||||
nw := cfg.Network
|
||||
if nw == "" {
|
||||
nw = "udp"
|
||||
}
|
||||
m.ep, err = p2p.NewEndPoint(nw, cfg.MyEndpoint)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -74,7 +81,7 @@ func NewMe(cfg *MyConfig) (m Me) {
|
||||
}
|
||||
m.me = ip
|
||||
m.subnet = *cidr
|
||||
m.udpconn, err = m.listenudp()
|
||||
m.conn, err = m.listen()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -125,16 +132,16 @@ func (m *Me) MTU() uint16 {
|
||||
return m.mtu
|
||||
}
|
||||
|
||||
func (m *Me) EndPoint() net.Addr {
|
||||
return m.udpep
|
||||
func (m *Me) EndPoint() p2p.EndPoint {
|
||||
return m.ep
|
||||
}
|
||||
|
||||
func (m *Me) Close() error {
|
||||
m.loop = nil
|
||||
m.connections = nil
|
||||
if m.udpconn != nil {
|
||||
_ = m.udpconn.Close()
|
||||
m.udpconn = nil
|
||||
if m.conn != nil {
|
||||
_ = m.conn.Close()
|
||||
m.conn = nil
|
||||
}
|
||||
m.router = nil
|
||||
if m.recving != nil {
|
||||
|
||||
@@ -2,12 +2,12 @@ package link
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/fumiama/WireGold/gold/head"
|
||||
"github.com/fumiama/WireGold/gold/p2p"
|
||||
"github.com/fumiama/WireGold/helper"
|
||||
)
|
||||
|
||||
@@ -44,11 +44,11 @@ func (l *Link) onNotify(packet []byte) {
|
||||
// ---- 遍历 Notify,注册对方的 endpoint 到
|
||||
// ---- connections,注意使用读写锁connmapmu
|
||||
for peer, ep := range notify {
|
||||
addr, err := net.ResolveUDPAddr("udp", ep)
|
||||
addr, err := p2p.NewEndPoint(ep[0], ep[1])
|
||||
if err == nil {
|
||||
p, ok := l.me.IsInPeer(peer)
|
||||
if ok {
|
||||
if p.endpoint.String() != ep {
|
||||
if !p.endpoint.Euqal(addr) {
|
||||
p.endpoint = addr
|
||||
logrus.Infoln("[nat] notify set ep of peer", peer, "to", ep)
|
||||
}
|
||||
@@ -80,7 +80,10 @@ func (l *Link) onQuery(packet []byte) {
|
||||
for _, p := range peers {
|
||||
lnk, ok := l.me.IsInPeer(p)
|
||||
if ok {
|
||||
notify[p] = lnk.endpoint.String()
|
||||
notify[p] = [2]string{
|
||||
lnk.endpoint.Network(),
|
||||
lnk.endpoint.String(),
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(notify) > 0 {
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/fumiama/WireGold/gold/head"
|
||||
"github.com/fumiama/WireGold/gold/p2p"
|
||||
curve "github.com/fumiama/go-x25519"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/crypto/chacha20poly1305"
|
||||
@@ -72,7 +73,7 @@ func (m *Me) AddPeer(cfg *PeerConfig) (l *Link) {
|
||||
}
|
||||
}
|
||||
if cfg.EndPoint != "" {
|
||||
e, err := net.ResolveUDPAddr("udp", cfg.EndPoint)
|
||||
e, err := p2p.NewEndPoint(m.ep.Network(), cfg.EndPoint)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
@@ -103,11 +103,11 @@ func (l *Link) write(p *head.Packet, teatype uint8, additional uint16, datasz ui
|
||||
bound = len(d)
|
||||
endl = "."
|
||||
}
|
||||
logrus.Debugln("[send] write", len(d), "bytes data from ep", l.me.udpconn.LocalAddr(), "to", peerep, "offset:", fmt.Sprintf("%04x", offset))
|
||||
logrus.Debugln("[send] write", len(d), "bytes data from ep", l.me.conn.LocalAddr(), "to", peerep, "offset:", fmt.Sprintf("%04x", offset))
|
||||
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)
|
||||
n, err = l.me.udpconn.WriteToUDP(d, peerep)
|
||||
n, err = l.me.conn.WriteToPeer(d, peerep)
|
||||
cl()
|
||||
return
|
||||
}
|
||||
|
||||
40
gold/p2p/define.go
Normal file
40
gold/p2p/define.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package p2p
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/RomiChan/syncx"
|
||||
)
|
||||
|
||||
type Initializer func(endpoint string, configs ...any) EndPoint
|
||||
|
||||
var factory syncx.Map[string, Initializer]
|
||||
|
||||
func Register(network string, initializer Initializer) (actual Initializer, hasexist bool) {
|
||||
return factory.LoadOrStore(network, initializer)
|
||||
}
|
||||
|
||||
type EndPoint interface {
|
||||
fmt.Stringer
|
||||
Network() string
|
||||
Euqal(EndPoint) bool
|
||||
Listen() (Conn, error)
|
||||
}
|
||||
|
||||
func NewEndPoint(network, endpoint string, configs ...any) (EndPoint, error) {
|
||||
initializer, ok := factory.Load(network)
|
||||
if !ok {
|
||||
return nil, errors.New("network " + network + " not found")
|
||||
}
|
||||
return initializer(endpoint, configs...), nil
|
||||
}
|
||||
|
||||
type Conn interface {
|
||||
io.Closer
|
||||
fmt.Stringer // basically, the local address string
|
||||
LocalAddr() EndPoint
|
||||
ReadFromPeer([]byte) (int, EndPoint, error)
|
||||
WriteToPeer([]byte, EndPoint) (int, error)
|
||||
}
|
||||
26
gold/p2p/udp/init.go
Normal file
26
gold/p2p/udp/init.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package udp
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"net/netip"
|
||||
|
||||
"github.com/fumiama/WireGold/gold/p2p"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrEndpointTypeMistatch = errors.New("endpoint type mismatch")
|
||||
)
|
||||
|
||||
func NewEndpoint(endpoint string, _ ...any) p2p.EndPoint {
|
||||
return (*EndPoint)(net.UDPAddrFromAddrPort(
|
||||
netip.MustParseAddrPort(endpoint),
|
||||
))
|
||||
}
|
||||
|
||||
func init() {
|
||||
_, hasexist := p2p.Register("udp", NewEndpoint)
|
||||
if hasexist {
|
||||
panic("network udp has been registered")
|
||||
}
|
||||
}
|
||||
58
gold/p2p/udp/udp.go
Normal file
58
gold/p2p/udp/udp.go
Normal file
@@ -0,0 +1,58 @@
|
||||
package udp
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/fumiama/WireGold/gold/p2p"
|
||||
)
|
||||
|
||||
type EndPoint net.UDPAddr
|
||||
|
||||
func (ep *EndPoint) String() string {
|
||||
return (*net.UDPAddr)(ep).String()
|
||||
}
|
||||
|
||||
func (ep *EndPoint) Network() string {
|
||||
return (*net.UDPAddr)(ep).Network()
|
||||
}
|
||||
|
||||
func (ep *EndPoint) Euqal(ep2 p2p.EndPoint) bool {
|
||||
udpep2, ok := ep2.(*EndPoint)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
udpep1 := ep
|
||||
return udpep1.IP.Equal(udpep2.IP) && udpep1.Port == udpep2.Port && udpep1.Zone == udpep2.Zone
|
||||
}
|
||||
|
||||
func (ep *EndPoint) Listen() (p2p.Conn, error) {
|
||||
conn, err := net.ListenUDP((*net.UDPAddr)(ep).Network(), (*net.UDPAddr)(ep))
|
||||
return (*Conn)(conn), err
|
||||
}
|
||||
|
||||
type Conn net.UDPConn
|
||||
|
||||
func (conn *Conn) Close() error {
|
||||
return (*net.UDPConn)(conn).Close()
|
||||
}
|
||||
|
||||
func (conn *Conn) String() string {
|
||||
return (*net.UDPConn)(conn).LocalAddr().String()
|
||||
}
|
||||
|
||||
func (conn *Conn) LocalAddr() p2p.EndPoint {
|
||||
return NewEndpoint((*net.UDPConn)(conn).LocalAddr().String())
|
||||
}
|
||||
|
||||
func (conn *Conn) ReadFromPeer(b []byte) (int, p2p.EndPoint, error) {
|
||||
n, addr, err := (*net.UDPConn)(conn).ReadFromUDP(b)
|
||||
return n, (*EndPoint)(addr), err
|
||||
}
|
||||
|
||||
func (conn *Conn) WriteToPeer(b []byte, ep p2p.EndPoint) (int, error) {
|
||||
udpep, ok := ep.(*EndPoint)
|
||||
if !ok {
|
||||
return 0, ErrEndpointTypeMistatch
|
||||
}
|
||||
return (*net.UDPConn)(conn).WriteTo(b, (*net.UDPAddr)(udpep))
|
||||
}
|
||||
@@ -8,6 +8,8 @@ import (
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
_ "github.com/fumiama/WireGold/gold/p2p/udp" // support udp connection
|
||||
|
||||
"github.com/fumiama/WireGold/gold/head"
|
||||
"github.com/fumiama/WireGold/gold/link"
|
||||
)
|
||||
|
||||
@@ -9,6 +9,8 @@ import (
|
||||
curve "github.com/fumiama/go-x25519"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
_ "github.com/fumiama/WireGold/gold/p2p/udp" // support udp connection
|
||||
|
||||
"github.com/fumiama/WireGold/config"
|
||||
"github.com/fumiama/WireGold/gold/link"
|
||||
"github.com/fumiama/WireGold/helper"
|
||||
@@ -93,6 +95,7 @@ func (wg *WG) init(srcport, dstport uint16) {
|
||||
wg.me = link.NewMe(&link.MyConfig{
|
||||
MyIPwithMask: wg.c.IP + "/32",
|
||||
MyEndpoint: wg.c.EndPoint,
|
||||
Network: wg.c.Network,
|
||||
PrivateKey: &wg.key,
|
||||
NIC: lower.NewNIC(wg.c.IP, wg.c.SubNet, strconv.FormatInt(wg.c.MTU, 10), cidrs...),
|
||||
SrcPort: srcport,
|
||||
|
||||
Reference in New Issue
Block a user