Branch data 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 "bpfilter/request.h"
7 : :
8 : : #include <errno.h>
9 : : #include <stddef.h>
10 : : #include <stdio.h>
11 : : #include <stdlib.h>
12 : : #include <string.h>
13 : :
14 : : #include "bpfilter/dynbuf.h"
15 : : #include "bpfilter/helper.h"
16 : : #include "bpfilter/pack.h"
17 : :
18 : : /**
19 : : * @struct bf_request
20 : : *
21 : : * Generic request format sent by the client to the daemon.
22 : : *
23 : : * @var bf_request::front
24 : : * Front this request is targeted to.
25 : : * @var bf_request::cmd
26 : : * Command.
27 : : * @var bf_request::ipt_cmd
28 : : * Custom command for the IPT front.
29 : : * @var bf_request::data_len
30 : : * Length of the client-specific data.
31 : : * @var bf_request::data
32 : : * Client-specific data.
33 : : */
34 : : struct bf_request
35 : : {
36 : : enum bf_front front;
37 : : enum bf_request_cmd cmd;
38 : :
39 : : /** Namespaces the request is coming from. This field will be automatically
40 : : * populated by the daemon when receiving the request. */
41 : : struct bf_ns *ns;
42 : :
43 : : /** File descriptor of the receiver socket. This field is automatically
44 : : * populated by the daemon when receiving the request. The request doesn't
45 : : * own the file descriptor. */
46 : : int fd;
47 : :
48 : : union
49 : : {
50 : : int ipt_cmd;
51 : : };
52 : :
53 : : size_t data_len;
54 : :
55 : : /// @todo Return a user-readable error message if the request fails.
56 : : char data[];
57 : : };
58 : :
59 : 130 : int bf_request_new(struct bf_request **request, enum bf_front front,
60 : : enum bf_request_cmd cmd, const void *data, size_t data_len)
61 : : {
62 : 130 : _free_bf_request_ struct bf_request *_request = NULL;
63 : :
64 : : bf_assert(request);
65 : : bf_assert(!(!!data ^ !!data_len));
66 : :
67 : 130 : _request = calloc(1, sizeof(*_request) + data_len);
68 [ + - ]: 130 : if (!_request)
69 : : return -ENOMEM;
70 : :
71 [ + + ]: 130 : if (data) {
72 : 120 : memcpy(_request->data, data, data_len);
73 : 120 : _request->data_len = data_len;
74 : : }
75 : :
76 : 130 : _request->front = front;
77 : 130 : _request->cmd = cmd;
78 : :
79 : 130 : *request = TAKE_PTR(_request);
80 : :
81 : 130 : return 0;
82 : : }
83 : :
84 : 106 : int bf_request_new_from_dynbuf(struct bf_request **request,
85 : : struct bf_dynbuf *dynbuf)
86 : : {
87 : : struct bf_request *tmpreq;
88 : :
89 : : bf_assert(request);
90 : : bf_assert(dynbuf);
91 : :
92 [ + + ]: 106 : if (dynbuf->len < sizeof(*tmpreq))
93 : : return -EINVAL;
94 : :
95 : 105 : tmpreq = dynbuf->data;
96 [ - + ]: 105 : if (bf_request_size(tmpreq) != dynbuf->len)
97 : : return -EINVAL;
98 : :
99 : 105 : *request = bf_dynbuf_take(dynbuf);
100 : :
101 : 105 : return 0;
102 : : }
103 : :
104 : 105 : int bf_request_new_from_pack(struct bf_request **request, enum bf_front front,
105 : : enum bf_request_cmd cmd, bf_wpack_t *pack)
106 : : {
107 : : const void *data;
108 : : size_t data_len;
109 : : int r;
110 : :
111 : : bf_assert(request);
112 : : bf_assert(pack);
113 : :
114 [ + - ]: 105 : if (!bf_wpack_is_valid(pack))
115 : : return -EINVAL;
116 : :
117 : 105 : r = bf_wpack_get_data(pack, &data, &data_len);
118 [ + - ]: 105 : if (r)
119 : : return r;
120 : :
121 : 105 : return bf_request_new(request, front, cmd, data, data_len);
122 : : }
123 : :
124 : 1 : int bf_request_copy(struct bf_request **dest, const struct bf_request *src)
125 : : {
126 : 1 : _free_bf_request_ struct bf_request *_request = NULL;
127 : :
128 : : bf_assert(dest);
129 : : bf_assert(src);
130 : :
131 : 1 : _request = bf_memdup(src, bf_request_size(src));
132 [ + - ]: 1 : if (!_request)
133 : : return -ENOMEM;
134 : :
135 : 1 : *dest = TAKE_PTR(_request);
136 : :
137 : 1 : return 0;
138 : : }
139 : :
140 : 395 : void bf_request_free(struct bf_request **request)
141 : : {
142 : 395 : free(*request);
143 : 395 : *request = NULL;
144 : 395 : }
145 : :
146 : 512 : enum bf_front bf_request_front(const struct bf_request *request)
147 : : {
148 : : bf_assert(request);
149 : 512 : return request->front;
150 : : }
151 : :
152 : 873 : enum bf_request_cmd bf_request_cmd(const struct bf_request *request)
153 : : {
154 : : bf_assert(request);
155 : 873 : return request->cmd;
156 : : }
157 : :
158 : 56 : struct bf_ns *bf_request_ns(const struct bf_request *request)
159 : : {
160 : : bf_assert(request);
161 : 56 : return request->ns;
162 : : }
163 : :
164 : 2 : int bf_request_fd(const struct bf_request *request)
165 : : {
166 : : bf_assert(request);
167 : 2 : return request->fd;
168 : : }
169 : :
170 : 106 : const void *bf_request_data(const struct bf_request *request)
171 : : {
172 : : bf_assert(request);
173 : 106 : return request->data;
174 : : }
175 : :
176 : 104 : size_t bf_request_data_len(const struct bf_request *request)
177 : : {
178 : : bf_assert(request);
179 : 104 : return request->data_len;
180 : : }
181 : :
182 : 218 : size_t bf_request_size(const struct bf_request *request)
183 : : {
184 : : bf_assert(request);
185 : :
186 : 218 : return sizeof(struct bf_request) + request->data_len;
187 : : }
188 : :
189 : 1 : int bf_request_ipt_cmd(const struct bf_request *request)
190 : : {
191 : : bf_assert(request);
192 : 1 : return request->ipt_cmd;
193 : : }
194 : :
195 : 102 : void bf_request_set_ns(struct bf_request *request, struct bf_ns *ns)
196 : : {
197 : : bf_assert(request);
198 : 102 : request->ns = ns;
199 : 102 : }
200 : :
201 : 102 : void bf_request_set_fd(struct bf_request *request, int fd)
202 : : {
203 : : bf_assert(request);
204 : 102 : request->fd = fd;
205 : 102 : }
206 : :
207 : 3 : void bf_request_set_ipt_cmd(struct bf_request *request, int ipt_cmd)
208 : : {
209 : : bf_assert(request);
210 : 3 : request->ipt_cmd = ipt_cmd;
211 : 3 : }
212 : :
213 : 117 : const char *bf_request_cmd_to_str(enum bf_request_cmd cmd)
214 : : {
215 : : static const char *cmd_strs[] = {
216 : : [BF_REQ_RULESET_FLUSH] = "BF_REQ_RULESET_FLUSH",
217 : : [BF_REQ_RULESET_GET] = "BF_REQ_RULESET_GET",
218 : : [BF_REQ_RULESET_SET] = "BF_REQ_RULESET_SET",
219 : : [BF_REQ_CHAIN_SET] = "BF_REQ_CHAIN_SET",
220 : : [BF_REQ_CHAIN_GET] = "BF_REQ_CHAIN_GET",
221 : : [BF_REQ_CHAIN_LOAD] = "BF_REQ_CHAIN_LOAD",
222 : : [BF_REQ_CHAIN_ATTACH] = "BF_REQ_CHAIN_ATTACH",
223 : : [BF_REQ_CHAIN_UPDATE] = "BF_REQ_CHAIN_UPDATE",
224 : : [BF_REQ_CHAIN_PROG_FD] = "BF_REQ_CHAIN_PROG_FD",
225 : : [BF_REQ_CHAIN_LOGS_FD] = "BF_REQ_CHAIN_LOGS_FD",
226 : : [BF_REQ_CHAIN_FLUSH] = "BF_REQ_CHAIN_FLUSH",
227 : : [BF_REQ_COUNTERS_SET] = "BF_REQ_COUNTERS_SET",
228 : : [BF_REQ_COUNTERS_GET] = "BF_REQ_COUNTERS_GET",
229 : : [BF_REQ_CUSTOM] = "BF_REQ_CUSTOM",
230 : : };
231 : :
232 : : static_assert(ARRAY_SIZE(cmd_strs) == _BF_REQ_CMD_MAX,
233 : : "missing entries in bf_request_cmd array");
234 : :
235 : 117 : return cmd_strs[cmd];
236 : : }
|