libnftnl  1.2.8
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 
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_target_set(struct nftnl_expr *e, uint16_t type,
39  const void *data, uint32_t data_len)
40 {
41  struct nftnl_expr_target *tg = nftnl_expr_data(e);
42 
43  switch(type) {
44  case NFTNL_EXPR_TG_NAME:
45  snprintf(tg->name, sizeof(tg->name), "%.*s", data_len,
46  (const char *) data);
47  break;
48  case NFTNL_EXPR_TG_REV:
49  memcpy(&tg->rev, data, data_len);
50  break;
51  case NFTNL_EXPR_TG_INFO:
52  if (e->flags & (1 << NFTNL_EXPR_TG_INFO))
53  xfree(tg->data);
54 
55  tg->data = data;
56  tg->data_len = data_len;
57  break;
58  }
59  return 0;
60 }
61 
62 static const void *
63 nftnl_expr_target_get(const struct nftnl_expr *e, uint16_t type,
64  uint32_t *data_len)
65 {
66  struct nftnl_expr_target *tg = nftnl_expr_data(e);
67 
68  switch(type) {
69  case NFTNL_EXPR_TG_NAME:
70  *data_len = sizeof(tg->name);
71  return tg->name;
72  case NFTNL_EXPR_TG_REV:
73  *data_len = sizeof(tg->rev);
74  return &tg->rev;
75  case NFTNL_EXPR_TG_INFO:
76  *data_len = tg->data_len;
77  return tg->data;
78  }
79  return NULL;
80 }
81 
82 static int nftnl_expr_target_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_TARGET_MAX) < 0)
88  return MNL_CB_OK;
89 
90  switch(type) {
91  case NFTA_TARGET_NAME:
92  if (mnl_attr_validate(attr, MNL_TYPE_NUL_STRING) < 0)
93  abi_breakage();
94  break;
95  case NFTA_TARGET_REV:
96  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
97  abi_breakage();
98  break;
99  case NFTA_TARGET_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_target_build(struct nlmsghdr *nlh, const struct nftnl_expr *e)
111 {
112  struct nftnl_expr_target *tg = nftnl_expr_data(e);
113 
114  if (e->flags & (1 << NFTNL_EXPR_TG_NAME))
115  mnl_attr_put_strz(nlh, NFTA_TARGET_NAME, tg->name);
116  if (e->flags & (1 << NFTNL_EXPR_TG_REV))
117  mnl_attr_put_u32(nlh, NFTA_TARGET_REV, htonl(tg->rev));
118  if (e->flags & (1 << NFTNL_EXPR_TG_INFO))
119  mnl_attr_put(nlh, NFTA_TARGET_INFO, tg->data_len, tg->data);
120 }
121 
122 static int nftnl_expr_target_parse(struct nftnl_expr *e, struct nlattr *attr)
123 {
124  struct nftnl_expr_target *target = nftnl_expr_data(e);
125  struct nlattr *tb[NFTA_TARGET_MAX+1] = {};
126 
127  if (mnl_attr_parse_nested(attr, nftnl_expr_target_cb, tb) < 0)
128  return -1;
129 
130  if (tb[NFTA_TARGET_NAME]) {
131  snprintf(target->name, XT_EXTENSION_MAXNAMELEN, "%s",
132  mnl_attr_get_str(tb[NFTA_TARGET_NAME]));
133 
134  target->name[XT_EXTENSION_MAXNAMELEN-1] = '\0';
135  e->flags |= (1 << NFTNL_EXPR_TG_NAME);
136  }
137 
138  if (tb[NFTA_TARGET_REV]) {
139  target->rev = ntohl(mnl_attr_get_u32(tb[NFTA_TARGET_REV]));
140  e->flags |= (1 << NFTNL_EXPR_TG_REV);
141  }
142 
143  if (tb[NFTA_TARGET_INFO]) {
144  uint32_t len = mnl_attr_get_payload_len(tb[NFTA_TARGET_INFO]);
145  void *target_data;
146 
147  if (target->data)
148  xfree(target->data);
149 
150  target_data = calloc(1, len);
151  if (target_data == NULL)
152  return -1;
153 
154  memcpy(target_data, mnl_attr_get_payload(tb[NFTA_TARGET_INFO]), len);
155 
156  target->data = target_data;
157  target->data_len = len;
158 
159  e->flags |= (1 << NFTNL_EXPR_TG_INFO);
160  }
161 
162  return 0;
163 }
164 
165 static int
166 nftnl_expr_target_snprintf(char *buf, size_t len,
167  uint32_t flags, const struct nftnl_expr *e)
168 {
169  struct nftnl_expr_target *target = nftnl_expr_data(e);
170 
171  return snprintf(buf, len, "name %s rev %u ", target->name, target->rev);
172 }
173 
174 static void nftnl_expr_target_free(const struct nftnl_expr *e)
175 {
176  struct nftnl_expr_target *target = nftnl_expr_data(e);
177 
178  xfree(target->data);
179 }
180 
181 static struct attr_policy target_attr_policy[__NFTNL_EXPR_TG_MAX] = {
182  [NFTNL_EXPR_TG_NAME] = { .maxlen = XT_EXTENSION_MAXNAMELEN },
183  [NFTNL_EXPR_TG_REV] = { .maxlen = sizeof(uint32_t) },
184  [NFTNL_EXPR_TG_INFO] = { .maxlen = 0 },
185 };
186 
187 struct expr_ops expr_ops_target = {
188  .name = "target",
189  .alloc_len = sizeof(struct nftnl_expr_target),
190  .nftnl_max_attr = __NFTNL_EXPR_TG_MAX - 1,
191  .attr_policy = target_attr_policy,
192  .free = nftnl_expr_target_free,
193  .set = nftnl_expr_target_set,
194  .get = nftnl_expr_target_get,
195  .parse = nftnl_expr_target_parse,
196  .build = nftnl_expr_target_build,
197  .output = nftnl_expr_target_snprintf,
198 };