Esempio n. 1
0
static void nft_ct_l3proto_module_put(uint8_t family)
{
    if (family == NFPROTO_INET) {
        nf_ct_l3proto_module_put(NFPROTO_IPV4);
        nf_ct_l3proto_module_put(NFPROTO_IPV6);
    } else
        nf_ct_l3proto_module_put(family);
}
Esempio n. 2
0
static int nf_ct_netns_do_get(struct net *net, u8 nfproto)
{
	const struct nf_conntrack_l3proto *l3proto;
	int ret;

	might_sleep();

	ret = nf_ct_l3proto_try_module_get(nfproto);
	if (ret < 0)
		return ret;

	/* we already have a reference, can't fail */
	rcu_read_lock();
	l3proto = __nf_ct_l3proto_find(nfproto);
	rcu_read_unlock();

	if (!l3proto->net_ns_get)
		return 0;

	ret = l3proto->net_ns_get(net);
	if (ret < 0)
		nf_ct_l3proto_module_put(nfproto);

	return ret;
}
Esempio n. 3
0
static void xt_ct_tg_destroy_v1(const struct xt_tgdtor_param *par)
{
	struct xt_ct_target_info_v1 *info = par->targinfo;
	struct nf_conn *ct = info->ct;
	struct nf_conn_help *help;
#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
	struct nf_conn_timeout *timeout_ext;
	typeof(nf_ct_timeout_put_hook) timeout_put;
#endif
	if (!nf_ct_is_untracked(ct)) {
		help = nfct_help(ct);
		if (help)
			module_put(help->helper->me);

		nf_ct_l3proto_module_put(par->family);

#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
		rcu_read_lock();
		timeout_put = rcu_dereference(nf_ct_timeout_put_hook);

		if (timeout_put) {
			timeout_ext = nf_ct_timeout_find(ct);
			if (timeout_ext)
				timeout_put(timeout_ext->timeout);
		}
		rcu_read_unlock();
#endif
	}
	nf_ct_put(info->ct);
}
Esempio n. 4
0
static bool conntrack_mt_check_v1(const struct xt_mtchk_param *par)
{
	struct xt_conntrack_mtinfo1 *info = par->matchinfo;
	struct xt_conntrack_mtinfo2 *up;
	int ret = conntrack_mt_check(par);

	if (ret < 0)
		return ret;

	up = kmalloc(sizeof(*up), GFP_KERNEL);
	if (up == NULL) {
		nf_ct_l3proto_module_put(par->family);
		return -ENOMEM;
	}

	/*
	 * The strategy here is to minimize the overhead of v1 matching,
	 * by prebuilding a v2 struct and putting the pointer into the
	 * v1 dataspace.
	 */
	memcpy(up, info, offsetof(typeof(*info), state_mask));
	up->state_mask  = info->state_mask;
	up->status_mask = info->status_mask;
	*(void **)info  = up;
	return true;
}
Esempio n. 5
0
static int xt_ct_tg_check(const struct xt_tgchk_param *par,
			  struct xt_ct_target_info_v1 *info)
{
	struct nf_conntrack_tuple t;
	struct nf_conn *ct;
	int ret = -EOPNOTSUPP;

	if (info->flags & XT_CT_NOTRACK) {
		ct = NULL;
		goto out;
	}

#ifndef CONFIG_NF_CONNTRACK_ZONES
	if (info->zone)
		goto err1;
#endif

	ret = nf_ct_l3proto_try_module_get(par->family);
	if (ret < 0)
		goto err1;

	memset(&t, 0, sizeof(t));
	ct = nf_conntrack_alloc(par->net, info->zone, &t, &t, GFP_KERNEL);
	ret = PTR_ERR(ct);
	if (IS_ERR(ct))
		goto err2;

	ret = 0;
	if ((info->ct_events || info->exp_events) &&
	    !nf_ct_ecache_ext_add(ct, info->ct_events, info->exp_events,
				  GFP_KERNEL)) {
		ret = -EINVAL;
		goto err3;
	}

	if (info->helper[0]) {
		ret = xt_ct_set_helper(ct, info->helper, par);
		if (ret < 0)
			goto err3;
	}

