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 
27 static int seq;
28 
29 static void memory_allocation_error(void)
30 {
31  perror("OOM");
32  exit(EXIT_FAILURE);
33 }
34 
35 static int
36 mnl_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  }
54 out:
55  if (ret < 0 && errno == EAGAIN)
56  return 0;
57 
58  return ret;
59 }
60 
61 /*
62  * Rule
63  */
64 static 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 
79 err_free:
80  nftnl_rule_free(r);
81  return MNL_CB_OK;
82 }
83 
84 static 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;
104 err:
105  nftnl_rule_list_free(nlr_list);
106  return NULL;
107 }
108 
109 /*
110  * Chain
111  */
112 static 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 
127 err_free:
128  nftnl_chain_free(c);
129  return MNL_CB_OK;
130 }
131 
132 static 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;
152 err:
153  nftnl_chain_list_free(nlc_list);
154  return NULL;
155 }
156 
157 /*
158  * Table
159  */
160 static 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 
175 err_free:
176  nftnl_table_free(t);
177  return MNL_CB_OK;
178 }
179 
180 static 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;
200 err:
201  nftnl_table_list_free(nlt_list);
202  return NULL;
203 }
204 
205 /*
206  * Set elements
207  */
208 static 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 
214 static 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  */
230 static 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 
245 err_free:
246  nftnl_set_free(s);
247  return MNL_CB_OK;
248 }
249 
250 static struct nftnl_set_list *
251 mnl_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;
295 err:
296  nftnl_set_list_free(nls_list);
297  return NULL;
298 }
299 
300 /*
301  * ruleset
302  */
303 
304 static 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 
335 int 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 }