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
23static int
24nftnl_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
48static const void *
49nftnl_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
71static 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
96static void
97nftnl_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
111static int
112nftnl_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
139static 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
148static 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
156static const char *xfrmdir2str_array[] = {
157 [XFRM_POLICY_IN] = "in",
158 [XFRM_POLICY_OUT] = "out",
159};
160
161static 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
169static int
170nftnl_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
186static 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
194struct 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};