コード例 #1
0
ファイル: nft_masq.c プロジェクト: 19Dan01/linux
int nft_masq_init(const struct nft_ctx *ctx,
		  const struct nft_expr *expr,
		  const struct nlattr * const tb[])
{
	struct nft_masq *priv = nft_expr_priv(expr);
	int err;

	err = nft_masq_validate(ctx, expr, NULL);
	if (err)
		return err;

	if (tb[NFTA_MASQ_FLAGS] == NULL)
		return 0;

	priv->flags = ntohl(nla_get_be32(tb[NFTA_MASQ_FLAGS]));
	if (priv->flags & ~NF_NAT_RANGE_MASK)
		return -EINVAL;

	return 0;
}
コード例 #2
0
ファイル: nft_cmp.c プロジェクト: AshishNamdev/linux
static int nft_cmp_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
			const struct nlattr * const tb[])
{
	struct nft_cmp_expr *priv = nft_expr_priv(expr);
	struct nft_data_desc desc;
	int err;

	err = nft_data_init(NULL, &priv->data, sizeof(priv->data), &desc,
			    tb[NFTA_CMP_DATA]);
	BUG_ON(err < 0);

	priv->sreg = nft_parse_register(tb[NFTA_CMP_SREG]);
	err = nft_validate_register_load(priv->sreg, desc.len);
	if (err < 0)
		return err;

	priv->op  = ntohl(nla_get_be32(tb[NFTA_CMP_OP]));
	priv->len = desc.len;
	return 0;
}
コード例 #3
0
static const struct nft_expr_ops *
nft_ng_select_ops(const struct nft_ctx *ctx, const struct nlattr * const tb[])
{
    u32 type;

    if (!tb[NFTA_NG_DREG]	 ||
            !tb[NFTA_NG_MODULUS] ||
            !tb[NFTA_NG_TYPE])
        return ERR_PTR(-EINVAL);

    type = ntohl(nla_get_be32(tb[NFTA_NG_TYPE]));

    switch (type) {
    case NFT_NG_INCREMENTAL:
        return &nft_ng_inc_ops;
    case NFT_NG_RANDOM:
        return &nft_ng_random_ops;
    }

    return ERR_PTR(-EINVAL);
}
コード例 #4
0
ファイル: nf_conntrack_proto_dccp.c プロジェクト: Lyude/linux
static int dccp_timeout_nlattr_to_obj(struct nlattr *tb[],
				      struct net *net, void *data)
{
	struct nf_dccp_net *dn = dccp_pernet(net);
	unsigned int *timeouts = data;
	int i;

	/* set default DCCP timeouts. */
	for (i=0; i<CT_DCCP_MAX; i++)
		timeouts[i] = dn->dccp_timeout[i];

	/* there's a 1:1 mapping between attributes and protocol states. */
	for (i=CTA_TIMEOUT_DCCP_UNSPEC+1; i<CTA_TIMEOUT_DCCP_MAX+1; i++) {
		if (tb[i]) {
			timeouts[i] = ntohl(nla_get_be32(tb[i])) * HZ;
		}
	}

	timeouts[CTA_TIMEOUT_DCCP_UNSPEC] = timeouts[CTA_TIMEOUT_DCCP_REQUEST];
	return 0;
}
コード例 #5
0
ファイル: nft_meta_bridge.c プロジェクト: acton393/linux
static int nft_meta_bridge_get_init(const struct nft_ctx *ctx,
				    const struct nft_expr *expr,
				    const struct nlattr * const tb[])
{
	struct nft_meta *priv = nft_expr_priv(expr);
	unsigned int len;

	priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY]));
	switch (priv->key) {
	case NFT_META_BRI_IIFNAME:
	case NFT_META_BRI_OIFNAME:
		len = IFNAMSIZ;
		break;
	default:
		return nft_meta_get_init(ctx, expr, tb);
	}

	priv->dreg = nft_parse_register(tb[NFTA_META_DREG]);
	return nft_validate_register_store(ctx, priv->dreg, NULL,
					   NFT_DATA_VALUE, len);
}
コード例 #6
0
static int nft_ct_set_init(const struct nft_ctx *ctx,
                           const struct nft_expr *expr,
                           const struct nlattr * const tb[])
{
    struct nft_ct *priv = nft_expr_priv(expr);
    unsigned int len;
    int err;

    priv->key = ntohl(nla_get_be32(tb[NFTA_CT_KEY]));
    switch (priv->key) {
#ifdef CONFIG_NF_CONNTRACK_MARK
    case NFT_CT_MARK:
        len = FIELD_SIZEOF(struct nf_conn, mark);
        break;
#endif
#ifdef CONFIG_NF_CONNTRACK_LABELS
    case NFT_CT_LABELS:
        if (tb[NFTA_CT_DIRECTION])
            return -EINVAL;
        len = NF_CT_LABELS_MAX_SIZE;
        err = nf_connlabels_get(ctx->net, (len * BITS_PER_BYTE) - 1);
        if (err)
            return err;
        break;
#endif
    default:
        return -EOPNOTSUPP;
    }

    priv->sreg = nft_parse_register(tb[NFTA_CT_SREG]);
    err = nft_validate_register_load(priv->sreg, len);
    if (err < 0)
        return err;

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

    return 0;
}
コード例 #7
0
static int nft_meta_init(const struct nft_expr *expr, struct nlattr *tb[])
{
	struct nft_meta *meta = nft_expr_priv(expr);

	if (tb[NFTA_META_KEY] == NULL)
		return -EINVAL;

	meta->key = ntohl(nla_get_be32(tb[NFTA_META_KEY]));
	switch (meta->key) {
	case NFT_META_MARK:
	case NFT_META_PRIORITY:
	case NFT_META_NFTRACE:
#ifdef CONFIG_NETWORK_SECMARK
	case NFT_META_SECMARK:
#endif
		break;
	default:
		return -EINVAL;
	}

	return 0;
}
コード例 #8
0
ファイル: nft_fib_ipv4.c プロジェクト: Lyude/linux
static const struct nft_expr_ops *
nft_fib4_select_ops(const struct nft_ctx *ctx,
		    const struct nlattr * const tb[])
{
	enum nft_fib_result result;

	if (!tb[NFTA_FIB_RESULT])
		return ERR_PTR(-EINVAL);

	result = ntohl(nla_get_be32(tb[NFTA_FIB_RESULT]));

	switch (result) {
	case NFT_FIB_RESULT_OIF:
		return &nft_fib4_ops;
	case NFT_FIB_RESULT_OIFNAME:
		return &nft_fib4_ops;
	case NFT_FIB_RESULT_ADDRTYPE:
		return &nft_fib4_type_ops;
	default:
		return ERR_PTR(-EOPNOTSUPP);
	}
}
コード例 #9
0
ファイル: nft_reject.c プロジェクト: 7799/linux
int nft_reject_init(const struct nft_ctx *ctx,
		    const struct nft_expr *expr,
		    const struct nlattr * const tb[])
{
	struct nft_reject *priv = nft_expr_priv(expr);

	if (tb[NFTA_REJECT_TYPE] == NULL)
		return -EINVAL;

	priv->type = ntohl(nla_get_be32(tb[NFTA_REJECT_TYPE]));
	switch (priv->type) {
	case NFT_REJECT_ICMP_UNREACH:
		if (tb[NFTA_REJECT_ICMP_CODE] == NULL)
			return -EINVAL;
		priv->icmp_code = nla_get_u8(tb[NFTA_REJECT_ICMP_CODE]);
	case NFT_REJECT_TCP_RST:
		break;
	default:
		return -EINVAL;
	}

	return 0;
}
コード例 #10
0
static int nft_objref_init(const struct nft_ctx *ctx,
			   const struct nft_expr *expr,
			   const struct nlattr * const tb[])
{
	struct nft_object *obj = nft_objref_priv(expr);
	u8 genmask = nft_genmask_next(ctx->net);
	u32 objtype;

	if (!tb[NFTA_OBJREF_IMM_NAME] ||
	    !tb[NFTA_OBJREF_IMM_TYPE])
		return -EINVAL;

	objtype = ntohl(nla_get_be32(tb[NFTA_OBJREF_IMM_TYPE]));
	obj = nf_tables_obj_lookup(ctx->table, tb[NFTA_OBJREF_IMM_NAME], objtype,
				   genmask);
	if (IS_ERR(obj))
		return -ENOENT;

	nft_objref_priv(expr) = obj;
	obj->use++;

	return 0;
}
コード例 #11
0
ファイル: nft_meta.c プロジェクト: AlexShiLucky/linux
static int nft_meta_set_init(const struct nft_ctx *ctx,
			     const struct nft_expr *expr,
			     const struct nlattr * const tb[])
{
	struct nft_meta *priv = nft_expr_priv(expr);
	unsigned int len;
	int err;

	priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY]));
	switch (priv->key) {
	case NFT_META_MARK:
	case NFT_META_PRIORITY:
#ifdef CONFIG_NETWORK_SECMARK
	case NFT_META_SECMARK:
#endif
		len = sizeof(u32);
		break;
	case NFT_META_NFTRACE:
		len = sizeof(u8);
		break;
	case NFT_META_PKTTYPE:
		len = sizeof(u8);
		break;
	default:
		return -EOPNOTSUPP;
	}

	priv->sreg = nft_parse_register(tb[NFTA_META_SREG]);
	err = nft_validate_register_load(priv->sreg, len);
	if (err < 0)
		return err;

	if (priv->key == NFT_META_NFTRACE)
		static_branch_inc(&nft_trace_enabled);

	return 0;
}
コード例 #12
0
ファイル: nft_cmp.c プロジェクト: AshishNamdev/linux
static const struct nft_expr_ops *
nft_cmp_select_ops(const struct nft_ctx *ctx, const struct nlattr * const tb[])
{
	struct nft_data_desc desc;
	struct nft_data data;
	enum nft_cmp_ops op;
	int err;

	if (tb[NFTA_CMP_SREG] == NULL ||
	    tb[NFTA_CMP_OP] == NULL ||
	    tb[NFTA_CMP_DATA] == NULL)
		return ERR_PTR(-EINVAL);

	op = ntohl(nla_get_be32(tb[NFTA_CMP_OP]));
	switch (op) {
	case NFT_CMP_EQ:
	case NFT_CMP_NEQ:
	case NFT_CMP_LT:
	case NFT_CMP_LTE:
	case NFT_CMP_GT:
	case NFT_CMP_GTE:
		break;
	default:
		return ERR_PTR(-EINVAL);
	}

	err = nft_data_init(NULL, &data, sizeof(data), &desc,
			    tb[NFTA_CMP_DATA]);
	if (err < 0)
		return ERR_PTR(err);

	if (desc.len <= sizeof(u32) && op == NFT_CMP_EQ)
		return &nft_cmp_fast_ops;
	else
		return &nft_cmp_ops;
}
コード例 #13
0
static int
nfnl_compat_get(struct sock *nfnl, struct sk_buff *skb,
		const struct nlmsghdr *nlh, const struct nlattr * const tb[])
{
	int ret = 0, target;
	struct nfgenmsg *nfmsg;
	const char *fmt;
	const char *name;
	u32 rev;
	struct sk_buff *skb2;

	if (tb[NFTA_COMPAT_NAME] == NULL ||
	    tb[NFTA_COMPAT_REV] == NULL ||
	    tb[NFTA_COMPAT_TYPE] == NULL)
		return -EINVAL;

	name = nla_data(tb[NFTA_COMPAT_NAME]);
	rev = ntohl(nla_get_be32(tb[NFTA_COMPAT_REV]));
	target = ntohl(nla_get_be32(tb[NFTA_COMPAT_TYPE]));

	nfmsg = nlmsg_data(nlh);

	switch(nfmsg->nfgen_family) {
	case AF_INET:
		fmt = "ipt_%s";
		break;
	case AF_INET6:
		fmt = "ip6t_%s";
		break;
	case NFPROTO_BRIDGE:
		fmt = "ebt_%s";
		break;
	default:
		pr_err("nft_compat: unsupported protocol %d\n",
			nfmsg->nfgen_family);
		return -EINVAL;
	}

	try_then_request_module(xt_find_revision(nfmsg->nfgen_family, name,
						 rev, target, &ret),
						 fmt, name);

	if (ret < 0)
		return ret;

	skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
	if (skb2 == NULL)
		return -ENOMEM;

	/* include the best revision for this extension in the message */
	if (nfnl_compat_fill_info(skb2, NETLINK_CB(skb).portid,
				  nlh->nlmsg_seq,
				  NFNL_MSG_TYPE(nlh->nlmsg_type),
				  NFNL_MSG_COMPAT_GET,
				  nfmsg->nfgen_family,
				  name, ret, target) <= 0) {
		kfree_skb(skb2);
		return -ENOSPC;
	}

	ret = netlink_unicast(nfnl, skb2, NETLINK_CB(skb).portid,
				MSG_DONTWAIT);
	if (ret > 0)
		ret = 0;

	return ret == -EAGAIN ? -ENOBUFS : ret;
}
コード例 #14
0
ファイル: act_tunnel_key.c プロジェクト: Lyude/linux
static int tunnel_key_init(struct net *net, struct nlattr *nla,
			   struct nlattr *est, struct tc_action **a,
			   int ovr, int bind, bool rtnl_held,
			   struct netlink_ext_ack *extack)
{
	struct tc_action_net *tn = net_generic(net, tunnel_key_net_id);
	struct nlattr *tb[TCA_TUNNEL_KEY_MAX + 1];
	struct tcf_tunnel_key_params *params_new;
	struct metadata_dst *metadata = NULL;
	struct tc_tunnel_key *parm;
	struct tcf_tunnel_key *t;
	bool exists = false;
	__be16 dst_port = 0;
	int opts_len = 0;
	__be64 key_id;
	__be16 flags;
	u8 tos, ttl;
	int ret = 0;
	int err;

