Skip to content

Repository files navigation

skypeernet

BSD license Build Status Ohloh Project Status

skypeernet is a decentralized peer-to-peer file sharing network with blockchain-based file tracking.

Table of Contents

Features

  • Decentralized P2P Network: Direct peer-to-peer communication with tracker-assisted discovery
  • Blockchain-based File Index: Files are tracked in a mineable blockchain
  • Chunked File Transfer: Large files are split into chunks with SHA256 verification
  • RSA Authentication: Peers authenticate using RSA key pairs
  • NAT Traversal: Proxy/shadow routing for peers behind NAT
  • TCP Tunneling: Tunnel TCP connections over the P2P network
  • Bandwidth Control: Configurable upload/download limits
  • Plugin System: Erlang (johnconnor) and Python (skynet) plugins

Architecture

┌─────────────────────────────────────────────────────────────────┐
│                         NETWORK                                  │
│  ┌─────────┐    ┌─────────┐    ┌─────────┐    ┌─────────┐      │
│  │ Tracker │◄──►│  Peer A │◄──►│  Peer B │◄──►│  Peer C │      │
│  └─────────┘    └─────────┘    └─────────┘    └─────────┘      │
│       │              │              │              │            │
│       └──────────────┴──────────────┴──────────────┘            │
│                    UDP Protocol (port 5775)                     │
└─────────────────────────────────────────────────────────────────┘

PEER INTERNALS:
┌─────────────────────────────────────────┐
│              Application                 │
│  ┌─────────────┐  ┌─────────────────┐   │
│  │  CLI (stdin)│  │  API (pipes)    │   │
│  └──────┬──────┘  └────────┬────────┘   │
│         └──────────┬───────┘            │
│              ┌─────▼─────┐              │
│              │  Commands │              │
│              └─────┬─────┘              │
│         ┌──────────┴──────────┐         │
│   ┌─────▼─────┐        ┌──────▼──────┐  │
│   │  DistFS   │        │   World     │  │
│   │(blockchain)│        │(peer mgmt)  │  │
│   └─────┬─────┘        └──────┬──────┘  │
│         └──────────┬──────────┘         │
│              ┌─────▼─────┐              │
│              │  Payload  │              │
│              └─────┬─────┘              │
│              ┌─────▼─────┐              │
│              │  Packet   │              │
│              └─────┬─────┘              │
│              ┌─────▼─────┐              │
│              │  Network  │              │
│              │   (UDP)   │              │
│              └───────────┘              │
└─────────────────────────────────────────┘

Building

Dependencies

  • CMake >= 2.8.9
  • OpenSSL (libssl-dev)
  • libev (libev-dev)
  • json-c (libjson-c-dev)
  • readline (libreadline-dev)
  • CUnit (libcunit1-dev) - for tests

Ubuntu/Debian

sudo apt-get install build-essential cmake libssl-dev libev-dev \
                     libjson-c-dev libreadline-dev libcunit1-dev

git clone https://github.com/farb3yonddriv3n/skypeernet.git
cd skypeernet
mkdir build && cd build
cmake ..
make
sudo make install

Docker

docker build -t skypeernet .
docker run -it skypeernet

Quick Start

1. Start the Tracker (on a public server)

# Create configuration directory
mkdir -p /etc/skypeernet

# Copy and edit configuration
cp config/settings.cfg /etc/skypeernet/tracker.cfg

# Start tracker
spntracker

2. Start a Peer

# Edit peer configuration (set tracker_ip to your tracker's IP)
cp config/settings.cfg /etc/skypeernet/peer.cfg
# Edit tracker_ip in peer.cfg

# Start peer
spnpeer

3. Share a File

# Inside spnpeer CLI:

# 1. Put file in finalized directory
#    (copy your file to ~/finalized/myfile.txt)

# 2. Create a transaction to share it
ta myfile.txt "my tags here"

# 3. Mine the block to commit the transaction
bm

# 4. After mining completes, advertise your block to peers
ba a

4. Download a File

# Inside spnpeer CLI:

# 1. List remote files available
lf r

# 2. Find the file hash you want and add download job
ja <64-char-file-hash>

# 3. Check download progress
jd

# 4. When complete, finalize the file
jf <64-char-file-hash>

# File will be in ~/finalized/

Configuration

Configuration file: /etc/skypeernet/peer.cfg (or tracker.cfg)

