293 lines
6.1 KiB
Go
293 lines
6.1 KiB
Go
package node
|
|
|
|
import (
|
|
"encoding/json"
|
|
"flag"
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"net"
|
|
"net/http"
|
|
"net/netip"
|
|
"os"
|
|
"runtime/debug"
|
|
"sync/atomic"
|
|
"time"
|
|
"vppn/m"
|
|
)
|
|
|
|
func panicHandler() {
|
|
if r := recover(); r != nil {
|
|
log.Fatalf("\n %v\n\nstacktrace from panic: %s\n", r, string(debug.Stack()))
|
|
}
|
|
}
|
|
|
|
func Main() {
|
|
defer panicHandler()
|
|
|
|
var (
|
|
initURL string
|
|
listenIP string
|
|
port int
|
|
)
|
|
|
|
flag.StringVar(&netName, "name", "", "[REQUIRED] The network name.")
|
|
flag.StringVar(&initURL, "init-url", "", "Initializes peer from the hub URL.")
|
|
flag.StringVar(&listenIP, "listen-ip", "", "IP address to listen on.")
|
|
flag.IntVar(&port, "port", 0, "Port to listen on.")
|
|
flag.Parse()
|
|
|
|
if netName == "" {
|
|
flag.Usage()
|
|
os.Exit(1)
|
|
}
|
|
|
|
if initURL != "" {
|
|
mainInit(initURL)
|
|
return
|
|
}
|
|
|
|
main(listenIP, uint16(port))
|
|
}
|
|
|
|
func mainInit(initURL string) {
|
|
if _, err := loadPeerConfig(netName); err == nil {
|
|
log.Fatalf("Network is already initialized.")
|
|
}
|
|
|
|
resp, err := http.Get(initURL)
|
|
if err != nil {
|
|
log.Fatalf("Failed to fetch data from hub: %v", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
data, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
log.Fatalf("Failed to read response body: %v", err)
|
|
}
|
|
|
|
peerConfig := m.PeerConfig{}
|
|
if err := json.Unmarshal(data, &peerConfig); err != nil {
|
|
log.Fatalf("Failed to parse configuration: %v", err)
|
|
}
|
|
|
|
if err := storePeerConfig(netName, peerConfig); err != nil {
|
|
log.Fatalf("Failed to store configuration: %v", err)
|
|
}
|
|
|
|
log.Print("Initialization successful.")
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
func main(listenIP string, port uint16) {
|
|
config, err := loadPeerConfig(netName)
|
|
if err != nil {
|
|
log.Fatalf("Failed to load configuration: %v", err)
|
|
}
|
|
|
|
port = determinePort(config.Port, port)
|
|
|
|
iface, err := openInterface(config.Network, config.PeerIP, netName)
|
|
if err != nil {
|
|
log.Fatalf("Failed to open interface: %v", err)
|
|
}
|
|
|
|
myAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", listenIP, port))
|
|
if err != nil {
|
|
log.Fatalf("Failed to resolve UDP address: %v", err)
|
|
}
|
|
|
|
conn, err := net.ListenUDP("udp", myAddr)
|
|
if err != nil {
|
|
log.Fatalf("Failed to open UDP port: %v", err)
|
|
}
|
|
|
|
// Intialize globals.
|
|
localIP = config.PeerIP
|
|
localPub = addrIsValid(config.PublicIP)
|
|
privateKey = config.PrivKey
|
|
|
|
_iface = newIFWriter(iface)
|
|
_conn = newConnWriter(conn)
|
|
|
|
for i := range 256 {
|
|
sendCounters[i] = uint64(time.Now().Unix()<<30) + 1
|
|
dupChecks[i] = newDupCheck(0)
|
|
controlPackets[i] = make(chan controlPacket, 256)
|
|
peerUpdates[i] = make(chan *m.Peer)
|
|
routingTable[i] = &atomic.Pointer[peerRoute]{}
|
|
route := peerRoute{IP: byte(i)}
|
|
routingTable[i].Store(&route)
|
|
}
|
|
|
|
// Start supervisors.
|
|
for i := range 256 {
|
|
go newPeerSupervisor(i).Run()
|
|
}
|
|
|
|
// --------------------
|
|
|
|
go newHubPoller(config).Run()
|
|
go readFromConn(conn)
|
|
readFromIFace(iface)
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
func determinePort(confPort, portFromCommandLine uint16) uint16 {
|
|
if portFromCommandLine != 0 {
|
|
return portFromCommandLine
|
|
}
|
|
if confPort != 0 {
|
|
return confPort
|
|
}
|
|
return 456
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
func readFromConn(conn *net.UDPConn) {
|
|
|
|
defer panicHandler()
|
|
|
|
var (
|
|
remoteAddr netip.AddrPort
|
|
n int
|
|
err error
|
|
buf = make([]byte, bufferSize)
|
|
decBuf = make([]byte, bufferSize)
|
|
data []byte
|
|
h header
|
|
)
|
|
|
|
for {
|
|
n, remoteAddr, err = conn.ReadFromUDPAddrPort(buf[:bufferSize])
|
|
if err != nil {
|
|
log.Fatalf("Failed to read from UDP port: %v", err)
|
|
}
|
|
|
|
data = buf[:n]
|
|
|
|
if n < headerSize {
|
|
continue // Packet it soo short.
|
|
}
|
|
|
|
h.Parse(data)
|
|
switch h.StreamID {
|
|
case controlStreamID:
|
|
handleControlPacket(remoteAddr, h, data, decBuf)
|
|
|
|
case dataStreamID:
|
|
handleDataPacket(h, data, decBuf)
|
|
|
|
default:
|
|
log.Printf("Unknown stream ID: %d", h.StreamID)
|
|
}
|
|
}
|
|
}
|
|
|
|
func handleControlPacket(addr netip.AddrPort, h header, data, decBuf []byte) {
|
|
route := routingTable[h.SourceIP].Load()
|
|
if route.ControlCipher == nil {
|
|
log.Printf("Not connected (control).")
|
|
return
|
|
}
|
|
|
|
if h.DestIP != localIP {
|
|
log.Printf("Incorrect destination IP on control packet: %d != %d", h.DestIP, localIP)
|
|
return
|
|
}
|
|
|
|
out, ok := route.ControlCipher.Decrypt(data, decBuf)
|
|
if !ok {
|
|
log.Printf("Failed to decrypt control packet.")
|
|
return
|
|
}
|
|
|
|
if len(out) == 0 {
|
|
log.Printf("Empty control packet from: %d", h.SourceIP)
|
|
return
|
|
}
|
|
|
|
if dupChecks[h.SourceIP].IsDup(h.Counter) {
|
|
log.Printf("[%03d] Duplicate control packet: %d", h.SourceIP, h.Counter)
|
|
return
|
|
}
|
|
|
|
pkt := controlPacket{
|
|
SrcIP: h.SourceIP,
|
|
RemoteAddr: addr,
|
|
}
|
|
|
|
if err := pkt.ParsePayload(out); err != nil {
|
|
log.Printf("Failed to parse control packet: %v", err)
|
|
return
|
|
}
|
|
|
|
select {
|
|
case controlPackets[h.SourceIP] <- pkt:
|
|
default:
|
|
log.Printf("Dropping control packet.")
|
|
}
|
|
}
|
|
|
|
func handleDataPacket(h header, data []byte, decBuf []byte) {
|
|
route := routingTable[h.SourceIP].Load()
|
|
if !route.Up {
|
|
log.Printf("Not connected (recv).")
|
|
return
|
|
}
|
|
|
|
dec, ok := route.DataCipher.Decrypt(data, decBuf)
|
|
if !ok {
|
|
log.Printf("Failed to decrypt data packet.")
|
|
return
|
|
}
|
|
|
|
if dupChecks[h.SourceIP].IsDup(h.Counter) {
|
|
log.Printf("[%03d] Duplicate data packet: %d", h.SourceIP, h.Counter)
|
|
return
|
|
}
|
|
|
|
if h.DestIP == localIP {
|
|
_iface.Write(dec)
|
|
return
|
|
}
|
|
|
|
destRoute := routingTable[h.DestIP].Load()
|
|
if !destRoute.Up || destRoute.RelayIP != 0 {
|
|
log.Printf("Not connected (relay)")
|
|
return
|
|
}
|
|
|
|
_conn.WriteTo(dec, destRoute.RemoteAddr)
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
func readFromIFace(iface io.ReadWriteCloser) {
|
|
var (
|
|
packet = make([]byte, bufferSize)
|
|
buf1 = make([]byte, bufferSize)
|
|
buf2 = make([]byte, bufferSize)
|
|
remoteIP byte
|
|
err error
|
|
)
|
|
|
|
for {
|
|
packet, remoteIP, err = readNextPacket(iface, packet)
|
|
if err != nil {
|
|
log.Fatalf("Failed to read from interface: %v", err)
|
|
}
|
|
|
|
route := routingTable[remoteIP].Load()
|
|
if !route.Up {
|
|
log.Printf("Route not connected: %d", remoteIP)
|
|
continue
|
|
}
|
|
|
|
_sendDataPacket(route, packet, buf1, buf2)
|
|
}
|
|
}
|