mirror of
https://github.com/fumiama/WireGold.git
synced 2026-06-05 07:50:24 +08:00
feat(p2p): add udplite protocol
This commit is contained in:
27
gold/p2p/udplite/init.go
Normal file
27
gold/p2p/udplite/init.go
Normal file
@@ -0,0 +1,27 @@
|
||||
//go:build !darwin
|
||||
|
||||
package udplite
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/netip"
|
||||
|
||||
"github.com/fumiama/WireGold/gold/p2p"
|
||||
"github.com/fumiama/WireGold/helper"
|
||||
)
|
||||
|
||||
func NewEndpoint(endpoint string, _ ...any) (p2p.EndPoint, error) {
|
||||
addr, err := netip.ParseAddrPort(endpoint)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return (*EndPoint)(net.UDPAddrFromAddrPort(addr)), nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
name := helper.FolderName()
|
||||
_, hasexist := p2p.Register(name, NewEndpoint)
|
||||
if hasexist {
|
||||
panic("network " + name + " has been registered")
|
||||
}
|
||||
}
|
||||
95
gold/p2p/udplite/lite.go
Normal file
95
gold/p2p/udplite/lite.go
Normal file
@@ -0,0 +1,95 @@
|
||||
//go:build !darwin
|
||||
|
||||
package udplite
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"github.com/fumiama/WireGold/gold/head"
|
||||
)
|
||||
|
||||
// https://www.kernel.org/doc/Documentation/networking/udplite.txt
|
||||
const (
|
||||
IPPROTO_UDPLITE = 136
|
||||
SOL_UDPLITE = 136
|
||||
UDPLITE_SEND_CSCOV = 10
|
||||
UDPLITE_RECV_CSCOV = 11
|
||||
)
|
||||
|
||||
type sysListener struct {
|
||||
net.ListenConfig
|
||||
network, address string
|
||||
}
|
||||
|
||||
type sockaddr interface {
|
||||
net.Addr
|
||||
}
|
||||
|
||||
//go:linkname toLocal net.(*UDPAddr).toLocal
|
||||
func toLocal(a *net.UDPAddr, net string) sockaddr
|
||||
|
||||
//go:linkname internetSocket net.internetSocket
|
||||
func internetSocket(ctx context.Context, net string, laddr, raddr sockaddr, sotype, proto int, mode string, ctrlCtxFn func(context.Context, string, string, syscall.RawConn) error) (fd unsafe.Pointer, err error)
|
||||
|
||||
//go:linkname newUDPConn net.newUDPConn
|
||||
func newUDPConn(fd unsafe.Pointer) *net.UDPConn
|
||||
|
||||
var sockaddrinterfaceinstance = toLocal(&net.UDPAddr{}, "")
|
||||
|
||||
func (sl *sysListener) listenUDP(ctx context.Context, laddr *net.UDPAddr) (*net.UDPConn, error) {
|
||||
var ctrlCtxFn func(cxt context.Context, network, address string, c syscall.RawConn) error
|
||||
if sl.ListenConfig.Control != nil {
|
||||
ctrlCtxFn = func(cxt context.Context, network, address string, c syscall.RawConn) error {
|
||||
return sl.ListenConfig.Control(network, address, c)
|
||||
}
|
||||
}
|
||||
sockladdr := sockaddrinterfaceinstance
|
||||
*(**net.UDPAddr)(unsafe.Add(unsafe.Pointer(&sockladdr), unsafe.Sizeof(uintptr(0)))) = laddr
|
||||
sockraddr := sockaddrinterfaceinstance
|
||||
sockladdr = nil
|
||||
fd, err := internetSocket(ctx, sl.network, sockladdr, sockraddr, syscall.SOCK_DGRAM, IPPROTO_UDPLITE, "listen", ctrlCtxFn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newUDPConn(fd), nil
|
||||
}
|
||||
|
||||
func listenUDPLite(network string, laddr *net.UDPAddr) (*net.UDPConn, error) {
|
||||
if laddr == nil {
|
||||
laddr = &net.UDPAddr{}
|
||||
}
|
||||
sl := &sysListener{network: network, address: laddr.String()}
|
||||
conn, err := sl.listenUDP(context.Background(), laddr)
|
||||
if err != nil {
|
||||
var laddrgeneral net.Addr
|
||||
if laddr != nil {
|
||||
laddrgeneral = laddr
|
||||
}
|
||||
return nil, &net.OpError{Op: "listen", Net: network, Source: nil, Addr: laddrgeneral, Err: err}
|
||||
}
|
||||
rc, err := conn.SyscallConn()
|
||||
if err != nil {
|
||||
_ = conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
var errsys error
|
||||
err = rc.Control(func(fd uintptr) {
|
||||
errsys = syscall.SetsockoptInt(int(fd), SOL_UDPLITE, UDPLITE_SEND_CSCOV, head.PacketHeadLen)
|
||||
if errsys != nil {
|
||||
return
|
||||
}
|
||||
errsys = syscall.SetsockoptInt(int(fd), SOL_UDPLITE, UDPLITE_RECV_CSCOV, head.PacketHeadLen)
|
||||
})
|
||||
if err != nil {
|
||||
_ = conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
if errsys != nil {
|
||||
_ = conn.Close()
|
||||
return nil, errsys
|
||||
}
|
||||
return conn, nil
|
||||
}
|
||||
1
gold/p2p/udplite/stub.go
Normal file
1
gold/p2p/udplite/stub.go
Normal file
@@ -0,0 +1 @@
|
||||
package udplite
|
||||
64
gold/p2p/udplite/udp.go
Normal file
64
gold/p2p/udplite/udp.go
Normal file
@@ -0,0 +1,64 @@
|
||||
//go:build !darwin
|
||||
|
||||
package udplite
|
||||
|
||||
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 {
|
||||
if ep == nil || ep2 == nil {
|
||||
return ep == nil && ep2 == nil
|
||||
}
|
||||
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 := listenUDPLite((*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 {
|
||||
ep, _ := NewEndpoint((*net.UDPConn)(conn).LocalAddr().String())
|
||||
return ep
|
||||
}
|
||||
|
||||
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, p2p.ErrEndpointTypeMistatch
|
||||
}
|
||||
return (*net.UDPConn)(conn).WriteTo(b, (*net.UDPAddr)(udpep))
|
||||
}
|
||||
@@ -8,9 +8,10 @@ import (
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
_ "github.com/fumiama/WireGold/gold/p2p/ip" // support ip connection
|
||||
_ "github.com/fumiama/WireGold/gold/p2p/tcp" // support tcp connection
|
||||
_ "github.com/fumiama/WireGold/gold/p2p/udp" // support udp connection
|
||||
_ "github.com/fumiama/WireGold/gold/p2p/ip" // support ip connection
|
||||
_ "github.com/fumiama/WireGold/gold/p2p/tcp" // support tcp connection
|
||||
_ "github.com/fumiama/WireGold/gold/p2p/udp" // support udp connection
|
||||
_ "github.com/fumiama/WireGold/gold/p2p/udplite" // support udplite connection
|
||||
|
||||
"github.com/fumiama/WireGold/gold/head"
|
||||
"github.com/fumiama/WireGold/gold/link"
|
||||
|
||||
@@ -192,6 +192,38 @@ func TestTunnelUDPSmallMTU(t *testing.T) {
|
||||
testTunnel(t, "udp", false, &buf, 1024) // test preshared
|
||||
}
|
||||
|
||||
func TestTunnelUDPLite(t *testing.T) {
|
||||
logrus.SetLevel(logrus.DebugLevel)
|
||||
logrus.SetFormatter(&logFormat{enableColor: false})
|
||||
|
||||
testTunnel(t, "udplite", true, nil, 4096) // test plain text
|
||||
|
||||
testTunnel(t, "udplite", false, nil, 4096) // test normal
|
||||
|
||||
var buf [32]byte
|
||||
_, err := rand.Read(buf[:])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
testTunnel(t, "udplite", false, &buf, 4096) // test preshared
|
||||
}
|
||||
|
||||
func TestTunnelUDPLiteSmallMTU(t *testing.T) {
|
||||
logrus.SetLevel(logrus.DebugLevel)
|
||||
logrus.SetFormatter(&logFormat{enableColor: false})
|
||||
|
||||
testTunnel(t, "udplite", true, nil, 1024) // test plain text
|
||||
|
||||
testTunnel(t, "udplite", false, nil, 1024) // test normal
|
||||
|
||||
var buf [32]byte
|
||||
_, err := rand.Read(buf[:])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
testTunnel(t, "udplite", false, &buf, 1024) // test preshared
|
||||
}
|
||||
|
||||
func TestTunnelTCP(t *testing.T) {
|
||||
logrus.SetLevel(logrus.DebugLevel)
|
||||
logrus.SetFormatter(&logFormat{enableColor: false})
|
||||
|
||||
@@ -9,8 +9,10 @@ import (
|
||||
curve "github.com/fumiama/go-x25519"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
_ "github.com/fumiama/WireGold/gold/p2p/tcp" // support tcp connection
|
||||
_ "github.com/fumiama/WireGold/gold/p2p/udp" // support udp connection
|
||||
_ "github.com/fumiama/WireGold/gold/p2p/ip" // support ip connection
|
||||
_ "github.com/fumiama/WireGold/gold/p2p/tcp" // support tcp connection
|
||||
_ "github.com/fumiama/WireGold/gold/p2p/udp" // support udp connection
|
||||
_ "github.com/fumiama/WireGold/gold/p2p/udplite" // support udplite connection
|
||||
|
||||
"github.com/fumiama/WireGold/config"
|
||||
"github.com/fumiama/WireGold/gold/link"
|
||||
|
||||
Reference in New Issue
Block a user