Implement I2P peers
This commit is contained in:
parent
a0cb3a430c
commit
5e57411c58
5 changed files with 125 additions and 6 deletions
|
@ -257,6 +257,13 @@ class FileRequest(object):
|
|||
if site.addPeer(*address):
|
||||
added += 1
|
||||
|
||||
# Add sent peers to site
|
||||
for packed_address in params.get("peers_i2p", []):
|
||||
address = helper.unpackI2PAddress(packed_address)
|
||||
got_peer_keys.append("%s:%s" % address)
|
||||
if site.addPeer(*address):
|
||||
added += 1
|
||||
|
||||
# Send back peers that is not in the sent list and connectable (not port 0)
|
||||
packed_peers = helper.packPeers(site.getConnectablePeers(params["need"], got_peer_keys))
|
||||
|
||||
|
@ -265,7 +272,7 @@ class FileRequest(object):
|
|||
if config.verbose:
|
||||
self.log.debug(
|
||||
"Added %s peers to %s using pex, sending back %s" %
|
||||
(added, site, len(packed_peers["ip4"]) + len(packed_peers["onion"]))
|
||||
(added, site, len(packed_peers["ip4"]) + len(packed_peers["onion"]) + len(packed_peers["i2p"]))
|
||||
)
|
||||
|
||||
back = {}
|
||||
|
@ -273,6 +280,8 @@ class FileRequest(object):
|
|||
back["peers"] = packed_peers["ip4"]
|
||||
if packed_peers["onion"]:
|
||||
back["peers_onion"] = packed_peers["onion"]
|
||||
if packed_peers["i2p"]:
|
||||
back["peers_i2p"] = packed_peers["i2p"]
|
||||
|
||||
self.response(back)
|
||||
|
||||
|
@ -317,14 +326,20 @@ class FileRequest(object):
|
|||
|
||||
back_ip4 = {}
|
||||
back_onion = {}
|
||||
back_i2p = {}
|
||||
for hash_id, peers in found.iteritems():
|
||||
back_onion[hash_id] = [helper.packOnionAddress(peer.ip, peer.port) for peer in peers if peer.ip.endswith("onion")]
|
||||
back_ip4[hash_id] = [helper.packAddress(peer.ip, peer.port) for peer in peers if not peer.ip.endswith("onion")]
|
||||
back_i2p[hash_id] = [helper.packI2PAddress(peer.ip, peer.port) for peer in peers if peer.ip.endswith("i2p")]
|
||||
back_ip4[hash_id] = [helper.packAddress(peer.ip, peer.port) for peer in peers if not (peer.ip.endswith("onion") or peer.ip.endswith("i2p"))]
|
||||
|
||||
# Check my hashfield
|
||||
# TODO Is it implied that a site address can only be on Tor, I2P or clearnet at once?
|
||||
if self.server.tor_manager and self.server.tor_manager.site_onions.get(site.address): # Running onion
|
||||
my_ip = helper.packOnionAddress(self.server.tor_manager.site_onions[site.address], self.server.port)
|
||||
my_back = back_onion
|
||||
elif self.server.i2p_manager and self.server.i2p_manager.site_dests.get(site.address): # Running I2P dest
|
||||
my_ip = helper.packI2PAddress(self.server.i2p_manager.site_dests[site.address], self.server.port)
|
||||
my_back = back_i2p
|
||||
elif config.ip_external: # External ip defined
|
||||
my_ip = helper.packAddress(config.ip_external, self.server.port)
|
||||
my_back = back_ip4
|
||||
|
@ -340,10 +355,10 @@ class FileRequest(object):
|
|||
|
||||
if config.verbose:
|
||||
self.log.debug(
|
||||
"Found: IP4: %s, Onion: %s for %s hashids" %
|
||||
(len(back_ip4), len(back_onion), len(params["hash_ids"]))
|
||||
"Found: IP4: %s, Onion: %s, I2P: %s for %s hashids" %
|
||||
(len(back_ip4), len(back_onion), len(back_i2p), len(params["hash_ids"]))
|
||||
)
|
||||
self.response({"peers": back_ip4, "peers_onion": back_onion})
|
||||
self.response({"peers": back_ip4, "peers_onion": back_onion, "peers_i2p": back_i2p})
|
||||
|
||||
def actionSetHashfield(self, params):
|
||||
site = self.sites.get(params["site"])
|
||||
|
|
|
@ -105,6 +105,8 @@ class Peer(object):
|
|||
def packMyAddress(self):
|
||||
if self.ip.endswith(".onion"):
|
||||
return helper.packOnionAddress(self.ip, self.port)
|
||||
elif self.ip.endswith(".i2p"):
|
||||
return helper.packI2PAddress(self.ip, self.port)
|
||||
else:
|
||||
return helper.packAddress(self.ip, self.port)
|
||||
|
||||
|
@ -241,6 +243,8 @@ class Peer(object):
|
|||
request = {"site": site.address, "peers": packed_peers["ip4"], "need": need_num}
|
||||
if packed_peers["onion"]:
|
||||
request["peers_onion"] = packed_peers["onion"]
|
||||
if packed_peers["i2p"]:
|
||||
request["peers_i2p"] = packed_peers["i2p"]
|
||||
res = self.request("pex", request)
|
||||
if not res or "error" in res:
|
||||
return False
|
||||
|
@ -255,6 +259,11 @@ class Peer(object):
|
|||
address = helper.unpackOnionAddress(peer)
|
||||
if site.addPeer(*address):
|
||||
added += 1
|
||||
# I2P
|
||||
for peer in res.get("peers_i2p", []):
|
||||
address = helper.unpackI2PAddress(peer)
|
||||
if site.addPeer(*address):
|
||||
added += 1
|
||||
|
||||
if added:
|
||||
self.log("Added peers using pex: %s" % added)
|
||||
|
@ -292,6 +301,11 @@ class Peer(object):
|
|||
if not hash in back:
|
||||
back[hash] = []
|
||||
back[hash] += map(helper.unpackOnionAddress, onion_peers)
|
||||
# Unpack I2P dest
|
||||
for hash, i2p_peers in res.get("peers_i2p", {}).items()[0:30]:
|
||||
if not hash in back:
|
||||
back[hash] = []
|
||||
back[hash] += map(helper.unpackI2PAddress, i2p_peers)
|
||||
|
||||
return back
|
||||
|
||||
|
|
|
@ -377,11 +377,17 @@ class Site(object):
|
|||
|
||||
# Find out my ip and port
|
||||
tor_manager = self.connection_server.tor_manager
|
||||
i2p_manager = self.connection_server.i2p_manager
|
||||
if tor_manager and tor_manager.enabled and tor_manager.start_onions:
|
||||
my_ip = tor_manager.getOnion(self.address)
|
||||
if my_ip:
|
||||
my_ip += ".onion"
|
||||
my_port = config.fileserver_port
|
||||
elif i2p_manager and i2p_manager.enabled and i2p_manager.start_dests:
|
||||
my_ip = i2p_manager.getDest(self.address)
|
||||
if my_ip:
|
||||
my_ip += ".i2p"
|
||||
my_port = 0
|
||||
else:
|
||||
my_ip = config.ip_external
|
||||
if self.connection_server.port_opened:
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import pytest
|
||||
import time
|
||||
|
||||
from File import FileServer
|
||||
|
||||
# stats.i2p
|
||||
TEST_B64 = 'Okd5sN9hFWx-sr0HH8EFaxkeIMi6PC5eGTcjM1KB7uQ0ffCUJ2nVKzcsKZFHQc7pLONjOs2LmG5H-2SheVH504EfLZnoB7vxoamhOMENnDABkIRGGoRisc5AcJXQ759LraLRdiGSR0WTHQ0O1TU0hAz7vAv3SOaDp9OwNDr9u902qFzzTKjUTG5vMTayjTkLo2kOwi6NVchDeEj9M7mjj5ySgySbD48QpzBgcqw1R27oIoHQmjgbtbmV2sBL-2Tpyh3lRe1Vip0-K0Sf4D-Zv78MzSh8ibdxNcZACmZiVODpgMj2ejWJHxAEz41RsfBpazPV0d38Mfg4wzaS95R5hBBo6SdAM4h5vcZ5ESRiheLxJbW0vBpLRd4mNvtKOrcEtyCvtvsP3FpA-6IKVswyZpHgr3wn6ndDHiVCiLAQZws4MsIUE1nkfxKpKtAnFZtPrrB8eh7QO9CkH2JBhj7bG0ED6mV5~X5iqi52UpsZ8gnjZTgyG5pOF8RcFrk86kHxAAAA'
|
||||
|
||||
|
@ -62,6 +64,72 @@ class TestI2P:
|
|||
assert "body" in connection_locked.request("getFile", {"site": site.address, "inner_path": "content.json", "location": 0})
|
||||
assert connection_locked.request("getFile", {"site": "1OTHERSITE", "inner_path": "content.json", "location": 0})["error"] == "Invalid site"
|
||||
|
||||
def testPex(self, file_server, site, site_temp):
|
||||
# Register site to currently running fileserver
|
||||
site.connection_server = file_server
|
||||
file_server.sites[site.address] = site
|
||||
# Create a new file server to emulate new peer connecting to our peer
|
||||
file_server_temp = FileServer("127.0.0.1", 1545)
|
||||
site_temp.connection_server = file_server_temp
|
||||
file_server_temp.sites[site_temp.address] = site_temp
|
||||
# We will request peers from this
|
||||
peer_source = site_temp.addPeer("127.0.0.1", 1544)
|
||||
|
||||
# Get ip4 peers from source site
|
||||
assert peer_source.pex(need_num=10) == 1 # Need >5 to return also return non-connected peers
|
||||
assert len(site_temp.peers) == 2 # Me, and the other peer
|
||||
site.addPeer("1.2.3.4", 1555) # Add peer to source site
|
||||
assert peer_source.pex(need_num=10) == 1
|
||||
assert len(site_temp.peers) == 3
|
||||
assert "1.2.3.4:1555" in site_temp.peers
|
||||
|
||||
# Get I2P peers from source site
|
||||
site.addPeer(TEST_B64+".i2p", 1555)
|
||||
assert TEST_B64+".i2p:1555" not in site_temp.peers
|
||||
assert peer_source.pex(need_num=10) == 1 # Need >5 to return also return non-connected peers
|
||||
assert TEST_B64+".i2p:1555" in site_temp.peers
|
||||
|
||||
def testFindHash(self, i2p_manager, file_server, site, site_temp):
|
||||
file_server.ip_incoming = {} # Reset flood protection
|
||||
file_server.sites[site.address] = site
|
||||
assert file_server.i2p_manager == None
|
||||
file_server.i2p_manager = i2p_manager
|
||||
|
||||
client = FileServer("127.0.0.1", 1545)
|
||||
client.sites[site_temp.address] = site_temp
|
||||
site_temp.connection_server = client
|
||||
|
||||
# Add file_server as peer to client
|
||||
peer_file_server = site_temp.addPeer("127.0.0.1", 1544)
|
||||
|
||||
assert peer_file_server.findHashIds([1234]) == {}
|
||||
|
||||
# Add fake peer with requred hash
|
||||
fake_peer_1 = site.addPeer(TEST_B64+".i2p", 1544)
|
||||
fake_peer_1.hashfield.append(1234)
|
||||
fake_peer_2 = site.addPeer("1.2.3.5", 1545)
|
||||
fake_peer_2.hashfield.append(1234)
|
||||
fake_peer_2.hashfield.append(1235)
|
||||
fake_peer_3 = site.addPeer("1.2.3.6", 1546)
|
||||
fake_peer_3.hashfield.append(1235)
|
||||
fake_peer_3.hashfield.append(1236)
|
||||
|
||||
assert peer_file_server.findHashIds([1234, 1235]) == {
|
||||
1234: [('1.2.3.5', 1545), (TEST_B64+".i2p", 1544)],
|
||||
1235: [('1.2.3.6', 1546), ('1.2.3.5', 1545)]
|
||||
}
|
||||
|
||||
# Test my address adding
|
||||
site.content_manager.hashfield.append(1234)
|
||||
my_i2p_address = i2p_manager.getDest(site_temp.address).base64()+".i2p"
|
||||
|
||||
res = peer_file_server.findHashIds([1234, 1235])
|
||||
assert res[1234] == [('1.2.3.5', 1545), (TEST_B64+".i2p", 1544), (my_i2p_address, 1544)]
|
||||
assert res[1235] == [('1.2.3.6', 1546), ('1.2.3.5', 1545)]
|
||||
|
||||
# Reset
|
||||
file_server.i2p_manager = None
|
||||
|
||||
def testSiteDest(self, i2p_manager):
|
||||
assert i2p_manager.getDest("address1") != i2p_manager.getDest("address2")
|
||||
assert i2p_manager.getDest("address1") == i2p_manager.getDest("address1")
|
||||
|
|
|
@ -7,6 +7,7 @@ import collections
|
|||
import time
|
||||
import logging
|
||||
import base64
|
||||
from i2p.datatypes import Destination
|
||||
|
||||
|
||||
def atomicWrite(dest, content, mode="w"):
|
||||
|
@ -52,11 +53,13 @@ def shellquote(*args):
|
|||
|
||||
|
||||
def packPeers(peers):
|
||||
packed_peers = {"ip4": [], "onion": []}
|
||||
packed_peers = {"ip4": [], "onion": [], "i2p": []}
|
||||
for peer in peers:
|
||||
try:
|
||||
if peer.ip.endswith(".onion"):
|
||||
packed_peers["onion"].append(peer.packMyAddress())
|
||||
elif peer.ip.endswith(".i2p"):
|
||||
packed_peers["i2p"].append(peer.packMyAddress())
|
||||
else:
|
||||
packed_peers["ip4"].append(peer.packMyAddress())
|
||||
except Exception, err:
|
||||
|
@ -86,6 +89,19 @@ def unpackOnionAddress(packed):
|
|||
return base64.b32encode(packed[0:-2]).lower() + ".onion", struct.unpack("H", packed[-2:])[0]
|
||||
|
||||
|
||||
# Destination, port to packed (389+)-byte format
|
||||
def packI2PAddress(dest, port):
|
||||
if not isinstance(dest, Destination):
|
||||
dest = dest.replace(".i2p", "")
|
||||
dest = Destination(raw=dest, b64=True)
|
||||
return dest.serialize() + struct.pack("H", port)
|
||||
|
||||
|
||||
# From (389+)-byte format to Destination, port
|
||||
def unpackI2PAddress(packed):
|
||||
return Destination(raw=packed[0:-2]).base64() + ".i2p", struct.unpack("H", packed[-2:])[0]
|
||||
|
||||
|
||||
# Get dir from file
|
||||
# Return: data/site/content.json -> data/site
|
||||
def getDirname(path):
|
||||
|
|
Loading…
Reference in a new issue