From abd8ca34dc85abbcc8b344526b78b429f533578f Mon Sep 17 00:00:00 2001 From: zzz <zzz@mail.i2p> Date: Wed, 6 May 2015 01:45:33 +0000 Subject: [PATCH] Transport: Add config to force IPv4 (only) to firewalled (ticket #1541) since we cannot reliably detect DS-lite (ticket #1458) Hide transport status on /peers unless routerconsole.advanced --- .../net/i2p/router/web/ConfigNetHandler.java | 15 +++++++ .../net/i2p/router/web/ConfigNetHelper.java | 5 +++ apps/routerconsole/jsp/confignet.jsp | 4 ++ .../i2p/router/transport/TransportImpl.java | 8 ++++ .../router/transport/TransportManager.java | 14 ++++--- .../i2p/router/transport/TransportUtil.java | 9 +++++ .../router/transport/ntcp/NTCPTransport.java | 4 +- .../router/transport/udp/UDPTransport.java | 39 ++++++++++++++----- 8 files changed, 83 insertions(+), 15 deletions(-) diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHandler.java index c52634b885..8465400f53 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHandler.java @@ -50,6 +50,7 @@ public class ConfigNetHandler extends FormHandler { private boolean _ratesOnly; private boolean _udpDisabled; private String _ipv6Mode; + private boolean _ipv4Firewalled; private final Map<String, String> changes = new HashMap<String, String>(); private static final String PROP_HIDDEN = Router.PROP_HIDDEN_HIDDEN; // see Router for other choice @@ -79,8 +80,12 @@ public class ConfigNetHandler extends FormHandler { public void setNtcpAutoPort(String mode) { _ntcpAutoPort = mode.equals("2"); } + public void setUpnp(String moo) { _upnp = true; } public void setLaptop(String moo) { _laptop = true; } + + /** @since 0.9.20 */ + public void setIPv4Firewalled(String moo) { _ipv4Firewalled = true; } public void setHostname(String hostname) { _hostname = (hostname != null ? hostname.trim() : null); @@ -348,6 +353,16 @@ public class ConfigNetHandler extends FormHandler { } changes.put(UDPTransport.PROP_LAPTOP_MODE, "" + _laptop); + if (Boolean.parseBoolean(_context.getProperty(TransportUtil.PROP_IPV4_FIREWALLED)) != + _ipv4Firewalled) { + if (_ipv4Firewalled) + addFormNotice(_("Disabling inbound IPv4")); + else + addFormNotice(_("Enabling inbound IPv4")); + restartRequired = true; + } + changes.put(TransportUtil.PROP_IPV4_FIREWALLED, "" + _ipv4Firewalled); + if (_context.getBooleanPropertyDefaultTrue(TransportManager.PROP_ENABLE_UDP) != !_udpDisabled) { if (_udpDisabled) diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHelper.java index cd2f89eba1..3c82277943 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHelper.java @@ -93,6 +93,11 @@ public class ConfigNetHelper extends HelperBase { return getChecked(UDPTransport.PROP_LAPTOP_MODE); } + /** @since 0.9.20 */ + public String getIPv4FirewalledChecked() { + return getChecked(TransportUtil.PROP_IPV4_FIREWALLED); + } + public String getTcpAutoPortChecked(int mode) { String port = _context.getProperty(PROP_I2NP_NTCP_PORT); boolean specified = port != null && port.length() > 0; diff --git a/apps/routerconsole/jsp/confignet.jsp b/apps/routerconsole/jsp/confignet.jsp index 6c4b6149c3..27fdfef7ef 100644 --- a/apps/routerconsole/jsp/confignet.jsp +++ b/apps/routerconsole/jsp/confignet.jsp @@ -51,6 +51,10 @@ <%=intl._("Laptop mode - Change router identity and UDP port when IP changes for enhanced anonymity")%> (<i><%=intl._("Experimental")%></i>) </p><p> + <%=intl._("IPv4 Configuration")%>:<br> + <input type="checkbox" class="optbox" name="IPv4Firewalled" value="true" <jsp:getProperty name="nethelper" property="IPv4FirewalledChecked" /> > + <%=intl._("Disable inbound (Firewalled by Carrier-grade NAT or DS-Lite)")%> + </p><p> <%=intl._("IPv6 Configuration")%>:<br> <input type="radio" class="optbox" name="ipv6" value="false" <%=nethelper.getIPv6Checked("false") %> > <%=intl._("Disable IPv6")%><br> diff --git a/router/java/src/net/i2p/router/transport/TransportImpl.java b/router/java/src/net/i2p/router/transport/TransportImpl.java index b5f0870aad..68b56bf336 100644 --- a/router/java/src/net/i2p/router/transport/TransportImpl.java +++ b/router/java/src/net/i2p/router/transport/TransportImpl.java @@ -813,6 +813,14 @@ public abstract class TransportImpl implements Transport { */ public void recheckReachability() {} + /** + * @param transportStyle ignored + * @since 0.9.20 + */ + protected boolean isIPv4Firewalled() { + return TransportUtil.isIPv4Firewalled(_context, getStyle()); + } + public boolean isBacklogged(Hash dest) { return false; } public boolean isEstablished(Hash dest) { return false; } diff --git a/router/java/src/net/i2p/router/transport/TransportManager.java b/router/java/src/net/i2p/router/transport/TransportManager.java index eb44660133..e5240d6a2d 100644 --- a/router/java/src/net/i2p/router/transport/TransportManager.java +++ b/router/java/src/net/i2p/router/transport/TransportManager.java @@ -60,6 +60,8 @@ public class TransportManager implements TransportEventListener { public final static String PROP_ENABLE_NTCP = "i2np.ntcp.enable"; /** default true */ public final static String PROP_ENABLE_UPNP = "i2np.upnp.enable"; + + private static final String PROP_ADVANCED = "routerconsole.advanced"; /** not forever, since they may update */ private static final long SIGTYPE_BANLIST_DURATION = 36*60*60*1000L; @@ -667,11 +669,13 @@ public class TransportManager implements TransportEventListener { * will take many seconds if it has vanished. */ public void renderStatusHTML(Writer out, String urlBase, int sortFlags) throws IOException { - out.write("<p>"); - out.write(_("Status")); - out.write(": "); - out.write(_(getReachabilityStatus().toStatusString())); - out.write("</p>"); + if (_context.getBooleanProperty(PROP_ADVANCED)) { + out.write("<p><b>"); + out.write(_("Status")); + out.write(": "); + out.write(_(getReachabilityStatus().toStatusString())); + out.write("</b></p>"); + } TreeMap<String, Transport> transports = new TreeMap<String, Transport>(); for (Transport t : _transports.values()) { transports.put(t.getStyle(), t); diff --git a/router/java/src/net/i2p/router/transport/TransportUtil.java b/router/java/src/net/i2p/router/transport/TransportUtil.java index 650a9656f3..3ca7e8a2e1 100644 --- a/router/java/src/net/i2p/router/transport/TransportUtil.java +++ b/router/java/src/net/i2p/router/transport/TransportUtil.java @@ -23,6 +23,7 @@ public abstract class TransportUtil { public static final String NTCP_IPV6_CONFIG = "i2np.ntcp.ipv6"; public static final String SSU_IPV6_CONFIG = "i2np.udp.ipv6"; + public static final String PROP_IPV4_FIREWALLED = "i2np.ipv4.firewalled"; public enum IPv6Config { /** IPv6 disabled */ @@ -83,6 +84,14 @@ public abstract class TransportUtil { return DEFAULT_IPV6_CONFIG; } + /** + * @param transportStyle ignored + * @since 0.9.20 + */ + public static boolean isIPv4Firewalled(RouterContext ctx, String transportStyle) { + return ctx.getBooleanProperty(PROP_IPV4_FIREWALLED); + } + /** * Addresses without a host (i.e. w/introducers) * are assumed to be IPv4 diff --git a/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java b/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java index ca6259e456..382d4d89e4 100644 --- a/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java +++ b/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java @@ -1344,7 +1344,9 @@ public class NTCPTransport extends TransportImpl { buf.append("<h3 id=\"ntcpcon\">").append(_("NTCP connections")).append(": ").append(peers.size()); buf.append(". ").append(_("Limit")).append(": ").append(getMaxConnections()); buf.append(". ").append(_("Timeout")).append(": ").append(DataHelper.formatDuration2(_pumper.getIdleTimeout())); - buf.append(". ").append(_("Status")).append(": ").append(_(getReachabilityStatus().toStatusString())); + if (_context.getBooleanProperty(PROP_ADVANCED)) { + buf.append(". ").append(_("Status")).append(": ").append(_(getReachabilityStatus().toStatusString())); + } buf.append(".</h3>\n" + "<table>\n" + "<tr><th><a href=\"#def.peer\">").append(_("Peer")).append("</a></th>" + diff --git a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java index 35f2accce1..a502eb327b 100644 --- a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java +++ b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java @@ -167,6 +167,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority public static final String PROP_BIND_INTERFACE = "i2np.udp.bindInterface"; /** override the "large" (max) MTU, default is PeerState.LARGE_MTU */ private static final String PROP_DEFAULT_MTU = "i2np.udp.mtu"; + private static final String PROP_ADVANCED = "routerconsole.advanced"; private static final String CAP_TESTING = "" + UDPAddress.CAPACITY_TESTING; private static final String CAP_TESTING_INTRO = "" + UDPAddress.CAPACITY_TESTING + UDPAddress.CAPACITY_INTRODUCER; @@ -457,6 +458,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority //if (SHOULD_FLOOD_PEERS) // _flooder.startup(); _expireEvent.setIsAlive(true); + _reachabilityStatus = Status.UNKNOWN; _testEvent.setIsAlive(true); // this queues it for 3-6 minutes in the future... _testEvent.reschedule(10*1000); // lets requeue it for Real Soon @@ -477,7 +479,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority _lastInboundIPv6 = _context.clock().now(); setReachabilityStatus(Status.IPV4_UNKNOWN_IPV6_OK); } else { - setReachabilityStatus(Status.IPV4_OK_IPV6_UNKNOWN); + if (!isIPv4Firewalled()) + setReachabilityStatus(Status.IPV4_OK_IPV6_UNKNOWN); } rebuildExternalAddress(ia.getHostAddress(), newPort, false); } @@ -487,11 +490,18 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority _lastInboundIPv6 = _context.clock().now(); setReachabilityStatus(Status.IPV4_UNKNOWN_IPV6_OK); } else { - setReachabilityStatus(Status.IPV4_OK_IPV6_UNKNOWN); + if (!isIPv4Firewalled()) + setReachabilityStatus(Status.IPV4_OK_IPV6_UNKNOWN); } rebuildExternalAddress(ia.getHostAddress(), newPort, false); } } + if (isIPv4Firewalled()) { + if (_lastInboundIPv6 > 0) + setReachabilityStatus(Status.IPV4_FIREWALLED_IPV6_UNKNOWN); + else + setReachabilityStatus(Status.REJECT_UNSOLICITED); + } rebuildExternalAddress(false); } @@ -763,12 +773,14 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority // Assume if we have an interface with a public IP that we aren't firewalled. // If this is wrong, the peer test will figure it out and change the status. if (changed && source == SOURCE_INTERFACE) { - if (ip.length == 4) - setReachabilityStatus(Status.IPV4_OK_IPV6_UNKNOWN); - else if (ip.length == 16) + if (ip.length == 4) { + if (!isIPv4Firewalled()) + setReachabilityStatus(Status.IPV4_OK_IPV6_UNKNOWN); + } else if (ip.length == 16) { // TODO should we set both to unknown and wait for an inbound v6 conn, // since there's no v6 testing? setReachabilityStatus(Status.IPV4_UNKNOWN_IPV6_OK); + } } } @@ -786,8 +798,10 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority else _log.warn("UPnP has failed to open the SSU port: " + port + " reason: " + reason); } - if (success && ip != null && getExternalIP() != null) - setReachabilityStatus(Status.IPV4_OK_IPV6_UNKNOWN); + if (success && ip != null && getExternalIP() != null) { + if (!isIPv4Firewalled()) + setReachabilityStatus(Status.IPV4_OK_IPV6_UNKNOWN); + } } /** @@ -2434,7 +2448,9 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority buf.append("<h3 id=\"udpcon\">").append(_("UDP connections")).append(": ").append(peers.size()); buf.append(". ").append(_("Limit")).append(": ").append(getMaxConnections()); buf.append(". ").append(_("Timeout")).append(": ").append(DataHelper.formatDuration2(_expireTimeout)); - buf.append(". ").append(_("Status")).append(": ").append(_(_reachabilityStatus.toStatusString())); + if (_context.getBooleanProperty(PROP_ADVANCED)) { + buf.append(". ").append(_("Status")).append(": ").append(_(_reachabilityStatus.toStatusString())); + } buf.append(".</h3>\n"); buf.append("<table>\n"); buf.append("<tr><th class=\"smallhead\" nowrap><a href=\"#def.peer\">").append(_("Peer")).append("</a><br>"); @@ -3003,7 +3019,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority } private boolean shouldTest() { - return ! _context.router().isHidden(); + return ! (_context.router().isHidden() || + isIPv4Firewalled()); //String val = _context.getProperty(PROP_SHOULD_TEST); //return ( (val != null) && ("true".equals(val)) ); } @@ -3053,6 +3070,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority * @since 0.9.13 */ public synchronized void forceRunSoon() { + if (isIPv4Firewalled()) + return; _forceRun = true; reschedule(MIN_TEST_FREQUENCY); } @@ -3063,6 +3082,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority * @since 0.9.13 */ public synchronized void forceRunImmediately() { + if (isIPv4Firewalled()) + return; _lastTested.set(0); _forceRun = true; reschedule(5*1000); -- GitLab