0ddb32363d062f115a347917c87799b0b9f4feff
[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         struct nf_conn_help *master_help;
100         enum ip_conntrack_info ctinfo;
101         int ret = info->invert;
102         
103         ct = nf_ct_get((struct sk_buff *)skb, &ctinfo);
104         if (!ct) {
105                 DEBUGP("xt_helper: Eek! invalid conntrack?\n");
106                 return ret;
107         }
108
109         if (!ct->master) {
110                 DEBUGP("xt_helper: conntrack %p has no master\n", ct);
111                 return ret;
112         }
113
114         read_lock_bh(&nf_conntrack_lock);
115         master_help = nfct_help(ct->master);
116         if (!master_help || !master_help->helper) {
117                 DEBUGP("xt_helper: master ct %p has no helper\n", 
118                         exp->expectant);
119                 goto out_unlock;
120         }
121
122         DEBUGP("master's name = %s , info->name = %s\n", 
123                 ct->master->helper->name, info->name);
124
125         if (info->name[0] == '\0')
126                 ret ^= 1;
127         else
128                 ret ^= !strncmp(master_help->helper->name, info->name,
129                                 strlen(master_help->helper->name));
130 out_unlock:
131         read_unlock_bh(&nf_conntrack_lock);
132         return ret;
133 }
134 #endif
135
136 static int check(const char *tablename,
137                  const void *inf,
138                  void *matchinfo,
139                  unsigned int matchsize,
140                  unsigned int hook_mask)
141 {
142         struct xt_helper_info *info = matchinfo;
143
144         info->name[29] = '\0';
145
146         /* verify size */
147         if (matchsize != XT_ALIGN(sizeof(struct xt_helper_info)))
148                 return 0;
149
150         return 1;
151 }
152
153 static struct xt_match helper_match = {
154         .name           = "helper",
155         .match          = &match,
156         .checkentry     = &check,
157         .me             = THIS_MODULE,
158 };
159 static struct xt_match helper6_match = {
160         .name           = "helper",
161         .match          = &match,
162         .checkentry     = &check,
163         .me             = THIS_MODULE,
164 };
165
166 static int __init init(void)
167 {
168         int ret;
169         need_conntrack();
170
171         ret = xt_register_match(AF_INET, &helper_match);
172         if (ret < 0)
173                 return ret;
174
175         ret = xt_register_match(AF_INET6, &helper6_match);
176         if (ret < 0)
177                 xt_unregister_match(AF_INET, &helper_match);
178
179         return ret;
180 }
181
182 static void __exit fini(void)
183 {
184         xt_unregister_match(AF_INET, &helper_match);
185         xt_unregister_match(AF_INET6, &helper6_match);
186 }
187
188 module_init(init);
189 module_exit(fini);
190