	if (!nla) {
		NL_SET_ERR_MSG(extack, "Tunnel requires attributes to be passed");
		return -EINVAL;
	}

	err = nla_parse_nested(tb, TCA_TUNNEL_KEY_MAX, nla, tunnel_key_policy,
			       extack);
	if (err < 0) {
		NL_SET_ERR_MSG(extack, "Failed to parse nested tunnel key attributes");
		return err;
	}

	if (!tb[TCA_TUNNEL_KEY_PARMS]) {
		NL_SET_ERR_MSG(extack, "Missing tunnel key parameters");
		return -EINVAL;
	}

	parm = nla_data(tb[TCA_TUNNEL_KEY_PARMS]);
	err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
	if (err < 0)
		return err;
	exists = err;
	if (exists && bind)
		return 0;

	switch (parm->t_action) {
	case TCA_TUNNEL_KEY_ACT_RELEASE:
		break;
	case TCA_TUNNEL_KEY_ACT_SET:
		if (!tb[TCA_TUNNEL_KEY_ENC_KEY_ID]) {
			NL_SET_ERR_MSG(extack, "Missing tunnel key id");
			ret = -EINVAL;
			goto err_out;
		}

		key_id = key32_to_tunnel_id(nla_get_be32(tb[TCA_TUNNEL_KEY_ENC_KEY_ID]));

		flags = TUNNEL_KEY | TUNNEL_CSUM;
		if (tb[TCA_TUNNEL_KEY_NO_CSUM] &&
		    nla_get_u8(tb[TCA_TUNNEL_KEY_NO_CSUM]))
			flags &= ~TUNNEL_CSUM;

		if (tb[TCA_TUNNEL_KEY_ENC_DST_PORT])
			dst_port = nla_get_be16(tb[TCA_TUNNEL_KEY_ENC_DST_PORT]);

		if (tb[TCA_TUNNEL_KEY_ENC_OPTS]) {
			opts_len = tunnel_key_get_opts_len(tb[TCA_TUNNEL_KEY_ENC_OPTS],
							   extack);
			if (opts_len < 0) {
				ret = opts_len;
				goto err_out;
			}
		}

		tos = 0;
		if (tb[TCA_TUNNEL_KEY_ENC_TOS])
			tos = nla_get_u8(tb[TCA_TUNNEL_KEY_ENC_TOS]);
		ttl = 0;
		if (tb[TCA_TUNNEL_KEY_ENC_TTL])
			ttl = nla_get_u8(tb[TCA_TUNNEL_KEY_ENC_TTL]);

		if (tb[TCA_TUNNEL_KEY_ENC_IPV4_SRC] &&
		    tb[TCA_TUNNEL_KEY_ENC_IPV4_DST]) {
			__be32 saddr;
			__be32 daddr;

			saddr = nla_get_in_addr(tb[TCA_TUNNEL_KEY_ENC_IPV4_SRC]);
			daddr = nla_get_in_addr(tb[TCA_TUNNEL_KEY_ENC_IPV4_DST]);

			metadata = __ip_tun_set_dst(saddr, daddr, tos, ttl,
						    dst_port, flags,
						    key_id, opts_len);
		} else if (tb[TCA_TUNNEL_KEY_ENC_IPV6_SRC] &&
			   tb[TCA_TUNNEL_KEY_ENC_IPV6_DST]) {
			struct in6_addr saddr;
			struct in6_addr daddr;

			saddr = nla_get_in6_addr(tb[TCA_TUNNEL_KEY_ENC_IPV6_SRC]);
			daddr = nla_get_in6_addr(tb[TCA_TUNNEL_KEY_ENC_IPV6_DST]);

			metadata = __ipv6_tun_set_dst(&saddr, &daddr, tos, ttl, dst_port,
						      0, flags,
						      key_id, 0);
		} else {
			NL_SET_ERR_MSG(extack, "Missing either ipv4 or ipv6 src and dst");
			ret = -EINVAL;
			goto err_out;
		}

		if (!metadata) {
			NL_SET_ERR_MSG(extack, "Cannot allocate tunnel metadata dst");
			ret = -ENOMEM;
			goto err_out;
		}

		if (opts_len) {
			ret = tunnel_key_opts_set(tb[TCA_TUNNEL_KEY_ENC_OPTS],
						  &metadata->u.tun_info,
						  opts_len, extack);
			if (ret < 0)
				goto release_tun_meta;
		}

		metadata->u.tun_info.mode |= IP_TUNNEL_INFO_TX;
		break;
	default:
		NL_SET_ERR_MSG(extack, "Unknown tunnel key action");
		ret = -EINVAL;
		goto err_out;
	}

	if (!exists) {
		ret = tcf_idr_create(tn, parm->index, est, a,
				     &act_tunnel_key_ops, bind, true);
		if (ret) {
			NL_SET_ERR_MSG(extack, "Cannot create TC IDR");
			goto release_tun_meta;
		}

		ret = ACT_P_CREATED;
	} else if (!ovr) {
		NL_SET_ERR_MSG(extack, "TC IDR already exists");
		ret = -EEXIST;
		goto release_tun_meta;
	}

	t = to_tunnel_key(*a);

	params_new = kzalloc(sizeof(*params_new), GFP_KERNEL);
	if (unlikely(!params_new)) {
		NL_SET_ERR_MSG(extack, "Cannot allocate tunnel key parameters");
		ret = -ENOMEM;
		exists = true;
		goto release_tun_meta;
	}
	params_new->tcft_action = parm->t_action;
	params_new->tcft_enc_metadata = metadata;

	spin_lock_bh(&t->tcf_lock);
	t->tcf_action = parm->action;
	rcu_swap_protected(t->params, params_new,
			   lockdep_is_held(&t->tcf_lock));
	spin_unlock_bh(&t->tcf_lock);
	if (params_new)
		kfree_rcu(params_new, rcu);

	if (ret == ACT_P_CREATED)
		tcf_idr_insert(tn, *a);

