Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ This structure is easy to explore with `sys.inspect`.
TCP can be analyzed by feeding the packets into a `TCPTracker` and then listening for `session` and `end` events.

```javascript
var pcap = require('./pcap'),
var pcap = require('pcap'),
tcp_tracker = new pcap.TCPTracker(),
pcap_session = pcap.createSession('en0', "ip proto \\tcp");

Expand All @@ -129,6 +129,16 @@ see the wonderful things it can do for you. Hopefully the names of the properti

See [http_trace](https://github.com/mranney/http_trace) for an example of how to use these events to decode HTTP (Works only on node 4).

### Logging

By default, all logging goes to `console`. All exposed methods support an optional `setLogger` function that takes in
a logging component (such as [bunyan](https://www.npmjs.com/package/bunyan) or [winston](https://www.npmjs.com/package/winston))
to direct logging into your application's preferred style.

If you'd like to disable logging altogether, simple pass `false` into the `setLogger` function.

Note: If you use the `pcap.decode` mechanism, your logger must be passed as an optional 3rd argument.

## Some Common Problems

### TCP Segmentation Offload - TSO
Expand Down
5 changes: 3 additions & 2 deletions decode/ethernet_packet.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ var IPv6 = require("./ipv6");
var Arp = require("./arp");
var Vlan = require("./vlan");

function EthernetPacket(emitter) {
function EthernetPacket(emitter, logger) {
this.emitter = emitter;
this.logger = logger;
this.dhost = null;
this.shost = null;
this.ethertype = null;
Expand Down Expand Up @@ -49,7 +50,7 @@ EthernetPacket.prototype.decode = function (raw_packet, offset) {
this.payload = "need to implement LLDP";
break;
default:
console.log("node_pcap: EthernetFrame() - Don't know how to decode ethertype " + this.ethertype);
this.logger.log("node_pcap: EthernetFrame() - Don't know how to decode ethertype " + this.ethertype);
}
}

Expand Down
5 changes: 3 additions & 2 deletions decode/ieee802.11/radio_packet.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,9 @@ PresentFieldFlags.prototype.decode = function decode (flags) {
return this;
};

function RadioPacket(emitter) {
function RadioPacket(emitter, logger) {
this.emitter = emitter;
this.logger = logger;
this.headerRevision = undefined;
this.headerPad = undefined;
this.headerLength = undefined;
Expand Down Expand Up @@ -95,7 +96,7 @@ RadioPacket.prototype.decode = function (raw_packet, offset) {
if(p.txAttenuation) { offset++; }
if(p.dbTxAttenuation) { offset += 2; }
if(p.dbmTxPower) { offset++; }
if(p.antenna) {
if(p.antenna) {
this.antenna = raw_packet[offset++];
}
if(p.dbAntennaSignal) { offset++; }
Expand Down
7 changes: 5 additions & 2 deletions decode/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@ exports.ArpPacket = require("./arp");
exports.PcapPacket = require("./pcap_packet");
var PcapPacket = exports.PcapPacket;

function decode(packet, emitter) {
return new PcapPacket(emitter).decode(packet);
function decode(packet, emitter, logger) {
if (typeof logger === "undefined") {
logger = console;
}
return new PcapPacket(emitter, logger).decode(packet);
}

exports.decode = decode;
Expand Down
7 changes: 4 additions & 3 deletions decode/ipv4.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,9 @@ IPFlags.prototype.toString = function () {
return ret;
};

function IPv4(emitter) {
this.emitter = emitter;
function IPv4(emitter, logger) {
this.emitter = emitter;
this.logger = logger;
this.version = undefined;
this.headerLength = undefined;
this.diffserv = undefined;
Expand Down Expand Up @@ -116,7 +117,7 @@ IPv4.prototype.toString = function () {
} else {
ret += this.payload.constructor.name;
}


return ret + " " + this.payload;
};
Expand Down
3 changes: 2 additions & 1 deletion decode/null_packet.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
var IPv4 = require("./ipv4");
var IPv6 = require("./ipv6");

function NullPacket(emitter) {
function NullPacket(emitter, logger) {
this.emitter = emitter;
this.logger = logger;
this.pftype = undefined;
this.payload = undefined;
this._error = undefined;
Expand Down
19 changes: 12 additions & 7 deletions decode/pcap_packet.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ var NullPacket = require("./null_packet");
var Ipv4 = require("./ipv4");
var RadioPacket = require("./ieee802.11/radio_packet");
var SLLPacket = require("./sll_packet");
var setLogger = require("../set_logger");

// Setting properties from the C++ side is very slow, so we send in a shared Buffer.
// The C++ side does this:
Expand All @@ -19,13 +20,17 @@ function PcapHeader(raw_header) {
this.len = raw_header.readUInt32LE(12, true);
}

function PcapPacket(emitter) {
function PcapPacket(emitter, logger) {
this.link_type = null;
this.pcap_header = null;
this.payload = null;
this.emitter = emitter;
this.logger = console;
this.setLogger(logger);
}

PcapPacket.prototype.setLogger = setLogger;

PcapPacket.prototype.decode = function (packet_with_header) {
this.link_type = packet_with_header.link_type;
this.pcap_header = new PcapHeader(packet_with_header.header);
Expand All @@ -34,22 +39,22 @@ PcapPacket.prototype.decode = function (packet_with_header) {

switch (this.link_type) {
case "LINKTYPE_ETHERNET":
this.payload = new EthernetPacket(this.emitter).decode(buf, 0);
this.payload = new EthernetPacket(this.emitter, this.logger).decode(buf, 0);
break;
case "LINKTYPE_NULL":
this.payload = new NullPacket(this.emitter).decode(buf, 0);
this.payload = new NullPacket(this.emitter, this.logger).decode(buf, 0);
break;
case "LINKTYPE_RAW":
this.payload = new Ipv4(this.emitter).decode(buf, 0);
this.payload = new Ipv4(this.emitter, this.logger).decode(buf, 0);
break;
case "LINKTYPE_IEEE802_11_RADIO":
this.payload = new RadioPacket(this.emitter).decode(buf, 0);
this.payload = new RadioPacket(this.emitter, this.logger).decode(buf, 0);
break;
case "LINKTYPE_LINUX_SLL":
this.payload = new SLLPacket(this.emitter).decode(buf, 0);
this.payload = new SLLPacket(this.emitter, this.logger).decode(buf, 0);
break;
default:
console.log("node_pcap: PcapPacket.decode - Don't yet know how to decode link type " + this.link_type);
this.logger.log("node_pcap: PcapPacket.decode - Don't yet know how to decode link type " + this.link_type);
}

return this;
Expand Down
5 changes: 3 additions & 2 deletions decode/sll_packet.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ var IPv4 = require("./ipv4");
var IPv6 = require("./ipv6");
var Arp = require("./arp");

function SLLPacket (emitter) {
function SLLPacket (emitter, logger) {
this.emitter = emitter;
this.logger = logger;
this.packet_type = null;
this.address_type = null;
this.address_len = null;
Expand Down Expand Up @@ -47,7 +48,7 @@ SLLPacket.prototype.decode = function (raw_packet, offset) {
this.payload = "need to implement LLDP";
break;
default:
console.log("node_pcap: SLLPacket() - Don't know how to decode ethertype " + this.ethertype);
this.logger.log("node_pcap: SLLPacket() - Don't know how to decode ethertype " + this.ethertype);
}
}

Expand Down
12 changes: 7 additions & 5 deletions decode/tcp.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

function TCPFlags(emitter) {
this.emitter = emitter;
function TCPFlags(logger) {
this.logger = logger;
this.nonce = undefined;
this.cwr = undefined;
this.ece = undefined;
Expand Down Expand Up @@ -57,7 +57,8 @@ TCPFlags.prototype.toString = function () {
return ret;
};

function TCPOptions() {
function TCPOptions(logger) {
this.logger = logger;
this.mss = null;
this.window_scale = null;
this.sack_ok = null;
Expand Down Expand Up @@ -128,7 +129,7 @@ TCPOptions.prototype.decode = function (raw_packet, offset, len) {
offset += 8;
break;
default:
console.log("Invalid TCP SACK option length " + raw_packet[offset + 1]);
this.logger.log("Invalid TCP SACK option length " + raw_packet[offset + 1]);
offset = end_offset;
}
break;
Expand Down Expand Up @@ -178,6 +179,7 @@ TCPOptions.prototype.toString = function () {

function TCP(emitter) {
this.emitter = emitter;
this.logger = console;
this.sport = undefined;
this.dport = undefined;
this.seqno = undefined;
Expand Down Expand Up @@ -216,7 +218,7 @@ TCP.prototype.decode = function (raw_packet, offset, len) {
// of the header.
this.headerLength = (raw_packet[offset] & 0xf0) >> 2;

this.flags = new TCPFlags().decode(raw_packet[offset], raw_packet[offset+1]);
this.flags = new TCPFlags(this.logger).decode(raw_packet[offset], raw_packet[offset+1]);
offset += 2;
this.windowSize = raw_packet.readUInt16BE(offset, true); // 14, 15
offset += 2;
Expand Down
4 changes: 4 additions & 0 deletions pcap.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ var SocketWatcher = require("socketwatcher").SocketWatcher;
var decode = require("./decode").decode;
var tcp_tracker = require("./tcp_tracker");
var DNSCache = require("./dns_cache");
var setLogger = require("./set_logger");
var timers = require("timers");

exports.decode = decode;
Expand All @@ -13,6 +14,7 @@ exports.TCPSession = tcp_tracker.TCPSession;
exports.DNSCache = DNSCache;

function PcapSession(is_live, device_name, filter, buffer_size, outfile, is_monitor) {
this.logger = console;
this.is_live = is_live;
this.device_name = device_name;
this.filter = filter || "";
Expand Down Expand Up @@ -94,6 +96,8 @@ function PacketWithHeader(buf, header, link_type) {
this.link_type = link_type;
}

PcapSession.prototype.setLogger = setLogger;

PcapSession.prototype.on_packet_ready = function () {
var full_packet = new PacketWithHeader(this.buf, this.header, this.link_type);
this.emit("packet", full_packet);
Expand Down
18 changes: 18 additions & 0 deletions set_logger.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
function setLogger(logger) {
if (typeof logger === "undefined") {
this.logger = console;
} else if (logger !== false) {
this.logger = logger;
} else {
this.logger = {
log: function() { },
info: function() { },
warn: function() { },
error: function() { },
trace: function() { }
};
}

}

module.exports = setLogger;
24 changes: 24 additions & 0 deletions spec/set_logger.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
var set_logger = require("../set_logger");
require("should");

describe("set_logger", function(){
beforeEach(function () {
this.instance = {};
this.instance.logger = undefined;
this.instance.setLogger = set_logger;
});

it("attaches console by default", function(){
this.instance.setLogger();
this.instance.logger.should.be.an.instanceOf(Object).and.have.property("Console");
});
it("attaches a stubbed console on false", function(){
this.instance.setLogger(false);
this.instance.logger.should.be.an.instanceOf(Object).and.not.have.property("Console");
});
it("attaches whatever else is passed in, if defined and not false", function(){
// Demonstrates that we don't prevent the user from sending whatever they want to Logger
this.instance.setLogger("b");
this.instance.logger.should.equal("b");
});
});
19 changes: 13 additions & 6 deletions tcp_tracker.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@ var EventEmitter = require("events").EventEmitter;
var inherits = require("util").inherits;
var IPv4 = require("./decode/ipv4");
var TCP = require("./decode/tcp");
var setLogger = require("./set_logger");

function TCPTracker() {
this.logger = console;
this.sessions = {};
EventEmitter.call(this);
}
inherits(TCPTracker, EventEmitter);

TCPTracker.prototype.setLogger = setLogger;

TCPTracker.prototype.track_packet = function (packet) {
var ip, tcp, src, dst, key, session;

Expand All @@ -28,7 +32,7 @@ TCPTracker.prototype.track_packet = function (packet) {
session = this.sessions[key];
if (! session) {
is_new = true;
session = new TCPSession();
session = new TCPSession(this.logger);
this.sessions[key] = session;
}

Expand All @@ -44,7 +48,8 @@ TCPTracker.prototype.track_packet = function (packet) {
// user should filter these out with their pcap filter, but oh well.
};

function TCPSession() {
function TCPSession(logger) {
this.logger = (typeof logger === "undefined") ? console : logger;
this.src = null;
this.src_name = null; // from DNS
this.dst = null;
Expand Down Expand Up @@ -83,6 +88,8 @@ function TCPSession() {
}
inherits(TCPSession, EventEmitter);

TCPSession.prototype.setLogger = setLogger;

TCPSession.prototype.track = function (packet) {
var ip = packet.payload.payload;
var tcp = ip.payload;
Expand Down Expand Up @@ -135,7 +142,7 @@ TCPSession.prototype.SYN_SENT = function (packet) {
this.state = "CLOSED";
this.emit("reset", this, "recv"); // TODO - check which direction did the reset, probably recv
// } else {
// console.log("Didn't get SYN-ACK packet from dst while handshaking: " + util.inspect(tcp, false, 4));
// this.logger.log("Didn't get SYN-ACK packet from dst while handshaking: " + util.inspect(tcp, false, 4));
}
};

Expand All @@ -152,7 +159,7 @@ TCPSession.prototype.SYN_RCVD = function (packet) {
this.emit("start", this);
this.state = "ESTAB";
// } else {
// console.log("Didn't get ACK packet from src while handshaking: " + util.inspect(tcp, false, 4));
// this.logger.log("Didn't get ACK packet from src while handshaking: " + util.inspect(tcp, false, 4));
}
};

Expand Down Expand Up @@ -188,7 +195,7 @@ TCPSession.prototype.ESTAB = function (packet) {
if (this.recv_packets[tcp.ackno]) {
this.send_acks[tcp.ackno] = this.current_cap_time;
}
// console.log("sending ACK for packet we didn't see received: " + tcp.ackno);
// this.logger.log("sending ACK for packet we didn't see received: " + tcp.ackno);
if (tcp.flags.fin) {
this.state = "FIN_WAIT";
}
Expand Down Expand Up @@ -216,7 +223,7 @@ TCPSession.prototype.ESTAB = function (packet) {
this.state = "CLOSE_WAIT";
}
} else {
console.log("non-matching packet in session: " + packet);
this.logger.log("non-matching packet in session: " + packet);
}
};

Expand Down