Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/net/netlabel/netlabel_addrlist.c
15109 views
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 <[email protected]>
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_exact(addr, mask, head);
260
if (entry == NULL)
261
return NULL;
262
netlbl_af4list_remove_entry(entry);
263
return entry;
264
}
265
266
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
267
/**
268
* netlbl_af6list_remove_entry - Remove an IPv6 address entry
269
* @entry: address entry
270
*
271
* Description:
272
* Remove the specified IP address entry. The caller is responsible for
273
* calling the necessary locking functions.
274
*
275
*/
276
void netlbl_af6list_remove_entry(struct netlbl_af6list *entry)
277
{
278
entry->valid = 0;
279
list_del_rcu(&entry->list);
280
}
281
282
/**
283
* netlbl_af6list_remove - Remove an IPv6 address entry
284
* @addr: IP address
285
* @mask: IP address mask
286
* @head: the list head
287
*
288
* Description:
289
* Remove an IP address entry from the list pointed to by @head. Returns the
290
* entry on success, NULL on failure. The caller is responsible for calling
291
* the necessary locking functions.
292
*
293
*/
294
struct netlbl_af6list *netlbl_af6list_remove(const struct in6_addr *addr,
295
const struct in6_addr *mask,
296
struct list_head *head)
297
{
298
struct netlbl_af6list *entry;
299
300
entry = netlbl_af6list_search_exact(addr, mask, head);
301
if (entry == NULL)
302
return NULL;
303
netlbl_af6list_remove_entry(entry);
304
return entry;
305
}
306
#endif /* IPv6 */
307
308
/*
309
* Audit Helper Functions
310
*/
311
312
#ifdef CONFIG_AUDIT
313
/**
314
* netlbl_af4list_audit_addr - Audit an IPv4 address
315
* @audit_buf: audit buffer
316
* @src: true if source address, false if destination
317
* @dev: network interface
318
* @addr: IP address
319
* @mask: IP address mask
320
*
321
* Description:
322
* Write the IPv4 address and address mask, if necessary, to @audit_buf.
323
*
324
*/
325
void netlbl_af4list_audit_addr(struct audit_buffer *audit_buf,
326
int src, const char *dev,
327
__be32 addr, __be32 mask)
328
{
329
u32 mask_val = ntohl(mask);
330
char *dir = (src ? "src" : "dst");
331
332
if (dev != NULL)
333
audit_log_format(audit_buf, " netif=%s", dev);
334
audit_log_format(audit_buf, " %s=%pI4", dir, &addr);
335
if (mask_val != 0xffffffff) {
336
u32 mask_len = 0;
337
while (mask_val > 0) {
338
mask_val <<= 1;
339
mask_len++;
340
}
341
audit_log_format(audit_buf, " %s_prefixlen=%d", dir, mask_len);
342
}
343
}
344
345
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
346
/**
347
* netlbl_af6list_audit_addr - Audit an IPv6 address
348
* @audit_buf: audit buffer
349
* @src: true if source address, false if destination
350
* @dev: network interface
351
* @addr: IP address
352
* @mask: IP address mask
353
*
354
* Description:
355
* Write the IPv6 address and address mask, if necessary, to @audit_buf.
356
*
357
*/
358
void netlbl_af6list_audit_addr(struct audit_buffer *audit_buf,
359
int src,
360
const char *dev,
361
const struct in6_addr *addr,
362
const struct in6_addr *mask)
363
{
364
char *dir = (src ? "src" : "dst");
365
366
if (dev != NULL)
367
audit_log_format(audit_buf, " netif=%s", dev);
368
audit_log_format(audit_buf, " %s=%pI6", dir, addr);
369
if (ntohl(mask->s6_addr32[3]) != 0xffffffff) {
370
u32 mask_len = 0;
371
u32 mask_val;
372
int iter = -1;
373
while (ntohl(mask->s6_addr32[++iter]) == 0xffffffff)
374
mask_len += 32;
375
mask_val = ntohl(mask->s6_addr32[iter]);
376
while (mask_val > 0) {
377
mask_val <<= 1;
378
mask_len++;
379
}
380
audit_log_format(audit_buf, " %s_prefixlen=%d", dir, mask_len);
381
}
382
}
383
#endif /* IPv6 */
384
#endif /* CONFIG_AUDIT */
385
386