From patchwork Fri Jul 19 15:17:44 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomasz Bursztyka X-Patchwork-Id: 260296 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id DFE552C0095 for ; Sat, 20 Jul 2013 01:18:59 +1000 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1760316Ab3GSPSo (ORCPT ); Fri, 19 Jul 2013 11:18:44 -0400 Received: from mga14.intel.com ([143.182.124.37]:10824 "EHLO mga14.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1760300Ab3GSPSm (ORCPT ); Fri, 19 Jul 2013 11:18:42 -0400 Received: from azsmga002.ch.intel.com ([10.2.17.35]) by azsmga102.ch.intel.com with ESMTP; 19 Jul 2013 08:18:19 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="4.89,702,1367996400"; d="scan'208";a="270609035" Received: from unknown (HELO rd-180.ger.corp.intel.com) ([10.252.122.114]) by AZSMGA002.ch.intel.com with ESMTP; 19 Jul 2013 08:18:17 -0700 From: Tomasz Bursztyka To: netfilter-devel@vger.kernel.org Cc: Tomasz Bursztyka Subject: [iptables-nftables - RFC PATCH 15/15] xtables: Support pure nft expressions for DNAT extension Date: Fri, 19 Jul 2013 18:17:44 +0300 Message-Id: <1374247064-3361-16-git-send-email-tomasz.bursztyka@linux.intel.com> X-Mailer: git-send-email 1.8.3.2 In-Reply-To: <1374247064-3361-1-git-send-email-tomasz.bursztyka@linux.intel.com> References: <1374247064-3361-1-git-send-email-tomasz.bursztyka@linux.intel.com> Sender: netfilter-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org Signed-off-by: Tomasz Bursztyka --- extensions/libipt_DNAT.c | 220 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 220 insertions(+) diff --git a/extensions/libipt_DNAT.c b/extensions/libipt_DNAT.c index 466c9de..92b4ef2 100644 --- a/extensions/libipt_DNAT.c +++ b/extensions/libipt_DNAT.c @@ -7,6 +7,7 @@ #include /* INT_MAX in ip_tables.h */ #include #include +#include enum { O_TO_DEST = 0, @@ -242,6 +243,223 @@ static void DNAT_save(const void *ip, const struct xt_entry_target *target) } } +static struct nft_rule_expr * +add_nat_data(struct nft_rule *rule, int reg, uint32_t data) +{ + struct nft_rule_expr *expr; + + expr = nft_rule_expr_alloc("immediate"); + if (expr == NULL) + return NULL; + + nft_rule_expr_set_u32(expr, NFT_EXPR_IMM_DREG, reg); + nft_rule_expr_set_u32(expr, NFT_EXPR_IMM_DATA, data); + + nft_rule_add_expr(rule, expr); + + return expr; +} + +static int add_nat_expr(struct nft_rule *rule, const struct nf_nat_range *r) +{ + struct nft_rule_expr *nat_expr; + int registers = 1; + + nat_expr = nft_rule_expr_alloc("nat"); + if (nat_expr == NULL) + return -1; + + nft_rule_expr_set_u32(nat_expr, NFT_EXPR_NAT_TYPE, NFT_NAT_DNAT); + nft_rule_expr_set_u32(nat_expr, NFT_EXPR_NAT_FAMILY, AF_INET); + + if (r->flags & IP_NAT_RANGE_MAP_IPS) { + nft_rule_expr_set_u32(nat_expr, NFT_EXPR_NAT_REG_ADDR_MIN, + registers); + if (add_nat_data(rule, registers, r->min_ip) == NULL) + goto error; + registers++; + + if (r->max_ip != r->min_ip) { + nft_rule_expr_set_u32(nat_expr, + NFT_EXPR_NAT_REG_ADDR_MAX, + registers); + if (add_nat_data(rule, registers, r->max_ip) == NULL) + goto error; + registers++; + } + } + + if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) { + nft_rule_expr_set_u32(nat_expr, NFT_EXPR_NAT_REG_PROTO_MIN, + registers); + if (add_nat_data(rule, registers, + ntohs(r->min.tcp.port)) == NULL) + goto error; + registers++; + + if (r->max.tcp.port != r->min.tcp.port) { + nft_rule_expr_set_u32(nat_expr, + NFT_EXPR_NAT_REG_PROTO_MAX, + registers); + if (add_nat_data(rule, registers, + ntohs(r->max.tcp.port)) == NULL) + goto error; + } + } + + nft_rule_add_expr(rule, nat_expr); + + return 0; + +error: + nft_rule_expr_free(nat_expr); + return -1; +} + +static int DNAT_to_nft(struct nft_rule *rule, struct xt_entry_target *target) +{ + const struct ipt_natinfo *info = (const void *)target; + int i; + + for (i = 0; i < info->mr.rangesize; i++) { + if (add_nat_expr(rule, &info->mr.range[i]) < 0) + return -1; + } + + return 0; +} + +static inline void get_nat_port(struct nft_rule_expr *expr, uint16_t *data) +{ + uint32_t value; + + value = nft_rule_expr_get_u32(expr, NFT_EXPR_IMM_DATA); + *data = htons((uint16_t) value); +} + +static int DNAT_parse_nft(struct nft_trans_rule_context *rule_ctx, + struct nft_trans_instruction_context *first, + struct nft_trans_instruction_context *last, + nft_trans_parse_callback_f user_cb, + void *user_data) +{ + struct nft_rule_expr *e_nat, *e; + struct nf_nat_range range; + struct ipt_natinfo *info; + uint32_t type, reg; + + if (user_cb == NULL) + return -1; + + e_nat = nft_trans_instruction_context_get_expr(last); + + if (!nft_rule_expr_is_set(e_nat, NFT_EXPR_NAT_TYPE)) + return -1; + + type = nft_rule_expr_get_u32(e_nat, NFT_EXPR_NAT_TYPE); + if (type != NFT_NAT_DNAT) + return -1; + + if (nft_rule_expr_is_set(e_nat, NFT_EXPR_NAT_REG_ADDR_MIN)) { + range.flags |= IP_NAT_RANGE_MAP_IPS; + + reg = nft_rule_expr_get_u32(e_nat, NFT_EXPR_NAT_REG_ADDR_MIN); + e = nft_trans_instruction_context_get_register(last, reg); + range.min_ip = nft_rule_expr_get_u32(e, NFT_EXPR_IMM_DATA); + + if (nft_rule_expr_is_set(e_nat, NFT_EXPR_NAT_REG_ADDR_MAX)) { + reg = nft_rule_expr_get_u32(e_nat, + NFT_EXPR_NAT_REG_ADDR_MAX); + e = nft_trans_instruction_context_get_register(last, reg); + range.max_ip = nft_rule_expr_get_u32(e, + NFT_EXPR_IMM_DATA); + } else + range.max_ip = range.min_ip; + } + + if (nft_rule_expr_is_set(e_nat, NFT_EXPR_NAT_REG_PROTO_MIN)) { + range.flags |= IP_NAT_RANGE_PROTO_SPECIFIED; + + reg = nft_rule_expr_get_u32(e_nat, NFT_EXPR_NAT_REG_PROTO_MIN); + e = nft_trans_instruction_context_get_register(last, reg); + get_nat_port(e, &range.min.tcp.port); + + if (nft_rule_expr_is_set(e_nat, NFT_EXPR_NAT_REG_PROTO_MAX)) { + reg = nft_rule_expr_get_u32(e_nat, + NFT_EXPR_NAT_REG_PROTO_MAX); + e = nft_trans_instruction_context_get_register(last, reg); + get_nat_port(e, &range.max.tcp.port); + } else + range.max.tcp.port = range.min.tcp.port; + } + + info = calloc(1, sizeof(struct ipt_natinfo)); + if (info == NULL) + return -1; + + info = append_range(NULL, &range); + if (user_cb("DNAT", &info->t, user_data) != 0) { + free(info); + return -1; + } + + return 0; +} + +static enum nft_instruction xt_dnat_instructions_1[] = { + NFT_INSTRUCTION_IMMEDIATE, NFT_INSTRUCTION_NAT, + NFT_INSTRUCTION_MAX, +}; + +static struct nft_trans_instruction xt_dnat_1 = { + .instructions = xt_dnat_instructions_1, + .function = DNAT_parse_nft, +}; + +static enum nft_instruction xt_dnat_instructions_2[] = { + NFT_INSTRUCTION_IMMEDIATE, NFT_INSTRUCTION_IMMEDIATE, + NFT_INSTRUCTION_NAT, + NFT_INSTRUCTION_MAX, +}; + +static struct nft_trans_instruction xt_dnat_2 = { + .instructions = xt_dnat_instructions_2, + .function = DNAT_parse_nft, +}; + +static enum nft_instruction xt_dnat_instructions_3[] = { + NFT_INSTRUCTION_IMMEDIATE, NFT_INSTRUCTION_IMMEDIATE, + NFT_INSTRUCTION_IMMEDIATE, NFT_INSTRUCTION_NAT, + NFT_INSTRUCTION_MAX, +}; + +static struct nft_trans_instruction xt_dnat_3 = { + .instructions = xt_dnat_instructions_3, + .function = DNAT_parse_nft, +}; + +static enum nft_instruction xt_dnat_instructions_4[] = { + NFT_INSTRUCTION_IMMEDIATE, NFT_INSTRUCTION_IMMEDIATE, + NFT_INSTRUCTION_IMMEDIATE, NFT_INSTRUCTION_IMMEDIATE, + NFT_INSTRUCTION_NAT, + NFT_INSTRUCTION_MAX, +}; + +static struct nft_trans_instruction xt_dnat_4 = { + .instructions = xt_dnat_instructions_4, + .function = DNAT_parse_nft, +}; + +static int DNAT_register_nft_instructions(struct nft_trans_instruction_tree *tree) +{ + nft_trans_add_instruction(tree, &xt_dnat_1); + nft_trans_add_instruction(tree, &xt_dnat_2); + nft_trans_add_instruction(tree, &xt_dnat_3); + nft_trans_add_instruction(tree, &xt_dnat_4); + + return 0; +} + static struct xtables_target dnat_tg_reg = { .name = "DNAT", .version = XTABLES_VERSION, @@ -254,6 +472,8 @@ static struct xtables_target dnat_tg_reg = { .print = DNAT_print, .save = DNAT_save, .x6_options = DNAT_opts, + .to_nft = DNAT_to_nft, + .register_nft_instructions = DNAT_register_nft_instructions, }; void _init(void)