diff --git a/apps/routerconsole/jsp/config.jsp b/apps/routerconsole/jsp/config.jsp index 10232ec73067b8b31f56f769f4a2f31ba568642c..5eb809ed5f2d007a12cb19c595d1f9d527379e1c 100644 --- a/apps/routerconsole/jsp/config.jsp +++ b/apps/routerconsole/jsp/config.jsp @@ -100,9 +100,10 @@ <input name ="udpPort" type="text" size="6" value="<jsp:getProperty name="nethelper" property="configuredUdpPort" />" /><br /> <input type="checkbox" name="requireIntroductions" value="true" <jsp:getProperty name="nethelper" property="requireIntroductionsChecked" /> /> Require SSU introductions - <i>(Enable if you cannot open your firewall)</i><br /> + <i>(Enable if you cannot open your firewall)</i> + <p> Current External UDP address: <i><jsp:getProperty name="nethelper" property="udpAddress" /></i><br /> - <p>If you can, please poke a hole in your NAT or firewall to allow unsolicited UDP packets to reach + </p><p>If you can, please poke a hole in your NAT or firewall to allow unsolicited UDP packets to reach you on your external UDP address. If you can't, I2P now includes supports UDP hole punching with "SSU introductions" - peers who will relay a request from someone you don't know to your router for your router so that you can make an outbound connection to them. I2P will use these diff --git a/apps/routerconsole/jsp/verifyupdate.jsp b/apps/routerconsole/jsp/verifyupdate.jsp deleted file mode 100644 index 2d13d3508d9cf2b0c99213132fe4f8bb171edb6e..0000000000000000000000000000000000000000 --- a/apps/routerconsole/jsp/verifyupdate.jsp +++ /dev/null @@ -1,12 +0,0 @@ -<%@page contentType="text/html" %> -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> - -<html><head> -<title>I2P Router Console - verify update file signature</title> -</head> -<body> - -<!-- net.i2p.crypto.TrustedUpdate.verify(request.getParameter("filename")) --> - -</body> -</html> diff --git a/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java b/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java index 217054d4054f7682a9be005a9e4070464588cd0a..9060ede84cd0f11e5d7e2a7afa764689f1358c7f 100644 --- a/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java +++ b/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java @@ -241,7 +241,7 @@ public class CommSystemFacadeImpl extends CommSystemFacade { public void notifyReplaceAddress(RouterAddress UDPAddr) { if (UDPAddr == null) return; - NTCPTransport t = (NTCPTransport) _manager.getNTCPTransport(); + NTCPTransport t = (NTCPTransport) _manager.getTransport(NTCPTransport.STYLE); if (t == null) return; Properties UDPProps = UDPAddr.getOptions(); diff --git a/router/java/src/net/i2p/router/transport/Transport.java b/router/java/src/net/i2p/router/transport/Transport.java index f95d2dc8f891a7e4735823951fca34726e5418f0..145129651ebb622607ebca557b9b9d3c27aa3b5f 100644 --- a/router/java/src/net/i2p/router/transport/Transport.java +++ b/router/java/src/net/i2p/router/transport/Transport.java @@ -35,6 +35,11 @@ public interface Transport { public RouterAddress startListening(); public void stopListening(); public RouterAddress getCurrentAddress(); + public static final String SOURCE_UPNP = "UPnP"; + public static final String SOURCE_INTERFACE = "Local interface"; + public static final String SOURCE_CONFIG = "Configuration change"; + public void externalAddressReceived(String source, byte[] ip, int port); + public void forwardPortStatus(int port, boolean success, String reason); public void setListener(TransportEventListener listener); public String getStyle(); diff --git a/router/java/src/net/i2p/router/transport/TransportImpl.java b/router/java/src/net/i2p/router/transport/TransportImpl.java index cff0d9a468275676760f261793095e07803c452e..685f6189ef4a5e396b1f6b03f4b02bcf40db9a13 100644 --- a/router/java/src/net/i2p/router/transport/TransportImpl.java +++ b/router/java/src/net/i2p/router/transport/TransportImpl.java @@ -422,6 +422,29 @@ public abstract class TransportImpl implements Transport { _context.commSystem().notifyReplaceAddress(address); } + /** + * Notify a transport of an external address change. + * This may be from a local interface, UPnP, a config change, etc. + * This should not be called if the ip didn't change + * (from that source's point of view), or is a local address, + * or if the ip is IPv6, but the transport should check anyway. + * The transport should also do its own checking on whether to accept + * notifications from this source. + * + * This can be called before startListening() to set an initial address, + * or after the transport is running. + * + * @param source defined in Transport.java + * @param ip typ. IPv4 non-local + * @param port 0 for unknown or unchanged + */ + public void externalAddressReceived(String source, byte[] ip, int port) {} + + /** + * Notify a transport of the results of trying to forward a port + */ + public void forwardPortStatus(int port, boolean success, String reason) {} + /** Who to notify on message availability */ public void setListener(TransportEventListener listener) { _listener = listener; } /** Make this stuff pretty (only used in the old console) */ diff --git a/router/java/src/net/i2p/router/transport/TransportManager.java b/router/java/src/net/i2p/router/transport/TransportManager.java index e0eefe9a54f5d31f103776d21aac92d7abff8314..ea3e09b82f61b4824976dec8d311678189c7d0f9 100644 --- a/router/java/src/net/i2p/router/transport/TransportManager.java +++ b/router/java/src/net/i2p/router/transport/TransportManager.java @@ -10,6 +10,8 @@ package net.i2p.router.transport; import java.io.IOException; import java.io.Writer; +import java.net.InetAddress; +import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -54,7 +56,7 @@ public class TransportManager implements TransportEventListener { _context.statManager().createRateStat("transport.bidFailAllTransports", "Could not attempt to bid on message, as all of the transports had failed", "Transport", new long[] { 60*1000, 10*60*1000, 60*60*1000 }); _transports = new ArrayList(); if (Boolean.valueOf(_context.getProperty(PROP_ENABLE_UPNP)).booleanValue()) - _upnpManager = new UPnPManager(context); + _upnpManager = new UPnPManager(context, this); } public void addTransport(Transport transport) { @@ -75,14 +77,11 @@ public class TransportManager implements TransportEventListener { enableUDP = DEFAULT_ENABLE_UDP; if ("true".equalsIgnoreCase(enableUDP)) { UDPTransport udp = new UDPTransport(_context); - udp.setListener(this); - _transports.add(udp); - } - if (enableNTCP(_context)) { - NTCPTransport ntcp = new NTCPTransport(_context); - ntcp.setListener(this); - _transports.add(ntcp); + addTransport(udp); + initializeAddress(udp); } + if (enableNTCP(_context)) + addTransport(new NTCPTransport(_context)); if (_transports.size() <= 0) _log.log(Log.CRIT, "No transports are enabled"); } @@ -94,6 +93,41 @@ public class TransportManager implements TransportEventListener { return "true".equalsIgnoreCase(enableNTCP); } + private static void initializeAddress(Transport t) { + String ips = Addresses.getAnyAddress(); + if (ips == null) + return; + InetAddress ia = null; + try { + ia = InetAddress.getByName(ips); + } catch (UnknownHostException e) {return;} + if (ia == null) + return; + byte[] ip = ia.getAddress(); + t.externalAddressReceived(Transport.SOURCE_INTERFACE, ip, 0); + } + + /** + * callback from UPnP + * Only tell SSU, it will tell NTCP + * + */ + public void externalAddressReceived(String source, byte[] ip, int port) { + Transport t = getTransport(UDPTransport.STYLE); + if (t != null) + t.externalAddressReceived(source, ip, port); + } + + /** + * callback from UPnP + * + */ + public void forwardPortStatus(String style, int port, boolean success, String reason) { + Transport t = getTransport(style); + if (t != null) + t.forwardPortStatus(port, success, reason); + } + public void startListening() { if (_upnpManager != null) _upnpManager.start(); @@ -102,7 +136,8 @@ public class TransportManager implements TransportEventListener { for (int i = 0; i < _transports.size(); i++) { Transport t = (Transport)_transports.get(i); RouterAddress addr = t.startListening(); - _log.debug("Transport " + i + " (" + t.getStyle() + ") started"); + if (_log.shouldLog(Log.DEBUG)) + _log.debug("Transport " + i + " (" + t.getStyle() + ") started"); } _log.debug("Done start listening on transports"); _context.router().rebuildRouterInfo(); @@ -123,10 +158,10 @@ public class TransportManager implements TransportEventListener { _transports.clear(); } - public Transport getNTCPTransport() { + public Transport getTransport(String style) { for (int i = 0; i < _transports.size(); i++) { Transport t = (Transport)_transports.get(i); - if("NTCP".equals(t.getStyle())) + if(style.equals(t.getStyle())) return t; } return null; diff --git a/router/java/src/net/i2p/router/transport/UPnPManager.java b/router/java/src/net/i2p/router/transport/UPnPManager.java index a508cabef3f2fede40b970a343a084daa9f69d9a..ca7873903b0cae11a89c9418ec0878f1ff7ec06c 100644 --- a/router/java/src/net/i2p/router/transport/UPnPManager.java +++ b/router/java/src/net/i2p/router/transport/UPnPManager.java @@ -4,6 +4,7 @@ package net.i2p.router.transport; * public domain */ +import java.net.InetAddress; import java.util.HashSet; import java.util.Map; import java.util.Properties; @@ -23,9 +24,7 @@ import org.freenetproject.ForwardPortStatus; * Bridge from the I2P RouterAddress data structure to * the freenet data structures * - * No disable option yet. * UPnP listens on ports 1900, 8008, and 8058 - no config option yet. - * No routerconsole support yet. * * @author zzz */ @@ -35,9 +34,12 @@ public class UPnPManager { private UPnP _upnp; private UPnPCallback _upnpCallback; private boolean _isRunning; + private InetAddress _detectedAddress; + private TransportManager _manager; - public UPnPManager(RouterContext context) { + public UPnPManager(RouterContext context, TransportManager manager) { _context = context; + _manager = manager; _log = _context.logManager().getLog(UPnPManager.class); _upnp = new UPnP(context); _upnpCallback = new UPnPCallback(); @@ -60,6 +62,7 @@ public class UPnPManager { if (_isRunning) _upnp.terminate(); _isRunning = false; + _detectedAddress = null; } /** call when the ports might have changed */ @@ -98,7 +101,10 @@ public class UPnPManager { _upnp.onChangePublicPorts(forwards, _upnpCallback); } - /** just logs for now */ + /** + * This is the callback from UPnP. + * It calls the TransportManager callbacks. + */ private class UPnPCallback implements ForwardPortCallback { /** Called to indicate status on one or more forwarded ports. */ @@ -107,10 +113,19 @@ public class UPnPManager { _log.debug("UPnP Callback:"); DetectedIP[] ips = _upnp.getAddress(); + byte[] detected = null; if (ips != null) { for (DetectedIP ip : ips) { - if (_log.shouldLog(Log.DEBUG)) - _log.debug("External address: " + ip.publicAddress + " type: " + ip.natType); + // store the first public one and tell the transport manager if it changed + if (TransportImpl.isPubliclyRoutable(ip.publicAddress.getAddress())) { + if (_log.shouldLog(Log.DEBUG)) + _log.debug("External address: " + ip.publicAddress + " type: " + ip.natType); + if (!ip.publicAddress.equals(_detectedAddress)) { + _detectedAddress = ip.publicAddress; + _manager.externalAddressReceived(Transport.SOURCE_UPNP, _detectedAddress.getAddress(), 0); + } + break; + } } } else { if (_log.shouldLog(Log.DEBUG)) @@ -122,6 +137,15 @@ public class UPnPManager { if (_log.shouldLog(Log.DEBUG)) _log.debug(fp.name + " " + fp.protocol + " " + fp.portNumber + " status: " + fps.status + " reason: " + fps.reasonString + " ext port: " + fps.externalPort); + String style; + if (fp.protocol == ForwardPort.PROTOCOL_UDP_IPV4) + style = "SSU"; + else if (fp.protocol == ForwardPort.PROTOCOL_TCP_IPV4) + style = "NTCP"; + else + continue; + boolean success = fps.status >= ForwardPortStatus.PROBABLE_SUCCESS; + _manager.forwardPortStatus(style, fp.portNumber, success, fps.reasonString); } } } diff --git a/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java b/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java index 4464e5f2d09e68326a24844b59ea9071799833ba..32a108ec0656a4caac32dc852905cb38d49aa74e 100644 --- a/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java +++ b/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java @@ -539,6 +539,19 @@ public class NTCPTransport extends TransportImpl { } } + /** + * If we didn't used to be forwarded, and we have an address, + * and we are configured to use UPnP, update our RouterAddress + */ + public void forwardPortStatus(int port, boolean success, String reason) { + if (_log.shouldLog(Log.WARN)) { + if (success) + _log.warn("UPnP has opened the NTCP port: " + port); + else + _log.warn("UPnP has failed to open the NTCP port: " + port + " reason: " + reason); + } + } + /** * This doesn't (completely) block, caller should check isAlive() * before calling startListening() or restartListening() diff --git a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java index 69e5190fb92fd24378e1d0dc972da67de0249d13..9e4289e38672a3b090e7e15d596258c61f9c5953 100644 --- a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java +++ b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java @@ -326,6 +326,15 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority _lastInboundReceivedOn = System.currentTimeMillis(); } + /** + * From config, UPnP, local i/f, ... + */ + public void externalAddressReceived(String source, byte[] ip, int port) { + String s = RemoteHostId.toString(ip); + if (_log.shouldLog(Log.WARN)) + _log.warn("Received address: " + s + " port: " + port + " from: " + source); + } + /** * 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 diff --git a/router/java/src/org/cybergarage/util/Debug.java b/router/java/src/org/cybergarage/util/Debug.java index 6cd9d939e883ef347272ed92a14ce838a059decc..caf6352ec28cbeb92187f009da1789606a26b942 100644 --- a/router/java/src/org/cybergarage/util/Debug.java +++ b/router/java/src/org/cybergarage/util/Debug.java @@ -3,7 +3,7 @@ * CyberUtil for Java * * Copyright (C) Satoshi Konno 2002 -* +* * File: Debug.java * * Revision; @@ -12,40 +12,40 @@ * - first revision. * ******************************************************************/ - + package org.cybergarage.util; - + public final class Debug { public static boolean enabled = false; public static final void on() { enabled = true; - } + } public static final void off() { enabled = false; - } + } public static boolean isOn() { return enabled; - } - public static final void message(String s) { - if (enabled == true) - System.out.println("CyberGarage message : " + s); - } + } + public static final void message(String s) { + if (enabled == true) + System.out.println("UPnP message : " + s); + } public static final void message(String m1, String m2) { if (enabled == true) - System.out.println("CyberGarage message : "); + System.out.println("UPnP message : "); System.out.println(m1); System.out.println(m2); } - public static final void warning(String s) { - System.out.println("CyberGarage warning : " + s); - } + public static final void warning(String s) { + System.out.println("UPnP warning : " + s); + } public static final void warning(String m, Exception e) { - System.out.println("CyberGarage warning : " + m + " (" + e.getMessage() + ")"); + System.out.println("UPnP warning : " + m + " (" + e.getMessage() + ")"); } public static final void warning(Exception e) { - warning(e.getMessage()); + warning(e.getMessage()); e.printStackTrace(); - } -} \ No newline at end of file + } +}