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(&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
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.