	if (info->timeout[0]) {
		ret = xt_ct_set_timeout(ct, par, info->timeout);
		if (ret < 0)
			goto err3;
	}

	nf_conntrack_tmpl_insert(par->net, ct);
out:
	info->ct = ct;
	return 0;

err3:
	nf_conntrack_free(ct);
err2:
	nf_ct_l3proto_module_put(par->family);
err1:
	return ret;
}
Esempio n. 6
0
void nf_nat_l3proto_unregister(const struct nf_nat_l3proto *l3proto)
{
	mutex_lock(&nf_nat_proto_mutex);
	RCU_INIT_POINTER(nf_nat_l3protos[l3proto->l3proto], NULL);
	mutex_unlock(&nf_nat_proto_mutex);
	synchronize_rcu();

	nf_nat_l3proto_clean(l3proto->l3proto);
	nf_ct_l3proto_module_put(l3proto->l3proto);
}
Esempio n. 7
0
static void xt_ct_tg_destroy(const struct xt_tgdtor_param *par)
{
    struct xt_ct_target_info *info = par->targinfo;
    struct nf_conn *ct = info->ct;
    struct nf_conn_help *help;

    if (!nf_ct_is_untracked(ct)) {
        help = nfct_help(ct);
        if (help)
            module_put(help->helper->me);

        nf_ct_l3proto_module_put(par->family);
    }
    nf_ct_put(info->ct);
}
Esempio n. 8
0
static void nf_ct_netns_do_put(struct net *net, u8 nfproto)
{
	const struct nf_conntrack_l3proto *l3proto;

	might_sleep();

	/* same as nf_conntrack_netns_get(), reference assumed */
	rcu_read_lock();
	l3proto = __nf_ct_l3proto_find(nfproto);
	rcu_read_unlock();

	if (WARN_ON(!l3proto))
		return;

	if (l3proto->net_ns_put)
		l3proto->net_ns_put(net);

	nf_ct_l3proto_module_put(nfproto);
}
Esempio n. 9
0
static int nft_ct_l3proto_try_module_get(uint8_t family)
{
    int err;

    if (family == NFPROTO_INET) {
        err = nf_ct_l3proto_try_module_get(NFPROTO_IPV4);
        if (err < 0)
            goto err1;
        err = nf_ct_l3proto_try_module_get(NFPROTO_IPV6);
        if (err < 0)
            goto err2;
    } else {
        err = nf_ct_l3proto_try_module_get(family);
        if (err < 0)
            goto err1;
    }
    return 0;

err2:
    nf_ct_l3proto_module_put(NFPROTO_IPV4);
err1:
    return err;
}
Esempio n. 10
0
static int xt_ct_tg_check(const struct xt_tgchk_param *par)
{
    struct xt_ct_target_info *info = par->targinfo;
    struct nf_conntrack_tuple t;
    struct nf_conn_help *help;
    struct nf_conn *ct;
    int ret = 0;
    u8 proto;

    if (info->flags & ~XT_CT_NOTRACK)
        return -EINVAL;

    if (info->flags & XT_CT_NOTRACK) {
        ct = nf_ct_untracked_get();
        atomic_inc(&ct->ct_general.use);
        goto out;
    }

#ifndef CONFIG_NF_CONNTRACK_ZONES
    if (info->zone)
        goto err1;
#endif

    ret = nf_ct_l3proto_try_module_get(par->family);
    if (ret < 0)
        goto err1;

    memset(&t, 0, sizeof(t));
    ct = nf_conntrack_alloc(par->net, info->zone, &t, &t, GFP_KERNEL);
    ret = PTR_ERR(ct);
    if (IS_ERR(ct))
        goto err2;

    ret = 0;
    if ((info->ct_events || info->exp_events) &&
            !nf_ct_ecache_ext_add(ct, info->ct_events, info->exp_events,
                                  GFP_KERNEL))
        goto err3;

    if (info->helper[0]) {
        ret = -ENOENT;
        proto = xt_ct_find_proto(par);
        if (!proto)
            goto err3;

        ret = -ENOMEM;
        help = nf_ct_helper_ext_add(ct, GFP_KERNEL);
        if (help == NULL)
            goto err3;

        ret = -ENOENT;
        help->helper = nf_conntrack_helper_try_module_get(info->helper,
                       par->family,
                       proto);
        if (help->helper == NULL)
            goto err3;
    }

    __set_bit(IPS_TEMPLATE_BIT, &ct->status);
    __set_bit(IPS_CONFIRMED_BIT, &ct->status);
out:
    info->ct = ct;
    return 0;

err3:
    nf_conntrack_free(ct);
err2:
    nf_ct_l3proto_module_put(par->family);
err1:
    return ret;
}
static void nft_ct_destroy(const struct nft_expr *expr)
{
	struct nft_ct *priv = nft_expr_priv(expr);

	nf_ct_l3proto_module_put(priv->family);
}
Esempio n. 12
0
static void connmark_tg_destroy(const struct xt_tgdtor_param *par)
{
	nf_ct_l3proto_module_put(par->family);
}
Esempio n. 13
0
static void destroy(const struct xt_match *match, void *matchinfo)
{
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
	nf_ct_l3proto_module_put(match->family);
#endif
}
Esempio n. 14
0
static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par)
{
	struct xt_ct_target_info_v1 *info = par->targinfo;
	struct nf_conntrack_tuple t;
	struct nf_conn_help *help;
	struct nf_conn *ct;
	int ret = 0;
	u8 proto;
#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
	struct ctnl_timeout *timeout;
#endif
	if (info->flags & ~XT_CT_NOTRACK)
		return -EINVAL;

	if (info->flags & XT_CT_NOTRACK) {
		ct = nf_ct_untracked_get();
		atomic_inc(&ct->ct_general.use);
		goto out;
	}

#ifndef CONFIG_NF_CONNTRACK_ZONES
	if (info->zone)
		goto err1;
#endif

	ret = nf_ct_l3proto_try_module_get(par->family);
	if (ret < 0)
		goto err1;

	memset(&t, 0, sizeof(t));
	ct = nf_conntrack_alloc(par->net, info->zone, &t, &t, GFP_KERNEL);
	ret = PTR_ERR(ct);
	if (IS_ERR(ct))
		goto err2;

	ret = 0;
	if ((info->ct_events || info->exp_events) &&
	    !nf_ct_ecache_ext_add(ct, info->ct_events, info->exp_events,
				  GFP_KERNEL))
		goto err3;

	if (info->helper[0]) {
		ret = -ENOENT;
		proto = xt_ct_find_proto(par);
		if (!proto) {
			pr_info("You must specify a L4 protocol, "
				"and not use inversions on it.\n");
			goto err3;
		}

		ret = -ENOMEM;
		help = nf_ct_helper_ext_add(ct, GFP_KERNEL);
		if (help == NULL)
			goto err3;

		ret = -ENOENT;
		help->helper = nf_conntrack_helper_try_module_get(info->helper,
								  par->family,
								  proto);
		if (help->helper == NULL) {
			pr_info("No such helper \"%s\"\n", info->helper);
			goto err3;
		}
	}

#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
	if (info->timeout[0]) {
		typeof(nf_ct_timeout_find_get_hook) timeout_find_get;
		struct nf_conn_timeout *timeout_ext;

		rcu_read_lock();
		timeout_find_get =
			rcu_dereference(nf_ct_timeout_find_get_hook);

		if (timeout_find_get) {
			const struct ipt_entry *e = par->entryinfo;
			struct nf_conntrack_l4proto *l4proto;

			if (e->ip.invflags & IPT_INV_PROTO) {
				ret = -EINVAL;
				pr_info("You cannot use inversion on "
					 "L4 protocol\n");
				goto err4;
			}
			timeout = timeout_find_get(info->timeout);
			if (timeout == NULL) {
				ret = -ENOENT;
				pr_info("No such timeout policy \"%s\"\n",
					info->timeout);
				goto err4;
			}
			if (timeout->l3num != par->family) {
				ret = -EINVAL;
				pr_info("Timeout policy `%s' can only be "
					"used by L3 protocol number %d\n",
					info->timeout, timeout->l3num);
				goto err5;
			}
			/* Make sure the timeout policy matches any existing
			 * protocol tracker, otherwise default to generic.
			 */
			l4proto = __nf_ct_l4proto_find(par->family,
						       e->ip.proto);
			if (timeout->l4proto->l4proto != l4proto->l4proto) {
				ret = -EINVAL;
				pr_info("Timeout policy `%s' can only be "
					"used by L4 protocol number %d\n",
					info->timeout,
					timeout->l4proto->l4proto);
				goto err5;
			}
			timeout_ext = nf_ct_timeout_ext_add(ct, timeout,
							    GFP_ATOMIC);
			if (timeout_ext == NULL) {
				ret = -ENOMEM;
				goto err5;
			}
		} else {
			ret = -ENOENT;
			pr_info("Timeout policy base is empty\n");
			goto err4;
		}
		rcu_read_unlock();
	}
#endif

	__set_bit(IPS_TEMPLATE_BIT, &ct->status);
	__set_bit(IPS_CONFIRMED_BIT, &ct->status);
out:
	info->ct = ct;
	return 0;

#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
err5:
	__xt_ct_tg_timeout_put(timeout);
err4:
	rcu_read_unlock();
#endif
err3:
	nf_conntrack_free(ct);
err2:
	nf_ct_l3proto_module_put(par->family);
err1:
	return ret;
}
static void synproxy_tg6_destroy(const struct xt_tgdtor_param *par)
{
	nf_ct_l3proto_module_put(par->family);
}
Esempio n. 16
0
static int xt_ct_tg_check_v0(const struct xt_tgchk_param *par)
{
	struct xt_ct_target_info *info = par->targinfo;
	struct xt_ct_target_info_v1 info_v1 = {
		.flags 		= info->flags,
		.zone		= info->zone,
		.ct_events	= info->ct_events,
		.exp_events	= info->exp_events,
	};
	int ret;

	if (info->flags & ~XT_CT_NOTRACK)
		return -EINVAL;

	memcpy(info_v1.helper, info->helper, sizeof(info->helper));

	ret = xt_ct_tg_check(par, &info_v1);
	if (ret < 0)
		return ret;

	info->ct = info_v1.ct;

	return ret;
}

