libnftnl 1.2.9
ct.c
1/* SPDX-License-Identifier: GPL-2.0-or-later */
2/*
3 * (C) 2012-2013 by Pablo Neira Ayuso <pablo@netfilter.org>
4 *
5 * This code has been sponsored by Sophos Astaro <http://www.sophos.com>
6 */
7
8#include <stdio.h>
9#include <string.h>
10#include <stdint.h>
11#include <arpa/inet.h>
12#include <errno.h>
13#include <linux/netfilter/nf_tables.h>
14
15#include "internal.h"
16#include <libmnl/libmnl.h>
17#include <libnftnl/expr.h>
18#include <libnftnl/rule.h>
19
21 enum nft_ct_keys key;
22 enum nft_registers dreg;
23 enum nft_registers sreg;
24 uint8_t dir;
25};
26
27#define IP_CT_DIR_ORIGINAL 0
28#define IP_CT_DIR_REPLY 1
29
30static int
31nftnl_expr_ct_set(struct nftnl_expr *e, uint16_t type,
32 const void *data, uint32_t data_len)
33{
34 struct nftnl_expr_ct *ct = nftnl_expr_data(e);
35
36 switch(type) {
37 case NFTNL_EXPR_CT_KEY:
38 memcpy(&ct->key, data, data_len);
39 break;
40 case NFTNL_EXPR_CT_DIR:
41 memcpy(&ct->dir, data, data_len);
42 break;
43 case NFTNL_EXPR_CT_DREG:
44 memcpy(&ct->dreg, data, data_len);
45 break;
46 case NFTNL_EXPR_CT_SREG:
47 memcpy(&ct->sreg, data, data_len);
48 break;
49 }
50 return 0;
51}
52
53static const void *
54nftnl_expr_ct_get(const struct nftnl_expr *e, uint16_t type,
55 uint32_t *data_len)
56{
57 struct nftnl_expr_ct *ct = nftnl_expr_data(e);
58
59 switch(type) {
60 case NFTNL_EXPR_CT_KEY:
61 *data_len = sizeof(ct->key);
62 return &ct->key;
63 case NFTNL_EXPR_CT_DIR:
64 *data_len = sizeof(ct->dir);
65 return &ct->dir;
66 case NFTNL_EXPR_CT_DREG:
67 *data_len = sizeof(ct->dreg);
68 return &ct->dreg;
69 case NFTNL_EXPR_CT_SREG:
70 *data_len = sizeof(ct->sreg);
71 return &ct->sreg;
72 }
73 return NULL;
74}
75
76static int nftnl_expr_ct_cb(const struct nlattr *attr, void *data)
77{
78 const struct nlattr **tb = data;
79 int type = mnl_attr_get_type(attr);
80
81 if (mnl_attr_type_valid(attr, NFTA_CT_MAX) < 0)
82 return MNL_CB_OK;
83
84 switch(type) {
85 case NFTA_CT_KEY:
86 case NFTA_CT_DREG:
87 case NFTA_CT_SREG:
88 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
89 abi_breakage();
90 break;
91 case NFTA_CT_DIRECTION:
92 if (mnl_attr_validate(attr, MNL_TYPE_U8) < 0)
93 abi_breakage();
94 break;
95 }
96
97 tb[type] = attr;
98 return MNL_CB_OK;
99}
100
101static void
102nftnl_expr_ct_build(struct nlmsghdr *nlh, const struct nftnl_expr *e)
103{
104 struct nftnl_expr_ct *ct = nftnl_expr_data(e);
105
106 if (e->flags & (1 << NFTNL_EXPR_CT_KEY))
107 mnl_attr_put_u32(nlh, NFTA_CT_KEY, htonl(ct->key));
108 if (e->flags & (1 << NFTNL_EXPR_CT_DREG))
109 mnl_attr_put_u32(nlh, NFTA_CT_DREG, htonl(ct->dreg));
110 if (e->flags & (1 << NFTNL_EXPR_CT_DIR))
111 mnl_attr_put_u8(nlh, NFTA_CT_DIRECTION, ct->dir);
112 if (e->flags & (1 << NFTNL_EXPR_CT_SREG))
113 mnl_attr_put_u32(nlh, NFTA_CT_SREG, htonl(ct->sreg));
114}
115
116static int
117nftnl_expr_ct_parse(struct nftnl_expr *e, struct nlattr *attr)
118{
119 struct nftnl_expr_ct *ct = nftnl_expr_data(e);
120 struct nlattr *tb[NFTA_CT_MAX+1] = {};
121
122 if (mnl_attr_parse_nested(attr, nftnl_expr_ct_cb, tb) < 0)
123 return -1;
124
125 if (tb[NFTA_CT_KEY]) {
126 ct->key = ntohl(mnl_attr_get_u32(tb[NFTA_CT_KEY]));
127 e->flags |= (1 << NFTNL_EXPR_CT_KEY);
128 }
129 if (tb[NFTA_CT_DREG]) {
130 ct->dreg = ntohl(mnl_attr_get_u32(tb[NFTA_CT_DREG]));
131 e->flags |= (1 << NFTNL_EXPR_CT_DREG);
132 }
133 if (tb[NFTA_CT_SREG]) {
134 ct->sreg = ntohl(mnl_attr_get_u32(tb[NFTA_CT_SREG]));
135 e->flags |= (1 << NFTNL_EXPR_CT_SREG);
136 }
137 if (tb[NFTA_CT_DIRECTION]) {
138 ct->dir = mnl_attr_get_u8(tb[NFTA_CT_DIRECTION]);
139 e->flags |= (1 << NFTNL_EXPR_CT_DIR);
140 }
141
142 return 0;
143}
144
145static const char *ctkey2str_array[NFT_CT_MAX + 1] = {
146 [NFT_CT_STATE] = "state",
147 [NFT_CT_DIRECTION] = "direction",
148 [NFT_CT_STATUS] = "status",
149 [NFT_CT_MARK] = "mark",
150 [NFT_CT_SECMARK] = "secmark",
151 [NFT_CT_EXPIRATION] = "expiration",
152 [NFT_CT_HELPER] = "helper",
153 [NFT_CT_L3PROTOCOL] = "l3protocol",
154 [NFT_CT_PROTOCOL] = "protocol",
155 [NFT_CT_SRC] = "src",
156 [NFT_CT_DST] = "dst",
157 [NFT_CT_PROTO_SRC] = "proto_src",
158 [NFT_CT_PROTO_DST] = "proto_dst",
159 [NFT_CT_LABELS] = "label",
160 [NFT_CT_PKTS] = "packets",
161 [NFT_CT_BYTES] = "bytes",
162 [NFT_CT_AVGPKT] = "avgpkt",
163 [NFT_CT_ZONE] = "zone",
164 [NFT_CT_EVENTMASK] = "event",
165 [NFT_CT_SRC_IP] = "src_ip",
166 [NFT_CT_DST_IP] = "dst_ip",
167 [NFT_CT_SRC_IP6] = "src_ip6",
168 [NFT_CT_DST_IP6] = "dst_ip6",
169 [NFT_CT_ID] = "id",
170};
171
172static const char *ctkey2str(uint32_t ctkey)
173{
174 if (ctkey > NFT_CT_MAX)
175 return "unknown";
176
177 return ctkey2str_array[ctkey];
178}
179
180static const char *ctdir2str(uint8_t ctdir)
181{
182 switch (ctdir) {
183 case IP_CT_DIR_ORIGINAL:
184 return "original";
185 case IP_CT_DIR_REPLY:
186 return "reply";
187 default:
188 return "unknown";
189 }
190}
191
192static int
193nftnl_expr_ct_snprintf(char *buf, size_t remain,
194 uint32_t flags, const struct nftnl_expr *e)
195{
196 struct nftnl_expr_ct *ct = nftnl_expr_data(e);
197 int ret, offset = 0;
198
199 if (e->flags & (1 << NFTNL_EXPR_CT_SREG)) {
200 ret = snprintf(buf, remain, "set %s with reg %u ",
201 ctkey2str(ct->key), ct->sreg);
202 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
203 }
204
205 if (e->flags & (1 << NFTNL_EXPR_CT_DREG)) {
206 ret = snprintf(buf, remain, "load %s => reg %u ",
207 ctkey2str(ct->key), ct->dreg);
208 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
209 }
210
211 if (nftnl_expr_is_set(e, NFTNL_EXPR_CT_DIR)) {
212 ret = snprintf(buf + offset, remain, ", dir %s ",
213 ctdir2str(ct->dir));
214 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
215 }
216
217 return offset;
218}
219
220static struct attr_policy ct_attr_policy[__NFTNL_EXPR_CT_MAX] = {
221 [NFTNL_EXPR_CT_DREG] = { .maxlen = sizeof(uint32_t) },
222 [NFTNL_EXPR_CT_KEY] = { .maxlen = sizeof(uint32_t) },
223 [NFTNL_EXPR_CT_DIR] = { .maxlen = sizeof(uint8_t) },
224 [NFTNL_EXPR_CT_SREG] = { .maxlen = sizeof(uint32_t) },
225};
226
227struct expr_ops expr_ops_ct = {
228 .name = "ct",
229 .alloc_len = sizeof(struct nftnl_expr_ct),
230 .nftnl_max_attr = __NFTNL_EXPR_CT_MAX - 1,
231 .attr_policy = ct_attr_policy,
232 .set = nftnl_expr_ct_set,
233 .get = nftnl_expr_ct_get,
234 .parse = nftnl_expr_ct_parse,
235 .build = nftnl_expr_ct_build,
236 .output = nftnl_expr_ct_snprintf,
237};