Line data Source code
1 : /* SPDX-License-Identifier: GPL-2.0-only */
2 : /*
3 : * Copyright (c) 2023 Meta Platforms, Inc. and affiliates.
4 : */
5 :
6 : #include <errno.h>
7 : #include <string.h>
8 :
9 : #include "bpfilter/chain.h"
10 : #include "bpfilter/counter.h"
11 : #include "bpfilter/front.h"
12 : #include "bpfilter/generic.h"
13 : #include "bpfilter/helper.h"
14 : #include "bpfilter/hook.h"
15 : #include "bpfilter/io.h"
16 : #include "bpfilter/list.h"
17 : #include "bpfilter/logger.h"
18 : #include "bpfilter/pack.h"
19 : #include "bpfilter/request.h"
20 : #include "bpfilter/response.h"
21 :
22 0 : int bf_ruleset_get(bf_list *chains, bf_list *hookopts, bf_list *counters)
23 : {
24 0 : _free_bf_request_ struct bf_request *request = NULL;
25 0 : _free_bf_response_ struct bf_response *response = NULL;
26 0 : _clean_bf_list_ bf_list _chains = bf_list_default_from(*chains);
27 0 : _clean_bf_list_ bf_list _hookopts = bf_list_default_from(*hookopts);
28 0 : _clean_bf_list_ bf_list _counters = bf_list_default_from(*counters);
29 0 : _free_bf_rpack_ bf_rpack_t *pack;
30 : bf_rpack_node_t root, node, child;
31 : int r;
32 :
33 0 : r = bf_request_new(&request, BF_FRONT_CLI, BF_REQ_RULESET_GET, NULL, 0);
34 0 : if (r < 0)
35 0 : return bf_err_r(r, "failed to init request");
36 :
37 0 : r = bf_send(request, &response);
38 0 : if (r < 0)
39 0 : return bf_err_r(r, "failed to send a ruleset get request");
40 :
41 0 : if (bf_response_status(response) != 0)
42 0 : return bf_response_status(response);
43 :
44 0 : r = bf_rpack_new(&pack, bf_response_data(response),
45 : bf_response_data_len(response));
46 0 : if (r)
47 : return r;
48 :
49 0 : r = bf_rpack_kv_obj(bf_rpack_root(pack), "ruleset", &root);
50 0 : if (r)
51 : return r;
52 :
53 0 : r = bf_rpack_kv_array(root, "chains", &node);
54 0 : if (r)
55 : return r;
56 0 : bf_rpack_array_foreach (node, child) {
57 0 : _free_bf_chain_ struct bf_chain *chain = NULL;
58 :
59 0 : r = bf_list_emplace(&_chains, bf_chain_new_from_pack, chain, child);
60 : if (r)
61 : return r;
62 : }
63 :
64 0 : r = bf_rpack_kv_array(root, "hookopts", &node);
65 0 : if (r)
66 : return r;
67 0 : bf_rpack_array_foreach (node, child) {
68 0 : _free_bf_hookopts_ struct bf_hookopts *hookopts = NULL;
69 :
70 0 : if (!bf_rpack_is_nil(child)) {
71 0 : r = bf_list_emplace(&_hookopts, bf_hookopts_new_from_pack, hookopts,
72 : child);
73 : } else {
74 0 : r = bf_list_add_tail(&_hookopts, NULL);
75 : }
76 :
77 0 : if (r)
78 : return r;
79 : }
80 :
81 0 : r = bf_rpack_kv_array(root, "counters", &node);
82 0 : if (r)
83 : return r;
84 0 : bf_rpack_array_foreach (node, child) {
85 0 : _free_bf_list_ bf_list *nested = NULL;
86 : bf_rpack_node_t subchild;
87 :
88 0 : if (!bf_rpack_is_array(child))
89 : return -EDOM;
90 :
91 0 : r = bf_list_new(&nested, &bf_list_ops_default(bf_counter_free, NULL));
92 0 : if (r)
93 : return r;
94 :
95 0 : bf_rpack_array_foreach (child, subchild) {
96 0 : _free_bf_counter_ struct bf_counter *counter = NULL;
97 :
98 0 : r = bf_list_emplace(nested, bf_counter_new_from_pack, counter,
99 : subchild);
100 : if (r)
101 : return r;
102 : }
103 :
104 0 : r = bf_list_add_tail(&_counters, nested);
105 0 : if (r)
106 : return r;
107 :
108 0 : TAKE_PTR(nested);
109 : }
110 :
111 0 : *chains = bf_list_move(_chains);
112 0 : *hookopts = bf_list_move(_hookopts);
113 0 : *counters = bf_list_move(_counters);
114 :
115 0 : return 0;
116 : }
117 :
118 0 : int bf_ruleset_set(bf_list *chains, bf_list *hookopts)
119 : {
120 0 : _free_bf_wpack_ bf_wpack_t *pack = NULL;
121 0 : _free_bf_request_ struct bf_request *request = NULL;
122 0 : _free_bf_response_ struct bf_response *response = NULL;
123 0 : struct bf_list_node *chain_node = bf_list_get_head(chains);
124 0 : struct bf_list_node *hookopts_node = bf_list_get_head(hookopts);
125 : int r;
126 :
127 0 : if (bf_list_size(chains) != bf_list_size(hookopts))
128 : return -EINVAL;
129 :
130 0 : r = bf_wpack_new(&pack);
131 0 : if (r)
132 : return r;
133 :
134 0 : bf_wpack_open_array(pack, "ruleset");
135 0 : while (chain_node && hookopts_node) {
136 0 : struct bf_chain *chain = bf_list_node_get_data(chain_node);
137 0 : struct bf_hookopts *hookopts = bf_list_node_get_data(hookopts_node);
138 :
139 0 : bf_wpack_open_object(pack, NULL);
140 :
141 0 : bf_wpack_open_object(pack, "chain");
142 0 : bf_chain_pack(chain, pack);
143 0 : bf_wpack_close_object(pack);
144 :
145 0 : if (hookopts) {
146 0 : bf_wpack_open_object(pack, "hookopts");
147 0 : bf_hookopts_pack(hookopts, pack);
148 0 : bf_wpack_close_object(pack);
149 : } else {
150 0 : bf_wpack_kv_nil(pack, "hookopts");
151 : }
152 :
153 0 : bf_wpack_close_object(pack);
154 :
155 0 : chain_node = bf_list_node_next(chain_node);
156 0 : hookopts_node = bf_list_node_next(hookopts_node);
157 : }
158 0 : bf_wpack_close_array(pack);
159 :
160 0 : r = bf_request_new_from_pack(&request, BF_FRONT_CLI, BF_REQ_RULESET_SET,
161 : pack);
162 0 : if (r)
163 0 : return bf_err_r(r, "failed to create request for chain");
164 :
165 0 : r = bf_send(request, &response);
166 0 : if (r)
167 0 : return bf_err_r(r, "failed to send chain to the daemon");
168 :
169 0 : return bf_response_status(response);
170 : }
171 :
172 0 : int bf_ruleset_flush(void)
173 : {
174 0 : _free_bf_request_ struct bf_request *request = NULL;
175 0 : _free_bf_response_ struct bf_response *response = NULL;
176 : int r;
177 :
178 0 : r = bf_request_new(&request, BF_FRONT_CLI, BF_REQ_RULESET_FLUSH, NULL, 0);
179 0 : if (r)
180 0 : return bf_err_r(r, "failed to create a ruleset flush request");
181 :
182 0 : r = bf_send(request, &response);
183 0 : if (r)
184 0 : return bf_err_r(r, "failed to send a ruleset flush request");
185 :
186 0 : return bf_response_status(response);
187 : }
188 :
189 0 : int bf_chain_set(struct bf_chain *chain, struct bf_hookopts *hookopts)
190 : {
191 0 : _free_bf_wpack_ bf_wpack_t *pack = NULL;
192 0 : _free_bf_request_ struct bf_request *request = NULL;
193 0 : _free_bf_response_ struct bf_response *response = NULL;
194 : int r;
195 :
196 0 : r = bf_wpack_new(&pack);
197 0 : if (r)
198 : return r;
199 :
200 0 : bf_wpack_open_object(pack, "chain");
201 0 : r = bf_chain_pack(chain, pack);
202 0 : if (r)
203 : return r;
204 0 : bf_wpack_close_object(pack);
205 :
206 0 : if (hookopts) {
207 0 : bf_wpack_open_object(pack, "hookopts");
208 0 : r = bf_hookopts_pack(hookopts, pack);
209 0 : if (r)
210 : return r;
211 0 : bf_wpack_close_object(pack);
212 : } else {
213 0 : bf_wpack_kv_nil(pack, "hookopts");
214 : }
215 :
216 0 : r = bf_request_new_from_pack(&request, BF_FRONT_CLI, BF_REQ_CHAIN_SET,
217 : pack);
218 0 : if (r)
219 0 : return bf_err_r(r, "bf_chain_set: failed to create request");
220 :
221 0 : r = bf_send(request, &response);
222 0 : if (r)
223 0 : return bf_err_r(r, "bf_chain_set: failed to send request");
224 :
225 0 : return bf_response_status(response);
226 : }
227 :
228 0 : int bf_chain_get(const char *name, struct bf_chain **chain,
229 : struct bf_hookopts **hookopts, bf_list *counters)
230 : {
231 0 : _free_bf_request_ struct bf_request *request = NULL;
232 0 : _free_bf_response_ struct bf_response *response = NULL;
233 0 : _free_bf_chain_ struct bf_chain *_chain = NULL;
234 0 : _free_bf_hookopts_ struct bf_hookopts *_hookopts = NULL;
235 0 : _clean_bf_list_ bf_list _counters = bf_list_default_from(*counters);
236 0 : _free_bf_wpack_ bf_wpack_t *wpack = NULL;
237 0 : _free_bf_rpack_ bf_rpack_t *rpack = NULL;
238 : bf_rpack_node_t child, array_node;
239 : int r;
240 :
241 0 : r = bf_wpack_new(&wpack);
242 0 : if (r)
243 : return r;
244 :
245 0 : bf_wpack_kv_str(wpack, "name", name);
246 0 : if (!bf_wpack_is_valid(wpack))
247 : return -EINVAL;
248 :
249 0 : r = bf_request_new_from_pack(&request, BF_FRONT_CLI, BF_REQ_CHAIN_GET,
250 : wpack);
251 0 : if (r < 0)
252 0 : return bf_err_r(r, "failed to init request");
253 :
254 0 : r = bf_send(request, &response);
255 0 : if (r < 0)
256 0 : return bf_err_r(r, "failed to send a ruleset get request");
257 :
258 0 : if (bf_response_status(response) != 0)
259 0 : return bf_response_status(response);
260 :
261 0 : r = bf_rpack_new(&rpack, bf_response_data(response),
262 : bf_response_data_len(response));
263 0 : if (r)
264 : return r;
265 :
266 0 : r = bf_rpack_kv_obj(bf_rpack_root(rpack), "chain", &child);
267 0 : if (r)
268 : return r;
269 0 : r = bf_chain_new_from_pack(&_chain, child);
270 0 : if (r)
271 : return r;
272 :
273 0 : r = bf_rpack_kv_node(bf_rpack_root(rpack), "hookopts", &child);
274 0 : if (r)
275 : return r;
276 0 : if (!bf_rpack_is_nil(child)) {
277 0 : r = bf_hookopts_new_from_pack(&_hookopts, child);
278 0 : if (r)
279 : return r;
280 : }
281 :
282 0 : r = bf_rpack_kv_array(bf_rpack_root(rpack), "counters", &child);
283 0 : if (r)
284 : return r;
285 0 : bf_rpack_array_foreach (child, array_node) {
286 0 : _free_bf_counter_ struct bf_counter *counter = NULL;
287 :
288 0 : r = bf_list_emplace(&_counters, bf_counter_new_from_pack, counter,
289 : array_node);
290 : if (r)
291 : return r;
292 : }
293 :
294 0 : *chain = TAKE_PTR(_chain);
295 0 : *hookopts = TAKE_PTR(_hookopts);
296 0 : *counters = bf_list_move(_counters);
297 :
298 0 : return 0;
299 : }
300 :
301 0 : int bf_chain_prog_fd(const char *name)
302 : {
303 0 : _free_bf_request_ struct bf_request *request = NULL;
304 0 : _free_bf_response_ struct bf_response *response = NULL;
305 0 : _cleanup_close_ int fd = -1;
306 0 : _free_bf_wpack_ bf_wpack_t *wpack = NULL;
307 : int r;
308 :
309 0 : if (!name)
310 : return -EINVAL;
311 :
312 0 : r = bf_wpack_new(&wpack);
313 0 : if (r)
314 : return r;
315 :
316 0 : bf_wpack_kv_str(wpack, "name", name);
317 0 : if (!bf_wpack_is_valid(wpack))
318 : return -EINVAL;
319 :
320 0 : r = bf_request_new_from_pack(&request, BF_FRONT_CLI, BF_REQ_CHAIN_PROG_FD,
321 : wpack);
322 0 : if (r < 0)
323 0 : return bf_err_r(r, "failed to init request");
324 :
325 0 : fd = bf_send_with_fd(request, &response);
326 0 : if (fd < 0)
327 0 : return bf_err_r(fd, "failed to request prog FD from the daemon");
328 :
329 0 : if (bf_response_status(response) != 0)
330 0 : return bf_err_r(bf_response_status(response),
331 : "BF_REQ_CHAIN_PROG_FD failed");
332 :
333 0 : return TAKE_FD(fd);
334 : }
335 :
336 0 : int bf_chain_logs_fd(const char *name)
337 : {
338 0 : _free_bf_request_ struct bf_request *request = NULL;
339 0 : _free_bf_response_ struct bf_response *response = NULL;
340 0 : _cleanup_close_ int fd = -1;
341 0 : _free_bf_wpack_ bf_wpack_t *wpack = NULL;
342 : int r;
343 :
344 0 : if (!name)
345 : return -EINVAL;
346 :
347 0 : r = bf_wpack_new(&wpack);
348 0 : if (r)
349 : return r;
350 :
351 0 : bf_wpack_kv_str(wpack, "name", name);
352 0 : if (!bf_wpack_is_valid(wpack))
353 : return -EINVAL;
354 :
355 0 : r = bf_request_new_from_pack(&request, BF_FRONT_CLI, BF_REQ_CHAIN_LOGS_FD,
356 : wpack);
357 0 : if (r < 0)
358 0 : return bf_err_r(r, "failed to init request");
359 :
360 0 : fd = bf_send_with_fd(request, &response);
361 0 : if (fd < 0)
362 0 : return bf_err_r(fd, "failed to request logs FD from the daemon");
363 :
364 0 : if (bf_response_status(response) != 0)
365 0 : return bf_err_r(bf_response_status(response),
366 : "BF_REQ_CHAIN_LOGS failed");
367 :
368 0 : return TAKE_FD(fd);
369 : }
370 :
371 0 : int bf_chain_load(struct bf_chain *chain)
372 : {
373 0 : _free_bf_request_ struct bf_request *request = NULL;
374 0 : _free_bf_response_ struct bf_response *response = NULL;
375 0 : _free_bf_wpack_ bf_wpack_t *wpack = NULL;
376 : int r;
377 :
378 0 : r = bf_wpack_new(&wpack);
379 0 : if (r)
380 : return r;
381 :
382 0 : bf_wpack_open_object(wpack, "chain");
383 0 : r = bf_chain_pack(chain, wpack);
384 0 : if (r)
385 : return r;
386 0 : bf_wpack_close_object(wpack);
387 :
388 0 : r = bf_request_new_from_pack(&request, BF_FRONT_CLI, BF_REQ_CHAIN_LOAD,
389 : wpack);
390 0 : if (r)
391 0 : return bf_err_r(r, "bf_chain_load: failed to create a new request");
392 :
393 0 : r = bf_send(request, &response);
394 0 : if (r)
395 0 : return bf_err_r(r, "bf_chain_set: failed to send request");
396 :
397 0 : return bf_response_status(response);
398 : }
399 :
400 0 : int bf_chain_attach(const char *name, const struct bf_hookopts *hookopts)
401 : {
402 0 : _free_bf_request_ struct bf_request *request = NULL;
403 0 : _free_bf_response_ struct bf_response *response = NULL;
404 0 : _free_bf_wpack_ bf_wpack_t *wpack = NULL;
405 : int r;
406 :
407 0 : r = bf_wpack_new(&wpack);
408 0 : if (r)
409 : return r;
410 :
411 0 : bf_wpack_kv_str(wpack, "name", name);
412 0 : bf_wpack_open_object(wpack, "hookopts");
413 0 : r = bf_hookopts_pack(hookopts, wpack);
414 0 : if (r)
415 : return r;
416 0 : bf_wpack_close_object(wpack);
417 :
418 0 : r = bf_request_new_from_pack(&request, BF_FRONT_CLI, BF_REQ_CHAIN_ATTACH,
419 : wpack);
420 0 : if (r)
421 0 : return bf_err_r(r, "bf_chain_attach: failed to create a new request");
422 :
423 0 : r = bf_send(request, &response);
424 0 : if (r)
425 0 : return bf_err_r(r, "bf_chain_attach: failed to send request");
426 :
427 0 : return bf_response_status(response);
428 : }
429 :
430 0 : int bf_chain_update(const struct bf_chain *chain)
431 : {
432 0 : _free_bf_request_ struct bf_request *request = NULL;
433 0 : _free_bf_response_ struct bf_response *response = NULL;
434 0 : _free_bf_wpack_ bf_wpack_t *wpack = NULL;
435 : int r;
436 :
437 0 : r = bf_wpack_new(&wpack);
438 0 : if (r)
439 : return r;
440 :
441 0 : bf_wpack_open_object(wpack, "chain");
442 0 : r = bf_chain_pack(chain, wpack);
443 0 : if (r)
444 : return r;
445 0 : bf_wpack_close_object(wpack);
446 :
447 0 : r = bf_request_new_from_pack(&request, BF_FRONT_CLI, BF_REQ_CHAIN_UPDATE,
448 : wpack);
449 0 : if (r)
450 0 : return bf_err_r(r, "bf_chain_update: failed to create a new request");
451 :
452 0 : r = bf_send(request, &response);
453 0 : if (r)
454 0 : return bf_err_r(r, "bf_chain_update: failed to send request");
455 :
456 0 : return bf_response_status(response);
457 : }
458 :
459 0 : int bf_chain_flush(const char *name)
460 : {
461 0 : _free_bf_request_ struct bf_request *request = NULL;
462 0 : _free_bf_response_ struct bf_response *response = NULL;
463 0 : _free_bf_wpack_ bf_wpack_t *wpack = NULL;
464 : int r;
465 :
466 0 : r = bf_wpack_new(&wpack);
467 0 : if (r)
468 : return r;
469 :
470 0 : bf_wpack_kv_str(wpack, "name", name);
471 :
472 0 : r = bf_request_new_from_pack(&request, BF_FRONT_CLI, BF_REQ_CHAIN_FLUSH,
473 : wpack);
474 0 : if (r)
475 0 : return bf_err_r(r, "failed to create request for chain");
476 :
477 0 : r = bf_send(request, &response);
478 0 : if (r)
479 0 : return bf_err_r(r, "failed to send chain to the daemon");
480 :
481 0 : return bf_response_status(response);
482 : }
|