Skip to content

Doki v0.9.3 -- DokiLink-Lite Mesh Networking + 190+ Bug Fixes

Choose a tag to compare

@awa-omg awa-omg released this 08 Jun 21:39
· 10 commits to main since this release

Doki v0.9.3 — 190+ Bug Fixes, DokiLink-Lite Mesh Networking

Breaking Changes

  • None. v0.9.3 is fully backward-compatible with v0.9.2. The default
    port for gossip listeners is configurable via DOKI_LINK_ADDR
    (default :7432).

What's New

DokiLink-Lite (Mesh Networking)

  • TCP/UDP proxy in pure stdlib: pkg/netlink/proxy.go and
    pkg/netlink/udp.go replace the old socat-based port forwarder.
    The new proxy supports half-close (graceful shutdown), idle timeouts,
    and per-connection transport wrappers.
  • TLS 1.3 wrapping for inter-host traffic: pkg/netlink/crypto.go
    exposes TLSWrapper (default encryption layer, L1). Each link
    certificate is signed by a per-install ECDSA P-256 CA; certs include
    SAN DNS names (Go 1.15+ requirement).
  • NaCl secretbox for payload encryption (L2, opt-in): crypto.go
    derives a 32-byte key from both peers' Ed25519 public keys (SHA-256,
    order-sensitive) and uses a 4-byte length-prefixed frame format for
    TCP and per-datagram nonces for UDP.
  • Install identity: pkg/netlink/keys.go generates an Ed25519
    keypair and an ECDSA P-256 CA on first start, stored at
    $DOKI_ROOT/keys/ with 0600 permissions.
  • Peer registry with TOFU trust: pkg/netlink/peer.go and
    TrustStore persist known peers at $DOKI_ROOT/trust/. On first
    contact, the public key is recorded; subsequent connections verify
    signatures against this record.
  • Static peer discovery: pkg/netlink/discovery_static.go reads
    $DOKI_ROOT/mesh/peers.json (managed by doki link add/rm).
  • mDNS discovery (opt-in): pkg/netlink/discovery_mdns_on.go is
    built with -tags netlink_mdns and depends on
    github.com/hashicorp/mdns. Default builds include a no-op stub.
  • Gossip protocol: pkg/netlink/mesh.go exchanges ed25519-signed
    JSON messages (hello, peer, container) over TCP, capped at
    4 KiB per message. The 15-second tick discovers new peers
    automatically; 30-second tick refreshes from the static config.
  • New CLI: doki mesh {ls,status} and doki link {add,rm,show}.
  • IPv6 ARPA support: arpaToIP now handles .ip6.arpa. suffix
    for IPv6 reverse DNS lookups.
  • nftables OUTPUT chain: Port mapping rules now also apply to
    locally-originated traffic (OUTPUT chain), not just PREROUTING.
  • Mesh data race fix: onMessage now reads pubKeyBytes() inside
    the RLock scope, preventing races with peer map mutations.

Bug Fixes (190+ total across Rounds 1-4)

Critical Fixes

  • kill not updating state: After killing a container, the state was
    never updated to "exited" — it stayed "running" forever. Now polls
    with signal(0) after sending the signal, then saves exited state.
  • stop not updating state on SIGKILL failure: When the 3-second
    SIGKILL timeout expired, Stop() returned nil without updating state.
    Now always saves exited state with exit code 137 before returning.
  • Stop ExitChan disconnect + goroutine Wait race: Replaced ExitChan
    polling with signal(0) polling. Replaced goroutine+select with
    100ms sleep+signal check to avoid race with monitorProcess.
  • Exec no output: Runtime.Exec wrote to os.Stdout (daemon stdout),
    not HTTP response. Changed to return (stdout, stderr []byte, error).
    API handler writes bytes to response.
  • flagsWithValue -f conflict: -f in flagsWithValue caused
    rm -f <container> to skip the container ID. Removed -f, -t, -s
    from flagsWithValue map.
  • Compose flags after command ignored: Parser broke out of loop
    after finding command, ignoring flags like -p 8080:80 after
    doki-compose up. Now continues parsing flags after command.

