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/ip_packet.c
ADDED
@@ -0,0 +1,424 @@
|
|
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
|
+
static unsigned short in_cksum(unsigned char *data, int len);
|
16
|
+
|
17
|
+
#define CheckTruncateIp(pkt, need) \
|
18
|
+
CheckTruncate(pkt, pkt->hdr.layer3_off, need, "truncated IP")
|
19
|
+
|
20
|
+
VALUE
|
21
|
+
setup_ip_packet(pkt, nl_len)
|
22
|
+
struct packet_object *pkt;
|
23
|
+
int nl_len;
|
24
|
+
{
|
25
|
+
VALUE class;
|
26
|
+
|
27
|
+
DEBUG_PRINT("setup_ip_packet");
|
28
|
+
|
29
|
+
if (nl_len > 0 && IP_HDR(pkt)->ip_v != 4) {
|
30
|
+
return cPacket;
|
31
|
+
}
|
32
|
+
|
33
|
+
class = cIPPacket;
|
34
|
+
nl_len = MIN(nl_len, ntohs(IP_HDR(pkt)->ip_len));
|
35
|
+
if (nl_len > 20) {
|
36
|
+
int hl = IP_HDR(pkt)->ip_hl * 4;
|
37
|
+
int tl_len = nl_len - hl;
|
38
|
+
if (tl_len > 0) {
|
39
|
+
pkt->hdr.layer4_off = pkt->hdr.layer3_off + hl;
|
40
|
+
/* if this is fragment zero, setup upper layer */
|
41
|
+
if ((ntohs(IP_HDR(pkt)->ip_off) & IP_OFFMASK) == 0) {
|
42
|
+
switch (IP_HDR(pkt)->ip_p) {
|
43
|
+
case IPPROTO_TCP:
|
44
|
+
class = setup_tcp_packet(pkt, tl_len);
|
45
|
+
break;
|
46
|
+
case IPPROTO_UDP:
|
47
|
+
class = setup_udp_packet(pkt, tl_len);
|
48
|
+
break;
|
49
|
+
case IPPROTO_ICMP:
|
50
|
+
class = setup_icmp_packet(pkt, tl_len);
|
51
|
+
break;
|
52
|
+
}
|
53
|
+
}
|
54
|
+
}
|
55
|
+
}
|
56
|
+
|
57
|
+
return class;
|
58
|
+
}
|
59
|
+
|
60
|
+
#define IPP_METHOD(func, need, val) \
|
61
|
+
static VALUE\
|
62
|
+
(func)(self)\
|
63
|
+
VALUE self;\
|
64
|
+
{\
|
65
|
+
struct packet_object *pkt;\
|
66
|
+
struct ip *ip;\
|
67
|
+
\
|
68
|
+
DEBUG_PRINT(#func);\
|
69
|
+
GetPacket(self, pkt);\
|
70
|
+
CheckTruncateIp(pkt, (need));\
|
71
|
+
ip = IP_HDR(pkt);\
|
72
|
+
return (val);\
|
73
|
+
}
|
74
|
+
|
75
|
+
IPP_METHOD(ipp_ver, 1, INT2FIX(ip->ip_v))
|
76
|
+
IPP_METHOD(ipp_hlen, 1, INT2FIX(ip->ip_hl))
|
77
|
+
IPP_METHOD(ipp_tos, 2, INT2FIX(ip->ip_tos))
|
78
|
+
IPP_METHOD(ipp_len, 4, INT2FIX(ntohs(ip->ip_len)))
|
79
|
+
IPP_METHOD(ipp_id, 6, INT2FIX(ntohs(ip->ip_id)))
|
80
|
+
IPP_METHOD(ipp_flags, 8, INT2FIX((ntohs(ip->ip_off) & ~IP_OFFMASK) >> 13))
|
81
|
+
IPP_METHOD(ipp_df, 8, ntohs(ip->ip_off) & IP_DF ? Qtrue : Qfalse)
|
82
|
+
IPP_METHOD(ipp_mf, 8, ntohs(ip->ip_off) & IP_MF ? Qtrue : Qfalse)
|
83
|
+
IPP_METHOD(ipp_off, 8, INT2FIX(ntohs(ip->ip_off) & IP_OFFMASK))
|
84
|
+
IPP_METHOD(ipp_ttl, 9, INT2FIX(ip->ip_ttl))
|
85
|
+
IPP_METHOD(ipp_proto, 10, INT2FIX(ip->ip_p))
|
86
|
+
IPP_METHOD(ipp_sum, 12, INT2FIX(ntohs(ip->ip_sum)))
|
87
|
+
IPP_METHOD(ipp_src, 16, new_ipaddr(&ip->ip_src))
|
88
|
+
IPP_METHOD(ipp_dst, 20, new_ipaddr(&ip->ip_dst))
|
89
|
+
|
90
|
+
|
91
|
+
#define IPP_SET_METHOD(func, need, member) \
|
92
|
+
static VALUE \
|
93
|
+
(func)(self, val) \
|
94
|
+
VALUE self; \
|
95
|
+
VALUE val; \
|
96
|
+
{ \
|
97
|
+
struct packet_object *pkt; \
|
98
|
+
struct ip *ip; \
|
99
|
+
\
|
100
|
+
DEBUG_PRINT(#func); \
|
101
|
+
GetPacket(self, pkt); \
|
102
|
+
CheckTruncateIp(pkt, (need)); \
|
103
|
+
ip = IP_HDR(pkt); \
|
104
|
+
\
|
105
|
+
switch(TYPE(val)) { \
|
106
|
+
case T_STRING: \
|
107
|
+
(member).s_addr = inet_addr(RSTRING_PTR(val)); \
|
108
|
+
break; \
|
109
|
+
case T_BIGNUM: \
|
110
|
+
(member).s_addr = NUM2UINT(val); \
|
111
|
+
break; \
|
112
|
+
case T_DATA: \
|
113
|
+
(member).s_addr = ((struct in_addr *)&(DATA_PTR(val)))->s_addr; \
|
114
|
+
} \
|
115
|
+
ip->ip_sum = 0; \
|
116
|
+
ip->ip_sum = in_cksum((unsigned char *)ip, ip->ip_hl*4); \
|
117
|
+
return val; \
|
118
|
+
}
|
119
|
+
|
120
|
+
|
121
|
+
IPP_SET_METHOD(ipp_set_src, 16, ip->ip_src)
|
122
|
+
IPP_SET_METHOD(ipp_set_dst, 20, ip->ip_dst)
|
123
|
+
|
124
|
+
static VALUE
|
125
|
+
ipp_sumok(self)
|
126
|
+
VALUE self;
|
127
|
+
{
|
128
|
+
struct packet_object *pkt;
|
129
|
+
struct ip *ip;
|
130
|
+
int hlen, i, sum;
|
131
|
+
unsigned short *ipus;
|
132
|
+
|
133
|
+
GetPacket(self, pkt);
|
134
|
+
CheckTruncateIp(pkt, 20);
|
135
|
+
ip = IP_HDR(pkt);
|
136
|
+
|
137
|
+
hlen = ip->ip_hl * 4;
|
138
|
+
CheckTruncateIp(pkt, hlen);
|
139
|
+
|
140
|
+
ipus = (unsigned short *)ip;
|
141
|
+
sum = 0;
|
142
|
+
hlen /= 2; /* 16-bit word */
|
143
|
+
for (i = 0; i < hlen; i++) {
|
144
|
+
sum += ntohs(ipus[i]);
|
145
|
+
sum = (sum & 0xffff) + (sum >> 16);
|
146
|
+
}
|
147
|
+
if (sum == 0xffff)
|
148
|
+
return Qtrue;
|
149
|
+
return Qfalse;
|
150
|
+
}
|
151
|
+
|
152
|
+
static unsigned short
|
153
|
+
in_cksum(unsigned char *data, int len)
|
154
|
+
{
|
155
|
+
long sum = 0; /* assume 32 bit long, 16 bit short */
|
156
|
+
unsigned short *temp = (unsigned short *)data;
|
157
|
+
|
158
|
+
while(len > 1){
|
159
|
+
sum += *temp++;
|
160
|
+
if(sum & 0x80000000) /* if high order bit set, fold */
|
161
|
+
sum = (sum & 0xFFFF) + (sum >> 16);
|
162
|
+
len -= 2;
|
163
|
+
}
|
164
|
+
if(len) /* take care of left over byte */
|
165
|
+
sum += (unsigned short) *((unsigned char *)temp);
|
166
|
+
|
167
|
+
while(sum>>16)
|
168
|
+
sum = (sum & 0xFFFF) + (sum >> 16);
|
169
|
+
|
170
|
+
return ~sum;
|
171
|
+
}
|
172
|
+
|
173
|
+
|
174
|
+
static VALUE
|
175
|
+
ipp_sum_update(self)
|
176
|
+
VALUE self;
|
177
|
+
{
|
178
|
+
struct packet_object *pkt;
|
179
|
+
struct ip *ip;
|
180
|
+
|
181
|
+
GetPacket(self, pkt);
|
182
|
+
CheckTruncateIp(pkt, 20);
|
183
|
+
ip = IP_HDR(pkt);
|
184
|
+
|
185
|
+
ip->ip_sum = 0;
|
186
|
+
ip->ip_sum = in_cksum((unsigned char *)ip, ip->ip_hl*4);
|
187
|
+
return INT2FIX(ntohs(ip->ip_sum));
|
188
|
+
}
|
189
|
+
|
190
|
+
|
191
|
+
static VALUE
|
192
|
+
ipp_data(self)
|
193
|
+
VALUE self;
|
194
|
+
{
|
195
|
+
struct packet_object *pkt;
|
196
|
+
struct ip *ip;
|
197
|
+
int len, hlen;
|
198
|
+
|
199
|
+
DEBUG_PRINT("ipp_data");
|
200
|
+
GetPacket(self, pkt);
|
201
|
+
CheckTruncateIp(pkt, 20);
|
202
|
+
ip = IP_HDR(pkt);
|
203
|
+
|
204
|
+
hlen = ip->ip_hl * 4;
|
205
|
+
len = pkt->hdr.pkthdr.caplen - pkt->hdr.layer3_off - hlen;
|
206
|
+
return rb_str_new((u_char *)ip + hlen, len);
|
207
|
+
}
|
208
|
+
|
209
|
+
/*
|
210
|
+
* IPAddress
|
211
|
+
*/
|
212
|
+
|
213
|
+
/* IPv4 adress (32bit) is stored by immediate value */
|
214
|
+
#if SIZEOF_VOIDP < 4
|
215
|
+
# error IPAddress assumes sizeof(void *) >= 4
|
216
|
+
#endif
|
217
|
+
|
218
|
+
#define GetIPAddress(obj, addr) {\
|
219
|
+
Check_Type(obj, T_DATA);\
|
220
|
+
addr = (struct in_addr *)&(DATA_PTR(obj));\
|
221
|
+
}
|
222
|
+
|
223
|
+
VALUE
|
224
|
+
new_ipaddr(addr)
|
225
|
+
struct in_addr *addr;
|
226
|
+
{
|
227
|
+
VALUE self;
|
228
|
+
|
229
|
+
self = Data_Wrap_Struct(cIPAddress, 0, 0, (void *)addr->s_addr);
|
230
|
+
return self;
|
231
|
+
}
|
232
|
+
|
233
|
+
|
234
|
+
|
235
|
+
#ifndef INADDR_NONE
|
236
|
+
# define INADDR_NONE (0xffffffff)
|
237
|
+
#endif
|
238
|
+
static VALUE
|
239
|
+
ipaddr_s_new(self, val)
|
240
|
+
VALUE self, val;
|
241
|
+
{
|
242
|
+
struct in_addr addr;
|
243
|
+
struct hostent *hent;
|
244
|
+
char *hname;
|
245
|
+
|
246
|
+
switch(TYPE(val)) {
|
247
|
+
case T_STRING:
|
248
|
+
hname = RSTRING_PTR(val);
|
249
|
+
hent = gethostbyname(hname);
|
250
|
+
if (hent == NULL) {
|
251
|
+
extern int h_errno;
|
252
|
+
switch (h_errno) {
|
253
|
+
case HOST_NOT_FOUND:
|
254
|
+
rb_raise(ePcapError, "host not found: %s", hname);
|
255
|
+
break;
|
256
|
+
default:
|
257
|
+
#ifdef HAVE_HSTRERROR
|
258
|
+
rb_raise(ePcapError, (char *)hstrerror(h_errno));
|
259
|
+
#else
|
260
|
+
rb_raise(ePcapError, "host not found: %s", hname);
|
261
|
+
#endif
|
262
|
+
}
|
263
|
+
}
|
264
|
+
addr = *(struct in_addr *)hent->h_addr;
|
265
|
+
break;
|
266
|
+
case T_FIXNUM:
|
267
|
+
case T_BIGNUM:
|
268
|
+
addr.s_addr = htonl(NUM2ULONG(val));
|
269
|
+
break;
|
270
|
+
default:
|
271
|
+
rb_raise(rb_eTypeError, "String or Integer required");
|
272
|
+
}
|
273
|
+
return new_ipaddr(&addr);
|
274
|
+
}
|
275
|
+
|
276
|
+
static VALUE
|
277
|
+
ipaddr_to_i(self)
|
278
|
+
VALUE self;
|
279
|
+
{
|
280
|
+
struct in_addr *addr;
|
281
|
+
|
282
|
+
GetIPAddress(self, addr);
|
283
|
+
return UINT32_2_NUM(ntohl(addr->s_addr));
|
284
|
+
}
|
285
|
+
|
286
|
+
static VALUE
|
287
|
+
ipaddr_num_s(self)
|
288
|
+
VALUE self;
|
289
|
+
{
|
290
|
+
struct in_addr *addr;
|
291
|
+
|
292
|
+
GetIPAddress(self, addr);
|
293
|
+
return rb_str_new2(inet_ntoa(*addr));
|
294
|
+
}
|
295
|
+
|
296
|
+
static VALUE
|
297
|
+
ipaddr_hostname(self)
|
298
|
+
VALUE self;
|
299
|
+
{
|
300
|
+
struct in_addr *addr;
|
301
|
+
struct hostent *host;
|
302
|
+
|
303
|
+
GetIPAddress(self, addr);
|
304
|
+
host = gethostbyaddr((char *)&addr->s_addr, sizeof addr->s_addr, AF_INET);
|
305
|
+
if (host == NULL)
|
306
|
+
return ipaddr_num_s(self);
|
307
|
+
return rb_str_new2(host->h_name);
|
308
|
+
}
|
309
|
+
|
310
|
+
static VALUE
|
311
|
+
ipaddr_to_s(self)
|
312
|
+
VALUE self;
|
313
|
+
{
|
314
|
+
if (RTEST(rbpcap_convert))
|
315
|
+
return ipaddr_hostname(self);
|
316
|
+
else
|
317
|
+
return ipaddr_num_s(self);
|
318
|
+
}
|
319
|
+
|
320
|
+
static VALUE
|
321
|
+
ipaddr_equal(self, other)
|
322
|
+
VALUE self, other;
|
323
|
+
{
|
324
|
+
struct in_addr *addr1;
|
325
|
+
struct in_addr *addr2;
|
326
|
+
|
327
|
+
GetIPAddress(self, addr1);
|
328
|
+
if (rb_class_of(other) == cIPAddress) {
|
329
|
+
GetIPAddress(other, addr2);
|
330
|
+
if (addr1->s_addr == addr2->s_addr)
|
331
|
+
return Qtrue;
|
332
|
+
}
|
333
|
+
return Qfalse;
|
334
|
+
}
|
335
|
+
|
336
|
+
static VALUE
|
337
|
+
ipaddr_hash(self)
|
338
|
+
VALUE self;
|
339
|
+
{
|
340
|
+
struct in_addr *addr;
|
341
|
+
|
342
|
+
GetIPAddress(self, addr);
|
343
|
+
return INT2FIX(ntohl(addr->s_addr));
|
344
|
+
}
|
345
|
+
|
346
|
+
static VALUE
|
347
|
+
ipaddr_dump(self, limit)
|
348
|
+
VALUE self;
|
349
|
+
VALUE limit;
|
350
|
+
{
|
351
|
+
struct in_addr *addr;
|
352
|
+
|
353
|
+
GetIPAddress(self, addr);
|
354
|
+
return rb_str_new((char *)addr, sizeof addr);
|
355
|
+
}
|
356
|
+
|
357
|
+
static VALUE
|
358
|
+
ipaddr_s_load(klass, str)
|
359
|
+
VALUE klass;
|
360
|
+
VALUE str;
|
361
|
+
{
|
362
|
+
struct in_addr addr;
|
363
|
+
int i;
|
364
|
+
|
365
|
+
if (RSTRING_LEN(str) != sizeof addr) {
|
366
|
+
rb_raise(rb_eArgError, "dump format error (IPAddress)");
|
367
|
+
}
|
368
|
+
for (i = 0; i < sizeof addr; i++) {
|
369
|
+
((char *)&addr)[i] = RSTRING_PTR(str)[i];
|
370
|
+
}
|
371
|
+
return new_ipaddr(&addr);
|
372
|
+
}
|
373
|
+
|
374
|
+
void
|
375
|
+
Init_ip_packet(void)
|
376
|
+
{
|
377
|
+
DEBUG_PRINT("Init_ip_packet");
|
378
|
+
|
379
|
+
cIPPacket = rb_define_class_under(mPcap, "IPPacket", cPacket);
|
380
|
+
|
381
|
+
rb_define_method(cIPPacket, "ip_ver", ipp_ver, 0);
|
382
|
+
rb_define_method(cIPPacket, "ip_hlen", ipp_hlen, 0);
|
383
|
+
rb_define_method(cIPPacket, "ip_tos", ipp_tos, 0);
|
384
|
+
rb_define_method(cIPPacket, "ip_len", ipp_len, 0);
|
385
|
+
rb_define_method(cIPPacket, "ip_id", ipp_id, 0);
|
386
|
+
rb_define_method(cIPPacket, "ip_flags", ipp_flags, 0);
|
387
|
+
rb_define_method(cIPPacket, "ip_df?", ipp_df, 0);
|
388
|
+
rb_define_method(cIPPacket, "ip_mf?", ipp_mf, 0);
|
389
|
+
rb_define_method(cIPPacket, "ip_off", ipp_off, 0);
|
390
|
+
rb_define_method(cIPPacket, "ip_ttl", ipp_ttl, 0);
|
391
|
+
rb_define_method(cIPPacket, "ip_proto", ipp_proto, 0);
|
392
|
+
rb_define_method(cIPPacket, "ip_sum", ipp_sum, 0);
|
393
|
+
rb_define_method(cIPPacket, "ip_sumok?", ipp_sumok, 0);
|
394
|
+
rb_define_method(cIPPacket, "ip_src", ipp_src, 0);
|
395
|
+
rb_define_method(cIPPacket, "src", ipp_src, 0);
|
396
|
+
rb_define_method(cIPPacket, "ip_src=", ipp_set_src, 1);
|
397
|
+
rb_define_method(cIPPacket, "src=", ipp_set_src, 1);
|
398
|
+
rb_define_method(cIPPacket, "ip_dst", ipp_dst, 0);
|
399
|
+
rb_define_method(cIPPacket, "dst", ipp_dst, 0);
|
400
|
+
rb_define_method(cIPPacket, "ip_dst=", ipp_set_dst, 1);
|
401
|
+
rb_define_method(cIPPacket, "dst=", ipp_set_dst, 1);
|
402
|
+
rb_define_method(cIPPacket, "ip_data", ipp_data, 0);
|
403
|
+
rb_define_method(cIPPacket, "ip_sum_update!", ipp_sum_update, 0);
|
404
|
+
|
405
|
+
cIPAddress = rb_define_class_under(mPcap, "IPAddress", rb_cObject);
|
406
|
+
rb_define_singleton_method(cIPAddress, "new", ipaddr_s_new, 1);
|
407
|
+
rb_define_method(cIPAddress, "to_i", ipaddr_to_i, 0);
|
408
|
+
rb_define_method(cIPAddress, "to_s", ipaddr_to_s, 0);
|
409
|
+
rb_define_method(cIPAddress, "num_s", ipaddr_num_s, 0);
|
410
|
+
rb_define_method(cIPAddress, "to_num_s", ipaddr_num_s, 0); /* BWC */
|
411
|
+
rb_define_method(cIPAddress, "hostname", ipaddr_hostname, 0);
|
412
|
+
rb_define_method(cIPAddress, "sym_s", ipaddr_hostname, 0);
|
413
|
+
rb_define_method(cIPAddress, "==", ipaddr_equal, 1);
|
414
|
+
rb_define_method(cIPAddress, "===", ipaddr_equal, 1);
|
415
|
+
rb_define_method(cIPAddress, "eql?", ipaddr_equal, 1);
|
416
|
+
rb_define_method(cIPAddress, "hash", ipaddr_hash, 0);
|
417
|
+
|
418
|
+
rb_define_method(cIPAddress, "_dump", ipaddr_dump, 1);
|
419
|
+
rb_define_singleton_method(cIPAddress, "_load", ipaddr_s_load, 1);
|
420
|
+
|
421
|
+
Init_tcp_packet();
|
422
|
+
Init_udp_packet();
|
423
|
+
Init_icmp_packet();
|
424
|
+
}
|
data/ext/packet.c
ADDED
@@ -0,0 +1,328 @@
|
|
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_PTR(str);
|
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_LEN(str) - 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_set_time_i(self, val)
|
244
|
+
VALUE self;
|
245
|
+
VALUE val;
|
246
|
+
{
|
247
|
+
struct packet_object *pkt;
|
248
|
+
unsigned int time_i;
|
249
|
+
|
250
|
+
DEBUG_PRINT("packet_set_time_i");
|
251
|
+
GetPacket(self, pkt);
|
252
|
+
Check_Type(val, T_FIXNUM);
|
253
|
+
time_i = NUM2UINT(val);
|
254
|
+
|
255
|
+
pkt->hdr.pkthdr.ts.tv_sec = time_i;
|
256
|
+
return val;
|
257
|
+
}
|
258
|
+
|
259
|
+
static VALUE
|
260
|
+
packet_match(self, expr)
|
261
|
+
VALUE self;
|
262
|
+
VALUE expr;
|
263
|
+
{
|
264
|
+
if (IsKindOf(expr, cFilter)) {
|
265
|
+
return filter_match(expr, self);
|
266
|
+
}
|
267
|
+
rb_raise(rb_eArgError, "Not Filter");
|
268
|
+
}
|
269
|
+
|
270
|
+
#define PACKET_METHOD(func, val) \
|
271
|
+
static VALUE\
|
272
|
+
(func)(self)\
|
273
|
+
VALUE self;\
|
274
|
+
{\
|
275
|
+
struct packet_object *pkt;\
|
276
|
+
\
|
277
|
+
DEBUG_PRINT(#func);\
|
278
|
+
GetPacket(self, pkt);\
|
279
|
+
return (val);\
|
280
|
+
}
|
281
|
+
|
282
|
+
PACKET_METHOD(packet_get_udata, pkt->udata);
|
283
|
+
PACKET_METHOD(packet_datalink, INT2FIX(pkt->hdr.dl_type));
|
284
|
+
PACKET_METHOD(packet_ip, rb_obj_is_kind_of(self, cIPPacket));
|
285
|
+
PACKET_METHOD(packet_tcp, rb_obj_is_kind_of(self, cTCPPacket));
|
286
|
+
PACKET_METHOD(packet_udp, rb_obj_is_kind_of(self, cUDPPacket));
|
287
|
+
PACKET_METHOD(packet_length, UINT32_2_NUM(pkt->hdr.pkthdr.len));
|
288
|
+
PACKET_METHOD(packet_caplen, UINT32_2_NUM(pkt->hdr.pkthdr.caplen));
|
289
|
+
PACKET_METHOD(packet_time, rb_time_new(pkt->hdr.pkthdr.ts.tv_sec,
|
290
|
+
pkt->hdr.pkthdr.ts.tv_usec));
|
291
|
+
PACKET_METHOD(packet_time_i, rb_int2inum(pkt->hdr.pkthdr.ts.tv_sec));
|
292
|
+
PACKET_METHOD(packet_raw_data, rb_str_new(pkt->data, pkt->hdr.pkthdr.caplen));
|
293
|
+
|
294
|
+
void
|
295
|
+
Init_packet(void)
|
296
|
+
{
|
297
|
+
DEBUG_PRINT("Init_packet");
|
298
|
+
|
299
|
+
/* define class Packet */
|
300
|
+
cPacket = rb_define_class_under(mPcap, "Packet", rb_cObject);
|
301
|
+
|
302
|
+
rb_define_singleton_method(cPacket, "_load", packet_load, 1);
|
303
|
+
rb_define_method(cPacket, "_dump", packet_dump, 1);
|
304
|
+
/* marshal backward compatibility */
|
305
|
+
rb_define_singleton_method(cPacket, "_load_from", packet_load, 1);
|
306
|
+
rb_define_method(cPacket, "_dump_to", packet_dump, 1);
|
307
|
+
|
308
|
+
rb_define_method(cPacket, "udata", packet_get_udata, 0);
|
309
|
+
rb_define_method(cPacket, "udata=", packet_set_udata, 1);
|
310
|
+
rb_define_method(cPacket, "datalink", packet_datalink, 0);
|
311
|
+
rb_define_method(cPacket, "ip?", packet_ip, 0);
|
312
|
+
rb_define_method(cPacket, "tcp?", packet_tcp, 0);
|
313
|
+
rb_define_method(cPacket, "udp?", packet_udp, 0);
|
314
|
+
rb_define_method(cPacket, "length", packet_length, 0);
|
315
|
+
rb_define_method(cPacket, "size", packet_length, 0);
|
316
|
+
rb_define_method(cPacket, "caplen", packet_caplen, 0);
|
317
|
+
rb_define_method(cPacket, "time", packet_time, 0);
|
318
|
+
rb_define_method(cPacket, "time_i", packet_time_i, 0);
|
319
|
+
rb_define_method(cPacket, "time_i=", packet_set_time_i, 1);
|
320
|
+
rb_define_method(cPacket, "raw_data", packet_raw_data, 0);
|
321
|
+
rb_define_method(cPacket, "=~", packet_match, 1);
|
322
|
+
|
323
|
+
/* mMarshal in ruby/marshal.c is static. Why? */
|
324
|
+
mMarshal = rb_eval_string("Marshal");
|
325
|
+
id_load = rb_intern("load");
|
326
|
+
id_dump = rb_intern("dump");
|
327
|
+
Init_ip_packet();
|
328
|
+
}
|