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