Socket
Socket
Sign inDemoInstall

pcap

Package Overview
Dependencies
Maintainers
2
Versions
36
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

pcap - npm Package Compare versions

Comparing version 2.0.1 to 2.1.0

.travis.yml

29

decode/arp.js
var EthernetAddr = require("./ethernet_addr");
var IPv4Addr = require("./ipv4_addr");
function Arp() {
this.htype = null;
this.ptype = null;
this.heln = null;
this.plen = null;
this.operation = null;
this.sender_ha = null;
this.sender_pa = null;
this.target_ha = null;
this.target_pa = null;
function Arp(emitter) {
this.emitter = emitter;
this.htype = undefined;
this.ptype = undefined;
this.hlen = undefined;
this.plen = undefined;
this.operation = undefined;
this.sender_ha = undefined;
this.sender_pa = undefined;
this.target_ha = undefined;
this.target_pa = undefined;
}

@@ -25,11 +26,15 @@

this.sender_ha = new EthernetAddr(raw_packet, offset + 8); // 8, 9, 10, 11, 12, 13
this.sender_pa = new IPv4Addr(raw_packet, offset + 14); // 14, 15, 16, 17
this.sender_pa = new IPv4Addr().decode(raw_packet, offset + 14); // 14, 15, 16, 17
this.target_ha = new EthernetAddr(raw_packet, offset + 18); // 18, 19, 20, 21, 22, 23
this.target_pa = new IPv4Addr(raw_packet, offset + 24); // 24, 25, 26, 27
this.target_pa = new IPv4Addr().decode(raw_packet, offset + 24); // 24, 25, 26, 27
}
// don't know how to decode more exotic ARP types yet, but please add them
if(this.emitter) { this.emitter.emit("arp", this); }
return this;
};
Arp.prototype.decoderName = "arp";
Arp.prototype.eventsOnDecode = true;
Arp.prototype.toString = function () {

@@ -36,0 +41,0 @@ var ret = "";

var IPv4Addr = require("./ipv4_addr");
var IPv6Addr = require("./ipv6_addr");
function DNSHeader(raw_packet, offset) {
this.id = raw_packet.readUInt16BE(offset); // 0, 1
this.qr = (raw_packet[offset + 2] & 128) >> 7;
this.opcode = (raw_packet[offset + 2] & 120) >> 3;
this.aa = (raw_packet[offset + 2] & 4) >> 2;
this.tc = (raw_packet[offset + 2] & 2) >> 1;
this.rd = raw_packet[offset + 2] & 1;
this.ra = (raw_packet[offset + 3] & 128) >> 7;
this.z = 0; // spec says this MUST always be 0
this.rcode = raw_packet[offset + 3] & 15;
this.qdcount = raw_packet.readUInt16BE(offset + 4); // 4, 5
this.ancount = raw_packet.readUInt16BE(offset + 6); // 6, 7
this.nscount = raw_packet.readUInt16BE(offset + 8); // 8, 9
this.arcount = raw_packet.readUInt16BE(offset + 10); // 10, 11
function DnsFlags() {
// is this a response?
this.isResponse = undefined;
// 0 == Query
// 1 == Inverse query
// 2 == Status
// 3-15 Reserved for future use
this.opcode = undefined;
// is the server the authority for the domain?
this.isAuthority = undefined;
// is this message truncated?
this.isTruncated = undefined;
// should name server recursively
// resolve domain?
this.isRecursionDesired = undefined;
// Can the server even do recursion?
this.isRecursionAvailible = undefined;
// Reserved for future use, unless the present is the future
// then assume the past is the present and the present is the
// past...or just update to support whatever this became.
//
// currently "should" always be zero.
this.z = undefined;
// 0 == no error
// 1 == format error (query could not be interpeted)
// 2 == server error
// 3 == name error (domain requested by query does not exist)
// 4 == unsupported request
// 5 == refused
// a 4bit reply status code
this.responseCode = undefined;
}
DNSHeader.prototype.toString = function () {
return "{" +
" id:" + this.id +
" qr:" + this.qr +
" op:" + this.opcode +
" aa:" + this.aa +
" tc:" + this.tc +
" rd:" + this.rd +
" ra:" + this.ra +
" rc:" + this.rcode +
" qd:" + this.qdcount +
" an:" + this.ancount +
" ns:" + this.nscount +
" ar:" + this.arcount +
DnsFlags.prototype.decode = function (raw_packet, offset) {
var byte1 = raw_packet[offset];
var byte2 = raw_packet[offset + 1];
this.isResponse = Boolean(byte1 & 0x80);
this.opcode = (byte1 & 0x78) >> 3;
this.isAuthority = Boolean(byte1 & 0x04);
this.isTruncated = Boolean(byte1 & 0x02);
this.isRecursionDesired = Boolean(byte1 & 0x01);
this.isRecursionAvailible = Boolean(byte2 & 0x80);
this.z = byte2 & 0x70 >> 4;
this.responseCode = byte2 & 0x0F;
return this;
};
DnsFlags.prototype.toString = function () {
return "{ isResponse:" + this.isResponse +
" opcode:" + this.opcode +
" isAuthority:" + this.isAuthority +
" isTruncated:" + this.isTruncated +
" isRecursionDesired:" + this.isRecursionDesired +
" isRecursionAvailible:" + this.isRecursionAvailible +
" z:" + this.z +
" responseCode:" + this.responseCode +
" }";
};
function DNS() {
this.header = null;
this.question = null;
this.answer = null;
this.authority = null;
this.additional = null;
// not part of DNS, but handy so we don't have to pass these around all over the place
this.raw_packet = null;
this.offset = null;
this.packet_start = null;
this.packet_len = null;
function DNS(emitter) {
this.emitter = emitter;
this.header = undefined;
this.question = undefined;
this.answer = undefined;
this.authority = undefined;
this.additional = undefined;
this._error = undefined;
}

@@ -59,17 +90,25 @@

DNS.prototype.decoderName = "dns";
DNS.prototype.eventsOnDecode = true;
// http://tools.ietf.org/html/rfc1035
DNS.prototype.decode = function (raw_packet, offset, caplen) {
DNS.prototype.decode = function (raw_packet, offset) {
//these 2 fields will be deleted soon.
this.raw_packet = raw_packet;
this.packet_start = offset;
this.offset = offset;
this.packet_len = caplen;
this.header = new DNSHeader(raw_packet, this.offset);
this.id = raw_packet.readUInt16BE(offset); // 0, 1
this.header = new DnsFlags().decode(raw_packet.readUInt16BE(this.offset+2));
this.qdcount = raw_packet.readUInt16BE(offset + 4); // 4, 5
this.ancount = raw_packet.readUInt16BE(offset + 6); // 6, 7
this.nscount = raw_packet.readUInt16BE(offset + 8); // 8, 9
this.arcount = raw_packet.readUInt16BE(offset + 10); // 10, 11
this.offset += 12;
this.question = this.decode_RRs(this.header.qdcount, true);
this.answer = this.decode_RRs(this.header.ancount, false);
this.authority = this.decode_RRs(this.header.nscount, false);
this.additional = this.decode_RRs(this.header.arcount, false);
this.question = this.decode_RRs(this.qdcount, true);
this.answer = this.decode_RRs(this.ancount, false);
this.authority = this.decode_RRs(this.nscount, false);
this.additional = this.decode_RRs(this.arcount, false);
if(this.emitter) { this.emitter.emit("dns", this); }
return this;

@@ -80,3 +119,4 @@ };

if (count > 100) {
throw new Error("Malformed DNS packet: too many RRs at offset " + this.offset);
this._error = "Malformed DNS packet: too many RRs at offset " + this.offset;
return;
}

@@ -136,4 +176,4 @@

pos++;
for (var i = pos; i < (pos + len_or_ptr) && i < this.packet_len ; i++) {
if (i > this.packet_len) {
for (var i = pos; i < (pos + len_or_ptr) && i < this.raw_packet.length; i++) {
if (i > this.raw_packet.length) {
throw new Error("invalid DNS RR: read beyond end of packet at offset " + i);

@@ -160,4 +200,4 @@ }

DNS.prototype.decode_RR = function (is_question) {
if (this.offset > this.packet_len) {
throw new Error("Malformed DNS RR. Offset is beyond packet len (decode_RR) :" + this.offset + " packet_len:" + this.packet_len);
if (this.offset > this.raw_packet.length) {
throw new Error("Malformed DNS RR. Offset is beyond packet len (decode_RR) :" + this.offset + " packet_len:" + this.raw_packet.length);
}

@@ -183,3 +223,3 @@

if (rr.type === 1 && rr.class === 1 && rr.rdlength) { // A, IN
rr.rdata = new IPv4Addr(this.raw_packet, this.offset);
rr.rdata = new IPv4Addr().decode(this.raw_packet, this.offset);
} else if (rr.type === 2 && rr.class === 1) { // NS, IN

@@ -202,12 +242,12 @@ rr.rdata = this.read_name();

ret += this.header.toString();
if (this.header.qdcount > 0) {
if (this.qdcount > 0) {
ret += "\n question:" + this.question.rrs[0];
}
if (this.header.ancount > 0) {
if (this.ancount > 0) {
ret += "\n answer:" + this.answer;
}
if (this.header.nscount > 0) {
if (this.nscount > 0) {
ret += "\n authority:" + this.authority;
}
if (this.header.arcount > 0) {
if (this.arcount > 0) {
ret += "\n additional:" + this.additional;

@@ -214,0 +254,0 @@ }

var util = require("../util");
//Also known as MAC address
function EthernetAddr(raw_packet, offset) {

@@ -13,3 +14,3 @@ this.addr = new Array(6);

EthernetAddr.prototype.toString = function () {
EthernetAddr.prototype.toString = function toString() {
return util.int8_to_hex[this.addr[0]] + ":" +

@@ -16,0 +17,0 @@ util.int8_to_hex[this.addr[1]] + ":" +

@@ -7,3 +7,4 @@ var EthernetAddr = require("./ethernet_addr");

function EthernetPacket() {
function EthernetPacket(emitter) {
this.emitter = emitter;
this.dhost = null;

@@ -40,9 +41,9 @@ this.shost = null;

case 0x800: // IPv4
this.payload = new IPv4().decode(raw_packet, offset);
this.payload = new IPv4(this.emitter).decode(raw_packet, offset);
break;
case 0x806: // ARP
this.payload = new Arp().decode(raw_packet, offset);
this.payload = new Arp(this.emitter).decode(raw_packet, offset);
break;
case 0x86dd: // IPv6 - http://en.wikipedia.org/wiki/IPv6
this.payload = new IPv6().decode(raw_packet, offset);
this.payload = new IPv6(this.emitter).decode(raw_packet, offset);
break;

@@ -60,2 +61,5 @@ case 0x88cc: // LLDP - http://en.wikipedia.org/wiki/Link_Layer_Discovery_Protocol

EthernetPacket.prototype.decoderName = "ethernet-packet";
EthernetPacket.prototype.eventsOnDecode = false;
EthernetPacket.prototype.toString = function () {

@@ -62,0 +66,0 @@ var ret = this.shost + " -> " + this.dhost;

@@ -1,7 +0,6 @@

function ICMP() {
this.type = null;
this.code = null;
this.checksum = null;
this.id = null;
this.sequence = null;
function ICMP(emitter) {
this.emitter = emitter;
this.type = undefined;
this.code = undefined;
this.checksum = undefined;
}

@@ -11,11 +10,13 @@

ICMP.prototype.decode = function (raw_packet, offset) {
this.type = raw_packet[offset];
this.code = raw_packet[offset + 1];
this.checksum = raw_packet.readUInt16BE(offset + 2); // 2, 3
this.id = raw_packet.readUInt16BE(offset + 4); // 4, 5
this.sequence = raw_packet.readUInt16BE(offset + 6); // 6, 7
this.type = raw_packet[offset++];
this.code = raw_packet[offset++];
this.checksum = raw_packet.readUInt16BE(offset); // 2, 3
if(this.emitter) { this.emitter.emit("icmp", this); }
return this;
};
ICMP.prototype.decoderName = "icmp";
ICMP.prototype.eventsOnDecode = true;
ICMP.prototype.toString = function () {

@@ -28,6 +29,2 @@ var ret = "";

break;
case 1:
case 2:
ret += "Reserved";
break;
case 3: // destination unreachable

@@ -85,3 +82,3 @@ switch (this.code) {

case 5: // redirect
switch (ret.code) {
switch (this.code) {
case 0:

@@ -100,3 +97,3 @@ ret += "Redirect Network";

default:
ret += "Redirect (unknown code " + ret.code + ")";
ret += "Redirect (unknown code " + this.code + ")";
break;

@@ -103,0 +100,0 @@ }

@@ -1,21 +0,32 @@

function IGMP() {
this.type = null;
this.version = null;
this.max_response_time = null;
this.checksum = null;
this.group_address = null;
var IPv4Addr = require("./ipv4_addr");
function IGMP(emitter) {
this.emitter = emitter;
this.type = undefined;
this.version = undefined;
this.maxResponseTime = undefined;
this.checksum = undefined;
this.groupAddress = undefined;
}
var IPV4Addr = require("./ipv4_addr");
// http://en.wikipedia.org/wiki/Internet_Group_Management_Protocol
// This is an implementation of V3
// https://tools.ietf.org/html/rfc3376
IGMP.prototype.decode = function (raw_packet, offset) {
this.type = raw_packet[offset];
this.max_response_time = raw_packet[offset + 1];
// units are 1/10s
// if value < 128 this is an int, else it is a float
// right now we don't handle the float version
this.maxResponseTime =raw_packet[offset + 1];
this.checksum = raw_packet.readUInt16BE(offset + 2); // 2, 3
this.group_address = new IPV4Addr(raw_packet, offset + 4); // 4, 5, 6, 7
this.groupAddress = new IPv4Addr().decode(raw_packet, offset + 4); // 4, 5, 6, 7
//Membership Query (0x11)
//Membership Report (IGMPv1: 0x12, IGMPv2: 0x16, IGMPv3: 0x22)
//Leave Group (0x17)
switch (this.type) {
case 0x11:
this.version = this.max_response_time > 0 ? 2 : 1;
this.version = 3;
break;

@@ -26,4 +37,2 @@ case 0x12:

case 0x16:
this.version = 2;
break;
case 0x17:

@@ -35,9 +44,11 @@ this.version = 2;

break;
default:
break;
}
if(this.emitter) { this.emitter.emit("igmp", this); }
return this;
};
IGMP.prototype.decoderName = "igmp";
IGMP.prototype.eventsOnDecode = true;
IGMP.prototype.toString = function () {

@@ -44,0 +55,0 @@ var ret;

@@ -10,4 +10,4 @@ // convert binary capture data into objects with friendly names

function decode(packet) {
return new PcapPacket().decode(packet);
function decode(packet, emitter) {
return new PcapPacket(emitter).decode(packet);
}

@@ -14,0 +14,0 @@

@@ -1,15 +0,23 @@

var map = require("../util").int8_to_dec;
var dec = require("../util").int8_to_dec;
function IPv4Addr(raw_packet, offset) {
this.o1 = raw_packet[offset];
this.o2 = raw_packet[offset + 1];
this.o3 = raw_packet[offset + 2];
this.o4 = raw_packet[offset + 3];
function IPv4Addr() {
this.addr = new Array(4);
}
IPv4Addr.prototype.decode = function decode(raw_packet, offset) {
this.addr[0] = raw_packet[offset];
this.addr[1] = raw_packet[offset + 1];
this.addr[2] = raw_packet[offset + 2];
this.addr[3] = raw_packet[offset + 3];
return this;
};
IPv4Addr.prototype.decoderName = "ipv4-addr";
IPv4Addr.prototype.eventsOnDecode = false;
// Don't use Array.prototype.join here, because string concat is much faster
IPv4Addr.prototype.toString = function () {
return map[this.o1] + "." + map[this.o2] + "." + map[this.o3] + "." + map[this.o4];
return dec[this.addr[0]] + "." + dec[this.addr[1]] + "." + dec[this.addr[2]] + "." + dec[this.addr[3]];
};
module.exports = IPv4Addr;

@@ -1,14 +0,19 @@

var ICMP = require("./icmp");
var IGMP = require("./igmp");
var TCP = require("./tcp");
var UDP = require("./udp");
var IPv6 = require("./ipv6");
var IPv4Addr = require("./ipv4_addr");
var protocols = require("./ip_protocols");
function IPFlags() {
this.reserved = null;
this.df = null;
this.mf = null;
function IPFlags(emitter) {
this.emitter = emitter;
this.reserved = undefined;
this.doNotFragment = undefined;
this.moreFragments = undefined;
}
IPFlags.prototype.decode = function (raw_flags) {
this.reserved = Boolean((raw_flags & 0x80) >> 7);
this.doNotFragment = Boolean((raw_flags & 0x40) > 0);
this.moreFragments = Boolean((raw_flags & 0x20) > 0);
return this;
};
IPFlags.prototype.toString = function () {

@@ -19,6 +24,6 @@ var ret = "[";

}
if (this.df) {
if (this.doNotFragment) {
ret += "d";
}
if (this.mf) {
if (this.moreFragments) {
ret += "m";

@@ -30,18 +35,18 @@ }

function IPv4() {
this.version = null;
this.header_length = null;
this.header_bytes = null; // not part of packet, but handy
this.diffserv = null;
this.total_length = null;
this.identification = null;
this.flags = new IPFlags();
this.fragment_offset = null;
this.ttl = null;
this.protocol = null;
this.header_checksum = null;
this.saddr = null;
this.daddr = null;
this.protocol_name = null;
this.payload = null;
function IPv4(emitter) {
this.emitter = emitter;
this.version = undefined;
this.headerLength = undefined;
this.diffserv = undefined;
this.length = undefined;
this.identification = undefined;
this.flags = undefined;
this.fragmentOffset = undefined;
this.ttl = undefined;
this.protocol = undefined;
this.headerChecksum = undefined;
this.saddr = undefined;
this.daddr = undefined;
this.protocolName = undefined;
this.payload = undefined;
}

@@ -53,26 +58,33 @@

this.version = (raw_packet[offset] & 240) >> 4; // first 4 bits
this.header_length = raw_packet[offset] & 15; // second 4 bits
this.header_bytes = this.header_length * 4;
this.version = (raw_packet[offset] & 0xf0) >> 4;
this.headerLength = (raw_packet[offset] & 0x0f) << 2;
offset += 1;
this.diffserv = raw_packet[offset];
offset += 1;
this.total_length = raw_packet.readUInt16BE(offset, true);
this.length = raw_packet.readUInt16BE(offset, true);
offset += 2;
this.identification = raw_packet.readUInt16BE(offset, true);
offset += 2;
this.flags.reserved = (raw_packet[offset] & 128) >> 7;
this.flags.df = (raw_packet[offset] & 64) >> 6;
this.flags.mf = (raw_packet[offset] & 32) >> 5;
this.fragment_offset = ((raw_packet[offset] & 31) * 256) + raw_packet[offset + 1]; // 13-bits from 6, 7
this.flags = new IPFlags().decode(raw_packet[offset]);
// flags only uses the top 3 bits of offset so don't advance yet
this.fragmentOffset = ((raw_packet.readUInt16BE(offset) & 0x1fff) << 3); // 13-bits from 6, 7
offset += 2;
this.ttl = raw_packet[offset];
offset += 1;
this.protocol = raw_packet[offset];
offset += 1;
this.header_checksum = raw_packet.readUInt16BE(offset, true);
this.headerChecksum = raw_packet.readUInt16BE(offset, true);
offset += 2;
this.saddr = new IPv4Addr(raw_packet, offset);
this.saddr = new IPv4Addr(this.emitter).decode(raw_packet, offset);
offset += 4;
this.daddr = new IPv4Addr(raw_packet, offset);
this.daddr = new IPv4Addr(this.emitter).decode(raw_packet, offset);
offset += 4;

@@ -82,60 +94,31 @@

offset = orig_offset + (this.header_length * 4);
offset = orig_offset + this.headerLength;
switch (this.protocol) {
case 1:
this.payload = new ICMP();
this.payload.decode(raw_packet, offset);
break;
case 2:
this.payload = new IGMP().decode(raw_packet, offset);
break;
case 4:
this.payload = new IPv4().decode(raw_packet, offset);
break;
case 6:
this.payload = new TCP().decode(raw_packet, offset, this.total_length - this.header_bytes);
break;
case 17:
this.payload = new UDP().decode(raw_packet, offset);
break;
case 41:
this.payload = new IPv6().decode(raw_packet, offset);
break;
default:
this.protocol_name = "Unknown";
var ProtocolDecoder = protocols[this.protocol];
if(ProtocolDecoder === undefined) {
this.protocolName = "Unknown";
} else {
this.payload = new ProtocolDecoder(this.emitter).decode(raw_packet, offset, this.length - this.headerLength);
}
if(this.emitter) { this.emitter.emit("ipv4", this); }
return this;
};
IPv4.prototype.decoderName = "ipv4";
IPv4.prototype.eventsOnDecode = true;
IPv4.prototype.toString = function () {
var ret = this.saddr + " -> " + this.daddr;
var ret = this.saddr + " -> " + this.daddr + " ";
var flags = this.flags.toString();
if (flags.length > 2) {
ret += " flags " + flags;
ret += "flags " + flags + " ";
}
switch (this.protocol) {
case 1:
ret += " ICMP";
break;
case 2:
ret += " IGMP";
break;
case 4:
ret += " IPv4_in_IPv4"; // IPv4 encapsulation, RFC2003
break;
case 6:
ret += " TCP";
break;
case 17:
ret += " UDP";
break;
case 41:
ret += " IPv6_in_IP4"; // IPv6 encapsulation, RFC2473
break;
default:
ret += " proto " + this.protocol;
if(this.payload === undefined || this.payload === null ){
ret += "proto " + this.protocol;
} else {
ret += this.payload.constructor.name;
}

@@ -142,0 +125,0 @@ return ret + " " + this.payload;

@@ -1,23 +0,24 @@

var map = require("../util").int8_to_hex_nopad;
var hex = require("../util").int8_to_hex;
function IPv6Addr() {
this.o1 = null;
this.o2 = null;
this.o3 = null;
this.o4 = null;
this.o5 = null;
this.o6 = null;
this.o7 = null;
this.o8 = null;
this.addr = new Array(16);
}
IPv6Addr.prototype.decode = function (raw_packet, offset) {
this.o1 = raw_packet.readUInt16LE[offset];
this.o2 = raw_packet.readUInt16LE[offset + 2];
this.o3 = raw_packet.readUInt16LE[offset + 4];
this.o4 = raw_packet.readUInt16LE[offset + 6];
this.o5 = raw_packet.readUInt16LE[offset + 8];
this.o6 = raw_packet.readUInt16LE[offset + 10];
this.o7 = raw_packet.readUInt16LE[offset + 12];
this.o8 = raw_packet.readUInt16LE[offset + 14];
IPv6Addr.prototype.decode = function decode(raw_packet, offset) {
this.addr[0] = raw_packet[offset + 0];
this.addr[1] = raw_packet[offset + 1];
this.addr[2] = raw_packet[offset + 2];
this.addr[3] = raw_packet[offset + 3];
this.addr[4] = raw_packet[offset + 4];
this.addr[5] = raw_packet[offset + 5];
this.addr[6] = raw_packet[offset + 6];
this.addr[7] = raw_packet[offset + 7];
this.addr[8] = raw_packet[offset + 8];
this.addr[9] = raw_packet[offset + 9];
this.addr[10] = raw_packet[offset + 10];
this.addr[11] = raw_packet[offset + 11];
this.addr[12] = raw_packet[offset + 12];
this.addr[13] = raw_packet[offset + 13];
this.addr[14] = raw_packet[offset + 14];
this.addr[15] = raw_packet[offset + 15];

@@ -27,17 +28,17 @@ return this;

function format(num) {
var p1 = (num & 0xff00) >> 8;
var p2 = num & 0x00ff;
if (p1 === 0) {
return map[p2];
} else {
return map[p1] + map[p2];
}
}
IPv6Addr.prototype.decoderName = "ipv6-addr";
IPv6Addr.prototype.eventsOnDecode = false;
IPv6Addr.prototype.toString = function () {
return format(this.o1) + ":" + format(this.o2) + ":" + format(this.o3) + ":" + format(this.o4) + ":" +
format(this.o5) + ":" + format(this.o6) + ":" + format(this.o7) + ":" + format(this.o8);
//There are some rules one can follow to
//shorten the string representation of an
//ipv6 address, but the long hand version
//is both simple and valid.
return hex[this.addr[0]] + hex[this.addr[1]] + ":" + hex[this.addr[2]] + hex[this.addr[3]] + ":" +
hex[this.addr[4]] + hex[this.addr[5]] + ":" + hex[this.addr[6]] + hex[this.addr[7]] + ":" +
hex[this.addr[8]] + hex[this.addr[9]] + ":" + hex[this.addr[10]] + hex[this.addr[11]] + ":" +
hex[this.addr[12]] + hex[this.addr[13]] + ":" + hex[this.addr[14]] + hex[this.addr[15]];
};
module.exports = IPv6Addr;

@@ -1,99 +0,60 @@

var ICMP = require("./icmp");
var IGMP = require("./igmp");
var TCP = require("./tcp");
var UDP = require("./udp");
var IPv4 = require("./ipv4");
var IPv6Addr = require("./ipv6_addr");
var protocols = require("./ip_protocols");
function IPv6Header() {
function IPv6(emitter) {
this.emitter = emitter;
this.version = undefined;
this.trafficClass = undefined;
this.flowLabel = undefined;
this.payloadLength = undefined;
this.nextHeader = undefined;
this.hopLimit = undefined;
this.saddr = undefined;
this.daddr = undefined;
this.payload = undefined;
}
IPv6Header.prototype.decode = function (raw_packet, next_header, ip, offset) {
switch (next_header) {
case 1:
ip.payload = new ICMP().decode(raw_packet, offset);
break;
case 2:
ip.payload = new IGMP().decode(raw_packet, offset);
break;
case 4:
ip.payload = new IPv4().decode(raw_packet, offset); // IPv4 encapsulation, RFC2003
break;
case 6:
ip.payload = new TCP().decode(raw_packet, offset, ip);
break;
case 17:
ip.payload = new UDP().decode(raw_packet, offset);
break;
case 41:
ip.payload = new IPv6().decode(raw_packet, offset); // IPv6 encapsulation, RFC2473
break;
/* Please follow numbers and RFC in http://www.iana.org/assignments/ipv6-parameters/ipv6-parameters.xhtml#extension-header
* Not all next protocols follow this rule (and we can have unsuported upper protocols here too).
* */
case 0: //Hop-by-Hop
case 60: //Destination Options
case 43: //Routing
case 135: //Mobility
case 139: //Host Identity Protocol. //Discussion: rfc5201 support only No Next Header/trailing data, but future documents May do.
case 140: //Shim6 Protocol
new IPv6Header().decode(raw_packet, raw_packet[offset], ip, offset + 8*raw_packet[offset+1] + 8);
break;
case 51: //Authentication Header
new IPv6Header().decode(raw_packet, raw_packet[offset], ip, offset + 4*raw_packet[offset+1] + 8);
break;
default:
// 59 - No next Header, and unknowed upper layer protocols, do nothing.
}
};
function IPv6() {
}
IPv6.prototype.decode = function (raw_packet, offset) {
// http://en.wikipedia.org/wiki/IPv6
this.version = (raw_packet[offset] & 240) >> 4; // first 4 bits
this.traffic_class = ((raw_packet[offset] & 15) << 4) + ((raw_packet[offset+1] & 240) >> 4);
this.flow_label = ((raw_packet[offset + 1] & 15) << 16) +
var originalOffset = offset;
this.version = ((raw_packet[offset] & 0xf0) >> 4); // first 4 bits
this.trafficClass = ((raw_packet[offset] & 0x0f) << 4) | ((raw_packet[offset+1] & 0xf0) >> 4);
this.flowLabel = ((raw_packet[offset + 1] & 0x0f) << 16) +
(raw_packet[offset + 2] << 8) +
raw_packet[offset + 3];
this.payload_length = raw_packet.readUInt16BE(offset+4, true);
this.total_length = this.payload_length + 40;
this.next_header = raw_packet[offset+6];
this.hop_limit = raw_packet[offset+7];
this.payloadLength = raw_packet.readUInt16BE(offset+4, true);
this.nextHeader = raw_packet[offset+6];
this.hopLimit = raw_packet[offset+7];
this.saddr = new IPv6Addr().decode(raw_packet, offset+8);
this.daddr = new IPv6Addr().decode(raw_packet, offset+24);
this.header_bytes = 40;
new IPv6Header().decode(raw_packet, this.next_header, this, offset+40);
/*
http://tools.ietf.org/html/rfc2780
* 5.3 IPv6 Next Header field
*
* The IPv6 Next Header field carries values from the same name space as
* the IPv4 Protocol name space.
*/
offset = originalOffset + 40;
var ProtocolDecoder = protocols[this.nextHeader];
if(ProtocolDecoder === undefined) {
this.protocolName = "Unknown";
} else {
this.payload = new ProtocolDecoder().decode(raw_packet, offset, raw_packet.length - 40);
}
if(this.emitter) { this.emitter.emit("ipv6", this); }
return this;
};
IPv6.prototype.decoderName = "ipv6";
IPv6.prototype.eventsOnDecode = true;
IPv6.prototype.toString = function () {
var ret = this.saddr + " -> " + this.daddr;
var ret = this.saddr + " -> " + this.daddr + " ";
switch (this.next_header) {
case 1:
ret += " ICMP";
break;
case 2:
ret += " IGMP";
break;
case 4:
ret += " IPv4_in_IPv6"; // IPv4 encapsulation, RFC2003
break;
case 6:
ret += " TCP";
break;
case 17:
ret += " UDP";
break;
case 41:
ret += " IPv6_in_IPv6"; // IPv6 encapsulation, RFC2473
break;
default:
ret += " proto " + this.next_header;
if(this.payload === undefined || this.payload === null ){
ret += "proto " + this.nextHeader;
} else {
ret += this.payload.constructor.name;
}

@@ -100,0 +61,0 @@

var IPv4 = require("./ipv4");
var IPv6 = require("./ipv6");
var ARP = require("./arp");
function LogicalLinkControl() {
this.dsap = null;
this.ssap = null;
this.control_field = null;
this.org_code = null;
this.type = null;
function LogicalLinkControl(emitter) {
this.emitter = emitter;
this.dsap = undefined;
this.ssap = undefined;
this.controlField = undefined;
this.orgCode = undefined;
this.type = undefined;
this._error = undefined;
}

@@ -15,5 +19,10 @@

if (((this.dsap === 0xaa) && (this.ssap === 0xaa)) || ((this.dsap === 0x00) && (this.ssap === 0x00))) {
this.control_field = raw_packet[offset++];
this.org_code = [
// https://en.wikipedia.org/wiki/IEEE_802.2#LSAP_Values
// http://tools.ietf.org/html/rfc1700
// 0xaa is SNAP
// 0x00 is NULL LSAP
if (((this.dsap === 0xaa) && (this.ssap === 0xaa)) ||
((this.dsap === 0x00) && (this.ssap === 0x00))) {
this.controlField = raw_packet[offset++];
this.orgCode = [
raw_packet[offset++],

@@ -23,15 +32,31 @@ raw_packet[offset++],

];
this.type = raw_packet.readUInt16BE(raw_packet, offset);
offset += 2;
this.type = raw_packet.readUInt16BE(offset); offset += 2;
switch (this.type) {
case 0x0800: // IPv4
this.payload = new IPv4().decode(raw_packet, offset);
break;
if (this.ethertype < 1536) {
// this packet is actually some 802.3 type without an ethertype
this.ethertype = 0;
} else {
switch (this.type) {
case 0x0800: // IPv4
this.payload = new IPv4(this.emitter).decode(raw_packet, offset);
break;
case 0x0806: // ARP
this.payload = new ARP(this.emitter).decode(raw_packet, offset);
break;
case 0x86dd: // IPv6
this.payload = new IPv6(this.emitter).decode(raw_packet, offset);
break;
}
}
} else {
throw new Error("Unknown LLC types: DSAP: " + this.dsap + ", SSAP: " + this.ssap);
this._error = "Unknown LLC types: DSAP: " + this.dsap + ", SSAP: " + this.ssap;
}
if(this.emitter) { this.emitter.emit("llc", this); }
return this;
};
LogicalLinkControl.prototype.decoderName = "llc";
LogicalLinkControl.prototype.eventsOnDecode = true;
module.exports = LogicalLinkControl;
var IPv4 = require("./ipv4");
var IPv6 = require("./ipv6");
function NullPacket() {
this.pftype = null;
this.payload = null;
function NullPacket(emitter) {
this.emitter = emitter;
this.pftype = undefined;
this.payload = undefined;
this._error = undefined;
}

@@ -20,7 +22,7 @@

if (this.pftype === 2) { // AF_INET, at least on my Linux and OSX machines right now
this.payload = new IPv4().decode(raw_packet, offset + 4);
this.payload = new IPv4(this.emitter).decode(raw_packet, offset + 4);
} else if (this.pftype === 30) { // AF_INET6, often
this.payload = new IPv6().decode(raw_packet, offset + 4);
this.payload = new IPv6(this.emitter).decode(raw_packet, offset + 4);
} else {
console.log("pcap.js: decode.nulltype() - Don't know how to decode protocol family " + this.pftype);
this._error = "unknown protocol family " + this.pftype;
}

@@ -31,2 +33,5 @@

NullPacket.prototype.decoderName = "null-packet";
NullPacket.prototype.eventsOnDecode = false;
NullPacket.prototype.toString = function () {

@@ -33,0 +38,0 @@ return this.pftype + " " + this.payload;

var EthernetPacket = require("./ethernet_packet");
var NullPacket = require("./null_packet");
var RawPacket = require("./raw_packet");
var RadioPacket = require("./radio_packet");
var Ipv4 = require("./ipv4");
var RadioPacket = require("./ieee802.11/radio_packet");
var SLLPacket = require("./sll_packet");

@@ -22,6 +22,7 @@

function PcapPacket() {
function PcapPacket(emitter) {
this.link_type = null;
this.pcap_header = null;
this.payload = null;
this.emitter = emitter;
}

@@ -33,19 +34,19 @@

var buf = packet_with_header.buf;
var buf = packet_with_header.buf.slice(0, this.pcap_header.len);
switch (this.link_type) {
case "LINKTYPE_ETHERNET":
this.payload = new EthernetPacket().decode(buf, 0);
this.payload = new EthernetPacket(this.emitter).decode(buf, 0);
break;
case "LINKTYPE_NULL":
this.payload = new NullPacket().decode(buf, 0);
this.payload = new NullPacket(this.emitter).decode(buf, 0);
break;
case "LINKTYPE_RAW":
this.payload = new RawPacket().decode(buf, 0);
this.payload = new Ipv4(this.emitter).decode(buf, 0);
break;
case "LINKTYPE_IEEE802_11_RADIO":
this.payload = new RadioPacket.decode(buf, 0);
this.payload = new RadioPacket(this.emitter).decode(buf, 0);
break;
case "LINKTYPE_LINUX_SLL":
this.payload = new SLLPacket().decode(buf, 0);
this.payload = new SLLPacket(this.emitter).decode(buf, 0);
break;

@@ -52,0 +53,0 @@ default:

@@ -10,2 +10,5 @@ var util = require("../util");

SLLAddr.prototype.decoderName = "ssl-addr";
SLLAddr.prototype.eventsOnDecode = false;
SLLAddr.prototype.toString = function () {

@@ -12,0 +15,0 @@ var ret = "";

@@ -9,3 +9,4 @@ // Synthetic Link Layer used by Linux to support the "any" pseudo device

function SLLPacket () {
function SLLPacket (emitter) {
this.emitter = emitter;
this.packet_type = null;

@@ -38,9 +39,9 @@ this.address_type = null;

case 0x800: // IPv4
this.payload = new IPv4().decode(raw_packet, offset);
this.payload = new IPv4(this.emitter).decode(raw_packet, offset);
break;
case 0x806: // ARP
this.payload = new Arp().decode(raw_packet, offset);
this.payload = new Arp(this.emitter).decode(raw_packet, offset);
break;
case 0x86dd: // IPv6 - http://en.wikipedia.org/wiki/IPv6
this.payload = new IPv6().decode(raw_packet, offset);
this.payload = new IPv6(this.emitter).decode(raw_packet, offset);
break;

@@ -58,2 +59,5 @@ case 0x88cc: // LLDP - http://en.wikipedia.org/wiki/Link_Layer_Discovery_Protocol

SLLPacket.prototype.decoderName = "ssl-packet";
SLLPacket.prototype.eventsOnDecode = false;
SLLPacket.prototype.toString = function () {

@@ -60,0 +64,0 @@ var ret = "";

function TCPFlags() {
this.cwr = null;
this.ece = null;
this.urg = null;
this.ack = null;
this.psh = null;
this.rst = null;
this.syn = null;
this.fin = null;
function TCPFlags(emitter) {
this.emitter = emitter;
this.nonce = undefined;
this.cwr = undefined;
this.ece = undefined;
this.urg = undefined;
this.ack = undefined;
this.psh = undefined;
this.rst = undefined;
this.syn = undefined;
this.fin = undefined;
}
TCPFlags.prototype.decode = function (first_byte, second_byte) {
this.nonce = Boolean(first_byte & 16);
this.cwr = Boolean(second_byte & 128);
this.ece = Boolean(second_byte & 64);
this.urg = Boolean(second_byte & 32);
this.ack = Boolean(second_byte & 16);
this.psh = Boolean(second_byte & 8);
this.rst = Boolean(second_byte & 4);
this.syn = Boolean(second_byte & 2);
this.fin = Boolean(second_byte & 1);
return this;
};
TCPFlags.prototype.toString = function () {

@@ -127,2 +142,9 @@ var ret = "[";

break;
case 254:
case 255:
//We do not know how to parse rfc6994 (Experimental TCP option)
//however, the first byte is the length of the option (including
//the 1 byte kind, and 1 byte of length.) So skip over option.
offset += raw_packet.readUInt8(offset + 1);
break;
default:

@@ -158,17 +180,17 @@ throw new Error("Don't know how to process TCP option " + raw_packet[offset]);

function TCP() {
this.sport = null;
this.dport = null;
this.seqno = null;
this.ackno = null;
this.data_offset = null;
this.header_bytes = null; // not part of packet but handy
this.reserved = null;
this.flags = new TCPFlags();
this.window_size = null;
this.checksum = null;
this.urgent_pointer = null;
this.options = null;
this.data = null;
this.data_bytes = null;
function TCP(emitter) {
this.emitter = emitter;
this.sport = undefined;
this.dport = undefined;
this.seqno = undefined;
this.ackno = undefined;
this.headerLength = undefined;
this.reserved = undefined;
this.flags = undefined;
this.windowSize = undefined;
this.checksum = undefined;
this.urgentPointer = undefined;
this.options = undefined;
this.data = undefined;
this.dataLength = undefined;
}

@@ -180,2 +202,4 @@

// }
TCP.prototype.decoderName = "tcp";
TCP.prototype.eventsOnDecode = true;

@@ -194,28 +218,17 @@ // http://en.wikipedia.org/wiki/Transmission_Control_Protocol

offset += 4;
this.data_offset = (raw_packet[offset] & 0xf0) >> 4; // first 4 bits of 12
if (this.data_offset < 5 || this.data_offset > 15) {
throw new Error("invalid data_offset: " + this.data_offset);
}
this.header_bytes = this.data_offset * 4; // convenience for using data_offset
this.reserved = raw_packet[offset] & 15; // second 4 bits of 12
offset += 1;
var all_flags = raw_packet[offset];
this.flags.cwr = (all_flags & 128) >> 7; // all flags packed into 13
this.flags.ece = (all_flags & 64) >> 6;
this.flags.urg = (all_flags & 32) >> 5;
this.flags.ack = (all_flags & 16) >> 4;
this.flags.psh = (all_flags & 8) >> 3;
this.flags.rst = (all_flags & 4) >> 2;
this.flags.syn = (all_flags & 2) >> 1;
this.flags.fin = all_flags & 1;
offset += 1;
this.window_size = raw_packet.readUInt16BE(offset, true); // 14, 15
// The first 4 bits of the next header * 4 tells use the length
// of the header.
this.headerLength = (raw_packet[offset] & 0xf0) >> 2;
this.flags = new TCPFlags().decode(raw_packet[offset], raw_packet[offset+1]);
offset += 2;
this.windowSize = raw_packet.readUInt16BE(offset, true); // 14, 15
offset += 2;
this.checksum = raw_packet.readUInt16BE(offset, true); // 16, 17
offset += 2;
this.urgent_pointer = raw_packet.readUInt16BE(offset, true); // 18, 19
this.urgentPointer = raw_packet.readUInt16BE(offset, true); // 18, 19
offset += 2;
this.options = new TCPOptions();
var options_len = this.header_bytes - (offset - orig_offset);
var options_len = this.headerLength - (offset - orig_offset);
if (options_len > 0) {

@@ -226,10 +239,16 @@ this.options.decode(raw_packet, offset, options_len);

this.data_bytes = len - this.header_bytes;
if (this.data_bytes > 0) {
this.dataLength = len - this.headerLength;
if (this.dataLength > 0) {
// add a buffer slice pointing to the data area of this TCP packet.
// Note that this does not make a copy, so ret.data is only valid for this current
// trip through the capture loop.
this.data = raw_packet.slice(offset, offset + this.data_bytes);
this.data = raw_packet.slice(offset, offset + this.dataLength);
} else {
// null indicated the value was set. Where as undefined
// means the value was never set. Since there is no data
// we explicity want to communicate this to consumers.
this.data = null;
}
if(this.emitter) { this.emitter.emit("tcp", this); }
return this;

@@ -240,8 +259,8 @@ };

var ret = this.sport + "->" + this.dport + " seq " + this.seqno + " ack " + this.ackno + " flags " + this.flags + " " +
"win " + this.window_size + " csum " + this.checksum;
"win " + this.windowSize + " csum " + this.checksum;
if (this.urgent_pointer) {
ret += " urg " + this.urgent_pointer;
ret += " urg " + this.urgentPointer;
}
ret += " " + this.options.toString();
ret += " len " + this.data_bytes;
ret += " len " + this.dataLength;
return ret;

@@ -248,0 +267,0 @@ };

var DNS = require("./dns");
function UDP() {
this.sport = null;
this.dport = null;
this.length = null;
this.checksum = null;
this.data = null;
function UDP(emitter) {
this.emitter = emitter;
this.sport = undefined;
this.dport = undefined;
this.length = undefined;
this.checksum = undefined;
this.data = undefined;
}

@@ -24,5 +25,9 @@

if(this.emitter) { this.emitter.emit("udp", this); }
return this;
};
UDP.prototype.decoderName = "udp";
UDP.prototype.eventsOnDecode = true;
UDP.prototype.toString = function () {

@@ -29,0 +34,0 @@ var ret = "UDP " + this.sport + "->" + this.dport + " len " + this.length;

@@ -16,2 +16,5 @@ function Vlan() {

Vlan.prototype.decoderName = "vlan";
Vlan.prototype.eventsOnDecode = false;
Vlan.prototype.toString = function () {

@@ -18,0 +21,0 @@ return this.priority + " " + this.canonical_format + " " + this.id;

@@ -0,1 +1,2 @@

var events = require("events");
// Meaningfully hold the different types of frames at some point

@@ -2,0 +3,0 @@ function WebSocketFrame() {

@@ -1,2 +0,2 @@

var pcap = require("pcap"),
var pcap = require("../pcap"),
pcap_session = pcap.createSession("", "tcp"),

@@ -3,0 +3,0 @@ matcher = /safari/i;

{
"name": "pcap",
"version": "2.0.1",
"version": "2.1.0",
"description": "raw packet capture, decoding, and analysis",
"author": "Matt Ranney <mjr@ranney.com>",
"maintainers": [
"Ujjwal Thaakar <ujjwalthaakar@gmail.com>"
],
"main": "./pcap",

@@ -11,6 +14,25 @@ "repository": {

},
"engines": {
"node": ">=0.10"
},
"dependencies": {
"nan": "~1.6.1",
"socketwatcher": "git://github.com/zerouid/node-socketwatcher.git"
"nan": "^2.0.9",
"socketwatcher": "git+https://github.com/bytzdev/node-socketwatcher.git"
},
"devDependencies": {
"grunt": "^0.4.5",
"grunt-cli": "^0.1.13",
"grunt-contrib-jshint": "^0.11.0",
"grunt-coveralls": "^1.0.0",
"grunt-mocha-istanbul": "^2.3.1",
"grunt-mocha-test": "^0.12.7",
"istanbul": "^0.3.5",
"mocha": "^2.1.0",
"mocha-sinon": "^1.1.4",
"should": "^5.0.0",
"sinon": "^1.14.1"
},
"scripts": {
"test": "grunt"
}
}

@@ -8,2 +8,3 @@ var util = require("util");

var DNSCache = require("./dns_cache");
var timers = require("timers");

@@ -72,3 +73,3 @@ exports.decode = decode;

} else {
setImmediate(function() {
timers.setImmediate(function() {
var packets = 0;

@@ -88,3 +89,3 @@ do {

PcapSession.prototype.findalldevs = function () {
exports.findalldevs = function () {
return binding.findalldevs();

@@ -107,3 +108,5 @@ };

this.session.close();
this.readWatcher.stop();
if (this.is_live) {
this.readWatcher.stop();
}
// TODO - remove listeners so program will exit I guess?

@@ -130,2 +133,1 @@ };

};

@@ -0,4 +1,10 @@

##Disclaimer
node_pcap is currently being heavily refactored much of the documentation is out of date. If you installed node_pcap from npm go to [v2.0.1](https://github.com/mranney/node_pcap/commit/6e4d56671c54e0cf690f72b92554a538244bd1b6). Thanks for your patience and contributions as we work on the next major version of node_pcap.
node_pcap
=========
[![Join the chat at https://gitter.im/mranney/node_pcap](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/mranney/node_pcap?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Build Status](https://travis-ci.org/mranney/node_pcap.svg?branch=master)](https://travis-ci.org/mranney/node_pcap)[![Coverage Status](https://coveralls.io/repos/mranney/node_pcap/badge.svg)](https://coveralls.io/r/mranney/node_pcap)
This is a set of bindings from `libpcap` to node as well as some useful libraries to decode, print, and

@@ -10,3 +16,3 @@ analyze packets. `libpcap` is a packet capture library used by programs like `tcpdump` and `wireshark`.

to use this package are
[http_trace](https://github.com/mranney/http_trace), and
[http_trace](https://github.com/mranney/http_trace) (works only on node 4), and
[htracr](https://github.com/mnot/htracr).

@@ -59,3 +65,3 @@

To use this library in your own program, `pcap.js` and `pcap_binding.node` must be in `NODE_PATH`. `npm`
To use this library in your own program, `pcap.js` and `pcap_binding.node` must be in `NODE_PATH`. `npm`
takes care of this automatically.

@@ -67,4 +73,6 @@

var pcap = require('pcap'),
pcap_session = pcap.createSession(interface, filter);
```javascript
var pcap = require('pcap'),
pcap_session = pcap.createSession(interface, filter);
```

@@ -87,8 +95,10 @@ `interface` is the name of the interface on which to capture packets. If passed an empty string, `libpcap`

pcap_session.on('packet', function (raw_packet) {
// do some stuff with a raw packet
});
```javascript
pcap_session.on('packet', function (raw_packet) {
// do some stuff with a raw packet
});
```
To convert `raw_packet` into a JavaScript object that is easy to work with, decode it:
var packet = pcap.decode.packet(raw_packet);

@@ -99,3 +109,5 @@

packet.link.ip.tcp.dport
```javascript
packet.link.ip.tcp.dport
```

@@ -106,84 +118,27 @@ This structure is easy to explore with `sys.inspect`.

TCP can be analyzed by feeding the packets into a `TCP_tracker` and then listening for `start` and `end` events.
TCP can be analyzed by feeding the packets into a `TCPTracker` and then listening for `session` and `end` events.
var pcap = require('pcap'),
tcp_tracker = new pcap.TCP_tracker(),
pcap_session = pcap.createSession(interface, "ip proto \\tcp");
```javascript
var pcap = require('pcap'),
tcp_tracker = new pcap.TCPTracker(),
pcap_session = pcap.createSession('en0', "ip proto \\tcp");
tcp_tracker.on('start', function (session) {
console.log("Start of TCP session between " + session.src_name + " and " + session.dst_name);
});
tcp_tracker.on('session', function (session) {
console.log("Start of session between " + session.src_name + " and " + session.dst_name);
session.on('end', function (session) {
console.log("End of TCP session between " + session.src_name + " and " + session.dst_name);
});
});
tcp_tracker.on('end', function (session) {
console.log("End of TCP session between " + session.src_name + " and " + session.dst_name);
});
pcap_session.on('packet', function (raw_packet) {
var packet = pcap.decode.packet(raw_packet);
tcp_tracker.track_packet(packet);
});
```
pcap_session.on('packet', function (raw_packet) {
var packet = pcap.decode.packet(raw_packet);
tcp_tracker.track_packet(packet);
});
You must only send IPv4 TCP packets to the TCP tracker. Explore the `session` object with `sys.inspect` to
see the wonderful things it can do for you. Hopefully the names of the properties are self-explanatory:
{ src: '10.51.2.130:55965'
, dst: '75.119.207.0:80'
, syn_time: 1280425738896.771
, state: 'ESTAB'
, key: '10.51.2.130:55965-75.119.207.0:80'
, send_isn: 2869922608
, send_window_scale: 8
, send_packets: { '2869922609': 1280425738896.771 }
, send_acks: { '1063203923': 1280425738911.618 }
, send_retrans: {}
, send_next_seq: 2869922609
, send_acked_seq: null
, send_bytes_ip: 60
, send_bytes_tcp: 108
, send_bytes_payload: 144
, recv_isn: 1063203922
, recv_window_scale: 128
, recv_packets: { '1063203923': 1280425738911.536 }
, recv_acks: { '2869922609': 1280425738911.536 }
, recv_retrans: {}
, recv_next_seq: null
, recv_acked_seq: null
, recv_bytes_ip: 20
, recv_bytes_tcp: 40
, recv_bytes_payload: 0
, src_name: '10.51.2.130:55965'
, dst_name: '75.119.207.0:80'
, current_cap_time: 1280425738911.65
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).
### HTTP Analysis
The `TCP_tracker` also detects and decodes HTTP on all streams it receives. If HTTP is detected, several
new events will be emitted:
* `http request`: function(session, http)
* `http request body`: function(session, http, data)
Note that `data` is a node Buffer object sliced from the original packet. If you want to use it past the
current tick, you'll need to make a copy somehow.
* `http request complete`: function(session, http)
* `http response`: function(session, http)
* `http response body`: function(session, http, data)
`data` is a Buffer slice. See above.
* `http response complete`: function(session, http)
See `http_trace` for an example of how to use these events to decode HTTP.
### WebSocket Analysis
The `TCP_tracker` further detects and decodes WebSocket traffic on all streams it receives.
* `websocket upgrade`: function(session, http)
* `websocket message`: function(session, dir, message)
See `http_trace` for an example of how to use these events to decode WebSocket.
## Some Common Problems

@@ -193,3 +148,3 @@

TSO is a technique that modern operating systems use to offload the burden of IP/TCP header computation to
TSO is a technique that modern operating systems use to offload the burden of IP/TCP header computation to
the network hardware. It also reduces the number of times that data is moved data between the kernel and the

@@ -199,3 +154,3 @@ network hardware. TSO saves CPU when sending data that is larger than a single IP packet.

This is amazing and wonderful, but it does make some kinds of packet sniffing more difficult. In many cases,
it is important to see the exact packets that are sent, but if the network hardware is sending the packets,
it is important to see the exact packets that are sent, but if the network hardware is sending the packets,
these are not available to `libpcap`. The solution is to disable TSO.

@@ -206,3 +161,3 @@

sudo sysctl -w net.inet.tcp.tso=0
Linux (substitute correct interface name):

@@ -222,3 +177,3 @@

sudo http_trace lo0 "ip proto \tcp"
The backslash is important. The pcap filter language has an ambiguity with the word "tcp", so by escaping it,

@@ -238,237 +193,8 @@ you'll get the correct interpretation for this case.

## examples/simple_capture
## Examples
This program captures packets and prints them using the built in simple printer. Here's a sample of it's output.
In another window I ran `curl nodejs.org`.
[redis_trace](https://github.com/mranney/redis_trace)
mjr:~/work/node_pcap$ sudo node examples/simple_capture.js en1 ""
libpcap version 1.0.0
en0 no address
* en1 10.240.0.133/255.255.255.0
lo0 127.0.0.1/255.0.0.0
00:18:39:ff:f9:1c -> 00:1f:5b:ce:3e:29 10.240.0.1 ARP request 10.240.0.133
00:1f:5b:ce:3e:29 -> 00:18:39:ff:f9:1c 10.240.0.133 ARP reply 10.240.0.1 hwaddr 00:18:39:ff:f9:1c
00:1f:5b:ce:3e:29 -> 00:18:39:ff:f9:1c 10.240.0.133:53808 -> 97.107.132.72:80 TCP len 64
00:1f:5b:ce:3e:29 -> 00:18:39:ff:f9:1c 10.240.0.133:57052 -> 10.240.0.1:53 DNS question 133.0.240.10.in-addr.arpa PTR
00:1f:5b:ce:3e:29 -> 00:18:39:ff:f9:1c 10.240.0.133:57052 -> 10.240.0.1:53 DNS question 72.132.107.97.in-addr.arpa PTR
00:1f:5b:ce:3e:29 -> 00:18:39:ff:f9:1c 10.240.0.133:57052 -> 10.240.0.1:53 DNS question 1.0.240.10.in-addr.arpa PTR
00:18:39:ff:f9:1c -> 00:1f:5b:ce:3e:29 10.240.0.1:53 -> 10.240.0.133:57052 DNS answer 133.0.240.10.in-addr.arpa PTR
00:18:39:ff:f9:1c -> 00:1f:5b:ce:3e:29 10.240.0.1:53 -> rv-mjr2.ranney.com:57052 DNS answer 72.132.107.97.in-addr.arpa PTR
00:18:39:ff:f9:1c -> 00:1f:5b:ce:3e:29 10.240.0.1:53 -> rv-mjr2.ranney.com:57052 DNS answer 1.0.240.10.in-addr.arpa PTR
00:18:39:ff:f9:1c -> 00:1f:5b:ce:3e:29 tinyclouds.org:80 -> rv-mjr2.ranney.com:53808 TCP len 60
00:1f:5b:ce:3e:29 -> 00:18:39:ff:f9:1c rv-mjr2.ranney.com:53808 -> tinyclouds.org:80 TCP len 52
00:1f:5b:ce:3e:29 -> 00:18:39:ff:f9:1c rv-mjr2.ranney.com:53808 -> tinyclouds.org:80 TCP len 196
00:18:39:ff:f9:1c -> 00:1f:5b:ce:3e:29 tinyclouds.org:80 -> rv-mjr2.ranney.com:53808 TCP len 52
00:18:39:ff:f9:1c -> 00:1f:5b:ce:3e:29 tinyclouds.org:80 -> rv-mjr2.ranney.com:53808 TCP len 1500
00:18:39:ff:f9:1c -> 00:1f:5b:ce:3e:29 tinyclouds.org:80 -> rv-mjr2.ranney.com:53808 TCP len 1500
00:1f:5b:ce:3e:29 -> 00:18:39:ff:f9:1c rv-mjr2.ranney.com:53808 -> tinyclouds.org:80 TCP len 52
00:18:39:ff:f9:1c -> 00:1f:5b:ce:3e:29 tinyclouds.org:80 -> rv-mjr2.ranney.com:53808 TCP len 1500
00:1f:5b:ce:3e:29 -> 00:18:39:ff:f9:1c rv-mjr2.ranney.com:53808 -> tinyclouds.org:80 TCP len 52
00:18:39:ff:f9:1c -> 00:1f:5b:ce:3e:29 tinyclouds.org:80 -> rv-mjr2.ranney.com:53808 TCP len 1500
00:18:39:ff:f9:1c -> 00:1f:5b:ce:3e:29 tinyclouds.org:80 -> rv-mjr2.ranney.com:53808 TCP len 1500
00:1f:5b:ce:3e:29 -> 00:18:39:ff:f9:1c rv-mjr2.ranney.com:53808 -> tinyclouds.org:80 TCP len 52
00:18:39:ff:f9:1c -> 00:1f:5b:ce:3e:29 tinyclouds.org:80 -> rv-mjr2.ranney.com:53808 TCP len 1500
00:1f:5b:ce:3e:29 -> 00:18:39:ff:f9:1c rv-mjr2.ranney.com:53808 -> tinyclouds.org:80 TCP len 52
00:18:39:ff:f9:1c -> 00:1f:5b:ce:3e:29 tinyclouds.org:80 -> rv-mjr2.ranney.com:53808 TCP len 1500
00:18:39:ff:f9:1c -> 00:1f:5b:ce:3e:29 tinyclouds.org:80 -> rv-mjr2.ranney.com:53808 TCP len 337
00:1f:5b:ce:3e:29 -> 00:18:39:ff:f9:1c rv-mjr2.ranney.com:53808 -> tinyclouds.org:80 TCP len 52
00:1f:5b:ce:3e:29 -> 00:18:39:ff:f9:1c rv-mjr2.ranney.com:53808 -> tinyclouds.org:80 TCP len 52
00:1f:5b:ce:3e:29 -> 00:18:39:ff:f9:1c rv-mjr2.ranney.com:53808 -> tinyclouds.org:80 TCP len 52
00:18:39:ff:f9:1c -> 00:1f:5b:ce:3e:29 tinyclouds.org:80 -> rv-mjr2.ranney.com:53808 TCP len 52
00:1f:5b:ce:3e:29 -> 00:18:39:ff:f9:1c rv-mjr2.ranney.com:53808 -> tinyclouds.org:80 TCP len 52
[http_trace](https://github.com/mranney/http_trace) (Node 4 only)
## Output from `session.findalldevs`:
[ { name: 'en0'
, addresses:
[ { addr: '10.51.2.183'
, netmask: '255.255.255.0'
, broadaddr: '10.51.2.255'
}
]
}
, { name: 'fw0', addresses: [] }
, { name: 'en1', addresses: [] }
, { name: 'lo0'
, addresses: [ { addr: '127.0.0.1', netmask: '255.0.0.0' } ]
, flags: 'PCAP_IF_LOOPBACK'
}
]
### Deep decode of `curl nodejs.org`:
Running `sys.inspect` on the first three decoded packets of this TCP session.
First packet, TCP SYN:
{ ethernet:
{ dhost: '00:18:39:ff:f9:1c'
, shost: '00:1f:5b:ce:3e:29'
, ethertype: 2048
, ip:
{ version: 4
, header_length: 5
, diffserv: 0
, total_length: 64
, identification: 49042
, flags: { reserved: 0, df: 1, mf: 0 }
, fragment_offset: 0
, ttl: 64
, protocol: 6
, header_checksum: 35325
, saddr: '10.240.0.133'
, daddr: '97.107.132.72'
, protocol_name: 'TCP'
, tcp:
{ sport: 57230
, dport: 80
, seqno: 4179361823
, ackno: 1540242985
, data_offset: 11
, reserved: 0
, flags:
{ cwr: 0
, ece: 0
, urg: 0
, ack: 0
, psh: 0
, rst: 0
, syn: 1
, fin: 0
}
, window_size: 65535
, checksum: 2601
, urgent_pointer: 0
, payload_offset: 78
, payload: { length: 0 }
}
}
}
, pcap_header:
{ time: Sat, 22 May 2010 07:48:40 GMT
, tv_sec: 1274514520
, tv_usec: 820479
, caplen: 78
, len: 78
, link_type: 'LINKTYPE_ETHERNET'
}
}
Second packet, TCP SYN+ACK:
{ ethernet:
{ dhost: '00:1f:5b:ce:3e:29'
, shost: '00:18:39:ff:f9:1c'
, ethertype: 2048
, ip:
{ version: 4
, header_length: 5
, diffserv: 32
, total_length: 60
, identification: 0
, flags: { reserved: 0, df: 1, mf: 0 }
, fragment_offset: 0
, ttl: 48
, protocol: 6
, header_checksum: 22900
, saddr: '97.107.132.72'
, daddr: '10.240.0.133'
, protocol_name: 'TCP'
, tcp:
{ sport: 80
, dport: 57230
, seqno: 1042874392
, ackno: 973076764
, data_offset: 10
, reserved: 0
, flags:
{ cwr: 0
, ece: 0
, urg: 0
, ack: 1
, psh: 0
, rst: 0
, syn: 1
, fin: 0
}
, window_size: 5792
, checksum: 35930
, urgent_pointer: 0
, payload_offset: 74
, payload: { length: 0 }
}
}
}
, pcap_header:
{ time: Sat, 22 May 2010 07:48:40 GMT
, tv_sec: 1274514520
, tv_usec: 915980
, caplen: 74
, len: 74
, link_type: 'LINKTYPE_ETHERNET'
}
}
Third packet, TCP ACK, 3-way handshake is now complete:
{ ethernet:
{ dhost: '00:18:39:ff:f9:1c'
, shost: '00:1f:5b:ce:3e:29'
, ethertype: 2048
, ip:
{ version: 4
, header_length: 5
, diffserv: 0
, total_length: 52
, identification: 39874
, flags: { reserved: 0, df: 1, mf: 0 }
, fragment_offset: 0
, ttl: 64
, protocol: 6
, header_checksum: 44505
, saddr: '10.240.0.133'
, daddr: '97.107.132.72'
, protocol_name: 'TCP'
, tcp:
{ sport: 57230
, dport: 80
, seqno: 4179361823
, ackno: 1540242985
, data_offset: 8
, reserved: 0
, flags:
{ cwr: 0
, ece: 0
, urg: 0
, ack: 1
, psh: 0
, rst: 0
, syn: 0
, fin: 0
}
, window_size: 65535
, checksum: 53698
, urgent_pointer: 0
, payload_offset: 66
, payload: { length: 0 }
}
}
}
, pcap_header:
{ time: Sat, 22 May 2010 07:48:40 GMT
, tv_sec: 1274514520
, tv_usec: 916054
, caplen: 66
, len: 66
, link_type: 'LINKTYPE_ETHERNET'
}
}
## Help Wanted
I want to build up decoders and printers for all popular protocols. Patches are welcome.
## LICENSE - "MIT License"

@@ -475,0 +201,0 @@

@@ -112,4 +112,4 @@ var EventEmitter = require("events").EventEmitter;

this.send_next_seq = tcp.seqno + 1;
this.send_bytes_ip = ip.header_bytes;
this.send_bytes_tcp = tcp.header_bytes;
this.send_bytes_ip = ip.headerLength;
this.send_bytes_tcp = tcp.headerLength;
} else if (tcp.flags.syn && !tcp.flags.ack) {

@@ -128,4 +128,4 @@ this.emit("syn retry", this);

if (src === this.dst && tcp.flags.syn && tcp.flags.ack) {
this.recv_bytes_ip += ip.header_bytes;
this.recv_bytes_tcp += tcp.header_bytes;
this.recv_bytes_ip += ip.headerLength;
this.recv_bytes_tcp += tcp.headerLength;
this.recv_packets[tcp.seqno + 1] = this.current_cap_time;

@@ -150,4 +150,4 @@ this.recv_acks[tcp.ackno] = this.current_cap_time;

if (src === this.src && tcp.flags.ack) { // TODO - make sure SYN flag isn't set, also match src and dst
this.send_bytes_ip += ip.header_bytes;
this.send_bytes_tcp += tcp.header_bytes;
this.send_bytes_ip += ip.headerLength;
this.send_bytes_tcp += tcp.headerLength;
this.send_acks[tcp.ackno] = this.current_cap_time;

@@ -175,11 +175,11 @@ this.connect_time = this.current_cap_time;

if (src === this.src) { // this packet came from the active opener / client
this.send_bytes_ip += ip.header_bytes;
this.send_bytes_tcp += tcp.header_bytes;
if (tcp.data_bytes) {
if (this.send_packets[tcp.seqno + tcp.data_bytes]) {
this.emit("retransmit", this, "send", tcp.seqno + tcp.data_bytes);
if (this.send_retrans[tcp.seqno + tcp.data_bytes]) {
this.send_retrans[tcp.seqno + tcp.data_bytes] += 1;
this.send_bytes_ip += ip.headerLength;
this.send_bytes_tcp += tcp.headerLength;
if (tcp.dataLength > 0) {
if (this.send_packets[tcp.seqno + tcp.dataLength]) {
this.emit("retransmit", this, "send", tcp.seqno + tcp.dataLength);
if (this.send_retrans[tcp.seqno + tcp.dataLength]) {
this.send_retrans[tcp.seqno + tcp.dataLength] += 1;
} else {
this.send_retrans[tcp.seqno + tcp.data_bytes] = 1;
this.send_retrans[tcp.seqno + tcp.dataLength] = 1;
}

@@ -189,4 +189,4 @@ } else {

}
this.send_bytes_payload += tcp.data_bytes;
this.send_packets[tcp.seqno + tcp.data_bytes] = this.current_cap_time;
this.send_bytes_payload += tcp.dataLength;
this.send_packets[tcp.seqno + tcp.dataLength] = this.current_cap_time;
}

@@ -201,11 +201,11 @@ if (this.recv_packets[tcp.ackno]) {

} else if (src === this.dst) { // this packet came from the passive opener / server
this.recv_bytes_ip += ip.header_bytes;
this.recv_bytes_tcp += tcp.header_bytes;
if (tcp.data_bytes) {
if (this.recv_packets[tcp.seqno + tcp.data_bytes]) {
this.emit("retransmit", this, "recv", tcp.seqno + tcp.data_bytes);
if (this.recv_retrans[tcp.seqno + tcp.data_bytes]) {
this.recv_retrans[tcp.seqno + tcp.data_bytes] += 1;
this.recv_bytes_ip += ip.headerLength;
this.recv_bytes_tcp += tcp.headerLength;
if (tcp.dataLength > 0) {
if (this.recv_packets[tcp.seqno + tcp.dataLength]) {
this.emit("retransmit", this, "recv", tcp.seqno + tcp.dataLength);
if (this.recv_retrans[tcp.seqno + tcp.dataLength]) {
this.recv_retrans[tcp.seqno + tcp.dataLength] += 1;
} else {
this.recv_retrans[tcp.seqno + tcp.data_bytes] = 1;
this.recv_retrans[tcp.seqno + tcp.dataLength] = 1;
}

@@ -215,4 +215,4 @@ } else {

}
this.recv_bytes_payload += tcp.data_bytes;
this.recv_packets[tcp.seqno + tcp.data_bytes] = this.current_cap_time;
this.recv_bytes_payload += tcp.dataLength;
this.recv_packets[tcp.seqno + tcp.dataLength] = this.current_cap_time;
}

@@ -281,3 +281,3 @@ if (this.send_packets[tcp.ackno]) {

TCPSession.prototype.CLOSED = function (packet) {
TCPSession.prototype.CLOSED = function (/*packet*/) {
// not sure what to do here. We are closed, so I guess bump some counters or something.

@@ -284,0 +284,0 @@ };

@@ -8,8 +8,2 @@ function lpad(str, len) {

exports.dump_bytes = function dump_bytes(raw_packet, offset) {
for (var i = offset; i < raw_packet.pcap_header.caplen ; i += 1) {
console.log(i + ": " + raw_packet[i]);
}
};
var int8_to_hex = [];

@@ -16,0 +10,0 @@ var int8_to_hex_nopad = [];

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc