1 | /*************************************** 2 | $Revision: 1.25 $ 3 | 4 | IP handling (ip). ip.c - conversions between ascii and binary forms 5 | of IP addresses, prefixes and ranges. 6 | 7 | various operations on binary forms. 8 | 9 | Status: NOT REVUED, TESTED, COMPLETE 10 | 11 | Design and implementation by: Marek Bukowy 12 | 13 | ******************/ /****************** 14 | Copyright (c) 1999 RIPE NCC 15 | 16 | All Rights Reserved 17 | 18 | Permission to use, copy, modify, and distribute this software and its 19 | documentation for any purpose and without fee is hereby granted, 20 | provided that the above copyright notice appear in all copies and that 21 | both that copyright notice and this permission notice appear in 22 | supporting documentation, and that the name of the author not be 23 | used in advertising or publicity pertaining to distribution of the 24 | software without specific, written prior permission. 25 | 26 | THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 27 | ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL 28 | AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY 29 | DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 30 | AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 31 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 32 | ***************************************/ 33 | 34 | #define IP_IMPL 35 | #include <iproutines.h> 36 | #include <string.h> 37 | #include <stdio.h> 38 | #include <erroutines.h> 39 | 40 | #include <ctype.h> 41 | #include <memwrap.h> 42 | 43 | #include <numconv.h> 44 | #include <stubs.h> 45 | 46 | #include <sys/socket.h> 47 | #include <netinet/in.h> 48 | 49 | #include <inet6def.h> 50 | 51 | /**************************************************************************/ 52 | /*+ return the max. length of bits per space 53 | 54 | Yes, it *could* be a macro - but as a function it can detect 55 | more programmer's errors. And will get inlined anyway. 56 | 57 | +*/ 58 | 59 | int IP_sizebits(ip_space_t spc_id) { 60 | switch (spc_id) { 61 | case IP_V4: 62 | return 32; 63 | case IP_V6: 64 | return 128; 65 | default: 66 | /* die; */ /* error: bad IP version specified */ 67 | return -1; 68 | } 69 | } 70 | 71 | static 72 | er_ret_t 73 | ip_rang_validate(ip_range_t *rangptr) 74 | { 75 | if( rangptr->begin.space != rangptr->end.space ) { 76 | /* die; */ /* incompatible IP spaces */ 77 | return IP_INVRAN; 78 | } 79 | 80 | /* XXX IPv6 range check missing */ 81 | if( rangptr->begin.space == IP_V4 ) { 82 | if( rangptr->begin.words[0] > rangptr->end.words[0] ) { 83 | return IP_INVRAN; 84 | } 85 | } 86 | 87 | return IP_OK; 88 | } 89 | /**************************************************************************/ 90 | /*+ 91 | ascii IP address to binary. 92 | 93 | In IP_EXPN mode IP will be "expanded" 94 | (missing octets will be set to 0, MSB's will be set). 95 | In IP_PLAIN mode the routine will complain if it sees less octets. 96 | 97 | why not use the standard inet_blabla routine ? 98 | it's because if some octets are missing, we make the address zero-padded 99 | (unlike the inet_blabla, which puts zeros in the middle). We also want 100 | to control the expansion with a flag. 101 | 102 | +*/ 103 | 104 | er_ret_t 105 | IP_addr_t2b(ip_addr_t *ipptr, char *addr, ip_exp_t expf) 106 | { 107 | if( index(addr, ':') == NULL ) { 108 | /* IPv4 */ 109 | char *dot=addr; 110 | unsigned len, byte, result=0; 111 | char cpy[4]; 112 | int last = 0, dotsfound=0; 113 | int bytes=0; 114 | 115 | if( expf != IP_PLAIN && expf != IP_EXPN ) { 116 | return IP_INVARG; 117 | } 118 | 119 | do { 120 | char *olddot = dot+1; 121 | /* dot should point to the "end of this number", not necessarily a dot */ 122 | 123 | if ( (dot = index (addr, '.')) == NULL) { 124 | /* after the ip it can contain lots of junk spaces */ 125 | while( *olddot != 0 && ! isspace(* (unsigned char *) olddot) ) { 126 | olddot++; 127 | } 128 | dot = olddot; 129 | last = 1; 130 | } 131 | else { 132 | if( ++dotsfound > 3 ) { 133 | /* handle syntax ERROR - too many dots found */ 134 | return IP_INVIP4; 135 | } 136 | } 137 | 138 | if ((len = dot - addr) > 3) { 139 | /* syntax ERROR - too many digits in an octet */ 140 | return IP_INVIP4; 141 | } 142 | strncpy( cpy, addr, len ); 143 | cpy[len]=0; 144 | 145 | /* sscanf is waay too slow */ 146 | 147 | if( ut_dec_2_uns(cpy, &byte) < 0 ) { 148 | /* handle syntax ERROR - invalid characters found */ 149 | return IP_INVIP4; 150 | } 151 | 152 | 153 | if( byte > 255 ) { 154 | /* handle syntax ERROR - number between dots too high */ 155 | return IP_INVIP4; 156 | } 157 | 158 | result <<= 8; 159 | result += byte; 160 | bytes++; 161 | 162 | addr = dot + 1; 163 | } while (!last); 164 | 165 | if( expf == IP_PLAIN ) { 166 | if( bytes!=4 ) { 167 | return IP_INVIP4; 168 | } 169 | } 170 | else { 171 | while( bytes<4 ) { 172 | result <<= 8; 173 | bytes++; 174 | } 175 | } 176 | 177 | memset(ipptr, 0, sizeof(ip_addr_t)); 178 | ipptr->space = IP_V4; 179 | ipptr->words[0] = result; 180 | } 181 | else { 182 | /* IPv6 */ 183 | #define _IPV6_LENGTH 128 184 | char addrcpy[_IPV6_LENGTH]; 185 | char *ch, *start; 186 | 187 | strncpy(addrcpy, addr, _IPV6_LENGTH-1); 188 | addrcpy[_IPV6_LENGTH-1] = 0; 189 | 190 | /* get rid of superfluous whitespaces */ 191 | /* leading... */ 192 | for( ch = start = addrcpy ; *ch != 0; ch++ ) { 193 | if( isspace( (int) *ch) ) { 194 | start++; 195 | } 196 | else { 197 | break; 198 | } 199 | } 200 | 201 | /* and trailing */ 202 | while( *ch != 0 ) { 203 | if( isspace( (int) *ch) ) { 204 | *ch = 0; 205 | break; 206 | } 207 | ch++; 208 | } 209 | 210 | if( inet_pton(AF_INET6, start, (ipptr->words)) == 0 ) { 211 | return IP_NO6YET; 212 | } 213 | 214 | ipptr->space = IP_V6; 215 | 216 | #undef _IPV6_LENGTH 217 | } 218 | return IP_OK; 219 | } 220 | 221 | /**************************************************************************/ 222 | 223 | /*+ converts a "IP/length" string into a binary prefix 224 | 225 | 226 | 227 | +*/ 228 | 229 | er_ret_t 230 | IP_pref_t2b(ip_prefix_t *prefptr, char *prefstr, ip_exp_t expf) 231 | { 232 | char ip[256]; 233 | char *trash; 234 | char *slash; 235 | int len; 236 | er_ret_t err; 237 | 238 | if( expf != IP_PLAIN && expf != IP_EXPN ) { 239 | return IP_INVARG; 240 | } 241 | 242 | if( (slash=index(prefstr, '/')) == NULL ) { 243 | /* die; */ /* error: missing slash in prefix */ 244 | return IP_NOSLAS; 245 | } 246 | else { 247 | /* copy the IP part to another string, ERROR if 256 chars not enough */ 248 | 249 | len = slash - prefstr; 250 | if( len > 255 ) { 251 | /* die; */ /* ERROR - ip address part of the string too long. */ 252 | return IP_ADTOLO; 253 | } 254 | strncpy(ip, prefstr, len); 255 | ip[len]=0; 256 | 257 | if( (err=IP_addr_t2b( &(prefptr->ip), ip, expf)) != IP_OK) { 258 | /* die; */ /* set error flag: incorrect address format */ 259 | return err; 260 | } 261 | 262 | /* stop at first non-digit */ 263 | for(trash = slash+1; 264 | isdigit(* (unsigned char*) trash); /* cast for stupid gcc */ 265 | trash++) 266 | ; 267 | len = trash - (slash+1) ; 268 | if( len > 4 ) { 269 | /* die; */ /* ERROR - prefix length part of the string too long. */ 270 | return IP_PRTOLO; 271 | } 272 | strncpy(ip, slash+1, len); 273 | ip[len]=0; 274 | 275 | if( ut_dec_2_uns(ip, &prefptr->bits) < 0 276 | || prefptr->bits > IP_sizebits(prefptr->ip.space)) 277 | { 278 | /* if( sscanf (slash+1, "%d", &(prefptr->bits)) < 1 ) { 279 | die; */ /* handle syntax ERROR invalid characters found */ 280 | return IP_INVPRF; 281 | } 282 | } 283 | /* sanitify the prefix - maybe some irrelevant bits are set */ 284 | /* never create broken binary prefixes. */ 285 | 286 | IP_pref_bit_fix(prefptr); 287 | 288 | return IP_OK; 289 | } 290 | 291 | /**************************************************************************/ 292 | 293 | /*+ converts an inaddr/ip6int string into a binary prefix. 294 | no distinction is made with respect to "expand" argument. 295 | +*/ 296 | er_ret_t 297 | IP_revd_t2b(ip_prefix_t *prefptr, char *domstr, ip_exp_t expf) 298 | { 299 | #define CPYLEN 264 300 | char ip[256], temp[256]; 301 | char prefstr[CPYLEN+1]; 302 | char *arpa; 303 | char *ch; 304 | int len, octets=0, goon=1; 305 | char *dot; 306 | er_ret_t err; 307 | 308 | dieif( expf != IP_PLAIN && expf != IP_EXPN ); 309 | 310 | /* The input may not be in lowercase, but must be processed as well. 311 | The simplest solution: make a copy and change it to lowercase. */ 312 | 313 | strncpy( prefstr, domstr, CPYLEN ); 314 | prefstr[CPYLEN] = '\0'; 315 | 316 | for(ch = prefstr; *ch != '\0'; ch++) { 317 | *ch = tolower(*ch); 318 | } 319 | 320 | if( (arpa=strstr(prefstr, ".in-addr.arpa")) == NULL ) { 321 | 322 | #if 0 /* XXX ip6.int version not yet implemented */ 323 | if( (arpa=strstr(prefstr, ".ip6.int")) != NULL ) { 324 | /* ipv6 */ 325 | } 326 | #endif 327 | 328 | return IP_NOREVD; 329 | } 330 | else { 331 | /* copy the IP part to another string, ERROR if 256 chars not enough */ 332 | len = arpa - prefstr; 333 | if( len > 255 ) { 334 | /* die; */ /* ERROR - ip address part of the string too long. */ 335 | return IP_ADTOLO; 336 | } 337 | strncpy(temp, prefstr, len); 338 | temp[len]=0; 339 | 340 | /* now : get the octets reversed one by one. */ 341 | ip[0]=0; /* init */ 342 | do { 343 | if( (dot = strrchr( temp, '.' )) == NULL ) { 344 | goon = 0; 345 | dot = temp; 346 | } 347 | 348 | strcat(ip, dot + ( goon ) ); 349 | octets++; 350 | 351 | /* add a dot, unless that was the last octet */ 352 | if( goon ) { 353 | strcat(ip, "."); 354 | } 355 | 356 | *dot = 0; 357 | 358 | } while( goon ); 359 | 360 | if( (err=IP_addr_t2b( &(prefptr->ip), ip, IP_EXPN)) != IP_OK) { 361 | /* die; */ /* set error flag: incorrect address format */ 362 | return err; 363 | } 364 | 365 | prefptr->bits = octets * 8; 366 | } 367 | return IP_OK; 368 | } 369 | 370 | /**************************************************************************/ 371 | 372 | /*+ convert a range string into a binary range struct. 373 | +*/ 374 | er_ret_t 375 | IP_rang_t2b(ip_range_t *rangptr, char *rangstr, ip_exp_t expf) 376 | { 377 | char *ips, *dash; 378 | er_ret_t err; 379 | 380 | if( expf != IP_PLAIN && expf != IP_EXPN ) { 381 | return IP_INVARG; 382 | } 383 | 384 | if( (dash=index(rangstr, '-')) == NULL ) { 385 | /* die; */ /* error: missing dash in range */ 386 | return IP_INVRAN; 387 | } 388 | else { 389 | /* copy the first IP */ 390 | if( (err = wr_calloc( (void*) &ips,1,dash - rangstr + 1)) != UT_OK ) { 391 | return err; 392 | } 393 | 394 | strncpy(ips, rangstr, dash - rangstr); 395 | 396 | /* convert the first IP into a binary struct */ 397 | err=IP_addr_t2b( &(rangptr->begin), ips, expf); 398 | 399 | /* check later */ /* set error flag: incorrect address format */ 400 | 401 | wr_free(ips); 402 | 403 | if( err != IP_OK ) { 404 | return err; 405 | } 406 | 407 | /* now find the other ip, skip the space */ 408 | ips=dash+1; 409 | while( *ips == ' ' ) { 410 | ips++; 411 | } 412 | 413 | /* convert the second IP into a binary struct */ 414 | if( (err=IP_addr_t2b( &(rangptr->end), ips, expf)) != IP_OK ) { 415 | /* die; */ /* incorrect address format */ 416 | return err; 417 | } 418 | 419 | 420 | 421 | return ip_rang_validate(rangptr); 422 | } 423 | } 424 | 425 | 426 | /**************************************************************************/ 427 | /* accessor functions */ 428 | 429 | /******** address **********/ 430 | 431 | unsigned IP_addr_b2_space(ip_addr_t *addrptr) 432 | { 433 | return addrptr->space; 434 | } 435 | 436 | unsigned IP_addr_b2v4_addr(ip_addr_t *addrptr) 437 | { 438 | dieif( addrptr->space != IP_V4 ); 439 | return addrptr->words[0]; 440 | } 441 | /* ipv4 */ 442 | 443 | ip_v6word_t IP_addr_b2v6_hi(ip_addr_t *addrptr) 444 | { 445 | dieif( addrptr->space != IP_V6 ); 446 | return ( (((ip_v6word_t) addrptr->words[0]) << 32) 447 | + (((ip_v6word_t) addrptr->words[1]) )); 448 | } 449 | 450 | ip_v6word_t IP_addr_b2v6_lo(ip_addr_t *addrptr) 451 | { 452 | dieif( addrptr->space != IP_V6 ); 453 | return ( (((ip_v6word_t) addrptr->words[2]) << 32) 454 | + (((ip_v6word_t) addrptr->words[3]) )); 455 | } 456 | 457 | /******** prefix **********/ 458 | 459 | unsigned IP_pref_b2_space(ip_prefix_t *prefix) { 460 | return IP_addr_b2_space( &(prefix->ip) ); 461 | } 462 | 463 | unsigned IP_pref_b2_len(ip_prefix_t *prefix) { 464 | return prefix->bits; 465 | } 466 | 467 | unsigned IP_pref_b2v4_addr(ip_prefix_t *prefix) { 468 | return IP_addr_b2v4_addr( &(prefix->ip) ); 469 | } 470 | 471 | /* range */ 472 | 473 | unsigned IP_rang_b2_space(ip_range_t *myrang) { 474 | /* hardwire to IPV4 for now */ 475 | return IP_V4; 476 | } 477 | 478 | /* 479 | * complex conversions (return void, set values through pointers * 480 | */ 481 | void IP_addr_b2v4(ip_addr_t *addrptr, unsigned *address) { 482 | *address = IP_addr_b2v4_addr(addrptr); 483 | } 484 | 485 | void IP_pref_b2v4(ip_prefix_t *prefptr, 486 | unsigned int *prefix, 487 | unsigned int *prefix_length) 488 | { 489 | *prefix = IP_addr_b2v4_addr( &(prefptr->ip)); 490 | *prefix_length = IP_pref_b2v4_len(prefptr); 491 | } 492 | 493 | 494 | 495 | void IP_pref_b2v6(ip_prefix_t *prefptr, 496 | ip_v6word_t *high, 497 | ip_v6word_t *low, 498 | unsigned int *prefix_length) 499 | { 500 | *high = IP_addr_b2v6_hi( &(prefptr->ip)); 501 | *low = IP_addr_b2v6_lo( &(prefptr->ip)); 502 | *prefix_length = IP_pref_b2v6_len(prefptr); 503 | } 504 | 505 | 506 | void IP_rang_b2v4(ip_range_t *myrang, 507 | unsigned *begin, 508 | unsigned *end) 509 | { 510 | *begin = IP_addr_b2v4_addr( &(myrang->begin)); 511 | *end = IP_addr_b2v4_addr( &(myrang->end)); 512 | } 513 | 514 | 515 | 516 | /******** construct from raw values **********/ 517 | 518 | /******** address **********/ 519 | er_ret_t IP_addr_v4_mk(ip_addr_t *addrptr, 520 | unsigned addrval) { 521 | addrptr->space = IP_V4; 522 | addrptr->words[0] = addrval; 523 | addrptr->words[1] = addrptr->words[2] = addrptr->words[3] = 0; 524 | 525 | /* no real possibility of checking the syntax */ 526 | return IP_OK; 527 | } 528 | 529 | er_ret_t IP_addr_v6_mk(ip_addr_t *addrptr, 530 | ip_v6word_t high, 531 | ip_v6word_t low) { 532 | 533 | ip_v6word_t ff = 0xffffffff; 534 | 535 | addrptr->space = IP_V6; 536 | (addrptr->words[0]) = (high >> 32) & ff; 537 | (addrptr->words[1]) = high & ff ; 538 | (addrptr->words[2]) = (low >> 32) & ff; 539 | (addrptr->words[3]) = low & ff; 540 | 541 | /* no real possibility of checking the syntax */ 542 | return IP_OK; 543 | } 544 | 545 | /******** prefix **********/ 546 | er_ret_t IP_pref_v4_mk(ip_prefix_t *prefix, 547 | unsigned prefval, 548 | unsigned preflen) 549 | { 550 | if( preflen > 32 ) { 551 | die; 552 | } 553 | IP_addr_v4_mk(&(prefix->ip), prefval); 554 | prefix->bits = preflen; 555 | 556 | IP_pref_bit_fix( prefix ); /* never produce inconsistent prefixes */ 557 | 558 | return IP_OK; 559 | } 560 | 561 | /******** range **********/ 562 | er_ret_t IP_rang_v4_mk(ip_range_t *rangptr, 563 | unsigned addrbegin, 564 | unsigned addrend) 565 | { 566 | er_ret_t err; 567 | 568 | if( (err=IP_addr_v4_mk( &(rangptr->begin), addrbegin)) == IP_OK ) { 569 | err=IP_addr_v4_mk( &(rangptr->end), addrend); 570 | } 571 | return err; 572 | } 573 | 574 | /**************************************************************************/ 575 | 576 | 577 | /**************************************************************************/ 578 | /*+ a2v4 == functions to convert the ascii representation into binary, 579 | * and then set the unsigned values at the pointers provided. 580 | * 581 | +*/ 582 | 583 | /* Convert route string into numbers */ 584 | /* ipv4 */ 585 | er_ret_t 586 | IP_pref_a2v4(char *avalue, ip_prefix_t *pref, 587 | unsigned *prefix, unsigned *prefix_length) 588 | { 589 | 590 | er_ret_t ret; 591 | 592 | if((ret = IP_pref_e2b(pref, avalue)) == IP_OK) { 593 | IP_pref_b2v4(pref, prefix, prefix_length); 594 | } 595 | return(ret); 596 | } 597 | 598 | /* ipv6 */ 599 | er_ret_t 600 | IP_pref_a2v6(char *avalue, ip_prefix_t *pref, 601 | ip_v6word_t *high, ip_v6word_t *low, 602 | unsigned *prefix_length) 603 | { 604 | er_ret_t ret; 605 | 606 | if((ret = IP_pref_e2b(pref, avalue)) == IP_OK) { 607 | IP_pref_b2v6(pref, high, low, prefix_length); 608 | } 609 | return(ret); 610 | } 611 | 612 | /* Convert reverse domain string into numbers */ 613 | er_ret_t 614 | IP_revd_a2v4(char *avalue, ip_prefix_t *pref, 615 | unsigned int *prefix, unsigned int *prefix_length) 616 | { 617 | er_ret_t ret; 618 | 619 | if((ret = IP_revd_e2b(pref, avalue)) == IP_OK) { 620 | IP_pref_b2v4(pref, prefix, prefix_length); 621 | } 622 | return(ret); 623 | } 624 | 625 | /* Convert ip addr string into numbers */ 626 | er_ret_t 627 | IP_addr_a2v4(char *avalue,ip_addr_t *ipaddr, unsigned int *address) 628 | { 629 | er_ret_t ret; 630 | 631 | if((ret = IP_addr_e2b(ipaddr, avalue)) == IP_OK) { 632 | IP_addr_b2v4(ipaddr, address); 633 | } 634 | return(ret); 635 | } 636 | 637 | /* Convert inetnum attribute into numbers */ 638 | er_ret_t 639 | IP_rang_a2v4(char *rangstr, ip_range_t *myrang, 640 | unsigned int *begin_in, unsigned int *end_in) 641 | { 642 | er_ret_t ret; 643 | 644 | if( (ret=IP_rang_e2b(myrang, rangstr)) == IP_OK ) { 645 | #if 0 /* no IPv4 classful ranges anymore */ 646 | if( IP_addr_e2b( &(myrang->begin), rangstr ) == IP_OK ) 647 | if ((ret=IP_rang_classful( myrang , &(myrang->begin))) == IP_OK ) 648 | ; 649 | #endif 650 | IP_rang_b2v4(myrang, begin_in, end_in); 651 | } 652 | 653 | return (ret); 654 | } 655 | 656 | 657 | /* ********************************************************************* 658 | f2b - free numbers represented in ascii into a binary struct 659 | ********************************************************************* */ 660 | 661 | er_ret_t 662 | IP_addr_f2b_v4(ip_addr_t *addrptr, char *adrstr) 663 | { 664 | unsigned address; 665 | 666 | if( ut_dec_2_uns(adrstr, &address) < 0 ) { 667 | return IP_INVARG; 668 | } 669 | 670 | return IP_addr_v4_mk(addrptr, address); 671 | } 672 | 673 | er_ret_t 674 | IP_rang_f2b_v4(ip_range_t *rangptr, char *beginstr, char *endstr) 675 | { 676 | if( IP_addr_f2b_v4( &(rangptr->begin), beginstr) != IP_OK 677 | || IP_addr_f2b_v4( &(rangptr->end), endstr) != IP_OK) { 678 | return IP_INVARG; 679 | } 680 | else { 681 | return IP_OK; 682 | } 683 | } 684 | 685 | er_ret_t 686 | IP_pref_f2b_v4(ip_prefix_t *prefptr, char *prefixstr, char *lengthstr) 687 | { 688 | if( IP_addr_f2b_v4( &(prefptr->ip), prefixstr) != IP_OK 689 | || ut_dec_2_uns(lengthstr, &(prefptr->bits) ) < 0 690 | || prefptr->bits > IP_sizebits(prefptr->ip.space)) { 691 | return IP_INVARG; 692 | } 693 | IP_pref_bit_fix(prefptr); /* never create broken binary prefixes. */ 694 | return IP_OK; 695 | } 696 | 697 | 698 | er_ret_t 699 | IP_addr_f2b_v6(ip_addr_t *addrptr, char *msbstr, char *lsbstr ) 700 | { 701 | ip_v6word_t high, low; 702 | 703 | if( sscanf(msbstr, "%llu", &high) < 1 || 704 | sscanf(lsbstr, "%llu", &low) < 1 ) { 705 | return IP_INVARG; 706 | } 707 | 708 | return IP_addr_v6_mk(addrptr, high, low); 709 | } 710 | 711 | 712 | er_ret_t 713 | IP_pref_f2b_v6(ip_prefix_t *prefptr, char *msbstr, char *lsbstr, char *lengthstr) 714 | { 715 | if( IP_addr_f2b_v6( &(prefptr->ip), msbstr, lsbstr ) != IP_OK 716 | || ut_dec_2_uns(lengthstr, &(prefptr->bits) ) < 0 717 | || prefptr->bits > IP_sizebits(prefptr->ip.space)) { 718 | return IP_INVARG; 719 | } 720 | IP_pref_bit_fix(prefptr); /* never create broken binary prefixes. */ 721 | return IP_OK; 722 | } 723 | 724 | 725 | /**************************************************************************/ 726 | /*+ convert the socket's idea of address into a binary range struct. 727 | 728 | space select the address type (and consequently struct type) 729 | */ 730 | 731 | er_ret_t 732 | IP_addr_s2b(ip_addr_t *addrptr, 733 | void *addr_in, 734 | int addr_len) 735 | { 736 | if( addr_len == sizeof(struct sockaddr_in) 737 | && ((struct sockaddr_in *)addr_in)->sin_family == AF_INET ) { 738 | addrptr->space = IP_V4; 739 | addrptr->words[0] = 740 | ntohl( ((struct sockaddr_in*)addr_in)->sin_addr.s_addr); 741 | 742 | /* set remaining limbs to zero */ 743 | addrptr->words[1] = addrptr->words[2] = addrptr->words[3] = 0; 744 | 745 | } 746 | else { /* unsupported family or invalid struct */ 747 | die; 748 | } 749 | return IP_OK; 750 | } 751 | 752 | /**************************************************************************/ 753 | /*+converts the IP binary address (binaddr) to a string (ascaddr) 754 | of at most strmax characters. Independent of the result 755 | (success or failure) it messes up the string. 756 | +*/ 757 | er_ret_t 758 | IP_addr_b2a( ip_addr_t *binaddr, char *ascaddr, int strmax ) 759 | { 760 | 761 | if(binaddr->space == IP_V4) { 762 | if (snprintf(ascaddr, strmax, "%d.%d.%d.%d", 763 | ((binaddr->words[0]) & ((unsigned)0xff<<24))>>24, 764 | ((binaddr->words[0]) & (0xff<<16))>>16, 765 | ((binaddr->words[0]) & (0xff<<8))>>8, 766 | ((binaddr->words[0]) & (0xff<<0))>>0 767 | ) >= strmax) { 768 | /*die; */ /* string too short */ 769 | return IP_TOSHRT; 770 | } 771 | } 772 | else { 773 | /* IPv6 */ 774 | 775 | if( inet_ntop(AF_INET6, &(binaddr->words[0]), ascaddr, strmax) 776 | == NULL ) { 777 | return IP_TOSHRT; 778 | } 779 | 780 | /* not yet implemented. Sorry. */ 781 | /* die; */ 782 | /*return IP_NO6YET;*/ 783 | } 784 | return IP_OK; 785 | } 786 | 787 | /**************************************************************************/ 788 | 789 | /*+ convert a binary prefix back into ascii string at most strmax chars long 790 | +*/ 791 | er_ret_t 792 | IP_pref_b2a(ip_prefix_t *prefptr, char *ascaddr, int strmax) 793 | { 794 | int strl; 795 | er_ret_t err; 796 | 797 | if( (err=IP_addr_b2a (&(prefptr->ip), ascaddr, strmax)) != IP_OK) { 798 | /*die; */ /* what the hell */ 799 | return err; 800 | } 801 | strl = strlen(ascaddr); 802 | strmax -= strl; 803 | 804 | /* now strmax holds the space that is left */ 805 | 806 | if( snprintf(ascaddr+strl, strmax, "/%d", prefptr->bits) >= strmax) { 807 | /* die; */ /* error: string too short */ 808 | return IP_TOSHRT; 809 | } 810 | return IP_OK; 811 | } 812 | 813 | 814 | 815 | /**************************************************************************/ 816 | /*+ convert a binary range back into ascii string at most strmax chars long 817 | +*/ 818 | er_ret_t 819 | IP_rang_b2a(ip_range_t *rangptr, char *ascaddr, int strmax) 820 | { 821 | int strl=0, strleft; 822 | er_ret_t err; 823 | 824 | strleft = strmax - strl; 825 | if( (err=IP_addr_b2a (&(rangptr->begin), ascaddr, strleft)) != IP_OK) { 826 | return err; 827 | } 828 | strl = strlen(ascaddr); 829 | 830 | strleft = strmax - strl; 831 | if( strleft < 5 ) { 832 | return IP_TOSHRT; 833 | } 834 | strcat( ascaddr, " - " ); 835 | strl += 3; 836 | 837 | strleft = strmax - strl; 838 | if( (err=IP_addr_b2a (&(rangptr->end), ascaddr+strl, strleft)) != IP_OK) { 839 | return err; 840 | } 841 | 842 | return IP_OK; 843 | } 844 | 845 | /**************************************************************************/ 846 | /*+ return the bitnum bit of the address, 847 | COUNTING FROM THE TOP !!!!! , 848 | starting with 0 for the *most significant bit*. 849 | +*/ 850 | int 851 | IP_addr_bit_get(ip_addr_t *binaddr, int bitnum) { 852 | int bitval; 853 | int w,c; 854 | 855 | /* avoid unnecessary division */ 856 | if( binaddr->space == IP_V4 ) { 857 | w = 0; 858 | c = bitnum; 859 | } 860 | else { 861 | w = bitnum / 32; 862 | c = bitnum % 32; 863 | } 864 | 865 | bitval = (binaddr->words[w] & (0x80000000 >> (c))); 866 | 867 | return (bitval != 0); 868 | 869 | } 870 | 871 | /**************************************************************************/ 872 | /*+ set the bitnum bit of the address to bitval, 873 | COUNTING FROM THE TOP !!!!! , 874 | starting with 0 for the *most significant bit*. 875 | +*/ 876 | void 877 | IP_addr_bit_set(ip_addr_t *binaddr, int bitnum, int bitval) { 878 | int w,c; 879 | 880 | /* avoid unnecessary division */ 881 | if( binaddr->space == IP_V4 ) { 882 | w = 0; 883 | c = bitnum; 884 | } 885 | else { 886 | w = bitnum / 32; 887 | c = bitnum % 32; 888 | } 889 | 890 | if ( bitval == 1 ) 891 | 892 | binaddr->words[w] |= (0x80000000 >> (c)); 893 | else 894 | binaddr->words[w] &= ~(0x80000000 >> (c)); 895 | } 896 | /**************************************************************************/ 897 | 898 | /*+ this fixes a prefix by setting insignificant bits to 0 +*/ 899 | void 900 | IP_pref_bit_fix( ip_prefix_t *prefix ) 901 | { 902 | 903 | if( prefix->ip.space == IP_V4 ) { 904 | ip_limb_t mask = 0xffffffff; 905 | 906 | /* shorthand for ipv4 */ 907 | 908 | /* Shifting out by 32 bits does NOT turn all bits into 0... */ 909 | if( prefix->bits < 32 ) { 910 | prefix->ip.words[0] &= ~(mask >> prefix->bits); 911 | } 912 | } 913 | else { 914 | int i; 915 | for(i=prefix->bits; i < IP_sizebits(prefix->ip.space) ; i++) { 916 | IP_addr_bit_set( & prefix->ip, i, 0); 917 | } 918 | } 919 | } 920 | 921 | 922 | /**************************************************************************/ 923 | 924 | /*+ compares two IP addresses up to the bit # len, 925 | returns 0 if equal, 1 if ptra greater, -1 if ptrb greater. 926 | 927 | It is the responsility of the caller to ensure that both addresses 928 | are from the same IP space. 929 | 930 | This is pretty slow; it is used in the searches of the radix tree, 931 | so it might be good to optimise this. 932 | +*/ 933 | 934 | int 935 | IP_addr_cmp(ip_addr_t *ptra, ip_addr_t *ptrb, int len) 936 | { 937 | int a,b,i; 938 | 939 | for(i=0; i<len; i++) { 940 | a=IP_addr_bit_get(ptra, i); 941 | b=IP_addr_bit_get(ptrb, i); 942 | if( a != b ) { 943 | if( a > b ) return 1; 944 | else return -1; 945 | } 946 | } 947 | return 0; 948 | } 949 | 950 | 951 | /*+ checks if an IP address is contained within the prefix 952 | returns 1 if it is, 0 otherwise 953 | 954 | It is the responsility of the caller to ensure that both address 955 | and prefix are from the same IP space. 956 | +*/ 957 | int 958 | IP_addr_in_pref(ip_addr_t *ptra, ip_prefix_t *prefix) 959 | { 960 | return (IP_addr_cmp( ptra, & prefix->ip, prefix->bits) == 0); 961 | } 962 | 963 | /*+ checks if an IP address is contained within the range 964 | returns 1 if it is, 0 otherwise 965 | 966 | It is the responsility of the caller to ensure that both address 967 | and range are from the same IP space. 968 | 969 | works only for IPv4 970 | +*/ 971 | 972 | int IP_addr_in_rang(ip_addr_t *ptra, ip_range_t *rangptr) 973 | { 974 | /* if( rangptr->end.space == IP_V4 ) { 975 | return ( rangptr->begin.words[0] <= ptra->words[0] 976 | && rangptr->end.words[0] >= ptra->words[0] ); 977 | } 978 | else { 979 | */ 980 | return( IP_addr_cmp(ptra, &rangptr->begin, 981 | IP_sizebits(rangptr->end.space)) >= 0 /* adr >= begin */ 982 | && IP_addr_cmp(ptra, &rangptr->end, 983 | IP_sizebits(rangptr->end.space)) <= 0 /* adr <= end */ 984 | ); 985 | /* }*/ 986 | } 987 | 988 | /**************************************************************************/ 989 | 990 | /*+ calculate the span of a range == size - 1 +*/ 991 | 992 | ip_rangesize_t 993 | IP_rang_span( ip_range_t *rangptr ) 994 | { 995 | /* IPv4: */ 996 | dieif( rangptr->end.space != IP_V4 ); 997 | 998 | return rangptr->end.words[0] - rangptr->begin.words[0]; 999 | } 1000 | 1001 | 1002 | /**************************************************************************/ 1003 | 1004 | /*+ 1005 | this is a shorthand notation to pull out the first word of the address. 1006 | it is defined for the scope od the following functions 1007 | +*/ 1008 | #define ad(which) (rangptr->which) 1009 | 1010 | /**************************************************************************/ 1011 | /*+ Decomposes a binary range into prefixes and appends them to the list. 1012 | Allocates prefix structures and list elements, they must be freed 1013 | after use. 1014 | 1015 | returns a bitmask of prefix lengths used. 1016 | +*/ 1017 | unsigned 1018 | IP_rang_decomp(ip_range_t *rangptr, GList **preflist) 1019 | { 1020 | unsigned prefmask=0; 1021 | register int slash=0; 1022 | register unsigned c_dif, blk, ff; 1023 | ip_range_t workrange; 1024 | ip_addr_t workbegin; 1025 | ip_addr_t workend; 1026 | ip_prefix_t *prefptr; 1027 | 1028 | dieif( rangptr->begin.space != IP_V4 ); 1029 | 1030 | if( ad(begin).words[0] > ad(end).words[0] ) { /* has gone too far */ 1031 | return 0; 1032 | } 1033 | 1034 | if( ad(begin).words[0] == ad(end).words[0] ) { /* an IP == a /32 (IPv4) */ 1035 | prefmask |= 1; 1036 | if( wr_calloc( (void **)& prefptr, sizeof(ip_prefix_t), 1) != UT_OK) { 1037 | die; 1038 | } 1039 | prefptr->ip = ad(begin); 1040 | prefptr->bits = 32; 1041 | 1042 | *preflist = g_list_append( *preflist, prefptr ); 1043 | 1044 | return prefmask; 1045 | } 1046 | 1047 | c_dif = ad(end).words[0] - ad(begin).words[0]; 1048 | 1049 | /* initialize work vars */ 1050 | 1051 | workbegin = ad(begin); 1052 | workend = ad(end); 1053 | 1054 | /* now find the biggest block fitting in this range */ 1055 | /* i.e. the first 2^n number smaller than c_dif */ 1056 | 1057 | /* the loop would not work for /0 (some stupid queries may have that) */ 1058 | /* so this must be checked for separately */ 1059 | 1060 | if( c_dif == 0xffffffff ) { 1061 | /* they are already set to 0.0.0.0 - 255.255.255.255 */ 1062 | /* leave them alone. */ 1063 | blk = 0; 1064 | slash = 0; 1065 | } 1066 | else { 1067 | 1068 | c_dif += 1; /* was not done earlier to protect from overflow */ 1069 | 1070 | for(slash=1; 1071 | slash<32 && ((blk=((unsigned)0x80000000>>(slash-1))) & c_dif) == 0; 1072 | slash++) {} 1073 | 1074 | /* clear all digits in a and b under the blk one. */ 1075 | ff=blk-1; 1076 | 1077 | workbegin.words[0] = (workbegin.words[0] + ff) & ~ff; 1078 | 1079 | workend.words[0] = (workend.words[0] + 1) & ~ff; 1080 | } 1081 | 1082 | if( workbegin.words[0] != workend.words[0] ) { 1083 | prefmask |= blk; 1084 | if( wr_malloc( (void **)& prefptr, sizeof(ip_prefix_t)) != UT_OK) { 1085 | die; 1086 | } 1087 | prefptr->ip = workbegin; 1088 | prefptr->bits = slash; 1089 | 1090 | *preflist = g_list_append( *preflist, prefptr ); 1091 | } 1092 | 1093 | if( ad(begin).words[0] != workbegin.words[0] ) { 1094 | workrange.begin = ad(begin); 1095 | 1096 | workbegin.words[0] -= 1; 1097 | workrange.end = workbegin; 1098 | 1099 | prefmask |= IP_rang_decomp( &workrange, preflist ); 1100 | } 1101 | 1102 | /* here we must protect from decomposition of 1103 | * 255.255.255.255 - 255.255.255.255 in case the range 1104 | * 0.0.0.0 - 255.255.255.255 is considered. Hence the slash>0 condition. 1105 | */ 1106 | 1107 | if( workend.words[0] <= ad(end).words[0] && slash > 0) { 1108 | workrange.begin = workend; 1109 | workrange.end = ad(end); 1110 | 1111 | prefmask |= IP_rang_decomp( &workrange, preflist ); 1112 | } 1113 | 1114 | return prefmask; 1115 | 1116 | } 1117 | 1118 | 1119 | /***************************************************************************/ 1120 | 1121 | /*+ Similar name, slightly different code, totally different functionality. 1122 | 1123 | finds the smallest canonical block encompassing the whole given range, 1124 | then MODIFIES the range pointed to by the argument 1125 | so that it's equal to this block. 1126 | 1127 | +*/ 1128 | 1129 | void IP_rang_encomp(ip_range_t *rangptr) 1130 | { 1131 | int slash=0; 1132 | unsigned c_dif, blk, ff, t_dif; 1133 | ip_addr_t workbegin; 1134 | ip_addr_t workend; 1135 | 1136 | dieif( rangptr->begin.space != IP_V4 ); 1137 | 1138 | c_dif = ad(end).words[0] - ad(begin).words[0]; 1139 | 1140 | /* now find the biggest block fitting in this range */ 1141 | /* i.e. the first 2^n number smaller than c_dif */ 1142 | 1143 | /* the loop would not work for /0 (some stupid queries may have that) */ 1144 | /* so this must be checked for separately */ 1145 | 1146 | if( c_dif > 0x80000000 ) { 1147 | slash = 0; 1148 | ff = 0xffffffff; 1149 | blk = 0; 1150 | 1151 | workbegin = workend = ad(begin); 1152 | workbegin.words[0] = 0; 1153 | workend.words[0] = ff; 1154 | } 1155 | else { 1156 | 1157 | do { 1158 | c_dif += 1; 1159 | 1160 | /* find the smallest block ENCOMPASSING c_dif. */ 1161 | /* this implies a loop from the bottom up */ 1162 | 1163 | for(slash=32; 1164 | slash>1 && (blk=((unsigned)0x80000000>>(slash-1))) < c_dif; 1165 | slash--) {} 1166 | 1167 | ff=blk-1; 1168 | 1169 | /* clear all digits in workbegin under the blk one. */ 1170 | 1171 | workbegin = ad(begin); 1172 | workbegin.words[0] = workbegin.words[0] & ~ff; 1173 | 1174 | /* see if it has not made the difference larger than blk, */ 1175 | /* retry if so */ 1176 | 1177 | t_dif = c_dif; 1178 | c_dif = ad(end).words[0] - workbegin.words[0]; 1179 | 1180 | } while( c_dif >= t_dif ); 1181 | 1182 | /* set the endpoint to workbegin + blocksize - 1 */ 1183 | /* which amounts to + ff */ 1184 | 1185 | workend = ad(begin); 1186 | workend.words[0] = workbegin.words[0] + ff; 1187 | } 1188 | 1189 | 1190 | /* set the range to new values */ 1191 | 1192 | rangptr->begin = workbegin; 1193 | rangptr->end = workend; 1194 | } 1195 | 1196 | /***************************************************************************/ 1197 | /*+ sets a range equal to a prefix +*/ 1198 | 1199 | er_ret_t 1200 | IP_pref_2_rang( ip_range_t *rangptr, ip_prefix_t *prefptr ) 1201 | { 1202 | int shift; 1203 | int i; 1204 | 1205 | ad(begin) = ad(end) = prefptr->ip; 1206 | 1207 | /* IPv6 is a bit more complicated, as four words are involved */ 1208 | 1209 | /* additional problem: shifting right by >=32 is equal to shifting by 0, 1210 | so it does not change any bits */ 1211 | /* solution: don't touch those words */ 1212 | 1213 | for(i=0; i<4; i++) { 1214 | 1215 | if( prefptr->bits < 32*(1+i) ) { 1216 | shift = prefptr->bits < 32 + (i-1) * 32 1217 | ? 0 : (prefptr->bits % 32) ; 1218 | ad(end).words[i] |= (0xffffffffU >> shift); 1219 | } 1220 | 1221 | if( prefptr->ip.space == IP_V4) { 1222 | break; /* do only first word for IPv4 */ 1223 | } 1224 | } 1225 | return IP_OK; 1226 | } 1227 | 1228 | #undef ad 1229 | 1230 | /***************************************************************************/ 1231 | 1232 | /*+ 1233 | This is to parse a classfull address into a range. 1234 | 1235 | Takes the address by pointer from addrptr and puts the result 1236 | at rangptr. 1237 | 1238 | Throws error if the address does not fall into any of the 1239 | classfull categories 1240 | 1241 | +*/ 1242 | 1243 | er_ret_t 1244 | IP_rang_classful( ip_range_t *rangptr, ip_addr_t *addrptr) 1245 | { 1246 | int i; 1247 | unsigned b[4]; 1248 | 1249 | if( addrptr->space != IP_V4 ) { 1250 | /* it's IPv6. There are no classful ranges or anything like that. */ 1251 | die; 1252 | } 1253 | 1254 | rangptr->begin = *addrptr; 1255 | rangptr->end.space = IP_V4; 1256 | 1257 | /* initisalise end to zero */ 1258 | for(i=0; i<IPLIMBNUM; i++) { 1259 | rangptr->end.words[i] = 0; 1260 | } 1261 | 1262 | /* assume it's at least a valid IP. let's try different classes now */ 1263 | 1264 | /* we could have used a union here, but it would not work on */ 1265 | /* low endians. So byte by byte copying to and from an array. */ 1266 | 1267 | for(i=0; i<4; i++) { 1268 | b[i] = ( rangptr->begin.words[0] & (0xFF << i*8) ) >> i*8; 1269 | } 1270 | 1271 | if( b[3] >= 1 && b[3] < 128 1272 | && b[2] == 0 && b[1] == 0 && b[0] == 0 ) { 1273 | b[2]=b[1]=b[0]=255; 1274 | } 1275 | else if( b[3] >= 128 && b[3] < 192 1276 | && b[1] == 0 && b[0] == 0 ) { 1277 | b[1]=b[0]=255; 1278 | } 1279 | else if( b[3] >= 192 && b[3] < 224 1280 | && b[0] == 0 ) { 1281 | b[0]=255; 1282 | } 1283 | else if( b[3] >= 224 && b[3] < 255 ) { 1284 | /* just leave it, make it a /32, i.e. begin == end */ 1285 | /* EMPTY */; 1286 | } 1287 | else { 1288 | /* Leave it and make it a /32 */ 1289 | /* This is AGAINST the rule! but we have some junk */ 1290 | /* so we have to compensate for it. */ 1291 | /* EMPTY */; 1292 | } 1293 | 1294 | /* copy the (now - modified) bytes into the end of range */ 1295 | for(i=0; i<4; i++) { 1296 | rangptr->end.words[0] |= (b[i] << i*8); 1297 | } 1298 | 1299 | return IP_OK; 1300 | } 1301 | 1302 | 1303 | /***************************************************************************/ 1304 | /*+ 1305 | Trying to be smart :-) and convert a query search term into prefix(es), 1306 | regardless of whether specified as IP address, prefix or range. 1307 | 1308 | justcheck - if just checking the syntax (justcheck == 1), 1309 | then the prefixes are freed before the function returns, 1310 | otherwise it is the responsibility of the caller to free the list. 1311 | 1312 | +*/ 1313 | 1314 | er_ret_t 1315 | IP_smart_conv(char *key, 1316 | int justcheck, 1317 | int encomp, 1318 | GList **preflist, 1319 | ip_exp_t expf, 1320 | ip_keytype_t *keytype 1321 | ) 1322 | { 1323 | int free_it; 1324 | er_ret_t call_err, err=IP_OK; /* let's be optimistic :-) */ 1325 | ip_prefix_t *querypref; 1326 | 1327 | /* if just checking the syntax (justcheck == 1), 1328 | then free_it = 1, 1329 | else 0, but may be modified later (in range conversion) 1330 | */ 1331 | 1332 | free_it = justcheck; 1333 | 1334 | if( (call_err = wr_malloc( (void **) &querypref, sizeof(ip_prefix_t))) 1335 | != UT_OK) { 1336 | return call_err; 1337 | } 1338 | 1339 | if( IP_pref_t2b(querypref, key, expf) == IP_OK ) { 1340 | *keytype = IPK_PREFIX; 1341 | 1342 | if( justcheck == 0) { 1343 | *preflist = g_list_append(*preflist, querypref); 1344 | } 1345 | } 1346 | else { 1347 | /* not a prefix. */ 1348 | /* Maybe an IP ? */ 1349 | if( IP_addr_t2b( &(querypref->ip), key, expf) == IP_OK ) { 1350 | 1351 | *keytype = IPK_IP; 1352 | 1353 | /*convert to a /32 or /128*/ 1354 | querypref->bits = IP_sizebits(querypref->ip.space); 1355 | 1356 | if( justcheck == 0) { 1357 | *preflist = g_list_append(*preflist, querypref); 1358 | } 1359 | } 1360 | else { 1361 | /* hm, maybe a range then ? */ 1362 | ip_range_t myrang; 1363 | 1364 | /* won't use the querypref anymore, mark it for freeing later */ 1365 | free_it = 1; 1366 | 1367 | if( IP_rang_t2b(&myrang, key, expf) == IP_OK ) { 1368 | /* Wow. Great. */ 1369 | 1370 | *keytype = IPK_RANGE; 1371 | 1372 | /* sometimes (exless match) we look for the first bigger(shorter) */ 1373 | /* prefix containing this range. */ 1374 | 1375 | if( encomp ) { 1376 | IP_rang_encomp(&myrang); 1377 | } 1378 | /* OK, now we can let the engine happily find that there's just one */ 1379 | /* prefix in range */ 1380 | 1381 | if( justcheck == 0) { 1382 | IP_rang_decomp(&myrang, preflist); 1383 | } 1384 | } 1385 | else { 1386 | *keytype = IPK_UNDEF; 1387 | err = IP_INVARG; /* "conversion error" */ 1388 | } 1389 | } 1390 | } 1391 | 1392 | if( free_it ) { 1393 | wr_free(querypref); 1394 | } 1395 | 1396 | return err; 1397 | } 1398 | 1399 | 1400 | /* convert whatever comes into a range */ 1401 | er_ret_t 1402 | IP_smart_range(char *key, 1403 | ip_range_t *rangptr, 1404 | ip_exp_t expf, 1405 | ip_keytype_t *keytype 1406 | ) 1407 | { 1408 | er_ret_t err=IP_OK; 1409 | GList *preflist = NULL; 1410 | 1411 | /* first : is it a range ? */ 1412 | 1413 | if( (err = IP_rang_t2b(rangptr, key, expf)) == IP_OK ) { 1414 | *keytype = IPK_RANGE; 1415 | } 1416 | else { 1417 | /* OK, this must be possible to convert it to prefix and from there 1418 | to a range. */ 1419 | if( (err = IP_smart_conv(key, 0, 0, &preflist, expf, keytype)) 1420 | == IP_OK ) { 1421 | 1422 | dieif( g_list_length(preflist) != 1 ); 1423 | 1424 | dieif(IP_pref_2_rang( rangptr, g_list_first(preflist)->data ) != IP_OK ); 1425 | } 1426 | } 1427 | 1428 | wr_clear_list( &preflist ); 1429 | 1430 | return err; 1431 | } 1432 |