mirror of
https://github.com/CPunch/Laika.git
synced 2024-11-21 12:40:04 +00:00
Removed Panel client, updated README requirements
This commit is contained in:
parent
e6dbada6ec
commit
12a1329101
@ -1,6 +1,6 @@
|
||||
# Laika
|
||||
|
||||
Laika is a simple Remote Access Toolkit stack for red teaming. It allows authenticated communication across a custom protocol with generated key pairs which are embedded into the executable (only the public key is embedded in the bot client ofc).
|
||||
Laika is a simple Remote Access Toolkit stack for red teaming. It allows authenticated communication across a custom protocol with generated key pairs which are embedded into the executable (only the public key is embedded in the bot client ofc). This project currently only targets Linux, however the socket API has already been ported to work under various OS including Windows, Linux & MacOS. Cross-platform support for the bot client will come eventually.
|
||||
|
||||
Some notable features thus far:
|
||||
- [X] Lightweight, the bot alone is 270kb (22kb if not statically linked with LibSodium) and uses very little resources.
|
||||
@ -22,13 +22,13 @@ I could add some padding to each packet to make it look pseudo-HTTP-like, howeve
|
||||
- `/cnc` is the Command aNd Control server.
|
||||
- `/bot` is the bot client to be ran on the target machine.
|
||||
- `/shell` is the main shell to connect to the CNC server with to issue commands.
|
||||
- `/panel` is a very incomplete & broken ncurses client. ignore for now.
|
||||
- `/tools` holds tools for generating keypairs, etc.
|
||||
|
||||
## Configuration and compilation
|
||||
|
||||
Make sure you have the following libraries and tools installed:
|
||||
- CMake (>=3.10)
|
||||
- Compiler with C11 support (GCC >= 4.7, Clang >= 3.1, etc.)
|
||||
- LibSodium (static library)
|
||||
|
||||
First, compile the target normally
|
||||
|
@ -1,22 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
set(PANEL_INCLUDEDIR ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
set(CURSES_NEED_NCURSES TRUE)
|
||||
|
||||
project(LaikaPanel VERSION 1.0)
|
||||
|
||||
# Put CMake targets (ALL_BUILD/ZERO_CHECK) into a folder
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
|
||||
find_package(Curses)
|
||||
|
||||
# compile LaikaPanel
|
||||
file(GLOB_RECURSE PANELSOURCE ${CMAKE_CURRENT_SOURCE_DIR}/src/**.c)
|
||||
add_executable(LaikaPanel ${PANELSOURCE})
|
||||
target_link_libraries(LaikaPanel PUBLIC LaikaLib ${CURSES_LIBRARIES})
|
||||
|
||||
# add the 'DEBUG' preprocessor definition if we're compiling as Debug
|
||||
target_compile_definitions(LaikaPanel PUBLIC "$<$<CONFIG:Debug>:DEBUG>")
|
||||
|
||||
# add include directory
|
||||
target_include_directories(LaikaPanel PUBLIC ${PANEL_INCLUDEDIR})
|
@ -1,104 +0,0 @@
|
||||
#ifndef PANELMENU_H
|
||||
#define PANELMENU_H
|
||||
|
||||
#include <ncurses.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define PANEL_CURSES_TIMEOUT 100
|
||||
#define COMMONPANELLIST tPanel_list list;
|
||||
|
||||
typedef void (*panelCallback)(void *uData);
|
||||
|
||||
typedef enum {
|
||||
LIST_LIST,
|
||||
LIST_TABS,
|
||||
LIST_MENU,
|
||||
LIST_TEXT,
|
||||
LIST_NONE
|
||||
} LISTTYPE;
|
||||
|
||||
struct sPanel_list;
|
||||
typedef struct sPanel_listItem {
|
||||
panelCallback callback;
|
||||
struct sPanel_list *child;
|
||||
void *uData;
|
||||
char *name;
|
||||
struct sPanel_listItem *next;
|
||||
struct sPanel_listItem *last;
|
||||
int x, y, width, height;
|
||||
} tPanel_listItem;
|
||||
|
||||
typedef struct sPanel_list {
|
||||
tPanel_listItem *itemHead, *selectedItem;
|
||||
WINDOW *win;
|
||||
int x, y, width, height;
|
||||
LISTTYPE type;
|
||||
bool hidden;
|
||||
} tPanel_list;
|
||||
|
||||
typedef struct sPanel_tabs {
|
||||
COMMONPANELLIST;
|
||||
char *title;
|
||||
} tPanel_tabs;
|
||||
|
||||
typedef struct sPanel_menu {
|
||||
COMMONPANELLIST;
|
||||
char *title;
|
||||
} tPanel_menu;
|
||||
|
||||
typedef struct sPanel_text {
|
||||
COMMONPANELLIST;
|
||||
char *title;
|
||||
char *text;
|
||||
} tPanel_text;
|
||||
|
||||
extern WINDOW *wmain;
|
||||
extern tPanel_list *panel_botList;
|
||||
extern tPanel_tabs *panel_tabList;
|
||||
|
||||
void panel_init(void);
|
||||
void panel_cleanUp(void);
|
||||
|
||||
tPanel_list *panel_getActiveList(void);
|
||||
int panel_getChar(void);
|
||||
void panel_pushActiveList(tPanel_list *list);
|
||||
void panel_popActiveList(void); /* also free's the item */
|
||||
void panel_draw(void);
|
||||
bool panel_tick(int input); /* ticks activeList list, returns true if input was accepted/valid */
|
||||
void panel_setTimeout(int timeout);
|
||||
|
||||
tPanel_listItem *panelL_newListItem(tPanel_list *list, tPanel_list *child, char *name, panelCallback callback, void *uData);
|
||||
void panelL_freeListItem(tPanel_list *list, tPanel_listItem *item);
|
||||
|
||||
/* call *after* adding listItems with panelL_newListItem */
|
||||
void panelL_init(tPanel_list *list);
|
||||
void panelL_draw(tPanel_list *list);
|
||||
void panelL_free(tPanel_list *list);
|
||||
bool panelL_tick(tPanel_list *list, int ch);
|
||||
void panelL_setHidden(tPanel_list *list, bool hidden);
|
||||
void panelL_setTimeout(tPanel_list *list, int timeout);
|
||||
|
||||
/* handles selection */
|
||||
void panelL_nextItem(tPanel_list *list);
|
||||
void panelL_prevItem(tPanel_list *list);
|
||||
void panelL_selectItem(tPanel_list *list); /* calls select item's callback */
|
||||
|
||||
/* center list */
|
||||
tPanel_list *panelL_newList(void);
|
||||
void panelL_freeList(tPanel_list *list);
|
||||
|
||||
/* top tabs */
|
||||
tPanel_tabs *panelL_newTabs(char *title);
|
||||
void panelL_freeTabs(tPanel_tabs *tabs);
|
||||
|
||||
/* menu popup */
|
||||
tPanel_menu *panelL_newMenu(char *title);
|
||||
void panelL_freeMenu(tPanel_menu *menu);
|
||||
|
||||
/* textbot popup */
|
||||
tPanel_text *panelL_newText(char *title, char *text);
|
||||
void panelL_freeText(tPanel_text *text);
|
||||
|
||||
#undef COMMONPANELLIST
|
||||
|
||||
#endif
|
@ -1,25 +0,0 @@
|
||||
#ifndef PBOT_H
|
||||
#define PBOT_H
|
||||
|
||||
#include "laika.h"
|
||||
#include "lpeer.h"
|
||||
#include "lsodium.h"
|
||||
|
||||
#include "panel.h"
|
||||
|
||||
typedef struct sPanel_bot {
|
||||
uint8_t pub[crypto_kx_PUBLICKEYBYTES];
|
||||
char hostname[LAIKA_HOSTNAME_LEN], ipv4[LAIKA_IPV4_LEN];
|
||||
PEERTYPE type;
|
||||
tPanel_listItem *item;
|
||||
char *name; /* heap allocated string */
|
||||
} tPanel_bot;
|
||||
|
||||
tPanel_bot *panelB_newBot(uint8_t *pubKey, char *hostname, char *ipv4);
|
||||
void panelB_freeBot(tPanel_bot *bot);
|
||||
|
||||
/* search connected bots by public key */
|
||||
tPanel_bot *panelB_getBot(uint8_t *pubKey);
|
||||
void panelB_setItem(tPanel_bot *bot, tPanel_listItem *item);
|
||||
|
||||
#endif
|
@ -1,24 +0,0 @@
|
||||
#ifndef PCLIENT_H
|
||||
#define PCLIENT_H
|
||||
|
||||
#include "laika.h"
|
||||
#include "lpeer.h"
|
||||
#include "lpolllist.h"
|
||||
#include "pbot.h"
|
||||
|
||||
typedef struct sPanel_client {
|
||||
uint8_t priv[crypto_kx_SECRETKEYBYTES], pub[crypto_kx_PUBLICKEYBYTES];
|
||||
struct sLaika_pollList pList;
|
||||
struct sLaika_peer *peer;
|
||||
} tPanel_client;
|
||||
|
||||
tPanel_client *panelC_newClient();
|
||||
void panelC_freeClient(tPanel_client *client);
|
||||
|
||||
void panelC_connectToCNC(tPanel_client *client, char *ip, char *port); /* can throw a LAIKA_ERROR */
|
||||
bool panelC_poll(tPanel_client *client, int timeout);
|
||||
|
||||
void panelC_addBot(tPanel_bot *bot);
|
||||
void panelC_rmvBot(tPanel_bot *bot);
|
||||
|
||||
#endif
|
100
panel/src/main.c
100
panel/src/main.c
@ -1,100 +0,0 @@
|
||||
#include "laika.h"
|
||||
#include "lerror.h"
|
||||
|
||||
#include "panel.h"
|
||||
#include "pclient.h"
|
||||
|
||||
#define STRING(x) #x
|
||||
#define MACROLITSTR(x) STRING(x)
|
||||
|
||||
tPanel_client *client;
|
||||
tPanel_tabs *panel_tabList;
|
||||
tPanel_list *panel_botList;
|
||||
|
||||
void connectToCNC(void *uData) {
|
||||
tPanel_listItem *curr;
|
||||
int ch;
|
||||
|
||||
/* hide main menu */
|
||||
panelL_setHidden(panel_getActiveList(), true);
|
||||
|
||||
/* init global lists */
|
||||
panel_tabList = panelL_newTabs("Laika CNC Panel");
|
||||
panel_botList = panelL_newList();
|
||||
|
||||
/* init tabs */
|
||||
panelL_newListItem(&panel_tabList->list, NULL, "CNC Flags", NULL, NULL);
|
||||
panelL_newListItem(&panel_tabList->list, panel_botList, "Bot List", NULL, NULL);
|
||||
panelL_init(&panel_tabList->list);
|
||||
panelL_init(panel_botList);
|
||||
|
||||
addstr("Connecting to CNC with pubkey [" LAIKA_PUBKEY "]...");
|
||||
refresh();
|
||||
|
||||
client = panelC_newClient();
|
||||
panelC_connectToCNC(client, "127.0.0.1", "13337");
|
||||
|
||||
/* main panel loop */
|
||||
panel_pushActiveList(&panel_tabList->list);
|
||||
while ((ch = panel_getChar()) != 'q' && laikaS_isAlive((&client->peer->sock))) {
|
||||
if (!panel_tick(ch)) {
|
||||
/* if we got an event to handle, we *probably* have more events to handle so temporarily make ncurses non-blocking */
|
||||
if (panelC_poll(client, 0)) {
|
||||
panel_setTimeout(0); /* makes ncurses non-blocking */
|
||||
panel_draw();
|
||||
} else {
|
||||
/* wait to poll if we didn't receive any new messages */
|
||||
panel_setTimeout(PANEL_CURSES_TIMEOUT);
|
||||
}
|
||||
} else {
|
||||
/* we got input, redraw screen */
|
||||
panel_draw();
|
||||
}
|
||||
}
|
||||
|
||||
/* free bots in botList */
|
||||
curr = panel_botList->itemHead;
|
||||
while (curr != NULL) {
|
||||
panelB_freeBot(curr->uData);
|
||||
curr = curr->next;
|
||||
}
|
||||
|
||||
/* since panel_botList is a child of one of panel_tabList's items, it
|
||||
gets free'd with panel_tabList. so popping it frees both */
|
||||
panel_popActiveList();
|
||||
panelC_freeClient(client);
|
||||
|
||||
/* re-show main menu */
|
||||
panelL_setHidden(panel_getActiveList(), false);
|
||||
}
|
||||
|
||||
void quitLaika(void *uData) {
|
||||
LAIKA_ERROR("quit!\n");
|
||||
}
|
||||
|
||||
int main(int argv, char **argc) {
|
||||
tPanel_menu *menu;
|
||||
int ch;
|
||||
|
||||
/* init ncurses */
|
||||
panel_init();
|
||||
|
||||
menu = panelL_newMenu("Laika v" MACROLITSTR(LAIKA_VERSION_MAJOR) "." MACROLITSTR(LAIKA_VERSION_MINOR));
|
||||
panelL_newListItem(&menu->list, NULL, "Quit", quitLaika, NULL);
|
||||
panelL_newListItem(&menu->list, NULL, "- Connect to CNC", connectToCNC, NULL);
|
||||
|
||||
/* start main menu */
|
||||
panelL_init(&menu->list);
|
||||
panel_pushActiveList(&menu->list);
|
||||
LAIKA_TRY
|
||||
while ((ch = panel_getChar()) != 'q') {
|
||||
if (panel_tick(ch))
|
||||
panel_draw();
|
||||
}
|
||||
LAIKA_TRYEND
|
||||
panel_popActiveList();
|
||||
|
||||
/* cleanup */
|
||||
panel_cleanUp();
|
||||
return 0;
|
||||
}
|
@ -1,486 +0,0 @@
|
||||
#include <string.h>
|
||||
#include <ncurses.h>
|
||||
#include "lmem.h"
|
||||
#include "lerror.h"
|
||||
#include "panel.h"
|
||||
#include "pbot.h"
|
||||
|
||||
/* i don't expect to ever be 16 layers deep of menus */
|
||||
#define ACTIVESIZE 16
|
||||
|
||||
WINDOW *wmain;
|
||||
|
||||
tPanel_list *activeList[ACTIVESIZE] = { NULL };
|
||||
int activeListSize = -1;
|
||||
|
||||
void printTitle(WINDOW *win, char *text, int width, int x, int y) {
|
||||
int pad = (width - (strlen(text) + 4)) / 2;
|
||||
mvwprintw(win, y, x+pad, "| %s |", text);
|
||||
}
|
||||
|
||||
void printCenter(WINDOW *win, char *text, int width, int x, int y) {
|
||||
int strLength = strlen(text);
|
||||
int pad = (width - strLength) / 2;
|
||||
mvwprintw(win, y, x, "%*s%s%*s", pad, "", text, (width-pad-strLength), "");
|
||||
}
|
||||
|
||||
void printLine(WINDOW *win, char *text, int width, int x, int y) {
|
||||
int strLength = strlen(text);
|
||||
int pad = (width - strLength);
|
||||
mvwprintw(win, y, x, "%s%*s\n", text, pad, "");
|
||||
}
|
||||
|
||||
void panel_init() {
|
||||
if ((wmain = initscr()) == NULL)
|
||||
LAIKA_ERROR("Failed to init ncurses!");
|
||||
|
||||
activeListSize = -1;
|
||||
|
||||
/* setup ncurses */
|
||||
cbreak();
|
||||
noecho();
|
||||
timeout(1);
|
||||
keypad(stdscr, true);
|
||||
curs_set(0); /* hide the default screen cursor. */
|
||||
|
||||
refresh();
|
||||
}
|
||||
|
||||
void panel_cleanUp() {
|
||||
/* clean up ncurses */
|
||||
delwin(wmain);
|
||||
endwin();
|
||||
}
|
||||
|
||||
tPanel_list *panel_newBaseList(size_t sz, LISTTYPE type) {
|
||||
tPanel_list *list = laikaM_malloc(sz);
|
||||
|
||||
list->itemHead = NULL;
|
||||
list->selectedItem = NULL;
|
||||
list->win = NULL;
|
||||
list->x = 1;
|
||||
list->y = 0;
|
||||
list->height = 0;
|
||||
list->type = type;
|
||||
list->hidden = false;
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
void panel_freeBaseList(tPanel_list *list) {
|
||||
/* free linked list */
|
||||
tPanel_listItem *curr = list->itemHead, *last = NULL;
|
||||
|
||||
while(curr != NULL) {
|
||||
last = curr;
|
||||
curr = curr->next;
|
||||
if (last != NULL)
|
||||
panelL_freeListItem(list, last);
|
||||
}
|
||||
|
||||
/* remove ncurses window */
|
||||
wclear(list->win);
|
||||
delwin(list->win);
|
||||
|
||||
/* free list */
|
||||
laikaM_free(list);
|
||||
}
|
||||
|
||||
tPanel_list *panel_getActiveList() {
|
||||
return activeList[activeListSize];
|
||||
}
|
||||
|
||||
int panel_getChar() {
|
||||
/* if we have an activeList panel, grab the input from that otherwise return -1 */
|
||||
if (panel_getActiveList() != NULL)
|
||||
return wgetch(panel_getActiveList()->win);
|
||||
return -1;
|
||||
}
|
||||
|
||||
void panel_pushActiveList(tPanel_list *list) {
|
||||
/* set activeList window & draw */
|
||||
activeList[++activeListSize] = list;
|
||||
panelL_draw(panel_getActiveList());
|
||||
}
|
||||
|
||||
void panel_popActiveList() {
|
||||
panelL_freeList(activeList[activeListSize--]);
|
||||
|
||||
if (activeListSize >= 0)
|
||||
panelL_init(panel_getActiveList());
|
||||
}
|
||||
|
||||
void panel_draw(void) {
|
||||
int i;
|
||||
|
||||
/* draw active panels from bottom most (pushed first) to top most (pushed last)
|
||||
this way, new-er windows will be drawn on-top of older ones */
|
||||
clear();
|
||||
for (i = 0; i <= activeListSize; i++) {
|
||||
panelL_draw(activeList[i]);
|
||||
}
|
||||
}
|
||||
|
||||
bool panel_tick(int ch) {
|
||||
int i;
|
||||
/* tick each panel from top most (pushed last) to bottom most (pushed first)
|
||||
this way, the top-most windows/lists will be the most interactive */
|
||||
|
||||
for (i = activeListSize; i >= 0; i--) {
|
||||
if (panelL_tick(activeList[i], ch))
|
||||
return true;
|
||||
}
|
||||
|
||||
/* no ticks returned any results */
|
||||
return false;
|
||||
}
|
||||
|
||||
void panel_setTimeout(int timeout) {
|
||||
panelL_setTimeout(panel_getActiveList(), timeout);
|
||||
}
|
||||
|
||||
/* ==================================================[[ List ]]================================================== */
|
||||
|
||||
tPanel_list *panelL_newList(void) {
|
||||
return (tPanel_list*)panel_newBaseList(sizeof(tPanel_list), LIST_LIST);
|
||||
}
|
||||
|
||||
void panelL_freeList(tPanel_list *list) {
|
||||
panel_freeBaseList(list);
|
||||
}
|
||||
|
||||
void panelL_initList(tPanel_list *list) {
|
||||
tPanel_listItem *curr = list->itemHead;
|
||||
int numLines = 0;
|
||||
|
||||
/* count # of lines */
|
||||
while (curr != NULL) {
|
||||
numLines++;
|
||||
curr = curr->next;
|
||||
}
|
||||
|
||||
/* create ncurses window */
|
||||
list->x = 0;
|
||||
list->y = 2;
|
||||
list->width = COLS;
|
||||
list->height = numLines;
|
||||
list->win = newwin(list->height, list->width, list->y, list->x);
|
||||
keypad(list->win, TRUE); /* setup keyboard input */
|
||||
wtimeout(list->win, 0);
|
||||
}
|
||||
|
||||
void panelL_drawList(tPanel_list *list) {
|
||||
tPanel_listItem *curr = list->itemHead;
|
||||
int i = 0;
|
||||
|
||||
/* write each line */
|
||||
while (curr != NULL) {
|
||||
/* highlight selected option */
|
||||
if (curr == list->selectedItem)
|
||||
wattron(list->win, A_STANDOUT);
|
||||
|
||||
printLine(list->win, curr->name, list->width, 0, i++);
|
||||
wattroff(list->win, A_STANDOUT);
|
||||
curr = curr->next;
|
||||
}
|
||||
|
||||
/* push to screen */
|
||||
wrefresh(list->win);
|
||||
}
|
||||
|
||||
bool panelL_tickList(tPanel_list *list, int ch) {
|
||||
switch (ch) {
|
||||
case KEY_DOWN: panelL_nextItem(list); break;
|
||||
case KEY_UP: panelL_prevItem(list); break;
|
||||
default: return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ==================================================[[ Tabs ]]================================================== */
|
||||
|
||||
tPanel_tabs *panelL_newTabs(char *title) {
|
||||
tPanel_tabs *tabs = (tPanel_tabs*)panel_newBaseList(sizeof(tPanel_tabs), LIST_TABS);
|
||||
tabs->title = title;
|
||||
tabs->list.width = strlen(title) + 4;
|
||||
|
||||
return tabs;
|
||||
}
|
||||
|
||||
void panelL_freeTabs(tPanel_tabs *tabs) {
|
||||
panel_freeBaseList((tPanel_list*)tabs);
|
||||
}
|
||||
|
||||
void panelL_initTabs(tPanel_list *tabs) {
|
||||
tPanel_listItem *curr = tabs->itemHead;
|
||||
int numTabs = 0;
|
||||
|
||||
if (tabs->win)
|
||||
delwin(tabs->win);
|
||||
|
||||
/* get tab count */
|
||||
while (curr != NULL) {
|
||||
curr = curr->next;
|
||||
numTabs++;
|
||||
}
|
||||
|
||||
tabs->x = 0;
|
||||
tabs->y = 0;
|
||||
if (numTabs <= 1)
|
||||
tabs->width = COLS;
|
||||
else
|
||||
tabs->width = COLS/numTabs;
|
||||
tabs->height = 2;
|
||||
tabs->win = newwin(tabs->height, COLS, tabs->y, tabs->x);
|
||||
|
||||
keypad(tabs->win, true);
|
||||
wtimeout(tabs->win, 0);
|
||||
}
|
||||
|
||||
void panelL_drawTabs(tPanel_tabs *tabs) {
|
||||
tPanel_listItem *curr = tabs->list.itemHead;
|
||||
int i = 0;
|
||||
|
||||
/* write title */
|
||||
printCenter(tabs->list.win, tabs->title, COLS, 0, 0);
|
||||
|
||||
/* write each tab */
|
||||
while (curr != NULL) {
|
||||
/* highlight selected option */
|
||||
if (curr == tabs->list.selectedItem)
|
||||
wattron(tabs->list.win, A_STANDOUT);
|
||||
|
||||
printCenter(tabs->list.win, curr->name, tabs->list.width, (i++)*tabs->list.width, 1);
|
||||
curr = curr->next;
|
||||
wattroff(tabs->list.win, A_STANDOUT);
|
||||
}
|
||||
|
||||
/* draw tab */
|
||||
refresh();
|
||||
if (tabs->list.selectedItem && tabs->list.selectedItem->child)
|
||||
panelL_draw(tabs->list.selectedItem->child);
|
||||
|
||||
wrefresh(tabs->list.win);
|
||||
}
|
||||
|
||||
bool panelL_tickTabs(tPanel_tabs *tabs, int ch) {
|
||||
switch (ch) {
|
||||
case KEY_RIGHT: panelL_nextItem(&tabs->list); break;
|
||||
case KEY_LEFT: panelL_prevItem(&tabs->list); break;
|
||||
/* tick child */
|
||||
default: return (tabs->list.selectedItem && tabs->list.selectedItem->child) ? panelL_tick(tabs->list.selectedItem->child, ch) : false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ==================================================[[ Menu ]]================================================== */
|
||||
|
||||
tPanel_menu *panelL_newMenu(char *title) {
|
||||
tPanel_menu *menu = (tPanel_menu*)panel_newBaseList(sizeof(tPanel_menu), LIST_MENU);
|
||||
menu->title = title;
|
||||
menu->list.width = strlen(title) + 4;
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
void panelL_freeMenu(tPanel_menu *menu) {
|
||||
panel_freeBaseList((tPanel_list*)menu);
|
||||
}
|
||||
|
||||
void panelL_initMenu(tPanel_list *menu) {
|
||||
tPanel_listItem *curr = menu->itemHead;
|
||||
|
||||
if (menu->win)
|
||||
delwin(menu->win);
|
||||
|
||||
/* get max line length & menu height */
|
||||
menu->height = 2;
|
||||
while (curr != NULL) {
|
||||
if (curr->width+6 > menu->width)
|
||||
menu->width = curr->width+6;
|
||||
|
||||
curr = curr->next;
|
||||
menu->height++;
|
||||
}
|
||||
|
||||
menu->y = (LINES-menu->height)/2;
|
||||
menu->x = (COLS-menu->width)/2;
|
||||
|
||||
menu->win = newwin(menu->height, menu->width, menu->y, menu->x);
|
||||
keypad(menu->win, true);
|
||||
wtimeout(menu->win, 0);
|
||||
}
|
||||
|
||||
void panelL_drawMenu(tPanel_menu *menu) {
|
||||
tPanel_listItem *curr = menu->list.itemHead;
|
||||
int i = 1;
|
||||
|
||||
/* write each line */
|
||||
while (curr != NULL) {
|
||||
/* highlight selected option */
|
||||
if (curr == menu->list.selectedItem)
|
||||
wattron(menu->list.win, A_STANDOUT);
|
||||
|
||||
printLine(menu->list.win, curr->name, menu->list.width-4, 2, i++);
|
||||
wattroff(menu->list.win, A_STANDOUT);
|
||||
curr = curr->next;
|
||||
}
|
||||
|
||||
/* write the title & border */
|
||||
box(menu->list.win, 0, 0);
|
||||
printTitle(menu->list.win, menu->title, menu->list.width, 0, 0);
|
||||
|
||||
/* push to screen */
|
||||
wrefresh(menu->list.win);
|
||||
}
|
||||
|
||||
bool panelL_tickMenu(tPanel_menu *menu, int ch) {
|
||||
switch (ch) {
|
||||
case KEY_UP: panelL_prevItem(&menu->list); break;
|
||||
case KEY_DOWN: panelL_nextItem(&menu->list); break;
|
||||
case '\n': case KEY_ENTER: panelL_selectItem(&menu->list); break;
|
||||
default: return false;
|
||||
}
|
||||
|
||||
panelL_drawMenu(menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ==================================================[[ Text ]]================================================== */
|
||||
|
||||
tPanel_text *panelL_newText(char *title, char *text) {
|
||||
tPanel_text *textP = (tPanel_text*)panel_newBaseList(sizeof(tPanel_text), LIST_TEXT);
|
||||
textP->title = title;
|
||||
textP->list.width = strlen(title) + 4;
|
||||
|
||||
return textP;
|
||||
}
|
||||
|
||||
void panelL_freeText(tPanel_text *textP) {
|
||||
panel_freeBaseList((tPanel_list*)textP);
|
||||
}
|
||||
|
||||
/* ==============================================[[ Panel Direct ]]============================================== */
|
||||
|
||||
tPanel_listItem *panelL_newListItem(tPanel_list *list, tPanel_list *child, char *name, panelCallback callback, void *uData) {
|
||||
tPanel_listItem *item = laikaM_malloc(sizeof(tPanel_listItem));
|
||||
|
||||
item->child = child;
|
||||
item->callback = callback;
|
||||
item->uData = uData;
|
||||
item->name = name;
|
||||
item->last = NULL;
|
||||
item->next = NULL;
|
||||
item->width = strlen(name);
|
||||
item->height = 1;
|
||||
item->x = 0;
|
||||
item->y = 0;
|
||||
|
||||
/* add to list */
|
||||
if (list->itemHead)
|
||||
list->itemHead->last = item;
|
||||
|
||||
item->next = list->itemHead;
|
||||
list->itemHead = item;
|
||||
list->selectedItem = item;
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
void panelL_freeListItem(tPanel_list *list, tPanel_listItem *item) {
|
||||
if (list->itemHead == item) {
|
||||
if (item->next)
|
||||
item->next->last = NULL;
|
||||
list->itemHead = item->next;
|
||||
} else {
|
||||
/* unlink from list */
|
||||
if (item->last)
|
||||
item->last->next = item->next;
|
||||
|
||||
if (item->next)
|
||||
item->next->last = item->last;
|
||||
}
|
||||
|
||||
/* free child */
|
||||
if (item->child)
|
||||
panelL_freeList(item->child);
|
||||
|
||||
/* update selected item */
|
||||
if (list->selectedItem == item)
|
||||
list->selectedItem = list->itemHead;
|
||||
|
||||
laikaM_free(item);
|
||||
}
|
||||
|
||||
void panelL_nextItem(tPanel_list *list) {
|
||||
if (!list->selectedItem || !list->selectedItem->next) /* sanity check */
|
||||
return;
|
||||
|
||||
list->selectedItem = list->selectedItem->next;
|
||||
}
|
||||
|
||||
void panelL_prevItem(tPanel_list *list) {
|
||||
if (!list->selectedItem || !list->selectedItem->last) /* sanity check */
|
||||
return;
|
||||
|
||||
list->selectedItem = list->selectedItem->last;
|
||||
}
|
||||
|
||||
void panelL_selectItem(tPanel_list *list) {
|
||||
if (!list->selectedItem || !list->selectedItem->callback) /* sanity check */
|
||||
return;
|
||||
|
||||
list->selectedItem->callback(list->selectedItem->uData);
|
||||
}
|
||||
|
||||
void panelL_init(tPanel_list *list) {
|
||||
switch (list->type) {
|
||||
case LIST_LIST: panelL_initList(list); break;
|
||||
case LIST_TABS: panelL_initTabs(list); break;
|
||||
case LIST_MENU: panelL_initMenu(list); break;
|
||||
default: LAIKA_ERROR("Malformed tPanel_list!\n"); break;
|
||||
}
|
||||
}
|
||||
|
||||
void panelL_free(tPanel_list *list) {
|
||||
switch (list->type) {
|
||||
case LIST_LIST: panelL_freeList(list); break;
|
||||
case LIST_TABS: panelL_freeTabs((tPanel_tabs*)list); break;
|
||||
case LIST_MENU: panelL_freeMenu((tPanel_menu*)list); break;
|
||||
default: LAIKA_ERROR("Malformed tPanel_list!\n"); break;
|
||||
}
|
||||
}
|
||||
|
||||
void panelL_draw(tPanel_list *list) {
|
||||
if (list->hidden) /* don't draw a hidden list */
|
||||
return;
|
||||
|
||||
switch (list->type) {
|
||||
case LIST_LIST: panelL_drawList(list); break;
|
||||
case LIST_TABS: panelL_drawTabs((tPanel_tabs*)list); break;
|
||||
case LIST_MENU: panelL_drawMenu((tPanel_menu*)list); break;
|
||||
default: LAIKA_ERROR("Malformed tPanel_list!\n"); break;
|
||||
}
|
||||
}
|
||||
|
||||
bool panelL_tick(tPanel_list *list, int ch) {
|
||||
if (list->hidden) /* don't tick a hidden list */
|
||||
return false;
|
||||
|
||||
switch (list->type) {
|
||||
case LIST_LIST: return panelL_tickList(list, ch);
|
||||
case LIST_TABS: return panelL_tickTabs((tPanel_tabs*)list, ch);
|
||||
case LIST_MENU: return panelL_tickMenu((tPanel_menu*)list, ch);
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
void panelL_setHidden(tPanel_list *list, bool hidden) {
|
||||
list->hidden = hidden;
|
||||
}
|
||||
|
||||
void panelL_setTimeout(tPanel_list *list, int timeout) {
|
||||
wtimeout(list->win, timeout);
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
#include "lmem.h"
|
||||
#include "lerror.h"
|
||||
#include "pbot.h"
|
||||
|
||||
#include "panel.h"
|
||||
|
||||
tPanel_bot *panelB_newBot(uint8_t *pubKey, char *hostname, char *ipv4) {
|
||||
tPanel_bot *bot = laikaM_malloc(sizeof(tPanel_bot));
|
||||
int length;
|
||||
|
||||
/* copy pubKey to bot's pubKey */
|
||||
memcpy(bot->pub, pubKey, crypto_kx_PUBLICKEYBYTES);
|
||||
|
||||
/* copy hostname & ipv4 */
|
||||
memcpy(bot->hostname, hostname, LAIKA_HOSTNAME_LEN);
|
||||
memcpy(bot->ipv4, ipv4, LAIKA_IPV4_LEN);
|
||||
|
||||
/* restore NULL terminators */
|
||||
bot->hostname[LAIKA_HOSTNAME_LEN-1] = 0;
|
||||
bot->ipv4[LAIKA_IPV4_LEN-1] = 0;
|
||||
|
||||
/* make bot name */
|
||||
length = strlen(bot->hostname) + 1 + strlen(bot->ipv4) + 1;
|
||||
bot->name = laikaM_malloc(length);
|
||||
sprintf(bot->name, "%s@%s", bot->hostname, bot->ipv4);
|
||||
|
||||
return bot;
|
||||
}
|
||||
|
||||
void panelB_freeBot(tPanel_bot *bot) {
|
||||
laikaM_free(bot->name);
|
||||
laikaM_free(bot);
|
||||
}
|
||||
|
||||
/* search connected bots by public key */
|
||||
tPanel_bot *panelB_getBot(uint8_t *pubKey) {
|
||||
tPanel_listItem *curr = panel_botList->itemHead;
|
||||
tPanel_bot *bot;
|
||||
|
||||
while (curr != NULL) {
|
||||
bot = (tPanel_bot*)curr->uData;
|
||||
|
||||
/* check pubKeys */
|
||||
if (memcmp(pubKey, bot->pub, crypto_kx_PUBLICKEYBYTES) == 0)
|
||||
return bot; /* they match! */
|
||||
|
||||
curr = curr->next;
|
||||
}
|
||||
|
||||
/* no match found :( */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void panelB_setItem(tPanel_bot *bot, tPanel_listItem *item) {
|
||||
bot->item = item;
|
||||
}
|
@ -1,202 +0,0 @@
|
||||
#include "lmem.h"
|
||||
#include "lerror.h"
|
||||
#include "pclient.h"
|
||||
#include "panel.h"
|
||||
|
||||
void handleHandshakeResponse(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData) {
|
||||
tPanel_client *client = (tPanel_client*)uData;
|
||||
uint8_t endianness = laikaS_readByte(&peer->sock);
|
||||
|
||||
peer->sock.flipEndian = endianness != laikaS_isBigEndian();
|
||||
}
|
||||
|
||||
void handleAddPeer(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData) {
|
||||
char hostname[LAIKA_HOSTNAME_LEN], ipv4[LAIKA_IPV4_LEN];
|
||||
uint8_t pubKey[crypto_kx_PUBLICKEYBYTES];
|
||||
uint8_t type;
|
||||
|
||||
/* read newly connected peer's pubKey */
|
||||
laikaS_read(&peer->sock, pubKey, crypto_kx_PUBLICKEYBYTES);
|
||||
|
||||
/* read hostname & ipv4 */
|
||||
laikaS_read(&peer->sock, hostname, LAIKA_HOSTNAME_LEN);
|
||||
laikaS_read(&peer->sock, ipv4, LAIKA_IPV4_LEN);
|
||||
|
||||
/* read peer's peerType */
|
||||
type = laikaS_readByte(&peer->sock);
|
||||
|
||||
/* add peer */
|
||||
switch (type) {
|
||||
case PEER_BOT: {
|
||||
tPanel_bot *bot = panelB_newBot(pubKey, hostname, ipv4);
|
||||
panelC_addBot(bot);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LAIKA_WARN("unknown peer type? [%d]\n", type);
|
||||
}
|
||||
}
|
||||
|
||||
void handleRmvPeer(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData) {
|
||||
uint8_t pubKey[crypto_kx_PUBLICKEYBYTES];
|
||||
uint8_t type;
|
||||
|
||||
/* read newly connected peer's pubKey */
|
||||
laikaS_read(&peer->sock, pubKey, crypto_kx_PUBLICKEYBYTES);
|
||||
|
||||
/* read peer's peerType */
|
||||
type = laikaS_readByte(&peer->sock);
|
||||
|
||||
/* find peer by pubkey & rmv it */
|
||||
switch (type) {
|
||||
case PEER_BOT: {
|
||||
tPanel_bot *bot = panelB_getBot(pubKey);
|
||||
if (bot != NULL)
|
||||
panelC_rmvBot(bot);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LAIKA_WARN("unknown peer type? [%d]\n", type);
|
||||
}
|
||||
}
|
||||
|
||||
LAIKAPKT_SIZE panelC_pktSizeTbl[LAIKAPKT_MAXNONE] = {
|
||||
[LAIKAPKT_HANDSHAKE_RES] = sizeof(uint8_t),
|
||||
[LAIKAPKT_AUTHENTICATED_ADD_PEER_RES] = crypto_kx_PUBLICKEYBYTES + sizeof(uint8_t) + LAIKA_HOSTNAME_LEN + LAIKA_IPV4_LEN, /* pubkey + peerType + host + ip */
|
||||
[LAIKAPKT_AUTHENTICATED_RMV_PEER_RES] = crypto_kx_PUBLICKEYBYTES + sizeof(uint8_t), /* pubkey + peerType */
|
||||
};
|
||||
|
||||
PeerPktHandler panelC_handlerTbl[LAIKAPKT_MAXNONE] = {
|
||||
[LAIKAPKT_HANDSHAKE_RES] = handleHandshakeResponse,
|
||||
[LAIKAPKT_AUTHENTICATED_ADD_PEER_RES] = handleAddPeer,
|
||||
[LAIKAPKT_AUTHENTICATED_RMV_PEER_RES] = handleRmvPeer,
|
||||
};
|
||||
|
||||
tPanel_client *panelC_newClient() {
|
||||
tPanel_client *client = laikaM_malloc(sizeof(tPanel_client));
|
||||
size_t _unused;
|
||||
|
||||
laikaP_initPList(&client->pList);
|
||||
client->peer = laikaS_newPeer(
|
||||
panelC_handlerTbl,
|
||||
panelC_pktSizeTbl,
|
||||
&client->pList,
|
||||
(void*)client
|
||||
);
|
||||
|
||||
/* load authenticated keypair */
|
||||
if (sodium_init() < 0) {
|
||||
panelC_freeClient(client);
|
||||
LAIKA_ERROR("LibSodium failed to initialize!\n");
|
||||
}
|
||||
|
||||
if (sodium_hex2bin(client->pub, crypto_kx_PUBLICKEYBYTES, LAIKA_PUBKEY, strlen(LAIKA_PUBKEY), NULL, &_unused, NULL) != 0) {
|
||||
panelC_freeClient(client);
|
||||
LAIKA_ERROR("Failed to init public key!\n");
|
||||
}
|
||||
|
||||
if (sodium_hex2bin(client->priv, crypto_kx_SECRETKEYBYTES, LAIKA_PRIVKEY, strlen(LAIKA_PRIVKEY), NULL, &_unused, NULL) != 0) {
|
||||
panelC_freeClient(client);
|
||||
LAIKA_ERROR("Failed to init private key!\n");
|
||||
}
|
||||
|
||||
/* read cnc's public key into peerPub */
|
||||
if (sodium_hex2bin(client->peer->peerPub, crypto_kx_PUBLICKEYBYTES, LAIKA_PUBKEY, strlen(LAIKA_PUBKEY), NULL, &_unused, NULL) != 0) {
|
||||
panelC_freeClient(client);
|
||||
LAIKA_ERROR("Failed to init cnc public key!\n");
|
||||
}
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
void panelC_freeClient(tPanel_client *client) {
|
||||
laikaS_freePeer(client->peer);
|
||||
laikaP_cleanPList(&client->pList);
|
||||
laikaM_free(client);
|
||||
}
|
||||
|
||||
void panelC_connectToCNC(tPanel_client *client, char *ip, char *port) {
|
||||
struct sLaika_socket *sock = &client->peer->sock;
|
||||
|
||||
/* setup socket */
|
||||
laikaS_connect(sock, ip, port);
|
||||
laikaS_setNonBlock(sock);
|
||||
|
||||
laikaP_addSock(&client->pList, sock);
|
||||
|
||||
/* queue handshake request */
|
||||
laikaS_startOutPacket(client->peer, LAIKAPKT_HANDSHAKE_REQ);
|
||||
laikaS_write(sock, LAIKA_MAGIC, LAIKA_MAGICLEN);
|
||||
laikaS_writeByte(sock, LAIKA_VERSION_MAJOR);
|
||||
laikaS_writeByte(sock, LAIKA_VERSION_MINOR);
|
||||
laikaS_write(sock, client->pub, sizeof(client->pub)); /* write public key */
|
||||
|
||||
/* write stub hostname & ipv4 (since we're a panel/dummy client, cnc doesn't need this information really) */
|
||||
laikaS_zeroWrite(sock, LAIKA_HOSTNAME_LEN);
|
||||
laikaS_zeroWrite(sock, LAIKA_IPV4_LEN);
|
||||
laikaS_endOutPacket(client->peer);
|
||||
laikaS_setSecure(client->peer, true);
|
||||
|
||||
if (crypto_kx_client_session_keys(client->peer->inKey, client->peer->outKey, client->pub, client->priv, client->peer->peerPub) != 0)
|
||||
LAIKA_ERROR("failed to gen session key!\n");
|
||||
|
||||
/* queue authenticated handshake request */
|
||||
laikaS_startOutPacket(client->peer, LAIKAPKT_AUTHENTICATED_HANDSHAKE_REQ);
|
||||
laikaS_writeByte(sock, PEER_AUTH);
|
||||
laikaS_endOutPacket(client->peer);
|
||||
|
||||
if (!laikaS_handlePeerOut(client->peer))
|
||||
LAIKA_ERROR("failed to send handshake request!\n");
|
||||
}
|
||||
|
||||
bool panelC_poll(tPanel_client *client, int timeout) {
|
||||
struct sLaika_pollEvent *evnt;
|
||||
int numEvents;
|
||||
|
||||
evnt = laikaP_poll(&client->pList, timeout, &numEvents);
|
||||
|
||||
if (numEvents == 0) /* no events? timeout was reached */
|
||||
return false;
|
||||
|
||||
LAIKA_TRY
|
||||
if (evnt->pollIn && !laikaS_handlePeerIn(client->peer))
|
||||
goto _CLIENTKILL;
|
||||
|
||||
if (evnt->pollOut && !laikaS_handlePeerOut(client->peer))
|
||||
goto _CLIENTKILL;
|
||||
|
||||
if (!evnt->pollIn && !evnt->pollOut)
|
||||
goto _CLIENTKILL;
|
||||
LAIKA_CATCH
|
||||
_CLIENTKILL:
|
||||
laikaS_kill(&client->peer->sock);
|
||||
LAIKA_TRYEND
|
||||
|
||||
/* flush pList's outQueue */
|
||||
if (client->pList.outCount > 0) {
|
||||
if (!laikaS_handlePeerOut(client->peer))
|
||||
laikaS_kill(&client->peer->sock);
|
||||
|
||||
laikaP_resetOutQueue(&client->pList);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void panelC_addBot(tPanel_bot *bot) {
|
||||
tPanel_listItem *bItem;
|
||||
|
||||
/* add to botList tab */
|
||||
bItem = panelL_newListItem(panel_botList, NULL, bot->name, NULL, (void*)bot);
|
||||
|
||||
/* link bot with listItem */
|
||||
panelB_setItem(bot, bItem);
|
||||
}
|
||||
|
||||
void panelC_rmvBot(tPanel_bot *bot) {
|
||||
tPanel_listItem *bItem = bot->item;
|
||||
|
||||
/* free from bot list & then free the bot */
|
||||
panelL_freeListItem(panel_botList, bItem);
|
||||
panelB_freeBot(bot);
|
||||
}
|
Loading…
Reference in New Issue
Block a user