diff --git a/history.txt b/history.txt index 39080b4ba8..ee60754c01 100644 --- a/history.txt +++ b/history.txt @@ -1,3 +1,24 @@ +2019-02-07 zzz + * NTCP: + - Add option to disable NTCP1 (ticket #2328) + - Don't bid for outbound-only NTCP2 addresses + - Fix NTCP2 cost when transitioning to inbound + +2019-02-06 zzz + * Build: Add targets for alternate debian distros (ticket #2410) + * Crypto: Shortcut GroupElement representation conversion + * I2CP: Prevent use of repliable datagrams with offline keys + +2019-02-05 zzz + * Transport: + - Clean up unreachable() methods (ticket #2382) + - Speed up NTCP allowConnection() (ticket #2381) + - OutNetMessage cleanup (ticket #2386) + - SSU PacketHandler cleanup (ticket #2383) + +2019-02-04 zzz + * I2CP: Change format and message type of CreateLeaseSet2 message + 2019-02-03 zzz * I2CP: - Remove revocation private key from CreateLeaseset2 message diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index c10128fe62..fecba78d69 100644 --- a/router/java/src/net/i2p/router/RouterVersion.java +++ b/router/java/src/net/i2p/router/RouterVersion.java @@ -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 = 6; + public final static long BUILD = 7; /** for example "-test" */ public final static String EXTRA = ""; diff --git a/router/java/src/net/i2p/router/transport/TransportManager.java b/router/java/src/net/i2p/router/transport/TransportManager.java index 070eb2b215..bff09ec83a 100644 --- a/router/java/src/net/i2p/router/transport/TransportManager.java +++ b/router/java/src/net/i2p/router/transport/TransportManager.java @@ -70,6 +70,8 @@ public class TransportManager implements TransportEventListener { private final UPnPManager _upnpManager; private final DHSessionKeyBuilder.PrecalcRunner _dhThread; private final X25519KeyFactory _xdhThread; + private final boolean _enableUDP; + private final boolean _enableNTCP1; /** default true */ public final static String PROP_ENABLE_UDP = "i2np.udp.enable"; @@ -78,6 +80,9 @@ public class TransportManager implements TransportEventListener { /** default true */ public final static String PROP_ENABLE_UPNP = "i2np.upnp.enable"; + /** default true */ + private static final String PROP_NTCP1_ENABLE = "i2np.ntcp1.enable"; + private static final boolean DEFAULT_NTCP1_ENABLE = true; private static final String PROP_NTCP2_ENABLE = "i2np.ntcp2.enable"; private static final boolean DEFAULT_NTCP2_ENABLE = true; @@ -102,9 +107,12 @@ public class TransportManager implements TransportEventListener { _upnpManager = new UPnPManager(context, this); else _upnpManager = null; - _dhThread = new DHSessionKeyBuilder.PrecalcRunner(context); + _enableUDP = _context.getBooleanPropertyDefaultTrue(PROP_ENABLE_UDP); + _enableNTCP1 = isNTCPEnabled(context) && + context.getProperty(PROP_NTCP1_ENABLE, DEFAULT_NTCP1_ENABLE); boolean enableNTCP2 = isNTCPEnabled(context) && context.getProperty(PROP_NTCP2_ENABLE, DEFAULT_NTCP2_ENABLE); + _dhThread = (_enableUDP || enableNTCP2) ? new DHSessionKeyBuilder.PrecalcRunner(context) : null; _xdhThread = enableNTCP2 ? new X25519KeyFactory(context) : null; } @@ -149,6 +157,7 @@ public class TransportManager implements TransportEventListener { /** * Hook for pluggable transport creation. * + * @return null if both NTCP1 and SSU are disabled * @since 0.9.16 */ DHSessionKeyBuilder.Factory getDHFactory() { @@ -172,15 +181,15 @@ public class TransportManager implements TransportEventListener { } private void configTransports() { - boolean enableUDP = _context.getBooleanPropertyDefaultTrue(PROP_ENABLE_UDP); Transport udp = null; - if (enableUDP) { + if (_enableUDP) { udp = new UDPTransport(_context, _dhThread); addTransport(udp); initializeAddress(udp); } if (isNTCPEnabled(_context)) { - Transport ntcp = new NTCPTransport(_context, _dhThread, _xdhThread); + DHSessionKeyBuilder.PrecalcRunner dh = _enableNTCP1 ? _dhThread : null; + Transport ntcp = new NTCPTransport(_context, dh, _xdhThread); addTransport(ntcp); initializeAddress(ntcp); if (udp != null) { @@ -315,7 +324,7 @@ public class TransportManager implements TransportEventListener { } synchronized void startListening() { - if (_dhThread.getState() == Thread.State.NEW) + if (_dhThread != null && _dhThread.getState() == Thread.State.NEW) _dhThread.start(); if (_xdhThread != null && _xdhThread.getState() == Thread.State.NEW) _xdhThread.start(); @@ -377,7 +386,8 @@ public class TransportManager implements TransportEventListener { */ synchronized void shutdown() { stopListening(); - _dhThread.shutdown(); + if (_dhThread != null) + _dhThread.shutdown(); if (_xdhThread != null) _xdhThread.shutdown(); Addresses.clearCaches(); diff --git a/router/java/src/net/i2p/router/transport/ntcp/EstablishBase.java b/router/java/src/net/i2p/router/transport/ntcp/EstablishBase.java index 115ecca60d..de10dce689 100644 --- a/router/java/src/net/i2p/router/transport/ntcp/EstablishBase.java +++ b/router/java/src/net/i2p/router/transport/ntcp/EstablishBase.java @@ -191,12 +191,17 @@ abstract class EstablishBase implements EstablishState { _log = ctx.logManager().getLog(getClass()); _transport = transport; _con = con; + // null if NTCP1 disabled _dh = _transport.getDHBuilder(); _hX_xor_bobIdentHash = SimpleByteCache.acquire(HXY_SIZE); if (_con.isInbound()) { _X = SimpleByteCache.acquire(XY_SIZE); - _Y = _dh.getMyPublicValueBytes(); + _Y = (_dh != null) ?_dh.getMyPublicValueBytes() : null; } else { + // OutboundNTCP2State does not extend this, + // can't get here with NTCP1 disabled + if (_dh == null) + throw new IllegalStateException(); _X = _dh.getMyPublicValueBytes(); _Y = SimpleByteCache.acquire(XY_SIZE); } @@ -304,7 +309,7 @@ abstract class EstablishBase implements EstablishState { SimpleByteCache.release(_prevEncrypted); SimpleByteCache.release(_curDecrypted); SimpleByteCache.release(_hX_xor_bobIdentHash); - if (_dh.getPeerPublicValue() == null) + if (_dh != null && _dh.getPeerPublicValue() == null) _transport.returnUnused(_dh); } diff --git a/router/java/src/net/i2p/router/transport/ntcp/InboundEstablishState.java b/router/java/src/net/i2p/router/transport/ntcp/InboundEstablishState.java index c718de552c..fdaa492319 100644 --- a/router/java/src/net/i2p/router/transport/ntcp/InboundEstablishState.java +++ b/router/java/src/net/i2p/router/transport/ntcp/InboundEstablishState.java @@ -123,6 +123,8 @@ class InboundEstablishState extends EstablishBase implements NTCP2Payload.Payloa public int getVersion() { if (!_transport.isNTCP2Enabled()) return 1; + if (!_transport.isNTCP1Enabled()) + return 2; synchronized (_stateLock) { if (_state == State.IB_INIT) return 0; @@ -160,7 +162,8 @@ class InboundEstablishState extends EstablishBase implements NTCP2Payload.Payloa _log.warn("Short buffer got " + remaining + " total now " + _received + " on " + this); return; } - if (remaining + _received < NTCP1_MSG1_SIZE) { + if (remaining + _received < NTCP1_MSG1_SIZE || + !_transport.isNTCP1Enabled()) { // Less than 288 total received, assume NTCP2 // TODO can't change our mind later if we get more than 287 _con.setVersion(2); @@ -743,6 +746,7 @@ class InboundEstablishState extends EstablishBase implements NTCP2Payload.Payloa fail("Clock Skew: " + _peerSkew, null, true); return; } + // TODO if NTCP1 disabled, we should allow longer padding if (_padlen1 > PADDING1_MAX) { fail("bad msg 1 padlen: " + _padlen1); return; 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 e231d7bbda..4addad6b06 100644 --- a/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java +++ b/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java @@ -137,6 +137,7 @@ public class NTCPTransport extends TransportImpl { private static final int NTCP2_IV_LEN = OutboundNTCP2State.IV_SIZE; private static final int NTCP2_KEY_LEN = OutboundNTCP2State.KEY_SIZE; private static final long MIN_DOWNTIME_TO_REKEY = 30*24*60*60*1000L; + private final boolean _enableNTCP1; private final boolean _enableNTCP2; private final byte[] _ntcp2StaticPubkey; private final byte[] _ntcp2StaticPrivkey; @@ -145,6 +146,7 @@ public class NTCPTransport extends TransportImpl { private final String _b64Ntcp2StaticIV; /** + * @param dh null to disable NTCP1 * @param xdh null to disable NTCP2 */ public NTCPTransport(RouterContext ctx, DHSessionKeyBuilder.Factory dh, X25519KeyFactory xdh) { @@ -238,7 +240,10 @@ public class NTCPTransport extends TransportImpl { _nearCapacityCostBid = new SharedBid(105); _transientFail = new SharedBid(TransportBid.TRANSIENT_FAIL); + _enableNTCP1 = dh != null; _enableNTCP2 = xdh != null; + if (!_enableNTCP1 && !_enableNTCP2) + throw new IllegalArgumentException(); if (_enableNTCP2) { boolean shouldSave = false; byte[] priv = null; @@ -577,6 +582,10 @@ public class NTCPTransport extends TransportImpl { List addrs = getTargetAddresses(target); for (int i = 0; i < addrs.size(); i++) { RouterAddress addr = addrs.get(i); + // use this to skip outbound-only NTCP2, + // and NTCP1 if disabled + if (getNTCPVersion(addr) == 0) + continue; byte[] ip = addr.getIP(); if (!TransportUtil.isValidPort(addr.getPort()) || ip == null) { //_context.statManager().addRateData("ntcp.connectFailedInvalidPort", 1); @@ -840,7 +849,7 @@ public class NTCPTransport extends TransportImpl { props.setProperty(RouterAddress.PROP_PORT, Integer.toString(port)); addNTCP2Options(props); int cost = getDefaultCost(ia instanceof Inet6Address); - myAddress = new RouterAddress(STYLE, props, cost); + myAddress = new RouterAddress(getPublishStyle(), props, cost); replaceAddress(myAddress); } } else if (_enableNTCP2) { @@ -969,7 +978,7 @@ public class NTCPTransport extends TransportImpl { props.setProperty(RouterAddress.PROP_PORT, Integer.toString(port)); addNTCP2Options(props); int cost = getDefaultCost(false); - myAddress = new RouterAddress(STYLE, props, cost); + myAddress = new RouterAddress(getPublishStyle(), props, cost); } if (!_endpoints.isEmpty()) { // If we are already bound to the new address, OR @@ -1052,6 +1061,9 @@ public class NTCPTransport extends TransportImpl { */ net.i2p.router.transport.ntcp.Writer getWriter() { return _writer; } + /** + * @return always "NTCP" even if NTCP1 is disabled + */ public String getStyle() { return STYLE; } /** @@ -1064,16 +1076,25 @@ public class NTCPTransport extends TransportImpl { return _enableNTCP2 ? STYLE2 : null; } + /** + * @return "NTCP" if NTCP1 is enabled, else "NTCP2" + * @since 0.9.39 + */ + private String getPublishStyle() { + return _enableNTCP1 ? STYLE : STYLE2; + } + /** * Hook for NTCPConnection */ EventPumper getPumper() { return _pumper; } /** + * @return null if not configured for NTCP1 * @since 0.9 */ DHSessionKeyBuilder getDHBuilder() { - return _dhFactory.getBuilder(); + return _dhFactory != null ? _dhFactory.getBuilder() : null; } /** @@ -1092,7 +1113,8 @@ public class NTCPTransport extends TransportImpl { * @since 0.9.16 */ void returnUnused(DHSessionKeyBuilder builder) { - _dhFactory.returnUnused(builder); + if (_dhFactory != null) + _dhFactory.returnUnused(builder); } /** @@ -1185,7 +1207,7 @@ public class NTCPTransport extends TransportImpl { props.setProperty(RouterAddress.PROP_PORT, Integer.toString(p)); addNTCP2Options(props); int cost = getDefaultCost(false); - RouterAddress addr = new RouterAddress(STYLE, props, cost); + RouterAddress addr = new RouterAddress(getPublishStyle(), props, cost); return addr; } @@ -1205,6 +1227,13 @@ public class NTCPTransport extends TransportImpl { props.setProperty("v", NTCP2_VERSION); } + /** + * Is NTCP1 enabled? + * + * @since 0.9.39 + */ + boolean isNTCP1Enabled() { return _enableNTCP1; } + /** * Is NTCP2 enabled? * @@ -1267,9 +1296,11 @@ public class NTCPTransport extends TransportImpl { addr.getOption("i") == null || addr.getOption("s") == null || (!v.equals(NTCP2_VERSION) && !v.startsWith(NTCP2_VERSION_ALT))) { - return (rv == 1) ? 1 : 0; + // his address is NTCP1 or is outbound NTCP2 only + return (rv == 1 && _enableNTCP1) ? 1 : 0; } - // todo validate s/i b64, or just catch it later? + // his address is NTCP2 + // do not validate the s/i b64, we will just catch it later return NTCP2_INT_VERSION; } @@ -1461,7 +1492,7 @@ public class NTCPTransport extends TransportImpl { cost = oldAddr.getCost(); newProps.putAll(oldAddr.getOptionsMap()); } - RouterAddress newAddr = new RouterAddress(STYLE, newProps, cost); + RouterAddress newAddr = new RouterAddress(getPublishStyle(), newProps, cost); boolean changed = false; @@ -1532,6 +1563,8 @@ public class NTCPTransport extends TransportImpl { return; if (ohost == null || ! ohost.equalsIgnoreCase(nhost)) { newProps.setProperty(RouterAddress.PROP_HOST, nhost); + if (cost == NTCP2_OUTBOUND_COST) + newAddr.setCost(DEFAULT_COST); changed = true; } } else if (enabled.equals("false") && @@ -1543,6 +1576,8 @@ public class NTCPTransport extends TransportImpl { if (_log.shouldLog(Log.INFO)) _log.info("old host: " + ohost + " config: " + name + " new: " + name); newProps.setProperty(RouterAddress.PROP_HOST, name); + if (cost == NTCP2_OUTBOUND_COST) + newAddr.setCost(DEFAULT_COST); changed = true; } else if (ohost == null || ohost.length() <= 0) { return;