Ejemplo n.º 1
0
        public override Task DeletePortMapAsync(Mapping mapping)
        {
            Guard.IsNotNull(mapping, "mapping");

            if (mapping.PrivateIP.Equals(IPAddress.None))
            {
                mapping.PrivateIP = DeviceInfo.LocalAddress;
            }

            NatDiscoverer.TraceSource.LogInfo("DeletePortMapAsync - Deleteing port mapping {0}", mapping);

            var message = new DeletePortMappingRequestMessage(mapping);

            return(_soapClient
                   .InvokeAsync("DeletePortMapping", message.ToXml())
                   .TimeoutAfter(TimeSpan.FromSeconds(4))
                   .ContinueWith(task =>
            {
                if (!task.IsFaulted)
                {
                    UnregisterMapping(mapping);
                }
                else
                {
                    MappingException e = task.Exception.InnerException as MappingException;
                    if (e != null && e.ErrorCode != UpnpConstants.NoSuchEntryInArray)
                    {
                        throw e;
                    }
                }
            }));
        }
Ejemplo n.º 2
0
        public override Task <Mapping> GetSpecificMappingAsync(Protocol protocol, int publicPort)
        {
            Guard.IsTrue(protocol == Protocol.Tcp || protocol == Protocol.Udp, "protocol");
            Guard.IsInRange(publicPort, 0, ushort.MaxValue, "port");

            NatDiscoverer.TraceSource.LogInfo("GetSpecificMappingAsync - Getting mapping for protocol: {0} port: {1}", Enum.GetName(typeof(Protocol), protocol), publicPort);

            var message = new GetSpecificPortMappingEntryRequestMessage(protocol, publicPort);

            return(_soapClient
                   .InvokeAsync("GetSpecificPortMappingEntry", message.ToXml())
                   .TimeoutAfter(TimeSpan.FromSeconds(4))
                   .ContinueWith(task =>
            {
                if (!task.IsFaulted)
                {
                    var responseData = task.Result;

                    var messageResponse = new GetPortMappingEntryResponseMessage(responseData, DeviceInfo.ServiceType, false);

                    return new Mapping(messageResponse.Protocol
                                       , IPAddress.Parse(messageResponse.InternalClient)
                                       , messageResponse.InternalPort
                                       , publicPort                  // messageResponse.ExternalPort is short.MaxValue
                                       , messageResponse.LeaseDuration
                                       , messageResponse.PortMappingDescription);
                }
                else
                {
                    MappingException e = task.Exception.InnerException as MappingException;
                    if (e != null && e.ErrorCode == UpnpConstants.NoSuchEntryInArray)
                    {
                        return null;
                    }

                    // DD-WRT Linux base router (and others probably) fails with 402-InvalidArgument
                    // when no mapping is found in the mappings table
                    if (e != null && e.ErrorCode == UpnpConstants.InvalidArguments)
                    {
                        NatDiscoverer.TraceSource.LogWarn("Router failed with 402-InvalidArgument. Mapping not found is assumed.");
                        return null;
                    }
                    throw task.Exception.InnerException;
                }
            }));
        }
Ejemplo n.º 3
0
        private async Task <Mapping> InternalCreatePortMapAsync(Mapping mapping, bool create)
        {
            List <byte> package = new List <byte>();

            package.Add(PmpConstants.Version);
            package.Add(mapping.NetworkProtocolType == NetworkProtocolType.Tcp ? PmpConstants.OperationCodeTcp : PmpConstants.OperationCodeUdp);
            package.Add(0);             //reserved
            package.Add(0);             //reserved
            package.AddRange(BitConverter.GetBytes(IPAddress.HostToNetworkOrder((short)mapping.PrivatePort)));
            package.AddRange(
                BitConverter.GetBytes(create ? IPAddress.HostToNetworkOrder((short)mapping.PublicPort) : (short)0));
            package.AddRange(BitConverter.GetBytes(IPAddress.HostToNetworkOrder(mapping.Lifetime)));

            try
            {
                byte[] buffer  = package.ToArray();
                int    attempt = 0;
                int    delay   = PmpConstants.RetryDelay;

                using (UdpClient udpClient = new UdpClient())
                {
                    CreatePortMapListen(udpClient, mapping);

                    while (attempt < PmpConstants.RetryAttempts)
                    {
                        await
                        udpClient.SendAsync(buffer, buffer.Length,
                                            new IPEndPoint(LocalAddress, PmpConstants.ServerPort));

                        attempt++;
                        delay *= 2;
                        Thread.Sleep(delay);
                    }
                }
            }
            catch (Exception e)
            {
                string type    = create ? "create" : "delete";
                string message = $"Failed to {type} portmap (protocol={mapping.NetworkProtocolType}, private port={mapping.PrivatePort})";
                NatDiscoverer.TraceSource.LogError(message);
                MappingException pmpException = e as MappingException;
                throw new MappingException(message, pmpException);
            }

            return(mapping);
        }
