[NETFILTER]: Convert x_tables matches/targets to centralized error checking
[linux-2.6] / 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         return 1;
146 }
147
148 static struct xt_match helper_match = {
149         .name           = "helper",
150         .match          = match,
151         .matchsize      = sizeof(struct xt_helper_info),
152         .checkentry     = check,
153         .me             = THIS_MODULE,
154 };
155 static struct xt_match helper6_match = {
156         .name           = "helper",
157         .match          = match,
158         .matchsize      = sizeof(struct xt_helper_info),
159         .checkentry     = check,
160         .me             = THIS_MODULE,
161 };
162
163 static int __init init(void)
164 {
165         int ret;
166         need_conntrack();
167
168         ret = xt_register_match(AF_INET, &helper_match);
169         if (ret < 0)
170                 return ret;
171
172         ret = xt_register_match(AF_INET6, &helper6_match);
173         if (ret < 0)
174                 xt_unregister_match(AF_INET, &helper_match);
175
176         return ret;
177 }
178
179 static void __exit fini(void)
180 {
181         xt_unregister_match(AF_INET, &helper_match);
182         xt_unregister_match(AF_INET6, &helper6_match);
183 }
184
185 module_init(init);
186 module_exit(fini);
187