• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * (C) 2012-2013 by Pablo Neira Ayuso <pablo@netfilter.org>
3  * (C) 2013 by Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
4  *
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.
9  *
10  * This code has been sponsored by Sophos Astaro <http://www.sophos.com>
11  */
12 
13 #include <stdbool.h>
14 #include <stdlib.h>
15 #include <string.h>
16 
17 #include <linux/netfilter/nf_log.h>
18 #include <linux/netfilter/xt_limit.h>
19 #include <linux/netfilter/xt_mark.h>
20 #include <linux/netfilter/xt_NFLOG.h>
21 #include <linux/netfilter/xt_pkttype.h>
22 
23 #include <linux/netfilter_ipv6/ip6t_hl.h>
24 
25 #include <libnftnl/rule.h>
26 #include <libnftnl/expr.h>
27 
28 #include <xtables.h>
29 
30 #include "nft-ruleparse.h"
31 #include "nft.h"
32 
33 static struct xtables_match *
nft_find_match_in_cs(struct iptables_command_state * cs,const char * name)34 nft_find_match_in_cs(struct iptables_command_state *cs, const char *name)
35 {
36 	struct xtables_rule_match *rm;
37 	struct ebt_match *ebm;
38 
39 	for (ebm = cs->match_list; ebm; ebm = ebm->next) {
40 		if (ebm->ismatch &&
41 		    !strcmp(ebm->u.match->m->u.user.name, name))
42 			return ebm->u.match;
43 	}
44 	for (rm = cs->matches; rm; rm = rm->next) {
45 		if (!strcmp(rm->match->m->u.user.name, name))
46 			return rm->match;
47 	}
48 	return NULL;
49 }
50 
51 void *
nft_create_match(struct nft_xt_ctx * ctx,struct iptables_command_state * cs,const char * name,bool reuse)52 nft_create_match(struct nft_xt_ctx *ctx,
53 		 struct iptables_command_state *cs,
54 		 const char *name, bool reuse)
55 {
56 	struct xtables_match *match;
57 	struct xt_entry_match *m;
58 	unsigned int size;
59 
60 	if (reuse) {
61 		match = nft_find_match_in_cs(cs, name);
62 		if (match)
63 			return match->m->data;
64 	}
65 
66 	match = xtables_find_match(name, XTF_TRY_LOAD,
67 				   &cs->matches);
68 	if (!match)
69 		return NULL;
70 
71 	size = XT_ALIGN(sizeof(struct xt_entry_match)) + match->size;
72 	m = xtables_calloc(1, size);
73 	m->u.match_size = size;
74 	m->u.user.revision = match->revision;
75 
76 	strcpy(m->u.user.name, match->name);
77 	match->m = m;
78 
79 	xs_init_match(match);
80 
81 	if (ctx->h->ops->rule_parse->match)
82 		ctx->h->ops->rule_parse->match(match, cs);
83 
84 	return match->m->data;
85 }
86 
87 static void *
__nft_create_target(struct nft_xt_ctx * ctx,const char * name,size_t tgsize)88 __nft_create_target(struct nft_xt_ctx *ctx, const char *name, size_t tgsize)
89 {
90 	struct xtables_target *target;
91 	size_t size;
92 
93 	target = xtables_find_target(name, XTF_TRY_LOAD);
94 	if (!target)
95 		return NULL;
96 
97 	size = XT_ALIGN(sizeof(*target->t)) + (tgsize ?: target->size);
98 
99 	target->t = xtables_calloc(1, size);
100 	target->t->u.target_size = size;
101 	target->t->u.user.revision = target->revision;
102 	strcpy(target->t->u.user.name, name);
103 
104 	xs_init_target(target);
105 
106 	ctx->cs->jumpto = name;
107 	ctx->cs->target = target;
108 
109 	if (ctx->h->ops->rule_parse->target)
110 		ctx->h->ops->rule_parse->target(target, ctx->cs);
111 
112 	return target->t->data;
113 }
114 
115 void *
nft_create_target(struct nft_xt_ctx * ctx,const char * name)116 nft_create_target(struct nft_xt_ctx *ctx, const char *name)
117 {
118 	return __nft_create_target(ctx, name, 0);
119 }
120 
nft_parse_counter(struct nftnl_expr * e,struct xt_counters * counters)121 static void nft_parse_counter(struct nftnl_expr *e, struct xt_counters *counters)
122 {
123 	counters->pcnt = nftnl_expr_get_u64(e, NFTNL_EXPR_CTR_PACKETS);
124 	counters->bcnt = nftnl_expr_get_u64(e, NFTNL_EXPR_CTR_BYTES);
125 }
126 
nft_parse_payload(struct nft_xt_ctx * ctx,struct nftnl_expr * e)127 static void nft_parse_payload(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
128 {
129 	enum nft_registers regnum = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_DREG);
130 	struct nft_xt_ctx_reg *reg = nft_xt_ctx_get_dreg(ctx, regnum);
131 
132 	if (!reg)
133 		return;
134 
135 	reg->type = NFT_XT_REG_PAYLOAD;
136 	reg->payload.base = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_BASE);
137 	reg->payload.offset = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_OFFSET);
138 	reg->payload.len = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_LEN);
139 }
140 
nft_parse_meta_set_common(struct nft_xt_ctx * ctx,struct nft_xt_ctx_reg * sreg)141 static bool nft_parse_meta_set_common(struct nft_xt_ctx* ctx,
142 				      struct nft_xt_ctx_reg *sreg)
143 {
144 	if ((sreg->type != NFT_XT_REG_IMMEDIATE)) {
145 		ctx->errmsg = "meta sreg is not an immediate";
146 		return false;
147 	}
148 
149 	return true;
150 }
151 
nft_parse_meta_set(struct nft_xt_ctx * ctx,struct nftnl_expr * e)152 static void nft_parse_meta_set(struct nft_xt_ctx *ctx,
153 			       struct nftnl_expr *e)
154 {
155 	struct nft_xt_ctx_reg *sreg;
156 	enum nft_registers sregnum;
157 
158 	sregnum = nftnl_expr_get_u32(e, NFTNL_EXPR_META_SREG);
159 	sreg = nft_xt_ctx_get_sreg(ctx, sregnum);
160 	if (!sreg)
161 		return;
162 
163 	switch (nftnl_expr_get_u32(e, NFTNL_EXPR_META_KEY)) {
164 	case NFT_META_NFTRACE:
165 		if (!nft_parse_meta_set_common(ctx, sreg))
166 			return;
167 
168 		if (sreg->immediate.data[0] == 0) {
169 			ctx->errmsg = "meta sreg immediate is 0";
170 			return;
171 		}
172 
173 		if (!nft_create_target(ctx, "TRACE"))
174 			ctx->errmsg = "target TRACE not found";
175 		break;
176 	case NFT_META_BRI_BROUTE:
177 		if (!nft_parse_meta_set_common(ctx, sreg))
178 			return;
179 
180 		ctx->cs->jumpto = "DROP";
181 		break;
182 	case NFT_META_MARK: {
183 		struct xt_mark_tginfo2 *mt;
184 
185 		if (!nft_parse_meta_set_common(ctx, sreg))
186 			return;
187 
188 		mt = nft_create_target(ctx, "MARK");
189 		if (!mt) {
190 			ctx->errmsg = "target MARK not found";
191 			return;
192 		}
193 
194 		mt->mark = sreg->immediate.data[0];
195 		if (sreg->bitwise.set)
196 			mt->mask = sreg->bitwise.mask[0];
197 		else
198 			mt->mask = ~0u;
199 		break;
200 	}
201 	default:
202 		ctx->errmsg = "meta sreg key not supported";
203 		break;
204 	}
205 }
206 
nft_parse_meta(struct nft_xt_ctx * ctx,struct nftnl_expr * e)207 static void nft_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
208 {
209         struct nft_xt_ctx_reg *reg;
210 
211 	if (nftnl_expr_is_set(e, NFTNL_EXPR_META_SREG)) {
212 		nft_parse_meta_set(ctx, e);
213 		return;
214 	}
215 
216 	reg = nft_xt_ctx_get_dreg(ctx, nftnl_expr_get_u32(e, NFTNL_EXPR_META_DREG));
217 	if (!reg)
218 		return;
219 
220 	reg->meta_dreg.key = nftnl_expr_get_u32(e, NFTNL_EXPR_META_KEY);
221 	reg->type = NFT_XT_REG_META_DREG;
222 }
223 
nft_parse_bitwise(struct nft_xt_ctx * ctx,struct nftnl_expr * e)224 static void nft_parse_bitwise(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
225 {
226 	enum nft_registers sregnum = nftnl_expr_get_u32(e, NFTNL_EXPR_BITWISE_SREG);
227 	enum nft_registers dregnum = nftnl_expr_get_u32(e, NFTNL_EXPR_BITWISE_DREG);
228 	struct nft_xt_ctx_reg *sreg = nft_xt_ctx_get_sreg(ctx, sregnum);
229 	struct nft_xt_ctx_reg *dreg = sreg;
230 	const void *data;
231 	uint32_t len;
232 
233 	if (!sreg)
234 		return;
235 
236 	if (sregnum != dregnum) {
237 		dreg = nft_xt_ctx_get_sreg(ctx, dregnum); /* sreg, do NOT clear ... */
238 		if (!dreg)
239 			return;
240 
241 		*dreg = *sreg;  /* .. and copy content instead */
242 	}
243 
244 	data = nftnl_expr_get(e, NFTNL_EXPR_BITWISE_XOR, &len);
245 
246 	if (len > sizeof(dreg->bitwise.xor)) {
247 		ctx->errmsg = "bitwise xor too large";
248 		return;
249 	}
250 
251 	memcpy(dreg->bitwise.xor, data, len);
252 
253 	data = nftnl_expr_get(e, NFTNL_EXPR_BITWISE_MASK, &len);
254 
255 	if (len > sizeof(dreg->bitwise.mask)) {
256 		ctx->errmsg = "bitwise mask too large";
257 		return;
258 	}
259 
260 	memcpy(dreg->bitwise.mask, data, len);
261 
262 	dreg->bitwise.set = true;
263 }
264 
nft_parse_icmp(struct nft_xt_ctx * ctx,struct iptables_command_state * cs,struct nft_xt_ctx_reg * sreg,uint8_t op,const char * data,size_t dlen)265 static void nft_parse_icmp(struct nft_xt_ctx *ctx,
266 			   struct iptables_command_state *cs,
267 			   struct nft_xt_ctx_reg *sreg,
268 			   uint8_t op, const char *data, size_t dlen)
269 {
270 	struct ipt_icmp icmp = {
271 		.type = UINT8_MAX,
272 		.code = { 0, UINT8_MAX },
273 	}, *icmpp;
274 
275 	if (dlen < 1)
276 		goto out_err_len;
277 
278 	switch (sreg->payload.offset) {
279 	case 0:
280 		icmp.type = data[0];
281 		if (dlen == 1)
282 			break;
283 		dlen--;
284 		data++;
285 		/* fall through */
286 	case 1:
287 		if (dlen > 1)
288 			goto out_err_len;
289 		icmp.code[0] = icmp.code[1] = data[0];
290 		break;
291 	default:
292 		ctx->errmsg = "unexpected payload offset";
293 		return;
294 	}
295 
296 	switch (ctx->h->family) {
297 	case NFPROTO_IPV4:
298 		icmpp = nft_create_match(ctx, cs, "icmp", false);
299 		break;
300 	case NFPROTO_IPV6:
301 		if (icmp.type == UINT8_MAX) {
302 			ctx->errmsg = "icmp6 code with any type match not supported";
303 			return;
304 		}
305 		icmpp = nft_create_match(ctx, cs, "icmp6", false);
306 		break;
307 	default:
308 		ctx->errmsg = "unexpected family for icmp match";
309 		return;
310 	}
311 
312 	if (!icmpp) {
313 		ctx->errmsg = "icmp match extension not found";
314 		return;
315 	}
316 	memcpy(icmpp, &icmp, sizeof(icmp));
317 	return;
318 
319 out_err_len:
320 	ctx->errmsg = "unexpected RHS data length";
321 }
322 
port_match_single_to_range(__u16 * ports,__u8 * invflags,uint8_t op,int port,__u8 invflag)323 static void port_match_single_to_range(__u16 *ports, __u8 *invflags,
324 				       uint8_t op, int port, __u8 invflag)
325 {
326 	if (port < 0)
327 		return;
328 
329 	switch (op) {
330 	case NFT_CMP_NEQ:
331 		*invflags |= invflag;
332 		/* fallthrough */
333 	case NFT_CMP_EQ:
334 		ports[0] = port;
335 		ports[1] = port;
336 		break;
337 	case NFT_CMP_LT:
338 		ports[1] = max(port - 1, 1);
339 		break;
340 	case NFT_CMP_LTE:
341 		ports[1] = port;
342 		break;
343 	case NFT_CMP_GT:
344 		ports[0] = min(port + 1, UINT16_MAX);
345 		break;
346 	case NFT_CMP_GTE:
347 		ports[0] = port;
348 		break;
349 	}
350 }
351 
nft_parse_udp(struct nft_xt_ctx * ctx,struct iptables_command_state * cs,int sport,int dport,uint8_t op)352 static void nft_parse_udp(struct nft_xt_ctx *ctx,
353 			  struct iptables_command_state *cs,
354 			  int sport, int dport,
355 			  uint8_t op)
356 {
357 	struct xt_udp *udp = nft_create_match(ctx, cs, "udp", true);
358 
359 	if (!udp) {
360 		ctx->errmsg = "udp match extension not found";
361 		return;
362 	}
363 
364 	port_match_single_to_range(udp->spts, &udp->invflags,
365 				   op, sport, XT_UDP_INV_SRCPT);
366 	port_match_single_to_range(udp->dpts, &udp->invflags,
367 				   op, dport, XT_UDP_INV_DSTPT);
368 }
369 
nft_parse_tcp(struct nft_xt_ctx * ctx,struct iptables_command_state * cs,int sport,int dport,uint8_t op)370 static void nft_parse_tcp(struct nft_xt_ctx *ctx,
371 			  struct iptables_command_state *cs,
372 			  int sport, int dport,
373 			  uint8_t op)
374 {
375 	struct xt_tcp *tcp = nft_create_match(ctx, cs, "tcp", true);
376 
377 	if (!tcp) {
378 		ctx->errmsg = "tcp match extension not found";
379 		return;
380 	}
381 
382 	port_match_single_to_range(tcp->spts, &tcp->invflags,
383 				   op, sport, XT_TCP_INV_SRCPT);
384 	port_match_single_to_range(tcp->dpts, &tcp->invflags,
385 				   op, dport, XT_TCP_INV_DSTPT);
386 }
387 
nft_parse_th_port(struct nft_xt_ctx * ctx,struct iptables_command_state * cs,uint8_t proto,int sport,int dport,uint8_t op)388 static void nft_parse_th_port(struct nft_xt_ctx *ctx,
389 			      struct iptables_command_state *cs,
390 			      uint8_t proto,
391 			      int sport, int dport, uint8_t op)
392 {
393 	switch (proto) {
394 	case IPPROTO_UDP:
395 		nft_parse_udp(ctx, cs, sport, dport, op);
396 		break;
397 	case IPPROTO_TCP:
398 		nft_parse_tcp(ctx, cs, sport, dport, op);
399 		break;
400 	default:
401 		ctx->errmsg = "unknown layer 4 protocol for TH match";
402 	}
403 }
404 
nft_parse_tcp_flags(struct nft_xt_ctx * ctx,struct iptables_command_state * cs,uint8_t op,uint8_t flags,uint8_t mask)405 static void nft_parse_tcp_flags(struct nft_xt_ctx *ctx,
406 				struct iptables_command_state *cs,
407 				uint8_t op, uint8_t flags, uint8_t mask)
408 {
409 	struct xt_tcp *tcp = nft_create_match(ctx, cs, "tcp", true);
410 
411 	if (!tcp) {
412 		ctx->errmsg = "tcp match extension not found";
413 		return;
414 	}
415 
416 	if (op == NFT_CMP_NEQ)
417 		tcp->invflags |= XT_TCP_INV_FLAGS;
418 	tcp->flg_cmp = flags;
419 	tcp->flg_mask = mask;
420 }
421 
nft_parse_transport(struct nft_xt_ctx * ctx,struct nftnl_expr * e,struct iptables_command_state * cs)422 static void nft_parse_transport(struct nft_xt_ctx *ctx,
423 				struct nftnl_expr *e,
424 				struct iptables_command_state *cs)
425 {
426 	struct nft_xt_ctx_reg *sreg;
427 	enum nft_registers reg;
428 	uint32_t sdport;
429 	uint16_t port;
430 	uint8_t proto, op;
431 	unsigned int len;
432 
433 	switch (ctx->h->family) {
434 	case NFPROTO_IPV4:
435 		proto = ctx->cs->fw.ip.proto;
436 		break;
437 	case NFPROTO_IPV6:
438 		proto = ctx->cs->fw6.ipv6.proto;
439 		break;
440 	default:
441 		ctx->errmsg = "invalid family for TH match";
442 		return;
443 	}
444 
445 	nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &len);
446 	op = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP);
447 
448 	reg = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_SREG);
449 	sreg = nft_xt_ctx_get_sreg(ctx, reg);
450 	if (!sreg)
451 		return;
452 
453 	if (sreg->type != NFT_XT_REG_PAYLOAD) {
454 		ctx->errmsg = "sgreg not payload";
455 		return;
456 	}
457 
458 	switch (proto) {
459 	case IPPROTO_UDP:
460 	case IPPROTO_TCP:
461 		break;
462 	case IPPROTO_ICMP:
463 	case IPPROTO_ICMPV6:
464 		nft_parse_icmp(ctx, cs, sreg, op,
465 			       nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &len),
466 			       len);
467 		return;
468 	default:
469 		ctx->errmsg = "unsupported layer 4 protocol value";
470 		return;
471 	}
472 
473 	switch(sreg->payload.offset) {
474 	case 0: /* th->sport */
475 		switch (len) {
476 		case 2: /* load sport only */
477 			port = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_CMP_DATA));
478 			nft_parse_th_port(ctx, cs, proto, port, -1, op);
479 			return;
480 		case 4: /* load both src and dst port */
481 			sdport = ntohl(nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_DATA));
482 			nft_parse_th_port(ctx, cs, proto, sdport >> 16, sdport & 0xffff, op);
483 			return;
484 		}
485 		break;
486 	case 2: /* th->dport */
487 		switch (len) {
488 		case 2:
489 			port = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_CMP_DATA));
490 			nft_parse_th_port(ctx, cs, proto, -1, port, op);
491 			return;
492 		}
493 		break;
494 	case 13: /* th->flags */
495 		if (len == 1 && proto == IPPROTO_TCP) {
496 			uint8_t flags = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA);
497 			uint8_t mask = ~0;
498 
499 			if (sreg->bitwise.set)
500 				memcpy(&mask, &sreg->bitwise.mask, sizeof(mask));
501 
502 			nft_parse_tcp_flags(ctx, cs, op, flags, mask);
503 		}
504 		return;
505 	}
506 }
507 
nft_parse_cmp(struct nft_xt_ctx * ctx,struct nftnl_expr * e)508 static void nft_parse_cmp(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
509 {
510 	struct nft_xt_ctx_reg *sreg;
511 	uint32_t reg;
512 
513 	reg = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_SREG);
514 
515 	sreg = nft_xt_ctx_get_sreg(ctx, reg);
516 	if (!sreg)
517 		return;
518 
519 	switch (sreg->type) {
520 	case NFT_XT_REG_UNDEF:
521 		ctx->errmsg = "cmp sreg undef";
522 		break;
523 	case NFT_XT_REG_META_DREG:
524 		ctx->h->ops->rule_parse->meta(ctx, sreg, e, ctx->cs);
525 		break;
526 	case NFT_XT_REG_PAYLOAD:
527 		switch (sreg->payload.base) {
528 		case NFT_PAYLOAD_LL_HEADER:
529 			if (ctx->h->family == NFPROTO_BRIDGE)
530 				ctx->h->ops->rule_parse->payload(ctx, sreg, e, ctx->cs);
531 			break;
532 		case NFT_PAYLOAD_NETWORK_HEADER:
533 			ctx->h->ops->rule_parse->payload(ctx, sreg, e, ctx->cs);
534 			break;
535 		case NFT_PAYLOAD_TRANSPORT_HEADER:
536 			nft_parse_transport(ctx, e, ctx->cs);
537 			break;
538 		}
539 
540 		break;
541 	default:
542 		ctx->errmsg = "cmp sreg has unknown type";
543 		break;
544 	}
545 }
546 
nft_parse_immediate(struct nft_xt_ctx * ctx,struct nftnl_expr * e)547 static void nft_parse_immediate(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
548 {
549 	const char *chain = nftnl_expr_get_str(e, NFTNL_EXPR_IMM_CHAIN);
550 	struct iptables_command_state *cs = ctx->cs;
551 	int verdict;
552 
553 	if (nftnl_expr_is_set(e, NFTNL_EXPR_IMM_DATA)) {
554 		struct nft_xt_ctx_reg *dreg;
555 		const void *imm_data;
556 		uint32_t len;
557 
558 		imm_data = nftnl_expr_get(e, NFTNL_EXPR_IMM_DATA, &len);
559 		dreg = nft_xt_ctx_get_dreg(ctx, nftnl_expr_get_u32(e, NFTNL_EXPR_IMM_DREG));
560 		if (!dreg)
561 			return;
562 
563 		if (len > sizeof(dreg->immediate.data)) {
564 			ctx->errmsg = "oversized immediate data";
565 			return;
566 		}
567 
568 		memcpy(dreg->immediate.data, imm_data, len);
569 		dreg->immediate.len = len;
570 		dreg->type = NFT_XT_REG_IMMEDIATE;
571 
572 		return;
573 	}
574 
575 	verdict = nftnl_expr_get_u32(e, NFTNL_EXPR_IMM_VERDICT);
576 	/* Standard target? */
577 	switch(verdict) {
578 	case NF_ACCEPT:
579 		if (cs->jumpto && strcmp(ctx->table, "broute") == 0)
580 			break;
581 		cs->jumpto = "ACCEPT";
582 		break;
583 	case NF_DROP:
584 		cs->jumpto = "DROP";
585 		break;
586 	case NFT_RETURN:
587 		cs->jumpto = "RETURN";
588 		break;;
589 	case NFT_GOTO:
590 		if (ctx->h->ops->set_goto_flag)
591 			ctx->h->ops->set_goto_flag(cs);
592 		/* fall through */
593 	case NFT_JUMP:
594 		cs->jumpto = chain;
595 		/* fall through */
596 	default:
597 		return;
598 	}
599 
600 	if (!nft_create_target(ctx, cs->jumpto))
601 		ctx->errmsg = "verdict extension not found";
602 }
603 
nft_parse_match(struct nft_xt_ctx * ctx,struct nftnl_expr * e)604 static void nft_parse_match(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
605 {
606 	uint32_t mt_len;
607 	const char *mt_name = nftnl_expr_get_str(e, NFTNL_EXPR_MT_NAME);
608 	const void *mt_info = nftnl_expr_get(e, NFTNL_EXPR_MT_INFO, &mt_len);
609 	struct xtables_match *match;
610 	struct xtables_rule_match **matches;
611 	struct xt_entry_match *m;
612 
613 	switch (ctx->h->family) {
614 	case NFPROTO_IPV4:
615 	case NFPROTO_IPV6:
616 	case NFPROTO_BRIDGE:
617 		matches = &ctx->cs->matches;
618 		break;
619 	default:
620 		fprintf(stderr, "BUG: nft_parse_match() unknown family %d\n",
621 			ctx->h->family);
622 		exit(EXIT_FAILURE);
623 	}
624 
625 	match = xtables_find_match(mt_name, XTF_TRY_LOAD, matches);
626 	if (match == NULL) {
627 		ctx->errmsg = "match extension not found";
628 		return;
629 	}
630 
631 	m = xtables_calloc(1, sizeof(struct xt_entry_match) + mt_len);
632 	memcpy(&m->data, mt_info, mt_len);
633 	m->u.match_size = mt_len + XT_ALIGN(sizeof(struct xt_entry_match));
634 	m->u.user.revision = nftnl_expr_get_u32(e, NFTNL_EXPR_TG_REV);
635 	strcpy(m->u.user.name, match->name);
636 
637 	match->m = m;
638 
639 	if (ctx->h->ops->rule_parse->match != NULL)
640 		ctx->h->ops->rule_parse->match(match, ctx->cs);
641 }
642 
nft_parse_target(struct nft_xt_ctx * ctx,struct nftnl_expr * e)643 static void nft_parse_target(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
644 {
645 	uint32_t tg_len;
646 	const char *targname = nftnl_expr_get_str(e, NFTNL_EXPR_TG_NAME);
647 	const void *targinfo = nftnl_expr_get(e, NFTNL_EXPR_TG_INFO, &tg_len);
648 	void *data;
649 
650 	data = __nft_create_target(ctx, targname, tg_len);
651 	if (!data)
652 		ctx->errmsg = "target extension not found";
653 	else
654 		memcpy(data, targinfo, tg_len);
655 }
656 
nft_parse_limit(struct nft_xt_ctx * ctx,struct nftnl_expr * e)657 static void nft_parse_limit(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
658 {
659 	__u32 burst = nftnl_expr_get_u32(e, NFTNL_EXPR_LIMIT_BURST);
660 	__u64 unit = nftnl_expr_get_u64(e, NFTNL_EXPR_LIMIT_UNIT);
661 	__u64 rate = nftnl_expr_get_u64(e, NFTNL_EXPR_LIMIT_RATE);
662 	struct xt_rateinfo *rinfo;
663 
664 	switch (ctx->h->family) {
665 	case NFPROTO_IPV4:
666 	case NFPROTO_IPV6:
667 	case NFPROTO_BRIDGE:
668 		break;
669 	default:
670 		fprintf(stderr, "BUG: nft_parse_limit() unknown family %d\n",
671 			ctx->h->family);
672 		exit(EXIT_FAILURE);
673 	}
674 
675 	rinfo = nft_create_match(ctx, ctx->cs, "limit", false);
676 	if (!rinfo) {
677 		ctx->errmsg = "limit match extension not found";
678 		return;
679 	}
680 
681 	rinfo->avg = XT_LIMIT_SCALE * unit / rate;
682 	rinfo->burst = burst;
683 }
684 
nft_parse_lookup(struct nft_xt_ctx * ctx,struct nft_handle * h,struct nftnl_expr * e)685 static void nft_parse_lookup(struct nft_xt_ctx *ctx, struct nft_handle *h,
686 			     struct nftnl_expr *e)
687 {
688 	if (ctx->h->ops->rule_parse->lookup)
689 		ctx->h->ops->rule_parse->lookup(ctx, e);
690 }
691 
nft_parse_log(struct nft_xt_ctx * ctx,struct nftnl_expr * e)692 static void nft_parse_log(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
693 {
694 	/*
695 	 * In order to handle the longer log-prefix supported by nft, instead of
696 	 * using struct xt_nflog_info, we use a struct with a compatible layout, but
697 	 * a larger buffer for the prefix.
698 	 */
699 	struct xt_nflog_info_nft {
700 		__u32 len;
701 		__u16 group;
702 		__u16 threshold;
703 		__u16 flags;
704 		__u16 pad;
705 		char  prefix[NF_LOG_PREFIXLEN];
706 	} info = {
707 		.group     = nftnl_expr_get_u16(e, NFTNL_EXPR_LOG_GROUP),
708 		.threshold = nftnl_expr_get_u16(e, NFTNL_EXPR_LOG_QTHRESHOLD),
709 	};
710 	void *data;
711 
712 	if (nftnl_expr_is_set(e, NFTNL_EXPR_LOG_SNAPLEN)) {
713 		info.len = nftnl_expr_get_u32(e, NFTNL_EXPR_LOG_SNAPLEN);
714 		info.flags = XT_NFLOG_F_COPY_LEN;
715 	}
716 	if (nftnl_expr_is_set(e, NFTNL_EXPR_LOG_PREFIX))
717 		snprintf(info.prefix, sizeof(info.prefix), "%s",
718 			 nftnl_expr_get_str(e, NFTNL_EXPR_LOG_PREFIX));
719 
720 	data = __nft_create_target(ctx, "NFLOG",
721 				   XT_ALIGN(sizeof(struct xt_nflog_info_nft)));
722 	if (!data)
723 		ctx->errmsg = "NFLOG target extension not found";
724 	else
725 		memcpy(data, &info, sizeof(info));
726 }
727 
nft_parse_udp_range(struct nft_xt_ctx * ctx,struct iptables_command_state * cs,int sport_from,int sport_to,int dport_from,int dport_to,uint8_t op)728 static void nft_parse_udp_range(struct nft_xt_ctx *ctx,
729 			        struct iptables_command_state *cs,
730 			        int sport_from, int sport_to,
731 			        int dport_from, int dport_to,
732 				uint8_t op)
733 {
734 	struct xt_udp *udp = nft_create_match(ctx, cs, "udp", true);
735 
736 	if (!udp) {
737 		ctx->errmsg = "udp match extension not found";
738 		return;
739 	}
740 
741 	if (sport_from >= 0) {
742 		switch (op) {
743 		case NFT_RANGE_NEQ:
744 			udp->invflags |= XT_UDP_INV_SRCPT;
745 			/* fallthrough */
746 		case NFT_RANGE_EQ:
747 			udp->spts[0] = sport_from;
748 			udp->spts[1] = sport_to;
749 			break;
750 		}
751 	}
752 
753 	if (dport_to >= 0) {
754 		switch (op) {
755 		case NFT_CMP_NEQ:
756 			udp->invflags |= XT_UDP_INV_DSTPT;
757 			/* fallthrough */
758 		case NFT_CMP_EQ:
759 			udp->dpts[0] = dport_from;
760 			udp->dpts[1] = dport_to;
761 			break;
762 		}
763 	}
764 }
765 
nft_parse_tcp_range(struct nft_xt_ctx * ctx,struct iptables_command_state * cs,int sport_from,int sport_to,int dport_from,int dport_to,uint8_t op)766 static void nft_parse_tcp_range(struct nft_xt_ctx *ctx,
767 			        struct iptables_command_state *cs,
768 			        int sport_from, int sport_to,
769 			        int dport_from, int dport_to,
770 				uint8_t op)
771 {
772 	struct xt_tcp *tcp = nft_create_match(ctx, cs, "tcp", true);
773 
774 	if (!tcp) {
775 		ctx->errmsg = "tcp match extension not found";
776 		return;
777 	}
778 
779 	if (sport_from >= 0) {
780 		switch (op) {
781 		case NFT_RANGE_NEQ:
782 			tcp->invflags |= XT_TCP_INV_SRCPT;
783 			/* fallthrough */
784 		case NFT_RANGE_EQ:
785 			tcp->spts[0] = sport_from;
786 			tcp->spts[1] = sport_to;
787 			break;
788 		}
789 	}
790 
791 	if (dport_to >= 0) {
792 		switch (op) {
793 		case NFT_CMP_NEQ:
794 			tcp->invflags |= XT_TCP_INV_DSTPT;
795 			/* fallthrough */
796 		case NFT_CMP_EQ:
797 			tcp->dpts[0] = dport_from;
798 			tcp->dpts[1] = dport_to;
799 			break;
800 		}
801 	}
802 }
803 
nft_parse_th_port_range(struct nft_xt_ctx * ctx,struct iptables_command_state * cs,uint8_t proto,int sport_from,int sport_to,int dport_from,int dport_to,uint8_t op)804 static void nft_parse_th_port_range(struct nft_xt_ctx *ctx,
805 				    struct iptables_command_state *cs,
806 				    uint8_t proto,
807 				    int sport_from, int sport_to,
808 				    int dport_from, int dport_to, uint8_t op)
809 {
810 	switch (proto) {
811 	case IPPROTO_UDP:
812 		nft_parse_udp_range(ctx, cs, sport_from, sport_to, dport_from, dport_to, op);
813 		break;
814 	case IPPROTO_TCP:
815 		nft_parse_tcp_range(ctx, cs, sport_from, sport_to, dport_from, dport_to, op);
816 		break;
817 	}
818 }
819 
nft_parse_transport_range(struct nft_xt_ctx * ctx,const struct nft_xt_ctx_reg * sreg,struct nftnl_expr * e,struct iptables_command_state * cs)820 static void nft_parse_transport_range(struct nft_xt_ctx *ctx,
821 				      const struct nft_xt_ctx_reg *sreg,
822 				      struct nftnl_expr *e,
823 				      struct iptables_command_state *cs)
824 {
825 	unsigned int len_from, len_to;
826 	uint8_t proto, op;
827 	uint16_t from, to;
828 
829 	switch (ctx->h->family) {
830 	case NFPROTO_IPV4:
831 		proto = ctx->cs->fw.ip.proto;
832 		break;
833 	case NFPROTO_IPV6:
834 		proto = ctx->cs->fw6.ipv6.proto;
835 		break;
836 	default:
837 		proto = 0;
838 		break;
839 	}
840 
841 	nftnl_expr_get(e, NFTNL_EXPR_RANGE_FROM_DATA, &len_from);
842 	nftnl_expr_get(e, NFTNL_EXPR_RANGE_FROM_DATA, &len_to);
843 	if (len_to != len_from || len_to != 2)
844 		return;
845 
846 	op = nftnl_expr_get_u32(e, NFTNL_EXPR_RANGE_OP);
847 
848 	from = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_RANGE_FROM_DATA));
849 	to = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_RANGE_TO_DATA));
850 
851 	switch (sreg->payload.offset) {
852 	case 0:
853 		nft_parse_th_port_range(ctx, cs, proto, from, to, -1, -1, op);
854 		return;
855 	case 2:
856 		to = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_RANGE_TO_DATA));
857 		nft_parse_th_port_range(ctx, cs, proto, -1, -1, from, to, op);
858 		return;
859 	}
860 }
861 
nft_parse_range(struct nft_xt_ctx * ctx,struct nftnl_expr * e)862 static void nft_parse_range(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
863 {
864 	struct nft_xt_ctx_reg *sreg;
865 	uint32_t reg;
866 
867 	reg = nftnl_expr_get_u32(e, NFTNL_EXPR_RANGE_SREG);
868 	sreg = nft_xt_ctx_get_sreg(ctx, reg);
869 
870 	switch (sreg->type) {
871 	case NFT_XT_REG_UNDEF:
872 		ctx->errmsg = "range sreg undef";
873 		break;
874 	case NFT_XT_REG_PAYLOAD:
875 		switch (sreg->payload.base) {
876 		case NFT_PAYLOAD_TRANSPORT_HEADER:
877 			nft_parse_transport_range(ctx, sreg, e, ctx->cs);
878 			break;
879 		default:
880 			ctx->errmsg = "range with unknown payload base";
881 			break;
882 		}
883 		break;
884 	default:
885 		ctx->errmsg = "range sreg type unsupported";
886 		break;
887 	}
888 }
889 
nft_rule_to_iptables_command_state(struct nft_handle * h,const struct nftnl_rule * r,struct iptables_command_state * cs)890 bool nft_rule_to_iptables_command_state(struct nft_handle *h,
891 					const struct nftnl_rule *r,
892 					struct iptables_command_state *cs)
893 {
894 	struct nftnl_expr *expr;
895 	struct nft_xt_ctx ctx = {
896 		.cs = cs,
897 		.h = h,
898 		.table = nftnl_rule_get_str(r, NFTNL_RULE_TABLE),
899 	};
900 	bool ret = true;
901 
902 	ctx.iter = nftnl_expr_iter_create(r);
903 	if (ctx.iter == NULL)
904 		return false;
905 
906 	expr = nftnl_expr_iter_next(ctx.iter);
907 	while (expr != NULL) {
908 		const char *name =
909 			nftnl_expr_get_str(expr, NFTNL_EXPR_NAME);
910 
911 		if (strcmp(name, "counter") == 0)
912 			nft_parse_counter(expr, &ctx.cs->counters);
913 		else if (strcmp(name, "payload") == 0)
914 			nft_parse_payload(&ctx, expr);
915 		else if (strcmp(name, "meta") == 0)
916 			nft_parse_meta(&ctx, expr);
917 		else if (strcmp(name, "bitwise") == 0)
918 			nft_parse_bitwise(&ctx, expr);
919 		else if (strcmp(name, "cmp") == 0)
920 			nft_parse_cmp(&ctx, expr);
921 		else if (strcmp(name, "immediate") == 0)
922 			nft_parse_immediate(&ctx, expr);
923 		else if (strcmp(name, "match") == 0)
924 			nft_parse_match(&ctx, expr);
925 		else if (strcmp(name, "target") == 0)
926 			nft_parse_target(&ctx, expr);
927 		else if (strcmp(name, "limit") == 0)
928 			nft_parse_limit(&ctx, expr);
929 		else if (strcmp(name, "lookup") == 0)
930 			nft_parse_lookup(&ctx, h, expr);
931 		else if (strcmp(name, "log") == 0)
932 			nft_parse_log(&ctx, expr);
933 		else if (strcmp(name, "range") == 0)
934 			nft_parse_range(&ctx, expr);
935 
936 		if (ctx.errmsg) {
937 			fprintf(stderr, "Error: %s\n", ctx.errmsg);
938 			ctx.errmsg = NULL;
939 			ret = false;
940 		}
941 
942 		expr = nftnl_expr_iter_next(ctx.iter);
943 	}
944 
945 	nftnl_expr_iter_destroy(ctx.iter);
946 
947 	if (nftnl_rule_is_set(r, NFTNL_RULE_USERDATA)) {
948 		const void *data;
949 		uint32_t len, size;
950 		const char *comment;
951 
952 		data = nftnl_rule_get_data(r, NFTNL_RULE_USERDATA, &len);
953 		comment = get_comment(data, len);
954 		if (comment) {
955 			struct xtables_match *match;
956 			struct xt_entry_match *m;
957 
958 			match = xtables_find_match("comment", XTF_TRY_LOAD,
959 						   &cs->matches);
960 			if (match == NULL)
961 				return false;
962 
963 			size = XT_ALIGN(sizeof(struct xt_entry_match))
964 				+ match->size;
965 			m = xtables_calloc(1, size);
966 
967 			strncpy((char *)m->data, comment, match->size - 1);
968 			m->u.match_size = size;
969 			m->u.user.revision = 0;
970 			strcpy(m->u.user.name, match->name);
971 
972 			match->m = m;
973 		}
974 	}
975 
976 	if (!cs->jumpto)
977 		cs->jumpto = "";
978 
979 	if (!ret)
980 		xtables_error(VERSION_PROBLEM, "Parsing nftables rule failed");
981 	return ret;
982 }
983 
parse_ifname(const char * name,unsigned int len,char * dst)984 static void parse_ifname(const char *name, unsigned int len, char *dst)
985 {
986 	if (len == 0)
987 		return;
988 
989 	memcpy(dst, name, len);
990 	if (name[len - 1] == '\0')
991 		return;
992 
993 	if (len >= IFNAMSIZ)
994 		return;
995 
996 	/* wildcard */
997 	dst[len++] = '+';
998 	if (len >= IFNAMSIZ)
999 		return;
1000 	dst[len++] = 0;
1001 }
1002 
parse_invalid_iface(char * iface,uint8_t * invflags,uint8_t invbit)1003 static void parse_invalid_iface(char *iface, uint8_t *invflags, uint8_t invbit)
1004 {
1005 	if (*invflags & invbit || strcmp(iface, "INVAL/D"))
1006 		return;
1007 
1008 	/* nft's poor "! -o +" excuse */
1009 	*invflags |= invbit;
1010 	iface[0] = '+';
1011 	iface[1] = '\0';
1012 }
1013 
get_meta_mask(struct nft_xt_ctx * ctx,enum nft_registers sreg)1014 static uint32_t get_meta_mask(struct nft_xt_ctx *ctx, enum nft_registers sreg)
1015 {
1016 	struct nft_xt_ctx_reg *reg = nft_xt_ctx_get_sreg(ctx, sreg);
1017 
1018 	if (reg->bitwise.set)
1019 		return reg->bitwise.mask[0];
1020 
1021 	return ~0u;
1022 }
1023 
parse_meta_mark(struct nft_xt_ctx * ctx,struct nftnl_expr * e)1024 static int parse_meta_mark(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
1025 {
1026 	struct xt_mark_mtinfo1 *mark;
1027 	uint32_t value;
1028 
1029 	mark = nft_create_match(ctx, ctx->cs, "mark", false);
1030 	if (!mark)
1031 		return -1;
1032 
1033 	if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ)
1034 		mark->invert = 1;
1035 
1036 	value = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_DATA);
1037 	mark->mark = value;
1038 	mark->mask = get_meta_mask(ctx, nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_SREG));
1039 
1040 	return 0;
1041 }
1042 
parse_meta_pkttype(struct nft_xt_ctx * ctx,struct nftnl_expr * e)1043 static int parse_meta_pkttype(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
1044 {
1045 	struct xt_pkttype_info *pkttype;
1046 	uint8_t value;
1047 
1048 	pkttype = nft_create_match(ctx, ctx->cs, "pkttype", false);
1049 	if (!pkttype)
1050 		return -1;
1051 
1052 	if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ)
1053 		pkttype->invert = 1;
1054 
1055 	value = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA);
1056 	pkttype->pkttype = value;
1057 
1058 	return 0;
1059 }
1060 
parse_meta(struct nft_xt_ctx * ctx,struct nftnl_expr * e,uint8_t key,char * iniface,char * outiface,uint8_t * invflags)1061 int parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e, uint8_t key,
1062 	       char *iniface, char *outiface, uint8_t *invflags)
1063 {
1064 	uint32_t value;
1065 	const void *ifname;
1066 	uint32_t len;
1067 
1068 	switch(key) {
1069 	case NFT_META_IIF:
1070 		value = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_DATA);
1071 		if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ)
1072 			*invflags |= IPT_INV_VIA_IN;
1073 
1074 		if_indextoname(value, iniface);
1075 		break;
1076 	case NFT_META_OIF:
1077 		value = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_DATA);
1078 		if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ)
1079 			*invflags |= IPT_INV_VIA_OUT;
1080 
1081 		if_indextoname(value, outiface);
1082 		break;
1083 	case NFT_META_BRI_IIFNAME:
1084 	case NFT_META_IIFNAME:
1085 		ifname = nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &len);
1086 		if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ)
1087 			*invflags |= IPT_INV_VIA_IN;
1088 
1089 		parse_ifname(ifname, len, iniface);
1090 		parse_invalid_iface(iniface, invflags, IPT_INV_VIA_IN);
1091 		break;
1092 	case NFT_META_BRI_OIFNAME:
1093 	case NFT_META_OIFNAME:
1094 		ifname = nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &len);
1095 		if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ)
1096 			*invflags |= IPT_INV_VIA_OUT;
1097 
1098 		parse_ifname(ifname, len, outiface);
1099 		parse_invalid_iface(outiface, invflags, IPT_INV_VIA_OUT);
1100 		break;
1101 	case NFT_META_MARK:
1102 		parse_meta_mark(ctx, e);
1103 		break;
1104 	case NFT_META_PKTTYPE:
1105 		parse_meta_pkttype(ctx, e);
1106 		break;
1107 	default:
1108 		return -1;
1109 	}
1110 
1111 	return 0;
1112 }
1113 
nft_parse_hl(struct nft_xt_ctx * ctx,struct nftnl_expr * e,struct iptables_command_state * cs)1114 int nft_parse_hl(struct nft_xt_ctx *ctx, struct nftnl_expr *e,
1115 		 struct iptables_command_state *cs)
1116 {
1117 	struct ip6t_hl_info *info;
1118 	uint8_t hl, mode;
1119 	int op;
1120 
1121 	hl = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA);
1122 	op = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP);
1123 
1124 	switch (op) {
1125 	case NFT_CMP_NEQ:
1126 		mode = IP6T_HL_NE;
1127 		break;
1128 	case NFT_CMP_EQ:
1129 		mode = IP6T_HL_EQ;
1130 		break;
1131 	case NFT_CMP_LT:
1132 		mode = IP6T_HL_LT;
1133 		break;
1134 	case NFT_CMP_GT:
1135 		mode = IP6T_HL_GT;
1136 		break;
1137 	case NFT_CMP_LTE:
1138 		mode = IP6T_HL_LT;
1139 		if (hl == 255)
1140 			return -1;
1141 		hl++;
1142 		break;
1143 	case NFT_CMP_GTE:
1144 		mode = IP6T_HL_GT;
1145 		if (hl == 0)
1146 			return -1;
1147 		hl--;
1148 		break;
1149 	default:
1150 		return -1;
1151 	}
1152 
1153 	/* ipt_ttl_info and ip6t_hl_info have same layout,
1154 	 * IPT_TTL_x and IP6T_HL_x are aliases as well, so
1155 	 * just use HL for both ipv4 and ipv6.
1156 	 */
1157 	switch (ctx->h->family) {
1158 	case NFPROTO_IPV4:
1159 		info = nft_create_match(ctx, ctx->cs, "ttl", false);
1160 		break;
1161 	case NFPROTO_IPV6:
1162 		info = nft_create_match(ctx, ctx->cs, "hl", false);
1163 		break;
1164 	default:
1165 		return -1;
1166 	}
1167 
1168 	if (!info)
1169 		return -1;
1170 
1171 	info->hop_limit = hl;
1172 	info->mode = mode;
1173 
1174 	return 0;
1175 }
1176