libnftnl 1.2.9
nft-ruleset-get.c
1/* SPDX-License-Identifier: GPL-2.0-or-later */
2/*
3 * Copyright (c) 2013 Arturo Borrero Gonzalez <arturo@debian.org>
4 *
5 * based on previous code from:
6 *
7 * Copyright (c) 2013 Pablo Neira Ayuso <pablo@netfilter.org>
8 */
9
10#include <stdlib.h>
11#include <time.h>
12#include <string.h>
13#include <netinet/in.h>
14#include <errno.h>
15
16#include <linux/netfilter.h>
17#include <linux/netfilter/nf_tables.h>
18
19#include <libmnl/libmnl.h>
20#include <libnftnl/common.h>
21#include <libnftnl/ruleset.h>
22#include <libnftnl/table.h>
23#include <libnftnl/chain.h>
24#include <libnftnl/set.h>
25#include <libnftnl/rule.h>
26
27static int seq;
28
29static void memory_allocation_error(void)
30{
31 perror("OOM");
32 exit(EXIT_FAILURE);
33}
34
35static int
36mnl_talk(struct mnl_socket *nf_sock, const void *data, unsigned int len,
37 int (*cb)(const struct nlmsghdr *nlh, void *data), void *cb_data)
38{
39 char buf[MNL_SOCKET_BUFFER_SIZE];
40 uint32_t portid = mnl_socket_get_portid(nf_sock);
41 int ret;
42
43 if (mnl_socket_sendto(nf_sock, data, len) < 0)
44 return -1;
45
46 ret = mnl_socket_recvfrom(nf_sock, buf, sizeof(buf));
47 while (ret > 0) {
48 ret = mnl_cb_run(buf, ret, seq, portid, cb, cb_data);
49 if (ret <= 0)
50 goto out;
51
52 ret = mnl_socket_recvfrom(nf_sock, buf, sizeof(buf));
53 }
54out:
55 if (ret < 0 && errno == EAGAIN)
56 return 0;
57
58 return ret;
59}
60
61/*
62 * Rule
63 */
64static int rule_cb(const struct nlmsghdr *nlh, void *data)
65{
66 struct nftnl_rule_list *nlr_list = data;
67 struct nftnl_rule *r;
68
69 r = nftnl_rule_alloc();
70 if (r == NULL)
71 memory_allocation_error();
72
73 if (nftnl_rule_nlmsg_parse(nlh, r) < 0)
74 goto err_free;
75
76 nftnl_rule_list_add_tail(r, nlr_list);
77 return MNL_CB_OK;
78
79err_free:
80 nftnl_rule_free(r);
81 return MNL_CB_OK;
82}
83
84static struct nftnl_rule_list *mnl_rule_dump(struct mnl_socket *nf_sock,
85 int family)
86{
87 char buf[MNL_SOCKET_BUFFER_SIZE];
88 struct nlmsghdr *nlh;
89 struct nftnl_rule_list *nlr_list;
90 int ret;
91
92 nlr_list = nftnl_rule_list_alloc();
93 if (nlr_list == NULL)
94 memory_allocation_error();
95
96 nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETRULE, family,
97 NLM_F_DUMP, seq);
98
99 ret = mnl_talk(nf_sock, nlh, nlh->nlmsg_len, rule_cb, nlr_list);
100 if (ret < 0)
101 goto err;
102
103 return nlr_list;
104err:
105 nftnl_rule_list_free(nlr_list);
106 return NULL;
107}
108
109/*
110 * Chain
111 */
112static int chain_cb(const struct nlmsghdr *nlh, void *data)
113{
114 struct nftnl_chain_list *nlc_list = data;
115 struct nftnl_chain *c;
116
117 c = nftnl_chain_alloc();
118 if (c == NULL)
119 memory_allocation_error();
120
121 if (nftnl_chain_nlmsg_parse(nlh, c) < 0)
122 goto err_free;
123
124 nftnl_chain_list_add_tail(c, nlc_list);
125 return MNL_CB_OK;
126
127err_free:
128 nftnl_chain_free(c);
129 return MNL_CB_OK;
130}
131
132static struct nftnl_chain_list *mnl_chain_dump(struct mnl_socket *nf_sock,
133 int family)
134{
135 char buf[MNL_SOCKET_BUFFER_SIZE];
136 struct nlmsghdr *nlh;
137 struct nftnl_chain_list *nlc_list;
138 int ret;
139
140 nlc_list = nftnl_chain_list_alloc();
141 if (nlc_list == NULL)
142 memory_allocation_error();
143
144 nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETCHAIN, family,
145 NLM_F_DUMP, seq);
146
147 ret = mnl_talk(nf_sock, nlh, nlh->nlmsg_len, chain_cb, nlc_list);
148 if (ret < 0)
149 goto err;
150
151 return nlc_list;
152err:
153 nftnl_chain_list_free(nlc_list);
154 return NULL;
155}
156
157/*
158 * Table
159 */
160static int table_cb(const struct nlmsghdr *nlh, void *data)
161{
162 struct nftnl_table_list *nlt_list = data;
163 struct nftnl_table *t;
164
165 t = nftnl_table_alloc();
166 if (t == NULL)
167 memory_allocation_error();
168
169 if (nftnl_table_nlmsg_parse(nlh, t) < 0)
170 goto err_free;
171
172 nftnl_table_list_add_tail(t, nlt_list);
173 return MNL_CB_OK;
174
175err_free:
176 nftnl_table_free(t);
177 return MNL_CB_OK;
178}
179
180static struct nftnl_table_list *mnl_table_dump(struct mnl_socket *nf_sock,
181 int family)
182{
183 char buf[MNL_SOCKET_BUFFER_SIZE];
184 struct nlmsghdr *nlh;
185 struct nftnl_table_list *nlt_list;
186 int ret;
187
188 nlt_list = nftnl_table_list_alloc();
189 if (nlt_list == NULL)
190 memory_allocation_error();
191
192 nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETTABLE, family,
193 NLM_F_DUMP, seq);
194
195 ret = mnl_talk(nf_sock, nlh, nlh->nlmsg_len, table_cb, nlt_list);
196 if (ret < 0)
197 goto err;
198
199 return nlt_list;
200err:
201 nftnl_table_list_free(nlt_list);
202 return NULL;
203}
204
205/*
206 * Set elements
207 */
208static int set_elem_cb(const struct nlmsghdr *nlh, void *data)
209{
210 nftnl_set_elems_nlmsg_parse(nlh, data);
211 return MNL_CB_OK;
212}
213
214static int mnl_setelem_get(struct mnl_socket *nf_sock, struct nftnl_set *nls)
215{
216 char buf[MNL_SOCKET_BUFFER_SIZE];
217 struct nlmsghdr *nlh;
218 uint32_t family = nftnl_set_get_u32(nls, NFTNL_SET_FAMILY);
219
220 nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETSETELEM, family,
221 NLM_F_DUMP | NLM_F_ACK, seq);
222 nftnl_set_nlmsg_build_payload(nlh, nls);
223
224 return mnl_talk(nf_sock, nlh, nlh->nlmsg_len, set_elem_cb, nls);
225}
226
227/*
228 * Set
229 */
230static int set_cb(const struct nlmsghdr *nlh, void *data)
231{
232 struct nftnl_set_list *nls_list = data;
233 struct nftnl_set *s;
234
235 s = nftnl_set_alloc();
236 if (s == NULL)
237 memory_allocation_error();
238
239 if (nftnl_set_nlmsg_parse(nlh, s) < 0)
240 goto err_free;
241
242 nftnl_set_list_add_tail(s, nls_list);
243 return MNL_CB_OK;
244
245err_free:
246 nftnl_set_free(s);
247 return MNL_CB_OK;
248}
249
250static struct nftnl_set_list *
251mnl_set_dump(struct mnl_socket *nf_sock, int family)
252{
253 char buf[MNL_SOCKET_BUFFER_SIZE];
254 struct nlmsghdr *nlh;
255 struct nftnl_set *s;
256 struct nftnl_set_list *nls_list;
257 struct nftnl_set *si;
258 struct nftnl_set_list_iter *i;
259 int ret;
260
261 s = nftnl_set_alloc();
262 if (s == NULL)
263 memory_allocation_error();
264
265 nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETSET, family,
266 NLM_F_DUMP | NLM_F_ACK, seq);
267 nftnl_set_nlmsg_build_payload(nlh, s);
268 nftnl_set_free(s);
269
270 nls_list = nftnl_set_list_alloc();
271 if (nls_list == NULL)
272 memory_allocation_error();
273
274 ret = mnl_talk(nf_sock, nlh, nlh->nlmsg_len, set_cb, nls_list);
275 if (ret < 0)
276 goto err;
277
278 i = nftnl_set_list_iter_create(nls_list);
279 if (i == NULL)
280 memory_allocation_error();
281
282 si = nftnl_set_list_iter_next(i);
283 while (si != NULL) {
284 if (mnl_setelem_get(nf_sock, si) != 0) {
285 perror("E: Unable to get set elements");
286 nftnl_set_list_iter_destroy(i);
287 goto err;
288 }
289 si = nftnl_set_list_iter_next(i);
290 }
291
292 nftnl_set_list_iter_destroy(i);
293
294 return nls_list;
295err:
296 nftnl_set_list_free(nls_list);
297 return NULL;
298}
299
300/*
301 * ruleset
302 */
303
304static struct nftnl_ruleset *mnl_ruleset_dump(struct mnl_socket *nf_sock)
305{
306 struct nftnl_ruleset *rs;
307 struct nftnl_table_list *t;
308 struct nftnl_chain_list *c;
309 struct nftnl_set_list *s;
310 struct nftnl_rule_list *r;
311
312 rs = nftnl_ruleset_alloc();
313 if (rs == NULL)
314 memory_allocation_error();
315
316 t = mnl_table_dump(nf_sock, NFPROTO_UNSPEC);
317 if (t != NULL)
318 nftnl_ruleset_set(rs, NFTNL_RULESET_TABLELIST, t);
319
320 c = mnl_chain_dump(nf_sock, NFPROTO_UNSPEC);
321 if (c != NULL)
322 nftnl_ruleset_set(rs, NFTNL_RULESET_CHAINLIST, c);
323
324 s = mnl_set_dump(nf_sock, NFPROTO_UNSPEC);
325 if (s != NULL)
326 nftnl_ruleset_set(rs, NFTNL_RULESET_SETLIST, s);
327
328 r = mnl_rule_dump(nf_sock, NFPROTO_UNSPEC);
329 if (r != NULL)
330 nftnl_ruleset_set(rs, NFTNL_RULESET_RULELIST, r);
331
332 return rs;
333}
334
335int main(int argc, char *argv[])
336{
337 struct mnl_socket *nl;
338 uint32_t type = NFTNL_OUTPUT_DEFAULT;
339 struct nftnl_ruleset *rs;
340 int ret;
341
342 if (argc > 2) {
343 fprintf(stderr, "%s\n", argv[0]);
344 exit(EXIT_FAILURE);
345 }
346
347 nl = mnl_socket_open(NETLINK_NETFILTER);
348 if (nl == NULL) {
349 perror("mnl_socket_open");
350 exit(EXIT_FAILURE);
351 }
352
353 if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
354 perror("mnl_socket_bind");
355 exit(EXIT_FAILURE);
356 }
357
358 seq = time(NULL);
359
360 rs = mnl_ruleset_dump(nl);
361 if (rs == NULL) {
362 perror("ruleset_dump");
363 exit(EXIT_FAILURE);
364 }
365
366 ret = nftnl_ruleset_fprintf(stdout, rs, type, 0);
367 fprintf(stdout, "\n");
368
369 if (ret == -1)
370 perror("E: Error during fprintf operations");
371
372 return 0;
373}