]> Cypherpunks.ru repositories - govpn.git/blobdiff - govpn.go
Ability to call up and down scripts
[govpn.git] / govpn.go
index 25792e8a5b0665c4e72926c391ffa848effd890b..1e157107c33cafab4cbdd7631184bed511666acb 100644 (file)
--- a/govpn.go
+++ b/govpn.go
@@ -18,6 +18,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 package main
 
 import (
+       "bytes"
        "encoding/binary"
        "encoding/hex"
        "flag"
@@ -26,6 +27,9 @@ import (
        "io/ioutil"
        "log"
        "net"
+       "os"
+       "os/exec"
+       "os/signal"
        "time"
 
        "code.google.com/p/go.crypto/poly1305"
@@ -37,6 +41,8 @@ var (
        bindAddr   = flag.String("bind", "", "Bind to address")
        ifaceName  = flag.String("iface", "tap0", "TAP network interface")
        keyPath    = flag.String("key", "", "Path to authentication key file")
+       upPath     = flag.String("up", "", "Path to up-script")
+       downPath   = flag.String("down", "", "Path to down-script")
        mtu        = flag.Int("mtu", 1500, "MTU")
        timeoutP   = flag.Int("timeout", 60, "Timeout seconds")
        verboseP   = flag.Bool("v", false, "Increase verbosity")
@@ -46,7 +52,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 {
@@ -66,6 +74,18 @@ type UDPPkt struct {
        size int
 }
 
+func ScriptCall(path *string) {
+       if *path == "" {
+               return
+       }
+       cmd := exec.Command(*path, *ifaceName)
+       var out bytes.Buffer
+       cmd.Stdout = &out
+       if err := cmd.Run(); err != nil {
+               fmt.Println(time.Now(), "script error: ", err.Error(), string(out.Bytes()))
+       }
+}
+
 func main() {
        flag.Parse()
        timeout := *timeoutP
@@ -163,6 +183,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 +202,22 @@ func main() {
                states[remote.String()] = HandshakeStart(conn, remote, key)
        }
 
+       heartbeat := time.Tick(time.Second * time.Duration(timeout/3))
+       heartbeatMark := []byte(HeartBeatMark)
+
+       termSignal := make(chan os.Signal, 1)
+       signal.Notify(termSignal, os.Interrupt, os.Kill)
+
        finished := false
        for {
                if finished {
                        break
                }
                select {
+               case <-termSignal:
+                       finished = true
+               case <-heartbeat:
+                       go func() { ethSink <- -1 }()
                case udpPkt = <-udpSink:
                        timeouts++
                        if !serverMode && timeouts >= timeout {
@@ -219,6 +250,7 @@ func main() {
                                        fmt.Print("[HS-OK]")
                                        peer = p
                                        delete(states, addr)
+                                       go ScriptCall(upPath)
                                }
                                continue
                        }
@@ -246,7 +278,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 +296,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)
@@ -279,4 +320,5 @@ func main() {
                        }
                }
        }
+       ScriptCall(downPath)
 }