libnftnl  1.0.2
target.c
1 /*
2  * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org>
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  * This code has been sponsored by Sophos Astaro <http://www.sophos.com>
10  */
11 
12 #include "internal.h"
13 
14 #include <stdio.h>
15 #include <stdint.h>
16 #include <string.h> /* for memcpy */
17 #include <arpa/inet.h>
18 #include <errno.h>
19 #include <libmnl/libmnl.h>
20 
21 #include <linux/netfilter/nf_tables.h>
22 #include <linux/netfilter/nf_tables_compat.h>
23 #include <linux/netfilter/x_tables.h>
24 
25 #include <libnftnl/expr.h>
26 #include <libnftnl/rule.h>
27 
28 #include "expr_ops.h"
29 
31  char name[XT_EXTENSION_MAXNAMELEN];
32  uint32_t rev;
33  uint32_t data_len;
34  const void *data;
35 };
36 
37 static int
38 nft_rule_expr_target_set(struct nft_rule_expr *e, uint16_t type,
39  const void *data, uint32_t data_len)
40 {
41  struct nft_expr_target *tg = nft_expr_data(e);
42 
43  switch(type) {
44  case NFT_EXPR_TG_NAME:
45  snprintf(tg->name, sizeof(tg->name), "%.*s", data_len,
46  (const char *) data);
47  break;
48  case NFT_EXPR_TG_REV:
49  tg->rev = *((uint32_t *)data);
50  break;
51  case NFT_EXPR_TG_INFO:
52  if (tg->data)
53  xfree(tg->data);
54 
55  tg->data = data;
56  tg->data_len = data_len;
57  break;
58  default:
59  return -1;
60  }
61  return 0;
62 }
63 
64 static const void *
65 nft_rule_expr_target_get(const struct nft_rule_expr *e, uint16_t type,
66  uint32_t *data_len)
67 {
68  struct nft_expr_target *tg = nft_expr_data(e);
69 
70  switch(type) {
71  case NFT_EXPR_TG_NAME:
72  *data_len = sizeof(tg->name);
73  return tg->name;
74  case NFT_EXPR_TG_REV:
75  *data_len = sizeof(tg->rev);
76  return &tg->rev;
77  case NFT_EXPR_TG_INFO:
78  *data_len = tg->data_len;
79  return tg->data;
80  }
81  return NULL;
82 }
83 
84 static int nft_rule_expr_target_cb(const struct nlattr *attr, void *data)
85 {
86  const struct nlattr **tb = data;
87  int type = mnl_attr_get_type(attr);
88 
89  if (mnl_attr_type_valid(attr, NFTA_TARGET_MAX) < 0)
90  return MNL_CB_OK;
91 
92  switch(type) {
93  case NFTA_TARGET_NAME:
94  if (mnl_attr_validate(attr, MNL_TYPE_NUL_STRING) < 0) {
95  perror("mnl_attr_validate");
96  return MNL_CB_ERROR;
97  }
98  break;
99  case NFTA_TARGET_REV:
100  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
101  perror("mnl_attr_validate");
102  return MNL_CB_ERROR;
103  }
104  break;
105  case NFTA_TARGET_INFO:
106  if (mnl_attr_validate(attr, MNL_TYPE_BINARY) < 0) {
107  perror("mnl_attr_validate");
108  return MNL_CB_ERROR;
109  }
110  break;
111  }
112 
113  tb[type] = attr;
114  return MNL_CB_OK;
115 }
116 
117 static void
118 nft_rule_expr_target_build(struct nlmsghdr *nlh, struct nft_rule_expr *e)
119 {
120  struct nft_expr_target *tg = nft_expr_data(e);
121 
122  if (e->flags & (1 << NFT_EXPR_TG_NAME))
123  mnl_attr_put_strz(nlh, NFTA_TARGET_NAME, tg->name);
124  if (e->flags & (1 << NFT_EXPR_TG_REV))
125  mnl_attr_put_u32(nlh, NFTA_TARGET_REV, htonl(tg->rev));
126  if (e->flags & (1 << NFT_EXPR_TG_INFO))
127  mnl_attr_put(nlh, NFTA_TARGET_INFO, tg->data_len, tg->data);
128 }
129 
130 static int nft_rule_expr_target_parse(struct nft_rule_expr *e, struct nlattr *attr)
131 {
132  struct nft_expr_target *target = nft_expr_data(e);
133  struct nlattr *tb[NFTA_TARGET_MAX+1] = {};
134 
135  if (mnl_attr_parse_nested(attr, nft_rule_expr_target_cb, tb) < 0)
136  return -1;
137 
138  if (tb[NFTA_TARGET_NAME]) {
139  snprintf(target->name, XT_EXTENSION_MAXNAMELEN, "%s",
140  mnl_attr_get_str(tb[NFTA_TARGET_NAME]));
141 
142  target->name[XT_EXTENSION_MAXNAMELEN-1] = '\0';
143  e->flags |= (1 << NFT_EXPR_TG_NAME);
144  }
145 
146  if (tb[NFTA_TARGET_REV]) {
147  target->rev = ntohl(mnl_attr_get_u32(tb[NFTA_TARGET_REV]));
148  e->flags |= (1 << NFT_EXPR_TG_REV);
149  }
150 
151  if (tb[NFTA_TARGET_INFO]) {
152  uint32_t len = mnl_attr_get_payload_len(tb[NFTA_TARGET_INFO]);
153  void *target_data;
154 
155  if (target->data)
156  xfree(target->data);
157 
158  target_data = calloc(1, len);
159  if (target_data == NULL)
160  return -1;
161 
162  memcpy(target_data, mnl_attr_get_payload(tb[NFTA_TARGET_INFO]), len);
163 
164  target->data = target_data;
165  target->data_len = len;
166 
167  e->flags |= (1 << NFT_EXPR_TG_INFO);
168  }
169 
170  return 0;
171 }
172 
173 static int
174 nft_rule_expr_target_json_parse(struct nft_rule_expr *e, json_t *root,
175  struct nft_parse_err *err)
176 {
177 #ifdef JSON_PARSING
178  const char *name;
179 
180  name = nft_jansson_parse_str(root, "name", err);
181  if (name != NULL)
182  nft_rule_expr_set_str(e, NFT_EXPR_TG_NAME, name);
183 
184  return 0;
185 #else
186  errno = EOPNOTSUPP;
187  return -1;
188 #endif
189 }
190 
191 static int
192 nft_rule_expr_target_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree,
193  struct nft_parse_err *err)
194 {
195 #ifdef XML_PARSING
196  const char *name;
197 
198  name = nft_mxml_str_parse(tree, "name", MXML_DESCEND_FIRST,
199  NFT_XML_MAND, err);
200  if (name != NULL)
201  nft_rule_expr_set_str(e, NFT_EXPR_TG_NAME, name);
202 
203  /* tg->info is ignored until other solution is reached */
204 
205  return 0;
206 #else
207  errno = EOPNOTSUPP;
208  return -1;
209 #endif
210 }
211 
212 static int nft_rule_exp_target_snprintf_json(char *buf, size_t len,
213  struct nft_rule_expr *e)
214 {
215  struct nft_expr_target *target = nft_expr_data(e);
216  int ret, size = len, offset = 0;
217 
218  if (e->flags & (1 << NFT_EXPR_TG_NAME)) {
219  ret = snprintf(buf, len, "\"name\":\"%s\"", target->name);
220  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
221  }
222 
223  return offset;
224 }
225 
226 static int nft_rule_exp_target_snprintf_xml(char *buf, size_t len,
227  struct nft_rule_expr *e)
228 {
229  struct nft_expr_target *target = nft_expr_data(e);
230  int ret, size=len;
231  int offset = 0;
232 
233  if (e->flags & (1 << NFT_EXPR_TG_NAME)) {
234  ret = snprintf(buf, len, "<name>%s</name>", target->name);
235  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
236  }
237 
238  return offset;
239 }
240 
241 static int
242 nft_rule_expr_target_snprintf(char *buf, size_t len, uint32_t type,
243  uint32_t flags, struct nft_rule_expr *e)
244 {
245  struct nft_expr_target *target = nft_expr_data(e);
246 
247  switch(type) {
248  case NFT_OUTPUT_DEFAULT:
249  return snprintf(buf, len, "name %s rev %u ",
250  target->name, target->rev);
251  case NFT_OUTPUT_XML:
252  return nft_rule_exp_target_snprintf_xml(buf, len, e);
253  case NFT_OUTPUT_JSON:
254  return nft_rule_exp_target_snprintf_json(buf, len, e);
255  default:
256  break;
257  }
258  return -1;
259 }
260 
261 static void nft_rule_expr_target_free(struct nft_rule_expr *e)
262 {
263  struct nft_expr_target *target = nft_expr_data(e);
264 
265  xfree(target->data);
266 }
267 
268 struct expr_ops expr_ops_target = {
269  .name = "target",
270  .alloc_len = sizeof(struct nft_expr_target),
271  .max_attr = NFTA_TARGET_MAX,
272  .free = nft_rule_expr_target_free,
273  .set = nft_rule_expr_target_set,
274  .get = nft_rule_expr_target_get,
275  .parse = nft_rule_expr_target_parse,
276  .build = nft_rule_expr_target_build,
277  .snprintf = nft_rule_expr_target_snprintf,
278  .xml_parse = nft_rule_expr_target_xml_parse,
279  .json_parse = nft_rule_expr_target_json_parse,
280 };
281 
282 static void __init expr_target_init(void)
283 {
284  nft_expr_ops_register(&expr_ops_target);
285 }