Nftables  0.9
Nftables like the firewall for Linux but next generation
libnftables.c
1 /*
2  * Copyright (c) 2017 Eric Leblond <eric@regit.org>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  *
8  */
9 
42 #include <string.h>
43 #include <errno.h>
44 #include <nftables.h>
45 #include <parser.h>
46 #include <iface.h>
47 #include <netlink.h>
48 #include <erec.h>
49 #include <libmnl/libmnl.h>
50 #include <mnl.h>
51 #include <netlink.h>
52 #include <nftables_common.h>
53 
54 #include <nftables/nftables.h>
55 
56 #include <unistd.h>
57 #include <fcntl.h>
58 
59 
60 unsigned int max_errors = 1;
61 #ifdef DEBUG
62 unsigned int debug_level;
63 #endif
64 
65 const char *include_paths[INCLUDE_PATHS_MAX] = { DEFAULT_INCLUDE_PATH };
66 
73 void nft_global_init(void)
74 {
75  mark_table_init();
76  realm_table_rt_init();
77  devgroup_table_init();
78  realm_table_meta_init();
79  ct_label_table_init();
80  gmp_init();
81 #ifdef HAVE_LIBXTABLES
82  xt_init();
83 #endif
84 }
85 
92 {
93  iface_cache_release();
94  ct_label_table_exit();
95  realm_table_rt_exit();
96  devgroup_table_exit();
97  realm_table_meta_exit();
98  mark_table_exit();
99 }
100 
110 int nft_global_set_max_errors(unsigned int errors)
111 {
112  max_errors = errors;
113  return NFT_EXIT_SUCCESS;
114 }
115 
116 __attribute__((format(printf, 2, 0)))
117 static int nft_print(void *ctx, const char *fmt, ...)
118 {
119  va_list arg;
120  va_start(arg, fmt);
121  vfprintf(stdout, fmt, arg);
122  va_end(arg);
123 
124  return 0;
125 }
126 
132 struct nft_ctx *nft_context_new(void)
133 {
134  struct nft_ctx *ctx = NULL;
135  ctx = calloc(1, sizeof(struct nft_ctx));
136  if (ctx == NULL)
137  return NULL;
138 
139  memset(ctx, 0, sizeof(*ctx));
140  ctx->nf_sock = netlink_open_sock();
141 
142  init_list_head(&ctx->cache.list);
143  init_list_head(&ctx->output.msgs);
144 
145  ctx->output.ctx = ctx;
146  ctx->output.print = nft_print;
147  return ctx;
148 }
149 
160 void nft_context_set_print_func(struct nft_ctx *nft,
161  int (*print)(void *ctx, const char *fmt, ...),
162  void *ctx)
163 {
164  if (nft) {
165  nft->output.print = print;
166  nft->output.ctx = ctx;
167  }
168 }
169 
175 void nft_context_free(struct nft_ctx *nft)
176 {
177  if (nft == NULL)
178  return;
179  netlink_close_sock(nft->nf_sock);
180  cache_release(&nft->cache);
181  erec_free_list(&nft->output.msgs);
182  xfree(nft);
183 }
184 
185 static const struct input_descriptor indesc_cmdline = {
186  .type = INDESC_BUFFER,
187  .name = "<cmdline>",
188 };
189 
195 int nft_get_error(struct nft_ctx *nft, char *err_buf, size_t err_buf_len)
196 {
197  FILE *errfile = fmemopen(err_buf, err_buf_len, "w");
198  *err_buf = '\0';
199  erec_print_list(errfile, &nft->output.msgs);
200  fclose(errfile);
201  if (!strlen(err_buf))
202  return NFT_EXIT_FAILURE;
203  return NFT_EXIT_SUCCESS;
204 }
205 
206 
237 int nft_run_command_from_buffer(struct nft_ctx *nft,
238  char *buf, size_t buflen)
239 {
240  int rc = NFT_EXIT_SUCCESS;
241  struct parser_state state;
242  void *scanner;
243 
244  parser_init(nft->nf_sock, &nft->cache, &state, &nft->output.msgs);
245  scanner = scanner_init(&state);
246  scanner_push_buffer(scanner, &indesc_cmdline, buf);
247 
248  if (nft_run(nft, nft->nf_sock, &nft->cache, scanner,
249  &state, &nft->output.msgs) != 0)
250  rc = NFT_EXIT_FAILURE;
251 
252  scanner_destroy(scanner);
253  return rc;
254 }
255 
276 int nft_run_command_from_filename(struct nft_ctx *nft, const char *filename)
277 {
278  int rc = NFT_EXIT_SUCCESS;
279  struct parser_state state;
280  LIST_HEAD(msgs);
281  void *scanner;
282 
283  rc = cache_update(nft->nf_sock, &nft->cache, CMD_INVALID, &msgs);
284  if (rc < 0)
285  return rc;
286  parser_init(nft->nf_sock, &nft->cache, &state, &nft->output.msgs);
287  scanner = scanner_init(&state);
288  if (scanner_read_file(scanner, filename, &internal_location) < 0)
289  return NFT_EXIT_FAILURE;
290  if (nft_run(nft, nft->nf_sock, &nft->cache, scanner,
291  &state, &nft->output.msgs) != 0)
292  rc = NFT_EXIT_FAILURE;
293 
294  scanner_destroy(scanner);
295  return rc;
296 }
297 
355 struct nft_batch *nft_batch_start(struct nft_ctx *nft)
356 {
357  uint32_t seqnum;
358  bool batch_supported = netlink_batch_supported(nft->nf_sock, &seqnum);
359  struct nft_batch *batch = NULL;
360 
361  if (!batch_supported)
362  return NULL;
363 
364  batch = calloc(1, sizeof(*batch));
365  if (batch == NULL)
366  return NULL;
367 
368  batch->batch = mnl_batch_init();
369  mnl_batch_begin(batch->batch, mnl_seqnum_alloc(&nft->cache.seqnum));
370 
371  batch->nl_ctx.msgs = &nft->output.msgs;
372  batch->nl_ctx.batch = batch->batch;
373  batch->nl_ctx.batch_supported = batch_supported;
374  batch->nl_ctx.octx = &nft->output;
375  batch->nl_ctx.nf_sock = nft->nf_sock;
376  batch->nl_ctx.cache = &nft->cache;
377  init_list_head(&batch->nl_ctx.list);
378  return batch;
379 }
380 
390 int nft_batch_add(struct nft_ctx *nft, struct nft_batch *batch,
391  const char * buf, size_t buflen)
392 {
393  int rc = NFT_EXIT_SUCCESS;
394  int ret = 0;
395  struct parser_state state;
396  void *scanner;
397  struct cmd *cmd, *next;
398  struct netlink_ctx *ctx = &batch->nl_ctx;
399  uint32_t seqnum;
400 
401  parser_init(nft->nf_sock, &nft->cache, &state, &nft->output.msgs);
402  scanner = scanner_init(&state);
403  scanner_push_buffer(scanner, &indesc_cmdline, buf);
404 
405  ret = nft_parse(scanner, &state);
406  if (ret != 0 || state.nerrs > 0) {
407  rc = NFT_EXIT_FAILURE;
408  goto err1;
409  }
410 
411  list_for_each_entry(cmd, &state.cmds, list) {
412  nft_cmd_expand(cmd);
413  ctx->seqnum = cmd->seqnum = mnl_seqnum_alloc(&seqnum);
414  ret = do_command(ctx, cmd);
415  if (ret < 0)
416  return NFT_EXIT_FAILURE;
417  }
418 
419  list_for_each_entry_safe(cmd, next, &state.cmds, list) {
420  list_del(&cmd->list);
421  cmd_free(cmd);
422  }
423 err1:
424  scanner_destroy(scanner);
425  return rc;
426 }
427 
435 int nft_batch_commit(struct nft_ctx *nft, struct nft_batch *batch)
436 {
437  int ret = 0;
438  LIST_HEAD(err_list);
439 
440  mnl_batch_end(batch->batch, mnl_seqnum_alloc(&nft->cache.seqnum));
441 
442  if (!mnl_batch_ready(batch->batch)) {
443  ret = -1;
444  goto out;
445  }
446 
447  ret = netlink_batch_send(&batch->nl_ctx, &err_list);
448  if (ret == -1) {
449  struct mnl_err *err, *tmp;
450  list_for_each_entry_safe(err, tmp, &err_list, head) {
451  netlink_io_error(&batch->nl_ctx, NULL,
452  "Could not process rule: %s",
453  strerror(err->err));
454  /* multiple errno but let's return one */
455  ret = -err->err;
456  mnl_err_list_free(err);
457  }
458  }
459 out:
460  return ret;
461 }
462 
468 void nft_batch_free(struct nft_batch *batch)
469 {
470  if (batch == NULL)
471  return;
472  mnl_batch_reset(batch->batch);
473  xfree(batch);
474 }
475 
int nft_global_set_max_errors(unsigned int errors)
Definition: libnftables.c:110
void nft_context_free(struct nft_ctx *nft)
Definition: libnftables.c:175
int nft_run_command_from_buffer(struct nft_ctx *nft, char *buf, size_t buflen)
Definition: libnftables.c:237
int nft_batch_commit(struct nft_ctx *nft, struct nft_batch *batch)
Definition: libnftables.c:435
void nft_context_set_print_func(struct nft_ctx *nft, int(*print)(void *ctx, const char *fmt,...), void *ctx)
Definition: libnftables.c:160
void nft_global_deinit(void)
Definition: libnftables.c:91
int nft_get_error(struct nft_ctx *nft, char *err_buf, size_t err_buf_len)
Definition: libnftables.c:195
struct nft_batch * nft_batch_start(struct nft_ctx *nft)
Definition: libnftables.c:355
int nft_batch_add(struct nft_ctx *nft, struct nft_batch *batch, const char *buf, size_t buflen)
Definition: libnftables.c:390
int nft_run_command_from_filename(struct nft_ctx *nft, const char *filename)
Definition: libnftables.c:276
void nft_global_init(void)
Definition: libnftables.c:73
struct nft_ctx * nft_context_new(void)
Definition: libnftables.c:132
void nft_batch_free(struct nft_batch *batch)
Definition: libnftables.c:468