From 3c6c88381e8f3e7ecb25afd1c691d11c91889aac Mon Sep 17 00:00:00 2001 From: Josh Dersch Date: Thu, 15 Oct 2015 16:47:45 -0700 Subject: [PATCH] Basics completed (still rough). No testing done (awaiting running Alto.) --- PUP/BSPManager.cs | 21 +++--- PUP/BreathOfLife.cs | 64 +++++++++++++++++ PUP/DirectoryServices.cs | 12 ++++ PUP/Dispatcher.cs | 113 ++++++++++++++++++++++++++++--- PUP/Entrypoint.cs | 22 +++++- PUP/IFS.csproj | 28 ++++++-- PUP/IFS.sln | 6 ++ PUP/Logging/Log.cs | 48 +++++++++++++ PUP/MiscServicesProtocol.cs | 7 +- PUP/Transport/Ethernet.cs | 53 ++++++++++----- PUP/Transport/PacketInterface.cs | 8 ++- 11 files changed, 336 insertions(+), 46 deletions(-) create mode 100644 PUP/BreathOfLife.cs create mode 100644 PUP/Logging/Log.cs diff --git a/PUP/BSPManager.cs b/PUP/BSPManager.cs index 753bc8a..3e976b1 100644 --- a/PUP/BSPManager.cs +++ b/PUP/BSPManager.cs @@ -25,7 +25,7 @@ namespace IFS _inputWriteEvent = new AutoResetEvent(false); - _inputQueue = new MemoryStream(65536); + _inputQueue = new Queue(65536); // TODO: init IDs, etc. based on RFC PUP _start_pos = _recv_pos = _send_pos = rfcPup.ID; @@ -161,13 +161,15 @@ namespace IFS _outputAckEvent.Set(); } + /* public void Mark(byte type); public void Interrupt(); public void Abort(int code, string message); public void Error(int code, string message); - public void End(); + public void End(); + */ // TODO: // Events for: @@ -235,10 +237,11 @@ namespace IFS case PupType.RFC: { BSPChannel newChannel = new BSPChannel(p); - _activeChannels.Add(newChannel.ClientPort.Socket); + _activeChannels.Add(newChannel.ClientPort.Socket, newChannel); return newChannel; } + break; case PupType.Data: case PupType.AData: @@ -253,11 +256,13 @@ namespace IFS break; case PupType.Ack: - BSPChannel channel = FindChannelForPup(p); + { + BSPChannel channel = FindChannelForPup(p); - if (channel != null) - { - channel.Ack(p); + if (channel != null) + { + channel.Ack(p); + } } break; @@ -267,7 +272,7 @@ namespace IFS if (channel != null) { - channel.EndReply(); + //channel.EndReply(); } } break; diff --git a/PUP/BreathOfLife.cs b/PUP/BreathOfLife.cs new file mode 100644 index 0000000..0bc09aa --- /dev/null +++ b/PUP/BreathOfLife.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IFS +{ + /// + /// Implements the BreathOfLife services. + /// It spins up a worker thread that wakes up every few seconds and broadcasts + /// a BreathOfLife packet. + /// + public class BreathOfLife + { + public BreathOfLife() + { + + } + + + /* + ushort[] _bolPacket = + { + 0,0, + + + + + 0022574, 0100000, 0040437, 0102000, 0034431, 0164000, + 0061005, 0102460, 0024567, 0034572, 0061006, 0024565, 0034570, 0061006, + 0024564, 0034566, 0061006, 0020565, 0034565, 0061005, 0125220, 0046573, + 0020576, 0061004, 0123400, 0030551, 0041211, 0004416, 0000000, 0001000, + 0000026, 0000244, 0000000, 0000000, 0000000, 0000000, 0000004, 0000000, + 0000000, 0000020, 0177777, 0055210, 0025400, 0107000, 0045400, 0041411, + 0020547, 0041207, 0020544, 0061004, 0006531, 0034517, 0030544, 0051606, + 0020510, 0041605, 0042526, 0102460, 0041601, 0020530, 0061004, 0021601, + 0101014, 0000414, 0061020, 0014737, 0000773, 0014517, 0000754, 0020517, + 0061004, 0030402, 0002402, 0000000, 0000732, 0034514, 0162414, 0000746, + 0021001, 0024511, 0106414, 0000742, 0021003, 0163400, 0035005, 0024501, + 0106415, 0175014, 0000733, 0021000, 0042465, 0034457, 0056445, 0055775, + 0055776, 0101300, 0041400, 0020467, 0041401, 0020432, 0041402, 0121400, + 0041403, 0021006, 0041411, 0021007, 0041412, 0021010, 0041413, 0021011, + 0041406, 0021012, 0041407, 0021013, 0041410, 0015414, 0006427, 0012434, + 0006426, 0020421, 0024437, 0134000, 0030417, 0002422, 0177035, 0000026, + 0000415, 0000427, 0000567, 0000607, 0000777, 0177751, 0177641, 0177600, + 0000225, 0177624, 0001013, 0000764, 0000431, 0000712, 0000634, 0000735, + 0000611, 0000567, 0000564, 0000566, 0000036, 0000002, 0000003, 0000015, + 0000030, 0000377, 0001000, 0177764, 0000436, 0054731, 0050750, 0020753, + 0040745, 0102460, 0040737, 0020762, 0061004, 0020734, 0105304, 0000406, + 0020743, 0101014, 0014741, 0000772, 0002712, 0034754, 0167700, 0116415, + 0024752, 0021001, 0106414, 0000754, 0021000, 0024703, 0106414, 0000750, + 0021003, 0163400, 0024736, 0106405, 0000404, 0121400, 0101404, 0000740, + 0044714, 0021005, 0042732, 0024664, 0122405, 0000404, 0101405, 0004404, + 0000727, 0010656, 0034654, 0024403, 0120500, 0101404, 0000777, 0040662, + 0040664, 0040664, 0102520, 0061004, 0020655, 0101015, 0000776, 0106415, + 0001400, 0014634, 0000761, 0020673, 0061004, 0000400, 0061005, 0102000, + 0143000, 0034672, 0024667, 0166400, 0061005, 0004670, 0020663, 0034664, + 0164000, 0147000, 0061005, 0024762, 0132414, 0133000, 0020636, 0034416, + 0101015, 0156415, 0131001, 0000754, 0024643, 0044625, 0101015, 0000750, + 0014623, 0004644, 0020634, 0061004, 0002000, 0176764, 0001401, 0041002 + }; */ + } +} diff --git a/PUP/DirectoryServices.cs b/PUP/DirectoryServices.cs index 16ab812..24b8edc 100644 --- a/PUP/DirectoryServices.cs +++ b/PUP/DirectoryServices.cs @@ -33,6 +33,18 @@ namespace IFS _localHost = new HostAddress(1, 34); } + public string AddressLookup(HostAddress address) + { + // TODO: actually look things up + return "Alto"; + } + + public HostAddress NameLookup(string hostName) + { + // TODO: actually look things up + return new HostAddress(1, 0x80); + } + public static DirectoryServices Instance { get { return _instance; } diff --git a/PUP/Dispatcher.cs b/PUP/Dispatcher.cs index 8065914..4b29e42 100644 --- a/PUP/Dispatcher.cs +++ b/PUP/Dispatcher.cs @@ -6,6 +6,9 @@ using System.Threading.Tasks; using IFS.Transport; using PcapDotNet.Packets; +using PcapDotNet.Packets.Ethernet; +using IFS.Logging; +using PcapDotNet.Base; namespace IFS { @@ -22,9 +25,7 @@ namespace IFS /// private Dispatcher() { - _dispatchMap = new Dictionary(); - - _packetInterface = new Ethernet(iface, OnPacketReceived); + _dispatchMap = new Dictionary(); } /// @@ -35,6 +36,13 @@ namespace IFS get { return _instance; } } + public void RegisterInterface(EthernetInterface i) + { + // TODO: support multiple interfaces (for gateway routing, for example.) + // Also, this should not be ethernet-specific. + _packetInterface = new Ethernet(i, OnPacketReceived); + } + /// /// Registers a new protocol with the dispatcher /// @@ -45,7 +53,7 @@ namespace IFS if (_dispatchMap.ContainsKey(entry.Socket)) { throw new InvalidOperationException( - String.Format("Socket {0} has already been registered for protocol {1}", impl.Socket, _dispatchMap[impl.Socket].FriendlyName)); + String.Format("Socket {0} has already been registered for protocol {1}", entry.Socket, _dispatchMap[entry.Socket].FriendlyName)); } _dispatchMap[entry.Socket] = entry; @@ -53,7 +61,41 @@ namespace IFS public void SendPup(PUP p) { - // TODO: Write PUP to ethernet + // + // Write PUP to ethernet: + // Get destination network & host address from PUP and route to correct ethernet address. + // For now, no actual routing (Gateway not implemented yet), everthing is on the same 'net. + // Just look up host address and find the MAC of the host to send it to. + // TODO: this translation should be at the Interface level, not here (we shouldn't be doing + // ethernet-specific things here -- at the moment it doesn't matter since we're only speaking + // ethernet, but this should be fixed.) + // + if (_pupToEthernetMap.ContainsKey(p.DestinationPort.Host)) + { + MacAddress destinationMac = _pupToEthernetMap[p.SourcePort.Host]; + + // Build the outgoing packet; place the source/dest addresses, type field and the PUP data. + EthernetLayer ethernetLayer = new EthernetLayer + { + Source = (MacAddress)_packetInterface.GetDeviceAddress(), + Destination = destinationMac, + EtherType = (EthernetType)512, // PUP type (TODO: move to constant) + }; + + PayloadLayer payloadLayer = new PayloadLayer + { + Data = new Datagram(p.RawData), + }; + + PacketBuilder builder = new PacketBuilder(ethernetLayer, payloadLayer); + + _packetInterface.SendPacket(builder.Build(DateTime.Now)); + } + else + { + // Log error, this should not happen. + Log.Write(LogLevel.Error, String.Format("PUP destination address {0} is unknown.", p.DestinationPort.Host)); + } } @@ -65,19 +107,64 @@ namespace IFS { PUP pup = new PUP(p.Ethernet.Payload.ToMemoryStream()); - if (_dispatchMap.ContainsKey(pup.DestinationPort.Socket)) + // + // Check the network -- if this is not network zero (coming from a host that doesn't yet know what + // network it's on) or the network we're on, we will ignore it (for now...). Once we implement + // Gateway services we will handle these appropriately. + // + if (pup.SourcePort.Network == 0 || pup.SourcePort.Network == DirectoryServices.Instance.LocalHostAddress.Network) { - PUPProtocolEntry entry = _dispatchMap[pup.DestinationPort.Socket]; - entry.ProtocolImplementation.RecvData(pup); + UpdateMACTable(pup, p); + + if (_dispatchMap.ContainsKey(pup.DestinationPort.Socket)) + { + PUPProtocolEntry entry = _dispatchMap[pup.DestinationPort.Socket]; + entry.ProtocolImplementation.RecvData(pup); + } + else + { + // Not a protocol we handle; TODO: log it. + Log.Write(LogLevel.UnhandledProtocol | LogLevel.DroppedPacket, String.Format("Unhandled PUP protocol, socket {0}, dropped packet.", pup.DestinationPort.Socket)); + } } else { - // Not a protocol we handle; TODO: log it. + // Not for our network; eventually we will look into routing... + Log.Write(LogLevel.DroppedPacket, String.Format("PUP is for network {0}, dropping.", pup.SourcePort.Network)); } } else { - // Not a PUP, Discard the packet. + // Not a PUP, Discard the packet. We will not log this to keep noise down. + //Log.Write(LogLevel.DroppedPacket, "Not a PUP. Dropping."); + } + } + + private void UpdateMACTable(PUP p, Packet e) + { + // + // See if we already have this entry. + // + if (_pupToEthernetMap.ContainsKey(p.SourcePort.Host)) + { + // + // We do; ensure that the mac addresses match -- if not we have a duplicate + // PUP id on the network. + // + if (_pupToEthernetMap[p.SourcePort.Host] != e.Ethernet.Source) + { + Log.Write(LogLevel.DuplicateHostNumber, + String.Format("Duplicate host number {0} for MAC {1} (currently mapped to MAC {2})", + p.SourcePort.Host, + e.Ethernet.Source, + _pupToEthernetMap[p.SourcePort.Host])); + } + } + else + { + // Add a mapping in both directions + _pupToEthernetMap.Add(p.SourcePort.Host, e.Ethernet.Source); + _ethernetToPupMap.Add(e.Ethernet.Source, p.SourcePort.Host); } } @@ -91,6 +178,12 @@ namespace IFS /// private Dictionary _dispatchMap; + /// + /// PUP<->Ethernet address map + /// + private Dictionary _pupToEthernetMap; + private Dictionary _ethernetToPupMap; + private static Dispatcher _instance = new Dispatcher(); } } diff --git a/PUP/Entrypoint.cs b/PUP/Entrypoint.cs index dea6ab1..68dc68b 100644 --- a/PUP/Entrypoint.cs +++ b/PUP/Entrypoint.cs @@ -1,4 +1,5 @@ -using System; +using IFS.Transport; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -10,6 +11,20 @@ namespace IFS { static void Main(string[] args) { + + Logging.Log.Level = Logging.LogLevel.All; + + List ifaces = EthernetInterface.EnumerateDevices(); + + Console.WriteLine("available interfaces are:"); + foreach(EthernetInterface i in ifaces) + { + Console.WriteLine(String.Format("{0} - address {1}", i.Name, i.MacAddress)); + } + + // TODO: MAKE THIS CONFIGURABLE. + Dispatcher.Instance.RegisterInterface(ifaces[1]); + // Set up protocols: // Connectionless @@ -19,5 +34,10 @@ namespace IFS // RTP/BSP based: Dispatcher.Instance.RegisterProtocol(new PUPProtocolEntry("CopyDisk", 0x15 /* 25B */, ConnectionType.BSP, new CopyDiskServer())); + while (true) + { + System.Threading.Thread.Sleep(100); + } } + } } diff --git a/PUP/IFS.csproj b/PUP/IFS.csproj index 8135c78..7e79323 100644 --- a/PUP/IFS.csproj +++ b/PUP/IFS.csproj @@ -32,18 +32,36 @@ + + true + bin\x64\Debug\ + DEBUG;TRACE + full + x64 + prompt + MinimumRecommendedRules.ruleset + + + bin\x64\Release\ + TRACE + true + pdbonly + x64 + prompt + MinimumRecommendedRules.ruleset + - ..\Ethernet\pcap\PcapDotNet.Base.dll + pcap\PcapDotNet.Base.dll - ..\Ethernet\pcap\PcapDotNet.Core.dll + pcap\PcapDotNet.Core.dll - ..\Ethernet\pcap\PcapDotNet.Core.Extensions.dll + pcap\PcapDotNet.Core.Extensions.dll - ..\Ethernet\pcap\PcapDotNet.Packets.dll + pcap\PcapDotNet.Packets.dll @@ -55,11 +73,13 @@ + + diff --git a/PUP/IFS.sln b/PUP/IFS.sln index 686ba3a..c39a31e 100644 --- a/PUP/IFS.sln +++ b/PUP/IFS.sln @@ -8,13 +8,19 @@ EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {5C0BBE4B-76AB-4AC1-8691-F19D8D282DCB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5C0BBE4B-76AB-4AC1-8691-F19D8D282DCB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5C0BBE4B-76AB-4AC1-8691-F19D8D282DCB}.Debug|x64.ActiveCfg = Debug|x64 + {5C0BBE4B-76AB-4AC1-8691-F19D8D282DCB}.Debug|x64.Build.0 = Debug|x64 {5C0BBE4B-76AB-4AC1-8691-F19D8D282DCB}.Release|Any CPU.ActiveCfg = Release|Any CPU {5C0BBE4B-76AB-4AC1-8691-F19D8D282DCB}.Release|Any CPU.Build.0 = Release|Any CPU + {5C0BBE4B-76AB-4AC1-8691-F19D8D282DCB}.Release|x64.ActiveCfg = Release|x64 + {5C0BBE4B-76AB-4AC1-8691-F19D8D282DCB}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/PUP/Logging/Log.cs b/PUP/Logging/Log.cs new file mode 100644 index 0000000..07566f6 --- /dev/null +++ b/PUP/Logging/Log.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IFS.Logging +{ + [Flags] + public enum LogLevel + { + None = 0, + Normal = 1, + Warning = 2, + Error = 4, + DroppedPacket = 8, + InvalidPacket = 0x10, + UnhandledProtocol = 0x20, + DuplicateHostNumber = 0x40, + + All = 0x7fffffff, + } + + public static class Log + { + static Log() + { + _level = LogLevel.None; + } + + public static LogLevel Level + { + get { return _level; } + set { _level = value; } + } + + public static void Write(LogLevel level, string message) + { + if ((level & _level) != 0) + { + // My log has something to tell you... + Console.WriteLine("{0}: {1} - {2}", DateTime.Now, level, message); + } + } + + private static LogLevel _level; + } +} diff --git a/PUP/MiscServicesProtocol.cs b/PUP/MiscServicesProtocol.cs index b02eb82..5df6e4a 100644 --- a/PUP/MiscServicesProtocol.cs +++ b/PUP/MiscServicesProtocol.cs @@ -1,4 +1,5 @@ -using System; +using IFS.Logging; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -48,7 +49,7 @@ namespace IFS break; default: - // Unhandled, TODO: log it + Log.Write(LogLevel.UnhandledProtocol, String.Format("Unhandled misc. protocol {0}", p.Type)); break; } } @@ -144,7 +145,7 @@ namespace IFS // and see if we have a match. // PUPPort lookupAddress = new PUPPort(p.Contents, 0); - string hostName = DirectoryServices.Instance.AddressLookup(lookupAddress); + string hostName = DirectoryServices.Instance.AddressLookup(new HostAddress(lookupAddress.Network, lookupAddress.Host)); if (!String.IsNullOrEmpty(hostName)) { diff --git a/PUP/Transport/Ethernet.cs b/PUP/Transport/Ethernet.cs index 62d023e..151e4c1 100644 --- a/PUP/Transport/Ethernet.cs +++ b/PUP/Transport/Ethernet.cs @@ -5,20 +5,36 @@ using System.Text; using System.Threading.Tasks; using PcapDotNet.Core; +using PcapDotNet.Core.Extensions; using PcapDotNet.Packets; +using PcapDotNet.Packets.Ethernet; namespace IFS.Transport { public struct EthernetInterface { - public EthernetInterface(string name, string description) + public EthernetInterface(string name, string description, MacAddress macAddress) { Name = name; Description = description; + MacAddress = macAddress; } - public string Name; - public string Description; + public static List EnumerateDevices() + { + List interfaces = new List(); + + foreach (LivePacketDevice device in LivePacketDevice.AllLocalMachine) + { + interfaces.Add(new EthernetInterface(device.Name, device.Description, device.GetMacAddress())); + } + + return interfaces; + } + + public string Name; + public string Description; + public MacAddress MacAddress; } /// @@ -30,23 +46,14 @@ namespace IFS.Transport { AttachInterface(iface); _callback = callback; - } - public static List EnumerateDevices() - { - List interfaces = new List(); - - foreach(LivePacketDevice device in LivePacketDevice.AllLocalMachine) - { - interfaces.Add(new EthernetInterface(device.Name, device.Description)); - } - - return interfaces; + Open(false, int.MaxValue); + BeginReceive(); } public void Open(bool promiscuous, int timeout) { - _communicator = _interface.Open(0xffff, promiscuous ? PacketDeviceOpenAttributes.Promiscuous : PacketDeviceOpenAttributes.None, timeout); + _communicator = _interface.Open(0xffff, promiscuous ? PacketDeviceOpenAttributes.Promiscuous : PacketDeviceOpenAttributes.None, timeout); } /// @@ -57,9 +64,19 @@ namespace IFS.Transport _communicator.ReceivePackets(-1, ReceiveCallback); } + public void SendPacket(Packet p) + { + _communicator.SendPacket(p); + } + + public object GetDeviceAddress() + { + return (object)_interface.GetMacAddress(); + } + private void ReceiveCallback(Packet p) - { - _callback(p); + { + _callback(p); } private void AttachInterface(EthernetInterface iface) @@ -69,7 +86,7 @@ namespace IFS.Transport // Find the specified device by name foreach (LivePacketDevice device in LivePacketDevice.AllLocalMachine) { - if (device.Name == iface.Name) + if (device.Name == iface.Name && device.GetMacAddress() == iface.MacAddress) { _interface = device; break; diff --git a/PUP/Transport/PacketInterface.cs b/PUP/Transport/PacketInterface.cs index f8a3329..183dc03 100644 --- a/PUP/Transport/PacketInterface.cs +++ b/PUP/Transport/PacketInterface.cs @@ -1,4 +1,5 @@ -using System; +using PcapDotNet.Packets; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -10,7 +11,10 @@ namespace IFS.Transport /// PacketInterface provides an abstraction over a transport (Ethernet, IP, Carrier Pigeon) /// which can provide raw packets. /// - interface IPacketInterface + public interface IPacketInterface { + void SendPacket(Packet p); + + object GetDeviceAddress(); } }