[relay] Feature/relay integration (#2244)

This update adds new relay integration for NetBird clients. The new relay is based on web sockets and listens on a single port.

- Adds new relay implementation with websocket with single port relaying mechanism
- refactor peer connection logic, allowing upgrade and downgrade from/to P2P connection
- peer connections are faster since it connects first to relay and then upgrades to P2P
- maintains compatibility with old clients by not using the new relay
- updates infrastructure scripts with new relay service
This commit is contained in:
Zoltan Papp
2024-09-08 12:06:14 +02:00
committed by GitHub
parent fcac02a92f
commit 0c039274a4
120 changed files with 9879 additions and 1940 deletions

View File

@@ -0,0 +1,72 @@
//go:build linux || darwin
package tun
import (
"net"
"sync/atomic"
log "github.com/sirupsen/logrus"
)
type Proxy struct {
Device *Device
PConn net.PacketConn
DstAddr net.Addr
shutdownFlag atomic.Bool
}
func (p *Proxy) Start() {
go p.readFromDevice()
go p.readFromConn()
}
func (p *Proxy) Close() {
p.shutdownFlag.Store(true)
}
func (p *Proxy) readFromDevice() {
buf := make([]byte, 1500)
for {
n, err := p.Device.Read(buf)
if err != nil {
if p.shutdownFlag.Load() {
return
}
log.Errorf("failed to read from device: %s", err)
return
}
_, err = p.PConn.WriteTo(buf[:n], p.DstAddr)
if err != nil {
if p.shutdownFlag.Load() {
return
}
log.Errorf("failed to write to conn: %s", err)
return
}
}
}
func (p *Proxy) readFromConn() {
buf := make([]byte, 1500)
for {
n, _, err := p.PConn.ReadFrom(buf)
if err != nil {
if p.shutdownFlag.Load() {
return
}
log.Errorf("failed to read from conn: %s", err)
return
}
_, err = p.Device.Write(buf[:n])
if err != nil {
if p.shutdownFlag.Load() {
return
}
log.Errorf("failed to write to device: %s", err)
return
}
}
}

110
relay/testec2/tun/tun.go Normal file
View File

@@ -0,0 +1,110 @@
//go:build linux || darwin
package tun
import (
"net"
log "github.com/sirupsen/logrus"
"github.com/songgao/water"
"github.com/vishvananda/netlink"
)
type Device struct {
Name string
IP string
PConn net.PacketConn
DstAddr net.Addr
iFace *water.Interface
proxy *Proxy
}
func (d *Device) Up() error {
cfg := water.Config{
DeviceType: water.TUN,
PlatformSpecificParams: water.PlatformSpecificParams{
Name: d.Name,
},
}
iFace, err := water.New(cfg)
if err != nil {
return err
}
d.iFace = iFace
err = d.assignIP()
if err != nil {
return err
}
err = d.bringUp()
if err != nil {
return err
}
d.proxy = &Proxy{
Device: d,
PConn: d.PConn,
DstAddr: d.DstAddr,
}
d.proxy.Start()
return nil
}
func (d *Device) Close() error {
if d.proxy != nil {
d.proxy.Close()
}
if d.iFace != nil {
return d.iFace.Close()
}
return nil
}
func (d *Device) Read(b []byte) (int, error) {
return d.iFace.Read(b)
}
func (d *Device) Write(b []byte) (int, error) {
return d.iFace.Write(b)
}
func (d *Device) assignIP() error {
iface, err := netlink.LinkByName(d.Name)
if err != nil {
log.Errorf("failed to get TUN device: %v", err)
return err
}
ip := net.IPNet{
IP: net.ParseIP(d.IP),
Mask: net.CIDRMask(24, 32),
}
addr := &netlink.Addr{
IPNet: &ip,
}
err = netlink.AddrAdd(iface, addr)
if err != nil {
log.Errorf("failed to add IP address: %v", err)
return err
}
return nil
}
func (d *Device) bringUp() error {
iface, err := netlink.LinkByName(d.Name)
if err != nil {
log.Errorf("failed to get device: %v", err)
return err
}
// Bring the interface up
err = netlink.LinkSetUp(iface)
if err != nil {
log.Errorf("failed to set device up: %v", err)
return err
}
return nil
}