summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuben Pollan <meskio@sindominio.net>2018-06-26 19:15:52 +0200
committerKali Kaneko (leap communications) <kali@leap.se>2018-06-27 20:31:49 +0200
commit8b0ad0c146015cfeef6abd4373ca99a3b4e57826 (patch)
tree5fe5098117950cb8d4a6657570c614a9d329b3f1
parent05bc3260b9c958a72096e7a28956f4666bd65603 (diff)
[feat] first implementation of the helper in go
-rw-r--r--.gitignore1
-rw-r--r--helper/README.txt2
-rwxr-xr-xhelper/bitmask_helper.nim112
-rw-r--r--helper/darwin.go46
-rw-r--r--helper/helper.go104
-rw-r--r--helper/linux.go50
-rwxr-xr-xhelper/protocol.nim54
-rw-r--r--helper/windows.go52
8 files changed, 253 insertions, 168 deletions
diff --git a/.gitignore b/.gitignore
index a55ddc9..641884d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,3 +6,4 @@
*.pyc
staging/*
__pycache__
+helper/helper
diff --git a/helper/README.txt b/helper/README.txt
deleted file mode 100644
index a77121b..0000000
--- a/helper/README.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-This is a first prototype in Nim.
-It will be replaced by a helper in golang.
diff --git a/helper/bitmask_helper.nim b/helper/bitmask_helper.nim
deleted file mode 100755
index 64333ee..0000000
--- a/helper/bitmask_helper.nim
+++ /dev/null
@@ -1,112 +0,0 @@
-# Bitmask Helper
-# A privileged helper that should run as a service in windows.
-
-import asyncdispatch, asyncnet
-import strutils
-import protocol
-import osproc
-
-type
- Client = ref object
- socket: AsyncSocket
- netAddr: string
- id: int
- connected: bool
-
- Server = ref object
- socket: AsyncSocket
- clients: seq[Client]
- openvpnProc: seq[Process]
-
-proc newServer(): Server = Server(socket: newAsyncSocket(), clients: @[])
-proc `$`(client: Client): string =
- $client.id & "(" & client.netAddr & ")"
-
-#
-# OpenVPN commands
-#
-
-proc startOpenVPN(line: string, server: Server) =
- let parsed = parseMessage(line)
- echo(">>> start OpenVPN. \n args:", parsed.args)
- if server.openvpnProc.len == 0:
- server.openvpnProc = @[]
- if server.openvpnProc.len > 0 and running(server.openvpnProc[0]):
- echo(">>> need to stop process first (len: ", server.openvpnProc.len, ")")
- return
-
- try:
- # TODO sanitize args
- let p = startProcess("c:/Program Files/OpenVPN/bin/openvpn.exe", args=split(parsed.args))
- echo "LEN: ", len(server.openvpnProc)
- if server.openvpnProc.len == 0:
- server.openvpnProc.add(p)
- else:
- server.openvpnProc[0] = p
- except OsError:
- echo("error while launching process!")
-
-
-proc stopOpenVPN(line: string, server: Server) =
- echo(">>> stop OpenVPN, \n args:", parseMessage(line).args)
- terminate(server.openvpnProc[0])
-
-
-proc doStatus(line: string, server: Server) =
- if len(server.openvpnProc) == 1:
- echo "running: ", running(server.openvpnProc[0])
- else:
- echo "no proc created"
-
-#
-# processing commands loop
-#
-
-proc processCommands(server: Server, client: Client) {.async.} =
- while true:
- let line = await client.socket.recvLine()
- if line.len == 0:
- echo(client, " disconnected!")
- client.connected = false
- client.socket.close()
- return
-
- echo("debug: ", client, " received: ", line)
-
- try:
- let parsed = parseMessage(line)
- let cmd = parsed.cmd
- case cmd
- of "openvpn_start":
- startOpenVPN(line, server)
- of "openvpn_stop":
- stopOpenVPN(line, server)
- of "status":
- doStatus(line, server)
- of "ping":
- ping(line, server)
- else:
- echo("Invalid command: ", cmd)
-
- except MessageParsingError:
- echo("Invalid message:", line)
-
-
-proc loop(server: Server, port = 7171) {.async.} =
- server.socket.bindAddr(port.Port, address = "127.0.0.1")
- server.socket.listen()
-
- while true:
- let (netAddr, clientSocket) = await server.socket.acceptAddr()
- echo("Accepted connection from ", netAddr)
- let client = Client(
- socket: clientSocket,
- netAddr: netAddr,
- id: server.clients.len,
- connected: true
- )
- server.clients.add(client)
- asyncCheck processCommands(server, client)
-
-var server = newServer()
-waitFor loop(server)
diff --git a/helper/darwin.go b/helper/darwin.go
new file mode 100644
index 0000000..47214bd
--- /dev/null
+++ b/helper/darwin.go
@@ -0,0 +1,46 @@
+// +build darwin
+// Copyright (C) 2018 LEAP
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// 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/>.
+
+package main
+
+import (
+ "log"
+ "net/http"
+ "os"
+ "os/exec"
+)
+
+const (
+ openvpnPath = "/Applications/RiseupVPN.app/Contents/Resources/openvpn.leap"
+)
+
+func getOpenvpnPath() string {
+ return openvpnPath
+}
+
+func kill(cmd *exec.Cmd) error {
+ return cmd.Process.Signal(os.Interrupt)
+}
+
+type firewallT struct{}
+
+func (firewall *firewallT) start(w http.ResponseWriter, r *http.Request) {
+ log.Println("Start firewall: do nothing, not implemented")
+}
+
+func (firewall *firewallT) stop(w http.ResponseWriter, r *http.Request) {
+ log.Println("Stop firewall: do nothing, not implemented")
+}
diff --git a/helper/helper.go b/helper/helper.go
new file mode 100644
index 0000000..a3816de
--- /dev/null
+++ b/helper/helper.go
@@ -0,0 +1,104 @@
+// Copyright (C) 2018 LEAP
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// 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/>.
+
+package main
+
+import (
+ "encoding/json"
+ "log"
+ "net/http"
+ "os/exec"
+)
+
+const (
+ bindAddr = "localhost:7171"
+)
+
+type openvpnT struct {
+ cmd *exec.Cmd
+}
+
+func main() {
+ openvpn := openvpnT{nil}
+ firewall := firewallT{}
+ http.HandleFunc("/openvpn/start", openvpn.start)
+ http.HandleFunc("/openvpn/stop", openvpn.stop)
+ http.HandleFunc("/firewall/start", firewall.start)
+ http.HandleFunc("/firewall/stop", firewall.stop)
+
+ log.Fatal(http.ListenAndServe(bindAddr, nil))
+}
+
+func (openvpn *openvpnT) start(w http.ResponseWriter, r *http.Request) {
+ args, err := getArgs(r)
+ if err != nil {
+ log.Printf("An error has occurred processing flags: %v", err)
+ w.Write([]byte(err.Error()))
+ return
+ }
+
+ log.Printf("start openvpn: %v", args)
+ err = openvpn.run(args)
+ if err != nil {
+ log.Printf("Error starting openvpn: %v", err)
+ w.Write([]byte(err.Error()))
+ }
+}
+
+func (openvpn *openvpnT) run(args []string) error {
+ if openvpn.cmd != nil {
+ log.Printf("openvpn was running, stop it first")
+ err := openvpn.kill()
+ if err != nil {
+ return err
+ }
+ }
+
+ // TODO: if it dies we should restart it
+ openvpn.cmd = exec.Command(getOpenvpnPath(), args...)
+ return openvpn.cmd.Start()
+}
+
+func (openvpn *openvpnT) stop(w http.ResponseWriter, r *http.Request) {
+ log.Println("stop openvpn")
+ if openvpn.cmd == nil || openvpn.cmd.ProcessState != nil {
+ openvpn.cmd = nil
+ return
+ }
+
+ err := openvpn.kill()
+ if err != nil {
+ log.Printf("Error stoping openvpn: %v", err)
+ w.Write([]byte(err.Error()))
+ }
+}
+
+func (openvpn *openvpnT) kill() error {
+ err := kill(openvpn.cmd)
+ if err != nil {
+ return err
+ }
+ openvpn.cmd.Wait()
+
+ openvpn.cmd = nil
+ return nil
+}
+
+func getArgs(r *http.Request) ([]string, error) {
+ args := []string{}
+ decoder := json.NewDecoder(r.Body)
+ err := decoder.Decode(&args)
+ return args, err
+}
diff --git a/helper/linux.go b/helper/linux.go
new file mode 100644
index 0000000..da570c2
--- /dev/null
+++ b/helper/linux.go
@@ -0,0 +1,50 @@
+// +build linux
+// Copyright (C) 2018 LEAP
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// 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/>.
+
+package main
+
+import (
+ "log"
+ "net/http"
+ "os"
+ "os/exec"
+)
+
+const (
+ systemOpenvpnPath = "/usr/sbin/openvpn"
+ snapOpenvpnPath = "/snap/bin/riseup-vpn.openvpn"
+)
+
+func getOpenvpnPath() string {
+ if os.Getenv("SNAP") != "" {
+ return snapOpenvpnPath
+ }
+ return systemOpenvpnPath
+}
+
+func kill(cmd *exec.Cmd) error {
+ return cmd.Process.Signal(os.Interrupt)
+}
+
+type firewallT struct{}
+
+func (firewall *firewallT) start(w http.ResponseWriter, r *http.Request) {
+ log.Println("Start firewall: do nothing, not implemented")
+}
+
+func (firewall *firewallT) stop(w http.ResponseWriter, r *http.Request) {
+ log.Println("Stop firewall: do nothing, not implemented")
+}
diff --git a/helper/protocol.nim b/helper/protocol.nim
deleted file mode 100755
index c7e097a..0000000
--- a/helper/protocol.nim
+++ /dev/null
@@ -1,54 +0,0 @@
-import json
-
-type
- Message* = object
- cmd*: string
- args*: string
-
- MessageParsingError* = object of Exception
-
-proc parseMessage*(data: string): Message {.raises: [MessageParsingError, KeyError].} =
- var dataJson: JsonNode
- try:
- dataJson = parseJson(data)
- except JsonParsingError:
- raise newException(MessageParsingError, "Invalid JSON: " &
- getCurrentExceptionMsg())
- except:
- raise newException(MessageParsingError, "Unknown error: " &
- getCurrentExceptionMsg())
-
- if not dataJson.hasKey("cmd"):
- raise newException(MessageParsingError, "Cmd field missing")
- result.cmd = dataJson["cmd"].getStr()
- if result.cmd.len == 0:
- raise newException(MessageParsingError, "Cmd field is empty")
-
- if not dataJson.hasKey("args"):
- raise newException(MessageParsingError, "Args field missing")
- result.args = dataJson["args"].getStr()
- if result.args.len == 0:
- raise newException(MessageParsingError, "Args field is empty")
-
-proc createMessage*(cmd, args: string): string =
- result = $(%{
- "cmd": %cmd,
- "args": %args
- }) & "\c\l"
-
-when isMainModule:
- block:
- let data = """{"cmd": "status", "args": "verbose"}"""
- let parsed = parseMessage(data)
- doAssert parsed.cmd == "status"
- doAssert parsed.args == "verbose"
-
- # Test failure
- block:
- try:
- let parsed = parseMessage("asdasd")
- except MessageParsingError:
- doAssert true
- except:
- doAssert false
-
diff --git a/helper/windows.go b/helper/windows.go
new file mode 100644
index 0000000..1a19cd2
--- /dev/null
+++ b/helper/windows.go
@@ -0,0 +1,52 @@
+// +build windows
+// Copyright (C) 2018 LEAP
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// 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/>.
+
+package main
+
+import (
+ "log"
+ "net/http"
+ "os"
+ "os/exec"
+)
+
+const (
+ openvpnPath = `C:\bitmask\openvpn.exe`
+ chocoOpenvpnPath = `C:\Program Files\OpenVPN\bin\openvpn.exe`
+)
+
+func getOpenvpnPath() string {
+ if _, err := os.Stat(openvpnPath); !os.IsNotExist(err) {
+ return openvpnPath
+ } else if _, err := os.Stat(chocoOpenvpnPath); !os.IsNotExist(err) {
+ return chocoOpenvpnPath
+ }
+ return "openvpn.exe"
+}
+
+func kill(cmd *exec.Cmd) error {
+ return cmd.Process.Kill()
+}
+
+type firewallT struct{}
+
+func (firewall *firewallT) start(w http.ResponseWriter, r *http.Request) {
+ log.Println("Start firewall: do nothing, not implemented")
+}
+
+func (firewall *firewallT) stop(w http.ResponseWriter, r *http.Request) {
+ log.Println("Stop firewall: do nothing, not implemented")
+}