diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index 2743c156caa00056232f7d516f3cf838409edef0..b6f0905a4ee2b99b12645100f4f8d318ebdf2fc3 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -195,6 +195,10 @@ static inline void nf_ct_put(struct nf_conn *ct) nf_conntrack_put(&ct->ct_general); } +/* Protocol module loading */ +extern int nf_ct_l3proto_try_module_get(unsigned short l3proto); +extern void nf_ct_l3proto_module_put(unsigned short l3proto); + extern struct nf_conntrack_tuple_hash * __nf_conntrack_find(const struct nf_conntrack_tuple *tuple, const struct nf_conn *ignored_conntrack); diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index cb9c661f3f331c5fb64f805bbfdff5f8a7e70b3e..c8abc9d859b96d946fbde352df73c4de8e7996d1 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c @@ -568,6 +568,7 @@ static int init_or_cleanup(int init) return ret; } +MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET)); MODULE_LICENSE("GPL"); static int __init init(void) diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c index ac35f95263687f1cac3e7bddfeb3e9a04d9e1c79..c16f62934bd9199ef2c76cbb0e16b2b52e0c7c9f 100644 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c @@ -584,6 +584,7 @@ static int init_or_cleanup(int init) return ret; } +MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET6)); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Yasuyuki KOZAKAI @USAGI "); diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index c28840656451cd4de1fc460a6ee90fbeb63e3fcb..0ae281d9bfc3f16cda2b7e36c34b109145045d1a 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -23,6 +23,8 @@ * 26 Jan 2006: Harald Welte * - restructure nf_conn (introduce nf_conn_help) * - redesign 'features' how they were originally intended + * 26 Feb 2006: Pablo Neira Ayuso + * - add support for L3 protocol module load on demand. * * Derived from net/ipv4/netfilter/ip_conntrack_core.c */ @@ -241,6 +243,35 @@ void nf_ct_l3proto_put(struct nf_conntrack_l3proto *p) module_put(p->me); } +int +nf_ct_l3proto_try_module_get(unsigned short l3proto) +{ + int ret; + struct nf_conntrack_l3proto *p; + +retry: p = nf_ct_l3proto_find_get(l3proto); + if (p == &nf_conntrack_generic_l3proto) { + ret = request_module("nf_conntrack-%d", l3proto); + if (!ret) + goto retry; + + return -EPROTOTYPE; + } + + return 0; +} + +void nf_ct_l3proto_module_put(unsigned short l3proto) +{ + struct nf_conntrack_l3proto *p; + + preempt_disable(); + p = __nf_ct_l3proto_find(l3proto); + preempt_enable(); + + module_put(p->me); +} + static int nf_conntrack_hash_rnd_initted; static unsigned int nf_conntrack_hash_rnd; diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c index 290d5a0c559b6d4a760fd1c2b41c23cd73e0501a..75577e175b35a3a44f9bb3d1a3318a84c930d2bd 100644 --- a/net/netfilter/nf_conntrack_standalone.c +++ b/net/netfilter/nf_conntrack_standalone.c @@ -834,6 +834,8 @@ EXPORT_SYMBOL_GPL(__nf_ct_event_cache_init); EXPORT_PER_CPU_SYMBOL_GPL(nf_conntrack_ecache); EXPORT_SYMBOL_GPL(nf_ct_deliver_cached_events); #endif +EXPORT_SYMBOL(nf_ct_l3proto_try_module_get); +EXPORT_SYMBOL(nf_ct_l3proto_module_put); EXPORT_SYMBOL(nf_conntrack_l3proto_register); EXPORT_SYMBOL(nf_conntrack_l3proto_unregister); EXPORT_SYMBOL(nf_conntrack_protocol_register); diff --git a/net/netfilter/xt_connmark.c b/net/netfilter/xt_connmark.c index e810600345e3a59fce7b02cc8d6a847c123fb06c..7b16f1ee16b4a8c78f4b8810e4a78194c2afe150 100644 --- a/net/netfilter/xt_connmark.c +++ b/net/netfilter/xt_connmark.c @@ -64,14 +64,30 @@ checkentry(const char *tablename, printk(KERN_WARNING "connmark: only support 32bit mark\n"); return 0; } +#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) + if (nf_ct_l3proto_try_module_get(match->family) < 0) { + printk(KERN_WARNING "can't load nf_conntrack support for " + "proto=%d\n", match->family); + return 0; + } +#endif return 1; } +static void +destroy(const struct xt_match *match, void *matchinfo, unsigned int matchsize) +{ +#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) + nf_ct_l3proto_module_put(match->family); +#endif +} + static struct xt_match connmark_match = { .name = "connmark", .match = match, .matchsize = sizeof(struct xt_connmark_info), .checkentry = checkentry, + .destroy = destroy, .family = AF_INET, .me = THIS_MODULE }; @@ -81,6 +97,7 @@ static struct xt_match connmark6_match = { .match = match, .matchsize = sizeof(struct xt_connmark_info), .checkentry = checkentry, + .destroy = destroy, .family = AF_INET6, .me = THIS_MODULE }; diff --git a/net/netfilter/xt_conntrack.c b/net/netfilter/xt_conntrack.c index 7d20caa0d605b9ee40a0f775d46623b89ec1a62e..65a84809fd3054a7c47eb3363c8146136eeb285e 100644 --- a/net/netfilter/xt_conntrack.c +++ b/net/netfilter/xt_conntrack.c @@ -203,9 +203,37 @@ match(const struct sk_buff *skb, #endif /* CONFIG_NF_IP_CONNTRACK */ +static int +checkentry(const char *tablename, + const void *ip, + const struct xt_match *match, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ +#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) + if (nf_ct_l3proto_try_module_get(match->family) < 0) { + printk(KERN_WARNING "can't load nf_conntrack support for " + "proto=%d\n", match->family); + return 0; + } +#endif + return 1; +} + +static void +destroy(const struct xt_match *match, void *matchinfo, unsigned int matchsize) +{ +#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) + nf_ct_l3proto_module_put(match->family); +#endif +} + static struct xt_match conntrack_match = { .name = "conntrack", .match = match, + .checkentry = checkentry, + .destroy = destroy, .matchsize = sizeof(struct xt_conntrack_info), .family = AF_INET, .me = THIS_MODULE, diff --git a/net/netfilter/xt_helper.c b/net/netfilter/xt_helper.c index 7d2d68b9155ff3e33f87a08fb8e89777b8a1267e..101f0005e987556d50b2dfbfcdd92abb4fe1f2e7 100644 --- a/net/netfilter/xt_helper.c +++ b/net/netfilter/xt_helper.c @@ -144,15 +144,31 @@ static int check(const char *tablename, { struct xt_helper_info *info = matchinfo; +#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) + if (nf_ct_l3proto_try_module_get(match->family) < 0) { + printk(KERN_WARNING "can't load nf_conntrack support for " + "proto=%d\n", match->family); + return 0; + } +#endif info->name[29] = '\0'; return 1; } +static void +destroy(const struct xt_match *match, void *matchinfo, unsigned int matchsize) +{ +#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) + nf_ct_l3proto_module_put(match->family); +#endif +} + static struct xt_match helper_match = { .name = "helper", .match = match, .matchsize = sizeof(struct xt_helper_info), .checkentry = check, + .destroy = destroy, .family = AF_INET, .me = THIS_MODULE, }; @@ -161,6 +177,7 @@ static struct xt_match helper6_match = { .match = match, .matchsize = sizeof(struct xt_helper_info), .checkentry = check, + .destroy = destroy, .family = AF_INET6, .me = THIS_MODULE, }; diff --git a/net/netfilter/xt_state.c b/net/netfilter/xt_state.c index 7cd557c932baf09394da1bda987354239fdbb69e..e6c0be9d94d2130cf076bd1f47b00aa867dd7406 100644 --- a/net/netfilter/xt_state.c +++ b/net/netfilter/xt_state.c @@ -44,9 +44,36 @@ match(const struct sk_buff *skb, return (sinfo->statemask & statebit); } +static int check(const char *tablename, + const void *inf, + const struct xt_match *match, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ +#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) + if (nf_ct_l3proto_try_module_get(match->family) < 0) { + printk(KERN_WARNING "can't load nf_conntrack support for " + "proto=%d\n", match->family); + return 0; + } +#endif + return 1; +} + +static void +destroy(const struct xt_match *match, void *matchinfo, unsigned int matchsize) +{ +#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) + nf_ct_l3proto_module_put(match->family); +#endif +} + static struct xt_match state_match = { .name = "state", .match = match, + .checkentry = check, + .destroy = destroy, .matchsize = sizeof(struct xt_state_info), .family = AF_INET, .me = THIS_MODULE, @@ -55,6 +82,8 @@ static struct xt_match state_match = { static struct xt_match state6_match = { .name = "state", .match = match, + .checkentry = check, + .destroy = destroy, .matchsize = sizeof(struct xt_state_info), .family = AF_INET6, .me = THIS_MODULE,