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