]> Cypherpunks.ru repositories - govpn.git/commitdiff
Exit when daemon is becoming dead 1.0
authorSergey Matveev <stargrave@stargrave.org>
Thu, 21 Aug 2014 12:41:09 +0000 (16:41 +0400)
committerSergey Matveev <stargrave@stargrave.org>
Thu, 21 Aug 2014 14:56:26 +0000 (18:56 +0400)
* Exit if handshake is timeouted
* Exit if daemon becomes unavailable
* Simplify overall code

Signed-off-by: Sergey Matveev <stargrave@stargrave.org>
README
govpn.go
handshake.go

diff --git a/README b/README
index e321da780221718f0c30886582802fceb1ecc19c..34d8be8314e4247805b5579f49cf66290e2827b1 100644 (file)
--- a/README
+++ b/README
@@ -42,7 +42,7 @@ COMPARISON TO OpenVPN
 
 CONSOLE OUTPUT LEGEND
 
-B -- bad UDP packet (some system error)
+B -- bad or timeouted UDP packet (maybe network is inactive)
 T -- bad tag on packet (MiTM, unordered packet)
 R -- invalid sequence number (MiTM, unordered packet)
 [HS?] -- unknown handshake message
@@ -77,7 +77,12 @@ Ethernet frame header length, that in my case is 14 bytes long (1476 - 14).
     pc% ip addr add 172.16.0.2/24 dev tap10
     pc% ip link set up dev tap10
     pc% ip route add default via 172.16.0.1
-    pc% govpn -key KEY -iface tap10 -remote 192.168.0.1:1194
+    pc% while :; do govpn -key KEY -iface tap10 -remote 192.168.0.1:1194; done
+
+If client won't finish handshake during -timeout, then it will exit.
+If no packets are received from remote side during timeout, then daemon
+will stop sending packets to the client and client will exit. In every
+cases you have to rehandshake again.
 
 TECHNICAL INTERNALS
 
index a6db5e34438c27f8d0d13789d7792ec4b6cb42bb..fcd1a00b898591fe2ccc034685ce2d82ca164a02 100644 (file)
--- a/govpn.go
+++ b/govpn.go
@@ -31,31 +31,28 @@ import (
        "github.com/chon219/water"
 )
 
