public VoipCall(List <PacketParser.AudioStream> audioStreamList, PacketParser.FileTransfer.FileStreamAssembler wavAssembler, string callId, string from, string to, Func <DateTime, string> toCustomTimeZoneStringFunction) : base() { this.toCustomTimeZoneStringFunction = toCustomTimeZoneStringFunction; this.reconstructedFile = null; //audioStream.Assembler.FileReconstructed += this.Assembler_FileReconstructed; wavAssembler.FileReconstructed += this.OnWavFileReconstructed; this.Start = DateTime.MaxValue; this.End = DateTime.MinValue; foreach (PacketParser.AudioStream stream in audioStreamList) { if (stream.StartTime < this.Start) { this.Start = stream.StartTime; } if (stream.EndTime > this.End) { this.End = stream.EndTime; } } this.CallId = callId; this.From = from; this.To = to; this.SourceHost = audioStreamList[0].SourceHost; this.DestinationkHost = audioStreamList[0].DestinationHost; this.Encoding = audioStreamList[0].Format; this.EncodingString = this.Encoding.ToString(); if (this.EncodingString.StartsWith(FORMAT_PREFIX)) { this.EncodingString = this.EncodingString.Substring(FORMAT_PREFIX.Length); } }
//public int ExtractData(NetworkTcpSession tcpSession, NetworkHost sourceHost, NetworkHost destinationHost, IEnumerable<Packets.AbstractPacket> packetList) { public int ExtractData(NetworkTcpSession tcpSession, bool transferIsClientToServer, IEnumerable <PacketParser.Packets.AbstractPacket> packetList) { /* * NetworkHost sourceHost, destinationHost; * if (transferIsClientToServer) { * sourceHost = tcpSession.Flow.FiveTuple.ClientHost; * destinationHost = tcpSession.Flow.FiveTuple.ServerHost; * } * else { * sourceHost = tcpSession.Flow.FiveTuple.ServerHost; * destinationHost = tcpSession.Flow.FiveTuple.ClientHost; * }*/ 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; int parsedBytes = 0; 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! parsedBytes = tcpPacket.PayloadDataLength; } //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; parsedBytes = tcpPacket.PayloadDataLength; } }//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(tcpSession.Flow.FiveTuple, transferIsClientToServer, true, PacketParser.FileTransfer.FileStreamTypes.FTP)) { PacketParser.FileTransfer.FileStreamAssembler assembler = this.MainPacketHandler.FileStreamAssemblerList.GetAssembler(tcpSession.Flow.FiveTuple, transferIsClientToServer); 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; parsedBytes = ftpPacket.PacketLength; if (ftpSessionList.ContainsKey(tcpSession)) { ftpSession = ftpSessionList[tcpSession]; } else { ftpSession = new FtpSession(tcpSession.ClientHost, tcpSession.ServerHost); this.ftpSessionList.Add(tcpSession, ftpSession); } /* * NetworkHost sourceHost, destinationHost; * if (transferIsClientToServer) { * sourceHost = tcpSession.Flow.FiveTuple.ClientHost; * destinationHost = tcpSession.Flow.FiveTuple.ServerHost; * } * else { * sourceHost = tcpSession.Flow.FiveTuple.ServerHost; * destinationHost = tcpSession.Flow.FiveTuple.ClientHost; * } */ 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, tcpSession.Flow.FiveTuple, transferIsClientToServer, 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, tcpSession.Flow.FiveTuple, transferIsClientToServer, tmpCol, ftpPacket.ParentFrame.Timestamp, "FTP Response")); //look for an FTP banner if (ftpPacket.ResponseCode == 220 && ftpPacket.ResponseArgument.ToLower().Contains("ftp")) { tcpSession.Flow.FiveTuple.ServerHost.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 - Response to client "PASV" command //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); } } else 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)); } } else if (ftpPacket.ResponseCode == 234) //server response to an 'AUTH TLS' command rfc4217 and rfc2228 /** * If the server is willing to accept the named security mechanism, * and does not require any security data, it must respond with reply * code 234. **/ //Unfortunately we haven't stored the request, so we can't know if the client was asking for TLS or some other security measure { if (ftpPacket.ResponseArgument.Contains("TLS") || ftpPacket.ResponseArgument.Contains("SSL")) { tcpSession.ProtocolFinder.SetConfirmedApplicationLayerProtocol(ApplicationLayerProtocol.Ssl, false); } } }//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... if (parsedBytes == 0) { parsedBytes = tcpPacket.PayloadDataLength; } //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.FileAssmeblyRootLocation fileAssemblyLocation; if ((ftpSession.ServerHost == pending.DataSessionServer) == pending.FileDirectionIsDataSessionServerToDataSessionClient.Value) { fileAssemblyLocation = FileTransfer.FileStreamAssembler.FileAssmeblyRootLocation.source; } else { fileAssemblyLocation = FileTransfer.FileStreamAssembler.FileAssmeblyRootLocation.destination; } FileTransfer.FileStreamAssembler assembler = new FileTransfer.FileStreamAssembler(MainPacketHandler.FileStreamAssemblerList, pending.GetFiveTuple(), !pending.FileDirectionIsDataSessionServerToDataSessionClient.Value, FileTransfer.FileStreamTypes.FTP, pending.Filename, "/", pending.Details, tcpPacket.ParentFrame.FrameNumber, tcpPacket.ParentFrame.Timestamp, fileAssemblyLocation); 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; } } return(parsedBytes); }