libnftnl  1.2.9
socket.c
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3  * Copyright (c) 2018 Máté Eckl <ecklm94@gmail.com>
4  */
5 
6 #include <stdio.h>
7 #include <stdint.h>
8 #include <string.h>
9 #include <arpa/inet.h>
10 #include <errno.h>
11 #include <linux/netfilter/nf_tables.h>
12 
13 #include "internal.h"
14 #include <libmnl/libmnl.h>
15 #include <libnftnl/expr.h>
16 #include <libnftnl/rule.h>
17 
19  enum nft_socket_keys key;
20  enum nft_registers dreg;
21  uint32_t level;
22 };
23 
24 static int
25 nftnl_expr_socket_set(struct nftnl_expr *e, uint16_t type,
26  const void *data, uint32_t data_len)
27 {
28  struct nftnl_expr_socket *socket = nftnl_expr_data(e);
29 
30  switch (type) {
31  case NFTNL_EXPR_SOCKET_KEY:
32  memcpy(&socket->key, data, data_len);
33  break;
34  case NFTNL_EXPR_SOCKET_DREG:
35  memcpy(&socket->dreg, data, data_len);
36  break;
37  case NFTNL_EXPR_SOCKET_LEVEL:
38  memcpy(&socket->level, data, data_len);
39  break;
40  }
41  return 0;
42 }
43 
44 static const void *
45 nftnl_expr_socket_get(const struct nftnl_expr *e, uint16_t type,
46  uint32_t *data_len)
47 {
48  struct nftnl_expr_socket *socket = nftnl_expr_data(e);
49 
50  switch (type) {
51  case NFTNL_EXPR_SOCKET_KEY:
52  *data_len = sizeof(socket->key);
53  return &socket->key;
54  case NFTNL_EXPR_SOCKET_DREG:
55  *data_len = sizeof(socket->dreg);
56  return &socket->dreg;
57  case NFTNL_EXPR_SOCKET_LEVEL:
58  *data_len = sizeof(socket->level);
59  return &socket->level;
60  }
61  return NULL;
62 }
63 
64 static int nftnl_expr_socket_cb(const struct nlattr *attr, void *data)
65 {
66  const struct nlattr **tb = data;
67  int type = mnl_attr_get_type(attr);
68 
69  if (mnl_attr_type_valid(attr, NFTA_SOCKET_MAX) < 0)
70  return MNL_CB_OK;
71 
72  switch (type) {
73  case NFTA_SOCKET_KEY:
74  case NFTA_SOCKET_DREG:
75  case NFTA_SOCKET_LEVEL:
76  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
77  abi_breakage();
78  break;
79  }
80 
81  tb[type] = attr;
82  return MNL_CB_OK;
83 }
84 
85 static void
86 nftnl_expr_socket_build(struct nlmsghdr *nlh, const struct nftnl_expr *e)
87 {
88  struct nftnl_expr_socket *socket = nftnl_expr_data(e);
89 
90  if (e->flags & (1 << NFTNL_EXPR_SOCKET_KEY))
91  mnl_attr_put_u32(nlh, NFTA_SOCKET_KEY, htonl(socket->key));
92  if (e->flags & (1 << NFTNL_EXPR_SOCKET_DREG))
93  mnl_attr_put_u32(nlh, NFTA_SOCKET_DREG, htonl(socket->dreg));
94  if (e->flags & (1 << NFTNL_EXPR_SOCKET_LEVEL))
95  mnl_attr_put_u32(nlh, NFTA_SOCKET_LEVEL, htonl(socket->level));
96 }
97 
98 static int
99 nftnl_expr_socket_parse(struct nftnl_expr *e, struct nlattr *attr)
100 {
101  struct nftnl_expr_socket *socket = nftnl_expr_data(e);
102  struct nlattr *tb[NFTA_SOCKET_MAX+1] = {};
103 
104  if (mnl_attr_parse_nested(attr, nftnl_expr_socket_cb, tb) < 0)
105  return -1;
106 
107  if (tb[NFTA_SOCKET_KEY]) {
108  socket->key = ntohl(mnl_attr_get_u32(tb[NFTA_SOCKET_KEY]));
109  e->flags |= (1 << NFTNL_EXPR_SOCKET_KEY);
110  }
111  if (tb[NFTA_SOCKET_DREG]) {
112  socket->dreg = ntohl(mnl_attr_get_u32(tb[NFTA_SOCKET_DREG]));
113  e->flags |= (1 << NFTNL_EXPR_SOCKET_DREG);
114  }
115  if (tb[NFTA_SOCKET_LEVEL]) {
116  socket->level = ntohl(mnl_attr_get_u32(tb[NFTA_SOCKET_LEVEL]));
117  e->flags |= (1 << NFTNL_EXPR_SOCKET_LEVEL);
118  }
119 
120  return 0;
121 }
122 
123 static const char *socket_key2str_array[NFT_SOCKET_MAX + 1] = {
124  [NFT_SOCKET_TRANSPARENT] = "transparent",
125  [NFT_SOCKET_MARK] = "mark",
126  [NFT_SOCKET_WILDCARD] = "wildcard",
127  [NFT_SOCKET_CGROUPV2] = "cgroupv2",
128 };
129 
130 static const char *socket_key2str(uint8_t key)
131 {
132  if (key < NFT_SOCKET_MAX + 1)
133  return socket_key2str_array[key];
134 
135  return "unknown";
136 }
137 
138 static int
139 nftnl_expr_socket_snprintf(char *buf, size_t len,
140  uint32_t flags, const struct nftnl_expr *e)
141 {
142  struct nftnl_expr_socket *socket = nftnl_expr_data(e);
143 
144  if (e->flags & (1 << NFTNL_EXPR_SOCKET_DREG)) {
145  return snprintf(buf, len, "load %s => reg %u ",
146  socket_key2str(socket->key), socket->dreg);
147  }
148  if (e->flags & (1 << NFTNL_EXPR_SOCKET_LEVEL))
149  return snprintf(buf, len, "level %u ", socket->level);
150 
151  return 0;
152 }
153 
154 static struct attr_policy socket_attr_policy[__NFTNL_EXPR_SOCKET_MAX] = {
155  [NFTNL_EXPR_SOCKET_KEY] = { .maxlen = sizeof(uint32_t) },
156  [NFTNL_EXPR_SOCKET_DREG] = { .maxlen = sizeof(uint32_t) },
157  [NFTNL_EXPR_SOCKET_LEVEL] = { .maxlen = sizeof(uint32_t) },
158 };
159 
160 struct expr_ops expr_ops_socket = {
161  .name = "socket",
162  .alloc_len = sizeof(struct nftnl_expr_socket),
163  .nftnl_max_attr = __NFTNL_EXPR_SOCKET_MAX - 1,
164  .attr_policy = socket_attr_policy,
165  .set = nftnl_expr_socket_set,
166  .get = nftnl_expr_socket_get,
167  .parse = nftnl_expr_socket_parse,
168  .build = nftnl_expr_socket_build,
169  .output = nftnl_expr_socket_snprintf,
170 };