{"id":45792428,"url":"https://github.com/mhajder/tftp-rs","last_synced_at":"2026-02-26T12:10:53.452Z","repository":{"id":338272015,"uuid":"1157294892","full_name":"mhajder/tftp-rs","owner":"mhajder","description":"A high-performance, single-binary TFTP server with a real-time TUI dashboard. Implements the TFTP protocol from scratch with full support for Read (RRQ), Write (WRQ), RFC 2347/2348 option negotiation, and an optional HTTP file server.","archived":false,"fork":false,"pushed_at":"2026-02-13T16:59:20.000Z","size":533,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-02-14T00:50:06.362Z","etag":null,"topics":["cli","file-transfer","http-server","networking","rust","server","tftp","tftp-server","tui"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mhajder.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"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}},"created_at":"2026-02-13T16:52:04.000Z","updated_at":"2026-02-13T16:59:16.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/mhajder/tftp-rs","commit_stats":null,"previous_names":["mhajder/tftp-rs"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/mhajder/tftp-rs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mhajder%2Ftftp-rs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mhajder%2Ftftp-rs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mhajder%2Ftftp-rs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mhajder%2Ftftp-rs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mhajder","download_url":"https://codeload.github.com/mhajder/tftp-rs/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mhajder%2Ftftp-rs/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29858513,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-26T08:51:08.701Z","status":"ssl_error","status_checked_at":"2026-02-26T08:50:19.607Z","response_time":89,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["cli","file-transfer","http-server","networking","rust","server","tftp","tftp-server","tui"],"created_at":"2026-02-26T12:10:52.893Z","updated_at":"2026-02-26T12:10:53.445Z","avatar_url":"https://github.com/mhajder.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# tftp-rs\n\nA high-performance, single-binary TFTP server with a real-time TUI dashboard. Implements the TFTP protocol from scratch with full support for both Read (RRQ) and Write (WRQ) operations, RFC option negotiation (blksize, timeout, tsize, windowsize), netascii mode, and an optional HTTP file server.\n\n## Implemented RFCs\n\n| RFC | Description |\n|-----|-------------|\n| [RFC 1350](https://www.rfc-editor.org/rfc/rfc1350) | The TFTP Protocol (Revision 2) |\n| [RFC 2347](https://www.rfc-editor.org/rfc/rfc2347) | TFTP Option Extension |\n| [RFC 2348](https://www.rfc-editor.org/rfc/rfc2348) | TFTP Blocksize Option |\n| [RFC 2349](https://www.rfc-editor.org/rfc/rfc2349) | TFTP Timeout Interval and Transfer Size Options |\n| [RFC 7440](https://www.rfc-editor.org/rfc/rfc7440) | TFTP Windowsize Option |\n\n## Features\n\n- **RFC 1350 compliant** -- hand-rolled TFTP protocol, no external TFTP crates\n- **RFC 2347/2348 option negotiation** -- blksize up to 65,464 bytes; capped via `--max-block-size` for VPN environments\n- **RFC 2349 timeout + tsize** -- clients can negotiate a custom reply timeout; tsize reports file size on downloads and is echoed on uploads\n- **RFC 7440 windowsize** -- windowed transfers send multiple DATA blocks before waiting for ACK, significantly improving throughput on high-latency links\n- **Netascii mode** -- full bidirectional conversion (`\\n` ↔ `\\r\\n`, `\\r` ↔ `\\r\\0`) across block boundaries for legacy clients\n- **Unlimited transfer size** -- block numbers roll over correctly (u16 wrap-around), enabling files larger than 32 MB with the default 512-byte block size\n- **Full RRQ + WRQ** -- serve files to clients (download) and receive files from clients (upload)\n- **Subdirectory support** -- read and write files in nested directories (e.g. `ios/config/router.cfg`)\n- **Async I/O** -- built on `tokio` with non-blocking UDP sockets\n- **Ephemeral transfer sockets** -- each transfer gets its own OS-assigned port, keeping the main listener free\n- **Request deduplication** -- duplicate requests from the same peer are silently dropped while a transfer is already in progress\n- **Overwrite protection** -- WRQ for existing files can be rejected with `--no-allow-overwrite` (returns error code 6)\n- **Access control** -- `--disable-read` or `--disable-write` to restrict what operations clients may perform\n- **Configurable retransmission** -- `--timeout` (ms) and `--max-retries` to tune behaviour for unstable networks\n- **HTTP file server** -- optional HTTP server for browser-based directory browsing and file downloads (`--http-port`)\n- **TUI dashboard** -- real-time view of server status, shared files tree, active transfers with progress bars, and timestamped scrollable logs\n- **Interface discovery** -- displays all non-loopback network interface IPs in the header (auto-refreshes every 10 seconds)\n- **Scrollable panels** -- Tab to cycle focus between Shared Files, Active Transfers, and Logs panels; Up/Down to scroll\n- **Log file export** -- optionally write all logs to a file with `--log-file`\n- **Path sanitization** -- prevents directory traversal attacks\n\n## Screenshot\n\n![Screenshot](./.github/screenshot.png)\n\n## Installation\n\n### From source\n\n```bash\ngit clone https://github.com/mhajder/tftp-rs.git\ncd tftp-rs\ncargo build --release\n```\n\nThe binary will be at `target/release/tftp-rs`.\n\n### From GitHub Releases\n\nDownload a pre-built binary for your platform from the [Releases](https://github.com/mhajder/tftp-rs/releases) page.\n\n## Usage\n\n```bash\n# Serve the current directory on port 69 (default)\ntftp-rs\n\n# Serve a specific directory on a custom port\ntftp-rs -p 69 -d /srv/tftp\n\n# Enable log file output\ntftp-rs -d /srv/tftp -l /var/log/tftp.log\n\n# Enable HTTP file server alongside TFTP\ntftp-rs -d /srv/tftp --http-port 8080\n\n# Enable windowed transfers (RFC 7440) for faster throughput\ntftp-rs -d /srv/tftp -w 4\n\n# Set a lower timeout for fast/unstable links\ntftp-rs -d /srv/tftp -t 200\n\n# Limit blksize (useful behind VPNs with small MTU)\ntftp-rs -d /srv/tftp --max-block-size 1468\n\n# Reject uploads for existing files\ntftp-rs -d /srv/tftp --allow-overwrite false\n\n# All options combined\ntftp-rs -p 69 -d /srv/tftp -l /var/log/tftp.log --http-port 8080 -w 4 -t 200\n```\n\n### CLI Options\n\n```\nOptions:\n  -p, --port \u003cPORT\u003e                  UDP port to listen on [default: 69]\n  -d, --dir \u003cDIR\u003e                    Directory to serve / receive files [default: .]\n  -l, --log-file \u003cLOG_FILE\u003e          Optional file path to write logs to\n      --http-port \u003cPORT\u003e             Enable HTTP file server on the specified port\n  -t, --timeout \u003cMS\u003e                 Reply timeout in milliseconds [default: 500]\n      --max-block-size \u003cBYTES\u003e       Max negotiable blksize (0 = OS auto-detect) [default: 0]\n  -w, --max-window-size \u003cN\u003e          Max RFC 7440 window size (1 = disable) [default: 1]\n      --allow-overwrite              Allow overwriting existing files on WRQ [default: true]\n      --max-retries \u003cN\u003e              Max retransmission attempts [default: 10]\n      --disable-read                 Reject all RRQ (download) requests\n      --disable-write                Reject all WRQ (upload) requests\n  -h, --help                         Print help\n  -V, --version                      Print version\n```\n\n### TUI Controls\n\n| Key              | Action                                  |\n|------------------|-----------------------------------------|\n| `q` / `Esc`      | Open quit confirmation dialog          |\n| `Tab`            | Cycle focus between panels              |\n| `Up` / `Down`    | Scroll the focused panel               |\n| `Left` / `Right` | Toggle Yes/No in quit dialog           |\n| `Enter`          | Confirm selection in quit dialog        |\n| `y`              | Confirm quit                            |\n| `n`              | Cancel quit                             |\n\n### Testing with a TFTP client\n\n```bash\n# Download a file from the server\ntftp localhost 69\n\u003e get filename.txt\n\n# Download a file from a subdirectory\ntftp localhost 69\n\u003e get configs/switches/sw1.cfg\n\n# Upload a file to the server\ntftp localhost 69\n\u003e put localfile.txt\n\n# Upload a file into a subdirectory (created automatically)\ntftp localhost 69\n\u003e put configs/new_config.cfg\n```\n\n## Architecture\n\n```\nsrc/\n  main.rs              Entry point, CLI args (clap), TUI event loop\n  tftp_protocol.rs     TFTP packet parsing/serialization + netascii codec\n                       (RFC 1350, 2347, 2348, 2349, 7440)\n  server.rs            Async TFTP server (tokio), RRQ + WRQ handlers,\n                       option negotiation, windowed transfer, ServerConfig\n  http_server.rs       Optional HTTP file server (axum)\n  ui.rs                TUI dashboard (ratatui + crossterm)\ntests/\n  integration.rs       End-to-end RRQ/WRQ integration tests including\n                       blksize/tsize negotiation and block-number rollover\n```\n\n### Protocol Implementation\n\nAll TFTP packet types are manually parsed and serialized with Big-Endian byte order:\n\n| Opcode | Type  | Description                                  |\n|--------|-------|----------------------------------------------|\n| 1      | RRQ   | Read request (client download)               |\n| 2      | WRQ   | Write request (client upload)                |\n| 3      | DATA  | Data payload (up to 65,464-byte blocks)      |\n| 4      | ACK   | Acknowledgment                               |\n| 5      | ERROR | Error notification                           |\n| 6      | OACK  | Option acknowledgment (RFC 2347)             |\n\n### Option Negotiation\n\nWhen a client includes options in its RRQ/WRQ request, the server responds with an OACK packet acknowledging the negotiated values before data transfer begins.\n\n| Option | RFC | Description |\n|--------|-----|-------------|\n| `blksize` | 2348 | Block payload size, 8–65,464 bytes (default 512). Capped by `--max-block-size` and OS UDP limit. |\n| `timeout` | 2349 | Per-transfer reply timeout in seconds (1–255). Overrides the server default for that transfer. |\n| `tsize` | 2349 | On RRQ: server reports actual file size. On WRQ: server echoes back the client's value. |\n| `windowsize` | 7440 | Number of DATA blocks sent before waiting for an ACK. Capped by `--max-window-size`. |\n\n### Windowed Transfer (RFC 7440)\n\nWith `--max-window-size N` (N \u003e 1), the server sends up to N DATA blocks before pausing for an ACK. Partial ACKs within a window slide it forward without retransmitting the already-acknowledged blocks. On timeout, the entire unacknowledged window is retransmitted. This significantly improves throughput on high-latency links.\n\n### Netascii Mode\n\nThe server fully supports the `netascii` transfer mode:\n- **Download (RRQ):** binary data is encoded on the fly (`\\n` → `\\r\\n`, `\\r` → `\\r\\0`) with overflow tracking across block boundaries.\n- **Upload (WRQ):** incoming netascii data is decoded to binary (`\\r\\n` → `\\n`, `\\r\\0` → `\\r`) with carry-over state for `\\r` spanning two consecutive blocks.\n\n### Block Number Roll-over\n\nBlock numbers are 16-bit unsigned integers. The server uses `wrapping_add(1)` on every block increment, enabling files of unlimited size with any block size (e.g. a file larger than 32 MB with the default 512-byte blksize requires block numbers to wrap past 65535).\n\n## Tech Stack\n\n- **Rust** 2024 edition\n- **tokio** -- async UDP and TCP I/O\n- **ratatui** + **crossterm** -- terminal UI\n- **axum** -- HTTP file server\n- **clap** -- CLI argument parsing\n- **anyhow** -- error handling\n- **if-addrs** -- network interface discovery\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmhajder%2Ftftp-rs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmhajder%2Ftftp-rs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmhajder%2Ftftp-rs/lists"}