Ejemplo n.º 4
0
        public override Task CreatePortMapAsync(Mapping mapping)
        {
            Guard.IsNotNull(mapping, "mapping");
            if (mapping.PrivateIP.Equals(IPAddress.None))
            {
                mapping.PrivateIP = DeviceInfo.LocalAddress;
            }

            NatDiscoverer.TraceSource.LogInfo("CreatePortMapAsync - Creating port mapping {0}", mapping);

            var message = new CreatePortMappingRequestMessage(mapping);

            return(_soapClient
                   .InvokeAsync("AddPortMapping", message.ToXml())
                   .TimeoutAfter(TimeSpan.FromSeconds(4))
                   .ContinueWith(task =>
            {
                if (!task.IsFaulted)
                {
                    RegisterMapping(mapping);
                }
                else
                {
                    MappingException me = task.Exception.InnerException as MappingException;

                    if (me == null)
                    {
                        throw task.Exception.InnerException;
                    }

                    switch (me.ErrorCode)
                    {
                    case UpnpConstants.OnlyPermanentLeasesSupported:
                        NatDiscoverer.TraceSource.LogWarn(
                            "Only Permanent Leases Supported - There is no warranty it will be closed");
                        mapping.Lifetime = 0;
                        // We create the mapping anyway. It must be released on shutdown.
                        mapping.LifetimeType = MappingLifetime.ForcedSession;
                        CreatePortMapAsync(mapping);
                        break;

                    case UpnpConstants.SamePortValuesRequired:
                        NatDiscoverer.TraceSource.LogWarn(
                            "Same Port Values Required - Using internal port {0}", mapping.PrivatePort);
                        mapping.PublicPort = mapping.PrivatePort;
                        CreatePortMapAsync(mapping);
                        break;

                    case UpnpConstants.RemoteHostOnlySupportsWildcard:
                        NatDiscoverer.TraceSource.LogWarn("Remote Host Only Supports Wildcard");
                        mapping.PublicIP = IPAddress.None;
                        CreatePortMapAsync(mapping);
                        break;

                    case UpnpConstants.ExternalPortOnlySupportsWildcard:
                        NatDiscoverer.TraceSource.LogWarn("External Port Only Supports Wildcard");
                        throw me;

                    case UpnpConstants.ConflictInMappingEntry:
                        NatDiscoverer.TraceSource.LogWarn("Conflict with an already existing mapping");
                        throw me;

                    default:
                        throw me;
                    }
                }
            }));
        }
Ejemplo n.º 5
0
        public void GetGenericMappingAsync(int index, List <Mapping> mappings,
                                           TaskCompletionSource <IEnumerable <Mapping> > taskCompletionSource)
        {
            var message = new GetGenericPortMappingEntry(index);

            _soapClient
            .InvokeAsync("GetGenericPortMappingEntry", message.ToXml())
            .TimeoutAfter(TimeSpan.FromSeconds(4))
            .ContinueWith(task =>
            {
                if (!task.IsFaulted)
                {
                    var responseData    = task.Result;
                    var responseMessage = new GetPortMappingEntryResponseMessage(responseData,
                                                                                 DeviceInfo.ServiceType, true);

                    IPAddress internalClientIp;
                    if (!IPAddress.TryParse(responseMessage.InternalClient, out internalClientIp))
                    {
                        NatDiscoverer.TraceSource.LogWarn("InternalClient is not an IP address. Mapping ignored!");
                    }
                    else
                    {
                        var mapping = new Mapping(responseMessage.Protocol
                                                  , internalClientIp
                                                  , responseMessage.InternalPort
                                                  , responseMessage.ExternalPort
                                                  , responseMessage.LeaseDuration
                                                  , responseMessage.PortMappingDescription);
                        mappings.Add(mapping);
                    }

                    GetGenericMappingAsync(index + 1, mappings, taskCompletionSource);
                }
                else
                {
                    MappingException e = task.Exception.InnerException as MappingException;

                    if (e == null)
                    {
                        throw task.Exception.InnerException;
                    }

                    if (e.ErrorCode == UpnpConstants.SpecifiedArrayIndexInvalid ||
                        e.ErrorCode == UpnpConstants.NoSuchEntryInArray)
                    {
                        // there are no more mappings
                        taskCompletionSource.SetResult(mappings);
                        return;
                    }

                    // DD-WRT Linux base router (and others probably) fails with 402-InvalidArgument when index is out of range
                    if (e.ErrorCode == UpnpConstants.InvalidArguments)
                    {
                        NatDiscoverer.TraceSource.LogWarn("Router failed with 402-InvalidArgument. No more mappings is assumed.");
                        taskCompletionSource.SetResult(mappings);
                        return;
                    }

                    throw task.Exception.InnerException;
                }
            });
        }