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