libnftnl  1.2.5
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 
24 #include <libnftnl/expr.h>
25 #include <libnftnl/rule.h>
26 
27 /* From include/linux/netfilter/x_tables.h */
28 #define XT_EXTENSION_MAXNAMELEN 29
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 nftnl_expr_match_set(struct nftnl_expr *e, uint16_t type,
39  const void *data, uint32_t data_len)
40 {
41  struct nftnl_expr_match *mt = nftnl_expr_data(e);
42 
43  switch(type) {
44  case NFTNL_EXPR_MT_NAME:
45  snprintf(mt->name, sizeof(mt->name), "%.*s", data_len,
46  (const char *)data);
47  break;
48  case NFTNL_EXPR_MT_REV:
49  memcpy(&mt->rev, data, sizeof(mt->rev));
50  break;
51  case NFTNL_EXPR_MT_INFO:
52  if (e->flags & (1 << NFTNL_EXPR_MT_INFO))
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 nftnl_expr_match_get(const struct nftnl_expr *e, uint16_t type,
66  uint32_t *data_len)
67 {
68  struct nftnl_expr_match *mt = nftnl_expr_data(e);
69 
70  switch(type) {
71  case NFTNL_EXPR_MT_NAME:
72  *data_len = sizeof(mt->name);
73  return mt->name;
74  case NFTNL_EXPR_MT_REV:
75  *data_len = sizeof(mt->rev);
76  return &mt->rev;
77  case NFTNL_EXPR_MT_INFO:
78  *data_len = mt->data_len;
79  return mt->data;
80  }
81  return NULL;
82 }
83 
84 static int nftnl_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  abi_breakage();
96  break;
97  case NFTA_MATCH_REV:
98  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
99  abi_breakage();
100  break;
101  case NFTA_MATCH_INFO:
102  if (mnl_attr_validate(attr, MNL_TYPE_BINARY) < 0)
103  abi_breakage();
104  break;
105  }
106 
107  tb[type] = attr;
108  return MNL_CB_OK;
109 }
110 
111 static void
112 nftnl_expr_match_build(struct nlmsghdr *nlh, const struct nftnl_expr *e)
113 {
114  struct nftnl_expr_match *mt = nftnl_expr_data(e);
115 
116  if (e->flags & (1 << NFTNL_EXPR_MT_NAME))
117  mnl_attr_put_strz(nlh, NFTA_MATCH_NAME, mt->name);
118  if (e->flags & (1 << NFTNL_EXPR_MT_REV))
119  mnl_attr_put_u32(nlh, NFTA_MATCH_REV, htonl(mt->rev));
120  if (e->flags & (1 << NFTNL_EXPR_MT_INFO))
121  mnl_attr_put(nlh, NFTA_MATCH_INFO, mt->data_len, mt->data);
122 }
123 
124 static int nftnl_expr_match_parse(struct nftnl_expr *e, struct nlattr *attr)
125 {
126  struct nftnl_expr_match *match = nftnl_expr_data(e);
127  struct nlattr *tb[NFTA_MATCH_MAX+1] = {};
128 
129  if (mnl_attr_parse_nested(attr, nftnl_expr_match_cb, tb) < 0)
130  return -1;
131 
132  if (tb[NFTA_MATCH_NAME]) {
133  snprintf(match->name, XT_EXTENSION_MAXNAMELEN, "%s",
134  mnl_attr_get_str(tb[NFTA_MATCH_NAME]));
135 
136  match->name[XT_EXTENSION_MAXNAMELEN-1] = '\0';
137  e->flags |= (1 << NFTNL_EXPR_MT_NAME);
138  }
139 
140  if (tb[NFTA_MATCH_REV]) {
141  match->rev = ntohl(mnl_attr_get_u32(tb[NFTA_MATCH_REV]));
142  e->flags |= (1 << NFTNL_EXPR_MT_REV);
143  }
144 
145  if (tb[NFTA_MATCH_INFO]) {
146  uint32_t len = mnl_attr_get_payload_len(tb[NFTA_MATCH_INFO]);
147  void *match_data;
148 
149  if (e->flags & (1 << NFTNL_EXPR_MT_INFO))
150  xfree(match->data);
151 
152  match_data = calloc(1, len);
153  if (match_data == NULL)
154  return -1;
155 
156  memcpy(match_data, mnl_attr_get_payload(tb[NFTA_MATCH_INFO]), len);
157 
158  match->data = match_data;
159  match->data_len = len;
160 
161  e->flags |= (1 << NFTNL_EXPR_MT_INFO);
162  }
163 
164  return 0;
165 }
166 
167 static int
168 nftnl_expr_match_snprintf(char *buf, size_t len,
169  uint32_t flags, const struct nftnl_expr *e)
170 {
171  struct nftnl_expr_match *match = nftnl_expr_data(e);
172 
173  return snprintf(buf, len, "name %s rev %u ", match->name, match->rev);
174 }
175 
176 static void nftnl_expr_match_free(const struct nftnl_expr *e)
177 {
178  struct nftnl_expr_match *match = nftnl_expr_data(e);
179 
180  xfree(match->data);
181 }
182 
183 struct expr_ops expr_ops_match = {
184  .name = "match",
185  .alloc_len = sizeof(struct nftnl_expr_match),
186  .max_attr = NFTA_MATCH_MAX,
187  .free = nftnl_expr_match_free,
188  .set = nftnl_expr_match_set,
189  .get = nftnl_expr_match_get,
190  .parse = nftnl_expr_match_parse,
191  .build = nftnl_expr_match_build,
192  .output = nftnl_expr_match_snprintf,
193 };