diff --git a/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java b/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java index e84709d93..a480d58ae 100644 --- a/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java +++ b/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java @@ -407,7 +407,7 @@ public class ProfileOrganizer { * */ public void selectFastPeers(int howMany, Set exclude, Set matches) { - selectFastPeers(howMany, exclude, matches, 0); + selectFastPeers(howMany, exclude, matches, 0, null); } /** @@ -421,17 +421,19 @@ public class ProfileOrganizer { * @param matches set to store the return value in * @param mask 0-4 Number of bytes to match to determine if peers in the same IP range should * not be in the same tunnel. 0 = disable check; 1 = /8; 2 = /16; 3 = /24; 4 = exact IP match + * @param ipSet in/out param, use for multiple calls, may be null only if mask is 0 + * @since 0.9.53 added ipSet param * */ - public void selectFastPeers(int howMany, Set exclude, Set matches, int mask) { + public void selectFastPeers(int howMany, Set exclude, Set matches, int mask, MaskedIPSet ipSet) { getReadLock(); try { - locked_selectPeers(_fastPeers, howMany, exclude, matches, mask); + locked_selectPeers(_fastPeers, howMany, exclude, matches, mask, ipSet); } finally { releaseReadLock(); } if (matches.size() < howMany) { if (_log.shouldLog(Log.INFO)) _log.info("selectFastPeers("+howMany+"), not enough fast (" + matches.size() + ") going on to highCap"); - selectHighCapacityPeers(howMany, exclude, matches, mask); + selectHighCapacityPeers(howMany, exclude, matches, mask, ipSet); } else { if (_log.shouldDebug()) _log.debug("selectFastPeers("+howMany+"), found enough fast (" + matches.size() + ")"); @@ -482,8 +484,12 @@ public class ProfileOrganizer { * 6: return only from group 2 * 7: return only from group 3 * + * @param mask 0-4 + * @param ipSet in/out param, use for multiple calls, may be null only if mask is 0 + * @since 0.9.53 added mask and ipSet params */ - public void selectFastPeers(int howMany, Set exclude, Set matches, SessionKey randomKey, Slice subTierMode) { + public void selectFastPeers(int howMany, Set exclude, Set matches, SessionKey randomKey, + Slice subTierMode, int mask, MaskedIPSet ipSet) { getReadLock(); try { if (subTierMode != Slice.SLICE_ALL) { @@ -492,14 +498,14 @@ public class ProfileOrganizer { subTierMode = Slice.SLICE_ALL; } if (subTierMode != Slice.SLICE_ALL) - locked_selectPeers(_fastPeers, howMany, exclude, matches, randomKey, subTierMode); + locked_selectPeers(_fastPeers, howMany, exclude, matches, randomKey, subTierMode, mask, ipSet); else - locked_selectPeers(_fastPeers, howMany, exclude, matches, 2); + locked_selectPeers(_fastPeers, howMany, exclude, matches, mask, ipSet); } finally { releaseReadLock(); } if (matches.size() < howMany) { if (_log.shouldLog(Log.INFO)) _log.info("selectFastPeers("+howMany+"), not enough fast (" + matches.size() + ") going on to highCap"); - selectHighCapacityPeers(howMany, exclude, matches, 2); + selectHighCapacityPeers(howMany, exclude, matches, mask, ipSet); } else { if (_log.shouldDebug()) _log.debug("selectFastPeers("+howMany+"), found enough fast (" + matches.size() + ")"); @@ -512,14 +518,16 @@ public class ProfileOrganizer { * */ public void selectHighCapacityPeers(int howMany, Set exclude, Set matches) { - selectHighCapacityPeers(howMany, exclude, matches, 0); + selectHighCapacityPeers(howMany, exclude, matches, 0, null); } /** * @param mask 0-4 Number of bytes to match to determine if peers in the same IP range should * not be in the same tunnel. 0 = disable check; 1 = /8; 2 = /16; 3 = /24; 4 = exact IP match + * @param ipSet in/out param, use for multiple calls, may be null only if mask is 0 + * @since 0.9.53 added ipSet param */ - public void selectHighCapacityPeers(int howMany, Set exclude, Set matches, int mask) { + public void selectHighCapacityPeers(int howMany, Set exclude, Set matches, int mask, MaskedIPSet ipSet) { getReadLock(); try { // we only use selectHighCapacityPeers when we are selecting for PURPOSE_TEST @@ -531,12 +539,12 @@ public class ProfileOrganizer { else exclude.addAll(_fastPeers.keySet()); */ - locked_selectPeers(_highCapacityPeers, howMany, exclude, matches, mask); + locked_selectPeers(_highCapacityPeers, howMany, exclude, matches, mask, ipSet); } finally { releaseReadLock(); } if (matches.size() < howMany) { if (_log.shouldLog(Log.INFO)) _log.info("selectHighCap("+howMany+"), not enough highcap (" + matches.size() + ") going on to ANFP2"); - selectActiveNotFailingPeers2(howMany, exclude, matches, mask); + selectActiveNotFailingPeers2(howMany, exclude, matches, mask, ipSet); } else { if (_log.shouldDebug()) _log.debug("selectHighCap("+howMany+"), found enough highCap (" + matches.size() + ")"); @@ -551,7 +559,7 @@ public class ProfileOrganizer { */ @Deprecated public void selectWellIntegratedPeers(int howMany, Set exclude, Set matches) { - selectWellIntegratedPeers(howMany, exclude, matches, 0); + selectWellIntegratedPeers(howMany, exclude, matches, 0, null); } /** @@ -559,18 +567,19 @@ public class ProfileOrganizer { * * @param mask 0-4 Number of bytes to match to determine if peers in the same IP range should * not be in the same tunnel. 0 = disable check; 1 = /8; 2 = /16; 3 = /24; 4 = exact IP match + * @since 0.9.53 added ipSet param * @deprecated unused */ @Deprecated - public void selectWellIntegratedPeers(int howMany, Set exclude, Set matches, int mask) { + public void selectWellIntegratedPeers(int howMany, Set exclude, Set matches, int mask, MaskedIPSet ipSet) { getReadLock(); try { - locked_selectPeers(_wellIntegratedPeers, howMany, exclude, matches, mask); + locked_selectPeers(_wellIntegratedPeers, howMany, exclude, matches, mask, ipSet); } finally { releaseReadLock(); } if (matches.size() < howMany) { if (_log.shouldLog(Log.INFO)) _log.info("selectWellIntegrated("+howMany+"), not enough integrated (" + matches.size() + ") going on to notFailing"); - selectNotFailingPeers(howMany, exclude, matches, mask); + selectNotFailingPeers(howMany, exclude, matches, mask, ipSet); } else { if (_log.shouldDebug()) _log.debug("selectWellIntegrated("+howMany+"), found enough well integrated (" + matches.size() + ")"); @@ -585,18 +594,20 @@ public class ProfileOrganizer { * */ public void selectNotFailingPeers(int howMany, Set exclude, Set matches) { - selectNotFailingPeers(howMany, exclude, matches, false, 0); + selectNotFailingPeers(howMany, exclude, matches, false, 0, null); } /** * @param mask ignored, should call locked_selectPeers, to be fixed + * @param ipSet ignored, should call locked_selectPeers, to be fixed + * @since 0.9.53 added ipSet param */ - public void selectNotFailingPeers(int howMany, Set exclude, Set matches, int mask) { - selectNotFailingPeers(howMany, exclude, matches, false, mask); + public void selectNotFailingPeers(int howMany, Set exclude, Set matches, int mask, MaskedIPSet ipSet) { + selectNotFailingPeers(howMany, exclude, matches, false, mask, ipSet); } public void selectNotFailingPeers(int howMany, Set exclude, Set matches, boolean onlyNotFailing) { - selectNotFailingPeers(howMany, exclude, matches, onlyNotFailing, 0); + selectNotFailingPeers(howMany, exclude, matches, onlyNotFailing, 0, null); } /** @@ -608,8 +619,11 @@ public class ProfileOrganizer { * @param matches set to store the matches in * @param onlyNotFailing if true, don't include any high capacity peers * @param mask ignored, should call locked_selectPeers, to be fixed + * @param ipSet ignored, should call locked_selectPeers, to be fixed + * @since 0.9.53 added ipSet param */ - public void selectNotFailingPeers(int howMany, Set exclude, Set matches, boolean onlyNotFailing, int mask) { + public void selectNotFailingPeers(int howMany, Set exclude, Set matches, boolean onlyNotFailing, + int mask, MaskedIPSet ipSet) { if (matches.size() < howMany) selectAllNotFailingPeers(howMany, exclude, matches, onlyNotFailing, mask); return; @@ -627,9 +641,30 @@ public class ProfileOrganizer { * be used when there is a good number of connected peers. * * @param exclude non-null, WARNING - side effect, all not-connected peers are added - * No mask parameter, to be fixed */ public void selectActiveNotFailingPeers(int howMany, Set exclude, Set matches) { + selectActiveNotFailingPeers(howMany, exclude, matches, 0, null); + } + + /** + * Return a set of Hashes for peers that are both not failing and we're actively + * talking with. + * + * We use commSystem().isEstablished(), not profile.getIsActive(), as the + * NTCP idle time is now shorter than the 5 minute getIsActive() threshold, + * and we're using this to try and limit connections. + * + * Caution, this does NOT cascade further to non-connected peers, so it should only + * be used when there is a good number of connected peers. + * + * @param exclude non-null, WARNING - side effect, all not-connected peers are added + * @param mask 0-4 Number of bytes to match to determine if peers in the same IP range should + * not be in the same tunnel. 0 = disable check; 1 = /8; 2 = /16; 3 = /24; 4 = exact IP match + * @param ipSet ignored, should call locked_selectPeers, to be fixed + * @param ipSet may be null only if mask is 0 + * @since 0.9.53 + */ + public void selectActiveNotFailingPeers(int howMany, Set exclude, Set matches, int mask, MaskedIPSet ipSet) { if (matches.size() < howMany) { Set connected = _context.commSystem().getEstablished(); getReadLock(); @@ -638,7 +673,7 @@ public class ProfileOrganizer { if (!connected.contains(peer)) exclude.add(peer); } - locked_selectPeers(_notFailingPeers, howMany, exclude, matches, 0); + locked_selectPeers(_notFailingPeers, howMany, exclude, matches, mask, ipSet); } finally { releaseReadLock(); } } } @@ -655,8 +690,10 @@ public class ProfileOrganizer { * * @param mask 0-4 Number of bytes to match to determine if peers in the same IP range should * not be in the same tunnel. 0 = disable check; 1 = /8; 2 = /16; 3 = /24; 4 = exact IP match + * @param ipSet in/out param, use for multiple calls, may be null only if mask is 0 + * @since 0.9.53 added ipSet param */ - private void selectActiveNotFailingPeers2(int howMany, Set exclude, Set matches, int mask) { + private void selectActiveNotFailingPeers2(int howMany, Set exclude, Set matches, int mask, MaskedIPSet ipSet) { if (matches.size() < howMany) { Set connected = _context.commSystem().getEstablished(); Map activePeers = new HashMap(connected.size()); @@ -667,13 +704,13 @@ public class ProfileOrganizer { if (prof != null) activePeers.put(peer, prof); } - locked_selectPeers(activePeers, howMany, exclude, matches, mask); + locked_selectPeers(activePeers, howMany, exclude, matches, mask, ipSet); } finally { releaseReadLock(); } } if (matches.size() < howMany) { if (_log.shouldLog(Log.INFO)) _log.info("selectANFP2("+howMany+"), not enough ANFP (" + matches.size() + ") going on to notFailing"); - selectNotFailingPeers(howMany, exclude, matches, mask); + selectNotFailingPeers(howMany, exclude, matches, mask, ipSet); } else { if (_log.shouldDebug()) _log.debug("selectANFP2("+howMany+"), found enough ANFP (" + matches.size() + ")"); @@ -690,7 +727,6 @@ public class ProfileOrganizer { /** * @param mask ignored, should call locked_selectPeers, to be fixed - * */ private void selectAllNotFailingPeers(int howMany, Set exclude, Set matches, boolean onlyNotFailing, int mask) { if (matches.size() < howMany) { @@ -1287,19 +1323,21 @@ public class ProfileOrganizer { * */ private void locked_selectPeers(Map peers, int howMany, Set toExclude, Set matches) { - locked_selectPeers(peers, howMany, toExclude, matches, 0); + locked_selectPeers(peers, howMany, toExclude, matches, 0, null); } /** - * - * As of 0.9.24, checks for a netdb family match as well, unless mask == 0. - * + * + * As of 0.9.24, checks for a netdb family match as well, unless mask == 0. + * * @param mask 0-4 Number of bytes to match to determine if peers in the same IP range should * not be in the same tunnel. 0 = disable check; 1 = /8; 2 = /16; 3 = /24; 4 = exact IP match + * @param ipSet may be null only if mask is 0 + * @since 0.9.53 added ipSet param */ - private void locked_selectPeers(Map peers, int howMany, Set toExclude, Set matches, int mask) { + private void locked_selectPeers(Map peers, int howMany, Set toExclude, Set matches, + int mask, MaskedIPSet ipSet) { List all = new ArrayList(peers.keySet()); - MaskedIPSet IPSet = new MaskedIPSet(16); // use RandomIterator to avoid shuffling the whole thing for (Iterator iter = new RandomIterator(all); (matches.size() < howMany) && iter.hasNext(); ) { Hash peer = iter.next(); @@ -1311,8 +1349,8 @@ public class ProfileOrganizer { continue; boolean ok = isSelectable(peer); if (ok) { - ok = mask <= 0 || notRestricted(peer, IPSet, mask); - if ((!ok) && _log.shouldLog(Log.WARN)) + ok = mask <= 0 || notRestricted(peer, ipSet, mask); + if ((!ok) && _log.shouldWarn()) _log.warn("IP restriction prevents " + peer + " from joining " + matches); } if (ok) @@ -1330,12 +1368,13 @@ public class ProfileOrganizer { * * @param mask is 1-4 (number of bytes to match) * @param IPMatches all IPs so far, modified by this routine + * @return true if ok, false if not */ - private boolean notRestricted(Hash peer, MaskedIPSet IPSet, int mask) { + private boolean notRestricted(Hash peer, MaskedIPSet ipSet, int mask) { Set peerIPs = new MaskedIPSet(_context, peer, mask); - if (IPSet.containsAny(peerIPs)) + if (!ipSet.isEmpty() && ipSet.containsAny(peerIPs)) return false; - IPSet.addAll(peerIPs); + ipSet.addAll(peerIPs); return true; } @@ -1350,9 +1389,13 @@ public class ProfileOrganizer { * 6: return only from group 2 * 7: return only from group 3 * + * @param mask is 1-4 (number of bytes to match) + * @param IPMatches all IPs so far, modified by this routine + * @since 0.9.53 added mask/ipSet params */ private void locked_selectPeers(Map peers, int howMany, Set toExclude, - Set matches, SessionKey randomKey, Slice subTierMode) { + Set matches, SessionKey randomKey, Slice subTierMode, + int mask, MaskedIPSet ipSet) { List all = new ArrayList(peers.keySet()); byte[] rk = randomKey.getData(); // we use the first half of the random key here, @@ -1373,6 +1416,11 @@ public class ProfileOrganizer { if ((subTier & subTierMode.mask) != subTierMode.val) continue; boolean ok = isSelectable(peer); + if (ok) { + ok = mask <= 0 || notRestricted(peer, ipSet, mask); + if ((!ok) && _log.shouldWarn()) + _log.warn("IP restriction prevents " + peer + " from joining " + matches); + } if (ok) matches.add(peer); else diff --git a/router/java/src/net/i2p/router/tunnel/pool/ClientPeerSelector.java b/router/java/src/net/i2p/router/tunnel/pool/ClientPeerSelector.java index cb8ffdef8..7a537c5e4 100644 --- a/router/java/src/net/i2p/router/tunnel/pool/ClientPeerSelector.java +++ b/router/java/src/net/i2p/router/tunnel/pool/ClientPeerSelector.java @@ -13,6 +13,7 @@ import net.i2p.router.TunnelInfo; import net.i2p.router.TunnelManagerFacade; import net.i2p.router.TunnelPoolSettings; import static net.i2p.router.peermanager.ProfileOrganizer.Slice.*; +import net.i2p.router.util.MaskedIPSet; /** * Pick peers randomly out of the fast pool, and put them into tunnels @@ -29,7 +30,7 @@ class ClientPeerSelector extends TunnelPeerSelector { * Returns ENDPOINT FIRST, GATEWAY LAST!!!! * In: us .. closest .. middle .. IBGW * Out: OBGW .. middle .. closest .. us - * + * * @return ordered list of Hash objects (one per peer) specifying what order * they should appear in a tunnel (ENDPOINT FIRST). This includes * the local router in the list. If there are no tunnels or peers @@ -45,7 +46,7 @@ class ClientPeerSelector extends TunnelPeerSelector { List rv; boolean isInbound = settings.isInbound(); - + if (length > 0) { // special cases boolean v6Only = isIPv6Only(); @@ -57,10 +58,12 @@ class ClientPeerSelector extends TunnelPeerSelector { !ctx.commSystem().haveInboundCapacity(95); boolean hiddenInbound = hidden && isInbound; boolean hiddenOutbound = hidden && !isInbound; + int ipRestriction = (ctx.getBooleanProperty("i2np.allowLocal") || length <= 1) ? 0 : settings.getIPRestriction(); + MaskedIPSet ipSet = ipRestriction > 0 ? new MaskedIPSet(16) : null; if (shouldSelectExplicit(settings)) return selectExplicit(settings, length); - + Set exclude = getExclude(isInbound, false); Set matches = new HashSet(length); if (length == 1) { @@ -70,6 +73,7 @@ class ClientPeerSelector extends TunnelPeerSelector { if (moreExclude != null) exclude.addAll(moreExclude); } + // 1-hop, IP restrictions not required here if (hiddenInbound) { // SANFP adds all not-connected to exclude, so make a copy Set SANFPExclude = new HashSet(exclude); @@ -77,7 +81,7 @@ class ClientPeerSelector extends TunnelPeerSelector { } if (matches.isEmpty()) { // ANFP does not fall back to non-connected - ctx.profileOrganizer().selectFastPeers(length, exclude, matches, 0); + ctx.profileOrganizer().selectFastPeers(length, exclude, matches); } matches.remove(ctx.routerHash()); rv = new ArrayList(matches); @@ -108,17 +112,17 @@ class ClientPeerSelector extends TunnelPeerSelector { lastHopExclude = exclude; } if (hiddenInbound) { - // IB closest hop + // IB closest hop if (log.shouldInfo()) log.info("CPS SANFP closest IB exclude " + lastHopExclude.size()); // SANFP adds all not-connected to exclude, so make a copy Set SANFPExclude = new HashSet(lastHopExclude); - ctx.profileOrganizer().selectActiveNotFailingPeers(1, SANFPExclude, matches); + ctx.profileOrganizer().selectActiveNotFailingPeers(1, SANFPExclude, matches, ipRestriction, ipSet); if (matches.isEmpty()) { if (log.shouldInfo()) log.info("CPS SFP closest IB exclude " + lastHopExclude.size()); // ANFP does not fall back to non-connected - ctx.profileOrganizer().selectFastPeers(1, lastHopExclude, matches, randomKey, length == 2 ? SLICE_0_1 : SLICE_0); + ctx.profileOrganizer().selectFastPeers(1, lastHopExclude, matches, randomKey, length == 2 ? SLICE_0_1 : SLICE_0, ipRestriction, ipSet); } } else if (hiddenOutbound) { // OBEP @@ -177,19 +181,19 @@ class ClientPeerSelector extends TunnelPeerSelector { log.info("CPS SANFP OBEP exclude " + lastHopExclude.size()); // SANFP adds all not-connected to exclude, so make a copy Set SANFPExclude = new HashSet(lastHopExclude); - ctx.profileOrganizer().selectActiveNotFailingPeers(1, SANFPExclude, matches); + ctx.profileOrganizer().selectActiveNotFailingPeers(1, SANFPExclude, matches, ipRestriction, ipSet); if (matches.isEmpty()) { // ANFP does not fall back to non-connected if (log.shouldInfo()) log.info("CPS SFP OBEP exclude " + lastHopExclude.size()); - ctx.profileOrganizer().selectFastPeers(1, lastHopExclude, matches, randomKey, length == 2 ? SLICE_0_1 : SLICE_0); + ctx.profileOrganizer().selectFastPeers(1, lastHopExclude, matches, randomKey, length == 2 ? SLICE_0_1 : SLICE_0, ipRestriction, ipSet); } } else { - ctx.profileOrganizer().selectFastPeers(1, lastHopExclude, matches, randomKey, length == 2 ? SLICE_0_1 : SLICE_0); + ctx.profileOrganizer().selectFastPeers(1, lastHopExclude, matches, randomKey, length == 2 ? SLICE_0_1 : SLICE_0, ipRestriction, ipSet); } } else { // TODO exclude IPv6-only at OBEP? Caught in checkTunnel() below - ctx.profileOrganizer().selectFastPeers(1, lastHopExclude, matches, randomKey, length == 2 ? SLICE_0_1 : SLICE_0); + ctx.profileOrganizer().selectFastPeers(1, lastHopExclude, matches, randomKey, length == 2 ? SLICE_0_1 : SLICE_0, ipRestriction, ipSet); } matches.remove(ctx.routerHash()); @@ -199,7 +203,7 @@ class ClientPeerSelector extends TunnelPeerSelector { if (length > 2) { // middle hop(s) // group 2 or 3 - ctx.profileOrganizer().selectFastPeers(length - 2, exclude, matches, randomKey, SLICE_2_3); + ctx.profileOrganizer().selectFastPeers(length - 2, exclude, matches, randomKey, SLICE_2_3, ipRestriction, ipSet); matches.remove(ctx.routerHash()); if (matches.size() > 1) { // order the middle peers for tunnels >= 4 hops @@ -225,14 +229,14 @@ class ClientPeerSelector extends TunnelPeerSelector { } } // TODO exclude IPv6-only at IBGW? Caught in checkTunnel() below - ctx.profileOrganizer().selectFastPeers(1, exclude, matches, randomKey, length == 2 ? SLICE_2_3 : SLICE_1); + ctx.profileOrganizer().selectFastPeers(1, exclude, matches, randomKey, length == 2 ? SLICE_2_3 : SLICE_1, ipRestriction, ipSet); matches.remove(ctx.routerHash()); rv.addAll(matches); } } else { rv = new ArrayList(1); } - + //if (length != rv.size() && log.shouldWarn()) // log.warn("CPS requested " + length + " got " + rv.size() + ": " + DataHelper.toString(rv)); //else if (log.shouldDebug()) diff --git a/router/java/src/net/i2p/router/tunnel/pool/ExploratoryPeerSelector.java b/router/java/src/net/i2p/router/tunnel/pool/ExploratoryPeerSelector.java index 866a1708b..fbff10922 100644 --- a/router/java/src/net/i2p/router/tunnel/pool/ExploratoryPeerSelector.java +++ b/router/java/src/net/i2p/router/tunnel/pool/ExploratoryPeerSelector.java @@ -11,6 +11,7 @@ import net.i2p.router.RouterContext; import net.i2p.router.TunnelInfo; import net.i2p.router.TunnelManagerFacade; import net.i2p.router.TunnelPoolSettings; +import net.i2p.router.util.MaskedIPSet; import net.i2p.stat.Rate; import net.i2p.stat.RateStat; import net.i2p.util.Log; @@ -31,7 +32,7 @@ class ExploratoryPeerSelector extends TunnelPeerSelector { * Returns ENDPOINT FIRST, GATEWAY LAST!!!! * In: us .. closest .. middle .. IBGW * Out: OBGW .. middle .. closest .. us - * + * * @return ordered list of Hash objects (one per peer) specifying what order * they should appear in a tunnel (ENDPOINT FIRST). This includes * the local router in the list. If there are no tunnels or peers @@ -40,19 +41,19 @@ class ExploratoryPeerSelector extends TunnelPeerSelector { */ public List selectPeers(TunnelPoolSettings settings) { int length = getLength(settings); - if (length < 0) { + if (length < 0) { if (log.shouldLog(Log.DEBUG)) log.debug("Length requested is zero: " + settings); return null; } - + //if (false && shouldSelectExplicit(settings)) { // List rv = selectExplicit(settings, length); // if (l.shouldLog(Log.DEBUG)) // l.debug("Explicit peers selected: " + rv); // return rv; //} - + boolean isInbound = settings.isInbound(); Set exclude = getExclude(isInbound, true); exclude.add(ctx.routerHash()); @@ -70,6 +71,8 @@ class ExploratoryPeerSelector extends TunnelPeerSelector { boolean hiddenInbound = hidden && isInbound; boolean hiddenOutbound = hidden && !isInbound; boolean lowOutbound = nonzero && !isInbound && !ctx.commSystem().haveHighOutboundCapacity(); + int ipRestriction = (ctx.getBooleanProperty("i2np.allowLocal") || length <= 1) ? 0 : settings.getIPRestriction(); + MaskedIPSet ipSet = ipRestriction > 0 ? new MaskedIPSet(16) : null; // closest-hop restrictions @@ -99,21 +102,21 @@ class ExploratoryPeerSelector extends TunnelPeerSelector { log.info("EPS SANFP closest " + (isInbound ? "IB" : "OB") + " exclude " + closestExclude.size()); // SANFP adds all not-connected to exclude, so make a copy Set SANFPExclude = new HashSet(closestExclude); - ctx.profileOrganizer().selectActiveNotFailingPeers(1, SANFPExclude, closest); + ctx.profileOrganizer().selectActiveNotFailingPeers(1, SANFPExclude, closest, ipRestriction, ipSet); if (closest.isEmpty()) { // ANFP does not fall back to non-connected if (log.shouldLog(Log.INFO)) log.info("EPS SFP closest " + (isInbound ? "IB" : "OB") + " exclude " + closestExclude.size()); - ctx.profileOrganizer().selectFastPeers(1, closestExclude, closest); + ctx.profileOrganizer().selectFastPeers(1, closestExclude, closest, ipRestriction, ipSet); } } else if (exploreHighCap) { if (log.shouldLog(Log.INFO)) log.info("EPS SHCP closest " + (isInbound ? "IB" : "OB") + " exclude " + closestExclude.size()); - ctx.profileOrganizer().selectHighCapacityPeers(1, closestExclude, closest); + ctx.profileOrganizer().selectHighCapacityPeers(1, closestExclude, closest, ipRestriction, ipSet); } else { if (log.shouldLog(Log.INFO)) log.info("EPS SNFP closest " + (isInbound ? "IB" : "OB") + " exclude " + closestExclude.size()); - ctx.profileOrganizer().selectNotFailingPeers(1, closestExclude, closest, false); + ctx.profileOrganizer().selectNotFailingPeers(1, closestExclude, closest, false, ipRestriction, ipSet); } if (!closest.isEmpty()) { closestHop = closest.iterator().next(); @@ -155,12 +158,12 @@ class ExploratoryPeerSelector extends TunnelPeerSelector { log.info("EPS SANFP furthest OB exclude " + exclude.size()); // ANFP adds all not-connected to exclude, so make a copy Set SANFPExclude = new HashSet(exclude); - ctx.profileOrganizer().selectActiveNotFailingPeers(1, SANFPExclude, furthest); + ctx.profileOrganizer().selectActiveNotFailingPeers(1, SANFPExclude, furthest, ipRestriction, ipSet); if (furthest.isEmpty()) { // ANFP does not fall back to non-connected if (log.shouldLog(Log.INFO)) log.info("EPS SFP furthest OB exclude " + exclude.size()); - ctx.profileOrganizer().selectFastPeers(1, exclude, furthest); + ctx.profileOrganizer().selectFastPeers(1, exclude, furthest, ipRestriction, ipSet); } if (!furthest.isEmpty()) { furthestHop = furthest.iterator().next(); @@ -179,13 +182,10 @@ class ExploratoryPeerSelector extends TunnelPeerSelector { HashSet matches = new HashSet(length); if (length > 0) { - // - // We don't honor IP Restriction here, to be fixed - // if (exploreHighCap) { if (log.shouldLog(Log.INFO)) log.info("EPS SHCP " + length + (isInbound ? " IB" : " OB") + " exclude " + exclude.size()); - ctx.profileOrganizer().selectHighCapacityPeers(length, exclude, matches); + ctx.profileOrganizer().selectHighCapacityPeers(length, exclude, matches, ipRestriction, ipSet); } else { // As of 0.9.23, we include a max of 2 not failing peers, // to improve build success on 3-hop tunnels. @@ -194,7 +194,7 @@ class ExploratoryPeerSelector extends TunnelPeerSelector { ctx.profileOrganizer().selectHighCapacityPeers(length - 2, exclude, matches); if (log.shouldLog(Log.INFO)) log.info("EPS SNFP " + length + (isInbound ? " IB" : " OB") + " exclude " + exclude.size()); - ctx.profileOrganizer().selectNotFailingPeers(length, exclude, matches, false); + ctx.profileOrganizer().selectNotFailingPeers(length, exclude, matches, false, ipRestriction, ipSet); } matches.remove(ctx.routerHash()); } @@ -231,7 +231,7 @@ class ExploratoryPeerSelector extends TunnelPeerSelector { } return rv; } - + private static final int MIN_NONFAILING_PCT = 15; private static final int MIN_ACTIVE_PEERS_STARTUP = 6; private static final int MIN_ACTIVE_PEERS = 12; @@ -290,7 +290,7 @@ class ExploratoryPeerSelector extends TunnelPeerSelector { } return (failPct >= ctx.random().nextInt(100)); } - + /** * We should really use the difference between the exploratory fail rate * and the high capacity fail rate - but we don't have a stat for high cap, @@ -326,11 +326,11 @@ class ExploratoryPeerSelector extends TunnelPeerSelector { double pct = (double)(reject + timeout) / (accept + reject + timeout); return (int)(100 * pct); } - + /** Use current + last to get more recent and smoother data */ private int getEvents(String stat, long period) { RateStat rs = ctx.statManager().getRate(stat); - if (rs == null) + if (rs == null) return 0; Rate r = rs.getRate(period); if (r == null) diff --git a/router/java/src/net/i2p/router/tunnel/pool/TunnelPeerSelector.java b/router/java/src/net/i2p/router/tunnel/pool/TunnelPeerSelector.java index 76519d8f0..969acde50 100644 --- a/router/java/src/net/i2p/router/tunnel/pool/TunnelPeerSelector.java +++ b/router/java/src/net/i2p/router/tunnel/pool/TunnelPeerSelector.java @@ -32,7 +32,7 @@ import net.i2p.util.SystemVersion; import net.i2p.util.VersionComparator; /** - * Coordinate the selection of peers to go into a tunnel for one particular + * Coordinate the selection of peers to go into a tunnel for one particular * pool. * */ @@ -45,8 +45,8 @@ public abstract class TunnelPeerSelector extends ConnectChecker { } /** - * Which peers should go into the next tunnel for the given settings? - * + * Which peers should go into the next tunnel for the given settings? + * * @return ordered list of Hash objects (one per peer) specifying what order * they should appear in a tunnel (ENDPOINT FIRST). This includes * the local router in the list. If there are no tunnels or peers @@ -54,7 +54,7 @@ public abstract class TunnelPeerSelector extends ConnectChecker { * return null. */ public abstract List selectPeers(TunnelPoolSettings settings); - + /** * @return randomized number of hops 0-7, not including ourselves */ @@ -81,7 +81,7 @@ public abstract class TunnelPeerSelector extends ConnectChecker { else if (length > 7) // as documented in tunnel.html length = 7; /* - if ( (ctx.tunnelManager().getOutboundTunnelCount() <= 0) || + if ( (ctx.tunnelManager().getOutboundTunnelCount() <= 0) || (ctx.tunnelManager().getFreeTunnelCount() <= 0) ) { Log log = ctx.logManager().getLog(TunnelPeerSelector.class); // no tunnels to build tunnels with @@ -98,7 +98,7 @@ public abstract class TunnelPeerSelector extends ConnectChecker { */ return length; } - + /** * For debugging, also possibly for restricted routes? * Needs analysis and testing @@ -118,7 +118,7 @@ public abstract class TunnelPeerSelector extends ConnectChecker { return true; return false; } - + /** * For debugging, also possibly for restricted routes? * Needs analysis and testing @@ -128,10 +128,10 @@ public abstract class TunnelPeerSelector extends ConnectChecker { String peers = null; Properties opts = settings.getUnknownOptions(); peers = opts.getProperty("explicitPeers"); - + if (peers == null) peers = ctx.getProperty("explicitPeers"); - + List rv = new ArrayList(); StringTokenizer tok = new StringTokenizer(peers, ","); while (tok.hasMoreTokens()) { @@ -139,7 +139,7 @@ public abstract class TunnelPeerSelector extends ConnectChecker { Hash peer = new Hash(); try { peer.fromBase64(peerStr); - + if (ctx.profileOrganizer().isSelectable(peer)) { rv.add(peer); } else { @@ -150,14 +150,14 @@ public abstract class TunnelPeerSelector extends ConnectChecker { log.error("Explicit peer is improperly formatted (" + peerStr + ")", dfe); } } - + int sz = rv.size(); if (sz == 0) { log.logAlways(Log.WARN, "No valid explicit peers found, building zero hop"); } else if (sz > 1) { Collections.shuffle(rv, ctx.random()); } - + while (rv.size() > length) { rv.remove(0); } @@ -166,11 +166,12 @@ public abstract class TunnelPeerSelector extends ConnectChecker { Set exclude = getExclude(settings.isInbound(), settings.isExploratory()); exclude.addAll(rv); Set matches = new HashSet(more); - ctx.profileOrganizer().selectFastPeers(more, exclude, matches, 0); + // don't bother with IP restrictions here + ctx.profileOrganizer().selectFastPeers(more, exclude, matches); rv.addAll(matches); Collections.shuffle(rv, ctx.random()); } - + if (log.shouldLog(Log.INFO)) { StringBuilder buf = new StringBuilder(); if (settings.getDestinationNickname() != null) @@ -187,16 +188,16 @@ public abstract class TunnelPeerSelector extends ConnectChecker { buf.append(", out of ").append(sz).append(" (not including self)"); log.info(buf.toString()); } - + if (settings.isInbound()) rv.add(0, ctx.routerHash()); else rv.add(ctx.routerHash()); - + return rv; } - - /** + + /** * Pick peers that we want to avoid */ public Set getExclude(boolean isInbound, boolean isExploratory) { @@ -267,7 +268,7 @@ public abstract class TunnelPeerSelector extends ConnectChecker { peers.add(peer.getIdentity().calculateHash()); // otherwise, it contains flags we aren't trying to focus on, // so don't exclude it based on published capacity - + if (filterUptime(ctx, isInbound, isExploratory)) { Properties opts = peer.getOptions(); if (opts != null) { @@ -298,7 +299,7 @@ public abstract class TunnelPeerSelector extends ConnectChecker { peers.add(peer.getIdentity().calculateHash()); continue; } - + long infoAge = ctx.clock().now() - peer.getPublished(); if (infoAge < 0) { infoAge = 0; @@ -387,8 +388,8 @@ public abstract class TunnelPeerSelector extends ConnectChecker { return false; return canConnect(ANY_V4, ri); } - - /** + + /** * Pick peers that we want to avoid for the first OB hop or last IB hop. * There's several cases of importance: *
  1. Inbound and we are hidden - @@ -452,19 +453,19 @@ public abstract class TunnelPeerSelector extends ConnectChecker { } return rv; } - + /** warning, this is also called by ProfileOrganizer.isSelectable() */ public static boolean shouldExclude(RouterContext ctx, RouterInfo peer) { return shouldExclude(peer, getExcludeCaps(ctx)); } - + /** * @return non-null, possibly empty */ private static String getExcludeCaps(RouterContext ctx) { return ctx.getProperty("router.excludePeerCaps", DEFAULT_EXCLUDE_CAPS); } - + /** NTCP2 */ private static final String MIN_VERSION = "0.9.36"; @@ -555,18 +556,18 @@ public abstract class TunnelPeerSelector extends ConnectChecker { ******/ return false; } - + private static final String PROP_OUTBOUND_EXPLORATORY_EXCLUDE_UNREACHABLE = "router.outboundExploratoryExcludeUnreachable"; private static final String PROP_OUTBOUND_CLIENT_EXCLUDE_UNREACHABLE = "router.outboundClientExcludeUnreachable"; private static final String PROP_INBOUND_EXPLORATORY_EXCLUDE_UNREACHABLE = "router.inboundExploratoryExcludeUnreachable"; private static final String PROP_INBOUND_CLIENT_EXCLUDE_UNREACHABLE = "router.inboundClientExcludeUnreachable"; - + private static final boolean DEFAULT_OUTBOUND_EXPLORATORY_EXCLUDE_UNREACHABLE = false; private static final boolean DEFAULT_OUTBOUND_CLIENT_EXCLUDE_UNREACHABLE = false; // see comments at getExclude() above private static final boolean DEFAULT_INBOUND_EXPLORATORY_EXCLUDE_UNREACHABLE = false; private static final boolean DEFAULT_INBOUND_CLIENT_EXCLUDE_UNREACHABLE = false; - + /** * do we want to skip unreachable peers? * @return true if yes @@ -587,18 +588,18 @@ public abstract class TunnelPeerSelector extends ConnectChecker { if (ctx.router().isHidden()) return true; return ctx.getProperty(PROP_INBOUND_CLIENT_EXCLUDE_UNREACHABLE, DEFAULT_INBOUND_CLIENT_EXCLUDE_UNREACHABLE); - } else { + } else { return ctx.getProperty(PROP_OUTBOUND_CLIENT_EXCLUDE_UNREACHABLE, DEFAULT_OUTBOUND_CLIENT_EXCLUDE_UNREACHABLE); } } } - + private static final String PROP_OUTBOUND_EXPLORATORY_EXCLUDE_SLOW = "router.outboundExploratoryExcludeSlow"; private static final String PROP_OUTBOUND_CLIENT_EXCLUDE_SLOW = "router.outboundClientExcludeSlow"; private static final String PROP_INBOUND_EXPLORATORY_EXCLUDE_SLOW = "router.inboundExploratoryExcludeSlow"; private static final String PROP_INBOUND_CLIENT_EXCLUDE_SLOW = "router.inboundClientExcludeSlow"; - + /** * do we want to skip peers that are slow? * @return true unless configured otherwise @@ -612,18 +613,18 @@ public abstract class TunnelPeerSelector extends ConnectChecker { } else { if (isInbound) return ctx.getProperty(PROP_INBOUND_CLIENT_EXCLUDE_SLOW, true); - else + else return ctx.getProperty(PROP_OUTBOUND_CLIENT_EXCLUDE_SLOW, true); - } + } } - + /**** private static final String PROP_OUTBOUND_EXPLORATORY_EXCLUDE_UPTIME = "router.outboundExploratoryExcludeUptime"; private static final String PROP_OUTBOUND_CLIENT_EXCLUDE_UPTIME = "router.outboundClientExcludeUptime"; private static final String PROP_INBOUND_EXPLORATORY_EXCLUDE_UPTIME = "router.inboundExploratoryExcludeUptime"; private static final String PROP_INBOUND_CLIENT_EXCLUDE_UPTIME = "router.inboundClientExcludeUptime"; ****/ - + /** * do we want to skip peers who haven't been up for long? * @return true unless configured otherwise @@ -638,7 +639,7 @@ public abstract class TunnelPeerSelector extends ConnectChecker { } else { if (isInbound) return ctx.getProperty(PROP_INBOUND_CLIENT_EXCLUDE_UPTIME, true); - else + else return ctx.getProperty(PROP_OUTBOUND_CLIENT_EXCLUDE_UPTIME, true); } }