├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── binding.gyp ├── examples ├── .gitignore ├── package.json └── print.js ├── index.js ├── lib ├── httpTracker.js ├── nodeShark.js └── tcpTracker.js ├── mnm.js ├── package.json ├── src ├── cfile.cpp ├── dissector.cpp ├── dissector.h ├── dissectorNode.cpp ├── dissectorNode.h ├── lazyDataSource.cpp ├── lazyDataSource.h ├── lazyDissectorNode.cpp ├── lazyDissectorNode.h ├── nodeshark.cpp ├── nodeshark.h ├── utils.cpp └── utils.h ├── test_data ├── ethereal.com.pcap ├── http.pcap └── http_gzip.pcap └── tests ├── dissectorTest.js ├── httpTrackerTest.js └── tcpTrackerTest.js /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea 2 | /build/* 3 | node_modules 4 | *.node 5 | *.sh 6 | *.swp 7 | .lock* 8 | npm-debug.log 9 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | build 2 | node_modules 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Near Infinity Corporation 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nodeshark 2 | 3 | Wrapper around libwireshark providing network packet dissection for [node.js](http://nodejs.org/). 4 | 5 | ## Installation 6 | 7 | $ npm install nodeshark 8 | 9 | ### Build linux 10 | 11 | ```bash 12 | $ git clone https://code.wireshark.org/review/wireshark 13 | $ cd wireshark 14 | $ ./autogen.sh 15 | $ ./configure 16 | $ make 17 | $ sudo make install 18 | $ export WIRESHARK_INCLUDE_DIR=[wireshark source directory] 19 | $ node-waf configure build 20 | ``` 21 | 22 | ### Build OSX 23 | 24 | ```bash 25 | $ git clone https://code.wireshark.org/review/wireshark 26 | $ cd wireshark 27 | $ ./macosx-setup.sh 28 | $ export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:/usr/X11/lib/pkgconfig 29 | $ ./autogen.sh 30 | $ ./configure 31 | $ make -j 3 32 | $ sudo make install 33 | 34 | $ export WIRESHARK_INCLUDE_DIR=[wireshark source directory] 35 | $ node-waf configure build 36 | ``` 37 | 38 | ## Usage 39 | 40 | ```javascript 41 | var nodeshark = require("nodeshark"); 42 | 43 | var dissector = new nodeshark.Dissector(nodeshark.LINK_LAYER_TYPE_ETHERNET); 44 | 45 | var rawPacket = { 46 | header: { 47 | timestampSeconds: 10, 48 | timestampMicroseconds: 20, 49 | capturedLength: buffer.length, 50 | originalLength: buffer.length 51 | }, 52 | data: new Buffer([ 53 | 0x58, 0x6d, 0x8f, 0x67, 0x8a, 0x4d, 0x00, 0x1b, 0x21, 0xcf, 0xa1, 0x00, 0x08, 0x00, 0x45, 0x00, 54 | 0x00, 0x3b, 0xd1, 0xb0, 0x40, 0x00, 0x40, 0x11, 0xc5, 0xde, 0x0a, 0x14, 0x08, 0x65, 0xc0, 0xa8, 55 | 0xd0, 0x01, 0xc5, 0x32, 0x00, 0x35, 0x00, 0x27, 0xa3, 0x5b, 0x65, 0x89, 0x01, 0x00, 0x00, 0x01, 56 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x6d, 0x61, 0x69, 0x6c, 0x04, 0x6c, 0x69, 0x76, 0x65, 57 | 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01 58 | ]); 59 | }; 60 | var packet = dissector.dissect(rawPacket); 61 | 62 | // OR 63 | 64 | var buffer = new Buffer([ 65 | 0x58, 0x6d, 0x8f, 0x67, 0x8a, 0x4d, 0x00, 0x1b, 0x21, 0xcf, 0xa1, 0x00, 0x08, 0x00, 0x45, 0x00, 66 | 0x00, 0x3b, 0xd1, 0xb0, 0x40, 0x00, 0x40, 0x11, 0xc5, 0xde, 0x0a, 0x14, 0x08, 0x65, 0xc0, 0xa8, 67 | 0xd0, 0x01, 0xc5, 0x32, 0x00, 0x35, 0x00, 0x27, 0xa3, 0x5b, 0x65, 0x89, 0x01, 0x00, 0x00, 0x01, 68 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x6d, 0x61, 0x69, 0x6c, 0x04, 0x6c, 0x69, 0x76, 0x65, 69 | 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01 70 | ]); 71 | var packet = dissector.dissect(buffer); 72 | ``` 73 | 74 | You can also use it it conjunction with [pcap-parser](https://github.com/nearinfinity/node-pcap-parser). 75 | 76 | ```javascript 77 | var pcapp = require('pcap-parser'); 78 | 79 | var parser = new pcapp.Parser('/path/to/file.pcap'); 80 | var dissector; 81 | parser.on('globalHeader', function(globalHeader) { 82 | dissector = new nodeshark.Dissector(globalHeader.linkLayerType); 83 | }); 84 | parser.on('packet', function(rawPacket) { 85 | var packet = dissector.dissect(rawPacket); 86 | }); 87 | parser.parse(); 88 | ``` 89 | 90 | ## License 91 | 92 | (The MIT License) 93 | 94 | Copyright (c) 2012 Near Infinity Corporation 95 | 96 | Permission is hereby granted, free of charge, to any person obtaining 97 | a copy of this software and associated documentation files (the 98 | "Software"), to deal in the Software without restriction, including 99 | without limitation the rights to use, copy, modify, merge, publish, 100 | distribute, sublicense, and/or sell copies of the Software, and to 101 | permit persons to whom the Software is furnished to do so, subject to 102 | the following conditions: 103 | 104 | The above copyright notice and this permission notice shall be 105 | included in all copies or substantial portions of the Software. 106 | 107 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 108 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 109 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 110 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 111 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 112 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 113 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 114 | -------------------------------------------------------------------------------- /binding.gyp: -------------------------------------------------------------------------------- 1 | # 2 | # 3 | 4 | { 5 | 'conditions': [ 6 | ['OS=="linux"', { 7 | # on Ubuntu 10.04 LTS and 12.04.2 LTS: install package wireshark-dev_1.x.y_amd64 8 | # for header files and 9 | # #export WIRESHARK_LIB=/usr/lib/wireshark/ 10 | # export WIRESHARK_LIB=/usr/local/lib/ 11 | 'variables': { 12 | #'wireshark_include_dir': '/home/rs/Gremlins/wireshark/wireshark-1.8.5/', 13 | 'wireshark_include_dir': '/home/rs/Gremlins/wireshark/wireshark-1.8.5-JDSU/', 14 | #'wireshark_include_dir': '/home/rs/Gremlins/wireshark/wireshark-1.9.x.backupJDSU/', 15 | #'wireshark_include_dir': '/usr/include/wireshark/', 16 | 'glib_include_dir': '/usr/include/glib-2.0/', 17 | #'glib_config_include_dir': '/usr/lib/glib-2.0/include/', 18 | 'glib_config_include_dir': '/usr/lib/x86_64-linux-gnu/glib-2.0/include', 19 | # headers installed by package wireshark-dev_1.x.y_amd64 20 | #'wireshark_lib': '/usr/local/lib/', 21 | 'wireshark_lib': '/usr/lib/wireshark/', 22 | }, 23 | }], 24 | ['OS=="mac"', { 25 | 'variables': { 26 | 'wireshark_include_dir': '/Users/sommerha/Gremlins/wireshark/wireshark-1.8', 27 | 'glib_include_dir': '/usr/include/glib-2.0/', 28 | 'glib_config_include_dir': '/opt/local/include/glib-2.0', 29 | 'wireshark_lib': '/usr/local/lib/', 30 | }, 31 | }], 32 | ['OS=="openbsd"', { 33 | 'variables': { 34 | # see pkg_info -L tshark19 35 | 'wireshark_include_dir': '/var/pobj/wireshark-1.9.0-SVN-46199/wireshark-1.9.0-SVN-46199', 36 | 'glib_include_dir': '/usr/local/include/glib-2.0/', # see pkg_info -L glib2 37 | 'glib_config_include_dir': '/usr/local/lib/glib-2.0/include/', 38 | 'wireshark_lib': '/usr/local/lib/', # see pkg_info -L tshark19 39 | }, 40 | }], 41 | ['OS=="smartos"', { 42 | 'variables': { 43 | 'wireshark_include_dir': '', 44 | 'glib_include_dir': '', 45 | 'glib_config_include_dir': '', 46 | 'wireshark_lib': '', 47 | }, 48 | }], 49 | ], 50 | 'targets': [ 51 | { 52 | 'target_name': 'nodeshark', 53 | 'sources': [ 54 | 'src/cfile.cpp', 55 | 'src/dissector.cpp', 56 | 'src/dissectorNode.cpp', 57 | 'src/lazyDataSource.cpp', 58 | 'src/lazyDissectorNode.cpp', 59 | 'src/nodeshark.cpp', 60 | 'src/utils.cpp', 61 | ], 62 | 'defines': [ 63 | 'HAVE_CONFIG_H', 64 | ], 65 | 'include_dirs': [ 66 | '<(wireshark_include_dir)', 67 | '<(glib_include_dir)', 68 | '<(glib_config_include_dir)', 69 | ], 70 | 'link_settings': { 71 | # library_dirs is not working, use ldflags, see 72 | # https://code.google.com/p/gyp/issues/detail?id=130 73 | #'library_dirs': [ 74 | # '<(wireshark_lib)', 75 | #], 76 | 'ldflags': [ 77 | '-L<(wireshark_lib)', 78 | ], 79 | 'libraries': [ 80 | '-lwireshark', 81 | '-lwiretap', 82 | '-lwsutil', 83 | ], 84 | }, 85 | }, 86 | ], 87 | } 88 | -------------------------------------------------------------------------------- /examples/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /examples/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nodesharkExamples", 3 | "version": "0.0.1", 4 | "private": true, 5 | "dependencies": { 6 | "optimist": "~0.3.1", 7 | "pcap-parser": "~0.0.3" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /examples/print.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var optimist = require('optimist'); 4 | var nodeshark = require("../"); 5 | var pcapp = require("pcap-parser"); 6 | 7 | var argv = optimist 8 | .default({ verbose: false, infile: true }) 9 | .usage('Usage: $0 [options]') 10 | .alias('infile', 'i') 11 | .alias('field', 'f') 12 | .alias('verbose', 'v') 13 | .alias('h', 'help') 14 | .alias('h', '?') 15 | .describe('infile', 'The file to read input from. Leave blank for stdin.') 16 | .describe('field', 'The field to print (ie request.fullUri).') 17 | .describe('verbose', 'Verbose mode.') 18 | .argv 19 | 20 | var verbose = argv.verbose; 21 | 22 | if (argv.help) { 23 | optimist.showHelp(); 24 | process.exit(1); 25 | } 26 | 27 | if(!(argv.field instanceof Array)) { 28 | argv.field = [ argv.field ]; 29 | } 30 | 31 | var pcapparser; 32 | if (argv.infile === true) { 33 | if(verbose) console.error("Loading pcap file from stdin"); 34 | pcapparser = new pcapp.Parser(process.stdin); 35 | } else { 36 | if(verbose) console.error("Loading pcap file: " + argv.infile); 37 | pcapparser = new pcapp.Parser(argv.infile); 38 | } 39 | 40 | var dissector; 41 | var tcpTracker = new nodeshark.TcpTracker(); 42 | var httpTracker = new nodeshark.HttpTracker(tcpTracker); 43 | 44 | pcapparser.on('globalHeader', function(globalHeader) { 45 | dissector = new nodeshark.Dissector(globalHeader.linkLayerType); 46 | }); 47 | 48 | pcapparser.on('packet', function (rawPacket) { 49 | var packet = dissector.dissect(rawPacket); 50 | evalFields(packet); 51 | tcpTracker.track(packet); 52 | }); 53 | 54 | pcapparser.on('end', function() { 55 | dissector.close(); 56 | }); 57 | 58 | httpTracker.on('responseData', function (http, buffer) { 59 | //console.log(http); 60 | evalFields(http); 61 | for(var i=0; i 0) { 120 | var name = shortKey.slice(0, token); 121 | var value = shortKey.slice(token + 2); 122 | requestResponse.headers[name] = value; 123 | return; 124 | } 125 | } 126 | requestResponse.headers[self._headerKeyToDisplay(key)] = packet.http[key].value; 127 | }); 128 | }; 129 | 130 | 131 | HttpTracker.prototype._headerKeyToDisplay = function(key) { 132 | if (key == 'host') { 133 | return 'Host'; 134 | } 135 | if (key == 'user_agent') { 136 | return 'User-Agent'; 137 | } 138 | if (key == 'accept') { 139 | return 'Accept'; 140 | } 141 | if (key == 'accept_language') { 142 | return 'Accept-Language'; 143 | } 144 | if (key == 'accept_encoding') { 145 | return 'Accept-Encoding'; 146 | } 147 | if (key == 'connection') { 148 | return 'Connection'; 149 | } 150 | if (key == 'referer') { 151 | return 'Referer'; 152 | } 153 | if (key == 'date') { 154 | return 'Date'; 155 | } 156 | if (key == 'server') { 157 | return 'Server'; 158 | } 159 | if (key == 'last_modified') { 160 | return 'Last-Modified'; 161 | } 162 | if (key == 'content_length_header') { 163 | return 'Content-Length'; 164 | } 165 | if (key == 'content_type') { 166 | return 'Content-Type'; 167 | } 168 | if (key == 'cache_control') { 169 | return 'Cache-Control'; 170 | } 171 | if (key == 'set_cookie') { 172 | return 'Set-Cookie'; 173 | } 174 | if (key == 'cookie') { 175 | return 'Cookie'; 176 | } 177 | return key; 178 | }; 179 | 180 | -------------------------------------------------------------------------------- /lib/nodeShark.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var bindings = require("../build/Release/nodeshark"); 4 | 5 | exports.LINK_LAYER_TYPE_ETHERNET = 1; 6 | //"encap:" with dlt= USER4= 151, see rawshark.c and http://www.tcpdump.org/linktypes.html 7 | //exports.LINK_LAYER_TYPE_FRP = 151; 8 | exports.PROTO_FRP = 5001; 9 | 10 | exports.Dissector = bindings.Dissector; 11 | exports.TcpTracker = require("./tcpTracker"); 12 | exports.HttpTracker = require("./httpTracker"); 13 | 14 | exports.Dissector.prototype.dissect = function() { 15 | if (arguments.length == 1) { 16 | var data = arguments[0]; 17 | return this._dissect(data); 18 | } else { 19 | throw new Error("Invalid number of arguments"); 20 | } 21 | }; 22 | 23 | exports.isStandardKey = function(key) { 24 | if (key == "sizeInPacket") { 25 | return true; 26 | } 27 | if (key == "positionInPacket") { 28 | return true; 29 | } 30 | if (key == "abbreviation") { 31 | return true; 32 | } 33 | if (key == "value") { 34 | return true; 35 | } 36 | if (key == "dataSource") { 37 | return true; 38 | } 39 | if (key == "rawData") { 40 | return true; 41 | } 42 | if (key == "text") { 43 | return true; 44 | } 45 | return false; 46 | }; 47 | 48 | -------------------------------------------------------------------------------- /lib/tcpTracker.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var util = require("util"); 4 | var events = require("events"); 5 | 6 | var TcpTracker = module.exports = function() { 7 | this.sessions = {}; 8 | events.EventEmitter.call(this); 9 | }; 10 | util.inherits(TcpTracker, events.EventEmitter); 11 | 12 | TcpTracker.prototype.track = function(packet) { 13 | if (!packet || !packet.tcp || !packet.tcp.stream) { 14 | return null; 15 | } 16 | var streamId = packet.tcp.stream.value; 17 | var session = this.sessions[streamId]; 18 | if (!session) { 19 | session = { 20 | streamId: streamId, 21 | srcIp: packet.ip.src.value, 22 | srcPort: packet.tcp.srcport.value, 23 | dstIp: packet.ip.dst.value, 24 | dstPort: packet.tcp.dstport.value, 25 | packetCount: 0, 26 | startTime: new Date(), 27 | isPacketFromSource: function(packet) { 28 | return !this.isPacketFromDestination(packet); 29 | }, 30 | isPacketFromDestination: function(packet) { 31 | if (packet.ip 32 | && packet.tcp 33 | && this.dstIp == packet.ip.src.value 34 | && this.dstPort == packet.tcp.srcport.value) { 35 | return true; 36 | } 37 | return false; 38 | } 39 | }; 40 | this.sessions[streamId] = session; 41 | this.emit('start', session, packet); 42 | } 43 | 44 | session.packetCount++; 45 | session.lastPacketTime = new Date(); 46 | this.emit('packet', session, packet); 47 | 48 | // TODO: detect close 49 | // this.emit('end', session); 50 | 51 | return session; 52 | }; 53 | 54 | -------------------------------------------------------------------------------- /mnm.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var path = require('path'); 4 | var Builder = require('mnm'); 5 | var builder = new Builder(); 6 | 7 | builder.appendUnique('CXXFLAGS', '-Isrc/'); 8 | builder.appendUnique('CXXFLAGS', ['-DHAVE_CONFIG_H']); 9 | 10 | var wiresharkInclude = process.env["WIRESHARK_INCLUDE_DIR"] || "/usr/include/wireshark/"; 11 | builder.failIfNotExists(wiresharkInclude, 'Could not find "%s" check WIRESHARK_INCLUDE_DIR environment variable.'); 12 | builder.appendUnique('CXXFLAGS', '-I' + wiresharkInclude); 13 | 14 | if(process.platform == 'darwin') { 15 | builder.appendUnique('CXXFLAGS', [ '-I' + wiresharkInclude + '/macosx-support-libs/glib-2.31.8/' ]); 16 | builder.appendUnique('CXXFLAGS', [ '-I' + wiresharkInclude + '/macosx-support-libs/glib-2.31.8/glib/' ]); 17 | builder.appendUnique('CXXFLAGS', [ '-I' + wiresharkInclude + '/macosx-support-libs/glib-2.31.8/gmodule/' ]); 18 | } else { 19 | var glibInclude = process.env["GLIB_INCLUDE_DIR"] || "/usr/include/glib-2.0/"; 20 | builder.failIfNotExists(glibInclude, 'Could not find "%s" check GLIB_INCLUDE_DIR environment variable.'); 21 | builder.appendUnique('CXXFLAGS', [ '-I' + glibInclude ]); 22 | 23 | var glibConfigInclude = process.env["GLIB_CONFIG_INCLUDE_DIR"] || "/usr/lib/i386-linux-gnu/glib-2.0/include/"; 24 | builder.failIfNotExists(glibConfigInclude, 'Could not find "%s" check GLIB_CONFIG_INCLUDE_DIR environment variable.'); 25 | builder.appendUnique('CXXFLAGS', [ '-I' + glibConfigInclude ]); 26 | } 27 | 28 | var wiresharkLib = process.env["WIRESHARK_LIB"] || "/usr/local/lib/"; 29 | builder.failIfNotExists(wiresharkLib, 'Could not find "%s" check WIRESHARK_LIB environment variable.'); 30 | builder.appendUnique('LINKFLAGS', [ '-L' + wiresharkLib ]); 31 | 32 | builder.appendUnique('LINKFLAGS', ['-lwireshark', '-lwiretap', '-lwsutil']); 33 | builder.appendUnique('LINKFLAGS', '-Wl,-rpath,' + wiresharkLib); 34 | 35 | builder.target = "nodeshark_bindings"; 36 | builder.appendSourceDir('./src'); 37 | 38 | builder.run(); 39 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nodeshark", 3 | "description": "Wrapper around libwireshark providing network packet dissection", 4 | "author": "Joe Ferner ", 5 | "keywords": [ 6 | "pcap", 7 | "parser", 8 | "dissect", 9 | "wireshark", 10 | "packet", 11 | "network" 12 | ], 13 | "homepage": "https://github.com/nearinfinity/node-shark", 14 | "version": "0.0.5", 15 | "engines": { 16 | "node": ">=0.6.0" 17 | }, 18 | "maintainers": [ 19 | { 20 | "name": "Jeff Kunkle", 21 | "email": "jeff.kunkle@nearinfinity.com" 22 | }, 23 | { 24 | "name": "Joe Ferner", 25 | "email": "joe.ferner@nearinfinity.com" 26 | } 27 | ], 28 | "bugs": { 29 | "url": "https://github.com/nearinfinity/node-shark/issues" 30 | }, 31 | "licenses": [ 32 | { 33 | "type": "MIT" 34 | } 35 | ], 36 | "repository": { 37 | "type": "git", 38 | "url": "git://github.com/nearinfinity/node-shark.git" 39 | }, 40 | "dependencies": { 41 | "mnm": "0.0.4" 42 | }, 43 | "devDependencies": { 44 | "nodeunit": "~0.6.4", 45 | "pcap-parser": "~>0.0.2" 46 | }, 47 | "scripts": { 48 | "test": "nodeunit tests/*", 49 | "install": "node mnm.js build" 50 | }, 51 | "main": "./index.js", 52 | "gypfile": true 53 | } 54 | -------------------------------------------------------------------------------- /src/cfile.cpp: -------------------------------------------------------------------------------- 1 | /* cfile.c 2 | * capture_file GUI-independent manipulation 3 | * Vassilii Khachaturov 4 | * 5 | * $Id: cfile.c 36881 2011-04-27 02:54:44Z guy $ 6 | * 7 | * Wireshark - Network traffic analyzer 8 | * By Gerald Combs 9 | * Copyright 1998 Gerald Combs 10 | * 11 | * This program is free software; you can redistribute it and/or 12 | * modify it under the terms of the GNU General Public License 13 | * as published by the Free Software Foundation; either version 2 14 | * of the License, or (at your option) any later version. 15 | * 16 | * This program is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program; if not, write to the Free Software 23 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 24 | */ 25 | 26 | #ifdef HAVE_CONFIG_H 27 | # include "config.h" 28 | #endif 29 | 30 | #include 31 | 32 | #include 33 | 34 | extern "C" { 35 | #include "cfile.h" 36 | } 37 | 38 | void 39 | cap_file_init(capture_file *cf) 40 | { 41 | /* Initialize the capture file struct */ 42 | memset(cf, 0, sizeof(capture_file)); 43 | cf->filename = NULL; 44 | cf->source = NULL; 45 | cf->is_tempfile = FALSE; 46 | cf->count = 0; 47 | cf->has_snap = FALSE; 48 | cf->snap = WTAP_MAX_PACKET_SIZE; 49 | cf->wth = NULL; 50 | cf->rfcode = NULL; 51 | cf->dfilter = NULL; 52 | cf->redissecting = FALSE; 53 | cf->frames = NULL; 54 | } 55 | -------------------------------------------------------------------------------- /src/dissector.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "dissector.h" 3 | #include "utils.h" 4 | #include "dissectorNode.h" 5 | #include 6 | #include 7 | #include "disabled_protos.h" 8 | 9 | /* for string manipulation as input for prefs_set_pref() */ 10 | #include 11 | 12 | BENCHMARK_GLOBAL_DEF(); 13 | BENCHMARK_DEF(epanDissect); 14 | BENCHMARK_DEF(dissect); 15 | BENCHMARK_DEF(dissectorNodeNew); 16 | BENCHMARK_DEF(dissectorNodeNewRoot); 17 | BENCHMARK_DEF(createChildren); 18 | BENCHMARK_DEF(createChildrenItem); 19 | BENCHMARK_DEF(getAbbreviation); 20 | BENCHMARK_DEF(lazyDissectorNodeNew); 21 | 22 | /* static */ v8::Persistent Dissector::s_ct; 23 | 24 | // the wireshark header file does not declare this as extern "C" so we need to declare it ourselves 25 | extern "C" { 26 | extern int wtap_pcap_encap_to_wtap_encap(int encap); 27 | }; 28 | 29 | /* from wireshark/epan/prefs.h */ 30 | //extern "C" { 31 | // extern prefs_set_pref_e prefs_set_pref(char *prefarg); 32 | //}; 33 | 34 | Dissector::Dissector(int linkLayerType) : m_linkLayerType(linkLayerType) { 35 | } 36 | 37 | /*static*/ void Dissector::Init(v8::Handle target) { 38 | v8::HandleScope scope; 39 | 40 | v8::Local t = v8::FunctionTemplate::New(New); 41 | s_ct = v8::Persistent::New(t); 42 | s_ct->InstanceTemplate()->SetInternalFieldCount(1); 43 | s_ct->SetClassName(v8::String::NewSymbol("Dissector")); 44 | 45 | NODE_SET_PROTOTYPE_METHOD(s_ct, "_dissect", dissect); 46 | NODE_SET_PROTOTYPE_METHOD(s_ct, "close", close); 47 | 48 | target->Set(v8::String::NewSymbol("Dissector"), s_ct->GetFunction()); 49 | } 50 | 51 | /*static*/ v8::Handle Dissector::New(const v8::Arguments& args) { 52 | v8::HandleScope scope; 53 | char errorString[1000]; 54 | dissector_handle_t dhandle; 55 | prefs_set_pref_e pref_e; 56 | int dp_read; 57 | GString *pref_str; 58 | 59 | BENCHMARK_GLOBAL_START(); 60 | 61 | REQ_NUMBER_ARG(0, linkLayerType); 62 | int linkLayerTypeVal = linkLayerType->Value(); 63 | 64 | Dissector *self = new Dissector(linkLayerTypeVal); 65 | 66 | cap_file_init(&self->m_cfile); 67 | 68 | // read preferences 69 | v8::Handle *error = NULL; 70 | e_prefs *prefs = self->readPrefs(error); 71 | if(prefs == NULL) { 72 | return *error; 73 | } 74 | // read disabled_protocols 75 | // dp_read= self->readDisabledProtos(error); 76 | 77 | // Build the column format array 78 | build_column_format_array(&self->m_cfile.cinfo, prefs->num_cols, TRUE); 79 | 80 | self->m_cfile.wth = NULL; 81 | self->m_cfile.f_datalen = 0; 82 | self->m_cfile.filename = NULL; 83 | self->m_cfile.is_tempfile = TRUE; 84 | self->m_cfile.unsaved_changes = FALSE; 85 | self->m_cfile.cd_t = WTAP_FILE_UNKNOWN; 86 | self->m_cfile.count = 0; 87 | self->m_cfile.drops_known = FALSE; 88 | self->m_cfile.drops = 0; 89 | self->m_cfile.has_snap = FALSE; 90 | self->m_cfile.snap = WTAP_MAX_PACKET_SIZE; 91 | nstime_set_zero(&self->m_cfile.elapsed_time); 92 | 93 | /*self->m_encap = wtap_pcap_encap_to_wtap_encap(self->m_linkLayerType);*/ 94 | /* see set_link_type() in http://anonsvn.wireshark.org/viewvc/trunk-1.8/rawshark.c?revision=48199&view=co */ 95 | #define LINK_LAYER_TYPE_ETHERNET 1 96 | #define PROTO_FRP 5001 97 | if (self->m_linkLayerType == LINK_LAYER_TYPE_ETHERNET) { 98 | self->m_encap = wtap_pcap_encap_to_wtap_encap(self->m_linkLayerType); 99 | } else if (self->m_linkLayerType == PROTO_FRP) { 100 | dhandle= find_dissector("frp"); 101 | if (dhandle) { 102 | self->m_encap = WTAP_ENCAP_USER0; 103 | /* "User 0 (DLT=147)","frp","0","","0","" see ~/.wireshark/user_dlts */ 104 | //pref_e= prefs_set_pref("uat:user_dlts:\"User 0 (DLT=147)\",\"frp\",\"0\",\"\",\"0\",\"\""); 105 | pref_str = g_string_new("uat:user_dlts:"); 106 | g_string_append_printf(pref_str, "\"User 0 (DLT=147)\",\"%s\",\"0\",\"\",\"0\",\"\"", "frp"); 107 | sprintf(errorString, "before prefs_set_pref()"); 108 | pref_e= prefs_set_pref(pref_str->str); 109 | g_string_free(pref_str, TRUE); 110 | if (pref_e != PREFS_SET_OK) { 111 | sprintf(errorString, "prefs_set_pref() failed: pref_e= %i", pref_e); 112 | //return pref_e; 113 | } 114 | } 115 | } 116 | 117 | /* disable dissectors as per list read above from disabled_protocolls files */ 118 | if (dp_read) { 119 | // set_disabled_protos_list(); 120 | } 121 | 122 | nstime_set_unset(&self->m_first_ts); 123 | nstime_set_unset(&self->m_prev_dis_ts); 124 | nstime_set_unset(&self->m_prev_cap_ts); 125 | 126 | self->m_data_offset = 0; 127 | 128 | self->Wrap(args.This()); 129 | return args.This(); 130 | } 131 | 132 | Dissector::~Dissector() { 133 | } 134 | 135 | /*static*/ v8::Handle Dissector::dissect(const v8::Arguments& args) { 136 | v8::HandleScope handleScope; 137 | 138 | BENCHMARK_START(dissect); 139 | Dissector* self = ObjectWrap::Unwrap(args.This()); 140 | 141 | struct wtap_pkthdr whdr; 142 | guchar *data; 143 | v8::Local dataBuffer; 144 | 145 | whdr.pkt_encap = self->m_encap; 146 | 147 | if(args.Length() != 1) { 148 | return v8::ThrowException(v8::Exception::Error(v8::String::New("Dissect takes 1 arguments."))); 149 | } 150 | 151 | // no packet information just a buffer 152 | if(node::Buffer::HasInstance(args[0])) { 153 | v8::Local dataBufferValue = args[0]; 154 | dataBuffer = dataBufferValue->ToObject(); 155 | int dataBufferLength = node::Buffer::Length(dataBuffer); 156 | data = (guchar*)node::Buffer::Data(dataBuffer); 157 | whdr.ts.secs = 0; 158 | whdr.ts.nsecs = 0; 159 | whdr.caplen = dataBufferLength; 160 | whdr.len = dataBufferLength; 161 | } 162 | 163 | // packet information with a buffer in the "data" property 164 | else { 165 | REQ_OBJECT_ARG(0, packet); 166 | v8::Local dataBufferValue = packet->Get(v8::String::New("data")); 167 | if(dataBufferValue->IsUndefined()) { 168 | return v8::ThrowException(v8::Exception::Error(v8::String::New("First argument must contain a member 'data' that is a buffer."))); 169 | } 170 | dataBuffer = dataBufferValue->ToObject(); 171 | data = (guchar*)node::Buffer::Data(dataBuffer); 172 | int dataBufferLength = node::Buffer::Length(dataBuffer); 173 | 174 | v8::Local header = packet->Get(v8::String::New("header")); 175 | if(header->IsUndefined()) { 176 | whdr.ts.secs = 0; 177 | whdr.ts.nsecs = 0; 178 | whdr.caplen = dataBufferLength; 179 | whdr.len = dataBufferLength; 180 | } else { 181 | v8::Local headerObj = header->ToObject(); 182 | whdr.ts.secs = getNumberFromV8Object(headerObj, "timestampSeconds", 0); 183 | whdr.ts.nsecs = getNumberFromV8Object(headerObj, "timestampMicroseconds", 0); 184 | whdr.caplen = getNumberFromV8Object(headerObj, "capturedLength", dataBufferLength); 185 | whdr.len = getNumberFromV8Object(headerObj, "originalLength", dataBufferLength); 186 | } 187 | } 188 | 189 | frame_data *fdata = new frame_data(); 190 | epan_dissect_t *edt = new epan_dissect_t(); 191 | 192 | BENCHMARK_START(epanDissect); 193 | self->m_cfile.count++; 194 | frame_data_init(fdata, self->m_cfile.count, &whdr, self->m_data_offset, self->m_cum_bytes); 195 | epan_dissect_init(edt, TRUE, TRUE); 196 | frame_data_set_before_dissect(fdata, &self->m_cfile.elapsed_time, &self->m_first_ts, &self->m_prev_dis_ts, &self->m_prev_cap_ts); 197 | epan_dissect_run(edt, &self->m_cfile.pseudo_header, data, fdata, &self->m_cfile.cinfo); 198 | frame_data_set_after_dissect(fdata, &self->m_cum_bytes, &self->m_prev_dis_ts); 199 | self->m_data_offset += whdr.caplen; 200 | BENCHMARK_END(epanDissect); 201 | 202 | v8::Local result = DissectorNode::New(NULL, fdata, edt, edt->tree); 203 | 204 | BENCHMARK_END(dissect); 205 | return handleScope.Close(result); 206 | } 207 | 208 | /*static*/ v8::Handle Dissector::close(const v8::Arguments& args) { 209 | v8::HandleScope handleScope; 210 | #ifdef BENCHMARK 211 | Dissector* self = node::ObjectWrap::Unwrap(args.This()); 212 | #endif 213 | 214 | BENCHMARK_GLOBAL_END(); 215 | 216 | BENCHMARK_PRINT_START(); 217 | BENCHMARK_PRINT(dissect); 218 | BENCHMARK_PRINT(epanDissect); 219 | BENCHMARK_PRINT(dissectorNodeNew); 220 | BENCHMARK_PRINT(dissectorNodeNewRoot); 221 | BENCHMARK_PRINT(createChildren); 222 | BENCHMARK_PRINT(createChildrenItem); 223 | BENCHMARK_PRINT(getAbbreviation); 224 | BENCHMARK_PRINT(lazyDissectorNodeNew); 225 | BENCHMARK_PRINT_END(); 226 | 227 | #ifdef BENCHMARK 228 | printf("packet count: %d\n", self->m_cfile.count); 229 | #endif 230 | 231 | return v8::Undefined(); 232 | } 233 | 234 | /* read .wireshark/preferences ... , see read_prefs() in 235 | http://anonsvn.wireshark.org/viewvc/trunk-1.8/rawshark.c?revision=48199&view=co */ 236 | e_prefs* Dissector::readPrefs(v8::Handle *error) { 237 | char errorString[1000]; 238 | e_prefs *prefs_p; 239 | char *gpf_path, *pf_path; 240 | int gpf_open_errno, gpf_read_errno; 241 | int pf_open_errno, pf_read_errno; 242 | prefs_p = read_prefs(&gpf_open_errno, &gpf_read_errno, &gpf_path, &pf_open_errno, &pf_read_errno, &pf_path); 243 | if (gpf_path != NULL) { 244 | if (gpf_open_errno != 0) { 245 | sprintf(errorString, "Can't open global preferences file \"%s\": %s.", pf_path, g_strerror(gpf_open_errno)); 246 | } 247 | if (gpf_read_errno != 0) { 248 | sprintf(errorString, "I/O error reading global preferences file \"%s\": %s.", pf_path, g_strerror(gpf_read_errno)); 249 | } 250 | *error = v8::ThrowException(v8::Exception::Error(v8::String::New(errorString))); 251 | return NULL; 252 | } 253 | if (pf_path != NULL) { 254 | if (pf_open_errno != 0) { 255 | sprintf(errorString, "Can't open your preferences file \"%s\": %s.", pf_path, g_strerror(pf_open_errno)); 256 | } 257 | if (pf_read_errno != 0) { 258 | sprintf(errorString, "I/O error reading your preferences file \"%s\": %s.", pf_path, g_strerror(pf_read_errno)); 259 | } 260 | g_free(pf_path); 261 | *error = v8::ThrowException(v8::Exception::Error(v8::String::New(errorString))); 262 | return NULL; 263 | } 264 | return prefs_p; 265 | } 266 | 267 | /* read .wireshark/disabled_protocols ..., see read_disabled_protos_list() in 268 | http://anonsvn.wireshark.org/viewvc/trunk-1.8/rawshark.c?revision=48199&view=co */ 269 | int Dissector::readDisabledProtos(v8::Handle *error) { 270 | char errorString[1000]; 271 | char *gdp_path, *dp_path; 272 | int gdp_open_errno, gdp_read_errno; 273 | int dp_open_errno, dp_read_errno; 274 | 275 | read_disabled_protos_list(&gdp_path, &gdp_open_errno, &gdp_read_errno, 276 | &dp_path, &dp_open_errno, &dp_read_errno); 277 | if (gdp_path != NULL) { 278 | if (gdp_open_errno != 0) { 279 | sprintf(errorString, "Could not open global disabled protocols file\n\"%s\": %s.", 280 | gdp_path, g_strerror(gdp_open_errno)); 281 | } 282 | if (gdp_read_errno != 0) { 283 | sprintf(errorString, "I/O error reading global disabled protocols file\n\"%s\": %s.", 284 | gdp_path, g_strerror(gdp_read_errno)); 285 | } 286 | g_free(gdp_path); 287 | *error = v8::ThrowException(v8::Exception::Error(v8::String::New(errorString))); 288 | } 289 | if (dp_path != NULL) { 290 | if (dp_open_errno != 0) { 291 | sprintf(errorString, "Could not open your disabled protocols file\n\"%s\": %s.", dp_path, 292 | g_strerror(dp_open_errno)); 293 | } 294 | if (dp_read_errno != 0) { 295 | sprintf(errorString, "I/O error reading your disabled protocols file\n\"%s\": %s.", dp_path, 296 | g_strerror(dp_read_errno)); 297 | } 298 | g_free(dp_path); 299 | *error = v8::ThrowException(v8::Exception::Error(v8::String::New(errorString))); 300 | } 301 | return (gdp_path == NULL && dp_path == NULL); 302 | } 303 | 304 | -------------------------------------------------------------------------------- /src/dissector.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _dissector_h_ 3 | #define _dissector_h_ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | extern "C" { 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | } 28 | #include 29 | #include 30 | 31 | class Dissector : node::ObjectWrap { 32 | public: 33 | static void Init(v8::Handle target); 34 | static v8::Handle New(const v8::Arguments& args); 35 | ~Dissector(); 36 | 37 | private: 38 | Dissector(int linkLayerType); 39 | static v8::Persistent s_ct; 40 | static v8::Handle dissect(const v8::Arguments& args); 41 | static v8::Handle close(const v8::Arguments& args); 42 | e_prefs* readPrefs(v8::Handle *error); 43 | int readDisabledProtos(v8::Handle *error); 44 | static void treeToObject(proto_node *node, gpointer data); 45 | static void treeToString(proto_node *node, gpointer data); 46 | static void xmlTreeToString(proto_node *node, gpointer data); 47 | static const guint8 *getFieldData(GSList *src_list, field_info *fi); 48 | static v8::Handle sliceBuffer(v8::Handle buffer, int start, int end); 49 | static const char* getNodeName(proto_node *node, const char *parentName, int *needsFree); 50 | static const char* fixEscapes(const char* src, char* dest); 51 | 52 | int m_linkLayerType; 53 | capture_file m_cfile; 54 | int m_encap; 55 | nstime_t m_first_ts; 56 | nstime_t m_prev_dis_ts; 57 | nstime_t m_prev_cap_ts; 58 | guint32 m_cum_bytes; 59 | gint64 m_data_offset; 60 | }; 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /src/dissectorNode.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "dissectorNode.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "utils.h" 14 | #include "lazyDissectorNode.h" 15 | #include "lazyDataSource.h" 16 | 17 | //#define SHOW_CREATES 18 | BENCHMARK_DEF_EXTERN(dissectorNodeNew); 19 | BENCHMARK_DEF_EXTERN(dissectorNodeNewRoot); 20 | BENCHMARK_DEF_EXTERN(createChildren); 21 | BENCHMARK_DEF_EXTERN(createChildrenItem); 22 | BENCHMARK_DEF_EXTERN(getAbbreviation); 23 | 24 | /*static*/ v8::Persistent DissectorNode::s_ct; 25 | 26 | /*static*/ void DissectorNode::Init(v8::Handle target) { 27 | v8::HandleScope scope; 28 | 29 | v8::Local t = v8::FunctionTemplate::New(); 30 | s_ct = v8::Persistent::New(t); 31 | s_ct->InstanceTemplate()->SetInternalFieldCount(1); 32 | s_ct->SetClassName(v8::String::NewSymbol("Node")); 33 | 34 | target->Set(v8::String::NewSymbol("Node"), s_ct->GetFunction()); 35 | } 36 | 37 | int DissectorNode::getPositionInPacket(proto_node *node, field_info *fi) { 38 | int posInPacket; 39 | if (node->parent && node->parent->finfo && (fi->start < node->parent->finfo->start)) { 40 | posInPacket = node->parent->finfo->start + fi->start; 41 | } else { 42 | posInPacket = fi->start; 43 | } 44 | return posInPacket; 45 | } 46 | 47 | const char* DissectorNode::fixEscapes(const char* src, char* dest) { 48 | const char* read = src; 49 | char* write = dest; 50 | while(*read) { 51 | if(*read == '\\') { 52 | read++; 53 | switch(*read) { 54 | case '\0': goto endOfRead; 55 | case '\\': *write++ = '\\'; read++; break; 56 | case 't': *write++ = '\t'; read++; break; 57 | case 'r': *write++ = '\r'; read++; break; 58 | case 'n': *write++ = '\n'; read++; break; 59 | default: 60 | *write++ = '\\'; 61 | *write++ = *read++; 62 | break; 63 | } 64 | } else { 65 | *write++ = *read++; 66 | } 67 | } 68 | endOfRead: 69 | *write++ = '\0'; 70 | return dest; 71 | } 72 | 73 | v8::Handle DissectorNode::getDataSourceName(tvbuff_t *tvb) { 74 | v8::HandleScope scope; 75 | for (GSList *src_le = m_edt->pi.data_src; src_le != NULL; src_le = src_le->next) { 76 | data_source *src = (data_source*)src_le->data; 77 | if(tvb == src->tvb) { 78 | char *name = strdup(get_data_source_name(src)); 79 | char *paren = strchr(name, '('); 80 | if(paren) *paren = '\0'; 81 | strtrim(name); 82 | v8::Local result = v8::String::New(name); 83 | delete[] name; 84 | return scope.Close(result); 85 | } 86 | } 87 | return v8::Undefined(); 88 | } 89 | 90 | /*static*/ v8::Local DissectorNode::New(DissectorNode *root, frame_data *fdata, epan_dissect_t *edt, proto_node *node) { 91 | v8::HandleScope scope; 92 | BENCHMARK_START(dissectorNodeNew); 93 | v8::Local ctor = s_ct->GetFunction(); 94 | v8::Local obj = ctor->NewInstance(); 95 | DissectorNode *self = new DissectorNode(root, fdata, edt, node); 96 | self->Wrap(obj); 97 | 98 | if(self->isRoot()) { 99 | BENCHMARK_START(dissectorNodeNewRoot); 100 | obj->Set(v8::String::New("root"), v8::Boolean::New(true)); 101 | 102 | v8::Local dataSources = v8::Object::New(); 103 | for (GSList *src_le = edt->pi.data_src; src_le != NULL; src_le = src_le->next) { 104 | data_source *src = (data_source*)src_le->data; 105 | tvbuff_t *tvb = src->tvb; 106 | v8::Local lazyDataSource = LazyDataSource::New(self, tvb); 107 | dataSources->SetAccessor(self->getDataSourceName(src->tvb)->ToString(), dataSourceGetter, dataSourceSetter, lazyDataSource); 108 | } 109 | obj->Set(v8::String::New("dataSources"), dataSources); 110 | BENCHMARK_END(dissectorNodeNewRoot); 111 | } 112 | 113 | field_info *fi = PNODE_FINFO(node); 114 | if(fi) { 115 | self->m_sizeInPacket = fi->length; 116 | self->m_posInPacket = getPositionInPacket(node, fi); 117 | obj->Set(v8::String::New("sizeInPacket"), v8::Integer::New(self->m_sizeInPacket)); 118 | obj->Set(v8::String::New("positionInPacket"), v8::Integer::New(self->m_posInPacket)); 119 | obj->Set(v8::String::New("abbreviation"), self->getAbbreviation(node)); 120 | obj->Set(v8::String::New("dataSource"), self->getDataSourceName(fi->ds_tvb)); 121 | 122 | if (fi->rep) { 123 | obj->SetAccessor(v8::String::New("representation"), representationGetter, representationSetter); 124 | } 125 | 126 | obj->SetAccessor(v8::String::New("value"), valueGetter, valueSetter); 127 | obj->SetAccessor(v8::String::New("rawData"), rawDataGetter, rawDataSetter); 128 | } 129 | 130 | self->createChildren(); 131 | 132 | BENCHMARK_END(dissectorNodeNew); 133 | return scope.Close(obj); 134 | } 135 | 136 | v8::Handle DissectorNode::getAbbreviation(proto_node *node) { 137 | v8::HandleScope scope; 138 | BENCHMARK_START(getAbbreviation); 139 | field_info *fi = PNODE_FINFO(node); 140 | if(fi) { 141 | const char *abbr = fi->hfinfo->abbrev; 142 | if(abbr) { 143 | if(strcmp(abbr, "text") == 0) { 144 | v8::Handle result = getRepresentation(node); 145 | BENCHMARK_END(getAbbreviation); 146 | return scope.Close(result); 147 | } 148 | 149 | if(!isRoot()) { 150 | v8::String::AsciiValue parentAbbr(handle_->Get(v8::String::New("abbreviation"))); 151 | int parentAbbrLen = strlen(*parentAbbr); 152 | if(strncmp(abbr, *parentAbbr, parentAbbrLen) == 0 153 | && abbr[parentAbbrLen] == '.') { 154 | abbr += parentAbbrLen + 1; 155 | } 156 | } 157 | 158 | v8::Handle result = v8::String::New(abbr); 159 | BENCHMARK_END(getAbbreviation); 160 | return scope.Close(result); 161 | } 162 | } 163 | BENCHMARK_END(getAbbreviation); 164 | return scope.Close(v8::Undefined()); 165 | } 166 | 167 | void DissectorNode::createChildren() { 168 | BENCHMARK_START(createChildren); 169 | proto_tree_children_foreach(m_node, createChildrenItem, this); 170 | BENCHMARK_END(createChildren); 171 | } 172 | 173 | /*static*/ void DissectorNode::createChildrenItem(proto_node *node, gpointer data) { 174 | BENCHMARK_START(createChildrenItem); 175 | DissectorNode *self = (DissectorNode*)data; 176 | v8::Local lazyNode = LazyDissectorNode::New(self->m_fdata, self->m_edt, node); 177 | v8::Handle abbreviationVal = self->getAbbreviation(node); 178 | self->handle_->SetAccessor(abbreviationVal->ToString(), childGetter, childSetter, lazyNode); 179 | BENCHMARK_END(createChildrenItem); 180 | } 181 | 182 | /*static*/ v8::Handle DissectorNode::childGetter(v8::Local property, const v8::AccessorInfo& info) { 183 | v8::HandleScope scope; 184 | DissectorNode *self = node::ObjectWrap::Unwrap(info.This()); 185 | if(self->m_childStorage->Has(property)) { 186 | return scope.Close(self->m_childStorage->Get(property)); 187 | } else { 188 | #ifdef SHOW_CREATES 189 | v8::String::AsciiValue propertyStr(property); 190 | printf("***** create child: %s\n", *propertyStr); 191 | #endif 192 | 193 | LazyDissectorNode *lazyNode = node::ObjectWrap::Unwrap(info.Data()->ToObject()); 194 | v8::Local newNodeObj = New(self->m_root, self->m_fdata, self->m_edt, lazyNode->getProtoNode()); 195 | self->m_childStorage->Set(property, newNodeObj); 196 | return scope.Close(newNodeObj); 197 | } 198 | } 199 | 200 | /*static*/ void DissectorNode::childSetter(v8::Local property, v8::Local value, const v8::AccessorInfo& info) { 201 | v8::HandleScope scope; 202 | DissectorNode *self = node::ObjectWrap::Unwrap(info.This()); 203 | self->m_childStorage->Set(property, value); 204 | } 205 | 206 | /*static*/ v8::Handle DissectorNode::dataSourceGetter(v8::Local property, const v8::AccessorInfo& info) { 207 | v8::HandleScope scope; 208 | LazyDataSource *lazyDataSource = node::ObjectWrap::Unwrap(info.Data()->ToObject()); 209 | DissectorNode *self = lazyDataSource->getParent(); 210 | if(self->m_dataSourceStorage->Has(property)) { 211 | return scope.Close(self->m_dataSourceStorage->Get(property)); 212 | } else { 213 | #ifdef SHOW_CREATES 214 | v8::String::AsciiValue propertyStr(property); 215 | printf("***** create datasource: %s\n", *propertyStr); 216 | #endif 217 | 218 | node::Buffer *buf = lazyDataSource->createBuffer(); 219 | self->m_dataSourceStorage->Set(property, buf->handle_); 220 | return scope.Close(buf->handle_); 221 | } 222 | } 223 | 224 | /*static*/ void DissectorNode::dataSourceSetter(v8::Local property, v8::Local value, const v8::AccessorInfo& info) { 225 | v8::HandleScope scope; 226 | DissectorNode *self = node::ObjectWrap::Unwrap(info.This()); 227 | self->m_dataSourceStorage->Set(property, value); 228 | } 229 | 230 | /*static*/ v8::Handle DissectorNode::representationGetter(v8::Local property, const v8::AccessorInfo& info) { 231 | v8::HandleScope scope; 232 | DissectorNode *self = node::ObjectWrap::Unwrap(info.This()); 233 | 234 | if(self->m_representation.IsEmpty()) { 235 | self->m_representation = v8::Persistent::New(getRepresentation(self->m_node)->ToString()); 236 | } 237 | 238 | return scope.Close(self->m_representation); 239 | } 240 | 241 | /*static*/ v8::Handle DissectorNode::getRepresentation(proto_node *node) { 242 | v8::HandleScope scope; 243 | field_info *fi = PNODE_FINFO(node); 244 | if(fi && fi->rep) { 245 | char *temp = new char[strlen(fi->rep->representation)+2]; // TODO: avoid copy 246 | fixEscapes(fi->rep->representation, temp); 247 | v8::Local result = v8::String::New(temp); 248 | delete[] temp; 249 | return scope.Close(result); 250 | } 251 | return scope.Close(v8::Undefined()); 252 | } 253 | 254 | /*static*/ void DissectorNode::representationSetter(v8::Local property, v8::Local value, const v8::AccessorInfo& info) { 255 | v8::HandleScope scope; 256 | DissectorNode *self = node::ObjectWrap::Unwrap(info.This()); 257 | self->m_representation.Dispose(); 258 | self->m_representation = v8::Persistent::New(value); 259 | } 260 | 261 | /*static*/ v8::Handle DissectorNode::valueGetter(v8::Local property, const v8::AccessorInfo& info) { 262 | v8::HandleScope scope; 263 | DissectorNode *self = node::ObjectWrap::Unwrap(info.This()); 264 | 265 | if(self->m_value.IsEmpty()) { 266 | field_info *fi = PNODE_FINFO(self->m_node); 267 | int showStringChopPos = 0; 268 | char *showString = proto_construct_match_selected_string(fi, self->m_edt); 269 | if (showString != NULL) { 270 | char *p = strstr(showString, "=="); 271 | if(p) { 272 | showStringChopPos = (int)(p - showString) + 3; 273 | } 274 | 275 | if (showString[strlen(showString)-1] == '"') { 276 | showString[strlen(showString)-1] = '\0'; 277 | showStringChopPos++; 278 | } 279 | 280 | char *theString = &(showString[showStringChopPos]); 281 | char *temp = new char[strlen(theString)+2]; // TODO: avoid copy 282 | fixEscapes(theString, temp); 283 | self->m_value = v8::Persistent::New(v8::String::New(temp)); 284 | delete[] temp; 285 | } 286 | } 287 | 288 | return scope.Close(self->m_value); 289 | } 290 | 291 | /*static*/ void DissectorNode::valueSetter(v8::Local property, v8::Local value, const v8::AccessorInfo& info) { 292 | v8::HandleScope scope; 293 | DissectorNode *self = node::ObjectWrap::Unwrap(info.This()); 294 | self->m_value.Dispose(); 295 | self->m_value = v8::Persistent::New(value); 296 | } 297 | 298 | /*static*/ v8::Handle DissectorNode::rawDataGetter(v8::Local property, const v8::AccessorInfo& info) { 299 | v8::HandleScope scope; 300 | DissectorNode *self = node::ObjectWrap::Unwrap(info.This()); 301 | 302 | if(self->m_rawData.IsEmpty()) { 303 | #ifdef SHOW_CREATES 304 | v8::String::AsciiValue propertyStr(property); 305 | printf("***** create rawData: %s\n", *propertyStr); 306 | #endif 307 | 308 | v8::Local dataSources = self->m_root->handle_->Get(v8::String::New("dataSources"))->ToObject(); 309 | v8::Local dataSourceNameObj = self->handle_->Get(v8::String::New("dataSource")); 310 | if(!dataSourceNameObj->IsNull() && !dataSourceNameObj->IsUndefined()) { 311 | v8::Local dataSourceName = dataSourceNameObj->ToString(); 312 | v8::Local dataSource = dataSources->Get(dataSourceName)->ToObject(); 313 | v8::Local sliceFn = dataSource->Get(v8::String::New("slice"))->ToObject(); 314 | v8::Handle sliceArgs[] = { 315 | v8::Integer::New(self->m_posInPacket), 316 | v8::Integer::New(self->m_posInPacket + self->m_sizeInPacket) 317 | }; 318 | self->m_rawData = v8::Persistent::New(sliceFn->CallAsFunction(dataSource, 2, sliceArgs)); 319 | } 320 | } 321 | 322 | return scope.Close(self->m_rawData); 323 | } 324 | 325 | /*static*/ void DissectorNode::rawDataSetter(v8::Local property, v8::Local value, const v8::AccessorInfo& info) { 326 | v8::HandleScope scope; 327 | DissectorNode *self = node::ObjectWrap::Unwrap(info.This()); 328 | self->m_rawData.Dispose(); 329 | self->m_rawData = v8::Persistent::New(value); 330 | } 331 | 332 | DissectorNode::DissectorNode(DissectorNode *root, frame_data *fdata, epan_dissect_t *edt, proto_node *node) { 333 | m_fdata = fdata; 334 | if(root == NULL) { 335 | m_root = this; 336 | } else { 337 | m_root = root; 338 | } 339 | m_edt = edt; 340 | m_node = node; 341 | m_childStorage = v8::Persistent::New(v8::Object::New()); 342 | m_dataSourceStorage = v8::Persistent::New(v8::Object::New()); 343 | } 344 | 345 | DissectorNode::~DissectorNode() { 346 | m_representation.Dispose(); 347 | m_value.Dispose(); 348 | m_childStorage.Dispose(); 349 | m_dataSourceStorage.Dispose(); 350 | m_rawData.Dispose(); 351 | if(isRoot()) { 352 | epan_dissect_cleanup(m_edt); 353 | frame_data_cleanup(m_fdata); 354 | delete m_edt; 355 | delete m_fdata; 356 | } 357 | } 358 | -------------------------------------------------------------------------------- /src/dissectorNode.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _node_h_ 3 | #define _node_h_ 4 | 5 | #include 6 | #include 7 | extern "C" { 8 | #include 9 | #include 10 | } 11 | 12 | class DissectorNode : node::ObjectWrap { 13 | public: 14 | static void Init(v8::Handle target); 15 | static v8::Local New(DissectorNode *root, frame_data *fdata, epan_dissect_t *edt, proto_node *node); 16 | bool isRoot() { return this == m_root; } 17 | 18 | private: 19 | DissectorNode(DissectorNode *root, frame_data *fdata, epan_dissect_t *edt, proto_node *node); 20 | ~DissectorNode(); 21 | 22 | static void NotImplementedSetter(v8::Local property, v8::Local value, const v8::AccessorInfo& info); 23 | static v8::Handle AbbreviationGetter(v8::Local property, const v8::AccessorInfo& info); 24 | static int getPositionInPacket(proto_node *node, field_info *fi); 25 | static const char* fixEscapes(const char* src, char* dest); 26 | static v8::Handle representationGetter(v8::Local property, const v8::AccessorInfo& info); 27 | static void representationSetter(v8::Local property, v8::Local value, const v8::AccessorInfo& info); 28 | static v8::Handle valueGetter(v8::Local property, const v8::AccessorInfo& info); 29 | static void valueSetter(v8::Local property, v8::Local value, const v8::AccessorInfo& info); 30 | void createChildren(); 31 | static void createChildrenItem(proto_node *node, gpointer data); 32 | static v8::Handle childGetter(v8::Local property, const v8::AccessorInfo& info); 33 | static void childSetter(v8::Local property, v8::Local value, const v8::AccessorInfo& info); 34 | static v8::Handle dataSourceGetter(v8::Local property, const v8::AccessorInfo& info); 35 | static void dataSourceSetter(v8::Local property, v8::Local value, const v8::AccessorInfo& info); 36 | v8::Handle getDataSourceName(tvbuff_t *tvb); 37 | static v8::Handle rawDataGetter(v8::Local property, const v8::AccessorInfo& info); 38 | static void rawDataSetter(v8::Local property, v8::Local value, const v8::AccessorInfo& info); 39 | v8::Handle getAbbreviation(proto_node *node); 40 | static v8::Handle getRepresentation(proto_node *node); 41 | 42 | static v8::Persistent s_ct; 43 | DissectorNode *m_root; 44 | frame_data *m_fdata; 45 | epan_dissect_t *m_edt; 46 | proto_node *m_node; 47 | int m_sizeInPacket; 48 | int m_posInPacket; 49 | v8::Persistent m_representation; 50 | v8::Persistent m_value; 51 | v8::Persistent m_rawData; 52 | v8::Persistent m_childStorage; 53 | v8::Persistent m_dataSourceStorage; 54 | }; 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /src/lazyDataSource.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include "lazyDataSource.h" 4 | 5 | /*static*/ v8::Persistent LazyDataSource::s_ct; 6 | 7 | /*static*/ void LazyDataSource::Init(v8::Handle target) { 8 | v8::HandleScope scope; 9 | 10 | v8::Local t = v8::FunctionTemplate::New(); 11 | s_ct = v8::Persistent::New(t); 12 | s_ct->InstanceTemplate()->SetInternalFieldCount(1); 13 | s_ct->SetClassName(v8::String::NewSymbol("LazyDataSource")); 14 | 15 | target->Set(v8::String::NewSymbol("LazyDataSource"), s_ct->GetFunction()); 16 | } 17 | 18 | /*static*/ v8::Local LazyDataSource::New(DissectorNode *parent, tvbuff_t *tvb) { 19 | v8::HandleScope scope; 20 | v8::Local ctor = s_ct->GetFunction(); 21 | v8::Local obj = ctor->NewInstance(); 22 | LazyDataSource *self = new LazyDataSource(parent, tvb); 23 | self->Wrap(obj); 24 | 25 | return scope.Close(obj); 26 | } 27 | 28 | LazyDataSource::LazyDataSource(DissectorNode *parent, tvbuff_t *tvb) { 29 | m_parent = parent; 30 | m_tvb = tvb; 31 | } 32 | 33 | LazyDataSource::~LazyDataSource() { 34 | 35 | } 36 | 37 | node::Buffer* LazyDataSource::createBuffer() { 38 | guint length = tvb_length(m_tvb); 39 | const guchar *cp = tvb_get_ptr(m_tvb, 0, length); 40 | node::Buffer *buf = node::Buffer::New(length); 41 | memcpy(node::Buffer::Data(buf), cp, length); 42 | return buf; 43 | } 44 | -------------------------------------------------------------------------------- /src/lazyDataSource.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _lazydatasource_h_ 3 | #define _lazydatasource_h_ 4 | 5 | #include 6 | #include 7 | extern "C" { 8 | #include 9 | #include 10 | } 11 | #include 12 | 13 | class DissectorNode; 14 | 15 | class LazyDataSource : node::ObjectWrap { 16 | public: 17 | static void Init(v8::Handle target); 18 | static v8::Local New(DissectorNode *parent, tvbuff_t *tvb); 19 | node::Buffer* createBuffer(); 20 | DissectorNode* getParent() { return m_parent; } 21 | 22 | private: 23 | LazyDataSource(DissectorNode *parent, tvbuff_t *tvb); 24 | ~LazyDataSource(); 25 | 26 | static v8::Persistent s_ct; 27 | DissectorNode *m_parent; 28 | tvbuff_t *m_tvb; 29 | }; 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /src/lazyDissectorNode.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "lazyDissectorNode.h" 3 | #include "utils.h" 4 | 5 | BENCHMARK_DEF_EXTERN(lazyDissectorNodeNew); 6 | 7 | /*static*/ v8::Persistent LazyDissectorNode::s_ct; 8 | 9 | /*static*/ void LazyDissectorNode::Init(v8::Handle target) { 10 | v8::HandleScope scope; 11 | 12 | v8::Local t = v8::FunctionTemplate::New(); 13 | s_ct = v8::Persistent::New(t); 14 | s_ct->InstanceTemplate()->SetInternalFieldCount(1); 15 | s_ct->SetClassName(v8::String::NewSymbol("LazyNode")); 16 | 17 | target->Set(v8::String::NewSymbol("LazyNode"), s_ct->GetFunction()); 18 | } 19 | 20 | /*static*/ v8::Local LazyDissectorNode::New(frame_data *fdata, epan_dissect_t *edt, proto_node *node) { 21 | v8::HandleScope scope; 22 | BENCHMARK_START(lazyDissectorNodeNew); 23 | v8::Local ctor = s_ct->GetFunction(); 24 | v8::Local obj = ctor->NewInstance(); 25 | LazyDissectorNode *self = new LazyDissectorNode(fdata, edt, node); 26 | self->Wrap(obj); 27 | BENCHMARK_END(lazyDissectorNodeNew); 28 | return scope.Close(obj); 29 | } 30 | 31 | LazyDissectorNode::LazyDissectorNode(frame_data *fdata, epan_dissect_t *edt, proto_node *node) { 32 | m_fdata = fdata; 33 | m_edt = edt; 34 | m_node = node; 35 | } 36 | 37 | LazyDissectorNode::~LazyDissectorNode() { 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/lazyDissectorNode.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _lazydissectornode_h_ 3 | #define _lazydissectornode_h_ 4 | 5 | #include 6 | #include 7 | extern "C" { 8 | #include 9 | #include 10 | } 11 | 12 | class LazyDissectorNode : node::ObjectWrap { 13 | public: 14 | static void Init(v8::Handle target); 15 | static v8::Local New(frame_data *fdata, epan_dissect_t *edt, proto_node *node); 16 | proto_node* getProtoNode() { return m_node; } 17 | 18 | private: 19 | LazyDissectorNode(frame_data *fdata, epan_dissect_t *edt, proto_node *node); 20 | ~LazyDissectorNode(); 21 | 22 | static v8::Persistent s_ct; 23 | frame_data *m_fdata; 24 | epan_dissect_t *m_edt; 25 | proto_node *m_node; 26 | }; 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /src/nodeshark.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "nodeshark.h" 3 | #include "dissector.h" 4 | #include "dissectorNode.h" 5 | #include "lazyDissectorNode.h" 6 | #include "lazyDataSource.h" 7 | 8 | /* static */ v8::Persistent NodeShark::s_ct; 9 | 10 | static void 11 | tshark_log_handler (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data) 12 | { 13 | g_log_default_handler(log_domain, log_level, message, user_data); 14 | } 15 | 16 | /*static*/ void NodeShark::Init(v8::Handle target) { 17 | v8::HandleScope scope; 18 | 19 | v8::Local t = v8::FunctionTemplate::New(New); 20 | s_ct = v8::Persistent::New(t); 21 | s_ct->InstanceTemplate()->SetInternalFieldCount(1); 22 | s_ct->SetClassName(v8::String::NewSymbol("NodeShark")); 23 | 24 | target->Set(v8::String::NewSymbol("NodeShark"), s_ct->GetFunction()); 25 | 26 | init_process_policies(); 27 | 28 | // nothing more than the standard GLib handler, but without a warning 29 | GLogLevelFlags log_flags = (GLogLevelFlags)( 30 | G_LOG_LEVEL_ERROR 31 | | G_LOG_LEVEL_CRITICAL 32 | | G_LOG_LEVEL_WARNING 33 | | G_LOG_LEVEL_MESSAGE 34 | | G_LOG_LEVEL_INFO 35 | | G_LOG_LEVEL_DEBUG 36 | | G_LOG_FLAG_FATAL 37 | | G_LOG_FLAG_RECURSION); 38 | 39 | g_log_set_handler(NULL, log_flags, tshark_log_handler, NULL); 40 | g_log_set_handler(LOG_DOMAIN_CAPTURE_CHILD, log_flags, tshark_log_handler, NULL); 41 | 42 | timestamp_set_type(TS_RELATIVE); 43 | timestamp_set_precision(TS_PREC_AUTO); 44 | timestamp_set_seconds_type(TS_SECONDS_DEFAULT); 45 | 46 | epan_init( 47 | register_all_protocols, 48 | register_all_protocol_handoffs, 49 | NULL, 50 | NULL, 51 | failureMessage, 52 | openFailureMessage, 53 | readFailureMessage, 54 | writeFailureMessage); 55 | 56 | prefs_register_modules(); 57 | 58 | setlocale(LC_ALL, ""); 59 | 60 | // Cleanup all data structures used for dissection. 61 | cleanup_dissection(); 62 | 63 | // Initialize all data structures used for dissection. 64 | init_dissection(); 65 | } 66 | 67 | /*static*/ v8::Handle NodeShark::New(const v8::Arguments& args) { 68 | return v8::Undefined(); 69 | } 70 | 71 | /* 72 | * Open/create errors are reported with an console message in TShark. 73 | */ 74 | /*static*/ void NodeShark::openFailureMessage(const char *filename, int err, gboolean for_writing) 75 | { 76 | fprintf(stderr, "nodeshark: filename: %s, err: %d\n", filename, err); 77 | } 78 | 79 | /* 80 | * General errors are reported with an console message in TShark. 81 | */ 82 | /*static*/ void NodeShark::failureMessage(const char *msg_format, va_list ap) 83 | { 84 | //fprintf(stderr, "nodeshark: "); 85 | //vfprintf(stderr, msg_format, ap); 86 | //fprintf(stderr, "\n"); 87 | } 88 | 89 | /* 90 | * Read errors are reported with an console message in TShark. 91 | */ 92 | /*static*/ void NodeShark::readFailureMessage(const char *filename, int err) 93 | { 94 | fprintf(stderr, "nodeshark: An error occurred while reading from the file \"%s\": %s.", filename, g_strerror(err)); 95 | } 96 | 97 | /* 98 | * Write errors are reported with an console message in TShark. 99 | */ 100 | /*static*/ void NodeShark::writeFailureMessage(const char *filename, int err) 101 | { 102 | fprintf(stderr, "nodeshark: An error occurred while writing to the file \"%s\": %s.", filename, g_strerror(err)); 103 | } 104 | 105 | extern "C" { 106 | static void init(v8::Handle target) { 107 | NodeShark::Init(target); 108 | Dissector::Init(target); 109 | DissectorNode::Init(target); 110 | LazyDissectorNode::Init(target); 111 | LazyDataSource::Init(target); 112 | } 113 | 114 | NODE_MODULE(nodeshark, init); 115 | } 116 | -------------------------------------------------------------------------------- /src/nodeshark.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef nodeshark_h_ 3 | #define nodeshark_h_ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | extern "C" { 15 | #include 16 | #include 17 | } 18 | 19 | class NodeShark : node::ObjectWrap { 20 | public: 21 | static void Init(v8::Handle target); 22 | static v8::Handle New(const v8::Arguments& args); 23 | 24 | private: 25 | static v8::Persistent s_ct; 26 | static void openFailureMessage(const char *filename, int err, gboolean for_writing); 27 | static void failureMessage(const char *msg_format, va_list ap); 28 | static void readFailureMessage(const char *filename, int err); 29 | static void writeFailureMessage(const char *filename, int err); 30 | }; 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /src/utils.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include "utils.h" 6 | 7 | double getNumberFromV8Object(v8::Local &obj, const char *key, double def) { 8 | v8::Local v = obj->Get(v8::String::New(key)); 9 | if(v->IsNumber()) { 10 | return v->ToNumber()->Value(); 11 | } 12 | if(v->IsString()) { 13 | v8::String::AsciiValue asciiVal(v); 14 | return atof(*asciiVal); 15 | } 16 | return def; 17 | } 18 | 19 | void strtrim(char *str) { 20 | char *read = str; 21 | char *write = str; 22 | char *lastChar = NULL; 23 | 24 | while(isspace(*read)) { 25 | read++; 26 | } 27 | while(*read) { 28 | if(!isspace(*read)) lastChar = read; 29 | *write++ = *read++; 30 | } 31 | if(lastChar) { 32 | *(lastChar+1) = '\0'; 33 | } 34 | } 35 | 36 | -------------------------------------------------------------------------------- /src/utils.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _utils_h_ 3 | #define _utils_h_ 4 | 5 | //#define BENCHMARK 6 | 7 | #include 8 | 9 | #define REQ_OBJECT_ARG(I, VAR) \ 10 | if (args.Length() <= (I) || !args[I]->IsObject()) \ 11 | return v8::ThrowException(v8::Exception::Error(v8::String::New("Argument " #I " must be an object"))); \ 12 | v8::Local VAR = v8::Local::Cast(args[I]); 13 | 14 | #define REQ_NUMBER_ARG(I, VAR) \ 15 | if (args.Length() <= (I) || !args[I]->IsNumber()) \ 16 | return v8::ThrowException(v8::Exception::Error(v8::String::New("Argument " #I " must be a number"))); \ 17 | v8::Local VAR = v8::Local::Cast(args[I]); 18 | 19 | double getNumberFromV8Object(v8::Local &obj, const char *key, double def); 20 | 21 | void strtrim(char *str); 22 | 23 | #ifdef BENCHMARK 24 | #include 25 | #define BENCHMARK_GLOBAL_DEF() BENCHMARK_DEF(total) 26 | #define BENCHMARK_DEF(NAME) clock_t g_benchmark_##NAME##_start = 0; \ 27 | clock_t g_benchmark_##NAME = 0; \ 28 | int g_benchmark_##NAME##_count = 0; 29 | #define BENCHMARK_DEF_EXTERN(NAME) extern clock_t g_benchmark_##NAME##_start; \ 30 | extern clock_t g_benchmark_##NAME; \ 31 | extern int g_benchmark_##NAME##_count; 32 | #define BENCHMARK_GLOBAL_START() BENCHMARK_START(total) 33 | #define BENCHMARK_GLOBAL_END() BENCHMARK_END(total) 34 | #define BENCHMARK_START(NAME) g_benchmark_##NAME##_start = clock(); 35 | #define BENCHMARK_END(NAME) g_benchmark_##NAME += clock() - g_benchmark_##NAME##_start; \ 36 | g_benchmark_##NAME##_count++; 37 | #define BENCHMARK_PRINT_START() printf("%35s %12s %8s %10s %10s\n", "Name", "Total Time", "Count", "Time per", "Percent"); \ 38 | printf("%35s %12s %8s %10s %10s\n", "---------------------------------", "------------", "--------", "----------", "----------"); 39 | #define BENCHMARK_PRINT_END() BENCHMARK_PRINT(total) \ 40 | printf("\n"); 41 | #define BENCHMARK_PRINT(NAME) printf("%35s -> %12f %8d %10f %9.1f%%\n", #NAME, (float)g_benchmark_##NAME / (float)CLOCKS_PER_SEC, g_benchmark_##NAME##_count, (float)g_benchmark_##NAME / CLOCKS_PER_SEC / (float)g_benchmark_##NAME##_count, (float)g_benchmark_##NAME / (float)g_benchmark_total * 100.0f); 42 | #else 43 | #define BENCHMARK_GLOBAL_DEF() 44 | #define BENCHMARK_DEF(NAME) 45 | #define BENCHMARK_DEF_EXTERN(NAME) 46 | #define BENCHMARK_GLOBAL_START() 47 | #define BENCHMARK_GLOBAL_END() 48 | #define BENCHMARK_START(NAME) 49 | #define BENCHMARK_END(NAME) 50 | #define BENCHMARK_PRINT_START() 51 | #define BENCHMARK_PRINT_END() 52 | #define BENCHMARK_PRINT(NAME) 53 | #endif 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /test_data/ethereal.com.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joeferner/node-shark/88309cad7369781096b552eb36e1cdca2471bb42/test_data/ethereal.com.pcap -------------------------------------------------------------------------------- /test_data/http.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joeferner/node-shark/88309cad7369781096b552eb36e1cdca2471bb42/test_data/http.pcap -------------------------------------------------------------------------------- /test_data/http_gzip.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joeferner/node-shark/88309cad7369781096b552eb36e1cdca2471bb42/test_data/http_gzip.pcap -------------------------------------------------------------------------------- /tests/dissectorTest.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | var nodeunit = require("nodeunit"); 4 | var nodeshark = require("../"); 5 | var util = require('util'); 6 | 7 | exports['DissectorTest'] = nodeunit.testCase({ 8 | "process just a buffer no packet": function(test) { 9 | var dissector = new nodeshark.Dissector(nodeshark.LINK_LAYER_TYPE_ETHERNET); 10 | var buffer = new Buffer([ 11 | 0x58, 0x6d, 0x8f, 0x67, 0x8a, 0x4d, 0x00, 0x1b, 0x21, 0xcf, 0xa1, 0x00, 0x08, 0x00, 0x45, 0x00, 12 | 0x00, 0x3b, 0xd1, 0xb0, 0x40, 0x00, 0x40, 0x11, 0xc5, 0xde, 0x0a, 0x14, 0x08, 0x65, 0xc0, 0xa8, 13 | 0xd0, 0x01, 0xc5, 0x32, 0x00, 0x35, 0x00, 0x27, 0xa3, 0x5b, 0x65, 0x89, 0x01, 0x00, 0x00, 0x01, 14 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x6d, 0x61, 0x69, 0x6c, 0x04, 0x6c, 0x69, 0x76, 0x65, 15 | 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01 16 | ]); 17 | var packet = dissector.dissect(buffer); 18 | //console.log(util.inspect(packet, true, 10)); 19 | test.ok(packet["dns"]["Queries"]["mail.live.com: type A, class IN"]); 20 | test.done(); 21 | }, 22 | 23 | "process dns packet": function(test) { 24 | var dissector = new nodeshark.Dissector(nodeshark.LINK_LAYER_TYPE_ETHERNET); 25 | var buffer = new Buffer([ 26 | 0x58, 0x6d, 0x8f, 0x67, 0x8a, 0x4d, 0x00, 0x1b, 0x21, 0xcf, 0xa1, 0x00, 0x08, 0x00, 0x45, 0x00, 27 | 0x00, 0x3b, 0xd1, 0xb0, 0x40, 0x00, 0x40, 0x11, 0xc5, 0xde, 0x0a, 0x14, 0x08, 0x65, 0xc0, 0xa8, 28 | 0xd0, 0x01, 0xc5, 0x32, 0x00, 0x35, 0x00, 0x27, 0xa3, 0x5b, 0x65, 0x89, 0x01, 0x00, 0x00, 0x01, 29 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x6d, 0x61, 0x69, 0x6c, 0x04, 0x6c, 0x69, 0x76, 0x65, 30 | 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01 31 | ]); 32 | var rawPacket = { 33 | header: { 34 | timestampSeconds: 1325800591, 35 | timestampMicroseconds: 379226000, 36 | capturedLength: buffer.length, 37 | originalLength: buffer.length 38 | }, 39 | data: buffer 40 | }; 41 | var packet = dissector.dissect(rawPacket); 42 | test.ok(packet["dns"]["Queries"]["mail.live.com: type A, class IN"]); 43 | test.equal(packet["frame"]["time"]["value"], "Jan 5, 2012 16:56:31.379226000"); 44 | //console.log(util.inspect(packet, true, 10)); 45 | test.done(); 46 | }, 47 | 48 | "process dns response packet with multiple answers": function(test) { 49 | var dissector = new nodeshark.Dissector(nodeshark.LINK_LAYER_TYPE_ETHERNET); 50 | var buffer = new Buffer([ 51 | 0x00, 0x1b, 0x21, 0xcf, 0xa1, 0x00, 0x58, 0x6d, 0x8f, 0x67, 0x8a, 0x4d, 0x08, 0x00, 0x45, 0x00, 52 | 0x01, 0x38, 0x36, 0xf5, 0x00, 0x00, 0x3f, 0x11, 0xa0, 0x9d, 0xc0, 0xa8, 0xd0, 0x01, 0x0a, 0x14, 53 | 0x08, 0x65, 0x00, 0x35, 0xd1, 0x12, 0x01, 0x24, 0xd6, 0x5b, 0x85, 0x11, 0x81, 0x80, 0x00, 0x01, 54 | 0x00, 0x07, 0x00, 0x04, 0x00, 0x04, 0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 55 | 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 56 | 0x00, 0x09, 0x21, 0x0d, 0x00, 0x08, 0x03, 0x77, 0x77, 0x77, 0x01, 0x6c, 0xc0, 0x10, 0xc0, 0x2c, 57 | 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x2c, 0x00, 0x04, 0x4a, 0x7d, 0x71, 0x6a, 0xc0, 0x2c, 58 | 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x2c, 0x00, 0x04, 0x4a, 0x7d, 0x71, 0x93, 0xc0, 0x2c, 59 | 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x2c, 0x00, 0x04, 0x4a, 0x7d, 0x71, 0x63, 0xc0, 0x2c, 60 | 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x2c, 0x00, 0x04, 0x4a, 0x7d, 0x71, 0x67, 0xc0, 0x2c, 61 | 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x2c, 0x00, 0x04, 0x4a, 0x7d, 0x71, 0x68, 0xc0, 0x2c, 62 | 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x2c, 0x00, 0x04, 0x4a, 0x7d, 0x71, 0x69, 0xc0, 0x10, 63 | 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x45, 0x8b, 0x00, 0x06, 0x03, 0x6e, 0x73, 0x33, 0xc0, 0x10, 64 | 0xc0, 0x10, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x45, 0x8b, 0x00, 0x06, 0x03, 0x6e, 0x73, 0x32, 65 | 0xc0, 0x10, 0xc0, 0x10, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x45, 0x8b, 0x00, 0x06, 0x03, 0x6e, 66 | 0x73, 0x31, 0xc0, 0x10, 0xc0, 0x10, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x45, 0x8b, 0x00, 0x06, 67 | 0x03, 0x6e, 0x73, 0x34, 0xc0, 0x10, 0xc0, 0xc4, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x8b, 0x38, 68 | 0x00, 0x04, 0xd8, 0xef, 0x20, 0x0a, 0xc0, 0xb2, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x8b, 0x38, 69 | 0x00, 0x04, 0xd8, 0xef, 0x22, 0x0a, 0xc0, 0xa0, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x8b, 0x38, 70 | 0x00, 0x04, 0xd8, 0xef, 0x24, 0x0a, 0xc0, 0xd6, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x8b, 0x38, 71 | 0x00, 0x04, 0xd8, 0xef, 0x26, 0x0a 72 | ]); 73 | var rawPacket = { 74 | header: { 75 | timestampSeconds: 1325800591, 76 | timestampMicroseconds: 379226000, 77 | capturedLength: buffer.length, 78 | originalLength: buffer.length 79 | }, 80 | data: buffer 81 | }; 82 | var packet = dissector.dissect(rawPacket); 83 | test.ok(packet["dns"]["Answers"]["www.l.google.com: type A, class IN, addr 74.125.113.103"]); 84 | //console.log(util.inspect(packet, true, 10)); 85 | test.done(); 86 | } 87 | }); 88 | -------------------------------------------------------------------------------- /tests/httpTrackerTest.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | var nodeunit = require("nodeunit"); 4 | var nodeshark = require("../"); 5 | var util = require('util'); 6 | var pcapp = require('pcap-parser'); 7 | 8 | exports['HttpTrackerTest'] = nodeunit.testCase({ 9 | "ethereal.com": function(test) { 10 | var dissector; 11 | 12 | var files = {}; 13 | var tcpTracker = new nodeshark.TcpTracker(); 14 | var httpTracker = new nodeshark.HttpTracker(tcpTracker); 15 | httpTracker.on("requestHeaders", function(http) { 16 | test.ok(http.request.fullUri); 17 | files[http.request.fullUri] = true; 18 | }); 19 | httpTracker.on("requestData", function(http, buffer) { 20 | console.log("requestData --- ", buffer); 21 | test.ok(buffer); 22 | }); 23 | httpTracker.on("responseHeaders", function(http) { 24 | test.ok(http.response.code, 200); 25 | files[http.request.fullUri] = true; 26 | }); 27 | httpTracker.on("responseData", function(http) { 28 | var rawData = http.response.getRawData(); 29 | files[http.request.fullUri] = rawData; 30 | test.ok(rawData); 31 | }); 32 | 33 | var pcapParser = new pcapp.Parser('./test_data/ethereal.com.pcap'); 34 | pcapParser.on('globalHeader', function(globalHeader) { 35 | dissector = new nodeshark.Dissector(globalHeader.linkLayerType); 36 | }); 37 | pcapParser.on('packet', function(rawPacket) { 38 | var packet = dissector.dissect(rawPacket); 39 | tcpTracker.track(packet); 40 | }); 41 | pcapParser.on('end', function() { 42 | test.equal(tcpTracker.sessions[0].packetCount, 30); 43 | test.equal(tcpTracker.sessions[1].packetCount, 35); 44 | test.equal(tcpTracker.sessions[2].packetCount, 15); 45 | 46 | test.ok(files["http://www.ethereal.com/"]); 47 | test.equal(files["http://www.ethereal.com/"].length, 8066); 48 | 49 | test.ok(files["http://www.ethereal.com/mm/css/ethereal-3-0.css"]); 50 | test.equal(files["http://www.ethereal.com/mm/css/ethereal-3-0.css"].length, 4609); 51 | 52 | test.ok(files["http://www.ethereal.com/mm/image/elogo-64-trans.gif"]); 53 | 54 | test.ok(files["http://www.ethereal.com/mm/image/go-button.gif"]); 55 | 56 | test.ok(files["http://pagead2.googlesyndication.com/pagead/show_ads.js"]); 57 | test.equal(files["http://pagead2.googlesyndication.com/pagead/show_ads.js"].length, 8020); 58 | 59 | test.ok(files["http://www.ethereal.com/mm/image/NISlogo75.gif"]); 60 | 61 | test.ok(files["http://www.ethereal.com/mm/image/front-wind.png"]); 62 | 63 | test.ok(files["http://pagead2.googlesyndication.com/pagead/ads?client=ca-pub-2309191948673629&dt=1099056744465&lmt=1098371814&format=120x600_as&output=html&url=http%3A%2F%2Fwww.ethereal.com%2F&color_bg=FFFFFF&color_text=333333&color_link=000000&color_url=666633&color_border=666633&u_h=768&u_w=1024&u_ah=738&u_aw=1024&u_cd=32&u_tz=-240&u_his=3&u_java=true&u_nplug=14&u_nmime=49"]); 64 | 65 | test.ok(files["http://www.ethereal.com/favicon.ico"]); 66 | 67 | test.done(); 68 | }); 69 | 70 | pcapParser.parse(); 71 | } 72 | }); 73 | -------------------------------------------------------------------------------- /tests/tcpTrackerTest.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | var nodeunit = require("nodeunit"); 4 | var nodeshark = require("../"); 5 | var util = require('util'); 6 | var pcapp = require('pcap-parser'); 7 | 8 | exports['TcpTrackerTest'] = nodeunit.testCase({ 9 | "ethereal.com": function(test) { 10 | var dissector; 11 | 12 | var tcpTracker = new nodeshark.TcpTracker(); 13 | tcpTracker.on('start', function(session) { 14 | //console.log("start", session); 15 | }); 16 | tcpTracker.on('packet', function(session, packet) { 17 | //console.log("packet", session); 18 | }); 19 | tcpTracker.on('end', function(session) { 20 | //console.log("end", session); 21 | }); 22 | 23 | var pcapParser = new pcapp.Parser('./test_data/ethereal.com.pcap'); 24 | pcapParser.on('globalHeader', function(globalHeader) { 25 | dissector = new nodeshark.Dissector(globalHeader.linkLayerType); 26 | }); 27 | pcapParser.on('packet', function(rawPacket) { 28 | var packet = dissector.dissect(rawPacket); 29 | tcpTracker.track(packet); 30 | }); 31 | pcapParser.on('end', function() { 32 | test.equal(tcpTracker.sessions[0].packetCount, 30); 33 | test.equal(tcpTracker.sessions[1].packetCount, 35); 34 | test.equal(tcpTracker.sessions[2].packetCount, 15); 35 | test.done(); 36 | }); 37 | 38 | pcapParser.parse(); 39 | } 40 | }); 41 | --------------------------------------------------------------------------------