netfilter-devel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Pablo Neira Ayuso <pablo@netfilter.org>
To: Jan Engelhardt <jengelh@medozas.de>
Cc: netfilter-devel@vger.kernel.org
Subject: Re: [PATCH 3/7] netfilter: xtables2: chain creation and deletion
Date: Tue, 14 Feb 2012 12:07:12 +0100	[thread overview]
Message-ID: <20120214110712.GA27221@1984> (raw)
In-Reply-To: <1326990381-14534-4-git-send-email-jengelh@medozas.de>

On Thu, Jan 19, 2012 at 05:26:17PM +0100, Jan Engelhardt wrote:
[...]
> diff --git a/net/netfilter/xt2_nfnetlink.c b/net/netfilter/xt2_nfnetlink.c
> index 3dc241f..b50e468d 100644
> --- a/net/netfilter/xt2_nfnetlink.c
> +++ b/net/netfilter/xt2_nfnetlink.c
> @@ -17,6 +17,7 @@
>  #include <linux/netfilter/nfnetlink.h>
>  #include <linux/netfilter/nfnetlink_xtables.h>
>  #include <net/netlink.h>
> +#include <net/sock.h>
>  #include <net/netfilter/x_tables2.h>
>  
>  MODULE_DESCRIPTION("Xtables2 nfnetlink interface");
> @@ -69,6 +70,66 @@ xtnetlink_fill(struct sk_buff *skb, const struct xtnetlink_pktref *old,
>  }
>  
>  /**
> + * @ref:	skb/nl pointers that will be filled in (secondary return values)
> + * @old:	pointers to the original incoming skb/nl headers
> + *
> + * xtnetlink_fill can be used when the outgoing skb already exists (e.g. in
> + * case of a dump operation), but for non-dump responses, we have to create it
> + * ourselves.
> + */
> +static int
> +xtnetlink_new_fill(struct xtnetlink_pktref *ref,
> +		   const struct xtnetlink_pktref *old)
> +{
> +	ref->skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
> +	if (ref->skb == NULL)
> +		return -ENOMEM;
> +	ref->msg = xtnetlink_fill(ref->skb, old, 0);
> +	if (IS_ERR(ref->msg)) {
> +		kfree_skb(ref->skb);
> +		return PTR_ERR(ref->msg);
> +	}
> +	return 0;
> +}
> +
> +/**
> + * @xtnl:	socket to send the error packet out on
> + * @old:	pointers to the original incoming skb/nl headers
> + * @errcode:	last error code
> + *
> + * Create and send out an NFXT error packet. If @errcode is < 0, it indicates
> + * a system-level error (such as %-ENOMEM), reported back using %NFXTA_ERRNO.
> + * If @errcode is >= 0, it indicates an NFXT-specific error codes (%NFXTE_*),
> + * which is more fine grained than the dreaded %EINVAL, and which is reported
> + * back using %NFXTA_XTERRNO.
> + */
> +static int
> +xtnetlink_error(struct sock *xtnl, const struct xtnetlink_pktref *old,
> +		int errcode)
> +{
> +	struct xtnetlink_pktref ref;
> +	int ret;
> +
> +	ret = xtnetlink_new_fill(&ref, old);
> +	if (ret < 0)
> +		return ret;
> +	if (errcode < 0)
> +		/* Prefer positive numbers on the wire */
> +		NLA_PUT_U32(ref.skb, NFXTA_ERRNO, -errcode);
> +	else
> +		NLA_PUT_U32(ref.skb, NFXTA_XTERRNO, errcode);
> +	nlmsg_end(ref.skb, ref.msg);
> +	ret = netlink_unicast(xtnl, ref.skb, NETLINK_CB(old->skb).pid,
> +			      MSG_DONTWAIT);
> +	if (ret < 0)
> +		return ret;
> +	/* ret is skb->len, but values >0 mean error to the caller -.- */
> +	return 0;
> + nla_put_failure:
> +	return -ENOBUFS;
> +}

