forked from I2P_Developers/i2p.i2p
* SSU: Allow port change if firewalled
* UPnP: - Prep for UPnP returning different external port - Better logging of errors
This commit is contained in:
12
history.txt
12
history.txt
@ -1,3 +1,13 @@
|
||||
2012-08-20 zzz
|
||||
* I2CP: MessageStatus cleanup
|
||||
* i2psnark: Add minimum tracker and DHT announce intervals
|
||||
* I2PTunnelRunner: Remove unnecessary lock (ticket #690)
|
||||
* SSU: Allow port change if firewalled
|
||||
* Streaming: Increase max connection timeout
|
||||
* UPnP:
|
||||
- Prep for UPnP returning different external port
|
||||
- Better logging of errors
|
||||
|
||||
2012-08-18 kytv
|
||||
* Fix hang during uninstallation experienced by some users in Windows
|
||||
|
||||
@ -8,7 +18,7 @@
|
||||
- Remove duplicate clean task for nodes
|
||||
- Fix another DHT warning message
|
||||
* SSU:
|
||||
- Use remote MTU when published (ticket #687)
|
||||
- Use remote MTU when published (ticket #682)
|
||||
- Queue outbound msgs during inbound establish
|
||||
- IntroManager cleanups
|
||||
- More synchronization
|
||||
|
@ -18,7 +18,7 @@ public class RouterVersion {
|
||||
/** deprecated */
|
||||
public final static String ID = "Monotone";
|
||||
public final static String VERSION = CoreVersion.VERSION;
|
||||
public final static long BUILD = 12;
|
||||
public final static long BUILD = 13;
|
||||
|
||||
/** for example "-test" */
|
||||
public final static String EXTRA = "";
|
||||
|
@ -40,7 +40,7 @@ public interface Transport {
|
||||
public static final String SOURCE_INTERFACE = "local";
|
||||
public static final String SOURCE_CONFIG = "config"; // unused
|
||||
public void externalAddressReceived(String source, byte[] ip, int port);
|
||||
public void forwardPortStatus(int port, boolean success, String reason);
|
||||
public void forwardPortStatus(int port, int externalPort, boolean success, String reason);
|
||||
public int getRequestedPort();
|
||||
public void setListener(TransportEventListener listener);
|
||||
public String getStyle();
|
||||
|
@ -477,9 +477,12 @@ public abstract class TransportImpl implements Transport {
|
||||
public void externalAddressReceived(String source, byte[] ip, int port) {}
|
||||
|
||||
/**
|
||||
* Notify a transport of the results of trying to forward a port
|
||||
* Notify a transport of the results of trying to forward a port.
|
||||
* @param port the internal port
|
||||
* @param externalPort the external port, which for now should always be the same as
|
||||
* the internal port if the forwarding was successful.
|
||||
*/
|
||||
public void forwardPortStatus(int port, boolean success, String reason) {}
|
||||
public void forwardPortStatus(int port, int externalPort, boolean success, String reason) {}
|
||||
|
||||
/**
|
||||
* What port would the transport like to have forwarded by UPnP.
|
||||
@ -583,15 +586,18 @@ public abstract class TransportImpl implements Transport {
|
||||
return _IPMap.get(peer);
|
||||
}
|
||||
|
||||
/** @param addr non-null */
|
||||
public static boolean isPubliclyRoutable(byte addr[]) {
|
||||
if (addr.length == 4) {
|
||||
if ((addr[0]&0xFF) == 127) return false;
|
||||
if ((addr[0]&0xFF) == 10) return false;
|
||||
if ( ((addr[0]&0xFF) == 172) && ((addr[1]&0xFF) >= 16) && ((addr[1]&0xFF) <= 31) ) return false;
|
||||
if ( ((addr[0]&0xFF) == 192) && ((addr[1]&0xFF) == 168) ) return false;
|
||||
if ((addr[0]&0xFF) >= 224) return false; // no multicast
|
||||
if ((addr[0]&0xFF) == 0) return false;
|
||||
if ( ((addr[0]&0xFF) == 169) && ((addr[1]&0xFF) == 254) ) return false;
|
||||
int a0 = addr[0] & 0xFF;
|
||||
if (a0 == 127) return false;
|
||||
if (a0 == 10) return false;
|
||||
int a1 = addr[1] & 0xFF;
|
||||
if (a0 == 172 && a1 >= 16 && a1 <= 31) return false;
|
||||
if (a0 == 192 && a1 == 168) return false;
|
||||
if (a0 >= 224) return false; // no multicast
|
||||
if (a0 == 0) return false;
|
||||
if (a0 == 169 && a1 == 254) return false;
|
||||
// 5/8 allocated to RIPE (30 November 2010)
|
||||
//if ((addr[0]&0xFF) == 5) return false; // Hamachi
|
||||
return true; // or at least possible to be true
|
||||
|
@ -130,10 +130,10 @@ public class TransportManager implements TransportEventListener {
|
||||
* callback from UPnP
|
||||
*
|
||||
*/
|
||||
public void forwardPortStatus(String style, int port, boolean success, String reason) {
|
||||
public void forwardPortStatus(String style, int port, int externalPort, boolean success, String reason) {
|
||||
Transport t = getTransport(style);
|
||||
if (t != null)
|
||||
t.forwardPortStatus(port, success, reason);
|
||||
t.forwardPortStatus(port, externalPort, success, reason);
|
||||
}
|
||||
|
||||
public void startListening() {
|
||||
|
@ -7,9 +7,10 @@ import java.net.InetAddress;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
@ -25,6 +26,7 @@ import org.cybergarage.upnp.Device;
|
||||
import org.cybergarage.upnp.DeviceList;
|
||||
import org.cybergarage.upnp.Service;
|
||||
import org.cybergarage.upnp.ServiceList;
|
||||
import org.cybergarage.upnp.UPnPStatus;
|
||||
import org.cybergarage.upnp.device.DeviceChangeListener;
|
||||
import org.cybergarage.upnp.event.EventListener;
|
||||
import org.freenetproject.DetectedIP;
|
||||
@ -161,6 +163,9 @@ class UPnP extends ControlPoint implements DeviceChangeListener, EventListener {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DeviceChangeListener
|
||||
*/
|
||||
public void deviceAdded(Device dev) {
|
||||
synchronized (lock) {
|
||||
if(isDisabled) {
|
||||
@ -279,6 +284,9 @@ class UPnP extends ControlPoint implements DeviceChangeListener, EventListener {
|
||||
this.unregisterPorts(ports);
|
||||
}
|
||||
|
||||
/**
|
||||
* DeviceChangeListener
|
||||
*/
|
||||
public void deviceRemoved(Device dev ){
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("UP&P device removed : " + dev.getFriendlyName() + " UDN: " + dev.getUDN());
|
||||
@ -298,7 +306,10 @@ class UPnP extends ControlPoint implements DeviceChangeListener, EventListener {
|
||||
}
|
||||
}
|
||||
|
||||
/** event callback - unused for now - how many devices support events? */
|
||||
/**
|
||||
* EventListener callback -
|
||||
* unused for now - how many devices support events?
|
||||
*/
|
||||
public void eventNotifyReceived(String uuid, long seq, String varName, String value) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Event: " + uuid + ' ' + seq + ' ' + varName + '=' + value);
|
||||
@ -535,7 +546,10 @@ class UPnP extends ControlPoint implements DeviceChangeListener, EventListener {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/** blocking */
|
||||
/**
|
||||
* This always requests that the external port == the internal port, for now.
|
||||
* Blocking!
|
||||
*/
|
||||
private boolean addMapping(String protocol, int port, String description, ForwardPort fp) {
|
||||
if(isDisabled || !isNATPresent() || _router == null) {
|
||||
_log.error("Can't addMapping: " + isDisabled + " " + isNATPresent() + " " + _router);
|
||||
@ -568,12 +582,42 @@ class UPnP extends ControlPoint implements DeviceChangeListener, EventListener {
|
||||
add.setArgumentValue("NewEnabled","1");
|
||||
add.setArgumentValue("NewLeaseDuration", 0);
|
||||
|
||||
if(add.postControlAction()) {
|
||||
boolean rv = add.postControlAction();
|
||||
if(rv) {
|
||||
synchronized(lock) {
|
||||
portsForwarded.add(fp);
|
||||
}
|
||||
return true;
|
||||
} else return false;
|
||||
}
|
||||
|
||||
int level = rv ? Log.INFO : Log.WARN;
|
||||
if (_log.shouldLog(level)) {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.append("AddPortMapping result for ").append(protocol).append(" port ").append(port);
|
||||
// Not sure which of these has the good info
|
||||
UPnPStatus status = add.getStatus();
|
||||
if (status != null)
|
||||
buf.append(" Status: ").append(status.getCode()).append(' ').append(status.getDescription());
|
||||
status = add.getControlStatus();
|
||||
if (status != null)
|
||||
buf.append(" ControlStatus: ").append(status.getCode()).append(' ').append(status.getDescription());
|
||||
_log.log(level, buf.toString());
|
||||
}
|
||||
|
||||
// TODO if port is busy, retry with wildcard external port ??
|
||||
// from spec:
|
||||
// 402 Invalid Args See UPnP Device Architecture section on Control.
|
||||
// 501 Action Failed See UPnP Device Architecture section on Control.
|
||||
// 715 WildCardNotPermittedInSrcIP The source IP address cannot be wild-carded
|
||||
// 716 WildCardNotPermittedInExtPort The external port cannot be wild-carded
|
||||
// 718 ConflictInMappingEntry The port mapping entry specified conflicts with a mapping assigned previously to another client
|
||||
// 724 SamePortValuesRequired Internal and External port values must be the same
|
||||
// 725 OnlyPermanentLeasesSupported The NAT implementation only supports permanent lease times on port mappings
|
||||
// 726 RemoteHostOnlySupportsWildcard RemoteHost must be a wildcard and cannot be a specific IP address or DNS name
|
||||
// 727 ExternalPortOnlySupportsWildcard ExternalPort must be a wildcard and cannot be a specific port value
|
||||
|
||||
// TODO return error code and description for display
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -667,8 +711,10 @@ class UPnP extends ControlPoint implements DeviceChangeListener, EventListener {
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a callback when the given ports change.
|
||||
* non-blocking
|
||||
* @param ports non-null
|
||||
* @param cb in UPnPManager
|
||||
*/
|
||||
public void onChangePublicPorts(Set<ForwardPort> ports, ForwardPortCallback cb) {
|
||||
Set<ForwardPort> portsToDumpNow = null;
|
||||
@ -760,10 +806,8 @@ class UPnP extends ControlPoint implements DeviceChangeListener, EventListener {
|
||||
}
|
||||
|
||||
public void run() {
|
||||
HashMap<ForwardPort, ForwardPortStatus> map = new HashMap(1);
|
||||
for(ForwardPort port : portsToForwardNow) {
|
||||
String proto = protoToString(port.protocol);
|
||||
map.clear();
|
||||
ForwardPortStatus fps;
|
||||
if (proto.length() <= 1) {
|
||||
fps = new ForwardPortStatus(ForwardPortStatus.DEFINITE_FAILURE, "Protocol not supported", port.portNumber);
|
||||
@ -772,7 +816,7 @@ class UPnP extends ControlPoint implements DeviceChangeListener, EventListener {
|
||||
} else {
|
||||
fps = new ForwardPortStatus(ForwardPortStatus.PROBABLE_FAILURE, "UPnP port forwarding apparently failed", port.portNumber);
|
||||
}
|
||||
map.put(port, fps);
|
||||
Map map = Collections.singletonMap(port, fps);
|
||||
forwardCallback.portForwardStatus(map);
|
||||
}
|
||||
}
|
||||
|
@ -152,7 +152,7 @@ class UPnPManager {
|
||||
else
|
||||
continue;
|
||||
boolean success = fps.status >= ForwardPortStatus.MAYBE_SUCCESS;
|
||||
_manager.forwardPortStatus(style, fp.portNumber, success, fps.reasonString);
|
||||
_manager.forwardPortStatus(style, fp.portNumber, fps.externalPort, success, fps.reasonString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -664,7 +664,7 @@ public class NTCPTransport extends TransportImpl {
|
||||
* NTCP address when it transitions to OK.
|
||||
*/
|
||||
@Override
|
||||
public void forwardPortStatus(int port, boolean success, String reason) {
|
||||
public void forwardPortStatus(int port, int externalPort, boolean success, String reason) {
|
||||
if (_log.shouldLog(Log.WARN)) {
|
||||
if (success)
|
||||
_log.warn("UPnP has opened the NTCP port: " + port);
|
||||
|
@ -102,11 +102,17 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
private static final int DROPLIST_PERIOD = 10*60*1000;
|
||||
public static final String STYLE = "SSU";
|
||||
public static final String PROP_INTERNAL_PORT = "i2np.udp.internalPort";
|
||||
/** now unused, we pick a random port */
|
||||
|
||||
/** now unused, we pick a random port
|
||||
* @deprecated unused
|
||||
*/
|
||||
public static final int DEFAULT_INTERNAL_PORT = 8887;
|
||||
/** since fixed port defaults to true, this doesnt do anything at the moment.
|
||||
* We should have an exception if it matches the existing low port. */
|
||||
|
||||
/** Limits on port told to us by others,
|
||||
* We should have an exception if it matches the existing low port.
|
||||
*/
|
||||
private static final int MIN_EXTERNAL_PORT = 1024;
|
||||
private static final int MAX_EXTERNAL_PORT = 65535;
|
||||
|
||||
/** define this to explicitly set an external IP address */
|
||||
public static final String PROP_EXTERNAL_HOST = "i2np.udp.host";
|
||||
@ -125,9 +131,10 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
public static final String PROP_PREFER_UDP = "i2np.udp.preferred";
|
||||
private static final String DEFAULT_PREFER_UDP = "false";
|
||||
|
||||
/** if true (default), we don't change our advertised port no matter what our peers tell us */
|
||||
public static final String PROP_FIXED_PORT = "i2np.udp.fixedPort";
|
||||
private static final String DEFAULT_FIXED_PORT = "true";
|
||||
/** Override whether we will change our advertised port no matter what our peers tell us
|
||||
* See getIsPortFixed() for default behaviour.
|
||||
*/
|
||||
private static final String PROP_FIXED_PORT = "i2np.udp.fixedPort";
|
||||
|
||||
/** allowed sources of address updates */
|
||||
public static final String PROP_SOURCES = "i2np.udp.addressSources";
|
||||
@ -480,10 +487,10 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
* Don't do anything if UPnP claims failure.
|
||||
*/
|
||||
@Override
|
||||
public void forwardPortStatus(int port, boolean success, String reason) {
|
||||
public void forwardPortStatus(int port, int externalPort, boolean success, String reason) {
|
||||
if (_log.shouldLog(Log.WARN)) {
|
||||
if (success)
|
||||
_log.warn("UPnP has opened the SSU port: " + port);
|
||||
_log.warn("UPnP has opened the SSU port: " + port + " via external port: " + externalPort);
|
||||
else
|
||||
_log.warn("UPnP has failed to open the SSU port: " + port + " reason: " + reason);
|
||||
}
|
||||
@ -509,7 +516,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
*/
|
||||
void externalAddressReceived(Hash from, byte ourIP[], int ourPort) {
|
||||
boolean isValid = isValid(ourIP) &&
|
||||
(ourPort >= MIN_EXTERNAL_PORT || ourPort == _externalListenPort || _externalListenPort <= 0);
|
||||
((ourPort >= MIN_EXTERNAL_PORT && ourPort <= MAX_EXTERNAL_PORT) ||
|
||||
ourPort == _externalListenPort || _externalListenPort <= 0);
|
||||
boolean explicitSpecified = explicitAddressSpecified();
|
||||
boolean inboundRecent = _lastInboundReceivedOn + ALLOW_IP_CHANGE_INTERVAL > System.currentTimeMillis();
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
@ -561,7 +569,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
* @param ourPort >= 1024 or 0 for no change
|
||||
*/
|
||||
private boolean changeAddress(byte ourIP[], int ourPort) {
|
||||
/** this defaults to true, which means we never change our external port based on what somebody tells us */
|
||||
// this defaults to true when we are firewalled and false otherwise.
|
||||
boolean fixedPort = getIsPortFixed();
|
||||
boolean updated = false;
|
||||
boolean fireTest = false;
|
||||
@ -583,7 +591,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
try {
|
||||
_externalListenHost = InetAddress.getByAddress(ourIP);
|
||||
// fixed port defaults to true so we never do this
|
||||
if (ourPort >= MIN_EXTERNAL_PORT && !fixedPort)
|
||||
if (ourPort >= MIN_EXTERNAL_PORT && ourPort <= MAX_EXTERNAL_PORT && !fixedPort)
|
||||
_externalListenPort = ourPort;
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Trying to change our external address to " +
|
||||
@ -614,9 +622,9 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
}
|
||||
|
||||
if (fireTest) {
|
||||
_context.statManager().addRateData("udp.addressTestInsteadOfUpdate", 1, 0);
|
||||
_context.statManager().addRateData("udp.addressTestInsteadOfUpdate", 1);
|
||||
} else if (updated) {
|
||||
_context.statManager().addRateData("udp.addressUpdated", 1, 0);
|
||||
_context.statManager().addRateData("udp.addressUpdated", 1);
|
||||
Map<String, String> changes = new HashMap();
|
||||
if (!fixedPort)
|
||||
changes.put(PROP_EXTERNAL_PORT, Integer.toString(ourPort));
|
||||
@ -669,16 +677,25 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
return (rport == lport) && DataHelper.eq(laddr, raddr);
|
||||
}
|
||||
|
||||
/** @param addr may be null */
|
||||
public final boolean isValid(byte addr[]) {
|
||||
if (addr == null) return false;
|
||||
if (addr.length < 4) return false;
|
||||
if (isPubliclyRoutable(addr))
|
||||
return true;
|
||||
return _context.getBooleanProperty("i2np.udp.allowLocal");
|
||||
}
|
||||
|
||||
/**
|
||||
* Was true before 0.9.2
|
||||
* Now false if we need introducers (as perhaps that's why we need them,
|
||||
* our firewall is changing our port), unless overridden by the property.
|
||||
*/
|
||||
private boolean getIsPortFixed() {
|
||||
return DEFAULT_FIXED_PORT.equals(_context.getProperty(PROP_FIXED_PORT, DEFAULT_FIXED_PORT));
|
||||
String prop = _context.getProperty(PROP_FIXED_PORT);
|
||||
if (prop != null)
|
||||
return Boolean.valueOf(prop).booleanValue();
|
||||
int status = getReachabilityStatus();
|
||||
return status != CommSystemFacade.STATUS_REJECT_UNSOLICITED;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -862,7 +879,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
if (peer != null) {
|
||||
RemoteHostId remote = peer.getRemoteHostId();
|
||||
_dropList.add(remote);
|
||||
_context.statManager().addRateData("udp.dropPeerDroplist", 1, 0);
|
||||
_context.statManager().addRateData("udp.dropPeerDroplist", 1);
|
||||
_context.simpleScheduler().addEvent(new RemoveDropList(remote), DROPLIST_PERIOD);
|
||||
}
|
||||
markUnreachable(peerHash);
|
||||
@ -2360,17 +2377,21 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
long now = _context.clock().now();
|
||||
switch (status) {
|
||||
case CommSystemFacade.STATUS_OK:
|
||||
_context.statManager().addRateData("udp.statusOK", 1, 0);
|
||||
// TODO if OK but internal port != external port, should we have
|
||||
// a different status state? ...as we don't know if the TCP
|
||||
// port will be mapped the same way or not...
|
||||
// Right now, we assume it is and hope for the best for TCP.
|
||||
_context.statManager().addRateData("udp.statusOK", 1);
|
||||
_reachabilityStatus = status;
|
||||
_reachabilityStatusLastUpdated = now;
|
||||
break;
|
||||
case CommSystemFacade.STATUS_DIFFERENT:
|
||||
_context.statManager().addRateData("udp.statusDifferent", 1, 0);
|
||||
_context.statManager().addRateData("udp.statusDifferent", 1);
|
||||
_reachabilityStatus = status;
|
||||
_reachabilityStatusLastUpdated = now;
|
||||
break;
|
||||
case CommSystemFacade.STATUS_REJECT_UNSOLICITED:
|
||||
_context.statManager().addRateData("udp.statusReject", 1, 0);
|
||||
_context.statManager().addRateData("udp.statusReject", 1);
|
||||
// if old != unsolicited && now - lastUpdated > STATUS_GRACE_PERIOD)
|
||||
//
|
||||
// fall through...
|
||||
@ -2380,7 +2401,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
break;
|
||||
case CommSystemFacade.STATUS_UNKNOWN:
|
||||
default:
|
||||
_context.statManager().addRateData("udp.statusUnknown", 1, 0);
|
||||
_context.statManager().addRateData("udp.statusUnknown", 1);
|
||||
//if (now - _reachabilityStatusLastUpdated < STATUS_GRACE_PERIOD) {
|
||||
// _testEvent.forceRun();
|
||||
// SimpleTimer.getInstance().addEvent(_testEvent, 5*1000);
|
||||
|
Reference in New Issue
Block a user