diff --git a/history.txt b/history.txt index 409869d97..c8ec60b31 100644 --- a/history.txt +++ b/history.txt @@ -1,3 +1,6 @@ +2011-08-16 zzz + * UPnP: Fix bug causing failure when the PC has multiple interfaces + 2011-08-06 kytv * Fix #473 (wrapper.logfile set to the wrong path in Windows). diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index 5b1ba79e3..f5c926454 100644 --- a/router/java/src/net/i2p/router/RouterVersion.java +++ b/router/java/src/net/i2p/router/RouterVersion.java @@ -18,7 +18,7 @@ public class RouterVersion { /** deprecated */ public final static String ID = "Monotone"; public final static String VERSION = CoreVersion.VERSION; - public final static long BUILD = 19; + public final static long BUILD = 20; /** for example "-test" */ public final static String EXTRA = ""; diff --git a/router/java/src/net/i2p/router/transport/UPnP.java b/router/java/src/net/i2p/router/transport/UPnP.java index 8da739e83..37c57d16c 100644 --- a/router/java/src/net/i2p/router/transport/UPnP.java +++ b/router/java/src/net/i2p/router/transport/UPnP.java @@ -4,7 +4,9 @@ package net.i2p.router.transport; import java.net.InetAddress; +import java.net.MalformedURLException; import java.net.UnknownHostException; +import java.net.URL; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -12,6 +14,7 @@ import java.util.Set; import net.i2p.I2PAppContext; import net.i2p.data.DataHelper; +import net.i2p.util.Addresses; import net.i2p.util.Log; import net.i2p.util.Translate; @@ -527,7 +530,7 @@ class UPnP extends ControlPoint implements DeviceChangeListener, EventListener { // Just in case... // this confuses my linksys? - zzz - removeMapping(protocol, port, fp, true); + //removeMapping(protocol, port, fp, true); Action add = _service.getAction("AddPortMapping"); if(add == null) { @@ -538,7 +541,13 @@ class UPnP extends ControlPoint implements DeviceChangeListener, EventListener { add.setArgumentValue("NewRemoteHost", ""); add.setArgumentValue("NewExternalPort", port); - add.setArgumentValue("NewInternalClient", _router.getInterfaceAddress()); + // bugfix, see below for details + String intf = _router.getInterfaceAddress(); + String us = getOurAddress(intf); + if (_log.shouldLog(Log.WARN) && !us.equals(intf)) + _log.warn("Requesting port forward to " + us + ':' + port + + " when cybergarage wanted " + intf); + add.setArgumentValue("NewInternalClient", us); add.setArgumentValue("NewInternalPort", port); add.setArgumentValue("NewProtocol", protocol); add.setArgumentValue("NewPortMappingDescription", description); @@ -552,7 +561,72 @@ class UPnP extends ControlPoint implements DeviceChangeListener, EventListener { return true; } else return false; } - + + /** + * Bug fix: + * If the SSDP notify or search response sockets listen on more than one interface, + * cybergarage can get our IP address wrong, and then we send the wrong one + * to the UPnP device, which will reject it if it enforces strict addressing. + * + * For example, if we have interfaces 192.168.1.1 and 192.168.2.1, we could + * get a response from 192.168.1.99 on the 192.168.2.1 interface, but when + * we send something to 192.168.1.99 it will go out the 192.168.1.1 interface + * with a request to forward to 192.168.2.1. + * + * So return the address of ours that is closest to his. + * + * @since 0.8.8 + */ + private String getOurAddress(String deflt) { + String rv = deflt; + String hisIP = null; + // see ControlRequest.setRequestHost() + String him = _router.getURLBase(); + if (him != null && him.length() > 0) { + try { + URL url = new URL(him); + hisIP = url.getHost(); + } catch (MalformedURLException mue) {} + } + if (hisIP == null) { + him = _router.getLocation(); + if (him != null && him.length() > 0) { + try { + URL url = new URL(him); + hisIP = url.getHost(); + } catch (MalformedURLException mue) {} + } + } + if (hisIP == null) + return rv; + try { + byte[] hisBytes = InetAddress.getByName(hisIP).getAddress(); + if (hisBytes.length != 4) + return deflt; + long hisLong = DataHelper.fromLong(hisBytes, 0, 4); + long distance = Long.MAX_VALUE; + + // loop through all our IP addresses, including the default, and + // return the one closest to the router's IP + Set myAddresses = Addresses.getAddresses(true, false); // yes local, no IPv6 + myAddresses.add(deflt); + for (String me : myAddresses) { + if (me.startsWith("127.") || me.equals("0.0.0.0")) + continue; + try { + byte[] myBytes = InetAddress.getByName(me).getAddress(); + long myLong = DataHelper.fromLong(myBytes, 0, 4); + long newDistance = myLong ^ hisLong; + if (newDistance < distance) { + rv = me; + distance = newDistance; + } + } catch (UnknownHostException uhe) {} + } + } catch (UnknownHostException uhe) {} + return rv; + } + /** blocking */ private boolean removeMapping(String protocol, int port, ForwardPort fp, boolean noLog) { if(isDisabled || !isNATPresent()) diff --git a/router/java/src/org/cybergarage/upnp/ControlPoint.java b/router/java/src/org/cybergarage/upnp/ControlPoint.java index 781786160..aaf3624bb 100644 --- a/router/java/src/org/cybergarage/upnp/ControlPoint.java +++ b/router/java/src/org/cybergarage/upnp/ControlPoint.java @@ -230,6 +230,7 @@ public class ControlPoint implements HTTPRequestListener if (rootDev == null) return; rootDev.setSSDPPacket(ssdpPacket); + Debug.warning("Add root device", new Exception("received on " + ssdpPacket.getLocalAddress())); addDevice(rootNode); // Thanks for Oliver Newell (2004/10/16) diff --git a/router/java/src/org/cybergarage/upnp/ssdp/HTTPMUSocket.java b/router/java/src/org/cybergarage/upnp/ssdp/HTTPMUSocket.java index 21f4f13a4..2c9dc0c5f 100644 --- a/router/java/src/org/cybergarage/upnp/ssdp/HTTPMUSocket.java +++ b/router/java/src/org/cybergarage/upnp/ssdp/HTTPMUSocket.java @@ -191,6 +191,7 @@ public class HTTPMUSocket try { ssdpMultiSock.receive(recvPacket.getDatagramPacket()); recvPacket.setTimeStamp(System.currentTimeMillis()); + Debug.warning("Received SSDP multicast packet on " + getLocalAddress() + " from " + recvPacket.getRemoteAddress()); } catch (Exception e) { //Debug.warning(e); diff --git a/router/java/src/org/cybergarage/upnp/ssdp/HTTPUSocket.java b/router/java/src/org/cybergarage/upnp/ssdp/HTTPUSocket.java index 04a21c70e..06bf7c0d6 100644 --- a/router/java/src/org/cybergarage/upnp/ssdp/HTTPUSocket.java +++ b/router/java/src/org/cybergarage/upnp/ssdp/HTTPUSocket.java @@ -195,6 +195,7 @@ public class HTTPUSocket try { ssdpUniSock.receive(recvPacket.getDatagramPacket()); recvPacket.setTimeStamp(System.currentTimeMillis()); + Debug.warning("Received SSDP unicast packet on " + getLocalAddress() + " from " + recvPacket.getRemoteAddress()); } catch (Exception e) { //Debug.warning(e); diff --git a/router/java/src/org/cybergarage/upnp/ssdp/SSDPNotifySocket.java b/router/java/src/org/cybergarage/upnp/ssdp/SSDPNotifySocket.java index ad5c26f75..7567624b8 100644 --- a/router/java/src/org/cybergarage/upnp/ssdp/SSDPNotifySocket.java +++ b/router/java/src/org/cybergarage/upnp/ssdp/SSDPNotifySocket.java @@ -29,6 +29,7 @@ import java.net.*; import org.cybergarage.net.*; import org.cybergarage.http.*; import org.cybergarage.upnp.*; +import org.cybergarage.util.Debug; public class SSDPNotifySocket extends HTTPMUSocket implements Runnable { @@ -47,6 +48,7 @@ public class SSDPNotifySocket extends HTTPMUSocket implements Runnable useIPv6Address = true; } open(addr, SSDP.PORT, bindAddr); + Debug.warning("Opened SSDP notify socket at " + bindAddr + ':' + SSDP.PORT); setControlPoint(null); } diff --git a/router/java/src/org/cybergarage/upnp/ssdp/SSDPSearchResponseSocketList.java b/router/java/src/org/cybergarage/upnp/ssdp/SSDPSearchResponseSocketList.java index e9a758244..a3650b8fa 100644 --- a/router/java/src/org/cybergarage/upnp/ssdp/SSDPSearchResponseSocketList.java +++ b/router/java/src/org/cybergarage/upnp/ssdp/SSDPSearchResponseSocketList.java @@ -3,7 +3,7 @@ * CyberUPnP for Java * * Copyright (C) Satoshi Konno 2002-2003 -* +* * File: SSDPSearchResponseSocketList.java * * Revision; @@ -14,7 +14,7 @@ * - Added post() to send a SSDPSearchRequest. * ******************************************************************/ - + package org.cybergarage.upnp.ssdp; import java.util.*; @@ -22,6 +22,7 @@ import java.util.*; import org.cybergarage.net.*; import org.cybergarage.upnp.*; +import org.cybergarage.util.Debug; public class SSDPSearchResponseSocketList extends Vector { @@ -68,6 +69,7 @@ public class SSDPSearchResponseSocketList extends Vector for (int n=0; n