summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKali Kaneko (leap communications) <kali@leap.se>2018-06-25 19:18:59 +0200
committerKali Kaneko (leap communications) <kali@leap.se>2018-06-25 19:18:59 +0200
commitb897ad541bcef182e9c072e872bf80d56513b5e4 (patch)
treee3dab8eb50dcea9390734b53f64edce4d2a0b628
parent9547df797f7a12e2410df2e4a82e3436248a282f (diff)
[feat] nim helper
-rw-r--r--helper/README.txt2
-rwxr-xr-xhelper/bitmask_helper.nim112
-rwxr-xr-xhelper/protocol.nim54
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
+