public override string ToString() { StringBuilder s = new StringBuilder(); for (int i = 0; i < 2; i++) { s.Append("List" + i.ToString() + "\r\n"); foreach (DictionaryEntry item in List[i]) { TCPState state = item.Value as TCPState; s.Append(item.Key.ToString() + ":" + state.State.ToString() + "\r\n"); } } return(s.ToString()); }
public void EndOfStream(TCPState state, int direction, string result) { Association Assoc = (Association)state.UserInfo; if(Assoc != null) // i.e. if DICOM { lock(Assoc) { OutputHandler("End : " + state.Signature[0] + "\r\n" + result + "\r\n",true,true); Assoc.Out(result + "\r\n",true); Assoc.HandleEnd(); if((state.State[0] != TCPState.States.RUNNING) && (state.State[1] != TCPState.States.RUNNING)) // i.e. if DICOM { state.Clear(); // should have been done elsewhere, but no harm to repeat // Select the first association from the list by default snifferObj.Invoke(snifferObj.SelectConnectionHandler); } //Handle incomplete byte stream if((result.IndexOf("DEAD data seen") != -1) && (((state.State[0] != TCPState.States.RUNNING) && (state.State[1] != TCPState.States.FINISHED)) || ((state.State[0] != TCPState.States.FINISHED) && (state.State[1] != TCPState.States.RUNNING)))) { Assoc.Dispose(true); state.Clear(); } //Handle unexpected Abort if(result == "Forced Close") { Assoc.Dispose(true); state.Clear(); } } } }
/// <summary> /// This is the main routine called from TCP layer for handling DICOM data /// </summary> /// <param name="state"></param> /// <param name="direction"></param> public void ReceiveTCPData(TCPState state, int direction) { byte[] p = state.data[direction]; int length = (int)state.Position[direction]; uint Position = 0; Association Assoc = (Association)state.UserInfo; bool TryAnotherPDU = true; while(length >= Position + 6 && TryAnotherPDU) { TryAnotherPDU = false; byte PDUType = p[Position]; uint Index = Position + 2; uint PDULength = DICOMUtility.Get4BytesBigEndian( p , ref Index); if(Assoc == null && PDUType == 1) { Assoc = new Association(state, BaseFileName + state.Signature[0], System.DateTime.Now); Assoc.Output += new Association.OutputEvent(OutputHandler); state.UserInfo = Assoc; string signature = state.Signature[0]; list.Add(signature,Assoc); OutputHandler("New : " + signature + "\r\n",true,true); // snifferObj.Invoke(snifferObj.AddConnectionHandler, new object[] { signature }); } if(Assoc !=null && length >= Index + PDULength) { lock(Assoc) { Assoc.HandlePDU(p,Position,PDULength,direction, state); TryAnotherPDU = true; } } else if(length>64000 && Assoc==null) // non-DICOM { OutputHandler("Non-DICOM data : " + state.Signature[0] + "\r\n",true,true); break; // don't process any more if we have a currently unhandleable PDU } else { break; // don't prcess any more if we have a currently unhandleable PDU } Position += PDULength + 6; } if(Position > 0 ) { if(state.data[direction] != null) { state.UsedData(Position, direction); } // Check if there is anything we have "stacked up" on the other direction ReceiveTCPData(state, 1-direction); } return; }
public void AnalysePacket(PacketInfo data) { byte [] PacketData = data.Data; int StartIndex = data.StartIndex; int Index = StartIndex; // Start by eliminating non IP and non TCP packets if( ( Index + LENGTH_OF_INTERNET + LENGTH_OF_TCP ) > PacketData.Length ) { return ; } PacketINTERNET.PACKET_INTERNET PInternet = new PacketINTERNET.PACKET_INTERNET(); PInternet.Version = PacketData[ Index++ ]; PInternet.HeaderLength = (byte) ( ( (int) PInternet.Version & 0x0f ) * 4 ); PInternet.Version = (byte) ( (int) PInternet.Version >> 4 ); PInternet.DifferentiatedServicesField = PacketData[ Index++ ]; PInternet.Length = Function.Get2Bytes( PacketData , ref Index , Const.NORMAL ); PInternet.Identification = Function.Get2Bytes( PacketData , ref Index , Const.NORMAL ); PInternet.FragmentOffset = Function.Get2Bytes( PacketData , ref Index , Const.NORMAL ); PInternet.Flags = (byte)( (int) PInternet.FragmentOffset >> 12 ); PInternet.FragmentOffset = (ushort) ( (int) PInternet.FragmentOffset & 0x0f ); PInternet.TimeToLive = PacketData[ Index++ ]; PInternet.Protocol = PacketData[ Index++ ]; PInternet.HeaderChecksum = Function.Get2Bytes( PacketData , ref Index , Const.NORMAL ); PInternet.Source = Function.GetIpAddress( PacketData , ref Index ); PInternet.Destination = Function.GetIpAddress( PacketData , ref Index ); if(PInternet.Protocol != IPPROTO_TCP ) return; // Check IPs //if(!analysisFromCapFile) //{ if(((PInternet.Source == IP1) && (PInternet.Destination == IP1)) || (PInternet.Source == PInternet.Destination)) { return; } //} PacketTCP.PACKET_TCP PTcp = new PacketTCP.PACKET_TCP(); PTcp.SourcePort = Function.Get2Bytes( PacketData , ref Index , Const.NORMAL ); PTcp.DestinationPort = Function.Get2Bytes( PacketData , ref Index , Const.NORMAL ); PTcp.SequenceNumber = Function.Get4Bytes( PacketData , ref Index , Const.NORMAL ); PTcp.Acknowledgement = Function.Get4Bytes( PacketData , ref Index , Const.NORMAL ); PTcp.HeaderLength = PacketData[ Index++ ]; PTcp.HeaderLength = (byte) ( ( (int) PTcp.HeaderLength >> 4 ) * 4 ); PTcp.Flags = PacketData[ Index++ ]; PTcp.WindowSize = Function.Get2Bytes( PacketData , ref Index , Const.NORMAL ); PTcp.Checksum = Function.Get2Bytes( PacketData , ref Index , Const.NORMAL ); PTcp.Options = Function.Get2Bytes( PacketData , ref Index , Const.NORMAL ); //if(!analysisFromCapFile) //{ if(((PTcp.SourcePort == Port1) && (PTcp.DestinationPort == Port1)) || ((PTcp.SourcePort == Port2) && (PTcp.DestinationPort == Port2))) { return; } //} String signature = Signature(PInternet.Source, PTcp.SourcePort, PInternet.Destination, PTcp.DestinationPort); //Keep track of the connections which have been established.(The list will be used later to populate the Associations Combo Box.) if (!listOfConnections.Contains(signature)) { listOfConnections.Add(signature); } TCPPacket packet = new TCPPacket(PacketData, StartIndex , PInternet, PTcp, data.TimeStamp); LastParsedPacketTime = packet.TimeStamp; int match = -1; TCPState state; for(int i=0;i<2;i++) { if(List[i].Contains(signature)) { match=i; } } // add as new item if necessary if(match==(-1)) { //Need to check here that we have SYNs String signature1 = Signature(PInternet.Destination, PTcp.DestinationPort,PInternet.Source, PTcp.SourcePort); state = new TCPState(packet,signature, signature1); List[0].Add(signature,state); List[1].Add(signature1,state); match=0; } else { state = (TCPState) List[match][signature]; } lock(state) { if(state.State[match] != TCPState.States.REPORTED) { state.AddPacket(match,packet); TCPState.PacketAction LastAction; while((LastAction = state.Defragment(match)) == TCPState.PacketAction.DATA) { if(FragmentAdded != null) { FragmentAdded(state, match); } nrOfCapturedPackets++; } if(LastAction == TCPState.PacketAction.FIN) { if(EndOfStream != null) EndOfStream(state, match, "FIN Seen (" + signature + ")"); } if(LastAction == TCPState.PacketAction.RST) { if(EndOfStream != null) EndOfStream(state, match, "RST Seen (" + signature + ")"); } if(LastAction == TCPState.PacketAction.DEAD) { //Error("DEAD seen" + signature); if(EndOfStream != null) EndOfStream(state, match, "DEAD data seen (" + signature + ")"); } } } }
public void AnalysePacket(PacketInfo data) { byte [] PacketData = data.Data; int StartIndex = data.StartIndex; int Index = StartIndex; // Start by eliminating non IP and non TCP packets if ((Index + LENGTH_OF_INTERNET + LENGTH_OF_TCP) > PacketData.Length) { return; } PacketINTERNET.PACKET_INTERNET PInternet = new PacketINTERNET.PACKET_INTERNET(); PInternet.Version = PacketData[Index++]; PInternet.HeaderLength = (byte)(((int)PInternet.Version & 0x0f) * 4); PInternet.Version = (byte)((int)PInternet.Version >> 4); PInternet.DifferentiatedServicesField = PacketData[Index++]; PInternet.Length = Function.Get2Bytes(PacketData, ref Index, Const.NORMAL); PInternet.Identification = Function.Get2Bytes(PacketData, ref Index, Const.NORMAL); PInternet.FragmentOffset = Function.Get2Bytes(PacketData, ref Index, Const.NORMAL); PInternet.Flags = (byte)((int)PInternet.FragmentOffset >> 12); PInternet.FragmentOffset = (ushort)((int)PInternet.FragmentOffset & 0x0f); PInternet.TimeToLive = PacketData[Index++]; PInternet.Protocol = PacketData[Index++]; PInternet.HeaderChecksum = Function.Get2Bytes(PacketData, ref Index, Const.NORMAL); PInternet.Source = Function.GetIpAddress(PacketData, ref Index); PInternet.Destination = Function.GetIpAddress(PacketData, ref Index); if (PInternet.Protocol != IPPROTO_TCP) { return; } // Check IPs //if(!analysisFromCapFile) //{ if (((PInternet.Source == IP1) && (PInternet.Destination == IP1)) || (PInternet.Source == PInternet.Destination)) { return; } //} PacketTCP.PACKET_TCP PTcp = new PacketTCP.PACKET_TCP(); PTcp.SourcePort = Function.Get2Bytes(PacketData, ref Index, Const.NORMAL); PTcp.DestinationPort = Function.Get2Bytes(PacketData, ref Index, Const.NORMAL); PTcp.SequenceNumber = Function.Get4Bytes(PacketData, ref Index, Const.NORMAL); PTcp.Acknowledgement = Function.Get4Bytes(PacketData, ref Index, Const.NORMAL); PTcp.HeaderLength = PacketData[Index++]; PTcp.HeaderLength = (byte)(((int)PTcp.HeaderLength >> 4) * 4); PTcp.Flags = PacketData[Index++]; PTcp.WindowSize = Function.Get2Bytes(PacketData, ref Index, Const.NORMAL); PTcp.Checksum = Function.Get2Bytes(PacketData, ref Index, Const.NORMAL); PTcp.Options = Function.Get2Bytes(PacketData, ref Index, Const.NORMAL); //if(!analysisFromCapFile) //{ if (((PTcp.SourcePort == Port1) && (PTcp.DestinationPort == Port1)) || ((PTcp.SourcePort == Port2) && (PTcp.DestinationPort == Port2))) { return; } //} String signature = Signature(PInternet.Source, PTcp.SourcePort, PInternet.Destination, PTcp.DestinationPort); //Keep track of the connections which have been established.(The list will be used later to populate the Associations Combo Box.) if (!listOfConnections.Contains(signature)) { listOfConnections.Add(signature); } TCPPacket packet = new TCPPacket(PacketData, StartIndex, PInternet, PTcp, data.TimeStamp); LastParsedPacketTime = packet.TimeStamp; int match = -1; TCPState state; for (int i = 0; i < 2; i++) { if (List[i].Contains(signature)) { match = i; } } // add as new item if necessary if (match == (-1)) { //Need to check here that we have SYNs String signature1 = Signature(PInternet.Destination, PTcp.DestinationPort, PInternet.Source, PTcp.SourcePort); state = new TCPState(packet, signature, signature1); List[0].Add(signature, state); List[1].Add(signature1, state); match = 0; } else { state = (TCPState)List[match][signature]; } lock (state) { if (state.State[match] != TCPState.States.REPORTED) { state.AddPacket(match, packet); TCPState.PacketAction LastAction; while ((LastAction = state.Defragment(match)) == TCPState.PacketAction.DATA) { if (FragmentAdded != null) { FragmentAdded(state, match); } nrOfCapturedPackets++; } if (LastAction == TCPState.PacketAction.FIN) { if (EndOfStream != null) { EndOfStream(state, match, "FIN Seen (" + signature + ")"); } } if (LastAction == TCPState.PacketAction.RST) { if (EndOfStream != null) { EndOfStream(state, match, "RST Seen (" + signature + ")"); } } if (LastAction == TCPState.PacketAction.DEAD) { //Error("DEAD seen" + signature); if (EndOfStream != null) { EndOfStream(state, match, "DEAD data seen (" + signature + ")"); } } } } }
public Association(TCPState state, String filename, System.DateTime time) { State = state; BaseFileName = filename; startTimeForAssoc = time; textLog= File.CreateText(BaseFileName + ".log"); //Load SOP Class & Transfer Syntax maps sopClassMap = new SOPClassMap(); tsMap = new TransferSyntaxMap(); }
/// <summary> /// This is the main routine called from DICOM Analyzer layer for handling each PDU /// </summary> /// <param name="p"></param> /// <param name="Position"></param> /// <param name="length"></param> /// <param name="direction"></param> /// <param name="state"></param> public void HandlePDU(byte[] p, uint Position, uint length, int direction, TCPState state) { byte PDUType = p[Position]; uint Index = Position + 2; uint PDULength = DICOMUtility.Get4BytesBigEndian( p , ref Index); uint FinalPosition = Position + length +6 ; // include length of PDU header StringBuilder s = new StringBuilder(500); System.DateTime dt1 = state.GetTime(direction,Position); System.DateTime dt2 = state.GetTime(direction,Position+length-1); int pduLength = (int)PDULength + 6; byte[] pduData = new byte[pduLength]; Array.Copy(p,Position,pduData,0,pduLength); //Populate PDU list PDU_DETAIL pduDetail = new PDU_DETAIL(); pduDetail.PduType = PDUType; pduDetail.PduDirection = direction; pduDetail.PduIndex = PDUNumber; pduDetail.PduData = pduData; pduDetail.PduLength = PDULength + 6; //include length of PDU header pduDetail.startTime = startTimeForAssoc; pduDetail.timeStamp = System.DateTime.Now; if(PDUType != 4) { pduList.Add(pduDetail); } DumpPDU(p, Position, BaseFileName, direction, PDULength,PDUNumber++); s.Append(string.Format("{0} Type {1} PDU : Length = {2} : Direction = {3}\r\n",state.Signature[direction],PDUType,PDULength,(direction==0)?"OUT":"IN")); s.Append(string.Format("{0:dd-MMM-yy HH:mm:ss.ffffff} to {1:HH:mm:ss.ffffff}\r\n",dt1,dt2)); bool send = true; switch(PDUType) { case 1: case 2: { isLastDatasetFragmentRecd = false; isDataSetRecd = false; HandleRequestPDU(s, p,Position+6, PDULength, direction,PDUType); PopulateAssociationInfo(PDUType); break; } case 3: s.Append("Association Rejection\r\n"); break; case 4: { if(PDULength==6) { s.Append("Illegal empty PDV\r\n"); } isDataSetRecd = true; Position +=6; bool isCmdDataPDU = false; while(Position < FinalPosition) { uint PDVLen = DICOMUtility.Get4BytesBigEndian(p, ref Position); byte PCID = p[Position++]; byte Flags = p[Position++]; s.Append(" PDV Length=" + PDVLen.ToString() ); s.Append(" PCID = " + PCID.ToString()); s.Append(" Type = " + ((Flags & 0x01)>0?"COMMAND":"DATA")); s.Append((Flags & 0x02)>0?" Last Fragment\r\n":" Continues...\r\n"); send = false; byte[] thisData = new byte[PDVLen-2]; Array.Copy(p,Position,thisData,0,PDVLen-2); ByteData[direction].Add(thisData); //Add only Dataset data if((Flags & 0x01)== 0) { DatasetData.Add(thisData); } if((Position + (PDVLen - 2)) == FinalPosition) { if((Flags & 0x01)== 0) { if(commandType != "") { if(isCmdDataPDU) pduDetail.CmdType = commandType + "[Command,Data]"; else pduDetail.CmdType = commandType + "[Data]"; } cmdPdusList.Add(pduDetail); } if((Flags & 0x02)>0) // Last fragment { if((Flags & 0x01)>0) { s.Append(DICOMCommandDump(ByteData[direction])); if(commandType != "") pduDetail.CmdType = commandType + "[Command]"; pduList.Add(pduDetail); } else { foreach(PDU_DETAIL pdu in cmdPdusList) { pduDetail.CmdPdusList.Add(pdu); } pduDetail.CmdType = ((PDU_DETAIL)cmdPdusList[0]).CmdType; pduDetail.TransferSyntaxDataset = TransferSyntax[PCID]; foreach(byte[] data in DatasetData) { pduDetail.ByteDataDump.Add(data); } pduList.Add(pduDetail); cmdPdusList.Clear(); isLastDatasetFragmentRecd = true; s.Append(DICOMDump(ByteData[direction],TransferSyntax[PCID])); } ByteData[direction].Clear(); DatasetData.Clear(); send = true; } } else { //PDU contains both Command & Data PDV isCmdDataPDU = true; if((Flags & 0x01)>0) { s.Append(DICOMCommandDump(ByteData[direction])); } else { s.Append(DICOMDump(ByteData[direction],TransferSyntax[PCID])); } } Position += (PDVLen - 2); } break; } case 5: { //Check for incomplete byte stream if( isDataSetRecd && (!isLastDatasetFragmentRecd)) { HandleIncompleteByteStream(); } s.Append("Association Release Request\r\n"); break; } case 6: { //Check for incomplete byte stream if(isDataSetRecd && (!isLastDatasetFragmentRecd)) { HandleIncompleteByteStream(); } s.Append("Association Release Acceptance\r\n"); break; } case 7: { s.Append("Association Abort\r\n"); break; } default: s.Append("Unknown PDU Type\r\n"); break; } Out(s.ToString(),send); LastPDU = PDUType; }