1 /*-------------------------------------------*\
2 | Netfilter Condition Module |
4 | Description: This module allows firewall |
5 | rules to match using condition variables |
6 | stored in /proc files. |
8 | Author: Stephane Ouellette 2002-10-22 |
9 | <ouellettes@videotron.ca> |
10 | Massimiliano Hofer 2006-05-15 |
14 | 2003-02-10 Second version with improved |
15 | locking and simplified code. |
16 | 2006-05-15 2.6.16 adaptations. |
18 | Various bug fixes. |
20 | This software is distributed under the |
21 | terms of the GNU GPL. |
22 \*-------------------------------------------*/
24 #include <linux/version.h>
25 #include <linux/kernel.h>
26 #include <linux/module.h>
27 #include <linux/proc_fs.h>
28 #include <linux/spinlock.h>
29 #include <linux/string.h>
30 #include <linux/list.h>
31 #include <asm/atomic.h>
32 #include <asm/uaccess.h>
33 #include <linux/netfilter/x_tables.h>
34 #include <linux/netfilter/xt_condition.h>
36 #ifndef CONFIG_PROC_FS
37 #error "Proc file system support is required for this module"
40 /* Defaults, these can be overridden on the module command-line. */
41 static unsigned int condition_list_perms
= 0644;
42 static unsigned int compat_dir_name
= 0;
43 static unsigned int condition_uid_perms
= 0;
44 static unsigned int condition_gid_perms
= 0;
46 MODULE_AUTHOR("Stephane Ouellette <ouellettes@videotron.ca> and Massimiliano Hofer <max@nucleus.it>");
47 MODULE_DESCRIPTION("Allows rules to match against condition variables");
48 MODULE_LICENSE("GPL");
49 module_param(condition_list_perms
, uint
, 0600);
50 MODULE_PARM_DESC(condition_list_perms
,"permissions on /proc/net/nf_condition/* files");
51 module_param(condition_uid_perms
, uint
, 0600);
52 MODULE_PARM_DESC(condition_uid_perms
,"user owner of /proc/net/nf_condition/* files");
53 module_param(condition_gid_perms
, uint
, 0600);
54 MODULE_PARM_DESC(condition_gid_perms
,"group owner of /proc/net/nf_condition/* files");
55 module_param(compat_dir_name
, bool, 0400);
56 MODULE_PARM_DESC(compat_dir_name
,"use old style /proc/net/ipt_condition/* files");
57 MODULE_ALIAS("ipt_condition");
58 MODULE_ALIAS("ip6t_condition");
60 struct condition_variable
{
61 struct list_head list
;
62 struct proc_dir_entry
*status_proc
;
63 unsigned int refcount
;
64 int enabled
; /* TRUE == 1, FALSE == 0 */
67 /* proc_lock is a user context only semaphore used for write access */
68 /* to the conditions' list. */
69 static DEFINE_MUTEX(proc_lock
);
71 static LIST_HEAD(conditions_list
);
72 static struct proc_dir_entry
*proc_net_condition
= NULL
;
73 static const char *dir_name
;
76 xt_condition_read_info(char __user
*buffer
, char **start
, off_t offset
,
77 int length
, int *eof
, void *data
)
79 struct condition_variable
*var
=
80 (struct condition_variable
*) data
;
82 buffer
[0] = (var
->enabled
) ? '1' : '0';
92 xt_condition_write_info(struct file
*file
, const char __user
*buffer
,
93 unsigned long length
, void *data
)
95 struct condition_variable
*var
=
96 (struct condition_variable
*) data
;
100 if (get_user(newval
, buffer
))
102 /* Match only on the first character */
118 match(const struct sk_buff
*skb
, struct xt_action_param
*par
)
120 const struct condition_info
*info
=
121 (const struct condition_info
*) par
->matchinfo
;
122 struct condition_variable
*var
;
123 int condition_status
= 0;
126 list_for_each_entry_rcu(var
, &conditions_list
, list
) {
127 if (strcmp(info
->name
, var
->status_proc
->name
) == 0) {
128 condition_status
= var
->enabled
;
134 return condition_status
^ info
->invert
;
140 checkentry(const struct xt_mtchk_param
*par
)
142 static const char * const forbidden_names
[]={ "", ".", ".." };
143 struct condition_info
*info
= (struct condition_info
*) par
->matchinfo
;
144 struct list_head
*pos
;
145 struct condition_variable
*var
, *newvar
;
149 /* We don't want a '/' in a proc file name. */
150 for (i
=0; i
< CONDITION_NAME_LEN
&& info
->name
[i
] != '\0'; i
++)
151 if (info
->name
[i
] == '/')
153 /* We can't handle file names longer than CONDITION_NAME_LEN and */
154 /* we want a NULL terminated string. */
155 if (i
== CONDITION_NAME_LEN
)
158 /* We don't want certain reserved names. */
159 for (i
=0; i
< sizeof(forbidden_names
)/sizeof(char *); i
++)
160 if(strcmp(info
->name
, forbidden_names
[i
])==0)
163 /* Let's acquire the lock, check for the condition and add it */
164 /* or increase the reference counter. */
165 if (mutex_lock_interruptible(&proc_lock
))
168 list_for_each(pos
, &conditions_list
) {
169 var
= list_entry(pos
, struct condition_variable
, list
);
170 if (strcmp(info
->name
, var
->status_proc
->name
) == 0) {
172 mutex_unlock(&proc_lock
);
177 /* At this point, we need to allocate a new condition variable. */
178 newvar
= kmalloc(sizeof(struct condition_variable
), GFP_KERNEL
);
181 mutex_unlock(&proc_lock
);
185 /* Create the condition variable's proc file entry. */
186 newvar
->status_proc
= create_proc_entry(info
->name
, condition_list_perms
, proc_net_condition
);
188 if (!newvar
->status_proc
) {
190 mutex_unlock(&proc_lock
);
194 newvar
->refcount
= 1;
196 newvar
->status_proc
->data
= newvar
;
198 newvar
->status_proc
->read_proc
= xt_condition_read_info
;
199 newvar
->status_proc
->write_proc
= xt_condition_write_info
;
201 list_add_rcu(&newvar
->list
, &conditions_list
);
203 newvar
->status_proc
->uid
= condition_uid_perms
;
204 newvar
->status_proc
->gid
= condition_gid_perms
;
206 mutex_unlock(&proc_lock
);
213 destroy(const struct xt_mtdtor_param
*par
)
215 struct condition_info
*info
= (struct condition_info
*) par
->matchinfo
;
216 struct list_head
*pos
;
217 struct condition_variable
*var
;
220 mutex_lock(&proc_lock
);
222 list_for_each(pos
, &conditions_list
) {
223 var
= list_entry(pos
, struct condition_variable
, list
);
224 if (strcmp(info
->name
, var
->status_proc
->name
) == 0) {
225 if (--var
->refcount
== 0) {
227 remove_proc_entry(var
->status_proc
->name
, proc_net_condition
);
228 mutex_unlock(&proc_lock
);
229 /* synchronize_rcu() would be goog enough, but synchronize_net() */
230 /* guarantees that no packet will go out with the old rule after */
231 /* succesful removal. */
240 mutex_unlock(&proc_lock
);
244 static struct xt_match condition_match
= {
246 .family
= NFPROTO_IPV4
,
247 .matchsize
= sizeof(struct condition_info
),
249 .checkentry
= &checkentry
,
254 static struct xt_match condition6_match
= {
256 .family
= NFPROTO_IPV6
,
257 .matchsize
= sizeof(struct condition_info
),
259 .checkentry
= &checkentry
,
267 struct proc_dir_entry
* const proc_net
=init_net
.proc_net
;
270 dir_name
= compat_dir_name
? "ipt_condition": "nf_condition";
272 proc_net_condition
= proc_mkdir(dir_name
, proc_net
);
273 if (!proc_net_condition
) {
274 remove_proc_entry(dir_name
, proc_net
);
278 errorcode
= xt_register_match(&condition_match
);
280 xt_unregister_match(&condition_match
);
281 remove_proc_entry(dir_name
, proc_net
);
285 errorcode
= xt_register_match(&condition6_match
);
287 xt_unregister_match(&condition6_match
);
288 xt_unregister_match(&condition_match
);
289 remove_proc_entry(dir_name
, proc_net
);
300 xt_unregister_match(&condition6_match
);
301 xt_unregister_match(&condition_match
);
302 remove_proc_entry(dir_name
, init_net
.proc_net
);