I2P Address: [http://git.idk.i2p]

Skip to content
Snippets Groups Projects

WIP: Add IP restriction based exclusions to ClientPeerSelection

Closed idk requested to merge idk/i2p.i2p:ip-restrictions into master

When I saw this post: http://zzz.i2p/topics/3215-vulnerability-iprestriction-is-ignored I did some grepping and saw that TunnelPoolSettings.getIPRestrictions() was never actually called anywhere. It looks like the setting might have been added, but the code to exclude based on similar IP ranges was not? So I tried to figure out where the IPRestriction rules should be enforced to be effective and then tried to figure out how to do it. This is untested so far, but if you get a moment, I'd appreciate it if you would take a glance and tell me if I'm on the right track @zzz .

Edited by idk

Merge request reports

Loading
Loading

Activity

Filter activity
  • Approvals
  • Assignees & reviewers
  • Comments (from bots)
  • Comments (from users)
  • Commits & branches
  • Edits
  • Labels
  • Lock status
  • Mentions
  • Merge request status
  • Tracking
  • idk requested review from @zzz

    requested review from @zzz

  • idk assigned to @idk

    assigned to @idk

  • idk changed the description

    changed the description

  • Maintainer

    I need to come at it from the other direction first and see how we got here, give me a couple days

  • Maintainer

    Appears to have been removed from ClientPeerSelector May 2011 when we went to slices.

    ExploratoryPeerSelector has never supported ip restriction, it's marked todo

    the efficient way to do this is in the select call, not the exclude call, and most of the select methods already have variants with mask args, but see below.

    The situation for the various ProfileOrganizer select calls, abbreviated:

    as called by CPS:

    SFP(w/ slice arg) no method w/ mask arg SANFP: method w/ mask arg is private and marked that mask arg is ignored

    as called by EPS:

    SFP(w/o slice arg) has public method w/ mask arg, appears to work SHCP: has public method w/ mask arg, appears to work SNFP: has public method w/ mask arg, marked that mask arg is ignored

  • Maintainer

    this may be easier for me to fix than try to explain it to you but lets talk about it

  • Author Owner

    Actually I think I figured my approach might be inefficient compared to another, looping over another bunch of potential peers and comparing IP's byte-by-byte seemed like a slow way to do it. I guess ideally we would only want to do that operation on as short a list of addresses as possible, which would be after it's been filtered. So I get that part. Is what you're saying that once the versions of the filter methods that accept the mask actually use the mask to filter similar/restricted IP's what is most efficient is to use them? That's the conclusion I found myself drawing when I looked at it again this morning.

  • Maintainer

    that and you added a huge amount (about 90 lines) of code to the organizer when it's already implemented in locked_selectPeers, that's all done. We just have to hook it all in again.

  • Maintainer

    ok the problem is that locked_selectPeers(w/ slice arg) doesn't have a mask arg

  • Maintainer

    here's my quick stab at it, unreviewed, untested

    diff --git a/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java b/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java
    index e84709d93..35a82a196 100644
    --- a/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java
    +++ b/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java
    @@ -483,7 +483,7 @@ public class ProfileOrganizer {
          *    7: return only from group 3
          *</pre>
          */
    -    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) {
             getReadLock();
             try {
                 if (subTierMode != Slice.SLICE_ALL) {
    @@ -492,9 +492,9 @@ 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);
                 else
    -                locked_selectPeers(_fastPeers, howMany, exclude, matches, 2);
    +                locked_selectPeers(_fastPeers, howMany, exclude, matches, mask);
             } finally { releaseReadLock(); }
             if (matches.size() < howMany) {
                 if (_log.shouldLog(Log.INFO))
    @@ -627,9 +627,28 @@ 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<Hash> exclude, Set<Hash> matches) {
    +        selectActiveNotFailingPeers(howMany, exclude, matches, 0);
    +    }
    +
    +    /**
    +     * 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
    +     * @since 0.9.53
    +     */
    +    public void selectActiveNotFailingPeers(int howMany, Set<Hash> exclude, Set<Hash> matches, int mask) {
             if (matches.size() < howMany) {
                 Set<Hash> connected = _context.commSystem().getEstablished();
                 getReadLock();
    @@ -638,7 +657,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);
                 } finally { releaseReadLock(); }
             }
         }
    @@ -690,7 +709,6 @@ public class ProfileOrganizer {
     
         /**
          * @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) {
             if (matches.size() < howMany) {
    @@ -1352,13 +1370,14 @@ public class ProfileOrganizer {
          *</pre>
          */
         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) {
             List<Hash> all = new ArrayList<Hash>(peers.keySet());
             byte[] rk = randomKey.getData();
             // we use the first half of the random key here,
             // the second half is used in TunnelPeerSelector.
             long k0 = DataHelper.fromLong8(rk, 0);
             long k1 = DataHelper.fromLong8(rk, 8);
    +        MaskedIPSet ipSet = new MaskedIPSet(16);
     
             // use RandomIterator to avoid shuffling the whole thing
             for (Iterator<Hash> iter = new RandomIterator<Hash>(all); (matches.size() < howMany) && iter.hasNext(); ) {
    @@ -1373,6 +1392,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.shouldLog(Log.WARN))
    +                    _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..1b0889e5e 100644
    --- a/router/java/src/net/i2p/router/tunnel/pool/ClientPeerSelector.java
    +++ b/router/java/src/net/i2p/router/tunnel/pool/ClientPeerSelector.java
    @@ -57,6 +57,7 @@ class ClientPeerSelector extends TunnelPeerSelector {
                                  !ctx.commSystem().haveInboundCapacity(95);
                 boolean hiddenInbound = hidden && isInbound;
                 boolean hiddenOutbound = hidden && !isInbound;
    +            int ipRestriction = settings.getIPRestriction();
     
                 if (shouldSelectExplicit(settings))
                     return selectExplicit(settings, length);
    @@ -73,11 +74,11 @@ class ClientPeerSelector extends TunnelPeerSelector {
                     if (hiddenInbound) {
                         // SANFP adds all not-connected to exclude, so make a copy
                         Set<Hash> SANFPExclude = new HashSet<Hash>(exclude);
    -                    ctx.profileOrganizer().selectActiveNotFailingPeers(1, SANFPExclude, matches);
    +                    ctx.profileOrganizer().selectActiveNotFailingPeers(1, SANFPExclude, matches, ipRestriction);
                     }
                     if (matches.isEmpty()) {
                         // ANFP does not fall back to non-connected
    -                    ctx.profileOrganizer().selectFastPeers(length, exclude, matches, 0);
    +                    ctx.profileOrganizer().selectFastPeers(length, exclude, matches, ipRestriction);
                     }
                     matches.remove(ctx.routerHash());
                     rv = new ArrayList<Hash>(matches);
    @@ -113,12 +114,12 @@ class ClientPeerSelector extends TunnelPeerSelector {
                             log.info("CPS SANFP closest IB exclude " + lastHopExclude.size());
                         // SANFP adds all not-connected to exclude, so make a copy
                         Set<Hash> SANFPExclude = new HashSet<Hash>(lastHopExclude);
    -                    ctx.profileOrganizer().selectActiveNotFailingPeers(1, SANFPExclude, matches);
    +                    ctx.profileOrganizer().selectActiveNotFailingPeers(1, SANFPExclude, matches, ipRestriction);
                         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);
                         }
                     } else if (hiddenOutbound) {
                         // OBEP
    @@ -177,19 +178,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<Hash> SANFPExclude = new HashSet<Hash>(lastHopExclude);
    -                        ctx.profileOrganizer().selectActiveNotFailingPeers(1, SANFPExclude, matches);
    +                        ctx.profileOrganizer().selectActiveNotFailingPeers(1, SANFPExclude, matches, ipRestriction);
                             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);
                             }
                         } 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);
                         }
                     } 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);
                     }
     
                     matches.remove(ctx.routerHash());
    @@ -199,7 +200,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);
                         matches.remove(ctx.routerHash());
                         if (matches.size() > 1) {
                             // order the middle peers for tunnels >= 4 hops
    @@ -225,7 +226,7 @@ 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);
                     matches.remove(ctx.routerHash());
                     rv.addAll(matches);
                 }
    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..2f8b657b8 100644
    --- a/router/java/src/net/i2p/router/tunnel/pool/ExploratoryPeerSelector.java
    +++ b/router/java/src/net/i2p/router/tunnel/pool/ExploratoryPeerSelector.java
    @@ -70,6 +70,7 @@ class ExploratoryPeerSelector extends TunnelPeerSelector {
             boolean hiddenInbound = hidden && isInbound;
             boolean hiddenOutbound = hidden && !isInbound;
             boolean lowOutbound = nonzero && !isInbound && !ctx.commSystem().haveHighOutboundCapacity();
    +        int ipRestriction = settings.getIPRestriction();
     
     
             // closest-hop restrictions
    @@ -99,21 +100,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<Hash> SANFPExclude = new HashSet<Hash>(closestExclude);
    -                ctx.profileOrganizer().selectActiveNotFailingPeers(1, SANFPExclude, closest);
    +                ctx.profileOrganizer().selectActiveNotFailingPeers(1, SANFPExclude, closest, ipRestriction);
                     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);
                     }
                 } 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);
                 } 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);
                 }
                 if (!closest.isEmpty()) {
                     closestHop = closest.iterator().next();
    @@ -155,12 +156,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<Hash> SANFPExclude = new HashSet<Hash>(exclude);
    -                ctx.profileOrganizer().selectActiveNotFailingPeers(1, SANFPExclude, furthest);
    +                ctx.profileOrganizer().selectActiveNotFailingPeers(1, SANFPExclude, furthest, ipRestriction);
                     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);
                     }
                     if (!furthest.isEmpty()) {
                         furthestHop = furthest.iterator().next();
    @@ -179,13 +180,10 @@ class ExploratoryPeerSelector extends TunnelPeerSelector {
             HashSet<Hash> matches = new HashSet<Hash>(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);
                 } 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 +192,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);
                 }
                 matches.remove(ctx.routerHash());
             }
  • Maintainer

    Here's the next problem. OP (here) misunderstands the intent of the IP restriction feature.

    It's not to prevent tunnel peers "too close" to you. It's to prevent tunnel peers "too close" to each other, i.e. possibly colluding.

    I don't see any code in ProfileOrganizer to do the too-close check to your own router. Maybe it's elsewhere or maybe I missed it.

    And this reveals why the feature was removed when we went to fast tier slicing. With slicing, we make a selectXXX() call for each slice. Nowhere do we create a single MaskedIPSet for the whole tunnel to check across all peers. So it's a little harder (and not addressed in my diff above)

    If there's some reason to exclude peers too close to you, that's a separate discussion.

  • Author Owner

    If there's some reason to exclude peers too close to you, that's a separate discussion.

    Not that I know of, I was just wrong.

    And this reveals why the feature was removed when we went to fast tier slicing. With slicing, we make a selectXXX() call for each slice. Nowhere do we create a single MaskedIPSet for the whole tunnel to check across all peers. So it's a little harder (and not addressed in my diff above)

    So without a single MaskedIPSet for the tunnel, what is IP restriction actually restricting here in your patch? I see a MaskedIPSet per call to locked_selectPeers, which gets called by SFP and SANFP, but if the MaskedIPSet they're using is just for the slice(s) they're being used on, then what actually gets restricted is the set of matches locked_selectPeers picks from the set of peers it's passed, right? Peers and matches go in, matches come out, up to howMany. So could each call to a selectXXX on the same set of matches could introduce a peer to the matches that violates the IP restriction?

    • Maintainer

      right, as I said, was not addressed in the diff above.

      Here's a new version, where a single MaskedIPSet is created in CPS and passed to all the select w/ slice calls. Still unreviewed, untested.

      diff --git a/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java b/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java
      index e84709d93..fc6ae7a4c 100644
      --- a/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java
      +++ b/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java
      @@ -482,8 +482,12 @@ public class ProfileOrganizer {
            *    6: return only from group 2
            *    7: return only from group 3
            *</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();
               try {
                   if (subTierMode != Slice.SLICE_ALL) {
      @@ -492,9 +496,9 @@ 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);
               } finally { releaseReadLock(); }
               if (matches.size() < howMany) {
                   if (_log.shouldLog(Log.INFO))
      @@ -627,9 +631,28 @@ 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<Hash> exclude, Set<Hash> matches) {
      +        selectActiveNotFailingPeers(howMany, exclude, matches, 0);
      +    }
      +
      +    /**
      +     * 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
      +     * @since 0.9.53
      +     */
      +    public void selectActiveNotFailingPeers(int howMany, Set<Hash> exclude, Set<Hash> matches, int mask) {
               if (matches.size() < howMany) {
                   Set<Hash> connected = _context.commSystem().getEstablished();
                   getReadLock();
      @@ -638,7 +661,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);
                   } finally { releaseReadLock(); }
               }
           }
      @@ -690,7 +713,6 @@ public class ProfileOrganizer {
       
           /**
            * @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) {
               if (matches.size() < howMany) {
      @@ -1352,7 +1374,8 @@ public class ProfileOrganizer {
            *</pre>
            */
           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());
               byte[] rk = randomKey.getData();
               // we use the first half of the random key here,
      @@ -1373,6 +1396,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.shouldLog(Log.WARN))
      +                    _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..2bc6450d0 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
      @@ -57,6 +58,8 @@ class ClientPeerSelector extends TunnelPeerSelector {
                                    !ctx.commSystem().haveInboundCapacity(95);
                   boolean hiddenInbound = hidden && isInbound;
                   boolean hiddenOutbound = hidden && !isInbound;
      +            int ipRestriction =  ctx.getBooleanProperty("i2np.allowLocal") ? 0 : settings.getIPRestriction();
      +            MaskedIPSet ipSet = ipRestriction > 0 ? new MaskedIPSet(16) : null;
       
                   if (shouldSelectExplicit(settings))
                       return selectExplicit(settings, length);
      @@ -73,11 +76,11 @@ class ClientPeerSelector extends TunnelPeerSelector {
                       if (hiddenInbound) {
                           // SANFP adds all not-connected to exclude, so make a copy
                           Set<Hash> SANFPExclude = new HashSet<Hash>(exclude);
      -                    ctx.profileOrganizer().selectActiveNotFailingPeers(1, SANFPExclude, matches);
      +                    ctx.profileOrganizer().selectActiveNotFailingPeers(1, SANFPExclude, matches, ipRestriction);
                       }
                       if (matches.isEmpty()) {
                           // ANFP does not fall back to non-connected
      -                    ctx.profileOrganizer().selectFastPeers(length, exclude, matches, 0);
      +                    ctx.profileOrganizer().selectFastPeers(length, exclude, matches, ipRestriction);
                       }
                       matches.remove(ctx.routerHash());
                       rv = new ArrayList<Hash>(matches);
      @@ -113,12 +116,12 @@ class ClientPeerSelector extends TunnelPeerSelector {
                               log.info("CPS SANFP closest IB exclude " + lastHopExclude.size());
                           // SANFP adds all not-connected to exclude, so make a copy
                           Set<Hash> SANFPExclude = new HashSet<Hash>(lastHopExclude);
      -                    ctx.profileOrganizer().selectActiveNotFailingPeers(1, SANFPExclude, matches);
      +                    ctx.profileOrganizer().selectActiveNotFailingPeers(1, SANFPExclude, matches, ipRestriction);
                           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 +180,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<Hash> SANFPExclude = new HashSet<Hash>(lastHopExclude);
      -                        ctx.profileOrganizer().selectActiveNotFailingPeers(1, SANFPExclude, matches);
      +                        ctx.profileOrganizer().selectActiveNotFailingPeers(1, SANFPExclude, matches, ipRestriction);
                               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 +202,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,7 +228,7 @@ 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);
                   }
      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..8236c3b80 100644
      --- a/router/java/src/net/i2p/router/tunnel/pool/ExploratoryPeerSelector.java
      +++ b/router/java/src/net/i2p/router/tunnel/pool/ExploratoryPeerSelector.java
      @@ -70,6 +70,7 @@ 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") ? 0 : settings.getIPRestriction();
       
       
               // closest-hop restrictions
      @@ -99,21 +100,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<Hash> SANFPExclude = new HashSet<Hash>(closestExclude);
      -                ctx.profileOrganizer().selectActiveNotFailingPeers(1, SANFPExclude, closest);
      +                ctx.profileOrganizer().selectActiveNotFailingPeers(1, SANFPExclude, closest, ipRestriction);
                       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);
                       }
                   } 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);
                   } 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);
                   }
                   if (!closest.isEmpty()) {
                       closestHop = closest.iterator().next();
      @@ -155,12 +156,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<Hash> SANFPExclude = new HashSet<Hash>(exclude);
      -                ctx.profileOrganizer().selectActiveNotFailingPeers(1, SANFPExclude, furthest);
      +                ctx.profileOrganizer().selectActiveNotFailingPeers(1, SANFPExclude, furthest, ipRestriction);
                       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);
                       }
                       if (!furthest.isEmpty()) {
                           furthestHop = furthest.iterator().next();
      @@ -179,13 +180,10 @@ class ExploratoryPeerSelector extends TunnelPeerSelector {
               HashSet<Hash> matches = new HashSet<Hash>(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);
                   } 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 +192,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);
                   }
                   matches.remove(ctx.routerHash());
               }
    • Author Owner

      Just wanted to make sure I understood the real effect of not having the single MaskedIPset on the tunnel. I think it looks good to me, I'll apply the patch on my side today and review it as best I can.

    • Please register or sign in to reply
  • zzz added 1 commit

    added 1 commit

    • d3af2af3 - Tunnels: Restore support for IP restriction in client tunnels

    Compare with previous version

  • Maintainer

    Test results: fairly rare for the check to trigger with ip restriction = 2, maybe one a day. Hardcoding the default to 1 for testing gets a few more, seems to be working:

    ProfileOrganizer: IP restriction prevents [Hash: CjURF3q~wUFm9zCwy-xCq2QpdGYKMJasLmCXxvViawQ=] from joining []
    ProfileOrganizer: IP restriction prevents [Hash: FqepmPcUjGwQGyiD5u8BKzqkspFhv8VJq8B~6~nKG0M=] from joining []
    ProfileOrganizer: IP restriction prevents [Hash: -N6Mmj9JPG6ZIJVAbOItk-Op4g9PbCu-f8AE5ZTsTQ4=] from joining []
    ProfileOrganizer: IP restriction prevents [Hash: XEyQDS6EgaCigJMasd0SqbCLJEJQsDEUuvfbbrSYh1A=] from joining []
    ProfileOrganizer: IP restriction prevents [Hash: XEyQDS6EgaCigJMasd0SqbCLJEJQsDEUuvfbbrSYh1A=] from joining []
    ProfileOrganizer: IP restriction prevents [Hash: Qgjl6sQr4RdInWiosf2yZ6CLCLiHixWjRRTyAZ3Z~Zg=] from joining []
    ProfileOrganizer: IP restriction prevents [Hash: q76tT08I5FxMPOtSuQQ7y5Jr81ghjE3X9OQdrTfrptg=] from joining []
    ProfileOrganizer: IP restriction prevents [Hash: DIYQw3o9eJp2cnr8S9l26WUvZFp0lLY6JCSCXwwyN1Y=] from joining []
    ProfileOrganizer: IP restriction prevents [Hash: Sf1kmIumpCxXUBB-FYMkVo5Zx3tymxIfdz38ks0B2Eg=] from joining [[Hash: c~IbETyUo317j4U1a0bcr9-avdWKt3yNFjt9KnVQw~Y=], [Hash: oChQ4-0nRZvnX~sGjWWtN~KAbjNXWNtc7i-IByAZeEg=]]
    ProfileOrganizer: IP restriction prevents [Hash: 2GZASJQHd~N31fuc~A8UWsXG2Ll-0ruCwMS0Yx80UZg=] from joining []
    ProfileOrganizer: IP restriction prevents [Hash: oChQ4-0nRZvnX~sGjWWtN~KAbjNXWNtc7i-IByAZeEg=] from joining []
    ProfileOrganizer: IP restriction prevents [Hash: m98szjhyz7So2tJY5JB5Ylfo45WssMUY7y3g9zvvVIY=] from joining []
    ProfileOrganizer: IP restriction prevents [Hash: oChQ4-0nRZvnX~sGjWWtN~KAbjNXWNtc7i-IByAZeEg=] from joining []
    ProfileOrganizer: IP restriction prevents [Hash: nH6a2UPl~vA2-K3Zvo2OPhDpkAPy13~hQM1iD-NKtF8=] from joining [[Hash: oChQ4-0nRZvnX~sGjWWtN~KAbjNXWNtc7i-IByAZeEg=]]
    ProfileOrganizer: IP restriction prevents [Hash: vwv7v9C6tYD0rQSXZmd8rFUoVHjaVpPwquMaRAbXKcY=] from joining [[Hash: -N6Mmj9JPG6ZIJVAbOItk-Op4g9PbCu-f8AE5ZTsTQ4=], [Hash: jN3PWONt5deKDEqfAyWxAbH2IedGkiNKDIAZLYc9bi0=]]
    ProfileOrganizer: IP restriction prevents [Hash: dXLYZM1rbl~glQ2Qin8Pw0Mi9deaKSNJDUUp6etD6Tg=] from joining [[Hash: 7jCT0SkzRRLrzxeuy~gpQ15f80WUJ3oS4UvQYDZBon4=]]
    ProfileOrganizer: IP restriction prevents [Hash: 3WmRnEbBOCJTKV5OlQswwWS8K3TwYrrMUr3cNNSCn48=] from joining [[Hash: 7jCT0SkzRRLrzxeuy~gpQ15f80WUJ3oS4UvQYDZBon4=]]
    ProfileOrganizer: IP restriction prevents [Hash: wvbryD53EYvK0ZaPNa~ShoVacDP2twEqTaTBmGSGorY=] from joining [[Hash: q76tT08I5FxMPOtSuQQ7y5Jr81ghjE3X9OQdrTfrptg=], [Hash: 2GZASJQHd~N31fuc~A8UWsXG2Ll-0ruCwMS0Yx80UZg=]]
    ProfileOrganizer: IP restriction prevents [Hash: 7jCT0SkzRRLrzxeuy~gpQ15f80WUJ3oS4UvQYDZBon4=] from joining [[Hash: hKDqxeTYHxEL-riYcvpy3vcdjom0L5-8Eb9~~oAbOAE=], [Hash: 3WmRnEbBOCJTKV5OlQswwWS8K3TwYrrMUr3cNNSCn48=]]

    I did go through several of the log entries, checked the RI for each hash, and verified that there was an IP overlap between the restricted router and one of the others.

    The ones with "joining []" are client tunnels where we're only picking one peer for a slice, so there's nothing in matches.

    Edited by zzz
  • Maintainer

    @idk looking for an ACK from you when you're done with your testing and review

  • idk approved this merge request

    approved this merge request

  • Author Owner

    I've gone over every bit of it and been running with it for the past several days, it's working fine for me and I'm seeing similar results to you when I turn on logging in ProfileOrganizer. Looks good, Ack.

  • Maintainer

    thank you. due to some possible issues raised in #i2p-dev, I'm not going to merge from here, will just checkin directly.

  • closed

  • Loading
  • Loading
  • Loading
  • Loading
  • Loading
  • Loading
  • Loading
  • Loading
  • Loading
  • Loading
Please register or sign in to reply
Loading