Search in sources :

Example 26 with RouterAddress

use of net.i2p.data.router.RouterAddress in project i2p.i2p by i2p.

the class UDPTransport method externalAddressReceived.

/**
 * Someone we tried to contact gave us what they think our IP address is.
 * Right now, we just blindly trust them, changing our IP and port on a
 * whim.  this is not good ;)
 *
 * Slight enhancement - require two different peers in a row to agree
 *
 * Todo:
 *   - Much better tracking of troublemakers
 *   - Disable if we have good local address or UPnP
 *   - This gets harder if and when we publish multiple addresses, or IPv6
 *
 * @param from Hash of inbound destination
 * @param ourIP publicly routable IPv4 only
 * @param ourPort >= 1024
 */
void externalAddressReceived(Hash from, byte[] ourIP, int ourPort) {
    boolean isValid = isValid(ourIP) && TransportUtil.isValidPort(ourPort);
    boolean explicitSpecified = explicitAddressSpecified();
    boolean inboundRecent = _lastInboundReceivedOn + ALLOW_IP_CHANGE_INTERVAL > System.currentTimeMillis();
    if (_log.shouldLog(Log.INFO))
        _log.info("External address received: " + Addresses.toString(ourIP, ourPort) + " from " + from + ", isValid? " + isValid + ", explicitSpecified? " + explicitSpecified + ", receivedInboundRecent? " + inboundRecent + " status " + _reachabilityStatus);
    if (ourIP.length != 4) {
        return;
    }
    if (explicitSpecified)
        return;
    String sources = _context.getProperty(PROP_SOURCES, DEFAULT_SOURCES);
    if (!sources.contains("ssu"))
        return;
    if (!isValid) {
        // ignore them
        if (_log.shouldLog(Log.ERROR))
            _log.error("The router " + from + " told us we have an invalid IP - " + Addresses.toString(ourIP, ourPort) + ".  Lets throw tomatoes at them");
        markUnreachable(from);
        // _context.banlist().banlistRouter(from, "They said we had an invalid IP", STYLE);
        return;
    }
    RouterAddress addr = getCurrentExternalAddress(false);
    if (inboundRecent && addr != null && addr.getPort() > 0 && addr.getHost() != null) {
        // leaving us thinking the second IP is still good.
        if (_log.shouldLog(Log.INFO))
            _log.info("Ignoring IP address suggestion, since we have received an inbound con recently");
    } else {
        // New IP
        boolean changeIt = false;
        synchronized (this) {
            if (from.equals(_lastFrom) || !eq(_lastOurIP, _lastOurPort, ourIP, ourPort)) {
                _lastFrom = from;
                _lastOurIP = ourIP;
                _lastOurPort = ourPort;
                if (_log.shouldLog(Log.INFO))
                    _log.info("The router " + from + " told us we have a new IP - " + Addresses.toString(ourIP, ourPort) + ".  Wait until somebody else tells us the same thing.");
            } else {
                _lastFrom = from;
                _lastOurIP = ourIP;
                _lastOurPort = ourPort;
                changeIt = true;
            }
        }
        if (changeIt) {
            if (_log.shouldLog(Log.INFO))
                _log.info(from + " and " + _lastFrom + " agree we have a new IP - " + Addresses.toString(ourIP, ourPort) + ".  Changing address.");
            changeAddress(ourIP, ourPort);
        }
    }
}
Also used : RouterAddress(net.i2p.data.router.RouterAddress)

Example 27 with RouterAddress

use of net.i2p.data.router.RouterAddress in project i2p.i2p by i2p.

the class UDPTransport method locked_needsRebuild.

