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