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 
28 static 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 
36 static int
37 nftnl_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 
62 static const void *
63 nftnl_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 
84 static void
85 nftnl_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 
104 static 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 
131 static int
132 nftnl_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 
173 static int
174 nftnl_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 
198 static 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 
205 struct 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 };