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