--- /dev/null
+#!/usr/bin/env python3
+# -*- mode: python; coding: utf-8; python-indent-offset: 2; indent-tabs-mode: nil -*-
+
+"""
+subu.py — CLI only.
+- No-args prints USAGE.
+- `help` / `usage` / `example` / `version` are handled *before* argparse.
+- `-h` / `--help` are mapped to `help`.
+- Delegates real work to subu_core.dispatch(args).
+"""
+
+from __future__ import annotations
+import argparse
+import sys
+
+try:
+ from subu_version import VERSION
+except Exception:
+ VERSION = "0.0.0-unknown"
+
+try:
+ from subu_text import USAGE, HELP, EXAMPLE
+except Exception:
+ USAGE = "usage: subu <verb> [args]\n"
+ HELP = "help text unavailable (subu_text import failed)\n"
+ EXAMPLE = "example text unavailable (subu_text import failed)\n"
+
+# -------------------------------
+# Parser construction (verbs that do real work)
+# -------------------------------
+def _build_parser() -> argparse.ArgumentParser:
+ # add_help=False so -h/--help don't get auto-bound; we intercept them manually
+ p = argparse.ArgumentParser(
+ prog="subu",
+ description="Manage subu containers, namespaces, and WireGuard attachments.",
+ add_help=False,
+ )
+ # keep -V only; -h/--help are handled by pre-parse
+ p.add_argument("-V", "--version", action="store_true",
+ help="Print version and exit.")
+
+ sub = p.add_subparsers(dest="verb",
+ metavar="{init,create,info,information,WG,attach,detach,network,lo,option,exec}",
+ required=False)
+
+ sub.add_parser("init", help="Initialize new subu database (refuses if exists).")
+ sub.add_parser("create", help="Create a subu (defaults only).")
+ sub.add_parser("info", help="Show info about a subu.")
+ sub.add_parser("information", help="Alias of 'info'.")
+ sub.add_parser("WG", help="WireGuard operations.")
+ sub.add_parser("attach", help="Attach WG to subu (netns + cgroup/eBPF).")
+ sub.add_parser("detach", help="Detach WG from subu.")
+ sub.add_parser("network", help="Bring attached ifaces up/down in the subu netns.")
+ sub.add_parser("lo", help="Bring loopback up/down in the subu netns.")
+ sub.add_parser("option", help="Persisted options (list/get/set).")
+ sub.add_parser("exec", help="Execute a command inside the subu netns: subu exec <id> -- <cmd...>")
+
+ return p
+
+def _print_topic_help(parser: argparse.ArgumentParser, topic: str) -> bool:
+ """Try to print help for a specific subparser topic. Returns True if found."""
+ for action in getattr(parser, "_subparsers", [])._actions:
+ if isinstance(action, argparse._SubParsersAction):
+ if topic in action.choices:
+ action.choices[topic].print_help()
+ return True
+ if topic == "information" and "info" in action.choices:
+ action.choices["info"].print_help()
+ return True
+ return False
+
+# -------------------------------
+# CLI entry (parse only)
+# -------------------------------
+def CLI(argv=None) -> int:
+ argv = sys.argv[1:] if argv is None else argv
+ parser = _build_parser()
+
+ # 0) No args => USAGE
+ if not argv:
+ sys.stdout.write(USAGE)
+ return 0
+
+ # 1) Pre-parse intercepts (robust vs. argparse)
+ first = argv[0]
+ if first in ("-h", "--help", "help"):
+ topic = argv[1] if len(argv) > 1 and argv[0] == "help" else None
+ if topic:
+ # Topic-aware help if possible; else fall back to full HELP
+ if not _print_topic_help(parser, topic):
+ sys.stdout.write(HELP)
+ else:
+ sys.stdout.write(HELP)
+ return 0
+
+ if first in ("usage",):
+ sys.stdout.write(USAGE)
+ return 0
+
+ if first in ("example",):
+ sys.stdout.write(EXAMPLE)
+ return 0
+
+ if first in ("version",):
+ print(VERSION)
+ return 0
+
+ # 2) Normal parse
+ try:
+ args = parser.parse_args(argv)
+ except SystemExit as e:
+ return int(e.code)
+
+ # 3) Global -V/--version
+ if getattr(args, "version", False):
+ print(VERSION)
+ return 0
+
+ # 4) Delegate to worker layer
+ try:
+ from subu_core import dispatch # type: ignore
+ except Exception as e:
+ sys.stderr.write(f"subu: internal error: cannot import subu_core.dispatch: {e}\n")
+ return 1
+
+ try:
+ rc = dispatch(args)
+ return int(rc) if rc is not None else 0
+ except KeyboardInterrupt:
+ return 130
+ except SystemExit as e:
+ return int(e.code)
+ except Exception as e:
+ sys.stderr.write(f"subu: error: {e}\n")
+ return 1
+
+if __name__ == "__main__":
+ sys.exit(CLI())
--- /dev/null
+// -*- mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
+// eBPF: force sockets inside this cgroup to use a specific ifindex
+// Hooks: cgroup/connect4 and cgroup/sendmsg4
+// Logic: read ifindex from array map[0], then setsockopt(SO_BINDTOIFINDEX)
+
+#include <linux/bpf.h>
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_endian.h>
+
+struct {
+ __uint(type, BPF_MAP_TYPE_ARRAY);
+ __uint(max_entries, 1);
+ __type(key, __u32);
+ __type(value, __u32); // ifindex
+ __uint(pinning, LIBBPF_PIN_BY_NAME);
+} force_ifindex_map SEC(".maps");
+
+static __always_inline int force_bind(struct bpf_sock_addr *ctx)
+{
+ __u32 k = 0;
+ __u32 *ifx = bpf_map_lookup_elem(&force_ifindex_map, &k);
+ if (!ifx || !*ifx)
+ return 1; // allow pass-through if not configured
+
+ int val = (int)*ifx;
+ // This sets sk->sk_bound_dev_if equivalently to userland SO_BINDTOIFINDEX.
+ // Ignore return (verifier- & failure-friendly).
+ (void)bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX, &val, sizeof(val));
+ return 1;
+}
+
+SEC("cgroup/connect4")
+int force_dev_connect4(struct bpf_sock_addr *ctx)
+{
+ return force_bind(ctx);
+}
+
+SEC("cgroup/sendmsg4")
+int force_dev_sendmsg4(struct bpf_sock_addr *ctx)
+{
+ return force_bind(ctx);
+}
+
+char _license[] SEC("license") = "GPL";
--- /dev/null
+# ===== File: subu_bpf.py =====
+#!/usr/bin/env python3
+# -*- mode: python; coding: utf-8; python-indent-offset: 2; indent-tabs-mode: nil -*-
+
+"""
+Stub for eBPF steering (cgroup/connect4+sendmsg4 hooks) to enforce sk_bound_dev_if.
+Implementation notes:
+ * We will later compile a small eBPF C program (libbpf/bpftool) that:
+ - on connect4/sendmsg4: if process UID==subu UID -> sets sk_bound_dev_if to WG ifindex
+ * For now, we provide placeholders that pretend success.
+"""
+
+import subu_utils as U
+import subu_db as DB
+
+
+def install_steer(subu_id: str, wg_ifindex: int):
+ # TODO: load BPF, attach to cgroup v2 path; store cgroup path in DB
+ DB.update_subu_cgroup(subu_id, "/sys/fs/cgroup/subu_placeholder")
+ return 0
+
+
+def remove_steer(subu_id: str):
+ # TODO: detach and unload
+ return 0
--- /dev/null
+# -*- mode: python; coding: utf-8; python-indent-offset: 2; indent-tabs-mode: nil -*-
+"""
+subu_core.py — main worker layer for Subu management
+Version 0.1.6
+"""
+
+import os, sqlite3, subprocess
+from pathlib import Path
+from contextlib import closing
+from subu_worker_bpf import install_steering, remove_steering, BpfError
+
+DB_FILE = Path("./subu.db")
+
+# ---------------------------------------------------------------------
+# SQLite helpers
+# ---------------------------------------------------------------------
+
+def db_connect():
+ if not DB_FILE.exists():
+ raise FileNotFoundError("subu.db not found; run `subu init <token>` first")
+ return sqlite3.connect(DB_FILE)
+
+def db_init():
+ if DB_FILE.exists():
+ raise FileExistsError("Database already exists")
+ with closing(sqlite3.connect(DB_FILE)) as db:
+ c = db.cursor()
+ c.executescript("""
+ CREATE TABLE subu (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ owner TEXT,
+ name TEXT,
+ netns TEXT,
+ lo_state TEXT DEFAULT 'down',
+ wg_id INTEGER,
+ network_state TEXT DEFAULT 'down'
+ );
+ CREATE TABLE wg (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ endpoint TEXT,
+ local_ip TEXT,
+ allowed_ips TEXT,
+ pubkey TEXT,
+ state TEXT DEFAULT 'down'
+ );
+ CREATE TABLE options (
+ subu_id INTEGER,
+ name TEXT,
+ value TEXT,
+ PRIMARY KEY (subu_id, name)
+ );
+ """)
+ db.commit()
+ print("✅ subu.db created")
+
+# ---------------------------------------------------------------------
+# System helpers
+# ---------------------------------------------------------------------
+
+def run(cmd, check=True):
+ r = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
+ if check and r.returncode != 0:
+ raise RuntimeError(f"cmd failed: {' '.join(cmd)}\n{r.stderr}")
+ return r.stdout.strip()
+
+def create_netns(nsname: str):
+ run(["ip", "netns", "add", nsname])
+ run(["ip", "-n", nsname, "link", "set", "lo", "down"])
+ return nsname
+
+def delete_netns(nsname: str):
+ run(["ip", "netns", "delete", nsname], check=False)
+
+def ifindex_in_netns(nsname: str, ifname: str) -> int:
+ out = run(["ip", "-n", nsname, "-o", "link", "show", ifname])
+ return int(out.split(":", 1)[0])
+
+# ---------------------------------------------------------------------
+# Subu operations
+# ---------------------------------------------------------------------
+
+def create_subu(owner: str, name: str) -> str:
+ with closing(db_connect()) as db:
+ c = db.cursor()
+ c.execute("INSERT INTO subu (owner, name, netns) VALUES (?, ?, ?)",
+ (owner, name, f"ns-{owner}-{name}"))
+ subu_id = c.lastrowid
+ db.commit()
+ nsname = f"ns-subu_{subu_id}"
+ create_netns(nsname)
+ print(f"Created subu_{subu_id} ({owner}:{name}) with netns {nsname}")
+ return f"subu_{subu_id}"
+
+def list_subu():
+ with closing(db_connect()) as db:
+ for row in db.execute("SELECT id, owner, name, netns, lo_state, wg_id, network_state FROM subu"):
+ print(row)
+
+def info_subu(subu_id: str):
+ sid = int(subu_id.split("_")[1])
+ with closing(db_connect()) as db:
+ for row in db.execute("SELECT * FROM subu WHERE id=?", (sid,)):
+ print(row)
+
+def lo_toggle(subu_id: str, state: str):
+ sid = int(subu_id.split("_")[1])
+ with closing(db_connect()) as db:
+ row = db.execute("SELECT netns FROM subu WHERE id=?", (sid,)).fetchone()
+ if not row: raise ValueError("subu not found")
+ ns = row[0]
+ run(["ip", "netns", "exec", ns, "ip", "link", "set", "lo", state])
+ db.execute("UPDATE subu SET lo_state=? WHERE id=?", (state, sid))
+ db.commit()
+ print(f"loopback {state} in {subu_id}")
+
+# ---------------------------------------------------------------------
+# WireGuard operations
+# ---------------------------------------------------------------------
+
+def wg_global(basecidr: str):
+ Path("./WG_GLOBAL").write_text(basecidr.strip() + "\n")
+ print(f"Base CIDR set to {basecidr}")
+
+def wg_create(endpoint: str) -> str:
+ base = Path("./WG_GLOBAL").read_text().strip() if Path("./WG_GLOBAL").exists() else None
+ if not base:
+ raise RuntimeError("No WG global base; set with `subu WG global`")
+ with closing(db_connect()) as db:
+ c = db.cursor()
+ # trivial allocator: next /32 by count
+ idx = c.execute("SELECT COUNT(*) FROM wg").fetchone()[0]
+ octets = base.split(".")
+ octets[3] = str(2 + idx)
+ local_ip = ".".join(octets) + "/32"
+ c.execute("INSERT INTO wg (endpoint, local_ip, allowed_ips) VALUES (?, ?, ?)",
+ (endpoint, local_ip, "0.0.0.0/0"))
+ wid = c.lastrowid
+ db.commit()
+ print(f"Created WG_{wid} ({endpoint}) local_ip={local_ip}")
+ return f"WG_{wid}"
+
+def wg_set_pubkey(wg_id: str, key: str):
+ wid = int(wg_id.split("_")[1])
+ with closing(db_connect()) as db:
+ db.execute("UPDATE wg SET pubkey=? WHERE id=?", (key, wid))
+ db.commit()
+ print(f"Public key stored for {wg_id}")
+
+def wg_info(wg_id: str):
+ wid = int(wg_id.split("_")[1])
+ with closing(db_connect()) as db:
+ row = db.execute("SELECT * FROM wg WHERE id=?", (wid,)).fetchone()
+ if not row: print("WG not found")
+ else: print(row)
+
+# ---------------------------------------------------------------------
+# Attach / Detach with eBPF steering
+# ---------------------------------------------------------------------
+
+def attach_wg(subu_id: str, wg_id: str):
+ sid = int(subu_id.split("_")[1])
+ wid = int(wg_id.split("_")[1])
+ wg_ifname = f"subu_{wid}"
+ netns = f"ns-{subu_id}"
+
+ # Create WG device inside namespace
+ run(["ip", "link", "add", wg_ifname, "type", "wireguard"])
+ run(["ip", "link", "set", wg_ifname, "netns", netns])
+ # Configure MTU + accept_local
+ run(["ip", "-n", netns, "link", "set", wg_ifname, "mtu", "1420"])
+ run(["ip", "-n", netns, "link", "set", "dev", wg_ifname, "up"])
+ print(f"Attached {wg_id} as {wg_ifname} inside {netns}")
+
+ # Install steering
+ try:
+ install_steering(subu_id, netns, wg_ifname)
+ print(f"Installed eBPF steering for {subu_id} via {wg_ifname}")
+ except BpfError as e:
+ print(f"warning: steering failed: {e}")
+
+ # Update DB linkage
+ with closing(db_connect()) as db:
+ db.execute("UPDATE subu SET wg_id=? WHERE id=?", (wid, sid))
+ db.commit()
+
+def detach_wg(subu_id: str):
+ sid = int(subu_id.split("_")[1])
+ with closing(db_connect()) as db:
+ row = db.execute("SELECT wg_id, netns FROM subu WHERE id=?", (sid,)).fetchone()
+ if not row or row[0] is None:
+ print("nothing attached")
+ return
+ wid, ns = row
+ wg_ifname = f"subu_{wid}"
+ run(["ip", "-n", ns, "link", "del", wg_ifname], check=False)
+ db.execute("UPDATE subu SET wg_id=NULL WHERE id=?", (sid,))
+ db.commit()
+ try:
+ remove_steering(subu_id)
+ print(f"Removed steering for {subu_id}")
+ except BpfError as e:
+ print(f"warning: remove steering failed: {e}")
+
+# ---------------------------------------------------------------------
+# Network up/down aggregate
+# ---------------------------------------------------------------------
+
+def network_toggle(subu_id: str, state: str):
+ sid = int(subu_id.split("_")[1])
+ with closing(db_connect()) as db:
+ row = db.execute("SELECT netns, wg_id FROM subu WHERE id=?", (sid,)).fetchone()
+ if not row: raise ValueError("subu not found")
+ ns, wid = row
+ # bring lo up first if needed
+ if state == "up":
+ run(["ip", "netns", "exec", ns, "ip", "link", "set", "lo", "up"], check=False)
+ # bring attached iface
+ if wid:
+ ifname = f"subu_{wid}"
+ run(["ip", "-n", ns, "link", "set", "dev", ifname, state], check=False)
+ with closing(db_connect()) as db:
+ db.execute("UPDATE subu SET network_state=? WHERE id=?", (state, sid))
+ db.commit()
+ print(f"{subu_id}: network {state}")
+
+# ---------------------------------------------------------------------
+# Exec inside namespace
+# ---------------------------------------------------------------------
+
+def exec_in_subu(subu_id: str, cmd: list):
+ sid = int(subu_id.split("_")[1])
+ with closing(db_connect()) as db:
+ ns = db.execute("SELECT netns FROM subu WHERE id=?", (sid,)).fetchone()[0]
+ full = ["ip", "netns", "exec", ns] + cmd
+ os.execvp(full[0], full)
--- /dev/null
+# ===== File: subu_db.py =====
+#!/usr/bin/env python3
+# -*- mode: python; coding: utf-8; python-indent-offset: 2; indent-tabs-mode: nil -*-
+
+import os, sqlite3, json
+import subu_utils as U
+
+SCHEMA = {
+ "meta": "CREATE TABLE IF NOT EXISTS meta (k TEXT PRIMARY KEY, v TEXT)" ,
+ "subu": """
+ CREATE TABLE IF NOT EXISTS subu (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ masu TEXT NOT NULL,
+ subu TEXT NOT NULL,
+ uid INTEGER,
+ netns TEXT,
+ cgroup_path TEXT,
+ UNIQUE(masu, subu)
+ )""",
+ "wg": """
+ CREATE TABLE IF NOT EXISTS wg (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ remote TEXT NOT NULL,
+ pubkey TEXT,
+ dev TEXT,
+ addr TEXT,
+ state TEXT DEFAULT 'down'
+ )""",
+ "attach": """
+ CREATE TABLE IF NOT EXISTS attach (
+ subu_id INTEGER NOT NULL,
+ wg_id INTEGER NOT NULL,
+ PRIMARY KEY (subu_id, wg_id)
+ )""",
+}
+
+class NotInitializedError(Exception):
+ pass
+
+
+def require_initialized():
+ if not os.path.exists(U.path_db()):
+ raise NotInitializedError()
+
+
+def connect():
+ return sqlite3.connect(U.path_db())
+
+
+def init_db():
+ if os.path.exists(U.path_db()):
+ return False
+ con = sqlite3.connect(U.path_db())
+ try:
+ cur = con.cursor()
+ for sql in SCHEMA.values():
+ cur.execute(sql)
+ con.commit()
+ return True
+ finally:
+ con.close()
+
+
+def put_meta(k, v):
+ con = connect(); cur = con.cursor()
+ cur.execute("INSERT OR REPLACE INTO meta(k,v) VALUES(?,?)", (k, v))
+ con.commit(); con.close()
+
+def get_meta(k, default=None):
+ con = connect(); cur = con.cursor()
+ cur.execute("SELECT v FROM meta WHERE k=?", (k,))
+ row = cur.fetchone(); con.close()
+ return row[0] if row else default
+
+
+def create_subu(masu, subu):
+ con = connect(); cur = con.cursor()
+ cur.execute("INSERT INTO subu(masu,subu) VALUES(?,?)", (masu, subu))
+ con.commit()
+ sid = cur.lastrowid
+ con.close()
+ return f"subu_{sid}"
+
+
+def list_subu():
+ con = connect(); cur = con.cursor()
+ cur.execute("SELECT id,masu,subu,uid,netns,cgroup_path FROM subu ORDER BY id")
+ rows = cur.fetchall(); con.close(); return rows
+
+
+def subu_by_id(subu_id):
+ if not subu_id.startswith("subu_"):
+ raise ValueError("bad subu id")
+ sid = int(subu_id.split("_")[1])
+ con = connect(); cur = con.cursor()
+ cur.execute("SELECT id,masu,subu,uid,netns,cgroup_path FROM subu WHERE id=?", (sid,))
+ row = cur.fetchone(); con.close(); return row
+
+
+def update_subu_netns(subu_id, netns):
+ sid = int(subu_id.split("_")[1])
+ con = connect(); cur = con.cursor()
+ cur.execute("UPDATE subu SET netns=? WHERE id=?", (netns, sid))
+ con.commit(); con.close()
+
+
+def update_subu_uid(subu_id, uid):
+ sid = int(subu_id.split("_")[1])
+ con = connect(); cur = con.cursor()
+ cur.execute("UPDATE subu SET uid=? WHERE id=?", (uid, sid))
+ con.commit(); con.close()
+
+
+def update_subu_cgroup(subu_id, path):
+ sid = int(subu_id.split("_")[1])
+ con = connect(); cur = con.cursor()
+ cur.execute("UPDATE subu SET cgroup_path=? WHERE id=?", (path, sid))
+ con.commit(); con.close()
+
+# WG
+
+def wg_set_global_base(cidr):
+ put_meta("wg_base_cidr", cidr)
+
+
+def wg_create(remote):
+ con = connect(); cur = con.cursor()
+ cur.execute("INSERT INTO wg(remote) VALUES(?)", (remote,))
+ con.commit(); wid = cur.lastrowid; con.close(); return f"WG_{wid}"
+
+
+def wg_list():
+ con = connect(); cur = con.cursor()
+ cur.execute("SELECT id,remote,pubkey,dev,addr,state FROM wg ORDER BY id")
+ rows = cur.fetchall(); con.close(); return rows
+
+
+def wg_by_id(wg_id):
+ if not wg_id.startswith("WG_"):
+ raise ValueError("bad WG id")
+ wid = int(wg_id.split("_")[1])
+ con = connect(); cur = con.cursor()
+ cur.execute("SELECT id,remote,pubkey,dev,addr,state FROM wg WHERE id=?", (wid,))
+ row = cur.fetchone(); con.close(); return row
+
+
+def wg_update(wg_id, **kv):
+ wid = int(wg_id.split("_")[1])
+ con = connect(); cur = con.cursor()
+ cols = ",".join([f"{k}=?" for k in kv.keys()])
+ cur.execute(f"UPDATE wg SET {cols} WHERE id=?", [*kv.values(), wid])
+ con.commit(); con.close()
+
+
+def attach(subu_id, wg_id):
+ sid = int(subu_id.split("_")[1])
+ wid = int(wg_id.split("_")[1])
+ con = connect(); cur = con.cursor()
+ cur.execute("INSERT OR REPLACE INTO attach(subu_id,wg_id) VALUES(?,?)", (sid, wid))
+ con.commit(); con.close()
+
+
+def detach(subu_id, wg_id):
+ sid = int(subu_id.split("_")[1])
+ wid = int(wg_id.split("_")[1])
+ con = connect(); cur = con.cursor()
+ cur.execute("DELETE FROM attach WHERE subu_id=? AND wg_id=?", (sid, wid))
+ con.commit(); con.close()
+
+
+def attached_wg_ids(sid: int):
+ con = connect(); cur = con.cursor()
+ cur.execute("SELECT wg_id FROM attach WHERE subu_id=?", (sid,))
+ rows = [f"WG_{r[0]}" for r in cur.fetchall()]
+ con.close(); return rows
+
--- /dev/null
+# ===== File: subu_net.py =====
+#!/usr/bin/env python3
+# -*- mode: python; coding: utf-8; python-indent-offset: 2; indent-tabs-mode: nil -*-
+
+import subu_utils as U
+import subu_db as DB
+
+
+def ensure_netns(ns):
+ # create netns if missing
+ rc, out = U.run("ip netns list", capture=True, check=False)
+ if ns not in out.split():
+ U.run(f"ip netns add {ns}")
+
+
+def lo(ns, action: str):
+ if action == "up":
+ U.run(f"ip -n {ns} link set lo up")
+ else:
+ U.run(f"ip -n {ns} link set lo down")
+
+
+def cmd_lo(sid, action) -> int:
+ row = DB.subu_by_id(sid)
+ if not row:
+ return U.err("unknown subu id")
+ ns = row[4] or sid
+ ensure_netns(ns)
+ lo(ns, action)
+ return 0
+
+
+def cmd_network_up(sid) -> int:
+ row = DB.subu_by_id(sid)
+ if not row:
+ return U.err("unknown subu id")
+ ns = row[4] or sid
+ ensure_netns(ns)
+ lo(ns, "up")
+ # bring all attached WG up
+ sid_int = int(sid.split("_")[1])
+ for wid in DB.attached_wg_ids(sid_int):
+ import subu_wg as WG
+ WG.cmd_wg_up(wid)
+ return U.ok(f"network up for {sid}")
+
+
+def cmd_network_down(sid) -> int:
+ row = DB.subu_by_id(sid)
+ if not row:
+ return U.err("unknown subu id")
+ ns = row[4] or sid
+ # bring attached WG down first
+ sid_int = int(sid.split("_")[1])
+ for wid in DB.attached_wg_ids(sid_int):
+ import subu_wg as WG
+ WG.cmd_wg_down(wid)
+ # leave lo state alone per spec (no warning here)
+ return U.ok(f"network down for {sid}")
+
--- /dev/null
+# -*- mode: python; coding: utf-8; python-indent-offset: 2; indent-tabs-mode: nil -*-
+
+USAGE = """\
+usage: subu [-V] <verb> [<args>]
+
+Quick verbs:
+ usage Show this usage summary
+ help [topic] Detailed help; same as -h / --help
+ example End-to-end example session
+ version Print version
+
+Main verbs:
+ init Initialize a new subu database (refuses if it exists)
+ create Create a minimal subu record (defaults only)
+ info | information Show details for a subu
+ WG WireGuard object operations
+ attach Attach a WG object to a subu (netns + install steering)
+ detach Detach WG from a subu (remove steering)
+ network Bring attached ifaces up/down inside the subu netns
+ lo Bring loopback up/down inside the subu netns
+ option Persisted options (list/set/get for future policy)
+ exec Run a command inside the subu netns
+
+Tip: `subu help` (or `subu --help`) shows detailed help; `subu help WG` shows topic help.
+"""
+
+HELP = """\
+subu — manage subu containers, namespaces, and WG attachments
+
+2.1 Core
+
+ subu init <TOKEN>
+ Create ./subu.db (tables: subu, wg, links, options, state).
+ Requires a 6-char token (e.g., dzkq7b). Refuses if DB already exists.
+
+ subu create <masu> <subu>
+ Make a default subu with netns ns-<Subu_ID> containing lo only (down).
+ Returns subu_N.
+
+ subu list
+ Columns: Subu_ID, Owner, Name, NetNS, WG_Attached?, Up/Down.
+
+ subu info <Subu_ID> | subu information <Subu_ID>
+ Full record + attached WG(s) + options + iface states.
+
+2.2 Loopback
+
+ subu lo up <Subu_ID> | subu lo down <Subu_ID>
+ Toggle loopback inside the subu’s netns.
+
+2.3 WireGuard objects (independent)
+
+ subu WG global <BaseCIDR>
+ e.g., 192.168.112.0/24; allocator hands out /32 peers sequentially.
+ Shows current base and next free on success.
+
+ subu WG create <host:port>
+ Creates WG object; allocates next /32 local IP; AllowedIPs=0.0.0.0/0.
+ Returns WG_M.
+
+ subu WG server_provided_public_key <WG_ID> <Base64Key>
+ Stores server’s pubkey.
+
+ subu WG info <WG_ID> | subu WG information <WG_ID>
+ Endpoint, allocated IP, pubkey set?, link state (admin/oper).
+
+2.4 Link WG ↔ subu, bring up/down
+
+ subu attach WG <Subu_ID> <WG_ID>
+ Creates/configures WG device inside ns-<Subu_ID>:
+ - device name: subu_<M> (M from WG_ID)
+ - set local /32, MTU 1420, accept_local=1
+ - no default route is added
+ - installs eBPF steering (force egress via this device) automatically
+
+ subu detach WG <Subu_ID>
+ Remove WG device/config from the subu’s netns and remove steering; keep WG object.
+
+ subu WG up <WG_ID> | subu WG down <WG_ID>
+ Toggle interface admin state in the subu’s netns (must be attached).
+ On “up”, warn if loopback is currently down in that netns.
+
+ subu network up <Subu_ID> | subu network down <Subu_ID>
+ Only toggles admin state for all attached ifaces. On “up”, loopback
+ is brought up first automatically. No route manipulation.
+
+2.5 Execution
+
+ subu exec <Subu_ID> -- <cmd> …
+ Run a process inside the subu’s netns.
+
+2.6 Options (persist only, for future policy)
+
+ subu option list <Subu_ID>
+ subu option get <Subu_ID> [name]
+ subu option set <Subu_ID> <name> <value>
+
+2.7 Meta
+
+ subu usage
+ Short usage summary (also printed when no args are given).
+
+ subu help [topic]
+ This help (or per-topic help such as `subu help WG`).
+
+ subu example
+ A concrete end-to-end scenario.
+
+ subu version
+ Print version (same as -V / --version).
+"""
+
+EXAMPLE = """\
+# 0) Safe init (refuses if ./subu.db exists)
+subu init dzkq7b
+# -> created ./subu.db
+
+# 1) Create Subu
+subu create Thomas US
+# -> Subu_ID: subu_7
+# -> netns: ns-subu_7 with lo (down)
+
+# 2) Define WG pool (once per host)
+subu WG global 192.168.112.0/24
+# -> base set; next free: 192.168.112.2/32
+
+# 3) Create WG object with endpoint
+subu WG create ReasoningTechnology.com:51820
+# -> WG_ID: WG_0
+# -> local IP: 192.168.112.2/32
+# -> AllowedIPs: 0.0.0.0/0
+
+# 4) Add server public key
+subu WG server_provided_public_key WG_0 ABCDEFG...xyz=
+# -> saved
+
+# 5) Attach WG to Subu (device created/configured in ns + steering)
+subu attach WG subu_7 WG_0
+# -> device ns-subu_7/subu_0 configured (no default route)
+# -> steering installed: egress forced via subu_0
+
+# 6) Bring network up (lo first, then attached ifaces)
+subu network up subu_7
+# -> lo up; subu_0 admin up
+
+# 7) Start the WG engine inside the netns
+subu WG up WG_0
+# -> up, handshakes should start (warn if lo was down)
+
+# 8) Test from inside the subu
+subu exec subu_7 -- curl -4v https://ifconfig.me
+"""
--- /dev/null
+# ===== File: subu_utils.py =====
+#!/usr/bin/env python3
+# -*- mode: python; coding: utf-8; python-indent-offset: 2; indent-tabs-mode: nil -*-
+
+import os, sys, subprocess, shlex
+
+
+def ok(msg: str, code: int = 0) -> int:
+ print(msg)
+ return code
+
+def err(msg: str, code: int = 2) -> int:
+ print(f"❌ {msg}")
+ return code
+
+
+def run(cmd: str, check=True, capture=False, env=None, ns_enter=None):
+ """Run shell command. If ns_enter is a netns name, prefix with `ip netns exec`.
+ Returns (rc, outstr).
+ """
+ if ns_enter:
+ cmd = f"ip netns exec {shlex.quote(ns_enter)} {cmd}"
+ p = subprocess.run(cmd, shell=True, env=env,
+ stdout=subprocess.PIPE if capture else None,
+ stderr=subprocess.STDOUT)
+ out = p.stdout.decode() if p.stdout else ""
+ if check and p.returncode != 0:
+ raise RuntimeError(f"command failed ({p.returncode}): {cmd}\n{out}")
+ return p.returncode, out
+
+
+def path_db():
+ return os.path.abspath("subu.db")
+
--- /dev/null
+# -*- mode: python; coding: utf-8; python-indent-offset: 2; indent-tabs-mode: nil -*-
+VERSION = "0.1.6"
--- /dev/null
+# ===== File: subu_wg.py =====
+#!/usr/bin/env python3
+# -*- mode: python; coding: utf-8; python-indent-offset: 2; indent-tabs-mode: nil -*-
+
+import ipaddress
+import subu_utils as U
+import subu_db as DB
+
+PREFIX_DEV = "subu_" # device name base; dev = f"{PREFIX_DEV}{WG_id_num}"
+
+
+def cmd_wg_help() -> int:
+ print("WG commands: global <cidr> | create <host:port> | info | server_provided_public_key <WG_id> <key> | up <WG_id> | down <WG_id>")
+ return 0
+
+
+def cmd_wg_global(base_cidr: str) -> int:
+ # validate CIDR
+ try:
+ net = ipaddress.ip_network(base_cidr, strict=False)
+ if net.version != 4:
+ return U.err("only IPv4 supported for WG base")
+ except Exception as e:
+ return U.err(f"invalid cidr: {e}")
+ DB.wg_set_global_base(base_cidr)
+ return U.ok(f"WG base set to {base_cidr}")
+
+
+def allocate_addr_for(wg_id: str) -> str:
+ base = DB.get_meta("wg_base_cidr")
+ if not base:
+ raise RuntimeError("WG base not set; run 'subu WG global <cidr>'")
+ net = ipaddress.ip_network(base, strict=False)
+ wid = int(wg_id.split("_")[1])
+ host = list(net.hosts())[wid + 1] # skip .1 for potential gateway
+ return f"{host}/32"
+
+
+def ensure_device(wg_id: str):
+ # create device if missing and store dev+addr in DB
+ row = DB.wg_by_id(wg_id)
+ if not row:
+ raise RuntimeError("unknown WG id")
+ _, remote, pubkey, dev, addr, state = row
+ if not dev:
+ dev = f"{PREFIX_DEV}{wg_id.split('_')[1]}"
+ DB.wg_update(wg_id, dev=dev)
+ if not addr:
+ addr = allocate_addr_for(wg_id)
+ DB.wg_update(wg_id, addr=addr)
+ # ensure link exists in root netns
+ rc, out = U.run("ip link show", capture=True, check=False)
+ if f": {dev}:" not in out:
+ # create WG link skeleton; full wg config is deferred
+ U.run(f"ip link add {dev} type wireguard")
+ U.run(f"ip addr add {addr} dev {dev}")
+ return dev, addr
+
+
+def move_to_netns(wg_id: str, ns: str):
+ dev, _ = ensure_device(wg_id)
+ # if already in ns, ip will refuse — treat as ok
+ U.run(f"ip link set {dev} netns {ns}", check=False)
+
+
+def detach_device(wg_id: str):
+ row = DB.wg_by_id(wg_id)
+ if not row: return
+ dev = row[3]
+ if not dev: return
+ # best effort delete (must run either in owning ns or root if present there)
+ # try root first
+ rc, out = U.run(f"ip link del {dev}", check=False)
+ if rc != 0:
+ # try to find owning ns? (skipped for brevity)
+ pass
+
+
+def cmd_wg_create(remote: str) -> int:
+ wid = DB.wg_create(remote)
+ print(wid)
+ return 0
+
+
+def cmd_wg_info() -> int:
+ rows = DB.wg_list()
+ for wid, remote, pubkey, dev, addr, state in rows:
+ print(f"WG_{wid}: remote={remote} dev={dev} addr={addr} state={state} pubkey={'set' if pubkey else 'unset'}")
+ return 0
+
+
+def cmd_wg_set_server_pub(wg_id: str, pub: str) -> int:
+ DB.wg_update(wg_id, pubkey=pub)
+ return U.ok(f"Set server pubkey for {wg_id}")
+
+
+def _ns_of_wg(wg_id: str):
+ # discover netns from attachment
+ rows = DB.list_subu()
+ for sid, *_ in rows:
+ attached = DB.attached_wg_ids(sid)
+ if wg_id in attached:
+ row = DB.subu_by_id(f"subu_{sid}")
+ return row[4] or f"subu_{sid}"
+ return None
+
+
+def cmd_wg_up(wg_id: str) -> int:
+ row = DB.wg_by_id(wg_id)
+ if not row:
+ return U.err("unknown WG id")
+ dev, addr = ensure_device(wg_id)
+ ns = _ns_of_wg(wg_id)
+ if ns:
+ # bring lo up silently before bringing WG up
+ U.run(f"ip -n {ns} link set lo up", check=False)
+ U.run(f"ip -n {ns} link set {dev} up")
+ else:
+ U.run(f"ip link set {dev} up")
+ DB.wg_update(wg_id, state="up")
+ return U.ok(f"WG {wg_id} up")
+
+
+def cmd_wg_down(wg_id: str) -> int:
+ row = DB.wg_by_id(wg_id)
+ if not row:
+ return U.err("unknown WG id")
+ dev = row[3]
+ if not dev:
+ return U.err("WG device not created yet")
+ ns = _ns_of_wg(wg_id)
+ if ns:
+ U.run(f"ip -n {ns} link set {dev} down", check=False)
+ else:
+ U.run(f"ip link set {dev} down", check=False)
+ DB.wg_update(wg_id, state="down")
+ return U.ok(f"WG {wg_id} down")
+
+
--- /dev/null
+# -*- mode: python; coding: utf-8; python-indent-offset: 2; indent-tabs-mode: nil -*-
+"""
+subu_worker_bpf.py — build, load, and manage eBPF steering for a Subu
+
+What it does:
+ * Compiles subu_bpf_force_egress.c -> /var/lib/subu/bpf/subu_force_egress.bpf.o
+ * Creates pins under /sys/fs/bpf/subu/<Subu_ID>:
+ force_connect4, force_sendmsg4, force_ifindex_map
+ * Creates a cgroup v2 node at /sys/fs/cgroup/subu/<Subu_ID>
+ * Attaches programs (connect4, sendmsg4) to that cgroup
+ * Writes the target ifindex into map[0]
+ * Idempotent: re-running updates ifindex and ensures attachments
+
+Requirements:
+ * bpffs mounted at /sys/fs/bpf
+ * cgroup v2 mounted at /sys/fs/cgroup
+ * tools: clang, bpftool
+ * privileges: CAP_BPF + CAP_SYS_ADMIN
+"""
+
+import os
+import shutil
+import subprocess
+from pathlib import Path
+from typing import Dict
+
+BPF_SRC = Path("subu_bpf_force_egress.c")
+BUILD_DIR = Path("/var/lib/subu/bpf")
+BPFFS_DIR = Path("/sys/fs/bpf")
+BPF_PIN_BASE = BPFFS_DIR / "subu" # /sys/fs/bpf/subu/<Subu_ID>/*
+CGROOT = Path("/sys/fs/cgroup/subu") # /sys/fs/cgroup/subu/<Subu_ID>
+
+OBJ_NAME = "subu_force_egress.bpf.o"
+PROG_CONNECT_PIN = "force_connect4"
+PROG_SENDMSG_PIN = "force_sendmsg4"
+MAP_IFINDEX_PIN = "force_ifindex_map" # matches map name in C
+
+class BpfError(RuntimeError):
+ pass
+
+def _run(cmd, check=True):
+ r = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
+ if check and r.returncode != 0:
+ raise BpfError(f"cmd failed: {' '.join(cmd)}\nstdout:\n{r.stdout}\nstderr:\n{r.stderr}")
+ return r
+
+def _which_or_die(tool: str):
+ if not shutil.which(tool):
+ raise BpfError(f"Missing required tool: {tool}")
+
+def ensure_prereqs():
+ _which_or_die("clang")
+ _which_or_die("bpftool")
+ # bpffs?
+ if not BPFFS_DIR.exists():
+ raise BpfError(f"{BPFFS_DIR} not mounted; try: mount -t bpf bpf {BPFFS_DIR}")
+ # cgroup v2?
+ cgroot = Path("/sys/fs/cgroup")
+ if not (cgroot / "cgroup.controllers").exists():
+ raise BpfError("cgroup v2 not mounted; e.g.: mount -t cgroup2 none /sys/fs/cgroup")
+
+def ensure_dirs(subu_id: str) -> Dict[str, Path]:
+ BUILD_DIR.mkdir(parents=True, exist_ok=True)
+ (BPF_PIN_BASE).mkdir(parents=True, exist_ok=True)
+ pin_dir = BPF_PIN_BASE / subu_id
+ pin_dir.mkdir(parents=True, exist_ok=True)
+
+ CGROOT.mkdir(parents=True, exist_ok=True)
+ cgdir = CGROOT / subu_id
+ cgdir.mkdir(parents=True, exist_ok=True)
+
+ return {
+ "build_obj": BUILD_DIR / OBJ_NAME,
+ "pin_dir": pin_dir,
+ "pin_prog_connect": pin_dir / PROG_CONNECT_PIN,
+ "pin_prog_sendmsg": pin_dir / PROG_SENDMSG_PIN,
+ "pin_map_ifindex": pin_dir / MAP_IFINDEX_PIN,
+ "cgdir": cgdir,
+ }
+
+def compile_bpf(obj_path: Path):
+ if not BPF_SRC.exists():
+ raise BpfError(f"BPF source not found: {BPF_SRC}")
+ cmd = [
+ "clang", "-O2", "-g",
+ "-target", "bpf",
+ "-D__TARGET_ARCH_x86",
+ "-c", str(BPF_SRC),
+ "-o", str(obj_path),
+ ]
+ _run(cmd)
+
+def _load_prog_with_pinmaps(obj: Path, section: str, prog_pin: Path, maps_dir: Path):
+ # bpftool prog load OBJ PIN_PATH section <section> pinmaps <maps_dir>
+ _run([
+ "bpftool", "prog", "load",
+ str(obj), str(prog_pin),
+ "section", section,
+ "pinmaps", str(maps_dir),
+ ])
+
+def load_and_pin_all(p: Dict[str, Path]):
+ obj = p["build_obj"]
+ maps_dir = p["pin_dir"]
+ # Load two sections; maps get pinned into maps_dir once (first load).
+ _load_prog_with_pinmaps(obj, "cgroup/connect4", p["pin_prog_connect"], maps_dir)
+ _load_prog_with_pinmaps(obj, "cgroup/sendmsg4", p["pin_prog_sendmsg"], maps_dir)
+
+ # Ensure map exists where we expect it (pinned by name from C)
+ if not p["pin_map_ifindex"].exists():
+ # Some bpftool/libbpf combos pin maps directly as <maps_dir>/<map_name>.
+ # If not present, try to locate by name and pin.
+ # Find map id by name:
+ out = _run(["bpftool", "map", "show"]).stdout.splitlines()
+ target_id = None
+ for line in out:
+ # sample: "123: array name force_ifindex_map flags 0x0 ..."
+ if " name " + MAP_IFINDEX_PIN + " " in line:
+ # id is before colon
+ try:
+ target_id = line.strip().split(":", 1)[0]
+ int(target_id) # validate
+ break
+ except Exception:
+ pass
+ if not target_id:
+ raise BpfError(f"Unable to find map '{MAP_IFINDEX_PIN}' to pin")
+ _run(["bpftool", "map", "pin", "id", target_id, str(p["pin_map_ifindex"])])
+
+def attach_to_cgroup(p: Dict[str, Path]):
+ # Attach programs to the subu-specific cgroup
+ _run(["bpftool", "cgroup", "attach", str(p["cgdir"]), "connect4", "pinned", str(p["pin_prog_connect"])])
+ _run(["bpftool", "cgroup", "attach", str(p["cgdir"]), "sendmsg4", "pinned", str(p["pin_prog_sendmsg"])])
+
+def detach_from_cgroup(p: Dict[str, Path]):
+ _run(["bpftool", "cgroup", "detach", str(p["cgdir"]), "connect4"], check=False)
+ _run(["bpftool", "cgroup", "detach", str(p["cgdir"]), "sendmsg4"], check=False)
+
+def set_ifindex(p: Dict[str, Path], ifindex: int):
+ # bpftool map update pinned <map> key <00 00 00 00> value <ifindex_le>
+ key_hex = "00 00 00 00".split()
+ val_hex = ifindex.to_bytes(4, "little").hex(" ").split()
+ _run(["bpftool", "map", "update", "pinned", str(p["pin_map_ifindex"]), "key", *key_hex, "value", *val_hex])
+
+def _ifindex_in_netns(netns_name: str, ifname: str) -> int:
+ # ip -n <ns> -o link show <ifname> -> "7: subu_0: <...>"
+ r = _run(["ip", "-n", netns_name, "-o", "link", "show", ifname])
+ first = r.stdout.strip().split(":", 1)[0]
+ return int(first)
+
+def install_steering(subu_id: str, netns_name: str, wg_ifname: str):
+ """
+ Build/load eBPF programs, pin them under /sys/fs/bpf/subu/<subu_id>,
+ attach to /sys/fs/cgroup/subu/<subu_id>, and set map[0]=ifindex(of wg_ifname in netns).
+ Idempotent across repeated calls.
+ """
+ ensure_prereqs()
+ paths = ensure_dirs(subu_id)
+ # compile if missing or stale
+ if (not paths["build_obj"].exists()) or (paths["build_obj"].stat().st_mtime < BPF_SRC.stat().st_mtime):
+ compile_bpf(paths["build_obj"])
+
+ # if pins already exist, keep them and just ensure attached + value updated
+ pins_exist = all(paths[k].exists() for k in ("pin_prog_connect", "pin_prog_sendmsg"))
+ if not pins_exist:
+ load_and_pin_all(paths)
+
+ # compute ifindex inside the subu netns
+ ifindex = _ifindex_in_netns(netns_name, wg_ifname)
+ set_ifindex(paths, ifindex)
+
+ # ensure cgroup attachments in place
+ attach_to_cgroup(paths)
+
+def remove_steering(subu_id: str):
+ """
+ Detach cgroup hooks and unpin programs/maps. Leaves the cgroup dir.
+ """
+ ensure_prereqs()
+ paths = ensure_dirs(subu_id)
+ # detach (ignore failure)
+ detach_from_cgroup(paths)
+ # unpin objects
+ for key in ("pin_prog_connect", "pin_prog_sendmsg", "pin_map_ifindex"):
+ try:
+ p = paths[key]
+ if p.exists():
+ p.unlink()
+ except Exception:
+ pass
+ # try to remove empty pin dir
+ try:
+ paths["pin_dir"].rmdir()
+ except Exception:
+ pass
--- /dev/null
+#!/bin/env bash
+
+set -x
+./subu.py # -> USAGE (exit 0)
+./subu.py usage # -> USAGE
+./subu.py -h # -> HELP
+./subu.py --help # -> HELP
+./subu.py help # -> HELP
+./subu.py help WG # -> WG topic help (or full HELP if topic unknown)
+./subu.py example # -> EXAMPLE
+./subu.py version # -> 0.1.4
+./subu.py -V # -> 0.1.4
+
--- /dev/null
+set -x
+./subu.py # -> USAGE (exit 0)
+./subu.py usage # -> USAGE
+./subu.py -h # -> HELP
+./subu.py --help # -> HELP
+./subu.py help # -> HELP
+./subu.py help WG # -> WG topic help (or full HELP if topic unknown)
+./subu.py example # -> EXAMPLE
+./subu.py version # -> 0.1.4
+./subu.py -V # -> 0.1.4
+set +x
--- /dev/null
+++ ./subu.py
+usage: subu [-V] <verb> [<args>]
+
+Quick verbs:
+ usage Show this usage summary
+ help [topic] Detailed help; same as -h / --help
+ example End-to-end example session
+ version Print version
+
+Main verbs:
+ init Initialize a new subu database (refuses if it exists)
+ create Create a minimal subu record (defaults only)
+ info | information Show details for a subu
+ WG WireGuard object operations
+ attach Attach a WG object to a subu (netns + cgroup/eBPF)
+ detach Detach WG from a subu
+ network Bring all attached ifaces up/down inside the subu netns
+ lo Bring loopback up/down inside the subu netns
+ option Persisted options (list/set/get for future policy)
+ exec Run a command inside the subu netns
+
+Tip: `subu help` (or `subu --help`) shows detailed help; `subu help WG` shows topic help.
+++ ./subu.py usage
+usage: subu [-V] <verb> [<args>]
+
+Quick verbs:
+ usage Show this usage summary
+ help [topic] Detailed help; same as -h / --help
+ example End-to-end example session
+ version Print version
+
+Main verbs:
+ init Initialize a new subu database (refuses if it exists)
+ create Create a minimal subu record (defaults only)
+ info | information Show details for a subu
+ WG WireGuard object operations
+ attach Attach a WG object to a subu (netns + cgroup/eBPF)
+ detach Detach WG from a subu
+ network Bring all attached ifaces up/down inside the subu netns
+ lo Bring loopback up/down inside the subu netns
+ option Persisted options (list/set/get for future policy)
+ exec Run a command inside the subu netns
+
+Tip: `subu help` (or `subu --help`) shows detailed help; `subu help WG` shows topic help.
+++ ./subu.py -h
+subu — manage subu containers, namespaces, and WG attachments
+
+2.1 Core
+
+ subu init <TOKEN>
+ Create ./subu.db (tables: subu, wg, links, options, state).
+ Requires a 6-char token (e.g., dzkq7b). Refuses if DB already exists.
+
+ subu create <masu> <subu>
+ Make a default subu with netns ns-<Subu_ID> containing lo only (down).
+ Returns subu_N.
+
+ subu list
+ Columns: Subu_ID, Owner, Name, NetNS, WG_Attached?, Up/Down, Steer?
+
+ subu info <Subu_ID> | subu information <Subu_ID>
+ Full record + attached WG(s) + options + iface states.
+
+2.2 Loopback
+
+ subu lo up <Subu_ID> | subu lo down <Subu_ID>
+ Toggle loopback inside the subu’s netns.
+
+2.3 WireGuard objects (independent)
+
+ subu WG global <BaseCIDR>
+ e.g., 192.168.112.0/24; allocator hands out /32 peers sequentially.
+ Shows current base and next free on success.
+
+ subu WG create <host:port>
+ Creates WG object; allocates next /32 local IP; AllowedIPs=0.0.0.0/0.
+ Returns WG_M.
+
+ subu WG server_provided_public_key <WG_ID> <Base64Key>
+ Stores server’s pubkey.
+
+ subu WG info <WG_ID> | subu WG information <WG_ID>
+ Endpoint, allocated IP, pubkey set?, link state (admin/oper).
+
+2.4 Link WG ↔ subu, bring up/down
+
+ subu attach WG <Subu_ID> <WG_ID>
+ Creates/configures WG device inside ns-<Subu_ID>:
+ - device name: subu_<M> (M from WG_ID)
+ - set local /32, MTU 1420, accept_local=1
+ - (no default route is added — steering uses eBPF)
+ - v1: enforce one WG per Subu; error if another attached
+
+ subu detach WG <Subu_ID>
+ Remove WG device/config from the subu’s netns; keep WG object.
+
+ subu WG up <WG_ID> | subu WG down <WG_ID>
+ Toggle interface admin state in the subu’s netns (must be attached).
+
+ subu network up <Subu_ID> | subu network down <Subu_ID>
+ Only toggles admin state for all attached ifaces. On “up”, loopback
+ is brought up first automatically. No route manipulation.
+
+2.5 Execution & (future) steering
+
+ subu exec <Subu_ID> -- <cmd> …
+ Run a process inside the subu’s netns.
+
+ subu steer enable <Subu_ID> | subu steer disable <Subu_ID>
+ (Future) Attach/detach eBPF cgroup programs to force SO_BINDTOIFINDEX=subu_<M>
+ for TCP/UDP. Default: disabled.
+
+2.6 Options (persist only, for future policy)
+
+ subu option list <Subu_ID>
+ subu option get <Subu_ID> [name]
+ subu option set <Subu_ID> <name> <value>
+
+2.7 Meta
+
+ subu usage
+ Short usage summary (also printed when no args are given).
+
+ subu help [topic]
+ This help (or per-topic help such as `subu help WG`).
+
+ subu example
+ A concrete end-to-end scenario.
+
+ subu version
+ Print version (same as -V / --version).
+++ ./subu.py --help
+subu — manage subu containers, namespaces, and WG attachments
+
+2.1 Core
+
+ subu init <TOKEN>
+ Create ./subu.db (tables: subu, wg, links, options, state).
+ Requires a 6-char token (e.g., dzkq7b). Refuses if DB already exists.
+
+ subu create <masu> <subu>
+ Make a default subu with netns ns-<Subu_ID> containing lo only (down).
+ Returns subu_N.
+
+ subu list
+ Columns: Subu_ID, Owner, Name, NetNS, WG_Attached?, Up/Down, Steer?
+
+ subu info <Subu_ID> | subu information <Subu_ID>
+ Full record + attached WG(s) + options + iface states.
+
+2.2 Loopback
+
+ subu lo up <Subu_ID> | subu lo down <Subu_ID>
+ Toggle loopback inside the subu’s netns.
+
+2.3 WireGuard objects (independent)
+
+ subu WG global <BaseCIDR>
+ e.g., 192.168.112.0/24; allocator hands out /32 peers sequentially.
+ Shows current base and next free on success.
+
+ subu WG create <host:port>
+ Creates WG object; allocates next /32 local IP; AllowedIPs=0.0.0.0/0.
+ Returns WG_M.
+
+ subu WG server_provided_public_key <WG_ID> <Base64Key>
+ Stores server’s pubkey.
+
+ subu WG info <WG_ID> | subu WG information <WG_ID>
+ Endpoint, allocated IP, pubkey set?, link state (admin/oper).
+
+2.4 Link WG ↔ subu, bring up/down
+
+ subu attach WG <Subu_ID> <WG_ID>
+ Creates/configures WG device inside ns-<Subu_ID>:
+ - device name: subu_<M> (M from WG_ID)
+ - set local /32, MTU 1420, accept_local=1
+ - (no default route is added — steering uses eBPF)
+ - v1: enforce one WG per Subu; error if another attached
+
+ subu detach WG <Subu_ID>
+ Remove WG device/config from the subu’s netns; keep WG object.
+
+ subu WG up <WG_ID> | subu WG down <WG_ID>
+ Toggle interface admin state in the subu’s netns (must be attached).
+
+ subu network up <Subu_ID> | subu network down <Subu_ID>
+ Only toggles admin state for all attached ifaces. On “up”, loopback
+ is brought up first automatically. No route manipulation.
+
+2.5 Execution & (future) steering
+
+ subu exec <Subu_ID> -- <cmd> …
+ Run a process inside the subu’s netns.
+
+ subu steer enable <Subu_ID> | subu steer disable <Subu_ID>
+ (Future) Attach/detach eBPF cgroup programs to force SO_BINDTOIFINDEX=subu_<M>
+ for TCP/UDP. Default: disabled.
+
+2.6 Options (persist only, for future policy)
+
+ subu option list <Subu_ID>
+ subu option get <Subu_ID> [name]
+ subu option set <Subu_ID> <name> <value>
+
+2.7 Meta
+
+ subu usage
+ Short usage summary (also printed when no args are given).
+
+ subu help [topic]
+ This help (or per-topic help such as `subu help WG`).
+
+ subu example
+ A concrete end-to-end scenario.
+
+ subu version
+ Print version (same as -V / --version).
+++ ./subu.py help
+subu — manage subu containers, namespaces, and WG attachments
+
+2.1 Core
+
+ subu init <TOKEN>
+ Create ./subu.db (tables: subu, wg, links, options, state).
+ Requires a 6-char token (e.g., dzkq7b). Refuses if DB already exists.
+
+ subu create <masu> <subu>
+ Make a default subu with netns ns-<Subu_ID> containing lo only (down).
+ Returns subu_N.
+
+ subu list
+ Columns: Subu_ID, Owner, Name, NetNS, WG_Attached?, Up/Down, Steer?
+
+ subu info <Subu_ID> | subu information <Subu_ID>
+ Full record + attached WG(s) + options + iface states.
+
+2.2 Loopback
+
+ subu lo up <Subu_ID> | subu lo down <Subu_ID>
+ Toggle loopback inside the subu’s netns.
+
+2.3 WireGuard objects (independent)
+
+ subu WG global <BaseCIDR>
+ e.g., 192.168.112.0/24; allocator hands out /32 peers sequentially.
+ Shows current base and next free on success.
+
+ subu WG create <host:port>
+ Creates WG object; allocates next /32 local IP; AllowedIPs=0.0.0.0/0.
+ Returns WG_M.
+
+ subu WG server_provided_public_key <WG_ID> <Base64Key>
+ Stores server’s pubkey.
+
+ subu WG info <WG_ID> | subu WG information <WG_ID>
+ Endpoint, allocated IP, pubkey set?, link state (admin/oper).
+
+2.4 Link WG ↔ subu, bring up/down
+
+ subu attach WG <Subu_ID> <WG_ID>
+ Creates/configures WG device inside ns-<Subu_ID>:
+ - device name: subu_<M> (M from WG_ID)
+ - set local /32, MTU 1420, accept_local=1
+ - (no default route is added — steering uses eBPF)
+ - v1: enforce one WG per Subu; error if another attached
+
+ subu detach WG <Subu_ID>
+ Remove WG device/config from the subu’s netns; keep WG object.
+
+ subu WG up <WG_ID> | subu WG down <WG_ID>
+ Toggle interface admin state in the subu’s netns (must be attached).
+
+ subu network up <Subu_ID> | subu network down <Subu_ID>
+ Only toggles admin state for all attached ifaces. On “up”, loopback
+ is brought up first automatically. No route manipulation.
+
+2.5 Execution & (future) steering
+
+ subu exec <Subu_ID> -- <cmd> …
+ Run a process inside the subu’s netns.
+
+ subu steer enable <Subu_ID> | subu steer disable <Subu_ID>
+ (Future) Attach/detach eBPF cgroup programs to force SO_BINDTOIFINDEX=subu_<M>
+ for TCP/UDP. Default: disabled.
+
+2.6 Options (persist only, for future policy)
+
+ subu option list <Subu_ID>
+ subu option get <Subu_ID> [name]
+ subu option set <Subu_ID> <name> <value>
+
+2.7 Meta
+
+ subu usage
+ Short usage summary (also printed when no args are given).
+
+ subu help [topic]
+ This help (or per-topic help such as `subu help WG`).
+
+ subu example
+ A concrete end-to-end scenario.
+
+ subu version
+ Print version (same as -V / --version).
+++ ./subu.py help WG
+usage: subu WG [-h]
+
+options:
+ -h, --help show this help message and exit
+++ ./subu.py example
+# 0) Safe init (refuses if ./subu.db exists)
+subu init dzkq7b
+# -> created ./subu.db
+
+# 1) Create Subu
+subu create Thomas US
+# -> Subu_ID: subu_7
+# -> netns: ns-subu_7 with lo (down)
+
+# 2) Define WG pool (once per host)
+subu WG global 192.168.112.0/24
+# -> base set; next free: 192.168.112.2/32
+
+# 3) Create WG object with endpoint
+subu WG create ReasoningTechnology.com:51820
+# -> WG_ID: WG_0
+# -> local IP: 192.168.112.2/32
+# -> AllowedIPs: 0.0.0.0/0
+
+# 4) Add server public key
+subu WG server_provided_public_key WG_0 ABCDEFG...xyz=
+# -> saved
+
+# 5) Attach WG to Subu (device created/configured in ns)
+subu attach WG subu_7 WG_0
+# -> device ns-subu_7/subu_0 configured (no default route)
+
+# 6) Bring network up (lo first, then attached ifaces)
+subu network up subu_7
+# -> lo up; subu_0 admin up
+
+# 7) Start the WG engine inside the netns
+subu WG up WG_0
+# -> up, handshakes should start
+
+# 8) Test from inside the subu
+subu exec subu_7 -- curl -4v https://ifconfig.me
+++ ./subu.py version
+0.1.3
+++ ./subu.py -V
+0.1.3
+++ set +x