	return ret;

release_tun_meta:
	dst_release(&metadata->dst);

err_out:
	if (exists)
		tcf_idr_release(*a, bind);
	else
		tcf_idr_cleanup(tn, parm->index);
	return ret;
}
コード例 #15
0
ファイル: nft_nat.c プロジェクト: Abioy/kasan
static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
			const struct nlattr * const tb[])
{
	struct nft_nat *priv = nft_expr_priv(expr);
	u32 family;
	int err;

	if (tb[NFTA_NAT_TYPE] == NULL ||
	    (tb[NFTA_NAT_REG_ADDR_MIN] == NULL &&
	     tb[NFTA_NAT_REG_PROTO_MIN] == NULL))
		return -EINVAL;

	switch (ntohl(nla_get_be32(tb[NFTA_NAT_TYPE]))) {
	case NFT_NAT_SNAT:
		priv->type = NF_NAT_MANIP_SRC;
		break;
	case NFT_NAT_DNAT:
		priv->type = NF_NAT_MANIP_DST;
		break;
	default:
		return -EINVAL;
	}

	err = nft_nat_validate(ctx, expr, NULL);
	if (err < 0)
		return err;

	if (tb[NFTA_NAT_FAMILY] == NULL)
		return -EINVAL;

	family = ntohl(nla_get_be32(tb[NFTA_NAT_FAMILY]));
	if (family != AF_INET && family != AF_INET6)
		return -EAFNOSUPPORT;
	if (family != ctx->afi->family)
		return -EOPNOTSUPP;
	priv->family = family;

	if (tb[NFTA_NAT_REG_ADDR_MIN]) {
		priv->sreg_addr_min =
			ntohl(nla_get_be32(tb[NFTA_NAT_REG_ADDR_MIN]));

		err = nft_validate_input_register(priv->sreg_addr_min);
		if (err < 0)
			return err;

		if (tb[NFTA_NAT_REG_ADDR_MAX]) {
			priv->sreg_addr_max =
				ntohl(nla_get_be32(tb[NFTA_NAT_REG_ADDR_MAX]));

			err = nft_validate_input_register(priv->sreg_addr_max);
			if (err < 0)
				return err;
		} else {
			priv->sreg_addr_max = priv->sreg_addr_min;
		}
	}

	if (tb[NFTA_NAT_REG_PROTO_MIN]) {
		priv->sreg_proto_min =
			ntohl(nla_get_be32(tb[NFTA_NAT_REG_PROTO_MIN]));

		err = nft_validate_input_register(priv->sreg_proto_min);
		if (err < 0)
			return err;

		if (tb[NFTA_NAT_REG_PROTO_MAX]) {
			priv->sreg_proto_max =
				ntohl(nla_get_be32(tb[NFTA_NAT_REG_PROTO_MAX]));

			err = nft_validate_input_register(priv->sreg_proto_max);
			if (err < 0)
				return err;
		} else {
			priv->sreg_proto_max = priv->sreg_proto_min;
		}
	}

	if (tb[NFTA_NAT_FLAGS]) {
		priv->flags = ntohl(nla_get_be32(tb[NFTA_NAT_FLAGS]));
		if (priv->flags & ~NF_NAT_RANGE_MASK)
			return -EINVAL;
	}

	return 0;
}
コード例 #16
0
ファイル: nft_compat.c プロジェクト: avagin/linux
static const struct nft_expr_ops *
nft_target_select_ops(const struct nft_ctx *ctx,
		      const struct nlattr * const tb[])
{
	struct nft_expr_ops *ops;
	struct xt_target *target;
	char *tg_name;
	u32 rev, family;
	int err;

	if (tb[NFTA_TARGET_NAME] == NULL ||
	    tb[NFTA_TARGET_REV] == NULL ||
	    tb[NFTA_TARGET_INFO] == NULL)
		return ERR_PTR(-EINVAL);

	tg_name = nla_data(tb[NFTA_TARGET_NAME]);
	rev = ntohl(nla_get_be32(tb[NFTA_TARGET_REV]));
	family = ctx->family;

	if (strcmp(tg_name, XT_ERROR_TARGET) == 0 ||
	    strcmp(tg_name, XT_STANDARD_TARGET) == 0 ||
	    strcmp(tg_name, "standard") == 0)
		return ERR_PTR(-EINVAL);

	target = xt_request_find_target(family, tg_name, rev);
	if (IS_ERR(target))
		return ERR_PTR(-ENOENT);

	if (!target->target) {
		err = -EINVAL;
		goto err;
	}

	if (target->targetsize > nla_len(tb[NFTA_TARGET_INFO])) {
		err = -EINVAL;
		goto err;
	}

	ops = kzalloc(sizeof(struct nft_expr_ops), GFP_KERNEL);
	if (!ops) {
		err = -ENOMEM;
		goto err;
	}

	ops->type = &nft_target_type;
	ops->size = NFT_EXPR_SIZE(XT_ALIGN(target->targetsize));
	ops->init = nft_target_init;
	ops->destroy = nft_target_destroy;
	ops->dump = nft_target_dump;
	ops->validate = nft_target_validate;
	ops->data = target;

	if (family == NFPROTO_BRIDGE)
		ops->eval = nft_target_eval_bridge;
	else
		ops->eval = nft_target_eval_xt;

	return ops;
err:
	module_put(target->me);
	return ERR_PTR(err);
}
コード例 #17
0
static int tcp_timeout_nlattr_to_obj(struct nlattr *tb[], void *data)
{
	unsigned int *timeouts = data;
	int i;

	
	for (i=0; i<TCP_CONNTRACK_TIMEOUT_MAX; i++)
		timeouts[i] = tcp_timeouts[i];

	if (tb[CTA_TIMEOUT_TCP_SYN_SENT]) {
		timeouts[TCP_CONNTRACK_SYN_SENT] =
			ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_SYN_SENT]))*HZ;
	}
	if (tb[CTA_TIMEOUT_TCP_SYN_RECV]) {
		timeouts[TCP_CONNTRACK_SYN_RECV] =
			ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_SYN_RECV]))*HZ;
	}
	if (tb[CTA_TIMEOUT_TCP_ESTABLISHED]) {
		timeouts[TCP_CONNTRACK_ESTABLISHED] =
			ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_ESTABLISHED]))*HZ;
	}
	if (tb[CTA_TIMEOUT_TCP_FIN_WAIT]) {
		timeouts[TCP_CONNTRACK_FIN_WAIT] =
			ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_FIN_WAIT]))*HZ;
	}
	if (tb[CTA_TIMEOUT_TCP_CLOSE_WAIT]) {
		timeouts[TCP_CONNTRACK_CLOSE_WAIT] =
			ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_CLOSE_WAIT]))*HZ;
	}
	if (tb[CTA_TIMEOUT_TCP_LAST_ACK]) {
		timeouts[TCP_CONNTRACK_LAST_ACK] =
			ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_LAST_ACK]))*HZ;
	}
	if (tb[CTA_TIMEOUT_TCP_TIME_WAIT]) {
		timeouts[TCP_CONNTRACK_TIME_WAIT] =
			ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_TIME_WAIT]))*HZ;
	}
	if (tb[CTA_TIMEOUT_TCP_CLOSE]) {
		timeouts[TCP_CONNTRACK_CLOSE] =
			ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_CLOSE]))*HZ;
	}
	if (tb[CTA_TIMEOUT_TCP_SYN_SENT2]) {
		timeouts[TCP_CONNTRACK_SYN_SENT2] =
			ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_SYN_SENT2]))*HZ;
	}
	if (tb[CTA_TIMEOUT_TCP_RETRANS]) {
		timeouts[TCP_CONNTRACK_RETRANS] =
			ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_RETRANS]))*HZ;
	}
	if (tb[CTA_TIMEOUT_TCP_UNACK]) {
		timeouts[TCP_CONNTRACK_UNACK] =
			ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_UNACK]))*HZ;
	}
	return 0;
}
コード例 #18
0
static int l2tp_nl_cmd_tunnel_create(struct sk_buff *skb, struct genl_info *info)
{
	u32 tunnel_id;
	u32 peer_tunnel_id;
	int proto_version;
	int fd;
	int ret = 0;
	struct l2tp_tunnel_cfg cfg = { 0, };
	struct l2tp_tunnel *tunnel;
	struct net *net = genl_info_net(info);

	if (!info->attrs[L2TP_ATTR_CONN_ID]) {
		ret = -EINVAL;
		goto out;
	}
	tunnel_id = nla_get_u32(info->attrs[L2TP_ATTR_CONN_ID]);

	if (!info->attrs[L2TP_ATTR_PEER_CONN_ID]) {
		ret = -EINVAL;
		goto out;
	}
	peer_tunnel_id = nla_get_u32(info->attrs[L2TP_ATTR_PEER_CONN_ID]);

	if (!info->attrs[L2TP_ATTR_PROTO_VERSION]) {
		ret = -EINVAL;
		goto out;
	}
	proto_version = nla_get_u8(info->attrs[L2TP_ATTR_PROTO_VERSION]);

	if (!info->attrs[L2TP_ATTR_ENCAP_TYPE]) {
		ret = -EINVAL;
		goto out;
	}
	cfg.encap = nla_get_u16(info->attrs[L2TP_ATTR_ENCAP_TYPE]);

	fd = -1;
	if (info->attrs[L2TP_ATTR_FD]) {
		fd = nla_get_u32(info->attrs[L2TP_ATTR_FD]);
	} else {
		if (info->attrs[L2TP_ATTR_IP_SADDR])
			cfg.local_ip.s_addr = nla_get_be32(info->attrs[L2TP_ATTR_IP_SADDR]);
		if (info->attrs[L2TP_ATTR_IP_DADDR])
			cfg.peer_ip.s_addr = nla_get_be32(info->attrs[L2TP_ATTR_IP_DADDR]);
		if (info->attrs[L2TP_ATTR_UDP_SPORT])
			cfg.local_udp_port = nla_get_u16(info->attrs[L2TP_ATTR_UDP_SPORT]);
		if (info->attrs[L2TP_ATTR_UDP_DPORT])
			cfg.peer_udp_port = nla_get_u16(info->attrs[L2TP_ATTR_UDP_DPORT]);
		if (info->attrs[L2TP_ATTR_UDP_CSUM])
			cfg.use_udp_checksums = nla_get_flag(info->attrs[L2TP_ATTR_UDP_CSUM]);
	}

	if (info->attrs[L2TP_ATTR_DEBUG])
		cfg.debug = nla_get_u32(info->attrs[L2TP_ATTR_DEBUG]);

	tunnel = l2tp_tunnel_find(net, tunnel_id);
	if (tunnel != NULL) {
		ret = -EEXIST;
		goto out;
	}

	ret = -EINVAL;
	switch (cfg.encap) {
	case L2TP_ENCAPTYPE_UDP:
	case L2TP_ENCAPTYPE_IP:
		ret = l2tp_tunnel_create(net, fd, proto_version, tunnel_id,
					 peer_tunnel_id, &cfg, &tunnel);
		break;
	}

out:
	return ret;
}
コード例 #19
0
ファイル: nft_fib_ipv6.c プロジェクト: AshishNamdev/linux
static u32 __nft_fib6_eval_type(const struct nft_fib *priv,
				const struct nft_pktinfo *pkt)
{
	const struct net_device *dev = NULL;
	const struct nf_ipv6_ops *v6ops;
	const struct nf_afinfo *afinfo;
	int route_err, addrtype;
	struct rt6_info *rt;
	struct flowi6 fl6 = {
		.flowi6_iif = LOOPBACK_IFINDEX,
		.flowi6_proto = pkt->tprot,
	};
	u32 ret = 0;

	afinfo = nf_get_afinfo(NFPROTO_IPV6);
	if (!afinfo)
		return RTN_UNREACHABLE;

	if (priv->flags & NFTA_FIB_F_IIF)
		dev = nft_in(pkt);
	else if (priv->flags & NFTA_FIB_F_OIF)
		dev = nft_out(pkt);

	nft_fib6_flowi_init(&fl6, priv, pkt, dev);

	v6ops = nf_get_ipv6_ops();
	if (dev && v6ops && v6ops->chk_addr(nft_net(pkt), &fl6.daddr, dev, true))
		ret = RTN_LOCAL;

	route_err = afinfo->route(nft_net(pkt), (struct dst_entry **)&rt,
				  flowi6_to_flowi(&fl6), false);
	if (route_err)
		goto err;

	if (rt->rt6i_flags & RTF_REJECT) {
		route_err = rt->dst.error;
		dst_release(&rt->dst);
		goto err;
	}

	if (ipv6_anycast_destination((struct dst_entry *)rt, &fl6.daddr))
		ret = RTN_ANYCAST;
	else if (!dev && rt->rt6i_flags & RTF_LOCAL)
		ret = RTN_LOCAL;

	dst_release(&rt->dst);

	if (ret)
		return ret;

	addrtype = ipv6_addr_type(&fl6.daddr);

	if (addrtype & IPV6_ADDR_MULTICAST)
		return RTN_MULTICAST;
	if (addrtype & IPV6_ADDR_UNICAST)
		return RTN_UNICAST;

	return RTN_UNSPEC;
 err:
	switch (route_err) {
	case -EINVAL:
		return RTN_BLACKHOLE;
	case -EACCES:
		return RTN_PROHIBIT;
	case -EAGAIN:
		return RTN_THROW;
	default:
		break;
	}

	return RTN_UNREACHABLE;
}

