1 /* 2 * (C) 2012 by Pablo Neira Ayuso <pablo (at) netfilter.org> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published 6 * by the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This code has been sponsored by Sophos Astaro <http://www.sophos.com> 10 */ 11 12 #include <unistd.h> 13 #include <fcntl.h> 14 #include <sys/types.h> 15 #include <sys/socket.h> 16 #include <stdbool.h> 17 #include <errno.h> 18 #include <netdb.h> /* getprotobynumber */ 19 #include <time.h> 20 #include <stdarg.h> 21 #include <inttypes.h> 22 23 #include <xtables.h> 24 #include <libiptc/libxtc.h> 25 #include <libiptc/xtcshared.h> 26 27 #include <stdlib.h> 28 #include <string.h> 29 30 #include <linux/netfilter/x_tables.h> 31 #include <linux/netfilter_ipv4/ip_tables.h> 32 #include <linux/netfilter_ipv6/ip6_tables.h> 33 #include <netinet/ip6.h> 34 35 #include <linux/netlink.h> 36 #include <linux/netfilter/nfnetlink.h> 37 #include <linux/netfilter/nf_tables.h> 38 #include <linux/netfilter/nf_tables_compat.h> 39 40 #include <libmnl/libmnl.h> 41 #include <libnftnl/table.h> 42 #include <libnftnl/chain.h> 43 #include <libnftnl/rule.h> 44 #include <libnftnl/expr.h> 45 #include <libnftnl/set.h> 46 #include <libnftnl/udata.h> 47 48 #include <netinet/in.h> /* inet_ntoa */ 49 #include <arpa/inet.h> 50 51 #include "nft.h" 52 #include "xshared.h" /* proto_to_name */ 53 #include "nft-shared.h" 54 #include "xtables-config-parser.h" 55 56 static void *nft_fn; 57 58 int mnl_talk(struct nft_handle *h, struct nlmsghdr *nlh, 59 int (*cb)(const struct nlmsghdr *nlh, void *data), 60 void *data) 61 { 62 int ret; 63 char buf[MNL_SOCKET_BUFFER_SIZE]; 64 65 if (mnl_socket_sendto(h->nl, nlh, nlh->nlmsg_len) < 0) 66 return -1; 67 68 ret = mnl_socket_recvfrom(h->nl, buf, sizeof(buf)); 69 while (ret > 0) { 70 ret = mnl_cb_run(buf, ret, h->seq, h->portid, cb, data); 71 if (ret <= 0) 72 break; 73 74 ret = mnl_socket_recvfrom(h->nl, buf, sizeof(buf)); 75 } 76 if (ret == -1) { 77 return -1; 78 } 79 80 return 0; 81 } 82 83 static LIST_HEAD(batch_page_list); 84 static int batch_num_pages; 85 86 struct batch_page { 87 struct list_head head; 88 struct mnl_nlmsg_batch *batch; 89 }; 90 91 /* selected batch page is 256 Kbytes long to load ruleset of 92 * half a million rules without hitting -EMSGSIZE due to large 93 * iovec. 94 */ 95 #define BATCH_PAGE_SIZE getpagesize() * 32 96 97 static struct mnl_nlmsg_batch *mnl_nftnl_batch_alloc(void) 98 { 99 static char *buf; 100 101 /* libmnl needs higher buffer to handle batch overflows */ 102 buf = malloc(BATCH_PAGE_SIZE + getpagesize()); 103 if (buf == NULL) 104 return NULL; 105 106 return mnl_nlmsg_batch_start(buf, BATCH_PAGE_SIZE); 107 } 108 109 static struct mnl_nlmsg_batch * 110 mnl_nftnl_batch_page_add(struct mnl_nlmsg_batch *batch) 111 { 112 struct batch_page *batch_page; 113 114 batch_page = malloc(sizeof(struct batch_page)); 115 if (batch_page == NULL) 116 return NULL; 117 118 batch_page->batch = batch; 119 list_add_tail(&batch_page->head, &batch_page_list); 120 batch_num_pages++; 121 122 return mnl_nftnl_batch_alloc(); 123 } 124 125 static int nlbuffsiz; 126 127 static void mnl_nft_set_sndbuffer(const struct mnl_socket *nl) 128 { 129 int newbuffsiz; 130 131 if (batch_num_pages * BATCH_PAGE_SIZE <= nlbuffsiz) 132 return; 133 134 newbuffsiz = batch_num_pages * BATCH_PAGE_SIZE; 135 136 /* Rise sender buffer length to avoid hitting -EMSGSIZE */ 137 if (setsockopt(mnl_socket_get_fd(nl), SOL_SOCKET, SO_SNDBUFFORCE, 138 &newbuffsiz, sizeof(socklen_t)) < 0) 139 return; 140 141 nlbuffsiz = newbuffsiz; 142 } 143 144 static void mnl_nftnl_batch_reset(void) 145 { 146 struct batch_page *batch_page, *next; 147 148 list_for_each_entry_safe(batch_page, next, &batch_page_list, head) { 149 list_del(&batch_page->head); 150 free(batch_page->batch); 151 free(batch_page); 152 batch_num_pages--; 153 } 154 } 155 156 static ssize_t mnl_nft_socket_sendmsg(const struct mnl_socket *nl) 157 { 158 static const struct sockaddr_nl snl = { 159 .nl_family = AF_NETLINK 160 }; 161 struct iovec iov[batch_num_pages]; 162 struct msghdr msg = { 163 .msg_name = (struct sockaddr *) &snl, 164 .msg_namelen = sizeof(snl), 165 .msg_iov = iov, 166 .msg_iovlen = batch_num_pages, 167 }; 168 struct batch_page *batch_page; 169 int i = 0, ret; 170 171 mnl_nft_set_sndbuffer(nl); 172 173 list_for_each_entry(batch_page, &batch_page_list, head) { 174 iov[i].iov_base = mnl_nlmsg_batch_head(batch_page->batch); 175 iov[i].iov_len = mnl_nlmsg_batch_size(batch_page->batch); 176 i++; 177 #ifdef NL_DEBUG 178 mnl_nlmsg_fprintf(stdout, 179 mnl_nlmsg_batch_head(batch_page->batch), 180 mnl_nlmsg_batch_size(batch_page->batch), 181 sizeof(struct nfgenmsg)); 182 #endif 183 } 184 185 ret = sendmsg(mnl_socket_get_fd(nl), &msg, 0); 186 mnl_nftnl_batch_reset(); 187 188 return ret; 189 } 190 191 static int mnl_nftnl_batch_talk(struct nft_handle *h) 192 { 193 int ret, fd = mnl_socket_get_fd(h->nl); 194 char rcv_buf[MNL_SOCKET_BUFFER_SIZE]; 195 fd_set readfds; 196 struct timeval tv = { 197 .tv_sec = 0, 198 .tv_usec = 0 199 }; 200 int err = 0; 201 202 ret = mnl_nft_socket_sendmsg(h->nl); 203 if (ret == -1) 204 return -1; 205 206 FD_ZERO(&readfds); 207 FD_SET(fd, &readfds); 208 209 /* receive and digest all the acknowledgments from the kernel. */ 210 ret = select(fd+1, &readfds, NULL, NULL, &tv); 211 if (ret == -1) 212 return -1; 213 214 while (ret > 0 && FD_ISSET(fd, &readfds)) { 215 ret = mnl_socket_recvfrom(h->nl, rcv_buf, sizeof(rcv_buf)); 216 if (ret == -1) 217 return -1; 218 219 ret = mnl_cb_run(rcv_buf, ret, 0, h->portid, NULL, NULL); 220 /* Annotate first error and continue, make sure we get all 221 * acknoledgments. 222 */ 223 if (!err && ret == -1) 224 err = errno; 225 226 ret = select(fd+1, &readfds, NULL, NULL, &tv); 227 if (ret == -1) 228 return -1; 229 230 FD_ZERO(&readfds); 231 FD_SET(fd, &readfds); 232 } 233 errno = err; 234 return err ? -1 : 0; 235 } 236 237 static void mnl_nftnl_batch_begin(struct mnl_nlmsg_batch *batch, uint32_t seq) 238 { 239 nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq); 240 if (!mnl_nlmsg_batch_next(batch)) 241 mnl_nftnl_batch_page_add(batch); 242 } 243 244 static void mnl_nftnl_batch_end(struct mnl_nlmsg_batch *batch, uint32_t seq) 245 { 246 nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq); 247 if (!mnl_nlmsg_batch_next(batch)) 248 mnl_nftnl_batch_page_add(batch); 249 } 250 251 enum obj_update_type { 252 NFT_COMPAT_TABLE_ADD, 253 NFT_COMPAT_CHAIN_ADD, 254 NFT_COMPAT_CHAIN_USER_ADD, 255 NFT_COMPAT_CHAIN_USER_DEL, 256 NFT_COMPAT_CHAIN_UPDATE, 257 NFT_COMPAT_CHAIN_RENAME, 258 NFT_COMPAT_RULE_APPEND, 259 NFT_COMPAT_RULE_INSERT, 260 NFT_COMPAT_RULE_REPLACE, 261 NFT_COMPAT_RULE_DELETE, 262 NFT_COMPAT_RULE_FLUSH, 263 }; 264 265 enum obj_action { 266 NFT_COMPAT_COMMIT, 267 NFT_COMPAT_ABORT, 268 }; 269 270 struct obj_update { 271 struct list_head head; 272 enum obj_update_type type; 273 union { 274 struct nftnl_table *table; 275 struct nftnl_chain *chain; 276 struct nftnl_rule *rule; 277 void *ptr; 278 }; 279 }; 280 281 static int batch_add(struct nft_handle *h, enum obj_update_type type, void *ptr) 282 { 283 struct obj_update *obj; 284 285 obj = calloc(1, sizeof(struct obj_update)); 286 if (obj == NULL) 287 return -1; 288 289 obj->ptr = ptr; 290 obj->type = type; 291 list_add_tail(&obj->head, &h->obj_list); 292 h->obj_list_num++; 293 294 return 0; 295 } 296 297 static int batch_table_add(struct nft_handle *h, enum obj_update_type type, 298 struct nftnl_table *t) 299 { 300 return batch_add(h, type, t); 301 } 302 303 static int batch_chain_add(struct nft_handle *h, enum obj_update_type type, 304 struct nftnl_chain *c) 305 { 306 return batch_add(h, type, c); 307 } 308 309 static int batch_rule_add(struct nft_handle *h, enum obj_update_type type, 310 struct nftnl_rule *r) 311 { 312 return batch_add(h, type, r); 313 } 314 315 struct builtin_table xtables_ipv4[TABLES_MAX] = { 316 [RAW] = { 317 .name = "raw", 318 .chains = { 319 { 320 .name = "PREROUTING", 321 .type = "filter", 322 .prio = -300, /* NF_IP_PRI_RAW */ 323 .hook = NF_INET_PRE_ROUTING, 324 }, 325 { 326 .name = "OUTPUT", 327 .type = "filter", 328 .prio = -300, /* NF_IP_PRI_RAW */ 329 .hook = NF_INET_LOCAL_OUT, 330 }, 331 }, 332 }, 333 [MANGLE] = { 334 .name = "mangle", 335 .chains = { 336 { 337 .name = "PREROUTING", 338 .type = "filter", 339 .prio = -150, /* NF_IP_PRI_MANGLE */ 340 .hook = NF_INET_PRE_ROUTING, 341 }, 342 { 343 .name = "INPUT", 344 .type = "filter", 345 .prio = -150, /* NF_IP_PRI_MANGLE */ 346 .hook = NF_INET_LOCAL_IN, 347 }, 348 { 349 .name = "FORWARD", 350 .type = "filter", 351 .prio = -150, /* NF_IP_PRI_MANGLE */ 352 .hook = NF_INET_FORWARD, 353 }, 354 { 355 .name = "OUTPUT", 356 .type = "route", 357 .prio = -150, /* NF_IP_PRI_MANGLE */ 358 .hook = NF_INET_LOCAL_OUT, 359 }, 360 { 361 .name = "POSTROUTING", 362 .type = "filter", 363 .prio = -150, /* NF_IP_PRI_MANGLE */ 364 .hook = NF_INET_POST_ROUTING, 365 }, 366 }, 367 }, 368 [FILTER] = { 369 .name = "filter", 370 .chains = { 371 { 372 .name = "INPUT", 373 .type = "filter", 374 .prio = 0, /* NF_IP_PRI_FILTER */ 375 .hook = NF_INET_LOCAL_IN, 376 }, 377 { 378 .name = "FORWARD", 379 .type = "filter", 380 .prio = 0, /* NF_IP_PRI_FILTER */ 381 .hook = NF_INET_FORWARD, 382 }, 383 { 384 .name = "OUTPUT", 385 .type = "filter", 386 .prio = 0, /* NF_IP_PRI_FILTER */ 387 .hook = NF_INET_LOCAL_OUT, 388 }, 389 }, 390 }, 391 [SECURITY] = { 392 .name = "security", 393 .chains = { 394 { 395 .name = "INPUT", 396 .type = "filter", 397 .prio = 150, /* NF_IP_PRI_SECURITY */ 398 .hook = NF_INET_LOCAL_IN, 399 }, 400 { 401 .name = "FORWARD", 402 .type = "filter", 403 .prio = 150, /* NF_IP_PRI_SECURITY */ 404 .hook = NF_INET_FORWARD, 405 }, 406 { 407 .name = "OUTPUT", 408 .type = "filter", 409 .prio = 150, /* NF_IP_PRI_SECURITY */ 410 .hook = NF_INET_LOCAL_OUT, 411 }, 412 }, 413 }, 414 [NAT] = { 415 .name = "nat", 416 .chains = { 417 { 418 .name = "PREROUTING", 419 .type = "nat", 420 .prio = -100, /* NF_IP_PRI_NAT_DST */ 421 .hook = NF_INET_PRE_ROUTING, 422 }, 423 { 424 .name = "INPUT", 425 .type = "nat", 426 .prio = 100, /* NF_IP_PRI_NAT_SRC */ 427 .hook = NF_INET_LOCAL_IN, 428 }, 429 { 430 .name = "POSTROUTING", 431 .type = "nat", 432 .prio = 100, /* NF_IP_PRI_NAT_SRC */ 433 .hook = NF_INET_POST_ROUTING, 434 }, 435 { 436 .name = "OUTPUT", 437 .type = "nat", 438 .prio = -100, /* NF_IP_PRI_NAT_DST */ 439 .hook = NF_INET_LOCAL_OUT, 440 }, 441 }, 442 }, 443 }; 444 445 #include <linux/netfilter_arp.h> 446 447 struct builtin_table xtables_arp[TABLES_MAX] = { 448 [FILTER] = { 449 .name = "filter", 450 .chains = { 451 { 452 .name = "INPUT", 453 .type = "filter", 454 .prio = NF_IP_PRI_FILTER, 455 .hook = NF_ARP_IN, 456 }, 457 { 458 .name = "FORWARD", 459 .type = "filter", 460 .prio = NF_IP_PRI_FILTER, 461 .hook = NF_ARP_FORWARD, 462 }, 463 { 464 .name = "OUTPUT", 465 .type = "filter", 466 .prio = NF_IP_PRI_FILTER, 467 .hook = NF_ARP_OUT, 468 }, 469 }, 470 }, 471 }; 472 473 #include <linux/netfilter_bridge.h> 474 475 struct builtin_table xtables_bridge[TABLES_MAX] = { 476 [FILTER] = { 477 .name = "filter", 478 .chains = { 479 { 480 .name = "INPUT", 481 .type = "filter", 482 .prio = NF_BR_PRI_FILTER_BRIDGED, 483 .hook = NF_BR_LOCAL_IN, 484 }, 485 { 486 .name = "FORWARD", 487 .type = "filter", 488 .prio = NF_BR_PRI_FILTER_BRIDGED, 489 .hook = NF_BR_FORWARD, 490 }, 491 { 492 .name = "OUTPUT", 493 .type = "filter", 494 .prio = NF_BR_PRI_FILTER_BRIDGED, 495 .hook = NF_BR_LOCAL_OUT, 496 }, 497 }, 498 }, 499 [NAT] = { 500 .name = "nat", 501 .chains = { 502 { 503 .name = "PREROUTING", 504 .type = "filter", 505 .prio = NF_BR_PRI_NAT_DST_BRIDGED, 506 .hook = NF_BR_PRE_ROUTING, 507 }, 508 { 509 .name = "OUTPUT", 510 .type = "filter", 511 .prio = NF_BR_PRI_NAT_DST_OTHER, 512 .hook = NF_BR_LOCAL_OUT, 513 }, 514 { 515 .name = "POSTROUTING", 516 .type = "filter", 517 .prio = NF_BR_PRI_NAT_SRC, 518 .hook = NF_BR_POST_ROUTING, 519 }, 520 }, 521 }, 522 }; 523 524 int nft_table_add(struct nft_handle *h, struct nftnl_table *t, uint16_t flags) 525 { 526 char buf[MNL_SOCKET_BUFFER_SIZE]; 527 struct nlmsghdr *nlh; 528 int ret; 529 530 nlh = nftnl_table_nlmsg_build_hdr(buf, NFT_MSG_NEWTABLE, h->family, 531 NLM_F_ACK|flags, h->seq); 532 nftnl_table_nlmsg_build_payload(nlh, t); 533 nftnl_table_free(t); 534 535 #ifdef NLDEBUG 536 char tmp[1024]; 537 538 nft_table_snprintf(tmp, sizeof(tmp), t, 0, 0); 539 printf("DEBUG: table: %s\n", tmp); 540 mnl_nlmsg_fprintf(stdout, nlh, nlh->nlmsg_len, sizeof(struct nfgenmsg)); 541 #endif 542 543 ret = mnl_talk(h, nlh, NULL, NULL); 544 545 return (ret == 0 || (ret == -1 && errno == EEXIST)) ? 0 : -1; 546 } 547 548 static int nft_table_builtin_add(struct nft_handle *h, 549 struct builtin_table *_t) 550 { 551 struct nftnl_table *t; 552 int ret; 553 554 if (_t->initialized) 555 return 0; 556 557 t = nftnl_table_alloc(); 558 if (t == NULL) 559 return -1; 560 561 nftnl_table_set(t, NFTNL_TABLE_NAME, (char *)_t->name); 562 563 if (h->batch_support) 564 ret = batch_table_add(h, NFT_COMPAT_TABLE_ADD, t); 565 else 566 ret = nft_table_add(h, t, NLM_F_EXCL); 567 568 if (ret == 0) 569 _t->initialized = true; 570 571 return ret; 572 } 573 574 static struct nftnl_chain * 575 nft_chain_builtin_alloc(struct builtin_table *table, 576 struct builtin_chain *chain, int policy) 577 { 578 struct nftnl_chain *c; 579 580 c = nftnl_chain_alloc(); 581 if (c == NULL) 582 return NULL; 583 584 nftnl_chain_set(c, NFTNL_CHAIN_TABLE, (char *)table->name); 585 nftnl_chain_set(c, NFTNL_CHAIN_NAME, (char *)chain->name); 586 nftnl_chain_set_u32(c, NFTNL_CHAIN_HOOKNUM, chain->hook); 587 nftnl_chain_set_u32(c, NFTNL_CHAIN_PRIO, chain->prio); 588 nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, policy); 589 nftnl_chain_set(c, NFTNL_CHAIN_TYPE, (char *)chain->type); 590 591 return c; 592 } 593 594 int nft_chain_add(struct nft_handle *h, struct nftnl_chain *c, uint16_t flags) 595 { 596 char buf[MNL_SOCKET_BUFFER_SIZE]; 597 struct nlmsghdr *nlh; 598 599 /* NLM_F_CREATE requests module autoloading */ 600 nlh = nftnl_chain_nlmsg_build_hdr(buf, NFT_MSG_NEWCHAIN, h->family, 601 NLM_F_ACK|flags|NLM_F_CREATE, 602 h->seq); 603 nftnl_chain_nlmsg_build_payload(nlh, c); 604 nftnl_chain_free(c); 605 606 #ifdef NLDEBUG 607 char tmp[1024]; 608 609 nft_chain_snprintf(tmp, sizeof(tmp), c, 0, 0); 610 printf("DEBUG: chain: %s\n", tmp); 611 mnl_nlmsg_fprintf(stdout, nlh, nlh->nlmsg_len, sizeof(struct nfgenmsg)); 612 #endif 613 614 return mnl_talk(h, nlh, NULL, NULL); 615 } 616 617 static void nft_chain_builtin_add(struct nft_handle *h, 618 struct builtin_table *table, 619 struct builtin_chain *chain) 620 { 621 struct nftnl_chain *c; 622 623 c = nft_chain_builtin_alloc(table, chain, NF_ACCEPT); 624 if (c == NULL) 625 return; 626 627 if (h->batch_support) 628 batch_chain_add(h, NFT_COMPAT_CHAIN_ADD, c); 629 else 630 nft_chain_add(h, c, NLM_F_EXCL); 631 } 632 633 /* find if built-in table already exists */ 634 static struct builtin_table * 635 nft_table_builtin_find(struct nft_handle *h, const char *table) 636 { 637 int i; 638 bool found = false; 639 640 for (i=0; i<TABLES_MAX; i++) { 641 if (h->tables[i].name == NULL) 642 continue; 643 644 if (strcmp(h->tables[i].name, table) != 0) 645 continue; 646 647 found = true; 648 break; 649 } 650 651 return found ? &h->tables[i] : NULL; 652 } 653 654 /* find if built-in chain already exists */ 655 static struct builtin_chain * 656 nft_chain_builtin_find(struct builtin_table *t, const char *chain) 657 { 658 int i; 659 bool found = false; 660 661 for (i=0; i<NF_IP_NUMHOOKS && t->chains[i].name != NULL; i++) { 662 if (strcmp(t->chains[i].name, chain) != 0) 663 continue; 664 665 found = true; 666 break; 667 } 668 return found ? &t->chains[i] : NULL; 669 } 670 671 static void nft_chain_builtin_init(struct nft_handle *h, 672 struct builtin_table *table) 673 { 674 int i; 675 struct nftnl_chain_list *list = nft_chain_dump(h); 676 struct nftnl_chain *c; 677 678 /* Initialize built-in chains if they don't exist yet */ 679 for (i=0; i<NF_IP_NUMHOOKS && table->chains[i].name != NULL; i++) { 680 681 c = nft_chain_list_find(list, table->name, 682 table->chains[i].name); 683 if (c != NULL) 684 continue; 685 686 nft_chain_builtin_add(h, table, &table->chains[i]); 687 } 688 689 nftnl_chain_list_free(list); 690 } 691 692 static int nft_xt_builtin_init(struct nft_handle *h, const char *table) 693 { 694 int ret = 0; 695 struct builtin_table *t; 696 697 t = nft_table_builtin_find(h, table); 698 if (t == NULL) { 699 ret = -1; 700 goto out; 701 } 702 if (nft_table_builtin_add(h, t) < 0) { 703 /* Built-in table already initialized, skip. */ 704 if (errno == EEXIST) 705 goto out; 706 } 707 nft_chain_builtin_init(h, t); 708 out: 709 return ret; 710 } 711 712 static bool nft_chain_builtin(struct nftnl_chain *c) 713 { 714 /* Check if this chain has hook number, in that case is built-in. 715 * Should we better export the flags to user-space via nf_tables? 716 */ 717 return nftnl_chain_get(c, NFTNL_CHAIN_HOOKNUM) != NULL; 718 } 719 720 static bool mnl_batch_supported(struct nft_handle *h) 721 { 722 char buf[MNL_SOCKET_BUFFER_SIZE]; 723 uint32_t seq = 1; 724 int ret; 725 726 mnl_nftnl_batch_begin(h->batch, seq++); 727 728 nftnl_set_nlmsg_build_hdr(mnl_nlmsg_batch_current(h->batch), 729 NFT_MSG_NEWSET, AF_INET, 730 NLM_F_ACK, seq++); 731 mnl_nlmsg_batch_next(h->batch); 732 733 mnl_nftnl_batch_end(h->batch, seq++); 734 735 ret = mnl_socket_sendto(h->nl, mnl_nlmsg_batch_head(h->batch), 736 mnl_nlmsg_batch_size(h->batch)); 737 if (ret < 0) 738 goto err; 739 740 mnl_nlmsg_batch_reset(h->batch); 741 742 ret = mnl_socket_recvfrom(h->nl, buf, sizeof(buf)); 743 while (ret > 0) { 744 ret = mnl_cb_run(buf, ret, 0, mnl_socket_get_portid(h->nl), 745 NULL, NULL); 746 if (ret <= 0) 747 break; 748 749 ret = mnl_socket_recvfrom(h->nl, buf, sizeof(buf)); 750 } 751 752 /* We're sending an incomplete message to see if the kernel supports 753 * set messages in batches. EINVAL means that we sent an incomplete 754 * message with missing attributes. The kernel just ignores messages 755 * that we cannot include in the batch. 756 */ 757 return (ret == -1 && errno == EINVAL) ? true : false; 758 err: 759 mnl_nlmsg_batch_reset(h->batch); 760 return ret; 761 } 762 763 int nft_init(struct nft_handle *h, struct builtin_table *t) 764 { 765 h->nl = mnl_socket_open(NETLINK_NETFILTER); 766 if (h->nl == NULL) 767 return -1; 768 769 if (mnl_socket_bind(h->nl, 0, MNL_SOCKET_AUTOPID) < 0) 770 return -1; 771 772 h->portid = mnl_socket_get_portid(h->nl); 773 h->tables = t; 774 775 INIT_LIST_HEAD(&h->obj_list); 776 777 h->batch = mnl_nftnl_batch_alloc(); 778 h->batch_support = mnl_batch_supported(h); 779 780 return 0; 781 } 782 783 static void flush_rule_cache(struct nft_handle *h) 784 { 785 if (!h->rule_cache) 786 return; 787 788 nftnl_rule_list_free(h->rule_cache); 789 h->rule_cache = NULL; 790 } 791 792 void nft_fini(struct nft_handle *h) 793 { 794 flush_rule_cache(h); 795 mnl_socket_close(h->nl); 796 free(mnl_nlmsg_batch_head(h->batch)); 797 mnl_nlmsg_batch_stop(h->batch); 798 } 799 800 static void nft_chain_print_debug(struct nftnl_chain *c, struct nlmsghdr *nlh) 801 { 802 #ifdef NLDEBUG 803 char tmp[1024]; 804 805 nft_chain_snprintf(tmp, sizeof(tmp), c, 0, 0); 806 printf("DEBUG: chain: %s\n", tmp); 807 mnl_nlmsg_fprintf(stdout, nlh, nlh->nlmsg_len, sizeof(struct nfgenmsg)); 808 #endif 809 } 810 811 static struct nftnl_chain *nft_chain_new(struct nft_handle *h, 812 const char *table, const char *chain, 813 int policy, 814 const struct xt_counters *counters) 815 { 816 struct nftnl_chain *c; 817 struct builtin_table *_t; 818 struct builtin_chain *_c; 819 820 _t = nft_table_builtin_find(h, table); 821 /* if this built-in table does not exists, create it */ 822 if (_t != NULL) 823 nft_table_builtin_add(h, _t); 824 825 _c = nft_chain_builtin_find(_t, chain); 826 if (_c != NULL) { 827 /* This is a built-in chain */ 828 c = nft_chain_builtin_alloc(_t, _c, policy); 829 if (c == NULL) 830 return NULL; 831 } else { 832 errno = ENOENT; 833 return NULL; 834 } 835 836 if (counters) { 837 nftnl_chain_set_u64(c, NFTNL_CHAIN_BYTES, 838 counters->bcnt); 839 nftnl_chain_set_u64(c, NFTNL_CHAIN_PACKETS, 840 counters->pcnt); 841 } 842 843 return c; 844 } 845 846 int nft_chain_set(struct nft_handle *h, const char *table, 847 const char *chain, const char *policy, 848 const struct xt_counters *counters) 849 { 850 struct nftnl_chain *c = NULL; 851 int ret; 852 853 nft_fn = nft_chain_set; 854 855 if (strcmp(policy, "DROP") == 0) 856 c = nft_chain_new(h, table, chain, NF_DROP, counters); 857 else if (strcmp(policy, "ACCEPT") == 0) 858 c = nft_chain_new(h, table, chain, NF_ACCEPT, counters); 859 860 if (c == NULL) 861 return 0; 862 863 if (h->batch_support) 864 ret = batch_chain_add(h, NFT_COMPAT_CHAIN_UPDATE, c); 865 else 866 ret = nft_chain_add(h, c, 0); 867 868 /* the core expects 1 for success and 0 for error */ 869 return ret == 0 ? 1 : 0; 870 } 871 872 static int __add_match(struct nftnl_expr *e, struct xt_entry_match *m) 873 { 874 void *info; 875 876 nftnl_expr_set(e, NFTNL_EXPR_MT_NAME, m->u.user.name, strlen(m->u.user.name)); 877 nftnl_expr_set_u32(e, NFTNL_EXPR_MT_REV, m->u.user.revision); 878 879 info = calloc(1, m->u.match_size); 880 if (info == NULL) 881 return -ENOMEM; 882 883 memcpy(info, m->data, m->u.match_size - sizeof(*m)); 884 nftnl_expr_set(e, NFTNL_EXPR_MT_INFO, info, m->u.match_size - sizeof(*m)); 885 886 return 0; 887 } 888 889 int add_match(struct nftnl_rule *r, struct xt_entry_match *m) 890 { 891 struct nftnl_expr *expr; 892 int ret; 893 894 expr = nftnl_expr_alloc("match"); 895 if (expr == NULL) 896 return -ENOMEM; 897 898 ret = __add_match(expr, m); 899 nftnl_rule_add_expr(r, expr); 900 901 return ret; 902 } 903 904 static int __add_target(struct nftnl_expr *e, struct xt_entry_target *t) 905 { 906 void *info; 907 908 nftnl_expr_set(e, NFTNL_EXPR_TG_NAME, t->u.user.name, 909 strlen(t->u.user.name)); 910 nftnl_expr_set_u32(e, NFTNL_EXPR_TG_REV, t->u.user.revision); 911 912 info = calloc(1, t->u.target_size); 913 if (info == NULL) 914 return -ENOMEM; 915 916 memcpy(info, t->data, t->u.target_size - sizeof(*t)); 917 nftnl_expr_set(e, NFTNL_EXPR_TG_INFO, info, t->u.target_size - sizeof(*t)); 918 919 return 0; 920 } 921 922 int add_target(struct nftnl_rule *r, struct xt_entry_target *t) 923 { 924 struct nftnl_expr *expr; 925 int ret; 926 927 expr = nftnl_expr_alloc("target"); 928 if (expr == NULL) 929 return -ENOMEM; 930 931 ret = __add_target(expr, t); 932 nftnl_rule_add_expr(r, expr); 933 934 return ret; 935 } 936 937 int add_jumpto(struct nftnl_rule *r, const char *name, int verdict) 938 { 939 struct nftnl_expr *expr; 940 941 expr = nftnl_expr_alloc("immediate"); 942 if (expr == NULL) 943 return -ENOMEM; 944 945 nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_DREG, NFT_REG_VERDICT); 946 nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_VERDICT, verdict); 947 nftnl_expr_set_str(expr, NFTNL_EXPR_IMM_CHAIN, (char *)name); 948 nftnl_rule_add_expr(r, expr); 949 950 return 0; 951 } 952 953 int add_verdict(struct nftnl_rule *r, int verdict) 954 { 955 struct nftnl_expr *expr; 956 957 expr = nftnl_expr_alloc("immediate"); 958 if (expr == NULL) 959 return -ENOMEM; 960 961 nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_DREG, NFT_REG_VERDICT); 962 nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_VERDICT, verdict); 963 nftnl_rule_add_expr(r, expr); 964 965 return 0; 966 } 967 968 int add_action(struct nftnl_rule *r, struct iptables_command_state *cs, 969 bool goto_set) 970 { 971 int ret = 0; 972 973 /* If no target at all, add nothing (default to continue) */ 974 if (cs->target != NULL) { 975 /* Standard target? */ 976 if (strcmp(cs->jumpto, XTC_LABEL_ACCEPT) == 0) 977 ret = add_verdict(r, NF_ACCEPT); 978 else if (strcmp(cs->jumpto, XTC_LABEL_DROP) == 0) 979 ret = add_verdict(r, NF_DROP); 980 else if (strcmp(cs->jumpto, XTC_LABEL_RETURN) == 0) 981 ret = add_verdict(r, NFT_RETURN); 982 else 983 ret = add_target(r, cs->target->t); 984 } else if (strlen(cs->jumpto) > 0) { 985 /* Not standard, then it's a go / jump to chain */ 986 if (goto_set) 987 ret = add_jumpto(r, cs->jumpto, NFT_GOTO); 988 else 989 ret = add_jumpto(r, cs->jumpto, NFT_JUMP); 990 } 991 return ret; 992 } 993 994 static void nft_rule_print_debug(struct nftnl_rule *r, struct nlmsghdr *nlh) 995 { 996 #ifdef NLDEBUG 997 char tmp[1024]; 998 999 nft_rule_snprintf(tmp, sizeof(tmp), r, 0, 0); 1000 printf("DEBUG: rule: %s\n", tmp); 1001 mnl_nlmsg_fprintf(stdout, nlh, nlh->nlmsg_len, sizeof(struct nfgenmsg)); 1002 #endif 1003 } 1004 1005 int add_counters(struct nftnl_rule *r, uint64_t packets, uint64_t bytes) 1006 { 1007 struct nftnl_expr *expr; 1008 1009 expr = nftnl_expr_alloc("counter"); 1010 if (expr == NULL) 1011 return -ENOMEM; 1012 1013 nftnl_expr_set_u64(expr, NFTNL_EXPR_CTR_PACKETS, packets); 1014 nftnl_expr_set_u64(expr, NFTNL_EXPR_CTR_BYTES, bytes); 1015 1016 nftnl_rule_add_expr(r, expr); 1017 1018 return 0; 1019 } 1020 1021 enum udata_type { 1022 UDATA_TYPE_COMMENT, 1023 __UDATA_TYPE_MAX, 1024 }; 1025 #define UDATA_TYPE_MAX (__UDATA_TYPE_MAX - 1) 1026 1027 int add_comment(struct nftnl_rule *r, const char *comment) 1028 { 1029 struct nftnl_udata_buf *udata; 1030 1031 udata = nftnl_udata_buf_alloc(NFT_USERDATA_MAXLEN); 1032 if (!udata) 1033 return -ENOMEM; 1034 1035 if (!nftnl_udata_put_strz(udata, UDATA_TYPE_COMMENT, comment)) 1036 return -ENOMEM; 1037 nftnl_rule_set_data(r, NFTNL_RULE_USERDATA, 1038 nftnl_udata_buf_data(udata), 1039 nftnl_udata_buf_len(udata)); 1040 1041 nftnl_udata_buf_free(udata); 1042 1043 return 0; 1044 } 1045 1046 static int parse_udata_cb(const struct nftnl_udata *attr, void *data) 1047 { 1048 unsigned char *value = nftnl_udata_get(attr); 1049 uint8_t type = nftnl_udata_type(attr); 1050 uint8_t len = nftnl_udata_len(attr); 1051 const struct nftnl_udata **tb = data; 1052 1053 switch (type) { 1054 case UDATA_TYPE_COMMENT: 1055 if (value[len - 1] != '\0') 1056 return -1; 1057 break; 1058 default: 1059 return 0; 1060 } 1061 tb[type] = attr; 1062 return 0; 1063 } 1064 1065 char *get_comment(const void *data, uint32_t data_len) 1066 { 1067 const struct nftnl_udata *tb[UDATA_TYPE_MAX + 1] = {}; 1068 1069 if (nftnl_udata_parse(data, data_len, parse_udata_cb, tb) < 0) 1070 return NULL; 1071 1072 if (!tb[UDATA_TYPE_COMMENT]) 1073 return NULL; 1074 1075 return nftnl_udata_get(tb[UDATA_TYPE_COMMENT]); 1076 } 1077 1078 void add_compat(struct nftnl_rule *r, uint32_t proto, bool inv) 1079 { 1080 nftnl_rule_set_u32(r, NFTNL_RULE_COMPAT_PROTO, proto); 1081 nftnl_rule_set_u32(r, NFTNL_RULE_COMPAT_FLAGS, 1082 inv ? NFT_RULE_COMPAT_F_INV : 0); 1083 } 1084 1085 static struct nftnl_rule * 1086 nft_rule_new(struct nft_handle *h, const char *chain, const char *table, 1087 void *data) 1088 { 1089 struct nftnl_rule *r; 1090 1091 r = nftnl_rule_alloc(); 1092 if (r == NULL) 1093 return NULL; 1094 1095 nftnl_rule_set_u32(r, NFTNL_RULE_FAMILY, h->family); 1096 nftnl_rule_set(r, NFTNL_RULE_TABLE, (char *)table); 1097 nftnl_rule_set(r, NFTNL_RULE_CHAIN, (char *)chain); 1098 1099 if (h->ops->add(r, data) < 0) 1100 goto err; 1101 1102 return r; 1103 err: 1104 nftnl_rule_free(r); 1105 return NULL; 1106 } 1107 1108 int 1109 nft_rule_append(struct nft_handle *h, const char *chain, const char *table, 1110 void *data, uint64_t handle, bool verbose) 1111 { 1112 struct nftnl_rule *r; 1113 int type; 1114 1115 /* If built-in chains don't exist for this table, create them */ 1116 if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0) 1117 nft_xt_builtin_init(h, table); 1118 1119 nft_fn = nft_rule_append; 1120 1121 r = nft_rule_new(h, chain, table, data); 1122 if (r == NULL) 1123 return 0; 1124 1125 if (handle > 0) { 1126 nftnl_rule_set(r, NFTNL_RULE_HANDLE, &handle); 1127 type = NFT_COMPAT_RULE_REPLACE; 1128 } else 1129 type = NFT_COMPAT_RULE_APPEND; 1130 1131 if (batch_rule_add(h, type, r) < 0) 1132 nftnl_rule_free(r); 1133 1134 flush_rule_cache(h); 1135 return 1; 1136 } 1137 1138 void 1139 nft_rule_print_save(const void *data, 1140 struct nftnl_rule *r, enum nft_rule_print type, 1141 unsigned int format) 1142 { 1143 const char *chain = nftnl_rule_get_str(r, NFTNL_RULE_CHAIN); 1144 int family = nftnl_rule_get_u32(r, NFTNL_RULE_FAMILY); 1145 struct nft_family_ops *ops; 1146 1147 ops = nft_family_ops_lookup(family); 1148 1149 if (!(format & FMT_NOCOUNTS) && ops->save_counters) 1150 ops->save_counters(data); 1151 1152 /* print chain name */ 1153 switch(type) { 1154 case NFT_RULE_APPEND: 1155 printf("-A %s ", chain); 1156 break; 1157 case NFT_RULE_DEL: 1158 printf("-D %s ", chain); 1159 break; 1160 } 1161 1162 if (ops->save_firewall) 1163 ops->save_firewall(data, format); 1164 1165 } 1166 1167 static int nftnl_chain_list_cb(const struct nlmsghdr *nlh, void *data) 1168 { 1169 struct nftnl_chain *c; 1170 struct nftnl_chain_list *list = data; 1171 1172 c = nftnl_chain_alloc(); 1173 if (c == NULL) 1174 goto err; 1175 1176 if (nftnl_chain_nlmsg_parse(nlh, c) < 0) 1177 goto out; 1178 1179 nftnl_chain_list_add_tail(c, list); 1180 1181 return MNL_CB_OK; 1182 out: 1183 nftnl_chain_free(c); 1184 err: 1185 return MNL_CB_OK; 1186 } 1187 1188 static struct nftnl_chain_list *nftnl_chain_list_get(struct nft_handle *h) 1189 { 1190 char buf[MNL_SOCKET_BUFFER_SIZE]; 1191 struct nlmsghdr *nlh; 1192 struct nftnl_chain_list *list; 1193 1194 list = nftnl_chain_list_alloc(); 1195 if (list == NULL) { 1196 errno = ENOMEM; 1197 return NULL; 1198 } 1199 1200 nlh = nftnl_chain_nlmsg_build_hdr(buf, NFT_MSG_GETCHAIN, h->family, 1201 NLM_F_DUMP, h->seq); 1202 1203 mnl_talk(h, nlh, nftnl_chain_list_cb, list); 1204 1205 return list; 1206 } 1207 1208 struct nftnl_chain_list *nft_chain_dump(struct nft_handle *h) 1209 { 1210 return nftnl_chain_list_get(h); 1211 } 1212 1213 static const char *policy_name[NF_ACCEPT+1] = { 1214 [NF_DROP] = "DROP", 1215 [NF_ACCEPT] = "ACCEPT", 1216 }; 1217 1218 static void nft_chain_print_save(struct nftnl_chain *c, bool basechain) 1219 { 1220 const char *chain = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME); 1221 uint64_t pkts = nftnl_chain_get_u64(c, NFTNL_CHAIN_PACKETS); 1222 uint64_t bytes = nftnl_chain_get_u64(c, NFTNL_CHAIN_BYTES); 1223 1224 /* print chain name */ 1225 if (basechain) { 1226 uint32_t pol = NF_ACCEPT; 1227 1228 /* no default chain policy? don't crash, display accept */ 1229 if (nftnl_chain_get(c, NFTNL_CHAIN_POLICY)) 1230 pol = nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY); 1231 1232 printf(":%s %s [%"PRIu64":%"PRIu64"]\n", chain, policy_name[pol], 1233 pkts, bytes); 1234 } else 1235 printf(":%s - [%"PRIu64":%"PRIu64"]\n", chain, pkts, bytes); 1236 } 1237 1238 int nft_chain_save(struct nft_handle *h, struct nftnl_chain_list *list, 1239 const char *table) 1240 { 1241 struct nftnl_chain_list_iter *iter; 1242 struct nftnl_chain *c; 1243 1244 iter = nftnl_chain_list_iter_create(list); 1245 if (iter == NULL) 1246 return 0; 1247 1248 c = nftnl_chain_list_iter_next(iter); 1249 while (c != NULL) { 1250 const char *chain_table = 1251 nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE); 1252 bool basechain = false; 1253 1254 if (strcmp(table, chain_table) != 0) 1255 goto next; 1256 1257 basechain = nft_chain_builtin(c); 1258 nft_chain_print_save(c, basechain); 1259 next: 1260 c = nftnl_chain_list_iter_next(iter); 1261 } 1262 1263 nftnl_chain_list_iter_destroy(iter); 1264 nftnl_chain_list_free(list); 1265 1266 return 1; 1267 } 1268 1269 static int nftnl_rule_list_cb(const struct nlmsghdr *nlh, void *data) 1270 { 1271 struct nftnl_rule *r; 1272 struct nftnl_rule_list *list = data; 1273 1274 r = nftnl_rule_alloc(); 1275 if (r == NULL) 1276 goto err; 1277 1278 if (nftnl_rule_nlmsg_parse(nlh, r) < 0) 1279 goto out; 1280 1281 nftnl_rule_list_add_tail(r, list); 1282 1283 return MNL_CB_OK; 1284 out: 1285 nftnl_rule_free(r); 1286 nftnl_rule_list_free(list); 1287 err: 1288 return MNL_CB_OK; 1289 } 1290 1291 static struct nftnl_rule_list *nft_rule_list_get(struct nft_handle *h) 1292 { 1293 char buf[MNL_SOCKET_BUFFER_SIZE]; 1294 struct nlmsghdr *nlh; 1295 struct nftnl_rule_list *list; 1296 int ret; 1297 1298 if (h->rule_cache) 1299 return h->rule_cache; 1300 1301 list = nftnl_rule_list_alloc(); 1302 if (list == NULL) 1303 return 0; 1304 1305 nlh = nftnl_rule_nlmsg_build_hdr(buf, NFT_MSG_GETRULE, h->family, 1306 NLM_F_DUMP, h->seq); 1307 1308 ret = mnl_talk(h, nlh, nftnl_rule_list_cb, list); 1309 if (ret < 0) { 1310 nftnl_rule_list_free(list); 1311 return NULL; 1312 } 1313 1314 h->rule_cache = list; 1315 return list; 1316 } 1317 1318 int nft_rule_save(struct nft_handle *h, const char *table, bool counters) 1319 { 1320 struct nftnl_rule_list *list; 1321 struct nftnl_rule_list_iter *iter; 1322 struct nftnl_rule *r; 1323 1324 list = nft_rule_list_get(h); 1325 if (list == NULL) 1326 return 0; 1327 1328 iter = nftnl_rule_list_iter_create(list); 1329 if (iter == NULL) 1330 return 0; 1331 1332 r = nftnl_rule_list_iter_next(iter); 1333 while (r != NULL) { 1334 const char *rule_table = 1335 nftnl_rule_get_str(r, NFTNL_RULE_TABLE); 1336 struct iptables_command_state cs = {}; 1337 1338 if (strcmp(table, rule_table) != 0) 1339 goto next; 1340 1341 nft_rule_to_iptables_command_state(r, &cs); 1342 1343 nft_rule_print_save(&cs, r, NFT_RULE_APPEND, 1344 counters ? 0 : FMT_NOCOUNTS); 1345 1346 next: 1347 r = nftnl_rule_list_iter_next(iter); 1348 } 1349 1350 nftnl_rule_list_iter_destroy(iter); 1351 1352 /* the core expects 1 for success and 0 for error */ 1353 return 1; 1354 } 1355 1356 static void 1357 __nft_rule_flush(struct nft_handle *h, const char *table, const char *chain) 1358 { 1359 struct nftnl_rule *r; 1360 1361 r = nftnl_rule_alloc(); 1362 if (r == NULL) 1363 return; 1364 1365 nftnl_rule_set(r, NFTNL_RULE_TABLE, (char *)table); 1366 nftnl_rule_set(r, NFTNL_RULE_CHAIN, (char *)chain); 1367 1368 if (batch_rule_add(h, NFT_COMPAT_RULE_FLUSH, r) < 0) 1369 nftnl_rule_free(r); 1370 } 1371 1372 int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table) 1373 { 1374 int ret; 1375 struct nftnl_chain_list *list; 1376 struct nftnl_chain_list_iter *iter; 1377 struct nftnl_chain *c; 1378 1379 nft_fn = nft_rule_flush; 1380 1381 list = nftnl_chain_list_get(h); 1382 if (list == NULL) { 1383 ret = 0; 1384 goto err; 1385 } 1386 1387 iter = nftnl_chain_list_iter_create(list); 1388 if (iter == NULL) 1389 goto err; 1390 1391 c = nftnl_chain_list_iter_next(iter); 1392 while (c != NULL) { 1393 const char *table_name = 1394 nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE); 1395 const char *chain_name = 1396 nftnl_chain_get_str(c, NFTNL_CHAIN_NAME); 1397 1398 if (strcmp(table, table_name) != 0) 1399 goto next; 1400 1401 if (chain != NULL && strcmp(chain, chain_name) != 0) 1402 goto next; 1403 1404 __nft_rule_flush(h, table_name, chain_name); 1405 1406 if (chain != NULL) 1407 break; 1408 next: 1409 c = nftnl_chain_list_iter_next(iter); 1410 } 1411 1412 nftnl_chain_list_iter_destroy(iter); 1413 flush_rule_cache(h); 1414 err: 1415 nftnl_chain_list_free(list); 1416 1417 /* the core expects 1 for success and 0 for error */ 1418 return ret == 0 ? 1 : 0; 1419 } 1420 1421 int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *table) 1422 { 1423 struct nftnl_chain *c; 1424 int ret; 1425 1426 nft_fn = nft_chain_user_add; 1427 1428 /* If built-in chains don't exist for this table, create them */ 1429 if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0) 1430 nft_xt_builtin_init(h, table); 1431 1432 c = nftnl_chain_alloc(); 1433 if (c == NULL) 1434 return 0; 1435 1436 nftnl_chain_set(c, NFTNL_CHAIN_TABLE, (char *)table); 1437 nftnl_chain_set(c, NFTNL_CHAIN_NAME, (char *)chain); 1438 1439 if (h->batch_support) { 1440 ret = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_ADD, c); 1441 } else { 1442 char buf[MNL_SOCKET_BUFFER_SIZE]; 1443 struct nlmsghdr *nlh; 1444 1445 nlh = nftnl_chain_nlmsg_build_hdr(buf, NFT_MSG_NEWCHAIN, 1446 h->family, 1447 NLM_F_ACK|NLM_F_EXCL, h->seq); 1448 nftnl_chain_nlmsg_build_payload(nlh, c); 1449 nftnl_chain_free(c); 1450 ret = mnl_talk(h, nlh, NULL, NULL); 1451 } 1452 1453 /* the core expects 1 for success and 0 for error */ 1454 return ret == 0 ? 1 : 0; 1455 } 1456 1457 static int __nft_chain_del(struct nft_handle *h, struct nftnl_chain *c) 1458 { 1459 char buf[MNL_SOCKET_BUFFER_SIZE]; 1460 struct nlmsghdr *nlh; 1461 1462 nlh = nftnl_chain_nlmsg_build_hdr(buf, NFT_MSG_DELCHAIN, h->family, 1463 NLM_F_ACK, h->seq); 1464 nftnl_chain_nlmsg_build_payload(nlh, c); 1465 1466 return mnl_talk(h, nlh, NULL, NULL); 1467 } 1468 1469 int nft_chain_user_del(struct nft_handle *h, const char *chain, const char *table) 1470 { 1471 struct nftnl_chain_list *list; 1472 struct nftnl_chain_list_iter *iter; 1473 struct nftnl_chain *c; 1474 int ret = 0; 1475 int deleted_ctr = 0; 1476 1477 list = nftnl_chain_list_get(h); 1478 if (list == NULL) 1479 goto err; 1480 1481 iter = nftnl_chain_list_iter_create(list); 1482 if (iter == NULL) 1483 goto err; 1484 1485 c = nftnl_chain_list_iter_next(iter); 1486 while (c != NULL) { 1487 const char *table_name = 1488 nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE); 1489 const char *chain_name = 1490 nftnl_chain_get_str(c, NFTNL_CHAIN_NAME); 1491 1492 /* don't delete built-in chain */ 1493 if (nft_chain_builtin(c)) 1494 goto next; 1495 1496 if (strcmp(table, table_name) != 0) 1497 goto next; 1498 1499 if (chain != NULL && strcmp(chain, chain_name) != 0) 1500 goto next; 1501 1502 if (h->batch_support) 1503 ret = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_DEL, c); 1504 else 1505 ret = __nft_chain_del(h, c); 1506 1507 if (ret < 0) 1508 break; 1509 1510 deleted_ctr++; 1511 1512 if (chain != NULL) 1513 break; 1514 next: 1515 c = nftnl_chain_list_iter_next(iter); 1516 } 1517 1518 nftnl_chain_list_iter_destroy(iter); 1519 err: 1520 if (!h->batch_support) 1521 nftnl_chain_list_free(list); 1522 1523 /* chain not found */ 1524 if (deleted_ctr == 0) { 1525 ret = -1; 1526 errno = ENOENT; 1527 } 1528 1529 /* the core expects 1 for success and 0 for error */ 1530 return ret == 0 ? 1 : 0; 1531 } 1532 1533 struct nftnl_chain * 1534 nft_chain_list_find(struct nftnl_chain_list *list, 1535 const char *table, const char *chain) 1536 { 1537 struct nftnl_chain_list_iter *iter; 1538 struct nftnl_chain *c; 1539 1540 iter = nftnl_chain_list_iter_create(list); 1541 if (iter == NULL) 1542 return NULL; 1543 1544 c = nftnl_chain_list_iter_next(iter); 1545 while (c != NULL) { 1546 const char *table_name = 1547 nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE); 1548 const char *chain_name = 1549 nftnl_chain_get_str(c, NFTNL_CHAIN_NAME); 1550 1551 if (strcmp(table, table_name) != 0) 1552 goto next; 1553 1554 if (strcmp(chain, chain_name) != 0) 1555 goto next; 1556 1557 nftnl_chain_list_iter_destroy(iter); 1558 return c; 1559 next: 1560 c = nftnl_chain_list_iter_next(iter); 1561 } 1562 nftnl_chain_list_iter_destroy(iter); 1563 return NULL; 1564 } 1565 1566 static struct nftnl_chain * 1567 nft_chain_find(struct nft_handle *h, const char *table, const char *chain) 1568 { 1569 struct nftnl_chain_list *list; 1570 1571 list = nftnl_chain_list_get(h); 1572 if (list == NULL) 1573 return NULL; 1574 1575 return nft_chain_list_find(list, table, chain); 1576 } 1577 1578 int nft_chain_user_rename(struct nft_handle *h,const char *chain, 1579 const char *table, const char *newname) 1580 { 1581 struct nftnl_chain *c; 1582 uint64_t handle; 1583 int ret; 1584 1585 nft_fn = nft_chain_user_add; 1586 1587 /* If built-in chains don't exist for this table, create them */ 1588 if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0) 1589 nft_xt_builtin_init(h, table); 1590 1591 /* Config load changed errno. Ensure genuine info for our callers. */ 1592 errno = 0; 1593 1594 /* Find the old chain to be renamed */ 1595 c = nft_chain_find(h, table, chain); 1596 if (c == NULL) { 1597 errno = ENOENT; 1598 return -1; 1599 } 1600 handle = nftnl_chain_get_u64(c, NFTNL_CHAIN_HANDLE); 1601 1602 /* Now prepare the new name for the chain */ 1603 c = nftnl_chain_alloc(); 1604 if (c == NULL) 1605 return -1; 1606 1607 nftnl_chain_set(c, NFTNL_CHAIN_TABLE, (char *)table); 1608 nftnl_chain_set(c, NFTNL_CHAIN_NAME, (char *)newname); 1609 nftnl_chain_set_u64(c, NFTNL_CHAIN_HANDLE, handle); 1610 1611 if (h->batch_support) { 1612 ret = batch_chain_add(h, NFT_COMPAT_CHAIN_RENAME, c); 1613 } else { 1614 char buf[MNL_SOCKET_BUFFER_SIZE]; 1615 struct nlmsghdr *nlh; 1616 1617 nlh = nftnl_chain_nlmsg_build_hdr(buf, NFT_MSG_NEWCHAIN, 1618 h->family, NLM_F_ACK, h->seq); 1619 nftnl_chain_nlmsg_build_payload(nlh, c); 1620 nftnl_chain_free(c); 1621 1622 ret = mnl_talk(h, nlh, NULL, NULL); 1623 } 1624 1625 /* the core expects 1 for success and 0 for error */ 1626 return ret == 0 ? 1 : 0; 1627 } 1628 1629 static int nftnl_table_list_cb(const struct nlmsghdr *nlh, void *data) 1630 { 1631 struct nftnl_table *t; 1632 struct nftnl_table_list *list = data; 1633 1634 t = nftnl_table_alloc(); 1635 if (t == NULL) 1636 goto err; 1637 1638 if (nftnl_table_nlmsg_parse(nlh, t) < 0) 1639 goto out; 1640 1641 nftnl_table_list_add_tail(t, list); 1642 1643 return MNL_CB_OK; 1644 out: 1645 nftnl_table_free(t); 1646 err: 1647 return MNL_CB_OK; 1648 } 1649 1650 static struct nftnl_table_list *nftnl_table_list_get(struct nft_handle *h) 1651 { 1652 char buf[MNL_SOCKET_BUFFER_SIZE]; 1653 struct nlmsghdr *nlh; 1654 struct nftnl_table_list *list; 1655 1656 list = nftnl_table_list_alloc(); 1657 if (list == NULL) 1658 return 0; 1659 1660 nlh = nftnl_rule_nlmsg_build_hdr(buf, NFT_MSG_GETTABLE, h->family, 1661 NLM_F_DUMP, h->seq); 1662 1663 mnl_talk(h, nlh, nftnl_table_list_cb, list); 1664 1665 return list; 1666 } 1667 1668 bool nft_table_find(struct nft_handle *h, const char *tablename) 1669 { 1670 struct nftnl_table_list *list; 1671 struct nftnl_table_list_iter *iter; 1672 struct nftnl_table *t; 1673 bool ret = false; 1674 1675 list = nftnl_table_list_get(h); 1676 if (list == NULL) 1677 goto err; 1678 1679 iter = nftnl_table_list_iter_create(list); 1680 if (iter == NULL) 1681 goto err; 1682 1683 t = nftnl_table_list_iter_next(iter); 1684 while (t != NULL) { 1685 const char *this_tablename = 1686 nftnl_table_get(t, NFTNL_TABLE_NAME); 1687 1688 if (strcmp(tablename, this_tablename) == 0) 1689 return true; 1690 1691 t = nftnl_table_list_iter_next(iter); 1692 } 1693 1694 nftnl_table_list_free(list); 1695 1696 err: 1697 return ret; 1698 } 1699 1700 int nft_for_each_table(struct nft_handle *h, 1701 int (*func)(struct nft_handle *h, const char *tablename, bool counters), 1702 bool counters) 1703 { 1704 int ret = 1; 1705 struct nftnl_table_list *list; 1706 struct nftnl_table_list_iter *iter; 1707 struct nftnl_table *t; 1708 1709 list = nftnl_table_list_get(h); 1710 if (list == NULL) { 1711 ret = 0; 1712 goto err; 1713 } 1714 1715 iter = nftnl_table_list_iter_create(list); 1716 if (iter == NULL) 1717 return 0; 1718 1719 t = nftnl_table_list_iter_next(iter); 1720 while (t != NULL) { 1721 const char *tablename = 1722 nftnl_table_get(t, NFTNL_TABLE_NAME); 1723 1724 func(h, tablename, counters); 1725 1726 t = nftnl_table_list_iter_next(iter); 1727 } 1728 1729 nftnl_table_list_free(list); 1730 1731 err: 1732 /* the core expects 1 for success and 0 for error */ 1733 return ret == 0 ? 1 : 0; 1734 } 1735 1736 int nft_table_purge_chains(struct nft_handle *h, const char *this_table, 1737 struct nftnl_chain_list *chain_list) 1738 { 1739 struct nftnl_chain_list_iter *iter; 1740 struct nftnl_chain *chain_obj; 1741 1742 iter = nftnl_chain_list_iter_create(chain_list); 1743 if (iter == NULL) 1744 return 0; 1745 1746 chain_obj = nftnl_chain_list_iter_next(iter); 1747 while (chain_obj != NULL) { 1748 const char *table = 1749 nftnl_chain_get_str(chain_obj, NFTNL_CHAIN_TABLE); 1750 1751 if (strcmp(this_table, table) != 0) 1752 goto next; 1753 1754 if (nft_chain_builtin(chain_obj)) 1755 goto next; 1756 1757 if ( __nft_chain_del(h, chain_obj) < 0) { 1758 if (errno != EBUSY) 1759 return -1; 1760 } 1761 next: 1762 chain_obj = nftnl_chain_list_iter_next(iter); 1763 } 1764 nftnl_chain_list_iter_destroy(iter); 1765 1766 return 0; 1767 } 1768 1769 static int __nft_rule_del(struct nft_handle *h, struct nftnl_rule_list *list, 1770 struct nftnl_rule *r) 1771 { 1772 int ret; 1773 1774 nftnl_rule_list_del(r); 1775 1776 ret = batch_rule_add(h, NFT_COMPAT_RULE_DELETE, r); 1777 if (ret < 0) { 1778 nftnl_rule_free(r); 1779 return -1; 1780 } 1781 return 1; 1782 } 1783 1784 static struct nftnl_rule * 1785 nft_rule_find(struct nft_handle *h, struct nftnl_rule_list *list, 1786 const char *chain, const char *table, void *data, int rulenum) 1787 { 1788 struct nftnl_rule *r; 1789 struct nftnl_rule_list_iter *iter; 1790 int rule_ctr = 0; 1791 bool found = false; 1792 1793 iter = nftnl_rule_list_iter_create(list); 1794 if (iter == NULL) 1795 return 0; 1796 1797 r = nftnl_rule_list_iter_next(iter); 1798 while (r != NULL) { 1799 const char *rule_table = 1800 nftnl_rule_get_str(r, NFTNL_RULE_TABLE); 1801 const char *rule_chain = 1802 nftnl_rule_get_str(r, NFTNL_RULE_CHAIN); 1803 1804 if (strcmp(table, rule_table) != 0 || 1805 strcmp(chain, rule_chain) != 0) { 1806 DEBUGP("different chain / table\n"); 1807 goto next; 1808 } 1809 1810 if (rulenum >= 0) { 1811 /* Delete by rule number case */ 1812 if (rule_ctr == rulenum) { 1813 found = true; 1814 break; 1815 } 1816 } else { 1817 found = h->ops->rule_find(h->ops, r, data); 1818 if (found) 1819 break; 1820 } 1821 rule_ctr++; 1822 next: 1823 r = nftnl_rule_list_iter_next(iter); 1824 } 1825 1826 nftnl_rule_list_iter_destroy(iter); 1827 1828 return found ? r : NULL; 1829 } 1830 1831 int nft_rule_check(struct nft_handle *h, const char *chain, 1832 const char *table, void *data, bool verbose) 1833 { 1834 struct nftnl_rule_list *list; 1835 int ret; 1836 1837 nft_fn = nft_rule_check; 1838 1839 list = nft_rule_list_get(h); 1840 if (list == NULL) 1841 return 0; 1842 1843 ret = nft_rule_find(h, list, chain, table, data, -1) ? 1 : 0; 1844 if (ret == 0) 1845 errno = ENOENT; 1846 1847 return ret; 1848 } 1849 1850 int nft_rule_delete(struct nft_handle *h, const char *chain, 1851 const char *table, void *data, bool verbose) 1852 { 1853 int ret = 0; 1854 struct nftnl_rule *r; 1855 struct nftnl_rule_list *list; 1856 1857 nft_fn = nft_rule_delete; 1858 1859 list = nft_rule_list_get(h); 1860 if (list == NULL) 1861 return 0; 1862 1863 r = nft_rule_find(h, list, chain, table, data, -1); 1864 if (r != NULL) { 1865 ret =__nft_rule_del(h, list, r); 1866 if (ret < 0) 1867 errno = ENOMEM; 1868 } else 1869 errno = ENOENT; 1870 1871 flush_rule_cache(h); 1872 1873 return ret; 1874 } 1875 1876 static int 1877 nft_rule_add(struct nft_handle *h, const char *chain, 1878 const char *table, struct iptables_command_state *cs, 1879 uint64_t handle, bool verbose) 1880 { 1881 struct nftnl_rule *r; 1882 1883 r = nft_rule_new(h, chain, table, cs); 1884 if (r == NULL) 1885 return 0; 1886 1887 if (handle > 0) 1888 nftnl_rule_set_u64(r, NFTNL_RULE_POSITION, handle); 1889 1890 if (batch_rule_add(h, NFT_COMPAT_RULE_INSERT, r) < 0) { 1891 nftnl_rule_free(r); 1892 return 0; 1893 } 1894 1895 flush_rule_cache(h); 1896 return 1; 1897 } 1898 1899 int nft_rule_insert(struct nft_handle *h, const char *chain, 1900 const char *table, void *data, int rulenum, bool verbose) 1901 { 1902 struct nftnl_rule_list *list; 1903 struct nftnl_rule *r; 1904 uint64_t handle = 0; 1905 1906 /* If built-in chains don't exist for this table, create them */ 1907 if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0) 1908 nft_xt_builtin_init(h, table); 1909 1910 nft_fn = nft_rule_insert; 1911 1912 if (rulenum > 0) { 1913 list = nft_rule_list_get(h); 1914 if (list == NULL) 1915 goto err; 1916 1917 r = nft_rule_find(h, list, chain, table, data, rulenum); 1918 if (r == NULL) { 1919 /* special case: iptables allows to insert into 1920 * rule_count + 1 position. 1921 */ 1922 r = nft_rule_find(h, list, chain, table, data, 1923 rulenum - 1); 1924 if (r != NULL) { 1925 flush_rule_cache(h); 1926 return nft_rule_append(h, chain, table, data, 1927 0, verbose); 1928 } 1929 1930 errno = ENOENT; 1931 goto err; 1932 } 1933 1934 handle = nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE); 1935 DEBUGP("adding after rule handle %"PRIu64"\n", handle); 1936 1937 flush_rule_cache(h); 1938 } 1939 1940 return nft_rule_add(h, chain, table, data, handle, verbose); 1941 err: 1942 flush_rule_cache(h); 1943 return 0; 1944 } 1945 1946 int nft_rule_delete_num(struct nft_handle *h, const char *chain, 1947 const char *table, int rulenum, bool verbose) 1948 { 1949 int ret = 0; 1950 struct nftnl_rule *r; 1951 struct nftnl_rule_list *list; 1952 1953 nft_fn = nft_rule_delete_num; 1954 1955 list = nft_rule_list_get(h); 1956 if (list == NULL) 1957 return 0; 1958 1959 r = nft_rule_find(h, list, chain, table, NULL, rulenum); 1960 if (r != NULL) { 1961 ret = 1; 1962 1963 DEBUGP("deleting rule by number %d\n", rulenum); 1964 ret = __nft_rule_del(h, list, r); 1965 if (ret < 0) 1966 errno = ENOMEM; 1967 } else 1968 errno = ENOENT; 1969 1970 flush_rule_cache(h); 1971 1972 return ret; 1973 } 1974 1975 int nft_rule_replace(struct nft_handle *h, const char *chain, 1976 const char *table, void *data, int rulenum, bool verbose) 1977 { 1978 int ret = 0; 1979 struct nftnl_rule *r; 1980 struct nftnl_rule_list *list; 1981 1982 nft_fn = nft_rule_replace; 1983 1984 list = nft_rule_list_get(h); 1985 if (list == NULL) 1986 return 0; 1987 1988 r = nft_rule_find(h, list, chain, table, data, rulenum); 1989 if (r != NULL) { 1990 DEBUGP("replacing rule with handle=%llu\n", 1991 (unsigned long long) 1992 nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE)); 1993 1994 ret = nft_rule_append(h, chain, table, data, 1995 nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE), 1996 verbose); 1997 } else 1998 errno = ENOENT; 1999 2000 flush_rule_cache(h); 2001 2002 return ret; 2003 } 2004 2005 static int 2006 __nft_rule_list(struct nft_handle *h, const char *chain, const char *table, 2007 int rulenum, unsigned int format, 2008 void (*cb)(struct nftnl_rule *r, unsigned int num, 2009 unsigned int format)) 2010 { 2011 struct nftnl_rule_list *list; 2012 struct nftnl_rule_list_iter *iter; 2013 struct nftnl_rule *r; 2014 int rule_ctr = 0, ret = 0; 2015 2016 list = nft_rule_list_get(h); 2017 if (list == NULL) 2018 return 0; 2019 2020 iter = nftnl_rule_list_iter_create(list); 2021 if (iter == NULL) 2022 goto err; 2023 2024 r = nftnl_rule_list_iter_next(iter); 2025 while (r != NULL) { 2026 const char *rule_table = 2027 nftnl_rule_get_str(r, NFTNL_RULE_TABLE); 2028 const char *rule_chain = 2029 nftnl_rule_get_str(r, NFTNL_RULE_CHAIN); 2030 2031 if (strcmp(table, rule_table) != 0 || 2032 strcmp(chain, rule_chain) != 0) 2033 goto next; 2034 2035 rule_ctr++; 2036 2037 if (rulenum > 0 && rule_ctr != rulenum) { 2038 /* List by rule number case */ 2039 goto next; 2040 } 2041 2042 cb(r, rule_ctr, format); 2043 if (rulenum > 0 && rule_ctr == rulenum) { 2044 ret = 1; 2045 break; 2046 } 2047 2048 next: 2049 r = nftnl_rule_list_iter_next(iter); 2050 } 2051 2052 nftnl_rule_list_iter_destroy(iter); 2053 err: 2054 if (ret == 0) 2055 errno = ENOENT; 2056 2057 return ret; 2058 } 2059 2060 int nft_rule_list(struct nft_handle *h, const char *chain, const char *table, 2061 int rulenum, unsigned int format) 2062 { 2063 const struct nft_family_ops *ops; 2064 struct nftnl_chain_list *list; 2065 struct nftnl_chain_list_iter *iter; 2066 struct nftnl_chain *c; 2067 bool found = false; 2068 2069 /* If built-in chains don't exist for this table, create them */ 2070 if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0) { 2071 nft_xt_builtin_init(h, table); 2072 /* Force table and chain creation, otherwise first iptables -L 2073 * lists no table/chains. 2074 */ 2075 if (!list_empty(&h->obj_list)) 2076 nft_commit(h); 2077 } 2078 2079 ops = nft_family_ops_lookup(h->family); 2080 2081 if (chain && rulenum) { 2082 __nft_rule_list(h, chain, table, 2083 rulenum, format, ops->print_firewall); 2084 return 1; 2085 } 2086 2087 list = nft_chain_dump(h); 2088 2089 iter = nftnl_chain_list_iter_create(list); 2090 if (iter == NULL) 2091 goto err; 2092 2093 if (ops->print_table_header) 2094 ops->print_table_header(table); 2095 2096 c = nftnl_chain_list_iter_next(iter); 2097 while (c != NULL) { 2098 const char *chain_table = 2099 nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE); 2100 const char *chain_name = 2101 nftnl_chain_get_str(c, NFTNL_CHAIN_NAME); 2102 uint32_t policy = 2103 nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY); 2104 uint32_t refs = 2105 nftnl_chain_get_u32(c, NFTNL_CHAIN_USE); 2106 struct xt_counters ctrs = { 2107 .pcnt = nftnl_chain_get_u64(c, NFTNL_CHAIN_PACKETS), 2108 .bcnt = nftnl_chain_get_u64(c, NFTNL_CHAIN_BYTES), 2109 }; 2110 bool basechain = false; 2111 2112 if (nftnl_chain_get(c, NFTNL_CHAIN_HOOKNUM)) 2113 basechain = true; 2114 2115 if (strcmp(table, chain_table) != 0) 2116 goto next; 2117 if (chain && strcmp(chain, chain_name) != 0) 2118 goto next; 2119 2120 if (found) 2121 printf("\n"); 2122 2123 ops->print_header(format, chain_name, policy_name[policy], 2124 &ctrs, basechain, refs); 2125 2126 __nft_rule_list(h, chain_name, table, 2127 rulenum, format, ops->print_firewall); 2128 2129 /* we printed the chain we wanted, stop processing. */ 2130 if (chain) 2131 break; 2132 2133 found = true; 2134 2135 next: 2136 c = nftnl_chain_list_iter_next(iter); 2137 } 2138 2139 nftnl_chain_list_iter_destroy(iter); 2140 err: 2141 nftnl_chain_list_free(list); 2142 2143 return 1; 2144 } 2145 2146 static void 2147 list_save(struct nftnl_rule *r, unsigned int num, unsigned int format) 2148 { 2149 struct iptables_command_state cs = {}; 2150 2151 nft_rule_to_iptables_command_state(r, &cs); 2152 2153 nft_rule_print_save(&cs, r, NFT_RULE_APPEND, !(format & FMT_NOCOUNTS)); 2154 } 2155 2156 static int 2157 nftnl_rule_list_chain_save(struct nft_handle *h, const char *chain, 2158 const char *table, struct nftnl_chain_list *list, 2159 int counters) 2160 { 2161 struct nftnl_chain_list_iter *iter; 2162 struct nftnl_chain *c; 2163 2164 iter = nftnl_chain_list_iter_create(list); 2165 if (iter == NULL) 2166 return 0; 2167 2168 c = nftnl_chain_list_iter_next(iter); 2169 while (c != NULL) { 2170 const char *chain_table = 2171 nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE); 2172 const char *chain_name = 2173 nftnl_chain_get_str(c, NFTNL_CHAIN_NAME); 2174 uint32_t policy = 2175 nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY); 2176 2177 if (strcmp(table, chain_table) != 0 || 2178 (chain && strcmp(chain, chain_name) != 0)) 2179 goto next; 2180 2181 /* this is a base chain */ 2182 if (nft_chain_builtin(c)) { 2183 printf("-P %s %s", chain_name, policy_name[policy]); 2184 2185 if (counters) { 2186 printf(" -c %"PRIu64" %"PRIu64"\n", 2187 nftnl_chain_get_u64(c, NFTNL_CHAIN_PACKETS), 2188 nftnl_chain_get_u64(c, NFTNL_CHAIN_BYTES)); 2189 } else 2190 printf("\n"); 2191 } else { 2192 printf("-N %s\n", chain_name); 2193 } 2194 next: 2195 c = nftnl_chain_list_iter_next(iter); 2196 } 2197 2198 nftnl_chain_list_iter_destroy(iter); 2199 2200 return 1; 2201 } 2202 2203 int nft_rule_list_save(struct nft_handle *h, const char *chain, 2204 const char *table, int rulenum, int counters) 2205 { 2206 struct nftnl_chain_list *list; 2207 struct nftnl_chain_list_iter *iter; 2208 struct nftnl_chain *c; 2209 int ret = 1; 2210 2211 list = nft_chain_dump(h); 2212 2213 /* Dump policies and custom chains first */ 2214 if (!rulenum) 2215 nftnl_rule_list_chain_save(h, chain, table, list, counters); 2216 2217 /* Now dump out rules in this table */ 2218 iter = nftnl_chain_list_iter_create(list); 2219 if (iter == NULL) 2220 goto err; 2221 2222 c = nftnl_chain_list_iter_next(iter); 2223 while (c != NULL) { 2224 const char *chain_table = 2225 nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE); 2226 const char *chain_name = 2227 nftnl_chain_get_str(c, NFTNL_CHAIN_NAME); 2228 2229 if (strcmp(table, chain_table) != 0) 2230 goto next; 2231 if (chain && strcmp(chain, chain_name) != 0) 2232 goto next; 2233 2234 ret = __nft_rule_list(h, chain_name, table, rulenum, 2235 counters ? 0 : FMT_NOCOUNTS, list_save); 2236 2237 /* we printed the chain we wanted, stop processing. */ 2238 if (chain) 2239 break; 2240 next: 2241 c = nftnl_chain_list_iter_next(iter); 2242 } 2243 2244 nftnl_chain_list_iter_destroy(iter); 2245 err: 2246 nftnl_chain_list_free(list); 2247 2248 return ret; 2249 } 2250 2251 int nft_rule_zero_counters(struct nft_handle *h, const char *chain, 2252 const char *table, int rulenum) 2253 { 2254 struct iptables_command_state cs = {}; 2255 struct nftnl_rule_list *list; 2256 struct nftnl_rule *r; 2257 int ret = 0; 2258 2259 nft_fn = nft_rule_delete; 2260 2261 list = nft_rule_list_get(h); 2262 if (list == NULL) 2263 return 0; 2264 2265 r = nft_rule_find(h, list, chain, table, NULL, rulenum); 2266 if (r == NULL) { 2267 errno = ENOENT; 2268 ret = 1; 2269 goto error; 2270 } 2271 2272 nft_rule_to_iptables_command_state(r, &cs); 2273 2274 cs.counters.pcnt = cs.counters.bcnt = 0; 2275 2276 ret = nft_rule_append(h, chain, table, &cs, 2277 nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE), 2278 false); 2279 2280 error: 2281 flush_rule_cache(h); 2282 2283 return ret; 2284 } 2285 2286 static void nft_compat_table_batch_add(struct nft_handle *h, uint16_t type, 2287 uint16_t flags, uint32_t seq, 2288 struct nftnl_table *table) 2289 { 2290 struct nlmsghdr *nlh; 2291 2292 nlh = nftnl_table_nlmsg_build_hdr(mnl_nlmsg_batch_current(h->batch), 2293 type, h->family, flags, seq); 2294 nftnl_table_nlmsg_build_payload(nlh, table); 2295 nftnl_table_free(table); 2296 } 2297 2298 static void nft_compat_chain_batch_add(struct nft_handle *h, uint16_t type, 2299 uint16_t flags, uint32_t seq, 2300 struct nftnl_chain *chain) 2301 { 2302 struct nlmsghdr *nlh; 2303 2304 nlh = nftnl_chain_nlmsg_build_hdr(mnl_nlmsg_batch_current(h->batch), 2305 type, h->family, flags, seq); 2306 nftnl_chain_nlmsg_build_payload(nlh, chain); 2307 nft_chain_print_debug(chain, nlh); 2308 nftnl_chain_free(chain); 2309 } 2310 2311 static void nft_compat_rule_batch_add(struct nft_handle *h, uint16_t type, 2312 uint16_t flags, uint32_t seq, 2313 struct nftnl_rule *rule) 2314 { 2315 struct nlmsghdr *nlh; 2316 2317 nlh = nftnl_rule_nlmsg_build_hdr(mnl_nlmsg_batch_current(h->batch), 2318 type, h->family, flags, seq); 2319 nftnl_rule_nlmsg_build_payload(nlh, rule); 2320 nft_rule_print_debug(rule, nlh); 2321 nftnl_rule_free(rule); 2322 } 2323 2324 static int nft_action(struct nft_handle *h, int action) 2325 { 2326 struct obj_update *n, *tmp; 2327 uint32_t seq = 1; 2328 int ret = 0; 2329 2330 mnl_nftnl_batch_begin(h->batch, seq++); 2331 2332 list_for_each_entry_safe(n, tmp, &h->obj_list, head) { 2333 switch (n->type) { 2334 case NFT_COMPAT_TABLE_ADD: 2335 nft_compat_table_batch_add(h, NFT_MSG_NEWTABLE, 2336 NLM_F_CREATE, seq++, 2337 n->table); 2338 break; 2339 case NFT_COMPAT_CHAIN_ADD: 2340 nft_compat_chain_batch_add(h, NFT_MSG_NEWCHAIN, 2341 NLM_F_CREATE, seq++, 2342 n->chain); 2343 break; 2344 case NFT_COMPAT_CHAIN_USER_ADD: 2345 nft_compat_chain_batch_add(h, NFT_MSG_NEWCHAIN, 2346 NLM_F_EXCL, seq++, 2347 n->chain); 2348 break; 2349 case NFT_COMPAT_CHAIN_USER_DEL: 2350 nft_compat_chain_batch_add(h, NFT_MSG_DELCHAIN, 2351 0, seq++, n->chain); 2352 break; 2353 case NFT_COMPAT_CHAIN_UPDATE: 2354 nft_compat_chain_batch_add(h, NFT_MSG_NEWCHAIN, 2355 h->restore ? 2356 NLM_F_CREATE : 0, 2357 seq++, n->chain); 2358 break; 2359 case NFT_COMPAT_CHAIN_RENAME: 2360 nft_compat_chain_batch_add(h, NFT_MSG_NEWCHAIN, 0, 2361 seq++, n->chain); 2362 break; 2363 case NFT_COMPAT_RULE_APPEND: 2364 nft_compat_rule_batch_add(h, NFT_MSG_NEWRULE, 2365 NLM_F_CREATE | NLM_F_APPEND, 2366 seq++, n->rule); 2367 break; 2368 case NFT_COMPAT_RULE_INSERT: 2369 nft_compat_rule_batch_add(h, NFT_MSG_NEWRULE, 2370 NLM_F_CREATE, seq++, 2371 n->rule); 2372 break; 2373 case NFT_COMPAT_RULE_REPLACE: 2374 nft_compat_rule_batch_add(h, NFT_MSG_NEWRULE, 2375 NLM_F_CREATE | NLM_F_REPLACE, 2376 seq++, n->rule); 2377 break; 2378 case NFT_COMPAT_RULE_DELETE: 2379 case NFT_COMPAT_RULE_FLUSH: 2380 nft_compat_rule_batch_add(h, NFT_MSG_DELRULE, 0, 2381 seq++, n->rule); 2382 break; 2383 } 2384 2385 h->obj_list_num--; 2386 list_del(&n->head); 2387 free(n); 2388 2389 if (!mnl_nlmsg_batch_next(h->batch)) 2390 h->batch = mnl_nftnl_batch_page_add(h->batch); 2391 } 2392 2393 switch (action) { 2394 case NFT_COMPAT_COMMIT: 2395 mnl_nftnl_batch_end(h->batch, seq++); 2396 break; 2397 case NFT_COMPAT_ABORT: 2398 break; 2399 } 2400 2401 if (!mnl_nlmsg_batch_is_empty(h->batch)) 2402 h->batch = mnl_nftnl_batch_page_add(h->batch); 2403 2404 ret = mnl_nftnl_batch_talk(h); 2405 2406 mnl_nlmsg_batch_reset(h->batch); 2407 2408 return ret == 0 ? 1 : 0; 2409 } 2410 2411 int nft_commit(struct nft_handle *h) 2412 { 2413 return nft_action(h, NFT_COMPAT_COMMIT); 2414 } 2415 2416 int nft_abort(struct nft_handle *h) 2417 { 2418 return nft_action(h, NFT_COMPAT_ABORT); 2419 } 2420 2421 int nft_compatible_revision(const char *name, uint8_t rev, int opt) 2422 { 2423 struct mnl_socket *nl; 2424 char buf[MNL_SOCKET_BUFFER_SIZE]; 2425 struct nlmsghdr *nlh; 2426 uint32_t portid, seq, type; 2427 int ret = 0; 2428 2429 if (opt == IPT_SO_GET_REVISION_MATCH || 2430 opt == IP6T_SO_GET_REVISION_MATCH) 2431 type = 0; 2432 else 2433 type = 1; 2434 2435 nlh = mnl_nlmsg_put_header(buf); 2436 nlh->nlmsg_type = (NFNL_SUBSYS_NFT_COMPAT << 8) | NFNL_MSG_COMPAT_GET; 2437 nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; 2438 nlh->nlmsg_seq = seq = time(NULL); 2439 2440 struct nfgenmsg *nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg)); 2441 nfg->nfgen_family = AF_INET; 2442 nfg->version = NFNETLINK_V0; 2443 nfg->res_id = 0; 2444 2445 mnl_attr_put_strz(nlh, NFTA_COMPAT_NAME, name); 2446 mnl_attr_put_u32(nlh, NFTA_COMPAT_REV, htonl(rev)); 2447 mnl_attr_put_u32(nlh, NFTA_COMPAT_TYPE, htonl(type)); 2448 2449 DEBUGP("requesting `%s' rev=%d type=%d via nft_compat\n", 2450 name, rev, type); 2451 2452 nl = mnl_socket_open(NETLINK_NETFILTER); 2453 if (nl == NULL) 2454 return 0; 2455 2456 if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) 2457 goto err; 2458 2459 portid = mnl_socket_get_portid(nl); 2460 2461 if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) 2462 goto err; 2463 2464 ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); 2465 if (ret == -1) 2466 goto err; 2467 2468 ret = mnl_cb_run(buf, ret, seq, portid, NULL, NULL); 2469 if (ret == -1) 2470 goto err; 2471 2472 err: 2473 mnl_socket_close(nl); 2474 2475 return ret < 0 ? 0 : 1; 2476 } 2477 2478 /* Translates errno numbers into more human-readable form than strerror. */ 2479 const char *nft_strerror(int err) 2480 { 2481 unsigned int i; 2482 static struct table_struct { 2483 void *fn; 2484 int err; 2485 const char *message; 2486 } table[] = 2487 { 2488 { nft_chain_user_del, ENOTEMPTY, "Chain is not empty" }, 2489 { nft_chain_user_del, EINVAL, "Can't delete built-in chain" }, 2490 { nft_chain_user_del, EBUSY, "Directory not empty" }, 2491 { nft_chain_user_del, EMLINK, 2492 "Can't delete chain with references left" }, 2493 { nft_chain_user_add, EEXIST, "Chain already exists" }, 2494 { nft_rule_add, E2BIG, "Index of insertion too big" }, 2495 { nft_rule_check, ENOENT, "Bad rule (does a matching rule exist in that chain?)" }, 2496 { nft_rule_replace, ENOENT, "Index of replacement too big" }, 2497 { nft_rule_delete_num, E2BIG, "Index of deletion too big" }, 2498 /* { TC_READ_COUNTER, E2BIG, "Index of counter too big" }, 2499 { TC_ZERO_COUNTER, E2BIG, "Index of counter too big" }, */ 2500 { nft_rule_add, ELOOP, "Loop found in table" }, 2501 { nft_rule_add, EINVAL, "Target problem" }, 2502 /* ENOENT for DELETE probably means no matching rule */ 2503 { nft_rule_delete, ENOENT, 2504 "Bad rule (does a matching rule exist in that chain?)" }, 2505 { nft_chain_set, ENOENT, "Bad built-in chain name" }, 2506 { nft_chain_set, EINVAL, "Bad policy name" }, 2507 { NULL, EPERM, "Permission denied (you must be root)" }, 2508 { NULL, 0, "Incompatible with this kernel" }, 2509 { NULL, ENOPROTOOPT, "iptables who? (do you need to insmod?)" }, 2510 { NULL, ENOSYS, "Will be implemented real soon. I promise ;)" }, 2511 { NULL, ENOMEM, "Memory allocation problem" }, 2512 { NULL, ENOENT, "No chain/target/match by that name" }, 2513 }; 2514 2515 for (i = 0; i < sizeof(table)/sizeof(struct table_struct); i++) { 2516 if ((!table[i].fn || table[i].fn == nft_fn) 2517 && table[i].err == err) 2518 return table[i].message; 2519 } 2520 2521 return strerror(err); 2522 } 2523 2524 static void xtables_config_perror(uint32_t flags, const char *fmt, ...) 2525 { 2526 va_list args; 2527 2528 va_start(args, fmt); 2529 2530 if (flags & NFT_LOAD_VERBOSE) 2531 vfprintf(stderr, fmt, args); 2532 2533 va_end(args); 2534 } 2535 2536 int nft_xtables_config_load(struct nft_handle *h, const char *filename, 2537 uint32_t flags) 2538 { 2539 struct nftnl_table_list *table_list = nftnl_table_list_alloc(); 2540 struct nftnl_chain_list *chain_list = nftnl_chain_list_alloc(); 2541 struct nftnl_table_list_iter *titer = NULL; 2542 struct nftnl_chain_list_iter *citer = NULL; 2543 struct nftnl_table *table; 2544 struct nftnl_chain *chain; 2545 uint32_t table_family, chain_family; 2546 bool found = false; 2547 2548 if (h->restore) 2549 return 0; 2550 2551 if (xtables_config_parse(filename, table_list, chain_list) < 0) { 2552 if (errno == ENOENT) { 2553 xtables_config_perror(flags, 2554 "configuration file `%s' does not exists\n", 2555 filename); 2556 } else { 2557 xtables_config_perror(flags, 2558 "Fatal error parsing config file: %s\n", 2559 strerror(errno)); 2560 } 2561 goto err; 2562 } 2563 2564 /* Stage 1) create tables */ 2565 titer = nftnl_table_list_iter_create(table_list); 2566 while ((table = nftnl_table_list_iter_next(titer)) != NULL) { 2567 table_family = nftnl_table_get_u32(table, 2568 NFTNL_TABLE_FAMILY); 2569 if (h->family != table_family) 2570 continue; 2571 2572 found = true; 2573 2574 if (batch_table_add(h, NFT_COMPAT_TABLE_ADD, table) < 0) { 2575 if (errno == EEXIST) { 2576 xtables_config_perror(flags, 2577 "table `%s' already exists, skipping\n", 2578 (char *)nftnl_table_get(table, NFTNL_TABLE_NAME)); 2579 } else { 2580 xtables_config_perror(flags, 2581 "table `%s' cannot be create, reason `%s'. Exitting\n", 2582 (char *)nftnl_table_get(table, NFTNL_TABLE_NAME), 2583 strerror(errno)); 2584 goto err; 2585 } 2586 continue; 2587 } 2588 xtables_config_perror(flags, "table `%s' has been created\n", 2589 (char *)nftnl_table_get(table, NFTNL_TABLE_NAME)); 2590 } 2591 nftnl_table_list_iter_destroy(titer); 2592 nftnl_table_list_free(table_list); 2593 2594 if (!found) 2595 goto err; 2596 2597 /* Stage 2) create chains */ 2598 citer = nftnl_chain_list_iter_create(chain_list); 2599 while ((chain = nftnl_chain_list_iter_next(citer)) != NULL) { 2600 chain_family = nftnl_chain_get_u32(chain, 2601 NFTNL_CHAIN_TABLE); 2602 if (h->family != chain_family) 2603 continue; 2604 2605 if (batch_chain_add(h, NFT_COMPAT_CHAIN_ADD, chain) < 0) { 2606 if (errno == EEXIST) { 2607 xtables_config_perror(flags, 2608 "chain `%s' already exists in table `%s', skipping\n", 2609 (char *)nftnl_chain_get(chain, NFTNL_CHAIN_NAME), 2610 (char *)nftnl_chain_get(chain, NFTNL_CHAIN_TABLE)); 2611 } else { 2612 xtables_config_perror(flags, 2613 "chain `%s' cannot be create, reason `%s'. Exitting\n", 2614 (char *)nftnl_chain_get(chain, NFTNL_CHAIN_NAME), 2615 strerror(errno)); 2616 goto err; 2617 } 2618 continue; 2619 } 2620 2621 xtables_config_perror(flags, 2622 "chain `%s' in table `%s' has been created\n", 2623 (char *)nftnl_chain_get(chain, NFTNL_CHAIN_NAME), 2624 (char *)nftnl_chain_get(chain, NFTNL_CHAIN_TABLE)); 2625 } 2626 nftnl_chain_list_iter_destroy(citer); 2627 nftnl_chain_list_free(chain_list); 2628 2629 return 0; 2630 2631 err: 2632 nftnl_table_list_free(table_list); 2633 nftnl_chain_list_free(chain_list); 2634 2635 if (titer != NULL) 2636 nftnl_table_list_iter_destroy(titer); 2637 if (citer != NULL) 2638 nftnl_chain_list_iter_destroy(citer); 2639 2640 return -1; 2641 } 2642 2643 int nft_chain_zero_counters(struct nft_handle *h, const char *chain, 2644 const char *table) 2645 { 2646 struct nftnl_chain_list *list; 2647 struct nftnl_chain_list_iter *iter; 2648 struct nftnl_chain *c; 2649 int ret = 0; 2650 2651 list = nftnl_chain_list_get(h); 2652 if (list == NULL) 2653 goto err; 2654 2655 iter = nftnl_chain_list_iter_create(list); 2656 if (iter == NULL) 2657 goto err; 2658 2659 c = nftnl_chain_list_iter_next(iter); 2660 while (c != NULL) { 2661 const char *chain_name = 2662 nftnl_chain_get(c, NFTNL_CHAIN_NAME); 2663 const char *chain_table = 2664 nftnl_chain_get(c, NFTNL_CHAIN_TABLE); 2665 2666 if (strcmp(table, chain_table) != 0) 2667 goto next; 2668 2669 if (chain != NULL && strcmp(chain, chain_name) != 0) 2670 goto next; 2671 2672 nftnl_chain_set_u64(c, NFTNL_CHAIN_PACKETS, 0); 2673 nftnl_chain_set_u64(c, NFTNL_CHAIN_BYTES, 0); 2674 2675 nftnl_chain_unset(c, NFTNL_CHAIN_HANDLE); 2676 2677 if (h->batch_support) { 2678 ret = batch_chain_add(h, NFT_COMPAT_CHAIN_ADD, c); 2679 } else { 2680 struct nlmsghdr *nlh; 2681 char buf[MNL_SOCKET_BUFFER_SIZE]; 2682 2683 nlh = nftnl_chain_nlmsg_build_hdr(buf, NFT_MSG_NEWCHAIN, 2684 h->family, NLM_F_ACK, 2685 h->seq); 2686 nftnl_chain_nlmsg_build_payload(nlh, c); 2687 ret = mnl_talk(h, nlh, NULL, NULL); 2688 } 2689 2690 if (chain != NULL) 2691 break; 2692 next: 2693 c = nftnl_chain_list_iter_next(iter); 2694 } 2695 2696 if (!h->batch_support) 2697 nftnl_chain_list_free(list); 2698 2699 nftnl_chain_list_iter_destroy(iter); 2700 2701 err: 2702 /* the core expects 1 for success and 0 for error */ 2703 return ret == 0 ? 1 : 0; 2704 } 2705 2706 uint32_t nft_invflags2cmp(uint32_t invflags, uint32_t flag) 2707 { 2708 if (invflags & flag) 2709 return NFT_CMP_NEQ; 2710 2711 return NFT_CMP_EQ; 2712 } 2713 2714 #define NFT_COMPAT_EXPR_MAX 8 2715 2716 static const char *supported_exprs[NFT_COMPAT_EXPR_MAX] = { 2717 "match", 2718 "target", 2719 "payload", 2720 "meta", 2721 "cmp", 2722 "bitwise", 2723 "counter", 2724 "immediate" 2725 }; 2726 2727 2728 static int nft_is_expr_compatible(const char *name) 2729 { 2730 int i; 2731 2732 for (i = 0; i < NFT_COMPAT_EXPR_MAX; i++) { 2733 if (strcmp(supported_exprs[i], name) == 0) 2734 return 0; 2735 } 2736 2737 return 1; 2738 } 2739 2740 static int nft_is_rule_compatible(struct nftnl_rule *rule) 2741 { 2742 struct nftnl_expr_iter *iter; 2743 struct nftnl_expr *expr; 2744 int ret = 0; 2745 2746 iter = nftnl_expr_iter_create(rule); 2747 if (iter == NULL) 2748 return -1; 2749 2750 expr = nftnl_expr_iter_next(iter); 2751 while (expr != NULL) { 2752 const char *name = nftnl_expr_get_str(expr, NFTNL_EXPR_NAME); 2753 2754 if (nft_is_expr_compatible(name) == 0) { 2755 expr = nftnl_expr_iter_next(iter); 2756 continue; 2757 } 2758 2759 ret = 1; 2760 break; 2761 } 2762 2763 nftnl_expr_iter_destroy(iter); 2764 return ret; 2765 } 2766 2767 static int nft_is_chain_compatible(const char *table, const char *chain) 2768 { 2769 const char *cur_table; 2770 struct builtin_chain *chains; 2771 int i, j; 2772 2773 for (i = 0; i < TABLES_MAX; i++) { 2774 cur_table = xtables_ipv4[i].name; 2775 chains = xtables_ipv4[i].chains; 2776 2777 if (strcmp(table, cur_table) != 0) 2778 continue; 2779 2780 for (j = 0; j < NF_INET_NUMHOOKS && chains[j].name; j++) { 2781 if (strcmp(chain, chains[j].name) == 0) 2782 return 0; 2783 } 2784 } 2785 2786 return 1; 2787 } 2788 2789 static int nft_are_chains_compatible(struct nft_handle *h) 2790 { 2791 struct nftnl_chain_list *list; 2792 struct nftnl_chain_list_iter *iter; 2793 struct nftnl_chain *chain; 2794 int ret = 0; 2795 2796 list = nftnl_chain_list_get(h); 2797 if (list == NULL) 2798 return -1; 2799 2800 iter = nftnl_chain_list_iter_create(list); 2801 if (iter == NULL) 2802 return -1; 2803 2804 chain = nftnl_chain_list_iter_next(iter); 2805 while (chain != NULL) { 2806 if (!nft_chain_builtin(chain)) 2807 goto next; 2808 2809 const char *table = nftnl_chain_get(chain, NFTNL_CHAIN_TABLE); 2810 const char *name = nftnl_chain_get(chain, NFTNL_CHAIN_NAME); 2811 2812 if (nft_is_chain_compatible(table, name) == 1) { 2813 ret = 1; 2814 break; 2815 } 2816 2817 next: 2818 chain = nftnl_chain_list_iter_next(iter); 2819 } 2820 2821 nftnl_chain_list_iter_destroy(iter); 2822 nftnl_chain_list_free(list); 2823 return ret; 2824 } 2825 2826 static int nft_is_table_compatible(const char *name) 2827 { 2828 int i; 2829 2830 for (i = 0; i < TABLES_MAX; i++) { 2831 if (strcmp(xtables_ipv4[i].name, name) == 0) 2832 return 0; 2833 } 2834 2835 return 1; 2836 } 2837 2838 static int nft_are_tables_compatible(struct nft_handle *h) 2839 { 2840 struct nftnl_table_list *list; 2841 struct nftnl_table_list_iter *iter; 2842 struct nftnl_table *table; 2843 int ret = 0; 2844 2845 list = nftnl_table_list_get(h); 2846 if (list == NULL) 2847 return -1; 2848 2849 iter = nftnl_table_list_iter_create(list); 2850 if (iter == NULL) 2851 return -1; 2852 2853 table = nftnl_table_list_iter_next(iter); 2854 while (table != NULL) { 2855 const char *name = nftnl_table_get(table, NFTNL_TABLE_NAME); 2856 2857 if (nft_is_table_compatible(name) == 0) { 2858 table = nftnl_table_list_iter_next(iter); 2859 continue; 2860 } 2861 2862 ret = 1; 2863 break; 2864 } 2865 2866 nftnl_table_list_iter_destroy(iter); 2867 nftnl_table_list_free(list); 2868 return ret; 2869 } 2870 2871 int nft_is_ruleset_compatible(struct nft_handle *h) 2872 { 2873 2874 struct nftnl_rule_list *list; 2875 struct nftnl_rule_list_iter *iter; 2876 struct nftnl_rule *rule; 2877 int ret = 0; 2878 2879 ret = nft_are_tables_compatible(h); 2880 if (ret != 0) 2881 return ret; 2882 2883 ret = nft_are_chains_compatible(h); 2884 if (ret != 0) 2885 return ret; 2886 2887 list = nft_rule_list_get(h); 2888 if (list == NULL) 2889 return -1; 2890 2891 iter = nftnl_rule_list_iter_create(list); 2892 if (iter == NULL) 2893 return -1; 2894 2895 rule = nftnl_rule_list_iter_next(iter); 2896 while (rule != NULL) { 2897 ret = nft_is_rule_compatible(rule); 2898 if (ret != 0) 2899 break; 2900 2901 rule = nftnl_rule_list_iter_next(iter); 2902 } 2903 2904 nftnl_rule_list_iter_destroy(iter); 2905 return ret; 2906 } 2907