xref: /openbmc/linux/net/netlabel/netlabel_addrlist.c (revision 58e16d792a6a8c6b750f637a4649967fcac853dc)
1*1ccea77eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
261e10682SPaul Moore /*
361e10682SPaul Moore  * NetLabel Network Address Lists
461e10682SPaul Moore  *
561e10682SPaul Moore  * This file contains network address list functions used to manage ordered
661e10682SPaul Moore  * lists of network addresses for use by the NetLabel subsystem.  The NetLabel
761e10682SPaul Moore  * system manages static and dynamic label mappings for network protocols such
861e10682SPaul Moore  * as CIPSO and RIPSO.
961e10682SPaul Moore  *
1082c21bfaSPaul Moore  * Author: Paul Moore <paul@paul-moore.com>
1161e10682SPaul Moore  */
1261e10682SPaul Moore 
1361e10682SPaul Moore /*
1461e10682SPaul Moore  * (c) Copyright Hewlett-Packard Development Company, L.P., 2008
1561e10682SPaul Moore  */
1661e10682SPaul Moore 
1761e10682SPaul Moore #include <linux/types.h>
1861e10682SPaul Moore #include <linux/rcupdate.h>
1961e10682SPaul Moore #include <linux/list.h>
2061e10682SPaul Moore #include <linux/spinlock.h>
2161e10682SPaul Moore #include <linux/in.h>
2261e10682SPaul Moore #include <linux/in6.h>
2361e10682SPaul Moore #include <linux/ip.h>
2461e10682SPaul Moore #include <linux/ipv6.h>
2561e10682SPaul Moore #include <net/ip.h>
2661e10682SPaul Moore #include <net/ipv6.h>
2763c41688SPaul Moore #include <linux/audit.h>
2861e10682SPaul Moore 
2961e10682SPaul Moore #include "netlabel_addrlist.h"
3061e10682SPaul Moore 
3161e10682SPaul Moore /*
3261e10682SPaul Moore  * Address List Functions
3361e10682SPaul Moore  */
3461e10682SPaul Moore 
3561e10682SPaul Moore /**
3661e10682SPaul Moore  * netlbl_af4list_search - Search for a matching IPv4 address entry
3761e10682SPaul Moore  * @addr: IPv4 address
3861e10682SPaul Moore  * @head: the list head
3961e10682SPaul Moore  *
4061e10682SPaul Moore  * Description:
4161e10682SPaul Moore  * Searches the IPv4 address list given by @head.  If a matching address entry
4261e10682SPaul Moore  * is found it is returned, otherwise NULL is returned.  The caller is
4361e10682SPaul Moore  * responsible for calling the rcu_read_[un]lock() functions.
4461e10682SPaul Moore  *
4561e10682SPaul Moore  */
netlbl_af4list_search(__be32 addr,struct list_head * head)4661e10682SPaul Moore struct netlbl_af4list *netlbl_af4list_search(__be32 addr,
4761e10682SPaul Moore 					     struct list_head *head)
4861e10682SPaul Moore {
4961e10682SPaul Moore 	struct netlbl_af4list *iter;
5061e10682SPaul Moore 
5161e10682SPaul Moore 	list_for_each_entry_rcu(iter, head, list)
5261e10682SPaul Moore 		if (iter->valid && (addr & iter->mask) == iter->addr)
5361e10682SPaul Moore 			return iter;
5461e10682SPaul Moore 
5561e10682SPaul Moore 	return NULL;
5661e10682SPaul Moore }
5761e10682SPaul Moore 
5863c41688SPaul Moore /**
5963c41688SPaul Moore  * netlbl_af4list_search_exact - Search for an exact IPv4 address entry
6063c41688SPaul Moore  * @addr: IPv4 address
6163c41688SPaul Moore  * @mask: IPv4 address mask
6263c41688SPaul Moore  * @head: the list head
6363c41688SPaul Moore  *
6463c41688SPaul Moore  * Description:
6563c41688SPaul Moore  * Searches the IPv4 address list given by @head.  If an exact match if found
6663c41688SPaul Moore  * it is returned, otherwise NULL is returned.  The caller is responsible for
6763c41688SPaul Moore  * calling the rcu_read_[un]lock() functions.
6863c41688SPaul Moore  *
6963c41688SPaul Moore  */
netlbl_af4list_search_exact(__be32 addr,__be32 mask,struct list_head * head)7063c41688SPaul Moore struct netlbl_af4list *netlbl_af4list_search_exact(__be32 addr,
7163c41688SPaul Moore 						   __be32 mask,
7263c41688SPaul Moore 						   struct list_head *head)
7363c41688SPaul Moore {
7463c41688SPaul Moore 	struct netlbl_af4list *iter;
7563c41688SPaul Moore 
7663c41688SPaul Moore 	list_for_each_entry_rcu(iter, head, list)
7763c41688SPaul Moore 		if (iter->valid && iter->addr == addr && iter->mask == mask)
7863c41688SPaul Moore 			return iter;
7963c41688SPaul Moore 
8063c41688SPaul Moore 	return NULL;
8163c41688SPaul Moore }
8263c41688SPaul Moore 
8363c41688SPaul Moore 
84dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6)
8561e10682SPaul Moore /**
8661e10682SPaul Moore  * netlbl_af6list_search - Search for a matching IPv6 address entry
8761e10682SPaul Moore  * @addr: IPv6 address
8861e10682SPaul Moore  * @head: the list head
8961e10682SPaul Moore  *
9061e10682SPaul Moore  * Description:
9161e10682SPaul Moore  * Searches the IPv6 address list given by @head.  If a matching address entry
9261e10682SPaul Moore  * is found it is returned, otherwise NULL is returned.  The caller is
9361e10682SPaul Moore  * responsible for calling the rcu_read_[un]lock() functions.
9461e10682SPaul Moore  *
9561e10682SPaul Moore  */
netlbl_af6list_search(const struct in6_addr * addr,struct list_head * head)9661e10682SPaul Moore struct netlbl_af6list *netlbl_af6list_search(const struct in6_addr *addr,
9761e10682SPaul Moore 					     struct list_head *head)
9861e10682SPaul Moore {
9961e10682SPaul Moore 	struct netlbl_af6list *iter;
10061e10682SPaul Moore 
10161e10682SPaul Moore 	list_for_each_entry_rcu(iter, head, list)
10261e10682SPaul Moore 		if (iter->valid &&
10361e10682SPaul Moore 		    ipv6_masked_addr_cmp(&iter->addr, &iter->mask, addr) == 0)
10461e10682SPaul Moore 			return iter;
10561e10682SPaul Moore 
10661e10682SPaul Moore 	return NULL;
10761e10682SPaul Moore }
10863c41688SPaul Moore 
10963c41688SPaul Moore /**
11063c41688SPaul Moore  * netlbl_af6list_search_exact - Search for an exact IPv6 address entry
11163c41688SPaul Moore  * @addr: IPv6 address
11263c41688SPaul Moore  * @mask: IPv6 address mask
11363c41688SPaul Moore  * @head: the list head
11463c41688SPaul Moore  *
11563c41688SPaul Moore  * Description:
11663c41688SPaul Moore  * Searches the IPv6 address list given by @head.  If an exact match if found
11763c41688SPaul Moore  * it is returned, otherwise NULL is returned.  The caller is responsible for
11863c41688SPaul Moore  * calling the rcu_read_[un]lock() functions.
11963c41688SPaul Moore  *
12063c41688SPaul Moore  */
netlbl_af6list_search_exact(const struct in6_addr * addr,const struct in6_addr * mask,struct list_head * head)12163c41688SPaul Moore struct netlbl_af6list *netlbl_af6list_search_exact(const struct in6_addr *addr,
12263c41688SPaul Moore 						   const struct in6_addr *mask,
12363c41688SPaul Moore 						   struct list_head *head)
12463c41688SPaul Moore {
12563c41688SPaul Moore 	struct netlbl_af6list *iter;
12663c41688SPaul Moore 
12763c41688SPaul Moore 	list_for_each_entry_rcu(iter, head, list)
12863c41688SPaul Moore 		if (iter->valid &&
12963c41688SPaul Moore 		    ipv6_addr_equal(&iter->addr, addr) &&
13063c41688SPaul Moore 		    ipv6_addr_equal(&iter->mask, mask))
13163c41688SPaul Moore 			return iter;
13263c41688SPaul Moore 
13363c41688SPaul Moore 	return NULL;
13463c41688SPaul Moore }
13561e10682SPaul Moore #endif /* IPv6 */
13661e10682SPaul Moore 
13761e10682SPaul Moore /**
13861e10682SPaul Moore  * netlbl_af4list_add - Add a new IPv4 address entry to a list
13961e10682SPaul Moore  * @entry: address entry
14061e10682SPaul Moore  * @head: the list head
14161e10682SPaul Moore  *
14261e10682SPaul Moore  * Description:
14361e10682SPaul Moore  * Add a new address entry to the list pointed to by @head.  On success zero is
14461e10682SPaul Moore  * returned, otherwise a negative value is returned.  The caller is responsible
14561e10682SPaul Moore  * for calling the necessary locking functions.
14661e10682SPaul Moore  *
14761e10682SPaul Moore  */
netlbl_af4list_add(struct netlbl_af4list * entry,struct list_head * head)14861e10682SPaul Moore int netlbl_af4list_add(struct netlbl_af4list *entry, struct list_head *head)
14961e10682SPaul Moore {
15061e10682SPaul Moore 	struct netlbl_af4list *iter;
15161e10682SPaul Moore 
15261e10682SPaul Moore 	iter = netlbl_af4list_search(entry->addr, head);
15361e10682SPaul Moore 	if (iter != NULL &&
15461e10682SPaul Moore 	    iter->addr == entry->addr && iter->mask == entry->mask)
15561e10682SPaul Moore 		return -EEXIST;
15661e10682SPaul Moore 
15761e10682SPaul Moore 	/* in order to speed up address searches through the list (the common
15861e10682SPaul Moore 	 * case) we need to keep the list in order based on the size of the
15961e10682SPaul Moore 	 * address mask such that the entry with the widest mask (smallest
16061e10682SPaul Moore 	 * numerical value) appears first in the list */
16161e10682SPaul Moore 	list_for_each_entry_rcu(iter, head, list)
16261e10682SPaul Moore 		if (iter->valid &&
16361e10682SPaul Moore 		    ntohl(entry->mask) > ntohl(iter->mask)) {
16461e10682SPaul Moore 			__list_add_rcu(&entry->list,
16561e10682SPaul Moore 				       iter->list.prev,
16661e10682SPaul Moore 				       &iter->list);
16761e10682SPaul Moore 			return 0;
16861e10682SPaul Moore 		}
16961e10682SPaul Moore 	list_add_tail_rcu(&entry->list, head);
17061e10682SPaul Moore 	return 0;
17161e10682SPaul Moore }
17261e10682SPaul Moore 
173dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6)
17461e10682SPaul Moore /**
17561e10682SPaul Moore  * netlbl_af6list_add - Add a new IPv6 address entry to a list
17661e10682SPaul Moore  * @entry: address entry
17761e10682SPaul Moore  * @head: the list head
17861e10682SPaul Moore  *
17961e10682SPaul Moore  * Description:
18061e10682SPaul Moore  * Add a new address entry to the list pointed to by @head.  On success zero is
18161e10682SPaul Moore  * returned, otherwise a negative value is returned.  The caller is responsible
18261e10682SPaul Moore  * for calling the necessary locking functions.
18361e10682SPaul Moore  *
18461e10682SPaul Moore  */
netlbl_af6list_add(struct netlbl_af6list * entry,struct list_head * head)18561e10682SPaul Moore int netlbl_af6list_add(struct netlbl_af6list *entry, struct list_head *head)
18661e10682SPaul Moore {
18761e10682SPaul Moore 	struct netlbl_af6list *iter;
18861e10682SPaul Moore 
18961e10682SPaul Moore 	iter = netlbl_af6list_search(&entry->addr, head);
19061e10682SPaul Moore 	if (iter != NULL &&
19161e10682SPaul Moore 	    ipv6_addr_equal(&iter->addr, &entry->addr) &&
19261e10682SPaul Moore 	    ipv6_addr_equal(&iter->mask, &entry->mask))
19361e10682SPaul Moore 		return -EEXIST;
19461e10682SPaul Moore 
19561e10682SPaul Moore 	/* in order to speed up address searches through the list (the common
19661e10682SPaul Moore 	 * case) we need to keep the list in order based on the size of the
19761e10682SPaul Moore 	 * address mask such that the entry with the widest mask (smallest
19861e10682SPaul Moore 	 * numerical value) appears first in the list */
19961e10682SPaul Moore 	list_for_each_entry_rcu(iter, head, list)
20061e10682SPaul Moore 		if (iter->valid &&
20161e10682SPaul Moore 		    ipv6_addr_cmp(&entry->mask, &iter->mask) > 0) {
20261e10682SPaul Moore 			__list_add_rcu(&entry->list,
20361e10682SPaul Moore 				       iter->list.prev,
20461e10682SPaul Moore 				       &iter->list);
20561e10682SPaul Moore 			return 0;
20661e10682SPaul Moore 		}
20761e10682SPaul Moore 	list_add_tail_rcu(&entry->list, head);
20861e10682SPaul Moore 	return 0;
20961e10682SPaul Moore }
21061e10682SPaul Moore #endif /* IPv6 */
21161e10682SPaul Moore 
21261e10682SPaul Moore /**
21361e10682SPaul Moore  * netlbl_af4list_remove_entry - Remove an IPv4 address entry
21461e10682SPaul Moore  * @entry: address entry
21561e10682SPaul Moore  *
21661e10682SPaul Moore  * Description:
21761e10682SPaul Moore  * Remove the specified IP address entry.  The caller is responsible for
21861e10682SPaul Moore  * calling the necessary locking functions.
21961e10682SPaul Moore  *
22061e10682SPaul Moore  */
netlbl_af4list_remove_entry(struct netlbl_af4list * entry)22161e10682SPaul Moore void netlbl_af4list_remove_entry(struct netlbl_af4list *entry)
22261e10682SPaul Moore {
22361e10682SPaul Moore 	entry->valid = 0;
22461e10682SPaul Moore 	list_del_rcu(&entry->list);
22561e10682SPaul Moore }
22661e10682SPaul Moore 
22761e10682SPaul Moore /**
22861e10682SPaul Moore  * netlbl_af4list_remove - Remove an IPv4 address entry
22961e10682SPaul Moore  * @addr: IP address
23061e10682SPaul Moore  * @mask: IP address mask
23161e10682SPaul Moore  * @head: the list head
23261e10682SPaul Moore  *
23361e10682SPaul Moore  * Description:
23461e10682SPaul Moore  * Remove an IP address entry from the list pointed to by @head.  Returns the
23561e10682SPaul Moore  * entry on success, NULL on failure.  The caller is responsible for calling
23661e10682SPaul Moore  * the necessary locking functions.
23761e10682SPaul Moore  *
23861e10682SPaul Moore  */
netlbl_af4list_remove(__be32 addr,__be32 mask,struct list_head * head)23961e10682SPaul Moore struct netlbl_af4list *netlbl_af4list_remove(__be32 addr, __be32 mask,
24061e10682SPaul Moore 					     struct list_head *head)
24161e10682SPaul Moore {
24261e10682SPaul Moore 	struct netlbl_af4list *entry;
24361e10682SPaul Moore 
24450b2ff1bSPaul Moore 	entry = netlbl_af4list_search_exact(addr, mask, head);
24550b2ff1bSPaul Moore 	if (entry == NULL)
24650b2ff1bSPaul Moore 		return NULL;
24761e10682SPaul Moore 	netlbl_af4list_remove_entry(entry);
24861e10682SPaul Moore 	return entry;
24961e10682SPaul Moore }
25061e10682SPaul Moore 
251dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6)
25261e10682SPaul Moore /**
25361e10682SPaul Moore  * netlbl_af6list_remove_entry - Remove an IPv6 address entry
25461e10682SPaul Moore  * @entry: address entry
25561e10682SPaul Moore  *
25661e10682SPaul Moore  * Description:
25761e10682SPaul Moore  * Remove the specified IP address entry.  The caller is responsible for
25861e10682SPaul Moore  * calling the necessary locking functions.
25961e10682SPaul Moore  *
26061e10682SPaul Moore  */
netlbl_af6list_remove_entry(struct netlbl_af6list * entry)26161e10682SPaul Moore void netlbl_af6list_remove_entry(struct netlbl_af6list *entry)
26261e10682SPaul Moore {
26361e10682SPaul Moore 	entry->valid = 0;
26461e10682SPaul Moore 	list_del_rcu(&entry->list);
26561e10682SPaul Moore }
26661e10682SPaul Moore 
26761e10682SPaul Moore /**
26861e10682SPaul Moore  * netlbl_af6list_remove - Remove an IPv6 address entry
26961e10682SPaul Moore  * @addr: IP address
27061e10682SPaul Moore  * @mask: IP address mask
27161e10682SPaul Moore  * @head: the list head
27261e10682SPaul Moore  *
27361e10682SPaul Moore  * Description:
27461e10682SPaul Moore  * Remove an IP address entry from the list pointed to by @head.  Returns the
27561e10682SPaul Moore  * entry on success, NULL on failure.  The caller is responsible for calling
27661e10682SPaul Moore  * the necessary locking functions.
27761e10682SPaul Moore  *
27861e10682SPaul Moore  */
netlbl_af6list_remove(const struct in6_addr * addr,const struct in6_addr * mask,struct list_head * head)27961e10682SPaul Moore struct netlbl_af6list *netlbl_af6list_remove(const struct in6_addr *addr,
28061e10682SPaul Moore 					     const struct in6_addr *mask,
28161e10682SPaul Moore 					     struct list_head *head)
28261e10682SPaul Moore {
28361e10682SPaul Moore 	struct netlbl_af6list *entry;
28461e10682SPaul Moore 
28550b2ff1bSPaul Moore 	entry = netlbl_af6list_search_exact(addr, mask, head);
28650b2ff1bSPaul Moore 	if (entry == NULL)
28750b2ff1bSPaul Moore 		return NULL;
28861e10682SPaul Moore 	netlbl_af6list_remove_entry(entry);
28961e10682SPaul Moore 	return entry;
29061e10682SPaul Moore }
29161e10682SPaul Moore #endif /* IPv6 */
29263c41688SPaul Moore 
29363c41688SPaul Moore /*
29463c41688SPaul Moore  * Audit Helper Functions
29563c41688SPaul Moore  */
29663c41688SPaul Moore 
29747b676c0SManish Katiyar #ifdef CONFIG_AUDIT
29863c41688SPaul Moore /**
29963c41688SPaul Moore  * netlbl_af4list_audit_addr - Audit an IPv4 address
30063c41688SPaul Moore  * @audit_buf: audit buffer
30163c41688SPaul Moore  * @src: true if source address, false if destination
30263c41688SPaul Moore  * @dev: network interface
30363c41688SPaul Moore  * @addr: IP address
30463c41688SPaul Moore  * @mask: IP address mask
30563c41688SPaul Moore  *
30663c41688SPaul Moore  * Description:
30763c41688SPaul Moore  * Write the IPv4 address and address mask, if necessary, to @audit_buf.
30863c41688SPaul Moore  *
30963c41688SPaul Moore  */
netlbl_af4list_audit_addr(struct audit_buffer * audit_buf,int src,const char * dev,__be32 addr,__be32 mask)31063c41688SPaul Moore void netlbl_af4list_audit_addr(struct audit_buffer *audit_buf,
31163c41688SPaul Moore 					int src, const char *dev,
31263c41688SPaul Moore 					__be32 addr, __be32 mask)
31363c41688SPaul Moore {
31463c41688SPaul Moore 	u32 mask_val = ntohl(mask);
31563c41688SPaul Moore 	char *dir = (src ? "src" : "dst");
31663c41688SPaul Moore 
31763c41688SPaul Moore 	if (dev != NULL)
31863c41688SPaul Moore 		audit_log_format(audit_buf, " netif=%s", dev);
31921454aaaSHarvey Harrison 	audit_log_format(audit_buf, " %s=%pI4", dir, &addr);
32063c41688SPaul Moore 	if (mask_val != 0xffffffff) {
32163c41688SPaul Moore 		u32 mask_len = 0;
32263c41688SPaul Moore 		while (mask_val > 0) {
32363c41688SPaul Moore 			mask_val <<= 1;
32463c41688SPaul Moore 			mask_len++;
32563c41688SPaul Moore 		}
32663c41688SPaul Moore 		audit_log_format(audit_buf, " %s_prefixlen=%d", dir, mask_len);
32763c41688SPaul Moore 	}
32863c41688SPaul Moore }
32963c41688SPaul Moore 
330dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6)
33163c41688SPaul Moore /**
33263c41688SPaul Moore  * netlbl_af6list_audit_addr - Audit an IPv6 address
33363c41688SPaul Moore  * @audit_buf: audit buffer
33463c41688SPaul Moore  * @src: true if source address, false if destination
33563c41688SPaul Moore  * @dev: network interface
33663c41688SPaul Moore  * @addr: IP address
33763c41688SPaul Moore  * @mask: IP address mask
33863c41688SPaul Moore  *
33963c41688SPaul Moore  * Description:
34063c41688SPaul Moore  * Write the IPv6 address and address mask, if necessary, to @audit_buf.
34163c41688SPaul Moore  *
34263c41688SPaul Moore  */
netlbl_af6list_audit_addr(struct audit_buffer * audit_buf,int src,const char * dev,const struct in6_addr * addr,const struct in6_addr * mask)34363c41688SPaul Moore void netlbl_af6list_audit_addr(struct audit_buffer *audit_buf,
34463c41688SPaul Moore 				 int src,
34563c41688SPaul Moore 				 const char *dev,
34663c41688SPaul Moore 				 const struct in6_addr *addr,
34763c41688SPaul Moore 				 const struct in6_addr *mask)
34863c41688SPaul Moore {
34963c41688SPaul Moore 	char *dir = (src ? "src" : "dst");
35063c41688SPaul Moore 
35163c41688SPaul Moore 	if (dev != NULL)
35263c41688SPaul Moore 		audit_log_format(audit_buf, " netif=%s", dev);
3535b095d98SHarvey Harrison 	audit_log_format(audit_buf, " %s=%pI6", dir, addr);
35463c41688SPaul Moore 	if (ntohl(mask->s6_addr32[3]) != 0xffffffff) {
35563c41688SPaul Moore 		u32 mask_len = 0;
35663c41688SPaul Moore 		u32 mask_val;
35763c41688SPaul Moore 		int iter = -1;
35863c41688SPaul Moore 		while (ntohl(mask->s6_addr32[++iter]) == 0xffffffff)
35963c41688SPaul Moore 			mask_len += 32;
36063c41688SPaul Moore 		mask_val = ntohl(mask->s6_addr32[iter]);
36163c41688SPaul Moore 		while (mask_val > 0) {
36263c41688SPaul Moore 			mask_val <<= 1;
36363c41688SPaul Moore 			mask_len++;
36463c41688SPaul Moore 		}
36563c41688SPaul Moore 		audit_log_format(audit_buf, " %s_prefixlen=%d", dir, mask_len);
36663c41688SPaul Moore 	}
36763c41688SPaul Moore }
36863c41688SPaul Moore #endif /* IPv6 */
36947b676c0SManish Katiyar #endif /* CONFIG_AUDIT */
370