546 lines
23 KiB
C#
546 lines
23 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.Drawing;
|
|
using System.Text.RegularExpressions;
|
|
|
|
namespace EduNetworkBuilder
|
|
{
|
|
//This is a network packet that can either contain data, or another packet
|
|
[Serializable]
|
|
public class Packet
|
|
{
|
|
public PacketType MyType = PacketType.none;
|
|
public PacketStatus _MyStatus = PacketStatus.processing; //new packets start by being processed by the source device
|
|
public PacketStatus MyStatus
|
|
{
|
|
get { return _MyStatus; }
|
|
set {
|
|
_MyStatus = value;
|
|
if(_MyStatus == PacketStatus.finished_ok)
|
|
{
|
|
Tracking.Finished = true;
|
|
}
|
|
if (_MyStatus == PacketStatus.finished_failed || _MyStatus == PacketStatus.finished_ok)
|
|
{
|
|
string status = _MyStatus.ToString();
|
|
PacketDump(" " + status, DebugPausePoint.packet_kill);
|
|
}
|
|
if (_MyStatus == PacketStatus.finished_ok)
|
|
Tracking.Finished = true;
|
|
}
|
|
}
|
|
public int packetID;
|
|
public int VLANID = NB.UntaggedVLAN; //starts on the management vlan
|
|
public int TTL = 20;
|
|
public int OrigTTL = 20; //The original TTL. We need to know what we started with so we can pass it back on a traceroute
|
|
public int TickTTL = 50;
|
|
public int health = 100;
|
|
public IPAddress sourceIP;
|
|
public IPAddress OriginalDestIP;
|
|
public IPAddress TsourceIP; //This is the local link source ip. It should go along with the local MAC address
|
|
public IPAddress destIP;
|
|
public string sourceMAC;
|
|
public string destMAC;
|
|
public Packet payloadPacket = null;
|
|
public string payloadData = ""; //Contains the mac-address, or ip-address string, or something else
|
|
public string EncryptionString = "";
|
|
public IPAddress payloadIP = null;
|
|
public PacketMessage Tracking = new PacketMessage();
|
|
public NetworkComponent WhereAmI = null;
|
|
public NetworkLink LastNetworkLink = null;
|
|
public nb_direction myDirection = nb_direction.none;
|
|
public int myLinkPercent = 0; //How far along the path are we. 0%, 50%, 100%. For moving a dot along the link line
|
|
public bool packet_good = true;
|
|
DateTime StartTime = DateTime.Now;
|
|
public NetworkCard OutboundNic = null;
|
|
public NetworkCard InboundNic = null;
|
|
public NetworkInterface InboundInterface = null;
|
|
public NetworkInterface OutboundIF = null;
|
|
public IPAddress OutboundIP = new IPAddress(NB.ZeroIPString);
|
|
public string OutboundMAC = "";
|
|
public string OutboundDestMAC = "";
|
|
public bool isFresh = false; //Set to be true if the packet is new. Set false as soon as it is processed
|
|
public bool DebugOn = false;
|
|
|
|
public bool ready_to_delete
|
|
{
|
|
get {
|
|
Tracking.duration = DateTime.Now - StartTime;
|
|
|
|
if (MyStatus == PacketStatus.finished_failed)
|
|
{
|
|
packet_good = false;
|
|
return true;
|
|
}
|
|
if (MyStatus == PacketStatus.finished_ok)
|
|
{
|
|
packet_good = true; //It should already be good, but we state it just in case
|
|
return true;
|
|
}
|
|
if (MyStatus == PacketStatus.finished)
|
|
{
|
|
packet_good = true; //It should already be good, but we state it just in case
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
public Packet(Packet copyfrom)
|
|
{
|
|
MyType = copyfrom.MyType;
|
|
TTL = copyfrom.TTL;
|
|
OrigTTL = copyfrom.OrigTTL;
|
|
sourceIP = copyfrom.sourceIP;
|
|
TsourceIP = copyfrom.TsourceIP;
|
|
destIP = copyfrom.destIP;
|
|
sourceMAC = copyfrom.sourceMAC;
|
|
destMAC = copyfrom.destMAC;
|
|
payloadData = copyfrom.payloadData;
|
|
payloadPacket = copyfrom.payloadPacket;
|
|
EncryptionString = copyfrom.EncryptionString;
|
|
payloadIP = copyfrom.payloadIP;
|
|
Tracking = copyfrom.Tracking;
|
|
WhereAmI = copyfrom.WhereAmI;
|
|
health = copyfrom.health;
|
|
StartTime = copyfrom.StartTime;
|
|
OriginalDestIP = copyfrom.OriginalDestIP;
|
|
packetID = copyfrom.packetID;
|
|
VLANID = copyfrom.VLANID;
|
|
Tracking.AddMessage(DebugLevel.debug, WhereAmI, NB.Translate("P_PacketDuplicated"));
|
|
}
|
|
|
|
//Generate a packet with the given payload.
|
|
public Packet(NetworkComponent start, string source, string dest, string payload, PacketType theType, int NewPacketID=-1, int startTTL = -1)
|
|
{
|
|
if (NewPacketID == -1)
|
|
{
|
|
packetID = NB.nextPacketID();
|
|
}
|
|
else
|
|
{
|
|
packetID = NewPacketID;
|
|
}
|
|
if (startTTL != -1) this.TTL = startTTL;
|
|
OrigTTL = TTL;
|
|
WhereAmI = start;
|
|
payloadData = payload;
|
|
MyType = theType;
|
|
if(theType == PacketType.arp_answer || theType == PacketType.arp_request ||
|
|
theType == PacketType.dhcp_request || theType == PacketType.dhcp_answer)
|
|
{
|
|
sourceMAC = source;
|
|
destMAC = dest;
|
|
OutboundDestMAC = dest;
|
|
Tracking.AddMessage(DebugLevel.info, start, theType.ToString() + string.Format(NB.Translate("Packet Created")));
|
|
Tracking.AddMessage(DebugLevel.routing, start, string.Format(" MAC: {0} -> {1}", source, dest));
|
|
}
|
|
else
|
|
{
|
|
sourceIP = new IPAddress(source);
|
|
TsourceIP = new IPAddress(source);
|
|
destIP = new IPAddress(dest);
|
|
if (destIP.BroadcastAddress == destIP.GetIP)
|
|
{
|
|
destMAC = NB.BroadcastMACString;
|
|
OutboundDestMAC = destMAC;
|
|
}
|
|
Tracking.AddMessage(DebugLevel.info, start, NB.Translate("Packet Created"));
|
|
Tracking.AddMessage(DebugLevel.routing, start, string.Format(" IP: {0} -> {1}", source, dest));
|
|
Tracking.AddMessage(DebugLevel.debug, start, string.Format(NB.Translate(" IPs Translated {0} -> {1}"),sourceIP.GetIP.ToIpString(), destIP.GetIP.ToIpString()));
|
|
}
|
|
isFresh = true;
|
|
}
|
|
|
|
public Packet(NetworkComponent start, IPAddress dest, string payload, PacketType theType, int NewPacketID = -1, int startTTL =-1)
|
|
{
|
|
WhereAmI = start;
|
|
payloadData = payload;
|
|
MyType = theType;
|
|
if (NewPacketID == -1)
|
|
{
|
|
packetID = NB.nextPacketID();
|
|
}
|
|
else
|
|
{
|
|
packetID = NewPacketID;
|
|
}
|
|
|
|
if (startTTL != -1) this.TTL = startTTL;
|
|
OrigTTL = TTL;
|
|
|
|
if (theType != PacketType.arp_answer && theType != PacketType.arp_request)
|
|
{
|
|
sourceIP = new IPAddress(NB.ZeroIPString);
|
|
destIP = dest;
|
|
if (destIP != null && destIP.BroadcastAddress == destIP.GetIP)
|
|
destMAC = NB.BroadcastMACString;
|
|
Tracking.AddMessage(DebugLevel.info, start, NB.Translate("Packet Created"));
|
|
Tracking.AddMessage(DebugLevel.routing, start, string.Format(" IP:{0} -> {1}", sourceIP.GetIP.ToIpString(), dest.GetIP.ToIpString()));
|
|
}
|
|
else
|
|
{
|
|
sourceIP = new IPAddress(NB.ZeroIPString);
|
|
destMAC = NB.BroadcastMACString;
|
|
destIP = dest;
|
|
Tracking.AddMessage(DebugLevel.info, start, NB.Translate("Packet Created"));
|
|
//Tracking.AddMessage(DebugLevel.routing, start, " IP:" + sourceIP.GetIP.ToIpString() + " -> " + dest.GetIP.ToIpString());
|
|
}
|
|
isFresh = true;
|
|
}
|
|
|
|
public Point PacketLocation()
|
|
{
|
|
if (NB.GetComponentType(WhereAmI) != GeneralComponentType.link)
|
|
return new Point(-1,-1);
|
|
NetworkLink Nl = (NetworkLink)WhereAmI;
|
|
Point mylocation = Nl.PositionOnLine(myDirection, myLinkPercent);
|
|
return mylocation;
|
|
}
|
|
|
|
public Rectangle PacketRectangle()
|
|
{
|
|
Point start = PacketLocation();
|
|
int half = NB.PacketPixelSize / 2;
|
|
return new Rectangle(start.X - half, start.Y - half, NB.PacketPixelSize, NB.PacketPixelSize);
|
|
}
|
|
|
|
public void Print(Image BaseImage)
|
|
{
|
|
//we draw a packet on the map
|
|
Point thePoint = PacketLocation();
|
|
if (thePoint.X == -1 || thePoint.Y == -1) return; //It is an invalid location
|
|
Color pencolor = Color.Blue;
|
|
switch (MyType)
|
|
{
|
|
case PacketType.arp_answer:
|
|
case PacketType.arp_request:
|
|
pencolor = Color.Green;
|
|
break;
|
|
case PacketType.dhcp_answer:
|
|
case PacketType.dhcp_request:
|
|
pencolor = Color.Red;
|
|
break;
|
|
case PacketType.ping_answer:
|
|
case PacketType.ping_request:
|
|
pencolor = Color.Blue;
|
|
break;
|
|
case PacketType.tracert_reply:
|
|
case PacketType.tracert_request:
|
|
pencolor = Color.LightBlue;
|
|
break;
|
|
case PacketType.tun_packet:
|
|
pencolor = Color.White;
|
|
break;
|
|
case PacketType.vpn_packet:
|
|
pencolor = Color.Orange;
|
|
break;
|
|
}
|
|
Network theNet = NB.GetNetwork();
|
|
if (theNet == null)
|
|
{
|
|
Pen myPen = new Pen(pencolor, NB.PacketPixelSize);
|
|
Graphics.FromImage(BaseImage).DrawEllipse(myPen, PacketRectangle());
|
|
}
|
|
else
|
|
{
|
|
Color VLANPacketColor = theNet.ColorFromPacketVLAN(VLANID);
|
|
//if (VLANPacketColor != Color.Blue)
|
|
// pencolor = VLANPacketColor;
|
|
Image tImage = theNet.GetPacketImage(pencolor, VLANPacketColor);
|
|
//if (VLANPacketColor != Color.Blue && VLANPacketColor != Color.Empty)
|
|
//{
|
|
// tImage = theNet.ColoredImage(tImage, VLANPacketColor);
|
|
//}
|
|
Graphics.FromImage(BaseImage).DrawImage(tImage, PacketRectangle());
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// See if we need to do anything for a packet. If so, do one step in processing it
|
|
/// </summary>
|
|
public void ProcessTick()
|
|
{
|
|
TickTTL--;
|
|
switch(MyStatus)
|
|
{
|
|
case PacketStatus.processing:
|
|
//The packet is "inside" the device.
|
|
// Here we masquerade
|
|
// Here we route
|
|
// Here the packet is just about to exit. Maybe we need to set the "source IP"
|
|
if (NB.PacketVersionNum != 2)
|
|
{
|
|
DoProcessing();
|
|
}
|
|
else
|
|
{
|
|
DoMainProcessing();
|
|
}
|
|
break;
|
|
case PacketStatus.finished_ok:
|
|
case PacketStatus.finished_failed:
|
|
break; //we do not have anything to do.
|
|
case PacketStatus.input: //Just entering a device.
|
|
case PacketStatus.moving: //Traversing a link
|
|
DoMoving();
|
|
break;
|
|
case PacketStatus.output: //Just leaving a device
|
|
break;
|
|
case PacketStatus.waiting_for_arp: //We need to see if the arp information has shown up. If so, we resume
|
|
if (NB.GetComponentType(WhereAmI) == GeneralComponentType.device)
|
|
{
|
|
NetworkDevice ndWhere = (NetworkDevice)WhereAmI;
|
|
IPAddress dest = ndWhere.DestinationFromIP(destIP);
|
|
string dMAC = ndWhere.ArpFromIP(dest.GetIP.ToIpString());
|
|
if (dMAC != "" || destMAC == NB.BroadcastMACString)
|
|
{
|
|
MyStatus = PacketStatus.processing;
|
|
}
|
|
else
|
|
{
|
|
Network MyNet = NB.GetNetwork();
|
|
if(MyNet.CountPackets(PacketType.arp_answer) + MyNet.CountPackets(PacketType.arp_request) == 0)
|
|
{
|
|
//No more arps going. We do not have an answer!
|
|
Tracking.AddMessage(DebugLevel.info, WhereAmI, NB.Translate("P_ProcessTick") + ": "+ dest.GetIP.ToIpString());
|
|
Tracking.Status = NB.LeftPad(WhereAmI.hostname) + NB.Translate("P_ProcessTick");
|
|
MyStatus = PacketStatus.finished_failed;
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
private void DoMainProcessing()
|
|
{
|
|
//We pass it to the device
|
|
if (WhereAmI == null)
|
|
{
|
|
AddMessage(DebugLevel.debug, NB.Translate("P_PacketLostLong"));
|
|
Tracking.Status = NB.Translate("P_PacketLostShort");
|
|
MyStatus = PacketStatus.finished_failed;
|
|
return; //We cannot process the packet
|
|
}
|
|
WhereAmI.ProcessPacket(this);//The device knows how to do the processing
|
|
}
|
|
|
|
private void DoProcessing()
|
|
{
|
|
//The packet is "inside" the device.
|
|
// Here we masquerade
|
|
// Here we route
|
|
// Here the packet is just about to exit. Maybe we need to set the "source IP"
|
|
|
|
//We need to find out which interface we are leaving.
|
|
//Then we figure out what rules we need to follow from there
|
|
//So, we pass the packet to the device to process
|
|
if (WhereAmI == null)
|
|
{
|
|
AddMessage(DebugLevel.debug, NB.Translate("P_PacketLostLong"));
|
|
Tracking.Status = NB.Translate("P_PacketLostShort");
|
|
MyStatus = PacketStatus.finished_failed;
|
|
return; //We cannot process the packet
|
|
}
|
|
WhereAmI.DoProcessing(this);//The device knows how to do the processing
|
|
}
|
|
|
|
private void DoMoving()
|
|
{
|
|
if (WhereAmI == null)
|
|
{
|
|
AddMessage(DebugLevel.debug, NB.Translate("P_PacketLostLong"));
|
|
Tracking.Status = NB.Translate("P_PacketLostShort");
|
|
MyStatus = PacketStatus.finished_failed;
|
|
return; //We cannot process the packet
|
|
}
|
|
WhereAmI.DoMoving(this);//The device knows how to do the processing
|
|
}
|
|
|
|
public void ReplaceMessage(PacketMessage Tracker)
|
|
{
|
|
Tracking = Tracker; //We do this if we are making a new packet, but tracking it with the old one.
|
|
//We do this for arp requests.
|
|
}
|
|
|
|
public void StartOnLink(NetworkLink theLink, NetworkDevice start_device)
|
|
{
|
|
if (theLink == null) return;
|
|
//Console.WriteLine("Starting on link: " + theLink.GetUniqueIdentifier + " vlanID = " + VLANID.ToString());
|
|
|
|
//We are just about to go out. Verify we are not getting blocked by the firewall.
|
|
if (start_device.FirewallRules.Count > 0)
|
|
{
|
|
if (InboundInterface != null && OutboundIF != null)
|
|
{
|
|
if (!start_device.FirewallAllows(InboundInterface.nic_name, OutboundIF.nic_name))
|
|
{
|
|
ResponseToPacket rtp = start_device.HowToRespondToPacket(this);
|
|
if (rtp != ResponseToPacket.accept)
|
|
{
|
|
//If we are here, the packet is rejected.
|
|
string message = string.Format(NB.Translate("P_FirewallDropped"), start_device.hostname);
|
|
AddMessage(DebugLevel.filtering, message);
|
|
Tracking.Status = message;
|
|
Tracking.AddMessage(DebugLevel.info, start_device, message);
|
|
AddMessage(DebugLevel.info, message);
|
|
MyStatus = PacketStatus.finished_ok;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
InboundNic = null;
|
|
InboundInterface = null;
|
|
WhereAmI = theLink;
|
|
LastNetworkLink = theLink;
|
|
MyStatus = PacketStatus.moving;
|
|
myLinkPercent = 0;
|
|
TickTTL = 200; //We keep resetting this as we go.
|
|
OutboundIF = null;
|
|
OutboundIP = null;
|
|
OutboundMAC = "";
|
|
OutboundNic = null;
|
|
if (theLink.IsSource(start_device.GetUniqueIdentifier))
|
|
myDirection = nb_direction.to_dst;
|
|
else
|
|
myDirection = nb_direction.to_src;
|
|
//Console.WriteLine(NB.Translate("P_StartingOnLink") + string.Format(" SMAC: {0} DMAC: {1}",sourceMAC,destMAC));
|
|
AddMessage(DebugLevel.debug, " " + NB.Translate("P_StartingOnLink"));
|
|
}
|
|
|
|
public void StartOnDevice(NetworkDevice theDevice)
|
|
{
|
|
WhereAmI = theDevice;
|
|
MyStatus = PacketStatus.processing;
|
|
myLinkPercent = 0;
|
|
TickTTL = 200;
|
|
}
|
|
|
|
public void PrepareToDelete()
|
|
{
|
|
Network myNet = NB.GetNetwork();
|
|
if(myNet != null)
|
|
{
|
|
if (payloadPacket != null)
|
|
{
|
|
payloadPacket.PrepareToDelete();
|
|
payloadPacket.Tracking.AddMessage(DebugLevel.info, WhereAmI, Tracking.Status);
|
|
payloadPacket.Tracking.Status = Tracking.Status;
|
|
payloadPacket.MyStatus = MyStatus;
|
|
}
|
|
if(MyType == PacketType.arp_request && MyStatus == PacketStatus.finished_failed)
|
|
{
|
|
Tracking.AddMessage(DebugLevel.info, NB.Translate("P_Packet"),
|
|
NB.Translate("P_PacketFailedToReach") + ": " + destIP.GetIPString);
|
|
Tracking.Status = NB.Translate("P_PacketFailedToReach2") + ": "+ destIP.GetIPString;
|
|
MyStatus = PacketStatus.finished_failed;
|
|
}
|
|
if (MyStatus != PacketStatus.finished)
|
|
myNet.AddMessage(Tracking); //We only store finished_failed, and finished_ok
|
|
//if (sourceIP != null && destIP != null)
|
|
//{
|
|
// if (MyType == PacketType.ping_answer && MyStatus == PacketStatus.finished_failed)
|
|
// {
|
|
// myNet.NoteActionDone(NetTestType.FailedPing, destIP.GetIPString, sourceIP.GetIPString);
|
|
// }
|
|
// if (MyType == PacketType.ping_request && MyStatus == PacketStatus.finished_failed)
|
|
// {
|
|
// myNet.NoteActionDone(NetTestType.FailedPing, sourceIP.GetIPString, destIP.GetIPString);
|
|
// if(WhereAmI != null)
|
|
// Console.WriteLine("Dropping at: "+ WhereAmI.hostname);
|
|
// }
|
|
//}
|
|
}
|
|
}
|
|
|
|
public void AddMessage(DebugLevel tLevel, string tMessage)
|
|
{
|
|
Tracking.AddMessage(tLevel, WhereAmI, tMessage);
|
|
}
|
|
|
|
public void IncrementDistance()
|
|
{
|
|
myLinkPercent += NB.LinkStep;
|
|
}
|
|
|
|
public bool Arrived()
|
|
{
|
|
if (myLinkPercent >= 100)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
public bool isFinshed()
|
|
{
|
|
if (_MyStatus == PacketStatus.finished_ok) return true;
|
|
if (_MyStatus == PacketStatus.finished_failed) return true;
|
|
if (_MyStatus == PacketStatus.finished_ok) return true;
|
|
return false;
|
|
}
|
|
|
|
private bool debugIsSet(DebugPausePoint what)
|
|
{
|
|
DebugPausePoint SetPoint = NB.GetDebugPauseSetting();
|
|
if ((SetPoint & what) == what)
|
|
return true;
|
|
return false;
|
|
}
|
|
public void PacketDump(string hostname, DebugPausePoint WhereWeAre)
|
|
{
|
|
DebugPausePoint WhatIsSet = NB.GetDebugPauseSetting();
|
|
string position = WhereWeAre.ToString();
|
|
string sIP = NB.ZeroIPString;
|
|
string dIP = NB.ZeroIPString;
|
|
if (sourceIP != null) sIP = sourceIP.GetIPString;
|
|
if (destIP != null) dIP = destIP.GetIPString;
|
|
position = Regex.Replace(position, "packet_", "");
|
|
if ((WhereWeAre & WhatIsSet) != WhereWeAre)
|
|
return; //We are not set to debug here.
|
|
if ((WhatIsSet & DebugPausePoint.pause) == DebugPausePoint.pause)
|
|
{
|
|
Console.WriteLine("Pausing");
|
|
}
|
|
if ((WhatIsSet & DebugPausePoint.dump) == DebugPausePoint.dump)
|
|
{
|
|
Console.WriteLine(string.Format("{0}: {1} PACKET: dstIP: {2} destMAC: {3}", hostname, position, dIP, destMAC));
|
|
Console.WriteLine(string.Format("{0}: {1} PACKET: srcIP: {2} srcMAC: {3}", hostname, position, sIP, sourceMAC));
|
|
Console.WriteLine("---");
|
|
}
|
|
AddMessage(DebugLevel.packet, string.Format("{0}: {1} PACKET: dstIP: {2} destMAC: {3}", hostname, position, dIP, destMAC));
|
|
AddMessage(DebugLevel.packet, string.Format("{0}: {1} PACKET: srcIP: {2} srcMAC: {3}", hostname,position,sIP,sourceMAC));
|
|
}
|
|
|
|
public static T Clone<T>(T source)
|
|
{
|
|
if (!typeof(T).IsSerializable)
|
|
{
|
|
throw new ArgumentException(NB.Translate("NC_CloneSerialzable"), NB.Translate("NC_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);
|
|
}
|
|
}
|
|
}
|
|
}
|