libnftnl  1.2.8
cmp.c
1 /*
2  * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org>
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  * This code has been sponsored by Sophos Astaro <http://www.sophos.com>
10  */
11 
12 #include "internal.h"
13 
14 #include <stdio.h>
15 #include <stdint.h>
16 #include <string.h>
17 #include <arpa/inet.h>
18 #include <errno.h>
19 
20 #include <libmnl/libmnl.h>
21 #include <linux/netfilter/nf_tables.h>
22 #include <libnftnl/expr.h>
23 #include <libnftnl/rule.h>
24 
26  union nftnl_data_reg data;
27  enum nft_registers sreg;
28  enum nft_cmp_ops op;
29 };
30 
31 static int
32 nftnl_expr_cmp_set(struct nftnl_expr *e, uint16_t type,
33  const void *data, uint32_t data_len)
34 {
35  struct nftnl_expr_cmp *cmp = nftnl_expr_data(e);
36 
37  switch(type) {
38  case NFTNL_EXPR_CMP_SREG:
39  memcpy(&cmp->sreg, data, data_len);
40  break;
41  case NFTNL_EXPR_CMP_OP:
42  memcpy(&cmp->op, data, data_len);
43  break;
44  case NFTNL_EXPR_CMP_DATA:
45  return nftnl_data_cpy(&cmp->data, data, data_len);
46  }
47  return 0;
48 }
49 
50 static const void *
51 nftnl_expr_cmp_get(const struct nftnl_expr *e, uint16_t type,
52  uint32_t *data_len)
53 {
54  struct nftnl_expr_cmp *cmp = nftnl_expr_data(e);
55 
56  switch(type) {
57  case NFTNL_EXPR_CMP_SREG:
58  *data_len = sizeof(cmp->sreg);
59  return &cmp->sreg;
60  case NFTNL_EXPR_CMP_OP:
61  *data_len = sizeof(cmp->op);
62  return &cmp->op;
63  case NFTNL_EXPR_CMP_DATA:
64  *data_len = cmp->data.len;
65  return &cmp->data.val;
66  }
67  return NULL;
68 }
69 
70 static int nftnl_expr_cmp_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_CMP_MAX) < 0)
76  return MNL_CB_OK;
77 
78  switch(type) {
79  case NFTA_CMP_SREG:
80  case NFTA_CMP_OP:
81  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
82  abi_breakage();
83  break;
84  case NFTA_CMP_DATA:
85  if (mnl_attr_validate(attr, MNL_TYPE_BINARY) < 0)
86  abi_breakage();
87  break;
88  }
89 
90  tb[type] = attr;
91  return MNL_CB_OK;
92 }
93 
94 static void
95 nftnl_expr_cmp_build(struct nlmsghdr *nlh, const struct nftnl_expr *e)
96 {
97  struct nftnl_expr_cmp *cmp = nftnl_expr_data(e);
98 
99  if (e->flags & (1 << NFTNL_EXPR_CMP_SREG))
100  mnl_attr_put_u32(nlh, NFTA_CMP_SREG, htonl(cmp->sreg));
101  if (e->flags & (1 << NFTNL_EXPR_CMP_OP))
102  mnl_attr_put_u32(nlh, NFTA_CMP_OP, htonl(cmp->op));
103  if (e->flags & (1 << NFTNL_EXPR_CMP_DATA)) {
104  struct nlattr *nest;
105 
106  nest = mnl_attr_nest_start(nlh, NFTA_CMP_DATA);
107  mnl_attr_put(nlh, NFTA_DATA_VALUE, cmp->data.len, cmp->data.val);
108  mnl_attr_nest_end(nlh, nest);
109  }
110 }
111 
112 static int
113 nftnl_expr_cmp_parse(struct nftnl_expr *e, struct nlattr *attr)
114 {
115  struct nftnl_expr_cmp *cmp = nftnl_expr_data(e);
116  struct nlattr *tb[NFTA_CMP_MAX+1] = {};
117  int ret = 0;
118 
119  if (mnl_attr_parse_nested(attr, nftnl_expr_cmp_cb, tb) < 0)
120  return -1;
121 
122  if (tb[NFTA_CMP_SREG]) {
123  cmp->sreg = ntohl(mnl_attr_get_u32(tb[NFTA_CMP_SREG]));
124  e->flags |= (1 << NFTA_CMP_SREG);
125  }
126  if (tb[NFTA_CMP_OP]) {
127  cmp->op = ntohl(mnl_attr_get_u32(tb[NFTA_CMP_OP]));
128  e->flags |= (1 << NFTA_CMP_OP);
129  }
130  if (tb[NFTA_CMP_DATA]) {
131  ret = nftnl_parse_data(&cmp->data, tb[NFTA_CMP_DATA], NULL);
132  e->flags |= (1 << NFTA_CMP_DATA);
133  }
134 
135  return ret;
136 }
137 
138 static const char *expr_cmp_str[] = {
139  [NFT_CMP_EQ] = "eq",
140  [NFT_CMP_NEQ] = "neq",
141  [NFT_CMP_LT] = "lt",
142  [NFT_CMP_LTE] = "lte",
143  [NFT_CMP_GT] = "gt",
144  [NFT_CMP_GTE] = "gte",
145 };
146 
147 static const char *cmp2str(uint32_t op)
148 {
149  if (op > NFT_CMP_GTE)
150  return "unknown";
151 
152  return expr_cmp_str[op];
153 }
154 
155 static inline int nftnl_str2cmp(const char *op)
156 {
157  if (strcmp(op, "eq") == 0)
158  return NFT_CMP_EQ;
159  else if (strcmp(op, "neq") == 0)
160  return NFT_CMP_NEQ;
161  else if (strcmp(op, "lt") == 0)
162  return NFT_CMP_LT;
163  else if (strcmp(op, "lte") == 0)
164  return NFT_CMP_LTE;
165  else if (strcmp(op, "gt") == 0)
166  return NFT_CMP_GT;
167  else if (strcmp(op, "gte") == 0)
168  return NFT_CMP_GTE;
169  else {
170  errno = EINVAL;
171  return -1;
172  }
173 }
174 
175 static int
176 nftnl_expr_cmp_snprintf(char *buf, size_t remain,
177  uint32_t flags, const struct nftnl_expr *e)
178 {
179  struct nftnl_expr_cmp *cmp = nftnl_expr_data(e);
180  int offset = 0, ret;
181 
182  ret = snprintf(buf, remain, "%s reg %u ",
183  cmp2str(cmp->op), cmp->sreg);
184  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
185 
186  ret = nftnl_data_reg_snprintf(buf + offset, remain, &cmp->data,
187  0, DATA_VALUE);
188  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
189 
190  return offset;
191 }
192 
193 static struct attr_policy cmp_attr_policy[__NFTNL_EXPR_CMP_MAX] = {
194  [NFTNL_EXPR_CMP_SREG] = { .maxlen = sizeof(uint32_t) },
195  [NFTNL_EXPR_CMP_OP] = { .maxlen = sizeof(uint32_t) },
196  [NFTNL_EXPR_CMP_DATA] = { .maxlen = NFT_DATA_VALUE_MAXLEN }
197 };
198 
199 struct expr_ops expr_ops_cmp = {
200  .name = "cmp",
201  .alloc_len = sizeof(struct nftnl_expr_cmp),
202  .nftnl_max_attr = __NFTNL_EXPR_CMP_MAX - 1,
203  .attr_policy = cmp_attr_policy,
204  .set = nftnl_expr_cmp_set,
205  .get = nftnl_expr_cmp_get,
206  .parse = nftnl_expr_cmp_parse,
207  .build = nftnl_expr_cmp_build,
208  .output = nftnl_expr_cmp_snprintf,
209 };