| 1 | /* $NetBSD: radix_ipf.c,v 1.6 2015/12/15 12:30:34 christos Exp $ */ |
| 2 | |
| 3 | /* |
| 4 | * Copyright (C) 2012 by Darren Reed. |
| 5 | * |
| 6 | * See the IPFILTER.LICENCE file for details on licencing. |
| 7 | */ |
| 8 | #include <sys/types.h> |
| 9 | #include <sys/time.h> |
| 10 | #include <sys/socket.h> |
| 11 | #include <sys/param.h> |
| 12 | #include <netinet/in.h> |
| 13 | #include <net/if.h> |
| 14 | #if !defined(_KERNEL) |
| 15 | # include <stddef.h> |
| 16 | # include <stdlib.h> |
| 17 | # include <strings.h> |
| 18 | # include <string.h> |
| 19 | #endif |
| 20 | #include "netinet/ip_compat.h" |
| 21 | #include "netinet/ip_fil.h" |
| 22 | #ifdef RDX_DEBUG |
| 23 | # include <arpa/inet.h> |
| 24 | # include <stdlib.h> |
| 25 | # include <stdio.h> |
| 26 | #endif |
| 27 | #include "netinet/radix_ipf.h" |
| 28 | |
| 29 | #define ADF_OFF offsetof(addrfamily_t, adf_addr) |
| 30 | #define ADF_OFF_BITS ((ADF_OFF << 3) & 0xffff) |
| 31 | |
| 32 | static ipf_rdx_node_t *ipf_rx_insert(ipf_rdx_head_t *, |
| 33 | ipf_rdx_node_t nodes[2], int *); |
| 34 | static void ipf_rx_attach_mask(ipf_rdx_node_t *, ipf_rdx_mask_t *); |
| 35 | static int count_mask_bits(addrfamily_t *, u_32_t **); |
| 36 | static void buildnodes(addrfamily_t *, addrfamily_t *, |
| 37 | ipf_rdx_node_t n[2]); |
| 38 | static ipf_rdx_node_t *ipf_rx_find_addr(ipf_rdx_node_t *, u_32_t *); |
| 39 | static ipf_rdx_node_t *ipf_rx_lookup(ipf_rdx_head_t *, addrfamily_t *, |
| 40 | addrfamily_t *); |
| 41 | static ipf_rdx_node_t *ipf_rx_match(ipf_rdx_head_t *, addrfamily_t *); |
| 42 | |
| 43 | /* |
| 44 | * Foreword. |
| 45 | * --------- |
| 46 | * The code in this file has been written to target using the addrfamily_t |
| 47 | * data structure to house the address information and no other. Thus there |
| 48 | * are certain aspects of thise code (such as offsets to the address itself) |
| 49 | * that are hard coded here whilst they might be more variable elsewhere. |
| 50 | * Similarly, this code enforces no maximum key length as that's implied by |
| 51 | * all keys needing to be stored in addrfamily_t. |
| 52 | */ |
| 53 | |
| 54 | /* ------------------------------------------------------------------------ */ |
| 55 | /* Function: count_mask_bits */ |
| 56 | /* Returns: number of consecutive bits starting at "mask". */ |
| 57 | /* */ |
| 58 | /* Count the number of bits set in the address section of addrfamily_t and */ |
| 59 | /* return both that number and a pointer to the last word with a bit set if */ |
| 60 | /* lastp is not NULL. The bit count is performed using network byte order */ |
| 61 | /* as the guide for which bit is the most significant bit. */ |
| 62 | /* ------------------------------------------------------------------------ */ |
| 63 | static int |
| 64 | count_mask_bits(addrfamily_t *mask, u_32_t **lastp) |
| 65 | { |
| 66 | u_32_t *mp = (u_32_t *)&mask->adf_addr; |
| 67 | u_32_t m; |
| 68 | int count = 0; |
| 69 | int mlen; |
| 70 | |
| 71 | mlen = mask->adf_len - offsetof(addrfamily_t, adf_addr); |
| 72 | for (; mlen > 0; mlen -= 4, mp++) { |
| 73 | if ((m = ntohl(*mp)) == 0) |
| 74 | break; |
| 75 | if (lastp != NULL) |
| 76 | *lastp = mp; |
| 77 | for (; m & 0x80000000; m <<= 1) |
| 78 | count++; |
| 79 | } |
| 80 | |
| 81 | return count; |
| 82 | } |
| 83 | |
| 84 | |
| 85 | /* ------------------------------------------------------------------------ */ |
| 86 | /* Function: buildnodes */ |
| 87 | /* Returns: Nil */ |
| 88 | /* Parameters: addr(I) - network address for this radix node */ |
| 89 | /* mask(I) - netmask associated with the above address */ |
| 90 | /* nodes(O) - pair of ipf_rdx_node_t's to initialise with data */ |
| 91 | /* associated with addr and mask. */ |
| 92 | /* */ |
| 93 | /* Initialise the fields in a pair of radix tree nodes according to the */ |
| 94 | /* data supplied in the paramters "addr" and "mask". It is expected that */ |
| 95 | /* "mask" will contain a consecutive string of bits set. Masks with gaps in */ |
| 96 | /* the middle are not handled by this implementation. */ |
| 97 | /* ------------------------------------------------------------------------ */ |
| 98 | static void |
| 99 | buildnodes(addrfamily_t *addr, addrfamily_t *mask, ipf_rdx_node_t nodes[2]) |
| 100 | { |
| 101 | u_32_t maskbits; |
| 102 | u_32_t lastmask; |
| 103 | u_32_t *last; |
| 104 | int masklen; |
| 105 | |
| 106 | last = NULL; |
| 107 | maskbits = count_mask_bits(mask, &last); |
| 108 | if (last == NULL) { |
| 109 | masklen = 0; |
| 110 | lastmask = 0; |
| 111 | } else { |
| 112 | masklen = last - (u_32_t *)mask; |
| 113 | lastmask = *last; |
| 114 | } |
| 115 | |
| 116 | bzero(&nodes[0], sizeof(ipf_rdx_node_t) * 2); |
| 117 | nodes[0].maskbitcount = maskbits; |
| 118 | nodes[0].index = -1 - (ADF_OFF_BITS + maskbits); |
| 119 | nodes[0].addrkey = (u_32_t *)addr; |
| 120 | nodes[0].maskkey = (u_32_t *)mask; |
| 121 | nodes[0].addroff = nodes[0].addrkey + masklen; |
| 122 | nodes[0].maskoff = nodes[0].maskkey + masklen; |
| 123 | nodes[0].parent = &nodes[1]; |
| 124 | nodes[0].offset = masklen; |
| 125 | nodes[0].lastmask = lastmask; |
| 126 | nodes[1].offset = masklen; |
| 127 | nodes[1].left = &nodes[0]; |
| 128 | nodes[1].maskbitcount = maskbits; |
| 129 | #ifdef RDX_DEBUG |
| 130 | (void) strcpy(nodes[0].name, "_BUILD.0" ); |
| 131 | (void) strcpy(nodes[1].name, "_BUILD.1" ); |
| 132 | #endif |
| 133 | } |
| 134 | |
| 135 | |
| 136 | /* ------------------------------------------------------------------------ */ |
| 137 | /* Function: ipf_rx_find_addr */ |
| 138 | /* Returns: ipf_rdx_node_t * - pointer to a node in the radix tree. */ |
| 139 | /* Parameters: tree(I) - pointer to first right node in tree to search */ |
| 140 | /* addr(I) - pointer to address to match */ |
| 141 | /* */ |
| 142 | /* Walk the radix tree given by "tree", looking for a leaf node that is a */ |
| 143 | /* match for the address given by "addr". */ |
| 144 | /* ------------------------------------------------------------------------ */ |
| 145 | static ipf_rdx_node_t * |
| 146 | ipf_rx_find_addr(ipf_rdx_node_t *tree, u_32_t *addr) |
| 147 | { |
| 148 | ipf_rdx_node_t *cur; |
| 149 | |
| 150 | for (cur = tree; cur->index >= 0;) { |
| 151 | if (cur->bitmask & addr[cur->offset]) { |
| 152 | cur = cur->right; |
| 153 | } else { |
| 154 | cur = cur->left; |
| 155 | } |
| 156 | } |
| 157 | |
| 158 | return (cur); |
| 159 | } |
| 160 | |
| 161 | |
| 162 | /* ------------------------------------------------------------------------ */ |
| 163 | /* Function: ipf_rx_match */ |
| 164 | /* Returns: ipf_rdx_node_t * - NULL on error, else pointer to the node */ |
| 165 | /* added to the tree. */ |
| 166 | /* Paramters: head(I) - pointer to tree head to search */ |
| 167 | /* addr(I) - pointer to address to find */ |
| 168 | /* */ |
| 169 | /* Search the radix tree for the best match to the address pointed to by */ |
| 170 | /* "addr" and return a pointer to that node. This search will not match the */ |
| 171 | /* address information stored in either of the root leaves as neither of */ |
| 172 | /* them are considered to be part of the tree of data being stored. */ |
| 173 | /* ------------------------------------------------------------------------ */ |
| 174 | static ipf_rdx_node_t * |
| 175 | ipf_rx_match(ipf_rdx_head_t *head, addrfamily_t *addr) |
| 176 | { |
| 177 | ipf_rdx_mask_t *masknode; |
| 178 | ipf_rdx_node_t *prev; |
| 179 | ipf_rdx_node_t *node; |
| 180 | ipf_rdx_node_t *cur; |
| 181 | u_32_t *data; |
| 182 | u_32_t *mask; |
| 183 | u_32_t *key; |
| 184 | u_32_t *end; |
| 185 | int len; |
| 186 | int i; |
| 187 | |
| 188 | len = addr->adf_len; |
| 189 | end = (u_32_t *)((u_char *)addr + len); |
| 190 | node = ipf_rx_find_addr(head->root, (u_32_t *)addr); |
| 191 | |
| 192 | /* |
| 193 | * Search the dupkey list for a potential match. |
| 194 | */ |
| 195 | for (cur = node; (cur != NULL) && (cur->root == 0); cur = cur->dupkey) { |
| 196 | i = cur[0].addroff - cur[0].addrkey; |
| 197 | data = cur[0].addrkey + i; |
| 198 | mask = cur[0].maskkey + i; |
| 199 | key = (u_32_t *)addr + i; |
| 200 | for (; key < end; data++, key++, mask++) |
| 201 | if ((*key & *mask) != *data) |
| 202 | break; |
| 203 | if ((end == key) && (cur->root == 0)) |
| 204 | return (cur); /* Equal keys */ |
| 205 | } |
| 206 | prev = node->parent; |
| 207 | key = (u_32_t *)addr; |
| 208 | |
| 209 | for (node = prev; node->root == 0; node = node->parent) { |
| 210 | /* |
| 211 | * We know that the node hasn't matched so therefore only |
| 212 | * the entries in the mask list are searched, not the top |
| 213 | * node nor the dupkey list. |
| 214 | */ |
| 215 | masknode = node->masks; |
| 216 | for (; masknode != NULL; masknode = masknode->next) { |
| 217 | if (masknode->maskbitcount > node->maskbitcount) |
| 218 | continue; |
| 219 | cur = masknode->node; |
| 220 | for (i = ADF_OFF >> 2; i <= node->offset; i++) { |
| 221 | if ((key[i] & masknode->mask[i]) == |
| 222 | cur->addrkey[i]) |
| 223 | return (cur); |
| 224 | } |
| 225 | } |
| 226 | } |
| 227 | |
| 228 | return NULL; |
| 229 | } |
| 230 | |
| 231 | |
| 232 | /* ------------------------------------------------------------------------ */ |
| 233 | /* Function: ipf_rx_lookup */ |
| 234 | /* Returns: ipf_rdx_node_t * - NULL on error, else pointer to the node */ |
| 235 | /* added to the tree. */ |
| 236 | /* Paramters: head(I) - pointer to tree head to search */ |
| 237 | /* addr(I) - address part of the key to match */ |
| 238 | /* mask(I) - netmask part of the key to match */ |
| 239 | /* */ |
| 240 | /* ipf_rx_lookup searches for an exact match on (addr,mask). The intention */ |
| 241 | /* is to see if a given key is in the tree, not to see if a route exists. */ |
| 242 | /* ------------------------------------------------------------------------ */ |
| 243 | ipf_rdx_node_t * |
| 244 | ipf_rx_lookup(ipf_rdx_head_t *head, addrfamily_t *addr, addrfamily_t *mask) |
| 245 | { |
| 246 | ipf_rdx_node_t *found; |
| 247 | ipf_rdx_node_t *node; |
| 248 | u_32_t *akey; |
| 249 | int count; |
| 250 | |
| 251 | found = ipf_rx_find_addr(head->root, (u_32_t *)addr); |
| 252 | if (found->root == 1) |
| 253 | return NULL; |
| 254 | |
| 255 | /* |
| 256 | * It is possible to find a matching address in the tree but for the |
| 257 | * netmask to not match. If the netmask does not match and there is |
| 258 | * no list of alternatives present at dupkey, return a failure. |
| 259 | */ |
| 260 | count = count_mask_bits(mask, NULL); |
| 261 | if (count != found->maskbitcount && found->dupkey == NULL) |
| 262 | return (NULL); |
| 263 | |
| 264 | akey = (u_32_t *)addr; |
| 265 | if ((found->addrkey[found->offset] & found->maskkey[found->offset]) != |
| 266 | akey[found->offset]) |
| 267 | return NULL; |
| 268 | |
| 269 | if (found->dupkey != NULL) { |
| 270 | node = found; |
| 271 | while (node != NULL && node->maskbitcount != count) |
| 272 | node = node->dupkey; |
| 273 | if (node == NULL) |
| 274 | return (NULL); |
| 275 | found = node; |
| 276 | } |
| 277 | return found; |
| 278 | } |
| 279 | |
| 280 | |
| 281 | /* ------------------------------------------------------------------------ */ |
| 282 | /* Function: ipf_rx_attach_mask */ |
| 283 | /* Returns: Nil */ |
| 284 | /* Parameters: node(I) - pointer to a radix tree node */ |
| 285 | /* mask(I) - pointer to mask structure to add */ |
| 286 | /* */ |
| 287 | /* Add the netmask to the given node in an ordering where the most specific */ |
| 288 | /* netmask is at the top of the list. */ |
| 289 | /* ------------------------------------------------------------------------ */ |
| 290 | static void |
| 291 | ipf_rx_attach_mask(ipf_rdx_node_t *node, ipf_rdx_mask_t *mask) |
| 292 | { |
| 293 | ipf_rdx_mask_t **pm; |
| 294 | ipf_rdx_mask_t *m; |
| 295 | |
| 296 | for (pm = &node->masks; (m = *pm) != NULL; pm = &m->next) |
| 297 | if (m->maskbitcount < mask->maskbitcount) |
| 298 | break; |
| 299 | mask->next = *pm; |
| 300 | *pm = mask; |
| 301 | } |
| 302 | |
| 303 | |
| 304 | /* ------------------------------------------------------------------------ */ |
| 305 | /* Function: ipf_rx_insert */ |
| 306 | /* Returns: ipf_rdx_node_t * - NULL on error, else pointer to the node */ |
| 307 | /* added to the tree. */ |
| 308 | /* Paramters: head(I) - pointer to tree head to add nodes to */ |
| 309 | /* nodes(I) - pointer to radix nodes to be added */ |
| 310 | /* dup(O) - set to 1 if node is a duplicate, else 0. */ |
| 311 | /* */ |
| 312 | /* Add the new radix tree entry that owns nodes[] to the tree given by head.*/ |
| 313 | /* If there is already a matching key in the table, "dup" will be set to 1 */ |
| 314 | /* and the existing node pointer returned if there is a complete key match. */ |
| 315 | /* A complete key match is a matching of all key data that is presented by */ |
| 316 | /* by the netmask. */ |
| 317 | /* ------------------------------------------------------------------------ */ |
| 318 | static ipf_rdx_node_t * |
| 319 | ipf_rx_insert(ipf_rdx_head_t *head, ipf_rdx_node_t nodes[2], int *dup) |
| 320 | { |
| 321 | ipf_rdx_mask_t **pmask; |
| 322 | ipf_rdx_node_t *node; |
| 323 | ipf_rdx_node_t *prev; |
| 324 | ipf_rdx_mask_t *mask; |
| 325 | ipf_rdx_node_t *cur; |
| 326 | u_32_t nodemask; |
| 327 | u_32_t *addr; |
| 328 | u_32_t *data; |
| 329 | int nodebits; |
| 330 | u_32_t *key; |
| 331 | u_32_t *end; |
| 332 | u_32_t bits; |
| 333 | int nodekey; |
| 334 | int nodeoff; |
| 335 | int nlen; |
| 336 | int len; |
| 337 | |
| 338 | addr = nodes[0].addrkey; |
| 339 | |
| 340 | node = ipf_rx_find_addr(head->root, addr); |
| 341 | len = ((addrfamily_t *)addr)->adf_len; |
| 342 | key = (u_32_t *)&((addrfamily_t *)addr)->adf_addr; |
| 343 | data= (u_32_t *)&((addrfamily_t *)node->addrkey)->adf_addr; |
| 344 | end = (u_32_t *)((u_char *)addr + len); |
| 345 | for (nlen = 0; key < end; data++, key++, nlen += 32) |
| 346 | if (*key != *data) |
| 347 | break; |
| 348 | if (end == data) { |
| 349 | *dup = 1; |
| 350 | return (node); /* Equal keys */ |
| 351 | } |
| 352 | *dup = 0; |
| 353 | |
| 354 | bits = (ntohl(*data) ^ ntohl(*key)); |
| 355 | for (; bits != 0; nlen++) { |
| 356 | if ((bits & 0x80000000) != 0) |
| 357 | break; |
| 358 | bits <<= 1; |
| 359 | } |
| 360 | nlen += ADF_OFF_BITS; |
| 361 | nodes[1].index = nlen; |
| 362 | nodes[1].bitmask = htonl(0x80000000 >> (nlen & 0x1f)); |
| 363 | nodes[0].offset = nlen / 32; |
| 364 | nodes[1].offset = nlen / 32; |
| 365 | |
| 366 | /* |
| 367 | * Walk through the tree and look for the correct place to attach |
| 368 | * this node. ipf_rx_fin_addr is not used here because the place |
| 369 | * to attach this node may be an internal node (same key, different |
| 370 | * netmask.) Additionally, the depth of the search is forcibly limited |
| 371 | * here to not exceed the netmask, so that a short netmask will be |
| 372 | * added higher up the tree even if there are lower branches. |
| 373 | */ |
| 374 | cur = head->root; |
| 375 | key = nodes[0].addrkey; |
| 376 | do { |
| 377 | prev = cur; |
| 378 | if (key[cur->offset] & cur->bitmask) { |
| 379 | cur = cur->right; |
| 380 | } else { |
| 381 | cur = cur->left; |
| 382 | } |
| 383 | } while (nlen > (unsigned)cur->index); |
| 384 | |
| 385 | if ((key[prev->offset] & prev->bitmask) == 0) { |
| 386 | prev->left = &nodes[1]; |
| 387 | } else { |
| 388 | prev->right = &nodes[1]; |
| 389 | } |
| 390 | cur->parent = &nodes[1]; |
| 391 | nodes[1].parent = prev; |
| 392 | if ((key[nodes[1].offset] & nodes[1].bitmask) == 0) { |
| 393 | nodes[1].right = cur; |
| 394 | } else { |
| 395 | nodes[1].right = &nodes[0]; |
| 396 | nodes[1].left = cur; |
| 397 | } |
| 398 | |
| 399 | nodeoff = nodes[0].offset; |
| 400 | nodekey = nodes[0].addrkey[nodeoff]; |
| 401 | nodemask = nodes[0].lastmask; |
| 402 | nodebits = nodes[0].maskbitcount; |
| 403 | prev = NULL; |
| 404 | /* |
| 405 | * Find the node up the tree with the largest pattern that still |
| 406 | * matches the node being inserted to see if this mask can be |
| 407 | * moved there. |
| 408 | */ |
| 409 | for (cur = nodes[1].parent; cur->root == 0; cur = cur->parent) { |
| 410 | if (cur->maskbitcount <= nodebits) |
| 411 | break; |
| 412 | if (((cur - 1)->addrkey[nodeoff] & nodemask) != nodekey) |
| 413 | break; |
| 414 | prev = cur; |
| 415 | } |
| 416 | |
| 417 | KMALLOC(mask, ipf_rdx_mask_t *); |
| 418 | if (mask == NULL) |
| 419 | return NULL; |
| 420 | bzero(mask, sizeof(*mask)); |
| 421 | mask->next = NULL; |
| 422 | mask->node = &nodes[0]; |
| 423 | mask->maskbitcount = nodebits; |
| 424 | mask->mask = nodes[0].maskkey; |
| 425 | nodes[0].mymask = mask; |
| 426 | |
| 427 | if (prev != NULL) { |
| 428 | ipf_rdx_mask_t *m; |
| 429 | |
| 430 | for (pmask = &prev->masks; (m = *pmask) != NULL; |
| 431 | pmask = &m->next) { |
| 432 | if (m->maskbitcount < nodebits) |
| 433 | break; |
| 434 | } |
| 435 | } else { |
| 436 | /* |
| 437 | * No higher up nodes qualify, so attach mask locally. |
| 438 | */ |
| 439 | pmask = &nodes[0].masks; |
| 440 | } |
| 441 | mask->next = *pmask; |
| 442 | *pmask = mask; |
| 443 | |
| 444 | /* |
| 445 | * Search the mask list on each child to see if there are any masks |
| 446 | * there that can be moved up to this newly inserted node. |
| 447 | */ |
| 448 | cur = nodes[1].right; |
| 449 | if (cur->root == 0) { |
| 450 | for (pmask = &cur->masks; (mask = *pmask) != NULL; ) { |
| 451 | if (mask->maskbitcount < nodebits) { |
| 452 | *pmask = mask->next; |
| 453 | ipf_rx_attach_mask(&nodes[0], mask); |
| 454 | } else { |
| 455 | pmask = &mask->next; |
| 456 | } |
| 457 | } |
| 458 | } |
| 459 | cur = nodes[1].left; |
| 460 | if (cur->root == 0 && cur != &nodes[0]) { |
| 461 | for (pmask = &cur->masks; (mask = *pmask) != NULL; ) { |
| 462 | if (mask->maskbitcount < nodebits) { |
| 463 | *pmask = mask->next; |
| 464 | ipf_rx_attach_mask(&nodes[0], mask); |
| 465 | } else { |
| 466 | pmask = &mask->next; |
| 467 | } |
| 468 | } |
| 469 | } |
| 470 | return (&nodes[0]); |
| 471 | } |
| 472 | |
| 473 | /* ------------------------------------------------------------------------ */ |
| 474 | /* Function: ipf_rx_addroute */ |
| 475 | /* Returns: ipf_rdx_node_t * - NULL on error, else pointer to the node */ |
| 476 | /* added to the tree. */ |
| 477 | /* Paramters: head(I) - pointer to tree head to search */ |
| 478 | /* addr(I) - address portion of "route" to add */ |
| 479 | /* mask(I) - netmask portion of "route" to add */ |
| 480 | /* nodes(I) - radix tree data nodes inside allocate structure */ |
| 481 | /* */ |
| 482 | /* Attempt to add a node to the radix tree. The key for the node is the */ |
| 483 | /* (addr,mask). No memory allocation for the radix nodes themselves is */ |
| 484 | /* performed here, the data structure that this radix node is being used to */ |
| 485 | /* find is expected to house the node data itself however the call to */ |
| 486 | /* ipf_rx_insert() will attempt to allocate memory in order for netmask to */ |
| 487 | /* be promoted further up the tree. */ |
| 488 | /* In this case, the ip_pool_node_t structure from ip_pool.h contains both */ |
| 489 | /* the key material (addr,mask) and the radix tree nodes[]. */ |
| 490 | /* */ |
| 491 | /* The mechanics of inserting the node into the tree is handled by the */ |
| 492 | /* function ipf_rx_insert() above. Here, the code deals with the case */ |
| 493 | /* where the data to be inserted is a duplicate. */ |
| 494 | /* ------------------------------------------------------------------------ */ |
| 495 | ipf_rdx_node_t * |
| 496 | ipf_rx_addroute(ipf_rdx_head_t *head, addrfamily_t *addr, addrfamily_t *mask, |
| 497 | ipf_rdx_node_t *nodes) |
| 498 | { |
| 499 | ipf_rdx_node_t *node; |
| 500 | ipf_rdx_node_t *prev; |
| 501 | ipf_rdx_node_t *x; |
| 502 | int dup; |
| 503 | |
| 504 | buildnodes(addr, mask, nodes); |
| 505 | x = ipf_rx_insert(head, nodes, &dup); |
| 506 | if (x == NULL) |
| 507 | return NULL; |
| 508 | |
| 509 | if (dup == 1) { |
| 510 | node = &nodes[0]; |
| 511 | prev = NULL; |
| 512 | /* |
| 513 | * The duplicate list is kept sorted with the longest |
| 514 | * mask at the top, meaning that the most specific entry |
| 515 | * in the listis found first. This list thus allows for |
| 516 | * duplicates such as 128.128.0.0/32 and 128.128.0.0/16. |
| 517 | */ |
| 518 | while ((x != NULL) && (x->maskbitcount > node->maskbitcount)) { |
| 519 | prev = x; |
| 520 | x = x->dupkey; |
| 521 | } |
| 522 | |
| 523 | /* |
| 524 | * Is it a complete duplicate? If so, return NULL and |
| 525 | * fail the insert. Otherwise, insert it into the list |
| 526 | * of netmasks active for this key. |
| 527 | */ |
| 528 | if ((x != NULL) && (x->maskbitcount == node->maskbitcount)) |
| 529 | return (NULL); |
| 530 | |
| 531 | if (prev != NULL) { |
| 532 | nodes[0].dupkey = x; |
| 533 | prev->dupkey = &nodes[0]; |
| 534 | nodes[0].parent = prev; |
| 535 | if (x != NULL) |
| 536 | x->parent = &nodes[0]; |
| 537 | } else { |
| 538 | nodes[0].dupkey = x->dupkey; |
| 539 | prev = x->parent; |
| 540 | nodes[0].parent = prev; |
| 541 | x->parent = &nodes[0]; |
| 542 | if (prev->left == x) |
| 543 | prev->left = &nodes[0]; |
| 544 | else |
| 545 | prev->right = &nodes[0]; |
| 546 | } |
| 547 | } |
| 548 | |
| 549 | return &nodes[0]; |
| 550 | } |
| 551 | |
| 552 | |
| 553 | /* ------------------------------------------------------------------------ */ |
| 554 | /* Function: ipf_rx_delete */ |
| 555 | /* Returns: ipf_rdx_node_t * - NULL on error, else node removed from */ |
| 556 | /* the tree. */ |
| 557 | /* Paramters: head(I) - pointer to tree head to search */ |
| 558 | /* addr(I) - pointer to the address part of the key */ |
| 559 | /* mask(I) - pointer to the netmask part of the key */ |
| 560 | /* */ |
| 561 | /* Search for an entry in the radix tree that is an exact match for (addr, */ |
| 562 | /* mask) and remove it if it exists. In the case where (addr,mask) is a not */ |
| 563 | /* a unique key, the tree structure itself is not changed - only the list */ |
| 564 | /* of duplicate keys. */ |
| 565 | /* ------------------------------------------------------------------------ */ |
| 566 | ipf_rdx_node_t * |
| 567 | ipf_rx_delete(ipf_rdx_head_t *head, addrfamily_t *addr, addrfamily_t *mask) |
| 568 | { |
| 569 | ipf_rdx_mask_t **pmask; |
| 570 | ipf_rdx_node_t *parent; |
| 571 | ipf_rdx_node_t *found; |
| 572 | ipf_rdx_node_t *prev; |
| 573 | ipf_rdx_node_t *node; |
| 574 | ipf_rdx_node_t *cur; |
| 575 | ipf_rdx_mask_t *m; |
| 576 | int count; |
| 577 | |
| 578 | found = ipf_rx_find_addr(head->root, (u_32_t *)addr); |
| 579 | if (found == NULL) |
| 580 | return NULL; |
| 581 | if (found->root == 1) |
| 582 | return NULL; |
| 583 | count = count_mask_bits(mask, NULL); |
| 584 | parent = found->parent; |
| 585 | if (found->dupkey != NULL) { |
| 586 | node = found; |
| 587 | while (node != NULL && node->maskbitcount != count) |
| 588 | node = node->dupkey; |
| 589 | if (node == NULL) |
| 590 | return (NULL); |
| 591 | if (node != found) { |
| 592 | /* |
| 593 | * Remove from the dupkey list. Here, "parent" is |
| 594 | * the previous node on the list (rather than tree) |
| 595 | * and "dupkey" is the next node on the list. |
| 596 | */ |
| 597 | parent = node->parent; |
| 598 | parent->dupkey = node->dupkey; |
| 599 | node->dupkey->parent = parent; |
| 600 | } else { |
| 601 | /* |
| 602 | * |
| 603 | * When removing the top node of the dupkey list, |
| 604 | * the pointers at the top of the list that point |
| 605 | * to other tree nodes need to be preserved and |
| 606 | * any children must have their parent updated. |
| 607 | */ |
| 608 | node = node->dupkey; |
| 609 | node->parent = found->parent; |
| 610 | node->right = found->right; |
| 611 | node->left = found->left; |
| 612 | found->right->parent = node; |
| 613 | found->left->parent = node; |
| 614 | if (parent->left == found) |
| 615 | parent->left = node; |
| 616 | else |
| 617 | parent->right= node; |
| 618 | } |
| 619 | } else { |
| 620 | if (count != found->maskbitcount) |
| 621 | return (NULL); |
| 622 | /* |
| 623 | * Remove the node from the tree and reconnect the subtree |
| 624 | * below. |
| 625 | */ |
| 626 | /* |
| 627 | * If there is a tree to the left, look for something to |
| 628 | * attach in place of "found". |
| 629 | */ |
| 630 | prev = found + 1; |
| 631 | cur = parent->parent; |
| 632 | if (parent != found + 1) { |
| 633 | if ((found + 1)->parent->right == found + 1) |
| 634 | (found + 1)->parent->right = parent; |
| 635 | else |
| 636 | (found + 1)->parent->left = parent; |
| 637 | if (cur->right == parent) { |
| 638 | if (parent->left == found) { |
| 639 | cur->right = parent->right; |
| 640 | } else if (parent->left != parent - 1) { |
| 641 | cur->right = parent->left; |
| 642 | } else { |
| 643 | cur->right = parent - 1; |
| 644 | } |
| 645 | cur->right->parent = cur; |
| 646 | } else { |
| 647 | if (parent->right == found) { |
| 648 | cur->left = parent->left; |
| 649 | } else if (parent->right != parent - 1) { |
| 650 | cur->left = parent->right; |
| 651 | } else { |
| 652 | cur->left = parent - 1; |
| 653 | } |
| 654 | cur->left->parent = cur; |
| 655 | } |
| 656 | parent->left = (found + 1)->left; |
| 657 | if ((found + 1)->right != parent) |
| 658 | parent->right = (found + 1)->right; |
| 659 | parent->left->parent = parent; |
| 660 | parent->right->parent = parent; |
| 661 | parent->parent = (found + 1)->parent; |
| 662 | |
| 663 | parent->bitmask = prev->bitmask; |
| 664 | parent->offset = prev->offset; |
| 665 | parent->index = prev->index; |
| 666 | } else { |
| 667 | /* |
| 668 | * We found an edge node. |
| 669 | */ |
| 670 | cur = parent->parent; |
| 671 | if (cur->left == parent) { |
| 672 | if (parent->left == found) { |
| 673 | cur->left = parent->right; |
| 674 | parent->right->parent = cur; |
| 675 | } else { |
| 676 | cur->left = parent->left; |
| 677 | parent->left->parent = cur; |
| 678 | } |
| 679 | } else { |
| 680 | if (parent->right != found) { |
| 681 | cur->right = parent->right; |
| 682 | parent->right->parent = cur; |
| 683 | } else { |
| 684 | cur->right = parent->left; |
| 685 | prev->left->parent = cur; |
| 686 | } |
| 687 | } |
| 688 | } |
| 689 | } |
| 690 | |
| 691 | /* |
| 692 | * Remove mask associated with this node. |
| 693 | */ |
| 694 | for (cur = parent; cur->root == 0; cur = cur->parent) { |
| 695 | ipf_rdx_mask_t **pm; |
| 696 | |
| 697 | if (cur->maskbitcount <= found->maskbitcount) |
| 698 | break; |
| 699 | if (((cur - 1)->addrkey[found->offset] & found->bitmask) != |
| 700 | found->addrkey[found->offset]) |
| 701 | break; |
| 702 | for (pm = &cur->masks; (m = *pm) != NULL; ) |
| 703 | if (m->node == cur) { |
| 704 | *pm = m->next; |
| 705 | break; |
| 706 | } else { |
| 707 | pm = &m->next; |
| 708 | } |
| 709 | } |
| 710 | KFREE(found->mymask); |
| 711 | |
| 712 | /* |
| 713 | * Masks that have been brought up to this node from below need to |
| 714 | * be sent back down. |
| 715 | */ |
| 716 | for (pmask = &parent->masks; (m = *pmask) != NULL; ) { |
| 717 | *pmask = m->next; |
| 718 | cur = m->node; |
| 719 | if (cur == found) |
| 720 | continue; |
| 721 | if (found->addrkey[cur->offset] & cur->lastmask) { |
| 722 | ipf_rx_attach_mask(parent->right, m); |
| 723 | } else if (parent->left != found) { |
| 724 | ipf_rx_attach_mask(parent->left, m); |
| 725 | } |
| 726 | } |
| 727 | |
| 728 | return (found); |
| 729 | } |
| 730 | |
| 731 | |
| 732 | /* ------------------------------------------------------------------------ */ |
| 733 | /* Function: ipf_rx_walktree */ |
| 734 | /* Returns: Nil */ |
| 735 | /* Paramters: head(I) - pointer to tree head to search */ |
| 736 | /* walker(I) - function to call for each node in the tree */ |
| 737 | /* arg(I) - parameter to pass to walker, in addition to the */ |
| 738 | /* node pointer */ |
| 739 | /* */ |
| 740 | /* A standard tree walking function except that it is iterative, rather */ |
| 741 | /* than recursive and tracks the next node in case the "walker" function */ |
| 742 | /* should happen to delete and free the current node. It thus goes without */ |
| 743 | /* saying that the "walker" function is not permitted to cause any change */ |
| 744 | /* in the validity of the data found at either the left or right child. */ |
| 745 | /* ------------------------------------------------------------------------ */ |
| 746 | void |
| 747 | ipf_rx_walktree(ipf_rdx_head_t *head, radix_walk_func_t walker, void *arg) |
| 748 | { |
| 749 | ipf_rdx_node_t *next; |
| 750 | ipf_rdx_node_t *node = head->root; |
| 751 | ipf_rdx_node_t *base; |
| 752 | |
| 753 | while (node->index >= 0) |
| 754 | node = node->left; |
| 755 | |
| 756 | for (;;) { |
| 757 | base = node; |
| 758 | while ((node->parent->right == node) && (node->root == 0)) |
| 759 | node = node->parent; |
| 760 | |
| 761 | for (node = node->parent->right; node->index >= 0; ) |
| 762 | node = node->left; |
| 763 | next = node; |
| 764 | |
| 765 | for (node = base; node != NULL; node = base) { |
| 766 | base = node->dupkey; |
| 767 | if (node->root == 0) |
| 768 | walker(node, arg); |
| 769 | } |
| 770 | node = next; |
| 771 | if (node->root) |
| 772 | return; |
| 773 | } |
| 774 | } |
| 775 | |
| 776 | |
| 777 | /* ------------------------------------------------------------------------ */ |
| 778 | /* Function: ipf_rx_inithead */ |
| 779 | /* Returns: int - 0 = success, else failure */ |
| 780 | /* Paramters: softr(I) - pointer to radix context */ |
| 781 | /* headp(O) - location for where to store allocated tree head */ |
| 782 | /* */ |
| 783 | /* This function allocates and initialises a radix tree head structure. */ |
| 784 | /* As a traditional radix tree, node 0 is used as the "0" sentinel and node */ |
| 785 | /* "2" is used as the all ones sentinel, leaving node "1" as the root from */ |
| 786 | /* which the tree is hung with node "0" on its left and node "2" to the */ |
| 787 | /* right. The context, "softr", is used here to provide a common source of */ |
| 788 | /* the zeroes and ones data rather than have one per head. */ |
| 789 | /* ------------------------------------------------------------------------ */ |
| 790 | int |
| 791 | ipf_rx_inithead(radix_softc_t *softr, ipf_rdx_head_t **headp) |
| 792 | { |
| 793 | ipf_rdx_head_t *ptr; |
| 794 | ipf_rdx_node_t *node; |
| 795 | |
| 796 | KMALLOC(ptr, ipf_rdx_head_t *); |
| 797 | *headp = ptr; |
| 798 | if (ptr == NULL) |
| 799 | return -1; |
| 800 | bzero(ptr, sizeof(*ptr)); |
| 801 | node = ptr->nodes; |
| 802 | ptr->root = node + 1; |
| 803 | node[0].index = ADF_OFF_BITS; |
| 804 | node[0].index = -1 - node[0].index; |
| 805 | node[1].index = ADF_OFF_BITS; |
| 806 | node[2].index = node[0].index; |
| 807 | node[0].parent = node + 1; |
| 808 | node[1].parent = node + 1; |
| 809 | node[2].parent = node + 1; |
| 810 | node[1].bitmask = htonl(0x80000000); |
| 811 | node[0].root = 1; |
| 812 | node[1].root = 1; |
| 813 | node[2].root = 1; |
| 814 | node[0].offset = ADF_OFF_BITS >> 5; |
| 815 | node[1].offset = ADF_OFF_BITS >> 5; |
| 816 | node[2].offset = ADF_OFF_BITS >> 5; |
| 817 | node[1].left = &node[0]; |
| 818 | node[1].right = &node[2]; |
| 819 | node[0].addrkey = (u_32_t *)softr->zeros; |
| 820 | node[2].addrkey = (u_32_t *)softr->ones; |
| 821 | #ifdef RDX_DEBUG |
| 822 | (void) strcpy(node[0].name, "0_ROOT" ); |
| 823 | (void) strcpy(node[1].name, "1_ROOT" ); |
| 824 | (void) strcpy(node[2].name, "2_ROOT" ); |
| 825 | #endif |
| 826 | |
| 827 | ptr->addaddr = ipf_rx_addroute; |
| 828 | ptr->deladdr = ipf_rx_delete; |
| 829 | ptr->lookup = ipf_rx_lookup; |
| 830 | ptr->matchaddr = ipf_rx_match; |
| 831 | ptr->walktree = ipf_rx_walktree; |
| 832 | return 0; |
| 833 | } |
| 834 | |
| 835 | |
| 836 | /* ------------------------------------------------------------------------ */ |
| 837 | /* Function: ipf_rx_freehead */ |
| 838 | /* Returns: Nil */ |
| 839 | /* Paramters: head(I) - pointer to tree head to free */ |
| 840 | /* */ |
| 841 | /* This function simply free's up the radix tree head. Prior to calling */ |
| 842 | /* this function, it is expected that the tree will have been emptied. */ |
| 843 | /* ------------------------------------------------------------------------ */ |
| 844 | void |
| 845 | ipf_rx_freehead(ipf_rdx_head_t *head) |
| 846 | { |
| 847 | KFREE(head); |
| 848 | } |
| 849 | |
| 850 | |
| 851 | /* ------------------------------------------------------------------------ */ |
| 852 | /* Function: ipf_rx_create */ |
| 853 | /* Parameters: Nil */ |
| 854 | /* */ |
| 855 | /* ------------------------------------------------------------------------ */ |
| 856 | void * |
| 857 | ipf_rx_create(void) |
| 858 | { |
| 859 | radix_softc_t *softr; |
| 860 | |
| 861 | KMALLOC(softr, radix_softc_t *); |
| 862 | if (softr == NULL) |
| 863 | return NULL; |
| 864 | bzero((char *)softr, sizeof(*softr)); |
| 865 | |
| 866 | KMALLOCS(softr->zeros, u_char *, 3 * sizeof(addrfamily_t)); |
| 867 | if (softr->zeros == NULL) { |
| 868 | KFREE(softr); |
| 869 | return (NULL); |
| 870 | } |
| 871 | softr->ones = softr->zeros + sizeof(addrfamily_t); |
| 872 | |
| 873 | return softr; |
| 874 | } |
| 875 | |
| 876 | |
| 877 | /* ------------------------------------------------------------------------ */ |
| 878 | /* Function: ipf_rx_init */ |
| 879 | /* Returns: int - 0 = success (always) */ |
| 880 | /* */ |
| 881 | /* ------------------------------------------------------------------------ */ |
| 882 | int |
| 883 | ipf_rx_init(void *ctx) |
| 884 | { |
| 885 | radix_softc_t *softr = ctx; |
| 886 | |
| 887 | memset(softr->zeros, 0, 3 * sizeof(addrfamily_t)); |
| 888 | memset(softr->ones, 0xff, sizeof(addrfamily_t)); |
| 889 | |
| 890 | return (0); |
| 891 | } |
| 892 | |
| 893 | |
| 894 | /* ------------------------------------------------------------------------ */ |
| 895 | /* Function: ipf_rx_destroy */ |
| 896 | /* Returns: Nil */ |
| 897 | /* */ |
| 898 | /* ------------------------------------------------------------------------ */ |
| 899 | void |
| 900 | ipf_rx_destroy(void *ctx) |
| 901 | { |
| 902 | radix_softc_t *softr = ctx; |
| 903 | |
| 904 | if (softr->zeros != NULL) |
| 905 | KFREES(softr->zeros, 3 * sizeof(addrfamily_t)); |
| 906 | KFREE(softr); |
| 907 | } |
| 908 | |
| 909 | /* ====================================================================== */ |
| 910 | |
| 911 | #ifdef RDX_DEBUG |
| 912 | /* |
| 913 | * To compile this file as a standalone test unit, use -DRDX_DEBUG=1 |
| 914 | */ |
| 915 | #define NAME(x) ((x)->index < 0 ? (x)->name : (x)->name) |
| 916 | #define GNAME(y) ((y) == NULL ? "NULL" : NAME(y)) |
| 917 | |
| 918 | typedef struct myst { |
| 919 | struct ipf_rdx_node nodes[2]; |
| 920 | addrfamily_t dst; |
| 921 | addrfamily_t mask; |
| 922 | struct myst *next; |
| 923 | int printed; |
| 924 | } myst_t; |
| 925 | |
| 926 | typedef struct tabe_s { |
| 927 | char *host; |
| 928 | char *mask; |
| 929 | char *what; |
| 930 | } tabe_t; |
| 931 | |
| 932 | tabe_t builtin[] = { |
| 933 | #if 1 |
| 934 | { "192:168:100::0" , "48" , "d" }, |
| 935 | { "192:168:100::2" , "128" , "d" }, |
| 936 | #else |
| 937 | { "127.192.0.0" , "255.255.255.0" , "d" }, |
| 938 | { "127.128.0.0" , "255.255.255.0" , "d" }, |
| 939 | { "127.96.0.0" , "255.255.255.0" , "d" }, |
| 940 | { "127.80.0.0" , "255.255.255.0" , "d" }, |
| 941 | { "127.72.0.0" , "255.255.255.0" , "d" }, |
| 942 | { "127.64.0.0" , "255.255.255.0" , "d" }, |
| 943 | { "127.56.0.0" , "255.255.255.0" , "d" }, |
| 944 | { "127.48.0.0" , "255.255.255.0" , "d" }, |
| 945 | { "127.40.0.0" , "255.255.255.0" , "d" }, |
| 946 | { "127.32.0.0" , "255.255.255.0" , "d" }, |
| 947 | { "127.24.0.0" , "255.255.255.0" , "d" }, |
| 948 | { "127.16.0.0" , "255.255.255.0" , "d" }, |
| 949 | { "127.8.0.0" , "255.255.255.0" , "d" }, |
| 950 | { "124.0.0.0" , "255.0.0.0" , "d" }, |
| 951 | { "125.0.0.0" , "255.0.0.0" , "d" }, |
| 952 | { "126.0.0.0" , "255.0.0.0" , "d" }, |
| 953 | { "127.0.0.0" , "255.0.0.0" , "d" }, |
| 954 | { "10.0.0.0" , "255.0.0.0" , "d" }, |
| 955 | { "128.250.0.0" , "255.255.0.0" , "d" }, |
| 956 | { "192.168.0.0" , "255.255.0.0" , "d" }, |
| 957 | { "192.168.1.0" , "255.255.255.0" , "d" }, |
| 958 | #endif |
| 959 | { NULL, NULL, NULL } |
| 960 | }; |
| 961 | |
| 962 | char *mtable[][1] = { |
| 963 | #if 1 |
| 964 | { "192:168:100::2" }, |
| 965 | { "192:168:101::2" }, |
| 966 | #else |
| 967 | { "9.0.0.0" }, |
| 968 | { "9.0.0.1" }, |
| 969 | { "11.0.0.0" }, |
| 970 | { "11.0.0.1" }, |
| 971 | { "127.0.0.1" }, |
| 972 | { "127.0.1.0" }, |
| 973 | { "255.255.255.0" }, |
| 974 | { "126.0.0.1" }, |
| 975 | { "128.251.0.0" }, |
| 976 | { "128.251.0.1" }, |
| 977 | { "128.251.255.255" }, |
| 978 | { "129.250.0.0" }, |
| 979 | { "129.250.0.1" }, |
| 980 | { "192.168.255.255" }, |
| 981 | #endif |
| 982 | { NULL } |
| 983 | }; |
| 984 | |
| 985 | |
| 986 | int forder[22] = { |
| 987 | 14, 13, 12, 5, 10, 3, 19, 7, 4, 20, 8, |
| 988 | 2, 17, 9, 16, 11, 15, 1, 6, 18, 0, 21 |
| 989 | }; |
| 990 | |
| 991 | static int nodecount = 0; |
| 992 | myst_t *myst_top = NULL; |
| 993 | tabe_t *ttable = NULL; |
| 994 | |
| 995 | void add_addr(ipf_rdx_head_t *, int , int); |
| 996 | void checktree(ipf_rdx_head_t *); |
| 997 | void delete_addr(ipf_rdx_head_t *rnh, int item); |
| 998 | void dumptree(ipf_rdx_head_t *rnh); |
| 999 | void nodeprinter(ipf_rdx_node_t *, void *); |
| 1000 | void printroots(ipf_rdx_head_t *); |
| 1001 | void random_add(ipf_rdx_head_t *); |
| 1002 | void random_delete(ipf_rdx_head_t *); |
| 1003 | void test_addr(ipf_rdx_head_t *rnh, int pref, addrfamily_t *, int); |
| 1004 | |
| 1005 | |
| 1006 | static void |
| 1007 | ipf_rx_freenode(node, arg) |
| 1008 | ipf_rdx_node_t *node; |
| 1009 | void *arg; |
| 1010 | { |
| 1011 | ipf_rdx_head_t *head = arg; |
| 1012 | ipf_rdx_node_t *rv; |
| 1013 | myst_t *stp; |
| 1014 | |
| 1015 | stp = (myst_t *)node; |
| 1016 | rv = ipf_rx_delete(head, &stp->dst, &stp->mask); |
| 1017 | if (rv != NULL) { |
| 1018 | free(rv); |
| 1019 | } |
| 1020 | } |
| 1021 | |
| 1022 | |
| 1023 | const char * |
| 1024 | addrname(ap) |
| 1025 | addrfamily_t *ap; |
| 1026 | { |
| 1027 | static char name[80]; |
| 1028 | const char *txt; |
| 1029 | |
| 1030 | bzero((char *)name, sizeof(name)); |
| 1031 | txt = inet_ntop(ap->adf_family, &ap->adf_addr, name, |
| 1032 | sizeof(name)); |
| 1033 | return txt; |
| 1034 | } |
| 1035 | |
| 1036 | |
| 1037 | void |
| 1038 | fill6bits(bits, msk) |
| 1039 | int bits; |
| 1040 | u_int *msk; |
| 1041 | { |
| 1042 | if (bits == 0) { |
| 1043 | msk[0] = 0; |
| 1044 | msk[1] = 0; |
| 1045 | msk[2] = 0; |
| 1046 | msk[3] = 0; |
| 1047 | return; |
| 1048 | } |
| 1049 | |
| 1050 | msk[0] = 0xffffffff; |
| 1051 | msk[1] = 0xffffffff; |
| 1052 | msk[2] = 0xffffffff; |
| 1053 | msk[3] = 0xffffffff; |
| 1054 | |
| 1055 | if (bits == 128) |
| 1056 | return; |
| 1057 | if (bits > 96) { |
| 1058 | msk[3] = htonl(msk[3] << (128 - bits)); |
| 1059 | } else if (bits > 64) { |
| 1060 | msk[3] = 0; |
| 1061 | msk[2] = htonl(msk[2] << (96 - bits)); |
| 1062 | } else if (bits > 32) { |
| 1063 | msk[3] = 0; |
| 1064 | msk[2] = 0; |
| 1065 | msk[1] = htonl(msk[1] << (64 - bits)); |
| 1066 | } else { |
| 1067 | msk[3] = 0; |
| 1068 | msk[2] = 0; |
| 1069 | msk[1] = 0; |
| 1070 | msk[0] = htonl(msk[0] << (32 - bits)); |
| 1071 | } |
| 1072 | } |
| 1073 | |
| 1074 | |
| 1075 | void |
| 1076 | setaddr(afp, str) |
| 1077 | addrfamily_t *afp; |
| 1078 | char *str; |
| 1079 | { |
| 1080 | |
| 1081 | bzero((char *)afp, sizeof(*afp)); |
| 1082 | |
| 1083 | if (strchr(str, ':') == NULL) { |
| 1084 | afp->adf_family = AF_INET; |
| 1085 | afp->adf_len = offsetof(addrfamily_t, adf_addr) + 4; |
| 1086 | } else { |
| 1087 | afp->adf_family = AF_INET6; |
| 1088 | afp->adf_len = offsetof(addrfamily_t, adf_addr) + 16; |
| 1089 | } |
| 1090 | inet_pton(afp->adf_family, str, &afp->adf_addr); |
| 1091 | } |
| 1092 | |
| 1093 | |
| 1094 | void |
| 1095 | setmask(afp, str) |
| 1096 | addrfamily_t *afp; |
| 1097 | char *str; |
| 1098 | { |
| 1099 | if (strchr(str, '.') != NULL) { |
| 1100 | afp->adf_addr.in4.s_addr = inet_addr(str); |
| 1101 | afp->adf_len = offsetof(addrfamily_t, adf_addr) + 4; |
| 1102 | } else if (afp->adf_family == AF_INET) { |
| 1103 | afp->adf_addr.i6[0] = htonl(0xffffffff << (32 - atoi(str))); |
| 1104 | afp->adf_len = offsetof(addrfamily_t, adf_addr) + 4; |
| 1105 | } else if (afp->adf_family == AF_INET6) { |
| 1106 | fill6bits(atoi(str), afp->adf_addr.i6); |
| 1107 | afp->adf_len = offsetof(addrfamily_t, adf_addr) + 16; |
| 1108 | } |
| 1109 | } |
| 1110 | |
| 1111 | |
| 1112 | void |
| 1113 | nodeprinter(node, arg) |
| 1114 | ipf_rdx_node_t *node; |
| 1115 | void *arg; |
| 1116 | { |
| 1117 | myst_t *stp = (myst_t *)node; |
| 1118 | |
| 1119 | printf("Node %-9.9s L %-9.9s R %-9.9s P %9.9s/%-9.9s %s/%d\n" , |
| 1120 | node[0].name, |
| 1121 | GNAME(node[1].left), GNAME(node[1].right), |
| 1122 | GNAME(node[0].parent), GNAME(node[1].parent), |
| 1123 | addrname(&stp->dst), node[0].maskbitcount); |
| 1124 | if (stp->printed == -1) |
| 1125 | printf("!!! %d\n" , stp->printed); |
| 1126 | else |
| 1127 | stp->printed = 1; |
| 1128 | } |
| 1129 | |
| 1130 | |
| 1131 | void |
| 1132 | printnode(stp) |
| 1133 | myst_t *stp; |
| 1134 | { |
| 1135 | ipf_rdx_node_t *node = &stp->nodes[0]; |
| 1136 | |
| 1137 | if (stp->nodes[0].index > 0) |
| 1138 | stp = (myst_t *)&stp->nodes[-1]; |
| 1139 | |
| 1140 | printf("Node %-9.9s " , node[0].name); |
| 1141 | printf("L %-9.9s " , GNAME(node[1].left)); |
| 1142 | printf("R %-9.9s " , GNAME(node[1].right)); |
| 1143 | printf("P %9.9s" , GNAME(node[0].parent)); |
| 1144 | printf("/%-9.9s " , GNAME(node[1].parent)); |
| 1145 | printf("%s P%d\n" , addrname(&stp->dst), stp->printed); |
| 1146 | } |
| 1147 | |
| 1148 | |
| 1149 | void |
| 1150 | buildtab(void) |
| 1151 | { |
| 1152 | char line[80], *s; |
| 1153 | tabe_t *tab; |
| 1154 | int lines; |
| 1155 | FILE *fp; |
| 1156 | |
| 1157 | lines = 0; |
| 1158 | fp = fopen("hosts" , "r" ); |
| 1159 | |
| 1160 | while (fgets(line, sizeof(line), fp) != NULL) { |
| 1161 | s = strchr(line, '\n'); |
| 1162 | if (s != NULL) |
| 1163 | *s = '\0'; |
| 1164 | lines++; |
| 1165 | if (lines == 1) |
| 1166 | tab = malloc(sizeof(*tab) * 2); |
| 1167 | else |
| 1168 | tab = realloc(tab, (lines + 1) * sizeof(*tab)); |
| 1169 | tab[lines - 1].host = strdup(line); |
| 1170 | s = strchr(tab[lines - 1].host, '/'); |
| 1171 | *s++ = '\0'; |
| 1172 | tab[lines - 1].mask = s; |
| 1173 | tab[lines - 1].what = "d" ; |
| 1174 | } |
| 1175 | fclose(fp); |
| 1176 | |
| 1177 | tab[lines].host = NULL; |
| 1178 | tab[lines].mask = NULL; |
| 1179 | tab[lines].what = NULL; |
| 1180 | ttable = tab; |
| 1181 | } |
| 1182 | |
| 1183 | |
| 1184 | void |
| 1185 | printroots(rnh) |
| 1186 | ipf_rdx_head_t *rnh; |
| 1187 | { |
| 1188 | printf("Root.0.%s b %3d p %-9.9s l %-9.9s r %-9.9s\n" , |
| 1189 | GNAME(&rnh->nodes[0]), |
| 1190 | rnh->nodes[0].index, GNAME(rnh->nodes[0].parent), |
| 1191 | GNAME(rnh->nodes[0].left), GNAME(rnh->nodes[0].right)); |
| 1192 | printf("Root.1.%s b %3d p %-9.9s l %-9.9s r %-9.9s\n" , |
| 1193 | GNAME(&rnh->nodes[1]), |
| 1194 | rnh->nodes[1].index, GNAME(rnh->nodes[1].parent), |
| 1195 | GNAME(rnh->nodes[1].left), GNAME(rnh->nodes[1].right)); |
| 1196 | printf("Root.2.%s b %3d p %-9.9s l %-9.9s r %-9.9s\n" , |
| 1197 | GNAME(&rnh->nodes[2]), |
| 1198 | rnh->nodes[2].index, GNAME(rnh->nodes[2].parent), |
| 1199 | GNAME(rnh->nodes[2].left), GNAME(rnh->nodes[2].right)); |
| 1200 | } |
| 1201 | |
| 1202 | |
| 1203 | int |
| 1204 | main(int argc, char *argv[]) |
| 1205 | { |
| 1206 | addrfamily_t af; |
| 1207 | ipf_rdx_head_t *rnh; |
| 1208 | radix_softc_t *ctx; |
| 1209 | int j; |
| 1210 | int i; |
| 1211 | |
| 1212 | rnh = NULL; |
| 1213 | |
| 1214 | buildtab(); |
| 1215 | ctx = ipf_rx_create(); |
| 1216 | ipf_rx_init(ctx); |
| 1217 | ipf_rx_inithead(ctx, &rnh); |
| 1218 | |
| 1219 | printf("=== ADD-0 ===\n" ); |
| 1220 | for (i = 0; ttable[i].host != NULL; i++) { |
| 1221 | add_addr(rnh, i, i); |
| 1222 | checktree(rnh); |
| 1223 | } |
| 1224 | printroots(rnh); |
| 1225 | ipf_rx_walktree(rnh, nodeprinter, NULL); |
| 1226 | printf("=== DELETE-0 ===\n" ); |
| 1227 | for (i = 0; ttable[i].host != NULL; i++) { |
| 1228 | delete_addr(rnh, i); |
| 1229 | printroots(rnh); |
| 1230 | ipf_rx_walktree(rnh, nodeprinter, NULL); |
| 1231 | } |
| 1232 | printf("=== ADD-1 ===\n" ); |
| 1233 | for (i = 0; ttable[i].host != NULL; i++) { |
| 1234 | setaddr(&af, ttable[i].host); |
| 1235 | add_addr(rnh, i, i); /*forder[i]); */ |
| 1236 | checktree(rnh); |
| 1237 | } |
| 1238 | dumptree(rnh); |
| 1239 | ipf_rx_walktree(rnh, nodeprinter, NULL); |
| 1240 | printf("=== TEST-1 ===\n" ); |
| 1241 | for (i = 0; ttable[i].host != NULL; i++) { |
| 1242 | setaddr(&af, ttable[i].host); |
| 1243 | test_addr(rnh, i, &af, -1); |
| 1244 | } |
| 1245 | |
| 1246 | printf("=== TEST-2 ===\n" ); |
| 1247 | for (i = 0; mtable[i][0] != NULL; i++) { |
| 1248 | setaddr(&af, mtable[i][0]); |
| 1249 | test_addr(rnh, i, &af, -1); |
| 1250 | } |
| 1251 | printf("=== DELETE-1 ===\n" ); |
| 1252 | for (i = 0; ttable[i].host != NULL; i++) { |
| 1253 | if (ttable[i].what[0] != 'd') |
| 1254 | continue; |
| 1255 | delete_addr(rnh, i); |
| 1256 | for (j = 0; ttable[j].host != NULL; j++) { |
| 1257 | setaddr(&af, ttable[j].host); |
| 1258 | test_addr(rnh, i, &af, 3); |
| 1259 | } |
| 1260 | printroots(rnh); |
| 1261 | ipf_rx_walktree(rnh, nodeprinter, NULL); |
| 1262 | } |
| 1263 | |
| 1264 | dumptree(rnh); |
| 1265 | |
| 1266 | printf("=== ADD-2 ===\n" ); |
| 1267 | random_add(rnh); |
| 1268 | checktree(rnh); |
| 1269 | dumptree(rnh); |
| 1270 | ipf_rx_walktree(rnh, nodeprinter, NULL); |
| 1271 | printf("=== DELETE-2 ===\n" ); |
| 1272 | random_delete(rnh); |
| 1273 | checktree(rnh); |
| 1274 | dumptree(rnh); |
| 1275 | |
| 1276 | ipf_rx_walktree(rnh, ipf_rx_freenode, rnh); |
| 1277 | |
| 1278 | return 0; |
| 1279 | } |
| 1280 | |
| 1281 | |
| 1282 | void |
| 1283 | dumptree(rnh) |
| 1284 | ipf_rdx_head_t *rnh; |
| 1285 | { |
| 1286 | myst_t *stp; |
| 1287 | |
| 1288 | printf("VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV\n" ); |
| 1289 | printroots(rnh); |
| 1290 | for (stp = myst_top; stp; stp = stp->next) |
| 1291 | printnode(stp); |
| 1292 | printf("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" ); |
| 1293 | } |
| 1294 | |
| 1295 | |
| 1296 | void |
| 1297 | test_addr(rnh, pref, addr, limit) |
| 1298 | ipf_rdx_head_t *rnh; |
| 1299 | int pref; |
| 1300 | addrfamily_t *addr; |
| 1301 | { |
| 1302 | static int extras[14] = { 0, -1, 1, 3, 5, 8, 9, |
| 1303 | 15, 16, 19, 255, 256, 65535, 65536 |
| 1304 | }; |
| 1305 | ipf_rdx_node_t *rn; |
| 1306 | addrfamily_t af; |
| 1307 | char name[80]; |
| 1308 | myst_t *stp; |
| 1309 | int i; |
| 1310 | |
| 1311 | memset(&af, 0, sizeof(af)); |
| 1312 | #if 0 |
| 1313 | if (limit < 0 || limit > 14) |
| 1314 | limit = 14; |
| 1315 | |
| 1316 | for (i = 0; i < limit; i++) { |
| 1317 | if (ttable[i].host == NULL) |
| 1318 | break; |
| 1319 | setaddr(&af, ttable[i].host); |
| 1320 | printf("%d.%d.LOOKUP(%s)" , pref, i, addrname(&af)); |
| 1321 | rn = ipf_rx_match(rnh, &af); |
| 1322 | stp = (myst_t *)rn; |
| 1323 | printf(" = %s (%s/%d)\n" , GNAME(rn), |
| 1324 | rn ? addrname(&stp->dst) : "NULL" , |
| 1325 | rn ? rn->maskbitcount : 0); |
| 1326 | } |
| 1327 | #else |
| 1328 | printf("%d.%d.LOOKUP(%s)" , pref, -1, addrname(addr)); |
| 1329 | rn = ipf_rx_match(rnh, addr); |
| 1330 | stp = (myst_t *)rn; |
| 1331 | printf(" = %s (%s/%d)\n" , GNAME(rn), |
| 1332 | rn ? addrname(&stp->dst) : "NULL" , rn ? rn->maskbitcount : 0); |
| 1333 | #endif |
| 1334 | } |
| 1335 | |
| 1336 | |
| 1337 | void |
| 1338 | delete_addr(rnh, item) |
| 1339 | ipf_rdx_head_t *rnh; |
| 1340 | int item; |
| 1341 | { |
| 1342 | ipf_rdx_node_t *rn; |
| 1343 | addrfamily_t mask; |
| 1344 | addrfamily_t af; |
| 1345 | myst_t **pstp; |
| 1346 | myst_t *stp; |
| 1347 | |
| 1348 | memset(&af, 0, sizeof(af)); |
| 1349 | memset(&mask, 0, sizeof(mask)); |
| 1350 | setaddr(&af, ttable[item].host); |
| 1351 | mask.adf_family = af.adf_family; |
| 1352 | setmask(&mask, ttable[item].mask); |
| 1353 | |
| 1354 | printf("DELETE(%s)\n" , addrname(&af)); |
| 1355 | rn = ipf_rx_delete(rnh, &af, &mask); |
| 1356 | if (rn == NULL) { |
| 1357 | printf("FAIL LOOKUP DELETE\n" ); |
| 1358 | checktree(rnh); |
| 1359 | for (stp = myst_top; stp != NULL; stp = stp->next) |
| 1360 | if (stp->printed != -1) |
| 1361 | stp->printed = -2; |
| 1362 | ipf_rx_walktree(rnh, nodeprinter, NULL); |
| 1363 | dumptree(rnh); |
| 1364 | abort(); |
| 1365 | } |
| 1366 | printf("%d.delete(%s) = %s\n" , item, addrname(&af), GNAME(rn)); |
| 1367 | |
| 1368 | for (pstp = &myst_top; (stp = *pstp) != NULL; pstp = &stp->next) |
| 1369 | if (stp == (myst_t *)rn) |
| 1370 | break; |
| 1371 | stp->printed = -1; |
| 1372 | stp->nodes[0].parent = &stp->nodes[0]; |
| 1373 | stp->nodes[1].parent = &stp->nodes[1]; |
| 1374 | *pstp = stp->next; |
| 1375 | free(stp); |
| 1376 | nodecount--; |
| 1377 | checktree(rnh); |
| 1378 | } |
| 1379 | |
| 1380 | |
| 1381 | void |
| 1382 | add_addr(rnh, n, item) |
| 1383 | ipf_rdx_head_t *rnh; |
| 1384 | int n, item; |
| 1385 | { |
| 1386 | ipf_rdx_node_t *rn; |
| 1387 | myst_t *stp; |
| 1388 | |
| 1389 | stp = calloc(1, sizeof(*stp)); |
| 1390 | rn = (ipf_rdx_node_t *)stp; |
| 1391 | setaddr(&stp->dst, ttable[item].host); |
| 1392 | stp->mask.adf_family = stp->dst.adf_family; |
| 1393 | setmask(&stp->mask, ttable[item].mask); |
| 1394 | stp->next = myst_top; |
| 1395 | myst_top = stp; |
| 1396 | (void) snprintf(rn[0].name, sizeof(rn[0].name), "_BORN.0" ); |
| 1397 | (void) snprintf(rn[1].name, sizeof(rn[1].name), "_BORN.1" ); |
| 1398 | rn = ipf_rx_addroute(rnh, &stp->dst, &stp->mask, stp->nodes); |
| 1399 | (void) snprintf(rn[0].name, sizeof(rn[0].name), "%d_NODE.0" , item); |
| 1400 | (void) snprintf(rn[1].name, sizeof(rn[1].name), "%d_NODE.1" , item); |
| 1401 | printf("ADD %d/%d %s/%s\n" , n, item, rn[0].name, rn[1].name); |
| 1402 | nodecount++; |
| 1403 | checktree(rnh); |
| 1404 | } |
| 1405 | |
| 1406 | |
| 1407 | void |
| 1408 | checktree(ipf_rdx_head_t *head) |
| 1409 | { |
| 1410 | myst_t *s1; |
| 1411 | ipf_rdx_node_t *rn; |
| 1412 | |
| 1413 | if (nodecount <= 1) |
| 1414 | return; |
| 1415 | |
| 1416 | for (s1 = myst_top; s1 != NULL; s1 = s1->next) { |
| 1417 | int fault = 0; |
| 1418 | if (s1->printed == -1) |
| 1419 | continue; |
| 1420 | rn = &s1->nodes[1]; |
| 1421 | if (rn->right->parent != rn) |
| 1422 | fault |= 1; |
| 1423 | if (rn->left->parent != rn) |
| 1424 | fault |= 2; |
| 1425 | if (rn->parent->left != rn && rn->parent->right != rn) |
| 1426 | fault |= 4; |
| 1427 | if (fault != 0) { |
| 1428 | printf("FAULT %#x %s\n" , fault, rn->name); |
| 1429 | dumptree(head); |
| 1430 | ipf_rx_walktree(head, nodeprinter, NULL); |
| 1431 | fflush(stdout); |
| 1432 | fflush(stderr); |
| 1433 | printf("--\n" ); |
| 1434 | abort(); |
| 1435 | } |
| 1436 | } |
| 1437 | } |
| 1438 | |
| 1439 | |
| 1440 | int * |
| 1441 | randomize(int *pnitems) |
| 1442 | { |
| 1443 | int *order; |
| 1444 | int nitems; |
| 1445 | int choice; |
| 1446 | int j; |
| 1447 | int i; |
| 1448 | |
| 1449 | nitems = sizeof(ttable) / sizeof(ttable[0]); |
| 1450 | *pnitems = nitems; |
| 1451 | order = calloc(nitems, sizeof(*order)); |
| 1452 | srandom(getpid() * time(NULL)); |
| 1453 | memset(order, 0xff, nitems * sizeof(*order)); |
| 1454 | order[21] = 21; |
| 1455 | for (i = 0; i < nitems - 1; i++) { |
| 1456 | do { |
| 1457 | choice = rand() % (nitems - 1); |
| 1458 | for (j = 0; j < nitems; j++) |
| 1459 | if (order[j] == choice) |
| 1460 | break; |
| 1461 | } while (j != nitems); |
| 1462 | order[i] = choice; |
| 1463 | } |
| 1464 | |
| 1465 | return order; |
| 1466 | } |
| 1467 | |
| 1468 | |
| 1469 | void |
| 1470 | random_add(rnh) |
| 1471 | ipf_rdx_head_t *rnh; |
| 1472 | { |
| 1473 | int *order; |
| 1474 | int nitems; |
| 1475 | int i; |
| 1476 | |
| 1477 | order = randomize(&nitems); |
| 1478 | |
| 1479 | for (i = 0; i < nitems - 1; i++) { |
| 1480 | add_addr(rnh, i, order[i]); |
| 1481 | checktree(rnh); |
| 1482 | } |
| 1483 | |
| 1484 | free(order); |
| 1485 | } |
| 1486 | |
| 1487 | |
| 1488 | void |
| 1489 | random_delete(rnh) |
| 1490 | ipf_rdx_head_t *rnh; |
| 1491 | { |
| 1492 | int *order; |
| 1493 | int nitems; |
| 1494 | int i; |
| 1495 | |
| 1496 | order = randomize(&nitems); |
| 1497 | |
| 1498 | for (i = 0; i < nitems - 1; i++) { |
| 1499 | delete_addr(rnh, i); |
| 1500 | checktree(rnh); |
| 1501 | } |
| 1502 | |
| 1503 | free(order); |
| 1504 | } |
| 1505 | #endif /* RDX_DEBUG */ |
| 1506 | |