sbstp / rust-igd Goto Github PK
View Code? Open in Web Editor NEWInternet Gateway Device (UPNP) client
Home Page: https://docs.rs/igd/
License: MIT License
Internet Gateway Device (UPNP) client
Home Page: https://docs.rs/igd/
License: MIT License
See https://seanmonstar.com/blog/hyper-v1/ for details
I am the author of vpncloud (https://github.com/dswd/vpncloud) and I am using the igd crate to establish port forwardings in NAT routers. Many thanks for the great crate by the way.
Since version 0.7 I experience the problem, that the vpncloud binary can't be closed via ctrl-c as my custom signal traps do not work anymore. It seems that since 0.7 something swallows all signals.
If you want to test it, you can use my current code, compile the binary and run vpncloud --type dummy
. If you upgrade idg to 0.7 ctrl-c will stop working.
Do you have any idea on how to prevent this?
Any help will be greatly appreciated.
Hi, is there interest in properly parsing the XML documents received through the wire or is it too much overkill?
I found your library a few days ago and I struggled to get your examples to work with my router, I always ended up with error code 402.
After comparing the library with miniupnp (which works with my router), I found out that the order of arguments that are sent to the router is different. With your library, the body looks like:
<?xml version="1.0"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body>
<u:AddPortMapping xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1">
<NewProtocol>TCP</NewProtocol>
<NewExternalPort>12345</NewExternalPort>
<NewInternalClient>192.168.0.115</NewInternalClient>
<NewInternalPort>12345</NewInternalPort>
<NewLeaseDuration>60</NewLeaseDuration>
<NewPortMappingDescription>crust</NewPortMappingDescription>
<NewEnabled>1</NewEnabled>
<NewRemoteHost></NewRemoteHost>
</u:AddPortMapping>
</s:Body>
</s:Envelope>
While miniupnp produces the following body:
<?xml version="1.0"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body>
<u:AddPortMapping xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1">
<NewRemoteHost></NewRemoteHost>
<NewExternalPort>12345</NewExternalPort>
<NewProtocol>TCP</NewProtocol>
<NewInternalPort>12345</NewInternalPort>
<NewInternalClient>192.168.0.115</NewInternalClient>
<NewEnabled>1</NewEnabled>
<NewPortMappingDescription>libminiupnpc</NewPortMappingDescription>
<NewLeaseDuration>60</NewLeaseDuration>
</u:AddPortMapping>
</s:Body>
</s:Envelope>
Note, that only the order of arguments is different. In fact, this is the only reason, why miniupnp works, while your library doesn't.
The routers that provide UPnP functionality also provide a schema document, describing the actions and arguments. According to the Spec (https://openconnectivity.org/upnp-specs/UPnP-arch-DeviceArchitecture-v2.0-20200417.pdf, page 79):
Every βinβ argument in the definition of the action in the service description shall be included, in the same order as specified in the service description (SCPD) that is available from the device.
I am currently working on a method to parse this SCPD (XML) and generate the Action body exactly as requested. Would you be willing to include this as a Pull-Request once I am done? Or are you by chance already working on the same issue?
(EDIT: Fixed wrong page number and description)
I'd love to get the IPv6 support, as of now, IPv6 doesn't really work and the external IP isn't fetched.
I think that the problem is here, as it returns Ipv4Addr
instead of the universal one IpAddr
.
It would be very useful to have support for GetListOfPortMappings() to get information about existing mappings, such that e.g. an application can choose a different port if it's already used by another one.
Is there a futures aware and tokio compatible version planned?
My Sky router advertises WANPPPConnection but not WANIPConnection:
<?xml version="1.0"?>
<root xmlns="urn:schemas-upnp-org:device-1-0">
<specVersion>
<major>1</major>
<minor>0</minor>
</specVersion>
<URLBase>http://192.168.0.1:5431/</URLBase>
<device>
<deviceType>urn:schemas-upnp-org:device:InternetGatewayDevice:1</deviceType>
<presentationURL>http://192.168.0.1:80/</presentationURL>
<friendlyName>Sky ADSL Router</friendlyName>
<manufacturer>Sky Hub</manufacturer>
<manufacturerURL>http://www.sky.com/</manufacturerURL>
<modelDescription>(null)</modelDescription>
<modelName>SR102</modelName>
<modelNumber>1.0</modelNumber>
<modelURL>http://www.broadcom.com/</modelURL>
<UDN>uuid:c03e0f91-77c4-c477-910f-3ec03e91c40000</UDN>
<serviceList>
<service>
<serviceType>urn:schemas-upnp-org:service:Layer3Forwarding:1</serviceType>
<serviceId>urn:upnp-org:serviceId:Layer3Forwarding.1</serviceId>
<controlURL>/uuid:c03e0f91-77c4-c477-910f-3ec03e91c40000/Layer3Forwarding:1</controlURL>
<eventSubURL>/uuid:c03e0f91-77c4-c477-910f-3ec03e91c40000/Layer3Forwarding:1</eventSubURL>
<SCPDURL>/dynsvc/Layer3Forwarding:1.xml</SCPDURL>
</service>
</serviceList>
<deviceList>
<device>
<deviceType>urn:schemas-upnp-org:device:WANDevice:1</deviceType>
<friendlyName>WANDevice.1</friendlyName>
<manufacturer>Sky Hub</manufacturer>
<manufacturerURL>http://www.sky.com/</manufacturerURL>
<modelDescription>(null)</modelDescription>
<modelName>SR102</modelName>
<modelNumber>1.0</modelNumber>
<modelURL>http://www.broadcom.com/</modelURL>
<UDN>uuid:c03e0f91-77c4-c477-910f-3ec03e91c40001</UDN>
<serviceList>
<service>
<serviceType>urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1</serviceType>
<serviceId>urn:upnp-org:serviceId:WANCommonInterfaceConfig.1</serviceId>
<controlURL>/uuid:c03e0f91-77c4-c477-910f-3ec03e91c40001/WANCommonInterfaceConfig:1</controlURL>
<eventSubURL>/uuid:c03e0f91-77c4-c477-910f-3ec03e91c40001/WANCommonInterfaceConfig:1</eventSubURL>
<SCPDURL>/dynsvc/WANCommonInterfaceConfig:1.xml</SCPDURL>
</service>
</serviceList>
<deviceList>
<device>
<deviceType>urn:schemas-upnp-org:device:WANConnectionDevice:1</deviceType>
<friendlyName>WanConnectionDevice.216</friendlyName>
<manufacturer>Sky Hub</manufacturer>
<manufacturerURL>http://www.sky.com/</manufacturerURL>
<modelDescription>(null)</modelDescription>
<modelName>SR102</modelName>
<modelNumber>1.0</modelNumber>
<modelURL>http://www.broadcom.com/</modelURL>
<UDN>uuid:c03e0f91-77c4-c477-910f-3ec03e91c40002</UDN>
<serviceList>
<service>
<serviceType>urn:schemas-upnp-org:service:WANPPPConnection:1</serviceType>
<serviceId>urn:upnp-org:serviceId:WANPPPConnection.1</serviceId>
<controlURL>/uuid:c03e0f91-77c4-c477-910f-3ec03e91c40002/WANPPPConnection:1</controlURL>
<eventSubURL>/uuid:c03e0f91-77c4-c477-910f-3ec03e91c40002/WANPPPConnection:1</eventSubURL>
<SCPDURL>/dynsvc/WANPPPConnection:1.xml</SCPDURL>
</service>
</serviceList>
</device>
</deviceList>
</device>
</deviceList>
</device>
</root>
They work in the same way though (with WANPPPConnection supporting more methods), so supporting them both should be pretty easy.
Spec, AddPortMapping
& DeletePortMapping
I'm not sure what the differences between InternetGatewayDevice:1 and InternetGatewayDevice:2 are, but I've found this:
IGDv2 is backwards compatible with IGDv1, meaning a device which advertises support for InternetGatewayDevice:2 implicitly also supports InternetGatewayDevice:1
If that's the case, implementing it is just a matter of executing two searches in search_gateway_from_timeout
(with v1 and v2) instead of just one (with v1).
The device usually sends a URL that contains an XML document describing its configuration.
This is possibly a similar issue to #47. However in this case no special IPv6 support is desired, just the ability to map a IPv4 port.
$ cargo run --features=aio --example aio 10.1.1.129:4321
Finished dev [unoptimized + debuginfo] target(s) in 0.06s
Running `target/debug/examples/aio '10.1.1.129:4321'`
06:17:20 [DEBUG] (1) igd::aio::search: sending broadcast request to: 239.255.255.250:1900 on interface: Ok(V4(0.0.0.0:53615))
06:17:20 [DEBUG] (1) igd::aio::search: received broadcast response from: 10.1.1.1:1900
06:17:20 [DEBUG] (1) igd::aio::search: handling broadcast response from: 10.1.1.1:1900
Faild to find IGD: Invalid response
A look with tshark shows this packet going out to 239.255.255.250:
Simple Service Discovery Protocol
M-SEARCH * HTTP/1.1\r\n
[Expert Info (Chat/Sequence): M-SEARCH * HTTP/1.1\r\n]
[M-SEARCH * HTTP/1.1\r\n]
[Severity level: Chat]
[Group: Sequence]
Request Method: M-SEARCH
Request URI: *
Request Version: HTTP/1.1
Host:239.255.255.250:1900\r\n
ST:urn:schemas-upnp-org:device:InternetGatewayDevice:1\r\n
Man:"ssdp:discover"\r\n
MX:3\r\n
\r\n
[Full request URI: http://239.255.255.250:1900*]
[HTTP request 1/1]
and the response from my OpenWRT router at 10.1.1.1:
Simple Service Discovery Protocol
HTTP/1.1 200 OK\r\n
[Expert Info (Chat/Sequence): HTTP/1.1 200 OK\r\n]
[HTTP/1.1 200 OK\r\n]
[Severity level: Chat]
[Group: Sequence]
Response Version: HTTP/1.1
Status Code: 200
[Status Code Description: OK]
Response Phrase: OK
CACHE-CONTROL: max-age=120\r\n
ST: urn:schemas-upnp-org:device:InternetGatewayDevice:1\r\n
USN: uuid:2569469e-5c8a-49c7-a65b-f83ef5f2a517::urn:schemas-upnp-org:device:InternetGatewayDevice:1\r\n
EXT:\r\n
SERVER: OpenWRT/19.07-SNAPSHOT UPnP/1.1 MiniUPnPd/2.1.20191006\r\n
LOCATION: http://[fdb6:cbcf:8a09::1]:5000/rootDesc.xml\r\n
OPT: "http://schemas.upnp.org/upnp/1/0/"; ns=01\r\n
01-NLS: 1592621464\r\n
BOOTID.UPNP.ORG: 1592621464\r\n
CONFIGID.UPNP.ORG: 1337\r\n
\r\n
[HTTP response 1/1]
Note the location field has a IPv6 address. It looks like MiniUPnPd sends two responses - both from 10.1.1.1 - the first one with the IPv6 address and another with the IPv4 address:
Simple Service Discovery Protocol
HTTP/1.1 200 OK\r\n
[Expert Info (Chat/Sequence): HTTP/1.1 200 OK\r\n]
[HTTP/1.1 200 OK\r\n]
[Severity level: Chat]
[Group: Sequence]
Response Version: HTTP/1.1
Status Code: 200
[Status Code Description: OK]
Response Phrase: OK
CACHE-CONTROL: max-age=120\r\n
ST: urn:schemas-upnp-org:device:InternetGatewayDevice:1\r\n
USN: uuid:2569469e-5c8a-49c7-a65b-f83ef5f2a517::urn:schemas-upnp-org:device:InternetGatewayDevice:1\r\n
EXT:\r\n
SERVER: OpenWRT/19.07-SNAPSHOT UPnP/1.1 MiniUPnPd/2.1.20191006\r\n
LOCATION: http://10.1.1.1:5000/rootDesc.xml\r\n
OPT: "http://schemas.upnp.org/upnp/1/0/"; ns=01\r\n
01-NLS: 1592621464\r\n
BOOTID.UPNP.ORG: 1592621464\r\n
CONFIGID.UPNP.ORG: 1337\r\n
\r\n
[HTTP response 2/2]
[Prev response in frame: 2]
And I think the bug is that the library is seeing the IPv6 response first and failing. It it not waiting for the IPv4 response.
For comparison, this is what the miniupnpc test client discovers:
$ upnpc -P
upnpc : miniupnpc library test client, version 2.1.
(c) 2005-2018 Thomas Bernard.
Go to http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
for more information.
List of UPNP devices found on the network :
desc: http://10.1.1.1:5000/rootDesc.xml
st: urn:schemas-upnp-org:device:InternetGatewayDevice:1
desc: http://[fdb6:cbcf:8a09::1]:5000/rootDesc.xml
st: urn:schemas-upnp-org:device:InternetGatewayDevice:1
Found valid IGD : http://10.1.1.1:5000/ctl/IPConn
Local LAN ip address : fdb6:cbcf:8a09:0:d065:6971:abe7:e483
Presentation URL found:
http://10.1.1.1/
I'm not sure if I'm just doing something stupid or if my router is completely and utterly broken but I get the above error when executing any of the example code.
extern crate igd;
use igd::*;
use std::time::Duration;
use std::net::{SocketAddr};
fn main() {
let opt = SearchOptions{
bind_addr: "0.0.0.0:0".parse::<SocketAddr>().unwrap(),
broadcast_address: "239.255.255.250:1900".parse::<SocketAddr>().unwrap(),
timeout: Some(Duration::from_secs(5)),
};
match igd::search_gateway(opt) {
Err(ref err) => println!("Error: {}", err),
Ok(gateway) => {
match gateway.get_external_ip() {
Err(ref err) => {
println!("There was an error! {}", err);
},
Ok(ext_addr) => {
println!("Local gateway: {}, External ip address: {}", gateway, ext_addr);
},
}
},
}
}
It is worth noting that I tested this on a few friend's routers which also had upnp enabled but got the same error, I decreased the timeout on the SearchOptions just to be able to test a little quicker but it fails regardless.
EDIT:
I've managed to find out that the code is complaining about an invalid response in particular:
<?xml version="1.0"?>
<root xmlns="urn:schemas-upnp-org:device-1-0">
<specVersion>
<major>1</major>
<minor>0</minor>
</specVersion>
<URLBase>http://10.0.0.2:5431/</URLBase>
<device>
<deviceType>urn:schemas-upnp-org:device:InternetGatewayDevice:1</deviceType>
<presentationURL>http://10.0.0.2:80/</presentationURL>
<friendlyName>Broadcom xDSL Router</friendlyName>
<manufacturer>D-Link</manufacturer>
<manufacturerURL>http://www.broadcom.com/</manufacturerURL>
<modelDescription>DSL-G225</modelDescription>
<modelName>DSL-G225</modelName>
<modelNumber>1.0</modelNumber>
<modelURL>http://www.broadcom.com/</modelURL>
<UDN>uuid:10bef592-a26d-6da2-92f5-be10be926d0000</UDN>
<serviceList>
<service>
<serviceType>urn:schemas-upnp-org:service:Layer3Forwarding:1</serviceType>
<serviceId>urn:upnp-org:serviceId:Layer3Forwarding.1</serviceId>
<controlURL>/uuid:10bef592-a26d-6da2-92f5-be10be926d0000/Layer3Forwarding:1</controlURL>
<eventSubURL>/uuid:10bef592-a26d-6da2-92f5-be10be926d0000/Layer3Forwarding:1</eventSubURL>
<SCPDURL>/dynsvc/Layer3Forwarding:1.xml</SCPDURL>
</service>
</serviceList>
<deviceList>
<device>
<deviceType>urn:schemas-upnp-org:device:WANDevice:1</deviceType>
<friendlyName>WANDevice.1</friendlyName>
<manufacturer>D-Link</manufacturer>
<manufacturerURL>http://www.broadcom.com/</manufacturerURL>
<modelDescription>DSL-G225</modelDescription>
<modelName>DSL-G225</modelName>
<modelNumber>1.0</modelNumber>
<modelURL>http://www.broadcom.com/</modelURL>
<UDN>uuid:10bef592-a26d-6da2-92f5-be10be926d0001</UDN>
<serviceList>
<service>
<serviceType>urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1</serviceType>
<serviceId>urn:upnp-org:serviceId:WANCommonInterfaceConfig.1</serviceId>
<controlURL>/uuid:10bef592-a26d-6da2-92f5-be10be926d0001/WANCommonInterfaceConfig:1</controlURL>
<eventSubURL>/uuid:10bef592-a26d-6da2-92f5-be10be926d0001/WANCommonInterfaceConfig:1</eventSubURL>
<SCPDURL>/dynsvc/WANCommonInterfaceConfig:1.xml</SCPDURL>
</service>
</serviceList>
<deviceList>
<device>
<deviceType>urn:schemas-upnp-org:device:WANConnectionDevice:1</deviceType>
<friendlyName>WanConnectionDevice.1</friendlyName>
<manufacturer>D-Link</manufacturer>
<manufacturerURL>http://www.broadcom.com/</manufacturerURL>
<modelDescription>DSL-G225</modelDescription>
<modelName>DSL-G225</modelName>
<modelNumber>1.0</modelNumber>
<modelURL>http://www.broadcom.com/</modelURL>
<UDN>uuid:10bef592-a26d-6da2-92f5-be10be926d0002</UDN>
<serviceList>
<service>
<serviceType>urn:schemas-upnp-org:service:WANPPPConnection:1</serviceType>
<serviceId>urn:upnp-org:serviceId:WANPPPConnection.1</serviceId>
<controlURL>/uuid:10bef592-a26d-6da2-92f5-be10be926d0002/WANPPPConnection:1</controlURL>
<eventSubURL>/uuid:10bef592-a26d-6da2-92f5-be10be926d0002/WANPPPConnection:1</eventSubURL>
<SCPDURL>/dynsvc/WANPPPConnection:1.xml</SCPDURL>
</service>
</serviceList>
</device>
</deviceList>
</device>
</deviceList>
</device>
</root>
A declarative, efficient, and flexible JavaScript library for building user interfaces.
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. πππ
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google β€οΈ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.