diff options
| -rw-r--r-- | include/linux/netfilter.h | 14 | ||||
| -rw-r--r-- | include/linux/netfilter/nfnetlink.h | 20 | ||||
| -rw-r--r-- | net/core/netfilter.c | 40 | ||||
| -rw-r--r-- | net/ipv4/netfilter/ip_queue.c | 3 | ||||
| -rw-r--r-- | net/ipv6/netfilter/ip6_queue.c | 3 | ||||
| -rw-r--r-- | net/netfilter/nfnetlink.c | 28 | 
6 files changed, 83 insertions, 25 deletions
| diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index d163e20ca8d9..711e05f33d68 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h | |||
| @@ -21,6 +21,16 @@ | |||
| 21 | #define NF_STOP 5 | 21 | #define NF_STOP 5 | 
| 22 | #define NF_MAX_VERDICT NF_STOP | 22 | #define NF_MAX_VERDICT NF_STOP | 
| 23 | 23 | ||
| 24 | /* we overload the higher bits for encoding auxiliary data such as the queue | ||
| 25 | * number. Not nice, but better than additional function arguments. */ | ||
| 26 | #define NF_VERDICT_MASK 0x0000ffff | ||
| 27 | #define NF_VERDICT_BITS 16 | ||
| 28 | |||
| 29 | #define NF_VERDICT_QMASK 0xffff0000 | ||
| 30 | #define NF_VERDICT_QBITS 16 | ||
| 31 | |||
| 32 | #define NF_QUEUE_NR(x) ((x << NF_VERDICT_QBITS) & NF_VERDICT_QMASK || NF_QUEUE) | ||
| 33 | |||
| 24 | /* only for userspace compatibility */ | 34 | /* only for userspace compatibility */ | 
| 25 | #ifndef __KERNEL__ | 35 | #ifndef __KERNEL__ | 
| 26 | /* Generic cache responses from hook functions. | 36 | /* Generic cache responses from hook functions. | 
| @@ -179,10 +189,12 @@ int nf_getsockopt(struct sock *sk, int pf, int optval, char __user *opt, | |||
| 179 | 189 | ||
| 180 | /* Packet queuing */ | 190 | /* Packet queuing */ | 
| 181 | typedef int (*nf_queue_outfn_t)(struct sk_buff *skb, | 191 | typedef int (*nf_queue_outfn_t)(struct sk_buff *skb, | 
| 182 | struct nf_info *info, void *data); | 192 | struct nf_info *info, | 
| 193 | unsigned int queuenum, void *data); | ||
| 183 | extern int nf_register_queue_handler(int pf, | 194 | extern int nf_register_queue_handler(int pf, | 
| 184 | nf_queue_outfn_t outfn, void *data); | 195 | nf_queue_outfn_t outfn, void *data); | 
| 185 | extern int nf_unregister_queue_handler(int pf); | 196 | extern int nf_unregister_queue_handler(int pf); | 
| 197 | extern void nf_unregister_queue_handlers(nf_queue_outfn_t outfn); | ||
| 186 | extern void nf_reinject(struct sk_buff *skb, | 198 | extern void nf_reinject(struct sk_buff *skb, | 
| 187 | struct nf_info *info, | 199 | struct nf_info *info, | 
| 188 | unsigned int verdict); | 200 | unsigned int verdict); | 
| diff --git a/include/linux/netfilter/nfnetlink.h b/include/linux/netfilter/nfnetlink.h index ace7a7be0742..561f9df28808 100644 --- a/include/linux/netfilter/nfnetlink.h +++ b/include/linux/netfilter/nfnetlink.h | |||
| @@ -69,15 +69,14 @@ struct nfgenmsg { | |||
| 69 | #define NFNL_SUBSYS_ID(x) ((x & 0xff00) >> 8) | 69 | #define NFNL_SUBSYS_ID(x) ((x & 0xff00) >> 8) | 
| 70 | #define NFNL_MSG_TYPE(x) (x & 0x00ff) | 70 | #define NFNL_MSG_TYPE(x) (x & 0x00ff) | 
| 71 | 71 | ||
| 72 | enum nfnl_subsys_id { | 72 | /* No enum here, otherwise __stringify() trick of MODULE_ALIAS_NFNL_SUBSYS() | 
| 73 | NFNL_SUBSYS_NONE = 0, | 73 | * won't work anymore */ | 
| 74 | NFNL_SUBSYS_CTNETLINK, | 74 | #define NFNL_SUBSYS_NONE 0 | 
| 75 | NFNL_SUBSYS_CTNETLINK_EXP, | 75 | #define NFNL_SUBSYS_CTNETLINK 1 | 
| 76 | NFNL_SUBSYS_IPTNETLINK, | 76 | #define NFNL_SUBSYS_CTNETLINK_EXP 2 | 
| 77 | NFNL_SUBSYS_QUEUE, | 77 | #define NFNL_SUBSYS_QUEUE 3 | 
| 78 | NFNL_SUBSYS_ULOG, | 78 | #define NFNL_SUBSYS_ULOG 4 | 
| 79 | NFNL_SUBSYS_COUNT, | 79 | #define NFNL_SUBSYS_COUNT 5 | 
| 80 | }; | ||
| 81 | 80 | ||
| 82 | #ifdef __KERNEL__ | 81 | #ifdef __KERNEL__ | 
| 83 | 82 | ||
| @@ -142,5 +141,8 @@ extern int nfnetlink_send(struct sk_buff *skb, u32 pid, unsigned group, | |||
| 142 | int echo); | 141 | int echo); | 
| 143 | extern int nfnetlink_unicast(struct sk_buff *skb, u_int32_t pid, int flags); | 142 | extern int nfnetlink_unicast(struct sk_buff *skb, u_int32_t pid, int flags); | 
| 144 | 143 | ||
| 144 | #define MODULE_ALIAS_NFNL_SUBSYS(subsys) \ | ||
| 145 | MODULE_ALIAS("nfnetlink-subsys-" __stringify(subsys)) | ||
| 146 | |||
| 145 | #endif /* __KERNEL__ */ | 147 | #endif /* __KERNEL__ */ | 
| 146 | #endif /* _NFNETLINK_H */ | 148 | #endif /* _NFNETLINK_H */ | 
| diff --git a/net/core/netfilter.c b/net/core/netfilter.c index 1ed4f3110421..3e38084ac2bd 100644 --- a/net/core/netfilter.c +++ b/net/core/netfilter.c | |||
| @@ -221,7 +221,8 @@ static unsigned int nf_iterate(struct list_head *head, | |||
| 221 | verdict = elem->hook(hook, skb, indev, outdev, okfn); | 221 | verdict = elem->hook(hook, skb, indev, outdev, okfn); | 
| 222 | if (verdict != NF_ACCEPT) { | 222 | if (verdict != NF_ACCEPT) { | 
| 223 | #ifdef CONFIG_NETFILTER_DEBUG | 223 | #ifdef CONFIG_NETFILTER_DEBUG | 
| 224 | if (unlikely(verdict > NF_MAX_VERDICT)) { | 224 | if (unlikely((verdict & NF_VERDICT_MASK) | 
| 225 | > NF_MAX_VERDICT)) { | ||
| 225 | NFDEBUG("Evil return from %p(%u).\n", | 226 | NFDEBUG("Evil return from %p(%u).\n", | 
| 226 | elem->hook, hook); | 227 | elem->hook, hook); | 
| 227 | continue; | 228 | continue; | 
| @@ -239,6 +240,9 @@ int nf_register_queue_handler(int pf, nf_queue_outfn_t outfn, void *data) | |||
| 239 | { | 240 | { | 
| 240 | int ret; | 241 | int ret; | 
| 241 | 242 | ||
| 243 | if (pf >= NPROTO) | ||
| 244 | return -EINVAL; | ||
| 245 | |||
| 242 | write_lock_bh(&queue_handler_lock); | 246 | write_lock_bh(&queue_handler_lock); | 
| 243 | if (queue_handler[pf].outfn) | 247 | if (queue_handler[pf].outfn) | 
| 244 | ret = -EBUSY; | 248 | ret = -EBUSY; | 
| @@ -255,6 +259,9 @@ int nf_register_queue_handler(int pf, nf_queue_outfn_t outfn, void *data) | |||
| 255 | /* The caller must flush their queue before this */ | 259 | /* The caller must flush their queue before this */ | 
| 256 | int nf_unregister_queue_handler(int pf) | 260 | int nf_unregister_queue_handler(int pf) | 
| 257 | { | 261 | { | 
| 262 | if (pf >= NPROTO) | ||
| 263 | return -EINVAL; | ||
| 264 | |||
| 258 | write_lock_bh(&queue_handler_lock); | 265 | write_lock_bh(&queue_handler_lock); | 
| 259 | queue_handler[pf].outfn = NULL; | 266 | queue_handler[pf].outfn = NULL; | 
| 260 | queue_handler[pf].data = NULL; | 267 | queue_handler[pf].data = NULL; | 
| @@ -286,6 +293,20 @@ int nf_unregister_queue_rerouter(int pf) | |||
| 286 | return 0; | 293 | return 0; | 
| 287 | } | 294 | } | 
| 288 | 295 | ||
| 296 | void nf_unregister_queue_handlers(nf_queue_outfn_t outfn) | ||
| 297 | { | ||
| 298 | int pf; | ||
| 299 | |||
| 300 | write_lock_bh(&queue_handler_lock); | ||
| 301 | for (pf = 0; pf < NPROTO; pf++) { | ||
| 302 | if (queue_handler[pf].outfn == outfn) { | ||
| 303 | queue_handler[pf].outfn = NULL; | ||
| 304 | queue_handler[pf].data = NULL; | ||
| 305 | } | ||
| 306 | } | ||
| 307 | write_unlock_bh(&queue_handler_lock); | ||
| 308 | } | ||
| 309 | |||
| 289 | /* | 310 | /* | 
| 290 | * Any packet that leaves via this function must come back | 311 | * Any packet that leaves via this function must come back | 
| 291 | * through nf_reinject(). | 312 | * through nf_reinject(). | 
| @@ -295,7 +316,8 @@ static int nf_queue(struct sk_buff **skb, | |||
| 295 | int pf, unsigned int hook, | 316 | int pf, unsigned int hook, | 
| 296 | struct net_device *indev, | 317 | struct net_device *indev, | 
| 297 | struct net_device *outdev, | 318 | struct net_device *outdev, | 
| 298 | int (*okfn)(struct sk_buff *)) | 319 | int (*okfn)(struct sk_buff *), | 
| 320 | unsigned int queuenum) | ||
| 299 | { | 321 | { | 
| 300 | int status; | 322 | int status; | 
| 301 | struct nf_info *info; | 323 | struct nf_info *info; | 
| @@ -347,7 +369,8 @@ static int nf_queue(struct sk_buff **skb, | |||
| 347 | if (queue_rerouter[pf].save) | 369 | if (queue_rerouter[pf].save) | 
| 348 | queue_rerouter[pf].save(*skb, info); | 370 | queue_rerouter[pf].save(*skb, info); | 
| 349 | 371 | ||
| 350 | status = queue_handler[pf].outfn(*skb, info, queue_handler[pf].data); | 372 | status = queue_handler[pf].outfn(*skb, info, queuenum, | 
| 373 | queue_handler[pf].data); | ||
| 351 | 374 | ||
| 352 | if (status >= 0 && queue_rerouter[pf].reroute) | 375 | if (status >= 0 && queue_rerouter[pf].reroute) | 
| 353 | status = queue_rerouter[pf].reroute(skb, info); | 376 | status = queue_rerouter[pf].reroute(skb, info); | 
| @@ -397,9 +420,10 @@ next_hook: | |||
| 397 | } else if (verdict == NF_DROP) { | 420 | } else if (verdict == NF_DROP) { | 
| 398 | kfree_skb(*pskb); | 421 | kfree_skb(*pskb); | 
| 399 | ret = -EPERM; | 422 | ret = -EPERM; | 
| 400 | } else if (verdict == NF_QUEUE) { | 423 | } else if ((verdict & NF_VERDICT_MASK) == NF_QUEUE) { | 
| 401 | NFDEBUG("nf_hook: Verdict = QUEUE.\n"); | 424 | NFDEBUG("nf_hook: Verdict = QUEUE.\n"); | 
| 402 | if (!nf_queue(pskb, elem, pf, hook, indev, outdev, okfn)) | 425 | if (!nf_queue(pskb, elem, pf, hook, indev, outdev, okfn, | 
| 426 | verdict >> NF_VERDICT_BITS)) | ||
| 403 | goto next_hook; | 427 | goto next_hook; | 
| 404 | } | 428 | } | 
| 405 | unlock: | 429 | unlock: | 
| @@ -456,14 +480,15 @@ void nf_reinject(struct sk_buff *skb, struct nf_info *info, | |||
| 456 | info->okfn, INT_MIN); | 480 | info->okfn, INT_MIN); | 
| 457 | } | 481 | } | 
| 458 | 482 | ||
| 459 | switch (verdict) { | 483 | switch (verdict & NF_VERDICT_MASK) { | 
| 460 | case NF_ACCEPT: | 484 | case NF_ACCEPT: | 
| 461 | info->okfn(skb); | 485 | info->okfn(skb); | 
| 462 | break; | 486 | break; | 
| 463 | 487 | ||
| 464 | case NF_QUEUE: | 488 | case NF_QUEUE: | 
| 465 | if (!nf_queue(&skb, elem, info->pf, info->hook, | 489 | if (!nf_queue(&skb, elem, info->pf, info->hook, | 
| 466 | info->indev, info->outdev, info->okfn)) | 490 | info->indev, info->outdev, info->okfn, | 
| 491 | verdict >> NF_VERDICT_BITS)) | ||
| 467 | goto next_hook; | 492 | goto next_hook; | 
| 468 | break; | 493 | break; | 
| 469 | } | 494 | } | 
| @@ -613,6 +638,7 @@ EXPORT_SYMBOL(nf_reinject); | |||
| 613 | EXPORT_SYMBOL(nf_setsockopt); | 638 | EXPORT_SYMBOL(nf_setsockopt); | 
| 614 | EXPORT_SYMBOL(nf_unregister_hook); | 639 | EXPORT_SYMBOL(nf_unregister_hook); | 
| 615 | EXPORT_SYMBOL(nf_unregister_queue_handler); | 640 | EXPORT_SYMBOL(nf_unregister_queue_handler); | 
| 641 | EXPORT_SYMBOL_GPL(nf_unregister_queue_handlers); | ||
| 616 | EXPORT_SYMBOL_GPL(nf_register_queue_rerouter); | 642 | EXPORT_SYMBOL_GPL(nf_register_queue_rerouter); | 
| 617 | EXPORT_SYMBOL_GPL(nf_unregister_queue_rerouter); | 643 | EXPORT_SYMBOL_GPL(nf_unregister_queue_rerouter); | 
| 618 | EXPORT_SYMBOL(nf_unregister_sockopt); | 644 | EXPORT_SYMBOL(nf_unregister_sockopt); | 
| diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c index 78892980f42c..cfc886f382ac 100644 --- a/net/ipv4/netfilter/ip_queue.c +++ b/net/ipv4/netfilter/ip_queue.c | |||
| @@ -280,7 +280,8 @@ nlmsg_failure: | |||
| 280 | } | 280 | } | 
| 281 | 281 | ||
| 282 | static int | 282 | static int | 
| 283 | ipq_enqueue_packet(struct sk_buff *skb, struct nf_info *info, void *data) | 283 | ipq_enqueue_packet(struct sk_buff *skb, struct nf_info *info, | 
| 284 | unsigned int queuenum, void *data) | ||
| 284 | { | 285 | { | 
| 285 | int status = -EINVAL; | 286 | int status = -EINVAL; | 
| 286 | struct sk_buff *nskb; | 287 | struct sk_buff *nskb; | 
| diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index c45d8f8815de..5af4cee93d9b 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c | |||
| @@ -278,7 +278,8 @@ nlmsg_failure: | |||
| 278 | } | 278 | } | 
| 279 | 279 | ||
| 280 | static int | 280 | static int | 
| 281 | ipq_enqueue_packet(struct sk_buff *skb, struct nf_info *info, void *data) | 281 | ipq_enqueue_packet(struct sk_buff *skb, struct nf_info *info, | 
| 282 | unsigned int queuenum, void *data) | ||
| 282 | { | 283 | { | 
| 283 | int status = -EINVAL; | 284 | int status = -EINVAL; | 
| 284 | struct sk_buff *nskb; | 285 | struct sk_buff *nskb; | 
| diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c index 6210ca42166c..30b25f47f7cc 100644 --- a/net/netfilter/nfnetlink.c +++ b/net/netfilter/nfnetlink.c | |||
| @@ -44,7 +44,9 @@ MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_NETFILTER); | |||
| 44 | static char __initdata nfversion[] = "0.30"; | 44 | static char __initdata nfversion[] = "0.30"; | 
| 45 | 45 | ||
| 46 | #if 0 | 46 | #if 0 | 
| 47 | #define DEBUGP printk | 47 | #define DEBUGP(format, args...) \ | 
| 48 | printk(KERN_DEBUG "%s(%d):%s(): " format, __FILE__, \ | ||
| 49 | __LINE__, __FUNCTION__, ## args) | ||
| 48 | #else | 50 | #else | 
| 49 | #define DEBUGP(format, args...) | 51 | #define DEBUGP(format, args...) | 
| 50 | #endif | 52 | #endif | 
| @@ -67,11 +69,11 @@ int nfnetlink_subsys_register(struct nfnetlink_subsystem *n) | |||
| 67 | { | 69 | { | 
| 68 | DEBUGP("registering subsystem ID %u\n", n->subsys_id); | 70 | DEBUGP("registering subsystem ID %u\n", n->subsys_id); | 
| 69 | 71 | ||
| 70 | /* If the netlink socket wasn't created, then fail */ | ||
| 71 | if (!nfnl) | ||
| 72 | return -1; | ||
| 73 | |||
| 74 | nfnl_lock(); | 72 | nfnl_lock(); | 
| 73 | if (subsys_table[n->subsys_id]) { | ||
| 74 | nfnl_unlock(); | ||
| 75 | return -EBUSY; | ||
| 76 | } | ||
| 75 | subsys_table[n->subsys_id] = n; | 77 | subsys_table[n->subsys_id] = n; | 
| 76 | nfnl_unlock(); | 78 | nfnl_unlock(); | 
| 77 | 79 | ||
| @@ -227,8 +229,18 @@ static inline int nfnetlink_rcv_msg(struct sk_buff *skb, | |||
| 227 | 229 | ||
| 228 | type = nlh->nlmsg_type; | 230 | type = nlh->nlmsg_type; | 
| 229 | ss = nfnetlink_get_subsys(type); | 231 | ss = nfnetlink_get_subsys(type); | 
| 230 | if (!ss) | 232 | if (!ss) { | 
| 233 | #ifdef CONFIG_KMOD | ||
| 234 | /* don't call nfnl_shunlock, since it would reenter | ||
| 235 | * with further packet processing */ | ||
| 236 | up(&nfnl_sem); | ||
| 237 | request_module("nfnetlink-subsys-%d", NFNL_SUBSYS_ID(type)); | ||
| 238 | nfnl_shlock(); | ||
| 239 | ss = nfnetlink_get_subsys(type); | ||
| 240 | if (!ss) | ||
| 241 | #endif | ||
| 231 | goto err_inval; | 242 | goto err_inval; | 
| 243 | } | ||
| 232 | 244 | ||
| 233 | nc = nfnetlink_find_client(type, ss); | 245 | nc = nfnetlink_find_client(type, ss); | 
| 234 | if (!nc) { | 246 | if (!nc) { | 
| @@ -252,12 +264,14 @@ static inline int nfnetlink_rcv_msg(struct sk_buff *skb, | |||
| 252 | if (err < 0) | 264 | if (err < 0) | 
| 253 | goto err_inval; | 265 | goto err_inval; | 
| 254 | 266 | ||
| 267 | DEBUGP("calling handler\n"); | ||
| 255 | err = nc->call(nfnl, skb, nlh, cda, errp); | 268 | err = nc->call(nfnl, skb, nlh, cda, errp); | 
| 256 | *errp = err; | 269 | *errp = err; | 
| 257 | return err; | 270 | return err; | 
| 258 | } | 271 | } | 
| 259 | 272 | ||
| 260 | err_inval: | 273 | err_inval: | 
| 274 | DEBUGP("returning -EINVAL\n"); | ||
| 261 | *errp = -EINVAL; | 275 | *errp = -EINVAL; | 
| 262 | return -1; | 276 | return -1; | 
| 263 | } | 277 | } | 
| @@ -311,6 +325,8 @@ static void nfnetlink_rcv(struct sock *sk, int len) | |||
| 311 | kfree_skb(skb); | 325 | kfree_skb(skb); | 
| 312 | } | 326 | } | 
| 313 | 327 | ||
| 328 | /* don't call nfnl_shunlock, since it would reenter | ||
| 329 | * with further packet processing */ | ||
| 314 | up(&nfnl_sem); | 330 | up(&nfnl_sem); | 
| 315 | } while(nfnl && nfnl->sk_receive_queue.qlen); | 331 | } while(nfnl && nfnl->sk_receive_queue.qlen); | 
| 316 | } | 332 | } | 