High Fixes

  • ps --format not implemented: Template parsing and execution for
    format strings now works. {% raw %}{{.ID}}{% endraw %} etc.
  • Search/history JSON tags incorrect: Updated to match daemon
    response format (repo_name, short_description for Hub API;
    PascalCase for Docker API).
  • Push exit 0 on error: Now parses JSON stream and checks for
    "status":"error" before returning.
  • Compose profile filter broken: Services with profiles were included
    when no profiles were specified. Now excluded correctly.
  • Validate before extends: Moved Validate() after resolveExtends()
    so inherited images pass validation.
  • ADD trailing slash: Now detects trailing slash destination for
    correct directory placement.
  • ONBUILD type incorrect: Stores inst.Args[0] (sub-instruction
    type) instead of inst.Type ("ONBUILD").
  • Build panic on empty tags: Safe access with default "image" name.
  • mDNS compile errors: Fixed WantUnicastResponse, mdns.Query(),
    AddrV6.String() calls.
  • SetupNetwork data race: Added m.mu.Lock() around container
    access/modification in nw.Containers.
  • TCP DNS PTR missing arpaToIP: Added conversion before
    ResolvePTR call.
  • Container list Name always empty: stateToInfo now sets
    info.Name = "/" + state.Name.
  • Container inspect missing fields: Added ImageID, ImageDigest,
    Name to inspect response.
  • Create ignores ?name= query parameter: Now reads
    r.URL.Query().Get("name") and overrides body name.
  • Image inspect Config lowercase OCI: Replaced with explicit
    PascalCase map (Entrypoint, Cmd, Env, etc.).
  • Image inspect Created int64 vs string: Converted to RFC3339
    format via time.Unix(record.Created, 0).
  • History.Created type mismatch: Added FlexString type that
    handles both JSON string and int64.
  • compose ps -q truncation: Now returns full container ID.
  • ps ID = Name same value: CONTAINER ID now shows actual ID,
    NAMES shows the name.
  • images sha256: prefix: Stripped from REPOSITORY column.
  • Pull exit code on failure: Returns exit code 1 on error.

Medium Fixes

  • Rename returns 200 vs 204: Changed to 204 No Content.
  • Stop already-stopped returns 204 vs 304: Returns 304 Not
    Modified for already-stopped containers.
  • cp copies file as directory: Fixed path handling so cp file.txt container:/tmp/file.txt writes to /tmp/file.txt not
    /tmp/file.txt/file.txt.
  • kill on non-running returns 0: Now returns an error.
  • logs missing newlines: Appends \n to each log line.
  • compose config non-deterministic order: Services, volumes, and
    networks now sorted alphabetically.
  • compose logs non-deterministic order: Services sorted before
    reading logs.
  • mesh onMessage data race: Moved pubKeyBytes() inside RLock.
  • nftables OUTPUT chain empty: Port mapping rules now also applied
    to OUTPUT chain for local traffic.
  • arpaToIP ignores IPv6: Handles .ip6.arpa. with 32 nibbles.
  • Rm prints error twice: Removed duplicate fmt.Fprintf calls.
  • Cp can't copy to non-existent path: Fixed destination detection.
  • Compose pull doesn't deduplicate: Tracked pulled images in map.
  • Compose logs --tail 1 returns empty: Filters empty lines first.
  • Rename doesn't persist: Calls SaveState after updating
    annotations.
  • Duplicate container names allowed: Check for existing names
    before create, return 409 Conflict.
  • Attach is a stub: Implemented log streaming with follow.
  • Update doesn't persist: Calls SaveState after updating config.
  • --target CLI flag not implemented: Added flag parsing and API
    pass-through.
  • inspect ImageID empty: Set ImageDigest from imgRecord.ID.
  • compose ps ignores global -q flag: Uses quietFlag variable.

Other

  • dokid startup logs the DokiLink install id and listen address at
    INFO level. Set DOKI_LINK_MESH=0 to disable mesh entirely
    (e.g. on air-gapped hosts).
  • Makefile produces doki-v0.9.3-{arch}.tar.gz under releases/
    with SHA256 checksums.
  • DOKI_USE_SOCAT=1 forces socat fallback for port forwarding.
  • DOKI_LINK_ADDR overrides gossip listen address.

Documentation

  • .wiki/Networking.md and .wiki/Networking.es.md updated with
    DokiLink-Lite architecture, Mermaid sequence diagram of
    TCP-proxy + TLS + secretbox layers, and limitations of mesh
    discovery (no NAT traversal, no relay, mDNS limited to LAN).
  • README.md and README.es.md updated with v0.9.3 as current
    version, DokiLink-Lite networking section, and full changelog.

Install / Upgrade

# ARM64 (most Android devices, Apple Silicon, Linux ARM servers)
curl -L https://github.com/OpceanAI/Doki/releases/download/v0.9.3/doki-v0.9.3-arm64.tar.gz | tar -xz
cd doki-v0.9.3-arm64
./install.sh

# ARMV7 (older 32-bit Android)
curl -L https://github.com/OpceanAI/Doki/releases/download/v0.9.3/doki-v0.9.3-armv7.tar.gz | tar -xz
cd doki-v0.9.3-armv7
./install.sh

Verifying

dokid --version
doki version
doki mesh status
doki link add mybuddy 192.168.1.42:7432 --pub "$(doki mesh status | awk '/public key/ {print $3}')"