forked from I2P_Developers/i2p.i2p
- Change secure Node ID requirements again
- Protect against null DHT races - Add message about restarting tunnel when DHT config changes - Add DHT size to table totals
This commit is contained in:
@ -28,6 +28,8 @@ import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
import org.klomp.snark.dht.DHT;
|
||||
|
||||
/**
|
||||
* TimerTask that checks for good/bad up/downloader. Works together
|
||||
* with the PeerCoordinator to select which Peers get (un)choked.
|
||||
@ -74,6 +76,7 @@ class PeerCheckerTask implements Runnable
|
||||
List<Peer> removed = new ArrayList();
|
||||
int uploadLimit = coordinator.allowedUploaders();
|
||||
boolean overBWLimit = coordinator.overUpBWLimit();
|
||||
DHT dht = _util.getDHT();
|
||||
for (Peer peer : peerList) {
|
||||
|
||||
// Remove dying peers
|
||||
@ -218,8 +221,8 @@ class PeerCheckerTask implements Runnable
|
||||
if (coordinator.getNeededLength() > 0 || !peer.isCompleted())
|
||||
peer.keepAlive();
|
||||
// announce them to local tracker (TrackerClient does this too)
|
||||
if (_util.getDHT() != null && (_runCount % 5) == 0) {
|
||||
_util.getDHT().announce(coordinator.getInfoHash(), peer.getPeerID().getDestHash());
|
||||
if (dht != null && (_runCount % 5) == 0) {
|
||||
dht.announce(coordinator.getInfoHash(), peer.getPeerID().getDestHash());
|
||||
}
|
||||
}
|
||||
|
||||
@ -267,8 +270,8 @@ class PeerCheckerTask implements Runnable
|
||||
}
|
||||
|
||||
// announce ourselves to local tracker (TrackerClient does this too)
|
||||
if (_util.getDHT() != null && (_runCount % 16) == 0) {
|
||||
_util.getDHT().announce(coordinator.getInfoHash());
|
||||
if (dht != null && (_runCount % 16) == 0) {
|
||||
dht.announce(coordinator.getInfoHash());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -577,6 +577,8 @@ public class SnarkManager implements Snark.CompleteListener {
|
||||
addMessage(_("Enabled DHT."));
|
||||
else
|
||||
addMessage(_("Disabled DHT."));
|
||||
if (_util.connected())
|
||||
addMessage(_("DHT change requires tunnel shutdown and reopen"));
|
||||
_util.setUseDHT(useDHT);
|
||||
changed = true;
|
||||
}
|
||||
|
@ -43,6 +43,8 @@ import net.i2p.util.I2PAppThread;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.SimpleTimer2;
|
||||
|
||||
import org.klomp.snark.dht.DHT;
|
||||
|
||||
/**
|
||||
* Informs metainfo tracker of events and gets new peers for peer
|
||||
* coordinator.
|
||||
@ -323,8 +325,9 @@ public class TrackerClient implements Runnable {
|
||||
}
|
||||
|
||||
// Local DHT tracker announce
|
||||
if (_util.getDHT() != null)
|
||||
_util.getDHT().announce(snark.getInfoHash());
|
||||
DHT dht = _util.getDHT();
|
||||
if (dht != null)
|
||||
dht.announce(snark.getInfoHash());
|
||||
|
||||
long uploaded = coordinator.getUploaded();
|
||||
long downloaded = coordinator.getDownloaded();
|
||||
@ -372,9 +375,10 @@ public class TrackerClient implements Runnable {
|
||||
snark.setTrackerSeenPeers(tr.seenPeers);
|
||||
|
||||
// pass everybody over to our tracker
|
||||
if (_util.getDHT() != null) {
|
||||
dht = _util.getDHT();
|
||||
if (dht != null) {
|
||||
for (Peer peer : peers) {
|
||||
_util.getDHT().announce(snark.getInfoHash(), peer.getPeerID().getDestHash());
|
||||
dht.announce(snark.getInfoHash(), peer.getPeerID().getDestHash());
|
||||
}
|
||||
}
|
||||
|
||||
@ -458,20 +462,21 @@ public class TrackerClient implements Runnable {
|
||||
|
||||
// Get peers from DHT
|
||||
// FIXME this needs to be in its own thread
|
||||
if (_util.getDHT() != null && (meta == null || !meta.isPrivate()) && !stop) {
|
||||
dht = _util.getDHT();
|
||||
if (dht != null && (meta == null || !meta.isPrivate()) && !stop) {
|
||||
int numwant;
|
||||
if (event.equals(STOPPED_EVENT) || !coordinator.needOutboundPeers())
|
||||
numwant = 1;
|
||||
else
|
||||
numwant = _util.getMaxConnections();
|
||||
List<Hash> hashes = _util.getDHT().getPeers(snark.getInfoHash(), numwant, 2*60*1000);
|
||||
List<Hash> hashes = dht.getPeers(snark.getInfoHash(), numwant, 2*60*1000);
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Got " + hashes + " from DHT");
|
||||
// announce ourselves while the token is still good
|
||||
// FIXME this needs to be in its own thread
|
||||
if (!stop) {
|
||||
// announce only to the 1 closest
|
||||
int good = _util.getDHT().announce(snark.getInfoHash(), 1, 5*60*1000);
|
||||
int good = dht.announce(snark.getInfoHash(), 1, 5*60*1000);
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Sent " + good + " good announces to DHT");
|
||||
}
|
||||
@ -548,8 +553,9 @@ public class TrackerClient implements Runnable {
|
||||
*/
|
||||
private void unannounce() {
|
||||
// Local DHT tracker unannounce
|
||||
if (_util.getDHT() != null)
|
||||
_util.getDHT().unannounce(snark.getInfoHash());
|
||||
DHT dht = _util.getDHT();
|
||||
if (dht != null)
|
||||
dht.unannounce(snark.getInfoHash());
|
||||
int i = 0;
|
||||
for (Tracker tr : trackers) {
|
||||
if (_util.connected() &&
|
||||
|
@ -89,4 +89,9 @@ public interface DHT {
|
||||
* Stop everything.
|
||||
*/
|
||||
public void stop();
|
||||
|
||||
/**
|
||||
* Known nodes, not estimated total network size.
|
||||
*/
|
||||
public int size();
|
||||
}
|
||||
|
@ -158,7 +158,7 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
|
||||
_qPort = 2555 + ctx.random().nextInt(61111);
|
||||
_rPort = _qPort + 1;
|
||||
if (SECURE_NID) {
|
||||
_myNID = NodeInfo.generateNID(session.getMyDestination().calculateHash(), _qPort);
|
||||
_myNID = NodeInfo.generateNID(session.getMyDestination().calculateHash(), _qPort, _context.random());
|
||||
_myID = _myNID.getData();
|
||||
} else {
|
||||
_myID = new byte[NID.HASH_LENGTH];
|
||||
@ -176,6 +176,13 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
|
||||
|
||||
///////////////// Public methods
|
||||
|
||||
/**
|
||||
* Known nodes, not estimated total network size.
|
||||
*/
|
||||
public int size() {
|
||||
return _knownNodes.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The UDP query port
|
||||
*/
|
||||
|
@ -9,6 +9,7 @@ import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.data.Hash;
|
||||
import net.i2p.data.SimpleDataStructure;
|
||||
import net.i2p.util.RandomSource;
|
||||
|
||||
/*
|
||||
* A Node ID, Hash, and port, and an optional Destination.
|
||||
@ -139,29 +140,35 @@ class NodeInfo extends SimpleDataStructure {
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a secure NID that matches the Hash and port
|
||||
* Generate a secure NID that matches the Hash and port.
|
||||
* Rules: First 4 bytes must match Hash.
|
||||
* Next 2 bytes must match Hash ^ port.
|
||||
* Remaining bytes may be random.
|
||||
*
|
||||
* @throws IllegalArgumentException
|
||||
*/
|
||||
public static NID generateNID(Hash h, int p) {
|
||||
public static NID generateNID(Hash h, int p, RandomSource random) {
|
||||
byte[] n = new byte[NID.HASH_LENGTH];
|
||||
System.arraycopy(h.getData(), 0, n, 0, NID.HASH_LENGTH);
|
||||
n[0] ^= (byte) (p >> 8);
|
||||
n[1] ^= (byte) p;
|
||||
System.arraycopy(h.getData(), 0, n, 0, 6);
|
||||
n[4] ^= (byte) (p >> 8);
|
||||
n[5] ^= (byte) p;
|
||||
random.nextBytes(n, 6, NID.HASH_LENGTH - 6);
|
||||
return new NID(n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the NID matches the Hash
|
||||
* @throws IllegalArgumentException
|
||||
* Verify the NID matches the Hash.
|
||||
* See generateNID() for requirements.
|
||||
* @throws IllegalArgumentException on mismatch
|
||||
*/
|
||||
private void verify() {
|
||||
if (!KRPC.SECURE_NID)
|
||||
return;
|
||||
byte[] nb = nID.getData();
|
||||
byte[] hb = hash.getData();
|
||||
if ((!DataHelper.eq(nb, 2, hb, 2, NID.HASH_LENGTH - 2)) ||
|
||||
((nb[0] ^ (port >> 8)) & 0xff) != (hb[0] & 0xff) ||
|
||||
((nb[1] ^ port) & 0xff) != (hb[1] & 0xff))
|
||||
if ((!DataHelper.eq(nb, 0, hb, 0, 4)) ||
|
||||
((nb[4] ^ (port >> 8)) & 0xff) != (hb[4] & 0xff) ||
|
||||
((nb[5] ^ port) & 0xff) != (hb[5] & 0xff))
|
||||
throw new IllegalArgumentException("NID/Hash mismatch");
|
||||
}
|
||||
|
||||
|
@ -42,6 +42,7 @@ import org.klomp.snark.SnarkManager;
|
||||
import org.klomp.snark.Storage;
|
||||
import org.klomp.snark.Tracker;
|
||||
import org.klomp.snark.TrackerClient;
|
||||
import org.klomp.snark.dht.DHT;
|
||||
|
||||
import org.mortbay.jetty.servlet.DefaultServlet;
|
||||
import org.mortbay.resource.Resource;
|
||||
@ -470,6 +471,14 @@ public class I2PSnarkServlet extends DefaultServlet {
|
||||
out.write(", ");
|
||||
out.write(DataHelper.formatSize2(stats[5]) + "B, ");
|
||||
out.write(ngettext("1 connected peer", "{0} connected peers", (int) stats[4]));
|
||||
DHT dht = _manager.util().getDHT();
|
||||
if (dht != null) {
|
||||
int dhts = dht.size();
|
||||
if (dhts > 0) {
|
||||
out.write(", ");
|
||||
out.write(ngettext("1 DHT peer", "{0} DHT peers", dhts));
|
||||
}
|
||||
}
|
||||
out.write("</th>\n");
|
||||
if (_manager.util().connected()) {
|
||||
out.write(" <th align=\"right\">" + formatSize(stats[0]) + "</th>\n" +
|
||||
|
Reference in New Issue
Block a user