void nft_fib6_eval_type(const struct nft_expr *expr, struct nft_regs *regs,
			const struct nft_pktinfo *pkt)
{
	const struct nft_fib *priv = nft_expr_priv(expr);
	u32 *dest = &regs->data[priv->dreg];

	*dest = __nft_fib6_eval_type(priv, pkt);
}
EXPORT_SYMBOL_GPL(nft_fib6_eval_type);

void nft_fib6_eval(const struct nft_expr *expr, struct nft_regs *regs,
		   const struct nft_pktinfo *pkt)
{
	const struct nft_fib *priv = nft_expr_priv(expr);
	const struct net_device *oif = NULL;
	u32 *dest = &regs->data[priv->dreg];
	struct flowi6 fl6 = {
		.flowi6_iif = LOOPBACK_IFINDEX,
		.flowi6_proto = pkt->tprot,
	};
	struct rt6_info *rt;
	int lookup_flags;

	if (priv->flags & NFTA_FIB_F_IIF)
		oif = nft_in(pkt);
	else if (priv->flags & NFTA_FIB_F_OIF)
		oif = nft_out(pkt);

	lookup_flags = nft_fib6_flowi_init(&fl6, priv, pkt, oif);

	if (nft_hook(pkt) == NF_INET_PRE_ROUTING &&
	    nft_fib_is_loopback(pkt->skb, nft_in(pkt))) {
		nft_fib_store_result(dest, priv->result, pkt,
				     nft_in(pkt)->ifindex);
		return;
	}

	*dest = 0;
 again:
	rt = (void *)ip6_route_lookup(nft_net(pkt), &fl6, lookup_flags);
	if (rt->dst.error)
		goto put_rt_err;

	/* Should not see RTF_LOCAL here */
	if (rt->rt6i_flags & (RTF_REJECT | RTF_ANYCAST | RTF_LOCAL))
		goto put_rt_err;

	if (oif && oif != rt->rt6i_idev->dev) {
		/* multipath route? Try again with F_IFACE */
		if ((lookup_flags & RT6_LOOKUP_F_IFACE) == 0) {
			lookup_flags |= RT6_LOOKUP_F_IFACE;
			fl6.flowi6_oif = oif->ifindex;
			ip6_rt_put(rt);
			goto again;
		}
	}

	switch (priv->result) {
	case NFT_FIB_RESULT_OIF:
		*dest = rt->rt6i_idev->dev->ifindex;
		break;
	case NFT_FIB_RESULT_OIFNAME:
		strncpy((char *)dest, rt->rt6i_idev->dev->name, IFNAMSIZ);
		break;
	default:
		WARN_ON_ONCE(1);
		break;
	}

 put_rt_err:
	ip6_rt_put(rt);
}
EXPORT_SYMBOL_GPL(nft_fib6_eval);

static struct nft_expr_type nft_fib6_type;

static const struct nft_expr_ops nft_fib6_type_ops = {
	.type		= &nft_fib6_type,
	.size		= NFT_EXPR_SIZE(sizeof(struct nft_fib)),
	.eval		= nft_fib6_eval_type,
	.init		= nft_fib_init,
	.dump		= nft_fib_dump,
	.validate	= nft_fib_validate,
};

static const struct nft_expr_ops nft_fib6_ops = {
	.type		= &nft_fib6_type,
	.size		= NFT_EXPR_SIZE(sizeof(struct nft_fib)),
	.eval		= nft_fib6_eval,
	.init		= nft_fib_init,
	.dump		= nft_fib_dump,
	.validate	= nft_fib_validate,
};

static const struct nft_expr_ops *
nft_fib6_select_ops(const struct nft_ctx *ctx,
		    const struct nlattr * const tb[])
{
	enum nft_fib_result result;

	if (!tb[NFTA_FIB_RESULT])
		return ERR_PTR(-EINVAL);

	result = ntohl(nla_get_be32(tb[NFTA_FIB_RESULT]));

	switch (result) {
	case NFT_FIB_RESULT_OIF:
		return &nft_fib6_ops;
	case NFT_FIB_RESULT_OIFNAME:
		return &nft_fib6_ops;
	case NFT_FIB_RESULT_ADDRTYPE:
		return &nft_fib6_type_ops;
	default:
		return ERR_PTR(-EOPNOTSUPP);
	}
}

static struct nft_expr_type nft_fib6_type __read_mostly = {
	.name		= "fib",
	.select_ops	= &nft_fib6_select_ops,
	.policy		= nft_fib_policy,
	.maxattr	= NFTA_FIB_MAX,
	.family		= NFPROTO_IPV6,
	.owner		= THIS_MODULE,
};

static int __init nft_fib6_module_init(void)
{
	return nft_register_expr(&nft_fib6_type);
}

