From: Frédéric Marchal Date: Mon, 20 Jun 2011 20:31:06 +0000 (+0000) Subject: Alias IP addresses in the URL using the CIDR notation X-Git-Tag: v2.3.2~47 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5207d9f81e80d712161de42a0057c3e45b442c87;p=thirdparty%2Fsarg.git Alias IP addresses in the URL using the CIDR notation Listing all the addresses in a range is tedious so the syntax is extended to support the CIDR notation. Only IPv4 are fully supported at the moment. --- diff --git a/include/defs.h b/include/defs.h index 8003ccc..5050800 100755 --- a/include/defs.h +++ b/include/defs.h @@ -278,3 +278,4 @@ void zdate(char *ftime,int ftimesize, const char *DateFormat); char *get_param_value(const char *param,char *line); int compar( const void *, const void * ); void unlinkdir(const char *dir,int contentonly); +int extract_address_mask(char *buf,char **text,unsigned char *ipv4,unsigned short int *ipv6,int *nbits,char **next); diff --git a/url.c b/url.c index 3c3d735..6de0abf 100644 --- a/url.c +++ b/url.c @@ -30,10 +30,10 @@ /*! A host name and the name to report. */ -struct hostalias +struct hostalias_name { //! The next host name in the list or NULL for the last item. - struct hostalias *Next; + struct hostalias_name *Next; //! The minimum length of a candidate host name. int MinLen; //! The length of the constant part at the beginning of the mask. @@ -48,72 +48,97 @@ struct hostalias const char *Alias; }; +/*! +An IPv4 address and the name to report. +*/ +struct hostalias_ipv4 +{ + //! The next host name in the list or NULL for the last item. + struct hostalias_ipv4 *Next; + //! The IP address. + unsigned char Ip[4]; + //! The number of bits in the prefix. + int NBits; + //! The replacement name. + const char *Alias; +}; + +/*! +An IPv6 address and the name to report. +*/ +struct hostalias_ipv6 +{ + //! The next host name in the list or NULL for the last item. + struct hostalias_ipv6 *Next; + //! The IP address. + unsigned short Ip[6]; + //! The number of bits in the prefix. + int NBits; + //! The replacement name. + const char *Alias; +}; + //! The first host name. -struct hostalias *FirstAlias=NULL; +static struct hostalias_name *FirstAliasName=NULL; +//! The first IPv4 address. +static struct hostalias_ipv4 *FirstAliasIpv4=NULL; +//! The first IPv§ address. +static struct hostalias_ipv6 *FirstAliasIpv6=NULL; /*! -Read the file containing the host names to alias in the report. + Store a name to alias. -\param Filename The name of the file. -*/ -void read_hostalias(const char *Filename) + \param name The name to match including the wildcard. + \param next A pointer to the first character after the name. + + \retval 1 Alias added. + \retval 0 Ignore the line. + \retval -1 Error. + */ +static int Alias_StoreName(char *name,char *next) { - FILE *fi; - longline line; - char *buf; - char *str; char *NameBegin; char *NameEnd; char *Replace; + char *str; + char sep; + struct hostalias_name *alias; + struct hostalias_name *new_alias; + struct hostalias_name *prev_alias; char *tmp; - struct hostalias *alias; - struct hostalias *prev_alias; - struct hostalias *new_alias; - int cmp; - if (debug) debuga(_("Reading host alias file \"%s\"\n"),Filename); - fi=fopen(Filename,"rt"); - if (!fi) { - debuga(_("Cannot read host name alias file \"%s\" - %s\n"),Filename,strerror(errno)); - exit(EXIT_FAILURE); - } - - if ((line=longline_create())==NULL) { - debuga(_("Not enough memory to read the host name aliases\n")); - exit(EXIT_FAILURE); - } + if (*name=='#' || *name==';') return(0); + sep=*next; + *next++='\0'; - prev_alias=NULL; - while ((buf=longline_read(fi,line)) != NULL) { - // get host name and split at the first wildcards - NameBegin=buf; - while (*NameBegin==' ' || *NameBegin=='\t') NameBegin++; - if ((unsigned char)*NameBegin<' ' || *NameBegin=='#' || *NameBegin==';') continue; - for (str=NameBegin ; *str && (unsigned char)*str>' ' && *str!='*' ; str++) - *str=tolower(*str); - if (*str=='*') { - *str++='\0'; - NameEnd=str; - while (*str && (unsigned char)*str>' ') { - if (*str=='*') { - debuga(_("Host name alias \"%s*%s\" contains too many wildcards (*) in \"%s\""),NameBegin,NameEnd,Filename); - exit(EXIT_FAILURE); - } - *str=tolower(*str); - str++; + // get host name and split at the wildcard + NameBegin=name; + for (str=NameBegin ; *str && (unsigned char)*str>' ' && *str!='*' ; str++) + *str=tolower(*str); + if (*str=='*') { + *str++='\0'; + NameEnd=str; + while (*str && (unsigned char)*str>' ') { + if (*str=='*') { + debuga(_("Host name alias \"%s*%s\" contains too many wildcards (*)"),NameBegin,NameEnd); + return(-1); } - } else - NameEnd=NULL; - while (*str && (unsigned char)*str<=' ') *str++='\0'; - if (NameEnd && NameEnd[0]=='\0') { - debuga(_("Host name alias \"%s\" must not end with a wildcard"),NameEnd); - exit(EXIT_FAILURE); + *str=tolower(*str); + str++; } - if (NameBegin[0]=='\0') NameBegin=NULL; - if (!NameBegin && !NameEnd) continue; + } else + NameEnd=NULL; + while (*str && (unsigned char)*str<=' ') *str++='\0'; + if (NameEnd && NameEnd[0]=='\0') { + debuga(_("Host name alias \"%s\" must not end with a wildcard"),NameEnd); + return(-1); + } + if (NameBegin[0]=='\0') NameBegin=NULL; + if (!NameBegin && !NameEnd) return(0); - // get the alias - Replace=str; + // get the alias + if (sep==' ' || sep=='\t') { + Replace=next; while (*Replace==' ' || *Replace=='\t') Replace++; if ((unsigned char)*Replace<' ') { Replace=NULL; @@ -121,93 +146,307 @@ void read_hostalias(const char *Filename) for (str=Replace ; *str && (unsigned char)*str>=' ' ; str++); *str='\0'; } + } else + Replace=NULL; - // ignore duplicates - cmp=1; - for (alias=FirstAlias ; alias ; alias=alias->Next) { - if (((NameBegin && alias->HostName_Prefix && !strcmp(NameBegin,alias->HostName_Prefix)) || (!NameBegin && !alias->HostName_Prefix)) && - ((NameEnd && alias->HostName_Suffix && !strcmp(NameEnd,alias->HostName_Suffix)) || (!NameEnd && !alias->HostName_Suffix))) { - cmp=0; - break; - } + // ignore duplicates + prev_alias=NULL; + for (alias=FirstAliasName ; alias ; alias=alias->Next) { + if (((NameBegin && alias->HostName_Prefix && !strcmp(NameBegin,alias->HostName_Prefix)) || (!NameBegin && !alias->HostName_Prefix)) && + ((NameEnd && alias->HostName_Suffix && !strcmp(NameEnd,alias->HostName_Suffix)) || (!NameEnd && !alias->HostName_Suffix))) { + return(0); } - if (!cmp) continue; + prev_alias=alias; + } - // insert into the list - new_alias=malloc(sizeof(*new_alias)); - if (!new_alias) { - debuga(_("Not enough memory to store the host name aliasing directives read in \"%s\""),Filename); - exit(EXIT_FAILURE); + // insert into the list + new_alias=malloc(sizeof(*new_alias)); + if (!new_alias) { + debuga(_("Not enough memory to store the host name aliasing directives")); + return(-1); + } + new_alias->MinLen=0; + if (NameBegin) { + new_alias->HostName_Prefix=strdup(NameBegin); + if (!new_alias->HostName_Prefix) { + debuga(_("Not enough memory to store the host name aliasing directives")); + return(-1); } - new_alias->MinLen=0; - if (NameBegin) { - new_alias->HostName_Prefix=strdup(NameBegin); - if (!new_alias->HostName_Prefix) { - debuga(_("Not enough memory to store the host name aliasing directives read in \"%s\""),Filename); - exit(EXIT_FAILURE); - } - new_alias->MinLen+=strlen(NameBegin); - new_alias->PrefixLen=strlen(NameBegin); - } else { - new_alias->HostName_Prefix=NULL; - new_alias->PrefixLen=0; + new_alias->MinLen+=strlen(NameBegin); + new_alias->PrefixLen=strlen(NameBegin); + } else { + new_alias->HostName_Prefix=NULL; + new_alias->PrefixLen=0; + } + if (NameEnd) { + new_alias->HostName_Suffix=strdup(NameEnd); + if (!new_alias->HostName_Suffix) { + debuga(_("Not enough memory to store the host name aliasing directives")); + return(-1); } - if (NameEnd) { - new_alias->HostName_Suffix=strdup(NameEnd); - if (!new_alias->HostName_Suffix) { - debuga(_("Not enough memory to store the host name aliasing directives read in \"%s\""),Filename); - exit(EXIT_FAILURE); - } - new_alias->MinLen+=strlen(NameEnd)+1; - new_alias->SuffixLen=strlen(NameEnd); - } else { - new_alias->HostName_Suffix=NULL; - new_alias->SuffixLen=0; + new_alias->MinLen+=strlen(NameEnd)+1; + new_alias->SuffixLen=strlen(NameEnd); + } else { + new_alias->HostName_Suffix=NULL; + new_alias->SuffixLen=0; + } + if (Replace) { + tmp=malloc(strlen(Replace)+2); + if (!tmp) { + debuga(_("Not enough memory to store the host name aliasing directives")); + return(-1); } - if (Replace) { - tmp=malloc(strlen(Replace)+2); - if (!tmp) { - debuga(_("Not enough memory to store the host name aliasing directives read in \"%s\""),Filename); - exit(EXIT_FAILURE); - } - tmp[0]=ALIAS_PREFIX; - strcpy(tmp+1,Replace); - new_alias->Alias=tmp; - } else { - tmp=malloc(new_alias->MinLen+2); - if (!tmp) { - debuga(_("Not enough memory to store the host name aliasing directives read in \"%s\""),Filename); - exit(EXIT_FAILURE); - } - tmp[0]=ALIAS_PREFIX; - if (new_alias->HostName_Prefix) strcpy(tmp+1,new_alias->HostName_Prefix); - if (new_alias->HostName_Suffix) { - tmp[new_alias->PrefixLen+1]='*'; - strcpy(tmp+new_alias->PrefixLen+2,new_alias->HostName_Suffix); - } - new_alias->Alias=tmp; + tmp[0]=ALIAS_PREFIX; + strcpy(tmp+1,Replace); + new_alias->Alias=tmp; + } else { + tmp=malloc(new_alias->MinLen+2); + if (!tmp) { + debuga(_("Not enough memory to store the host name aliasing directives")); + return(-1); + } + tmp[0]=ALIAS_PREFIX; + if (new_alias->HostName_Prefix) strcpy(tmp+1,new_alias->HostName_Prefix); + if (new_alias->HostName_Suffix) { + tmp[new_alias->PrefixLen+1]='*'; + strcpy(tmp+new_alias->PrefixLen+2,new_alias->HostName_Suffix); + } + new_alias->Alias=tmp; + } + + new_alias->Next=NULL; + if (prev_alias) + prev_alias->Next=new_alias; + else + FirstAliasName=new_alias; + return(1); +} + +/*! + Store a IPv4 to alias. + + \param ipv4 The IPv4 to match. + \param nbits The number of bits in the prefix + \param next A pointer to the first character after the address. + + \retval 1 Alias added. + \retval 0 Ignore the line. + \retval -1 Error. + */ +static int Alias_StoreIpv4(unsigned char *ipv4,int nbits,char *next) +{ + char *Replace; + char *str; + struct hostalias_ipv4 *alias; + struct hostalias_ipv4 *new_alias; + struct hostalias_ipv4 *prev_alias; + int i; + char *tmp; + + // get the alias + Replace=next; + while (*Replace==' ' || *Replace=='\t') Replace++; + if ((unsigned char)*Replace<' ') { + Replace=NULL; + } else { + for (str=Replace ; *str && (unsigned char)*str>=' ' ; str++); + *str='\0'; + } + + // store more restrictive range first + prev_alias=NULL; + for (alias=FirstAliasIpv4 ; alias ; alias=alias->Next) { + i=(nbitsNBits) ? nbits : alias->NBits; + if ((i<8 || memcmp(ipv4,alias->Ip,i/8)==0) && ((i%8)==0 || (ipv4[i/8] ^ alias->Ip[i/8]) & (0xFFU<<(8-i%8)))==0) { + break; + } + prev_alias=alias; + } + + // insert into the list + new_alias=malloc(sizeof(*new_alias)); + if (!new_alias) { + debuga(_("Not enough memory to store the host name aliasing directives")); + return(-1); + } + memcpy(new_alias->Ip,ipv4,4); + new_alias->NBits=nbits; + if (Replace) { + tmp=malloc(strlen(Replace)+2); + if (!tmp) { + debuga(_("Not enough memory to store the host name aliasing directives")); + return(-1); + } + tmp[0]=ALIAS_PREFIX; + strcpy(tmp+1,Replace); + new_alias->Alias=tmp; + } else { + tmp=malloc(5*4+1); + if (!tmp) { + debuga(_("Not enough memory to store the host name aliasing directives")); + return(-1); } + sprintf(tmp,"%c%d.%d.%d.%d/%d",ALIAS_PREFIX,ipv4[0],ipv4[1],ipv4[2],ipv4[3],nbits); + new_alias->Alias=tmp; + } + if (prev_alias) { + new_alias->Next=prev_alias->Next; + prev_alias->Next=new_alias; + } else { new_alias->Next=NULL; - if (prev_alias) - prev_alias->Next=new_alias; - else - FirstAlias=new_alias; - prev_alias=new_alias; + FirstAliasIpv4=new_alias; + } + return(1); +} + +/*! + Store a IPv6 to alias. + + \param ipv6 The IPv6 to match. + \param nbits The number of bits in the prefix + \param next A pointer to the first character after the address. + + \retval 1 Alias added. + \retval 0 Ignore the line. + \retval -1 Error. + */ +static int Alias_StoreIpv6(unsigned short *ipv6,int nbits,char *next) +{ + char *Replace; + char *str; + struct hostalias_ipv6 *alias; + struct hostalias_ipv6 *new_alias; + struct hostalias_ipv6 *prev_alias; + int i; + char *tmp; + + // get the alias + Replace=next; + while (*Replace==' ' || *Replace=='\t') Replace++; + if ((unsigned char)*Replace<' ') { + Replace=NULL; + } else { + for (str=Replace ; *str && (unsigned char)*str>=' ' ; str++); + *str='\0'; + } + + // store more restrictive range first + prev_alias=NULL; + for (alias=FirstAliasIpv6 ; alias ; alias=alias->Next) { + i=(nbitsNBits) ? nbits : alias->NBits; + if ((i<16 || memcmp(ipv6,alias->Ip,i/16*2)==0) && ((i%16)==0 || (ipv6[i/16] ^ alias->Ip[i/16]) & (0xFFFFU<<(16-i%16)))==0) { + break; + } + prev_alias=alias; + } + + // insert into the list + new_alias=malloc(sizeof(*new_alias)); + if (!new_alias) { + debuga(_("Not enough memory to store the host name aliasing directives")); + return(-1); + } + memcpy(new_alias->Ip,ipv6,8); + new_alias->NBits=nbits; + if (Replace) { + tmp=malloc(strlen(Replace)+2); + if (!tmp) { + debuga(_("Not enough memory to store the host name aliasing directives")); + return(-1); + } + tmp[0]=ALIAS_PREFIX; + strcpy(tmp+1,Replace); + new_alias->Alias=tmp; + } else { + tmp=malloc(5*4+1); + if (!tmp) { + debuga(_("Not enough memory to store the host name aliasing directives")); + return(-1); + } + sprintf(tmp,"%c%x:%x:%x:%x:%x:%x:%x:%x/%d",ALIAS_PREFIX,ipv6[0],ipv6[1],ipv6[2],ipv6[3],ipv6[4],ipv6[5],ipv6[6],ipv6[7],nbits); + new_alias->Alias=tmp; + } + + if (prev_alias) { + new_alias->Next=prev_alias->Next; + prev_alias->Next=new_alias; + } else { + new_alias->Next=NULL; + FirstAliasIpv6=new_alias; + } + return(1); +} + +/*! +Read the file containing the host names to alias in the report. + +\param Filename The name of the file. +*/ +void read_hostalias(const char *Filename) +{ + FILE *fi; + longline line; + char *buf; + int type; + char *name; + unsigned char ipv4[4]; + unsigned short int ipv6[8]; + int nbits; + char *next; + + if (debug) debuga(_("Reading host alias file \"%s\"\n"),Filename); + fi=fopen(Filename,"rt"); + if (!fi) { + debuga(_("Cannot read host name alias file \"%s\" - %s\n"),Filename,strerror(errno)); + exit(EXIT_FAILURE); + } + + if ((line=longline_create())==NULL) { + debuga(_("Not enough memory to read the host name aliases\n")); + exit(EXIT_FAILURE); + } + + while ((buf=longline_read(fi,line)) != NULL) { + + type=extract_address_mask(buf,&name,ipv4,ipv6,&nbits,&next); + if (type<0) { + debuga(_("While reading \"%s\""),Filename); + exit(EXIT_FAILURE); + } + + if (type==1) { + Alias_StoreName(name,next); + } else if (type==2) { + Alias_StoreIpv4(ipv4,nbits,next); + } else if (type==3) { + Alias_StoreIpv6(ipv6,nbits,next); + } } longline_destroy(&line); fclose(fi); if (debug) { + struct hostalias_name *alias1; + struct hostalias_ipv4 *alias4; + struct hostalias_ipv6 *alias6; + debuga(_("List of host names to alias:\n")); - for (alias=FirstAlias ; alias ; alias=alias->Next) { - if (alias->HostName_Prefix && alias->HostName_Suffix) - debuga(_(" %s*%s => %s\n"),alias->HostName_Prefix,alias->HostName_Suffix,alias->Alias); - else if (alias->HostName_Prefix) - debuga(_(" %s => %s\n"),alias->HostName_Prefix,alias->Alias); + for (alias1=FirstAliasName ; alias1 ; alias1=alias1->Next) { + if (alias1->HostName_Prefix && alias1->HostName_Suffix) + debuga(_(" %s*%s => %s\n"),alias1->HostName_Prefix,alias1->HostName_Suffix,alias1->Alias); + else if (alias1->HostName_Prefix) + debuga(_(" %s => %s\n"),alias1->HostName_Prefix,alias1->Alias); else - debuga(_(" *%s => %s\n"),alias->HostName_Suffix,alias->Alias); + debuga(_(" *%s => %s\n"),alias1->HostName_Suffix,alias1->Alias); + } + for (alias4=FirstAliasIpv4 ; alias4 ; alias4=alias4->Next) { + debuga(_(" %d.%d.%d.%d/%d => %s\n"),alias4->Ip[0],alias4->Ip[1],alias4->Ip[2],alias4->Ip[3],alias4->NBits,alias4->Alias); + } + for (alias6=FirstAliasIpv6 ; alias6 ; alias6=alias6->Next) { + debuga(_(" %x:%x:%x:%x:%x:%x:%x:%x/%d => %s\n"),alias6->Ip[0],alias6->Ip[1],alias6->Ip[2],alias6->Ip[3], + alias6->Ip[4],alias6->Ip[5],alias6->Ip[6],alias6->Ip[7],alias6->NBits,alias6->Alias); } } } @@ -217,33 +456,49 @@ Free the memory allocated by read_hostalias(). */ void free_hostalias(void) { - struct hostalias *alias; - struct hostalias *next; + struct hostalias_name *alias1; + struct hostalias_name *next1; + struct hostalias_ipv4 *alias4; + struct hostalias_ipv4 *next4; + struct hostalias_ipv6 *alias6; + struct hostalias_ipv6 *next6; - for (alias=FirstAlias ; alias ; alias=next) { - next=alias->Next; - if (alias->HostName_Prefix) free((void *)alias->HostName_Prefix); - if (alias->HostName_Suffix) free((void *)alias->HostName_Suffix); - free((void *)alias->Alias); - free(alias); + for (alias1=FirstAliasName ; alias1 ; alias1=next1) { + next1=alias1->Next; + if (alias1->HostName_Prefix) free((void *)alias1->HostName_Prefix); + if (alias1->HostName_Suffix) free((void *)alias1->HostName_Suffix); + free((void *)alias1->Alias); + free(alias1); + } + FirstAliasName=NULL; + for (alias4=FirstAliasIpv4 ; alias4 ; alias4=next4) { + next4=alias4->Next; + free((void *)alias4->Alias); + free(alias4); + } + FirstAliasIpv4=NULL; + for (alias6=FirstAliasIpv6 ; alias6 ; alias6=next6) { + next6=alias6->Next; + free((void *)alias6->Alias); + free(alias6); } - FirstAlias=NULL; + FirstAliasIpv6=NULL; } /*! Replace the host name by its alias if it is in our list. -\param host The host name. +\param url The host name. \return The pointer to the host name or its alias. */ -const char *alias_url(const char *url) +const char *alias_url_name(const char *url) { - struct hostalias *alias; + struct hostalias_name *alias; int len; len=strlen(url); - for (alias=FirstAlias ; alias ; alias=alias->Next) { + for (alias=FirstAliasName ; alias ; alias=alias->Next) { if (lenMinLen) continue; if (alias->HostName_Prefix) { if (alias->HostName_Suffix) { @@ -263,6 +518,28 @@ const char *alias_url(const char *url) return(url); } +/*! +Replace the IPv4 address by its alias if it is in our list. + +\param url The host name. +\param ipv4 The address. + +\return The pointer to the host name or its alias. +*/ +const char *alias_url_ipv4(const char *url,unsigned char *ipv4) +{ + struct hostalias_ipv4 *alias; + int len; + + for (alias=FirstAliasIpv4 ; alias ; alias=alias->Next) { + len=alias->NBits; + if ((len<8 || memcmp(ipv4,alias->Ip,len/8)==0) && ((len%8)==0 || (ipv4[len/8] ^ alias->Ip[len/8]) & (0xFFU<<(8-len%8)))==0) { + return(alias->Alias); + } + } + return(url); +} + /*! Get the part of the URL necessary to generate the report. @@ -274,6 +551,11 @@ const char *process_url(char *url,bool full_url) { char *str; const char *start; + int type; + char *address; + unsigned char ipv4[4]; + unsigned short int ipv6[8]; + char *next; /* Remove any scheme:// at the beginning of the URL (see rfc2396 section 3.1). @@ -289,8 +571,14 @@ const char *process_url(char *url,bool full_url) if (!full_url) { for (str=url ; *str && *str!='/' ; str++); if (*str=='/') *str='\0'; - if (FirstAlias) - start=alias_url(start); + type=extract_address_mask(url,&address,ipv4,ipv6,NULL,&next); + if (type==1) { + if (FirstAliasName) + start=alias_url_name(start); + } else if (type==2) { + if (FirstAliasIpv4) + start=alias_url_ipv4(start,ipv4); + } } return(start); } diff --git a/util.c b/util.c index 8bebb43..00d9206 100644 --- a/util.c +++ b/util.c @@ -1769,3 +1769,120 @@ void unlinkdir(const char *dir,int contentonly) } } +/*! + Extract an url, IPv4 or IPv6 from a buffer. The IP addresses may end with a + prefix size. + + \param buf The buffer to parse. + \param text A pointer to set to the beginning of the string pattern. No terminating zero is inserted. + \param ipv4 A 4 bytes buffer to store the bytes of the IPv4 address. + \param ipv6 A 8 short integers buffer to store the values of the IPv6 address. + \param nbits The number of prefix bits for an IP address. + \param next The content of the line after the extracted address. + + \retval 3 The pattern is a IPv6 address. + \retval 2 The pattern is a IPv4 address. + \retval 1 The patter is a string. + \retval 0 Empty pattern. + */ +int extract_address_mask(char *buf,char **text,unsigned char *ipv4,unsigned short int *ipv6,int *nbits,char **next) +{ + int i; + int j; + int ip_size; + unsigned int value4, value6; + unsigned short int addr[8]; + int addr_len; + int mask, max_mask; + int pad_pos; + int pad_len; + + // skip leading spaces and tabs + while (*buf && (*buf==' ' || *buf=='\t')) buf++; + + // find out the nature of the pattern + ip_size=0x60 | 0x04; + value4=0U; + value6=0U; + addr_len=0; + pad_pos=-1; + for (i=0 ; (unsigned char)buf[i]>' ' && buf[i]!='/' && ip_size ; i++) { + if (ip_size & 0x04) { + if (isdigit(buf[i])) { + value4=value4*10+(buf[i]-'0'); + if (value4>0xFFU) ip_size&=~0x04; + } else if (buf[i]=='.' && addr_len<4) { + addr[addr_len++]=(unsigned short)(value4 & 0xFFU); + value4=0U; + } else { + ip_size&=~0x04; + } + } + if (ip_size & 0x60) { + if (isdigit(buf[i])) { + value6=(value6<<4)+(buf[i]-'0'); + if (value6>0xFFFFU) ip_size&=~0x60; + } else if (toupper(buf[i])>='A' && toupper(buf[i])<='F') { + value6=(value6<<4)+(toupper(buf[i])-'A'+10); + if (value6>0xFFFFU) ip_size&=~0x60; + } else if (buf[i]==':' && addr_len<8) { + addr[addr_len++]=(unsigned short)(value6 & 0xFFFFU); + value6=0U; + if (buf[i+1]==':') pad_pos=addr_len++; + } else { + ip_size&=~0x60; + } + } + } + if (i==0) return(0); + if (ip_size & 0x04) { + if (addr_len!=3) + ip_size&=~0x04; + else + addr[addr_len++]=(unsigned short)(value4 & 0xFFU); + } + if (ip_size & 0x60) { + if (pad_pos<0 && addr_len!=7) { + ip_size&=~0x60; + } else if (pad_pos>=0 && addr_len>=7) + ip_size&=~0x60; + else + addr[addr_len++]=(unsigned short)(value6 & 0xFFFFU); + } + if (!ip_size) { + *text=buf; + while ((unsigned char)buf[i]>' ') i++; + *next=buf+i; + return(1); + } + max_mask=(ip_size & 0x04) ? 4*8 : 8*16; + if (buf[i]=='/') { + i++; + mask=atoi(buf+i); + while (isdigit(buf[i])) i++; + if (mask<0 || mask>max_mask) mask=max_mask; + } else + mask=max_mask; + *next=buf+i; + if (ip_size & 0x04) { + if (nbits) *nbits=mask; + for (i=0 ; i=0) { + while (i