capp 1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|