Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/net/netlabel/netlabel_addrlist.c
26285 views
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 <[email protected]>
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(&iter->addr, &iter->mask, 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(&iter->addr, addr) &&
130
ipv6_addr_equal(&iter->mask, 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(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(&entry->list,
165
iter->list.prev,
166
&iter->list);
167
return 0;
168
}
169
list_add_tail_rcu(&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(&entry->addr, head);
190
if (iter != NULL &&
191
ipv6_addr_equal(&iter->addr, &entry->addr) &&
192
ipv6_addr_equal(&iter->mask, &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(&entry->mask, &iter->mask) > 0) {
202
__list_add_rcu(&entry->list,
203
iter->list.prev,
204
&iter->list);
205
return 0;
206
}
207
list_add_tail_rcu(&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->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->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(audit_buf, " netif=%s", dev);
319
audit_log_format(audit_buf, " %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(audit_buf, " %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(audit_buf, " netif=%s", dev);
353
audit_log_format(audit_buf, " %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(audit_buf, " %s_prefixlen=%d", dir, mask_len);
366
}
367
}
368
#endif /* IPv6 */
369
#endif /* CONFIG_AUDIT */
370
371