UPnP: IPv6 part 2

Add support for storing multiple location URLs in DeviceData
Add methods to prefer IPv6 for location URLs
Prefer IPv6 for POST target to WANIPv6FirewallControl service
Add method to bind local address for POST, needed for security checks when forwarding IPv6
Remove IPv6 checks from XML URL parser
Remove unused call in QueryRequest
This commit is contained in:
zzz
2021-02-28 08:08:07 -05:00
parent fa3ca565ca
commit eb535762c4
8 changed files with 146 additions and 16 deletions

View File

@@ -388,6 +388,16 @@ public class HTTPRequest extends HTTPPacket
private Socket postSocket = null;
private String bindTo = null;
/**
* I2P - bind HTTP socket to specified local host address
*
* @param fromHost null to not bind to a particlar local address
* @since 0.9.50
*/
public void setBindHost(String host) { bindTo = host; }
public HTTPResponse post(String host, int port, boolean isKeepAlive)
{
HTTPResponse httpRes = new HTTPResponse();
@@ -413,6 +423,8 @@ public class HTTPRequest extends HTTPPacket
// And set the soTimeout to 2 second (for reads).
//postSocket = new Socket(host, port);
postSocket = new Socket();
if (bindTo != null)
postSocket.bind(new InetSocketAddress(bindTo, 0));
postSocket.setSoTimeout(2000);
SocketAddress sa = new InetSocketAddress(host, port);
postSocket.connect(sa, 3000);

View File

@@ -52,7 +52,7 @@ public class Action
////////////////////////////////////////////////
private Node serviceNode;
private Node actionNode;
private final Node actionNode;
private Node getServiceNode()
{
@@ -369,12 +369,25 @@ public class Action
////////////////////////////////////////////////
public boolean postControlAction()
{
return postControlAction(null);
}
/**
* I2P - bind HTTP socket to specified local host address
*
* @param fromHost null to not bind to a particlar local address
* @since 0.9.50
*/
public boolean postControlAction(String fromHost)
{
// Thanks for Giordano Sassaroli <sassarol@cefriel.it> (08/30/03)
ArgumentList actionArgList = getArgumentList();
ArgumentList actionInputArgList = getInputArgumentList();
ActionRequest ctrlReq = new ActionRequest();
ctrlReq.setRequest(this, actionInputArgList);
if (fromHost != null)
ctrlReq.setBindHost(fromHost);
if (Debug.isOn() == true)
ctrlReq.print();
ActionResponse ctrlRes = ctrlReq.post();

View File

@@ -108,6 +108,9 @@ public class ControlPoint implements HTTPRequestListener
private final static String DEFAULT_EVENTSUB_URI = "/evetSub";
// I2P
private static final boolean ALLOW_IPV6_LOCATION = true;
////////////////////////////////////////////////
// Member
////////////////////////////////////////////////
@@ -277,15 +280,20 @@ public class ControlPoint implements HTTPRequestListener
Debug.warning("Ignoring localhost device at " + location);
return;
}
if (host.startsWith("[")) {
Debug.warning("Ignoring IPv6 device at " + location);
return;
if (host.startsWith("[") && host.endsWith("]")) {
if (!ALLOW_IPV6_LOCATION) {
Debug.warning("Ignoring IPv6 device at " + location);
return;
}
// fixup for valid checks below
host = host.substring(1, host.length() - 1);
}
if (!"http".equals(locationUrl.getProtocol())) {
Debug.warning("Ignoring non-http device at " + location);
return;
}
if (!Addresses.isIPv4Address(host)) {
if (!Addresses.isIPv4Address(host) &&
(!ALLOW_IPV6_LOCATION || !Addresses.isIPv6Address(host))) {
Debug.warning("Ignoring non-IPv4 address at " + location);
return;
}
@@ -294,7 +302,7 @@ public class ControlPoint implements HTTPRequestListener
Debug.warning("Ignoring bad IP at " + location);
return;
}
if (TransportUtil.isPubliclyRoutable(ip, false)) {
if (TransportUtil.isPubliclyRoutable(ip, ALLOW_IPV6_LOCATION)) {
Debug.warning("Ignoring public address at " + location);
return;
}

View File

@@ -731,9 +731,18 @@ public class Device implements org.cybergarage.http.HTTPRequestListener,
}
public SSDPPacket getSSDPPacket() {
return getSSDPPacket(false);
}
/**
* I2P for multiple location support
*
* @since 0.9.50
*/
public SSDPPacket getSSDPPacket(boolean preferIPv6) {
if (isRootDevice() == false)
return null;
return getDeviceData().getSSDPPacket();
return getDeviceData().getSSDPPacket(preferIPv6);
}
// //////////////////////////////////////////////
@@ -745,10 +754,19 @@ public class Device implements org.cybergarage.http.HTTPRequestListener,
}
public String getLocation() {
SSDPPacket packet = getSSDPPacket();
return getLocation(false);
}
/**
* I2P for multiple location support
*
* @since 0.9.50
*/
public String getLocation(boolean preferIPv6) {
SSDPPacket packet = getSSDPPacket(preferIPv6);
if (packet != null)
return packet.getLocation();
return getDeviceData().getLocation();
return getDeviceData().getLocation(preferIPv6);
}
// //////////////////////////////////////////////

View File

@@ -50,6 +50,9 @@ import org.cybergarage.upnp.*;
public class ControlRequest extends SOAPRequest
{
// I2P see setRequestHost();
private static final String WAN_IPV6_CONNECTION = "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1";
////////////////////////////////////////////////
// Constructor
////////////////////////////////////////////////
@@ -114,8 +117,13 @@ public class ControlRequest extends SOAPRequest
// Thanks for Rob van den Boomen <rob.van.den.boomen@philips.com> (02/17/04)
// BUGFIX, set urlbase from location string if not set in description.xml
if (postURL == null || postURL.length() <= 0)
postURL = service.getRootDevice().getLocation();
if (postURL == null || postURL.length() <= 0) {
// I2P
// if service is ipv6 service...
String type = service.getServiceType();
boolean preferIPv6 = WAN_IPV6_CONNECTION.equals(type);
postURL = service.getRootDevice().getLocation(preferIPv6);
}
String reqHost = HTTP.getHost(postURL);
int reqPort = HTTP.getPort(postURL);

View File

@@ -74,7 +74,7 @@ public class QueryRequest extends ControlRequest
{
Service service = stateVar.getService();
String ctrlURL = service.getControlURL();
//String ctrlURL = service.getControlURL();
setRequestHost(service);

View File

@@ -19,6 +19,8 @@ package org.cybergarage.upnp.xml;
import java.io.*;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;
import org.cybergarage.util.*;
import org.cybergarage.http.*;
@@ -27,6 +29,11 @@ import org.cybergarage.upnp.*;
import org.cybergarage.upnp.ssdp.*;
import org.cybergarage.upnp.device.*;
/**
*
* I2P added multiple location support
*
*/
public class DeviceData extends NodeData
{
public DeviceData()
@@ -61,12 +68,43 @@ public class DeviceData extends NodeData
////////////////////////////////////////////////
private String location = "";
private String location_ipv6 = "";
public String getLocation() {
return location;
return getLocation(false);
}
/**
* I2P for multiple location support
*
* @since 0.9.50
*/
public String getLocation(boolean preferIPv6) {
if (preferIPv6) {
if (location_ipv6 != null && !location_ipv6.isEmpty())
return location_ipv6;
return location;
} else {
if (location != null && !location.isEmpty())
return location;
return location_ipv6;
}
}
public void setLocation(String location) {
if (location != null) {
try {
URL url = new URL(location);
String host = url.getHost();
if (host != null && host.startsWith("[")) {
location_ipv6 = location;
return;
}
} catch (MalformedURLException me) {
Debug.warning("Bad location: " + location, me);
return;
}
}
this.location = location;
}
@@ -241,12 +279,44 @@ public class DeviceData extends NodeData
////////////////////////////////////////////////
private SSDPPacket ssdpPacket = null;
private SSDPPacket ssdpPacket_ipv6 = null;
public SSDPPacket getSSDPPacket() {
return ssdpPacket;
return getSSDPPacket(false);
}
/**
* I2P for multiple location support
*
* @since 0.9.50
*/
public SSDPPacket getSSDPPacket(boolean preferIPv6) {
if (preferIPv6) {
if (ssdpPacket_ipv6 != null)
return ssdpPacket_ipv6;
return ssdpPacket;
} else {
if (ssdpPacket != null)
return ssdpPacket;
return ssdpPacket_ipv6;
}
}
public void setSSDPPacket(SSDPPacket packet) {
String location = packet.getLocation();
if (location != null) {
try {
URL url = new URL(location);
String host = url.getHost();
if (host != null && host.startsWith("[")) {
ssdpPacket_ipv6 = packet;
return;
}
} catch (MalformedURLException me) {
Debug.warning("Bad location: " + location, me);
return;
}
}
ssdpPacket = packet;
}

View File

@@ -71,12 +71,13 @@ public abstract class Parser
throw new ParserException("Not HTTP");
String host = locationURL.getHost();
if (host == null ||
!Addresses.isIPv4Address(host) ||
host.startsWith("127."))
throw new ParserException("Bad host " + host);
if (host.startsWith("[") && host.endsWith("]"))
host = host.substring(1, host.length() - 1);
byte[] ip = Addresses.getIP(host);
if (ip == null ||
TransportUtil.isPubliclyRoutable(ip, false))
TransportUtil.isPubliclyRoutable(ip, true))
throw new ParserException("Bad host " + host);
int port = locationURL.getPort();