Protocollo di rete ZeroNet¶
- Ogni messaggio è codificato utilizzando MessagePack
- Ogni richiesta ha tre parametri:
cmd
: il comando richiestoreq_id
: un ID univoco della richiesta (semplice parola univoca incrementata per connessione), il client deve includerla nella risposta al comandoparams
: parametri della richiesta
- Esempio di richiesta:
{"cmd": "getFile", "req_id": 1, "params:" {"site": "1EU...", "inner_path": "content.json", "location": 0}}
- Esempio di risposta:
{"cmd": "response", "to": 1, "body": "content.json content", "location": 1132, "size": 1132}
- Esmpio risposta con errore:
{"cmd": "response", "to": 1, "error": "Unknown site"}
Handshake¶
Ogni connessione inizia con un riconoscimento (handshake) inviando una richiesta all'indirizzo richiesto della rete:
Parametro | Descrizione |
---|---|
crypt | Null/None, utilizzato solo nelle risposte |
crypt_supported | Un elenco di metodi di crittografia supportati dal client |
fileserver_port | porta del file server del client |
onion | (utilizzato solo su Tor) indirizzo onion del client |
protocol | versione del protocollo utilizzata dal client (v1 o v2) |
port_opened | stato aperto della porta client del client |
peer_id | (non utilizzato in Tor) il peer_id del client |
rev | il numero revisione del client |
version | versione del client |
target_ip | indirizzo di rete del server |
La destinazione inizializza la crittografia sul socket in base a crypt_supported
, quindi restituisce:
Chiave resa | Descrizione |
---|---|
crypt | la crittografia da utilizzare |
crypt_supported | un elenco di metodi di crittografia supportati dal server |
fileserver_port | porta del file server del server |
onion | (utilizzato solo su Tor) indirizzo onion del server |
protocol | versione del protocollo utilizzata dal server (v1 o v2) |
port_opened | stato aperto della porta client del server |
peer_id | (non utilizzato in Tor) il peer_id del server |
rev | numero revisione del server |
version | versione del server |
target_ip | indirizzo di rete del client |
Nota: non si utilizza la crittografia nelle connessioni .onion, perché la rete Tor fornisce la sicurezza di trasporto di default. Nota: si può anche inizializzare l'SSL prima dell'handshake se si suppone che è supportato dal client remoto.
Esempio:
Invio handshake:
{ "cmd": "handshake", "req_id": 0, "params": { "crypt": None, "crypt_supported": ["tls-rsa"], "fileserver_port": 15441, "onion": "zp2ynpztyxj2kw7x", "protocol": "v2", "port_opened": True, "peer_id": "-ZN0056-DMK3XX30mOrw", "rev": 2122, "target_ip": "192.168.1.13", "version": "0.5.6" } }
Risposta:
{ "protocol": "v2", "onion": "boot3rdez4rzn36x", "to": 0, "crypt": None, "cmd": "response", "rev": 2092, "crypt_supported": [], "target_ip": "zp2ynpztyxj2kw7x.onion", "version": "0.5.5", "fileserver_port": 15441, "port_opened": False, "peer_id": "" }
Richiesta peer¶
getFile site, inner_path, location, [file_size]¶
Richiesta di un file dal client
Parametro | Descrizione |
---|---|
site | Indirizzo del sito (esempio: 1EU1tbG9oC1A8jz2ouVwGZyQ5asrNsE4Vr) |
inner_path | Percorso del file relativo alla cartella del sito |
location | Richede il file da questo byte (vengono inviati al massimo 512 byte per richiesta, quindi servono richieste multiple per file grandi) |
file_size | Dimensione del file richiesto (opzionale) |
Risposta:
Chiave resa | Descrizione |
---|---|
body | Contenuto del file richiesto |
location | Posizione dell'ultimo byte inviato |
size | Dimensione del file |
streamFile site, inner_path, location, [file_size]¶
Stream di un file dal client
Risposta:
Chiave resa | Descrizione |
---|---|
stream_bytes | Lunghezza dei dati del file dopo il contenuto di MessagePack |
Per evitare che python-msgpack serializzi grandi stringhe binarie, il corpo del file è aggiunto direttamente dopo il contenuto di MessagePack. Per esempio,
> {"cmd": "streamFile", "id": 1, "inner_path": "content.json", "size": 1234} < {"cmd": "response", "to": 1, "stream_bytes": 1234} < content of the file
Dettaglio implementazione ZeroNet: per segmenti di file maggiori di 256 kb, lo streaming è abilitato di default.
ping¶
Controlla se il client è ancora attivo
Risposta:
Chiave resa | Descrizione |
---|---|
body | Pong |
pex site, peers, need¶
Scambio di peer con il client. I peer sono compressi in 6 bytes (4 byte per l'IP utilizzando inet_ntoa + 2 byte per la porta)
Parametro | Descrizione |
---|---|
site | Indirizzo del sito (esempio: 1EU1tbG9oC1A8jz2ouVwGZyQ5asrNsE4Vr) |
peers | Elenco dei peer che ha il richiedente (compressi) |
peers_onion | Elenco dei peer di Tor Onion che ha il richiedente (compressi) |
need | Numero dei peer che vuole il richiedente |
Risposta:
Chiave resa | Descrizione |
---|---|
peers | Elenco dei peer IPv4 disponibili per il sito (compressi) |
peers_onion | Elenco dei peer di Tor onion per il sito (compressi) |
Ogni elemento nell'elenco peers
è un indirizzo compresso IPv4 .
Indirizzo IP | Porta |
---|---|
4 byte |
2 byte |
Ogni elemento nell'elenco peers_onion
è un indirizzo compresso del servizio Tor onion.
Indirizzo onion B32-decoded | Porta |
---|---|
binary_str[0:-2] |
binary_str[-2:] |
Per ripristinare l'indirizzo onion, passare la prima parte attraverso base64.b32encode
e appendere .onion
al valore restituito.
update site, inner_path, body, [diffs]¶
Aggiornare il file di un sito.
Parametro | Descrizione |
---|---|
site | Indirizzo del sito (esempio: 1EU1tbG9oC1A8jz2ouVwGZyQ5asrNsE4Vr) |
inner_path | Percorso del file relativo alla cartella del sito |
body | Contenuto completo del file content.json aggiornato |
diffs (opzionale) | Codici variazioni per i file modificati in content.json |
Risposta:
Chiave resa | Descrizione |
---|---|
ok | Messaggio di ringraziamento per aggiornamento riuscito :) |
Formato variazioni¶
Un dizionario che contiene le modifiche
- Chiave: percorso relativo del file modificato rispetto a content.json (es.:
data.json
) - Valore: Elenco dei codici variazione per il file (es.:
[['=', 5], ['+', '\nCiao nuova riga'], ['-', 6]]
)
Possibili codici variazione¶
Codice | Descrizione |
---|---|
['=', numero di caratteri uguali] | Non ha modificato parte del file (es.: ['=', 5] ) |
['+', nuovo testo] | Caratteri inseriti (es.: ['+', '\nCiao nuova riga'] ) |
['-', numero di caratteri rimossi] | Contenuto completo del file modificiato (es.: ['-', 6] ) |
Dopo la ricezione delle modifiche, il client tenta di allineare il file utilizzando le differenze. Se fallisce il controllo della chiave SHA fornita dal file content.json (aveva una versione diversa del file) riscarica automaticamente l'intero file da chi ha inviato l'aggiornamento.
Nota: Le correzioni sono limitate a 30KB per file e utilizzate solo per i file .json
listModified site, since¶
Elenco dei file content.json modificati da un certo parametro. Viene utilizzato per recuperare il contenuto inviato dall'utente del sito.
Parametro | Descrizione |
---|---|
site | Indirizzo del sito (esempio: 1EU1tbG9oC1A8jz2ouVwGZyQ5asrNsE4Vr) |
since | Elenco dei file content.json da questa data. |
Risposta:
Chiave resa | Descrizione |
---|---|
modified_files | Chiave: content.json inner_path Valore: data ultima modifica |
Esempio:
> zeronet.py --silent peerCmd 127.0.0.1 15441 listModified "{'site': '1BLogC9LN4oPDcruNz3qo1ysa133E9AGg8', 'since': 1497507030}" { "to": 1, "cmd": "response", "modified_files": { "data/users/1NM9k7VJfrb1UWw5agAvyRfSn3ws1wTJ5U/content.json": 1497579272, "data/users/1QEfmMwKVxgR4rkREbdJYjgUmF3Zy8pwHt/content.json": 1497565986, "data/users/16NS3rBdW9zpLmLSQoD8nLTtNVsRFtVBhd/content.json": 1497575039, "data/users/1CjXarXgvcNeCJ2nMQxUi4DRFWp3GEur2W/content.json": 1497513808, "data/users/1L5rGDgTs4W2V7gekSvJNhKa7XaHkVwotD/content.json": 1497615798, "data/users/1LWuc6JBhUGrKEAh1aPrPU85dEMcKmg3pS/content.json": 1497594716, "data/users/1KdnTJVBGzEZrJppFZtzfG9chukuMv8xSb/content.json": 1497584640, "data/users/1GMNmr2bDPbT4c8yVnyCoDHke52CNCdqAa/content.json": 1497614188, "data/users/1GRm9rED83Tkfi3iWS9m3LWHiRpPZehWLd/content.json": 1497827772, "data/users/12Ugp53jiMdvj1Kxa1w7c2LcXUBdGPs1oK/content.json": 1497692901, "data/users/1F6BMqittjWUStzUbRXm2kG2GQ3RdBLqFQ/content.json": 1497571485, "data/users/1GgNo3CmxPd7n2pMSF3uyqf1XHvgtTUqCe/content.json": 1497560829, "data/users/16nArdxrSaNThNp83kL8E6NLL9WD98iUne/content.json": 1497627929, "data/users/16CAJkbfNRxNJq4aKdrZ2MSYFfFGvQ8JPi/content.json": 1497664899, "data/users/1DrBS2sTD3BX5BBxG8eqYsxXSvGt9kc5HE/content.json": 1497632000, "data/users/19sggoAZ4hcorrrfWoFWP9rwfpVsL29cnZ/content.json": 1497928134, "data/users/1NYpJupegoTXL4cFpkNdLNJ4XaAhTNhPe1/content.json": 1497535771, "data/users/1R67TfYzNkCnh89EFfGmXn5LMb4hXaMRQ/content.json": 1497691787, "data/users/1C9HXUYFSVafLxanwkaFPZRcRgCEGsj2Cn/content.json": 1497572833, "data/users/1LgoHzNGWeijeZbJ8a1YgGjMCnjaM4BWG/content.json": 1497620232, "content.json": 1497623639 } }
getHashfield site¶
Ottiene gli id dei file opzionali scaricati.
Parametro | Descrizione |
---|---|
site | Indirizzo sito (esempio: 1EU1tbG9oC1A8jz2ouVwGZyQ5asrNsE4Vr) |
Risposta:
Chiave resa | Descrizione |
---|---|
hashfield_raw | Id opzionali del file codificati utilizzando array.array("H", [1000, 1001..]).tostring() |
Esempio:
> zeronet.py --silent peerCmd 192.168.1.13 15441 getHashfield "{'site': '1Gif7PqWTzVWDQ42Mo7np3zXmGAo3DXc7h'} { 'to': 1, 'hashfield_raw': 'iG\xde\x02\xc6o\r;...', 'cmd': 'response' }
setHashfield site, hashfield_raw¶
Imposta l'elenco degli id dei file opzionali che possiede il client richiedente.
Parametro | Descrizione |
---|---|
site | Indirizzo sito (esempio: 1EU1tbG9oC1A8jz2ouVwGZyQ5asrNsE4Vr) |
hashfield_raw | Id file opzionali codificato utilizzando array.array("H", [1000, 1001..]).tostring() |
Risposta:
Chiave resa | Descrizione |
---|---|
ok | Aggiornato |
findHashIds site, hash_ids¶
Richiede se il client conosce un peer che ha la chiave hash_ids richiesta
Parametro | Descrizione |
---|---|
site | Indirizzo sito (esempio: 1EU1tbG9oC1A8jz2ouVwGZyQ5asrNsE4Vr) |
hash_ids | Elenco degli id dei file opzionali che il client sta cercando |
Risposta:
Chiave resa | Descrizione |
---|---|
peers | Chiave: id del file opzionale Valore: elenco dei peer ipv4 codificati utilizzando socket.inet_aton(ip) + struct.pack("H", port) |
peers_onion | Chiave: id del file opzionale Valore: elenco dei peer onion codificati utilizzando base64.b32decode(onion.replace(".onion", "").upper()) + struct.pack("H", port) |
Esempio:
> zeronet.py --silent peerCmd 192.168.1.13 15441 findHashIds "{'site': '1Gif7PqWTzVWDQ42Mo7np3zXmGAo3DXc7h', 'hash_ids': [59948, 29811]}" { 'to': 1, 'peers': { 29811: [ 'S&9\xd3Q<', '>f\x94\x98N\xa4', 'gIB\x90Q<', '\xb4\xady\xf7Q<' ], 59948: [ 'x\xcc>\xf6Q<', 'S\xa1\xddkQ<', '\x05\xac\xe8\x8dQ<', '\x05\xc4\xe1\x93Q<', 'Q\x02\xed\nQ<' ] }, 'cmd': 'response', 'peers_onion': { 29811: ['\xc7;A\xce\xbc\xd9O\xe2w<Q<'], 59948: ['\xc7;A\xce\xbc\xd9O\xe2w<Q<'] } }
File id opzionale¶
Rappresentazione intera dei primi 4 caratteri della chiave (hash):
>>> int("ea2c2acb30bd5e1249021976536574dd3f0fd83340e023bb4e78d0d818adf30a"[0:4], 16) 59948
checkport port¶
Controlla la porta richiesta dell'altro peer.
Parametro | Descrizione |
---|---|
port | Porta che verrà controllata. |
Return:
Chiave resa | Descrizione |
---|---|
status | Stato della porta ("open" o "closed") |
ip_external | IP esterno del richiedente |
Plugin file grandi¶
getPieceFields site¶
Restituisce tutte le sezioni del file che il cliente ha per questo sito in un dizionario.
Parametro | Descrizione |
---|---|
site | Sito richiesto |
Risposta:
Chiave resa | Descrizione |
---|---|
piecefields_packed | Chiave: chiave merkle root sha512/256 di Bigfile Valore: sezioni compresse |
setPieceFields site, piecefields_packed¶
Imposta le sezioni del client per quel sito.
Parametro | Descrizione |
---|---|
site | Sito richiesto |
piecefields_packed | Chiave: chiave merkle root sha512/256 del file grande Valore: sezione compressa |
Risposta:
Chiave resa | Descrizione |
---|---|
ok | Aggiornato |
Sezioni di file grandi¶
Contiene le informazioni dei pezzi dei file grandi scaricati in una semplice stringa di valori 1/0. (1 = scaricato, 0 = non scaricato)
Esempio:
1110000001
significa che il file ha una dimensione di 9-10MB e il client ha scaricato i primi 3MB e l'ultimo MB a pezzi da 1MB.
Formato compressione:
Converte una stringa in una lista di interi contando i caratteri che si ripetono iniziando con 1
.
Esempio:
1110000001
in[3, 6, 1]
,0000000001
in[0, 9, 1]
,1111111111
in[10]
Dopo la conversione viene convertito in un più efficente array specializzato utilizzando array.array('H', piecefield)
Merkle root per file grandi¶
Nella procedura di codifica dei file grandi, oltre a salvare l'elenco delle chiavi sha512/256 per peer nel file piecemap, l'algoritmo calcola anche la merkle root SHA-512/256 del file utilizzando l'implementazione merkle-tools. La merkle root è utilizzata solo come un ID per identificare i grandi file, non (ancora) per verificare i pezzi.
Nota: La merkle root è scelta per identificare il file al posto dell'attuale chiave SHA-512/256 del file. Ovviamente, utilizzando la seconda risulterebbe nel calcolare due volte la chiave del file (una per la piecemap e una per l'intero file).
Nota: La merkle root non è utilizzata per verificare l'integrità dei pezzi o dei file grandi, perché ciò utilizzerebbe più banda e spazio per trasferire e salvare la merkle-proofs per verifiche parziali, rispetto alla mappa delle chiavi per pezzo del file stesso.
Mappa sezioni di file grandi¶
Contiene le chiavi SHA-512/256 per peer. La dimensione del pezzo e il nome del file della picemap è definita in content.json
, es.:
... "files_optional": { "bigfile.mp4": { "piece_size": 1048576, "piecemap": "bigfile.mp4.piecemap.msgpack", "sha512": "d1f0d150e1e73bb1e684d370224315d7ba21e656189eb646ef7cc394d033bc2b", "size": 42958831 }, ...
Avendo la seguente struttura dati, il file piecemap è compresso nel formato msgpack:
{ b'bigfile.mp4': {b'sha512_pieces': [ b"e\xde\x0fx\xec\xc5LZ9\x0e\xe7\x85E\x1b\xd5\xe4C'\xe7req\xe3<\xff\\\xbb\xc8b\xc2\xc1\x8e", b'\xef\xe8\xed\xfe\x16/\x96\xdb;;\x06n[8_\x06\x9ak|\xe1\x9f\xe1\xaf\x87\x96\xdd\xfd\x9bEf\xd9!', b'\x1c\xd6-\x1f\xce\xde{\xcd\x01\x93un =D\x0brmB-\xd1\x8c\xbf\xfe\xca\x8a\x1c\xf60\xbb\xedD', b'\x1aQdF\xd2\xbc\xdff{\xb7\x89\xf2\xd3\r\xa9\xe1\xefA-V\x18\xa4\xc8e\x13\x88v\x13\\&\xfbW', ... ]} }