{
    "tracker_ip"               : "127.0.0.1",    // Tracker IP address
    "tracker_port"             : 5775,           // Tracker UDP port
    "proxy"                    : 0,              // Act as proxy (0=no, 1=yes)

    "download_directory"       : "downloads",    // Temp download chunks
    "block_directory"          : "block",        // Blockchain storage
    "keys_directory"           : "keys",         // RSA keys
    "finalized_directory"      : "finalized",    // Completed files
    "tcp_directory"            : "tcp",          // TCP tunnel temp files

    "interval_retry"           : 0.050,          // Packet retry interval (sec)
    "interval_peers_reachable" : 5,              // Peer check interval (sec)

    "mining_target"            : 2,              // Mining difficulty (leading zeros)
    "send_factor"              : 2,              // Send rate multiplier

    "max_task_buffer"          : 51200,          // Max task buffer size
    "max_send_queue"           : 50,             // Max packets in send queue
    "max_send_retry"           : 200,            // Max retry attempts
    "max_peer_unreachable"     : 5,              // Max unreachable count before removal
    "max_chunk_size"           : 524288000,      // Max chunk size (500MB)

    "max_upload_kbytes"        : 2048,           // Upload limit (KB/s)
    "max_download_kbytes"      : 4096,           // Download limit (KB/s)

    "pipe_read"                : "/tmp/skypeernet_read",   // API read pipe
    "pipe_write"               : "/tmp/skypeernet_write",  // API write pipe

    "tcp_allowed_ports"        : [22, 80, 443],  // Exposed TCP ports
    "tcp_ports_description"    : "SSH, HTTP"     // Description for peers
}

CLI Commands Reference

Network & Peers

Command Alias Arguments Description
peers p, l, list - List all connected peers
whoami w - Show your IP, port, and public key hash
msg m <host> <port> <message> Send message to peer
filesend fs <host> <port> <filename> Send file to peer
traffic tf - Show upload/download statistics

Whitelist (Tracker only)

Command Alias Arguments Description
whitelist wl - List whitelisted public key hashes
whitelist_add wa <pubkeyhash> Add peer to whitelist
whitelist_rem wr <pubkeyhash> Remove peer from whitelist

File Sharing (Transactions & Blocks)

Command Alias Arguments Description
tadd ta <filename> <tags> [plain | to <pubkeyhash>,...] Create transaction to share a file; plain = unencrypted, to = grant listed peers access
tshare ts <filehash> Re-share existing file from network
tlist tl - List pending transactions
bmine bm - Mine a block with pending transactions
blocksaction ba u or a Update (u) or Advertise (a) block

File Download (Jobs)

Command Alias Arguments Description
listfiles lf l or r List local (l) or remote (r) files
jobadd ja <filehash> Start downloading a file
jobdump jd - Show download job status
jobfinalize jf <filehash> Finalize completed download
jobremove jr <filehash> Remove/cancel a download job
jobclean jc - Clean up completed jobs

Tasks & Debug

Command Alias Arguments Description
taskdump ad - Show active file transfer tasks
taskcancel ac <taskindex> Cancel a transfer task
keysdump kd - Show RSA key information
keysexport kx - Export own public key to keys/<pubkeyhash>.pub.pem for sharing
keysend ks <filehash|gkhash> <pubkeyhash> Send a file key or group key to an online peer (grant access without re-mining)
keygroup kg - Create a group key; share files to it with ta ... to <gkhash>
rdump rd - Dump rogue peer info
versiondump v - Show version information

TCP Tunneling

Command Alias Arguments Description
tunneladd ua <pubkeyhash> <port> Open tunnel to peer's TCP port
tunneldump ud - List active tunnels
endpointdump ed - List tunnel endpoints

Encryption and Keys

See docs/encryption.md for the full design.

How Encryption Works

By default, every shared file is encrypted with AES-256-GCM under a random per-file content key (CEK). The CEK is stored in the transaction as a "key slot", wrapped with the recipient's RSA public key. Your identity RSA keypair (.priv.key / .pub.key) is used for authentication and unwrapping key slots only — it never leaves your machine.

┌─────────────────────────────────────────────────────────────────┐
│  FILE ENCRYPTION (when sharing)                                  │
│                                                                   │
│  CEK = 32 random bytes (fresh per file)                          │
│                              │                                   │
│  Original File ──────────────┼──► Encrypted Chunks               │
│  Filename ───────────────────┼──► Encrypted Description          │
│                              │                                   │
│  Transaction key slots:                                          │
│    { to: your_pubkeyhash, key: RSA(your_pubkey, CEK) }           │
│                                                                   │
│  Each chunk gets unique IV (timeiter)                            │
└─────────────────────────────────────────────────────────────────┘

