libnftnl  1.3.1
utils.c
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3  * (C) 2012-2013 by Pablo Neira Ayuso <pablo@netfilter.org>
4  * (C) 2013 by Arturo Borrero Gonzalez <arturo@debian.org>
5  */
6 
7 #include <internal.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <limits.h>
11 #include <stdint.h>
12 #include <arpa/inet.h>
13 #include <errno.h>
14 #include <inttypes.h>
15 
16 #include <libmnl/libmnl.h>
17 
18 #include <libnftnl/common.h>
19 
20 #include <linux/if.h>
21 #include <linux/netfilter.h>
22 #include <linux/netfilter/nf_tables.h>
23 
24 static const char *const nftnl_family_str[NFPROTO_NUMPROTO] = {
25  [NFPROTO_INET] = "inet",
26  [NFPROTO_IPV4] = "ip",
27  [NFPROTO_ARP] = "arp",
28  [NFPROTO_NETDEV] = "netdev",
29  [NFPROTO_BRIDGE] = "bridge",
30  [NFPROTO_IPV6] = "ip6",
31 };
32 
33 const char *nftnl_family2str(uint32_t family)
34 {
35  if (family >= NFPROTO_NUMPROTO || !nftnl_family_str[family])
36  return "unknown";
37 
38  return nftnl_family_str[family];
39 }
40 
41 const char *nftnl_verdict2str(uint32_t verdict)
42 {
43  switch (verdict) {
44  case NF_ACCEPT:
45  return "accept";
46  case NF_DROP:
47  return "drop";
48  case NF_STOLEN:
49  return "stolen";
50  case NF_QUEUE:
51  return "queue";
52  case NF_REPEAT:
53  return "repeat";
54  case NF_STOP:
55  return "stop";
56  case NFT_RETURN:
57  return "return";
58  case NFT_JUMP:
59  return "jump";
60  case NFT_GOTO:
61  return "goto";
62  case NFT_CONTINUE:
63  return "continue";
64  case NFT_BREAK:
65  return "break";
66  default:
67  return "unknown";
68  }
69 }
70 
71 enum nftnl_cmd_type nftnl_flag2cmd(uint32_t flags)
72 {
73  if (flags & NFTNL_OF_EVENT_NEW)
74  return NFTNL_CMD_ADD;
75  else if (flags & NFTNL_OF_EVENT_DEL)
76  return NFTNL_CMD_DELETE;
77 
78  return NFTNL_CMD_UNSPEC;
79 }
80 
81 int nftnl_fprintf(FILE *fp, const void *obj, uint32_t cmd, uint32_t type,
82  uint32_t flags,
83  int (*snprintf_cb)(char *buf, size_t bufsiz, const void *obj,
84  uint32_t cmd, uint32_t type,
85  uint32_t flags))
86 {
87  char _buf[NFTNL_SNPRINTF_BUFSIZ];
88  char *buf = _buf;
89  size_t bufsiz = sizeof(_buf);
90  int ret;
91 
92  ret = snprintf_cb(buf, bufsiz, obj, cmd, type, flags);
93  if (ret <= 0)
94  goto out;
95 
96  if (ret >= NFTNL_SNPRINTF_BUFSIZ) {
97  bufsiz = ret + 1;
98 
99  buf = malloc(bufsiz);
100  if (buf == NULL)
101  return -1;
102 
103  ret = snprintf_cb(buf, bufsiz, obj, cmd, type, flags);
104  if (ret <= 0)
105  goto out;
106  }
107 
108  ret = fprintf(fp, "%s", buf);
109 
110 out:
111  if (buf != _buf)
112  xfree(buf);
113 
114  return ret;
115 }
116 
117 void __nftnl_assert_attr_exists(uint16_t attr, uint16_t attr_max,
118  const char *filename, int line)
119 {
120  fprintf(stderr, "libnftnl: attribute %d > %d (maximum) assertion failed in %s:%d\n",
121  attr, attr_max, filename, line);
122  exit(EXIT_FAILURE);
123 }
124 
125 void __nftnl_assert_fail(uint16_t attr, const char *filename, int line)
126 {
127  fprintf(stderr, "libnftnl: attribute %d assertion failed in %s:%d\n",
128  attr, filename, line);
129  exit(EXIT_FAILURE);
130 }
131 
132 void __noreturn __abi_breakage(const char *file, int line, const char *reason)
133 {
134  fprintf(stderr, "nf_tables kernel ABI is broken, contact your vendor.\n"
135  "%s:%d reason: %s\n", file, line, reason);
136  exit(EXIT_FAILURE);
137 }
138 
139 int nftnl_set_str_attr(const char **dptr, uint32_t *flags,
140  uint16_t attr, const void *data, uint32_t data_len)
141 {
142  if (*flags & (1 << attr))
143  xfree(*dptr);
144 
145  *dptr = strndup(data, data_len);
146  if (!*dptr)
147  return -1;
148 
149  *flags |= (1 << attr);
150  return 0;
151 }
152 
153 static bool is_wildcard_str(const char *str)
154 {
155  size_t len = strlen(str);
156 
157  if (len < 1 || str[len - 1] != '*')
158  return false;
159  if (len < 2 || str[len - 2] != '\\')
160  return true;
161  /* XXX: ignore backslash escaping for now */
162  return false;
163 }
164 
165 void nftnl_attr_put_ifname(struct nlmsghdr *nlh, const char *ifname)
166 {
167  uint16_t attr = NFTA_DEVICE_NAME;
168  char pfx[IFNAMSIZ];
169 
170  if (is_wildcard_str(ifname)) {
171  snprintf(pfx, IFNAMSIZ, "%s", ifname);
172  pfx[strlen(pfx) - 1] = '\0';
173 
174  attr = NFTA_DEVICE_PREFIX;
175  ifname = pfx;
176  }
177  mnl_attr_put_strz(nlh, attr, ifname);
178 }
179 
180 char *nftnl_attr_get_ifname(const struct nlattr *attr)
181 {
182  const char *dev = mnl_attr_get_str(attr);
183  char buf[IFNAMSIZ];
184 
185  switch (mnl_attr_get_type(attr)) {
186  case NFTA_DEVICE_NAME:
187  return strdup(dev);
188  case NFTA_DEVICE_PREFIX:
189  snprintf(buf, IFNAMSIZ, "%s*", dev);
190  return strdup(buf);
191  default:
192  return NULL;
193  }
194 }
195 
196 int nftnl_parse_str_attr(const struct nlattr *tb, int attr,
197  const char **field, uint32_t *flags)
198 {
199  if (!tb)
200  return 0;
201 
202  if (*flags & (1 << attr))
203  xfree(*field);
204  *field = strdup(mnl_attr_get_str(tb));
205  if (!*field)
206  return -1;
207  *flags |= (1 << attr);
208  return 0;
209 }