| // Copyright 2015 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| /** |
| * @fileoverview Handles file actions and triggers pcap processing. |
| * Pcap files are converted into PSML and PDML using a ported version of |
| * tshark which runs under native client. After processing, the information is |
| * displayed in the document. |
| */ |
| |
| 'use strict'; |
| |
| /** |
| * Namespace for the Packet Trace Analyzer app. |
| */ |
| var pcap = pcap || {}; |
| |
| /** |
| * The container for the packet's summary information. |
| */ |
| pcap.psmlDocument = new pcap.PsmlDocument(); |
| |
| /** |
| * The container for the packet's detailed information. |
| */ |
| pcap.pdmlDocument = new pcap.PdmlDocument(); |
| |
| /** |
| * Executes the tshark native executable with the specifed arguments and calls |
| * back when finished. |
| * |
| * For example, executing tshark with the following arguments: |
| * -r /tmp/input.pcap -T psml -o /tmp/output.psml |
| * will tell tshark to open input.pcap from the temporary file system, |
| * generate the packet summary, and write the output to output.psml in the |
| * temporary file system. |
| * |
| * @param {array<string>} args The flags and arguments for the executable. |
| * @param {function()} callback Called when finished executing. |
| */ |
| pcap.executeTshark = function(args, callback) { |
| var listeners = document.getElementById('listeners'); |
| var div = document.createElement('div'); |
| var listener = document.createElement('div'); |
| |
| var embed = document.createElement('embed'); |
| embed.setAttribute('width', 0); |
| embed.setAttribute('height', 0); |
| embed.setAttribute('src', './tshark.nmf'); |
| embed.setAttribute('type', 'application/x-nacl'); |
| embed.setAttribute('PS_VERBOSITY', '0'); |
| embed.setAttribute('PS_EXIT_MESSAGE', 'exit'); |
| embed.setAttribute('PS_TTY_PREFIX', 'a'); |
| embed.setAttribute('PS_STDOUT', '/dev/tty'); |
| embed.setAttribute('PS_STDERR', '/dev/console1'); |
| |
| var argCount = args.length; |
| for (var i = 0; i < argCount; i++) { |
| var key = 'arg' + (i + 1); |
| var value = args[i]; |
| embed.setAttribute(key, value); |
| } |
| |
| embed.addEventListener('crash', console.error); |
| embed.addEventListener('error', console.error); |
| |
| listener.appendChild(embed); |
| listener.addEventListener('message', function(message) { |
| if (message.data.search('exit') >= 0) { /* true when module is finished */ |
| callback(); |
| } |
| }, true); |
| |
| div.appendChild(listener); |
| listeners.appendChild(div); |
| }; |
| |
| /** |
| * Handles setting up the listeners for the application. |
| */ |
| pcap.onDomContentLoaded = function() { |
| var pcapFileInput = document.getElementById('pcap_file_input'); |
| if (!pcapFileInput) { |
| console.error('document.addEventListener: missing pcap file input.'); |
| return; |
| } |
| pcapFileInput.addEventListener('change', pcap.onPcapFileInputChanged); |
| }; |
| |
| /** |
| * Called when the file input is changed. If a valid file is found, it is |
| * copied over to the sandboxed temporary file system, and then the PSML and |
| * PDML are loaded into the document. |
| */ |
| pcap.onPcapFileInputChanged = function() { |
| var file = pcap.getFileFromFileInput('pcap_file_input'); |
| if (file) { |
| pcap.copyFileToTemporaryFileSystem(file, function() { |
| pcap.loadPsmlAndPdml(file.name); |
| }); |
| } |
| }; |
| |
| /** |
| * Function to get the file from the file input. |
| * |
| * @param {string} fileInputId The ID of the file input. |
| * @return {fileObject} The file or null if missing. |
| */ |
| pcap.getFileFromFileInput = function(fileInputId) { |
| pcap.clearState(); |
| |
| var pcapFileInput = document.getElementById(fileInputId); |
| if (!pcapFileInput) { |
| console.error('process_pcap: missing pcap file input.'); |
| return null; |
| } |
| |
| var files = pcapFileInput.files; |
| |
| if (!files[0]) { |
| console.log('process_pcap: file selection cancelled.'); |
| return null; |
| } |
| else if (files[0].type !== 'application/vnd.tcpdump.pcap') { |
| pcap.displayError('Invalid file type.'); |
| return null; |
| } |
| |
| console.log('process_pcap: got the file: ' + files[0].name); |
| return files[0]; |
| }; |
| |
| /** |
| * Function to copy a file to the sandboxed temporary file system. |
| * |
| * @param {fileObject} file The file to copy over. |
| * @param {function()} callback Called when finished copying. |
| */ |
| pcap.copyFileToTemporaryFileSystem = function(file, callback) { |
| window.webkitRequestFileSystem(window.TEMPORARY, 1024 * 1024, function(fs) { |
| fs.root.getFile(file.name, {create: true}, function(fileEntry) { |
| fileEntry.createWriter(function(fileWriter) { |
| fileWriter.write(file); |
| fileWriter.onwriteend = callback; |
| }, console.error); |
| }, console.error); |
| }, console.error); |
| }; |
| |
| /** |
| * Function to load the PSML and PDML from the pcap file using tshark and |
| * display the information in the document. |
| * |
| * @param {string} filename The name of the file to read. |
| */ |
| pcap.loadPsmlAndPdml = function(filename) { |
| document.getElementById('psml_display').innerText = 'Loading PSML...'; |
| document.getElementById('pdml_display').innerText = 'Loading PDML...'; |
| pcap.loadTsharkTextOutput('psml', filename, 'psml.xml', function(psml) { |
| if (psml && pcap.psmlDocument.read(psml)) { |
| pcap.psmlDocument.display(); |
| pcap.loadTsharkTextOutput('pdml', filename, 'pdml.xml', function(pdml) { |
| if (pdml && pcap.pdmlDocument.read(pdml)) { |
| pcap.pdmlDocument.display(); |
| } else { |
| pcap.displayError('Failed to load PDML.'); |
| } |
| }); |
| } else { |
| pcap.displayError('Failed to load PSML.'); |
| } |
| }); |
| }; |
| |
| /** |
| * Executes tshark and calls back with the resulting xml. |
| * |
| * @param {string} type The format of the text output (psml, pdml). |
| * @param {string} ifilename The input file name to read from. |
| * @param {string} ofilename The ouptut file name to write to. |
| * @param {function(Document)} callback Called with the resulting text output. |
| */ |
| pcap.loadTsharkTextOutput = function(type, ifilename, ofilename, callback) { |
| pcap.executeTshark([ |
| '-r', |
| '/tmp/' + ifilename, |
| '-T', |
| type, |
| '-o', |
| '/tmp/' + ofilename |
| ], function() { |
| pcap.readXmlFromFile(ofilename, callback); |
| }); |
| }; |
| |
| /** |
| * Opens and reads the specified file. If the file is a valid xml file, it |
| * calls back with the resulting XML. |
| * |
| * @param {string} filename The name of the file to read. |
| * @param {function(xml)} callback Called with the resulting xml. |
| */ |
| pcap.readXmlFromFile = function(filename, callback) { |
| window.webkitRequestFileSystem(window.TEMPORARY, 1024 * 1024, function(fs) { |
| fs.root.getFile(filename, {create: false}, function(fileEntry) { |
| fileEntry.file(function(file) { |
| var reader = new FileReader(); |
| reader.onloadend = function(e) { |
| var parser = new DOMParser(); |
| var xml = parser.parseFromString(reader.result, 'application/xml'); |
| callback(xml); |
| }; |
| reader.readAsText(file); |
| }, console.error); |
| }, console.error); |
| }, console.error); |
| }; |
| |
| /** |
| * Displays an error message to the user. |
| * |
| * @param {string} message The error message to display. |
| */ |
| pcap.displayError = function(message) { |
| var errorElement = document.getElementById('error'); |
| errorElement.innerText = message; |
| }; |
| |
| /** |
| * Clears the state of the application. |
| */ |
| pcap.clearState = function() { |
| var psmlDisplayEl = document.getElementById('psml_display'); |
| var pdmlDisplayEl = document.getElementById('pdml_display'); |
| var errorEl = document.getElementById('error'); |
| |
| if (!psmlDisplayEl || !pdmlDisplayEl || !errorEl) { |
| console.error('clearState: missing elements'); |
| return; |
| } |
| |
| psmlDisplayEl.innerText = ''; |
| pdmlDisplayEl.innerText = ''; |
| errorEl.innerText = ''; |
| }; |
| |
| /** |
| * The main entry point to the application. |
| */ |
| document.addEventListener('DOMContentLoaded', pcap.onDomContentLoaded); |
| |