UPnP: Fix bug causing failure when the PC has multiple interfaces

This commit is contained in:
zzz
2011-08-16 16:20:51 +00:00
parent dc02f9cd88
commit f7c31950b3
9 changed files with 91 additions and 6 deletions

View File

@@ -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 = "";

View File

@@ -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<String> 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())

View File

@@ -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)

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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<nHostAddrs; n++) {
String bindAddr = HostInterface.getHostAddress(n);
SSDPSearchResponseSocket socket = new SSDPSearchResponseSocket(bindAddr, port);
Debug.warning("Opened SSDP search response socket at " + bindAddr + ':' + port);
add(socket);
}
}

View File

@@ -37,6 +37,7 @@ public class SSDPSearchSocket extends HTTPMUSocket implements Runnable
public SSDPSearchSocket(String bindAddr)
{
open(bindAddr);
Debug.warning("Opened SSDP search socket at " + bindAddr + ':' + SSDP.PORT);
}
////////////////////////////////////////////////