To finalize (decrypt) a downloaded file, your peer looks for a key slot addressed to your public key hash and unwraps the CEK with your own private key. No slot for you = no access; the sharer must grant it.

Encryption schemes ("scheme" in lf r output):

Scheme Meaning
0 plain not encrypted, anyone can download and finalize
1 legacy pre-CEK blocks: AES key derived from the sharer's private key
2 cek per-file content key + key slots (current default)

Sharing Without Encryption

Append plain to the tadd command to share a file unencrypted:

> ta myfile.txt "my tags" plain

Plain files can be downloaded and finalized by any peer — no key exchange is needed, and the filename is visible to everyone in lf r ("encrypted": false). Chunks are stored and transferred as-is, so use this only for content you consider public.

Granting Access

Add key slots for other peers at share time:

> ta myfile.txt "my tags" to <pubkeyhash>[,<pubkeyhash>...]

The recipient's public key is resolved automatically, in this order:

  1. keys/<pubkeyhash>.pub.pem — an imported public key file
  2. the live peer list — public keys are exchanged during peer discovery, so any currently online peer can be granted access directly

To let someone grant you access while you are offline, export your public key with kx and hand them the file; they place it in their keys directory and restart. Sharing a public key is safe — it cannot impersonate you or decrypt anything.

> kx
Public key exported to keys/<your_pubkeyhash>.pub.pem

To grant access to an already-shared file (no re-mining needed), send the key directly to an online peer:

> ks <filehash> <pubkeyhash>

The CEK is wrapped with the recipient's public key and sent over the network (COMMAND_KEY). The recipient verifies it unwraps with their own private key, stores it as keys/<filehash>.cek, and can finalize the file from then on. A key that doesn't unwrap (not addressed to you) is ignored, and an existing stored key is never overwritten.

Group Sharing

A group key is a symmetric AES-256 key identified by its SHA256 hash. It lives in the same hash namespace as peer keys, so ta ... to and ks accept it transparently:

> kg                                   # create a group key
Group key created: <gkhash>

> ta report.pdf "weekly" to <gkhash>   # share a file to the group
> ks <gkhash> <member_pubkeyhash>      # add an online member (they load it live)

Members hold keys/<gkhash>.grp (base64 of the key; also importable offline by copying the file and restarting) and can decrypt every file shared to that group — including files shared before they joined — and can pass the group key on. Treat the group key as shared trust: anyone holding it is a full member. To evict members, create a new group key with kg and share future files to the new hash.

Legacy Blocks and Shared Keys

