rbbcc 0.11.6 → 0.11.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/lib/rbbcc/table.rb +8 -7
  4. data/lib/rbbcc/version.rb +1 -1
  5. data/rbbcc.gemspec +5 -2
  6. metadata +2 -62
  7. data/docs/README.md +0 -7
  8. data/docs/answers/01-hello-world.rb +0 -16
  9. data/docs/answers/02-sys_sync.rb +0 -18
  10. data/docs/answers/03-hello_fields.rb +0 -33
  11. data/docs/answers/04-sync_timing.rb +0 -46
  12. data/docs/answers/05-sync_count.rb +0 -54
  13. data/docs/answers/06-disksnoop.rb +0 -71
  14. data/docs/answers/07-hello_perf_output.rb +0 -59
  15. data/docs/answers/08-sync_perf_output.rb +0 -60
  16. data/docs/answers/09-bitehist.rb +0 -32
  17. data/docs/answers/10-disklatency.rb +0 -51
  18. data/docs/answers/11-vfsreadlat.c +0 -46
  19. data/docs/answers/11-vfsreadlat.rb +0 -66
  20. data/docs/answers/12-urandomread.rb +0 -38
  21. data/docs/answers/13-disksnoop_fixed.rb +0 -108
  22. data/docs/answers/14-strlen_count.rb +0 -46
  23. data/docs/answers/15-nodejs_http_server.rb +0 -44
  24. data/docs/answers/16-task_switch.c +0 -23
  25. data/docs/answers/16-task_switch.rb +0 -17
  26. data/docs/answers/node-server.js +0 -11
  27. data/docs/getting_started.md +0 -154
  28. data/docs/projects_using_rbbcc.md +0 -43
  29. data/docs/tutorial_bcc_ruby_developer.md +0 -774
  30. data/docs/tutorial_bcc_ruby_developer_japanese.md +0 -770
  31. data/examples/bitehist.rb +0 -46
  32. data/examples/charty/Gemfile +0 -11
  33. data/examples/charty/Gemfile.lock +0 -48
  34. data/examples/charty/bitehist-unicode.rb +0 -87
  35. data/examples/collectsyscall.rb +0 -182
  36. data/examples/dddos.rb +0 -112
  37. data/examples/disksnoop.rb +0 -73
  38. data/examples/dns_blocker.rb +0 -134
  39. data/examples/example.gif +0 -0
  40. data/examples/extract_arg.rb +0 -26
  41. data/examples/hello_fields.rb +0 -32
  42. data/examples/hello_perf_output.rb +0 -64
  43. data/examples/hello_ring_buffer.rb +0 -64
  44. data/examples/hello_world.rb +0 -6
  45. data/examples/kvm_hypercall.rb +0 -69
  46. data/examples/lsm_sockblock.rb +0 -141
  47. data/examples/mallocstack.rb +0 -63
  48. data/examples/networking/http_filter/http-parse-simple.c +0 -114
  49. data/examples/networking/http_filter/http-parse-simple.rb +0 -85
  50. data/examples/pin_maps_a.rb +0 -88
  51. data/examples/pin_maps_b.rb +0 -71
  52. data/examples/py-orig/sockblock.py +0 -119
  53. data/examples/ringbuf_pin_a.rb +0 -51
  54. data/examples/ringbuf_pin_b.rb +0 -29
  55. data/examples/ruby_usdt.rb +0 -105
  56. data/examples/sbrk_trace.rb +0 -204
  57. data/examples/ssl_http_trace.rb +0 -274
  58. data/examples/syscalluname.rb +0 -39
  59. data/examples/table.rb +0 -15
  60. data/examples/tools/bashreadline.rb +0 -83
  61. data/examples/tools/execsnoop.rb +0 -229
  62. data/examples/tools/runqlat.rb +0 -148
  63. data/examples/urandomread-explicit.rb +0 -58
  64. data/examples/urandomread.rb +0 -39
  65. data/examples/usdt-test.rb +0 -6
  66. data/examples/usdt.rb +0 -26
