libnftnl  1.0.2
match.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_match_set(struct nft_rule_expr *e, uint16_t type,
39  const void *data, uint32_t data_len)
40 {
41  struct nft_expr_match *mt = nft_expr_data(e);
42 
43  switch(type) {
44  case NFT_EXPR_MT_NAME:
45  snprintf(mt->name, sizeof(mt->name), "%.*s", data_len,
46  (const char *)data);
47  break;
48  case NFT_EXPR_MT_REV:
49  mt->rev = *((uint32_t *)data);
50  break;
51  case NFT_EXPR_MT_INFO:
52  if (mt->data)
53  xfree(mt->data);
54 
55  mt->data = data;
56  mt->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_match_get(const struct nft_rule_expr *e, uint16_t type,
66  uint32_t *data_len)
67 {
68  struct nft_expr_match *mt = nft_expr_data(e);
69 
70  switch(type) {
71  case NFT_EXPR_MT_NAME:
72  *data_len = sizeof(mt->name);
73  return mt->name;
74  case NFT_EXPR_MT_REV:
75  *data_len = sizeof(mt->rev);
76  return &mt->rev;
77  case NFT_EXPR_MT_INFO:
78  *data_len = mt->data_len;
79  return mt->data;
80  }
81  return NULL;
82 }
83 
84 static int nft_rule_expr_match_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_MATCH_MAX) < 0)
90  return MNL_CB_OK;
91 
92  switch(type) {
93  case NFTA_MATCH_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_MATCH_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_MATCH_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_match_build(struct nlmsghdr *nlh, struct nft_rule_expr *e)
119 {
120  struct nft_expr_match *mt = nft_expr_data(e);
121 
122  if (e->flags & (1 << NFT_EXPR_MT_NAME))
123  mnl_attr_put_strz(nlh, NFTA_MATCH_NAME, mt->name);
124  if (e->flags & (1 << NFT_EXPR_MT_REV))
125  mnl_attr_put_u32(nlh, NFTA_MATCH_REV, htonl(mt->rev));
126  if (e->flags & (1 << NFT_EXPR_MT_INFO))
127  mnl_attr_put(nlh, NFTA_MATCH_INFO, mt->data_len, mt->data);
128 }
129 
130 static int nft_rule_expr_match_parse(struct nft_rule_expr *e, struct nlattr *attr)
131 {
132  struct nft_expr_match *match = nft_expr_data(e);
133  struct nlattr *tb[NFTA_MATCH_MAX+1] = {};
134 
135  if (mnl_attr_parse_nested(attr, nft_rule_expr_match_cb, tb) < 0)
136  return -1;
137 
138  if (tb[NFTA_MATCH_NAME]) {
139  snprintf(match->name, XT_EXTENSION_MAXNAMELEN, "%s",
140  mnl_attr_get_str(tb[NFTA_MATCH_NAME]));
141 
142  match->name[XT_EXTENSION_MAXNAMELEN-1] = '\0';
143  e->flags |= (1 << NFT_EXPR_MT_NAME);
144  }
145 
146  if (tb[NFTA_MATCH_REV]) {
147  match->rev = ntohl(mnl_attr_get_u32(tb[NFTA_MATCH_REV]));
148  e->flags |= (1 << NFT_EXPR_MT_REV);
149  }
150 
151  if (tb[NFTA_MATCH_INFO]) {
152  uint32_t len = mnl_attr_get_payload_len(tb[NFTA_MATCH_INFO]);
153  void *match_data;
154 
155  if (match->data)
156  xfree(match->data);
157 
158  match_data = calloc(1, len);
159  if (match_data == NULL)
160  return -1;
161 
162  memcpy(match_data, mnl_attr_get_payload(tb[NFTA_MATCH_INFO]), len);
163 
164  match->data = match_data;
165  match->data_len = len;
166 
167  e->flags |= (1 << NFT_EXPR_MT_INFO);
168  }
169 
170  return 0;
171 }
172 
173 static int nft_rule_expr_match_json_parse(struct nft_rule_expr *e, json_t *root,
174  struct nft_parse_err *err)
175 {
176 #ifdef JSON_PARSING
177  const char *name;
178 
179  name = nft_jansson_parse_str(root, "name", err);
180  if (name != NULL)
181  nft_rule_expr_set_str(e, NFT_EXPR_MT_NAME, name);
182 
183  return 0;
184 #else
185  errno = EOPNOTSUPP;
186  return -1;
187 #endif
188 }
189 
190 
191 static int nft_rule_expr_match_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree,
192  struct nft_parse_err *err)
193 {
194 #ifdef XML_PARSING
195  const char *name;
196 
197  name = nft_mxml_str_parse(tree, "name", MXML_DESCEND_FIRST,
198  NFT_XML_MAND, err);
199  if (name != NULL)
200  nft_rule_expr_set_str(e, NFT_EXPR_MT_NAME, name);
201 
202  /* mt->info is ignored until other solution is reached */
203 
204  return 0;
205 #else
206  errno = EOPNOTSUPP;
207  return -1;
208 #endif
209 }
210 
211 static int nft_rule_expr_match_snprintf_json(char *buf, size_t len,
212  struct nft_rule_expr *e)
213 {
214  struct nft_expr_match *mt = nft_expr_data(e);
215  int ret, size = len, offset = 0;
216 
217  if (e->flags & (1 << NFT_EXPR_MT_NAME)) {
218  ret = snprintf(buf, len, "\"name\":\"%s\"", mt->name);
219  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
220  }
221 
222  return offset;
223 }
224 
225 static int nft_rule_expr_match_snprintf_xml(char *buf, size_t len,
226  struct nft_rule_expr *e)
227 {
228  struct nft_expr_match *mt = nft_expr_data(e);
229  int ret, size=len;
230  int offset = 0;
231 
232  if (e->flags & (1 << NFT_EXPR_MT_NAME)) {
233  ret = snprintf(buf, len, "<name>%s</name>", mt->name);
234  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
235  }
236 
237  return offset;
238 }
239 
240 static int
241 nft_rule_expr_match_snprintf(char *buf, size_t len, uint32_t type,
242  uint32_t flags, struct nft_rule_expr *e)
243 {
244  struct nft_expr_match *match = nft_expr_data(e);
245 
246  switch(type) {
247  case NFT_OUTPUT_DEFAULT:
248  return snprintf(buf, len, "name %s rev %u ",
249  match->name, match->rev);
250  case NFT_OUTPUT_XML:
251  return nft_rule_expr_match_snprintf_xml(buf, len, e);
252  case NFT_OUTPUT_JSON:
253  return nft_rule_expr_match_snprintf_json(buf, len, e);
254  default:
255  break;
256  }
257  return -1;
258 }
259 
260 static void nft_rule_expr_match_free(struct nft_rule_expr *e)
261 {
262  struct nft_expr_match *match = nft_expr_data(e);
263 
264  xfree(match->data);
265 }
266 
267 struct expr_ops expr_ops_match = {
268  .name = "match",
269  .alloc_len = sizeof(struct nft_expr_match),
270  .max_attr = NFTA_MATCH_MAX,
271  .free = nft_rule_expr_match_free,
272  .set = nft_rule_expr_match_set,
273  .get = nft_rule_expr_match_get,
274  .parse = nft_rule_expr_match_parse,
275  .build = nft_rule_expr_match_build,
276  .snprintf = nft_rule_expr_match_snprintf,
277  .xml_parse = nft_rule_expr_match_xml_parse,
278  .json_parse = nft_rule_expr_match_json_parse,
279 };
280 
281 static void __init expr_match_init(void)
282 {
283  nft_expr_ops_register(&expr_ops_match);
284 }