private boolean locked_needsRebuild() {
    // simple enough
    if (_needsRebuild)
        return true;
    if (_context.router().isHidden())
        return false;
    boolean v6Only = getIPv6Config() == IPV6_ONLY;
    RouterAddress addr = getCurrentAddress(v6Only);
    if (!v6Only && introducersRequired()) {
        UDPAddress ua = new UDPAddress(addr);
        long now = _context.clock().now();
        int valid = 0;
        for (int i = 0; i < ua.getIntroducerCount(); i++) {
            // warning: this is only valid as long as we use the ident hash as their key.
            byte[] key = ua.getIntroducerKey(i);
            if (key.length != Hash.HASH_LENGTH)
                continue;
            long exp = ua.getIntroducerExpiration(i);
            if (exp > 0 && exp < now + INTRODUCER_EXPIRATION_MARGIN)
                continue;
            PeerState peer = getPeerState(new Hash(key));
            if (peer != null)
                valid++;
        }
        long sinceSelected = now - _introducersSelectedOn;
        if (valid >= PUBLIC_RELAY_COUNT) {
            // try to shift 'em around every 10 minutes or so
            if (sinceSelected > 17 * 60 * 1000) {
                if (_log.shouldLog(Log.WARN))
                    _log.warn("Our introducers are valid, but haven't changed in " + DataHelper.formatDuration(sinceSelected) + ", so lets rechoose");
                return true;
            } else {
                if (_log.shouldLog(Log.INFO))
                    _log.info("Our introducers are valid and were selected " + DataHelper.formatDuration(sinceSelected) + " ago");
                return false;
            }
        } else if (sinceSelected > 2 * 60 * 1000) {
            // Rate limit to prevent rapid churn after transition to firewalled or at startup
            if (_log.shouldLog(Log.INFO))
                _log.info("Need more introducers (have " + valid + " need " + PUBLIC_RELAY_COUNT + ')');
            return true;
        } else {
            if (_log.shouldLog(Log.INFO))
                _log.info("Need more introducers (have " + valid + " need " + PUBLIC_RELAY_COUNT + ')' + " but we just chose them " + DataHelper.formatDuration(sinceSelected) + " ago so wait");
            // TODO also check to see if we actually have more available
            return false;
        }
    } else {
        byte[] externalListenHost = addr != null ? addr.getIP() : null;
        int externalListenPort = addr != null ? addr.getPort() : -1;
        boolean rv = (externalListenHost == null) || (externalListenPort <= 0);
        if (!rv) {
            // shortcut to determine if introducers are present
            if (addr.getOption("ihost0") != null)
                // status == ok and we don't actually need introducers, so rebuild
                rv = true;
        }
        if (rv) {
            if (_log.shouldLog(Log.INFO))
                _log.info("Need to initialize our direct SSU info (" + Addresses.toString(externalListenHost, externalListenPort) + ')');
        } else if (addr.getPort() <= 0 || addr.getHost() == null) {
            if (_log.shouldLog(Log.INFO))
                _log.info("Our direct SSU info is initialized, but not used in our address yet");
            rv = true;
        } else {
        // _log.info("Our direct SSU info is initialized");
        }
        return rv;
    }
}
Also used : RouterAddress(net.i2p.data.router.RouterAddress) Hash(net.i2p.data.Hash)

Example 28 with RouterAddress

use of net.i2p.data.router.RouterAddress in project i2p.i2p by i2p.

the class UDPTransport method changeAddress.

/**
 * Possibly change our external address to the IP/port.
 * IP/port are already validated, but not yet compared to current IP/port.
 * We compare here.
 *
 * @param ourIP MUST have been previously validated with isValid()
 *              IPv4 or IPv6 OK
 * @param ourPort &gt;= 1024 or 0 for no change
 */
