]> Cypherpunks.ru repositories - govpn.git/commitdiff
Heartbeating the channel twice during timeout
authorSergey Matveev <stargrave@stargrave.org>
Sat, 10 Jan 2015 18:57:14 +0000 (21:57 +0300)
committerSergey Matveev <stargrave@stargrave.org>
Sat, 10 Jan 2015 20:02:23 +0000 (23:02 +0300)
Signed-off-by: Sergey Matveev <stargrave@stargrave.org>
README
govpn.go

diff --git a/README b/README
index 078c42e7917bf7dffbd3ac999202275a71f3c2e1..058ef02937ec51fe90f24e9337ec28107c607a63 100644 (file)
--- a/README
+++ b/README
@@ -12,9 +12,8 @@ All packets captured on network interface are encrypted, authenticated
 and sent to remote server, that writes them to his interface, and vice
 versa. Client and server use pre-shared authentication key (PSK).
 Because of stateless UDP nature, after some timeout of inactivity peers
-forget about each other and have to retry handshake process again. As a
-rule, there are enough time-to-time traffic in ordinary Ethernet
-networks to heartbeat connection.
+forget about each other and have to retry handshake process again,
+therefore background heartbeat process will be ran.
 
 Handshake is used to mutually authenticate peers, exchange common secret
 per-session encryption key and checks UDP transport availability.
index 25792e8a5b0665c4e72926c391ffa848effd890b..89ccabffa6e602f7b767639457b10fd38a7ecfc1 100644 (file)
--- a/govpn.go
+++ b/govpn.go
@@ -46,7 +46,9 @@ const (
        NonceSize = 8
        KeySize   = 32
        // S20BS is Salsa20's internal blocksize in bytes
-       S20BS = 64
+       S20BS         = 64
+       HeartBeatSize = 12
+       HeartBeatMark = "\x00\x00\x00HEARTBEAT"
 )
 
 type TAP interface {
@@ -163,6 +165,7 @@ func main() {
        var udpPkt *UDPPkt
        var udpPktData []byte
        var ethPktSize int
+       var frame []byte
        var addr string
        var peer *Peer
        var p *Peer
@@ -181,12 +184,17 @@ func main() {
                states[remote.String()] = HandshakeStart(conn, remote, key)
        }
 
+       heartbeat := time.Tick(time.Second * time.Duration(timeout/3))
+       heartbeatMark := []byte(HeartBeatMark)
+
        finished := false
        for {
                if finished {
                        break
                }
                select {
+               case <-heartbeat:
+                       go func() { ethSink <- -1 }()
                case udpPkt = <-udpSink:
                        timeouts++
                        if !serverMode && timeouts >= timeout {
@@ -246,7 +254,11 @@ func main() {
                        }
                        peer.nonceRecv = nonceRecv
                        timeouts = 0
-                       if _, err := iface.Write(buf[S20BS : S20BS+udpPkt.size-NonceSize-poly1305.TagSize]); err != nil {
+                       frame = buf[S20BS : S20BS+udpPkt.size-NonceSize-poly1305.TagSize]
+                       if string(frame[0:HeartBeatSize]) == HeartBeatMark {
+                               continue
+                       }
+                       if _, err := iface.Write(frame); err != nil {
                                log.Println("Error writing to iface: ", err)
                        }
                        if verbose {
@@ -260,8 +272,13 @@ func main() {
                                ethSinkReady <- true
                                continue
                        }
-                       copy(ethPkt, ethBuf[:ethPktSize])
-                       ethSinkReady <- true
+                       if ethPktSize > -1 {
+                               copy(ethPkt, ethBuf[:ethPktSize])
+                               ethSinkReady <- true
+                       } else {
+                               copy(ethPkt, heartbeatMark)
+                               ethPktSize = HeartBeatSize
+                       }
                        peer.nonceOur = peer.nonceOur + 2
                        binary.PutUvarint(nonce, peer.nonceOur)
                        copy(buf[:KeySize], emptyKey)