You seem to be using some similar approach that ipset uses for error
handling. I like the idea of having fine grain error handling indeed,
but I think we can extend the Netlink framework to integrate as part
of NLMSG_ERR message types.

My idea is to attach the specific error at the end of the NLMSG_ERR,
IIRC we need to allow passing one callback to netlink_ack to add the
specific error message after the generic netlink error message.

I think this will be also backward compatible with existing netlink
library since they will ignore the trailing part of the error message
that they don't know how to interpret.

> +static int
> +xtnetlink_chain_new(struct sock *xtnl, struct sk_buff *iskb,
> +		    const struct nlmsghdr *imsg, const struct nlattr *const *ad)
> +{
> +	struct xt2_pernet_data *pnet = xtables2_pernet(sock_net(xtnl));
> +	struct xtnetlink_pktref ref = {.c_skb = iskb, .c_msg = imsg};
> +	const struct nlattr *attr;
> +	struct xt2_table *table;
> +	struct xt2_chain *chain;
> +	const char *name;
> +	int ret = 0;
> +
> +	attr = nlmsg_find_attr(imsg, sizeof(struct nfgenmsg), NFXTA_NAME);
> +	if (attr == NULL)
> +		return xtnetlink_error(xtnl, &ref, NFXTE_ATTRSET_INCOMPLETE);
> +	name = nla_data(attr);
> +	if (*name == '\0')

I think you may better identify this special chains with some flags?
You end up defining flags for objects sooner or later instead of using
this special name.

> +		/* Anonymous chains are internal. */
> +		return xtnetlink_error(xtnl, &ref, NFXTE_CHAIN_INVALID_NAME);
> +	/*
> +	 * The table needs to stay, but note that rcu_read_lock cannot be used,
> +	 * since we might sleep.
> +	 */
> +	mutex_lock(&pnet->master_lock);
> +	table = pnet->master;
> +	mutex_lock(&table->lock);
> +	if (xt2_chain_lookup(table, name) != NULL) {
> +		ret = xtnetlink_error(xtnl, &ref, NFXTE_CHAIN_EXISTS);
> +	} else {
> +		chain = xt2_chain_new(table, name);
> +		if (IS_ERR(chain))
> +			ret = PTR_ERR(chain);
> +		/* Use NFXTE error codes whenever possible. */
> +		if (ret == -ENAMETOOLONG)
> +			ret = NFXTE_CHAIN_NAMETOOLONG;
> +		ret = xtnetlink_error(xtnl, &ref, ret);
> +	}
> +	mutex_unlock(&table->lock);
> +	mutex_unlock(&pnet->master_lock);
> +	return ret;
> +}
> +
> +/**
> + * Act on a %NFXTM_CHAIN_DEL message.
> + */
> +static int
> +xtnetlink_chain_del(struct sock *xtnl, struct sk_buff *iskb,
> +		    const struct nlmsghdr *imsg,
> +		    const struct nlattr *const *ad)
> +{
> +	struct xt2_pernet_data *pnet = xtables2_pernet(sock_net(xtnl));
> +	struct xtnetlink_pktref ref = {.c_skb = iskb, .c_msg = imsg};
> +	const struct nlattr *name_attr;
> +	struct xt2_table *table;
> +	struct xt2_chain *chain;
> +	const char *name;
> +	int ret = 0;
> +
> +	name_attr = nlmsg_find_attr(imsg, sizeof(struct nfgenmsg), NFXTA_NAME);
> +	if (name_attr == NULL)
> +		return xtnetlink_error(xtnl, &ref, NFXTE_ATTRSET_INCOMPLETE);
> +	name = nla_data(name_attr);
> +	if (*name == '\0')
> +		return xtnetlink_error(xtnl, &ref, NFXTE_CHAIN_NOENT);
> +
> +	mutex_lock(&pnet->master_lock);
> +	table = pnet->master;
> +	mutex_lock(&table->lock);
> +	chain = xt2_chain_lookup(table, name);
> +	if (chain != NULL)
> +		xt2_chain_free(chain);
> +	else
> +		ret = NFXTE_CHAIN_NOENT;
> +	ret = xtnetlink_error(xtnl, &ref, ret);
> +	mutex_unlock(&table->lock);
> +	mutex_unlock(&pnet->master_lock);
> +	return ret;
> +}
> +
>  static const struct nla_policy xtnetlink_policy[] = {
>  	[NFXTA_NAME] = {.type = NLA_NUL_STRING},
> +	[NFXTA_ERRNO] = {.type = NLA_U32},
> +	[NFXTA_XTERRNO] = {.type = NLA_U32},
>  };
>  
>  /*
>   * Use the same policy for all messages. I do not want to see EINVAL anytime
>   * soon again just because I forgot sending an attribute from userspace.
> - * (If such occurs, it will be dealt with %NFXTE_ATTRSET_INCOMPLETE, tbd.)
> + * (If such occurs, it will be dealt with %NFXTE_ATTRSET_INCOMPLETE.)
>   */
>  #define pol \
>  	.policy = xtnetlink_policy, \
> @@ -128,6 +270,8 @@ static const struct nla_policy xtnetlink_policy[] = {
>  static const struct nfnl_callback xtnetlink_callback[] = {
>  	[0] = {.call = xtnetlink_ignore},
>  	[NFXTM_IDENTIFY] = {.call = xtnetlink_identify, pol},
> +	[NFXTM_CHAIN_NEW] = {.call = xtnetlink_chain_new, pol},
> +	[NFXTM_CHAIN_DEL] = {.call = xtnetlink_chain_del, pol},
>  };
>  #undef pol
>  
> -- 
> 1.7.7
> 

  reply	other threads:[~2012-02-14 11:07 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-01-19 16:26 xtables2 a8, netlink interface Jan Engelhardt
2012-01-19 16:26 ` [PATCH 1/7] netfilter: xtables2: initial table skeletal functions Jan Engelhardt
2012-01-20  0:23   ` Pablo Neira Ayuso
2012-01-20  9:23     ` Jan Engelhardt
2012-01-19 16:26 ` [PATCH 2/7] netfilter: xtables2: initial Netlink interface Jan Engelhardt
2012-02-14 10:47   ` Pablo Neira Ayuso
2012-02-14 15:56     ` Jan Engelhardt
2012-02-14 19:53       ` Pablo Neira Ayuso
2012-01-19 16:26 ` [PATCH 3/7] netfilter: xtables2: chain creation and deletion Jan Engelhardt
2012-02-14 11:07   ` Pablo Neira Ayuso [this message]
2012-01-19 16:26 ` [PATCH 4/7] netfilter: xtables2: chain renaming support Jan Engelhardt
2012-01-19 16:26 ` [PATCH 5/7] netfilter: xtables2: initial table replace support Jan Engelhardt
2012-01-19 16:26 ` [PATCH 6/7] netfilter: xtables2: transaction abort support Jan Engelhardt
2012-01-19 16:26 ` [PATCH 7/7] netfilter: xtables2: redirect writes into transaction buffer Jan Engelhardt
2012-01-20  0:56 ` xtables2 a8, netlink interface Stephen Hemminger
2012-01-20  8:33   ` Jan Engelhardt
2012-01-20  9:23     ` Dave Taht
2012-01-20 16:50       ` Stephen Hemminger
2012-01-21 14:10 ` Jozsef Kadlecsik
2012-01-21 15:53   ` Jan Engelhardt
2012-01-21 20:21     ` Jozsef Kadlecsik
2012-01-23 15:42       ` Jan Engelhardt
2012-01-23 19:48         ` Jozsef Kadlecsik

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20120214110712.GA27221@1984 \
    --to=pablo@netfilter.org \
    --cc=jengelh@medozas.de \
    --cc=netfilter-devel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).