* UDP: Pick a random port on first install or bind failure -
No more port 8887 to prevent easy state-level blocking
This commit is contained in:
@ -11,10 +11,6 @@ While you are waiting, please <b>adjust your bandwidth settings</b> on the
|
||||
<a href="config.jsp">configuration page</a>.
|
||||
</li>
|
||||
<li>
|
||||
If you can, open up <b>port 8887</b> on your firewall, then <b>enable inbound TCP</b> on the
|
||||
<a href="config.jsp">configuration page</a>.
|
||||
</li>
|
||||
<li>
|
||||
Once you have a "shared clients" destination listed on the left,
|
||||
please <b>check out</b> our
|
||||
<a href="http://www.i2p2.i2p/faq.html">FAQ</a>.
|
||||
@ -35,9 +31,6 @@ Passe bitte In der Wartezeit <b>deine Einstellungen zur Bandbreite</b> auf der
|
||||
<a href="config.jsp">Einstellungsseite</a> an.
|
||||
</li>
|
||||
<li>
|
||||
Bitte öffne sobald möglich den <b>Port 8887</b> in deiner Firewall, aktiviere danach den <b>eingehenden TCP Verkehr</b> auf der <a href="config.jsp">Einstellungsseite</a>.
|
||||
</li>
|
||||
<li>
|
||||
Sobald auf der linken Seite eine "shared clients" Verbindung aufgelistet ist <b>besuche bitte</b> unsere <a href="http://www.i2p2.i2p/faq_de.html">FAQ</a>.
|
||||
</li>
|
||||
<li>
|
||||
|
@ -22,7 +22,11 @@ public class UDPEndpoint {
|
||||
private DatagramSocket _socket;
|
||||
private InetAddress _bindAddress;
|
||||
|
||||
public UDPEndpoint(RouterContext ctx, UDPTransport transport, int listenPort, InetAddress bindAddress) throws SocketException {
|
||||
/**
|
||||
* @param listenPort -1 or the requested port, may not be honored
|
||||
* @param bindAddress null ok
|
||||
*/
|
||||
public UDPEndpoint(RouterContext ctx, UDPTransport transport, int listenPort, InetAddress bindAddress) {
|
||||
_context = ctx;
|
||||
_log = ctx.logManager().getLog(UDPEndpoint.class);
|
||||
_transport = transport;
|
||||
@ -30,23 +34,20 @@ public class UDPEndpoint {
|
||||
_listenPort = listenPort;
|
||||
}
|
||||
|
||||
/** caller should call getListenPort() after this to get the actual bound port and determine success */
|
||||
public void startup() {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Starting up the UDP endpoint");
|
||||
shutdown();
|
||||
try {
|
||||
if (_bindAddress == null)
|
||||
_socket = new DatagramSocket(_listenPort);
|
||||
else
|
||||
_socket = new DatagramSocket(_listenPort, _bindAddress);
|
||||
_sender = new UDPSender(_context, _socket, "UDPSender");
|
||||
_receiver = new UDPReceiver(_context, _transport, _socket, "UDPReceiver");
|
||||
_sender.startup();
|
||||
_receiver.startup();
|
||||
} catch (SocketException se) {
|
||||
_transport.setReachabilityStatus(CommSystemFacade.STATUS_HOSED);
|
||||
_log.log(Log.CRIT, "Unable to bind on port " + _listenPort, se);
|
||||
_socket = getSocket();
|
||||
if (_socket == null) {
|
||||
_log.log(Log.CRIT, "UDP Unable to open a port");
|
||||
return;
|
||||
}
|
||||
_sender = new UDPSender(_context, _socket, "UDPSender");
|
||||
_receiver = new UDPReceiver(_context, _transport, _socket, "UDPReceiver");
|
||||
_sender.startup();
|
||||
_receiver.startup();
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
@ -60,6 +61,8 @@ public class UDPEndpoint {
|
||||
}
|
||||
|
||||
public void setListenPort(int newPort) { _listenPort = newPort; }
|
||||
|
||||
/*******
|
||||
public void updateListenPort(int newPort) {
|
||||
if (newPort == _listenPort) return;
|
||||
try {
|
||||
@ -76,7 +79,54 @@ public class UDPEndpoint {
|
||||
_log.error("Unable to bind on " + _listenPort);
|
||||
}
|
||||
}
|
||||
********/
|
||||
|
||||
/** 8998 is monotone, and 32000 is the wrapper, so let's stay between those */
|
||||
private static final int MIN_RANDOM_PORT = 9111;
|
||||
private static final int MAX_RANDOM_PORT = 31777;
|
||||
private static final int MAX_PORT_RETRIES = 20;
|
||||
|
||||
/**
|
||||
* Open socket using requested port in _listenPort and bind host in _bindAddress.
|
||||
* If _listenPort <= 0, or requested port is busy, repeatedly try a new random port.
|
||||
* @return null on failure
|
||||
* Sets _listenPort to actual port or -1 on failure
|
||||
*/
|
||||
private DatagramSocket getSocket() {
|
||||
DatagramSocket socket = null;
|
||||
int port = _listenPort;
|
||||
|
||||
for (int i = 0; i < MAX_PORT_RETRIES; i++) {
|
||||
if (port <= 0) {
|
||||
// try random ports rather than just do new DatagramSocket()
|
||||
// so we stay out of the way of other I2P stuff
|
||||
port = MIN_RANDOM_PORT + _context.random().nextInt(MAX_RANDOM_PORT - MIN_RANDOM_PORT);
|
||||
}
|
||||
try {
|
||||
if (_bindAddress == null)
|
||||
socket = new DatagramSocket(port);
|
||||
else
|
||||
socket = new DatagramSocket(port, _bindAddress);
|
||||
break;
|
||||
} catch (SocketException se) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Binding to port " + port + " failed: " + se);
|
||||
}
|
||||
port = -1;
|
||||
}
|
||||
if (socket == null) {
|
||||
_log.log(Log.CRIT, "SSU Unable to bind to a port on " + _bindAddress);
|
||||
} else if (port != _listenPort) {
|
||||
if (_listenPort > 0)
|
||||
_log.error("SSU Unable to bind to requested port " + _listenPort + ", using random port " + port);
|
||||
else
|
||||
_log.error("SSU selected random port " + port);
|
||||
}
|
||||
_listenPort = port;
|
||||
return socket;
|
||||
}
|
||||
|
||||
/** call after startup() to get actual port or -1 on startup failure */
|
||||
public int getListenPort() { return _listenPort; }
|
||||
public UDPSender getSender() { return _sender; }
|
||||
|
||||
|
@ -100,6 +100,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
|
||||
public static final String STYLE = "SSU";
|
||||
public static final String PROP_INTERNAL_PORT = "i2np.udp.internalPort";
|
||||
/** now unused, we pick a random port */
|
||||
public static final int DEFAULT_INTERNAL_PORT = 8887;
|
||||
/** since fixed port defaults to true, this doesnt do anything at the moment.
|
||||
* We should have an exception if it matches the existing low port. */
|
||||
@ -137,6 +138,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
public static final String PROP_FORCE_INTRODUCERS = "i2np.udp.forceIntroducers";
|
||||
/** do we allow direct SSU connections, sans introducers? */
|
||||
public static final String PROP_ALLOW_DIRECT = "i2np.udp.allowDirect";
|
||||
/** this is rarely if ever used, default is to bind to wildcard address */
|
||||
public static final String PROP_BIND_INTERFACE = "i2np.udp.bindInterface";
|
||||
|
||||
/** how many relays offered to us will we use at a time? */
|
||||
@ -226,40 +228,41 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
System.arraycopy(_context.routerHash().getData(), 0, _introKey.getData(), 0, SessionKey.KEYSIZE_BYTES);
|
||||
|
||||
rebuildExternalAddress();
|
||||
|
||||
int port = -1;
|
||||
if (_externalListenPort <= 0) {
|
||||
// no explicit external port, so lets try an internal one
|
||||
port = _context.getProperty(PROP_INTERNAL_PORT, DEFAULT_INTERNAL_PORT);
|
||||
// attempt to use it as our external port - this will be overridden by
|
||||
// externalAddressReceived(...)
|
||||
_context.router().setConfigSetting(PROP_EXTERNAL_PORT, port+"");
|
||||
_context.router().saveConfig();
|
||||
} else {
|
||||
port = _externalListenPort;
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Binding to the explicitly specified external port: " + port);
|
||||
}
|
||||
if (_endpoint == null) {
|
||||
String bindTo = _context.getProperty(PROP_BIND_INTERFACE);
|
||||
InetAddress bindToAddr = null;
|
||||
if (bindTo != null) {
|
||||
try {
|
||||
bindToAddr = InetAddress.getByName(bindTo);
|
||||
} catch (UnknownHostException uhe) {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Invalid SSU bind interface specified [" + bindTo + "]", uhe);
|
||||
bindToAddr = null;
|
||||
}
|
||||
}
|
||||
|
||||
// bind host
|
||||
String bindTo = _context.getProperty(PROP_BIND_INTERFACE);
|
||||
InetAddress bindToAddr = null;
|
||||
if (bindTo != null) {
|
||||
try {
|
||||
_endpoint = new UDPEndpoint(_context, this, port, bindToAddr);
|
||||
} catch (SocketException se) {
|
||||
if (_log.shouldLog(Log.CRIT))
|
||||
_log.log(Log.CRIT, "Unable to listen on the UDP port (" + port + ")", se);
|
||||
bindToAddr = InetAddress.getByName(bindTo);
|
||||
} catch (UnknownHostException uhe) {
|
||||
_log.log(Log.CRIT, "Invalid SSU bind interface specified [" + bindTo + "]", uhe);
|
||||
setReachabilityStatus(CommSystemFacade.STATUS_HOSED);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Requested bind port
|
||||
// This may be -1 or may not be honored if busy,
|
||||
// we will check below after starting up the endpoint.
|
||||
int port;
|
||||
int oldIPort = _context.getProperty(PROP_INTERNAL_PORT, -1);
|
||||
int oldEPort = _context.getProperty(PROP_EXTERNAL_PORT, -1);
|
||||
if (_externalListenPort <= 0) {
|
||||
// no explicit external port, so lets try an internal one
|
||||
if (oldIPort > 0)
|
||||
port = oldIPort;
|
||||
else
|
||||
port = oldEPort;
|
||||
} else {
|
||||
port = _externalListenPort;
|
||||
}
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Binding to the port: " + port);
|
||||
if (_endpoint == null) {
|
||||
_endpoint = new UDPEndpoint(_context, this, port, bindToAddr);
|
||||
} else {
|
||||
// todo, set bind address too
|
||||
_endpoint.setListenPort(port);
|
||||
}
|
||||
|
||||
@ -278,7 +281,24 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
if (_flooder == null)
|
||||
_flooder = new UDPFlooder(_context, this);
|
||||
|
||||
// Startup the endpoint with the requested port, check the actual port, and
|
||||
// take action if it failed or was different than requested or it needs to be saved
|
||||
_endpoint.startup();
|
||||
int newPort = _endpoint.getListenPort();
|
||||
_externalListenPort = newPort;
|
||||
if (newPort <= 0) {
|
||||
_log.log(Log.CRIT, "Unable to open UDP port");
|
||||
setReachabilityStatus(CommSystemFacade.STATUS_HOSED);
|
||||
return;
|
||||
}
|
||||
if (newPort != port || newPort != oldIPort || newPort != oldEPort) {
|
||||
// attempt to use it as our external port - this will be overridden by
|
||||
// externalAddressReceived(...)
|
||||
_context.router().setConfigSetting(PROP_INTERNAL_PORT, newPort+"");
|
||||
_context.router().setConfigSetting(PROP_EXTERNAL_PORT, newPort+"");
|
||||
_context.router().saveConfig();
|
||||
}
|
||||
|
||||
_establisher.startup();
|
||||
_handler.startup();
|
||||
_fragments.startup();
|
||||
@ -321,11 +341,16 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
public int getLocalPort() { return _externalListenPort; }
|
||||
public InetAddress getLocalAddress() { return _externalListenHost; }
|
||||
public int getExternalPort() { return _externalListenPort; }
|
||||
|
||||
/**
|
||||
* _externalListenPort should always be set (by startup()) before this is called,
|
||||
* so the returned value should be > 0
|
||||
*/
|
||||
@Override
|
||||
public int getRequestedPort() {
|
||||
if (_externalListenPort > 0)
|
||||
return _externalListenPort;
|
||||
return _context.getProperty(PROP_INTERNAL_PORT, DEFAULT_INTERNAL_PORT);
|
||||
return _context.getProperty(PROP_INTERNAL_PORT, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2003,6 +2028,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
buf.append(" <td align=\"center\"><b>").append(resentTotal);
|
||||
buf.append("</b></td> <td align=\"center\"><b>").append(dupRecvTotal).append("</b></td>\n");
|
||||
buf.append(" </tr></table></div>\n");
|
||||
|
||||
/*****
|
||||
long bytesTransmitted = _context.bandwidthLimiter().getTotalAllocatedOutboundBytes();
|
||||
// NPE here early
|
||||
double averagePacketSize = _context.statManager().getRate("udp.sendPacketSize").getLifetimeAverageValue();
|
||||
@ -2012,6 +2039,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
double bwResent = (nondupSent <= 0 ? 0d : ((((double)resentTotal)*averagePacketSize) / nondupSent));
|
||||
buf.append("<h3>Percentage of bytes retransmitted (lifetime): ").append(formatPct(bwResent));
|
||||
buf.append("</h3><i>(Includes retransmission required by packet loss)</i>\n");
|
||||
*****/
|
||||
|
||||
out.write(buf.toString());
|
||||
buf.setLength(0);
|
||||
out.write(KEY);
|
||||
|
Reference in New Issue
Block a user