New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details →
Socket
Book a DemoSign in
Socket

@tty-pt/ndc

Package Overview
Dependencies
Maintainers
1
Versions
205
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@tty-pt/ndc

ndc example project

latest
Source
npmnpm
Version
1.0.0
Version published
Maintainers
1
Created
Source

ndc

HTTP(S) + WS(S) + Terminal MUX

A cross-platform C library for building network daemons - HTTP servers, WebSocket servers, telnet-like services, terminal multiplexers, or custom network applications.

From NeverDark • Powers tty.pt

What is ndc?

libndc - C library for building network daemons
ndc - Standalone server binary with HTTP/WS/terminal mux

Build telnet-like servers, custom protocol handlers, HTTP APIs, WebSocket apps, or anything that needs persistent network connections with an event loop.

Platform Support

PlatformStatus
Linux, macOS, BSD✅ Full support
Windows⚠️ HTTP/WS only (no PTY/CGI/privilege dropping)

Quick Start

# Run simple HTTP server
ndc -d -p 8888

# With SSL (POSIX)
sudo ndc -C . -K certs.txt -d

Command Line Options

OptionDescription
-p PORTSpecify HTTP server port
-s PORTSpecify HTTPS server port (POSIX)
-C PATHChange directory to PATH before starting
-K PATHLoad SSL certificate mappings from file (POSIX)
-k CERTAdd single SSL certificate mapping (POSIX)
-dDon't detach (run in foreground)
-rRoot multiplex mode
-?Display help message

certs.txt Format (POSIX)

example.com:cert.pem:key.pem

Building Custom Daemons

Minimal Example

#include <ttypt/ndc.h>

int main(void) {
    ndc_config.port = 8080;
    ndc_register("GET", do_GET, CF_NOAUTH);
    return ndc_main();  // Blocks, runs event loop
}

Telnet-Style Server

void cmd_echo(socket_t fd, int argc, char *argv[]) {
    for (int i = 0; i < argc; i++)
        ndc_writef(fd, "%s ", argv[i]);
    ndc_writef(fd, "\n");
}

int ndc_connect(socket_t fd) {
    ndc_writef(fd, "Welcome! Type 'echo hello'\n");
    return 1;  // Accept connection
}

int main(void) {
    ndc_config.port = 2323;
    ndc_register("echo", cmd_echo, CF_NOAUTH);
    return ndc_main();
}

Custom Protocol Handler

void my_handler(socket_t fd, char *body) {
    // Handle raw data from client
    ndc_write(fd, "RESPONSE", 8);
}

void ndc_command(socket_t fd, int argc, char *argv[]) {
    // Called on every command
    log_command(argv[0]);
}

void ndc_update(unsigned long long dt) {
    // Periodic tick (game loops, etc)
}

Library API

Core Functions

FunctionDescriptionReturn Value
ndc_main()Start event loop (blocking)Exit code
ndc_register(name, cb, flags)Register command handler-
ndc_register_handler(path, handler)Register HTTP handler for exact path-
ndc_write(fd, data, len)Write raw bytesBytes written or -1
ndc_writef(fd, fmt, ...)Write formatted dataBytes written or -1
ndc_dwritef(fd, fmt, va)Write formatted data with va_listBytes written or -1
ndc_close(fd)Close connection-
ndc_wall(msg)Broadcast message to all descriptors-

HTTP Functions

FunctionDescriptionReturn Value
ndc_header(fd, key, val)Add response header (call before ndc_head)-
ndc_head(fd, code)Send HTTP status and headers-
ndc_body(fd, body)Send body and close connection-
ndc_sendfile(fd, path)Serve static file with auto MIME type-
ndc_status_text(code)Get HTTP status text for codeStatus string

Descriptor Functions

FunctionDescriptionReturn Value
ndc_flags(fd)Get descriptor flagsFlags bitmask
ndc_set_flags(fd, flags)Set descriptor flags-

Request Environment Functions

FunctionDescriptionReturn Value
ndc_env_get(fd, target, key)Get request environment value0 on success
ndc_env_put(fd, key, value)Set environment key/value0 on success
ndc_env_clear(fd)Clear request environment-
ndc_env(fd)Get internal env handle (advanced)Env handle

POSIX-Only Functions

FunctionDescriptionReturn Value
ndc_pty(fd, args[])Spawn PTY-backed command-
ndc_exec(fd, args[], cb, input, len)Execute command with callback-
ndc_auth(fd, username)Mark user as authenticated, drop privileges (POSIX)0 on success, 1 on failure
ndc_cert_add(str)Add cert mapping: domain:cert.pem:key.pem-
ndc_certs_add(fname)Load certificate mappings from file-
ndc_mmap(mapped, file)Map file into memoryFile size or -1
ndc_mmap_iter(start, pos)Iterate mapped lines separated by \nNext line or NULL
ndc_sendfile(fd, path)Serve static file (POSIX uses sendfile syscall)-

Built-in Command Handlers

HandlerDescription
do_GETHTTP GET request handler
do_POSTHTTP POST request handler
do_shShell PTY handler (POSIX-only)

Hook Functions (Optional)

Define these weak symbol hooks to customize behavior:

