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 <stdio.h>
8 : #include <string.h>
9 :
10 : #include "core/chain.h"
11 : #include "core/counter.h"
12 : #include "core/front.h"
13 : #include "core/helper.h"
14 : #include "core/hook.h"
15 : #include "core/list.h"
16 : #include "core/logger.h"
17 : #include "core/marsh.h"
18 : #include "core/request.h"
19 : #include "core/response.h"
20 : #include "core/rule.h"
21 : #include "libbpfilter/generic.h"
22 :
23 0 : int bf_cli_ruleset_get(bf_list *chains, bf_list *hookopts, bf_list *counters)
24 : {
25 0 : _cleanup_bf_request_ struct bf_request *request = NULL;
26 0 : _cleanup_bf_response_ struct bf_response *response = NULL;
27 0 : _clean_bf_list_ bf_list _chains = bf_list_default_from(*chains);
28 0 : _clean_bf_list_ bf_list _hookopts = bf_list_default_from(*hookopts);
29 0 : _clean_bf_list_ bf_list _counters = bf_list_default_from(*counters);
30 : struct bf_marsh *marsh = NULL;
31 : struct bf_marsh *child = NULL;
32 : int r;
33 :
34 0 : r = bf_request_new(&request, NULL, 0);
35 0 : if (r < 0)
36 0 : return bf_err_r(r, "failed to init request");
37 :
38 0 : request->front = BF_FRONT_CLI;
39 0 : request->cmd = BF_REQ_RULESET_GET;
40 :
41 0 : r = bf_send(request, &response);
42 0 : if (r < 0)
43 0 : return bf_err_r(r, "failed to send a ruleset get request");
44 :
45 0 : if (response->type == BF_RES_FAILURE)
46 0 : return response->error;
47 :
48 0 : if (response->data_len == 0)
49 : return 0;
50 :
51 0 : marsh = (struct bf_marsh *)response->data;
52 :
53 0 : if (!(child = bf_marsh_next_child(marsh, child)))
54 : return -EINVAL;
55 0 : for (struct bf_marsh *schild = bf_marsh_next_child(child, NULL); schild;
56 0 : schild = bf_marsh_next_child(child, schild)) {
57 0 : _cleanup_bf_chain_ struct bf_chain *chain = NULL;
58 :
59 0 : r = bf_chain_new_from_marsh(&chain, schild);
60 0 : if (r)
61 : return r;
62 :
63 0 : r = bf_list_add_tail(&_chains, chain);
64 0 : if (r)
65 : return r;
66 :
67 0 : TAKE_PTR(chain);
68 : }
69 :
70 0 : if (!(child = bf_marsh_next_child(marsh, child)))
71 : return -EINVAL;
72 0 : for (struct bf_marsh *schild = bf_marsh_next_child(child, NULL); schild;
73 0 : schild = bf_marsh_next_child(child, schild)) {
74 0 : _free_bf_hookopts_ struct bf_hookopts *hookopts = NULL;
75 :
76 0 : if (!bf_marsh_is_empty(schild)) {
77 0 : r = bf_hookopts_new_from_marsh(&hookopts, schild);
78 0 : if (r)
79 : return r;
80 : }
81 :
82 0 : r = bf_list_add_tail(&_hookopts, hookopts);
83 0 : if (r)
84 : return r;
85 :
86 0 : TAKE_PTR(hookopts);
87 : }
88 :
89 0 : if (!(child = bf_marsh_next_child(marsh, child)))
90 : return -EINVAL;
91 0 : for (struct bf_marsh *schild = bf_marsh_next_child(child, NULL); schild;
92 0 : schild = bf_marsh_next_child(child, schild)) {
93 0 : _cleanup_bf_list_ bf_list *nested = NULL;
94 :
95 0 : r = bf_list_new(
96 0 : &nested, &bf_list_ops_default(bf_counter_free, bf_counter_marsh));
97 0 : if (r)
98 : return r;
99 :
100 0 : for (struct bf_marsh *counter_marsh = bf_marsh_next_child(schild, NULL);
101 0 : counter_marsh;
102 0 : counter_marsh = bf_marsh_next_child(schild, counter_marsh)) {
103 0 : _cleanup_bf_counter_ struct bf_counter *counter = NULL;
104 :
105 0 : r = bf_counter_new_from_marsh(&counter, counter_marsh);
106 0 : if (r)
107 : return r;
108 :
109 0 : r = bf_list_add_tail(nested, counter);
110 0 : if (r)
111 : return r;
112 :
113 0 : TAKE_PTR(counter);
114 : }
115 :
116 0 : r = bf_list_add_tail(&_counters, nested);
117 0 : if (r)
118 : return r;
119 :
120 0 : TAKE_PTR(nested);
121 : }
122 :
123 0 : *chains = bf_list_move(_chains);
124 0 : *hookopts = bf_list_move(_hookopts);
125 0 : *counters = bf_list_move(_counters);
126 :
127 0 : return 0;
128 : }
129 :
130 0 : int bf_cli_ruleset_flush(void)
131 : {
132 0 : _cleanup_bf_request_ struct bf_request *request = NULL;
133 0 : _cleanup_bf_response_ struct bf_response *response = NULL;
134 : int r;
135 :
136 0 : r = bf_request_new(&request, NULL, 0);
137 0 : if (r)
138 0 : return bf_err_r(r, "failed to create a ruleset flush request");
139 :
140 0 : request->front = BF_FRONT_CLI;
141 0 : request->cmd = BF_REQ_RULESET_FLUSH;
142 :
143 0 : r = bf_send(request, &response);
144 0 : if (r)
145 0 : return bf_err_r(r, "failed to send a ruleset flush request");
146 :
147 0 : return response->type == BF_RES_FAILURE ? response->error : 0;
148 : }
149 :
150 0 : int bf_cli_ruleset_set(bf_list *chains, bf_list *hookopts)
151 : {
152 0 : _cleanup_bf_request_ struct bf_request *request = NULL;
153 0 : _cleanup_bf_response_ struct bf_response *response = NULL;
154 0 : _cleanup_bf_marsh_ struct bf_marsh *marsh = NULL;
155 0 : struct bf_list_node *chain_node = bf_list_get_head(chains);
156 0 : struct bf_list_node *hookopts_node = bf_list_get_head(hookopts);
157 : int r;
158 :
159 0 : if (bf_list_size(chains) != bf_list_size(hookopts))
160 : return -EINVAL;
161 :
162 0 : r = bf_marsh_new(&marsh, NULL, 0);
163 0 : if (r)
164 : return r;
165 :
166 0 : while (chain_node && hookopts_node) {
167 0 : _cleanup_bf_marsh_ struct bf_marsh *chain_marsh = NULL;
168 0 : _cleanup_bf_marsh_ struct bf_marsh *hook_marsh = NULL;
169 0 : _cleanup_bf_marsh_ struct bf_marsh *_marsh = NULL;
170 0 : struct bf_chain *chain = bf_list_node_get_data(chain_node);
171 0 : struct bf_hookopts *hookopts = bf_list_node_get_data(hookopts_node);
172 :
173 0 : r = bf_marsh_new(&_marsh, NULL, 0);
174 0 : if (r)
175 : return r;
176 :
177 0 : r = bf_chain_marsh(chain, &chain_marsh);
178 0 : if (r)
179 : return r;
180 :
181 0 : r = bf_marsh_add_child_obj(&_marsh, chain_marsh);
182 0 : if (r)
183 : return r;
184 :
185 0 : if (hookopts) {
186 0 : r = bf_hookopts_marsh(hookopts, &hook_marsh);
187 0 : if (r)
188 : return r;
189 :
190 0 : r = bf_marsh_add_child_obj(&_marsh, hook_marsh);
191 0 : if (r)
192 : return r;
193 : } else {
194 0 : r = bf_marsh_add_child_raw(&_marsh, NULL, 0);
195 0 : if (r)
196 : return r;
197 : }
198 :
199 0 : r = bf_marsh_add_child_obj(&marsh, _marsh);
200 0 : if (r)
201 : return r;
202 :
203 0 : chain_node = bf_list_node_next(chain_node);
204 0 : hookopts_node = bf_list_node_next(hookopts_node);
205 : }
206 :
207 0 : r = bf_request_new(&request, marsh, bf_marsh_size(marsh));
208 0 : if (r)
209 0 : return bf_err_r(r, "failed to create request for chain");
210 :
211 0 : request->front = BF_FRONT_CLI;
212 0 : request->cmd = BF_REQ_RULESET_SET;
213 :
214 0 : r = bf_send(request, &response);
215 0 : if (r)
216 0 : return bf_err_r(r, "failed to send chain to the daemon");
217 :
218 0 : return response->type == BF_RES_FAILURE ? response->error : 0;
219 : }
220 :
221 0 : int bf_chain_set(struct bf_chain *chain, struct bf_hookopts *hookopts)
222 : {
223 0 : _cleanup_bf_request_ struct bf_request *request = NULL;
224 0 : _cleanup_bf_response_ struct bf_response *response = NULL;
225 0 : _cleanup_bf_marsh_ struct bf_marsh *marsh = NULL;
226 0 : _cleanup_bf_marsh_ struct bf_marsh *chain_marsh = NULL;
227 0 : _cleanup_bf_marsh_ struct bf_marsh *hook_marsh = NULL;
228 : int r;
229 :
230 0 : r = bf_marsh_new(&marsh, NULL, 0);
231 0 : if (r)
232 : return r;
233 :
234 0 : r = bf_chain_marsh(chain, &chain_marsh);
235 0 : if (r)
236 : return r;
237 :
238 0 : r = bf_marsh_add_child_obj(&marsh, chain_marsh);
239 0 : if (r)
240 : return r;
241 :
242 0 : if (hookopts) {
243 0 : r = bf_hookopts_marsh(hookopts, &hook_marsh);
244 0 : if (r)
245 : return r;
246 :
247 0 : r = bf_marsh_add_child_obj(&marsh, hook_marsh);
248 0 : if (r)
249 : return r;
250 : } else {
251 0 : r = bf_marsh_add_child_raw(&marsh, NULL, 0);
252 0 : if (r)
253 : return r;
254 : }
255 :
256 0 : r = bf_request_new(&request, marsh, bf_marsh_size(marsh));
257 0 : if (r)
258 0 : return bf_err_r(r, "bf_chain_set: failed to create request");
259 :
260 0 : request->front = BF_FRONT_CLI;
261 0 : request->cmd = BF_REQ_CHAIN_SET;
262 :
263 0 : r = bf_send(request, &response);
264 0 : if (r)
265 0 : return bf_err_r(r, "bf_chain_set: failed to send request");
266 :
267 0 : return response->type == BF_RES_FAILURE ? response->error : 0;
268 : }
269 :
270 0 : int bf_chain_get(const char *name, struct bf_chain **chain,
271 : struct bf_hookopts **hookopts, bf_list *counters)
272 : {
273 0 : _cleanup_bf_request_ struct bf_request *request = NULL;
274 0 : _cleanup_bf_response_ struct bf_response *response = NULL;
275 0 : _cleanup_bf_chain_ struct bf_chain *_chain = NULL;
276 0 : _free_bf_hookopts_ struct bf_hookopts *_hookopts = NULL;
277 0 : _clean_bf_list_ bf_list _counters = bf_list_default_from(*counters);
278 : struct bf_marsh *marsh, *child = NULL;
279 0 : _cleanup_bf_marsh_ struct bf_marsh *req_marsh = NULL;
280 : int r;
281 :
282 0 : r = bf_marsh_new(&req_marsh, NULL, 0);
283 0 : if (r)
284 : return r;
285 :
286 0 : r = bf_marsh_add_child_raw(&req_marsh, name, strlen(name) + 1);
287 0 : if (r)
288 : return r;
289 :
290 0 : r = bf_request_new(&request, req_marsh, bf_marsh_size(req_marsh));
291 0 : if (r < 0)
292 0 : return bf_err_r(r, "failed to init request");
293 :
294 0 : request->front = BF_FRONT_CLI;
295 0 : request->cmd = BF_REQ_CHAIN_GET;
296 :
297 0 : r = bf_send(request, &response);
298 0 : if (r < 0)
299 0 : return bf_err_r(r, "failed to send a ruleset get request");
300 :
301 0 : if (response->type == BF_RES_FAILURE)
302 0 : return response->error;
303 :
304 0 : marsh = (struct bf_marsh *)response->data;
305 0 : if (bf_marsh_size(marsh) != response->data_len) {
306 0 : return bf_err_r(
307 : -EINVAL,
308 : "response payload is expected to have the same size as the marsh");
309 : }
310 :
311 0 : if (!(child = bf_marsh_next_child(marsh, child)))
312 : return -EINVAL;
313 0 : r = bf_chain_new_from_marsh(&_chain, child);
314 0 : if (r)
315 : return r;
316 :
317 0 : if (!(child = bf_marsh_next_child(marsh, child)))
318 : return -EINVAL;
319 0 : if (child->data_len) {
320 0 : r = bf_hookopts_new_from_marsh(&_hookopts, child);
321 0 : if (r)
322 : return r;
323 : }
324 :
325 0 : if (!(child = bf_marsh_next_child(marsh, child)))
326 : return -EINVAL;
327 0 : for (struct bf_marsh *counter_marsh = bf_marsh_next_child(child, NULL);
328 0 : counter_marsh;
329 0 : counter_marsh = bf_marsh_next_child(child, counter_marsh)) {
330 0 : _cleanup_bf_counter_ struct bf_counter *counter = NULL;
331 :
332 0 : r = bf_counter_new_from_marsh(&counter, counter_marsh);
333 0 : if (r)
334 : return r;
335 :
336 0 : r = bf_list_add_tail(&_counters, counter);
337 0 : if (r)
338 : return r;
339 :
340 0 : TAKE_PTR(counter);
341 : }
342 :
343 0 : *chain = TAKE_PTR(_chain);
344 0 : *hookopts = TAKE_PTR(_hookopts);
345 0 : *counters = bf_list_move(_counters);
346 :
347 0 : return 0;
348 : }
349 :
350 0 : int bf_chain_load(struct bf_chain *chain)
351 : {
352 0 : _cleanup_bf_request_ struct bf_request *request = NULL;
353 0 : _cleanup_bf_response_ struct bf_response *response = NULL;
354 0 : _cleanup_bf_marsh_ struct bf_marsh *marsh = NULL;
355 : int r;
356 :
357 0 : r = bf_marsh_new(&marsh, NULL, 0);
358 0 : if (r)
359 : return r;
360 :
361 : {
362 0 : _cleanup_bf_marsh_ struct bf_marsh *child = NULL;
363 :
364 0 : r = bf_chain_marsh(chain, &child);
365 0 : if (r)
366 : return r;
367 :
368 0 : r = bf_marsh_add_child_obj(&marsh, child);
369 0 : if (r)
370 : return r;
371 : }
372 :
373 0 : r = bf_request_new(&request, marsh, bf_marsh_size(marsh));
374 0 : if (r)
375 0 : return bf_err_r(r, "bf_chain_load: failed to create a new request");
376 :
377 0 : request->front = BF_FRONT_CLI;
378 0 : request->cmd = BF_REQ_CHAIN_LOAD;
379 :
380 0 : r = bf_send(request, &response);
381 0 : if (r)
382 0 : return bf_err_r(r, "bf_chain_set: failed to send request");
383 :
384 0 : return response->type == BF_RES_FAILURE ? response->error : 0;
385 : }
386 :
387 0 : int bf_chain_attach(const char *name, const struct bf_hookopts *hookopts)
388 : {
389 0 : _cleanup_bf_request_ struct bf_request *request = NULL;
390 0 : _cleanup_bf_response_ struct bf_response *response = NULL;
391 0 : _cleanup_bf_marsh_ struct bf_marsh *marsh = NULL;
392 : int r;
393 :
394 0 : r = bf_marsh_new(&marsh, NULL, 0);
395 0 : if (r)
396 : return r;
397 :
398 0 : r = bf_marsh_add_child_raw(&marsh, name, strlen(name) + 1);
399 0 : if (r)
400 : return r;
401 :
402 : {
403 0 : _cleanup_bf_marsh_ struct bf_marsh *child = NULL;
404 :
405 0 : r = bf_hookopts_marsh(hookopts, &child);
406 0 : if (r)
407 : return r;
408 :
409 0 : r = bf_marsh_add_child_obj(&marsh, child);
410 0 : if (r)
411 : return r;
412 : }
413 :
414 0 : r = bf_request_new(&request, marsh, bf_marsh_size(marsh));
415 0 : if (r)
416 0 : return bf_err_r(r, "bf_chain_attach: failed to create a new request");
417 :
418 0 : request->front = BF_FRONT_CLI;
419 0 : request->cmd = BF_REQ_CHAIN_ATTACH;
420 :
421 0 : r = bf_send(request, &response);
422 0 : if (r)
423 0 : return bf_err_r(r, "bf_chain_attach: failed to send request");
424 :
425 0 : return response->type == BF_RES_FAILURE ? response->error : 0;
426 : }
427 :
428 0 : int bf_chain_update(const struct bf_chain *chain)
429 : {
430 0 : _cleanup_bf_request_ struct bf_request *request = NULL;
431 0 : _cleanup_bf_response_ struct bf_response *response = NULL;
432 0 : _cleanup_bf_marsh_ struct bf_marsh *marsh = NULL;
433 0 : _cleanup_bf_marsh_ struct bf_marsh *child = NULL;
434 : int r;
435 :
436 0 : r = bf_marsh_new(&marsh, NULL, 0);
437 0 : if (r)
438 : return r;
439 :
440 0 : r = bf_chain_marsh(chain, &child);
441 0 : if (r)
442 : return r;
443 :
444 0 : r = bf_marsh_add_child_obj(&marsh, child);
445 0 : if (r)
446 : return r;
447 :
448 0 : r = bf_request_new(&request, marsh, bf_marsh_size(marsh));
449 0 : if (r)
450 0 : return bf_err_r(r, "bf_chain_update: failed to create a new request");
451 :
452 0 : request->front = BF_FRONT_CLI;
453 0 : request->cmd = BF_REQ_CHAIN_UPDATE;
454 :
455 0 : r = bf_send(request, &response);
456 0 : if (r)
457 0 : return bf_err_r(r, "bf_chain_update: failed to send request");
458 :
459 0 : return response->type == BF_RES_FAILURE ? response->error : 0;
460 : }
461 :
462 0 : int bf_chain_flush(const char *name)
463 : {
464 0 : _cleanup_bf_request_ struct bf_request *request = NULL;
465 0 : _cleanup_bf_response_ struct bf_response *response = NULL;
466 0 : _cleanup_bf_marsh_ struct bf_marsh *marsh = NULL;
467 : int r;
468 :
469 0 : r = bf_marsh_new(&marsh, NULL, 0);
470 0 : if (r)
471 : return r;
472 :
473 0 : r = bf_marsh_add_child_raw(&marsh, name, strlen(name) + 1);
474 0 : if (r)
475 : return r;
476 :
477 0 : r = bf_marsh_add_child_raw(&marsh, name, strlen(name) + 1);
478 0 : if (r)
479 : return r;
480 :
481 0 : r = bf_request_new(&request, marsh, bf_marsh_size(marsh));
482 0 : if (r)
483 0 : return bf_err_r(r, "failed to create request for chain");
484 :
485 0 : request->front = BF_FRONT_CLI;
486 0 : request->cmd = BF_REQ_CHAIN_FLUSH;
487 :
488 0 : r = bf_send(request, &response);
489 0 : if (r)
490 0 : return bf_err_r(r, "failed to send chain to the daemon");
491 :
492 0 : return response->type == BF_RES_FAILURE ? response->error : 0;
493 : }
|