Blocks created before the CEK scheme use the legacy scheme: the AES key is SHA256(sharer's private key). To finalize such files you still need the sharer's private key imported into keys_directory:

~/keys/
└── <pubkeyhash>.pem     # legacy shared private keys (64-char hex names)
  1. Get the sharer's private key file (out-of-band)
  2. Rename it to their pubkeyhash with .pem extension and put it in ~/keys/
  3. Restart spnpeer (keys are loaded at startup); check with kd

⚠️ This mechanism exists for backward compatibility only. Possessing a peer's private key allows full impersonation of that peer — never use it for new shares.

Use Cases

Scenario Key Required How to Get It
Download a plain-shared file None -
Download your own files Your private key Already have it (auto)
Download a peer's CEK file A key slot addressed to you Sharer uses ta ... to <yourhash> or ks
Download a group-shared file The group key Any member sends it (ks <gkhash> ...) or hands you the .grp file
Download a legacy file Sharer's private key They share it (deprecated)

File Sharing Workflow

Sharing a File (Step by Step)

┌──────────────────────────────────────────────────────────────────┐
│  YOUR MACHINE                                                     │
│                                                                   │
│  1. Place file in ~/finalized/                                   │
│     $ cp myfile.pdf ~/finalized/                                 │
│                                                                   │
│  2. Create transaction (in spnpeer CLI)                          │
│     > ta myfile.pdf "pdf documents work"                         │
│     Transaction added                                            │
│                                                                   │
│  3. Mine the block                                               │
│     > bm                                                         │
│     Mining finished. It took 2.345 seconds                       │
│                                                                   │
│  4. Advertise to network                                         │
│     > ba a                                                       │
│     Block action 2 to 5 peers                                    │
│                                                                   │
│  ✓ File is now visible to other peers via "lf r"                 │
└──────────────────────────────────────────────────────────────────┘

Downloading a File (Step by Step)

┌──────────────────────────────────────────────────────────────────┐
│  YOUR MACHINE                                                     │
│                                                                   │
│  1. List available remote files                                  │
│     > lf r                                                       │
│     {                                                            │
│       "files": [{                                                │
│         "name": "myfile.pdf",                                    │
│         "hash": "a1b2c3d4...64chars...",                        │
│         "pubkeyhash": "f6e5d4c3...64chars...",  ◄── NOTE THIS!  │
│         "size": 1048576,                                         │
│         "downloaded": false                                      │
│       }]                                                         │
│     }                                                            │
│                                                                   │
│  ⚠️  BEFORE DOWNLOADING: Ensure you have the sharer's private   │
│     key in ~/keys/<pubkeyhash>.pem (see "Encryption and Keys")  │
│                                                                   │
│  2. Start download job (use the 64-char hash)                    │
│     > ja a1b2c3d4e5f6...                                        │
│     Job a1b2c3d4e5f6... added                                   │
│                                                                   │
│  3. Monitor progress                                             │
│     > jd                                                         │
│     {                                                            │
│       "jobs": [{                                                 │
│         "file": "a1b2c3d4...",                                  │
│         "progress": "75%",                                       │
│         "chunks_done": 3,                                        │
│         "chunks_total": 4                                        │
│       }]                                                         │
│     }                                                            │
│                                                                   │
│  4. Finalize when complete (100%)                                │
│     > jf a1b2c3d4e5f6...                                        │
│                                                                   │
│     ⚠️  If finalization fails silently, you're missing the key! │
│                                                                   │
│  ✓ File is now in ~/finalized/myfile.pdf                        │
└──────────────────────────────────────────────────────────────────┘

Understanding File Hashes

Files in skypeernet are identified by SHA256 hashes (64 hexadecimal characters):

File: myfile.pdf
Hash: a1b2c3d4e5f678901234567890abcdef1234567890abcdef1234567890abcdef

This hash is used to:
- Uniquely identify the file across the network
- Verify file integrity after download
- Reference files in commands (ja, jf, jr, ts)

TCP Tunneling

TCP tunneling allows you to access TCP services on remote peers through the P2P network.

Example: Access SSH on a remote peer

# On your machine (inside spnpeer CLI):

# 1. Get the peer's public key hash
> p
# Find the peer and note their pubkeyhash

# 2. Open tunnel to their SSH port (22)
> ua a1b2c3d4e5f6...pubkeyhash...64chars 22
{
  "success": true,
  "src_port": 12345,    # Your local port
  "dst_port": 22         # Remote SSH port
}

# 3. Now connect via the tunnel
$ ssh user@localhost -p 12345
# This connects to the remote peer's SSH through the P2P network!

# 4. Check tunnel status
> ud

# 5. Close tunnel when done (not shown - tunnels persist until peer restart)

Plugins

johnconnor (Erlang/OTP)

Web-based management interface accessible at http://localhost:8080

cd plugins/johnconnor
./rebar get-deps
./rebar compile
./rel/files/erws start

skynet (Python)

Automated file synchronization daemon.

cd plugins/skynet
pip install -r requirements.txt
python skynet.py

Troubleshooting

Peer won't connect to tracker

  1. Check tracker IP in configuration
  2. Ensure UDP port 5775 is open
  3. Verify tracker is running: netstat -ulnp | grep 5775

Files not downloading

  1. Check peer connectivity: p (peers command)
  2. Verify file exists remotely: lf r
  3. Check job status: jd
  4. Look at tasks: ad

File finalization fails (no file appears)

Most common cause: Missing decryption key!

  1. Check the file's pubkeyhash with lf r
  2. Verify you have the key: kd (should show matching shared key)
  3. If missing, obtain the private key from the file sharer
  4. Place key in ~/keys/<pubkeyhash>.pem
  5. Restart spnpeer (keys only load at startup)
  6. Try jf <hash> again

Mining takes too long

Reduce mining_target in configuration (fewer leading zeros = easier mining)

NAT/Firewall issues

  1. Set proxy: 1 on public-facing peers
  2. Use TCP tunneling for direct connections
  3. Check if peer shows shadow: true (being routed through proxy)

Debug logging

Check syslog for detailed logs:

tail -f /var/log/syslog | grep -E "(distfs|spnpeer)"

Protocol Details

See the header files in src/include/ for detailed protocol documentation:

  • packet.h - Packet structure and fragmentation
  • payload.h - Command handlers
  • data.h - Serialization format
  • peer.h - Peer state machine
  • net.h - Network layer
  • world.h - Peer discovery

License

GPL 3.0 - See LICENSE file.

Contributing

Pull requests welcome! Please ensure:

  1. Code follows existing style
  2. Tests pass: ./spntest
  3. No compiler warnings with -Wall

About

p2p network

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages