[NETFILTER]: Core changes required by upcoming nfnetlink_queue code
- split netfiler verdict in 16bit verdict and 16bit queue number - add 'queuenum' argument to nf_queue_outfn_t and its users ip[6]_queue - move NFNL_SUBSYS_ definitions from enum to #define - introduce autoloading for nfnetlink subsystem modules - add MODULE_ALIAS_NFNL_SUBSYS macro - add nf_unregister_queue_handlers() to register all handlers for a given nf_queue_outfn_t - add more verbose DEBUGP macro definition to nfnetlink.c - make nfnetlink_subsys_register fail if subsys already exists - add some more comments and debug statements to nfnetlink.c Signed-off-by: Harald Welte <laforge@netfilter.org> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
2cc7d57309
commit
0ab43f8499
|
@ -21,6 +21,16 @@
|
||||||
#define NF_STOP 5
|
#define NF_STOP 5
|
||||||
#define NF_MAX_VERDICT NF_STOP
|
#define NF_MAX_VERDICT NF_STOP
|
||||||
|
|
||||||
|
/* we overload the higher bits for encoding auxiliary data such as the queue
|
||||||
|
* number. Not nice, but better than additional function arguments. */
|
||||||
|
#define NF_VERDICT_MASK 0x0000ffff
|
||||||
|
#define NF_VERDICT_BITS 16
|
||||||
|
|
||||||
|
#define NF_VERDICT_QMASK 0xffff0000
|
||||||
|
#define NF_VERDICT_QBITS 16
|
||||||
|
|
||||||
|
#define NF_QUEUE_NR(x) ((x << NF_VERDICT_QBITS) & NF_VERDICT_QMASK || NF_QUEUE)
|
||||||
|
|
||||||
/* only for userspace compatibility */
|
/* only for userspace compatibility */
|
||||||
#ifndef __KERNEL__
|
#ifndef __KERNEL__
|
||||||
/* Generic cache responses from hook functions.
|
/* Generic cache responses from hook functions.
|
||||||
|
@ -179,10 +189,12 @@ int nf_getsockopt(struct sock *sk, int pf, int optval, char __user *opt,
|
||||||
|
|
||||||
/* Packet queuing */
|
/* Packet queuing */
|
||||||
typedef int (*nf_queue_outfn_t)(struct sk_buff *skb,
|
typedef int (*nf_queue_outfn_t)(struct sk_buff *skb,
|
||||||
struct nf_info *info, void *data);
|
struct nf_info *info,
|
||||||
|
unsigned int queuenum, void *data);
|
||||||
extern int nf_register_queue_handler(int pf,
|
extern int nf_register_queue_handler(int pf,
|
||||||
nf_queue_outfn_t outfn, void *data);
|
nf_queue_outfn_t outfn, void *data);
|
||||||
extern int nf_unregister_queue_handler(int pf);
|
extern int nf_unregister_queue_handler(int pf);
|
||||||
|
extern void nf_unregister_queue_handlers(nf_queue_outfn_t outfn);
|
||||||
extern void nf_reinject(struct sk_buff *skb,
|
extern void nf_reinject(struct sk_buff *skb,
|
||||||
struct nf_info *info,
|
struct nf_info *info,
|
||||||
unsigned int verdict);
|
unsigned int verdict);
|
||||||
|
|
|
@ -69,15 +69,14 @@ struct nfgenmsg {
|
||||||
#define NFNL_SUBSYS_ID(x) ((x & 0xff00) >> 8)
|
#define NFNL_SUBSYS_ID(x) ((x & 0xff00) >> 8)
|
||||||
#define NFNL_MSG_TYPE(x) (x & 0x00ff)
|
#define NFNL_MSG_TYPE(x) (x & 0x00ff)
|
||||||
|
|
||||||
enum nfnl_subsys_id {
|
/* No enum here, otherwise __stringify() trick of MODULE_ALIAS_NFNL_SUBSYS()
|
||||||
NFNL_SUBSYS_NONE = 0,
|
* won't work anymore */
|
||||||
NFNL_SUBSYS_CTNETLINK,
|
#define NFNL_SUBSYS_NONE 0
|
||||||
NFNL_SUBSYS_CTNETLINK_EXP,
|
#define NFNL_SUBSYS_CTNETLINK 1
|
||||||
NFNL_SUBSYS_IPTNETLINK,
|
#define NFNL_SUBSYS_CTNETLINK_EXP 2
|
||||||
NFNL_SUBSYS_QUEUE,
|
#define NFNL_SUBSYS_QUEUE 3
|
||||||
NFNL_SUBSYS_ULOG,
|
#define NFNL_SUBSYS_ULOG 4
|
||||||
NFNL_SUBSYS_COUNT,
|
#define NFNL_SUBSYS_COUNT 5
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef __KERNEL__
|
#ifdef __KERNEL__
|
||||||
|
|
||||||
|
@ -142,5 +141,8 @@ extern int nfnetlink_send(struct sk_buff *skb, u32 pid, unsigned group,
|
||||||
int echo);
|
int echo);
|
||||||
extern int nfnetlink_unicast(struct sk_buff *skb, u_int32_t pid, int flags);
|
extern int nfnetlink_unicast(struct sk_buff *skb, u_int32_t pid, int flags);
|
||||||
|
|
||||||
|
#define MODULE_ALIAS_NFNL_SUBSYS(subsys) \
|
||||||
|
MODULE_ALIAS("nfnetlink-subsys-" __stringify(subsys))
|
||||||
|
|
||||||
#endif /* __KERNEL__ */
|
#endif /* __KERNEL__ */
|
||||||
#endif /* _NFNETLINK_H */
|
#endif /* _NFNETLINK_H */
|
||||||
|
|
|
@ -221,7 +221,8 @@ static unsigned int nf_iterate(struct list_head *head,
|
||||||
verdict = elem->hook(hook, skb, indev, outdev, okfn);
|
verdict = elem->hook(hook, skb, indev, outdev, okfn);
|
||||||
if (verdict != NF_ACCEPT) {
|
if (verdict != NF_ACCEPT) {
|
||||||
#ifdef CONFIG_NETFILTER_DEBUG
|
#ifdef CONFIG_NETFILTER_DEBUG
|
||||||
if (unlikely(verdict > NF_MAX_VERDICT)) {
|
if (unlikely((verdict & NF_VERDICT_MASK)
|
||||||
|
> NF_MAX_VERDICT)) {
|
||||||
NFDEBUG("Evil return from %p(%u).\n",
|
NFDEBUG("Evil return from %p(%u).\n",
|
||||||
elem->hook, hook);
|
elem->hook, hook);
|
||||||
continue;
|
continue;
|
||||||
|
@ -239,6 +240,9 @@ int nf_register_queue_handler(int pf, nf_queue_outfn_t outfn, void *data)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (pf >= NPROTO)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
write_lock_bh(&queue_handler_lock);
|
write_lock_bh(&queue_handler_lock);
|
||||||
if (queue_handler[pf].outfn)
|
if (queue_handler[pf].outfn)
|
||||||
ret = -EBUSY;
|
ret = -EBUSY;
|
||||||
|
@ -255,6 +259,9 @@ int nf_register_queue_handler(int pf, nf_queue_outfn_t outfn, void *data)
|
||||||
/* The caller must flush their queue before this */
|
/* The caller must flush their queue before this */
|
||||||
int nf_unregister_queue_handler(int pf)
|
int nf_unregister_queue_handler(int pf)
|
||||||
{
|
{
|
||||||
|
if (pf >= NPROTO)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
write_lock_bh(&queue_handler_lock);
|
write_lock_bh(&queue_handler_lock);
|
||||||
queue_handler[pf].outfn = NULL;
|
queue_handler[pf].outfn = NULL;
|
||||||
queue_handler[pf].data = NULL;
|
queue_handler[pf].data = NULL;
|
||||||
|
@ -286,6 +293,20 @@ int nf_unregister_queue_rerouter(int pf)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void nf_unregister_queue_handlers(nf_queue_outfn_t outfn)
|
||||||
|
{
|
||||||
|
int pf;
|
||||||
|
|
||||||
|
write_lock_bh(&queue_handler_lock);
|
||||||
|
for (pf = 0; pf < NPROTO; pf++) {
|
||||||
|
if (queue_handler[pf].outfn == outfn) {
|
||||||
|
queue_handler[pf].outfn = NULL;
|
||||||
|
queue_handler[pf].data = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
write_unlock_bh(&queue_handler_lock);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Any packet that leaves via this function must come back
|
* Any packet that leaves via this function must come back
|
||||||
* through nf_reinject().
|
* through nf_reinject().
|
||||||
|
@ -295,7 +316,8 @@ static int nf_queue(struct sk_buff **skb,
|
||||||
int pf, unsigned int hook,
|
int pf, unsigned int hook,
|
||||||
struct net_device *indev,
|
struct net_device *indev,
|
||||||
struct net_device *outdev,
|
struct net_device *outdev,
|
||||||
int (*okfn)(struct sk_buff *))
|
int (*okfn)(struct sk_buff *),
|
||||||
|
unsigned int queuenum)
|
||||||
{
|
{
|
||||||
int status;
|
int status;
|
||||||
struct nf_info *info;
|
struct nf_info *info;
|
||||||
|
@ -347,7 +369,8 @@ static int nf_queue(struct sk_buff **skb,
|
||||||
if (queue_rerouter[pf].save)
|
if (queue_rerouter[pf].save)
|
||||||
queue_rerouter[pf].save(*skb, info);
|
queue_rerouter[pf].save(*skb, info);
|
||||||
|
|
||||||
status = queue_handler[pf].outfn(*skb, info, queue_handler[pf].data);
|
status = queue_handler[pf].outfn(*skb, info, queuenum,
|
||||||
|
queue_handler[pf].data);
|
||||||
|
|
||||||
if (status >= 0 && queue_rerouter[pf].reroute)
|
if (status >= 0 && queue_rerouter[pf].reroute)
|
||||||
status = queue_rerouter[pf].reroute(skb, info);
|
status = queue_rerouter[pf].reroute(skb, info);
|
||||||
|
@ -397,9 +420,10 @@ next_hook:
|
||||||
} else if (verdict == NF_DROP) {
|
} else if (verdict == NF_DROP) {
|
||||||
kfree_skb(*pskb);
|
kfree_skb(*pskb);
|
||||||
ret = -EPERM;
|
ret = -EPERM;
|
||||||
} else if (verdict == NF_QUEUE) {
|
} else if ((verdict & NF_VERDICT_MASK) == NF_QUEUE) {
|
||||||
NFDEBUG("nf_hook: Verdict = QUEUE.\n");
|
NFDEBUG("nf_hook: Verdict = QUEUE.\n");
|
||||||
if (!nf_queue(pskb, elem, pf, hook, indev, outdev, okfn))
|
if (!nf_queue(pskb, elem, pf, hook, indev, outdev, okfn,
|
||||||
|
verdict >> NF_VERDICT_BITS))
|
||||||
goto next_hook;
|
goto next_hook;
|
||||||
}
|
}
|
||||||
unlock:
|
unlock:
|
||||||
|
@ -456,14 +480,15 @@ void nf_reinject(struct sk_buff *skb, struct nf_info *info,
|
||||||
info->okfn, INT_MIN);
|
info->okfn, INT_MIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (verdict) {
|
switch (verdict & NF_VERDICT_MASK) {
|
||||||
case NF_ACCEPT:
|
case NF_ACCEPT:
|
||||||
info->okfn(skb);
|
info->okfn(skb);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NF_QUEUE:
|
case NF_QUEUE:
|
||||||
if (!nf_queue(&skb, elem, info->pf, info->hook,
|
if (!nf_queue(&skb, elem, info->pf, info->hook,
|
||||||
info->indev, info->outdev, info->okfn))
|
info->indev, info->outdev, info->okfn,
|
||||||
|
verdict >> NF_VERDICT_BITS))
|
||||||
goto next_hook;
|
goto next_hook;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -613,6 +638,7 @@ EXPORT_SYMBOL(nf_reinject);
|
||||||
EXPORT_SYMBOL(nf_setsockopt);
|
EXPORT_SYMBOL(nf_setsockopt);
|
||||||
EXPORT_SYMBOL(nf_unregister_hook);
|
EXPORT_SYMBOL(nf_unregister_hook);
|
||||||
EXPORT_SYMBOL(nf_unregister_queue_handler);
|
EXPORT_SYMBOL(nf_unregister_queue_handler);
|
||||||
|
EXPORT_SYMBOL_GPL(nf_unregister_queue_handlers);
|
||||||
EXPORT_SYMBOL_GPL(nf_register_queue_rerouter);
|
EXPORT_SYMBOL_GPL(nf_register_queue_rerouter);
|
||||||
EXPORT_SYMBOL_GPL(nf_unregister_queue_rerouter);
|
EXPORT_SYMBOL_GPL(nf_unregister_queue_rerouter);
|
||||||
EXPORT_SYMBOL(nf_unregister_sockopt);
|
EXPORT_SYMBOL(nf_unregister_sockopt);
|
||||||
|
|
|
@ -280,7 +280,8 @@ nlmsg_failure:
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ipq_enqueue_packet(struct sk_buff *skb, struct nf_info *info, void *data)
|
ipq_enqueue_packet(struct sk_buff *skb, struct nf_info *info,
|
||||||
|
unsigned int queuenum, void *data)
|
||||||
{
|
{
|
||||||
int status = -EINVAL;
|
int status = -EINVAL;
|
||||||
struct sk_buff *nskb;
|
struct sk_buff *nskb;
|
||||||
|
|
|
@ -278,7 +278,8 @@ nlmsg_failure:
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ipq_enqueue_packet(struct sk_buff *skb, struct nf_info *info, void *data)
|
ipq_enqueue_packet(struct sk_buff *skb, struct nf_info *info,
|
||||||
|
unsigned int queuenum, void *data)
|
||||||
{
|
{
|
||||||
int status = -EINVAL;
|
int status = -EINVAL;
|
||||||
struct sk_buff *nskb;
|
struct sk_buff *nskb;
|
||||||
|
|
|
@ -44,7 +44,9 @@ MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_NETFILTER);
|
||||||
static char __initdata nfversion[] = "0.30";
|
static char __initdata nfversion[] = "0.30";
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
#define DEBUGP printk
|
#define DEBUGP(format, args...) \
|
||||||
|
printk(KERN_DEBUG "%s(%d):%s(): " format, __FILE__, \
|
||||||
|
__LINE__, __FUNCTION__, ## args)
|
||||||
#else
|
#else
|
||||||
#define DEBUGP(format, args...)
|
#define DEBUGP(format, args...)
|
||||||
#endif
|
#endif
|
||||||
|
@ -67,11 +69,11 @@ int nfnetlink_subsys_register(struct nfnetlink_subsystem *n)
|
||||||
{
|
{
|
||||||
DEBUGP("registering subsystem ID %u\n", n->subsys_id);
|
DEBUGP("registering subsystem ID %u\n", n->subsys_id);
|
||||||
|
|
||||||
/* If the netlink socket wasn't created, then fail */
|
|
||||||
if (!nfnl)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
nfnl_lock();
|
nfnl_lock();
|
||||||
|
if (subsys_table[n->subsys_id]) {
|
||||||
|
nfnl_unlock();
|
||||||
|
return -EBUSY;
|
||||||
|
}
|
||||||
subsys_table[n->subsys_id] = n;
|
subsys_table[n->subsys_id] = n;
|
||||||
nfnl_unlock();
|
nfnl_unlock();
|
||||||
|
|
||||||
|
@ -227,8 +229,18 @@ static inline int nfnetlink_rcv_msg(struct sk_buff *skb,
|
||||||
|
|
||||||
type = nlh->nlmsg_type;
|
type = nlh->nlmsg_type;
|
||||||
ss = nfnetlink_get_subsys(type);
|
ss = nfnetlink_get_subsys(type);
|
||||||
if (!ss)
|
if (!ss) {
|
||||||
|
#ifdef CONFIG_KMOD
|
||||||
|
/* don't call nfnl_shunlock, since it would reenter
|
||||||
|
* with further packet processing */
|
||||||
|
up(&nfnl_sem);
|
||||||
|
request_module("nfnetlink-subsys-%d", NFNL_SUBSYS_ID(type));
|
||||||
|
nfnl_shlock();
|
||||||
|
ss = nfnetlink_get_subsys(type);
|
||||||
|
if (!ss)
|
||||||
|
#endif
|
||||||
goto err_inval;
|
goto err_inval;
|
||||||
|
}
|
||||||
|
|
||||||
nc = nfnetlink_find_client(type, ss);
|
nc = nfnetlink_find_client(type, ss);
|
||||||
if (!nc) {
|
if (!nc) {
|
||||||
|
@ -252,12 +264,14 @@ static inline int nfnetlink_rcv_msg(struct sk_buff *skb,
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto err_inval;
|
goto err_inval;
|
||||||
|
|
||||||
|
DEBUGP("calling handler\n");
|
||||||
err = nc->call(nfnl, skb, nlh, cda, errp);
|
err = nc->call(nfnl, skb, nlh, cda, errp);
|
||||||
*errp = err;
|
*errp = err;
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
err_inval:
|
err_inval:
|
||||||
|
DEBUGP("returning -EINVAL\n");
|
||||||
*errp = -EINVAL;
|
*errp = -EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -311,6 +325,8 @@ static void nfnetlink_rcv(struct sock *sk, int len)
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* don't call nfnl_shunlock, since it would reenter
|
||||||
|
* with further packet processing */
|
||||||
up(&nfnl_sem);
|
up(&nfnl_sem);
|
||||||
} while(nfnl && nfnl->sk_receive_queue.qlen);
|
} while(nfnl && nfnl->sk_receive_queue.qlen);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue