use of net.i2p.data.router.RouterAddress in project i2p.i2p by i2p.
the class Blocklist method getAddresses.
/**
* Will not contain duplicates.
* @since 0.9.29
*/
private static List<byte[]> getAddresses(RouterInfo pinfo) {
List<byte[]> rv = new ArrayList<byte[]>(4);
// for each peer address
for (RouterAddress pa : pinfo.getAddresses()) {
byte[] pib = pa.getIP();
if (pib == null)
continue;
// O(n**2)
boolean dup = false;
for (int i = 0; i < rv.size(); i++) {
if (DataHelper.eq(rv.get(i), pib)) {
dup = true;
break;
}
}
if (!dup)
rv.add(pib);
}
return rv;
}
use of net.i2p.data.router.RouterAddress in project i2p.i2p by i2p.
the class BundleRouterInfos method main.
/**
* Usage: PersistentDataStore -i configDir -o toDir -c count
*
* Copy a random selection of 'count' router infos from configDir/netDb
* to 'toDir'. Skip your own router info, and old, hidden, unreachable, and
* introduced routers, and those from bad countries.
*
* @since 0.9.15
*/
public static void main(String[] args) {
Getopt g = new Getopt("PersistentDataStore", args, "i:o:c:");
String in = System.getProperty("user.home") + "/.i2p";
String out = "netDb";
int count = 200;
boolean error = false;
int c;
while ((c = g.getopt()) != -1) {
switch(c) {
case 'i':
in = g.getOptarg();
break;
case 'o':
out = g.getOptarg();
break;
case 'c':
String scount = g.getOptarg();
try {
count = Integer.parseInt(scount);
} catch (NumberFormatException nfe) {
error = true;
}
break;
case '?':
case ':':
default:
error = true;
}
}
if (error) {
usage();
System.exit(1);
}
Properties props = new Properties();
props.setProperty(GeoIP.PROP_GEOIP_DIR, System.getProperty("user.dir") + "/installer/resources");
GeoIP geoIP = new GeoIP(new I2PAppContext(props));
File confDir = new File(in);
File dbDir = new File(confDir, "netDb");
if (!dbDir.exists()) {
System.out.println("NetDB directory " + dbDir + " does not exist");
System.exit(1);
}
File myFile = new File(confDir, "router.info");
File toDir = new File(out);
toDir.mkdirs();
InputStream fis = null;
Hash me = null;
try {
fis = new BufferedInputStream(new FileInputStream(myFile));
RouterInfo ri = new RouterInfo();
// true = verify sig on read
ri.readBytes(fis, true);
me = ri.getIdentity().getHash();
} catch (IOException e) {
// System.out.println("Can't determine our identity");
} catch (DataFormatException e) {
// System.out.println("Can't determine our identity");
} finally {
if (fis != null)
try {
fis.close();
} catch (IOException ioe) {
}
}
int routerCount = 0;
List<File> toRead = new ArrayList<File>(2048);
for (int j = 0; j < Base64.ALPHABET_I2P.length(); j++) {
File subdir = new File(dbDir, PersistentDataStore.DIR_PREFIX + Base64.ALPHABET_I2P.charAt(j));
File[] files = subdir.listFiles(PersistentDataStore.RI_FILTER);
if (files == null)
continue;
routerCount += files.length;
for (int i = 0; i < files.length; i++) {
toRead.add(files[i]);
}
}
if (toRead.isEmpty()) {
System.out.println("No files to copy in " + dbDir);
System.exit(1);
}
Collections.shuffle(toRead);
int copied = 0;
long tooOld = System.currentTimeMillis() - 7 * 24 * 60 * 60 * 1000L;
Map<String, String> ipMap = new HashMap<String, String>(count);
for (File file : toRead) {
if (copied >= count)
break;
Hash key = PersistentDataStore.getRouterInfoHash(file.getName());
if (key == null) {
System.out.println("Skipping bad " + file);
continue;
}
if (key.equals(me)) {
System.out.println("Skipping my RI");
continue;
}
fis = null;
try {
fis = new BufferedInputStream(new FileInputStream(file));
RouterInfo ri = new RouterInfo();
// true = verify sig on read
ri.readBytes(fis, true);
try {
fis.close();
} catch (IOException ioe) {
}
fis = null;
if (ri.getPublished() < tooOld) {
System.out.println("Skipping too old " + key);
continue;
}
if (ri.getCapabilities().contains("U")) {
System.out.println("Skipping unreachable " + key);
continue;
}
if (ri.getCapabilities().contains("K")) {
System.out.println("Skipping slow " + key);
continue;
}
Collection<RouterAddress> addrs = ri.getAddresses();
if (addrs.isEmpty()) {
System.out.println("Skipping hidden " + key);
continue;
}
boolean hasIntro = false;
boolean hasIPv4 = false;
boolean dupIP = false;
for (RouterAddress addr : addrs) {
if ("SSU".equals(addr.getTransportStyle()) && addr.getOption("ihost0") != null) {
hasIntro = true;
break;
}
String host = addr.getHost();
if (host != null && host.contains(".")) {
hasIPv4 = true;
geoIP.add(host);
String old = ipMap.put(host, file.getName());
if (old != null && !old.equals(file.getName())) {
dupIP = true;
break;
}
}
}
if (dupIP) {
System.out.println("Skipping dup IP " + key);
continue;
}
if (hasIntro) {
System.out.println("Skipping introduced " + key);
continue;
}
if (!hasIPv4) {
System.out.println("Skipping IPv6-only " + key);
continue;
}
File toFile = new File(toDir, file.getName());
// We could call ri.write() to avoid simultaneous change by the router
boolean ok = FileUtil.copy(file, toFile, true, true);
if (ok)
copied++;
else
System.out.println("Failed copy of " + file + " to " + toDir);
} catch (IOException e) {
System.out.println("Skipping bad " + file);
} catch (DataFormatException e) {
System.out.println("Skipping bad " + file);
} finally {
if (fis != null)
try {
fis.close();
} catch (IOException ioe) {
}
}
}
if (copied > 0) {
// now do all the geoip lookups, and delete any bad countries
geoIP.blockingLookup();
for (Map.Entry<String, String> e : ipMap.entrySet()) {
String co = geoIP.get(e.getKey());
if (co != null) {
if (BadCountries.contains(co)) {
String name = e.getValue();
File toFile = new File(toDir, name);
if (toFile.delete()) {
String full = geoIP.fullName(co);
if (full == null)
full = co;
System.out.println("Skipping " + full + ": " + name);
copied--;
}
}
}
}
}
if (copied > 0) {
System.out.println("Copied " + copied + " router info files to " + toDir);
} else {
System.out.println("Failed to copy any files to " + toDir);
System.exit(1);
}
}
use of net.i2p.data.router.RouterAddress in project i2p.i2p by i2p.
the class NTCPTransport method outboundMessageReady.
protected void outboundMessageReady() {
OutNetMessage msg = getNextMessage();
if (msg != null) {
RouterInfo target = msg.getTarget();
RouterIdentity ident = target.getIdentity();
Hash ih = ident.calculateHash();
NTCPConnection con = null;
boolean isNew = false;
boolean fail = false;
synchronized (_conLock) {
con = _conByIdent.get(ih);
if (con == null) {
isNew = true;
RouterAddress addr = getTargetAddress(target);
if (addr != null) {
con = new NTCPConnection(_context, this, ident, addr);
// if (_log.shouldLog(Log.DEBUG))
// _log.debug("Send on a new con: " + con + " at " + addr + " for " + ih);
// Note that outbound conns go in the map BEFORE establishment
_conByIdent.put(ih, con);
} else {
// race, RI changed out from under us
// call afterSend below outside of conLock
fail = true;
}
}
}
if (fail) {
// race, RI changed out from under us, maybe SSU can handle it
if (_log.shouldLog(Log.WARN))
_log.warn("we bid on a peer who doesn't have an ntcp address? " + target);
afterSend(msg, false);
return;
}
if (isNew) {
// doesn't do anything yet, just enqueues it
con.send(msg);
// As of 0.9.12, don't send our info if the first message is
// doing the same (common when connecting to a floodfill).
// Also, put the info message after whatever we are trying to send
// (it's a priority queue anyway and the info is low priority)
// Prior to 0.9.12, Bob would not send his RI unless he had ours,
// but that's fixed in 0.9.12.
boolean shouldSkipInfo = false;
I2NPMessage m = msg.getMessage();
if (m.getType() == DatabaseStoreMessage.MESSAGE_TYPE) {
DatabaseStoreMessage dsm = (DatabaseStoreMessage) m;
if (dsm.getKey().equals(_context.routerHash())) {
shouldSkipInfo = true;
}
}
if (!shouldSkipInfo) {
con.enqueueInfoMessage();
} else if (_log.shouldLog(Log.INFO)) {
_log.info("SKIPPING INFO message: " + con);
}
try {
SocketChannel channel = SocketChannel.open();
con.setChannel(channel);
channel.configureBlocking(false);
_pumper.registerConnect(con);
con.getEstablishState().prepareOutbound();
} catch (IOException ioe) {
if (_log.shouldLog(Log.ERROR))
_log.error("Error opening a channel", ioe);
_context.statManager().addRateData("ntcp.outboundFailedIOEImmediate", 1);
con.close();
}
} else {
con.send(msg);
}
/*
NTCPConnection con = getCon(ident);
remove the race here
if (con != null) {
//if (_log.shouldLog(Log.DEBUG))
// _log.debug("Send on an existing con: " + con);
con.send(msg);
} else {
RouterAddress addr = msg.getTarget().getTargetAddress(STYLE);
if (addr != null) {
NTCPAddress naddr = new NTCPAddress(addr);
con = new NTCPConnection(_context, this, ident, naddr);
Hash ih = ident.calculateHash();
if (_log.shouldLog(Log.DEBUG))
_log.debug("Send on a new con: " + con + " at " + addr + " for " + ih.toBase64());
NTCPConnection old = null;
synchronized (_conLock) {
old = (NTCPConnection)_conByIdent.put(ih, con);
}
if (old != null) {
if (_log.shouldLog(Log.WARN))
_log.warn("Multiple connections on out ready, closing " + old + " and keeping " + con);
old.close();
}
con.enqueueInfoMessage(); // enqueues a netDb store of our own info
con.send(msg); // doesn't do anything yet, just enqueues it
try {
SocketChannel channel = SocketChannel.open();
con.setChannel(channel);
channel.configureBlocking(false);
_pumper.registerConnect(con);
} catch (IOException ioe) {
if (_log.shouldLog(Log.ERROR))
_log.error("Error opening a channel", ioe);
con.close();
}
} else {
con.close();
}
}
*/
}
}
use of net.i2p.data.router.RouterAddress in project i2p.i2p by i2p.
the class NTCPTransport method getTargetAddress.
/**
* Get first available address we can use.
* @return address or null
* @since 0.9.6
*/
private RouterAddress getTargetAddress(RouterInfo target) {
List<RouterAddress> addrs = getTargetAddresses(target);
for (int i = 0; i < addrs.size(); i++) {
RouterAddress addr = addrs.get(i);
byte[] ip = addr.getIP();
if (!TransportUtil.isValidPort(addr.getPort()) || ip == null) {
// _log.debug("no bid when trying to send to " + peer + " as they don't have a valid ntcp address");
continue;
}
if (!isValid(ip)) {
if (!allowLocal()) {
// _log.debug("no bid when trying to send to " + peer + " as they have a private ntcp address");
continue;
}
}
return addr;
}
return null;
}
use of net.i2p.data.router.RouterAddress in project i2p.i2p by i2p.
the class NTCPTransport method externalAddressReceived.
/**
* UDP changed addresses, tell NTCP and restart.
* Port may be set to indicate requested port even if ip is null.
*
* @param ip previously validated; may be null to indicate IPv4 failure or port info only
* @since IPv6 moved from CSFI.notifyReplaceAddress()
*/
private synchronized void externalAddressReceived(byte[] ip, boolean isIPv6, int port) {
// FIXME just take first address for now
// FIXME if SSU set to hostname, NTCP will be set to IP
RouterAddress oldAddr = getCurrentAddress(isIPv6);
if (_log.shouldLog(Log.INFO))
_log.info("Changing NTCP Address? was " + oldAddr);
OrderedProperties newProps = new OrderedProperties();
int cost;
if (oldAddr == null) {
cost = getDefaultCost(isIPv6);
} else {
cost = oldAddr.getCost();
newProps.putAll(oldAddr.getOptionsMap());
}
RouterAddress newAddr = new RouterAddress(STYLE, newProps, cost);
boolean changed = false;
// Auto Port Setting
// old behavior (<= 0.7.3): auto-port defaults to false, and true trumps explicit setting
// new behavior (>= 0.7.4): auto-port defaults to true, but explicit setting trumps auto
// TODO rewrite this to operate on ints instead of strings
String oport = newProps.getProperty(RouterAddress.PROP_PORT);
String nport = null;
String cport = _context.getProperty(PROP_I2NP_NTCP_PORT);
if (cport != null && cport.length() > 0) {
nport = cport;
} else if (_context.getBooleanPropertyDefaultTrue(PROP_I2NP_NTCP_AUTO_PORT)) {
// it probably isn't mapping UDP and TCP the same.
if (port > 0)
// should always be true
nport = Integer.toString(port);
}
if (_log.shouldLog(Log.INFO))
_log.info("old port: " + oport + " config: " + cport + " new: " + nport);
// if (oport == null || ! oport.equals(nport)) {
if (oport == null && nport != null && nport.length() > 0) {
newProps.setProperty(RouterAddress.PROP_PORT, nport);
changed = true;
}
// Auto IP Setting
// old behavior (<= 0.7.3): auto-ip defaults to false, and trumps configured hostname,
// and ignores reachability status - leading to
// "firewalled with inbound TCP enabled" warnings.
// new behavior (>= 0.7.4): auto-ip defaults to true, and explicit setting trumps auto,
// and only takes effect if reachability is OK.
// And new "always" setting ignores reachability status, like
// "true" was in 0.7.3
String ohost = newProps.getProperty(RouterAddress.PROP_HOST);
String enabled = _context.getProperty(PROP_I2NP_NTCP_AUTO_IP, "true").toLowerCase(Locale.US);
String name = getConfiguredIP();
// hostname config trumps auto config
if (name != null && name.length() > 0)
enabled = "false";
// assume SSU is happy if the address is non-null
// TODO is this sufficient?
boolean ssuOK = ip != null;
if (_log.shouldLog(Log.INFO))
_log.info("old: " + ohost + " config: " + name + " auto: " + enabled + " ssuOK? " + ssuOK);
if (enabled.equals("always") || (Boolean.parseBoolean(enabled) && ssuOK)) {
if (!ssuOK) {
if (_log.shouldLog(Log.WARN))
_log.warn("null address with always config", new Exception());
return;
}
// ip non-null
String nhost = Addresses.toString(ip);
if (_log.shouldLog(Log.INFO))
_log.info("old: " + ohost + " config: " + name + " new: " + nhost);
if (nhost == null || nhost.length() <= 0)
return;
if (ohost == null || !ohost.equalsIgnoreCase(nhost)) {
newProps.setProperty(RouterAddress.PROP_HOST, nhost);
changed = true;
}
} else if (enabled.equals("false") && name != null && name.length() > 0 && !name.equals(ohost)) {
// otherwise createNTCPAddress() would have done it already
if (_log.shouldLog(Log.INFO))
_log.info("old host: " + ohost + " config: " + name + " new: " + name);
newProps.setProperty(RouterAddress.PROP_HOST, name);
changed = true;
} else if (ohost == null || ohost.length() <= 0) {
return;
} else if (Boolean.parseBoolean(enabled) && !ssuOK) {
// we are still firewalled (SW firewall, bad UPnP indication, etc.)
if (_log.shouldLog(Log.INFO))
_log.info("old host: " + ohost + " config: " + name + " new: null");
newAddr = null;
changed = true;
}
if (!changed) {
if (oldAddr != null) {
// change cost only?
int oldCost = oldAddr.getCost();
int newCost = getDefaultCost(ohost != null && ohost.contains(":"));
if (ADJUST_COST && !haveCapacity())
newCost += CONGESTION_COST_ADJUSTMENT;
if (newCost != oldCost) {
newAddr.setCost(newCost);
if (_log.shouldLog(Log.WARN))
_log.warn("Changing NTCP cost from " + oldCost + " to " + newCost);
// fall thru and republish
} else {
_log.info("No change to NTCP Address");
return;
}
} else {
_log.info("No change to NTCP Address");
return;
}
}
// stopListening stops the pumper, readers, and writers, so required even if
// oldAddr == null since startListening starts them all again
//
// really need to fix this so that we can change or create an inbound address
// without tearing down everything
// Especially on disabling the address, we shouldn't tear everything down.
//
// if (_log.shouldLog(Log.WARN))
// _log.warn("Halting NTCP to change address");
// stopListening();
// Wait for NTCP Pumper to stop so we don't end up with two...
// while (isAlive()) {
// try { Thread.sleep(5*1000); } catch (InterruptedException ie) {}
// }
restartListening(newAddr, isIPv6);
if (_log.shouldLog(Log.WARN))
_log.warn("Updating NTCP Address (ipv6? " + isIPv6 + ") with " + newAddr);
return;
}
Aggregations