Compare commits

...

2 Commits

Author SHA1 Message Date
zzz
d3af2af369 Tunnels: Restore support for IP restriction in client tunnels
Removed in May 2011 when we added fast tier slices
Add support in exploratory tunnels
Create MaskedIPSet in peer selectors, pass to ProfileOrganizer.selectXXX() for each call.
Not required for one-hop tunnels.
Disable for test networks (i2np.allowLocal)
Reported by 'vulnerability_reports' http://zzz.i2p/topics/3215
Briefly tested, to be reviewed and fully tested
2021-12-14 08:31:25 -05:00
idk
257c0aff42 Add IP restriction based exclusions to ClientPeerSelection, TunnelPeerSelector. I think this might be a naive way to do this, there's a lot of checking to do. This version excludes peers if any of their addresses are too close to any of our addresses. 2021-12-11 18:25:28 -05:00
4 changed files with 156 additions and 104 deletions

View File

@ -407,7 +407,7 @@ public class ProfileOrganizer {
* *
*/ */
public void selectFastPeers(int howMany, Set<Hash> exclude, Set<Hash> matches) { public void selectFastPeers(int howMany, Set<Hash> exclude, Set<Hash> 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 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 * @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 * 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<Hash> exclude, Set<Hash> matches, int mask) { public void selectFastPeers(int howMany, Set<Hash> exclude, Set<Hash> matches, int mask, MaskedIPSet ipSet) {
getReadLock(); getReadLock();
try { try {
locked_selectPeers(_fastPeers, howMany, exclude, matches, mask); locked_selectPeers(_fastPeers, howMany, exclude, matches, mask, ipSet);
} finally { releaseReadLock(); } } finally { releaseReadLock(); }
if (matches.size() < howMany) { if (matches.size() < howMany) {
if (_log.shouldLog(Log.INFO)) if (_log.shouldLog(Log.INFO))
_log.info("selectFastPeers("+howMany+"), not enough fast (" + matches.size() + ") going on to highCap"); _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 { } else {
if (_log.shouldDebug()) if (_log.shouldDebug())
_log.debug("selectFastPeers("+howMany+"), found enough fast (" + matches.size() + ")"); _log.debug("selectFastPeers("+howMany+"), found enough fast (" + matches.size() + ")");
@ -482,8 +484,12 @@ public class ProfileOrganizer {
* 6: return only from group 2 * 6: return only from group 2
* 7: return only from group 3 * 7: return only from group 3
*</pre> *</pre>
* @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<Hash> exclude, Set<Hash> matches, SessionKey randomKey, Slice subTierMode) { public void selectFastPeers(int howMany, Set<Hash> exclude, Set<Hash> matches, SessionKey randomKey,
Slice subTierMode, int mask, MaskedIPSet ipSet) {
getReadLock(); getReadLock();
try { try {
if (subTierMode != Slice.SLICE_ALL) { if (subTierMode != Slice.SLICE_ALL) {
@ -492,14 +498,14 @@ public class ProfileOrganizer {
subTierMode = Slice.SLICE_ALL; subTierMode = Slice.SLICE_ALL;
} }
if (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 else
locked_selectPeers(_fastPeers, howMany, exclude, matches, 2); locked_selectPeers(_fastPeers, howMany, exclude, matches, mask, ipSet);
} finally { releaseReadLock(); } } finally { releaseReadLock(); }
if (matches.size() < howMany) { if (matches.size() < howMany) {
if (_log.shouldLog(Log.INFO)) if (_log.shouldLog(Log.INFO))
_log.info("selectFastPeers("+howMany+"), not enough fast (" + matches.size() + ") going on to highCap"); _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 { } else {
if (_log.shouldDebug()) if (_log.shouldDebug())
_log.debug("selectFastPeers("+howMany+"), found enough fast (" + matches.size() + ")"); _log.debug("selectFastPeers("+howMany+"), found enough fast (" + matches.size() + ")");
@ -512,14 +518,16 @@ public class ProfileOrganizer {
* *
*/ */
public void selectHighCapacityPeers(int howMany, Set<Hash> exclude, Set<Hash> matches) { public void selectHighCapacityPeers(int howMany, Set<Hash> exclude, Set<Hash> 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 * @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 * 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<Hash> exclude, Set<Hash> matches, int mask) { public void selectHighCapacityPeers(int howMany, Set<Hash> exclude, Set<Hash> matches, int mask, MaskedIPSet ipSet) {
getReadLock(); getReadLock();
try { try {
// we only use selectHighCapacityPeers when we are selecting for PURPOSE_TEST // we only use selectHighCapacityPeers when we are selecting for PURPOSE_TEST
@ -531,12 +539,12 @@ public class ProfileOrganizer {
else else
exclude.addAll(_fastPeers.keySet()); exclude.addAll(_fastPeers.keySet());
*/ */
locked_selectPeers(_highCapacityPeers, howMany, exclude, matches, mask); locked_selectPeers(_highCapacityPeers, howMany, exclude, matches, mask, ipSet);
} finally { releaseReadLock(); } } finally { releaseReadLock(); }
if (matches.size() < howMany) { if (matches.size() < howMany) {
if (_log.shouldLog(Log.INFO)) if (_log.shouldLog(Log.INFO))
_log.info("selectHighCap("+howMany+"), not enough highcap (" + matches.size() + ") going on to ANFP2"); _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 { } else {
if (_log.shouldDebug()) if (_log.shouldDebug())
_log.debug("selectHighCap("+howMany+"), found enough highCap (" + matches.size() + ")"); _log.debug("selectHighCap("+howMany+"), found enough highCap (" + matches.size() + ")");
@ -551,7 +559,7 @@ public class ProfileOrganizer {
*/ */
@Deprecated @Deprecated
public void selectWellIntegratedPeers(int howMany, Set<Hash> exclude, Set<Hash> matches) { public void selectWellIntegratedPeers(int howMany, Set<Hash> exclude, Set<Hash> 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 * @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 * 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 unused
*/ */
@Deprecated @Deprecated
public void selectWellIntegratedPeers(int howMany, Set<Hash> exclude, Set<Hash> matches, int mask) { public void selectWellIntegratedPeers(int howMany, Set<Hash> exclude, Set<Hash> matches, int mask, MaskedIPSet ipSet) {
getReadLock(); getReadLock();
try { try {
locked_selectPeers(_wellIntegratedPeers, howMany, exclude, matches, mask); locked_selectPeers(_wellIntegratedPeers, howMany, exclude, matches, mask, ipSet);
} finally { releaseReadLock(); } } finally { releaseReadLock(); }
if (matches.size() < howMany) { if (matches.size() < howMany) {
if (_log.shouldLog(Log.INFO)) if (_log.shouldLog(Log.INFO))
_log.info("selectWellIntegrated("+howMany+"), not enough integrated (" + matches.size() + ") going on to notFailing"); _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 { } else {
if (_log.shouldDebug()) if (_log.shouldDebug())
_log.debug("selectWellIntegrated("+howMany+"), found enough well integrated (" + matches.size() + ")"); _log.debug("selectWellIntegrated("+howMany+"), found enough well integrated (" + matches.size() + ")");
@ -585,18 +594,20 @@ public class ProfileOrganizer {
* *
*/ */
public void selectNotFailingPeers(int howMany, Set<Hash> exclude, Set<Hash> matches) { public void selectNotFailingPeers(int howMany, Set<Hash> exclude, Set<Hash> 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 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<Hash> exclude, Set<Hash> matches, int mask) { public void selectNotFailingPeers(int howMany, Set<Hash> exclude, Set<Hash> matches, int mask, MaskedIPSet ipSet) {
selectNotFailingPeers(howMany, exclude, matches, false, mask); selectNotFailingPeers(howMany, exclude, matches, false, mask, ipSet);
} }
public void selectNotFailingPeers(int howMany, Set<Hash> exclude, Set<Hash> matches, boolean onlyNotFailing) { public void selectNotFailingPeers(int howMany, Set<Hash> exclude, Set<Hash> 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 matches set to store the matches in
* @param onlyNotFailing if true, don't include any high capacity peers * @param onlyNotFailing if true, don't include any high capacity peers
* @param mask ignored, should call locked_selectPeers, to be fixed * @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<Hash> exclude, Set<Hash> matches, boolean onlyNotFailing, int mask) { public void selectNotFailingPeers(int howMany, Set<Hash> exclude, Set<Hash> matches, boolean onlyNotFailing,
int mask, MaskedIPSet ipSet) {
if (matches.size() < howMany) if (matches.size() < howMany)
selectAllNotFailingPeers(howMany, exclude, matches, onlyNotFailing, mask); selectAllNotFailingPeers(howMany, exclude, matches, onlyNotFailing, mask);
return; return;
@ -627,9 +641,30 @@ public class ProfileOrganizer {
* be used when there is a good number of connected peers. * 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 exclude non-null, WARNING - side effect, all not-connected peers are added
* No mask parameter, to be fixed
*/ */
public void selectActiveNotFailingPeers(int howMany, Set<Hash> exclude, Set<Hash> matches) { public void selectActiveNotFailingPeers(int howMany, Set<Hash> exclude, Set<Hash> 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<Hash> exclude, Set<Hash> matches, int mask, MaskedIPSet ipSet) {
if (matches.size() < howMany) { if (matches.size() < howMany) {
Set<Hash> connected = _context.commSystem().getEstablished(); Set<Hash> connected = _context.commSystem().getEstablished();
getReadLock(); getReadLock();
@ -638,7 +673,7 @@ public class ProfileOrganizer {
if (!connected.contains(peer)) if (!connected.contains(peer))
exclude.add(peer); exclude.add(peer);
} }
locked_selectPeers(_notFailingPeers, howMany, exclude, matches, 0); locked_selectPeers(_notFailingPeers, howMany, exclude, matches, mask, ipSet);
} finally { releaseReadLock(); } } 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 * @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 * 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<Hash> exclude, Set<Hash> matches, int mask) { private void selectActiveNotFailingPeers2(int howMany, Set<Hash> exclude, Set<Hash> matches, int mask, MaskedIPSet ipSet) {
if (matches.size() < howMany) { if (matches.size() < howMany) {
Set<Hash> connected = _context.commSystem().getEstablished(); Set<Hash> connected = _context.commSystem().getEstablished();
Map<Hash, PeerProfile> activePeers = new HashMap<Hash, PeerProfile>(connected.size()); Map<Hash, PeerProfile> activePeers = new HashMap<Hash, PeerProfile>(connected.size());
@ -667,13 +704,13 @@ public class ProfileOrganizer {
if (prof != null) if (prof != null)
activePeers.put(peer, prof); activePeers.put(peer, prof);
} }
locked_selectPeers(activePeers, howMany, exclude, matches, mask); locked_selectPeers(activePeers, howMany, exclude, matches, mask, ipSet);
} finally { releaseReadLock(); } } finally { releaseReadLock(); }
} }
if (matches.size() < howMany) { if (matches.size() < howMany) {
if (_log.shouldLog(Log.INFO)) if (_log.shouldLog(Log.INFO))
_log.info("selectANFP2("+howMany+"), not enough ANFP (" + matches.size() + ") going on to notFailing"); _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 { } else {
if (_log.shouldDebug()) if (_log.shouldDebug())
_log.debug("selectANFP2("+howMany+"), found enough ANFP (" + matches.size() + ")"); _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 * @param mask ignored, should call locked_selectPeers, to be fixed
*
*/ */
private void selectAllNotFailingPeers(int howMany, Set<Hash> exclude, Set<Hash> matches, boolean onlyNotFailing, int mask) { private void selectAllNotFailingPeers(int howMany, Set<Hash> exclude, Set<Hash> matches, boolean onlyNotFailing, int mask) {
if (matches.size() < howMany) { if (matches.size() < howMany) {
@ -1287,19 +1323,21 @@ public class ProfileOrganizer {
* *
*/ */
private void locked_selectPeers(Map<Hash, PeerProfile> peers, int howMany, Set<Hash> toExclude, Set<Hash> matches) { private void locked_selectPeers(Map<Hash, PeerProfile> peers, int howMany, Set<Hash> toExclude, Set<Hash> 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 * @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 * 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<Hash, PeerProfile> peers, int howMany, Set<Hash> toExclude, Set<Hash> matches, int mask) { private void locked_selectPeers(Map<Hash, PeerProfile> peers, int howMany, Set<Hash> toExclude, Set<Hash> matches,
int mask, MaskedIPSet ipSet) {
List<Hash> all = new ArrayList<Hash>(peers.keySet()); List<Hash> all = new ArrayList<Hash>(peers.keySet());
MaskedIPSet IPSet = new MaskedIPSet(16);
// use RandomIterator to avoid shuffling the whole thing // use RandomIterator to avoid shuffling the whole thing
for (Iterator<Hash> iter = new RandomIterator<Hash>(all); (matches.size() < howMany) && iter.hasNext(); ) { for (Iterator<Hash> iter = new RandomIterator<Hash>(all); (matches.size() < howMany) && iter.hasNext(); ) {
Hash peer = iter.next(); Hash peer = iter.next();
@ -1311,7 +1349,7 @@ public class ProfileOrganizer {
continue; continue;
boolean ok = isSelectable(peer); boolean ok = isSelectable(peer);
if (ok) { if (ok) {
ok = mask <= 0 || notRestricted(peer, IPSet, mask); ok = mask <= 0 || notRestricted(peer, ipSet, mask);
if ((!ok) && _log.shouldLog(Log.WARN)) if ((!ok) && _log.shouldLog(Log.WARN))
_log.warn("IP restriction prevents " + peer + " from joining " + matches); _log.warn("IP restriction prevents " + peer + " from joining " + matches);
} }
@ -1350,9 +1388,13 @@ public class ProfileOrganizer {
* 6: return only from group 2 * 6: return only from group 2
* 7: return only from group 3 * 7: return only from group 3
*</pre> *</pre>
* @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<Hash, PeerProfile> peers, int howMany, Set<Hash> toExclude, private void locked_selectPeers(Map<Hash, PeerProfile> peers, int howMany, Set<Hash> toExclude,
Set<Hash> matches, SessionKey randomKey, Slice subTierMode) { Set<Hash> matches, SessionKey randomKey, Slice subTierMode,
int mask, MaskedIPSet ipSet) {
List<Hash> all = new ArrayList<Hash>(peers.keySet()); List<Hash> all = new ArrayList<Hash>(peers.keySet());
byte[] rk = randomKey.getData(); byte[] rk = randomKey.getData();
// we use the first half of the random key here, // we use the first half of the random key here,
@ -1373,6 +1415,11 @@ public class ProfileOrganizer {
if ((subTier & subTierMode.mask) != subTierMode.val) if ((subTier & subTierMode.mask) != subTierMode.val)
continue; continue;
boolean ok = isSelectable(peer); boolean ok = isSelectable(peer);
if (ok) {
ok = mask <= 0 || notRestricted(peer, ipSet, mask);
if ((!ok) && _log.shouldLog(Log.WARN))
_log.warn("IP restriction prevents " + peer + " from joining " + matches);
}
if (ok) if (ok)
matches.add(peer); matches.add(peer);
else else

View File

@ -13,6 +13,7 @@ import net.i2p.router.TunnelInfo;
import net.i2p.router.TunnelManagerFacade; import net.i2p.router.TunnelManagerFacade;
import net.i2p.router.TunnelPoolSettings; import net.i2p.router.TunnelPoolSettings;
import static net.i2p.router.peermanager.ProfileOrganizer.Slice.*; 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 * 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!!!! * Returns ENDPOINT FIRST, GATEWAY LAST!!!!
* In: us .. closest .. middle .. IBGW * In: us .. closest .. middle .. IBGW
* Out: OBGW .. middle .. closest .. us * Out: OBGW .. middle .. closest .. us
* *
* @return ordered list of Hash objects (one per peer) specifying what order * @return ordered list of Hash objects (one per peer) specifying what order
* they should appear in a tunnel (ENDPOINT FIRST). This includes * they should appear in a tunnel (ENDPOINT FIRST). This includes
* the local router in the list. If there are no tunnels or peers * the local router in the list. If there are no tunnels or peers
@ -45,7 +46,7 @@ class ClientPeerSelector extends TunnelPeerSelector {
List<Hash> rv; List<Hash> rv;
boolean isInbound = settings.isInbound(); boolean isInbound = settings.isInbound();
if (length > 0) { if (length > 0) {
// special cases // special cases
boolean v6Only = isIPv6Only(); boolean v6Only = isIPv6Only();
@ -57,10 +58,12 @@ class ClientPeerSelector extends TunnelPeerSelector {
!ctx.commSystem().haveInboundCapacity(95); !ctx.commSystem().haveInboundCapacity(95);
boolean hiddenInbound = hidden && isInbound; boolean hiddenInbound = hidden && isInbound;
boolean hiddenOutbound = 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)) if (shouldSelectExplicit(settings))
return selectExplicit(settings, length); return selectExplicit(settings, length);
Set<Hash> exclude = getExclude(isInbound, false); Set<Hash> exclude = getExclude(isInbound, false);
Set<Hash> matches = new HashSet<Hash>(length); Set<Hash> matches = new HashSet<Hash>(length);
if (length == 1) { if (length == 1) {
@ -70,6 +73,7 @@ class ClientPeerSelector extends TunnelPeerSelector {
if (moreExclude != null) if (moreExclude != null)
exclude.addAll(moreExclude); exclude.addAll(moreExclude);
} }
// 1-hop, IP restrictions not required here
if (hiddenInbound) { if (hiddenInbound) {
// SANFP adds all not-connected to exclude, so make a copy // SANFP adds all not-connected to exclude, so make a copy
Set<Hash> SANFPExclude = new HashSet<Hash>(exclude); Set<Hash> SANFPExclude = new HashSet<Hash>(exclude);
@ -77,7 +81,7 @@ class ClientPeerSelector extends TunnelPeerSelector {
} }
if (matches.isEmpty()) { if (matches.isEmpty()) {
// ANFP does not fall back to non-connected // 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()); matches.remove(ctx.routerHash());
rv = new ArrayList<Hash>(matches); rv = new ArrayList<Hash>(matches);
@ -108,17 +112,17 @@ class ClientPeerSelector extends TunnelPeerSelector {
lastHopExclude = exclude; lastHopExclude = exclude;
} }
if (hiddenInbound) { if (hiddenInbound) {
// IB closest hop // IB closest hop
if (log.shouldInfo()) if (log.shouldInfo())
log.info("CPS SANFP closest IB exclude " + lastHopExclude.size()); log.info("CPS SANFP closest IB exclude " + lastHopExclude.size());
// SANFP adds all not-connected to exclude, so make a copy // SANFP adds all not-connected to exclude, so make a copy
Set<Hash> SANFPExclude = new HashSet<Hash>(lastHopExclude); Set<Hash> SANFPExclude = new HashSet<Hash>(lastHopExclude);
ctx.profileOrganizer().selectActiveNotFailingPeers(1, SANFPExclude, matches); ctx.profileOrganizer().selectActiveNotFailingPeers(1, SANFPExclude, matches, ipRestriction, ipSet);
if (matches.isEmpty()) { if (matches.isEmpty()) {
if (log.shouldInfo()) if (log.shouldInfo())
log.info("CPS SFP closest IB exclude " + lastHopExclude.size()); log.info("CPS SFP closest IB exclude " + lastHopExclude.size());
// ANFP does not fall back to non-connected // 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) { } else if (hiddenOutbound) {
// OBEP // OBEP
@ -177,19 +181,19 @@ class ClientPeerSelector extends TunnelPeerSelector {
log.info("CPS SANFP OBEP exclude " + lastHopExclude.size()); log.info("CPS SANFP OBEP exclude " + lastHopExclude.size());
// SANFP adds all not-connected to exclude, so make a copy // SANFP adds all not-connected to exclude, so make a copy
Set<Hash> SANFPExclude = new HashSet<Hash>(lastHopExclude); Set<Hash> SANFPExclude = new HashSet<Hash>(lastHopExclude);
ctx.profileOrganizer().selectActiveNotFailingPeers(1, SANFPExclude, matches); ctx.profileOrganizer().selectActiveNotFailingPeers(1, SANFPExclude, matches, ipRestriction, ipSet);
if (matches.isEmpty()) { if (matches.isEmpty()) {
// ANFP does not fall back to non-connected // ANFP does not fall back to non-connected
if (log.shouldInfo()) if (log.shouldInfo())
log.info("CPS SFP OBEP exclude " + lastHopExclude.size()); 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 { } 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 { } else {
// TODO exclude IPv6-only at OBEP? Caught in checkTunnel() below // 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()); matches.remove(ctx.routerHash());
@ -199,7 +203,7 @@ class ClientPeerSelector extends TunnelPeerSelector {
if (length > 2) { if (length > 2) {
// middle hop(s) // middle hop(s)
// group 2 or 3 // 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()); matches.remove(ctx.routerHash());
if (matches.size() > 1) { if (matches.size() > 1) {
// order the middle peers for tunnels >= 4 hops // 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 // 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()); matches.remove(ctx.routerHash());
rv.addAll(matches); rv.addAll(matches);
} }
} else { } else {
rv = new ArrayList<Hash>(1); rv = new ArrayList<Hash>(1);
} }
//if (length != rv.size() && log.shouldWarn()) //if (length != rv.size() && log.shouldWarn())
// log.warn("CPS requested " + length + " got " + rv.size() + ": " + DataHelper.toString(rv)); // log.warn("CPS requested " + length + " got " + rv.size() + ": " + DataHelper.toString(rv));
//else if (log.shouldDebug()) //else if (log.shouldDebug())

View File

@ -11,6 +11,7 @@ import net.i2p.router.RouterContext;
import net.i2p.router.TunnelInfo; import net.i2p.router.TunnelInfo;
import net.i2p.router.TunnelManagerFacade; import net.i2p.router.TunnelManagerFacade;
import net.i2p.router.TunnelPoolSettings; import net.i2p.router.TunnelPoolSettings;
import net.i2p.router.util.MaskedIPSet;
import net.i2p.stat.Rate; import net.i2p.stat.Rate;
import net.i2p.stat.RateStat; import net.i2p.stat.RateStat;
import net.i2p.util.Log; import net.i2p.util.Log;
@ -31,7 +32,7 @@ class ExploratoryPeerSelector extends TunnelPeerSelector {
* Returns ENDPOINT FIRST, GATEWAY LAST!!!! * Returns ENDPOINT FIRST, GATEWAY LAST!!!!
* In: us .. closest .. middle .. IBGW * In: us .. closest .. middle .. IBGW
* Out: OBGW .. middle .. closest .. us * Out: OBGW .. middle .. closest .. us
* *
* @return ordered list of Hash objects (one per peer) specifying what order * @return ordered list of Hash objects (one per peer) specifying what order
* they should appear in a tunnel (ENDPOINT FIRST). This includes * they should appear in a tunnel (ENDPOINT FIRST). This includes
* the local router in the list. If there are no tunnels or peers * the local router in the list. If there are no tunnels or peers
@ -40,19 +41,19 @@ class ExploratoryPeerSelector extends TunnelPeerSelector {
*/ */
public List<Hash> selectPeers(TunnelPoolSettings settings) { public List<Hash> selectPeers(TunnelPoolSettings settings) {
int length = getLength(settings); int length = getLength(settings);
if (length < 0) { if (length < 0) {
if (log.shouldLog(Log.DEBUG)) if (log.shouldLog(Log.DEBUG))
log.debug("Length requested is zero: " + settings); log.debug("Length requested is zero: " + settings);
return null; return null;
} }
//if (false && shouldSelectExplicit(settings)) { //if (false && shouldSelectExplicit(settings)) {
// List<Hash> rv = selectExplicit(settings, length); // List<Hash> rv = selectExplicit(settings, length);
// if (l.shouldLog(Log.DEBUG)) // if (l.shouldLog(Log.DEBUG))
// l.debug("Explicit peers selected: " + rv); // l.debug("Explicit peers selected: " + rv);
// return rv; // return rv;
//} //}
boolean isInbound = settings.isInbound(); boolean isInbound = settings.isInbound();
Set<Hash> exclude = getExclude(isInbound, true); Set<Hash> exclude = getExclude(isInbound, true);
exclude.add(ctx.routerHash()); exclude.add(ctx.routerHash());
@ -70,6 +71,8 @@ class ExploratoryPeerSelector extends TunnelPeerSelector {
boolean hiddenInbound = hidden && isInbound; boolean hiddenInbound = hidden && isInbound;
boolean hiddenOutbound = hidden && !isInbound; boolean hiddenOutbound = hidden && !isInbound;
boolean lowOutbound = nonzero && !isInbound && !ctx.commSystem().haveHighOutboundCapacity(); 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 // closest-hop restrictions
@ -99,21 +102,21 @@ class ExploratoryPeerSelector extends TunnelPeerSelector {
log.info("EPS SANFP closest " + (isInbound ? "IB" : "OB") + " exclude " + closestExclude.size()); log.info("EPS SANFP closest " + (isInbound ? "IB" : "OB") + " exclude " + closestExclude.size());
// SANFP adds all not-connected to exclude, so make a copy // SANFP adds all not-connected to exclude, so make a copy
Set<Hash> SANFPExclude = new HashSet<Hash>(closestExclude); Set<Hash> SANFPExclude = new HashSet<Hash>(closestExclude);
ctx.profileOrganizer().selectActiveNotFailingPeers(1, SANFPExclude, closest); ctx.profileOrganizer().selectActiveNotFailingPeers(1, SANFPExclude, closest, ipRestriction, ipSet);
if (closest.isEmpty()) { if (closest.isEmpty()) {
// ANFP does not fall back to non-connected // ANFP does not fall back to non-connected
if (log.shouldLog(Log.INFO)) if (log.shouldLog(Log.INFO))
log.info("EPS SFP closest " + (isInbound ? "IB" : "OB") + " exclude " + closestExclude.size()); 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) { } else if (exploreHighCap) {
if (log.shouldLog(Log.INFO)) if (log.shouldLog(Log.INFO))
log.info("EPS SHCP closest " + (isInbound ? "IB" : "OB") + " exclude " + closestExclude.size()); 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 { } else {
if (log.shouldLog(Log.INFO)) if (log.shouldLog(Log.INFO))
log.info("EPS SNFP closest " + (isInbound ? "IB" : "OB") + " exclude " + closestExclude.size()); 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()) { if (!closest.isEmpty()) {
closestHop = closest.iterator().next(); closestHop = closest.iterator().next();
@ -155,12 +158,12 @@ class ExploratoryPeerSelector extends TunnelPeerSelector {
log.info("EPS SANFP furthest OB exclude " + exclude.size()); log.info("EPS SANFP furthest OB exclude " + exclude.size());
// ANFP adds all not-connected to exclude, so make a copy // ANFP adds all not-connected to exclude, so make a copy
Set<Hash> SANFPExclude = new HashSet<Hash>(exclude); Set<Hash> SANFPExclude = new HashSet<Hash>(exclude);
ctx.profileOrganizer().selectActiveNotFailingPeers(1, SANFPExclude, furthest); ctx.profileOrganizer().selectActiveNotFailingPeers(1, SANFPExclude, furthest, ipRestriction, ipSet);
if (furthest.isEmpty()) { if (furthest.isEmpty()) {
// ANFP does not fall back to non-connected // ANFP does not fall back to non-connected
if (log.shouldLog(Log.INFO)) if (log.shouldLog(Log.INFO))
log.info("EPS SFP furthest OB exclude " + exclude.size()); 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()) { if (!furthest.isEmpty()) {
furthestHop = furthest.iterator().next(); furthestHop = furthest.iterator().next();
@ -179,13 +182,10 @@ class ExploratoryPeerSelector extends TunnelPeerSelector {
HashSet<Hash> matches = new HashSet<Hash>(length); HashSet<Hash> matches = new HashSet<Hash>(length);
if (length > 0) { if (length > 0) {
//
// We don't honor IP Restriction here, to be fixed
//
if (exploreHighCap) { if (exploreHighCap) {
if (log.shouldLog(Log.INFO)) if (log.shouldLog(Log.INFO))
log.info("EPS SHCP " + length + (isInbound ? " IB" : " OB") + " exclude " + exclude.size()); 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 { } else {
// As of 0.9.23, we include a max of 2 not failing peers, // As of 0.9.23, we include a max of 2 not failing peers,
// to improve build success on 3-hop tunnels. // to improve build success on 3-hop tunnels.
@ -194,7 +194,7 @@ class ExploratoryPeerSelector extends TunnelPeerSelector {
ctx.profileOrganizer().selectHighCapacityPeers(length - 2, exclude, matches); ctx.profileOrganizer().selectHighCapacityPeers(length - 2, exclude, matches);
if (log.shouldLog(Log.INFO)) if (log.shouldLog(Log.INFO))
log.info("EPS SNFP " + length + (isInbound ? " IB" : " OB") + " exclude " + exclude.size()); 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()); matches.remove(ctx.routerHash());
} }
@ -231,7 +231,7 @@ class ExploratoryPeerSelector extends TunnelPeerSelector {
} }
return rv; return rv;
} }
private static final int MIN_NONFAILING_PCT = 15; private static final int MIN_NONFAILING_PCT = 15;
private static final int MIN_ACTIVE_PEERS_STARTUP = 6; private static final int MIN_ACTIVE_PEERS_STARTUP = 6;
private static final int MIN_ACTIVE_PEERS = 12; private static final int MIN_ACTIVE_PEERS = 12;
@ -290,7 +290,7 @@ class ExploratoryPeerSelector extends TunnelPeerSelector {
} }
return (failPct >= ctx.random().nextInt(100)); return (failPct >= ctx.random().nextInt(100));
} }
/** /**
* We should really use the difference between the exploratory fail rate * 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, * 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); double pct = (double)(reject + timeout) / (accept + reject + timeout);
return (int)(100 * pct); return (int)(100 * pct);
} }
/** Use current + last to get more recent and smoother data */ /** Use current + last to get more recent and smoother data */
private int getEvents(String stat, long period) { private int getEvents(String stat, long period) {
RateStat rs = ctx.statManager().getRate(stat); RateStat rs = ctx.statManager().getRate(stat);
if (rs == null) if (rs == null)
return 0; return 0;
Rate r = rs.getRate(period); Rate r = rs.getRate(period);
if (r == null) if (r == null)

View File

@ -32,7 +32,7 @@ import net.i2p.util.SystemVersion;
import net.i2p.util.VersionComparator; 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. * 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 * @return ordered list of Hash objects (one per peer) specifying what order
* they should appear in a tunnel (ENDPOINT FIRST). This includes * they should appear in a tunnel (ENDPOINT FIRST). This includes
* the local router in the list. If there are no tunnels or peers * 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. * return null.
*/ */
public abstract List<Hash> selectPeers(TunnelPoolSettings settings); public abstract List<Hash> selectPeers(TunnelPoolSettings settings);
/** /**
* @return randomized number of hops 0-7, not including ourselves * @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 else if (length > 7) // as documented in tunnel.html
length = 7; length = 7;
/* /*
if ( (ctx.tunnelManager().getOutboundTunnelCount() <= 0) || if ( (ctx.tunnelManager().getOutboundTunnelCount() <= 0) ||
(ctx.tunnelManager().getFreeTunnelCount() <= 0) ) { (ctx.tunnelManager().getFreeTunnelCount() <= 0) ) {
Log log = ctx.logManager().getLog(TunnelPeerSelector.class); Log log = ctx.logManager().getLog(TunnelPeerSelector.class);
// no tunnels to build tunnels with // no tunnels to build tunnels with
@ -98,7 +98,7 @@ public abstract class TunnelPeerSelector extends ConnectChecker {
*/ */
return length; return length;
} }
/** /**
* For debugging, also possibly for restricted routes? * For debugging, also possibly for restricted routes?
* Needs analysis and testing * Needs analysis and testing
@ -118,7 +118,7 @@ public abstract class TunnelPeerSelector extends ConnectChecker {
return true; return true;
return false; return false;
} }
/** /**
* For debugging, also possibly for restricted routes? * For debugging, also possibly for restricted routes?
* Needs analysis and testing * Needs analysis and testing
@ -128,10 +128,10 @@ public abstract class TunnelPeerSelector extends ConnectChecker {
String peers = null; String peers = null;
Properties opts = settings.getUnknownOptions(); Properties opts = settings.getUnknownOptions();
peers = opts.getProperty("explicitPeers"); peers = opts.getProperty("explicitPeers");
if (peers == null) if (peers == null)
peers = ctx.getProperty("explicitPeers"); peers = ctx.getProperty("explicitPeers");
List<Hash> rv = new ArrayList<Hash>(); List<Hash> rv = new ArrayList<Hash>();
StringTokenizer tok = new StringTokenizer(peers, ","); StringTokenizer tok = new StringTokenizer(peers, ",");
while (tok.hasMoreTokens()) { while (tok.hasMoreTokens()) {
@ -139,7 +139,7 @@ public abstract class TunnelPeerSelector extends ConnectChecker {
Hash peer = new Hash(); Hash peer = new Hash();
try { try {
peer.fromBase64(peerStr); peer.fromBase64(peerStr);
if (ctx.profileOrganizer().isSelectable(peer)) { if (ctx.profileOrganizer().isSelectable(peer)) {
rv.add(peer); rv.add(peer);
} else { } else {
@ -150,14 +150,14 @@ public abstract class TunnelPeerSelector extends ConnectChecker {
log.error("Explicit peer is improperly formatted (" + peerStr + ")", dfe); log.error("Explicit peer is improperly formatted (" + peerStr + ")", dfe);
} }
} }
int sz = rv.size(); int sz = rv.size();
if (sz == 0) { if (sz == 0) {
log.logAlways(Log.WARN, "No valid explicit peers found, building zero hop"); log.logAlways(Log.WARN, "No valid explicit peers found, building zero hop");
} else if (sz > 1) { } else if (sz > 1) {
Collections.shuffle(rv, ctx.random()); Collections.shuffle(rv, ctx.random());
} }
while (rv.size() > length) { while (rv.size() > length) {
rv.remove(0); rv.remove(0);
} }
@ -166,11 +166,12 @@ public abstract class TunnelPeerSelector extends ConnectChecker {
Set<Hash> exclude = getExclude(settings.isInbound(), settings.isExploratory()); Set<Hash> exclude = getExclude(settings.isInbound(), settings.isExploratory());
exclude.addAll(rv); exclude.addAll(rv);
Set<Hash> matches = new HashSet<Hash>(more); Set<Hash> matches = new HashSet<Hash>(more);
ctx.profileOrganizer().selectFastPeers(more, exclude, matches, 0); // don't bother with IP restrictions here
ctx.profileOrganizer().selectFastPeers(more, exclude, matches);
rv.addAll(matches); rv.addAll(matches);
Collections.shuffle(rv, ctx.random()); Collections.shuffle(rv, ctx.random());
} }
if (log.shouldLog(Log.INFO)) { if (log.shouldLog(Log.INFO)) {
StringBuilder buf = new StringBuilder(); StringBuilder buf = new StringBuilder();
if (settings.getDestinationNickname() != null) if (settings.getDestinationNickname() != null)
@ -187,16 +188,16 @@ public abstract class TunnelPeerSelector extends ConnectChecker {
buf.append(", out of ").append(sz).append(" (not including self)"); buf.append(", out of ").append(sz).append(" (not including self)");
log.info(buf.toString()); log.info(buf.toString());
} }
if (settings.isInbound()) if (settings.isInbound())
rv.add(0, ctx.routerHash()); rv.add(0, ctx.routerHash());
else else
rv.add(ctx.routerHash()); rv.add(ctx.routerHash());
return rv; return rv;
} }
/** /**
* Pick peers that we want to avoid * Pick peers that we want to avoid
*/ */
public Set<Hash> getExclude(boolean isInbound, boolean isExploratory) { public Set<Hash> getExclude(boolean isInbound, boolean isExploratory) {
@ -267,7 +268,7 @@ public abstract class TunnelPeerSelector extends ConnectChecker {
peers.add(peer.getIdentity().calculateHash()); peers.add(peer.getIdentity().calculateHash());
// otherwise, it contains flags we aren't trying to focus on, // otherwise, it contains flags we aren't trying to focus on,
// so don't exclude it based on published capacity // so don't exclude it based on published capacity
if (filterUptime(ctx, isInbound, isExploratory)) { if (filterUptime(ctx, isInbound, isExploratory)) {
Properties opts = peer.getOptions(); Properties opts = peer.getOptions();
if (opts != null) { if (opts != null) {
@ -298,7 +299,7 @@ public abstract class TunnelPeerSelector extends ConnectChecker {
peers.add(peer.getIdentity().calculateHash()); peers.add(peer.getIdentity().calculateHash());
continue; continue;
} }
long infoAge = ctx.clock().now() - peer.getPublished(); long infoAge = ctx.clock().now() - peer.getPublished();
if (infoAge < 0) { if (infoAge < 0) {
infoAge = 0; infoAge = 0;
@ -387,8 +388,8 @@ public abstract class TunnelPeerSelector extends ConnectChecker {
return false; return false;
return canConnect(ANY_V4, ri); return canConnect(ANY_V4, ri);
} }
/** /**
* Pick peers that we want to avoid for the first OB hop or last IB hop. * Pick peers that we want to avoid for the first OB hop or last IB hop.
* There's several cases of importance: * There's several cases of importance:
* <ol><li>Inbound and we are hidden - * <ol><li>Inbound and we are hidden -
@ -452,19 +453,19 @@ public abstract class TunnelPeerSelector extends ConnectChecker {
} }
return rv; return rv;
} }
/** warning, this is also called by ProfileOrganizer.isSelectable() */ /** warning, this is also called by ProfileOrganizer.isSelectable() */
public static boolean shouldExclude(RouterContext ctx, RouterInfo peer) { public static boolean shouldExclude(RouterContext ctx, RouterInfo peer) {
return shouldExclude(peer, getExcludeCaps(ctx)); return shouldExclude(peer, getExcludeCaps(ctx));
} }
/** /**
* @return non-null, possibly empty * @return non-null, possibly empty
*/ */
private static String getExcludeCaps(RouterContext ctx) { private static String getExcludeCaps(RouterContext ctx) {
return ctx.getProperty("router.excludePeerCaps", DEFAULT_EXCLUDE_CAPS); return ctx.getProperty("router.excludePeerCaps", DEFAULT_EXCLUDE_CAPS);
} }
/** NTCP2 */ /** NTCP2 */
private static final String MIN_VERSION = "0.9.36"; private static final String MIN_VERSION = "0.9.36";
@ -555,18 +556,18 @@ public abstract class TunnelPeerSelector extends ConnectChecker {
******/ ******/
return false; return false;
} }
private static final String PROP_OUTBOUND_EXPLORATORY_EXCLUDE_UNREACHABLE = "router.outboundExploratoryExcludeUnreachable"; 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_OUTBOUND_CLIENT_EXCLUDE_UNREACHABLE = "router.outboundClientExcludeUnreachable";
private static final String PROP_INBOUND_EXPLORATORY_EXCLUDE_UNREACHABLE = "router.inboundExploratoryExcludeUnreachable"; 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 String PROP_INBOUND_CLIENT_EXCLUDE_UNREACHABLE = "router.inboundClientExcludeUnreachable";
private static final boolean DEFAULT_OUTBOUND_EXPLORATORY_EXCLUDE_UNREACHABLE = false; private static final boolean DEFAULT_OUTBOUND_EXPLORATORY_EXCLUDE_UNREACHABLE = false;
private static final boolean DEFAULT_OUTBOUND_CLIENT_EXCLUDE_UNREACHABLE = false; private static final boolean DEFAULT_OUTBOUND_CLIENT_EXCLUDE_UNREACHABLE = false;
// see comments at getExclude() above // see comments at getExclude() above
private static final boolean DEFAULT_INBOUND_EXPLORATORY_EXCLUDE_UNREACHABLE = false; private static final boolean DEFAULT_INBOUND_EXPLORATORY_EXCLUDE_UNREACHABLE = false;
private static final boolean DEFAULT_INBOUND_CLIENT_EXCLUDE_UNREACHABLE = false; private static final boolean DEFAULT_INBOUND_CLIENT_EXCLUDE_UNREACHABLE = false;
/** /**
* do we want to skip unreachable peers? * do we want to skip unreachable peers?
* @return true if yes * @return true if yes
@ -587,18 +588,18 @@ public abstract class TunnelPeerSelector extends ConnectChecker {
if (ctx.router().isHidden()) if (ctx.router().isHidden())
return true; return true;
return ctx.getProperty(PROP_INBOUND_CLIENT_EXCLUDE_UNREACHABLE, DEFAULT_INBOUND_CLIENT_EXCLUDE_UNREACHABLE); 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); 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_EXPLORATORY_EXCLUDE_SLOW = "router.outboundExploratoryExcludeSlow";
private static final String PROP_OUTBOUND_CLIENT_EXCLUDE_SLOW = "router.outboundClientExcludeSlow"; 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_EXPLORATORY_EXCLUDE_SLOW = "router.inboundExploratoryExcludeSlow";
private static final String PROP_INBOUND_CLIENT_EXCLUDE_SLOW = "router.inboundClientExcludeSlow"; private static final String PROP_INBOUND_CLIENT_EXCLUDE_SLOW = "router.inboundClientExcludeSlow";
/** /**
* do we want to skip peers that are slow? * do we want to skip peers that are slow?
* @return true unless configured otherwise * @return true unless configured otherwise
@ -612,18 +613,18 @@ public abstract class TunnelPeerSelector extends ConnectChecker {
} else { } else {
if (isInbound) if (isInbound)
return ctx.getProperty(PROP_INBOUND_CLIENT_EXCLUDE_SLOW, true); return ctx.getProperty(PROP_INBOUND_CLIENT_EXCLUDE_SLOW, true);
else else
return ctx.getProperty(PROP_OUTBOUND_CLIENT_EXCLUDE_SLOW, true); 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_EXPLORATORY_EXCLUDE_UPTIME = "router.outboundExploratoryExcludeUptime";
private static final String PROP_OUTBOUND_CLIENT_EXCLUDE_UPTIME = "router.outboundClientExcludeUptime"; 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_EXPLORATORY_EXCLUDE_UPTIME = "router.inboundExploratoryExcludeUptime";
private static final String PROP_INBOUND_CLIENT_EXCLUDE_UPTIME = "router.inboundClientExcludeUptime"; private static final String PROP_INBOUND_CLIENT_EXCLUDE_UPTIME = "router.inboundClientExcludeUptime";
****/ ****/
/** /**
* do we want to skip peers who haven't been up for long? * do we want to skip peers who haven't been up for long?
* @return true unless configured otherwise * @return true unless configured otherwise
@ -638,7 +639,7 @@ public abstract class TunnelPeerSelector extends ConnectChecker {
} else { } else {
if (isInbound) if (isInbound)
return ctx.getProperty(PROP_INBOUND_CLIENT_EXCLUDE_UPTIME, true); return ctx.getProperty(PROP_INBOUND_CLIENT_EXCLUDE_UPTIME, true);
else else
return ctx.getProperty(PROP_OUTBOUND_CLIENT_EXCLUDE_UPTIME, true); return ctx.getProperty(PROP_OUTBOUND_CLIENT_EXCLUDE_UPTIME, true);
} }
} }