libnftnl  1.2.9
numgen.c
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3  * (C) 2016 by Laura Garcia <nevola@gmail.com>
4  */
5 
6 #include <stdio.h>
7 #include <stdint.h>
8 #include <string.h>
9 #include <arpa/inet.h>
10 #include <errno.h>
11 #include <linux/netfilter/nf_tables.h>
12 
13 #include "internal.h"
14 #include <libmnl/libmnl.h>
15 #include <libnftnl/expr.h>
16 #include <libnftnl/rule.h>
17 
18 struct nftnl_expr_ng {
19  enum nft_registers dreg;
20  unsigned int modulus;
21  enum nft_ng_types type;
22  unsigned int offset;
23 };
24 
25 static int
26 nftnl_expr_ng_set(struct nftnl_expr *e, uint16_t type,
27  const void *data, uint32_t data_len)
28 {
29  struct nftnl_expr_ng *ng = nftnl_expr_data(e);
30 
31  switch (type) {
32  case NFTNL_EXPR_NG_DREG:
33  memcpy(&ng->dreg, data, data_len);
34  break;
35  case NFTNL_EXPR_NG_MODULUS:
36  memcpy(&ng->modulus, data, data_len);
37  break;
38  case NFTNL_EXPR_NG_TYPE:
39  memcpy(&ng->type, data, data_len);
40  break;
41  case NFTNL_EXPR_NG_OFFSET:
42  memcpy(&ng->offset, data, data_len);
43  break;
44  default:
45  return -1;
46  }
47  return 0;
48 }
49 
50 static const void *
51 nftnl_expr_ng_get(const struct nftnl_expr *e, uint16_t type,
52  uint32_t *data_len)
53 {
54  struct nftnl_expr_ng *ng = nftnl_expr_data(e);
55 
56  switch (type) {
57  case NFTNL_EXPR_NG_DREG:
58  *data_len = sizeof(ng->dreg);
59  return &ng->dreg;
60  case NFTNL_EXPR_NG_MODULUS:
61  *data_len = sizeof(ng->modulus);
62  return &ng->modulus;
63  case NFTNL_EXPR_NG_TYPE:
64  *data_len = sizeof(ng->type);
65  return &ng->type;
66  case NFTNL_EXPR_NG_OFFSET:
67  *data_len = sizeof(ng->offset);
68  return &ng->offset;
69  }
70  return NULL;
71 }
72 
73 static int nftnl_expr_ng_cb(const struct nlattr *attr, void *data)
74 {
75  const struct nlattr **tb = data;
76  int type = mnl_attr_get_type(attr);
77 
78  if (mnl_attr_type_valid(attr, NFTA_NG_MAX) < 0)
79  return MNL_CB_OK;
80 
81  switch (type) {
82  case NFTA_NG_DREG:
83  case NFTA_NG_MODULUS:
84  case NFTA_NG_TYPE:
85  case NFTA_NG_OFFSET:
86  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
87  abi_breakage();
88  break;
89  }
90 
91  tb[type] = attr;
92  return MNL_CB_OK;
93 }
94 
95 static void
96 nftnl_expr_ng_build(struct nlmsghdr *nlh, const struct nftnl_expr *e)
97 {
98  struct nftnl_expr_ng *ng = nftnl_expr_data(e);
99 
100  if (e->flags & (1 << NFTNL_EXPR_NG_DREG))
101  mnl_attr_put_u32(nlh, NFTA_NG_DREG, htonl(ng->dreg));
102  if (e->flags & (1 << NFTNL_EXPR_NG_MODULUS))
103  mnl_attr_put_u32(nlh, NFTA_NG_MODULUS, htonl(ng->modulus));
104  if (e->flags & (1 << NFTNL_EXPR_NG_TYPE))
105  mnl_attr_put_u32(nlh, NFTA_NG_TYPE, htonl(ng->type));
106  if (e->flags & (1 << NFTNL_EXPR_NG_OFFSET))
107  mnl_attr_put_u32(nlh, NFTA_NG_OFFSET, htonl(ng->offset));
108 }
109 
110 static int
111 nftnl_expr_ng_parse(struct nftnl_expr *e, struct nlattr *attr)
112 {
113  struct nftnl_expr_ng *ng = nftnl_expr_data(e);
114  struct nlattr *tb[NFTA_NG_MAX+1] = {};
115  int ret = 0;
116 
117  if (mnl_attr_parse_nested(attr, nftnl_expr_ng_cb, tb) < 0)
118  return -1;
119 
120  if (tb[NFTA_NG_DREG]) {
121  ng->dreg = ntohl(mnl_attr_get_u32(tb[NFTA_NG_DREG]));
122  e->flags |= (1 << NFTNL_EXPR_NG_DREG);
123  }
124  if (tb[NFTA_NG_MODULUS]) {
125  ng->modulus = ntohl(mnl_attr_get_u32(tb[NFTA_NG_MODULUS]));
126  e->flags |= (1 << NFTNL_EXPR_NG_MODULUS);
127  }
128  if (tb[NFTA_NG_TYPE]) {
129  ng->type = ntohl(mnl_attr_get_u32(tb[NFTA_NG_TYPE]));
130  e->flags |= (1 << NFTNL_EXPR_NG_TYPE);
131  }
132  if (tb[NFTA_NG_OFFSET]) {
133  ng->offset = ntohl(mnl_attr_get_u32(tb[NFTA_NG_OFFSET]));
134  e->flags |= (1 << NFTNL_EXPR_NG_OFFSET);
135  }
136 
137  return ret;
138 }
139 
140 static int
141 nftnl_expr_ng_snprintf(char *buf, size_t remain,
142  uint32_t flags, const struct nftnl_expr *e)
143 {
144  struct nftnl_expr_ng *ng = nftnl_expr_data(e);
145  int offset = 0, ret;
146 
147  switch (ng->type) {
148  case NFT_NG_INCREMENTAL:
149  ret = snprintf(buf, remain, "reg %u = inc mod %u ",
150  ng->dreg, ng->modulus);
151  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
152  break;
153  case NFT_NG_RANDOM:
154  ret = snprintf(buf, remain, "reg %u = random mod %u ",
155  ng->dreg, ng->modulus);
156  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
157  break;
158  default:
159  return 0;
160  }
161 
162  if (ng->offset) {
163  ret = snprintf(buf + offset, remain, "offset %u ", ng->offset);
164  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
165  }
166 
167  return offset;
168 }
169 
170 static struct attr_policy numgen_attr_policy[__NFTNL_EXPR_NG_MAX] = {
171  [NFTNL_EXPR_NG_DREG] = { .maxlen = sizeof(uint32_t) },
172  [NFTNL_EXPR_NG_MODULUS] = { .maxlen = sizeof(uint32_t) },
173  [NFTNL_EXPR_NG_TYPE] = { .maxlen = sizeof(uint32_t) },
174  [NFTNL_EXPR_NG_OFFSET] = { .maxlen = sizeof(uint32_t) },
175 };
176 
177 struct expr_ops expr_ops_ng = {
178  .name = "numgen",
179  .alloc_len = sizeof(struct nftnl_expr_ng),
180  .nftnl_max_attr = __NFTNL_EXPR_NG_MAX - 1,
181  .attr_policy = numgen_attr_policy,
182  .set = nftnl_expr_ng_set,
183  .get = nftnl_expr_ng_get,
184  .parse = nftnl_expr_ng_parse,
185  .build = nftnl_expr_ng_build,
186  .output = nftnl_expr_ng_snprintf,
187 };