SSU: MTU fixes for IPv6 and SSU2

Fix setting local IPv6 MTU when firewalled
Fix publishing MTU when firewalled or hidden
Save local MTU when changing addresses, not when publishing
Add SSU2 MTU methods (no mod 16 required)
Allow MTU up to 1500 for SSU2 transport style
Disable SSU2 at startup if local MTU too low
This commit is contained in:
zzz
2022-06-25 13:14:59 -04:00
parent 26cffabf86
commit 3c7659277d
5 changed files with 96 additions and 24 deletions

View File

@@ -18,7 +18,7 @@ public class RouterVersion {
/** deprecated */
public final static String ID = "Git";
public final static String VERSION = CoreVersion.VERSION;
public final static long BUILD = 8;
public final static long BUILD = 9;
/** for example "-test" */
public final static String EXTRA = "";

View File

@@ -34,11 +34,15 @@ public class MTU {
* altough we could perhaps just look for the first non-loopback address.
* But the MTU of the default route probably isn't relevant.
*
* For SSU2 MTU, values lower than PeerState2.MIN_MTU may be returned,
* so the caller can determine if SSU2 should be supported.
*
* @param ia null ok
* @param isSSU2 if true, calculate SSU2 MTU
* @return 0 if Java 5, or if not bound to an address;
* limited to range MIN_MTU to LARGE_MTU.
* limited to range MIN_MTU to LARGE_MTU for SSU 1.
*/
public static int getMTU(InetAddress ia) {
public static int getMTU(InetAddress ia, boolean isSSU2) {
if (ia == null || !hasMTU)
return 0;
Enumeration<NetworkInterface> ifcs;
@@ -93,6 +97,8 @@ public class MTU {
ip[2] == 0x04 && ip[3] == 0x70)
return 1472;
}
if (isSSU2)
return Math.min(mtu, PeerState2.MAX_MTU);
return rectify(isIPv6, mtu);
} catch (SocketException se) {
// ignore
@@ -159,7 +165,8 @@ public class MTU {
for(Enumeration<InetAddress> addrs = ifc.getInetAddresses(); addrs.hasMoreElements();) {
InetAddress addr = addrs.nextElement();
System.out.println("MTU for " + addr.getHostAddress() + " is " + ifc.getMTU() +
" I2P MTU is " + getMTU(addr));
"; I2P MTU is " + getMTU(addr, false) +
"; SSU2 MTU is " + getMTU(addr, true));
}
}
}

View File

@@ -405,9 +405,9 @@ public class PeerState {
_mtu = PeerState2.MIN_MTU;
_mtuReceive = PeerState2.MIN_MTU;
if (_remoteIP.length == 4) {
_largeMTU = transport.getMTU(false);
_largeMTU = transport.getSSU2MTU(false);
} else {
_largeMTU = transport.getMTU(true);
_largeMTU = transport.getSSU2MTU(true);
}
_minMTU = PeerState2.MIN_MTU;
// RFC 5681 sec. 3.1

View File

@@ -100,6 +100,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
private final SSUHMACGenerator _hmac;
private int _mtu;
private int _mtu_ipv6;
private int _mtu_ssu2;
private int _mtu_ssu2_ipv6;
private boolean _mismatchLogged;
private final int _networkID;
@@ -389,7 +391,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
_context.statManager().createRateStat("udp.dropPeerDroplist", "How many peers currently have their packets dropped outright when a new peer is added to the list?", "udp", RATES);
_context.statManager().createRateStat("udp.dropPeerConsecutiveFailures", "How many consecutive failed sends to a peer did we attempt before giving up and reestablishing a new session (lifetime is inactivity perood)", "udp", RATES);
_context.statManager().createRateStat("udp.inboundIPv4Conn", "Inbound IPv4 UDP Connection", "udp", RATES);
_context.statManager().createRateStat("udp.inboundIPv6Conn", "Inbound IPv4 UDP Connection", "udp", RATES);
_context.statManager().createRateStat("udp.inboundIPv6Conn", "Inbound IPv6 UDP Connection", "udp", RATES);
// following are for PacketBuider
//_context.statManager().createRateStat("udp.packetAuthTime", "How long it takes to encrypt and MAC a packet for sending", "udp", RATES);
//_context.statManager().createRateStat("udp.packetAuthTimeSlow", "How long it takes to encrypt and MAC a packet for sending (when its slow)", "udp", RATES);
@@ -398,7 +400,23 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
// SSU2 key and IV generation if required
_enableSSU1 = dh != null;
_enableSSU2 = xdh != null;
boolean enableSSU2 = xdh != null;
if (enableSSU2) {
// if any ipv4 address is lower than 1280 MTU, disable
Set<String> ipset = Addresses.getAddresses(true, false, false);
for (String ips : ipset) {
try {
InetAddress addr = InetAddress.getByName(ips);
int mtu = MTU.getMTU(addr, true);
if (mtu > 0 && mtu < PeerState2.MIN_MTU) {
_log.logAlways(Log.WARN, "Disabling SSU2, MTU is " + mtu + ", minimum is " + PeerState2.MIN_MTU);
enableSSU2 = false;
break;
}
} catch (UnknownHostException e) {}
}
}
_enableSSU2 = enableSSU2;
byte[] ikey = null;
String b64Ikey = null;
if (_enableSSU2) {
@@ -935,6 +953,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
}
// his address is SSU2
// do not validate the s/i b64, we will just catch it later
// todo check mtu
return SSU2_INT_VERSION;
}
@@ -1059,6 +1078,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
* @since 0.9.2
*/
private int setMTU(InetAddress addr) {
// TODO remove config
String p = _context.getProperty(PROP_DEFAULT_MTU);
if (p != null) {
try {
@@ -1068,7 +1088,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
return _mtu;
} catch (NumberFormatException nfe) {}
}
int mtu = MTU.getMTU(addr);
int mtu = MTU.getMTU(addr, false);
if (addr != null && addr.getAddress().length == 16) {
if (mtu <= 0)
mtu = PeerState.MIN_IPV6_MTU;
@@ -1078,6 +1098,18 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
mtu = PeerState.LARGE_MTU;
_mtu = mtu;
}
if (_enableSSU2) {
int mtussu2 = MTU.getMTU(addr, true);
if (mtussu2 < PeerState2.MIN_MTU) {
_log.logAlways(Log.WARN, "Low MTU " + mtussu2 + " for interface " + addr + ", consider disabling SSU2");
mtussu2 = PeerState2.MIN_MTU;
}
if (addr != null && addr.getAddress().length == 16) {
_mtu_ssu2_ipv6 = mtussu2;
} else {
_mtu_ssu2 = mtussu2;
}
}
return mtu;
}
@@ -1092,6 +1124,17 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
return ipv6 ? _mtu_ipv6 : _mtu;
}
/**
* The SSU2 MTU for the socket interface.
* To be used as the "large" MTU.
*
* @return limited to range PeerState2.MIN_MTU to PeerState2.LARGE_MTU, or 0 if unavailable
* @since 0.9.55
*/
public int getSSU2MTU(boolean ipv6) {
return ipv6 ? _mtu_ssu2_ipv6 : _mtu_ssu2;
}
/**
* If we have received an inbound connection in the last 2 minutes, don't allow
* our IP to change.
@@ -1156,6 +1199,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
try {
InetAddress ia = InetAddress.getByAddress(ip);
saveLocalAddress(ia);
setMTU(ia);
} catch (UnknownHostException uhe) {}
}
return;
@@ -2716,14 +2760,21 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
}
// As of 0.9.50, make an address with only 4/6 caps
String caps;
int mtu;
TransportUtil.IPv6Config config = getIPv6Config();
if (config == IPV6_ONLY)
if (config == IPV6_ONLY) {
caps = CAP_IPV6;
else if (config != IPV6_DISABLED && hasIPv6Address())
mtu = getMTU(true);
} else if (config != IPV6_DISABLED && hasIPv6Address()) {
caps = CAP_IPV4_IPV6;
else
mtu = getMTU(true);
} else {
caps = CAP_IPV4;
mtu = getMTU(false);
}
options.setProperty(UDPAddress.PROP_CAPACITY, caps);
if (mtu != PeerState.LARGE_MTU && mtu > 0)
options.setProperty(UDPAddress.PROP_MTU, Integer.toString(mtu));
if (_enableSSU2)
addSSU2Options(options);
RouterAddress current = getCurrentAddress(false);
@@ -2791,18 +2842,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
options.setProperty(UDPAddress.PROP_CAPACITY, caps);
// MTU since 0.9.2
int mtu;
if (host == null) {
mtu = _mtu;
} else {
try {
InetAddress ia = InetAddress.getByName(host);
mtu = setMTU(ia);
} catch (UnknownHostException uhe) {
mtu = _mtu;
}
}
if (mtu != PeerState.LARGE_MTU)
int mtu = getMTU(isIPv6);
if (mtu != PeerState.LARGE_MTU && mtu > 0)
options.setProperty(UDPAddress.PROP_MTU, Integer.toString(mtu));
if (directIncluded || introducersIncluded) {
@@ -2858,6 +2899,9 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
// Also make an empty "6" address
OrderedProperties opts = new OrderedProperties();
opts.setProperty(UDPAddress.PROP_CAPACITY, CAP_IPV6);
mtu = getMTU(true);
if (mtu > 0)
opts.setProperty(UDPAddress.PROP_MTU, Integer.toString(mtu));
if (_enableSSU2)
addSSU2Options(opts);
RouterAddress addr6 = new RouterAddress(STYLE, opts, SSU_OUTBOUND_COST);
@@ -2891,6 +2935,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
// Make an empty "4" or "6" address
OrderedProperties opts = new OrderedProperties();
opts.setProperty(UDPAddress.PROP_CAPACITY, isIPv6 ? CAP_IPV6 : CAP_IPV4);
if (mtu != PeerState.LARGE_MTU && mtu > 0)
opts.setProperty(UDPAddress.PROP_MTU, Integer.toString(mtu));
if (_enableSSU2)
addSSU2Options(opts);
RouterAddress addr = new RouterAddress(STYLE, opts, SSU_OUTBOUND_COST);
@@ -2910,6 +2956,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
* we don't put them in the real, published RouterAddress anymore
* if we are firewalled.
*
* Side effect: Sets our MTU
*
* Caller must sync on _rebuildLock
*
* @since 0.9.18
@@ -2919,6 +2967,10 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
_currentOurV6Address = ra;
else
_currentOurV4Address = ra;
try {
InetAddress ia = InetAddress.getByName(ra.getHost());
setMTU(ia);
} catch (UnknownHostException uhe) {}
}
/**