38b6715e1db41e4aff52c1a2a046bb886fc35c11
[linux-2.6.git] / net / netfilter / xt_helper.c
1 /* iptables module to match on related connections */
2 /*
3  * (C) 2001 Martin Josefsson <gandalf@wlug.westbo.se>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  *
9  *   19 Mar 2002 Harald Welte <laforge@gnumonks.org>:
10  *               - Port to newnat infrastructure
11  */
12
13 #include <linux/module.h>
14 #include <linux/skbuff.h>
15 #include <linux/netfilter.h>
16 #if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)
17 #include <linux/netfilter_ipv4/ip_conntrack.h>
18 #include <linux/netfilter_ipv4/ip_conntrack_core.h>
19 #include <linux/netfilter_ipv4/ip_conntrack_helper.h>
20 #else
21 #include <net/netfilter/nf_conntrack.h>
22 #include <net/netfilter/nf_conntrack_core.h>
23 #include <net/netfilter/nf_conntrack_helper.h>
24 #endif
25 #include <linux/netfilter/x_tables.h>
26 #include <linux/netfilter/xt_helper.h>
27
28 MODULE_LICENSE("GPL");
29 MODULE_AUTHOR("Martin Josefsson <gandalf@netfilter.org>");
30 MODULE_DESCRIPTION("iptables helper match module");
31 MODULE_ALIAS("ipt_helper");
32 MODULE_ALIAS("ip6t_helper");
33
34 #if 0
35 #define DEBUGP printk
36 #else
37 #define DEBUGP(format, args...)
38 #endif
39
40 #if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)
41 static int
42 match(const struct sk_buff *skb,
43       const struct net_device *in,
44       const struct net_device *out,
45       const void *matchinfo,
46       int offset,
47       unsigned int protoff,
48       int *hotdrop)
49 {
50         const struct xt_helper_info *info = matchinfo;
51         struct ip_conntrack *ct;
52         enum ip_conntrack_info ctinfo;
53         int ret = info->invert;
54         
55         ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
56         if (!ct) {
57                 DEBUGP("xt_helper: Eek! invalid conntrack?\n");
58                 return ret;
59         }
60
61         if (!ct->master) {
62                 DEBUGP("xt_helper: conntrack %p has no master\n", ct);
63                 return ret;
64         }
65
66         read_lock_bh(&ip_conntrack_lock);
67         if (!ct->master->helper) {
68                 DEBUGP("xt_helper: master ct %p has no helper\n", 
69                         exp->expectant);
70                 goto out_unlock;
71         }
72
73         DEBUGP("master's name = %s , info->name = %s\n", 
74                 ct->master->helper->name, info->name);
75
76         if (info->name[0] == '\0')
77                 ret ^= 1;
78         else
79                 ret ^= !strncmp(ct->master->helper->name, info->name, 
80                                 strlen(ct->master->helper->name));
81 out_unlock:
82         read_unlock_bh(&ip_conntrack_lock);
83         return ret;
84 }
85
86 #else /* CONFIG_IP_NF_CONNTRACK */
87
88 static int
89 match(const struct sk_buff *skb,
90       const struct net_device *in,
91       const struct net_device *out,
92       const void *matchinfo,
93       int offset,
94       unsigned int protoff,
95       int *hotdrop)
96 {
97         const struct xt_helper_info *info = matchinfo;
98         struct nf_conn *ct;
99         enum ip_conntrack_info ctinfo;
100         int ret = info->invert;
101         
102         ct = nf_ct_get((struct sk_buff *)skb, &ctinfo);
103         if (!ct) {
104                 DEBUGP("xt_helper: Eek! invalid conntrack?\n");
105                 return ret;
106         }
107
108         if (!ct->master) {
109                 DEBUGP("xt_helper: conntrack %p has no master\n", ct);
110                 return ret;
111         }
112
113         read_lock_bh(&nf_conntrack_lock);
114         if (!ct->master->helper) {
115                 DEBUGP("xt_helper: master ct %p has no helper\n", 
116                         exp->expectant);
117                 goto out_unlock;
118         }
119
120         DEBUGP("master's name = %s , info->name = %s\n", 
121                 ct->master->helper->name, info->name);
122
123         if (info->name[0] == '\0')
124                 ret ^= 1;
125         else
126                 ret ^= !strncmp(ct->master->helper->name, info->name, 
127                                 strlen(ct->master->helper->name));
128 out_unlock:
129         read_unlock_bh(&nf_conntrack_lock);
130         return ret;
131 }
132 #endif
133
134 static int check(const char *tablename,
135                  const void *inf,
136                  void *matchinfo,
137                  unsigned int matchsize,
138                  unsigned int hook_mask)
139 {
140         struct xt_helper_info *info = matchinfo;
141
142         info->name[29] = '\0';
143
144         /* verify size */
145         if (matchsize != XT_ALIGN(sizeof(struct xt_helper_info)))
146                 return 0;
147
148         return 1;
149 }
150
151 static struct xt_match helper_match = {
152         .name           = "helper",
153         .match          = &match,
154         .checkentry     = &check,
155         .me             = THIS_MODULE,
156 };
157 static struct xt_match helper6_match = {
158         .name           = "helper",
159         .match          = &match,
160         .checkentry     = &check,
161         .me             = THIS_MODULE,
162 };
163
164 static int __init init(void)
165 {
166         int ret;
167         need_conntrack();
168
169         ret = xt_register_match(AF_INET, &helper_match);
170         if (ret < 0)
171                 return ret;
172
173         ret = xt_register_match(AF_INET6, &helper6_match);
174         if (ret < 0)
175                 xt_unregister_match(AF_INET, &helper_match);
176
177         return ret;
178 }
179
180 static void __exit fini(void)
181 {
182         xt_unregister_match(AF_INET, &helper_match);
183         xt_unregister_match(AF_INET6, &helper6_match);
184 }
185
186 module_init(init);
187 module_exit(fini);
188