]> git.ipfire.org Git - thirdparty/sarg.git/commitdiff
Alias IP addresses in the URL using the CIDR notation
authorFrédéric Marchal <fmarchal@users.sourceforge.net>
Mon, 20 Jun 2011 20:31:06 +0000 (20:31 +0000)
committerFrédéric Marchal <fmarchal@users.sourceforge.net>
Mon, 20 Jun 2011 20:31:06 +0000 (20:31 +0000)
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.

include/defs.h
url.c
util.c

index 8003cccb33ed2ac7ff7d95c3a17a6e8894bf0dab..50508006059317044b59af1ea17f70d13e8e1629 100755 (executable)
@@ -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 3c3d73515bf3400fe42063ad86be694e9f3e0727..6de0abf3d6df2c5db44041e271440e147b1c686a 100644 (file)
--- a/url.c
+++ b/url.c
 /*!
 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=(nbits<alias->NBits) ? 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=(nbits<alias->NBits) ? 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 (len<alias->MinLen) 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 8bebb439c40be72aeb412d8aa56f2641ab8cdd65..00d92064d6c8e8f76360cefeaac7a297c6eee667 100644 (file)
--- 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<addr_len ; i++)
+                       ipv4[i]=(unsigned char)addr[i];
+               return(2);
+       }
+
+       // IPv6 address
+       if (nbits) *nbits=mask;
+       i=0;
+       j=0;
+       if (pad_pos>=0) {
+               while (i<pad_pos)
+                       ipv6[j++]=(unsigned short int)addr[i++];
+               pad_len=8-addr_len;
+               while (i<pad_pos+pad_len)
+                       ipv6[j++]=0;
+       }
+       while (i<addr_len)
+               ipv6[j++]=(unsigned short int)addr[i++];
+       return(3);
+}