]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-netlink/nfnl-message.c
add ipv6 range element creation test cases
[thirdparty/systemd.git] / src / libsystemd / sd-netlink / nfnl-message.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <netinet/in.h>
4 #include <linux/if_addrlabel.h>
5 #include <linux/netfilter/nfnetlink.h>
6 #include <linux/netfilter/nf_tables.h>
7 #include <linux/nexthop.h>
8 #include <stdbool.h>
9 #include <unistd.h>
10
11 #include "sd-netlink.h"
12
13 #include "format-util.h"
14 #include "netlink-internal.h"
15 #include "netlink-types.h"
16 #include "netlink-util.h"
17 #include "socket-util.h"
18 #include "util.h"
19
20 static int nft_message_new(sd_netlink *nfnl, sd_netlink_message **ret, int family, uint16_t type, uint16_t flags) {
21 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
22 struct nfgenmsg *nfh;
23 const NLType *nl_type;
24 size_t size;
25 int r;
26
27 assert_return(nfnl, -EINVAL);
28
29 r = type_system_root_get_type(nfnl, &nl_type, NFNL_SUBSYS_NFTABLES);
30 if (r < 0)
31 return r;
32
33 if (type_get_type(nl_type) != NETLINK_TYPE_NESTED)
34 return -EINVAL;
35
36 r = message_new_empty(nfnl, &m);
37 if (r < 0)
38 return r;
39
40 size = NLMSG_SPACE(type_get_size(nl_type));
41
42 assert(size >= sizeof(struct nlmsghdr));
43 m->hdr = malloc0(size);
44 if (!m->hdr)
45 return -ENOMEM;
46
47 m->hdr->nlmsg_flags = NLM_F_REQUEST | flags;
48
49 type_get_type_system(nl_type, &m->containers[0].type_system);
50
51 r = type_system_get_type_system(m->containers[0].type_system,
52 &m->containers[0].type_system,
53 type);
54 if (r < 0)
55 return r;
56
57 m->hdr->nlmsg_len = size;
58 m->hdr->nlmsg_type = NFNL_SUBSYS_NFTABLES << 8 | type;
59
60 nfh = NLMSG_DATA(m->hdr);
61 nfh->nfgen_family = family;
62 nfh->version = NFNETLINK_V0;
63 nfh->res_id = nfnl->serial;
64
65 *ret = TAKE_PTR(m);
66 return 0;
67 }
68
69 static int sd_nfnl_message_batch(sd_netlink *nfnl, sd_netlink_message **ret, int v) {
70 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
71 struct nfgenmsg *nfh;
72 int r;
73
74 r = message_new(nfnl, &m, v);
75 if (r < 0)
76 return r;
77
78 nfh = NLMSG_DATA(m->hdr);
79 nfh->nfgen_family = AF_UNSPEC;
80 nfh->version = NFNETLINK_V0;
81 nfh->res_id = NFNL_SUBSYS_NFTABLES;
82
83 *ret = TAKE_PTR(m);
84 return r;
85 }
86
87 int sd_nfnl_message_batch_begin(sd_netlink *nfnl, sd_netlink_message **ret) {
88 return sd_nfnl_message_batch(nfnl, ret, NFNL_MSG_BATCH_BEGIN);
89 }
90
91 int sd_nfnl_message_batch_end(sd_netlink *nfnl, sd_netlink_message **ret) {
92 return sd_nfnl_message_batch(nfnl, ret, NFNL_MSG_BATCH_END);
93 }
94
95 int sd_nfnl_nft_message_new_basechain(sd_netlink *nfnl, sd_netlink_message **ret,
96 int family,
97 const char *table, const char *chain,
98 const char *type,
99 uint8_t hook, int prio) {
100 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
101 int r;
102
103 r = nft_message_new(nfnl, &m, family, NFT_MSG_NEWCHAIN, NLM_F_CREATE | NLM_F_ACK);
104 if (r < 0)
105 return r;
106
107 r = sd_netlink_message_append_string(m, NFTA_CHAIN_TABLE, table);
108 if (r < 0)
109 return r;
110
111 r = sd_netlink_message_append_string(m, NFTA_CHAIN_NAME, chain);
112 if (r < 0)
113 return r;
114
115 r = sd_netlink_message_append_string(m, NFTA_CHAIN_TYPE, type);
116 if (r < 0)
117 return r;
118
119 r = sd_netlink_message_open_container(m, NFTA_CHAIN_HOOK);
120 if (r < 0)
121 return r;
122
123 r = sd_netlink_message_append_u32(m, NFTA_HOOK_HOOKNUM, htobe32(hook));
124 if (r < 0)
125 return r;
126
127 r = sd_netlink_message_append_u32(m, NFTA_HOOK_PRIORITY, htobe32(prio));
128 if (r < 0)
129 return r;
130
131 r = sd_netlink_message_close_container(m);
132 if (r < 0)
133 return r;
134
135 *ret = TAKE_PTR(m);
136 return 0;
137 }
138
139 int sd_nfnl_nft_message_del_table(sd_netlink *nfnl, sd_netlink_message **ret,
140 int family, const char *table) {
141 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
142 int r;
143
144 r = nft_message_new(nfnl, &m, family, NFT_MSG_DELTABLE, NLM_F_CREATE | NLM_F_ACK);
145 if (r < 0)
146 return r;
147
148 r = sd_netlink_message_append_string(m, NFTA_TABLE_NAME, table);
149 if (r < 0)
150 return r;
151
152 *ret = TAKE_PTR(m);
153 return r;
154 }
155
156 int sd_nfnl_nft_message_new_table(sd_netlink *nfnl, sd_netlink_message **ret,
157 int family, const char *table, uint16_t flags) {
158 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
159 int r;
160
161 r = nft_message_new(nfnl, &m, family, NFT_MSG_NEWTABLE, NLM_F_CREATE | flags);
162 if (r < 0)
163 return r;
164
165 r = sd_netlink_message_append_string(m, NFTA_TABLE_NAME, table);
166 if (r < 0)
167 return r;
168
169 *ret = TAKE_PTR(m);
170 return r;
171 }
172
173 int sd_nfnl_nft_message_new_rule(sd_netlink *nfnl, sd_netlink_message **ret,
174 int family, const char *table, const char *chain) {
175 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
176 int r;
177
178 r = nft_message_new(nfnl, &m, family, NFT_MSG_NEWRULE, NLM_F_CREATE | NLM_F_ACK);
179 if (r < 0)
180 return r;
181
182 r = sd_netlink_message_append_string(m, NFTA_RULE_TABLE, table);
183 if (r < 0)
184 return r;
185
186 r = sd_netlink_message_append_string(m, NFTA_RULE_CHAIN, chain);
187 if (r < 0)
188 return r;
189
190 *ret = TAKE_PTR(m);
191 return r;
192 }
193
194 int sd_nfnl_nft_message_new_set(sd_netlink *nfnl, sd_netlink_message **ret,
195 int family, const char *table, const char *set_name,
196 uint32_t set_id, uint32_t klen) {
197 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
198 int r;
199
200 r = nft_message_new(nfnl, &m, family, NFT_MSG_NEWSET, NLM_F_CREATE | NLM_F_ACK);
201 if (r < 0)
202 return r;
203
204 r = sd_netlink_message_append_string(m, NFTA_SET_TABLE, table);
205 if (r < 0)
206 return r;
207
208 r = sd_netlink_message_append_string(m, NFTA_SET_NAME, set_name);
209 if (r < 0)
210 return r;
211
212 r = sd_netlink_message_append_u32(m, NFTA_SET_ID, ++set_id);
213 if (r < 0)
214 return r;
215
216 r = sd_netlink_message_append_u32(m, NFTA_SET_KEY_LEN, htobe32(klen));
217 if (r < 0)
218 return r;
219 *ret = TAKE_PTR(m);
220 return r;
221 }
222
223 int sd_nfnl_nft_message_new_setelems_begin(sd_netlink *nfnl, sd_netlink_message **ret,
224 int family, const char *table, const char *set_name) {
225 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
226 int r;
227
228 r = nft_message_new(nfnl, &m, family, NFT_MSG_NEWSETELEM, NLM_F_CREATE | NLM_F_ACK);
229 if (r < 0)
230 return r;
231
232 r = sd_netlink_message_append_string(m, NFTA_SET_ELEM_LIST_TABLE, table);
233 if (r < 0)
234 return r;
235
236 r = sd_netlink_message_append_string(m, NFTA_SET_ELEM_LIST_SET, set_name);
237 if (r < 0)
238 return r;
239
240 r = sd_netlink_message_open_container(m, NFTA_SET_ELEM_LIST_ELEMENTS);
241 if (r < 0)
242 return r;
243
244 *ret = TAKE_PTR(m);
245 return r;
246 }
247
248 int sd_nfnl_nft_message_del_setelems_begin(sd_netlink *nfnl, sd_netlink_message **ret,
249 int family, const char *table, const char *set_name) {
250 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
251 int r;
252
253 r = nft_message_new(nfnl, &m, family, NFT_MSG_DELSETELEM, NLM_F_ACK);
254 if (r < 0)
255 return r;
256
257 r = sd_netlink_message_append_string(m, NFTA_SET_ELEM_LIST_TABLE, table);
258 if (r < 0)
259 return r;
260
261 r = sd_netlink_message_append_string(m, NFTA_SET_ELEM_LIST_SET, set_name);
262 if (r < 0)
263 return r;
264
265 r = sd_netlink_message_open_container(m, NFTA_SET_ELEM_LIST_ELEMENTS);
266 if (r < 0)
267 return r;
268
269 *ret = TAKE_PTR(m);
270 return r;
271 }
272
273 static int sd_nfnl_add_data(sd_netlink_message *m, uint16_t attr, const void *data, uint32_t dlen) {
274 int r = sd_netlink_message_open_container(m, attr);
275 if (r < 0)
276 return r;
277
278 r = sd_netlink_message_append_data(m, NFTA_DATA_VALUE, data, dlen);
279 if (r < 0)
280 return r;
281
282 return sd_netlink_message_close_container(m); /* attr */
283 }
284
285 int sd_nfnl_nft_message_add_setelem(sd_netlink_message *m, uint32_t num,
286 const void *key, uint32_t klen,
287 const void *data, uint32_t dlen) {
288 int r;
289
290 r = sd_netlink_message_open_array(m, num);
291 if (r < 0)
292 return r;
293
294 r = sd_nfnl_add_data(m, NFTA_SET_ELEM_KEY, key, klen);
295 if (r < 0)
296 goto cancel;
297
298 if (data) {
299 r = sd_nfnl_add_data(m, NFTA_SET_ELEM_DATA, data, dlen);
300 if (r < 0)
301 goto cancel;
302 }
303
304 return r;
305 cancel:
306 sd_netlink_message_cancel_array(m);
307 return r;
308 }
309
310 int sd_nfnl_nft_message_add_setelem_end(sd_netlink_message *m) {
311 return sd_netlink_message_close_container(m); /* NFTA_SET_ELEM_LIST_ELEMENTS */
312 }
313
314 int sd_nfnl_socket_open(sd_netlink **ret) {
315 return netlink_open_family(ret, NETLINK_NETFILTER);
316 }