libnftnl  1.2.1
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, sizeof(socket->key));
37  break;
38  case NFTNL_EXPR_SOCKET_DREG:
39  memcpy(&socket->dreg, data, sizeof(socket->dreg));
40  break;
41  case NFTNL_EXPR_SOCKET_LEVEL:
42  memcpy(&socket->level, data, sizeof(socket->level));
43  break;
44  default:
45  return -1;
46  }
47  return 0;
48 }
49 
50 static const void *
51 nftnl_expr_socket_get(const struct nftnl_expr *e, uint16_t type,
52  uint32_t *data_len)
53 {
54  struct nftnl_expr_socket *socket = nftnl_expr_data(e);
55 
56  switch (type) {
57  case NFTNL_EXPR_SOCKET_KEY:
58  *data_len = sizeof(socket->key);
59  return &socket->key;
60  case NFTNL_EXPR_SOCKET_DREG:
61  *data_len = sizeof(socket->dreg);
62  return &socket->dreg;
63  case NFTNL_EXPR_SOCKET_LEVEL:
64  *data_len = sizeof(socket->level);
65  return &socket->level;
66  }
67  return NULL;
68 }
69 
70 static int nftnl_expr_socket_cb(const struct nlattr *attr, void *data)
71 {
72  const struct nlattr **tb = data;
73  int type = mnl_attr_get_type(attr);
74 
75  if (mnl_attr_type_valid(attr, NFTA_SOCKET_MAX) < 0)
76  return MNL_CB_OK;
77 
78  switch (type) {
79  case NFTA_SOCKET_KEY:
80  case NFTA_SOCKET_DREG:
81  case NFTA_SOCKET_LEVEL:
82  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
83  abi_breakage();
84  break;
85  }
86 
87  tb[type] = attr;
88  return MNL_CB_OK;
89 }
90 
91 static void
92 nftnl_expr_socket_build(struct nlmsghdr *nlh, const struct nftnl_expr *e)
93 {
94  struct nftnl_expr_socket *socket = nftnl_expr_data(e);
95 
96  if (e->flags & (1 << NFTNL_EXPR_SOCKET_KEY))
97  mnl_attr_put_u32(nlh, NFTA_SOCKET_KEY, htonl(socket->key));
98  if (e->flags & (1 << NFTNL_EXPR_SOCKET_DREG))
99  mnl_attr_put_u32(nlh, NFTA_SOCKET_DREG, htonl(socket->dreg));
100  if (e->flags & (1 << NFTNL_EXPR_SOCKET_LEVEL))
101  mnl_attr_put_u32(nlh, NFTA_SOCKET_LEVEL, htonl(socket->level));
102 }
103 
104 static int
105 nftnl_expr_socket_parse(struct nftnl_expr *e, struct nlattr *attr)
106 {
107  struct nftnl_expr_socket *socket = nftnl_expr_data(e);
108  struct nlattr *tb[NFTA_SOCKET_MAX+1] = {};
109 
110  if (mnl_attr_parse_nested(attr, nftnl_expr_socket_cb, tb) < 0)
111  return -1;
112 
113  if (tb[NFTA_SOCKET_KEY]) {
114  socket->key = ntohl(mnl_attr_get_u32(tb[NFTA_SOCKET_KEY]));
115  e->flags |= (1 << NFTNL_EXPR_SOCKET_KEY);
116  }
117  if (tb[NFTA_SOCKET_DREG]) {
118  socket->dreg = ntohl(mnl_attr_get_u32(tb[NFTA_SOCKET_DREG]));
119  e->flags |= (1 << NFTNL_EXPR_SOCKET_DREG);
120  }
121  if (tb[NFTA_SOCKET_LEVEL]) {
122  socket->level = ntohl(mnl_attr_get_u32(tb[NFTA_SOCKET_LEVEL]));
123  e->flags |= (1 << NFTNL_EXPR_SOCKET_LEVEL);
124  }
125 
126  return 0;
127 }
128 
129 static const char *socket_key2str_array[NFT_SOCKET_MAX + 1] = {
130  [NFT_SOCKET_TRANSPARENT] = "transparent",
131  [NFT_SOCKET_MARK] = "mark",
132  [NFT_SOCKET_WILDCARD] = "wildcard",
133  [NFT_SOCKET_CGROUPV2] = "cgroupv2",
134 };
135 
136 static const char *socket_key2str(uint8_t key)
137 {
138  if (key < NFT_SOCKET_MAX + 1)
139  return socket_key2str_array[key];
140 
141  return "unknown";
142 }
143 
144 static int
145 nftnl_expr_socket_snprintf(char *buf, size_t len,
146  uint32_t flags, const struct nftnl_expr *e)
147 {
148  struct nftnl_expr_socket *socket = nftnl_expr_data(e);
149 
150  if (e->flags & (1 << NFTNL_EXPR_SOCKET_DREG)) {
151  return snprintf(buf, len, "load %s => reg %u ",
152  socket_key2str(socket->key), socket->dreg);
153  }
154  if (e->flags & (1 << NFTNL_EXPR_SOCKET_LEVEL))
155  return snprintf(buf, len, "level %u ", socket->level);
156 
157  return 0;
158 }
159 
160 struct expr_ops expr_ops_socket = {
161  .name = "socket",
162  .alloc_len = sizeof(struct nftnl_expr_socket),
163  .max_attr = NFTA_SOCKET_MAX,
164  .set = nftnl_expr_socket_set,
165  .get = nftnl_expr_socket_get,
166  .parse = nftnl_expr_socket_parse,
167  .build = nftnl_expr_socket_build,
168  .snprintf = nftnl_expr_socket_snprintf,
169 };