use of net.i2p.router.networkdb.kademlia.FloodfillNetworkDatabaseFacade in project i2p.i2p by i2p.
the class NetDbRenderer method renderLeaseSetHTML.
/**
* @param debug @since 0.7.14 sort by distance from us, display
* median distance, and other stuff, useful when floodfill
*/
public void renderLeaseSetHTML(Writer out, boolean debug) throws IOException {
StringBuilder buf = new StringBuilder(4 * 1024);
if (debug)
buf.append("<p id=\"debugmode\">Debug mode - Sorted by hash distance, closest first</p>\n");
Hash ourRKey;
Set<LeaseSet> leases;
DecimalFormat fmt;
if (debug) {
ourRKey = _context.routerHash();
leases = new TreeSet<LeaseSet>(new LeaseSetRoutingKeyComparator(ourRKey));
fmt = new DecimalFormat("#0.00");
} else {
ourRKey = null;
leases = new TreeSet<LeaseSet>(new LeaseSetComparator());
fmt = null;
}
leases.addAll(_context.netDb().getLeases());
int medianCount = 0;
int rapCount = 0;
BigInteger median = null;
int c = 0;
// Summary
FloodfillNetworkDatabaseFacade netdb = (FloodfillNetworkDatabaseFacade) _context.netDb();
if (debug) {
buf.append("<table id=\"leasesetdebug\">\n");
} else {
buf.append("<table id=\"leasesetsummary\">\n");
}
buf.append("<tr><th colspan=\"3\">Leaseset Summary</th>").append("<th><a href=\"/configadvanced\" title=\"").append(_t("Manually Configure Floodfill Participation")).append("\">[").append(_t("Configure Floodfill Participation")).append("]</a></th></tr>\n").append("<tr><td><b>Total Leasesets:</b></td><td colspan=\"3\">").append(leases.size()).append("</td></tr>\n");
if (debug) {
buf.append("<tr><td><b>Published (RAP) Leasesets:</b></td><td colspan=\"3\">").append(netdb.getKnownLeaseSets()).append("</td></tr>\n").append("<tr><td><b>Mod Data:</b></td><td>").append(DataHelper.getUTF8(_context.routerKeyGenerator().getModData())).append("</td>").append("<td><b>Last Changed:</b></td><td>").append(new Date(_context.routerKeyGenerator().getLastChanged())).append("</td></tr>\n").append("<tr><td><b>Next Mod Data:</b></td><td>").append(DataHelper.getUTF8(_context.routerKeyGenerator().getNextModData())).append("</td>").append("<td><b>Change in:</b></td><td>").append(DataHelper.formatDuration(_context.routerKeyGenerator().getTimeTillMidnight())).append("</td></tr>\n");
}
int ff = _context.peerManager().getPeersByCapability(FloodfillNetworkDatabaseFacade.CAPABILITY_FLOODFILL).size();
buf.append("<tr><td><b>Known Floodfills:</b></td><td colspan=\"3\">").append(ff).append("</td></tr>\n").append("<tr><td><b>Currently Floodfill?</b></td><td colspan=\"3\">").append(netdb.floodfillEnabled() ? "yes" : "no").append("</td></tr>\n");
buf.append("</table>\n");
if (leases.isEmpty()) {
if (!debug)
buf.append("<div id=\"noleasesets\"><i>").append(_t("No Leasesets currently active.")).append("</i></div>");
} else {
if (debug) {
// Find the center of the RAP leasesets
for (LeaseSet ls : leases) {
if (ls.getReceivedAsPublished())
rapCount++;
}
medianCount = rapCount / 2;
}
boolean linkSusi = WebAppStarter.isWebAppRunning("susidns");
long now = _context.clock().now();
buf.append("<div class=\"leasesets_container\">");
for (LeaseSet ls : leases) {
Destination dest = ls.getDestination();
Hash key = dest.calculateHash();
buf.append("<table class=\"leaseset\">\n").append("<tr><th><b>").append(_t("LeaseSet")).append(":</b> <code>").append(key.toBase64()).append("</code>");
if (_context.keyRing().get(key) != null)
buf.append(" (").append(_t("Encrypted")).append(')');
buf.append("</th>");
if (_context.clientManager().isLocal(dest)) {
buf.append("<th><a href=\"tunnels#" + key.toBase64().substring(0, 4) + "\">" + _t("Local") + "</a> ");
boolean unpublished = !_context.clientManager().shouldPublishLeaseSet(key);
if (unpublished)
buf.append("<b>").append(_t("Unpublished")).append("</b> ");
buf.append("<b>").append(_t("Destination")).append(":</b> ");
TunnelPoolSettings in = _context.tunnelManager().getInboundSettings(key);
if (in != null && in.getDestinationNickname() != null)
buf.append(in.getDestinationNickname());
else
buf.append(dest.toBase64().substring(0, 6));
buf.append("</th></tr>\n<tr><td");
// If the dest is published but not in the addressbook, an extra
// <td> is appended with an "Add to addressbook" link, so this
// <td> should not span 2 columns.
String host = null;
if (!unpublished) {
host = _context.namingService().reverseLookup(dest);
}
if (unpublished || host != null || !linkSusi) {
buf.append(" colspan=\"2\"");
}
buf.append(">");
String b32 = dest.toBase32();
buf.append("<a href=\"http://").append(b32).append("\">").append(b32).append("</a></td>");
if (linkSusi && !unpublished) {
if (host == null) {
buf.append("<td class=\"addtobook\" colspan=\"2\">").append("<a title=\"").append(_t("Add to addressbook")).append("\" href=\"/susidns/addressbook.jsp?book=private&destination=").append(dest.toBase64()).append("#add\">").append(_t("Add to local addressbook")).append("</a></td>");
}
}
// else probably a client
} else {
buf.append("<th><b>").append(_t("Destination")).append(":</b> ");
String host = _context.namingService().reverseLookup(dest);
if (host != null) {
buf.append("<a href=\"http://").append(host).append("/\">").append(host).append("</a></th>");
} else {
String b32 = dest.toBase32();
buf.append("<code>").append(dest.toBase64().substring(0, 6)).append("</code></th>").append("</tr>\n<tr><td");
if (!linkSusi)
buf.append(" colspan=\"2\"");
buf.append("><a href=\"http://").append(b32).append("\">").append(b32).append("</a></td>\n");
if (linkSusi) {
buf.append("<td class=\"addtobook\"><a title=\"").append(_t("Add to addressbook")).append("\" href=\"/susidns/addressbook.jsp?book=private&destination=").append(dest.toBase64()).append("#add\">").append(_t("Add to local addressbook")).append("</a></td>");
}
}
}
buf.append("</tr>\n<tr><td colspan=\"2\">\n");
long exp = ls.getLatestLeaseDate() - now;
if (exp > 0)
buf.append("<b>").append(_t("Expires in {0}", DataHelper.formatDuration2(exp))).append("</b>");
else
buf.append("<b>").append(_t("Expired {0} ago", DataHelper.formatDuration2(0 - exp))).append("</b>");
buf.append("</td></tr>\n");
if (debug) {
buf.append("<tr><td colspan=\"2\">");
buf.append("<b>RAP?</b> ").append(ls.getReceivedAsPublished());
buf.append(" <b>RAR?</b> ").append(ls.getReceivedAsReply());
BigInteger dist = HashDistance.getDistance(ourRKey, ls.getRoutingKey());
if (ls.getReceivedAsPublished()) {
if (c++ == medianCount)
median = dist;
}
buf.append(" <b>Distance: </b>").append(fmt.format(biLog2(dist)));
buf.append("</td></tr>\n<tr><td colspan=\"2\">");
// buf.append(dest.toBase32()).append("<br>");
buf.append("<b>Signature type:</b> ").append(dest.getSigningPublicKey().getType());
buf.append(" <b>Encryption Key:</b> ").append(ls.getEncryptionKey().toBase64().substring(0, 20)).append("…");
buf.append("</td></tr>\n<tr><td colspan=\"2\">");
buf.append("<b>Routing Key:</b> ").append(ls.getRoutingKey().toBase64());
buf.append("</td></tr>");
}
buf.append("<tr><td colspan=\"2\"><ul class=\"netdb_leases\">");
for (int i = 0; i < ls.getLeaseCount(); i++) {
Lease lease = ls.getLease(i);
buf.append("<li><b>").append(_t("Lease")).append(' ').append(i + 1).append(":</b> <span class=\"netdb_gateway\" title=\"").append(_t("Gateway")).append("\"><img src=\"themes/console/images/info/gateway.png\" alt=\"").append(_t("Gateway")).append("\"></span> <span class=\"tunnel_peer\">");
buf.append(_context.commSystem().renderPeerHTML(lease.getGateway()));
buf.append("</span> <span class=\"netdb_tunnel\">").append(_t("Tunnel")).append(" <span class=\"tunnel_id\">").append(lease.getTunnelId().getTunnelId()).append("</span></span> ");
if (debug) {
long exl = lease.getEndDate().getTime() - now;
if (exl > 0)
buf.append("<b class=\"netdb_expiry\">").append(_t("Expires in {0}", DataHelper.formatDuration2(exl))).append("</b>");
else
buf.append("<b class=\"netdb_expiry\">").append(_t("Expired {0} ago", DataHelper.formatDuration2(0 - exl))).append("</b>");
}
buf.append("</li>");
}
buf.append("</ul></td></tr>\n");
buf.append("</table>\n");
out.write(buf.toString());
buf.setLength(0);
}
// for each
if (debug) {
buf.append("<table id=\"leasesetdebug\"><tr><td><b>Network data (only valid if floodfill):</b></td><td colspan=\"3\">");
// buf.append("</b></p><p><b>Center of Key Space (router hash): " + ourRKey.toBase64());
if (median != null) {
double log2 = biLog2(median);
buf.append("</td></tr>").append("<tr><td><b>Median distance (bits):</b></td><td colspan=\"3\">").append(fmt.format(log2)).append("</td></tr>\n");
// 2 for 4 floodfills... -1 for median
// this can be way off for unknown reasons
int total = (int) Math.round(Math.pow(2, 2 + 256 - 1 - log2));
buf.append("<tr><td><b>Estimated total floodfills:</b></td><td colspan=\"3\">").append(total).append("</td></tr>\n");
buf.append("<tr><td><b>Estimated total leasesets:</b></td><td colspan=\"3\">").append(total * rapCount / 4);
} else {
buf.append("<i>Not floodfill or no data.</i>");
}
buf.append("</td></tr></table>\n");
}
// median table
buf.append("</div>");
}
// !empty
out.write(buf.toString());
out.flush();
}
use of net.i2p.router.networkdb.kademlia.FloodfillNetworkDatabaseFacade in project i2p.i2p by i2p.
the class ConfigAdvancedHandler method saveFF.
/**
* @since 0.9.20
*/
private void saveFF() {
boolean saved = _context.router().saveConfig(ConfigAdvancedHelper.PROP_FLOODFILL_PARTICIPANT, _ff);
if (_ff.equals("false") || _ff.equals("true")) {
FloodfillNetworkDatabaseFacade fndf = (FloodfillNetworkDatabaseFacade) _context.netDb();
boolean wasFF = fndf.floodfillEnabled();
boolean isFF = _ff.equals("true");
// this will rebuild the RI, log in the event log, etc.
fndf.setFloodfillEnabled(isFF);
}
if (saved)
addFormNotice(_t("Configuration saved successfully"));
else
addFormError(_t("Error saving the configuration (applied but not saved) - please see the error logs"));
}
use of net.i2p.router.networkdb.kademlia.FloodfillNetworkDatabaseFacade in project i2p.i2p by i2p.
the class TunnelPeerSelector method getExclude.
/**
* Pick peers that we want to avoid
*/
public Set<Hash> getExclude(boolean isInbound, boolean isExploratory) {
// we may want to update this to skip 'hidden' or 'unreachable' peers, but that
// isn't safe, since they may publish one set of routerInfo to us and another to
// other peers. the defaults for filterUnreachable has always been to return false,
// but might as well make it explicit with a "false &&"
//
// Unreachable peers at the inbound gateway is a major cause of problems.
// Due to a bug in SSU peer testing in 0.6.1.32 and earlier, peers don't know
// if they are unreachable, so the netdb indication won't help much.
// As of 0.6.1.33 we should have lots of unreachables, so enable this for now.
// Also (and more effectively) exclude peers we detect are unreachable,
// this should be much more effective, especially on a router that has been
// up a few hours.
//
// We could just try and exclude them as the inbound gateway but that's harder
// (and even worse for anonymity?).
//
// Defaults changed to true for inbound only in filterUnreachable below.
Set<Hash> peers = new HashSet<Hash>(8);
peers.addAll(ctx.profileOrganizer().selectPeersRecentlyRejecting());
peers.addAll(ctx.tunnelManager().selectPeersInTooManyTunnels());
// if (false && filterUnreachable(ctx, isInbound, isExploratory)) {
if (filterUnreachable(isInbound, isExploratory)) {
// NOTE: filterUnreachable returns true for inbound, false for outbound
// This is the only use for getPeersByCapability? And the whole set of datastructures in PeerManager?
Collection<Hash> caps = ctx.peerManager().getPeersByCapability(Router.CAPABILITY_UNREACHABLE);
if (caps != null)
peers.addAll(caps);
caps = ctx.profileOrganizer().selectPeersLocallyUnreachable();
if (caps != null)
peers.addAll(caps);
}
if (filterSlow(isInbound, isExploratory)) {
// NOTE: filterSlow always returns true
char[] excl = getExcludeCaps(ctx);
if (excl != null) {
FloodfillNetworkDatabaseFacade fac = (FloodfillNetworkDatabaseFacade) ctx.netDb();
List<RouterInfo> known = fac.getKnownRouterData();
if (known != null) {
for (int i = 0; i < known.size(); i++) {
RouterInfo peer = known.get(i);
boolean shouldExclude = shouldExclude(peer, excl);
if (shouldExclude) {
peers.add(peer.getIdentity().calculateHash());
continue;
}
/*
String cap = peer.getCapabilities();
if (cap == null) {
peers.add(peer.getIdentity().calculateHash());
continue;
}
for (int j = 0; j < excl.length; j++) {
if (cap.indexOf(excl[j]) >= 0) {
peers.add(peer.getIdentity().calculateHash());
continue;
}
}
int maxLen = 0;
if (cap.indexOf(FloodfillNetworkDatabaseFacade.CAPACITY_FLOODFILL) >= 0)
maxLen++;
if (cap.indexOf(Router.CAPABILITY_REACHABLE) >= 0)
maxLen++;
if (cap.indexOf(Router.CAPABILITY_UNREACHABLE) >= 0)
maxLen++;
if (cap.length() <= maxLen)
peers.add(peer.getIdentity().calculateHash());
// otherwise, it contains flags we aren't trying to focus on,
// so don't exclude it based on published capacity
if (filterUptime(ctx, isInbound, isExploratory)) {
Properties opts = peer.getOptions();
if (opts != null) {
String val = opts.getProperty("stat_uptime");
long uptimeMs = 0;
if (val != null) {
long factor = 1;
if (val.endsWith("ms")) {
factor = 1;
val = val.substring(0, val.length()-2);
} else if (val.endsWith("s")) {
factor = 1000l;
val = val.substring(0, val.length()-1);
} else if (val.endsWith("m")) {
factor = 60*1000l;
val = val.substring(0, val.length()-1);
} else if (val.endsWith("h")) {
factor = 60*60*1000l;
val = val.substring(0, val.length()-1);
} else if (val.endsWith("d")) {
factor = 24*60*60*1000l;
val = val.substring(0, val.length()-1);
}
try { uptimeMs = Long.parseLong(val); } catch (NumberFormatException nfe) {}
uptimeMs *= factor;
} else {
// not publishing an uptime, so exclude it
peers.add(peer.getIdentity().calculateHash());
continue;
}
long infoAge = ctx.clock().now() - peer.getPublished();
if (infoAge < 0) {
infoAge = 0;
} else if (infoAge > 24*60*60*1000) {
// Only exclude long-unseen peers if we haven't just started up
long DONT_EXCLUDE_PERIOD = 15*60*1000;
if (ctx.router().getUptime() < DONT_EXCLUDE_PERIOD) {
if (log.shouldLog(Log.DEBUG))
log.debug("Not excluding a long-unseen peer, since we just started up.");
} else {
if (log.shouldLog(Log.DEBUG))
log.debug("Excluding a long-unseen peer.");
peers.add(peer.getIdentity().calculateHash());
}
//peers.add(peer.getIdentity().calculateHash());
continue;
} else {
if (infoAge + uptimeMs < 2*60*60*1000) {
// up for less than 2 hours, so exclude it
peers.add(peer.getIdentity().calculateHash());
}
}
} else {
// not publishing stats, so exclude it
peers.add(peer.getIdentity().calculateHash());
continue;
}
}
*/
}
}
/*
for (int i = 0; i < excludeCaps.length(); i++) {
List matches = ctx.peerManager().getPeersByCapability(excludeCaps.charAt(i));
if (log.shouldLog(Log.INFO))
log.info("Filtering out " + matches.size() + " peers with capability " + excludeCaps.charAt(i));
peers.addAll(matches);
}
*/
}
}
return peers;
}
use of net.i2p.router.networkdb.kademlia.FloodfillNetworkDatabaseFacade in project i2p.i2p by i2p.
the class TunnelPeerSelector method getClosestHopExclude.
/**
* Pick peers that we want to avoid for the first OB hop or last IB hop.
* There's several cases of importance:
* <ol><li>Inbound and we are hidden -
* Exclude all unless connected.
* This is taken care of in ClientPeerSelector and TunnelPeerSelector selectPeers(), not here.
*
* <li>We are IPv6-only.
* Exclude all v4-only peers, unless connected
* This is taken care of here.
*
* <li>We have NTCP or SSU disabled.
* Exclude all incompatible peers, unless connected
* This is taken care of here.
*
* <li>Minimum version check, if we are some brand-new sig type,
* or are using some new tunnel build method.
* Not currently used, but this is where to implement the checks if needed.
* Make sure that ClientPeerSelector and TunnelPeerSelector selectPeers() call this when needed.
* </ol>
*
* Don't call this unless you need to.
* See ClientPeerSelector and TunnelPeerSelector selectPeers().
*
* @param isInbound
* @return null if none
* @since 0.9.17
*/
protected Set<Hash> getClosestHopExclude(boolean isInbound) {
RouterInfo ri = ctx.router().getRouterInfo();
if (ri == null)
return null;
// we can skip this check now, uncomment if we have some new sigtype
// SigType type = ri.getIdentity().getSigType();
// if (type == SigType.DSA_SHA1)
// return null;
int ourMask = isInbound ? getInboundMask(ri) : getOutboundMask(ri);
Set<Hash> connected = ctx.commSystem().getEstablished();
Set<Hash> rv = new HashSet<Hash>(256);
FloodfillNetworkDatabaseFacade fac = (FloodfillNetworkDatabaseFacade) ctx.netDb();
List<RouterInfo> known = fac.getKnownRouterData();
if (known != null) {
for (int i = 0; i < known.size(); i++) {
RouterInfo peer = known.get(i);
// we can skip this check now, uncomment if we have some breaking change
// String v = peer.getVersion();
// RI sigtypes added in 0.9.16
// SSU inbound connection bug fixed in 0.9.17, but it won't bid, so NTCP only,
// no need to check
// if (VersionComparator.comp(v, "0.9.16") < 0)
// rv.add(peer.getIdentity().calculateHash());
Hash h = peer.getIdentity().calculateHash();
if (connected.contains(h))
continue;
boolean canConnect = isInbound ? canConnect(peer, ourMask) : canConnect(ourMask, peer);
if (!canConnect)
rv.add(h);
}
}
return rv;
}
use of net.i2p.router.networkdb.kademlia.FloodfillNetworkDatabaseFacade in project i2p.i2p by i2p.
the class SummaryHelper method reachability.
private NetworkStateMessage reachability() {
if (_context.commSystem().isDummy())
return new NetworkStateMessage(NetworkState.VMCOMM, "VM Comm System");
if (_context.router().getUptime() > 60 * 1000 && (!_context.router().gracefulShutdownInProgress()) && !_context.clientManager().isAlive())
// not a router problem but the user should know
return new NetworkStateMessage(NetworkState.ERROR, _t("ERR-Client Manager I2CP Error - check logs"));
// Warn based on actual skew from peers, not update status, so if we successfully offset
// the clock, we don't complain.
// if (!_context.clock().getUpdatedSuccessfully())
long skew = _context.commSystem().getFramedAveragePeerClockSkew(33);
// Display the actual skew, not the offset
if (Math.abs(skew) > 30 * 1000)
return new NetworkStateMessage(NetworkState.CLOCKSKEW, _t("ERR-Clock Skew of {0}", DataHelper.formatDuration2(Math.abs(skew))));
if (_context.router().isHidden())
return new NetworkStateMessage(NetworkState.HIDDEN, _t("Hidden"));
RouterInfo routerInfo = _context.router().getRouterInfo();
if (routerInfo == null)
return new NetworkStateMessage(NetworkState.TESTING, _t("Testing"));
Status status = _context.commSystem().getStatus();
NetworkState state = NetworkState.RUNNING;
switch(status) {
case OK:
case IPV4_OK_IPV6_UNKNOWN:
case IPV4_OK_IPV6_FIREWALLED:
case IPV4_UNKNOWN_IPV6_OK:
case IPV4_DISABLED_IPV6_OK:
case IPV4_SNAT_IPV6_OK:
RouterAddress ra = routerInfo.getTargetAddress("NTCP");
if (ra == null)
return new NetworkStateMessage(NetworkState.RUNNING, _t(status.toStatusString()));
byte[] ip = ra.getIP();
if (ip == null)
return new NetworkStateMessage(NetworkState.ERROR, _t("ERR-Unresolved TCP Address"));
// TODO set IPv6 arg based on configuration?
if (TransportUtil.isPubliclyRoutable(ip, true))
return new NetworkStateMessage(NetworkState.RUNNING, _t(status.toStatusString()));
return new NetworkStateMessage(NetworkState.ERROR, _t("ERR-Private TCP Address"));
case IPV4_SNAT_IPV6_UNKNOWN:
case DIFFERENT:
return new NetworkStateMessage(NetworkState.ERROR, _t("ERR-SymmetricNAT"));
case REJECT_UNSOLICITED:
state = NetworkState.FIREWALLED;
case IPV4_DISABLED_IPV6_FIREWALLED:
if (routerInfo.getTargetAddress("NTCP") != null)
return new NetworkStateMessage(NetworkState.WARN, _t("WARN-Firewalled with Inbound TCP Enabled"));
// fall through...
case IPV4_FIREWALLED_IPV6_OK:
case IPV4_FIREWALLED_IPV6_UNKNOWN:
if (((FloodfillNetworkDatabaseFacade) _context.netDb()).floodfillEnabled())
return new NetworkStateMessage(NetworkState.WARN, _t("WARN-Firewalled and Floodfill"));
// return new NetworkStateMessage(NetworkState.WARN, _t("WARN-Firewalled and Fast"));
return new NetworkStateMessage(state, _t(status.toStatusString()));
case DISCONNECTED:
return new NetworkStateMessage(NetworkState.TESTING, _t("Disconnected - check network connection"));
case HOSED:
return new NetworkStateMessage(NetworkState.ERROR, _t("ERR-UDP Port In Use - Set i2np.udp.internalPort=xxxx in advanced config and restart"));
case UNKNOWN:
state = NetworkState.TESTING;
case IPV4_UNKNOWN_IPV6_FIREWALLED:
case IPV4_DISABLED_IPV6_UNKNOWN:
default:
ra = routerInfo.getTargetAddress("SSU");
if (ra == null && _context.router().getUptime() > 5 * 60 * 1000) {
if (getActivePeers() <= 0)
return new NetworkStateMessage(NetworkState.ERROR, _t("ERR-No Active Peers, Check Network Connection and Firewall"));
else if (_context.getProperty(ConfigNetHelper.PROP_I2NP_NTCP_HOSTNAME) == null || _context.getProperty(ConfigNetHelper.PROP_I2NP_NTCP_PORT) == null)
return new NetworkStateMessage(NetworkState.ERROR, _t("ERR-UDP Disabled and Inbound TCP host/port not set"));
else
return new NetworkStateMessage(NetworkState.WARN, _t("WARN-Firewalled with UDP Disabled"));
}
return new NetworkStateMessage(state, _t(status.toStatusString()));
}
}
Aggregations