Hi Pablo,

I prepared this third version to get aligned about the way forward for the 
extension for struct nf_nat_range.

Renaming the old definition as you suggested indeed results in a much smaller 
patch for netfilter kernel part.
However, doing it like this also means that userspace code will require changes 
to cope with the new value for sizeof(struct nf_nat_range).

i.e. iptables-1.6.1 :

./extensions/libip6t_SNAT.c:306:    .userspacesize    = XT_ALIGN(sizeof(struct 
nf_nat_range)),
./extensions/libip6t_DNAT.c:290:    .userspacesize    = XT_ALIGN(sizeof(struct 
nf_nat_range)),
./extensions/libip6t_NETMAP.c:89:    .userspacesize    = XT_ALIGN(sizeof(struct 
nf_nat_range)),
./extensions/libip6t_MASQUERADE.c:159:    .userspacesize    = 
XT_ALIGN(sizeof(struct nf_nat_range)),
./extensions/libip6t_REDIRECT.c:158:    .userspacesize    = 
XT_ALIGN(sizeof(struct nf_nat_range)),

As far as I understand, all these xt target modules will have to increment 
their revision which makes them incompatible with current kernel versions.
The other option is to replace all occurences of nf_nat_range with 
nf_nat_range1 in these userspace libraries.
That would solve iptables but possible other applications might also be 
impacted ?

Somehow this doesn't seem right to me, so I might have misinterpreted your 
earlier response.


