A peer-to-peer file synchronization tool for local networks that requires no prior configuration or persistent credentials.
Most file synchronization tools rely on one of the following:
- Manual device pairing (e.g exchanging device IDs)
- Cloud-based coordination
- Pre-shared secrets or credentials
- Certificate authorities
dsync instead uses ephemeral identities and automatic peer discovery.
Typical workflow:
- Start dsync → generates a temporary cryptographic identity
- Peers are discovered automatically using mDNS
- A challenge–response handshake verifies peer identity
- An encrypted channel is established via X25519 key exchange
- File synchronization begins
- When dsync exits, the identity is discarded
- Ed25519 challenge–response authentication
- X25519 ECDH key exchange per session
- ChaCha20-Poly1305 end-to-end encryption
- Ephemeral identities generated on each startup
- No pre-configured peers or persistent credentials
- Rate limiting to protect against handshake flooding
- Designed for local networks only (no internet communication)
- Real-time synchronization using filesystem notifications
- Chunked file transfers for large files
- Blake3 hashing for fast integrity verification
- Asynchronous I/O using Tokio
- LZ4 compression for compressible files
- Persistent connection pool (eliminates per-transfer handshake overhead)
- Parallel transfers with configurable concurrency
- Automatic peer discovery using mDNS
- Direct peer-to-peer TCP connections
- Supports multiple peers on the same network
- Handles temporary network interruptions
- No cloud services
- No telemetry or data collection
- No accounts or registration
- Fully peer-to-peer architecture
- Rust toolchain (1.80+)
# Clone the repository
git clone https://github.com/mel-edo/dsync.git
cd dsync
# Build release binary
cargo build --release
# Install to system (optional)
sudo cp target/release/dsync /usr/local/bin/
# or for user-only install
cp target/release/dsync ~/.local/bin/# On Machine 1
dsync -d ~/path/to/folder
# On Machine 2
dsync -d ~/path/to/folder
# That's it! They'll discover each other and start syncing.dsync -d <directory> -p <port> -n <name>| Flag | Description | Default | Required |
|---|---|---|---|
-d, --path |
Directory to sync | - | Yes |
-p, --port |
TCP port to listen on | 9000 | No |
-n, --name |
Friendly name for this instance | dsync-instance |
No |
-a, --peer |
Manually specify peer (format: ip:port) |
- | No |
--no-discovery |
Disable automatic mDNS discovery | false | No |
-v, --verbose |
Show detailed logs | false | No |
-e, --exclude |
Exclude pattern, repeatable (e.g. *.log) |
- | No |
Basic sync between two machines:
# Machine A
dsync -d ~/shared -p 9000 -n machine-a
# Machine B
dsync -d ~/shared -p 9000 -n machine-bVerbose mode (see what's happening):
dsync -d ~/Documents -vDisable auto-discovery (manual peer specification):
dsync -d ~/sync -p 9000 --no-discovery -a 192.168.1.100:9000Exclude patterns:
dsync -d ~/code -e "*.log" -e "build/"Multiple instances on same machine (for testing):
# Terminal 1
dsync -d ./test_a -p 9000 -n instance-a -v
# Terminal 2
dsync -d ./test_b -p 9001 -n instance-b -v
# Terminal 3
dsync -d ./test_c -p 9002 -n instance-c -vdsync looks for a config file at:
- Linux/macOS:
~/.config/dsync/dsync.toml - Windows:
%APPDATA%\dsync\dsync.toml
All values are optional and overridden by CLI arguments.
# dsync.toml
# Folder to sync (can be overridden with -d)
path = "/home/user/sync"
# Port to listen on
port = 9000
# Instance name shown during discovery
name = "dsync-instance"
# Static peer to always connect to (in addition to mDNS)
# peer = "192.168.1.100:9000"
# Disable mDNS auto-discovery
# no_discovery = false
# Maximum concurrent file transfers
max_concurrent_transfers = 4On startup:
├─ Generate Ed25519 keypair (signing key)
├─ Derive peer ID from public key
└─ Identity exists only in memory (never saved to disk)
mDNS Broadcast:
├─ Service: _dsync._tcp.local
├─ Port: 9000 (configurable)
└─ TXT Record: {id: <public_key_hex>}
Peers discover each other automatically on LAN
Client → Server: [TCP Connect]
Server → Client: Challenge (32 random bytes)
Client → Server: {PublicKey, Signature(Challenge)}
Server: Verify signature → Send Ack + X25519 public key
Client → Server: X25519 public key
Both: Derive shared secret → ChaCha20-Poly1305 encrypted channel
If signature valid → Encrypted channel established
If signature invalid → Connection dropped immediately
Initial Sync:
├─ Exchange file indexes (path, size, modified time)
├─ Calculate diff (missing/outdated files)
└─ Request missing files
Real-time Sync:
├─ File watcher detects changes
├─ Compute Blake3 hash
├─ Compress with LZ4 (if compressible)
├─ Encrypt and broadcast to all trusted peers
└─ Peers apply changes locally
A .dsyncignore file is automatically created in your sync directory on first run. Edit it to control what gets synced.
# dsyncignore - files and patterns listed here will not be synced
# Uses glob syntax. Lines starting with # are comments.
# Version control
.git
.git/**
# Dependencies
node_modules
node_modules/**
# OS files
.DS_Store
# Temporary files
*.tmp
*.partAlways ignored:
*.part- partial downloads in progress.dsyncignore- the ignore file itself
Authentication - peers prove ownership of their advertised public key Encryption - all traffic is encrypted with ChaCha20-Poly1305 Integrity - Blake3 hashing detects corruption and prevents duplicate transfers Ephemeral identity - no persistent credentials to steal or leak Local trust - only peers on the same mDNS domain can discover each other DoS protection - rate limiting on handshake attempts per IP
Internet sync - dsync is designed for trusted local networks only
Authorization - Any peer on LAN that completes the handshake can sync (by design)
Anonymity - Hostnames/IPs are visible on the network
Protected against:
- Unauthorized peers (must complete Ed25519 handshake)
- Replay attacks (challenge-response with fresh random challenge each time)
- Identity theft (keys are never saved to disk)
- Passive eavesdropping (ChaCha20-Poly1305 encryption)
- Handshake flooding (per-IP rate limiting)
Not protected against:
- Malicious peers on the same network (dsync assumes a trusted LAN)
- Man-in-the-middle (mDNS can be spoofed on hostile networks)
- Physical access to a running machine (keys exist in memory while running)
Recommendation: Use on trusted networks (home/office LAN, VPN). Do not expose port 9000 to the internet.
- Ephemeral Ed25519 identity
- mDNS peer discovery
- Challenge-response handshake
- X25519 ECDH + ChaCha20-Poly1305 end-to-end encryption
- Real-time file watching
- Chunked file transfers
- LZ4 compression
- Persistent connection pool
- Parallel transfers
- Progress indicators
- .dsyncignore with auto-generation
- --exclude CLI flag
- Rate limiting (DoS protection)
- Config file support (dsync.toml)
- Graceful shutdown
- Multi-peer support
- Cross-platform support
Check:
- Both machines on same network segment (mDNS doesn't cross VLANs)
- Firewall allows UDP 5353 (mDNS) and TCP port 9000
- mDNS/Avahi service running (Linux:
systemctl status avahi-daemon)
Workaround:
# Manually specify peer IP
dsync -d ~/sync -p 9000 -a 192.168.1.100:9000Check:
- File not in
.dsyncignore - Run with
-vto see events - Check file permissions
- Verify available disk space on receiving end
Suggestions, fixes and improvments are welcome. Feel free to open an issue or a PR.
This project is licensed under the GNU General Public License v3.0 - see the LICENSE file for details.