]> Cypherpunks.ru repositories - govpn.git/blobdiff - govpn.go
Well, performance is not so high actually
[govpn.git] / govpn.go
index 1e157107c33cafab4cbdd7631184bed511666acb..7b15dd429910ab039016347a8dff3966fd0fa1e9 100644 (file)
--- a/govpn.go
+++ b/govpn.go
@@ -1,5 +1,5 @@
 /*
-govpn -- high-performance secure virtual private network daemon
+govpn -- simple secure virtual private network daemon
 Copyright (C) 2014 Sergey Matveev <stargrave@stargrave.org>
 
 This program is free software: you can redistribute it and/or modify
@@ -15,6 +15,8 @@ GNU General Public License for more details.
 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
+
+// Simple secure virtual private network daemon
 package main
 
 import (
@@ -32,8 +34,8 @@ import (
        "os/signal"
        "time"
 
-       "code.google.com/p/go.crypto/poly1305"
-       "code.google.com/p/go.crypto/salsa20"
+       "golang.org/x/crypto/poly1305"
+       "golang.org/x/crypto/salsa20"
 )
 
 var (
@@ -44,6 +46,7 @@ var (
        upPath     = flag.String("up", "", "Path to up-script")
        downPath   = flag.String("down", "", "Path to down-script")
        mtu        = flag.Int("mtu", 1500, "MTU")
+       nonceDiff  = flag.Int("noncediff", 1, "Allow nonce difference")
        timeoutP   = flag.Int("timeout", 60, "Timeout seconds")
        verboseP   = flag.Bool("v", false, "Increase verbosity")
 )
@@ -55,6 +58,8 @@ const (
        S20BS         = 64
        HeartBeatSize = 12
        HeartBeatMark = "\x00\x00\x00HEARTBEAT"
+       // Maximal amount of bytes transfered with single key (4 GiB)
+       MaxBytesPerKey = 4294967296
 )
 
 type TAP interface {
@@ -90,6 +95,7 @@ func main() {
        flag.Parse()
        timeout := *timeoutP
        verbose := *verboseP
+       noncediff := uint64(*nonceDiff)
        log.SetFlags(log.Ldate | log.Lmicroseconds | log.Lshortfile)
 
        // Key decoding
@@ -189,20 +195,20 @@ func main() {
        var p *Peer
 
        timeouts := 0
+       bytes := 0
        states := make(map[string]*Handshake)
        nonce := make([]byte, NonceSize)
        keyAuth := new([KeySize]byte)
        tag := new([poly1305.TagSize]byte)
        buf := make([]byte, *mtu+S20BS)
        emptyKey := make([]byte, KeySize)
-       ethPkt := make([]byte, maxIfacePktSize)
-       udpPktDataBuf := make([]byte, *mtu)
 
        if !serverMode {
                states[remote.String()] = HandshakeStart(conn, remote, key)
        }
 
        heartbeat := time.Tick(time.Second * time.Duration(timeout/3))
+       go func() { <-heartbeat }()
        heartbeatMark := []byte(HeartBeatMark)
 
        termSignal := make(chan os.Signal, 1)
@@ -213,6 +219,10 @@ func main() {
                if finished {
                        break
                }
+               if !serverMode && bytes > MaxBytesPerKey {
+                       states[remote.String()] = HandshakeStart(conn, remote, key)
+                       bytes = 0
+               }
                select {
                case <-termSignal:
                        finished = true
@@ -227,9 +237,7 @@ func main() {
                                udpSinkReady <- true
                                continue
                        }
-                       copy(udpPktDataBuf, udpBuf[:udpPkt.size])
-                       udpSinkReady <- true
-                       udpPktData = udpPktDataBuf[:udpPkt.size]
+                       udpPktData = udpBuf[:udpPkt.size]
                        if isValidHandshakePkt(udpPktData) {
                                addr = udpPkt.addr.String()
                                state, exists := states[addr]
@@ -238,28 +246,34 @@ func main() {
                                                state = &Handshake{addr: udpPkt.addr}
                                                states[addr] = state
                                        }
-                                       p = state.Server(conn, key, udpPktData)
+                                       p = state.Server(noncediff, conn, key, udpPktData)
                                } else {
                                        if !exists {
                                                fmt.Print("[HS?]")
+                                               udpSinkReady <- true
                                                continue
                                        }
-                                       p = state.Client(conn, key, udpPktData)
+                                       p = state.Client(noncediff, conn, key, udpPktData)
                                }
                                if p != nil {
                                        fmt.Print("[HS-OK]")
+                                       if peer == nil {
+                                               go ScriptCall(upPath)
+                                       }
                                        peer = p
                                        delete(states, addr)
-                                       go ScriptCall(upPath)
                                }
+                               udpSinkReady <- true
                                continue
                        }
                        if peer == nil {
+                               udpSinkReady <- true
                                continue
                        }
                        nonceRecv, _ := binary.Uvarint(udpPktData[:8])
-                       if peer.nonceRecv >= nonceRecv {
+                       if nonceRecv < peer.nonceRecv-noncediff {
                                fmt.Print("R")
+                               udpSinkReady <- true
                                continue
                        }
                        copy(buf[:KeySize], emptyKey)
@@ -273,12 +287,15 @@ func main() {
                        )
                        copy(keyAuth[:], buf[:KeySize])
                        if !poly1305.Verify(tag, udpPktData[:udpPkt.size-poly1305.TagSize], keyAuth) {
+                               udpSinkReady <- true
                                fmt.Print("T")
                                continue
                        }
+                       udpSinkReady <- true
                        peer.nonceRecv = nonceRecv
                        timeouts = 0
                        frame = buf[S20BS : S20BS+udpPkt.size-NonceSize-poly1305.TagSize]
+                       bytes += len(frame)
                        if string(frame[0:HeartBeatSize]) == HeartBeatMark {
                                continue
                        }
@@ -296,22 +313,22 @@ func main() {
                                ethSinkReady <- true
                                continue
                        }
+                       peer.nonceOur = peer.nonceOur + 2
+                       binary.PutUvarint(nonce, peer.nonceOur)
+                       copy(buf[:KeySize], emptyKey)
                        if ethPktSize > -1 {
-                               copy(ethPkt, ethBuf[:ethPktSize])
+                               copy(buf[S20BS:], ethBuf[:ethPktSize])
                                ethSinkReady <- true
                        } else {
-                               copy(ethPkt, heartbeatMark)
+                               copy(buf[S20BS:], heartbeatMark)
                                ethPktSize = HeartBeatSize
                        }
-                       peer.nonceOur = peer.nonceOur + 2
-                       binary.PutUvarint(nonce, peer.nonceOur)
-                       copy(buf[:KeySize], emptyKey)
-                       copy(buf[S20BS:], ethPkt[:ethPktSize])
                        salsa20.XORKeyStream(buf, buf, nonce, peer.key)
                        copy(buf[S20BS-NonceSize:S20BS], nonce)
                        copy(keyAuth[:], buf[:KeySize])
                        dataToSend := buf[S20BS-NonceSize : S20BS+ethPktSize]
                        poly1305.Sum(tag, dataToSend, keyAuth)
+                       bytes += len(dataToSend)
                        if _, err := conn.WriteTo(append(dataToSend, tag[:]...), peer.addr); err != nil {
                                log.Println("Error sending UDP", err)
                        }