/// <summary> /// Creates and adds a new connection mapping to the NAT. /// </summary> /// <param name="networkPort">The network interface number of the inside node.</param> /// <param name="insideNode">The inside node.</param> /// <param name="outsideNode">The outside node.</param> /// <param name="connection">The <see cref="NatConnection{TPacket, TNode}"/> that is created.</param> private void CreateMapping(int networkPort, TNode insideNode, TNode outsideNode, out NatConnection <TPacket, TNode> connection) { // Get the node which the outside node will see as the source. E.g. the NAT with a new TCP port var natNode = CreateMasqueradeNode(OutsideFacingAddress, Port_Drop, PaxConfig.deviceMap[Port_Outside].MacAddress); // Create connection object connection = new NatConnection <TPacket, TNode>(insideNode, outsideNode, natNode, GetInitialStateForNewConnection()); // Add to NAT_MapToOutside var toOutsideKey = new ConnectionKey(insideNode, outsideNode); NAT_MapToOutside[toOutsideKey] = connection; // Add to NAT_MapToInside var toInsideKey = new ConnectionKey(outsideNode, natNode); NAT_MapToInside[toInsideKey] = connection; #if DEBUG Console.WriteLine("Added mapping"); Console.WriteLine("Inside: {0}", insideNode); Console.WriteLine("Outside: {0}", outsideNode); Console.WriteLine("Nat: {0}", natNode); PrintMappings(); #endif }
/// <summary> /// Remove connections that have timed out or are closed. /// </summary> public void GarbageCollectConnections() { bool removedAny = false; DateTime now = DateTime.Now; foreach (var pair in NAT_MapToInside) { NatConnection <TPacket, TNode> connection = pair.Value; bool removeEntry = false; if (now - connection.LastUsed > InactivityTimeout) { removeEntry = true; #if DEBUG Console.WriteLine("Removing inactive connection (LastUsed {0}, Diff {1}, InactivityTimeout {2})", connection.LastUsed.ToShortTimeString(), (now - connection.LastUsed).ToString(), InactivityTimeout); #endif } else if (connection.State.CanBeClosed) { removeEntry = true; #if DEBUG Console.WriteLine("Removing closed connection (LastUsed {0}, Diff {1}, InactivityTimeout {2})", connection.LastUsed.ToShortTimeString(), (now - connection.LastUsed).ToString(), InactivityTimeout); #endif } if (removeEntry) { // Remove this connection from both lookups NAT_MapToInside.Remove(pair); NAT_MapToOutside.Remove(new ConnectionKey(connection.InsideNode, connection.OutsideNode)); #if DEBUG removedAny = true; #endif } } #if DEBUG if (removedAny) { PrintMappings(); } #endif // FIXME - currently O(n); improve performance for sparse traffic. // Could use a regularly invoked GC, and keep the connections in one of two pools: // - For connections with lower traffic, keep a double-LL of MRU, moving the connection to the head when used, // and start at the LRU end when iterating. Needs to be concurrent. // Cost is per packet, and maintains an ordering, meaning we only need to check those that have expired plus one extra. // - For connections with higher traffic, it would be less expensive to leave unsorted and iterate in O(n). // However, this would add complexity in terms of tracking which pool each connection should be in. }