ruby-pcap 0.7.8
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.
- data/.gitignore +19 -0
- data/COPYING +340 -0
- data/ChangeLog +145 -0
- data/Gemfile +4 -0
- data/MANIFEST +47 -0
- data/README +47 -0
- data/README.ja +50 -0
- data/Rakefile +1 -0
- data/VERSION +1 -0
- data/doc-ja/Capture.html +147 -0
- data/doc-ja/Dumper.html +54 -0
- data/doc-ja/Filter.html +112 -0
- data/doc-ja/ICMPPacket.html +189 -0
- data/doc-ja/IPAddress.html +60 -0
- data/doc-ja/IPPacket.html +142 -0
- data/doc-ja/Packet.html +101 -0
- data/doc-ja/Pcap.html +111 -0
- data/doc-ja/PcapError.html +21 -0
- data/doc-ja/Pcaplet.html +113 -0
- data/doc-ja/TCPPacket.html +148 -0
- data/doc-ja/TruncatedPacket.html +22 -0
- data/doc-ja/UDPPacket.html +73 -0
- data/doc-ja/index.html +54 -0
- data/examples/httpdump.rb +27 -0
- data/examples/rewrite_time.rb +28 -0
- data/examples/tcpdump.rb +26 -0
- data/examples/test.rb +11 -0
- data/ext/Pcap.c +938 -0
- data/ext/extconf.rb +22 -0
- data/ext/icmp_packet.c +444 -0
- data/ext/ip_packet.c +424 -0
- data/ext/packet.c +328 -0
- data/ext/ruby_pcap.h +134 -0
- data/ext/tcp_packet.c +121 -0
- data/ext/udp_packet.c +96 -0
- data/lib/pcap_misc.rb +80 -0
- data/lib/pcaplet.rb +127 -0
- data/ruby-pcap.gemspec +20 -0
- metadata +101 -0
data/ext/ruby_pcap.h
ADDED
@@ -0,0 +1,134 @@
|
|
1
|
+
/*
|
2
|
+
* ruby_pcap.h
|
3
|
+
*
|
4
|
+
* $Id: ruby_pcap.h,v 1.4 2000/08/13 06:56:15 fukusima Exp $
|
5
|
+
*
|
6
|
+
* Copyright (C) 1998-2000 Masaki Fukushima
|
7
|
+
*/
|
8
|
+
|
9
|
+
#ifndef RUBY_PCAP_H
|
10
|
+
#define RUBY_PCAP_H
|
11
|
+
|
12
|
+
#include "ruby.h"
|
13
|
+
#include <pcap.h>
|
14
|
+
#include <stdio.h>
|
15
|
+
#include <netinet/in.h>
|
16
|
+
#include <netinet/in_systm.h>
|
17
|
+
#include <netinet/ip.h>
|
18
|
+
#include <arpa/inet.h>
|
19
|
+
#ifndef IP_OFFMASK
|
20
|
+
# define IP_OFFMASK 0x1fff
|
21
|
+
#endif
|
22
|
+
#ifdef linux
|
23
|
+
# define __FAVOR_BSD
|
24
|
+
#endif
|
25
|
+
#include <netinet/tcp.h>
|
26
|
+
#include <netinet/udp.h>
|
27
|
+
#include <netinet/ip_icmp.h>
|
28
|
+
#include <sys/socket.h>
|
29
|
+
#include <netdb.h>
|
30
|
+
|
31
|
+
#ifdef DEBUG
|
32
|
+
# define DEBUG_PRINT(x) do {\
|
33
|
+
((RTEST(ruby_debug) && RTEST(ruby_verbose))?\
|
34
|
+
(fprintf(stderr, "%s\n", x),fflush(stderr)) : 0)\
|
35
|
+
} while (0)
|
36
|
+
#else
|
37
|
+
# define DEBUG_PRINT(x) do {} while (0)
|
38
|
+
#endif
|
39
|
+
|
40
|
+
#define UINT32_2_NUM(i) rb_uint2inum(i)
|
41
|
+
#ifndef UINT2NUM
|
42
|
+
# define UINT2NUM(i) rb_uint2inum(i)
|
43
|
+
#endif
|
44
|
+
#define MIN(x, y) ((x)<(y) ? (x) : (y))
|
45
|
+
|
46
|
+
|
47
|
+
#define PACKET_MARSHAL_VERSION 1
|
48
|
+
|
49
|
+
/* ruby config.h defines WORDS_BIGENDIAN if big-endian */
|
50
|
+
struct packet_object_header {
|
51
|
+
#ifdef WORDS_BIGENDIAN
|
52
|
+
u_char version:4; /* marshal format version */
|
53
|
+
u_char flags:4; /* flags */
|
54
|
+
#else
|
55
|
+
u_char flags:4; /* flags */
|
56
|
+
u_char version:4; /* marshal format version */
|
57
|
+
#endif
|
58
|
+
#define POH_UDATA 0x01 /* flag: user data exists */
|
59
|
+
#define POH_RSVD1 0x02 /* (reserved) */
|
60
|
+
#define POH_RSVD2 0x03 /* (reserved) */
|
61
|
+
#define POH_RSVD3 0x04 /* (reserved) */
|
62
|
+
u_char dl_type; /* data-link type (DLT_*) */
|
63
|
+
u_short layer3_off; /* layer 3 header offset */
|
64
|
+
u_short layer4_off; /* layer 4 header offset */
|
65
|
+
u_short layer5_off; /* layer 5 header offset */
|
66
|
+
#define OFF_NONEXIST 0xffff /* offset value for non-existent layer */
|
67
|
+
struct pcap_pkthdr pkthdr; /* pcap packet header */
|
68
|
+
};
|
69
|
+
|
70
|
+
struct packet_object {
|
71
|
+
struct packet_object_header hdr; /* packet object header */
|
72
|
+
u_char *data; /* packet data */
|
73
|
+
VALUE udata; /* user data */
|
74
|
+
};
|
75
|
+
|
76
|
+
#define PKTFLAG_TEST(pkt, flag) ((pkt)->hdr.flags & (flag))
|
77
|
+
#define PKTFLAG_SET(pkt, flag, val) \
|
78
|
+
((val) ? ((pkt)->hdr.flags |= (flag)) : ((pkt)->hdr.flags &= ~(flag)))
|
79
|
+
|
80
|
+
#define LAYER2_HDR(pkt) ((pkt)->data)
|
81
|
+
#define LAYER3_HDR(pkt) ((pkt)->data + (pkt)->hdr.layer3_off)
|
82
|
+
#define LAYER4_HDR(pkt) ((pkt)->data + (pkt)->hdr.layer4_off)
|
83
|
+
#define LAYER5_HDR(pkt) ((pkt)->data + (pkt)->hdr.layer5_off)
|
84
|
+
|
85
|
+
#define GetPacket(obj, pkt) Data_Get_Struct(obj, struct packet_object, pkt)
|
86
|
+
#define Caplen(pkt, from) ((pkt)->hdr.pkthdr.caplen - (from))
|
87
|
+
#define CheckTruncate(pkt, from, need, emsg) (\
|
88
|
+
(from) + (need) > (pkt)->hdr.pkthdr.caplen ? \
|
89
|
+
rb_raise(eTruncatedPacket, (emsg)) : 0 \
|
90
|
+
)
|
91
|
+
|
92
|
+
#define IsKindOf(v, class) RTEST(rb_obj_is_kind_of(v, class))
|
93
|
+
#define CheckClass(v, class) ((IsKindOf(v, class)) ? 0 :\
|
94
|
+
rb_raise(rb_eTypeError, "wrong type %s (expected %s)",\
|
95
|
+
rb_class2name(CLASS_OF(v)), rb_class2name(class)))
|
96
|
+
|
97
|
+
|
98
|
+
/* Pcap.c */
|
99
|
+
extern VALUE mPcap, rbpcap_convert;
|
100
|
+
extern VALUE ePcapError;
|
101
|
+
extern VALUE eTruncatedPacket;
|
102
|
+
extern VALUE cFilter;
|
103
|
+
void Init_pcap(void);
|
104
|
+
VALUE filter_match(VALUE self, VALUE v_pkt);
|
105
|
+
|
106
|
+
/* packet.c */
|
107
|
+
extern VALUE cPacket;
|
108
|
+
void Init_packet(void);
|
109
|
+
VALUE new_packet(const u_char *, const struct pcap_pkthdr *, int);
|
110
|
+
|
111
|
+
/* ip_packet.c */
|
112
|
+
#define IP_HDR(pkt) ((struct ip *)LAYER3_HDR(pkt))
|
113
|
+
#define IP_DATA(pkt) ((u_char *)LAYER4_HDR(pkt))
|
114
|
+
extern VALUE cIPPacket;
|
115
|
+
void Init_ip_packet(void);
|
116
|
+
VALUE setup_ip_packet(struct packet_object *, int);
|
117
|
+
VALUE new_ipaddr(struct in_addr *);
|
118
|
+
|
119
|
+
/* tcp_packet.c */
|
120
|
+
extern VALUE cTCPPacket;
|
121
|
+
void Init_tcp_packet(void);
|
122
|
+
VALUE setup_tcp_packet(struct packet_object *, int);
|
123
|
+
|
124
|
+
/* udp_packet.c */
|
125
|
+
extern VALUE cUDPPacket;
|
126
|
+
void Init_udp_packet(void);
|
127
|
+
VALUE setup_udp_packet(struct packet_object *, int);
|
128
|
+
|
129
|
+
/* icmp_packet.c */
|
130
|
+
extern VALUE cICMPPacket;
|
131
|
+
void Init_icmp_packet(void);
|
132
|
+
VALUE setup_icmp_packet(struct packet_object *, int);
|
133
|
+
|
134
|
+
#endif /* RUBY_PCAP_H */
|
data/ext/tcp_packet.c
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
/*
|
2
|
+
* tcp_packet.c
|
3
|
+
*
|
4
|
+
* $Id: tcp_packet.c,v 1.1.1.1 1999/10/27 09:54:38 fukusima Exp $
|
5
|
+
*
|
6
|
+
* Copyright (C) 1998, 1999 Masaki Fukushima
|
7
|
+
*/
|
8
|
+
|
9
|
+
#include "ruby_pcap.h"
|
10
|
+
#include <limits.h>
|
11
|
+
|
12
|
+
#define TCP_HDR(pkt) ((struct tcphdr *)LAYER4_HDR(pkt))
|
13
|
+
#define TCP_DATA(pkt) ((u_char *)LAYER5_HDR(pkt))
|
14
|
+
#define TCP_DATALEN(pkt) (ntohs(IP_HDR(pkt)->ip_len) - \
|
15
|
+
(IP_HDR(pkt)->ip_hl + TCP_HDR(pkt)->th_off) * 4)
|
16
|
+
|
17
|
+
VALUE cTCPPacket;
|
18
|
+
|
19
|
+
#define CheckTruncateTcp(pkt, need) \
|
20
|
+
CheckTruncate(pkt, pkt->hdr.layer4_off, need, "truncated TCP")
|
21
|
+
|
22
|
+
VALUE
|
23
|
+
setup_tcp_packet(pkt, tl_len)
|
24
|
+
struct packet_object *pkt;
|
25
|
+
int tl_len;
|
26
|
+
{
|
27
|
+
VALUE class;
|
28
|
+
|
29
|
+
DEBUG_PRINT("setup_tcp_packet");
|
30
|
+
|
31
|
+
class = cTCPPacket;
|
32
|
+
if (tl_len > 20) {
|
33
|
+
int hl = TCP_HDR(pkt)->th_off * 4;
|
34
|
+
int layer5_len = tl_len - hl;
|
35
|
+
if (layer5_len > 0) {
|
36
|
+
pkt->hdr.layer5_off = pkt->hdr.layer4_off + hl;
|
37
|
+
/* upper layer */
|
38
|
+
}
|
39
|
+
}
|
40
|
+
return class;
|
41
|
+
}
|
42
|
+
|
43
|
+
#define TCPP_METHOD(func, need, val) \
|
44
|
+
static VALUE\
|
45
|
+
(func)(self)\
|
46
|
+
VALUE self;\
|
47
|
+
{\
|
48
|
+
struct packet_object *pkt;\
|
49
|
+
struct tcphdr *tcp;\
|
50
|
+
DEBUG_PRINT(#func);\
|
51
|
+
GetPacket(self, pkt);\
|
52
|
+
CheckTruncateTcp(pkt, (need));\
|
53
|
+
tcp = TCP_HDR(pkt);\
|
54
|
+
return (val);\
|
55
|
+
}
|
56
|
+
|
57
|
+
TCPP_METHOD(tcpp_sport, 2, INT2FIX(ntohs(tcp->th_sport)))
|
58
|
+
TCPP_METHOD(tcpp_dport, 4, INT2FIX(ntohs(tcp->th_dport)))
|
59
|
+
TCPP_METHOD(tcpp_seq, 8, UINT32_2_NUM(ntohl(tcp->th_seq)))
|
60
|
+
TCPP_METHOD(tcpp_acknum, 12, UINT32_2_NUM(ntohl(tcp->th_ack)))
|
61
|
+
TCPP_METHOD(tcpp_off, 13, INT2FIX(tcp->th_off))
|
62
|
+
TCPP_METHOD(tcpp_flags, 14, INT2FIX(tcp->th_flags))
|
63
|
+
TCPP_METHOD(tcpp_win, 16, INT2FIX(ntohs(tcp->th_win)))
|
64
|
+
TCPP_METHOD(tcpp_sum, 18, INT2FIX(ntohs(tcp->th_sum)))
|
65
|
+
TCPP_METHOD(tcpp_urp, 20, INT2FIX(ntohs(tcp->th_urp)))
|
66
|
+
|
67
|
+
#define TCPP_FLAG(func, flag) \
|
68
|
+
TCPP_METHOD(func, 14, (tcp->th_flags & flag) ? Qtrue : Qfalse)
|
69
|
+
TCPP_FLAG(tcpp_fin, TH_FIN)
|
70
|
+
TCPP_FLAG(tcpp_syn, TH_SYN)
|
71
|
+
TCPP_FLAG(tcpp_rst, TH_RST)
|
72
|
+
TCPP_FLAG(tcpp_psh, TH_PUSH)
|
73
|
+
TCPP_FLAG(tcpp_ack, TH_ACK)
|
74
|
+
TCPP_FLAG(tcpp_urg, TH_URG)
|
75
|
+
|
76
|
+
static VALUE
|
77
|
+
tcpp_data(self)
|
78
|
+
VALUE self;
|
79
|
+
{
|
80
|
+
struct packet_object *pkt;
|
81
|
+
VALUE v_len;
|
82
|
+
int len;
|
83
|
+
|
84
|
+
DEBUG_PRINT("tcpp_data");
|
85
|
+
GetPacket(self, pkt);
|
86
|
+
|
87
|
+
if (pkt->hdr.layer5_off == OFF_NONEXIST) return Qnil;
|
88
|
+
|
89
|
+
len = MIN(Caplen(pkt, pkt->hdr.layer5_off), TCP_DATALEN(pkt));
|
90
|
+
if (len < 1) return Qnil;
|
91
|
+
return rb_str_new(TCP_DATA(pkt), len);
|
92
|
+
}
|
93
|
+
|
94
|
+
void
|
95
|
+
Init_tcp_packet(void)
|
96
|
+
{
|
97
|
+
DEBUG_PRINT("Init_tcp_packet");
|
98
|
+
|
99
|
+
/* define class TcpPacket */
|
100
|
+
cTCPPacket = rb_define_class_under(mPcap, "TCPPacket", cIPPacket);
|
101
|
+
|
102
|
+
rb_define_method(cTCPPacket, "tcp_sport", tcpp_sport, 0);
|
103
|
+
rb_define_method(cTCPPacket, "sport", tcpp_sport, 0);
|
104
|
+
rb_define_method(cTCPPacket, "tcp_dport", tcpp_dport, 0);
|
105
|
+
rb_define_method(cTCPPacket, "dport", tcpp_dport, 0);
|
106
|
+
rb_define_method(cTCPPacket, "tcp_seq", tcpp_seq, 0);
|
107
|
+
rb_define_method(cTCPPacket, "tcp_ack", tcpp_acknum, 0);
|
108
|
+
rb_define_method(cTCPPacket, "tcp_off", tcpp_off, 0);
|
109
|
+
rb_define_method(cTCPPacket, "tcp_hlen", tcpp_off, 0);
|
110
|
+
rb_define_method(cTCPPacket, "tcp_flags", tcpp_flags, 0);
|
111
|
+
rb_define_method(cTCPPacket, "tcp_win", tcpp_win, 0);
|
112
|
+
rb_define_method(cTCPPacket, "tcp_sum", tcpp_sum, 0);
|
113
|
+
rb_define_method(cTCPPacket, "tcp_urp", tcpp_urp, 0);
|
114
|
+
rb_define_method(cTCPPacket, "tcp_fin?", tcpp_fin, 0);
|
115
|
+
rb_define_method(cTCPPacket, "tcp_syn?", tcpp_syn, 0);
|
116
|
+
rb_define_method(cTCPPacket, "tcp_rst?", tcpp_rst, 0);
|
117
|
+
rb_define_method(cTCPPacket, "tcp_psh?", tcpp_psh, 0);
|
118
|
+
rb_define_method(cTCPPacket, "tcp_ack?", tcpp_ack, 0);
|
119
|
+
rb_define_method(cTCPPacket, "tcp_urg?", tcpp_urg, 0);
|
120
|
+
rb_define_method(cTCPPacket, "tcp_data", tcpp_data, 0);
|
121
|
+
}
|
data/ext/udp_packet.c
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
/*
|
2
|
+
* udp_packet.c
|
3
|
+
*
|
4
|
+
* $Id: udp_packet.c,v 1.1.1.1 1999/10/27 09:54:38 fukusima Exp $
|
5
|
+
*
|
6
|
+
* Copyright (C) 1999 Masaki Fukushima
|
7
|
+
*/
|
8
|
+
|
9
|
+
#include "ruby_pcap.h"
|
10
|
+
#include <limits.h>
|
11
|
+
|
12
|
+
#define UDP_HDR(pkt) ((struct udphdr *)LAYER4_HDR(pkt))
|
13
|
+
#define UDP_DATA(pkt) ((u_char *)LAYER5_HDR(pkt))
|
14
|
+
#define UDP_LENGTH(pkt) (ntohs(UDP_HDR(pkt)->uh_ulen))
|
15
|
+
|
16
|
+
VALUE cUDPPacket;
|
17
|
+
|
18
|
+
#define CheckTruncateUdp(pkt, need) \
|
19
|
+
CheckTruncate(pkt, pkt->hdr.layer4_off, need, "truncated UDP")
|
20
|
+
|
21
|
+
VALUE
|
22
|
+
setup_udp_packet(pkt, tl_len)
|
23
|
+
struct packet_object *pkt;
|
24
|
+
int tl_len;
|
25
|
+
{
|
26
|
+
VALUE class;
|
27
|
+
|
28
|
+
DEBUG_PRINT("setup_udp_packet");
|
29
|
+
|
30
|
+
class = cUDPPacket;
|
31
|
+
if (tl_len > 8) {
|
32
|
+
int hl = 8;
|
33
|
+
int layer5_len;
|
34
|
+
|
35
|
+
tl_len = MIN(tl_len, UDP_LENGTH(pkt));
|
36
|
+
layer5_len = tl_len - hl;
|
37
|
+
if (layer5_len > 0) {
|
38
|
+
pkt->hdr.layer5_off = pkt->hdr.layer4_off + hl;
|
39
|
+
/* upper layer */
|
40
|
+
}
|
41
|
+
}
|
42
|
+
return class;
|
43
|
+
}
|
44
|
+
|
45
|
+
#define UDPP_METHOD(func, need, val) \
|
46
|
+
static VALUE\
|
47
|
+
(func)(self)\
|
48
|
+
VALUE self;\
|
49
|
+
{\
|
50
|
+
struct packet_object *pkt;\
|
51
|
+
struct udphdr *udp;\
|
52
|
+
DEBUG_PRINT(#func);\
|
53
|
+
GetPacket(self, pkt);\
|
54
|
+
CheckTruncateUdp(pkt, (need));\
|
55
|
+
udp = UDP_HDR(pkt);\
|
56
|
+
return (val);\
|
57
|
+
}
|
58
|
+
|
59
|
+
UDPP_METHOD(udpp_sport, 2, INT2FIX(ntohs(udp->uh_sport)))
|
60
|
+
UDPP_METHOD(udpp_dport, 4, INT2FIX(ntohs(udp->uh_dport)))
|
61
|
+
UDPP_METHOD(udpp_len, 6, INT2FIX(ntohs(udp->uh_ulen)))
|
62
|
+
UDPP_METHOD(udpp_sum, 8, INT2FIX(ntohs(udp->uh_sum)))
|
63
|
+
|
64
|
+
static VALUE
|
65
|
+
udpp_data(self)
|
66
|
+
VALUE self;
|
67
|
+
{
|
68
|
+
struct packet_object *pkt;
|
69
|
+
int len;
|
70
|
+
|
71
|
+
DEBUG_PRINT("udpp_data");
|
72
|
+
GetPacket(self, pkt);
|
73
|
+
CheckTruncateUdp(pkt, 8);
|
74
|
+
|
75
|
+
if (pkt->hdr.layer5_off == OFF_NONEXIST) return Qnil;
|
76
|
+
|
77
|
+
len = MIN(Caplen(pkt, pkt->hdr.layer5_off), UDP_LENGTH(pkt)-8);
|
78
|
+
return rb_str_new(UDP_DATA(pkt), len);
|
79
|
+
}
|
80
|
+
|
81
|
+
void
|
82
|
+
Init_udp_packet(void)
|
83
|
+
{
|
84
|
+
DEBUG_PRINT("Init_udp_packet");
|
85
|
+
|
86
|
+
/* define class UdpPacket */
|
87
|
+
cUDPPacket = rb_define_class_under(mPcap, "UDPPacket", cIPPacket);
|
88
|
+
|
89
|
+
rb_define_method(cUDPPacket, "udp_sport", udpp_sport, 0);
|
90
|
+
rb_define_method(cUDPPacket, "sport", udpp_sport, 0);
|
91
|
+
rb_define_method(cUDPPacket, "udp_dport", udpp_dport, 0);
|
92
|
+
rb_define_method(cUDPPacket, "dport", udpp_dport, 0);
|
93
|
+
rb_define_method(cUDPPacket, "udp_len", udpp_len, 0);
|
94
|
+
rb_define_method(cUDPPacket, "udp_sum", udpp_sum, 0);
|
95
|
+
rb_define_method(cUDPPacket, "udp_data", udpp_data, 0);
|
96
|
+
}
|
data/lib/pcap_misc.rb
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
|
2
|
+
module Pcap
|
3
|
+
class Packet
|
4
|
+
def to_s
|
5
|
+
'Some packet'
|
6
|
+
end
|
7
|
+
|
8
|
+
def inspect
|
9
|
+
"#<#{self.class}: #{self}>"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class IPPacket
|
14
|
+
def to_s
|
15
|
+
"#{ip_src} > #{ip_dst}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class TCPPacket
|
20
|
+
def tcp_data_len
|
21
|
+
ip_len - 4 * (ip_hlen + tcp_hlen)
|
22
|
+
end
|
23
|
+
|
24
|
+
def tcp_flags_s
|
25
|
+
return \
|
26
|
+
(tcp_urg? ? 'U' : '.') +
|
27
|
+
(tcp_ack? ? 'A' : '.') +
|
28
|
+
(tcp_psh? ? 'P' : '.') +
|
29
|
+
(tcp_rst? ? 'R' : '.') +
|
30
|
+
(tcp_syn? ? 'S' : '.') +
|
31
|
+
(tcp_fin? ? 'F' : '.')
|
32
|
+
end
|
33
|
+
|
34
|
+
def to_s
|
35
|
+
"#{src}:#{sport} > #{dst}:#{dport} #{tcp_flags_s}"
|
36
|
+
end
|
37
|
+
|
38
|
+
def src_mac_address
|
39
|
+
return unpack_hex_string(raw_data[6, 12])
|
40
|
+
end
|
41
|
+
|
42
|
+
def dst_mac_address
|
43
|
+
return unpack_hex_string(raw_data[0, 6])
|
44
|
+
end
|
45
|
+
|
46
|
+
def unpack_hex_string(hex)
|
47
|
+
return hex.unpack('H2H2H2H2H2H2').join('')
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
class UDPPacket
|
52
|
+
def to_s
|
53
|
+
"#{src}:#{sport} > #{dst}:#{dport} len #{udp_len} sum #{udp_sum}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class ICMPPacket
|
58
|
+
def to_s
|
59
|
+
"#{src} > #{dst}: icmp: #{icmp_typestr}"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
#
|
64
|
+
# Backword compatibility
|
65
|
+
#
|
66
|
+
IpPacket = IPPacket
|
67
|
+
IpAddress = IPAddress
|
68
|
+
TcpPacket = TCPPacket
|
69
|
+
UdpPacket = UDPPacket
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
class Time
|
74
|
+
# tcpdump style format
|
75
|
+
def tcpdump
|
76
|
+
sprintf "%0.2d:%0.2d:%0.2d.%0.6d", hour, min, sec, tv_usec
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
autoload :Pcaplet, 'pcaplet'
|
data/lib/pcaplet.rb
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
require 'pcap'
|
2
|
+
require 'optparse'
|
3
|
+
|
4
|
+
def pcaplet_usage()
|
5
|
+
$stderr.print <<END
|
6
|
+
Usage: #{File.basename $0} [ -dnv ] [ -i interface | -r file ]
|
7
|
+
#{' ' * File.basename($0).length} [ -c count ] [ -s snaplen ] [ filter ]
|
8
|
+
Options:
|
9
|
+
-n do not convert address to name
|
10
|
+
-d debug mode
|
11
|
+
-v verbose mode
|
12
|
+
END
|
13
|
+
end
|
14
|
+
|
15
|
+
module Pcap
|
16
|
+
class Pcaplet
|
17
|
+
def usage(status, msg = nil)
|
18
|
+
$stderr.puts msg if msg
|
19
|
+
pcaplet_usage
|
20
|
+
exit(status)
|
21
|
+
end
|
22
|
+
|
23
|
+
def initialize(args = nil)
|
24
|
+
if args
|
25
|
+
ARGV[0,0] = args.split(/\s+/)
|
26
|
+
end
|
27
|
+
@device = nil
|
28
|
+
@rfile = nil
|
29
|
+
@count = -1
|
30
|
+
@snaplen = 68
|
31
|
+
@log_packets = false
|
32
|
+
@duplicated = nil
|
33
|
+
|
34
|
+
opts = OptionParser.new do |opts|
|
35
|
+
opts.on('-d') {$DEBUG = true}
|
36
|
+
opts.on('-v') {$VERBOSE = true}
|
37
|
+
opts.on('-n') {Pcap.convert = false}
|
38
|
+
opts.on('-i IFACE') {|s| @device = s}
|
39
|
+
opts.on('-r FILE') {|s| @rfile = s}
|
40
|
+
opts.on('-c COUNT', OptionParser::DecimalInteger) {|i| @count = i}
|
41
|
+
opts.on('-s LEN', OptionParser::DecimalInteger) {|i| @snaplen = i}
|
42
|
+
opts.on('-l') { @log_packets = true }
|
43
|
+
end
|
44
|
+
begin
|
45
|
+
opts.parse!
|
46
|
+
rescue
|
47
|
+
usage(1)
|
48
|
+
end
|
49
|
+
|
50
|
+
@filter = ARGV.join(' ')
|
51
|
+
|
52
|
+
# check option consistency
|
53
|
+
usage(1) if @device && @rfile
|
54
|
+
if !@device and !@rfile
|
55
|
+
@device = Pcap.lookupdev
|
56
|
+
end
|
57
|
+
|
58
|
+
# open
|
59
|
+
begin
|
60
|
+
if @device
|
61
|
+
@capture = Capture.open_live(@device, @snaplen)
|
62
|
+
elsif @rfile
|
63
|
+
if @rfile !~ /\.gz$/
|
64
|
+
@capture = Capture.open_offline(@rfile)
|
65
|
+
else
|
66
|
+
$stdin = IO.popen("gzip -dc < #@rfile", 'r')
|
67
|
+
@capture = Capture.open_offline('-')
|
68
|
+
end
|
69
|
+
end
|
70
|
+
@capture.setfilter(@filter)
|
71
|
+
rescue PcapError, ArgumentError
|
72
|
+
$stdout.flush
|
73
|
+
$stderr.puts $!
|
74
|
+
exit(1)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
attr('capture')
|
79
|
+
|
80
|
+
def add_filter(f)
|
81
|
+
if @filter == nil || @filter =~ /^\s*$/ # if empty
|
82
|
+
@filter = f
|
83
|
+
else
|
84
|
+
f = f.source if f.is_a? Filter
|
85
|
+
@filter = "( #{@filter} ) and ( #{f} )"
|
86
|
+
end
|
87
|
+
@capture.setfilter(@filter)
|
88
|
+
end
|
89
|
+
|
90
|
+
def each_packet(&block)
|
91
|
+
begin
|
92
|
+
@duplicated ||= (RUBY_PLATFORM =~ /linux/ && @device == "lo")
|
93
|
+
if !@duplicated
|
94
|
+
@capture.loop(@count, &block)
|
95
|
+
else
|
96
|
+
flip = true
|
97
|
+
@capture.loop(@count) do |pkt|
|
98
|
+
flip = (! flip)
|
99
|
+
next if flip
|
100
|
+
|
101
|
+
block.call pkt
|
102
|
+
end
|
103
|
+
end
|
104
|
+
rescue Exception => e
|
105
|
+
$stderr.puts "exception when looping over each packet loop: #{e.inspect}"
|
106
|
+
raise
|
107
|
+
ensure
|
108
|
+
# print statistics if live
|
109
|
+
if @device && @log_packets
|
110
|
+
stat = @capture.stats
|
111
|
+
if stat
|
112
|
+
$stderr.print("#{stat.recv} packets received by filter\n");
|
113
|
+
$stderr.print("#{stat.drop} packets dropped by kernel\n");
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
alias :each :each_packet
|
120
|
+
|
121
|
+
def close
|
122
|
+
@capture.close
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
Pcaplet = Pcap::Pcaplet
|