rbbcc 0.10.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +2 -1
- data/examples/dns_blocker.rb +134 -0
- data/examples/lsm_sockblock.rb +142 -0
- data/examples/py-orig/sockblock.py +119 -0
- data/lib/rbbcc/bcc.rb +21 -2
- data/lib/rbbcc/clib.rb +1 -0
- data/lib/rbbcc/consts.rb +3 -0
- data/lib/rbbcc/version.rb +1 -1
- metadata +4 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0cafb82823139848b9c16a2182ef4ba3c86c391126700ee6cbb31ab0a427da85
|
|
4
|
+
data.tar.gz: 711be4b7c0bf09879445d02b7bf0379b9c51dc186f56129227c416a0515e00ff
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 007c4273121411d6548b071fe48fda59c36af94a36c7de183a8fbacceba722c837115af8a2892ec79277957217b5152b58ec12ce4dd56c153293a2ac6fae9894
|
|
7
|
+
data.tar.gz: 94da55a1738a534d0bffc95ac2ebabcb431e5ea98785506a0006e1d249b83d602f8bbcaec47890124afbf42a9a11f394f986b9795b194db0acb101a8d536ca26
|
data/Gemfile.lock
CHANGED
|
@@ -0,0 +1,134 @@
|
|
|
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
|
|
@@ -0,0 +1,142 @@
|
|
|
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/lsm_hooks.h>
|
|
24
|
+
#include <linux/socket.h>
|
|
25
|
+
#include <uapi/asm-generic/errno-base.h>
|
|
26
|
+
|
|
27
|
+
struct data_t {
|
|
28
|
+
u32 pid;
|
|
29
|
+
int family;
|
|
30
|
+
int type;
|
|
31
|
+
int is_warning;
|
|
32
|
+
int is_blocked;
|
|
33
|
+
char comm[16];
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
BPF_PERF_OUTPUT(events);
|
|
37
|
+
BPF_ARRAY(config_map, u32, 1);
|
|
38
|
+
|
|
39
|
+
LSM_PROBE(socket_create, int family, int type, int protocol, int kern)
|
|
40
|
+
{
|
|
41
|
+
u32 pid = bpf_get_current_pid_tgid() >> 32;
|
|
42
|
+
struct data_t data = {};
|
|
43
|
+
|
|
44
|
+
u32 key = 0;
|
|
45
|
+
u32 *mode = config_map.lookup(&key);
|
|
46
|
+
int is_block_mode = (mode && *mode == 1);
|
|
47
|
+
|
|
48
|
+
data.pid = pid;
|
|
49
|
+
data.family = family;
|
|
50
|
+
data.type = type;
|
|
51
|
+
bpf_get_current_comm(&data.comm, sizeof(data.comm));
|
|
52
|
+
|
|
53
|
+
if (family == AF_ALG) {
|
|
54
|
+
data.is_blocked = is_block_mode;
|
|
55
|
+
data.is_warning = 1;
|
|
56
|
+
events.perf_submit(ctx, &data, sizeof(data));
|
|
57
|
+
|
|
58
|
+
if (is_block_mode) {
|
|
59
|
+
return -EPERM;
|
|
60
|
+
}
|
|
61
|
+
} else {
|
|
62
|
+
data.is_blocked = 0;
|
|
63
|
+
data.is_warning = 0;
|
|
64
|
+
events.perf_submit(ctx, &data, sizeof(data));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return 0;
|
|
68
|
+
}
|
|
69
|
+
CLANG
|
|
70
|
+
|
|
71
|
+
options = {
|
|
72
|
+
mode: "preview",
|
|
73
|
+
pin_path: "/sys/fs/bpf/rbbcc_lsm_config_map"
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
OptionParser.new do |opts|
|
|
77
|
+
opts.banner = "Usage: #{$0} [--mode preview|block] [--pin-path PATH]"
|
|
78
|
+
|
|
79
|
+
opts.on("--mode MODE", ["preview", "block"], "Operation mode (default: preview)") do |v|
|
|
80
|
+
options[:mode] = v
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
opts.on("--pin-path PATH", "bpffs pin path (default: /sys/fs/bpf/rbbcc_lsm_config_map)") do |v|
|
|
84
|
+
options[:pin_path] = v
|
|
85
|
+
end
|
|
86
|
+
end.parse!
|
|
87
|
+
|
|
88
|
+
mode_value = (options[:mode] == "block") ? 1 : 0
|
|
89
|
+
|
|
90
|
+
families = Socket.constants.grep(/^AF_/).each_with_object({}) do |name, h|
|
|
91
|
+
begin
|
|
92
|
+
v = Socket.const_get(name)
|
|
93
|
+
h[v] = name.to_s if v.is_a?(Integer)
|
|
94
|
+
rescue NameError
|
|
95
|
+
next
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
types = Socket.constants.grep(/^SOCK_/).each_with_object({}) do |name, h|
|
|
100
|
+
begin
|
|
101
|
+
v = Socket.const_get(name)
|
|
102
|
+
h[v] = name.to_s if v.is_a?(Integer)
|
|
103
|
+
rescue NameError
|
|
104
|
+
next
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
begin
|
|
109
|
+
b = BCC.new(text: PROGRAM)
|
|
110
|
+
|
|
111
|
+
config = b["config_map"]
|
|
112
|
+
config[0] = mode_value
|
|
113
|
+
|
|
114
|
+
File.unlink(options[:pin_path]) if File.exist?(options[:pin_path])
|
|
115
|
+
BCC.pin!(config.map_fd, options[:pin_path])
|
|
116
|
+
|
|
117
|
+
puts "LSM BPF started in #{options[:mode].upcase} mode."
|
|
118
|
+
puts "Pinned config map: #{options[:pin_path]}"
|
|
119
|
+
puts "Tracing AF_ALG socket_create... Press Ctrl-C to exit."
|
|
120
|
+
|
|
121
|
+
b["events"].open_perf_buffer do |cpu, data, size|
|
|
122
|
+
event = b["events"].event(data)
|
|
123
|
+
family = families.fetch(event.family, "AF_UNKNOWN(#{event.family})")
|
|
124
|
+
stype = types.fetch(event.type, "SOCK_UNKNOWN(#{event.type})")
|
|
125
|
+
|
|
126
|
+
puts "PID: #{event.pid.to_s.ljust(7)} | COMM: #{event.comm.to_s.ljust(15)} | FAMILY: #{family.ljust(14)} | TYPE: #{stype}"
|
|
127
|
+
|
|
128
|
+
next if event.is_warning == 0
|
|
129
|
+
|
|
130
|
+
mode_str = (event.is_blocked == 1) ? "BLOCK" : "PREVIEW"
|
|
131
|
+
status = (event.is_blocked == 1) ? "REJECTED" : "WARNING"
|
|
132
|
+
puts "\e[1;31m[#{mode_str}] #{status}: PID #{event.pid} (#{event.comm}) tried AF_ALG socket creation.\e[0m"
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
loop do
|
|
136
|
+
b.perf_buffer_poll
|
|
137
|
+
end
|
|
138
|
+
rescue Interrupt
|
|
139
|
+
puts "\nStopping..."
|
|
140
|
+
ensure
|
|
141
|
+
File.unlink(options[:pin_path]) if File.exist?(options[:pin_path])
|
|
142
|
+
end
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
from bcc import BPF, lib
|
|
2
|
+
import socket
|
|
3
|
+
import ctypes
|
|
4
|
+
import os
|
|
5
|
+
|
|
6
|
+
# 1. C言語側のプログラム
|
|
7
|
+
program = r"""
|
|
8
|
+
#include <linux/lsm_hooks.h>
|
|
9
|
+
#include <linux/socket.h>
|
|
10
|
+
#include <uapi/asm-generic/errno-base.h>
|
|
11
|
+
|
|
12
|
+
struct data_t {
|
|
13
|
+
u32 pid;
|
|
14
|
+
int family;
|
|
15
|
+
int type;
|
|
16
|
+
int is_warning;
|
|
17
|
+
int is_blocked;
|
|
18
|
+
char comm[16];
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
BPF_PERF_OUTPUT(events);
|
|
22
|
+
|
|
23
|
+
// モード保存用マップ (Index 0 を使用)
|
|
24
|
+
// 1: blockモード, 0: previewモード
|
|
25
|
+
BPF_ARRAY(config_map, u32, 1);
|
|
26
|
+
|
|
27
|
+
LSM_PROBE(socket_create, int family, int type, int protocol, int kern)
|
|
28
|
+
{
|
|
29
|
+
u32 pid = bpf_get_current_pid_tgid() >> 32;
|
|
30
|
+
struct data_t data = {};
|
|
31
|
+
|
|
32
|
+
// マップから現在のモードを取得
|
|
33
|
+
u32 key = 0;
|
|
34
|
+
u32 *mode = config_map.lookup(&key);
|
|
35
|
+
int is_block_mode = (mode && *mode == 1);
|
|
36
|
+
|
|
37
|
+
data.pid = pid;
|
|
38
|
+
data.family = family;
|
|
39
|
+
data.type = type;
|
|
40
|
+
bpf_get_current_comm(&data.comm, sizeof(data.comm));
|
|
41
|
+
|
|
42
|
+
if (family == AF_ALG) {
|
|
43
|
+
data.is_blocked = is_block_mode;
|
|
44
|
+
data.is_warning = 1;
|
|
45
|
+
|
|
46
|
+
// ログデータを送信
|
|
47
|
+
events.perf_submit(ctx, &data, sizeof(data));
|
|
48
|
+
|
|
49
|
+
// blockモードならエラーを返してシステムコールを失敗させる
|
|
50
|
+
if (is_block_mode) {
|
|
51
|
+
return -EPERM; // -1 (Operation not permitted)
|
|
52
|
+
}
|
|
53
|
+
} else {
|
|
54
|
+
data.is_blocked = 0;
|
|
55
|
+
data.is_warning = 0;
|
|
56
|
+
|
|
57
|
+
// ログデータを送信
|
|
58
|
+
events.perf_submit(ctx, &data, sizeof(data));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return 0;
|
|
62
|
+
}
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
# 定数解決用
|
|
66
|
+
families = {getattr(socket, n): n for n in dir(socket) if n.startswith('AF_')}
|
|
67
|
+
types = {getattr(socket, n): n for n in dir(socket) if n.startswith('SOCK_')}
|
|
68
|
+
|
|
69
|
+
def print_event(cpu, data, size):
|
|
70
|
+
event = b["events"].event(data)
|
|
71
|
+
|
|
72
|
+
family_str = families.get(event.family, f"AF_UNKNOWN({event.family})")
|
|
73
|
+
type_str = types.get(event.type, f"SOCK_UNKNOWN({event.type})")
|
|
74
|
+
|
|
75
|
+
print(f"PID: {event.pid:<7} | COMM: {event.comm.decode('utf-8'):<15} | "
|
|
76
|
+
f"FAMILY: {family_str:<12} | TYPE: {type_str}")
|
|
77
|
+
|
|
78
|
+
if event.is_warning:
|
|
79
|
+
mode_str = "BLOCK" if event.is_blocked else "PREVIEW"
|
|
80
|
+
status = "!! REJECTED !!" if event.is_blocked else "WARNING"
|
|
81
|
+
|
|
82
|
+
print(f"[{mode_str}] {status}: PID {event.pid} ({event.comm.decode()}) "
|
|
83
|
+
f"tried to create AF_ALG socket.")
|
|
84
|
+
|
|
85
|
+
# 2. ロードと設定
|
|
86
|
+
try:
|
|
87
|
+
b = BPF(text=program)
|
|
88
|
+
|
|
89
|
+
# --- モード設定 ---
|
|
90
|
+
# 1 を書き込むと blockモード、0 だと previewモード
|
|
91
|
+
mode = 0
|
|
92
|
+
config_table = b.get_table("config_map")
|
|
93
|
+
config_table[ctypes.c_uint32(0)] = ctypes.c_uint32(mode)
|
|
94
|
+
|
|
95
|
+
# Mapの永続化 - ユーザ空間からモードを変更できるようにするため
|
|
96
|
+
map_path = "/sys/fs/bpf/my_config_map"
|
|
97
|
+
if os.path.exists(map_path):
|
|
98
|
+
os.remove(map_path)
|
|
99
|
+
print(f"Pinning config map to -> {map_path}")
|
|
100
|
+
map_fd = config_table.get_fd()
|
|
101
|
+
res = lib.bpf_obj_pin(map_fd, ctypes.c_char_p(map_path.encode()))
|
|
102
|
+
if res != 0:
|
|
103
|
+
raise Exception(f"Failed to pin map to {map_path}: {os.strerror(-res)}")
|
|
104
|
+
|
|
105
|
+
# -----------------
|
|
106
|
+
|
|
107
|
+
print(f"LSM BPF started in {'BLOCK' if mode == 1 else 'PREVIEW'} mode.")
|
|
108
|
+
print("Tracing AF_ALG creation... Press Ctrl-C to exit.")
|
|
109
|
+
|
|
110
|
+
b["events"].open_perf_buffer(print_event)
|
|
111
|
+
|
|
112
|
+
while True:
|
|
113
|
+
try:
|
|
114
|
+
b.perf_buffer_poll()
|
|
115
|
+
except KeyboardInterrupt:
|
|
116
|
+
exit()
|
|
117
|
+
|
|
118
|
+
except Exception as e:
|
|
119
|
+
print(f"Failed: {e}")
|
data/lib/rbbcc/bcc.rb
CHANGED
|
@@ -180,7 +180,7 @@ module RbBCC
|
|
|
180
180
|
end
|
|
181
181
|
orig_name = c.inspect
|
|
182
182
|
c.define_singleton_method :inspect do
|
|
183
|
-
orig_name.sub
|
|
183
|
+
orig_name.sub(/(?=>$)/, " original_desc=#{desc.inspect}") rescue super
|
|
184
184
|
end
|
|
185
185
|
c
|
|
186
186
|
end
|
|
@@ -218,6 +218,23 @@ module RbBCC
|
|
|
218
218
|
fn[:sock] = sock
|
|
219
219
|
fn
|
|
220
220
|
end
|
|
221
|
+
|
|
222
|
+
#: (Integer | Hash[Symbol, untyped] fd, String path) -> String
|
|
223
|
+
def pin!(fd, path)
|
|
224
|
+
fd = fd[:fd] if fd.is_a?(Hash)
|
|
225
|
+
unless fd.is_a?(Integer) && fd >= 0
|
|
226
|
+
raise ArgumentError, "fd must exist and be a non-negative Integer"
|
|
227
|
+
end
|
|
228
|
+
unless path.is_a?(String) && !path.empty?
|
|
229
|
+
raise ArgumentError, "path must be a non-empty String"
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
res = Clib.bpf_obj_pin(fd, path)
|
|
233
|
+
if res < 0
|
|
234
|
+
raise SystemCallError.new("Failed to pin BPF object to %s" % path, Fiddle.last_error)
|
|
235
|
+
end
|
|
236
|
+
path
|
|
237
|
+
end
|
|
221
238
|
end
|
|
222
239
|
|
|
223
240
|
def initialize(text: "", src_file: nil, hdr_file: nil, debug: 0, cflags: [], usdt_contexts: [], allow_rlimit: 0, dev_name: nil)
|
|
@@ -279,7 +296,6 @@ module RbBCC
|
|
|
279
296
|
|
|
280
297
|
def gen_args_from_usdt
|
|
281
298
|
ptr = Clib.bcc_usdt_genargs(@usdt_contexts.map(&:context).pack('J*'), @usdt_contexts.size)
|
|
282
|
-
code = ""
|
|
283
299
|
if !ptr || ptr.null?
|
|
284
300
|
return nil
|
|
285
301
|
end
|
|
@@ -627,6 +643,9 @@ module RbBCC
|
|
|
627
643
|
tp: tp,
|
|
628
644
|
fn_name: fn[:name]
|
|
629
645
|
)
|
|
646
|
+
elsif func_name.start_with?("lsm__")
|
|
647
|
+
# LSM_PROBE programs are attached by libbcc while loading.
|
|
648
|
+
load_func(func_name, BPF::LSM)
|
|
630
649
|
end
|
|
631
650
|
end
|
|
632
651
|
end
|
data/lib/rbbcc/clib.rb
CHANGED
data/lib/rbbcc/consts.rb
CHANGED
data/lib/rbbcc/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rbbcc
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.11.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Uchio Kondo
|
|
@@ -84,6 +84,7 @@ files:
|
|
|
84
84
|
- examples/collectsyscall.rb
|
|
85
85
|
- examples/dddos.rb
|
|
86
86
|
- examples/disksnoop.rb
|
|
87
|
+
- examples/dns_blocker.rb
|
|
87
88
|
- examples/example.gif
|
|
88
89
|
- examples/extract_arg.rb
|
|
89
90
|
- examples/hello_fields.rb
|
|
@@ -91,9 +92,11 @@ files:
|
|
|
91
92
|
- examples/hello_ring_buffer.rb
|
|
92
93
|
- examples/hello_world.rb
|
|
93
94
|
- examples/kvm_hypercall.rb
|
|
95
|
+
- examples/lsm_sockblock.rb
|
|
94
96
|
- examples/mallocstack.rb
|
|
95
97
|
- examples/networking/http_filter/http-parse-simple.c
|
|
96
98
|
- examples/networking/http_filter/http-parse-simple.rb
|
|
99
|
+
- examples/py-orig/sockblock.py
|
|
97
100
|
- examples/ruby_usdt.rb
|
|
98
101
|
- examples/sbrk_trace.rb
|
|
99
102
|
- examples/syscalluname.rb
|