libnftnl  1.2.9
meta.c
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3  * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org>
4  *
5  * This code has been sponsored by Sophos Astaro <http://www.sophos.com>
6  */
7 
8 #include <stdio.h>
9 #include <stdint.h>
10 #include <string.h>
11 #include <arpa/inet.h>
12 #include <errno.h>
13 #include <linux/netfilter/nf_tables.h>
14 
15 #include "internal.h"
16 #include <libmnl/libmnl.h>
17 #include <libnftnl/expr.h>
18 #include <libnftnl/rule.h>
19 
20 #ifndef NFT_META_MAX
21 #define NFT_META_MAX (NFT_META_BRI_BROUTE + 1)
22 #endif
23 
25  enum nft_meta_keys key;
26  enum nft_registers dreg;
27  enum nft_registers sreg;
28 };
29 
30 static int
31 nftnl_expr_meta_set(struct nftnl_expr *e, uint16_t type,
32  const void *data, uint32_t data_len)
33 {
34  struct nftnl_expr_meta *meta = nftnl_expr_data(e);
35 
36  switch(type) {
37  case NFTNL_EXPR_META_KEY:
38  memcpy(&meta->key, data, data_len);
39  break;
40  case NFTNL_EXPR_META_DREG:
41  memcpy(&meta->dreg, data, data_len);
42  break;
43  case NFTNL_EXPR_META_SREG:
44  memcpy(&meta->sreg, data, data_len);
45  break;
46  }
47  return 0;
48 }
49 
50 static const void *
51 nftnl_expr_meta_get(const struct nftnl_expr *e, uint16_t type,
52  uint32_t *data_len)
53 {
54  struct nftnl_expr_meta *meta = nftnl_expr_data(e);
55 
56  switch(type) {
57  case NFTNL_EXPR_META_KEY:
58  *data_len = sizeof(meta->key);
59  return &meta->key;
60  case NFTNL_EXPR_META_DREG:
61  *data_len = sizeof(meta->dreg);
62  return &meta->dreg;
63  case NFTNL_EXPR_META_SREG:
64  *data_len = sizeof(meta->sreg);
65  return &meta->sreg;
66  }
67  return NULL;
68 }
69 
70 static int nftnl_expr_meta_cb(const struct nlattr *attr, void *data)
71 {
72  const struct nlattr **tb = data;
73  int type = mnl_attr_get_type(attr);
74 
75  if (mnl_attr_type_valid(attr, NFTA_META_MAX) < 0)
76  return MNL_CB_OK;
77 
78  switch(type) {
79  case NFTA_META_KEY:
80  case NFTA_META_DREG:
81  case NFTA_META_SREG:
82  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
83  abi_breakage();
84  break;
85  }
86 
87  tb[type] = attr;
88  return MNL_CB_OK;
89 }
90 
91 static void
92 nftnl_expr_meta_build(struct nlmsghdr *nlh, const struct nftnl_expr *e)
93 {
94  struct nftnl_expr_meta *meta = nftnl_expr_data(e);
95 
96  if (e->flags & (1 << NFTNL_EXPR_META_KEY))
97  mnl_attr_put_u32(nlh, NFTA_META_KEY, htonl(meta->key));
98  if (e->flags & (1 << NFTNL_EXPR_META_DREG))
99  mnl_attr_put_u32(nlh, NFTA_META_DREG, htonl(meta->dreg));
100  if (e->flags & (1 << NFTNL_EXPR_META_SREG))
101  mnl_attr_put_u32(nlh, NFTA_META_SREG, htonl(meta->sreg));
102 }
103 
104 static int
105 nftnl_expr_meta_parse(struct nftnl_expr *e, struct nlattr *attr)
106 {
107  struct nftnl_expr_meta *meta = nftnl_expr_data(e);
108  struct nlattr *tb[NFTA_META_MAX+1] = {};
109 
110  if (mnl_attr_parse_nested(attr, nftnl_expr_meta_cb, tb) < 0)
111  return -1;
112 
113  if (tb[NFTA_META_KEY]) {
114  meta->key = ntohl(mnl_attr_get_u32(tb[NFTA_META_KEY]));
115  e->flags |= (1 << NFTNL_EXPR_META_KEY);
116  }
117  if (tb[NFTA_META_DREG]) {
118  meta->dreg = ntohl(mnl_attr_get_u32(tb[NFTA_META_DREG]));
119  e->flags |= (1 << NFTNL_EXPR_META_DREG);
120  }
121  if (tb[NFTA_META_SREG]) {
122  meta->sreg = ntohl(mnl_attr_get_u32(tb[NFTA_META_SREG]));
123  e->flags |= (1 << NFTNL_EXPR_META_SREG);
124  }
125 
126  return 0;
127 }
128 
129 static const char *meta_key2str_array[NFT_META_MAX] = {
130  [NFT_META_LEN] = "len",
131  [NFT_META_PROTOCOL] = "protocol",
132  [NFT_META_NFPROTO] = "nfproto",
133  [NFT_META_L4PROTO] = "l4proto",
134  [NFT_META_PRIORITY] = "priority",
135  [NFT_META_MARK] = "mark",
136  [NFT_META_IIF] = "iif",
137  [NFT_META_OIF] = "oif",
138  [NFT_META_IIFNAME] = "iifname",
139  [NFT_META_OIFNAME] = "oifname",
140  [NFT_META_IIFTYPE] = "iiftype",
141  [NFT_META_OIFTYPE] = "oiftype",
142  [NFT_META_SKUID] = "skuid",
143  [NFT_META_SKGID] = "skgid",
144  [NFT_META_NFTRACE] = "nftrace",
145  [NFT_META_RTCLASSID] = "rtclassid",
146  [NFT_META_SECMARK] = "secmark",
147  [NFT_META_BRI_IIFNAME] = "bri_iifname",
148  [NFT_META_BRI_OIFNAME] = "bri_oifname",
149  [NFT_META_PKTTYPE] = "pkttype",
150  [NFT_META_CPU] = "cpu",
151  [NFT_META_IIFGROUP] = "iifgroup",
152  [NFT_META_OIFGROUP] = "oifgroup",
153  [NFT_META_CGROUP] = "cgroup",
154  [NFT_META_PRANDOM] = "prandom",
155  [NFT_META_SECPATH] = "secpath",
156  [NFT_META_IIFKIND] = "iifkind",
157  [NFT_META_OIFKIND] = "oifkind",
158  [NFT_META_BRI_IIFPVID] = "bri_iifpvid",
159  [NFT_META_BRI_IIFVPROTO] = "bri_iifvproto",
160  [NFT_META_TIME_NS] = "time",
161  [NFT_META_TIME_DAY] = "day",
162  [NFT_META_TIME_HOUR] = "hour",
163  [NFT_META_SDIF] = "sdif",
164  [NFT_META_SDIFNAME] = "sdifname",
165  [NFT_META_BRI_BROUTE] = "broute",
166 };
167 
168 static const char *meta_key2str(uint8_t key)
169 {
170  if (key < NFT_META_MAX)
171  return meta_key2str_array[key];
172 
173  return "unknown";
174 }
175 
176 static int
177 nftnl_expr_meta_snprintf(char *buf, size_t len,
178  uint32_t flags, const struct nftnl_expr *e)
179 {
180  struct nftnl_expr_meta *meta = nftnl_expr_data(e);
181 
182  if (e->flags & (1 << NFTNL_EXPR_META_SREG)) {
183  return snprintf(buf, len, "set %s with reg %u ",
184  meta_key2str(meta->key), meta->sreg);
185  }
186  if (e->flags & (1 << NFTNL_EXPR_META_DREG)) {
187  return snprintf(buf, len, "load %s => reg %u ",
188  meta_key2str(meta->key), meta->dreg);
189  }
190  return 0;
191 }
192 
193 static struct attr_policy meta_attr_policy[__NFTNL_EXPR_META_MAX] = {
194  [NFTNL_EXPR_META_KEY] = { .maxlen = sizeof(uint32_t) },
195  [NFTNL_EXPR_META_DREG] = { .maxlen = sizeof(uint32_t) },
196  [NFTNL_EXPR_META_SREG] = { .maxlen = sizeof(uint32_t) },
197 };
198 
199 struct expr_ops expr_ops_meta = {
200  .name = "meta",
201  .alloc_len = sizeof(struct nftnl_expr_meta),
202  .nftnl_max_attr = __NFTNL_EXPR_META_MAX - 1,
203  .attr_policy = meta_attr_policy,
204  .set = nftnl_expr_meta_set,
205  .get = nftnl_expr_meta_get,
206  .parse = nftnl_expr_meta_parse,
207  .build = nftnl_expr_meta_build,
208  .output = nftnl_expr_meta_snprintf,
209 };