@@ -1,26 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'rbbcc'
4
- include RbBCC
5
-
6
- code = <<CLANG
7
- #include <uapi/linux/ptrace.h>
8
- #define ARGSIZE 128
9
-
10
- // must be syscall__${the_name} ?
11
- int syscall__execve(struct pt_regs *ctx,
12
- const char __user *filename,
13
- const char __user *const __user *__argv,
14
- const char __user *const __user *__envp)
15
- {
16
- char buf[ARGSIZE] = {};
17
- bpf_probe_read(buf, sizeof(buf), (void *)filename);
18
- bpf_trace_printk("execve: %s\\n", &buf);
19
-
20
- return 0;
21
- }
22
- CLANG
23
-
24
- b = BCC.new(text: code)
25
- b.attach_kprobe(event: b.get_syscall_fnname("execve"), fn_name: "syscall__execve")
26
- b.trace_print
@@ -1,32 +0,0 @@
1
- #!/usr/bin/env ruby
2
- #
3
- # This is a Hello World example that formats output as fields.
4
-
5
- require 'rbbcc'
6
- include RbBCC
7
-
8
- # define BPF program
9
- prog = <<CLANG
10
- int hello(void *ctx) {
11
- bpf_trace_printk("Hello, World!\\n");
12
- return 0;
13
- }
14
- CLANG
15
-
16
- # load BPF program
17
- b = BCC.new(text: prog)
18
- b.attach_kprobe(event: b.get_syscall_fnname("clone"), fn_name: "hello")
19
-
20
- # header
21
- puts("%-18s %-16s %-6s %s" % ["TIME(s)", "COMM", "PID", "MESSAGE"])
22
-
23
- # format output
24
- loop do
25
- begin
26
- b.trace_fields do |task, pid, cpu, flags, ts, msg|
27
- puts("%-18.9f %-16s %-6d %s" % [ts, task, pid, msg])
28
- end
29
- rescue Interrupt
30
- exit
31
- end
32
- end
@@ -1,64 +0,0 @@
1
- #!/usr/bin/env ruby
2
- #
3
- # This is a Hello World example that uses BPF_PERF_OUTPUT.
4
- # Ported from hello_perf_output.py
5
-
6
- require 'rbbcc'
7
- include RbBCC
8
-
9
- # define BPF program
10
- prog = """
11
- #include <linux/sched.h>
12
-
13
- // define output data structure in C
14
- struct data_t {
15
- u32 pid;
16
- u64 ts;
17
- char comm[TASK_COMM_LEN];
18
- };
19
- BPF_PERF_OUTPUT(events);
20
-
21
- int hello(struct pt_regs *ctx) {
22
- struct data_t data = {};
23
-
24
- data.pid = bpf_get_current_pid_tgid();
25
- data.ts = bpf_ktime_get_ns();
26
- bpf_get_current_comm(&data.comm, sizeof(data.comm));
27
-
28
- events.perf_submit(ctx, &data, sizeof(data));
29
-
30
- return 0;
31
- }
32
- """
33
-
34
- # load BPF program
35
- b = BCC.new(text: prog)
36
- b.attach_kprobe(event: b.get_syscall_fnname("clone"), fn_name: "hello")
37
-
38
- # header
39
- puts("%-18s %-16s %-6s %s" % ["TIME(s)", "COMM", "PID", "MESSAGE"])
40
-
41
- # process event
42
- start = 0
43
- print_event = lambda { |cpu, data, size|
44
- event = b["events"].event(data)
45
- if start == 0
46
- start = event.ts
47
- end
48
-
49
- time_s = ((event.ts - start).to_f) / 1000000000
50
- # event.comm.pack("c*").sprit
51
- puts("%-18.9f %-16s %-6d %s" % [time_s, event.comm, event.pid,
52
- "Hello, perf_output!"])
53
- }
54
-
55
- # loop with callback to print_event
56
- b["events"].open_perf_buffer(&print_event)
57
-
58
- loop do
59
- begin
60
- b.perf_buffer_poll()
61
- rescue Interrupt
62
- exit()
63
- end
64
- end
@@ -1,64 +0,0 @@
1
- #!/usr/bin/env ruby
2
- #
3
- # This is a Hello World example that uses BPF_PERF_OUTPUT.
4
- # Ported from hello_perf_output.py
5
-
6
- require 'rbbcc'
7
- include RbBCC
8
-
9
- # define BPF program
10
- prog = """
11
- #include <linux/sched.h>
12
-
13
- struct data_t {
14
- u32 pid;
15
- u64 ts;
16
- char comm[TASK_COMM_LEN];
17
- };
18
- BPF_RINGBUF_OUTPUT(buffer, 1 << 4);
19
-
20
- int hello(struct pt_regs *ctx) {
21
- struct data_t data = {};
22
-
23
- data.pid = bpf_get_current_pid_tgid();
24
- data.ts = bpf_ktime_get_ns();
25
- bpf_get_current_comm(&data.comm, sizeof(data.comm));
26
-
27
- buffer.ringbuf_output(&data, sizeof(data), 0);
28
-
29
- return 0;
30
- }
31
- """
32
-
33
- # load BPF program
34
- b = BCC.new(text: prog)
35
- b.attach_kprobe(event: b.get_syscall_fnname("clone"), fn_name: "hello")
36
-
37
- # header
38
- puts("%-18s %-16s %-6s %s" % ["TIME(s)", "COMM", "PID", "MESSAGE"])
39
-
40
- # process event
41
- start = 0
42
- print_event = lambda { |ctx, data, size|
43
- event = b["buffer"].event(data)
44
- if start == 0
45
- start = event.ts
46
- end
47
-
48
- time_s = ((event.ts - start).to_f) / 1000000000
49
- # event.comm.pack("c*").sprit
50
- puts("%-18.9f %-16s %-6d %s" % [time_s, event.comm, event.pid,
51
- "Hello, ringbuf!"])
52
- }
53
-
54
- # loop with callback to print_event
55
- b["buffer"].open_ring_buffer(&print_event)
56
-
57
- loop do
58
- begin
59
- b.ring_buffer_poll()
60
- sleep(0.5)
61
- rescue Interrupt
62
- exit()
63
- end
64
- end
@@ -1,6 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'rbbcc'
4
- include RbBCC
5
-
6
- BCC.new(text: 'int kprobe__sys_clone(void *ctx) { bpf_trace_printk("Hello, World!\\n"); return 0; }').trace_print
@@ -1,69 +0,0 @@
1
- #!/usr/bin/python
2
- #
3
- # kvm_hypercall.rb - TODO: it is still not tested
4
- # See original kvm_hypercall.py and txt
5
- #
6
- # Demonstrates stateful kvm_entry and kvm_exit recording along with the
7
- # associated hypercall when exit_reason is VMCALL. See kvm_hypercall.txt
8
- # for usage
9
- #
10
- # REQUIRES: Linux 4.7+ (BPF_PROG_TYPE_TRACEPOINT support)
11
- #
12
- # Copyright (c) 2017 ShiftLeft Inc.
13
- #
14
- # Author(s):
15
- # Suchakrapani Sharma <suchakra@shiftleft.io>
16
-
17
- require 'rbbcc'
18
- include RbBCC
19
-
20
- # load BPF program
21
- b = BCC.new(text: <<CLANG)
22
- #define EXIT_REASON 18
23
- BPF_HASH(start, u8, u8);
24
-
25
- TRACEPOINT_PROBE(kvm, kvm_exit) {
26
- u8 e = EXIT_REASON;
27
- u8 one = 1;
28
- if (args->exit_reason == EXIT_REASON) {
29
- bpf_trace_printk("KVM_EXIT exit_reason : %d\\n", args->exit_reason);
30
- start.update(&e, &one);
31
- }
32
- return 0;
33
- }
34
-
35
- TRACEPOINT_PROBE(kvm, kvm_entry) {
36
- u8 e = EXIT_REASON;
37
- u8 zero = 0;
38
- u8 *s = start.lookup(&e);
39
- if (s != NULL && *s == 1) {
40
- bpf_trace_printk("KVM_ENTRY vcpu_id : %u\\n", args->vcpu_id);
41
- start.update(&e, &zero);
42
- }
43
- return 0;
44
- }
45
-
46
- TRACEPOINT_PROBE(kvm, kvm_hypercall) {
47
- u8 e = EXIT_REASON;
48
- u8 zero = 0;
49
- u8 *s = start.lookup(&e);
50
- if (s != NULL && *s == 1) {
51
- bpf_trace_printk("HYPERCALL nr : %d\\n", args->nr);
52
- }
53
- return 0;
54
- };
55
- CLANG
56
-
57
- # header
58
- puts("%-18s %-16s %-6s %s" % ["TIME(s)", "COMM", "PID", "EVENT"])
59
-
60
- # format output
61
- loop do
62
- begin
63
- b.trace_fields do |task, pid, cpu, flags, ts, msg|
64
- puts("%-18.9f %-16s %-6d %s" % [ts, task, pid, msg])
65
- end
66
- rescue Interrupt
67
- exit
68
- end
69
- end
@@ -1,141 +0,0 @@
1
- #!/usr/bin/env ruby
2
- #
3
- # lsm_sockblock.rb Monitor/block AF_ALG socket_create via BPF LSM.
4
- #
5
- # This example uses LSM_PROBE(socket_create) and a BPF_ARRAY map for mode:
6
- # 0 = preview (log only)
7
- # 1 = block (return -EPERM)
8
- #
9
- # The config map is pinned to bpffs so mode can be changed externally.
10
- #
11
- # Usage:
12
- # sudo ruby examples/lsm_sockblock.rb
13
- # sudo ruby examples/lsm_sockblock.rb --mode block
14
- # sudo ruby examples/lsm_sockblock.rb --pin-path /sys/fs/bpf/my_config_map
15
-
16
- require 'optparse'
17
- require 'socket'
18
- require 'rbbcc'
19
-
20
- include RbBCC
21
-
22
- PROGRAM = <<~CLANG
23
- #include <linux/socket.h>
24
- #include <uapi/asm-generic/errno-base.h>
25
-
26
- struct data_t {
27
- u32 pid;
28
- int family;
29
- int type;
30
- int is_warning;
31
- int is_blocked;
32
- char comm[16];
33
- };
34
-
35
- BPF_PERF_OUTPUT(events);
36
- BPF_ARRAY(config_map, u32, 1);
37
-
38
- LSM_PROBE(socket_create, int family, int type, int protocol, int kern)
39
- {
40
- u32 pid = bpf_get_current_pid_tgid() >> 32;
41
- struct data_t data = {};
42
-
43
- u32 key = 0;
44
- u32 *mode = config_map.lookup(&key);
45
- int is_block_mode = (mode && *mode == 1);
46
-
47
- data.pid = pid;
48
- data.family = family;
49
- data.type = type;
50
- bpf_get_current_comm(&data.comm, sizeof(data.comm));
51
-
52
- if (family == AF_ALG) {
53
- data.is_blocked = is_block_mode;
54
- data.is_warning = 1;
55
- events.perf_submit(ctx, &data, sizeof(data));
56
-
57
- if (is_block_mode) {
58
- return -EPERM;
59
- }
60
- } else {
61
- data.is_blocked = 0;
62
- data.is_warning = 0;
63
- events.perf_submit(ctx, &data, sizeof(data));
64
- }
65
-
66
- return 0;
67
- }
68
- CLANG
69
-
70
- options = {
71
- mode: "preview",
72
- pin_path: "/sys/fs/bpf/rbbcc_lsm_config_map"
73
- }
74
-
75
- OptionParser.new do |opts|
76
- opts.banner = "Usage: #{$0} [--mode preview|block] [--pin-path PATH]"
77
-
78
- opts.on("--mode MODE", ["preview", "block"], "Operation mode (default: preview)") do |v|
79
- options[:mode] = v
80
- end
81
-
82
- opts.on("--pin-path PATH", "bpffs pin path (default: /sys/fs/bpf/rbbcc_lsm_config_map)") do |v|
83
- options[:pin_path] = v
84
- end
85
- end.parse!
86
-
87
- mode_value = (options[:mode] == "block") ? 1 : 0
88
-
89
- families = Socket.constants.grep(/^AF_/).each_with_object({}) do |name, h|
90
- begin
91
- v = Socket.const_get(name)
92
- h[v] = name.to_s if v.is_a?(Integer)
93
- rescue NameError
94
- next
95
- end
96
- end
97
-
98
- types = Socket.constants.grep(/^SOCK_/).each_with_object({}) do |name, h|
99
- begin
100
- v = Socket.const_get(name)
101
- h[v] = name.to_s if v.is_a?(Integer)
102
- rescue NameError
103
- next
104
- end
105
- end
106
-
107
- begin
108
- b = BCC.new(text: PROGRAM)
109
-
110
- config = b["config_map"]
111
- config[0] = mode_value
112
-
113
- File.unlink(options[:pin_path]) if File.exist?(options[:pin_path])
114
- BCC.pin!(config.map_fd, options[:pin_path])
115
-
116
- puts "LSM BPF started in #{options[:mode].upcase} mode."
117
- puts "Pinned config map: #{options[:pin_path]}"
118
- puts "Tracing AF_ALG socket_create... Press Ctrl-C to exit."
119
-
120
- b["events"].open_perf_buffer do |cpu, data, size|
121
- event = b["events"].event(data)
122
- family = families.fetch(event.family, "AF_UNKNOWN(#{event.family})")
123
- stype = types.fetch(event.type, "SOCK_UNKNOWN(#{event.type})")
124
-
125
- puts "PID: #{event.pid.to_s.ljust(7)} | COMM: #{event.comm.to_s.ljust(15)} | FAMILY: #{family.ljust(14)} | TYPE: #{stype}"
126
-
127
- next if event.is_warning == 0
128
-
129
- mode_str = (event.is_blocked == 1) ? "BLOCK" : "PREVIEW"
130
- status = (event.is_blocked == 1) ? "REJECTED" : "WARNING"
131
- puts "\e[1;31m[#{mode_str}] #{status}: PID #{event.pid} (#{event.comm}) tried AF_ALG socket creation.\e[0m"
132
- end
133
-
134
- loop do
135
- b.perf_buffer_poll
136
- end
137
- rescue Interrupt
138
- puts "\nStopping..."
139
- ensure
140
- File.unlink(options[:pin_path]) if File.exist?(options[:pin_path])
141
- end
@@ -1,63 +0,0 @@
1
- #!/usr/bin/env ruby
2
- #
3
- # mallocstacks Trace malloc() calls in a process and print the full
4
- # stack trace for all callsites.
5
- # For Linux, uses BCC, eBPF. Embedded C.
6
- #
7
- # This script is a basic example of the new Linux 4.6+ BPF_STACK_TRACE
8
- # table API.
9
- #
10
- # Copyright 2016 GitHub, Inc.
11
- # Licensed under the Apache License, Version 2.0 (the "License")
12
-
13
- require 'rbbcc'
14
- include RbBCC
15
-
16
- if ARGV.size == 0
17
- $stderr.puts("USAGE: mallocstacks PID")
18
- exit
19
- end
20
- pid = ARGV[0].to_i
21
-
22
- # load BPF program
23
- b = BCC.new(text: <<CLANG)
24
- #include <uapi/linux/ptrace.h>
25
-
26
- BPF_HASH(calls, int);
27
- BPF_STACK_TRACE(stack_traces, 1024);
28
-
29
- int alloc_enter(struct pt_regs *ctx, size_t size) {
30
- int key = stack_traces.get_stackid(ctx,
31
- BPF_F_USER_STACK|BPF_F_REUSE_STACKID);
32
- if (key < 0)
33
- return 0;
34
-
35
- // could also use `calls.increment(key, size);`
36
- u64 zero = 0, *val;
37
- val = calls.lookup_or_init(&key, &zero);
38
- if (val)
39
- (*val) += size;
40
- return 0;
41
- };
42
- CLANG
43
-
44
- b.attach_uprobe(name: "c", sym: "malloc", fn_name: "alloc_enter", pid: pid)
45
- puts("Attaching to malloc in pid %d, Ctrl+C to quit." % pid)
46
-
47
- # sleep until Ctrl-C
48
- loop do
49
- begin
50
- sleep 1
51
- rescue Interrupt
52
- break # pass
53
- end
54
- end
55
- calls = b.get_table("calls")
56
- stack_traces = b.get_table("stack_traces")
57
-
58
- calls.items.sort_by{|k, v| v.to_bcc_value }.reverse.each do |(k, v)|
59
- puts("%d bytes allocated at:" % v.to_bcc_value)
60
- stack_traces.walk(k) do |addr|
61
- puts("\t%s" % BCC.sym(addr, pid, show_offset: true))
62
- end
63
- end
@@ -1,114 +0,0 @@
1
- #include <uapi/linux/ptrace.h>
2
- #include <net/sock.h>
3
- #include <bcc/proto.h>
4
-
5
- #define IP_TCP 6
6
- #define ETH_HLEN 14
7
-
8
- /*eBPF program.
9
- Filter IP and TCP packets, having payload not empty
10
- and containing "HTTP", "GET", "POST" ... as first bytes of payload
11
- if the program is loaded as PROG_TYPE_SOCKET_FILTER
12
- and attached to a socket
13
- return 0 -> DROP the packet
14
- return -1 -> KEEP the packet and return it to user space (userspace can read it from the socket_fd )
15
- */
16
- int http_filter(struct __sk_buff *skb) {
17
-
18
- u8 *cursor = 0;
19
-
20
- struct ethernet_t *ethernet = cursor_advance(cursor, sizeof(*ethernet));
21
- //filter IP packets (ethernet type = 0x0800)
22
- if (!(ethernet->type == 0x0800)) {
23
- goto DROP;
24
- }
25
-
26
- struct ip_t *ip = cursor_advance(cursor, sizeof(*ip));
27
- //filter TCP packets (ip next protocol = 0x06)
28
- if (ip->nextp != IP_TCP) {
29
- goto DROP;
30
- }
31
-
32
- u32 tcp_header_length = 0;
33
- u32 ip_header_length = 0;
34
- u32 payload_offset = 0;
35
- u32 payload_length = 0;
36
-
37
- //calculate ip header length
38
- //value to multiply * 4
39
- //e.g. ip->hlen = 5 ; IP Header Length = 5 x 4 byte = 20 byte
40
- ip_header_length = ip->hlen << 2; //SHL 2 -> *4 multiply
41
-
42
- //check ip header length against minimum
43
- if (ip_header_length < sizeof(*ip)) {
44
- goto DROP;
45
- }
46
-
47
- //shift cursor forward for dynamic ip header size
48
- void *_ = cursor_advance(cursor, (ip_header_length-sizeof(*ip)));
49
-
50
- struct tcp_t *tcp = cursor_advance(cursor, sizeof(*tcp));
51
-
52
- //calculate tcp header length
53
- //value to multiply *4
54
- //e.g. tcp->offset = 5 ; TCP Header Length = 5 x 4 byte = 20 byte
55
- tcp_header_length = tcp->offset << 2; //SHL 2 -> *4 multiply
56
-
57
- //calculate payload offset and length
58
- payload_offset = ETH_HLEN + ip_header_length + tcp_header_length;
59
- payload_length = ip->tlen - ip_header_length - tcp_header_length;
60
-
61
- //http://stackoverflow.com/questions/25047905/http-request-minimum-size-in-bytes
62
- //minimum length of http request is always geater than 7 bytes
63
- //avoid invalid access memory
64
- //include empty payload
65
- if(payload_length < 7) {
66
- goto DROP;
67
- }
68
-
69
- //load first 7 byte of payload into p (payload_array)
70
- //direct access to skb not allowed
71
- unsigned long p[7];
72
- int i = 0;
73
- for (i = 0; i < 7; i++) {
74
- p[i] = load_byte(skb , payload_offset + i);
75
- }
76
-
77
- //find a match with an HTTP message
78
- //HTTP
79
- if ((p[0] == 'H') && (p[1] == 'T') && (p[2] == 'T') && (p[3] == 'P')) {
80
- goto KEEP;
81
- }
82
- //GET
83
- if ((p[0] == 'G') && (p[1] == 'E') && (p[2] == 'T')) {
84
- goto KEEP;
85
- }
86
- //POST
87
- if ((p[0] == 'P') && (p[1] == 'O') && (p[2] == 'S') && (p[3] == 'T')) {
88
- goto KEEP;
89
- }
90
- //PUT
91
- if ((p[0] == 'P') && (p[1] == 'U') && (p[2] == 'T')) {
92
- goto KEEP;
93
- }
94
- //DELETE
95
- if ((p[0] == 'D') && (p[1] == 'E') && (p[2] == 'L') && (p[3] == 'E') && (p[4] == 'T') && (p[5] == 'E')) {
96
- goto KEEP;
97
- }
98
- //HEAD
99
- if ((p[0] == 'H') && (p[1] == 'E') && (p[2] == 'A') && (p[3] == 'D')) {
100
- goto KEEP;
101
- }
102
-
103
- //no HTTP match
104
- goto DROP;
105
-
106
- //keep the packet and send it to userspace retruning -1
107
- KEEP:
108
- return -1;
109
-
110
- //drop the packet returning 0
111
- DROP:
112
- return 0;
113
-
114
- }
@@ -1,85 +0,0 @@
1
- #!/usr/bin/env ruby
2
- #
3
- #Original http-parse-simple.py in invisor/bcc
4
- #Bertrone Matteo - Polytechnic of Turin
5
- #November 2015
6
- #Ruby version by Uchio Kondo, License follows
7
- #
8
- #eBPF application that parses HTTP packets
9
- #and extracts (and prints on screen) the URL contained in the GET/POST request.
10
- #
11
- #eBPF program http_filter is used as SOCKET_FILTER attached to eth0 interface.
12
- #only packet of type ip and tcp containing HTTP GET/POST are returned to userspace, others dropped
13
- #
14
- #python script uses bcc BPF Compiler Collection by iovisor (https://github.com/iovisor/bcc)
15
- #and prints on stdout the first line of the HTTP GET/POST request containing the url
16
-
17
- require 'rbbcc'
18
- require 'socket'
19
- require 'io/nonblock'
20
- include RbBCC
21
-
22
- def usage
23
- puts <<-USAGE
24
- USAGE: #{$0} [-i <if_name>]
25
- USAGE
26
- exit
27
- end
28
-
29
- interface = "eth0"
30
-
31
- if ARGV.size == 2
32
- if ARGV[0] == '-i'
33
- interface = ARGV[1]
34
- else
35
- usage
36
- end
37
- elsif ARGV.size != 0
38
- usage
39
- end
40
-
41
- puts("binding socket to '%s'" % interface)
42
-
43
- bpf = BCC.new(src_file: "http-parse-simple.c")
44
-
45
- function_http_filter = bpf.load_func("http_filter", BPF::SOCKET_FILTER)
46
-
47
- BCC.attach_raw_socket(function_http_filter, interface)
48
-
49
- socket_fd = function_http_filter[:sock]
50
-
51
- sock = Socket.for_fd socket_fd
52
- sock.nonblock = false
53
-
54
- ETH_HLEN = 14
55
- loop do
56
- packet_str = sock.sysread(2048)
57
- packet_bytearray = packet_str.bytes
58
-
59
- # See original comment...
60
- #calculate packet total length
61
- total_length = packet_bytearray[ETH_HLEN + 2] #load MSB
62
- total_length = total_length << 8 #shift MSB
63
- total_length = total_length + packet_bytearray[ETH_HLEN + 3] #add LSB
64
-
65
- #calculate ip header length
66
- ip_header_length = packet_bytearray[ETH_HLEN] #load Byte
67
- ip_header_length = ip_header_length & 0x0F #mask bits 0..3
68
- ip_header_length = ip_header_length << 2 #shift to obtain length
69
-
70
- tcp_header_length = packet_bytearray[ETH_HLEN + ip_header_length + 12] #load Byte
71
- tcp_header_length = tcp_header_length & 0xF0 #mask bit 4..7
72
- tcp_header_length = tcp_header_length >> 2 #SHR 4 ; SHL 2 -> SHR 2
73
-
74
- payload_offset = ETH_HLEN + ip_header_length + tcp_header_length
75
-
76
- ((payload_offset-1)..(packet_bytearray.size-1)).each do |i|
77
- if packet_bytearray[i] == 0x0A
78
- if packet_bytearray[i-1] == 0x0D
79
- break
80
- end
81
- end
82
- print(packet_bytearray[i].chr)
83
- end
84
- puts
85
- end