HookDescriptionReturn Value
ndc_connect(socket_t fd)Accept/reject WebSocket connectionsNon-zero to accept
ndc_disconnect(socket_t fd)Cleanup on disconnect-
ndc_accept(socket_t fd)Called on socket acceptIgnored
ndc_command(socket_t fd, int argc, char *argv[])Before command execution-
ndc_flush(socket_t fd, int argc, char *argv[])After command execution-
ndc_vim(socket_t fd, int argc, char *argv[])Called when command not found-
ndc_update(unsigned long long dt)Periodic updates (dt in milliseconds)-
ndc_auth_check(socket_t fd)Custom auth hook: validate credentials, return username. Default: session file lookup in ./sessions/Username string or NULL

Example:

int ndc_connect(socket_t fd) {
    ndc_writef(fd, "Welcome!\n");
    return 1;  // Accept connection
}

void ndc_disconnect(socket_t fd) {
    // Cleanup resources
}

void ndc_command(socket_t fd, int argc, char *argv[]) {
    // Log or validate commands
}

void ndc_flush(socket_t fd, int argc, char *argv[]) {
    // Post-command processing
}

void ndc_vim(socket_t fd, int argc, char *argv[]) {
    ndc_writef(fd, "Unknown command: %s\n", argv[0]);
}

void ndc_update(unsigned long long dt) {
    // Game loop, periodic tasks, etc.
}

char *ndc_auth_check(socket_t fd) {
    // Check cookies, tokens, etc.
    // Return username or NULL
    return authenticated_user;
}

Configuration

struct ndc_config {
    char *chroot;                    // chroot directory (POSIX)
    unsigned flags;                  // Server flags (see below)
    unsigned port;                   // HTTP listen port
    unsigned ssl_port;               // HTTPS listen port (POSIX)
    ndc_handler_t *default_handler;  // Fallback HTTP handler
};

// Example usage
ndc_config.port = 8080;              // HTTP on port 8080
ndc_config.ssl_port = 8443;          // HTTPS on port 8443 (POSIX)
ndc_config.flags = NDC_SSL;          // Enable TLS
ndc_config.chroot = "/var/www";      // chroot directory (POSIX)
ndc_config.default_handler = my_404; // Custom 404 handler

Server Flags

FlagDescription
NDC_WAKEWake on activity
NDC_SSLEnable TLS/SSL
NDC_ROOTRoot multiplex mode
NDC_SSL_ONLYRedirect HTTP to HTTPS when SSL enabled
NDC_DETACHDetach into background (daemon mode)

Command Flags

Use with ndc_register():

FlagDescription
CF_NOAUTHAllow command without authentication
CF_NOTRIMDo not trim trailing CR from input

Descriptor Flags

Access with ndc_flags() and ndc_set_flags():

FlagDescription
DF_CONNECTEDConnection established and accepted
DF_WEBSOCKETWebSocket mode enabled
DF_TO_CLOSEMarked to close after remaining output
DF_ACCEPTEDAccepted socket (pre-WebSocket)
DF_AUTHENTICATEDUser authenticated

POSIX vs Windows

FeaturePOSIXWindows
HTTP/WebSocket
Custom commands
PTY/Terminal
CGI execution
Authentication (privilege dropping)
SSL certs

Windows build provides core networking only.

CGI & Static Files (POSIX)

Create index.sh for dynamic pages:

#!/bin/sh
# CGI scripts output status line without "HTTP/1.1" prefix
printf "200 OK\r\n"
printf "Content-Type: text/plain\r\n"
printf "\r\n"
printf "Hello world\n"
printf "REQUEST_METHOD=%s\n" "$REQUEST_METHOD"
printf "QUERY_STRING=%s\n" "$QUERY_STRING"

Control access with serve.allow and serve.autoindex files.

NPM for Web Terminal

Install the package:

npm install @tty-pt/ndc

JavaScript/TypeScript API:

import { create } from "@tty-pt/ndc";

// Create terminal instance
const term = create(document.getElementById("terminal"), {
  proto: "ws",        // or "wss" for secure
  port: 4201,
  sub: {
    onOpen: (term, ws) => {
      console.log("Connected to server");
    },
    onClose: (ws) => {
      console.log("Disconnected, reconnecting...");
    },
    onMessage: (ev, arr) => {
      // Return true to continue default processing
      return true;
    },
    cols: 80,
    rows: 25,
  },
  debug: false,
});

See types/ndc.d.ts for full TypeScript definitions.

Documentation

  • Man pages: man ndc and man ndc.3
  • Full API: include/ttypt/ndc.h
  • Examples: src/test-*.c

Plugin System

Load dynamic modules with dependency resolution via libndx:

// In your plugin module
const char *ndx_deps[] = { "dependency.so", NULL };

// In main application
ndx_load("plugin.so");  // Automatically loads dependencies

The binary automatically loads core.so at startup. Plugins can hook into lifecycle events (ndc_update, ndc_connect, etc.) to extend functionality.

Installation: See install docs
Entry points: src/ndc.c (native), ndc-cli.js (npm)

Keywords

ndc

FAQs

Package last updated on 23 Feb 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts