diff options
author | Kali Kaneko (leap communications) <kali@leap.se> | 2018-06-25 19:18:59 +0200 |
---|---|---|
committer | Kali Kaneko (leap communications) <kali@leap.se> | 2018-06-25 19:18:59 +0200 |
commit | b897ad541bcef182e9c072e872bf80d56513b5e4 (patch) | |
tree | e3dab8eb50dcea9390734b53f64edce4d2a0b628 /helper | |
parent | 9547df797f7a12e2410df2e4a82e3436248a282f (diff) |
[feat] nim helper
Diffstat (limited to 'helper')
-rw-r--r-- | helper/README.txt | 2 | ||||
-rwxr-xr-x | helper/bitmask_helper.nim | 112 | ||||
-rwxr-xr-x | helper/protocol.nim | 54 |
3 files changed, 168 insertions, 0 deletions
diff --git a/helper/README.txt b/helper/README.txt new file mode 100644 index 0000000..a77121b --- /dev/null +++ b/helper/README.txt @@ -0,0 +1,2 @@ +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 new file mode 100755 index 0000000..64333ee --- /dev/null +++ b/helper/bitmask_helper.nim @@ -0,0 +1,112 @@ +# 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/protocol.nim b/helper/protocol.nim new file mode 100755 index 0000000..c7e097a --- /dev/null +++ b/helper/protocol.nim @@ -0,0 +1,54 @@ +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 + |