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