From 472c0af016fcce87ae26b89b900d1809ad0731d9 Mon Sep 17 00:00:00 2001 From: Arne Babenhauserheide Date: Tue, 12 Nov 2024 22:26:10 +0100 Subject: [PATCH 01/10] Only update the handshake IPs of one random node per check, but check every second --- src/freenet/node/DNSRequester.java | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/freenet/node/DNSRequester.java b/src/freenet/node/DNSRequester.java index 4cb68a64e3..1dc67cbadb 100644 --- a/src/freenet/node/DNSRequester.java +++ b/src/freenet/node/DNSRequester.java @@ -56,23 +56,24 @@ public void run() { private void realRun() { PeerNode[] nodes = node.getPeers().myPeers(); long now = System.currentTimeMillis(); - if((now - lastLogTime) > 1000) { - if(logMINOR) + if((now - lastLogTime) > 100) { + if(logMINOR) { Logger.minor(this, "Processing DNS Requests (log rate-limited)"); + } lastLogTime = now; } - for(PeerNode pn: nodes) { - //Logger.minor(this, "Node: "+pn); - if(!pn.isConnected()) { - // Not connected - // Try new DNS lookup - //Logger.minor(this, "Doing lookup on "+pn+" of "+nodes.length); - pn.maybeUpdateHandshakeIPs(false); - } + // check a randomly chosen node to avoid sending bursts of DNS requests + PeerNode pn = nodes[node.getFastWeakRandom().nextInt(nodes.length)]; + //Logger.minor(this, "Node: "+pn); + if(!pn.isConnected()) { + // Not connected + // Try new DNS lookup + //Logger.minor(this, "Doing lookup on "+pn+" of "+nodes.length); + pn.maybeUpdateHandshakeIPs(false); } try { synchronized(this) { - wait(10000); // sleep 10s ... + wait(1000); // sleep 1s ... } } catch (InterruptedException e) { // Ignore, just wake up. Just sleeping to not busy wait anyway From 96b9241dc74e0e9cb4695ba95bc1c76b64a8d27e Mon Sep 17 00:00:00 2001 From: Arne Babenhauserheide Date: Tue, 12 Nov 2024 22:27:33 +0100 Subject: [PATCH 02/10] Only sort the list nominalPeer when necessary. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit That sorting can cause Pings to be sent. Now sorting is only done when receiving a new noderef and at random intervals. This should make the node less visible in DNS requests and Pings (more typical pattern instead of requesting all peers at the same time). Also it fixes the startup time regression by not doing a ping in the PeerNode constructor. The sorting result in the constructor was overwritten anyway … --- src/freenet/node/PeerNode.java | 57 ++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/src/freenet/node/PeerNode.java b/src/freenet/node/PeerNode.java index 2d887eb461..e402bcbc08 100644 --- a/src/freenet/node/PeerNode.java +++ b/src/freenet/node/PeerNode.java @@ -14,7 +14,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import java.util.Comparator; import java.util.EnumMap; import java.util.GregorianCalendar; import java.util.HashSet; @@ -142,7 +141,7 @@ public abstract class PeerNode implements USKRetrieverCallback, BasePeerNode, Pe protected long jfkContextLifetime = 0; /** My low-level address for SocketManager purposes */ - private Peer detectedPeer; + private Peer detectedPeer = null; /** My OutgoingPacketMangler i.e. the object which encrypts packets sent to this node */ private final OutgoingPacketMangler outgoingMangler; /** Advertised addresses */ @@ -456,7 +455,7 @@ public PeerNode(SimpleFieldSet fs, Node node2, NodeCrypto crypto, boolean fromLo testnetEnabled = fs.getBoolean("testnet", false); if(testnetEnabled) { - String err = "Ignoring incompatible testnet node " + detectedPeer; + String err = "Ignoring incompatible testnet node " + fs.toOrderedString(); Logger.error(this, err); throw new PeerParseException(err); } @@ -543,8 +542,7 @@ public PeerNode(SimpleFieldSet fs, Node node2, NodeCrypto crypto, boolean fromLo "\nNode: " + HexUtil.bytesToHex(nodeKey) + "\nNode hash: " + HexUtil.bytesToHex(nodeKeyHash) + "\nThis: " + HexUtil.bytesToHex(identityHash) + - "\nThis hash: " + HexUtil.bytesToHex(identityHashHash) + - "\nFor: " + getPeer()); + "\nThis hash: " + HexUtil.bytesToHex(identityHashHash)); try { incomingSetupCipher = new Rijndael(256, 256); @@ -593,12 +591,6 @@ public PeerNode(SimpleFieldSet fs, Node node2, NodeCrypto crypto, boolean fromLo } if(nominalPeer.isEmpty()) { Logger.normal(this, "No IP addresses found for identity '" + identityAsBase64String + "', possibly at location '" + location + ": " + userToString()); - detectedPeer = null; - } else { - nominalPeer.sort(Peer.PEER_COMPARATOR); - // TODO this throws away all valid addresses but the first, without checking whether they can connect. Need to try a later one if connection fails. - // sort hostName first. - detectedPeer = nominalPeer.get(0); } updateShortToString(); @@ -692,7 +684,6 @@ public PeerNode(SimpleFieldSet fs, Node node2, NodeCrypto crypto, boolean fromLo } // populate handshakeIPs so handshakes can start ASAP lastAttemptedHandshakeIPUpdateTime = 0; - maybeUpdateHandshakeIPs(true); listeningHandshakeBurstCount = 0; listeningHandshakeBurstSize = Node.MIN_BURSTING_HANDSHAKE_BURST_SIZE @@ -788,9 +779,17 @@ private boolean parseARK(SimpleFieldSet fs, boolean onStartup, boolean forDiffNo */ @Override public synchronized Peer getPeer() { + if (detectedPeer == null && !nominalPeer.isEmpty()) { + sortNominalPeer(); + detectedPeer = nominalPeer.get(0); + } return detectedPeer; } + private void sortNominalPeer() { + nominalPeer.sort(Peer.PEER_COMPARATOR); + } + /** * Returns an array with the advertised addresses and the detected one */ @@ -863,7 +862,7 @@ public void maybeUpdateHandshakeIPs(boolean ignoreHostnames) { long now = System.currentTimeMillis(); Peer localDetectedPeer = null; synchronized(this) { - localDetectedPeer = detectedPeer; + localDetectedPeer = getPeer(); if((now - lastAttemptedHandshakeIPUpdateTime) < MINUTES.toMillis(5)) { //Logger.minor(this, "Looked up recently (localDetectedPeer = "+localDetectedPeer + " : "+((localDetectedPeer == null) ? "" : localDetectedPeer.getAddress(false).toString())); return; @@ -1187,7 +1186,7 @@ public void startRekeying() { sendHandshakeTime = now; // Immediately ctx = null; } - Logger.normal(this, "We are asking for the key to be renewed (" + this.detectedPeer + ')'); + Logger.normal(this, "We are asking for the key to be renewed (" + this.getPeer() + ')'); } /** @@ -1414,7 +1413,12 @@ public boolean shouldSendHandshake() { boolean tempShouldSendHandshake = false; synchronized(this) { if(disconnecting) return false; - tempShouldSendHandshake = ((now > sendHandshakeTime) && (handshakeIPs != null) && (isRekeying || !isConnected())); + if (now > sendHandshakeTime) { + maybeUpdateHandshakeIPs(true); + tempShouldSendHandshake = ((now > sendHandshakeTime) && (getHandshakeIPs() != null) && ( + isRekeying + || !isConnected())); + } } if(logMINOR) Logger.minor(this, "shouldSendHandshake(): initial = "+tempShouldSendHandshake); if(tempShouldSendHandshake && (hasLiveHandshake(now))) @@ -1807,7 +1811,7 @@ private void setDetectedPeer(Peer newPeer) { return; } synchronized(this) { - Peer oldPeer = detectedPeer; + Peer oldPeer = getPeer(); if((newPeer != null) && ((oldPeer == null) || !oldPeer.equals(newPeer))) { this.detectedPeer = newPeer; updateShortToString(); @@ -2256,7 +2260,7 @@ protected void sendInitialMessages() { loadSender(true).setSendASAP(); loadSender(false).setSendASAP(); Message locMsg = DMT.createFNPLocChangeNotificationNew(node.getLocationManager().getLocation(), node.getPeers().getPeerLocationDoubles(true)); - Message ipMsg = DMT.createFNPDetectedIPAddress(detectedPeer); + Message ipMsg = DMT.createFNPDetectedIPAddress(getPeer()); Message timeMsg = DMT.createFNPTime(System.currentTimeMillis()); Message dRoutingMsg = DMT.createRoutingStatus(!disableRoutingHasBeenSetLocally); Message uptimeMsg = DMT.createFNPUptime((byte)(int)(100*node.getUptimeEstimator().getUptime())); @@ -2276,7 +2280,7 @@ protected void sendInitialMessages() { } private void sendIPAddressMessage() { - Message ipMsg = DMT.createFNPDetectedIPAddress(detectedPeer); + Message ipMsg = DMT.createFNPDetectedIPAddress(getPeer()); try { sendAsync(ipMsg, null, node.getNodeStats().changedIPCtr); } catch(NotConnectedException e) { @@ -2444,7 +2448,7 @@ protected synchronized boolean innerProcessNewNoderef(SimpleFieldSet fs, boolean // Anything may be omitted for a differential node reference boolean changedAnything = false; if(!forDiffNodeRef && (false != fs.getBoolean("testnet", false))) { - String err = "Preventing connection to node " + detectedPeer +" - testnet is enabled!"; + String err = "Preventing connection to node " + getPeer() +" - testnet is enabled!"; Logger.error(this, err); throw new FSParseException(err); } @@ -2554,8 +2558,9 @@ else if(logMINOR) nominalPeer.add(p); } } + sortNominalPeer(); // XXX should we trigger changedAnything on *any* change, or on just *addition* of new addresses - if(!Arrays.equals(oldPeers, nominalPeer.toArray(new Peer[nominalPeer.size()]))) { + if(!Arrays.equals(oldPeers, nominalPeer.toArray(new Peer[0]))) { changedAnything = true; if(logMINOR) Logger.minor(this, "Got new physical.udp for "+this+" : "+Arrays.toString(nominalPeer.toArray())); // Look up the DNS names if any ASAP @@ -2694,8 +2699,8 @@ public synchronized SimpleFieldSet exportDiskFieldSet() { */ public synchronized SimpleFieldSet exportMetadataFieldSet(long now) { SimpleFieldSet fs = new SimpleFieldSet(true); - if(detectedPeer != null) - fs.putSingle("detected.udp", detectedPeer.toStringPrefNumeric()); + if(getPeer() != null) + fs.putSingle("detected.udp", getPeer().toStringPrefNumeric()); if(lastReceivedPacketTime() > 0) fs.put("timeLastReceivedPacket", timeLastReceivedPacket); if(lastReceivedAckTime() > 0) @@ -3956,7 +3961,7 @@ public WeakReference getWeakRef() { public Peer getHandshakeIP() { Peer[] localHandshakeIPs; if(!shouldSendHandshake()) { - if(logMINOR) Logger.minor(this, "Not sending handshake to "+getPeer()+" because pn.shouldSendHandshake() returned false"); + if(logMINOR) Logger.minor(this, "Not sending handshake to "+detectedPeer+" because pn.shouldSendHandshake() returned false"); return null; } long firstTime = System.currentTimeMillis(); @@ -5427,7 +5432,7 @@ public Random paddingGen() { } public synchronized boolean matchesPeerAndPort(Peer peer) { - if(detectedPeer != null && detectedPeer.laxEquals(peer)) return true; + if(getPeer() != null && getPeer().laxEquals(peer)) return true; if(nominalPeer != null) { // FIXME condition necessary??? for(Peer p : nominalPeer) { if(p != null && p.laxEquals(peer)) return true; @@ -5440,8 +5445,8 @@ public synchronized boolean matchesPeerAndPort(Peer peer) { * @param strict If true, only match if the IP is actually in use. If false, * also match from nominal IP addresses and domain names etc. */ public synchronized boolean matchesIP(FreenetInetAddress addr, boolean strict) { - if(detectedPeer != null) { - FreenetInetAddress a = detectedPeer.getFreenetAddress(); + if(getPeer() != null) { + FreenetInetAddress a = getPeer().getFreenetAddress(); if(a != null) { if(strict ? a.equals(addr) : a.laxEquals(addr)) return true; From ced3b161f8480ff570927be43450cd38e3443617 Mon Sep 17 00:00:00 2001 From: Arne Babenhauserheide Date: Sat, 30 Nov 2024 01:08:03 +0100 Subject: [PATCH 03/10] =?UTF-8?q?Avoid=20coupon=20collector=E2=80=99s=20pr?= =?UTF-8?q?oblem=20=E2=80=94=20thanks=20to=20bertm!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/freenet/node/DNSRequester.java | 51 ++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 13 deletions(-) diff --git a/src/freenet/node/DNSRequester.java b/src/freenet/node/DNSRequester.java index 1dc67cbadb..bd124aaeba 100644 --- a/src/freenet/node/DNSRequester.java +++ b/src/freenet/node/DNSRequester.java @@ -3,6 +3,12 @@ * http://www.gnu.org/ for further details of the GPL. */ package freenet.node; +import java.util.ArrayDeque; +import java.util.Arrays; +import java.util.Deque; +import java.util.HashSet; +import java.util.Set; + import freenet.support.LogThresholdCallback; import freenet.support.Logger; import freenet.support.Logger.LogLevel; @@ -16,6 +22,8 @@ public class DNSRequester implements Runnable { final Node node; private long lastLogTime; + private final Set recentNodeIdentitySet = new HashSet<>(); + private final Deque recentNodeIdentityQueue = new ArrayDeque<>(); // Only set when doing simulations. static boolean DISABLE = false; @@ -54,23 +62,40 @@ public void run() { } private void realRun() { - PeerNode[] nodes = node.getPeers().myPeers(); - long now = System.currentTimeMillis(); - if((now - lastLogTime) > 100) { - if(logMINOR) { - Logger.minor(this, "Processing DNS Requests (log rate-limited)"); + // run DNS requests for not recently checked, unconnected + // nodes to avoid the coupon collector's problem + PeerNode[] nodesToCheck = Arrays.stream(node.getPeers().myPeers()) + .filter(peerNode -> !peerNode.isConnected()) + // identify recent nodes by location, because the exact location cannot be used twice + // (that already triggers the simplest pitch black attack defenses) + // Double may not be comparable in general (floating point), + // but just checking for equality with itself is safe + .filter(peerNode -> !recentNodeIdentitySet.contains(peerNode.getLocation())) + .toArray(PeerNode[]::new); + + if(logMINOR) { + long now = System.currentTimeMillis(); + if((now - lastLogTime) > 100) { + Logger.minor(this, "Processing DNS Requests (log rate-limited)"); } lastLogTime = now; } - // check a randomly chosen node to avoid sending bursts of DNS requests - PeerNode pn = nodes[node.getFastWeakRandom().nextInt(nodes.length)]; - //Logger.minor(this, "Node: "+pn); - if(!pn.isConnected()) { - // Not connected - // Try new DNS lookup - //Logger.minor(this, "Doing lookup on "+pn+" of "+nodes.length); - pn.maybeUpdateHandshakeIPs(false); + // check a randomly chosen node that has not been checked + // recently to avoid sending bursts of DNS requests + int unconnectedNodesLength = nodesToCheck.length; + PeerNode pn = nodesToCheck[node.getFastWeakRandom().nextInt(unconnectedNodesLength)]; + // do not request this node again, + // until at least 80% of the other unconnected nodes have been checked + recentNodeIdentitySet.add(pn.getLocation()); + recentNodeIdentityQueue.offerFirst(pn.getLocation()); + while (unconnectedNodesLength > 5 && recentNodeIdentityQueue.size() > (0.81 * unconnectedNodesLength)) { + recentNodeIdentitySet.remove(recentNodeIdentityQueue.removeLast()); } + //Logger.minor(this, "Node: "+pn); + + // Try new DNS lookup + //Logger.minor(this, "Doing lookup on "+pn+" of "+nodesToCheck.length); + pn.maybeUpdateHandshakeIPs(false); try { synchronized(this) { wait(1000); // sleep 1s ... From 1cf9ed50656ab819e324299f077ab8f6a44a49d3 Mon Sep 17 00:00:00 2001 From: Arne Babenhauserheide Date: Sat, 30 Nov 2024 01:20:42 +0100 Subject: [PATCH 04/10] Update short to string if a detectedPeer is first set --- src/freenet/node/PeerNode.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/freenet/node/PeerNode.java b/src/freenet/node/PeerNode.java index e402bcbc08..2aae7274fa 100644 --- a/src/freenet/node/PeerNode.java +++ b/src/freenet/node/PeerNode.java @@ -782,6 +782,7 @@ public synchronized Peer getPeer() { if (detectedPeer == null && !nominalPeer.isEmpty()) { sortNominalPeer(); detectedPeer = nominalPeer.get(0); + updateShortToString(); } return detectedPeer; } From 89572210250f1a4911f1ef5925f50bb21bfae46e Mon Sep 17 00:00:00 2001 From: Arne Babenhauserheide Date: Sat, 30 Nov 2024 02:26:28 +0100 Subject: [PATCH 05/10] Fix: at less than 5 unconnected nodes no optimization is needed --- src/freenet/node/DNSRequester.java | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/freenet/node/DNSRequester.java b/src/freenet/node/DNSRequester.java index bd124aaeba..7c4cb384d4 100644 --- a/src/freenet/node/DNSRequester.java +++ b/src/freenet/node/DNSRequester.java @@ -84,12 +84,18 @@ private void realRun() { // recently to avoid sending bursts of DNS requests int unconnectedNodesLength = nodesToCheck.length; PeerNode pn = nodesToCheck[node.getFastWeakRandom().nextInt(unconnectedNodesLength)]; - // do not request this node again, - // until at least 80% of the other unconnected nodes have been checked - recentNodeIdentitySet.add(pn.getLocation()); - recentNodeIdentityQueue.offerFirst(pn.getLocation()); - while (unconnectedNodesLength > 5 && recentNodeIdentityQueue.size() > (0.81 * unconnectedNodesLength)) { - recentNodeIdentitySet.remove(recentNodeIdentityQueue.removeLast()); + if (unconnectedNodesLength < 5) { + // no need for optimizations: just clear all state + recentNodeIdentitySet.clear(); + recentNodeIdentityQueue.clear(); + } else { + // do not request this node again, + // until at least 80% of the other unconnected nodes have been checked + recentNodeIdentitySet.add(pn.getLocation()); + recentNodeIdentityQueue.offerFirst(pn.getLocation()); + while (recentNodeIdentityQueue.size() > (0.81 * unconnectedNodesLength)) { + recentNodeIdentitySet.remove(recentNodeIdentityQueue.removeLast()); + } } //Logger.minor(this, "Node: "+pn); From 3bdf89afe8386035111c747d3aff51b36859aa4d Mon Sep 17 00:00:00 2001 From: Arne Babenhauserheide Date: Sat, 30 Nov 2024 09:25:11 +0100 Subject: [PATCH 06/10] Reduce DNS checking frequency now that node selection is more efficient --- src/freenet/node/DNSRequester.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/freenet/node/DNSRequester.java b/src/freenet/node/DNSRequester.java index 7c4cb384d4..ccaa246fbe 100644 --- a/src/freenet/node/DNSRequester.java +++ b/src/freenet/node/DNSRequester.java @@ -104,7 +104,7 @@ private void realRun() { pn.maybeUpdateHandshakeIPs(false); try { synchronized(this) { - wait(1000); // sleep 1s ... + wait(1000 + node.getFastWeakRandom().nextInt(60000)); // sleep 1-61s ... } } catch (InterruptedException e) { // Ignore, just wake up. Just sleeping to not busy wait anyway From 61e74fa1bd9d4142114163266f17720f6622497c Mon Sep 17 00:00:00 2001 From: Arne Babenhauserheide Date: Sat, 30 Nov 2024 09:26:59 +0100 Subject: [PATCH 07/10] Move wait time calculation out of try synchronized --- src/freenet/node/DNSRequester.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/freenet/node/DNSRequester.java b/src/freenet/node/DNSRequester.java index ccaa246fbe..6e069e3258 100644 --- a/src/freenet/node/DNSRequester.java +++ b/src/freenet/node/DNSRequester.java @@ -102,9 +102,11 @@ private void realRun() { // Try new DNS lookup //Logger.minor(this, "Doing lookup on "+pn+" of "+nodesToCheck.length); pn.maybeUpdateHandshakeIPs(false); + + int nextMaxWaitTime = 1000 + node.getFastWeakRandom().nextInt(60000); try { synchronized(this) { - wait(1000 + node.getFastWeakRandom().nextInt(60000)); // sleep 1-61s ... + wait(nextMaxWaitTime); // sleep 1-61s ... } } catch (InterruptedException e) { // Ignore, just wake up. Just sleeping to not busy wait anyway From ae05c2cb8c220c309bc12a0eb51cd48077924a45 Mon Sep 17 00:00:00 2001 From: Arne Babenhauserheide Date: Sat, 30 Nov 2024 21:33:45 +0100 Subject: [PATCH 08/10] Early return if nothing to do --- src/freenet/node/DNSRequester.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/freenet/node/DNSRequester.java b/src/freenet/node/DNSRequester.java index 6e069e3258..9a86a397c9 100644 --- a/src/freenet/node/DNSRequester.java +++ b/src/freenet/node/DNSRequester.java @@ -80,9 +80,13 @@ private void realRun() { } lastLogTime = now; } + + int unconnectedNodesLength = nodesToCheck.length; + if (unconnectedNodesLength == 0) { + return; // nothing to do + } // check a randomly chosen node that has not been checked // recently to avoid sending bursts of DNS requests - int unconnectedNodesLength = nodesToCheck.length; PeerNode pn = nodesToCheck[node.getFastWeakRandom().nextInt(unconnectedNodesLength)]; if (unconnectedNodesLength < 5) { // no need for optimizations: just clear all state From 62203888dc207a2184bf876841875470167438b8 Mon Sep 17 00:00:00 2001 From: Arne Babenhauserheide Date: Sat, 30 Nov 2024 21:34:08 +0100 Subject: [PATCH 09/10] Align comment with code --- src/freenet/node/DNSRequester.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/freenet/node/DNSRequester.java b/src/freenet/node/DNSRequester.java index 9a86a397c9..250ef87b0f 100644 --- a/src/freenet/node/DNSRequester.java +++ b/src/freenet/node/DNSRequester.java @@ -94,7 +94,7 @@ private void realRun() { recentNodeIdentityQueue.clear(); } else { // do not request this node again, - // until at least 80% of the other unconnected nodes have been checked + // until at least 81% of the other unconnected nodes have been checked recentNodeIdentitySet.add(pn.getLocation()); recentNodeIdentityQueue.offerFirst(pn.getLocation()); while (recentNodeIdentityQueue.size() > (0.81 * unconnectedNodesLength)) { From 825bc26d3d12c9f4fc0a58b672f2dbff6c26e224 Mon Sep 17 00:00:00 2001 From: Arne Babenhauserheide Date: Sat, 30 Nov 2024 21:34:16 +0100 Subject: [PATCH 10/10] Remove commented out debug code --- src/freenet/node/DNSRequester.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/freenet/node/DNSRequester.java b/src/freenet/node/DNSRequester.java index 250ef87b0f..1be4b82f63 100644 --- a/src/freenet/node/DNSRequester.java +++ b/src/freenet/node/DNSRequester.java @@ -101,10 +101,8 @@ private void realRun() { recentNodeIdentitySet.remove(recentNodeIdentityQueue.removeLast()); } } - //Logger.minor(this, "Node: "+pn); // Try new DNS lookup - //Logger.minor(this, "Doing lookup on "+pn+" of "+nodesToCheck.length); pn.maybeUpdateHandshakeIPs(false); int nextMaxWaitTime = 1000 + node.getFastWeakRandom().nextInt(60000);