libnftnl  1.0.2
reject.c
1 /*
2  * (C) 2013 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 <stdio.h>
13 #include <stdint.h>
14 #include <string.h>
15 #include <arpa/inet.h>
16 #include <errno.h>
17 #include <linux/netfilter/nf_tables.h>
18 
19 #include "internal.h"
20 #include <libmnl/libmnl.h>
21 #include <libnftnl/expr.h>
22 #include <libnftnl/rule.h>
23 #include "expr_ops.h"
24 
26  uint32_t type;
27  uint8_t icmp_code;
28 };
29 
30 static int nft_rule_expr_reject_set(struct nft_rule_expr *e, uint16_t type,
31  const void *data, uint32_t data_len)
32 {
33  struct nft_expr_reject *reject = nft_expr_data(e);
34 
35  switch(type) {
36  case NFT_EXPR_REJECT_TYPE:
37  reject->type = *((uint32_t *)data);
38  break;
39  case NFT_EXPR_REJECT_CODE:
40  reject->icmp_code = *((uint8_t *)data);
41  break;
42  default:
43  return -1;
44  }
45  return 0;
46 }
47 
48 static const void *
49 nft_rule_expr_reject_get(const struct nft_rule_expr *e, uint16_t type,
50  uint32_t *data_len)
51 {
52  struct nft_expr_reject *reject = nft_expr_data(e);
53 
54  switch(type) {
55  case NFT_EXPR_REJECT_TYPE:
56  *data_len = sizeof(reject->type);
57  return &reject->type;
58  case NFT_EXPR_REJECT_CODE:
59  *data_len = sizeof(reject->icmp_code);
60  return &reject->icmp_code;
61  }
62  return NULL;
63 }
64 
65 static int nft_rule_expr_reject_cb(const struct nlattr *attr, void *data)
66 {
67  const struct nlattr **tb = data;
68  int type = mnl_attr_get_type(attr);
69 
70  if (mnl_attr_type_valid(attr, NFTA_REJECT_MAX) < 0)
71  return MNL_CB_OK;
72 
73  switch(type) {
74  case NFTA_REJECT_TYPE:
75  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
76  perror("mnl_attr_validate");
77  return MNL_CB_ERROR;
78  }
79  break;
80  case NFTA_REJECT_ICMP_CODE:
81  if (mnl_attr_validate(attr, MNL_TYPE_U8) < 0) {
82  perror("mnl_attr_validate");
83  return MNL_CB_ERROR;
84  }
85  break;
86  }
87 
88  tb[type] = attr;
89  return MNL_CB_OK;
90 }
91 
92 static void
93 nft_rule_expr_reject_build(struct nlmsghdr *nlh, struct nft_rule_expr *e)
94 {
95  struct nft_expr_reject *reject = nft_expr_data(e);
96 
97  if (e->flags & (1 << NFT_EXPR_REJECT_TYPE))
98  mnl_attr_put_u32(nlh, NFTA_REJECT_TYPE, htonl(reject->type));
99  if (e->flags & (1 << NFT_EXPR_REJECT_CODE))
100  mnl_attr_put_u8(nlh, NFTA_REJECT_ICMP_CODE, reject->icmp_code);
101 }
102 
103 static int
104 nft_rule_expr_reject_parse(struct nft_rule_expr *e, struct nlattr *attr)
105 {
106  struct nft_expr_reject *reject = nft_expr_data(e);
107  struct nlattr *tb[NFTA_REJECT_MAX+1] = {};
108 
109  if (mnl_attr_parse_nested(attr, nft_rule_expr_reject_cb, tb) < 0)
110  return -1;
111 
112  if (tb[NFTA_REJECT_TYPE]) {
113  reject->type = ntohl(mnl_attr_get_u32(tb[NFTA_REJECT_TYPE]));
114  e->flags |= (1 << NFT_EXPR_REJECT_TYPE);
115  }
116  if (tb[NFTA_REJECT_ICMP_CODE]) {
117  reject->icmp_code = mnl_attr_get_u8(tb[NFTA_REJECT_ICMP_CODE]);
118  e->flags |= (1 << NFT_EXPR_REJECT_CODE);
119  }
120 
121  return 0;
122 }
123 
124 static int
125 nft_rule_expr_reject_json_parse(struct nft_rule_expr *e, json_t *root,
126  struct nft_parse_err *err)
127 {
128 #ifdef JSON_PARSING
129  uint32_t type;
130  uint8_t code;
131 
132  if (nft_jansson_parse_val(root, "type", NFT_TYPE_U32, &type, err) == 0)
133  nft_rule_expr_set_u32(e, NFT_EXPR_REJECT_TYPE, type);
134 
135  if (nft_jansson_parse_val(root, "code", NFT_TYPE_U8, &code, err) == 0)
136  nft_rule_expr_set_u8(e, NFT_EXPR_REJECT_CODE, code);
137 
138  return 0;
139 #else
140  errno = EOPNOTSUPP;
141  return -1;
142 #endif
143 }
144 
145 static int
146 nft_rule_expr_reject_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree,
147  struct nft_parse_err *err)
148 {
149 #ifdef XML_PARSING
150  uint32_t type;
151  uint8_t code;
152 
153  if (nft_mxml_num_parse(tree, "type", MXML_DESCEND_FIRST, BASE_DEC,
154  &type, NFT_TYPE_U32, NFT_XML_MAND, err) == 0)
155  nft_rule_expr_set_u32(e, NFT_EXPR_REJECT_TYPE, type);
156 
157  if (nft_mxml_num_parse(tree, "code", MXML_DESCEND_FIRST, BASE_DEC,
158  &code, NFT_TYPE_U8, NFT_XML_MAND, err) == 0)
159  nft_rule_expr_set_u8(e, NFT_EXPR_REJECT_CODE, code);
160 
161  return 0;
162 #else
163  errno = EOPNOTSUPP;
164  return -1;
165 #endif
166 }
167 
168 static int nft_rule_expr_reject_snprintf_default(char *buf, size_t len,
169  struct nft_rule_expr *e)
170 {
171  struct nft_expr_reject *reject = nft_expr_data(e);
172 
173  return snprintf(buf, len, "type %u code %u ",
174  reject->type, reject->icmp_code);
175 }
176 
177 static int nft_rule_expr_reject_snprintf_xml(char *buf, size_t len,
178  struct nft_rule_expr *e)
179 {
180  int ret, size = len, offset = 0;
181  struct nft_expr_reject *reject = nft_expr_data(e);
182 
183  if (e->flags & (1 << NFT_EXPR_REJECT_TYPE)) {
184  ret = snprintf(buf+offset, len, "<type>%u</type>",
185  reject->type);
186  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
187  }
188  if (e->flags & (1 << NFT_EXPR_REJECT_CODE)) {
189  ret = snprintf(buf+offset, len, "<code>%u</code>",
190  reject->icmp_code);
191  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
192  }
193 
194  return offset;
195 }
196 
197 static int nft_rule_expr_reject_snprintf_json(char *buf, size_t len,
198  struct nft_rule_expr *e)
199 {
200  int ret, size = len, offset = 0;
201  struct nft_expr_reject *reject = nft_expr_data(e);
202 
203  if (e->flags & (1 << NFT_EXPR_REJECT_TYPE)) {
204  ret = snprintf(buf+offset, len, "\"type\":%u,",
205  reject->type);
206  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
207  }
208  if (e->flags & (1 << NFT_EXPR_REJECT_CODE)) {
209  ret = snprintf(buf+offset, len, "\"code\":%u,",
210  reject->icmp_code);
211  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
212  }
213 
214  if (offset > 0)
215  offset--;
216 
217  return offset;
218 }
219 
220 static int
221 nft_rule_expr_reject_snprintf(char *buf, size_t len, uint32_t type,
222  uint32_t flags, struct nft_rule_expr *e)
223 {
224  switch(type) {
225  case NFT_OUTPUT_DEFAULT:
226  return nft_rule_expr_reject_snprintf_default(buf, len, e);
227  case NFT_OUTPUT_XML:
228  return nft_rule_expr_reject_snprintf_xml(buf, len, e);
229  case NFT_OUTPUT_JSON:
230  return nft_rule_expr_reject_snprintf_json(buf, len, e);
231  default:
232  break;
233  }
234  return -1;
235 }
236 
237 struct expr_ops expr_ops_reject = {
238  .name = "reject",
239  .alloc_len = sizeof(struct nft_expr_reject),
240  .max_attr = NFTA_REJECT_MAX,
241  .set = nft_rule_expr_reject_set,
242  .get = nft_rule_expr_reject_get,
243  .parse = nft_rule_expr_reject_parse,
244  .build = nft_rule_expr_reject_build,
245  .snprintf = nft_rule_expr_reject_snprintf,
246  .xml_parse = nft_rule_expr_reject_xml_parse,
247  .json_parse = nft_rule_expr_reject_json_parse,
248 };
249 
250 static void __init expr_reject_init(void)
251 {
252  nft_expr_ops_register(&expr_ops_reject);
253 }