diff options
author | Patrick McHardy <kaber@trash.net> | 2007-12-05 04:25:46 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-28 17:56:12 -0500 |
commit | 9521409265d3bae939ace4c259f765c29339730f (patch) | |
tree | c622a14e0b245b2b32b2915b45649fa06f2fb7ea /net | |
parent | b43d8d85987bf21578e270c9f57c8503114ff399 (diff) |
[NETFILTER]: ip_queue: deobfuscate entry lookups
A queue entry lookup currently looks like this:
ipq_find_dequeue_entry -> __ipq_find_dequeue_entry ->
__ipq_find_entry -> cmpfn -> id_cmp
Use simple open-coded list walking and kill the cmpfn for
ipq_find_dequeue_entry. Instead add it to ipq_flush (after
similar cleanups) and use ipq_flush for both complete flushes
and flushing entries related to a device.
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/netfilter/ip_queue.c | 101 |
1 files changed, 37 insertions, 64 deletions
diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c index 9e72246ede25..df2957c5bcb4 100644 --- a/net/ipv4/netfilter/ip_queue.c +++ b/net/ipv4/netfilter/ip_queue.c | |||
@@ -77,52 +77,6 @@ __ipq_enqueue_entry(struct ipq_queue_entry *entry) | |||
77 | queue_total++; | 77 | queue_total++; |
78 | } | 78 | } |
79 | 79 | ||
80 | /* | ||
81 | * Find and return a queued entry matched by cmpfn, or return the last | ||
82 | * entry if cmpfn is NULL. | ||
83 | */ | ||
84 | static inline struct ipq_queue_entry * | ||
85 | __ipq_find_entry(ipq_cmpfn cmpfn, unsigned long data) | ||
86 | { | ||
87 | struct ipq_queue_entry *entry; | ||
88 | |||
89 | list_for_each_entry(entry, &queue_list, list) { | ||
90 | if (!cmpfn || cmpfn(entry, data)) | ||
91 | return entry; | ||
92 | } | ||
93 | return NULL; | ||
94 | } | ||
95 | |||
96 | static inline void | ||
97 | __ipq_dequeue_entry(struct ipq_queue_entry *entry) | ||
98 | { | ||
99 | list_del(&entry->list); | ||
100 | queue_total--; | ||
101 | } | ||
102 | |||
103 | static inline struct ipq_queue_entry * | ||
104 | __ipq_find_dequeue_entry(ipq_cmpfn cmpfn, unsigned long data) | ||
105 | { | ||
106 | struct ipq_queue_entry *entry; | ||
107 | |||
108 | entry = __ipq_find_entry(cmpfn, data); | ||
109 | if (entry == NULL) | ||
110 | return NULL; | ||
111 | |||
112 | __ipq_dequeue_entry(entry); | ||
113 | return entry; | ||
114 | } | ||
115 | |||
116 | |||
117 | static inline void | ||
118 | __ipq_flush(int verdict) | ||
119 | { | ||
120 | struct ipq_queue_entry *entry; | ||
121 | |||
122 | while ((entry = __ipq_find_dequeue_entry(NULL, 0))) | ||
123 | ipq_issue_verdict(entry, verdict); | ||
124 | } | ||
125 | |||
126 | static inline int | 80 | static inline int |
127 | __ipq_set_mode(unsigned char mode, unsigned int range) | 81 | __ipq_set_mode(unsigned char mode, unsigned int range) |
128 | { | 82 | { |
@@ -149,31 +103,59 @@ __ipq_set_mode(unsigned char mode, unsigned int range) | |||
149 | return status; | 103 | return status; |
150 | } | 104 | } |
151 | 105 | ||
106 | static void __ipq_flush(ipq_cmpfn cmpfn, unsigned long data); | ||
107 | |||
152 | static inline void | 108 | static inline void |
153 | __ipq_reset(void) | 109 | __ipq_reset(void) |
154 | { | 110 | { |
155 | peer_pid = 0; | 111 | peer_pid = 0; |
156 | net_disable_timestamp(); | 112 | net_disable_timestamp(); |
157 | __ipq_set_mode(IPQ_COPY_NONE, 0); | 113 | __ipq_set_mode(IPQ_COPY_NONE, 0); |
158 | __ipq_flush(NF_DROP); | 114 | __ipq_flush(NULL, 0); |
159 | } | 115 | } |
160 | 116 | ||
161 | static struct ipq_queue_entry * | 117 | static struct ipq_queue_entry * |
162 | ipq_find_dequeue_entry(ipq_cmpfn cmpfn, unsigned long data) | 118 | ipq_find_dequeue_entry(unsigned long id) |
163 | { | 119 | { |
164 | struct ipq_queue_entry *entry; | 120 | struct ipq_queue_entry *entry = NULL, *i; |
165 | 121 | ||
166 | write_lock_bh(&queue_lock); | 122 | write_lock_bh(&queue_lock); |
167 | entry = __ipq_find_dequeue_entry(cmpfn, data); | 123 | |
124 | list_for_each_entry(i, &queue_list, list) { | ||
125 | if ((unsigned long)i == id) { | ||
126 | entry = i; | ||
127 | break; | ||
128 | } | ||
129 | } | ||
130 | |||
131 | if (entry) { | ||
132 | list_del(&entry->list); | ||
133 | queue_total--; | ||
134 | } | ||
135 | |||
168 | write_unlock_bh(&queue_lock); | 136 | write_unlock_bh(&queue_lock); |
169 | return entry; | 137 | return entry; |
170 | } | 138 | } |
171 | 139 | ||
172 | static void | 140 | static void |
173 | ipq_flush(int verdict) | 141 | __ipq_flush(ipq_cmpfn cmpfn, unsigned long data) |
142 | { | ||
143 | struct ipq_queue_entry *entry, *next; | ||
144 | |||
145 | list_for_each_entry_safe(entry, next, &queue_list, list) { | ||
146 | if (!cmpfn || cmpfn(entry, data)) { | ||
147 | list_del(&entry->list); | ||
148 | queue_total--; | ||
149 | ipq_issue_verdict(entry, NF_DROP); | ||
150 | } | ||
151 | } | ||
152 | } | ||
153 | |||
154 | static void | ||
155 | ipq_flush(ipq_cmpfn cmpfn, unsigned long data) | ||
174 | { | 156 | { |
175 | write_lock_bh(&queue_lock); | 157 | write_lock_bh(&queue_lock); |
176 | __ipq_flush(verdict); | 158 | __ipq_flush(cmpfn, data); |
177 | write_unlock_bh(&queue_lock); | 159 | write_unlock_bh(&queue_lock); |
178 | } | 160 | } |
179 | 161 | ||
@@ -367,12 +349,6 @@ ipq_mangle_ipv4(ipq_verdict_msg_t *v, struct ipq_queue_entry *e) | |||
367 | return 0; | 349 | return 0; |
368 | } | 350 | } |
369 | 351 | ||
370 | static inline int | ||
371 | id_cmp(struct ipq_queue_entry *e, unsigned long id) | ||
372 | { | ||
373 | return (id == (unsigned long )e); | ||
374 | } | ||
375 | |||
376 | static int | 352 | static int |
377 | ipq_set_verdict(struct ipq_verdict_msg *vmsg, unsigned int len) | 353 | ipq_set_verdict(struct ipq_verdict_msg *vmsg, unsigned int len) |
378 | { | 354 | { |
@@ -381,7 +357,7 @@ ipq_set_verdict(struct ipq_verdict_msg *vmsg, unsigned int len) | |||
381 | if (vmsg->value > NF_MAX_VERDICT) | 357 | if (vmsg->value > NF_MAX_VERDICT) |
382 | return -EINVAL; | 358 | return -EINVAL; |
383 | 359 | ||
384 | entry = ipq_find_dequeue_entry(id_cmp, vmsg->id); | 360 | entry = ipq_find_dequeue_entry(vmsg->id); |
385 | if (entry == NULL) | 361 | if (entry == NULL) |
386 | return -ENOENT; | 362 | return -ENOENT; |
387 | else { | 363 | else { |
@@ -460,10 +436,7 @@ dev_cmp(struct ipq_queue_entry *entry, unsigned long ifindex) | |||
460 | static void | 436 | static void |
461 | ipq_dev_drop(int ifindex) | 437 | ipq_dev_drop(int ifindex) |
462 | { | 438 | { |
463 | struct ipq_queue_entry *entry; | 439 | ipq_flush(dev_cmp, ifindex); |
464 | |||
465 | while ((entry = ipq_find_dequeue_entry(dev_cmp, ifindex)) != NULL) | ||
466 | ipq_issue_verdict(entry, NF_DROP); | ||
467 | } | 440 | } |
468 | 441 | ||
469 | #define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0) | 442 | #define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0) |
@@ -699,7 +672,7 @@ static void __exit ip_queue_fini(void) | |||
699 | { | 672 | { |
700 | nf_unregister_queue_handlers(&nfqh); | 673 | nf_unregister_queue_handlers(&nfqh); |
701 | synchronize_net(); | 674 | synchronize_net(); |
702 | ipq_flush(NF_DROP); | 675 | ipq_flush(NULL, 0); |
703 | 676 | ||
704 | unregister_sysctl_table(ipq_sysctl_header); | 677 | unregister_sysctl_table(ipq_sysctl_header); |
705 | unregister_netdevice_notifier(&ipq_dev_notifier); | 678 | unregister_netdevice_notifier(&ipq_dev_notifier); |