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