static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par)
{
	struct xt_ct_target_info_v1 *info = par->targinfo;

	if (info->flags & ~XT_CT_NOTRACK)
		return -EINVAL;

	return xt_ct_tg_check(par, par->targinfo);
}

static int xt_ct_tg_check_v2(const struct xt_tgchk_param *par)
{
	struct xt_ct_target_info_v1 *info = par->targinfo;

	if (info->flags & ~XT_CT_MASK)
		return -EINVAL;

	return xt_ct_tg_check(par, par->targinfo);
}

static void xt_ct_destroy_timeout(struct nf_conn *ct)
{
#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
	struct nf_conn_timeout *timeout_ext;
	typeof(nf_ct_timeout_put_hook) timeout_put;

	rcu_read_lock();
	timeout_put = rcu_dereference(nf_ct_timeout_put_hook);

	if (timeout_put) {
		timeout_ext = nf_ct_timeout_find(ct);
		if (timeout_ext)
			timeout_put(timeout_ext->timeout);
	}
	rcu_read_unlock();
#endif
}

static void xt_ct_tg_destroy(const struct xt_tgdtor_param *par,
			     struct xt_ct_target_info_v1 *info)
{
	struct nf_conn *ct = info->ct;
	struct nf_conn_help *help;

	if (ct && !nf_ct_is_untracked(ct)) {
		help = nfct_help(ct);
		if (help)
			module_put(help->helper->me);

		nf_ct_l3proto_module_put(par->family);

		xt_ct_destroy_timeout(ct);
		nf_ct_put(info->ct);
	}
}

