NEWv0.1.0, the first tagged release, is out →

The proxy core you can
read in an afternoon.

Shadowsocks, VMess, Trojan and VLESS over TCP, TLS or WebSocket, on its own bounded userspace TCP/IP engine. 2,814 lines of original C and Swift, fuzzed under sanitizers, Apache-2.0.

mockmini / Sources CSwiftarea = lines of code
This is all of it: 13 files and 2,814 lines. Click any file to read it on GitHub. No Go runtime · no vendored TCP/IP stack · no proxy-kernel code
2,814lines, C + Swift
4proxy protocols
1,024concurrent flows
≈99%fuzzer line coverage
0vendored kernels

Protocols & transports

Build a connection. See exactly what runs.

Each connection is a stack of independent layers: a ProxySession on top of a TransportPlan. Pick a combination below. The rules and error messages are the real ones from Model.swift.

TLS always verifies the server certificate and host name. Turning verification off is not an option.

The packet engine

A TCP/IP endpoint in 905 lines of C.

The wlp engine takes raw IP packets from your tun device and turns them into flows you can dial upstream. It is portable C with no third-party code and a small serial callback API.

  • 01
    IPv4 and IPv6, TCP and UDPValidates lengths and checksums, reassembles fragments, and tracks each flow on its own.
  • 02
    A real TCP state machineThree-way handshake, reassembly, peer windows, retransmission, zero-window probes, FIN half-close and TIME_WAIT.
  • 03
    Memory you can predictBuffers are allocated on first use and freed after a second idle. Idle flows hold nothing.
  • 04
    Backpressure built inWhen wlp_remote_capacity() returns 0, pause upstream reads and resume on the next input or tick.
wlp.h ↗
#include "wlp.h"

wlp_callbacks cb = {
    on_connect, on_data, on_close, on_packet, on_eof
};
wlp_engine *engine = wlp_new(cb, ctx);

wlp_tick(engine, now_ms());           // then at least every 100 ms
wlp_input(engine, packet, length);     // raw IP packet from utun

// on_connect(ctx, flow, host, port, udp): dial upstream, then
wlp_remote_open(engine, flow);
wlp_remote_data(engine, flow, bytes, n); // upstream → client

if (wlp_remote_capacity(engine, flow) == 0) {
    /* pause reads; resume after next input or tick */
}

wlp_remote_close(engine, flow);       // orderly EOF
wlp_remote_abort(engine, flow);       // failed upstream → RST
wlp_free(engine);

Known limits

Bounded on purpose. Every number is in the header.

MockMini is a small TCP/UDP proxy endpoint, not a general-purpose IP stack. It publishes its limits instead of hiding them.

1,024
Concurrent flows
TCP and UDP, hashed by tuple and id
WLP_FLOW_LIMIT
32KiB
TCP receive reassembly
Per flow, allocated on use
256KiB
Unacked remote data
Per flow, freed after 1 s idle
128queues
Send queues held at once
32 MiB total budget
WLP_TX_BUFFERS
16· 15 s
Fragment reassembly
Partial datagrams, then expiry
32/ 64 KiB
UDP held before open
Datagrams waiting for upstream

Not supported today

SACKTCP timestampsECNICMPPMTUDIPv6 jumbogramsIPsecTCP urgentgRPC transportuTLSRealityVLESS flow control

Throughput and edge protocols still trail mature kernels like mihomo. That gap is the price of staying small and original.

Testing

Fuzzed, sanitized, and checked against a real server.

Every push runs the engine under ASan and UBSan with gcc and clang, plus a libFuzzer smoke test, and drives each protocol against a pinned, checksum-verified Xray release.

bash scripts/run-packet-tests.sh
$ MOCKMINI_FUZZ_STEPS=200000 bash scripts/run-packet-tests.sh
cc -std=c11 -O1 -fsanitize=address,undefined ...
✓ packet tests passed: TCP loss/order/window/FIN/RST/
  wrap/limits/options/window-scaling; IPv4/IPv6
  UDP/fragments; malformed corpus
✓ packet fuzz passed: 200000 steps over 8 seed(s);
  stateful TCP/UDP/fragments + remote API invariants
# stress build: WLP_FLOW_LIMIT=128, WLP_TX_BUFFERS=4
✓ packet fuzz passed: 200000 steps over 8 seed(s);
  stateful TCP/UDP/fragments + remote API invariants
real 0m4.4s

# CI jobs on every push and pull request
· Packet engine (Linux, gcc + clang, ASan/UBSan)
· Packet engine libFuzzer smoke (60 s)
· macOS: packet engine + Swift protocol tests
· Swift package (Linux, portable core)
· Interop (macOS, real Xray servers)
Stateful, checksum-aware fuzzerIt generates valid IPv4/IPv6 traffic with options, extension headers, fragments and clock jumps, and checks byte-exact, in-order delivery on every callback.
Stress buildLimits are lowered so the flow cap and send-queue budget are hit constantly, not rarely.
Independent wire fixturesSwift crypto fixtures are computed from the public protocol descriptions, not from MockMini's own code.
1.25 GiB through VMessThe interop run sends past the point where the 16-bit nonce counter wraps.
Interop matrix SS aes-128-gcmSS aes-256-gcmSS chacha20VMessVMess+WS+TLSTrojanTrojan+WS+TLSVLESSVLESS+TLSVLESS+WS+TLS
yezicheng2011 / mockmini

Built in the open by one developer.

MockMini is an independent project by daniel.ye. It is young and changes quickly, and every commit and test run is public on GitHub. Bug reports, reviews and pull requests are all welcome.

$ git clone https://github.com/yezicheng2011/mockmini.git
+ .package(url: "https://github.com/yezicheng2011/mockmini.git", from: "0.1.0")