diff --git a/router/java/src/net/i2p/router/transport/UPnP.java b/router/java/src/net/i2p/router/transport/UPnP.java
index 556a346a048168adf8c9e33bd9dacd1207005972..657aadfcb887c8bc9b5c3eee51c8bb7dd86bc9df 100644
--- a/router/java/src/net/i2p/router/transport/UPnP.java
+++ b/router/java/src/net/i2p/router/transport/UPnP.java
@@ -28,6 +28,8 @@ import net.i2p.util.I2PThread;
 import net.i2p.util.Log;
 import net.i2p.util.Translate;
 
+import org.cybergarage.http.HTTPServer;
+import org.cybergarage.http.HTTPServerList;
 import org.cybergarage.upnp.Action;
 import org.cybergarage.upnp.ActionList;
 import org.cybergarage.upnp.Argument;
@@ -42,7 +44,11 @@ import org.cybergarage.upnp.StateVariable;
 import org.cybergarage.upnp.UPnPStatus;
 import org.cybergarage.upnp.device.DeviceChangeListener;
 import org.cybergarage.upnp.event.EventListener;
+import org.cybergarage.upnp.ssdp.SSDPNotifySocket;
+import org.cybergarage.upnp.ssdp.SSDPNotifySocketList;
 import org.cybergarage.upnp.ssdp.SSDPPacket;
+import org.cybergarage.upnp.ssdp.SSDPSearchResponseSocket;
+import org.cybergarage.upnp.ssdp.SSDPSearchResponseSocketList;
 import org.cybergarage.util.Debug;
 import org.freenetproject.DetectedIP;
 import org.freenetproject.ForwardPort;
@@ -640,6 +646,133 @@ public class UPnP extends ControlPoint implements DeviceChangeListener, EventLis
 		}
 	}
 
