diff options
Diffstat (limited to 'net/netlabel/netlabel_addrlist.c')
-rw-r--r-- | net/netlabel/netlabel_addrlist.c | 388 |
1 files changed, 388 insertions, 0 deletions
diff --git a/net/netlabel/netlabel_addrlist.c b/net/netlabel/netlabel_addrlist.c new file mode 100644 index 000000000000..b0925a303353 --- /dev/null +++ b/net/netlabel/netlabel_addrlist.c | |||
@@ -0,0 +1,388 @@ | |||
1 | /* | ||
2 | * NetLabel Network Address Lists | ||
3 | * | ||
4 | * This file contains network address list functions used to manage ordered | ||
5 | * lists of network addresses for use by the NetLabel subsystem. The NetLabel | ||
6 | * system manages static and dynamic label mappings for network protocols such | ||
7 | * as CIPSO and RIPSO. | ||
8 | * | ||
9 | * Author: Paul Moore <paul.moore@hp.com> | ||
10 | * | ||
11 | */ | ||
12 | |||
13 | /* | ||
14 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2008 | ||
15 | * | ||
16 | * This program is free software; you can redistribute it and/or modify | ||
17 | * it under the terms of the GNU General Public License as published by | ||
18 | * the Free Software Foundation; either version 2 of the License, or | ||
19 | * (at your option) any later version. | ||
20 | * | ||
21 | * This program is distributed in the hope that it will be useful, | ||
22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
24 | * the GNU General Public License for more details. | ||
25 | * | ||
26 | * You should have received a copy of the GNU General Public License | ||
27 | * along with this program; if not, write to the Free Software | ||
28 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
29 | * | ||
30 | */ | ||
31 | |||
32 | #include <linux/types.h> | ||
33 | #include <linux/rcupdate.h> | ||
34 | #include <linux/list.h> | ||
35 | #include <linux/spinlock.h> | ||
36 | #include <linux/in.h> | ||
37 | #include <linux/in6.h> | ||
38 | #include <linux/ip.h> | ||
39 | #include <linux/ipv6.h> | ||
40 | #include <net/ip.h> | ||
41 | #include <net/ipv6.h> | ||
42 | #include <linux/audit.h> | ||
43 | |||
44 | #include "netlabel_addrlist.h" | ||
45 | |||
46 | /* | ||
47 | * Address List Functions | ||
48 | */ | ||
49 | |||
50 | /** | ||
51 | * netlbl_af4list_search - Search for a matching IPv4 address entry | ||
52 | * @addr: IPv4 address | ||
53 | * @head: the list head | ||
54 | * | ||
55 | * Description: | ||
56 | * Searches the IPv4 address list given by @head. If a matching address entry | ||
57 | * is found it is returned, otherwise NULL is returned. The caller is | ||
58 | * responsible for calling the rcu_read_[un]lock() functions. | ||
59 | * | ||
60 | */ | ||
61 | struct netlbl_af4list *netlbl_af4list_search(__be32 addr, | ||
62 | struct list_head *head) | ||
63 | { | ||
64 | struct netlbl_af4list *iter; | ||
65 | |||
66 | list_for_each_entry_rcu(iter, head, list) | ||
67 | if (iter->valid && (addr & iter->mask) == iter->addr) | ||
68 | return iter; | ||
69 | |||
70 | return NULL; | ||
71 | } | ||
72 | |||
73 | /** | ||
74 | * netlbl_af4list_search_exact - Search for an exact IPv4 address entry | ||
75 | * @addr: IPv4 address | ||
76 | * @mask: IPv4 address mask | ||
77 | * @head: the list head | ||
78 | * | ||
79 | * Description: | ||
80 | * Searches the IPv4 address list given by @head. If an exact match if found | ||
81 | * it is returned, otherwise NULL is returned. The caller is responsible for | ||
82 | * calling the rcu_read_[un]lock() functions. | ||
83 | * | ||
84 | */ | ||
85 | struct netlbl_af4list *netlbl_af4list_search_exact(__be32 addr, | ||
86 | __be32 mask, | ||
87 | struct list_head *head) | ||
88 | { | ||
89 | struct netlbl_af4list *iter; | ||
90 | |||
91 | list_for_each_entry_rcu(iter, head, list) | ||
92 | if (iter->valid && iter->addr == addr && iter->mask == mask) | ||
93 | return iter; | ||
94 | |||
95 | return NULL; | ||
96 | } | ||
97 | |||
98 | |||
99 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
100 | /** | ||
101 | * netlbl_af6list_search - Search for a matching IPv6 address entry | ||
102 | * @addr: IPv6 address | ||
103 | * @head: the list head | ||
104 | * | ||
105 | * Description: | ||
106 | * Searches the IPv6 address list given by @head. If a matching address entry | ||
107 | * is found it is returned, otherwise NULL is returned. The caller is | ||
108 | * responsible for calling the rcu_read_[un]lock() functions. | ||
109 | * | ||
110 | */ | ||
111 | struct netlbl_af6list *netlbl_af6list_search(const struct in6_addr *addr, | ||
112 | struct list_head *head) | ||
113 | { | ||
114 | struct netlbl_af6list *iter; | ||
115 | |||
116 | list_for_each_entry_rcu(iter, head, list) | ||
117 | if (iter->valid && | ||
118 | ipv6_masked_addr_cmp(&iter->addr, &iter->mask, addr) == 0) | ||
119 | return iter; | ||
120 | |||
121 | return NULL; | ||
122 | } | ||
123 | |||
124 | /** | ||
125 | * netlbl_af6list_search_exact - Search for an exact IPv6 address entry | ||
126 | * @addr: IPv6 address | ||
127 | * @mask: IPv6 address mask | ||
128 | * @head: the list head | ||
129 | * | ||
130 | * Description: | ||
131 | * Searches the IPv6 address list given by @head. If an exact match if found | ||
132 | * it is returned, otherwise NULL is returned. The caller is responsible for | ||
133 | * calling the rcu_read_[un]lock() functions. | ||
134 | * | ||
135 | */ | ||
136 | struct netlbl_af6list *netlbl_af6list_search_exact(const struct in6_addr *addr, | ||
137 | const struct in6_addr *mask, | ||
138 | struct list_head *head) | ||
139 | { | ||
140 | struct netlbl_af6list *iter; | ||
141 | |||
142 | list_for_each_entry_rcu(iter, head, list) | ||
143 | if (iter->valid && | ||
144 | ipv6_addr_equal(&iter->addr, addr) && | ||
145 | ipv6_addr_equal(&iter->mask, mask)) | ||
146 | return iter; | ||
147 | |||
148 | return NULL; | ||
149 | } | ||
150 | #endif /* IPv6 */ | ||
151 | |||
152 | /** | ||
153 | * netlbl_af4list_add - Add a new IPv4 address entry to a list | ||
154 | * @entry: address entry | ||
155 | * @head: the list head | ||
156 | * | ||
157 | * Description: | ||
158 | * Add a new address entry to the list pointed to by @head. On success zero is | ||
159 | * returned, otherwise a negative value is returned. The caller is responsible | ||
160 | * for calling the necessary locking functions. | ||
161 | * | ||
162 | */ | ||
163 | int netlbl_af4list_add(struct netlbl_af4list *entry, struct list_head *head) | ||
164 | { | ||
165 | struct netlbl_af4list *iter; | ||
166 | |||
167 | iter = netlbl_af4list_search(entry->addr, head); | ||
168 | if (iter != NULL && | ||
169 | iter->addr == entry->addr && iter->mask == entry->mask) | ||
170 | return -EEXIST; | ||
171 | |||
172 | /* in order to speed up address searches through the list (the common | ||
173 | * case) we need to keep the list in order based on the size of the | ||
174 | * address mask such that the entry with the widest mask (smallest | ||
175 | * numerical value) appears first in the list */ | ||
176 | list_for_each_entry_rcu(iter, head, list) | ||
177 | if (iter->valid && | ||
178 | ntohl(entry->mask) > ntohl(iter->mask)) { | ||
179 | __list_add_rcu(&entry->list, | ||
180 | iter->list.prev, | ||
181 | &iter->list); | ||
182 | return 0; | ||
183 | } | ||
184 | list_add_tail_rcu(&entry->list, head); | ||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
189 | /** | ||
190 | * netlbl_af6list_add - Add a new IPv6 address entry to a list | ||
191 | * @entry: address entry | ||
192 | * @head: the list head | ||
193 | * | ||
194 | * Description: | ||
195 | * Add a new address entry to the list pointed to by @head. On success zero is | ||
196 | * returned, otherwise a negative value is returned. The caller is responsible | ||
197 | * for calling the necessary locking functions. | ||
198 | * | ||
199 | */ | ||
200 | int netlbl_af6list_add(struct netlbl_af6list *entry, struct list_head *head) | ||
201 | { | ||
202 | struct netlbl_af6list *iter; | ||
203 | |||
204 | iter = netlbl_af6list_search(&entry->addr, head); | ||
205 | if (iter != NULL && | ||
206 | ipv6_addr_equal(&iter->addr, &entry->addr) && | ||
207 | ipv6_addr_equal(&iter->mask, &entry->mask)) | ||
208 | return -EEXIST; | ||
209 | |||
210 | /* in order to speed up address searches through the list (the common | ||
211 | * case) we need to keep the list in order based on the size of the | ||
212 | * address mask such that the entry with the widest mask (smallest | ||
213 | * numerical value) appears first in the list */ | ||
214 | list_for_each_entry_rcu(iter, head, list) | ||
215 | if (iter->valid && | ||
216 | ipv6_addr_cmp(&entry->mask, &iter->mask) > 0) { | ||
217 | __list_add_rcu(&entry->list, | ||
218 | iter->list.prev, | ||
219 | &iter->list); | ||
220 | return 0; | ||
221 | } | ||
222 | list_add_tail_rcu(&entry->list, head); | ||
223 | return 0; | ||
224 | } | ||
225 | #endif /* IPv6 */ | ||
226 | |||
227 | /** | ||
228 | * netlbl_af4list_remove_entry - Remove an IPv4 address entry | ||
229 | * @entry: address entry | ||
230 | * | ||
231 | * Description: | ||
232 | * Remove the specified IP address entry. The caller is responsible for | ||
233 | * calling the necessary locking functions. | ||
234 | * | ||
235 | */ | ||
236 | void netlbl_af4list_remove_entry(struct netlbl_af4list *entry) | ||
237 | { | ||
238 | entry->valid = 0; | ||
239 | list_del_rcu(&entry->list); | ||
240 | } | ||
241 | |||
242 | /** | ||
243 | * netlbl_af4list_remove - Remove an IPv4 address entry | ||
244 | * @addr: IP address | ||
245 | * @mask: IP address mask | ||
246 | * @head: the list head | ||
247 | * | ||
248 | * Description: | ||
249 | * Remove an IP address entry from the list pointed to by @head. Returns the | ||
250 | * entry on success, NULL on failure. The caller is responsible for calling | ||
251 | * the necessary locking functions. | ||
252 | * | ||
253 | */ | ||
254 | struct netlbl_af4list *netlbl_af4list_remove(__be32 addr, __be32 mask, | ||
255 | struct list_head *head) | ||
256 | { | ||
257 | struct netlbl_af4list *entry; | ||
258 | |||
259 | entry = netlbl_af4list_search(addr, head); | ||
260 | if (entry != NULL && entry->addr == addr && entry->mask == mask) { | ||
261 | netlbl_af4list_remove_entry(entry); | ||
262 | return entry; | ||
263 | } | ||
264 | |||
265 | return NULL; | ||
266 | } | ||
267 | |||
268 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
269 | /** | ||
270 | * netlbl_af6list_remove_entry - Remove an IPv6 address entry | ||
271 | * @entry: address entry | ||
272 | * | ||
273 | * Description: | ||
274 | * Remove the specified IP address entry. The caller is responsible for | ||
275 | * calling the necessary locking functions. | ||
276 | * | ||
277 | */ | ||
278 | void netlbl_af6list_remove_entry(struct netlbl_af6list *entry) | ||
279 | { | ||
280 | entry->valid = 0; | ||
281 | list_del_rcu(&entry->list); | ||
282 | } | ||
283 | |||
284 | /** | ||
285 | * netlbl_af6list_remove - Remove an IPv6 address entry | ||
286 | * @addr: IP address | ||
287 | * @mask: IP address mask | ||
288 | * @head: the list head | ||
289 | * | ||
290 | * Description: | ||
291 | * Remove an IP address entry from the list pointed to by @head. Returns the | ||
292 | * entry on success, NULL on failure. The caller is responsible for calling | ||
293 | * the necessary locking functions. | ||
294 | * | ||
295 | */ | ||
296 | struct netlbl_af6list *netlbl_af6list_remove(const struct in6_addr *addr, | ||
297 | const struct in6_addr *mask, | ||
298 | struct list_head *head) | ||
299 | { | ||
300 | struct netlbl_af6list *entry; | ||
301 | |||
302 | entry = netlbl_af6list_search(addr, head); | ||
303 | if (entry != NULL && | ||
304 | ipv6_addr_equal(&entry->addr, addr) && | ||
305 | ipv6_addr_equal(&entry->mask, mask)) { | ||
306 | netlbl_af6list_remove_entry(entry); | ||
307 | return entry; | ||
308 | } | ||
309 | |||
310 | return NULL; | ||
311 | } | ||
312 | #endif /* IPv6 */ | ||
313 | |||
314 | /* | ||
315 | * Audit Helper Functions | ||
316 | */ | ||
317 | |||
318 | /** | ||
319 | * netlbl_af4list_audit_addr - Audit an IPv4 address | ||
320 | * @audit_buf: audit buffer | ||
321 | * @src: true if source address, false if destination | ||
322 | * @dev: network interface | ||
323 | * @addr: IP address | ||
324 | * @mask: IP address mask | ||
325 | * | ||
326 | * Description: | ||
327 | * Write the IPv4 address and address mask, if necessary, to @audit_buf. | ||
328 | * | ||
329 | */ | ||
330 | void netlbl_af4list_audit_addr(struct audit_buffer *audit_buf, | ||
331 | int src, const char *dev, | ||
332 | __be32 addr, __be32 mask) | ||
333 | { | ||
334 | u32 mask_val = ntohl(mask); | ||
335 | char *dir = (src ? "src" : "dst"); | ||
336 | |||
337 | if (dev != NULL) | ||
338 | audit_log_format(audit_buf, " netif=%s", dev); | ||
339 | audit_log_format(audit_buf, " %s=" NIPQUAD_FMT, dir, NIPQUAD(addr)); | ||
340 | if (mask_val != 0xffffffff) { | ||
341 | u32 mask_len = 0; | ||
342 | while (mask_val > 0) { | ||
343 | mask_val <<= 1; | ||
344 | mask_len++; | ||
345 | } | ||
346 | audit_log_format(audit_buf, " %s_prefixlen=%d", dir, mask_len); | ||
347 | } | ||
348 | } | ||
349 | |||
350 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
351 | /** | ||
352 | * netlbl_af6list_audit_addr - Audit an IPv6 address | ||
353 | * @audit_buf: audit buffer | ||
354 | * @src: true if source address, false if destination | ||
355 | * @dev: network interface | ||
356 | * @addr: IP address | ||
357 | * @mask: IP address mask | ||
358 | * | ||
359 | * Description: | ||
360 | * Write the IPv6 address and address mask, if necessary, to @audit_buf. | ||
361 | * | ||
362 | */ | ||
363 | void netlbl_af6list_audit_addr(struct audit_buffer *audit_buf, | ||
364 | int src, | ||
365 | const char *dev, | ||
366 | const struct in6_addr *addr, | ||
367 | const struct in6_addr *mask) | ||
368 | { | ||
369 | char *dir = (src ? "src" : "dst"); | ||
370 | |||
371 | if (dev != NULL) | ||
372 | audit_log_format(audit_buf, " netif=%s", dev); | ||
373 | audit_log_format(audit_buf, " %s=" NIP6_FMT, dir, NIP6(*addr)); | ||
374 | if (ntohl(mask->s6_addr32[3]) != 0xffffffff) { | ||
375 | u32 mask_len = 0; | ||
376 | u32 mask_val; | ||
377 | int iter = -1; | ||
378 | while (ntohl(mask->s6_addr32[++iter]) == 0xffffffff) | ||
379 | mask_len += 32; | ||
380 | mask_val = ntohl(mask->s6_addr32[iter]); | ||
381 | while (mask_val > 0) { | ||
382 | mask_val <<= 1; | ||
383 | mask_len++; | ||
384 | } | ||
385 | audit_log_format(audit_buf, " %s_prefixlen=%d", dir, mask_len); | ||
386 | } | ||
387 | } | ||
388 | #endif /* IPv6 */ | ||