Branch data Line data Source code
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@paul-moore.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, see <http://www.gnu.org/licenses/>.
28 : : *
29 : : */
30 : :
31 : : #include <linux/types.h>
32 : : #include <linux/rcupdate.h>
33 : : #include <linux/list.h>
34 : : #include <linux/spinlock.h>
35 : : #include <linux/in.h>
36 : : #include <linux/in6.h>
37 : : #include <linux/ip.h>
38 : : #include <linux/ipv6.h>
39 : : #include <net/ip.h>
40 : : #include <net/ipv6.h>
41 : : #include <linux/audit.h>
42 : :
43 : : #include "netlabel_addrlist.h"
44 : :
45 : : /*
46 : : * Address List Functions
47 : : */
48 : :
49 : : /**
50 : : * netlbl_af4list_search - Search for a matching IPv4 address entry
51 : : * @addr: IPv4 address
52 : : * @head: the list head
53 : : *
54 : : * Description:
55 : : * Searches the IPv4 address list given by @head. If a matching address entry
56 : : * is found it is returned, otherwise NULL is returned. The caller is
57 : : * responsible for calling the rcu_read_[un]lock() functions.
58 : : *
59 : : */
60 : 0 : struct netlbl_af4list *netlbl_af4list_search(__be32 addr,
61 : : struct list_head *head)
62 : : {
63 : : struct netlbl_af4list *iter;
64 : :
65 [ # # ]: 0 : list_for_each_entry_rcu(iter, head, list)
66 [ # # ][ # # ]: 0 : if (iter->valid && (addr & iter->mask) == iter->addr)
67 : : return iter;
68 : :
69 : : return NULL;
70 : : }
71 : :
72 : : /**
73 : : * netlbl_af4list_search_exact - Search for an exact IPv4 address entry
74 : : * @addr: IPv4 address
75 : : * @mask: IPv4 address mask
76 : : * @head: the list head
77 : : *
78 : : * Description:
79 : : * Searches the IPv4 address list given by @head. If an exact match if found
80 : : * it is returned, otherwise NULL is returned. The caller is responsible for
81 : : * calling the rcu_read_[un]lock() functions.
82 : : *
83 : : */
84 : 0 : struct netlbl_af4list *netlbl_af4list_search_exact(__be32 addr,
85 : : __be32 mask,
86 : : struct list_head *head)
87 : : {
88 : : struct netlbl_af4list *iter;
89 : :
90 [ # # ]: 0 : list_for_each_entry_rcu(iter, head, list)
91 [ # # ][ # # ]: 0 : if (iter->valid && iter->addr == addr && iter->mask == mask)
[ # # ]
92 : : return iter;
93 : :
94 : : return NULL;
95 : : }
96 : :
97 : :
98 : : #if IS_ENABLED(CONFIG_IPV6)
99 : : /**
100 : : * netlbl_af6list_search - Search for a matching IPv6 address entry
101 : : * @addr: IPv6 address
102 : : * @head: the list head
103 : : *
104 : : * Description:
105 : : * Searches the IPv6 address list given by @head. If a matching address entry
106 : : * is found it is returned, otherwise NULL is returned. The caller is
107 : : * responsible for calling the rcu_read_[un]lock() functions.
108 : : *
109 : : */
110 : 0 : struct netlbl_af6list *netlbl_af6list_search(const struct in6_addr *addr,
111 : : struct list_head *head)
112 : : {
113 : : struct netlbl_af6list *iter;
114 : :
115 [ # # ]: 0 : list_for_each_entry_rcu(iter, head, list)
116 [ # # ][ # # ]: 0 : if (iter->valid &&
117 : : ipv6_masked_addr_cmp(&iter->addr, &iter->mask, addr) == 0)
118 : : return iter;
119 : :
120 : : return NULL;
121 : : }
122 : :
123 : : /**
124 : : * netlbl_af6list_search_exact - Search for an exact IPv6 address entry
125 : : * @addr: IPv6 address
126 : : * @mask: IPv6 address mask
127 : : * @head: the list head
128 : : *
129 : : * Description:
130 : : * Searches the IPv6 address list given by @head. If an exact match if found
131 : : * it is returned, otherwise NULL is returned. The caller is responsible for
132 : : * calling the rcu_read_[un]lock() functions.
133 : : *
134 : : */
135 : 0 : struct netlbl_af6list *netlbl_af6list_search_exact(const struct in6_addr *addr,
136 : : const struct in6_addr *mask,
137 : : struct list_head *head)
138 : : {
139 : : struct netlbl_af6list *iter;
140 : :
141 [ # # ]: 0 : list_for_each_entry_rcu(iter, head, list)
142 [ # # ][ # # ]: 0 : if (iter->valid &&
143 [ # # ]: 0 : ipv6_addr_equal(&iter->addr, addr) &&
144 : : ipv6_addr_equal(&iter->mask, mask))
145 : : return iter;
146 : :
147 : : return NULL;
148 : : }
149 : : #endif /* IPv6 */
150 : :
151 : : /**
152 : : * netlbl_af4list_add - Add a new IPv4 address entry to a list
153 : : * @entry: address entry
154 : : * @head: the list head
155 : : *
156 : : * Description:
157 : : * Add a new address entry to the list pointed to by @head. On success zero is
158 : : * returned, otherwise a negative value is returned. The caller is responsible
159 : : * for calling the necessary locking functions.
160 : : *
161 : : */
162 : 0 : int netlbl_af4list_add(struct netlbl_af4list *entry, struct list_head *head)
163 : : {
164 : : struct netlbl_af4list *iter;
165 : :
166 : 0 : iter = netlbl_af4list_search(entry->addr, head);
167 [ # # ][ # # ]: 0 : if (iter != NULL &&
168 [ # # ]: 0 : iter->addr == entry->addr && iter->mask == entry->mask)
169 : : return -EEXIST;
170 : :
171 : : /* in order to speed up address searches through the list (the common
172 : : * case) we need to keep the list in order based on the size of the
173 : : * address mask such that the entry with the widest mask (smallest
174 : : * numerical value) appears first in the list */
175 [ # # ]: 0 : list_for_each_entry_rcu(iter, head, list)
176 [ # # ][ # # ]: 0 : if (iter->valid &&
177 [ # # ][ # # ]: 0 : ntohl(entry->mask) > ntohl(iter->mask)) {
178 : 0 : __list_add_rcu(&entry->list,
179 : : iter->list.prev,
180 : : &iter->list);
181 : 0 : return 0;
182 : : }
183 : 0 : list_add_tail_rcu(&entry->list, head);
184 : 0 : return 0;
185 : : }
186 : :
187 : : #if IS_ENABLED(CONFIG_IPV6)
188 : : /**
189 : : * netlbl_af6list_add - Add a new IPv6 address entry to a list
190 : : * @entry: address entry
191 : : * @head: the list head
192 : : *
193 : : * Description:
194 : : * Add a new address entry to the list pointed to by @head. On success zero is
195 : : * returned, otherwise a negative value is returned. The caller is responsible
196 : : * for calling the necessary locking functions.
197 : : *
198 : : */
199 : 0 : int netlbl_af6list_add(struct netlbl_af6list *entry, struct list_head *head)
200 : : {
201 : : struct netlbl_af6list *iter;
202 : :
203 : 0 : iter = netlbl_af6list_search(&entry->addr, head);
204 [ # # ][ # # ]: 0 : if (iter != NULL &&
205 [ # # ]: 0 : ipv6_addr_equal(&iter->addr, &entry->addr) &&
206 : : ipv6_addr_equal(&iter->mask, &entry->mask))
207 : : return -EEXIST;
208 : :
209 : : /* in order to speed up address searches through the list (the common
210 : : * case) we need to keep the list in order based on the size of the
211 : : * address mask such that the entry with the widest mask (smallest
212 : : * numerical value) appears first in the list */
213 [ # # ]: 0 : list_for_each_entry_rcu(iter, head, list)
214 [ # # ][ # # ]: 0 : if (iter->valid &&
215 : 0 : ipv6_addr_cmp(&entry->mask, &iter->mask) > 0) {
216 : 0 : __list_add_rcu(&entry->list,
217 : : iter->list.prev,
218 : : &iter->list);
219 : 0 : return 0;
220 : : }
221 : 0 : list_add_tail_rcu(&entry->list, head);
222 : 0 : return 0;
223 : : }
224 : : #endif /* IPv6 */
225 : :
226 : : /**
227 : : * netlbl_af4list_remove_entry - Remove an IPv4 address entry
228 : : * @entry: address entry
229 : : *
230 : : * Description:
231 : : * Remove the specified IP address entry. The caller is responsible for
232 : : * calling the necessary locking functions.
233 : : *
234 : : */
235 : 0 : void netlbl_af4list_remove_entry(struct netlbl_af4list *entry)
236 : : {
237 : 0 : entry->valid = 0;
238 : : list_del_rcu(&entry->list);
239 : 0 : }
240 : :
241 : : /**
242 : : * netlbl_af4list_remove - Remove an IPv4 address entry
243 : : * @addr: IP address
244 : : * @mask: IP address mask
245 : : * @head: the list head
246 : : *
247 : : * Description:
248 : : * Remove an IP address entry from the list pointed to by @head. Returns the
249 : : * entry on success, NULL on failure. The caller is responsible for calling
250 : : * the necessary locking functions.
251 : : *
252 : : */
253 : 0 : struct netlbl_af4list *netlbl_af4list_remove(__be32 addr, __be32 mask,
254 : : struct list_head *head)
255 : : {
256 : : struct netlbl_af4list *entry;
257 : :
258 : 0 : entry = netlbl_af4list_search_exact(addr, mask, head);
259 [ # # ]: 0 : if (entry == NULL)
260 : : return NULL;
261 : : netlbl_af4list_remove_entry(entry);
262 : 0 : return entry;
263 : : }
264 : :
265 : : #if IS_ENABLED(CONFIG_IPV6)
266 : : /**
267 : : * netlbl_af6list_remove_entry - Remove an IPv6 address entry
268 : : * @entry: address entry
269 : : *
270 : : * Description:
271 : : * Remove the specified IP address entry. The caller is responsible for
272 : : * calling the necessary locking functions.
273 : : *
274 : : */
275 : 0 : void netlbl_af6list_remove_entry(struct netlbl_af6list *entry)
276 : : {
277 : 0 : entry->valid = 0;
278 : : list_del_rcu(&entry->list);
279 : 0 : }
280 : :
281 : : /**
282 : : * netlbl_af6list_remove - Remove an IPv6 address entry
283 : : * @addr: IP address
284 : : * @mask: IP address mask
285 : : * @head: the list head
286 : : *
287 : : * Description:
288 : : * Remove an IP address entry from the list pointed to by @head. Returns the
289 : : * entry on success, NULL on failure. The caller is responsible for calling
290 : : * the necessary locking functions.
291 : : *
292 : : */
293 : 0 : struct netlbl_af6list *netlbl_af6list_remove(const struct in6_addr *addr,
294 : : const struct in6_addr *mask,
295 : : struct list_head *head)
296 : : {
297 : : struct netlbl_af6list *entry;
298 : :
299 : 0 : entry = netlbl_af6list_search_exact(addr, mask, head);
300 [ # # ]: 0 : if (entry == NULL)
301 : : return NULL;
302 : : netlbl_af6list_remove_entry(entry);
303 : 0 : return entry;
304 : : }
305 : : #endif /* IPv6 */
306 : :
307 : : /*
308 : : * Audit Helper Functions
309 : : */
310 : :
311 : : #ifdef CONFIG_AUDIT
312 : : /**
313 : : * netlbl_af4list_audit_addr - Audit an IPv4 address
314 : : * @audit_buf: audit buffer
315 : : * @src: true if source address, false if destination
316 : : * @dev: network interface
317 : : * @addr: IP address
318 : : * @mask: IP address mask
319 : : *
320 : : * Description:
321 : : * Write the IPv4 address and address mask, if necessary, to @audit_buf.
322 : : *
323 : : */
324 : 0 : void netlbl_af4list_audit_addr(struct audit_buffer *audit_buf,
325 : : int src, const char *dev,
326 : : __be32 addr, __be32 mask)
327 : : {
328 [ # # ]: 0 : u32 mask_val = ntohl(mask);
329 [ # # ]: 0 : char *dir = (src ? "src" : "dst");
330 : :
331 [ # # ]: 0 : if (dev != NULL)
332 : 0 : audit_log_format(audit_buf, " netif=%s", dev);
333 : 0 : audit_log_format(audit_buf, " %s=%pI4", dir, &addr);
334 [ # # ]: 0 : if (mask_val != 0xffffffff) {
335 : : u32 mask_len = 0;
336 [ # # ]: 0 : while (mask_val > 0) {
337 : 0 : mask_val <<= 1;
338 : 0 : mask_len++;
339 : : }
340 : 0 : audit_log_format(audit_buf, " %s_prefixlen=%d", dir, mask_len);
341 : : }
342 : 0 : }
343 : :
344 : : #if IS_ENABLED(CONFIG_IPV6)
345 : : /**
346 : : * netlbl_af6list_audit_addr - Audit an IPv6 address
347 : : * @audit_buf: audit buffer
348 : : * @src: true if source address, false if destination
349 : : * @dev: network interface
350 : : * @addr: IP address
351 : : * @mask: IP address mask
352 : : *
353 : : * Description:
354 : : * Write the IPv6 address and address mask, if necessary, to @audit_buf.
355 : : *
356 : : */
357 : 0 : void netlbl_af6list_audit_addr(struct audit_buffer *audit_buf,
358 : : int src,
359 : : const char *dev,
360 : : const struct in6_addr *addr,
361 : : const struct in6_addr *mask)
362 : : {
363 [ # # ]: 0 : char *dir = (src ? "src" : "dst");
364 : :
365 [ # # ]: 0 : if (dev != NULL)
366 : 0 : audit_log_format(audit_buf, " netif=%s", dev);
367 : 0 : audit_log_format(audit_buf, " %s=%pI6", dir, addr);
368 [ # # ][ # # ]: 0 : if (ntohl(mask->s6_addr32[3]) != 0xffffffff) {
369 : : u32 mask_len = 0;
370 : : u32 mask_val;
371 : : int iter = -1;
372 [ # # ]: 0 : while (ntohl(mask->s6_addr32[++iter]) == 0xffffffff)
373 : 0 : mask_len += 32;
374 [ # # ]: 0 : mask_val = ntohl(mask->s6_addr32[iter]);
375 [ # # ]: 0 : while (mask_val > 0) {
376 : 0 : mask_val <<= 1;
377 : 0 : mask_len++;
378 : : }
379 : 0 : audit_log_format(audit_buf, " %s_prefixlen=%d", dir, mask_len);
380 : : }
381 : 0 : }
382 : : #endif /* IPv6 */
383 : : #endif /* CONFIG_AUDIT */
|