On 12-01-18 15:01, Thierry Du Tre wrote:
> This is a patch proposal to support shifted ranges in portmaps.
> (i.e. tcp/udp incoming port 5000-5100 on WAN redirected to LAN 
> 192.168.1.5:2000-2100)
>
> Currently DNAT only works for single port or identical port ranges.
> (i.e. ports 5000-5100 on WAN interface redirected to a LAN host while 
> original destination port is not altered)
> When different port ranges are configured, either 'random' mode should be 
> used, or else all incoming connections are mapped onto the first port in the 
> redirect range. (in described example WAN:5000-5100 will all be mapped to 
> 192.168.1.5:2000)
>
> This patch introduces a new mode indicated by flag NF_NAT_RANGE_PROTO_OFFSET 
> which uses a base port value to calculate an offset with the destination port 
> present in the incoming stream. That offset is then applied as index within 
> the redirect port range (index modulo rangewidth to handle range overflow).
>
> In described example the base port would be 5000. An incoming stream with 
> destination port 5004 would result in an offset value 4 which means that the 
> NAT'ed stream will be using destination port 2004.
>
> Other possibilities include deterministic mapping of larger or multiple 
> ranges to a smaller range : WAN:5000-5999 -> LAN:5000-5099 (maps WAN port 
> 5*xx to port 51xx)
>
> This patch does not change any current behavior. It just adds new NAT proto 
> range functionality which must be selected via the specific flag when 
> intended to use.
>
> A patch for iptables (libipt_DNAT.c) will also be proposed which makes this 
> functionality immediately available.
>
> Signed-off-by: Thierry Du Tre <thie...@dtsystems.be>
>
> ---
> Changes in v3:
>     - use nf_nat_range as name for updated struct, renamed existing 
> nf_nat_range to nf_nat_range1
>     - reverted all nf_nat_range2 occurences
>
> Changes in v2:
>     - added new revision for SNAT and DNAT targets to support the new base 
> port variable in struct nf_nat_range2
>     - replaced all occurences of struct nf_nat_range with struct nf_nat_range2
>
>  include/uapi/linux/netfilter/nf_nat.h | 12 +++++++-
>  net/netfilter/nf_nat_core.c           |  9 +++---
>  net/netfilter/nf_nat_proto_common.c   |  5 ++-
>  net/netfilter/xt_nat.c                | 58 
> ++++++++++++++++++++++++++++++++++-
>  4 files changed, 77 insertions(+), 7 deletions(-)
>
> diff --git a/include/uapi/linux/netfilter/nf_nat.h 
> b/include/uapi/linux/netfilter/nf_nat.h
> index a33000d..0fa792a 100644
> --- a/include/uapi/linux/netfilter/nf_nat.h
> +++ b/include/uapi/linux/netfilter/nf_nat.h
> @@ -10,6 +10,7 @@
>  #define NF_NAT_RANGE_PROTO_RANDOM            (1 << 2)
>  #define NF_NAT_RANGE_PERSISTENT                      (1 << 3)
>  #define NF_NAT_RANGE_PROTO_RANDOM_FULLY              (1 << 4)
> +#define NF_NAT_RANGE_PROTO_OFFSET            (1 << 5)
>  
>  #define NF_NAT_RANGE_PROTO_RANDOM_ALL                \
>       (NF_NAT_RANGE_PROTO_RANDOM | NF_NAT_RANGE_PROTO_RANDOM_FULLY)
> @@ -17,7 +18,7 @@
>  #define NF_NAT_RANGE_MASK                                    \
>       (NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED |  \
>        NF_NAT_RANGE_PROTO_RANDOM | NF_NAT_RANGE_PERSISTENT |  \
> -      NF_NAT_RANGE_PROTO_RANDOM_FULLY)
> +      NF_NAT_RANGE_PROTO_RANDOM_FULLY | NF_NAT_RANGE_PROTO_OFFSET)
>  
>  struct nf_nat_ipv4_range {
>       unsigned int                    flags;
> @@ -32,12 +33,21 @@ struct nf_nat_ipv4_multi_range_compat {
>       struct nf_nat_ipv4_range        range[1];
>  };
>  
> +struct nf_nat_range1 {
> +     unsigned int                    flags;
> +     union nf_inet_addr              min_addr;
> +     union nf_inet_addr              max_addr;
> +     union nf_conntrack_man_proto    min_proto;
> +     union nf_conntrack_man_proto    max_proto;
> +};
> +
>  struct nf_nat_range {
>       unsigned int                    flags;
>       union nf_inet_addr              min_addr;
>       union nf_inet_addr              max_addr;
>       union nf_conntrack_man_proto    min_proto;
>       union nf_conntrack_man_proto    max_proto;
> +     union nf_conntrack_man_proto    base_proto;
>  };
>  
>  #endif /* _NETFILTER_NF_NAT_H */
> diff --git a/net/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c
> index af8345f..de5c327 100644
> --- a/net/netfilter/nf_nat_core.c
> +++ b/net/netfilter/nf_nat_core.c
> @@ -347,9 +347,10 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple,
>       /* Only bother mapping if it's not already in range and unique */
>       if (!(range->flags & NF_NAT_RANGE_PROTO_RANDOM_ALL)) {
>               if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
> -                     if (l4proto->in_range(tuple, maniptype,
> -                                           &range->min_proto,
> -                                           &range->max_proto) &&
> +                     if (!(range->flags & NF_NAT_RANGE_PROTO_OFFSET) &&
> +                         l4proto->in_range(tuple, maniptype,
> +                               &range->min_proto,
> +                               &range->max_proto) &&
>                           (range->min_proto.all == range->max_proto.all ||
>                            !nf_nat_used_tuple(tuple, ct)))
>                               goto out;
> @@ -358,7 +359,7 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple,
>               }
>       }
>  
> -     /* Last change: get protocol to try to obtain unique tuple. */
> +     /* Last chance: get protocol to try to obtain unique tuple. */
>       l4proto->unique_tuple(l3proto, tuple, range, maniptype, ct);
>  out:
>       rcu_read_unlock();
> diff --git a/net/netfilter/nf_nat_proto_common.c 
> b/net/netfilter/nf_nat_proto_common.c
> index fbce552..2c30eca 100644
> --- a/net/netfilter/nf_nat_proto_common.c
> +++ b/net/netfilter/nf_nat_proto_common.c
> @@ -80,6 +80,8 @@ void nf_nat_l4proto_unique_tuple(const struct 
> nf_nat_l3proto *l3proto,
>                                                 : tuple->src.u.all);
>       } else if (range->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) {
>               off = prandom_u32();
> +     } else if (range->flags & NF_NAT_RANGE_PROTO_OFFSET) {
> +             off = (ntohs(*portptr) - ntohs(range->base_proto.all));
>       } else {
>               off = *rover;
>       }
> @@ -88,7 +90,8 @@ void nf_nat_l4proto_unique_tuple(const struct 
> nf_nat_l3proto *l3proto,
>               *portptr = htons(min + off % range_size);
>               if (++i != range_size && nf_nat_used_tuple(tuple, ct))
>                       continue;
> -             if (!(range->flags & NF_NAT_RANGE_PROTO_RANDOM_ALL))
> +             if (!(range->flags & (NF_NAT_RANGE_PROTO_RANDOM_ALL|
> +                                     NF_NAT_RANGE_PROTO_OFFSET)))
>                       *rover = off;
>               return;
>       }
> diff --git a/net/netfilter/xt_nat.c b/net/netfilter/xt_nat.c
> index 0fd14d1..7e8552b 100644
> --- a/net/netfilter/xt_nat.c
> +++ b/net/netfilter/xt_nat.c
> @@ -41,6 +41,7 @@ static void xt_nat_convert_range(struct nf_nat_range *dst,
>  {
>       memset(&dst->min_addr, 0, sizeof(dst->min_addr));
>       memset(&dst->max_addr, 0, sizeof(dst->max_addr));
> +     memset(&dst->base_proto, 0, sizeof(dst->base_proto));
>  
>       dst->flags       = src->flags;
>       dst->min_addr.ip = src->min_ip;
> @@ -85,6 +86,39 @@ xt_dnat_target_v0(struct sk_buff *skb, const struct 
> xt_action_param *par)
>  static unsigned int
>  xt_snat_target_v1(struct sk_buff *skb, const struct xt_action_param *par)
>  {
> +     const struct nf_nat_range1 *range_v1 = par->targinfo;
> +     struct nf_nat_range range = {};
> +     enum ip_conntrack_info ctinfo;
> +     struct nf_conn *ct;
> +
> +     ct = nf_ct_get(skb, &ctinfo);
> +     WARN_ON(!(ct != NULL &&
> +              (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED ||
> +               ctinfo == IP_CT_RELATED_REPLY)));
> +
> +     memcpy(&range, range_v1, sizeof(*range_v1));
> +     return nf_nat_setup_info(ct, &range, NF_NAT_MANIP_SRC);
> +}
> +
> +static unsigned int
> +xt_dnat_target_v1(struct sk_buff *skb, const struct xt_action_param *par)
> +{
> +     const struct nf_nat_range1 *range_v1 = par->targinfo;
> +     struct nf_nat_range range = {};
> +     enum ip_conntrack_info ctinfo;
> +     struct nf_conn *ct;
> +
> +     ct = nf_ct_get(skb, &ctinfo);
> +     WARN_ON(!(ct != NULL &&
> +              (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED)));
> +
> +     memcpy(&range, range_v1, sizeof(*range_v1));
> +     return nf_nat_setup_info(ct, &range, NF_NAT_MANIP_DST);
> +}
> +
> +static unsigned int
> +xt_snat_target_v2(struct sk_buff *skb, const struct xt_action_param *par)
> +{
>       const struct nf_nat_range *range = par->targinfo;
>       enum ip_conntrack_info ctinfo;
>       struct nf_conn *ct;
> @@ -98,7 +132,7 @@ xt_snat_target_v1(struct sk_buff *skb, const struct 
> xt_action_param *par)
>  }
>  
>  static unsigned int
> -xt_dnat_target_v1(struct sk_buff *skb, const struct xt_action_param *par)
> +xt_dnat_target_v2(struct sk_buff *skb, const struct xt_action_param *par)
>  {
>       const struct nf_nat_range *range = par->targinfo;
>       enum ip_conntrack_info ctinfo;
> @@ -162,6 +196,28 @@ static struct xt_target xt_nat_target_reg[] 
> __read_mostly = {
>                                 (1 << NF_INET_LOCAL_OUT),
>               .me             = THIS_MODULE,
>       },
> +     {
> +             .name           = "SNAT",
> +             .revision       = 2,
> +             .checkentry     = xt_nat_checkentry,
> +             .destroy        = xt_nat_destroy,
> +             .target         = xt_snat_target_v2,
> +             .targetsize     = sizeof(struct nf_nat_range),
> +             .table          = "nat",
> +             .hooks          = (1 << NF_INET_POST_ROUTING) |
> +                               (1 << NF_INET_LOCAL_IN),
> +             .me             = THIS_MODULE,
> +     },
> +     {
> +             .name           = "DNAT",
> +             .revision       = 2,
> +             .target         = xt_dnat_target_v2,
> +             .targetsize     = sizeof(struct nf_nat_range),
> +             .table          = "nat",
> +             .hooks          = (1 << NF_INET_PRE_ROUTING) |
> +                               (1 << NF_INET_LOCAL_OUT),
> +             .me             = THIS_MODULE,
> +     },
>  };
>  
>  static int __init xt_nat_init(void)

--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to