public int ExtractData(NetworkTcpSession tcpSession, NetworkHost sourceHost, NetworkHost destinationHost, IEnumerable <Packets.AbstractPacket> packetList) { Packets.TcpPacket tcpPacket = null; Packets.FtpPacket ftpPacket = null; foreach (Packets.AbstractPacket p in packetList) { if (p.GetType() == typeof(Packets.TcpPacket)) { tcpPacket = (Packets.TcpPacket)p; } else if (p.GetType() == typeof(Packets.FtpPacket)) { ftpPacket = (Packets.FtpPacket)p; } } FtpSession ftpSession = null;//we can only have one FtpSession per packet... bool returnValue = false; if (tcpSession.SynPacketReceived && tcpSession.SynAckPacketReceived) { //start by checking if this is an incoming file transfer through FTP if (!tcpSession.SessionEstablished) { //we now have an upcoming session //see if it matches the pending FTP data sessions if (this.pendingFileTransferList.ContainsKey(PendingFileTransfer.GetKey(tcpSession.ClientHost, tcpSession.ClientTcpPort, tcpSession.ServerHost, tcpSession.ServerTcpPort))) { PendingFileTransfer pending = this.pendingFileTransferList[PendingFileTransfer.GetKey(tcpSession.ClientHost, tcpSession.ClientTcpPort, tcpSession.ServerHost, tcpSession.ServerTcpPort)]; pending.FileTransferSessionEstablished = true; ftpSession = pending.FtpControlSession; returnValue = true;//we managed to get some data out of this! } //see if the client port was unknown else if (this.pendingFileTransferList.ContainsKey(PendingFileTransfer.GetKey(tcpSession.ClientHost, null, tcpSession.ServerHost, tcpSession.ServerTcpPort))) { PendingFileTransfer pending = this.pendingFileTransferList[PendingFileTransfer.GetKey(tcpSession.ClientHost, null, tcpSession.ServerHost, tcpSession.ServerTcpPort)]; this.pendingFileTransferList.Remove(pending.GetKey()); pending.DataSessionClientPort = tcpSession.ClientTcpPort;//the Key will now be changed! pending.FileTransferSessionEstablished = true; this.pendingFileTransferList.Add(pending.GetKey(), pending); ftpSession = pending.FtpControlSession; returnValue = true; } }//end check for new FTP DATA sessions else if (tcpPacket != null && tcpPacket.FlagBits.Fin) { //check if there is an FTP data session being closed if (this.MainPacketHandler.FileStreamAssemblerList.ContainsAssembler(sourceHost, tcpPacket.SourcePort, destinationHost, tcpPacket.DestinationPort, true, true, PacketParser.FileTransfer.FileStreamTypes.FTP)) { PacketParser.FileTransfer.FileStreamAssembler assembler = this.MainPacketHandler.FileStreamAssemblerList.GetAssembler(sourceHost, tcpPacket.SourcePort, destinationHost, tcpPacket.DestinationPort, true); if (assembler.FileContentLength == -1 && assembler.FileSegmentRemainingBytes == -1) { //TODO: see if all data has been received or if the FIN arrived before the final data packet assembler.FinishAssembling(); } } } } if (ftpPacket != null && tcpPacket != null) { returnValue = true; if (ftpSessionList.ContainsKey(tcpSession)) { ftpSession = ftpSessionList[tcpSession]; } else { ftpSession = new FtpSession(tcpSession.ClientHost, tcpSession.ServerHost); this.ftpSessionList.Add(tcpSession, ftpSession); } if (ftpPacket.ClientToServer) { if (ftpPacket.RequestCommand != null) { if (ftpPacket.RequestArgument != null) { System.Collections.Specialized.NameValueCollection tmpCol = new System.Collections.Specialized.NameValueCollection(); tmpCol.Add(ftpPacket.RequestCommand, ftpPacket.RequestArgument); base.MainPacketHandler.OnParametersDetected(new Events.ParametersEventArgs(ftpPacket.ParentFrame.FrameNumber, sourceHost, destinationHost, "TCP " + tcpPacket.SourcePort, "TCP " + tcpPacket.DestinationPort, tmpCol, ftpPacket.ParentFrame.Timestamp, "FTP Request")); } if (ftpPacket.RequestCommand.ToUpper() == "USER")//username { ftpSession.Username = ftpPacket.RequestArgument; } else if (ftpPacket.RequestCommand.ToUpper() == "PASS")//password { ftpSession.Password = ftpPacket.RequestArgument; if (ftpSession.Username != null && ftpSession.Password != null) { base.MainPacketHandler.AddCredential(new NetworkCredential(tcpSession.ClientHost, tcpSession.ServerHost, ftpPacket.PacketTypeDescription, ftpSession.Username, ftpSession.Password, ftpPacket.ParentFrame.Timestamp)); } } else if (ftpPacket.RequestCommand.ToUpper() == "PORT") { ushort clientListeningOnPort; if (TryGetPort(ftpPacket.RequestArgument, out clientListeningOnPort)) { //ftpSession.ActiveMode=true; //ftpSession.ClientDataListenerTcpPort=this.GetPort(ftpPacket.RequestArgument); //ftpSession.PendingFileTransfer=new PendingFileTransfer(ftpSession.ServerHost, (ushort)20, ftpSession.ClientHost, clientListeningOnPort, false, ftpSession); ftpSession.PendingFileTransfer = new PendingFileTransfer(ftpSession.ServerHost, null, ftpSession.ClientHost, clientListeningOnPort, false, ftpSession); if (this.pendingFileTransferList.ContainsKey(ftpSession.PendingFileTransfer.GetKey())) { this.pendingFileTransferList.Remove(ftpSession.PendingFileTransfer.GetKey()); } this.pendingFileTransferList.Add(ftpSession.PendingFileTransfer.GetKey(), ftpSession.PendingFileTransfer); } } else if (ftpPacket.RequestCommand.ToUpper() == "STOR")//file upload (client -> server) //set filename and file direction { if (ftpSession.PendingFileTransfer != null) { ftpSession.PendingFileTransfer.Filename = ftpPacket.RequestArgument; ftpSession.PendingFileTransfer.FileDirectionIsDataSessionServerToDataSessionClient = !ftpSession.PendingFileTransfer.DataSessionIsPassive; ftpSession.PendingFileTransfer.Details = ftpPacket.RequestCommand + " " + ftpPacket.RequestArgument; } else { //ftpPacket.ParentFrame.Errors.Add(new Frame.Error(ftpPacket.ParentFrame, ftpPacket.PacketStartIndex, ftpPacket.PacketEndIndex, "STOR command without a pending ftp data session")); this.MainPacketHandler.OnAnomalyDetected("STOR command without a pending ftp data session. Frame: " + ftpPacket.ParentFrame.ToString(), ftpPacket.ParentFrame.Timestamp); //System.Diagnostics.Debugger.Break();//this should not occur! } } else if (ftpPacket.RequestCommand.ToUpper() == "RETR")//file download (server -> client) { if (ftpSession.PendingFileTransfer != null) { ftpSession.PendingFileTransfer.Filename = ftpPacket.RequestArgument; ftpSession.PendingFileTransfer.FileDirectionIsDataSessionServerToDataSessionClient = ftpSession.PendingFileTransfer.DataSessionIsPassive; ftpSession.PendingFileTransfer.Details = ftpPacket.RequestCommand + " " + ftpPacket.RequestArgument; } else { //System.Diagnostics.Debugger.Break();//this should not iccur //ftpPacket.ParentFrame.Errors.Add(new Frame.Error(ftpPacket.ParentFrame, ftpPacket.PacketStartIndex, ftpPacket.PacketEndIndex, "RETR command without a pending ftp data session")); this.MainPacketHandler.OnAnomalyDetected("RETR command without a pending ftp data session. Frame: " + ftpPacket.ParentFrame.ToString(), ftpPacket.ParentFrame.Timestamp); } } else if (ftpPacket.RequestCommand.ToUpper() == "SIZE") { ftpSession.PendingSizeRequestFileName = ftpPacket.RequestArgument; } } } else //server to client packet { if (ftpPacket.ResponseCode != 0 && ftpPacket.ResponseArgument != null) { System.Collections.Specialized.NameValueCollection tmpCol = new System.Collections.Specialized.NameValueCollection(); tmpCol.Add(ftpPacket.ResponseCode.ToString(), ftpPacket.ResponseArgument); MainPacketHandler.OnParametersDetected(new Events.ParametersEventArgs(ftpPacket.ParentFrame.FrameNumber, sourceHost, destinationHost, "TCP " + tcpPacket.SourcePort, "TCP " + tcpPacket.DestinationPort, tmpCol, ftpPacket.ParentFrame.Timestamp, "FTP Response")); //look for an FTP banner if (ftpPacket.ResponseCode == 220 && ftpPacket.ResponseArgument.ToLower().Contains("ftp")) { sourceHost.AddFtpServerBanner(ftpPacket.ResponseArgument, tcpPacket.SourcePort); } } if (ftpPacket.ResponseCode == 213 && ftpSession.PendingSizeRequestFileName != null)//File size response { int fileSize; if (Int32.TryParse(ftpPacket.ResponseArgument, out fileSize)) { ftpSession.FileSizes[ftpSession.PendingSizeRequestFileName] = fileSize; } //ftpSession.FileSizes.Add(ftpSession.PendingSizeRequestFileName, fileSize); ftpSession.PendingSizeRequestFileName = null; } if (ftpPacket.ResponseCode == 226)//File receive OK //close file stream assembler? { } else if (ftpPacket.ResponseCode == 227)//Entering Passive Mode //From: http://cr.yp.to/ftp/retr.html //Many servers put different strings before h1 and after p2. //I recommend that clients use the following strategy to parse the //response line: look for the first digit after the initial space; //look for the fourth comma after that digit; read two (possibly negative) //integers, separated by a comma; the TCP port number is p1*256+p2, //where p1 is the first integer modulo 256 and p2 is the second integer //modulo 256. //it is probably simpler to do this with RegEx, but this is simple enough so I wont bother with RegEx for now... { char[] digits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; string ipAndPort = ftpPacket.ResponseArgument.Substring(ftpPacket.ResponseArgument.IndexOfAny(digits)); //string ipAndPort=ftpPacket.ResponseArgument.Substring(ftpPacket.ResponseArgument.IndexOf('(')+1); ipAndPort = ipAndPort.Substring(0, ipAndPort.LastIndexOfAny(digits) + 1); //ipAndPort=ipAndPort.Substring(0, ipAndPort.IndexOf(')')); ushort serverListeningOnPort; if (this.TryGetPort(ipAndPort, out serverListeningOnPort)) { ftpSession.PendingFileTransfer = new PendingFileTransfer(ftpSession.ClientHost, null, ftpSession.ServerHost, serverListeningOnPort, true, ftpSession); if (this.pendingFileTransferList.ContainsKey(ftpSession.PendingFileTransfer.GetKey())) { this.pendingFileTransferList.Remove(ftpSession.PendingFileTransfer.GetKey()); } this.pendingFileTransferList.Add(ftpSession.PendingFileTransfer.GetKey(), ftpSession.PendingFileTransfer); } } if (ftpPacket.ResponseCode == 230)//Login successful //ftpSession.=ftpPacket.RequestArgument; { if (ftpSession.Username != null && ftpSession.Password != null) { base.MainPacketHandler.AddCredential(new NetworkCredential(tcpSession.ClientHost, tcpSession.ServerHost, ftpPacket.PacketTypeDescription, ftpSession.Username, ftpSession.Password, true, ftpPacket.ParentFrame.Timestamp)); } } }//end server to client } if (ftpSession != null && ftpSession.PendingFileTransfer != null) { //I guess returnValue is already set to true by now, but I'll do it again just to be sure... returnValue = true; PendingFileTransfer pending = ftpSession.PendingFileTransfer; //see if the pending file transfer could be transformed into a real file stream assembler if (pending.FileTransferSessionEstablished && pending.FileDirectionIsDataSessionServerToDataSessionClient != null && pending.DataSessionClientPort != null) { //Server->Client ? FileTransfer.FileStreamAssembler assembler = null; if (pending.FileDirectionIsDataSessionServerToDataSessionClient.Value) { assembler = new FileTransfer.FileStreamAssembler(MainPacketHandler.FileStreamAssemblerList, pending.DataSessionServer, pending.DataSessionServerPort, pending.DataSessionClient, pending.DataSessionClientPort.Value, true, FileTransfer.FileStreamTypes.FTP, pending.Filename, "/", pending.Details, tcpPacket.ParentFrame.FrameNumber, tcpPacket.ParentFrame.Timestamp); } else { assembler = new FileTransfer.FileStreamAssembler(MainPacketHandler.FileStreamAssemblerList, pending.DataSessionClient, pending.DataSessionClientPort.Value, pending.DataSessionServer, pending.DataSessionServerPort, true, FileTransfer.FileStreamTypes.FTP, pending.Filename, "/", pending.Details, tcpPacket.ParentFrame.FrameNumber, tcpPacket.ParentFrame.Timestamp); } string fileCompletePath = ""; if (assembler.Filename != null && assembler.FileLocation != null) { fileCompletePath = assembler.FileLocation + "/" + assembler.Filename; } if (ftpSession.FileSizes.ContainsKey(fileCompletePath)) { assembler.FileContentLength = ftpSession.FileSizes[fileCompletePath]; assembler.FileSegmentRemainingBytes = ftpSession.FileSizes[fileCompletePath]; } else { //-1 is set instead of null if Content-Length is not defined assembler.FileContentLength = -1; assembler.FileSegmentRemainingBytes = -1; } if (assembler.TryActivate()) { MainPacketHandler.FileStreamAssemblerList.Add(assembler); } //assembler.Activate(); //the file transfer is no longer pending since the assembler is started! pendingFileTransferList.Remove(pending.GetKey()); ftpSession.PendingFileTransfer = null; } } if (returnValue) { return(tcpPacket.PayloadDataLength); } else { return(0); } }