EduNetworkBuilder/EduNetworkBuilder/NetworkCard.cs

727 lines
33 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization;
using System.IO;
using System.Xml;
namespace EduNetworkBuilder
{
[Serializable]
public class NetworkCard
{
public string MAC = NB.GenerateMACAddress(); //Technically we should make sure it is unique
List<NetworkInterface> interfaces = new List<NetworkInterface>();
public bool UsesDHCP = false;
public bool CanUseDHCP = false;
public bool MustUseDHCP = false;
private NicType myNicType = NicType.eth;
public HostNicID myID;
public int ConnectedLink=-1; //The link that is connected to this nic.
private int UniqueIdentifier = NB.GetUniqueIdentifier();
private string _nic_name="";
public IPAddress TunnelEndpoint;
public string EncryptionKey;
public string SSID;
public string WirelessKey
{
get { return EncryptionKey; }
set { EncryptionKey = value; }
}
public NetworkCard(int index, int HostID, string hostname, NicType theType = NicType.eth)
{
myNicType = theType;
_nic_name = myNicType.ToString() + index.ToString();
NetworkInterface nInterface = new NetworkInterface(NicName(), NB.ZeroIPString, NB.ZeroIPString, myID);
if(theType == NicType.lo)
nInterface = new NetworkInterface(NicName(), "127.0.0.1", "255.0.0.0", myID);
myID = new HostNicID(HostID, UniqueIdentifier,hostname,nInterface.nic_name);
interfaces.Add(nInterface);
ApplyNicRules();
SetIPForDHCP();
}
public NetworkCard(XmlNode theNode)
{
foreach (XmlNode Individual in theNode.ChildNodes)
{
XmlNodeType myNodetype = Individual.NodeType;
if (myNodetype == XmlNodeType.Element)
{
switch (Individual.Name.ToLower())
{
case "nictype":
myNicType = NB.ParseEnum<NicType>(Individual.InnerText);
break;
case "nicname":
_nic_name = Individual.InnerText;
break;
case "myid":
myID = new HostNicID(Individual);
break;
case "usesdhcp":
bool.TryParse(Individual.InnerText, out UsesDHCP);
break;
case "uniqueidentifier":
int.TryParse(Individual.InnerText, out UniqueIdentifier);
break;
case "interface":
NetworkInterface newIF = new NetworkInterface(Individual,myID);
interfaces.Add(newIF);
break;
case "mac":
string tmac = Individual.InnerText;
if (tmac.Length == MAC.Length)
MAC = tmac.ToUpper(); //Make sure it is all uppercase
break;
case "tunnelendpoint":
TunnelEndpoint = new IPAddress(Individual);
break;
case "encryptionkey":
EncryptionKey = Individual.InnerText;
break;
case "ssid":
SSID = Individual.InnerText;
break;
}
}
}
ApplyNicRules();
SetIPForDHCP();
}
private void ApplyNicRules()
{
//These are the defaults for the various nic types. They can be overridden by the device.
if(myNicType == NicType.eth || myNicType == NicType.management_interface || myNicType == NicType.wlan)
{
CanUseDHCP = true;
}
else
{
CanUseDHCP = false;
}
}
public void Save(XmlWriter writer)
{
writer.WriteStartElement("nic");
writer.WriteElementString("nictype", myNicType.ToString());
writer.WriteElementString("nicname", _nic_name);
myID.Save(writer, "myid");
writer.WriteElementString("nictype", myNicType.ToString());
writer.WriteElementString("uniqueidentifier", UniqueIdentifier.ToString());
writer.WriteElementString("usesdhcp", UsesDHCP.ToString());
if(EncryptionKey != "")
writer.WriteElementString("encryptionkey", EncryptionKey);
if (SSID != "")
writer.WriteElementString("ssid", SSID);
if (TunnelEndpoint != null)
{
TunnelEndpoint.Save(writer, "tunnelendpoint");
}
foreach (NetworkInterface nIF in interfaces)
{
nIF.Save(writer);
}
writer.WriteEndElement();
}
public int GetUniqueIdentifier
{
get { return UniqueIdentifier; }
}
public NicType GetNicType
{
get { return myNicType; }
}
public bool isWireless()
{
if (myNicType == NicType.wport || myNicType == NicType.wlan)
return true;
return false;
}
public bool HasIP(UInt32 IP)
{
if (myNicType == NicType.port) return false;
if (myNicType == NicType.none) return false;
foreach (NetworkInterface IF in interfaces)
{
if (IF.myIP.Equals(IP))
return true;
}
return false;
}
public string NicName()
{
return _nic_name;
}
public string NicString(int index)
{
string connected = " ";
if (isConnected(true)) connected = "*";
if (myNicType == NicType.port || myNicType == NicType.wport)
return NicName() + connected;
return NicName() + connected + " " + MAC;
}
public List<string> NICRouteStrings(string GW)
{
List<string> thestrings = new List<string>();
if (myNicType == NicType.port) return thestrings;
if (myNicType == NicType.none) return thestrings;
foreach (NetworkInterface iface in interfaces)
{
thestrings.Add(iface.RouteString(_nic_name,GW));
}
return thestrings;
}
public List<string> IPAddresses(bool UseCidr = false)
{
List<string> theIPs = new List<string>();
if (myNicType == NicType.port) return theIPs;
if (myNicType == NicType.wport) return theIPs;
if (myNicType == NicType.none) return theIPs;
string DHCPString = "";
if (UsesDHCP && CanUseDHCP) DHCPString = "DHCP: ";
foreach (NetworkInterface iface in interfaces)
{
theIPs.Add(DHCPString + iface.InterfaceString(UseCidr));
}
return theIPs;
}
public List<IPAddress> IPAddressList()
{
List<IPAddress> theIPs = new List<IPAddress>();
if (myNicType == NicType.port) return theIPs;
if (myNicType == NicType.none) return theIPs;
foreach (NetworkInterface iface in interfaces)
{
theIPs.Add(iface.myIP);
}
return theIPs;
}
public bool HasIPAddresses(IPAddress dest)
{
if (myNicType == NicType.port) return false;
if (myNicType == NicType.none) return false;
if (dest == null) return false;
foreach (NetworkInterface iface in interfaces)
{
if (iface.myIP.GetIP == dest.GetIP)
return true;
}
return false;
}
public bool HasBroadcastAddresses(IPAddress dest)
{
if (myNicType == NicType.port) return false;
if (myNicType == NicType.none) return false;
if (myNicType == NicType.lo) return false;
if (dest == null) return false;
foreach (NetworkInterface iface in interfaces)
{
if (iface.myIP.BroadcastAddress == 0) continue; //a netmask of 0.0.0.0 causes grief
if (iface.myIP.BroadcastAddress == dest.GetIP)
return true;//If they are pinging the broadcast IP
if (iface.myIP.GetIPString == NB.BroadcastIPString)
return true;
}
return false;
}
public void EditInterface(int index)
{
if (index < 0 || index > interfaces.Count())
return;
interfaces[index].EditAddress();
}
public void DeleteInterface(int index)
{
if (index < 0 || index > interfaces.Count())
return;
if (interfaces.Count < 2)
return; //We cannot delete the sole remaining interface
interfaces.RemoveAt(index);
}
public void AddInterface()
{
NetworkInterface iface = new NetworkInterface(NicName(), NB.ZeroIPString, NB.ZeroIPString, myID);
interfaces.Add(iface);
}
public NetworkInterface GetInterface(int index)
{
if (index < 0 || index > interfaces.Count())
return null;
return interfaces[index];
}
public bool isConnected(bool CheckForBrokenLink)
{
if(ConnectedLink != -1)
{
if (!CheckForBrokenLink) return true; //We only care if there is any link
Network myNet = NB.GetNetwork();
NetworkLink NL = myNet.GetLinkFromID(ConnectedLink);
if(NL != null)
{
if (NL.theLinkType != LinkType.broken) return true;
else return false;
}
}
return false;
}
public void Edit()
{
NetworkCardEditor nce = new NetworkCardEditor(this);
nce.ShowDialog();
//Now. update the interfaces if we need to do so.
SetIPForDHCP();
}
public void SetIPForDHCP()
{
if (UsesDHCP && CanUseDHCP)
{
//remove any extra interfaces.
//set the one interface to 0.0.0.0
switch(myNicType)
{
case NicType.eth:
case NicType.wlan:
interfaces.Clear(); //empty out all interfaces
//Give it an interface with an empty IP
NetworkInterface nInterface = new NetworkInterface(NicName(), NB.ZeroIPString, NB.ZeroIPString,myID);
interfaces.Add(nInterface);
break;
}
}
}
public void SetIPForDHCP(IPAddress newIP)
{
if (UsesDHCP && CanUseDHCP)
{
bool doIt = true;
if (interfaces.Count > 0 && interfaces[0].myIP.GetIPString == NB.ZeroIPString)
{
doIt = true;
}
else
{
if(interfaces.Count > 0)
{
//The IP address is not zero. This means it already has an IP.
Random rnd = NB.GetRandom();
int chance = rnd.Next(6);
if (chance > 3)
doIt = false;
}
}
if (doIt && interfaces.Count > 0)
{
interfaces[0].myIP = newIP;
}
}
}
public bool HasLocalInterface(IPAddress theIP)
{
foreach(NetworkInterface nIF in interfaces)
{
if (nIF.isLocal(theIP))
return true;
}
return false;
}
/// <summary>
/// Return the interface that is considered "local" to the IP address we are trying to reach
/// </summary>
/// <param name="theIP">An IP address we are trying to send out</param>
/// <returns>null if no interface is local. Otherwise, it returns the one that matches the packet</returns>
public NetworkInterface LocalInterface(IPAddress theIP, PacketMessage Tracker)
{
if (myNicType == NicType.port) return null; //ports have no local interfaces
foreach (NetworkInterface nIF in interfaces)
{
if (nIF.isLocal(theIP))
{
if(Tracker != null)
Tracker.AddMessage(DebugLevel.routing, myID.HostName, "Found local interface: ip" + nIF.myIP.GetIP.ToIpString() +
" gw:" + nIF.myIP.GetMask.ToIpString());
if(Tracker != null && theIP != null)
Tracker.AddMessage(DebugLevel.routing, myID.HostName, " IP of local: " + theIP.GetIPString + " " + theIP.GetGateway.ToIpString());
return nIF;
}
}
return null;
}
public NetworkInterface PrimaryInterface()
{
if (interfaces.Count == 1)
return interfaces[0];
return null;
}
/***************************************
*
* *************************************/
public bool SendPacketOutNIC(Packet tPacket)
{
bool madeprogress = false;
Packet nPacket = null;
Network myNet = NB.GetNetwork();
NetworkLink nl;
if (NB.GetComponentType(tPacket.WhereAmI) != GeneralComponentType.device) return false; //we cannot do this.
NetworkDevice WhereFrom = (NetworkDevice)tPacket.WhereAmI;
NicType what = GetNicType;
if (!tPacket.isFresh && WhereFrom.IsWirelessForwarder() && (what == NicType.wlan || (WhereFrom.GetNetType() == NetworkComponentType.wap && what == NicType.eth)))
what = NicType.wport;
switch (what)
{
case NicType.lo:
case NicType.management_interface:
case NicType.none:
break; //Do nothing
case NicType.eth:
case NicType.wlan:
//see if it the packet dest is local to this nic
foreach (NetworkInterface nf in interfaces.ToList())
{
if (tPacket.InboundNic != null && tPacket.InboundNic == this &&
tPacket.InboundInterface != null && tPacket.InboundInterface == nf)
continue; //skip sending it out this interface if it came in this interface.
if (tPacket.MyType == PacketType.arp_request && !nf.isLocal(tPacket.destIP))
continue; //only send out arp requests on local networks
nPacket = new Packet(tPacket);//Creates a new packet but sets isfresh=false
if (tPacket.OutboundIP == null || (nf.isLocal(tPacket.OutboundIP) || (tPacket.OutboundIP.GetIPString == NB.BroadcastIPString && tPacket.isFresh)))
{
if ((nf != null && nf.myIP.GetIPString != NB.ZeroIPString) || nPacket.MyType == PacketType.dhcp_request)
{
//this means we have a local interface to send it out of
//if(nPacket.sourceMAC == null || nPacket.sourceMAC == "" || nPacket.isFresh)
nPacket.sourceMAC = MAC;
//If the source IP is empty then it is a new packet. We set the source to be us
if (nPacket.sourceIP == null || nPacket.sourceIP.GetIPString == NB.ZeroIPString)
nPacket.sourceIP = nf.myIP;
nPacket.TsourceIP = nf.myIP;
if (nPacket.destMAC == null || nPacket.destMAC == "")
{
nPacket.destMAC = WhereFrom.LookupArpFromIP(tPacket.OutboundIP.GetIPString);
if (nPacket.MyType == PacketType.arp_request)
{
nPacket.destMAC = NB.BroadcastMACString;
}
if(nPacket.destMAC == "")
{
nPacket.AddMessage(DebugLevel.debug, " No Machine matching that IP address on this subnet. " + nPacket.destIP.GetIPString);
Network mynet = NB.GetNetwork();
NetworkDevice nd = mynet.GetDeviceFromID(myID);
string hostname = "No Host";
if (nd != null) hostname = nd.hostname;
nPacket.Tracking.Status = hostname + " No Machine matching that IP address on this subnet. " + nPacket.destIP.GetIPString;
nPacket.MyStatus = PacketStatus.finished_failed;
return false;
}
}
nl = myNet.GetLinkFromID(ConnectedLink);
nPacket.StartOnLink(nl, WhereFrom); //This sends the packet down the link.
//Store outbound information here - som we expect the returning packet
WhereFrom.StoreOutgoingPacketInfo(nPacket);
myNet.addPacket(nPacket);
nPacket.PacketDump(myID.HostName + "-" + _nic_name, DebugPausePoint.packet_out);
madeprogress = true;
}
}
}
break;
case NicType.wan:
//see if it the packet dest is local to this nic
if (tPacket.MyType == PacketType.dhcp_answer && tPacket.isFresh)
break; //We do not broadcast out the WAN port
foreach (NetworkInterface nf in interfaces.ToList())
{
nPacket = new Packet(tPacket);//Creates a new packet but sets isfresh=false
if (tPacket.OutboundIP != null && (nf.isLocal(tPacket.OutboundIP) || tPacket.OutboundIP.GetIPString == NB.BroadcastIPString))
{
if ((nf != null && nf.myIP != null && nf.myIP.GetIPString != NB.ZeroIPString) || nPacket.MyType == PacketType.dhcp_request)
{
//this means we have a local interface to send it out of
nPacket.sourceMAC = MAC;
//If the source IP is empty then it originated from here. We set the source to be us
if (nPacket.sourceIP == null || nPacket.sourceIP.GetIPString == NB.ZeroIPString)
{
nPacket.sourceIP = nf.myIP;
WhereFrom.StoreOutgoingPacketInfo(nPacket); //the packet is not masqueraded, just accepted
}
else
{
//When we leave the WAN port, we are masqueraded. Track that.
WhereFrom.StoreOutgoingPacketInfo(nPacket, ResponseToPacket.masq);
//Now, we masquerade the packet so it looks like it comes fromhere
nPacket.Tracking.AddMessage(DebugLevel.natting, WhereFrom.hostname, "MASQ: Changing outbound IP to: " + nf.myIP.GetIPString);
nPacket.sourceIP = nf.myIP;
}
nPacket.TsourceIP = nf.myIP;
if (nPacket.destMAC == null || nPacket.destMAC == "")
{
nPacket.destMAC = WhereFrom.LookupArpFromIP(tPacket.OutboundIP.GetIPString);
if (nPacket.destMAC == "")
{
nPacket.AddMessage(DebugLevel.debug, " No Machine matching that IP address on this subnet. " + nPacket.destIP.GetIPString);
Network mynet = NB.GetNetwork();
NetworkDevice nd = mynet.GetDeviceFromID(myID);
string hostname = "No Host";
if (nd != null) hostname = nd.hostname;
nPacket.Tracking.Status = hostname + " No Machine matching that IP address on this subnet. " + nPacket.destIP.GetIPString;
nPacket.MyStatus = PacketStatus.finished_failed;
return false;
}
}
nl = myNet.GetLinkFromID(ConnectedLink);
nPacket.StartOnLink(nl, WhereFrom); //This sends the packet down the link.
//Store outbound information here - som we expect the returning packet
WhereFrom.StoreOutgoingPacketInfo(nPacket);
myNet.addPacket(nPacket);
nPacket.PacketDump(myID.HostName + "-" + _nic_name, DebugPausePoint.packet_out);
madeprogress = true;
}
}
}
break;
case NicType.tun:
case NicType.vpn:
foreach (NetworkInterface nf in interfaces.ToList())
{
if (nf.isLocal(tPacket.OutboundIP, false))
{
//We need to tell the original packet that it is inside another packet
tPacket.MyStatus = PacketStatus.encapsulated;
tPacket.TsourceIP = nf.myIP;
tPacket.destMAC = WhereFrom.LookupArpFromIP(tPacket.OutboundIP.GetIPString);
//We need to make a new, tunnel packet
if (myNicType == NicType.tun)
EncryptionKey = "";
Packet rnPacket = new Packet(tPacket);
WhereFrom.TunnelPacketFromHere(TunnelEndpoint, rnPacket, EncryptionKey);
//We need to send the new packet on (pass it back to the device to process)
madeprogress = true;
}
}
break;
case NicType.port:
case NicType.wport:
if (tPacket.InboundNic == this)
break; //This is the port we came in on. Do not sent it back out this port
nPacket = new Packet(tPacket);
if((tPacket.InboundNic != null && tPacket.InboundNic.GetNicType == NicType.wan) || tPacket.InboundNic == null || tPacket.destMAC == "")
{
//We need to find destination MAC and set source MAC
if(nPacket.sourceMAC == null || nPacket.sourceMAC == "" || nPacket.isFresh)
nPacket.sourceMAC = MAC;
//Update the MAC
string getMAC="";
if (tPacket.OutboundIP != null)
getMAC = WhereFrom.LookupArpFromIP(tPacket.OutboundIP.GetIPString);
else if(tPacket.destIP != null)
getMAC = WhereFrom.LookupArpFromIP(tPacket.destIP.GetIPString);
if (getMAC != "") nPacket.destMAC = getMAC;
if (nPacket.MyType == PacketType.arp_request)
{
nPacket.destMAC = NB.BroadcastMACString;
}
if (nPacket.destMAC == "")
{
nPacket.AddMessage(DebugLevel.debug, " No Machine matching that IP address on this subnet. " + nPacket.destIP.GetIPString);
Network mynet = NB.GetNetwork();
NetworkDevice nd = mynet.GetDeviceFromID(myID);
string hostname = "No Host";
if (nd != null) hostname = nd.hostname;
nPacket.Tracking.Status = hostname + " No Machine matching that IP address on this subnet. " + nPacket.destIP.GetIPString;
nPacket.MyStatus = PacketStatus.finished_failed;
return false;
}
}
if (HasBroadcastAddresses(tPacket.destIP))
{
//Broadcast packets will go to everything and we want a response from all of them.
nPacket.Tracking = PacketMessage.Clone(tPacket.Tracking);
}
if (nPacket.sourceMAC == null || nPacket.sourceMAC == "")
{
//Need to find the managament interface MAC
nPacket.sourceMAC = WhereFrom.HubManagementMAC();
}
if((nPacket.sourceIP == null || nPacket.sourceIP.GetIPString == NB.ZeroIPString) && nPacket.MyType != PacketType.dhcp_request)
{
//set it to be the ip of management interface
nPacket.sourceIP = WhereFrom.HubManagementIP();
nPacket.sourceMAC = MAC;
}
if (nPacket.destMAC == null || nPacket.destMAC == "" && tPacket.OutboundIP != null)
{
nPacket.destMAC = WhereFrom.LookupArpFromIP(tPacket.OutboundIP.GetIPString);
}
if(nPacket.TsourceIP == null)
nPacket.TsourceIP = WhereFrom.HubManagementIP();
nl = myNet.GetLinkFromID(ConnectedLink);
if (nl == null) break;
nPacket.StartOnLink(nl, WhereFrom); //This sends the packet down the link.
myNet.addPacket(nPacket);
if(tPacket.isFresh)
WhereFrom.StoreOutgoingPacketInfo(nPacket); //if it originated from here...
madeprogress = true;
nPacket.PacketDump(myID.HostName, DebugPausePoint.packet_out);
break;
}
return madeprogress;
}
//********************Process Packet ********
public void ProcessOutboundPacket(Packet tPacket)
{
//We set the MAC addrss to this nic
tPacket.sourceMAC = MAC;
//If the nic has a special function, we need to do that too.
// VPN, etc
}
public void ProcessInboundPacket(Packet tPacket)
{
Network mynet;
NetworkDevice nd;
//We make sure the MAC matches.
mynet = NB.GetNetwork();
nd = mynet.GetDeviceFromID(myID);
if (tPacket == null) return;
tPacket.InboundNic = this; //track which nic we came in on.
if (myNicType == NicType.port || myNicType == NicType.wport || (nd.IsWirelessForwarder() && (myNicType == NicType.wlan ||
(myNicType == NicType.eth && nd.GetNetType() == NetworkComponentType.wap ))))
{
//Try tracking the arp if we can
if (tPacket.TsourceIP == null) tPacket.TsourceIP = tPacket.sourceIP;
nd.StoreArp(tPacket.sourceMAC, tPacket.TsourceIP.GetIP.ToIpString(), myID);
//If it is a return DHCP packet. We should try to update the MAC
if (tPacket.MyType == PacketType.dhcp_answer)
{
HostNicID otherid = nd.NicIDFromArp(tPacket.destMAC);
if (otherid.HostID != -1)
{
string ipstring = NB.ZeroIPString;
if (tPacket.payloadIP != null)
ipstring = tPacket.payloadIP.GetIPString;
nd.StoreArp(tPacket.destMAC, ipstring, otherid);
}
}
return;
}
if(myNicType == NicType.wan)
{
mynet = NB.GetNetwork();
nd = mynet.GetDeviceFromID(myID);
if(nd.HowToRespondToPacket(tPacket) == ResponseToPacket.masq)
{
IPAddress oAddress = nd.PacketMasqueradeSource(tPacket);
if(oAddress != null)
{
tPacket.Tracking.AddMessage(DebugLevel.natting, nd.hostname, "MASQ: Changing source IP back to: " + oAddress.GetIPString);
tPacket.destIP = oAddress;
}
}
else if(!HasIP(tPacket.destIP.GetIP))
{
tPacket.AddMessage(DebugLevel.routing, "The packet was rejected by the firewall.");
tPacket.AddMessage(DebugLevel.debug, " The packet was not expected by the firewall, so it was rejected.");
mynet = NB.GetNetwork();
nd = mynet.GetDeviceFromID(myID);
string hostname = "No Host";
if (nd != null) hostname = nd.hostname;
tPacket.Tracking.Status = hostname + " The packet was rejected by the firewall.. Dropped.";
tPacket.MyStatus = PacketStatus.finished_failed;
}
}
if(tPacket.destMAC == MAC || tPacket.destMAC == NB.BroadcastMACString || myNicType == NicType.port)
{
//It matches. We are ok. Anything to do?
//If the NIC is a vpn, do that here.
}
else
{
tPacket.AddMessage(DebugLevel.routing,"The Packet was destined for a different machine (MAC Address): Rejected");
tPacket.AddMessage(DebugLevel.debug, " Device MAC: " + MAC + " did not match packet: " + tPacket.destMAC);
mynet = NB.GetNetwork();
nd = mynet.GetDeviceFromID(myID);
string hostname = "No Host";
if (nd != null) hostname = nd.hostname;
tPacket.Tracking.Status = hostname + " Packet destined for another machine. Dropped.";
tPacket.MyStatus = PacketStatus.finished_failed;
}
}
public void ClearIPs()
{
foreach(NetworkInterface nf in interfaces)
{
if(myNicType != NicType.lo)
nf.myIP = new IPAddress(NB.ZeroIPString);
}
}
public IPAddress FirstIP()
{
List<IPAddress> addresses = IPAddressList();
if (addresses.Count > 0)
return addresses[0];
else
return new IPAddress(NB.ZeroIPString);
}
public static T Clone<T>(T source)
{
if (!typeof(T).IsSerializable)
{
throw new ArgumentException("The type must be serializable.", "source");
}
// Don't serialize a null object, simply return the default for that object
if (Object.ReferenceEquals(source, null))
{
return default(T);
}
IFormatter formatter = new BinaryFormatter();
Stream stream = new MemoryStream();
using (stream)
{
formatter.Serialize(stream, source);
stream.Seek(0, SeekOrigin.Begin);
return (T)formatter.Deserialize(stream);
}
}
}
}