static void xt_ct_tg_destroy_v0(const struct xt_tgdtor_param *par)
{
	struct xt_ct_target_info *info = par->targinfo;
	struct xt_ct_target_info_v1 info_v1 = {
		.flags 		= info->flags,
		.zone		= info->zone,
		.ct_events	= info->ct_events,
		.exp_events	= info->exp_events,
		.ct		= info->ct,
	};
	memcpy(info_v1.helper, info->helper, sizeof(info->helper));

	xt_ct_tg_destroy(par, &info_v1);
}

static void xt_ct_tg_destroy_v1(const struct xt_tgdtor_param *par)
{
	xt_ct_tg_destroy(par, par->targinfo);
}

static struct xt_target xt_ct_tg_reg[] __read_mostly = {
	{
		.name		= "CT",
		.family		= NFPROTO_UNSPEC,
		.targetsize	= sizeof(struct xt_ct_target_info),
		.checkentry	= xt_ct_tg_check_v0,
		.destroy	= xt_ct_tg_destroy_v0,
		.target		= xt_ct_target_v0,
		.table		= "raw",
		.me		= THIS_MODULE,
	},
	{
		.name		= "CT",
		.family		= NFPROTO_UNSPEC,
		.revision	= 1,
		.targetsize	= sizeof(struct xt_ct_target_info_v1),
		.checkentry	= xt_ct_tg_check_v1,
		.destroy	= xt_ct_tg_destroy_v1,
		.target		= xt_ct_target_v1,
		.table		= "raw",
		.me		= THIS_MODULE,
	},
	{
		.name		= "CT",
Esempio n. 17
0
static void
conntrack_mt_destroy(const struct xt_match *match, void *matchinfo)
{
    nf_ct_l3proto_module_put(match->family);
}
Esempio n. 18
0
static void
destroy(const struct xt_target *target, void *targinfo)
{
	nf_ct_l3proto_module_put(target->family);
}
Esempio n. 19
0
static void state_mt_destroy(const struct xt_mtdtor_param *par)
{
	nf_ct_l3proto_module_put(par->family);
}
static int nft_ct_init(const struct nft_ctx *ctx,
		       const struct nft_expr *expr,
		       const struct nlattr * const tb[])
{
	struct nft_ct *priv = nft_expr_priv(expr);
	int err;

	if (tb[NFTA_CT_DREG] == NULL ||
	    tb[NFTA_CT_KEY] == NULL)
		return -EINVAL;

	priv->key = ntohl(nla_get_be32(tb[NFTA_CT_KEY]));
	if (tb[NFTA_CT_DIRECTION] != NULL) {
		priv->dir = nla_get_u8(tb[NFTA_CT_DIRECTION]);
		switch (priv->dir) {
		case IP_CT_DIR_ORIGINAL:
		case IP_CT_DIR_REPLY:
			break;
		default:
			return -EINVAL;
		}
	}

	switch (priv->key) {
	case NFT_CT_STATE:
	case NFT_CT_DIRECTION:
	case NFT_CT_STATUS:
#ifdef CONFIG_NF_CONNTRACK_MARK
	case NFT_CT_MARK:
#endif
#ifdef CONFIG_NF_CONNTRACK_SECMARK
	case NFT_CT_SECMARK:
#endif
	case NFT_CT_EXPIRATION:
	case NFT_CT_HELPER:
		if (tb[NFTA_CT_DIRECTION] != NULL)
			return -EINVAL;
		break;
	case NFT_CT_PROTOCOL:
	case NFT_CT_SRC:
	case NFT_CT_DST:
	case NFT_CT_PROTO_SRC:
	case NFT_CT_PROTO_DST:
		if (tb[NFTA_CT_DIRECTION] == NULL)
			return -EINVAL;
		break;
	default:
		return -EOPNOTSUPP;
	}

	err = nf_ct_l3proto_try_module_get(ctx->afi->family);
	if (err < 0)
		return err;
	priv->family = ctx->afi->family;

	priv->dreg = ntohl(nla_get_be32(tb[NFTA_CT_DREG]));
	err = nft_validate_output_register(priv->dreg);
	if (err < 0)
		goto err1;

	err = nft_validate_data_load(ctx, priv->dreg, NULL, NFT_DATA_VALUE);
	if (err < 0)
		goto err1;
	return 0;

err1:
	nf_ct_l3proto_module_put(ctx->afi->family);
	return err;
}