Skip to content

xlanor/wg-nx

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

wg-nx

Note: This is a personal project, and as such, I will most likely not provide any support at all for this outside of personal use cases

Userland WireGuard library for Nintendo Switch.

tester

Cryptography

Algorithm Implementation Reference
ChaCha20 ARM NEON (src/wg_chacha20_neon.c) RFC 8439
Poly1305 ARM NEON (src/wg_poly1305_neon.c) RFC 8439
BLAKE2s ARM NEON (src/blake2s_neon.c) RFC 7693
X25519 ECDH Monocypher RFC 7748

Monocypher provides X25519 and is used as a reference for verifying NEON correctness in tests.

Protocol

Component Reference
WireGuard WireGuard Whitepaper
Noise IKpsk2 Noise Protocol Framework

API

Error Codes

typedef enum {
    WG_OK = 0,
    WG_ERR_INVALID_CONFIG = -1,
    WG_ERR_SOCKET = -2,
    WG_ERR_HANDSHAKE = -3,
    WG_ERR_TIMEOUT = -4,
    WG_ERR_DECRYPT = -5,
    WG_ERR_NOT_CONNECTED = -6,
    WG_ERR_BUFFER_TOO_SMALL = -7,
    WG_ERR_THREAD = -8,
    WG_ERR_ALREADY_RUNNING = -9,
} WgError;

Configuration

#define WG_KEY_LEN 32
#define WG_MAX_ENDPOINT 256

typedef struct {
    uint8_t private_key[WG_KEY_LEN];
    struct in_addr tunnel_ip;
    uint8_t peer_public_key[WG_KEY_LEN];
    char endpoint_host[WG_MAX_ENDPOINT];
    uint16_t endpoint_port;
    uint16_t keepalive_interval;
    uint8_t preshared_key[WG_KEY_LEN];
    int has_preshared_key;
} WgConfig;

Tunnel Lifecycle

WgTunnel* wg_init(const WgConfig* config);
int wg_connect(WgTunnel* tun);
int wg_start(WgTunnel* tun);
void wg_stop(WgTunnel* tun);
void wg_close(WgTunnel* tun);

Send/Receive

/* Zero-copy recv callback. `data` lives inside `slot`.
 *   Return 0  -> slot is auto-released on return (simple synchronous consumers).
 *   Return !0 -> callback takes ownership; must later call
 *                wg_recv_slot_release(tun, slot) exactly once. */
typedef int (*WgRecvCallback)(void* user, WgRecvSlot* slot, const void* data, size_t len);

int wg_send(WgTunnel* tun, const void* data, size_t len);
int wg_recv(WgTunnel* tun, void* buf, size_t len, int timeout_ms);
void wg_set_recv_callback(WgTunnel* tun, WgRecvCallback cb, void* user);
void wg_recv_slot_release(WgTunnel* tun, WgRecvSlot* slot);

Session Management

int wg_rekey(WgTunnel* tun);
uint32_t wg_get_session_index(WgTunnel* tun);
int wg_get_ip(WgTunnel* tun, struct in_addr* addr);

Key Utilities

void wg_generate_keypair(uint8_t private_key[WG_KEY_LEN], uint8_t public_key[WG_KEY_LEN]);
int wg_key_from_base64(uint8_t key[WG_KEY_LEN], const char* base64);
int wg_key_to_base64(char* base64, size_t len, const uint8_t key[WG_KEY_LEN]);

Logging

void wg_set_log_callback(void (*func)(const char* msg));

UDP Relay

For apps that expect a normal UDP socket:

typedef struct WgRelay WgRelay;

WgRelay* wg_relay_create(WgTunnel* tun, uint16_t local_port);
int wg_relay_start(WgRelay* relay);
void wg_relay_stop(WgRelay* relay);
void wg_relay_destroy(WgRelay* relay);
uint16_t wg_relay_get_port(WgRelay* relay);

lwIP TCP/UDP Relay

For apps that need full TCP/UDP connectivity over the tunnel, the lwip-relay/ module provides a relay using the lwIP TCP/IP stack.

namespace wgnx {

enum class LogLevel {
    Debug,
    Info,
    Error
};

struct LwipRelayConfig {
    std::function<void(LogLevel level, const char* message)> log_callback;
    std::function<void()> thread_affinity_callback;
    bool debug_logging = false;
};

class LwipRelay {
public:
    explicit LwipRelay(WgTunnel* tunnel, const LwipRelayConfig& config = {});
    ~LwipRelay();

    bool start(const std::string& tunnelIp, const std::string& targetIp);
    void stop();

    uint16_t startTcpRelay(uint16_t targetPort, uint16_t localPort);
    uint16_t startUdpRelay(uint16_t targetPort, uint16_t localPort);

    void tick();

    bool isRunning() const;
};

}

LwipRelay::start() installs its own zero-copy recv callback on the tunnel; no manual wg_set_recv_callback wiring is required. The relay must be stopped (or destroyed, which stops it) before wg_close(tun).

Example

#include <wg_lwip_relay.hpp>

wgnx::LwipRelayConfig config;
config.log_callback = [](wgnx::LogLevel level, const char* msg) {
    printf("[WG] %s\n", msg);
};
config.debug_logging = false;

wgnx::LwipRelay relay(tunnel, config);
relay.start("10.0.0.2", "10.0.0.1");

relay.startTcpRelay(9295, 9295);
relay.startUdpRelay(9296, 9296);

relay.stop();

Testing

wg-tester/ provides a borealis app that tests crypto primitives, threading, and a small integration rekey test against the publicly available wireguard demo server.

./dev.sh --build-only
./dev.sh <SWITCH_IP>

About

Experimental userland wireguard library for NX

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors