Changeset 3054a24


Ignore:
Timestamp:
Dec 15, 2018 4:54:01 PM (18 months ago)
Author:
zzz <zzz@…>
Branches:
master
Children:
9437e2c
Parents:
5d06de8
Message:

Sybil: More refactoring to separate analysis and display

Location:
apps/routerconsole/java/src/net/i2p/router
Files:
1 added
1 edited

Legend:

Unmodified
Added
Removed
  • apps/routerconsole/java/src/net/i2p/router/web/helpers/SybilRenderer.java

    r5d06de8 r3054a24  
    3131import net.i2p.router.peermanager.DBHistory;
    3232import net.i2p.router.peermanager.PeerProfile;
     33import net.i2p.router.sybil.Pair;
    3334import net.i2p.router.sybil.Points;
    3435import net.i2p.router.tunnel.pool.TunnelPool;
     
    248249
    249250        // IP analysis
    250         renderIPGroupsFamily(out, buf, ris, points);
    251         renderIPGroupsUs(out, buf, ris, points);
    252         renderIPGroups32(out, buf, ris, points);
    253         renderIPGroups24(out, buf, ris, points);
    254         renderIPGroups16(out, buf, ris, points);
     251        Map<String, List<RouterInfo>> fmap = calculateIPGroupsFamily(ris, points);
     252        renderIPGroupsFamily(out, buf, fmap);
     253        List<RouterInfo> ri32 = new ArrayList<RouterInfo>(4);
     254        List<RouterInfo> ri24 = new ArrayList<RouterInfo>(4);
     255        List<RouterInfo> ri16 = new ArrayList<RouterInfo>(4);
     256        calculateIPGroupsUs(ris, points, ri32, ri24, ri16);
     257        renderIPGroupsUs(out, buf, ri32, ri24, ri16);
     258        Map<Integer, List<RouterInfo>> map = calculateIPGroups32(ris, points);
     259        renderIPGroups32(out, buf, map);
     260        map = calculateIPGroups24(ris, points);
     261        renderIPGroups24(out, buf, map);
     262        map = calculateIPGroups16(ris, points);
     263        //renderIPGroups16(out, buf, map);
    255264
    256265        // Pairwise distance analysis
    257         renderPairDistance(out, buf, ris, points);
     266        List<Pair> pairs = new ArrayList<Pair>(PAIRMAX);
     267        double avg = calculatePairDistance(ris, points, pairs);
     268        renderPairDistance(out, buf, pairs, avg);
    258269
    259270        // Distance to our router analysis
    260271        buf.append("<h3 id=\"ritoday\" class=\"sybils\">Closest Floodfills to Our Routing Key (Where we Store our RI)</h3>");
    261272        buf.append("<p class=\"sybil_info\"><a href=\"/netdb?caps=f&amp;sybil\">See all</a></p>");
    262         renderRouterInfoHTML(out, buf, ourRKey, "our rkey", avgMinDist, ris, points);
     273        calculateRouterInfo(ourRKey, "our rkey", ris, points);
     274        renderRouterInfoHTML(out, buf, ourRKey, avgMinDist, ris);
    263275        RouterKeyGenerator rkgen = _context.routerKeyGenerator();
    264276        Hash nkey = rkgen.getNextRoutingKey(us);
    265277        buf.append("<h3 id=\"ritmrw\" class=\"sybils\">Closest Floodfills to Tomorrow's Routing Key (Where we will Store our RI)</h3>");
    266278        buf.append("<p class=\"sybil_info\"><a href=\"/netdb?caps=f&amp;sybil\">See all</a></p>");
    267         renderRouterInfoHTML(out, buf, nkey, "our rkey (tomorrow)", avgMinDist, ris, points);
     279        calculateRouterInfo(nkey, "our rkey (tomorrow)", ris, points);
     280        renderRouterInfoHTML(out, buf, nkey, avgMinDist, ris);
    268281
    269282        buf.append("<h3 id=\"dht\" class=\"sybils\">Closest Floodfills to Our Router Hash (DHT Neighbors if we are Floodfill)</h3>");
    270         renderRouterInfoHTML(out, buf, us, "our router", avgMinDist, ris, points);
     283        calculateRouterInfo(us, "our router", ris, points);
     284        renderRouterInfoHTML(out, buf, us, avgMinDist, ris);
    271285
    272286        // Distance to our published destinations analysis
     
    289303            buf.append("<h3 class=\"sybils\">Closest floodfills to the Routing Key for " + name + " (where we store our LS)</h3>");
    290304            buf.append("<p class=\"sybil_info\"><a href=\"/netdb?caps=f&amp;sybil=" + ls.getHash().toBase64() + "\">See all</a></p>");
    291             renderRouterInfoHTML(out, buf, rkey, name, avgMinDist, ris, points);
     305            calculateRouterInfo(rkey, name, ris, points);
     306            renderRouterInfoHTML(out, buf, rkey, avgMinDist, ris);
    292307            nkey = rkgen.getNextRoutingKey(ls.getHash());
    293308            buf.append("<h3 class=\"sybils\">Closest floodfills to Tomorrow's Routing Key for " + name + " (where we will store our LS)</h3>");
    294309            buf.append("<p class=\"sybil_info\"><a href=\"/netdb?caps=f&amp;sybil=" + ls.getHash().toBase64() + "\">See all</a></p>");
    295             renderRouterInfoHTML(out, buf, nkey, name + " (tomorrow)", avgMinDist, ris, points);
     310            calculateRouterInfo(nkey, name + " (tomorrow)", ris, points);
     311            renderRouterInfoHTML(out, buf, nkey, avgMinDist, ris);
    296312        }
    297313
     
    345361
    346362        // IP analysis
    347         renderIPGroupsFamily(null, null, ris, points);
    348         renderIPGroupsUs(null, null, ris, points);
    349         renderIPGroups32(null, null, ris, points);
    350         renderIPGroups24(null, null, ris, points);
    351         renderIPGroups16(null, null, ris, points);
     363        calculateIPGroupsFamily(ris, points);
     364        List<RouterInfo> ri32 = new ArrayList<RouterInfo>(4);
     365        List<RouterInfo> ri24 = new ArrayList<RouterInfo>(4);
     366        List<RouterInfo> ri16 = new ArrayList<RouterInfo>(4);
     367        calculateIPGroupsUs(ris, points, ri32, ri24, ri16);
     368        calculateIPGroups32(ris, points);
     369        calculateIPGroups24(ris, points);
     370        calculateIPGroups16(ris, points);
    352371
    353372        // Pairwise distance analysis
    354         renderPairDistance(null, null, ris, points);
     373        List<Pair> pairs = new ArrayList<Pair>(PAIRMAX);
     374        calculatePairDistance(ris, points, pairs);
    355375
    356376        // Distance to our router analysis
    357377        // closest to our routing key today
    358378        Hash ourRKey = _context.router().getRouterInfo().getRoutingKey();
    359         renderRouterInfoHTML(null, null, ourRKey, "our rkey", avgMinDist, ris, points);
     379        calculateRouterInfo(ourRKey, "our rkey", ris, points);
    360380        // closest to our routing key tomorrow
    361381        RouterKeyGenerator rkgen = _context.routerKeyGenerator();
    362382        Hash nkey = rkgen.getNextRoutingKey(us);
    363         renderRouterInfoHTML(null, null, nkey, "our rkey (tomorrow)", avgMinDist, ris, points);
     383        calculateRouterInfo(nkey, "our rkey (tomorrow)", ris, points);
    364384        // closest to us
    365         renderRouterInfoHTML(null, null, us, "our router", avgMinDist, ris, points);
     385        calculateRouterInfo(us, "our router", ris, points);
    366386
    367387        // Distance to our published destinations analysis
     
    381401            String name = (in != null) ? DataHelper.escapeHTML(in.getSettings().getDestinationNickname()) : client.toBase64().substring(0,4);
    382402            // closest to routing key today
    383             renderRouterInfoHTML(null, null, rkey, name, avgMinDist, ris, points);
     403            calculateRouterInfo(rkey, name, ris, points);
    384404            // closest to routing key tomorrow
    385405            nkey = rkgen.getNextRoutingKey(ls.getHash());
    386             renderRouterInfoHTML(null, null, nkey, name + " (tomorrow)", avgMinDist, ris, points);
     406            calculateRouterInfo(nkey, name + " (tomorrow)", ris, points);
    387407        }
    388408
     
    393413    }
    394414
    395     private static class Pair implements Comparable<Pair> {
    396         public final RouterInfo r1, r2;
    397         public final BigInteger dist;
    398         public Pair(RouterInfo ri1, RouterInfo ri2, BigInteger distance) {
    399             r1 = ri1; r2 = ri2; dist = distance;
    400         }
    401         public int compareTo(Pair p) {
    402             return this.dist.compareTo(p.dist);
    403         }
    404     }
    405 
    406     /**
    407      *  @param out null for background analysis
    408      *  @param buf null for background analysis
    409      */
    410     private void renderPairDistance(Writer out, StringBuilder buf, List<RouterInfo> ris, Map<Hash, Points> points) throws IOException {
     415    /**
     416     *  @param pairs out parameter, sorted
     417     *  @param return average distance
     418     *  @since 0.9.38 split out from renderPairDistance()
     419     */
     420    private double calculatePairDistance(List<RouterInfo> ris, Map<Hash, Points> points,
     421                                         List<Pair> pairs) {
    411422        int sz = ris.size();
    412         List<Pair> pairs = new ArrayList<Pair>(PAIRMAX);
    413423        double total = 0;
    414424        for (int i = 0; i < sz; i++) {
     
    431441
    432442        double avg = total / (sz * sz / 2d);
    433         if (buf != null) {
    434             buf.append("<h3 class=\"sybils\">Average Floodfill Distance is ").append(fmt.format(avg)).append("</h3>" +
    435                        "<h3 id=\"pairs\" class=\"sybils\">Closest Floodfill Pairs by Hash</h3>");
    436         }
    437443        for (Pair p : pairs) {
    438444            double distance = biLog2(p.dist);
     
    440446            if (point < 0)
    441447                break;  // sorted;
    442             if (buf != null && point >= 2) {
    443                 // limit display
    444                 buf.append("<p class=\"hashdist\"><b>Hash Distance: ").append(fmt.format(distance)).append(": </b>" +
    445                            "</p>");
    446                 renderRouterInfo(buf, p.r1, null, false, false);
    447                 renderRouterInfo(buf, p.r2, null, false, false);
    448             }
    449448            point *= PAIR_DISTANCE_FACTOR;
    450449            String b2 = p.r2.getHash().toBase64();
     
    455454                          ") to other floodfill <a href=\"netdb?r=" + b1 + "\">" + b1 + "</a>");
    456455        }
    457         if (buf != null) {
    458             out.write(buf.toString());
    459             out.flush();
    460             buf.setLength(0);
    461         }
     456        return avg;
     457    }
     458
     459    /**
     460     *  @param pairs sorted
     461     */
     462    private void renderPairDistance(Writer out, StringBuilder buf, List<Pair> pairs, double avg) throws IOException {
     463        buf.append("<h3 class=\"sybils\">Average Floodfill Distance is ").append(fmt.format(avg)).append("</h3>" +
     464                   "<h3 id=\"pairs\" class=\"sybils\">Closest Floodfill Pairs by Hash</h3>");
     465
     466        for (Pair p : pairs) {
     467            double distance = biLog2(p.dist);
     468            double point = MIN_CLOSE - distance;
     469            // limit display
     470            if (point < 2)
     471                break;  // sorted;
     472            buf.append("<p class=\"hashdist\"><b>Hash Distance: ").append(fmt.format(distance)).append("</b>" +
     473                       "</p>");
     474            renderRouterInfo(buf, p.r1, null, false, false);
     475            renderRouterInfo(buf, p.r2, null, false, false);
     476        }
     477
     478        out.write(buf.toString());
     479        out.flush();
     480        buf.setLength(0);
    462481    }
    463482
     
    483502
    484503    private static class FooComparator implements Comparator<Integer>, Serializable {
    485          private final ObjectCounter<Integer> _o;
    486          public FooComparator(ObjectCounter<Integer> o) { _o = o;}
     504         private final Map<Integer, List<RouterInfo>> _o;
     505         public FooComparator(Map<Integer, List<RouterInfo>> o) { _o = o;}
    487506         public int compare(Integer l, Integer r) {
    488507             // reverse by count
    489              int rv = _o.count(r) - _o.count(l);
     508             int rv = _o.get(r).size() - _o.get(l).size();
    490509             if (rv != 0)
    491510                 return rv;
     
    496515
    497516    private static class FoofComparator implements Comparator<String>, Serializable {
    498          private final ObjectCounter<String> _o;
     517         private final Map<String, List<RouterInfo>> _o;
    499518         private final Collator _comp = Collator.getInstance();
    500          public FoofComparator(ObjectCounter<String> o) { _o = o;}
     519         public FoofComparator(Map<String, List<RouterInfo>> o) { _o = o;}
    501520         public int compare(String l, String r) {
    502521             // reverse by count
    503              int rv = _o.count(r) - _o.count(l);
     522             int rv = _o.get(r).size() - _o.get(l).size();
    504523             if (rv != 0)
    505524                 return rv;
     
    510529
    511530    /**
    512      *  @param out null for background analysis
    513      *  @param buf null for background analysis
    514      */
    515     private void renderIPGroupsUs(Writer out, StringBuilder buf, List<RouterInfo> ris, Map<Hash, Points> points) throws IOException {
     531     *  @param ri32 out parameter
     532     *  @param ri24 out parameter
     533     *  @param ri16 out parameter
     534     *  @since 0.9.38 split out from renderIPGroupsUs()
     535     */
     536    private void calculateIPGroupsUs(List<RouterInfo> ris, Map<Hash, Points> points,
     537                                     List<RouterInfo> ri32, List<RouterInfo> ri24, List<RouterInfo> ri16) {
    516538        RouterInfo us = _context.router().getRouterInfo();
    517539        byte[] ourIP = getIP(us);
    518540        if (ourIP == null)
    519541            return;
    520         if (buf != null)
    521             buf.append("<h3 id=\"ourIP\" class=\"sybils\">Floodfills close to Our IP</h3>");
    522         boolean found = false;
    523542        for (RouterInfo info : ris) {
    524543            byte[] ip = getIP(info);
     
    526545                continue;
    527546            if (ip[0] == ourIP[0] && ip[1] == ourIP[1]) {
    528                 if (buf != null)
    529                     buf.append("<p id=\"sybil_info\"><b>");
    530547                if (ip[2] == ourIP[2]) {
    531548                    if (ip[3] == ourIP[3]) {
    532                         if (buf != null)
    533                             buf.append("Same IP as us");
    534549                        addPoints(points, info.getHash(), POINTS_US32, "Same IP as us");
    535550                    } else {
    536                         if (buf != null)
    537                             buf.append("Same /24 as us");
    538551                        addPoints(points, info.getHash(), POINTS_US24, "Same /24 as us");
    539552                    }
    540553                } else {
    541                     if (buf != null)
    542                         buf.append("Same /16 as us");
    543554                    addPoints(points, info.getHash(), POINTS_US16, "Same /16 as us");
    544555                }
    545                 if (buf != null) {
    546                     buf.append(":</b></p>");
    547                     renderRouterInfo(buf, info, null, false, false);
    548                 }
    549                 found = true;
    550             }
    551         }
    552         if (buf != null) {
    553             if (!found)
    554                 buf.append("<p class=\"notfound\">None</p>");
    555             out.write(buf.toString());
    556             out.flush();
    557             buf.setLength(0);
    558         }
    559     }
    560 
    561     /**
    562      *  @param out null for background analysis
    563      *  @param buf null for background analysis
    564      */
    565     private void renderIPGroups32(Writer out, StringBuilder buf, List<RouterInfo> ris, Map<Hash, Points> points) throws IOException {
    566         if (buf != null)
    567             buf.append("<h3 id=\"sameIP\" class=\"sybils\">Floodfills with the Same IP</h3>");
     556            }
     557        }
     558    }
     559
     560    /**
     561     *
     562     */
     563    private void renderIPGroupsUs(Writer out, StringBuilder buf, List<RouterInfo> ri32,
     564                                  List<RouterInfo> ri24, List<RouterInfo> ri16) throws IOException {
     565        buf.append("<h3 id=\"ourIP\" class=\"sybils\">Floodfills close to Our IP</h3>");
     566        boolean found = false;
     567        for (RouterInfo info : ri32) {
     568             buf.append("<p id=\"sybil_info\"><b>");
     569             buf.append("Same IP as us");
     570             buf.append(":</b></p>");
     571             renderRouterInfo(buf, info, null, false, false);
     572             found = true;
     573        }
     574        for (RouterInfo info : ri24) {
     575             buf.append("<p id=\"sybil_info\"><b>");
     576             buf.append("Same /24 as us");
     577             buf.append(":</b></p>");
     578             renderRouterInfo(buf, info, null, false, false);
     579             found = true;
     580        }
     581        for (RouterInfo info : ri16) {
     582             buf.append("<p id=\"sybil_info\"><b>");
     583             buf.append("Same /16 as us");
     584             buf.append(":</b></p>");
     585             renderRouterInfo(buf, info, null, false, false);
     586             found = true;
     587        }
     588        if (!found)
     589            buf.append("<p class=\"notfound\">None</p>");
     590        out.write(buf.toString());
     591        out.flush();
     592        buf.setLength(0);
     593    }
     594
     595    /**
     596     *  @since 0.9.38 split out from renderIPGroups32()
     597     */
     598    private Map<Integer, List<RouterInfo>> calculateIPGroups32(List<RouterInfo> ris, Map<Hash, Points> points) {
    568599        ObjectCounter<Integer> oc = new ObjectCounter<Integer>();
    569600        for (RouterInfo info : ris) {
     
    574605            oc.increment(x);
    575606        }
    576         List<Integer> foo = new ArrayList<Integer>();
     607        Map<Integer, List<RouterInfo>> rv = new HashMap<Integer, List<RouterInfo>>();
    577608        for (Integer ii : oc.objects()) {
    578609            int count = oc.count(ii);
    579610            if (count >= 2)
    580                 foo.add(ii);
    581         }
    582         Collections.sort(foo, new FooComparator(oc));
    583         boolean found = false;
    584         for (Integer ii : foo) {
     611                rv.put(ii, new ArrayList<RouterInfo>(4));
     612        }
     613        for (Map.Entry<Integer, List<RouterInfo>> e : rv.entrySet()) {
     614            Integer ii = e.getKey();
    585615            int count = oc.count(ii);
    586616            int i = ii.intValue();
     
    589619            int i2 = (i >> 8) & 0xff;
    590620            int i3 = i & 0xff;
    591             String sip = i0 + "." + i1 + '.' + i2 + '.' + i3;
    592             if (buf != null) {
    593                 buf.append("<p class=\"sybil_info\"><b>").append(count).append(" floodfills with IP <a href=\"/netdb?ip=")
    594                    .append(sip).append("&amp;sybil\">").append(sip)
    595                    .append("</a>:</b></p>");
    596             }
    597621            for (RouterInfo info : ris) {
    598622                byte[] ip = getIP(info);
     
    607631                if ((ip[3] & 0xff) != i3)
    608632                    continue;
    609                 found = true;
    610                 if (buf != null)
    611                     renderRouterInfo(buf, info, null, false, false);
     633                e.getValue().add(info);
    612634                double point = POINTS32 * (count - 1);
    613635                addPoints(points, info.getHash(), point, "Same IP with " + (count - 1) + " other" + (( count > 2) ? "s" : ""));
    614636            }
    615637        }
    616         if (buf != null) {
    617             if (!found)
    618                 buf.append("<p class=\"notfound\">None</p>");
    619             out.write(buf.toString());
    620             out.flush();
    621             buf.setLength(0);
    622         }
    623     }
    624 
    625     /**
    626      *  @param out null for background analysis
    627      *  @param buf null for background analysis
    628      */
    629     private void renderIPGroups24(Writer out, StringBuilder buf, List<RouterInfo> ris, Map<Hash, Points> points) throws IOException {
    630         if (buf != null)
    631             buf.append("<h3 id=\"same24\" class=\"sybils\">Floodfills in the Same /24 (2 minimum)</h3>");
     638        return rv;
     639    }
     640
     641    /**
     642     *
     643     */
     644    private void renderIPGroups32(Writer out, StringBuilder buf, Map<Integer, List<RouterInfo>> map) throws IOException {
     645        buf.append("<h3 id=\"sameIP\" class=\"sybils\">Floodfills with the Same IP</h3>");
     646        List<Integer> foo = new ArrayList<Integer>(map.keySet());
     647        Collections.sort(foo, new FooComparator(map));
     648        boolean found = false;
     649        for (Integer ii : foo) {
     650            List<RouterInfo> ris = map.get(ii);
     651            int count = ris.size();
     652            int i = ii.intValue();
     653            int i0 = (i >> 24) & 0xff;
     654            int i1 = (i >> 16) & 0xff;
     655            int i2 = (i >> 8) & 0xff;
     656            int i3 = i & 0xff;
     657            String sip = i0 + "." + i1 + '.' + i2 + '.' + i3;
     658            buf.append("<p class=\"sybil_info\"><b>").append(count).append(" floodfills with IP <a href=\"/netdb?ip=")
     659               .append(sip).append("&amp;sybil\">").append(sip)
     660               .append("</a>:</b></p>");
     661            for (RouterInfo info : ris) {
     662                found = true;
     663                renderRouterInfo(buf, info, null, false, false);
     664            }
     665        }
     666        if (!found)
     667            buf.append("<p class=\"notfound\">None</p>");
     668        out.write(buf.toString());
     669        out.flush();
     670        buf.setLength(0);
     671    }
     672
     673    /**
     674     *  @since 0.9.38 split out from renderIPGroups24()
     675     */
     676    private Map<Integer, List<RouterInfo>> calculateIPGroups24(List<RouterInfo> ris, Map<Hash, Points> points) {
    632677        ObjectCounter<Integer> oc = new ObjectCounter<Integer>();
    633678        for (RouterInfo info : ris) {
     
    638683            oc.increment(x);
    639684        }
    640         List<Integer> foo = new ArrayList<Integer>();
     685        Map<Integer, List<RouterInfo>> rv = new HashMap<Integer, List<RouterInfo>>();
    641686        for (Integer ii : oc.objects()) {
    642687            int count = oc.count(ii);
    643688            if (count >= 2)
    644                 foo.add(ii);
    645         }
    646         Collections.sort(foo, new FooComparator(oc));
    647         boolean found = false;
    648         for (Integer ii : foo) {
     689                rv.put(ii, new ArrayList<RouterInfo>(4));
     690        }
     691        for (Map.Entry<Integer, List<RouterInfo>> e : rv.entrySet()) {
     692            Integer ii = e.getKey();
    649693            int count = oc.count(ii);
    650694            int i = ii.intValue();
     
    652696            int i1 = (i >> 8) & 0xff;
    653697            int i2 = i & 0xff;
    654             String sip = i0 + "." + i1 + '.' + i2 + ".0/24";
    655             if (buf != null) {
    656                 buf.append("<p class=\"sybil_info\"><b>").append(count).append(" floodfills with IP <a href=\"/netdb?ip=")
    657                    .append(sip).append("&amp;sybil\">").append(sip)
    658                    .append("</a>:</b></p>");
    659             }
    660698            for (RouterInfo info : ris) {
    661699                byte[] ip = getIP(info);
     
    668706                if ((ip[2] & 0xff) != i2)
    669707                    continue;
    670                 found = true;
    671                 if (buf != null)
    672                     renderRouterInfo(buf, info, null, false, false);
     708                e.getValue().add(info);
    673709                double point = POINTS24 * (count - 1);
    674710                addPoints(points, info.getHash(), point, "Same /24 IP with " + (count - 1) + " other" + (( count > 2) ? "s" : ""));
    675711            }
    676712        }
    677         if (buf != null) {
    678             if (!found)
    679                 buf.append("<p class=\"notfound\">None</p>");
    680             out.write(buf.toString());
    681             out.flush();
    682             buf.setLength(0);
    683         }
    684     }
    685 
    686     /**
    687      *  @param out null for background analysis
    688      *  @param buf null for background analysis
    689      */
    690     private void renderIPGroups16(Writer out, StringBuilder buf, List<RouterInfo> ris, Map<Hash, Points> points) throws IOException {
    691         if (buf != null)
    692             buf.append("<h3 id=\"same16\" class=\"sybils\">Floodfills in the Same /16 (4 minimum)</h3>");
     713        return rv;
     714    }
     715
     716    /**
     717     *
     718     */
     719    private void renderIPGroups24(Writer out, StringBuilder buf, Map<Integer, List<RouterInfo>> map) throws IOException {
     720        buf.append("<h3 id=\"same24\" class=\"sybils\">Floodfills in the Same /24 (2 minimum)</h3>");
     721        List<Integer> foo = new ArrayList<Integer>(map.keySet());
     722        Collections.sort(foo, new FooComparator(map));
     723        boolean found = false;
     724        for (Integer ii : foo) {
     725            List<RouterInfo> ris = map.get(ii);
     726            int count = ris.size();
     727            int i = ii.intValue();
     728            int i0 = i >> 16;
     729            int i1 = (i >> 8) & 0xff;
     730            int i2 = i & 0xff;
     731            String sip = i0 + "." + i1 + '.' + i2 + ".0/24";
     732            buf.append("<p class=\"sybil_info\"><b>").append(count).append(" floodfills with IP <a href=\"/netdb?ip=")
     733               .append(sip).append("&amp;sybil\">").append(sip)
     734               .append("</a>:</b></p>");
     735            for (RouterInfo info : ris) {
     736                found = true;
     737                renderRouterInfo(buf, info, null, false, false);
     738            }
     739        }
     740        if (!found)
     741            buf.append("<p class=\"notfound\">None</p>");
     742        out.write(buf.toString());
     743        out.flush();
     744        buf.setLength(0);
     745    }
     746
     747    /**
     748     *  @since 0.9.38 split out from renderIPGroups16()
     749     */
     750    private Map<Integer, List<RouterInfo>> calculateIPGroups16(List<RouterInfo> ris, Map<Hash, Points> points) {
    693751        ObjectCounter<Integer> oc = new ObjectCounter<Integer>();
    694752        for (RouterInfo info : ris) {
     
    699757            oc.increment(x);
    700758        }
    701         List<Integer> foo = new ArrayList<Integer>();
     759        Map<Integer, List<RouterInfo>> rv = new HashMap<Integer, List<RouterInfo>>();
    702760        for (Integer ii : oc.objects()) {
    703761            int count = oc.count(ii);
    704762            if (count >= 4)
    705                 foo.add(ii);
    706         }
    707         Collections.sort(foo, new FooComparator(oc));
     763                rv.put(ii, new ArrayList<RouterInfo>(8));
     764        }
     765        for (Map.Entry<Integer, List<RouterInfo>> e : rv.entrySet()) {
     766            Integer ii = e.getKey();
     767            int count = oc.count(ii);
     768            int i = ii.intValue();
     769            int i0 = i >> 8;
     770            int i1 = i & 0xff;
     771            for (RouterInfo info : ris) {
     772                byte[] ip = getIP(info);
     773                if (ip == null)
     774                    continue;
     775                if ((ip[0] & 0xff) != i0)
     776                    continue;
     777                if ((ip[1] & 0xff) != i1)
     778                    continue;
     779                e.getValue().add(info);
     780                double point = POINTS16 * (count - 1);
     781                addPoints(points, info.getHash(), point, "Same /16 IP with " + (count - 1) + " other" + (( count > 2) ? "s" : ""));
     782            }
     783        }
     784        return rv;
     785    }
     786
     787    /**
     788     *
     789     */
     790    private void renderIPGroups16(Writer out, StringBuilder buf, Map<Integer, List<RouterInfo>> map) throws IOException {
     791        buf.append("<h3 id=\"same16\" class=\"sybils\">Floodfills in the Same /16 (4 minimum)</h3>");
     792        List<Integer> foo = new ArrayList<Integer>(map.keySet());
     793        Collections.sort(foo, new FooComparator(map));
    708794        boolean found = false;
    709795        for (Integer ii : foo) {
    710             int count = oc.count(ii);
     796            List<RouterInfo> ris = map.get(ii);
     797            int count = ris.size();
    711798            int i = ii.intValue();
    712799            int i0 = i >> 8;
     
    719806            }
    720807            for (RouterInfo info : ris) {
    721                 byte[] ip = getIP(info);
    722                 if (ip == null)
    723                     continue;
    724                 if ((ip[0] & 0xff) != i0)
    725                     continue;
    726                 if ((ip[1] & 0xff) != i1)
    727                     continue;
    728808                found = true;
    729                 // limit display
    730                 //renderRouterInfo(buf, info, null, false, false);
    731                 double point = POINTS16 * (count - 1);
    732                 addPoints(points, info.getHash(), point, "Same /16 IP with " + (count - 1) + " other" + (( count > 2) ? "s" : ""));
    733             }
    734         }
    735         if (buf != null) {
    736             if (!found)
    737                 buf.append("<p class=\"notfound\">None</p>");
    738             out.write(buf.toString());
    739             out.flush();
    740             buf.setLength(0);
    741         }
    742     }
    743 
    744     /**
    745      *  @param out null for background analysis
    746      *  @param buf null for background analysis
    747      */
    748     private void renderIPGroupsFamily(Writer out, StringBuilder buf, List<RouterInfo> ris, Map<Hash, Points> points) throws IOException {
    749         if (buf != null)
    750             buf.append("<h3 id=\"samefamily\" class=\"sybils\">Floodfills in the same Family</h3><div class=\"sybil_container\">");
     809                renderRouterInfo(buf, info, null, false, false);
     810            }
     811        }
     812        if (!found)
     813            buf.append("<p class=\"notfound\">None</p>");
     814        out.write(buf.toString());
     815        out.flush();
     816        buf.setLength(0);
     817    }
     818
     819    /**
     820     *  @since 0.9.38 split out from renderIPGroupsFamily()
     821     */
     822    private Map<String, List<RouterInfo>> calculateIPGroupsFamily(List<RouterInfo> ris, Map<Hash, Points> points) {
    751823        ObjectCounter<String> oc = new ObjectCounter<String>();
    752824        for (RouterInfo info : ris) {
     
    757829        }
    758830        List<String> foo = new ArrayList<String>(oc.objects());
    759         Collections.sort(foo, new FoofComparator(oc));
     831        Map<String, List<RouterInfo>> rv = new HashMap<String, List<RouterInfo>>(foo.size());
    760832        FamilyKeyCrypto fkc = _context.router().getFamilyKeyCrypto();
    761833        String ourFamily = fkc != null ? fkc.getOurFamilyName() : null;
    762         boolean found = false;
    763834        for (String s : foo) {
    764835            int count = oc.count(s);
     836            List<RouterInfo> list = new ArrayList<RouterInfo>(count);
     837            rv.put(s, list);
    765838            String ss = DataHelper.escapeHTML(s);
    766             if (buf != null && count > 1) {
    767                 buf.append("<p class=\"family\"><b>").append(count).append(" floodfills in family: &nbsp;<a href=\"/netdb?fam=")
    768                    .append(ss).append("&amp;sybil\">").append(ss).append("</a></b></p>");
    769             }
    770839            for (RouterInfo info : ris) {
    771840                String fam = info.getOption("family");
     
    774843                if (!fam.equals(s))
    775844                    continue;
    776                 found = true;
    777                 // limit display
    778                 //renderRouterInfo(buf, info, null, false, false);
     845                list.add(info);
    779846                double point = POINTS_FAMILY;
    780847                if (fkc != null && s.equals(ourFamily)) {
     
    790857            }
    791858        }
    792         if (buf != null) {
    793             if (!found)
    794                 buf.append("<p class=\"notfound\">None</p>");
    795             buf.append("</div>");
    796             out.write(buf.toString());
    797             out.flush();
    798             buf.setLength(0);
    799         }
     859        return rv;
     860    }
     861
     862    /**
     863     *
     864     */
     865    private void renderIPGroupsFamily(Writer out, StringBuilder buf, Map<String, List<RouterInfo>> map) throws IOException {
     866        buf.append("<h3 id=\"samefamily\" class=\"sybils\">Floodfills in the same Family</h3><div class=\"sybil_container\">");
     867        List<String> foo = new ArrayList<String>(map.keySet());
     868        Collections.sort(foo, new FoofComparator(map));
     869        FamilyKeyCrypto fkc = _context.router().getFamilyKeyCrypto();
     870        String ourFamily = fkc != null ? fkc.getOurFamilyName() : null;
     871        boolean found = false;
     872        for (String s : foo) {
     873            List<RouterInfo> list = map.get(s);
     874            int count = list.size();
     875            String ss = DataHelper.escapeHTML(s);
     876            if (count > 1) {
     877                buf.append("<p class=\"family\"><b>").append(count).append(" floodfills in family: &nbsp;<a href=\"/netdb?fam=")
     878                   .append(ss).append("&amp;sybil\">").append(ss).append("</a></b></p>");
     879                found = true;
     880            }
     881            //for (RouterInfo info : ris) {
     882                // limit display
     883                //renderRouterInfo(buf, info, null, false, false);
     884            //}
     885        }
     886        if (!found)
     887            buf.append("<p class=\"notfound\">None</p>");
     888        buf.append("</div>");
     889        out.write(buf.toString());
     890        out.flush();
     891        buf.setLength(0);
    800892    }
    801893
     
    879971
    880972    /**
    881      *  @param out null for background analysis
    882      *  @param buf null for background analysis
    883973     *  @param usName HTML escaped
    884      */
    885     private void renderRouterInfoHTML(Writer out, StringBuilder buf, Hash us, String usName, double avgMinDist,
    886                                       List<RouterInfo> ris, Map<Hash, Points> points) throws IOException {
     974     *  @param ris will be re-sorted in place
     975     *  @since 0.9.38 split out from renderRouterInfoHTML()
     976     */
     977    private void calculateRouterInfo(Hash us, String usName,
     978                                     List<RouterInfo> ris, Map<Hash, Points> points) {
    887979        Collections.sort(ris, new RouterInfoRoutingKeyComparator(us));
     980        int count = Math.min(MAX, ris.size());
     981        for (int i = 0; i < count; i++) {
     982            RouterInfo ri = ris.get(i);
     983            BigInteger bidist = HashDistance.getDistance(us, ri.getHash());
     984            double dist = biLog2(bidist);
     985            double point = MIN_CLOSE - dist;
     986            if (point <= 0)
     987                break;
     988            point *= OUR_KEY_FACTOR;
     989            addPoints(points, ri.getHash(), point, "Very close (" + fmt.format(dist) + ") to our key " + usName + ": " + us.toBase64());
     990        }
     991    }
     992
     993    /**
     994     *  Render routers closer than MIN_CLOSE up to MAX routers
     995     *  @param ris sorted, closest first
     996     *  @param usName HTML escaped
     997     */
     998    private void renderRouterInfoHTML(Writer out, StringBuilder buf, Hash us, double avgMinDist,
     999                                      List<RouterInfo> ris) throws IOException {
    8881000        double min = 256;
    8891001        double max = 0;
     
    8951007        for (int i = 0; i < count; i++) {
    8961008            RouterInfo ri = ris.get(i);
    897             double dist;
    898             if (buf != null) {
    899                 dist = renderRouterInfo(buf, ri, us, false, false);
    900             } else {
    901                 BigInteger bidist = HashDistance.getDistance(us, ri.getHash());
    902                 dist = biLog2(bidist);
    903             }
    904             if (buf != null && dist < avgMinDist) {
     1009            double dist = renderRouterInfo(buf, ri, us, false, false);
     1010            if (dist < MIN_CLOSE)
     1011                break;
     1012            if (dist < avgMinDist) {
    9051013                if (i == 0) {
    9061014                    //buf.append("<p><b>Not to worry, but above router is closer than average minimum distance " + fmt.format(avgMinDist) + "</b></p>");
     
    9231031            else if (i == medIdx + 1 && isEven)
    9241032                median = (median + dist) / 2;
    925             double point = MIN_CLOSE - dist;
    926             if (point > 0) {
    927                 point *= OUR_KEY_FACTOR;
    928                 addPoints(points, ri.getHash(), point, "Very close (" + fmt.format(dist) + ") to our key " + usName + ": " + us.toBase64());
    929             }
    930             if (i >= MAX - 1)
    931                 break;
    932         }
    933         if (buf != null) {
    934             double avg = tot / count;
    935             buf.append("<p id=\"sybil_totals\"><b>Totals for " + count + " floodfills: &nbsp;</b><span class=\"netdb_name\">MIN:</span > " + fmt.format(min) + "&nbsp; <span class=\"netdb_name\">AVG:</span> " +
    936                 fmt.format(avg) + "&nbsp; <span class=\"netdb_name\">MEDIAN:</span> " + fmt.format(median) + "&nbsp; <span class=\"netdb_name\">MAX:</span> " + fmt.format(max) + "</p>\n");
    937             out.write(buf.toString());
    938             out.flush();
    939             buf.setLength(0);
    940         }
     1033        }
     1034        double avg = tot / count;
     1035        buf.append("<p id=\"sybil_totals\"><b>Totals for " + count +
     1036                   " floodfills: &nbsp;</b><span class=\"netdb_name\">MIN:</span > " + fmt.format(min) +
     1037                   "&nbsp; <span class=\"netdb_name\">AVG:</span> " + fmt.format(avg) +
     1038                   "&nbsp; <span class=\"netdb_name\">MEDIAN:</span> " + fmt.format(median) +
     1039                   "&nbsp; <span class=\"netdb_name\">MAX:</span> " + fmt.format(max) +
     1040                   "</p>\n");
     1041        out.write(buf.toString());
     1042        out.flush();
     1043        buf.setLength(0);
    9411044    }
    9421045
Note: See TracChangeset for help on using the changeset viewer.