NTCP: Add option to disable NTCP1 (ticket #2328)

Don't bid for outbound-only NTCP2 addresses
Fix NTCP2 cost when transitioning to inbound
This commit is contained in:
zzz
2019-02-07 14:54:56 +00:00
parent b310c60188
commit 636016d107
6 changed files with 93 additions and 18 deletions

View File

@ -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

View File

@ -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 = "";

View File

@ -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,6 +386,7 @@ public class TransportManager implements TransportEventListener {
*/
synchronized void shutdown() {
stopListening();
if (_dhThread != null)
_dhThread.shutdown();
if (_xdhThread != null)
_xdhThread.shutdown();

View File

@ -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);
}

View File

@ -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;

View File

@ -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<RouterAddress> 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,6 +1113,7 @@ public class NTCPTransport extends TransportImpl {
* @since 0.9.16
*/
void returnUnused(DHSessionKeyBuilder 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;