diff options
-rw-r--r-- | include/linux/netfilter.h | 28 | ||||
-rw-r--r-- | net/netfilter/core.c | 32 | ||||
-rw-r--r-- | net/netfilter/nf_internals.h | 11 | ||||
-rw-r--r-- | net/netfilter/nf_queue.c | 38 |
4 files changed, 59 insertions, 50 deletions
diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index 2517ece98820..aee7ef1e23ed 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h | |||
@@ -44,6 +44,16 @@ int netfilter_init(void); | |||
44 | struct sk_buff; | 44 | struct sk_buff; |
45 | 45 | ||
46 | struct nf_hook_ops; | 46 | struct nf_hook_ops; |
47 | |||
48 | struct nf_hook_state { | ||
49 | unsigned int hook; | ||
50 | int thresh; | ||
51 | u_int8_t pf; | ||
52 | struct net_device *in; | ||
53 | struct net_device *out; | ||
54 | int (*okfn)(struct sk_buff *); | ||
55 | }; | ||
56 | |||
47 | typedef unsigned int nf_hookfn(const struct nf_hook_ops *ops, | 57 | typedef unsigned int nf_hookfn(const struct nf_hook_ops *ops, |
48 | struct sk_buff *skb, | 58 | struct sk_buff *skb, |
49 | const struct net_device *in, | 59 | const struct net_device *in, |
@@ -118,9 +128,7 @@ static inline bool nf_hooks_active(u_int8_t pf, unsigned int hook) | |||
118 | } | 128 | } |
119 | #endif | 129 | #endif |
120 | 130 | ||
121 | int nf_hook_slow(u_int8_t pf, unsigned int hook, struct sk_buff *skb, | 131 | int nf_hook_slow(struct sk_buff *skb, struct nf_hook_state *state); |
122 | struct net_device *indev, struct net_device *outdev, | ||
123 | int (*okfn)(struct sk_buff *), int thresh); | ||
124 | 132 | ||
125 | /** | 133 | /** |
126 | * nf_hook_thresh - call a netfilter hook | 134 | * nf_hook_thresh - call a netfilter hook |
@@ -135,8 +143,18 @@ static inline int nf_hook_thresh(u_int8_t pf, unsigned int hook, | |||
135 | struct net_device *outdev, | 143 | struct net_device *outdev, |
136 | int (*okfn)(struct sk_buff *), int thresh) | 144 | int (*okfn)(struct sk_buff *), int thresh) |
137 | { | 145 | { |
138 | if (nf_hooks_active(pf, hook)) | 146 | if (nf_hooks_active(pf, hook)) { |
139 | return nf_hook_slow(pf, hook, skb, indev, outdev, okfn, thresh); | 147 | struct nf_hook_state state = { |
148 | .hook = hook, | ||
149 | .thresh = thresh, | ||
150 | .pf = pf, | ||
151 | .in = indev, | ||
152 | .out = outdev, | ||
153 | .okfn = okfn | ||
154 | }; | ||
155 | |||
156 | return nf_hook_slow(skb, &state); | ||
157 | } | ||
140 | return 1; | 158 | return 1; |
141 | } | 159 | } |
142 | 160 | ||
diff --git a/net/netfilter/core.c b/net/netfilter/core.c index fea9ef566427..11d04ebfc5e3 100644 --- a/net/netfilter/core.c +++ b/net/netfilter/core.c | |||
@@ -120,12 +120,8 @@ EXPORT_SYMBOL(nf_unregister_hooks); | |||
120 | 120 | ||
121 | unsigned int nf_iterate(struct list_head *head, | 121 | unsigned int nf_iterate(struct list_head *head, |
122 | struct sk_buff *skb, | 122 | struct sk_buff *skb, |
123 | unsigned int hook, | 123 | struct nf_hook_state *state, |
124 | const struct net_device *indev, | 124 | struct nf_hook_ops **elemp) |
125 | const struct net_device *outdev, | ||
126 | struct nf_hook_ops **elemp, | ||
127 | int (*okfn)(struct sk_buff *), | ||
128 | int hook_thresh) | ||
129 | { | 125 | { |
130 | unsigned int verdict; | 126 | unsigned int verdict; |
131 | 127 | ||
@@ -134,19 +130,20 @@ unsigned int nf_iterate(struct list_head *head, | |||
134 | * function because of risk of continuing from deleted element. | 130 | * function because of risk of continuing from deleted element. |
135 | */ | 131 | */ |
136 | list_for_each_entry_continue_rcu((*elemp), head, list) { | 132 | list_for_each_entry_continue_rcu((*elemp), head, list) { |
137 | if (hook_thresh > (*elemp)->priority) | 133 | if (state->thresh > (*elemp)->priority) |
138 | continue; | 134 | continue; |
139 | 135 | ||
140 | /* Optimization: we don't need to hold module | 136 | /* Optimization: we don't need to hold module |
141 | reference here, since function can't sleep. --RR */ | 137 | reference here, since function can't sleep. --RR */ |
142 | repeat: | 138 | repeat: |
143 | verdict = (*elemp)->hook(*elemp, skb, indev, outdev, okfn); | 139 | verdict = (*elemp)->hook(*elemp, skb, state->in, state->out, |
140 | state->okfn); | ||
144 | if (verdict != NF_ACCEPT) { | 141 | if (verdict != NF_ACCEPT) { |
145 | #ifdef CONFIG_NETFILTER_DEBUG | 142 | #ifdef CONFIG_NETFILTER_DEBUG |
146 | if (unlikely((verdict & NF_VERDICT_MASK) | 143 | if (unlikely((verdict & NF_VERDICT_MASK) |
147 | > NF_MAX_VERDICT)) { | 144 | > NF_MAX_VERDICT)) { |
148 | NFDEBUG("Evil return from %p(%u).\n", | 145 | NFDEBUG("Evil return from %p(%u).\n", |
149 | (*elemp)->hook, hook); | 146 | (*elemp)->hook, state->hook); |
150 | continue; | 147 | continue; |
151 | } | 148 | } |
152 | #endif | 149 | #endif |
@@ -161,11 +158,7 @@ repeat: | |||
161 | 158 | ||
162 | /* Returns 1 if okfn() needs to be executed by the caller, | 159 | /* Returns 1 if okfn() needs to be executed by the caller, |
163 | * -EPERM for NF_DROP, 0 otherwise. */ | 160 | * -EPERM for NF_DROP, 0 otherwise. */ |
164 | int nf_hook_slow(u_int8_t pf, unsigned int hook, struct sk_buff *skb, | 161 | int nf_hook_slow(struct sk_buff *skb, struct nf_hook_state *state) |
165 | struct net_device *indev, | ||
166 | struct net_device *outdev, | ||
167 | int (*okfn)(struct sk_buff *), | ||
168 | int hook_thresh) | ||
169 | { | 162 | { |
170 | struct nf_hook_ops *elem; | 163 | struct nf_hook_ops *elem; |
171 | unsigned int verdict; | 164 | unsigned int verdict; |
@@ -174,10 +167,11 @@ int nf_hook_slow(u_int8_t pf, unsigned int hook, struct sk_buff *skb, | |||
174 | /* We may already have this, but read-locks nest anyway */ | 167 | /* We may already have this, but read-locks nest anyway */ |
175 | rcu_read_lock(); | 168 | rcu_read_lock(); |
176 | 169 | ||
177 | elem = list_entry_rcu(&nf_hooks[pf][hook], struct nf_hook_ops, list); | 170 | elem = list_entry_rcu(&nf_hooks[state->pf][state->hook], |
171 | struct nf_hook_ops, list); | ||
178 | next_hook: | 172 | next_hook: |
179 | verdict = nf_iterate(&nf_hooks[pf][hook], skb, hook, indev, | 173 | verdict = nf_iterate(&nf_hooks[state->pf][state->hook], skb, state, |
180 | outdev, &elem, okfn, hook_thresh); | 174 | &elem); |
181 | if (verdict == NF_ACCEPT || verdict == NF_STOP) { | 175 | if (verdict == NF_ACCEPT || verdict == NF_STOP) { |
182 | ret = 1; | 176 | ret = 1; |
183 | } else if ((verdict & NF_VERDICT_MASK) == NF_DROP) { | 177 | } else if ((verdict & NF_VERDICT_MASK) == NF_DROP) { |
@@ -186,8 +180,8 @@ next_hook: | |||
186 | if (ret == 0) | 180 | if (ret == 0) |
187 | ret = -EPERM; | 181 | ret = -EPERM; |
188 | } else if ((verdict & NF_VERDICT_MASK) == NF_QUEUE) { | 182 | } else if ((verdict & NF_VERDICT_MASK) == NF_QUEUE) { |
189 | int err = nf_queue(skb, elem, pf, hook, indev, outdev, okfn, | 183 | int err = nf_queue(skb, elem, state, |
190 | verdict >> NF_VERDICT_QBITS); | 184 | verdict >> NF_VERDICT_QBITS); |
191 | if (err < 0) { | 185 | if (err < 0) { |
192 | if (err == -ECANCELED) | 186 | if (err == -ECANCELED) |
193 | goto next_hook; | 187 | goto next_hook; |
diff --git a/net/netfilter/nf_internals.h b/net/netfilter/nf_internals.h index 61a3c927e63c..ea7f36784b3d 100644 --- a/net/netfilter/nf_internals.h +++ b/net/netfilter/nf_internals.h | |||
@@ -14,16 +14,11 @@ | |||
14 | 14 | ||
15 | /* core.c */ | 15 | /* core.c */ |
16 | unsigned int nf_iterate(struct list_head *head, struct sk_buff *skb, | 16 | unsigned int nf_iterate(struct list_head *head, struct sk_buff *skb, |
17 | unsigned int hook, const struct net_device *indev, | 17 | struct nf_hook_state *state, struct nf_hook_ops **elemp); |
18 | const struct net_device *outdev, | ||
19 | struct nf_hook_ops **elemp, | ||
20 | int (*okfn)(struct sk_buff *), int hook_thresh); | ||
21 | 18 | ||
22 | /* nf_queue.c */ | 19 | /* nf_queue.c */ |
23 | int nf_queue(struct sk_buff *skb, struct nf_hook_ops *elem, u_int8_t pf, | 20 | int nf_queue(struct sk_buff *skb, struct nf_hook_ops *elem, |
24 | unsigned int hook, struct net_device *indev, | 21 | struct nf_hook_state *state, unsigned int queuenum); |
25 | struct net_device *outdev, int (*okfn)(struct sk_buff *), | ||
26 | unsigned int queuenum); | ||
27 | int __init netfilter_queue_init(void); | 22 | int __init netfilter_queue_init(void); |
28 | 23 | ||
29 | /* nf_log.c */ | 24 | /* nf_log.c */ |
diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c index 4c8b68e5fa16..6f8e9485cc83 100644 --- a/net/netfilter/nf_queue.c +++ b/net/netfilter/nf_queue.c | |||
@@ -100,12 +100,9 @@ EXPORT_SYMBOL_GPL(nf_queue_entry_get_refs); | |||
100 | * through nf_reinject(). | 100 | * through nf_reinject(). |
101 | */ | 101 | */ |
102 | int nf_queue(struct sk_buff *skb, | 102 | int nf_queue(struct sk_buff *skb, |
103 | struct nf_hook_ops *elem, | 103 | struct nf_hook_ops *elem, |
104 | u_int8_t pf, unsigned int hook, | 104 | struct nf_hook_state *state, |
105 | struct net_device *indev, | 105 | unsigned int queuenum) |
106 | struct net_device *outdev, | ||
107 | int (*okfn)(struct sk_buff *), | ||
108 | unsigned int queuenum) | ||
109 | { | 106 | { |
110 | int status = -ENOENT; | 107 | int status = -ENOENT; |
111 | struct nf_queue_entry *entry = NULL; | 108 | struct nf_queue_entry *entry = NULL; |
@@ -121,7 +118,7 @@ int nf_queue(struct sk_buff *skb, | |||
121 | goto err_unlock; | 118 | goto err_unlock; |
122 | } | 119 | } |
123 | 120 | ||
124 | afinfo = nf_get_afinfo(pf); | 121 | afinfo = nf_get_afinfo(state->pf); |
125 | if (!afinfo) | 122 | if (!afinfo) |
126 | goto err_unlock; | 123 | goto err_unlock; |
127 | 124 | ||
@@ -134,11 +131,11 @@ int nf_queue(struct sk_buff *skb, | |||
134 | *entry = (struct nf_queue_entry) { | 131 | *entry = (struct nf_queue_entry) { |
135 | .skb = skb, | 132 | .skb = skb, |
136 | .elem = elem, | 133 | .elem = elem, |
137 | .pf = pf, | 134 | .pf = state->pf, |
138 | .hook = hook, | 135 | .hook = state->hook, |
139 | .indev = indev, | 136 | .indev = state->in, |
140 | .outdev = outdev, | 137 | .outdev = state->out, |
141 | .okfn = okfn, | 138 | .okfn = state->okfn, |
142 | .size = sizeof(*entry) + afinfo->route_key_size, | 139 | .size = sizeof(*entry) + afinfo->route_key_size, |
143 | }; | 140 | }; |
144 | 141 | ||
@@ -171,6 +168,7 @@ void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict) | |||
171 | struct sk_buff *skb = entry->skb; | 168 | struct sk_buff *skb = entry->skb; |
172 | struct nf_hook_ops *elem = entry->elem; | 169 | struct nf_hook_ops *elem = entry->elem; |
173 | const struct nf_afinfo *afinfo; | 170 | const struct nf_afinfo *afinfo; |
171 | struct nf_hook_state state; | ||
174 | int err; | 172 | int err; |
175 | 173 | ||
176 | rcu_read_lock(); | 174 | rcu_read_lock(); |
@@ -189,12 +187,17 @@ void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict) | |||
189 | verdict = NF_DROP; | 187 | verdict = NF_DROP; |
190 | } | 188 | } |
191 | 189 | ||
190 | state.hook = entry->hook; | ||
191 | state.thresh = INT_MIN; | ||
192 | state.pf = entry->pf; | ||
193 | state.in = entry->indev; | ||
194 | state.out = entry->outdev; | ||
195 | state.okfn = entry->okfn; | ||
196 | |||
192 | if (verdict == NF_ACCEPT) { | 197 | if (verdict == NF_ACCEPT) { |
193 | next_hook: | 198 | next_hook: |
194 | verdict = nf_iterate(&nf_hooks[entry->pf][entry->hook], | 199 | verdict = nf_iterate(&nf_hooks[entry->pf][entry->hook], |
195 | skb, entry->hook, | 200 | skb, &state, &elem); |
196 | entry->indev, entry->outdev, &elem, | ||
197 | entry->okfn, INT_MIN); | ||
198 | } | 201 | } |
199 | 202 | ||
200 | switch (verdict & NF_VERDICT_MASK) { | 203 | switch (verdict & NF_VERDICT_MASK) { |
@@ -205,9 +208,8 @@ void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict) | |||
205 | local_bh_enable(); | 208 | local_bh_enable(); |
206 | break; | 209 | break; |
207 | case NF_QUEUE: | 210 | case NF_QUEUE: |
208 | err = nf_queue(skb, elem, entry->pf, entry->hook, | 211 | err = nf_queue(skb, elem, &state, |
209 | entry->indev, entry->outdev, entry->okfn, | 212 | verdict >> NF_VERDICT_QBITS); |
210 | verdict >> NF_VERDICT_QBITS); | ||
211 | if (err < 0) { | 213 | if (err < 0) { |
212 | if (err == -ECANCELED) | 214 | if (err == -ECANCELED) |
213 | goto next_hook; | 215 | goto next_hook; |