1 /*
2 * (C) 2012-2013 by Pablo Neira Ayuso <[email protected]>
3 * (C) 2013 by Tomasz Bursztyka <[email protected]>
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_iter *iter;
895 struct nftnl_expr *expr;
896 struct nft_xt_ctx ctx = {
897 .cs = cs,
898 .h = h,
899 .table = nftnl_rule_get_str(r, NFTNL_RULE_TABLE),
900 };
901 bool ret = true;
902
903 iter = nftnl_expr_iter_create(r);
904 if (iter == NULL)
905 return false;
906
907 ctx.iter = iter;
908 expr = nftnl_expr_iter_next(iter);
909 while (expr != NULL) {
910 const char *name =
911 nftnl_expr_get_str(expr, NFTNL_EXPR_NAME);
912
913 if (strcmp(name, "counter") == 0)
914 nft_parse_counter(expr, &ctx.cs->counters);
915 else if (strcmp(name, "payload") == 0)
916 nft_parse_payload(&ctx, expr);
917 else if (strcmp(name, "meta") == 0)
918 nft_parse_meta(&ctx, expr);
919 else if (strcmp(name, "bitwise") == 0)
920 nft_parse_bitwise(&ctx, expr);
921 else if (strcmp(name, "cmp") == 0)
922 nft_parse_cmp(&ctx, expr);
923 else if (strcmp(name, "immediate") == 0)
924 nft_parse_immediate(&ctx, expr);
925 else if (strcmp(name, "match") == 0)
926 nft_parse_match(&ctx, expr);
927 else if (strcmp(name, "target") == 0)
928 nft_parse_target(&ctx, expr);
929 else if (strcmp(name, "limit") == 0)
930 nft_parse_limit(&ctx, expr);
931 else if (strcmp(name, "lookup") == 0)
932 nft_parse_lookup(&ctx, h, expr);
933 else if (strcmp(name, "log") == 0)
934 nft_parse_log(&ctx, expr);
935 else if (strcmp(name, "range") == 0)
936 nft_parse_range(&ctx, expr);
937
938 if (ctx.errmsg) {
939 fprintf(stderr, "Error: %s\n", ctx.errmsg);
940 ctx.errmsg = NULL;
941 ret = false;
942 }
943
944 expr = nftnl_expr_iter_next(iter);
945 }
946
947 nftnl_expr_iter_destroy(iter);
948
949 if (nftnl_rule_is_set(r, NFTNL_RULE_USERDATA)) {
950 const void *data;
951 uint32_t len, size;
952 const char *comment;
953
954 data = nftnl_rule_get_data(r, NFTNL_RULE_USERDATA, &len);
955 comment = get_comment(data, len);
956 if (comment) {
957 struct xtables_match *match;
958 struct xt_entry_match *m;
959
960 match = xtables_find_match("comment", XTF_TRY_LOAD,
961 &cs->matches);
962 if (match == NULL)
963 return false;
964
965 size = XT_ALIGN(sizeof(struct xt_entry_match))
966 + match->size;
967 m = xtables_calloc(1, size);
968
969 strncpy((char *)m->data, comment, match->size - 1);
970 m->u.match_size = size;
971 m->u.user.revision = 0;
972 strcpy(m->u.user.name, match->name);
973
974 match->m = m;
975 }
976 }
977
978 if (!cs->jumpto)
979 cs->jumpto = "";
980
981 if (!ret)
982 xtables_error(VERSION_PROBLEM, "Parsing nftables rule failed");
983 return ret;
984 }
985
parse_ifname(const char * name,unsigned int len,char * dst,unsigned char * mask)986 static void parse_ifname(const char *name, unsigned int len,
987 char *dst, unsigned char *mask)
988 {
989 if (len == 0)
990 return;
991
992 memcpy(dst, name, len);
993 if (name[len - 1] == '\0') {
994 if (mask)
995 memset(mask, 0xff, strlen(name) + 1);
996 return;
997 }
998
999 if (len >= IFNAMSIZ)
1000 return;
1001
1002 /* wildcard */
1003 dst[len++] = '+';
1004 if (len >= IFNAMSIZ)
1005 return;
1006 dst[len++] = 0;
1007 if (mask)
1008 memset(mask, 0xff, len - 2);
1009 }
1010
parse_invalid_iface(char * iface,unsigned char * mask,uint8_t * invflags,uint8_t invbit)1011 static void parse_invalid_iface(char *iface, unsigned char *mask,
1012 uint8_t *invflags, uint8_t invbit)
1013 {
1014 if (*invflags & invbit || strcmp(iface, "INVAL/D"))
1015 return;
1016
1017 /* nft's poor "! -o +" excuse */
1018 *invflags |= invbit;
1019 iface[0] = '+';
1020 iface[1] = '\0';
1021 mask[0] = 0xff;
1022 mask[1] = 0xff;
1023 memset(mask + 2, 0, IFNAMSIZ - 2);
1024 }
1025
get_meta_mask(struct nft_xt_ctx * ctx,enum nft_registers sreg)1026 static uint32_t get_meta_mask(struct nft_xt_ctx *ctx, enum nft_registers sreg)
1027 {
1028 struct nft_xt_ctx_reg *reg = nft_xt_ctx_get_sreg(ctx, sreg);
1029
1030 if (reg->bitwise.set)
1031 return reg->bitwise.mask[0];
1032
1033 return ~0u;
1034 }
1035
parse_meta_mark(struct nft_xt_ctx * ctx,struct nftnl_expr * e)1036 static int parse_meta_mark(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
1037 {
1038 struct xt_mark_mtinfo1 *mark;
1039 uint32_t value;
1040
1041 mark = nft_create_match(ctx, ctx->cs, "mark", false);
1042 if (!mark)
1043 return -1;
1044
1045 if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ)
1046 mark->invert = 1;
1047
1048 value = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_DATA);
1049 mark->mark = value;
1050 mark->mask = get_meta_mask(ctx, nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_SREG));
1051
1052 return 0;
1053 }
1054
parse_meta_pkttype(struct nft_xt_ctx * ctx,struct nftnl_expr * e)1055 static int parse_meta_pkttype(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
1056 {
1057 struct xt_pkttype_info *pkttype;
1058 uint8_t value;
1059
1060 pkttype = nft_create_match(ctx, ctx->cs, "pkttype", false);
1061 if (!pkttype)
1062 return -1;
1063
1064 if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ)
1065 pkttype->invert = 1;
1066
1067 value = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA);
1068 pkttype->pkttype = value;
1069
1070 return 0;
1071 }
1072
parse_meta(struct nft_xt_ctx * ctx,struct nftnl_expr * e,uint8_t key,char * iniface,unsigned char * iniface_mask,char * outiface,unsigned char * outiface_mask,uint8_t * invflags)1073 int parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e, uint8_t key,
1074 char *iniface, unsigned char *iniface_mask,
1075 char *outiface, unsigned char *outiface_mask, uint8_t *invflags)
1076 {
1077 uint32_t value;
1078 const void *ifname;
1079 uint32_t len;
1080
1081 switch(key) {
1082 case NFT_META_IIF:
1083 value = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_DATA);
1084 if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ)
1085 *invflags |= IPT_INV_VIA_IN;
1086
1087 if_indextoname(value, iniface);
1088
1089 memset(iniface_mask, 0xff, strlen(iniface)+1);
1090 break;
1091 case NFT_META_OIF:
1092 value = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_DATA);
1093 if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ)
1094 *invflags |= IPT_INV_VIA_OUT;
1095
1096 if_indextoname(value, outiface);
1097
1098 memset(outiface_mask, 0xff, strlen(outiface)+1);
1099 break;
1100 case NFT_META_BRI_IIFNAME:
1101 case NFT_META_IIFNAME:
1102 ifname = nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &len);
1103 if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ)
1104 *invflags |= IPT_INV_VIA_IN;
1105
1106 parse_ifname(ifname, len, iniface, iniface_mask);
1107 parse_invalid_iface(iniface, iniface_mask,
1108 invflags, IPT_INV_VIA_IN);
1109 break;
1110 case NFT_META_BRI_OIFNAME:
1111 case NFT_META_OIFNAME:
1112 ifname = nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &len);
1113 if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ)
1114 *invflags |= IPT_INV_VIA_OUT;
1115
1116 parse_ifname(ifname, len, outiface, outiface_mask);
1117 parse_invalid_iface(outiface, outiface_mask,
1118 invflags, IPT_INV_VIA_OUT);
1119 break;
1120 case NFT_META_MARK:
1121 parse_meta_mark(ctx, e);
1122 break;
1123 case NFT_META_PKTTYPE:
1124 parse_meta_pkttype(ctx, e);
1125 break;
1126 default:
1127 return -1;
1128 }
1129
1130 return 0;
1131 }
1132
nft_parse_hl(struct nft_xt_ctx * ctx,struct nftnl_expr * e,struct iptables_command_state * cs)1133 int nft_parse_hl(struct nft_xt_ctx *ctx, struct nftnl_expr *e,
1134 struct iptables_command_state *cs)
1135 {
1136 struct ip6t_hl_info *info;
1137 uint8_t hl, mode;
1138 int op;
1139
1140 hl = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA);
1141 op = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP);
1142
1143 switch (op) {
1144 case NFT_CMP_NEQ:
1145 mode = IP6T_HL_NE;
1146 break;
1147 case NFT_CMP_EQ:
1148 mode = IP6T_HL_EQ;
1149 break;
1150 case NFT_CMP_LT:
1151 mode = IP6T_HL_LT;
1152 break;
1153 case NFT_CMP_GT:
1154 mode = IP6T_HL_GT;
1155 break;
1156 case NFT_CMP_LTE:
1157 mode = IP6T_HL_LT;
1158 if (hl == 255)
1159 return -1;
1160 hl++;
1161 break;
1162 case NFT_CMP_GTE:
1163 mode = IP6T_HL_GT;
1164 if (hl == 0)
1165 return -1;
1166 hl--;
1167 break;
1168 default:
1169 return -1;
1170 }
1171
1172 /* ipt_ttl_info and ip6t_hl_info have same layout,
1173 * IPT_TTL_x and IP6T_HL_x are aliases as well, so
1174 * just use HL for both ipv4 and ipv6.
1175 */
1176 switch (ctx->h->family) {
1177 case NFPROTO_IPV4:
1178 info = nft_create_match(ctx, ctx->cs, "ttl", false);
1179 break;
1180 case NFPROTO_IPV6:
1181 info = nft_create_match(ctx, ctx->cs, "hl", false);
1182 break;
1183 default:
1184 return -1;
1185 }
1186
1187 if (!info)
1188 return -1;
1189
1190 info->hop_limit = hl;
1191 info->mode = mode;
1192
1193 return 0;
1194 }
1195