Skip to content

Commit

Permalink
Merge branch 'reduce-pings-and-dns-lookups' into next
Browse files Browse the repository at this point in the history
  • Loading branch information
ArneBab committed Nov 30, 2024
2 parents 28bd779 + 825bc26 commit 0c51872
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 38 deletions.
62 changes: 49 additions & 13 deletions src/freenet/node/DNSRequester.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -16,6 +22,8 @@ public class DNSRequester implements Runnable {

final Node node;
private long lastLogTime;
private final Set<Double> recentNodeIdentitySet = new HashSet<>();
private final Deque<Double> recentNodeIdentityQueue = new ArrayDeque<>();
// Only set when doing simulations.
static boolean DISABLE = false;

Expand Down Expand Up @@ -54,25 +62,53 @@ public void run() {
}

private void realRun() {
PeerNode[] nodes = node.getPeers().myPeers();
long now = System.currentTimeMillis();
if((now - lastLogTime) > 1000) {
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;
}
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);

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
PeerNode pn = nodesToCheck[node.getFastWeakRandom().nextInt(unconnectedNodesLength)];
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 81% 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());
}
}

// Try new DNS lookup
pn.maybeUpdateHandshakeIPs(false);

int nextMaxWaitTime = 1000 + node.getFastWeakRandom().nextInt(60000);
try {
synchronized(this) {
wait(10000); // sleep 10s ...
wait(nextMaxWaitTime); // sleep 1-61s ...
}
} catch (InterruptedException e) {
// Ignore, just wake up. Just sleeping to not busy wait anyway
Expand Down
57 changes: 32 additions & 25 deletions src/freenet/node/PeerNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -141,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 */
Expand Down Expand Up @@ -455,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);
}
Expand Down Expand Up @@ -542,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);
Expand Down Expand Up @@ -592,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();

Expand Down Expand Up @@ -691,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
Expand Down Expand Up @@ -787,9 +779,18 @@ private boolean parseARK(SimpleFieldSet fs, boolean onStartup, boolean forDiffNo
*/
@Override
public synchronized Peer getPeer() {
if (detectedPeer == null && !nominalPeer.isEmpty()) {
sortNominalPeer();
detectedPeer = nominalPeer.get(0);
updateShortToString();
}
return detectedPeer;
}

private void sortNominalPeer() {
nominalPeer.sort(Peer.PEER_COMPARATOR);
}

/**
* Returns an array with the advertised addresses and the detected one
*/
Expand Down Expand Up @@ -862,7 +863,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;
Expand Down Expand Up @@ -1186,7 +1187,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() + ')');
}

/**
Expand Down Expand Up @@ -1413,7 +1414,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)))
Expand Down Expand Up @@ -1806,7 +1812,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();
Expand Down Expand Up @@ -2255,7 +2261,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()));
Expand All @@ -2275,7 +2281,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) {
Expand Down Expand Up @@ -2443,7 +2449,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);
}
Expand Down Expand Up @@ -2553,8 +2559,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
Expand Down Expand Up @@ -2693,8 +2700,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)
Expand Down Expand Up @@ -3955,7 +3962,7 @@ public WeakReference<PeerNode> 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();
Expand Down Expand Up @@ -5426,7 +5433,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;
Expand All @@ -5439,8 +5446,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;
Expand Down

0 comments on commit 0c51872

Please sign in to comment.