hyprspace/svc/network.go
2tefan a0d0788b59
Handle packetSize more carefully (#132)
Also move MTU + max packet size to `internal/protocol/network.go`.
 And add tests.
2026-08-27 00:47:40 +02:00

143 lines
3.7 KiB
Go

package svc
import (
"fmt"
"net"
"net/netip"
"github.com/hyprspace/hyprspace/config"
"github.com/hyprspace/hyprspace/internal/protocol"
"github.com/hyprspace/hyprspace/netstack"
hstun "github.com/hyprspace/hyprspace/tun"
"github.com/ipfs/go-log/v2"
"github.com/libp2p/go-libp2p/core/host"
"go.uber.org/zap"
"golang.zx2c4.com/wireguard/tun"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/network/ipv6"
)
const Protocol = "/hyprspace/service/0.0.1"
var logger = log.Logger("hyprspace/svc")
type ServiceNetwork struct {
host host.Host
config *config.Config
self [4]byte
NetworkRange net.IPNet
Tun *tun.Device
netx *netstack.Net
activeAddrs map[[16]byte]struct{}
activePorts map[[16]byte]map[uint16]struct{}
listeners map[[2]byte]Proxy
services map[[2]byte]config.Service
}
func (sn *ServiceNetwork) Register(serviceName string, proxy Proxy) {
svcId := config.MkServiceID(serviceName)
sn.listeners[svcId] = proxy
sn.services[svcId] = sn.config.Services[serviceName]
logger.With(zap.String("name", serviceName), zap.String("id", fmt.Sprintf("%x", svcId[:])), zap.String("description", proxy.Description)).Info("Registered service")
}
func (sn *ServiceNetwork) EnsureListener(addr [16]byte, port uint16) bool {
registerAddr := true
if _, ok := sn.activeAddrs[addr]; ok {
if _, ok := sn.activePorts[addr][port]; ok {
return true
}
registerAddr = false
}
netId := [4]byte(addr[10:14])
svcId := [2]byte(addr[14:16])
var proxy Proxy
if netId == sn.self {
// local service
if s, ok := sn.listeners[svcId]; ok {
proxy = s
} else {
logger.With(zap.ByteString("address", addr[10:16])).Warn("Unknown service")
return false
}
} else if p, ok := sn.config.PeerLookup.ByNetID[netId]; ok {
proxy = RemoteServiceProxy(sn.host, p.ID, svcId)
}
tcpAddr := net.TCPAddr{
IP: net.IP(addr[:]),
Port: int(port),
}
if registerAddr {
logger.Debug(fmt.Sprintf("Registering /ip6/%s", tcpAddr.IP))
sn.netx.AddProtocolAddress(tcpip.ProtocolAddress{
Protocol: ipv6.ProtocolNumber,
AddressWithPrefix: tcpip.AddrFrom16(addr).WithPrefix(),
})
sn.activeAddrs[addr] = struct{}{}
sn.activePorts[addr] = make(map[uint16]struct{})
}
tcpL, err := sn.netx.ListenTCP(&tcpAddr)
sn.activePorts[addr][port] = struct{}{}
if err != nil {
panic(err)
}
go proxy.ServeFunc()(tcpL)
logger.Debug(fmt.Sprintf("Listening on /ip6/%s/tcp/%d", tcpAddr.IP, tcpAddr.Port))
return true
}
func NewServiceNetwork(host host.Host, cfg *config.Config, tunDev *hstun.TUN) ServiceNetwork {
tun, netx, err := netstack.CreateNetTUN(
[]netip.Addr{
netip.AddrFrom16([16]byte([]byte("\xfd\x00hyprspinternal"))),
},
[]netip.Addr{},
protocol.TunnelMTU,
)
if err != nil {
logger.With(err).Fatal("Failed to Create service-network tunnel device")
}
go func() {
sizes := make([]int, 1)
buffer := make([]byte, protocol.MaxPacketSize)
buffers := make([][]byte, 1)
buffers[0] = buffer
for {
count, err := tun.Read(buffers, sizes, 0)
if err != nil {
panic(err)
}
if count == 1 {
_, err := tunDev.Iface.Write(buffers[0])
if err != nil {
panic(err)
}
}
}
}()
logger.Info("Service Network ready")
sn := ServiceNetwork{
host: host,
config: cfg,
self: [4]byte(cfg.BuiltinAddr6[12:16]),
NetworkRange: net.IPNet{
IP: []byte("\xfd\x00hyprspsv\x00\x00\x00\x00\x00\x00"),
Mask: net.CIDRMask(80, 128),
},
Tun: &tun,
netx: netx,
activeAddrs: make(map[[16]byte]struct{}),
activePorts: make(map[[16]byte]map[uint16]struct{}),
listeners: make(map[[2]byte]Proxy),
services: make(map[[2]byte]config.Service),
}
host.SetStreamHandler(Protocol, sn.streamHandler())
return sn
}