libnftnl  1.3.2
data_reg.c
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3  * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org>
4  *
5  * This code has been sponsored by Sophos Astaro <http://www.sophos.com>
6  */
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 <netinet/in.h>
15 
16 #include <libmnl/libmnl.h>
17 #include <linux/netfilter.h>
18 #include <linux/netfilter/nf_tables.h>
19 #include <libnftnl/expr.h>
20 #include <libnftnl/rule.h>
21 #include "internal.h"
22 
23 static bool big_endian_host(void)
24 {
25  uint16_t v = 1;
26 
27  return v == htons(v);
28 }
29 
30 static int __reg_value_snprintf(char *buf, size_t remain,
31  uint8_t *data, size_t datalen,
32  bool reverse, const char *pfx)
33 {
34  int offset = 0, ret, i, idx;
35  const char *sep = "";
36 
37  for (i = 0; i < datalen; i++) {
38  if ((i % 4) == 0) {
39  ret = snprintf(buf + offset, remain, "%s%s", sep, pfx);
40  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
41  sep = " ";
42  }
43  if (reverse)
44  idx = datalen - i - 1;
45  else
46  idx = i;
47 
48  ret = snprintf(buf + offset, remain, "%.2x", data[idx]);
49  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
50  }
51 
52  return offset;
53 }
54 
55 static int
56 nftnl_data_reg_value_snprintf_default(char *buf, size_t remain,
57  const union nftnl_data_reg *reg,
58  uint32_t flags)
59 {
60  uint32_t byteorder = big_endian_host() ? 0 : reg->byteorder;
61  const char *pfx = flags & DATA_F_NOPFX ? "" : "0x";
62  int offset = 0, ret, i, pos = 0;
63 
64  for (i = 0; i < array_size(reg->sizes); i++) {
65  int curlen = reg->sizes[i] ?: reg->len;
66  bool reverse = byteorder & (1 << i);
67 
68  if (i > 0) {
69  ret = snprintf(buf + offset, remain, " . ");
70  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
71  }
72 
73  ret = __reg_value_snprintf(buf + offset, remain,
74  (void *)&reg->val[pos],
75  curlen, reverse, pfx);
76  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
77 
78  pos += div_round_up(curlen, sizeof(uint32_t));
79  if (pos >= reg->len / sizeof(uint32_t))
80  break;
81  }
82 
83  return offset;
84 }
85 
86 static int
87 nftnl_data_reg_verdict_snprintf_def(char *buf, size_t size,
88  const union nftnl_data_reg *reg,
89  uint32_t flags)
90 {
91  int remain = size, offset = 0, ret = 0;
92 
93  ret = snprintf(buf, size, "%s", nftnl_verdict2str(reg->verdict));
94  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
95 
96  if (reg->chain != NULL) {
97  ret = snprintf(buf + offset, remain, " -> %s", reg->chain);
98  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
99  }
100 
101  return offset;
102 }
103 
104 int nftnl_data_reg_snprintf(char *buf, size_t size,
105  const union nftnl_data_reg *reg,
106  uint32_t flags, int reg_type)
107 {
108  switch(reg_type) {
109  case DATA_VALUE:
110  return nftnl_data_reg_value_snprintf_default(buf, size,
111  reg, flags);
112  case DATA_VERDICT:
113  case DATA_CHAIN:
114  return nftnl_data_reg_verdict_snprintf_def(buf, size,
115  reg, flags);
116  default:
117  return -1;
118  }
119 }
120 
121 static int nftnl_data_parse_cb(const struct nlattr *attr, void *data)
122 {
123  const struct nlattr **tb = data;
124  int type = mnl_attr_get_type(attr);
125 
126  if (mnl_attr_type_valid(attr, NFTA_DATA_MAX) < 0)
127  return MNL_CB_OK;
128 
129  switch(type) {
130  case NFTA_DATA_VALUE:
131  if (mnl_attr_validate(attr, MNL_TYPE_BINARY) < 0)
132  abi_breakage();
133  break;
134  case NFTA_DATA_VERDICT:
135  if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
136  abi_breakage();
137  break;
138  }
139  tb[type] = attr;
140  return MNL_CB_OK;
141 }
142 
143 static int nftnl_verdict_parse_cb(const struct nlattr *attr, void *data)
144 {
145  const struct nlattr **tb = data;
146  int type = mnl_attr_get_type(attr);
147 
148  if (mnl_attr_type_valid(attr, NFTA_VERDICT_MAX) < 0)
149  return MNL_CB_OK;
150 
151  switch(type) {
152  case NFTA_VERDICT_CODE:
153  case NFTA_VERDICT_CHAIN_ID:
154  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
155  abi_breakage();
156  break;
157  case NFTA_VERDICT_CHAIN:
158  if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
159  abi_breakage();
160  break;
161  }
162  tb[type] = attr;
163  return MNL_CB_OK;
164 }
165 
166 static int
167 nftnl_parse_verdict(union nftnl_data_reg *data, const struct nlattr *attr, int *type)
168 {
169  struct nlattr *tb[NFTA_VERDICT_MAX+1];
170 
171  if (mnl_attr_parse_nested(attr, nftnl_verdict_parse_cb, tb) < 0)
172  return -1;
173 
174  if (!tb[NFTA_VERDICT_CODE])
175  return -1;
176 
177  data->verdict = ntohl(mnl_attr_get_u32(tb[NFTA_VERDICT_CODE]));
178 
179  switch(data->verdict) {
180  case NF_ACCEPT:
181  case NF_DROP:
182  case NF_QUEUE:
183  case NFT_CONTINUE:
184  case NFT_BREAK:
185  case NFT_RETURN:
186  if (type)
187  *type = DATA_VERDICT;
188  data->len = sizeof(data->verdict);
189  break;
190  case NFT_JUMP:
191  case NFT_GOTO:
192  if (!tb[NFTA_VERDICT_CHAIN])
193  return -1;
194 
195  data->chain = strdup(mnl_attr_get_str(tb[NFTA_VERDICT_CHAIN]));
196  if (!data->chain)
197  return -1;
198 
199  if (type)
200  *type = DATA_CHAIN;
201  break;
202  default:
203  return -1;
204  }
205 
206  return 0;
207 }
208 
209 static int
210 __nftnl_parse_data(union nftnl_data_reg *data, const struct nlattr *attr)
211 {
212  void *orig = mnl_attr_get_payload(attr);
213  uint32_t data_len = mnl_attr_get_payload_len(attr);
214 
215  if (data_len == 0)
216  return -1;
217 
218  if (data_len > sizeof(data->val))
219  return -1;
220 
221  memcpy(data->val, orig, data_len);
222  data->len = data_len;
223 
224  return 0;
225 }
226 
227 int nftnl_parse_data(union nftnl_data_reg *data, struct nlattr *attr, int *type)
228 {
229  struct nlattr *tb[NFTA_DATA_MAX+1] = {};
230  int ret = 0;
231 
232  if (mnl_attr_parse_nested(attr, nftnl_data_parse_cb, tb) < 0)
233  return -1;
234 
235  if (tb[NFTA_DATA_VALUE]) {
236  if (type)
237  *type = DATA_VALUE;
238 
239  ret = __nftnl_parse_data(data, tb[NFTA_DATA_VALUE]);
240  if (ret < 0)
241  return ret;
242  }
243  if (tb[NFTA_DATA_VERDICT])
244  ret = nftnl_parse_verdict(data, tb[NFTA_DATA_VERDICT], type);
245 
246  return ret;
247 }
248 
249 int nftnl_data_cpy(union nftnl_data_reg *dreg, const void *src,
250  uint32_t len, uint32_t byteorder, uint8_t *sizes)
251 {
252  int ret = 0;
253 
254  if (len > sizeof(dreg->val)) {
255  len = sizeof(dreg->val);
256  ret = -1;
257  }
258 
259  memcpy(dreg->val, src, len);
260  dreg->len = len;
261  dreg->byteorder = byteorder;
262  if (sizes)
263  memcpy(dreg->sizes, sizes, sizeof(dreg->sizes));
264  else
265  memset(dreg->sizes, 0, sizeof(dreg->sizes));
266  return ret;
267 }