0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #include <linux/types.h>
0018 #include <linux/rcupdate.h>
0019 #include <linux/list.h>
0020 #include <linux/spinlock.h>
0021 #include <linux/in.h>
0022 #include <linux/in6.h>
0023 #include <linux/ip.h>
0024 #include <linux/ipv6.h>
0025 #include <net/ip.h>
0026 #include <net/ipv6.h>
0027 #include <linux/audit.h>
0028
0029 #include "netlabel_addrlist.h"
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046 struct netlbl_af4list *netlbl_af4list_search(__be32 addr,
0047 struct list_head *head)
0048 {
0049 struct netlbl_af4list *iter;
0050
0051 list_for_each_entry_rcu(iter, head, list)
0052 if (iter->valid && (addr & iter->mask) == iter->addr)
0053 return iter;
0054
0055 return NULL;
0056 }
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070 struct netlbl_af4list *netlbl_af4list_search_exact(__be32 addr,
0071 __be32 mask,
0072 struct list_head *head)
0073 {
0074 struct netlbl_af4list *iter;
0075
0076 list_for_each_entry_rcu(iter, head, list)
0077 if (iter->valid && iter->addr == addr && iter->mask == mask)
0078 return iter;
0079
0080 return NULL;
0081 }
0082
0083
0084 #if IS_ENABLED(CONFIG_IPV6)
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096 struct netlbl_af6list *netlbl_af6list_search(const struct in6_addr *addr,
0097 struct list_head *head)
0098 {
0099 struct netlbl_af6list *iter;
0100
0101 list_for_each_entry_rcu(iter, head, list)
0102 if (iter->valid &&
0103 ipv6_masked_addr_cmp(&iter->addr, &iter->mask, addr) == 0)
0104 return iter;
0105
0106 return NULL;
0107 }
0108
0109
0110
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121 struct netlbl_af6list *netlbl_af6list_search_exact(const struct in6_addr *addr,
0122 const struct in6_addr *mask,
0123 struct list_head *head)
0124 {
0125 struct netlbl_af6list *iter;
0126
0127 list_for_each_entry_rcu(iter, head, list)
0128 if (iter->valid &&
0129 ipv6_addr_equal(&iter->addr, addr) &&
0130 ipv6_addr_equal(&iter->mask, mask))
0131 return iter;
0132
0133 return NULL;
0134 }
0135 #endif
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148 int netlbl_af4list_add(struct netlbl_af4list *entry, struct list_head *head)
0149 {
0150 struct netlbl_af4list *iter;
0151
0152 iter = netlbl_af4list_search(entry->addr, head);
0153 if (iter != NULL &&
0154 iter->addr == entry->addr && iter->mask == entry->mask)
0155 return -EEXIST;
0156
0157
0158
0159
0160
0161 list_for_each_entry_rcu(iter, head, list)
0162 if (iter->valid &&
0163 ntohl(entry->mask) > ntohl(iter->mask)) {
0164 __list_add_rcu(&entry->list,
0165 iter->list.prev,
0166 &iter->list);
0167 return 0;
0168 }
0169 list_add_tail_rcu(&entry->list, head);
0170 return 0;
0171 }
0172
0173 #if IS_ENABLED(CONFIG_IPV6)
0174
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185 int netlbl_af6list_add(struct netlbl_af6list *entry, struct list_head *head)
0186 {
0187 struct netlbl_af6list *iter;
0188
0189 iter = netlbl_af6list_search(&entry->addr, head);
0190 if (iter != NULL &&
0191 ipv6_addr_equal(&iter->addr, &entry->addr) &&
0192 ipv6_addr_equal(&iter->mask, &entry->mask))
0193 return -EEXIST;
0194
0195
0196
0197
0198
0199 list_for_each_entry_rcu(iter, head, list)
0200 if (iter->valid &&
0201 ipv6_addr_cmp(&entry->mask, &iter->mask) > 0) {
0202 __list_add_rcu(&entry->list,
0203 iter->list.prev,
0204 &iter->list);
0205 return 0;
0206 }
0207 list_add_tail_rcu(&entry->list, head);
0208 return 0;
0209 }
0210 #endif
0211
0212
0213
0214
0215
0216
0217
0218
0219
0220
0221 void netlbl_af4list_remove_entry(struct netlbl_af4list *entry)
0222 {
0223 entry->valid = 0;
0224 list_del_rcu(&entry->list);
0225 }
0226
0227
0228
0229
0230
0231
0232
0233
0234
0235
0236
0237
0238
0239 struct netlbl_af4list *netlbl_af4list_remove(__be32 addr, __be32 mask,
0240 struct list_head *head)
0241 {
0242 struct netlbl_af4list *entry;
0243
0244 entry = netlbl_af4list_search_exact(addr, mask, head);
0245 if (entry == NULL)
0246 return NULL;
0247 netlbl_af4list_remove_entry(entry);
0248 return entry;
0249 }
0250
0251 #if IS_ENABLED(CONFIG_IPV6)
0252
0253
0254
0255
0256
0257
0258
0259
0260
0261 void netlbl_af6list_remove_entry(struct netlbl_af6list *entry)
0262 {
0263 entry->valid = 0;
0264 list_del_rcu(&entry->list);
0265 }
0266
0267
0268
0269
0270
0271
0272
0273
0274
0275
0276
0277
0278
0279 struct netlbl_af6list *netlbl_af6list_remove(const struct in6_addr *addr,
0280 const struct in6_addr *mask,
0281 struct list_head *head)
0282 {
0283 struct netlbl_af6list *entry;
0284
0285 entry = netlbl_af6list_search_exact(addr, mask, head);
0286 if (entry == NULL)
0287 return NULL;
0288 netlbl_af6list_remove_entry(entry);
0289 return entry;
0290 }
0291 #endif
0292
0293
0294
0295
0296
0297 #ifdef CONFIG_AUDIT
0298
0299
0300
0301
0302
0303
0304
0305
0306
0307
0308
0309
0310 void netlbl_af4list_audit_addr(struct audit_buffer *audit_buf,
0311 int src, const char *dev,
0312 __be32 addr, __be32 mask)
0313 {
0314 u32 mask_val = ntohl(mask);
0315 char *dir = (src ? "src" : "dst");
0316
0317 if (dev != NULL)
0318 audit_log_format(audit_buf, " netif=%s", dev);
0319 audit_log_format(audit_buf, " %s=%pI4", dir, &addr);
0320 if (mask_val != 0xffffffff) {
0321 u32 mask_len = 0;
0322 while (mask_val > 0) {
0323 mask_val <<= 1;
0324 mask_len++;
0325 }
0326 audit_log_format(audit_buf, " %s_prefixlen=%d", dir, mask_len);
0327 }
0328 }
0329
0330 #if IS_ENABLED(CONFIG_IPV6)
0331
0332
0333
0334
0335
0336
0337
0338
0339
0340
0341
0342
0343 void netlbl_af6list_audit_addr(struct audit_buffer *audit_buf,
0344 int src,
0345 const char *dev,
0346 const struct in6_addr *addr,
0347 const struct in6_addr *mask)
0348 {
0349 char *dir = (src ? "src" : "dst");
0350
0351 if (dev != NULL)
0352 audit_log_format(audit_buf, " netif=%s", dev);
0353 audit_log_format(audit_buf, " %s=%pI6", dir, addr);
0354 if (ntohl(mask->s6_addr32[3]) != 0xffffffff) {
0355 u32 mask_len = 0;
0356 u32 mask_val;
0357 int iter = -1;
0358 while (ntohl(mask->s6_addr32[++iter]) == 0xffffffff)
0359 mask_len += 32;
0360 mask_val = ntohl(mask->s6_addr32[iter]);
0361 while (mask_val > 0) {
0362 mask_val <<= 1;
0363 mask_len++;
0364 }
0365 audit_log_format(audit_buf, " %s_prefixlen=%d", dir, mask_len);
0366 }
0367 }
0368 #endif
0369 #endif