using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Deployment.Application; using System.Windows.Forms; using System.Globalization; using System.Resources; using System.Xml; using System.Drawing; using System.Media; using System.Reflection; using System.Text.RegularExpressions; namespace EduNetworkBuilder { public enum PacketStatus { processing, //It is inside a device. It needs to be routed, masqueraded, or whatever input, //It is hitting the interface/nic of a device. output, //It is leaving a device. Make sure the mac address is what it should be & that we are going out the right link waiting_for_arp, //It is in the output chain, has been procesed, but is waiting for an arp packet to give it the dest MAC moving, //It is traveling along a link. We increment the distance it has gone and re-draw the packet. encapsulated, //It has been put inside another packet. finished_ok,//The packet has finished and is ready to be removed from the network finished_failed, //The packet is finished (failed) and is ready to be removed from the network. finished //There was an appropriate reason this packet finished. It stopped } public enum VLANTagType { Tagged, Untagged, Forbidden } public enum LinkType { normal, wireless, broken } public enum PacketType { none, ping_request, ping_answer, arp_request, arp_answer, dhcp_request, dhcp_answer, vpn_packet, tun_packet } public enum ResponseToPacket { none, accept, masq, drop, reject } public enum DebugLevel { none=0, info=1, routing=2, switching=4, natting=8, filtering=16, debug=32 , packet=64, all=127} public enum NetworkComponentType { none, router, net_switch, net_hub, laptop, pc, server, wap , wrouter, wbridge, wrepeater, link, firewall, ip_phone, printer, copier, microwave, fluorescent, cellphone, tablet } public enum NicType { none, lo, eth, wlan, wan, vpn, tun, management_interface, port, wport } public enum IPAddressType { ip, gw, route, ip_only } public enum nb_direction { none, to_src, to_dst } public enum GeneralComponentType { none, link, device } public enum NBSoundType { none, success, saved_ok, saved_failed } public enum RTFWindowContents { help, about, release_notes } public enum NetTestType { NeedsLocalIPTo, NeedsDefaultGW, NeedsLinkToDevice, NeedsRouteToNet, NeedsUntaggedVLAN, NeedsTaggedVLAN, NeedsForbiddenVLAN, SuccessfullyPings, SuccessfullyPingsAgain, SuccessfullyArps, SuccessfullyDHCPs, HelpRequest, ReadContextHelp, FailedPing, DHCPServerEnabled, LockAll, LockIP, LockRoute, LockNic, LockDHCP, LockGateway, LockVLANsOnHost, LockNicVLAN, LockInterfaceVLAN, LockVLANNames, } public enum NetTestVerbosity { none, basic, hints, full } public enum LBContents { routes, messages, dhcp, puzzles } public enum HelpTopics { None, DHCP, DHCPServer, Firewall, Gateway, Help, IPAddress, Link, Subnet, Ping, VPN, Hub, Switch, ARP, StaticRoute, Subnetting, WhenToSubnet, ComparingAddresses, MACAddress, Network, Packet, NIC, Interface, Router, PacketCorruption, GeneralWireless, WirelessSSID, WirelessKey, WirelessAP, WirelessRouter, WirelessRepeater, WirelessBridge, VLAN } public enum FirewallRuleType { Allow, Drop } public enum PuzzleNames { Level0_IP, Level1_NoGateway, Level0_NeedsLink, Level0_NoSwitch, Level1_BadDHCP, Level1_BadGateway, Level0_SimpleDHCP, Level1_BadIP, Level0_Help, Level0_Ping, Level0_HubVsSwitch, Level0_PacketCorruption1, Level0_PacketCorruption2, Level1_AddingDevices, Level1_MidDHCP, Level1_OneNetTwoSubnets, Level1_DuplicateIPs, Level0_NetworkLoop, Level1_DuplicateMAC, Level2_FirewallDemo, Level1_OneNetTwoSubnets2, Level2_VPN_Demo, Level2_Bad_VPN_IP, Level2_Bad_Encryption, Level2_Bad_Route, Level2_Blast_From_Past, Level2_Not_Working, Level2_Build_A_VPN, Level2_Connect_The_Dots, Level2_VPN_woes, Level2_FirewallTest2, Level3_BlackHole, Level3_Busted, Level3_Middle_Man_Out, Level3_PhoneyNetwork, Level3_VPNify, Level3_EncryptionTroubles, Level3_NowhereToGo, Level3_GrandCentralStation, Level3_Dead, Level0_NetworkLoop2, Level0_BrokenLink, Level3_TwoDHCPServers, Level4_DualWans, Level4_SinglesLife, Level4_SmallSubnets, Level4_OneRoute, Level4_RouterReplacement, Level4_InternalSubnetting, Level4_Internalhemorrhage, Level5_WirelessRouters, Level5_WirelessDevices, Level5_WirelessBridge, Level5_WirelessRepeater, Level5_WirelessRepeater2, Level5_WirelessAccessPoint, Level5_WirelessCorruption, Level5_Failed, Level5_LostPacket, Level5_HereComesTrouble, Level6_VLAN_Intro, Level6_VLAN_Intro2, Level6_Intro3_LockedOut, Level6_ForbiddenVLAN, Level6_TaggedBetweenSwitches, Level6_VLANRouting, Level6_VLANRouting2, level6_UntaggedAndDHCP, Level6_SorryBoss, Level6_VLANFrustrations, Level6_TwoAccessPoints, Level6_VlanRouting3, Level6_ConnectTheLaptop, Level6_CleanSlate, Level6_WhereFrom, Level6_NeedVLANs, Level6_SwitchedUp, } public enum DebugPausePoint { none=0, packet_create=1, packet_kill=2, packet_in=4, packet_out=8, packet_duplicate=16, all=63, dump=256, pause=512} [Serializable] public struct HostNicID //This holds a unique identifier for a network card. Links use this to know what it is connected to { public int HostID; public int NicID; public string HostName; public string NicName; public HostNicID(int host, int nic, string hostname, string nicname) { HostID = host; NicID = nic; HostName = hostname; NicName = nicname; } public HostNicID(XmlNode theNode) { HostID = 0; NicID = 0; HostName = ""; NicName = ""; foreach (XmlNode Individual in theNode.ChildNodes) { XmlNodeType myNodetype = Individual.NodeType; if (myNodetype == XmlNodeType.Element) { switch (Individual.Name.ToLower()) { case "hostid": int.TryParse(Individual.InnerText, out HostID); break; case "nicid": int.TryParse(Individual.InnerText, out NicID); break; case "hostname": HostName = Individual.InnerText; break; case "nicname": NicName = Individual.InnerText; break; } } } } public void Save(XmlWriter writer, string tag) { writer.WriteStartElement(tag); writer.WriteElementString("hostid", HostID.ToString()); writer.WriteElementString("nicid", NicID.ToString()); writer.WriteElementString("hostname", HostName); writer.WriteElementString("nicname", NicName); writer.WriteEndElement(); } public string HostNicIDString { get { return HostID.ToString()+"-"+NicID.ToString(); } } public bool Equals(HostNicID toCheck) { if (HostID != toCheck.HostID) return false; if (NicID != toCheck.NicID) return false; if (HostName != toCheck.HostName) return false; if (NicName != toCheck.NicName) return false; return true; } } [Serializable] public struct IPConnectionEntry { public IPAddress destIP; //where we are sending the packet to. We expect a response to come from here public PacketType What; //ping, dhcp, etc public ResponseToPacket Response; //accept, masq public IPAddress internalIP; //Used if we are masquerading public IPConnectionEntry(IPAddress dest, PacketType what, ResponseToPacket response) { destIP = dest; What = what; Response = response; internalIP = null; } public IPConnectionEntry(IPAddress dest, PacketType what, ResponseToPacket response, IPAddress internal_ip) { destIP = dest; What = what; Response = response; internalIP = internal_ip; } } public class PingTestStatus { public string Source; public string Dest; public bool Succeeded = false; } [Serializable] public struct ArpEntry { public string MACAddress; public string IPAddr; public HostNicID NicOnWhichItIsFound; public ArpEntry(string mac, string ip, HostNicID thenic) { MACAddress = mac; IPAddr = ip; NicOnWhichItIsFound = thenic; } } public class PuzzleInfo { public string PuzzleName; public string PuzzleTitle; public string PuzzleDescription; public List PuzzleTags = new List(); public int Level=0; public double SortOrder=0; public void Load(XmlNode TheNode, string Name) { PuzzleName = Name; foreach (XmlNode Individual in TheNode.ChildNodes) { XmlNodeType myNodetype = Individual.NodeType; if (myNodetype == XmlNodeType.Element) { switch (Individual.Name.ToLower()) { case "edunetworkbuilder": case "network": Load(Individual, PuzzleName); break; case "message": PuzzleDescription = Individual.InnerText; break; case "title": PuzzleTitle = Individual.InnerText; break; case "tag": PuzzleTags.Add(Individual.InnerText); break; case "level": PuzzleTags.Add("Level_" + Individual.InnerText); int.TryParse(Individual.InnerText, out Level); break; case "sortorder": double.TryParse(Individual.InnerText, out SortOrder); break; } } } } } [Serializable] public class FirewallRule { public string Source; public string Destination; public FirewallRuleType Action; public FirewallRule(string source, string dest, FirewallRuleType action) { Source = source; Destination = dest; Action = action; } public FirewallRule(XmlNode theNode) { foreach (XmlNode Individual in theNode.ChildNodes) { XmlNodeType myNodetype = Individual.NodeType; if (myNodetype == XmlNodeType.Element) { switch (Individual.Name.ToLower()) { case "source": Source = Individual.InnerText; break; case "destination": Destination = Individual.InnerText; break; case "action": Action = NB.ParseEnum(Individual.InnerText); break; } } } } public void Save(XmlWriter writer, string tag) { writer.WriteStartElement(tag); writer.WriteElementString("source", Source); writer.WriteElementString("destination", Destination); writer.WriteElementString("action", Action.ToString()); writer.WriteEndElement(); } } class NB { public static string BroadcastMACString = "FF:FF:FF:FF:FF:FF"; //The broadcast MAC address public static string BroadcastIPString = "255.255.255.255"; //the generic broadcast IP address public static string ZeroIPString = "0.0.0.0"; public static string LoopbackIPString = "127.0.0.1"; public static int LinkStep = 8;//The percentage of the link we move at each "tick" public static int PacketPixelSize = 16; //The size of the packet pixel public static int PacketVersionNum = 2; //2 uses the new stuff. Anything else uses the old stuff public const int GridSize = 10; public static string[,] LanguageChoices = { { NB.Translate("NB_NBEn"), "en" }, { NB.Translate("NB_NBFr"), "fr" } }; public static int WirelessMaxUnsuccessfulLink = 120; //The link will connect, but the packet will drop public static int WirelessMaxSuccessfulLink = 100; //Packets will drop after this distance public static int WirelessReconnectDistance = 70; //Try to find a closer AP if we are this far out. public static int UntaggedVLAN = -1; //If the packet is not tagged. public static int MaxPacketsBeforeOptimizing = 50; /// /// Find the global random number generator. /// /// A valid random number generator public static Random GetRandom() { BuilderWindow myWin = (BuilderWindow)Application.OpenForms["BuilderWindow"]; if (myWin == null) return new Random(); if (myWin.GameRandomGen == null) return new Random(); return myWin.GameRandomGen; } /// /// Find the global random number generator. /// /// A valid random number generator public static CultureInfo GetCulture() { BuilderWindow myWin = (BuilderWindow)Application.OpenForms["BuilderWindow"]; CultureInfo CI=null; if (myWin != null) { CI = myWin.GetCulture(); } if(CI == null || myWin == null) { string CL = Properties.Settings.Default.ChosenLanguage; CI = CultureInfo.CreateSpecificCulture(CL); } return CI; } /// /// Find the global random number generator. /// /// A valid random number generator public static ResourceManager GetResource() { ResourceManager myresource = null; BuilderWindow myWin = (BuilderWindow)Application.OpenForms["BuilderWindow"]; if (myWin != null) { myresource = myWin.GetResource(); } if(myresource == null || myWin == null) { System.Reflection.Assembly MyAssembly; MyAssembly = Assembly.GetCallingAssembly(); myresource = new ResourceManager("EduNetworkBuilder.Resources.languages.edustrings", MyAssembly); } return myresource; } public static Point GetSnapped(Point Location) { int x = (Location.X / NB.GridSize) * NB.GridSize; int y = (Location.Y / NB.GridSize) * NB.GridSize; Point newlocation = new Point(x, y); return newlocation; } public static Network GetNetwork() { BuilderWindow myWin = (BuilderWindow)Application.OpenForms["BuilderWindow"]; if (myWin == null) return null; if (myWin.GameRandomGen == null) return null; return myWin.myNetwork; } public static void MarkToUpdate() { BuilderWindow myWin = (BuilderWindow)Application.OpenForms["BuilderWindow"]; if (myWin == null) return; myWin.NeedsUpdate = true; } public static int nextPacketID() { BuilderWindow myWin = (BuilderWindow)Application.OpenForms["BuilderWindow"]; if (myWin == null) return 1; //return something. return myWin.nextPacketID(); } public static BuilderWindow GetBuilderWin() { BuilderWindow myWin = (BuilderWindow)Application.OpenForms["BuilderWindow"]; if (myWin == null) return null; return myWin; } /// /// Return a translated string in the current chosen language /// /// The key for the item we are translating /// A string of the translated information public static string Translate(string key) { BuilderWindow myWin = (BuilderWindow)Application.OpenForms["BuilderWindow"]; if (myWin == null) { ResourceManager RM = GetResource(); CultureInfo CI = GetCulture(); string answer=""; answer = RM.GetString(key, CI); if (answer == null) return ""; return answer; } return myWin.Translate(key); } public static string GetHelpTopicKey(HelpTopics What) { return "H_" + What.ToString() + "_Key"; } public static string GetHelpTopicTitle(HelpTopics What) { return "H_" + What.ToString() + "_Title"; } public static DebugPausePoint GetDebugPauseSetting() { BuilderWindow myWin = (BuilderWindow)Application.OpenForms["BuilderWindow"]; if (myWin == null) return DebugPausePoint.none; if (myWin.GameRandomGen == null) return DebugPausePoint.none; return myWin.DebugSetting; } public static PuzzleInfo GetPuzzleInfoFromName(string PuzzleName) { BuilderWindow myWin = (BuilderWindow)Application.OpenForms["BuilderWindow"]; if (myWin == null) return null; return myWin.PuzzleInfoFromName(PuzzleName); } public static string LeftPad(string what, int amount=-1) { int UseAmount = 10; if (amount != -1) UseAmount = amount; string format = "{0," + (0 - UseAmount).ToString() + "}"; string mystring = string.Format(format, what); return mystring; } public static void ChangeLanguage() { //Find the window. If it exists, use /set the language setting there. If not, use / set the default. BuilderWindow myWin = (BuilderWindow)Application.OpenForms["BuilderWindow"]; string lang = Properties.Settings.Default.ChosenLanguage; if (lang == "") lang = "en"; string StartingItem = ""; for (int i = 0; i < LanguageChoices.GetLength(0); i++) { if (lang == LanguageChoices[i, 1]) { StartingItem = LanguageChoices[i, 0]; } } //we need to choose a language: Form LanguageForm = new Form(); LanguageForm.Text = NB.Translate("NB_ChangeLang1"); Label lblText = new Label(); lblText.Location = new Point(5, 5); lblText.AutoSize = true; lblText.Text = NB.Translate("NB_ChangeLang2"); LanguageForm.Icon = Properties.Resources.NBIco; ComboBox cbQuestions = new ComboBox(); cbQuestions.Location = new Point(lblText.Location.X + lblText.Width + 10, lblText.Location.Y); cbQuestions.Width = 60; for (int i = 0; i < LanguageChoices.GetLength(0); i++ ) { cbQuestions.Items.Add(LanguageChoices[i,0]); } if(cbQuestions.Items.Contains(StartingItem)) { cbQuestions.SelectedItem = StartingItem; } else cbQuestions.SelectedIndex = 0; LanguageForm.Width = cbQuestions.Location.X + cbQuestions.Width + 70; LanguageForm.Height = 90; LanguageForm.AutoSize = true; Button btnAccept = new Button(); btnAccept.Location = new Point(cbQuestions.Location.X, cbQuestions.Location.Y + cbQuestions.Height + 10); btnAccept.Text = NB.Translate("_OK"); btnAccept.Click += (s, g) => { Button b = (Button)s; Form f = (Form)b.Parent; f.Close(); }; LanguageForm.Controls.Add(lblText); LanguageForm.Controls.Add(cbQuestions); LanguageForm.Controls.Add(btnAccept); LanguageForm.ShowDialog(); if (cbQuestions.SelectedIndex >= 0) { Properties.Settings.Default.LanguageHasBeenChosen = true; string mychoice = LanguageChoices[cbQuestions.SelectedIndex, 1]; if (myWin == null) { Properties.Settings.Default.ChosenLanguage = mychoice; //Properties.Settings.Default.Save(); //We do this when we exit. No need to save it right this instant. } else { myWin.ChosenLanguage = mychoice; } } } public static void PlaySound(NBSoundType What) { SoundPlayer sndClick; switch (What) { case NBSoundType.none: break; case NBSoundType.success: sndClick = new SoundPlayer(Properties.Resources.wavBellDing); sndClick.Play(); break; case NBSoundType.saved_failed: sndClick = new SoundPlayer(Properties.Resources.noBeep); sndClick.Play(); break; case NBSoundType.saved_ok: sndClick = new SoundPlayer(Properties.Resources.click); sndClick.Play(); break; } } public static List GetPuzzleTags() { BuilderWindow myWin = (BuilderWindow)Application.OpenForms["BuilderWindow"]; if (myWin == null) return null; return myWin.GetPuzzleTags(); } public static bool PuzzleLevelHasUnsolved(string LevelName) { BuilderWindow myWin = (BuilderWindow)Application.OpenForms["BuilderWindow"]; if (myWin == null) return false; return myWin.PuzzleLevelHasUnsolved(LevelName); } public static List GetPuzzleNames() { BuilderWindow myWin = (BuilderWindow)Application.OpenForms["BuilderWindow"]; if (myWin == null) return null; return myWin.GetPuzzleNames(); } public static void LoadNetworkFromResource(string resource) { BuilderWindow myWin = (BuilderWindow)Application.OpenForms["BuilderWindow"]; if (myWin == null) return; myWin.LoadNetworkFromResource(resource); } public static void SetProgress(double HowFar, double total) { BuilderWindow myWin = (BuilderWindow)Application.OpenForms["BuilderWindow"]; if (myWin == null) return; myWin.SetProgress(HowFar, total); } public static void UpdateMessages() { BuilderWindow myWin = (BuilderWindow)Application.OpenForms["BuilderWindow"]; if (myWin == null) return; myWin.UpdateMessages(); } public static int GetUniqueIdentifier() { Network myNet = GetNetwork(); if(myNet == null) { //We should never get here. If so, we are in a bad sort of way. Random rnd = GetRandom(); return rnd.Next(1,100); } return myNet.GetUniqueIdentifier(); } public static void Delay(int amount) { System.Threading.Thread.Sleep(amount); } public static T ParseEnum(string value) { // Do not initialize this variable here. return (T)Enum.Parse(typeof(T), value, true); } public static T TryParseEnum(string value, T Default ) { if (!Enum.IsDefined(typeof(T), value)) return Default; return (T)Enum.Parse(typeof(T), value); } public static GeneralComponentType GetComponentType(NetworkComponent What) { GeneralComponentType theType = GeneralComponentType.none; if(What.GetType().ToString() == "EduNetworkBuilder.NetworkDevice") theType = GeneralComponentType.device; if (What.GetType().ToString() == "EduNetworkBuilder.NetworkLink") theType = GeneralComponentType.link; return theType; } public static void ReadContextHelp(HelpTopics What) { RTFWindow tForm = null; //make a new window if needed foreach(Form myfrm in Application.OpenForms) { if(myfrm.Name == NB.Translate("NB_RdCtxtHelp")) { //We have a context window tForm = (RTFWindow)myfrm; break; } } if(tForm == null) { //We do not have one yet. Make a new one tForm = new RTFWindow(RTFWindowContents.help); tForm.Name = NB.Translate("NB_RdCtxtHelp"); } //load help tForm.Show(); //Jump to the correct location if(tForm != null) { tForm.JumpToSelection(What); } } public static string GenerateMACAddress() { var sBuilder = new StringBuilder(); var random = GetRandom(); int number; byte b; for (int i = 0; i < 6; i++) { number = random.Next(0, 255); b = Convert.ToByte(number); if (i == 0) { b = setBit(b, 6); //--> set locally administered b = unsetBit(b, 7); // --> set unicast } sBuilder.Append(number.ToString("X2")); } string mac= sBuilder.ToString().ToUpper(); if (MAC_Exists(mac)) return GenerateMACAddress(); //If it already exists, generate another return mac; } public static bool MAC_Exists(string MAC) { Network myNet = GetNetwork(); if(myNet == null) return false; return myNet.MAC_Exists(MAC); } public static List arp(UInt32 IP) { List arps = new List(); Network myNet = GetNetwork(); if (myNet == null) return arps; return myNet.arp(IP); } private static byte setBit(byte b, int BitNumber) { if (BitNumber < 8 && BitNumber > -1) { return (byte)(b | (byte)(0x01 << BitNumber)); } else { throw new InvalidOperationException( string.Format(NB.Translate("NB_BitError"), BitNumber.ToString())); } } private static byte unsetBit(byte b, int BitNumber) { if (BitNumber < 8 && BitNumber > -1) { return (byte)(b | (byte)(0x00 << BitNumber)); } else { throw new InvalidOperationException( string.Format(NB.Translate("NB_BitError"), BitNumber.ToString())); } } /// /// Randomize a list /// /// The type of list to return /// The list to randomize /// a new list that is randomized public static List Randomize(List list) { List randomizedList = new List(list); Random rnd = GetRandom(); int n = randomizedList.Count; int counter = 0; T value; while (n > 1) { n--; int k = rnd.Next(n + 1); value = randomizedList[k]; randomizedList[k] = randomizedList[n]; randomizedList[n] = value; counter++; if (counter > 10) { counter = 0; } } return randomizedList; } } }