diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | helper/README.txt | 2 | ||||
-rwxr-xr-x | helper/bitmask_helper.nim | 112 | ||||
-rw-r--r-- | helper/darwin.go | 46 | ||||
-rw-r--r-- | helper/helper.go | 104 | ||||
-rw-r--r-- | helper/linux.go | 50 | ||||
-rwxr-xr-x | helper/protocol.nim | 54 | ||||
-rw-r--r-- | helper/windows.go | 52 |
8 files changed, 253 insertions, 168 deletions
@@ -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") +} |