Hi Pablo,
On 6/26/19 11:24 AM, Pablo Neira Ayuso wrote:
> On Tue, Jun 25, 2019 at 12:37:11PM +0200, Fernando Fernandez Mancera wrote:
> [...]
>> +static int nft_synproxy_init(const struct nft_ctx *ctx,
>> + const struct nft_expr *expr,
>> + const struct nlattr * const tb[])
>> +{
>> + struct synproxy_net *snet = synproxy_pernet(ctx->net);
>> + struct nft_synproxy *priv = nft_expr_priv(expr);
>> + u32 flags;
>> + int err;
>> +
>> + if (tb[NFTA_SYNPROXY_MSS])
>> + priv->info.mss = ntohs(nla_get_be16(tb[NFTA_SYNPROXY_MSS]));
>> + if (tb[NFTA_SYNPROXY_WSCALE])
>> + priv->info.wscale = nla_get_u8(tb[NFTA_SYNPROXY_WSCALE]);
>> + if (tb[NFTA_SYNPROXY_FLAGS]) {
>> + flags = ntohl(nla_get_be32(tb[NFTA_SYNPROXY_FLAGS]));
>> + if (flags != 0 && (flags & NF_SYNPROXY_OPT_MASK) == 0)
>
> Question: Is flag == 0 valid? If so, no need to return EINVAL in this
> case.
Yes, following the iptables behavior, in nftables we can set something
like this:
table ip x {
chain y {
type filter hook prerouting priority raw; policy accept;
tcp flags syn notrack
}
chain z {
type filter hook input priority filter; policy accept;
ct state { invalid, untracked } synproxy
ct state invalid drop
}
}
In this case, flags == 0 because there is anything set.
>
>> + return -EINVAL;
>> + priv->info.options = flags;
>> + }
>> +
>> + err = nf_ct_netns_get(ctx->net, ctx->family);
>> + if (err)
>> + return err;
>> +
>> + switch (ctx->family) {
>> + case NFPROTO_IPV4:
>> + err = nf_synproxy_ipv4_init(snet, ctx->net);
>> + if (err)
>> + goto nf_ct_failure;
>> + snet->hook_ref4++;
>
> nf_synproxy_ipv4_init() internally deals with bumping hook_ref4,
> right?
>
Yes, sorry I forgot to remove it. Same for the IPv6 bump.
>> + break;
>> +#if IS_ENABLED(CONFIG_IPV6)
>> + case NFPROTO_IPV6:
>> + err = nf_synproxy_ipv6_init(snet, ctx->net);
>> + if (err)
>> + goto nf_ct_failure;
>> + snet->hook_ref6++;
>
> Same here.
>
>> + break;
>
> #endif /* CONFIG_IPV6 */
>
> Note that #endif should finish here, NFPROTO_INET and NFPROTO_BRIDGE
> should not be wrapper by this.
>
> finishes here. You can probably replace this to CONFIG_NF_TABLES_IPV6
> as above, right?
Yes. In this case we can replace it with CONFIG_NF_TABLES_IPV6.
>
>> + case NFPROTO_INET:
>> + case NFPROTO_BRIDGE:
>> + err = nf_synproxy_ipv4_init(snet, ctx->net);
>> + if (err)
>> + goto nf_ct_failure;
>
> Missing ifdef.
>
>> + err = nf_synproxy_ipv6_init(snet, ctx->net);
>> + if (err)
>> + goto nf_ct_failure;
>> + snet->hook_ref4++;
>> + snet->hook_ref6++;
>
> Bumping refcnt manually?
>
>> + break;
>> +#endif
>> + }
>> +
>> + return 0;
>> +
>> +nf_ct_failure:
>> + nf_ct_netns_put(ctx->net, ctx->family);
>> + return err;
>> +}
>> +
>> +static void nft_synproxy_destroy(const struct nft_ctx *ctx,
>> + const struct nft_expr *expr)
>> +{
>> + struct synproxy_net *snet = synproxy_pernet(ctx->net);
>> +
>> + switch (ctx->family) {
>> + case NFPROTO_IPV4:
>> + nf_synproxy_ipv4_fini(snet, ctx->net);
>> + break;
>> +#if IS_ENABLED(CONFIG_IPV6)
>> + case NFPROTO_IPV6:
>> + nf_synproxy_ipv6_fini(snet, ctx->net);
>> + break;
>> + case NFPROTO_INET:
>> + case NFPROTO_BRIDGE:
>> + nf_synproxy_ipv4_fini(snet, ctx->net);
>
> We should allow bridge to run only with IPv4, if CONFIG_IPV6 is unset.
>
> Just wrap this:
>
> #ifdef IS_ENABLED(...)
>
>> + nf_synproxy_ipv6_fini(snet, ctx->net);
>
> #endif
>
> Or there's another trick you can do, in the header file, you add:
>
> #ifdef IS_ENABLED(...)
> void nf_synproxy_ipv6_fini(..., ...);
> #else
> static inline void nf_synproxy_ipv6_fini(..., ...) {}
> #endid
>
> so we don't need this #ifdef in the code.
>
If there is no problem to have an inline definition with an empty body
then this is a good trick to avoid the #ifdef.