EduNetworkBuilder/EduNetworkBuilder/NB.cs

748 lines
29 KiB
C#

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<string> PuzzleTags = new List<string>();
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<FirewallRuleType>(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;
/// <summary>
/// Find the global random number generator.
/// </summary>
/// <returns>A valid random number generator</returns>
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;
}
/// <summary>
/// Find the global random number generator.
/// </summary>
/// <returns>A valid random number generator</returns>
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;
}
/// <summary>
/// Find the global random number generator.
/// </summary>
/// <returns>A valid random number generator</returns>
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;
}
/// <summary>
/// Return a translated string in the current chosen language
/// </summary>
/// <param name="key">The key for the item we are translating</param>
/// <returns>A string of the translated information</returns>
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<string> 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<string> 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<T>(string value)
{
// Do not initialize this variable here.
return (T)Enum.Parse(typeof(T), value, true);
}
public static T TryParseEnum<T>(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<string> arp(UInt32 IP)
{
List<string> arps = new List<string>();
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()));
}
}
/// <summary>
/// Randomize a list
/// </summary>
/// <typeparam name="T">The type of list to return</typeparam>
/// <param name="list">The list to randomize</param>
/// <returns>a new list that is randomized</returns>
public static List<T> Randomize<T>(List<T> list)
{
List<T> randomizedList = new List<T>(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;
}
}
}