inspektor-gadget

Форк
0
230 строк · 6.0 Кб
1
// SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
2

3
/* Copyright (c) 2021 The Inspektor Gadget authors */
4

5
/*
6
 * Inspired by the BPF selftests in the Linux tree:
7
 * https://github.com/torvalds/linux/blob/v5.13/tools/testing/selftests/bpf/progs/bpf_iter_tcp4.c
8
 */
9

10
/*
11
 * This BPF program uses the GPL-restricted function bpf_seq_printf().
12
 */
13

14
#include <vmlinux.h>
15

16
#include <bpf/bpf_helpers.h>
17
#include <bpf/bpf_endian.h>
18

19
#define AF_INET 2
20
#define AF_INET6 10
21

22
#define IPV6_LEN 16
23

24
#define sk_v6_daddr __sk_common.skc_v6_daddr
25
#define sk_v6_rcv_saddr __sk_common.skc_v6_rcv_saddr
26

27
#define inet_daddr sk.__sk_common.skc_daddr
28
#define inet_rcv_saddr sk.__sk_common.skc_rcv_saddr
29
#define inet_dport sk.__sk_common.skc_dport
30

31
#define ir_loc_addr req.__req_common.skc_rcv_saddr
32
#define ir_num req.__req_common.skc_num
33
#define ir_rmt_addr req.__req_common.skc_daddr
34
#define ir_rmt_port req.__req_common.skc_dport
35
#define ir_v6_loc_addr req.__req_common.skc_v6_rcv_saddr
36
#define ir_v6_rmt_addr req.__req_common.skc_v6_daddr
37
#define ireq_family req.__req_common.skc_family
38

39
#define sk_family __sk_common.skc_family
40
#define sk_state __sk_common.skc_state
41
#define sk_proto __sk_common.sk_protocol
42

43
#define tw_daddr __tw_common.skc_daddr
44
#define tw_rcv_saddr __tw_common.skc_rcv_saddr
45
#define tw_dport __tw_common.skc_dport
46
#define tw_v6_daddr __tw_common.skc_v6_daddr
47
#define tw_v6_rcv_saddr __tw_common.skc_v6_rcv_saddr
48
#define tw_family __tw_common.skc_family
49

50
struct entry {
51
	__u8 daddr[IPV6_LEN];
52
	__u8 saddr[IPV6_LEN];
53
	__u16 dport;
54
	__u16 sport;
55
	__u16 proto; // IP protocol
56
	__u16 family;
57
	__u8 state;
58
	__u64 inode;
59
};
60

61
// we need this to make sure the compiler doesn't remove our struct
62
const struct entry *unused __attribute__((unused));
63

64
/**
65
 * sock_i_ino - Returns the inode identifier associated to a socket.
66
 * @sk: The socket whom inode identifier will be returned.
67
 *
68
 * Returns the inode identifier corresponding to the given as parameter socket.
69
 *
70
 * Returns:
71
 * * The inode identifier associated to the socket.
72
 */
73
static unsigned long sock_i_ino(const struct sock *sk)
74
{
75
	const struct socket *sk_socket = sk->sk_socket;
76
	const struct inode *inode;
77
	unsigned long ino;
78

79
	if (!sk_socket)
80
		return 0;
81

82
	inode = &container_of(sk_socket, struct socket_alloc, socket)->vfs_inode;
83
	bpf_probe_read_kernel(&ino, sizeof(ino), &inode->i_ino);
84
	return ino;
85
}
86

87
/*
88
 * This function receives arguments as they are stored
89
 * in the different socket structure, i.e. network-byte order.
90
 */
91
static __always_inline void
92
socket_bpf_seq_write(struct seq_file *seq, __u16 family, __u16 proto,
93
		     __be32 src_v4, struct in6_addr *src_v6, __u16 srcp,
94
		     __be32 dest_v4, struct in6_addr *dest_v6, __u16 destp,
95
		     __u8 state, __u64 ino)
96
{
97
	struct entry entry = {};
98

99
	switch (family) {
100
	case AF_INET:
101
		*((__u32 *)entry.saddr) = src_v4;
102
		*((__u32 *)entry.daddr) = dest_v4;
103

104
		break;
105
	case AF_INET6:
106
		bpf_probe_read_kernel(&entry.daddr, sizeof(entry.daddr),
107
				      dest_v6);
108
		bpf_probe_read_kernel(&entry.saddr, sizeof(entry.saddr),
109
				      src_v6);
110

111
		break;
112
	default:
113
		return;
114
	}
115

116
	entry.dport = bpf_ntohs(destp);
117
	entry.sport = bpf_ntohs(srcp);
118
	entry.proto = proto;
119
	entry.family = family;
120
	entry.state = state;
121
	entry.inode = ino;
122

123
	bpf_seq_write(seq, &entry, sizeof(entry));
124
}
125

