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