configure: Avoid addition assignment operators
[iptables-mirror.git] / iptables / nft-shared.c
blob2c29e68f551df26dc9d20043cc5199d8865bc659
1 /*
2 * (C) 2012-2013 by Pablo Neira Ayuso <pablo@netfilter.org>
3 * (C) 2013 by Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This code has been sponsored by Sophos Astaro <http://www.sophos.com>
13 #include <assert.h>
14 #include <string.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <stdbool.h>
18 #include <netdb.h>
19 #include <errno.h>
20 #include <inttypes.h>
22 #include <xtables.h>
24 #include <libmnl/libmnl.h>
25 #include <libnftnl/rule.h>
26 #include <libnftnl/expr.h>
28 #include "nft-shared.h"
29 #include "nft-bridge.h"
30 #include "xshared.h"
31 #include "nft.h"
33 extern struct nft_family_ops nft_family_ops_ipv4;
34 extern struct nft_family_ops nft_family_ops_ipv6;
35 extern struct nft_family_ops nft_family_ops_arp;
36 extern struct nft_family_ops nft_family_ops_bridge;
38 static struct nftnl_expr *xt_nftnl_expr_alloc(const char *name)
40 struct nftnl_expr *expr = nftnl_expr_alloc(name);
42 if (expr)
43 return expr;
45 xtables_error(RESOURCE_PROBLEM,
46 "Failed to allocate nftnl expression '%s'", name);
49 void add_meta(struct nft_handle *h, struct nftnl_rule *r, uint32_t key,
50 uint8_t *dreg)
52 struct nftnl_expr *expr;
53 uint8_t reg;
55 expr = xt_nftnl_expr_alloc("meta");
57 reg = NFT_REG_1;
58 nftnl_expr_set_u32(expr, NFTNL_EXPR_META_KEY, key);
59 nftnl_expr_set_u32(expr, NFTNL_EXPR_META_DREG, reg);
60 nftnl_rule_add_expr(r, expr);
62 *dreg = reg;
65 void add_payload(struct nft_handle *h, struct nftnl_rule *r,
66 int offset, int len, uint32_t base, uint8_t *dreg)
68 struct nftnl_expr *expr;
69 uint8_t reg;
71 expr = xt_nftnl_expr_alloc("payload");
73 reg = NFT_REG_1;
74 nftnl_expr_set_u32(expr, NFTNL_EXPR_PAYLOAD_BASE, base);
75 nftnl_expr_set_u32(expr, NFTNL_EXPR_PAYLOAD_DREG, reg);
76 nftnl_expr_set_u32(expr, NFTNL_EXPR_PAYLOAD_OFFSET, offset);
77 nftnl_expr_set_u32(expr, NFTNL_EXPR_PAYLOAD_LEN, len);
78 nftnl_rule_add_expr(r, expr);
80 *dreg = reg;
83 /* bitwise operation is = sreg & mask ^ xor */
84 void add_bitwise_u16(struct nft_handle *h, struct nftnl_rule *r,
85 uint16_t mask, uint16_t xor, uint8_t sreg, uint8_t *dreg)
87 struct nftnl_expr *expr;
88 uint8_t reg;
90 expr = xt_nftnl_expr_alloc("bitwise");
92 reg = NFT_REG_1;
93 nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_SREG, sreg);
94 nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_DREG, reg);
95 nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_LEN, sizeof(uint16_t));
96 nftnl_expr_set(expr, NFTNL_EXPR_BITWISE_MASK, &mask, sizeof(uint16_t));
97 nftnl_expr_set(expr, NFTNL_EXPR_BITWISE_XOR, &xor, sizeof(uint16_t));
98 nftnl_rule_add_expr(r, expr);
100 *dreg = reg;
103 void add_bitwise(struct nft_handle *h, struct nftnl_rule *r,
104 uint8_t *mask, size_t len, uint8_t sreg, uint8_t *dreg)
106 struct nftnl_expr *expr;
107 uint32_t xor[4] = { 0 };
108 uint8_t reg = *dreg;
110 expr = xt_nftnl_expr_alloc("bitwise");
112 nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_SREG, sreg);
113 nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_DREG, reg);
114 nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_LEN, len);
115 nftnl_expr_set(expr, NFTNL_EXPR_BITWISE_MASK, mask, len);
116 nftnl_expr_set(expr, NFTNL_EXPR_BITWISE_XOR, &xor, len);
117 nftnl_rule_add_expr(r, expr);
119 *dreg = reg;
122 void add_cmp_ptr(struct nftnl_rule *r, uint32_t op, void *data, size_t len,
123 uint8_t sreg)
125 struct nftnl_expr *expr;
127 expr = xt_nftnl_expr_alloc("cmp");
129 nftnl_expr_set_u32(expr, NFTNL_EXPR_CMP_SREG, sreg);
130 nftnl_expr_set_u32(expr, NFTNL_EXPR_CMP_OP, op);
131 nftnl_expr_set(expr, NFTNL_EXPR_CMP_DATA, data, len);
132 nftnl_rule_add_expr(r, expr);
135 void add_cmp_u8(struct nftnl_rule *r, uint8_t val, uint32_t op, uint8_t sreg)
137 add_cmp_ptr(r, op, &val, sizeof(val), sreg);
140 void add_cmp_u16(struct nftnl_rule *r, uint16_t val, uint32_t op, uint8_t sreg)
142 add_cmp_ptr(r, op, &val, sizeof(val), sreg);
145 void add_cmp_u32(struct nftnl_rule *r, uint32_t val, uint32_t op, uint8_t sreg)
147 add_cmp_ptr(r, op, &val, sizeof(val), sreg);
150 void add_iface(struct nft_handle *h, struct nftnl_rule *r,
151 char *iface, uint32_t key, uint32_t op)
153 int iface_len = strlen(iface);
154 uint8_t reg;
157 if (iface[iface_len - 1] == '+') {
158 if (iface_len > 1) {
159 iface_len -= 1;
160 } else if (op != NFT_CMP_EQ) {
161 op = NFT_CMP_EQ;
162 iface = "INVAL/D";
163 iface_len = strlen(iface) + 1;
164 } else {
165 return; /* -o + */
167 } else {
168 iface_len += 1;
171 add_meta(h, r, key, &reg);
172 add_cmp_ptr(r, op, iface, iface_len, reg);
175 void add_addr(struct nft_handle *h, struct nftnl_rule *r,
176 enum nft_payload_bases base, int offset,
177 void *data, void *mask, size_t len, uint32_t op)
179 const unsigned char *m = mask;
180 bool bitwise = false;
181 uint8_t reg;
182 int i, j;
184 for (i = 0; i < len; i++) {
185 if (m[i] != 0xff) {
186 bitwise = m[i] != 0;
187 break;
190 for (j = i + 1; !bitwise && j < len; j++)
191 bitwise = !!m[j];
193 if (!bitwise)
194 len = i;
196 add_payload(h, r, offset, len, base, &reg);
198 if (bitwise)
199 add_bitwise(h, r, mask, len, reg, &reg);
201 add_cmp_ptr(r, op, data, len, reg);
204 void add_proto(struct nft_handle *h, struct nftnl_rule *r,
205 int offset, size_t len, uint8_t proto, uint32_t op)
207 uint8_t reg;
209 add_payload(h, r, offset, len, NFT_PAYLOAD_NETWORK_HEADER, &reg);
210 add_cmp_u8(r, proto, op, reg);
213 void add_l4proto(struct nft_handle *h, struct nftnl_rule *r,
214 uint8_t proto, uint32_t op)
216 uint8_t reg;
218 add_meta(h, r, NFT_META_L4PROTO, &reg);
219 add_cmp_u8(r, proto, op, reg);
222 bool is_same_interfaces(const char *a_iniface, const char *a_outiface,
223 const char *b_iniface, const char *b_outiface)
225 if (strncmp(a_iniface, b_iniface, IFNAMSIZ)) {
226 DEBUGP("different iniface\n");
227 return false;
229 if (strncmp(a_outiface, b_outiface, IFNAMSIZ)) {
230 DEBUGP("different outiface\n");
231 return false;
233 return true;
236 void __get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, uint8_t *op)
238 uint32_t len;
240 memcpy(data, nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &len), dlen);
241 *op = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP);
244 void get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, bool *inv)
246 uint8_t op;
248 __get_cmp_data(e, data, dlen, &op);
249 *inv = (op == NFT_CMP_NEQ);
252 void nft_ipv46_save_chain(const struct nftnl_chain *c, const char *policy)
254 const char *chain = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
255 uint64_t pkts = nftnl_chain_get_u64(c, NFTNL_CHAIN_PACKETS);
256 uint64_t bytes = nftnl_chain_get_u64(c, NFTNL_CHAIN_BYTES);
258 printf(":%s %s [%"PRIu64":%"PRIu64"]\n",
259 chain, policy ?: "-", pkts, bytes);
262 void save_matches_and_target(const struct iptables_command_state *cs,
263 bool goto_flag, const void *fw,
264 unsigned int format)
266 struct xtables_rule_match *matchp;
268 for (matchp = cs->matches; matchp; matchp = matchp->next) {
269 if (matchp->match->alias) {
270 printf(" -m %s",
271 matchp->match->alias(matchp->match->m));
272 } else
273 printf(" -m %s", matchp->match->name);
275 if (matchp->match->save != NULL) {
276 /* cs->fw union makes the trick */
277 matchp->match->save(fw, matchp->match->m);
281 if ((format & (FMT_NOCOUNTS | FMT_C_COUNTS)) == FMT_C_COUNTS)
282 printf(" -c %llu %llu",
283 (unsigned long long)cs->counters.pcnt,
284 (unsigned long long)cs->counters.bcnt);
286 if (cs->target != NULL) {
287 if (cs->target->alias) {
288 printf(" -j %s", cs->target->alias(cs->target->t));
289 } else
290 printf(" -j %s", cs->jumpto);
292 if (cs->target->save != NULL) {
293 cs->target->save(fw, cs->target->t);
295 } else if (strlen(cs->jumpto) > 0) {
296 printf(" -%c %s", goto_flag ? 'g' : 'j', cs->jumpto);
299 printf("\n");
302 void print_matches_and_target(struct iptables_command_state *cs,
303 unsigned int format)
305 struct xtables_rule_match *matchp;
307 for (matchp = cs->matches; matchp; matchp = matchp->next) {
308 if (matchp->match->print != NULL) {
309 matchp->match->print(&cs->fw, matchp->match->m,
310 format & FMT_NUMERIC);
314 if (cs->target != NULL) {
315 if (cs->target->print != NULL) {
316 cs->target->print(&cs->fw, cs->target->t,
317 format & FMT_NUMERIC);
322 struct nft_family_ops *nft_family_ops_lookup(int family)
324 switch (family) {
325 case AF_INET:
326 return &nft_family_ops_ipv4;
327 case AF_INET6:
328 return &nft_family_ops_ipv6;
329 case NFPROTO_ARP:
330 return &nft_family_ops_arp;
331 case NFPROTO_BRIDGE:
332 return &nft_family_ops_bridge;
333 default:
334 break;
337 return NULL;
340 bool compare_matches(struct xtables_rule_match *mt1,
341 struct xtables_rule_match *mt2)
343 struct xtables_rule_match *mp1;
344 struct xtables_rule_match *mp2;
346 for (mp1 = mt1, mp2 = mt2; mp1 && mp2; mp1 = mp1->next, mp2 = mp2->next) {
347 struct xt_entry_match *m1 = mp1->match->m;
348 struct xt_entry_match *m2 = mp2->match->m;
349 size_t cmplen = mp1->match->userspacesize;
351 if (strcmp(m1->u.user.name, m2->u.user.name) != 0) {
352 DEBUGP("mismatching match name\n");
353 return false;
356 if (m1->u.user.match_size != m2->u.user.match_size) {
357 DEBUGP("mismatching match size\n");
358 return false;
361 if (!strcmp(m1->u.user.name, "among"))
362 cmplen = m1->u.match_size - sizeof(*m1);
364 if (memcmp(m1->data, m2->data, cmplen) != 0) {
365 DEBUGP("mismatch match data\n");
366 DEBUG_HEXDUMP("m1->data", m1->data, cmplen);
367 DEBUG_HEXDUMP("m2->data", m2->data, cmplen);
368 return false;
372 /* Both cursors should be NULL */
373 if (mp1 != mp2) {
374 DEBUGP("mismatch matches amount\n");
375 return false;
378 return true;
381 bool compare_targets(struct xtables_target *tg1, struct xtables_target *tg2)
383 if (tg1 == NULL && tg2 == NULL)
384 return true;
386 if (tg1 == NULL || tg2 == NULL)
387 return false;
388 if (tg1->userspacesize != tg2->userspacesize)
389 return false;
391 if (strcmp(tg1->t->u.user.name, tg2->t->u.user.name) != 0)
392 return false;
394 if (memcmp(tg1->t->data, tg2->t->data, tg1->userspacesize) != 0)
395 return false;
397 return true;
400 void nft_check_xt_legacy(int family, bool is_ipt_save)
402 static const char tables6[] = "/proc/net/ip6_tables_names";
403 static const char tables4[] = "/proc/net/ip_tables_names";
404 static const char tablesa[] = "/proc/net/arp_tables_names";
405 const char *prefix = "ip";
406 FILE *fp = NULL;
407 char buf[1024];
409 switch (family) {
410 case NFPROTO_IPV4:
411 fp = fopen(tables4, "r");
412 break;
413 case NFPROTO_IPV6:
414 fp = fopen(tables6, "r");
415 prefix = "ip6";
416 break;
417 case NFPROTO_ARP:
418 fp = fopen(tablesa, "r");
419 prefix = "arp";
420 break;
421 default:
422 break;
425 if (!fp)
426 return;
428 if (fgets(buf, sizeof(buf), fp))
429 fprintf(stderr, "# Warning: %stables-legacy tables present, use %stables-legacy%s to see them\n",
430 prefix, prefix, is_ipt_save ? "-save" : "");
431 fclose(fp);
434 enum nft_registers nft_get_next_reg(enum nft_registers reg, size_t size)
436 /* convert size to NETLINK_ALIGN-sized chunks */
437 size = (size + NETLINK_ALIGN - 1) / NETLINK_ALIGN;
439 /* map 16byte reg to 4byte one */
440 if (reg < __NFT_REG_MAX)
441 reg = NFT_REG32_00 + (reg - 1) * NFT_REG_SIZE / NFT_REG32_SIZE;
443 reg += size;
444 assert(reg <= NFT_REG32_15);
446 return reg;