Commit 19eda879a136889110c692dec4c2ab59e0e43cef
Committed by
Patrick McHardy
1 parent
18219d3f7d
Exists in
master
and in
7 other branches
netfilter: change return types of check functions for Ebtables extensions
Signed-off-by: Jan Engelhardt <jengelh@medozas.de> Signed-off-by: Patrick McHardy <kaber@trash.net>
Showing 20 changed files with 109 additions and 108 deletions Inline Diff
- include/linux/netfilter_bridge/ebtables.h
- net/bridge/netfilter/ebt_802_3.c
- net/bridge/netfilter/ebt_among.c
- net/bridge/netfilter/ebt_arp.c
- net/bridge/netfilter/ebt_arpreply.c
- net/bridge/netfilter/ebt_dnat.c
- net/bridge/netfilter/ebt_ip.c
- net/bridge/netfilter/ebt_ip6.c
- net/bridge/netfilter/ebt_limit.c
- net/bridge/netfilter/ebt_log.c
- net/bridge/netfilter/ebt_mark.c
- net/bridge/netfilter/ebt_mark_m.c
- net/bridge/netfilter/ebt_nflog.c
- net/bridge/netfilter/ebt_pkttype.c
- net/bridge/netfilter/ebt_redirect.c
- net/bridge/netfilter/ebt_snat.c
- net/bridge/netfilter/ebt_stp.c
- net/bridge/netfilter/ebt_ulog.c
- net/bridge/netfilter/ebt_vlan.c
- net/bridge/netfilter/ebtables.c
include/linux/netfilter_bridge/ebtables.h
1 | /* | 1 | /* |
2 | * ebtables | 2 | * ebtables |
3 | * | 3 | * |
4 | * Authors: | 4 | * Authors: |
5 | * Bart De Schuymer <bdschuym@pandora.be> | 5 | * Bart De Schuymer <bdschuym@pandora.be> |
6 | * | 6 | * |
7 | * ebtables.c,v 2.0, April, 2002 | 7 | * ebtables.c,v 2.0, April, 2002 |
8 | * | 8 | * |
9 | * This code is stongly inspired on the iptables code which is | 9 | * This code is stongly inspired on the iptables code which is |
10 | * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling | 10 | * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #ifndef __LINUX_BRIDGE_EFF_H | 13 | #ifndef __LINUX_BRIDGE_EFF_H |
14 | #define __LINUX_BRIDGE_EFF_H | 14 | #define __LINUX_BRIDGE_EFF_H |
15 | #include <linux/if.h> | 15 | #include <linux/if.h> |
16 | #include <linux/netfilter_bridge.h> | 16 | #include <linux/netfilter_bridge.h> |
17 | #include <linux/if_ether.h> | 17 | #include <linux/if_ether.h> |
18 | 18 | ||
19 | #define EBT_TABLE_MAXNAMELEN 32 | 19 | #define EBT_TABLE_MAXNAMELEN 32 |
20 | #define EBT_CHAIN_MAXNAMELEN EBT_TABLE_MAXNAMELEN | 20 | #define EBT_CHAIN_MAXNAMELEN EBT_TABLE_MAXNAMELEN |
21 | #define EBT_FUNCTION_MAXNAMELEN EBT_TABLE_MAXNAMELEN | 21 | #define EBT_FUNCTION_MAXNAMELEN EBT_TABLE_MAXNAMELEN |
22 | 22 | ||
23 | /* verdicts >0 are "branches" */ | 23 | /* verdicts >0 are "branches" */ |
24 | #define EBT_ACCEPT -1 | 24 | #define EBT_ACCEPT -1 |
25 | #define EBT_DROP -2 | 25 | #define EBT_DROP -2 |
26 | #define EBT_CONTINUE -3 | 26 | #define EBT_CONTINUE -3 |
27 | #define EBT_RETURN -4 | 27 | #define EBT_RETURN -4 |
28 | #define NUM_STANDARD_TARGETS 4 | 28 | #define NUM_STANDARD_TARGETS 4 |
29 | /* ebtables target modules store the verdict inside an int. We can | 29 | /* ebtables target modules store the verdict inside an int. We can |
30 | * reclaim a part of this int for backwards compatible extensions. | 30 | * reclaim a part of this int for backwards compatible extensions. |
31 | * The 4 lsb are more than enough to store the verdict. */ | 31 | * The 4 lsb are more than enough to store the verdict. */ |
32 | #define EBT_VERDICT_BITS 0x0000000F | 32 | #define EBT_VERDICT_BITS 0x0000000F |
33 | 33 | ||
34 | struct ebt_counter | 34 | struct ebt_counter |
35 | { | 35 | { |
36 | uint64_t pcnt; | 36 | uint64_t pcnt; |
37 | uint64_t bcnt; | 37 | uint64_t bcnt; |
38 | }; | 38 | }; |
39 | 39 | ||
40 | struct ebt_replace | 40 | struct ebt_replace |
41 | { | 41 | { |
42 | char name[EBT_TABLE_MAXNAMELEN]; | 42 | char name[EBT_TABLE_MAXNAMELEN]; |
43 | unsigned int valid_hooks; | 43 | unsigned int valid_hooks; |
44 | /* nr of rules in the table */ | 44 | /* nr of rules in the table */ |
45 | unsigned int nentries; | 45 | unsigned int nentries; |
46 | /* total size of the entries */ | 46 | /* total size of the entries */ |
47 | unsigned int entries_size; | 47 | unsigned int entries_size; |
48 | /* start of the chains */ | 48 | /* start of the chains */ |
49 | struct ebt_entries __user *hook_entry[NF_BR_NUMHOOKS]; | 49 | struct ebt_entries __user *hook_entry[NF_BR_NUMHOOKS]; |
50 | /* nr of counters userspace expects back */ | 50 | /* nr of counters userspace expects back */ |
51 | unsigned int num_counters; | 51 | unsigned int num_counters; |
52 | /* where the kernel will put the old counters */ | 52 | /* where the kernel will put the old counters */ |
53 | struct ebt_counter __user *counters; | 53 | struct ebt_counter __user *counters; |
54 | char __user *entries; | 54 | char __user *entries; |
55 | }; | 55 | }; |
56 | 56 | ||
57 | struct ebt_replace_kernel | 57 | struct ebt_replace_kernel |
58 | { | 58 | { |
59 | char name[EBT_TABLE_MAXNAMELEN]; | 59 | char name[EBT_TABLE_MAXNAMELEN]; |
60 | unsigned int valid_hooks; | 60 | unsigned int valid_hooks; |
61 | /* nr of rules in the table */ | 61 | /* nr of rules in the table */ |
62 | unsigned int nentries; | 62 | unsigned int nentries; |
63 | /* total size of the entries */ | 63 | /* total size of the entries */ |
64 | unsigned int entries_size; | 64 | unsigned int entries_size; |
65 | /* start of the chains */ | 65 | /* start of the chains */ |
66 | struct ebt_entries *hook_entry[NF_BR_NUMHOOKS]; | 66 | struct ebt_entries *hook_entry[NF_BR_NUMHOOKS]; |
67 | /* nr of counters userspace expects back */ | 67 | /* nr of counters userspace expects back */ |
68 | unsigned int num_counters; | 68 | unsigned int num_counters; |
69 | /* where the kernel will put the old counters */ | 69 | /* where the kernel will put the old counters */ |
70 | struct ebt_counter *counters; | 70 | struct ebt_counter *counters; |
71 | char *entries; | 71 | char *entries; |
72 | }; | 72 | }; |
73 | 73 | ||
74 | struct ebt_entries { | 74 | struct ebt_entries { |
75 | /* this field is always set to zero | 75 | /* this field is always set to zero |
76 | * See EBT_ENTRY_OR_ENTRIES. | 76 | * See EBT_ENTRY_OR_ENTRIES. |
77 | * Must be same size as ebt_entry.bitmask */ | 77 | * Must be same size as ebt_entry.bitmask */ |
78 | unsigned int distinguisher; | 78 | unsigned int distinguisher; |
79 | /* the chain name */ | 79 | /* the chain name */ |
80 | char name[EBT_CHAIN_MAXNAMELEN]; | 80 | char name[EBT_CHAIN_MAXNAMELEN]; |
81 | /* counter offset for this chain */ | 81 | /* counter offset for this chain */ |
82 | unsigned int counter_offset; | 82 | unsigned int counter_offset; |
83 | /* one standard (accept, drop, return) per hook */ | 83 | /* one standard (accept, drop, return) per hook */ |
84 | int policy; | 84 | int policy; |
85 | /* nr. of entries */ | 85 | /* nr. of entries */ |
86 | unsigned int nentries; | 86 | unsigned int nentries; |
87 | /* entry list */ | 87 | /* entry list */ |
88 | char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace)))); | 88 | char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace)))); |
89 | }; | 89 | }; |
90 | 90 | ||
91 | /* used for the bitmask of struct ebt_entry */ | 91 | /* used for the bitmask of struct ebt_entry */ |
92 | 92 | ||
93 | /* This is a hack to make a difference between an ebt_entry struct and an | 93 | /* This is a hack to make a difference between an ebt_entry struct and an |
94 | * ebt_entries struct when traversing the entries from start to end. | 94 | * ebt_entries struct when traversing the entries from start to end. |
95 | * Using this simplifies the code alot, while still being able to use | 95 | * Using this simplifies the code alot, while still being able to use |
96 | * ebt_entries. | 96 | * ebt_entries. |
97 | * Contrary, iptables doesn't use something like ebt_entries and therefore uses | 97 | * Contrary, iptables doesn't use something like ebt_entries and therefore uses |
98 | * different techniques for naming the policy and such. So, iptables doesn't | 98 | * different techniques for naming the policy and such. So, iptables doesn't |
99 | * need a hack like this. | 99 | * need a hack like this. |
100 | */ | 100 | */ |
101 | #define EBT_ENTRY_OR_ENTRIES 0x01 | 101 | #define EBT_ENTRY_OR_ENTRIES 0x01 |
102 | /* these are the normal masks */ | 102 | /* these are the normal masks */ |
103 | #define EBT_NOPROTO 0x02 | 103 | #define EBT_NOPROTO 0x02 |
104 | #define EBT_802_3 0x04 | 104 | #define EBT_802_3 0x04 |
105 | #define EBT_SOURCEMAC 0x08 | 105 | #define EBT_SOURCEMAC 0x08 |
106 | #define EBT_DESTMAC 0x10 | 106 | #define EBT_DESTMAC 0x10 |
107 | #define EBT_F_MASK (EBT_NOPROTO | EBT_802_3 | EBT_SOURCEMAC | EBT_DESTMAC \ | 107 | #define EBT_F_MASK (EBT_NOPROTO | EBT_802_3 | EBT_SOURCEMAC | EBT_DESTMAC \ |
108 | | EBT_ENTRY_OR_ENTRIES) | 108 | | EBT_ENTRY_OR_ENTRIES) |
109 | 109 | ||
110 | #define EBT_IPROTO 0x01 | 110 | #define EBT_IPROTO 0x01 |
111 | #define EBT_IIN 0x02 | 111 | #define EBT_IIN 0x02 |
112 | #define EBT_IOUT 0x04 | 112 | #define EBT_IOUT 0x04 |
113 | #define EBT_ISOURCE 0x8 | 113 | #define EBT_ISOURCE 0x8 |
114 | #define EBT_IDEST 0x10 | 114 | #define EBT_IDEST 0x10 |
115 | #define EBT_ILOGICALIN 0x20 | 115 | #define EBT_ILOGICALIN 0x20 |
116 | #define EBT_ILOGICALOUT 0x40 | 116 | #define EBT_ILOGICALOUT 0x40 |
117 | #define EBT_INV_MASK (EBT_IPROTO | EBT_IIN | EBT_IOUT | EBT_ILOGICALIN \ | 117 | #define EBT_INV_MASK (EBT_IPROTO | EBT_IIN | EBT_IOUT | EBT_ILOGICALIN \ |
118 | | EBT_ILOGICALOUT | EBT_ISOURCE | EBT_IDEST) | 118 | | EBT_ILOGICALOUT | EBT_ISOURCE | EBT_IDEST) |
119 | 119 | ||
120 | struct ebt_entry_match | 120 | struct ebt_entry_match |
121 | { | 121 | { |
122 | union { | 122 | union { |
123 | char name[EBT_FUNCTION_MAXNAMELEN]; | 123 | char name[EBT_FUNCTION_MAXNAMELEN]; |
124 | struct ebt_match *match; | 124 | struct ebt_match *match; |
125 | } u; | 125 | } u; |
126 | /* size of data */ | 126 | /* size of data */ |
127 | unsigned int match_size; | 127 | unsigned int match_size; |
128 | unsigned char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace)))); | 128 | unsigned char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace)))); |
129 | }; | 129 | }; |
130 | 130 | ||
131 | struct ebt_entry_watcher | 131 | struct ebt_entry_watcher |
132 | { | 132 | { |
133 | union { | 133 | union { |
134 | char name[EBT_FUNCTION_MAXNAMELEN]; | 134 | char name[EBT_FUNCTION_MAXNAMELEN]; |
135 | struct ebt_watcher *watcher; | 135 | struct ebt_watcher *watcher; |
136 | } u; | 136 | } u; |
137 | /* size of data */ | 137 | /* size of data */ |
138 | unsigned int watcher_size; | 138 | unsigned int watcher_size; |
139 | unsigned char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace)))); | 139 | unsigned char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace)))); |
140 | }; | 140 | }; |
141 | 141 | ||
142 | struct ebt_entry_target | 142 | struct ebt_entry_target |
143 | { | 143 | { |
144 | union { | 144 | union { |
145 | char name[EBT_FUNCTION_MAXNAMELEN]; | 145 | char name[EBT_FUNCTION_MAXNAMELEN]; |
146 | struct ebt_target *target; | 146 | struct ebt_target *target; |
147 | } u; | 147 | } u; |
148 | /* size of data */ | 148 | /* size of data */ |
149 | unsigned int target_size; | 149 | unsigned int target_size; |
150 | unsigned char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace)))); | 150 | unsigned char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace)))); |
151 | }; | 151 | }; |
152 | 152 | ||
153 | #define EBT_STANDARD_TARGET "standard" | 153 | #define EBT_STANDARD_TARGET "standard" |
154 | struct ebt_standard_target | 154 | struct ebt_standard_target |
155 | { | 155 | { |
156 | struct ebt_entry_target target; | 156 | struct ebt_entry_target target; |
157 | int verdict; | 157 | int verdict; |
158 | }; | 158 | }; |
159 | 159 | ||
160 | /* one entry */ | 160 | /* one entry */ |
161 | struct ebt_entry { | 161 | struct ebt_entry { |
162 | /* this needs to be the first field */ | 162 | /* this needs to be the first field */ |
163 | unsigned int bitmask; | 163 | unsigned int bitmask; |
164 | unsigned int invflags; | 164 | unsigned int invflags; |
165 | __be16 ethproto; | 165 | __be16 ethproto; |
166 | /* the physical in-dev */ | 166 | /* the physical in-dev */ |
167 | char in[IFNAMSIZ]; | 167 | char in[IFNAMSIZ]; |
168 | /* the logical in-dev */ | 168 | /* the logical in-dev */ |
169 | char logical_in[IFNAMSIZ]; | 169 | char logical_in[IFNAMSIZ]; |
170 | /* the physical out-dev */ | 170 | /* the physical out-dev */ |
171 | char out[IFNAMSIZ]; | 171 | char out[IFNAMSIZ]; |
172 | /* the logical out-dev */ | 172 | /* the logical out-dev */ |
173 | char logical_out[IFNAMSIZ]; | 173 | char logical_out[IFNAMSIZ]; |
174 | unsigned char sourcemac[ETH_ALEN]; | 174 | unsigned char sourcemac[ETH_ALEN]; |
175 | unsigned char sourcemsk[ETH_ALEN]; | 175 | unsigned char sourcemsk[ETH_ALEN]; |
176 | unsigned char destmac[ETH_ALEN]; | 176 | unsigned char destmac[ETH_ALEN]; |
177 | unsigned char destmsk[ETH_ALEN]; | 177 | unsigned char destmsk[ETH_ALEN]; |
178 | /* sizeof ebt_entry + matches */ | 178 | /* sizeof ebt_entry + matches */ |
179 | unsigned int watchers_offset; | 179 | unsigned int watchers_offset; |
180 | /* sizeof ebt_entry + matches + watchers */ | 180 | /* sizeof ebt_entry + matches + watchers */ |
181 | unsigned int target_offset; | 181 | unsigned int target_offset; |
182 | /* sizeof ebt_entry + matches + watchers + target */ | 182 | /* sizeof ebt_entry + matches + watchers + target */ |
183 | unsigned int next_offset; | 183 | unsigned int next_offset; |
184 | unsigned char elems[0] __attribute__ ((aligned (__alignof__(struct ebt_replace)))); | 184 | unsigned char elems[0] __attribute__ ((aligned (__alignof__(struct ebt_replace)))); |
185 | }; | 185 | }; |
186 | 186 | ||
187 | /* {g,s}etsockopt numbers */ | 187 | /* {g,s}etsockopt numbers */ |
188 | #define EBT_BASE_CTL 128 | 188 | #define EBT_BASE_CTL 128 |
189 | 189 | ||
190 | #define EBT_SO_SET_ENTRIES (EBT_BASE_CTL) | 190 | #define EBT_SO_SET_ENTRIES (EBT_BASE_CTL) |
191 | #define EBT_SO_SET_COUNTERS (EBT_SO_SET_ENTRIES+1) | 191 | #define EBT_SO_SET_COUNTERS (EBT_SO_SET_ENTRIES+1) |
192 | #define EBT_SO_SET_MAX (EBT_SO_SET_COUNTERS+1) | 192 | #define EBT_SO_SET_MAX (EBT_SO_SET_COUNTERS+1) |
193 | 193 | ||
194 | #define EBT_SO_GET_INFO (EBT_BASE_CTL) | 194 | #define EBT_SO_GET_INFO (EBT_BASE_CTL) |
195 | #define EBT_SO_GET_ENTRIES (EBT_SO_GET_INFO+1) | 195 | #define EBT_SO_GET_ENTRIES (EBT_SO_GET_INFO+1) |
196 | #define EBT_SO_GET_INIT_INFO (EBT_SO_GET_ENTRIES+1) | 196 | #define EBT_SO_GET_INIT_INFO (EBT_SO_GET_ENTRIES+1) |
197 | #define EBT_SO_GET_INIT_ENTRIES (EBT_SO_GET_INIT_INFO+1) | 197 | #define EBT_SO_GET_INIT_ENTRIES (EBT_SO_GET_INIT_INFO+1) |
198 | #define EBT_SO_GET_MAX (EBT_SO_GET_INIT_ENTRIES+1) | 198 | #define EBT_SO_GET_MAX (EBT_SO_GET_INIT_ENTRIES+1) |
199 | 199 | ||
200 | #ifdef __KERNEL__ | 200 | #ifdef __KERNEL__ |
201 | 201 | ||
202 | /* return values for match() functions */ | 202 | /* return values for match() functions */ |
203 | #define EBT_MATCH 0 | 203 | #define EBT_MATCH 0 |
204 | #define EBT_NOMATCH 1 | 204 | #define EBT_NOMATCH 1 |
205 | 205 | ||
206 | struct ebt_match | 206 | struct ebt_match |
207 | { | 207 | { |
208 | struct list_head list; | 208 | struct list_head list; |
209 | const char name[EBT_FUNCTION_MAXNAMELEN]; | 209 | const char name[EBT_FUNCTION_MAXNAMELEN]; |
210 | /* 0 == it matches */ | 210 | /* 0 == it matches */ |
211 | int (*match)(const struct sk_buff *skb, const struct net_device *in, | 211 | int (*match)(const struct sk_buff *skb, const struct net_device *in, |
212 | const struct net_device *out, const void *matchdata, | 212 | const struct net_device *out, const void *matchdata, |
213 | unsigned int datalen); | 213 | unsigned int datalen); |
214 | /* 0 == let it in */ | 214 | bool (*check)(const char *tablename, unsigned int hookmask, |
215 | int (*check)(const char *tablename, unsigned int hookmask, | ||
216 | const struct ebt_entry *e, void *matchdata, unsigned int datalen); | 215 | const struct ebt_entry *e, void *matchdata, unsigned int datalen); |
217 | void (*destroy)(void *matchdata, unsigned int datalen); | 216 | void (*destroy)(void *matchdata, unsigned int datalen); |
218 | unsigned int matchsize; | 217 | unsigned int matchsize; |
219 | struct module *me; | 218 | struct module *me; |
220 | }; | 219 | }; |
221 | 220 | ||
222 | struct ebt_watcher | 221 | struct ebt_watcher |
223 | { | 222 | { |
224 | struct list_head list; | 223 | struct list_head list; |
225 | const char name[EBT_FUNCTION_MAXNAMELEN]; | 224 | const char name[EBT_FUNCTION_MAXNAMELEN]; |
226 | void (*watcher)(const struct sk_buff *skb, unsigned int hooknr, | 225 | void (*watcher)(const struct sk_buff *skb, unsigned int hooknr, |
227 | const struct net_device *in, const struct net_device *out, | 226 | const struct net_device *in, const struct net_device *out, |
228 | const void *watcherdata, unsigned int datalen); | 227 | const void *watcherdata, unsigned int datalen); |
229 | /* 0 == let it in */ | 228 | bool (*check)(const char *tablename, unsigned int hookmask, |
230 | int (*check)(const char *tablename, unsigned int hookmask, | ||
231 | const struct ebt_entry *e, void *watcherdata, unsigned int datalen); | 229 | const struct ebt_entry *e, void *watcherdata, unsigned int datalen); |
232 | void (*destroy)(void *watcherdata, unsigned int datalen); | 230 | void (*destroy)(void *watcherdata, unsigned int datalen); |
233 | unsigned int targetsize; | 231 | unsigned int targetsize; |
234 | struct module *me; | 232 | struct module *me; |
235 | }; | 233 | }; |
236 | 234 | ||
237 | struct ebt_target | 235 | struct ebt_target |
238 | { | 236 | { |
239 | struct list_head list; | 237 | struct list_head list; |
240 | const char name[EBT_FUNCTION_MAXNAMELEN]; | 238 | const char name[EBT_FUNCTION_MAXNAMELEN]; |
241 | /* returns one of the standard verdicts */ | 239 | /* returns one of the standard verdicts */ |
242 | int (*target)(struct sk_buff *skb, unsigned int hooknr, | 240 | int (*target)(struct sk_buff *skb, unsigned int hooknr, |
243 | const struct net_device *in, const struct net_device *out, | 241 | const struct net_device *in, const struct net_device *out, |
244 | const void *targetdata, unsigned int datalen); | 242 | const void *targetdata, unsigned int datalen); |
245 | /* 0 == let it in */ | 243 | bool (*check)(const char *tablename, unsigned int hookmask, |
246 | int (*check)(const char *tablename, unsigned int hookmask, | ||
247 | const struct ebt_entry *e, void *targetdata, unsigned int datalen); | 244 | const struct ebt_entry *e, void *targetdata, unsigned int datalen); |
248 | void (*destroy)(void *targetdata, unsigned int datalen); | 245 | void (*destroy)(void *targetdata, unsigned int datalen); |
249 | unsigned int targetsize; | 246 | unsigned int targetsize; |
250 | struct module *me; | 247 | struct module *me; |
251 | }; | 248 | }; |
252 | 249 | ||
253 | /* used for jumping from and into user defined chains (udc) */ | 250 | /* used for jumping from and into user defined chains (udc) */ |
254 | struct ebt_chainstack | 251 | struct ebt_chainstack |
255 | { | 252 | { |
256 | struct ebt_entries *chaininfo; /* pointer to chain data */ | 253 | struct ebt_entries *chaininfo; /* pointer to chain data */ |
257 | struct ebt_entry *e; /* pointer to entry data */ | 254 | struct ebt_entry *e; /* pointer to entry data */ |
258 | unsigned int n; /* n'th entry */ | 255 | unsigned int n; /* n'th entry */ |
259 | }; | 256 | }; |
260 | 257 | ||
261 | struct ebt_table_info | 258 | struct ebt_table_info |
262 | { | 259 | { |
263 | /* total size of the entries */ | 260 | /* total size of the entries */ |
264 | unsigned int entries_size; | 261 | unsigned int entries_size; |
265 | unsigned int nentries; | 262 | unsigned int nentries; |
266 | /* pointers to the start of the chains */ | 263 | /* pointers to the start of the chains */ |
267 | struct ebt_entries *hook_entry[NF_BR_NUMHOOKS]; | 264 | struct ebt_entries *hook_entry[NF_BR_NUMHOOKS]; |
268 | /* room to maintain the stack used for jumping from and into udc */ | 265 | /* room to maintain the stack used for jumping from and into udc */ |
269 | struct ebt_chainstack **chainstack; | 266 | struct ebt_chainstack **chainstack; |
270 | char *entries; | 267 | char *entries; |
271 | struct ebt_counter counters[0] ____cacheline_aligned; | 268 | struct ebt_counter counters[0] ____cacheline_aligned; |
272 | }; | 269 | }; |
273 | 270 | ||
274 | struct ebt_table | 271 | struct ebt_table |
275 | { | 272 | { |
276 | struct list_head list; | 273 | struct list_head list; |
277 | char name[EBT_TABLE_MAXNAMELEN]; | 274 | char name[EBT_TABLE_MAXNAMELEN]; |
278 | struct ebt_replace_kernel *table; | 275 | struct ebt_replace_kernel *table; |
279 | unsigned int valid_hooks; | 276 | unsigned int valid_hooks; |
280 | rwlock_t lock; | 277 | rwlock_t lock; |
281 | /* e.g. could be the table explicitly only allows certain | 278 | /* e.g. could be the table explicitly only allows certain |
282 | * matches, targets, ... 0 == let it in */ | 279 | * matches, targets, ... 0 == let it in */ |
283 | int (*check)(const struct ebt_table_info *info, | 280 | int (*check)(const struct ebt_table_info *info, |
284 | unsigned int valid_hooks); | 281 | unsigned int valid_hooks); |
285 | /* the data used by the kernel */ | 282 | /* the data used by the kernel */ |
286 | struct ebt_table_info *private; | 283 | struct ebt_table_info *private; |
287 | struct module *me; | 284 | struct module *me; |
288 | }; | 285 | }; |
289 | 286 | ||
290 | #define EBT_ALIGN(s) (((s) + (__alignof__(struct ebt_replace)-1)) & \ | 287 | #define EBT_ALIGN(s) (((s) + (__alignof__(struct ebt_replace)-1)) & \ |
291 | ~(__alignof__(struct ebt_replace)-1)) | 288 | ~(__alignof__(struct ebt_replace)-1)) |
292 | extern int ebt_register_table(struct ebt_table *table); | 289 | extern int ebt_register_table(struct ebt_table *table); |
293 | extern void ebt_unregister_table(struct ebt_table *table); | 290 | extern void ebt_unregister_table(struct ebt_table *table); |
294 | extern int ebt_register_match(struct ebt_match *match); | 291 | extern int ebt_register_match(struct ebt_match *match); |
295 | extern void ebt_unregister_match(struct ebt_match *match); | 292 | extern void ebt_unregister_match(struct ebt_match *match); |
296 | extern int ebt_register_watcher(struct ebt_watcher *watcher); | 293 | extern int ebt_register_watcher(struct ebt_watcher *watcher); |
297 | extern void ebt_unregister_watcher(struct ebt_watcher *watcher); | 294 | extern void ebt_unregister_watcher(struct ebt_watcher *watcher); |
298 | extern int ebt_register_target(struct ebt_target *target); | 295 | extern int ebt_register_target(struct ebt_target *target); |
299 | extern void ebt_unregister_target(struct ebt_target *target); | 296 | extern void ebt_unregister_target(struct ebt_target *target); |
300 | extern unsigned int ebt_do_table(unsigned int hook, struct sk_buff *skb, | 297 | extern unsigned int ebt_do_table(unsigned int hook, struct sk_buff *skb, |
301 | const struct net_device *in, const struct net_device *out, | 298 | const struct net_device *in, const struct net_device *out, |
302 | struct ebt_table *table); | 299 | struct ebt_table *table); |
303 | 300 | ||
304 | /* Used in the kernel match() functions */ | 301 | /* Used in the kernel match() functions */ |
305 | #define FWINV(bool,invflg) ((bool) ^ !!(info->invflags & invflg)) | 302 | #define FWINV(bool,invflg) ((bool) ^ !!(info->invflags & invflg)) |
306 | /* True if the hook mask denotes that the rule is in a base chain, | 303 | /* True if the hook mask denotes that the rule is in a base chain, |
307 | * used in the check() functions */ | 304 | * used in the check() functions */ |
308 | #define BASE_CHAIN (hookmask & (1 << NF_BR_NUMHOOKS)) | 305 | #define BASE_CHAIN (hookmask & (1 << NF_BR_NUMHOOKS)) |
309 | /* Clear the bit in the hook mask that tells if the rule is on a base chain */ | 306 | /* Clear the bit in the hook mask that tells if the rule is on a base chain */ |
310 | #define CLEAR_BASE_CHAIN_BIT (hookmask &= ~(1 << NF_BR_NUMHOOKS)) | 307 | #define CLEAR_BASE_CHAIN_BIT (hookmask &= ~(1 << NF_BR_NUMHOOKS)) |
311 | /* True if the target is not a standard target */ | 308 | /* True if the target is not a standard target */ |
312 | #define INVALID_TARGET (info->target < -NUM_STANDARD_TARGETS || info->target >= 0) | 309 | #define INVALID_TARGET (info->target < -NUM_STANDARD_TARGETS || info->target >= 0) |
313 | 310 | ||
314 | #endif /* __KERNEL__ */ | 311 | #endif /* __KERNEL__ */ |
315 | 312 | ||
316 | /* blatently stolen from ip_tables.h | 313 | /* blatently stolen from ip_tables.h |
317 | * fn returns 0 to continue iteration */ | 314 | * fn returns 0 to continue iteration */ |
318 | #define EBT_MATCH_ITERATE(e, fn, args...) \ | 315 | #define EBT_MATCH_ITERATE(e, fn, args...) \ |
319 | ({ \ | 316 | ({ \ |
320 | unsigned int __i; \ | 317 | unsigned int __i; \ |
321 | int __ret = 0; \ | 318 | int __ret = 0; \ |
322 | struct ebt_entry_match *__match; \ | 319 | struct ebt_entry_match *__match; \ |
323 | \ | 320 | \ |
324 | for (__i = sizeof(struct ebt_entry); \ | 321 | for (__i = sizeof(struct ebt_entry); \ |
325 | __i < (e)->watchers_offset; \ | 322 | __i < (e)->watchers_offset; \ |
326 | __i += __match->match_size + \ | 323 | __i += __match->match_size + \ |
327 | sizeof(struct ebt_entry_match)) { \ | 324 | sizeof(struct ebt_entry_match)) { \ |
328 | __match = (void *)(e) + __i; \ | 325 | __match = (void *)(e) + __i; \ |
329 | \ | 326 | \ |
330 | __ret = fn(__match , ## args); \ | 327 | __ret = fn(__match , ## args); \ |
331 | if (__ret != 0) \ | 328 | if (__ret != 0) \ |
332 | break; \ | 329 | break; \ |
333 | } \ | 330 | } \ |
334 | if (__ret == 0) { \ | 331 | if (__ret == 0) { \ |
335 | if (__i != (e)->watchers_offset) \ | 332 | if (__i != (e)->watchers_offset) \ |
336 | __ret = -EINVAL; \ | 333 | __ret = -EINVAL; \ |
337 | } \ | 334 | } \ |
338 | __ret; \ | 335 | __ret; \ |
339 | }) | 336 | }) |
340 | 337 | ||
341 | #define EBT_WATCHER_ITERATE(e, fn, args...) \ | 338 | #define EBT_WATCHER_ITERATE(e, fn, args...) \ |
342 | ({ \ | 339 | ({ \ |
343 | unsigned int __i; \ | 340 | unsigned int __i; \ |
344 | int __ret = 0; \ | 341 | int __ret = 0; \ |
345 | struct ebt_entry_watcher *__watcher; \ | 342 | struct ebt_entry_watcher *__watcher; \ |
346 | \ | 343 | \ |
347 | for (__i = e->watchers_offset; \ | 344 | for (__i = e->watchers_offset; \ |
348 | __i < (e)->target_offset; \ | 345 | __i < (e)->target_offset; \ |
349 | __i += __watcher->watcher_size + \ | 346 | __i += __watcher->watcher_size + \ |
350 | sizeof(struct ebt_entry_watcher)) { \ | 347 | sizeof(struct ebt_entry_watcher)) { \ |
351 | __watcher = (void *)(e) + __i; \ | 348 | __watcher = (void *)(e) + __i; \ |
352 | \ | 349 | \ |
353 | __ret = fn(__watcher , ## args); \ | 350 | __ret = fn(__watcher , ## args); \ |
354 | if (__ret != 0) \ | 351 | if (__ret != 0) \ |
355 | break; \ | 352 | break; \ |
356 | } \ | 353 | } \ |
357 | if (__ret == 0) { \ | 354 | if (__ret == 0) { \ |
358 | if (__i != (e)->target_offset) \ | 355 | if (__i != (e)->target_offset) \ |
359 | __ret = -EINVAL; \ | 356 | __ret = -EINVAL; \ |
360 | } \ | 357 | } \ |
361 | __ret; \ | 358 | __ret; \ |
362 | }) | 359 | }) |
363 | 360 | ||
364 | #define EBT_ENTRY_ITERATE(entries, size, fn, args...) \ | 361 | #define EBT_ENTRY_ITERATE(entries, size, fn, args...) \ |
365 | ({ \ | 362 | ({ \ |
366 | unsigned int __i; \ | 363 | unsigned int __i; \ |
367 | int __ret = 0; \ | 364 | int __ret = 0; \ |
368 | struct ebt_entry *__entry; \ | 365 | struct ebt_entry *__entry; \ |
369 | \ | 366 | \ |
370 | for (__i = 0; __i < (size);) { \ | 367 | for (__i = 0; __i < (size);) { \ |
371 | __entry = (void *)(entries) + __i; \ | 368 | __entry = (void *)(entries) + __i; \ |
372 | __ret = fn(__entry , ## args); \ | 369 | __ret = fn(__entry , ## args); \ |
373 | if (__ret != 0) \ | 370 | if (__ret != 0) \ |
374 | break; \ | 371 | break; \ |
375 | if (__entry->bitmask != 0) \ | 372 | if (__entry->bitmask != 0) \ |
376 | __i += __entry->next_offset; \ | 373 | __i += __entry->next_offset; \ |
377 | else \ | 374 | else \ |
378 | __i += sizeof(struct ebt_entries); \ | 375 | __i += sizeof(struct ebt_entries); \ |
379 | } \ | 376 | } \ |
380 | if (__ret == 0) { \ | 377 | if (__ret == 0) { \ |
381 | if (__i != (size)) \ | 378 | if (__i != (size)) \ |
382 | __ret = -EINVAL; \ | 379 | __ret = -EINVAL; \ |
383 | } \ | 380 | } \ |
384 | __ret; \ | 381 | __ret; \ |
385 | }) | 382 | }) |
386 | 383 | ||
387 | #endif | 384 | #endif |
388 | 385 |
net/bridge/netfilter/ebt_802_3.c
1 | /* | 1 | /* |
2 | * 802_3 | 2 | * 802_3 |
3 | * | 3 | * |
4 | * Author: | 4 | * Author: |
5 | * Chris Vitale csv@bluetail.com | 5 | * Chris Vitale csv@bluetail.com |
6 | * | 6 | * |
7 | * May 2003 | 7 | * May 2003 |
8 | * | 8 | * |
9 | */ | 9 | */ |
10 | #include <linux/module.h> | 10 | #include <linux/module.h> |
11 | #include <linux/netfilter/x_tables.h> | 11 | #include <linux/netfilter/x_tables.h> |
12 | #include <linux/netfilter_bridge/ebtables.h> | 12 | #include <linux/netfilter_bridge/ebtables.h> |
13 | #include <linux/netfilter_bridge/ebt_802_3.h> | 13 | #include <linux/netfilter_bridge/ebt_802_3.h> |
14 | 14 | ||
15 | static int ebt_filter_802_3(const struct sk_buff *skb, const struct net_device *in, | 15 | static int ebt_filter_802_3(const struct sk_buff *skb, const struct net_device *in, |
16 | const struct net_device *out, const void *data, unsigned int datalen) | 16 | const struct net_device *out, const void *data, unsigned int datalen) |
17 | { | 17 | { |
18 | const struct ebt_802_3_info *info = data; | 18 | const struct ebt_802_3_info *info = data; |
19 | const struct ebt_802_3_hdr *hdr = ebt_802_3_hdr(skb); | 19 | const struct ebt_802_3_hdr *hdr = ebt_802_3_hdr(skb); |
20 | __be16 type = hdr->llc.ui.ctrl & IS_UI ? hdr->llc.ui.type : hdr->llc.ni.type; | 20 | __be16 type = hdr->llc.ui.ctrl & IS_UI ? hdr->llc.ui.type : hdr->llc.ni.type; |
21 | 21 | ||
22 | if (info->bitmask & EBT_802_3_SAP) { | 22 | if (info->bitmask & EBT_802_3_SAP) { |
23 | if (FWINV(info->sap != hdr->llc.ui.ssap, EBT_802_3_SAP)) | 23 | if (FWINV(info->sap != hdr->llc.ui.ssap, EBT_802_3_SAP)) |
24 | return EBT_NOMATCH; | 24 | return EBT_NOMATCH; |
25 | if (FWINV(info->sap != hdr->llc.ui.dsap, EBT_802_3_SAP)) | 25 | if (FWINV(info->sap != hdr->llc.ui.dsap, EBT_802_3_SAP)) |
26 | return EBT_NOMATCH; | 26 | return EBT_NOMATCH; |
27 | } | 27 | } |
28 | 28 | ||
29 | if (info->bitmask & EBT_802_3_TYPE) { | 29 | if (info->bitmask & EBT_802_3_TYPE) { |
30 | if (!(hdr->llc.ui.dsap == CHECK_TYPE && hdr->llc.ui.ssap == CHECK_TYPE)) | 30 | if (!(hdr->llc.ui.dsap == CHECK_TYPE && hdr->llc.ui.ssap == CHECK_TYPE)) |
31 | return EBT_NOMATCH; | 31 | return EBT_NOMATCH; |
32 | if (FWINV(info->type != type, EBT_802_3_TYPE)) | 32 | if (FWINV(info->type != type, EBT_802_3_TYPE)) |
33 | return EBT_NOMATCH; | 33 | return EBT_NOMATCH; |
34 | } | 34 | } |
35 | 35 | ||
36 | return EBT_MATCH; | 36 | return EBT_MATCH; |
37 | } | 37 | } |
38 | 38 | ||
39 | static struct ebt_match filter_802_3; | 39 | static struct ebt_match filter_802_3; |
40 | static int ebt_802_3_check(const char *tablename, unsigned int hookmask, | 40 | static bool ebt_802_3_check(const char *tablename, unsigned int hookmask, |
41 | const struct ebt_entry *e, void *data, unsigned int datalen) | 41 | const struct ebt_entry *e, void *data, unsigned int datalen) |
42 | { | 42 | { |
43 | const struct ebt_802_3_info *info = data; | 43 | const struct ebt_802_3_info *info = data; |
44 | 44 | ||
45 | if (info->bitmask & ~EBT_802_3_MASK || info->invflags & ~EBT_802_3_MASK) | 45 | if (info->bitmask & ~EBT_802_3_MASK || info->invflags & ~EBT_802_3_MASK) |
46 | return -EINVAL; | 46 | return false; |
47 | 47 | ||
48 | return 0; | 48 | return true; |
49 | } | 49 | } |
50 | 50 | ||
51 | static struct ebt_match filter_802_3 __read_mostly = { | 51 | static struct ebt_match filter_802_3 __read_mostly = { |
52 | .name = EBT_802_3_MATCH, | 52 | .name = EBT_802_3_MATCH, |
53 | .match = ebt_filter_802_3, | 53 | .match = ebt_filter_802_3, |
54 | .check = ebt_802_3_check, | 54 | .check = ebt_802_3_check, |
55 | .matchsize = XT_ALIGN(sizeof(struct ebt_802_3_info)), | 55 | .matchsize = XT_ALIGN(sizeof(struct ebt_802_3_info)), |
56 | .me = THIS_MODULE, | 56 | .me = THIS_MODULE, |
57 | }; | 57 | }; |
58 | 58 | ||
59 | static int __init ebt_802_3_init(void) | 59 | static int __init ebt_802_3_init(void) |
60 | { | 60 | { |
61 | return ebt_register_match(&filter_802_3); | 61 | return ebt_register_match(&filter_802_3); |
62 | } | 62 | } |
63 | 63 | ||
64 | static void __exit ebt_802_3_fini(void) | 64 | static void __exit ebt_802_3_fini(void) |
65 | { | 65 | { |
66 | ebt_unregister_match(&filter_802_3); | 66 | ebt_unregister_match(&filter_802_3); |
67 | } | 67 | } |
68 | 68 | ||
69 | module_init(ebt_802_3_init); | 69 | module_init(ebt_802_3_init); |
70 | module_exit(ebt_802_3_fini); | 70 | module_exit(ebt_802_3_fini); |
71 | MODULE_DESCRIPTION("Ebtables: DSAP/SSAP field and SNAP type matching"); | 71 | MODULE_DESCRIPTION("Ebtables: DSAP/SSAP field and SNAP type matching"); |
72 | MODULE_LICENSE("GPL"); | 72 | MODULE_LICENSE("GPL"); |
73 | 73 |
net/bridge/netfilter/ebt_among.c
1 | /* | 1 | /* |
2 | * ebt_among | 2 | * ebt_among |
3 | * | 3 | * |
4 | * Authors: | 4 | * Authors: |
5 | * Grzegorz Borowiak <grzes@gnu.univ.gda.pl> | 5 | * Grzegorz Borowiak <grzes@gnu.univ.gda.pl> |
6 | * | 6 | * |
7 | * August, 2003 | 7 | * August, 2003 |
8 | * | 8 | * |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/netfilter_bridge/ebtables.h> | 11 | #include <linux/netfilter_bridge/ebtables.h> |
12 | #include <linux/netfilter_bridge/ebt_among.h> | 12 | #include <linux/netfilter_bridge/ebt_among.h> |
13 | #include <linux/ip.h> | 13 | #include <linux/ip.h> |
14 | #include <linux/if_arp.h> | 14 | #include <linux/if_arp.h> |
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | 16 | ||
17 | static int ebt_mac_wormhash_contains(const struct ebt_mac_wormhash *wh, | 17 | static int ebt_mac_wormhash_contains(const struct ebt_mac_wormhash *wh, |
18 | const char *mac, __be32 ip) | 18 | const char *mac, __be32 ip) |
19 | { | 19 | { |
20 | /* You may be puzzled as to how this code works. | 20 | /* You may be puzzled as to how this code works. |
21 | * Some tricks were used, refer to | 21 | * Some tricks were used, refer to |
22 | * include/linux/netfilter_bridge/ebt_among.h | 22 | * include/linux/netfilter_bridge/ebt_among.h |
23 | * as there you can find a solution of this mystery. | 23 | * as there you can find a solution of this mystery. |
24 | */ | 24 | */ |
25 | const struct ebt_mac_wormhash_tuple *p; | 25 | const struct ebt_mac_wormhash_tuple *p; |
26 | int start, limit, i; | 26 | int start, limit, i; |
27 | uint32_t cmp[2] = { 0, 0 }; | 27 | uint32_t cmp[2] = { 0, 0 }; |
28 | int key = ((const unsigned char *)mac)[5]; | 28 | int key = ((const unsigned char *)mac)[5]; |
29 | 29 | ||
30 | memcpy(((char *) cmp) + 2, mac, 6); | 30 | memcpy(((char *) cmp) + 2, mac, 6); |
31 | start = wh->table[key]; | 31 | start = wh->table[key]; |
32 | limit = wh->table[key + 1]; | 32 | limit = wh->table[key + 1]; |
33 | if (ip) { | 33 | if (ip) { |
34 | for (i = start; i < limit; i++) { | 34 | for (i = start; i < limit; i++) { |
35 | p = &wh->pool[i]; | 35 | p = &wh->pool[i]; |
36 | if (cmp[1] == p->cmp[1] && cmp[0] == p->cmp[0]) { | 36 | if (cmp[1] == p->cmp[1] && cmp[0] == p->cmp[0]) { |
37 | if (p->ip == 0 || p->ip == ip) { | 37 | if (p->ip == 0 || p->ip == ip) { |
38 | return 1; | 38 | return 1; |
39 | } | 39 | } |
40 | } | 40 | } |
41 | } | 41 | } |
42 | } else { | 42 | } else { |
43 | for (i = start; i < limit; i++) { | 43 | for (i = start; i < limit; i++) { |
44 | p = &wh->pool[i]; | 44 | p = &wh->pool[i]; |
45 | if (cmp[1] == p->cmp[1] && cmp[0] == p->cmp[0]) { | 45 | if (cmp[1] == p->cmp[1] && cmp[0] == p->cmp[0]) { |
46 | if (p->ip == 0) { | 46 | if (p->ip == 0) { |
47 | return 1; | 47 | return 1; |
48 | } | 48 | } |
49 | } | 49 | } |
50 | } | 50 | } |
51 | } | 51 | } |
52 | return 0; | 52 | return 0; |
53 | } | 53 | } |
54 | 54 | ||
55 | static int ebt_mac_wormhash_check_integrity(const struct ebt_mac_wormhash | 55 | static int ebt_mac_wormhash_check_integrity(const struct ebt_mac_wormhash |
56 | *wh) | 56 | *wh) |
57 | { | 57 | { |
58 | int i; | 58 | int i; |
59 | 59 | ||
60 | for (i = 0; i < 256; i++) { | 60 | for (i = 0; i < 256; i++) { |
61 | if (wh->table[i] > wh->table[i + 1]) | 61 | if (wh->table[i] > wh->table[i + 1]) |
62 | return -0x100 - i; | 62 | return -0x100 - i; |
63 | if (wh->table[i] < 0) | 63 | if (wh->table[i] < 0) |
64 | return -0x200 - i; | 64 | return -0x200 - i; |
65 | if (wh->table[i] > wh->poolsize) | 65 | if (wh->table[i] > wh->poolsize) |
66 | return -0x300 - i; | 66 | return -0x300 - i; |
67 | } | 67 | } |
68 | if (wh->table[256] > wh->poolsize) | 68 | if (wh->table[256] > wh->poolsize) |
69 | return -0xc00; | 69 | return -0xc00; |
70 | return 0; | 70 | return 0; |
71 | } | 71 | } |
72 | 72 | ||
73 | static int get_ip_dst(const struct sk_buff *skb, __be32 *addr) | 73 | static int get_ip_dst(const struct sk_buff *skb, __be32 *addr) |
74 | { | 74 | { |
75 | if (eth_hdr(skb)->h_proto == htons(ETH_P_IP)) { | 75 | if (eth_hdr(skb)->h_proto == htons(ETH_P_IP)) { |
76 | const struct iphdr *ih; | 76 | const struct iphdr *ih; |
77 | struct iphdr _iph; | 77 | struct iphdr _iph; |
78 | 78 | ||
79 | ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph); | 79 | ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph); |
80 | if (ih == NULL) | 80 | if (ih == NULL) |
81 | return -1; | 81 | return -1; |
82 | *addr = ih->daddr; | 82 | *addr = ih->daddr; |
83 | } else if (eth_hdr(skb)->h_proto == htons(ETH_P_ARP)) { | 83 | } else if (eth_hdr(skb)->h_proto == htons(ETH_P_ARP)) { |
84 | const struct arphdr *ah; | 84 | const struct arphdr *ah; |
85 | struct arphdr _arph; | 85 | struct arphdr _arph; |
86 | const __be32 *bp; | 86 | const __be32 *bp; |
87 | __be32 buf; | 87 | __be32 buf; |
88 | 88 | ||
89 | ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph); | 89 | ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph); |
90 | if (ah == NULL || | 90 | if (ah == NULL || |
91 | ah->ar_pln != sizeof(__be32) || | 91 | ah->ar_pln != sizeof(__be32) || |
92 | ah->ar_hln != ETH_ALEN) | 92 | ah->ar_hln != ETH_ALEN) |
93 | return -1; | 93 | return -1; |
94 | bp = skb_header_pointer(skb, sizeof(struct arphdr) + | 94 | bp = skb_header_pointer(skb, sizeof(struct arphdr) + |
95 | 2 * ETH_ALEN + sizeof(__be32), | 95 | 2 * ETH_ALEN + sizeof(__be32), |
96 | sizeof(__be32), &buf); | 96 | sizeof(__be32), &buf); |
97 | if (bp == NULL) | 97 | if (bp == NULL) |
98 | return -1; | 98 | return -1; |
99 | *addr = *bp; | 99 | *addr = *bp; |
100 | } | 100 | } |
101 | return 0; | 101 | return 0; |
102 | } | 102 | } |
103 | 103 | ||
104 | static int get_ip_src(const struct sk_buff *skb, __be32 *addr) | 104 | static int get_ip_src(const struct sk_buff *skb, __be32 *addr) |
105 | { | 105 | { |
106 | if (eth_hdr(skb)->h_proto == htons(ETH_P_IP)) { | 106 | if (eth_hdr(skb)->h_proto == htons(ETH_P_IP)) { |
107 | const struct iphdr *ih; | 107 | const struct iphdr *ih; |
108 | struct iphdr _iph; | 108 | struct iphdr _iph; |
109 | 109 | ||
110 | ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph); | 110 | ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph); |
111 | if (ih == NULL) | 111 | if (ih == NULL) |
112 | return -1; | 112 | return -1; |
113 | *addr = ih->saddr; | 113 | *addr = ih->saddr; |
114 | } else if (eth_hdr(skb)->h_proto == htons(ETH_P_ARP)) { | 114 | } else if (eth_hdr(skb)->h_proto == htons(ETH_P_ARP)) { |
115 | const struct arphdr *ah; | 115 | const struct arphdr *ah; |
116 | struct arphdr _arph; | 116 | struct arphdr _arph; |
117 | const __be32 *bp; | 117 | const __be32 *bp; |
118 | __be32 buf; | 118 | __be32 buf; |
119 | 119 | ||
120 | ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph); | 120 | ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph); |
121 | if (ah == NULL || | 121 | if (ah == NULL || |
122 | ah->ar_pln != sizeof(__be32) || | 122 | ah->ar_pln != sizeof(__be32) || |
123 | ah->ar_hln != ETH_ALEN) | 123 | ah->ar_hln != ETH_ALEN) |
124 | return -1; | 124 | return -1; |
125 | bp = skb_header_pointer(skb, sizeof(struct arphdr) + | 125 | bp = skb_header_pointer(skb, sizeof(struct arphdr) + |
126 | ETH_ALEN, sizeof(__be32), &buf); | 126 | ETH_ALEN, sizeof(__be32), &buf); |
127 | if (bp == NULL) | 127 | if (bp == NULL) |
128 | return -1; | 128 | return -1; |
129 | *addr = *bp; | 129 | *addr = *bp; |
130 | } | 130 | } |
131 | return 0; | 131 | return 0; |
132 | } | 132 | } |
133 | 133 | ||
134 | static int ebt_filter_among(const struct sk_buff *skb, | 134 | static int ebt_filter_among(const struct sk_buff *skb, |
135 | const struct net_device *in, | 135 | const struct net_device *in, |
136 | const struct net_device *out, const void *data, | 136 | const struct net_device *out, const void *data, |
137 | unsigned int datalen) | 137 | unsigned int datalen) |
138 | { | 138 | { |
139 | const struct ebt_among_info *info = data; | 139 | const struct ebt_among_info *info = data; |
140 | const char *dmac, *smac; | 140 | const char *dmac, *smac; |
141 | const struct ebt_mac_wormhash *wh_dst, *wh_src; | 141 | const struct ebt_mac_wormhash *wh_dst, *wh_src; |
142 | __be32 dip = 0, sip = 0; | 142 | __be32 dip = 0, sip = 0; |
143 | 143 | ||
144 | wh_dst = ebt_among_wh_dst(info); | 144 | wh_dst = ebt_among_wh_dst(info); |
145 | wh_src = ebt_among_wh_src(info); | 145 | wh_src = ebt_among_wh_src(info); |
146 | 146 | ||
147 | if (wh_src) { | 147 | if (wh_src) { |
148 | smac = eth_hdr(skb)->h_source; | 148 | smac = eth_hdr(skb)->h_source; |
149 | if (get_ip_src(skb, &sip)) | 149 | if (get_ip_src(skb, &sip)) |
150 | return EBT_NOMATCH; | 150 | return EBT_NOMATCH; |
151 | if (!(info->bitmask & EBT_AMONG_SRC_NEG)) { | 151 | if (!(info->bitmask & EBT_AMONG_SRC_NEG)) { |
152 | /* we match only if it contains */ | 152 | /* we match only if it contains */ |
153 | if (!ebt_mac_wormhash_contains(wh_src, smac, sip)) | 153 | if (!ebt_mac_wormhash_contains(wh_src, smac, sip)) |
154 | return EBT_NOMATCH; | 154 | return EBT_NOMATCH; |
155 | } else { | 155 | } else { |
156 | /* we match only if it DOES NOT contain */ | 156 | /* we match only if it DOES NOT contain */ |
157 | if (ebt_mac_wormhash_contains(wh_src, smac, sip)) | 157 | if (ebt_mac_wormhash_contains(wh_src, smac, sip)) |
158 | return EBT_NOMATCH; | 158 | return EBT_NOMATCH; |
159 | } | 159 | } |
160 | } | 160 | } |
161 | 161 | ||
162 | if (wh_dst) { | 162 | if (wh_dst) { |
163 | dmac = eth_hdr(skb)->h_dest; | 163 | dmac = eth_hdr(skb)->h_dest; |
164 | if (get_ip_dst(skb, &dip)) | 164 | if (get_ip_dst(skb, &dip)) |
165 | return EBT_NOMATCH; | 165 | return EBT_NOMATCH; |
166 | if (!(info->bitmask & EBT_AMONG_DST_NEG)) { | 166 | if (!(info->bitmask & EBT_AMONG_DST_NEG)) { |
167 | /* we match only if it contains */ | 167 | /* we match only if it contains */ |
168 | if (!ebt_mac_wormhash_contains(wh_dst, dmac, dip)) | 168 | if (!ebt_mac_wormhash_contains(wh_dst, dmac, dip)) |
169 | return EBT_NOMATCH; | 169 | return EBT_NOMATCH; |
170 | } else { | 170 | } else { |
171 | /* we match only if it DOES NOT contain */ | 171 | /* we match only if it DOES NOT contain */ |
172 | if (ebt_mac_wormhash_contains(wh_dst, dmac, dip)) | 172 | if (ebt_mac_wormhash_contains(wh_dst, dmac, dip)) |
173 | return EBT_NOMATCH; | 173 | return EBT_NOMATCH; |
174 | } | 174 | } |
175 | } | 175 | } |
176 | 176 | ||
177 | return EBT_MATCH; | 177 | return EBT_MATCH; |
178 | } | 178 | } |
179 | 179 | ||
180 | static int ebt_among_check(const char *tablename, unsigned int hookmask, | 180 | static bool |
181 | const struct ebt_entry *e, void *data, | 181 | ebt_among_check(const char *tablename, unsigned int hookmask, |
182 | unsigned int datalen) | 182 | const struct ebt_entry *e, void *data, |
183 | unsigned int datalen) | ||
183 | { | 184 | { |
184 | const struct ebt_among_info *info = data; | 185 | const struct ebt_among_info *info = data; |
185 | int expected_length = sizeof(struct ebt_among_info); | 186 | int expected_length = sizeof(struct ebt_among_info); |
186 | const struct ebt_mac_wormhash *wh_dst, *wh_src; | 187 | const struct ebt_mac_wormhash *wh_dst, *wh_src; |
187 | int err; | 188 | int err; |
188 | 189 | ||
189 | wh_dst = ebt_among_wh_dst(info); | 190 | wh_dst = ebt_among_wh_dst(info); |
190 | wh_src = ebt_among_wh_src(info); | 191 | wh_src = ebt_among_wh_src(info); |
191 | expected_length += ebt_mac_wormhash_size(wh_dst); | 192 | expected_length += ebt_mac_wormhash_size(wh_dst); |
192 | expected_length += ebt_mac_wormhash_size(wh_src); | 193 | expected_length += ebt_mac_wormhash_size(wh_src); |
193 | 194 | ||
194 | if (datalen != EBT_ALIGN(expected_length)) { | 195 | if (datalen != EBT_ALIGN(expected_length)) { |
195 | printk(KERN_WARNING | 196 | printk(KERN_WARNING |
196 | "ebtables: among: wrong size: %d " | 197 | "ebtables: among: wrong size: %d " |
197 | "against expected %d, rounded to %Zd\n", | 198 | "against expected %d, rounded to %Zd\n", |
198 | datalen, expected_length, | 199 | datalen, expected_length, |
199 | EBT_ALIGN(expected_length)); | 200 | EBT_ALIGN(expected_length)); |
200 | return -EINVAL; | 201 | return false; |
201 | } | 202 | } |
202 | if (wh_dst && (err = ebt_mac_wormhash_check_integrity(wh_dst))) { | 203 | if (wh_dst && (err = ebt_mac_wormhash_check_integrity(wh_dst))) { |
203 | printk(KERN_WARNING | 204 | printk(KERN_WARNING |
204 | "ebtables: among: dst integrity fail: %x\n", -err); | 205 | "ebtables: among: dst integrity fail: %x\n", -err); |
205 | return -EINVAL; | 206 | return false; |
206 | } | 207 | } |
207 | if (wh_src && (err = ebt_mac_wormhash_check_integrity(wh_src))) { | 208 | if (wh_src && (err = ebt_mac_wormhash_check_integrity(wh_src))) { |
208 | printk(KERN_WARNING | 209 | printk(KERN_WARNING |
209 | "ebtables: among: src integrity fail: %x\n", -err); | 210 | "ebtables: among: src integrity fail: %x\n", -err); |
210 | return -EINVAL; | 211 | return false; |
211 | } | 212 | } |
212 | return 0; | 213 | return true; |
213 | } | 214 | } |
214 | 215 | ||
215 | static struct ebt_match filter_among __read_mostly = { | 216 | static struct ebt_match filter_among __read_mostly = { |
216 | .name = EBT_AMONG_MATCH, | 217 | .name = EBT_AMONG_MATCH, |
217 | .match = ebt_filter_among, | 218 | .match = ebt_filter_among, |
218 | .check = ebt_among_check, | 219 | .check = ebt_among_check, |
219 | .matchsize = -1, /* special case */ | 220 | .matchsize = -1, /* special case */ |
220 | .me = THIS_MODULE, | 221 | .me = THIS_MODULE, |
221 | }; | 222 | }; |
222 | 223 | ||
223 | static int __init ebt_among_init(void) | 224 | static int __init ebt_among_init(void) |
224 | { | 225 | { |
225 | return ebt_register_match(&filter_among); | 226 | return ebt_register_match(&filter_among); |
226 | } | 227 | } |
227 | 228 | ||
228 | static void __exit ebt_among_fini(void) | 229 | static void __exit ebt_among_fini(void) |
229 | { | 230 | { |
230 | ebt_unregister_match(&filter_among); | 231 | ebt_unregister_match(&filter_among); |
231 | } | 232 | } |
232 | 233 | ||
233 | module_init(ebt_among_init); | 234 | module_init(ebt_among_init); |
234 | module_exit(ebt_among_fini); | 235 | module_exit(ebt_among_fini); |
235 | MODULE_DESCRIPTION("Ebtables: Combined MAC/IP address list matching"); | 236 | MODULE_DESCRIPTION("Ebtables: Combined MAC/IP address list matching"); |
236 | MODULE_LICENSE("GPL"); | 237 | MODULE_LICENSE("GPL"); |
237 | 238 |
net/bridge/netfilter/ebt_arp.c
1 | /* | 1 | /* |
2 | * ebt_arp | 2 | * ebt_arp |
3 | * | 3 | * |
4 | * Authors: | 4 | * Authors: |
5 | * Bart De Schuymer <bdschuym@pandora.be> | 5 | * Bart De Schuymer <bdschuym@pandora.be> |
6 | * Tim Gardner <timg@tpi.com> | 6 | * Tim Gardner <timg@tpi.com> |
7 | * | 7 | * |
8 | * April, 2002 | 8 | * April, 2002 |
9 | * | 9 | * |
10 | */ | 10 | */ |
11 | #include <linux/if_arp.h> | 11 | #include <linux/if_arp.h> |
12 | #include <linux/if_ether.h> | 12 | #include <linux/if_ether.h> |
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/netfilter/x_tables.h> | 14 | #include <linux/netfilter/x_tables.h> |
15 | #include <linux/netfilter_bridge/ebtables.h> | 15 | #include <linux/netfilter_bridge/ebtables.h> |
16 | #include <linux/netfilter_bridge/ebt_arp.h> | 16 | #include <linux/netfilter_bridge/ebt_arp.h> |
17 | 17 | ||
18 | static int ebt_filter_arp(const struct sk_buff *skb, const struct net_device *in, | 18 | static int ebt_filter_arp(const struct sk_buff *skb, const struct net_device *in, |
19 | const struct net_device *out, const void *data, unsigned int datalen) | 19 | const struct net_device *out, const void *data, unsigned int datalen) |
20 | { | 20 | { |
21 | const struct ebt_arp_info *info = data; | 21 | const struct ebt_arp_info *info = data; |
22 | const struct arphdr *ah; | 22 | const struct arphdr *ah; |
23 | struct arphdr _arph; | 23 | struct arphdr _arph; |
24 | 24 | ||
25 | ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph); | 25 | ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph); |
26 | if (ah == NULL) | 26 | if (ah == NULL) |
27 | return EBT_NOMATCH; | 27 | return EBT_NOMATCH; |
28 | if (info->bitmask & EBT_ARP_OPCODE && FWINV(info->opcode != | 28 | if (info->bitmask & EBT_ARP_OPCODE && FWINV(info->opcode != |
29 | ah->ar_op, EBT_ARP_OPCODE)) | 29 | ah->ar_op, EBT_ARP_OPCODE)) |
30 | return EBT_NOMATCH; | 30 | return EBT_NOMATCH; |
31 | if (info->bitmask & EBT_ARP_HTYPE && FWINV(info->htype != | 31 | if (info->bitmask & EBT_ARP_HTYPE && FWINV(info->htype != |
32 | ah->ar_hrd, EBT_ARP_HTYPE)) | 32 | ah->ar_hrd, EBT_ARP_HTYPE)) |
33 | return EBT_NOMATCH; | 33 | return EBT_NOMATCH; |
34 | if (info->bitmask & EBT_ARP_PTYPE && FWINV(info->ptype != | 34 | if (info->bitmask & EBT_ARP_PTYPE && FWINV(info->ptype != |
35 | ah->ar_pro, EBT_ARP_PTYPE)) | 35 | ah->ar_pro, EBT_ARP_PTYPE)) |
36 | return EBT_NOMATCH; | 36 | return EBT_NOMATCH; |
37 | 37 | ||
38 | if (info->bitmask & (EBT_ARP_SRC_IP | EBT_ARP_DST_IP | EBT_ARP_GRAT)) { | 38 | if (info->bitmask & (EBT_ARP_SRC_IP | EBT_ARP_DST_IP | EBT_ARP_GRAT)) { |
39 | const __be32 *sap, *dap; | 39 | const __be32 *sap, *dap; |
40 | __be32 saddr, daddr; | 40 | __be32 saddr, daddr; |
41 | 41 | ||
42 | if (ah->ar_pln != sizeof(__be32) || ah->ar_pro != htons(ETH_P_IP)) | 42 | if (ah->ar_pln != sizeof(__be32) || ah->ar_pro != htons(ETH_P_IP)) |
43 | return EBT_NOMATCH; | 43 | return EBT_NOMATCH; |
44 | sap = skb_header_pointer(skb, sizeof(struct arphdr) + | 44 | sap = skb_header_pointer(skb, sizeof(struct arphdr) + |
45 | ah->ar_hln, sizeof(saddr), | 45 | ah->ar_hln, sizeof(saddr), |
46 | &saddr); | 46 | &saddr); |
47 | if (sap == NULL) | 47 | if (sap == NULL) |
48 | return EBT_NOMATCH; | 48 | return EBT_NOMATCH; |
49 | dap = skb_header_pointer(skb, sizeof(struct arphdr) + | 49 | dap = skb_header_pointer(skb, sizeof(struct arphdr) + |
50 | 2*ah->ar_hln+sizeof(saddr), | 50 | 2*ah->ar_hln+sizeof(saddr), |
51 | sizeof(daddr), &daddr); | 51 | sizeof(daddr), &daddr); |
52 | if (dap == NULL) | 52 | if (dap == NULL) |
53 | return EBT_NOMATCH; | 53 | return EBT_NOMATCH; |
54 | if (info->bitmask & EBT_ARP_SRC_IP && | 54 | if (info->bitmask & EBT_ARP_SRC_IP && |
55 | FWINV(info->saddr != (*sap & info->smsk), EBT_ARP_SRC_IP)) | 55 | FWINV(info->saddr != (*sap & info->smsk), EBT_ARP_SRC_IP)) |
56 | return EBT_NOMATCH; | 56 | return EBT_NOMATCH; |
57 | if (info->bitmask & EBT_ARP_DST_IP && | 57 | if (info->bitmask & EBT_ARP_DST_IP && |
58 | FWINV(info->daddr != (*dap & info->dmsk), EBT_ARP_DST_IP)) | 58 | FWINV(info->daddr != (*dap & info->dmsk), EBT_ARP_DST_IP)) |
59 | return EBT_NOMATCH; | 59 | return EBT_NOMATCH; |
60 | if (info->bitmask & EBT_ARP_GRAT && | 60 | if (info->bitmask & EBT_ARP_GRAT && |
61 | FWINV(*dap != *sap, EBT_ARP_GRAT)) | 61 | FWINV(*dap != *sap, EBT_ARP_GRAT)) |
62 | return EBT_NOMATCH; | 62 | return EBT_NOMATCH; |
63 | } | 63 | } |
64 | 64 | ||
65 | if (info->bitmask & (EBT_ARP_SRC_MAC | EBT_ARP_DST_MAC)) { | 65 | if (info->bitmask & (EBT_ARP_SRC_MAC | EBT_ARP_DST_MAC)) { |
66 | const unsigned char *mp; | 66 | const unsigned char *mp; |
67 | unsigned char _mac[ETH_ALEN]; | 67 | unsigned char _mac[ETH_ALEN]; |
68 | uint8_t verdict, i; | 68 | uint8_t verdict, i; |
69 | 69 | ||
70 | if (ah->ar_hln != ETH_ALEN || ah->ar_hrd != htons(ARPHRD_ETHER)) | 70 | if (ah->ar_hln != ETH_ALEN || ah->ar_hrd != htons(ARPHRD_ETHER)) |
71 | return EBT_NOMATCH; | 71 | return EBT_NOMATCH; |
72 | if (info->bitmask & EBT_ARP_SRC_MAC) { | 72 | if (info->bitmask & EBT_ARP_SRC_MAC) { |
73 | mp = skb_header_pointer(skb, sizeof(struct arphdr), | 73 | mp = skb_header_pointer(skb, sizeof(struct arphdr), |
74 | sizeof(_mac), &_mac); | 74 | sizeof(_mac), &_mac); |
75 | if (mp == NULL) | 75 | if (mp == NULL) |
76 | return EBT_NOMATCH; | 76 | return EBT_NOMATCH; |
77 | verdict = 0; | 77 | verdict = 0; |
78 | for (i = 0; i < 6; i++) | 78 | for (i = 0; i < 6; i++) |
79 | verdict |= (mp[i] ^ info->smaddr[i]) & | 79 | verdict |= (mp[i] ^ info->smaddr[i]) & |
80 | info->smmsk[i]; | 80 | info->smmsk[i]; |
81 | if (FWINV(verdict != 0, EBT_ARP_SRC_MAC)) | 81 | if (FWINV(verdict != 0, EBT_ARP_SRC_MAC)) |
82 | return EBT_NOMATCH; | 82 | return EBT_NOMATCH; |
83 | } | 83 | } |
84 | 84 | ||
85 | if (info->bitmask & EBT_ARP_DST_MAC) { | 85 | if (info->bitmask & EBT_ARP_DST_MAC) { |
86 | mp = skb_header_pointer(skb, sizeof(struct arphdr) + | 86 | mp = skb_header_pointer(skb, sizeof(struct arphdr) + |
87 | ah->ar_hln + ah->ar_pln, | 87 | ah->ar_hln + ah->ar_pln, |
88 | sizeof(_mac), &_mac); | 88 | sizeof(_mac), &_mac); |
89 | if (mp == NULL) | 89 | if (mp == NULL) |
90 | return EBT_NOMATCH; | 90 | return EBT_NOMATCH; |
91 | verdict = 0; | 91 | verdict = 0; |
92 | for (i = 0; i < 6; i++) | 92 | for (i = 0; i < 6; i++) |
93 | verdict |= (mp[i] ^ info->dmaddr[i]) & | 93 | verdict |= (mp[i] ^ info->dmaddr[i]) & |
94 | info->dmmsk[i]; | 94 | info->dmmsk[i]; |
95 | if (FWINV(verdict != 0, EBT_ARP_DST_MAC)) | 95 | if (FWINV(verdict != 0, EBT_ARP_DST_MAC)) |
96 | return EBT_NOMATCH; | 96 | return EBT_NOMATCH; |
97 | } | 97 | } |
98 | } | 98 | } |
99 | 99 | ||
100 | return EBT_MATCH; | 100 | return EBT_MATCH; |
101 | } | 101 | } |
102 | 102 | ||
103 | static int ebt_arp_check(const char *tablename, unsigned int hookmask, | 103 | static bool ebt_arp_check(const char *tablename, unsigned int hookmask, |
104 | const struct ebt_entry *e, void *data, unsigned int datalen) | 104 | const struct ebt_entry *e, void *data, unsigned int datalen) |
105 | { | 105 | { |
106 | const struct ebt_arp_info *info = data; | 106 | const struct ebt_arp_info *info = data; |
107 | 107 | ||
108 | if ((e->ethproto != htons(ETH_P_ARP) && | 108 | if ((e->ethproto != htons(ETH_P_ARP) && |
109 | e->ethproto != htons(ETH_P_RARP)) || | 109 | e->ethproto != htons(ETH_P_RARP)) || |
110 | e->invflags & EBT_IPROTO) | 110 | e->invflags & EBT_IPROTO) |
111 | return -EINVAL; | 111 | return false; |
112 | if (info->bitmask & ~EBT_ARP_MASK || info->invflags & ~EBT_ARP_MASK) | 112 | if (info->bitmask & ~EBT_ARP_MASK || info->invflags & ~EBT_ARP_MASK) |
113 | return -EINVAL; | 113 | return false; |
114 | return 0; | 114 | return true; |
115 | } | 115 | } |
116 | 116 | ||
117 | static struct ebt_match filter_arp __read_mostly = { | 117 | static struct ebt_match filter_arp __read_mostly = { |
118 | .name = EBT_ARP_MATCH, | 118 | .name = EBT_ARP_MATCH, |
119 | .match = ebt_filter_arp, | 119 | .match = ebt_filter_arp, |
120 | .check = ebt_arp_check, | 120 | .check = ebt_arp_check, |
121 | .matchsize = XT_ALIGN(sizeof(struct ebt_arp_info)), | 121 | .matchsize = XT_ALIGN(sizeof(struct ebt_arp_info)), |
122 | .me = THIS_MODULE, | 122 | .me = THIS_MODULE, |
123 | }; | 123 | }; |
124 | 124 | ||
125 | static int __init ebt_arp_init(void) | 125 | static int __init ebt_arp_init(void) |
126 | { | 126 | { |
127 | return ebt_register_match(&filter_arp); | 127 | return ebt_register_match(&filter_arp); |
128 | } | 128 | } |
129 | 129 | ||
130 | static void __exit ebt_arp_fini(void) | 130 | static void __exit ebt_arp_fini(void) |
131 | { | 131 | { |
132 | ebt_unregister_match(&filter_arp); | 132 | ebt_unregister_match(&filter_arp); |
133 | } | 133 | } |
134 | 134 | ||
135 | module_init(ebt_arp_init); | 135 | module_init(ebt_arp_init); |
136 | module_exit(ebt_arp_fini); | 136 | module_exit(ebt_arp_fini); |
137 | MODULE_DESCRIPTION("Ebtables: ARP protocol packet match"); | 137 | MODULE_DESCRIPTION("Ebtables: ARP protocol packet match"); |
138 | MODULE_LICENSE("GPL"); | 138 | MODULE_LICENSE("GPL"); |
139 | 139 |
net/bridge/netfilter/ebt_arpreply.c
1 | /* | 1 | /* |
2 | * ebt_arpreply | 2 | * ebt_arpreply |
3 | * | 3 | * |
4 | * Authors: | 4 | * Authors: |
5 | * Grzegorz Borowiak <grzes@gnu.univ.gda.pl> | 5 | * Grzegorz Borowiak <grzes@gnu.univ.gda.pl> |
6 | * Bart De Schuymer <bdschuym@pandora.be> | 6 | * Bart De Schuymer <bdschuym@pandora.be> |
7 | * | 7 | * |
8 | * August, 2003 | 8 | * August, 2003 |
9 | * | 9 | * |
10 | */ | 10 | */ |
11 | #include <linux/if_arp.h> | 11 | #include <linux/if_arp.h> |
12 | #include <net/arp.h> | 12 | #include <net/arp.h> |
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/netfilter/x_tables.h> | 14 | #include <linux/netfilter/x_tables.h> |
15 | #include <linux/netfilter_bridge/ebtables.h> | 15 | #include <linux/netfilter_bridge/ebtables.h> |
16 | #include <linux/netfilter_bridge/ebt_arpreply.h> | 16 | #include <linux/netfilter_bridge/ebt_arpreply.h> |
17 | 17 | ||
18 | static int ebt_target_reply(struct sk_buff *skb, unsigned int hooknr, | 18 | static int ebt_target_reply(struct sk_buff *skb, unsigned int hooknr, |
19 | const struct net_device *in, const struct net_device *out, | 19 | const struct net_device *in, const struct net_device *out, |
20 | const void *data, unsigned int datalen) | 20 | const void *data, unsigned int datalen) |
21 | { | 21 | { |
22 | struct ebt_arpreply_info *info = (void *)data; | 22 | struct ebt_arpreply_info *info = (void *)data; |
23 | const __be32 *siptr, *diptr; | 23 | const __be32 *siptr, *diptr; |
24 | __be32 _sip, _dip; | 24 | __be32 _sip, _dip; |
25 | const struct arphdr *ap; | 25 | const struct arphdr *ap; |
26 | struct arphdr _ah; | 26 | struct arphdr _ah; |
27 | const unsigned char *shp; | 27 | const unsigned char *shp; |
28 | unsigned char _sha[ETH_ALEN]; | 28 | unsigned char _sha[ETH_ALEN]; |
29 | 29 | ||
30 | ap = skb_header_pointer(skb, 0, sizeof(_ah), &_ah); | 30 | ap = skb_header_pointer(skb, 0, sizeof(_ah), &_ah); |
31 | if (ap == NULL) | 31 | if (ap == NULL) |
32 | return EBT_DROP; | 32 | return EBT_DROP; |
33 | 33 | ||
34 | if (ap->ar_op != htons(ARPOP_REQUEST) || | 34 | if (ap->ar_op != htons(ARPOP_REQUEST) || |
35 | ap->ar_hln != ETH_ALEN || | 35 | ap->ar_hln != ETH_ALEN || |
36 | ap->ar_pro != htons(ETH_P_IP) || | 36 | ap->ar_pro != htons(ETH_P_IP) || |
37 | ap->ar_pln != 4) | 37 | ap->ar_pln != 4) |
38 | return EBT_CONTINUE; | 38 | return EBT_CONTINUE; |
39 | 39 | ||
40 | shp = skb_header_pointer(skb, sizeof(_ah), ETH_ALEN, &_sha); | 40 | shp = skb_header_pointer(skb, sizeof(_ah), ETH_ALEN, &_sha); |
41 | if (shp == NULL) | 41 | if (shp == NULL) |
42 | return EBT_DROP; | 42 | return EBT_DROP; |
43 | 43 | ||
44 | siptr = skb_header_pointer(skb, sizeof(_ah) + ETH_ALEN, | 44 | siptr = skb_header_pointer(skb, sizeof(_ah) + ETH_ALEN, |
45 | sizeof(_sip), &_sip); | 45 | sizeof(_sip), &_sip); |
46 | if (siptr == NULL) | 46 | if (siptr == NULL) |
47 | return EBT_DROP; | 47 | return EBT_DROP; |
48 | 48 | ||
49 | diptr = skb_header_pointer(skb, | 49 | diptr = skb_header_pointer(skb, |
50 | sizeof(_ah) + 2 * ETH_ALEN + sizeof(_sip), | 50 | sizeof(_ah) + 2 * ETH_ALEN + sizeof(_sip), |
51 | sizeof(_dip), &_dip); | 51 | sizeof(_dip), &_dip); |
52 | if (diptr == NULL) | 52 | if (diptr == NULL) |
53 | return EBT_DROP; | 53 | return EBT_DROP; |
54 | 54 | ||
55 | arp_send(ARPOP_REPLY, ETH_P_ARP, *siptr, (struct net_device *)in, | 55 | arp_send(ARPOP_REPLY, ETH_P_ARP, *siptr, (struct net_device *)in, |
56 | *diptr, shp, info->mac, shp); | 56 | *diptr, shp, info->mac, shp); |
57 | 57 | ||
58 | return info->target; | 58 | return info->target; |
59 | } | 59 | } |
60 | 60 | ||
61 | static int ebt_target_reply_check(const char *tablename, unsigned int hookmask, | 61 | static bool ebt_target_reply_check(const char *tablename, unsigned int hookmask, |
62 | const struct ebt_entry *e, void *data, unsigned int datalen) | 62 | const struct ebt_entry *e, void *data, unsigned int datalen) |
63 | { | 63 | { |
64 | const struct ebt_arpreply_info *info = data; | 64 | const struct ebt_arpreply_info *info = data; |
65 | 65 | ||
66 | if (BASE_CHAIN && info->target == EBT_RETURN) | 66 | if (BASE_CHAIN && info->target == EBT_RETURN) |
67 | return -EINVAL; | 67 | return false; |
68 | if (e->ethproto != htons(ETH_P_ARP) || | 68 | if (e->ethproto != htons(ETH_P_ARP) || |
69 | e->invflags & EBT_IPROTO) | 69 | e->invflags & EBT_IPROTO) |
70 | return -EINVAL; | 70 | return false; |
71 | CLEAR_BASE_CHAIN_BIT; | 71 | CLEAR_BASE_CHAIN_BIT; |
72 | if (strcmp(tablename, "nat") || hookmask & ~(1 << NF_BR_PRE_ROUTING)) | 72 | if (strcmp(tablename, "nat") || hookmask & ~(1 << NF_BR_PRE_ROUTING)) |
73 | return -EINVAL; | 73 | return false; |
74 | return 0; | 74 | return true; |
75 | } | 75 | } |
76 | 76 | ||
77 | static struct ebt_target reply_target __read_mostly = { | 77 | static struct ebt_target reply_target __read_mostly = { |
78 | .name = EBT_ARPREPLY_TARGET, | 78 | .name = EBT_ARPREPLY_TARGET, |
79 | .target = ebt_target_reply, | 79 | .target = ebt_target_reply, |
80 | .check = ebt_target_reply_check, | 80 | .check = ebt_target_reply_check, |
81 | .targetsize = XT_ALIGN(sizeof(struct ebt_arpreply_info)), | 81 | .targetsize = XT_ALIGN(sizeof(struct ebt_arpreply_info)), |
82 | .me = THIS_MODULE, | 82 | .me = THIS_MODULE, |
83 | }; | 83 | }; |
84 | 84 | ||
85 | static int __init ebt_arpreply_init(void) | 85 | static int __init ebt_arpreply_init(void) |
86 | { | 86 | { |
87 | return ebt_register_target(&reply_target); | 87 | return ebt_register_target(&reply_target); |
88 | } | 88 | } |
89 | 89 | ||
90 | static void __exit ebt_arpreply_fini(void) | 90 | static void __exit ebt_arpreply_fini(void) |
91 | { | 91 | { |
92 | ebt_unregister_target(&reply_target); | 92 | ebt_unregister_target(&reply_target); |
93 | } | 93 | } |
94 | 94 | ||
95 | module_init(ebt_arpreply_init); | 95 | module_init(ebt_arpreply_init); |
96 | module_exit(ebt_arpreply_fini); | 96 | module_exit(ebt_arpreply_fini); |
97 | MODULE_DESCRIPTION("Ebtables: ARP reply target"); | 97 | MODULE_DESCRIPTION("Ebtables: ARP reply target"); |
98 | MODULE_LICENSE("GPL"); | 98 | MODULE_LICENSE("GPL"); |
99 | 99 |
net/bridge/netfilter/ebt_dnat.c
1 | /* | 1 | /* |
2 | * ebt_dnat | 2 | * ebt_dnat |
3 | * | 3 | * |
4 | * Authors: | 4 | * Authors: |
5 | * Bart De Schuymer <bdschuym@pandora.be> | 5 | * Bart De Schuymer <bdschuym@pandora.be> |
6 | * | 6 | * |
7 | * June, 2002 | 7 | * June, 2002 |
8 | * | 8 | * |
9 | */ | 9 | */ |
10 | #include <linux/module.h> | 10 | #include <linux/module.h> |
11 | #include <net/sock.h> | 11 | #include <net/sock.h> |
12 | #include <linux/netfilter.h> | 12 | #include <linux/netfilter.h> |
13 | #include <linux/netfilter/x_tables.h> | 13 | #include <linux/netfilter/x_tables.h> |
14 | #include <linux/netfilter_bridge/ebtables.h> | 14 | #include <linux/netfilter_bridge/ebtables.h> |
15 | #include <linux/netfilter_bridge/ebt_nat.h> | 15 | #include <linux/netfilter_bridge/ebt_nat.h> |
16 | 16 | ||
17 | static int ebt_target_dnat(struct sk_buff *skb, unsigned int hooknr, | 17 | static int ebt_target_dnat(struct sk_buff *skb, unsigned int hooknr, |
18 | const struct net_device *in, const struct net_device *out, | 18 | const struct net_device *in, const struct net_device *out, |
19 | const void *data, unsigned int datalen) | 19 | const void *data, unsigned int datalen) |
20 | { | 20 | { |
21 | const struct ebt_nat_info *info = data; | 21 | const struct ebt_nat_info *info = data; |
22 | 22 | ||
23 | if (!skb_make_writable(skb, 0)) | 23 | if (!skb_make_writable(skb, 0)) |
24 | return EBT_DROP; | 24 | return EBT_DROP; |
25 | 25 | ||
26 | memcpy(eth_hdr(skb)->h_dest, info->mac, ETH_ALEN); | 26 | memcpy(eth_hdr(skb)->h_dest, info->mac, ETH_ALEN); |
27 | return info->target; | 27 | return info->target; |
28 | } | 28 | } |
29 | 29 | ||
30 | static int ebt_target_dnat_check(const char *tablename, unsigned int hookmask, | 30 | static bool ebt_target_dnat_check(const char *tablename, unsigned int hookmask, |
31 | const struct ebt_entry *e, void *data, unsigned int datalen) | 31 | const struct ebt_entry *e, void *data, unsigned int datalen) |
32 | { | 32 | { |
33 | const struct ebt_nat_info *info = data; | 33 | const struct ebt_nat_info *info = data; |
34 | 34 | ||
35 | if (BASE_CHAIN && info->target == EBT_RETURN) | 35 | if (BASE_CHAIN && info->target == EBT_RETURN) |
36 | return -EINVAL; | 36 | return false; |
37 | CLEAR_BASE_CHAIN_BIT; | 37 | CLEAR_BASE_CHAIN_BIT; |
38 | if ( (strcmp(tablename, "nat") || | 38 | if ( (strcmp(tablename, "nat") || |
39 | (hookmask & ~((1 << NF_BR_PRE_ROUTING) | (1 << NF_BR_LOCAL_OUT)))) && | 39 | (hookmask & ~((1 << NF_BR_PRE_ROUTING) | (1 << NF_BR_LOCAL_OUT)))) && |
40 | (strcmp(tablename, "broute") || hookmask & ~(1 << NF_BR_BROUTING)) ) | 40 | (strcmp(tablename, "broute") || hookmask & ~(1 << NF_BR_BROUTING)) ) |
41 | return -EINVAL; | 41 | return false; |
42 | if (INVALID_TARGET) | 42 | if (INVALID_TARGET) |
43 | return -EINVAL; | 43 | return false; |
44 | return 0; | 44 | return true; |
45 | } | 45 | } |
46 | 46 | ||
47 | static struct ebt_target dnat __read_mostly = { | 47 | static struct ebt_target dnat __read_mostly = { |
48 | .name = EBT_DNAT_TARGET, | 48 | .name = EBT_DNAT_TARGET, |
49 | .target = ebt_target_dnat, | 49 | .target = ebt_target_dnat, |
50 | .check = ebt_target_dnat_check, | 50 | .check = ebt_target_dnat_check, |
51 | .targetsize = XT_ALIGN(sizeof(struct ebt_nat_info)), | 51 | .targetsize = XT_ALIGN(sizeof(struct ebt_nat_info)), |
52 | .me = THIS_MODULE, | 52 | .me = THIS_MODULE, |
53 | }; | 53 | }; |
54 | 54 | ||
55 | static int __init ebt_dnat_init(void) | 55 | static int __init ebt_dnat_init(void) |
56 | { | 56 | { |
57 | return ebt_register_target(&dnat); | 57 | return ebt_register_target(&dnat); |
58 | } | 58 | } |
59 | 59 | ||
60 | static void __exit ebt_dnat_fini(void) | 60 | static void __exit ebt_dnat_fini(void) |
61 | { | 61 | { |
62 | ebt_unregister_target(&dnat); | 62 | ebt_unregister_target(&dnat); |
63 | } | 63 | } |
64 | 64 | ||
65 | module_init(ebt_dnat_init); | 65 | module_init(ebt_dnat_init); |
66 | module_exit(ebt_dnat_fini); | 66 | module_exit(ebt_dnat_fini); |
67 | MODULE_DESCRIPTION("Ebtables: Destination MAC address translation"); | 67 | MODULE_DESCRIPTION("Ebtables: Destination MAC address translation"); |
68 | MODULE_LICENSE("GPL"); | 68 | MODULE_LICENSE("GPL"); |
69 | 69 |
net/bridge/netfilter/ebt_ip.c
1 | /* | 1 | /* |
2 | * ebt_ip | 2 | * ebt_ip |
3 | * | 3 | * |
4 | * Authors: | 4 | * Authors: |
5 | * Bart De Schuymer <bdschuym@pandora.be> | 5 | * Bart De Schuymer <bdschuym@pandora.be> |
6 | * | 6 | * |
7 | * April, 2002 | 7 | * April, 2002 |
8 | * | 8 | * |
9 | * Changes: | 9 | * Changes: |
10 | * added ip-sport and ip-dport | 10 | * added ip-sport and ip-dport |
11 | * Innominate Security Technologies AG <mhopf@innominate.com> | 11 | * Innominate Security Technologies AG <mhopf@innominate.com> |
12 | * September, 2002 | 12 | * September, 2002 |
13 | */ | 13 | */ |
14 | #include <linux/ip.h> | 14 | #include <linux/ip.h> |
15 | #include <net/ip.h> | 15 | #include <net/ip.h> |
16 | #include <linux/in.h> | 16 | #include <linux/in.h> |
17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
18 | #include <linux/netfilter/x_tables.h> | 18 | #include <linux/netfilter/x_tables.h> |
19 | #include <linux/netfilter_bridge/ebtables.h> | 19 | #include <linux/netfilter_bridge/ebtables.h> |
20 | #include <linux/netfilter_bridge/ebt_ip.h> | 20 | #include <linux/netfilter_bridge/ebt_ip.h> |
21 | 21 | ||
22 | struct tcpudphdr { | 22 | struct tcpudphdr { |
23 | __be16 src; | 23 | __be16 src; |
24 | __be16 dst; | 24 | __be16 dst; |
25 | }; | 25 | }; |
26 | 26 | ||
27 | static int ebt_filter_ip(const struct sk_buff *skb, const struct net_device *in, | 27 | static int ebt_filter_ip(const struct sk_buff *skb, const struct net_device *in, |
28 | const struct net_device *out, const void *data, | 28 | const struct net_device *out, const void *data, |
29 | unsigned int datalen) | 29 | unsigned int datalen) |
30 | { | 30 | { |
31 | const struct ebt_ip_info *info = data; | 31 | const struct ebt_ip_info *info = data; |
32 | const struct iphdr *ih; | 32 | const struct iphdr *ih; |
33 | struct iphdr _iph; | 33 | struct iphdr _iph; |
34 | const struct tcpudphdr *pptr; | 34 | const struct tcpudphdr *pptr; |
35 | struct tcpudphdr _ports; | 35 | struct tcpudphdr _ports; |
36 | 36 | ||
37 | ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph); | 37 | ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph); |
38 | if (ih == NULL) | 38 | if (ih == NULL) |
39 | return EBT_NOMATCH; | 39 | return EBT_NOMATCH; |
40 | if (info->bitmask & EBT_IP_TOS && | 40 | if (info->bitmask & EBT_IP_TOS && |
41 | FWINV(info->tos != ih->tos, EBT_IP_TOS)) | 41 | FWINV(info->tos != ih->tos, EBT_IP_TOS)) |
42 | return EBT_NOMATCH; | 42 | return EBT_NOMATCH; |
43 | if (info->bitmask & EBT_IP_SOURCE && | 43 | if (info->bitmask & EBT_IP_SOURCE && |
44 | FWINV((ih->saddr & info->smsk) != | 44 | FWINV((ih->saddr & info->smsk) != |
45 | info->saddr, EBT_IP_SOURCE)) | 45 | info->saddr, EBT_IP_SOURCE)) |
46 | return EBT_NOMATCH; | 46 | return EBT_NOMATCH; |
47 | if ((info->bitmask & EBT_IP_DEST) && | 47 | if ((info->bitmask & EBT_IP_DEST) && |
48 | FWINV((ih->daddr & info->dmsk) != | 48 | FWINV((ih->daddr & info->dmsk) != |
49 | info->daddr, EBT_IP_DEST)) | 49 | info->daddr, EBT_IP_DEST)) |
50 | return EBT_NOMATCH; | 50 | return EBT_NOMATCH; |
51 | if (info->bitmask & EBT_IP_PROTO) { | 51 | if (info->bitmask & EBT_IP_PROTO) { |
52 | if (FWINV(info->protocol != ih->protocol, EBT_IP_PROTO)) | 52 | if (FWINV(info->protocol != ih->protocol, EBT_IP_PROTO)) |
53 | return EBT_NOMATCH; | 53 | return EBT_NOMATCH; |
54 | if (!(info->bitmask & EBT_IP_DPORT) && | 54 | if (!(info->bitmask & EBT_IP_DPORT) && |
55 | !(info->bitmask & EBT_IP_SPORT)) | 55 | !(info->bitmask & EBT_IP_SPORT)) |
56 | return EBT_MATCH; | 56 | return EBT_MATCH; |
57 | if (ntohs(ih->frag_off) & IP_OFFSET) | 57 | if (ntohs(ih->frag_off) & IP_OFFSET) |
58 | return EBT_NOMATCH; | 58 | return EBT_NOMATCH; |
59 | pptr = skb_header_pointer(skb, ih->ihl*4, | 59 | pptr = skb_header_pointer(skb, ih->ihl*4, |
60 | sizeof(_ports), &_ports); | 60 | sizeof(_ports), &_ports); |
61 | if (pptr == NULL) | 61 | if (pptr == NULL) |
62 | return EBT_NOMATCH; | 62 | return EBT_NOMATCH; |
63 | if (info->bitmask & EBT_IP_DPORT) { | 63 | if (info->bitmask & EBT_IP_DPORT) { |
64 | u32 dst = ntohs(pptr->dst); | 64 | u32 dst = ntohs(pptr->dst); |
65 | if (FWINV(dst < info->dport[0] || | 65 | if (FWINV(dst < info->dport[0] || |
66 | dst > info->dport[1], | 66 | dst > info->dport[1], |
67 | EBT_IP_DPORT)) | 67 | EBT_IP_DPORT)) |
68 | return EBT_NOMATCH; | 68 | return EBT_NOMATCH; |
69 | } | 69 | } |
70 | if (info->bitmask & EBT_IP_SPORT) { | 70 | if (info->bitmask & EBT_IP_SPORT) { |
71 | u32 src = ntohs(pptr->src); | 71 | u32 src = ntohs(pptr->src); |
72 | if (FWINV(src < info->sport[0] || | 72 | if (FWINV(src < info->sport[0] || |
73 | src > info->sport[1], | 73 | src > info->sport[1], |
74 | EBT_IP_SPORT)) | 74 | EBT_IP_SPORT)) |
75 | return EBT_NOMATCH; | 75 | return EBT_NOMATCH; |
76 | } | 76 | } |
77 | } | 77 | } |
78 | return EBT_MATCH; | 78 | return EBT_MATCH; |
79 | } | 79 | } |
80 | 80 | ||
81 | static int ebt_ip_check(const char *tablename, unsigned int hookmask, | 81 | static bool ebt_ip_check(const char *tablename, unsigned int hookmask, |
82 | const struct ebt_entry *e, void *data, unsigned int datalen) | 82 | const struct ebt_entry *e, void *data, unsigned int datalen) |
83 | { | 83 | { |
84 | const struct ebt_ip_info *info = data; | 84 | const struct ebt_ip_info *info = data; |
85 | 85 | ||
86 | if (e->ethproto != htons(ETH_P_IP) || | 86 | if (e->ethproto != htons(ETH_P_IP) || |
87 | e->invflags & EBT_IPROTO) | 87 | e->invflags & EBT_IPROTO) |
88 | return -EINVAL; | 88 | return false; |
89 | if (info->bitmask & ~EBT_IP_MASK || info->invflags & ~EBT_IP_MASK) | 89 | if (info->bitmask & ~EBT_IP_MASK || info->invflags & ~EBT_IP_MASK) |
90 | return -EINVAL; | 90 | return false; |
91 | if (info->bitmask & (EBT_IP_DPORT | EBT_IP_SPORT)) { | 91 | if (info->bitmask & (EBT_IP_DPORT | EBT_IP_SPORT)) { |
92 | if (info->invflags & EBT_IP_PROTO) | 92 | if (info->invflags & EBT_IP_PROTO) |
93 | return -EINVAL; | 93 | return false; |
94 | if (info->protocol != IPPROTO_TCP && | 94 | if (info->protocol != IPPROTO_TCP && |
95 | info->protocol != IPPROTO_UDP && | 95 | info->protocol != IPPROTO_UDP && |
96 | info->protocol != IPPROTO_UDPLITE && | 96 | info->protocol != IPPROTO_UDPLITE && |
97 | info->protocol != IPPROTO_SCTP && | 97 | info->protocol != IPPROTO_SCTP && |
98 | info->protocol != IPPROTO_DCCP) | 98 | info->protocol != IPPROTO_DCCP) |
99 | return -EINVAL; | 99 | return false; |
100 | } | 100 | } |
101 | if (info->bitmask & EBT_IP_DPORT && info->dport[0] > info->dport[1]) | 101 | if (info->bitmask & EBT_IP_DPORT && info->dport[0] > info->dport[1]) |
102 | return -EINVAL; | 102 | return false; |
103 | if (info->bitmask & EBT_IP_SPORT && info->sport[0] > info->sport[1]) | 103 | if (info->bitmask & EBT_IP_SPORT && info->sport[0] > info->sport[1]) |
104 | return -EINVAL; | 104 | return false; |
105 | return 0; | 105 | return true; |
106 | } | 106 | } |
107 | 107 | ||
108 | static struct ebt_match filter_ip __read_mostly = { | 108 | static struct ebt_match filter_ip __read_mostly = { |
109 | .name = EBT_IP_MATCH, | 109 | .name = EBT_IP_MATCH, |
110 | .match = ebt_filter_ip, | 110 | .match = ebt_filter_ip, |
111 | .check = ebt_ip_check, | 111 | .check = ebt_ip_check, |
112 | .matchsize = XT_ALIGN(sizeof(struct ebt_ip_info)), | 112 | .matchsize = XT_ALIGN(sizeof(struct ebt_ip_info)), |
113 | .me = THIS_MODULE, | 113 | .me = THIS_MODULE, |
114 | }; | 114 | }; |
115 | 115 | ||
116 | static int __init ebt_ip_init(void) | 116 | static int __init ebt_ip_init(void) |
117 | { | 117 | { |
118 | return ebt_register_match(&filter_ip); | 118 | return ebt_register_match(&filter_ip); |
119 | } | 119 | } |
120 | 120 | ||
121 | static void __exit ebt_ip_fini(void) | 121 | static void __exit ebt_ip_fini(void) |
122 | { | 122 | { |
123 | ebt_unregister_match(&filter_ip); | 123 | ebt_unregister_match(&filter_ip); |
124 | } | 124 | } |
125 | 125 | ||
126 | module_init(ebt_ip_init); | 126 | module_init(ebt_ip_init); |
127 | module_exit(ebt_ip_fini); | 127 | module_exit(ebt_ip_fini); |
128 | MODULE_DESCRIPTION("Ebtables: IPv4 protocol packet match"); | 128 | MODULE_DESCRIPTION("Ebtables: IPv4 protocol packet match"); |
129 | MODULE_LICENSE("GPL"); | 129 | MODULE_LICENSE("GPL"); |
130 | 130 |
net/bridge/netfilter/ebt_ip6.c
1 | /* | 1 | /* |
2 | * ebt_ip6 | 2 | * ebt_ip6 |
3 | * | 3 | * |
4 | * Authors: | 4 | * Authors: |
5 | * Manohar Castelino <manohar.r.castelino@intel.com> | 5 | * Manohar Castelino <manohar.r.castelino@intel.com> |
6 | * Kuo-Lang Tseng <kuo-lang.tseng@intel.com> | 6 | * Kuo-Lang Tseng <kuo-lang.tseng@intel.com> |
7 | * Jan Engelhardt <jengelh@computergmbh.de> | 7 | * Jan Engelhardt <jengelh@computergmbh.de> |
8 | * | 8 | * |
9 | * Summary: | 9 | * Summary: |
10 | * This is just a modification of the IPv4 code written by | 10 | * This is just a modification of the IPv4 code written by |
11 | * Bart De Schuymer <bdschuym@pandora.be> | 11 | * Bart De Schuymer <bdschuym@pandora.be> |
12 | * with the changes required to support IPv6 | 12 | * with the changes required to support IPv6 |
13 | * | 13 | * |
14 | * Jan, 2008 | 14 | * Jan, 2008 |
15 | */ | 15 | */ |
16 | #include <linux/ipv6.h> | 16 | #include <linux/ipv6.h> |
17 | #include <net/ipv6.h> | 17 | #include <net/ipv6.h> |
18 | #include <linux/in.h> | 18 | #include <linux/in.h> |
19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
20 | #include <net/dsfield.h> | 20 | #include <net/dsfield.h> |
21 | #include <linux/netfilter/x_tables.h> | 21 | #include <linux/netfilter/x_tables.h> |
22 | #include <linux/netfilter_bridge/ebtables.h> | 22 | #include <linux/netfilter_bridge/ebtables.h> |
23 | #include <linux/netfilter_bridge/ebt_ip6.h> | 23 | #include <linux/netfilter_bridge/ebt_ip6.h> |
24 | 24 | ||
25 | struct tcpudphdr { | 25 | struct tcpudphdr { |
26 | __be16 src; | 26 | __be16 src; |
27 | __be16 dst; | 27 | __be16 dst; |
28 | }; | 28 | }; |
29 | 29 | ||
30 | static int ebt_filter_ip6(const struct sk_buff *skb, | 30 | static int ebt_filter_ip6(const struct sk_buff *skb, |
31 | const struct net_device *in, | 31 | const struct net_device *in, |
32 | const struct net_device *out, const void *data, | 32 | const struct net_device *out, const void *data, |
33 | unsigned int datalen) | 33 | unsigned int datalen) |
34 | { | 34 | { |
35 | const struct ebt_ip6_info *info = (struct ebt_ip6_info *)data; | 35 | const struct ebt_ip6_info *info = (struct ebt_ip6_info *)data; |
36 | const struct ipv6hdr *ih6; | 36 | const struct ipv6hdr *ih6; |
37 | struct ipv6hdr _ip6h; | 37 | struct ipv6hdr _ip6h; |
38 | const struct tcpudphdr *pptr; | 38 | const struct tcpudphdr *pptr; |
39 | struct tcpudphdr _ports; | 39 | struct tcpudphdr _ports; |
40 | struct in6_addr tmp_addr; | 40 | struct in6_addr tmp_addr; |
41 | int i; | 41 | int i; |
42 | 42 | ||
43 | ih6 = skb_header_pointer(skb, 0, sizeof(_ip6h), &_ip6h); | 43 | ih6 = skb_header_pointer(skb, 0, sizeof(_ip6h), &_ip6h); |
44 | if (ih6 == NULL) | 44 | if (ih6 == NULL) |
45 | return EBT_NOMATCH; | 45 | return EBT_NOMATCH; |
46 | if (info->bitmask & EBT_IP6_TCLASS && | 46 | if (info->bitmask & EBT_IP6_TCLASS && |
47 | FWINV(info->tclass != ipv6_get_dsfield(ih6), EBT_IP6_TCLASS)) | 47 | FWINV(info->tclass != ipv6_get_dsfield(ih6), EBT_IP6_TCLASS)) |
48 | return EBT_NOMATCH; | 48 | return EBT_NOMATCH; |
49 | for (i = 0; i < 4; i++) | 49 | for (i = 0; i < 4; i++) |
50 | tmp_addr.in6_u.u6_addr32[i] = ih6->saddr.in6_u.u6_addr32[i] & | 50 | tmp_addr.in6_u.u6_addr32[i] = ih6->saddr.in6_u.u6_addr32[i] & |
51 | info->smsk.in6_u.u6_addr32[i]; | 51 | info->smsk.in6_u.u6_addr32[i]; |
52 | if (info->bitmask & EBT_IP6_SOURCE && | 52 | if (info->bitmask & EBT_IP6_SOURCE && |
53 | FWINV((ipv6_addr_cmp(&tmp_addr, &info->saddr) != 0), | 53 | FWINV((ipv6_addr_cmp(&tmp_addr, &info->saddr) != 0), |
54 | EBT_IP6_SOURCE)) | 54 | EBT_IP6_SOURCE)) |
55 | return EBT_NOMATCH; | 55 | return EBT_NOMATCH; |
56 | for (i = 0; i < 4; i++) | 56 | for (i = 0; i < 4; i++) |
57 | tmp_addr.in6_u.u6_addr32[i] = ih6->daddr.in6_u.u6_addr32[i] & | 57 | tmp_addr.in6_u.u6_addr32[i] = ih6->daddr.in6_u.u6_addr32[i] & |
58 | info->dmsk.in6_u.u6_addr32[i]; | 58 | info->dmsk.in6_u.u6_addr32[i]; |
59 | if (info->bitmask & EBT_IP6_DEST && | 59 | if (info->bitmask & EBT_IP6_DEST && |
60 | FWINV((ipv6_addr_cmp(&tmp_addr, &info->daddr) != 0), EBT_IP6_DEST)) | 60 | FWINV((ipv6_addr_cmp(&tmp_addr, &info->daddr) != 0), EBT_IP6_DEST)) |
61 | return EBT_NOMATCH; | 61 | return EBT_NOMATCH; |
62 | if (info->bitmask & EBT_IP6_PROTO) { | 62 | if (info->bitmask & EBT_IP6_PROTO) { |
63 | uint8_t nexthdr = ih6->nexthdr; | 63 | uint8_t nexthdr = ih6->nexthdr; |
64 | int offset_ph; | 64 | int offset_ph; |
65 | 65 | ||
66 | offset_ph = ipv6_skip_exthdr(skb, sizeof(_ip6h), &nexthdr); | 66 | offset_ph = ipv6_skip_exthdr(skb, sizeof(_ip6h), &nexthdr); |
67 | if (offset_ph == -1) | 67 | if (offset_ph == -1) |
68 | return EBT_NOMATCH; | 68 | return EBT_NOMATCH; |
69 | if (FWINV(info->protocol != nexthdr, EBT_IP6_PROTO)) | 69 | if (FWINV(info->protocol != nexthdr, EBT_IP6_PROTO)) |
70 | return EBT_NOMATCH; | 70 | return EBT_NOMATCH; |
71 | if (!(info->bitmask & EBT_IP6_DPORT) && | 71 | if (!(info->bitmask & EBT_IP6_DPORT) && |
72 | !(info->bitmask & EBT_IP6_SPORT)) | 72 | !(info->bitmask & EBT_IP6_SPORT)) |
73 | return EBT_MATCH; | 73 | return EBT_MATCH; |
74 | pptr = skb_header_pointer(skb, offset_ph, sizeof(_ports), | 74 | pptr = skb_header_pointer(skb, offset_ph, sizeof(_ports), |
75 | &_ports); | 75 | &_ports); |
76 | if (pptr == NULL) | 76 | if (pptr == NULL) |
77 | return EBT_NOMATCH; | 77 | return EBT_NOMATCH; |
78 | if (info->bitmask & EBT_IP6_DPORT) { | 78 | if (info->bitmask & EBT_IP6_DPORT) { |
79 | u32 dst = ntohs(pptr->dst); | 79 | u32 dst = ntohs(pptr->dst); |
80 | if (FWINV(dst < info->dport[0] || | 80 | if (FWINV(dst < info->dport[0] || |
81 | dst > info->dport[1], EBT_IP6_DPORT)) | 81 | dst > info->dport[1], EBT_IP6_DPORT)) |
82 | return EBT_NOMATCH; | 82 | return EBT_NOMATCH; |
83 | } | 83 | } |
84 | if (info->bitmask & EBT_IP6_SPORT) { | 84 | if (info->bitmask & EBT_IP6_SPORT) { |
85 | u32 src = ntohs(pptr->src); | 85 | u32 src = ntohs(pptr->src); |
86 | if (FWINV(src < info->sport[0] || | 86 | if (FWINV(src < info->sport[0] || |
87 | src > info->sport[1], EBT_IP6_SPORT)) | 87 | src > info->sport[1], EBT_IP6_SPORT)) |
88 | return EBT_NOMATCH; | 88 | return EBT_NOMATCH; |
89 | } | 89 | } |
90 | return EBT_MATCH; | 90 | return EBT_MATCH; |
91 | } | 91 | } |
92 | return EBT_MATCH; | 92 | return EBT_MATCH; |
93 | } | 93 | } |
94 | 94 | ||
95 | static int ebt_ip6_check(const char *tablename, unsigned int hookmask, | 95 | static bool ebt_ip6_check(const char *tablename, unsigned int hookmask, |
96 | const struct ebt_entry *e, void *data, unsigned int datalen) | 96 | const struct ebt_entry *e, void *data, unsigned int datalen) |
97 | { | 97 | { |
98 | struct ebt_ip6_info *info = (struct ebt_ip6_info *)data; | 98 | struct ebt_ip6_info *info = (struct ebt_ip6_info *)data; |
99 | 99 | ||
100 | if (e->ethproto != htons(ETH_P_IPV6) || e->invflags & EBT_IPROTO) | 100 | if (e->ethproto != htons(ETH_P_IPV6) || e->invflags & EBT_IPROTO) |
101 | return -EINVAL; | 101 | return false; |
102 | if (info->bitmask & ~EBT_IP6_MASK || info->invflags & ~EBT_IP6_MASK) | 102 | if (info->bitmask & ~EBT_IP6_MASK || info->invflags & ~EBT_IP6_MASK) |
103 | return -EINVAL; | 103 | return false; |
104 | if (info->bitmask & (EBT_IP6_DPORT | EBT_IP6_SPORT)) { | 104 | if (info->bitmask & (EBT_IP6_DPORT | EBT_IP6_SPORT)) { |
105 | if (info->invflags & EBT_IP6_PROTO) | 105 | if (info->invflags & EBT_IP6_PROTO) |
106 | return -EINVAL; | 106 | return false; |
107 | if (info->protocol != IPPROTO_TCP && | 107 | if (info->protocol != IPPROTO_TCP && |
108 | info->protocol != IPPROTO_UDP && | 108 | info->protocol != IPPROTO_UDP && |
109 | info->protocol != IPPROTO_UDPLITE && | 109 | info->protocol != IPPROTO_UDPLITE && |
110 | info->protocol != IPPROTO_SCTP && | 110 | info->protocol != IPPROTO_SCTP && |
111 | info->protocol != IPPROTO_DCCP) | 111 | info->protocol != IPPROTO_DCCP) |
112 | return -EINVAL; | 112 | return false; |
113 | } | 113 | } |
114 | if (info->bitmask & EBT_IP6_DPORT && info->dport[0] > info->dport[1]) | 114 | if (info->bitmask & EBT_IP6_DPORT && info->dport[0] > info->dport[1]) |
115 | return -EINVAL; | 115 | return false; |
116 | if (info->bitmask & EBT_IP6_SPORT && info->sport[0] > info->sport[1]) | 116 | if (info->bitmask & EBT_IP6_SPORT && info->sport[0] > info->sport[1]) |
117 | return -EINVAL; | 117 | return false; |
118 | return 0; | 118 | return true; |
119 | } | 119 | } |
120 | 120 | ||
121 | static struct ebt_match filter_ip6 = | 121 | static struct ebt_match filter_ip6 = |
122 | { | 122 | { |
123 | .name = EBT_IP6_MATCH, | 123 | .name = EBT_IP6_MATCH, |
124 | .match = ebt_filter_ip6, | 124 | .match = ebt_filter_ip6, |
125 | .check = ebt_ip6_check, | 125 | .check = ebt_ip6_check, |
126 | .matchsize = XT_ALIGN(sizeof(struct ebt_ip6_info)), | 126 | .matchsize = XT_ALIGN(sizeof(struct ebt_ip6_info)), |
127 | .me = THIS_MODULE, | 127 | .me = THIS_MODULE, |
128 | }; | 128 | }; |
129 | 129 | ||
130 | static int __init ebt_ip6_init(void) | 130 | static int __init ebt_ip6_init(void) |
131 | { | 131 | { |
132 | return ebt_register_match(&filter_ip6); | 132 | return ebt_register_match(&filter_ip6); |
133 | } | 133 | } |
134 | 134 | ||
135 | static void __exit ebt_ip6_fini(void) | 135 | static void __exit ebt_ip6_fini(void) |
136 | { | 136 | { |
137 | ebt_unregister_match(&filter_ip6); | 137 | ebt_unregister_match(&filter_ip6); |
138 | } | 138 | } |
139 | 139 | ||
140 | module_init(ebt_ip6_init); | 140 | module_init(ebt_ip6_init); |
141 | module_exit(ebt_ip6_fini); | 141 | module_exit(ebt_ip6_fini); |
142 | MODULE_DESCRIPTION("Ebtables: IPv6 protocol packet match"); | 142 | MODULE_DESCRIPTION("Ebtables: IPv6 protocol packet match"); |
143 | MODULE_LICENSE("GPL"); | 143 | MODULE_LICENSE("GPL"); |
144 | 144 |
net/bridge/netfilter/ebt_limit.c
1 | /* | 1 | /* |
2 | * ebt_limit | 2 | * ebt_limit |
3 | * | 3 | * |
4 | * Authors: | 4 | * Authors: |
5 | * Tom Marshall <tommy@home.tig-grr.com> | 5 | * Tom Marshall <tommy@home.tig-grr.com> |
6 | * | 6 | * |
7 | * Mostly copied from netfilter's ipt_limit.c, see that file for | 7 | * Mostly copied from netfilter's ipt_limit.c, see that file for |
8 | * more explanation | 8 | * more explanation |
9 | * | 9 | * |
10 | * September, 2003 | 10 | * September, 2003 |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/netdevice.h> | 14 | #include <linux/netdevice.h> |
15 | #include <linux/spinlock.h> | 15 | #include <linux/spinlock.h> |
16 | #include <linux/netfilter/x_tables.h> | 16 | #include <linux/netfilter/x_tables.h> |
17 | #include <linux/netfilter_bridge/ebtables.h> | 17 | #include <linux/netfilter_bridge/ebtables.h> |
18 | #include <linux/netfilter_bridge/ebt_limit.h> | 18 | #include <linux/netfilter_bridge/ebt_limit.h> |
19 | 19 | ||
20 | static DEFINE_SPINLOCK(limit_lock); | 20 | static DEFINE_SPINLOCK(limit_lock); |
21 | 21 | ||
22 | #define MAX_CPJ (0xFFFFFFFF / (HZ*60*60*24)) | 22 | #define MAX_CPJ (0xFFFFFFFF / (HZ*60*60*24)) |
23 | 23 | ||
24 | #define _POW2_BELOW2(x) ((x)|((x)>>1)) | 24 | #define _POW2_BELOW2(x) ((x)|((x)>>1)) |
25 | #define _POW2_BELOW4(x) (_POW2_BELOW2(x)|_POW2_BELOW2((x)>>2)) | 25 | #define _POW2_BELOW4(x) (_POW2_BELOW2(x)|_POW2_BELOW2((x)>>2)) |
26 | #define _POW2_BELOW8(x) (_POW2_BELOW4(x)|_POW2_BELOW4((x)>>4)) | 26 | #define _POW2_BELOW8(x) (_POW2_BELOW4(x)|_POW2_BELOW4((x)>>4)) |
27 | #define _POW2_BELOW16(x) (_POW2_BELOW8(x)|_POW2_BELOW8((x)>>8)) | 27 | #define _POW2_BELOW16(x) (_POW2_BELOW8(x)|_POW2_BELOW8((x)>>8)) |
28 | #define _POW2_BELOW32(x) (_POW2_BELOW16(x)|_POW2_BELOW16((x)>>16)) | 28 | #define _POW2_BELOW32(x) (_POW2_BELOW16(x)|_POW2_BELOW16((x)>>16)) |
29 | #define POW2_BELOW32(x) ((_POW2_BELOW32(x)>>1) + 1) | 29 | #define POW2_BELOW32(x) ((_POW2_BELOW32(x)>>1) + 1) |
30 | 30 | ||
31 | #define CREDITS_PER_JIFFY POW2_BELOW32(MAX_CPJ) | 31 | #define CREDITS_PER_JIFFY POW2_BELOW32(MAX_CPJ) |
32 | 32 | ||
33 | static int ebt_limit_match(const struct sk_buff *skb, | 33 | static int ebt_limit_match(const struct sk_buff *skb, |
34 | const struct net_device *in, const struct net_device *out, | 34 | const struct net_device *in, const struct net_device *out, |
35 | const void *data, unsigned int datalen) | 35 | const void *data, unsigned int datalen) |
36 | { | 36 | { |
37 | struct ebt_limit_info *info = (struct ebt_limit_info *)data; | 37 | struct ebt_limit_info *info = (struct ebt_limit_info *)data; |
38 | unsigned long now = jiffies; | 38 | unsigned long now = jiffies; |
39 | 39 | ||
40 | spin_lock_bh(&limit_lock); | 40 | spin_lock_bh(&limit_lock); |
41 | info->credit += (now - xchg(&info->prev, now)) * CREDITS_PER_JIFFY; | 41 | info->credit += (now - xchg(&info->prev, now)) * CREDITS_PER_JIFFY; |
42 | if (info->credit > info->credit_cap) | 42 | if (info->credit > info->credit_cap) |
43 | info->credit = info->credit_cap; | 43 | info->credit = info->credit_cap; |
44 | 44 | ||
45 | if (info->credit >= info->cost) { | 45 | if (info->credit >= info->cost) { |
46 | /* We're not limited. */ | 46 | /* We're not limited. */ |
47 | info->credit -= info->cost; | 47 | info->credit -= info->cost; |
48 | spin_unlock_bh(&limit_lock); | 48 | spin_unlock_bh(&limit_lock); |
49 | return EBT_MATCH; | 49 | return EBT_MATCH; |
50 | } | 50 | } |
51 | 51 | ||
52 | spin_unlock_bh(&limit_lock); | 52 | spin_unlock_bh(&limit_lock); |
53 | return EBT_NOMATCH; | 53 | return EBT_NOMATCH; |
54 | } | 54 | } |
55 | 55 | ||
56 | /* Precision saver. */ | 56 | /* Precision saver. */ |
57 | static u_int32_t | 57 | static u_int32_t |
58 | user2credits(u_int32_t user) | 58 | user2credits(u_int32_t user) |
59 | { | 59 | { |
60 | /* If multiplying would overflow... */ | 60 | /* If multiplying would overflow... */ |
61 | if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY)) | 61 | if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY)) |
62 | /* Divide first. */ | 62 | /* Divide first. */ |
63 | return (user / EBT_LIMIT_SCALE) * HZ * CREDITS_PER_JIFFY; | 63 | return (user / EBT_LIMIT_SCALE) * HZ * CREDITS_PER_JIFFY; |
64 | 64 | ||
65 | return (user * HZ * CREDITS_PER_JIFFY) / EBT_LIMIT_SCALE; | 65 | return (user * HZ * CREDITS_PER_JIFFY) / EBT_LIMIT_SCALE; |
66 | } | 66 | } |
67 | 67 | ||
68 | static int ebt_limit_check(const char *tablename, unsigned int hookmask, | 68 | static bool ebt_limit_check(const char *tablename, unsigned int hookmask, |
69 | const struct ebt_entry *e, void *data, unsigned int datalen) | 69 | const struct ebt_entry *e, void *data, unsigned int datalen) |
70 | { | 70 | { |
71 | struct ebt_limit_info *info = data; | 71 | struct ebt_limit_info *info = data; |
72 | 72 | ||
73 | /* Check for overflow. */ | 73 | /* Check for overflow. */ |
74 | if (info->burst == 0 || | 74 | if (info->burst == 0 || |
75 | user2credits(info->avg * info->burst) < user2credits(info->avg)) { | 75 | user2credits(info->avg * info->burst) < user2credits(info->avg)) { |
76 | printk("Overflow in ebt_limit, try lower: %u/%u\n", | 76 | printk("Overflow in ebt_limit, try lower: %u/%u\n", |
77 | info->avg, info->burst); | 77 | info->avg, info->burst); |
78 | return -EINVAL; | 78 | return false; |
79 | } | 79 | } |
80 | 80 | ||
81 | /* User avg in seconds * EBT_LIMIT_SCALE: convert to jiffies * 128. */ | 81 | /* User avg in seconds * EBT_LIMIT_SCALE: convert to jiffies * 128. */ |
82 | info->prev = jiffies; | 82 | info->prev = jiffies; |
83 | info->credit = user2credits(info->avg * info->burst); | 83 | info->credit = user2credits(info->avg * info->burst); |
84 | info->credit_cap = user2credits(info->avg * info->burst); | 84 | info->credit_cap = user2credits(info->avg * info->burst); |
85 | info->cost = user2credits(info->avg); | 85 | info->cost = user2credits(info->avg); |
86 | return 0; | 86 | return true; |
87 | } | 87 | } |
88 | 88 | ||
89 | static struct ebt_match ebt_limit_reg __read_mostly = { | 89 | static struct ebt_match ebt_limit_reg __read_mostly = { |
90 | .name = EBT_LIMIT_MATCH, | 90 | .name = EBT_LIMIT_MATCH, |
91 | .match = ebt_limit_match, | 91 | .match = ebt_limit_match, |
92 | .check = ebt_limit_check, | 92 | .check = ebt_limit_check, |
93 | .matchsize = XT_ALIGN(sizeof(struct ebt_limit_info)), | 93 | .matchsize = XT_ALIGN(sizeof(struct ebt_limit_info)), |
94 | .me = THIS_MODULE, | 94 | .me = THIS_MODULE, |
95 | }; | 95 | }; |
96 | 96 | ||
97 | static int __init ebt_limit_init(void) | 97 | static int __init ebt_limit_init(void) |
98 | { | 98 | { |
99 | return ebt_register_match(&ebt_limit_reg); | 99 | return ebt_register_match(&ebt_limit_reg); |
100 | } | 100 | } |
101 | 101 | ||
102 | static void __exit ebt_limit_fini(void) | 102 | static void __exit ebt_limit_fini(void) |
103 | { | 103 | { |
104 | ebt_unregister_match(&ebt_limit_reg); | 104 | ebt_unregister_match(&ebt_limit_reg); |
105 | } | 105 | } |
106 | 106 | ||
107 | module_init(ebt_limit_init); | 107 | module_init(ebt_limit_init); |
108 | module_exit(ebt_limit_fini); | 108 | module_exit(ebt_limit_fini); |
109 | MODULE_DESCRIPTION("Ebtables: Rate-limit match"); | 109 | MODULE_DESCRIPTION("Ebtables: Rate-limit match"); |
110 | MODULE_LICENSE("GPL"); | 110 | MODULE_LICENSE("GPL"); |
111 | 111 |
net/bridge/netfilter/ebt_log.c
1 | /* | 1 | /* |
2 | * ebt_log | 2 | * ebt_log |
3 | * | 3 | * |
4 | * Authors: | 4 | * Authors: |
5 | * Bart De Schuymer <bdschuym@pandora.be> | 5 | * Bart De Schuymer <bdschuym@pandora.be> |
6 | * Harald Welte <laforge@netfilter.org> | 6 | * Harald Welte <laforge@netfilter.org> |
7 | * | 7 | * |
8 | * April, 2002 | 8 | * April, 2002 |
9 | * | 9 | * |
10 | */ | 10 | */ |
11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
12 | #include <linux/ip.h> | 12 | #include <linux/ip.h> |
13 | #include <linux/in.h> | 13 | #include <linux/in.h> |
14 | #include <linux/if_arp.h> | 14 | #include <linux/if_arp.h> |
15 | #include <linux/spinlock.h> | 15 | #include <linux/spinlock.h> |
16 | #include <net/netfilter/nf_log.h> | 16 | #include <net/netfilter/nf_log.h> |
17 | #include <linux/ipv6.h> | 17 | #include <linux/ipv6.h> |
18 | #include <net/ipv6.h> | 18 | #include <net/ipv6.h> |
19 | #include <linux/in6.h> | 19 | #include <linux/in6.h> |
20 | #include <linux/netfilter/x_tables.h> | 20 | #include <linux/netfilter/x_tables.h> |
21 | #include <linux/netfilter_bridge/ebtables.h> | 21 | #include <linux/netfilter_bridge/ebtables.h> |
22 | #include <linux/netfilter_bridge/ebt_log.h> | 22 | #include <linux/netfilter_bridge/ebt_log.h> |
23 | #include <linux/netfilter.h> | 23 | #include <linux/netfilter.h> |
24 | 24 | ||
25 | static DEFINE_SPINLOCK(ebt_log_lock); | 25 | static DEFINE_SPINLOCK(ebt_log_lock); |
26 | 26 | ||
27 | static int ebt_log_check(const char *tablename, unsigned int hookmask, | 27 | static bool ebt_log_check(const char *tablename, unsigned int hookmask, |
28 | const struct ebt_entry *e, void *data, unsigned int datalen) | 28 | const struct ebt_entry *e, void *data, unsigned int datalen) |
29 | { | 29 | { |
30 | struct ebt_log_info *info = data; | 30 | struct ebt_log_info *info = data; |
31 | 31 | ||
32 | if (info->bitmask & ~EBT_LOG_MASK) | 32 | if (info->bitmask & ~EBT_LOG_MASK) |
33 | return -EINVAL; | 33 | return false; |
34 | if (info->loglevel >= 8) | 34 | if (info->loglevel >= 8) |
35 | return -EINVAL; | 35 | return false; |
36 | info->prefix[EBT_LOG_PREFIX_SIZE - 1] = '\0'; | 36 | info->prefix[EBT_LOG_PREFIX_SIZE - 1] = '\0'; |
37 | return 0; | 37 | return true; |
38 | } | 38 | } |
39 | 39 | ||
40 | struct tcpudphdr | 40 | struct tcpudphdr |
41 | { | 41 | { |
42 | __be16 src; | 42 | __be16 src; |
43 | __be16 dst; | 43 | __be16 dst; |
44 | }; | 44 | }; |
45 | 45 | ||
46 | struct arppayload | 46 | struct arppayload |
47 | { | 47 | { |
48 | unsigned char mac_src[ETH_ALEN]; | 48 | unsigned char mac_src[ETH_ALEN]; |
49 | unsigned char ip_src[4]; | 49 | unsigned char ip_src[4]; |
50 | unsigned char mac_dst[ETH_ALEN]; | 50 | unsigned char mac_dst[ETH_ALEN]; |
51 | unsigned char ip_dst[4]; | 51 | unsigned char ip_dst[4]; |
52 | }; | 52 | }; |
53 | 53 | ||
54 | static void print_MAC(const unsigned char *p) | 54 | static void print_MAC(const unsigned char *p) |
55 | { | 55 | { |
56 | int i; | 56 | int i; |
57 | 57 | ||
58 | for (i = 0; i < ETH_ALEN; i++, p++) | 58 | for (i = 0; i < ETH_ALEN; i++, p++) |
59 | printk("%02x%c", *p, i == ETH_ALEN - 1 ? ' ':':'); | 59 | printk("%02x%c", *p, i == ETH_ALEN - 1 ? ' ':':'); |
60 | } | 60 | } |
61 | 61 | ||
62 | static void | 62 | static void |
63 | print_ports(const struct sk_buff *skb, uint8_t protocol, int offset) | 63 | print_ports(const struct sk_buff *skb, uint8_t protocol, int offset) |
64 | { | 64 | { |
65 | if (protocol == IPPROTO_TCP || | 65 | if (protocol == IPPROTO_TCP || |
66 | protocol == IPPROTO_UDP || | 66 | protocol == IPPROTO_UDP || |
67 | protocol == IPPROTO_UDPLITE || | 67 | protocol == IPPROTO_UDPLITE || |
68 | protocol == IPPROTO_SCTP || | 68 | protocol == IPPROTO_SCTP || |
69 | protocol == IPPROTO_DCCP) { | 69 | protocol == IPPROTO_DCCP) { |
70 | const struct tcpudphdr *pptr; | 70 | const struct tcpudphdr *pptr; |
71 | struct tcpudphdr _ports; | 71 | struct tcpudphdr _ports; |
72 | 72 | ||
73 | pptr = skb_header_pointer(skb, offset, | 73 | pptr = skb_header_pointer(skb, offset, |
74 | sizeof(_ports), &_ports); | 74 | sizeof(_ports), &_ports); |
75 | if (pptr == NULL) { | 75 | if (pptr == NULL) { |
76 | printk(" INCOMPLETE TCP/UDP header"); | 76 | printk(" INCOMPLETE TCP/UDP header"); |
77 | return; | 77 | return; |
78 | } | 78 | } |
79 | printk(" SPT=%u DPT=%u", ntohs(pptr->src), ntohs(pptr->dst)); | 79 | printk(" SPT=%u DPT=%u", ntohs(pptr->src), ntohs(pptr->dst)); |
80 | } | 80 | } |
81 | } | 81 | } |
82 | 82 | ||
83 | #define myNIPQUAD(a) a[0], a[1], a[2], a[3] | 83 | #define myNIPQUAD(a) a[0], a[1], a[2], a[3] |
84 | static void | 84 | static void |
85 | ebt_log_packet(u_int8_t pf, unsigned int hooknum, | 85 | ebt_log_packet(u_int8_t pf, unsigned int hooknum, |
86 | const struct sk_buff *skb, const struct net_device *in, | 86 | const struct sk_buff *skb, const struct net_device *in, |
87 | const struct net_device *out, const struct nf_loginfo *loginfo, | 87 | const struct net_device *out, const struct nf_loginfo *loginfo, |
88 | const char *prefix) | 88 | const char *prefix) |
89 | { | 89 | { |
90 | unsigned int bitmask; | 90 | unsigned int bitmask; |
91 | 91 | ||
92 | spin_lock_bh(&ebt_log_lock); | 92 | spin_lock_bh(&ebt_log_lock); |
93 | printk("<%c>%s IN=%s OUT=%s MAC source = ", '0' + loginfo->u.log.level, | 93 | printk("<%c>%s IN=%s OUT=%s MAC source = ", '0' + loginfo->u.log.level, |
94 | prefix, in ? in->name : "", out ? out->name : ""); | 94 | prefix, in ? in->name : "", out ? out->name : ""); |
95 | 95 | ||
96 | print_MAC(eth_hdr(skb)->h_source); | 96 | print_MAC(eth_hdr(skb)->h_source); |
97 | printk("MAC dest = "); | 97 | printk("MAC dest = "); |
98 | print_MAC(eth_hdr(skb)->h_dest); | 98 | print_MAC(eth_hdr(skb)->h_dest); |
99 | 99 | ||
100 | printk("proto = 0x%04x", ntohs(eth_hdr(skb)->h_proto)); | 100 | printk("proto = 0x%04x", ntohs(eth_hdr(skb)->h_proto)); |
101 | 101 | ||
102 | if (loginfo->type == NF_LOG_TYPE_LOG) | 102 | if (loginfo->type == NF_LOG_TYPE_LOG) |
103 | bitmask = loginfo->u.log.logflags; | 103 | bitmask = loginfo->u.log.logflags; |
104 | else | 104 | else |
105 | bitmask = NF_LOG_MASK; | 105 | bitmask = NF_LOG_MASK; |
106 | 106 | ||
107 | if ((bitmask & EBT_LOG_IP) && eth_hdr(skb)->h_proto == | 107 | if ((bitmask & EBT_LOG_IP) && eth_hdr(skb)->h_proto == |
108 | htons(ETH_P_IP)){ | 108 | htons(ETH_P_IP)){ |
109 | const struct iphdr *ih; | 109 | const struct iphdr *ih; |
110 | struct iphdr _iph; | 110 | struct iphdr _iph; |
111 | 111 | ||
112 | ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph); | 112 | ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph); |
113 | if (ih == NULL) { | 113 | if (ih == NULL) { |
114 | printk(" INCOMPLETE IP header"); | 114 | printk(" INCOMPLETE IP header"); |
115 | goto out; | 115 | goto out; |
116 | } | 116 | } |
117 | printk(" IP SRC=%u.%u.%u.%u IP DST=%u.%u.%u.%u, IP " | 117 | printk(" IP SRC=%u.%u.%u.%u IP DST=%u.%u.%u.%u, IP " |
118 | "tos=0x%02X, IP proto=%d", NIPQUAD(ih->saddr), | 118 | "tos=0x%02X, IP proto=%d", NIPQUAD(ih->saddr), |
119 | NIPQUAD(ih->daddr), ih->tos, ih->protocol); | 119 | NIPQUAD(ih->daddr), ih->tos, ih->protocol); |
120 | print_ports(skb, ih->protocol, ih->ihl*4); | 120 | print_ports(skb, ih->protocol, ih->ihl*4); |
121 | goto out; | 121 | goto out; |
122 | } | 122 | } |
123 | 123 | ||
124 | #if defined(CONFIG_BRIDGE_EBT_IP6) || defined(CONFIG_BRIDGE_EBT_IP6_MODULE) | 124 | #if defined(CONFIG_BRIDGE_EBT_IP6) || defined(CONFIG_BRIDGE_EBT_IP6_MODULE) |
125 | if ((bitmask & EBT_LOG_IP6) && eth_hdr(skb)->h_proto == | 125 | if ((bitmask & EBT_LOG_IP6) && eth_hdr(skb)->h_proto == |
126 | htons(ETH_P_IPV6)) { | 126 | htons(ETH_P_IPV6)) { |
127 | const struct ipv6hdr *ih; | 127 | const struct ipv6hdr *ih; |
128 | struct ipv6hdr _iph; | 128 | struct ipv6hdr _iph; |
129 | uint8_t nexthdr; | 129 | uint8_t nexthdr; |
130 | int offset_ph; | 130 | int offset_ph; |
131 | 131 | ||
132 | ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph); | 132 | ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph); |
133 | if (ih == NULL) { | 133 | if (ih == NULL) { |
134 | printk(" INCOMPLETE IPv6 header"); | 134 | printk(" INCOMPLETE IPv6 header"); |
135 | goto out; | 135 | goto out; |
136 | } | 136 | } |
137 | printk(" IPv6 SRC=%x:%x:%x:%x:%x:%x:%x:%x " | 137 | printk(" IPv6 SRC=%x:%x:%x:%x:%x:%x:%x:%x " |
138 | "IPv6 DST=%x:%x:%x:%x:%x:%x:%x:%x, IPv6 " | 138 | "IPv6 DST=%x:%x:%x:%x:%x:%x:%x:%x, IPv6 " |
139 | "priority=0x%01X, Next Header=%d", NIP6(ih->saddr), | 139 | "priority=0x%01X, Next Header=%d", NIP6(ih->saddr), |
140 | NIP6(ih->daddr), ih->priority, ih->nexthdr); | 140 | NIP6(ih->daddr), ih->priority, ih->nexthdr); |
141 | nexthdr = ih->nexthdr; | 141 | nexthdr = ih->nexthdr; |
142 | offset_ph = ipv6_skip_exthdr(skb, sizeof(_iph), &nexthdr); | 142 | offset_ph = ipv6_skip_exthdr(skb, sizeof(_iph), &nexthdr); |
143 | if (offset_ph == -1) | 143 | if (offset_ph == -1) |
144 | goto out; | 144 | goto out; |
145 | print_ports(skb, nexthdr, offset_ph); | 145 | print_ports(skb, nexthdr, offset_ph); |
146 | goto out; | 146 | goto out; |
147 | } | 147 | } |
148 | #endif | 148 | #endif |
149 | 149 | ||
150 | if ((bitmask & EBT_LOG_ARP) && | 150 | if ((bitmask & EBT_LOG_ARP) && |
151 | ((eth_hdr(skb)->h_proto == htons(ETH_P_ARP)) || | 151 | ((eth_hdr(skb)->h_proto == htons(ETH_P_ARP)) || |
152 | (eth_hdr(skb)->h_proto == htons(ETH_P_RARP)))) { | 152 | (eth_hdr(skb)->h_proto == htons(ETH_P_RARP)))) { |
153 | const struct arphdr *ah; | 153 | const struct arphdr *ah; |
154 | struct arphdr _arph; | 154 | struct arphdr _arph; |
155 | 155 | ||
156 | ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph); | 156 | ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph); |
157 | if (ah == NULL) { | 157 | if (ah == NULL) { |
158 | printk(" INCOMPLETE ARP header"); | 158 | printk(" INCOMPLETE ARP header"); |
159 | goto out; | 159 | goto out; |
160 | } | 160 | } |
161 | printk(" ARP HTYPE=%d, PTYPE=0x%04x, OPCODE=%d", | 161 | printk(" ARP HTYPE=%d, PTYPE=0x%04x, OPCODE=%d", |
162 | ntohs(ah->ar_hrd), ntohs(ah->ar_pro), | 162 | ntohs(ah->ar_hrd), ntohs(ah->ar_pro), |
163 | ntohs(ah->ar_op)); | 163 | ntohs(ah->ar_op)); |
164 | 164 | ||
165 | /* If it's for Ethernet and the lengths are OK, | 165 | /* If it's for Ethernet and the lengths are OK, |
166 | * then log the ARP payload */ | 166 | * then log the ARP payload */ |
167 | if (ah->ar_hrd == htons(1) && | 167 | if (ah->ar_hrd == htons(1) && |
168 | ah->ar_hln == ETH_ALEN && | 168 | ah->ar_hln == ETH_ALEN && |
169 | ah->ar_pln == sizeof(__be32)) { | 169 | ah->ar_pln == sizeof(__be32)) { |
170 | const struct arppayload *ap; | 170 | const struct arppayload *ap; |
171 | struct arppayload _arpp; | 171 | struct arppayload _arpp; |
172 | 172 | ||
173 | ap = skb_header_pointer(skb, sizeof(_arph), | 173 | ap = skb_header_pointer(skb, sizeof(_arph), |
174 | sizeof(_arpp), &_arpp); | 174 | sizeof(_arpp), &_arpp); |
175 | if (ap == NULL) { | 175 | if (ap == NULL) { |
176 | printk(" INCOMPLETE ARP payload"); | 176 | printk(" INCOMPLETE ARP payload"); |
177 | goto out; | 177 | goto out; |
178 | } | 178 | } |
179 | printk(" ARP MAC SRC="); | 179 | printk(" ARP MAC SRC="); |
180 | print_MAC(ap->mac_src); | 180 | print_MAC(ap->mac_src); |
181 | printk(" ARP IP SRC=%u.%u.%u.%u", | 181 | printk(" ARP IP SRC=%u.%u.%u.%u", |
182 | myNIPQUAD(ap->ip_src)); | 182 | myNIPQUAD(ap->ip_src)); |
183 | printk(" ARP MAC DST="); | 183 | printk(" ARP MAC DST="); |
184 | print_MAC(ap->mac_dst); | 184 | print_MAC(ap->mac_dst); |
185 | printk(" ARP IP DST=%u.%u.%u.%u", | 185 | printk(" ARP IP DST=%u.%u.%u.%u", |
186 | myNIPQUAD(ap->ip_dst)); | 186 | myNIPQUAD(ap->ip_dst)); |
187 | } | 187 | } |
188 | } | 188 | } |
189 | out: | 189 | out: |
190 | printk("\n"); | 190 | printk("\n"); |
191 | spin_unlock_bh(&ebt_log_lock); | 191 | spin_unlock_bh(&ebt_log_lock); |
192 | 192 | ||
193 | } | 193 | } |
194 | 194 | ||
195 | static void ebt_log(const struct sk_buff *skb, unsigned int hooknr, | 195 | static void ebt_log(const struct sk_buff *skb, unsigned int hooknr, |
196 | const struct net_device *in, const struct net_device *out, | 196 | const struct net_device *in, const struct net_device *out, |
197 | const void *data, unsigned int datalen) | 197 | const void *data, unsigned int datalen) |
198 | { | 198 | { |
199 | const struct ebt_log_info *info = data; | 199 | const struct ebt_log_info *info = data; |
200 | struct nf_loginfo li; | 200 | struct nf_loginfo li; |
201 | 201 | ||
202 | li.type = NF_LOG_TYPE_LOG; | 202 | li.type = NF_LOG_TYPE_LOG; |
203 | li.u.log.level = info->loglevel; | 203 | li.u.log.level = info->loglevel; |
204 | li.u.log.logflags = info->bitmask; | 204 | li.u.log.logflags = info->bitmask; |
205 | 205 | ||
206 | if (info->bitmask & EBT_LOG_NFLOG) | 206 | if (info->bitmask & EBT_LOG_NFLOG) |
207 | nf_log_packet(NFPROTO_BRIDGE, hooknr, skb, in, out, &li, | 207 | nf_log_packet(NFPROTO_BRIDGE, hooknr, skb, in, out, &li, |
208 | "%s", info->prefix); | 208 | "%s", info->prefix); |
209 | else | 209 | else |
210 | ebt_log_packet(NFPROTO_BRIDGE, hooknr, skb, in, out, &li, | 210 | ebt_log_packet(NFPROTO_BRIDGE, hooknr, skb, in, out, &li, |
211 | info->prefix); | 211 | info->prefix); |
212 | } | 212 | } |
213 | 213 | ||
214 | static struct ebt_watcher log = | 214 | static struct ebt_watcher log = |
215 | { | 215 | { |
216 | .name = EBT_LOG_WATCHER, | 216 | .name = EBT_LOG_WATCHER, |
217 | .watcher = ebt_log, | 217 | .watcher = ebt_log, |
218 | .check = ebt_log_check, | 218 | .check = ebt_log_check, |
219 | .targetsize = XT_ALIGN(sizeof(struct ebt_log_info)), | 219 | .targetsize = XT_ALIGN(sizeof(struct ebt_log_info)), |
220 | .me = THIS_MODULE, | 220 | .me = THIS_MODULE, |
221 | }; | 221 | }; |
222 | 222 | ||
223 | static const struct nf_logger ebt_log_logger = { | 223 | static const struct nf_logger ebt_log_logger = { |
224 | .name = "ebt_log", | 224 | .name = "ebt_log", |
225 | .logfn = &ebt_log_packet, | 225 | .logfn = &ebt_log_packet, |
226 | .me = THIS_MODULE, | 226 | .me = THIS_MODULE, |
227 | }; | 227 | }; |
228 | 228 | ||
229 | static int __init ebt_log_init(void) | 229 | static int __init ebt_log_init(void) |
230 | { | 230 | { |
231 | int ret; | 231 | int ret; |
232 | 232 | ||
233 | ret = ebt_register_watcher(&log); | 233 | ret = ebt_register_watcher(&log); |
234 | if (ret < 0) | 234 | if (ret < 0) |
235 | return ret; | 235 | return ret; |
236 | nf_log_register(NFPROTO_BRIDGE, &ebt_log_logger); | 236 | nf_log_register(NFPROTO_BRIDGE, &ebt_log_logger); |
237 | return 0; | 237 | return 0; |
238 | } | 238 | } |
239 | 239 | ||
240 | static void __exit ebt_log_fini(void) | 240 | static void __exit ebt_log_fini(void) |
241 | { | 241 | { |
242 | nf_log_unregister(&ebt_log_logger); | 242 | nf_log_unregister(&ebt_log_logger); |
243 | ebt_unregister_watcher(&log); | 243 | ebt_unregister_watcher(&log); |
244 | } | 244 | } |
245 | 245 | ||
246 | module_init(ebt_log_init); | 246 | module_init(ebt_log_init); |
247 | module_exit(ebt_log_fini); | 247 | module_exit(ebt_log_fini); |
248 | MODULE_DESCRIPTION("Ebtables: Packet logging to syslog"); | 248 | MODULE_DESCRIPTION("Ebtables: Packet logging to syslog"); |
249 | MODULE_LICENSE("GPL"); | 249 | MODULE_LICENSE("GPL"); |
250 | 250 |
net/bridge/netfilter/ebt_mark.c
1 | /* | 1 | /* |
2 | * ebt_mark | 2 | * ebt_mark |
3 | * | 3 | * |
4 | * Authors: | 4 | * Authors: |
5 | * Bart De Schuymer <bdschuym@pandora.be> | 5 | * Bart De Schuymer <bdschuym@pandora.be> |
6 | * | 6 | * |
7 | * July, 2002 | 7 | * July, 2002 |
8 | * | 8 | * |
9 | */ | 9 | */ |
10 | 10 | ||
11 | /* The mark target can be used in any chain, | 11 | /* The mark target can be used in any chain, |
12 | * I believe adding a mangle table just for marking is total overkill. | 12 | * I believe adding a mangle table just for marking is total overkill. |
13 | * Marking a frame doesn't really change anything in the frame anyway. | 13 | * Marking a frame doesn't really change anything in the frame anyway. |
14 | */ | 14 | */ |
15 | 15 | ||
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/netfilter/x_tables.h> | 17 | #include <linux/netfilter/x_tables.h> |
18 | #include <linux/netfilter_bridge/ebtables.h> | 18 | #include <linux/netfilter_bridge/ebtables.h> |
19 | #include <linux/netfilter_bridge/ebt_mark_t.h> | 19 | #include <linux/netfilter_bridge/ebt_mark_t.h> |
20 | 20 | ||
21 | static int ebt_target_mark(struct sk_buff *skb, unsigned int hooknr, | 21 | static int ebt_target_mark(struct sk_buff *skb, unsigned int hooknr, |
22 | const struct net_device *in, const struct net_device *out, | 22 | const struct net_device *in, const struct net_device *out, |
23 | const void *data, unsigned int datalen) | 23 | const void *data, unsigned int datalen) |
24 | { | 24 | { |
25 | const struct ebt_mark_t_info *info = data; | 25 | const struct ebt_mark_t_info *info = data; |
26 | int action = info->target & -16; | 26 | int action = info->target & -16; |
27 | 27 | ||
28 | if (action == MARK_SET_VALUE) | 28 | if (action == MARK_SET_VALUE) |
29 | skb->mark = info->mark; | 29 | skb->mark = info->mark; |
30 | else if (action == MARK_OR_VALUE) | 30 | else if (action == MARK_OR_VALUE) |
31 | skb->mark |= info->mark; | 31 | skb->mark |= info->mark; |
32 | else if (action == MARK_AND_VALUE) | 32 | else if (action == MARK_AND_VALUE) |
33 | skb->mark &= info->mark; | 33 | skb->mark &= info->mark; |
34 | else | 34 | else |
35 | skb->mark ^= info->mark; | 35 | skb->mark ^= info->mark; |
36 | 36 | ||
37 | return info->target | ~EBT_VERDICT_BITS; | 37 | return info->target | ~EBT_VERDICT_BITS; |
38 | } | 38 | } |
39 | 39 | ||
40 | static int ebt_target_mark_check(const char *tablename, unsigned int hookmask, | 40 | static bool ebt_target_mark_check(const char *tablename, unsigned int hookmask, |
41 | const struct ebt_entry *e, void *data, unsigned int datalen) | 41 | const struct ebt_entry *e, void *data, unsigned int datalen) |
42 | { | 42 | { |
43 | const struct ebt_mark_t_info *info = data; | 43 | const struct ebt_mark_t_info *info = data; |
44 | int tmp; | 44 | int tmp; |
45 | 45 | ||
46 | tmp = info->target | ~EBT_VERDICT_BITS; | 46 | tmp = info->target | ~EBT_VERDICT_BITS; |
47 | if (BASE_CHAIN && tmp == EBT_RETURN) | 47 | if (BASE_CHAIN && tmp == EBT_RETURN) |
48 | return -EINVAL; | 48 | return false; |
49 | CLEAR_BASE_CHAIN_BIT; | 49 | CLEAR_BASE_CHAIN_BIT; |
50 | if (tmp < -NUM_STANDARD_TARGETS || tmp >= 0) | 50 | if (tmp < -NUM_STANDARD_TARGETS || tmp >= 0) |
51 | return -EINVAL; | 51 | return false; |
52 | tmp = info->target & ~EBT_VERDICT_BITS; | 52 | tmp = info->target & ~EBT_VERDICT_BITS; |
53 | if (tmp != MARK_SET_VALUE && tmp != MARK_OR_VALUE && | 53 | if (tmp != MARK_SET_VALUE && tmp != MARK_OR_VALUE && |
54 | tmp != MARK_AND_VALUE && tmp != MARK_XOR_VALUE) | 54 | tmp != MARK_AND_VALUE && tmp != MARK_XOR_VALUE) |
55 | return -EINVAL; | 55 | return false; |
56 | return 0; | 56 | return true; |
57 | } | 57 | } |
58 | 58 | ||
59 | static struct ebt_target mark_target __read_mostly = { | 59 | static struct ebt_target mark_target __read_mostly = { |
60 | .name = EBT_MARK_TARGET, | 60 | .name = EBT_MARK_TARGET, |
61 | .target = ebt_target_mark, | 61 | .target = ebt_target_mark, |
62 | .check = ebt_target_mark_check, | 62 | .check = ebt_target_mark_check, |
63 | .targetsize = XT_ALIGN(sizeof(struct ebt_mark_t_info)), | 63 | .targetsize = XT_ALIGN(sizeof(struct ebt_mark_t_info)), |
64 | .me = THIS_MODULE, | 64 | .me = THIS_MODULE, |
65 | }; | 65 | }; |
66 | 66 | ||
67 | static int __init ebt_mark_init(void) | 67 | static int __init ebt_mark_init(void) |
68 | { | 68 | { |
69 | return ebt_register_target(&mark_target); | 69 | return ebt_register_target(&mark_target); |
70 | } | 70 | } |
71 | 71 | ||
72 | static void __exit ebt_mark_fini(void) | 72 | static void __exit ebt_mark_fini(void) |
73 | { | 73 | { |
74 | ebt_unregister_target(&mark_target); | 74 | ebt_unregister_target(&mark_target); |
75 | } | 75 | } |
76 | 76 | ||
77 | module_init(ebt_mark_init); | 77 | module_init(ebt_mark_init); |
78 | module_exit(ebt_mark_fini); | 78 | module_exit(ebt_mark_fini); |
79 | MODULE_DESCRIPTION("Ebtables: Packet mark modification"); | 79 | MODULE_DESCRIPTION("Ebtables: Packet mark modification"); |
80 | MODULE_LICENSE("GPL"); | 80 | MODULE_LICENSE("GPL"); |
81 | 81 |
net/bridge/netfilter/ebt_mark_m.c
1 | /* | 1 | /* |
2 | * ebt_mark_m | 2 | * ebt_mark_m |
3 | * | 3 | * |
4 | * Authors: | 4 | * Authors: |
5 | * Bart De Schuymer <bdschuym@pandora.be> | 5 | * Bart De Schuymer <bdschuym@pandora.be> |
6 | * | 6 | * |
7 | * July, 2002 | 7 | * July, 2002 |
8 | * | 8 | * |
9 | */ | 9 | */ |
10 | #include <linux/module.h> | 10 | #include <linux/module.h> |
11 | #include <linux/netfilter/x_tables.h> | 11 | #include <linux/netfilter/x_tables.h> |
12 | #include <linux/netfilter_bridge/ebtables.h> | 12 | #include <linux/netfilter_bridge/ebtables.h> |
13 | #include <linux/netfilter_bridge/ebt_mark_m.h> | 13 | #include <linux/netfilter_bridge/ebt_mark_m.h> |
14 | 14 | ||
15 | static int ebt_filter_mark(const struct sk_buff *skb, | 15 | static int ebt_filter_mark(const struct sk_buff *skb, |
16 | const struct net_device *in, const struct net_device *out, const void *data, | 16 | const struct net_device *in, const struct net_device *out, const void *data, |
17 | unsigned int datalen) | 17 | unsigned int datalen) |
18 | { | 18 | { |
19 | const struct ebt_mark_m_info *info = data; | 19 | const struct ebt_mark_m_info *info = data; |
20 | 20 | ||
21 | if (info->bitmask & EBT_MARK_OR) | 21 | if (info->bitmask & EBT_MARK_OR) |
22 | return !(!!(skb->mark & info->mask) ^ info->invert); | 22 | return !(!!(skb->mark & info->mask) ^ info->invert); |
23 | return !(((skb->mark & info->mask) == info->mark) ^ info->invert); | 23 | return !(((skb->mark & info->mask) == info->mark) ^ info->invert); |
24 | } | 24 | } |
25 | 25 | ||
26 | static int ebt_mark_check(const char *tablename, unsigned int hookmask, | 26 | static bool ebt_mark_check(const char *tablename, unsigned int hookmask, |
27 | const struct ebt_entry *e, void *data, unsigned int datalen) | 27 | const struct ebt_entry *e, void *data, unsigned int datalen) |
28 | { | 28 | { |
29 | const struct ebt_mark_m_info *info = data; | 29 | const struct ebt_mark_m_info *info = data; |
30 | 30 | ||
31 | if (info->bitmask & ~EBT_MARK_MASK) | 31 | if (info->bitmask & ~EBT_MARK_MASK) |
32 | return -EINVAL; | 32 | return false; |
33 | if ((info->bitmask & EBT_MARK_OR) && (info->bitmask & EBT_MARK_AND)) | 33 | if ((info->bitmask & EBT_MARK_OR) && (info->bitmask & EBT_MARK_AND)) |
34 | return -EINVAL; | 34 | return false; |
35 | if (!info->bitmask) | 35 | if (!info->bitmask) |
36 | return -EINVAL; | 36 | return false; |
37 | return 0; | 37 | return true; |
38 | } | 38 | } |
39 | 39 | ||
40 | static struct ebt_match filter_mark __read_mostly = { | 40 | static struct ebt_match filter_mark __read_mostly = { |
41 | .name = EBT_MARK_MATCH, | 41 | .name = EBT_MARK_MATCH, |
42 | .match = ebt_filter_mark, | 42 | .match = ebt_filter_mark, |
43 | .check = ebt_mark_check, | 43 | .check = ebt_mark_check, |
44 | .matchsize = XT_ALIGN(sizeof(struct ebt_mark_m_info)), | 44 | .matchsize = XT_ALIGN(sizeof(struct ebt_mark_m_info)), |
45 | .me = THIS_MODULE, | 45 | .me = THIS_MODULE, |
46 | }; | 46 | }; |
47 | 47 | ||
48 | static int __init ebt_mark_m_init(void) | 48 | static int __init ebt_mark_m_init(void) |
49 | { | 49 | { |
50 | return ebt_register_match(&filter_mark); | 50 | return ebt_register_match(&filter_mark); |
51 | } | 51 | } |
52 | 52 | ||
53 | static void __exit ebt_mark_m_fini(void) | 53 | static void __exit ebt_mark_m_fini(void) |
54 | { | 54 | { |
55 | ebt_unregister_match(&filter_mark); | 55 | ebt_unregister_match(&filter_mark); |
56 | } | 56 | } |
57 | 57 | ||
58 | module_init(ebt_mark_m_init); | 58 | module_init(ebt_mark_m_init); |
59 | module_exit(ebt_mark_m_fini); | 59 | module_exit(ebt_mark_m_fini); |
60 | MODULE_DESCRIPTION("Ebtables: Packet mark match"); | 60 | MODULE_DESCRIPTION("Ebtables: Packet mark match"); |
61 | MODULE_LICENSE("GPL"); | 61 | MODULE_LICENSE("GPL"); |
62 | 62 |
net/bridge/netfilter/ebt_nflog.c
1 | /* | 1 | /* |
2 | * ebt_nflog | 2 | * ebt_nflog |
3 | * | 3 | * |
4 | * Author: | 4 | * Author: |
5 | * Peter Warasin <peter@endian.com> | 5 | * Peter Warasin <peter@endian.com> |
6 | * | 6 | * |
7 | * February, 2008 | 7 | * February, 2008 |
8 | * | 8 | * |
9 | * Based on: | 9 | * Based on: |
10 | * xt_NFLOG.c, (C) 2006 by Patrick McHardy <kaber@trash.net> | 10 | * xt_NFLOG.c, (C) 2006 by Patrick McHardy <kaber@trash.net> |
11 | * ebt_ulog.c, (C) 2004 by Bart De Schuymer <bdschuym@pandora.be> | 11 | * ebt_ulog.c, (C) 2004 by Bart De Schuymer <bdschuym@pandora.be> |
12 | * | 12 | * |
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/spinlock.h> | 16 | #include <linux/spinlock.h> |
17 | #include <linux/netfilter/x_tables.h> | 17 | #include <linux/netfilter/x_tables.h> |
18 | #include <linux/netfilter_bridge/ebtables.h> | 18 | #include <linux/netfilter_bridge/ebtables.h> |
19 | #include <linux/netfilter_bridge/ebt_nflog.h> | 19 | #include <linux/netfilter_bridge/ebt_nflog.h> |
20 | #include <net/netfilter/nf_log.h> | 20 | #include <net/netfilter/nf_log.h> |
21 | 21 | ||
22 | static void ebt_nflog(const struct sk_buff *skb, | 22 | static void ebt_nflog(const struct sk_buff *skb, |
23 | unsigned int hooknr, | 23 | unsigned int hooknr, |
24 | const struct net_device *in, | 24 | const struct net_device *in, |
25 | const struct net_device *out, | 25 | const struct net_device *out, |
26 | const void *data, unsigned int datalen) | 26 | const void *data, unsigned int datalen) |
27 | { | 27 | { |
28 | struct ebt_nflog_info *info = (struct ebt_nflog_info *)data; | 28 | struct ebt_nflog_info *info = (struct ebt_nflog_info *)data; |
29 | struct nf_loginfo li; | 29 | struct nf_loginfo li; |
30 | 30 | ||
31 | li.type = NF_LOG_TYPE_ULOG; | 31 | li.type = NF_LOG_TYPE_ULOG; |
32 | li.u.ulog.copy_len = info->len; | 32 | li.u.ulog.copy_len = info->len; |
33 | li.u.ulog.group = info->group; | 33 | li.u.ulog.group = info->group; |
34 | li.u.ulog.qthreshold = info->threshold; | 34 | li.u.ulog.qthreshold = info->threshold; |
35 | 35 | ||
36 | nf_log_packet(PF_BRIDGE, hooknr, skb, in, out, &li, "%s", info->prefix); | 36 | nf_log_packet(PF_BRIDGE, hooknr, skb, in, out, &li, "%s", info->prefix); |
37 | } | 37 | } |
38 | 38 | ||
39 | static int ebt_nflog_check(const char *tablename, | 39 | static bool ebt_nflog_check(const char *tablename, |
40 | unsigned int hookmask, | 40 | unsigned int hookmask, |
41 | const struct ebt_entry *e, | 41 | const struct ebt_entry *e, |
42 | void *data, unsigned int datalen) | 42 | void *data, unsigned int datalen) |
43 | { | 43 | { |
44 | struct ebt_nflog_info *info = (struct ebt_nflog_info *)data; | 44 | struct ebt_nflog_info *info = (struct ebt_nflog_info *)data; |
45 | 45 | ||
46 | if (info->flags & ~EBT_NFLOG_MASK) | 46 | if (info->flags & ~EBT_NFLOG_MASK) |
47 | return -EINVAL; | 47 | return false; |
48 | info->prefix[EBT_NFLOG_PREFIX_SIZE - 1] = '\0'; | 48 | info->prefix[EBT_NFLOG_PREFIX_SIZE - 1] = '\0'; |
49 | return 0; | 49 | return true; |
50 | } | 50 | } |
51 | 51 | ||
52 | static struct ebt_watcher nflog __read_mostly = { | 52 | static struct ebt_watcher nflog __read_mostly = { |
53 | .name = EBT_NFLOG_WATCHER, | 53 | .name = EBT_NFLOG_WATCHER, |
54 | .watcher = ebt_nflog, | 54 | .watcher = ebt_nflog, |
55 | .check = ebt_nflog_check, | 55 | .check = ebt_nflog_check, |
56 | .targetsize = XT_ALIGN(sizeof(struct ebt_nflog_info)), | 56 | .targetsize = XT_ALIGN(sizeof(struct ebt_nflog_info)), |
57 | .me = THIS_MODULE, | 57 | .me = THIS_MODULE, |
58 | }; | 58 | }; |
59 | 59 | ||
60 | static int __init ebt_nflog_init(void) | 60 | static int __init ebt_nflog_init(void) |
61 | { | 61 | { |
62 | return ebt_register_watcher(&nflog); | 62 | return ebt_register_watcher(&nflog); |
63 | } | 63 | } |
64 | 64 | ||
65 | static void __exit ebt_nflog_fini(void) | 65 | static void __exit ebt_nflog_fini(void) |
66 | { | 66 | { |
67 | ebt_unregister_watcher(&nflog); | 67 | ebt_unregister_watcher(&nflog); |
68 | } | 68 | } |
69 | 69 | ||
70 | module_init(ebt_nflog_init); | 70 | module_init(ebt_nflog_init); |
71 | module_exit(ebt_nflog_fini); | 71 | module_exit(ebt_nflog_fini); |
72 | MODULE_LICENSE("GPL"); | 72 | MODULE_LICENSE("GPL"); |
73 | MODULE_AUTHOR("Peter Warasin <peter@endian.com>"); | 73 | MODULE_AUTHOR("Peter Warasin <peter@endian.com>"); |
74 | MODULE_DESCRIPTION("ebtables NFLOG netfilter logging module"); | 74 | MODULE_DESCRIPTION("ebtables NFLOG netfilter logging module"); |
75 | 75 |
net/bridge/netfilter/ebt_pkttype.c
1 | /* | 1 | /* |
2 | * ebt_pkttype | 2 | * ebt_pkttype |
3 | * | 3 | * |
4 | * Authors: | 4 | * Authors: |
5 | * Bart De Schuymer <bdschuym@pandora.be> | 5 | * Bart De Schuymer <bdschuym@pandora.be> |
6 | * | 6 | * |
7 | * April, 2003 | 7 | * April, 2003 |
8 | * | 8 | * |
9 | */ | 9 | */ |
10 | #include <linux/module.h> | 10 | #include <linux/module.h> |
11 | #include <linux/netfilter/x_tables.h> | 11 | #include <linux/netfilter/x_tables.h> |
12 | #include <linux/netfilter_bridge/ebtables.h> | 12 | #include <linux/netfilter_bridge/ebtables.h> |
13 | #include <linux/netfilter_bridge/ebt_pkttype.h> | 13 | #include <linux/netfilter_bridge/ebt_pkttype.h> |
14 | 14 | ||
15 | static int ebt_filter_pkttype(const struct sk_buff *skb, | 15 | static int ebt_filter_pkttype(const struct sk_buff *skb, |
16 | const struct net_device *in, | 16 | const struct net_device *in, |
17 | const struct net_device *out, | 17 | const struct net_device *out, |
18 | const void *data, | 18 | const void *data, |
19 | unsigned int datalen) | 19 | unsigned int datalen) |
20 | { | 20 | { |
21 | const struct ebt_pkttype_info *info = data; | 21 | const struct ebt_pkttype_info *info = data; |
22 | 22 | ||
23 | return (skb->pkt_type != info->pkt_type) ^ info->invert; | 23 | return (skb->pkt_type != info->pkt_type) ^ info->invert; |
24 | } | 24 | } |
25 | 25 | ||
26 | static int ebt_pkttype_check(const char *tablename, unsigned int hookmask, | 26 | static bool ebt_pkttype_check(const char *tablename, unsigned int hookmask, |
27 | const struct ebt_entry *e, void *data, unsigned int datalen) | 27 | const struct ebt_entry *e, void *data, unsigned int datalen) |
28 | { | 28 | { |
29 | const struct ebt_pkttype_info *info = data; | 29 | const struct ebt_pkttype_info *info = data; |
30 | 30 | ||
31 | if (info->invert != 0 && info->invert != 1) | 31 | if (info->invert != 0 && info->invert != 1) |
32 | return -EINVAL; | 32 | return false; |
33 | /* Allow any pkt_type value */ | 33 | /* Allow any pkt_type value */ |
34 | return 0; | 34 | return true; |
35 | } | 35 | } |
36 | 36 | ||
37 | static struct ebt_match filter_pkttype __read_mostly = { | 37 | static struct ebt_match filter_pkttype __read_mostly = { |
38 | .name = EBT_PKTTYPE_MATCH, | 38 | .name = EBT_PKTTYPE_MATCH, |
39 | .match = ebt_filter_pkttype, | 39 | .match = ebt_filter_pkttype, |
40 | .check = ebt_pkttype_check, | 40 | .check = ebt_pkttype_check, |
41 | .matchsize = XT_ALIGN(sizeof(struct ebt_pkttype_info)), | 41 | .matchsize = XT_ALIGN(sizeof(struct ebt_pkttype_info)), |
42 | .me = THIS_MODULE, | 42 | .me = THIS_MODULE, |
43 | }; | 43 | }; |
44 | 44 | ||
45 | static int __init ebt_pkttype_init(void) | 45 | static int __init ebt_pkttype_init(void) |
46 | { | 46 | { |
47 | return ebt_register_match(&filter_pkttype); | 47 | return ebt_register_match(&filter_pkttype); |
48 | } | 48 | } |
49 | 49 | ||
50 | static void __exit ebt_pkttype_fini(void) | 50 | static void __exit ebt_pkttype_fini(void) |
51 | { | 51 | { |
52 | ebt_unregister_match(&filter_pkttype); | 52 | ebt_unregister_match(&filter_pkttype); |
53 | } | 53 | } |
54 | 54 | ||
55 | module_init(ebt_pkttype_init); | 55 | module_init(ebt_pkttype_init); |
56 | module_exit(ebt_pkttype_fini); | 56 | module_exit(ebt_pkttype_fini); |
57 | MODULE_DESCRIPTION("Ebtables: Link layer packet type match"); | 57 | MODULE_DESCRIPTION("Ebtables: Link layer packet type match"); |
58 | MODULE_LICENSE("GPL"); | 58 | MODULE_LICENSE("GPL"); |
59 | 59 |
net/bridge/netfilter/ebt_redirect.c
1 | /* | 1 | /* |
2 | * ebt_redirect | 2 | * ebt_redirect |
3 | * | 3 | * |
4 | * Authors: | 4 | * Authors: |
5 | * Bart De Schuymer <bdschuym@pandora.be> | 5 | * Bart De Schuymer <bdschuym@pandora.be> |
6 | * | 6 | * |
7 | * April, 2002 | 7 | * April, 2002 |
8 | * | 8 | * |
9 | */ | 9 | */ |
10 | #include <linux/module.h> | 10 | #include <linux/module.h> |
11 | #include <net/sock.h> | 11 | #include <net/sock.h> |
12 | #include "../br_private.h" | 12 | #include "../br_private.h" |
13 | #include <linux/netfilter.h> | 13 | #include <linux/netfilter.h> |
14 | #include <linux/netfilter/x_tables.h> | 14 | #include <linux/netfilter/x_tables.h> |
15 | #include <linux/netfilter_bridge/ebtables.h> | 15 | #include <linux/netfilter_bridge/ebtables.h> |
16 | #include <linux/netfilter_bridge/ebt_redirect.h> | 16 | #include <linux/netfilter_bridge/ebt_redirect.h> |
17 | 17 | ||
18 | static int ebt_target_redirect(struct sk_buff *skb, unsigned int hooknr, | 18 | static int ebt_target_redirect(struct sk_buff *skb, unsigned int hooknr, |
19 | const struct net_device *in, const struct net_device *out, | 19 | const struct net_device *in, const struct net_device *out, |
20 | const void *data, unsigned int datalen) | 20 | const void *data, unsigned int datalen) |
21 | { | 21 | { |
22 | const struct ebt_redirect_info *info = data; | 22 | const struct ebt_redirect_info *info = data; |
23 | 23 | ||
24 | if (!skb_make_writable(skb, 0)) | 24 | if (!skb_make_writable(skb, 0)) |
25 | return EBT_DROP; | 25 | return EBT_DROP; |
26 | 26 | ||
27 | if (hooknr != NF_BR_BROUTING) | 27 | if (hooknr != NF_BR_BROUTING) |
28 | memcpy(eth_hdr(skb)->h_dest, | 28 | memcpy(eth_hdr(skb)->h_dest, |
29 | in->br_port->br->dev->dev_addr, ETH_ALEN); | 29 | in->br_port->br->dev->dev_addr, ETH_ALEN); |
30 | else | 30 | else |
31 | memcpy(eth_hdr(skb)->h_dest, in->dev_addr, ETH_ALEN); | 31 | memcpy(eth_hdr(skb)->h_dest, in->dev_addr, ETH_ALEN); |
32 | skb->pkt_type = PACKET_HOST; | 32 | skb->pkt_type = PACKET_HOST; |
33 | return info->target; | 33 | return info->target; |
34 | } | 34 | } |
35 | 35 | ||
36 | static int ebt_target_redirect_check(const char *tablename, unsigned int hookmask, | 36 | static bool ebt_target_redirect_check(const char *tablename, unsigned int hookmask, |
37 | const struct ebt_entry *e, void *data, unsigned int datalen) | 37 | const struct ebt_entry *e, void *data, unsigned int datalen) |
38 | { | 38 | { |
39 | const struct ebt_redirect_info *info = data; | 39 | const struct ebt_redirect_info *info = data; |
40 | 40 | ||
41 | if (BASE_CHAIN && info->target == EBT_RETURN) | 41 | if (BASE_CHAIN && info->target == EBT_RETURN) |
42 | return -EINVAL; | 42 | return false; |
43 | CLEAR_BASE_CHAIN_BIT; | 43 | CLEAR_BASE_CHAIN_BIT; |
44 | if ( (strcmp(tablename, "nat") || hookmask & ~(1 << NF_BR_PRE_ROUTING)) && | 44 | if ( (strcmp(tablename, "nat") || hookmask & ~(1 << NF_BR_PRE_ROUTING)) && |
45 | (strcmp(tablename, "broute") || hookmask & ~(1 << NF_BR_BROUTING)) ) | 45 | (strcmp(tablename, "broute") || hookmask & ~(1 << NF_BR_BROUTING)) ) |
46 | return -EINVAL; | 46 | return false; |
47 | if (INVALID_TARGET) | 47 | if (INVALID_TARGET) |
48 | return -EINVAL; | 48 | return false; |
49 | return 0; | 49 | return true; |
50 | } | 50 | } |
51 | 51 | ||
52 | static struct ebt_target redirect_target __read_mostly = { | 52 | static struct ebt_target redirect_target __read_mostly = { |
53 | .name = EBT_REDIRECT_TARGET, | 53 | .name = EBT_REDIRECT_TARGET, |
54 | .target = ebt_target_redirect, | 54 | .target = ebt_target_redirect, |
55 | .check = ebt_target_redirect_check, | 55 | .check = ebt_target_redirect_check, |
56 | .targetsize = XT_ALIGN(sizeof(struct ebt_redirect_info)), | 56 | .targetsize = XT_ALIGN(sizeof(struct ebt_redirect_info)), |
57 | .me = THIS_MODULE, | 57 | .me = THIS_MODULE, |
58 | }; | 58 | }; |
59 | 59 | ||
60 | static int __init ebt_redirect_init(void) | 60 | static int __init ebt_redirect_init(void) |
61 | { | 61 | { |
62 | return ebt_register_target(&redirect_target); | 62 | return ebt_register_target(&redirect_target); |
63 | } | 63 | } |
64 | 64 | ||
65 | static void __exit ebt_redirect_fini(void) | 65 | static void __exit ebt_redirect_fini(void) |
66 | { | 66 | { |
67 | ebt_unregister_target(&redirect_target); | 67 | ebt_unregister_target(&redirect_target); |
68 | } | 68 | } |
69 | 69 | ||
70 | module_init(ebt_redirect_init); | 70 | module_init(ebt_redirect_init); |
71 | module_exit(ebt_redirect_fini); | 71 | module_exit(ebt_redirect_fini); |
72 | MODULE_DESCRIPTION("Ebtables: Packet redirection to localhost"); | 72 | MODULE_DESCRIPTION("Ebtables: Packet redirection to localhost"); |
73 | MODULE_LICENSE("GPL"); | 73 | MODULE_LICENSE("GPL"); |
74 | 74 |
net/bridge/netfilter/ebt_snat.c
1 | /* | 1 | /* |
2 | * ebt_snat | 2 | * ebt_snat |
3 | * | 3 | * |
4 | * Authors: | 4 | * Authors: |
5 | * Bart De Schuymer <bdschuym@pandora.be> | 5 | * Bart De Schuymer <bdschuym@pandora.be> |
6 | * | 6 | * |
7 | * June, 2002 | 7 | * June, 2002 |
8 | * | 8 | * |
9 | */ | 9 | */ |
10 | #include <linux/module.h> | 10 | #include <linux/module.h> |
11 | #include <net/sock.h> | 11 | #include <net/sock.h> |
12 | #include <linux/if_arp.h> | 12 | #include <linux/if_arp.h> |
13 | #include <net/arp.h> | 13 | #include <net/arp.h> |
14 | #include <linux/netfilter.h> | 14 | #include <linux/netfilter.h> |
15 | #include <linux/netfilter/x_tables.h> | 15 | #include <linux/netfilter/x_tables.h> |
16 | #include <linux/netfilter_bridge/ebtables.h> | 16 | #include <linux/netfilter_bridge/ebtables.h> |
17 | #include <linux/netfilter_bridge/ebt_nat.h> | 17 | #include <linux/netfilter_bridge/ebt_nat.h> |
18 | 18 | ||
19 | static int ebt_target_snat(struct sk_buff *skb, unsigned int hooknr, | 19 | static int ebt_target_snat(struct sk_buff *skb, unsigned int hooknr, |
20 | const struct net_device *in, const struct net_device *out, | 20 | const struct net_device *in, const struct net_device *out, |
21 | const void *data, unsigned int datalen) | 21 | const void *data, unsigned int datalen) |
22 | { | 22 | { |
23 | const struct ebt_nat_info *info = data; | 23 | const struct ebt_nat_info *info = data; |
24 | 24 | ||
25 | if (!skb_make_writable(skb, 0)) | 25 | if (!skb_make_writable(skb, 0)) |
26 | return EBT_DROP; | 26 | return EBT_DROP; |
27 | 27 | ||
28 | memcpy(eth_hdr(skb)->h_source, info->mac, ETH_ALEN); | 28 | memcpy(eth_hdr(skb)->h_source, info->mac, ETH_ALEN); |
29 | if (!(info->target & NAT_ARP_BIT) && | 29 | if (!(info->target & NAT_ARP_BIT) && |
30 | eth_hdr(skb)->h_proto == htons(ETH_P_ARP)) { | 30 | eth_hdr(skb)->h_proto == htons(ETH_P_ARP)) { |
31 | const struct arphdr *ap; | 31 | const struct arphdr *ap; |
32 | struct arphdr _ah; | 32 | struct arphdr _ah; |
33 | 33 | ||
34 | ap = skb_header_pointer(skb, 0, sizeof(_ah), &_ah); | 34 | ap = skb_header_pointer(skb, 0, sizeof(_ah), &_ah); |
35 | if (ap == NULL) | 35 | if (ap == NULL) |
36 | return EBT_DROP; | 36 | return EBT_DROP; |
37 | if (ap->ar_hln != ETH_ALEN) | 37 | if (ap->ar_hln != ETH_ALEN) |
38 | goto out; | 38 | goto out; |
39 | if (skb_store_bits(skb, sizeof(_ah), info->mac,ETH_ALEN)) | 39 | if (skb_store_bits(skb, sizeof(_ah), info->mac,ETH_ALEN)) |
40 | return EBT_DROP; | 40 | return EBT_DROP; |
41 | } | 41 | } |
42 | out: | 42 | out: |
43 | return info->target | ~EBT_VERDICT_BITS; | 43 | return info->target | ~EBT_VERDICT_BITS; |
44 | } | 44 | } |
45 | 45 | ||
46 | static int ebt_target_snat_check(const char *tablename, unsigned int hookmask, | 46 | static bool ebt_target_snat_check(const char *tablename, unsigned int hookmask, |
47 | const struct ebt_entry *e, void *data, unsigned int datalen) | 47 | const struct ebt_entry *e, void *data, unsigned int datalen) |
48 | { | 48 | { |
49 | const struct ebt_nat_info *info = data; | 49 | const struct ebt_nat_info *info = data; |
50 | int tmp; | 50 | int tmp; |
51 | 51 | ||
52 | tmp = info->target | ~EBT_VERDICT_BITS; | 52 | tmp = info->target | ~EBT_VERDICT_BITS; |
53 | if (BASE_CHAIN && tmp == EBT_RETURN) | 53 | if (BASE_CHAIN && tmp == EBT_RETURN) |
54 | return -EINVAL; | 54 | return false; |
55 | CLEAR_BASE_CHAIN_BIT; | 55 | CLEAR_BASE_CHAIN_BIT; |
56 | if (strcmp(tablename, "nat")) | 56 | if (strcmp(tablename, "nat")) |
57 | return -EINVAL; | 57 | return false; |
58 | if (hookmask & ~(1 << NF_BR_POST_ROUTING)) | 58 | if (hookmask & ~(1 << NF_BR_POST_ROUTING)) |
59 | return -EINVAL; | 59 | return false; |
60 | 60 | ||
61 | if (tmp < -NUM_STANDARD_TARGETS || tmp >= 0) | 61 | if (tmp < -NUM_STANDARD_TARGETS || tmp >= 0) |
62 | return -EINVAL; | 62 | return false; |
63 | tmp = info->target | EBT_VERDICT_BITS; | 63 | tmp = info->target | EBT_VERDICT_BITS; |
64 | if ((tmp & ~NAT_ARP_BIT) != ~NAT_ARP_BIT) | 64 | if ((tmp & ~NAT_ARP_BIT) != ~NAT_ARP_BIT) |
65 | return -EINVAL; | 65 | return false; |
66 | return 0; | 66 | return true; |
67 | } | 67 | } |
68 | 68 | ||
69 | static struct ebt_target snat __read_mostly = { | 69 | static struct ebt_target snat __read_mostly = { |
70 | .name = EBT_SNAT_TARGET, | 70 | .name = EBT_SNAT_TARGET, |
71 | .target = ebt_target_snat, | 71 | .target = ebt_target_snat, |
72 | .check = ebt_target_snat_check, | 72 | .check = ebt_target_snat_check, |
73 | .targetsize = XT_ALIGN(sizeof(struct ebt_nat_info)), | 73 | .targetsize = XT_ALIGN(sizeof(struct ebt_nat_info)), |
74 | .me = THIS_MODULE, | 74 | .me = THIS_MODULE, |
75 | }; | 75 | }; |
76 | 76 | ||
77 | static int __init ebt_snat_init(void) | 77 | static int __init ebt_snat_init(void) |
78 | { | 78 | { |
79 | return ebt_register_target(&snat); | 79 | return ebt_register_target(&snat); |
80 | } | 80 | } |
81 | 81 | ||
82 | static void __exit ebt_snat_fini(void) | 82 | static void __exit ebt_snat_fini(void) |
83 | { | 83 | { |
84 | ebt_unregister_target(&snat); | 84 | ebt_unregister_target(&snat); |
85 | } | 85 | } |
86 | 86 | ||
87 | module_init(ebt_snat_init); | 87 | module_init(ebt_snat_init); |
88 | module_exit(ebt_snat_fini); | 88 | module_exit(ebt_snat_fini); |
89 | MODULE_DESCRIPTION("Ebtables: Source MAC address translation"); | 89 | MODULE_DESCRIPTION("Ebtables: Source MAC address translation"); |
90 | MODULE_LICENSE("GPL"); | 90 | MODULE_LICENSE("GPL"); |
91 | 91 |
net/bridge/netfilter/ebt_stp.c
1 | /* | 1 | /* |
2 | * ebt_stp | 2 | * ebt_stp |
3 | * | 3 | * |
4 | * Authors: | 4 | * Authors: |
5 | * Bart De Schuymer <bdschuym@pandora.be> | 5 | * Bart De Schuymer <bdschuym@pandora.be> |
6 | * Stephen Hemminger <shemminger@osdl.org> | 6 | * Stephen Hemminger <shemminger@osdl.org> |
7 | * | 7 | * |
8 | * July, 2003 | 8 | * July, 2003 |
9 | */ | 9 | */ |
10 | #include <linux/etherdevice.h> | 10 | #include <linux/etherdevice.h> |
11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
12 | #include <linux/netfilter/x_tables.h> | 12 | #include <linux/netfilter/x_tables.h> |
13 | #include <linux/netfilter_bridge/ebtables.h> | 13 | #include <linux/netfilter_bridge/ebtables.h> |
14 | #include <linux/netfilter_bridge/ebt_stp.h> | 14 | #include <linux/netfilter_bridge/ebt_stp.h> |
15 | 15 | ||
16 | #define BPDU_TYPE_CONFIG 0 | 16 | #define BPDU_TYPE_CONFIG 0 |
17 | #define BPDU_TYPE_TCN 0x80 | 17 | #define BPDU_TYPE_TCN 0x80 |
18 | 18 | ||
19 | struct stp_header { | 19 | struct stp_header { |
20 | uint8_t dsap; | 20 | uint8_t dsap; |
21 | uint8_t ssap; | 21 | uint8_t ssap; |
22 | uint8_t ctrl; | 22 | uint8_t ctrl; |
23 | uint8_t pid; | 23 | uint8_t pid; |
24 | uint8_t vers; | 24 | uint8_t vers; |
25 | uint8_t type; | 25 | uint8_t type; |
26 | }; | 26 | }; |
27 | 27 | ||
28 | struct stp_config_pdu { | 28 | struct stp_config_pdu { |
29 | uint8_t flags; | 29 | uint8_t flags; |
30 | uint8_t root[8]; | 30 | uint8_t root[8]; |
31 | uint8_t root_cost[4]; | 31 | uint8_t root_cost[4]; |
32 | uint8_t sender[8]; | 32 | uint8_t sender[8]; |
33 | uint8_t port[2]; | 33 | uint8_t port[2]; |
34 | uint8_t msg_age[2]; | 34 | uint8_t msg_age[2]; |
35 | uint8_t max_age[2]; | 35 | uint8_t max_age[2]; |
36 | uint8_t hello_time[2]; | 36 | uint8_t hello_time[2]; |
37 | uint8_t forward_delay[2]; | 37 | uint8_t forward_delay[2]; |
38 | }; | 38 | }; |
39 | 39 | ||
40 | #define NR16(p) (p[0] << 8 | p[1]) | 40 | #define NR16(p) (p[0] << 8 | p[1]) |
41 | #define NR32(p) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]) | 41 | #define NR32(p) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]) |
42 | 42 | ||
43 | static int ebt_filter_config(const struct ebt_stp_info *info, | 43 | static int ebt_filter_config(const struct ebt_stp_info *info, |
44 | const struct stp_config_pdu *stpc) | 44 | const struct stp_config_pdu *stpc) |
45 | { | 45 | { |
46 | const struct ebt_stp_config_info *c; | 46 | const struct ebt_stp_config_info *c; |
47 | uint16_t v16; | 47 | uint16_t v16; |
48 | uint32_t v32; | 48 | uint32_t v32; |
49 | int verdict, i; | 49 | int verdict, i; |
50 | 50 | ||
51 | c = &info->config; | 51 | c = &info->config; |
52 | if ((info->bitmask & EBT_STP_FLAGS) && | 52 | if ((info->bitmask & EBT_STP_FLAGS) && |
53 | FWINV(c->flags != stpc->flags, EBT_STP_FLAGS)) | 53 | FWINV(c->flags != stpc->flags, EBT_STP_FLAGS)) |
54 | return EBT_NOMATCH; | 54 | return EBT_NOMATCH; |
55 | if (info->bitmask & EBT_STP_ROOTPRIO) { | 55 | if (info->bitmask & EBT_STP_ROOTPRIO) { |
56 | v16 = NR16(stpc->root); | 56 | v16 = NR16(stpc->root); |
57 | if (FWINV(v16 < c->root_priol || | 57 | if (FWINV(v16 < c->root_priol || |
58 | v16 > c->root_priou, EBT_STP_ROOTPRIO)) | 58 | v16 > c->root_priou, EBT_STP_ROOTPRIO)) |
59 | return EBT_NOMATCH; | 59 | return EBT_NOMATCH; |
60 | } | 60 | } |
61 | if (info->bitmask & EBT_STP_ROOTADDR) { | 61 | if (info->bitmask & EBT_STP_ROOTADDR) { |
62 | verdict = 0; | 62 | verdict = 0; |
63 | for (i = 0; i < 6; i++) | 63 | for (i = 0; i < 6; i++) |
64 | verdict |= (stpc->root[2+i] ^ c->root_addr[i]) & | 64 | verdict |= (stpc->root[2+i] ^ c->root_addr[i]) & |
65 | c->root_addrmsk[i]; | 65 | c->root_addrmsk[i]; |
66 | if (FWINV(verdict != 0, EBT_STP_ROOTADDR)) | 66 | if (FWINV(verdict != 0, EBT_STP_ROOTADDR)) |
67 | return EBT_NOMATCH; | 67 | return EBT_NOMATCH; |
68 | } | 68 | } |
69 | if (info->bitmask & EBT_STP_ROOTCOST) { | 69 | if (info->bitmask & EBT_STP_ROOTCOST) { |
70 | v32 = NR32(stpc->root_cost); | 70 | v32 = NR32(stpc->root_cost); |
71 | if (FWINV(v32 < c->root_costl || | 71 | if (FWINV(v32 < c->root_costl || |
72 | v32 > c->root_costu, EBT_STP_ROOTCOST)) | 72 | v32 > c->root_costu, EBT_STP_ROOTCOST)) |
73 | return EBT_NOMATCH; | 73 | return EBT_NOMATCH; |
74 | } | 74 | } |
75 | if (info->bitmask & EBT_STP_SENDERPRIO) { | 75 | if (info->bitmask & EBT_STP_SENDERPRIO) { |
76 | v16 = NR16(stpc->sender); | 76 | v16 = NR16(stpc->sender); |
77 | if (FWINV(v16 < c->sender_priol || | 77 | if (FWINV(v16 < c->sender_priol || |
78 | v16 > c->sender_priou, EBT_STP_SENDERPRIO)) | 78 | v16 > c->sender_priou, EBT_STP_SENDERPRIO)) |
79 | return EBT_NOMATCH; | 79 | return EBT_NOMATCH; |
80 | } | 80 | } |
81 | if (info->bitmask & EBT_STP_SENDERADDR) { | 81 | if (info->bitmask & EBT_STP_SENDERADDR) { |
82 | verdict = 0; | 82 | verdict = 0; |
83 | for (i = 0; i < 6; i++) | 83 | for (i = 0; i < 6; i++) |
84 | verdict |= (stpc->sender[2+i] ^ c->sender_addr[i]) & | 84 | verdict |= (stpc->sender[2+i] ^ c->sender_addr[i]) & |
85 | c->sender_addrmsk[i]; | 85 | c->sender_addrmsk[i]; |
86 | if (FWINV(verdict != 0, EBT_STP_SENDERADDR)) | 86 | if (FWINV(verdict != 0, EBT_STP_SENDERADDR)) |
87 | return EBT_NOMATCH; | 87 | return EBT_NOMATCH; |
88 | } | 88 | } |
89 | if (info->bitmask & EBT_STP_PORT) { | 89 | if (info->bitmask & EBT_STP_PORT) { |
90 | v16 = NR16(stpc->port); | 90 | v16 = NR16(stpc->port); |
91 | if (FWINV(v16 < c->portl || | 91 | if (FWINV(v16 < c->portl || |
92 | v16 > c->portu, EBT_STP_PORT)) | 92 | v16 > c->portu, EBT_STP_PORT)) |
93 | return EBT_NOMATCH; | 93 | return EBT_NOMATCH; |
94 | } | 94 | } |
95 | if (info->bitmask & EBT_STP_MSGAGE) { | 95 | if (info->bitmask & EBT_STP_MSGAGE) { |
96 | v16 = NR16(stpc->msg_age); | 96 | v16 = NR16(stpc->msg_age); |
97 | if (FWINV(v16 < c->msg_agel || | 97 | if (FWINV(v16 < c->msg_agel || |
98 | v16 > c->msg_ageu, EBT_STP_MSGAGE)) | 98 | v16 > c->msg_ageu, EBT_STP_MSGAGE)) |
99 | return EBT_NOMATCH; | 99 | return EBT_NOMATCH; |
100 | } | 100 | } |
101 | if (info->bitmask & EBT_STP_MAXAGE) { | 101 | if (info->bitmask & EBT_STP_MAXAGE) { |
102 | v16 = NR16(stpc->max_age); | 102 | v16 = NR16(stpc->max_age); |
103 | if (FWINV(v16 < c->max_agel || | 103 | if (FWINV(v16 < c->max_agel || |
104 | v16 > c->max_ageu, EBT_STP_MAXAGE)) | 104 | v16 > c->max_ageu, EBT_STP_MAXAGE)) |
105 | return EBT_NOMATCH; | 105 | return EBT_NOMATCH; |
106 | } | 106 | } |
107 | if (info->bitmask & EBT_STP_HELLOTIME) { | 107 | if (info->bitmask & EBT_STP_HELLOTIME) { |
108 | v16 = NR16(stpc->hello_time); | 108 | v16 = NR16(stpc->hello_time); |
109 | if (FWINV(v16 < c->hello_timel || | 109 | if (FWINV(v16 < c->hello_timel || |
110 | v16 > c->hello_timeu, EBT_STP_HELLOTIME)) | 110 | v16 > c->hello_timeu, EBT_STP_HELLOTIME)) |
111 | return EBT_NOMATCH; | 111 | return EBT_NOMATCH; |
112 | } | 112 | } |
113 | if (info->bitmask & EBT_STP_FWDD) { | 113 | if (info->bitmask & EBT_STP_FWDD) { |
114 | v16 = NR16(stpc->forward_delay); | 114 | v16 = NR16(stpc->forward_delay); |
115 | if (FWINV(v16 < c->forward_delayl || | 115 | if (FWINV(v16 < c->forward_delayl || |
116 | v16 > c->forward_delayu, EBT_STP_FWDD)) | 116 | v16 > c->forward_delayu, EBT_STP_FWDD)) |
117 | return EBT_NOMATCH; | 117 | return EBT_NOMATCH; |
118 | } | 118 | } |
119 | return EBT_MATCH; | 119 | return EBT_MATCH; |
120 | } | 120 | } |
121 | 121 | ||
122 | static int ebt_filter_stp(const struct sk_buff *skb, const struct net_device *in, | 122 | static int ebt_filter_stp(const struct sk_buff *skb, const struct net_device *in, |
123 | const struct net_device *out, const void *data, unsigned int datalen) | 123 | const struct net_device *out, const void *data, unsigned int datalen) |
124 | { | 124 | { |
125 | const struct ebt_stp_info *info = data; | 125 | const struct ebt_stp_info *info = data; |
126 | const struct stp_header *sp; | 126 | const struct stp_header *sp; |
127 | struct stp_header _stph; | 127 | struct stp_header _stph; |
128 | const uint8_t header[6] = {0x42, 0x42, 0x03, 0x00, 0x00, 0x00}; | 128 | const uint8_t header[6] = {0x42, 0x42, 0x03, 0x00, 0x00, 0x00}; |
129 | 129 | ||
130 | sp = skb_header_pointer(skb, 0, sizeof(_stph), &_stph); | 130 | sp = skb_header_pointer(skb, 0, sizeof(_stph), &_stph); |
131 | if (sp == NULL) | 131 | if (sp == NULL) |
132 | return EBT_NOMATCH; | 132 | return EBT_NOMATCH; |
133 | 133 | ||
134 | /* The stp code only considers these */ | 134 | /* The stp code only considers these */ |
135 | if (memcmp(sp, header, sizeof(header))) | 135 | if (memcmp(sp, header, sizeof(header))) |
136 | return EBT_NOMATCH; | 136 | return EBT_NOMATCH; |
137 | 137 | ||
138 | if (info->bitmask & EBT_STP_TYPE | 138 | if (info->bitmask & EBT_STP_TYPE |
139 | && FWINV(info->type != sp->type, EBT_STP_TYPE)) | 139 | && FWINV(info->type != sp->type, EBT_STP_TYPE)) |
140 | return EBT_NOMATCH; | 140 | return EBT_NOMATCH; |
141 | 141 | ||
142 | if (sp->type == BPDU_TYPE_CONFIG && | 142 | if (sp->type == BPDU_TYPE_CONFIG && |
143 | info->bitmask & EBT_STP_CONFIG_MASK) { | 143 | info->bitmask & EBT_STP_CONFIG_MASK) { |
144 | const struct stp_config_pdu *st; | 144 | const struct stp_config_pdu *st; |
145 | struct stp_config_pdu _stpc; | 145 | struct stp_config_pdu _stpc; |
146 | 146 | ||
147 | st = skb_header_pointer(skb, sizeof(_stph), | 147 | st = skb_header_pointer(skb, sizeof(_stph), |
148 | sizeof(_stpc), &_stpc); | 148 | sizeof(_stpc), &_stpc); |
149 | if (st == NULL) | 149 | if (st == NULL) |
150 | return EBT_NOMATCH; | 150 | return EBT_NOMATCH; |
151 | return ebt_filter_config(info, st); | 151 | return ebt_filter_config(info, st); |
152 | } | 152 | } |
153 | return EBT_MATCH; | 153 | return EBT_MATCH; |
154 | } | 154 | } |
155 | 155 | ||
156 | static int ebt_stp_check(const char *tablename, unsigned int hookmask, | 156 | static bool ebt_stp_check(const char *tablename, unsigned int hookmask, |
157 | const struct ebt_entry *e, void *data, unsigned int datalen) | 157 | const struct ebt_entry *e, void *data, unsigned int datalen) |
158 | { | 158 | { |
159 | const struct ebt_stp_info *info = data; | 159 | const struct ebt_stp_info *info = data; |
160 | const uint8_t bridge_ula[6] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x00}; | 160 | const uint8_t bridge_ula[6] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x00}; |
161 | const uint8_t msk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; | 161 | const uint8_t msk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; |
162 | 162 | ||
163 | if (info->bitmask & ~EBT_STP_MASK || info->invflags & ~EBT_STP_MASK || | 163 | if (info->bitmask & ~EBT_STP_MASK || info->invflags & ~EBT_STP_MASK || |
164 | !(info->bitmask & EBT_STP_MASK)) | 164 | !(info->bitmask & EBT_STP_MASK)) |
165 | return -EINVAL; | 165 | return false; |
166 | /* Make sure the match only receives stp frames */ | 166 | /* Make sure the match only receives stp frames */ |
167 | if (compare_ether_addr(e->destmac, bridge_ula) || | 167 | if (compare_ether_addr(e->destmac, bridge_ula) || |
168 | compare_ether_addr(e->destmsk, msk) || !(e->bitmask & EBT_DESTMAC)) | 168 | compare_ether_addr(e->destmsk, msk) || !(e->bitmask & EBT_DESTMAC)) |
169 | return -EINVAL; | 169 | return false; |
170 | 170 | ||
171 | return 0; | 171 | return true; |
172 | } | 172 | } |
173 | 173 | ||
174 | static struct ebt_match filter_stp __read_mostly = { | 174 | static struct ebt_match filter_stp __read_mostly = { |
175 | .name = EBT_STP_MATCH, | 175 | .name = EBT_STP_MATCH, |
176 | .match = ebt_filter_stp, | 176 | .match = ebt_filter_stp, |
177 | .check = ebt_stp_check, | 177 | .check = ebt_stp_check, |
178 | .matchsize = XT_ALIGN(sizeof(struct ebt_stp_info)), | 178 | .matchsize = XT_ALIGN(sizeof(struct ebt_stp_info)), |
179 | .me = THIS_MODULE, | 179 | .me = THIS_MODULE, |
180 | }; | 180 | }; |
181 | 181 | ||
182 | static int __init ebt_stp_init(void) | 182 | static int __init ebt_stp_init(void) |
183 | { | 183 | { |
184 | return ebt_register_match(&filter_stp); | 184 | return ebt_register_match(&filter_stp); |
185 | } | 185 | } |
186 | 186 | ||
187 | static void __exit ebt_stp_fini(void) | 187 | static void __exit ebt_stp_fini(void) |
188 | { | 188 | { |
189 | ebt_unregister_match(&filter_stp); | 189 | ebt_unregister_match(&filter_stp); |
190 | } | 190 | } |
191 | 191 | ||
192 | module_init(ebt_stp_init); | 192 | module_init(ebt_stp_init); |
193 | module_exit(ebt_stp_fini); | 193 | module_exit(ebt_stp_fini); |
194 | MODULE_DESCRIPTION("Ebtables: Spanning Tree Protocol packet match"); | 194 | MODULE_DESCRIPTION("Ebtables: Spanning Tree Protocol packet match"); |
195 | MODULE_LICENSE("GPL"); | 195 | MODULE_LICENSE("GPL"); |
196 | 196 |
net/bridge/netfilter/ebt_ulog.c
1 | /* | 1 | /* |
2 | * netfilter module for userspace bridged Ethernet frames logging daemons | 2 | * netfilter module for userspace bridged Ethernet frames logging daemons |
3 | * | 3 | * |
4 | * Authors: | 4 | * Authors: |
5 | * Bart De Schuymer <bdschuym@pandora.be> | 5 | * Bart De Schuymer <bdschuym@pandora.be> |
6 | * Harald Welte <laforge@netfilter.org> | 6 | * Harald Welte <laforge@netfilter.org> |
7 | * | 7 | * |
8 | * November, 2004 | 8 | * November, 2004 |
9 | * | 9 | * |
10 | * Based on ipt_ULOG.c, which is | 10 | * Based on ipt_ULOG.c, which is |
11 | * (C) 2000-2002 by Harald Welte <laforge@netfilter.org> | 11 | * (C) 2000-2002 by Harald Welte <laforge@netfilter.org> |
12 | * | 12 | * |
13 | * This module accepts two parameters: | 13 | * This module accepts two parameters: |
14 | * | 14 | * |
15 | * nlbufsiz: | 15 | * nlbufsiz: |
16 | * The parameter specifies how big the buffer for each netlink multicast | 16 | * The parameter specifies how big the buffer for each netlink multicast |
17 | * group is. e.g. If you say nlbufsiz=8192, up to eight kb of packets will | 17 | * group is. e.g. If you say nlbufsiz=8192, up to eight kb of packets will |
18 | * get accumulated in the kernel until they are sent to userspace. It is | 18 | * get accumulated in the kernel until they are sent to userspace. It is |
19 | * NOT possible to allocate more than 128kB, and it is strongly discouraged, | 19 | * NOT possible to allocate more than 128kB, and it is strongly discouraged, |
20 | * because atomically allocating 128kB inside the network rx softirq is not | 20 | * because atomically allocating 128kB inside the network rx softirq is not |
21 | * reliable. Please also keep in mind that this buffer size is allocated for | 21 | * reliable. Please also keep in mind that this buffer size is allocated for |
22 | * each nlgroup you are using, so the total kernel memory usage increases | 22 | * each nlgroup you are using, so the total kernel memory usage increases |
23 | * by that factor. | 23 | * by that factor. |
24 | * | 24 | * |
25 | * flushtimeout: | 25 | * flushtimeout: |
26 | * Specify, after how many hundredths of a second the queue should be | 26 | * Specify, after how many hundredths of a second the queue should be |
27 | * flushed even if it is not full yet. | 27 | * flushed even if it is not full yet. |
28 | * | 28 | * |
29 | */ | 29 | */ |
30 | 30 | ||
31 | #include <linux/module.h> | 31 | #include <linux/module.h> |
32 | #include <linux/spinlock.h> | 32 | #include <linux/spinlock.h> |
33 | #include <linux/socket.h> | 33 | #include <linux/socket.h> |
34 | #include <linux/skbuff.h> | 34 | #include <linux/skbuff.h> |
35 | #include <linux/kernel.h> | 35 | #include <linux/kernel.h> |
36 | #include <linux/timer.h> | 36 | #include <linux/timer.h> |
37 | #include <linux/netlink.h> | 37 | #include <linux/netlink.h> |
38 | #include <linux/netdevice.h> | 38 | #include <linux/netdevice.h> |
39 | #include <linux/netfilter/x_tables.h> | 39 | #include <linux/netfilter/x_tables.h> |
40 | #include <linux/netfilter_bridge/ebtables.h> | 40 | #include <linux/netfilter_bridge/ebtables.h> |
41 | #include <linux/netfilter_bridge/ebt_ulog.h> | 41 | #include <linux/netfilter_bridge/ebt_ulog.h> |
42 | #include <net/netfilter/nf_log.h> | 42 | #include <net/netfilter/nf_log.h> |
43 | #include <net/sock.h> | 43 | #include <net/sock.h> |
44 | #include "../br_private.h" | 44 | #include "../br_private.h" |
45 | 45 | ||
46 | #define PRINTR(format, args...) do { if (net_ratelimit()) \ | 46 | #define PRINTR(format, args...) do { if (net_ratelimit()) \ |
47 | printk(format , ## args); } while (0) | 47 | printk(format , ## args); } while (0) |
48 | 48 | ||
49 | static unsigned int nlbufsiz = NLMSG_GOODSIZE; | 49 | static unsigned int nlbufsiz = NLMSG_GOODSIZE; |
50 | module_param(nlbufsiz, uint, 0600); | 50 | module_param(nlbufsiz, uint, 0600); |
51 | MODULE_PARM_DESC(nlbufsiz, "netlink buffer size (number of bytes) " | 51 | MODULE_PARM_DESC(nlbufsiz, "netlink buffer size (number of bytes) " |
52 | "(defaults to 4096)"); | 52 | "(defaults to 4096)"); |
53 | 53 | ||
54 | static unsigned int flushtimeout = 10; | 54 | static unsigned int flushtimeout = 10; |
55 | module_param(flushtimeout, uint, 0600); | 55 | module_param(flushtimeout, uint, 0600); |
56 | MODULE_PARM_DESC(flushtimeout, "buffer flush timeout (hundredths ofa second) " | 56 | MODULE_PARM_DESC(flushtimeout, "buffer flush timeout (hundredths ofa second) " |
57 | "(defaults to 10)"); | 57 | "(defaults to 10)"); |
58 | 58 | ||
59 | typedef struct { | 59 | typedef struct { |
60 | unsigned int qlen; /* number of nlmsgs' in the skb */ | 60 | unsigned int qlen; /* number of nlmsgs' in the skb */ |
61 | struct nlmsghdr *lastnlh; /* netlink header of last msg in skb */ | 61 | struct nlmsghdr *lastnlh; /* netlink header of last msg in skb */ |
62 | struct sk_buff *skb; /* the pre-allocated skb */ | 62 | struct sk_buff *skb; /* the pre-allocated skb */ |
63 | struct timer_list timer; /* the timer function */ | 63 | struct timer_list timer; /* the timer function */ |
64 | spinlock_t lock; /* the per-queue lock */ | 64 | spinlock_t lock; /* the per-queue lock */ |
65 | } ebt_ulog_buff_t; | 65 | } ebt_ulog_buff_t; |
66 | 66 | ||
67 | static ebt_ulog_buff_t ulog_buffers[EBT_ULOG_MAXNLGROUPS]; | 67 | static ebt_ulog_buff_t ulog_buffers[EBT_ULOG_MAXNLGROUPS]; |
68 | static struct sock *ebtulognl; | 68 | static struct sock *ebtulognl; |
69 | 69 | ||
70 | /* send one ulog_buff_t to userspace */ | 70 | /* send one ulog_buff_t to userspace */ |
71 | static void ulog_send(unsigned int nlgroup) | 71 | static void ulog_send(unsigned int nlgroup) |
72 | { | 72 | { |
73 | ebt_ulog_buff_t *ub = &ulog_buffers[nlgroup]; | 73 | ebt_ulog_buff_t *ub = &ulog_buffers[nlgroup]; |
74 | 74 | ||
75 | if (timer_pending(&ub->timer)) | 75 | if (timer_pending(&ub->timer)) |
76 | del_timer(&ub->timer); | 76 | del_timer(&ub->timer); |
77 | 77 | ||
78 | if (!ub->skb) | 78 | if (!ub->skb) |
79 | return; | 79 | return; |
80 | 80 | ||
81 | /* last nlmsg needs NLMSG_DONE */ | 81 | /* last nlmsg needs NLMSG_DONE */ |
82 | if (ub->qlen > 1) | 82 | if (ub->qlen > 1) |
83 | ub->lastnlh->nlmsg_type = NLMSG_DONE; | 83 | ub->lastnlh->nlmsg_type = NLMSG_DONE; |
84 | 84 | ||
85 | NETLINK_CB(ub->skb).dst_group = nlgroup + 1; | 85 | NETLINK_CB(ub->skb).dst_group = nlgroup + 1; |
86 | netlink_broadcast(ebtulognl, ub->skb, 0, nlgroup + 1, GFP_ATOMIC); | 86 | netlink_broadcast(ebtulognl, ub->skb, 0, nlgroup + 1, GFP_ATOMIC); |
87 | 87 | ||
88 | ub->qlen = 0; | 88 | ub->qlen = 0; |
89 | ub->skb = NULL; | 89 | ub->skb = NULL; |
90 | } | 90 | } |
91 | 91 | ||
92 | /* timer function to flush queue in flushtimeout time */ | 92 | /* timer function to flush queue in flushtimeout time */ |
93 | static void ulog_timer(unsigned long data) | 93 | static void ulog_timer(unsigned long data) |
94 | { | 94 | { |
95 | spin_lock_bh(&ulog_buffers[data].lock); | 95 | spin_lock_bh(&ulog_buffers[data].lock); |
96 | if (ulog_buffers[data].skb) | 96 | if (ulog_buffers[data].skb) |
97 | ulog_send(data); | 97 | ulog_send(data); |
98 | spin_unlock_bh(&ulog_buffers[data].lock); | 98 | spin_unlock_bh(&ulog_buffers[data].lock); |
99 | } | 99 | } |
100 | 100 | ||
101 | static struct sk_buff *ulog_alloc_skb(unsigned int size) | 101 | static struct sk_buff *ulog_alloc_skb(unsigned int size) |
102 | { | 102 | { |
103 | struct sk_buff *skb; | 103 | struct sk_buff *skb; |
104 | unsigned int n; | 104 | unsigned int n; |
105 | 105 | ||
106 | n = max(size, nlbufsiz); | 106 | n = max(size, nlbufsiz); |
107 | skb = alloc_skb(n, GFP_ATOMIC); | 107 | skb = alloc_skb(n, GFP_ATOMIC); |
108 | if (!skb) { | 108 | if (!skb) { |
109 | PRINTR(KERN_ERR "ebt_ulog: can't alloc whole buffer " | 109 | PRINTR(KERN_ERR "ebt_ulog: can't alloc whole buffer " |
110 | "of size %ub!\n", n); | 110 | "of size %ub!\n", n); |
111 | if (n > size) { | 111 | if (n > size) { |
112 | /* try to allocate only as much as we need for | 112 | /* try to allocate only as much as we need for |
113 | * current packet */ | 113 | * current packet */ |
114 | skb = alloc_skb(size, GFP_ATOMIC); | 114 | skb = alloc_skb(size, GFP_ATOMIC); |
115 | if (!skb) | 115 | if (!skb) |
116 | PRINTR(KERN_ERR "ebt_ulog: can't even allocate " | 116 | PRINTR(KERN_ERR "ebt_ulog: can't even allocate " |
117 | "buffer of size %ub\n", size); | 117 | "buffer of size %ub\n", size); |
118 | } | 118 | } |
119 | } | 119 | } |
120 | 120 | ||
121 | return skb; | 121 | return skb; |
122 | } | 122 | } |
123 | 123 | ||
124 | static void ebt_ulog_packet(unsigned int hooknr, const struct sk_buff *skb, | 124 | static void ebt_ulog_packet(unsigned int hooknr, const struct sk_buff *skb, |
125 | const struct net_device *in, const struct net_device *out, | 125 | const struct net_device *in, const struct net_device *out, |
126 | const struct ebt_ulog_info *uloginfo, const char *prefix) | 126 | const struct ebt_ulog_info *uloginfo, const char *prefix) |
127 | { | 127 | { |
128 | ebt_ulog_packet_msg_t *pm; | 128 | ebt_ulog_packet_msg_t *pm; |
129 | size_t size, copy_len; | 129 | size_t size, copy_len; |
130 | struct nlmsghdr *nlh; | 130 | struct nlmsghdr *nlh; |
131 | unsigned int group = uloginfo->nlgroup; | 131 | unsigned int group = uloginfo->nlgroup; |
132 | ebt_ulog_buff_t *ub = &ulog_buffers[group]; | 132 | ebt_ulog_buff_t *ub = &ulog_buffers[group]; |
133 | spinlock_t *lock = &ub->lock; | 133 | spinlock_t *lock = &ub->lock; |
134 | ktime_t kt; | 134 | ktime_t kt; |
135 | 135 | ||
136 | if ((uloginfo->cprange == 0) || | 136 | if ((uloginfo->cprange == 0) || |
137 | (uloginfo->cprange > skb->len + ETH_HLEN)) | 137 | (uloginfo->cprange > skb->len + ETH_HLEN)) |
138 | copy_len = skb->len + ETH_HLEN; | 138 | copy_len = skb->len + ETH_HLEN; |
139 | else | 139 | else |
140 | copy_len = uloginfo->cprange; | 140 | copy_len = uloginfo->cprange; |
141 | 141 | ||
142 | size = NLMSG_SPACE(sizeof(*pm) + copy_len); | 142 | size = NLMSG_SPACE(sizeof(*pm) + copy_len); |
143 | if (size > nlbufsiz) { | 143 | if (size > nlbufsiz) { |
144 | PRINTR("ebt_ulog: Size %Zd needed, but nlbufsiz=%d\n", | 144 | PRINTR("ebt_ulog: Size %Zd needed, but nlbufsiz=%d\n", |
145 | size, nlbufsiz); | 145 | size, nlbufsiz); |
146 | return; | 146 | return; |
147 | } | 147 | } |
148 | 148 | ||
149 | spin_lock_bh(lock); | 149 | spin_lock_bh(lock); |
150 | 150 | ||
151 | if (!ub->skb) { | 151 | if (!ub->skb) { |
152 | if (!(ub->skb = ulog_alloc_skb(size))) | 152 | if (!(ub->skb = ulog_alloc_skb(size))) |
153 | goto alloc_failure; | 153 | goto alloc_failure; |
154 | } else if (size > skb_tailroom(ub->skb)) { | 154 | } else if (size > skb_tailroom(ub->skb)) { |
155 | ulog_send(group); | 155 | ulog_send(group); |
156 | 156 | ||
157 | if (!(ub->skb = ulog_alloc_skb(size))) | 157 | if (!(ub->skb = ulog_alloc_skb(size))) |
158 | goto alloc_failure; | 158 | goto alloc_failure; |
159 | } | 159 | } |
160 | 160 | ||
161 | nlh = NLMSG_PUT(ub->skb, 0, ub->qlen, 0, | 161 | nlh = NLMSG_PUT(ub->skb, 0, ub->qlen, 0, |
162 | size - NLMSG_ALIGN(sizeof(*nlh))); | 162 | size - NLMSG_ALIGN(sizeof(*nlh))); |
163 | ub->qlen++; | 163 | ub->qlen++; |
164 | 164 | ||
165 | pm = NLMSG_DATA(nlh); | 165 | pm = NLMSG_DATA(nlh); |
166 | 166 | ||
167 | /* Fill in the ulog data */ | 167 | /* Fill in the ulog data */ |
168 | pm->version = EBT_ULOG_VERSION; | 168 | pm->version = EBT_ULOG_VERSION; |
169 | kt = ktime_get_real(); | 169 | kt = ktime_get_real(); |
170 | pm->stamp = ktime_to_timeval(kt); | 170 | pm->stamp = ktime_to_timeval(kt); |
171 | if (ub->qlen == 1) | 171 | if (ub->qlen == 1) |
172 | ub->skb->tstamp = kt; | 172 | ub->skb->tstamp = kt; |
173 | pm->data_len = copy_len; | 173 | pm->data_len = copy_len; |
174 | pm->mark = skb->mark; | 174 | pm->mark = skb->mark; |
175 | pm->hook = hooknr; | 175 | pm->hook = hooknr; |
176 | if (uloginfo->prefix != NULL) | 176 | if (uloginfo->prefix != NULL) |
177 | strcpy(pm->prefix, uloginfo->prefix); | 177 | strcpy(pm->prefix, uloginfo->prefix); |
178 | else | 178 | else |
179 | *(pm->prefix) = '\0'; | 179 | *(pm->prefix) = '\0'; |
180 | 180 | ||
181 | if (in) { | 181 | if (in) { |
182 | strcpy(pm->physindev, in->name); | 182 | strcpy(pm->physindev, in->name); |
183 | /* If in isn't a bridge, then physindev==indev */ | 183 | /* If in isn't a bridge, then physindev==indev */ |
184 | if (in->br_port) | 184 | if (in->br_port) |
185 | strcpy(pm->indev, in->br_port->br->dev->name); | 185 | strcpy(pm->indev, in->br_port->br->dev->name); |
186 | else | 186 | else |
187 | strcpy(pm->indev, in->name); | 187 | strcpy(pm->indev, in->name); |
188 | } else | 188 | } else |
189 | pm->indev[0] = pm->physindev[0] = '\0'; | 189 | pm->indev[0] = pm->physindev[0] = '\0'; |
190 | 190 | ||
191 | if (out) { | 191 | if (out) { |
192 | /* If out exists, then out is a bridge port */ | 192 | /* If out exists, then out is a bridge port */ |
193 | strcpy(pm->physoutdev, out->name); | 193 | strcpy(pm->physoutdev, out->name); |
194 | strcpy(pm->outdev, out->br_port->br->dev->name); | 194 | strcpy(pm->outdev, out->br_port->br->dev->name); |
195 | } else | 195 | } else |
196 | pm->outdev[0] = pm->physoutdev[0] = '\0'; | 196 | pm->outdev[0] = pm->physoutdev[0] = '\0'; |
197 | 197 | ||
198 | if (skb_copy_bits(skb, -ETH_HLEN, pm->data, copy_len) < 0) | 198 | if (skb_copy_bits(skb, -ETH_HLEN, pm->data, copy_len) < 0) |
199 | BUG(); | 199 | BUG(); |
200 | 200 | ||
201 | if (ub->qlen > 1) | 201 | if (ub->qlen > 1) |
202 | ub->lastnlh->nlmsg_flags |= NLM_F_MULTI; | 202 | ub->lastnlh->nlmsg_flags |= NLM_F_MULTI; |
203 | 203 | ||
204 | ub->lastnlh = nlh; | 204 | ub->lastnlh = nlh; |
205 | 205 | ||
206 | if (ub->qlen >= uloginfo->qthreshold) | 206 | if (ub->qlen >= uloginfo->qthreshold) |
207 | ulog_send(group); | 207 | ulog_send(group); |
208 | else if (!timer_pending(&ub->timer)) { | 208 | else if (!timer_pending(&ub->timer)) { |
209 | ub->timer.expires = jiffies + flushtimeout * HZ / 100; | 209 | ub->timer.expires = jiffies + flushtimeout * HZ / 100; |
210 | add_timer(&ub->timer); | 210 | add_timer(&ub->timer); |
211 | } | 211 | } |
212 | 212 | ||
213 | unlock: | 213 | unlock: |
214 | spin_unlock_bh(lock); | 214 | spin_unlock_bh(lock); |
215 | 215 | ||
216 | return; | 216 | return; |
217 | 217 | ||
218 | nlmsg_failure: | 218 | nlmsg_failure: |
219 | printk(KERN_CRIT "ebt_ulog: error during NLMSG_PUT. This should " | 219 | printk(KERN_CRIT "ebt_ulog: error during NLMSG_PUT. This should " |
220 | "not happen, please report to author.\n"); | 220 | "not happen, please report to author.\n"); |
221 | goto unlock; | 221 | goto unlock; |
222 | alloc_failure: | 222 | alloc_failure: |
223 | goto unlock; | 223 | goto unlock; |
224 | } | 224 | } |
225 | 225 | ||
226 | /* this function is registered with the netfilter core */ | 226 | /* this function is registered with the netfilter core */ |
227 | static void ebt_log_packet(u_int8_t pf, unsigned int hooknum, | 227 | static void ebt_log_packet(u_int8_t pf, unsigned int hooknum, |
228 | const struct sk_buff *skb, const struct net_device *in, | 228 | const struct sk_buff *skb, const struct net_device *in, |
229 | const struct net_device *out, const struct nf_loginfo *li, | 229 | const struct net_device *out, const struct nf_loginfo *li, |
230 | const char *prefix) | 230 | const char *prefix) |
231 | { | 231 | { |
232 | struct ebt_ulog_info loginfo; | 232 | struct ebt_ulog_info loginfo; |
233 | 233 | ||
234 | if (!li || li->type != NF_LOG_TYPE_ULOG) { | 234 | if (!li || li->type != NF_LOG_TYPE_ULOG) { |
235 | loginfo.nlgroup = EBT_ULOG_DEFAULT_NLGROUP; | 235 | loginfo.nlgroup = EBT_ULOG_DEFAULT_NLGROUP; |
236 | loginfo.cprange = 0; | 236 | loginfo.cprange = 0; |
237 | loginfo.qthreshold = EBT_ULOG_DEFAULT_QTHRESHOLD; | 237 | loginfo.qthreshold = EBT_ULOG_DEFAULT_QTHRESHOLD; |
238 | loginfo.prefix[0] = '\0'; | 238 | loginfo.prefix[0] = '\0'; |
239 | } else { | 239 | } else { |
240 | loginfo.nlgroup = li->u.ulog.group; | 240 | loginfo.nlgroup = li->u.ulog.group; |
241 | loginfo.cprange = li->u.ulog.copy_len; | 241 | loginfo.cprange = li->u.ulog.copy_len; |
242 | loginfo.qthreshold = li->u.ulog.qthreshold; | 242 | loginfo.qthreshold = li->u.ulog.qthreshold; |
243 | strlcpy(loginfo.prefix, prefix, sizeof(loginfo.prefix)); | 243 | strlcpy(loginfo.prefix, prefix, sizeof(loginfo.prefix)); |
244 | } | 244 | } |
245 | 245 | ||
246 | ebt_ulog_packet(hooknum, skb, in, out, &loginfo, prefix); | 246 | ebt_ulog_packet(hooknum, skb, in, out, &loginfo, prefix); |
247 | } | 247 | } |
248 | 248 | ||
249 | static void ebt_ulog(const struct sk_buff *skb, unsigned int hooknr, | 249 | static void ebt_ulog(const struct sk_buff *skb, unsigned int hooknr, |
250 | const struct net_device *in, const struct net_device *out, | 250 | const struct net_device *in, const struct net_device *out, |
251 | const void *data, unsigned int datalen) | 251 | const void *data, unsigned int datalen) |
252 | { | 252 | { |
253 | const struct ebt_ulog_info *uloginfo = data; | 253 | const struct ebt_ulog_info *uloginfo = data; |
254 | 254 | ||
255 | ebt_ulog_packet(hooknr, skb, in, out, uloginfo, NULL); | 255 | ebt_ulog_packet(hooknr, skb, in, out, uloginfo, NULL); |
256 | } | 256 | } |
257 | 257 | ||
258 | 258 | static bool ebt_ulog_check(const char *tablename, unsigned int hookmask, | |
259 | static int ebt_ulog_check(const char *tablename, unsigned int hookmask, | ||
260 | const struct ebt_entry *e, void *data, unsigned int datalen) | 259 | const struct ebt_entry *e, void *data, unsigned int datalen) |
261 | { | 260 | { |
262 | struct ebt_ulog_info *uloginfo = data; | 261 | struct ebt_ulog_info *uloginfo = data; |
263 | 262 | ||
264 | if (uloginfo->nlgroup > 31) | 263 | if (uloginfo->nlgroup > 31) |
265 | return -EINVAL; | 264 | return false; |
266 | 265 | ||
267 | uloginfo->prefix[EBT_ULOG_PREFIX_LEN - 1] = '\0'; | 266 | uloginfo->prefix[EBT_ULOG_PREFIX_LEN - 1] = '\0'; |
268 | 267 | ||
269 | if (uloginfo->qthreshold > EBT_ULOG_MAX_QLEN) | 268 | if (uloginfo->qthreshold > EBT_ULOG_MAX_QLEN) |
270 | uloginfo->qthreshold = EBT_ULOG_MAX_QLEN; | 269 | uloginfo->qthreshold = EBT_ULOG_MAX_QLEN; |
271 | 270 | ||
272 | return 0; | 271 | return 0; |
273 | } | 272 | } |
274 | 273 | ||
275 | static struct ebt_watcher ulog __read_mostly = { | 274 | static struct ebt_watcher ulog __read_mostly = { |
276 | .name = EBT_ULOG_WATCHER, | 275 | .name = EBT_ULOG_WATCHER, |
277 | .watcher = ebt_ulog, | 276 | .watcher = ebt_ulog, |
278 | .check = ebt_ulog_check, | 277 | .check = ebt_ulog_check, |
279 | .targetsize = XT_ALIGN(sizeof(struct ebt_ulog_info)), | 278 | .targetsize = XT_ALIGN(sizeof(struct ebt_ulog_info)), |
280 | .me = THIS_MODULE, | 279 | .me = THIS_MODULE, |
281 | }; | 280 | }; |
282 | 281 | ||
283 | static const struct nf_logger ebt_ulog_logger = { | 282 | static const struct nf_logger ebt_ulog_logger = { |
284 | .name = EBT_ULOG_WATCHER, | 283 | .name = EBT_ULOG_WATCHER, |
285 | .logfn = &ebt_log_packet, | 284 | .logfn = &ebt_log_packet, |
286 | .me = THIS_MODULE, | 285 | .me = THIS_MODULE, |
287 | }; | 286 | }; |
288 | 287 | ||
289 | static int __init ebt_ulog_init(void) | 288 | static int __init ebt_ulog_init(void) |
290 | { | 289 | { |
291 | int i, ret = 0; | 290 | bool ret = true; |
291 | int i; | ||
292 | 292 | ||
293 | if (nlbufsiz >= 128*1024) { | 293 | if (nlbufsiz >= 128*1024) { |
294 | printk(KERN_NOTICE "ebt_ulog: Netlink buffer has to be <= 128kB," | 294 | printk(KERN_NOTICE "ebt_ulog: Netlink buffer has to be <= 128kB," |
295 | " please try a smaller nlbufsiz parameter.\n"); | 295 | " please try a smaller nlbufsiz parameter.\n"); |
296 | return -EINVAL; | 296 | return false; |
297 | } | 297 | } |
298 | 298 | ||
299 | /* initialize ulog_buffers */ | 299 | /* initialize ulog_buffers */ |
300 | for (i = 0; i < EBT_ULOG_MAXNLGROUPS; i++) { | 300 | for (i = 0; i < EBT_ULOG_MAXNLGROUPS; i++) { |
301 | setup_timer(&ulog_buffers[i].timer, ulog_timer, i); | 301 | setup_timer(&ulog_buffers[i].timer, ulog_timer, i); |
302 | spin_lock_init(&ulog_buffers[i].lock); | 302 | spin_lock_init(&ulog_buffers[i].lock); |
303 | } | 303 | } |
304 | 304 | ||
305 | ebtulognl = netlink_kernel_create(&init_net, NETLINK_NFLOG, | 305 | ebtulognl = netlink_kernel_create(&init_net, NETLINK_NFLOG, |
306 | EBT_ULOG_MAXNLGROUPS, NULL, NULL, | 306 | EBT_ULOG_MAXNLGROUPS, NULL, NULL, |
307 | THIS_MODULE); | 307 | THIS_MODULE); |
308 | if (!ebtulognl) | 308 | if (!ebtulognl) { |
309 | ret = -ENOMEM; | 309 | printk(KERN_WARNING KBUILD_MODNAME ": out of memory trying to " |
310 | else if ((ret = ebt_register_watcher(&ulog))) | 310 | "call netlink_kernel_create\n"); |
311 | ret = false; | ||
312 | } else if (ebt_register_watcher(&ulog) != 0) { | ||
311 | netlink_kernel_release(ebtulognl); | 313 | netlink_kernel_release(ebtulognl); |
314 | } | ||
312 | 315 | ||
313 | if (ret == 0) | 316 | if (ret) |
314 | nf_log_register(NFPROTO_BRIDGE, &ebt_ulog_logger); | 317 | nf_log_register(NFPROTO_BRIDGE, &ebt_ulog_logger); |
315 | 318 | ||
316 | return ret; | 319 | return ret; |
317 | } | 320 | } |
318 | 321 | ||
319 | static void __exit ebt_ulog_fini(void) | 322 | static void __exit ebt_ulog_fini(void) |
320 | { | 323 | { |
321 | ebt_ulog_buff_t *ub; | 324 | ebt_ulog_buff_t *ub; |
322 | int i; | 325 | int i; |
323 | 326 | ||
324 | nf_log_unregister(&ebt_ulog_logger); | 327 | nf_log_unregister(&ebt_ulog_logger); |
325 | ebt_unregister_watcher(&ulog); | 328 | ebt_unregister_watcher(&ulog); |
326 | for (i = 0; i < EBT_ULOG_MAXNLGROUPS; i++) { | 329 | for (i = 0; i < EBT_ULOG_MAXNLGROUPS; i++) { |
327 | ub = &ulog_buffers[i]; | 330 | ub = &ulog_buffers[i]; |
328 | if (timer_pending(&ub->timer)) | 331 | if (timer_pending(&ub->timer)) |
329 | del_timer(&ub->timer); | 332 | del_timer(&ub->timer); |
330 | spin_lock_bh(&ub->lock); | 333 | spin_lock_bh(&ub->lock); |
331 | if (ub->skb) { | 334 | if (ub->skb) { |
332 | kfree_skb(ub->skb); | 335 | kfree_skb(ub->skb); |
333 | ub->skb = NULL; | 336 | ub->skb = NULL; |
334 | } | 337 | } |
335 | spin_unlock_bh(&ub->lock); | 338 | spin_unlock_bh(&ub->lock); |
336 | } | 339 | } |
337 | netlink_kernel_release(ebtulognl); | 340 | netlink_kernel_release(ebtulognl); |
338 | } | 341 | } |
339 | 342 | ||
340 | module_init(ebt_ulog_init); | 343 | module_init(ebt_ulog_init); |
341 | module_exit(ebt_ulog_fini); | 344 | module_exit(ebt_ulog_fini); |
342 | MODULE_LICENSE("GPL"); | 345 | MODULE_LICENSE("GPL"); |
343 | MODULE_AUTHOR("Bart De Schuymer <bdschuym@pandora.be>"); | 346 | MODULE_AUTHOR("Bart De Schuymer <bdschuym@pandora.be>"); |
344 | MODULE_DESCRIPTION("Ebtables: Packet logging to netlink using ULOG"); | 347 | MODULE_DESCRIPTION("Ebtables: Packet logging to netlink using ULOG"); |
net/bridge/netfilter/ebt_vlan.c
1 | /* | 1 | /* |
2 | * Description: EBTables 802.1Q match extension kernelspace module. | 2 | * Description: EBTables 802.1Q match extension kernelspace module. |
3 | * Authors: Nick Fedchik <nick@fedchik.org.ua> | 3 | * Authors: Nick Fedchik <nick@fedchik.org.ua> |
4 | * Bart De Schuymer <bdschuym@pandora.be> | 4 | * Bart De Schuymer <bdschuym@pandora.be> |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by | 7 | * it under the terms of the GNU General Public License as published by |
8 | * the Free Software Foundation; either version 2 of the License, or | 8 | * the Free Software Foundation; either version 2 of the License, or |
9 | * (at your option) any later version. | 9 | * (at your option) any later version. |
10 | * | 10 | * |
11 | * This program is distributed in the hope that it will be useful, | 11 | * This program is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | * GNU General Public License for more details. | 14 | * GNU General Public License for more details. |
15 | * | 15 | * |
16 | * You should have received a copy of the GNU General Public License | 16 | * You should have received a copy of the GNU General Public License |
17 | * along with this program; if not, write to the Free Software | 17 | * along with this program; if not, write to the Free Software |
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <linux/if_ether.h> | 21 | #include <linux/if_ether.h> |
22 | #include <linux/if_vlan.h> | 22 | #include <linux/if_vlan.h> |
23 | #include <linux/module.h> | 23 | #include <linux/module.h> |
24 | #include <linux/moduleparam.h> | 24 | #include <linux/moduleparam.h> |
25 | #include <linux/netfilter/x_tables.h> | 25 | #include <linux/netfilter/x_tables.h> |
26 | #include <linux/netfilter_bridge/ebtables.h> | 26 | #include <linux/netfilter_bridge/ebtables.h> |
27 | #include <linux/netfilter_bridge/ebt_vlan.h> | 27 | #include <linux/netfilter_bridge/ebt_vlan.h> |
28 | 28 | ||
29 | static int debug; | 29 | static int debug; |
30 | #define MODULE_VERS "0.6" | 30 | #define MODULE_VERS "0.6" |
31 | 31 | ||
32 | module_param(debug, int, 0); | 32 | module_param(debug, int, 0); |
33 | MODULE_PARM_DESC(debug, "debug=1 is turn on debug messages"); | 33 | MODULE_PARM_DESC(debug, "debug=1 is turn on debug messages"); |
34 | MODULE_AUTHOR("Nick Fedchik <nick@fedchik.org.ua>"); | 34 | MODULE_AUTHOR("Nick Fedchik <nick@fedchik.org.ua>"); |
35 | MODULE_DESCRIPTION("Ebtables: 802.1Q VLAN tag match"); | 35 | MODULE_DESCRIPTION("Ebtables: 802.1Q VLAN tag match"); |
36 | MODULE_LICENSE("GPL"); | 36 | MODULE_LICENSE("GPL"); |
37 | 37 | ||
38 | 38 | ||
39 | #define DEBUG_MSG(args...) if (debug) printk (KERN_DEBUG "ebt_vlan: " args) | 39 | #define DEBUG_MSG(args...) if (debug) printk (KERN_DEBUG "ebt_vlan: " args) |
40 | #define GET_BITMASK(_BIT_MASK_) info->bitmask & _BIT_MASK_ | 40 | #define GET_BITMASK(_BIT_MASK_) info->bitmask & _BIT_MASK_ |
41 | #define EXIT_ON_MISMATCH(_MATCH_,_MASK_) {if (!((info->_MATCH_ == _MATCH_)^!!(info->invflags & _MASK_))) return EBT_NOMATCH;} | 41 | #define EXIT_ON_MISMATCH(_MATCH_,_MASK_) {if (!((info->_MATCH_ == _MATCH_)^!!(info->invflags & _MASK_))) return EBT_NOMATCH;} |
42 | 42 | ||
43 | static int | 43 | static int |
44 | ebt_filter_vlan(const struct sk_buff *skb, | 44 | ebt_filter_vlan(const struct sk_buff *skb, |
45 | const struct net_device *in, | 45 | const struct net_device *in, |
46 | const struct net_device *out, | 46 | const struct net_device *out, |
47 | const void *data, unsigned int datalen) | 47 | const void *data, unsigned int datalen) |
48 | { | 48 | { |
49 | const struct ebt_vlan_info *info = data; | 49 | const struct ebt_vlan_info *info = data; |
50 | const struct vlan_hdr *fp; | 50 | const struct vlan_hdr *fp; |
51 | struct vlan_hdr _frame; | 51 | struct vlan_hdr _frame; |
52 | 52 | ||
53 | unsigned short TCI; /* Whole TCI, given from parsed frame */ | 53 | unsigned short TCI; /* Whole TCI, given from parsed frame */ |
54 | unsigned short id; /* VLAN ID, given from frame TCI */ | 54 | unsigned short id; /* VLAN ID, given from frame TCI */ |
55 | unsigned char prio; /* user_priority, given from frame TCI */ | 55 | unsigned char prio; /* user_priority, given from frame TCI */ |
56 | /* VLAN encapsulated Type/Length field, given from orig frame */ | 56 | /* VLAN encapsulated Type/Length field, given from orig frame */ |
57 | __be16 encap; | 57 | __be16 encap; |
58 | 58 | ||
59 | fp = skb_header_pointer(skb, 0, sizeof(_frame), &_frame); | 59 | fp = skb_header_pointer(skb, 0, sizeof(_frame), &_frame); |
60 | if (fp == NULL) | 60 | if (fp == NULL) |
61 | return EBT_NOMATCH; | 61 | return EBT_NOMATCH; |
62 | 62 | ||
63 | /* Tag Control Information (TCI) consists of the following elements: | 63 | /* Tag Control Information (TCI) consists of the following elements: |
64 | * - User_priority. The user_priority field is three bits in length, | 64 | * - User_priority. The user_priority field is three bits in length, |
65 | * interpreted as a binary number. | 65 | * interpreted as a binary number. |
66 | * - Canonical Format Indicator (CFI). The Canonical Format Indicator | 66 | * - Canonical Format Indicator (CFI). The Canonical Format Indicator |
67 | * (CFI) is a single bit flag value. Currently ignored. | 67 | * (CFI) is a single bit flag value. Currently ignored. |
68 | * - VLAN Identifier (VID). The VID is encoded as | 68 | * - VLAN Identifier (VID). The VID is encoded as |
69 | * an unsigned binary number. */ | 69 | * an unsigned binary number. */ |
70 | TCI = ntohs(fp->h_vlan_TCI); | 70 | TCI = ntohs(fp->h_vlan_TCI); |
71 | id = TCI & VLAN_VID_MASK; | 71 | id = TCI & VLAN_VID_MASK; |
72 | prio = (TCI >> 13) & 0x7; | 72 | prio = (TCI >> 13) & 0x7; |
73 | encap = fp->h_vlan_encapsulated_proto; | 73 | encap = fp->h_vlan_encapsulated_proto; |
74 | 74 | ||
75 | /* Checking VLAN Identifier (VID) */ | 75 | /* Checking VLAN Identifier (VID) */ |
76 | if (GET_BITMASK(EBT_VLAN_ID)) | 76 | if (GET_BITMASK(EBT_VLAN_ID)) |
77 | EXIT_ON_MISMATCH(id, EBT_VLAN_ID); | 77 | EXIT_ON_MISMATCH(id, EBT_VLAN_ID); |
78 | 78 | ||
79 | /* Checking user_priority */ | 79 | /* Checking user_priority */ |
80 | if (GET_BITMASK(EBT_VLAN_PRIO)) | 80 | if (GET_BITMASK(EBT_VLAN_PRIO)) |
81 | EXIT_ON_MISMATCH(prio, EBT_VLAN_PRIO); | 81 | EXIT_ON_MISMATCH(prio, EBT_VLAN_PRIO); |
82 | 82 | ||
83 | /* Checking Encapsulated Proto (Length/Type) field */ | 83 | /* Checking Encapsulated Proto (Length/Type) field */ |
84 | if (GET_BITMASK(EBT_VLAN_ENCAP)) | 84 | if (GET_BITMASK(EBT_VLAN_ENCAP)) |
85 | EXIT_ON_MISMATCH(encap, EBT_VLAN_ENCAP); | 85 | EXIT_ON_MISMATCH(encap, EBT_VLAN_ENCAP); |
86 | 86 | ||
87 | return EBT_MATCH; | 87 | return EBT_MATCH; |
88 | } | 88 | } |
89 | 89 | ||
90 | static int | 90 | static bool |
91 | ebt_check_vlan(const char *tablename, | 91 | ebt_check_vlan(const char *tablename, |
92 | unsigned int hooknr, | 92 | unsigned int hooknr, |
93 | const struct ebt_entry *e, void *data, unsigned int datalen) | 93 | const struct ebt_entry *e, void *data, unsigned int datalen) |
94 | { | 94 | { |
95 | struct ebt_vlan_info *info = data; | 95 | struct ebt_vlan_info *info = data; |
96 | 96 | ||
97 | /* Is it 802.1Q frame checked? */ | 97 | /* Is it 802.1Q frame checked? */ |
98 | if (e->ethproto != htons(ETH_P_8021Q)) { | 98 | if (e->ethproto != htons(ETH_P_8021Q)) { |
99 | DEBUG_MSG | 99 | DEBUG_MSG |
100 | ("passed entry proto %2.4X is not 802.1Q (8100)\n", | 100 | ("passed entry proto %2.4X is not 802.1Q (8100)\n", |
101 | (unsigned short) ntohs(e->ethproto)); | 101 | (unsigned short) ntohs(e->ethproto)); |
102 | return -EINVAL; | 102 | return false; |
103 | } | 103 | } |
104 | 104 | ||
105 | /* Check for bitmask range | 105 | /* Check for bitmask range |
106 | * True if even one bit is out of mask */ | 106 | * True if even one bit is out of mask */ |
107 | if (info->bitmask & ~EBT_VLAN_MASK) { | 107 | if (info->bitmask & ~EBT_VLAN_MASK) { |
108 | DEBUG_MSG("bitmask %2X is out of mask (%2X)\n", | 108 | DEBUG_MSG("bitmask %2X is out of mask (%2X)\n", |
109 | info->bitmask, EBT_VLAN_MASK); | 109 | info->bitmask, EBT_VLAN_MASK); |
110 | return -EINVAL; | 110 | return false; |
111 | } | 111 | } |
112 | 112 | ||
113 | /* Check for inversion flags range */ | 113 | /* Check for inversion flags range */ |
114 | if (info->invflags & ~EBT_VLAN_MASK) { | 114 | if (info->invflags & ~EBT_VLAN_MASK) { |
115 | DEBUG_MSG("inversion flags %2X is out of mask (%2X)\n", | 115 | DEBUG_MSG("inversion flags %2X is out of mask (%2X)\n", |
116 | info->invflags, EBT_VLAN_MASK); | 116 | info->invflags, EBT_VLAN_MASK); |
117 | return -EINVAL; | 117 | return false; |
118 | } | 118 | } |
119 | 119 | ||
120 | /* Reserved VLAN ID (VID) values | 120 | /* Reserved VLAN ID (VID) values |
121 | * ----------------------------- | 121 | * ----------------------------- |
122 | * 0 - The null VLAN ID. | 122 | * 0 - The null VLAN ID. |
123 | * 1 - The default Port VID (PVID) | 123 | * 1 - The default Port VID (PVID) |
124 | * 0x0FFF - Reserved for implementation use. | 124 | * 0x0FFF - Reserved for implementation use. |
125 | * if_vlan.h: VLAN_GROUP_ARRAY_LEN 4096. */ | 125 | * if_vlan.h: VLAN_GROUP_ARRAY_LEN 4096. */ |
126 | if (GET_BITMASK(EBT_VLAN_ID)) { | 126 | if (GET_BITMASK(EBT_VLAN_ID)) { |
127 | if (!!info->id) { /* if id!=0 => check vid range */ | 127 | if (!!info->id) { /* if id!=0 => check vid range */ |
128 | if (info->id > VLAN_GROUP_ARRAY_LEN) { | 128 | if (info->id > VLAN_GROUP_ARRAY_LEN) { |
129 | DEBUG_MSG | 129 | DEBUG_MSG |
130 | ("id %d is out of range (1-4096)\n", | 130 | ("id %d is out of range (1-4096)\n", |
131 | info->id); | 131 | info->id); |
132 | return -EINVAL; | 132 | return false; |
133 | } | 133 | } |
134 | /* Note: This is valid VLAN-tagged frame point. | 134 | /* Note: This is valid VLAN-tagged frame point. |
135 | * Any value of user_priority are acceptable, | 135 | * Any value of user_priority are acceptable, |
136 | * but should be ignored according to 802.1Q Std. | 136 | * but should be ignored according to 802.1Q Std. |
137 | * So we just drop the prio flag. */ | 137 | * So we just drop the prio flag. */ |
138 | info->bitmask &= ~EBT_VLAN_PRIO; | 138 | info->bitmask &= ~EBT_VLAN_PRIO; |
139 | } | 139 | } |
140 | /* Else, id=0 (null VLAN ID) => user_priority range (any?) */ | 140 | /* Else, id=0 (null VLAN ID) => user_priority range (any?) */ |
141 | } | 141 | } |
142 | 142 | ||
143 | if (GET_BITMASK(EBT_VLAN_PRIO)) { | 143 | if (GET_BITMASK(EBT_VLAN_PRIO)) { |
144 | if ((unsigned char) info->prio > 7) { | 144 | if ((unsigned char) info->prio > 7) { |
145 | DEBUG_MSG("prio %d is out of range (0-7)\n", | 145 | DEBUG_MSG("prio %d is out of range (0-7)\n", |
146 | info->prio); | 146 | info->prio); |
147 | return -EINVAL; | 147 | return false; |
148 | } | 148 | } |
149 | } | 149 | } |
150 | /* Check for encapsulated proto range - it is possible to be | 150 | /* Check for encapsulated proto range - it is possible to be |
151 | * any value for u_short range. | 151 | * any value for u_short range. |
152 | * if_ether.h: ETH_ZLEN 60 - Min. octets in frame sans FCS */ | 152 | * if_ether.h: ETH_ZLEN 60 - Min. octets in frame sans FCS */ |
153 | if (GET_BITMASK(EBT_VLAN_ENCAP)) { | 153 | if (GET_BITMASK(EBT_VLAN_ENCAP)) { |
154 | if ((unsigned short) ntohs(info->encap) < ETH_ZLEN) { | 154 | if ((unsigned short) ntohs(info->encap) < ETH_ZLEN) { |
155 | DEBUG_MSG | 155 | DEBUG_MSG |
156 | ("encap frame length %d is less than minimal\n", | 156 | ("encap frame length %d is less than minimal\n", |
157 | ntohs(info->encap)); | 157 | ntohs(info->encap)); |
158 | return -EINVAL; | 158 | return false; |
159 | } | 159 | } |
160 | } | 160 | } |
161 | 161 | ||
162 | return 0; | 162 | return true; |
163 | } | 163 | } |
164 | 164 | ||
165 | static struct ebt_match filter_vlan __read_mostly = { | 165 | static struct ebt_match filter_vlan __read_mostly = { |
166 | .name = EBT_VLAN_MATCH, | 166 | .name = EBT_VLAN_MATCH, |
167 | .match = ebt_filter_vlan, | 167 | .match = ebt_filter_vlan, |
168 | .check = ebt_check_vlan, | 168 | .check = ebt_check_vlan, |
169 | .matchsize = XT_ALIGN(sizeof(struct ebt_vlan_info)), | 169 | .matchsize = XT_ALIGN(sizeof(struct ebt_vlan_info)), |
170 | .me = THIS_MODULE, | 170 | .me = THIS_MODULE, |
171 | }; | 171 | }; |
172 | 172 | ||
173 | static int __init ebt_vlan_init(void) | 173 | static int __init ebt_vlan_init(void) |
174 | { | 174 | { |
175 | DEBUG_MSG("ebtables 802.1Q extension module v" | 175 | DEBUG_MSG("ebtables 802.1Q extension module v" |
176 | MODULE_VERS "\n"); | 176 | MODULE_VERS "\n"); |
177 | DEBUG_MSG("module debug=%d\n", !!debug); | 177 | DEBUG_MSG("module debug=%d\n", !!debug); |
178 | return ebt_register_match(&filter_vlan); | 178 | return ebt_register_match(&filter_vlan); |
179 | } | 179 | } |
180 | 180 | ||
181 | static void __exit ebt_vlan_fini(void) | 181 | static void __exit ebt_vlan_fini(void) |
182 | { | 182 | { |
183 | ebt_unregister_match(&filter_vlan); | 183 | ebt_unregister_match(&filter_vlan); |
184 | } | 184 | } |
185 | 185 | ||
186 | module_init(ebt_vlan_init); | 186 | module_init(ebt_vlan_init); |
187 | module_exit(ebt_vlan_fini); | 187 | module_exit(ebt_vlan_fini); |
188 | 188 |
net/bridge/netfilter/ebtables.c
1 | /* | 1 | /* |
2 | * ebtables | 2 | * ebtables |
3 | * | 3 | * |
4 | * Author: | 4 | * Author: |
5 | * Bart De Schuymer <bdschuym@pandora.be> | 5 | * Bart De Schuymer <bdschuym@pandora.be> |
6 | * | 6 | * |
7 | * ebtables.c,v 2.0, July, 2002 | 7 | * ebtables.c,v 2.0, July, 2002 |
8 | * | 8 | * |
9 | * This code is stongly inspired on the iptables code which is | 9 | * This code is stongly inspired on the iptables code which is |
10 | * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling | 10 | * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling |
11 | * | 11 | * |
12 | * This program is free software; you can redistribute it and/or | 12 | * This program is free software; you can redistribute it and/or |
13 | * modify it under the terms of the GNU General Public License | 13 | * modify it under the terms of the GNU General Public License |
14 | * as published by the Free Software Foundation; either version | 14 | * as published by the Free Software Foundation; either version |
15 | * 2 of the License, or (at your option) any later version. | 15 | * 2 of the License, or (at your option) any later version. |
16 | */ | 16 | */ |
17 | 17 | ||
18 | 18 | ||
19 | #include <linux/kmod.h> | 19 | #include <linux/kmod.h> |
20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
21 | #include <linux/vmalloc.h> | 21 | #include <linux/vmalloc.h> |
22 | #include <linux/netfilter/x_tables.h> | 22 | #include <linux/netfilter/x_tables.h> |
23 | #include <linux/netfilter_bridge/ebtables.h> | 23 | #include <linux/netfilter_bridge/ebtables.h> |
24 | #include <linux/spinlock.h> | 24 | #include <linux/spinlock.h> |
25 | #include <linux/mutex.h> | 25 | #include <linux/mutex.h> |
26 | #include <asm/uaccess.h> | 26 | #include <asm/uaccess.h> |
27 | #include <linux/smp.h> | 27 | #include <linux/smp.h> |
28 | #include <linux/cpumask.h> | 28 | #include <linux/cpumask.h> |
29 | #include <net/sock.h> | 29 | #include <net/sock.h> |
30 | /* needed for logical [in,out]-dev filtering */ | 30 | /* needed for logical [in,out]-dev filtering */ |
31 | #include "../br_private.h" | 31 | #include "../br_private.h" |
32 | 32 | ||
33 | #define BUGPRINT(format, args...) printk("kernel msg: ebtables bug: please "\ | 33 | #define BUGPRINT(format, args...) printk("kernel msg: ebtables bug: please "\ |
34 | "report to author: "format, ## args) | 34 | "report to author: "format, ## args) |
35 | /* #define BUGPRINT(format, args...) */ | 35 | /* #define BUGPRINT(format, args...) */ |
36 | #define MEMPRINT(format, args...) printk("kernel msg: ebtables "\ | 36 | #define MEMPRINT(format, args...) printk("kernel msg: ebtables "\ |
37 | ": out of memory: "format, ## args) | 37 | ": out of memory: "format, ## args) |
38 | /* #define MEMPRINT(format, args...) */ | 38 | /* #define MEMPRINT(format, args...) */ |
39 | 39 | ||
40 | 40 | ||
41 | 41 | ||
42 | /* | 42 | /* |
43 | * Each cpu has its own set of counters, so there is no need for write_lock in | 43 | * Each cpu has its own set of counters, so there is no need for write_lock in |
44 | * the softirq | 44 | * the softirq |
45 | * For reading or updating the counters, the user context needs to | 45 | * For reading or updating the counters, the user context needs to |
46 | * get a write_lock | 46 | * get a write_lock |
47 | */ | 47 | */ |
48 | 48 | ||
49 | /* The size of each set of counters is altered to get cache alignment */ | 49 | /* The size of each set of counters is altered to get cache alignment */ |
50 | #define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1)) | 50 | #define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1)) |
51 | #define COUNTER_OFFSET(n) (SMP_ALIGN(n * sizeof(struct ebt_counter))) | 51 | #define COUNTER_OFFSET(n) (SMP_ALIGN(n * sizeof(struct ebt_counter))) |
52 | #define COUNTER_BASE(c, n, cpu) ((struct ebt_counter *)(((char *)c) + \ | 52 | #define COUNTER_BASE(c, n, cpu) ((struct ebt_counter *)(((char *)c) + \ |
53 | COUNTER_OFFSET(n) * cpu)) | 53 | COUNTER_OFFSET(n) * cpu)) |
54 | 54 | ||
55 | 55 | ||
56 | 56 | ||
57 | static DEFINE_MUTEX(ebt_mutex); | 57 | static DEFINE_MUTEX(ebt_mutex); |
58 | static LIST_HEAD(ebt_tables); | 58 | static LIST_HEAD(ebt_tables); |
59 | static LIST_HEAD(ebt_targets); | 59 | static LIST_HEAD(ebt_targets); |
60 | static LIST_HEAD(ebt_matches); | 60 | static LIST_HEAD(ebt_matches); |
61 | static LIST_HEAD(ebt_watchers); | 61 | static LIST_HEAD(ebt_watchers); |
62 | 62 | ||
63 | static struct ebt_target ebt_standard_target = { | 63 | static struct ebt_target ebt_standard_target = { |
64 | .name = "standard", | 64 | .name = "standard", |
65 | }; | 65 | }; |
66 | 66 | ||
67 | static inline int ebt_do_watcher (struct ebt_entry_watcher *w, | 67 | static inline int ebt_do_watcher (struct ebt_entry_watcher *w, |
68 | const struct sk_buff *skb, unsigned int hooknr, const struct net_device *in, | 68 | const struct sk_buff *skb, unsigned int hooknr, const struct net_device *in, |
69 | const struct net_device *out) | 69 | const struct net_device *out) |
70 | { | 70 | { |
71 | w->u.watcher->watcher(skb, hooknr, in, out, w->data, | 71 | w->u.watcher->watcher(skb, hooknr, in, out, w->data, |
72 | w->watcher_size); | 72 | w->watcher_size); |
73 | /* watchers don't give a verdict */ | 73 | /* watchers don't give a verdict */ |
74 | return 0; | 74 | return 0; |
75 | } | 75 | } |
76 | 76 | ||
77 | static inline int ebt_do_match (struct ebt_entry_match *m, | 77 | static inline int ebt_do_match (struct ebt_entry_match *m, |
78 | const struct sk_buff *skb, const struct net_device *in, | 78 | const struct sk_buff *skb, const struct net_device *in, |
79 | const struct net_device *out) | 79 | const struct net_device *out) |
80 | { | 80 | { |
81 | return m->u.match->match(skb, in, out, m->data, | 81 | return m->u.match->match(skb, in, out, m->data, |
82 | m->match_size); | 82 | m->match_size); |
83 | } | 83 | } |
84 | 84 | ||
85 | static inline int ebt_dev_check(char *entry, const struct net_device *device) | 85 | static inline int ebt_dev_check(char *entry, const struct net_device *device) |
86 | { | 86 | { |
87 | int i = 0; | 87 | int i = 0; |
88 | const char *devname = device->name; | 88 | const char *devname = device->name; |
89 | 89 | ||
90 | if (*entry == '\0') | 90 | if (*entry == '\0') |
91 | return 0; | 91 | return 0; |
92 | if (!device) | 92 | if (!device) |
93 | return 1; | 93 | return 1; |
94 | /* 1 is the wildcard token */ | 94 | /* 1 is the wildcard token */ |
95 | while (entry[i] != '\0' && entry[i] != 1 && entry[i] == devname[i]) | 95 | while (entry[i] != '\0' && entry[i] != 1 && entry[i] == devname[i]) |
96 | i++; | 96 | i++; |
97 | return (devname[i] != entry[i] && entry[i] != 1); | 97 | return (devname[i] != entry[i] && entry[i] != 1); |
98 | } | 98 | } |
99 | 99 | ||
100 | #define FWINV2(bool,invflg) ((bool) ^ !!(e->invflags & invflg)) | 100 | #define FWINV2(bool,invflg) ((bool) ^ !!(e->invflags & invflg)) |
101 | /* process standard matches */ | 101 | /* process standard matches */ |
102 | static inline int ebt_basic_match(struct ebt_entry *e, struct ethhdr *h, | 102 | static inline int ebt_basic_match(struct ebt_entry *e, struct ethhdr *h, |
103 | const struct net_device *in, const struct net_device *out) | 103 | const struct net_device *in, const struct net_device *out) |
104 | { | 104 | { |
105 | int verdict, i; | 105 | int verdict, i; |
106 | 106 | ||
107 | if (e->bitmask & EBT_802_3) { | 107 | if (e->bitmask & EBT_802_3) { |
108 | if (FWINV2(ntohs(h->h_proto) >= 1536, EBT_IPROTO)) | 108 | if (FWINV2(ntohs(h->h_proto) >= 1536, EBT_IPROTO)) |
109 | return 1; | 109 | return 1; |
110 | } else if (!(e->bitmask & EBT_NOPROTO) && | 110 | } else if (!(e->bitmask & EBT_NOPROTO) && |
111 | FWINV2(e->ethproto != h->h_proto, EBT_IPROTO)) | 111 | FWINV2(e->ethproto != h->h_proto, EBT_IPROTO)) |
112 | return 1; | 112 | return 1; |
113 | 113 | ||
114 | if (FWINV2(ebt_dev_check(e->in, in), EBT_IIN)) | 114 | if (FWINV2(ebt_dev_check(e->in, in), EBT_IIN)) |
115 | return 1; | 115 | return 1; |
116 | if (FWINV2(ebt_dev_check(e->out, out), EBT_IOUT)) | 116 | if (FWINV2(ebt_dev_check(e->out, out), EBT_IOUT)) |
117 | return 1; | 117 | return 1; |
118 | if ((!in || !in->br_port) ? 0 : FWINV2(ebt_dev_check( | 118 | if ((!in || !in->br_port) ? 0 : FWINV2(ebt_dev_check( |
119 | e->logical_in, in->br_port->br->dev), EBT_ILOGICALIN)) | 119 | e->logical_in, in->br_port->br->dev), EBT_ILOGICALIN)) |
120 | return 1; | 120 | return 1; |
121 | if ((!out || !out->br_port) ? 0 : FWINV2(ebt_dev_check( | 121 | if ((!out || !out->br_port) ? 0 : FWINV2(ebt_dev_check( |
122 | e->logical_out, out->br_port->br->dev), EBT_ILOGICALOUT)) | 122 | e->logical_out, out->br_port->br->dev), EBT_ILOGICALOUT)) |
123 | return 1; | 123 | return 1; |
124 | 124 | ||
125 | if (e->bitmask & EBT_SOURCEMAC) { | 125 | if (e->bitmask & EBT_SOURCEMAC) { |
126 | verdict = 0; | 126 | verdict = 0; |
127 | for (i = 0; i < 6; i++) | 127 | for (i = 0; i < 6; i++) |
128 | verdict |= (h->h_source[i] ^ e->sourcemac[i]) & | 128 | verdict |= (h->h_source[i] ^ e->sourcemac[i]) & |
129 | e->sourcemsk[i]; | 129 | e->sourcemsk[i]; |
130 | if (FWINV2(verdict != 0, EBT_ISOURCE) ) | 130 | if (FWINV2(verdict != 0, EBT_ISOURCE) ) |
131 | return 1; | 131 | return 1; |
132 | } | 132 | } |
133 | if (e->bitmask & EBT_DESTMAC) { | 133 | if (e->bitmask & EBT_DESTMAC) { |
134 | verdict = 0; | 134 | verdict = 0; |
135 | for (i = 0; i < 6; i++) | 135 | for (i = 0; i < 6; i++) |
136 | verdict |= (h->h_dest[i] ^ e->destmac[i]) & | 136 | verdict |= (h->h_dest[i] ^ e->destmac[i]) & |
137 | e->destmsk[i]; | 137 | e->destmsk[i]; |
138 | if (FWINV2(verdict != 0, EBT_IDEST) ) | 138 | if (FWINV2(verdict != 0, EBT_IDEST) ) |
139 | return 1; | 139 | return 1; |
140 | } | 140 | } |
141 | return 0; | 141 | return 0; |
142 | } | 142 | } |
143 | 143 | ||
144 | /* Do some firewalling */ | 144 | /* Do some firewalling */ |
145 | unsigned int ebt_do_table (unsigned int hook, struct sk_buff *skb, | 145 | unsigned int ebt_do_table (unsigned int hook, struct sk_buff *skb, |
146 | const struct net_device *in, const struct net_device *out, | 146 | const struct net_device *in, const struct net_device *out, |
147 | struct ebt_table *table) | 147 | struct ebt_table *table) |
148 | { | 148 | { |
149 | int i, nentries; | 149 | int i, nentries; |
150 | struct ebt_entry *point; | 150 | struct ebt_entry *point; |
151 | struct ebt_counter *counter_base, *cb_base; | 151 | struct ebt_counter *counter_base, *cb_base; |
152 | struct ebt_entry_target *t; | 152 | struct ebt_entry_target *t; |
153 | int verdict, sp = 0; | 153 | int verdict, sp = 0; |
154 | struct ebt_chainstack *cs; | 154 | struct ebt_chainstack *cs; |
155 | struct ebt_entries *chaininfo; | 155 | struct ebt_entries *chaininfo; |
156 | char *base; | 156 | char *base; |
157 | struct ebt_table_info *private; | 157 | struct ebt_table_info *private; |
158 | 158 | ||
159 | read_lock_bh(&table->lock); | 159 | read_lock_bh(&table->lock); |
160 | private = table->private; | 160 | private = table->private; |
161 | cb_base = COUNTER_BASE(private->counters, private->nentries, | 161 | cb_base = COUNTER_BASE(private->counters, private->nentries, |
162 | smp_processor_id()); | 162 | smp_processor_id()); |
163 | if (private->chainstack) | 163 | if (private->chainstack) |
164 | cs = private->chainstack[smp_processor_id()]; | 164 | cs = private->chainstack[smp_processor_id()]; |
165 | else | 165 | else |
166 | cs = NULL; | 166 | cs = NULL; |
167 | chaininfo = private->hook_entry[hook]; | 167 | chaininfo = private->hook_entry[hook]; |
168 | nentries = private->hook_entry[hook]->nentries; | 168 | nentries = private->hook_entry[hook]->nentries; |
169 | point = (struct ebt_entry *)(private->hook_entry[hook]->data); | 169 | point = (struct ebt_entry *)(private->hook_entry[hook]->data); |
170 | counter_base = cb_base + private->hook_entry[hook]->counter_offset; | 170 | counter_base = cb_base + private->hook_entry[hook]->counter_offset; |
171 | /* base for chain jumps */ | 171 | /* base for chain jumps */ |
172 | base = private->entries; | 172 | base = private->entries; |
173 | i = 0; | 173 | i = 0; |
174 | while (i < nentries) { | 174 | while (i < nentries) { |
175 | if (ebt_basic_match(point, eth_hdr(skb), in, out)) | 175 | if (ebt_basic_match(point, eth_hdr(skb), in, out)) |
176 | goto letscontinue; | 176 | goto letscontinue; |
177 | 177 | ||
178 | if (EBT_MATCH_ITERATE(point, ebt_do_match, skb, in, out) != 0) | 178 | if (EBT_MATCH_ITERATE(point, ebt_do_match, skb, in, out) != 0) |
179 | goto letscontinue; | 179 | goto letscontinue; |
180 | 180 | ||
181 | /* increase counter */ | 181 | /* increase counter */ |
182 | (*(counter_base + i)).pcnt++; | 182 | (*(counter_base + i)).pcnt++; |
183 | (*(counter_base + i)).bcnt += skb->len; | 183 | (*(counter_base + i)).bcnt += skb->len; |
184 | 184 | ||
185 | /* these should only watch: not modify, nor tell us | 185 | /* these should only watch: not modify, nor tell us |
186 | what to do with the packet */ | 186 | what to do with the packet */ |
187 | EBT_WATCHER_ITERATE(point, ebt_do_watcher, skb, hook, in, | 187 | EBT_WATCHER_ITERATE(point, ebt_do_watcher, skb, hook, in, |
188 | out); | 188 | out); |
189 | 189 | ||
190 | t = (struct ebt_entry_target *) | 190 | t = (struct ebt_entry_target *) |
191 | (((char *)point) + point->target_offset); | 191 | (((char *)point) + point->target_offset); |
192 | /* standard target */ | 192 | /* standard target */ |
193 | if (!t->u.target->target) | 193 | if (!t->u.target->target) |
194 | verdict = ((struct ebt_standard_target *)t)->verdict; | 194 | verdict = ((struct ebt_standard_target *)t)->verdict; |
195 | else | 195 | else |
196 | verdict = t->u.target->target(skb, hook, | 196 | verdict = t->u.target->target(skb, hook, |
197 | in, out, t->data, t->target_size); | 197 | in, out, t->data, t->target_size); |
198 | if (verdict == EBT_ACCEPT) { | 198 | if (verdict == EBT_ACCEPT) { |
199 | read_unlock_bh(&table->lock); | 199 | read_unlock_bh(&table->lock); |
200 | return NF_ACCEPT; | 200 | return NF_ACCEPT; |
201 | } | 201 | } |
202 | if (verdict == EBT_DROP) { | 202 | if (verdict == EBT_DROP) { |
203 | read_unlock_bh(&table->lock); | 203 | read_unlock_bh(&table->lock); |
204 | return NF_DROP; | 204 | return NF_DROP; |
205 | } | 205 | } |
206 | if (verdict == EBT_RETURN) { | 206 | if (verdict == EBT_RETURN) { |
207 | letsreturn: | 207 | letsreturn: |
208 | #ifdef CONFIG_NETFILTER_DEBUG | 208 | #ifdef CONFIG_NETFILTER_DEBUG |
209 | if (sp == 0) { | 209 | if (sp == 0) { |
210 | BUGPRINT("RETURN on base chain"); | 210 | BUGPRINT("RETURN on base chain"); |
211 | /* act like this is EBT_CONTINUE */ | 211 | /* act like this is EBT_CONTINUE */ |
212 | goto letscontinue; | 212 | goto letscontinue; |
213 | } | 213 | } |
214 | #endif | 214 | #endif |
215 | sp--; | 215 | sp--; |
216 | /* put all the local variables right */ | 216 | /* put all the local variables right */ |
217 | i = cs[sp].n; | 217 | i = cs[sp].n; |
218 | chaininfo = cs[sp].chaininfo; | 218 | chaininfo = cs[sp].chaininfo; |
219 | nentries = chaininfo->nentries; | 219 | nentries = chaininfo->nentries; |
220 | point = cs[sp].e; | 220 | point = cs[sp].e; |
221 | counter_base = cb_base + | 221 | counter_base = cb_base + |
222 | chaininfo->counter_offset; | 222 | chaininfo->counter_offset; |
223 | continue; | 223 | continue; |
224 | } | 224 | } |
225 | if (verdict == EBT_CONTINUE) | 225 | if (verdict == EBT_CONTINUE) |
226 | goto letscontinue; | 226 | goto letscontinue; |
227 | #ifdef CONFIG_NETFILTER_DEBUG | 227 | #ifdef CONFIG_NETFILTER_DEBUG |
228 | if (verdict < 0) { | 228 | if (verdict < 0) { |
229 | BUGPRINT("bogus standard verdict\n"); | 229 | BUGPRINT("bogus standard verdict\n"); |
230 | read_unlock_bh(&table->lock); | 230 | read_unlock_bh(&table->lock); |
231 | return NF_DROP; | 231 | return NF_DROP; |
232 | } | 232 | } |
233 | #endif | 233 | #endif |
234 | /* jump to a udc */ | 234 | /* jump to a udc */ |
235 | cs[sp].n = i + 1; | 235 | cs[sp].n = i + 1; |
236 | cs[sp].chaininfo = chaininfo; | 236 | cs[sp].chaininfo = chaininfo; |
237 | cs[sp].e = (struct ebt_entry *) | 237 | cs[sp].e = (struct ebt_entry *) |
238 | (((char *)point) + point->next_offset); | 238 | (((char *)point) + point->next_offset); |
239 | i = 0; | 239 | i = 0; |
240 | chaininfo = (struct ebt_entries *) (base + verdict); | 240 | chaininfo = (struct ebt_entries *) (base + verdict); |
241 | #ifdef CONFIG_NETFILTER_DEBUG | 241 | #ifdef CONFIG_NETFILTER_DEBUG |
242 | if (chaininfo->distinguisher) { | 242 | if (chaininfo->distinguisher) { |
243 | BUGPRINT("jump to non-chain\n"); | 243 | BUGPRINT("jump to non-chain\n"); |
244 | read_unlock_bh(&table->lock); | 244 | read_unlock_bh(&table->lock); |
245 | return NF_DROP; | 245 | return NF_DROP; |
246 | } | 246 | } |
247 | #endif | 247 | #endif |
248 | nentries = chaininfo->nentries; | 248 | nentries = chaininfo->nentries; |
249 | point = (struct ebt_entry *)chaininfo->data; | 249 | point = (struct ebt_entry *)chaininfo->data; |
250 | counter_base = cb_base + chaininfo->counter_offset; | 250 | counter_base = cb_base + chaininfo->counter_offset; |
251 | sp++; | 251 | sp++; |
252 | continue; | 252 | continue; |
253 | letscontinue: | 253 | letscontinue: |
254 | point = (struct ebt_entry *) | 254 | point = (struct ebt_entry *) |
255 | (((char *)point) + point->next_offset); | 255 | (((char *)point) + point->next_offset); |
256 | i++; | 256 | i++; |
257 | } | 257 | } |
258 | 258 | ||
259 | /* I actually like this :) */ | 259 | /* I actually like this :) */ |
260 | if (chaininfo->policy == EBT_RETURN) | 260 | if (chaininfo->policy == EBT_RETURN) |
261 | goto letsreturn; | 261 | goto letsreturn; |
262 | if (chaininfo->policy == EBT_ACCEPT) { | 262 | if (chaininfo->policy == EBT_ACCEPT) { |
263 | read_unlock_bh(&table->lock); | 263 | read_unlock_bh(&table->lock); |
264 | return NF_ACCEPT; | 264 | return NF_ACCEPT; |
265 | } | 265 | } |
266 | read_unlock_bh(&table->lock); | 266 | read_unlock_bh(&table->lock); |
267 | return NF_DROP; | 267 | return NF_DROP; |
268 | } | 268 | } |
269 | 269 | ||
270 | /* If it succeeds, returns element and locks mutex */ | 270 | /* If it succeeds, returns element and locks mutex */ |
271 | static inline void * | 271 | static inline void * |
272 | find_inlist_lock_noload(struct list_head *head, const char *name, int *error, | 272 | find_inlist_lock_noload(struct list_head *head, const char *name, int *error, |
273 | struct mutex *mutex) | 273 | struct mutex *mutex) |
274 | { | 274 | { |
275 | struct { | 275 | struct { |
276 | struct list_head list; | 276 | struct list_head list; |
277 | char name[EBT_FUNCTION_MAXNAMELEN]; | 277 | char name[EBT_FUNCTION_MAXNAMELEN]; |
278 | } *e; | 278 | } *e; |
279 | 279 | ||
280 | *error = mutex_lock_interruptible(mutex); | 280 | *error = mutex_lock_interruptible(mutex); |
281 | if (*error != 0) | 281 | if (*error != 0) |
282 | return NULL; | 282 | return NULL; |
283 | 283 | ||
284 | list_for_each_entry(e, head, list) { | 284 | list_for_each_entry(e, head, list) { |
285 | if (strcmp(e->name, name) == 0) | 285 | if (strcmp(e->name, name) == 0) |
286 | return e; | 286 | return e; |
287 | } | 287 | } |
288 | *error = -ENOENT; | 288 | *error = -ENOENT; |
289 | mutex_unlock(mutex); | 289 | mutex_unlock(mutex); |
290 | return NULL; | 290 | return NULL; |
291 | } | 291 | } |
292 | 292 | ||
293 | #ifndef CONFIG_KMOD | 293 | #ifndef CONFIG_KMOD |
294 | #define find_inlist_lock(h,n,p,e,m) find_inlist_lock_noload((h),(n),(e),(m)) | 294 | #define find_inlist_lock(h,n,p,e,m) find_inlist_lock_noload((h),(n),(e),(m)) |
295 | #else | 295 | #else |
296 | static void * | 296 | static void * |
297 | find_inlist_lock(struct list_head *head, const char *name, const char *prefix, | 297 | find_inlist_lock(struct list_head *head, const char *name, const char *prefix, |
298 | int *error, struct mutex *mutex) | 298 | int *error, struct mutex *mutex) |
299 | { | 299 | { |
300 | void *ret; | 300 | void *ret; |
301 | 301 | ||
302 | ret = find_inlist_lock_noload(head, name, error, mutex); | 302 | ret = find_inlist_lock_noload(head, name, error, mutex); |
303 | if (!ret) { | 303 | if (!ret) { |
304 | request_module("%s%s", prefix, name); | 304 | request_module("%s%s", prefix, name); |
305 | ret = find_inlist_lock_noload(head, name, error, mutex); | 305 | ret = find_inlist_lock_noload(head, name, error, mutex); |
306 | } | 306 | } |
307 | return ret; | 307 | return ret; |
308 | } | 308 | } |
309 | #endif | 309 | #endif |
310 | 310 | ||
311 | static inline struct ebt_table * | 311 | static inline struct ebt_table * |
312 | find_table_lock(const char *name, int *error, struct mutex *mutex) | 312 | find_table_lock(const char *name, int *error, struct mutex *mutex) |
313 | { | 313 | { |
314 | return find_inlist_lock(&ebt_tables, name, "ebtable_", error, mutex); | 314 | return find_inlist_lock(&ebt_tables, name, "ebtable_", error, mutex); |
315 | } | 315 | } |
316 | 316 | ||
317 | static inline struct ebt_match * | 317 | static inline struct ebt_match * |
318 | find_match_lock(const char *name, int *error, struct mutex *mutex) | 318 | find_match_lock(const char *name, int *error, struct mutex *mutex) |
319 | { | 319 | { |
320 | return find_inlist_lock(&ebt_matches, name, "ebt_", error, mutex); | 320 | return find_inlist_lock(&ebt_matches, name, "ebt_", error, mutex); |
321 | } | 321 | } |
322 | 322 | ||
323 | static inline struct ebt_watcher * | 323 | static inline struct ebt_watcher * |
324 | find_watcher_lock(const char *name, int *error, struct mutex *mutex) | 324 | find_watcher_lock(const char *name, int *error, struct mutex *mutex) |
325 | { | 325 | { |
326 | return find_inlist_lock(&ebt_watchers, name, "ebt_", error, mutex); | 326 | return find_inlist_lock(&ebt_watchers, name, "ebt_", error, mutex); |
327 | } | 327 | } |
328 | 328 | ||
329 | static inline struct ebt_target * | 329 | static inline struct ebt_target * |
330 | find_target_lock(const char *name, int *error, struct mutex *mutex) | 330 | find_target_lock(const char *name, int *error, struct mutex *mutex) |
331 | { | 331 | { |
332 | return find_inlist_lock(&ebt_targets, name, "ebt_", error, mutex); | 332 | return find_inlist_lock(&ebt_targets, name, "ebt_", error, mutex); |
333 | } | 333 | } |
334 | 334 | ||
335 | static inline int | 335 | static inline int |
336 | ebt_check_match(struct ebt_entry_match *m, struct ebt_entry *e, | 336 | ebt_check_match(struct ebt_entry_match *m, struct ebt_entry *e, |
337 | const char *name, unsigned int hookmask, unsigned int *cnt) | 337 | const char *name, unsigned int hookmask, unsigned int *cnt) |
338 | { | 338 | { |
339 | struct ebt_match *match; | 339 | struct ebt_match *match; |
340 | size_t left = ((char *)e + e->watchers_offset) - (char *)m; | 340 | size_t left = ((char *)e + e->watchers_offset) - (char *)m; |
341 | int ret; | 341 | int ret; |
342 | 342 | ||
343 | if (left < sizeof(struct ebt_entry_match) || | 343 | if (left < sizeof(struct ebt_entry_match) || |
344 | left - sizeof(struct ebt_entry_match) < m->match_size) | 344 | left - sizeof(struct ebt_entry_match) < m->match_size) |
345 | return -EINVAL; | 345 | return -EINVAL; |
346 | match = find_match_lock(m->u.name, &ret, &ebt_mutex); | 346 | match = find_match_lock(m->u.name, &ret, &ebt_mutex); |
347 | if (!match) | 347 | if (!match) |
348 | return ret; | 348 | return ret; |
349 | m->u.match = match; | 349 | m->u.match = match; |
350 | if (!try_module_get(match->me)) { | 350 | if (!try_module_get(match->me)) { |
351 | mutex_unlock(&ebt_mutex); | 351 | mutex_unlock(&ebt_mutex); |
352 | return -ENOENT; | 352 | return -ENOENT; |
353 | } | 353 | } |
354 | mutex_unlock(&ebt_mutex); | 354 | mutex_unlock(&ebt_mutex); |
355 | if (XT_ALIGN(match->matchsize) != m->match_size && | 355 | if (XT_ALIGN(match->matchsize) != m->match_size && |
356 | match->matchsize != -1) { | 356 | match->matchsize != -1) { |
357 | /* | 357 | /* |
358 | * ebt_among is exempt from centralized matchsize checking | 358 | * ebt_among is exempt from centralized matchsize checking |
359 | * because it uses a dynamic-size data set. | 359 | * because it uses a dynamic-size data set. |
360 | */ | 360 | */ |
361 | printk(KERN_WARNING "ebtables: %s match: " | 361 | printk(KERN_WARNING "ebtables: %s match: " |
362 | "invalid size %Zu != %u\n", | 362 | "invalid size %Zu != %u\n", |
363 | match->name, XT_ALIGN(match->matchsize), m->match_size); | 363 | match->name, XT_ALIGN(match->matchsize), m->match_size); |
364 | module_put(match->me); | 364 | module_put(match->me); |
365 | return -EINVAL; | 365 | return -EINVAL; |
366 | } | 366 | } |
367 | if (match->check && | 367 | if (match->check && |
368 | match->check(name, hookmask, e, m->data, m->match_size) != 0) { | 368 | !match->check(name, hookmask, e, m->data, m->match_size)) { |
369 | BUGPRINT("match->check failed\n"); | 369 | BUGPRINT("match->check failed\n"); |
370 | module_put(match->me); | 370 | module_put(match->me); |
371 | return -EINVAL; | 371 | return -EINVAL; |
372 | } | 372 | } |
373 | (*cnt)++; | 373 | (*cnt)++; |
374 | return 0; | 374 | return 0; |
375 | } | 375 | } |
376 | 376 | ||
377 | static inline int | 377 | static inline int |
378 | ebt_check_watcher(struct ebt_entry_watcher *w, struct ebt_entry *e, | 378 | ebt_check_watcher(struct ebt_entry_watcher *w, struct ebt_entry *e, |
379 | const char *name, unsigned int hookmask, unsigned int *cnt) | 379 | const char *name, unsigned int hookmask, unsigned int *cnt) |
380 | { | 380 | { |
381 | struct ebt_watcher *watcher; | 381 | struct ebt_watcher *watcher; |
382 | size_t left = ((char *)e + e->target_offset) - (char *)w; | 382 | size_t left = ((char *)e + e->target_offset) - (char *)w; |
383 | int ret; | 383 | int ret; |
384 | 384 | ||
385 | if (left < sizeof(struct ebt_entry_watcher) || | 385 | if (left < sizeof(struct ebt_entry_watcher) || |
386 | left - sizeof(struct ebt_entry_watcher) < w->watcher_size) | 386 | left - sizeof(struct ebt_entry_watcher) < w->watcher_size) |
387 | return -EINVAL; | 387 | return -EINVAL; |
388 | watcher = find_watcher_lock(w->u.name, &ret, &ebt_mutex); | 388 | watcher = find_watcher_lock(w->u.name, &ret, &ebt_mutex); |
389 | if (!watcher) | 389 | if (!watcher) |
390 | return ret; | 390 | return ret; |
391 | w->u.watcher = watcher; | 391 | w->u.watcher = watcher; |
392 | if (!try_module_get(watcher->me)) { | 392 | if (!try_module_get(watcher->me)) { |
393 | mutex_unlock(&ebt_mutex); | 393 | mutex_unlock(&ebt_mutex); |
394 | return -ENOENT; | 394 | return -ENOENT; |
395 | } | 395 | } |
396 | mutex_unlock(&ebt_mutex); | 396 | mutex_unlock(&ebt_mutex); |
397 | if (XT_ALIGN(watcher->targetsize) != w->watcher_size) { | 397 | if (XT_ALIGN(watcher->targetsize) != w->watcher_size) { |
398 | printk(KERN_WARNING "ebtables: %s watcher: " | 398 | printk(KERN_WARNING "ebtables: %s watcher: " |
399 | "invalid size %Zu != %u\n", | 399 | "invalid size %Zu != %u\n", |
400 | watcher->name, XT_ALIGN(watcher->targetsize), | 400 | watcher->name, XT_ALIGN(watcher->targetsize), |
401 | w->watcher_size); | 401 | w->watcher_size); |
402 | module_put(watcher->me); | 402 | module_put(watcher->me); |
403 | return -EINVAL; | 403 | return -EINVAL; |
404 | } | 404 | } |
405 | if (watcher->check && | 405 | if (watcher->check && |
406 | watcher->check(name, hookmask, e, w->data, w->watcher_size) != 0) { | 406 | !watcher->check(name, hookmask, e, w->data, w->watcher_size)) { |
407 | BUGPRINT("watcher->check failed\n"); | 407 | BUGPRINT("watcher->check failed\n"); |
408 | module_put(watcher->me); | 408 | module_put(watcher->me); |
409 | return -EINVAL; | 409 | return -EINVAL; |
410 | } | 410 | } |
411 | (*cnt)++; | 411 | (*cnt)++; |
412 | return 0; | 412 | return 0; |
413 | } | 413 | } |
414 | 414 | ||
415 | static int ebt_verify_pointers(struct ebt_replace *repl, | 415 | static int ebt_verify_pointers(struct ebt_replace *repl, |
416 | struct ebt_table_info *newinfo) | 416 | struct ebt_table_info *newinfo) |
417 | { | 417 | { |
418 | unsigned int limit = repl->entries_size; | 418 | unsigned int limit = repl->entries_size; |
419 | unsigned int valid_hooks = repl->valid_hooks; | 419 | unsigned int valid_hooks = repl->valid_hooks; |
420 | unsigned int offset = 0; | 420 | unsigned int offset = 0; |
421 | int i; | 421 | int i; |
422 | 422 | ||
423 | for (i = 0; i < NF_BR_NUMHOOKS; i++) | 423 | for (i = 0; i < NF_BR_NUMHOOKS; i++) |
424 | newinfo->hook_entry[i] = NULL; | 424 | newinfo->hook_entry[i] = NULL; |
425 | 425 | ||
426 | newinfo->entries_size = repl->entries_size; | 426 | newinfo->entries_size = repl->entries_size; |
427 | newinfo->nentries = repl->nentries; | 427 | newinfo->nentries = repl->nentries; |
428 | 428 | ||
429 | while (offset < limit) { | 429 | while (offset < limit) { |
430 | size_t left = limit - offset; | 430 | size_t left = limit - offset; |
431 | struct ebt_entry *e = (void *)newinfo->entries + offset; | 431 | struct ebt_entry *e = (void *)newinfo->entries + offset; |
432 | 432 | ||
433 | if (left < sizeof(unsigned int)) | 433 | if (left < sizeof(unsigned int)) |
434 | break; | 434 | break; |
435 | 435 | ||
436 | for (i = 0; i < NF_BR_NUMHOOKS; i++) { | 436 | for (i = 0; i < NF_BR_NUMHOOKS; i++) { |
437 | if ((valid_hooks & (1 << i)) == 0) | 437 | if ((valid_hooks & (1 << i)) == 0) |
438 | continue; | 438 | continue; |
439 | if ((char __user *)repl->hook_entry[i] == | 439 | if ((char __user *)repl->hook_entry[i] == |
440 | repl->entries + offset) | 440 | repl->entries + offset) |
441 | break; | 441 | break; |
442 | } | 442 | } |
443 | 443 | ||
444 | if (i != NF_BR_NUMHOOKS || !(e->bitmask & EBT_ENTRY_OR_ENTRIES)) { | 444 | if (i != NF_BR_NUMHOOKS || !(e->bitmask & EBT_ENTRY_OR_ENTRIES)) { |
445 | if (e->bitmask != 0) { | 445 | if (e->bitmask != 0) { |
446 | /* we make userspace set this right, | 446 | /* we make userspace set this right, |
447 | so there is no misunderstanding */ | 447 | so there is no misunderstanding */ |
448 | BUGPRINT("EBT_ENTRY_OR_ENTRIES shouldn't be set " | 448 | BUGPRINT("EBT_ENTRY_OR_ENTRIES shouldn't be set " |
449 | "in distinguisher\n"); | 449 | "in distinguisher\n"); |
450 | return -EINVAL; | 450 | return -EINVAL; |
451 | } | 451 | } |
452 | if (i != NF_BR_NUMHOOKS) | 452 | if (i != NF_BR_NUMHOOKS) |
453 | newinfo->hook_entry[i] = (struct ebt_entries *)e; | 453 | newinfo->hook_entry[i] = (struct ebt_entries *)e; |
454 | if (left < sizeof(struct ebt_entries)) | 454 | if (left < sizeof(struct ebt_entries)) |
455 | break; | 455 | break; |
456 | offset += sizeof(struct ebt_entries); | 456 | offset += sizeof(struct ebt_entries); |
457 | } else { | 457 | } else { |
458 | if (left < sizeof(struct ebt_entry)) | 458 | if (left < sizeof(struct ebt_entry)) |
459 | break; | 459 | break; |
460 | if (left < e->next_offset) | 460 | if (left < e->next_offset) |
461 | break; | 461 | break; |
462 | offset += e->next_offset; | 462 | offset += e->next_offset; |
463 | } | 463 | } |
464 | } | 464 | } |
465 | if (offset != limit) { | 465 | if (offset != limit) { |
466 | BUGPRINT("entries_size too small\n"); | 466 | BUGPRINT("entries_size too small\n"); |
467 | return -EINVAL; | 467 | return -EINVAL; |
468 | } | 468 | } |
469 | 469 | ||
470 | /* check if all valid hooks have a chain */ | 470 | /* check if all valid hooks have a chain */ |
471 | for (i = 0; i < NF_BR_NUMHOOKS; i++) { | 471 | for (i = 0; i < NF_BR_NUMHOOKS; i++) { |
472 | if (!newinfo->hook_entry[i] && | 472 | if (!newinfo->hook_entry[i] && |
473 | (valid_hooks & (1 << i))) { | 473 | (valid_hooks & (1 << i))) { |
474 | BUGPRINT("Valid hook without chain\n"); | 474 | BUGPRINT("Valid hook without chain\n"); |
475 | return -EINVAL; | 475 | return -EINVAL; |
476 | } | 476 | } |
477 | } | 477 | } |
478 | return 0; | 478 | return 0; |
479 | } | 479 | } |
480 | 480 | ||
481 | /* | 481 | /* |
482 | * this one is very careful, as it is the first function | 482 | * this one is very careful, as it is the first function |
483 | * to parse the userspace data | 483 | * to parse the userspace data |
484 | */ | 484 | */ |
485 | static inline int | 485 | static inline int |
486 | ebt_check_entry_size_and_hooks(struct ebt_entry *e, | 486 | ebt_check_entry_size_and_hooks(struct ebt_entry *e, |
487 | struct ebt_table_info *newinfo, | 487 | struct ebt_table_info *newinfo, |
488 | unsigned int *n, unsigned int *cnt, | 488 | unsigned int *n, unsigned int *cnt, |
489 | unsigned int *totalcnt, unsigned int *udc_cnt) | 489 | unsigned int *totalcnt, unsigned int *udc_cnt) |
490 | { | 490 | { |
491 | int i; | 491 | int i; |
492 | 492 | ||
493 | for (i = 0; i < NF_BR_NUMHOOKS; i++) { | 493 | for (i = 0; i < NF_BR_NUMHOOKS; i++) { |
494 | if ((void *)e == (void *)newinfo->hook_entry[i]) | 494 | if ((void *)e == (void *)newinfo->hook_entry[i]) |
495 | break; | 495 | break; |
496 | } | 496 | } |
497 | /* beginning of a new chain | 497 | /* beginning of a new chain |
498 | if i == NF_BR_NUMHOOKS it must be a user defined chain */ | 498 | if i == NF_BR_NUMHOOKS it must be a user defined chain */ |
499 | if (i != NF_BR_NUMHOOKS || !e->bitmask) { | 499 | if (i != NF_BR_NUMHOOKS || !e->bitmask) { |
500 | /* this checks if the previous chain has as many entries | 500 | /* this checks if the previous chain has as many entries |
501 | as it said it has */ | 501 | as it said it has */ |
502 | if (*n != *cnt) { | 502 | if (*n != *cnt) { |
503 | BUGPRINT("nentries does not equal the nr of entries " | 503 | BUGPRINT("nentries does not equal the nr of entries " |
504 | "in the chain\n"); | 504 | "in the chain\n"); |
505 | return -EINVAL; | 505 | return -EINVAL; |
506 | } | 506 | } |
507 | if (((struct ebt_entries *)e)->policy != EBT_DROP && | 507 | if (((struct ebt_entries *)e)->policy != EBT_DROP && |
508 | ((struct ebt_entries *)e)->policy != EBT_ACCEPT) { | 508 | ((struct ebt_entries *)e)->policy != EBT_ACCEPT) { |
509 | /* only RETURN from udc */ | 509 | /* only RETURN from udc */ |
510 | if (i != NF_BR_NUMHOOKS || | 510 | if (i != NF_BR_NUMHOOKS || |
511 | ((struct ebt_entries *)e)->policy != EBT_RETURN) { | 511 | ((struct ebt_entries *)e)->policy != EBT_RETURN) { |
512 | BUGPRINT("bad policy\n"); | 512 | BUGPRINT("bad policy\n"); |
513 | return -EINVAL; | 513 | return -EINVAL; |
514 | } | 514 | } |
515 | } | 515 | } |
516 | if (i == NF_BR_NUMHOOKS) /* it's a user defined chain */ | 516 | if (i == NF_BR_NUMHOOKS) /* it's a user defined chain */ |
517 | (*udc_cnt)++; | 517 | (*udc_cnt)++; |
518 | if (((struct ebt_entries *)e)->counter_offset != *totalcnt) { | 518 | if (((struct ebt_entries *)e)->counter_offset != *totalcnt) { |
519 | BUGPRINT("counter_offset != totalcnt"); | 519 | BUGPRINT("counter_offset != totalcnt"); |
520 | return -EINVAL; | 520 | return -EINVAL; |
521 | } | 521 | } |
522 | *n = ((struct ebt_entries *)e)->nentries; | 522 | *n = ((struct ebt_entries *)e)->nentries; |
523 | *cnt = 0; | 523 | *cnt = 0; |
524 | return 0; | 524 | return 0; |
525 | } | 525 | } |
526 | /* a plain old entry, heh */ | 526 | /* a plain old entry, heh */ |
527 | if (sizeof(struct ebt_entry) > e->watchers_offset || | 527 | if (sizeof(struct ebt_entry) > e->watchers_offset || |
528 | e->watchers_offset > e->target_offset || | 528 | e->watchers_offset > e->target_offset || |
529 | e->target_offset >= e->next_offset) { | 529 | e->target_offset >= e->next_offset) { |
530 | BUGPRINT("entry offsets not in right order\n"); | 530 | BUGPRINT("entry offsets not in right order\n"); |
531 | return -EINVAL; | 531 | return -EINVAL; |
532 | } | 532 | } |
533 | /* this is not checked anywhere else */ | 533 | /* this is not checked anywhere else */ |
534 | if (e->next_offset - e->target_offset < sizeof(struct ebt_entry_target)) { | 534 | if (e->next_offset - e->target_offset < sizeof(struct ebt_entry_target)) { |
535 | BUGPRINT("target size too small\n"); | 535 | BUGPRINT("target size too small\n"); |
536 | return -EINVAL; | 536 | return -EINVAL; |
537 | } | 537 | } |
538 | (*cnt)++; | 538 | (*cnt)++; |
539 | (*totalcnt)++; | 539 | (*totalcnt)++; |
540 | return 0; | 540 | return 0; |
541 | } | 541 | } |
542 | 542 | ||
543 | struct ebt_cl_stack | 543 | struct ebt_cl_stack |
544 | { | 544 | { |
545 | struct ebt_chainstack cs; | 545 | struct ebt_chainstack cs; |
546 | int from; | 546 | int from; |
547 | unsigned int hookmask; | 547 | unsigned int hookmask; |
548 | }; | 548 | }; |
549 | 549 | ||
550 | /* | 550 | /* |
551 | * we need these positions to check that the jumps to a different part of the | 551 | * we need these positions to check that the jumps to a different part of the |
552 | * entries is a jump to the beginning of a new chain. | 552 | * entries is a jump to the beginning of a new chain. |
553 | */ | 553 | */ |
554 | static inline int | 554 | static inline int |
555 | ebt_get_udc_positions(struct ebt_entry *e, struct ebt_table_info *newinfo, | 555 | ebt_get_udc_positions(struct ebt_entry *e, struct ebt_table_info *newinfo, |
556 | unsigned int *n, struct ebt_cl_stack *udc) | 556 | unsigned int *n, struct ebt_cl_stack *udc) |
557 | { | 557 | { |
558 | int i; | 558 | int i; |
559 | 559 | ||
560 | /* we're only interested in chain starts */ | 560 | /* we're only interested in chain starts */ |
561 | if (e->bitmask) | 561 | if (e->bitmask) |
562 | return 0; | 562 | return 0; |
563 | for (i = 0; i < NF_BR_NUMHOOKS; i++) { | 563 | for (i = 0; i < NF_BR_NUMHOOKS; i++) { |
564 | if (newinfo->hook_entry[i] == (struct ebt_entries *)e) | 564 | if (newinfo->hook_entry[i] == (struct ebt_entries *)e) |
565 | break; | 565 | break; |
566 | } | 566 | } |
567 | /* only care about udc */ | 567 | /* only care about udc */ |
568 | if (i != NF_BR_NUMHOOKS) | 568 | if (i != NF_BR_NUMHOOKS) |
569 | return 0; | 569 | return 0; |
570 | 570 | ||
571 | udc[*n].cs.chaininfo = (struct ebt_entries *)e; | 571 | udc[*n].cs.chaininfo = (struct ebt_entries *)e; |
572 | /* these initialisations are depended on later in check_chainloops() */ | 572 | /* these initialisations are depended on later in check_chainloops() */ |
573 | udc[*n].cs.n = 0; | 573 | udc[*n].cs.n = 0; |
574 | udc[*n].hookmask = 0; | 574 | udc[*n].hookmask = 0; |
575 | 575 | ||
576 | (*n)++; | 576 | (*n)++; |
577 | return 0; | 577 | return 0; |
578 | } | 578 | } |
579 | 579 | ||
580 | static inline int | 580 | static inline int |
581 | ebt_cleanup_match(struct ebt_entry_match *m, unsigned int *i) | 581 | ebt_cleanup_match(struct ebt_entry_match *m, unsigned int *i) |
582 | { | 582 | { |
583 | if (i && (*i)-- == 0) | 583 | if (i && (*i)-- == 0) |
584 | return 1; | 584 | return 1; |
585 | if (m->u.match->destroy) | 585 | if (m->u.match->destroy) |
586 | m->u.match->destroy(m->data, m->match_size); | 586 | m->u.match->destroy(m->data, m->match_size); |
587 | module_put(m->u.match->me); | 587 | module_put(m->u.match->me); |
588 | 588 | ||
589 | return 0; | 589 | return 0; |
590 | } | 590 | } |
591 | 591 | ||
592 | static inline int | 592 | static inline int |
593 | ebt_cleanup_watcher(struct ebt_entry_watcher *w, unsigned int *i) | 593 | ebt_cleanup_watcher(struct ebt_entry_watcher *w, unsigned int *i) |
594 | { | 594 | { |
595 | if (i && (*i)-- == 0) | 595 | if (i && (*i)-- == 0) |
596 | return 1; | 596 | return 1; |
597 | if (w->u.watcher->destroy) | 597 | if (w->u.watcher->destroy) |
598 | w->u.watcher->destroy(w->data, w->watcher_size); | 598 | w->u.watcher->destroy(w->data, w->watcher_size); |
599 | module_put(w->u.watcher->me); | 599 | module_put(w->u.watcher->me); |
600 | 600 | ||
601 | return 0; | 601 | return 0; |
602 | } | 602 | } |
603 | 603 | ||
604 | static inline int | 604 | static inline int |
605 | ebt_cleanup_entry(struct ebt_entry *e, unsigned int *cnt) | 605 | ebt_cleanup_entry(struct ebt_entry *e, unsigned int *cnt) |
606 | { | 606 | { |
607 | struct ebt_entry_target *t; | 607 | struct ebt_entry_target *t; |
608 | 608 | ||
609 | if (e->bitmask == 0) | 609 | if (e->bitmask == 0) |
610 | return 0; | 610 | return 0; |
611 | /* we're done */ | 611 | /* we're done */ |
612 | if (cnt && (*cnt)-- == 0) | 612 | if (cnt && (*cnt)-- == 0) |
613 | return 1; | 613 | return 1; |
614 | EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, NULL); | 614 | EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, NULL); |
615 | EBT_MATCH_ITERATE(e, ebt_cleanup_match, NULL); | 615 | EBT_MATCH_ITERATE(e, ebt_cleanup_match, NULL); |
616 | t = (struct ebt_entry_target *)(((char *)e) + e->target_offset); | 616 | t = (struct ebt_entry_target *)(((char *)e) + e->target_offset); |
617 | if (t->u.target->destroy) | 617 | if (t->u.target->destroy) |
618 | t->u.target->destroy(t->data, t->target_size); | 618 | t->u.target->destroy(t->data, t->target_size); |
619 | module_put(t->u.target->me); | 619 | module_put(t->u.target->me); |
620 | 620 | ||
621 | return 0; | 621 | return 0; |
622 | } | 622 | } |
623 | 623 | ||
624 | static inline int | 624 | static inline int |
625 | ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo, | 625 | ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo, |
626 | const char *name, unsigned int *cnt, | 626 | const char *name, unsigned int *cnt, |
627 | struct ebt_cl_stack *cl_s, unsigned int udc_cnt) | 627 | struct ebt_cl_stack *cl_s, unsigned int udc_cnt) |
628 | { | 628 | { |
629 | struct ebt_entry_target *t; | 629 | struct ebt_entry_target *t; |
630 | struct ebt_target *target; | 630 | struct ebt_target *target; |
631 | unsigned int i, j, hook = 0, hookmask = 0; | 631 | unsigned int i, j, hook = 0, hookmask = 0; |
632 | size_t gap; | 632 | size_t gap; |
633 | int ret; | 633 | int ret; |
634 | 634 | ||
635 | /* don't mess with the struct ebt_entries */ | 635 | /* don't mess with the struct ebt_entries */ |
636 | if (e->bitmask == 0) | 636 | if (e->bitmask == 0) |
637 | return 0; | 637 | return 0; |
638 | 638 | ||
639 | if (e->bitmask & ~EBT_F_MASK) { | 639 | if (e->bitmask & ~EBT_F_MASK) { |
640 | BUGPRINT("Unknown flag for bitmask\n"); | 640 | BUGPRINT("Unknown flag for bitmask\n"); |
641 | return -EINVAL; | 641 | return -EINVAL; |
642 | } | 642 | } |
643 | if (e->invflags & ~EBT_INV_MASK) { | 643 | if (e->invflags & ~EBT_INV_MASK) { |
644 | BUGPRINT("Unknown flag for inv bitmask\n"); | 644 | BUGPRINT("Unknown flag for inv bitmask\n"); |
645 | return -EINVAL; | 645 | return -EINVAL; |
646 | } | 646 | } |
647 | if ( (e->bitmask & EBT_NOPROTO) && (e->bitmask & EBT_802_3) ) { | 647 | if ( (e->bitmask & EBT_NOPROTO) && (e->bitmask & EBT_802_3) ) { |
648 | BUGPRINT("NOPROTO & 802_3 not allowed\n"); | 648 | BUGPRINT("NOPROTO & 802_3 not allowed\n"); |
649 | return -EINVAL; | 649 | return -EINVAL; |
650 | } | 650 | } |
651 | /* what hook do we belong to? */ | 651 | /* what hook do we belong to? */ |
652 | for (i = 0; i < NF_BR_NUMHOOKS; i++) { | 652 | for (i = 0; i < NF_BR_NUMHOOKS; i++) { |
653 | if (!newinfo->hook_entry[i]) | 653 | if (!newinfo->hook_entry[i]) |
654 | continue; | 654 | continue; |
655 | if ((char *)newinfo->hook_entry[i] < (char *)e) | 655 | if ((char *)newinfo->hook_entry[i] < (char *)e) |
656 | hook = i; | 656 | hook = i; |
657 | else | 657 | else |
658 | break; | 658 | break; |
659 | } | 659 | } |
660 | /* (1 << NF_BR_NUMHOOKS) tells the check functions the rule is on | 660 | /* (1 << NF_BR_NUMHOOKS) tells the check functions the rule is on |
661 | a base chain */ | 661 | a base chain */ |
662 | if (i < NF_BR_NUMHOOKS) | 662 | if (i < NF_BR_NUMHOOKS) |
663 | hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS); | 663 | hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS); |
664 | else { | 664 | else { |
665 | for (i = 0; i < udc_cnt; i++) | 665 | for (i = 0; i < udc_cnt; i++) |
666 | if ((char *)(cl_s[i].cs.chaininfo) > (char *)e) | 666 | if ((char *)(cl_s[i].cs.chaininfo) > (char *)e) |
667 | break; | 667 | break; |
668 | if (i == 0) | 668 | if (i == 0) |
669 | hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS); | 669 | hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS); |
670 | else | 670 | else |
671 | hookmask = cl_s[i - 1].hookmask; | 671 | hookmask = cl_s[i - 1].hookmask; |
672 | } | 672 | } |
673 | i = 0; | 673 | i = 0; |
674 | ret = EBT_MATCH_ITERATE(e, ebt_check_match, e, name, hookmask, &i); | 674 | ret = EBT_MATCH_ITERATE(e, ebt_check_match, e, name, hookmask, &i); |
675 | if (ret != 0) | 675 | if (ret != 0) |
676 | goto cleanup_matches; | 676 | goto cleanup_matches; |
677 | j = 0; | 677 | j = 0; |
678 | ret = EBT_WATCHER_ITERATE(e, ebt_check_watcher, e, name, hookmask, &j); | 678 | ret = EBT_WATCHER_ITERATE(e, ebt_check_watcher, e, name, hookmask, &j); |
679 | if (ret != 0) | 679 | if (ret != 0) |
680 | goto cleanup_watchers; | 680 | goto cleanup_watchers; |
681 | t = (struct ebt_entry_target *)(((char *)e) + e->target_offset); | 681 | t = (struct ebt_entry_target *)(((char *)e) + e->target_offset); |
682 | gap = e->next_offset - e->target_offset; | 682 | gap = e->next_offset - e->target_offset; |
683 | target = find_target_lock(t->u.name, &ret, &ebt_mutex); | 683 | target = find_target_lock(t->u.name, &ret, &ebt_mutex); |
684 | if (!target) | 684 | if (!target) |
685 | goto cleanup_watchers; | 685 | goto cleanup_watchers; |
686 | if (!try_module_get(target->me)) { | 686 | if (!try_module_get(target->me)) { |
687 | mutex_unlock(&ebt_mutex); | 687 | mutex_unlock(&ebt_mutex); |
688 | ret = -ENOENT; | 688 | ret = -ENOENT; |
689 | goto cleanup_watchers; | 689 | goto cleanup_watchers; |
690 | } | 690 | } |
691 | mutex_unlock(&ebt_mutex); | 691 | mutex_unlock(&ebt_mutex); |
692 | 692 | ||
693 | t->u.target = target; | 693 | t->u.target = target; |
694 | if (t->u.target == &ebt_standard_target) { | 694 | if (t->u.target == &ebt_standard_target) { |
695 | if (gap < sizeof(struct ebt_standard_target)) { | 695 | if (gap < sizeof(struct ebt_standard_target)) { |
696 | BUGPRINT("Standard target size too big\n"); | 696 | BUGPRINT("Standard target size too big\n"); |
697 | ret = -EFAULT; | 697 | ret = -EFAULT; |
698 | goto cleanup_watchers; | 698 | goto cleanup_watchers; |
699 | } | 699 | } |
700 | if (((struct ebt_standard_target *)t)->verdict < | 700 | if (((struct ebt_standard_target *)t)->verdict < |
701 | -NUM_STANDARD_TARGETS) { | 701 | -NUM_STANDARD_TARGETS) { |
702 | BUGPRINT("Invalid standard target\n"); | 702 | BUGPRINT("Invalid standard target\n"); |
703 | ret = -EFAULT; | 703 | ret = -EFAULT; |
704 | goto cleanup_watchers; | 704 | goto cleanup_watchers; |
705 | } | 705 | } |
706 | } else if (t->target_size > gap - sizeof(struct ebt_entry_target)) { | 706 | } else if (t->target_size > gap - sizeof(struct ebt_entry_target)) { |
707 | module_put(t->u.target->me); | 707 | module_put(t->u.target->me); |
708 | ret = -EFAULT; | 708 | ret = -EFAULT; |
709 | goto cleanup_watchers; | 709 | goto cleanup_watchers; |
710 | } else if (XT_ALIGN(target->targetsize) != t->target_size) { | 710 | } else if (XT_ALIGN(target->targetsize) != t->target_size) { |
711 | printk(KERN_WARNING "ebtables: %s target: " | 711 | printk(KERN_WARNING "ebtables: %s target: " |
712 | "invalid size %Zu != %u\n", | 712 | "invalid size %Zu != %u\n", |
713 | target->name, XT_ALIGN(target->targetsize), | 713 | target->name, XT_ALIGN(target->targetsize), |
714 | t->target_size); | 714 | t->target_size); |
715 | module_put(t->u.target->me); | 715 | module_put(t->u.target->me); |
716 | ret = -EINVAL; | 716 | ret = -EINVAL; |
717 | goto cleanup_watchers; | 717 | goto cleanup_watchers; |
718 | } else if (t->u.target->check && | 718 | } else if (t->u.target->check && |
719 | t->u.target->check(name, hookmask, e, t->data, t->target_size) != 0) { | 719 | !t->u.target->check(name, hookmask, e, t->data, t->target_size)) { |
720 | module_put(t->u.target->me); | 720 | module_put(t->u.target->me); |
721 | ret = -EFAULT; | 721 | ret = -EFAULT; |
722 | goto cleanup_watchers; | 722 | goto cleanup_watchers; |
723 | } | 723 | } |
724 | (*cnt)++; | 724 | (*cnt)++; |
725 | return 0; | 725 | return 0; |
726 | cleanup_watchers: | 726 | cleanup_watchers: |
727 | EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, &j); | 727 | EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, &j); |
728 | cleanup_matches: | 728 | cleanup_matches: |
729 | EBT_MATCH_ITERATE(e, ebt_cleanup_match, &i); | 729 | EBT_MATCH_ITERATE(e, ebt_cleanup_match, &i); |
730 | return ret; | 730 | return ret; |
731 | } | 731 | } |
732 | 732 | ||
733 | /* | 733 | /* |
734 | * checks for loops and sets the hook mask for udc | 734 | * checks for loops and sets the hook mask for udc |
735 | * the hook mask for udc tells us from which base chains the udc can be | 735 | * the hook mask for udc tells us from which base chains the udc can be |
736 | * accessed. This mask is a parameter to the check() functions of the extensions | 736 | * accessed. This mask is a parameter to the check() functions of the extensions |
737 | */ | 737 | */ |
738 | static int check_chainloops(struct ebt_entries *chain, struct ebt_cl_stack *cl_s, | 738 | static int check_chainloops(struct ebt_entries *chain, struct ebt_cl_stack *cl_s, |
739 | unsigned int udc_cnt, unsigned int hooknr, char *base) | 739 | unsigned int udc_cnt, unsigned int hooknr, char *base) |
740 | { | 740 | { |
741 | int i, chain_nr = -1, pos = 0, nentries = chain->nentries, verdict; | 741 | int i, chain_nr = -1, pos = 0, nentries = chain->nentries, verdict; |
742 | struct ebt_entry *e = (struct ebt_entry *)chain->data; | 742 | struct ebt_entry *e = (struct ebt_entry *)chain->data; |
743 | struct ebt_entry_target *t; | 743 | struct ebt_entry_target *t; |
744 | 744 | ||
745 | while (pos < nentries || chain_nr != -1) { | 745 | while (pos < nentries || chain_nr != -1) { |
746 | /* end of udc, go back one 'recursion' step */ | 746 | /* end of udc, go back one 'recursion' step */ |
747 | if (pos == nentries) { | 747 | if (pos == nentries) { |
748 | /* put back values of the time when this chain was called */ | 748 | /* put back values of the time when this chain was called */ |
749 | e = cl_s[chain_nr].cs.e; | 749 | e = cl_s[chain_nr].cs.e; |
750 | if (cl_s[chain_nr].from != -1) | 750 | if (cl_s[chain_nr].from != -1) |
751 | nentries = | 751 | nentries = |
752 | cl_s[cl_s[chain_nr].from].cs.chaininfo->nentries; | 752 | cl_s[cl_s[chain_nr].from].cs.chaininfo->nentries; |
753 | else | 753 | else |
754 | nentries = chain->nentries; | 754 | nentries = chain->nentries; |
755 | pos = cl_s[chain_nr].cs.n; | 755 | pos = cl_s[chain_nr].cs.n; |
756 | /* make sure we won't see a loop that isn't one */ | 756 | /* make sure we won't see a loop that isn't one */ |
757 | cl_s[chain_nr].cs.n = 0; | 757 | cl_s[chain_nr].cs.n = 0; |
758 | chain_nr = cl_s[chain_nr].from; | 758 | chain_nr = cl_s[chain_nr].from; |
759 | if (pos == nentries) | 759 | if (pos == nentries) |
760 | continue; | 760 | continue; |
761 | } | 761 | } |
762 | t = (struct ebt_entry_target *) | 762 | t = (struct ebt_entry_target *) |
763 | (((char *)e) + e->target_offset); | 763 | (((char *)e) + e->target_offset); |
764 | if (strcmp(t->u.name, EBT_STANDARD_TARGET)) | 764 | if (strcmp(t->u.name, EBT_STANDARD_TARGET)) |
765 | goto letscontinue; | 765 | goto letscontinue; |
766 | if (e->target_offset + sizeof(struct ebt_standard_target) > | 766 | if (e->target_offset + sizeof(struct ebt_standard_target) > |
767 | e->next_offset) { | 767 | e->next_offset) { |
768 | BUGPRINT("Standard target size too big\n"); | 768 | BUGPRINT("Standard target size too big\n"); |
769 | return -1; | 769 | return -1; |
770 | } | 770 | } |
771 | verdict = ((struct ebt_standard_target *)t)->verdict; | 771 | verdict = ((struct ebt_standard_target *)t)->verdict; |
772 | if (verdict >= 0) { /* jump to another chain */ | 772 | if (verdict >= 0) { /* jump to another chain */ |
773 | struct ebt_entries *hlp2 = | 773 | struct ebt_entries *hlp2 = |
774 | (struct ebt_entries *)(base + verdict); | 774 | (struct ebt_entries *)(base + verdict); |
775 | for (i = 0; i < udc_cnt; i++) | 775 | for (i = 0; i < udc_cnt; i++) |
776 | if (hlp2 == cl_s[i].cs.chaininfo) | 776 | if (hlp2 == cl_s[i].cs.chaininfo) |
777 | break; | 777 | break; |
778 | /* bad destination or loop */ | 778 | /* bad destination or loop */ |
779 | if (i == udc_cnt) { | 779 | if (i == udc_cnt) { |
780 | BUGPRINT("bad destination\n"); | 780 | BUGPRINT("bad destination\n"); |
781 | return -1; | 781 | return -1; |
782 | } | 782 | } |
783 | if (cl_s[i].cs.n) { | 783 | if (cl_s[i].cs.n) { |
784 | BUGPRINT("loop\n"); | 784 | BUGPRINT("loop\n"); |
785 | return -1; | 785 | return -1; |
786 | } | 786 | } |
787 | if (cl_s[i].hookmask & (1 << hooknr)) | 787 | if (cl_s[i].hookmask & (1 << hooknr)) |
788 | goto letscontinue; | 788 | goto letscontinue; |
789 | /* this can't be 0, so the loop test is correct */ | 789 | /* this can't be 0, so the loop test is correct */ |
790 | cl_s[i].cs.n = pos + 1; | 790 | cl_s[i].cs.n = pos + 1; |
791 | pos = 0; | 791 | pos = 0; |
792 | cl_s[i].cs.e = ((void *)e + e->next_offset); | 792 | cl_s[i].cs.e = ((void *)e + e->next_offset); |
793 | e = (struct ebt_entry *)(hlp2->data); | 793 | e = (struct ebt_entry *)(hlp2->data); |
794 | nentries = hlp2->nentries; | 794 | nentries = hlp2->nentries; |
795 | cl_s[i].from = chain_nr; | 795 | cl_s[i].from = chain_nr; |
796 | chain_nr = i; | 796 | chain_nr = i; |
797 | /* this udc is accessible from the base chain for hooknr */ | 797 | /* this udc is accessible from the base chain for hooknr */ |
798 | cl_s[i].hookmask |= (1 << hooknr); | 798 | cl_s[i].hookmask |= (1 << hooknr); |
799 | continue; | 799 | continue; |
800 | } | 800 | } |
801 | letscontinue: | 801 | letscontinue: |
802 | e = (void *)e + e->next_offset; | 802 | e = (void *)e + e->next_offset; |
803 | pos++; | 803 | pos++; |
804 | } | 804 | } |
805 | return 0; | 805 | return 0; |
806 | } | 806 | } |
807 | 807 | ||
808 | /* do the parsing of the table/chains/entries/matches/watchers/targets, heh */ | 808 | /* do the parsing of the table/chains/entries/matches/watchers/targets, heh */ |
809 | static int translate_table(char *name, struct ebt_table_info *newinfo) | 809 | static int translate_table(char *name, struct ebt_table_info *newinfo) |
810 | { | 810 | { |
811 | unsigned int i, j, k, udc_cnt; | 811 | unsigned int i, j, k, udc_cnt; |
812 | int ret; | 812 | int ret; |
813 | struct ebt_cl_stack *cl_s = NULL; /* used in the checking for chain loops */ | 813 | struct ebt_cl_stack *cl_s = NULL; /* used in the checking for chain loops */ |
814 | 814 | ||
815 | i = 0; | 815 | i = 0; |
816 | while (i < NF_BR_NUMHOOKS && !newinfo->hook_entry[i]) | 816 | while (i < NF_BR_NUMHOOKS && !newinfo->hook_entry[i]) |
817 | i++; | 817 | i++; |
818 | if (i == NF_BR_NUMHOOKS) { | 818 | if (i == NF_BR_NUMHOOKS) { |
819 | BUGPRINT("No valid hooks specified\n"); | 819 | BUGPRINT("No valid hooks specified\n"); |
820 | return -EINVAL; | 820 | return -EINVAL; |
821 | } | 821 | } |
822 | if (newinfo->hook_entry[i] != (struct ebt_entries *)newinfo->entries) { | 822 | if (newinfo->hook_entry[i] != (struct ebt_entries *)newinfo->entries) { |
823 | BUGPRINT("Chains don't start at beginning\n"); | 823 | BUGPRINT("Chains don't start at beginning\n"); |
824 | return -EINVAL; | 824 | return -EINVAL; |
825 | } | 825 | } |
826 | /* make sure chains are ordered after each other in same order | 826 | /* make sure chains are ordered after each other in same order |
827 | as their corresponding hooks */ | 827 | as their corresponding hooks */ |
828 | for (j = i + 1; j < NF_BR_NUMHOOKS; j++) { | 828 | for (j = i + 1; j < NF_BR_NUMHOOKS; j++) { |
829 | if (!newinfo->hook_entry[j]) | 829 | if (!newinfo->hook_entry[j]) |
830 | continue; | 830 | continue; |
831 | if (newinfo->hook_entry[j] <= newinfo->hook_entry[i]) { | 831 | if (newinfo->hook_entry[j] <= newinfo->hook_entry[i]) { |
832 | BUGPRINT("Hook order must be followed\n"); | 832 | BUGPRINT("Hook order must be followed\n"); |
833 | return -EINVAL; | 833 | return -EINVAL; |
834 | } | 834 | } |
835 | i = j; | 835 | i = j; |
836 | } | 836 | } |
837 | 837 | ||
838 | /* do some early checkings and initialize some things */ | 838 | /* do some early checkings and initialize some things */ |
839 | i = 0; /* holds the expected nr. of entries for the chain */ | 839 | i = 0; /* holds the expected nr. of entries for the chain */ |
840 | j = 0; /* holds the up to now counted entries for the chain */ | 840 | j = 0; /* holds the up to now counted entries for the chain */ |
841 | k = 0; /* holds the total nr. of entries, should equal | 841 | k = 0; /* holds the total nr. of entries, should equal |
842 | newinfo->nentries afterwards */ | 842 | newinfo->nentries afterwards */ |
843 | udc_cnt = 0; /* will hold the nr. of user defined chains (udc) */ | 843 | udc_cnt = 0; /* will hold the nr. of user defined chains (udc) */ |
844 | ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size, | 844 | ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size, |
845 | ebt_check_entry_size_and_hooks, newinfo, | 845 | ebt_check_entry_size_and_hooks, newinfo, |
846 | &i, &j, &k, &udc_cnt); | 846 | &i, &j, &k, &udc_cnt); |
847 | 847 | ||
848 | if (ret != 0) | 848 | if (ret != 0) |
849 | return ret; | 849 | return ret; |
850 | 850 | ||
851 | if (i != j) { | 851 | if (i != j) { |
852 | BUGPRINT("nentries does not equal the nr of entries in the " | 852 | BUGPRINT("nentries does not equal the nr of entries in the " |
853 | "(last) chain\n"); | 853 | "(last) chain\n"); |
854 | return -EINVAL; | 854 | return -EINVAL; |
855 | } | 855 | } |
856 | if (k != newinfo->nentries) { | 856 | if (k != newinfo->nentries) { |
857 | BUGPRINT("Total nentries is wrong\n"); | 857 | BUGPRINT("Total nentries is wrong\n"); |
858 | return -EINVAL; | 858 | return -EINVAL; |
859 | } | 859 | } |
860 | 860 | ||
861 | /* get the location of the udc, put them in an array | 861 | /* get the location of the udc, put them in an array |
862 | while we're at it, allocate the chainstack */ | 862 | while we're at it, allocate the chainstack */ |
863 | if (udc_cnt) { | 863 | if (udc_cnt) { |
864 | /* this will get free'd in do_replace()/ebt_register_table() | 864 | /* this will get free'd in do_replace()/ebt_register_table() |
865 | if an error occurs */ | 865 | if an error occurs */ |
866 | newinfo->chainstack = | 866 | newinfo->chainstack = |
867 | vmalloc(nr_cpu_ids * sizeof(*(newinfo->chainstack))); | 867 | vmalloc(nr_cpu_ids * sizeof(*(newinfo->chainstack))); |
868 | if (!newinfo->chainstack) | 868 | if (!newinfo->chainstack) |
869 | return -ENOMEM; | 869 | return -ENOMEM; |
870 | for_each_possible_cpu(i) { | 870 | for_each_possible_cpu(i) { |
871 | newinfo->chainstack[i] = | 871 | newinfo->chainstack[i] = |
872 | vmalloc(udc_cnt * sizeof(*(newinfo->chainstack[0]))); | 872 | vmalloc(udc_cnt * sizeof(*(newinfo->chainstack[0]))); |
873 | if (!newinfo->chainstack[i]) { | 873 | if (!newinfo->chainstack[i]) { |
874 | while (i) | 874 | while (i) |
875 | vfree(newinfo->chainstack[--i]); | 875 | vfree(newinfo->chainstack[--i]); |
876 | vfree(newinfo->chainstack); | 876 | vfree(newinfo->chainstack); |
877 | newinfo->chainstack = NULL; | 877 | newinfo->chainstack = NULL; |
878 | return -ENOMEM; | 878 | return -ENOMEM; |
879 | } | 879 | } |
880 | } | 880 | } |
881 | 881 | ||
882 | cl_s = vmalloc(udc_cnt * sizeof(*cl_s)); | 882 | cl_s = vmalloc(udc_cnt * sizeof(*cl_s)); |
883 | if (!cl_s) | 883 | if (!cl_s) |
884 | return -ENOMEM; | 884 | return -ENOMEM; |
885 | i = 0; /* the i'th udc */ | 885 | i = 0; /* the i'th udc */ |
886 | EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size, | 886 | EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size, |
887 | ebt_get_udc_positions, newinfo, &i, cl_s); | 887 | ebt_get_udc_positions, newinfo, &i, cl_s); |
888 | /* sanity check */ | 888 | /* sanity check */ |
889 | if (i != udc_cnt) { | 889 | if (i != udc_cnt) { |
890 | BUGPRINT("i != udc_cnt\n"); | 890 | BUGPRINT("i != udc_cnt\n"); |
891 | vfree(cl_s); | 891 | vfree(cl_s); |
892 | return -EFAULT; | 892 | return -EFAULT; |
893 | } | 893 | } |
894 | } | 894 | } |
895 | 895 | ||
896 | /* Check for loops */ | 896 | /* Check for loops */ |
897 | for (i = 0; i < NF_BR_NUMHOOKS; i++) | 897 | for (i = 0; i < NF_BR_NUMHOOKS; i++) |
898 | if (newinfo->hook_entry[i]) | 898 | if (newinfo->hook_entry[i]) |
899 | if (check_chainloops(newinfo->hook_entry[i], | 899 | if (check_chainloops(newinfo->hook_entry[i], |
900 | cl_s, udc_cnt, i, newinfo->entries)) { | 900 | cl_s, udc_cnt, i, newinfo->entries)) { |
901 | vfree(cl_s); | 901 | vfree(cl_s); |
902 | return -EINVAL; | 902 | return -EINVAL; |
903 | } | 903 | } |
904 | 904 | ||
905 | /* we now know the following (along with E=mcยฒ): | 905 | /* we now know the following (along with E=mcยฒ): |
906 | - the nr of entries in each chain is right | 906 | - the nr of entries in each chain is right |
907 | - the size of the allocated space is right | 907 | - the size of the allocated space is right |
908 | - all valid hooks have a corresponding chain | 908 | - all valid hooks have a corresponding chain |
909 | - there are no loops | 909 | - there are no loops |
910 | - wrong data can still be on the level of a single entry | 910 | - wrong data can still be on the level of a single entry |
911 | - could be there are jumps to places that are not the | 911 | - could be there are jumps to places that are not the |
912 | beginning of a chain. This can only occur in chains that | 912 | beginning of a chain. This can only occur in chains that |
913 | are not accessible from any base chains, so we don't care. */ | 913 | are not accessible from any base chains, so we don't care. */ |
914 | 914 | ||
915 | /* used to know what we need to clean up if something goes wrong */ | 915 | /* used to know what we need to clean up if something goes wrong */ |
916 | i = 0; | 916 | i = 0; |
917 | ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size, | 917 | ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size, |
918 | ebt_check_entry, newinfo, name, &i, cl_s, udc_cnt); | 918 | ebt_check_entry, newinfo, name, &i, cl_s, udc_cnt); |
919 | if (ret != 0) { | 919 | if (ret != 0) { |
920 | EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size, | 920 | EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size, |
921 | ebt_cleanup_entry, &i); | 921 | ebt_cleanup_entry, &i); |
922 | } | 922 | } |
923 | vfree(cl_s); | 923 | vfree(cl_s); |
924 | return ret; | 924 | return ret; |
925 | } | 925 | } |
926 | 926 | ||
927 | /* called under write_lock */ | 927 | /* called under write_lock */ |
928 | static void get_counters(struct ebt_counter *oldcounters, | 928 | static void get_counters(struct ebt_counter *oldcounters, |
929 | struct ebt_counter *counters, unsigned int nentries) | 929 | struct ebt_counter *counters, unsigned int nentries) |
930 | { | 930 | { |
931 | int i, cpu; | 931 | int i, cpu; |
932 | struct ebt_counter *counter_base; | 932 | struct ebt_counter *counter_base; |
933 | 933 | ||
934 | /* counters of cpu 0 */ | 934 | /* counters of cpu 0 */ |
935 | memcpy(counters, oldcounters, | 935 | memcpy(counters, oldcounters, |
936 | sizeof(struct ebt_counter) * nentries); | 936 | sizeof(struct ebt_counter) * nentries); |
937 | 937 | ||
938 | /* add other counters to those of cpu 0 */ | 938 | /* add other counters to those of cpu 0 */ |
939 | for_each_possible_cpu(cpu) { | 939 | for_each_possible_cpu(cpu) { |
940 | if (cpu == 0) | 940 | if (cpu == 0) |
941 | continue; | 941 | continue; |
942 | counter_base = COUNTER_BASE(oldcounters, nentries, cpu); | 942 | counter_base = COUNTER_BASE(oldcounters, nentries, cpu); |
943 | for (i = 0; i < nentries; i++) { | 943 | for (i = 0; i < nentries; i++) { |
944 | counters[i].pcnt += counter_base[i].pcnt; | 944 | counters[i].pcnt += counter_base[i].pcnt; |
945 | counters[i].bcnt += counter_base[i].bcnt; | 945 | counters[i].bcnt += counter_base[i].bcnt; |
946 | } | 946 | } |
947 | } | 947 | } |
948 | } | 948 | } |
949 | 949 | ||
950 | /* replace the table */ | 950 | /* replace the table */ |
951 | static int do_replace(void __user *user, unsigned int len) | 951 | static int do_replace(void __user *user, unsigned int len) |
952 | { | 952 | { |
953 | int ret, i, countersize; | 953 | int ret, i, countersize; |
954 | struct ebt_table_info *newinfo; | 954 | struct ebt_table_info *newinfo; |
955 | struct ebt_replace tmp; | 955 | struct ebt_replace tmp; |
956 | struct ebt_table *t; | 956 | struct ebt_table *t; |
957 | struct ebt_counter *counterstmp = NULL; | 957 | struct ebt_counter *counterstmp = NULL; |
958 | /* used to be able to unlock earlier */ | 958 | /* used to be able to unlock earlier */ |
959 | struct ebt_table_info *table; | 959 | struct ebt_table_info *table; |
960 | 960 | ||
961 | if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) | 961 | if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) |
962 | return -EFAULT; | 962 | return -EFAULT; |
963 | 963 | ||
964 | if (len != sizeof(tmp) + tmp.entries_size) { | 964 | if (len != sizeof(tmp) + tmp.entries_size) { |
965 | BUGPRINT("Wrong len argument\n"); | 965 | BUGPRINT("Wrong len argument\n"); |
966 | return -EINVAL; | 966 | return -EINVAL; |
967 | } | 967 | } |
968 | 968 | ||
969 | if (tmp.entries_size == 0) { | 969 | if (tmp.entries_size == 0) { |
970 | BUGPRINT("Entries_size never zero\n"); | 970 | BUGPRINT("Entries_size never zero\n"); |
971 | return -EINVAL; | 971 | return -EINVAL; |
972 | } | 972 | } |
973 | /* overflow check */ | 973 | /* overflow check */ |
974 | if (tmp.nentries >= ((INT_MAX - sizeof(struct ebt_table_info)) / NR_CPUS - | 974 | if (tmp.nentries >= ((INT_MAX - sizeof(struct ebt_table_info)) / NR_CPUS - |
975 | SMP_CACHE_BYTES) / sizeof(struct ebt_counter)) | 975 | SMP_CACHE_BYTES) / sizeof(struct ebt_counter)) |
976 | return -ENOMEM; | 976 | return -ENOMEM; |
977 | if (tmp.num_counters >= INT_MAX / sizeof(struct ebt_counter)) | 977 | if (tmp.num_counters >= INT_MAX / sizeof(struct ebt_counter)) |
978 | return -ENOMEM; | 978 | return -ENOMEM; |
979 | 979 | ||
980 | countersize = COUNTER_OFFSET(tmp.nentries) * nr_cpu_ids; | 980 | countersize = COUNTER_OFFSET(tmp.nentries) * nr_cpu_ids; |
981 | newinfo = vmalloc(sizeof(*newinfo) + countersize); | 981 | newinfo = vmalloc(sizeof(*newinfo) + countersize); |
982 | if (!newinfo) | 982 | if (!newinfo) |
983 | return -ENOMEM; | 983 | return -ENOMEM; |
984 | 984 | ||
985 | if (countersize) | 985 | if (countersize) |
986 | memset(newinfo->counters, 0, countersize); | 986 | memset(newinfo->counters, 0, countersize); |
987 | 987 | ||
988 | newinfo->entries = vmalloc(tmp.entries_size); | 988 | newinfo->entries = vmalloc(tmp.entries_size); |
989 | if (!newinfo->entries) { | 989 | if (!newinfo->entries) { |
990 | ret = -ENOMEM; | 990 | ret = -ENOMEM; |
991 | goto free_newinfo; | 991 | goto free_newinfo; |
992 | } | 992 | } |
993 | if (copy_from_user( | 993 | if (copy_from_user( |
994 | newinfo->entries, tmp.entries, tmp.entries_size) != 0) { | 994 | newinfo->entries, tmp.entries, tmp.entries_size) != 0) { |
995 | BUGPRINT("Couldn't copy entries from userspace\n"); | 995 | BUGPRINT("Couldn't copy entries from userspace\n"); |
996 | ret = -EFAULT; | 996 | ret = -EFAULT; |
997 | goto free_entries; | 997 | goto free_entries; |
998 | } | 998 | } |
999 | 999 | ||
1000 | /* the user wants counters back | 1000 | /* the user wants counters back |
1001 | the check on the size is done later, when we have the lock */ | 1001 | the check on the size is done later, when we have the lock */ |
1002 | if (tmp.num_counters) { | 1002 | if (tmp.num_counters) { |
1003 | counterstmp = vmalloc(tmp.num_counters * sizeof(*counterstmp)); | 1003 | counterstmp = vmalloc(tmp.num_counters * sizeof(*counterstmp)); |
1004 | if (!counterstmp) { | 1004 | if (!counterstmp) { |
1005 | ret = -ENOMEM; | 1005 | ret = -ENOMEM; |
1006 | goto free_entries; | 1006 | goto free_entries; |
1007 | } | 1007 | } |
1008 | } | 1008 | } |
1009 | else | 1009 | else |
1010 | counterstmp = NULL; | 1010 | counterstmp = NULL; |
1011 | 1011 | ||
1012 | /* this can get initialized by translate_table() */ | 1012 | /* this can get initialized by translate_table() */ |
1013 | newinfo->chainstack = NULL; | 1013 | newinfo->chainstack = NULL; |
1014 | ret = ebt_verify_pointers(&tmp, newinfo); | 1014 | ret = ebt_verify_pointers(&tmp, newinfo); |
1015 | if (ret != 0) | 1015 | if (ret != 0) |
1016 | goto free_counterstmp; | 1016 | goto free_counterstmp; |
1017 | 1017 | ||
1018 | ret = translate_table(tmp.name, newinfo); | 1018 | ret = translate_table(tmp.name, newinfo); |
1019 | 1019 | ||
1020 | if (ret != 0) | 1020 | if (ret != 0) |
1021 | goto free_counterstmp; | 1021 | goto free_counterstmp; |
1022 | 1022 | ||
1023 | t = find_table_lock(tmp.name, &ret, &ebt_mutex); | 1023 | t = find_table_lock(tmp.name, &ret, &ebt_mutex); |
1024 | if (!t) { | 1024 | if (!t) { |
1025 | ret = -ENOENT; | 1025 | ret = -ENOENT; |
1026 | goto free_iterate; | 1026 | goto free_iterate; |
1027 | } | 1027 | } |
1028 | 1028 | ||
1029 | /* the table doesn't like it */ | 1029 | /* the table doesn't like it */ |
1030 | if (t->check && (ret = t->check(newinfo, tmp.valid_hooks))) | 1030 | if (t->check && (ret = t->check(newinfo, tmp.valid_hooks))) |
1031 | goto free_unlock; | 1031 | goto free_unlock; |
1032 | 1032 | ||
1033 | if (tmp.num_counters && tmp.num_counters != t->private->nentries) { | 1033 | if (tmp.num_counters && tmp.num_counters != t->private->nentries) { |
1034 | BUGPRINT("Wrong nr. of counters requested\n"); | 1034 | BUGPRINT("Wrong nr. of counters requested\n"); |
1035 | ret = -EINVAL; | 1035 | ret = -EINVAL; |
1036 | goto free_unlock; | 1036 | goto free_unlock; |
1037 | } | 1037 | } |
1038 | 1038 | ||
1039 | /* we have the mutex lock, so no danger in reading this pointer */ | 1039 | /* we have the mutex lock, so no danger in reading this pointer */ |
1040 | table = t->private; | 1040 | table = t->private; |
1041 | /* make sure the table can only be rmmod'ed if it contains no rules */ | 1041 | /* make sure the table can only be rmmod'ed if it contains no rules */ |
1042 | if (!table->nentries && newinfo->nentries && !try_module_get(t->me)) { | 1042 | if (!table->nentries && newinfo->nentries && !try_module_get(t->me)) { |
1043 | ret = -ENOENT; | 1043 | ret = -ENOENT; |
1044 | goto free_unlock; | 1044 | goto free_unlock; |
1045 | } else if (table->nentries && !newinfo->nentries) | 1045 | } else if (table->nentries && !newinfo->nentries) |
1046 | module_put(t->me); | 1046 | module_put(t->me); |
1047 | /* we need an atomic snapshot of the counters */ | 1047 | /* we need an atomic snapshot of the counters */ |
1048 | write_lock_bh(&t->lock); | 1048 | write_lock_bh(&t->lock); |
1049 | if (tmp.num_counters) | 1049 | if (tmp.num_counters) |
1050 | get_counters(t->private->counters, counterstmp, | 1050 | get_counters(t->private->counters, counterstmp, |
1051 | t->private->nentries); | 1051 | t->private->nentries); |
1052 | 1052 | ||
1053 | t->private = newinfo; | 1053 | t->private = newinfo; |
1054 | write_unlock_bh(&t->lock); | 1054 | write_unlock_bh(&t->lock); |
1055 | mutex_unlock(&ebt_mutex); | 1055 | mutex_unlock(&ebt_mutex); |
1056 | /* so, a user can change the chains while having messed up her counter | 1056 | /* so, a user can change the chains while having messed up her counter |
1057 | allocation. Only reason why this is done is because this way the lock | 1057 | allocation. Only reason why this is done is because this way the lock |
1058 | is held only once, while this doesn't bring the kernel into a | 1058 | is held only once, while this doesn't bring the kernel into a |
1059 | dangerous state. */ | 1059 | dangerous state. */ |
1060 | if (tmp.num_counters && | 1060 | if (tmp.num_counters && |
1061 | copy_to_user(tmp.counters, counterstmp, | 1061 | copy_to_user(tmp.counters, counterstmp, |
1062 | tmp.num_counters * sizeof(struct ebt_counter))) { | 1062 | tmp.num_counters * sizeof(struct ebt_counter))) { |
1063 | BUGPRINT("Couldn't copy counters to userspace\n"); | 1063 | BUGPRINT("Couldn't copy counters to userspace\n"); |
1064 | ret = -EFAULT; | 1064 | ret = -EFAULT; |
1065 | } | 1065 | } |
1066 | else | 1066 | else |
1067 | ret = 0; | 1067 | ret = 0; |
1068 | 1068 | ||
1069 | /* decrease module count and free resources */ | 1069 | /* decrease module count and free resources */ |
1070 | EBT_ENTRY_ITERATE(table->entries, table->entries_size, | 1070 | EBT_ENTRY_ITERATE(table->entries, table->entries_size, |
1071 | ebt_cleanup_entry, NULL); | 1071 | ebt_cleanup_entry, NULL); |
1072 | 1072 | ||
1073 | vfree(table->entries); | 1073 | vfree(table->entries); |
1074 | if (table->chainstack) { | 1074 | if (table->chainstack) { |
1075 | for_each_possible_cpu(i) | 1075 | for_each_possible_cpu(i) |
1076 | vfree(table->chainstack[i]); | 1076 | vfree(table->chainstack[i]); |
1077 | vfree(table->chainstack); | 1077 | vfree(table->chainstack); |
1078 | } | 1078 | } |
1079 | vfree(table); | 1079 | vfree(table); |
1080 | 1080 | ||
1081 | vfree(counterstmp); | 1081 | vfree(counterstmp); |
1082 | return ret; | 1082 | return ret; |
1083 | 1083 | ||
1084 | free_unlock: | 1084 | free_unlock: |
1085 | mutex_unlock(&ebt_mutex); | 1085 | mutex_unlock(&ebt_mutex); |
1086 | free_iterate: | 1086 | free_iterate: |
1087 | EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size, | 1087 | EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size, |
1088 | ebt_cleanup_entry, NULL); | 1088 | ebt_cleanup_entry, NULL); |
1089 | free_counterstmp: | 1089 | free_counterstmp: |
1090 | vfree(counterstmp); | 1090 | vfree(counterstmp); |
1091 | /* can be initialized in translate_table() */ | 1091 | /* can be initialized in translate_table() */ |
1092 | if (newinfo->chainstack) { | 1092 | if (newinfo->chainstack) { |
1093 | for_each_possible_cpu(i) | 1093 | for_each_possible_cpu(i) |
1094 | vfree(newinfo->chainstack[i]); | 1094 | vfree(newinfo->chainstack[i]); |
1095 | vfree(newinfo->chainstack); | 1095 | vfree(newinfo->chainstack); |
1096 | } | 1096 | } |
1097 | free_entries: | 1097 | free_entries: |
1098 | vfree(newinfo->entries); | 1098 | vfree(newinfo->entries); |
1099 | free_newinfo: | 1099 | free_newinfo: |
1100 | vfree(newinfo); | 1100 | vfree(newinfo); |
1101 | return ret; | 1101 | return ret; |
1102 | } | 1102 | } |
1103 | 1103 | ||
1104 | int ebt_register_target(struct ebt_target *target) | 1104 | int ebt_register_target(struct ebt_target *target) |
1105 | { | 1105 | { |
1106 | struct ebt_target *t; | 1106 | struct ebt_target *t; |
1107 | int ret; | 1107 | int ret; |
1108 | 1108 | ||
1109 | ret = mutex_lock_interruptible(&ebt_mutex); | 1109 | ret = mutex_lock_interruptible(&ebt_mutex); |
1110 | if (ret != 0) | 1110 | if (ret != 0) |
1111 | return ret; | 1111 | return ret; |
1112 | list_for_each_entry(t, &ebt_targets, list) { | 1112 | list_for_each_entry(t, &ebt_targets, list) { |
1113 | if (strcmp(t->name, target->name) == 0) { | 1113 | if (strcmp(t->name, target->name) == 0) { |
1114 | mutex_unlock(&ebt_mutex); | 1114 | mutex_unlock(&ebt_mutex); |
1115 | return -EEXIST; | 1115 | return -EEXIST; |
1116 | } | 1116 | } |
1117 | } | 1117 | } |
1118 | list_add(&target->list, &ebt_targets); | 1118 | list_add(&target->list, &ebt_targets); |
1119 | mutex_unlock(&ebt_mutex); | 1119 | mutex_unlock(&ebt_mutex); |
1120 | 1120 | ||
1121 | return 0; | 1121 | return 0; |
1122 | } | 1122 | } |
1123 | 1123 | ||
1124 | void ebt_unregister_target(struct ebt_target *target) | 1124 | void ebt_unregister_target(struct ebt_target *target) |
1125 | { | 1125 | { |
1126 | mutex_lock(&ebt_mutex); | 1126 | mutex_lock(&ebt_mutex); |
1127 | list_del(&target->list); | 1127 | list_del(&target->list); |
1128 | mutex_unlock(&ebt_mutex); | 1128 | mutex_unlock(&ebt_mutex); |
1129 | } | 1129 | } |
1130 | 1130 | ||
1131 | int ebt_register_match(struct ebt_match *match) | 1131 | int ebt_register_match(struct ebt_match *match) |
1132 | { | 1132 | { |
1133 | struct ebt_match *m; | 1133 | struct ebt_match *m; |
1134 | int ret; | 1134 | int ret; |
1135 | 1135 | ||
1136 | ret = mutex_lock_interruptible(&ebt_mutex); | 1136 | ret = mutex_lock_interruptible(&ebt_mutex); |
1137 | if (ret != 0) | 1137 | if (ret != 0) |
1138 | return ret; | 1138 | return ret; |
1139 | list_for_each_entry(m, &ebt_matches, list) { | 1139 | list_for_each_entry(m, &ebt_matches, list) { |
1140 | if (strcmp(m->name, match->name) == 0) { | 1140 | if (strcmp(m->name, match->name) == 0) { |
1141 | mutex_unlock(&ebt_mutex); | 1141 | mutex_unlock(&ebt_mutex); |
1142 | return -EEXIST; | 1142 | return -EEXIST; |
1143 | } | 1143 | } |
1144 | } | 1144 | } |
1145 | list_add(&match->list, &ebt_matches); | 1145 | list_add(&match->list, &ebt_matches); |
1146 | mutex_unlock(&ebt_mutex); | 1146 | mutex_unlock(&ebt_mutex); |
1147 | 1147 | ||
1148 | return 0; | 1148 | return 0; |
1149 | } | 1149 | } |
1150 | 1150 | ||
1151 | void ebt_unregister_match(struct ebt_match *match) | 1151 | void ebt_unregister_match(struct ebt_match *match) |
1152 | { | 1152 | { |
1153 | mutex_lock(&ebt_mutex); | 1153 | mutex_lock(&ebt_mutex); |
1154 | list_del(&match->list); | 1154 | list_del(&match->list); |
1155 | mutex_unlock(&ebt_mutex); | 1155 | mutex_unlock(&ebt_mutex); |
1156 | } | 1156 | } |
1157 | 1157 | ||
1158 | int ebt_register_watcher(struct ebt_watcher *watcher) | 1158 | int ebt_register_watcher(struct ebt_watcher *watcher) |
1159 | { | 1159 | { |
1160 | struct ebt_watcher *w; | 1160 | struct ebt_watcher *w; |
1161 | int ret; | 1161 | int ret; |
1162 | 1162 | ||
1163 | ret = mutex_lock_interruptible(&ebt_mutex); | 1163 | ret = mutex_lock_interruptible(&ebt_mutex); |
1164 | if (ret != 0) | 1164 | if (ret != 0) |
1165 | return ret; | 1165 | return ret; |
1166 | list_for_each_entry(w, &ebt_watchers, list) { | 1166 | list_for_each_entry(w, &ebt_watchers, list) { |
1167 | if (strcmp(w->name, watcher->name) == 0) { | 1167 | if (strcmp(w->name, watcher->name) == 0) { |
1168 | mutex_unlock(&ebt_mutex); | 1168 | mutex_unlock(&ebt_mutex); |
1169 | return -EEXIST; | 1169 | return -EEXIST; |
1170 | } | 1170 | } |
1171 | } | 1171 | } |
1172 | list_add(&watcher->list, &ebt_watchers); | 1172 | list_add(&watcher->list, &ebt_watchers); |
1173 | mutex_unlock(&ebt_mutex); | 1173 | mutex_unlock(&ebt_mutex); |
1174 | 1174 | ||
1175 | return 0; | 1175 | return 0; |
1176 | } | 1176 | } |
1177 | 1177 | ||
1178 | void ebt_unregister_watcher(struct ebt_watcher *watcher) | 1178 | void ebt_unregister_watcher(struct ebt_watcher *watcher) |
1179 | { | 1179 | { |
1180 | mutex_lock(&ebt_mutex); | 1180 | mutex_lock(&ebt_mutex); |
1181 | list_del(&watcher->list); | 1181 | list_del(&watcher->list); |
1182 | mutex_unlock(&ebt_mutex); | 1182 | mutex_unlock(&ebt_mutex); |
1183 | } | 1183 | } |
1184 | 1184 | ||
1185 | int ebt_register_table(struct ebt_table *table) | 1185 | int ebt_register_table(struct ebt_table *table) |
1186 | { | 1186 | { |
1187 | struct ebt_table_info *newinfo; | 1187 | struct ebt_table_info *newinfo; |
1188 | struct ebt_table *t; | 1188 | struct ebt_table *t; |
1189 | struct ebt_replace_kernel *repl; | 1189 | struct ebt_replace_kernel *repl; |
1190 | int ret, i, countersize; | 1190 | int ret, i, countersize; |
1191 | void *p; | 1191 | void *p; |
1192 | 1192 | ||
1193 | if (!table || !(repl = table->table) || !repl->entries || | 1193 | if (!table || !(repl = table->table) || !repl->entries || |
1194 | repl->entries_size == 0 || | 1194 | repl->entries_size == 0 || |
1195 | repl->counters || table->private) { | 1195 | repl->counters || table->private) { |
1196 | BUGPRINT("Bad table data for ebt_register_table!!!\n"); | 1196 | BUGPRINT("Bad table data for ebt_register_table!!!\n"); |
1197 | return -EINVAL; | 1197 | return -EINVAL; |
1198 | } | 1198 | } |
1199 | 1199 | ||
1200 | countersize = COUNTER_OFFSET(repl->nentries) * nr_cpu_ids; | 1200 | countersize = COUNTER_OFFSET(repl->nentries) * nr_cpu_ids; |
1201 | newinfo = vmalloc(sizeof(*newinfo) + countersize); | 1201 | newinfo = vmalloc(sizeof(*newinfo) + countersize); |
1202 | ret = -ENOMEM; | 1202 | ret = -ENOMEM; |
1203 | if (!newinfo) | 1203 | if (!newinfo) |
1204 | return -ENOMEM; | 1204 | return -ENOMEM; |
1205 | 1205 | ||
1206 | p = vmalloc(repl->entries_size); | 1206 | p = vmalloc(repl->entries_size); |
1207 | if (!p) | 1207 | if (!p) |
1208 | goto free_newinfo; | 1208 | goto free_newinfo; |
1209 | 1209 | ||
1210 | memcpy(p, repl->entries, repl->entries_size); | 1210 | memcpy(p, repl->entries, repl->entries_size); |
1211 | newinfo->entries = p; | 1211 | newinfo->entries = p; |
1212 | 1212 | ||
1213 | newinfo->entries_size = repl->entries_size; | 1213 | newinfo->entries_size = repl->entries_size; |
1214 | newinfo->nentries = repl->nentries; | 1214 | newinfo->nentries = repl->nentries; |
1215 | 1215 | ||
1216 | if (countersize) | 1216 | if (countersize) |
1217 | memset(newinfo->counters, 0, countersize); | 1217 | memset(newinfo->counters, 0, countersize); |
1218 | 1218 | ||
1219 | /* fill in newinfo and parse the entries */ | 1219 | /* fill in newinfo and parse the entries */ |
1220 | newinfo->chainstack = NULL; | 1220 | newinfo->chainstack = NULL; |
1221 | for (i = 0; i < NF_BR_NUMHOOKS; i++) { | 1221 | for (i = 0; i < NF_BR_NUMHOOKS; i++) { |
1222 | if ((repl->valid_hooks & (1 << i)) == 0) | 1222 | if ((repl->valid_hooks & (1 << i)) == 0) |
1223 | newinfo->hook_entry[i] = NULL; | 1223 | newinfo->hook_entry[i] = NULL; |
1224 | else | 1224 | else |
1225 | newinfo->hook_entry[i] = p + | 1225 | newinfo->hook_entry[i] = p + |
1226 | ((char *)repl->hook_entry[i] - repl->entries); | 1226 | ((char *)repl->hook_entry[i] - repl->entries); |
1227 | } | 1227 | } |
1228 | ret = translate_table(repl->name, newinfo); | 1228 | ret = translate_table(repl->name, newinfo); |
1229 | if (ret != 0) { | 1229 | if (ret != 0) { |
1230 | BUGPRINT("Translate_table failed\n"); | 1230 | BUGPRINT("Translate_table failed\n"); |
1231 | goto free_chainstack; | 1231 | goto free_chainstack; |
1232 | } | 1232 | } |
1233 | 1233 | ||
1234 | if (table->check && table->check(newinfo, table->valid_hooks)) { | 1234 | if (table->check && table->check(newinfo, table->valid_hooks)) { |
1235 | BUGPRINT("The table doesn't like its own initial data, lol\n"); | 1235 | BUGPRINT("The table doesn't like its own initial data, lol\n"); |
1236 | return -EINVAL; | 1236 | return -EINVAL; |
1237 | } | 1237 | } |
1238 | 1238 | ||
1239 | table->private = newinfo; | 1239 | table->private = newinfo; |
1240 | rwlock_init(&table->lock); | 1240 | rwlock_init(&table->lock); |
1241 | ret = mutex_lock_interruptible(&ebt_mutex); | 1241 | ret = mutex_lock_interruptible(&ebt_mutex); |
1242 | if (ret != 0) | 1242 | if (ret != 0) |
1243 | goto free_chainstack; | 1243 | goto free_chainstack; |
1244 | 1244 | ||
1245 | list_for_each_entry(t, &ebt_tables, list) { | 1245 | list_for_each_entry(t, &ebt_tables, list) { |
1246 | if (strcmp(t->name, table->name) == 0) { | 1246 | if (strcmp(t->name, table->name) == 0) { |
1247 | ret = -EEXIST; | 1247 | ret = -EEXIST; |
1248 | BUGPRINT("Table name already exists\n"); | 1248 | BUGPRINT("Table name already exists\n"); |
1249 | goto free_unlock; | 1249 | goto free_unlock; |
1250 | } | 1250 | } |
1251 | } | 1251 | } |
1252 | 1252 | ||
1253 | /* Hold a reference count if the chains aren't empty */ | 1253 | /* Hold a reference count if the chains aren't empty */ |
1254 | if (newinfo->nentries && !try_module_get(table->me)) { | 1254 | if (newinfo->nentries && !try_module_get(table->me)) { |
1255 | ret = -ENOENT; | 1255 | ret = -ENOENT; |
1256 | goto free_unlock; | 1256 | goto free_unlock; |
1257 | } | 1257 | } |
1258 | list_add(&table->list, &ebt_tables); | 1258 | list_add(&table->list, &ebt_tables); |
1259 | mutex_unlock(&ebt_mutex); | 1259 | mutex_unlock(&ebt_mutex); |
1260 | return 0; | 1260 | return 0; |
1261 | free_unlock: | 1261 | free_unlock: |
1262 | mutex_unlock(&ebt_mutex); | 1262 | mutex_unlock(&ebt_mutex); |
1263 | free_chainstack: | 1263 | free_chainstack: |
1264 | if (newinfo->chainstack) { | 1264 | if (newinfo->chainstack) { |
1265 | for_each_possible_cpu(i) | 1265 | for_each_possible_cpu(i) |
1266 | vfree(newinfo->chainstack[i]); | 1266 | vfree(newinfo->chainstack[i]); |
1267 | vfree(newinfo->chainstack); | 1267 | vfree(newinfo->chainstack); |
1268 | } | 1268 | } |
1269 | vfree(newinfo->entries); | 1269 | vfree(newinfo->entries); |
1270 | free_newinfo: | 1270 | free_newinfo: |
1271 | vfree(newinfo); | 1271 | vfree(newinfo); |
1272 | return ret; | 1272 | return ret; |
1273 | } | 1273 | } |
1274 | 1274 | ||
1275 | void ebt_unregister_table(struct ebt_table *table) | 1275 | void ebt_unregister_table(struct ebt_table *table) |
1276 | { | 1276 | { |
1277 | int i; | 1277 | int i; |
1278 | 1278 | ||
1279 | if (!table) { | 1279 | if (!table) { |
1280 | BUGPRINT("Request to unregister NULL table!!!\n"); | 1280 | BUGPRINT("Request to unregister NULL table!!!\n"); |
1281 | return; | 1281 | return; |
1282 | } | 1282 | } |
1283 | mutex_lock(&ebt_mutex); | 1283 | mutex_lock(&ebt_mutex); |
1284 | list_del(&table->list); | 1284 | list_del(&table->list); |
1285 | mutex_unlock(&ebt_mutex); | 1285 | mutex_unlock(&ebt_mutex); |
1286 | vfree(table->private->entries); | 1286 | vfree(table->private->entries); |
1287 | if (table->private->chainstack) { | 1287 | if (table->private->chainstack) { |
1288 | for_each_possible_cpu(i) | 1288 | for_each_possible_cpu(i) |
1289 | vfree(table->private->chainstack[i]); | 1289 | vfree(table->private->chainstack[i]); |
1290 | vfree(table->private->chainstack); | 1290 | vfree(table->private->chainstack); |
1291 | } | 1291 | } |
1292 | vfree(table->private); | 1292 | vfree(table->private); |
1293 | } | 1293 | } |
1294 | 1294 | ||
1295 | /* userspace just supplied us with counters */ | 1295 | /* userspace just supplied us with counters */ |
1296 | static int update_counters(void __user *user, unsigned int len) | 1296 | static int update_counters(void __user *user, unsigned int len) |
1297 | { | 1297 | { |
1298 | int i, ret; | 1298 | int i, ret; |
1299 | struct ebt_counter *tmp; | 1299 | struct ebt_counter *tmp; |
1300 | struct ebt_replace hlp; | 1300 | struct ebt_replace hlp; |
1301 | struct ebt_table *t; | 1301 | struct ebt_table *t; |
1302 | 1302 | ||
1303 | if (copy_from_user(&hlp, user, sizeof(hlp))) | 1303 | if (copy_from_user(&hlp, user, sizeof(hlp))) |
1304 | return -EFAULT; | 1304 | return -EFAULT; |
1305 | 1305 | ||
1306 | if (len != sizeof(hlp) + hlp.num_counters * sizeof(struct ebt_counter)) | 1306 | if (len != sizeof(hlp) + hlp.num_counters * sizeof(struct ebt_counter)) |
1307 | return -EINVAL; | 1307 | return -EINVAL; |
1308 | if (hlp.num_counters == 0) | 1308 | if (hlp.num_counters == 0) |
1309 | return -EINVAL; | 1309 | return -EINVAL; |
1310 | 1310 | ||
1311 | if (!(tmp = vmalloc(hlp.num_counters * sizeof(*tmp)))) { | 1311 | if (!(tmp = vmalloc(hlp.num_counters * sizeof(*tmp)))) { |
1312 | MEMPRINT("Update_counters && nomemory\n"); | 1312 | MEMPRINT("Update_counters && nomemory\n"); |
1313 | return -ENOMEM; | 1313 | return -ENOMEM; |
1314 | } | 1314 | } |
1315 | 1315 | ||
1316 | t = find_table_lock(hlp.name, &ret, &ebt_mutex); | 1316 | t = find_table_lock(hlp.name, &ret, &ebt_mutex); |
1317 | if (!t) | 1317 | if (!t) |
1318 | goto free_tmp; | 1318 | goto free_tmp; |
1319 | 1319 | ||
1320 | if (hlp.num_counters != t->private->nentries) { | 1320 | if (hlp.num_counters != t->private->nentries) { |
1321 | BUGPRINT("Wrong nr of counters\n"); | 1321 | BUGPRINT("Wrong nr of counters\n"); |
1322 | ret = -EINVAL; | 1322 | ret = -EINVAL; |
1323 | goto unlock_mutex; | 1323 | goto unlock_mutex; |
1324 | } | 1324 | } |
1325 | 1325 | ||
1326 | if ( copy_from_user(tmp, hlp.counters, | 1326 | if ( copy_from_user(tmp, hlp.counters, |
1327 | hlp.num_counters * sizeof(struct ebt_counter)) ) { | 1327 | hlp.num_counters * sizeof(struct ebt_counter)) ) { |
1328 | BUGPRINT("Updata_counters && !cfu\n"); | 1328 | BUGPRINT("Updata_counters && !cfu\n"); |
1329 | ret = -EFAULT; | 1329 | ret = -EFAULT; |
1330 | goto unlock_mutex; | 1330 | goto unlock_mutex; |
1331 | } | 1331 | } |
1332 | 1332 | ||
1333 | /* we want an atomic add of the counters */ | 1333 | /* we want an atomic add of the counters */ |
1334 | write_lock_bh(&t->lock); | 1334 | write_lock_bh(&t->lock); |
1335 | 1335 | ||
1336 | /* we add to the counters of the first cpu */ | 1336 | /* we add to the counters of the first cpu */ |
1337 | for (i = 0; i < hlp.num_counters; i++) { | 1337 | for (i = 0; i < hlp.num_counters; i++) { |
1338 | t->private->counters[i].pcnt += tmp[i].pcnt; | 1338 | t->private->counters[i].pcnt += tmp[i].pcnt; |
1339 | t->private->counters[i].bcnt += tmp[i].bcnt; | 1339 | t->private->counters[i].bcnt += tmp[i].bcnt; |
1340 | } | 1340 | } |
1341 | 1341 | ||
1342 | write_unlock_bh(&t->lock); | 1342 | write_unlock_bh(&t->lock); |
1343 | ret = 0; | 1343 | ret = 0; |
1344 | unlock_mutex: | 1344 | unlock_mutex: |
1345 | mutex_unlock(&ebt_mutex); | 1345 | mutex_unlock(&ebt_mutex); |
1346 | free_tmp: | 1346 | free_tmp: |
1347 | vfree(tmp); | 1347 | vfree(tmp); |
1348 | return ret; | 1348 | return ret; |
1349 | } | 1349 | } |
1350 | 1350 | ||
1351 | static inline int ebt_make_matchname(struct ebt_entry_match *m, | 1351 | static inline int ebt_make_matchname(struct ebt_entry_match *m, |
1352 | char *base, char __user *ubase) | 1352 | char *base, char __user *ubase) |
1353 | { | 1353 | { |
1354 | char __user *hlp = ubase + ((char *)m - base); | 1354 | char __user *hlp = ubase + ((char *)m - base); |
1355 | if (copy_to_user(hlp, m->u.match->name, EBT_FUNCTION_MAXNAMELEN)) | 1355 | if (copy_to_user(hlp, m->u.match->name, EBT_FUNCTION_MAXNAMELEN)) |
1356 | return -EFAULT; | 1356 | return -EFAULT; |
1357 | return 0; | 1357 | return 0; |
1358 | } | 1358 | } |
1359 | 1359 | ||
1360 | static inline int ebt_make_watchername(struct ebt_entry_watcher *w, | 1360 | static inline int ebt_make_watchername(struct ebt_entry_watcher *w, |
1361 | char *base, char __user *ubase) | 1361 | char *base, char __user *ubase) |
1362 | { | 1362 | { |
1363 | char __user *hlp = ubase + ((char *)w - base); | 1363 | char __user *hlp = ubase + ((char *)w - base); |
1364 | if (copy_to_user(hlp , w->u.watcher->name, EBT_FUNCTION_MAXNAMELEN)) | 1364 | if (copy_to_user(hlp , w->u.watcher->name, EBT_FUNCTION_MAXNAMELEN)) |
1365 | return -EFAULT; | 1365 | return -EFAULT; |
1366 | return 0; | 1366 | return 0; |
1367 | } | 1367 | } |
1368 | 1368 | ||
1369 | static inline int ebt_make_names(struct ebt_entry *e, char *base, char __user *ubase) | 1369 | static inline int ebt_make_names(struct ebt_entry *e, char *base, char __user *ubase) |
1370 | { | 1370 | { |
1371 | int ret; | 1371 | int ret; |
1372 | char __user *hlp; | 1372 | char __user *hlp; |
1373 | struct ebt_entry_target *t; | 1373 | struct ebt_entry_target *t; |
1374 | 1374 | ||
1375 | if (e->bitmask == 0) | 1375 | if (e->bitmask == 0) |
1376 | return 0; | 1376 | return 0; |
1377 | 1377 | ||
1378 | hlp = ubase + (((char *)e + e->target_offset) - base); | 1378 | hlp = ubase + (((char *)e + e->target_offset) - base); |
1379 | t = (struct ebt_entry_target *)(((char *)e) + e->target_offset); | 1379 | t = (struct ebt_entry_target *)(((char *)e) + e->target_offset); |
1380 | 1380 | ||
1381 | ret = EBT_MATCH_ITERATE(e, ebt_make_matchname, base, ubase); | 1381 | ret = EBT_MATCH_ITERATE(e, ebt_make_matchname, base, ubase); |
1382 | if (ret != 0) | 1382 | if (ret != 0) |
1383 | return ret; | 1383 | return ret; |
1384 | ret = EBT_WATCHER_ITERATE(e, ebt_make_watchername, base, ubase); | 1384 | ret = EBT_WATCHER_ITERATE(e, ebt_make_watchername, base, ubase); |
1385 | if (ret != 0) | 1385 | if (ret != 0) |
1386 | return ret; | 1386 | return ret; |
1387 | if (copy_to_user(hlp, t->u.target->name, EBT_FUNCTION_MAXNAMELEN)) | 1387 | if (copy_to_user(hlp, t->u.target->name, EBT_FUNCTION_MAXNAMELEN)) |
1388 | return -EFAULT; | 1388 | return -EFAULT; |
1389 | return 0; | 1389 | return 0; |
1390 | } | 1390 | } |
1391 | 1391 | ||
1392 | /* called with ebt_mutex locked */ | 1392 | /* called with ebt_mutex locked */ |
1393 | static int copy_everything_to_user(struct ebt_table *t, void __user *user, | 1393 | static int copy_everything_to_user(struct ebt_table *t, void __user *user, |
1394 | int *len, int cmd) | 1394 | int *len, int cmd) |
1395 | { | 1395 | { |
1396 | struct ebt_replace tmp; | 1396 | struct ebt_replace tmp; |
1397 | struct ebt_counter *counterstmp, *oldcounters; | 1397 | struct ebt_counter *counterstmp, *oldcounters; |
1398 | unsigned int entries_size, nentries; | 1398 | unsigned int entries_size, nentries; |
1399 | char *entries; | 1399 | char *entries; |
1400 | 1400 | ||
1401 | if (cmd == EBT_SO_GET_ENTRIES) { | 1401 | if (cmd == EBT_SO_GET_ENTRIES) { |
1402 | entries_size = t->private->entries_size; | 1402 | entries_size = t->private->entries_size; |
1403 | nentries = t->private->nentries; | 1403 | nentries = t->private->nentries; |
1404 | entries = t->private->entries; | 1404 | entries = t->private->entries; |
1405 | oldcounters = t->private->counters; | 1405 | oldcounters = t->private->counters; |
1406 | } else { | 1406 | } else { |
1407 | entries_size = t->table->entries_size; | 1407 | entries_size = t->table->entries_size; |
1408 | nentries = t->table->nentries; | 1408 | nentries = t->table->nentries; |
1409 | entries = t->table->entries; | 1409 | entries = t->table->entries; |
1410 | oldcounters = t->table->counters; | 1410 | oldcounters = t->table->counters; |
1411 | } | 1411 | } |
1412 | 1412 | ||
1413 | if (copy_from_user(&tmp, user, sizeof(tmp))) { | 1413 | if (copy_from_user(&tmp, user, sizeof(tmp))) { |
1414 | BUGPRINT("Cfu didn't work\n"); | 1414 | BUGPRINT("Cfu didn't work\n"); |
1415 | return -EFAULT; | 1415 | return -EFAULT; |
1416 | } | 1416 | } |
1417 | 1417 | ||
1418 | if (*len != sizeof(struct ebt_replace) + entries_size + | 1418 | if (*len != sizeof(struct ebt_replace) + entries_size + |
1419 | (tmp.num_counters? nentries * sizeof(struct ebt_counter): 0)) { | 1419 | (tmp.num_counters? nentries * sizeof(struct ebt_counter): 0)) { |
1420 | BUGPRINT("Wrong size\n"); | 1420 | BUGPRINT("Wrong size\n"); |
1421 | return -EINVAL; | 1421 | return -EINVAL; |
1422 | } | 1422 | } |
1423 | 1423 | ||
1424 | if (tmp.nentries != nentries) { | 1424 | if (tmp.nentries != nentries) { |
1425 | BUGPRINT("Nentries wrong\n"); | 1425 | BUGPRINT("Nentries wrong\n"); |
1426 | return -EINVAL; | 1426 | return -EINVAL; |
1427 | } | 1427 | } |
1428 | 1428 | ||
1429 | if (tmp.entries_size != entries_size) { | 1429 | if (tmp.entries_size != entries_size) { |
1430 | BUGPRINT("Wrong size\n"); | 1430 | BUGPRINT("Wrong size\n"); |
1431 | return -EINVAL; | 1431 | return -EINVAL; |
1432 | } | 1432 | } |
1433 | 1433 | ||
1434 | /* userspace might not need the counters */ | 1434 | /* userspace might not need the counters */ |
1435 | if (tmp.num_counters) { | 1435 | if (tmp.num_counters) { |
1436 | if (tmp.num_counters != nentries) { | 1436 | if (tmp.num_counters != nentries) { |
1437 | BUGPRINT("Num_counters wrong\n"); | 1437 | BUGPRINT("Num_counters wrong\n"); |
1438 | return -EINVAL; | 1438 | return -EINVAL; |
1439 | } | 1439 | } |
1440 | counterstmp = vmalloc(nentries * sizeof(*counterstmp)); | 1440 | counterstmp = vmalloc(nentries * sizeof(*counterstmp)); |
1441 | if (!counterstmp) { | 1441 | if (!counterstmp) { |
1442 | MEMPRINT("Couldn't copy counters, out of memory\n"); | 1442 | MEMPRINT("Couldn't copy counters, out of memory\n"); |
1443 | return -ENOMEM; | 1443 | return -ENOMEM; |
1444 | } | 1444 | } |
1445 | write_lock_bh(&t->lock); | 1445 | write_lock_bh(&t->lock); |
1446 | get_counters(oldcounters, counterstmp, nentries); | 1446 | get_counters(oldcounters, counterstmp, nentries); |
1447 | write_unlock_bh(&t->lock); | 1447 | write_unlock_bh(&t->lock); |
1448 | 1448 | ||
1449 | if (copy_to_user(tmp.counters, counterstmp, | 1449 | if (copy_to_user(tmp.counters, counterstmp, |
1450 | nentries * sizeof(struct ebt_counter))) { | 1450 | nentries * sizeof(struct ebt_counter))) { |
1451 | BUGPRINT("Couldn't copy counters to userspace\n"); | 1451 | BUGPRINT("Couldn't copy counters to userspace\n"); |
1452 | vfree(counterstmp); | 1452 | vfree(counterstmp); |
1453 | return -EFAULT; | 1453 | return -EFAULT; |
1454 | } | 1454 | } |
1455 | vfree(counterstmp); | 1455 | vfree(counterstmp); |
1456 | } | 1456 | } |
1457 | 1457 | ||
1458 | if (copy_to_user(tmp.entries, entries, entries_size)) { | 1458 | if (copy_to_user(tmp.entries, entries, entries_size)) { |
1459 | BUGPRINT("Couldn't copy entries to userspace\n"); | 1459 | BUGPRINT("Couldn't copy entries to userspace\n"); |
1460 | return -EFAULT; | 1460 | return -EFAULT; |
1461 | } | 1461 | } |
1462 | /* set the match/watcher/target names right */ | 1462 | /* set the match/watcher/target names right */ |
1463 | return EBT_ENTRY_ITERATE(entries, entries_size, | 1463 | return EBT_ENTRY_ITERATE(entries, entries_size, |
1464 | ebt_make_names, entries, tmp.entries); | 1464 | ebt_make_names, entries, tmp.entries); |
1465 | } | 1465 | } |
1466 | 1466 | ||
1467 | static int do_ebt_set_ctl(struct sock *sk, | 1467 | static int do_ebt_set_ctl(struct sock *sk, |
1468 | int cmd, void __user *user, unsigned int len) | 1468 | int cmd, void __user *user, unsigned int len) |
1469 | { | 1469 | { |
1470 | int ret; | 1470 | int ret; |
1471 | 1471 | ||
1472 | switch(cmd) { | 1472 | switch(cmd) { |
1473 | case EBT_SO_SET_ENTRIES: | 1473 | case EBT_SO_SET_ENTRIES: |
1474 | ret = do_replace(user, len); | 1474 | ret = do_replace(user, len); |
1475 | break; | 1475 | break; |
1476 | case EBT_SO_SET_COUNTERS: | 1476 | case EBT_SO_SET_COUNTERS: |
1477 | ret = update_counters(user, len); | 1477 | ret = update_counters(user, len); |
1478 | break; | 1478 | break; |
1479 | default: | 1479 | default: |
1480 | ret = -EINVAL; | 1480 | ret = -EINVAL; |
1481 | } | 1481 | } |
1482 | return ret; | 1482 | return ret; |
1483 | } | 1483 | } |
1484 | 1484 | ||
1485 | static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) | 1485 | static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) |
1486 | { | 1486 | { |
1487 | int ret; | 1487 | int ret; |
1488 | struct ebt_replace tmp; | 1488 | struct ebt_replace tmp; |
1489 | struct ebt_table *t; | 1489 | struct ebt_table *t; |
1490 | 1490 | ||
1491 | if (copy_from_user(&tmp, user, sizeof(tmp))) | 1491 | if (copy_from_user(&tmp, user, sizeof(tmp))) |
1492 | return -EFAULT; | 1492 | return -EFAULT; |
1493 | 1493 | ||
1494 | t = find_table_lock(tmp.name, &ret, &ebt_mutex); | 1494 | t = find_table_lock(tmp.name, &ret, &ebt_mutex); |
1495 | if (!t) | 1495 | if (!t) |
1496 | return ret; | 1496 | return ret; |
1497 | 1497 | ||
1498 | switch(cmd) { | 1498 | switch(cmd) { |
1499 | case EBT_SO_GET_INFO: | 1499 | case EBT_SO_GET_INFO: |
1500 | case EBT_SO_GET_INIT_INFO: | 1500 | case EBT_SO_GET_INIT_INFO: |
1501 | if (*len != sizeof(struct ebt_replace)){ | 1501 | if (*len != sizeof(struct ebt_replace)){ |
1502 | ret = -EINVAL; | 1502 | ret = -EINVAL; |
1503 | mutex_unlock(&ebt_mutex); | 1503 | mutex_unlock(&ebt_mutex); |
1504 | break; | 1504 | break; |
1505 | } | 1505 | } |
1506 | if (cmd == EBT_SO_GET_INFO) { | 1506 | if (cmd == EBT_SO_GET_INFO) { |
1507 | tmp.nentries = t->private->nentries; | 1507 | tmp.nentries = t->private->nentries; |
1508 | tmp.entries_size = t->private->entries_size; | 1508 | tmp.entries_size = t->private->entries_size; |
1509 | tmp.valid_hooks = t->valid_hooks; | 1509 | tmp.valid_hooks = t->valid_hooks; |
1510 | } else { | 1510 | } else { |
1511 | tmp.nentries = t->table->nentries; | 1511 | tmp.nentries = t->table->nentries; |
1512 | tmp.entries_size = t->table->entries_size; | 1512 | tmp.entries_size = t->table->entries_size; |
1513 | tmp.valid_hooks = t->table->valid_hooks; | 1513 | tmp.valid_hooks = t->table->valid_hooks; |
1514 | } | 1514 | } |
1515 | mutex_unlock(&ebt_mutex); | 1515 | mutex_unlock(&ebt_mutex); |
1516 | if (copy_to_user(user, &tmp, *len) != 0){ | 1516 | if (copy_to_user(user, &tmp, *len) != 0){ |
1517 | BUGPRINT("c2u Didn't work\n"); | 1517 | BUGPRINT("c2u Didn't work\n"); |
1518 | ret = -EFAULT; | 1518 | ret = -EFAULT; |
1519 | break; | 1519 | break; |
1520 | } | 1520 | } |
1521 | ret = 0; | 1521 | ret = 0; |
1522 | break; | 1522 | break; |
1523 | 1523 | ||
1524 | case EBT_SO_GET_ENTRIES: | 1524 | case EBT_SO_GET_ENTRIES: |
1525 | case EBT_SO_GET_INIT_ENTRIES: | 1525 | case EBT_SO_GET_INIT_ENTRIES: |
1526 | ret = copy_everything_to_user(t, user, len, cmd); | 1526 | ret = copy_everything_to_user(t, user, len, cmd); |
1527 | mutex_unlock(&ebt_mutex); | 1527 | mutex_unlock(&ebt_mutex); |
1528 | break; | 1528 | break; |
1529 | 1529 | ||
1530 | default: | 1530 | default: |
1531 | mutex_unlock(&ebt_mutex); | 1531 | mutex_unlock(&ebt_mutex); |
1532 | ret = -EINVAL; | 1532 | ret = -EINVAL; |
1533 | } | 1533 | } |
1534 | 1534 | ||
1535 | return ret; | 1535 | return ret; |
1536 | } | 1536 | } |
1537 | 1537 | ||
1538 | static struct nf_sockopt_ops ebt_sockopts = | 1538 | static struct nf_sockopt_ops ebt_sockopts = |
1539 | { | 1539 | { |
1540 | .pf = PF_INET, | 1540 | .pf = PF_INET, |
1541 | .set_optmin = EBT_BASE_CTL, | 1541 | .set_optmin = EBT_BASE_CTL, |
1542 | .set_optmax = EBT_SO_SET_MAX + 1, | 1542 | .set_optmax = EBT_SO_SET_MAX + 1, |
1543 | .set = do_ebt_set_ctl, | 1543 | .set = do_ebt_set_ctl, |
1544 | .get_optmin = EBT_BASE_CTL, | 1544 | .get_optmin = EBT_BASE_CTL, |
1545 | .get_optmax = EBT_SO_GET_MAX + 1, | 1545 | .get_optmax = EBT_SO_GET_MAX + 1, |
1546 | .get = do_ebt_get_ctl, | 1546 | .get = do_ebt_get_ctl, |
1547 | .owner = THIS_MODULE, | 1547 | .owner = THIS_MODULE, |
1548 | }; | 1548 | }; |
1549 | 1549 | ||
1550 | static int __init ebtables_init(void) | 1550 | static int __init ebtables_init(void) |
1551 | { | 1551 | { |
1552 | int ret; | 1552 | int ret; |
1553 | 1553 | ||
1554 | mutex_lock(&ebt_mutex); | 1554 | mutex_lock(&ebt_mutex); |
1555 | list_add(&ebt_standard_target.list, &ebt_targets); | 1555 | list_add(&ebt_standard_target.list, &ebt_targets); |
1556 | mutex_unlock(&ebt_mutex); | 1556 | mutex_unlock(&ebt_mutex); |
1557 | if ((ret = nf_register_sockopt(&ebt_sockopts)) < 0) | 1557 | if ((ret = nf_register_sockopt(&ebt_sockopts)) < 0) |
1558 | return ret; | 1558 | return ret; |
1559 | 1559 | ||
1560 | printk(KERN_INFO "Ebtables v2.0 registered\n"); | 1560 | printk(KERN_INFO "Ebtables v2.0 registered\n"); |
1561 | return 0; | 1561 | return 0; |
1562 | } | 1562 | } |
1563 | 1563 | ||
1564 | static void __exit ebtables_fini(void) | 1564 | static void __exit ebtables_fini(void) |
1565 | { | 1565 | { |
1566 | nf_unregister_sockopt(&ebt_sockopts); | 1566 | nf_unregister_sockopt(&ebt_sockopts); |
1567 | printk(KERN_INFO "Ebtables v2.0 unregistered\n"); | 1567 | printk(KERN_INFO "Ebtables v2.0 unregistered\n"); |
1568 | } | 1568 | } |
1569 | 1569 | ||
1570 | EXPORT_SYMBOL(ebt_register_table); | 1570 | EXPORT_SYMBOL(ebt_register_table); |
1571 | EXPORT_SYMBOL(ebt_unregister_table); | 1571 | EXPORT_SYMBOL(ebt_unregister_table); |
1572 | EXPORT_SYMBOL(ebt_register_match); | 1572 | EXPORT_SYMBOL(ebt_register_match); |
1573 | EXPORT_SYMBOL(ebt_unregister_match); | 1573 | EXPORT_SYMBOL(ebt_unregister_match); |
1574 | EXPORT_SYMBOL(ebt_register_watcher); | 1574 | EXPORT_SYMBOL(ebt_register_watcher); |
1575 | EXPORT_SYMBOL(ebt_unregister_watcher); | 1575 | EXPORT_SYMBOL(ebt_unregister_watcher); |
1576 | EXPORT_SYMBOL(ebt_register_target); | 1576 | EXPORT_SYMBOL(ebt_register_target); |
1577 | EXPORT_SYMBOL(ebt_unregister_target); | 1577 | EXPORT_SYMBOL(ebt_unregister_target); |
1578 | EXPORT_SYMBOL(ebt_do_table); | 1578 | EXPORT_SYMBOL(ebt_do_table); |
1579 | module_init(ebtables_init); | 1579 | module_init(ebtables_init); |
1580 | module_exit(ebtables_fini); | 1580 | module_exit(ebtables_fini); |
1581 | MODULE_LICENSE("GPL"); | 1581 | MODULE_LICENSE("GPL"); |
1582 | 1582 |