forked from I2P_Developers/i2p.i2p
* NTCP:
Move SSU address notification handling from CSFI to NTCPTransport
This commit is contained in:
@ -194,249 +194,26 @@ public class CommSystemFacadeImpl extends CommSystemFacade {
|
|||||||
//if (_context.router().isHidden())
|
//if (_context.router().isHidden())
|
||||||
// return Collections.EMPTY_SET;
|
// return Collections.EMPTY_SET;
|
||||||
List<RouterAddress> addresses = new ArrayList(_manager.getAddresses());
|
List<RouterAddress> addresses = new ArrayList(_manager.getAddresses());
|
||||||
|
|
||||||
Transport ntcp = _manager.getTransport(NTCPTransport.STYLE);
|
|
||||||
boolean hasNTCP = ntcp != null && ntcp.hasCurrentAddress();
|
|
||||||
|
|
||||||
boolean newCreated = false;
|
|
||||||
if (!hasNTCP) {
|
|
||||||
RouterAddress addr = createNTCPAddress(_context);
|
|
||||||
if (_log.shouldLog(Log.INFO))
|
|
||||||
_log.info("NTCP address: " + addr);
|
|
||||||
if (addr != null) {
|
|
||||||
addresses.add(addr);
|
|
||||||
newCreated = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_log.shouldLog(Log.INFO))
|
if (_log.shouldLog(Log.INFO))
|
||||||
_log.info("Creating addresses: " + addresses + " isNew? " + newCreated, new Exception("creator"));
|
_log.info("Creating addresses: " + addresses, new Exception("creator"));
|
||||||
return addresses;
|
return addresses;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final static String PROP_I2NP_NTCP_HOSTNAME = "i2np.ntcp.hostname";
|
|
||||||
public final static String PROP_I2NP_NTCP_PORT = "i2np.ntcp.port";
|
|
||||||
public final static String PROP_I2NP_NTCP_AUTO_PORT = "i2np.ntcp.autoport";
|
|
||||||
public final static String PROP_I2NP_NTCP_AUTO_IP = "i2np.ntcp.autoip";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This only creates an address if the hostname AND port are set in router.config,
|
|
||||||
* which should be rare.
|
|
||||||
* Otherwise, notifyReplaceAddress() below takes care of it.
|
|
||||||
* Note this is called both from above and from NTCPTransport.startListening()
|
|
||||||
*
|
|
||||||
* This should really be moved to ntcp/NTCPTransport.java, why is it here?
|
|
||||||
*/
|
|
||||||
public static RouterAddress createNTCPAddress(RouterContext ctx) {
|
|
||||||
if (!TransportManager.isNTCPEnabled(ctx)) return null;
|
|
||||||
String name = ctx.router().getConfigSetting(PROP_I2NP_NTCP_HOSTNAME);
|
|
||||||
String port = ctx.router().getConfigSetting(PROP_I2NP_NTCP_PORT);
|
|
||||||
/*
|
|
||||||
boolean isNew = false;
|
|
||||||
if (name == null) {
|
|
||||||
name = "localhost";
|
|
||||||
isNew = true;
|
|
||||||
}
|
|
||||||
if (port == null) {
|
|
||||||
port = String.valueOf(ctx.random().nextInt(10240)+1024);
|
|
||||||
isNew = true;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
if ( (name == null) || (port == null) || (name.trim().length() <= 0) || ("null".equals(name)) )
|
|
||||||
return null;
|
|
||||||
try {
|
|
||||||
int p = Integer.parseInt(port);
|
|
||||||
if ( (p <= 0) || (p > 64*1024) )
|
|
||||||
return null;
|
|
||||||
} catch (NumberFormatException nfe) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
Properties props = new Properties();
|
|
||||||
props.setProperty(NTCPAddress.PROP_HOST, name);
|
|
||||||
props.setProperty(NTCPAddress.PROP_PORT, port);
|
|
||||||
RouterAddress addr = new RouterAddress();
|
|
||||||
addr.setCost(NTCPAddress.DEFAULT_COST);
|
|
||||||
//addr.setExpiration(null);
|
|
||||||
addr.setOptions(props);
|
|
||||||
addr.setTransportStyle(NTCPTransport.STYLE);
|
|
||||||
//if (isNew) {
|
|
||||||
// why save the same thing?
|
|
||||||
Map<String, String> changes = new HashMap();
|
|
||||||
changes.put(PROP_I2NP_NTCP_HOSTNAME, name);
|
|
||||||
changes.put(PROP_I2NP_NTCP_PORT, port);
|
|
||||||
ctx.router().saveConfig(changes, null);
|
|
||||||
//}
|
|
||||||
return addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* UDP changed addresses, tell NTCP and restart
|
* UDP changed addresses, tell NTCP and restart
|
||||||
* This should really be moved to ntcp/NTCPTransport.java, why is it here?
|
*
|
||||||
|
* All the work moved to NTCPTransport.externalAddressReceived()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public synchronized void notifyReplaceAddress(RouterAddress udpAddr) {
|
public void notifyReplaceAddress(RouterAddress udpAddr) {
|
||||||
if (udpAddr == null)
|
byte[] ip = udpAddr != null ? udpAddr.getIP() : null;
|
||||||
return;
|
int port = udpAddr != null ? udpAddr.getPort() : 0;
|
||||||
NTCPTransport t = (NTCPTransport) _manager.getTransport(NTCPTransport.STYLE);
|
if (port < 0) {
|
||||||
if (t == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
//////// FIXME just take first IPv4 address for now
|
|
||||||
List<RouterAddress> oldAddrs = t.getCurrentAddresses();
|
|
||||||
RouterAddress oldAddr = null;
|
|
||||||
for (RouterAddress ra : oldAddrs) {
|
|
||||||
byte[] ipx = ra.getIP();
|
|
||||||
if (ipx != null && ipx.length == 4) {
|
|
||||||
oldAddr = ra;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (_log.shouldLog(Log.INFO))
|
|
||||||
_log.info("Changing NTCP Address? was " + oldAddr);
|
|
||||||
|
|
||||||
RouterAddress newAddr = new RouterAddress();
|
|
||||||
newAddr.setTransportStyle(NTCPTransport.STYLE);
|
|
||||||
Properties newProps = new Properties();
|
|
||||||
if (oldAddr == null) {
|
|
||||||
newAddr.setCost(NTCPAddress.DEFAULT_COST);
|
|
||||||
} else {
|
|
||||||
newAddr.setCost(oldAddr.getCost());
|
|
||||||
newProps.putAll(oldAddr.getOptionsMap());
|
|
||||||
}
|
|
||||||
|
|
||||||
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(NTCPAddress.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)) {
|
|
||||||
// 0.9.6 change
|
|
||||||
// This wasn't quite right, as udpAddr is the EXTERNAL port and we really
|
|
||||||
// want NTCP to bind to the INTERNAL port the first time,
|
|
||||||
// because if they are different, the NAT is changing them, and
|
|
||||||
// it probably isn't mapping UDP and TCP the same.
|
|
||||||
Transport udp = _manager.getTransport(UDPTransport.STYLE);
|
Transport udp = _manager.getTransport(UDPTransport.STYLE);
|
||||||
if (udp != null) {
|
if (udp != null)
|
||||||
int udpIntPort = udp.getRequestedPort();
|
port = udp.getRequestedPort();
|
||||||
if (udpIntPort > 0)
|
|
||||||
// should always be true
|
|
||||||
nport = Integer.toString(udpIntPort);
|
|
||||||
}
|
|
||||||
if (nport == null)
|
|
||||||
// fallback
|
|
||||||
nport = udpAddr.getOption(UDPAddress.PROP_PORT);
|
|
||||||
}
|
}
|
||||||
if (_log.shouldLog(Log.INFO))
|
_manager.externalAddressReceived(Transport.AddressSource.SOURCE_SSU, ip, port);
|
||||||
_log.info("old: " + oport + " config: " + cport + " new: " + nport);
|
|
||||||
if (nport == null || nport.length() <= 0)
|
|
||||||
return;
|
|
||||||
// 0.9.6 change
|
|
||||||
// Don't have NTCP "chase" SSU's external port,
|
|
||||||
// as it may change, possibly frequently.
|
|
||||||
//if (oport == null || ! oport.equals(nport)) {
|
|
||||||
if (oport == null) {
|
|
||||||
newProps.setProperty(NTCPAddress.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(NTCPAddress.PROP_HOST);
|
|
||||||
String enabled = _context.getProperty(PROP_I2NP_NTCP_AUTO_IP, "true").toLowerCase(Locale.US);
|
|
||||||
String name = _context.getProperty(PROP_I2NP_NTCP_HOSTNAME);
|
|
||||||
// hostname config trumps auto config
|
|
||||||
if (name != null && name.length() > 0)
|
|
||||||
enabled = "false";
|
|
||||||
Transport udp = _manager.getTransport(UDPTransport.STYLE);
|
|
||||||
short status = STATUS_UNKNOWN;
|
|
||||||
if (udp != null)
|
|
||||||
status = udp.getReachabilityStatus();
|
|
||||||
if (_log.shouldLog(Log.INFO))
|
|
||||||
_log.info("old: " + ohost + " config: " + name + " auto: " + enabled + " status: " + status);
|
|
||||||
if (enabled.equals("always") ||
|
|
||||||
(Boolean.parseBoolean(enabled) && status == STATUS_OK)) {
|
|
||||||
String nhost = udpAddr.getOption(UDPAddress.PROP_HOST);
|
|
||||||
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(NTCPAddress.PROP_HOST, nhost);
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
} else if (enabled.equals("false") &&
|
|
||||||
name != null && name.length() > 0 &&
|
|
||||||
!name.equals(ohost) &&
|
|
||||||
nport != null) {
|
|
||||||
// Host name is configured, and we have a port (either auto or configured)
|
|
||||||
// but we probably only get here if the port is auto,
|
|
||||||
// otherwise createNTCPAddress() would have done it already
|
|
||||||
if (_log.shouldLog(Log.INFO))
|
|
||||||
_log.info("old: " + ohost + " config: " + name + " new: " + name);
|
|
||||||
newProps.setProperty(NTCPAddress.PROP_HOST, name);
|
|
||||||
changed = true;
|
|
||||||
} else if (ohost == null || ohost.length() <= 0) {
|
|
||||||
return;
|
|
||||||
} else if (Boolean.parseBoolean(enabled) && status != STATUS_OK) {
|
|
||||||
// UDP transitioned to not-OK, turn off NTCP address
|
|
||||||
// This will commonly happen at startup if we were initially OK
|
|
||||||
// because UPnP was successful, but a subsequent SSU Peer Test determines
|
|
||||||
// we are still firewalled (SW firewall, bad UPnP indication, etc.)
|
|
||||||
if (_log.shouldLog(Log.INFO))
|
|
||||||
_log.info("old: " + ohost + " config: " + name + " new: null");
|
|
||||||
newAddr = null;
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!changed) {
|
|
||||||
if (oldAddr != null) {
|
|
||||||
int oldCost = oldAddr.getCost();
|
|
||||||
int newCost = NTCPAddress.DEFAULT_COST;
|
|
||||||
if (TransportImpl.ADJUST_COST && !t.haveCapacity())
|
|
||||||
newCost++;
|
|
||||||
if (newCost != oldCost) {
|
|
||||||
oldAddr.setCost(newCost);
|
|
||||||
if (_log.shouldLog(Log.WARN))
|
|
||||||
_log.warn("Changing NTCP cost from " + oldCost + " to " + newCost);
|
|
||||||
} else {
|
|
||||||
_log.info("No change to NTCP Address");
|
|
||||||
}
|
|
||||||
} 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.
|
|
||||||
//
|
|
||||||
_log.warn("Halting NTCP to change address");
|
|
||||||
t.stopListening();
|
|
||||||
if (newAddr != null)
|
|
||||||
newAddr.setOptions(newProps);
|
|
||||||
// Wait for NTCP Pumper to stop so we don't end up with two...
|
|
||||||
while (t.isAlive()) {
|
|
||||||
try { Thread.sleep(5*1000); } catch (InterruptedException ie) {}
|
|
||||||
}
|
|
||||||
t.restartListening(newAddr);
|
|
||||||
_log.warn("Changed NTCP Address and started up, address is now " + newAddr);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -63,8 +63,7 @@ public interface Transport {
|
|||||||
SOURCE_INTERFACE("local"),
|
SOURCE_INTERFACE("local"),
|
||||||
/** unused */
|
/** unused */
|
||||||
SOURCE_CONFIG("config"),
|
SOURCE_CONFIG("config"),
|
||||||
/** unused */
|
SOURCE_SSU("ssu");
|
||||||
SOURCE_SSU_PEER("ssu");
|
|
||||||
|
|
||||||
private final String cfgstr;
|
private final String cfgstr;
|
||||||
|
|
||||||
|
@ -552,7 +552,7 @@ public abstract class TransportImpl implements Transport {
|
|||||||
* This implementation does nothing. Transports should override if they want notification.
|
* This implementation does nothing. Transports should override if they want notification.
|
||||||
*
|
*
|
||||||
* @param source defined in Transport.java
|
* @param source defined in Transport.java
|
||||||
* @param ip typ. IPv4 or IPv6 non-local
|
* @param ip typ. IPv4 or IPv6 non-local; may be null to indicate IPv4 failure or port info only
|
||||||
* @param port 0 for unknown or unchanged
|
* @param port 0 for unknown or unchanged
|
||||||
*/
|
*/
|
||||||
public void externalAddressReceived(AddressSource source, byte[] ip, int port) {}
|
public void externalAddressReceived(AddressSource source, byte[] ip, int port) {}
|
||||||
|
@ -30,7 +30,7 @@ import net.i2p.data.i2np.I2NPMessage;
|
|||||||
import net.i2p.router.CommSystemFacade;
|
import net.i2p.router.CommSystemFacade;
|
||||||
import net.i2p.router.OutNetMessage;
|
import net.i2p.router.OutNetMessage;
|
||||||
import net.i2p.router.RouterContext;
|
import net.i2p.router.RouterContext;
|
||||||
import static net.i2p.router.transport.Transport.AddressSource.SOURCE_INTERFACE;
|
import static net.i2p.router.transport.Transport.AddressSource.*;
|
||||||
import net.i2p.router.transport.crypto.DHSessionKeyBuilder;
|
import net.i2p.router.transport.crypto.DHSessionKeyBuilder;
|
||||||
import net.i2p.router.transport.ntcp.NTCPTransport;
|
import net.i2p.router.transport.ntcp.NTCPTransport;
|
||||||
import net.i2p.router.transport.udp.UDPTransport;
|
import net.i2p.router.transport.udp.UDPTransport;
|
||||||
@ -120,14 +120,16 @@ public class TransportManager implements TransportEventListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* callback from UPnP
|
* callback from UPnP or SSU
|
||||||
* Only tell SSU, it will tell NTCP
|
* Only tell SSU, it will tell NTCP
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public void externalAddressReceived(Transport.AddressSource source, byte[] ip, int port) {
|
public void externalAddressReceived(Transport.AddressSource source, byte[] ip, int port) {
|
||||||
Transport t = getTransport(UDPTransport.STYLE);
|
for (Transport t : _transports.values()) {
|
||||||
if (t != null)
|
// don't loop
|
||||||
t.externalAddressReceived(source, ip, port);
|
if (!(source == SOURCE_SSU && t.getStyle().equals(UDPTransport.STYLE)))
|
||||||
|
t.externalAddressReceived(source, ip, port);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -385,7 +387,7 @@ public class TransportManager implements TransportEventListener {
|
|||||||
int port = t.getRequestedPort();
|
int port = t.getRequestedPort();
|
||||||
// Use UDP port for NTCP too - see comment in NTCPTransport.getRequestedPort() for why this is here
|
// Use UDP port for NTCP too - see comment in NTCPTransport.getRequestedPort() for why this is here
|
||||||
if (t.getStyle().equals(NTCPTransport.STYLE) && port <= 0 &&
|
if (t.getStyle().equals(NTCPTransport.STYLE) && port <= 0 &&
|
||||||
_context.getBooleanProperty(CommSystemFacadeImpl.PROP_I2NP_NTCP_AUTO_PORT)) {
|
_context.getBooleanProperty(NTCPTransport.PROP_I2NP_NTCP_AUTO_PORT)) {
|
||||||
Transport udp = getTransport(UDPTransport.STYLE);
|
Transport udp = getTransport(UDPTransport.STYLE);
|
||||||
if (udp != null)
|
if (udp != null)
|
||||||
port = t.getRequestedPort();
|
port = t.getRequestedPort();
|
||||||
|
@ -30,12 +30,15 @@ import net.i2p.router.OutNetMessage;
|
|||||||
import net.i2p.router.RouterContext;
|
import net.i2p.router.RouterContext;
|
||||||
import net.i2p.router.transport.CommSystemFacadeImpl;
|
import net.i2p.router.transport.CommSystemFacadeImpl;
|
||||||
import net.i2p.router.transport.Transport;
|
import net.i2p.router.transport.Transport;
|
||||||
|
import static net.i2p.router.transport.Transport.AddressSource.*;
|
||||||
import net.i2p.router.transport.TransportBid;
|
import net.i2p.router.transport.TransportBid;
|
||||||
import net.i2p.router.transport.TransportImpl;
|
import net.i2p.router.transport.TransportImpl;
|
||||||
import net.i2p.router.transport.crypto.DHSessionKeyBuilder;
|
import net.i2p.router.transport.crypto.DHSessionKeyBuilder;
|
||||||
|
import net.i2p.router.transport.udp.UDPTransport;
|
||||||
import net.i2p.util.Addresses;
|
import net.i2p.util.Addresses;
|
||||||
import net.i2p.util.ConcurrentHashSet;
|
import net.i2p.util.ConcurrentHashSet;
|
||||||
import net.i2p.util.Log;
|
import net.i2p.util.Log;
|
||||||
|
import net.i2p.util.OrderedProperties;
|
||||||
import net.i2p.util.Translate;
|
import net.i2p.util.Translate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -62,6 +65,11 @@ public class NTCPTransport extends TransportImpl {
|
|||||||
*/
|
*/
|
||||||
private final Set<NTCPConnection> _establishing;
|
private final Set<NTCPConnection> _establishing;
|
||||||
|
|
||||||
|
public final static String PROP_I2NP_NTCP_HOSTNAME = "i2np.ntcp.hostname";
|
||||||
|
public final static String PROP_I2NP_NTCP_PORT = "i2np.ntcp.port";
|
||||||
|
public final static String PROP_I2NP_NTCP_AUTO_PORT = "i2np.ntcp.autoport";
|
||||||
|
public final static String PROP_I2NP_NTCP_AUTO_IP = "i2np.ntcp.autoip";
|
||||||
|
|
||||||
/** this is rarely if ever used, default is to bind to wildcard address */
|
/** this is rarely if ever used, default is to bind to wildcard address */
|
||||||
public static final String PROP_BIND_INTERFACE = "i2np.ntcp.bindInterface";
|
public static final String PROP_BIND_INTERFACE = "i2np.ntcp.bindInterface";
|
||||||
|
|
||||||
@ -471,11 +479,11 @@ public class NTCPTransport extends TransportImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Only called by CSFI.
|
* Only called by externalAddressReceived().
|
||||||
* Caller should stop the transport first, then
|
* Caller should stop the transport first, then
|
||||||
* verify stopped with isAlive()
|
* verify stopped with isAlive()
|
||||||
*/
|
*/
|
||||||
public synchronized void restartListening(RouterAddress addr) {
|
private synchronized void restartListening(RouterAddress addr) {
|
||||||
// try once again to prevent two pumpers which is fatal
|
// try once again to prevent two pumpers which is fatal
|
||||||
// we could just return null since the return value is ignored
|
// we could just return null since the return value is ignored
|
||||||
if (_pumper.isAlive())
|
if (_pumper.isAlive())
|
||||||
@ -528,9 +536,9 @@ public class NTCPTransport extends TransportImpl {
|
|||||||
// If we are configured with a fixed IP address,
|
// If we are configured with a fixed IP address,
|
||||||
// AND it's one of our local interfaces,
|
// AND it's one of our local interfaces,
|
||||||
// bind only to that.
|
// bind only to that.
|
||||||
boolean isFixed = _context.getProperty(CommSystemFacadeImpl.PROP_I2NP_NTCP_AUTO_IP, "true")
|
boolean isFixed = _context.getProperty(PROP_I2NP_NTCP_AUTO_IP, "true")
|
||||||
.toLowerCase(Locale.US).equals("false");
|
.toLowerCase(Locale.US).equals("false");
|
||||||
String fixedHost = _context.getProperty(CommSystemFacadeImpl.PROP_I2NP_NTCP_HOSTNAME);
|
String fixedHost = _context.getProperty(PROP_I2NP_NTCP_HOSTNAME);
|
||||||
if (isFixed && fixedHost != null) {
|
if (isFixed && fixedHost != null) {
|
||||||
try {
|
try {
|
||||||
String testAddr = InetAddress.getByName(fixedHost).getHostAddress();
|
String testAddr = InetAddress.getByName(fixedHost).getHostAddress();
|
||||||
@ -638,12 +646,8 @@ public class NTCPTransport extends TransportImpl {
|
|||||||
|
|
||||||
/** caller must synch on this */
|
/** caller must synch on this */
|
||||||
private void configureLocalAddress() {
|
private void configureLocalAddress() {
|
||||||
RouterContext ctx = getContext();
|
|
||||||
if (ctx == null) {
|
|
||||||
System.err.println("NIO transport has no context?");
|
|
||||||
} else {
|
|
||||||
// this generally returns null -- see javadoc
|
// this generally returns null -- see javadoc
|
||||||
RouterAddress ra = CommSystemFacadeImpl.createNTCPAddress(ctx);
|
RouterAddress ra = createNTCPAddress();
|
||||||
if (ra != null) {
|
if (ra != null) {
|
||||||
NTCPAddress addr = new NTCPAddress(ra);
|
NTCPAddress addr = new NTCPAddress(ra);
|
||||||
if (addr.getPort() <= 0) {
|
if (addr.getPort() <= 0) {
|
||||||
@ -660,9 +664,200 @@ public class NTCPTransport extends TransportImpl {
|
|||||||
if (_log.shouldLog(Log.INFO))
|
if (_log.shouldLog(Log.INFO))
|
||||||
_log.info("NTCP address is outbound only");
|
_log.info("NTCP address is outbound only");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This only creates an address if the hostname AND port are set in router.config,
|
||||||
|
* which should be rare.
|
||||||
|
* Otherwise, notifyReplaceAddress() below takes care of it.
|
||||||
|
* Note this is called both from above and from NTCPTransport.startListening()
|
||||||
|
*
|
||||||
|
* @since IPv6 moved from CSFI
|
||||||
|
*/
|
||||||
|
private RouterAddress createNTCPAddress() {
|
||||||
|
String name = _context.getProperty(PROP_I2NP_NTCP_HOSTNAME);
|
||||||
|
if ( (name == null) || (name.trim().length() <= 0) || ("null".equals(name)) )
|
||||||
|
return null;
|
||||||
|
int p = _context.getProperty(PROP_I2NP_NTCP_PORT, -1);
|
||||||
|
if (p <= 0 || p >= 64*1024)
|
||||||
|
return null;
|
||||||
|
OrderedProperties props = new OrderedProperties();
|
||||||
|
props.setProperty(NTCPAddress.PROP_HOST, name);
|
||||||
|
props.setProperty(NTCPAddress.PROP_PORT, Integer.toString(p));
|
||||||
|
RouterAddress addr = new RouterAddress(STYLE, props, NTCPAddress.DEFAULT_COST);
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UDP changed addresses, tell NTCP and restart
|
||||||
|
*
|
||||||
|
* @since IPv6 moved from CSFI.notifyReplaceAddress()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void externalAddressReceived(AddressSource source, byte[] ip, int port) {
|
||||||
|
if (_log.shouldLog(Log.WARN))
|
||||||
|
_log.warn("Received address: " + Addresses.toString(ip, port) + " from: " + source);
|
||||||
|
// ignore UPnP for now, get everything from SSU
|
||||||
|
if (source != SOURCE_SSU)
|
||||||
|
return;
|
||||||
|
externalAddressReceived(ip, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UDP changed addresses, tell NTCP and restart
|
||||||
|
* Port may be set to indicate requested port even if ip is null;
|
||||||
|
* see CSFI.notifyReplaceAddress()
|
||||||
|
*
|
||||||
|
* @since IPv6 moved from CSFI.notifyReplaceAddress()
|
||||||
|
*/
|
||||||
|
private synchronized void externalAddressReceived(byte[] ip, int port) {
|
||||||
|
// FIXME just take first IPv4 address for now
|
||||||
|
// FIXME if SSU set to hostname, NTCP will be set to IP
|
||||||
|
RouterAddress oldAddr = getCurrentAddress(false);
|
||||||
|
if (_log.shouldLog(Log.INFO))
|
||||||
|
_log.info("Changing NTCP Address? was " + oldAddr);
|
||||||
|
|
||||||
|
OrderedProperties newProps = new OrderedProperties();
|
||||||
|
int cost;
|
||||||
|
if (oldAddr == null) {
|
||||||
|
cost = NTCPAddress.DEFAULT_COST;
|
||||||
|
} 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(NTCPAddress.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)) {
|
||||||
|
// 0.9.6 change
|
||||||
|
// This wasn't quite right, as udpAddr is the EXTERNAL port and we really
|
||||||
|
// want NTCP to bind to the INTERNAL port the first time,
|
||||||
|
// because if they are different, the NAT is changing them, and
|
||||||
|
// 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: " + oport + " config: " + cport + " new: " + nport);
|
||||||
|
if (nport == null || nport.length() <= 0)
|
||||||
|
return;
|
||||||
|
// 0.9.6 change
|
||||||
|
// Don't have NTCP "chase" SSU's external port,
|
||||||
|
// as it may change, possibly frequently.
|
||||||
|
//if (oport == null || ! oport.equals(nport)) {
|
||||||
|
if (oport == null) {
|
||||||
|
newProps.setProperty(NTCPAddress.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(NTCPAddress.PROP_HOST);
|
||||||
|
String enabled = _context.getProperty(PROP_I2NP_NTCP_AUTO_IP, "true").toLowerCase(Locale.US);
|
||||||
|
String name = _context.getProperty(PROP_I2NP_NTCP_HOSTNAME);
|
||||||
|
// 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)) {
|
||||||
|
// 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(NTCPAddress.PROP_HOST, nhost);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
} else if (enabled.equals("false") &&
|
||||||
|
name != null && name.length() > 0 &&
|
||||||
|
!name.equals(ohost) &&
|
||||||
|
nport != null) {
|
||||||
|
// Host name is configured, and we have a port (either auto or configured)
|
||||||
|
// but we probably only get here if the port is auto,
|
||||||
|
// otherwise createNTCPAddress() would have done it already
|
||||||
|
if (_log.shouldLog(Log.INFO))
|
||||||
|
_log.info("old: " + ohost + " config: " + name + " new: " + name);
|
||||||
|
newProps.setProperty(NTCPAddress.PROP_HOST, name);
|
||||||
|
changed = true;
|
||||||
|
} else if (ohost == null || ohost.length() <= 0) {
|
||||||
|
return;
|
||||||
|
} else if (Boolean.parseBoolean(enabled) && !ssuOK) {
|
||||||
|
// UDP transitioned to not-OK, turn off NTCP address
|
||||||
|
// This will commonly happen at startup if we were initially OK
|
||||||
|
// because UPnP was successful, but a subsequent SSU Peer Test determines
|
||||||
|
// we are still firewalled (SW firewall, bad UPnP indication, etc.)
|
||||||
|
if (_log.shouldLog(Log.INFO))
|
||||||
|
_log.info("old: " + ohost + " config: " + name + " new: null");
|
||||||
|
newAddr = null;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!changed) {
|
||||||
|
if (oldAddr != null) {
|
||||||
|
int oldCost = oldAddr.getCost();
|
||||||
|
int newCost = NTCPAddress.DEFAULT_COST;
|
||||||
|
if (TransportImpl.ADJUST_COST && !haveCapacity())
|
||||||
|
newCost++;
|
||||||
|
if (newCost != oldCost) {
|
||||||
|
oldAddr.setCost(newCost);
|
||||||
|
if (_log.shouldLog(Log.WARN))
|
||||||
|
_log.warn("Changing NTCP cost from " + oldCost + " to " + newCost);
|
||||||
|
} else {
|
||||||
|
_log.info("No change to NTCP Address");
|
||||||
|
}
|
||||||
|
} 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.
|
||||||
|
//
|
||||||
|
_log.warn("Halting NTCP to change address");
|
||||||
|
stopListening();
|
||||||
|
if (newAddr != null)
|
||||||
|
newAddr.setOptions(newProps);
|
||||||
|
// 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);
|
||||||
|
_log.warn("Changed NTCP Address and started up, address is now " + newAddr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If we didn't used to be forwarded, and we have an address,
|
* If we didn't used to be forwarded, and we have an address,
|
||||||
* and we are configured to use UPnP, update our RouterAddress
|
* and we are configured to use UPnP, update our RouterAddress
|
||||||
@ -698,7 +893,7 @@ public class NTCPTransport extends TransportImpl {
|
|||||||
// from here, so we do it in TransportManager.
|
// from here, so we do it in TransportManager.
|
||||||
// if (Boolean.valueOf(_context.getProperty(CommSystemFacadeImpl.PROP_I2NP_NTCP_AUTO_PORT)).booleanValue())
|
// if (Boolean.valueOf(_context.getProperty(CommSystemFacadeImpl.PROP_I2NP_NTCP_AUTO_PORT)).booleanValue())
|
||||||
// return foo;
|
// return foo;
|
||||||
return _context.getProperty(CommSystemFacadeImpl.PROP_I2NP_NTCP_PORT, -1);
|
return _context.getProperty(PROP_I2NP_NTCP_PORT, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -155,7 +155,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
|||||||
public static final String PROP_SOURCES = "i2np.udp.addressSources";
|
public static final String PROP_SOURCES = "i2np.udp.addressSources";
|
||||||
public static final String DEFAULT_SOURCES = SOURCE_INTERFACE.toConfigString() + ',' +
|
public static final String DEFAULT_SOURCES = SOURCE_INTERFACE.toConfigString() + ',' +
|
||||||
SOURCE_UPNP.toConfigString() + ',' +
|
SOURCE_UPNP.toConfigString() + ',' +
|
||||||
SOURCE_SSU_PEER.toConfigString();
|
SOURCE_SSU.toConfigString();
|
||||||
/** remember IP changes */
|
/** remember IP changes */
|
||||||
public static final String PROP_IP= "i2np.lastIP";
|
public static final String PROP_IP= "i2np.lastIP";
|
||||||
public static final String PROP_IP_CHANGE = "i2np.lastIPChange";
|
public static final String PROP_IP_CHANGE = "i2np.lastIPChange";
|
||||||
@ -563,13 +563,15 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
|||||||
* Not for info received from peers - see externalAddressReceived(Hash, ip, port)
|
* Not for info received from peers - see externalAddressReceived(Hash, ip, port)
|
||||||
*
|
*
|
||||||
* @param source as defined in Transport.SOURCE_xxx
|
* @param source as defined in Transport.SOURCE_xxx
|
||||||
* @param ip publicly routable IPv4 or IPv6
|
* @param ip publicly routable IPv4 or IPv6, null ok
|
||||||
* @param port 0 if unknown
|
* @param port 0 if unknown
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void externalAddressReceived(Transport.AddressSource source, byte[] ip, int port) {
|
public void externalAddressReceived(Transport.AddressSource source, byte[] ip, int port) {
|
||||||
if (_log.shouldLog(Log.WARN))
|
if (_log.shouldLog(Log.WARN))
|
||||||
_log.warn("Received address: " + Addresses.toString(ip, port) + " from: " + source);
|
_log.warn("Received address: " + Addresses.toString(ip, port) + " from: " + source);
|
||||||
|
if (ip == null)
|
||||||
|
return;
|
||||||
if (source == SOURCE_INTERFACE && ip.length == 16) {
|
if (source == SOURCE_INTERFACE && ip.length == 16) {
|
||||||
// must be set before isValid() call
|
// must be set before isValid() call
|
||||||
_haveIPv6Address = true;
|
_haveIPv6Address = true;
|
||||||
|
Reference in New Issue
Block a user