libnftnl 1.2.9
inner.c
1/* SPDX-License-Identifier: GPL-2.0-or-later */
2/*
3 * (C) 2012-2022 by Pablo Neira Ayuso <pablo@netfilter.org>
4 */
5
6#include "internal.h"
7
8#include <stdio.h>
9#include <stdint.h>
10#include <string.h>
11#include <limits.h>
12#include <arpa/inet.h>
13#include <errno.h>
14#include <libmnl/libmnl.h>
15
16#include <linux/netfilter/nf_tables.h>
17
18#include <libnftnl/expr.h>
19#include <libnftnl/rule.h>
20
22 uint32_t type;
23 uint32_t flags;
24 uint32_t hdrsize;
25 struct nftnl_expr *expr;
26};
27
28static void nftnl_expr_inner_free(const struct nftnl_expr *e)
29{
30 struct nftnl_expr_inner *inner = nftnl_expr_data(e);
31
32 if (inner->expr)
33 nftnl_expr_free(inner->expr);
34}
35
36static int
37nftnl_expr_inner_set(struct nftnl_expr *e, uint16_t type,
38 const void *data, uint32_t data_len)
39{
40 struct nftnl_expr_inner *inner = nftnl_expr_data(e);
41
42 switch(type) {
43 case NFTNL_EXPR_INNER_TYPE:
44 memcpy(&inner->type, data, data_len);
45 break;
46 case NFTNL_EXPR_INNER_FLAGS:
47 memcpy(&inner->flags, data, data_len);
48 break;
49 case NFTNL_EXPR_INNER_HDRSIZE:
50 memcpy(&inner->hdrsize, data, data_len);
51 break;
52 case NFTNL_EXPR_INNER_EXPR:
53 if (inner->expr)
54 nftnl_expr_free(inner->expr);
55
56 inner->expr = (void *)data;
57 break;
58 }
59 return 0;
60}
61
62static const void *
63nftnl_expr_inner_get(const struct nftnl_expr *e, uint16_t type,
64 uint32_t *data_len)
65{
66 struct nftnl_expr_inner *inner = nftnl_expr_data(e);
67
68 switch(type) {
69 case NFTNL_EXPR_INNER_FLAGS:
70 *data_len = sizeof(inner->flags);
71 return &inner->flags;
72 case NFTNL_EXPR_INNER_TYPE:
73 *data_len = sizeof(inner->type);
74 return &inner->type;
75 case NFTNL_EXPR_INNER_HDRSIZE:
76 *data_len = sizeof(inner->hdrsize);
77 return &inner->hdrsize;
78 case NFTNL_EXPR_INNER_EXPR:
79 return inner->expr;
80 }
81 return NULL;
82}
83
84static void
85nftnl_expr_inner_build(struct nlmsghdr *nlh, const struct nftnl_expr *e)
86{
87 struct nftnl_expr_inner *inner = nftnl_expr_data(e);
88 struct nlattr *nest;
89
90 mnl_attr_put_u32(nlh, NFTA_INNER_NUM, htonl(0));
91 if (e->flags & (1 << NFTNL_EXPR_INNER_TYPE))
92 mnl_attr_put_u32(nlh, NFTA_INNER_TYPE, htonl(inner->type));
93 if (e->flags & (1 << NFTNL_EXPR_INNER_FLAGS))
94 mnl_attr_put_u32(nlh, NFTA_INNER_FLAGS, htonl(inner->flags));
95 if (e->flags & (1 << NFTNL_EXPR_INNER_HDRSIZE))
96 mnl_attr_put_u32(nlh, NFTA_INNER_HDRSIZE, htonl(inner->hdrsize));
97 if (e->flags & (1 << NFTNL_EXPR_INNER_EXPR)) {
98 nest = mnl_attr_nest_start(nlh, NFTA_INNER_EXPR);
99 nftnl_expr_build_payload(nlh, inner->expr);
100 mnl_attr_nest_end(nlh, nest);
101 }
102}
103
104static int nftnl_inner_parse_cb(const struct nlattr *attr, void *data)
105{
106 const struct nlattr **tb = data;
107 int type = mnl_attr_get_type(attr);
108
109 if (mnl_attr_type_valid(attr, NFTA_INNER_MAX) < 0)
110 return MNL_CB_OK;
111
112 switch(type) {
113 case NFTA_INNER_NUM:
114 case NFTA_INNER_TYPE:
115 case NFTA_INNER_HDRSIZE:
116 case NFTA_INNER_FLAGS:
117 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
118 abi_breakage();
119 break;
120 case NFTA_INNER_EXPR:
121 if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
122 abi_breakage();
123 break;
124 }
125
126 tb[type] = attr;
127
128 return MNL_CB_OK;
129}
130
131static int
132nftnl_expr_inner_parse(struct nftnl_expr *e, struct nlattr *attr)
133{
134 struct nftnl_expr_inner *inner = nftnl_expr_data(e);
135 struct nlattr *tb[NFTA_INNER_MAX + 1] = {};
136 struct nftnl_expr *expr;
137 int err;
138
139 err = mnl_attr_parse_nested(attr, nftnl_inner_parse_cb, tb);
140 if (err < 0)
141 return err;
142
143 if (tb[NFTA_INNER_HDRSIZE]) {
144 inner->hdrsize =
145 ntohl(mnl_attr_get_u32(tb[NFTA_INNER_HDRSIZE]));
146 e->flags |= (1 << NFTNL_EXPR_INNER_HDRSIZE);
147 }
148 if (tb[NFTA_INNER_FLAGS]) {
149 inner->flags =
150 ntohl(mnl_attr_get_u32(tb[NFTA_INNER_FLAGS]));
151 e->flags |= (1 << NFTNL_EXPR_INNER_FLAGS);
152 }
153 if (tb[NFTA_INNER_TYPE]) {
154 inner->type =
155 ntohl(mnl_attr_get_u32(tb[NFTA_INNER_TYPE]));
156 e->flags |= (1 << NFTNL_EXPR_INNER_TYPE);
157 }
158 if (tb[NFTA_INNER_EXPR]) {
159 expr = nftnl_expr_parse(tb[NFTA_INNER_EXPR]);
160 if (!expr)
161 return -1;
162
163 if (inner->expr)
164 nftnl_expr_free(inner->expr);
165
166 inner->expr = expr;
167 e->flags |= (1 << NFTNL_EXPR_INNER_EXPR);
168 }
169
170 return 0;
171}
172
173static int
174nftnl_expr_inner_snprintf(char *buf, size_t remain, uint32_t flags,
175 const struct nftnl_expr *e)
176{
177 struct nftnl_expr_inner *inner = nftnl_expr_data(e);
178 uint32_t offset = 0;
179 int ret;
180
181 ret = snprintf(buf, remain, "type %u hdrsize %u flags %x [",
182 inner->type, inner->hdrsize, inner->flags);
183 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
184
185 ret = snprintf(buf + offset, remain, " %s ", inner->expr->ops->name);
186 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
187
188 ret = nftnl_expr_snprintf(buf + offset, remain, inner->expr,
189 NFTNL_OUTPUT_DEFAULT, 0);
190 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
191
192 ret = snprintf(buf + offset, remain, "] ");
193 SNPRINTF_BUFFER_SIZE(ret, remain, offset);
194
195 return offset;
196}
197
198static struct attr_policy inner_attr_policy[__NFTNL_EXPR_INNER_MAX] = {
199 [NFTNL_EXPR_INNER_TYPE] = { .maxlen = sizeof(uint32_t) },
200 [NFTNL_EXPR_INNER_FLAGS] = { .maxlen = sizeof(uint32_t) },
201 [NFTNL_EXPR_INNER_HDRSIZE] = { .maxlen = sizeof(uint32_t) },
202 [NFTNL_EXPR_INNER_EXPR] = { .maxlen = 0 },
203};
204
205struct expr_ops expr_ops_inner = {
206 .name = "inner",
207 .alloc_len = sizeof(struct nftnl_expr_inner),
208 .nftnl_max_attr = __NFTNL_EXPR_INNER_MAX - 1,
209 .attr_policy = inner_attr_policy,
210 .free = nftnl_expr_inner_free,
211 .set = nftnl_expr_inner_set,
212 .get = nftnl_expr_inner_get,
213 .parse = nftnl_expr_inner_parse,
214 .build = nftnl_expr_inner_build,
215 .output = nftnl_expr_inner_snprintf,
216};