private boolean changeAddress(byte[] ourIP, int ourPort) {
    // this defaults to true when we are firewalled and false otherwise.
    boolean fixedPort = getIsPortFixed();
    boolean updated = false;
    boolean fireTest = false;
    boolean isIPv6 = ourIP.length == 16;
    RouterAddress current = getCurrentExternalAddress(isIPv6);
    byte[] externalListenHost = current != null ? current.getIP() : null;
    int externalListenPort = current != null ? current.getPort() : getRequestedPort(isIPv6);
    if (_log.shouldLog(Log.INFO))
        _log.info("Change address? status = " + _reachabilityStatus + " diff = " + (_context.clock().now() - _reachabilityStatusLastUpdated) + " old = " + Addresses.toString(externalListenHost, externalListenPort) + " new = " + Addresses.toString(ourIP, ourPort));
    if ((fixedPort && externalListenPort > 0) || ourPort <= 0)
        ourPort = externalListenPort;
    synchronized (this) {
        if (ourPort > 0 && !eq(externalListenHost, externalListenPort, ourIP, ourPort)) {
            // they told us something different and our tests are either old or failing
            if (_log.shouldLog(Log.WARN))
                _log.warn("Trying to change our external address to " + Addresses.toString(ourIP, ourPort));
            RouterAddress newAddr = rebuildExternalAddress(ourIP, ourPort, true);
            updated = newAddr != null;
        // } else {
        // // they told us something different, but our tests are recent and positive,
        // // so lets test again
        // fireTest = true;
        // if (_log.shouldLog(Log.WARN))
        // _log.warn("Different address, but we're fine.. (" + _reachabilityStatus + ")");
        // }
        } else {
            // matched what we expect
            if (_log.shouldLog(Log.INFO))
                _log.info("Same address as the current one");
        }
    }
    if (fireTest) {
        // always false, commented out above
        _context.statManager().addRateData("udp.addressTestInsteadOfUpdate", 1);
        _testEvent.forceRunImmediately(isIPv6);
    } else if (updated) {
        _context.statManager().addRateData("udp.addressUpdated", 1);
        Map<String, String> changes = new HashMap<String, String>();
        if (ourIP.length == 4 && !fixedPort)
            changes.put(PROP_EXTERNAL_PORT, Integer.toString(ourPort));
        // queue a country code lookup of the new IP
        if (ourIP.length == 4)
            _context.commSystem().queueLookup(ourIP);
        // store these for laptop-mode (change ident on restart... or every time... when IP changes)
        // IPV4 ONLY
        String oldIP = _context.getProperty(PROP_IP);
        String newIP = Addresses.toString(ourIP);
        if (ourIP.length == 4 && !newIP.equals(oldIP)) {
            long lastChanged = 0;
            long now = _context.clock().now();
            String lcs = _context.getProperty(PROP_IP_CHANGE);
            if (lcs != null) {
                try {
                    lastChanged = Long.parseLong(lcs);
                } catch (NumberFormatException nfe) {
                }
            }
            changes.put(PROP_IP, newIP);
            changes.put(PROP_IP_CHANGE, Long.toString(now));
            _context.router().saveConfig(changes, null);
            if (oldIP != null) {
                _context.router().eventLog().addEvent(EventLog.CHANGE_IP, newIP);
            }
            // For now, only do this at startup
            if (oldIP != null && System.getProperty("wrapper.version") != null && _context.getBooleanProperty(PROP_LAPTOP_MODE) && now - lastChanged > 10 * 60 * 1000 && _context.router().getUptime() < 10 * 60 * 1000) {
                System.out.println("WARN: IP changed, restarting with a new identity and port");
                _log.logAlways(Log.WARN, "IP changed, restarting with a new identity and port");
                // this removes the UDP port config
                _context.router().killKeys();
                // do we need WrapperManager.signalStopped() like in ConfigServiceHandler ???
                // without it, the wrapper complains "shutdown unexpectedly"
                // but we can't have that dependency in the router
                _context.router().shutdown(Router.EXIT_HARD_RESTART);
            // doesn't return
            }
        } else if (ourIP.length == 4 && !fixedPort) {
            // save PROP_EXTERNAL_PORT
            _context.router().saveConfig(changes, null);
        }
        // deadlock thru here ticket #1699
        _context.router().rebuildRouterInfo();
        _testEvent.forceRunImmediately(isIPv6);
    }
    return updated;
}
Also used : RouterAddress(net.i2p.data.router.RouterAddress) Map(java.util.Map) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashMap(java.util.HashMap)

Example 29 with RouterAddress

use of net.i2p.data.router.RouterAddress in project i2p.i2p by i2p.

the class UDPTransport method rebuildExternalAddress.

/**
 *  Update our IPv4 address and optionally tell the router to rebuild and republish the router info.
 *
 *  If PROP_EXTERNAL_HOST is set, use those addresses (comma/space separated).
 *  If a hostname is configured in that property, use it.
 *  As of 0.9.32, a hostname is resolved here into one or more addresses
 *  and the IPs are published, to implement proposal 141.
 *
 *  A max of one v4 and one v6 address will be set. Significant changes both
 *  here and in NTCP would be required to publish multiple v4 or v6 addresses.
 *
 *  @param allowRebuildRouterInfo whether to tell the router
 *  @return the new address if changed, else null
 */
