libnftnl  1.2.8
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, data_len);
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  }
59  return 0;
60 }
61 
62 static const void *
63 nftnl_expr_match_get(const struct nftnl_expr *e, uint16_t type,
64  uint32_t *data_len)
65 {
66  struct nftnl_expr_match *mt = nftnl_expr_data(e);
67 
68  switch(type) {
69  case NFTNL_EXPR_MT_NAME:
70  *data_len = sizeof(mt->name);
71  return mt->name;
72  case NFTNL_EXPR_MT_REV:
73  *data_len = sizeof(mt->rev);
74  return &mt->rev;
75  case NFTNL_EXPR_MT_INFO:
76  *data_len = mt->data_len;
77  return mt->data;
78  }
79  return NULL;
80 }
81 
82 static int nftnl_expr_match_cb(const struct nlattr *attr, void *data)
83 {
84  const struct nlattr **tb = data;
85  int type = mnl_attr_get_type(attr);
86 
87  if (mnl_attr_type_valid(attr, NFTA_MATCH_MAX) < 0)
88  return MNL_CB_OK;
89 
90  switch(type) {
91  case NFTA_MATCH_NAME:
92  if (mnl_attr_validate(attr, MNL_TYPE_NUL_STRING) < 0)
93  abi_breakage();
94  break;
95  case NFTA_MATCH_REV:
96  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
97  abi_breakage();
98  break;
99  case NFTA_MATCH_INFO:
100  if (mnl_attr_validate(attr, MNL_TYPE_BINARY) < 0)
101  abi_breakage();
102  break;
103  }
104 
105  tb[type] = attr;
106  return MNL_CB_OK;
107 }
108 
109 static void
110 nftnl_expr_match_build(struct nlmsghdr *nlh, const struct nftnl_expr *e)
111 {
112  struct nftnl_expr_match *mt = nftnl_expr_data(e);
113 
114  if (e->flags & (1 << NFTNL_EXPR_MT_NAME))
115  mnl_attr_put_strz(nlh, NFTA_MATCH_NAME, mt->name);
116  if (e->flags & (1 << NFTNL_EXPR_MT_REV))
117  mnl_attr_put_u32(nlh, NFTA_MATCH_REV, htonl(mt->rev));
118  if (e->flags & (1 << NFTNL_EXPR_MT_INFO))
119  mnl_attr_put(nlh, NFTA_MATCH_INFO, mt->data_len, mt->data);
120 }
121 
122 static int nftnl_expr_match_parse(struct nftnl_expr *e, struct nlattr *attr)
123 {
124  struct nftnl_expr_match *match = nftnl_expr_data(e);
125  struct nlattr *tb[NFTA_MATCH_MAX+1] = {};
126 
127  if (mnl_attr_parse_nested(attr, nftnl_expr_match_cb, tb) < 0)
128  return -1;
129 
130  if (tb[NFTA_MATCH_NAME]) {
131  snprintf(match->name, XT_EXTENSION_MAXNAMELEN, "%s",
132  mnl_attr_get_str(tb[NFTA_MATCH_NAME]));
133 
134  match->name[XT_EXTENSION_MAXNAMELEN-1] = '\0';
135  e->flags |= (1 << NFTNL_EXPR_MT_NAME);
136  }
137 
138  if (tb[NFTA_MATCH_REV]) {
139  match->rev = ntohl(mnl_attr_get_u32(tb[NFTA_MATCH_REV]));
140  e->flags |= (1 << NFTNL_EXPR_MT_REV);
141  }
142 
143  if (tb[NFTA_MATCH_INFO]) {
144  uint32_t len = mnl_attr_get_payload_len(tb[NFTA_MATCH_INFO]);
145  void *match_data;
146 
147  if (e->flags & (1 << NFTNL_EXPR_MT_INFO))
148  xfree(match->data);
149 
150  match_data = calloc(1, len);
151  if (match_data == NULL)
152  return -1;
153 
154  memcpy(match_data, mnl_attr_get_payload(tb[NFTA_MATCH_INFO]), len);
155 
156  match->data = match_data;
157  match->data_len = len;
158 
159  e->flags |= (1 << NFTNL_EXPR_MT_INFO);
160  }
161 
162  return 0;
163 }
164 
165 static int
166 nftnl_expr_match_snprintf(char *buf, size_t len,
167  uint32_t flags, const struct nftnl_expr *e)
168 {
169  struct nftnl_expr_match *match = nftnl_expr_data(e);
170 
171  return snprintf(buf, len, "name %s rev %u ", match->name, match->rev);
172 }
173 
174 static void nftnl_expr_match_free(const struct nftnl_expr *e)
175 {
176  struct nftnl_expr_match *match = nftnl_expr_data(e);
177 
178  xfree(match->data);
179 }
180 
181 static struct attr_policy match_attr_policy[__NFTNL_EXPR_MT_MAX] = {
182  [NFTNL_EXPR_MT_NAME] = { .maxlen = XT_EXTENSION_MAXNAMELEN },
183  [NFTNL_EXPR_MT_REV] = { .maxlen = sizeof(uint32_t) },
184  [NFTNL_EXPR_MT_INFO] = { .maxlen = 0 },
185 };
186 
187 struct expr_ops expr_ops_match = {
188  .name = "match",
189  .alloc_len = sizeof(struct nftnl_expr_match),
190  .nftnl_max_attr = __NFTNL_EXPR_MT_MAX - 1,
191  .attr_policy = match_attr_policy,
192  .free = nftnl_expr_match_free,
193  .set = nftnl_expr_match_set,
194  .get = nftnl_expr_match_get,
195  .parse = nftnl_expr_match_parse,
196  .build = nftnl_expr_match_build,
197  .output = nftnl_expr_match_snprintf,
198 };