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