Skip to content

Commit 60a3815

Browse files
committed
netfilter: add inet ingress support
This patch adds the NF_INET_INGRESS pseudohook for the NFPROTO_INET family. This is a mapping this new hook to the existing NFPROTO_NETDEV and NF_NETDEV_INGRESS hook. The hook does not guarantee that packets are inet only, users must filter out non-ip traffic explicitly. This infrastructure makes it easier to support this new hook in nf_tables. Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
1 parent ddcfa71 commit 60a3815

2 files changed

Lines changed: 83 additions & 21 deletions

File tree

include/uapi/linux/netfilter.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ enum nf_inet_hooks {
4545
NF_INET_FORWARD,
4646
NF_INET_LOCAL_OUT,
4747
NF_INET_POST_ROUTING,
48+
NF_INET_INGRESS,
4849
NF_INET_NUMHOOKS
4950
};
5051

net/netfilter/core.c

Lines changed: 82 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,16 @@ nf_hook_entry_head(struct net *net, int pf, unsigned int hooknum,
281281
if (WARN_ON_ONCE(ARRAY_SIZE(net->nf.hooks_bridge) <= hooknum))
282282
return NULL;
283283
return net->nf.hooks_bridge + hooknum;
284+
#endif
285+
#ifdef CONFIG_NETFILTER_INGRESS
286+
case NFPROTO_INET:
287+
if (WARN_ON_ONCE(hooknum != NF_INET_INGRESS))
288+
return NULL;
289+
if (!dev || dev_net(dev) != net) {
290+
WARN_ON_ONCE(1);
291+
return NULL;
292+
}
293+
return &dev->nf_hooks_ingress;
284294
#endif
285295
case NFPROTO_IPV4:
286296
if (WARN_ON_ONCE(ARRAY_SIZE(net->nf.hooks_ipv4) <= hooknum))
@@ -311,22 +321,56 @@ nf_hook_entry_head(struct net *net, int pf, unsigned int hooknum,
311321
return NULL;
312322
}
313323

324+
static int nf_ingress_check(struct net *net, const struct nf_hook_ops *reg,
325+
int hooknum)
326+
{
327+
#ifndef CONFIG_NETFILTER_INGRESS
328+
if (reg->hooknum == hooknum)
329+
return -EOPNOTSUPP;
330+
#endif
331+
if (reg->hooknum != hooknum ||
332+
!reg->dev || dev_net(reg->dev) != net)
333+
return -EINVAL;
334+
335+
return 0;
336+
}
337+
314338
static inline bool nf_ingress_hook(const struct nf_hook_ops *reg, int pf)
315339
{
316-
return pf == NFPROTO_NETDEV && reg->hooknum == NF_NETDEV_INGRESS;
340+
if ((pf == NFPROTO_NETDEV && reg->hooknum == NF_NETDEV_INGRESS) ||
341+
(pf == NFPROTO_INET && reg->hooknum == NF_INET_INGRESS))
342+
return true;
343+
344+
return false;
317345
}
318346

319347
static void nf_static_key_inc(const struct nf_hook_ops *reg, int pf)
320348
{
321349
#ifdef CONFIG_JUMP_LABEL
322-
static_key_slow_inc(&nf_hooks_needed[pf][reg->hooknum]);
350+
int hooknum;
351+
352+
if (pf == NFPROTO_INET && reg->hooknum == NF_INET_INGRESS) {
353+
pf = NFPROTO_NETDEV;
354+
hooknum = NF_NETDEV_INGRESS;
355+
} else {
356+
hooknum = reg->hooknum;
357+
}
358+
static_key_slow_inc(&nf_hooks_needed[pf][hooknum]);
323359
#endif
324360
}
325361

326362
static void nf_static_key_dec(const struct nf_hook_ops *reg, int pf)
327363
{
328364
#ifdef CONFIG_JUMP_LABEL
329-
static_key_slow_dec(&nf_hooks_needed[pf][reg->hooknum]);
365+
int hooknum;
366+
367+
if (pf == NFPROTO_INET && reg->hooknum == NF_INET_INGRESS) {
368+
pf = NFPROTO_NETDEV;
369+
hooknum = NF_NETDEV_INGRESS;
370+
} else {
371+
hooknum = reg->hooknum;
372+
}
373+
static_key_slow_dec(&nf_hooks_needed[pf][hooknum]);
330374
#endif
331375
}
332376

@@ -335,15 +379,22 @@ static int __nf_register_net_hook(struct net *net, int pf,
335379
{
336380
struct nf_hook_entries *p, *new_hooks;
337381
struct nf_hook_entries __rcu **pp;
382+
int err;
338383

339-
if (pf == NFPROTO_NETDEV) {
340-
#ifndef CONFIG_NETFILTER_INGRESS
341-
if (reg->hooknum == NF_NETDEV_INGRESS)
342-
return -EOPNOTSUPP;
343-
#endif
344-
if (reg->hooknum != NF_NETDEV_INGRESS ||
345-
!reg->dev || dev_net(reg->dev) != net)
346-
return -EINVAL;
384+
switch (pf) {
385+
case NFPROTO_NETDEV:
386+
err = nf_ingress_check(net, reg, NF_NETDEV_INGRESS);
387+
if (err < 0)
388+
return err;
389+
break;
390+
case NFPROTO_INET:
391+
if (reg->hooknum != NF_INET_INGRESS)
392+
break;
393+
394+
err = nf_ingress_check(net, reg, NF_INET_INGRESS);
395+
if (err < 0)
396+
return err;
397+
break;
347398
}
348399

349400
pp = nf_hook_entry_head(net, pf, reg->hooknum, reg->dev);
@@ -441,8 +492,12 @@ static void __nf_unregister_net_hook(struct net *net, int pf,
441492
void nf_unregister_net_hook(struct net *net, const struct nf_hook_ops *reg)
442493
{
443494
if (reg->pf == NFPROTO_INET) {
444-
__nf_unregister_net_hook(net, NFPROTO_IPV4, reg);
445-
__nf_unregister_net_hook(net, NFPROTO_IPV6, reg);
495+
if (reg->hooknum == NF_INET_INGRESS) {
496+
__nf_unregister_net_hook(net, NFPROTO_INET, reg);
497+
} else {
498+
__nf_unregister_net_hook(net, NFPROTO_IPV4, reg);
499+
__nf_unregister_net_hook(net, NFPROTO_IPV6, reg);
500+
}
446501
} else {
447502
__nf_unregister_net_hook(net, reg->pf, reg);
448503
}
@@ -467,14 +522,20 @@ int nf_register_net_hook(struct net *net, const struct nf_hook_ops *reg)
467522
int err;
468523

469524
if (reg->pf == NFPROTO_INET) {
470-
err = __nf_register_net_hook(net, NFPROTO_IPV4, reg);
471-
if (err < 0)
472-
return err;
473-
474-
err = __nf_register_net_hook(net, NFPROTO_IPV6, reg);
475-
if (err < 0) {
476-
__nf_unregister_net_hook(net, NFPROTO_IPV4, reg);
477-
return err;
525+
if (reg->hooknum == NF_INET_INGRESS) {
526+
err = __nf_register_net_hook(net, NFPROTO_INET, reg);
527+
if (err < 0)
528+
return err;
529+
} else {
530+
err = __nf_register_net_hook(net, NFPROTO_IPV4, reg);
531+
if (err < 0)
532+
return err;
533+
534+
err = __nf_register_net_hook(net, NFPROTO_IPV6, reg);
535+
if (err < 0) {
536+
__nf_unregister_net_hook(net, NFPROTO_IPV4, reg);
537+
return err;
538+
}
478539
}
479540
} else {
480541
err = __nf_register_net_hook(net, reg->pf, reg);

0 commit comments

Comments
 (0)