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