libnftnl  1.2.9
xfrm.c
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include <stdio.h>
4 #include <string.h>
5 #include <stdint.h>
6 #include <arpa/inet.h>
7 #include <errno.h>
8 #include <linux/netfilter/nf_tables.h>
9 #include <linux/xfrm.h>
10 
11 #include "internal.h"
12 #include <libmnl/libmnl.h>
13 #include <libnftnl/expr.h>
14 #include <libnftnl/rule.h>
15 
17  enum nft_registers dreg;
18  enum nft_xfrm_keys key;
19  uint32_t spnum;
20  uint8_t dir;
21 };
22 
23 static int
24 nftnl_expr_xfrm_set(struct nftnl_expr *e, uint16_t type,
25  const void *data, uint32_t data_len)
26 {
27  struct nftnl_expr_xfrm *x = nftnl_expr_data(e);
28 
29  switch(type) {
30  case NFTNL_EXPR_XFRM_KEY:
31  memcpy(&x->key, data, data_len);
32  break;
33  case NFTNL_EXPR_XFRM_DIR:
34  memcpy(&x->dir, data, data_len);
35  break;
36  case NFTNL_EXPR_XFRM_SPNUM:
37  memcpy(&x->spnum, data, data_len);
38  break;
39  case NFTNL_EXPR_XFRM_DREG:
40  memcpy(&x->dreg, data, data_len);
41  break;
42  default:
43  return -1;
44  }
45  return 0;
46 }
47 
48 static const void *
49 nftnl_expr_xfrm_get(const struct nftnl_expr *e, uint16_t type,
50  uint32_t *data_len)
51 {
52  struct nftnl_expr_xfrm *x = nftnl_expr_data(e);
53 
54  switch(type) {
55  case NFTNL_EXPR_XFRM_KEY:
56  *data_len = sizeof(x->key);
57  return &x->key;
58  case NFTNL_EXPR_XFRM_DIR:
59  *data_len = sizeof(x->dir);
60  return &x->dir;
61  case NFTNL_EXPR_XFRM_SPNUM:
62  *data_len = sizeof(x->spnum);
63  return &x->spnum;
64  case NFTNL_EXPR_XFRM_DREG:
65  *data_len = sizeof(x->dreg);
66  return &x->dreg;
67  }
68  return NULL;
69 }
70 
71 static int nftnl_expr_xfrm_cb(const struct nlattr *attr, void *data)
72 {
73  const struct nlattr **tb = data;
74  int type = mnl_attr_get_type(attr);
75 
76  if (mnl_attr_type_valid(attr, NFTA_XFRM_MAX) < 0)
77  return MNL_CB_OK;
78 
79  switch (type) {
80  case NFTA_XFRM_DREG:
81  case NFTA_XFRM_KEY:
82  case NFTA_XFRM_SPNUM:
83  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
84  abi_breakage();
85  break;
86  case NFTA_XFRM_DIR:
87  if (mnl_attr_validate(attr, MNL_TYPE_U8) < 0)
88  abi_breakage();
89  break;
90  }
91 
92  tb[type] = attr;
93  return MNL_CB_OK;
94 }
95 
96 static void
97 nftnl_expr_xfrm_build(struct nlmsghdr *nlh, const struct nftnl_expr *e)
98 {
99  struct nftnl_expr_xfrm *x = nftnl_expr_data(e);
100 
101  if (e->flags & (1 << NFTNL_EXPR_XFRM_KEY))
102  mnl_attr_put_u32(nlh, NFTA_XFRM_KEY, htonl(x->key));
103  if (e->flags & (1 << NFTNL_EXPR_XFRM_DIR))
104  mnl_attr_put_u8(nlh, NFTA_XFRM_DIR, x->dir);
105  if (e->flags & (1 << NFTNL_EXPR_XFRM_SPNUM))
106  mnl_attr_put_u32(nlh, NFTA_XFRM_SPNUM, htonl(x->spnum));
107  if (e->flags & (1 << NFTNL_EXPR_XFRM_DREG))
108  mnl_attr_put_u32(nlh, NFTA_XFRM_DREG, htonl(x->dreg));
109 }
110 
111 static int
112 nftnl_expr_xfrm_parse(struct nftnl_expr *e, struct nlattr *attr)
113 {
114  struct nftnl_expr_xfrm *x = nftnl_expr_data(e);
115  struct nlattr *tb[NFTA_XFRM_MAX+1] = {};
116 
117  if (mnl_attr_parse_nested(attr, nftnl_expr_xfrm_cb, tb) < 0)
118  return -1;
119 
120  if (tb[NFTA_XFRM_KEY]) {
121  x->key = ntohl(mnl_attr_get_u32(tb[NFTA_XFRM_KEY]));
122  e->flags |= (1 << NFTNL_EXPR_XFRM_KEY);
123  }
124  if (tb[NFTA_XFRM_DIR]) {
125  x->dir = mnl_attr_get_u8(tb[NFTA_XFRM_DIR]);
126  e->flags |= (1 << NFTNL_EXPR_XFRM_DIR);
127  }
128  if (tb[NFTA_XFRM_SPNUM]) {
129  x->spnum = ntohl(mnl_attr_get_u32(tb[NFTA_XFRM_SPNUM]));
130  e->flags |= (1 << NFTNL_EXPR_XFRM_SPNUM);
131  }
132  if (tb[NFTA_XFRM_DREG]) {
133  x->dreg = ntohl(mnl_attr_get_u32(tb[NFTA_XFRM_DREG]));
134  e->flags |= (1 << NFTNL_EXPR_XFRM_DREG);
135  }
136  return 0;
137 }
138 
139 static const char *xfrmkey2str_array[] = {
140  [NFT_XFRM_KEY_DADDR_IP4] = "daddr4",
141  [NFT_XFRM_KEY_SADDR_IP4] = "saddr4",
142  [NFT_XFRM_KEY_DADDR_IP6] = "daddr6",
143  [NFT_XFRM_KEY_SADDR_IP6] = "saddr6",
144  [NFT_XFRM_KEY_REQID] = "reqid",
145  [NFT_XFRM_KEY_SPI] = "spi",
146 };
147 
148 static const char *xfrmkey2str(uint32_t key)
149 {
150  if (key >= sizeof(xfrmkey2str_array) / sizeof(xfrmkey2str_array[0]))
151  return "unknown";
152 
153  return xfrmkey2str_array[key];
154 }
155 
156 static const char *xfrmdir2str_array[] = {
157  [XFRM_POLICY_IN] = "in",
158  [XFRM_POLICY_OUT] = "out",
159 };
160 
161 static const char *xfrmdir2str(uint8_t dir)
162 {
163  if (dir >= sizeof(xfrmdir2str_array) / sizeof(xfrmdir2str_array[0]))
164  return "unknown";
165 
166  return xfrmdir2str_array[dir];
167 }
168 
169 static int
170 nftnl_expr_xfrm_snprintf(char *buf, size_t remain,
171  uint32_t flags, const struct nftnl_expr *e)
172 {
173  struct nftnl_expr_xfrm *x = nftnl_expr_data(e);
174  int ret, offset = 0;
175 
176  if (e->flags & (1 << NFTNL_EXPR_XFRM_DREG)) {
177  ret = snprintf(buf, remain, "load %s %u %s => reg %u ",
178  xfrmdir2str(x->dir),
179  x->spnum,
180  xfrmkey2str(x->key), x->dreg);
181  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
182  }
183  return offset;
184 }
185 
186 static struct attr_policy xfrm_attr_policy[__NFTNL_EXPR_XFRM_MAX] = {
187  [NFTNL_EXPR_XFRM_DREG] = { .maxlen = sizeof(uint32_t) },
188  [NFTNL_EXPR_XFRM_SREG] = { .maxlen = 0 },
189  [NFTNL_EXPR_XFRM_KEY] = { .maxlen = sizeof(uint32_t) },
190  [NFTNL_EXPR_XFRM_DIR] = { .maxlen = sizeof(uint8_t) },
191  [NFTNL_EXPR_XFRM_SPNUM] = { .maxlen = sizeof(uint32_t) },
192 };
193 
194 struct expr_ops expr_ops_xfrm = {
195  .name = "xfrm",
196  .alloc_len = sizeof(struct nftnl_expr_xfrm),
197  .nftnl_max_attr = __NFTNL_EXPR_XFRM_MAX - 1,
198  .attr_policy = xfrm_attr_policy,
199  .set = nftnl_expr_xfrm_set,
200  .get = nftnl_expr_xfrm_get,
201  .parse = nftnl_expr_xfrm_parse,
202  .build = nftnl_expr_xfrm_build,
203  .output = nftnl_expr_xfrm_snprintf,
204 };