capp 1.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 +7 -0
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/.autotest +12 -0
- data/.gemtest +0 -0
- data/.hoerc +2 -0
- data/History.rdoc +4 -0
- data/Manifest.txt +24 -0
- data/README.rdoc +84 -0
- data/Rakefile +57 -0
- data/ext/capp/capp.c +1382 -0
- data/ext/capp/extconf.rb +34 -0
- data/ext/capp/structs.h +86 -0
- data/lib/capp.rb +168 -0
- data/lib/capp/packet.rb +402 -0
- data/lib/capp/test_case.rb +61 -0
- data/test/802.1X.pcap +0 -0
- data/test/arp.pcap +0 -0
- data/test/icmp4.pcap +0 -0
- data/test/icmp6.pcap +0 -0
- data/test/tcp4.pcap +0 -0
- data/test/tcp6.pcap +0 -0
- data/test/test_capp.rb +273 -0
- data/test/test_capp_packet.rb +160 -0
- data/test/test_capp_packet_tcp_header.rb +103 -0
- data/test/test_capp_root.rb +194 -0
- data/test/udp4.pcap +0 -0
- data/test/udp6.pcap +0 -0
- metadata +161 -0
- metadata.gz.sig +0 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 5277c07b5623a004709e40ee59b46fd0f5a21617
|
4
|
+
data.tar.gz: 63df47ceb85aaa2d77ab4a100f8d7d1a241277fe
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d0bb5ba29e2ff727b16e2c5eaf2c49f3aa74bcb43e722df14455271a76f15938fbe5ce54d218316b81f250ddc3272fcd2ab1e233e4d0d298bf3a964c3611ff75
|
7
|
+
data.tar.gz: 2caceca5822d67d340ec641e17ca153f357dbc8794cea4977dcf01db4169b3b0a7b26aa8d744d8ccaffafc27845a83460ba018b3a8a148721622519ceb3aef46
|
checksums.yaml.gz.sig
ADDED
Binary file
|
data.tar.gz.sig
ADDED
Binary file
|
data/.autotest
ADDED
data/.gemtest
ADDED
File without changes
|
data/.hoerc
ADDED
data/History.rdoc
ADDED
data/Manifest.txt
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
.autotest
|
2
|
+
.hoerc
|
3
|
+
History.rdoc
|
4
|
+
Manifest.txt
|
5
|
+
README.rdoc
|
6
|
+
Rakefile
|
7
|
+
ext/capp/capp.c
|
8
|
+
ext/capp/extconf.rb
|
9
|
+
ext/capp/structs.h
|
10
|
+
lib/capp.rb
|
11
|
+
lib/capp/packet.rb
|
12
|
+
lib/capp/test_case.rb
|
13
|
+
test/802.1X.pcap
|
14
|
+
test/arp.pcap
|
15
|
+
test/icmp4.pcap
|
16
|
+
test/icmp6.pcap
|
17
|
+
test/tcp4.pcap
|
18
|
+
test/tcp6.pcap
|
19
|
+
test/test_capp.rb
|
20
|
+
test/test_capp_packet.rb
|
21
|
+
test/test_capp_packet_tcp_header.rb
|
22
|
+
test/test_capp_root.rb
|
23
|
+
test/udp4.pcap
|
24
|
+
test/udp6.pcap
|
data/README.rdoc
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
= capp
|
2
|
+
|
3
|
+
home :: https://github.com/drbrain/capp
|
4
|
+
rdoc :: http://docs.seattlerb.org/capp
|
5
|
+
bugs :: https://github.com/drbrain/capp/issues
|
6
|
+
|
7
|
+
== Description
|
8
|
+
|
9
|
+
Capp is a packet capture library that wraps libpcap. Capp provides a simple
|
10
|
+
API for capturing packets and automatically unpacks common packets (including
|
11
|
+
Ethernet, IP, TCP, UDP and ICMP). Capp also cooperates with other threads
|
12
|
+
better than other pcap wrapper libraries for ruby.
|
13
|
+
|
14
|
+
== Examples
|
15
|
+
|
16
|
+
Basic single-thread packet capturing:
|
17
|
+
|
18
|
+
require 'capp'
|
19
|
+
|
20
|
+
Capp.live.loop do |packet|
|
21
|
+
# ...
|
22
|
+
end
|
23
|
+
|
24
|
+
Basic multi-thread packet capturing:
|
25
|
+
|
26
|
+
require 'capp'
|
27
|
+
require 'thread'
|
28
|
+
|
29
|
+
q = Queue.new
|
30
|
+
|
31
|
+
Thread.new do
|
32
|
+
while packet = q.deq do
|
33
|
+
# ...
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
capp = Capp.live.loop do |packet|
|
38
|
+
q.enq packet
|
39
|
+
end
|
40
|
+
|
41
|
+
== Requirements
|
42
|
+
|
43
|
+
* libpcap, tested with 1.1.1 and 1.3.0
|
44
|
+
|
45
|
+
== Install
|
46
|
+
|
47
|
+
sudo gem install capp
|
48
|
+
|
49
|
+
== Developers
|
50
|
+
|
51
|
+
After checking out the source, run:
|
52
|
+
|
53
|
+
$ rake newb
|
54
|
+
$ rake newb
|
55
|
+
|
56
|
+
This task will install any missing dependencies, run the tests/specs,
|
57
|
+
and generate the RDoc. You need to run it twice as the first run installs the
|
58
|
+
dependencies needed to compile the C extension.
|
59
|
+
|
60
|
+
== License
|
61
|
+
|
62
|
+
(The MIT License)
|
63
|
+
|
64
|
+
Copyright (c) Eric Hodel
|
65
|
+
|
66
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
67
|
+
a copy of this software and associated documentation files (the
|
68
|
+
'Software'), to deal in the Software without restriction, including
|
69
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
70
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
71
|
+
permit persons to whom the Software is furnished to do so, subject to
|
72
|
+
the following conditions:
|
73
|
+
|
74
|
+
The above copyright notice and this permission notice shall be
|
75
|
+
included in all copies or substantial portions of the Software.
|
76
|
+
|
77
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
78
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
79
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
80
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
81
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
82
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
83
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
84
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'hoe'
|
5
|
+
begin
|
6
|
+
require 'rake/extensiontask'
|
7
|
+
rescue LoadError => e
|
8
|
+
warn "\nmissing #{e.path} (for rake-compiler)" if e.respond_to? :path
|
9
|
+
warn "run: rake newb\n\n"
|
10
|
+
end
|
11
|
+
|
12
|
+
Hoe.plugin :git
|
13
|
+
Hoe.plugin :minitest
|
14
|
+
Hoe.plugin :travis
|
15
|
+
|
16
|
+
HOE = Hoe.spec 'capp' do
|
17
|
+
developer 'Eric Hodel', 'drbrain@segment7.net'
|
18
|
+
|
19
|
+
rdoc_locations << 'docs.seattlerb.org:/data/www/docs.seattlerb.org/capp/'
|
20
|
+
|
21
|
+
self.extra_rdoc_files << 'ext/capp/capp.c'
|
22
|
+
self.spec_extras[:extensions] = 'ext/capp/extconf.rb'
|
23
|
+
|
24
|
+
self.readme_file = 'README.rdoc'
|
25
|
+
|
26
|
+
self.extra_dev_deps << ['rake-compiler', '~> 0.8']
|
27
|
+
end
|
28
|
+
|
29
|
+
if Rake.const_defined? :ExtensionTask then
|
30
|
+
Rake::ExtensionTask.new 'capp', HOE.spec do |ext|
|
31
|
+
ext.lib_dir = 'lib/capp'
|
32
|
+
end
|
33
|
+
|
34
|
+
task test: :compile
|
35
|
+
end
|
36
|
+
|
37
|
+
namespace :travis do
|
38
|
+
task :install_libpcap do
|
39
|
+
sh 'sudo apt-get install libpcap-dev'
|
40
|
+
end
|
41
|
+
|
42
|
+
Rake::TestTask.new root_test: %w[compile] do |t|
|
43
|
+
t.libs << 'lib'
|
44
|
+
t.test_files = FileList['test/test_capp_root.rb']
|
45
|
+
end
|
46
|
+
|
47
|
+
task :run_root_test do
|
48
|
+
ruby = Gem.ruby
|
49
|
+
sh 'sudo', '-E', ruby, '-S', 'rake', '-t', 'travis:root_test'
|
50
|
+
end
|
51
|
+
|
52
|
+
task before: %w[install_libpcap]
|
53
|
+
end
|
54
|
+
|
55
|
+
task travis: %w[travis:run_root_test]
|
56
|
+
|
57
|
+
# vim: syntax=ruby
|
data/ext/capp/capp.c
ADDED
@@ -0,0 +1,1382 @@
|
|
1
|
+
#include <pcap/pcap.h>
|
2
|
+
|
3
|
+
#include <unistd.h>
|
4
|
+
#include <sys/socket.h>
|
5
|
+
#include <net/ethernet.h>
|
6
|
+
#include <net/if_arp.h>
|
7
|
+
#include <netinet/in.h>
|
8
|
+
#include <netinet/ip.h>
|
9
|
+
#include <netinet/ip6.h>
|
10
|
+
#include <netinet/ip_icmp.h>
|
11
|
+
#include <arpa/inet.h>
|
12
|
+
|
13
|
+
#include <ruby.h>
|
14
|
+
#include <ruby/io.h>
|
15
|
+
|
16
|
+
#include "extconf.h"
|
17
|
+
#include "structs.h"
|
18
|
+
|
19
|
+
#ifdef HAVE_NET_IF_DL_H
|
20
|
+
#include <net/if_dl.h>
|
21
|
+
#endif
|
22
|
+
|
23
|
+
/* Ethernet functions in the internet headers? WTF Linux? */
|
24
|
+
#ifdef HAVE_NETINET_ETHER_H
|
25
|
+
#include <netinet/ether.h>
|
26
|
+
#endif
|
27
|
+
|
28
|
+
#ifdef HAVE_RUBY_THREAD_H
|
29
|
+
#include <ruby/thread.h>
|
30
|
+
#else
|
31
|
+
void *rb_thread_call_with_gvl(void *(*func)(void *), void *data1);
|
32
|
+
|
33
|
+
void *rb_thread_call_without_gvl(void *(*func)(void *), void *data1,
|
34
|
+
rb_unblock_function_t *ubf, void *data2);
|
35
|
+
#endif
|
36
|
+
|
37
|
+
#ifndef ETHERTYPE_PAE
|
38
|
+
#define ETHERTYPE_PAE 0x888e
|
39
|
+
#endif
|
40
|
+
|
41
|
+
#ifndef ETHERTYPE_RSN_PREAUTH
|
42
|
+
#define ETHERTYPE_RSN_PREAUTH 0x88c7
|
43
|
+
#endif
|
44
|
+
|
45
|
+
#ifndef ARPHRD_FRELAY
|
46
|
+
#define ARPHRD_FRELAY 15
|
47
|
+
#endif
|
48
|
+
|
49
|
+
#ifndef ARPHRD_IEEE1394_EUI64
|
50
|
+
#define ARPHRD_IEEE1394_EUI64 27
|
51
|
+
#endif
|
52
|
+
|
53
|
+
#ifndef ARPOP_REVREQUEST
|
54
|
+
#define ARPOP_REVREQUEST 3
|
55
|
+
#endif
|
56
|
+
|
57
|
+
#ifndef ARPOP_REVREPLY
|
58
|
+
#define ARPOP_REVREPLY 4
|
59
|
+
#endif
|
60
|
+
|
61
|
+
#ifndef ARPOP_INVREQUEST
|
62
|
+
#define ARPOP_INVREQUEST 8
|
63
|
+
#endif
|
64
|
+
|
65
|
+
#ifndef ARPOP_INVREPLY
|
66
|
+
#define ARPOP_INVREPLY 9
|
67
|
+
#endif
|
68
|
+
|
69
|
+
#ifndef PCAP_NETMASK_UNKNOWN
|
70
|
+
#define PCAP_NETMASK_UNKNOWN 0xFFFFFFFF
|
71
|
+
#endif
|
72
|
+
|
73
|
+
#ifndef NUM2USHORT
|
74
|
+
#define NUM2USHORT (unsigned short)NUM2UINT
|
75
|
+
#endif
|
76
|
+
|
77
|
+
struct capp_loop_args {
|
78
|
+
pcap_t *handle;
|
79
|
+
int datalink;
|
80
|
+
const struct pcap_pkthdr *header;
|
81
|
+
const u_char *data;
|
82
|
+
};
|
83
|
+
|
84
|
+
#define GetCapp(obj, capp) Data_Get_Struct(obj, pcap_t, capp)
|
85
|
+
|
86
|
+
static ID id_arp;
|
87
|
+
static ID id_drop;
|
88
|
+
static ID id_ethernet;
|
89
|
+
static ID id_icmp;
|
90
|
+
static ID id_ifdrop;
|
91
|
+
static ID id_ipv4;
|
92
|
+
static ID id_ipv6;
|
93
|
+
static ID id_iv_datalink;
|
94
|
+
static ID id_iv_device;
|
95
|
+
static ID id_recv;
|
96
|
+
static ID id_type;
|
97
|
+
static ID id_tcp;
|
98
|
+
static ID id_udp;
|
99
|
+
static ID id_unknown_layer3;
|
100
|
+
static ID id_unpack_sockaddr_in;
|
101
|
+
|
102
|
+
static VALUE cCapp;
|
103
|
+
static VALUE cCappAddress;
|
104
|
+
static VALUE cCappDevice;
|
105
|
+
static VALUE cCappPacket;
|
106
|
+
static VALUE cCappPacketARPHeader;
|
107
|
+
static VALUE cCappPacketEthernetHeader;
|
108
|
+
static VALUE cCappPacketICMPHeader;
|
109
|
+
static VALUE cCappPacketIPv4Header;
|
110
|
+
static VALUE cCappPacketIPv6Header;
|
111
|
+
static VALUE cCappPacketTCPHeader;
|
112
|
+
static VALUE cCappPacketUDPHeader;
|
113
|
+
static VALUE cCappPacketUnknownLayer3Header;
|
114
|
+
static VALUE cSocket;
|
115
|
+
|
116
|
+
static VALUE eCappError;
|
117
|
+
|
118
|
+
/*
|
119
|
+
* call-seq:
|
120
|
+
* Capp.default_device_name -> string
|
121
|
+
*
|
122
|
+
* Returns the default device name
|
123
|
+
*/
|
124
|
+
static VALUE
|
125
|
+
capp_s_default_device_name(VALUE klass)
|
126
|
+
{
|
127
|
+
char errbuf[PCAP_ERRBUF_SIZE];
|
128
|
+
char *device;
|
129
|
+
|
130
|
+
*errbuf = '\0';
|
131
|
+
|
132
|
+
device = pcap_lookupdev(errbuf);
|
133
|
+
|
134
|
+
if (device == NULL)
|
135
|
+
rb_raise(eCappError, "pcap_create: %s", errbuf);
|
136
|
+
|
137
|
+
if (*errbuf)
|
138
|
+
rb_warn("%s", errbuf);
|
139
|
+
|
140
|
+
return rb_usascii_str_new_cstr(device);
|
141
|
+
}
|
142
|
+
|
143
|
+
static VALUE
|
144
|
+
capp_sockaddr_to_address(struct sockaddr *addr)
|
145
|
+
{
|
146
|
+
VALUE address, sockaddr_string;
|
147
|
+
#ifdef HAVE_NET_IF_DL_H
|
148
|
+
struct ether_addr *ether;
|
149
|
+
struct sockaddr_dl *dl;
|
150
|
+
#endif
|
151
|
+
|
152
|
+
if (NULL == addr)
|
153
|
+
return Qnil;
|
154
|
+
|
155
|
+
switch (addr->sa_family) {
|
156
|
+
case AF_INET:
|
157
|
+
sockaddr_string = rb_str_new((char *)addr, sizeof(struct sockaddr_in));
|
158
|
+
address =
|
159
|
+
rb_funcall(cSocket, id_unpack_sockaddr_in, 1, sockaddr_string);
|
160
|
+
return rb_ary_entry(address, 1);
|
161
|
+
case AF_INET6:
|
162
|
+
sockaddr_string = rb_str_new((char *)addr, sizeof(struct sockaddr_in6));
|
163
|
+
address =
|
164
|
+
rb_funcall(cSocket, id_unpack_sockaddr_in, 1, sockaddr_string);
|
165
|
+
return rb_ary_entry(address, 1);
|
166
|
+
#ifdef HAVE_NET_IF_DL_H
|
167
|
+
case AF_LINK:
|
168
|
+
dl = (struct sockaddr_dl *)addr;
|
169
|
+
ether = (struct ether_addr *)LLADDR(dl);
|
170
|
+
|
171
|
+
return rb_usascii_str_new_cstr(ether_ntoa(ether));
|
172
|
+
#endif
|
173
|
+
default:
|
174
|
+
return rb_usascii_str_new_cstr("(unsupported address family)");
|
175
|
+
}
|
176
|
+
}
|
177
|
+
|
178
|
+
static VALUE
|
179
|
+
capp_addr_to_addresses(pcap_addr_t *addrs)
|
180
|
+
{
|
181
|
+
VALUE address, addresses, addr_args[4];
|
182
|
+
pcap_addr_t *addr;
|
183
|
+
|
184
|
+
addresses = rb_ary_new();
|
185
|
+
|
186
|
+
if (addrs) {
|
187
|
+
for (addr = addrs; addr; addr = addr->next) {
|
188
|
+
addr_args[0] = capp_sockaddr_to_address(addr->addr);
|
189
|
+
addr_args[1] = capp_sockaddr_to_address(addr->netmask);
|
190
|
+
addr_args[2] = capp_sockaddr_to_address(addr->broadaddr);
|
191
|
+
addr_args[3] = capp_sockaddr_to_address(addr->dstaddr);
|
192
|
+
|
193
|
+
address = rb_class_new_instance(4, addr_args, cCappAddress);
|
194
|
+
|
195
|
+
rb_ary_push(addresses, address);
|
196
|
+
}
|
197
|
+
}
|
198
|
+
|
199
|
+
return addresses;
|
200
|
+
}
|
201
|
+
|
202
|
+
/*
|
203
|
+
* call-seq:
|
204
|
+
* Capp.devices -> array
|
205
|
+
*
|
206
|
+
* Returns an Array containing the devices and their addresses:
|
207
|
+
*
|
208
|
+
* [#<struct Capp::Address
|
209
|
+
* address="lo0",
|
210
|
+
* netmask=nil,
|
211
|
+
* broadcast=
|
212
|
+
* [#<struct Capp::Address
|
213
|
+
* address="0:0:0:0:0:0",
|
214
|
+
* netmask=nil,
|
215
|
+
* broadcast=nil,
|
216
|
+
* destination=nil>,
|
217
|
+
* #<struct Capp::Address
|
218
|
+
* address="fe80::1%lo0",
|
219
|
+
* netmask="ffff:ffff:ffff:ffff::",
|
220
|
+
* broadcast=nil,
|
221
|
+
* destination=nil>,
|
222
|
+
* #<struct Capp::Address
|
223
|
+
* address="127.0.0.1",
|
224
|
+
* netmask="255.0.0.0",
|
225
|
+
* broadcast=nil,
|
226
|
+
* destination=nil>,
|
227
|
+
* #<struct Capp::Address
|
228
|
+
* address="::1",
|
229
|
+
* netmask="ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
|
230
|
+
* broadcast=nil,
|
231
|
+
* destination=nil>],
|
232
|
+
* destination=1>,
|
233
|
+
* # [...]
|
234
|
+
* ]
|
235
|
+
*/
|
236
|
+
static VALUE
|
237
|
+
capp_s_devices(VALUE klass)
|
238
|
+
{
|
239
|
+
VALUE device, devices, dev_args[4];
|
240
|
+
char errbuf[PCAP_ERRBUF_SIZE];
|
241
|
+
pcap_if_t *iface, *ifaces;
|
242
|
+
|
243
|
+
*errbuf = '\0';
|
244
|
+
|
245
|
+
if (pcap_findalldevs(&ifaces, errbuf))
|
246
|
+
rb_raise(eCappError, "pcap_create: %s", errbuf);
|
247
|
+
|
248
|
+
if (*errbuf)
|
249
|
+
rb_warn("%s", errbuf);
|
250
|
+
|
251
|
+
devices = rb_ary_new();
|
252
|
+
|
253
|
+
for (iface = ifaces; iface; iface = iface->next) {
|
254
|
+
dev_args[0] = rb_usascii_str_new_cstr(iface->name);
|
255
|
+
if (iface->description) {
|
256
|
+
dev_args[1] = rb_usascii_str_new_cstr(iface->description);
|
257
|
+
} else {
|
258
|
+
dev_args[1] = Qnil;
|
259
|
+
}
|
260
|
+
dev_args[2] = capp_addr_to_addresses(iface->addresses);
|
261
|
+
dev_args[3] = UINT2NUM(iface->flags);
|
262
|
+
|
263
|
+
device = rb_class_new_instance(4, dev_args, cCappDevice);
|
264
|
+
|
265
|
+
rb_ary_push(devices, device);
|
266
|
+
}
|
267
|
+
|
268
|
+
pcap_freealldevs(ifaces);
|
269
|
+
|
270
|
+
return devices;
|
271
|
+
}
|
272
|
+
|
273
|
+
/*
|
274
|
+
* call-seq:
|
275
|
+
* Capp.live -> capp
|
276
|
+
* Capp.live device -> capp
|
277
|
+
* Capp.live device, capture_length, -> capp
|
278
|
+
* Capp.live device, capture_length, promiscuous -> capp
|
279
|
+
* Capp.live device, capture_length, promiscuous, timeout -> capp
|
280
|
+
*
|
281
|
+
* Creates a Capp instance that will capture packets from a network device.
|
282
|
+
*
|
283
|
+
* +device+ is the device to capture packets from. If the device is omitted
|
284
|
+
* the default device (::default_device_name) is used.
|
285
|
+
*
|
286
|
+
* +capture_length+ is the number of bytes to capture from each packet. If
|
287
|
+
* a length is omitted 65535 is used.
|
288
|
+
*
|
289
|
+
* +promiscuous+ places the device in promiscuous mode when true, allowing you
|
290
|
+
* to see packets not sent directly to or from the device. Promiscuous mode
|
291
|
+
* is enabled by default.
|
292
|
+
*
|
293
|
+
* The +timeout+ is the number of maximum number of milliseconds that will
|
294
|
+
* elapse between receiving a packet and yielding it to the block given to
|
295
|
+
* #loop. The default timeout is 10 milliseconds. See #timeout= for further
|
296
|
+
* discussion.
|
297
|
+
*
|
298
|
+
* After creating an instance use #loop to start capturing packets.
|
299
|
+
*/
|
300
|
+
static VALUE
|
301
|
+
capp_s_open_live(int argc, VALUE *argv, VALUE klass)
|
302
|
+
{
|
303
|
+
VALUE obj, device, snaplen, promiscuous, timeout;
|
304
|
+
int promisc = 0;
|
305
|
+
char errbuf[PCAP_ERRBUF_SIZE];
|
306
|
+
pcap_t *handle;
|
307
|
+
|
308
|
+
rb_scan_args(argc, argv, "04", &device, &snaplen, &promiscuous, &timeout);
|
309
|
+
|
310
|
+
if (!RTEST(device)) device = capp_s_default_device_name(klass);
|
311
|
+
if (!RTEST(snaplen)) snaplen = INT2NUM(65535);
|
312
|
+
if (!RTEST(promiscuous)) promiscuous = Qtrue;
|
313
|
+
if (!RTEST(timeout)) timeout = INT2NUM(10);
|
314
|
+
|
315
|
+
if (RTEST(promiscuous))
|
316
|
+
promisc = 1;
|
317
|
+
|
318
|
+
*errbuf = '\0';
|
319
|
+
|
320
|
+
handle = pcap_open_live(StringValueCStr(device), NUM2INT(snaplen),
|
321
|
+
promisc, NUM2INT(timeout), errbuf);
|
322
|
+
|
323
|
+
if (NULL == handle)
|
324
|
+
rb_raise(eCappError, "pcap_create: %s", errbuf);
|
325
|
+
|
326
|
+
if (*errbuf)
|
327
|
+
rb_warn("%s", errbuf);
|
328
|
+
|
329
|
+
obj = Data_Wrap_Struct(klass, NULL, pcap_close, handle);
|
330
|
+
|
331
|
+
rb_ivar_set(obj, id_iv_device, device);
|
332
|
+
|
333
|
+
return obj;
|
334
|
+
}
|
335
|
+
|
336
|
+
/*
|
337
|
+
* call-seq:
|
338
|
+
* Capp.offline filename -> capp
|
339
|
+
* Capp.offline io -> capp
|
340
|
+
*
|
341
|
+
* Creates an Capp that instance that captures packets from a pcap savefile.
|
342
|
+
* A savefile may be loaded from an open +file+:
|
343
|
+
*
|
344
|
+
* open 'savefile' do |io|
|
345
|
+
* capp = Capp.offline io
|
346
|
+
* # ...
|
347
|
+
* end
|
348
|
+
*
|
349
|
+
* Or a +filename+:
|
350
|
+
*
|
351
|
+
* capp = Capp.offline 'savefile'
|
352
|
+
*
|
353
|
+
* After creating an instance use #loop to start capturing packets.
|
354
|
+
*
|
355
|
+
* NOTE: When you give Capp.offline a Ruby IO you should avoid buffered
|
356
|
+
* reads or writes to the IO due to limitations of libpcap. (Using a pipe and
|
357
|
+
* reading from one end and writing to the other is fine, of course.)
|
358
|
+
*/
|
359
|
+
static VALUE
|
360
|
+
capp_s_open_offline(VALUE klass, VALUE file)
|
361
|
+
{
|
362
|
+
VALUE obj;
|
363
|
+
char errbuf[PCAP_ERRBUF_SIZE];
|
364
|
+
pcap_t *handle;
|
365
|
+
|
366
|
+
*errbuf = '\0';
|
367
|
+
|
368
|
+
if (TYPE(file) == T_FILE) {
|
369
|
+
FILE *c_file;
|
370
|
+
rb_io_t *fptr;
|
371
|
+
int fd;
|
372
|
+
|
373
|
+
GetOpenFile(file, fptr);
|
374
|
+
|
375
|
+
fd = dup(fptr->fd);
|
376
|
+
|
377
|
+
if (-1 == fd)
|
378
|
+
rb_sys_fail("dup");
|
379
|
+
|
380
|
+
c_file = fdopen(fd, "r");
|
381
|
+
|
382
|
+
if (NULL == c_file)
|
383
|
+
rb_sys_fail("fdopen");
|
384
|
+
|
385
|
+
handle = pcap_fopen_offline(c_file, errbuf);
|
386
|
+
} else {
|
387
|
+
handle = pcap_open_offline(StringValueCStr(file), errbuf);
|
388
|
+
}
|
389
|
+
|
390
|
+
if (NULL == handle) {
|
391
|
+
if (RFILE(file))
|
392
|
+
rb_raise(eCappError, "pcap_fopen_offline: %s", errbuf);
|
393
|
+
|
394
|
+
rb_raise(eCappError, "pcap_open_offline: %s", errbuf);
|
395
|
+
}
|
396
|
+
|
397
|
+
if (*errbuf)
|
398
|
+
rb_warn("%s", errbuf);
|
399
|
+
|
400
|
+
obj = Data_Wrap_Struct(klass, NULL, pcap_close, handle);
|
401
|
+
|
402
|
+
rb_ivar_set(obj, id_iv_device, Qnil);
|
403
|
+
|
404
|
+
return obj;
|
405
|
+
}
|
406
|
+
|
407
|
+
/*
|
408
|
+
* call-seq:
|
409
|
+
* Capp.pcap_lib_version -> libpcap version string
|
410
|
+
*
|
411
|
+
* Returns the libpcap version string:
|
412
|
+
*
|
413
|
+
* Capp.pcap_lib_version #=> "libpcap version 1.1.1"
|
414
|
+
*
|
415
|
+
*/
|
416
|
+
static VALUE
|
417
|
+
capp_s_pcap_lib_version(VALUE klass)
|
418
|
+
{
|
419
|
+
return rb_usascii_str_new_cstr(pcap_lib_version());
|
420
|
+
}
|
421
|
+
|
422
|
+
/*
|
423
|
+
* call-seq:
|
424
|
+
* capp.datalinks #=> ["datalink name", ...]
|
425
|
+
*
|
426
|
+
* Returns the supported datalinks for this capture instance:
|
427
|
+
*
|
428
|
+
* p Capp.live.datalinks
|
429
|
+
* #=> ["EN10MB", "PPI", "IEEE802_11_RADIO", "IEEE802_11",
|
430
|
+
* "IEEE802_11_RADIO_AVS", "RAW"]
|
431
|
+
*
|
432
|
+
* These can be used to change the datalink used to capture packets by using
|
433
|
+
* #datalink=
|
434
|
+
*/
|
435
|
+
static VALUE
|
436
|
+
capp_datalinks(VALUE self)
|
437
|
+
{
|
438
|
+
int *dlt_buf;
|
439
|
+
pcap_t *handle;
|
440
|
+
VALUE datalink_ary;
|
441
|
+
int i, datalink_count;
|
442
|
+
|
443
|
+
GetCapp(self, handle);
|
444
|
+
|
445
|
+
datalink_count = pcap_list_datalinks(handle, &dlt_buf);
|
446
|
+
|
447
|
+
if (datalink_count == -1)
|
448
|
+
rb_raise(eCappError, "%s", pcap_geterr(handle));
|
449
|
+
|
450
|
+
datalink_ary = rb_ary_new2(datalink_count);
|
451
|
+
|
452
|
+
for (i = 0; i < datalink_count; i++) {
|
453
|
+
const char *datalink_name_cstr = pcap_datalink_val_to_name(dlt_buf[i]);
|
454
|
+
VALUE datalink_name = rb_usascii_str_new_cstr(datalink_name_cstr);
|
455
|
+
|
456
|
+
rb_ary_push(datalink_ary, datalink_name);
|
457
|
+
}
|
458
|
+
|
459
|
+
pcap_free_datalinks(dlt_buf);
|
460
|
+
|
461
|
+
return datalink_ary;
|
462
|
+
}
|
463
|
+
|
464
|
+
/*
|
465
|
+
* call-seq:
|
466
|
+
* capp.datalink #=> "datalink name"
|
467
|
+
*
|
468
|
+
* Returns datalink used for capturing packets.
|
469
|
+
*
|
470
|
+
* Capp.live.datalink #=> ["EN10MB"]
|
471
|
+
*/
|
472
|
+
static VALUE
|
473
|
+
capp_datalink(VALUE self)
|
474
|
+
{
|
475
|
+
const char *datalink_name;
|
476
|
+
int dlt;
|
477
|
+
pcap_t *handle;
|
478
|
+
|
479
|
+
GetCapp(self, handle);
|
480
|
+
|
481
|
+
dlt = pcap_datalink(handle);
|
482
|
+
|
483
|
+
datalink_name = pcap_datalink_val_to_name(dlt);
|
484
|
+
return rb_usascii_str_new_cstr(datalink_name);
|
485
|
+
}
|
486
|
+
|
487
|
+
static VALUE
|
488
|
+
capp_make_ether_str(const struct ether_addr *addr)
|
489
|
+
{
|
490
|
+
return rb_usascii_str_new_cstr(ether_ntoa(addr));
|
491
|
+
}
|
492
|
+
|
493
|
+
static void
|
494
|
+
capp_make_unknown_layer3_header(VALUE headers, off_t offset)
|
495
|
+
{
|
496
|
+
VALUE unknown_args[1];
|
497
|
+
|
498
|
+
unknown_args[0] = UINT2NUM(offset);
|
499
|
+
|
500
|
+
rb_hash_aset(headers, ID2SYM(id_unknown_layer3),
|
501
|
+
rb_class_new_instance(1, unknown_args, cCappPacketUnknownLayer3Header));
|
502
|
+
}
|
503
|
+
|
504
|
+
static void
|
505
|
+
capp_make_ethernet_header(VALUE headers, const struct ether_header *ether)
|
506
|
+
{
|
507
|
+
VALUE ether_args[3];
|
508
|
+
|
509
|
+
ether_args[0] =
|
510
|
+
capp_make_ether_str((struct ether_addr *)ether->ether_dhost);
|
511
|
+
ether_args[1] =
|
512
|
+
capp_make_ether_str((struct ether_addr *)ether->ether_shost);
|
513
|
+
ether_args[2] = UINT2NUM(ntohs(ether->ether_type));
|
514
|
+
|
515
|
+
rb_hash_aset(headers, ID2SYM(id_ethernet),
|
516
|
+
rb_class_new_instance(3, ether_args, cCappPacketEthernetHeader));
|
517
|
+
}
|
518
|
+
|
519
|
+
static void
|
520
|
+
capp_make_icmp_header(VALUE headers, const struct icmp *header)
|
521
|
+
{
|
522
|
+
VALUE icmp_args[3];
|
523
|
+
|
524
|
+
icmp_args[0] = UINT2NUM(header->icmp_type);
|
525
|
+
icmp_args[1] = UINT2NUM(header->icmp_code);
|
526
|
+
icmp_args[2] = UINT2NUM(ntohs(header->icmp_cksum));
|
527
|
+
|
528
|
+
rb_hash_aset(headers, ID2SYM(id_icmp),
|
529
|
+
rb_class_new_instance(3, icmp_args, cCappPacketICMPHeader));
|
530
|
+
}
|
531
|
+
|
532
|
+
static void
|
533
|
+
capp_make_tcp_header(VALUE headers, const struct tcphdr *header)
|
534
|
+
{
|
535
|
+
VALUE tcp_args[9];
|
536
|
+
|
537
|
+
tcp_args[0] = UINT2NUM(ntohs(header->th_sport));
|
538
|
+
tcp_args[1] = UINT2NUM(ntohs(header->th_dport));
|
539
|
+
tcp_args[2] = UINT2NUM(ntohl(header->th_seq));
|
540
|
+
tcp_args[3] = UINT2NUM(ntohl(header->th_ack));
|
541
|
+
tcp_args[4] = UINT2NUM(TH_OFF(header));
|
542
|
+
tcp_args[5] = UINT2NUM(header->th_flags);
|
543
|
+
tcp_args[6] = UINT2NUM(ntohs(header->th_win));
|
544
|
+
tcp_args[7] = UINT2NUM(ntohs(header->th_sum));
|
545
|
+
tcp_args[8] = UINT2NUM(ntohs(header->th_urp));
|
546
|
+
|
547
|
+
rb_hash_aset(headers, ID2SYM(id_tcp),
|
548
|
+
rb_class_new_instance(9, tcp_args, cCappPacketTCPHeader));
|
549
|
+
}
|
550
|
+
|
551
|
+
static void
|
552
|
+
capp_make_udp_header(VALUE headers, const struct udphdr *header)
|
553
|
+
{
|
554
|
+
VALUE udp_args[4];
|
555
|
+
|
556
|
+
udp_args[0] = UINT2NUM(ntohs(header->uh_sport));
|
557
|
+
udp_args[1] = UINT2NUM(ntohs(header->uh_dport));
|
558
|
+
udp_args[2] = UINT2NUM(ntohs(header->uh_ulen));
|
559
|
+
udp_args[3] = UINT2NUM(ntohs(header->uh_sum));
|
560
|
+
|
561
|
+
rb_hash_aset(headers, ID2SYM(id_udp),
|
562
|
+
rb_class_new_instance(4, udp_args, cCappPacketUDPHeader));
|
563
|
+
}
|
564
|
+
|
565
|
+
static void
|
566
|
+
capp_make_arp_header(VALUE headers, const struct arphdr *header)
|
567
|
+
{
|
568
|
+
VALUE arp_args[7];
|
569
|
+
u_char hln, pln;
|
570
|
+
u_short hrd, pro;
|
571
|
+
u_short sha_offset, spa_offset, tha_offset, tpa_offset;
|
572
|
+
|
573
|
+
hrd = ntohs(header->ar_hrd);
|
574
|
+
arp_args[0] = UINT2NUM(hrd);
|
575
|
+
|
576
|
+
pro = ntohs(header->ar_pro);
|
577
|
+
arp_args[1] = UINT2NUM(pro);
|
578
|
+
arp_args[2] = UINT2NUM(ntohs(header->ar_op));
|
579
|
+
|
580
|
+
hln = header->ar_hln;
|
581
|
+
pln = header->ar_pln;
|
582
|
+
|
583
|
+
sha_offset = sizeof(struct arphdr);
|
584
|
+
spa_offset = sizeof(struct arphdr) + hln;
|
585
|
+
tha_offset = sizeof(struct arphdr) + hln + pln;
|
586
|
+
tpa_offset = sizeof(struct arphdr) + hln + pln + hln;
|
587
|
+
|
588
|
+
switch (hrd) {
|
589
|
+
case ARPHRD_ETHER:
|
590
|
+
arp_args[3] =
|
591
|
+
capp_make_ether_str((struct ether_addr *)((char *)header + sha_offset));
|
592
|
+
arp_args[5] =
|
593
|
+
capp_make_ether_str((struct ether_addr *)((char *)header + tha_offset));
|
594
|
+
break;
|
595
|
+
default:
|
596
|
+
rb_raise(rb_eNotImpError, "unsupported ARP hardware type %d", hrd);
|
597
|
+
}
|
598
|
+
|
599
|
+
switch (pro) {
|
600
|
+
case ETHERTYPE_IP:
|
601
|
+
arp_args[4] =
|
602
|
+
rb_usascii_str_new_cstr(inet_ntoa(*(struct in_addr *)((char *)header + spa_offset)));
|
603
|
+
arp_args[6] =
|
604
|
+
rb_usascii_str_new_cstr(inet_ntoa(*(struct in_addr *)((char *)header + tpa_offset)));
|
605
|
+
break;
|
606
|
+
default:
|
607
|
+
rb_raise(rb_eNotImpError, "unsupported ARP protocol %x", pro);
|
608
|
+
}
|
609
|
+
|
610
|
+
rb_hash_aset(headers, ID2SYM(id_arp),
|
611
|
+
rb_class_new_instance(7, arp_args, cCappPacketARPHeader));
|
612
|
+
}
|
613
|
+
|
614
|
+
static void
|
615
|
+
capp_make_ipv4_header(VALUE headers, const struct ip *header)
|
616
|
+
{
|
617
|
+
const char * ip_payload;
|
618
|
+
VALUE ipv4_args[11];
|
619
|
+
|
620
|
+
ipv4_args[0] = UINT2NUM(header->ip_v);
|
621
|
+
ipv4_args[1] = UINT2NUM(header->ip_hl);
|
622
|
+
ipv4_args[2] = UINT2NUM(header->ip_tos);
|
623
|
+
ipv4_args[3] = UINT2NUM(ntohs(header->ip_len));
|
624
|
+
ipv4_args[4] = UINT2NUM(ntohs(header->ip_id));
|
625
|
+
ipv4_args[5] = UINT2NUM(ntohs(header->ip_off));
|
626
|
+
ipv4_args[6] = UINT2NUM(header->ip_ttl);
|
627
|
+
ipv4_args[7] = UINT2NUM(header->ip_p);
|
628
|
+
ipv4_args[8] = UINT2NUM(ntohs(header->ip_sum));
|
629
|
+
ipv4_args[9] = rb_usascii_str_new_cstr(inet_ntoa(header->ip_src));
|
630
|
+
ipv4_args[10] = rb_usascii_str_new_cstr(inet_ntoa(header->ip_dst));
|
631
|
+
|
632
|
+
ip_payload = (char *)header + header->ip_hl * 4;
|
633
|
+
|
634
|
+
switch (header->ip_p) {
|
635
|
+
case IPPROTO_ICMP:
|
636
|
+
capp_make_icmp_header(headers, (const struct icmp *)ip_payload);
|
637
|
+
break;
|
638
|
+
case IPPROTO_TCP:
|
639
|
+
capp_make_tcp_header(headers, (const struct tcphdr *)ip_payload);
|
640
|
+
break;
|
641
|
+
case IPPROTO_UDP:
|
642
|
+
capp_make_udp_header(headers, (const struct udphdr *)ip_payload);
|
643
|
+
break;
|
644
|
+
}
|
645
|
+
|
646
|
+
rb_hash_aset(headers, ID2SYM(id_ipv4),
|
647
|
+
rb_class_new_instance(11, ipv4_args, cCappPacketIPv4Header));
|
648
|
+
}
|
649
|
+
|
650
|
+
static VALUE
|
651
|
+
capp_make_ipv6_addr(struct in6_addr addr)
|
652
|
+
{
|
653
|
+
char buf[INET6_ADDRSTRLEN];
|
654
|
+
const char *ptr;
|
655
|
+
|
656
|
+
ptr = inet_ntop(AF_INET6, &addr, buf, sizeof(buf));
|
657
|
+
|
658
|
+
if (!ptr)
|
659
|
+
rb_sys_fail("inet_ntop");
|
660
|
+
|
661
|
+
return rb_usascii_str_new_cstr(ptr);
|
662
|
+
}
|
663
|
+
|
664
|
+
static void
|
665
|
+
capp_make_ipv6_header(VALUE headers, const struct ip6_hdr *header)
|
666
|
+
{
|
667
|
+
const char * ip_payload;
|
668
|
+
VALUE ipv6_args[8];
|
669
|
+
|
670
|
+
ipv6_args[0] = UINT2NUM(6);
|
671
|
+
ipv6_args[1] = UINT2NUM((header->ip6_flow >> 20) & 0xff);
|
672
|
+
ipv6_args[2] = UINT2NUM(ntohl(header->ip6_flow & 0xfffff));
|
673
|
+
ipv6_args[3] = UINT2NUM(ntohs(header->ip6_plen));
|
674
|
+
ipv6_args[4] = UINT2NUM(header->ip6_nxt);
|
675
|
+
ipv6_args[5] = UINT2NUM(header->ip6_hlim);
|
676
|
+
ipv6_args[6] = capp_make_ipv6_addr(header->ip6_src);
|
677
|
+
ipv6_args[7] = capp_make_ipv6_addr(header->ip6_dst);
|
678
|
+
|
679
|
+
ip_payload = (char *)header + sizeof(struct ip6_hdr);
|
680
|
+
|
681
|
+
switch (header->ip6_nxt) {
|
682
|
+
case IPPROTO_ICMP:
|
683
|
+
case IPPROTO_ICMPV6:
|
684
|
+
capp_make_icmp_header(headers, (const struct icmp *)ip_payload);
|
685
|
+
break;
|
686
|
+
case IPPROTO_TCP:
|
687
|
+
capp_make_tcp_header(headers, (const struct tcphdr *)ip_payload);
|
688
|
+
break;
|
689
|
+
case IPPROTO_UDP:
|
690
|
+
capp_make_udp_header(headers, (const struct udphdr *)ip_payload);
|
691
|
+
break;
|
692
|
+
}
|
693
|
+
|
694
|
+
rb_hash_aset(headers, ID2SYM(id_ipv6),
|
695
|
+
rb_class_new_instance(8, ipv6_args, cCappPacketIPv6Header));
|
696
|
+
}
|
697
|
+
|
698
|
+
static void
|
699
|
+
capp_make_packet_ethernet(VALUE headers, const u_char *data)
|
700
|
+
{
|
701
|
+
VALUE ether_header;
|
702
|
+
uint16_t ethertype;
|
703
|
+
size_t ether_header_size = sizeof(struct ether_header);
|
704
|
+
|
705
|
+
capp_make_ethernet_header(headers, (const struct ether_header *)data);
|
706
|
+
|
707
|
+
ether_header = rb_hash_aref(headers, ID2SYM(id_ethernet));
|
708
|
+
ethertype = NUM2USHORT(rb_funcall(ether_header, id_type, 0));
|
709
|
+
|
710
|
+
switch (ethertype) {
|
711
|
+
case ETHERTYPE_ARP:
|
712
|
+
capp_make_arp_header(headers,
|
713
|
+
(const struct arphdr *)(data + ether_header_size));
|
714
|
+
break;
|
715
|
+
case ETHERTYPE_IP:
|
716
|
+
capp_make_ipv4_header(headers,
|
717
|
+
(const struct ip *)(data + ether_header_size));
|
718
|
+
break;
|
719
|
+
case ETHERTYPE_IPV6:
|
720
|
+
capp_make_ipv6_header(headers,
|
721
|
+
(const struct ip6_hdr *)(data + ether_header_size));
|
722
|
+
break;
|
723
|
+
default:
|
724
|
+
capp_make_unknown_layer3_header(headers, ether_header_size);
|
725
|
+
break;
|
726
|
+
}
|
727
|
+
}
|
728
|
+
|
729
|
+
static void
|
730
|
+
capp_make_packet_null(VALUE headers, const u_char *data)
|
731
|
+
{
|
732
|
+
uint32_t protocol_family;
|
733
|
+
size_t protocol_family_size = sizeof(protocol_family);
|
734
|
+
|
735
|
+
memcpy((char *)&protocol_family, (char *)data, protocol_family_size);
|
736
|
+
|
737
|
+
/*
|
738
|
+
* This isn't necessarily in our host byte order; if this is
|
739
|
+
* a DLT_LOOP capture, it's in network byte order, and if
|
740
|
+
* this is a DLT_NULL capture from a machine with the opposite
|
741
|
+
* byte-order, it's in the opposite byte order from ours.
|
742
|
+
*
|
743
|
+
* If the upper 16 bits aren't all zero, assume it's byte-swapped.
|
744
|
+
*/
|
745
|
+
if ((protocol_family & 0xFFFF0000) != 0)
|
746
|
+
protocol_family = SWAPLONG(protocol_family);
|
747
|
+
|
748
|
+
switch (protocol_family) {
|
749
|
+
/* PF_INET */
|
750
|
+
case BSD_AFNUM_INET:
|
751
|
+
capp_make_ipv4_header(headers,
|
752
|
+
(const struct ip *)(data + protocol_family_size));
|
753
|
+
break;
|
754
|
+
/* PF_INET6 */
|
755
|
+
case BSD_AFNUM_INET6_BSD:
|
756
|
+
case BSD_AFNUM_INET6_DARWIN:
|
757
|
+
case BSD_AFNUM_INET6_FREEBSD:
|
758
|
+
capp_make_ipv6_header(headers,
|
759
|
+
(const struct ip6_hdr *)(data + protocol_family_size));
|
760
|
+
break;
|
761
|
+
default:
|
762
|
+
capp_make_unknown_layer3_header(headers, protocol_family_size);
|
763
|
+
break;
|
764
|
+
}
|
765
|
+
}
|
766
|
+
|
767
|
+
/*
|
768
|
+
* capp_make_packet parses out the packet structure (if it understands it) and
|
769
|
+
* calls Capp::Packet::new.
|
770
|
+
*
|
771
|
+
* Parsing starts at the datalink level and works its way through the packet
|
772
|
+
* to the payload. Each parsing function is passed the payload for the
|
773
|
+
* current packet and the collected headers. The function must insert new
|
774
|
+
* data from the packet payload into the headers and repeat, with its payload,
|
775
|
+
* if possible.
|
776
|
+
*/
|
777
|
+
|
778
|
+
static VALUE
|
779
|
+
capp_make_packet(int datalink, const struct pcap_pkthdr *header,
|
780
|
+
const u_char *data)
|
781
|
+
{
|
782
|
+
VALUE headers = rb_hash_new();
|
783
|
+
VALUE packet_args[6];
|
784
|
+
|
785
|
+
switch (datalink) {
|
786
|
+
case DLT_NULL:
|
787
|
+
capp_make_packet_null(headers, data);
|
788
|
+
break;
|
789
|
+
case DLT_EN10MB:
|
790
|
+
capp_make_packet_ethernet(headers, data);
|
791
|
+
break;
|
792
|
+
}
|
793
|
+
|
794
|
+
packet_args[0] = rb_time_new(header->ts.tv_sec, header->ts.tv_usec);
|
795
|
+
packet_args[1] = UINT2NUM(header->len);
|
796
|
+
packet_args[2] = UINT2NUM(header->caplen);
|
797
|
+
packet_args[3] = rb_str_new((const char *)data, header->caplen);
|
798
|
+
packet_args[4] = UINT2NUM(datalink);
|
799
|
+
packet_args[5] = headers;
|
800
|
+
|
801
|
+
return rb_class_new_instance(6, packet_args, cCappPacket);
|
802
|
+
}
|
803
|
+
|
804
|
+
static void *
|
805
|
+
capp_loop_callback_with_gvl(void *ptr)
|
806
|
+
{
|
807
|
+
struct capp_loop_args *args = (struct capp_loop_args *)ptr;
|
808
|
+
|
809
|
+
rb_yield(capp_make_packet(args->datalink, args->header, args->data));
|
810
|
+
|
811
|
+
return NULL;
|
812
|
+
}
|
813
|
+
|
814
|
+
static void
|
815
|
+
capp_loop_callback(u_char *ptr, const struct pcap_pkthdr *header,
|
816
|
+
const u_char *data)
|
817
|
+
{
|
818
|
+
struct capp_loop_args *args = (struct capp_loop_args *)ptr;
|
819
|
+
|
820
|
+
args->header = header;
|
821
|
+
args->data = data;
|
822
|
+
|
823
|
+
rb_thread_call_with_gvl(capp_loop_callback_with_gvl, (void *)args);
|
824
|
+
}
|
825
|
+
|
826
|
+
static VALUE
|
827
|
+
capp_loop_end(VALUE self)
|
828
|
+
{
|
829
|
+
pcap_t *handle;
|
830
|
+
|
831
|
+
GetCapp(self, handle);
|
832
|
+
|
833
|
+
pcap_breakloop(handle);
|
834
|
+
|
835
|
+
return Qnil;
|
836
|
+
}
|
837
|
+
|
838
|
+
static void
|
839
|
+
capp_loop_interrupt(void *ptr)
|
840
|
+
{
|
841
|
+
pcap_t *handle = (pcap_t *)ptr;
|
842
|
+
|
843
|
+
pcap_breakloop(handle);
|
844
|
+
}
|
845
|
+
|
846
|
+
static void *
|
847
|
+
capp_loop_run_no_gvl(void *ptr)
|
848
|
+
{
|
849
|
+
struct capp_loop_args *args = (struct capp_loop_args *)ptr;
|
850
|
+
int res;
|
851
|
+
|
852
|
+
res = pcap_loop(args->handle, -1, capp_loop_callback, (u_char *)ptr);
|
853
|
+
|
854
|
+
return (void *)(intptr_t)res;
|
855
|
+
}
|
856
|
+
|
857
|
+
static VALUE
|
858
|
+
capp_loop_run(VALUE self)
|
859
|
+
{
|
860
|
+
struct capp_loop_args args;
|
861
|
+
int res;
|
862
|
+
|
863
|
+
GetCapp(self, args.handle);
|
864
|
+
|
865
|
+
args.datalink = pcap_datalink(args.handle);
|
866
|
+
|
867
|
+
rb_ivar_set(self, id_iv_datalink, INT2NUM(args.datalink));
|
868
|
+
|
869
|
+
res = (int)(intptr_t)rb_thread_call_without_gvl(capp_loop_run_no_gvl,
|
870
|
+
(void *)&args, capp_loop_interrupt, (void *)args.handle);
|
871
|
+
|
872
|
+
if (res == -1)
|
873
|
+
rb_raise(eCappError, "%s", pcap_geterr(args.handle));
|
874
|
+
|
875
|
+
return self;
|
876
|
+
}
|
877
|
+
|
878
|
+
/*
|
879
|
+
* call-seq:
|
880
|
+
* capp.loop { |packet| ... } -> self
|
881
|
+
* capp.loop -> enumerator
|
882
|
+
*
|
883
|
+
* Starts capturing packets. Each packet captured is yielded to the block.
|
884
|
+
* Packets are instances of Capp::Packet.
|
885
|
+
*
|
886
|
+
* If no block is given an enumerator is returned.
|
887
|
+
*
|
888
|
+
* You can stop capturing packets by returning from the block (or using break)
|
889
|
+
* or by calling #stop on the instance. Packet capture can be restarted
|
890
|
+
* later.
|
891
|
+
*/
|
892
|
+
static VALUE
|
893
|
+
capp_loop(VALUE self)
|
894
|
+
{
|
895
|
+
RETURN_ENUMERATOR(self, 0, 0);
|
896
|
+
|
897
|
+
rb_ensure(capp_loop_run, self, capp_loop_end, self);
|
898
|
+
|
899
|
+
return self;
|
900
|
+
}
|
901
|
+
|
902
|
+
/*
|
903
|
+
* call-seq:
|
904
|
+
* capp.savefile_major_version -> integer
|
905
|
+
*
|
906
|
+
* When called on a capture instance created from a savefile, returns the
|
907
|
+
* major version of the savefile. When called on a live capture instance it
|
908
|
+
* returns a meaningless value.
|
909
|
+
*/
|
910
|
+
static VALUE
|
911
|
+
capp_savefile_major_version(VALUE self)
|
912
|
+
{
|
913
|
+
pcap_t *handle;
|
914
|
+
|
915
|
+
GetCapp(self, handle);
|
916
|
+
|
917
|
+
return INT2NUM(pcap_major_version(handle));
|
918
|
+
}
|
919
|
+
|
920
|
+
/*
|
921
|
+
* call-seq:
|
922
|
+
* capp.savefile_minor_version -> integer
|
923
|
+
*
|
924
|
+
* When called on a capture instance created from a savefile, returns the
|
925
|
+
* minor version of the savefile. When called on a live capture instance it
|
926
|
+
* returns a meaningless value.
|
927
|
+
*/
|
928
|
+
static VALUE
|
929
|
+
capp_savefile_minor_version(VALUE self)
|
930
|
+
{
|
931
|
+
pcap_t *handle;
|
932
|
+
|
933
|
+
GetCapp(self, handle);
|
934
|
+
|
935
|
+
return INT2NUM(pcap_minor_version(handle));
|
936
|
+
}
|
937
|
+
|
938
|
+
/*
|
939
|
+
* call-seq:
|
940
|
+
* capp.datalink = datalink_name
|
941
|
+
*
|
942
|
+
* Sets the link-layer header type to be used by the capture instance to the
|
943
|
+
* given +datalink_name+. You can see the supported datalink names by calling
|
944
|
+
* #datalinks on the capture instance.
|
945
|
+
*
|
946
|
+
* Note that most possible datalink types do not have full support in Capp.
|
947
|
+
* You may receive the raw packet without any further extraction of packet
|
948
|
+
* fields.
|
949
|
+
*/
|
950
|
+
static VALUE
|
951
|
+
capp_set_datalink(VALUE self, VALUE datalink)
|
952
|
+
{
|
953
|
+
int dlt;
|
954
|
+
pcap_t *handle;
|
955
|
+
const char *datalink_name = StringValueCStr(datalink);
|
956
|
+
|
957
|
+
GetCapp(self, handle);
|
958
|
+
|
959
|
+
dlt = pcap_datalink_name_to_val(datalink_name);
|
960
|
+
|
961
|
+
if (-1 == dlt)
|
962
|
+
rb_raise(eCappError, "unrecognized datalink name %s", datalink_name);
|
963
|
+
|
964
|
+
if (pcap_set_datalink(handle, dlt))
|
965
|
+
rb_raise(eCappError, "%s", pcap_geterr(handle));
|
966
|
+
|
967
|
+
return datalink;
|
968
|
+
}
|
969
|
+
|
970
|
+
/*
|
971
|
+
* call-seq:
|
972
|
+
* capp.filter = filter -> self
|
973
|
+
*
|
974
|
+
* Sets the packet filter to the given +filter+ string. The format is the
|
975
|
+
* same format as for tcpdump. Read the pcap-filter(7) man page for
|
976
|
+
* documentation on the filter syntax.
|
977
|
+
*/
|
978
|
+
static VALUE
|
979
|
+
capp_set_filter(VALUE self, VALUE filter)
|
980
|
+
{
|
981
|
+
VALUE device;
|
982
|
+
pcap_t *handle;
|
983
|
+
struct bpf_program program;
|
984
|
+
bpf_u_int32 network, netmask = PCAP_NETMASK_UNKNOWN;
|
985
|
+
char errbuf[PCAP_ERRBUF_SIZE];
|
986
|
+
int res;
|
987
|
+
|
988
|
+
device = rb_ivar_get(self, id_iv_device);
|
989
|
+
|
990
|
+
if (RTEST(device)) {
|
991
|
+
*errbuf = '\0';
|
992
|
+
|
993
|
+
res =
|
994
|
+
pcap_lookupnet(StringValueCStr(device), &network, &netmask, errbuf);
|
995
|
+
|
996
|
+
if (res == -1)
|
997
|
+
rb_raise(eCappError, "%s", errbuf);
|
998
|
+
|
999
|
+
if (*errbuf)
|
1000
|
+
rb_warn("%s", errbuf);
|
1001
|
+
}
|
1002
|
+
|
1003
|
+
GetCapp(self, handle);
|
1004
|
+
|
1005
|
+
res = pcap_compile(handle, &program, StringValueCStr(filter), 0, netmask);
|
1006
|
+
|
1007
|
+
if (res)
|
1008
|
+
rb_raise(eCappError, "%s", pcap_geterr(handle));
|
1009
|
+
|
1010
|
+
res = pcap_setfilter(handle, &program);
|
1011
|
+
|
1012
|
+
pcap_freecode(&program);
|
1013
|
+
|
1014
|
+
if (res)
|
1015
|
+
rb_raise(eCappError, "%s", pcap_geterr(handle));
|
1016
|
+
|
1017
|
+
return self;
|
1018
|
+
}
|
1019
|
+
|
1020
|
+
/*
|
1021
|
+
* call-seq:
|
1022
|
+
* capp.promiscuous = boolean
|
1023
|
+
*
|
1024
|
+
* Enables or disables promiscuous mode. When promiscuous mode is enabled
|
1025
|
+
* packets that were not sent directly to the device will be captured.
|
1026
|
+
*/
|
1027
|
+
static VALUE
|
1028
|
+
capp_set_promisc(VALUE self, VALUE promiscuous)
|
1029
|
+
{
|
1030
|
+
pcap_t *handle;
|
1031
|
+
int promisc = RTEST(promiscuous);
|
1032
|
+
|
1033
|
+
GetCapp(self, handle);
|
1034
|
+
|
1035
|
+
if (pcap_set_promisc(handle, promisc))
|
1036
|
+
rb_raise(eCappError, "pcap already activated");
|
1037
|
+
|
1038
|
+
return promiscuous;
|
1039
|
+
}
|
1040
|
+
|
1041
|
+
/*
|
1042
|
+
* call-seq:
|
1043
|
+
* capp.snaplen = bytes
|
1044
|
+
*
|
1045
|
+
* Sets the number of +bytes+ captured from each packet.
|
1046
|
+
*/
|
1047
|
+
static VALUE
|
1048
|
+
capp_set_snaplen(VALUE self, VALUE snaplen)
|
1049
|
+
{
|
1050
|
+
pcap_t *handle;
|
1051
|
+
|
1052
|
+
GetCapp(self, handle);
|
1053
|
+
|
1054
|
+
if (pcap_set_snaplen(handle, NUM2INT(snaplen)))
|
1055
|
+
rb_raise(eCappError, "pcap already activated");
|
1056
|
+
|
1057
|
+
return snaplen;
|
1058
|
+
}
|
1059
|
+
|
1060
|
+
/*
|
1061
|
+
* call-seq:
|
1062
|
+
* capp.timeout = milliseconds
|
1063
|
+
*
|
1064
|
+
* Sets the maximum amount of time in +milliseconds+ that will elapse between
|
1065
|
+
* receiving a packet and yielding it to #loop.
|
1066
|
+
*
|
1067
|
+
* Reducing the timeout will increase responsiveness as pcap_loop(3) must
|
1068
|
+
* "check in" more frequently while increasing the timeout will reduce
|
1069
|
+
* responsiveness.
|
1070
|
+
*
|
1071
|
+
* Setting the timeout too low may increase GVL contention when many packets
|
1072
|
+
* are arriving at once as #loop will be waking up frequently to service
|
1073
|
+
* captured packets.
|
1074
|
+
*/
|
1075
|
+
static VALUE
|
1076
|
+
capp_set_timeout(VALUE self, VALUE milliseconds)
|
1077
|
+
{
|
1078
|
+
pcap_t *handle;
|
1079
|
+
|
1080
|
+
GetCapp(self, handle);
|
1081
|
+
|
1082
|
+
if (pcap_set_timeout(handle, NUM2INT(milliseconds)))
|
1083
|
+
rb_raise(eCappError, "pcap already activated");
|
1084
|
+
|
1085
|
+
return milliseconds;
|
1086
|
+
}
|
1087
|
+
|
1088
|
+
/*
|
1089
|
+
* call-seq:
|
1090
|
+
* capp.stats -> hash
|
1091
|
+
*
|
1092
|
+
* Retrieves packet capture statistics:
|
1093
|
+
*
|
1094
|
+
* p capp.stats #=> {:drop => 0, :ifdrop => 0, :recv => 123}
|
1095
|
+
*/
|
1096
|
+
static VALUE
|
1097
|
+
capp_stats(VALUE self)
|
1098
|
+
{
|
1099
|
+
VALUE stats;
|
1100
|
+
pcap_t *handle;
|
1101
|
+
struct pcap_stat ps;
|
1102
|
+
|
1103
|
+
GetCapp(self, handle);
|
1104
|
+
|
1105
|
+
if (pcap_stats(handle, &ps))
|
1106
|
+
rb_raise(eCappError, "%s", pcap_geterr(handle));
|
1107
|
+
|
1108
|
+
stats = rb_hash_new();
|
1109
|
+
|
1110
|
+
rb_hash_aset(stats, ID2SYM(id_drop), UINT2NUM(ps.ps_drop));
|
1111
|
+
rb_hash_aset(stats, ID2SYM(id_ifdrop), UINT2NUM(ps.ps_ifdrop));
|
1112
|
+
rb_hash_aset(stats, ID2SYM(id_recv), UINT2NUM(ps.ps_recv));
|
1113
|
+
|
1114
|
+
return stats;
|
1115
|
+
}
|
1116
|
+
|
1117
|
+
/*
|
1118
|
+
* call-seq:
|
1119
|
+
* capp.stop -> capp
|
1120
|
+
*
|
1121
|
+
* Stops a running loop
|
1122
|
+
*/
|
1123
|
+
static VALUE
|
1124
|
+
capp_stop(VALUE self)
|
1125
|
+
{
|
1126
|
+
pcap_t *handle;
|
1127
|
+
|
1128
|
+
GetCapp(self, handle);
|
1129
|
+
|
1130
|
+
pcap_breakloop(handle);
|
1131
|
+
|
1132
|
+
return self;
|
1133
|
+
}
|
1134
|
+
|
1135
|
+
void
|
1136
|
+
Init_capp(void) {
|
1137
|
+
id_arp = rb_intern("arp");
|
1138
|
+
id_drop = rb_intern("drop");
|
1139
|
+
id_ethernet = rb_intern("ethernet");
|
1140
|
+
id_icmp = rb_intern("icmp");
|
1141
|
+
id_ifdrop = rb_intern("ifdrop");
|
1142
|
+
id_ipv4 = rb_intern("ipv4");
|
1143
|
+
id_ipv6 = rb_intern("ipv6");
|
1144
|
+
id_iv_datalink = rb_intern("@datalink");
|
1145
|
+
id_iv_device = rb_intern("@device");
|
1146
|
+
id_recv = rb_intern("recv");
|
1147
|
+
id_tcp = rb_intern("tcp");
|
1148
|
+
id_type = rb_intern("type");
|
1149
|
+
id_udp = rb_intern("udp");
|
1150
|
+
id_unknown_layer3 = rb_intern("unknown_layer3");
|
1151
|
+
id_unpack_sockaddr_in = rb_intern("unpack_sockaddr_in");
|
1152
|
+
|
1153
|
+
cCapp = rb_define_class("Capp", rb_cObject);
|
1154
|
+
|
1155
|
+
cCappAddress = rb_const_get(cCapp, rb_intern("Address"));
|
1156
|
+
cCappDevice = rb_const_get(cCapp, rb_intern("Device"));
|
1157
|
+
cCappPacket = rb_const_get(cCapp, rb_intern("Packet"));
|
1158
|
+
eCappError = rb_const_get(cCapp, rb_intern("Error"));
|
1159
|
+
|
1160
|
+
cCappPacketARPHeader =
|
1161
|
+
rb_const_get(cCappPacket, rb_intern("ARPHeader"));
|
1162
|
+
cCappPacketEthernetHeader =
|
1163
|
+
rb_const_get(cCappPacket, rb_intern("EthernetHeader"));
|
1164
|
+
cCappPacketICMPHeader =
|
1165
|
+
rb_const_get(cCappPacket, rb_intern("ICMPHeader"));
|
1166
|
+
cCappPacketIPv4Header =
|
1167
|
+
rb_const_get(cCappPacket, rb_intern("IPv4Header"));
|
1168
|
+
cCappPacketIPv6Header =
|
1169
|
+
rb_const_get(cCappPacket, rb_intern("IPv6Header"));
|
1170
|
+
cCappPacketTCPHeader =
|
1171
|
+
rb_const_get(cCappPacket, rb_intern("TCPHeader"));
|
1172
|
+
cCappPacketUDPHeader =
|
1173
|
+
rb_const_get(cCappPacket, rb_intern("UDPHeader"));
|
1174
|
+
cCappPacketUnknownLayer3Header =
|
1175
|
+
rb_const_get(cCappPacket, rb_intern("UnknownLayer3Header"));
|
1176
|
+
|
1177
|
+
cSocket = rb_const_get(rb_cObject, rb_intern("Socket"));
|
1178
|
+
|
1179
|
+
rb_undef_alloc_func(cCapp);
|
1180
|
+
|
1181
|
+
rb_define_singleton_method(cCapp, "default_device_name", capp_s_default_device_name, 0);
|
1182
|
+
rb_define_singleton_method(cCapp, "devices", capp_s_devices, 0);
|
1183
|
+
rb_define_singleton_method(cCapp, "live", capp_s_open_live, -1);
|
1184
|
+
rb_define_singleton_method(cCapp, "offline", capp_s_open_offline, 1);
|
1185
|
+
rb_define_singleton_method(cCapp, "pcap_lib_version", capp_s_pcap_lib_version, 0);
|
1186
|
+
|
1187
|
+
rb_define_method(cCapp, "datalink", capp_datalink, 0);
|
1188
|
+
rb_define_method(cCapp, "datalink=", capp_set_datalink, 1);
|
1189
|
+
rb_define_method(cCapp, "datalinks", capp_datalinks, 0);
|
1190
|
+
rb_define_method(cCapp, "filter=", capp_set_filter, 1);
|
1191
|
+
rb_define_method(cCapp, "loop", capp_loop, 0);
|
1192
|
+
rb_define_method(cCapp, "promiscuous=", capp_set_promisc, 1);
|
1193
|
+
rb_define_method(cCapp, "savefile_major_version", capp_savefile_major_version, 0);
|
1194
|
+
rb_define_method(cCapp, "savefile_minor_version", capp_savefile_minor_version, 0);
|
1195
|
+
rb_define_method(cCapp, "snaplen=", capp_set_snaplen, 1);
|
1196
|
+
rb_define_method(cCapp, "stats", capp_stats, 0);
|
1197
|
+
rb_define_method(cCapp, "stop", capp_stop, 0);
|
1198
|
+
rb_define_method(cCapp, "timeout=", capp_set_timeout, 1);
|
1199
|
+
|
1200
|
+
/* Document-const: ARPHRD_ETHER
|
1201
|
+
*
|
1202
|
+
* Ethernet hardware
|
1203
|
+
*/
|
1204
|
+
rb_define_const(cCapp, "ARPHRD_ETHER", INT2NUM(ARPHRD_ETHER));
|
1205
|
+
|
1206
|
+
/* Document-const: ARPHRD_FRELAY
|
1207
|
+
*
|
1208
|
+
* frame relay hardware
|
1209
|
+
*/
|
1210
|
+
rb_define_const(cCapp, "ARPHRD_FRELAY", INT2NUM(ARPHRD_FRELAY));
|
1211
|
+
|
1212
|
+
/* Document-const: ARPHRD_IEEE1394
|
1213
|
+
*
|
1214
|
+
* IEEE1394 (FireWire™) hardware
|
1215
|
+
*/
|
1216
|
+
rb_define_const(cCapp, "ARPHRD_IEEE1394", INT2NUM(ARPHRD_IEEE1394));
|
1217
|
+
|
1218
|
+
/* Document-const: ARPHRD_IEEE1394_EUI64
|
1219
|
+
*
|
1220
|
+
* IEEE1394 (FireWire™) hardware with EUI-64 addresses
|
1221
|
+
*/
|
1222
|
+
rb_define_const(cCapp, "ARPHRD_IEEE1394_EUI64",
|
1223
|
+
INT2NUM(ARPHRD_IEEE1394_EUI64));
|
1224
|
+
|
1225
|
+
/* Document-const: ARPHRD_IEEE802
|
1226
|
+
*
|
1227
|
+
* token-ring hardware
|
1228
|
+
*/
|
1229
|
+
rb_define_const(cCapp, "ARPHRD_IEEE802", INT2NUM(ARPHRD_IEEE802));
|
1230
|
+
|
1231
|
+
/* Document-const: ARPOP_INVREPLY
|
1232
|
+
*
|
1233
|
+
* ARP response identifying peer
|
1234
|
+
*/
|
1235
|
+
rb_define_const(cCapp, "ARPOP_INVREPLY", INT2NUM(ARPOP_INVREPLY));
|
1236
|
+
|
1237
|
+
/* Document-const: ARPOP_INVREQUEST
|
1238
|
+
*
|
1239
|
+
* ARP request to identify peer
|
1240
|
+
*/
|
1241
|
+
rb_define_const(cCapp, "ARPOP_INVREQUEST", INT2NUM(ARPOP_INVREQUEST));
|
1242
|
+
|
1243
|
+
/* Document-const: ARPOP_REPLY
|
1244
|
+
*
|
1245
|
+
* ARP response to resolve request
|
1246
|
+
*/
|
1247
|
+
rb_define_const(cCapp, "ARPOP_REPLY", INT2NUM(ARPOP_REPLY));
|
1248
|
+
|
1249
|
+
/* Document-const: ARPOP_REQUEST
|
1250
|
+
*
|
1251
|
+
* ARP resolve address request
|
1252
|
+
*/
|
1253
|
+
rb_define_const(cCapp, "ARPOP_REQUEST", INT2NUM(ARPOP_REQUEST));
|
1254
|
+
|
1255
|
+
/* Document-const: ARPOP_REVREPLY
|
1256
|
+
*
|
1257
|
+
* ARP response giving protocol address
|
1258
|
+
*/
|
1259
|
+
rb_define_const(cCapp, "ARPOP_REVREPLY", INT2NUM(ARPOP_REVREPLY));
|
1260
|
+
|
1261
|
+
/* Document-const: ARPOP_REVREQUEST
|
1262
|
+
*
|
1263
|
+
* ARP request protocol address given hardware address
|
1264
|
+
*/
|
1265
|
+
rb_define_const(cCapp, "ARPOP_REVREQUEST", INT2NUM(ARPOP_REVREQUEST));
|
1266
|
+
|
1267
|
+
/* Document-const: DLT_NULL
|
1268
|
+
*
|
1269
|
+
* BSD loopback encapsulation.
|
1270
|
+
*/
|
1271
|
+
rb_define_const(cCapp, "DLT_NULL", INT2NUM(DLT_NULL));
|
1272
|
+
|
1273
|
+
/* Document-const: DLT_EN10MB
|
1274
|
+
*
|
1275
|
+
* Ethernet encapsulation.
|
1276
|
+
*/
|
1277
|
+
rb_define_const(cCapp, "DLT_EN10MB", INT2NUM(DLT_EN10MB));
|
1278
|
+
|
1279
|
+
/* Document-const: ETHERTYPE_ARP
|
1280
|
+
*
|
1281
|
+
* Address Resolution Protocol
|
1282
|
+
*/
|
1283
|
+
rb_define_const(cCapp, "ETHERTYPE_ARP", INT2NUM(ETHERTYPE_ARP));
|
1284
|
+
|
1285
|
+
/* Document-const: ETHERTYPE_IP
|
1286
|
+
*
|
1287
|
+
* IPv4
|
1288
|
+
*/
|
1289
|
+
rb_define_const(cCapp, "ETHERTYPE_IP", INT2NUM(ETHERTYPE_IP));
|
1290
|
+
|
1291
|
+
/* Document-const: ETHERTYPE_IPV6
|
1292
|
+
*
|
1293
|
+
* IPv6
|
1294
|
+
*/
|
1295
|
+
rb_define_const(cCapp, "ETHERTYPE_IPV6", INT2NUM(ETHERTYPE_IPV6));
|
1296
|
+
|
1297
|
+
/* Document-const: ETHERTYPE_LOOPBACK
|
1298
|
+
*
|
1299
|
+
* Used to test interfaces
|
1300
|
+
*/
|
1301
|
+
rb_define_const(cCapp, "ETHERTYPE_LOOPBACK", INT2NUM(ETHERTYPE_LOOPBACK));
|
1302
|
+
|
1303
|
+
/* Document-const: ETHERTYPE_PUP
|
1304
|
+
*
|
1305
|
+
* PUP protocol
|
1306
|
+
*/
|
1307
|
+
rb_define_const(cCapp, "ETHERTYPE_PUP", INT2NUM(ETHERTYPE_PUP));
|
1308
|
+
|
1309
|
+
/* Document-const: ETHERTYPE_PAE
|
1310
|
+
*
|
1311
|
+
* EAPOL PAE/802.1x
|
1312
|
+
*/
|
1313
|
+
rb_define_const(cCapp, "ETHERTYPE_PAE", INT2NUM(ETHERTYPE_PAE));
|
1314
|
+
|
1315
|
+
/* Document-const: ETHERTYPE_REVARP
|
1316
|
+
*
|
1317
|
+
* Reverse Address Resolution Protocol
|
1318
|
+
*/
|
1319
|
+
rb_define_const(cCapp, "ETHERTYPE_REVARP", INT2NUM(ETHERTYPE_REVARP));
|
1320
|
+
|
1321
|
+
/* Document-const: ETHERTYPE_RSN_PREAUTH
|
1322
|
+
*
|
1323
|
+
* 802.11i / RSN Pre-Authentication
|
1324
|
+
*/
|
1325
|
+
rb_define_const(cCapp, "ETHERTYPE_RSN_PREAUTH",
|
1326
|
+
INT2NUM(ETHERTYPE_RSN_PREAUTH));
|
1327
|
+
|
1328
|
+
/* Document-const: ETHERTYPE_VLAN
|
1329
|
+
*
|
1330
|
+
* IEEE 802.1Q VLAN tagging
|
1331
|
+
*/
|
1332
|
+
rb_define_const(cCapp, "ETHERTYPE_VLAN", INT2NUM(ETHERTYPE_VLAN));
|
1333
|
+
|
1334
|
+
/* Document-const: TCP_ACK
|
1335
|
+
*
|
1336
|
+
* TCP Acknowledged flag
|
1337
|
+
*/
|
1338
|
+
rb_define_const(cCapp, "TCP_ACK", INT2NUM(TH_ACK));
|
1339
|
+
|
1340
|
+
/* Document-const: TCP_CWR
|
1341
|
+
*
|
1342
|
+
* TCP Congestion Window Reduced flag
|
1343
|
+
*/
|
1344
|
+
rb_define_const(cCapp, "TCP_CWR", INT2NUM(TH_CWR));
|
1345
|
+
|
1346
|
+
/* Document-const: TCP_ECE
|
1347
|
+
*
|
1348
|
+
* TCP ECN echo flag
|
1349
|
+
*/
|
1350
|
+
rb_define_const(cCapp, "TCP_ECE", INT2NUM(TH_ECE));
|
1351
|
+
|
1352
|
+
/* Document-const: TCP_FIN
|
1353
|
+
*
|
1354
|
+
* TCP Finish flag
|
1355
|
+
*/
|
1356
|
+
rb_define_const(cCapp, "TCP_FIN", INT2NUM(TH_FIN));
|
1357
|
+
|
1358
|
+
/* Document-const: TCP_PUSH
|
1359
|
+
*
|
1360
|
+
* TCP Push flag
|
1361
|
+
*/
|
1362
|
+
rb_define_const(cCapp, "TCP_PUSH", INT2NUM(TH_PUSH));
|
1363
|
+
|
1364
|
+
/* Document-const: TCP_RST
|
1365
|
+
*
|
1366
|
+
* TCP Reset flag
|
1367
|
+
*/
|
1368
|
+
rb_define_const(cCapp, "TCP_RST", INT2NUM(TH_RST));
|
1369
|
+
|
1370
|
+
/* Document-const: TCP_SYN
|
1371
|
+
*
|
1372
|
+
* TCP Synchronize flag
|
1373
|
+
*/
|
1374
|
+
rb_define_const(cCapp, "TCP_SYN", INT2NUM(TH_SYN));
|
1375
|
+
|
1376
|
+
/* Document-const: TCP_URG
|
1377
|
+
*
|
1378
|
+
* TCP Urgent flag
|
1379
|
+
*/
|
1380
|
+
rb_define_const(cCapp, "TCP_URG", INT2NUM(TH_URG));
|
1381
|
+
}
|
1382
|
+
|