- 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:
zzz
2012-08-04 17:11:11 +00:00
parent 4715dbdbd0
commit 280a708afe
7 changed files with 63 additions and 24 deletions

View File

@ -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());
} }
} }
} }

View File

@ -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;
} }

View File

@ -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() &&

View File

@ -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();
} }

View File

@ -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
*/ */

View File

@ -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");
} }

View File

@ -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" +