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