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