예제 #1
0
        private void CreatePortMapListen(UdpClient udpClient, Mapping mapping)
        {
            IPEndPoint endPoint = new IPEndPoint(LocalAddress, PmpConstants.ServerPort);

            while (true)
            {
                byte[] data = udpClient.Receive(ref endPoint);

                if (data.Length < 16)
                {
                    continue;
                }

                if (data[0] != PmpConstants.Version)
                {
                    continue;
                }

                byte opCode = (byte)(data[1] & 127);

                NetworkProtocolType protocol = NetworkProtocolType.Tcp;
                if (opCode == PmpConstants.OperationCodeUdp)
                {
                    protocol = NetworkProtocolType.Udp;
                }

                short resultCode = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(data, 2));
                int   epoch      = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(data, 4));

                short privatePort = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(data, 8));
                short publicPort  = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(data, 10));

                uint lifetime = (uint)IPAddress.NetworkToHostOrder(BitConverter.ToInt32(data, 12));

                if (privatePort < 0 || publicPort < 0 || resultCode != PmpConstants.ResultCodeSuccess)
                {
                    string[] errors = new[]
                    {
                        "Success",
                        "Unsupported Version",
                        "Not Authorized/Refused (e.g. box supports mapping, but user has turned feature off)"
                        ,
                        "Network Failure (e.g. NAT box itself has not obtained a DHCP lease)",
                        "Out of resources (NAT box cannot create any more mappings at this time)",
                        "Unsupported opcode"
                    };
                    throw new MappingException(resultCode, errors[resultCode]);
                }

                if (lifetime == 0)
                {
                    return;                                //mapping was deleted
                }
                //mapping was created
                //TODO: verify that the private port+protocol are a match
                mapping.PublicPort          = publicPort;
                mapping.NetworkProtocolType = protocol;
                mapping.Expiration          = DateTime.Now.AddSeconds(lifetime);
                return;
            }
        }
예제 #2
0
 public override Task DeletePortMapAsync(Mapping mapping)
 {
     return(InternalCreatePortMapAsync(mapping, false)
            .TimeoutAfter(TimeSpan.FromSeconds(4))
            .ContinueWith(t => UnregisterMapping(mapping)));
 }
예제 #3
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;
                }
            });
        }
예제 #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;
                    }
                }
            }));
        }
예제 #5
0
 /// <summary>
 /// Deletes a mapped port asynchronous.
 /// </summary>
 /// <param name="mapping">The <see cref="Mapping">Mapping</see> entry.</param>
 /// <example>
 /// device.DeletePortMapAsync(new Mapping(Protocol.Tcp, 1700, 1600));
 /// </example>
 /// <exception cref="MappingException">MappingException-class</exception>
 public abstract Task DeletePortMapAsync(Mapping mapping);
예제 #6
0
 /// <summary>
 /// Creates the port map asynchronous.
 /// </summary>
 /// <param name="mapping">The <see cref="Mapping">Mapping</see> entry.</param>
 /// <example>
 /// device.CreatePortMapAsync(new Mapping(Protocol.Tcp, 1700, 1600));
 /// </example>
 /// <exception cref="MappingException">MappingException</exception>
 public abstract Task CreatePortMapAsync(Mapping mapping);
예제 #7
0
 protected void UnregisterMapping(Mapping mapping)
 {
     _openedMapping.RemoveWhere(x => x.Equals(mapping));
 }
예제 #8
0
 protected void RegisterMapping(Mapping mapping)
 {
     _openedMapping.Remove(mapping);
     _openedMapping.Add(mapping);
 }
 public CreatePortMappingRequestMessage(Mapping mapping)
 {
     _mapping = mapping;
 }