libnftnl  1.2.9
common.c
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3  * (C) 2012-2013 by Pablo Neira Ayuso <pablo@netfilter.org>
4  */
5 
6 #include <stdlib.h>
7 #include <sys/socket.h>
8 #include <time.h>
9 #include <arpa/inet.h>
10 #include <linux/netlink.h>
11 #include <linux/netfilter/nfnetlink.h>
12 #include <linux/netfilter/nf_tables.h>
13 
14 #include <libmnl/libmnl.h>
15 #include <libnftnl/common.h>
16 #include <libnftnl/set.h>
17 
18 #include <errno.h>
19 #include "internal.h"
20 
21 static struct nlmsghdr *__nftnl_nlmsg_build_hdr(char *buf, uint16_t type,
22  uint16_t family,
23  uint16_t flags, uint32_t seq,
24  uint16_t res_id)
25 {
26  struct nlmsghdr *nlh;
27  struct nfgenmsg *nfh;
28 
29  nlh = mnl_nlmsg_put_header(buf);
30  nlh->nlmsg_type = type;
31  nlh->nlmsg_flags = NLM_F_REQUEST | flags;
32  nlh->nlmsg_seq = seq;
33 
34  nfh = mnl_nlmsg_put_extra_header(nlh, sizeof(struct nfgenmsg));
35  nfh->nfgen_family = family;
36  nfh->version = NFNETLINK_V0;
37  nfh->res_id = htons(res_id);
38 
39  return nlh;
40 }
41 
42 EXPORT_SYMBOL(nftnl_nlmsg_build_hdr);
43 struct nlmsghdr *nftnl_nlmsg_build_hdr(char *buf, uint16_t type, uint16_t family,
44  uint16_t flags, uint32_t seq)
45 {
46  return __nftnl_nlmsg_build_hdr(buf, (NFNL_SUBSYS_NFTABLES << 8) | type,
47  family, flags, seq, 0);
48 }
49 
50 EXPORT_SYMBOL(nftnl_parse_err_alloc);
51 struct nftnl_parse_err *nftnl_parse_err_alloc(void)
52 {
53  struct nftnl_parse_err *err;
54 
55  err = calloc(1, sizeof(struct nftnl_parse_err));
56  if (err == NULL)
57  return NULL;
58 
59  err->error = NFTNL_PARSE_EOPNOTSUPP;
60 
61  return err;
62 }
63 
64 EXPORT_SYMBOL(nftnl_parse_err_free);
65 void nftnl_parse_err_free(struct nftnl_parse_err *err)
66 {
67  xfree(err);
68 }
69 
70 EXPORT_SYMBOL(nftnl_parse_perror);
71 int nftnl_parse_perror(const char *msg, struct nftnl_parse_err *err)
72 {
73  switch (err->error) {
74  case NFTNL_PARSE_EBADINPUT:
75  return fprintf(stderr, "%s: Bad input format in line %d column %d\n",
76  msg, err->line, err->column);
77  case NFTNL_PARSE_EMISSINGNODE:
78  return fprintf(stderr, "%s: Node \"%s\" not found\n",
79  msg, err->node_name);
80  case NFTNL_PARSE_EBADTYPE:
81  return fprintf(stderr, "%s: Invalid type in node \"%s\"\n",
82  msg, err->node_name);
83  case NFTNL_PARSE_EOPNOTSUPP:
84  return fprintf(stderr, "%s: Operation not supported\n", msg);
85  default:
86  return fprintf(stderr, "%s: Undefined error\n", msg);
87  }
88 }
89 
90 EXPORT_SYMBOL(nftnl_batch_begin);
91 struct nlmsghdr *nftnl_batch_begin(char *buf, uint32_t seq)
92 {
93  return __nftnl_nlmsg_build_hdr(buf, NFNL_MSG_BATCH_BEGIN, AF_UNSPEC,
94  0, seq, NFNL_SUBSYS_NFTABLES);
95 }
96 
97 EXPORT_SYMBOL(nftnl_batch_end);
98 struct nlmsghdr *nftnl_batch_end(char *buf, uint32_t seq)
99 {
100  return __nftnl_nlmsg_build_hdr(buf, NFNL_MSG_BATCH_END, AF_UNSPEC,
101  0, seq, NFNL_SUBSYS_NFTABLES);
102 }
103 
104 EXPORT_SYMBOL(nftnl_batch_is_supported);
105 int nftnl_batch_is_supported(void)
106 {
107  struct mnl_socket *nl;
108  struct mnl_nlmsg_batch *b;
109  char buf[MNL_SOCKET_BUFFER_SIZE];
110  uint32_t seq = time(NULL), req_seq;
111  int ret;
112 
113  nl = mnl_socket_open(NETLINK_NETFILTER);
114  if (nl == NULL)
115  return -1;
116 
117  if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0)
118  return -1;
119 
120  b = mnl_nlmsg_batch_start(buf, sizeof(buf));
121 
122  nftnl_batch_begin(mnl_nlmsg_batch_current(b), seq++);
123  mnl_nlmsg_batch_next(b);
124 
125  req_seq = seq;
126  nftnl_nlmsg_build_hdr(mnl_nlmsg_batch_current(b), NFT_MSG_NEWSET,
127  AF_INET, NLM_F_ACK, seq++);
128  mnl_nlmsg_batch_next(b);
129 
130  nftnl_batch_end(mnl_nlmsg_batch_current(b), seq++);
131  mnl_nlmsg_batch_next(b);
132 
133  ret = mnl_socket_sendto(nl, mnl_nlmsg_batch_head(b),
134  mnl_nlmsg_batch_size(b));
135  if (ret < 0)
136  goto err;
137 
138  mnl_nlmsg_batch_stop(b);
139 
140  ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
141  while (ret > 0) {
142  ret = mnl_cb_run(buf, ret, req_seq, mnl_socket_get_portid(nl),
143  NULL, NULL);
144  if (ret <= 0)
145  break;
146 
147  ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
148  }
149  mnl_socket_close(nl);
150 
151  /* We're sending an incomplete message to see if the kernel supports
152  * set messages in batches. EINVAL means that we sent an incomplete
153  * message with missing attributes. The kernel just ignores messages
154  * that we cannot include in the batch.
155  */
156  return (ret == -1 && errno == EINVAL) ? 1 : 0;
157 err:
158  mnl_nlmsg_batch_stop(b);
159  return -1;
160 }