2026-08-22 — Initial public release prepared
Onion Downloader combines a native graphical queue and a complete command-line downloader in one
2.67 MiB Windows executable. Its original HTTP, SOCKS5, range scheduling and resume engines spread
one file over multiple independent Tor circuits. A specialized client-only Tor 0.4.9.11 is packed
into the application's icon resource, so there is no installer, browser bundle, external runtime
or loosetor.exeto carry beside the program.
Graphical queue — a multi-gigabyte transfer spread across ten parallel circuits

Command line — the same engine and the same binary, od.exe --help

Downloading a large file through one Tor circuit means that one slow path controls the whole transfer. Onion Downloader takes a different route. If an HTTP server supports byte ranges, the file is divided into independent regions and fetched by parallel workers distributed over several Tor daemons. Every daemon maintains its own circuits, so a weak route can continue working without preventing faster routes from advancing other parts of the file.
This is not a browser automation tool and it does not contain pieces of Tor Browser. The application implements the downloader itself: HTTP requests and response parsing, SOCKS5 negotiation, range planning, direct random-access writes, progress accounting, queue persistence and validated resume metadata. Tor is used for Onion transport and nothing else.
| Property | Current release |
|---|---|
| Final executable | 2.67 MiB (2,801,152 bytes) |
| Platform | Windows x64 |
| Default parallelism | 10 range workers |
| Tor process pool | Automatically selected, normally 2–8 daemons |
| Embedded Tor | 0.4.9.11, client-only, proof-of-work enabled |
| Interface | Native Win32 GUI and CLI in the same PE file |
| Runtime dependencies | Windows system libraries only |
| Default destination | Current user's Windows Downloads folder |
Real speed still depends on the Onion service, its range support, relay conditions and the user's connection. Multi-circuit scheduling removes the single-route bottleneck; it cannot manufacture bandwidth the remote service does not have.
Range is downloaded as one ordinary stream instead of producing a corrupted file.od.exe is a dual-mode executable in the same sense as a good native system utility: the presence and meaning of command-line arguments choose the interface, not a second launcher.
With no arguments it enters its Win32 message loop and presents the graphical queue. With a URL it behaves as a console downloader suitable for batch files and terminals. Both heads call the same coordinator and share every important implementation below the presentation layer. A transfer created in either mode follows the same range validation, circuit allocation and part-file rules.
This matters for correctness as much as size. There is only one resume implementation to test, one Tor lifecycle, one HTTP parser and one answer to what should happen when a server returns an unexpected status. Unknown command-line switches are rejected with an error and help text; they never accidentally open a graphical window.
| Invocation | Behaviour |
|---|---|
od.exe |
Launch the graphical interface |
od.exe http://service.onion/file.zip |
Download through the CLI using the default worker and circuit policy |
od.exe --gui |
Explicitly launch the GUI |
od.exe --help |
Print command-line usage |
Each Tor instance gets an isolated data directory and SOCKS listener. The pool waits for bootstrap rather than treating a process launch as network readiness. Workers then open SOCKS5 connections to the Onion hostname through selected instances and write only into their assigned regions of the pre-sized part file.
The coordinator owns the transfer state. It can stop issuing work immediately on Pause while preserving completed intervals, or cancel the entire operation and let the UI decide whether its recoverable files should remain.
The most important decisions are encoded as invariants rather than UI conventions. They remain true whether a transfer starts from the GUI, CLI or a restored session.
A naive parallel downloader cuts a file into exactly as many pieces as it has workers. That is particularly poor over Tor: circuit speeds can differ by an order of magnitude, so nine workers may finish and sit idle while the slowest circuit owns the final tenth of the file.
Onion Downloader creates a work queue with a target of eight segments per worker. Segment size is rounded to whole MiB and clamped between 2 MiB and 16 MiB. Workers claim the next available segment dynamically, which lets a fast circuit complete several regions while a slow circuit is still handling one. Small files automatically receive fewer effective workers; parallelism is not created merely to satisfy a number in the settings.
Progress bytes are useful for presentation but are not the source of resume truth. A segment changes from Pending to InFlight when claimed and to Complete only after its entire expected body has been received and written. If a connection stalls halfway through, the worker subtracts that partial contribution from the displayed counter and returns the whole segment to Pending. A later circuit overwrites that region from its first byte.
The completion bitmap therefore never claims that a partially received segment is durable. Resume restores only Complete bits. It does not attempt to infer safe ranges from the physical size of a sparse or pre-sized part file.
The initial probe asks for byte zero only. Parallel mode is accepted only when the response is HTTP 206, contains a parseable Content-Range, and reports a non-zero total instance length. HTTP 200 means that the server ignored the request, so the plan becomes one sequential segment. During transfer every ranged response must again be 206 and its Content-Length must equal the exact inclusive range length. An unexpected status or length is not written optimistically.
The probe follows at most five redirects and resolves their Location against the current URL. Client errors in the 4xx family stop the job because changing Tor circuits cannot make a missing or forbidden resource valid.
Every worker authenticates to SOCKS5 with its own generated isolation username. When a connection fails, the socket closes and the credential nonce advances before the range is retried. Tor's IsolateSOCKSAuth policy therefore prevents the retry from silently returning to the path that just stalled.
A worker tolerates up to ten consecutive failures, with a short linear backoff capped at five seconds. Linear rather than long exponential delay is intentional: congested Onion services often recover quickly, and another circuit should notice that recovery without making a paused-looking application wait for minutes.
Pause cannot merely set a Boolean and wait for a long receive timeout. Each live HttpConnection is registered with the job; cancellation closes its atomic socket handle, which wakes a thread blocked inside Winsock. Workers observe the stop flag, release any unfinished claim, persist the current completion bitmap and leave the file resumable.
The part file is opened once, but each worker obtains a writer that performs explicit offset-based writes. No shared sequential file position exists to race between threads. The file is pre-sized to the known resource length before range work begins, making every final offset stable; actual write failures still stop the job and preserve only ranges that reached Complete.
Stored metadata is accepted only when URL, total resource size and calculated segment size match the new probe and plan. Changing the worker count may change segmentation, so an incompatible bitmap is rejected instead of being projected onto different byte boundaries. Re-downloading is slower than guessing, but it cannot silently assemble a corrupt file.
CreateProcess returning successfully does not mean Tor can carry traffic. Onion Downloader opens each daemon's cookie-authenticated control port and polls GETINFO status/bootstrap-phase until progress reaches 100 percent. The first profile pays for a cold directory fetch; once ready, its consensus and descriptor caches seed the remaining private profiles, which then bootstrap concurrently. Guard state remains separate for the independent instances.
Socks and control ports are selected in free pairs beginning above the usual Tor and Tor Browser ports, avoiding collisions with ports 9050 and 9150. A partial pool is useful: if some secondary daemons fail, every successfully bootstrapped instance remains available and workers are distributed round-robin over the ready ports.
An unfinished archive.zip is represented by two files next to the future destination:
| File | Purpose |
|---|---|
archive.zip.odpart |
Pre-sized data file; completed ranges already occupy their final offsets |
archive.zip.odmeta |
Small JSON description used to validate the URL, expected size and completed segment map |
Resume information is not rewritten for every received block. The engine checkpoints it at controlled intervals and uses a temporary file plus replacement for atomic updates. That keeps I/O low while avoiding a half-written JSON document if the process or machine stops during a save.
The GUI has a separate session.json for queue presentation. It remembers which jobs were present, but it does not pretend that a queue row is sufficient proof that the bytes are resumable. On startup unfinished jobs return in the Paused state. Selecting a row makes Resume available, and only an explicit Resume starts Tor and network activity. This avoids a confusing apparent hang when the machine starts without Internet access.
Once every byte range has been validated, the helper pair is removed and the final destination remains.
Onion Downloader treats application code, Tor and packaging as one engineering problem. The size is produced by a chain of independent reductions rather than by one compressor at the end.
The principal size decisions are:
build.ps1 reuses the verified payload.The application never downloads Tor behind the user's back. The complete engine is already inside od.exe and can be reconstructed by Windows' native Cabinet FDI implementation in cabinet.dll.
The bundled Tor is not a renamed copy of an entire browser distribution. It is a separate, statically linked Windows x64 console program built from official C-Tor sources for one job: establish client circuits and expose local SOCKS endpoints to Onion Downloader.
| Tor capability | Included? | Reason |
|---|---|---|
| Onion client and SOCKS proxy | Yes | Core transport required by the downloader |
| Onion-service proof-of-work client | Yes | Required for compatibility with services defending themselves under load |
| Relay module | No | Onion Downloader never carries traffic for other clients |
| Directory authority module | No | It never operates Tor network authority infrastructure |
| Directory cache role | No | It is a client, not a public cache |
| Unit tests, manuals and Tor applications | No | Build-time material, not runtime client functionality |
System-wide torrc |
No | Each managed process receives its explicit private configuration |
Removing proof-of-work would save some code but would be the wrong optimization: a smaller engine that cannot reach a protected Onion service is not an equivalent engine. The build keeps this feature and still removes several megabytes of unrelated general-purpose functionality.
As a technical curiosity, the embedded engine uses Tor 0.4.9.11 — the newest official C-Tor release available when the build was prepared — compiled inside Ubuntu 26.04 under WSL. The output is nevertheless a genuine native Windows PE executable. MinGW-w64 cross-compiles every component for x86-64 Windows; Linux is only the build host.
Tor is configured as a static GPL client with relay and directory-authority modules disabled. OpenSSL 3.5.7 is separately configured without its applications, tests, documentation, legacy provider and cryptographic or protocol families the selected Tor client does not use. libevent and zlib are static as well. Functions and data occupy separate object sections, allowing the linker to remove unreachable sections before the final executable is stripped.
The Windows PE security flags remain intentional: NX compatibility, ASLR, high-entropy ASLR and a Windows 7-or-newer API target. The full reproducible command line is kept in build-tor.sh in the repository rather than turning this page into a configure log.
The GUI follows Windows rather than imposing a custom theme. It uses native controls, PerMonitorV2 scaling, system light/dark preference and Mica where Windows 11 provides it. Download rows use a restrained grayscale presentation: progress is visible without turning the queue into a collection of unrelated status colours.
Paste an Onion URL with Ctrl+V anywhere in the main window, drag a URL onto it, or focus the address field and type normally. Add places the address in the queue. Selecting a live or incomplete row exposes the operation that makes sense for its current state: Pause for running work, Resume for a recoverable stopped transfer, and Remove for queue cleanup.
The address hint explicitly advertises both methods — paste an Onion URL or use Ctrl+V — so the fastest path is visible before the user interacts with the window.
Running with no arguments launches the GUI. Supplying a URL downloads to the current user's Windows Downloads directory with ten workers and the automatic Tor pool:
od.exe http://example.onion/dataset.zip
Choose the output directory or tune worker and Tor process counts when the service and local machine justify it:
od.exe -s 20 -c 8 -o D:\Data http://example.onion/bigfile.bin
| Option | Meaning |
|---|---|
<URL> |
Target HTTP address, normally an Onion service |
-s, --split <N> |
Parallel workers; default 10, maximum 64 |
-c, --circuits <N> |
Independent Tor daemons; default automatic, normally 2–8 |
-o, --out <dir> |
Destination directory; default is the user's Downloads known folder |
-g, --gui |
Launch the graphical interface explicitly |
-h, --help |
Print help and exit |
-v, --version |
Print version and build information |
The command-line banner uses ASCII (C) Marek Wesolowski (2026) deliberately, so it remains readable in shells and redirected files using different legacy code pages. The graphical About information retains the proper copyright symbol and Polish spelling.
The source tree follows runtime responsibility rather than putting the whole program behind the window class:
| Area | Responsibility |
|---|---|
src/core/DownloadEngine.* |
Job lifecycle, probing, worker creation, retry policy, progress monitoring and finalization |
src/core/SegmentMap.* |
Dynamic range work queue, Pending/InFlight/Complete state and compact resume bitmap |
src/core/PartFile.* |
Pre-sized random-access file, independent writers, atomic metadata and final rename |
src/core/SessionManager.* |
GUI queue persistence and safe restoration of active work as Paused |
src/core/TorPool.* |
Private profiles, ports, process job, control authentication, bootstrap and consensus seeding |
src/core/TorExtractor.* |
In-memory Cabinet FDI callbacks, embedded payload fingerprint and local Tor cache |
src/net/Socks5.* |
Cancellable Winsock stream and SOCKS5 hostname connection with authentication isolation |
src/net/HttpClient.* |
URL parsing, HTTP requests, bounded headers, ranges, redirects and response validation |
src/ui/OdWindow.* |
Native window lifecycle, queue interaction, clipboard, OLE drop target and command routing |
src/ui/Controls.* |
List view, grayscale progress-cell drawing and control theming |
src/cli/* |
Strict argument parsing, console ownership and terminal progress presentation |
The dependencies point inward: GUI and CLI depend on the core; the core depends on the small networking layer and WinAPI; neither networking nor persistence knows how a row is painted. This is what makes the dual-mode design real instead of a GUI program with a thin command-line afterthought.
Concurrency ownership is similarly explicit. Job state and segment publication use engine mutexes, high-frequency counters and stop state are atomic, segment claims are serialized inside SegmentMap, and connection registration has its own mutex so cancellation can close live sockets without racing their destruction.
Correctness is tested at the boundaries where downloaders commonly fail:
Content-Range from a server returning 200 to a range probe.tor.exe survives.od.exe with the checked-in payload and confirm its compiled module list.od.zip, reopen it and test every archived byte before publication so the published binary is exactly the verified one.The current specialized Tor reports proof-of-work support enabled and relay, directory-authority and directory-cache modules disabled. Its imported libraries are Windows system DLLs only. The complete CLI integration run exits cleanly after downloading through the embedded engine.
The engineering rule is that a visual success state follows the durable state, never precedes it. A transfer becomes Completed only after all segments are complete and the part file has been flushed, closed and moved into its final name. If finalization fails, the UI receives an error instead of a cosmetic 100 percent result.
The application build requires Windows x64, PowerShell and Visual Studio with the MSVC C++ x64 toolchain. Extract od_source_code.zip; the bundled resources\tor.exe is the pinned client payload, so an ordinary build does not require WSL:
# From the extracted source-tree root:
.\build.ps1
The script locates the newest usable Visual Studio installation, builds Release|x64, removes stale loose Tor files and leaves the single application in bin\od.exe. Its deterministic PE settings use a fixed file timestamp and reproducible-link option. Repack the Tor cabinet intentionally with:
.\build.ps1 -Clean -RepackTor
Rebuilding Tor itself is a separate WSL/MinGW path. On Ubuntu install the standard compiler, autotools, Perl and MinGW-w64 packages, then run ./build-tor.sh. The script downloads pinned Tor, OpenSSL, libevent and zlib releases, verifies the Tor source checksum, cross-builds the Windows client, replaces resources\tor.exe and invokes the Windows repack step.
od.zip contains the single Windows x64 binary od.exe (2,801,152 bytes) with the embedded Tor engine; od_source_code.zip contains the full source tree, the build scripts and the pinned resources. Neither archive is password-protected.
Onion Downloader's original source is released under the MIT License.
The embedded Tor executable remains a separate GPLv3-or-later program. OpenSSL, libevent and zlib retain their upstream licenses. Exact versions, source links and the reproducible Tor configuration are included in the public repository.
Marek Wesołowski — WESMAR
https://kvc.pl