libnftnl  1.2.8
redir.c
1 /*
2  * (C) 2014 by Arturo Borrero Gonzalez <arturo@debian.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 
10 #include <stdio.h>
11 #include <stdint.h>
12 #include <arpa/inet.h>
13 #include <errno.h>
14 #include <inttypes.h>
15 
16 #include <linux/netfilter/nf_tables.h>
17 
18 #include "internal.h"
19 #include <libmnl/libmnl.h>
20 #include <libnftnl/expr.h>
21 #include <libnftnl/rule.h>
22 
24  enum nft_registers sreg_proto_min;
25  enum nft_registers sreg_proto_max;
26  uint32_t flags;
27 };
28 
29 static int
30 nftnl_expr_redir_set(struct nftnl_expr *e, uint16_t type,
31  const void *data, uint32_t data_len)
32 {
33  struct nftnl_expr_redir *redir = nftnl_expr_data(e);
34 
35  switch (type) {
36  case NFTNL_EXPR_REDIR_REG_PROTO_MIN:
37  memcpy(&redir->sreg_proto_min, data, data_len);
38  break;
39  case NFTNL_EXPR_REDIR_REG_PROTO_MAX:
40  memcpy(&redir->sreg_proto_max, data, data_len);
41  break;
42  case NFTNL_EXPR_REDIR_FLAGS:
43  memcpy(&redir->flags, data, data_len);
44  break;
45  }
46  return 0;
47 }
48 
49 static const void *
50 nftnl_expr_redir_get(const struct nftnl_expr *e, uint16_t type,
51  uint32_t *data_len)
52 {
53  struct nftnl_expr_redir *redir = nftnl_expr_data(e);
54 
55  switch (type) {
56  case NFTNL_EXPR_REDIR_REG_PROTO_MIN:
57  *data_len = sizeof(redir->sreg_proto_min);
58  return &redir->sreg_proto_min;
59  case NFTNL_EXPR_REDIR_REG_PROTO_MAX:
60  *data_len = sizeof(redir->sreg_proto_max);
61  return &redir->sreg_proto_max;
62  case NFTNL_EXPR_REDIR_FLAGS:
63  *data_len = sizeof(redir->flags);
64  return &redir->flags;
65  }
66  return NULL;
67 }
68 
69 static int nftnl_expr_redir_cb(const struct nlattr *attr, void *data)
70 {
71  const struct nlattr **tb = data;
72  int type = mnl_attr_get_type(attr);
73 
74  if (mnl_attr_type_valid(attr, NFTA_REDIR_MAX) < 0)
75  return MNL_CB_OK;
76 
77  switch (type) {
78  case NFTA_REDIR_REG_PROTO_MIN:
79  case NFTA_REDIR_REG_PROTO_MAX:
80  case NFTA_REDIR_FLAGS:
81  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
82  abi_breakage();
83  break;
84  }
85 
86  tb[type] = attr;
87  return MNL_CB_OK;
88 }
89 
90 static void
91 nftnl_expr_redir_build(struct nlmsghdr *nlh, const struct nftnl_expr *e)
92 {
93  struct nftnl_expr_redir *redir = nftnl_expr_data(e);
94 
95  if (e->flags & (1 << NFTNL_EXPR_REDIR_REG_PROTO_MIN))
96  mnl_attr_put_u32(nlh, NFTA_REDIR_REG_PROTO_MIN,
97  htobe32(redir->sreg_proto_min));
98  if (e->flags & (1 << NFTNL_EXPR_REDIR_REG_PROTO_MAX))
99  mnl_attr_put_u32(nlh, NFTA_REDIR_REG_PROTO_MAX,
100  htobe32(redir->sreg_proto_max));
101  if (e->flags & (1 << NFTNL_EXPR_REDIR_FLAGS))
102  mnl_attr_put_u32(nlh, NFTA_REDIR_FLAGS, htobe32(redir->flags));
103 }
104 
105 static int
106 nftnl_expr_redir_parse(struct nftnl_expr *e, struct nlattr *attr)
107 {
108  struct nftnl_expr_redir *redir = nftnl_expr_data(e);
109  struct nlattr *tb[NFTA_REDIR_MAX + 1] = {};
110 
111  if (mnl_attr_parse_nested(attr, nftnl_expr_redir_cb, tb) < 0)
112  return -1;
113 
114  if (tb[NFTA_REDIR_REG_PROTO_MIN]) {
115  redir->sreg_proto_min =
116  ntohl(mnl_attr_get_u32(tb[NFTA_REDIR_REG_PROTO_MIN]));
117  e->flags |= (1 << NFTNL_EXPR_REDIR_REG_PROTO_MIN);
118  }
119  if (tb[NFTA_REDIR_REG_PROTO_MAX]) {
120  redir->sreg_proto_max =
121  ntohl(mnl_attr_get_u32(tb[NFTA_REDIR_REG_PROTO_MAX]));
122  e->flags |= (1 << NFTNL_EXPR_REDIR_REG_PROTO_MAX);
123  }
124  if (tb[NFTA_REDIR_FLAGS]) {
125  redir->flags = be32toh(mnl_attr_get_u32(tb[NFTA_REDIR_FLAGS]));
126  e->flags |= (1 << NFTNL_EXPR_REDIR_FLAGS);
127  }
128 
129  return 0;
130 }
131 
132 static int
133 nftnl_expr_redir_snprintf(char *buf, size_t remain,
134  uint32_t flags, const struct nftnl_expr *e)
135 {
136  int ret, offset = 0;
137  struct nftnl_expr_redir *redir = nftnl_expr_data(e);
138 
139  if (nftnl_expr_is_set(e, NFTNL_EXPR_REDIR_REG_PROTO_MIN)) {
140  ret = snprintf(buf + offset, remain, "proto_min reg %u ",
141  redir->sreg_proto_min);
142  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
143  }
144 
145  if (nftnl_expr_is_set(e, NFTNL_EXPR_REDIR_REG_PROTO_MAX)) {
146  ret = snprintf(buf + offset, remain, "proto_max reg %u ",
147  redir->sreg_proto_max);
148  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
149  }
150 
151  if (nftnl_expr_is_set(e, NFTNL_EXPR_REDIR_FLAGS)) {
152  ret = snprintf(buf + offset, remain, "flags 0x%x ",
153  redir->flags);
154  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
155  }
156 
157  return offset;
158 }
159 
160 static struct attr_policy redir_attr_policy[__NFTNL_EXPR_REDIR_MAX] = {
161  [NFTNL_EXPR_REDIR_REG_PROTO_MIN] = { .maxlen = sizeof(uint32_t) },
162  [NFTNL_EXPR_REDIR_REG_PROTO_MAX] = { .maxlen = sizeof(uint32_t) },
163  [NFTNL_EXPR_REDIR_FLAGS] = { .maxlen = sizeof(uint32_t) },
164 };
165 
166 struct expr_ops expr_ops_redir = {
167  .name = "redir",
168  .alloc_len = sizeof(struct nftnl_expr_redir),
169  .nftnl_max_attr = __NFTNL_EXPR_REDIR_MAX - 1,
170  .attr_policy = redir_attr_policy,
171  .set = nftnl_expr_redir_set,
172  .get = nftnl_expr_redir_get,
173  .parse = nftnl_expr_redir_parse,
174  .build = nftnl_expr_redir_build,
175  .output = nftnl_expr_redir_snprintf,
176 };