blackfoundry-pcap 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog +145 -0
- data/README +48 -0
- data/README.ja +50 -0
- data/Rakefile +23 -0
- data/ext/Pcap.c +798 -0
- data/ext/extconf.rb +16 -0
- data/ext/icmp_packet.c +444 -0
- data/ext/ip_packet.c +342 -0
- data/ext/packet.c +310 -0
- data/ext/ruby_pcap.h +133 -0
- data/ext/tcp_packet.c +121 -0
- data/ext/udp_packet.c +96 -0
- data/lib/pcap_misc.rb +116 -0
- data/lib/pcaplet.rb +113 -0
- metadata +79 -0
data/ext/ip_packet.c
ADDED
@@ -0,0 +1,342 @@
|
|
1
|
+
/*
|
2
|
+
* ip_packet.c
|
3
|
+
*
|
4
|
+
* $Id: ip_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 <netdb.h>
|
11
|
+
|
12
|
+
VALUE cIPPacket;
|
13
|
+
static VALUE cIPAddress;
|
14
|
+
|
15
|
+
#define CheckTruncateIp(pkt, need) \
|
16
|
+
CheckTruncate(pkt, pkt->hdr.layer3_off, need, "truncated IP")
|
17
|
+
|
18
|
+
VALUE
|
19
|
+
setup_ip_packet(pkt, nl_len)
|
20
|
+
struct packet_object *pkt;
|
21
|
+
int nl_len;
|
22
|
+
{
|
23
|
+
VALUE class;
|
24
|
+
|
25
|
+
DEBUG_PRINT("setup_ip_packet");
|
26
|
+
|
27
|
+
if (nl_len > 0 && IP_HDR(pkt)->ip_v != 4) {
|
28
|
+
return cPacket;
|
29
|
+
}
|
30
|
+
|
31
|
+
class = cIPPacket;
|
32
|
+
nl_len = MIN(nl_len, ntohs(IP_HDR(pkt)->ip_len));
|
33
|
+
if (nl_len > 20) {
|
34
|
+
int hl = IP_HDR(pkt)->ip_hl * 4;
|
35
|
+
int tl_len = nl_len - hl;
|
36
|
+
if (tl_len > 0) {
|
37
|
+
pkt->hdr.layer4_off = pkt->hdr.layer3_off + hl;
|
38
|
+
/* if this is fragment zero, setup upper layer */
|
39
|
+
if ((ntohs(IP_HDR(pkt)->ip_off) & IP_OFFMASK) == 0) {
|
40
|
+
switch (IP_HDR(pkt)->ip_p) {
|
41
|
+
case IPPROTO_TCP:
|
42
|
+
class = setup_tcp_packet(pkt, tl_len);
|
43
|
+
break;
|
44
|
+
case IPPROTO_UDP:
|
45
|
+
class = setup_udp_packet(pkt, tl_len);
|
46
|
+
break;
|
47
|
+
case IPPROTO_ICMP:
|
48
|
+
class = setup_icmp_packet(pkt, tl_len);
|
49
|
+
break;
|
50
|
+
}
|
51
|
+
}
|
52
|
+
}
|
53
|
+
}
|
54
|
+
|
55
|
+
return class;
|
56
|
+
}
|
57
|
+
|
58
|
+
#define IPP_METHOD(func, need, val) \
|
59
|
+
static VALUE\
|
60
|
+
(func)(self)\
|
61
|
+
VALUE self;\
|
62
|
+
{\
|
63
|
+
struct packet_object *pkt;\
|
64
|
+
struct ip *ip;\
|
65
|
+
\
|
66
|
+
DEBUG_PRINT(#func);\
|
67
|
+
GetPacket(self, pkt);\
|
68
|
+
CheckTruncateIp(pkt, (need));\
|
69
|
+
ip = IP_HDR(pkt);\
|
70
|
+
return (val);\
|
71
|
+
}
|
72
|
+
|
73
|
+
IPP_METHOD(ipp_ver, 1, INT2FIX(ip->ip_v))
|
74
|
+
IPP_METHOD(ipp_hlen, 1, INT2FIX(ip->ip_hl))
|
75
|
+
IPP_METHOD(ipp_tos, 2, INT2FIX(ip->ip_tos))
|
76
|
+
IPP_METHOD(ipp_len, 4, INT2FIX(ntohs(ip->ip_len)))
|
77
|
+
IPP_METHOD(ipp_id, 6, INT2FIX(ntohs(ip->ip_id)))
|
78
|
+
IPP_METHOD(ipp_flags, 8, INT2FIX((ntohs(ip->ip_off) & ~IP_OFFMASK) >> 13))
|
79
|
+
IPP_METHOD(ipp_df, 8, ntohs(ip->ip_off) & IP_DF ? Qtrue : Qfalse)
|
80
|
+
IPP_METHOD(ipp_mf, 8, ntohs(ip->ip_off) & IP_MF ? Qtrue : Qfalse)
|
81
|
+
IPP_METHOD(ipp_off, 8, INT2FIX(ntohs(ip->ip_off) & IP_OFFMASK))
|
82
|
+
IPP_METHOD(ipp_ttl, 9, INT2FIX(ip->ip_ttl))
|
83
|
+
IPP_METHOD(ipp_proto, 10, INT2FIX(ip->ip_p))
|
84
|
+
IPP_METHOD(ipp_sum, 12, INT2FIX(ntohs(ip->ip_sum)))
|
85
|
+
IPP_METHOD(ipp_src, 16, new_ipaddr(&ip->ip_src))
|
86
|
+
IPP_METHOD(ipp_dst, 20, new_ipaddr(&ip->ip_dst))
|
87
|
+
|
88
|
+
static VALUE
|
89
|
+
ipp_sumok(self)
|
90
|
+
VALUE self;
|
91
|
+
{
|
92
|
+
struct packet_object *pkt;
|
93
|
+
struct ip *ip;
|
94
|
+
int hlen, i, sum;
|
95
|
+
unsigned short *ipus;
|
96
|
+
|
97
|
+
GetPacket(self, pkt);
|
98
|
+
CheckTruncateIp(pkt, 20);
|
99
|
+
ip = IP_HDR(pkt);
|
100
|
+
|
101
|
+
hlen = ip->ip_hl * 4;
|
102
|
+
CheckTruncateIp(pkt, hlen);
|
103
|
+
|
104
|
+
ipus = (unsigned short *)ip;
|
105
|
+
sum = 0;
|
106
|
+
hlen /= 2; /* 16-bit word */
|
107
|
+
for (i = 0; i < hlen; i++) {
|
108
|
+
sum += ntohs(ipus[i]);
|
109
|
+
sum = (sum & 0xffff) + (sum >> 16);
|
110
|
+
}
|
111
|
+
if (sum == 0xffff)
|
112
|
+
return Qtrue;
|
113
|
+
return Qfalse;
|
114
|
+
}
|
115
|
+
|
116
|
+
static VALUE
|
117
|
+
ipp_data(self)
|
118
|
+
VALUE self;
|
119
|
+
{
|
120
|
+
struct packet_object *pkt;
|
121
|
+
struct ip *ip;
|
122
|
+
int len, hlen;
|
123
|
+
|
124
|
+
DEBUG_PRINT("ipp_data");
|
125
|
+
GetPacket(self, pkt);
|
126
|
+
CheckTruncateIp(pkt, 20);
|
127
|
+
ip = IP_HDR(pkt);
|
128
|
+
|
129
|
+
hlen = ip->ip_hl * 4;
|
130
|
+
len = pkt->hdr.pkthdr.caplen - pkt->hdr.layer3_off - hlen;
|
131
|
+
return rb_str_new((u_char *)ip + hlen, len);
|
132
|
+
}
|
133
|
+
|
134
|
+
/*
|
135
|
+
* IPAddress
|
136
|
+
*/
|
137
|
+
|
138
|
+
/* IPv4 adress (32bit) is stored by immediate value */
|
139
|
+
#if SIZEOF_VOIDP < 4
|
140
|
+
# error IPAddress assumes sizeof(void *) >= 4
|
141
|
+
#endif
|
142
|
+
|
143
|
+
#define GetIPAddress(obj, addr) {\
|
144
|
+
Check_Type(obj, T_DATA);\
|
145
|
+
addr = (struct in_addr *)&(DATA_PTR(obj));\
|
146
|
+
}
|
147
|
+
|
148
|
+
VALUE
|
149
|
+
new_ipaddr(addr)
|
150
|
+
struct in_addr *addr;
|
151
|
+
{
|
152
|
+
VALUE self;
|
153
|
+
|
154
|
+
self = Data_Wrap_Struct(cIPAddress, 0, 0, (void *)addr->s_addr);
|
155
|
+
return self;
|
156
|
+
}
|
157
|
+
|
158
|
+
#ifndef INADDR_NONE
|
159
|
+
# define INADDR_NONE (0xffffffff)
|
160
|
+
#endif
|
161
|
+
static VALUE
|
162
|
+
ipaddr_s_new(self, val)
|
163
|
+
VALUE self, val;
|
164
|
+
{
|
165
|
+
struct in_addr addr;
|
166
|
+
struct hostent *hent;
|
167
|
+
char *hname;
|
168
|
+
|
169
|
+
switch(TYPE(val)) {
|
170
|
+
case T_STRING:
|
171
|
+
hname = RSTRING(val)->ptr;
|
172
|
+
hent = gethostbyname(hname);
|
173
|
+
if (hent == NULL) {
|
174
|
+
extern int h_errno;
|
175
|
+
switch (h_errno) {
|
176
|
+
case HOST_NOT_FOUND:
|
177
|
+
rb_raise(ePcapError, "host not found: %s", hname);
|
178
|
+
break;
|
179
|
+
default:
|
180
|
+
#ifdef HAVE_HSTRERROR
|
181
|
+
rb_raise(ePcapError, (char *)hstrerror(h_errno));
|
182
|
+
#else
|
183
|
+
rb_raise(ePcapError, "host not found: %s", hname);
|
184
|
+
#endif
|
185
|
+
}
|
186
|
+
}
|
187
|
+
addr = *(struct in_addr *)hent->h_addr;
|
188
|
+
break;
|
189
|
+
case T_FIXNUM:
|
190
|
+
case T_BIGNUM:
|
191
|
+
addr.s_addr = htonl(NUM2ULONG(val));
|
192
|
+
break;
|
193
|
+
default:
|
194
|
+
rb_raise(rb_eTypeError, "String or Integer required");
|
195
|
+
}
|
196
|
+
return new_ipaddr(&addr);
|
197
|
+
}
|
198
|
+
|
199
|
+
static VALUE
|
200
|
+
ipaddr_to_i(self)
|
201
|
+
VALUE self;
|
202
|
+
{
|
203
|
+
struct in_addr *addr;
|
204
|
+
|
205
|
+
GetIPAddress(self, addr);
|
206
|
+
return UINT32_2_NUM(ntohl(addr->s_addr));
|
207
|
+
}
|
208
|
+
|
209
|
+
static VALUE
|
210
|
+
ipaddr_num_s(self)
|
211
|
+
VALUE self;
|
212
|
+
{
|
213
|
+
struct in_addr *addr;
|
214
|
+
|
215
|
+
GetIPAddress(self, addr);
|
216
|
+
return rb_str_new2(inet_ntoa(*addr));
|
217
|
+
}
|
218
|
+
|
219
|
+
static VALUE
|
220
|
+
ipaddr_hostname(self)
|
221
|
+
VALUE self;
|
222
|
+
{
|
223
|
+
struct in_addr *addr;
|
224
|
+
struct hostent *host;
|
225
|
+
|
226
|
+
GetIPAddress(self, addr);
|
227
|
+
host = gethostbyaddr((char *)&addr->s_addr, sizeof addr->s_addr, AF_INET);
|
228
|
+
if (host == NULL)
|
229
|
+
return ipaddr_num_s(self);
|
230
|
+
return rb_str_new2(host->h_name);
|
231
|
+
}
|
232
|
+
|
233
|
+
static VALUE
|
234
|
+
ipaddr_to_s(self)
|
235
|
+
VALUE self;
|
236
|
+
{
|
237
|
+
if (RTEST(rbpcap_convert))
|
238
|
+
return ipaddr_hostname(self);
|
239
|
+
else
|
240
|
+
return ipaddr_num_s(self);
|
241
|
+
}
|
242
|
+
|
243
|
+
static VALUE
|
244
|
+
ipaddr_equal(self, other)
|
245
|
+
VALUE self, other;
|
246
|
+
{
|
247
|
+
struct in_addr *addr1;
|
248
|
+
struct in_addr *addr2;
|
249
|
+
|
250
|
+
GetIPAddress(self, addr1);
|
251
|
+
if (rb_class_of(other) == cIPAddress) {
|
252
|
+
GetIPAddress(other, addr2);
|
253
|
+
if (addr1->s_addr == addr2->s_addr)
|
254
|
+
return Qtrue;
|
255
|
+
}
|
256
|
+
return Qfalse;
|
257
|
+
}
|
258
|
+
|
259
|
+
static VALUE
|
260
|
+
ipaddr_hash(self)
|
261
|
+
VALUE self;
|
262
|
+
{
|
263
|
+
struct in_addr *addr;
|
264
|
+
|
265
|
+
GetIPAddress(self, addr);
|
266
|
+
return INT2FIX(ntohl(addr->s_addr));
|
267
|
+
}
|
268
|
+
|
269
|
+
static VALUE
|
270
|
+
ipaddr_dump(self, limit)
|
271
|
+
VALUE self;
|
272
|
+
VALUE limit;
|
273
|
+
{
|
274
|
+
struct in_addr *addr;
|
275
|
+
|
276
|
+
GetIPAddress(self, addr);
|
277
|
+
return rb_str_new((char *)addr, sizeof addr);
|
278
|
+
}
|
279
|
+
|
280
|
+
static VALUE
|
281
|
+
ipaddr_s_load(klass, str)
|
282
|
+
VALUE klass;
|
283
|
+
VALUE str;
|
284
|
+
{
|
285
|
+
struct in_addr addr;
|
286
|
+
int i;
|
287
|
+
|
288
|
+
if (RSTRING(str)->len != sizeof addr) {
|
289
|
+
rb_raise(rb_eArgError, "dump format error (IPAddress)");
|
290
|
+
}
|
291
|
+
for (i = 0; i < sizeof addr; i++) {
|
292
|
+
((char *)&addr)[i] = RSTRING(str)->ptr[i];
|
293
|
+
}
|
294
|
+
return new_ipaddr(&addr);
|
295
|
+
}
|
296
|
+
|
297
|
+
void
|
298
|
+
Init_ip_packet(void)
|
299
|
+
{
|
300
|
+
DEBUG_PRINT("Init_ip_packet");
|
301
|
+
|
302
|
+
cIPPacket = rb_define_class_under(mPcap, "IPPacket", cPacket);
|
303
|
+
|
304
|
+
rb_define_method(cIPPacket, "ip_ver", ipp_ver, 0);
|
305
|
+
rb_define_method(cIPPacket, "ip_hlen", ipp_hlen, 0);
|
306
|
+
rb_define_method(cIPPacket, "ip_tos", ipp_tos, 0);
|
307
|
+
rb_define_method(cIPPacket, "ip_len", ipp_len, 0);
|
308
|
+
rb_define_method(cIPPacket, "ip_id", ipp_id, 0);
|
309
|
+
rb_define_method(cIPPacket, "ip_flags", ipp_flags, 0);
|
310
|
+
rb_define_method(cIPPacket, "ip_df?", ipp_df, 0);
|
311
|
+
rb_define_method(cIPPacket, "ip_mf?", ipp_mf, 0);
|
312
|
+
rb_define_method(cIPPacket, "ip_off", ipp_off, 0);
|
313
|
+
rb_define_method(cIPPacket, "ip_ttl", ipp_ttl, 0);
|
314
|
+
rb_define_method(cIPPacket, "ip_proto", ipp_proto, 0);
|
315
|
+
rb_define_method(cIPPacket, "ip_sum", ipp_sum, 0);
|
316
|
+
rb_define_method(cIPPacket, "ip_sumok?", ipp_sumok, 0);
|
317
|
+
rb_define_method(cIPPacket, "ip_src", ipp_src, 0);
|
318
|
+
rb_define_method(cIPPacket, "src", ipp_src, 0);
|
319
|
+
rb_define_method(cIPPacket, "ip_dst", ipp_dst, 0);
|
320
|
+
rb_define_method(cIPPacket, "dst", ipp_dst, 0);
|
321
|
+
rb_define_method(cIPPacket, "ip_data", ipp_data, 0);
|
322
|
+
|
323
|
+
cIPAddress = rb_define_class_under(mPcap, "IPAddress", rb_cObject);
|
324
|
+
rb_define_singleton_method(cIPAddress, "new", ipaddr_s_new, 1);
|
325
|
+
rb_define_method(cIPAddress, "to_i", ipaddr_to_i, 0);
|
326
|
+
rb_define_method(cIPAddress, "to_s", ipaddr_to_s, 0);
|
327
|
+
rb_define_method(cIPAddress, "num_s", ipaddr_num_s, 0);
|
328
|
+
rb_define_method(cIPAddress, "to_num_s", ipaddr_num_s, 0); /* BWC */
|
329
|
+
rb_define_method(cIPAddress, "hostname", ipaddr_hostname, 0);
|
330
|
+
rb_define_method(cIPAddress, "sym_s", ipaddr_hostname, 0);
|
331
|
+
rb_define_method(cIPAddress, "==", ipaddr_equal, 1);
|
332
|
+
rb_define_method(cIPAddress, "===", ipaddr_equal, 1);
|
333
|
+
rb_define_method(cIPAddress, "eql?", ipaddr_equal, 1);
|
334
|
+
rb_define_method(cIPAddress, "hash", ipaddr_hash, 0);
|
335
|
+
|
336
|
+
rb_define_method(cIPAddress, "_dump", ipaddr_dump, 1);
|
337
|
+
rb_define_singleton_method(cIPAddress, "_load", ipaddr_s_load, 1);
|
338
|
+
|
339
|
+
Init_tcp_packet();
|
340
|
+
Init_udp_packet();
|
341
|
+
Init_icmp_packet();
|
342
|
+
}
|
data/ext/packet.c
ADDED
@@ -0,0 +1,310 @@
|
|
1
|
+
/*
|
2
|
+
* packet.c
|
3
|
+
*
|
4
|
+
* $Id: packet.c,v 1.4 2000/08/13 06:56:15 fukusima Exp $
|
5
|
+
*
|
6
|
+
* Copyright (C) 1998-2000 Masaki Fukushima
|
7
|
+
*/
|
8
|
+
|
9
|
+
#include "ruby.h"
|
10
|
+
#include "ruby_pcap.h"
|
11
|
+
#include <sys/socket.h>
|
12
|
+
#include <net/if.h>
|
13
|
+
#include <netinet/if_ether.h>
|
14
|
+
|
15
|
+
#define DL_HDR(pkt) ((u_char *)LAYER2_HDR(pkt))
|
16
|
+
#define DL_DATA(pkt) ((u_char *)LAYER3_HDR(pkt))
|
17
|
+
|
18
|
+
VALUE cPacket;
|
19
|
+
static VALUE mMarshal;
|
20
|
+
int id_load;
|
21
|
+
int id_dump;
|
22
|
+
|
23
|
+
/* called from GC */
|
24
|
+
static void
|
25
|
+
free_packet(pkt)
|
26
|
+
struct packet_object *pkt;
|
27
|
+
{
|
28
|
+
DEBUG_PRINT("free_packet");
|
29
|
+
free(pkt);
|
30
|
+
}
|
31
|
+
|
32
|
+
/* called from GC */
|
33
|
+
static void
|
34
|
+
mark_packet(pkt)
|
35
|
+
struct packet_object *pkt;
|
36
|
+
{
|
37
|
+
DEBUG_PRINT("mark_packet");
|
38
|
+
if (pkt->udata != Qnil)
|
39
|
+
rb_gc_mark(pkt->udata);
|
40
|
+
}
|
41
|
+
|
42
|
+
struct datalink_type {
|
43
|
+
int nltype_off; /* offset of network-layer type field */
|
44
|
+
int nl_off; /* offset of network-layer header */
|
45
|
+
};
|
46
|
+
|
47
|
+
static struct datalink_type datalinks[] = {
|
48
|
+
#if 0
|
49
|
+
{ 0, 4 }, /* 0: DLT_NULL */
|
50
|
+
#else
|
51
|
+
{ -1, 4 }, /* 0: DLT_NULL */
|
52
|
+
#endif
|
53
|
+
{ 12, 14 }, /* 1: DLT_EN10MB */
|
54
|
+
{ -1, -1 }, /* 2: DLT_EN3MB */
|
55
|
+
{ -1, -1 }, /* 3: DLT_AX25 */
|
56
|
+
{ -1, -1 }, /* 4: DLT_PRONET */
|
57
|
+
{ -1, -1 }, /* 5: DLT_CHAOS */
|
58
|
+
{ 20, 22 }, /* 6: DLT_IEEE802 */
|
59
|
+
{ -1, -1 }, /* 7: DLT_ARCNET */
|
60
|
+
{ -1, 16 }, /* 8: DLT_SLIP */
|
61
|
+
{ 2, 4 }, /* 9: DLT_PPP */
|
62
|
+
#ifndef PCAP_FDDIPAD
|
63
|
+
{ 19, 21 }, /* 10: DLT_FDDI */
|
64
|
+
#else
|
65
|
+
{ 19 + PCAP_FDDIPAD, 21 + PCAP_FDDIPAD },
|
66
|
+
#endif
|
67
|
+
{ 6, 8 }, /* 11: DLT_ATM_RFC1483 */
|
68
|
+
{ -1, 0 }, /* 12: DLT_RAW */
|
69
|
+
{ -1, 24 }, /* 13: DLT_SLIP_BSDOS */
|
70
|
+
{ 5, 24 } /* 14: DLT_PPP_BSDOS */
|
71
|
+
#define DATALINK_MAX 14
|
72
|
+
};
|
73
|
+
|
74
|
+
VALUE
|
75
|
+
new_packet(data, pkthdr, dl_type)
|
76
|
+
const u_char *data;
|
77
|
+
const struct pcap_pkthdr *pkthdr;
|
78
|
+
int dl_type;
|
79
|
+
{
|
80
|
+
VALUE class;
|
81
|
+
struct packet_object *pkt;
|
82
|
+
int nl_off, nl_len, nltype_off, nl_type, pad;
|
83
|
+
|
84
|
+
DEBUG_PRINT("new_packet");
|
85
|
+
|
86
|
+
/* check nework layer type and offset */
|
87
|
+
if (dl_type > DATALINK_MAX) {
|
88
|
+
rb_raise(ePcapError, "Unknown data-link type (%d)", dl_type);
|
89
|
+
}
|
90
|
+
nltype_off = datalinks[dl_type].nltype_off;
|
91
|
+
nl_off = datalinks[dl_type].nl_off;
|
92
|
+
if (nl_off < 0) {
|
93
|
+
rb_raise(ePcapError, "Unsupported data-link type (%d)", dl_type);
|
94
|
+
}
|
95
|
+
if (nltype_off == -1) {
|
96
|
+
/* assume IP */
|
97
|
+
nl_type = ETHERTYPE_IP;
|
98
|
+
} else {
|
99
|
+
/* assume Ether Type value */
|
100
|
+
nl_type = ntohs(*(u_short *)(data + nltype_off));
|
101
|
+
}
|
102
|
+
|
103
|
+
/* alloc memory and setup packet_object */
|
104
|
+
pad = nl_off % 4; /* align network layer header */
|
105
|
+
pkt = xmalloc(sizeof(*pkt) + pad + pkthdr->caplen);
|
106
|
+
pkt->hdr.version = PACKET_MARSHAL_VERSION;
|
107
|
+
pkt->hdr.flags = 0;
|
108
|
+
pkt->hdr.dl_type = dl_type;
|
109
|
+
pkt->hdr.layer3_off = OFF_NONEXIST;
|
110
|
+
pkt->hdr.layer4_off = OFF_NONEXIST;
|
111
|
+
pkt->hdr.layer5_off = OFF_NONEXIST;
|
112
|
+
pkt->hdr.pkthdr = *pkthdr;
|
113
|
+
pkt->data = (u_char *)pkt + sizeof(*pkt) + pad;
|
114
|
+
pkt->udata = Qnil;
|
115
|
+
memcpy(pkt->data, data, pkthdr->caplen);
|
116
|
+
|
117
|
+
nl_len = pkthdr->caplen - nl_off;
|
118
|
+
if (nl_off >= 0 && nl_len > 0)
|
119
|
+
pkt->hdr.layer3_off = nl_off;
|
120
|
+
|
121
|
+
/* setup upper layer */
|
122
|
+
class = cPacket;
|
123
|
+
if (pkt->hdr.layer3_off != OFF_NONEXIST) {
|
124
|
+
switch (nl_type) {
|
125
|
+
case ETHERTYPE_IP:
|
126
|
+
class = setup_ip_packet(pkt, nl_len);
|
127
|
+
break;
|
128
|
+
}
|
129
|
+
}
|
130
|
+
#if DEBUG
|
131
|
+
if (ruby_debug && TYPE(class) != T_CLASS) {
|
132
|
+
rb_fatal("not class");
|
133
|
+
}
|
134
|
+
#endif
|
135
|
+
return Data_Wrap_Struct(class, mark_packet, free_packet, pkt);
|
136
|
+
}
|
137
|
+
|
138
|
+
static VALUE
|
139
|
+
packet_load(class, str)
|
140
|
+
VALUE class;
|
141
|
+
VALUE str;
|
142
|
+
{
|
143
|
+
struct packet_object *pkt = NULL;
|
144
|
+
struct packet_object_header *hdr;
|
145
|
+
int version;
|
146
|
+
u_char *str_ptr;
|
147
|
+
|
148
|
+
DEBUG_PRINT("packet_load");
|
149
|
+
|
150
|
+
str_ptr = RSTRING(str)->ptr;
|
151
|
+
hdr = (struct packet_object_header *)str_ptr;
|
152
|
+
version = hdr->version;
|
153
|
+
if (version == PACKET_MARSHAL_VERSION) {
|
154
|
+
bpf_u_int32 caplen;
|
155
|
+
u_short layer3_off;
|
156
|
+
int pad;
|
157
|
+
|
158
|
+
caplen = ntohl(hdr->pkthdr.caplen);
|
159
|
+
layer3_off = ntohs(hdr->layer3_off);
|
160
|
+
pad = layer3_off % 4; /* align network layer header */
|
161
|
+
pkt = (struct packet_object *)xmalloc(sizeof(*pkt) + pad + caplen);
|
162
|
+
|
163
|
+
pkt->hdr.version = PACKET_MARSHAL_VERSION;
|
164
|
+
pkt->hdr.flags = hdr->flags;
|
165
|
+
pkt->hdr.dl_type = hdr->dl_type;
|
166
|
+
pkt->hdr.layer3_off = ntohs(hdr->layer3_off);
|
167
|
+
pkt->hdr.layer4_off = ntohs(hdr->layer4_off);
|
168
|
+
pkt->hdr.layer5_off = ntohs(hdr->layer5_off);
|
169
|
+
pkt->hdr.pkthdr.ts.tv_sec = ntohl(hdr->pkthdr.ts.tv_sec);
|
170
|
+
pkt->hdr.pkthdr.ts.tv_usec = ntohl(hdr->pkthdr.ts.tv_usec);
|
171
|
+
pkt->hdr.pkthdr.caplen = ntohl(hdr->pkthdr.caplen);
|
172
|
+
pkt->hdr.pkthdr.len = ntohl(hdr->pkthdr.len);
|
173
|
+
|
174
|
+
pkt->data = (u_char *)pkt + sizeof(*pkt) + pad;
|
175
|
+
memcpy(pkt->data, str_ptr + sizeof(*hdr), caplen);
|
176
|
+
if (PKTFLAG_TEST(pkt, POH_UDATA)) {
|
177
|
+
int l = sizeof(*hdr) + caplen;
|
178
|
+
VALUE ustr = rb_str_substr(str, l, RSTRING(str)->len - l);
|
179
|
+
pkt->udata = rb_funcall(mMarshal, id_load, 1, ustr);
|
180
|
+
} else {
|
181
|
+
pkt->udata = Qnil;
|
182
|
+
}
|
183
|
+
PKTFLAG_SET(pkt, POH_UDATA, (pkt->udata != Qnil));
|
184
|
+
} else {
|
185
|
+
rb_raise(rb_eArgError, "unknown packet marshal version(0x%x)", version);
|
186
|
+
}
|
187
|
+
|
188
|
+
if (pkt != NULL)
|
189
|
+
return Data_Wrap_Struct(class, mark_packet, free_packet, pkt);
|
190
|
+
else
|
191
|
+
return Qnil;
|
192
|
+
}
|
193
|
+
|
194
|
+
static VALUE
|
195
|
+
packet_dump(self, limit)
|
196
|
+
VALUE self;
|
197
|
+
VALUE limit;
|
198
|
+
{
|
199
|
+
struct packet_object *pkt;
|
200
|
+
struct packet_object_header hdr;
|
201
|
+
VALUE str;
|
202
|
+
|
203
|
+
DEBUG_PRINT("packet_dump");
|
204
|
+
GetPacket(self, pkt);
|
205
|
+
|
206
|
+
hdr.version = PACKET_MARSHAL_VERSION;
|
207
|
+
hdr.flags = pkt->hdr.flags;
|
208
|
+
hdr.dl_type = pkt->hdr.dl_type;
|
209
|
+
hdr.layer3_off = htons(pkt->hdr.layer3_off);
|
210
|
+
hdr.layer4_off = htons(pkt->hdr.layer4_off);
|
211
|
+
hdr.layer5_off = htons(pkt->hdr.layer5_off);
|
212
|
+
hdr.pkthdr.ts.tv_sec = htonl(pkt->hdr.pkthdr.ts.tv_sec);
|
213
|
+
hdr.pkthdr.ts.tv_usec = htonl(pkt->hdr.pkthdr.ts.tv_usec);
|
214
|
+
hdr.pkthdr.caplen = htonl(pkt->hdr.pkthdr.caplen);
|
215
|
+
hdr.pkthdr.len = htonl(pkt->hdr.pkthdr.len);
|
216
|
+
|
217
|
+
str = rb_str_new((char *)&hdr, sizeof(hdr));
|
218
|
+
rb_str_cat(str, pkt->data, pkt->hdr.pkthdr.caplen);
|
219
|
+
if (pkt->udata != Qnil) {
|
220
|
+
VALUE ustr;
|
221
|
+
ustr = rb_funcall(mMarshal, id_dump, 1, pkt->udata);
|
222
|
+
rb_str_concat(str, ustr);
|
223
|
+
}
|
224
|
+
return str;
|
225
|
+
}
|
226
|
+
|
227
|
+
static VALUE
|
228
|
+
packet_set_udata(self, val)
|
229
|
+
VALUE self;
|
230
|
+
VALUE val;
|
231
|
+
{
|
232
|
+
struct packet_object *pkt;
|
233
|
+
|
234
|
+
DEBUG_PRINT("packet_set_udata");
|
235
|
+
GetPacket(self, pkt);
|
236
|
+
|
237
|
+
pkt->udata = val;
|
238
|
+
PKTFLAG_SET(pkt, POH_UDATA, (val != Qnil));
|
239
|
+
return val;
|
240
|
+
}
|
241
|
+
|
242
|
+
static VALUE
|
243
|
+
packet_match(self, expr)
|
244
|
+
VALUE self;
|
245
|
+
VALUE expr;
|
246
|
+
{
|
247
|
+
if (IsKindOf(expr, cFilter)) {
|
248
|
+
return filter_match(expr, self);
|
249
|
+
}
|
250
|
+
rb_raise(rb_eArgError, "Not Filter");
|
251
|
+
}
|
252
|
+
|
253
|
+
#define PACKET_METHOD(func, val) \
|
254
|
+
static VALUE\
|
255
|
+
(func)(self)\
|
256
|
+
VALUE self;\
|
257
|
+
{\
|
258
|
+
struct packet_object *pkt;\
|
259
|
+
\
|
260
|
+
DEBUG_PRINT(#func);\
|
261
|
+
GetPacket(self, pkt);\
|
262
|
+
return (val);\
|
263
|
+
}
|
264
|
+
|
265
|
+
PACKET_METHOD(packet_get_udata, pkt->udata);
|
266
|
+
PACKET_METHOD(packet_datalink, INT2FIX(pkt->hdr.dl_type));
|
267
|
+
PACKET_METHOD(packet_ip, rb_obj_is_kind_of(self, cIPPacket));
|
268
|
+
PACKET_METHOD(packet_tcp, rb_obj_is_kind_of(self, cTCPPacket));
|
269
|
+
PACKET_METHOD(packet_udp, rb_obj_is_kind_of(self, cUDPPacket));
|
270
|
+
PACKET_METHOD(packet_length, UINT32_2_NUM(pkt->hdr.pkthdr.len));
|
271
|
+
PACKET_METHOD(packet_caplen, UINT32_2_NUM(pkt->hdr.pkthdr.caplen));
|
272
|
+
PACKET_METHOD(packet_time, rb_time_new(pkt->hdr.pkthdr.ts.tv_sec,
|
273
|
+
pkt->hdr.pkthdr.ts.tv_usec));
|
274
|
+
PACKET_METHOD(packet_time_i, rb_int2inum(pkt->hdr.pkthdr.ts.tv_sec));
|
275
|
+
PACKET_METHOD(packet_raw_data, rb_str_new(pkt->data, pkt->hdr.pkthdr.caplen));
|
276
|
+
|
277
|
+
void
|
278
|
+
Init_packet(void)
|
279
|
+
{
|
280
|
+
DEBUG_PRINT("Init_packet");
|
281
|
+
|
282
|
+
/* define class Packet */
|
283
|
+
cPacket = rb_define_class_under(mPcap, "Packet", rb_cObject);
|
284
|
+
|
285
|
+
rb_define_singleton_method(cPacket, "_load", packet_load, 1);
|
286
|
+
rb_define_method(cPacket, "_dump", packet_dump, 1);
|
287
|
+
/* marshal backward compatibility */
|
288
|
+
rb_define_singleton_method(cPacket, "_load_from", packet_load, 1);
|
289
|
+
rb_define_method(cPacket, "_dump_to", packet_dump, 1);
|
290
|
+
|
291
|
+
rb_define_method(cPacket, "udata", packet_get_udata, 0);
|
292
|
+
rb_define_method(cPacket, "udata=", packet_set_udata, 1);
|
293
|
+
rb_define_method(cPacket, "datalink", packet_datalink, 0);
|
294
|
+
rb_define_method(cPacket, "ip?", packet_ip, 0);
|
295
|
+
rb_define_method(cPacket, "tcp?", packet_tcp, 0);
|
296
|
+
rb_define_method(cPacket, "udp?", packet_udp, 0);
|
297
|
+
rb_define_method(cPacket, "length", packet_length, 0);
|
298
|
+
rb_define_method(cPacket, "size", packet_length, 0);
|
299
|
+
rb_define_method(cPacket, "caplen", packet_caplen, 0);
|
300
|
+
rb_define_method(cPacket, "time", packet_time, 0);
|
301
|
+
rb_define_method(cPacket, "time_i", packet_time_i, 0);
|
302
|
+
rb_define_method(cPacket, "raw_data", packet_raw_data, 0);
|
303
|
+
rb_define_method(cPacket, "=~", packet_match, 1);
|
304
|
+
|
305
|
+
/* mMarshal in ruby/marshal.c is static. Why? */
|
306
|
+
mMarshal = rb_eval_string("Marshal");
|
307
|
+
id_load = rb_intern("load");
|
308
|
+
id_dump = rb_intern("dump");
|
309
|
+
Init_ip_packet();
|
310
|
+
}
|