ruby-pcap 0.7.9 → 0.8.0
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/README.md +1 -4
- data/ext/pcap/Pcap.c +125 -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 +13 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 78bf37291d08a1c9dbe2ab08269e494dbb8f3c5d6a37932e3468ca30c4899648
|
4
|
+
data.tar.gz: 42cb108300efda78d65a7f742f691863a226cd4365339ef0a68a97ebfae0987e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5572b9bdb5361c4b2e5061e20af5c15257e1c22dee6c747b86edff3053949795003ab892fb1b3e4f0ce77363a1f2c046a3a696d79cc047f3d178d81360a777e7
|
7
|
+
data.tar.gz: 28cb162c6fdd85499effb7c397364e1f90828292c9da9465d789a8d798c594e8f45632fd62955900a015961701f01e0ecbfb5b8c61a0440a687dd26263c786c8
|
data/README.md
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
|
1
2
|
## ruby-pcap
|
2
3
|
|
3
4
|
[](https://travis-ci.org/ickymettle/ruby-pcap)
|
@@ -26,10 +27,6 @@ Directory 'examples' contains some simple scripts.
|
|
26
27
|
|
27
28
|
Masaki Fukushima <fukusima@goto.info.waseda.ac.jp>
|
28
29
|
|
29
|
-
## Maintained by
|
30
|
-
|
31
|
-
Marcus Barczak <mbarczak@etsy.com>
|
32
|
-
|
33
30
|
## Copyright
|
34
31
|
|
35
32
|
ruby-pcap is copyrighted free software by Masaki Fukushima.
|
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>
|
@@ -318,36 +317,112 @@ handler(cap, pkthdr, data)
|
|
318
317
|
rb_yield(new_packet(data, pkthdr, cap->dl_type));
|
319
318
|
}
|
320
319
|
|
320
|
+
#define DST_ADDR(data) INT2FIX(ntohl(*((unsigned int *) (data + 30))))
|
321
|
+
#define SRC_ADDR(data) INT2FIX(ntohl(*((unsigned int *) (data + 26))))
|
322
|
+
|
323
|
+
static void
|
324
|
+
dst_ipv4_addr_handler(cap, pkthdr, data)
|
325
|
+
struct capture_object *cap;
|
326
|
+
const struct pcap_pkthdr *pkthdr;
|
327
|
+
const u_char *data;
|
328
|
+
{
|
329
|
+
rb_yield(DST_ADDR(data));
|
330
|
+
}
|
331
|
+
|
332
|
+
static void
|
333
|
+
src_ipv4_addr_handler(cap, pkthdr, data)
|
334
|
+
struct capture_object *cap;
|
335
|
+
const struct pcap_pkthdr *pkthdr;
|
336
|
+
const u_char *data;
|
337
|
+
{
|
338
|
+
rb_yield(SRC_ADDR(data));
|
339
|
+
}
|
340
|
+
|
341
|
+
#define SRCV6_ADDR(data) rb_integer_unpack((u_char *) (data + 22), 16, 1, 0, INTEGER_PACK_BIG_ENDIAN)
|
342
|
+
#define DSTV6_ADDR(data) rb_integer_unpack((u_char *) (data + 38), 16, 1, 0, INTEGER_PACK_BIG_ENDIAN)
|
343
|
+
|
344
|
+
static void
|
345
|
+
dst_ipv6_addr_handler(cap, pkthdr, data)
|
346
|
+
struct capture_object *cap;
|
347
|
+
const struct pcap_pkthdr *pkthdr;
|
348
|
+
const u_char *data;
|
349
|
+
{
|
350
|
+
rb_yield(DSTV6_ADDR(data));
|
351
|
+
}
|
352
|
+
|
353
|
+
static void
|
354
|
+
src_ipv6_addr_handler(cap, pkthdr, data)
|
355
|
+
struct capture_object *cap;
|
356
|
+
const struct pcap_pkthdr *pkthdr;
|
357
|
+
const u_char *data;
|
358
|
+
{
|
359
|
+
rb_yield(SRCV6_ADDR(data));
|
360
|
+
}
|
361
|
+
|
362
|
+
void parse_opts(VALUE v_opts, void **default_handler)
|
363
|
+
{
|
364
|
+
if (NIL_P(v_opts)) {
|
365
|
+
DEBUG_PRINT("using default capture handler");
|
366
|
+
*default_handler = &handler;
|
367
|
+
} else {
|
368
|
+
// raise error if second argument is not a symbol
|
369
|
+
Check_Type(v_opts, T_SYMBOL);
|
370
|
+
// only :source, :destination are supported
|
371
|
+
if (SYM2ID(v_opts) == rb_intern("source")) {
|
372
|
+
DEBUG_PRINT("yeilding only source ipv4 addresses");
|
373
|
+
*default_handler = &src_ipv4_addr_handler;
|
374
|
+
} else if (SYM2ID(v_opts) == rb_intern("destination")) {
|
375
|
+
DEBUG_PRINT("yeilding only destination ipv4 addresses");
|
376
|
+
*default_handler = &dst_ipv4_addr_handler;
|
377
|
+
} else if (SYM2ID(v_opts) == rb_intern("destinationv6")) {
|
378
|
+
DEBUG_PRINT("yeilding only destination ipv6 addresses");
|
379
|
+
*default_handler = &dst_ipv6_addr_handler;
|
380
|
+
} else if (SYM2ID(v_opts) == rb_intern("sourcev6")) {
|
381
|
+
DEBUG_PRINT("yeilding only source ipv6 addresses");
|
382
|
+
*default_handler = &src_ipv6_addr_handler;
|
383
|
+
} else {
|
384
|
+
// unkonw keyword passed, use default capture handler
|
385
|
+
DEBUG_PRINT("unknown option, using default capture handler");
|
386
|
+
*default_handler = &handler;
|
387
|
+
}
|
388
|
+
}
|
389
|
+
}
|
390
|
+
|
321
391
|
static VALUE
|
322
392
|
capture_dispatch(argc, argv, self)
|
323
393
|
int argc;
|
324
394
|
VALUE *argv;
|
325
395
|
VALUE self;
|
326
396
|
{
|
327
|
-
VALUE v_cnt;
|
328
|
-
int cnt;
|
397
|
+
VALUE v_cnt, v_opts;
|
398
|
+
int ret = 0, cnt = 0;
|
399
|
+
unsigned int cap_cnt = 0;
|
329
400
|
struct capture_object *cap;
|
330
|
-
|
401
|
+
void *default_handler;
|
331
402
|
|
332
403
|
DEBUG_PRINT("capture_dispatch");
|
333
404
|
GetCapture(self, cap);
|
334
405
|
|
335
406
|
/* scan arg */
|
336
|
-
|
337
|
-
|
338
|
-
|
407
|
+
rb_scan_args(argc, argv, "02", &v_cnt, &v_opts);
|
408
|
+
if (NIL_P(v_cnt)) {
|
409
|
+
cnt = -1;
|
339
410
|
} else {
|
340
|
-
|
411
|
+
FIXNUM_P(v_cnt);
|
412
|
+
cnt = FIX2INT(v_cnt);
|
341
413
|
}
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
414
|
+
parse_opts(v_opts, &default_handler);
|
415
|
+
// call dispatch with 10,000 and break if we have reached desired amount
|
416
|
+
// if dispatch is called with -1/0 sometimes it dispatches millions of packets
|
417
|
+
for (cap_cnt = 0; cap_cnt < cnt; cap_cnt += ret ) {
|
418
|
+
MAYBE_TRAP_BEG;
|
419
|
+
ret = pcap_dispatch(cap->pcap, 10000, default_handler, (u_char *)cap);
|
420
|
+
MAYBE_TRAP_END;
|
421
|
+
if (ret < 0) {
|
347
422
|
rb_raise(ePcapError, "dispatch: %s", pcap_geterr(cap->pcap));
|
423
|
+
}
|
348
424
|
}
|
349
|
-
|
350
|
-
return INT2FIX(ret);
|
425
|
+
return UINT2NUM(cap_cnt);
|
351
426
|
}
|
352
427
|
|
353
428
|
static VALUE
|
@@ -373,25 +448,27 @@ capture_loop(argc, argv, self)
|
|
373
448
|
VALUE *argv;
|
374
449
|
VALUE self;
|
375
450
|
{
|
376
|
-
VALUE v_cnt;
|
451
|
+
VALUE v_cnt, v_opts;
|
377
452
|
int cnt;
|
378
453
|
struct capture_object *cap;
|
379
454
|
int ret;
|
455
|
+
void *default_handler;
|
380
456
|
|
381
457
|
DEBUG_PRINT("capture_loop");
|
382
458
|
GetCapture(self, cap);
|
383
459
|
|
384
460
|
/* scan arg */
|
385
|
-
|
386
|
-
|
387
|
-
|
461
|
+
rb_scan_args(argc, argv, "02", &v_cnt, &v_opts);
|
462
|
+
if (NIL_P(v_cnt)) {
|
463
|
+
cnt = -1;
|
388
464
|
} else {
|
389
|
-
|
465
|
+
FIXNUM_P(v_cnt);
|
466
|
+
cnt = FIX2INT(v_cnt);
|
390
467
|
}
|
391
|
-
|
468
|
+
parse_opts(v_opts, &default_handler);
|
392
469
|
if (pcap_file(cap->pcap) != NULL) {
|
393
470
|
MAYBE_TRAP_BEG;
|
394
|
-
ret = pcap_loop(cap->pcap, cnt,
|
471
|
+
ret = pcap_loop(cap->pcap, cnt, default_handler, (u_char *)cap);
|
395
472
|
MAYBE_TRAP_END;
|
396
473
|
}
|
397
474
|
else {
|
@@ -409,7 +486,7 @@ capture_loop(argc, argv, self)
|
|
409
486
|
rb_thread_wait_fd(fd);
|
410
487
|
}
|
411
488
|
MAYBE_TRAP_BEG;
|
412
|
-
ret = pcap_dispatch(cap->pcap, 1,
|
489
|
+
ret = pcap_dispatch(cap->pcap, 1, default_handler, (u_char *)cap);
|
413
490
|
MAYBE_TRAP_END;
|
414
491
|
} while (ret == 0);
|
415
492
|
|
@@ -540,6 +617,30 @@ capture_inject(self, v_buf)
|
|
540
617
|
return Qnil;
|
541
618
|
}
|
542
619
|
|
620
|
+
// configure capture direction: IN/OUT packets
|
621
|
+
static VALUE
|
622
|
+
capture_direction(self, direction)
|
623
|
+
VALUE direction;
|
624
|
+
VALUE self;
|
625
|
+
{
|
626
|
+
struct capture_object *cap;
|
627
|
+
// default value is in and out packets
|
628
|
+
int v_direction = PCAP_D_INOUT;
|
629
|
+
|
630
|
+
DEBUG_PRINT("capture_direction");
|
631
|
+
GetCapture(self, cap);
|
632
|
+
Check_Type(direction, T_SYMBOL);
|
633
|
+
// set desired direction: :in,:out or both
|
634
|
+
if (SYM2ID(direction) == rb_intern("in")) {
|
635
|
+
DEBUG_PRINT("setting capture direction IN");
|
636
|
+
v_direction = PCAP_D_IN;
|
637
|
+
} else if (SYM2ID(direction) == rb_intern("out")) {
|
638
|
+
DEBUG_PRINT("setting capture direction OUT");
|
639
|
+
v_direction = PCAP_D_OUT;
|
640
|
+
}
|
641
|
+
return INT2NUM(pcap_setdirection(cap->pcap, v_direction));
|
642
|
+
}
|
643
|
+
|
543
644
|
/*
|
544
645
|
* Dumper object
|
545
646
|
*/
|
@@ -905,6 +1006,7 @@ Init_pcap(void)
|
|
905
1006
|
rb_define_method(cCapture, "snaplen", capture_snapshot, 0);
|
906
1007
|
rb_define_method(cCapture, "stats", capture_stats, 0);
|
907
1008
|
rb_define_method(cCapture, "inject", capture_inject, 1);
|
1009
|
+
rb_define_method(cCapture, "direction", capture_direction, 1);
|
908
1010
|
|
909
1011
|
/* define class Dumper */
|
910
1012
|
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
|
}
|
@@ -0,0 +1,162 @@
|
|
1
|
+
/*
|
2
|
+
* ipv6_packet.c
|
3
|
+
*/
|
4
|
+
|
5
|
+
#include "ruby_pcap.h"
|
6
|
+
|
7
|
+
VALUE cIPv6Packet;
|
8
|
+
|
9
|
+
#define CheckTruncateIpv6(pkt, need) CheckTruncate(pkt, pkt->hdr.layer3_off, need, "truncated IPv6")
|
10
|
+
#define IPV6_HL 40
|
11
|
+
|
12
|
+
VALUE
|
13
|
+
setup_ipv6_packet(pkt, nl_len)
|
14
|
+
struct packet_object *pkt;
|
15
|
+
int nl_len;
|
16
|
+
{
|
17
|
+
VALUE class;
|
18
|
+
|
19
|
+
class = cIPv6Packet;
|
20
|
+
pkt->hdr.layer4_off = pkt->hdr.layer3_off + IPV6_HL;
|
21
|
+
switch (IPV6_HDR(pkt)->ip6_nxt) {
|
22
|
+
case IPPROTO_TCP:
|
23
|
+
DEBUG_PRINT("setup_tcpv6_packet");
|
24
|
+
class = setup_tcpv6_packet(pkt, nl_len - IPV6_HL);
|
25
|
+
break;
|
26
|
+
case IPPROTO_UDP:
|
27
|
+
DEBUG_PRINT("setup_udpv6_packet");
|
28
|
+
class = setup_udpv6_packet(pkt, nl_len - IPV6_HL);
|
29
|
+
break;
|
30
|
+
case IPPROTO_ICMPV6:
|
31
|
+
DEBUG_PRINT("setup_icmpv6_packet");
|
32
|
+
class = setup_icmpv6_packet(pkt);
|
33
|
+
break;
|
34
|
+
}
|
35
|
+
return class;
|
36
|
+
}
|
37
|
+
|
38
|
+
#define IPV6P_METHOD(func, val) \
|
39
|
+
static VALUE\
|
40
|
+
(func)(self)\
|
41
|
+
VALUE self;\
|
42
|
+
{\
|
43
|
+
struct ip6_hdr *ip;\
|
44
|
+
\
|
45
|
+
DEBUG_PRINT(#func);\
|
46
|
+
ip = IPV6_HDR_OBJ(self);\
|
47
|
+
return (val);\
|
48
|
+
}
|
49
|
+
|
50
|
+
IPV6P_METHOD(ipp_ver, INT2FIX(ip->ip6_vfc >> 4))
|
51
|
+
/*
|
52
|
+
The bits of this field hold two values.
|
53
|
+
The six most-significant bits hold the Differentiated Services (DS) field, which is used to classify packets.
|
54
|
+
Currently, all standard DS fields end with a '0' bit. Any DS field that ends with two '1' bits is intended for local or experimental use.[4]
|
55
|
+
The remaining two bits are used for Explicit Congestion Notification (ECN);
|
56
|
+
priority values subdivide into ranges: traffic where the source provides congestion control and non-congestion control traffic.
|
57
|
+
*/
|
58
|
+
IPV6P_METHOD(ipp_tc, INT2FIX((ntohl(ip->ip6_flow) & 0x0FF00000) >> 20))
|
59
|
+
IPV6P_METHOD(ipp_ds, INT2FIX((ntohl(ip->ip6_flow) & 0x0FF00000) >> 22))
|
60
|
+
IPV6P_METHOD(ipp_ecn, INT2FIX((ntohl(ip->ip6_flow) & 0x00300000) >> 20))
|
61
|
+
IPV6P_METHOD(ipp_fl, INT2FIX(ntohl(ip->ip6_flow) & 0x000FFFFF))
|
62
|
+
IPV6P_METHOD(ipp_pl, INT2FIX(ntohs(ip->ip6_plen)))
|
63
|
+
IPV6P_METHOD(ipp_nh, INT2FIX(ip->ip6_nxt))
|
64
|
+
IPV6P_METHOD(ipp_hl, INT2FIX(ip->ip6_hlim))
|
65
|
+
|
66
|
+
|
67
|
+
static VALUE
|
68
|
+
ipp_truncated(self)
|
69
|
+
VALUE self;
|
70
|
+
{
|
71
|
+
struct packet_object *pkt;
|
72
|
+
struct ip6_hdr *ip;
|
73
|
+
GetPacket(self, pkt);
|
74
|
+
ip = IPV6_HDR(pkt);
|
75
|
+
if IsTruncated(pkt, pkt->hdr.layer3_off, ntohs(ip->ip6_plen))
|
76
|
+
return Qtrue;
|
77
|
+
return Qfalse;
|
78
|
+
}
|
79
|
+
|
80
|
+
static VALUE
|
81
|
+
ipp_data(self)
|
82
|
+
VALUE self;
|
83
|
+
{
|
84
|
+
struct packet_object *pkt;
|
85
|
+
struct ip6_hdr *ip;
|
86
|
+
int len;
|
87
|
+
|
88
|
+
GetPacket(self, pkt);
|
89
|
+
ip = IPV6_HDR(pkt);
|
90
|
+
CheckTruncateIpv6(pkt, 20);
|
91
|
+
len = pkt->hdr.pkthdr.caplen - pkt->hdr.layer3_off - IPV6_HL;
|
92
|
+
return rb_str_new((u_char *)ip + IPV6_HL, len);
|
93
|
+
}
|
94
|
+
|
95
|
+
/*
|
96
|
+
* IPv6Address
|
97
|
+
*/
|
98
|
+
|
99
|
+
static VALUE
|
100
|
+
ipp_src_i(self)
|
101
|
+
VALUE self;
|
102
|
+
{
|
103
|
+
struct ip6_hdr *ip;
|
104
|
+
ip = (struct ip6_hdr *)IPV6_HDR_OBJ(self);
|
105
|
+
return rb_integer_unpack(ip->ip6_src.s6_addr, 16, 1, 0, INTEGER_PACK_BIG_ENDIAN);
|
106
|
+
}
|
107
|
+
|
108
|
+
static VALUE
|
109
|
+
ipp_src_s(self)
|
110
|
+
VALUE self;
|
111
|
+
{
|
112
|
+
struct ip6_hdr *ip;
|
113
|
+
char buff[INET6_ADDRSTRLEN];
|
114
|
+
ip = (struct ip6_hdr *)IPV6_HDR_OBJ(self);
|
115
|
+
|
116
|
+
inet_ntop(AF_INET6, ip->ip6_src.s6_addr, buff, INET6_ADDRSTRLEN);
|
117
|
+
return rb_str_new2(buff);
|
118
|
+
}
|
119
|
+
|
120
|
+
static VALUE
|
121
|
+
ipp_dst_i(self)
|
122
|
+
VALUE self;
|
123
|
+
{
|
124
|
+
struct ip6_hdr *ip;
|
125
|
+
ip = IPV6_HDR_OBJ(self);
|
126
|
+
return rb_integer_unpack(ip->ip6_dst.s6_addr, 16, 1, 0, INTEGER_PACK_BIG_ENDIAN);
|
127
|
+
}
|
128
|
+
|
129
|
+
static VALUE
|
130
|
+
ipp_dst_s(self)
|
131
|
+
VALUE self;
|
132
|
+
{
|
133
|
+
char buff[INET6_ADDRSTRLEN];
|
134
|
+
struct ip6_hdr *ip;
|
135
|
+
ip = IPV6_HDR_OBJ(self);
|
136
|
+
|
137
|
+
inet_ntop(AF_INET6, ip->ip6_dst.s6_addr, buff, INET6_ADDRSTRLEN);
|
138
|
+
return rb_str_new2(buff);
|
139
|
+
}
|
140
|
+
|
141
|
+
void
|
142
|
+
Init_ipv6_packet(void)
|
143
|
+
{
|
144
|
+
DEBUG_PRINT("Init_ipv6_packet");
|
145
|
+
|
146
|
+
cIPv6Packet = rb_define_class_under(mPcap, "IPv6Packet", cPacket);
|
147
|
+
|
148
|
+
rb_define_method(cIPv6Packet, "ip_ver", ipp_ver, 0);
|
149
|
+
rb_define_method(cIPv6Packet, "ip_tc", ipp_tc, 0);
|
150
|
+
rb_define_method(cIPv6Packet, "ip_ds", ipp_ds, 0);
|
151
|
+
rb_define_method(cIPv6Packet, "ip_ecn", ipp_ecn, 0);
|
152
|
+
rb_define_method(cIPv6Packet, "ip_fl", ipp_fl, 0); /* IPv6 flow label */
|
153
|
+
rb_define_method(cIPv6Packet, "ip_pl", ipp_pl, 0); /* IPv6 Payload length */
|
154
|
+
rb_define_method(cIPv6Packet, "ip_nh", ipp_nh, 0); /* IPv6 Next header */
|
155
|
+
rb_define_method(cIPv6Packet, "ip_hl", ipp_hl, 0); /* IPv6 Hop limit */
|
156
|
+
rb_define_method(cIPv6Packet, "src_s", ipp_src_s, 0);
|
157
|
+
rb_define_method(cIPv6Packet, "dst_s", ipp_dst_s, 0);
|
158
|
+
rb_define_method(cIPv6Packet, "src_i", ipp_src_i, 0);
|
159
|
+
rb_define_method(cIPv6Packet, "dst_i", ipp_dst_i, 0);
|
160
|
+
rb_define_method(cIPv6Packet, "ip_data", ipp_data, 0);
|
161
|
+
rb_define_method(cIPv6Packet, "ip_truncated?", ipp_truncated, 0);
|
162
|
+
}
|