alanmcgovern / mono.nat Goto Github PK
View Code? Open in Web Editor NEWUPNP and NAT-PMP port forwarding for .NET
Home Page: https://github.com/mono/Mono.Nat
License: MIT License
UPNP and NAT-PMP port forwarding for .NET
Home Page: https://github.com/mono/Mono.Nat
License: MIT License
Hello,
Thank you for this project.
I've created a fork named SharpOpenNat
for multi-targeting .Net 8.0, .Net 6.0, .Net 4.8, and .Net Standard 2.0.
I am currently working on an application which uses uPNP to open ports for P2P communication. I am using DI quite heavily, and would like to be able to inject the uPNP searcher through that, rather than going through the global. Because I need to perform operations based primarily on the capabilities of the network adapter, I am currently manually polling with NatUtility.Search(gatewayIp)
, using the gateway I've identified for the interface I'm targeting.
In addition, having a public API that does not have global state makes it much easier to test around, as well as being easier to write code with thread-safety.
Of course, I could also just be missing something that is already present that does exactly this. ๐
The problem is that the code will just block indefinitely at the line:
Mapping = await Device.CreatePortMapAsync(mapping);
So I just looked into the CreatePortMapAsync method and I just found that the code block at: (It's in the UpnpNatDevice class)
var response = await SendMessageAsync (message).ConfigureAwait (false);
So I looked in the SendMessageAsync method and I found that is blocks at:
using (var response = await request.GetResponseAsync().ConfigureAwait(false))
Do you have a solution for this problem ? (My modem supports UPnP)
I am using Unity with the target as .NET Standard 2.0
Thanks for your help !
and:
Here's my code with the Start() function my entry point.
public static class NatTraversal {
public static INatDevice Device;
public static Mapping Mapping;
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
public static void Start() {
// Subscribe to the quitting event
Application.quitting += Stop;
// Subscribe to the device found event
NatUtility.DeviceFound += OnDeviceFound;
NatUtility.StartDiscovery();
Debug.Log("[NAT] Started discovery");
}
public async static void Stop() {
// If we found a device
if (Mapping != null && Device != null) {
// Delete the port map
await Device.DeletePortMapAsync(Mapping);
}
// Unsubscribe from the quitting event
Application.quitting -= Stop;
// Stop the discovery
NatUtility.StopDiscovery();
Debug.Log("[NAT] Stopped discovery");
}
public static async void OnDeviceFound(object sender, DeviceEventArgs e) {
// Stop the discovery
NatUtility.StopDiscovery();
Debug.Log("[NAT] Found a device, stop discovery");
// Create the mapping
Mapping mapping = new Mapping(Protocol.Udp, 7777, 7777, int.MaxValue, "NetworkPrototyping");
Debug.Log("[NAT] Mapping created");
Device = e.Device;
Mapping = await Device.CreatePortMapAsync(mapping);
Debug.Log("[NAT] Mapping created and applied");
}
}
Hi I would love to use this library, but I can't figure out how to use it....
Could you link some documentation (if any), or provide some basic documentation on how to use the library...
Hi,
I'm using MonoTorrent and want to clients can seed even if port not forwarded by it's router.
I've tried to use this utility, but with no luck, I still can't connect with the specified port.
Code example:
private async void DeviceFoundAsync(object sender, DeviceEventArgs e) {
await _locker.WaitAsync();
try {
INatDevice device = e.Device;
Mapping mapping = new Mapping(Protocol.Tcp, Core.TorrentClient.Port, Core.TorrentClient.Port);
await device.CreatePortMapAsync(mapping);
try {
Mapping m = await device.GetSpecificMappingAsync(Protocol.Tcp, Core.TorrentClient.Port);
} catch {
}
} catch (Exception exc) {
} finally {
_locker.Release();
}
}
Is this is correct?
Hi,
I would like to use Mono Nat to open a UDP port for an app I am developing. When trying to create a port mapping, I get the following exception "Mono.Nat.MappingException: Error ConflictInMappingEntry". I get this exception for any port number I try, regardless of udp/tcp. I see the following output for my log statement regarding Device details:
Device details: Upnp 4/4/2020 5:09:20 PM 192.168.1.1:49808
My router is Asus CM_AC2600 and upnp is enabled. Any ideas on where to go next? Router is reachable and has the services needed as far as i can tell. Code is attached below:
urn:schemas-upnp-org:device:WANDevice:1
WANDevice
MiniUPnP
private Mapping _currentMapping;
public int MIN_PORT => 42500;
public int MAX_PORT => 42900;
private void DeviceFound(object sender, DeviceEventArgs args)
{
Debug.Log("Device Found");
INatDevice device = args.Device;
Debug.Log($"Device details: {device.NatProtocol} {device.LastSeen} {device.DeviceEndpoint}");
try
{
for (int i = MIN_PORT; i < MAX_PORT; i++)
{
try
{
_currentMapping = device.CreatePortMap(new Mapping(Mono.Nat.Protocol.Udp, i, i));
break;
}
catch (Exception e)
{
Debug.Log($"port {i} in use, still scanning for port to open..., {e}");
}
}
Debug.Log($"We got map of public, {_currentMapping.PublicPort} private {_currentMapping.PrivatePort}");
}
catch (Exception e)
{
Debug.Log($"exception device: {e}");
}
}
Mono.Nat.MappingException: Error ConflictInMappingEntry: ConflictInMappingEntry
at Mono.Nat.Upnp.ResponseMessage.Decode (Mono.Nat.Upnp.UpnpNatDevice device, System.String message) [0x0009e] in :0
at Mono.Nat.Upnp.UpnpNatDevice+d__21.MoveNext () [0x001b6] in :0
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <599589bf4ce248909b8a14cbe4a2034e>:0
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0003e] in <599589bf4ce248909b8a14cbe4a2034e>:0
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] in <599589bf4ce248909b8a14cbe4a2034e>:0
at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00008] in <599589bf4ce248909b8a14cbe4a2034e>:0
at System.Runtime.CompilerServices.TaskAwaiter1[TResult].GetResult () [0x00000] in <599589bf4ce248909b8a14cbe4a2034e>:0 at Mono.Nat.Upnp.UpnpNatDevice+<SendMessageAsync>d__17.MoveNext () [0x00340] in <bb7a49cf350d4cdf92cc79833d23f455>:0 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <599589bf4ce248909b8a14cbe4a2034e>:0 at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0003e] in <599589bf4ce248909b8a14cbe4a2034e>:0 at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] in <599589bf4ce248909b8a14cbe4a2034e>:0 at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00008] in <599589bf4ce248909b8a14cbe4a2034e>:0 at System.Runtime.CompilerServices.ConfiguredTaskAwaitable
1+ConfiguredTaskAwaiter[TResult].GetResult () [0x00000] in <599589bf4ce248909b8a14cbe4a2034e>:0
at Mono.Nat.Upnp.UpnpNatDevice+d__12.MoveNext () [0x00083] in :0
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <599589bf4ce248909b8a14cbe4a2034e>:0
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0003e] in <599589bf4ce248909b8a14cbe4a2034e>:0
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] in <599589bf4ce248909b8a14cbe4a2034e>:0
at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00008] in <599589bf4ce248909b8a14cbe4a2034e>:0
at System.Runtime.CompilerServices.TaskAwaiter`1[TResult].GetResult () [0x00000] in <599589bf4ce248909b8a14cbe4a2034e>:0
at Mono.Nat.NatDeviceExtensions.CreatePortMap (Mono.Nat.INatDevice device, Mono.Nat.Mapping mapping) [0x0000d] in :0
After creating a port mapping just like this:
device.CreatePortMap(new Mapping(Protocol.Ucp, Port, Port));
and verifying it's in the devices map with:
foreach (Mapping portMap in device.GetAllMappings())
{
Console.WriteLine(portMap.ToString());
}
My port listener won't pick up any incoming messages from a client I have connected to the public IP of my router and the same port until I go into my router network manager and reload the firewall settings.
Same thing if the maps are deleted, it won't take effect until the router settings are reloaded.
I have an ARRIS TG1682G gateway with Xfinity (Comcast) ISP.
afaik there's no real way to programmatically solve this but I thought I'd at least put this out there for others to know
I use a router to expand my mesh, like a switch, and GetExternalIPAsync did throw "System.FormatException: An invalid IP address was specified". The string provided by the router was empty like this:
uPnP Response: , <?xml version="1.0" encoding="utf-8"?> <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <s:Body> <u:GetExternalIPAddressResponse xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1"> <NewExternalIPAddress></NewExternalIPAddress> </u:GetExternalIPAddressResponse> </s:Body> </s:Envelope>
I caught the exception so no big deal, was unsure if this is expected behavior though.
Great piece of code!
Hello,
First of all i would like to thank you such an awesome library to deal with p2p problems. That being said, my current network topology is fairly simple - I have a router (Lets call it RouteB) in front of my ISP router(RouteA). When I run NatConsole while being connected to RouteB, it does not return a public IP for forwarding.
But when I connect to RouteA, it gives public IP without any hitch - is there any way to traverse in a mesh/layers of router?
Thank you again! This question maybe dumb but I am trying to figure out a way forward.
HttpWebRequest
should not be used anymore https://docs.microsoft.com/en-us/dotnet/api/system.net.httpwebrequest?view=netstandard-2.0#remarks
I'm running this across my home network, but the code is never picking up my router, as it is also an access point - and the SSDP response is with "urn:schemas-wifialliance-org:device:WFADevice:1".
An ST to "urn:schemas-upnp-org:device:InternetGatewayDevice:1" actually returns the correct "view"of the device.
UpnpSearcher tries to initially match on "urn:schemas-upnp-org:service:WANPPPConnection"
or "urn:schemas-upnp-org:service:WANIPConnection", neither of which fit, so its services are not parsed.
As a later function looks the services of the detected item - shouldn't UpnpSearcher be checking devices?
ErrorMessage:
Kan ikke koble til den eksterne serveren
Data string:
HTTP/1.1 200 OK
CACHE-CONTROL: max-age=1800
DATE: Thu, 31 Oct 2019 16:10:07 GMT
EXT:
LOCATION: http://192.168.10.1:49152/gatedesc.xml
SERVER: Linux/3.10.12, UPnP/1.0, Portable SDK for UPnP devices/1.4.2
X-User-Agent: ZyXEL
ST: urn:schemas-upnp-org:service:WANIPConnection:1
USN: uuid:39f4c64e-1dd2-11b2-b754-5c6a804a34b8::urn:schemas-upnp-org:service:WANIPConnection:1
This is the error I get when the router sends a response.
I have enabled Upnp within my router, and I'm sure it works because of the response (obviously). But how come the library is unable to decode the response?
"Kan ikke koble til den eksterne serveren" means "Unable to connect to external server"
So I messaged the dot net foundation way back when it began and they indicated a cursory interest in adding this library to their projects.
Is that something you would be interested in @alanmcgovern ?
Trying to create a port mapping when one already exists does not error and continues (Or creates mapping). MappingError is not thrown.
[2020-08-15 19:47:37.213 +01:00] [INF] [5] Mono.Nat.Upnp.UpnpNatDevice: uPnP Response: , <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:DeletePortMappingResponse xmlns:u="DeletePortMapping"></u:DeletePortMappingResponse></s:Body></s:Envelope>
[2020-08-15 19:47:37.220 +01:00] [ERR] [5] Mono.Nat.Upnp.ResponseMessage: Unknown message returned. Please send me back the following XML: <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:DeletePortMappingResponse xmlns:u="DeletePortMapping"></u:DeletePortMappingResponse></s:Body></s:Envelope>
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.