Author: toad
Date: 2007-12-07 13:16:04 +0000 (Fri, 07 Dec 2007)
New Revision: 16392
Modified:
trunk/freenet/src/freenet/io/comm/PacketSocketHandler.java
trunk/freenet/src/freenet/io/comm/UdpSocketHandler.java
trunk/freenet/src/freenet/l10n/freenet.l10n.en.properties
trunk/freenet/src/freenet/node/DarknetPeerNode.java
trunk/freenet/src/freenet/node/FNPPacketMangler.java
trunk/freenet/src/freenet/node/NodeCryptoConfig.java
trunk/freenet/src/freenet/node/OutgoingPacketMangler.java
trunk/freenet/src/freenet/node/PeerNode.java
Log:
Use burst-only automatically if we are fairly sure we are port forwarded.
Can be turned off by node.assumedNATed = true (new option), which is on by
default.
Please tell me if your NAT or firewall is detected as definitely port forwarded.
Modified: trunk/freenet/src/freenet/io/comm/PacketSocketHandler.java
===================================================================
--- trunk/freenet/src/freenet/io/comm/PacketSocketHandler.java 2007-12-07
12:32:11 UTC (rev 16391)
+++ trunk/freenet/src/freenet/io/comm/PacketSocketHandler.java 2007-12-07
13:16:04 UTC (rev 16392)
@@ -32,4 +32,7 @@
/** How big must the pending data be before we send a packet?
*Includes* transport layer headers. */
public int getPacketSendThreshold();
+ /** Does this port appear to be port forwarded? @see AddressTracker */
+ int getDetectedConnectivityStatus();
+
}
Modified: trunk/freenet/src/freenet/io/comm/UdpSocketHandler.java
===================================================================
--- trunk/freenet/src/freenet/io/comm/UdpSocketHandler.java 2007-12-07
12:32:11 UTC (rev 16391)
+++ trunk/freenet/src/freenet/io/comm/UdpSocketHandler.java 2007-12-07
13:16:04 UTC (rev 16392)
@@ -414,4 +414,8 @@
tracker.setBrokenDetector(detector);
}
+ public int getDetectedConnectivityStatus() {
+ return tracker.getPortForwardStatus();
+ }
+
}
Modified: trunk/freenet/src/freenet/l10n/freenet.l10n.en.properties
===================================================================
--- trunk/freenet/src/freenet/l10n/freenet.l10n.en.properties 2007-12-07
12:32:11 UTC (rev 16391)
+++ trunk/freenet/src/freenet/l10n/freenet.l10n.en.properties 2007-12-07
13:16:04 UTC (rev 16392)
@@ -552,6 +552,8 @@
N2NTMUserAlert.title=Node to Node Text Message ${number} from ${peername}
(${peer})
Node.alwaysAllowLocalAddresses=Always allow connecting to nodes via local
addresses?
Node.alwaysAllowLocalAddressesLong=If true, the node will attempt to connect
to nodes via their local (localhost, LAN) addresses as well as their public
IPs. If this is not set, you can still enable it for specific darknet peers
(but not opennet peers). Set this if you want to connect to other nodes on the
same LAN or computer, and don't mind that bogus references can cause your node
to send UDP packets to machines on your LAN.
+Node.assumeNATed=Assume the port is not forwarded.
+Node.assumeNATedLong=Should the node assume the port is NATed and not
forwarded, and always send handshakes aggressively (every 10-30 seconds),
regardless of any evidence to the contrary?
Node.bandwidthLimitMustBePositiveOrMinusOne=Bandwidth limit must be positive
or -1
Node.bindTo=IP address to bind to
Node.bindToLong=IP address to bind to
Modified: trunk/freenet/src/freenet/node/DarknetPeerNode.java
===================================================================
--- trunk/freenet/src/freenet/node/DarknetPeerNode.java 2007-12-07 12:32:11 UTC
(rev 16391)
+++ trunk/freenet/src/freenet/node/DarknetPeerNode.java 2007-12-07 13:16:04 UTC
(rev 16392)
@@ -57,9 +57,6 @@
/** True if we send handshake requests to this peer in infrequent bursts */
private boolean isBurstOnly;
- /** True if we are currently sending this peer a burst of handshake
requests */
- private boolean isBursting;
-
/** True if we want to ignore the source port of the node's sent packets.
* This is normally set when dealing with an Evil Corporate Firewall which
rewrites the port on outgoing
* packets but does not redirect incoming packets destined to the
rewritten port.
@@ -82,12 +79,6 @@
/** Queued-to-send N2NTM extra peer data file numbers */
private LinkedHashSet queuedToSendN2NTMExtraPeerDataFileNumbers;
- /** Number of handshake attempts (while in ListenOnly mode) since the
beginning of this burst */
- private int listeningHandshakeBurstCount;
-
- /** Total number of handshake attempts (while in ListenOnly mode) to be in
this burst */
- private int listeningHandshakeBurstSize;
-
private static boolean logMINOR;
/**
@@ -100,8 +91,6 @@
logMINOR = Logger.shouldLog(Logger.MINOR, this);
- long now = System.currentTimeMillis();
-
String name = fs.get("myName");
if(name == null) throw new FSParseException("No name");
myName = name;
@@ -117,13 +106,6 @@
allowLocalAddresses =
Fields.stringToBool(metadata.get("allowLocalAddresses"), false);
}
- listeningHandshakeBurstCount = 0;
- listeningHandshakeBurstSize = Node.MIN_BURSTING_HANDSHAKE_BURST_SIZE
- +
node.random.nextInt(Node.RANDOMIZED_BURSTING_HANDSHAKE_BURST_SIZE);
- if(isBurstOnly) {
- Logger.minor(this, "First BurstOnly mode handshake in
"+(sendHandshakeTime - now)+"ms for "+getName()+" (count:
"+listeningHandshakeBurstCount+", size: "+listeningHandshakeBurstSize+ ')');
- }
-
// Setup the private darknet comment note
privateDarknetComment = "";
privateDarknetCommentFileNumber = -1;
@@ -168,13 +150,7 @@
if(isDisabled) return false;
if(isListenOnly) return false;
if(!super.shouldSendHandshake()) return false;
- if(isBurstOnly())
- isBursting = true;
- else
- return true;
}
- // Might have changed from burst only to bursting
- setPeerNodeStatus(System.currentTimeMillis());
return true;
}
@@ -231,8 +207,6 @@
return status;
if(isListenOnly)
return PeerManager.PEER_NODE_STATUS_LISTEN_ONLY;
- if(isBursting)
- return PeerManager.PEER_NODE_STATUS_BURSTING;
if(isBurstOnly)
return PeerManager.PEER_NODE_STATUS_LISTENING;
return status;
@@ -341,8 +315,11 @@
return ignoreSourcePort;
}
- public synchronized boolean isBurstOnly() {
- return isBurstOnly;
+ public boolean isBurstOnly() {
+ synchronized(this) {
+ if(isBurstOnly) return true;
+ }
+ return super.isBurstOnly();
}
public boolean allowLocalAddresses() {
@@ -1516,31 +1493,6 @@
return ""+getPeer()+" : "+getName();
}
- protected synchronized boolean innerCalcNextHandshake(boolean
successfulHandshakeSend, boolean dontFetchARK, long now) {
- if(isBurstOnly) {
- boolean fetchARKFlag = false;
- listeningHandshakeBurstCount++;
- if(listeningHandshakeBurstCount >=
listeningHandshakeBurstSize) {
- listeningHandshakeBurstCount = 0;
- fetchARKFlag = true;
- }
- if(listeningHandshakeBurstCount == 0) { // 0 only if
we just reset it above
- sendHandshakeTime = now +
Node.MIN_TIME_BETWEEN_BURSTING_HANDSHAKE_BURSTS
- +
node.random.nextInt(Node.RANDOMIZED_TIME_BETWEEN_BURSTING_HANDSHAKE_BURSTS);
- listeningHandshakeBurstSize =
Node.MIN_BURSTING_HANDSHAKE_BURST_SIZE
- +
node.random.nextInt(Node.RANDOMIZED_BURSTING_HANDSHAKE_BURST_SIZE);
- isBursting = false;
- } else {
- sendHandshakeTime = now +
Node.MIN_TIME_BETWEEN_HANDSHAKE_SENDS
- +
node.random.nextInt(Node.RANDOMIZED_TIME_BETWEEN_HANDSHAKE_SENDS);
- }
- if(logMINOR) Logger.minor(this, "Next BurstOnly mode
handshake in "+(sendHandshakeTime - now)+"ms for "+getName()+" (count:
"+listeningHandshakeBurstCount+", size: "+listeningHandshakeBurstSize+ ')', new
Exception("double-called debug"));
- return fetchARKFlag;
- } else {
- return
super.innerCalcNextHandshake(successfulHandshakeSend, dontFetchARK, now);
- }
- }
-
public PeerNodeStatus getStatus() {
return new DarknetPeerNodeStatus(this);
}
Modified: trunk/freenet/src/freenet/node/FNPPacketMangler.java
===================================================================
--- trunk/freenet/src/freenet/node/FNPPacketMangler.java 2007-12-07
12:32:11 UTC (rev 16391)
+++ trunk/freenet/src/freenet/node/FNPPacketMangler.java 2007-12-07
13:16:04 UTC (rev 16392)
@@ -4,6 +4,7 @@
* http://www.gnu.org/ for further details of the GPL. */
package freenet.node;
+import freenet.io.AddressTracker;
import freenet.io.comm.SocketHandler;
import java.security.MessageDigest;
@@ -2757,4 +2758,10 @@
return data;
}
+ public int getConnectivityStatus() {
+ if(crypto.config.alwaysHandshakeAggressively())
+ return AddressTracker.DEFINITELY_NATED;
+ return sock.getDetectedConnectivityStatus();
+ }
+
}
Modified: trunk/freenet/src/freenet/node/NodeCryptoConfig.java
===================================================================
--- trunk/freenet/src/freenet/node/NodeCryptoConfig.java 2007-12-07
12:32:11 UTC (rev 16391)
+++ trunk/freenet/src/freenet/node/NodeCryptoConfig.java 2007-12-07
13:16:04 UTC (rev 16392)
@@ -46,6 +46,10 @@
* regardless of any per-peer setting. */
private boolean alwaysAllowLocalAddresses;
+ /** If true, assume we are NATed regardless of the evidence, and
therefore always send
+ * aggressive handshakes (every 10-30 seconds). */
+ private boolean assumeNATed;
+
NodeCryptoConfig(SubConfig config, int sortOrder, boolean onePerIP)
throws NodeInitException {
config.register("listenPort", -1 /* means random */,
sortOrder++, true, true, "Node.port", "Node.portLong", new IntCallback() {
@@ -149,6 +153,18 @@
}
});
alwaysAllowLocalAddresses =
config.getBoolean("alwaysAllowLocalAddresses");
+
+ config.register("assumeNATed", true, sortOrder++, true, false,
"Node.assumeNATed", "Node.assumeNATedLong", new BooleanCallback() {
+
+ public boolean get() {
+ return assumeNATed;
+ }
+
+ public void set(boolean val) throws
InvalidConfigValueException {
+ assumeNATed = val;
+ }
+ });
+ assumeNATed = config.getBoolean("assumeNATed");
}
/** The number of config options i.e. the amount to increment sortOrder
by */
@@ -211,4 +227,9 @@
public synchronized boolean alwaysAllowLocalAddresses() {
return alwaysAllowLocalAddresses;
}
+
+ public boolean alwaysHandshakeAggressively() {
+ // TODO Auto-generated method stub
+ return false;
+ }
}
Modified: trunk/freenet/src/freenet/node/OutgoingPacketMangler.java
===================================================================
--- trunk/freenet/src/freenet/node/OutgoingPacketMangler.java 2007-12-07
12:32:11 UTC (rev 16391)
+++ trunk/freenet/src/freenet/node/OutgoingPacketMangler.java 2007-12-07
13:16:04 UTC (rev 16392)
@@ -105,4 +105,10 @@
* Always allow local addresses?
*/
public boolean alwaysAllowLocalAddresses();
+
+ /**
+ * Port forwarding status.
+ * @return A status code from AddressTracker. FIXME make this more
generic when we need to.
+ */
+ public int getConnectivityStatus();
}
Modified: trunk/freenet/src/freenet/node/PeerNode.java
===================================================================
--- trunk/freenet/src/freenet/node/PeerNode.java 2007-12-07 12:32:11 UTC
(rev 16391)
+++ trunk/freenet/src/freenet/node/PeerNode.java 2007-12-07 13:16:04 UTC
(rev 16392)
@@ -33,6 +33,7 @@
import freenet.crypt.SHA256;
import freenet.crypt.UnsupportedCipherException;
import freenet.crypt.ciphers.Rijndael;
+import freenet.io.AddressTracker;
import freenet.io.comm.AsyncMessageCallback;
import freenet.io.comm.ByteCounter;
import freenet.io.comm.DMT;
@@ -282,6 +283,15 @@
/** Previous time of disconnection */
long timePrevDisconnect;
+ // Burst-only mode
+ /** True if we are currently sending this peer a burst of handshake
requests */
+ private boolean isBursting;
+ /** Number of handshake attempts (while in ListenOnly mode) since the
beginning of this burst */
+ private int listeningHandshakeBurstCount;
+ /** Total number of handshake attempts (while in ListenOnly mode) to be in
this burst */
+ private int listeningHandshakeBurstSize;
+
+
/**
* For FNP link setup:
* The initiator has to ensure that nonces send back by the
@@ -590,6 +600,14 @@
lastAttemptedHandshakeIPUpdateTime = 0;
maybeUpdateHandshakeIPs(true);
+ listeningHandshakeBurstCount = 0;
+ listeningHandshakeBurstSize = Node.MIN_BURSTING_HANDSHAKE_BURST_SIZE
+ +
node.random.nextInt(Node.RANDOMIZED_BURSTING_HANDSHAKE_BURST_SIZE);
+
+ if(isBurstOnly()) {
+ Logger.minor(this, "First BurstOnly mode handshake in
"+(sendHandshakeTime - now)+"ms for "+shortToString()+" (count:
"+listeningHandshakeBurstCount+", size: "+listeningHandshakeBurstSize+ ')');
+ }
+
if(fromLocal)
innerCalcNextHandshake(false, false, now); // Let them
connect so we can recognise we are NATed
@@ -1143,6 +1161,15 @@
}
if(tempShouldSendHandshake && (hasLiveHandshake(now)))
tempShouldSendHandshake = false;
+ if(tempShouldSendHandshake) {
+ if(isBurstOnly()) {
+ synchronized(this) {
+ isBursting = true;
+ }
+ setPeerNodeStatus(System.currentTimeMillis());
+ } else
+ return true;
+ }
return tempShouldSendHandshake;
}
@@ -1165,6 +1192,8 @@
* Set sendHandshakeTime, and return whether to fetch the ARK.
*/
protected synchronized boolean innerCalcNextHandshake(boolean
successfulHandshakeSend, boolean dontFetchARK, long now) {
+ if(isBurstOnly())
+ return calcNextHandshakeBurstOnly(now);
if(verifiedIncompatibleOlderVersion ||
verifiedIncompatibleNewerVersion || disableRouting) {
// Let them know we're here, but have no hope of
connecting
sendHandshakeTime = now +
Node.MIN_TIME_BETWEEN_VERSION_SENDS +
node.random.nextInt(Node.RANDOMIZED_TIME_BETWEEN_VERSION_SENDS);
@@ -1180,6 +1209,29 @@
return ((handshakeCount == MAX_HANDSHAKE_COUNT) &&
!(verifiedIncompatibleOlderVersion || verifiedIncompatibleNewerVersion));
}
+ private synchronized boolean calcNextHandshakeBurstOnly(long now) {
+ boolean fetchARKFlag = false;
+ listeningHandshakeBurstCount++;
+ if(isBurstOnly()) {
+ if(listeningHandshakeBurstCount >=
listeningHandshakeBurstSize) {
+ listeningHandshakeBurstCount = 0;
+ fetchARKFlag = true;
+ }
+ }
+ if(listeningHandshakeBurstCount == 0) { // 0 only if we just
reset it above
+ sendHandshakeTime = now +
Node.MIN_TIME_BETWEEN_BURSTING_HANDSHAKE_BURSTS
+ +
node.random.nextInt(Node.RANDOMIZED_TIME_BETWEEN_BURSTING_HANDSHAKE_BURSTS);
+ listeningHandshakeBurstSize =
Node.MIN_BURSTING_HANDSHAKE_BURST_SIZE
+ +
node.random.nextInt(Node.RANDOMIZED_BURSTING_HANDSHAKE_BURST_SIZE);
+ isBursting = false;
+ } else {
+ sendHandshakeTime = now +
Node.MIN_TIME_BETWEEN_HANDSHAKE_SENDS
+ +
node.random.nextInt(Node.RANDOMIZED_TIME_BETWEEN_HANDSHAKE_SENDS);
+ }
+ if(logMINOR) Logger.minor(this, "Next BurstOnly mode handshake
in "+(sendHandshakeTime - now)+"ms for "+shortToString()+" (count:
"+listeningHandshakeBurstCount+", size: "+listeningHandshakeBurstSize+ ')', new
Exception("double-called debug"));
+ return fetchARKFlag;
+ }
+
protected void calcNextHandshake(boolean successfulHandshakeSend,
boolean dontFetchARK) {
long now = System.currentTimeMillis();
boolean fetchARKFlag = false;
@@ -1195,6 +1247,30 @@
}
}
+ /** If the outgoingMangler allows bursting, we still don't want to
burst *all the time*, because it may be mistaken
+ * in its detection of a port forward. So from time to time we will
aggressively handshake anyway. This flag is set
+ * once every UPDATE_BURST_NOW_PERIOD. */
+ private boolean burstNow;
+ private long timeSetBurstNow;
+ static final int UPDATE_BURST_NOW_PERIOD = 5*60*1000;
+ /** Burst only 19 in 20 times if definitely port forwarded. Save
entropy by writing this as 20 not 0.95. */
+ static final int P_BURST_IF_DEFINITELY_FORWARDED = 20;
+
+ public boolean isBurstOnly() {
+ int status = outgoingMangler.getConnectivityStatus();
+ if(status == AddressTracker.DONT_KNOW) return false;
+ if(status == AddressTracker.DEFINITELY_NATED) return false;
+
+ // For now. FIXME try it with a lower probability when we're
sure that the packet-deltas mechanisms works.
+ if(status == AddressTracker.MAYBE_PORT_FORWARDED) return false;
+ long now = System.currentTimeMillis();
+ if(now - timeSetBurstNow > UPDATE_BURST_NOW_PERIOD) {
+ burstNow =
(node.random.nextInt(P_BURST_IF_DEFINITELY_FORWARDED) == 0);
+ timeSetBurstNow = now;
+ }
+ return burstNow;
+ }
+
/**
* Call this method when a handshake request has been
* sent.
@@ -2606,6 +2682,8 @@
peerNodeStatus =
PeerManager.PEER_NODE_STATUS_CLOCK_PROBLEM;
else if(neverConnected)
peerNodeStatus =
PeerManager.PEER_NODE_STATUS_NEVER_CONNECTED;
+ else if(isBursting)
+ return PeerManager.PEER_NODE_STATUS_BURSTING;
else
peerNodeStatus =
PeerManager.PEER_NODE_STATUS_DISCONNECTED;
if(!isConnected && (previousRoutingBackoffReason != null)) {