inspektor-gadget

Форк
0
199 строк · 5.9 Кб
1
// SPDX-License-Identifier: GPL-2.0
2
/* Copyright (c) 2021-2022 The Inspektor Gadget authors */
3
/* Copyright (c) 2021-2022 SAP SE or an SAP affiliate company and Gardener contributors */
4

5
#include <linux/bpf.h>
6
#include <linux/if_ether.h>
7
#include <linux/ip.h>
8
#include <linux/in.h>
9
#include <linux/tcp.h>
10

11
#include <bpf/bpf_helpers.h>
12
#include <bpf/bpf_endian.h>
13

14
#define GADGET_TYPE_NETWORKING
15
#include <gadget/sockets-map.h>
16

17
#include "snisnoop.h"
18

19
// we need this to make sure the compiler doesn't remove our struct
20
const struct event_t *unusedevent __attribute__((unused));
21

22
struct {
23
	__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
24
} events SEC(".maps");
25

26
// parse_sni() from:
27
// https://github.com/gardener/connectivity-monitor/blob/4e924f50367c9fa02075b50b0ecd8c821b3a15f1/connectivity-exporter/packet/c/cap.c#L146-L149
28

29
// Parses the provided SKB at the given offset for SNI information. If parsing
30
// succeeds, the SNI information is written to the out array. Returns the
31
// number of characters in the SNI field or 0 if SNI couldn't be parsed.
32
static __always_inline int parse_sni(struct __sk_buff *skb, int data_offset,
33
				     char *out)
34
{
35
	// Verify TLS content type.
36
	__u8 content_type;
37
	bpf_skb_load_bytes(skb, data_offset, &content_type, 1);
38
	if (content_type != TLS_CONTENT_TYPE_HANDSHAKE)
39
		return 0;
40

41
	// Verify TLS handshake type.
42
	__u8 handshake_type;
43
	bpf_skb_load_bytes(skb, data_offset + TLS_HANDSHAKE_TYPE_OFF,
44
			   &handshake_type, 1);
45
	if (handshake_type != TLS_HANDSHAKE_TYPE_CLIENT_HELLO)
46
		return 0;
47

48
	int session_id_len_off = data_offset + TLS_SESSION_ID_LENGTH_OFF;
49
	__u8 session_id_len;
50
	bpf_skb_load_bytes(skb, session_id_len_off, &session_id_len, 1);
51

52
	int cipher_suites_len_off =
53
		session_id_len_off + TLS_SESSION_ID_LENGTH_LEN + session_id_len;
54
	__u16 cipher_suites_len_be;
55
	bpf_skb_load_bytes(skb, cipher_suites_len_off, &cipher_suites_len_be,
56
			   2);
57

58
	int compression_methods_len_off = cipher_suites_len_off +
59
					  TLS_CIPHER_SUITES_LENGTH_LEN +
60
					  bpf_ntohs(cipher_suites_len_be);
61

62
	__u8 compression_methods_len;
63
	bpf_skb_load_bytes(skb, compression_methods_len_off,
64
			   &compression_methods_len, 1);
65

66
	int extensions_len_off = compression_methods_len_off +
67
				 TLS_COMPRESSION_METHODS_LENGTH_LEN +
68
				 compression_methods_len;
69

70
	int extensions_off = extensions_len_off + TLS_EXTENSIONS_LENGTH_LEN;
71

72
	// TODO: Ensure the cursor doesn't surpass the extensions length value?
73
	__u16 cur = 0;
74
	__u16 server_name_ext_off = 0;
75
	for (int i = 0; i < TLS_MAX_EXTENSION_COUNT; i++) {
76
		__u16 curr_ext_type_be;
77
		bpf_skb_load_bytes(skb, extensions_off + cur, &curr_ext_type_be,
78
				   2);
79
		if (bpf_ntohs(curr_ext_type_be) == TLS_EXTENSION_SERVER_NAME) {
80
			server_name_ext_off = extensions_off + cur;
81
			break;
82
		}
83
		// Skip the extension type field to get to the extension length field.
84
		cur += TLS_EXTENSION_TYPE_LEN;
85

86
		// Read the extension length and skip the extension length field as well as
87
		// the rest of the extension to get to the next extension.
88
		__u16 len_be;
89
		bpf_skb_load_bytes(skb, extensions_off + cur, &len_be, 2);
90
		cur += TLS_EXTENSION_LENGTH_LEN + bpf_ntohs(len_be);
91
	}
92

93
	if (server_name_ext_off == 0) // Couldn't find server name extension.
94
		return 0;
95

96
	__u16 server_name_len_be;
97
	bpf_skb_load_bytes(skb,
98
			   server_name_ext_off + TLS_SERVER_NAME_LENGTH_OFF,
99
			   &server_name_len_be, 2);
100
	__u16 server_name_len = bpf_ntohs(server_name_len_be);
101
	if (server_name_len == 0 || server_name_len > TLS_MAX_SERVER_NAME_LEN)
102
		return 0;
103

104
	// The server name field under the server name extension.
105
	__u16 server_name_off = server_name_ext_off + TLS_SERVER_NAME_OFF;
106

107
	// Read the server name field.
108
	int counter = 0;
109
	for (int i = 0; i < TLS_MAX_SERVER_NAME_LEN; i++) {
110
		if (!out)
111
			break;
112
		if (i >= server_name_len)
113
			break;
114
		char b;
115
		bpf_skb_load_bytes(skb, server_name_off + i, &b, 1);
116
		if (b == '\0')
117
			break;
118
		out[i] = b;
119
		counter++;
120
	}
121
	return counter;
122
}
123

