root/net/netlabel/netlabel_addrlist.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. netlbl_af4list_search
  2. netlbl_af4list_search_exact
  3. netlbl_af6list_search
  4. netlbl_af6list_search_exact
  5. netlbl_af4list_add
  6. netlbl_af6list_add
  7. netlbl_af4list_remove_entry
  8. netlbl_af4list_remove
  9. netlbl_af6list_remove_entry
  10. netlbl_af6list_remove
  11. netlbl_af4list_audit_addr
  12. netlbl_af6list_audit_addr

   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 */

/* [<][>][^][v][top][bottom][index][help] */