nfs-ganesha 1.4

cidr_from_str.c

Go to the documentation of this file.
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 }