124
SEC("socket1")
125
int ig_trace_sni(struct __sk_buff *skb)
126
{
127
	// Skip frames with non-IP Ethernet protocol.
128
	struct ethhdr ethh;
129
	if (bpf_skb_load_bytes(skb, 0, &ethh, sizeof ethh))
130
		return 0;
131
	if (bpf_ntohs(ethh.h_proto) != ETH_P_IP)
132
		return 0;
133

134
	int ip_off = ETH_HLEN;
135
	// Read the IP header.
136
	struct iphdr iph;
137
	if (bpf_skb_load_bytes(skb, ip_off, &iph, sizeof iph))
138
		return 0;
139

140
	// Skip packets with IP protocol other than TCP.
141
	if (iph.protocol != IPPROTO_TCP)
142
		return 0;
143

144
	// An IPv4 header doesn't have a fixed size. The IHL field of a packet
145
	// represents the size of the IP header in 32-bit words, so we need to
146
	// multiply this value by 4 to get the header size in bytes.
147
	__u8 ip_header_len = iph.ihl * 4;
148
	int tcp_off = ip_off + ip_header_len;
149

150
	// Read the TCP header.
151
	struct tcphdr tcph;
152
	if (bpf_skb_load_bytes(skb, tcp_off, &tcph, sizeof tcph))
153
		return 0;
154

155
	if (!tcph.psh)
156
		return 0;
157

158
	// The data offset field in the header is specified in 32-bit words. We
159
	// have to multiply this value by 4 to get the TCP header length in bytes.
160
	__u8 tcp_header_len = tcph.doff * 4;
161
	// TLS data starts at this offset.
162
	int payload_off = tcp_off + tcp_header_len;
163

164
	// Parse SNI.
165
	char sni[TLS_MAX_SERVER_NAME_LEN] = {};
166
	int read = parse_sni(skb, payload_off, sni);
167
	if (read == 0)
168
		return 0;
169

170
	struct event_t event = {
171
		0,
172
	};
173
	event.netns = skb->cb[0]; // cb[0] initialized by dispatcher.bpf.c
174
	for (int i = 0; i < TLS_MAX_SERVER_NAME_LEN; i++) {
175
		if (sni[i] == '\0')
176
			break;
177
		event.name[i] = sni[i];
178
	}
179
	event.timestamp = bpf_ktime_get_boot_ns();
180

181
	// Enrich event with process metadata
182
	struct sockets_value *skb_val = gadget_socket_lookup(skb);
183
	if (skb_val != NULL) {
184
		event.mount_ns_id = skb_val->mntns;
185
		event.pid = skb_val->pid_tgid >> 32;
186
		event.tid = (__u32)skb_val->pid_tgid;
187
		__builtin_memcpy(&event.task, skb_val->task,
188
				 sizeof(event.task));
189
		event.uid = (__u32)skb_val->uid_gid;
190
		event.gid = (__u32)(skb_val->uid_gid >> 32);
191
	}
192

193
	bpf_perf_event_output(skb, &events, BPF_F_CURRENT_CPU, &event,
194
			      sizeof(event));
195

196
	return 0;
197
}
198

199
char _license[] SEC("license") = "GPL";
200

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

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

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

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