Re: [PATCH 1/5] ipset: netmask: expand to support cidr and full mask

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, 21 Mar 2017, Josh Hunt wrote:

> Convert netmask to store cidr and netmask.
> 
> Signed-off-by: Josh Hunt <johunt@xxxxxxxxxx>
> ---
>  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  : kadlec@xxxxxxxxxxxxxxxxx, kadlecsik.jozsef@xxxxxxxxxxxxx
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 majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Netfitler Users]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux