Hello, On Tue, 2013-12-10 at 18:18 +0100, Pablo Neira Ayuso wrote: > From: Arturo Borrero Gonzalez <arturo.borrero.glez@xxxxxxxxx> > > This patch reworks the existing example to add the rule: > > nft add rule ip filter input tcp dport 22 counter > > It uses the existing nfnl batching approach using the generic mnl > netlink message batching infrastructure. It also removed the code > that uses xtables compat code. I don't see this patch in any of the branch. Is there any issue with it ? It seems really useful as existing examples are using really old code. BR, > > Based on original patch by Arturo Borrero Gonzalez. > > Signed-off-by: Pablo Neira Ayuso <pablo@xxxxxxxxxxxxx> > --- > examples/nft-rule-add.c | 257 ++++++++++++++++++++--------------- > include/linux/netfilter/nfnetlink.h | 5 + > 2 files changed, 152 insertions(+), 110 deletions(-) > > diff --git a/examples/nft-rule-add.c b/examples/nft-rule-add.c > index f896bc0..0534fa5 100644 > --- a/examples/nft-rule-add.c > +++ b/examples/nft-rule-add.c > @@ -14,126 +14,178 @@ > #include <string.h> > #include <stddef.h> /* for offsetof */ > #include <netinet/in.h> > +#include <netinet/ip.h> > +#include <netinet/tcp.h> > #include <arpa/inet.h> > +#include <sys/types.h> > +#include <sys/socket.h> > +#include <errno.h> > > #include <linux/netfilter.h> > +#include <linux/netfilter/nfnetlink.h> > #include <linux/netfilter/nf_tables.h> > > #include <libmnl/libmnl.h> > #include <libnftables/rule.h> > #include <libnftables/expr.h> > > -#include <linux/netfilter_ipv4/ipt_LOG.h> > -#include <linux/netfilter/xt_iprange.h> > - > -#include <netinet/ip.h> > - > -static void add_target_log(struct nft_rule_expr *e) > +static void add_payload(struct nft_rule *r, uint32_t base, uint32_t dreg, > + uint32_t offset, uint32_t len) > { > - struct ipt_log_info *info; > + struct nft_rule_expr *e; > > - nft_rule_expr_set(e, NFT_EXPR_TG_NAME, "LOG", strlen("LOG")); > - nft_rule_expr_set_u32(e, NFT_EXPR_TG_REV, 0); > - > - info = calloc(1, sizeof(struct ipt_log_info)); > - if (info == NULL) > - return; > + e = nft_rule_expr_alloc("payload"); > + if (e == NULL) { > + perror("expr payload oom"); > + exit(EXIT_FAILURE); > + } > > - sprintf(info->prefix, "test: "); > - info->prefix[sizeof(info->prefix)-1] = '\0'; > - info->logflags = 0x0f; > - info->level = 5; > + nft_rule_expr_set_u32(e, NFT_EXPR_PAYLOAD_BASE, base); > + nft_rule_expr_set_u32(e, NFT_EXPR_PAYLOAD_DREG, dreg); > + nft_rule_expr_set_u32(e, NFT_EXPR_PAYLOAD_OFFSET, offset); > + nft_rule_expr_set_u32(e, NFT_EXPR_PAYLOAD_LEN, len); > > - nft_rule_expr_set(e, NFT_EXPR_TG_INFO, info, sizeof(*info)); > + nft_rule_add_expr(r, e); > } > > -static void add_expr_target(struct nft_rule *r) > +static void add_cmp(struct nft_rule *r, uint32_t sreg, uint32_t op, > + const void *data, uint32_t data_len) > { > - struct nft_rule_expr *expr; > + struct nft_rule_expr *e; > > - expr = nft_rule_expr_alloc("target"); > - if (expr == NULL) > - return; > + e = nft_rule_expr_alloc("cmp"); > + if (e == NULL) { > + perror("expr cmp oom"); > + exit(EXIT_FAILURE); > + } > > - add_target_log(expr); > + nft_rule_expr_set_u32(e, NFT_EXPR_CMP_SREG, sreg); > + nft_rule_expr_set_u32(e, NFT_EXPR_CMP_OP, op); > + nft_rule_expr_set(e, NFT_EXPR_CMP_DATA, data, data_len); > > - nft_rule_add_expr(r, expr); > + nft_rule_add_expr(r, e); > } > > -static void add_match_iprange(struct nft_rule_expr *e) > +static void add_counter(struct nft_rule *r) > { > - struct xt_iprange_mtinfo *info; > - > - nft_rule_expr_set(e, NFT_EXPR_MT_NAME, "iprange", strlen("iprange")); > - nft_rule_expr_set_u32(e, NFT_EXPR_MT_REV, 1); > + struct nft_rule_expr *e; > > - info = calloc(1, sizeof(struct xt_iprange_mtinfo)); > - if (info == NULL) > - return; > - > - info->src_min.ip = info->dst_min.ip = inet_addr("127.0.0.1"); > - info->src_max.ip = info->dst_max.ip = inet_addr("127.0.0.1"); > - info->flags = IPRANGE_SRC; > + e = nft_rule_expr_alloc("counter"); > + if (e == NULL) { > + perror("expr counter oom"); > + exit(EXIT_FAILURE); > + } > > - nft_rule_expr_set(e, NFT_EXPR_MT_INFO, info, sizeof(*info)); > + nft_rule_add_expr(r, e); > } > > -static void add_expr_match(struct nft_rule *r) > +static struct nft_rule *setup_rule(uint8_t family, const char *table, > + const char *chain) > { > - struct nft_rule_expr *expr; > + struct nft_rule *r = NULL; > + uint8_t proto; > + uint16_t dport; > > - expr = nft_rule_expr_alloc("match"); > - if (expr == NULL) > - return; > + r = nft_rule_alloc(); > + if (r == NULL) { > + perror("OOM"); > + exit(EXIT_FAILURE); > + } > > - add_match_iprange(expr); > + nft_rule_attr_set(r, NFT_RULE_ATTR_TABLE, table); > + nft_rule_attr_set(r, NFT_RULE_ATTR_CHAIN, chain); > + nft_rule_attr_set_u32(r, NFT_RULE_ATTR_FAMILY, family); > > - nft_rule_add_expr(r, expr); > -} > + proto = IPPROTO_TCP; > + add_payload(r, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1, > + offsetof(struct iphdr, protocol), sizeof(uint8_t)); > + add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &proto, sizeof(uint8_t)); > > -#define field_sizeof(t, f) (sizeof(((t *)NULL)->f)) > + dport = htons(22); > + add_payload(r, NFT_PAYLOAD_TRANSPORT_HEADER, NFT_REG_1, > + offsetof(struct tcphdr, dest), sizeof(uint16_t)); > + add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &dport, sizeof(uint16_t)); > > -static void add_payload2(struct nft_rule_expr *e) > -{ > - nft_rule_expr_set_u32(e, NFT_EXPR_PAYLOAD_BASE, > - NFT_PAYLOAD_NETWORK_HEADER); > - nft_rule_expr_set_u32(e, NFT_EXPR_PAYLOAD_DREG, NFT_REG_1); > - nft_rule_expr_set_u32(e, NFT_EXPR_PAYLOAD_OFFSET, > - offsetof(struct iphdr, protocol)); > - nft_rule_expr_set_u32(e, NFT_EXPR_PAYLOAD_LEN, 1); > + add_counter(r); > + > + return r; > } > > -static void add_payload(struct nft_rule *r) > +static int seq; > + > +static void nft_mnl_batch_put(struct mnl_nlmsg_batch *batch, int type) > { > - struct nft_rule_expr *expr; > + struct nlmsghdr *nlh; > + struct nfgenmsg *nfg; > > - expr = nft_rule_expr_alloc("payload"); > - if (expr == NULL) > - return; > + nlh = mnl_nlmsg_put_header(mnl_nlmsg_batch_current(batch)); > + nlh->nlmsg_type = type; > + nlh->nlmsg_flags = NLM_F_REQUEST; > + nlh->nlmsg_seq = seq++; > > - add_payload2(expr); > + nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg)); > + nfg->nfgen_family = AF_INET; > + nfg->version = NFNETLINK_V0; > + nfg->res_id = NFNL_SUBSYS_NFTABLES; > > - nft_rule_add_expr(r, expr); > + mnl_nlmsg_batch_next(batch); > +} > + > +static int nft_mnl_batch_talk(struct mnl_socket *nl, struct mnl_nlmsg_batch *b) > +{ > + int ret, fd = mnl_socket_get_fd(nl); > + char rcv_buf[MNL_SOCKET_BUFFER_SIZE]; > + fd_set readfds; > + struct timeval tv = { > + .tv_sec = 0, > + .tv_usec = 0 > + }; > + > + ret = mnl_socket_sendto(nl, mnl_nlmsg_batch_head(b), > + mnl_nlmsg_batch_size(b)); > + if (ret == -1) > + goto err; > + > + FD_ZERO(&readfds); > + FD_SET(fd, &readfds); > + > + /* receive and digest all the acknowledgments from the kernel. */ > + ret = select(fd+1, &readfds, NULL, NULL, &tv); > + if (ret == -1) > + goto err; > + > + while (ret > 0 && FD_ISSET(fd, &readfds)) { > + ret = mnl_socket_recvfrom(nl, rcv_buf, sizeof(rcv_buf)); > + if (ret == -1) > + goto err; > + > + ret = mnl_cb_run(rcv_buf, ret, 0, mnl_socket_get_portid(nl), > + NULL, NULL); > + if (ret < 0) > + goto err; > + > + ret = select(fd+1, &readfds, NULL, NULL, &tv); > + if (ret == -1) > + goto err; > + > + FD_ZERO(&readfds); > + FD_SET(fd, &readfds); > + } > +err: > + return ret; > } > > int main(int argc, char *argv[]) > { > struct mnl_socket *nl; > - char buf[MNL_SOCKET_BUFFER_SIZE]; > + struct nft_rule *r; > struct nlmsghdr *nlh; > - uint32_t portid, seq; > - struct nft_rule *r = NULL; > - int ret, family; > + struct mnl_nlmsg_batch *batch; > + uint8_t family; > + char buf[4096]; > > if (argc != 4) { > - fprintf(stderr, "Usage: %s <family> <table> <chain>\n", > - argv[0]); > - exit(EXIT_FAILURE); > - } > - > - r = nft_rule_alloc(); > - if (r == NULL) { > - perror("OOM"); > + fprintf(stderr, "Usage: %s <family> <table> <chain>\n", argv[0]); > exit(EXIT_FAILURE); > } > > @@ -141,32 +193,12 @@ int main(int argc, char *argv[]) > 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"); > + fprintf(stderr, "Unknown family: ip, ip6\n"); > exit(EXIT_FAILURE); > } > > - nft_rule_attr_set(r, NFT_RULE_ATTR_TABLE, argv[2]); > - nft_rule_attr_set(r, NFT_RULE_ATTR_CHAIN, argv[3]); > - > - add_expr_match(r); > - add_payload(r); > - add_expr_target(r); > - > - char tmp[1024]; > - nft_rule_snprintf(tmp, sizeof(tmp), r, 0, 0); > - printf("%s\n", tmp); > - > - seq = time(NULL); > - nlh = nft_rule_nlmsg_build_hdr(buf, NFT_MSG_NEWRULE, family, > - NLM_F_APPEND|NLM_F_ACK|NLM_F_CREATE, > - seq); > - nft_rule_nlmsg_build_payload(nlh, r); > - nft_rule_free(r); > + r = setup_rule(family, argv[2], argv[3]); > > nl = mnl_socket_open(NETLINK_NETFILTER); > if (nl == NULL) { > @@ -178,24 +210,29 @@ int main(int argc, char *argv[]) > perror("mnl_socket_bind"); > exit(EXIT_FAILURE); > } > - portid = mnl_socket_get_portid(nl); > > - if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { > - perror("mnl_socket_send"); > - exit(EXIT_FAILURE); > - } > + batch = mnl_nlmsg_batch_start(buf, sizeof(buf)); > > - ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); > - while (ret > 0) { > - ret = mnl_cb_run(buf, ret, seq, portid, NULL, NULL); > - if (ret <= 0) > - break; > - ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); > - } > - if (ret == -1) { > - perror("error"); > + nft_mnl_batch_put(batch, NFNL_MSG_BATCH_BEGIN); > + > + nlh = nft_rule_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), > + NFT_MSG_NEWRULE, > + nft_rule_attr_get_u32(r, NFT_RULE_ATTR_FAMILY), > + NLM_F_APPEND|NLM_F_CREATE, seq); > + > + nft_rule_nlmsg_build_payload(nlh, r); > + nft_rule_free(r); > + mnl_nlmsg_batch_next(batch); > + > + nft_mnl_batch_put(batch, NFNL_MSG_BATCH_END); > + > + if (nft_mnl_batch_talk(nl, batch) < 0) { > + perror("Netlink problem"); > exit(EXIT_FAILURE); > } > + > + mnl_nlmsg_batch_stop(batch); > + > mnl_socket_close(nl); > > return EXIT_SUCCESS; > diff --git a/include/linux/netfilter/nfnetlink.h b/include/linux/netfilter/nfnetlink.h > index 91eebab..336c10c 100644 > --- a/include/linux/netfilter/nfnetlink.h > +++ b/include/linux/netfilter/nfnetlink.h > @@ -97,4 +97,9 @@ extern void nfnl_unlock(void); > MODULE_ALIAS("nfnetlink-subsys-" __stringify(subsys)) > > #endif /* __KERNEL__ */ > + > +/* Reserved control nfnetlink messages */ > +#define NFNL_MSG_BATCH_BEGIN NLMSG_MIN_TYPE > +#define NFNL_MSG_BATCH_END NLMSG_MIN_TYPE+1 > + > #endif /* _NFNETLINK_H */ -- Eric Leblond <eric@xxxxxxxxx> -- To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html