126
char _license[] SEC("license") = "GPL";
127

128
static int dump_tcp_sock(struct seq_file *seq, struct tcp_sock *tp)
129
{
130
	struct inet_connection_sock *icsk = &tp->inet_conn;
131
	struct inet_sock *inet = &icsk->icsk_inet;
132
	struct sock *sp = &inet->sk;
133

134
	socket_bpf_seq_write(seq, sp->sk_family, IPPROTO_TCP,
135
			     inet->inet_rcv_saddr, &sp->sk_v6_rcv_saddr,
136
			     inet->inet_sport, inet->inet_daddr,
137
			     &sp->sk_v6_daddr, inet->inet_dport, sp->sk_state,
138
			     sock_i_ino(sp));
139

140
	return 0;
141
}
142

143
static int dump_tw_sock(struct seq_file *seq, struct tcp_timewait_sock *ttw)
144
{
145
	struct inet_timewait_sock *tw = &ttw->tw_sk;
146

147
	/*
148
	 * tcp_timewait_sock represents socket in TIME_WAIT state.
149
	 * Socket is this particular state are not associated with a
150
	 * struct sock:
151
	 * https://elixir.bootlin.com/linux/v5.15.12/source/include/linux/tcp.h#L442
152
	 * https://elixir.bootlin.com/linux/v5.15.12/source/include/net/inet_timewait_sock.h#L33
153
	 * Hence, they do not have an underlying file and, as a
154
	 * consequence, no inode.
155
	 *
156
	 * Like /proc/net/tcp, we print 0 as inode number for TIME_WAIT
157
	 * (state 6) socket:
158
	 * https://elixir.bootlin.com/linux/v5.15.12/source/include/net/tcp_states.h#L18
159
	 */
160

161
	socket_bpf_seq_write(seq, tw->tw_family, IPPROTO_TCP, tw->tw_rcv_saddr,
162
			     &tw->tw_v6_rcv_saddr, tw->tw_sport, tw->tw_daddr,
163
			     &tw->tw_v6_daddr, tw->tw_dport, tw->tw_substate,
164
			     0);
165

166
	return 0;
167
}
168

169
static int dump_req_sock(struct seq_file *seq, struct tcp_request_sock *treq)
170
{
171
	struct inet_request_sock *irsk = &treq->req;
172

173
	socket_bpf_seq_write(seq, irsk->ireq_family, IPPROTO_TCP,
174
			     irsk->ir_loc_addr, &irsk->ir_v6_loc_addr,
175
			     irsk->ir_num, irsk->ir_rmt_addr,
176
			     &irsk->ir_v6_rmt_addr, irsk->ir_rmt_port,
177
			     TCP_SYN_RECV, sock_i_ino(treq->req.req.sk));
178

179
	return 0;
180
}
181

182
SEC("iter/tcp")
183
int ig_snap_tcp(struct bpf_iter__tcp *ctx)
184
{
185
	struct sock_common *sk_common = ctx->sk_common;
186
	struct seq_file *seq = ctx->meta->seq;
187
	struct tcp_timewait_sock *tw;
188
	struct tcp_request_sock *req;
189
	struct tcp_sock *tp;
190

191
	if (sk_common == (void *)0)
192
		return 0;
193

194
	tp = bpf_skc_to_tcp_sock(sk_common);
195
	if (tp)
196
		return dump_tcp_sock(seq, tp);
197

198
	tw = bpf_skc_to_tcp_timewait_sock(sk_common);
199
	if (tw)
200
		return dump_tw_sock(seq, tw);
201

202
	req = bpf_skc_to_tcp_request_sock(sk_common);
203
	if (req)
204
		return dump_req_sock(seq, req);
205

206
	return 0;
207
}
208

209
SEC("iter/udp")
210
int ig_snap_udp(struct bpf_iter__udp *ctx)
211
{
212
	struct seq_file *seq = ctx->meta->seq;
213
	struct udp_sock *udp_sk = ctx->udp_sk;
214
	struct inet_sock *inet;
215
	struct sock *sp;
216

217
	if (udp_sk == (void *)0)
218
		return 0;
219

220
	inet = &udp_sk->inet;
221
	sp = &inet->sk;
222

223
	socket_bpf_seq_write(seq, sp->sk_family, IPPROTO_UDP,
224
			     inet->inet_rcv_saddr, &sp->sk_v6_rcv_saddr,
225
			     inet->inet_sport, inet->inet_daddr,
226
			     &sp->sk_v6_daddr, inet->inet_dport, sp->sk_state,
227
			     sock_i_ino(sp));
228

229
	return 0;
230
}
231

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.