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 0 : 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 0 : _free_bf_request_ struct bf_request *_request = NULL;
63 :
64 0 : bf_assert(request);
65 0 : bf_assert(!(!!data ^ !!data_len));
66 :
67 0 : _request = calloc(1, sizeof(*_request) + data_len);
68 0 : if (!_request)
69 : return -ENOMEM;
70 :
71 0 : if (data) {
72 0 : memcpy(_request->data, data, data_len);
73 0 : _request->data_len = data_len;
74 : }
75 :
76 0 : _request->front = front;
77 0 : _request->cmd = cmd;
78 :
79 0 : *request = TAKE_PTR(_request);
80 :
81 0 : return 0;
82 : }
83 :
84 0 : int bf_request_new_from_dynbuf(struct bf_request **request,
85 : struct bf_dynbuf *dynbuf)
86 : {
87 : struct bf_request *tmpreq;
88 :
89 0 : bf_assert(request);
90 0 : bf_assert(dynbuf);
91 :
92 0 : if (dynbuf->len < sizeof(*tmpreq))
93 : return -EINVAL;
94 :
95 0 : tmpreq = dynbuf->data;
96 0 : if (bf_request_size(tmpreq) != dynbuf->len)
97 : return -EINVAL;
98 :
99 0 : *request = bf_dynbuf_take(dynbuf);
100 :
101 0 : return 0;
102 : }
103 :
104 0 : 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 0 : bf_assert(request);
112 0 : bf_assert(pack);
113 :
114 0 : if (!bf_wpack_is_valid(pack))
115 : return -EINVAL;
116 :
117 0 : r = bf_wpack_get_data(pack, &data, &data_len);
118 0 : if (r)
119 : return r;
120 :
121 0 : return bf_request_new(request, front, cmd, data, data_len);
122 : }
123 :
124 0 : int bf_request_copy(struct bf_request **dest, const struct bf_request *src)
125 : {
126 0 : _free_bf_request_ struct bf_request *_request = NULL;
127 :
128 0 : bf_assert(dest);
129 0 : bf_assert(src);
130 :
131 0 : _request = bf_memdup(src, bf_request_size(src));
132 0 : if (!_request)
133 : return -ENOMEM;
134 :
135 0 : *dest = TAKE_PTR(_request);
136 :
137 0 : return 0;
138 : }
139 :
140 0 : void bf_request_free(struct bf_request **request)
141 : {
142 0 : free(*request);
143 0 : *request = NULL;
144 0 : }
145 :
146 0 : enum bf_front bf_request_front(const struct bf_request *request)
147 : {
148 0 : bf_assert(request);
149 0 : return request->front;
150 : }
151 :
152 0 : enum bf_request_cmd bf_request_cmd(const struct bf_request *request)
153 : {
154 0 : bf_assert(request);
155 0 : return request->cmd;
156 : }
157 :
158 0 : struct bf_ns *bf_request_ns(const struct bf_request *request)
159 : {
160 0 : bf_assert(request);
161 0 : return request->ns;
162 : }
163 :
164 0 : int bf_request_fd(const struct bf_request *request)
165 : {
166 0 : bf_assert(request);
167 0 : return request->fd;
168 : }
169 :
170 0 : const void *bf_request_data(const struct bf_request *request)
171 : {
172 0 : bf_assert(request);
173 0 : return request->data;
174 : }
175 :
176 0 : size_t bf_request_data_len(const struct bf_request *request)
177 : {
178 0 : bf_assert(request);
179 0 : return request->data_len;
180 : }
181 :
182 0 : size_t bf_request_size(const struct bf_request *request)
183 : {
184 0 : bf_assert(request);
185 :
186 0 : return sizeof(struct bf_request) + request->data_len;
187 : }
188 :
189 0 : int bf_request_ipt_cmd(const struct bf_request *request)
190 : {
191 0 : bf_assert(request);
192 0 : return request->ipt_cmd;
193 : }
194 :
195 0 : void bf_request_set_ns(struct bf_request *request, struct bf_ns *ns)
196 : {
197 0 : bf_assert(request);
198 0 : request->ns = ns;
199 0 : }
200 :
201 0 : void bf_request_set_fd(struct bf_request *request, int fd)
202 : {
203 0 : bf_assert(request);
204 0 : request->fd = fd;
205 0 : }
206 :
207 0 : void bf_request_set_ipt_cmd(struct bf_request *request, int ipt_cmd)
208 : {
209 0 : bf_assert(request);
210 0 : request->ipt_cmd = ipt_cmd;
211 0 : }
212 :
213 0 : 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 0 : return cmd_strs[cmd];
236 : }
|