diff --git a/aestests/aes_test.go b/aestests/aes_test.go deleted file mode 100644 index 1d284eb..0000000 --- a/aestests/aes_test.go +++ /dev/null @@ -1,79 +0,0 @@ -package aestests - -import ( - "crypto/aes" - "crypto/cipher" - "crypto/rand" - "log" - "testing" -) - -func must(err error) { - if err != nil { - panic(err) - } -} - -func TestAES(t *testing.T) { - key := make([]byte, 32) - rand.Read(key) - - block, err := aes.NewCipher(key) - must(err) - - aesgcm, err := cipher.NewGCM(block) - must(err) - - log.Print(aesgcm.NonceSize()) - log.Print(aesgcm.Overhead()) -} - -func BenchmarkSeal(b *testing.B) { - key := make([]byte, 32) - rand.Read(key) - - block, err := aes.NewCipher(key) - must(err) - - cryptor, err := cipher.NewGCM(block) - must(err) - - nonce := make([]byte, 12) - rand.Read(nonce) - - data := make([]byte, 1400) - rand.Read(data) - - out := make([]byte, 1500) - b.ResetTimer() - for i := 0; i < b.N; i++ { - out = cryptor.Seal(out[:0], nonce, data, nil) - } -} - -func BenchmarkOpen(b *testing.B) { - key := make([]byte, 32) - rand.Read(key) - - block, err := aes.NewCipher(key) - must(err) - - cryptor, err := cipher.NewGCM(block) - must(err) - - nonce := make([]byte, 12) - rand.Read(nonce) - - data := make([]byte, 1400) - rand.Read(data) - - sealed := make([]byte, 1500) - sealed = cryptor.Seal(sealed[:0], nonce, data, nil) - - dec := make([]byte, 1500) - - b.ResetTimer() - for i := 0; i < b.N; i++ { - dec, err = cryptor.Open(dec[:0], nonce, sealed, nil) - } -} diff --git a/hub/api/api.go b/hub/api/api.go index 8870a85..ec8d77b 100644 --- a/hub/api/api.go +++ b/hub/api/api.go @@ -24,7 +24,6 @@ var migrations embed.FS type API struct { db *sql.DB lock sync.Mutex - peerIntents map[string]PeerCreateArgs initIntents map[string]byte // Map from intent key to peer IP } @@ -40,7 +39,6 @@ func New(dbPath string) (*API, error) { a := &API{ db: sqlDB, - peerIntents: map[string]PeerCreateArgs{}, initIntents: map[string]byte{}, } @@ -153,34 +151,6 @@ func (a *API) Peer_CreateNew(p *Peer) error { return db.Peer_Insert(a.db, p) } -// TODO: Remove -type PeerCreateArgs struct { - Name string - PublicIP []byte - Port uint16 - Relay bool -} - -// TODO: Remove -// Create the intention to add a peer. The returned code is used to complete -// the peer creation. The code is valid for 5 minutes. -func (a *API) Peer_CreateIntent(args PeerCreateArgs) string { - a.lock.Lock() - defer a.lock.Unlock() - - code := idgen.NewToken() - a.peerIntents[code] = args - - go func() { - time.Sleep(5 * time.Minute) - a.lock.Lock() - defer a.lock.Unlock() - delete(a.peerIntents, code) - }() - - return code -} - // Create the intention to initialize a peer. The returned code is used to // complete the peer initialization. The code is valid for 5 minutes. func (a *API) Peer_CreateInitIntent(peerIP byte) string { @@ -252,79 +222,6 @@ func (a *API) Peer_Init(initCode string) (*m.PeerConfig, error) { }, nil } -// TODO: Remove -func (a *API) Peer_Create(creationCode string) (*m.PeerConfig, error) { - a.lock.Lock() - defer a.lock.Unlock() - - args, ok := a.peerIntents[creationCode] - if !ok { - return nil, ErrNotAuthorized - } - - delete(a.peerIntents, creationCode) - - encPubKey, encPrivKey, err := box.GenerateKey(rand.Reader) - if err != nil { - return nil, err - } - - signPubKey, signPrivKey, err := sign.GenerateKey(rand.Reader) - if err != nil { - return nil, err - } - - // Get peer IP. - peerIP := byte(0) - - for i := byte(1); i < 255; i++ { - exists, err := db.Peer_Exists(a.db, i) - if err != nil { - return nil, err - } - if !exists { - peerIP = i - break - } - } - - if peerIP == 0 { - return nil, ErrNoIPAvailable - } - - peer := &Peer{ - PeerIP: peerIP, - Version: idgen.NextID(0), - APIKey: idgen.NewToken(), - Name: args.Name, - PublicIP: args.PublicIP, - Port: args.Port, - Relay: args.Relay, - PubKey: encPubKey[:], - PubSignKey: signPubKey[:], - } - - if err := db.Peer_Insert(a.db, peer); err != nil { - return nil, err - } - - conf := a.Config_Get() - - return &m.PeerConfig{ - PeerIP: peer.PeerIP, - HubAddress: conf.HubAddress, - APIKey: peer.APIKey, - Network: conf.VPNNetwork, - PublicIP: peer.PublicIP, - Port: peer.Port, - Relay: peer.Relay, - PubKey: encPubKey[:], - PrivKey: encPrivKey[:], - PubSignKey: signPubKey[:], - PrivSignKey: signPrivKey[:], - }, nil -} - func (a *API) Peer_Update(p *Peer) error { a.lock.Lock() defer a.lock.Unlock() diff --git a/hub/api/session.go b/hub/api/session.go deleted file mode 100644 index 778f64e..0000000 --- a/hub/api/session.go +++ /dev/null @@ -1 +0,0 @@ -package api diff --git a/hub/handlers.go b/hub/handlers.go index 238a4c5..dcd2688 100644 --- a/hub/handlers.go +++ b/hub/handlers.go @@ -208,7 +208,7 @@ func (a *App) _adminPeerInit(s *api.Session, w http.ResponseWriter, r *http.Requ return err } code := a.api.Peer_CreateInitIntent(peerIP) - log.Printf("Got code: %v / %v", peerIP, cod) + log.Printf("Got code: %v / %v", peerIP, code) return a.render("/admin-peer-init.html", w, struct { Session *api.Session @@ -217,20 +217,6 @@ func (a *App) _adminPeerInit(s *api.Session, w http.ResponseWriter, r *http.Requ }{s, a.api.Config_Get().HubAddress, code}) } -// TODO: Remove -func (a *App) _adminPeerIntentCreated(s *api.Session, w http.ResponseWriter, r *http.Request) error { - code := r.FormValue("Code") - if code == "" { - return errors.New("missing Code") - } - - return a.render("/admin-peer-intent.html", w, struct { - Session *api.Session - HubAddress string - Code string - }{s, a.api.Config_Get().HubAddress, code}) -} - func (a *App) _adminPeerView(s *api.Session, w http.ResponseWriter, r *http.Request) error { var peerIP byte err := webutil.NewFormScanner(r.Form).Scan("PeerIP", &peerIP).Error() @@ -345,17 +331,6 @@ func (a *App) _peerInit(w http.ResponseWriter, r *http.Request) error { return a.sendJSON(w, conf) } -// TODO: Remove -func (a *App) _peerCreate(w http.ResponseWriter, r *http.Request) error { - code := r.FormValue("Code") - conf, err := a.api.Peer_Create(code) - if err != nil { - return err - } - - return a.sendJSON(w, conf) -} - func (a *App) _peerFetchState(w http.ResponseWriter, r *http.Request) error { _, apiKey, ok := r.BasicAuth() if !ok { @@ -385,13 +360,14 @@ func (a *App) _peerFetchState(w http.ResponseWriter, r *http.Request) error { for _, p := range peers { if len(p.PubKey) != 0 { state.Peers[p.PeerIP] = &m.Peer{ - PeerIP: p.PeerIP, - Version: p.Version, - Name: p.Name, - PublicIP: p.PublicIP, - Port: p.Port, - Relay: p.Relay, - PubKey: p.PubKey, + PeerIP: p.PeerIP, + Version: p.Version, + Name: p.Name, + PublicIP: p.PublicIP, + Port: p.Port, + Relay: p.Relay, + PubKey: p.PubKey, + PubSignKey: p.PubSignKey, } } } diff --git a/hub/routes.go b/hub/routes.go index a86619e..adf9b58 100644 --- a/hub/routes.go +++ b/hub/routes.go @@ -20,15 +20,12 @@ func (a *App) registerRoutes() { a.handleSignedIn("GET /admin/peer/create/", a._adminPeerCreate) a.handleSignedIn("POST /admin/peer/create/", a._adminPeerCreateSubmit) a.handleSignedIn("GET /admin/peer/init/", a._adminPeerInit) - // TODO: Remove - a.handleSignedIn("GET /admin/peer/intent-created/", a._adminPeerIntentCreated) a.handleSignedIn("GET /admin/peer/view/", a._adminPeerView) a.handleSignedIn("GET /admin/peer/edit/", a._adminPeerEdit) a.handleSignedIn("POST /admin/peer/edit/", a._adminPeerEditSubmit) a.handleSignedIn("GET /admin/peer/delete/", a._adminPeerDelete) a.handleSignedIn("POST /admin/peer/delete/", a._adminPeerDeleteSubmit) - a.handlePeer("GET /peer/create/", a._peerCreate) // TODO: Remove a.handlePeer("GET /peer/init/", a._peerInit) a.handlePeer("GET /peer/fetch-state/", a._peerFetchState) } diff --git a/hub/time.go b/hub/time.go deleted file mode 100644 index 8485440..0000000 --- a/hub/time.go +++ /dev/null @@ -1 +0,0 @@ -package hub diff --git a/node/addrdiscovery.go b/node/addrdiscovery.go index b62e13f..4875c1f 100644 --- a/node/addrdiscovery.go +++ b/node/addrdiscovery.go @@ -13,21 +13,17 @@ func addrDiscoveryServer() { ) for { - pkt := <-discoveryPackets + msg := <-discoveryMessages + p := msg.Packet - p, ok := pkt.Payload.(addrDiscoveryPacket) - if !ok { - continue - } - - route := routingTable[pkt.SrcIP].Load() + route := routingTable[msg.SrcIP].Load() if route == nil || !route.RemoteAddr.IsValid() { continue } _sendControlPacket(addrDiscoveryPacket{ TraceID: p.TraceID, - ToAddr: pkt.SrcAddr, + ToAddr: msg.SrcAddr, }, *route, buf1, buf2) } } @@ -46,9 +42,9 @@ func addrDiscoveryClient() { for { select { - case pkt := <-discoveryPackets: - p, ok := pkt.Payload.(addrDiscoveryPacket) - if !ok || p.TraceID != addrPacket.TraceID || !p.ToAddr.IsValid() || p.ToAddr == lAddr { + case msg := <-discoveryMessages: + p := msg.Packet + if p.TraceID != addrPacket.TraceID || !p.ToAddr.IsValid() || p.ToAddr == lAddr { continue } diff --git a/node/cmd/client/build.sh b/node/cmd/client/build.sh deleted file mode 100755 index c7d72ea..0000000 --- a/node/cmd/client/build.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -go build -sudo setcap cap_net_admin+iep ./client -./client 144.76.78.93 diff --git a/node/cmd/client/main.go b/node/cmd/client/main.go deleted file mode 100644 index 66d0493..0000000 --- a/node/cmd/client/main.go +++ /dev/null @@ -1,15 +0,0 @@ -package main - -import ( - "log" - "os" - "vppn/node" -) - -func main() { - if len(os.Args) != 2 { - log.Fatalf("Usage: %s ", os.Args[0]) - } - n := node.NewTmpNodeClient(os.Args[1]) - n.RunClient() -} diff --git a/node/cmd/server/build.sh b/node/cmd/server/build.sh deleted file mode 100755 index fcc5787..0000000 --- a/node/cmd/server/build.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -go build -ssh kevin "killall server" -scp server kevin:/home/jdl/tmp/ -ssh root@kevin "sudo setcap cap_net_admin+iep /home/jdl/tmp/server" -ssh kevin "/home/jdl/tmp/server" diff --git a/node/cmd/server/main.go b/node/cmd/server/main.go deleted file mode 100644 index 47272cb..0000000 --- a/node/cmd/server/main.go +++ /dev/null @@ -1,8 +0,0 @@ -package main - -import "vppn/node" - -func main() { - n := node.NewTmpNodeServer() - n.RunServer() -} diff --git a/node/globals.go b/node/globals.go index 5438a9c..a6f0e57 100644 --- a/node/globals.go +++ b/node/globals.go @@ -1,10 +1,10 @@ package node import ( + "net" "net/netip" "sync/atomic" "time" - "vppn/m" ) const ( @@ -13,6 +13,12 @@ const ( if_queue_len = 2048 controlCipherOverhead = 16 dataCipherOverhead = 16 + signOverhead = 64 +) + +var ( + multicastIP = netip.AddrFrom4([4]byte{224, 0, 0, 157}) + multicastAddr = net.UDPAddrFromAddrPort(netip.AddrPortFrom(multicastIP, 4560)) ) type peerRoute struct { @@ -56,18 +62,9 @@ var ( return }() - // Channels for incoming control packets. - controlPackets [256]chan controlPacket = func() (out [256]chan controlPacket) { + messages [256]chan any = func() (out [256]chan any) { for i := range out { - out[i] = make(chan controlPacket, 256) - } - return - }() - - // Channels for incoming peer updates from the hub. - peerUpdates [256]chan *m.Peer = func() (out [256]chan *m.Peer) { - for i := range out { - out[i] = make(chan *m.Peer) + out[i] = make(chan any, 256) } return }() @@ -81,8 +78,10 @@ var ( return }() + // Managed by the addrDiscovery* functions. + discoveryMessages = make(chan controlMsg[addrDiscoveryPacket], 256) + // Managed by the relayManager. - discoveryPackets = make(chan controlPacket, 256) - localAddr = &atomic.Pointer[netip.AddrPort]{} - relayIP = &atomic.Pointer[byte]{} + localAddr = &atomic.Pointer[netip.AddrPort]{} + relayIP = &atomic.Pointer[byte]{} ) diff --git a/node/hubpoller.go b/node/hubpoller.go index ac6b110..fc9a309 100644 --- a/node/hubpoller.go +++ b/node/hubpoller.go @@ -86,7 +86,7 @@ func (hp *hubPoller) applyNetworkState(state m.NetworkState) { for i, peer := range state.Peers { if i != int(localIP) { if peer != nil && peer.Version != hp.versions[i] { - peerUpdates[i] <- state.Peers[i] + messages[i] <- peerUpdateMsg{Peer: state.Peers[i]} hp.versions[i] = peer.Version } } diff --git a/node/localbroadcaster.go b/node/localbroadcaster.go deleted file mode 100644 index 0b2cd17..0000000 --- a/node/localbroadcaster.go +++ /dev/null @@ -1,75 +0,0 @@ -package node - -import ( - "encoding/binary" - "log" - "net" - "net/netip" - "time" -) - -func localBroadcaster() { - var ( - buf1 = make([]byte, bufferSize) - buf2 = make([]byte, bufferSize) - ) - time.Sleep(4 * time.Second) - doBroadcast(buf1, buf2) - for range time.Tick(32 * time.Second) { - doBroadcast(buf1, buf2) - } -} - -func doBroadcast(buf1, buf2 []byte) { - ifaces, err := net.Interfaces() - if err != nil { - log.Printf("Failed to list interfaces: %v", err) - return - } - - for _, iface := range ifaces { - if iface.Flags&net.FlagUp == 0 || iface.Flags&net.FlagRunning == 0 { - continue - } - if iface.Flags&net.FlagPointToPoint != 0 { - continue - } - if iface.Flags&net.FlagBroadcast == 0 { - continue - } - - addrs, err := iface.Addrs() - if err != nil { - log.Printf("Failed to get interface addresses: %v", err) - continue - } - - for _, addr := range addrs { - ipNet, ok := addr.(*net.IPNet) - if !ok { - continue - } - ip4 := ipNet.IP.To4() - if ip4 == nil { - continue - } - - ip, ok := lastAddr(ipNet) - if !ok { - log.Printf("Failed to find broadcast address: %v", ipNet) - continue - } - - log.Printf("Broadcasting on address: %v", ip) - //addr := netip.AddrPortFrom(ip, 456) - } - } -} - -// works when the n is a prefix, otherwise... -func lastAddr(n *net.IPNet) (netip.Addr, bool) { - ip := make(net.IP, len(n.IP.To4())) - binary.BigEndian.PutUint32(ip, binary.BigEndian.Uint32(n.IP.To4())| - ^binary.BigEndian.Uint32(net.IP(n.Mask).To4())) - return netip.AddrFromSlice(ip) -} diff --git a/node/localdiscovery.go b/node/localdiscovery.go index acc9f14..b0d35d6 100644 --- a/node/localdiscovery.go +++ b/node/localdiscovery.go @@ -3,18 +3,11 @@ package node import ( "log" "net" - "net/netip" "time" "golang.org/x/crypto/nacl/sign" ) -var ( - signOverhead = 64 - multicastIP = netip.AddrFrom4([4]byte{224, 0, 0, 157}) - multicastAddr = net.UDPAddrFromAddrPort(netip.AddrPortFrom(multicastIP, 4560)) -) - func localDiscovery() { conn, err := net.ListenMulticastUDP("udp", nil, multicastAddr) if err != nil { @@ -32,8 +25,9 @@ func sendLocalDiscovery(conn *net.UDPConn) { buf2 = make([]byte, bufferSize) ) - for range time.Tick(16 * time.Second) { + for range time.Tick(32 * time.Second) { signed := buildLocalDiscoveryPacket(buf1, buf2) + log.Printf("Sending discovery packet...") if _, err := conn.WriteToUDP(signed, multicastAddr); err != nil { log.Printf("Failed to write multicast UDP packet: %v", err) } @@ -51,21 +45,24 @@ func recvLocalDiscovery(conn *net.UDPConn) { if err != nil { log.Fatalf("Failed to read from UDP port (multicast): %v", err) } + log.Printf("Got local discovery packet...") raw = raw[:n] h, ok := openLocalDiscoveryPacket(raw, buf) if !ok { + log.Printf("Failed to open discovery packet?") continue } - pkt := controlPacket{ + msg := controlMsg[localDiscoveryPacket]{ SrcIP: h.SourceIP, SrcAddr: remoteAddr, - Payload: localDiscoveryPacket{}, + Packet: localDiscoveryPacket{}, } + log.Printf("Got local discovery packet from %d/%v...", h.SourceIP, remoteAddr) select { - case controlPackets[h.SourceIP] <- pkt: + case messages[h.SourceIP] <- msg: default: } } @@ -92,6 +89,7 @@ func openLocalDiscoveryPacket(raw, buf []byte) (h header, ok bool) { h.Parse(raw[signOverhead:]) route := routingTable[h.SourceIP].Load() if route == nil || route.PubSignKey == nil { + log.Printf("Missing signing key") ok = false return } diff --git a/node/main.go b/node/main.go index e1dfe5f..46b16d7 100644 --- a/node/main.go +++ b/node/main.go @@ -11,6 +11,7 @@ import ( "net/netip" "os" "runtime/debug" + "time" "vppn/m" ) @@ -26,13 +27,11 @@ func Main() { 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 == "" { @@ -45,7 +44,7 @@ func Main() { return } - main(listenIP, uint16(port)) + main(listenIP) } func mainInit(initURL string) { @@ -74,20 +73,18 @@ func mainInit(initURL string) { // ---------------------------------------------------------------------------- -func main(listenIP string, port uint16) { +func main(listenIP string) { 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)) + myAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", listenIP, config.Port)) if err != nil { log.Fatalf("Failed to resolve UDP address: %v", err) } @@ -129,6 +126,17 @@ func main(listenIP string, port uint16) { go localDiscovery() } + go func() { + for range time.Tick(pingInterval) { + for i := range messages { + select { + case messages[i] <- pingTimerMsg{}: + default: + } + } + } + }() + go newHubPoller(config).Run() go readFromConn(conn) readFromIFace(iface) @@ -136,18 +144,6 @@ func main(listenIP string, port uint16) { // ---------------------------------------------------------------------------- -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() @@ -218,31 +214,21 @@ func handleControlPacket(addr netip.AddrPort, h header, data, decBuf []byte) { return } - pkt := controlPacket{ - SrcIP: h.SourceIP, - SrcAddr: addr, - } - - if err := pkt.ParsePayload(out); err != nil { + msg, err := parseControlMsg(h.SourceIP, addr, out) + if err != nil { log.Printf("Failed to parse control packet: %v", err) return } - switch pkt.Payload.(type) { - - case addrDiscoveryPacket: - select { - case discoveryPackets <- pkt: - default: - log.Printf("Dropping discovery packet.") - } + if dm, ok := msg.(controlMsg[addrDiscoveryPacket]); ok { + discoveryMessages <- dm + return + } + select { + case messages[h.SourceIP] <- msg: default: - select { - case controlPackets[h.SourceIP] <- pkt: - default: - log.Printf("Dropping control packet.") - } + log.Printf("Dropping control packet.") } } diff --git a/node/messages.go b/node/messages.go index 2b4023a..9279bd3 100644 --- a/node/messages.go +++ b/node/messages.go @@ -1 +1,66 @@ package node + +import ( + "net/netip" + "vppn/m" +) + +// ---------------------------------------------------------------------------- + +type controlMsg[T any] struct { + SrcIP byte + SrcAddr netip.AddrPort + Packet T +} + +func parseControlMsg(srcIP byte, srcAddr netip.AddrPort, buf []byte) (any, error) { + switch buf[0] { + + case packetTypeSyn: + packet, err := parseSynPacket(buf) + return controlMsg[synPacket]{ + SrcIP: srcIP, + SrcAddr: srcAddr, + Packet: packet, + }, err + + case packetTypeSynAck: + packet, err := parseSynAckPacket(buf) + return controlMsg[synAckPacket]{ + SrcIP: srcIP, + SrcAddr: srcAddr, + Packet: packet, + }, err + + case packetTypeProbe: + packet, err := parseProbePacket(buf) + return controlMsg[probePacket]{ + SrcIP: srcIP, + SrcAddr: srcAddr, + Packet: packet, + }, err + + case packetTypeAddrDiscovery: + packet, err := parseAddrDiscoveryPacket(buf) + return controlMsg[addrDiscoveryPacket]{ + SrcIP: srcIP, + SrcAddr: srcAddr, + Packet: packet, + }, err + + default: + return nil, errUnknownPacketType + } +} + +// ---------------------------------------------------------------------------- + +type peerUpdateMsg struct { + Peer *m.Peer +} + +// ---------------------------------------------------------------------------- + +type pingTimerMsg struct{} + +// ---------------------------------------------------------------------------- diff --git a/node/packets.go b/node/packets.go index b173887..89b6915 100644 --- a/node/packets.go +++ b/node/packets.go @@ -20,30 +20,6 @@ const ( // ---------------------------------------------------------------------------- -type controlPacket struct { - SrcIP byte - SrcAddr netip.AddrPort - Payload any -} - -func (p *controlPacket) ParsePayload(buf []byte) (err error) { - switch buf[0] { - case packetTypeSyn: - p.Payload, err = parseSynPacket(buf) - case packetTypeSynAck: - p.Payload, err = parseSynAckPacket(buf) - case packetTypeProbe: - p.Payload, err = parseProbePacket(buf) - case packetTypeAddrDiscovery: - p.Payload, err = parseAddrDiscoveryPacket(buf) - default: - return errUnknownPacketType - } - return err -} - -// ---------------------------------------------------------------------------- - type synPacket struct { TraceID uint64 // TraceID to match response w/ request. SharedKey [32]byte // Our shared key. diff --git a/node/peer-supervisor.go b/node/peer-supervisor.go index b31ae84..5363ac2 100644 --- a/node/peer-supervisor.go +++ b/node/peer-supervisor.go @@ -29,8 +29,7 @@ type peerSupervisor struct { remotePub bool // Incoming events. - peerUpdates chan *m.Peer - controlPackets chan controlPacket + messages chan any // Buffers for sending control packets. buf1 []byte @@ -39,12 +38,11 @@ type peerSupervisor struct { func newPeerSupervisor(i int) *peerSupervisor { return &peerSupervisor{ - published: routingTable[i], - remoteIP: byte(i), - peerUpdates: peerUpdates[i], - controlPackets: controlPackets[i], - buf1: make([]byte, bufferSize), - buf2: make([]byte, bufferSize), + published: routingTable[i], + remoteIP: byte(i), + messages: messages[i], + buf1: make([]byte, bufferSize), + buf2: make([]byte, bufferSize), } } @@ -95,7 +93,12 @@ func (s *peerSupervisor) publish() { // ---------------------------------------------------------------------------- func (s *peerSupervisor) noPeer() stateFunc { - return s.peerUpdate(<-s.peerUpdates) + for { + rawMsg := <-s.messages + if msg, ok := rawMsg.(peerUpdateMsg); ok { + return s.peerUpdate(msg.Peer) + } + } } // ---------------------------------------------------------------------------- @@ -149,75 +152,73 @@ func (s *peerSupervisor) server() stateFunc { logf("DOWN") var ( - syn synPacket - timeoutTimer = time.NewTimer(timeoutInterval) + syn synPacket + lastSeen = time.Now() ) - // Timer will be restarted once we have established a connection. - timeoutTimer.Stop() - for { - select { - case peer := <-s.peerUpdates: - return s.peerUpdate(peer) + rawMsg := <-s.messages + switch msg := rawMsg.(type) { - case pkt := <-s.controlPackets: - switch p := pkt.Payload.(type) { + case peerUpdateMsg: + return s.peerUpdate(msg.Peer) - case synPacket: - timeoutTimer.Reset(timeoutInterval) + case controlMsg[synPacket]: + p := msg.Packet + lastSeen = time.Now() - // Before we can respond to this packet, we need to make sure the - // route is setup properly. - // - // The client will update the syn's TraceID whenever there's a change. - // The server will follow the client's request. - if p.TraceID != syn.TraceID || !s.staged.Up { - if p.Direct { - logf("UP - Direct") - } else { - logf("UP - Relayed") - } - - syn = p - s.staged.Up = true - s.staged.Direct = syn.Direct - s.staged.DataCipher = newDataCipherFromKey(syn.SharedKey) - s.staged.RemoteAddr = pkt.SrcAddr - - s.publish() - } - - // We should always respond. - ack := synAckPacket{ - TraceID: syn.TraceID, - FromAddr: getLocalAddr(), - } - s.sendControlPacket(ack) - - if s.staged.Direct { - continue - } - - if !syn.FromAddr.IsValid() { - continue - } - - probe := probePacket{TraceID: newTraceID()} - s.sendControlPacketTo(probe, syn.FromAddr) - - case probePacket: - if pkt.SrcAddr.IsValid() { - s.sendControlPacketTo(probePacket{TraceID: p.TraceID}, pkt.SrcAddr) + // Before we can respond to this packet, we need to make sure the + // route is setup properly. + // + // The client will update the syn's TraceID whenever there's a change. + // The server will follow the client's request. + if p.TraceID != syn.TraceID || !s.staged.Up { + if p.Direct { + logf("UP - Direct") } else { - logf("Invalid probe address") + logf("UP - Relayed") } + + syn = p + s.staged.Up = true + s.staged.Direct = syn.Direct + s.staged.DataCipher = newDataCipherFromKey(syn.SharedKey) + s.staged.RemoteAddr = msg.SrcAddr + + s.publish() } - case <-timeoutTimer.C: - logf("Connection timeout") - s.staged.Up = false - s.publish() + // We should always respond. + ack := synAckPacket{ + TraceID: syn.TraceID, + FromAddr: getLocalAddr(), + } + s.sendControlPacket(ack) + + if s.staged.Direct { + continue + } + + if !syn.FromAddr.IsValid() { + continue + } + + probe := probePacket{TraceID: newTraceID()} + s.sendControlPacketTo(probe, syn.FromAddr) + + case controlMsg[probePacket]: + if !msg.SrcAddr.IsValid() { + logf("Invalid probe address") + continue + } + s.sendControlPacketTo(probePacket{TraceID: msg.Packet.TraceID}, msg.SrcAddr) + + case pingTimerMsg: + if time.Since(lastSeen) > timeoutInterval { + logf("Connection timeout") + s.staged.Up = false + s.publish() + } } } } @@ -237,91 +238,106 @@ func (s *peerSupervisor) client() stateFunc { FromAddr: getLocalAddr(), } - ack synAckPacket + lastSeen = time.Now() + ack synAckPacket probe probePacket probeAddr netip.AddrPort - remoteAddr netip.AddrPort + localProbe probePacket + localProbeAddr netip.AddrPort - timeoutTimer = time.NewTimer(timeoutInterval) - pingTimer = time.NewTimer(pingInterval) + lastLocalAddr netip.AddrPort ) - defer timeoutTimer.Stop() - defer pingTimer.Stop() - s.sendControlPacket(syn) for { - select { + rawMsg := <-s.messages + switch msg := rawMsg.(type) { - case peer := <-s.peerUpdates: - return s.peerUpdate(peer) + case peerUpdateMsg: + return s.peerUpdate(msg.Peer) - case pkt := <-s.controlPackets: - switch p := pkt.Payload.(type) { + case controlMsg[synAckPacket]: + p := msg.Packet - case synAckPacket: - if p.TraceID != syn.TraceID { - continue // Hmm... - } + if p.TraceID != syn.TraceID { + continue // Hmm... + } - ack = p - timeoutTimer.Reset(timeoutInterval) + lastSeen = time.Now() + ack = msg.Packet - if !s.staged.Up { - if s.staged.Direct { - logf("UP - Direct") - } else { - logf("UP - Relayed") - } - - s.staged.Up = true - s.publish() - } - - case probePacket: + if !s.staged.Up { if s.staged.Direct { - continue + logf("UP - Direct") + } else { + logf("UP - Relayed") } - if p.TraceID != probe.TraceID { - continue - } - - // Upgrade connection. - - logf("UP - Direct") - s.staged.Direct = true - s.staged.RemoteAddr = probeAddr + s.staged.Up = true s.publish() - - syn.TraceID = newTraceID() - syn.Direct = true - syn.FromAddr = getLocalAddr() - s.sendControlPacket(syn) } - case <-pingTimer.C: - // Send syn. - - syn.FromAddr = getLocalAddr() - if syn.FromAddr != remoteAddr { - syn.TraceID = newTraceID() - remoteAddr = syn.FromAddr - } - - s.sendControlPacket(syn) - - pingTimer.Reset(pingInterval) - + case controlMsg[probePacket]: if s.staged.Direct { continue } - // TODO: Check if we have local address. - // TODO: Send local probe + p := msg.Packet + + if p.TraceID != localProbe.TraceID && p.TraceID != probe.TraceID { + continue + } + + // Upgrade connection. + + s.staged.Direct = true + if p.TraceID == localProbe.TraceID { + logf("UP - Local") + s.staged.RemoteAddr = localProbeAddr + } else { + logf("UP - Direct") + s.staged.RemoteAddr = probeAddr + } + s.publish() + + syn.TraceID = newTraceID() + syn.Direct = true + syn.FromAddr = getLocalAddr() + s.sendControlPacket(syn) + + case controlMsg[localDiscoveryPacket]: + if s.staged.Direct { + continue + } + + // Send probe. + // + // The source port will be the multicast port, so we'll have to + // construct the correct address using the peer's listed port. + localProbe = probePacket{TraceID: newTraceID()} + localProbeAddr = netip.AddrPortFrom(msg.SrcAddr.Addr(), s.peer.Port) + s.sendControlPacketTo(localProbe, localProbeAddr) + + case pingTimerMsg: + if time.Since(lastSeen) > timeoutInterval { + logf("Connection timeout") + return s.peerUpdate(s.peer) + } + + syn.FromAddr = getLocalAddr() + if syn.FromAddr != lastLocalAddr { + syn.TraceID = newTraceID() + lastLocalAddr = syn.FromAddr + } + + s.sendControlPacket(syn) + + if s.staged.Direct { + continue + } if !ack.FromAddr.IsValid() { continue @@ -331,10 +347,6 @@ func (s *peerSupervisor) client() stateFunc { probeAddr = ack.FromAddr s.sendControlPacketTo(probe, ack.FromAddr) - - case <-timeoutTimer.C: - logf("Connection timeout") - return s.peerUpdate(s.peer) } } } diff --git a/node/signing.go b/node/signing.go deleted file mode 100644 index 2b4023a..0000000 --- a/node/signing.go +++ /dev/null @@ -1 +0,0 @@ -package node diff --git a/stage1/README.md b/stage1/README.md deleted file mode 100644 index 546f4de..0000000 --- a/stage1/README.md +++ /dev/null @@ -1 +0,0 @@ -## Stage1: Point-to-point Tunnel w/ no Encryption diff --git a/stage1/client.go b/stage1/client.go deleted file mode 100644 index 42d8e03..0000000 --- a/stage1/client.go +++ /dev/null @@ -1,32 +0,0 @@ -package stage1 - -import ( - "fmt" - "net" - "net/netip" - "runtime/debug" -) - -func RunClient(serverAddrStr string) { - defer func() { - if r := recover(); r != nil { - fmt.Printf("%v", r) - debug.PrintStack() - } - }() - - iface, err := openInterface(network, clientIP, netName) - must(err) - - myAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf(":%d", port)) - must(err) - - conn, err := net.ListenUDP("udp", myAddr) - must(err) - - serverAddr, err := netip.ParseAddrPort(fmt.Sprintf("%s:%d", serverAddrStr, port)) - must(err) - - go readFromIFace(iface, conn, serverIP, serverAddr) - readFromConn(iface, conn) -} diff --git a/stage1/cmd/client/build.sh b/stage1/cmd/client/build.sh deleted file mode 100755 index 951ca95..0000000 --- a/stage1/cmd/client/build.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -go build - -scp client kevin:/home/jdl/tmp -ssh root@home "setcap cap_net_admin+iep /home/jdl/tmp/client" -ssh home "/home/jdl/tmp/client 192.168.1.21" diff --git a/stage1/cmd/client/main.go b/stage1/cmd/client/main.go deleted file mode 100644 index 60ccfbf..0000000 --- a/stage1/cmd/client/main.go +++ /dev/null @@ -1,14 +0,0 @@ -package main - -import ( - "log" - "os" - "vppn/stage1" -) - -func main() { - if len(os.Args) != 2 { - log.Fatalf("Usage: %s ", os.Args[0]) - } - stage1.RunClient(os.Args[1]) -} diff --git a/stage1/cmd/server/build.sh b/stage1/cmd/server/build.sh deleted file mode 100755 index 0c89238..0000000 --- a/stage1/cmd/server/build.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash - -go build -sudo setcap cap_net_admin+iep server diff --git a/stage1/cmd/server/main.go b/stage1/cmd/server/main.go deleted file mode 100644 index 5c5cd36..0000000 --- a/stage1/cmd/server/main.go +++ /dev/null @@ -1,14 +0,0 @@ -package main - -import ( - "log" - "os" - "vppn/stage1" -) - -func main() { - if len(os.Args) != 2 { - log.Fatalf("Usage: %s ", os.Args[0]) - } - stage1.RunServer(os.Args[1]) -} diff --git a/stage1/interface.go b/stage1/interface.go deleted file mode 100644 index 1e587a2..0000000 --- a/stage1/interface.go +++ /dev/null @@ -1,142 +0,0 @@ -package stage1 - -import ( - "fmt" - "io" - "net" - "os" - "syscall" - - "golang.org/x/sys/unix" -) - -const ( - if_mtu = 1200 - if_queue_len = 1000 -) - -func openInterface(network []byte, localIP byte, name string) (io.ReadWriteCloser, error) { - if len(network) != 4 { - return nil, fmt.Errorf("expected network to be 4 bytes, got %d", len(network)) - } - ip := net.IPv4(network[0], network[1], network[2], localIP) - - ////////////////////////// - // Create TUN Interface // - ////////////////////////// - - tunFD, err := syscall.Open("/dev/net/tun", syscall.O_RDWR|unix.O_CLOEXEC, 0600) - if err != nil { - return nil, fmt.Errorf("failed to open TUN device: %w", err) - } - - // New interface request. - req, err := unix.NewIfreq(name) - if err != nil { - return nil, fmt.Errorf("failed to create new TUN interface request: %w", err) - } - - // Flags: - // - // IFF_NO_PI => don't add packet info data to packets sent to the interface. - // IFF_TUN => create a TUN device handling IP packets. - req.SetUint16(unix.IFF_NO_PI | unix.IFF_TUN) - - err = unix.IoctlIfreq(tunFD, unix.TUNSETIFF, req) - if err != nil { - return nil, fmt.Errorf("failed to set TUN device settings: %w", err) - } - - // Name may not be exactly the same? - name = req.Name() - - ///////////// - // Set MTU // - ///////////// - - // We need a socket file descriptor to set other options for some reason. - sockFD, err := unix.Socket(unix.AF_INET, unix.SOCK_DGRAM, unix.IPPROTO_IP) - if err != nil { - return nil, fmt.Errorf("failed to open socket: %w", err) - } - defer unix.Close(sockFD) - - req, err = unix.NewIfreq(name) - if err != nil { - return nil, fmt.Errorf("failed to create MTU interface request: %w", err) - } - - req.SetUint32(if_mtu) - if err = unix.IoctlIfreq(sockFD, unix.SIOCSIFMTU, req); err != nil { - return nil, fmt.Errorf("failed to set interface MTU: %w", err) - } - - ////////////////////// - // Set Queue Length // - ////////////////////// - - req, err = unix.NewIfreq(name) - if err != nil { - return nil, fmt.Errorf("failed to create IP interface request: %w", err) - } - - req.SetUint16(if_queue_len) - if err = unix.IoctlIfreq(sockFD, unix.SIOCSIFTXQLEN, req); err != nil { - return nil, fmt.Errorf("failed to set interface queue length: %w", err) - } - - ///////////////////// - // Set IP and Mask // - ///////////////////// - - req, err = unix.NewIfreq(name) - if err != nil { - return nil, fmt.Errorf("failed to create IP interface request: %w", err) - } - - if err := req.SetInet4Addr(ip.To4()); err != nil { - return nil, fmt.Errorf("failed to set interface request IP: %w", err) - } - - if err = unix.IoctlIfreq(sockFD, unix.SIOCSIFADDR, req); err != nil { - return nil, fmt.Errorf("failed to set interface IP: %w", err) - } - - // SET MASK - must happen after setting address. - req, err = unix.NewIfreq(name) - if err != nil { - return nil, fmt.Errorf("failed to create mask interface request: %w", err) - } - - if err := req.SetInet4Addr(net.IPv4(255, 255, 255, 0).To4()); err != nil { - return nil, fmt.Errorf("failed to set interface request mask: %w", err) - } - - if err := unix.IoctlIfreq(sockFD, unix.SIOCSIFNETMASK, req); err != nil { - return nil, fmt.Errorf("failed to set interface mask: %w", err) - } - - //////////////////////// - // Bring Interface Up // - //////////////////////// - - req, err = unix.NewIfreq(name) - if err != nil { - return nil, fmt.Errorf("failed to create up interface request: %w", err) - } - - // Get current flags. - if err = unix.IoctlIfreq(sockFD, unix.SIOCGIFFLAGS, req); err != nil { - return nil, fmt.Errorf("failed to get interface flags: %w", err) - } - - flags := req.Uint16() | unix.IFF_UP | unix.IFF_RUNNING - - // Set UP flag / broadcast flags. - req.SetUint16(flags) - if err = unix.IoctlIfreq(sockFD, unix.SIOCSIFFLAGS, req); err != nil { - return nil, fmt.Errorf("failed to set interface up: %w", err) - } - - return os.NewFile(uintptr(tunFD), "tun"), nil -} diff --git a/stage1/server.go b/stage1/server.go deleted file mode 100644 index 8f210c0..0000000 --- a/stage1/server.go +++ /dev/null @@ -1,109 +0,0 @@ -package stage1 - -import ( - "fmt" - "io" - "log" - "net" - "net/netip" - "runtime/debug" -) - -var ( - network = []byte{10, 1, 1, 0} - serverIP = byte(1) - clientIP = byte(2) - port = uint16(5151) - netName = "testnet" - bufferSize = if_mtu * 2 -) - -func must(err error) { - if err != nil { - panic(err) - } -} - -func RunServer(clientAddrStr string) { - defer func() { - if r := recover(); r != nil { - fmt.Printf("%v", r) - debug.PrintStack() - } - }() - - iface, err := openInterface(network, serverIP, netName) - must(err) - - myAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf(":%d", port)) - must(err) - - conn, err := net.ListenUDP("udp", myAddr) - must(err) - - clientAddr, err := netip.ParseAddrPort(fmt.Sprintf("%s:%d", clientAddrStr, port)) - must(err) - - go readFromIFace(iface, conn, clientIP, clientAddr) - readFromConn(iface, conn) -} - -func readFromIFace(iface io.ReadWriteCloser, conn *net.UDPConn, remoteIP byte, remoteAddr netip.AddrPort) { - var ( - n int - packet = make([]byte, bufferSize) - version byte - ip byte - err error - ) - - for { - n, err = iface.Read(packet[:bufferSize]) - must(err) - packet = packet[:n] - - if len(packet) < 20 { - log.Printf("Dropping small packet: %d", n) - continue - } - - packet = packet[:n] - version = packet[0] >> 4 - - switch version { - case 4: - ip = packet[19] - case 6: - ip = packet[39] - default: - log.Printf("Dropping packet with IP version: %d", version) - continue - } - - if ip != remoteIP { - log.Printf("Dropping packet for incorrect IP: %d", ip) - continue - } - - _, err = conn.WriteToUDPAddrPort(packet, remoteAddr) - must(err) - } -} - -func readFromConn(iface io.ReadWriteCloser, conn *net.UDPConn) { - var ( - n int - packet = make([]byte, bufferSize) - err error - ) - - for { - // We assume that we're only receiving packets from one source. - n, err = conn.Read(packet[:bufferSize]) - must(err) - - packet = packet[:n] - _, err = iface.Write(packet) - must(err) - } -} diff --git a/stage1/startup.go b/stage1/startup.go deleted file mode 100644 index e164d95..0000000 --- a/stage1/startup.go +++ /dev/null @@ -1 +0,0 @@ -package stage1 diff --git a/stage2/README.md b/stage2/README.md deleted file mode 100644 index ef00a03..0000000 --- a/stage2/README.md +++ /dev/null @@ -1,4 +0,0 @@ -## Stage2: - -* Point-to-point Tunnel w/ no Encryption -* Server gets client's addr from first packet diff --git a/stage2/client.go b/stage2/client.go deleted file mode 100644 index 6d969d1..0000000 --- a/stage2/client.go +++ /dev/null @@ -1,35 +0,0 @@ -package stage2 - -import ( - "fmt" - "net" - "net/netip" - "runtime/debug" -) - -func RunClient(serverAddrStr string) { - defer func() { - if r := recover(); r != nil { - fmt.Printf("%v", r) - debug.PrintStack() - } - }() - - iface, err := openInterface(network, clientIP, netName) - must(err) - - myAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf(":%d", port)) - must(err) - - conn, err := net.ListenUDP("udp", myAddr) - must(err) - - serverAddr, err := netip.ParseAddrPort(fmt.Sprintf("%s:%d", serverAddrStr, port)) - must(err) - - _, err = conn.WriteToUDPAddrPort([]byte{1, 2, 3, 4, 5, 6, 7, 8}, serverAddr) - must(err) - - go readFromIFace(iface, conn, serverIP, serverAddr) - readFromConn(iface, conn) -} diff --git a/stage2/cmd/client/build.sh b/stage2/cmd/client/build.sh deleted file mode 100755 index c7d72ea..0000000 --- a/stage2/cmd/client/build.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -go build -sudo setcap cap_net_admin+iep ./client -./client 144.76.78.93 diff --git a/stage2/cmd/client/main.go b/stage2/cmd/client/main.go deleted file mode 100644 index 7217b31..0000000 --- a/stage2/cmd/client/main.go +++ /dev/null @@ -1,14 +0,0 @@ -package main - -import ( - "log" - "os" - "vppn/stage2" -) - -func main() { - if len(os.Args) != 2 { - log.Fatalf("Usage: %s ", os.Args[0]) - } - stage2.RunClient(os.Args[1]) -} diff --git a/stage2/cmd/server/build.sh b/stage2/cmd/server/build.sh deleted file mode 100755 index 8f90f02..0000000 --- a/stage2/cmd/server/build.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash - -go build -scp server kevin:/home/jdl/tmp/ -ssh root@kevin "sudo setcap cap_net_admin+iep /home/jdl/tmp/server" -ssh kevin "/home/jdl/tmp/server" diff --git a/stage2/cmd/server/main.go b/stage2/cmd/server/main.go deleted file mode 100644 index d38dc86..0000000 --- a/stage2/cmd/server/main.go +++ /dev/null @@ -1,7 +0,0 @@ -package main - -import "vppn/stage2" - -func main() { - stage2.RunServer() -} diff --git a/stage2/interface.go b/stage2/interface.go deleted file mode 100644 index f890c55..0000000 --- a/stage2/interface.go +++ /dev/null @@ -1,142 +0,0 @@ -package stage2 - -import ( - "fmt" - "io" - "net" - "os" - "syscall" - - "golang.org/x/sys/unix" -) - -const ( - if_mtu = 1200 - if_queue_len = 1000 -) - -func openInterface(network []byte, localIP byte, name string) (io.ReadWriteCloser, error) { - if len(network) != 4 { - return nil, fmt.Errorf("expected network to be 4 bytes, got %d", len(network)) - } - ip := net.IPv4(network[0], network[1], network[2], localIP) - - ////////////////////////// - // Create TUN Interface // - ////////////////////////// - - tunFD, err := syscall.Open("/dev/net/tun", syscall.O_RDWR|unix.O_CLOEXEC, 0600) - if err != nil { - return nil, fmt.Errorf("failed to open TUN device: %w", err) - } - - // New interface request. - req, err := unix.NewIfreq(name) - if err != nil { - return nil, fmt.Errorf("failed to create new TUN interface request: %w", err) - } - - // Flags: - // - // IFF_NO_PI => don't add packet info data to packets sent to the interface. - // IFF_TUN => create a TUN device handling IP packets. - req.SetUint16(unix.IFF_NO_PI | unix.IFF_TUN) - - err = unix.IoctlIfreq(tunFD, unix.TUNSETIFF, req) - if err != nil { - return nil, fmt.Errorf("failed to set TUN device settings: %w", err) - } - - // Name may not be exactly the same? - name = req.Name() - - ///////////// - // Set MTU // - ///////////// - - // We need a socket file descriptor to set other options for some reason. - sockFD, err := unix.Socket(unix.AF_INET, unix.SOCK_DGRAM, unix.IPPROTO_IP) - if err != nil { - return nil, fmt.Errorf("failed to open socket: %w", err) - } - defer unix.Close(sockFD) - - req, err = unix.NewIfreq(name) - if err != nil { - return nil, fmt.Errorf("failed to create MTU interface request: %w", err) - } - - req.SetUint32(if_mtu) - if err = unix.IoctlIfreq(sockFD, unix.SIOCSIFMTU, req); err != nil { - return nil, fmt.Errorf("failed to set interface MTU: %w", err) - } - - ////////////////////// - // Set Queue Length // - ////////////////////// - - req, err = unix.NewIfreq(name) - if err != nil { - return nil, fmt.Errorf("failed to create IP interface request: %w", err) - } - - req.SetUint16(if_queue_len) - if err = unix.IoctlIfreq(sockFD, unix.SIOCSIFTXQLEN, req); err != nil { - return nil, fmt.Errorf("failed to set interface queue length: %w", err) - } - - ///////////////////// - // Set IP and Mask // - ///////////////////// - - req, err = unix.NewIfreq(name) - if err != nil { - return nil, fmt.Errorf("failed to create IP interface request: %w", err) - } - - if err := req.SetInet4Addr(ip.To4()); err != nil { - return nil, fmt.Errorf("failed to set interface request IP: %w", err) - } - - if err = unix.IoctlIfreq(sockFD, unix.SIOCSIFADDR, req); err != nil { - return nil, fmt.Errorf("failed to set interface IP: %w", err) - } - - // SET MASK - must happen after setting address. - req, err = unix.NewIfreq(name) - if err != nil { - return nil, fmt.Errorf("failed to create mask interface request: %w", err) - } - - if err := req.SetInet4Addr(net.IPv4(255, 255, 255, 0).To4()); err != nil { - return nil, fmt.Errorf("failed to set interface request mask: %w", err) - } - - if err := unix.IoctlIfreq(sockFD, unix.SIOCSIFNETMASK, req); err != nil { - return nil, fmt.Errorf("failed to set interface mask: %w", err) - } - - //////////////////////// - // Bring Interface Up // - //////////////////////// - - req, err = unix.NewIfreq(name) - if err != nil { - return nil, fmt.Errorf("failed to create up interface request: %w", err) - } - - // Get current flags. - if err = unix.IoctlIfreq(sockFD, unix.SIOCGIFFLAGS, req); err != nil { - return nil, fmt.Errorf("failed to get interface flags: %w", err) - } - - flags := req.Uint16() | unix.IFF_UP | unix.IFF_RUNNING - - // Set UP flag / broadcast flags. - req.SetUint16(flags) - if err = unix.IoctlIfreq(sockFD, unix.SIOCSIFFLAGS, req); err != nil { - return nil, fmt.Errorf("failed to set interface up: %w", err) - } - - return os.NewFile(uintptr(tunFD), "tun"), nil -} diff --git a/stage2/server.go b/stage2/server.go deleted file mode 100644 index 01581d7..0000000 --- a/stage2/server.go +++ /dev/null @@ -1,112 +0,0 @@ -package stage2 - -import ( - "fmt" - "io" - "log" - "net" - "net/netip" - "runtime/debug" -) - -var ( - network = []byte{10, 1, 1, 0} - serverIP = byte(1) - clientIP = byte(2) - port = uint16(5151) - netName = "testnet" - bufferSize = if_mtu * 2 -) - -func must(err error) { - if err != nil { - panic(err) - } -} - -func RunServer() { - defer func() { - if r := recover(); r != nil { - fmt.Printf("%v", r) - debug.PrintStack() - } - }() - - iface, err := openInterface(network, serverIP, netName) - must(err) - - myAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf(":%d", port)) - must(err) - - conn, err := net.ListenUDP("udp", myAddr) - must(err) - - // Get remoteAddr from a packet. - buf := make([]byte, 8) - _, remoteAddr, err := conn.ReadFromUDPAddrPort(buf) - log.Printf("Got remote addr: %v", remoteAddr) - must(err) - - go readFromIFace(iface, conn, clientIP, remoteAddr) - readFromConn(iface, conn) -} - -func readFromIFace(iface io.ReadWriteCloser, conn *net.UDPConn, remoteIP byte, remoteAddr netip.AddrPort) { - var ( - n int - packet = make([]byte, bufferSize) - version byte - ip byte - err error - ) - - for { - n, err = iface.Read(packet[:bufferSize]) - must(err) - packet = packet[:n] - - if len(packet) < 20 { - log.Printf("Dropping small packet: %d", n) - continue - } - - packet = packet[:n] - version = packet[0] >> 4 - - switch version { - case 4: - ip = packet[19] - case 6: - ip = packet[39] - default: - log.Printf("Dropping packet with IP version: %d", version) - continue - } - - if ip != remoteIP { - log.Printf("Dropping packet for incorrect IP: %d", ip) - continue - } - - _, err = conn.WriteToUDPAddrPort(packet, remoteAddr) - must(err) - } -} - -func readFromConn(iface io.ReadWriteCloser, conn *net.UDPConn) { - var ( - n int - packet = make([]byte, bufferSize) - err error - ) - - for { - // We assume that we're only receiving packets from one source. - n, err = conn.Read(packet[:bufferSize]) - must(err) - - packet = packet[:n] - _, err = iface.Write(packet) - must(err) - } -} diff --git a/stage2/startup.go b/stage2/startup.go deleted file mode 100644 index 65b92ec..0000000 --- a/stage2/startup.go +++ /dev/null @@ -1 +0,0 @@ -package stage2 diff --git a/stage3/README.md b/stage3/README.md deleted file mode 100644 index dc76e28..0000000 --- a/stage3/README.md +++ /dev/null @@ -1,16 +0,0 @@ -## Stage3: - -* Point-to-point Tunnel w/ no Encryption -* Server gets client's addr from first packet -* Add packet counter to detect skipped and late packets - -### Learnings - -* Directional packet loss is an issue. - * Sending to hetzner: ~380 Mbits/sec - * From hetzner: ~800 Mbits/sec -* Runs of dropped packets are generally small < 30 - * Saw a few cases of 100-200 -* Runs of correctly-sequenced packets are generally >> drops -* Late packets aren't so common -* Dropping late packets causes large slow-down. diff --git a/stage3/client.go b/stage3/client.go deleted file mode 100644 index a8b9e98..0000000 --- a/stage3/client.go +++ /dev/null @@ -1,35 +0,0 @@ -package stage3 - -import ( - "fmt" - "net" - "net/netip" - "runtime/debug" -) - -func RunClient(serverAddrStr string) { - defer func() { - if r := recover(); r != nil { - fmt.Printf("%v", r) - debug.PrintStack() - } - }() - - iface, err := openInterface(network, clientIP, netName) - must(err) - - myAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf(":%d", port)) - must(err) - - conn, err := net.ListenUDP("udp", myAddr) - must(err) - - serverAddr, err := netip.ParseAddrPort(fmt.Sprintf("%s:%d", serverAddrStr, port)) - must(err) - - _, err = conn.WriteToUDPAddrPort([]byte{1, 2, 3, 4, 5, 6, 7, 8}, serverAddr) - must(err) - - go readFromIFace(iface, conn, clientIP, serverIP, serverAddr) - readFromConn(iface, conn, serverIP) -} diff --git a/stage3/cmd/client/build.sh b/stage3/cmd/client/build.sh deleted file mode 100755 index c7d72ea..0000000 --- a/stage3/cmd/client/build.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -go build -sudo setcap cap_net_admin+iep ./client -./client 144.76.78.93 diff --git a/stage3/cmd/client/main.go b/stage3/cmd/client/main.go deleted file mode 100644 index e27e22f..0000000 --- a/stage3/cmd/client/main.go +++ /dev/null @@ -1,14 +0,0 @@ -package main - -import ( - "log" - "os" - "vppn/stage3" -) - -func main() { - if len(os.Args) != 2 { - log.Fatalf("Usage: %s ", os.Args[0]) - } - stage3.RunClient(os.Args[1]) -} diff --git a/stage3/cmd/server/build.sh b/stage3/cmd/server/build.sh deleted file mode 100755 index fcc5787..0000000 --- a/stage3/cmd/server/build.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -go build -ssh kevin "killall server" -scp server kevin:/home/jdl/tmp/ -ssh root@kevin "sudo setcap cap_net_admin+iep /home/jdl/tmp/server" -ssh kevin "/home/jdl/tmp/server" diff --git a/stage3/cmd/server/main.go b/stage3/cmd/server/main.go deleted file mode 100644 index e8430a4..0000000 --- a/stage3/cmd/server/main.go +++ /dev/null @@ -1,7 +0,0 @@ -package main - -import "vppn/stage3" - -func main() { - stage3.RunServer() -} diff --git a/stage3/interface.go b/stage3/interface.go deleted file mode 100644 index fa8de32..0000000 --- a/stage3/interface.go +++ /dev/null @@ -1,142 +0,0 @@ -package stage3 - -import ( - "fmt" - "io" - "net" - "os" - "syscall" - - "golang.org/x/sys/unix" -) - -const ( - if_mtu = 1200 - if_queue_len = 1000 -) - -func openInterface(network []byte, localIP byte, name string) (io.ReadWriteCloser, error) { - if len(network) != 4 { - return nil, fmt.Errorf("expected network to be 4 bytes, got %d", len(network)) - } - ip := net.IPv4(network[0], network[1], network[2], localIP) - - ////////////////////////// - // Create TUN Interface // - ////////////////////////// - - tunFD, err := syscall.Open("/dev/net/tun", syscall.O_RDWR|unix.O_CLOEXEC, 0600) - if err != nil { - return nil, fmt.Errorf("failed to open TUN device: %w", err) - } - - // New interface request. - req, err := unix.NewIfreq(name) - if err != nil { - return nil, fmt.Errorf("failed to create new TUN interface request: %w", err) - } - - // Flags: - // - // IFF_NO_PI => don't add packet info data to packets sent to the interface. - // IFF_TUN => create a TUN device handling IP packets. - req.SetUint16(unix.IFF_NO_PI | unix.IFF_TUN) - - err = unix.IoctlIfreq(tunFD, unix.TUNSETIFF, req) - if err != nil { - return nil, fmt.Errorf("failed to set TUN device settings: %w", err) - } - - // Name may not be exactly the same? - name = req.Name() - - ///////////// - // Set MTU // - ///////////// - - // We need a socket file descriptor to set other options for some reason. - sockFD, err := unix.Socket(unix.AF_INET, unix.SOCK_DGRAM, unix.IPPROTO_IP) - if err != nil { - return nil, fmt.Errorf("failed to open socket: %w", err) - } - defer unix.Close(sockFD) - - req, err = unix.NewIfreq(name) - if err != nil { - return nil, fmt.Errorf("failed to create MTU interface request: %w", err) - } - - req.SetUint32(if_mtu) - if err = unix.IoctlIfreq(sockFD, unix.SIOCSIFMTU, req); err != nil { - return nil, fmt.Errorf("failed to set interface MTU: %w", err) - } - - ////////////////////// - // Set Queue Length // - ////////////////////// - - req, err = unix.NewIfreq(name) - if err != nil { - return nil, fmt.Errorf("failed to create IP interface request: %w", err) - } - - req.SetUint16(if_queue_len) - if err = unix.IoctlIfreq(sockFD, unix.SIOCSIFTXQLEN, req); err != nil { - return nil, fmt.Errorf("failed to set interface queue length: %w", err) - } - - ///////////////////// - // Set IP and Mask // - ///////////////////// - - req, err = unix.NewIfreq(name) - if err != nil { - return nil, fmt.Errorf("failed to create IP interface request: %w", err) - } - - if err := req.SetInet4Addr(ip.To4()); err != nil { - return nil, fmt.Errorf("failed to set interface request IP: %w", err) - } - - if err = unix.IoctlIfreq(sockFD, unix.SIOCSIFADDR, req); err != nil { - return nil, fmt.Errorf("failed to set interface IP: %w", err) - } - - // SET MASK - must happen after setting address. - req, err = unix.NewIfreq(name) - if err != nil { - return nil, fmt.Errorf("failed to create mask interface request: %w", err) - } - - if err := req.SetInet4Addr(net.IPv4(255, 255, 255, 0).To4()); err != nil { - return nil, fmt.Errorf("failed to set interface request mask: %w", err) - } - - if err := unix.IoctlIfreq(sockFD, unix.SIOCSIFNETMASK, req); err != nil { - return nil, fmt.Errorf("failed to set interface mask: %w", err) - } - - //////////////////////// - // Bring Interface Up // - //////////////////////// - - req, err = unix.NewIfreq(name) - if err != nil { - return nil, fmt.Errorf("failed to create up interface request: %w", err) - } - - // Get current flags. - if err = unix.IoctlIfreq(sockFD, unix.SIOCGIFFLAGS, req); err != nil { - return nil, fmt.Errorf("failed to get interface flags: %w", err) - } - - flags := req.Uint16() | unix.IFF_UP | unix.IFF_RUNNING - - // Set UP flag / broadcast flags. - req.SetUint16(flags) - if err = unix.IoctlIfreq(sockFD, unix.SIOCSIFFLAGS, req); err != nil { - return nil, fmt.Errorf("failed to set interface up: %w", err) - } - - return os.NewFile(uintptr(tunFD), "tun"), nil -} diff --git a/stage3/packet.go b/stage3/packet.go deleted file mode 100644 index d8e96b7..0000000 --- a/stage3/packet.go +++ /dev/null @@ -1,23 +0,0 @@ -package stage3 - -import "unsafe" - -const headerSize = 9 - -type packetHeader struct { - SrcIP byte - Counter uint64 -} - -func (h packetHeader) Marshal(buf []byte) int { - buf = buf[:9] - buf[0] = h.SrcIP - *(*uint64)(unsafe.Pointer(&buf[1])) = h.Counter - return headerSize -} - -func (h *packetHeader) Parse(buf []byte) int { - h.SrcIP = buf[0] - h.Counter = *(*uint64)(unsafe.Pointer(&buf[1])) - return headerSize -} diff --git a/stage3/packet_test.go b/stage3/packet_test.go deleted file mode 100644 index ef643e4..0000000 --- a/stage3/packet_test.go +++ /dev/null @@ -1,22 +0,0 @@ -package stage3 - -import ( - "reflect" - "testing" -) - -func TestPacketHeader(t *testing.T) { - b := make([]byte, 1024) - - h := packetHeader{ - SrcIP: 8, - Counter: 2354, - } - n := h.Marshal(b) - h2 := packetHeader{} - h2.Parse(b[:n]) - - if !reflect.DeepEqual(h, h2) { - t.Fatal(h, h2) - } -} diff --git a/stage3/server.go b/stage3/server.go deleted file mode 100644 index 4bb3d87..0000000 --- a/stage3/server.go +++ /dev/null @@ -1,147 +0,0 @@ -package stage3 - -import ( - "fmt" - "io" - "log" - "net" - "net/netip" - "runtime/debug" -) - -var ( - network = []byte{10, 1, 1, 0} - serverIP = byte(1) - clientIP = byte(2) - port = uint16(5151) - netName = "testnet" - bufferSize = if_mtu * 2 -) - -func must(err error) { - if err != nil { - panic(err) - } -} - -func RunServer() { - defer func() { - if r := recover(); r != nil { - fmt.Printf("%v", r) - debug.PrintStack() - } - }() - - iface, err := openInterface(network, serverIP, netName) - must(err) - - myAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf(":%d", port)) - must(err) - - conn, err := net.ListenUDP("udp", myAddr) - must(err) - - // Get remoteAddr from a packet. - buf := make([]byte, 8) - _, remoteAddr, err := conn.ReadFromUDPAddrPort(buf) - log.Printf("Got remote addr: %v", remoteAddr) - must(err) - - go readFromIFace(iface, conn, serverIP, clientIP, remoteAddr) - readFromConn(iface, conn, clientIP) -} - -func readFromIFace(iface io.ReadWriteCloser, conn *net.UDPConn, localIP, remoteIP byte, remoteAddr netip.AddrPort) { - var ( - n int - packet = make([]byte, bufferSize) - version byte - ip byte - err error - counter uint64 - buf = make([]byte, bufferSize) - ) - - for { - n, err = iface.Read(packet[:bufferSize]) - must(err) - packet = packet[:n] - - if len(packet) < 20 { - log.Printf("Dropping small packet: %d", n) - continue - } - - packet = packet[:n] - version = packet[0] >> 4 - - switch version { - case 4: - ip = packet[19] - case 6: - ip = packet[39] - default: - log.Printf("Dropping packet with IP version: %d", version) - continue - } - - if ip != remoteIP { - log.Printf("Dropping packet for incorrect IP: %d", ip) - continue - } - - h := packetHeader{SrcIP: localIP, Counter: counter} - counter++ - buf = buf[:headerSize+len(packet)] - h.Marshal(buf) - copy(buf[headerSize:], packet) - - _, err = conn.WriteToUDPAddrPort(buf, remoteAddr) - must(err) - } -} - -func readFromConn(iface io.ReadWriteCloser, conn *net.UDPConn, remoteIP byte) { - var ( - n int - packet = make([]byte, bufferSize) - err error - counter uint64 - run uint64 - h packetHeader - ) - - for { - // We assume that we're only receiving packets from one source. - n, err = conn.Read(packet[:bufferSize]) - must(err) - - packet = packet[:n] - if len(packet) < headerSize { - fmt.Print("_") - continue - } - - h.Parse(packet) - if h.SrcIP != remoteIP { - fmt.Print("?") - continue - } - - if h.Counter == counter+1 { - run++ - counter = h.Counter - } else if h.Counter > counter+1 { - fmt.Printf("x(%d/%d)", h.Counter-counter+1, run) - run = 0 - counter = h.Counter - } else if h.Counter <= counter { - //log.Printf("Skipped late packet: -%d", counter-h.Counter) - //continue - fmt.Print("<") - } - - _, err = iface.Write(packet[headerSize:]) - must(err) - } -} diff --git a/stage3/startup.go b/stage3/startup.go deleted file mode 100644 index 65332e0..0000000 --- a/stage3/startup.go +++ /dev/null @@ -1 +0,0 @@ -package stage3