libnftnl  1.2.6
utils.c
1 /*
2  * (C) 2012-2013 by Pablo Neira Ayuso <pablo@netfilter.org>
3  * (C) 2013 by Arturo Borrero Gonzalez <arturo@debian.org>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published
7  * by the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  */
10 
11 #include <internal.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <limits.h>
15 #include <stdint.h>
16 #include <arpa/inet.h>
17 #include <errno.h>
18 #include <inttypes.h>
19 
20 #include <libnftnl/common.h>
21 
22 #include <linux/netfilter.h>
23 #include <linux/netfilter/nf_tables.h>
24 
25 static const char *const nftnl_family_str[NFPROTO_NUMPROTO] = {
26  [NFPROTO_INET] = "inet",
27  [NFPROTO_IPV4] = "ip",
28  [NFPROTO_ARP] = "arp",
29  [NFPROTO_NETDEV] = "netdev",
30  [NFPROTO_BRIDGE] = "bridge",
31  [NFPROTO_IPV6] = "ip6",
32 };
33 
34 const char *nftnl_family2str(uint32_t family)
35 {
36  if (family >= NFPROTO_NUMPROTO || !nftnl_family_str[family])
37  return "unknown";
38 
39  return nftnl_family_str[family];
40 }
41 
42 int nftnl_str2family(const char *family)
43 {
44  int i;
45 
46  for (i = 0; i < NFPROTO_NUMPROTO; i++) {
47  if (nftnl_family_str[i] == NULL)
48  continue;
49 
50  if (strcmp(nftnl_family_str[i], family) == 0)
51  return i;
52  }
53 
54  errno = EAFNOSUPPORT;
55  return -1;
56 }
57 
58 static struct {
59  int len;
60  int64_t min;
61  uint64_t max;
62 } basetype[] = {
63  [NFTNL_TYPE_U8] = { .len = sizeof(uint8_t), .max = UINT8_MAX },
64  [NFTNL_TYPE_U16] = { .len = sizeof(uint16_t), .max = UINT16_MAX },
65  [NFTNL_TYPE_U32] = { .len = sizeof(uint32_t), .max = UINT32_MAX },
66  [NFTNL_TYPE_U64] = { .len = sizeof(uint64_t), .max = UINT64_MAX },
67  [NFTNL_TYPE_S8] = { .len = sizeof(int8_t), .min = INT8_MIN, .max = INT8_MAX },
68  [NFTNL_TYPE_S16] = { .len = sizeof(int16_t), .min = INT16_MIN, .max = INT16_MAX },
69  [NFTNL_TYPE_S32] = { .len = sizeof(int32_t), .min = INT32_MIN, .max = INT32_MAX },
70  [NFTNL_TYPE_S64] = { .len = sizeof(int64_t), .min = INT64_MIN, .max = INT64_MAX },
71 };
72 
73 int nftnl_get_value(enum nftnl_type type, void *val, void *out)
74 {
75  union {
76  uint8_t u8;
77  uint16_t u16;
78  uint32_t u32;
79  int8_t s8;
80  int16_t s16;
81  int32_t s32;
82  } values;
83  void *valuep = NULL;
84  int64_t sval;
85  uint64_t uval;
86 
87  switch (type) {
88  case NFTNL_TYPE_U8:
89  case NFTNL_TYPE_U16:
90  case NFTNL_TYPE_U32:
91  case NFTNL_TYPE_U64:
92  memcpy(&uval, val, sizeof(uval));
93  if (uval > basetype[type].max) {
94  errno = ERANGE;
95  return -1;
96  }
97  break;
98  case NFTNL_TYPE_S8:
99  case NFTNL_TYPE_S16:
100  case NFTNL_TYPE_S32:
101  case NFTNL_TYPE_S64:
102  memcpy(&sval, val, sizeof(sval));
103  if (sval < basetype[type].min ||
104  sval > (int64_t)basetype[type].max) {
105  errno = ERANGE;
106  return -1;
107  }
108  break;
109  }
110 
111  switch (type) {
112  case NFTNL_TYPE_U8:
113  values.u8 = uval;
114  valuep = &values.u8;
115  break;
116  case NFTNL_TYPE_U16:
117  values.u16 = uval;
118  valuep = &values.u16;
119  break;
120  case NFTNL_TYPE_U32:
121  values.u32 = uval;
122  valuep = &values.u32;
123  break;
124  case NFTNL_TYPE_U64:
125  valuep = &uval;
126  break;
127  case NFTNL_TYPE_S8:
128  values.s8 = sval;
129  valuep = &values.s8;
130  break;
131  case NFTNL_TYPE_S16:
132  values.s16 = sval;
133  valuep = &values.s16;
134  break;
135  case NFTNL_TYPE_S32:
136  values.s32 = sval;
137  valuep = &values.s32;
138  break;
139  case NFTNL_TYPE_S64:
140  valuep = &sval;
141  break;
142  }
143  memcpy(out, valuep, basetype[type].len);
144  return 0;
145 }
146 
147 int nftnl_strtoi(const char *string, int base, void *out, enum nftnl_type type)
148 {
149  int ret;
150  int64_t sval = 0;
151  uint64_t uval = -1;
152  char *endptr;
153 
154  switch (type) {
155  case NFTNL_TYPE_U8:
156  case NFTNL_TYPE_U16:
157  case NFTNL_TYPE_U32:
158  case NFTNL_TYPE_U64:
159  uval = strtoll(string, &endptr, base);
160  ret = nftnl_get_value(type, &uval, out);
161  break;
162  case NFTNL_TYPE_S8:
163  case NFTNL_TYPE_S16:
164  case NFTNL_TYPE_S32:
165  case NFTNL_TYPE_S64:
166  sval = strtoull(string, &endptr, base);
167  ret = nftnl_get_value(type, &sval, out);
168  break;
169  default:
170  errno = EINVAL;
171  return -1;
172  }
173 
174  if (*endptr) {
175  errno = EINVAL;
176  return -1;
177  }
178 
179  return ret;
180 }
181 
182 const char *nftnl_verdict2str(uint32_t verdict)
183 {
184  switch (verdict) {
185  case NF_ACCEPT:
186  return "accept";
187  case NF_DROP:
188  return "drop";
189  case NF_STOLEN:
190  return "stolen";
191  case NF_QUEUE:
192  return "queue";
193  case NF_REPEAT:
194  return "repeat";
195  case NF_STOP:
196  return "stop";
197  case NFT_RETURN:
198  return "return";
199  case NFT_JUMP:
200  return "jump";
201  case NFT_GOTO:
202  return "goto";
203  case NFT_CONTINUE:
204  return "continue";
205  case NFT_BREAK:
206  return "break";
207  default:
208  return "unknown";
209  }
210 }
211 
212 int nftnl_str2verdict(const char *verdict, int *verdict_num)
213 {
214  if (strcmp(verdict, "accept") == 0) {
215  *verdict_num = NF_ACCEPT;
216  return 0;
217  } else if (strcmp(verdict, "drop") == 0) {
218  *verdict_num = NF_DROP;
219  return 0;
220  } else if (strcmp(verdict, "return") == 0) {
221  *verdict_num = NFT_RETURN;
222  return 0;
223  } else if (strcmp(verdict, "jump") == 0) {
224  *verdict_num = NFT_JUMP;
225  return 0;
226  } else if (strcmp(verdict, "goto") == 0) {
227  *verdict_num = NFT_GOTO;
228  return 0;
229  }
230 
231  return -1;
232 }
233 
234 enum nftnl_cmd_type nftnl_flag2cmd(uint32_t flags)
235 {
236  if (flags & NFTNL_OF_EVENT_NEW)
237  return NFTNL_CMD_ADD;
238  else if (flags & NFTNL_OF_EVENT_DEL)
239  return NFTNL_CMD_DELETE;
240 
241  return NFTNL_CMD_UNSPEC;
242 }
243 
244 static const char *cmd2tag[NFTNL_CMD_MAX] = {
245  [NFTNL_CMD_ADD] = "add",
246  [NFTNL_CMD_INSERT] = "insert",
247  [NFTNL_CMD_DELETE] = "delete",
248  [NFTNL_CMD_REPLACE] = "replace",
249  [NFTNL_CMD_FLUSH] = "flush",
250 };
251 
252 const char *nftnl_cmd2tag(enum nftnl_cmd_type cmd)
253 {
254  if (cmd >= NFTNL_CMD_MAX)
255  return "unknown";
256 
257  return cmd2tag[cmd];
258 }
259 
260 uint32_t nftnl_str2cmd(const char *cmd)
261 {
262  if (strcmp(cmd, "add") == 0)
263  return NFTNL_CMD_ADD;
264  else if (strcmp(cmd, "insert") == 0)
265  return NFTNL_CMD_INSERT;
266  else if (strcmp(cmd, "delete") == 0)
267  return NFTNL_CMD_DELETE;
268  else if (strcmp(cmd, "replace") == 0)
269  return NFTNL_CMD_REPLACE;
270  else if (strcmp(cmd, "flush") == 0)
271  return NFTNL_CMD_FLUSH;
272 
273  return NFTNL_CMD_UNSPEC;
274 }
275 
276 int nftnl_fprintf(FILE *fp, const void *obj, uint32_t cmd, uint32_t type,
277  uint32_t flags,
278  int (*snprintf_cb)(char *buf, size_t bufsiz, const void *obj,
279  uint32_t cmd, uint32_t type,
280  uint32_t flags))
281 {
282  char _buf[NFTNL_SNPRINTF_BUFSIZ];
283  char *buf = _buf;
284  size_t bufsiz = sizeof(_buf);
285  int ret;
286 
287  ret = snprintf_cb(buf, bufsiz, obj, cmd, type, flags);
288  if (ret <= 0)
289  goto out;
290 
291  if (ret >= NFTNL_SNPRINTF_BUFSIZ) {
292  bufsiz = ret + 1;
293 
294  buf = malloc(bufsiz);
295  if (buf == NULL)
296  return -1;
297 
298  ret = snprintf_cb(buf, bufsiz, obj, cmd, type, flags);
299  if (ret <= 0)
300  goto out;
301  }
302 
303  ret = fprintf(fp, "%s", buf);
304 
305 out:
306  if (buf != _buf)
307  xfree(buf);
308 
309  return ret;
310 }
311 
312 void __nftnl_assert_attr_exists(uint16_t attr, uint16_t attr_max,
313  const char *filename, int line)
314 {
315  fprintf(stderr, "libnftnl: attribute %d > %d (maximum) assertion failed in %s:%d\n",
316  attr, attr_max, filename, line);
317  exit(EXIT_FAILURE);
318 }
319 
320 void __nftnl_assert_fail(uint16_t attr, const char *filename, int line)
321 {
322  fprintf(stderr, "libnftnl: attribute %d assertion failed in %s:%d\n",
323  attr, filename, line);
324  exit(EXIT_FAILURE);
325 }
326 
327 void __noreturn __abi_breakage(const char *file, int line, const char *reason)
328 {
329  fprintf(stderr, "nf_tables kernel ABI is broken, contact your vendor.\n"
330  "%s:%d reason: %s\n", file, line, reason);
331  exit(EXIT_FAILURE);
332 }