rbbcc 0.11.6 → 0.11.7
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 +4 -4
- data/Gemfile.lock +1 -1
- data/lib/rbbcc/version.rb +1 -1
- data/rbbcc.gemspec +5 -2
- metadata +2 -62
- data/docs/README.md +0 -7
- data/docs/answers/01-hello-world.rb +0 -16
- data/docs/answers/02-sys_sync.rb +0 -18
- data/docs/answers/03-hello_fields.rb +0 -33
- data/docs/answers/04-sync_timing.rb +0 -46
- data/docs/answers/05-sync_count.rb +0 -54
- data/docs/answers/06-disksnoop.rb +0 -71
- data/docs/answers/07-hello_perf_output.rb +0 -59
- data/docs/answers/08-sync_perf_output.rb +0 -60
- data/docs/answers/09-bitehist.rb +0 -32
- data/docs/answers/10-disklatency.rb +0 -51
- data/docs/answers/11-vfsreadlat.c +0 -46
- data/docs/answers/11-vfsreadlat.rb +0 -66
- data/docs/answers/12-urandomread.rb +0 -38
- data/docs/answers/13-disksnoop_fixed.rb +0 -108
- data/docs/answers/14-strlen_count.rb +0 -46
- data/docs/answers/15-nodejs_http_server.rb +0 -44
- data/docs/answers/16-task_switch.c +0 -23
- data/docs/answers/16-task_switch.rb +0 -17
- data/docs/answers/node-server.js +0 -11
- data/docs/getting_started.md +0 -154
- data/docs/projects_using_rbbcc.md +0 -43
- data/docs/tutorial_bcc_ruby_developer.md +0 -774
- data/docs/tutorial_bcc_ruby_developer_japanese.md +0 -770
- data/examples/bitehist.rb +0 -46
- data/examples/charty/Gemfile +0 -11
- data/examples/charty/Gemfile.lock +0 -48
- data/examples/charty/bitehist-unicode.rb +0 -87
- data/examples/collectsyscall.rb +0 -182
- data/examples/dddos.rb +0 -112
- data/examples/disksnoop.rb +0 -73
- data/examples/dns_blocker.rb +0 -134
- data/examples/example.gif +0 -0
- data/examples/extract_arg.rb +0 -26
- data/examples/hello_fields.rb +0 -32
- data/examples/hello_perf_output.rb +0 -64
- data/examples/hello_ring_buffer.rb +0 -64
- data/examples/hello_world.rb +0 -6
- data/examples/kvm_hypercall.rb +0 -69
- data/examples/lsm_sockblock.rb +0 -141
- data/examples/mallocstack.rb +0 -63
- data/examples/networking/http_filter/http-parse-simple.c +0 -114
- data/examples/networking/http_filter/http-parse-simple.rb +0 -85
- data/examples/pin_maps_a.rb +0 -88
- data/examples/pin_maps_b.rb +0 -71
- data/examples/py-orig/sockblock.py +0 -119
- data/examples/ringbuf_pin_a.rb +0 -51
- data/examples/ringbuf_pin_b.rb +0 -29
- data/examples/ruby_usdt.rb +0 -105
- data/examples/sbrk_trace.rb +0 -204
- data/examples/ssl_http_trace.rb +0 -274
- data/examples/syscalluname.rb +0 -39
- data/examples/table.rb +0 -15
- data/examples/tools/bashreadline.rb +0 -83
- data/examples/tools/execsnoop.rb +0 -229
- data/examples/tools/runqlat.rb +0 -148
- data/examples/urandomread-explicit.rb +0 -58
- data/examples/urandomread.rb +0 -39
- data/examples/usdt-test.rb +0 -6
- data/examples/usdt.rb +0 -26
data/examples/bitehist.rb
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
#
|
|
3
|
-
# bitehist.rb, ported from bitehist.py. See license on that file
|
|
4
|
-
#
|
|
5
|
-
# Written as a basic example of using histograms to show a distribution.
|
|
6
|
-
#
|
|
7
|
-
# A Ctrl-C will print the gathered histogram then exit.
|
|
8
|
-
#
|
|
9
|
-
|
|
10
|
-
require 'rbbcc'
|
|
11
|
-
include RbBCC
|
|
12
|
-
|
|
13
|
-
b = BCC.new(text: <<CLANG)
|
|
14
|
-
#include <uapi/linux/ptrace.h>
|
|
15
|
-
#include <linux/blkdev.h>
|
|
16
|
-
|
|
17
|
-
BPF_HISTOGRAM(dist);
|
|
18
|
-
BPF_HISTOGRAM(dist_linear);
|
|
19
|
-
|
|
20
|
-
int kprobe__blk_account_io_done(struct pt_regs *ctx, struct request *req)
|
|
21
|
-
{
|
|
22
|
-
dist.increment(bpf_log2l(req->__data_len / 1024));
|
|
23
|
-
dist_linear.increment(req->__data_len / 1024);
|
|
24
|
-
return 0;
|
|
25
|
-
}
|
|
26
|
-
CLANG
|
|
27
|
-
|
|
28
|
-
puts "Tracing... Hit Ctrl-C to end."
|
|
29
|
-
|
|
30
|
-
loop do
|
|
31
|
-
begin
|
|
32
|
-
sleep 0.1
|
|
33
|
-
rescue Interrupt
|
|
34
|
-
puts
|
|
35
|
-
break
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
puts "log2 histogram"
|
|
40
|
-
puts "~~~~~~~~~~~~~~"
|
|
41
|
-
b["dist"].print_log2_hist("kbytes")
|
|
42
|
-
|
|
43
|
-
puts
|
|
44
|
-
puts "linear histogram"
|
|
45
|
-
puts "~~~~~~~~~~~~~~~~"
|
|
46
|
-
b["dist_linear"].print_linear_hist("kbytes")
|
data/examples/charty/Gemfile
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
source "https://rubygems.org"
|
|
4
|
-
|
|
5
|
-
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
|
|
6
|
-
|
|
7
|
-
gem "rbbcc", path: '../../'
|
|
8
|
-
gem "charty", path: '/usr/local/ghq/github.com/udzura/charty'
|
|
9
|
-
gem "unicode_plot"
|
|
10
|
-
gem "numo"
|
|
11
|
-
gem "matplotlib"
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
PATH
|
|
2
|
-
remote: ../..
|
|
3
|
-
specs:
|
|
4
|
-
rbbcc (0.2.0)
|
|
5
|
-
|
|
6
|
-
PATH
|
|
7
|
-
remote: /usr/local/ghq/github.com/udzura/charty
|
|
8
|
-
specs:
|
|
9
|
-
charty (0.2.2)
|
|
10
|
-
red-colors
|
|
11
|
-
|
|
12
|
-
GEM
|
|
13
|
-
remote: https://rubygems.org/
|
|
14
|
-
specs:
|
|
15
|
-
enumerable-statistics (2.0.1)
|
|
16
|
-
matplotlib (1.1.0)
|
|
17
|
-
pycall (>= 1.0.0)
|
|
18
|
-
numo (0.1.1)
|
|
19
|
-
numo-fftw (~> 0.1.1)
|
|
20
|
-
numo-gnuplot (~> 0.2.4)
|
|
21
|
-
numo-gsl (~> 0.1.1)
|
|
22
|
-
numo-linalg (~> 0.1.0)
|
|
23
|
-
numo-narray (~> 0.9.1)
|
|
24
|
-
numo-fftw (0.1.1)
|
|
25
|
-
numo-narray (~> 0.9.0)
|
|
26
|
-
numo-gnuplot (0.2.4)
|
|
27
|
-
numo-gsl (0.1.2)
|
|
28
|
-
numo-narray (>= 0.9.0.8)
|
|
29
|
-
numo-linalg (0.1.5)
|
|
30
|
-
numo-narray (>= 0.9.1.4)
|
|
31
|
-
numo-narray (0.9.1.6)
|
|
32
|
-
pycall (1.3.0)
|
|
33
|
-
red-colors (0.1.1)
|
|
34
|
-
unicode_plot (0.0.4)
|
|
35
|
-
enumerable-statistics (>= 2.0.1)
|
|
36
|
-
|
|
37
|
-
PLATFORMS
|
|
38
|
-
ruby
|
|
39
|
-
|
|
40
|
-
DEPENDENCIES
|
|
41
|
-
charty!
|
|
42
|
-
matplotlib
|
|
43
|
-
numo
|
|
44
|
-
rbbcc!
|
|
45
|
-
unicode_plot
|
|
46
|
-
|
|
47
|
-
BUNDLED WITH
|
|
48
|
-
2.0.2
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
#
|
|
3
|
-
# bitehist.rb, ported from bitehist.py. See license on that file
|
|
4
|
-
#
|
|
5
|
-
# Written as a basic example of using histograms to show a distribution.
|
|
6
|
-
#
|
|
7
|
-
# A Ctrl-C will print the gathered histogram then exit.
|
|
8
|
-
#
|
|
9
|
-
|
|
10
|
-
require 'rbbcc'
|
|
11
|
-
include RbBCC
|
|
12
|
-
|
|
13
|
-
b = BCC.new(text: <<CLANG)
|
|
14
|
-
#include <uapi/linux/ptrace.h>
|
|
15
|
-
#include <linux/blkdev.h>
|
|
16
|
-
|
|
17
|
-
BPF_HISTOGRAM(dist);
|
|
18
|
-
BPF_HISTOGRAM(dist_linear);
|
|
19
|
-
|
|
20
|
-
int kprobe__blk_account_io_completion(struct pt_regs *ctx, struct request *req)
|
|
21
|
-
{
|
|
22
|
-
dist.increment(bpf_log2l(req->__data_len / 1024));
|
|
23
|
-
dist_linear.increment(req->__data_len / 1024);
|
|
24
|
-
return 0;
|
|
25
|
-
}
|
|
26
|
-
CLANG
|
|
27
|
-
|
|
28
|
-
puts "Tracing... Hit Ctrl-C to end."
|
|
29
|
-
|
|
30
|
-
loop do
|
|
31
|
-
begin
|
|
32
|
-
sleep 0.1
|
|
33
|
-
rescue Interrupt
|
|
34
|
-
puts
|
|
35
|
-
break
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
require 'unicode_plot'
|
|
40
|
-
def log2hist_unicode(table)
|
|
41
|
-
strip_leading_zero = true
|
|
42
|
-
vals = Array.new($log2_index_max) { 0 }
|
|
43
|
-
data = {}
|
|
44
|
-
table.each_pair do |k, v|
|
|
45
|
-
vals[k.to_bcc_value] = v.to_bcc_value
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
log2_dist_max = 64
|
|
49
|
-
idx_max = -1
|
|
50
|
-
val_max = 0
|
|
51
|
-
|
|
52
|
-
vals.each_with_index do |v, i|
|
|
53
|
-
idx_max = i if v > 0
|
|
54
|
-
val_max = v if v > val_max
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
(1...(idx_max + 1)).each do |i|
|
|
58
|
-
low = (1 << i) >> 1
|
|
59
|
-
high = (1 << i)
|
|
60
|
-
if (low == high)
|
|
61
|
-
low -= 1
|
|
62
|
-
end
|
|
63
|
-
val = vals[i]
|
|
64
|
-
|
|
65
|
-
if strip_leading_zero
|
|
66
|
-
if val
|
|
67
|
-
data["[#{low}, #{high})"] = val
|
|
68
|
-
strip_leading_zero = false
|
|
69
|
-
end
|
|
70
|
-
else
|
|
71
|
-
data["[#{low}, #{high})"] = val
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
unless data.empty?
|
|
76
|
-
puts UnicodePlot.barplot(ylabel: "kbytes", data: data, title: "log2 histogram", color: :magenta).render
|
|
77
|
-
else
|
|
78
|
-
puts "No sample found."
|
|
79
|
-
end
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
log2hist_unicode b["dist"]
|
|
83
|
-
|
|
84
|
-
# puts
|
|
85
|
-
# puts "linear histogram"
|
|
86
|
-
# puts "~~~~~~~~~~~~~~~~"
|
|
87
|
-
# b["dist_linear"].print_linear_hist("kbytes")
|
data/examples/collectsyscall.rb
DELETED
|
@@ -1,182 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
#
|
|
3
|
-
# Example to use complecated structure in BPF Map key:
|
|
4
|
-
# This program collects and shows raw syscall usage summary.
|
|
5
|
-
#
|
|
6
|
-
# Usage:
|
|
7
|
-
# bundle exec ruby examples/collectsyscall.rb
|
|
8
|
-
#
|
|
9
|
-
# Output example:
|
|
10
|
-
# Collecting syscalls...
|
|
11
|
-
# ^C
|
|
12
|
-
# PID=1098(maybe: gmain) --->
|
|
13
|
-
# inotify_add_watch 4 0.019 ms
|
|
14
|
-
# poll 1 0.000 ms
|
|
15
|
-
#
|
|
16
|
-
# PID=1114(maybe: dbus-daemon) --->
|
|
17
|
-
# stat 12 0.021 ms
|
|
18
|
-
# openat 3 0.015 ms
|
|
19
|
-
# getdents 2 0.013 ms
|
|
20
|
-
# recvmsg 2 0.006 ms
|
|
21
|
-
# sendmsg 1 0.008 ms
|
|
22
|
-
# close 1 0.002 ms
|
|
23
|
-
# fstat 1 0.002 ms
|
|
24
|
-
# epoll_wait 1 0.000 ms
|
|
25
|
-
#
|
|
26
|
-
# PID=1175(maybe: memcached) --->
|
|
27
|
-
# epoll_wait 3 2012.455 ms
|
|
28
|
-
#
|
|
29
|
-
# PID=1213(maybe: redis-server) --->
|
|
30
|
-
# read 64 0.736 ms
|
|
31
|
-
# epoll_wait 32 3782.098 ms
|
|
32
|
-
# openat 32 1.149 ms
|
|
33
|
-
# getpid 32 0.074 ms
|
|
34
|
-
# close 32 0.045 ms
|
|
35
|
-
# ....
|
|
36
|
-
|
|
37
|
-
require 'rbbcc'
|
|
38
|
-
include RbBCC
|
|
39
|
-
|
|
40
|
-
$pid = nil
|
|
41
|
-
$comm = nil
|
|
42
|
-
|
|
43
|
-
if ARGV.size == 2 &&
|
|
44
|
-
ARGV[0] == '-p'
|
|
45
|
-
$pid = ARGV[1].to_i
|
|
46
|
-
elsif ARGV.size == 2 &&
|
|
47
|
-
ARGV[0] == '-c'
|
|
48
|
-
$comm = ARGV[1]
|
|
49
|
-
elsif ARGV[0] == '-h' ||
|
|
50
|
-
ARGV[0] == '--help'
|
|
51
|
-
$stderr.puts "Usage: #{$0} [-p PID]"
|
|
52
|
-
exit 1
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
SYSCALL_MAP = `ausyscall --dump`
|
|
56
|
-
.lines
|
|
57
|
-
.map{|l| l.chomp.split }
|
|
58
|
-
.each_with_object(Hash.new) {|(k, v), ha| ha[k.to_i] = v }
|
|
59
|
-
|
|
60
|
-
# if no ausyscall(8) then shows number itself
|
|
61
|
-
# it is included in auditd package (e.g. Ubuntu)
|
|
62
|
-
def to_name(nr)
|
|
63
|
-
SYSCALL_MAP[nr] || nr.to_s
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
prog = <<BPF
|
|
67
|
-
#include <uapi/linux/ptrace.h>
|
|
68
|
-
|
|
69
|
-
struct key_t {
|
|
70
|
-
u32 pid;
|
|
71
|
-
u64 syscall_nr;
|
|
72
|
-
};
|
|
73
|
-
struct leaf_t{
|
|
74
|
-
u64 count;
|
|
75
|
-
u64 elapsed_ns;
|
|
76
|
-
u64 enter_ns;
|
|
77
|
-
char comm[16];
|
|
78
|
-
};
|
|
79
|
-
BPF_HASH(store, struct key_t, struct leaf_t);
|
|
80
|
-
|
|
81
|
-
TRACEPOINT_PROBE(raw_syscalls, sys_enter) {
|
|
82
|
-
struct key_t key = {0};
|
|
83
|
-
struct leaf_t initial = {0}, *val_;
|
|
84
|
-
char comm[16];
|
|
85
|
-
|
|
86
|
-
// key.pid = bpf_get_current_pid_tgid();
|
|
87
|
-
key.pid = (bpf_get_current_pid_tgid() >> 32);
|
|
88
|
-
key.syscall_nr = args->id;
|
|
89
|
-
|
|
90
|
-
DO_FILTER_BY_PID
|
|
91
|
-
bpf_get_current_comm(&comm, sizeof(comm));
|
|
92
|
-
DO_FILTER_BY_COMM
|
|
93
|
-
|
|
94
|
-
val_ = store.lookup_or_try_init(&key, &initial);
|
|
95
|
-
if (val_) {
|
|
96
|
-
struct leaf_t val = *val_;
|
|
97
|
-
val.count++;
|
|
98
|
-
val.enter_ns = bpf_ktime_get_ns();
|
|
99
|
-
bpf_get_current_comm(&val.comm, sizeof(val.comm));
|
|
100
|
-
store.update(&key, &val);
|
|
101
|
-
}
|
|
102
|
-
return 0;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
TRACEPOINT_PROBE(raw_syscalls, sys_exit) {
|
|
106
|
-
struct key_t key = {0};
|
|
107
|
-
struct leaf_t *val_;
|
|
108
|
-
|
|
109
|
-
key.pid = (bpf_get_current_pid_tgid() >> 32);
|
|
110
|
-
key.syscall_nr = args->id;
|
|
111
|
-
|
|
112
|
-
val_ = store.lookup(&key);
|
|
113
|
-
if (val_) {
|
|
114
|
-
struct leaf_t val = *val_;
|
|
115
|
-
if(val.enter_ns) {
|
|
116
|
-
u64 delta = bpf_ktime_get_ns() - val.enter_ns;
|
|
117
|
-
val.enter_ns = 0;
|
|
118
|
-
val.elapsed_ns += delta;
|
|
119
|
-
}
|
|
120
|
-
store.update(&key, &val);
|
|
121
|
-
}
|
|
122
|
-
return 0;
|
|
123
|
-
}
|
|
124
|
-
BPF
|
|
125
|
-
|
|
126
|
-
if $pid
|
|
127
|
-
prog.sub!('DO_FILTER_BY_PID', <<~FILTER)
|
|
128
|
-
if (key.pid != #{$pid}) return 0;
|
|
129
|
-
FILTER
|
|
130
|
-
else
|
|
131
|
-
prog.sub!('DO_FILTER_BY_PID', '')
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
if $comm
|
|
135
|
-
prog.sub!('DO_FILTER_BY_COMM', <<~FILTER)
|
|
136
|
-
int idx;
|
|
137
|
-
int matched = 1;
|
|
138
|
-
char *needle = "#{$comm}";
|
|
139
|
-
for(idx=0;idx<sizeof(comm);++idx) {
|
|
140
|
-
if (comm[idx] != needle[idx]) matched = 0;
|
|
141
|
-
if (!needle[idx]) break;
|
|
142
|
-
if (!comm[idx]) break;
|
|
143
|
-
}
|
|
144
|
-
if(!matched) return 0;
|
|
145
|
-
FILTER
|
|
146
|
-
else
|
|
147
|
-
prog.sub!('DO_FILTER_BY_COMM', '')
|
|
148
|
-
end
|
|
149
|
-
|
|
150
|
-
b = BCC.new(text: prog)
|
|
151
|
-
|
|
152
|
-
puts "Collecting syscalls..."
|
|
153
|
-
begin
|
|
154
|
-
sleep(99999999)
|
|
155
|
-
rescue Interrupt
|
|
156
|
-
puts
|
|
157
|
-
end
|
|
158
|
-
|
|
159
|
-
info_by_pids = {}
|
|
160
|
-
comms = {}
|
|
161
|
-
store = b.get_table("store")
|
|
162
|
-
store.items.each do |k, v|
|
|
163
|
-
#require 'pry'; binding.pry
|
|
164
|
-
count, elapsed_ns, _dummy, comm = v[0, 40].unpack("Q Q Q Z16")
|
|
165
|
-
info_by_pids[k.pid] ||= {}
|
|
166
|
-
info_by_pids[k.pid][k.syscall_nr] = {
|
|
167
|
-
name: to_name(k.syscall_nr),
|
|
168
|
-
count: count,
|
|
169
|
-
elapsed_ms: elapsed_ns / 1000000.0
|
|
170
|
-
}
|
|
171
|
-
comms[k.pid] ||= comm
|
|
172
|
-
end
|
|
173
|
-
|
|
174
|
-
pids = info_by_pids.keys.sort
|
|
175
|
-
pids.each do |pid|
|
|
176
|
-
puts "PID=#{pid}(maybe: #{comms[pid]}) --->"
|
|
177
|
-
i = info_by_pids[pid]
|
|
178
|
-
i.to_a.sort_by {|k, v| [-v[:count], -v[:elapsed_ms]] }.each do |nr, record|
|
|
179
|
-
puts "\t%<name>-22s %<count>7d %<elapsed_ms>10.3f ms" % record
|
|
180
|
-
end
|
|
181
|
-
puts
|
|
182
|
-
end
|
data/examples/dddos.rb
DELETED
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
#
|
|
3
|
-
# dddos.rb DDOS dectection system, ported from python code.
|
|
4
|
-
#
|
|
5
|
-
# Written as a basic tracing example of using ePBF
|
|
6
|
-
# to detect a potential DDOS attack against a system.
|
|
7
|
-
#
|
|
8
|
-
# See Copyright and License on bcc project:
|
|
9
|
-
# examples/tracing/dddos.py
|
|
10
|
-
#
|
|
11
|
-
# 14-Jan-2019 Jugurtha BELKALEM Created dddos.py.
|
|
12
|
-
|
|
13
|
-
require 'rbbcc'
|
|
14
|
-
include RbBCC
|
|
15
|
-
|
|
16
|
-
prog = """
|
|
17
|
-
#include <linux/skbuff.h>
|
|
18
|
-
#include <uapi/linux/ip.h>
|
|
19
|
-
|
|
20
|
-
#define MAX_NB_PACKETS 1000
|
|
21
|
-
#define LEGAL_DIFF_TIMESTAMP_PACKETS 1000000
|
|
22
|
-
|
|
23
|
-
BPF_HASH(rcv_packets);
|
|
24
|
-
|
|
25
|
-
struct detectionPackets {
|
|
26
|
-
u64 nb_ddos_packets;
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
BPF_PERF_OUTPUT(events);
|
|
30
|
-
|
|
31
|
-
int detect_ddos(struct pt_regs *ctx, void *skb){
|
|
32
|
-
struct detectionPackets detectionPacket = {};
|
|
33
|
-
|
|
34
|
-
// Used to count number of received packets
|
|
35
|
-
u64 rcv_packets_nb_index = 0, rcv_packets_nb_inter=1, *rcv_packets_nb_ptr;
|
|
36
|
-
|
|
37
|
-
// Used to measure elapsed time between 2 successive received packets
|
|
38
|
-
u64 rcv_packets_ts_index = 1, rcv_packets_ts_inter=0, *rcv_packets_ts_ptr;
|
|
39
|
-
|
|
40
|
-
/* The algorithm analyses packets received by ip_rcv function
|
|
41
|
-
* and measures the difference in reception time between each packet.
|
|
42
|
-
* DDOS flooders send millions of packets such that difference of
|
|
43
|
-
* timestamp between 2 successive packets is so small
|
|
44
|
-
* (which is not like regular applications behaviour).
|
|
45
|
-
* This script looks for this difference in time and if it sees
|
|
46
|
-
* more than MAX_NB_PACKETS succesive packets with a difference
|
|
47
|
-
* of timestamp between each one of them less than
|
|
48
|
-
* LEGAL_DIFF_TIMESTAMP_PACKETS ns,
|
|
49
|
-
* ------------------ It Triggers an ALERT -----------------
|
|
50
|
-
* Those settings must be adapted depending on regular network traffic
|
|
51
|
-
* -------------------------------------------------------------------
|
|
52
|
-
* Important: this is a rudimentary intrusion detection system, one can
|
|
53
|
-
* test a real case attack using hping3. However; if regular network
|
|
54
|
-
* traffic increases above predefined detection settings, a false
|
|
55
|
-
* positive alert will be triggered (an example would be the
|
|
56
|
-
case of large file downloads).
|
|
57
|
-
*/
|
|
58
|
-
rcv_packets_nb_ptr = rcv_packets.lookup(&rcv_packets_nb_index);
|
|
59
|
-
rcv_packets_ts_ptr = rcv_packets.lookup(&rcv_packets_ts_index);
|
|
60
|
-
if(rcv_packets_nb_ptr != 0 && rcv_packets_ts_ptr != 0){
|
|
61
|
-
rcv_packets_nb_inter = *rcv_packets_nb_ptr;
|
|
62
|
-
rcv_packets_ts_inter = bpf_ktime_get_ns() - *rcv_packets_ts_ptr;
|
|
63
|
-
if(rcv_packets_ts_inter < LEGAL_DIFF_TIMESTAMP_PACKETS){
|
|
64
|
-
rcv_packets_nb_inter++;
|
|
65
|
-
} else {
|
|
66
|
-
rcv_packets_nb_inter = 0;
|
|
67
|
-
}
|
|
68
|
-
if(rcv_packets_nb_inter > MAX_NB_PACKETS){
|
|
69
|
-
detectionPacket.nb_ddos_packets = rcv_packets_nb_inter;
|
|
70
|
-
events.perf_submit(ctx, &detectionPacket, sizeof(detectionPacket));
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
rcv_packets_ts_inter = bpf_ktime_get_ns();
|
|
74
|
-
rcv_packets.update(&rcv_packets_nb_index, &rcv_packets_nb_inter);
|
|
75
|
-
rcv_packets.update(&rcv_packets_ts_index, &rcv_packets_ts_inter);
|
|
76
|
-
return 0;
|
|
77
|
-
}
|
|
78
|
-
"""
|
|
79
|
-
|
|
80
|
-
# Loads eBPF program
|
|
81
|
-
b = BCC.new(text: prog)
|
|
82
|
-
|
|
83
|
-
# Attach kprobe to kernel function and sets detect_ddos as kprobe handler
|
|
84
|
-
b.attach_kprobe(event: "ip_rcv", fn_name: "detect_ddos")
|
|
85
|
-
|
|
86
|
-
DetectionTimestamp = \
|
|
87
|
-
Fiddle::Importer.struct(["unsigned long long nb_ddos_packets"])
|
|
88
|
-
|
|
89
|
-
# Show message when ePBF stats
|
|
90
|
-
puts("DDOS detector started ... Hit Ctrl-C to end!")
|
|
91
|
-
|
|
92
|
-
puts("%-26s %-10s" % ["TIME(s)", "MESSAGE"])
|
|
93
|
-
|
|
94
|
-
trigger_alert_event = lambda { |cpu, data, size|
|
|
95
|
-
# data is raw Fiddle::Pointer instance
|
|
96
|
-
event = DetectionTimestamp.malloc
|
|
97
|
-
Fiddle::Pointer.new(event.to_ptr)[0, DetectionTimestamp.size] = data[0, DetectionTimestamp.size]
|
|
98
|
-
puts("%-26s %s %d" % [
|
|
99
|
-
Time.now,
|
|
100
|
-
"DDOS Attack => nb of packets up to now : ",
|
|
101
|
-
event.nb_ddos_packets])
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
# loop with callback to trigger_alert_event
|
|
105
|
-
b["events"].open_perf_buffer(&trigger_alert_event)
|
|
106
|
-
loop do
|
|
107
|
-
begin
|
|
108
|
-
b.perf_buffer_poll
|
|
109
|
-
rescue Interrupt
|
|
110
|
-
exit
|
|
111
|
-
end
|
|
112
|
-
end
|
data/examples/disksnoop.rb
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
#
|
|
3
|
-
# disksnoop.rb Trace block device I/O: basic version of iosnoop.
|
|
4
|
-
# For Linux, uses BCC, eBPF. Embedded C.
|
|
5
|
-
# This is ported from original disksnoop.py
|
|
6
|
-
#
|
|
7
|
-
# Written as a basic example of tracing latency.
|
|
8
|
-
#
|
|
9
|
-
# Licensed under the Apache License, Version 2.0 (the "License")
|
|
10
|
-
#
|
|
11
|
-
# 11-Aug-2015 Brendan Gregg Created disksnoop.py
|
|
12
|
-
|
|
13
|
-
require 'rbbcc'
|
|
14
|
-
include RbBCC
|
|
15
|
-
|
|
16
|
-
REQ_WRITE = 1 # from include/linux/blk_types.h
|
|
17
|
-
|
|
18
|
-
# load BPF program
|
|
19
|
-
b = BCC.new(text: <<CLANG)
|
|
20
|
-
#include <uapi/linux/ptrace.h>
|
|
21
|
-
#include <linux/blkdev.h>
|
|
22
|
-
|
|
23
|
-
BPF_HASH(start, struct request *);
|
|
24
|
-
|
|
25
|
-
void trace_start(struct pt_regs *ctx, struct request *req) {
|
|
26
|
-
// stash start timestamp by request ptr
|
|
27
|
-
u64 ts = bpf_ktime_get_ns();
|
|
28
|
-
|
|
29
|
-
start.update(&req, &ts);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
void trace_completion(struct pt_regs *ctx, struct request *req) {
|
|
33
|
-
u64 *tsp, delta;
|
|
34
|
-
|
|
35
|
-
tsp = start.lookup(&req);
|
|
36
|
-
if (tsp != 0) {
|
|
37
|
-
delta = bpf_ktime_get_ns() - *tsp;
|
|
38
|
-
bpf_trace_printk("%d %x %d\\n", req->__data_len,
|
|
39
|
-
req->cmd_flags, delta / 1000);
|
|
40
|
-
start.delete(&req);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
CLANG
|
|
44
|
-
|
|
45
|
-
if BCC.get_kprobe_functions('blk_start_request')
|
|
46
|
-
b.attach_kprobe(event: "blk_start_request", fn_name: "trace_start")
|
|
47
|
-
end
|
|
48
|
-
b.attach_kprobe(event: "blk_mq_start_request", fn_name: "trace_start")
|
|
49
|
-
b.attach_kprobe(event: "blk_account_io_completion", fn_name: "trace_completion")
|
|
50
|
-
|
|
51
|
-
# header
|
|
52
|
-
puts("%-18s %-2s %-7s %8s" % ["TIME(s)", "T", "BYTES", "LAT(ms)"])
|
|
53
|
-
|
|
54
|
-
# format output
|
|
55
|
-
loop do
|
|
56
|
-
begin
|
|
57
|
-
task, pid, cpu, flags, ts, msg = b.trace_fields
|
|
58
|
-
bytes_s, bflags_s, us_s = msg.split
|
|
59
|
-
|
|
60
|
-
if (bflags_s.to_i(16) & REQ_WRITE).nonzero?
|
|
61
|
-
type_s = "W"
|
|
62
|
-
elsif bytes_s == "0" # see blk_fill_rwbs() for logic
|
|
63
|
-
type_s = "M"
|
|
64
|
-
else
|
|
65
|
-
type_s = "R"
|
|
66
|
-
end
|
|
67
|
-
ms = us_s.to_i.to_f / 1000
|
|
68
|
-
|
|
69
|
-
puts("%-18.9f %-2s %-7s %8.2f" % [ts, type_s, bytes_s, ms])
|
|
70
|
-
rescue Interrupt
|
|
71
|
-
exit
|
|
72
|
-
end
|
|
73
|
-
end
|
data/examples/dns_blocker.rb
DELETED
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
#
|
|
3
|
-
# dns_blocker.rb Block DNS queries for a specified domain using TC/eBPF.
|
|
4
|
-
#
|
|
5
|
-
# Uses TC clsact qdisc and attaches a SCHED_CLS BPF program to the
|
|
6
|
-
# egress path. Because pyroute2 is unavailable in Ruby, the BPF
|
|
7
|
-
# program is pinned to /sys/fs/bpf and attached via the `tc` shell
|
|
8
|
-
# command.
|
|
9
|
-
#
|
|
10
|
-
# Usage (must be run as root):
|
|
11
|
-
# ruby dns_blocker.rb -i eth0 -d ruby-lang.org
|
|
12
|
-
#
|
|
13
|
-
|
|
14
|
-
require 'rbbcc'
|
|
15
|
-
require 'optparse'
|
|
16
|
-
|
|
17
|
-
include RbBCC
|
|
18
|
-
|
|
19
|
-
def domain_to_payload_check_code(domain)
|
|
20
|
-
# Convert a domain name to DNS wire format (length-prefixed labels)
|
|
21
|
-
# For example, "example.com" becomes "\\x07example\\x03com\\x00"
|
|
22
|
-
dns_expression = domain.split('.').map { |label| "#{label.length.chr}#{label}" }.join + "\x00"
|
|
23
|
-
c_check_code = dns_expression.chars.map.with_index { |c, i| "payload[offset+#{i}] == #{c.ord}" }.join(" &&\n ")
|
|
24
|
-
c_check_code
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
BPF_TEXT = ->(domain) {
|
|
28
|
-
<<~CLANG
|
|
29
|
-
// Some Hack :(
|
|
30
|
-
#define BPF_LOAD_ACQ -1
|
|
31
|
-
#define BPF_STORE_REL -2
|
|
32
|
-
|
|
33
|
-
#include <uapi/linux/bpf.h>
|
|
34
|
-
#include <uapi/linux/pkt_cls.h>
|
|
35
|
-
#include <linux/if_ether.h>
|
|
36
|
-
#include <linux/ip.h>
|
|
37
|
-
#include <linux/udp.h>
|
|
38
|
-
|
|
39
|
-
int block_dns(struct __sk_buff *skb) {
|
|
40
|
-
void *data = (void *)(long)skb->data;
|
|
41
|
-
void *data_end = (void *)(long)skb->data_end;
|
|
42
|
-
|
|
43
|
-
// Ethernet header check
|
|
44
|
-
struct ethhdr *eth = data;
|
|
45
|
-
if ((void *)(eth + 1) > data_end) return TC_ACT_OK;
|
|
46
|
-
if (eth->h_proto != bpf_htons(ETH_P_IP)) return TC_ACT_OK;
|
|
47
|
-
|
|
48
|
-
// IP header check
|
|
49
|
-
struct iphdr *ip = (void *)(eth + 1);
|
|
50
|
-
if ((void *)(ip + 1) > data_end) return TC_ACT_OK;
|
|
51
|
-
if (ip->protocol != IPPROTO_UDP) return TC_ACT_OK;
|
|
52
|
-
|
|
53
|
-
// UDP header check
|
|
54
|
-
struct udphdr *udp = (void *)ip + (ip->ihl * 4);
|
|
55
|
-
if ((void *)(udp + 1) > data_end) return TC_ACT_OK;
|
|
56
|
-
|
|
57
|
-
// Only care about port 53 (DNS) egress queries
|
|
58
|
-
if (udp->dest != bpf_htons(53)) return TC_ACT_OK;
|
|
59
|
-
|
|
60
|
-
// DNS payload boundary check: DNS header (12 bytes) + "example.com" wire format (13 bytes)
|
|
61
|
-
unsigned char *payload = (unsigned char *)(udp + 1);
|
|
62
|
-
if ((void *)(payload + 12 + 13) > data_end) return TC_ACT_OK;
|
|
63
|
-
|
|
64
|
-
// "example.com" in DNS wire format: \\x07example\\x03com\\x00
|
|
65
|
-
int offset = 12;
|
|
66
|
-
if (#{domain_to_payload_check_code(domain)}) {
|
|
67
|
-
bpf_trace_printk("Blocked DNS query for #{domain}\\n");
|
|
68
|
-
return TC_ACT_SHOT;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return TC_ACT_OK;
|
|
72
|
-
}
|
|
73
|
-
CLANG
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
PIN_PATH = "/sys/fs/bpf/dns_blocker_prog"
|
|
77
|
-
|
|
78
|
-
def setup_tc(interface)
|
|
79
|
-
# Run idempotently
|
|
80
|
-
system("sudo tc qdisc add dev #{interface} clsact 2>/dev/null")
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
def attach_tc(interface)
|
|
84
|
-
system(
|
|
85
|
-
"sudo tc filter add dev #{interface} egress" +
|
|
86
|
-
" bpf pinned #{PIN_PATH} da",
|
|
87
|
-
exception: true
|
|
88
|
-
)
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
def cleanup_tc(interface)
|
|
92
|
-
# Run idempotently
|
|
93
|
-
system("sudo tc qdisc del dev #{interface} clsact 2>/dev/null")
|
|
94
|
-
File.unlink(PIN_PATH) if File.exist?(PIN_PATH)
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
options = {domain: "example.com"}
|
|
98
|
-
OptionParser.new { |opts|
|
|
99
|
-
opts.banner = "Usage: #{$0} -i INTERFACE"
|
|
100
|
-
opts.on("-i", "--interface IFACE", "Network interface to monitor (e.g. eth0)") do |v|
|
|
101
|
-
options[:interface] = v
|
|
102
|
-
end
|
|
103
|
-
opts.on("-d", "--domain DOMAIN", "Domain to block (default: example.com)") do |v|
|
|
104
|
-
options[:domain] = v
|
|
105
|
-
end
|
|
106
|
-
}.parse!
|
|
107
|
-
|
|
108
|
-
iface = options[:interface] || abort("Error: Interface name is required")
|
|
109
|
-
|
|
110
|
-
# Clean up any leftover state from a previous run
|
|
111
|
-
cleanup_tc(iface)
|
|
112
|
-
|
|
113
|
-
puts "[*] Compiling BPF program..."
|
|
114
|
-
b = BCC.new(text: BPF_TEXT.call(options[:domain]))
|
|
115
|
-
fn = b.load_func("block_dns", BPF::SCHED_CLS)
|
|
116
|
-
|
|
117
|
-
# Pin the loaded BPF program so that `tc` can reference it by path
|
|
118
|
-
puts "[*] Pinning BPF program to #{PIN_PATH} ..."
|
|
119
|
-
BCC.pin!(fn, PIN_PATH)
|
|
120
|
-
|
|
121
|
-
# Set up clsact qdisc and attach the pinned program to egress
|
|
122
|
-
puts "[*] Attaching TC filter to #{iface} (egress) ..."
|
|
123
|
-
setup_tc(iface)
|
|
124
|
-
attach_tc(iface)
|
|
125
|
-
|
|
126
|
-
puts "[*] Blocking DNS queries for #{options[:domain]} on #{iface}. Press Ctrl+C to stop."
|
|
127
|
-
begin
|
|
128
|
-
b.trace_print
|
|
129
|
-
rescue Interrupt
|
|
130
|
-
puts "\n[*] Shutting down..."
|
|
131
|
-
ensure
|
|
132
|
-
cleanup_tc(iface)
|
|
133
|
-
puts "[*] Cleanup done."
|
|
134
|
-
end
|
data/examples/example.gif
DELETED
|
Binary file
|