diff --git a/router/java/src/net/i2p/router/Router.java b/router/java/src/net/i2p/router/Router.java index 453b2f84a7..2f762ac144 100644 --- a/router/java/src/net/i2p/router/Router.java +++ b/router/java/src/net/i2p/router/Router.java @@ -385,7 +385,11 @@ public class Router implements RouterClock.ClockShiftListener { if (sid != null) { try { id = Integer.parseInt(sid); - } catch (NumberFormatException nfe) {} + if (id < 2 || id > 254) + throw new IllegalArgumentException("Invalid " + PROP_NETWORK_ID); + } catch (NumberFormatException nfe) { + throw new IllegalArgumentException("Invalid " + PROP_NETWORK_ID); + } } _networkID = id; // for testing @@ -600,6 +604,8 @@ public class Router implements RouterClock.ClockShiftListener { * The network ID. Default 2. * May be changed with the config property router.networkID (restart required). * Change only if running a test network to prevent cross-network contamination. + * + * @return 2 - 254 * @since 0.9.25 */ public int getNetworkID() { return _networkID; } diff --git a/router/java/src/net/i2p/router/networkdb/reseed/Reseeder.java b/router/java/src/net/i2p/router/networkdb/reseed/Reseeder.java index 9d2de9bb6c..f21e777afb 100644 --- a/router/java/src/net/i2p/router/networkdb/reseed/Reseeder.java +++ b/router/java/src/net/i2p/router/networkdb/reseed/Reseeder.java @@ -66,6 +66,8 @@ public class Reseeder { private static final boolean ENABLE_NON_SU3 = false; private static final int MIN_RI_WANTED = 100; private static final int MIN_RESEED_SERVERS = 2; + // network ID cross-check, proposal 147, as of 0.9.42 + private static final String NETID_PARAM = "?netid="; /** * NOTE - URLs that are in both the standard and SSL groups must use the same hostname, @@ -112,10 +114,8 @@ public class Reseeder { "https://reseed.i2p.net.in/" + ',' + // reseedi2pnetin_at_mail.i2p.crt // CA // Java 8+ only, TLS 1.2 only "https://i2p.novg.net/" + ',' + // igor_at_novg.net.crt // CA // Java 8+ only "https://i2pseed.creativecowpat.net:8443/" + ',' + // creativecowpat_at_mail.i2p.crt // i2pseed.creativecowpat.net.crt // Java 7+ - //"https://itoopie.atomike.ninja/" + ',' + // atomike_at_mail.i2p.crt // CA // Java 8+ only "https://reseed.onion.im/" + ',' + // lazygravy_at_mail.i2p // reseed.onion.im.crt // Java 8+ only "https://reseed.memcpy.io/" + ',' + // hottuna_at_mail.i2p.crt // CA // SNI required - //"https://reseed.atomike.ninja/" + ',' + // atomike_at_mail.i2p.crt // CA // SNI required, Java 8+ only "https://i2p.mooo.com/netDb/" + ',' + // bugme_at_mail.i2p.crt // i2p.mooo.com.crt "https://download.xxlspeed.com/" + ',' + // backup_at_mail.i2p.crt // CA // Java 8+ "https://netdb.i2p2.no/" + ',' + // meeh_at_mail.i2p.crt // CA // SNI required @@ -338,12 +338,19 @@ public class Reseeder { int total; if (_url != null) { String lc = _url.getPath().toLowerCase(Locale.US); - if (lc.endsWith(".su3")) - total = reseedSU3(_url, false); - else if (lc.endsWith(".zip")) + if (lc.endsWith(".su3")) { + URI uri; + try { + uri = new URI(_url.toString() + SU3_FILENAME + NETID_PARAM + _context.router().getNetworkID()); + } catch (URISyntaxException use) { + throw new IllegalArgumentException("Bad URL " + _url, use); + } + total = reseedSU3(uri, false); + } else if (lc.endsWith(".zip")) { total = reseedZip(_url, false); - else + } else { throw new IllegalArgumentException("Must end with .zip or .su3"); + } } else { total = reseed(false); } @@ -550,8 +557,6 @@ public class Reseeder { } if (!isSNISupported()) { try { - URLList.remove(new URI("https://i2p.manas.ca:8443/")); - URLList.remove(new URI("https://i2p-0.manas.ca:8443/")); URLList.remove(new URI("https://download.xxlspeed.com/")); URLList.remove(new URI("https://netdb.i2p2.no/")); } catch (URISyntaxException mue) {} @@ -573,6 +578,8 @@ public class Reseeder { * @return count of routerinfos successfully fetched */ private int reseed(List URLList, boolean echoStatus) { + // network ID cross-check, proposal 147, as of 0.9.42 + String query = NETID_PARAM + _context.router().getNetworkID(); int total = 0; int fetched_reseed_servers = 0; for (int i = 0; i < URLList.size() && _isRunning; i++) { @@ -584,7 +591,7 @@ public class Reseeder { int dl = 0; if (ENABLE_SU3) { try { - dl = reseedSU3(new URI(url.toString() + SU3_FILENAME), echoStatus); + dl = reseedSU3(new URI(url.toString() + SU3_FILENAME + query), echoStatus); } catch (URISyntaxException mue) {} } if (ENABLE_NON_SU3) { 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 3fe6b35cd4..3e2b739dcc 100644 --- a/router/java/src/net/i2p/router/transport/ntcp/InboundEstablishState.java +++ b/router/java/src/net/i2p/router/transport/ntcp/InboundEstablishState.java @@ -729,6 +729,20 @@ class InboundEstablishState extends EstablishBase implements NTCP2Payload.Payloa fail("Bad version: " + v); return; } + // network ID cross-check, proposal 147, as of 0.9.42 + v = options[0] & 0xff; + if (v != 0 && v != _context.router().getNetworkID()) { + InetAddress addr = _con.getChannel().socket().getInetAddress(); + if (addr != null) { + if (_log.shouldLog(Log.WARN)) + _log.warn("Dropping inbound connection from wrong network: " + addr); + byte[] ip = addr.getAddress(); + // So next time we will not accept the con from this IP + _context.blocklist().add(ip); + } + fail("Bad network id: " + v); + return; + } _padlen1 = (int) DataHelper.fromLong(options, 2, 2); _msg3p2len = (int) DataHelper.fromLong(options, 4, 2); long tsA = DataHelper.fromLong(options, 8, 4); diff --git a/router/java/src/net/i2p/router/transport/ntcp/OutboundNTCP2State.java b/router/java/src/net/i2p/router/transport/ntcp/OutboundNTCP2State.java index 8886faf722..56156804e2 100644 --- a/router/java/src/net/i2p/router/transport/ntcp/OutboundNTCP2State.java +++ b/router/java/src/net/i2p/router/transport/ntcp/OutboundNTCP2State.java @@ -191,6 +191,8 @@ class OutboundNTCP2State implements EstablishState { if (_log.shouldLog(Log.DEBUG)) _log.debug(this + "send X"); byte options[] = new byte[OPTIONS1_SIZE]; + // network ID cross-check, proposal 147 + options[0] = (byte) (_context.router().getNetworkID()); options[1] = NTCPTransport.NTCP2_INT_VERSION; int padlen1 = _context.random().nextInt(PADDING1_MAX); DataHelper.toLong(options, 2, 2, padlen1); diff --git a/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java b/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java index 200195f621..311216056f 100644 --- a/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java +++ b/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java @@ -1614,7 +1614,14 @@ class PacketBuilder { off += totalSize; System.arraycopy(iv, 0, data, off, UDPPacket.IV_SIZE); off += UDPPacket.IV_SIZE; - DataHelper.toLong(data, off, 2, totalSize /* ^ PROTOCOL_VERSION */ ); + // version is zero, unlikely to ever change + int plval = totalSize /* ^ PacketBuilder.PROTOCOL_VERSION */ ; + // network ID cross-check, proposal 147 + int netid = _context.router().getNetworkID(); + if (netid != 2) { + plval ^= (netid - 2) << 8; + } + DataHelper.toLong(data, off, 2, plval); int hmacLen = totalSize + UDPPacket.IV_SIZE + 2; //Hash hmac = _context.hmac().calculate(macKey, data, hmacOff, hmacLen); diff --git a/router/java/src/net/i2p/router/transport/udp/UDPPacket.java b/router/java/src/net/i2p/router/transport/udp/UDPPacket.java index 86c4055a21..fbb69ac337 100644 --- a/router/java/src/net/i2p/router/transport/udp/UDPPacket.java +++ b/router/java/src/net/i2p/router/transport/udp/UDPPacket.java @@ -242,7 +242,14 @@ class UDPPacket implements CDQEntry { off += payloadLength; System.arraycopy(_data, _packet.getOffset() + MAC_SIZE, _validateBuf, off, IV_SIZE); off += IV_SIZE; - DataHelper.toLong(_validateBuf, off, 2, payloadLength /* ^ PacketBuilder.PROTOCOL_VERSION */ ); + // version is zero, unlikely to ever change + int plval = payloadLength /* ^ PacketBuilder.PROTOCOL_VERSION */ ; + // network ID cross-check, proposal 147 + int netid = _context.router().getNetworkID(); + if (netid != 2) { + plval ^= (netid - 2) << 8; + } + DataHelper.toLong(_validateBuf, off, 2, plval); off += 2; eq = hmac.verify(macKey, _validateBuf, 0, off, _data, _packet.getOffset(), MAC_SIZE);