nfs-ganesha 1.4
|
00001 /* 00002 * cidr_from_str() - Generate a CIDR structure from a string in addr/len 00003 * form. 00004 */ 00005 #ifdef HAVE_CONFIG_H 00006 #include "config.h" 00007 #endif 00008 00009 #include <ctype.h> 00010 #include <errno.h> 00011 #include <stdio.h> /* I'm always stuffing debug printf's into here */ 00012 #include <stdlib.h> 00013 #include <string.h> 00014 #include <strings.h> 00015 00016 #include "../include/cidr.h" 00017 00018 CIDR * 00019 cidr_from_str(const char *addr) 00020 { 00021 size_t alen; 00022 CIDR *toret, *ctmp; 00023 const char *pfx, *buf; 00024 char *buf2; /* strtoul() can't use a (const char *) */ 00025 int i, j; 00026 int pflen; 00027 unsigned long octet; 00028 int nocts, eocts; 00029 short foundpf, foundmask, nsect; 00030 00031 /* There has to be *SOMETHING* to work with */ 00032 if(addr==NULL || (alen=strlen(addr))<1) 00033 { 00034 errno = EFAULT; 00035 return(NULL); 00036 } 00037 00038 /* And we know it can only contain a given set of chars */ 00039 buf = addr + strspn(addr, "0123456789abcdefABCDEFxX.:/in-rpt"); 00040 if(*buf!='\0') 00041 { 00042 errno = EINVAL; 00043 return(NULL); 00044 } 00045 00046 toret = cidr_alloc(); 00047 if(toret==NULL) 00048 return(NULL); /* Preserve errno */ 00049 00050 00051 /* First check if we're a PTR-style string */ 00052 /* 00053 * XXX This could be folded with *pfx; they aren't used in code paths 00054 * that overlap. I'm keeping them separate just to keep my sanity 00055 * though. 00056 */ 00057 buf = NULL; 00058 /* Handle the deprecated RFC1886 form of v6 PTR */ 00059 if(strcasecmp(addr+alen-8, ".ip6.int")==0) 00060 { 00061 toret->proto = CIDR_IPV6; 00062 buf = addr+alen-8; 00063 } 00064 00065 if(buf!=NULL || strcasecmp(addr+alen-5, ".arpa")==0) 00066 { 00067 /* 00068 * Do all this processing here, instead of trying to intermix it 00069 * with the rest of the formats. This might lead to some code 00070 * duplication, but it'll be easier to read. 00071 */ 00072 if(buf==NULL) /* If not set by .ip6.int above */ 00073 { 00074 /* First, see what protocol it is */ 00075 if(strncasecmp(addr+alen-9, ".ip6", 3)==0) 00076 { 00077 toret->proto = CIDR_IPV6; 00078 buf = addr+alen-9; 00079 } 00080 else if(strncasecmp(addr+alen-13, ".in-addr", 7)==0) 00081 { 00082 toret->proto = CIDR_IPV4; 00083 buf = addr+alen-13; 00084 } 00085 else 00086 { 00087 /* Unknown */ 00088 cidr_free(toret); 00089 errno = EINVAL; 00090 return(NULL); 00091 } 00092 } 00093 /* 00094 * buf now points to the period after the last (first) bit of 00095 * address numbering in the PTR name. 00096 */ 00097 00098 /* 00099 * Now convert based on that protocol. Note that we're going to 00100 * be slightly asymmetrical to the way cidr_to_str() works, in 00101 * how we handle the netmask. cidr_to_str() ignores it, and 00102 * treats the PTR-style output solely as host addresses. We'll 00103 * use the netmask bits to specify how much of the address is 00104 * given in the PTR we get. That is, if we get 00105 * "3.2.1.in-addr.arpa", we'll set a /24 netmask on the returned 00106 * result. This way, the calling program can tell the difference 00107 * between "3.2.1..." and "0.3.2.1..." if it really cares to. 00108 */ 00109 buf--; /* Step before the period */ 00110 if(toret->proto == CIDR_IPV4) 00111 { 00112 for(i=11 ; i<=14 ; /* */) 00113 { 00114 /* If we're before the beginning, we're done */ 00115 if(buf<addr) 00116 break; 00117 00118 /* Step backward until we at the start of an octet */ 00119 while(isdigit(*buf) && buf>=addr) 00120 buf--; 00121 00122 /* 00123 * Save that number (++i here to show that this octet is 00124 * now set. 00125 */ 00126 octet = strtoul(buf+1, NULL, 10); 00127 if(octet > (unsigned long)0xff) 00128 { 00129 /* Bad octet! No biscuit! */ 00130 cidr_free(toret); 00131 errno = EINVAL; 00132 return(NULL); 00133 } 00134 toret->addr[++i] = octet; 00135 00136 00137 /* 00138 * Back up a step to get before the '.', and process the 00139 * next [previous] octet. If we were at the beginning of 00140 * the string already, the test at the top of the loop 00141 * will drop us out. 00142 */ 00143 buf--; 00144 } 00145 00146 /* Too much? */ 00147 if(buf>=addr) 00148 { 00149 cidr_free(toret); 00150 errno = EINVAL; 00151 return(NULL); 00152 } 00153 00154 /* 00155 * Now, what about the mask? We set the netmask bits to 00156 * describe how much information we've actually gotten, if we 00157 * didn't get all 4 octets. Because of the way .in-addr.arpa 00158 * works, the mask can only fall on an octet boundary, so we 00159 * don't need too many fancy tricks. 'i' is still set from 00160 * the above loop to whatever the last octet we filled in is, 00161 * so we don't even have to special case anything. 00162 */ 00163 for(j=0 ; j<=i ; j++) 00164 toret->mask[j] = 0xff; 00165 00166 /* Done processing */ 00167 } 00168 else if(toret->proto == CIDR_IPV6) 00169 { 00170 /* 00171 * This processing happens somewhat similarly to IPV4 above, 00172 * the format is simplier, and we need to be a little 00173 * sneakier about the mask, since it can fall on a half-octet 00174 * boundary with .ip6.arpa format. 00175 */ 00176 for(i=0 ; i<=15 ; i++) 00177 { 00178 /* If we're before the beginning, we're done */ 00179 if(buf<addr) 00180 break; 00181 00182 /* We better point at a number */ 00183 if(!isxdigit(*buf)) 00184 { 00185 /* Bad input */ 00186 cidr_free(toret); 00187 errno = EINVAL; 00188 return(NULL); 00189 } 00190 00191 /* Save the current number */ 00192 octet = strtoul(buf, NULL, 16); 00193 if(octet > (unsigned long)0xff) 00194 { 00195 /* Bad octet! No biscuit! */ 00196 cidr_free(toret); 00197 errno = EINVAL; 00198 return(NULL); 00199 } 00200 toret->addr[i] = octet << 4; 00201 toret->mask[i] = 0xf0; 00202 00203 /* If we're at the beginning of the string, we're thru */ 00204 if(buf==addr) 00205 { 00206 /* Shift back to skip error condition at end of loop */ 00207 buf--; 00208 break; 00209 } 00210 00211 /* If we're not, stepping back should give us a period */ 00212 if(*--buf != '.') 00213 { 00214 /* Bad input */ 00215 cidr_free(toret); 00216 errno = EINVAL; 00217 return(NULL); 00218 } 00219 00220 /* Stepping back again should give us a number */ 00221 if(!isxdigit(*--buf)) 00222 { 00223 /* Bad input */ 00224 cidr_free(toret); 00225 errno = EINVAL; 00226 return(NULL); 00227 } 00228 00229 /* Save that one */ 00230 octet = strtoul(buf, NULL, 16); 00231 if(octet > (unsigned long)0xff) 00232 { 00233 /* Bad octet! No biscuit! */ 00234 cidr_free(toret); 00235 errno = EINVAL; 00236 return(NULL); 00237 } 00238 toret->addr[i] |= octet & 0x0f; 00239 toret->mask[i] |= 0x0f; 00240 00241 00242 /* 00243 * Step back and loop back around. If that last step 00244 * back moves us to before the beginning of the string, 00245 * the condition at the top of the loop will drop us out. 00246 */ 00247 while(*--buf=='.' && buf>=addr) 00248 /* nothing */; 00249 } 00250 00251 /* Too much? */ 00252 if(buf>=addr) 00253 { 00254 cidr_free(toret); 00255 errno = EINVAL; 00256 return(NULL); 00257 } 00258 00259 /* Mask is set in the loop for v6 */ 00260 } 00261 else 00262 { 00263 /* Shouldn't happen */ 00264 cidr_free(toret); 00265 errno = ENOENT; /* Bad choice of errno */ 00266 return(NULL); 00267 } 00268 00269 /* Return the value we built up, and we're done! */ 00270 return(toret); 00271 00272 /* NOTREACHED */ 00273 } 00274 buf=NULL; /* Done */ 00275 00276 00277 /* 00278 * It's not a PTR form, so find the '/' prefix marker if we can. We 00279 * support both prefix length and netmasks after the /, so flag if we 00280 * find a mask. 00281 */ 00282 foundpf=foundmask=0; 00283 for(i=alen-1 ; i>=0 ; i--) 00284 { 00285 /* Handle both possible forms of netmasks */ 00286 if(addr[i]=='.' || addr[i]==':') 00287 foundmask=1; 00288 00289 /* Are we at the beginning of the prefix? */ 00290 if(addr[i]=='/') 00291 { 00292 foundpf=1; 00293 break; 00294 } 00295 } 00296 00297 if(foundpf==0) 00298 { 00299 /* We didn't actually find a prefix, so reset the foundmask */ 00300 foundmask=0; 00301 00302 /* 00303 * pfx is only used if foundpf==1, but set it to NULL here to 00304 * quiet gcc down. 00305 */ 00306 pfx=NULL; 00307 } 00308 else 00309 { 00310 /* Remember where the prefix is */ 00311 pfx = addr+i; 00312 00313 if(foundmask==0) 00314 { 00315 /* 00316 * If we didn't find a netmask, it may be that it's one of 00317 * the v4 forms without dots. Technically, it COULD be 00318 * expressed as a single (32-bit) number that happens to be 00319 * between 0 and 32 inclusive, so there's no way to be 00320 * ABSOLUTELY sure when we have a prefix length and not a 00321 * netmask. But, that would be a non-contiguous netmask, 00322 * which we don't attempt to support, so we can probably 00323 * safely ignore that case. So try a few things... 00324 */ 00325 /* If it's a hex or octal number, assume it's a mask */ 00326 if(pfx[1]=='0' && tolower(pfx[2])=='x') 00327 foundmask=1; /* Hex */ 00328 else if(pfx[1]=='0') 00329 foundmask=1; /* Oct */ 00330 else if(isdigit(pfx[1])) 00331 { 00332 /* 00333 * If we get here, it looks like a decimal number, and we 00334 * know there aren't any periods or colons in it, so if 00335 * it's valid, it can ONLY be a single 32-bit decimal 00336 * spanning the whole 4-byte v4 address range. If that's 00337 * true, it's GOTTA be a valid number, it's GOTTA reach 00338 * to the end of the strong, and it's GOTTA be at least 00339 * 2**31 and less than 2**32. 00340 */ 00341 octet = strtoul(pfx+1, &buf2, 10); 00342 if(*buf2=='\0' && octet >= (unsigned long)(1<<31) 00343 && octet <= (unsigned long)0xffffffff) 00344 foundmask=1; /* Valid! */ 00345 00346 octet=0; buf2=NULL; /* Done */ 00347 } 00348 } 00349 } 00350 i=0; /* Done */ 00351 00352 00353 /* 00354 * Now, let's figure out what kind of address this is. A v6 address 00355 * will contain a : within the first 5 characters ('0000:'), a v4 00356 * address will have a . within the first 4 ('123.'), UNLESS it's 00357 * just a single number (in hex, octal, or decimal). Anything else 00358 * isn't an address we know anything about, so fail. 00359 */ 00360 if((buf = strchr(addr, ':'))!=NULL && (buf-addr)<=5) 00361 toret->proto = CIDR_IPV6; 00362 else if((buf = strchr(addr, '.'))!=NULL && (buf-addr)<=4) 00363 toret->proto = CIDR_IPV4; 00364 else 00365 { 00366 /* 00367 * Special v4 forms 00368 */ 00369 if(*addr=='0' && tolower(*(addr+1))=='x') 00370 { 00371 /* Hex? */ 00372 buf = (addr+2) + strspn(addr+2, "0123456789abcdefABCDEF"); 00373 if(*buf=='\0' || *buf=='/') 00374 toret->proto = CIDR_IPV4; /* Yep */ 00375 } 00376 else if(*addr=='0') 00377 { 00378 /* Oct? */ 00379 /* (note: this also catches the [decimal] address '0' */ 00380 buf = (addr+1) + strspn(addr+1, "01234567"); 00381 if(*buf=='\0' || *buf=='/') 00382 toret->proto = CIDR_IPV4; /* Yep */ 00383 } 00384 else 00385 { 00386 /* Dec? */ 00387 buf = (addr) + strspn(addr, "0123456789"); 00388 if(*buf=='\0' || *buf=='/') 00389 toret->proto = CIDR_IPV4; /* Yep */ 00390 } 00391 00392 /* Did we catch anything? */ 00393 if(toret->proto == 0) 00394 { 00395 /* Unknown */ 00396 cidr_free(toret); 00397 errno = EINVAL; 00398 return(NULL); 00399 } 00400 } 00401 buf=NULL; /* Done */ 00402 00403 00404 /* 00405 * So now we know what sort of address it is, we can go ahead and 00406 * have a parser for either. 00407 */ 00408 if(toret->proto==CIDR_IPV4) 00409 { 00410 /* 00411 * Parse a v4 address. Now, we're being a little tricksy here, 00412 * and parsing it from the end instead of from the front. 00413 */ 00414 00415 /* 00416 * First, find out how many bits we have. We need to have 4 or 00417 * less... 00418 */ 00419 buf = strchr(addr, '.'); 00420 /* Through here, nsect counts dots */ 00421 for(nsect=0 ; buf!=NULL && (pfx!=NULL?buf<pfx:1) ; buf=strchr(buf, '.')) 00422 { 00423 nsect++; /* One more section */ 00424 buf++; /* Move past . */ 00425 if(nsect>3) 00426 { 00427 /* Bad! We can't have more than 4 sections... */ 00428 cidr_free(toret); 00429 errno = EINVAL; 00430 return(NULL); 00431 } 00432 } 00433 buf=NULL; /* Done */ 00434 nsect++; /* sects = dots+1 */ 00435 00436 /* 00437 * First, initialize this so we can skip building the bits if we 00438 * don't have to. 00439 */ 00440 pflen=-1; 00441 00442 /* 00443 * Initialize the first 12 octets of the address/mask to look 00444 * like a v6-mapped address. This is the correct info for those 00445 * octets to have if/when we decide to use this v4 address as a 00446 * v6 one. 00447 */ 00448 for(i=0 ; i<=9 ; i++) 00449 toret->addr[i] = 0; 00450 for(i=10 ; i<=11 ; i++) 00451 toret->addr[i] = 0xff; 00452 for(i=0 ; i<=11 ; i++) 00453 toret->mask[i] = 0xff; 00454 00455 /* 00456 * Handle the prefix/netmask. If it's not set at all, slam it to 00457 * the maximum, and put us at the end of the string to start out. 00458 * Ditto if the '/' is the end of the string. 00459 */ 00460 if(foundpf==0) 00461 { 00462 pflen=32; 00463 i=alen-1; 00464 } 00465 else if(foundpf==1 && *(pfx+1)=='\0') 00466 { 00467 pflen=32; 00468 i=pfx-addr-1; 00469 } 00470 00471 /* 00472 * Or, if we found it, and it's a NETMASK, we need to parse it 00473 * just like an address. So, cheat a little and call ourself 00474 * recursively, and then just count the bits in our returned 00475 * address for the pflen. 00476 */ 00477 if(foundpf==1 && foundmask==1 && pflen==-1) 00478 { 00479 ctmp = cidr_from_str(pfx+1); 00480 if(ctmp==NULL) 00481 { 00482 /* This shouldn't happen */ 00483 cidr_free(toret); 00484 return(NULL); /* Preserve errno */ 00485 } 00486 /* Stick it in the mask */ 00487 for(i=0 ; i<=11 ; i++) 00488 ctmp->mask[i] = 0; 00489 for(i=12 ; i<=15 ; i++) 00490 ctmp->mask[i] = ctmp->addr[i]; 00491 00492 /* Get our prefix length */ 00493 pflen = cidr_get_pflen(ctmp); 00494 cidr_free(ctmp); 00495 if(pflen==-1) 00496 { 00497 /* Failed; probably non-contiguous */ 00498 cidr_free(toret); 00499 return(NULL); /* Preserve errno */ 00500 } 00501 00502 /* And set us to before the '/' like below */ 00503 i = pfx-addr-1; 00504 } 00505 00506 /* 00507 * Finally, if we did find it and it's a normal prefix length, 00508 * just pull it it, parse it out, and set ourselves to the first 00509 * character before the / for the address reading 00510 */ 00511 if(foundpf==1 && foundmask==0 && pflen==-1) 00512 { 00513 pflen = (int)strtol(pfx+1, NULL, 10); 00514 i = pfx-addr-1; 00515 } 00516 00517 00518 /* 00519 * If pflen is set, we need to turn it into a mask for the bits. 00520 * XXX pflen actually should ALWAYS be set, so we might not need 00521 * to make this conditional at all... 00522 */ 00523 if(pflen>0) 00524 { 00525 /* 0 < pflen <= 32 */ 00526 if(pflen<0 || pflen>32) 00527 { 00528 /* Always bad */ 00529 cidr_free(toret); 00530 errno = EINVAL; 00531 return(NULL); 00532 } 00533 00534 /* 00535 * Now pflen is in the 0...32 range and thus good. Set it in 00536 * the structure. Note that memset zero'd the whole thing to 00537 * start. We ignore mask[<12] with v4 addresses normally, 00538 * but they're already set to all-1 anyway, since if we ever 00539 * DO care about them, that's the most appropriate thing for 00540 * them to be. 00541 * 00542 * This is a horribly grody set of macros. I'm only using 00543 * them here to test them out before using them in the v6 00544 * section, where I'll need them more due to the sheer number 00545 * of clauses I'll have to get written. Here's the straight 00546 * code I had written that the macro should be writing for me 00547 * now: 00548 * 00549 * if(pflen>24) 00550 * for(j=24 ; j<pflen ; j++) 00551 * toret->mask[15] |= 1<<(31-j); 00552 * if(pflen>16) 00553 * for(j=16 ; j<pflen ; j++) 00554 * toret->mask[14] |= 1<<(23-j); 00555 * if(pflen>8) 00556 * for(j=8 ; j<pflen ; j++) 00557 * toret->mask[13] |= 1<<(15-j); 00558 * if(pflen>0) 00559 * for(j=0 ; j<pflen ; j++) 00560 * toret->mask[12] |= 1<<(7-j); 00561 */ 00562 #define UMIN(x,y) ((x)<(y)?(x):(y)) 00563 #define MASKNUM(x) (24-((15-x)*8)) 00564 #define WRMASKSET(x) \ 00565 if(pflen>MASKNUM(x)) \ 00566 for(j=MASKNUM(x) ; j<UMIN(pflen,MASKNUM(x)+8) ; j++) \ 00567 toret->mask[x] |= 1<<(MASKNUM(x)+7-j); 00568 00569 WRMASKSET(15); 00570 WRMASKSET(14); 00571 WRMASKSET(13); 00572 WRMASKSET(12); 00573 00574 #undef WRMASKET 00575 #undef MASKNUM 00576 #undef UMIN 00577 } /* Normal v4 prefix */ 00578 00579 00580 /* 00581 * Now we have 4 octets to grab. If any of 'em fail, or are 00582 * outside the 0...255 range, bomb. 00583 */ 00584 nocts = 0; 00585 00586 /* Here, i should be before the /, but we may have multiple */ 00587 while(i>0 && addr[i]=='/') 00588 i--; 00589 00590 for( /* i */ ; i>=0 ; i--) 00591 { 00592 /* 00593 * As long as it's still a number or an 'x' (as in '0x'), 00594 * keep backing up. Could be hex, so don't just use 00595 * isdigit(). 00596 */ 00597 if((isxdigit(addr[i]) || tolower(addr[i])=='x') && i>0) 00598 continue; 00599 00600 /* 00601 * It's no longer a number. So, grab the number we just 00602 * moved before. 00603 */ 00604 /* Cheat for "beginning-of-string" rather than "NaN" */ 00605 if(i==0) 00606 i--; 00607 /* Theoretically, this can be in hex/oct/dec... */ 00608 if(addr[i+1]=='0' && tolower(addr[i+2])=='x') 00609 octet = strtoul(addr+i+1, &buf2, 16); 00610 else if(addr[i+1] == '0') 00611 octet = strtoul(addr+i+1, &buf2, 8); 00612 else 00613 octet = strtoul(addr+i+1, &buf2, 10); 00614 00615 /* If buf isn't pointing at one of [./'\0'], it's screwed */ 00616 if(!(*buf2=='.' || *buf2=='/' || *buf2=='\0')) 00617 { 00618 cidr_free(toret); 00619 errno = EINVAL; 00620 return(NULL); 00621 } 00622 buf2=NULL; /* Done */ 00623 00624 /* 00625 * Now, because of the way compressed IPv4 addresses work, 00626 * this number CAN be greater than 255, IF it's the last bit 00627 * in the address (the first bit we parse), in which case it 00628 * must be no bigger than needed to fill the unaccounted-for 00629 * 'slots' in the address. 00630 * 00631 * See 00632 * <http://www.opengroup.org/onlinepubs/007908799/xns/inet_addr.html> 00633 * for details. 00634 */ 00635 if( octet<0 || (nocts!=0 && octet>255) 00636 || (nocts==0 && octet>(0xffffffff >> (8*(nsect-1)))) ) 00637 { 00638 cidr_free(toret); 00639 errno = EINVAL; 00640 return(NULL); 00641 } 00642 00643 /* Save the lower 8 bits into this octet */ 00644 toret->addr[15-nocts++] = octet & 0xff; 00645 00646 /* 00647 * If this is the 'last' piece of the address (the first we 00648 * process), and there are fewer than 4 pieces total, we need 00649 * to extend it out into additional fields. See above 00650 * reference. 00651 */ 00652 if(nocts==1) 00653 { 00654 if(nsect<=3) 00655 toret->addr[15-nocts++] = (octet >> 8) & 0xff; 00656 if(nsect<=2) 00657 toret->addr[15-nocts++] = (octet >> 16) & 0xff; 00658 if(nsect==1) 00659 toret->addr[15-nocts++] = (octet >> 24) & 0xff; 00660 } 00661 00662 /* 00663 * If we've got 4 of 'em, we're actually done. We got the 00664 * prefix above, so just return direct from here. 00665 */ 00666 if(nocts==4) 00667 return(toret); 00668 } 00669 00670 /* 00671 * If we get here, it failed to get all 4. That shouldn't 00672 * happen, since we catch proper abbreviated forms above. 00673 */ 00674 cidr_free(toret); 00675 errno = EINVAL; 00676 return(NULL); 00677 } 00678 else if(toret->proto==CIDR_IPV6) 00679 { 00680 /* 00681 * Parse a v6 address. Like the v4, we start from the end and 00682 * parse backward. However, to handle compressed form, if we hit 00683 * a ::, we drop off and start parsing from the beginning, 00684 * because at the end we'll then have a hole that is what the :: 00685 * is supposed to contain, which is already automagically 0 from 00686 * the memset() we did earlier. Neat! 00687 * 00688 * Initialize the prefix length 00689 */ 00690 pflen=-1; 00691 00692 /* If no prefix was found, assume the max */ 00693 if(foundpf==0) 00694 { 00695 pflen = 128; 00696 /* Stretch back to the end of the string */ 00697 i=alen-1; 00698 } 00699 else if(foundpf==1 && *(pfx+1)=='\0') 00700 { 00701 pflen = 128; 00702 i=pfx-addr-1; 00703 } 00704 00705 /* 00706 * If we got a netmask, rather than a prefix length, parse it and 00707 * count the bits, like we did for v4. 00708 */ 00709 if(foundpf==1 && foundmask==1 && pflen==-1) 00710 { 00711 ctmp = cidr_from_str(pfx+1); 00712 if(ctmp==NULL) 00713 { 00714 /* This shouldn't happen */ 00715 cidr_free(toret); 00716 return(NULL); /* Preserve errno */ 00717 } 00718 /* Stick it in the mask */ 00719 for(i=0 ; i<=15 ; i++) 00720 ctmp->mask[i] = ctmp->addr[i]; 00721 00722 /* Get the prefix length */ 00723 pflen = cidr_get_pflen(ctmp); 00724 cidr_free(ctmp); 00725 if(pflen==-1) 00726 { 00727 /* Failed; probably non-contiguous */ 00728 cidr_free(toret); 00729 return(NULL); /* Preserve errno */ 00730 } 00731 00732 /* And set us to before the '/' like below */ 00733 i = pfx-addr-1; 00734 } 00735 00736 /* Finally, the normal prefix case */ 00737 if(foundpf==1 && foundmask==0 && pflen==-1) 00738 { 00739 pflen = (int)strtol(pfx+1, NULL, 10); 00740 i = pfx-addr-1; 00741 } 00742 00743 00744 /* 00745 * Now, if we have a pflen, turn it into a mask. 00746 * XXX pflen actually should ALWAYS be set, so we might not need 00747 * to make this conditional at all... 00748 */ 00749 if(pflen>0) 00750 { 00751 /* Better be 0...128 */ 00752 if(pflen<0 || pflen>128) 00753 { 00754 /* Always bad */ 00755 cidr_free(toret); 00756 errno = EINVAL; 00757 return(NULL); 00758 } 00759 00760 /* 00761 * Now save the pflen. See comments on the similar code up in 00762 * the v4 section about the macros. 00763 */ 00764 #define UMIN(x,y) ((x)<(y)?(x):(y)) 00765 #define MASKNUM(x) (120-((15-x)*8)) 00766 #define WRMASKSET(x) \ 00767 if(pflen>MASKNUM(x)) \ 00768 for(j=MASKNUM(x) ; j<UMIN(pflen,MASKNUM(x)+8) ; j++) \ 00769 toret->mask[x] |= 1<<(MASKNUM(x)+7-j); 00770 00771 WRMASKSET(15); 00772 WRMASKSET(14); 00773 WRMASKSET(13); 00774 WRMASKSET(12); 00775 WRMASKSET(11); 00776 WRMASKSET(10); 00777 WRMASKSET(9); 00778 WRMASKSET(8); 00779 WRMASKSET(7); 00780 WRMASKSET(6); 00781 WRMASKSET(5); 00782 WRMASKSET(4); 00783 WRMASKSET(3); 00784 WRMASKSET(2); 00785 WRMASKSET(1); 00786 WRMASKSET(0); 00787 00788 #undef WRMASKET 00789 #undef MASKNUM 00790 #undef UMIN 00791 } 00792 00793 00794 /* 00795 * Now we have 16 octets to grab. If any of 'em fail, or are 00796 * outside the 0...0xff range, bomb. However, we MAY have a 00797 * v4-ish form, whether it's a formal v4 mapped/compat address, 00798 * or just a v4 address written in a v6 block. So, look for 00799 * .-separated octets, but there better be exactly 4 of them 00800 * before we hit a :. 00801 */ 00802 nocts = 0; 00803 00804 /* Bump before / (or multiple /'s */ 00805 while(i>0 && addr[i]=='/') 00806 i--; 00807 00808 for( /* i */ ; i>=0 ; i--) 00809 { 00810 /* 00811 * First, check the . cases, and handle them all in one 00812 * place. These can only happen at the beginning, when we 00813 * have no octets yet, and if it happens at all, we need to 00814 * have 4 of them. 00815 */ 00816 if(nocts==0 && addr[i]=='.') 00817 { 00818 i++; /* Shift back to after the '.' */ 00819 00820 for( /* i */ ; i>0 && nocts<4 ; i--) 00821 { 00822 /* This shouldn't happen except at the end */ 00823 if(addr[i]==':' && nocts<3) 00824 { 00825 cidr_free(toret); 00826 errno = EINVAL; 00827 return(NULL); 00828 } 00829 00830 /* If it's not a . or :, move back 1 */ 00831 if(addr[i]!='.' && addr[i]!=':') 00832 continue; 00833 00834 /* Should be a [decimal] octet right after here */ 00835 octet = strtoul(addr+i+1, NULL, 10); 00836 /* Be sure */ 00837 if(octet<0 || octet>255) 00838 { 00839 cidr_free(toret); 00840 errno = EINVAL; 00841 return(NULL); 00842 } 00843 00844 /* Save it */ 00845 toret->addr[15-nocts] = octet & 0xff; 00846 nocts++; 00847 00848 /* And find the next octet */ 00849 } 00850 00851 /* 00852 * At this point, 4 dotted-decimal octets should be 00853 * consumed. i has gone back one step past the : before 00854 * the decimal, so addr[i+1] should be the ':' that 00855 * preceeds them. Verify. 00856 */ 00857 if(nocts!=4 || addr[i+1]!=':') 00858 { 00859 cidr_free(toret); 00860 errno = EINVAL; 00861 return(NULL); 00862 } 00863 } 00864 00865 /* 00866 * Now we've either gotten 4 octets filled in from 00867 * dotted-decimal stuff, or we've filled in nothing and have 00868 * no dotted decimal. 00869 */ 00870 00871 00872 /* As long as it's not our separator, keep moving */ 00873 if(addr[i]!=':' && i>0) 00874 continue; 00875 00876 /* If it's a :, and our NEXT char is a : too, flee */ 00877 if(addr[i]==':' && addr[i+1]==':') 00878 { 00879 /* 00880 * If i is 0, we're already at the beginning of the 00881 * string, so we can just return; we've already filled in 00882 * everything but the leading 0's, which are already 00883 * zero-filled from the memory 00884 */ 00885 if(i==0) 00886 return(toret); 00887 00888 /* Else, i!=0, and we break out */ 00889 break; 00890 } 00891 00892 /* If it's not a number either... well, bad data */ 00893 if(!isxdigit(addr[i]) && addr[i]!=':' && i>0) 00894 { 00895 cidr_free(toret); 00896 errno = EINVAL; 00897 return(NULL); 00898 } 00899 00900 /* 00901 * It's no longer a number. So, grab the number we just 00902 * moved before. 00903 */ 00904 /* Cheat for "beginning-of-string" rather than "NaN" */ 00905 if(i==0) 00906 i--; 00907 octet = strtoul(addr+i+1, &buf2, 16); 00908 if(*buf2!=':' && *buf2!='/' && *buf2!='\0') 00909 { 00910 /* Got something unexpected */ 00911 cidr_free(toret); 00912 errno = EINVAL; 00913 return(NULL); 00914 } 00915 buf2=NULL; 00916 00917 /* Remember, this is TWO octets */ 00918 if(octet<0 || octet>0xffff) 00919 { 00920 cidr_free(toret); 00921 errno = EINVAL; 00922 return(NULL); 00923 } 00924 00925 /* Save it */ 00926 toret->addr[15-nocts] = octet & 0xff; 00927 nocts++; 00928 toret->addr[15-nocts] = (octet>>8) & 0xff; 00929 nocts++; 00930 00931 /* If we've got all of 'em, just return from here. */ 00932 if(nocts==16) 00933 return(toret); 00934 } 00935 00936 /* 00937 * Now, if i is >=0 and we've got two :'s, jump around to the 00938 * front of the string and start parsing inward. 00939 */ 00940 if(i>=0 && addr[i]==':' && addr[i+1]==':') 00941 { 00942 /* Remember how many octets we put on the end */ 00943 eocts = nocts; 00944 00945 /* Remember how far we were into the string */ 00946 j=i; 00947 00948 /* Going this way, we do things a little differently */ 00949 i=0; 00950 while(i<j) 00951 { 00952 /* 00953 * The first char better be a number. If it's not, bail 00954 * (a leading '::' was already handled in the loop above 00955 * by just returning). 00956 */ 00957 if(i==0 && !isxdigit(addr[i])) 00958 { 00959 cidr_free(toret); 00960 errno = EINVAL; 00961 return(NULL); 00962 } 00963 00964 /* 00965 * We should be pointing at the beginning of a digit 00966 * string now. Translate it into an octet. 00967 */ 00968 octet = strtoul(addr+i, &buf2, 16); 00969 if(*buf2!=':' && *buf2!='/' && *buf2!='\0') 00970 { 00971 /* Got something unexpected */ 00972 cidr_free(toret); 00973 errno = EINVAL; 00974 return(NULL); 00975 } 00976 buf2=NULL; 00977 00978 /* Sanity (again, 2 octets) */ 00979 if(octet<0 || octet>0xffff) 00980 { 00981 cidr_free(toret); 00982 errno = EINVAL; 00983 return(NULL); 00984 } 00985 00986 /* Save it */ 00987 toret->addr[nocts-eocts] = (octet>>8) & 0xff; 00988 nocts++; 00989 toret->addr[nocts-eocts] = octet & 0xff; 00990 nocts++; 00991 00992 /* 00993 * Discussion: If we're in this code block, it's because 00994 * we hit a ::-compression while parsing from the end 00995 * backward. So, if we hit 15 octets here, it's an 00996 * error, because with the at-least-2 that were minimized, 00997 * that makes 17 total, which is too many. So, error 00998 * out. 00999 */ 01000 if(nocts==15) 01001 { 01002 cidr_free(toret); 01003 return(NULL); 01004 } 01005 01006 /* Now skip around to the end of this number */ 01007 while(isxdigit(addr[i]) && i<j) 01008 i++; 01009 01010 /* 01011 * If i==j, we're back where we started. So we've filled 01012 * in all the leading stuff, and the struct is ready to 01013 * return. 01014 */ 01015 if(i==j) 01016 return(toret); 01017 01018 /* 01019 * Else, there's more to come. We better be pointing at 01020 * a ':', else die. 01021 */ 01022 if(addr[i]!=':') 01023 { 01024 cidr_free(toret); 01025 return(NULL); 01026 } 01027 01028 /* Skip past : */ 01029 i++; 01030 01031 /* If we're at j now, we had a ':::', which is invalid */ 01032 if(i==j) 01033 { 01034 cidr_free(toret); 01035 return(NULL); 01036 } 01037 01038 /* Head back around */ 01039 } 01040 } 01041 01042 /* If we get here, it failed somewhere odd */ 01043 cidr_free(toret); 01044 errno = EINVAL; 01045 return(NULL); 01046 } 01047 else 01048 { 01049 /* Shouldn't happen */ 01050 cidr_free(toret); 01051 errno = ENOENT; /* Bad choice of errno */ 01052 return(NULL); 01053 } 01054 01055 01056 /* NOTREACHED */ 01057 errno = ENOENT; 01058 return(NULL); 01059 }