On Tue, 21 Mar 2017, Josh Hunt wrote:

> Convert netmask to store cidr and netmask.
> 
> Signed-off-by: Josh Hunt <joh...@akamai.com>
> ---
>  include/libipset/data.h         |  5 ++-
>  include/libipset/linux_ip_set.h |  5 +++
>  include/libipset/print.h        |  3 ++
>  lib/data.c                      | 25 +++++++++++++--
>  lib/debug.c                     |  1 +
>  lib/parse.c                     | 68 
> ++++++++++++++++++++++++++++++++++++-----
>  lib/print.c                     | 39 +++++++++++++++++++++--
>  lib/session.c                   |  8 +++++
>  8 files changed, 141 insertions(+), 13 deletions(-)
> 
> diff --git a/include/libipset/data.h b/include/libipset/data.h
> index ca21890..0314cfb 100644
> --- a/include/libipset/data.h
> +++ b/include/libipset/data.h
> @@ -37,6 +37,7 @@ enum ipset_opt {
>       IPSET_OPT_RESIZE,
>       IPSET_OPT_SIZE,
>       IPSET_OPT_FORCEADD,
> +     IPSET_OPT_NETMASK_MASK,
>       /* Create-specific options, filled out by the kernel */
>       IPSET_OPT_ELEMENTS,
>       IPSET_OPT_REFERENCES,
> @@ -66,6 +67,7 @@ enum ipset_opt {
>       IPSET_OPT_SKBMARK,
>       IPSET_OPT_SKBPRIO,
>       IPSET_OPT_SKBQUEUE,
> +     IPSET_OPT_NETMASK_FLAG,
>       /* Internal options */
>       IPSET_OPT_FLAGS = 48,   /* IPSET_FLAG_EXIST| */
>       IPSET_OPT_CADT_FLAGS,   /* IPSET_FLAG_BEFORE| */
> @@ -101,7 +103,8 @@ enum ipset_opt {
>       | IPSET_FLAG(IPSET_OPT_COUNTERS)\
>       | IPSET_FLAG(IPSET_OPT_CREATE_COMMENT)\
>       | IPSET_FLAG(IPSET_OPT_FORCEADD)\
> -     | IPSET_FLAG(IPSET_OPT_SKBINFO))
> +     | IPSET_FLAG(IPSET_OPT_SKBINFO)\
> +     | IPSET_FLAG(IPSET_OPT_NETMASK_MASK))
>  
>  #define IPSET_ADT_FLAGS                      \
>       (IPSET_FLAG(IPSET_OPT_IP)       \
> diff --git a/include/libipset/linux_ip_set.h b/include/libipset/linux_ip_set.h
> index def91b9..4f93886 100644
> --- a/include/libipset/linux_ip_set.h
> +++ b/include/libipset/linux_ip_set.h
> @@ -84,6 +84,7 @@ enum {
>       IPSET_ATTR_CADT_LINENO = IPSET_ATTR_LINENO,     /* 9 */
>       IPSET_ATTR_MARK,        /* 10 */
>       IPSET_ATTR_MARKMASK,    /* 11 */
> +     IPSET_ATTR_NETMASK_MASK,/* 12 */
>       /* Reserve empty slots */
>       IPSET_ATTR_CADT_MAX = 16,
>       /* Create-only specific attributes */
> @@ -199,6 +200,8 @@ enum ipset_cadt_flags {
>       IPSET_FLAG_WITH_FORCEADD = (1 << IPSET_FLAG_BIT_WITH_FORCEADD),
>       IPSET_FLAG_BIT_WITH_SKBINFO = 6,
>       IPSET_FLAG_WITH_SKBINFO = (1 << IPSET_FLAG_BIT_WITH_SKBINFO),
> +     IPSET_FLAG_BIT_WITH_NETMASK = 7,
> +     IPSET_FLAG_WITH_NETMASK = (1 << IPSET_FLAG_BIT_WITH_NETMASK),
>       IPSET_FLAG_CADT_MAX     = 15,
>  };
>  
> @@ -206,6 +209,8 @@ enum ipset_cadt_flags {
>  enum ipset_create_flags {
>       IPSET_CREATE_FLAG_BIT_FORCEADD = 0,
>       IPSET_CREATE_FLAG_FORCEADD = (1 << IPSET_CREATE_FLAG_BIT_FORCEADD),
> +     IPSET_CREATE_FLAG_BIT_NETMASK = 1,
> +     IPSET_CREATE_FLAG_NETMASK = (1 << IPSET_CREATE_FLAG_BIT_NETMASK),
>       IPSET_CREATE_FLAG_BIT_MAX = 7,
>  };
>  
> diff --git a/include/libipset/print.h b/include/libipset/print.h
> index 2103ce1..f9e77d3 100644
> --- a/include/libipset/print.h
> +++ b/include/libipset/print.h
> @@ -74,6 +74,9 @@ extern int ipset_print_flag(char *buf, unsigned int len,
>  extern int ipset_print_elem(char *buf, unsigned int len,
>                           const struct ipset_data *data,
>                           enum ipset_opt opt, uint8_t env);
> +extern int ipset_print_netmask(char *buf, unsigned int len,
> +                         const struct ipset_data *data,
> +                         enum ipset_opt opt, uint8_t env);
>  
>  #define ipset_print_portnum  ipset_print_number
>  
> diff --git a/lib/data.c b/lib/data.c
> index 8372a2f..951a124 100644
> --- a/lib/data.c
> +++ b/lib/data.c
> @@ -24,6 +24,11 @@
>   * We always store the data in host order, *except* IP addresses.
>   */
>  
> +struct ipset_netmask {
> +     uint8_t cidr;
> +     union nf_inet_addr mask;
> +};
> +
>  struct ipset_data {
>       /* Option bits: which fields are set */
>       uint64_t bits;
> @@ -51,7 +56,7 @@ struct ipset_data {
>               struct {
>                       uint8_t probes;
>                       uint8_t resize;
> -                     uint8_t netmask;
> +                     struct ipset_netmask netmask;
>                       uint32_t hashsize;
>                       uint32_t maxelem;
>                       uint32_t markmask;
> @@ -295,7 +300,13 @@ ipset_data_set(struct ipset_data *data, enum ipset_opt 
> opt, const void *value)
>               data->create.markmask = *(const uint32_t *) value;
>               break;
>       case IPSET_OPT_NETMASK:
> -             data->create.netmask = *(const uint8_t *) value;
> +             data->create.netmask.cidr = *(const uint8_t *) value;
> +             break;
> +     case IPSET_OPT_NETMASK_MASK:
> +             if (!(data->family == NFPROTO_IPV4 ||
> +                   data->family == NFPROTO_IPV6))
> +                     return -1;
> +             copy_addr(data->family, &data->create.netmask.mask, value);
>               break;
>       case IPSET_OPT_PROBES:
>               data->create.probes = *(const uint8_t *) value;
> @@ -318,6 +329,9 @@ ipset_data_set(struct ipset_data *data, enum ipset_opt 
> opt, const void *value)
>       case IPSET_OPT_SKBINFO:
>               cadt_flag_type_attr(data, opt, IPSET_FLAG_WITH_SKBINFO);
>               break;
> +     case IPSET_OPT_NETMASK_FLAG:
> +             cadt_flag_type_attr(data, opt, IPSET_FLAG_WITH_NETMASK);
> +             break;
>       /* Create-specific options, filled out by the kernel */
>       case IPSET_OPT_ELEMENTS:
>               data->create.elements = *(const uint32_t *) value;
> @@ -495,7 +509,9 @@ ipset_data_get(const struct ipset_data *data, enum 
> ipset_opt opt)
>       case IPSET_OPT_MARKMASK:
>               return &data->create.markmask;
>       case IPSET_OPT_NETMASK:
> -             return &data->create.netmask;
> +             return &data->create.netmask.cidr;
> +     case IPSET_OPT_NETMASK_MASK:
> +             return &data->create.netmask.mask;
>       case IPSET_OPT_PROBES:
>               return &data->create.probes;
>       case IPSET_OPT_RESIZE:
> @@ -558,6 +574,7 @@ ipset_data_get(const struct ipset_data *data, enum 
> ipset_opt opt)
>       case IPSET_OPT_CREATE_COMMENT:
>       case IPSET_OPT_FORCEADD:
>       case IPSET_OPT_SKBINFO:
> +     case IPSET_OPT_NETMASK_FLAG:
>               return &data->cadt_flags;
>       default:
>               return NULL;
> @@ -581,6 +598,7 @@ ipset_data_sizeof(enum ipset_opt opt, uint8_t family)
>       case IPSET_OPT_IP_TO:
>       case IPSET_OPT_IP2:
>       case IPSET_OPT_IP2_TO:
> +     case IPSET_OPT_NETMASK_MASK:
>               return family == NFPROTO_IPV4 ? sizeof(uint32_t)
>                                        : sizeof(struct in6_addr);
>       case IPSET_OPT_MARK:
> @@ -623,6 +641,7 @@ ipset_data_sizeof(enum ipset_opt opt, uint8_t family)
>       case IPSET_OPT_NOMATCH:
>       case IPSET_OPT_COUNTERS:
>       case IPSET_OPT_FORCEADD:
> +     case IPSET_OPT_NETMASK_FLAG:
>               return sizeof(uint32_t);
>       case IPSET_OPT_ADT_COMMENT:
>               return IPSET_MAX_COMMENT_SIZE + 1;
> diff --git a/lib/debug.c b/lib/debug.c
> index 6f831ec..a32f709 100644
> --- a/lib/debug.c
> +++ b/lib/debug.c
> @@ -40,6 +40,7 @@ static const struct ipset_attrname createattr2name[] = {
>       [IPSET_ATTR_MAXELEM]    = { .name = "MAXELEM" },
>       [IPSET_ATTR_MARKMASK]   = { .name = "MARKMASK" },
>       [IPSET_ATTR_NETMASK]    = { .name = "NETMASK" },
> +     [IPSET_ATTR_NETMASK_MASK] = { .name = "NETMASK_MASK" },
>       [IPSET_ATTR_PROBES]     = { .name = "PROBES" },
>       [IPSET_ATTR_RESIZE]     = { .name = "RESIZE" },
>       [IPSET_ATTR_SIZE]       = { .name = "SIZE" },
> diff --git a/lib/parse.c b/lib/parse.c
> index 88d2888..5c41c37 100644
> --- a/lib/parse.c
> +++ b/lib/parse.c
> @@ -1654,7 +1654,35 @@ ipset_parse_uint8(struct ipset_session *session,
>  }
>  
>  /**
> + * ipset_cidr_to_mask - convert cidr value to mask stored in nf_inet_addr
> + * @addr: store resulting mask here
> + * @cidr: value to convert to mask
> + * @family: INET family type
> + *
> + * Parse cidr value and convert it into a mask stored in an nf_inet_addr.
> + */
> +static void
> +ipset_cidr_to_mask(union nf_inet_addr *addr, uint8_t cidr, uint8_t family)
> +{
> +     uint8_t i;
> +     uint8_t addrsize = (family == NFPROTO_IPV4) ? 1 : 4;
> +
> +        for (i=0; i < addrsize; i++) {
> +             if (!cidr) {
> +                     addr->all[i] = 0;
> +             } else if (cidr >= 32) {
> +                     addr->all[i] = 0xffffffff;
> +                     cidr -= 32;
> +             } else {
> +                     addr->all[i] = htonl(~((1 << (32 - cidr)) - 1));
> +                     break;
> +             }
> +     }
> +}

If either IPSET_ATTR_NETMASK or IPSET_ATTR_NETMASK_MASK is passed then
I think ipset_cidr_to_mask() is unnecessary.

> +/**
>   * ipset_parse_netmask - parse string as a CIDR netmask value
> + *                    or netmask value
>   * @session: session structure
>   * @opt: option kind of the data
>   * @str: string to parse
> @@ -1669,12 +1697,13 @@ int
>  ipset_parse_netmask(struct ipset_session *session,
>                   enum ipset_opt opt, const char *str)
>  {
> -     uint8_t family, cidr;
> +     uint8_t family, cidr = 0;
>       struct ipset_data *data;
>       int err = 0;
> +     union nf_inet_addr netmask = {};
>  
>       assert(session);
> -     assert(opt == IPSET_OPT_NETMASK);
> +     assert(opt == IPSET_OPT_NETMASK_MASK || opt == IPSET_OPT_NETMASK);
>       assert(str);
>  
>       data = ipset_session_data(session);
> @@ -1684,16 +1713,41 @@ ipset_parse_netmask(struct ipset_session *session,
>               ipset_data_set(data, IPSET_OPT_FAMILY, &family);
>       }
>  
> +     /* Try to parse input as CIDR first */
>       err = string_to_cidr(session, str, 1,
>                            family == NFPROTO_IPV4 ? 32 : 128,
>                            &cidr);
>  
> -     if (err)
> -             return syntax_err("netmask is out of the inclusive range "
> -                               "of 1-%u",
> -                               family == NFPROTO_IPV4 ? 32 : 128);
> +     if (opt == IPSET_OPT_NETMASK) {
> +             if (err)
> +                     return syntax_err("netmask is out of the inclusive 
> range "
> +                                       "of 1-%u",
> +                                       family == NFPROTO_IPV4 ? 32 : 128);
> +
> +             return ipset_data_set(data, opt, &cidr);
> +     } else {
> +
> +             /* If that fails, attempt to parse as an IP addr */
> +             if (err) {
> +                     /* Store mask value as input by user */
> +                     err = parse_ipaddr(session, opt, str, family);
> +                     if (err)
> +                             return err;
>  
> -     return ipset_data_set(data, opt, &cidr);
> +                     /* Check if it's a CIDR and store if it is */
> +                     netmask = *(const union nf_inet_addr *) 
> ipset_data_get(data, IPSET_OPT_NETMASK_MASK);
> +             } else {
> +                     ipset_cidr_to_mask(&netmask, cidr, family);
> +
> +                     err = ipset_data_set(data, opt, &netmask);
> +                     if (err)
> +                             return err;
> +             }
> +
> +             ipset_data_set(data, IPSET_OPT_NETMASK_FLAG, &family);
> +
> +             return ipset_data_set(data, IPSET_OPT_NETMASK, &cidr);
> +     }
>  }

The parser should work with IPSET_OPT_NETMASK only and depending on the 
value, it should set either IPSET_OPT_NETMASK (cidr is parsed) or
both IPSET_OPT_NETMASK_MASK (wildcard mask is passed) and  
IPSET_CREATE_FLAG_NETMASK.

>  /**
> diff --git a/lib/print.c b/lib/print.c
> index 7dd229e..cc450c6 100644
> --- a/lib/print.c
> +++ b/lib/print.c
> @@ -241,6 +241,39 @@ SNPRINTF_IP(32, 4)
>  SNPRINTF_IP(128, 6)
>  
>  /**
> + * ipset_print_netmask - print netmask in either CIDR or address to string
> + * @buf: printing buffer
> + * @len: length of available buffer space
> + * @data: data blob
> + * @opt: the option kind
> + * @env: environment flags
> + *
> + * If the netmask can be represented as a CIDR print that, otherwise print
> + * the mask value.
> + *
> + * Return length of printed string or error size.
> + */
> +int
> +ipset_print_netmask(char *buf, unsigned int len,
> +                 const struct ipset_data *data, enum ipset_opt opt,
> +                 uint8_t env)
> +{
> +     uint8_t cidr;
> +
> +     assert(buf);
> +     assert(len > 0);
> +     assert(data);
> +     assert(opt == IPSET_OPT_NETMASK_MASK);
> +
> +     cidr = *(const uint8_t *) ipset_data_get(data, IPSET_OPT_NETMASK);
> +
> +     if (cidr)
> +             return snprintf(buf, len, "%u", cidr);
> +     else
> +             return ipset_print_ip(buf, len, data, opt, env);
> +}
> +
> +/**
>   * ipset_print_ip - print IPv4|IPv6 address to string
>   * @buf: printing buffer
>   * @len: length of available buffer space
> @@ -265,7 +298,7 @@ ipset_print_ip(char *buf, unsigned int len,
>       assert(buf);
>       assert(len > 0);
>       assert(data);
> -     assert(opt == IPSET_OPT_IP || opt == IPSET_OPT_IP2);
> +     assert(opt == IPSET_OPT_IP || opt == IPSET_OPT_IP2 || opt == 
> IPSET_OPT_NETMASK_MASK);
>  
>       D("len: %u", len);
>       family = ipset_data_family(data);
> @@ -944,7 +977,6 @@ ipset_print_data(char *buf, unsigned int len,
>       case IPSET_OPT_HASHSIZE:
>       case IPSET_OPT_MAXELEM:
>       case IPSET_OPT_MARKMASK:
> -     case IPSET_OPT_NETMASK:
>       case IPSET_OPT_PROBES:
>       case IPSET_OPT_RESIZE:
>       case IPSET_OPT_TIMEOUT:
> @@ -953,6 +985,9 @@ ipset_print_data(char *buf, unsigned int len,
>       case IPSET_OPT_SIZE:
>               size = ipset_print_number(buf, len, data, opt, env);
>               break;
> +     case IPSET_OPT_NETMASK_MASK:
> +             size = ipset_print_netmask(buf, len, data, opt, env);
> +             break;
>       default:
>               return -1;
>       }
> diff --git a/lib/session.c b/lib/session.c
> index 1bdaaa7..55eab83 100644
> --- a/lib/session.c
> +++ b/lib/session.c
> @@ -414,6 +414,10 @@ static const struct ipset_attr_policy create_attrs[] = {
>               .type = MNL_TYPE_U32,
>               .opt = IPSET_OPT_MEMSIZE,
>       },
> +     [IPSET_ATTR_NETMASK_MASK] = {
> +             .type = MNL_TYPE_NESTED,
> +             .opt = IPSET_OPT_NETMASK_MASK,
> +     },
>  };
>  
>  static const struct ipset_attr_policy adt_attrs[] = {
> @@ -1494,6 +1498,10 @@ rawdata2attr(struct ipset_session *session, struct 
> nlmsghdr *nlh,
>       if (attr->type == MNL_TYPE_NESTED) {
>               /* IP addresses */
>               struct nlattr *nested;
> +
> +             if (type == IPSET_ATTR_NETMASK_MASK)
> +                     family = ipset_data_family(session->data);
> +
>               int atype = family == NFPROTO_IPV4 ? IPSET_ATTR_IPADDR_IPV4
>                                             : IPSET_ATTR_IPADDR_IPV6;
>  
> -- 
> 1.9.1

Best regards,
Jozsef
-
E-mail  : kad...@blackhole.kfki.hu, kadlecsik.joz...@wigner.mta.hu
PGP key : http://www.kfki.hu/~kadlec/pgp_public_key.txt
Address : Wigner Research Centre for Physics, Hungarian Academy of Sciences
          H-1525 Budapest 114, POB. 49, Hungary
--
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