package node import ( "encoding/json" "flag" "fmt" "io" "log" "net" "net/http" "net/netip" "os" "runtime/debug" "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 ( netName string 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(netName, initURL) return } main(netName, listenIP, uint16(port)) } func mainInit(netName, 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(netName, listenIP string, port uint16) { conf, err := loadPeerConfig(netName) if err != nil { log.Fatalf("Failed to load configuration: %v", err) } port = determinePort(conf.Port, port) iface, err := openInterface(conf.Network, conf.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) } routing := newRoutingTable() w := newConnWriter(conn, conf.PeerIP, routing) r := newConnReader(conn, conf.PeerIP, routing) router := newRouter(netName, conf, routing, w) go nodeConnReader(r, w, iface, router) nodeIFaceReader(w, iface, router) } // ---------------------------------------------------------------------------- func determinePort(confPort, portFromCommandLine uint16) uint16 { if portFromCommandLine != 0 { return portFromCommandLine } if confPort != 0 { return confPort } return 456 } // ---------------------------------------------------------------------------- func nodeConnReader(r *connReader, w *connWriter, iface io.ReadWriteCloser, router *router) { defer panicHandler() var ( remoteAddr netip.AddrPort h header buf = make([]byte, bufferSize) data []byte err error ) for { remoteAddr, h, data = r.Read(buf) if h.Forward != 0 { w.Forward(h.DestIP, data) continue } switch h.Stream { case streamData: if _, err = iface.Write(data); err != nil { log.Printf("Malformed data from peer %d: %v", h.SourceIP, err) } case streamRouting: router.HandlePacket(h.SourceIP, remoteAddr, data) default: log.Printf("Dropping unknown stream: %d", h.Stream) } } } // ---------------------------------------------------------------------------- func nodeIFaceReader(w *connWriter, iface io.ReadWriteCloser, router *router) { var ( buf = make([]byte, bufferSize) packet []byte remoteIP byte err error ) for { packet, remoteIP, err = readNextPacket(iface, buf) if err != nil { log.Fatalf("Failed to read from interface: %v", err) } if remoteIP == w.localIP { continue // Don't write to self. } w.WriteTo(remoteIP, streamData, packet) } }