Line data Source code
1 : /* SPDX-License-Identifier: GPL-2.0-only */
2 : /*
3 : * Copyright (c) 2022 Meta Platforms, Inc. and affiliates.
4 : */
5 :
6 : #include "bpfilter/xlate/nft/nfmsg.h"
7 :
8 : #include <linux/netfilter/nf_tables.h>
9 : #include <linux/netfilter/nfnetlink.h>
10 : #include <linux/netlink.h>
11 :
12 : #include <errno.h>
13 : #include <libnl3/netlink/attr.h>
14 : #include <limits.h>
15 : #include <netlink/msg.h>
16 : #include <stdbool.h>
17 : #include <stddef.h>
18 : #include <stdint.h>
19 : #include <stdlib.h>
20 : #include <sys/socket.h>
21 :
22 : #include "core/helper.h"
23 : #include "core/logger.h"
24 :
25 : struct bf_nfmsg
26 : {
27 : struct nl_msg *msg;
28 : };
29 :
30 : static const struct nla_policy _bf_nf_table_policy[__NFTA_TABLE_MAX] = {
31 : [NFTA_TABLE_NAME] = {.type = NLA_STRING},
32 : [NFTA_TABLE_FLAGS] = {.type = NLA_U32},
33 : [NFTA_TABLE_HANDLE] = {.type = NLA_U64},
34 : [NFTA_TABLE_USERDATA] = {.type = NLA_BINARY},
35 : };
36 : const bf_nfpolicy *bf_nf_table_policy = _bf_nf_table_policy;
37 :
38 : static const struct nla_policy _bf_nf_chain_policy[__NFTA_CHAIN_MAX] = {
39 : [NFTA_CHAIN_TABLE] = {.type = NLA_STRING},
40 : [NFTA_CHAIN_HANDLE] = {.type = NLA_U64},
41 : [NFTA_CHAIN_NAME] = {.type = NLA_STRING},
42 : [NFTA_CHAIN_HOOK] = {.type = NLA_NESTED},
43 : [NFTA_CHAIN_POLICY] = {.type = NLA_U32},
44 : [NFTA_CHAIN_TYPE] = {.type = NLA_STRING},
45 : [NFTA_CHAIN_COUNTERS] = {.type = NLA_NESTED},
46 : [NFTA_CHAIN_FLAGS] = {.type = NLA_U32},
47 : [NFTA_CHAIN_ID] = {.type = NLA_U32},
48 : [NFTA_CHAIN_USERDATA] = {.type = NLA_BINARY},
49 : };
50 : const bf_nfpolicy *bf_nf_chain_policy = _bf_nf_chain_policy;
51 :
52 : static const struct nla_policy _bf_nf_hook_policy[__NFTA_HOOK_MAX] = {
53 : [NFTA_HOOK_HOOKNUM] = {.type = NLA_U32},
54 : [NFTA_HOOK_PRIORITY] = {.type = NLA_U32},
55 : [NFTA_HOOK_DEV] = {.type = NLA_STRING},
56 : };
57 : const bf_nfpolicy *bf_nf_hook_policy = _bf_nf_hook_policy;
58 :
59 : static const struct nla_policy _bf_nf_rule_policy[__NFTA_RULE_MAX] = {
60 : [NFTA_RULE_TABLE] = {.type = NLA_STRING},
61 : [NFTA_RULE_CHAIN] = {.type = NLA_STRING},
62 : [NFTA_RULE_HANDLE] = {.type = NLA_U64},
63 : [NFTA_RULE_EXPRESSIONS] = {.type = NLA_NESTED},
64 : [NFTA_RULE_COMPAT] = {.type = NLA_NESTED},
65 : [NFTA_RULE_POSITION] = {.type = NLA_U64},
66 : [NFTA_RULE_USERDATA] = {.type = NLA_BINARY},
67 : [NFTA_RULE_ID] = {.type = NLA_U32},
68 : [NFTA_RULE_POSITION_ID] = {.type = NLA_U32},
69 : [NFTA_RULE_CHAIN_ID] = {.type = NLA_U32},
70 : };
71 : const bf_nfpolicy *bf_nf_rule_policy = _bf_nf_rule_policy;
72 :
73 : static const struct nla_policy _bf_nf_expr_policy[__NFTA_EXPR_MAX] = {
74 : [NFTA_EXPR_NAME] = {.type = NLA_STRING},
75 : [NFTA_EXPR_DATA] = {.type = NLA_NESTED},
76 : };
77 : const bf_nfpolicy *bf_nf_expr_policy = _bf_nf_expr_policy;
78 :
79 : static const struct nla_policy _bf_nf_counter_policy[NFTA_COUNTER_MAX + 1] = {
80 : [NFTA_COUNTER_PACKETS] = {.type = NLA_U64},
81 : [NFTA_COUNTER_BYTES] = {.type = NLA_U64},
82 : };
83 : const bf_nfpolicy *bf_nf_counter_policy = _bf_nf_counter_policy;
84 :
85 : static const struct nla_policy _bf_nf_payload_policy[__NFTA_PAYLOAD_MAX] = {
86 : [NFTA_PAYLOAD_SREG] = {.type = NLA_U32},
87 : [NFTA_PAYLOAD_DREG] = {.type = NLA_U32},
88 : [NFTA_PAYLOAD_BASE] = {.type = NLA_U32},
89 : [NFTA_PAYLOAD_OFFSET] = {.type = NLA_U32},
90 : [NFTA_PAYLOAD_LEN] = {.type = NLA_U32},
91 : [NFTA_PAYLOAD_CSUM_TYPE] = {.type = NLA_U32},
92 : [NFTA_PAYLOAD_CSUM_OFFSET] = {.type = NLA_U32},
93 : [NFTA_PAYLOAD_CSUM_FLAGS] = {.type = NLA_U32},
94 : };
95 : const bf_nfpolicy *bf_nf_payload_policy = _bf_nf_payload_policy;
96 :
97 : static const struct nla_policy _bf_nf_cmp_policy[__NFTA_CMP_MAX] = {
98 : [NFTA_CMP_SREG] = {.type = NLA_U32},
99 : [NFTA_CMP_OP] = {.type = NLA_U32},
100 : [NFTA_CMP_DATA] = {.type = NLA_NESTED},
101 : };
102 : const bf_nfpolicy *bf_nf_cmp_policy = _bf_nf_cmp_policy;
103 :
104 : static const struct nla_policy _bf_nf_immediate_policy[__NFTA_IMMEDIATE_MAX] = {
105 : [NFTA_IMMEDIATE_DREG] = {.type = NLA_U32},
106 : [NFTA_IMMEDIATE_DATA] = {.type = NLA_NESTED},
107 : };
108 : const bf_nfpolicy *bf_nf_immediate_policy = _bf_nf_immediate_policy;
109 :
110 : static const struct nla_policy _bf_nf_data_policy[__NFTA_DATA_MAX] = {
111 : [NFTA_DATA_VALUE] = {.type = NLA_BINARY},
112 : [NFTA_DATA_VERDICT] = {.type = NLA_NESTED},
113 : };
114 : const bf_nfpolicy *bf_nf_data_policy = _bf_nf_data_policy;
115 :
116 : static const struct nla_policy _bf_nf_verdict_policy[__NFTA_VERDICT_MAX] = {
117 : [NFTA_VERDICT_CODE] = {.type = NLA_U32},
118 : [NFTA_VERDICT_CHAIN] = {.type = NLA_STRING},
119 : [NFTA_VERDICT_CHAIN_ID] = {.type = NLA_U32},
120 : };
121 : const bf_nfpolicy *bf_nf_verdict_policy = _bf_nf_verdict_policy;
122 :
123 32 : int bf_nfmsg_new(struct bf_nfmsg **msg, uint8_t command, uint32_t seqnr)
124 : {
125 32 : bf_assert(msg);
126 :
127 31 : _cleanup_bf_nfmsg_ struct bf_nfmsg *_msg = NULL;
128 : struct nlmsghdr *nlh;
129 31 : struct nfgenmsg extra_hdr = {
130 : .nfgen_family = AF_INET,
131 : .version = NFNETLINK_V0,
132 : .res_id = 0,
133 : };
134 : int r;
135 :
136 31 : _msg = calloc(1, sizeof(*_msg));
137 31 : if (!_msg)
138 : return -ENOMEM;
139 :
140 30 : _msg->msg = nlmsg_alloc();
141 30 : if (!_msg->msg)
142 : return -ENOMEM;
143 :
144 29 : nlh = nlmsg_put(_msg->msg, 0, seqnr, NFNL_SUBSYS_NFTABLES << 8 | command, 0,
145 : 0);
146 29 : if (!nlh)
147 1 : return bf_err_r(-ENOMEM, "failed to insert Netlink header");
148 :
149 28 : r = nlmsg_append(_msg->msg, &extra_hdr, sizeof(extra_hdr), NLMSG_ALIGNTO);
150 28 : if (r)
151 1 : return bf_err_r(r, "failed to insert Netfilter extra header");
152 :
153 27 : *msg = TAKE_PTR(_msg);
154 :
155 27 : return 0;
156 : }
157 :
158 8 : int bf_nfmsg_new_done(struct bf_nfmsg **msg)
159 : {
160 8 : bf_assert(msg);
161 :
162 7 : _cleanup_bf_nfmsg_ struct bf_nfmsg *_msg = NULL;
163 : struct nlmsghdr *nlh;
164 7 : struct nfgenmsg extra_hdr = {
165 : .nfgen_family = AF_INET,
166 : .version = NFNETLINK_V0,
167 : .res_id = 0,
168 : };
169 : int r;
170 :
171 7 : _msg = calloc(1, sizeof(*_msg));
172 7 : if (!_msg)
173 : return -ENOMEM;
174 :
175 6 : _msg->msg = nlmsg_alloc();
176 6 : if (!_msg->msg)
177 : return -ENOMEM;
178 :
179 5 : nlh = nlmsg_put(_msg->msg, 0, 0, NLMSG_DONE, 0, NLM_F_MULTI);
180 5 : if (!nlh)
181 1 : return bf_err_r(-ENOMEM, "failed to insert Netlink header");
182 :
183 4 : r = nlmsg_append(_msg->msg, &extra_hdr, sizeof(extra_hdr), NLMSG_ALIGNTO);
184 4 : if (r)
185 1 : return bf_err_r(r, "failed to insert Netfilter extra header");
186 :
187 3 : *msg = TAKE_PTR(_msg);
188 :
189 3 : return 0;
190 : }
191 :
192 64 : int bf_nfmsg_new_from_nlmsghdr(struct bf_nfmsg **msg, struct nlmsghdr *nlh)
193 : {
194 64 : bf_assert(msg);
195 63 : bf_assert(nlh);
196 :
197 62 : _cleanup_bf_nfmsg_ struct bf_nfmsg *_msg = NULL;
198 :
199 62 : if (nlh->nlmsg_type >> 8 != NFNL_SUBSYS_NFTABLES) {
200 1 : return bf_err_r(-EINVAL, "invalid Netlink message type: %u",
201 : nlh->nlmsg_type);
202 : }
203 :
204 61 : if ((size_t)nlmsg_datalen(nlh) < sizeof(struct nfgenmsg)) {
205 0 : return bf_err_r(-EINVAL, "invalid Netlink message payload size: %d",
206 : nlmsg_datalen(nlh));
207 : }
208 :
209 61 : _msg = calloc(1, sizeof(*_msg));
210 61 : if (!_msg)
211 : return -ENOMEM;
212 :
213 60 : _msg->msg = nlmsg_convert(nlh);
214 60 : if (!_msg->msg)
215 : return -ENOMEM;
216 :
217 59 : *msg = TAKE_PTR(_msg);
218 :
219 59 : return 0;
220 : }
221 :
222 279 : void bf_nfmsg_free(struct bf_nfmsg **msg)
223 : {
224 279 : bf_assert(msg);
225 :
226 278 : if (!*msg)
227 : return;
228 :
229 96 : nlmsg_free((*msg)->msg);
230 96 : free(*msg);
231 96 : *msg = NULL;
232 : }
233 :
234 110 : struct nlmsghdr *bf_nfmsg_hdr(const struct bf_nfmsg *msg)
235 : {
236 110 : bf_assert(msg);
237 :
238 109 : return nlmsg_hdr(msg->msg);
239 : }
240 :
241 83 : size_t bf_nfmsg_data_len(const struct bf_nfmsg *msg)
242 : {
243 83 : bf_assert(msg);
244 :
245 83 : return nlmsg_datalen(bf_nfmsg_hdr(msg));
246 : }
247 :
248 79 : size_t bf_nfmsg_len(const struct bf_nfmsg *msg)
249 : {
250 79 : bf_assert(msg);
251 :
252 79 : return nlmsg_total_size((int)bf_nfmsg_data_len(msg));
253 : }
254 :
255 5 : uint8_t bf_nfmsg_command(const struct bf_nfmsg *msg)
256 : {
257 5 : bf_assert(msg);
258 :
259 4 : return bf_nfmsg_hdr(msg)->nlmsg_type & 0xff;
260 : }
261 :
262 5 : uint32_t bf_nfmsg_seqnr(const struct bf_nfmsg *msg)
263 : {
264 5 : bf_assert(msg);
265 :
266 4 : return bf_nfmsg_hdr(msg)->nlmsg_seq;
267 : }
268 :
269 12 : int bf_nfmsg_attr_push(struct bf_nfmsg *msg, uint16_t type, const void *data,
270 : size_t len)
271 : {
272 12 : bf_assert(msg);
273 11 : bf_assert(data);
274 :
275 10 : return nla_put(msg->msg, type, (int)len, data);
276 : }
277 :
278 1 : int bf_nfmsg_parse(const struct bf_nfmsg *msg, bf_nfattr **attrs, int maxtype,
279 : const bf_nfpolicy *policy)
280 : {
281 1 : bf_assert(msg);
282 1 : bf_assert(attrs);
283 :
284 1 : return nlmsg_parse(bf_nfmsg_hdr(msg), sizeof(struct nfgenmsg), attrs,
285 : maxtype - 1, policy);
286 : }
287 :
288 1 : int bf_nfattr_parse(bf_nfattr *attr, bf_nfattr **attrs, int maxtype,
289 : const bf_nfpolicy *policy)
290 : {
291 1 : bf_assert(attr);
292 1 : bf_assert(attrs);
293 :
294 1 : return nla_parse_nested(attrs, maxtype - 1, attr, policy);
295 : }
296 :
297 10 : void *bf_nfattr_data(bf_nfattr *attr)
298 : {
299 10 : bf_assert(attr);
300 :
301 10 : return nla_data(attr);
302 : }
303 :
304 0 : size_t bf_nfattr_data_len(bf_nfattr *attr)
305 : {
306 0 : bf_assert(attr);
307 :
308 0 : return (size_t)nla_len(attr);
309 : }
310 :
311 0 : bool bf_nfattr_is_ok(bf_nfattr *attr, size_t remaining)
312 : {
313 0 : bf_assert(attr);
314 0 : bf_assert(remaining < INT_MAX);
315 :
316 0 : return nla_ok(attr, (int)remaining);
317 : }
318 :
319 0 : bf_nfattr *bf_nfattr_next(bf_nfattr *attr, size_t *remaining)
320 : {
321 0 : bf_assert(attr);
322 0 : bf_assert(remaining && *remaining < INT_MAX);
323 :
324 0 : int _remaining = (int)*remaining;
325 :
326 0 : attr = nla_next(attr, &_remaining);
327 0 : *remaining = (size_t)_remaining;
328 :
329 0 : return attr;
330 : }
331 :
332 3 : int bf_nfmsg_nest_init(struct bf_nfnest *nest, struct bf_nfmsg *parent,
333 : uint16_t type)
334 : {
335 3 : bf_assert(nest);
336 2 : bf_assert(parent);
337 :
338 : bf_nfattr *attr;
339 :
340 1 : attr = nla_nest_start(parent->msg, type);
341 1 : if (!attr)
342 : return -ENOMEM;
343 :
344 1 : nest->attr = attr;
345 1 : nest->parent = parent;
346 :
347 1 : return 0;
348 : }
349 :
350 1 : void bf_nfnest_cleanup(struct bf_nfnest *nest)
351 : {
352 1 : bf_assert(nest);
353 :
354 1 : nla_nest_end(nest->parent->msg, nest->attr);
355 1 : }
|