{"id":51478123,"url":"https://github.com/oxyzenq/zelynic","last_synced_at":"2026-07-06T23:01:16.666Z","repository":{"id":351721407,"uuid":"1212140003","full_name":"oxyzenQ/zelynic","owner":"oxyzenQ","description":"Per-process network shaping and bandwidth control for Linux","archived":false,"fork":false,"pushed_at":"2026-06-29T12:08:12.000Z","size":7586,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-06-29T14:12:34.892Z","etag":null,"topics":["bandwidth-limiter","cgroup-v2","cli","linux","network","network-management","networking","nftables","rust","tc","traffic-control","userspace"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/oxyzenQ.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"ko_fi":"rezky"}},"created_at":"2026-04-16T05:15:42.000Z","updated_at":"2026-06-29T12:08:22.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/oxyzenQ/zelynic","commit_stats":null,"previous_names":["oxyzenq/oxy","oxyzenq/zelynic"],"tags_count":15,"template":false,"template_full_name":null,"purl":"pkg:github/oxyzenQ/zelynic","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oxyzenQ%2Fzelynic","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oxyzenQ%2Fzelynic/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oxyzenQ%2Fzelynic/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oxyzenQ%2Fzelynic/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/oxyzenQ","download_url":"https://codeload.github.com/oxyzenQ/zelynic/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oxyzenQ%2Fzelynic/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35208141,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-06T02:00:07.184Z","response_time":106,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bandwidth-limiter","cgroup-v2","cli","linux","network","network-management","networking","nftables","rust","tc","traffic-control","userspace"],"created_at":"2026-07-06T23:01:15.664Z","updated_at":"2026-07-06T23:01:16.651Z","avatar_url":"https://github.com/oxyzenQ.png","language":"Rust","funding_links":["https://ko-fi.com/rezky"],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"assets/zelynic-logo-master.png\" alt=\"zelynic logo\" width=\"260\"\u003e\n\u003c/p\u003e\n\n\u003ch1 align=\"center\"\u003ezelynic\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cstrong\u003ePer-app network rate limiter for Linux.\u003c/strong\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  Pure eBPF enforcement — no \u003ccode\u003etc\u003c/code\u003e, no \u003ccode\u003enftables\u003c/code\u003e, no \u003ccode\u003esystemd-wrapper\u003c/code\u003e.\u003cbr\u003e\n  One of the first open-source Linux bandwidth managers built around a pure eBPF datapath with per-application rate limiting.\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://ko-fi.com/rezky\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/Ko--fi-support-7C3AED?style=flat-square\u0026logo=kofi\u0026logoColor=white\u0026labelColor=111827\" alt=\"Support on Ko-fi\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n## What is zelynic?\n\nzelynic limits any app's download/upload speed using **eBPF** — the Linux kernel's\nbuilt-in programmable packet filter. No external tools, no wrapper coordination,\nno daemon. Just pure kernel enforcement.\n\n```\n$ sudo zelynic strict-single brave 100kb\nLimiting 'brave' to 97.7 KB /s + 97.7 KB /s (2 policies, active in background)\nRun 'zelynic unstrict brave' to remove, 'zelynic status' to check.\n$ echo $?\n0\n# brave is now limited to 100 KB/s download + upload — persists in background\n```\n\n## Why zelynic?\n\n| Traditional tools | zelynic |\n|-------------------|---------|\n| `tc` — per-interface shaping | Per-app (per-cgroup) shaping |\n| `nftables` — packet marking | Direct eBPF token bucket |\n| `wondershaper` — global limit | Individual app limits |\n| `trickle` — LD_PRELOAD hack | Kernel-level enforcement |\n\n**Key difference**: zelynic limits **individual applications**, not interfaces.\nBrave can be limited to 100 KB/s while Firefox runs at full speed — all on the\nsame WiFi interface.\n\n## Quick Start\n\n### Prerequisites\n\n- Linux kernel 5.13+ (cgroup v2 + `cgroup.id` file)\n- Root access (BPF requires `CAP_BPF`)\n- `clang` (compile BPF programs)\n- `libbpf-dev` (BPF headers)\n\n### Build\n\n```bash\ngit clone https://github.com/oxyzenQ/zelynic.git\ncd zelynic\ngit checkout wolf-architecture\n\n# Compile BPF programs\nclang -O2 -g -target bpf -c bpf/observer.bpf.c -o bpf/observer.bpf.o\nclang -O2 -g -target bpf -c bpf/limiter.bpf.c -o bpf/limiter.bpf.o\n\n# Build Rust binary\ncargo build --release --features ebpf\n```\n\n### Usage\n\n```bash\n# Limit a single app (both download + upload = 100kb)\nsudo zelynic strict-single brave 100kb\n\n# Limit per-direction\nsudo zelynic strict-single firefox -d 1mb -u 500kb\n\n# Limit multiple apps sharing one rate (group limit)\nsudo zelynic strict-multi brave:curl:pacman 1mb\n\n# Check active limits\nsudo zelynic status\n\n# List apps with cgroup IDs\nsudo zelynic list-apps\n\n# Remove one app's limit\nsudo zelynic unstrict brave\n\n# Remove ALL limits (emergency)\nsudo zelynic unstrict-all\n\n# Real-time traffic monitor\nsudo zelynic observe --interval 5\n\n# Check eBPF support\nzelynic doctor\n```\n\n## Rate Formats\n\nLowercase units only:\n\n| Format | Meaning |\n|--------|---------|\n| `500b` | 500 bytes/second |\n| `100kb` | 100 kilobytes/second |\n| `1mb` | 1 megabyte/second |\n| `1gb` | 1 gigabyte/second |\n| `1000000` | Plain number = bytes/second |\n\n**Bounds**: minimum 1 KB/s, maximum 1 GB/s. Below minimum requires `--allow-dangerous`.\n\n## Safety Features\n\n- **Watchdog**: BPF auto-disables if zelynic crashes (default 30s timeout)\n- **Min-rate guard**: rejects rates below 1 KB/s (prevents bricking apps)\n- **Fire-and-forget**: `strict-single` exits 0, limit persists in background\n- **No residue**: `unstrict-all` kills child + removes all pin files\n- **Fail-safe BPF**: returns \"allow\" on any error path (never blocks on failure)\n\n## Architecture\n\n**Wolf Architecture** — pure eBPF, single hooking layer:\n\n```\n┌─────────────────────────────────────────────────────────┐\n│  Layer 4 — Presentation (CLI)                           │\n│  strict-single / strict-multi / status / unstrict       │\n├─────────────────────────────────────────────────────────┤\n│  Layer 3 — Aggregation (delta computation, sorting)     │\n├─────────────────────────────────────────────────────────┤\n│  Layer 2 — Identity Resolution (/proc → cgroup ID)      │\n├─────────────────────────────────────────────────────────┤\n│  Layer 1 — Map Interface (aya, pinned maps)             │\n├─────────────────────────────────────────────────────────┤\n│  Layer 0 — BPF Programs (kernel)                        │\n│  cgroup_skb/ingress (download) + cgroup_skb/egress (upload) │\n└─────────────────────────────────────────────────────────┘\n```\n\nSee [docs/WOLF_ARCHITECTURE.md](docs/WOLF_ARCHITECTURE.md) for full design.\n\n## Branches\n\n| Branch | Purpose | Status |\n|--------|---------|--------|\n| `main` | Legacy v3.x (tc/nft/systemd-wrapper) | Stable, maintained |\n| `wolf-architecture` | Pure eBPF v4.0.0-alpha | Active development |\n\n## Documentation\n\n- [Wolf Architecture](docs/WOLF_ARCHITECTURE.md) — design + principles\n- [Kernel Compatibility](docs/KERNEL_COMPATIBILITY.md) — requirements + distro matrix\n- [Migration to v4.0](docs/MIGRATION_V4.md) — v3.x → v4.0 guide\n- [Stress Test](scripts/stress-test.sh) — long-running enforcement test\n- [Benchmark](scripts/benchmark.sh) — CPU/memory overhead measurement\n\n## Test Results\n\nReal test results (Arch Linux, kernel 6.18, AMD Ryzen 7 5800HS):\n\n| App | Target | Actual Download | Actual Upload | Status |\n|-----|--------|-----------------|---------------|--------|\n| Chromium | -d 100kb -u 500kb | 670 Kbps (83 KB/s) | 3.5 Mbps | ✅ Working |\n| Brave | -d 100kb -u 500kb | 730 Kbps (91 KB/s) | 4.3 Mbps | ✅ Working |\n| aria2c | 500→100→10→2kb | Override each time | — | ✅ Override works |\n\nCPU/memory: negligible (serve child \u003c 1% CPU, \u003c 10 MB RAM).\n\n## Release Verification\n\nEach release ships **three** checksums: classical SHA-512 + quantum-resistant\nBLAKE2b-512 + SHAKE256. Full instructions in\n[docs/VERIFY_RELEASE.md](docs/VERIFY_RELEASE.md).\n\n```bash\n# Classical (universal)\nsha512sum -c zelynic-vX.Y.Z-linux-amd64-gnu.tar.gz.sha512sum\n\n# Quantum-resistant — BLAKE2b (fastest, in coreutils)\nb2sum -c zelynic-vX.Y.Z-linux-amd64-gnu.tar.gz.b2sum\n\n# Quantum-resistant — SHAKE256 (NIST PQ standard, via Python)\n# openssl's -shake256 default output length varies; Python is consistent\nCOMPUTED=$(python3 -c \"import hashlib; print(hashlib.shake_256(open('zelynic-vX.Y.Z-linux-amd64-gnu.tar.gz','rb').read()).hexdigest(64))\")\nEXPECTED=$(awk '{print $1}' zelynic-vX.Y.Z-linux-amd64-gnu.tar.gz.shake256)\n[ \"$COMPUTED\" = \"$EXPECTED\" ] \u0026\u0026 echo \"OK\" || echo \"FAILED\"\n```\n\n## License\n\nGPL-3.0-only\n\n## Author\n\n**rezky_nightky (oxyzenQ)** — built with curiosity, not pressure.\n\n---\n\n\u003cp align=\"center\"\u003e\n  \u003cem\u003eClean safely. Explain every decision. Recover anything.\u003c/em\u003e\n\u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foxyzenq%2Fzelynic","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Foxyzenq%2Fzelynic","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foxyzenq%2Fzelynic/lists"}