EduNetworkBuilder/EduNetworkBuilder/Packet.cs

556 lines
24 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 NB_IPAddress sourceIP;
public NB_IPAddress OriginalDestIP;
public NB_IPAddress TsourceIP; //This is the local link source ip. It should go along with the local MAC address
public NB_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 NB_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 NB_IPAddress OutboundIP = new NB_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 TraversalClass TraversalInformation = new TraversalClass();
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"));
TraversalInformation = copyfrom.TraversalInformation.Clone();
}
//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 NB_IPAddress(source);
TsourceIP = new NB_IPAddress(source);
destIP = new NB_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, NB_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 NB_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 NB_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;
case PacketType.bad_packet:
pencolor = Color.Black; //bad packets look bad
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;
NB_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"));
if(theLink.theLinkType == LinkType.wireless)
TraversalInformation.AddPath(theLink.hostname, TraversalTechnology.wireless,""); //We just went to wireless
else
TraversalInformation.AddPath(theLink.hostname, TraversalTechnology.ethernet,""); //We just went to ethernet
}
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 && MyType != PacketType.bad_packet)
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);
}
}
}
}