+	/**
+	 * Update the SSDPSearchResponseSocketList,
+	 * SSDPNotifySocketList, and HTTPServerList every time.
+	 * Otherwise, we are just listening on the interfaces that were present when started.
+	 *
+	 * @since 0.9.46
+	 */
+	private void updateInterfaces() {
+		Set<String> addrs = Addresses.getAddresses(true, false, false);
+		// remove public addresses
+		// see TransportManager.startListening()
+		for (Iterator<String> iter = addrs.iterator(); iter.hasNext(); ) {
+			String addr = iter.next();
+			byte[] ip = Addresses.getIP(addr);
+			if (ip == null || TransportUtil.isPubliclyRoutable(ip, false))
+				iter.remove();
+		}
+		Set<String> oldaddrs = new HashSet<String>(addrs.size());
+
+		// protect against list mod in super.stop()
+		synchronized(this) {
+			// we do this one first because we can detect failure before adding
+			HTTPServerList hlist = getHTTPServerList();
+			for (Iterator<HTTPServer> iter = hlist.iterator(); iter.hasNext(); ) {
+				HTTPServer skt = iter.next();
+				String addr = skt.getBindAddress();
+				int slash = addr.indexOf('/');
+				if (slash >= 0)
+					addr = addr.substring(slash + 1);
+				if (!addrs.contains(addr)) {
+					iter.remove();
+					skt.close();
+					skt.stop();
+					if (_log.shouldWarn())
+						_log.warn("Closed HTTP server socket: " + addr);
+				}
+				oldaddrs.add(addr);
+			}
+			for (Iterator<String> iter = addrs.iterator(); iter.hasNext(); ) {
+				String addr = iter.next();
+				if (!oldaddrs.contains(addr)) {
+					HTTPServer socket = new HTTPServer();
+					boolean ok = socket.open(addr, getHTTPPort());
+					if (ok) {
+						socket.addRequestListener(this);
+						socket.start();
+						hlist.add(socket);
+						if (_log.shouldWarn())
+							_log.warn("Added HTTP server socket: " + addr);
+					} else {
+						// so we don't attempt to add to the other lists below
+						iter.remove();
+						if (_log.shouldWarn())
+							_log.warn("open() failed on new HTTP server socket: " + addr);
+					}
+				}
+			}
+
+			oldaddrs.clear();
+			SSDPSearchResponseSocketList list = getSSDPSearchResponseSocketList();
+			for (Iterator<SSDPSearchResponseSocket> iter = list.iterator(); iter.hasNext(); ) {
+				SSDPSearchResponseSocket skt = iter.next();
+				String addr = skt.getLocalAddress();
+				if (!addrs.contains(addr)) {
+					iter.remove();
+					skt.setControlPoint(null);
+					skt.close();
+					skt.stop();
+					if (_log.shouldWarn())
+						_log.warn("Closed SSDP search response socket: " + addr);
+				}
+				oldaddrs.add(addr);
+			}
+			for (String addr : addrs) {
+				if (!oldaddrs.contains(addr)) {
+					// TODO this calls open() in constructor, fails silently
+					SSDPSearchResponseSocket socket = new SSDPSearchResponseSocket(addr, getSSDPPort());
+					socket.setControlPoint(this);
+					socket.start();
+					list.add(socket);
+					if (_log.shouldWarn())
+						_log.warn("Added SSDP search response socket: " + addr);
+				}
+			}
+
+			oldaddrs.clear();
+			SSDPNotifySocketList nlist = getSSDPNotifySocketList();
+			for (Iterator<SSDPNotifySocket> iter = nlist.iterator(); iter.hasNext(); ) {
+				SSDPNotifySocket skt = iter.next();
+				String addr = skt.getLocalAddress();
+				if (!addrs.contains(addr)) {
+					iter.remove();
+					skt.setControlPoint(null);
+					skt.close();
+					skt.stop();
+					if (_log.shouldWarn())
+						_log.warn("Closed SSDP notify socket: " + addr);
+				}
+				oldaddrs.add(addr);
+			}
+			for (String addr : addrs) {
+				if (!oldaddrs.contains(addr)) {
+					// TODO this calls open() in constructor, fails silently
+					SSDPNotifySocket socket = new SSDPNotifySocket(addr);
+					socket.setControlPoint(this);
+					socket.start();
+					nlist.add(socket);
+					if (_log.shouldWarn())
+						_log.warn("Added SSDP notify socket: " + addr);
+				}
+			}
+		}
+	}
+
+	/**
+	 * We override search() to update the SSDPSearchResponseSocketList,
+	 * SSDPNotifySocketList, and HTTPServerList every time.
+	 * Otherwise, we are just listening on the interfaces that were present when started.
+	 *
+	 * @since 0.9.46
+	 */
+	@Override
+	public void search() {
+		updateInterfaces();
+		super.search();
+	}
+
 	/** compare two strings, either of which could be null */
 	private static boolean stringEquals(String a, String b) {
 		if (a != null)
diff --git a/router/java/src/org/cybergarage/upnp/ControlPoint.java b/router/java/src/org/cybergarage/upnp/ControlPoint.java
index 0da72f6763caf563d655d4f7479fb3a962660640..0d8b8b62cc307c7cbfc742d5371f7e3d2dabe617 100644
--- a/router/java/src/org/cybergarage/upnp/ControlPoint.java
+++ b/router/java/src/org/cybergarage/upnp/ControlPoint.java
@@ -111,12 +111,14 @@ public class ControlPoint implements HTTPRequestListener
 	private SSDPNotifySocketList ssdpNotifySocketList;
 	private SSDPSearchResponseSocketList ssdpSearchResponseSocketList;
 
-	private SSDPNotifySocketList getSSDPNotifySocketList()
+	/** I2P was private */
+	protected SSDPNotifySocketList getSSDPNotifySocketList()
 	{
 		return ssdpNotifySocketList;
 	}
 	
-	private SSDPSearchResponseSocketList getSSDPSearchResponseSocketList()
+	/** I2P was private */
+	protected SSDPSearchResponseSocketList getSSDPSearchResponseSocketList()
 	{
 		return ssdpSearchResponseSocketList;
 	}
@@ -574,7 +576,8 @@ public class ControlPoint implements HTTPRequestListener
 
 	private HTTPServerList httpServerList = new HTTPServerList();
 	
-	private HTTPServerList getHTTPServerList()
+	/** I2P was private */
+	protected HTTPServerList getHTTPServerList()
 	{
 		return httpServerList;
 	}