1 /* 2 * (C) 2012-2013 by Pablo Neira Ayuso <pablo (at) netfilter.org> 3 * (C) 2013 by Tomasz Bursztyka <tomasz.bursztyka (at) 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 <string.h> 14 #include <stdio.h> 15 #include <stdlib.h> 16 #include <stdbool.h> 17 #include <netdb.h> 18 #include <errno.h> 19 20 #include <xtables.h> 21 22 #include <linux/netfilter/nf_tables.h> 23 24 #include <libmnl/libmnl.h> 25 #include <libnftnl/rule.h> 26 #include <libnftnl/expr.h> 27 28 #include "nft-shared.h" 29 #include "nft-bridge.h" 30 #include "xshared.h" 31 #include "nft.h" 32 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; 37 38 void add_meta(struct nftnl_rule *r, uint32_t key) 39 { 40 struct nftnl_expr *expr; 41 42 expr = nftnl_expr_alloc("meta"); 43 if (expr == NULL) 44 return; 45 46 nftnl_expr_set_u32(expr, NFTNL_EXPR_META_KEY, key); 47 nftnl_expr_set_u32(expr, NFTNL_EXPR_META_DREG, NFT_REG_1); 48 49 nftnl_rule_add_expr(r, expr); 50 } 51 52 void add_payload(struct nftnl_rule *r, int offset, int len, uint32_t base) 53 { 54 struct nftnl_expr *expr; 55 56 expr = nftnl_expr_alloc("payload"); 57 if (expr == NULL) 58 return; 59 60 nftnl_expr_set_u32(expr, NFTNL_EXPR_PAYLOAD_BASE, base); 61 nftnl_expr_set_u32(expr, NFTNL_EXPR_PAYLOAD_DREG, NFT_REG_1); 62 nftnl_expr_set_u32(expr, NFTNL_EXPR_PAYLOAD_OFFSET, offset); 63 nftnl_expr_set_u32(expr, NFTNL_EXPR_PAYLOAD_LEN, len); 64 65 nftnl_rule_add_expr(r, expr); 66 } 67 68 /* bitwise operation is = sreg & mask ^ xor */ 69 void add_bitwise_u16(struct nftnl_rule *r, int mask, int xor) 70 { 71 struct nftnl_expr *expr; 72 73 expr = nftnl_expr_alloc("bitwise"); 74 if (expr == NULL) 75 return; 76 77 nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_SREG, NFT_REG_1); 78 nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_DREG, NFT_REG_1); 79 nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_LEN, sizeof(uint16_t)); 80 nftnl_expr_set(expr, NFTNL_EXPR_BITWISE_MASK, &mask, sizeof(uint16_t)); 81 nftnl_expr_set(expr, NFTNL_EXPR_BITWISE_XOR, &xor, sizeof(uint16_t)); 82 83 nftnl_rule_add_expr(r, expr); 84 } 85 86 static void add_bitwise(struct nftnl_rule *r, uint8_t *mask, size_t len) 87 { 88 struct nftnl_expr *expr; 89 uint32_t xor[4] = { 0 }; 90 91 expr = nftnl_expr_alloc("bitwise"); 92 if (expr == NULL) 93 return; 94 95 nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_SREG, NFT_REG_1); 96 nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_DREG, NFT_REG_1); 97 nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_LEN, len); 98 nftnl_expr_set(expr, NFTNL_EXPR_BITWISE_MASK, mask, len); 99 nftnl_expr_set(expr, NFTNL_EXPR_BITWISE_XOR, &xor, len); 100 101 nftnl_rule_add_expr(r, expr); 102 } 103 104 void add_cmp_ptr(struct nftnl_rule *r, uint32_t op, void *data, size_t len) 105 { 106 struct nftnl_expr *expr; 107 108 expr = nftnl_expr_alloc("cmp"); 109 if (expr == NULL) 110 return; 111 112 nftnl_expr_set_u32(expr, NFTNL_EXPR_CMP_SREG, NFT_REG_1); 113 nftnl_expr_set_u32(expr, NFTNL_EXPR_CMP_OP, op); 114 nftnl_expr_set(expr, NFTNL_EXPR_CMP_DATA, data, len); 115 116 nftnl_rule_add_expr(r, expr); 117 } 118 119 void add_cmp_u8(struct nftnl_rule *r, uint8_t val, uint32_t op) 120 { 121 add_cmp_ptr(r, op, &val, sizeof(val)); 122 } 123 124 void add_cmp_u16(struct nftnl_rule *r, uint16_t val, uint32_t op) 125 { 126 add_cmp_ptr(r, op, &val, sizeof(val)); 127 } 128 129 void add_cmp_u32(struct nftnl_rule *r, uint32_t val, uint32_t op) 130 { 131 add_cmp_ptr(r, op, &val, sizeof(val)); 132 } 133 134 void add_iniface(struct nftnl_rule *r, char *iface, uint32_t op) 135 { 136 int iface_len; 137 138 iface_len = strlen(iface); 139 140 add_meta(r, NFT_META_IIFNAME); 141 if (iface[iface_len - 1] == '+') 142 add_cmp_ptr(r, op, iface, iface_len - 1); 143 else 144 add_cmp_ptr(r, op, iface, iface_len + 1); 145 } 146 147 void add_outiface(struct nftnl_rule *r, char *iface, uint32_t op) 148 { 149 int iface_len; 150 151 iface_len = strlen(iface); 152 153 add_meta(r, NFT_META_OIFNAME); 154 if (iface[iface_len - 1] == '+') 155 add_cmp_ptr(r, op, iface, iface_len - 1); 156 else 157 add_cmp_ptr(r, op, iface, iface_len + 1); 158 } 159 160 void add_addr(struct nftnl_rule *r, int offset, 161 void *data, void *mask, size_t len, uint32_t op) 162 { 163 add_payload(r, offset, len, NFT_PAYLOAD_NETWORK_HEADER); 164 add_bitwise(r, mask, len); 165 166 add_cmp_ptr(r, op, data, len); 167 } 168 169 void add_proto(struct nftnl_rule *r, int offset, size_t len, 170 uint8_t proto, uint32_t op) 171 { 172 add_payload(r, offset, len, NFT_PAYLOAD_NETWORK_HEADER); 173 add_cmp_u8(r, proto, op); 174 } 175 176 bool is_same_interfaces(const char *a_iniface, const char *a_outiface, 177 unsigned const char *a_iniface_mask, 178 unsigned const char *a_outiface_mask, 179 const char *b_iniface, const char *b_outiface, 180 unsigned const char *b_iniface_mask, 181 unsigned const char *b_outiface_mask) 182 { 183 int i; 184 185 for (i = 0; i < IFNAMSIZ; i++) { 186 if (a_iniface_mask[i] != b_iniface_mask[i]) { 187 DEBUGP("different iniface mask %x, %x (%d)\n", 188 a_iniface_mask[i] & 0xff, b_iniface_mask[i] & 0xff, i); 189 return false; 190 } 191 if ((a_iniface[i] & a_iniface_mask[i]) 192 != (b_iniface[i] & b_iniface_mask[i])) { 193 DEBUGP("different iniface\n"); 194 return false; 195 } 196 if (a_outiface_mask[i] != b_outiface_mask[i]) { 197 DEBUGP("different outiface mask\n"); 198 return false; 199 } 200 if ((a_outiface[i] & a_outiface_mask[i]) 201 != (b_outiface[i] & b_outiface_mask[i])) { 202 DEBUGP("different outiface\n"); 203 return false; 204 } 205 } 206 207 return true; 208 } 209 210 int parse_meta(struct nftnl_expr *e, uint8_t key, char *iniface, 211 unsigned char *iniface_mask, char *outiface, 212 unsigned char *outiface_mask, uint8_t *invflags) 213 { 214 uint32_t value; 215 const void *ifname; 216 uint32_t len; 217 218 switch(key) { 219 case NFT_META_IIF: 220 value = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_DATA); 221 if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ) 222 *invflags |= IPT_INV_VIA_IN; 223 224 if_indextoname(value, iniface); 225 226 memset(iniface_mask, 0xff, strlen(iniface)+1); 227 break; 228 case NFT_META_OIF: 229 value = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_DATA); 230 if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ) 231 *invflags |= IPT_INV_VIA_OUT; 232 233 if_indextoname(value, outiface); 234 235 memset(outiface_mask, 0xff, strlen(outiface)+1); 236 break; 237 case NFT_META_IIFNAME: 238 ifname = nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &len); 239 if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ) 240 *invflags |= IPT_INV_VIA_IN; 241 242 memcpy(iniface, ifname, len); 243 244 if (iniface[len] == '\0') 245 memset(iniface_mask, 0xff, len); 246 else { 247 iniface[len] = '+'; 248 iniface[len+1] = '\0'; 249 memset(iniface_mask, 0xff, len + 1); 250 } 251 break; 252 case NFT_META_OIFNAME: 253 ifname = nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &len); 254 if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ) 255 *invflags |= IPT_INV_VIA_OUT; 256 257 memcpy(outiface, ifname, len); 258 259 if (outiface[len] == '\0') 260 memset(outiface_mask, 0xff, len); 261 else { 262 outiface[len] = '+'; 263 outiface[len+1] = '\0'; 264 memset(outiface_mask, 0xff, len + 1); 265 } 266 break; 267 default: 268 return -1; 269 } 270 271 return 0; 272 } 273 274 static void *nft_get_data(struct nft_xt_ctx *ctx) 275 { 276 switch(ctx->family) { 277 case NFPROTO_IPV4: 278 case NFPROTO_IPV6: 279 return ctx->state.cs; 280 case NFPROTO_ARP: 281 return ctx->state.cs_arp; 282 case NFPROTO_BRIDGE: 283 return ctx->state.cs_eb; 284 default: 285 /* Should not happen */ 286 return NULL; 287 } 288 } 289 290 void nft_parse_target(struct nft_xt_ctx *ctx, struct nftnl_expr *e) 291 { 292 uint32_t tg_len; 293 const char *targname = nftnl_expr_get_str(e, NFTNL_EXPR_TG_NAME); 294 const void *targinfo = nftnl_expr_get(e, NFTNL_EXPR_TG_INFO, &tg_len); 295 struct xtables_target *target; 296 struct xt_entry_target *t; 297 size_t size; 298 struct nft_family_ops *ops; 299 void *data = nft_get_data(ctx); 300 301 target = xtables_find_target(targname, XTF_TRY_LOAD); 302 if (target == NULL) 303 return; 304 305 size = XT_ALIGN(sizeof(struct xt_entry_target)) + tg_len; 306 307 t = calloc(1, size); 308 if (t == NULL) { 309 fprintf(stderr, "OOM"); 310 exit(EXIT_FAILURE); 311 } 312 memcpy(&t->data, targinfo, tg_len); 313 t->u.target_size = size; 314 t->u.user.revision = nftnl_expr_get_u32(e, NFTNL_EXPR_TG_REV); 315 strcpy(t->u.user.name, target->name); 316 317 target->t = t; 318 319 ops = nft_family_ops_lookup(ctx->family); 320 ops->parse_target(target, data); 321 } 322 323 void nft_parse_match(struct nft_xt_ctx *ctx, struct nftnl_expr *e) 324 { 325 uint32_t mt_len; 326 const char *mt_name = nftnl_expr_get_str(e, NFTNL_EXPR_MT_NAME); 327 const void *mt_info = nftnl_expr_get(e, NFTNL_EXPR_MT_INFO, &mt_len); 328 struct xtables_match *match; 329 struct xtables_rule_match **matches; 330 struct xt_entry_match *m; 331 struct nft_family_ops *ops; 332 333 switch (ctx->family) { 334 case NFPROTO_IPV4: 335 case NFPROTO_IPV6: 336 matches = &ctx->state.cs->matches; 337 break; 338 case NFPROTO_BRIDGE: 339 matches = &ctx->state.cs_eb->matches; 340 break; 341 default: 342 fprintf(stderr, "BUG: nft_parse_match() unknown family %d\n", 343 ctx->family); 344 exit(EXIT_FAILURE); 345 } 346 347 match = xtables_find_match(mt_name, XTF_TRY_LOAD, matches); 348 if (match == NULL) 349 return; 350 351 m = calloc(1, sizeof(struct xt_entry_match) + mt_len); 352 if (m == NULL) { 353 fprintf(stderr, "OOM"); 354 exit(EXIT_FAILURE); 355 } 356 357 memcpy(&m->data, mt_info, mt_len); 358 m->u.match_size = mt_len + XT_ALIGN(sizeof(struct xt_entry_match)); 359 m->u.user.revision = nftnl_expr_get_u32(e, NFTNL_EXPR_TG_REV); 360 strcpy(m->u.user.name, match->name); 361 362 match->m = m; 363 364 ops = nft_family_ops_lookup(ctx->family); 365 if (ops->parse_match != NULL) 366 ops->parse_match(match, nft_get_data(ctx)); 367 } 368 369 void print_proto(uint16_t proto, int invert) 370 { 371 const struct protoent *pent = getprotobynumber(proto); 372 373 if (invert) 374 printf("! "); 375 376 if (pent) { 377 printf("-p %s ", pent->p_name); 378 return; 379 } 380 381 printf("-p %u ", proto); 382 } 383 384 void get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, bool *inv) 385 { 386 uint32_t len; 387 uint8_t op; 388 389 memcpy(data, nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &len), dlen); 390 op = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP); 391 if (op == NFT_CMP_NEQ) 392 *inv = true; 393 else 394 *inv = false; 395 } 396 397 void nft_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e) 398 { 399 ctx->reg = nftnl_expr_get_u32(e, NFTNL_EXPR_META_DREG); 400 ctx->meta.key = nftnl_expr_get_u32(e, NFTNL_EXPR_META_KEY); 401 ctx->flags |= NFT_XT_CTX_META; 402 } 403 404 void nft_parse_payload(struct nft_xt_ctx *ctx, struct nftnl_expr *e) 405 { 406 ctx->reg = nftnl_expr_get_u32(e, NFTNL_EXPR_META_DREG); 407 ctx->payload.offset = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_OFFSET); 408 ctx->flags |= NFT_XT_CTX_PAYLOAD; 409 } 410 411 void nft_parse_bitwise(struct nft_xt_ctx *ctx, struct nftnl_expr *e) 412 { 413 uint32_t reg, len; 414 const void *data; 415 416 reg = nftnl_expr_get_u32(e, NFTNL_EXPR_BITWISE_SREG); 417 if (ctx->reg && reg != ctx->reg) 418 return; 419 420 data = nftnl_expr_get(e, NFTNL_EXPR_BITWISE_XOR, &len); 421 memcpy(ctx->bitwise.xor, data, len); 422 data = nftnl_expr_get(e, NFTNL_EXPR_BITWISE_MASK, &len); 423 memcpy(ctx->bitwise.mask, data, len); 424 ctx->flags |= NFT_XT_CTX_BITWISE; 425 } 426 427 void nft_parse_cmp(struct nft_xt_ctx *ctx, struct nftnl_expr *e) 428 { 429 struct nft_family_ops *ops = nft_family_ops_lookup(ctx->family); 430 void *data = nft_get_data(ctx); 431 uint32_t reg; 432 433 reg = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_SREG); 434 if (ctx->reg && reg != ctx->reg) 435 return; 436 437 if (ctx->flags & NFT_XT_CTX_META) { 438 ops->parse_meta(ctx, e, data); 439 ctx->flags &= ~NFT_XT_CTX_META; 440 } 441 /* bitwise context is interpreted from payload */ 442 if (ctx->flags & NFT_XT_CTX_PAYLOAD) { 443 ops->parse_payload(ctx, e, data); 444 ctx->flags &= ~NFT_XT_CTX_PAYLOAD; 445 } 446 } 447 448 void nft_parse_counter(struct nftnl_expr *e, struct xt_counters *counters) 449 { 450 counters->pcnt = nftnl_expr_get_u64(e, NFTNL_EXPR_CTR_PACKETS); 451 counters->bcnt = nftnl_expr_get_u64(e, NFTNL_EXPR_CTR_BYTES); 452 } 453 454 void nft_parse_immediate(struct nft_xt_ctx *ctx, struct nftnl_expr *e) 455 { 456 int verdict = nftnl_expr_get_u32(e, NFTNL_EXPR_IMM_VERDICT); 457 const char *chain = nftnl_expr_get_str(e, NFTNL_EXPR_IMM_CHAIN); 458 struct nft_family_ops *ops; 459 const char *jumpto = NULL; 460 bool nft_goto = false; 461 void *data = nft_get_data(ctx); 462 463 /* Standard target? */ 464 switch(verdict) { 465 case NF_ACCEPT: 466 jumpto = "ACCEPT"; 467 break; 468 case NF_DROP: 469 jumpto = "DROP"; 470 break; 471 case NFT_RETURN: 472 jumpto = "RETURN"; 473 break;; 474 case NFT_GOTO: 475 nft_goto = true; 476 case NFT_JUMP: 477 jumpto = chain; 478 break; 479 } 480 481 ops = nft_family_ops_lookup(ctx->family); 482 ops->parse_immediate(jumpto, nft_goto, data); 483 } 484 485 void nft_rule_to_iptables_command_state(struct nftnl_rule *r, 486 struct iptables_command_state *cs) 487 { 488 struct nftnl_expr_iter *iter; 489 struct nftnl_expr *expr; 490 int family = nftnl_rule_get_u32(r, NFTNL_RULE_FAMILY); 491 struct nft_xt_ctx ctx = { 492 .state.cs = cs, 493 .family = family, 494 }; 495 496 iter = nftnl_expr_iter_create(r); 497 if (iter == NULL) 498 return; 499 500 ctx.iter = iter; 501 expr = nftnl_expr_iter_next(iter); 502 while (expr != NULL) { 503 const char *name = 504 nftnl_expr_get_str(expr, NFTNL_EXPR_NAME); 505 506 if (strcmp(name, "counter") == 0) 507 nft_parse_counter(expr, &ctx.state.cs->counters); 508 else if (strcmp(name, "payload") == 0) 509 nft_parse_payload(&ctx, expr); 510 else if (strcmp(name, "meta") == 0) 511 nft_parse_meta(&ctx, expr); 512 else if (strcmp(name, "bitwise") == 0) 513 nft_parse_bitwise(&ctx, expr); 514 else if (strcmp(name, "cmp") == 0) 515 nft_parse_cmp(&ctx, expr); 516 else if (strcmp(name, "immediate") == 0) 517 nft_parse_immediate(&ctx, expr); 518 else if (strcmp(name, "match") == 0) 519 nft_parse_match(&ctx, expr); 520 else if (strcmp(name, "target") == 0) 521 nft_parse_target(&ctx, expr); 522 523 expr = nftnl_expr_iter_next(iter); 524 } 525 526 nftnl_expr_iter_destroy(iter); 527 528 if (nftnl_rule_is_set(r, NFTNL_RULE_USERDATA)) { 529 const void *data; 530 uint32_t len; 531 struct xtables_match *match; 532 struct xt_entry_match *m; 533 534 data = nftnl_rule_get_data(r, NFTNL_RULE_USERDATA, &len); 535 match = xtables_find_match("comment", XTF_TRY_LOAD, 536 &cs->matches); 537 if (match == NULL) 538 return; 539 540 m = calloc(1, sizeof(struct xt_entry_match) + len); 541 if (m == NULL) { 542 fprintf(stderr, "OOM"); 543 exit(EXIT_FAILURE); 544 } 545 546 memcpy(&m->data, get_comment(data, len), len); 547 m->u.match_size = len + XT_ALIGN(sizeof(struct xt_entry_match)); 548 m->u.user.revision = 0; 549 strcpy(m->u.user.name, match->name); 550 551 match->m = m; 552 } 553 554 if (cs->target != NULL) 555 cs->jumpto = cs->target->name; 556 else if (cs->jumpto != NULL) 557 cs->target = xtables_find_target(cs->jumpto, XTF_TRY_LOAD); 558 else 559 cs->jumpto = ""; 560 } 561 562 void print_header(unsigned int format, const char *chain, const char *pol, 563 const struct xt_counters *counters, bool basechain, 564 uint32_t refs) 565 { 566 printf("Chain %s", chain); 567 if (basechain) { 568 printf(" (policy %s", pol); 569 if (!(format & FMT_NOCOUNTS)) { 570 fputc(' ', stdout); 571 xtables_print_num(counters->pcnt, (format|FMT_NOTABLE)); 572 fputs("packets, ", stdout); 573 xtables_print_num(counters->bcnt, (format|FMT_NOTABLE)); 574 fputs("bytes", stdout); 575 } 576 printf(")\n"); 577 } else { 578 printf(" (%u references)\n", refs); 579 } 580 581 if (format & FMT_LINENUMBERS) 582 printf(FMT("%-4s ", "%s "), "num"); 583 if (!(format & FMT_NOCOUNTS)) { 584 if (format & FMT_KILOMEGAGIGA) { 585 printf(FMT("%5s ","%s "), "pkts"); 586 printf(FMT("%5s ","%s "), "bytes"); 587 } else { 588 printf(FMT("%8s ","%s "), "pkts"); 589 printf(FMT("%10s ","%s "), "bytes"); 590 } 591 } 592 if (!(format & FMT_NOTARGET)) 593 printf(FMT("%-9s ","%s "), "target"); 594 fputs(" prot ", stdout); 595 if (format & FMT_OPTIONS) 596 fputs("opt", stdout); 597 if (format & FMT_VIA) { 598 printf(FMT(" %-6s ","%s "), "in"); 599 printf(FMT("%-6s ","%s "), "out"); 600 } 601 printf(FMT(" %-19s ","%s "), "source"); 602 printf(FMT(" %-19s "," %s "), "destination"); 603 printf("\n"); 604 } 605 606 void print_firewall_details(const struct iptables_command_state *cs, 607 const char *targname, uint8_t flags, 608 uint8_t invflags, uint8_t proto, 609 unsigned int num, unsigned int format) 610 { 611 if (format & FMT_LINENUMBERS) 612 printf(FMT("%-4u ", "%u "), num); 613 614 if (!(format & FMT_NOCOUNTS)) { 615 xtables_print_num(cs->counters.pcnt, format); 616 xtables_print_num(cs->counters.bcnt, format); 617 } 618 619 if (!(format & FMT_NOTARGET)) 620 printf(FMT("%-9s ", "%s "), targname ? targname : ""); 621 622 fputc(invflags & XT_INV_PROTO ? '!' : ' ', stdout); 623 { 624 const char *pname = 625 proto_to_name(proto, format&FMT_NUMERIC); 626 if (pname) 627 printf(FMT("%-5s", "%s "), pname); 628 else 629 printf(FMT("%-5hu", "%hu "), proto); 630 } 631 } 632 633 void print_ifaces(const char *iniface, const char *outiface, uint8_t invflags, 634 unsigned int format) 635 { 636 char iface[IFNAMSIZ+2]; 637 638 if (!(format & FMT_VIA)) 639 return; 640 641 if (invflags & IPT_INV_VIA_IN) { 642 iface[0] = '!'; 643 iface[1] = '\0'; 644 } else 645 iface[0] = '\0'; 646 647 if (iniface[0] != '\0') 648 strcat(iface, iniface); 649 else if (format & FMT_NUMERIC) 650 strcat(iface, "*"); 651 else 652 strcat(iface, "any"); 653 654 printf(FMT(" %-6s ","in %s "), iface); 655 656 if (invflags & IPT_INV_VIA_OUT) { 657 iface[0] = '!'; 658 iface[1] = '\0'; 659 } else 660 iface[0] = '\0'; 661 662 if (outiface[0] != '\0') 663 strcat(iface, outiface); 664 else if (format & FMT_NUMERIC) 665 strcat(iface, "*"); 666 else 667 strcat(iface, "any"); 668 669 printf(FMT("%-6s ","out %s "), iface); 670 } 671 672 static void 673 print_iface(char letter, const char *iface, const unsigned char *mask, int inv) 674 { 675 unsigned int i; 676 677 if (mask[0] == 0) 678 return; 679 680 printf("%s-%c ", inv ? "! " : "", letter); 681 682 for (i = 0; i < IFNAMSIZ; i++) { 683 if (mask[i] != 0) { 684 if (iface[i] != '\0') 685 printf("%c", iface[i]); 686 } else { 687 if (iface[i-1] != '\0') 688 printf("+"); 689 break; 690 } 691 } 692 693 printf(" "); 694 } 695 696 void save_firewall_details(const struct iptables_command_state *cs, 697 uint8_t invflags, uint16_t proto, 698 const char *iniface, 699 unsigned const char *iniface_mask, 700 const char *outiface, 701 unsigned const char *outiface_mask) 702 { 703 if (iniface != NULL) { 704 print_iface('i', iniface, iniface_mask, 705 invflags & IPT_INV_VIA_IN); 706 } 707 if (outiface != NULL) { 708 print_iface('o', outiface, outiface_mask, 709 invflags & IPT_INV_VIA_OUT); 710 } 711 712 if (proto > 0) { 713 const struct protoent *pent = getprotobynumber(proto); 714 715 if (invflags & XT_INV_PROTO) 716 printf("! "); 717 718 if (pent) 719 printf("-p %s ", pent->p_name); 720 else 721 printf("-p %u ", proto); 722 } 723 } 724 725 void save_counters(uint64_t pcnt, uint64_t bcnt) 726 { 727 printf("[%llu:%llu] ", (unsigned long long)pcnt, 728 (unsigned long long)bcnt); 729 } 730 731 void save_matches_and_target(struct xtables_rule_match *m, 732 struct xtables_target *target, 733 const char *jumpto, uint8_t flags, const void *fw) 734 { 735 struct xtables_rule_match *matchp; 736 737 for (matchp = m; matchp; matchp = matchp->next) { 738 if (matchp->match->alias) { 739 printf("-m %s", 740 matchp->match->alias(matchp->match->m)); 741 } else 742 printf("-m %s", matchp->match->name); 743 744 if (matchp->match->save != NULL) { 745 /* cs->fw union makes the trick */ 746 matchp->match->save(fw, matchp->match->m); 747 } 748 printf(" "); 749 } 750 751 if (target != NULL) { 752 if (target->alias) { 753 printf("-j %s", target->alias(target->t)); 754 } else 755 printf("-j %s", jumpto); 756 757 if (target->save != NULL) 758 target->save(fw, target->t); 759 } 760 } 761 762 void print_matches_and_target(struct iptables_command_state *cs, 763 unsigned int format) 764 { 765 struct xtables_rule_match *matchp; 766 767 for (matchp = cs->matches; matchp; matchp = matchp->next) { 768 if (matchp->match->print != NULL) { 769 matchp->match->print(&cs->fw, matchp->match->m, 770 format & FMT_NUMERIC); 771 } 772 } 773 774 if (cs->target != NULL) { 775 if (cs->target->print != NULL) { 776 cs->target->print(&cs->fw, cs->target->t, 777 format & FMT_NUMERIC); 778 } 779 } 780 } 781 782 struct nft_family_ops *nft_family_ops_lookup(int family) 783 { 784 switch (family) { 785 case AF_INET: 786 return &nft_family_ops_ipv4; 787 case AF_INET6: 788 return &nft_family_ops_ipv6; 789 case NFPROTO_ARP: 790 return &nft_family_ops_arp; 791 case NFPROTO_BRIDGE: 792 return &nft_family_ops_bridge; 793 default: 794 break; 795 } 796 797 return NULL; 798 } 799 800 bool compare_matches(struct xtables_rule_match *mt1, 801 struct xtables_rule_match *mt2) 802 { 803 struct xtables_rule_match *mp1; 804 struct xtables_rule_match *mp2; 805 806 for (mp1 = mt1, mp2 = mt2; mp1 && mp2; mp1 = mp1->next, mp2 = mp2->next) { 807 struct xt_entry_match *m1 = mp1->match->m; 808 struct xt_entry_match *m2 = mp2->match->m; 809 810 if (strcmp(m1->u.user.name, m2->u.user.name) != 0) { 811 DEBUGP("mismatching match name\n"); 812 return false; 813 } 814 815 if (m1->u.user.match_size != m2->u.user.match_size) { 816 DEBUGP("mismatching match size\n"); 817 return false; 818 } 819 820 if (memcmp(m1->data, m2->data, 821 mp1->match->userspacesize) != 0) { 822 DEBUGP("mismatch match data\n"); 823 return false; 824 } 825 } 826 827 /* Both cursors should be NULL */ 828 if (mp1 != mp2) { 829 DEBUGP("mismatch matches amount\n"); 830 return false; 831 } 832 833 return true; 834 } 835 836 bool compare_targets(struct xtables_target *tg1, struct xtables_target *tg2) 837 { 838 if (tg1 == NULL && tg2 == NULL) 839 return true; 840 841 if ((tg1 == NULL && tg2 != NULL) || (tg1 != NULL && tg2 == NULL)) 842 return false; 843 844 if (strcmp(tg1->t->u.user.name, tg2->t->u.user.name) != 0) 845 return false; 846 847 if (memcmp(tg1->t->data, tg2->t->data, tg1->userspacesize) != 0) 848 return false; 849 850 return true; 851 } 852 853 bool nft_ipv46_rule_find(struct nft_family_ops *ops, 854 struct nftnl_rule *r, struct iptables_command_state *cs) 855 { 856 struct iptables_command_state this = {}; 857 858 nft_rule_to_iptables_command_state(r, &this); 859 860 DEBUGP("comparing with... "); 861 #ifdef DEBUG_DEL 862 nft_rule_print_save(&this, r, NFT_RULE_APPEND, 0); 863 #endif 864 if (!ops->is_same(cs, &this)) 865 return false; 866 867 if (!compare_matches(cs->matches, this.matches)) { 868 DEBUGP("Different matches\n"); 869 return false; 870 } 871 872 if (!compare_targets(cs->target, this.target)) { 873 DEBUGP("Different target\n"); 874 return false; 875 } 876 877 if (strcmp(cs->jumpto, this.jumpto) != 0) { 878 DEBUGP("Different verdict\n"); 879 return false; 880 } 881 882 return true; 883 } 884