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