static void __exit nft_fib6_module_exit(void)
{
	nft_unregister_expr(&nft_fib6_type);
}
module_init(nft_fib6_module_init);
module_exit(nft_fib6_module_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Florian Westphal <*****@*****.**>");
MODULE_ALIAS_NFT_AF_EXPR(10, "fib");
コード例 #20
0
ファイル: bond_netlink.c プロジェクト: 020gzh/linux
static int bond_changelink(struct net_device *bond_dev,
			   struct nlattr *tb[], struct nlattr *data[])
{
	struct bonding *bond = netdev_priv(bond_dev);
	struct bond_opt_value newval;
	int miimon = 0;
	int err;

	if (!data)
		return 0;

	if (data[IFLA_BOND_MODE]) {
		int mode = nla_get_u8(data[IFLA_BOND_MODE]);

		bond_opt_initval(&newval, mode);
		err = __bond_opt_set(bond, BOND_OPT_MODE, &newval);
		if (err)
			return err;
	}
	if (data[IFLA_BOND_ACTIVE_SLAVE]) {
		int ifindex = nla_get_u32(data[IFLA_BOND_ACTIVE_SLAVE]);
		struct net_device *slave_dev;
		char *active_slave = "";

		if (ifindex != 0) {
			slave_dev = __dev_get_by_index(dev_net(bond_dev),
						       ifindex);
			if (!slave_dev)
				return -ENODEV;
			active_slave = slave_dev->name;
		}
		bond_opt_initstr(&newval, active_slave);
		err = __bond_opt_set(bond, BOND_OPT_ACTIVE_SLAVE, &newval);
		if (err)
			return err;
	}
	if (data[IFLA_BOND_MIIMON]) {
		miimon = nla_get_u32(data[IFLA_BOND_MIIMON]);

		bond_opt_initval(&newval, miimon);
		err = __bond_opt_set(bond, BOND_OPT_MIIMON, &newval);
		if (err)
			return err;
	}
	if (data[IFLA_BOND_UPDELAY]) {
		int updelay = nla_get_u32(data[IFLA_BOND_UPDELAY]);

		bond_opt_initval(&newval, updelay);
		err = __bond_opt_set(bond, BOND_OPT_UPDELAY, &newval);
		if (err)
			return err;
	}
	if (data[IFLA_BOND_DOWNDELAY]) {
		int downdelay = nla_get_u32(data[IFLA_BOND_DOWNDELAY]);

		bond_opt_initval(&newval, downdelay);
		err = __bond_opt_set(bond, BOND_OPT_DOWNDELAY, &newval);
		if (err)
			return err;
	}
	if (data[IFLA_BOND_USE_CARRIER]) {
		int use_carrier = nla_get_u8(data[IFLA_BOND_USE_CARRIER]);

		bond_opt_initval(&newval, use_carrier);
		err = __bond_opt_set(bond, BOND_OPT_USE_CARRIER, &newval);
		if (err)
			return err;
	}
	if (data[IFLA_BOND_ARP_INTERVAL]) {
		int arp_interval = nla_get_u32(data[IFLA_BOND_ARP_INTERVAL]);

		if (arp_interval && miimon) {
			netdev_err(bond->dev, "ARP monitoring cannot be used with MII monitoring\n");
			return -EINVAL;
		}

		bond_opt_initval(&newval, arp_interval);
		err = __bond_opt_set(bond, BOND_OPT_ARP_INTERVAL, &newval);
		if (err)
			return err;
	}
	if (data[IFLA_BOND_ARP_IP_TARGET]) {
		struct nlattr *attr;
		int i = 0, rem;

		bond_option_arp_ip_targets_clear(bond);
		nla_for_each_nested(attr, data[IFLA_BOND_ARP_IP_TARGET], rem) {
			__be32 target;

			if (nla_len(attr) < sizeof(target))
				return -EINVAL;

			target = nla_get_be32(attr);

			bond_opt_initval(&newval, (__force u64)target);
			err = __bond_opt_set(bond, BOND_OPT_ARP_TARGETS,
					     &newval);
			if (err)
				break;
			i++;
		}
		if (i == 0 && bond->params.arp_interval)
			netdev_warn(bond->dev, "Removing last arp target with arp_interval on\n");
		if (err)
			return err;
	}
コード例 #21
0
ファイル: nft_lookup.c プロジェクト: Anjali05/linux
static int nft_lookup_init(const struct nft_ctx *ctx,
			   const struct nft_expr *expr,
			   const struct nlattr * const tb[])
{
	struct nft_lookup *priv = nft_expr_priv(expr);
	u8 genmask = nft_genmask_next(ctx->net);
	struct nft_set *set;
	u32 flags;
	int err;

	if (tb[NFTA_LOOKUP_SET] == NULL ||
	    tb[NFTA_LOOKUP_SREG] == NULL)
		return -EINVAL;

	set = nft_set_lookup_global(ctx->net, ctx->table, tb[NFTA_LOOKUP_SET],
				    tb[NFTA_LOOKUP_SET_ID], genmask);
	if (IS_ERR(set))
		return PTR_ERR(set);

	if (set->flags & NFT_SET_EVAL)
		return -EOPNOTSUPP;

	priv->sreg = nft_parse_register(tb[NFTA_LOOKUP_SREG]);
	err = nft_validate_register_load(priv->sreg, set->klen);
	if (err < 0)
		return err;

	if (tb[NFTA_LOOKUP_FLAGS]) {
		flags = ntohl(nla_get_be32(tb[NFTA_LOOKUP_FLAGS]));

		if (flags & ~NFT_LOOKUP_F_INV)
			return -EINVAL;

		if (flags & NFT_LOOKUP_F_INV) {
			if (set->flags & NFT_SET_MAP)
				return -EINVAL;
			priv->invert = true;
		}
	}

	if (tb[NFTA_LOOKUP_DREG] != NULL) {
		if (priv->invert)
			return -EINVAL;
		if (!(set->flags & NFT_SET_MAP))
			return -EINVAL;

		priv->dreg = nft_parse_register(tb[NFTA_LOOKUP_DREG]);
		err = nft_validate_register_store(ctx, priv->dreg, NULL,
						  set->dtype, set->dlen);
		if (err < 0)
			return err;
	} else if (set->flags & NFT_SET_MAP)
		return -EINVAL;

	priv->binding.flags = set->flags & NFT_SET_MAP;

	err = nf_tables_bind_set(ctx, set, &priv->binding);
	if (err < 0)
		return err;

	priv->set = set;
	return 0;
}
コード例 #22
0
static int tcp_timeout_nlattr_to_obj(struct nlattr *tb[],
				     struct net *net, void *data)
{
	struct nf_tcp_net *tn = nf_tcp_pernet(net);
	unsigned int *timeouts = data;
	int i;

	if (!timeouts)
		timeouts = tn->timeouts;
	/* set default TCP timeouts. */
	for (i=0; i<TCP_CONNTRACK_TIMEOUT_MAX; i++)
		timeouts[i] = tn->timeouts[i];

	if (tb[CTA_TIMEOUT_TCP_SYN_SENT]) {
		timeouts[TCP_CONNTRACK_SYN_SENT] =
			ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_SYN_SENT]))*HZ;
	}

	if (tb[CTA_TIMEOUT_TCP_SYN_RECV]) {
		timeouts[TCP_CONNTRACK_SYN_RECV] =
			ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_SYN_RECV]))*HZ;
	}
	if (tb[CTA_TIMEOUT_TCP_ESTABLISHED]) {
		timeouts[TCP_CONNTRACK_ESTABLISHED] =
			ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_ESTABLISHED]))*HZ;
	}
	if (tb[CTA_TIMEOUT_TCP_FIN_WAIT]) {
		timeouts[TCP_CONNTRACK_FIN_WAIT] =
			ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_FIN_WAIT]))*HZ;
	}
	if (tb[CTA_TIMEOUT_TCP_CLOSE_WAIT]) {
		timeouts[TCP_CONNTRACK_CLOSE_WAIT] =
			ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_CLOSE_WAIT]))*HZ;
	}
	if (tb[CTA_TIMEOUT_TCP_LAST_ACK]) {
		timeouts[TCP_CONNTRACK_LAST_ACK] =
			ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_LAST_ACK]))*HZ;
	}
	if (tb[CTA_TIMEOUT_TCP_TIME_WAIT]) {
		timeouts[TCP_CONNTRACK_TIME_WAIT] =
			ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_TIME_WAIT]))*HZ;
	}
	if (tb[CTA_TIMEOUT_TCP_CLOSE]) {
		timeouts[TCP_CONNTRACK_CLOSE] =
			ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_CLOSE]))*HZ;
	}
	if (tb[CTA_TIMEOUT_TCP_SYN_SENT2]) {
		timeouts[TCP_CONNTRACK_SYN_SENT2] =
			ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_SYN_SENT2]))*HZ;
	}
	if (tb[CTA_TIMEOUT_TCP_RETRANS]) {
		timeouts[TCP_CONNTRACK_RETRANS] =
			ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_RETRANS]))*HZ;
	}
	if (tb[CTA_TIMEOUT_TCP_UNACK]) {
		timeouts[TCP_CONNTRACK_UNACK] =
			ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_UNACK]))*HZ;
	}

	timeouts[CTA_TIMEOUT_TCP_UNSPEC] = timeouts[CTA_TIMEOUT_TCP_SYN_SENT];
	return 0;
}
コード例 #23
0
ファイル: nft_log.c プロジェクト: AshishNamdev/linux
static int nft_log_init(const struct nft_ctx *ctx,
			const struct nft_expr *expr,
			const struct nlattr * const tb[])
{
	struct nft_log *priv = nft_expr_priv(expr);
	struct nf_loginfo *li = &priv->loginfo;
	const struct nlattr *nla;
	int err;

	li->type = NF_LOG_TYPE_LOG;
	if (tb[NFTA_LOG_LEVEL] != NULL &&
	    tb[NFTA_LOG_GROUP] != NULL)
		return -EINVAL;
	if (tb[NFTA_LOG_GROUP] != NULL) {
		li->type = NF_LOG_TYPE_ULOG;
		if (tb[NFTA_LOG_FLAGS] != NULL)
			return -EINVAL;
	}

	nla = tb[NFTA_LOG_PREFIX];
	if (nla != NULL) {
		priv->prefix = kmalloc(nla_len(nla) + 1, GFP_KERNEL);
		if (priv->prefix == NULL)
			return -ENOMEM;
		nla_strlcpy(priv->prefix, nla, nla_len(nla) + 1);
	} else {
		priv->prefix = (char *)nft_log_null_prefix;
	}

	switch (li->type) {
	case NF_LOG_TYPE_LOG:
		if (tb[NFTA_LOG_LEVEL] != NULL) {
			li->u.log.level =
				ntohl(nla_get_be32(tb[NFTA_LOG_LEVEL]));
		} else {
			li->u.log.level = LOGLEVEL_WARNING;
		}
		if (li->u.log.level > LOGLEVEL_DEBUG) {
			err = -EINVAL;
			goto err1;
		}

		if (tb[NFTA_LOG_FLAGS] != NULL) {
			li->u.log.logflags =
				ntohl(nla_get_be32(tb[NFTA_LOG_FLAGS]));
			if (li->u.log.logflags & ~NF_LOG_MASK) {
				err = -EINVAL;
				goto err1;
			}
		}
		break;
	case NF_LOG_TYPE_ULOG:
		li->u.ulog.group = ntohs(nla_get_be16(tb[NFTA_LOG_GROUP]));
		if (tb[NFTA_LOG_SNAPLEN] != NULL) {
			li->u.ulog.flags |= NF_LOG_F_COPY_LEN;
			li->u.ulog.copy_len =
				ntohl(nla_get_be32(tb[NFTA_LOG_SNAPLEN]));
		}
		if (tb[NFTA_LOG_QTHRESHOLD] != NULL) {
			li->u.ulog.qthreshold =
				ntohs(nla_get_be16(tb[NFTA_LOG_QTHRESHOLD]));
		}
		break;
	}

	err = nf_logger_find_get(ctx->afi->family, li->type);
	if (err < 0)
		goto err1;

	return 0;

err1:
	if (priv->prefix != nft_log_null_prefix)
		kfree(priv->prefix);
	return err;
}
コード例 #24
0
ファイル: nfct.c プロジェクト: crs-chin/lavender
nfct_t *nfct_create(ginkgo_ctx *ctx, int grps, nfct_notify cb, void *ud)
{
    nfct_t *ct;
    char name[20];
    ginkgo_src src = {
        .name = name,
        .fd = -1,
        .rd = NULL,
        .wr = NULL,
        .pars = nl_parse,
        .resp = nfct_response,
        .hand = nfct_handler,
        .ud = NULL,
    };
    int fd;

    if(! ctx) return NULL;
    if((fd = nl_open(NETLINK_NETFILTER, grps)) < 0)
        return NULL;
    if(! instantiate(ct))  {
        close(fd);
        return NULL;
    }
    ct->ginkgo = ctx;
    ct->nlfd = fd;
    ct->nlgrps = grps;
    ct->nlseq = 0;
    ct->cb = cb;
    ct->ud = ud;

    src.fd = fd;
    src.ud = ct;
    sprintf(name, "nfct-%d", fd);
    if(ginkgo_src_register(ctx, &src, &ct->id, 0) < 0)  {
        close(fd);
        free(ct);
        return NULL;
    }
    return ct;
}

