diff --git a/README.md b/README.md index b7a7612..abb55f0 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,10 @@ * Peer: local peer discovery - part of RoutingProcessor * Peer: update hub w/ latest port on startup +## Learnings + +* Encryption / decryption is 20x faster than signing/opening. + ## Principles * Creates an IPv4/24 network with a maximum of 254 peers. (1-254) @@ -107,3 +111,11 @@ TimeoutStopSec=24 [Install] WantedBy=default.target ``` + +--- + +## Sub-packets + +If we make our MTU large, like 8k, our computations become more efficient. + +We can send packets with header like: diff --git a/peer/connhandler.go b/peer/connhandler.go index 4eb2749..c9ff8df 100644 --- a/peer/connhandler.go +++ b/peer/connhandler.go @@ -78,7 +78,7 @@ func (h *connHandler) mainLoop() { state = state.HandlePong(w) case <-data.pingTimer.C: - state.HandleSendPing() + data.HandleSendPing() case <-data.timeoutTimer.C: log.Printf("[%s] Connection timeout.", state.Name()) @@ -86,7 +86,7 @@ func (h *connHandler) mainLoop() { } if state.Name() != name { - log.Printf("[%03d] STATE: %s --> %s", data.peerIP, name, state.Name()) + log.Printf("[%03d] STATE: %s", data.peerIP, state.Name()) name = state.Name() } } diff --git a/peer/connstate.go b/peer/connstate.go index 441532f..dae3167 100644 --- a/peer/connstate.go +++ b/peer/connstate.go @@ -17,7 +17,6 @@ func logState(s connState, msg string, args ...any) { type connState interface { Name() string HandleMediatorUpdate(ip byte) connState - HandleSendPing() HandlePing(wrapper[Ping]) connState HandlePong(wrapper[Pong]) connState HandleTimeout() connState @@ -33,11 +32,11 @@ func newConnStateFromPeer(update peerUpdate, data *connData) connState { } if _, isPublic := netip.AddrFromSlice(peer.PublicIP); isPublic { - return newConnUnconnectedServer(data, peer) + return newStateServerDown(data, peer) } else if data.server { - return newConnUnconnectedClient(data, peer) + return newStateClientDown(data, peer) } else { - return newConnUnconnectedMediator(data, peer) + return newStateMediatedDown(data, peer) } } @@ -91,15 +90,15 @@ func (c connNull) HandleTimeout() connState { // Unconnected Server // //////////////////////// -type connUnconnectedServer struct { +type stateServerDown struct { *connData } -func newConnUnconnectedServer(data *connData, peer *m.Peer) connState { +func newStateServerDown(data *connData, peer *m.Peer) connState { addr, _ := netip.AddrFromSlice(peer.PublicIP) pubAddr := netip.AddrPortFrom(addr, peer.Port) - c := connUnconnectedServer{data} + c := stateServerDown{data} c.peer = peer c.encSharedKey = computeSharedKey(peer.EncPubKey, c.encPrivKey) c.publicAddr = pubAddr @@ -113,26 +112,26 @@ func newConnUnconnectedServer(data *connData, peer *m.Peer) connState { return c } -func (c connUnconnectedServer) Name() string { - return "ServerUnconnected" +func (c stateServerDown) Name() string { + return "Server:DOWN" } -func (c connUnconnectedServer) HandleMediatorUpdate(ip byte) connState { +func (c stateServerDown) HandleMediatorUpdate(ip byte) connState { // Server connection doesn't use a mediator. c.mediatorIP = ip return c } -func (c connUnconnectedServer) HandlePing(w wrapper[Ping]) connState { +func (c stateServerDown) HandlePing(w wrapper[Ping]) connState { logState(c, "Ignoring ping.") return c } -func (c connUnconnectedServer) HandlePong(w wrapper[Pong]) connState { - return newConnConnectedServer(c.connData, w) +func (c stateServerDown) HandlePong(w wrapper[Pong]) connState { + return newStateServerUp(c.connData, w) } -func (c connUnconnectedServer) HandleTimeout() connState { +func (c stateServerDown) HandleTimeout() connState { logState(c, "Unexpected timeout.") return c } @@ -141,12 +140,12 @@ func (c connUnconnectedServer) HandleTimeout() connState { // Connected Server // ////////////////////// -type connConnectedServer struct { +type stateServerUp struct { *connData } -func newConnConnectedServer(data *connData, w wrapper[Pong]) connState { - c := connConnectedServer{data} +func newStateServerUp(data *connData, w wrapper[Pong]) connState { + c := stateServerUp{data} c.pingTimer.Reset(pingInterval) c.timeoutTimer.Reset(timeoutInterval) c.addr = w.SrcAddr @@ -156,43 +155,43 @@ func newConnConnectedServer(data *connData, w wrapper[Pong]) connState { return c } -func (c connConnectedServer) Name() string { - return "ServerConnected" +func (c stateServerUp) Name() string { + return "Server:UP" } -func (c connConnectedServer) HandleMediatorUpdate(ip byte) connState { +func (c stateServerUp) HandleMediatorUpdate(ip byte) connState { // Server connection doesn't use a mediator. c.mediatorIP = ip return c } -func (c connConnectedServer) HandlePing(w wrapper[Ping]) connState { +func (c stateServerUp) HandlePing(w wrapper[Ping]) connState { logState(c, "Ignoring ping.") return c } -func (c connConnectedServer) HandlePong(w wrapper[Pong]) connState { +func (c stateServerUp) HandlePong(w wrapper[Pong]) connState { c.timeoutTimer.Reset(timeoutInterval) return c } -func (c connConnectedServer) HandleTimeout() connState { - return newConnUnconnectedServer(c.connData, c.peer) +func (c stateServerUp) HandleTimeout() connState { + return newStateServerDown(c.connData, c.peer) } //////////////////////// // Unconnected Client // //////////////////////// -type connUnconnectedClient struct { +type stateClientDown struct { *connData } -func newConnUnconnectedClient(data *connData, peer *m.Peer) connState { +func newStateClientDown(data *connData, peer *m.Peer) connState { addr, _ := netip.AddrFromSlice(peer.PublicIP) pubAddr := netip.AddrPortFrom(addr, peer.Port) - c := connUnconnectedClient{data} + c := stateClientDown{data} c.peer = peer c.publicAddr = pubAddr c.encPrivKey = data.encPrivKey @@ -208,28 +207,28 @@ func newConnUnconnectedClient(data *connData, peer *m.Peer) connState { return c } -func (c connUnconnectedClient) Name() string { - return "ClientUnconnected" +func (c stateClientDown) Name() string { + return "Client:DOWN" } -func (c connUnconnectedClient) HandleMediatorUpdate(ip byte) connState { +func (c stateClientDown) HandleMediatorUpdate(ip byte) connState { // Client connection doesn't use a mediator. c.mediatorIP = ip return c } -func (c connUnconnectedClient) HandlePing(w wrapper[Ping]) connState { - next := newConnConnectedClient(c.connData, w) +func (c stateClientDown) HandlePing(w wrapper[Ping]) connState { + next := newStateClientUp(c.connData, w) c.sendPong(w) // Have to send after transitionsing so route is ok. return next } -func (c connUnconnectedClient) HandlePong(w wrapper[Pong]) connState { +func (c stateClientDown) HandlePong(w wrapper[Pong]) connState { logState(c, "Ignorning pong.") return c } -func (c connUnconnectedClient) HandleTimeout() connState { +func (c stateClientDown) HandleTimeout() connState { logState(c, "Unexpected timeout.") return c } @@ -238,12 +237,12 @@ func (c connUnconnectedClient) HandleTimeout() connState { // Connected Client // ////////////////////// -type connConnectedClient struct { +type stateClientUp struct { *connData } -func newConnConnectedClient(data *connData, w wrapper[Ping]) connState { - c := connConnectedClient{data} +func newStateClientUp(data *connData, w wrapper[Ping]) connState { + c := stateClientUp{data} c.addr = w.SrcAddr c.viaIP = 0 c.up = true @@ -254,17 +253,17 @@ func newConnConnectedClient(data *connData, w wrapper[Ping]) connState { return c } -func (c connConnectedClient) Name() string { - return "ClientConnected" +func (c stateClientUp) Name() string { + return "Client:UP" } -func (c connConnectedClient) HandleMediatorUpdate(ip byte) connState { +func (c stateClientUp) HandleMediatorUpdate(ip byte) connState { // Client connection doesn't use a mediator. c.mediatorIP = ip return c } -func (c connConnectedClient) HandlePing(w wrapper[Ping]) connState { +func (c stateClientUp) HandlePing(w wrapper[Ping]) connState { // The connection is from a client. If the client's address changes, we // should follow that change. if c.addr != w.SrcAddr { @@ -276,28 +275,28 @@ func (c connConnectedClient) HandlePing(w wrapper[Ping]) connState { return c } -func (c connConnectedClient) HandlePong(w wrapper[Pong]) connState { +func (c stateClientUp) HandlePong(w wrapper[Pong]) connState { logState(c, "Ignoring pong.") return c } -func (c connConnectedClient) HandleTimeout() connState { - return newConnUnconnectedClient(c.connData, c.peer) +func (c stateClientUp) HandleTimeout() connState { + return newStateClientDown(c.connData, c.peer) } ////////////////////////// // Unconnected Mediator // ////////////////////////// -type connUnconnectedMediator struct { +type stateMediatedDown struct { *connData } -func newConnUnconnectedMediator(data *connData, peer *m.Peer) connState { +func newStateMediatedDown(data *connData, peer *m.Peer) connState { addr, _ := netip.AddrFromSlice(peer.PublicIP) pubAddr := netip.AddrPortFrom(addr, peer.Port) - c := connUnconnectedMediator{data} + c := stateMediatedDown{data} c.peer = peer c.publicAddr = pubAddr c.encPrivKey = data.encPrivKey @@ -312,35 +311,35 @@ func newConnUnconnectedMediator(data *connData, peer *m.Peer) connState { // If we have a mediator route, we can connect. if mRoute := c.routes[c.mediatorIP].Load(); mRoute != nil { - return newConnConnectedMediator(data, mRoute) + return newStateMediatedUp(data, mRoute) } return c } -func (c connUnconnectedMediator) Name() string { - return "MediatorUnconnected" +func (c stateMediatedDown) Name() string { + return "Mediated:DOWN" } -func (c connUnconnectedMediator) HandleMediatorUpdate(ip byte) connState { +func (c stateMediatedDown) HandleMediatorUpdate(ip byte) connState { c.mediatorIP = ip if mRoute := c.routes[c.mediatorIP].Load(); mRoute != nil { - return newConnConnectedMediator(c.connData, mRoute) + return newStateMediatedUp(c.connData, mRoute) } return c } -func (c connUnconnectedMediator) HandlePing(w wrapper[Ping]) connState { +func (c stateMediatedDown) HandlePing(w wrapper[Ping]) connState { logState(c, "Ignorning ping.") return c } -func (c connUnconnectedMediator) HandlePong(w wrapper[Pong]) connState { +func (c stateMediatedDown) HandlePong(w wrapper[Pong]) connState { logState(c, "Ignorning pong.") return c } -func (c connUnconnectedMediator) HandleTimeout() connState { +func (c stateMediatedDown) HandleTimeout() connState { logState(c, "Unexpected timeout.") return c } @@ -349,12 +348,12 @@ func (c connUnconnectedMediator) HandleTimeout() connState { // Connected Mediator // //////////////////////// -type connConnectedMediator struct { +type stateMediatedUp struct { *connData } -func newConnConnectedMediator(data *connData, route *route) connState { - c := connConnectedMediator{data} +func newStateMediatedUp(data *connData, route *route) connState { + c := stateMediatedUp{data} c.addr = route.Addr c.viaIP = route.PeerIP c.up = true @@ -366,28 +365,28 @@ func newConnConnectedMediator(data *connData, route *route) connState { return c } -func (c connConnectedMediator) Name() string { - return "MediatorConnected" +func (c stateMediatedUp) Name() string { + return "Mediated:UP" } -func (c connConnectedMediator) HandleMediatorUpdate(ip byte) connState { +func (c stateMediatedUp) HandleMediatorUpdate(ip byte) connState { c.mediatorIP = ip if mRoute := c.routes[c.mediatorIP].Load(); mRoute != nil { - return newConnConnectedMediator(c.connData, mRoute) + return newStateMediatedUp(c.connData, mRoute) } - return newConnUnconnectedMediator(c.connData, c.peer) + return newStateMediatedDown(c.connData, c.peer) } -func (c connConnectedMediator) HandlePing(w wrapper[Ping]) connState { +func (c stateMediatedUp) HandlePing(w wrapper[Ping]) connState { logState(c, "Ignoring ping.") return c } -func (c connConnectedMediator) HandlePong(w wrapper[Pong]) connState { +func (c stateMediatedUp) HandlePong(w wrapper[Pong]) connState { logState(c, "Ignoring pong.") return c } -func (c connConnectedMediator) HandleTimeout() connState { - return newConnUnconnectedMediator(c.connData, c.peer) +func (c stateMediatedUp) HandleTimeout() connState { + return newStateMediatedDown(c.connData, c.peer) } diff --git a/peer/crypto_test.go b/peer/crypto_test.go index 8a0f34a..e2b5f1b 100644 --- a/peer/crypto_test.go +++ b/peer/crypto_test.go @@ -106,6 +106,22 @@ func BenchmarkDecryptPacket(b *testing.B) { } } +func BenchmarkSignPacket(b *testing.B) { + _, privKey1, err := sign.GenerateKey(rand.Reader) + if err != nil { + b.Fatal(err) + } + + original := make([]byte, 8192) + rand.Read(original) + out := make([]byte, 9000) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + signPacket(privKey1[:], original, out) + } +} + func TestSignOpenPacket(t *testing.T) { pubKey, privKey, err := sign.GenerateKey(rand.Reader) if err != nil { @@ -127,3 +143,22 @@ func TestSignOpenPacket(t *testing.T) { t.Fatal("not equal") } } + +func BenchmarkOpenPacket(b *testing.B) { + pubKey, privKey, err := sign.GenerateKey(rand.Reader) + if err != nil { + b.Fatal(err) + } + + packet := make([]byte, MTU) + + rand.Read(packet) + + signedPacket := signPacket(privKey[:], packet, make([]byte, 9000)) + out := make([]byte, BUFFER_SIZE) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + out, _ = openPacket(pubKey[:], signedPacket, out) + } +} diff --git a/peer/peer-netreader.go b/peer/peer-netreader.go index 7cba662..661e0a6 100644 --- a/peer/peer-netreader.go +++ b/peer/peer-netreader.go @@ -57,12 +57,10 @@ NEXT_PACKET: } if nonce.Counter <= counters[nonce.StreamID][nonce.SourceIP] { - log.Printf("Dropping packet with bad counter: %d <= %d", nonce.Counter, counters[nonce.StreamID][nonce.SourceIP]) + log.Printf("Dropping packet with bad counter: -%d", counters[nonce.StreamID][nonce.SourceIP]-nonce.Counter) goto NEXT_PACKET } - counters[nonce.StreamID][nonce.SourceIP] = nonce.Counter - route = peer.router.GetRoute(nonce.SourceIP) if route == nil { log.Printf("Dropping packet without route: %+v", nonce) @@ -87,6 +85,9 @@ DECRYPT: goto NEXT_PACKET } + // Only updated after verification. + counters[nonce.StreamID][nonce.SourceIP] = nonce.Counter + switch nonce.StreamID { case STREAM_DATA: goto WRITE_IFACE_DATA @@ -119,6 +120,9 @@ VALIDATE_SIGNATURE: goto NEXT_PACKET } + // Only updated after verification. + counters[nonce.StreamID][nonce.SourceIP] = nonce.Counter + route = peer.router.GetRoute(nonce.DestIP) if route == nil || !route.Up { log.Printf("Dropping mediated packet, route not available: %v", nonce)