ruby-pcap 0.7.9 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.github/workflows/build.yml +26 -0
- data/README.md +3 -7
- data/examples/capture_duration.rb +28 -0
- data/ext/pcap/Pcap.c +152 -23
- data/ext/pcap/arp_packet.c +82 -0
- data/ext/pcap/icmp_packet.c +35 -0
- data/ext/pcap/icmpv6_packet.c +107 -0
- data/ext/pcap/ip_packet.c +16 -7
- data/ext/pcap/ipv6_packet.c +162 -0
- data/ext/pcap/packet.c +36 -8
- data/ext/pcap/ruby_pcap.h +34 -4
- data/ext/pcap/slow_protocol_packet.c +29 -0
- data/ext/pcap/tcp_packet.c +346 -6
- data/ext/pcap/udp_packet.c +262 -1
- data/lib/pcap/packet.rb +123 -11
- data/ruby-pcap.gemspec +4 -4
- metadata +16 -10
- data/.travis.yml +0 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 0c416ece1a8344e1f07c5170957aab941a4670eb422727dce36fc5c346db048f
|
4
|
+
data.tar.gz: 4b8f52b6059947608699b8fa125351990504ac027b8fdbf47780e76809885a99
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c82fc770ddec96e61b75b099991a33a59d9fca0a575958d5101aff095acd4e81242c09d8a22a773a2b2348a9c7dcae23fed9d9f458179d57e6ffc626c7f4d6bf
|
7
|
+
data.tar.gz: cc556bf0383bf6babec625a01db347ea421894d67f45d0f69c33b3e9d847cda66abf60b1ede6c1ee8ce6186846e1cec4f2324ed74bb0e54603c785576079af40
|
@@ -0,0 +1,26 @@
|
|
1
|
+
name: build
|
2
|
+
on:
|
3
|
+
push:
|
4
|
+
branches:
|
5
|
+
- master
|
6
|
+
pull_request:
|
7
|
+
branches:
|
8
|
+
- master
|
9
|
+
jobs:
|
10
|
+
build:
|
11
|
+
runs-on: ubuntu-latest
|
12
|
+
strategy:
|
13
|
+
matrix:
|
14
|
+
ruby-version: ['3.1', '3.0', '2.7','2.4','2.1']
|
15
|
+
steps:
|
16
|
+
- uses: actions/checkout@v2
|
17
|
+
- name: Set up ruby ${{ matrix.ruby_version}}
|
18
|
+
uses: ruby/setup-ruby@v1
|
19
|
+
with:
|
20
|
+
ruby-version: ${{ matrix.ruby-version }}
|
21
|
+
- name: Install system libs dependencies
|
22
|
+
run: sudo apt-get update -qq && sudo apt-get install -y libpcap-dev
|
23
|
+
- name: Get deps
|
24
|
+
run: bundle install
|
25
|
+
- name: Build it
|
26
|
+
run: bundle exec rake
|
data/README.md
CHANGED
@@ -1,6 +1,7 @@
|
|
1
|
+
|
1
2
|
## ruby-pcap
|
2
3
|
|
3
|
-
[](https://github.com/vitoshalabs/ruby-pcap/actions/workflows/build.yml)
|
4
5
|
|
5
6
|
ruby-pcap is a ruby extension to LBL libpcap (Packet Capture library).
|
6
7
|
This library also includes classes to access TCP/IP header.
|
@@ -13,8 +14,7 @@ gem install ruby-pcap
|
|
13
14
|
|
14
15
|
### Requirements
|
15
16
|
|
16
|
-
* ruby-1
|
17
|
-
* May work with older ruby version but not being tested
|
17
|
+
* ruby-2.1 or higher
|
18
18
|
* libpcap (http://www.tcpdump.org/)
|
19
19
|
|
20
20
|
## Usage
|
@@ -26,10 +26,6 @@ Directory 'examples' contains some simple scripts.
|
|
26
26
|
|
27
27
|
Masaki Fukushima <fukusima@goto.info.waseda.ac.jp>
|
28
28
|
|
29
|
-
## Maintained by
|
30
|
-
|
31
|
-
Marcus Barczak <mbarczak@etsy.com>
|
32
|
-
|
33
29
|
## Copyright
|
34
30
|
|
35
31
|
ruby-pcap is copyrighted free software by Masaki Fukushima.
|
@@ -0,0 +1,28 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'pcap'
|
5
|
+
require 'pcap/pcaplet'
|
6
|
+
|
7
|
+
iface = ARGV[0] || 'en0'
|
8
|
+
duration = (ARGV[1] || 10).to_i
|
9
|
+
count = 0
|
10
|
+
capture = Pcap::Capture.open_live(iface, 65_535, true)
|
11
|
+
Thread.new do
|
12
|
+
sleep duration
|
13
|
+
if capture.closed?
|
14
|
+
puts 'device is already closed!'
|
15
|
+
else
|
16
|
+
puts 'signaling OS to stop capture!'
|
17
|
+
capture.breakloop
|
18
|
+
end
|
19
|
+
end
|
20
|
+
puts "starting capture on #{iface} for #{duration} seconds"
|
21
|
+
start_time = Time.now
|
22
|
+
capture.loop do |pkt|
|
23
|
+
puts "Got #{pkt}"
|
24
|
+
count += 1
|
25
|
+
end
|
26
|
+
capture.close
|
27
|
+
end_time = Time.now
|
28
|
+
puts "packets count #{count} completed in #{end_time - start_time} seconds"
|
data/ext/pcap/Pcap.c
CHANGED
@@ -7,7 +7,6 @@
|
|
7
7
|
*/
|
8
8
|
|
9
9
|
#include "ruby_pcap.h"
|
10
|
-
#include "rubysig.h"
|
11
10
|
#include <sys/time.h>
|
12
11
|
#include <sys/types.h>
|
13
12
|
#include <unistd.h>
|
@@ -309,6 +308,19 @@ capture_close(self)
|
|
309
308
|
return Qnil;
|
310
309
|
}
|
311
310
|
|
311
|
+
static VALUE
|
312
|
+
is_capture_closed(self)
|
313
|
+
VALUE self;
|
314
|
+
{
|
315
|
+
struct capture_object *cap;
|
316
|
+
DEBUG_PRINT("is_capture_closed");
|
317
|
+
Data_Get_Struct(self, struct capture_object, cap);
|
318
|
+
if (cap->pcap == NULL) {
|
319
|
+
return Qtrue;
|
320
|
+
}
|
321
|
+
return Qfalse;
|
322
|
+
}
|
323
|
+
|
312
324
|
static void
|
313
325
|
handler(cap, pkthdr, data)
|
314
326
|
struct capture_object *cap;
|
@@ -318,36 +330,112 @@ handler(cap, pkthdr, data)
|
|
318
330
|
rb_yield(new_packet(data, pkthdr, cap->dl_type));
|
319
331
|
}
|
320
332
|
|
333
|
+
#define DST_ADDR(data) INT2FIX(ntohl(*((unsigned int *) (data + 30))))
|
334
|
+
#define SRC_ADDR(data) INT2FIX(ntohl(*((unsigned int *) (data + 26))))
|
335
|
+
|
336
|
+
static void
|
337
|
+
dst_ipv4_addr_handler(cap, pkthdr, data)
|
338
|
+
struct capture_object *cap;
|
339
|
+
const struct pcap_pkthdr *pkthdr;
|
340
|
+
const u_char *data;
|
341
|
+
{
|
342
|
+
rb_yield(DST_ADDR(data));
|
343
|
+
}
|
344
|
+
|
345
|
+
static void
|
346
|
+
src_ipv4_addr_handler(cap, pkthdr, data)
|
347
|
+
struct capture_object *cap;
|
348
|
+
const struct pcap_pkthdr *pkthdr;
|
349
|
+
const u_char *data;
|
350
|
+
{
|
351
|
+
rb_yield(SRC_ADDR(data));
|
352
|
+
}
|
353
|
+
|
354
|
+
#define SRCV6_ADDR(data) rb_integer_unpack((u_char *) (data + 22), 16, 1, 0, INTEGER_PACK_BIG_ENDIAN)
|
355
|
+
#define DSTV6_ADDR(data) rb_integer_unpack((u_char *) (data + 38), 16, 1, 0, INTEGER_PACK_BIG_ENDIAN)
|
356
|
+
|
357
|
+
static void
|
358
|
+
dst_ipv6_addr_handler(cap, pkthdr, data)
|
359
|
+
struct capture_object *cap;
|
360
|
+
const struct pcap_pkthdr *pkthdr;
|
361
|
+
const u_char *data;
|
362
|
+
{
|
363
|
+
rb_yield(DSTV6_ADDR(data));
|
364
|
+
}
|
365
|
+
|
366
|
+
static void
|
367
|
+
src_ipv6_addr_handler(cap, pkthdr, data)
|
368
|
+
struct capture_object *cap;
|
369
|
+
const struct pcap_pkthdr *pkthdr;
|
370
|
+
const u_char *data;
|
371
|
+
{
|
372
|
+
rb_yield(SRCV6_ADDR(data));
|
373
|
+
}
|
374
|
+
|
375
|
+
void parse_opts(VALUE v_opts, void **default_handler)
|
376
|
+
{
|
377
|
+
if (NIL_P(v_opts)) {
|
378
|
+
DEBUG_PRINT("using default capture handler");
|
379
|
+
*default_handler = &handler;
|
380
|
+
} else {
|
381
|
+
// raise error if second argument is not a symbol
|
382
|
+
Check_Type(v_opts, T_SYMBOL);
|
383
|
+
// only :source, :destination are supported
|
384
|
+
if (SYM2ID(v_opts) == rb_intern("source")) {
|
385
|
+
DEBUG_PRINT("yeilding only source ipv4 addresses");
|
386
|
+
*default_handler = &src_ipv4_addr_handler;
|
387
|
+
} else if (SYM2ID(v_opts) == rb_intern("destination")) {
|
388
|
+
DEBUG_PRINT("yeilding only destination ipv4 addresses");
|
389
|
+
*default_handler = &dst_ipv4_addr_handler;
|
390
|
+
} else if (SYM2ID(v_opts) == rb_intern("destinationv6")) {
|
391
|
+
DEBUG_PRINT("yeilding only destination ipv6 addresses");
|
392
|
+
*default_handler = &dst_ipv6_addr_handler;
|
393
|
+
} else if (SYM2ID(v_opts) == rb_intern("sourcev6")) {
|
394
|
+
DEBUG_PRINT("yeilding only source ipv6 addresses");
|
395
|
+
*default_handler = &src_ipv6_addr_handler;
|
396
|
+
} else {
|
397
|
+
// unkonw keyword passed, use default capture handler
|
398
|
+
DEBUG_PRINT("unknown option, using default capture handler");
|
399
|
+
*default_handler = &handler;
|
400
|
+
}
|
401
|
+
}
|
402
|
+
}
|
403
|
+
|
321
404
|
static VALUE
|
322
405
|
capture_dispatch(argc, argv, self)
|
323
406
|
int argc;
|
324
407
|
VALUE *argv;
|
325
408
|
VALUE self;
|
326
409
|
{
|
327
|
-
VALUE v_cnt;
|
328
|
-
int cnt;
|
410
|
+
VALUE v_cnt, v_opts;
|
411
|
+
int ret = 0, cnt = 0;
|
412
|
+
unsigned int cap_cnt = 0;
|
329
413
|
struct capture_object *cap;
|
330
|
-
|
414
|
+
void *default_handler;
|
331
415
|
|
332
416
|
DEBUG_PRINT("capture_dispatch");
|
333
417
|
GetCapture(self, cap);
|
334
418
|
|
335
419
|
/* scan arg */
|
336
|
-
|
337
|
-
|
338
|
-
|
420
|
+
rb_scan_args(argc, argv, "02", &v_cnt, &v_opts);
|
421
|
+
if (NIL_P(v_cnt)) {
|
422
|
+
cnt = -1;
|
339
423
|
} else {
|
340
|
-
|
424
|
+
FIXNUM_P(v_cnt);
|
425
|
+
cnt = FIX2INT(v_cnt);
|
341
426
|
}
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
427
|
+
parse_opts(v_opts, &default_handler);
|
428
|
+
// call dispatch with 10,000 and break if we have reached desired amount
|
429
|
+
// if dispatch is called with -1/0 sometimes it dispatches millions of packets
|
430
|
+
for (cap_cnt = 0; cap_cnt < cnt; cap_cnt += ret ) {
|
431
|
+
MAYBE_TRAP_BEG;
|
432
|
+
ret = pcap_dispatch(cap->pcap, 10000, default_handler, (u_char *)cap);
|
433
|
+
MAYBE_TRAP_END;
|
434
|
+
if (ret < 0) {
|
347
435
|
rb_raise(ePcapError, "dispatch: %s", pcap_geterr(cap->pcap));
|
436
|
+
}
|
348
437
|
}
|
349
|
-
|
350
|
-
return INT2FIX(ret);
|
438
|
+
return UINT2NUM(cap_cnt);
|
351
439
|
}
|
352
440
|
|
353
441
|
static VALUE
|
@@ -367,31 +455,45 @@ capture_fh(argc, argv, self)
|
|
367
455
|
return rb_funcall(rb_path2class("IO"), rb_intern("new"), 1, INT2FIX(pcap_fileno(cap->pcap)));
|
368
456
|
}
|
369
457
|
|
458
|
+
static VALUE
|
459
|
+
capture_breakloop(self)
|
460
|
+
VALUE self;
|
461
|
+
{
|
462
|
+
struct capture_object *cap;
|
463
|
+
|
464
|
+
DEBUG_PRINT("capture_breakloop");
|
465
|
+
GetCapture(self, cap);
|
466
|
+
pcap_breakloop(cap->pcap);
|
467
|
+
return Qnil;
|
468
|
+
}
|
469
|
+
|
370
470
|
static VALUE
|
371
471
|
capture_loop(argc, argv, self)
|
372
472
|
int argc;
|
373
473
|
VALUE *argv;
|
374
474
|
VALUE self;
|
375
475
|
{
|
376
|
-
VALUE v_cnt;
|
476
|
+
VALUE v_cnt, v_opts;
|
377
477
|
int cnt;
|
378
478
|
struct capture_object *cap;
|
379
479
|
int ret;
|
480
|
+
void *default_handler;
|
380
481
|
|
381
482
|
DEBUG_PRINT("capture_loop");
|
382
483
|
GetCapture(self, cap);
|
383
484
|
|
384
485
|
/* scan arg */
|
385
|
-
|
386
|
-
|
387
|
-
|
486
|
+
rb_scan_args(argc, argv, "02", &v_cnt, &v_opts);
|
487
|
+
if (NIL_P(v_cnt)) {
|
488
|
+
cnt = -1;
|
388
489
|
} else {
|
389
|
-
|
490
|
+
FIXNUM_P(v_cnt);
|
491
|
+
cnt = FIX2INT(v_cnt);
|
390
492
|
}
|
391
|
-
|
493
|
+
parse_opts(v_opts, &default_handler);
|
392
494
|
if (pcap_file(cap->pcap) != NULL) {
|
393
495
|
MAYBE_TRAP_BEG;
|
394
|
-
ret = pcap_loop(cap->pcap, cnt,
|
496
|
+
ret = pcap_loop(cap->pcap, cnt, default_handler, (u_char *)cap);
|
395
497
|
MAYBE_TRAP_END;
|
396
498
|
}
|
397
499
|
else {
|
@@ -409,7 +511,7 @@ capture_loop(argc, argv, self)
|
|
409
511
|
rb_thread_wait_fd(fd);
|
410
512
|
}
|
411
513
|
MAYBE_TRAP_BEG;
|
412
|
-
ret = pcap_dispatch(cap->pcap, 1,
|
514
|
+
ret = pcap_dispatch(cap->pcap, 1, default_handler, (u_char *)cap);
|
413
515
|
MAYBE_TRAP_END;
|
414
516
|
} while (ret == 0);
|
415
517
|
|
@@ -540,6 +642,30 @@ capture_inject(self, v_buf)
|
|
540
642
|
return Qnil;
|
541
643
|
}
|
542
644
|
|
645
|
+
// configure capture direction: IN/OUT packets
|
646
|
+
static VALUE
|
647
|
+
capture_direction(self, direction)
|
648
|
+
VALUE direction;
|
649
|
+
VALUE self;
|
650
|
+
{
|
651
|
+
struct capture_object *cap;
|
652
|
+
// default value is in and out packets
|
653
|
+
int v_direction = PCAP_D_INOUT;
|
654
|
+
|
655
|
+
DEBUG_PRINT("capture_direction");
|
656
|
+
GetCapture(self, cap);
|
657
|
+
Check_Type(direction, T_SYMBOL);
|
658
|
+
// set desired direction: :in,:out or both
|
659
|
+
if (SYM2ID(direction) == rb_intern("in")) {
|
660
|
+
DEBUG_PRINT("setting capture direction IN");
|
661
|
+
v_direction = PCAP_D_IN;
|
662
|
+
} else if (SYM2ID(direction) == rb_intern("out")) {
|
663
|
+
DEBUG_PRINT("setting capture direction OUT");
|
664
|
+
v_direction = PCAP_D_OUT;
|
665
|
+
}
|
666
|
+
return INT2NUM(pcap_setdirection(cap->pcap, v_direction));
|
667
|
+
}
|
668
|
+
|
543
669
|
/*
|
544
670
|
* Dumper object
|
545
671
|
*/
|
@@ -905,6 +1031,9 @@ Init_pcap(void)
|
|
905
1031
|
rb_define_method(cCapture, "snaplen", capture_snapshot, 0);
|
906
1032
|
rb_define_method(cCapture, "stats", capture_stats, 0);
|
907
1033
|
rb_define_method(cCapture, "inject", capture_inject, 1);
|
1034
|
+
rb_define_method(cCapture, "direction", capture_direction, 1);
|
1035
|
+
rb_define_method(cCapture, "breakloop", capture_breakloop, 0);
|
1036
|
+
rb_define_method(cCapture, "closed?", is_capture_closed, 0);
|
908
1037
|
|
909
1038
|
/* define class Dumper */
|
910
1039
|
cDumper = rb_define_class_under(mPcap, "Dumper", rb_cObject);
|
@@ -0,0 +1,82 @@
|
|
1
|
+
/*
|
2
|
+
* arp_packet.c
|
3
|
+
*
|
4
|
+
* $Id: arp_packet.c,v 0.1
|
5
|
+
*
|
6
|
+
*/
|
7
|
+
|
8
|
+
#include "ruby_pcap.h"
|
9
|
+
#include <netdb.h>
|
10
|
+
|
11
|
+
struct arphdr
|
12
|
+
{
|
13
|
+
unsigned short int ar_hrd; /* Format of hardware address. */
|
14
|
+
unsigned short int ar_pro; /* Format of protocol address. */
|
15
|
+
unsigned char ar_hln; /* Length of hardware address. */
|
16
|
+
unsigned char ar_pln; /* Length of protocol address. */
|
17
|
+
unsigned short int ar_op; /* ARP opcode (command). */
|
18
|
+
unsigned char ar_sha[6]; /* Sender hardware address. */
|
19
|
+
unsigned char ar_sip[4]; /* Sender IP address. */
|
20
|
+
unsigned char ar_tha[6]; /* Target hardware address. */
|
21
|
+
unsigned char ar_tip[4]; /* Target IP address. */
|
22
|
+
};
|
23
|
+
|
24
|
+
|
25
|
+
VALUE cARPPacket;
|
26
|
+
|
27
|
+
VALUE
|
28
|
+
setup_arp_packet(pkt, nl_len)
|
29
|
+
struct packet_object *pkt;
|
30
|
+
int nl_len;
|
31
|
+
{
|
32
|
+
VALUE class;
|
33
|
+
|
34
|
+
DEBUG_PRINT("setup_arp_packet");
|
35
|
+
|
36
|
+
class = cARPPacket;
|
37
|
+
|
38
|
+
return class;
|
39
|
+
}
|
40
|
+
|
41
|
+
#define ARP_HDR(pkt) ((struct arphdr *)LAYER3_HDR(pkt))
|
42
|
+
|
43
|
+
#define ARPP_METHOD(func, val) \
|
44
|
+
static VALUE\
|
45
|
+
(func)(self)\
|
46
|
+
VALUE self;\
|
47
|
+
{\
|
48
|
+
struct packet_object *pkt;\
|
49
|
+
struct arphdr *arp;\
|
50
|
+
DEBUG_PRINT(#func);\
|
51
|
+
GetPacket(self, pkt);\
|
52
|
+
arp = ARP_HDR(pkt);\
|
53
|
+
return (val);\
|
54
|
+
}
|
55
|
+
|
56
|
+
ARPP_METHOD(arpp_hw, INT2FIX(ntohs(arp->ar_hrd)))
|
57
|
+
ARPP_METHOD(arpp_prot, INT2FIX(ntohs(arp->ar_pro)))
|
58
|
+
ARPP_METHOD(arpp_hlen, INT2FIX(arp->ar_hln))
|
59
|
+
ARPP_METHOD(arpp_plen, INT2FIX(arp->ar_pln))
|
60
|
+
ARPP_METHOD(arpp_op, INT2FIX(ntohs(arp->ar_op)))
|
61
|
+
ARPP_METHOD(arpp_s_hw, rb_str_new(arp->ar_sha,6))
|
62
|
+
ARPP_METHOD(arpp_s_ip, UINT32_2_NUM(ntohl( *((unsigned long int *) arp->ar_sip))))
|
63
|
+
ARPP_METHOD(arpp_t_hw, rb_str_new(arp->ar_tha,6))
|
64
|
+
ARPP_METHOD(arpp_t_ip, UINT32_2_NUM(ntohl( *((unsigned long int *) arp->ar_tip))))
|
65
|
+
|
66
|
+
|
67
|
+
void
|
68
|
+
Init_arp_packet(void)
|
69
|
+
{
|
70
|
+
DEBUG_PRINT("Init_arp_packet");
|
71
|
+
|
72
|
+
cARPPacket = rb_define_class_under(mPcap, "ARPPacket", cPacket);
|
73
|
+
rb_define_method(cARPPacket, "hw", arpp_hw, 0);
|
74
|
+
rb_define_method(cARPPacket, "protocol", arpp_prot, 0);
|
75
|
+
rb_define_method(cARPPacket, "hwlen", arpp_hlen, 0);
|
76
|
+
rb_define_method(cARPPacket, "plen", arpp_plen, 0);
|
77
|
+
rb_define_method(cARPPacket, "op_code", arpp_op, 0);
|
78
|
+
rb_define_method(cARPPacket, "sender_hw", arpp_s_hw, 0);
|
79
|
+
rb_define_method(cARPPacket, "sender_ip", arpp_s_ip, 0);
|
80
|
+
rb_define_method(cARPPacket, "target_hw", arpp_t_hw, 0);
|
81
|
+
rb_define_method(cARPPacket, "target_ip", arpp_t_ip, 0);
|
82
|
+
}
|
data/ext/pcap/icmp_packet.c
CHANGED
@@ -232,6 +232,40 @@ icmpp_radv(self, ind)
|
|
232
232
|
rb_ary_push(ary, INT2NUM(ntohl(IDRD(icmp)->ird_pref)));
|
233
233
|
return ary;
|
234
234
|
}
|
235
|
+
static VALUE
|
236
|
+
icmpp_csumok(self)
|
237
|
+
VALUE self;
|
238
|
+
{
|
239
|
+
struct packet_object *pkt;
|
240
|
+
struct ip *ip;
|
241
|
+
struct icmp *icmp;
|
242
|
+
GetPacket(self, pkt);
|
243
|
+
ip = IP_HDR(pkt);
|
244
|
+
icmp = ICMP_HDR(pkt);
|
245
|
+
|
246
|
+
long sum = 0;
|
247
|
+
unsigned short *temp = (unsigned short *)icmp;
|
248
|
+
int len = ntohs(ip->ip_len) - ip->ip_hl*4; // length of ip data
|
249
|
+
int csum = ntohs(icmp->icmp_cksum); // keep the checksum in packet
|
250
|
+
|
251
|
+
icmp->icmp_cksum = 0;
|
252
|
+
while(len > 1){
|
253
|
+
sum += ntohs(*temp++);
|
254
|
+
len -= 2;
|
255
|
+
}
|
256
|
+
if(len)
|
257
|
+
sum += ntohs((unsigned short) *((unsigned char *)temp));
|
258
|
+
while(sum>>16)
|
259
|
+
sum = (sum & 0xFFFF) + (sum >> 16);
|
260
|
+
unsigned short answer = ~sum;
|
261
|
+
|
262
|
+
icmp->icmp_cksum = csum; //restore the checkum in packet
|
263
|
+
if (DEBUG_CHECKSUM)
|
264
|
+
printf("ICMP csum in packet:%d should be %d\n", csum, answer);
|
265
|
+
if (answer == csum)
|
266
|
+
return Qtrue;
|
267
|
+
return Qfalse;
|
268
|
+
}
|
235
269
|
|
236
270
|
#define time_new_msec(t) rb_time_new((t)/1000, (t)%1000 * 1000)
|
237
271
|
ICMPP_METHOD(icmpp_otime, 12, time_new_msec(ntohl(icmp->icmp_otime)))
|
@@ -336,6 +370,7 @@ Init_icmp_packet(void)
|
|
336
370
|
rb_define_method(cICMPPacket, "icmp_typestr", icmpp_typestr, 0);
|
337
371
|
rb_define_method(cICMPPacket, "icmp_code", icmpp_code, 0);
|
338
372
|
rb_define_method(cICMPPacket, "icmp_cksum", icmpp_cksum, 0);
|
373
|
+
rb_define_method(cICMPPacket, "icmp_csum_ok?", icmpp_csumok, 0);
|
339
374
|
|
340
375
|
klass = rb_define_class_under(mPcap, "ICMPEchoReply", cICMPPacket);
|
341
376
|
icmp_types[ICMP_ECHOREPLY].klass = klass;
|
@@ -0,0 +1,107 @@
|
|
1
|
+
/*
|
2
|
+
* icmpv6_packet.c
|
3
|
+
*/
|
4
|
+
|
5
|
+
#include "ruby_pcap.h"
|
6
|
+
|
7
|
+
#define ICMPV6_HDR(pkt) ((struct icmp6_hdr *)LAYER4_HDR(pkt))
|
8
|
+
#define ICMP_CAPLEN(pkt) (pkt->hdr.pkthdr.caplen - pkt->hdr.layer4_off)
|
9
|
+
|
10
|
+
VALUE cICMPv6Packet;
|
11
|
+
|
12
|
+
#define CheckTruncateICMP(pkt, need) CheckTruncate(pkt, pkt->hdr.layer4_off, need, "truncated ICMPv6")
|
13
|
+
|
14
|
+
|
15
|
+
VALUE
|
16
|
+
setup_icmpv6_packet(pkt)
|
17
|
+
struct packet_object *pkt;
|
18
|
+
{
|
19
|
+
return cICMPv6Packet;
|
20
|
+
}
|
21
|
+
|
22
|
+
|
23
|
+
#define ICMPP_METHOD(func, need, val) \
|
24
|
+
static VALUE\
|
25
|
+
(func)(self)\
|
26
|
+
VALUE self;\
|
27
|
+
{\
|
28
|
+
struct packet_object *pkt;\
|
29
|
+
struct icmp6_hdr *icmp;\
|
30
|
+
GetPacket(self, pkt);\
|
31
|
+
CheckTruncateICMP(pkt, (need));\
|
32
|
+
icmp = ICMPV6_HDR(pkt);\
|
33
|
+
return (val);\
|
34
|
+
}
|
35
|
+
|
36
|
+
/*
|
37
|
+
* Common methods based on icmp6_hdr
|
38
|
+
*/
|
39
|
+
|
40
|
+
ICMPP_METHOD(icmpp_type, 1, INT2FIX(icmp->icmp6_type))
|
41
|
+
ICMPP_METHOD(icmpp_code, 2, INT2FIX(icmp->icmp6_code))
|
42
|
+
ICMPP_METHOD(icmpp_cksum, 4, INT2FIX(ntohs(icmp->icmp6_cksum)))
|
43
|
+
/* 4 Bytes is the common ICMPv6 Header*/
|
44
|
+
ICMPP_METHOD(icmppv6_data, 5, rb_str_new(icmp->icmp6_data8, ICMP_CAPLEN(pkt)-4))
|
45
|
+
|
46
|
+
|
47
|
+
static VALUE
|
48
|
+
icmpp_csumokv6(self)
|
49
|
+
VALUE self;
|
50
|
+
{
|
51
|
+
struct packet_object *pkt;
|
52
|
+
struct ip6_hdr *ip;
|
53
|
+
struct icmp6_hdr *icmp;
|
54
|
+
GetPacket(self, pkt);
|
55
|
+
ip = IPV6_HDR(pkt);
|
56
|
+
icmp = ICMPV6_HDR(pkt);
|
57
|
+
|
58
|
+
long sum = 0;
|
59
|
+
unsigned short *temp = (unsigned short *)icmp;
|
60
|
+
int len = ntohs(ip->ip6_plen); // length of ip data
|
61
|
+
int csum = ntohs(icmp->icmp6_cksum); // keep the checksum in packet
|
62
|
+
unsigned short *ip_src = (void *)&ip->ip6_src.s6_addr;
|
63
|
+
unsigned short *ip_dst = (void *)&ip->ip6_dst.s6_addr;
|
64
|
+
|
65
|
+
// ICMPv6 now inclides pseudo header sum
|
66
|
+
int i = 1;
|
67
|
+
for (i = 0; i < 8; i++) {
|
68
|
+
sum += ntohs(*(ip_src));
|
69
|
+
sum += ntohs(*(ip_dst));
|
70
|
+
ip_src++;
|
71
|
+
ip_dst++;
|
72
|
+
}
|
73
|
+
sum += 58; // ICMPv6 next header value
|
74
|
+
sum += len;
|
75
|
+
|
76
|
+
icmp->icmp6_cksum = 0;
|
77
|
+
while(len > 1){
|
78
|
+
sum += ntohs(*temp++);
|
79
|
+
len -= 2;
|
80
|
+
}
|
81
|
+
if(len)
|
82
|
+
sum += ntohs((unsigned short) *((unsigned char *)temp));
|
83
|
+
while(sum>>16)
|
84
|
+
sum = (sum & 0xFFFF) + (sum >> 16);
|
85
|
+
unsigned short answer = ~sum;
|
86
|
+
|
87
|
+
icmp->icmp6_cksum = csum; //restore the checkum in packet
|
88
|
+
if (DEBUG_CHECKSUM)
|
89
|
+
printf("ICMP csum in packet:%d should be %d\n", csum, answer);
|
90
|
+
if (answer == csum)
|
91
|
+
return Qtrue;
|
92
|
+
return Qfalse;
|
93
|
+
}
|
94
|
+
|
95
|
+
|
96
|
+
void
|
97
|
+
Init_icmpv6_packet(void)
|
98
|
+
{
|
99
|
+
|
100
|
+
cICMPv6Packet = rb_define_class_under(mPcap, "ICMPv6Packet", cIPv6Packet);
|
101
|
+
|
102
|
+
rb_define_method(cICMPv6Packet, "icmp_type", icmpp_type, 0);
|
103
|
+
rb_define_method(cICMPv6Packet, "icmp_code", icmpp_code, 0);
|
104
|
+
rb_define_method(cICMPv6Packet, "icmp_cksum", icmpp_cksum, 0);
|
105
|
+
rb_define_method(cICMPv6Packet, "icmp_csum_ok?", icmpp_csumokv6, 0);
|
106
|
+
rb_define_method(cICMPv6Packet, "icmp_data", icmppv6_data, 0);
|
107
|
+
}
|
data/ext/pcap/ip_packet.c
CHANGED
@@ -14,8 +14,7 @@ static VALUE cIPAddress;
|
|
14
14
|
|
15
15
|
static unsigned short in_cksum(unsigned char *data, int len);
|
16
16
|
|
17
|
-
#define CheckTruncateIp(pkt, need)
|
18
|
-
CheckTruncate(pkt, pkt->hdr.layer3_off, need, "truncated IP")
|
17
|
+
#define CheckTruncateIp(pkt, need) CheckTruncate(pkt, pkt->hdr.layer3_off, need, "truncated IP")
|
19
18
|
|
20
19
|
VALUE
|
21
20
|
setup_ip_packet(pkt, nl_len)
|
@@ -49,7 +48,7 @@ setup_ip_packet(pkt, nl_len)
|
|
49
48
|
case IPPROTO_ICMP:
|
50
49
|
class = setup_icmp_packet(pkt, tl_len);
|
51
50
|
break;
|
52
|
-
}
|
51
|
+
}
|
53
52
|
}
|
54
53
|
}
|
55
54
|
}
|
@@ -149,6 +148,19 @@ ipp_sumok(self)
|
|
149
148
|
return Qfalse;
|
150
149
|
}
|
151
150
|
|
151
|
+
static VALUE
|
152
|
+
ipp_truncated(self)
|
153
|
+
VALUE self;
|
154
|
+
{
|
155
|
+
struct packet_object *pkt;
|
156
|
+
struct ip *ip;
|
157
|
+
GetPacket(self, pkt);
|
158
|
+
ip = IP_HDR(pkt);
|
159
|
+
if IsTruncated(pkt, pkt->hdr.layer3_off, ntohs(ip->ip_len))
|
160
|
+
return Qtrue;
|
161
|
+
return Qfalse;
|
162
|
+
}
|
163
|
+
|
152
164
|
static unsigned short
|
153
165
|
in_cksum(unsigned char *data, int len)
|
154
166
|
{
|
@@ -401,6 +413,7 @@ Init_ip_packet(void)
|
|
401
413
|
rb_define_method(cIPPacket, "dst=", ipp_set_dst, 1);
|
402
414
|
rb_define_method(cIPPacket, "ip_data", ipp_data, 0);
|
403
415
|
rb_define_method(cIPPacket, "ip_sum_update!", ipp_sum_update, 0);
|
416
|
+
rb_define_method(cIPPacket, "ip_truncated?", ipp_truncated, 0);
|
404
417
|
|
405
418
|
cIPAddress = rb_define_class_under(mPcap, "IPAddress", rb_cObject);
|
406
419
|
rb_define_singleton_method(cIPAddress, "new", ipaddr_s_new, 1);
|
@@ -417,8 +430,4 @@ Init_ip_packet(void)
|
|
417
430
|
|
418
431
|
rb_define_method(cIPAddress, "_dump", ipaddr_dump, 1);
|
419
432
|
rb_define_singleton_method(cIPAddress, "_load", ipaddr_s_load, 1);
|
420
|
-
|
421
|
-
Init_tcp_packet();
|
422
|
-
Init_udp_packet();
|
423
|
-
Init_icmp_packet();
|
424
433
|
}
|