Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 501 lines (397 sloc) 19.359 kB
b567b74 @mranney Add simple README
authored
1 node_pcap
2 =========
3
58701b8 @mranney Add some actual documentation and some updated examples.
authored
4 This is a set of bindings from `libpcap` to node as well as some useful libraries to decode, print, and
5 analyze packets. `libpcap` is a packet capture library used by programs like `tcpdump` and `wireshark`.
6 It has been tested on OSX and Linux.
b567b74 @mranney Add simple README
authored
7
ab2145e @mranney Documentation updates.
authored
8 `node_pcap` is useful for many things, but it does not yet understand all common protocols. A popular reason
9 to use this package is `examples/http_trace`, described below.
58701b8 @mranney Add some actual documentation and some updated examples.
authored
10
0ccd603 @mranney Mention @mnot's htracr.
authored
11 Another great reason to use `node_pcap` is
12 [htracr](https://github.com/mnot/htracr), written by Mark Nottingham.
13
14 ## Why capture packets in JavaScript?
58701b8 @mranney Add some actual documentation and some updated examples.
authored
15
16 There are already many tools for capturing, decoding, and analyzing packets. Many of them are thoroughly
0ccd603 @mranney Mention @mnot's htracr.
authored
17 tested and very fast. Why would anybody want to do such low level things like packet capture and analysis
18 in JavaScript? A few reasons:
58701b8 @mranney Add some actual documentation and some updated examples.
authored
19
20 * JavaScript makes writing event-based programs very natural. Each packet that is captured generates an
21 event, and as higher level protocols are decoded, they might generate events as well. Writing code to handle
22 these events is much easier and more readable with anonymous functions and closures.
23
24 * node makes handling binary data in JavaScript fast and efficient with its Buffer class. Decoding packets involves
25 a lot of binary slicing and dicing which can be awkward with JavaScript strings.
26
27 * Writing servers that capture packets, process them somehow, and then serve the processed data up in some way is
28 very straightforward in node.
29
0ebc243 @mranney Improve error messages and documentation.
authored
30 * Node has a very good HTTP parser that is used to progressively decode HTTP sessions.
b567b74 @mranney Add simple README
authored
31
3054c0e @mranney Add installation example
authored
32 ## Installation
33
34 You will need `libpcap` installed. Most OSX machines seem to have it. All major Linux distributions have it available
35 either by default or with a package like `libpcap-dev`.
36
878080a @mranney Update installation instructions.
authored
37 The easiest way to get `node_pcap` and its tools is with `npm`:
38
39 npm install pcap
40
41 If you want to hack on the source code, you can get it from github. Clone the repo like this:
3054c0e @mranney Add installation example
authored
42
43 git clone git://github.com/mranney/node_pcap.git
44
45 To compile the native code bindings, do this:
46
47 cd node_pcap
48 node-waf configure build
49
50 Assuming it built without errors, you should be able to run the examples and then write your own packet
51 capture programs.
52
b567b74 @mranney Add simple README
authored
53
06423e3 @mranney Update examples.
authored
54 ## Usage
b567b74 @mranney Add simple README
authored
55
58701b8 @mranney Add some actual documentation and some updated examples.
authored
56 There are several example programs that show how to use `node_pcap`. These examples are best documentation.
57 Try them out and see what they do.
58
35011ae @mranney Documentation updates for TCP_tracker events
authored
59 To use this library in your own program, `pcap.js` and `pcap_binding.node` must be in `NODE_PATH`. `npm`
0ebc243 @mranney Improve error messages and documentation.
authored
60 takes care of this automatically.
61
35011ae @mranney Documentation updates for TCP_tracker events
authored
62 ### Starting a capture session
63
64 To start a capture session, call `pcap.createSession` with an interface name and a pcap filter string:
58701b8 @mranney Add some actual documentation and some updated examples.
authored
65
0ebc243 @mranney Improve error messages and documentation.
authored
66 var pcap = require('pcap'),
58701b8 @mranney Add some actual documentation and some updated examples.
authored
67 pcap_session = pcap.createSession(interface, filter);
68
69 `interface` is the name of the interface on which to capture packets. If passed an empty string, `libpcap`
0ebc243 @mranney Improve error messages and documentation.
authored
70 will try to pick a "default" interface, which is often just the first one in some list and not what you want.
58701b8 @mranney Add some actual documentation and some updated examples.
authored
71
72 `fitler` is a pcap filter expression, see `pcap-filter(7)` for more information. An empty string will capture
73 all packets visible on the interface.
06423e3 @mranney Update examples.
authored
74
35011ae @mranney Documentation updates for TCP_tracker events
authored
75 Note that `node_pcap` always opens the interface in promiscuous mode, which generally requires running as root.
76 Unless you are recklessly roaming about as root already, you'll probably want to start your node program like this:
77
78 sudo node test.js
79
58701b8 @mranney Add some actual documentation and some updated examples.
authored
80 `pcap_session` is an `EventEmitter` that emits a `packet` event. The only argument to the callback will be a
81 `Buffer` object with the raw bytes returned by `libpcap`.
82
83 Listening for packets:
84
35011ae @mranney Documentation updates for TCP_tracker events
authored
85 pcap_session.on('packet', function (raw_packet) {
58701b8 @mranney Add some actual documentation and some updated examples.
authored
86 // do some stuff with a raw packet
06423e3 @mranney Update examples.
authored
87 });
b567b74 @mranney Add simple README
authored
88
35011ae @mranney Documentation updates for TCP_tracker events
authored
89 To convert `raw_packet` into a JavaScript object that is easy to work with, decode it:
58701b8 @mranney Add some actual documentation and some updated examples.
authored
90
91 var packet = pcap.decode.packet(raw_packet);
92
93 The protocol stack is exposed as a nested set of objects. For example, the TCP destination port is part of TCP
94 which is encapsulated within IP, which is encapsulated within a link layer. Access it like this:
95
96 packet.link.ip.tcp.dport
ad9d634 @mranney Update examples and show payload dump.
authored
97
58701b8 @mranney Add some actual documentation and some updated examples.
authored
98 This structure is easy to explore with `sys.inspect`.
ad9d634 @mranney Update examples and show payload dump.
authored
99
35011ae @mranney Documentation updates for TCP_tracker events
authored
100 ### TCP Analysis
101
102 TCP can be analyzed by feeding the packets into a `TCP_tracker` and then listening for `start` and `end` events.
103
104 var pcap = require('pcap'),
105 tcp_tracker = new pcap.TCP_tracker(),
106 pcap_session = pcap.createSession(interface, "ip proto \tcp");
107
108 tcp_tracker.on('start', function (session) {
109 console.log("Start of TCP session between " + session.src_name + " and " + session.dst_name);
110 });
111
112 tcp_tracker.on('end', function (session) {
113 console.log("End of TCP session between " + session.src_name + " and " + session.dst_name);
114 });
115
116 pcap_session.on('packet', function (raw_packet) {
117 var packet = pcap.decode.packet(raw_packet);
118 tcp_tracker.track_packet(packet);
119 });
120
121 You must only send IPv4 TCP packets to the TCP tracker. Explore the `session` object with `sys.inspect` to
122 see the wonderful things it can do for you. Hopefully the names of the properties are self-explanatory:
123
124 { src: '10.51.2.130:55965'
125 , dst: '75.119.207.0:80'
126 , syn_time: 1280425738896.771
127 , state: 'ESTAB'
128 , key: '10.51.2.130:55965-75.119.207.0:80'
129 , send_isn: 2869922608
130 , send_window_scale: 8
131 , send_packets: { '2869922609': 1280425738896.771 }
132 , send_acks: { '1063203923': 1280425738911.618 }
133 , send_retrans: {}
134 , send_next_seq: 2869922609
135 , send_acked_seq: null
136 , send_bytes_ip: 60
137 , send_bytes_tcp: 108
138 , send_bytes_payload: 144
139 , recv_isn: 1063203922
140 , recv_window_scale: 128
141 , recv_packets: { '1063203923': 1280425738911.536 }
142 , recv_acks: { '2869922609': 1280425738911.536 }
143 , recv_retrans: {}
144 , recv_next_seq: null
145 , recv_acked_seq: null
146 , recv_bytes_ip: 20
147 , recv_bytes_tcp: 40
148 , recv_bytes_payload: 0
149 , src_name: '10.51.2.130:55965'
150 , dst_name: '75.119.207.0:80'
151 , current_cap_time: 1280425738911.65
152
153 ### HTTP Analysis
154
155 The `TCP_tracker` also detects and decodes HTTP on all streams it receives. If HTTP is detected, several
7f16837 @mranney Documentation updates for HTTP events.
authored
156 new events will be emitted:
157
158 * `http_request`: function(session, http)
159 * `http_request_body`: function(session, http, data)
160
161 Note that `data` is a node Buffer object sliced from the original packet. If you want to use it past the
162 current tick, you'll need to make a copy somehow.
163
164 * `http_request_complete`: function(session, http)
165 * `http_response`: function(session, http)
166 * `http_response_body`: function(session, http, data)
167
168 `data` is a Buffer slice. See above.
169
170 * `http_response_complete`: function(session, http)
35011ae @mranney Documentation updates for TCP_tracker events
authored
171
172 See `examples/http_trace` for an example of how to use these events to decode HTTP.
173
174 ### WebSocket Analysis
175
176 The `TCP_tracker` further detects and decodes WebSocket traffic on all streams it receives.
177
178 * `websocket_upgrade`: function(session, http)
179 * `websocket_message`: function(session, dir, message)
180
181 See `examples/http_trace` for an example of how to use these events to decode WebSocket.
ad9d634 @mranney Update examples and show payload dump.
authored
182
0ebc243 @mranney Improve error messages and documentation.
authored
183
184 ## Some Common Problems
185
186 ### TCP Segmentation Offload - TSO
187
188 TSO is a technique that modern operating systems use to offload the burden of IP/TCP header computation to
189 the network hardware. It also reduces the number of times that data is moved data between the kernel and the
190 network hardware. TSO saves CPU when sending data that is larger than a single IP packet.
191
192 This is amazing and wonderful, but it does make some kinds of packet sniffing more difficult. In many cases,
193 it is important to see the exact packets that are sent, but if the network hardware is sending the packets,
194 these are not available to `libpcap`. The solution is to disable TSO.
195
196 OSX:
197
198 sudo sysctl -w net.inet.tcp.tso=0
199
200 Linux (substitute correct interface name):
201
202 sudo ethtool -K eth0 tso off
203
204 The symptoms of needing to disable TSO are messages like, "Received ACK for packet we didn't see get sent".
205
206 ### IPv6
207
208 Sadly, `node_pcap` does not know how to decode IPv6 packets yet. Often when capturing traffic to `localhost`, IPv6 traffic
209 will arrive surprisingly, even though you were expecting IPv4. A common case is the hostname `localhost`, which many client programs will
210 resolve to the IPv6 address `::1` and then will try `127.0.0.1`. Until we get IPv6 decode support, a `libpcap` filter can be
211 set to only see IPv4 traffic:
212
35011ae @mranney Documentation updates for TCP_tracker events
authored
213 sudo http_trace lo0 "ip proto \tcp"
0ebc243 @mranney Improve error messages and documentation.
authored
214
215 The backslash is important. The pcap filter language has an ambiguity with the word "tcp", so by escaping it,
216 you'll get the correct interpretation for this case.
217
218 ### Dropped packets
219
220 There are several levels of buffering involved in capturing packets. Sometimes these buffers fill up, and
221 you'll drop packets. If this happens, it becomes difficult to reconstruct higher level protocols. The best
222 way to keep the buffers from filling up is to use pcap filters to only consider traffic that you need to decode.
223 The pcap filters are very efficient and run close to the kernel where they can process high packet rates.
224
225 If the pcap filters are set correctly and `libpcap` still drops packets, it is possible to increase `libpcap`'s
226 buffer size. At the moment, this requires changing `pcap_binding.cc`. Look for `pcap_set_buffer_size()` and
227 set to a larger value.
3663bd0 @mranney Add http_trace.js example.
authored
228
46b1ea7 @mranney Update docs for http_trace slightly and add image.
authored
229 ## examples/http_trace
230
6f43642 @mranney Support for WebSocket decoding and printing
authored
231 This is a handy standalone program that can help diagnose HTTP and WebSocket traffic.
3663bd0 @mranney Add http_trace.js example.
authored
232
233 The TCP tracker looks for HTTP at the beginning of every TCP connection. If found, all captured on this connection
46b1ea7 @mranney Update docs for http_trace slightly and add image.
authored
234 will be fed to node's HTTP parser and events will be generated. `http_trace` has listeners for these events and will
235 print out some helpful information.
236
6f43642 @mranney Support for WebSocket decoding and printing
authored
237 If a WebSocket upgrade is detected, `http_trace` will start looking for WebSocket messages on that connection.
238
a86e1fa @mranney Fix image URL.
authored
239 ![http_trace screenshot](http://ranney.com/httptrace.jpg)
46b1ea7 @mranney Update docs for http_trace slightly and add image.
authored
240
241
242 ## examples/simple_capture
58701b8 @mranney Add some actual documentation and some updated examples.
authored
243
35011ae @mranney Documentation updates for TCP_tracker events
authored
244 This program captures packets and prints them using the built in simple printer. Here's a sample of it's output.
58701b8 @mranney Add some actual documentation and some updated examples.
authored
245 In another window I ran `curl nodejs.org`.
246
247 mjr:~/work/node_pcap$ sudo node examples/simple_capture.js en1 ""
248 libpcap version 1.0.0
249 en0 no address
250 * en1 10.240.0.133/255.255.255.0
251 lo0 127.0.0.1/255.0.0.0
252 00:18:39:ff:f9:1c -> 00:1f:5b:ce:3e:29 10.240.0.1 ARP request 10.240.0.133
253 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
254 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
255 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
256 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
257 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
258 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
259 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
260 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
261 00:18:39:ff:f9:1c -> 00:1f:5b:ce:3e:29 tinyclouds.org:80 -> rv-mjr2.ranney.com:53808 TCP len 60
262 00:1f:5b:ce:3e:29 -> 00:18:39:ff:f9:1c rv-mjr2.ranney.com:53808 -> tinyclouds.org:80 TCP len 52
263 00:1f:5b:ce:3e:29 -> 00:18:39:ff:f9:1c rv-mjr2.ranney.com:53808 -> tinyclouds.org:80 TCP len 196
264 00:18:39:ff:f9:1c -> 00:1f:5b:ce:3e:29 tinyclouds.org:80 -> rv-mjr2.ranney.com:53808 TCP len 52
265 00:18:39:ff:f9:1c -> 00:1f:5b:ce:3e:29 tinyclouds.org:80 -> rv-mjr2.ranney.com:53808 TCP len 1500
266 00:18:39:ff:f9:1c -> 00:1f:5b:ce:3e:29 tinyclouds.org:80 -> rv-mjr2.ranney.com:53808 TCP len 1500
267 00:1f:5b:ce:3e:29 -> 00:18:39:ff:f9:1c rv-mjr2.ranney.com:53808 -> tinyclouds.org:80 TCP len 52
268 00:18:39:ff:f9:1c -> 00:1f:5b:ce:3e:29 tinyclouds.org:80 -> rv-mjr2.ranney.com:53808 TCP len 1500
269 00:1f:5b:ce:3e:29 -> 00:18:39:ff:f9:1c rv-mjr2.ranney.com:53808 -> tinyclouds.org:80 TCP len 52
270 00:18:39:ff:f9:1c -> 00:1f:5b:ce:3e:29 tinyclouds.org:80 -> rv-mjr2.ranney.com:53808 TCP len 1500
271 00:18:39:ff:f9:1c -> 00:1f:5b:ce:3e:29 tinyclouds.org:80 -> rv-mjr2.ranney.com:53808 TCP len 1500
272 00:1f:5b:ce:3e:29 -> 00:18:39:ff:f9:1c rv-mjr2.ranney.com:53808 -> tinyclouds.org:80 TCP len 52
273 00:18:39:ff:f9:1c -> 00:1f:5b:ce:3e:29 tinyclouds.org:80 -> rv-mjr2.ranney.com:53808 TCP len 1500
274 00:1f:5b:ce:3e:29 -> 00:18:39:ff:f9:1c rv-mjr2.ranney.com:53808 -> tinyclouds.org:80 TCP len 52
275 00:18:39:ff:f9:1c -> 00:1f:5b:ce:3e:29 tinyclouds.org:80 -> rv-mjr2.ranney.com:53808 TCP len 1500
276 00:18:39:ff:f9:1c -> 00:1f:5b:ce:3e:29 tinyclouds.org:80 -> rv-mjr2.ranney.com:53808 TCP len 337
277 00:1f:5b:ce:3e:29 -> 00:18:39:ff:f9:1c rv-mjr2.ranney.com:53808 -> tinyclouds.org:80 TCP len 52
278 00:1f:5b:ce:3e:29 -> 00:18:39:ff:f9:1c rv-mjr2.ranney.com:53808 -> tinyclouds.org:80 TCP len 52
279 00:1f:5b:ce:3e:29 -> 00:18:39:ff:f9:1c rv-mjr2.ranney.com:53808 -> tinyclouds.org:80 TCP len 52
280 00:18:39:ff:f9:1c -> 00:1f:5b:ce:3e:29 tinyclouds.org:80 -> rv-mjr2.ranney.com:53808 TCP len 52
281 00:1f:5b:ce:3e:29 -> 00:18:39:ff:f9:1c rv-mjr2.ranney.com:53808 -> tinyclouds.org:80 TCP len 52
ad9d634 @mranney Update examples and show payload dump.
authored
282
283
284 ## Output from `session.findalldevs`:
b567b74 @mranney Add simple README
authored
285
286 [ { name: 'en0'
287 , addresses:
288 [ { addr: '10.51.2.183'
289 , netmask: '255.255.255.0'
290 , broadaddr: '10.51.2.255'
291 }
292 ]
293 }
294 , { name: 'fw0', addresses: [] }
295 , { name: 'en1', addresses: [] }
296 , { name: 'lo0'
297 , addresses: [ { addr: '127.0.0.1', netmask: '255.0.0.0' } ]
298 , flags: 'PCAP_IF_LOOPBACK'
299 }
300 ]
301
302
58701b8 @mranney Add some actual documentation and some updated examples.
authored
303 ### Deep decode of `curl nodejs.org`:
304
305 Running `sys.inspect` on the first three decoded packets of this TCP session.
b9a7d4a @mranney Update example output.
authored
306
307 First packet, TCP SYN:
308
309 { ethernet:
310 { dhost: '00:18:39:ff:f9:1c'
311 , shost: '00:1f:5b:ce:3e:29'
312 , ethertype: 2048
313 , ip:
314 { version: 4
315 , header_length: 5
316 , diffserv: 0
317 , total_length: 64
318 , identification: 49042
319 , flags: { reserved: 0, df: 1, mf: 0 }
320 , fragment_offset: 0
321 , ttl: 64
322 , protocol: 6
323 , header_checksum: 35325
324 , saddr: '10.240.0.133'
325 , daddr: '97.107.132.72'
326 , protocol_name: 'TCP'
327 , tcp:
328 { sport: 57230
329 , dport: 80
330 , seqno: 4179361823
331 , ackno: 1540242985
332 , data_offset: 11
333 , reserved: 0
334 , flags:
335 { cwr: 0
336 , ece: 0
337 , urg: 0
338 , ack: 0
339 , psh: 0
340 , rst: 0
341 , syn: 1
342 , fin: 0
343 }
344 , window_size: 65535
345 , checksum: 2601
346 , urgent_pointer: 0
347 , payload_offset: 78
348 , payload: { length: 0 }
349 }
350 }
351 }
352 , pcap_header:
353 { time: Sat, 22 May 2010 07:48:40 GMT
354 , tv_sec: 1274514520
355 , tv_usec: 820479
356 , caplen: 78
357 , len: 78
358 , link_type: 'LINKTYPE_ETHERNET'
359 }
b567b74 @mranney Add simple README
authored
360 }
b9a7d4a @mranney Update example output.
authored
361
362 Second packet, TCP SYN+ACK:
363
364 { ethernet:
365 { dhost: '00:1f:5b:ce:3e:29'
366 , shost: '00:18:39:ff:f9:1c'
367 , ethertype: 2048
368 , ip:
369 { version: 4
370 , header_length: 5
371 , diffserv: 32
372 , total_length: 60
373 , identification: 0
374 , flags: { reserved: 0, df: 1, mf: 0 }
375 , fragment_offset: 0
376 , ttl: 48
377 , protocol: 6
378 , header_checksum: 22900
379 , saddr: '97.107.132.72'
380 , daddr: '10.240.0.133'
381 , protocol_name: 'TCP'
382 , tcp:
383 { sport: 80
384 , dport: 57230
385 , seqno: 1042874392
386 , ackno: 973076764
387 , data_offset: 10
388 , reserved: 0
389 , flags:
390 { cwr: 0
391 , ece: 0
392 , urg: 0
393 , ack: 1
394 , psh: 0
395 , rst: 0
396 , syn: 1
397 , fin: 0
398 }
399 , window_size: 5792
400 , checksum: 35930
401 , urgent_pointer: 0
402 , payload_offset: 74
403 , payload: { length: 0 }
404 }
405 }
406 }
407 , pcap_header:
408 { time: Sat, 22 May 2010 07:48:40 GMT
409 , tv_sec: 1274514520
410 , tv_usec: 915980
411 , caplen: 74
412 , len: 74
413 , link_type: 'LINKTYPE_ETHERNET'
414 }
06423e3 @mranney Update examples.
authored
415 }
b9a7d4a @mranney Update example output.
authored
416
417 Third packet, TCP ACK, 3-way handshake is now complete:
418
419 { ethernet:
420 { dhost: '00:18:39:ff:f9:1c'
421 , shost: '00:1f:5b:ce:3e:29'
422 , ethertype: 2048
423 , ip:
424 { version: 4
425 , header_length: 5
426 , diffserv: 0
427 , total_length: 52
428 , identification: 39874
429 , flags: { reserved: 0, df: 1, mf: 0 }
430 , fragment_offset: 0
431 , ttl: 64
432 , protocol: 6
433 , header_checksum: 44505
434 , saddr: '10.240.0.133'
435 , daddr: '97.107.132.72'
436 , protocol_name: 'TCP'
437 , tcp:
438 { sport: 57230
439 , dport: 80
440 , seqno: 4179361823
441 , ackno: 1540242985
442 , data_offset: 8
443 , reserved: 0
444 , flags:
445 { cwr: 0
446 , ece: 0
447 , urg: 0
448 , ack: 1
449 , psh: 0
450 , rst: 0
451 , syn: 0
452 , fin: 0
453 }
454 , window_size: 65535
455 , checksum: 53698
456 , urgent_pointer: 0
457 , payload_offset: 66
458 , payload: { length: 0 }
459 }
460 }
461 }
462 , pcap_header:
463 { time: Sat, 22 May 2010 07:48:40 GMT
464 , tv_sec: 1274514520
465 , tv_usec: 916054
466 , caplen: 66
467 , len: 66
468 , link_type: 'LINKTYPE_ETHERNET'
469 }
470 }
471
0ebc243 @mranney Improve error messages and documentation.
authored
472 ## Help Wanted
473
7f16837 @mranney Documentation updates for HTTP events.
authored
474 I want to build up decoders and printers for all popular protocols. Patches are welcome.
0ebc243 @mranney Improve error messages and documentation.
authored
475
476
31a0616 @mranney Decode ARP.
authored
477 ## LICENSE - "MIT License"
478
479 Copyright (c) 2010 Matthew Ranney, http://ranney.com/
480
481 Permission is hereby granted, free of charge, to any person
482 obtaining a copy of this software and associated documentation
483 files (the "Software"), to deal in the Software without
484 restriction, including without limitation the rights to use,
485 copy, modify, merge, publish, distribute, sublicense, and/or sell
486 copies of the Software, and to permit persons to whom the
487 Software is furnished to do so, subject to the following
488 conditions:
489
490 The above copyright notice and this permission notice shall be
491 included in all copies or substantial portions of the Software.
492
493 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
494 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
495 OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
496 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
497 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
498 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
499 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
500 OTHER DEALINGS IN THE SOFTWARE.
Something went wrong with that request. Please try again.