void nfct_destroy(nfct_t *ct)
{
    if(ct)  {
        ginkgo_src_deregister(ct->ginkgo, ct->id, 1, 1);
        close(ct->nlfd);
        free(ct);
    }
}

int nfct_conn_get_counter(const conn_entry *e, conn_counter *counter)
{
    const struct nlattr *orig = e->nla[CTA_COUNTERS_ORIG];
    const struct nlattr *rep = e->nla[CTA_COUNTERS_REPLY];
    struct nlattr *arr[CTA_COUNTERS_MAX + 1];

    if(orig && rep)  {
        nla_parse_nested(arr, CTA_COUNTERS_MAX, orig);
        if(! arr[CTA_COUNTERS_PACKETS] || ! arr[CTA_COUNTERS_BYTES])
            return -1;
        counter->orig_pkts = be64toh(nla_get_be64(arr[CTA_COUNTERS_PACKETS]));
        counter->orig_bytes = be64toh(nla_get_be64(arr[CTA_COUNTERS_BYTES]));

        nla_parse_nested(arr, CTA_COUNTERS_MAX, rep);
        if(! arr[CTA_COUNTERS_PACKETS] || ! arr[CTA_COUNTERS_BYTES])
            return -1;
        counter->rep_pkts = be64toh(nla_get_be64(arr[CTA_COUNTERS_PACKETS]));
        counter->rep_bytes = be64toh(nla_get_be64(arr[CTA_COUNTERS_BYTES]));
        return 0;
    }
    return -1;
}

int nfct_conn_get_tcpinfo(const conn_entry *e, conn_tcpinfo *info)
{
    const struct nlattr *proto = e->nla[CTA_PROTOINFO];
    const struct nlattr *tcp;
    struct nlattr *arr[CTA_PROTOINFO_TCP_MAX + 1];

    if(proto)  {
        tcp = (const struct nlattr *)nla_data(proto);
        if(nla_type(tcp) != CTA_PROTOINFO_TCP)
            return -1;
        nla_parse_nested(arr, CTA_PROTOINFO_TCP_MAX, tcp);
        if(arr[CTA_PROTOINFO_TCP_STATE]
           || arr[CTA_PROTOINFO_TCP_WSCALE_ORIGINAL]
           || arr[CTA_PROTOINFO_TCP_WSCALE_REPLY]
           || arr[CTA_PROTOINFO_TCP_FLAGS_ORIGINAL]
           || arr[CTA_PROTOINFO_TCP_FLAGS_REPLY])  {
            info->state = nla_get_u8(arr[CTA_PROTOINFO_TCP_STATE]);
            info->wscale_orig = nla_get_u8(arr[CTA_PROTOINFO_TCP_WSCALE_ORIGINAL]);
            info->wscale_rep = nla_get_u8(arr[CTA_PROTOINFO_TCP_WSCALE_REPLY]);
            nla_get_mem(arr[CTA_PROTOINFO_TCP_FLAGS_ORIGINAL], &info->flags_orig, sizeof(info->flags_orig));
            nla_get_mem(arr[CTA_PROTOINFO_TCP_FLAGS_REPLY], &info->flags_rep, sizeof(info->flags_rep));
            return 0;
        }
    }
    return -1;
}

int nfct_conn_get_sctpinfo(const conn_entry *e, conn_sctpinfo *info)
{
    const struct nlattr *proto = e->nla[CTA_PROTOINFO];
    const struct nlattr *sctp;
    struct nlattr *arr[CTA_PROTOINFO_SCTP_MAX + 1];

    if(proto)  {
        sctp = (const struct nlattr *)nla_data(proto);
        if(nla_type(sctp) != CTA_PROTOINFO_SCTP)
            return -1;
        nla_parse_nested(arr, CTA_PROTOINFO_SCTP_MAX, sctp);
        if(! arr[CTA_PROTOINFO_SCTP_STATE]
           || ! arr[CTA_PROTOINFO_SCTP_VTAG_ORIGINAL]
           || ! arr[CTA_PROTOINFO_SCTP_VTAG_REPLY])  {
            info->state = nla_get_u8(arr[CTA_PROTOINFO_SCTP_STATE]);
            info->vtag_orig = ntohl(nla_get_u8(arr[CTA_PROTOINFO_SCTP_VTAG_ORIGINAL]));
            info->vtag_rep = ntohl(nla_get_u8(arr[CTA_PROTOINFO_SCTP_VTAG_REPLY]));
            return 0;
        }
    }
    return -1;
}

int __nfct_conn_get_tuple(const conn_entry *e, int type, conn_tuple *tuple)
{
    struct nlattr *arr[CTA_TUPLE_MAX + 1];
    struct nlattr *ip[CTA_IP_MAX + 1];
    struct nlattr *proto[CTA_PROTO_MAX + 1];

    if(! e->nla[type])
        return -1;

    memset(tuple, 0, sizeof(*tuple));
    nla_parse_nested(arr, CTA_TUPLE_MAX, e->nla[type]);
    if(! arr[CTA_TUPLE_IP] || ! arr[CTA_TUPLE_PROTO])  {
        PR_WARN("unexpected NULL tuple IP or proto");
        return-1;
    }

    nla_parse_nested(ip, CTA_IP_MAX, arr[CTA_TUPLE_IP]);
    tuple->src.l3num = e->l3num;
    if(e->l3num == AF_INET)  {
        if(! ip[CTA_IP_V4_SRC] || ! ip[CTA_IP_V4_DST])
            return -1;
        tuple->src.u3.ip = nla_get_be32(ip[CTA_IP_V4_SRC]);
        tuple->dst.u3.ip = nla_get_be32(ip[CTA_IP_V4_DST]);
    }else if(e->l3num == AF_INET6)  {
        if(! ip[CTA_IP_V6_SRC] || ! ip[CTA_IP_V6_DST])
            return -1;
        nla_get_mem(ip[CTA_IP_V6_SRC], &tuple->src.u3.in6, sizeof(tuple->src.u3.in6));
        nla_get_mem(ip[CTA_IP_V6_DST], &tuple->dst.u3.in6, sizeof(tuple->dst.u3.in6));
    }else  {
        PR_WARN("unexpected l3num while parsing tuple:%d", e->l3num);
        return -1;
    }

    nla_parse_nested(proto, CTA_PROTO_MAX, arr[CTA_TUPLE_PROTO]);
    if(! proto[CTA_PROTO_NUM])  {
        PR_WARN("unexpected NULL proto num while parsing tuple");
        return -1;
    }
    tuple->dst.protonum = nla_get_u8(proto[CTA_PROTO_NUM]);
    switch(tuple->dst.protonum)  {
    case IPPROTO_TCP:
    case IPPROTO_UDP:
    case IPPROTO_UDPLITE:
        if(! proto[CTA_PROTO_SRC_PORT] || ! proto[CTA_PROTO_DST_PORT])  {
            PR_WARN("unexpected NULL port while parsing tuple");
            return -1;
        }
        tuple->src.u.tcp.port = nla_get_be16(proto[CTA_PROTO_SRC_PORT]);
        tuple->dst.u.tcp.port = nla_get_be16(proto[CTA_PROTO_DST_PORT]);
        break;
    case IPPROTO_ICMP:
        if(! proto[CTA_PROTO_ICMP_ID] || ! proto[CTA_PROTO_ICMP_TYPE] || ! proto[CTA_PROTO_ICMP_CODE])  {
            PR_WARN("unexpected NULL icmp attr while parsing tuple");
            return -1;
        }
        tuple->src.u.icmp.id = nla_get_be16(proto[CTA_PROTO_ICMP_ID]);
        tuple->dst.u.icmp.type = nla_get_u8(proto[CTA_PROTO_ICMP_TYPE]);
        tuple->dst.u.icmp.code = nla_get_u8(proto[CTA_PROTO_ICMP_CODE]);
        break;
    case IPPROTO_ICMPV6:
        if(! proto[CTA_PROTO_ICMPV6_ID]
           || ! proto[CTA_PROTO_ICMPV6_TYPE]
           || ! proto[CTA_PROTO_ICMPV6_CODE])  {
            PR_WARN("unexpected NULL icmpv6 attr while parsing tuple");
            return -1;
        }
        tuple->src.u.icmp.id = nla_get_be16(proto[CTA_PROTO_ICMPV6_ID]);
        tuple->dst.u.icmp.type = nla_get_u8(proto[CTA_PROTO_ICMPV6_TYPE]);
        tuple->dst.u.icmp.code = nla_get_u8(proto[CTA_PROTO_ICMPV6_CODE]);
        break;
    default:
        PR_INFO("unsupported proto %d while parsing tuple", tuple->dst.protonum);
        return -1;
    }
    return 0;
}

