iptable_filter.c revision c9bdd4b5257406b0608385d19c40b5511decf4f6
1/*
2 * This is the 1999 rewrite of IP Firewalling, aiming for kernel 2.3.x.
3 *
4 * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
5 * Copyright (C) 2000-2004 Netfilter Core Team <coreteam@netfilter.org>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 */
12
13#include <linux/module.h>
14#include <linux/moduleparam.h>
15#include <linux/netfilter_ipv4/ip_tables.h>
16#include <net/ip.h>
17
18MODULE_LICENSE("GPL");
19MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
20MODULE_DESCRIPTION("iptables filter table");
21
22#define FILTER_VALID_HOOKS ((1 << NF_IP_LOCAL_IN) | (1 << NF_IP_FORWARD) | (1 << NF_IP_LOCAL_OUT))
23
24static struct
25{
26	struct ipt_replace repl;
27	struct ipt_standard entries[3];
28	struct ipt_error term;
29} initial_table __initdata
30= { { "filter", FILTER_VALID_HOOKS, 4,
31      sizeof(struct ipt_standard) * 3 + sizeof(struct ipt_error),
32      { [NF_IP_LOCAL_IN] = 0,
33	[NF_IP_FORWARD] = sizeof(struct ipt_standard),
34	[NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2 },
35      { [NF_IP_LOCAL_IN] = 0,
36	[NF_IP_FORWARD] = sizeof(struct ipt_standard),
37	[NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2 },
38      0, NULL, { } },
39    {
40	    /* LOCAL_IN */
41	    { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
42		0,
43		sizeof(struct ipt_entry),
44		sizeof(struct ipt_standard),
45		0, { 0, 0 }, { } },
46	      { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
47		-NF_ACCEPT - 1 } },
48	    /* FORWARD */
49	    { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
50		0,
51		sizeof(struct ipt_entry),
52		sizeof(struct ipt_standard),
53		0, { 0, 0 }, { } },
54	      { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
55		-NF_ACCEPT - 1 } },
56	    /* LOCAL_OUT */
57	    { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
58		0,
59		sizeof(struct ipt_entry),
60		sizeof(struct ipt_standard),
61		0, { 0, 0 }, { } },
62	      { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
63		-NF_ACCEPT - 1 } }
64    },
65    /* ERROR */
66    { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
67	0,
68	sizeof(struct ipt_entry),
69	sizeof(struct ipt_error),
70	0, { 0, 0 }, { } },
71      { { { { IPT_ALIGN(sizeof(struct ipt_error_target)), IPT_ERROR_TARGET } },
72	  { } },
73	"ERROR"
74      }
75    }
76};
77
78static struct xt_table packet_filter = {
79	.name		= "filter",
80	.valid_hooks	= FILTER_VALID_HOOKS,
81	.lock		= RW_LOCK_UNLOCKED,
82	.me		= THIS_MODULE,
83	.af		= AF_INET,
84};
85
86/* The work comes in here from netfilter.c. */
87static unsigned int
88ipt_hook(unsigned int hook,
89	 struct sk_buff **pskb,
90	 const struct net_device *in,
91	 const struct net_device *out,
92	 int (*okfn)(struct sk_buff *))
93{
94	return ipt_do_table(pskb, hook, in, out, &packet_filter);
95}
96
97static unsigned int
98ipt_local_out_hook(unsigned int hook,
99		   struct sk_buff **pskb,
100		   const struct net_device *in,
101		   const struct net_device *out,
102		   int (*okfn)(struct sk_buff *))
103{
104	/* root is playing with raw sockets. */
105	if ((*pskb)->len < sizeof(struct iphdr)
106	    || ip_hdrlen(*pskb) < sizeof(struct iphdr)) {
107		if (net_ratelimit())
108			printk("ipt_hook: happy cracking.\n");
109		return NF_ACCEPT;
110	}
111
112	return ipt_do_table(pskb, hook, in, out, &packet_filter);
113}
114
115static struct nf_hook_ops ipt_ops[] = {
116	{
117		.hook		= ipt_hook,
118		.owner		= THIS_MODULE,
119		.pf		= PF_INET,
120		.hooknum	= NF_IP_LOCAL_IN,
121		.priority	= NF_IP_PRI_FILTER,
122	},
123	{
124		.hook		= ipt_hook,
125		.owner		= THIS_MODULE,
126		.pf		= PF_INET,
127		.hooknum	= NF_IP_FORWARD,
128		.priority	= NF_IP_PRI_FILTER,
129	},
130	{
131		.hook		= ipt_local_out_hook,
132		.owner		= THIS_MODULE,
133		.pf		= PF_INET,
134		.hooknum	= NF_IP_LOCAL_OUT,
135		.priority	= NF_IP_PRI_FILTER,
136	},
137};
138
139/* Default to forward because I got too much mail already. */
140static int forward = NF_ACCEPT;
141module_param(forward, bool, 0000);
142
143static int __init iptable_filter_init(void)
144{
145	int ret;
146
147	if (forward < 0 || forward > NF_MAX_VERDICT) {
148		printk("iptables forward must be 0 or 1\n");
149		return -EINVAL;
150	}
151
152	/* Entry 1 is the FORWARD hook */
153	initial_table.entries[1].target.verdict = -forward - 1;
154
155	/* Register table */
156	ret = ipt_register_table(&packet_filter, &initial_table.repl);
157	if (ret < 0)
158		return ret;
159
160	/* Register hooks */
161	ret = nf_register_hooks(ipt_ops, ARRAY_SIZE(ipt_ops));
162	if (ret < 0)
163		goto cleanup_table;
164
165	return ret;
166
167 cleanup_table:
168	ipt_unregister_table(&packet_filter);
169	return ret;
170}
171
172static void __exit iptable_filter_fini(void)
173{
174	nf_unregister_hooks(ipt_ops, ARRAY_SIZE(ipt_ops));
175	ipt_unregister_table(&packet_filter);
176}
177
178module_init(iptable_filter_init);
179module_exit(iptable_filter_fini);
180