+var (
+       remoteAddr = flag.String("remote", "", "Remote server address")
+       bindAddr   = flag.String("bind", "", "Bind to address")
+       ifaceName  = flag.String("iface", "tap0", "TAP network interface")
+       keyHex     = flag.String("key", "", "Authentication key")
+       mtu        = flag.Int("mtu", 1500, "MTU")
+       timeout    = flag.Int("timeout", 60, "Timeout seconds")
+       verbose    = flag.Bool("v", false, "Increase verbosity")
+)
+
 const (
-       NonceSize    = 8
-       AliveTimeout = time.Second * 90
-       KeySize      = 32
+       NonceSize = 8
+       KeySize   = 32
        // S20BS is Salsa20's internal blocksize in bytes
        S20BS = 64
 )
 
 type Peer struct {
        addr      *net.UDPAddr
-       lastPing  time.Time
        key       *[KeySize]byte // encryption key
-       nonceOur  uint64    // nonce for our messages
-       nonceRecv uint64    // latest received nonce from remote peer
-}
-
-func (p *Peer) IsAlive() bool {
-       if (p == nil) || (p.lastPing.Add(AliveTimeout).Before(time.Now())) {
-               return false
-       }
-       return true
-}
-
-func (p *Peer) SetAlive() {
-       p.lastPing = time.Now()
+       nonceOur  uint64         // nonce for our messages
+       nonceRecv uint64         // latest received nonce from remote peer
 }
 
 type UDPPkt struct {
@@ -63,15 +60,6 @@ type UDPPkt struct {
        size int
 }
 
-var (
-       remoteAddr = flag.String("remote", "", "Remote server address")
-       bindAddr   = flag.String("bind", "", "Bind to address")
-       ifaceName  = flag.String("iface", "tap0", "TAP network interface")
-       keyHex     = flag.String("key", "", "Authentication key")
-       mtu        = flag.Int("mtu", 1500, "MTU")
-       verbose    = flag.Bool("v", false, "Increase verbosity")
-)
-
 func main() {
        flag.Parse()
        log.SetFlags(log.Ldate | log.Lmicroseconds | log.Lshortfile)
@@ -99,7 +87,7 @@ func main() {
        ethSinkReady := make(chan bool)
        go func() {
                for {
-                       <- ethSinkReady
+                       <-ethSinkReady
                        n, err := iface.Read(ethBuf)
                        if err != nil {
                                panic(err)
@@ -141,28 +129,34 @@ func main() {
        }
 
        udpBuf := make([]byte, *mtu)
-       udpSink := make(chan UDPPkt)
+       udpSink := make(chan *UDPPkt)
        udpSinkReady := make(chan bool)
        go func(conn *net.UDPConn) {
                for {
-                       <- udpSinkReady
+                       <-udpSinkReady
+                       conn.SetReadDeadline(time.Now().Add(time.Second))
                        n, addr, err := conn.ReadFromUDP(udpBuf)
                        if err != nil {
-                               fmt.Print("B")
+                               if *verbose {
+                                       fmt.Print("B")
+                               }
+                               udpSink <- nil
+                       } else {
+                               udpSink <- &UDPPkt{addr, n}
                        }
-                       udpSink <- UDPPkt{addr, n}
                }
        }(conn)
        udpSinkReady <- true
 
        // Process packets
-       var udpPkt UDPPkt
+       var udpPkt *UDPPkt
        var udpPktData []byte
        var ethPktSize int
        var addr string
-       var peer Peer
+       var peer *Peer
        var p *Peer
 
+       timeouts := 0
        states := make(map[string]*Handshake)
        nonce := make([]byte, NonceSize)
        keyAuth := new([KeySize]byte)
@@ -173,13 +167,24 @@ func main() {
        udpPktDataBuf := make([]byte, *mtu)
 
        if !serverMode {
-               log.Println("starting handshake with", *remoteAddr)
                states[remote.String()] = HandshakeStart(conn, remote, key)
        }
 
+       finished := false
        for {
+               if finished {
+                       break
+               }
                select {
                case udpPkt = <-udpSink:
+                       timeouts++
+                       if !serverMode && timeouts >= *timeout {
+                               finished = true
+                       }
+                       if udpPkt == nil {
+                               udpSinkReady <- true
+                               continue
+                       }
                        copy(udpPktDataBuf, udpBuf[:udpPkt.size])
                        udpSinkReady <- true
                        udpPktData = udpPktDataBuf[:udpPkt.size]
@@ -201,12 +206,12 @@ func main() {
                                }
                                if p != nil {
                                        fmt.Print("[HS-OK]")
-                                       peer = *p
+                                       peer = p
                                        delete(states, addr)
                                }
                                continue
                        }
-                       if !peer.IsAlive() {
+                       if peer == nil {
                                continue
                        }
                        nonceRecv, _ := binary.Uvarint(udpPktData[:8])
@@ -229,7 +234,7 @@ func main() {
                                continue
                        }
                        peer.nonceRecv = nonceRecv
-                       peer.SetAlive()
+                       timeouts = 0
                        if _, err := iface.Write(buf[S20BS : S20BS+udpPkt.size-NonceSize-poly1305.TagSize]); err != nil {
                                log.Println("Error writing to iface")
                        }
@@ -240,7 +245,7 @@ func main() {
                        if ethPktSize > maxIfacePktSize {
                                panic("Too large packet on interface")
                        }
-                       if !peer.IsAlive() {
+                       if peer == nil {
                                ethSinkReady <- true
                                continue
                        }
index a3403ea2d978755762e9a04c5aa4d5089353f1ee..072a7bd5be7424c1ae2bbe6551278f434f2f27e2 100644 (file)
@@ -184,7 +184,6 @@ func (h *Handshake) Server(conn *net.UDPConn, key *[32]byte, data []byte) *Peer
 
                // Switch peer
                peer := Peer{addr: h.addr, nonceOur: 0, nonceRecv: 0}
-               peer.SetAlive()
                peer.key = KeyFromSecrets(h.sServer[:], decRs[8+8:])
                fmt.Print("[OK]")
                return &peer
@@ -252,7 +251,6 @@ func (h *Handshake) Client(conn *net.UDPConn, key *[32]byte, data []byte) *Peer
 
                // Switch peer
                peer := Peer{addr: h.addr, nonceOur: 1, nonceRecv: 0}
-               peer.SetAlive()
                peer.key = KeyFromSecrets(h.sServer[:], h.sClient[:])
                fmt.Print("[OK]")
                return &peer