From: Frédéric Marchal Date: Sat, 2 Jul 2011 19:49:43 +0000 (+0000) Subject: Exclude IPv6 hosts X-Git-Tag: v2.3.2~40 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=7819e0d5ccd2404be303719b74683de69abe837e;p=thirdparty%2Fsarg.git Exclude IPv6 hosts Host exclusion didn't support IPv6 addresses. This change add the possibility to exclude host identified by a IPv6 address in the log. The change required some extensive changes to the code to alias the host names as several strings had to be made constants. --- diff --git a/exclude.c b/exclude.c index f7b5573..a37edf9 100644 --- a/exclude.c +++ b/exclude.c @@ -35,6 +35,14 @@ struct hostip4struct unsigned long int mask; }; +struct hostip6struct +{ + //! The IP address. + unsigned short int address[8]; + //! The number of bits in the prefix. + int nbits; +}; + struct hostnamestruct { //! The URL to match without any leading wildcard. @@ -45,14 +53,23 @@ struct hostnamestruct static struct hostip4struct *exclude_ip4=NULL; static int num_exclude_ip4=0; +static struct hostip6struct *exclude_ip6=NULL; +static int num_exclude_ip6=0; static struct hostnamestruct *exclude_name=NULL; static int num_exclude_name=0; static int ip4allocated=0; +static int ip6allocated=0; static int nameallocated=0; static char *excludeuser=NULL; -static void store_exclude_ip4(unsigned short int *addr,int mask) +/*! + Store a IPv4 address to exclude from the reported URL. + + \param addr The 4 char of the address. + \param nbits The number of bits to keep in the prefix. + */ +static void store_exclude_ip4(unsigned char *addr,int nbits) { int i; @@ -70,20 +87,54 @@ static void store_exclude_ip4(unsigned short int *addr,int mask) exclude_ip4[num_exclude_ip4].address=0UL; for (i=0 ; i<4 ; i++) exclude_ip4[num_exclude_ip4].address=(exclude_ip4[num_exclude_ip4].address<<8) | (unsigned char)(addr[i] & 0xFFU); - exclude_ip4[num_exclude_ip4].mask=(0xFFFFFFFFUL << (32-mask)); + exclude_ip4[num_exclude_ip4].mask=(0xFFFFFFFFUL << (32-nbits)); num_exclude_ip4++; } -static void store_exclude_url(char *url,int length) +/*! + Store a IPv6 address to exclude from the reported URL. + + \param addr The 8 short int of the address. + \param nbits The number of bits to keep in the prefix. + */ +static void store_exclude_ip6(unsigned short *addr,int nbits) +{ + int i; + + if (num_exclude_ip6>=ip6allocated) { + struct hostip6struct *temp; + + ip6allocated+=5; + temp=realloc(exclude_ip6,ip6allocated*sizeof(*temp)); + if (temp==NULL) { + debuga(_("Not enough memory to store the exlcluded IP addresses\n")); + exit(EXIT_FAILURE); + } + exclude_ip6=temp; + } + for (i=0 ; i<8 ; i++) + exclude_ip6[num_exclude_ip6].address[i]=addr[i]; + exclude_ip6[num_exclude_ip6].nbits=nbits; + num_exclude_ip6++; +} + +/*! + Store a host name to exclude from the report. + + \param url The host name to exclude. + */ +static void store_exclude_url(const char *url,const char *next) { int start; int i; + int length; int ndots, firstdot; struct hostnamestruct *item; start=0; ndots=-1; firstdot=0; + length=next-url; for (i=0 ; indots=(ndots>0) ? ndots : -1; } - +/*! + Read the file listing the host to exclude from the report. + + \param hexfile The name of the file. + \param debug \c True to print debug information. + */ void gethexclude(const char *hexfile, int debug) { FILE *fp_ex; char buf[255]; - int i; - int ip_size; - unsigned int value4, value6; - unsigned short int addr[8]; - int addr_len; - int mask, max_mask; + int type; + const char *name; + unsigned char ipv4[4]; + unsigned short int ipv6[8]; + int nbits; + const char *next; if(access(hexfile, R_OK) != 0) { debuga(_("Cannot open exclude_hosts file: %s - %s\n"),hexfile,strerror(errno)); @@ -153,65 +209,19 @@ void gethexclude(const char *hexfile, int debug) if(buf[0]=='#') continue; fixendofline(buf); - ip_size=0x60 | 0x04; - value4=0U; - value6=0U; - addr_len=0; - for (i=0 ; (unsigned char)buf[i]>' ' && buf[i]!='/' ; 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; - } else { - ip_size&=~0x60; - } - } - } - if (i==0) continue; - if (ip_size & 0x04) { - if (addr_len!=3) - ip_size&=~0x04; - else - addr[addr_len++]=(unsigned short)(value4 & 0xFFU); - } - if (ip_size & 0x60) { - if (addr_len>=8) - ip_size&=~0x60; - else - addr[addr_len++]=(unsigned short)(value6 & 0xFFFFU); + + type=extract_address_mask(buf,&name,ipv4,ipv6,&nbits,&next); + if (type<0) { + debuga(_("While reading \"%s\""),hexfile); + exit(EXIT_FAILURE); } - if (ip_size) { - max_mask=(ip_size & 0x04) ? 4*8 : 8*16; - if (buf[i]=='/') { - mask=atoi(buf+i+1); - if (mask<0 || mask>max_mask) mask=max_mask; - } else - mask=max_mask; - if (ip_size & 0x04) - store_exclude_ip4(addr,mask); - else { - debuga(_("IPv6 addresses are not supported (found in %s)\n"),hexfile); - exit(EXIT_FAILURE); - } - } else { - store_exclude_url(buf,i); + + if (type==1) { + store_exclude_url(name,next); + } else if (type==2) { + store_exclude_ip4(ipv4,nbits); + } else if (type==3) { + store_exclude_ip6(ipv6,nbits); } } @@ -219,63 +229,32 @@ void gethexclude(const char *hexfile, int debug) return; } +/*! + Check if the URL is excluded as per the host exclusion list. + + \param url The URL to check. + + \retval 1 Keep the URL. + \retval 0 Exclude the URL. + */ int vhexclude(const char *url) { int i, j; int length; - int ip_size; - unsigned int value4, value6; + int type; + const char *name; + unsigned char ipv4[4]; + unsigned short int ipv6[8]; unsigned long int addr4; - unsigned short int addr6[8]; - int addr_len; - int dotpos[10]; + int dotpos[50]; int ndots; - ip_size=0x60 | 0x04; - addr4=0UL; - value4=0U; - value6=0U; - addr_len=0; - for (i=0 ; (unsigned char)url[i]>' ' && url[i]!='/' && url[i]!='?'&& ((ip_size & 0x60)!=0 || url[i]!=':') && ip_size ; i++) { - if (ip_size & 0x04) { - if (isdigit(url[i])) { - value4=value4*10+(url[i]-'0'); - if (value4>0xFFU) ip_size&=~0x04; - } else if (url[i]=='.' && addr_len<4) { - addr_len++; - addr4=(addr4<<8) | (unsigned long int)(value4 & 0xFFU); - value4=0U; - } else { - ip_size&=~0x04; - } - } - if (ip_size & 0x60) { - if (isdigit(url[i])) { - value6=(value6<<4)+(url[i]-'0'); - if (value6>0xFFFFU) ip_size&=~0x60; - } else if (toupper(url[i])>='A' && toupper(url[i])<='F') { - value6=(value6<<4)+(toupper(url[i])-'A'+10); - if (value6>0xFFFFU) ip_size&=~0x60; - } else if (url[i]==':' && addr_len<8) { - addr6[addr_len++]=(unsigned short)(value6 & 0xFFFFU); - value6=0U; - } else { - ip_size&=~0x60; - } - } - } - if ((ip_size & 0x04) && addr_len==3) { - if (exclude_ip4 == NULL) return(1); - addr4=(addr4<<8) | (unsigned long int)(value4 & 0xFFU); - for (i=0 ; i' ' && url[length]!=':' && url[length]!='/' && url[length]!='?' ; length++) - if (url[length]=='.') { + for (length=0 ; (unsigned char)name[length]>' ' && name[length]!=':' && name[length]!='/' && name[length]!='?' ; length++) + if (name[length]=='.') { /* We store the position of each dots of the URL to match it against any wildcard in the excluded list. The size of dotpos is big enough for the most @@ -292,7 +271,7 @@ int vhexclude(const char *url) if (length>0) { for (i=0 ; i0) { - const char *wurl=url; + const char *wurl=name; int len=length; if (exclude_name[i].ndots<=ndots) { wurl+=dotpos[ndots-exclude_name[i].ndots]; @@ -304,8 +283,24 @@ int vhexclude(const char *url) } } } + } else if (type==2) { + if (exclude_ip4 == NULL) return(1); + addr4=0UL; + for (i=0 ; i<4 ; i++) addr4=(addr4 << 8) | ipv4[i]; + for (i=0 ; i=0 && ipv6[j]==exclude_ip6[i].address[j] ; j--); + if (j>=0) return(1); + j=length/16; + if (j>=8 || length%16==0 || ((ipv6[j] ^ exclude_ip6[i].address[j]) & (0xFFFF<<(length-j*16)))==0) + return(0); + } } - return(1); } diff --git a/include/defs.h b/include/defs.h index 5050800..dd02666 100755 --- a/include/defs.h +++ b/include/defs.h @@ -278,4 +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); +int extract_address_mask(const char *buf,const char **text,unsigned char *ipv4,unsigned short int *ipv6,int *nbits,const char **next); diff --git a/url.c b/url.c index 3d7ada5..188c225 100644 --- a/url.c +++ b/url.c @@ -95,48 +95,51 @@ static struct hostalias_ipv6 *FirstAliasIpv6=NULL; \retval 0 Ignore the line. \retval -1 Error. */ -static int Alias_StoreName(char *name,char *next) +static int Alias_StoreName(const char *name,const char *next) { - char *NameBegin; - char *NameEnd; - char *Replace; - char *str; + const char *NameBegin; + const char *NameBeginE; + const char *NameEnd; + const char *NameEndE; + const char *Replace; + const char *ReplaceE; + const char *str; char sep; struct hostalias_name *alias; struct hostalias_name *new_alias; struct hostalias_name *prev_alias; char *tmp; + int len; if (*name=='#' || *name==';') return(0); - sep=*next; - *next++='\0'; // 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>' ') { + for (str=NameBegin ; str' ' && *str!='*' ; str++); + NameBeginE=str; + if (NameBegin==NameBeginE) NameBegin=NULL; + if (str' ') { if (*str=='*') { debuga(_("Host name alias \"%s*%s\" contains too many wildcards (*)"),NameBegin,NameEnd); return(-1); } - *str=tolower(*str); str++; } - } else + NameEndE=str; + if (NameEnd==NameEndE) { + debuga(_("Host name alias \"%*s\" must not end with a wildcard"),(int)(next-name),name); + 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); - return(-1); } - if (NameBegin[0]=='\0') NameBegin=NULL; + while (str=' ' ; str++); - *str='\0'; + ReplaceE=str; } } else Replace=NULL; + if (NameBegin) { + len=(int)(NameBeginE-NameBegin); + tmp=malloc(len+1); + if (!tmp) { + debuga(_("Not enough memory to store the host name aliasing directives")); + return(-1); + } + memcpy(tmp,NameBegin,len); + tmp[len]='\0'; + NameBegin=tmp; + } + if (NameEnd) { + len=(int)(NameEndE-NameEnd); + tmp=malloc(len+1); + if (!tmp) { + if (NameBegin) free((void*)NameBegin); + debuga(_("Not enough memory to store the host name aliasing directives")); + return(-1); + } + memcpy(tmp,NameEnd,len); + tmp[len]='\0'; + NameEnd=tmp; + } + // 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))) { + if (NameBegin) free((void*)NameBegin); return(0); } prev_alias=alias; @@ -162,16 +190,14 @@ static int Alias_StoreName(char *name,char *next) // insert into the list new_alias=malloc(sizeof(*new_alias)); if (!new_alias) { + if (NameBegin) free((void*)NameBegin); + if (NameEnd) free((void*)NameEnd); 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->HostName_Prefix=NameBegin; new_alias->MinLen+=strlen(NameBegin); new_alias->PrefixLen=strlen(NameBegin); } else { @@ -179,11 +205,7 @@ static int Alias_StoreName(char *name,char *next) 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); - } + new_alias->HostName_Suffix=NameEnd; new_alias->MinLen+=strlen(NameEnd)+1; new_alias->SuffixLen=strlen(NameEnd); } else { @@ -191,13 +213,15 @@ static int Alias_StoreName(char *name,char *next) new_alias->SuffixLen=0; } if (Replace) { - tmp=malloc(strlen(Replace)+2); + len=(int)(ReplaceE-Replace); + tmp=malloc(len+2); if (!tmp) { debuga(_("Not enough memory to store the host name aliasing directives")); return(-1); } tmp[0]=ALIAS_PREFIX; - strcpy(tmp+1,Replace); + memcpy(tmp+1,Replace,len); + tmp[len+1]='\0'; new_alias->Alias=tmp; } else { tmp=malloc(new_alias->MinLen+2); @@ -233,15 +257,17 @@ static int Alias_StoreName(char *name,char *next) \retval 0 Ignore the line. \retval -1 Error. */ -static int Alias_StoreIpv4(unsigned char *ipv4,int nbits,char *next) +static int Alias_StoreIpv4(unsigned char *ipv4,int nbits,const char *next) { - char *Replace; - char *str; + const char *Replace; + const char *ReplaceE; + const char *str; struct hostalias_ipv4 *alias; struct hostalias_ipv4 *new_alias; struct hostalias_ipv4 *prev_alias; int i; char *tmp; + int len; // get the alias Replace=next; @@ -250,7 +276,7 @@ static int Alias_StoreIpv4(unsigned char *ipv4,int nbits,char *next) Replace=NULL; } else { for (str=Replace ; *str && (unsigned char)*str>=' ' ; str++); - *str='\0'; + ReplaceE=str; } // store more restrictive range first @@ -272,13 +298,15 @@ static int Alias_StoreIpv4(unsigned char *ipv4,int nbits,char *next) memcpy(new_alias->Ip,ipv4,4); new_alias->NBits=nbits; if (Replace) { - tmp=malloc(strlen(Replace)+2); + len=(int)(ReplaceE-Replace); + tmp=malloc(len+2); if (!tmp) { debuga(_("Not enough memory to store the host name aliasing directives")); return(-1); } tmp[0]=ALIAS_PREFIX; - strcpy(tmp+1,Replace); + memcpy(tmp+1,Replace,len); + tmp[len+1]='\0'; new_alias->Alias=tmp; } else { tmp=malloc(5*4+1); @@ -311,15 +339,17 @@ static int Alias_StoreIpv4(unsigned char *ipv4,int nbits,char *next) \retval 0 Ignore the line. \retval -1 Error. */ -static int Alias_StoreIpv6(unsigned short *ipv6,int nbits,char *next) +static int Alias_StoreIpv6(unsigned short *ipv6,int nbits,const char *next) { - char *Replace; - char *str; + const char *Replace; + const char *ReplaceE; + const char *str; struct hostalias_ipv6 *alias; struct hostalias_ipv6 *new_alias; struct hostalias_ipv6 *prev_alias; int i; char *tmp; + int len; // get the alias Replace=next; @@ -328,7 +358,7 @@ static int Alias_StoreIpv6(unsigned short *ipv6,int nbits,char *next) Replace=NULL; } else { for (str=Replace ; *str && (unsigned char)*str>=' ' ; str++); - *str='\0'; + ReplaceE=str; } // store more restrictive range first @@ -350,13 +380,15 @@ static int Alias_StoreIpv6(unsigned short *ipv6,int nbits,char *next) memcpy(new_alias->Ip,ipv6,8*sizeof(unsigned short int)); new_alias->NBits=nbits; if (Replace) { - tmp=malloc(strlen(Replace)+2); + len=ReplaceE-Replace; + tmp=malloc(len+2); if (!tmp) { debuga(_("Not enough memory to store the host name aliasing directives")); return(-1); } tmp[0]=ALIAS_PREFIX; - strcpy(tmp+1,Replace); + memcpy(tmp+1,Replace,len); + tmp[len+1]='\0'; new_alias->Alias=tmp; } else { tmp=malloc(5*8+5); @@ -389,11 +421,11 @@ void read_hostalias(const char *Filename) longline line; char *buf; int type; - char *name; + const char *name; unsigned char ipv4[4]; unsigned short int ipv6[8]; int nbits; - char *next; + const char *next; if (debug) debuga(_("Reading host alias file \"%s\"\n"),Filename); fi=fopen(Filename,"rt"); @@ -408,7 +440,6 @@ void read_hostalias(const char *Filename) } 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); @@ -492,26 +523,26 @@ Replace the host name by its alias if it is in our list. \return The pointer to the host name or its alias. */ -const char *alias_url_name(const char *url) +const char *alias_url_name(const char *url,const char *next) { struct hostalias_name *alias; int len; - len=strlen(url); + len=(int)(next-url); for (alias=FirstAliasName ; alias ; alias=alias->Next) { if (lenMinLen) continue; if (alias->HostName_Prefix) { if (alias->HostName_Suffix) { if (strncasecmp(url,alias->HostName_Prefix,alias->PrefixLen)==0 && - strcasecmp(url+(len-alias->SuffixLen),alias->HostName_Suffix)==0) { + strncasecmp(url+(len-alias->SuffixLen),alias->HostName_Suffix,len)==0) { return(alias->Alias); } } else { - if (len==alias->PrefixLen && strcasecmp(url,alias->HostName_Prefix)==0) { + if (len==alias->PrefixLen && strncasecmp(url,alias->HostName_Prefix,len)==0) { return(alias->Alias); } } - } else if (strcasecmp(url+(len-alias->SuffixLen),alias->HostName_Suffix)==0) { + } else if (strncasecmp(url+(len-alias->SuffixLen),alias->HostName_Suffix,len)==0) { return(alias->Alias); } } @@ -578,10 +609,10 @@ const char *process_url(char *url,bool full_url) char *str; const char *start; int type; - char *address; + const char *address; unsigned char ipv4[4]; unsigned short int ipv6[8]; - char *next; + const char *next; /* Remove any scheme:// at the beginning of the URL (see rfc2396 section 3.1). @@ -600,7 +631,7 @@ const char *process_url(char *url,bool full_url) type=extract_address_mask(url,&address,ipv4,ipv6,NULL,&next); if (type==1) { if (FirstAliasName) - start=alias_url_name(start); + start=alias_url_name(start,next); } else if (type==2) { if (FirstAliasIpv4) start=alias_url_ipv4(start,ipv4); diff --git a/util.c b/util.c index b5cb4b5..45519b9 100644 --- a/util.c +++ b/util.c @@ -1785,7 +1785,7 @@ void unlinkdir(const char *dir,int contentonly) \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 extract_address_mask(const char *buf,const char **text,unsigned char *ipv4,unsigned short int *ipv6,int *nbits,const char **next) { int i; int j; @@ -1869,7 +1869,7 @@ int extract_address_mask(char *buf,char **text,unsigned char *ipv4,unsigned shor *text=buf; if (bracket) (*text)--; while ((unsigned char)buf[i]>' ') i++; - *next=buf+i; + if (next) *next=buf+i; return(1); } max_mask=(ip_size & 0x04) ? 4*8 : 8*16; @@ -1881,7 +1881,7 @@ int extract_address_mask(char *buf,char **text,unsigned char *ipv4,unsigned shor } else mask=max_mask; if (ip_size & 0x60 && bracket && buf[i]==']') i++; - *next=buf+i; + if (next) *next=buf+i; if (ip_size & 0x04) { if (nbits) *nbits=mask; for (i=0 ; i