static int chain_cmd(struct mnl_socket *nl, struct nftnl_chain *chain, uint16_t cmd, int family, uint16_t type, enum callback_return_type cb_type, uint64_t *cb_val) { char buf[MNL_SOCKET_BUFFER_SIZE]; struct mnl_nlmsg_batch *batch; struct nlmsghdr *nlh; uint32_t seq = 0; int err; bzero(buf, sizeof(buf)); batch = mnl_nlmsg_batch_start(buf, sizeof(buf)); nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++); mnl_nlmsg_batch_next(batch); nlh = nftnl_chain_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), cmd, family, type, seq++); nftnl_chain_nlmsg_build_payload(nlh, chain); nftnl_chain_free(chain); mnl_nlmsg_batch_next(batch); nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq++); mnl_nlmsg_batch_next(batch); err = send_and_dispatch(nl, mnl_nlmsg_batch_head(batch), mnl_nlmsg_batch_size(batch), cb_type, cb_val); mnl_nlmsg_batch_stop(batch); return err; }
static int table_cmd(struct mnl_socket *nl, struct nftnl_table *t, uint16_t cmd, uint16_t family, uint16_t type) { char buf[MNL_SOCKET_BUFFER_SIZE]; struct mnl_nlmsg_batch *batch; struct nlmsghdr *nlh; uint32_t seq = 0; int err; bzero(buf, sizeof(buf)); batch = mnl_nlmsg_batch_start(buf, sizeof(buf)); nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++); mnl_nlmsg_batch_next(batch); nlh = nftnl_table_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), cmd, family, type, seq++); nftnl_table_nlmsg_build_payload(nlh, t); nftnl_table_free(t); mnl_nlmsg_batch_next(batch); nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq++); mnl_nlmsg_batch_next(batch); /* The current table commands do not support any callback returns. */ err = send_and_dispatch(nl, mnl_nlmsg_batch_head(batch), mnl_nlmsg_batch_size(batch), 0, NULL); mnl_nlmsg_batch_stop(batch); return err; }
int nftnl_batch_is_supported(void) { struct mnl_socket *nl; struct mnl_nlmsg_batch *b; char buf[MNL_SOCKET_BUFFER_SIZE]; uint32_t seq = time(NULL), req_seq; int ret; nl = mnl_socket_open(NETLINK_NETFILTER); if (nl == NULL) return -1; if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) return -1; b = mnl_nlmsg_batch_start(buf, sizeof(buf)); nftnl_batch_begin(mnl_nlmsg_batch_current(b), seq++); mnl_nlmsg_batch_next(b); req_seq = seq; nftnl_set_nlmsg_build_hdr(mnl_nlmsg_batch_current(b), NFT_MSG_NEWSET, AF_INET, NLM_F_ACK, seq++); mnl_nlmsg_batch_next(b); nftnl_batch_end(mnl_nlmsg_batch_current(b), seq++); mnl_nlmsg_batch_next(b); ret = mnl_socket_sendto(nl, mnl_nlmsg_batch_head(b), mnl_nlmsg_batch_size(b)); if (ret < 0) goto err; mnl_nlmsg_batch_stop(b); ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); while (ret > 0) { ret = mnl_cb_run(buf, ret, req_seq, mnl_socket_get_portid(nl), NULL, NULL); if (ret <= 0) break; ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); } mnl_socket_close(nl); /* We're sending an incomplete message to see if the kernel supports * set messages in batches. EINVAL means that we sent an incomplete * message with missing attributes. The kernel just ignores messages * that we cannot include in the batch. */ return (ret == -1 && errno == EINVAL) ? 1 : 0; err: mnl_nlmsg_batch_stop(b); return -1; }
static int rule_cmd(struct mnl_socket *nl, struct nftnl_rule *rule, uint16_t cmd, uint16_t family, uint16_t type, enum callback_return_type callback_type, uint64_t *callback_value) { char buf[MNL_SOCKET_BUFFER_SIZE]; struct mnl_nlmsg_batch *batch; struct nlmsghdr *nlh; uint32_t seq = 0; int err; bzero(buf, sizeof(buf)); debug_netlink_dump_rule(rule); batch = mnl_nlmsg_batch_start(buf, sizeof(buf)); put_batch_headers(mnl_nlmsg_batch_current(batch), NFNL_MSG_BATCH_BEGIN, seq++); mnl_nlmsg_batch_next(batch); nlh = nftnl_rule_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), cmd, family, type, seq++); nftnl_rule_nlmsg_build_payload(nlh, rule); mnl_nlmsg_batch_next(batch); put_batch_headers(mnl_nlmsg_batch_current(batch), NFNL_MSG_BATCH_END, seq++); mnl_nlmsg_batch_next(batch); err = send_and_dispatch(nl, mnl_nlmsg_batch_head(batch), mnl_nlmsg_batch_size(batch), callback_type, callback_value); mnl_nlmsg_batch_stop(batch); return err; }
int main(int argc, char *argv[]) { struct mnl_socket *nl; char buf[MNL_SOCKET_BUFFER_SIZE]; struct nlmsghdr *nlh; struct mnl_nlmsg_batch *batch; uint32_t portid, seq; struct nft_rule *r = NULL; int ret, family; if (argc < 4 || argc > 5) { fprintf(stderr, "Usage: %s <family> <table> <chain> [<handle>]\n", argv[0]); exit(EXIT_FAILURE); } r = nft_rule_alloc(); if (r == NULL) { perror("OOM"); exit(EXIT_FAILURE); } if (strcmp(argv[1], "ip") == 0) family = NFPROTO_IPV4; else if (strcmp(argv[1], "ip6") == 0) family = NFPROTO_IPV6; else if (strcmp(argv[1], "bridge") == 0) family = NFPROTO_BRIDGE; else if (strcmp(argv[1], "arp") == 0) family = NFPROTO_ARP; else { fprintf(stderr, "Unknown family: ip, ip6, bridge, arp\n"); exit(EXIT_FAILURE); } seq = time(NULL); nft_rule_attr_set(r, NFT_RULE_ATTR_TABLE, argv[2]); nft_rule_attr_set(r, NFT_RULE_ATTR_CHAIN, argv[3]); /* If no handle is specified, delete all rules in the chain */ if (argc == 5) nft_rule_attr_set_u64(r, NFT_RULE_ATTR_HANDLE, atoi(argv[4])); batch = mnl_nlmsg_batch_start(buf, sizeof(buf)); nft_mnl_batch_put(mnl_nlmsg_batch_current(batch), NFNL_MSG_BATCH_BEGIN, seq++); mnl_nlmsg_batch_next(batch); nlh = nft_rule_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_DELRULE, family, NLM_F_ACK, seq++); nft_rule_nlmsg_build_payload(nlh, r); nft_rule_free(r); mnl_nlmsg_batch_next(batch); nft_mnl_batch_put(mnl_nlmsg_batch_current(batch), NFNL_MSG_BATCH_END, seq++); mnl_nlmsg_batch_next(batch); nl = mnl_socket_open(NETLINK_NETFILTER); if (nl == NULL) { perror("mnl_socket_open"); exit(EXIT_FAILURE); } if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) { perror("mnl_socket_bind"); exit(EXIT_FAILURE); } portid = mnl_socket_get_portid(nl); if (mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch), mnl_nlmsg_batch_size(batch)) < 0) { perror("mnl_socket_send"); exit(EXIT_FAILURE); } mnl_nlmsg_batch_stop(batch); ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); while (ret > 0) { ret = mnl_cb_run(buf, ret, 0, portid, NULL, NULL); if (ret <= 0) break; ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); } if (ret == -1) { perror("error"); exit(EXIT_FAILURE); } mnl_socket_close(nl); return EXIT_SUCCESS; }
int main(int argc, char *argv[]) { struct mnl_socket *nl; char buf[MNL_SOCKET_BUFFER_SIZE]; struct nlmsghdr *nlh; uint32_t portid, seq, table_seq, family; struct nft_table *t; struct mnl_nlmsg_batch *batch; int ret, batching; if (argc != 3) { fprintf(stderr, "%s <family> <name>\n", argv[0]); exit(EXIT_FAILURE); } t = table_add_parse(argc, argv); if (t == NULL) exit(EXIT_FAILURE); batching = nft_batch_is_supported(); if (batching < 0) { perror("cannot talk to nfnetlink"); exit(EXIT_FAILURE); } seq = time(NULL); batch = mnl_nlmsg_batch_start(buf, sizeof(buf)); if (batching) { nft_batch_begin(mnl_nlmsg_batch_current(batch), seq++); mnl_nlmsg_batch_next(batch); } table_seq = seq; family = nft_table_attr_get_u32(t, NFT_TABLE_ATTR_FAMILY); nlh = nft_table_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWTABLE, family, NLM_F_ACK, seq++); nft_table_nlmsg_build_payload(nlh, t); nft_table_free(t); mnl_nlmsg_batch_next(batch); if (batching) { nft_batch_end(mnl_nlmsg_batch_current(batch), seq++); mnl_nlmsg_batch_next(batch); } nl = mnl_socket_open(NETLINK_NETFILTER); if (nl == NULL) { perror("mnl_socket_open"); exit(EXIT_FAILURE); } if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) { perror("mnl_socket_bind"); exit(EXIT_FAILURE); } portid = mnl_socket_get_portid(nl); if (mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch), mnl_nlmsg_batch_size(batch)) < 0) { perror("mnl_socket_send"); exit(EXIT_FAILURE); } mnl_nlmsg_batch_stop(batch); ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); while (ret > 0) { ret = mnl_cb_run(buf, ret, table_seq, portid, NULL, NULL); if (ret <= 0) break; ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); } if (ret == -1) { perror("error"); exit(EXIT_FAILURE); } mnl_socket_close(nl); return EXIT_SUCCESS; }
int main(int argc, char *argv[]) { struct mnl_socket *nl; char buf[MNL_SOCKET_BUFFER_SIZE]; struct nlmsghdr *nlh; uint32_t portid, seq, set_seq; struct nftnl_set *s; int ret, batching; uint16_t family, format, outformat; struct mnl_nlmsg_batch *batch; if (argc < 2) { printf("Usage: %s {xml|json} <file>\n", argv[0]); exit(EXIT_FAILURE); } if (strcmp(argv[1], "xml") == 0) { format = NFTNL_PARSE_XML; outformat = NFTNL_OUTPUT_XML; } else if (strcmp(argv[1], "json") == 0) { format = NFTNL_PARSE_JSON; outformat = NFTNL_OUTPUT_JSON; } else { printf("Unknown format: xml, json\n"); exit(EXIT_FAILURE); } s = set_parse_file(argv[2], format); if (s == NULL) exit(EXIT_FAILURE); nftnl_set_fprintf(stdout, s, outformat, 0); fprintf(stdout, "\n"); seq = time(NULL); batching = nftnl_batch_is_supported(); if (batching < 0) { perror("cannot talk to nfnetlink"); exit(EXIT_FAILURE); } batch = mnl_nlmsg_batch_start(buf, sizeof(buf)); if (batching) { nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++); mnl_nlmsg_batch_next(batch); } family = nftnl_set_get_u32(s, NFTNL_SET_FAMILY); set_seq = seq; nlh = nftnl_set_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWSET, family, NLM_F_CREATE|NLM_F_ACK, seq++); nftnl_set_nlmsg_build_payload(nlh, s); nftnl_set_free(s); mnl_nlmsg_batch_next(batch); if (batching) { nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq++); mnl_nlmsg_batch_next(batch); } nl = mnl_socket_open(NETLINK_NETFILTER); if (nl == NULL) { perror("mnl_socket_open"); exit(EXIT_FAILURE); } if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) { perror("mnl_socket_bind"); exit(EXIT_FAILURE); } portid = mnl_socket_get_portid(nl); if (mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch), mnl_nlmsg_batch_size(batch)) < 0) { perror("mnl_socket_send"); exit(EXIT_FAILURE); } mnl_nlmsg_batch_stop(batch); ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); while (ret > 0) { ret = mnl_cb_run(buf, ret, set_seq, portid, NULL, NULL); if (ret <= 0) break; ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); } if (ret == -1) { perror("error"); exit(EXIT_FAILURE); } mnl_socket_close(nl); return EXIT_SUCCESS; }
static void send_batch(struct mnl_socket *nl, struct mnl_nlmsg_batch *b, int portid) { int ret, fd = mnl_socket_get_fd(nl); size_t len = mnl_nlmsg_batch_size(b); char rcv_buf[MNL_SOCKET_BUFFER_SIZE]; ret = mnl_socket_sendto(nl, mnl_nlmsg_batch_head(b), len); if (ret == -1) { perror("mnl_socket_recvfrom"); exit(EXIT_FAILURE); } /* receive and digest all the acknowledgments from the kernel. */ struct timeval tv = { .tv_sec = 0, .tv_usec = 0 }; fd_set readfds; FD_ZERO(&readfds); FD_SET(fd, &readfds); ret = select(fd+1, &readfds, NULL, NULL, &tv); if (ret == -1) { perror("select"); exit(EXIT_FAILURE); } while (ret > 0 && FD_ISSET(fd, &readfds)) { ret = mnl_socket_recvfrom(nl, rcv_buf, sizeof(rcv_buf)); if (ret == -1) { perror("mnl_socket_recvfrom"); exit(EXIT_FAILURE); } ret = mnl_cb_run2(rcv_buf, ret, 0, portid, NULL, NULL, cb_ctl_array, MNL_ARRAY_SIZE(cb_ctl_array)); if (ret == -1) { perror("mnl_cb_run"); exit(EXIT_FAILURE); } ret = select(fd+1, &readfds, NULL, NULL, &tv); if (ret == -1) { perror("select"); exit(EXIT_FAILURE); } FD_ZERO(&readfds); FD_SET(fd, &readfds); } } int main(void) { struct mnl_socket *nl; char snd_buf[MNL_SOCKET_BUFFER_SIZE*2]; struct mnl_nlmsg_batch *b; int j; unsigned int seq, portid; uint16_t i; nl = mnl_socket_open(NETLINK_NETFILTER); if (nl == NULL) { perror("mnl_socket_open"); exit(EXIT_FAILURE); } if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) { perror("mnl_socket_bind"); exit(EXIT_FAILURE); } portid = mnl_socket_get_portid(nl); /* The buffer that we use to batch messages is MNL_SOCKET_BUFFER_SIZE * multiplied by 2 bytes long, but we limit the batch to half of it * since the last message that does not fit the batch goes over the * upper boundary, if you break this rule, expect memory corruptions. */ b = mnl_nlmsg_batch_start(snd_buf, MNL_SOCKET_BUFFER_SIZE); if (b == NULL) { perror("mnl_nlmsg_batch_start"); exit(EXIT_FAILURE); } seq = time(NULL); for (i=1024, j=0; i<65535; i++, j++) { put_msg(mnl_nlmsg_batch_current(b), i, seq+j); /* is there room for more messages in this batch? * if so, continue. */ if (mnl_nlmsg_batch_next(b)) continue; send_batch(nl, b, portid); /* this moves the last message that did not fit into the * batch to the head of it. */ mnl_nlmsg_batch_reset(b); } /* check if there is any message in the batch not sent yet. */ if (!mnl_nlmsg_batch_is_empty(b)) send_batch(nl, b, portid); mnl_nlmsg_batch_stop(b); mnl_socket_close(nl); return 0; }
int main(int argc, char *argv[]) { struct mnl_socket *nl; struct nftnl_rule *r; struct nlmsghdr *nlh; struct mnl_nlmsg_batch *batch; uint8_t family; char buf[MNL_SOCKET_BUFFER_SIZE]; uint32_t seq = time(NULL); int ret; if (argc < 4 || argc > 5) { fprintf(stderr, "Usage: %s <family> <table> <chain>\n", argv[0]); exit(EXIT_FAILURE); } if (strcmp(argv[1], "ip") == 0) family = NFPROTO_IPV4; else if (strcmp(argv[1], "ip6") == 0) family = NFPROTO_IPV6; else { fprintf(stderr, "Unknown family: ip, ip6\n"); exit(EXIT_FAILURE); } if (argc != 5) r = setup_rule(family, argv[2], argv[3], NULL); else r = setup_rule(family, argv[2], argv[3], argv[4]); nl = mnl_socket_open(NETLINK_NETFILTER); if (nl == NULL) { perror("mnl_socket_open"); exit(EXIT_FAILURE); } if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) { perror("mnl_socket_bind"); exit(EXIT_FAILURE); } batch = mnl_nlmsg_batch_start(buf, sizeof(buf)); nftnl_mnl_batch_put(mnl_nlmsg_batch_current(batch), NFNL_MSG_BATCH_BEGIN, seq++); mnl_nlmsg_batch_next(batch); nlh = nftnl_rule_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWRULE, nftnl_rule_get_u32(r, NFTNL_RULE_FAMILY), NLM_F_APPEND|NLM_F_CREATE|NLM_F_ACK, seq++); nftnl_rule_nlmsg_build_payload(nlh, r); nftnl_rule_free(r); mnl_nlmsg_batch_next(batch); nftnl_mnl_batch_put(mnl_nlmsg_batch_current(batch), NFNL_MSG_BATCH_END, seq++); mnl_nlmsg_batch_next(batch); ret = mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch), mnl_nlmsg_batch_size(batch)); if (ret == -1) { perror("mnl_socket_sendto"); exit(EXIT_FAILURE); } mnl_nlmsg_batch_stop(batch); ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); if (ret == -1) { perror("mnl_socket_recvfrom"); exit(EXIT_FAILURE); } ret = mnl_cb_run(buf, ret, 0, mnl_socket_get_portid(nl), NULL, NULL); if (ret < 0) { perror("mnl_cb_run"); exit(EXIT_FAILURE); } mnl_socket_close(nl); return EXIT_SUCCESS; }
int main(int argc, char *argv[]) { struct mnl_socket *nl; struct mnl_nlmsg_batch *batch; char buf[MNL_SOCKET_BUFFER_SIZE]; struct nlmsghdr *nlh; uint32_t portid, seq, chain_seq; struct nft_chain *t; int ret, family, batching; if (argc != 4) { fprintf(stderr, "Usage: %s <family> <table> <chain>\n", argv[0]); exit(EXIT_FAILURE); } if (strcmp(argv[1], "ip") == 0) family = NFPROTO_IPV4; else if (strcmp(argv[1], "ip6") == 0) family = NFPROTO_IPV6; else if (strcmp(argv[1], "bridge") == 0) family = NFPROTO_BRIDGE; else if (strcmp(argv[1], "arp") == 0) family = NFPROTO_ARP; else { fprintf(stderr, "Unknown family: ip, ip6, bridge, arp\n"); exit(EXIT_FAILURE); } t = chain_del_parse(argc, argv); if (t == NULL) exit(EXIT_FAILURE); batching = nft_batch_is_supported(); if (batching < 0) { perror("cannot talk to nfnetlink"); exit(EXIT_FAILURE); } seq = time(NULL); batch = mnl_nlmsg_batch_start(buf, sizeof(buf)); if (batching) { nft_batch_begin(mnl_nlmsg_batch_current(batch), seq++); mnl_nlmsg_batch_next(batch); } chain_seq = seq; nlh = nft_chain_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_DELCHAIN, family, NLM_F_ACK, seq++); nft_chain_nlmsg_build_payload(nlh, t); nft_chain_free(t); mnl_nlmsg_batch_next(batch); if (batching) { nft_batch_end(mnl_nlmsg_batch_current(batch), seq++); mnl_nlmsg_batch_next(batch); } nl = mnl_socket_open(NETLINK_NETFILTER); if (nl == NULL) { perror("mnl_socket_open"); exit(EXIT_FAILURE); } if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) { perror("mnl_socket_bind"); exit(EXIT_FAILURE); } portid = mnl_socket_get_portid(nl); if (mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch), mnl_nlmsg_batch_size(batch)) < 0) { perror("mnl_socket_send"); exit(EXIT_FAILURE); } ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); while (ret > 0) { ret = mnl_cb_run(buf, ret, chain_seq, portid, NULL, NULL); if (ret <= 0) break; ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); } if (ret == -1) { perror("error"); exit(EXIT_FAILURE); } mnl_socket_close(nl); return EXIT_SUCCESS; }