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; } }
public override Task DeletePortMapAsync(Mapping mapping) { return(InternalCreatePortMapAsync(mapping, false) .TimeoutAfter(TimeSpan.FromSeconds(4)) .ContinueWith(t => UnregisterMapping(mapping))); }
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; } }); }
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; } } })); }
/// <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);
/// <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);
protected void UnregisterMapping(Mapping mapping) { _openedMapping.RemoveWhere(x => x.Equals(mapping)); }
protected void RegisterMapping(Mapping mapping) { _openedMapping.Remove(mapping); _openedMapping.Add(mapping); }
public CreatePortMappingRequestMessage(Mapping mapping) { _mapping = mapping; }