Changeset 156d868


Ignore:
Timestamp:
Sep 13, 2014 2:50:11 PM (7 years ago)
Author:
zzz <zzz@…>
Branches:
master
Children:
5183b44d
Parents:
eab4397 (diff), 42eb43f (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

propagate from branch 'i2p.i2p' (head 60a9a2297abeaf042645e3f0bc8d106f1ff585bf)

to branch 'i2p.i2p.zzz.test2' (head 6ff6f0bcee835d32aad62449a37f5171afde915a)

Files:
9 added
127 edited
22 moved

Legend:

Unmodified
Added
Removed
  • apps/i2psnark/java/build.xml

    reab4397 r156d868  
    101101        <!-- set if unset -->
    102102        <property name="workspace.changes.tr" value="" />
    103         <copy todir="build/icons/.icons" >
    104             <fileset dir="../icons/" />
     103        <copy todir="build/resources/.resources" >
     104            <fileset dir="../resources/" />
    105105        </copy>
    106106        <!-- mime.properties must be in with the classes -->
     
    109109          <!-- include only the web stuff, as of 0.7.12 the router will add i2psnark.jar to the classpath for the war -->
    110110          <classes dir="./build/obj" includes="**/web/*" />
    111             <fileset dir="build/icons/" />
     111            <fileset dir="build/resources/" />
    112112            <manifest>
    113113                <attribute name="Implementation-Version" value="${full.version}" />
     
    122122    <target name="warUpToDate">
    123123        <uptodate property="war.uptodate" targetfile="../i2psnark.war" >
    124             <srcfiles dir= "." includes="build/obj/org/klomp/snark/web/*.class ../icons/* ../web.xml" />
     124            <srcfiles dir= "." includes="build/obj/org/klomp/snark/web/*.class ../resources/**/* ../web.xml" />
    125125        </uptodate>
    126126    </target>
  • apps/i2psnark/java/src/org/klomp/snark/Peer.java

    reab4397 r156d868  
    5858
    5959  /** running counters */
    60   private long downloaded;
    61   private long uploaded;
     60  private final AtomicLong downloaded = new AtomicLong();
     61  private final AtomicLong uploaded = new AtomicLong();
    6262
    6363  // Keeps state for in/out connections.  Non-null when the handshake
     
    619619   */
    620620  public void downloaded(int size) {
    621       downloaded += size;
     621      downloaded.addAndGet(size);
    622622  }
    623623
     
    627627   */
    628628  public void uploaded(int size) {
    629       uploaded += size;
     629      uploaded.addAndGet(size);
    630630  }
    631631
     
    636636  public long getDownloaded()
    637637  {
    638       return downloaded;
     638      return downloaded.get();
    639639  }
    640640
     
    645645  public long getUploaded()
    646646  {
    647       return uploaded;
     647      return uploaded.get();
    648648  }
    649649
     
    653653  public void resetCounters()
    654654  {
    655       downloaded = 0;
    656       uploaded = 0;
     655      downloaded.set(0);
     656      uploaded.set(0);
    657657  }
    658658 
  • apps/i2psnark/java/src/org/klomp/snark/Snark.java

    reab4397 r156d868  
    2828import java.util.List;
    2929import java.util.Properties;
    30 import java.util.Random;
    3130import java.util.StringTokenizer;
    3231
     
    246245   * @deprecated unused
    247246   */
     247/****
    248248  Snark(I2PSnarkUtil util, String torrent, String ip, int user_port,
    249249        StorageListener slistener, CoordinatorListener clistener) {
    250250    this(util, torrent, ip, user_port, slistener, clistener, null, null, null, true, ".");
    251251  }
     252****/
    252253
    253254  /**
     
    256257   * @deprecated unused
    257258   */
     259/****
    258260  public Snark(I2PAppContext ctx, Properties opts, String torrent,
    259261               StorageListener slistener, boolean start, String rootDir) {
     
    285287        this.startTorrent();
    286288  }
     289****/
    287290
    288291  /**
     
    516519    // Create a new ID and fill it with something random.  First nine
    517520    // zeros bytes, then three bytes filled with snark and then
    518     // sixteen random bytes.
     521    // eight random bytes.
    519522    byte snark = (((3 + 7 + 10) * (1000 - 8)) / 992) - 17;
    520523    byte[] rv = new byte[20];
    521     Random random = I2PAppContext.getGlobalContext().random();
    522     int i;
    523     for (i = 0; i < 9; i++)
    524       rv[i] = 0;
    525     rv[i++] = snark;
    526     rv[i++] = snark;
    527     rv[i++] = snark;
    528     while (i < 20)
    529       rv[i++] = (byte)random.nextInt(256);
     524    rv[9] = snark;
     525    rv[10] = snark;
     526    rv[11] = snark;
     527    I2PAppContext.getGlobalContext().random().nextBytes(rv, 12, 8);
    530528    return rv;
    531529  }
     
    959957   * passed to all components that take one.
    960958   */
     959/****
    961960  private static Snark parseArguments(String[] args,
    962961                              StorageListener slistener,
     
    973972    while (i < args.length)
    974973      {
     974****/
    975975/*
    976976        if (args[i].equals("--debug"))
     
    994994              }
    995995          }
    996         else */ if (args[i].equals("--port"))
     996        else */
     997/****
     998          if (args[i].equals("--port"))
    997999          {
    9981000            if (args.length - 1 < i + 1)
     
    11001102      ("         \tor (with --share) a file to share.");
    11011103  }
     1104****/
    11021105
    11031106  /**
  • apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java

    reab4397 r156d868  
    6262    private static final String DEFAULT_NAME = "i2psnark";
    6363    public static final String PROP_CONFIG_FILE = "i2psnark.configFile";
    64     private static final String WARBASE = "/.icons/";
     64    private static final String WARBASE = "/.resources/";
    6565    private static final char HELLIP = '\u2026';
    6666 
     
    195195        resp.setHeader("X-XSS-Protection", "1; mode=block");
    196196
    197         String peerParam = req.getParameter("p");
    198         String stParam = req.getParameter("st");
    199         String peerString;
    200         if (peerParam == null || (!_manager.util().connected()) ||
    201             peerParam.replaceAll("[a-zA-Z0-9~=-]", "").length() > 0) {  // XSS
    202             peerString = "";
    203         } else {
    204             peerString = "?p=" + DataHelper.stripHTML(peerParam);
    205         }
    206         if (stParam != null && !stParam.equals("0")) {
    207             stParam = DataHelper.stripHTML(stParam);
    208             if (peerString.length() > 0)
    209                 peerString += "&amp;st=" + stParam;
    210             else
    211                 peerString =  "?st="+ stParam;
    212         }
     197        String pOverride = _manager.util().connected() ? null : "";
     198        String peerString = getQueryString(req, pOverride, null, null);
    213199
    214200        // AJAX for mainsection
     
    293279        else
    294280            out.write(_("Anonymous BitTorrent Client"));
     281        String peerParam = req.getParameter("p");
    295282        if ("2".equals(peerParam))
    296283            out.write(" | Debug Mode");
     
    414401        if (isForm) {
    415402            out.write("<form action=\"_post\" method=\"POST\">\n");
    416             out.write("<input type=\"hidden\" name=\"nonce\" value=\"" + _nonce + "\" >\n");
    417             // don't lose peer setting
    418             if (peerParam != null)
    419                 out.write("<input type=\"hidden\" name=\"p\" value=\"" + peerParam + "\" >\n");
    420             // ...or st setting
    421             if (stParam != null)
    422                 out.write("<input type=\"hidden\" name=\"st\" value=\"" + stParam + "\" >\n");
     403            writeHiddenInputs(out, req, null);
    423404        }
    424405        out.write(TABLE_HEADER);
     
    442423        int pageSize = Math.max(_manager.getPageSize(), 5);
    443424
    444         out.write("<tr><th><img border=\"0\" src=\"" + _imgPath + "status.png\" title=\"");
    445         out.write(_("Status"));
     425        String currentSort = req.getParameter("sort");
     426        boolean showSort = total > 1;
     427        out.write("<tr><th>");
     428        String sort = ("2".equals(currentSort)) ? "-2" : "2";
     429        if (showSort) {
     430            out.write("<a href=\"" + _contextPath + '/' + getQueryString(req, null, null, sort));
     431            out.write("\">");
     432        }
     433        out.write("<img border=\"0\" src=\"" + _imgPath + "status.png\" title=\"");
     434        if (showSort)
     435            out.write(_("Sort by {0}", _("Status")));
     436        else
     437            out.write(_("Status"));
    446438        out.write("\" alt=\"");
    447439        out.write(_("Status"));
    448         out.write("\"></th>\n<th>");
     440        out.write("\">");
     441        if (showSort)
     442            out.write("</a>");
     443        out.write("</th>\n<th>");
    449444        if (_manager.util().connected() && !snarks.isEmpty()) {
    450445            out.write(" <a href=\"" + _contextPath + '/');
    451446            if (peerParam != null) {
    452                 if (stParam != null) {
    453                     out.write("?st=");
    454                     out.write(stParam);
    455                 }
     447                // disable peer view
    456448                out.write("\">");
    457449                out.write("<img border=\"0\" src=\"" + _imgPath + "hidepeers.png\" title=\"");
     
    461453                out.write("\">");
    462454            } else {
    463                 out.write("?p=1");
    464                 if (stParam != null) {
    465                     out.write("&amp;st=");
    466                     out.write(stParam);
    467                 }
     455                // enable peer view
     456                out.write(getQueryString(req, "1", null, null));
    468457                out.write("\">");
    469458                out.write("<img border=\"0\" src=\"" + _imgPath + "showpeers.png\" title=\"");
     
    476465        }
    477466        out.write("</th>\n<th colspan=\"2\" align=\"left\">");
     467        // cycle through sort by name or type
     468        boolean isTypeSort = false;
     469        if (showSort) {
     470            if (currentSort == null || "0".equals(currentSort) || "1".equals(currentSort)) {
     471                sort = "-1";
     472            } else if ("-1".equals(currentSort)) {
     473                sort = "12";
     474                isTypeSort = true;
     475            } else if ("12".equals(currentSort)) {
     476                sort = "-12";
     477                isTypeSort = true;
     478            } else {
     479                sort = "";
     480            }
     481            out.write("<a href=\"" + _contextPath + '/' + getQueryString(req, null, null, sort));
     482            out.write("\">");
     483        }
    478484        out.write("<img border=\"0\" src=\"" + _imgPath + "torrent.png\" title=\"");
    479         out.write(_("Torrent"));
     485        if (showSort)
     486            out.write(_("Sort by {0}", (isTypeSort ? _("File type") : _("Torrent"))));
     487        else
     488            out.write(_("Torrent"));
    480489        out.write("\" alt=\"");
    481490        out.write(_("Torrent"));
    482         out.write("\"></th>\n<th align=\"center\">");
     491        out.write("\">");
     492        if (showSort)
     493            out.write("</a>");
     494        out.write("</th>\n<th align=\"center\">");
    483495        if (total > 0 && (start > 0 || total > pageSize)) {
    484             writePageNav(out, start, pageSize, total, peerParam, noThinsp);
     496            writePageNav(out, req, start, pageSize, total, noThinsp);
    485497        }
    486498        out.write("</th>\n<th align=\"right\">");
    487499        if (_manager.util().connected() && !snarks.isEmpty()) {
     500            if (showSort) {
     501                sort = ("4".equals(currentSort)) ? "-4" : "4";
     502                out.write("<a href=\"" + _contextPath + '/' + getQueryString(req, null, null, sort));
     503                out.write("\">");
     504            }
    488505            out.write("<img border=\"0\" src=\"" + _imgPath + "eta.png\" title=\"");
    489             out.write(_("Estimated time remaining"));
     506            if (showSort)
     507                out.write(_("Sort by {0}", _("Estimated time remaining")));
     508            else
     509                out.write(_("Estimated time remaining"));
    490510            out.write("\" alt=\"");
    491511            // Translators: Please keep short or translate as " "
    492512            out.write(_("ETA"));
    493513            out.write("\">");
     514            if (showSort)
     515                out.write("</a>");
    494516        }
    495517        out.write("</th>\n<th align=\"right\">");
     518        // cycle through sort by size or downloaded
     519        boolean isDlSort = false;
     520        if (showSort) {
     521            if ("5".equals(currentSort)) {
     522                sort = "-5";
     523            } else if ("-5".equals(currentSort)) {
     524                sort = "6";
     525                isDlSort = true;
     526            } else if ("6".equals(currentSort)) {
     527                sort = "-6";
     528                isDlSort = true;
     529            } else {
     530                sort = "5";
     531            }
     532            out.write("<a href=\"" + _contextPath + '/' + getQueryString(req, null, null, sort));
     533            out.write("\">");
     534        }
    496535        out.write("<img border=\"0\" src=\"" + _imgPath + "head_rx.png\" title=\"");
    497         out.write(_("Downloaded"));
     536        if (showSort)
     537            out.write(_("Sort by {0}", (isDlSort ? _("Downloaded") : _("Size"))));
     538        else
     539            out.write(_("Downloaded"));
    498540        out.write("\" alt=\"");
    499541        // Translators: Please keep short or translate as " "
    500542        out.write(_("RX"));
    501543        out.write("\">");
     544        if (showSort)
     545            out.write("</a>");
    502546        out.write("</th>\n<th align=\"right\">");
     547        boolean isRatSort = false;
    503548        if (!snarks.isEmpty()) {
     549            // cycle through sort by uploaded or ratio
     550            boolean nextRatSort = false;
     551            if (showSort) {
     552                if ("7".equals(currentSort)) {
     553                    sort = "-7";
     554                } else if ("-7".equals(currentSort)) {
     555                    sort = "11";
     556                    nextRatSort = true;
     557                } else if ("11".equals(currentSort)) {
     558                    sort = "-11";
     559                    nextRatSort = true;
     560                    isRatSort = true;
     561                } else if ("-11".equals(currentSort)) {
     562                    sort = "7";
     563                    isRatSort = true;
     564                } else {
     565                    sort = "7";
     566                }
     567                out.write("<a href=\"" + _contextPath + '/' + getQueryString(req, null, null, sort));
     568                out.write("\">");
     569            }
    504570            out.write("<img border=\"0\" src=\"" + _imgPath + "head_tx.png\" title=\"");
    505             out.write(_("Uploaded"));
     571            if (showSort)
     572                out.write(_("Sort by {0}", (nextRatSort ? _("Upload ratio") : _("Uploaded"))));
     573            else
     574                out.write(_("Uploaded"));
    506575            out.write("\" alt=\"");
    507576            // Translators: Please keep short or translate as " "
    508577            out.write(_("TX"));
    509578            out.write("\">");
     579            if (showSort)
     580                out.write("</a>");
    510581        }
    511582        out.write("</th>\n<th align=\"right\">");
    512583        if (_manager.util().connected() && !snarks.isEmpty()) {
     584            if (showSort) {
     585                sort = ("8".equals(currentSort)) ? "-8" : "8";
     586                out.write("<a href=\"" + _contextPath + '/' + getQueryString(req, null, null, sort));
     587                out.write("\">");
     588            }
    513589            out.write("<img border=\"0\" src=\"" + _imgPath + "head_rxspeed.png\" title=\"");
    514             out.write(_("Down Rate"));
     590            if (showSort)
     591                out.write(_("Sort by {0}", _("Down Rate")));
     592            else
     593                out.write(_("Down Rate"));
    515594            out.write("\" alt=\"");
    516595            // Translators: Please keep short or translate as " "
    517596            out.write(_("RX Rate"));
    518             out.write(" \">");
     597            out.write("\">");
     598            if (showSort)
     599                out.write("</a>");
    519600        }
    520601        out.write("</th>\n<th align=\"right\">");
    521602        if (_manager.util().connected() && !snarks.isEmpty()) {
     603            if (showSort) {
     604                sort = ("9".equals(currentSort)) ? "-9" : "9";
     605                out.write("<a href=\"" + _contextPath + '/' + getQueryString(req, null, null, sort));
     606                out.write("\">");
     607            }
    522608            out.write("<img border=\"0\" src=\"" + _imgPath + "head_txspeed.png\" title=\"");
    523             out.write(_("Up Rate"));
     609            if (showSort)
     610                out.write(_("Sort by {0}", _("Up Rate")));
     611            else
     612                out.write(_("Up Rate"));
    524613            out.write("\" alt=\"");
    525614            // Translators: Please keep short or translate as " "
    526615            out.write(_("TX Rate"));
    527             out.write(" \">");
     616            out.write("\">");
     617            if (showSort)
     618                out.write("</a>");
    528619        }
    529620        out.write("</th>\n<th align=\"center\">");
     
    581672        boolean showDebug = "2".equals(peerParam);
    582673
    583         String stParamStr = stParam == null ? "" : "&amp;st=" + stParam;
    584674        for (int i = 0; i < total; i++) {
    585675            Snark snark = snarks.get(i);
    586676            boolean showPeers = showDebug || "1".equals(peerParam) || Base64.encode(snark.getInfoHash()).equals(peerParam);
    587677            boolean hide = i < start || i >= start + pageSize;
    588             displaySnark(out, snark, uri, i, stats, showPeers, isDegraded, noThinsp, showDebug, hide, stParamStr);
     678            displaySnark(out, req, snark, uri, i, stats, showPeers, isDegraded, noThinsp, showDebug, hide, isRatSort);
    589679        }
    590680
     
    638728   
    639729    /**
     730     *  hidden inputs for nonce and paramters p, st, and sort
     731     *
     732     *  @param out writes to it
     733     *  @param action if non-null, add it as the action
     734     *  @since 0.9.16
     735     */
     736    private void writeHiddenInputs(PrintWriter out, HttpServletRequest req, String action) {
     737        StringBuilder buf = new StringBuilder(256);
     738        writeHiddenInputs(buf, req, action);
     739        out.write(buf.toString());
     740    }
     741   
     742    /**
     743     *  hidden inputs for nonce and paramters p, st, and sort
     744     *
     745     *  @param out appends to it
     746     *  @param action if non-null, add it as the action
     747     *  @since 0.9.16
     748     */
     749    private void writeHiddenInputs(StringBuilder buf, HttpServletRequest req, String action) {
     750        buf.append("<input type=\"hidden\" name=\"nonce\" value=\"")
     751           .append(_nonce).append("\" >\n");
     752        String peerParam = req.getParameter("p");
     753        if (peerParam != null) {
     754            buf.append("<input type=\"hidden\" name=\"p\" value=\"")
     755               .append(DataHelper.stripHTML(peerParam)).append("\" >\n");
     756        }
     757        String stParam = req.getParameter("st");
     758        if (stParam != null) {
     759            buf.append("<input type=\"hidden\" name=\"st\" value=\"")
     760               .append(DataHelper.stripHTML(stParam)).append("\" >\n");
     761        }
     762        String soParam = req.getParameter("sort");
     763        if (soParam != null) {
     764            buf.append("<input type=\"hidden\" name=\"sort\" value=\"")
     765               .append(DataHelper.stripHTML(soParam)).append("\" >\n");
     766        }
     767        if (action != null) {
     768            buf.append("<input type=\"hidden\" name=\"action\" value=\"")
     769               .append(action).append("\" >\n");
     770        }
     771    }
     772   
     773    /**
     774     *  Build HTML-escaped and stripped query string
     775     *
     776     *  @param p override or "" for default or null to keep the same as in req
     777     *  @param st override or "" for default or null to keep the same as in req
     778     *  @param so override or "" for default or null to keep the same as in req
     779     *  @return non-null, possibly empty
     780     *  @since 0.9.16
     781     */
     782    private static String getQueryString(HttpServletRequest req, String p, String st, String so) {
     783        StringBuilder buf = new StringBuilder(64);
     784        if (p == null) {
     785            p = req.getParameter("p");
     786            if (p != null)
     787                p = DataHelper.stripHTML(p);
     788        }
     789        if (p != null && !p.equals(""))
     790            buf.append("?p=").append(p);
     791        if (so == null) {
     792            so = req.getParameter("sort");
     793            if (so != null)
     794                so = DataHelper.stripHTML(so);
     795        }
     796        if (so != null && !so.equals("")) {
     797            if (buf.length() <= 0)
     798                buf.append("?sort=");
     799            else
     800                buf.append("&amp;sort=");
     801            buf.append(so);
     802        }
     803        if (st == null) {
     804            st = req.getParameter("st");
     805            if (st != null)
     806                st = DataHelper.stripHTML(st);
     807        }
     808        if (st != null && !st.equals("")) {
     809            if (buf.length() <= 0)
     810                buf.append("?st=");
     811            else
     812                buf.append("&amp;st=");
     813            buf.append(st);
     814        }
     815        return buf.toString();
     816    }
     817   
     818    /**
    640819     *  @since 0.9.6
    641820     */
    642     private void writePageNav(PrintWriter out, int start, int pageSize, int total,
    643                               String peerParam, boolean noThinsp) {
     821    private void writePageNav(PrintWriter out, HttpServletRequest req, int start, int pageSize, int total,
     822                              boolean noThinsp) {
    644823            // Page nav
    645824            if (start > 0) {
    646825                // First
    647826                out.write("<a href=\"" + _contextPath);
    648                 if (peerParam != null)
    649                     out.write("?p=" + peerParam);
     827                out.write(getQueryString(req, null, "", null));
    650828                out.write("\">" +
    651829                          "<img alt=\"" + _("First") + "\" title=\"" + _("First page") + "\" border=\"0\" src=\"" +
     
    656834                if (true) {
    657835                    // Back
    658                     out.write("&nbsp;<a href=\"" + _contextPath +  "?st=" + prev);
    659                     if (peerParam != null)
    660                         out.write("&amp;p=" + peerParam);
     836                    out.write("&nbsp;<a href=\"" + _contextPath);
     837                    String sprev = (prev > 0) ? Integer.toString(prev) : "";
     838                    out.write(getQueryString(req, null, sprev, null));
    661839                    out.write("\">" +
    662840                          "<img alt=\"" + _("Prev") + "\" title=\"" + _("Previous page") + "\" border=\"0\" src=\"" +
     
    691869                if (true) {
    692870                    // Next
    693                     out.write("&nbsp;<a href=\"" + _contextPath +  "?st=" + next);
    694                     if (peerParam != null)
    695                         out.write("&amp;p=" + peerParam);
     871                    out.write("&nbsp;<a href=\"" + _contextPath);
     872                    out.write(getQueryString(req, null, Integer.toString(next), null));
    696873                    out.write("\">" +
    697874                          "<img alt=\"" + _("Next") + "\" title=\"" + _("Next page") + "\" border=\"0\" src=\"" +
     
    701878                // Last
    702879                int last = ((total - 1) / pageSize) * pageSize;
    703                 out.write("&nbsp;<a href=\"" + _contextPath +  "?st=" + last);
    704                 if (peerParam != null)
    705                     out.write("&amp;p=" + peerParam);
     880                out.write("&nbsp;<a href=\"" + _contextPath);
     881                out.write(getQueryString(req, null, Integer.toString(last), null));
    706882                out.write("\">" +
    707883                          "<img alt=\"" + _("Last") + "\" title=\"" + _("Last page") + "\" border=\"0\" src=\"" +
     
    11911367    }
    11921368
    1193     /**
    1194      *  Sort alphabetically in current locale, ignore case, ignore leading "the "
    1195      *  (I guess this is worth it, a lot of torrents start with "The "
    1196      *  @since 0.7.14
    1197      */
    1198     private static class TorrentNameComparator implements Comparator<Snark>, Serializable {
    1199 
    1200         public int compare(Snark l, Snark r) {
    1201             // put downloads and magnets first
    1202             if (l.getStorage() == null && r.getStorage() != null)
    1203                 return -1;
    1204             if (l.getStorage() != null && r.getStorage() == null)
    1205                 return 1;
    1206             String ls = l.getBaseName();
    1207             String llc = ls.toLowerCase(Locale.US);
    1208             if (llc.startsWith("the ") || llc.startsWith("the.") || llc.startsWith("the_"))
    1209                 ls = ls.substring(4);
    1210             String rs = r.getBaseName();
    1211             String rlc = rs.toLowerCase(Locale.US);
    1212             if (rlc.startsWith("the ") || rlc.startsWith("the.") || rlc.startsWith("the_"))
    1213                 rs = rs.substring(4);
    1214             return Collator.getInstance().compare(ls, rs);
    1215         }
    1216     }
    1217 
    12181369    private List<Snark> getSortedSnarks(HttpServletRequest req) {
    12191370        ArrayList<Snark> rv = new ArrayList<Snark>(_manager.getTorrents());
    1220         Collections.sort(rv, new TorrentNameComparator());
     1371        if (rv.size() > 1) {
     1372            int sort = 0;
     1373            String ssort = req.getParameter("sort");
     1374            if (ssort != null) {
     1375                try {
     1376                    sort = Integer.parseInt(ssort);
     1377                } catch (NumberFormatException nfe) {}
     1378            }
     1379            try {
     1380                Collections.sort(rv, Sorters.getComparator(sort, this));
     1381            } catch (IllegalArgumentException iae) {
     1382                // Java 7 TimSort - may be unstable
     1383            }
     1384        }
    12211385        return rv;
    12221386    }
     
    12301394     *  @param stats in/out param (totals)
    12311395     *  @param statsOnly if true, output nothing, update stats only
    1232      *  @param stParam non null; empty or e.g. &amp;st=10
    12331396     */
    1234     private void displaySnark(PrintWriter out, Snark snark, String uri, int row, long stats[], boolean showPeers,
     1397    private void displaySnark(PrintWriter out, HttpServletRequest req,
     1398                              Snark snark, String uri, int row, long stats[], boolean showPeers,
    12351399                              boolean isDegraded, boolean noThinsp, boolean showDebug, boolean statsOnly,
    1236                               String stParam) throws IOException {
     1400                              boolean showRatios) throws IOException {
    12371401        // stats
    12381402        long uploaded = snark.getUploaded();
     
    13361500                    statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + img + ".png\" title=\"" + txt + "\"></td>" +
    13371501                               "<td class=\"snarkTorrentStatus\">" + txt +
    1338                                ": <a href=\"" + uri + "?p=" + Base64.encode(snark.getInfoHash()) + stParam + "\">" +
     1502                               ": <a href=\"" + uri + getQueryString(req, Base64.encode(snark.getInfoHash()), null, null) + "\">" +
    13391503                               curPeers + thinsp(noThinsp) +
    13401504                               ngettext("1 peer", "{0} peers", knownPeers) + "</a>";
     
    13521516                statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "downloading.png\" title=\"" + _("OK") + "\"></td>" +
    13531517                               "<td class=\"snarkTorrentStatus\">" + _("OK") +
    1354                                ": <a href=\"" + uri + "?p=" + Base64.encode(snark.getInfoHash()) + stParam + "\">" +
     1518                               ": <a href=\"" + uri + getQueryString(req, Base64.encode(snark.getInfoHash()), null, null) + "\">" +
    13551519                               curPeers + thinsp(noThinsp) +
    13561520                               ngettext("1 peer", "{0} peers", knownPeers) + "</a>";
     
    13631527                statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "stalled.png\" title=\"" + _("Stalled") + "\"></td>" +
    13641528                               "<td class=\"snarkTorrentStatus\">" + _("Stalled") +
    1365                                ": <a href=\"" + uri + "?p=" + Base64.encode(snark.getInfoHash()) + stParam + "\">" +
     1529                               ": <a href=\"" + uri + getQueryString(req, Base64.encode(snark.getInfoHash()), null, null) + "\">" +
    13661530                               curPeers + thinsp(noThinsp) +
    13671531                               ngettext("1 peer", "{0} peers", knownPeers) + "</a>";
     
    14671631        out.write("</td>\n\t");
    14681632        out.write("<td align=\"right\" class=\"snarkTorrentUploaded\">");
    1469         if (isValid && uploaded > 0)
    1470            out.write(formatSize(uploaded));
     1633        if (isValid) {
     1634            if (showRatios) {
     1635                if (total > 0) {
     1636                    double ratio = uploaded / ((double) total);
     1637                    out.write((new DecimalFormat("0.000")).format(ratio));
     1638                    out.write("&nbsp;x");
     1639                }
     1640            } else if (uploaded > 0) {
     1641                out.write(formatSize(uploaded));
     1642            }
     1643        }
    14711644        out.write("</td>\n\t");
    14721645        out.write("<td align=\"right\" class=\"snarkTorrentRateDown\">");
     
    14851658            // Stop Button
    14861659            if (isDegraded)
    1487                 out.write("<a href=\"" + _contextPath + "/?action=Stop_" + b64 + "&amp;nonce=" + _nonce + stParam + "\"><img title=\"");
     1660                out.write("<a href=\"" + _contextPath + "/?action=Stop_" + b64 + "&amp;nonce=" + _nonce +
     1661                          getQueryString(req, "", null, null).replace("?", "&amp;") + "\"><img title=\"");
    14881662            else
    14891663                out.write("<input type=\"image\" name=\"action_Stop_" + b64 + "\" value=\"foo\" title=\"");
     
    14991673                // This works in Opera but it's displayed a little differently, so use noThinsp here too so all 3 icons are consistent
    15001674                if (noThinsp)
    1501                     out.write("<a href=\"" + _contextPath + "/?action=Start_" + b64 + "&amp;nonce=" + _nonce + stParam + "\"><img title=\"");
     1675                    out.write("<a href=\"" + _contextPath + "/?action=Start_" + b64 + "&amp;nonce=" + _nonce +
     1676                              getQueryString(req, "", null, null).replace("?", "&amp;") + "\"><img title=\"");
    15021677                else
    15031678                    out.write("<input type=\"image\" name=\"action_Start_" + b64 + "\" value=\"foo\" title=\"");
     
    15131688                // Doesnt work with Opera so use noThinsp instead of isDegraded
    15141689                if (noThinsp)
    1515                     out.write("<a href=\"" + _contextPath + "/?action=Remove_" + b64 + "&amp;nonce=" + _nonce + stParam + "\"><img title=\"");
     1690                    out.write("<a href=\"" + _contextPath + "/?action=Remove_" + b64 + "&amp;nonce=" + _nonce +
     1691                              getQueryString(req, "", null, null).replace("?", "&amp;") + "\"><img title=\"");
    15161692                else
    15171693                    out.write("<input type=\"image\" name=\"action_Remove_" + b64 + "\" value=\"foo\" title=\"");
     
    15341710            // Doesnt work with Opera so use noThinsp instead of isDegraded
    15351711            if (noThinsp)
    1536                 out.write("<a href=\"" + _contextPath + "/?action=Delete_" + b64 + "&amp;nonce=" + _nonce + stParam + "\"><img title=\"");
     1712                out.write("<a href=\"" + _contextPath + "/?action=Delete_" + b64 + "&amp;nonce=" + _nonce +
     1713                          getQueryString(req, "", null, null).replace("?", "&amp;") + "\"><img title=\"");
    15371714            else
    15381715                out.write("<input type=\"image\" name=\"action_Delete_" + b64 + "\" value=\"foo\" title=\"");
     
    18432020        // *not* enctype="multipart/form-data", so that the input type=file sends the filename, not the file
    18442021        out.write("<form action=\"_post\" method=\"POST\">\n");
    1845         out.write("<input type=\"hidden\" name=\"nonce\" value=\"" + _nonce + "\" >\n");
    1846         out.write("<input type=\"hidden\" name=\"action\" value=\"Add\" >\n");
    1847         // don't lose peer setting
    1848         String peerParam = req.getParameter("p");
    1849         if (peerParam != null)
    1850             out.write("<input type=\"hidden\" name=\"p\" value=\"" + DataHelper.stripHTML(peerParam) + "\" >\n");
     2022        writeHiddenInputs(out, req, "Add");
    18512023        out.write("<div class=\"addtorrentsection\"><span class=\"snarkConfigTitle\">");
    18522024        out.write("<img alt=\"\" border=\"0\" src=\"" + _imgPath + "add.png\"> ");
     
    18752047        // *not* enctype="multipart/form-data", so that the input type=file sends the filename, not the file
    18762048        out.write("<form action=\"_post\" method=\"POST\">\n");
    1877         out.write("<input type=\"hidden\" name=\"nonce\" value=\"" + _nonce + "\" >\n");
    1878         out.write("<input type=\"hidden\" name=\"action\" value=\"Create\" >\n");
    1879         // don't lose peer setting
    1880         String peerParam = req.getParameter("p");
    1881         if (peerParam != null)
    1882             out.write("<input type=\"hidden\" name=\"p\" value=\"" + DataHelper.stripHTML(peerParam) + "\" >\n");
     2049        writeHiddenInputs(out, req, "Create");
    18832050        out.write("<span class=\"snarkConfigTitle\">");
    18842051        out.write("<img alt=\"\" border=\"0\" src=\"" + _imgPath + "create.png\"> ");
     
    19462113       
    19472114        out.write("<form action=\"" + _contextPath + "/configure\" method=\"POST\">\n" +
    1948                   "<div class=\"configsectionpanel\"><div class=\"snarkConfig\">\n" +
    1949                   "<input type=\"hidden\" name=\"nonce\" value=\"" + _nonce + "\" >\n" +
    1950                   "<input type=\"hidden\" name=\"action\" value=\"Save\" >\n" +
    1951                   "<span class=\"snarkConfigTitle\">" +
     2115                  "<div class=\"configsectionpanel\"><div class=\"snarkConfig\">\n");
     2116        writeHiddenInputs(out, req, "Save");
     2117        out.write("<span class=\"snarkConfigTitle\">" +
    19522118                  "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "config.png\"> ");
    19532119        out.write(_("Configuration"));
     
    21322298        StringBuilder buf = new StringBuilder(1024);
    21332299        buf.append("<form action=\"" + _contextPath + "/configure\" method=\"POST\">\n" +
    2134                   "<div class=\"configsectionpanel\"><div class=\"snarkConfig\">\n" +
    2135                   "<input type=\"hidden\" name=\"nonce\" value=\"" + _nonce + "\" >\n" +
    2136                   "<input type=\"hidden\" name=\"action\" value=\"Save2\" >\n" +
    2137                   "<span class=\"snarkConfigTitle\">" +
     2300                   "<div class=\"configsectionpanel\"><div class=\"snarkConfig\">\n");
     2301        writeHiddenInputs(buf, req, "Save2");
     2302        buf.append("<span class=\"snarkConfigTitle\">" +
    21382303                  "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "config.png\"> ");
    21392304        buf.append(_("Trackers"));
     
    24362601            r = new File("");
    24372602        }
     2603
     2604        boolean showPriority = snark != null && snark.getStorage() != null && !snark.getStorage().complete() &&
     2605                               r.isDirectory();
     2606
    24382607        StringBuilder buf=new StringBuilder(4096);
    24392608        buf.append(DOCTYPE).append("<HTML><HEAD><TITLE>");
     
    24432612        title = _("Torrent") + ": " + DataHelper.escapeHTML(title);
    24442613        buf.append(title);
    2445         buf.append("</TITLE>").append(HEADER_A).append(_themePath).append(HEADER_B).append("<link rel=\"shortcut icon\" href=\"" + _themePath + "favicon.ico\">" +
    2446              "</HEAD><BODY>\n<center><div class=\"snarknavbar\"><a href=\"").append(_contextPath).append("/\" title=\"Torrents\"");
     2614        buf.append("</TITLE>\n").append(HEADER_A).append(_themePath).append(HEADER_B)
     2615            .append("<link rel=\"shortcut icon\" href=\"" + _themePath + "favicon.ico\">\n");
     2616        if (showPriority)
     2617            buf.append("<script src=\"").append(_contextPath).append(WARBASE + "js/folder.js\" type=\"text/javascript\"></script>\n");
     2618        buf.append("</HEAD><BODY");
     2619        if (showPriority)
     2620            buf.append(" onload=\"setupbuttons()\"");
     2621        buf.append(">\n<center><div class=\"snarknavbar\"><a href=\"").append(_contextPath).append("/\" title=\"Torrents\"");
    24472622        buf.append(" class=\"snarkRefresh\"><img alt=\"\" border=\"0\" src=\"").append(_imgPath).append("arrow_refresh.png\">&nbsp;&nbsp;");
    24482623        if (_contextName.equals(DEFAULT_NAME))
     
    24542629        if (parent)  // always true
    24552630            buf.append("<div class=\"page\"><div class=\"mainsection\">");
    2456         boolean showPriority = snark != null && snark.getStorage() != null && !snark.getStorage().complete() &&
    2457                                r.isDirectory();
    24582631        if (showPriority) {
    24592632            buf.append("<form action=\"").append(base).append("\" method=\"POST\">\n");
     
    25952768                   .append((new DecimalFormat("0.00%")).format(completion));
    25962769            else
    2597                 buf.append("&nbsp;<img alt=\"\" border=\"0\" src=\"").append(_imgPath).append("head_rx.png\" >&nbsp;")
    2598                    .append(_("Complete"));
    2599             // else unknown
     2770                buf.append("&nbsp;<img alt=\"\" border=\"0\" src=\"").append(_imgPath).append("head_rx.png\" >&nbsp;<b>")
     2771                   .append(_("Complete")).append("</b>");
     2772            // up ratio
     2773            buf.append("&nbsp;<img alt=\"\" border=\"0\" src=\"").append(_imgPath).append("head_tx.png\" >&nbsp;<b>")
     2774               .append(_("Upload ratio"))
     2775               .append(":</b> ");
     2776            long uploaded = snark.getUploaded();
     2777            if (uploaded > 0) {
     2778                double ratio = uploaded / ((double) snark.getTotalLength());
     2779                buf.append((new DecimalFormat("0.000")).format(ratio));
     2780                buf.append("&nbsp;x");
     2781            } else {
     2782                buf.append('0');
     2783            }
    26002784            long needed = snark.getNeededLength();
    26012785            if (needed > 0)
     
    27822966                buf.append("<td class=\"priority\">");
    27832967                if ((!complete) && (!item.isDirectory())) {
    2784                     buf.append("<input type=\"radio\" value=\"5\" name=\"pri.").append(fileIndex).append("\" ");
     2968                    buf.append("\n<input type=\"radio\" onclick=\"priorityclicked();\" class=\"prihigh\" value=\"5\" name=\"pri.").append(fileIndex).append("\" ");
    27852969                    if (priority > 0)
    2786                         buf.append("checked=\"true\"");
     2970                        buf.append("checked=\"checked\"");
    27872971                    buf.append('>').append(_("High"));
    27882972
    2789                     buf.append("<input type=\"radio\" value=\"0\" name=\"pri.").append(fileIndex).append("\" ");
     2973                    buf.append("\n<input type=\"radio\" onclick=\"priorityclicked();\" class=\"prinorm\" value=\"0\" name=\"pri.").append(fileIndex).append("\" ");
    27902974                    if (priority == 0)
    2791                         buf.append("checked=\"true\"");
     2975                        buf.append("checked=\"checked\"");
    27922976                    buf.append('>').append(_("Normal"));
    27932977
    2794                     buf.append("<input type=\"radio\" value=\"-9\" name=\"pri.").append(fileIndex).append("\" ");
     2978                    buf.append("\n<input type=\"radio\" onclick=\"priorityclicked();\" class=\"priskip\" value=\"-9\" name=\"pri.").append(fileIndex).append("\" ");
    27952979                    if (priority < 0)
    2796                         buf.append("checked=\"true\"");
     2980                        buf.append("checked=\"checked\"");
    27972981                    buf.append('>').append(_("Skip"));
    27982982                    showSaveButton = true;
     
    28032987        }
    28042988        if (showSaveButton) {
    2805             buf.append("<thead><tr><th colspan=\"4\">&nbsp;</th><th class=\"headerpriority\"><input type=\"submit\" value=\"");
    2806             buf.append(_("Save priorities"));
    2807             buf.append("\" name=\"foo\" ></th></tr></thead>\n");
     2989            buf.append("<thead><tr><th colspan=\"4\">&nbsp;</th><th class=\"headerpriority\">" +
     2990                       "<a class=\"control\" id=\"setallhigh\" href=\"javascript:void(null);\" onclick=\"setallhigh();\">")
     2991               .append(toImg("clock_red")).append(_("Set all high")).append("</a>\n" +
     2992                       "<a class=\"control\" id=\"setallnorm\" href=\"javascript:void(null);\" onclick=\"setallnorm();\">")
     2993               .append(toImg("clock")).append(_("Set all normal")).append("</a>\n" +
     2994                       "<a class=\"control\" id=\"setallskip\" href=\"javascript:void(null);\" onclick=\"setallskip();\">")
     2995               .append(toImg("cancel")).append(_("Skip all")).append("</a>\n" +
     2996                       "<br><br><input type=\"submit\" class=\"accept\" value=\"").append(_("Save priorities"))
     2997               .append("\" name=\"savepri\" >\n" +
     2998                       "</th></tr></thead>\n");
    28082999        }
    28093000        buf.append("</table>\n");
     
    28153006    }
    28163007
    2817     /** @since 0.7.14 */
     3008    /**
     3009     *  Pick an icon; try to catch the common types in an i2p environment.
     3010     *
     3011     *  @return file name not including ".png"
     3012     *  @since 0.7.14
     3013     */
    28183014    private String toIcon(File item) {
    28193015        if (item.isDirectory())
     
    28243020    /**
    28253021     *  Pick an icon; try to catch the common types in an i2p environment
     3022     *  Pkg private for FileTypeSorter.
     3023     *
    28263024     *  @return file name not including ".png"
    28273025     *  @since 0.7.14
    28283026     */
    2829     private String toIcon(String path) {
     3027    String toIcon(String path) {
    28303028        String icon;
    28313029        // Note that for this to work well, our custom mime.properties file must be loaded.
     
    28743072    /** @since 0.7.14 */
    28753073    private String toImg(String icon) {
    2876         return "<img alt=\"\" height=\"16\" width=\"16\" src=\"" + _contextPath + "/.icons/" + icon + ".png\">";
     3074        return toImg(icon, "");
    28773075    }
    28783076
    28793077    /** @since 0.8.2 */
    28803078    private String toImg(String icon, String altText) {
    2881         return "<img alt=\"" + altText + "\" height=\"16\" width=\"16\" src=\"" + _contextPath + "/.icons/" + icon + ".png\">";
     3079        return "<img alt=\"" + altText + "\" height=\"16\" width=\"16\" src=\"" + _contextPath + WARBASE + "icons/" + icon + ".png\">";
    28823080    }
    28833081
  • apps/i2psnark/mime.properties

    reab4397 r156d868  
    99flv     = video/x-flv
    1010iso     = application/x-iso9660-image
     11js      = text/javascript
    1112m4a     = audio/mp4a-latm
    1213m4v     = video/x-m4v
  • apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClientBase.java

    reab4397 r156d868  
    602602        int status = ise != null ? ise.getStatus() : -1;
    603603        String error;
    604         //TODO MessageStatusMessage.STATUS_SEND_FAILURE_UNSUPPORTED_ENCRYPTION
    605604        if (status == MessageStatusMessage.STATUS_SEND_FAILURE_NO_LEASESET) {
     605            // We won't get this one unless it is treated as a hard failure
     606            // in streaming. See PacketQueue.java
    606607            error = usingWWWProxy ? "nolsp" : "nols";
     608        } else if (status == MessageStatusMessage.STATUS_SEND_FAILURE_UNSUPPORTED_ENCRYPTION) {
     609            error = usingWWWProxy ? "encp" : "enc";
    607610        } else {
    608611            error = usingWWWProxy ? "dnfp" : "dnf";
  • apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/EditBean.java

    reab4397 r156d868  
    189189    /** @since 0.9.12 */
    190190    public boolean isSigTypeAvailable(int code) {
    191         SigType type = SigType.getByCode(code);
    192         return type != null && type.isAvailable();
     191        return SigType.isAvailable(code);
    193192    }
    194193   
  • apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHelper.java

    reab4397 r156d868  
    66
    77import net.i2p.data.DataHelper;
    8 import net.i2p.data.RouterAddress;
     8import net.i2p.data.router.RouterAddress;
    99import net.i2p.router.CommSystemFacade;
    1010import net.i2p.router.Router;
  • apps/routerconsole/java/src/net/i2p/router/web/NetDbRenderer.java

    reab4397 r156d868  
    3030import net.i2p.data.Lease;
    3131import net.i2p.data.LeaseSet;
    32 import net.i2p.data.RouterAddress;
    33 import net.i2p.data.RouterInfo;
     32import net.i2p.data.router.RouterAddress;
     33import net.i2p.data.router.RouterInfo;
    3434import net.i2p.router.RouterContext;
    3535import net.i2p.router.TunnelPoolSettings;
     
    416416            buf.append("<b>" + _("Published") + ":</b> in ").append(DataHelper.formatDuration2(0-age)).append("???<br>\n");
    417417        }
    418         buf.append("<b>" + _("Address(es)") + ":</b> ");
     418        buf.append("<b>").append(_("Signing Key")).append(":</b> ")
     419           .append(info.getIdentity().getSigningPublicKey().getType().toString());
     420        buf.append("<br>\n<b>" + _("Address(es)") + ":</b> ");
    419421        String country = _context.commSystem().getCountry(info.getIdentity().getHash());
    420422        if(country != null) {
  • apps/routerconsole/java/src/net/i2p/router/web/ProfileOrganizerRenderer.java

    reab4397 r156d868  
    1111import net.i2p.data.DataHelper;
    1212import net.i2p.data.Hash;
    13 import net.i2p.data.RouterInfo;
     13import net.i2p.data.router.RouterInfo;
    1414import net.i2p.router.RouterContext;
    1515import net.i2p.router.peermanager.DBHistory;
  • apps/routerconsole/java/src/net/i2p/router/web/ProofHelper.java

    reab4397 r156d868  
    44
    55import net.i2p.data.DataHelper;
    6 import net.i2p.data.RouterAddress;
    7 import net.i2p.data.RouterInfo;
     6import net.i2p.data.router.RouterAddress;
     7import net.i2p.data.router.RouterInfo;
    88import net.i2p.data.Signature;
    99
  • apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java

    reab4397 r156d868  
    1616import net.i2p.data.Hash;
    1717import net.i2p.data.LeaseSet;
    18 import net.i2p.data.RouterAddress;
    19 import net.i2p.data.RouterInfo;
     18import net.i2p.data.router.RouterAddress;
     19import net.i2p.data.router.RouterInfo;
    2020import net.i2p.router.CommSystemFacade;
    2121import net.i2p.router.Router;
  • apps/routerconsole/java/src/net/i2p/router/web/TunnelRenderer.java

    reab4397 r156d868  
    1212import net.i2p.data.DataHelper;
    1313import net.i2p.data.Hash;
    14 import net.i2p.data.RouterInfo;
     14import net.i2p.data.router.RouterInfo;
    1515import net.i2p.data.TunnelId;
    1616import net.i2p.router.Router;
  • apps/streaming/java/src/net/i2p/client/streaming/impl/PacketQueue.java

    reab4397 r156d868  
    4545    private static final int FINAL_TAG_THRESHOLD = 2;
    4646    private static final long REMOVE_EXPIRED_TIME = 67*1000;
    47     private static final boolean ENABLE_STATUS_LISTEN = false;
     47    private static final boolean ENABLE_STATUS_LISTEN = true;
    4848
    4949    public PacketQueue(I2PAppContext context, I2PSession session, ConnectionManager mgr) {
     
    268268                break;
    269269
     270            case MessageStatusMessage.STATUS_SEND_FAILURE_NO_LEASESET:
     271                // Ideally we would like to make this a hard failure,
     272                // but it caused far too many fast-fails that were then
     273                // resolved by the user clicking reload in his browser.
     274                // Until the LS fetch is faster and more reliable,
     275                // or we increase the timeout for it,
     276                // we can't treat this one as a hard fail.
     277                // Let the streaming retransmission paper over the problem.
     278                if (_log.shouldLog(Log.WARN))
     279                    _log.warn("LS lookup (soft) failure for msg " + msgId + " on " + con);
     280                _messageStatusMap.remove(id);
     281                break;
     282
     283
    270284            case MessageStatusMessage.STATUS_SEND_FAILURE_LOCAL:
    271285            case MessageStatusMessage.STATUS_SEND_FAILURE_ROUTER:
     
    281295            case MessageStatusMessage.STATUS_SEND_FAILURE_BAD_LEASESET:
    282296            case MessageStatusMessage.STATUS_SEND_FAILURE_EXPIRED_LEASESET:
    283             case MessageStatusMessage.STATUS_SEND_FAILURE_NO_LEASESET:
    284297            case SendMessageStatusListener.STATUS_CANCELLED:
    285298                if (con.getHighestAckedThrough() >= 0) {
  • build.xml

    reab4397 r156d868  
    549549            <group title="Core SDK (i2p.jar)" packages="net.i2p:net.i2p.*:net.i2p.client:net.i2p.client.*:net.i2p.internal:net.i2p.internal.*:freenet.support.CPUInformation:org.bouncycastle.oldcrypto:org.bouncycastle.oldcrypto.*:gnu.crypto.*:gnu.getopt:gnu.gettext:com.nettgryppa.security:net.metanotion:net.metanotion.*" />
    550550            <group title="Streaming Library" packages="net.i2p.client.streaming:net.i2p.client.streaming.impl" />
    551             <group title="Router" packages="net.i2p.router:net.i2p.router.*:net.i2p.data.i2np:org.cybergarage.*:org.freenetproject:org.xlattice.crypto.filters" />
     551            <group title="Router" packages="net.i2p.router:net.i2p.router.*:net.i2p.data.i2np:net.i2p.data.router:org.cybergarage.*:org.freenetproject:org.xlattice.crypto.filters" />
    552552            <group title="Router Console" packages="net.i2p.router.web:net.i2p.router.update" />
    553553            <!-- apps and bridges starting here, alphabetical please -->
  • core/java/src/net/i2p/crypto/KeyGenerator.java

    reab4397 r156d868  
    1313import java.security.GeneralSecurityException;
    1414import java.security.InvalidKeyException;
     15import java.security.KeyFactory;
    1516import java.security.KeyPair;
    1617import java.security.KeyPairGenerator;
    1718import java.security.ProviderException;
     19import java.security.interfaces.ECPrivateKey;
     20import java.security.interfaces.ECPublicKey;
     21import java.security.interfaces.RSAPrivateKey;
     22import java.security.interfaces.RSAPublicKey;
     23import java.security.spec.ECParameterSpec;
     24import java.security.spec.ECPoint;
     25import java.security.spec.ECPublicKeySpec;
     26import java.security.spec.EllipticCurve;
     27import java.security.spec.RSAKeyGenParameterSpec;
     28import java.security.spec.RSAPublicKeySpec;
    1829
    1930import net.i2p.I2PAppContext;
     31import net.i2p.crypto.eddsa.EdDSAPrivateKey;
     32import net.i2p.crypto.eddsa.EdDSAPublicKey;
     33import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec;
    2034import net.i2p.data.Hash;
    2135import net.i2p.data.PrivateKey;
     
    269283
    270284    /** Convert a SigningPrivateKey to a SigningPublicKey.
    271      * DSA-SHA1 only.
     285     *  As of 0.9.16, supports all key types.
    272286     *
    273287     * @param priv a SigningPrivateKey object
    274288     * @return a SigningPublicKey object
    275      * @throws IllegalArgumentException on bad key
     289     * @throws IllegalArgumentException on bad key or unknown type
    276290     */
    277291    public static SigningPublicKey getSigningPublicKey(SigningPrivateKey priv) {
    278         if (priv.getType() != SigType.DSA_SHA1)
    279             throw new IllegalArgumentException();
    280         BigInteger x = new NativeBigInteger(1, priv.toByteArray());
    281         BigInteger y = CryptoConstants.dsag.modPow(x, CryptoConstants.dsap);
    282         SigningPublicKey pub = new SigningPublicKey();
    283         try {
    284             pub.setData(SigUtil.rectify(y, SigningPublicKey.KEYSIZE_BYTES));
    285         } catch (InvalidKeyException ike) {
    286             throw new IllegalArgumentException(ike);
    287         }
    288         return pub;
     292        SigType type = priv.getType();
     293        if (type == null)
     294            throw new IllegalArgumentException("Unknown type");
     295        try {
     296            switch (type.getBaseAlgorithm()) {
     297              case DSA:
     298                BigInteger x = new NativeBigInteger(1, priv.toByteArray());
     299                BigInteger y = CryptoConstants.dsag.modPow(x, CryptoConstants.dsap);
     300                SigningPublicKey pub = new SigningPublicKey();
     301                pub.setData(SigUtil.rectify(y, SigningPublicKey.KEYSIZE_BYTES));
     302                return pub;
     303
     304              case EC:
     305                ECPrivateKey ecpriv = SigUtil.toJavaECKey(priv);
     306                BigInteger s = ecpriv.getS();
     307                ECParameterSpec spec = (ECParameterSpec) type.getParams();
     308                EllipticCurve curve = spec.getCurve();
     309                ECPoint g = spec.getGenerator();
     310                ECPoint w = ECUtil.scalarMult(g, s, curve);
     311                ECPublicKeySpec ecks = new ECPublicKeySpec(w, ecpriv.getParams());
     312                KeyFactory eckf = KeyFactory.getInstance("EC");
     313                ECPublicKey ecpub = (ECPublicKey) eckf.generatePublic(ecks);
     314                return SigUtil.fromJavaKey(ecpub, type);
     315
     316              case RSA:
     317                RSAPrivateKey rsapriv = SigUtil.toJavaRSAKey(priv);
     318                BigInteger exp = ((RSAKeyGenParameterSpec)type.getParams()).getPublicExponent();
     319                RSAPublicKeySpec rsaks = new RSAPublicKeySpec(rsapriv.getModulus(), exp);
     320                KeyFactory rsakf = KeyFactory.getInstance("RSA");
     321                RSAPublicKey rsapub = (RSAPublicKey) rsakf.generatePublic(rsaks);
     322                return SigUtil.fromJavaKey(rsapub, type);
     323
     324              case EdDSA:
     325                EdDSAPrivateKey epriv = SigUtil.toJavaEdDSAKey(priv);
     326                EdDSAPublicKey epub = new EdDSAPublicKey(new EdDSAPublicKeySpec(epriv.getA(), epriv.getParams()));
     327                return SigUtil.fromJavaKey(epub, type);
     328
     329              default:
     330                throw new IllegalArgumentException("Unsupported algorithm");
     331            }
     332        } catch (GeneralSecurityException gse) {
     333            throw new IllegalArgumentException("Conversion failed", gse);
     334        }
    289335    }
    290336
     
    323369        long vtime = 0;
    324370        SimpleDataStructure keys[] = KeyGenerator.getInstance().generateSigningKeys(type);
    325         //System.out.println("pubkey " + keys[0]);
     371        SigningPublicKey pubkey = (SigningPublicKey) keys[0];
     372        SigningPrivateKey privkey = (SigningPrivateKey) keys[1];
     373        SigningPublicKey pubkey2 = getSigningPublicKey(privkey);
     374        if (pubkey.equals(pubkey2))
     375            System.out.println(type + " private-to-public test PASSED");
     376        else
     377            System.out.println(type + " private-to-public test FAILED");
    326378        //System.out.println("privkey " + keys[1]);
    327379        for (int i = 0; i < runs; i++) {
    328380            RandomSource.getInstance().nextBytes(src);
    329381            long start = System.nanoTime();
    330             Signature sig = DSAEngine.getInstance().sign(src, (SigningPrivateKey) keys[1]);
     382            Signature sig = DSAEngine.getInstance().sign(src, privkey);
    331383            long mid = System.nanoTime();
    332             boolean ok = DSAEngine.getInstance().verifySignature(sig, src, (SigningPublicKey) keys[0]);
     384            boolean ok = DSAEngine.getInstance().verifySignature(sig, src, pubkey);
    333385            long end = System.nanoTime();
    334386            stime += mid - start;
  • core/java/src/net/i2p/crypto/SigUtil.java

    reab4397 r156d868  
    332332
    333333    /**
    334      *  @deprecated unused
     334     *
    335335     */
    336336    public static RSAPrivateKey toJavaRSAKey(SigningPrivateKey pk)
     
    345345
    346346    /**
    347      *  @deprecated unused
     347     *
    348348     */
    349349    public static SigningPublicKey fromJavaKey(RSAPublicKey pk, SigType type)
  • core/java/src/net/i2p/data/DataHelper.java

    reab4397 r156d868  
    2525import java.io.OutputStreamWriter;
    2626import java.io.PrintWriter;
    27 import java.io.Serializable;
    2827import java.io.UnsupportedEncodingException;
    2928import java.math.BigInteger;
    3029import java.security.MessageDigest;
    3130import java.text.DecimalFormat;
    32 import java.util.ArrayList;
    3331import java.util.Arrays;
    3432import java.util.Collection;
    35 import java.util.Collections;
    36 import java.util.Comparator;
    3733import java.util.Date;
    3834import java.util.HashMap;
    3935import java.util.Iterator;
    40 import java.util.List;
    4136import java.util.Locale;
    4237import java.util.Map;
     
    639634     * @param value value to write out, non-negative
    640635     * @param rawStream stream to write to
    641      * @param numBytes number of bytes to write the number into (padding as necessary)
    642      * @throws DataFormatException if value is negative
     636     * @param numBytes number of bytes to write the number into, 1-8 (padding as necessary)
     637     * @throws DataFormatException if value is negative or if numBytes not 1-8
    643638     * @throws IOException if there is an IO error writing to the stream
    644639     */
    645640    public static void writeLong(OutputStream rawStream, int numBytes, long value)
    646641        throws DataFormatException, IOException {
    647         if (value < 0) throw new DataFormatException("Value is negative (" + value + ")");
     642        if (numBytes <= 0 || numBytes > 8)
     643            // probably got the args backwards
     644            throw new DataFormatException("Bad byte count " + numBytes);
     645        if (value < 0)
     646            throw new DataFormatException("Value is negative (" + value + ")");
    648647        for (int i = (numBytes - 1) * 8; i >= 0; i -= 8) {
    649648            byte cur = (byte) (value >> i);
     
    14241423        hash.update(data);
    14251424        out.write(data);
    1426     }
    1427 
    1428     /**
    1429      *  Sort based on the Hash of the DataStructure.
    1430      *  Warning - relatively slow.
    1431      *  WARNING - this sort order must be consistent network-wide, so while the order is arbitrary,
    1432      *  it cannot be changed.
    1433      *  Why? Just because it has to be consistent so signing will work.
    1434      *  How to spec as returning the same type as the param?
    1435      *  DEPRECATED - Only used by RouterInfo.
    1436      *
    1437      *  @return a new list
    1438      */
    1439     public static List<? extends DataStructure> sortStructures(Collection<? extends DataStructure> dataStructures) {
    1440         if (dataStructures == null) return Collections.emptyList();
    1441 
    1442         // This used to use Hash.toString(), which is insane, since a change to toString()
    1443         // would break the whole network. Now use Hash.toBase64().
    1444         // Note that the Base64 sort order is NOT the same as the raw byte sort order,
    1445         // despite what you may read elsewhere.
    1446 
    1447         //ArrayList<DataStructure> rv = new ArrayList(dataStructures.size());
    1448         //TreeMap<String, DataStructure> tm = new TreeMap();
    1449         //for (DataStructure struct : dataStructures) {
    1450         //    tm.put(struct.calculateHash().toString(), struct);
    1451         //}
    1452         //for (DataStructure struct : tm.values()) {
    1453         //    rv.add(struct);
    1454         //}
    1455         ArrayList<DataStructure> rv = new ArrayList<DataStructure>(dataStructures);
    1456         sortStructureList(rv);
    1457         return rv;
    1458     }
    1459 
    1460     /**
    1461      *  See above.
    1462      *  DEPRECATED - Only used by RouterInfo.
    1463      *
    1464      *  @since 0.9
    1465      */
    1466     static void sortStructureList(List<? extends DataStructure> dataStructures) {
    1467         Collections.sort(dataStructures, new DataStructureComparator());
    1468     }
    1469 
    1470     /**
    1471      * See sortStructures() comments.
    1472      * @since 0.8.3
    1473      */
    1474     private static class DataStructureComparator implements Comparator<DataStructure>, Serializable {
    1475         public int compare(DataStructure l, DataStructure r) {
    1476             return l.calculateHash().toBase64().compareTo(r.calculateHash().toBase64());
    1477         }
    14781425    }
    14791426
  • core/java/src/net/i2p/data/KeysAndCert.java

    reab4397 r156d868  
    7979   
    8080    /**
     81     * @since 0.9.16
     82     */
     83    public byte[] getPadding() {
     84        return _padding;
     85    }
     86   
     87    /**
    8188     * @throws IllegalStateException if was already set
    8289     * @since 0.9.12
     
    115122        if (_padding != null)
    116123            out.write(_padding);
     124        else if (_signingKey.length() < SigningPublicKey.KEYSIZE_BYTES)
     125            throw new DataFormatException("No padding set");
    117126        _signingKey.writeTruncatedBytes(out);
    118127        _certificate.writeBytes(out);
  • core/java/src/net/i2p/data/PrivateKey.java

    reab4397 r156d868  
    5151     * of this PrivateKey
    5252     * @return a PublicKey object
     53     * @throws IllegalArgumentException on bad key
    5354     */
    5455    public PublicKey toPublic() {
  • core/java/src/net/i2p/data/PrivateKeyFile.java

    reab4397 r156d868  
    22
    33
     4import java.io.BufferedInputStream;
    45import java.io.ByteArrayInputStream;
    56import java.io.File;
    67import java.io.FileInputStream;
    7 import java.io.FileOutputStream;
     8import java.io.InputStream;
    89import java.io.IOException;
     10import java.io.OutputStream;
    911import java.security.GeneralSecurityException;
    1012import java.util.Locale;
     
    2527import net.i2p.crypto.SigType;
    2628import net.i2p.util.RandomSource;
     29import net.i2p.util.SecureFileOutputStream;
    2730
    2831/**
     
    4952    private static final int HASH_EFFORT = VerifiedDestination.MIN_HASHCASH_EFFORT;
    5053   
    51     private final File file;
     54    protected final File file;
    5255    private final I2PClient client;
    53     private Destination dest;
    54     private PrivateKey privKey;
    55     private SigningPrivateKey signingPrivKey;
     56    protected Destination dest;
     57    protected PrivateKey privKey;
     58    protected SigningPrivateKey signingPrivKey;
    5659
    5760    /**
     
    225228    public PrivateKeyFile(File file, PublicKey pubkey, SigningPublicKey spubkey, Certificate cert,
    226229                          PrivateKey pk, SigningPrivateKey spk) {
     230        this(file, pubkey, spubkey, cert, pk, spk, null);
     231    }
     232   
     233    /**
     234     *  @param padding null OK, must be non-null if spubkey length < 128
     235     *  @throws IllegalArgumentException on mismatch of spubkey and spk types
     236     *  @since 0.9.16
     237     */
     238    public PrivateKeyFile(File file, PublicKey pubkey, SigningPublicKey spubkey, Certificate cert,
     239                          PrivateKey pk, SigningPrivateKey spk, byte[] padding) {
    227240        if (spubkey.getType() != spk.getType())
    228241            throw new IllegalArgumentException("Signing key type mismatch");
     
    233246        this.dest.setSigningPublicKey(spubkey);
    234247        this.dest.setCertificate(cert);
     248        if (padding != null)
     249            this.dest.setPadding(padding);
    235250        this.privKey = pk;
    236251        this.signingPrivKey = spk;
     
    242257    public Destination createIfAbsent() throws I2PException, IOException, DataFormatException {
    243258        if(!this.file.exists()) {
    244             FileOutputStream out = null;
     259            OutputStream out = null;
    245260            try {
    246                 out = new FileOutputStream(this.file);
     261                out = new SecureFileOutputStream(this.file);
    247262                if (this.client != null)
    248263                    this.client.createDestination(out);
     
    258273    }
    259274   
    260     /** Also sets the local privKey and signingPrivKey */
     275    /**
     276     *  If the destination is not set, read it in from the file.
     277     *  Also sets the local privKey and signingPrivKey.
     278     */
    261279    public Destination getDestination() throws I2PSessionException, IOException, DataFormatException {
    262280        if (dest == null) {
     
    409427
    410428    public I2PSession open(Properties opts) throws I2PSessionException, IOException {
    411         FileInputStream in = null;
    412         try {
    413             in = new FileInputStream(this.file);
     429        InputStream in = null;
     430        try {
     431            in = new BufferedInputStream(new FileInputStream(this.file));
    414432            I2PSession s = this.client.createSession(in, opts);
    415433            return s;
     
    425443     */
    426444    public void write() throws IOException, DataFormatException {
    427         FileOutputStream out = null;
    428         try {
    429             out = new FileOutputStream(this.file);
     445        OutputStream out = null;
     446        try {
     447            out = new SecureFileOutputStream(this.file);
    430448            this.dest.writeBytes(out);
    431449            this.privKey.writeBytes(out);
    432450            this.signingPrivKey.writeBytes(out);
    433             out.flush();
    434451        } finally {
    435452            if (out != null) {
    436453                try { out.close(); } catch (IOException ioe) {}
    437454            }
     455        }
     456    }
     457
     458    /**
     459     *  Verify that the PublicKey matches the PrivateKey, and
     460     *  the SigningPublicKey matches the SigningPrivateKey.
     461     *
     462     *  @return success
     463     *  @since 0.9.16
     464     */
     465    public boolean validateKeyPairs() {
     466        try {
     467            if (!dest.getPublicKey().equals(KeyGenerator.getPublicKey(privKey)))
     468                return false;
     469            return dest.getSigningPublicKey().equals(KeyGenerator.getSigningPublicKey(signingPrivKey));
     470        } catch (IllegalArgumentException iae) {
     471            return false;
    438472        }
    439473    }
  • core/java/src/net/i2p/data/SigningPrivateKey.java

    reab4397 r156d868  
    7676    }
    7777
    78     /** converts this signing private key to its public equivalent
    79      * @return a SigningPublicKey object derived from this private key
     78    /**
     79     *  Converts this signing private key to its public equivalent.
     80     *  As of 0.9.16, supports all key types.
     81     *
     82     *  @return a SigningPublicKey object derived from this private key
     83     *  @throws IllegalArgumentException on bad key or unknown or unsupported type
    8084     */
    8185    public SigningPublicKey toPublic() {
  • installer/resources/themes/snark/ubergine/snark.css

    reab4397 r156d868  
    527527}
    528528
     529a.control, a.controld {
     530     background: #989;
     531     border: 1px inset #bbb;
     532     border-radius: 4px;
     533     color: #000;
     534     font-weight: bold;
     535     margin: 2px 4px;
     536     padding: 2px;
     537     text-shadow: 0px 0px #410;
     538     white-space: nowrap;
     539}
     540
     541a.controld {
     542     color: #444;
     543     font-weight: normal;
     544}
     545
     546a.controld img {
     547     display: none;
     548}
     549
     550a.control:hover {
     551     background-color: #f60;
     552     border: 1px outset #bbb;
     553     color: #fff;
     554     text-shadow: 0px 1px 5px #f00;
     555}
     556
     557a.control:active {
     558     background: #000 !important;
     559     color: #f60 !important;
     560     text-shadow: 0 !important;
     561}
     562
    529563input {
    530564     font-size: 8.5pt;
     
    598632
    599633input.default { width: 1px; height: 1px; visibility: hidden; }
     634
     635input.disabled, input.disabled:hover {
     636     background-color: #989;
     637     border: 1px inset #bbb;
     638     color: #444;
     639     font-weight: normal;
     640     text-shadow: 0px 0px 0px #444;
     641}
    600642
    601643input.accept {
  • router/java/src/net/i2p/data/i2np/BuildRequestRecord.java

    reab4397 r156d868  
    147147    }
    148148    /**
    149      * Time that the request was sent, truncated to the nearest hour
     149     * Time that the request was sent (ms), truncated to the nearest hour
    150150     */
    151151    public long readRequestTime() {
    152         return DataHelper.fromLong(_data.getData(), _data.getOffset() + OFF_REQ_TIME, 4) * 60l * 60l * 1000l;
     152        return DataHelper.fromLong(_data.getData(), _data.getOffset() + OFF_REQ_TIME, 4) * (60 * 60 * 1000L);
    153153    }
    154154    /**
     
    251251            buf[OFF_FLAG] |= FLAG_OUTBOUND_ENDPOINT;
    252252        long truncatedHour = ctx.clock().now();
     253        // prevent hop identification at top of the hour
     254        truncatedHour -= ctx.random().nextInt(90*1000);
    253255        truncatedHour /= (60l*60l*1000l);
    254256        DataHelper.toLong(buf, OFF_REQ_TIME, 4, truncatedHour);
  • router/java/src/net/i2p/data/i2np/DatabaseLookupMessage.java

    reab4397 r156d868  
    1818import net.i2p.data.DataHelper;
    1919import net.i2p.data.Hash;
    20 import net.i2p.data.RouterInfo;
     20import net.i2p.data.router.RouterInfo;
    2121import net.i2p.data.SessionKey;
    2222import net.i2p.data.SessionTag;
  • router/java/src/net/i2p/data/i2np/DatabaseStoreMessage.java

    reab4397 r156d868  
    1919import net.i2p.data.Hash;
    2020import net.i2p.data.LeaseSet;
    21 import net.i2p.data.RouterInfo;
     21import net.i2p.data.router.RouterInfo;
    2222import net.i2p.data.TunnelId;
    2323
  • router/java/src/net/i2p/data/router/RouterAddress.java

    reab4397 r156d868  
    1 package net.i2p.data;
     1package net.i2p.data.router;
    22
    33/*
     
    1818import java.util.Properties;
    1919
     20import net.i2p.data.DataFormatException;
     21import net.i2p.data.DataHelper;
     22import net.i2p.data.DataStructureImpl;
    2023import net.i2p.util.Addresses;
    2124import net.i2p.util.OrderedProperties;
     
    3740 * Restored as of 0.9.12.
    3841 *
     42 * @since 0.9.16 moved from net.i2p.data
    3943 * @author jrandom
    4044 */
  • router/java/src/net/i2p/data/router/RouterIdentity.java

    reab4397 r156d868  
    1 package net.i2p.data;
     1package net.i2p.data.router;
     2
     3import net.i2p.data.Certificate;
     4import net.i2p.data.KeysAndCert;
    25
    36/*
     
    1720 * are set; attempts to change them will throw an IllegalStateException.
    1821 *
     22 * @since 0.9.16 moved from net.i2p.data
    1923 * @author jrandom
    2024 */
  • router/java/src/net/i2p/data/router/RouterInfo.java

    reab4397 r156d868  
    1 package net.i2p.data;
     1package net.i2p.data.router;
    22
    33/*
     
    3232import net.i2p.crypto.SHA256Generator;
    3333import net.i2p.crypto.SigType;
     34import net.i2p.data.DatabaseEntry;
     35import net.i2p.data.DataFormatException;
     36import net.i2p.data.DataHelper;
     37import net.i2p.data.Hash;
     38import net.i2p.data.KeysAndCert;
     39import net.i2p.data.Signature;
     40import net.i2p.data.SimpleDataStructure;
    3441import net.i2p.util.Clock;
    3542import net.i2p.util.Log;
     
    4855 * RouterInfo will throw an IllegalStateException after the RouterInfo is signed.
    4956 *
     57 * @since 0.9.16 moved from net.i2p.data
    5058 * @author jrandom
    5159 */
     
    191199                // network-wide. The signature is not checked at readin time, but only
    192200                // later, and the addresses are stored in a Set, not a List.
    193                 DataHelper.sortStructureList(_addresses);
     201                SortHelper.sortStructureList(_addresses);
    194202            }
    195203        }
     
    309317                    // network-wide. The signature is not checked at readin time, but only
    310318                    // later, and the hashes are stored in a Set, not a List.
    311                     peers = (Collection<Hash>) DataHelper.sortStructures(peers);
     319                    peers = (Collection<Hash>) SortHelper.sortStructures(peers);
    312320                for (Hash peerHash : peers) {
    313321                    peerHash.writeBytes(out);
  • router/java/src/net/i2p/router/Blocklist.java

    reab4397 r156d868  
    2929import net.i2p.data.DataHelper;
    3030import net.i2p.data.Hash;
    31 import net.i2p.data.RouterAddress;
    32 import net.i2p.data.RouterInfo;
     31import net.i2p.data.router.RouterAddress;
     32import net.i2p.data.router.RouterInfo;
    3333import net.i2p.router.networkdb.kademlia.FloodfillNetworkDatabaseFacade;
    3434import net.i2p.util.Addresses;
  • router/java/src/net/i2p/router/CommSystemFacade.java

    reab4397 r156d868  
    1414import java.util.List;
    1515import net.i2p.data.Hash;
    16 import net.i2p.data.RouterAddress;
     16import net.i2p.data.router.RouterAddress;
    1717
    1818/**
  • router/java/src/net/i2p/router/HandlerJobBuilder.java

    reab4397 r156d868  
    1010
    1111import net.i2p.data.Hash;
    12 import net.i2p.data.RouterIdentity;
     12import net.i2p.data.router.RouterIdentity;
    1313import net.i2p.data.i2np.I2NPMessage;
    1414
  • router/java/src/net/i2p/router/InNetMessagePool.java

    reab4397 r156d868  
    1515
    1616import net.i2p.data.Hash;
    17 import net.i2p.data.RouterIdentity;
     17import net.i2p.data.router.RouterIdentity;
    1818import net.i2p.data.i2np.DatabaseLookupMessage;
    1919import net.i2p.data.i2np.DatabaseSearchReplyMessage;
  • router/java/src/net/i2p/router/KeyManager.java

    reab4397 r156d868  
    1919import java.util.concurrent.ConcurrentHashMap;
    2020
     21import net.i2p.crypto.SigType;
    2122import net.i2p.data.DataFormatException;
    2223import net.i2p.data.DataStructure;
     
    2728import net.i2p.data.SigningPrivateKey;
    2829import net.i2p.data.SigningPublicKey;
     30import net.i2p.router.startup.CreateRouterInfoJob;
    2931import net.i2p.util.Log;
    3032import net.i2p.util.SecureDirectory;
     
    4850    public final static String PROP_KEYDIR = "router.keyBackupDir";
    4951    public final static String DEFAULT_KEYDIR = "keyBackup";
    50     private final static String KEYFILE_PRIVATE_ENC = "privateEncryption.key";
    51     private final static String KEYFILE_PUBLIC_ENC = "publicEncryption.key";
    52     private final static String KEYFILE_PRIVATE_SIGNING = "privateSigning.key";
    53     private final static String KEYFILE_PUBLIC_SIGNING = "publicSigning.key";
     52    public final static String KEYFILE_PRIVATE_ENC = "privateEncryption.key";
     53    public final static String KEYFILE_PUBLIC_ENC = "publicEncryption.key";
     54    public final static String KEYFILE_PRIVATE_SIGNING = "privateSigning.key";
     55    public final static String KEYFILE_PUBLIC_SIGNING = "publicSigning.key";
    5456   
    5557    public KeyManager(RouterContext context) {
     
    152154            syncPrivateKey(keyDir);
    153155            syncPublicKey(keyDir);
    154             syncSigningKey(keyDir);
    155             syncVerificationKey(keyDir);
     156            SigType type = CreateRouterInfoJob.getSigTypeConfig(getContext());
     157            syncSigningKey(keyDir, type);
     158            syncVerificationKey(keyDir, type);
    156159        }
    157160
     
    182185        }
    183186
    184         private void syncSigningKey(File keyDir) {
     187        /**
     188         *  @param type the SigType to expect on read-in, ignored on write
     189         */
     190        private void syncSigningKey(File keyDir, SigType type) {
    185191            DataStructure ds;
    186192            File keyFile = new File(keyDir, KEYFILE_PRIVATE_SIGNING);
     
    189195                ds = _signingPrivateKey;
    190196            else
    191                 ds = new SigningPrivateKey();
     197                ds = new SigningPrivateKey(type);
    192198            DataStructure readin = syncKey(keyFile, ds, exists);
    193199            if (readin != null && !exists)
     
    195201        }
    196202
    197         private void syncVerificationKey(File keyDir) {
     203        /**
     204         *  @param type the SigType to expect on read-in, ignored on write
     205         */
     206        private void syncVerificationKey(File keyDir, SigType type) {
    198207            DataStructure ds;
    199208            File keyFile = new File(keyDir, KEYFILE_PUBLIC_SIGNING);
     
    202211                ds = _signingPublicKey;
    203212            else
    204                 ds = new SigningPublicKey();
     213                ds = new SigningPublicKey(type);
    205214            DataStructure readin = syncKey(keyFile, ds, exists);
    206215            if (readin != null && !exists)
  • router/java/src/net/i2p/router/LeaseSetKeys.java

    reab4397 r156d868  
    4141     * Key with which a LeaseSet can be revoked (by republishing it with no Leases)
    4242     *
    43      * @deprecated unused
     43     * Deprecated, unused
    4444     */
    4545    public SigningPrivateKey getRevocationKey() { return _revocationKey; }
  • router/java/src/net/i2p/router/MultiRouter.java

    reab4397 r156d868  
    1111import net.i2p.I2PAppContext;
    1212import net.i2p.data.DataHelper;
    13 import net.i2p.data.RouterInfo;
     13import net.i2p.data.router.RouterInfo;
    1414import net.i2p.router.Router;
    1515
  • router/java/src/net/i2p/router/NetworkDatabaseFacade.java

    reab4397 r156d868  
    1515
    1616import net.i2p.data.DatabaseEntry;
     17import net.i2p.data.Destination;
    1718import net.i2p.data.Hash;
    1819import net.i2p.data.LeaseSet;
    19 import net.i2p.data.RouterInfo;
     20import net.i2p.data.router.RouterInfo;
    2021import net.i2p.router.networkdb.reseed.ReseedChecker;
    2122
     
    5253    public abstract void lookupRouterInfo(Hash key, Job onFindJob, Job onFailedLookupJob, long timeoutMs);
    5354    public abstract RouterInfo lookupRouterInfoLocally(Hash key);
     55
     56    /**
     57     *  Lookup using the client's tunnels
     58     *  Succeeds even if LS validation fails due to unsupported sig type
     59     *
     60     *  @param fromLocalDest use these tunnels for the lookup, or null for exploratory
     61     *  @since 0.9.16
     62     */
     63    public abstract void lookupDestination(Hash key, Job onFinishedJob, long timeoutMs, Hash fromLocalDest);
     64
     65    /**
     66     *  Lookup locally in netDB and in badDest cache
     67     *  Succeeds even if LS validation failed due to unsupported sig type
     68     *
     69     *  @since 0.9.16
     70     */
     71    public abstract Destination lookupDestinationLocally(Hash key);
     72
    5473    /**
    55      * return the leaseSet if another leaseSet already existed at that key
     74     * @return the leaseSet if another leaseSet already existed at that key
    5675     *
    5776     * @throws IllegalArgumentException if the data is not valid
    5877     */
    5978    public abstract LeaseSet store(Hash key, LeaseSet leaseSet) throws IllegalArgumentException;
     79
    6080    /**
    61      * return the routerInfo if another router already existed at that key
     81     * @return the routerInfo if another router already existed at that key
    6282     *
    6383     * @throws IllegalArgumentException if the data is not valid
    6484     */
    6585    public abstract RouterInfo store(Hash key, RouterInfo routerInfo) throws IllegalArgumentException;
     86
     87    /**
     88     *  @return the old entry if it already existed at that key
     89     *  @throws IllegalArgumentException if the data is not valid
     90     *  @since 0.9.16
     91     */
     92    public DatabaseEntry store(Hash key, DatabaseEntry entry) throws IllegalArgumentException {
     93        if (entry.getType() == DatabaseEntry.KEY_TYPE_ROUTERINFO)
     94            return store(key, (RouterInfo) entry);
     95        if (entry.getType() == DatabaseEntry.KEY_TYPE_LEASESET)
     96            return store(key, (LeaseSet) entry);
     97        throw new IllegalArgumentException("unknown type");
     98    }
     99
    66100    /**
    67101     * @throws IllegalArgumentException if the local router is not valid
     
    102136     */
    103137    public boolean floodfillEnabled() { return false; };
     138
     139    /**
     140     *  Is it permanently negative cached?
     141     *
     142     *  @param key only for Destinations; for RouterIdentities, see Banlist
     143     *  @since 0.9.16
     144     */
     145    public boolean isNegativeCachedForever(Hash key) { return false; }
    104146}
  • router/java/src/net/i2p/router/OutNetMessage.java

    reab4397 r156d868  
    1919import java.util.Set;
    2020
    21 import net.i2p.data.RouterInfo;
     21import net.i2p.data.router.RouterInfo;
    2222import net.i2p.data.i2np.I2NPMessage;
    2323import net.i2p.router.util.CDPQEntry;
  • router/java/src/net/i2p/router/PersistentKeyRing.java

    reab4397 r156d868  
    7171            buf.append(h.toBase64().substring(0, 6)).append("&hellip;");
    7272            buf.append("<td>");
    73             LeaseSet ls = _ctx.netDb().lookupLeaseSetLocally(h);
    74             if (ls != null) {
    75                 Destination dest = ls.getDestination();
     73            Destination dest = _ctx.netDb().lookupDestinationLocally(h);
     74            if (dest != null) {
    7675                if (_ctx.clientManager().isLocal(dest)) {
    7776                    TunnelPoolSettings in = _ctx.tunnelManager().getInboundSettings(h);
  • router/java/src/net/i2p/router/Router.java

    reab4397 r156d868  
    3030import net.i2p.data.DataHelper;
    3131import net.i2p.data.Destination;
    32 import net.i2p.data.RouterInfo;
     32import net.i2p.data.router.RouterInfo;
    3333import net.i2p.data.SigningPrivateKey;
    3434import net.i2p.data.i2np.GarlicMessage;
    3535import net.i2p.router.message.GarlicMessageHandler;
    3636import net.i2p.router.networkdb.kademlia.FloodfillNetworkDatabaseFacade;
     37import net.i2p.router.startup.CreateRouterInfoJob;
    3738import net.i2p.router.startup.StartupJob;
    3839import net.i2p.router.startup.WorkingDir;
     
    99100    public final static String PROP_HIDDEN_HIDDEN = "router.isHidden";
    100101    public final static String PROP_DYNAMIC_KEYS = "router.dynamicKeys";
    101     public final static String PROP_INFO_FILENAME = "router.info.location";
    102     public final static String PROP_INFO_FILENAME_DEFAULT = "router.info";
    103     public final static String PROP_KEYS_FILENAME = "router.keys.location";
    104     public final static String PROP_KEYS_FILENAME_DEFAULT = "router.keys";
    105102    public final static String PROP_SHUTDOWN_IN_PROGRESS = "__shutdownInProgress";
    106103    public final static String DNS_CACHE_TIME = "" + (5*60);
     
    673670        return _context.commSystem().isInBadCountry();
    674671    }
    675 
    676     /**
    677      *  Only called at startup via LoadRouterInfoJob and RebuildRouterInfoJob.
    678      *  Not called by periodic RepublishLocalRouterInfoJob.
    679      *  We don't want to change the cert on the fly as it changes the router hash.
    680      *  RouterInfo.isHidden() checks the capability, but RouterIdentity.isHidden() checks the cert.
    681      *  There's no reason to ever add a hidden cert?
    682      *  @return the certificate for a new RouterInfo - probably a null cert.
    683      */
    684     public Certificate createCertificate() {
    685         if (_context.getBooleanProperty(PROP_HIDDEN))
    686             return new Certificate(Certificate.CERTIFICATE_TYPE_HIDDEN, null);
    687         return Certificate.NULL_CERT;
    688     }
    689672   
    690673    /**
     
    699682     *
    700683     */
    701     private static final String _rebuildFiles[] = new String[] { "router.info",
    702                                                                  "router.keys",
    703                                                                  "netDb/my.info",      // no longer used
    704                                                                  "connectionTag.keys", // never used?
    705                                                                  "keyBackup/privateEncryption.key",
    706                                                                  "keyBackup/privateSigning.key",
    707                                                                  "keyBackup/publicEncryption.key",
    708                                                                  "keyBackup/publicSigning.key",
    709                                                                  "sessionKeys.dat"     // no longer used
    710                                                                };
     684    private static final String _rebuildFiles[] = new String[] {
     685        CreateRouterInfoJob.INFO_FILENAME,
     686        CreateRouterInfoJob.KEYS_FILENAME,
     687        CreateRouterInfoJob.KEYS2_FILENAME,
     688        "netDb/my.info",      // no longer used
     689        "connectionTag.keys", // never used?
     690        KeyManager.DEFAULT_KEYDIR + '/' + KeyManager.KEYFILE_PRIVATE_ENC,
     691        KeyManager.DEFAULT_KEYDIR + '/' + KeyManager.KEYFILE_PUBLIC_ENC,
     692        KeyManager.DEFAULT_KEYDIR + '/' + KeyManager.KEYFILE_PRIVATE_SIGNING,
     693        KeyManager.DEFAULT_KEYDIR + '/' + KeyManager.KEYFILE_PUBLIC_SIGNING,
     694        "sessionKeys.dat"     // no longer used
     695    };
    711696
    712697    public void killKeys() {
  • router/java/src/net/i2p/router/RouterContext.java

    reab4397 r156d868  
    1111import net.i2p.app.ClientAppManager;
    1212import net.i2p.data.Hash;
    13 import net.i2p.data.RouterInfo;
     13import net.i2p.data.router.RouterInfo;
    1414import net.i2p.internal.InternalClientManager;
    1515import net.i2p.router.client.ClientManagerFacadeImpl;
  • router/java/src/net/i2p/router/RouterThrottleImpl.java

    reab4397 r156d868  
    22
    33import net.i2p.data.Hash;
    4 import net.i2p.data.RouterInfo;
     4import net.i2p.data.router.RouterInfo;
    55import net.i2p.router.peermanager.TunnelHistory;
    66import net.i2p.stat.Rate;
  • router/java/src/net/i2p/router/client/ClientMessageEventListener.java

    reab4397 r156d868  
    1313import net.i2p.CoreVersion;
    1414import net.i2p.crypto.SigType;
     15import net.i2p.data.Destination;
    1516import net.i2p.data.Hash;
    1617import net.i2p.data.Payload;
     18import net.i2p.data.PublicKey;
    1719import net.i2p.data.i2cp.BandwidthLimitsMessage;
    1820import net.i2p.data.i2cp.CreateLeaseSetMessage;
     
    3840import net.i2p.data.i2cp.SetDateMessage;
    3941import net.i2p.router.ClientTunnelSettings;
     42import net.i2p.router.LeaseSetKeys;
    4043import net.i2p.router.RouterContext;
    4144import net.i2p.util.Log;
     
    8285        int type = message.getType();
    8386        if (!_authorized) {
    84             // TODO change to default true
    85             boolean strict = _context.getBooleanProperty(PROP_AUTH_STRICT);
     87            // Default true as of 0.9.16
     88            boolean strict = _context.getBooleanPropertyDefaultTrue(PROP_AUTH_STRICT);
    8689            if ((strict && type != GetDateMessage.MESSAGE_TYPE) ||
    8790                (type != CreateSessionMessage.MESSAGE_TYPE &&
     
    368371            return;
    369372        }
    370 
    371         _context.keyManager().registerKeys(message.getLeaseSet().getDestination(), message.getSigningPrivateKey(), message.getPrivateKey());
     373        Destination dest = _runner.getConfig().getDestination();
     374        Destination ndest = message.getLeaseSet().getDestination();
     375        if (!dest.equals(ndest)) {
     376            if (_log.shouldLog(Log.ERROR))
     377                _log.error("Different destination in LS");
     378            _runner.disconnectClient("Different destination in LS");
     379            return;
     380        }
     381        LeaseSetKeys keys = _context.keyManager().getKeys(dest);
     382        if (keys == null ||
     383            !message.getPrivateKey().equals(keys.getDecryptionKey())) {
     384            // Verify and register crypto keys if new or if changed
     385            // Private crypto key should never change, and if it does,
     386            // one of the checks below will fail
     387            PublicKey pk;
     388            try {
     389                pk = message.getPrivateKey().toPublic();
     390            } catch (IllegalArgumentException iae) {
     391                if (_log.shouldLog(Log.ERROR))
     392                    _log.error("Bad private key in LS");
     393                _runner.disconnectClient("Bad private key in LS");
     394                return;
     395            }
     396            if (!pk.equals(message.getLeaseSet().getEncryptionKey())) {
     397                if (_log.shouldLog(Log.ERROR))
     398                    _log.error("Private/public crypto key mismatch in LS");
     399                _runner.disconnectClient("Private/public crypto key mismatch in LS");
     400                return;
     401            }
     402            // just register new SPK, don't verify, unused
     403            _context.keyManager().registerKeys(dest, message.getSigningPrivateKey(), message.getPrivateKey());
     404        } else if (!message.getSigningPrivateKey().equals(keys.getRevocationKey())) {
     405            // just register new SPK, don't verify, unused
     406            _context.keyManager().registerKeys(dest, message.getSigningPrivateKey(), message.getPrivateKey());
     407        }
    372408        try {
    373409            _context.netDb().publish(message.getLeaseSet());
  • router/java/src/net/i2p/router/client/LookupDestJob.java

    reab4397 r156d868  
    3939
    4040    /**
    41      *  One of h or name non-null
     41     *  One of h or name non-null.
     42     *
     43     *  For hash or b32 name, the dest will be returned if the LS can be found,
     44     *  even if the dest uses unsupported crypto.
     45     *
    4246     *  @param reqID must be >= 0 if name != null
    4347     *  @param sessID must non-null if reqID >= 0
     
    8993        } else {
    9094            DoneJob done = new DoneJob(getContext());
    91             getContext().netDb().lookupLeaseSet(_hash, done, done, _timeout, _fromLocalDest);
     95            getContext().netDb().lookupDestination(_hash, done, _timeout, _fromLocalDest);
    9296        }
    9397    }
     
    99103        public String getName() { return "LeaseSet Lookup Reply to Client"; }
    100104        public void runJob() {
    101             LeaseSet ls = getContext().netDb().lookupLeaseSetLocally(_hash);
    102             if (ls != null)
    103                 returnDest(ls.getDestination());
     105            Destination dest = getContext().netDb().lookupDestinationLocally(_hash);
     106            if (dest != null)
     107                returnDest(dest);
    104108            else
    105109                returnFail();
  • router/java/src/net/i2p/router/dummy/DummyNetworkDatabaseFacade.java

    reab4397 r156d868  
    1616
    1717import net.i2p.data.DatabaseEntry;
     18import net.i2p.data.Destination;
    1819import net.i2p.data.Hash;
    1920import net.i2p.data.LeaseSet;
    20 import net.i2p.data.RouterInfo;
     21import net.i2p.data.router.RouterInfo;
    2122import net.i2p.router.Job;
    2223import net.i2p.router.NetworkDatabaseFacade;
     
    2425
    2526public class DummyNetworkDatabaseFacade extends NetworkDatabaseFacade {
    26     private Map<Hash, RouterInfo> _routers;
    27     private RouterContext _context;
     27    private final Map<Hash, RouterInfo> _routers;
     28    private final RouterContext _context;
    2829   
    2930    public DummyNetworkDatabaseFacade(RouterContext ctx) {
     
    4344    public void lookupLeaseSet(Hash key, Job onFindJob, Job onFailedLookupJob, long timeoutMs, Hash fromLocalDest) {}
    4445    public LeaseSet lookupLeaseSetLocally(Hash key) { return null; }
     46
     47    public void lookupDestination(Hash key, Job onFinishedJob, long timeoutMs, Hash fromLocalDest) {}
     48
     49    public Destination lookupDestinationLocally(Hash key) { return null; }
     50
    4551    public void lookupRouterInfo(Hash key, Job onFindJob, Job onFailedLookupJob, long timeoutMs) {
    4652        RouterInfo info = lookupRouterInfoLocally(key);
     
    5157    }
    5258    public RouterInfo lookupRouterInfoLocally(Hash key) { return _routers.get(key); }
     59
    5360    public void publish(LeaseSet localLeaseSet) {}
    5461    public void publish(RouterInfo localRouterInfo) {}
     62
    5563    public LeaseSet store(Hash key, LeaseSet leaseSet) { return leaseSet; }
    5664    public RouterInfo store(Hash key, RouterInfo routerInfo) {
     
    5866        return rv;
    5967    }
     68
    6069    public void unpublish(LeaseSet localLeaseSet) {}
    6170    public void fail(Hash dbEntry) {
  • router/java/src/net/i2p/router/message/GarlicConfig.java

    reab4397 r156d868  
    1515import net.i2p.data.Certificate;
    1616import net.i2p.data.PublicKey;
    17 import net.i2p.data.RouterInfo;
     17import net.i2p.data.router.RouterInfo;
    1818import net.i2p.data.i2np.DeliveryInstructions;
    1919
  • router/java/src/net/i2p/router/message/GarlicMessageHandler.java

    reab4397 r156d868  
    1010
    1111import net.i2p.data.Hash;
    12 import net.i2p.data.RouterIdentity;
     12import net.i2p.data.router.RouterIdentity;
    1313import net.i2p.data.i2np.GarlicMessage;
    1414import net.i2p.data.i2np.I2NPMessage;
  • router/java/src/net/i2p/router/message/HandleGarlicMessageJob.java

    reab4397 r156d868  
    1010
    1111import net.i2p.data.Hash;
    12 import net.i2p.data.RouterIdentity;
     12import net.i2p.data.router.RouterIdentity;
    1313import net.i2p.data.i2np.DeliveryInstructions;
    1414import net.i2p.data.i2np.GarlicMessage;
  • router/java/src/net/i2p/router/message/OutboundClientMessageOneShotJob.java

    reab4397 r156d868  
    1919import net.i2p.data.Payload;
    2020import net.i2p.data.PublicKey;
    21 import net.i2p.data.RouterInfo;
     21import net.i2p.data.router.RouterInfo;
    2222import net.i2p.data.SessionKey;
    2323import net.i2p.data.SessionTag;
     
    426426            }
    427427           
    428             //if (_finished == Result.NONE) {
     428
     429            int cause;
     430            if (getContext().netDb().isNegativeCachedForever(_to.calculateHash())) {
     431                if (_log.shouldLog(Log.WARN))
     432                    _log.warn("Unable to send to " + _toString + " because the sig type is unsupported");
     433                cause = MessageStatusMessage.STATUS_SEND_FAILURE_UNSUPPORTED_ENCRYPTION;
     434            } else {
    429435                if (_log.shouldLog(Log.WARN))
    430436                    _log.warn("Unable to send to " + _toString + " because we couldn't find their leaseSet");
    431             //}
    432 
    433             dieFatal(MessageStatusMessage.STATUS_SEND_FAILURE_NO_LEASESET);
     437                cause = MessageStatusMessage.STATUS_SEND_FAILURE_NO_LEASESET;
     438            }
     439
     440            dieFatal(cause);
    434441        }
    435442    }
  • router/java/src/net/i2p/router/message/SendMessageDirectJob.java

    reab4397 r156d868  
    1212
    1313import net.i2p.data.Hash;
    14 import net.i2p.data.RouterInfo;
     14import net.i2p.data.router.RouterInfo;
    1515import net.i2p.data.i2np.I2NPMessage;
    1616import net.i2p.router.Job;
  • router/java/src/net/i2p/router/networkdb/HandleDatabaseLookupMessageJob.java

    reab4397 r156d868  
    1515import net.i2p.data.Hash;
    1616import net.i2p.data.LeaseSet;
    17 import net.i2p.data.RouterIdentity;
    18 import net.i2p.data.RouterInfo;
     17import net.i2p.data.router.RouterIdentity;
     18import net.i2p.data.router.RouterInfo;
    1919import net.i2p.data.SessionKey;
    2020import net.i2p.data.TunnelId;
  • router/java/src/net/i2p/router/networkdb/PublishLocalRouterInfoJob.java

    reab4397 r156d868  
    1313
    1414import net.i2p.data.DataFormatException;
    15 import net.i2p.data.RouterInfo;
     15import net.i2p.data.router.RouterInfo;
    1616import net.i2p.data.SigningPrivateKey;
    1717import net.i2p.router.JobImpl;
  • router/java/src/net/i2p/router/networkdb/kademlia/BundleRouterInfos.java

    reab4397 r156d868  
    2626import net.i2p.I2PAppContext;
    2727import net.i2p.data.Hash;
    28 import net.i2p.data.RouterAddress;
    29 import net.i2p.data.RouterInfo;
     28import net.i2p.data.router.RouterAddress;
     29import net.i2p.data.router.RouterInfo;
    3030import net.i2p.router.transport.BadCountries;
    3131import net.i2p.router.transport.GeoIP;
  • router/java/src/net/i2p/router/networkdb/kademlia/ExpireRoutersJob.java

    reab4397 r156d868  
    1313import net.i2p.data.DatabaseEntry;
    1414import net.i2p.data.Hash;
    15 import net.i2p.data.RouterInfo;
     15import net.i2p.data.router.RouterInfo;
    1616import net.i2p.router.CommSystemFacade;
    1717import net.i2p.router.JobImpl;
  • router/java/src/net/i2p/router/networkdb/kademlia/ExploreJob.java

    reab4397 r156d868  
    1616import net.i2p.data.TunnelId;
    1717import net.i2p.data.i2np.DatabaseLookupMessage;
     18import net.i2p.data.i2np.I2NPMessage;
     19import net.i2p.data.router.RouterInfo;
    1820import net.i2p.kademlia.KBucketSet;
    1921import net.i2p.router.RouterContext;
     
    7274     * so we add the ff peers ourselves and then use the regular PeerSelector.
    7375     *
    74      * TODO should we encrypt this also like we do for normal lookups?
    75      * Could the OBEP capture it and reply with a reference to a hostile peer?
    76      *
    7776     * @param replyTunnelId tunnel to receive replies through
    7877     * @param replyGateway gateway for the reply tunnel
    7978     * @param expiration when the search should stop
     79     * @param peer the peer to send it to
     80     *
     81     * @return a DatabaseLookupMessage or GarlicMessage
    8082     */
    8183    @Override
    82     protected DatabaseLookupMessage buildMessage(TunnelId replyTunnelId, Hash replyGateway, long expiration) {
     84    protected I2NPMessage buildMessage(TunnelId replyTunnelId, Hash replyGateway, long expiration, RouterInfo peer) {
    8385        DatabaseLookupMessage msg = new DatabaseLookupMessage(getContext(), true);
    8486        msg.setSearchKey(getState().getTarget());
     
    128130       
    129131        msg.setDontIncludePeers(dontIncludePeers);
    130         return msg;
     132
     133        // Now encrypt if we can
     134        I2NPMessage outMsg;
     135        if (getContext().getProperty(IterativeSearchJob.PROP_ENCRYPT_RI, IterativeSearchJob.DEFAULT_ENCRYPT_RI)) {
     136            // request encrypted reply?
     137            if (DatabaseLookupMessage.supportsEncryptedReplies(peer)) {
     138                MessageWrapper.OneTimeSession sess;
     139                sess = MessageWrapper.generateSession(getContext());
     140                if (_log.shouldLog(Log.INFO))
     141                    _log.info(getJobId() + ": Requesting encrypted reply from " + peer.getIdentity().calculateHash() +
     142                              ' ' + sess.key + ' ' + sess.tag);
     143                msg.setReplySession(sess.key, sess.tag);
     144            }
     145            outMsg = MessageWrapper.wrap(getContext(), msg, peer);
     146            if (_log.shouldLog(Log.DEBUG))
     147                _log.debug(getJobId() + ": Encrypted exploratory DLM for " + getState().getTarget() + " to " +
     148                           peer.getIdentity().calculateHash());
     149        } else {
     150            outMsg = msg;
     151        }
     152        return outMsg;
    131153    }
    132154   
  • router/java/src/net/i2p/router/networkdb/kademlia/FloodOnlyLookupMatchJob.java

    reab4397 r156d868  
    33import net.i2p.data.DatabaseEntry;
    44import net.i2p.data.LeaseSet;
    5 import net.i2p.data.RouterInfo;
    65import net.i2p.data.i2np.DatabaseSearchReplyMessage;
    76import net.i2p.data.i2np.DatabaseStoreMessage;
    87import net.i2p.data.i2np.I2NPMessage;
     8import net.i2p.data.router.RouterInfo;
    99import net.i2p.router.JobImpl;
    1010import net.i2p.router.ReplyJob;
     
    6363                getContext().netDb().store(dsm.getKey(), (RouterInfo) dsm.getEntry());
    6464            }
     65        } catch (UnsupportedCryptoException uce) {
     66            _search.failed();
     67            return;
    6568        } catch (IllegalArgumentException iae) {
    6669            if (_log.shouldLog(Log.WARN))
  • router/java/src/net/i2p/router/networkdb/kademlia/FloodfillDatabaseLookupMessageHandler.java

    reab4397 r156d868  
    1010
    1111import net.i2p.data.Hash;
    12 import net.i2p.data.RouterIdentity;
     12import net.i2p.data.router.RouterIdentity;
    1313import net.i2p.data.i2np.DatabaseLookupMessage;
    1414import net.i2p.data.i2np.I2NPMessage;
  • router/java/src/net/i2p/router/networkdb/kademlia/FloodfillDatabaseStoreMessageHandler.java

    reab4397 r156d868  
    1010
    1111import net.i2p.data.Hash;
    12 import net.i2p.data.RouterIdentity;
     12import net.i2p.data.router.RouterIdentity;
    1313import net.i2p.data.i2np.DatabaseStoreMessage;
    1414import net.i2p.data.i2np.I2NPMessage;
  • router/java/src/net/i2p/router/networkdb/kademlia/FloodfillMonitorJob.java

    reab4397 r156d868  
    44
    55import net.i2p.data.Hash;
    6 import net.i2p.data.RouterAddress;
    7 import net.i2p.data.RouterInfo;
     6import net.i2p.data.router.RouterAddress;
     7import net.i2p.data.router.RouterInfo;
    88import net.i2p.router.JobImpl;
    99import net.i2p.router.Router;
  • router/java/src/net/i2p/router/networkdb/kademlia/FloodfillNetworkDatabaseFacade.java

    reab4397 r156d868  
    88
    99import net.i2p.data.DatabaseEntry;
     10import net.i2p.data.Destination;
    1011import net.i2p.data.Hash;
    11 import net.i2p.data.RouterInfo;
    1212import net.i2p.data.TunnelId;
    1313import net.i2p.data.i2np.DatabaseLookupMessage;
    1414import net.i2p.data.i2np.DatabaseStoreMessage;
     15import net.i2p.data.router.RouterInfo;
    1516import net.i2p.router.Job;
    1617import net.i2p.router.JobImpl;
     
    3233    private FloodThrottler _floodThrottler;
    3334    private LookupThrottler _lookupThrottler;
    34     private NegativeLookupCache _negativeCache;
    3535
    3636    /**
     
    6666        _context.statManager().createRateStat("netDb.searchReplyValidationSkipped", "How many search replies we get from unreliable peers that we skip?", "NetworkDatabase", new long[] { 5*60*1000l, 10*60*1000l, 60*60*1000l, 3*60*60*1000l, 24*60*60*1000l });
    6767        _context.statManager().createRateStat("netDb.republishQuantity", "How many peers do we need to send a found leaseSet to?", "NetworkDatabase", new long[] { 10*60*1000l, 60*60*1000l, 3*60*60*1000l, 24*60*60*1000l });
    68         _context.statManager().createRateStat("netDb.negativeCache", "Aborted lookup, already cached", "NetworkDatabase", new long[] { 60*60*1000l });
    6968    }
    7069
     
    7473        _context.jobQueue().addJob(new FloodfillMonitorJob(_context, this));
    7574        _lookupThrottler = new LookupThrottler();
    76         _negativeCache = new NegativeLookupCache();
    7775
    7876        // refresh old routers
     
    170168    boolean shouldThrottleLookup(Hash from, TunnelId id) {
    171169        return _lookupThrottler.shouldThrottle(from, id);
    172     }
    173 
    174     /**
    175      *  Increment in the negative lookup cache
    176      *  @since 0.9.4
    177      */
    178     void lookupFailed(Hash key) {
    179         _negativeCache.lookupFailed(key);
    180     }
    181 
    182     /**
    183      *  Is the key in the negative lookup cache?
    184      *  @since 0.9.4
    185      */
    186     boolean isNegativeCached(Hash key) {
    187         boolean rv = _negativeCache.isCached(key);
    188         if (rv)
    189             _context.statManager().addRateData("netDb.negativeCache", 1);
    190         return rv;
    191170    }
    192171
     
    302281   
    303282    /**
    304      * Lookup using exploratory tunnels
     283     * Lookup using exploratory tunnels.
     284     *
     285     * Caller should check negative cache and/or banlist before calling.
    305286     *
    306287     * Begin a kademlia style search for the key specified, which can take up to timeoutMs and
     
    316297
    317298    /**
    318      * Lookup using the client's tunnels
     299     * Lookup using the client's tunnels.
     300     *
     301     * Caller should check negative cache and/or banlist before calling.
     302     *
    319303     * @param fromLocalDest use these tunnels for the lookup, or null for exploratory
    320304     * @return null always
     
    474458        if (_floodfillEnabled ||
    475459            _context.jobQueue().getMaxLag() > 500 ||
     460            _context.banlist().isBanlistedForever(peer) ||
    476461            getKBucketSetSize() > MAX_DB_BEFORE_SKIPPING_SEARCH) {
    477462            // don't try to overload ourselves (e.g. failing 3000 router refs at
  • router/java/src/net/i2p/router/networkdb/kademlia/FloodfillPeerSelector.java

    reab4397 r156d868  
    1919
    2020import net.i2p.data.Hash;
    21 import net.i2p.data.RouterAddress;
    22 import net.i2p.data.RouterInfo;
     21import net.i2p.data.router.RouterAddress;
     22import net.i2p.data.router.RouterInfo;
    2323import net.i2p.kademlia.KBucketSet;
    2424import net.i2p.kademlia.SelectionCollector;
  • router/java/src/net/i2p/router/networkdb/kademlia/FloodfillVerifyStoreJob.java

    reab4397 r156d868  
    77import net.i2p.data.Certificate;
    88import net.i2p.data.DatabaseEntry;
     9import net.i2p.data.Destination;
    910import net.i2p.data.Hash;
    1011import net.i2p.data.LeaseSet;
    11 import net.i2p.data.RouterInfo;
     12import net.i2p.data.router.RouterInfo;
    1213import net.i2p.data.i2np.DatabaseLookupMessage;
    1314import net.i2p.data.i2np.DatabaseSearchReplyMessage;
     
    174175        Certificate keyCert = null;
    175176        if (!_isRouterInfo) {
    176             LeaseSet ls = _facade.lookupLeaseSetLocally(_key);
    177             if (ls != null) {
    178                 Certificate cert = ls.getDestination().getCertificate();
     177            Destination dest = _facade.lookupDestinationLocally(_key);
     178            if (dest != null) {
     179                Certificate cert = dest.getCertificate();
    179180                if (cert.getCertificateType() == Certificate.CERTIFICATE_TYPE_KEY)
    180181                    keyCert = cert;
  • router/java/src/net/i2p/router/networkdb/kademlia/HandleFloodfillDatabaseLookupMessageJob.java

    reab4397 r156d868  
    1212
    1313import net.i2p.data.Hash;
    14 import net.i2p.data.RouterIdentity;
    15 import net.i2p.data.RouterInfo;
     14import net.i2p.data.router.RouterIdentity;
     15import net.i2p.data.router.RouterInfo;
    1616import net.i2p.data.TunnelId;
    1717import net.i2p.data.i2np.DatabaseStoreMessage;
  • router/java/src/net/i2p/router/networkdb/kademlia/HandleFloodfillDatabaseStoreMessageJob.java

    reab4397 r156d868  
    1515import net.i2p.data.Hash;
    1616import net.i2p.data.LeaseSet;
    17 import net.i2p.data.RouterAddress;
    18 import net.i2p.data.RouterIdentity;
    19 import net.i2p.data.RouterInfo;
     17import net.i2p.data.router.RouterAddress;
     18import net.i2p.data.router.RouterIdentity;
     19import net.i2p.data.router.RouterInfo;
    2020import net.i2p.data.i2np.DatabaseStoreMessage;
    2121import net.i2p.data.i2np.DeliveryStatusMessage;
     
    5252       
    5353        String invalidMessage = null;
     54        // set if invalid store but not his fault
     55        boolean dontBlamePeer = false;
    5456        boolean wasNew = false;
    5557        RouterInfo prevNetDb = null;
     
    7375                    //getContext().statManager().addRateData("netDb.storeLocalLeaseSetAttempt", 1, 0);
    7476                    // throw rather than return, so that we send the ack below (prevent easy attack)
     77                    dontBlamePeer = true;
    7578                    throw new IllegalArgumentException("Peer attempted to store local leaseSet: " +
    7679                                                       key.toBase64().substring(0, 4));
     
    115118                    //    match.setReceivedAsPublished(true);
    116119                }
     120            } catch (UnsupportedCryptoException uce) {
     121                invalidMessage = uce.getMessage();
     122                dontBlamePeer = true;
    117123            } catch (IllegalArgumentException iae) {
    118124                invalidMessage = iae.getMessage();
     
    132138                    //getContext().statManager().addRateData("netDb.storeLocalRouterInfoAttempt", 1, 0);
    133139                    // throw rather than return, so that we send the ack below (prevent easy attack)
     140                    dontBlamePeer = true;
    134141                    throw new IllegalArgumentException("Peer attempted to store our RouterInfo");
    135142                }
     143                getContext().profileManager().heardAbout(key);
    136144                prevNetDb = getContext().netDb().store(key, ri);
    137145                wasNew = ((null == prevNetDb) || (prevNetDb.getPublished() < ri.getPublished()));
     
    153161                    }
    154162                }
    155                 getContext().profileManager().heardAbout(key);
     163            } catch (UnsupportedCryptoException uce) {
     164                invalidMessage = uce.getMessage();
     165                dontBlamePeer = true;
    156166            } catch (IllegalArgumentException iae) {
    157167                invalidMessage = iae.getMessage();
     
    166176        getContext().statManager().addRateData("netDb.storeRecvTime", recvEnd-recvBegin);
    167177       
    168         if (_message.getReplyToken() > 0)
     178        // ack even if invalid or unsupported
     179        // TODO any cases where we shouldn't?
     180        if (_message.getReplyToken() > 0)
    169181            sendAck();
    170182        long ackEnd = System.currentTimeMillis();
     
    173185            _fromHash = _from.getHash();
    174186        if (_fromHash != null) {
    175             if (invalidMessage == null) {
     187            if (invalidMessage == null || dontBlamePeer) {
    176188                getContext().profileManager().dbStoreReceived(_fromHash, wasNew);
    177189                getContext().statManager().addRateData("netDb.storeHandled", ackEnd-recvEnd);
     
    181193                    _log.warn("Peer " + _fromHash.toBase64() + " sent bad data: " + invalidMessage);
    182194            }
    183         } else if (invalidMessage != null) {
     195        } else if (invalidMessage != null && !dontBlamePeer) {
    184196            if (_log.shouldLog(Log.WARN))
    185197                _log.warn("Unknown peer sent bad data: " + invalidMessage);
  • router/java/src/net/i2p/router/networkdb/kademlia/HarvesterJob.java

    reab4397 r156d868  
    88
    99import net.i2p.data.Hash;
    10 import net.i2p.data.RouterInfo;
     10import net.i2p.data.router.RouterInfo;
    1111import net.i2p.data.i2np.DatabaseLookupMessage;
    1212import net.i2p.router.JobImpl;
  • router/java/src/net/i2p/router/networkdb/kademlia/IterativeLookupJob.java

    reab4397 r156d868  
    22
    33import net.i2p.data.Hash;
    4 import net.i2p.data.RouterInfo;
     4import net.i2p.data.router.RouterInfo;
    55import net.i2p.data.i2np.DatabaseSearchReplyMessage;
    66import net.i2p.util.Log;
  • router/java/src/net/i2p/router/networkdb/kademlia/IterativeSearchJob.java

    reab4397 r156d868  
    1414import net.i2p.data.DataHelper;
    1515import net.i2p.data.Hash;
    16 import net.i2p.data.RouterInfo;
    1716import net.i2p.data.i2np.DatabaseLookupMessage;
    1817import net.i2p.data.i2np.I2NPMessage;
     18import net.i2p.data.router.RouterInfo;
    1919import net.i2p.kademlia.KBucketSet;
    2020import net.i2p.kademlia.XORComparator;
     
    2929import net.i2p.router.util.RandomIterator;
    3030import net.i2p.util.Log;
     31import net.i2p.util.NativeBigInteger;
     32import net.i2p.util.SystemVersion;
    3133
    3234/**
     
    8991    private static final int MAX_CONCURRENT = 1;
    9092
    91     /** testing */
    92     private static final String PROP_ENCRYPT_RI = "router.encryptRouterLookups";
     93    public static final String PROP_ENCRYPT_RI = "router.encryptRouterLookups";
     94
     95    /** only on fast boxes, for now */
     96    public static final boolean DEFAULT_ENCRYPT_RI =
     97            SystemVersion.isX86() && SystemVersion.is64Bit() &&
     98            !SystemVersion.isApache() && !SystemVersion.isGNU() &&
     99            NativeBigInteger.isNative();
    93100
    94101    /**
     
    316323
    317324            I2NPMessage outMsg = null;
    318             if (_isLease || getContext().getBooleanProperty(PROP_ENCRYPT_RI)) {
     325            if (_isLease || getContext().getProperty(PROP_ENCRYPT_RI, DEFAULT_ENCRYPT_RI)) {
    319326                // Full ElG is fairly expensive so only do it for LS lookups
    320327                // if we have the ff RI, garlic encrypt it
  • router/java/src/net/i2p/router/networkdb/kademlia/KademliaNetworkDatabaseFacade.java

    reab4397 r156d868  
    2020import java.util.Set;
    2121
     22import net.i2p.crypto.SigType;
     23import net.i2p.data.Certificate;
    2224import net.i2p.data.DatabaseEntry;
     25import net.i2p.data.DataFormatException;
    2326import net.i2p.data.DataHelper;
     27import net.i2p.data.Destination;
    2428import net.i2p.data.Hash;
     29import net.i2p.data.KeyCertificate;
    2530import net.i2p.data.LeaseSet;
    26 import net.i2p.data.RouterAddress;
    27 import net.i2p.data.RouterInfo;
    2831import net.i2p.data.i2np.DatabaseLookupMessage;
    2932import net.i2p.data.i2np.DatabaseStoreMessage;
     33import net.i2p.data.router.RouterAddress;
     34import net.i2p.data.router.RouterIdentity;
     35import net.i2p.data.router.RouterInfo;
    3036import net.i2p.kademlia.KBucketSet;
    3137import net.i2p.kademlia.RejectTrimmer;
     
    6470    private final ReseedChecker _reseedChecker;
    6571    private volatile long _lastRIPublishTime;
     72    private NegativeLookupCache _negativeCache;
    6673
    6774    /**
     
    156163        context.statManager().createRateStat("netDb.lookupDeferred", "how many lookups are deferred?", "NetworkDatabase", new long[] { 60*60*1000 });
    157164        context.statManager().createRateStat("netDb.exploreKeySet", "how many keys are queued for exploration?", "NetworkDatabase", new long[] { 60*60*1000 });
     165        context.statManager().createRateStat("netDb.negativeCache", "Aborted lookup, already cached", "NetworkDatabase", new long[] { 60*60*1000l });
    158166        // following are for StoreJob
    159167        context.statManager().createRateStat("netDb.storeRouterInfoSent", "How many routerInfo store messages have we sent?", "NetworkDatabase", new long[] { 60*60*1000l });
     
    224232        _exploreKeys.clear(); // hope this doesn't cause an explosion, it shouldn't.
    225233        // _exploreKeys = null;
     234        _negativeCache.clear();
    226235    }
    227236   
     
    263272//        _exploreKeys = new HashSet(64);
    264273        _dbDir = dbDir;
     274        _negativeCache = new NegativeLookupCache();
    265275       
    266276        createHandlers();
     
    481491
    482492    /**
    483      *  Lookup using exploratory tunnels
     493     *  Lookup using exploratory tunnels.
     494     *  Use lookupDestination() if you don't need the LS or need it validated.
    484495     */
    485496    public void lookupLeaseSet(Hash key, Job onFindJob, Job onFailedLookupJob, long timeoutMs) {
     
    489500    /**
    490501     *  Lookup using the client's tunnels
     502     *  Use lookupDestination() if you don't need the LS or need it validated.
     503     *
    491504     *  @param fromLocalDest use these tunnels for the lookup, or null for exploratory
    492505     *  @since 0.9.10
     
    501514            if (onFindJob != null)
    502515                _context.jobQueue().addJob(onFindJob);
     516        } else if (isNegativeCached(key)) {
     517            if (_log.shouldLog(Log.WARN))
     518                _log.warn("Negative cached, not searching: " + key);
     519            if (onFailedLookupJob != null)
     520                _context.jobQueue().addJob(onFailedLookupJob);
    503521        } else {
    504522            if (_log.shouldLog(Log.DEBUG))
     
    510528    }
    511529   
     530    /**
     531     *  Use lookupDestination() if you don't need the LS or need it validated.
     532     */
    512533    public LeaseSet lookupLeaseSetLocally(Hash key) {
    513534        if (!_initialized) return null;
     
    532553        }
    533554    }
     555
     556    /**
     557     *  Lookup using the client's tunnels
     558     *  Succeeds even if LS validation and store fails due to unsupported sig type, expired, etc.
     559     *
     560     *  Note that there are not separate success and fail jobs. Caller must call
     561     *  lookupDestinationLocally() in the job to determine success.
     562     *
     563     *  @param onFinishedJob non-null
     564     *  @param fromLocalDest use these tunnels for the lookup, or null for exploratory
     565     *  @since 0.9.16
     566     */
     567    public void lookupDestination(Hash key, Job onFinishedJob, long timeoutMs, Hash fromLocalDest) {
     568        if (!_initialized) return;
     569        Destination d = lookupDestinationLocally(key);
     570        if (d != null) {
     571            _context.jobQueue().addJob(onFinishedJob);
     572        } else {
     573            search(key, onFinishedJob, onFinishedJob, timeoutMs, true, fromLocalDest);
     574        }
     575    }
     576
     577    /**
     578     *  Lookup locally in netDB and in badDest cache
     579     *  Succeeds even if LS validation fails due to unsupported sig type, expired, etc.
     580     *
     581     *  @since 0.9.16
     582     */
     583    public Destination lookupDestinationLocally(Hash key) {
     584        if (!_initialized) return null;
     585        DatabaseEntry ds = _ds.get(key);
     586        if (ds != null) {
     587            if (ds.getType() == DatabaseEntry.KEY_TYPE_LEASESET) {
     588                LeaseSet ls = (LeaseSet)ds;
     589                return ls.getDestination();
     590            }
     591        } else {
     592            return _negativeCache.getBadDest(key);
     593        }
     594        return null;
     595    }
    534596   
    535597    public void lookupRouterInfo(Hash key, Job onFindJob, Job onFailedLookupJob, long timeoutMs) {
     
    539601            if (onFindJob != null)
    540602                _context.jobQueue().addJob(onFindJob);
     603        } else if (_context.banlist().isBanlistedForever(key)) {
     604            if (onFailedLookupJob != null)
     605                _context.jobQueue().addJob(onFailedLookupJob);
    541606        } else {
    542607            search(key, onFindJob, onFailedLookupJob, timeoutMs, false);
     
    695760     * After that, LeaseSet.isCurrent() is used.
    696761     *
     762     * @throws UnsupportedCryptoException if that's why it failed.
    697763     * @return reason why the entry is not valid, or null if it is valid
    698764     */
    699     private String validate(Hash key, LeaseSet leaseSet) {
     765    private String validate(Hash key, LeaseSet leaseSet) throws UnsupportedCryptoException {
    700766        if (!key.equals(leaseSet.getDestination().calculateHash())) {
    701767            if (_log.shouldLog(Log.WARN))
     
    705771        }
    706772        if (!leaseSet.verifySignature()) {
     773            // throws UnsupportedCryptoException
     774            processStoreFailure(key, leaseSet);
    707775            if (_log.shouldLog(Log.WARN))
    708                 _log.warn("Invalid leaseSet signature!  leaseSet = " + leaseSet);
    709             return "Invalid leaseSet signature on " + leaseSet.getDestination().calculateHash().toBase64();
     776                _log.warn("Invalid leaseSet signature! " + leaseSet);
     777            return "Invalid leaseSet signature on " + key;
    710778        }
    711779        long earliest = leaseSet.getEarliestLeaseDate();
     
    723791                          + " last exp. " + new Date(latest),
    724792                          new Exception("Rejecting store"));
    725             return "Expired leaseSet for " + leaseSet.getDestination().calculateHash().toBase64()
     793            return "Expired leaseSet for " + leaseSet.getDestination().calculateHash()
    726794                   + " expired " + DataHelper.formatDuration(age) + " ago";
    727795        }
     
    740808   
    741809    /**
    742      * Store the leaseSet
     810     * Store the leaseSet.
     811     *
     812     * If the store fails due to unsupported crypto, it will negative cache
     813     * the hash until restart.
    743814     *
    744815     * @throws IllegalArgumentException if the leaseSet is not valid
     816     * @throws UnsupportedCryptoException if that's why it failed.
    745817     * @return previous entry or null
    746818     */
     
    799871     * Call this only on first store, to check the key and signature once
    800872     *
     873     * If the store fails due to unsupported crypto, it will banlist
     874     * the router hash until restart and then throw UnsupportedCrytpoException.
     875     *
     876     * @throws UnsupportedCryptoException if that's why it failed.
    801877     * @return reason why the entry is not valid, or null if it is valid
    802878     */
     
    808884        }
    809885        if (!routerInfo.isValid()) {
     886            // throws UnsupportedCryptoException
     887            processStoreFailure(key, routerInfo);
    810888            if (_log.shouldLog(Log.WARN))
    811889                _log.warn("Invalid routerInfo signature!  forged router structure!  router = " + routerInfo);
     
    893971   
    894972    /**
    895      * store the routerInfo
     973     * Store the routerInfo.
     974     *
     975     * If the store fails due to unsupported crypto, it will banlist
     976     * the router hash until restart and then throw UnsupportedCrytpoException.
    896977     *
    897978     * @throws IllegalArgumentException if the routerInfo is not valid
     979     * @throws UnsupportedCryptoException if that's why it failed.
    898980     * @return previous entry or null
    899981     */
     
    902984    }
    903985
     986    /**
     987     * Store the routerInfo.
     988     *
     989     * If the store fails due to unsupported crypto, it will banlist
     990     * the router hash until restart and then throw UnsupportedCrytpoException.
     991     *
     992     * @throws IllegalArgumentException if the routerInfo is not valid
     993     * @throws UnsupportedCryptoException if that's why it failed.
     994     * @return previous entry or null
     995     */
    904996    RouterInfo store(Hash key, RouterInfo routerInfo, boolean persist) throws IllegalArgumentException {
    905997        if (!_initialized) return null;
     
    9351027        return rv;
    9361028    }
     1029
     1030    /**
     1031     *  If the validate fails, call this
     1032     *  to determine if it was because of unsupported crypto.
     1033     *
     1034     *  If so, this will banlist-forever the router hash or permanently negative cache the dest hash,
     1035     *  and then throw the exception. Otherwise it does nothing.
     1036     *
     1037     *  @throws UnsupportedCryptoException if that's why it failed.
     1038     *  @since 0.9.16
     1039     */
     1040    private void processStoreFailure(Hash h, DatabaseEntry entry) throws UnsupportedCryptoException {
     1041        if (entry.getHash().equals(h)) {
     1042            if (entry.getType() == DatabaseEntry.KEY_TYPE_LEASESET) {
     1043                LeaseSet ls = (LeaseSet) entry;
     1044                Destination d = ls.getDestination();
     1045                Certificate c = d.getCertificate();
     1046                if (c.getCertificateType() == Certificate.CERTIFICATE_TYPE_KEY) {
     1047                    try {
     1048                        KeyCertificate kc = c.toKeyCertificate();
     1049                        SigType type = kc.getSigType();
     1050                        if (type == null || !type.isAvailable()) {
     1051                            failPermanently(d);
     1052                            String stype = (type != null) ? type.toString() : Integer.toString(kc.getSigTypeCode());
     1053                            if (_log.shouldLog(Log.WARN))
     1054                                _log.warn("Unsupported sig type " + stype + " for destination " + h);
     1055                            throw new UnsupportedCryptoException("Sig type " + stype);
     1056                        }
     1057                    } catch (DataFormatException dfe) {}
     1058                }
     1059            } else if (entry.getType() == DatabaseEntry.KEY_TYPE_ROUTERINFO) {
     1060                RouterInfo ri = (RouterInfo) entry;
     1061                RouterIdentity id = ri.getIdentity();
     1062                Certificate c = id.getCertificate();
     1063                if (c.getCertificateType() == Certificate.CERTIFICATE_TYPE_KEY) {
     1064                    try {
     1065                        KeyCertificate kc = c.toKeyCertificate();
     1066                        SigType type = kc.getSigType();
     1067                        if (type == null || !type.isAvailable()) {
     1068                            String stype = (type != null) ? type.toString() : Integer.toString(kc.getSigTypeCode());
     1069                            _context.banlist().banlistRouterForever(h, "Unsupported signature type " + stype);
     1070                            if (_log.shouldLog(Log.WARN))
     1071                                _log.warn("Unsupported sig type " + stype + " for router " + h);
     1072                            throw new UnsupportedCryptoException("Sig type " + stype);
     1073                        }
     1074                    } catch (DataFormatException dfe) {}
     1075                }
     1076            }
     1077        }
     1078        if (_log.shouldLog(Log.WARN))
     1079            _log.warn("Verify fail, cause unknown: " + entry);
     1080    }
     1081
    9371082   
    9381083    /**
     
    10061151     *
    10071152     * Unused - called only by FNDF.searchFull() from FloodSearchJob which is overridden - don't use this.
     1153     *
     1154     * @throws UnsupportedOperationException always
    10081155     */
    10091156    SearchJob search(Hash key, Job onFindJob, Job onFailedLookupJob, long timeoutMs, boolean isLease) {
     1157        throw new UnsupportedOperationException();
     1158/****
    10101159        if (!_initialized) return null;
    10111160        boolean isNew = true;
     
    10321181        }
    10331182        return searchJob;
     1183****/
    10341184    }
    10351185   
     
    11041254
    11051255    /**
     1256     *  Increment in the negative lookup cache
     1257     *
     1258     *  @param key for Destinations or RouterIdentities
     1259     *  @since 0.9.4 moved from FNDF to KNDF in 0.9.16
     1260     */
     1261    void lookupFailed(Hash key) {
     1262        _negativeCache.lookupFailed(key);
     1263    }
     1264
     1265    /**
     1266     *  Is the key in the negative lookup cache?
     1267     *&
     1268     *  @param key for Destinations or RouterIdentities
     1269     *  @since 0.9.4 moved from FNDF to KNDF in 0.9.16
     1270     */
     1271    boolean isNegativeCached(Hash key) {
     1272        boolean rv = _negativeCache.isCached(key);
     1273        if (rv)
     1274            _context.statManager().addRateData("netDb.negativeCache", 1);
     1275        return rv;
     1276    }
     1277
     1278    /**
     1279     *  Negative cache until restart
     1280     *  @since 0.9.16
     1281     */
     1282    void failPermanently(Destination dest) {
     1283        _negativeCache.failPermanently(dest);
     1284    }
     1285
     1286    /**
     1287     *  Is it permanently negative cached?
     1288     *
     1289     *  @param key only for Destinations; for RouterIdentities, see Banlist
     1290     *  @since 0.9.16
     1291     */
     1292    public boolean isNegativeCachedForever(Hash key) {
     1293        return _negativeCache.getBadDest(key) != null;
     1294    }
     1295
     1296    /**
    11061297     * Debug info, HTML formatted
    11071298     * @since 0.9.10
  • router/java/src/net/i2p/router/networkdb/kademlia/MessageWrapper.java

    reab4397 r156d868  
    99import net.i2p.data.Hash;
    1010import net.i2p.data.PublicKey;
    11 import net.i2p.data.RouterInfo;
     11import net.i2p.data.router.RouterInfo;
    1212import net.i2p.data.SessionKey;
    1313import net.i2p.data.SessionTag;
  • router/java/src/net/i2p/router/networkdb/kademlia/NegativeLookupCache.java

    reab4397 r156d868  
    11package net.i2p.router.networkdb.kademlia;
    22
     3import java.util.Map;
     4import net.i2p.data.Destination;
    35import net.i2p.data.Hash;
     6import net.i2p.util.LHMCache;
    47import net.i2p.util.ObjectCounter;
    58import net.i2p.util.SimpleScheduler;
     
    1316class NegativeLookupCache {
    1417    private final ObjectCounter<Hash> counter;
     18    private final Map<Hash, Destination> badDests;
     19
    1520    private static final int MAX_FAILS = 3;
     21    private static final int MAX_BAD_DESTS = 128;
    1622    private static final long CLEAN_TIME = 2*60*1000;
    1723
    1824    public NegativeLookupCache() {
    1925        this.counter = new ObjectCounter<Hash>();
     26        this.badDests = new LHMCache<Hash, Destination>(MAX_BAD_DESTS);
    2027        SimpleScheduler.getInstance().addPeriodicEvent(new Cleaner(), CLEAN_TIME);
    2128    }
     
    2633
    2734    public boolean isCached(Hash h) {
    28         return this.counter.count(h) >= MAX_FAILS;
     35        if (counter.count(h) >= MAX_FAILS)
     36            return true;
     37        synchronized(badDests) {
     38            return badDests.get(h) != null;
     39        }
     40    }
     41
     42    /**
     43     *  Negative cache the hash until restart,
     44     *  but cache the destination.
     45     *
     46     *  @since 0.9.16
     47     */
     48    public void failPermanently(Destination dest) {
     49        Hash h = dest.calculateHash();
     50        synchronized(badDests) {
     51            badDests.put(h, dest);
     52        }
     53    }
     54
     55    /**
     56     *  Get an unsupported but cached Destination
     57     *
     58     *  @return dest or null if not cached
     59     *  @since 0.9.16
     60     */
     61    public Destination getBadDest(Hash h) {
     62        synchronized(badDests) {
     63            return badDests.get(h);
     64        }
     65    }
     66
     67    /**
     68     *  @since 0.9.16
     69     */
     70    public void clear() {
     71        counter.clear();
     72        synchronized(badDests) {
     73            badDests.clear();
     74        }
    2975    }
    3076
  • router/java/src/net/i2p/router/networkdb/kademlia/PeerSelector.java

    reab4397 r156d868  
    1717
    1818import net.i2p.data.Hash;
    19 import net.i2p.data.RouterInfo;
     19import net.i2p.data.router.RouterInfo;
    2020import net.i2p.kademlia.KBucketSet;
    2121import net.i2p.kademlia.SelectionCollector;
  • router/java/src/net/i2p/router/networkdb/kademlia/PersistentDataStore.java

    reab4397 r156d868  
    3030import net.i2p.data.DataFormatException;
    3131import net.i2p.data.Hash;
    32 import net.i2p.data.RouterInfo;
     32import net.i2p.data.router.RouterInfo;
    3333import net.i2p.router.JobImpl;
    3434import net.i2p.router.Router;
  • router/java/src/net/i2p/router/networkdb/kademlia/RefreshRoutersJob.java

    reab4397 r156d868  
    66
    77import net.i2p.data.Hash;
    8 import net.i2p.data.RouterInfo;
     8import net.i2p.data.router.RouterInfo;
    99import net.i2p.router.JobImpl;
    1010import net.i2p.router.RouterContext;
  • router/java/src/net/i2p/router/networkdb/kademlia/SearchJob.java

    reab4397 r156d868  
    1818import net.i2p.data.Hash;
    1919import net.i2p.data.LeaseSet;
    20 import net.i2p.data.RouterInfo;
    2120import net.i2p.data.TunnelId;
    2221import net.i2p.data.i2np.DatabaseLookupMessage;
    2322import net.i2p.data.i2np.DatabaseSearchReplyMessage;
    2423import net.i2p.data.i2np.DatabaseStoreMessage;
     24import net.i2p.data.i2np.I2NPMessage;
     25import net.i2p.data.router.RouterInfo;
    2526import net.i2p.router.Job;
    2627import net.i2p.router.JobImpl;
     
    202203            return;
    203204        }
     205        if (_state.isAborted()) {
     206            if (_log.shouldLog(Log.INFO))
     207                _log.info(getJobId() + ": Search aborted");
     208            _state.complete();
     209            fail();
     210            return;
     211        }
    204212        if (_log.shouldLog(Log.INFO))
    205213            _log.info(getJobId() + ": Searching: " + _state);
     
    207215            if (_log.shouldLog(Log.INFO))
    208216                _log.info(getJobId() + ": Key found locally");
    209             _state.complete(true);
     217            _state.complete();
    210218            succeed();
    211219        } else if (isExpired()) {
    212220            if (_log.shouldLog(Log.INFO))
    213221                _log.info(getJobId() + ": Key search expired");
    214             _state.complete(true);
     222            _state.complete();
    215223            fail();
    216224        } else if (_state.getAttempted().size() > MAX_PEERS_QUERIED) {
    217225            if (_log.shouldLog(Log.INFO))
    218226                _log.info(getJobId() + ": Too many peers quried");
    219             _state.complete(true);
     227            _state.complete();
    220228            fail();
    221229        } else {
     
    425433        long expiration = getContext().clock().now() + timeout;
    426434
    427         DatabaseLookupMessage msg = buildMessage(inTunnelId, inTunnel.getPeer(0), expiration); 
     435        I2NPMessage msg = buildMessage(inTunnelId, inTunnel.getPeer(0), expiration, router);   
    428436       
    429437        TunnelInfo outTunnel = getContext().tunnelManager().selectOutboundExploratoryTunnel(to);
     
    438446        if (_log.shouldLog(Log.DEBUG))
    439447            _log.debug(getJobId() + ": Sending search to " + to
    440                        + " for " + msg.getSearchKey().toBase64() + " w/ replies through ["
    441                        + msg.getFrom().toBase64() + "] via tunnel ["
    442                        + msg.getReplyTunnel() + "]");
     448                       + " for " + getState().getTarget() + " w/ replies through "
     449                       + inTunnel.getPeer(0) + " via tunnel "
     450                       + inTunnelId);
    443451
    444452        SearchMessageSelector sel = new SearchMessageSelector(getContext(), router, _expiration, _state);
     
    483491     * @param replyGateway gateway for the reply tunnel
    484492     * @param expiration when the search should stop
    485      */
    486     protected DatabaseLookupMessage buildMessage(TunnelId replyTunnelId, Hash replyGateway, long expiration) {
     493     * @param peer unused here; see ExploreJob extension
     494     *
     495     * @return a DatabaseLookupMessage
     496     */
     497    protected I2NPMessage buildMessage(TunnelId replyTunnelId, Hash replyGateway, long expiration, RouterInfo peer) {
    487498        DatabaseLookupMessage msg = new DatabaseLookupMessage(getContext(), true);
    488499        msg.setSearchKey(_state.getTarget());
  • router/java/src/net/i2p/router/networkdb/kademlia/SearchMessageSelector.java

    reab4397 r156d868  
    44
    55import net.i2p.data.Hash;
    6 import net.i2p.data.RouterInfo;
     6import net.i2p.data.router.RouterInfo;
    77import net.i2p.data.i2np.DatabaseSearchReplyMessage;
    88import net.i2p.data.i2np.DatabaseStoreMessage;
  • router/java/src/net/i2p/router/networkdb/kademlia/SearchReplyJob.java

    reab4397 r156d868  
    33import net.i2p.data.Hash;
    44import net.i2p.data.i2np.DatabaseSearchReplyMessage;
    5 import net.i2p.data.RouterInfo;
     5import net.i2p.data.router.RouterInfo;
    66import net.i2p.router.JobImpl;
    77import net.i2p.router.RouterContext;
  • router/java/src/net/i2p/router/networkdb/kademlia/SearchState.java

    reab4397 r156d868  
    2020class SearchState {
    2121    private final RouterContext _context;
    22     private final HashSet<Hash> _pendingPeers;
     22    private final Set<Hash> _pendingPeers;
    2323    private final Map<Hash, Long> _pendingPeerTimes;
    24     private final HashSet<Hash> _attemptedPeers;
    25     private final HashSet<Hash> _failedPeers;
    26     private final HashSet<Hash> _successfulPeers;
    27     private final HashSet<Hash> _repliedPeers;
     24    private final Set<Hash> _attemptedPeers;
     25    private final Set<Hash> _failedPeers;
     26    private final Set<Hash> _successfulPeers;
     27    private final Set<Hash> _repliedPeers;
    2828    private final Hash _searchKey;
    2929    private volatile long _completed;
    3030    private volatile long _started;
     31    private volatile boolean _aborted;
    3132   
    3233    public SearchState(RouterContext context, Hash key) {
     
    8889        }
    8990    }
     91
    9092    public boolean completed() { return _completed != -1; }
    91     public void complete(boolean completed) {
    92         if (completed)
    93             _completed = _context.clock().now();
     93
     94    public void complete() {
     95        _completed = _context.clock().now();
     96    }
     97
     98    /** @since 0.9.16 */
     99    public boolean isAborted() { return _aborted; }
     100
     101    /** @since 0.9.16 */
     102    public void abort() {
     103        _aborted = true;
    94104    }
    95105   
     
    178188        else
    179189            buf.append(" completed on ").append(new Date(_completed));
     190        if (_aborted)
     191            buf.append("  (Aborted)");
    180192        buf.append("\n\tAttempted: ");
    181193        synchronized (_attemptedPeers) {
  • router/java/src/net/i2p/router/networkdb/kademlia/SearchUpdateReplyFoundJob.java

    reab4397 r156d868  
    66import net.i2p.data.Hash;
    77import net.i2p.data.LeaseSet;
    8 import net.i2p.data.RouterInfo;
     8import net.i2p.data.router.RouterInfo;
    99import net.i2p.data.i2np.DatabaseSearchReplyMessage;
    1010import net.i2p.data.i2np.DatabaseStoreMessage;
     
    1919 * Called after a match to a db search is found
    2020 *
     21 * Used only by SearchJob which is only used by ExploreJob
    2122 */
    2223class SearchUpdateReplyFoundJob extends JobImpl implements ReplyJob {
    23     private Log _log;
     24    private final Log _log;
    2425    private I2NPMessage _message;
    25     private Hash _peer;
    26     private SearchState _state;
    27     private KademliaNetworkDatabaseFacade _facade;
    28     private SearchJob _job;
    29     private TunnelInfo _outTunnel;
    30     private TunnelInfo _replyTunnel;
    31     private boolean _isFloodfillPeer;
    32     private long _sentOn;
     26    private final Hash _peer;
     27    private final SearchState _state;
     28    private final KademliaNetworkDatabaseFacade _facade;
     29    private final SearchJob _job;
     30    private final TunnelInfo _outTunnel;
     31    private final TunnelInfo _replyTunnel;
     32    private final boolean _isFloodfillPeer;
     33    private final long _sentOn;
    3334   
    3435    public SearchUpdateReplyFoundJob(RouterContext context, RouterInfo peer,
     
    3738        this(context, peer, state, facade, job, null, null);
    3839    }
     40
    3941    public SearchUpdateReplyFoundJob(RouterContext context, RouterInfo peer,
    4042                                     SearchState state, KademliaNetworkDatabaseFacade facade,
     
    5355   
    5456    public String getName() { return "Update Reply Found for Kademlia Search"; }
     57
    5558    public void runJob() {
    5659        if (_isFloodfillPeer)
     
    6063        if (_log.shouldLog(Log.INFO))
    6164            _log.info(getJobId() + ": Reply from " + _peer.toBase64()
    62                       + " with message " + message.getClass().getName());
     65                      + " with message " + message.getClass().getSimpleName());
    6366       
    6467        long howLong = System.currentTimeMillis() - _sentOn;
     
    7982        if (message instanceof DatabaseStoreMessage) {
    8083            long timeToReply = _state.dataFound(_peer);
    81            
    8284            DatabaseStoreMessage msg = (DatabaseStoreMessage)message;
    8385            DatabaseEntry entry = msg.getEntry();
    84             if (entry.getType() == DatabaseEntry.KEY_TYPE_LEASESET) {
    85                 try {
    86                     _facade.store(msg.getKey(), (LeaseSet) entry);
    87                     getContext().profileManager().dbLookupSuccessful(_peer, timeToReply);
    88                 } catch (IllegalArgumentException iae) {
    89                     if (_log.shouldLog(Log.ERROR))
    90                         _log.warn("Peer " + _peer + " sent us an invalid leaseSet: " + iae.getMessage());
    91                     getContext().profileManager().dbLookupReply(_peer, 0, 0, 1, 0, timeToReply);
    92                 }
    93             } else if (entry.getType() == DatabaseEntry.KEY_TYPE_ROUTERINFO) {
    94                 if (_log.shouldLog(Log.INFO))
    95                     _log.info(getJobId() + ": dbStore received on search containing router "
    96                               + msg.getKey() + " with publishDate of "
    97                               + new Date(entry.getDate()));
    98                 try {
    99                     _facade.store(msg.getKey(), (RouterInfo) entry);
    100                     getContext().profileManager().dbLookupSuccessful(_peer, timeToReply);
    101                 } catch (IllegalArgumentException iae) {
    102                     if (_log.shouldLog(Log.ERROR))
    103                         _log.warn("Peer " + _peer + " sent us an invalid routerInfo: " + iae.getMessage());
    104                     getContext().profileManager().dbLookupReply(_peer, 0, 0, 1, 0, timeToReply);
    105                 }
    106             } else {
    107                 if (_log.shouldLog(Log.ERROR))
    108                     _log.error(getJobId() + ": Unknown db store type?!@ " + entry.getType());
     86            try {
     87                _facade.store(msg.getKey(), entry);
     88                getContext().profileManager().dbLookupSuccessful(_peer, timeToReply);
     89            } catch (UnsupportedCryptoException iae) {
     90                // don't blame the peer
     91                getContext().profileManager().dbLookupSuccessful(_peer, timeToReply);
     92                _state.abort();
     93                // searchNext() will call fail()
     94            } catch (IllegalArgumentException iae) {
     95                if (_log.shouldLog(Log.WARN))
     96                    _log.warn("Peer " + _peer + " sent us invalid data: ", iae);
     97                // blame the peer
     98                getContext().profileManager().dbLookupReply(_peer, 0, 0, 1, 0, timeToReply);
    10999            }
    110100        } else if (message instanceof DatabaseSearchReplyMessage) {
  • router/java/src/net/i2p/router/networkdb/kademlia/SingleLookupJob.java

    reab4397 r156d868  
    22
    33import net.i2p.data.Hash;
    4 import net.i2p.data.RouterInfo;
     4import net.i2p.data.router.RouterInfo;
    55import net.i2p.data.i2np.DatabaseSearchReplyMessage;
    66import net.i2p.router.JobImpl;
  • router/java/src/net/i2p/router/networkdb/kademlia/StartExplorersJob.java

    reab4397 r156d868  
    1313
    1414import net.i2p.data.Hash;
    15 import net.i2p.data.RouterInfo;
     15import net.i2p.data.router.RouterInfo;
    1616import net.i2p.router.JobImpl;
    1717import net.i2p.router.Router;
  • router/java/src/net/i2p/router/networkdb/kademlia/StoreJob.java

    reab4397 r156d868  
    1919import net.i2p.data.Hash;
    2020import net.i2p.data.LeaseSet;
    21 import net.i2p.data.RouterInfo;
     21import net.i2p.data.router.RouterInfo;
    2222import net.i2p.data.TunnelId;
    2323import net.i2p.data.i2np.DatabaseStoreMessage;
  • router/java/src/net/i2p/router/networkdb/kademlia/StoreMessageSelector.java

    reab4397 r156d868  
    22
    33import net.i2p.data.Hash;
    4 import net.i2p.data.RouterInfo;
     4import net.i2p.data.router.RouterInfo;
    55import net.i2p.data.i2np.DeliveryStatusMessage;
    66import net.i2p.data.i2np.I2NPMessage;
  • router/java/src/net/i2p/router/networkdb/kademlia/TransientDataStore.java

    reab4397 r156d868  
    1919import net.i2p.data.Hash;
    2020import net.i2p.data.LeaseSet;
    21 import net.i2p.data.RouterInfo;
     21import net.i2p.data.router.RouterInfo;
    2222import net.i2p.router.RouterContext;
    2323import net.i2p.util.Log;
  • router/java/src/net/i2p/router/peermanager/PeerManager.java

    reab4397 r156d868  
    2020
    2121import net.i2p.data.Hash;
    22 import net.i2p.data.RouterInfo;
     22import net.i2p.data.router.RouterInfo;
    2323import net.i2p.router.PeerSelectionCriteria;
    2424import net.i2p.router.Router;
  • router/java/src/net/i2p/router/peermanager/PeerTestJob.java

    reab4397 r156d868  
    66
    77import net.i2p.data.Hash;
    8 import net.i2p.data.RouterInfo;
     8import net.i2p.data.router.RouterInfo;
    99import net.i2p.data.TunnelId;
    1010import net.i2p.data.i2np.DatabaseStoreMessage;
  • router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java

    reab4397 r156d868  
    2020import net.i2p.crypto.SHA256Generator;
    2121import net.i2p.data.Hash;
    22 import net.i2p.data.RouterAddress;
    23 import net.i2p.data.RouterInfo;
     22import net.i2p.data.router.RouterAddress;
     23import net.i2p.data.router.RouterInfo;
    2424import net.i2p.router.NetworkDatabaseFacade;
    2525import net.i2p.router.RouterContext;
  • router/java/src/net/i2p/router/startup/BootCommSystemJob.java

    reab4397 r156d868  
    1717
    1818/** This actually boots almost everything */
    19 public class BootCommSystemJob extends JobImpl {
     19class BootCommSystemJob extends JobImpl {
    2020    private Log _log;
    2121   
  • router/java/src/net/i2p/router/startup/BootNetworkDbJob.java

    reab4397 r156d868  
    1313
    1414/** start up the network database */
    15 public class BootNetworkDbJob extends JobImpl {
     15class BootNetworkDbJob extends JobImpl {
    1616   
    1717    public BootNetworkDbJob(RouterContext ctx) {
  • router/java/src/net/i2p/router/startup/BootPeerManagerJob.java

    reab4397 r156d868  
    1313
    1414/** start up the peer manager */
    15 public class BootPeerManagerJob extends JobImpl {
     15class BootPeerManagerJob extends JobImpl {
    1616   
    1717    public BootPeerManagerJob(RouterContext ctx) {
  • router/java/src/net/i2p/router/startup/BuildTrustedLinksJob.java

    reab4397 r156d868  
    1616 *  For future restricted routes. Does nothing now.
    1717 */
    18 public class BuildTrustedLinksJob extends JobImpl {
     18class BuildTrustedLinksJob extends JobImpl {
    1919    private final Job _next;
    2020   
  • router/java/src/net/i2p/router/startup/CreateRouterInfoJob.java

    reab4397 r156d868  
    1313import java.io.IOException;
    1414import java.io.OutputStream;
     15import java.security.GeneralSecurityException;
    1516import java.util.Properties;
    1617
     18import net.i2p.crypto.SigType;
    1719import net.i2p.data.Certificate;
    1820import net.i2p.data.DataFormatException;
     21import net.i2p.data.DataHelper;
     22import net.i2p.data.KeyCertificate;
    1923import net.i2p.data.PrivateKey;
     24import net.i2p.data.PrivateKeyFile;
    2025import net.i2p.data.PublicKey;
    21 import net.i2p.data.RouterIdentity;
    22 import net.i2p.data.RouterInfo;
     26import net.i2p.data.router.RouterIdentity;
     27import net.i2p.data.router.RouterInfo;
    2328import net.i2p.data.SigningPrivateKey;
    2429import net.i2p.data.SigningPublicKey;
     30import net.i2p.data.SimpleDataStructure;
    2531import net.i2p.router.Job;
    2632import net.i2p.router.JobImpl;
     
    4147    private final Job _next;
    4248   
    43     public CreateRouterInfoJob(RouterContext ctx, Job next) {
     49    public static final String INFO_FILENAME = "router.info";
     50    public static final String KEYS_FILENAME = "router.keys";
     51    public static final String KEYS2_FILENAME = "router.keys.dat";
     52    private static final String PROP_ROUTER_SIGTYPE = "router.sigType";
     53    /** TODO when changing, check isAvailable() and fallback to DSA_SHA1 */
     54    private static final SigType DEFAULT_SIGTYPE = SigType.DSA_SHA1;
     55
     56    CreateRouterInfoJob(RouterContext ctx, Job next) {
    4457        super(ctx);
    4558        _next = next;
     
    6073    /**
    6174     *  Writes 6 files: router.info (standard RI format),
    62      *  router,keys, and 4 individual key files under keyBackup/
    63      *
    64      *  router.keys file format: Note that this is NOT the
     75     *  router.keys2, and 4 individual key files under keyBackup/
     76     *
     77     *  router.keys2 file format: This is the
     78     *  same "eepPriv.dat" format used by the client code,
     79     *  as documented in PrivateKeyFile.
     80     *
     81     *  Old router.keys file format: Note that this is NOT the
    6582     *  same "eepPriv.dat" format used by the client code.
    6683     *<pre>
     
    7592     */
    7693    RouterInfo createRouterInfo() {
     94        SigType type = getSigTypeConfig(getContext());
    7795        RouterInfo info = new RouterInfo();
    7896        OutputStream fos1 = null;
    79         OutputStream fos2 = null;
    8097        try {
    8198            info.setAddresses(getContext().commSystem().createAddresses());
     
    87104            //info.setPeers(new HashSet());
    88105            info.setPublished(getCurrentPublishDate(getContext()));
     106            Object keypair[] = getContext().keyGenerator().generatePKIKeypair();
     107            PublicKey pubkey = (PublicKey)keypair[0];
     108            PrivateKey privkey = (PrivateKey)keypair[1];
     109            SimpleDataStructure signingKeypair[] = getContext().keyGenerator().generateSigningKeys(type);
     110            SigningPublicKey signingPubKey = (SigningPublicKey)signingKeypair[0];
     111            SigningPrivateKey signingPrivKey = (SigningPrivateKey)signingKeypair[1];
    89112            RouterIdentity ident = new RouterIdentity();
    90             Certificate cert = getContext().router().createCertificate();
     113            Certificate cert = createCertificate(getContext(), signingPubKey);
    91114            ident.setCertificate(cert);
    92             PublicKey pubkey = null;
    93             PrivateKey privkey = null;
    94             SigningPublicKey signingPubKey = null;
    95             SigningPrivateKey signingPrivKey = null;
    96             Object keypair[] = getContext().keyGenerator().generatePKIKeypair();
    97             pubkey = (PublicKey)keypair[0];
    98             privkey = (PrivateKey)keypair[1];
    99             Object signingKeypair[] = getContext().keyGenerator().generateSigningKeypair();
    100             signingPubKey = (SigningPublicKey)signingKeypair[0];
    101             signingPrivKey = (SigningPrivateKey)signingKeypair[1];
    102115            ident.setPublicKey(pubkey);
    103116            ident.setSigningPublicKey(signingPubKey);
     117            byte[] padding;
     118            int padLen = SigningPublicKey.KEYSIZE_BYTES - signingPubKey.length();
     119            if (padLen > 0) {
     120                padding = new byte[padLen];
     121                getContext().random().nextBytes(padding);
     122                ident.setPadding(padding);
     123            } else {
     124                padding = null;
     125            }
    104126            info.setIdentity(ident);
    105127           
     
    109131                throw new DataFormatException("RouterInfo we just built is invalid: " + info);
    110132           
    111             String infoFilename = getContext().getProperty(Router.PROP_INFO_FILENAME, Router.PROP_INFO_FILENAME_DEFAULT);
    112             File ifile = new File(getContext().getRouterDir(), infoFilename);
     133            // remove router.keys
     134            (new File(getContext().getRouterDir(), KEYS_FILENAME)).delete();
     135
     136            // write router.info
     137            File ifile = new File(getContext().getRouterDir(), INFO_FILENAME);
    113138            fos1 = new BufferedOutputStream(new SecureFileOutputStream(ifile));
    114139            info.writeBytes(fos1);
    115140           
    116             String keyFilename = getContext().getProperty(Router.PROP_KEYS_FILENAME, Router.PROP_KEYS_FILENAME_DEFAULT);
    117             File kfile = new File(getContext().getRouterDir(), keyFilename);
    118             fos2 = new BufferedOutputStream(new SecureFileOutputStream(kfile));
    119             privkey.writeBytes(fos2);
    120             signingPrivKey.writeBytes(fos2);
    121             pubkey.writeBytes(fos2);
    122             signingPubKey.writeBytes(fos2);
     141            // write router.keys.dat
     142            File kfile = new File(getContext().getRouterDir(), KEYS2_FILENAME);
     143            PrivateKeyFile pkf = new PrivateKeyFile(kfile, pubkey, signingPubKey, cert,
     144                                                    privkey, signingPrivKey, padding);
     145            pkf.write();
    123146           
    124147            getContext().keyManager().setKeys(pubkey, privkey, signingPubKey, signingPrivKey);
    125148           
    126             _log.info("Router info created and stored at " + ifile.getAbsolutePath() + " with private keys stored at " + kfile.getAbsolutePath() + " [" + info + "]");
     149            if (_log.shouldLog(Log.INFO))
     150                _log.info("Router info created and stored at " + ifile.getAbsolutePath() + " with private keys stored at " + kfile.getAbsolutePath() + " [" + info + "]");
    127151            getContext().router().eventLog().addEvent(EventLog.REKEYED, ident.calculateHash().toBase64());
     152        } catch (GeneralSecurityException gse) {
     153            _log.log(Log.CRIT, "Error building the new router information", gse);
    128154        } catch (DataFormatException dfe) {
    129155            _log.log(Log.CRIT, "Error building the new router information", dfe);
     
    132158        } finally {
    133159            if (fos1 != null) try { fos1.close(); } catch (IOException ioe) {}
    134             if (fos2 != null) try { fos2.close(); } catch (IOException ioe) {}
    135160        }
    136161        return info;
    137162    }
    138163   
     164    /**
     165     *  The configured SigType to expect on read-in
     166     *  @since 0.9.16
     167     */
     168    public static SigType getSigTypeConfig(RouterContext ctx) {
     169        SigType cstype = CreateRouterInfoJob.DEFAULT_SIGTYPE;
     170        String sstype = ctx.getProperty(PROP_ROUTER_SIGTYPE);
     171        if (sstype != null) {
     172            SigType ntype = SigType.parseSigType(sstype);
     173            if (ntype != null)
     174                cstype = ntype;
     175        }
     176        // fallback?
     177        if (cstype != SigType.DSA_SHA1 && !cstype.isAvailable())
     178            cstype = SigType.DSA_SHA1;
     179        return cstype;
     180    }
    139181   
    140182    /**
     
    147189        return context.clock().now();
    148190    }
     191
     192    /**
     193     *  Only called at startup via LoadRouterInfoJob and RebuildRouterInfoJob.
     194     *  Not called by periodic RepublishLocalRouterInfoJob.
     195     *  We don't want to change the cert on the fly as it changes the router hash.
     196     *  RouterInfo.isHidden() checks the capability, but RouterIdentity.isHidden() checks the cert.
     197     *  There's no reason to ever add a hidden cert?
     198     *
     199     *  @return the certificate for a new RouterInfo - probably a null cert.
     200     *  @since 0.9.16 moved from Router
     201     */
     202    static Certificate createCertificate(RouterContext ctx, SigningPublicKey spk) {
     203        if (spk.getType() != SigType.DSA_SHA1)
     204            return new KeyCertificate(spk);
     205        if (ctx.getBooleanProperty(Router.PROP_HIDDEN))
     206            return new Certificate(Certificate.CERTIFICATE_TYPE_HIDDEN, null);
     207        return Certificate.NULL_CERT;
     208    }
    149209}
  • router/java/src/net/i2p/router/startup/LoadRouterInfoJob.java

    reab4397 r156d868  
    1616import java.util.concurrent.atomic.AtomicBoolean;
    1717
     18import net.i2p.crypto.KeyGenerator;
     19import net.i2p.crypto.SigType;
     20import net.i2p.data.Certificate;
    1821import net.i2p.data.DataFormatException;
     22import net.i2p.data.DataHelper;
    1923import net.i2p.data.PrivateKey;
    2024import net.i2p.data.PublicKey;
    21 import net.i2p.data.RouterInfo;
    2225import net.i2p.data.SigningPrivateKey;
    2326import net.i2p.data.SigningPublicKey;
     27import net.i2p.data.router.RouterIdentity;
     28import net.i2p.data.router.RouterInfo;
     29import net.i2p.data.router.RouterPrivateKeyFile;
    2430import net.i2p.router.JobImpl;
    2531import net.i2p.router.Router;
     
    2733import net.i2p.util.Log;
    2834
    29 public class LoadRouterInfoJob extends JobImpl {
     35/**
     36 *  Run once or twice at startup by StartupJob,
     37 *  and then runs BootCommSystemJob
     38 */
     39class LoadRouterInfoJob extends JobImpl {
    3040    private final Log _log;
    3141    private RouterInfo _us;
     
    4656            RebuildRouterInfoJob r = new RebuildRouterInfoJob(getContext());
    4757            r.rebuildRouterInfo(false);
     58            // run a second time
    4859            getContext().jobQueue().addJob(this);
    4960            return;
     
    5566    }
    5667   
     68    /**
     69     *  Loads router.info and router.keys2 or router.keys.
     70     *
     71     *  See CreateRouterInfoJob for file formats
     72     */
    5773    private void loadRouterInfo() {
    58         String routerInfoFile = getContext().getProperty(Router.PROP_INFO_FILENAME, Router.PROP_INFO_FILENAME_DEFAULT);
    5974        RouterInfo info = null;
    60         String keyFilename = getContext().getProperty(Router.PROP_KEYS_FILENAME, Router.PROP_KEYS_FILENAME_DEFAULT);
    61        
    62         File rif = new File(getContext().getRouterDir(), routerInfoFile);
     75        File rif = new File(getContext().getRouterDir(), CreateRouterInfoJob.INFO_FILENAME);
    6376        boolean infoExists = rif.exists();
    64         File rkf = new File(getContext().getRouterDir(), keyFilename);
     77        File rkf = new File(getContext().getRouterDir(), CreateRouterInfoJob.KEYS_FILENAME);
    6578        boolean keysExist = rkf.exists();
     79        File rkf2 = new File(getContext().getRouterDir(), CreateRouterInfoJob.KEYS2_FILENAME);
     80        boolean keys2Exist = rkf2.exists();
    6681       
    6782        InputStream fis1 = null;
    68         InputStream fis2 = null;
    6983        try {
    7084            // if we have a routerinfo but no keys, things go bad in a hurry:
     
    7488            // at net.i2p.router.transport.udp.PacketBuilder.buildSessionConfirmedPacket(PacketBuilder.java:574)
    7589            // so pretend the RI isn't there if there is no keyfile
    76             if (infoExists && keysExist) {
     90            if (infoExists && (keys2Exist || keysExist)) {
    7791                fis1 = new BufferedInputStream(new FileInputStream(rif));
    7892                info = new RouterInfo();
     
    86100            }
    87101           
    88             if (keysExist) {
    89                 fis2 = new BufferedInputStream(new FileInputStream(rkf));
    90                 PrivateKey privkey = new PrivateKey();
    91                 privkey.readBytes(fis2);
    92                 if (shouldRebuild(privkey)) {
     102            if (keys2Exist || keysExist) {
     103                KeyData kd = readKeyData(rkf, rkf2);
     104                PublicKey pubkey = kd.routerIdentity.getPublicKey();
     105                SigningPublicKey signingPubKey = kd.routerIdentity.getSigningPublicKey();
     106                PrivateKey privkey = kd.privateKey;
     107                SigningPrivateKey signingPrivKey = kd.signingPrivateKey;
     108                SigType stype = signingPubKey.getType();
     109
     110                // check if the sigtype config changed
     111                SigType cstype = CreateRouterInfoJob.getSigTypeConfig(getContext());
     112                boolean sigTypeChanged = stype != cstype;
     113
     114                if (sigTypeChanged || shouldRebuild(privkey)) {
     115                    if (sigTypeChanged)
     116                        _log.logAlways(Log.WARN, "Rebuilding RouterInfo with new signature type " + cstype);
    93117                    _us = null;
    94118                    // windows... close before deleting
     
    97121                        fis1 = null;
    98122                    }
    99                     try { fis2.close(); } catch (IOException ioe) {}
    100                     fis2 = null;
    101123                    rif.delete();
    102124                    rkf.delete();
     125                    rkf2.delete();
    103126                    return;
    104127                }
    105                 SigningPrivateKey signingPrivKey = new SigningPrivateKey();
    106                 signingPrivKey.readBytes(fis2);
    107                 PublicKey pubkey = new PublicKey();
    108                 pubkey.readBytes(fis2);
    109                 SigningPublicKey signingPubKey = new SigningPublicKey();
    110                 signingPubKey.readBytes(fis2);
    111128               
    112129                getContext().keyManager().setKeys(pubkey, privkey, signingPubKey, signingPrivKey);
     
    120137                fis1 = null;
    121138            }
    122             if (fis2 != null) {
    123                 try { fis2.close(); } catch (IOException ioe2) {}
    124                 fis2 = null;
    125             }
    126139            rif.delete();
    127140            rkf.delete();
     141            rkf2.delete();
    128142        } catch (DataFormatException dfe) {
    129143            _log.log(Log.CRIT, "Corrupt router info or keys at " + rif.getAbsolutePath() + " / " + rkf.getAbsolutePath(), dfe);
     
    134148                fis1 = null;
    135149            }
    136             if (fis2 != null) {
    137                 try { fis2.close(); } catch (IOException ioe) {}
    138                 fis2 = null;
    139             }
    140150            rif.delete();
    141151            rkf.delete();
     152            rkf2.delete();
    142153        } finally {
    143154            if (fis1 != null) try { fis1.close(); } catch (IOException ioe) {}
    144             if (fis2 != null) try { fis2.close(); } catch (IOException ioe) {}
    145155        }
    146156    }
     
    175185        return uselong != haslong;
    176186    }
     187
     188    /** @since 0.9.16 */
     189    public static class KeyData {
     190        public final RouterIdentity routerIdentity;
     191        public final PrivateKey privateKey;
     192        public final SigningPrivateKey signingPrivateKey;
     193
     194        public KeyData(RouterIdentity ri, PrivateKey pk, SigningPrivateKey spk) {
     195            routerIdentity = ri;
     196            privateKey = pk;
     197            signingPrivateKey = spk;
     198        }
     199    }
     200
     201    /**
     202     *  @param rkf1 in router.keys format, tried second
     203     *  @param rkf2 in eepPriv.dat format, tried first
     204     *  @return non-null, throws IOE if neither exisits
     205     *  @since 0.9.16
     206     */
     207    public static KeyData readKeyData(File rkf1, File rkf2) throws DataFormatException, IOException {
     208        RouterIdentity ri;
     209        PrivateKey privkey;
     210        SigningPrivateKey signingPrivKey;
     211        if (rkf2.exists()) {
     212            RouterPrivateKeyFile pkf = new RouterPrivateKeyFile(rkf2);
     213            ri = pkf.getRouterIdentity();
     214            if (!pkf.validateKeyPairs())
     215                throw new DataFormatException("Key pairs invalid");
     216            privkey = pkf.getPrivKey();
     217            signingPrivKey = pkf.getSigningPrivKey();
     218        } else {
     219            InputStream fis = null;
     220            try {
     221                fis = new BufferedInputStream(new FileInputStream(rkf1));
     222                privkey = new PrivateKey();
     223                privkey.readBytes(fis);
     224                signingPrivKey = new SigningPrivateKey();
     225                signingPrivKey.readBytes(fis);
     226                PublicKey pubkey = new PublicKey();
     227                pubkey.readBytes(fis);
     228                SigningPublicKey signingPubKey = new SigningPublicKey();
     229                signingPubKey.readBytes(fis);
     230
     231                // validate
     232                try {
     233                    if (!pubkey.equals(KeyGenerator.getPublicKey(privkey)))
     234                        throw new DataFormatException("Key pairs invalid");
     235                    if (!signingPubKey.equals(KeyGenerator.getSigningPublicKey(signingPrivKey)))
     236                        throw new DataFormatException("Key pairs invalid");
     237                } catch (IllegalArgumentException iae) {
     238                    throw new DataFormatException("Key pairs invalid", iae);
     239                }
     240
     241                ri = new RouterIdentity();
     242                ri.setPublicKey(pubkey);
     243                ri.setSigningPublicKey(signingPubKey);
     244                ri.setCertificate(Certificate.NULL_CERT);
     245            } finally {
     246                if (fis != null) try { fis.close(); } catch (IOException ioe) {}
     247            }
     248        }
     249        return new KeyData(ri, privkey, signingPrivKey);
     250    }
    177251}
  • router/java/src/net/i2p/router/startup/RebuildRouterInfoJob.java

    reab4397 r156d868  
    1010
    1111import java.io.File;
    12 import java.io.FileInputStream;
    1312import java.io.FileOutputStream;
    1413import java.io.IOException;
    1514import java.util.Properties;
    1615
     16import net.i2p.crypto.SigType;
    1717import net.i2p.data.Certificate;
    1818import net.i2p.data.DataFormatException;
     19import net.i2p.data.DataHelper;
    1920import net.i2p.data.PrivateKey;
    2021import net.i2p.data.PublicKey;
    21 import net.i2p.data.RouterIdentity;
    22 import net.i2p.data.RouterInfo;
     22import net.i2p.data.router.RouterIdentity;
     23import net.i2p.data.router.RouterInfo;
    2324import net.i2p.data.SigningPrivateKey;
    2425import net.i2p.data.SigningPublicKey;
     
    2627import net.i2p.router.Router;
    2728import net.i2p.router.RouterContext;
     29import net.i2p.router.startup.LoadRouterInfoJob.KeyData;
    2830import net.i2p.util.Log;
    2931import net.i2p.util.SecureFileOutputStream;
     
    4547 *
    4648 */
    47 public class RebuildRouterInfoJob extends JobImpl {
     49class RebuildRouterInfoJob extends JobImpl {
    4850    private final Log _log;
    4951   
     
    5860   
    5961    public void runJob() {
     62        throw new UnsupportedOperationException();
     63/****
    6064        _log.debug("Testing to rebuild router info");
    61         String infoFile = getContext().getProperty(Router.PROP_INFO_FILENAME, Router.PROP_INFO_FILENAME_DEFAULT);
    62         File info = new File(getContext().getRouterDir(), infoFile);
    63         String keyFilename = getContext().getProperty(Router.PROP_KEYS_FILENAME, Router.PROP_KEYS_FILENAME_DEFAULT);
    64         File keyFile = new File(getContext().getRouterDir(), keyFilename);
     65        File info = new File(getContext().getRouterDir(), CreateRouterInfoJob.INFO_FILENAME);
     66        File keyFile = new File(getContext().getRouterDir(), CreateRouterInfoJob.KEYS2_FILENAME);
    6567       
    6668        if (!info.exists() || !keyFile.exists()) {
     
    7274        getTiming().setStartAfter(getContext().clock().now() + REBUILD_DELAY);
    7375        getContext().jobQueue().addJob(this);
     76****/
    7477    }
    7578   
     
    7881    }
    7982
     83    /**
     84     *  @param alreadyRunning unused
     85     */
    8086    void rebuildRouterInfo(boolean alreadyRunning) {
    8187        _log.debug("Rebuilding the new router info");
    8288        RouterInfo info = null;
    83         String infoFilename = getContext().getProperty(Router.PROP_INFO_FILENAME, Router.PROP_INFO_FILENAME_DEFAULT);
    84         File infoFile = new File(getContext().getRouterDir(), infoFilename);
    85         String keyFilename = getContext().getProperty(Router.PROP_KEYS_FILENAME, Router.PROP_KEYS_FILENAME_DEFAULT);
    86         File keyFile = new File(getContext().getRouterDir(), keyFilename);
     89        File infoFile = new File(getContext().getRouterDir(), CreateRouterInfoJob.INFO_FILENAME);
     90        File keyFile = new File(getContext().getRouterDir(), CreateRouterInfoJob.KEYS_FILENAME);
     91        File keyFile2 = new File(getContext().getRouterDir(), CreateRouterInfoJob.KEYS2_FILENAME);
    8792       
    88         if (keyFile.exists()) {
     93        if (keyFile2.exists() || keyFile.exists()) {
    8994            // ok, no need to rebuild a brand new identity, just update what we can
    9095            RouterInfo oldinfo = getContext().router().getRouterInfo();
    9196            if (oldinfo == null) {
    92                 info = new RouterInfo();
    93                 FileInputStream fis = null;
    9497                try {
    95                     fis = new FileInputStream(keyFile);
    96                     PrivateKey privkey = new PrivateKey();
    97                     privkey.readBytes(fis);
    98                     SigningPrivateKey signingPrivKey = new SigningPrivateKey();
    99                     signingPrivKey.readBytes(fis);
    100                     PublicKey pubkey = new PublicKey();
    101                     pubkey.readBytes(fis);
    102                     SigningPublicKey signingPubKey = new SigningPublicKey();
    103                     signingPubKey.readBytes(fis);
    104                     RouterIdentity ident = new RouterIdentity();
    105                     Certificate cert = getContext().router().createCertificate();
    106                     ident.setCertificate(cert);
    107                     ident.setPublicKey(pubkey);
    108                     ident.setSigningPublicKey(signingPubKey);
    109                     info.setIdentity(ident);
     98                    KeyData kd = LoadRouterInfoJob.readKeyData(keyFile, keyFile2);
     99                    info = new RouterInfo();
     100                    info.setIdentity(kd.routerIdentity);
    110101                } catch (Exception e) {
    111102                    _log.log(Log.CRIT, "Error reading in the key data from " + keyFile.getAbsolutePath(), e);
    112                     if (fis != null) try { fis.close(); } catch (IOException ioe) {}
    113                     fis = null;
    114103                    keyFile.delete();
     104                    keyFile2.delete();
    115105                    rebuildRouterInfo(alreadyRunning);
    116106                    return;
    117                 } finally {
    118                     if (fis != null) try { fis.close(); } catch (IOException ioe) {}
    119107                }
    120108            } else {
     
    161149            // this proc writes the keys and info to the file as well as builds the latest and greatest info
    162150            CreateRouterInfoJob j = new CreateRouterInfoJob(getContext(), null);
    163             info = j.createRouterInfo();
     151            synchronized (getContext().router().routerInfoFileLock) {
     152                info = j.createRouterInfo();
     153            }
    164154        }
    165155       
    166156        //MessageHistory.initialize();
    167157        getContext().router().setRouterInfo(info);
    168         _log.info("Router info rebuilt and stored at " + infoFilename + " [" + info + "]");
     158        _log.info("Router info rebuilt and stored at " + infoFile + " [" + info + "]");
    169159    }
    170160   
  • router/java/src/net/i2p/router/startup/StartAcceptingClientsJob.java

    reab4397 r156d868  
    1313
    1414/** start I2CP interface */
    15 public class StartAcceptingClientsJob extends JobImpl {
     15class StartAcceptingClientsJob extends JobImpl {
    1616   
    1717    public StartAcceptingClientsJob(RouterContext context) {
  • router/java/src/net/i2p/router/startup/WorkingDir.java

    reab4397 r156d868  
    148148        // and only migrate the data files if told to do so
    149149        // (router.keys could be deleted later by a killkeys())
    150         test = new File(oldDirf, "router.keys");
     150        test = new File(oldDirf, CreateRouterInfoJob.KEYS_FILENAME);
    151151        boolean oldInstall = test.exists();
    152152        if (!oldInstall) {
  • router/java/src/net/i2p/router/tasks/GracefulShutdown.java

    reab4397 r156d868  
    3232                        log.log(Log.CRIT, "Restarting after a brief delay");
    3333                    else
    34                         log.log(Log.CRIT, "Graceful shutdown progress - no more tunnels, safe to die");
     34                        log.log(Log.CRIT, "Graceful shutdown progress: No more tunnels, starting final shutdown");
    3535                    // Allow time for a UI reponse
    3636                    try {
  • router/java/src/net/i2p/router/tasks/PersistRouterInfoJob.java

    reab4397 r156d868  
    1414
    1515import net.i2p.data.DataFormatException;
    16 import net.i2p.data.RouterInfo;
     16import net.i2p.data.router.RouterInfo;
    1717import net.i2p.router.JobImpl;
    18 import net.i2p.router.Router;
    1918import net.i2p.router.RouterContext;
     19import net.i2p.router.startup.CreateRouterInfoJob;
    2020import net.i2p.util.Log;
    2121import net.i2p.util.SecureFileOutputStream;
     
    3838            _log.debug("Persisting updated router info");
    3939
    40         String infoFilename = getContext().getProperty(Router.PROP_INFO_FILENAME, Router.PROP_INFO_FILENAME_DEFAULT);
    41         File infoFile = new File(getContext().getRouterDir(), infoFilename);
     40        File infoFile = new File(getContext().getRouterDir(), CreateRouterInfoJob.INFO_FILENAME);
    4241
    4342        RouterInfo info = getContext().router().getRouterInfo();
  • router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java

    reab4397 r156d868  
    1818
    1919import net.i2p.data.Hash;
    20 import net.i2p.data.RouterAddress;
    21 import net.i2p.data.RouterInfo;
     20import net.i2p.data.router.RouterAddress;
     21import net.i2p.data.router.RouterInfo;
    2222import net.i2p.router.CommSystemFacade;
    2323import net.i2p.router.OutNetMessage;
  • router/java/src/net/i2p/router/transport/Transport.java

    reab4397 r156d868  
    1515
    1616import net.i2p.data.Hash;
    17 import net.i2p.data.RouterAddress;
    18 import net.i2p.data.RouterInfo;
     17import net.i2p.data.router.RouterAddress;
     18import net.i2p.data.router.RouterInfo;
    1919import net.i2p.router.OutNetMessage;
    2020
  • router/java/src/net/i2p/router/transport/TransportEventListener.java

    reab4397 r156d868  
    1010
    1111import net.i2p.data.Hash;
    12 import net.i2p.data.RouterIdentity;
     12import net.i2p.data.router.RouterIdentity;
    1313import net.i2p.data.i2np.I2NPMessage;
    1414
  • router/java/src/net/i2p/router/transport/TransportImpl.java

    reab4397 r156d868  
    3131import net.i2p.data.DataHelper;
    3232import net.i2p.data.Hash;
    33 import net.i2p.data.RouterAddress;
    34 import net.i2p.data.RouterIdentity;
    35 import net.i2p.data.RouterInfo;
     33import net.i2p.data.router.RouterAddress;
     34import net.i2p.data.router.RouterIdentity;
     35import net.i2p.data.router.RouterInfo;
    3636import net.i2p.data.i2np.I2NPMessage;
    3737import net.i2p.router.CommSystemFacade;
  • router/java/src/net/i2p/router/transport/TransportManager.java

    reab4397 r156d868  
    2323
    2424import net.i2p.data.Hash;
    25 import net.i2p.data.RouterAddress;
    26 import net.i2p.data.RouterIdentity;
     25import net.i2p.data.router.RouterAddress;
     26import net.i2p.data.router.RouterIdentity;
    2727import net.i2p.data.i2np.I2NPMessage;
    2828import net.i2p.router.CommSystemFacade;
     
    6060        _log = _context.logManager().getLog(TransportManager.class);
    6161        _context.statManager().createRateStat("transport.banlistOnUnreachable", "Add a peer to the banlist since none of the transports can reach them", "Transport", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
     62        _context.statManager().createRateStat("transport.banlistOnUsupportedSigType", "Add a peer to the banlist since signature type is unsupported", "Transport", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
    6263        _context.statManager().createRateStat("transport.noBidsYetNotAllUnreachable", "Add a peer to the banlist since none of the transports can reach them", "Transport", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
    6364        _context.statManager().createRateStat("transport.bidFailBanlisted", "Could not attempt to bid on message, as they were banlisted", "Transport", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
     
    500501        }
    501502        if (unreachableTransports >= _transports.size()) {
    502             // Don't banlist if we aren't talking to anybody, as we may have a network connection issue
    503             if (unreachableTransports >= _transports.size() && countActivePeers() > 0) {
     503            if (msg.getTarget().getIdentity().getSigningPublicKey().getType() == null) {
     504                _context.statManager().addRateData("transport.banlistOnUnsupportedSigType", 1);
     505                _context.banlist().banlistRouterForever(peer, _x("Unsupported signature type"));
     506            } else if (unreachableTransports >= _transports.size() && countActivePeers() > 0) {
     507                // Don't banlist if we aren't talking to anybody, as we may have a network connection issue
    504508                _context.statManager().addRateData("transport.banlistOnUnreachable", msg.getLifetime(), msg.getLifetime());
    505509                _context.banlist().banlistRouter(peer, _x("Unreachable on any transport"));
  • router/java/src/net/i2p/router/transport/TransportUtil.java

    reab4397 r156d868  
    1414import java.util.Map;
    1515
    16 import net.i2p.data.RouterAddress;
     16import net.i2p.data.router.RouterAddress;
    1717import net.i2p.router.RouterContext;
    1818
  • router/java/src/net/i2p/router/transport/ntcp/EstablishState.java

    reab4397 r156d868  
    11package net.i2p.router.transport.ntcp;
    22
     3import java.io.ByteArrayInputStream;
    34import java.io.ByteArrayOutputStream;
    45import java.io.IOException;
     
    89
    910import net.i2p.I2PAppContext;
     11import net.i2p.crypto.SigType;
    1012import net.i2p.data.Base64;
    1113import net.i2p.data.DataFormatException;
    1214import net.i2p.data.DataHelper;
    1315import net.i2p.data.Hash;
    14 import net.i2p.data.RouterIdentity;
     16import net.i2p.data.router.RouterIdentity;
    1517import net.i2p.data.Signature;
    1618import net.i2p.router.Router;
     
    7173    private final byte _hX_xor_bobIdentHash[];
    7274    private int _aliceIdentSize;
     75    private RouterIdentity _aliceIdent;
    7376    /** contains the decrypted aliceIndexSize + aliceIdent + tsA + padding + aliceSig */
    7477    private ByteArrayOutputStream _sz_aliceIdent_tsA_padding_aliceSig;
     
    113116    private boolean _failedBySkew;
    114117   
     118    private static final int MIN_RI_SIZE = 387;
     119    private static final int MAX_RI_SIZE = 2048;
     120
    115121    private EstablishState() {
    116122        _context = null;
     
    157163    public void receive(ByteBuffer src) {
    158164        if (_corrupt || _verified)
    159             throw new IllegalStateException(prefix() + "received after completion [corrupt?" + _corrupt + " verified? " + _verified + "] on " + _con);
     165            throw new IllegalStateException(prefix() + "received after completion [corrupt?" +
     166                                            _corrupt + " verified? " + _verified + "] on " + _con);
    160167        if (!src.hasRemaining())
    161168            return; // nothing to receive
     
    186193    private void receiveInbound(ByteBuffer src) {
    187194        if (_log.shouldLog(Log.DEBUG))
    188             _log.debug(prefix()+"Receiving inbound: prev received=" + _received + " src.remaining=" + src.remaining());
     195            _log.debug(prefix() + "Receiving inbound: prev received=" + _received +
     196                       " src.remaining=" + src.remaining());
    189197        while (_received < _X.length && src.hasRemaining()) {
    190198            byte c = src.get();
     
    270278                    SimpleByteCache.release(hxy);
    271279                    _e_hXY_tsB = new byte[toEncrypt.length];
    272                     _context.aes().encrypt(toEncrypt, 0, _e_hXY_tsB, 0, _dh.getSessionKey(), _Y, _Y.length-16, toEncrypt.length);
     280                    _context.aes().encrypt(toEncrypt, 0, _e_hXY_tsB, 0, _dh.getSessionKey(),
     281                                           _Y, _Y.length-16, toEncrypt.length);
    273282                    if (_log.shouldLog(Log.DEBUG))
    274283                        _log.debug(prefix()+"encrypted H(X+Y)+tsB+padding: " + Base64.encode(_e_hXY_tsB));
     
    287296            }
    288297
    289             // ok, we are onto the encrypted area
     298            // ok, we are onto the encrypted area, i.e. Message #3
    290299            while (src.hasRemaining() && !_corrupt) {
    291300                //if (_log.shouldLog(Log.DEBUG))
     
    296305                }
    297306                if (_curEncryptedOffset >= _curEncrypted.length) {
    298                     _context.aes().decrypt(_curEncrypted, 0, _curDecrypted, 0, _dh.getSessionKey(), _prevEncrypted, 0, _curEncrypted.length);
     307                    _context.aes().decrypt(_curEncrypted, 0, _curDecrypted, 0, _dh.getSessionKey(),
     308                                           _prevEncrypted, 0, _curEncrypted.length);
    299309                    //if (_log.shouldLog(Log.DEBUG))
    300310                    //    _log.debug(prefix()+"full block read and decrypted: " + Base64.encode(_curDecrypted));
     
    306316
    307317                    if (_aliceIdentSize <= 0) { // we are on the first decrypted block
    308                         _aliceIdentSize = (int)DataHelper.fromLong(_curDecrypted, 0, 2);
    309                         _sz_aliceIdent_tsA_padding_aliceSigSize = 2 + _aliceIdentSize + 4 + Signature.SIGNATURE_BYTES;
     318                        int sz = (int)DataHelper.fromLong(_curDecrypted, 0, 2);
     319                        if (sz < MIN_RI_SIZE || sz > MAX_RI_SIZE) {
     320                            _context.statManager().addRateData("ntcp.invalidInboundSize", sz);
     321                            fail("size is invalid", new Exception("size is " + sz));
     322                            return;
     323                        }
     324                        _aliceIdentSize  = sz;
     325
     326                        // We must defer the calculations for total size of the message until
     327                        //  we get the full alice ident so
     328                        // we can determine how long the signature is.
     329                        // See below
     330
     331                    }
     332                    try {
     333                        _sz_aliceIdent_tsA_padding_aliceSig.write(_curDecrypted);
     334                    } catch (IOException ioe) {
     335                        if (_log.shouldLog(Log.ERROR)) _log.error(prefix()+"Error writing to the baos?", ioe);
     336                    }
     337                    //if (_log.shouldLog(Log.DEBUG))
     338                    //    _log.debug(prefix()+"subsequent block decrypted (" + _sz_aliceIdent_tsA_padding_aliceSig.size() + ")");
     339
     340                    if (_aliceIdent == null &&
     341                        _sz_aliceIdent_tsA_padding_aliceSig.size() >= 2 + _aliceIdentSize) {
     342                        // we have enough to get Alice's RI and determine the sig+padding length
     343                        readAliceRouterIdentity();
     344                        if (_aliceIdent == null) {
     345                            // readAliceRouterIdentity already called fail
     346                            return;
     347                        }
     348                        SigType type = _aliceIdent.getSigningPublicKey().getType();
     349                        if (type == null) {
     350                            fail("Unsupported sig type");
     351                            return;
     352                        }
     353                        // handle variable signature size
     354                        _sz_aliceIdent_tsA_padding_aliceSigSize = 2 + _aliceIdentSize + 4 + type.getSigLen();
    310355                        int rem = (_sz_aliceIdent_tsA_padding_aliceSigSize % 16);
    311356                        int padding = 0;
     
    313358                            padding = 16-rem;
    314359                        _sz_aliceIdent_tsA_padding_aliceSigSize += padding;
    315                         try {
    316                             _sz_aliceIdent_tsA_padding_aliceSig.write(_curDecrypted);
    317                         } catch (IOException ioe) {
    318                             if (_log.shouldLog(Log.ERROR)) _log.error(prefix()+"Error writing to the baos?", ioe);
    319                         }
    320360                        if (_log.shouldLog(Log.DEBUG))
    321                             _log.debug(prefix()+"alice ident size decrypted as " + _aliceIdentSize + ", making the padding at " + padding + " and total size at " + _sz_aliceIdent_tsA_padding_aliceSigSize);
    322                     } else {
    323                         // subsequent block...
    324                         try {
    325                             _sz_aliceIdent_tsA_padding_aliceSig.write(_curDecrypted);
    326                         } catch (IOException ioe) {
    327                             if (_log.shouldLog(Log.ERROR)) _log.error(prefix()+"Error writing to the baos?", ioe);
    328                         }
    329                         //if (_log.shouldLog(Log.DEBUG))
    330                         //    _log.debug(prefix()+"subsequent block decrypted (" + _sz_aliceIdent_tsA_padding_aliceSig.size() + ")");
    331 
    332                         if (_sz_aliceIdent_tsA_padding_aliceSig.size() >= _sz_aliceIdent_tsA_padding_aliceSigSize) {
     361                            _log.debug(prefix() + "alice ident size decrypted as " + _aliceIdentSize +
     362                                       ", making the padding at " + padding + " and total size at " +
     363                                       _sz_aliceIdent_tsA_padding_aliceSigSize);
     364                    }
     365
     366                    if (_aliceIdent != null &&
     367                        _sz_aliceIdent_tsA_padding_aliceSig.size() >= _sz_aliceIdent_tsA_padding_aliceSigSize) {
     368                        // we have the remainder of Message #3, i.e. the padding+signature
     369                        // Time to verify.
     370
    333371                            verifyInbound();
    334372                            if (!_corrupt && _verified && src.hasRemaining())
     
    340378                                           + " verified=" + _verified + " extra=" + (_extra != null ? _extra.length : 0) + ")");
    341379                            return;
    342                         }
    343380                    }
    344381                } else {
     
    346383                    // block was read, so we can't decrypt it.
    347384                    if (_log.shouldLog(Log.DEBUG))
    348                         _log.debug(prefix()+"end of available data with only a partial block read (" + _curEncryptedOffset + ", " + _received + ")");
     385                        _log.debug(prefix() + "end of available data with only a partial block read (" +
     386                                   _curEncryptedOffset + ", " + _received + ")");
    349387                }
    350388            }
     
    459497
    460498                byte ident[] = _context.router().getRouterInfo().getIdentity().toByteArray();
    461                 int min = 2+ident.length+4+Signature.SIGNATURE_BYTES;
     499                // handle variable signature size
     500                int min = 2 + ident.length + 4 + sig.length();
    462501                int rem = min % 16;
    463502                int padding = 0;
     
    470509                if (padding > 0)
    471510                    _context.random().nextBytes(preEncrypt, 2 + ident.length + 4, padding);
    472                 System.arraycopy(sig.getData(), 0, preEncrypt, 2+ident.length+4+padding, Signature.SIGNATURE_BYTES);
     511                System.arraycopy(sig.getData(), 0, preEncrypt, 2+ident.length+4+padding, sig.length());
    473512
    474513                _prevEncrypted = new byte[preEncrypt.length];
    475                 _context.aes().encrypt(preEncrypt, 0, _prevEncrypted, 0, _dh.getSessionKey(), _hX_xor_bobIdentHash, _hX_xor_bobIdentHash.length-16, preEncrypt.length);
     514                _context.aes().encrypt(preEncrypt, 0, _prevEncrypted, 0, _dh.getSessionKey(),
     515                                       _hX_xor_bobIdentHash, _hX_xor_bobIdentHa