EduNetworkBuilder/EduNetworkBuilder/NetworkInterface.cs

458 lines
18 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Windows.Forms;
using System.Text.RegularExpressions;
namespace EduNetworkBuilder
{
[Serializable]
public class NetworkInterface
{
public NB_IPAddress myIP;
public string nic_name; //eth0, eth0:0, etc
public HostNicID AttachedToHostNic;
public List<VLANInfo> VLANs = new List<VLANInfo>() { new VLANInfo(1, VLANTagType.Untagged ) };
//We should have a feature: none, IP_in_IP_Tunnel, encrypted_vpn, vlan, etc
public NetworkInterface() { }
public NetworkInterface(string name, string IP, string Mask, HostNicID AttachedTo)
{
nic_name = name;
myIP = new NB_IPAddress(IP, Mask,IPAddressType.ip);
AttachedToHostNic = AttachedTo;
}
public NetworkInterface(XmlNode theNode, HostNicID AttachedTo)
{
AttachedToHostNic = AttachedTo;
foreach (XmlNode Individual in theNode.ChildNodes)
{
XmlNodeType myNodetype = Individual.NodeType;
if (myNodetype == XmlNodeType.Element)
{
switch (Individual.Name.ToLower())
{
case "myip":
myIP = new NB_IPAddress(Individual);
break;
case "nicname":
nic_name = Individual.InnerText;
break;
case "vlan":
if (Individual.Attributes != null && Individual.Attributes["ID"] != null)
{
int ID;
VLANTagType Tag = NB.TryParseEnum<VLANTagType>(Individual.InnerText, VLANTagType.Untagged);
int.TryParse(Individual.Attributes["ID"].Value, out ID);
VLANInfo current = GetVLANInfo(ID);
if (current != null) VLANs.Remove(current); //we are replacing it
VLANs.Add(new VLANInfo(ID, Tag));
}
break;
}
}
}
}
public NetworkInterface(NetworkInterface CopyFrom)
{
myIP = new NB_IPAddress(CopyFrom.myIP.GetIPString, CopyFrom.myIP.GetMaskString, CopyFrom.myIP.GetAddressType);
nic_name = CopyFrom.nic_name;
foreach(VLANInfo VLI in CopyFrom.VLANs)
{
VLANs.Add(new VLANInfo(VLI.ID, VLI.Tag));
}
}
/// <summary>
/// When we are doing replays and we load in a network interface using reflection,
/// it can create a duplicate VLAN tag (1,untagged). Rebuilding these fixes that.
/// </summary>
public void UpdateVLANsAfterClone()
{
List<VLANInfo> tmpVLANs = new List<VLANInfo>();
tmpVLANs.AddRange(VLANs);
VLANs.Clear();
foreach(VLANInfo VLI in tmpVLANs)
{
bool found = false;
foreach(VLANInfo VLI2 in VLANs)
{
if(VLI2.ID == VLI.ID)
{
VLI2.Tag = VLI.Tag;
found = true;
}
}
if (!found)
VLANs.Add(VLI);
}
}
public VLANInfo GetVLANInfo(int id)
{
VLANInfo status = null;
foreach(VLANInfo one in VLANs)
{
if (one.ID == id)
status = one;
}
return status;
}
public bool Equals(NetworkInterface CompareWith)
{
if (!myIP.Equals(CompareWith.myIP)) return false;
if (nic_name != CompareWith.nic_name) return false;
if (!AttachedToHostNic.Equals(CompareWith.AttachedToHostNic)) return false;
if (VLANs.Count != CompareWith.VLANs.Count) return false;
for (int i = 0; i < VLANs.Count; i++)
if (!VLANs[i].Equals(CompareWith.VLANs[i])) return false;
return true;
}
public VLANTagType GetVLANTag(int id)
{
VLANInfo vli = GetVLANInfo(id);
if (vli != null) return vli.Tag;
return VLANTagType.Forbidden; //if not defined, it is forbidden
}
public int GetNonForbiddenVLANID()
{
foreach(VLANInfo vin in VLANs)
{
if (vin.Tag != VLANTagType.Forbidden)
return vin.ID;
}
return -999;
}
public void SetVLANTag(int id, VLANTagType Tag)
{
bool foundit = false;
Network theNet = NB.GetNetwork();
if (theNet == null)
return;
NetworkDevice ND = theNet.GetDeviceFromID(AttachedToHostNic);
if (ND == null)
return;
NetworkCard NC = ND.NicFromID(AttachedToHostNic);
if (NC == null)
return;
NicType NT = NC.GetNicType;
bool isPort = NT == NicType.port;
//Ports (switches) can have multiple tagged ports.
//WAN, ETH0, etc, can only have one tagged or untagged per interface
//nothing can have multiple untagged ports
// If something is untagged, everything else is forbidden
foreach (VLANInfo one in VLANs)
{
if (one.ID == id)
{
one.Tag = Tag;
foundit = true;
}
else
{
if (Tag == VLANTagType.Untagged)
one.Tag = VLANTagType.Forbidden; //Only one untagged port allowed at a time
if (Tag == VLANTagType.Tagged && !isPort) //Ports can have multiple tags on one interface
one.Tag = VLANTagType.Forbidden;
if (Tag == VLANTagType.Tagged && isPort)
{
if(one.Tag != VLANTagType.Tagged)
one.Tag = VLANTagType.Forbidden; //We cannot have an untagged port and tagged ports at the same time
}
}
}
if (!foundit)
VLANs.Add(new VLANInfo(id, Tag));
}
public void LockOutVLANInterface()
{
Network theNet = NB.GetNetwork();
if (theNet == null)
return;
foreach(VLANName one in theNet.VlanNames)
{
SetVLANTag(one.ID, VLANTagType.Forbidden);
}
}
public void Save(XmlWriter writer)
{
writer.WriteStartElement("interface");
writer.WriteElementString("nicname", nic_name);
myIP.Save(writer, "myip");
foreach (VLANInfo one in VLANs)
{
writer.WriteStartElement("VLAN");
writer.WriteAttributeString("ID", one.ID.ToString());
writer.WriteString(one.Tag.ToString());
writer.WriteEndElement();
}
writer.WriteEndElement();
}
public string InterfaceString(bool UseCidr = false)
{
string tstring = myIP.GetIP.ToIpString();
if (!UseCidr)
{
tstring += " - " + myIP.GetMask.ToIpString();
}
else
{
int cidr = myIP.CIDRNumber();
string answer = cidr.ToString();
if (!myIP.ValidCIDR()) answer = "?";
tstring += "/" + answer;
}
return tstring;
}
public string RouteString(string nic_name, string GW)
{
string tstring = myIP.IPFormat(GW); ;
return tstring;
}
/// <summary>
/// Pop up a window to edit this address.
/// </summary>
public void EditAddress(Form ParentForm)
{
Network myNet = NB.GetNetwork();
NetworkDevice ND = myNet.GetDeviceFromID(AttachedToHostNic);
IPAddressEntry ipe = new IPAddressEntry(myIP,ND, ParentForm);
ipe.ShowDialog();
}
public bool isLocal(NB_IPAddress tIp, bool AllowZeroMatch = true)
{
if (tIp == null) return false;
if (!AllowZeroMatch && (myIP == null || myIP.GetIP == 0))
return false;
if (myIP.IsLocal(tIp))
return true;
return false;
}
/// <summary>
/// We are sending the packet out this interface.
/// </summary>
/// <param name="tPacket"></param>
public void ProcessOutboundPacket(Packet tPacket)
{
//tPacket.InboundInterface = null; //forget the interface we had come in on now that we are leaving.
//if (tPacket.sourceIP == null || tPacket.sourceIP.GetIP.ToIpString() == NB.ZeroIPString)
//{
// //This happens if we are starting a new packet. We should also do this if we are masquerading.
// tPacket.sourceIP = new IPAddress(myIP.GetIP.ToIpString(), "", IPAddressType.ip_only); //We only want the IP address
//}
//VLAN stuff
VLANInfo VI = OutgoingVLAN(tPacket.VLANID);
VLANTagType What = VI.Tag;
Network theNet = NB.GetNetwork();
NetworkDevice HD = theNet.GetDeviceFromID(AttachedToHostNic);
if (HD == null) return; //Oops! Something went wrong.
string hostname = HD.hostname;
//added to fix the issue with vpns and pings - 11-09-2016
//Only do this on non-ports?
tPacket.TraversalInformation.AddPath(hostname, TraversalTechnology.network_interface, nic_name);
NetworkCard nic = HD.NicFromID(AttachedToHostNic);
if(nic != null && nic.GetNicType != NicType.port && nic.GetNicType != NicType.wport)
tPacket.TsourceIP = myIP;
if(tPacket.TsourceIP == null || tPacket.TsourceIP.GetIPString == NB.ZeroIPString)
tPacket.TsourceIP = myIP;
if (What == VLANTagType.Forbidden)
{
//we drop it silently
//Console.WriteLine(" -- Forbidding outbound packet. " + tPacket.VLANID + " " + HD.hostname + " " + VI.ID);
string errString = string.Format(NB.Translate("NI_VLANOut"), hostname, tPacket.destIP.GetIPString);
tPacket.AddMessage(DebugLevel.switching, errString);
tPacket.Tracking.Status = errString;
tPacket.MyStatus = PacketStatus.finished_ok;
return;
}
if(What == VLANTagType.Untagged)
{
//We strip off the tagging
tPacket.VLANID = NB.UntaggedVLAN; //set to the default vlan
}
if(What == VLANTagType.Tagged)
{
//We actually do not do anything. The tag remains intact.
tPacket.VLANID = VI.ID;
}
}
private VLANInfo IncomingVLAN(int ID)
{
//Search through incoming vlan stuff to find the right one
//If the packet is tagged with the ID, and the port is tagged, return that
//If the packet is untagged, return the one that is untagged
VLANInfo newVLANinfo = null;
if (ID != NB.UntaggedVLAN) //It is tagged
{
foreach(VLANInfo vi in VLANs)
{
if (vi.ID == ID)
{
//if (vi.Tag == VLANTagType.Forbidden)
// Console.WriteLine(" About to be forbidden.");
return vi;
}
}
//We do not have one set yet. Add a new one
newVLANinfo = new VLANInfo(ID, VLANTagType.Forbidden);
//Console.WriteLine(" Creating forbidden vlan - " + ID);
VLANs.Add(newVLANinfo);
return newVLANinfo;
}
else //the packet is untagged.
{
foreach (VLANInfo vi in VLANs)
{
if (vi.Tag == VLANTagType.Untagged) return vi;
}
//We do not have an "untagged" vlan. Return the settings for vlan1
foreach (VLANInfo vi in VLANs)
{
if (vi.ID == 1) return vi;
}
}
//We should never get here. This is just a fall-through
newVLANinfo = new VLANInfo(ID, VLANTagType.Forbidden);
VLANs.Add(newVLANinfo);
return newVLANinfo;
}
private VLANInfo OutgoingVLAN(int ID)
{
//Search through outgoing vlan stuff to find the right one
//If the packet is tagged with the ID, and the port is tagged, return that
//If the packet is untagged, return the one that is untagged
VLANInfo newVLANinfo = null;
if (ID != NB.UntaggedVLAN) //the packet is tagged
{
foreach (VLANInfo vi in VLANs)
{
if (vi.ID == ID)
{
//if (vi.Tag == VLANTagType.Forbidden)
// Console.WriteLine(" About to be outbound forbidden.");
return vi;
}
}
//We do not have one set yet. Add a new one
newVLANinfo = new VLANInfo(ID, VLANTagType.Forbidden);
//Console.WriteLine(" Creating outbound forbidden vlan - " + ID);
VLANs.Add(newVLANinfo);
return newVLANinfo;
}
else //the packet is untagged.
{
//we should find the untagged vlan
//if no untagged vlan, find the tagged vlan
foreach (VLANInfo vi in VLANs)
{
if (vi.Tag == VLANTagType.Untagged) return vi;
}
foreach (VLANInfo vi in VLANs)
{
if (vi.Tag == VLANTagType.Tagged) return vi;
}
//We do not have an "untagged" vlan. Return the settings for vlan1
foreach (VLANInfo vi in VLANs)
{
if (vi.ID == 1) return vi;
}
}
//We should never get here. This is just a fall-through
newVLANinfo = new VLANInfo(ID, VLANTagType.Forbidden);
VLANs.Add(newVLANinfo);
return newVLANinfo;
}
public void ProcessInboundPacket(Packet tPacket)
{
bool isgood = false;
if (tPacket.destIP != null && tPacket.destIP.GetIP == myIP.GetIP) isgood = true;
if (tPacket.destIP != null && myIP.IsLocal(tPacket.destIP)) isgood = true;
if (myIP.NetworkAddress == myIP.GetIP) isgood = true;
Network MyNet = NB.GetNetwork();
NetworkDevice ND = MyNet.GetDeviceFromID(AttachedToHostNic);
tPacket.InboundInterface = this;
tPacket.TraversalInformation.AddPath(ND.hostname, TraversalTechnology.network_interface, nic_name);
if (isgood)
{
//anything we should do here?
//Mainly vlan if we are a vlan.
VLANInfo VI = IncomingVLAN(tPacket.VLANID);
VLANTagType What = VI.Tag;
Network theNet = NB.GetNetwork();
NetworkDevice HD = theNet.GetDeviceFromID(AttachedToHostNic);
if (HD == null) return;
string hostname = HD.hostname;
if (What == VLANTagType.Forbidden)
{
//This vlan packet is deliberately forbidden. Reject it (fail)
string errString = string.Format(NB.Translate("NI_VLANInForbidden"), hostname, tPacket.destIP.GetIPString);
tPacket.AddMessage(DebugLevel.switching, errString);
tPacket.Tracking.Status = errString;
tPacket.MyStatus = PacketStatus.finished_ok;
return;
}
if (What == VLANTagType.Untagged)
{
//If it is (default vlan), this is OK. Otherwise drop.
//Untagged means we expect it to be vlan of (untagged) on the cable side
if(tPacket.VLANID != NB.UntaggedVLAN)
{
//Oops. We need to reject the packet
string errString = string.Format(NB.Translate("NI_VLANInUntagged"), hostname, tPacket.destIP.GetIPString);
tPacket.AddMessage(DebugLevel.switching, errString);
tPacket.Tracking.Status = errString;
tPacket.MyStatus = PacketStatus.finished_ok;
return;
}
else //We need to tag the packet with the new VLAN-ID
{
tPacket.VLANID = VI.ID; //The packet is now tagged
}
}
if (What == VLANTagType.Tagged)
{
//If the packet is tagged, and the vlan expected tagged, all is good.
if (tPacket.VLANID != NB.UntaggedVLAN && tPacket.VLANID != VI.ID)
{
//Oops. We need to reject the packet
string errString = string.Format(NB.Translate("NI_VLANInMisMatch"), hostname, tPacket.destIP.GetIPString);
tPacket.AddMessage(DebugLevel.switching, errString);
tPacket.Tracking.Status = errString;
tPacket.MyStatus = PacketStatus.finished_ok;
return;
}
else
tPacket.VLANID = VI.ID; //Make sure it is properly tagged.
}
}
}
}
}