private RouterAddress rebuildExternalAddress(boolean allowRebuildRouterInfo) {
    if (_log.shouldDebug())
        _log.debug("REA2 " + allowRebuildRouterInfo);
    // if the external port is specified, we want to use that to bind to even
    // if we don't know the external host.
    int port = _context.getProperty(PROP_EXTERNAL_PORT, -1);
    String host = null;
    if (explicitAddressSpecified()) {
        host = _context.getProperty(PROP_EXTERNAL_HOST);
        if (host != null) {
            String[] hosts = DataHelper.split(host, "[,; \r\n\t]");
            RouterAddress rv = null;
            // we only take one each of v4 and v6
            boolean v4 = false;
            boolean v6 = false;
            // prevent adding a type if disabled
            TransportUtil.IPv6Config cfg = getIPv6Config();
            if (cfg == IPV6_DISABLED)
                v6 = true;
            else if (cfg == IPV6_ONLY)
                v4 = true;
            for (int i = 0; i < hosts.length; i++) {
                String h = hosts[i];
                if (h.length() <= 0)
                    continue;
                if (Addresses.isIPv4Address(h)) {
                    if (v4)
                        continue;
                    v4 = true;
                } else if (Addresses.isIPv6Address(h)) {
                    if (v6)
                        continue;
                    v6 = true;
                } else {
                    int valid = 0;
                    List<byte[]> ips = Addresses.getIPs(h);
                    if (ips != null) {
                        for (byte[] ip : ips) {
                            if (!isValid(ip)) {
                                if (_log.shouldWarn())
                                    _log.warn("REA2: skipping invalid " + Addresses.toString(ip) + " for " + h);
                                continue;
                            }
                            if ((v4 && ip.length == 4) || (v6 && ip.length == 16)) {
                                if (_log.shouldWarn())
                                    _log.warn("REA2: skipping additional " + Addresses.toString(ip) + " for " + h);
                                continue;
                            }
                            if (ip.length == 4)
                                v4 = true;
                            else if (ip.length == 16)
                                v6 = true;
                            valid++;
                            if (_log.shouldDebug())
                                _log.debug("REA2: adding " + Addresses.toString(ip) + " for " + h);
                            RouterAddress trv = rebuildExternalAddress(ip, port, allowRebuildRouterInfo);
                            if (trv != null)
                                rv = trv;
                        }
                    }
                    if (valid == 0)
                        _log.error("No valid IPs for configured hostname " + h);
                    continue;
                }
                RouterAddress trv = rebuildExternalAddress(h, port, allowRebuildRouterInfo);
                if (trv != null)
                    rv = trv;
            }
            return rv;
        }
    } else {
        if (!introducersRequired()) {
            boolean v6Only = getIPv6Config() == IPV6_ONLY;
            RouterAddress cur = getCurrentExternalAddress(v6Only);
            if (cur != null)
                host = cur.getHost();
        }
    }
    return rebuildExternalAddress(host, port, allowRebuildRouterInfo);
}
Also used : IPv6Config(net.i2p.router.transport.TransportUtil.IPv6Config) TransportUtil(net.i2p.router.transport.TransportUtil) RouterAddress(net.i2p.data.router.RouterAddress) List(java.util.List) CopyOnWriteArrayList(java.util.concurrent.CopyOnWriteArrayList) ArrayList(java.util.ArrayList)

Example 30 with RouterAddress

use of net.i2p.data.router.RouterAddress in project i2p.i2p by i2p.

the class ConnectChecker method getConnectMask.

/**
 *  @param addrs non-empty, set your own default if empty
 *  @return bitmask of v4/v6 NTCP/SSU
 *  @since 0.9.34
 */
private static int getConnectMask(Collection<RouterAddress> addrs) {
    int rv = 0;
    for (RouterAddress ra : addrs) {
        String style = ra.getTransportStyle();
        String host = ra.getHost();
        if ("NTCP".equals(style)) {
            if (host != null) {
                if (host.contains(":"))
                    rv |= NTCP_V6;
                else
                    rv |= NTCP_V4;
            }
        } else if ("SSU".equals(style)) {
            if (host == null) {
                for (int i = 0; i < 2; i++) {
                    String ihost = ra.getOption(IHOST[i]);
                    if (ihost == null)
                        break;
                    if (ihost.contains(":"))
                        rv |= SSU_V6;
                    else
                        rv |= SSU_V4;
                }
            } else if (host.contains(":")) {
                rv |= SSU_V6;
            } else {
                rv |= SSU_V4;
            }
        }
    }
    return rv;
}
Also used : RouterAddress(net.i2p.data.router.RouterAddress)

Aggregations

RouterAddress (net.i2p.data.router.RouterAddress)42 RouterInfo (net.i2p.data.router.RouterInfo)17 Hash (net.i2p.data.Hash)11 IOException (java.io.IOException)9 ArrayList (java.util.ArrayList)9 OrderedProperties (net.i2p.util.OrderedProperties)6 InetAddress (java.net.InetAddress)5 Map (java.util.Map)5 RouterIdentity (net.i2p.data.router.RouterIdentity)5 UnknownHostException (java.net.UnknownHostException)4 HashMap (java.util.HashMap)4 DataFormatException (net.i2p.data.DataFormatException)4 ServerSocketChannel (java.nio.channels.ServerSocketChannel)3 Date (java.util.Date)3 Status (net.i2p.router.CommSystemFacade.Status)3 OutNetMessage (net.i2p.router.OutNetMessage)3 File (java.io.File)2 InetSocketAddress (java.net.InetSocketAddress)2 Properties (java.util.Properties)2 CopyOnWriteArrayList (java.util.concurrent.CopyOnWriteArrayList)2