/* fixme: nat seq adj */

nfct_msg *nfct_msg_new(__u8 l3num, int flags)
{
    ginkgo_msg *msg;
    struct nlmsghdr *nlh;
    struct nfgenmsg *nfmsg;
    nfct_msg_ctl *ctl;
    conn_entry *e;

    if((msg = ginkgo_new_msg(0, NFCT_MSG_GOOD_SIZE)))  {
        if(! instantiate(e))  {
            free(msg);
            return NULL;
        }

        nlh = NL_HEADER(msg);
        BZERO(nlh);
        nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
        if(flags & NFCT_F_CREATE)
            nlh->nlmsg_flags |= NLM_F_CREATE;
        if(flags & NFCT_F_EXCL)
            nlh->nlmsg_flags |= NLM_F_EXCL;
        if(flags & NFCT_F_DUMP)
            nlh->nlmsg_flags |= NLM_F_DUMP;

        nfmsg = (struct nfgenmsg *)NLMSG_DATA(nlh);
        nfmsg->nfgen_family = l3num;
        nfmsg->version = NFNETLINK_V0;
        nfmsg->res_id = 0;

        BZERO(e);
        e->l3num = l3num;

        ctl = msg_ctl(msg);
        BZERO(ctl);
        ctl->base.entry = e;
        ctl->ctx = (char *)nfmsg + NLMSG_ALIGN(sizeof(struct nfgenmsg));
        ctl->sz = NFCT_MSG_GOOD_SIZE;
        return (nfct_msg *)ctl;
    }
    return NULL;
}
コード例 #25
0
ファイル: nft_log.c プロジェクト: 383530895/linux
static int nft_log_init(const struct nft_ctx *ctx,
			const struct nft_expr *expr,
			const struct nlattr * const tb[])
{
	struct nft_log *priv = nft_expr_priv(expr);
	struct nf_loginfo *li = &priv->loginfo;
	const struct nlattr *nla;
	int ret;

	nla = tb[NFTA_LOG_PREFIX];
	if (nla != NULL) {
		priv->prefix = kmalloc(nla_len(nla) + 1, GFP_KERNEL);
		if (priv->prefix == NULL)
			return -ENOMEM;
		nla_strlcpy(priv->prefix, nla, nla_len(nla) + 1);
	} else {
		priv->prefix = (char *)nft_log_null_prefix;
	}

	li->type = NF_LOG_TYPE_LOG;
	if (tb[NFTA_LOG_LEVEL] != NULL &&
	    tb[NFTA_LOG_GROUP] != NULL)
		return -EINVAL;
	if (tb[NFTA_LOG_GROUP] != NULL)
		li->type = NF_LOG_TYPE_ULOG;

	switch (li->type) {
	case NF_LOG_TYPE_LOG:
		if (tb[NFTA_LOG_LEVEL] != NULL) {
			li->u.log.level =
				ntohl(nla_get_be32(tb[NFTA_LOG_LEVEL]));
		} else {
			li->u.log.level = 4;
		}
		if (tb[NFTA_LOG_FLAGS] != NULL) {
			li->u.log.logflags =
				ntohl(nla_get_be32(tb[NFTA_LOG_FLAGS]));
		}
		break;
	case NF_LOG_TYPE_ULOG:
		li->u.ulog.group = ntohs(nla_get_be16(tb[NFTA_LOG_GROUP]));
		if (tb[NFTA_LOG_SNAPLEN] != NULL) {
			li->u.ulog.copy_len =
				ntohl(nla_get_be32(tb[NFTA_LOG_SNAPLEN]));
		}
		if (tb[NFTA_LOG_QTHRESHOLD] != NULL) {
			li->u.ulog.qthreshold =
				ntohs(nla_get_be16(tb[NFTA_LOG_QTHRESHOLD]));
		}
		break;
	}

	if (ctx->afi->family == NFPROTO_INET) {
		ret = nf_logger_find_get(NFPROTO_IPV4, li->type);
		if (ret < 0)
			return ret;

		ret = nf_logger_find_get(NFPROTO_IPV6, li->type);
		if (ret < 0) {
			nf_logger_put(NFPROTO_IPV4, li->type);
			return ret;
		}
		return 0;
	}

	return nf_logger_find_get(ctx->afi->family, li->type);
}
コード例 #26
0
ファイル: nft_nat.c プロジェクト: 020gzh/linux
static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
			const struct nlattr * const tb[])
{
	struct nft_nat *priv = nft_expr_priv(expr);
	unsigned int alen, plen;
	u32 family;
	int err;

	if (tb[NFTA_NAT_TYPE] == NULL ||
	    (tb[NFTA_NAT_REG_ADDR_MIN] == NULL &&
	     tb[NFTA_NAT_REG_PROTO_MIN] == NULL))
		return -EINVAL;

	switch (ntohl(nla_get_be32(tb[NFTA_NAT_TYPE]))) {
	case NFT_NAT_SNAT:
		priv->type = NF_NAT_MANIP_SRC;
		break;
	case NFT_NAT_DNAT:
		priv->type = NF_NAT_MANIP_DST;
		break;
	default:
		return -EINVAL;
	}

	err = nft_nat_validate(ctx, expr, NULL);
	if (err < 0)
		return err;

	if (tb[NFTA_NAT_FAMILY] == NULL)
		return -EINVAL;

	family = ntohl(nla_get_be32(tb[NFTA_NAT_FAMILY]));
	if (family != ctx->afi->family)
		return -EOPNOTSUPP;

	switch (family) {
	case NFPROTO_IPV4:
		alen = FIELD_SIZEOF(struct nf_nat_range, min_addr.ip);
		break;
	case NFPROTO_IPV6:
		alen = FIELD_SIZEOF(struct nf_nat_range, min_addr.ip6);
		break;
	default:
		return -EAFNOSUPPORT;
	}
	priv->family = family;

	if (tb[NFTA_NAT_REG_ADDR_MIN]) {
		priv->sreg_addr_min =
			nft_parse_register(tb[NFTA_NAT_REG_ADDR_MIN]);
		err = nft_validate_register_load(priv->sreg_addr_min, alen);
		if (err < 0)
			return err;

		if (tb[NFTA_NAT_REG_ADDR_MAX]) {
			priv->sreg_addr_max =
				nft_parse_register(tb[NFTA_NAT_REG_ADDR_MAX]);

			err = nft_validate_register_load(priv->sreg_addr_max,
							 alen);
			if (err < 0)
				return err;
		} else {
			priv->sreg_addr_max = priv->sreg_addr_min;
		}
	}

	plen = FIELD_SIZEOF(struct nf_nat_range, min_addr.all);
	if (tb[NFTA_NAT_REG_PROTO_MIN]) {
		priv->sreg_proto_min =
			nft_parse_register(tb[NFTA_NAT_REG_PROTO_MIN]);

		err = nft_validate_register_load(priv->sreg_proto_min, plen);
		if (err < 0)
			return err;

		if (tb[NFTA_NAT_REG_PROTO_MAX]) {
			priv->sreg_proto_max =
				nft_parse_register(tb[NFTA_NAT_REG_PROTO_MAX]);

			err = nft_validate_register_load(priv->sreg_proto_max,
							 plen);
			if (err < 0)
				return err;
		} else {
			priv->sreg_proto_max = priv->sreg_proto_min;
		}
	}

	if (tb[NFTA_NAT_FLAGS]) {
		priv->flags = ntohl(nla_get_be32(tb[NFTA_NAT_FLAGS]));
		if (priv->flags & ~NF_NAT_RANGE_MASK)
			return -EINVAL;
	}

	return 0;
}
コード例 #27
0
static int nft_ct_get_init(const struct nft_ctx *ctx,
                           const struct nft_expr *expr,
                           const struct nlattr * const tb[])
{
    struct nft_ct *priv = nft_expr_priv(expr);
    unsigned int len;
    int err;

    priv->key = ntohl(nla_get_be32(tb[NFTA_CT_KEY]));
    switch (priv->key) {
    case NFT_CT_DIRECTION:
        if (tb[NFTA_CT_DIRECTION] != NULL)
            return -EINVAL;
        len = sizeof(u8);
        break;
    case NFT_CT_STATE:
    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:
        if (tb[NFTA_CT_DIRECTION] != NULL)
            return -EINVAL;
        len = sizeof(u32);
        break;
#ifdef CONFIG_NF_CONNTRACK_LABELS
    case NFT_CT_LABELS:
        if (tb[NFTA_CT_DIRECTION] != NULL)
            return -EINVAL;
        len = NF_CT_LABELS_MAX_SIZE;
        break;
#endif
    case NFT_CT_HELPER:
        if (tb[NFTA_CT_DIRECTION] != NULL)
            return -EINVAL;
        len = NF_CT_HELPER_NAME_LEN;
        break;

    case NFT_CT_L3PROTOCOL:
    case NFT_CT_PROTOCOL:
        if (tb[NFTA_CT_DIRECTION] == NULL)
            return -EINVAL;
        len = sizeof(u8);
        break;
    case NFT_CT_SRC:
    case NFT_CT_DST:
        if (tb[NFTA_CT_DIRECTION] == NULL)
            return -EINVAL;

        switch (ctx->afi->family) {
        case NFPROTO_IPV4:
            len = FIELD_SIZEOF(struct nf_conntrack_tuple,
                               src.u3.ip);
            break;
        case NFPROTO_IPV6:
        case NFPROTO_INET:
            len = FIELD_SIZEOF(struct nf_conntrack_tuple,
                               src.u3.ip6);
            break;
        default:
            return -EAFNOSUPPORT;
        }
        break;
    case NFT_CT_PROTO_SRC:
    case NFT_CT_PROTO_DST:
        if (tb[NFTA_CT_DIRECTION] == NULL)
            return -EINVAL;
        len = FIELD_SIZEOF(struct nf_conntrack_tuple, src.u.all);
        break;
    case NFT_CT_BYTES:
    case NFT_CT_PKTS:
        /* no direction? return sum of original + reply */
        if (tb[NFTA_CT_DIRECTION] == NULL)
            priv->dir = IP_CT_DIR_MAX;
        len = sizeof(u64);
        break;
    default:
        return -EOPNOTSUPP;
    }

    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;
        }
    }

    priv->dreg = nft_parse_register(tb[NFTA_CT_DREG]);
    err = nft_validate_register_store(ctx, priv->dreg, NULL,
                                      NFT_DATA_VALUE, len);
    if (err < 0)
        return err;

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

    if (priv->key == NFT_CT_BYTES || priv->key == NFT_CT_PKTS)
        nf_ct_set_acct(ctx->net, true);

    return 0;
}
コード例 #28
0
static int tunnel_key_init(struct net *net, struct nlattr *nla,
			   struct nlattr *est, struct tc_action **a,
			   int ovr, int bind)
{
	struct tc_action_net *tn = net_generic(net, tunnel_key_net_id);
	struct nlattr *tb[TCA_TUNNEL_KEY_MAX + 1];
	struct tcf_tunnel_key_params *params_old;
	struct tcf_tunnel_key_params *params_new;
	struct metadata_dst *metadata = NULL;
	struct tc_tunnel_key *parm;
	struct tcf_tunnel_key *t;
	bool exists = false;
	__be16 dst_port = 0;
	__be64 key_id;
	int ret = 0;
	int err;

	if (!nla)
		return -EINVAL;

	err = nla_parse_nested(tb, TCA_TUNNEL_KEY_MAX, nla, tunnel_key_policy);
	if (err < 0)
		return err;

	if (!tb[TCA_TUNNEL_KEY_PARMS])
		return -EINVAL;

	parm = nla_data(tb[TCA_TUNNEL_KEY_PARMS]);
	exists = tcf_hash_check(tn, parm->index, a, bind);
	if (exists && bind)
		return 0;

	switch (parm->t_action) {
	case TCA_TUNNEL_KEY_ACT_RELEASE:
		break;
	case TCA_TUNNEL_KEY_ACT_SET:
		if (!tb[TCA_TUNNEL_KEY_ENC_KEY_ID]) {
			ret = -EINVAL;
			goto err_out;
		}

		key_id = key32_to_tunnel_id(nla_get_be32(tb[TCA_TUNNEL_KEY_ENC_KEY_ID]));

		if (tb[TCA_TUNNEL_KEY_ENC_DST_PORT])
			dst_port = nla_get_be16(tb[TCA_TUNNEL_KEY_ENC_DST_PORT]);

		if (tb[TCA_TUNNEL_KEY_ENC_IPV4_SRC] &&
		    tb[TCA_TUNNEL_KEY_ENC_IPV4_DST]) {
			__be32 saddr;
			__be32 daddr;

			saddr = nla_get_in_addr(tb[TCA_TUNNEL_KEY_ENC_IPV4_SRC]);
			daddr = nla_get_in_addr(tb[TCA_TUNNEL_KEY_ENC_IPV4_DST]);

			metadata = __ip_tun_set_dst(saddr, daddr, 0, 0,
						    dst_port, TUNNEL_KEY,
						    key_id, 0);
		} else if (tb[TCA_TUNNEL_KEY_ENC_IPV6_SRC] &&
			   tb[TCA_TUNNEL_KEY_ENC_IPV6_DST]) {
			struct in6_addr saddr;
			struct in6_addr daddr;

			saddr = nla_get_in6_addr(tb[TCA_TUNNEL_KEY_ENC_IPV6_SRC]);
			daddr = nla_get_in6_addr(tb[TCA_TUNNEL_KEY_ENC_IPV6_DST]);

			metadata = __ipv6_tun_set_dst(&saddr, &daddr, 0, 0, 0,
						      dst_port, TUNNEL_KEY,
						      key_id, 0);
		}

		if (!metadata) {
			ret = -EINVAL;
			goto err_out;
		}

		metadata->u.tun_info.mode |= IP_TUNNEL_INFO_TX;
		break;
	default:
		goto err_out;
	}

	if (!exists) {
		ret = tcf_hash_create(tn, parm->index, est, a,
				      &act_tunnel_key_ops, bind, true);
		if (ret)
			return ret;

		ret = ACT_P_CREATED;
	} else {
		tcf_hash_release(*a, bind);
		if (!ovr)
			return -EEXIST;
	}

	t = to_tunnel_key(*a);

	ASSERT_RTNL();
	params_new = kzalloc(sizeof(*params_new), GFP_KERNEL);
	if (unlikely(!params_new)) {
		if (ret == ACT_P_CREATED)
			tcf_hash_release(*a, bind);
		return -ENOMEM;
	}

	params_old = rtnl_dereference(t->params);

	params_new->action = parm->action;
	params_new->tcft_action = parm->t_action;
	params_new->tcft_enc_metadata = metadata;

	rcu_assign_pointer(t->params, params_new);

	if (params_old)
		kfree_rcu(params_old, rcu);

	if (ret == ACT_P_CREATED)
		tcf_hash_insert(tn, *a);

	return ret;

err_out:
	if (exists)
		tcf_hash_release(*a, bind);
	return ret;
}
コード例 #29
0
static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh)
{
	struct nlattr *tb[IFA_MAX+1];
	struct in_ifaddr *ifa;
	struct ifaddrmsg *ifm;
	struct net_device *dev;
	struct in_device *in_dev;
	int err;

	err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy);
	if (err < 0)
		goto errout;

	ifm = nlmsg_data(nlh);
	err = -EINVAL;
	if (ifm->ifa_prefixlen > 32 || tb[IFA_LOCAL] == NULL)
		goto errout;

	dev = __dev_get_by_index(net, ifm->ifa_index);
	err = -ENODEV;
	if (dev == NULL)
		goto errout;

	in_dev = __in_dev_get_rtnl(dev);
	err = -ENOBUFS;
	if (in_dev == NULL)
		goto errout;

	ifa = inet_alloc_ifa();
	if (ifa == NULL)
		/*
		 * A potential indev allocation can be left alive, it stays
		 * assigned to its device and is destroy with it.
		 */
		goto errout;

	ipv4_devconf_setall(in_dev);
	in_dev_hold(in_dev);

	if (tb[IFA_ADDRESS] == NULL)
		tb[IFA_ADDRESS] = tb[IFA_LOCAL];

	ifa->ifa_prefixlen = ifm->ifa_prefixlen;
	ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen);
	ifa->ifa_flags = ifm->ifa_flags;
	ifa->ifa_scope = ifm->ifa_scope;
	ifa->ifa_dev = in_dev;

	ifa->ifa_local = nla_get_be32(tb[IFA_LOCAL]);
	ifa->ifa_address = nla_get_be32(tb[IFA_ADDRESS]);

	if (tb[IFA_BROADCAST])
		ifa->ifa_broadcast = nla_get_be32(tb[IFA_BROADCAST]);

	if (tb[IFA_LABEL])
		nla_strlcpy(ifa->ifa_label, tb[IFA_LABEL], IFNAMSIZ);
	else
		memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);

	return ifa;

