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>
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"
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
);
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
,
52 struct nftnl_expr
*expr
;
55 expr
= xt_nftnl_expr_alloc("meta");
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
);
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
;
71 expr
= xt_nftnl_expr_alloc("payload");
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
);
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
;
90 expr
= xt_nftnl_expr_alloc("bitwise");
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
);
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 };
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
);
122 void add_cmp_ptr(struct nftnl_rule
*r
, uint32_t op
, void *data
, size_t len
,
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
);
157 if (iface
[iface_len
- 1] == '+') {
160 } else if (op
!= NFT_CMP_EQ
) {
163 iface_len
= strlen(iface
) + 1;
171 add_meta(h
, r
, key
, ®
);
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;
184 for (i
= 0; i
< len
; i
++) {
190 for (j
= i
+ 1; !bitwise
&& j
< len
; j
++)
196 add_payload(h
, r
, offset
, len
, base
, ®
);
199 add_bitwise(h
, r
, mask
, len
, 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
)
209 add_payload(h
, r
, offset
, len
, NFT_PAYLOAD_NETWORK_HEADER
, ®
);
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
)
218 add_meta(h
, r
, NFT_META_L4PROTO
, ®
);
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");
229 if (strncmp(a_outiface
, b_outiface
, IFNAMSIZ
)) {
230 DEBUGP("different outiface\n");
236 void __get_cmp_data(struct nftnl_expr
*e
, void *data
, size_t dlen
, uint8_t *op
)
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
)
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
,
266 struct xtables_rule_match
*matchp
;
268 for (matchp
= cs
->matches
; matchp
; matchp
= matchp
->next
) {
269 if (matchp
->match
->alias
) {
271 matchp
->match
->alias(matchp
->match
->m
));
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
));
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
);
302 void print_matches_and_target(struct iptables_command_state
*cs
,
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
)
326 return &nft_family_ops_ipv4
;
328 return &nft_family_ops_ipv6
;
330 return &nft_family_ops_arp
;
332 return &nft_family_ops_bridge
;
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");
356 if (m1
->u
.user
.match_size
!= m2
->u
.user
.match_size
) {
357 DEBUGP("mismatching match size\n");
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
);
372 /* Both cursors should be NULL */
374 DEBUGP("mismatch matches amount\n");
381 bool compare_targets(struct xtables_target
*tg1
, struct xtables_target
*tg2
)
383 if (tg1
== NULL
&& tg2
== NULL
)
386 if (tg1
== NULL
|| tg2
== NULL
)
388 if (tg1
->userspacesize
!= tg2
->userspacesize
)
391 if (strcmp(tg1
->t
->u
.user
.name
, tg2
->t
->u
.user
.name
) != 0)
394 if (memcmp(tg1
->t
->data
, tg2
->t
->data
, tg1
->userspacesize
) != 0)
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";
411 fp
= fopen(tables4
, "r");
414 fp
= fopen(tables6
, "r");
418 fp
= fopen(tablesa
, "r");
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" : "");
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
;
444 assert(reg
<= NFT_REG32_15
);