errout:
	return ERR_PTR(err);
}
コード例 #30
0
ファイル: nft_meta.c プロジェクト: AlexShiLucky/linux
static int nft_meta_get_init(const struct nft_ctx *ctx,
			     const struct nft_expr *expr,
			     const struct nlattr * const tb[])
{
	struct nft_meta *priv = nft_expr_priv(expr);
	unsigned int len;

	priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY]));
	switch (priv->key) {
	case NFT_META_PROTOCOL:
	case NFT_META_IIFTYPE:
	case NFT_META_OIFTYPE:
		len = sizeof(u16);
		break;
	case NFT_META_NFPROTO:
	case NFT_META_L4PROTO:
	case NFT_META_LEN:
	case NFT_META_PRIORITY:
	case NFT_META_MARK:
	case NFT_META_IIF:
	case NFT_META_OIF:
	case NFT_META_SKUID:
	case NFT_META_SKGID:
#ifdef CONFIG_IP_ROUTE_CLASSID
	case NFT_META_RTCLASSID:
#endif
#ifdef CONFIG_NETWORK_SECMARK
	case NFT_META_SECMARK:
#endif
	case NFT_META_PKTTYPE:
	case NFT_META_CPU:
	case NFT_META_IIFGROUP:
	case NFT_META_OIFGROUP:
#ifdef CONFIG_CGROUP_NET_CLASSID
	case NFT_META_CGROUP:
#endif
		len = sizeof(u32);
		break;
	case NFT_META_IIFNAME:
	case NFT_META_OIFNAME:
		len = IFNAMSIZ;
		break;
	case NFT_META_PRANDOM:
		prandom_init_once(&nft_prandom_state);
		len = sizeof(u32);
		break;
#ifdef CONFIG_XFRM
	case NFT_META_SECPATH:
		len = sizeof(u8);
		break;
#endif
#ifdef CONFIG_NF_TABLES_BRIDGE
	case NFT_META_BRI_IIFNAME:
	case NFT_META_BRI_OIFNAME:
		if (ctx->family != NFPROTO_BRIDGE)
			return -EOPNOTSUPP;
		len = IFNAMSIZ;
		break;
#endif
	default:
		return -EOPNOTSUPP;
	}

	priv->dreg = nft_parse_register(tb[NFTA_META_DREG]);
	return nft_validate_register_store(ctx, priv->dreg, NULL,
					   NFT_DATA_VALUE, len);
}