"Fossies" - the Fresh Open Source Software Archive

Member "sarg-2.4.0/alias.c" (30 Jan 2017, 22219 Bytes) of package /linux/privat/sarg-2.4.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "alias.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * SARG Squid Analysis Report Generator      http://sarg.sourceforge.net
    3  *                                                            1998, 2015
    4  *
    5  * SARG donations:
    6  *      please look at http://sarg.sourceforge.net/donations.php
    7  * Support:
    8  *     http://sourceforge.net/projects/sarg/forums/forum/363374
    9  * ---------------------------------------------------------------------
   10  *
   11  *  This program is free software; you can redistribute it and/or modify
   12  *  it under the terms of the GNU General Public License as published by
   13  *  the Free Software Foundation; either version 2 of the License, or
   14  *  (at your option) any later version.
   15  *
   16  *  This program is distributed in the hope that it will be useful,
   17  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   18  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   19  *  GNU General Public License for more details.
   20  *
   21  *  You should have received a copy of the GNU General Public License
   22  *  along with this program; if not, write to the Free Software
   23  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
   24  *
   25  */
   26 
   27 #include "include/conf.h"
   28 #include "include/defs.h"
   29 #include "include/stringbuffer.h"
   30 #include "include/alias.h"
   31 #ifdef HAVE_PCRE_H
   32 #include <pcre.h>
   33 #define USE_PCRE 1
   34 #endif
   35 
   36 //! Longest alias name length including the terminating zero.
   37 #define MAX_ALIAS_LEN 256
   38 
   39 /*!
   40 A host name and the name to report.
   41 */
   42 struct aliasitem_name
   43 {
   44     //! The minimum length of a candidate user name.
   45     int MinLen;
   46     //! Number of wildcards in the mask.
   47     int Wildcards;
   48     //! The mask of the user name.
   49     const char *Mask;
   50 };
   51 
   52 /*!
   53 An IPv4 address and the name to report.
   54 */
   55 struct aliasitem_ipv4
   56 {
   57     //! The IP address.
   58     unsigned char Ip[4];
   59     //! The number of bits in the prefix.
   60     int NBits;
   61 };
   62 
   63 /*!
   64 An IPv6 address and the name to report.
   65 */
   66 struct aliasitem_ipv6
   67 {
   68     //! The IP address.
   69     unsigned short Ip[8];
   70     //! The number of bits in the prefix.
   71     int NBits;
   72 };
   73 
   74 #ifdef USE_PCRE
   75 /*!
   76 A regular expression.
   77 */
   78 struct aliasitem_regex
   79 {
   80     //! The regular expression to match against the name.
   81     pcre *Re;
   82     //! \c True if this regular expression contains at least one subpattern
   83     bool SubPartern;
   84 };
   85 #endif
   86 
   87 //! Type of grouping criterion.
   88 enum aliasitem_type
   89 {
   90     ALIASTYPE_Name,
   91     ALIASTYPE_Ipv4,
   92     ALIASTYPE_Ipv6,
   93     ALIASTYPE_Pcre
   94 };
   95 
   96 //! \brief One item to group.
   97 struct AliasItemStruct
   98 {
   99     //! The next item in the list or NULL for the last item.
  100     struct AliasItemStruct *Next;
  101     //! What criterion to use to group the item.
  102     enum aliasitem_type Type;
  103     union
  104     {
  105         //! The alias of a name.
  106         struct aliasitem_name Name;
  107         //! The alias of an IPv4 address.
  108         struct aliasitem_ipv4 Ipv4;
  109         //! The alias of an IPv6 address.
  110         struct aliasitem_ipv6 Ipv6;
  111 #ifdef USE_PCRE
  112         //! The alias of regular expression.
  113         struct aliasitem_regex Regex;
  114 #endif
  115     };
  116     //! The replacement name.
  117     const char *Alias;
  118 };
  119 
  120 //! Object to group items together.
  121 struct AliasStruct
  122 {
  123     //! First item in the list.
  124     struct AliasItemStruct *First;
  125     //! Buffer to store the strings.
  126     StringBufferObject StringBuffer;
  127 };
  128 
  129 /*!
  130   Create an object to alias items.
  131 
  132   \return A pointer to the object or NULL if the
  133   creation failed.
  134 
  135   The returned pointer must be freed by Alias_Destroy().
  136  */
  137 AliasObject Alias_Create(void)
  138 {
  139     struct AliasStruct *Alias;
  140 
  141     Alias=calloc(1,sizeof(struct AliasStruct));
  142     if (!Alias) return(NULL);
  143 
  144     Alias->StringBuffer=StringBuffer_Create();
  145     if (!Alias->StringBuffer)
  146     {
  147         free(Alias);
  148         return(NULL);
  149     }
  150 
  151     return(Alias);
  152 }
  153 
  154 /*!
  155   Destroy the object created by Alias_Create().
  156 
  157   \param AliasPtr Pointer to the variable containing
  158   the alias. It is reset to NULL to prevent subsequent
  159   use of the pointer.
  160  */
  161 void Alias_Destroy(AliasObject *AliasPtr)
  162 {
  163     struct AliasStruct *Alias;
  164     struct AliasItemStruct *Item;
  165 
  166     if (!AliasPtr || !*AliasPtr) return;
  167     Alias=*AliasPtr;
  168     *AliasPtr=NULL;
  169 
  170     for (Item=Alias->First ; Item ; Item=Item->Next)
  171     {
  172         switch (Item->Type)
  173         {
  174             case ALIASTYPE_Name:
  175             case ALIASTYPE_Ipv4:
  176             case ALIASTYPE_Ipv6:
  177                 break;
  178 
  179             case ALIASTYPE_Pcre:
  180 #ifdef USE_PCRE
  181                 pcre_free(Item->Regex.Re);
  182 #endif
  183                 break;
  184         }
  185     }
  186 
  187     StringBuffer_Destroy(&Alias->StringBuffer);
  188     free(Alias);
  189 }
  190 
  191 
  192 /*!
  193   Store a name to alias.
  194 
  195   \param name The name to match including the wildcard.
  196   \param next A pointer to the first character after the name.
  197 
  198   \retval 1 Alias added.
  199   \retval 0 Ignore the line.
  200   \retval -1 Error.
  201  */
  202 static int Alias_StoreName(struct AliasStruct *AliasData,const char *name,const char *next)
  203 {
  204     char Name[MAX_ALIAS_LEN];
  205     const char *Replace;
  206     const char *ReplaceE;
  207     const char *str;
  208     struct AliasItemStruct *alias;
  209     struct AliasItemStruct *new_alias;
  210     struct AliasItemStruct *prev_alias;
  211     int len;
  212     int minlen=0;
  213     int wildcards=0;
  214     bool in_wildcard=false;
  215 
  216     // get user name and count the wildcards
  217     len=0;
  218     for (str=name ; len<sizeof(Name)-1 && str<next ; str++)
  219     {
  220         if (*str=='*')
  221         {
  222             if (!in_wildcard)
  223             {
  224                 Name[len++]=*str;
  225                 wildcards++;
  226                 in_wildcard=true;
  227             }
  228         }
  229         else
  230         {
  231             Name[len++]=tolower(*str);
  232             minlen++;
  233             in_wildcard=false;
  234         }
  235     }
  236     if (len==0) return(0);
  237     Name[len]='\0';
  238 
  239     // get the alias
  240     while (*str==' ' || *str=='\t') str++;
  241     Replace=str;
  242     while ((unsigned char)*str>=' ') str++;
  243     ReplaceE=str;
  244     if (Replace==ReplaceE) return(0);
  245 
  246     // ignore duplicates
  247     prev_alias=NULL;
  248     for (alias=AliasData->First ; alias ; alias=alias->Next) {
  249         if (alias->Type==ALIASTYPE_Name && !strcmp(Name,alias->Name.Mask)) {
  250             debuga(__FILE__,__LINE__,_("Duplicate aliasing directive for name %s\n"),Name);
  251             return(0);
  252         }
  253         prev_alias=alias;
  254     }
  255 
  256     // insert into the list
  257     new_alias=malloc(sizeof(*new_alias));
  258     if (!new_alias) {
  259         debuga(__FILE__,__LINE__,_("Not enough memory to store the user name aliasing directives\n"));
  260         return(-1);
  261     }
  262     new_alias->Type=ALIASTYPE_Name;
  263     new_alias->Name.MinLen=minlen;
  264     new_alias->Name.Wildcards=wildcards;
  265     new_alias->Name.Mask=StringBuffer_Store(AliasData->StringBuffer,Name);
  266     if (!new_alias->Name.Mask) {
  267         debuga(__FILE__,__LINE__,_("Not enough memory to store the user name aliasing directives\n"));
  268         free(new_alias);
  269         return(-1);
  270     }
  271 
  272     len=(int)(ReplaceE-Replace);
  273     new_alias->Alias=StringBuffer_StoreLength(AliasData->StringBuffer,Replace,len);
  274     if (!new_alias->Alias) {
  275         debuga(__FILE__,__LINE__,_("Not enough memory to store the user name aliasing directives\n"));
  276         free(new_alias);
  277         return(-1);
  278     }
  279 
  280     new_alias->Next=NULL;
  281     if (prev_alias)
  282         prev_alias->Next=new_alias;
  283     else
  284         AliasData->First=new_alias;
  285     return(1);
  286 }
  287 
  288 /*!
  289   Store a IPv4 to alias.
  290 
  291   \param ipv4 The IPv4 to match.
  292   \param nbits The number of bits in the prefix
  293   \param next A pointer to the first character after the address.
  294 
  295   \retval 1 Alias added.
  296   \retval 0 Ignore the line.
  297   \retval -1 Error.
  298  */
  299 static int Alias_StoreIpv4(struct AliasStruct *AliasData,unsigned char *ipv4,int nbits,const char *next)
  300 {
  301     const char *Replace;
  302     const char *ReplaceE;
  303     const char *str;
  304     struct AliasItemStruct *alias;
  305     struct AliasItemStruct *new_alias;
  306     struct AliasItemStruct *prev_alias;
  307     int len;
  308 
  309     // get the alias
  310     Replace=next;
  311     while (*Replace==' ' || *Replace=='\t') Replace++;
  312     if ((unsigned char)*Replace<' ') {
  313         Replace=NULL;
  314     } else {
  315         for (str=Replace ; *str && (unsigned char)*str>=' ' ; str++);
  316         ReplaceE=str;
  317     }
  318 
  319     // check for duplicate or broader range
  320     prev_alias=NULL;
  321     for (alias=AliasData->First ; alias ; alias=alias->Next) {
  322         if (alias->Type==ALIASTYPE_Ipv4 && nbits>=alias->Ipv4.NBits) {
  323             int byte=alias->Ipv4.NBits/8;
  324             int bit=alias->Ipv4.NBits%8;
  325             if ((byte<1 || memcmp(ipv4,alias->Ipv4.Ip,byte)==0) && (bit==0 || (ipv4[byte] ^ alias->Ipv4.Ip[byte]) & (0xFFU<<(8-bit)))==0) {
  326                 if (nbits==alias->Ipv4.NBits)
  327                     debuga(__FILE__,__LINE__,_("Duplicate aliasing directive for IPv4 address %d.%d.%d.%d/%d\n"),
  328                            ipv4[0],ipv4[1],ipv4[2],ipv4[3],nbits);
  329                 else
  330                     debuga(__FILE__,__LINE__,_("IPv4 aliasing directive ignored for IPv4 address %d.%d.%d.%d/%d as it is"
  331                              " narrower than a previous one (%d.%d.%d.%d/%d\n"),
  332                            ipv4[0],ipv4[1],ipv4[2],ipv4[3],nbits,
  333                             alias->Ipv4.Ip[0],alias->Ipv4.Ip[1],alias->Ipv4.Ip[2],alias->Ipv4.Ip[3],
  334                             alias->Ipv4.NBits);
  335                 return(0);
  336             }
  337         }
  338         prev_alias=alias;
  339     }
  340 
  341     // insert into the list
  342     new_alias=malloc(sizeof(*new_alias));
  343     if (!new_alias) {
  344         debuga(__FILE__,__LINE__,_("Not enough memory to store the host name aliasing directives\n"));
  345         return(-1);
  346     }
  347     new_alias->Type=ALIASTYPE_Ipv4;
  348     memcpy(new_alias->Ipv4.Ip,ipv4,4);
  349     new_alias->Ipv4.NBits=nbits;
  350     if (Replace) {
  351         char *tmp;
  352 
  353         len=(int)(ReplaceE-Replace);
  354         tmp=malloc(len+2);
  355         if (!tmp) {
  356             debuga(__FILE__,__LINE__,_("Not enough memory to store the host name aliasing directives\n"));
  357             free(new_alias);
  358             return(-1);
  359         }
  360         tmp[0]=ALIAS_PREFIX;
  361         memcpy(tmp+1,Replace,len);
  362         tmp[len+1]='\0';
  363         new_alias->Alias=StringBuffer_Store(AliasData->StringBuffer,tmp);
  364         free(tmp);
  365     } else {
  366         char tmp[5*4+1];
  367         sprintf(tmp,"%c%d.%d.%d.%d/%d",ALIAS_PREFIX,ipv4[0],ipv4[1],ipv4[2],ipv4[3],nbits);
  368         new_alias->Alias=StringBuffer_Store(AliasData->StringBuffer,tmp);
  369     }
  370     if (!new_alias->Alias) {
  371         debuga(__FILE__,__LINE__,_("Not enough memory to store the IPv4 aliasing directives\n"));
  372         free(new_alias);
  373         return(-1);
  374     }
  375 
  376     new_alias->Next=NULL;
  377     if (prev_alias)
  378         prev_alias->Next=new_alias;
  379     else
  380         AliasData->First=new_alias;
  381     return(1);
  382 }
  383 
  384 /*!
  385   Store a IPv6 to alias.
  386 
  387   \param ipv6 The IPv6 to match.
  388   \param nbits The number of bits in the prefix
  389   \param next A pointer to the first character after the address.
  390 
  391   \retval 1 Alias added.
  392   \retval 0 Ignore the line.
  393   \retval -1 Error.
  394  */
  395 static int Alias_StoreIpv6(struct AliasStruct *AliasData,unsigned short *ipv6,int nbits,const char *next)
  396 {
  397     const char *Replace;
  398     const char *ReplaceE;
  399     const char *str;
  400     struct AliasItemStruct *alias;
  401     struct AliasItemStruct *new_alias;
  402     struct AliasItemStruct *prev_alias;
  403     int len;
  404 
  405     // get the alias
  406     Replace=next;
  407     while (*Replace==' ' || *Replace=='\t') Replace++;
  408     if ((unsigned char)*Replace<' ') {
  409         Replace=NULL;
  410     } else {
  411         for (str=Replace ; *str && (unsigned char)*str>=' ' ; str++);
  412         ReplaceE=str;
  413     }
  414 
  415     // check for duplicate or broader range
  416     prev_alias=NULL;
  417     for (alias=AliasData->First ; alias ; alias=alias->Next) {
  418         if (alias->Type==ALIASTYPE_Ipv6 && nbits>=alias->Ipv6.NBits) {
  419             int word=alias->Ipv6.NBits/16;
  420             int bit=alias->Ipv6.NBits%16;
  421             if ((word<1 || memcmp(ipv6,alias->Ipv6.Ip,word*2)==0) && (bit==0 || (ipv6[word] ^ alias->Ipv6.Ip[word]) & (0xFFFFU<<(16-bit)))==0) {
  422                 if (nbits==alias->Ipv6.NBits)
  423                     debuga(__FILE__,__LINE__,_("Duplicate aliasing directive for IPv6 address %x:%x:%x:%x:%x:%x:%x:%x/%d\n"),
  424                            ipv6[0],ipv6[1],ipv6[2],ipv6[3],ipv6[4],ipv6[5],ipv6[6],ipv6[7],nbits);
  425                 else
  426                     debuga(__FILE__,__LINE__,_("IPv6 aliasing directive ignored for IPv6 address %x:%x:%x:%x:%x:%x:%x:%x/%d as it is"
  427                              " narrower than a previous one (%x:%x:%x:%x:%x:%x:%x:%x/%d\n"),
  428                            ipv6[0],ipv6[1],ipv6[2],ipv6[3],ipv6[4],ipv6[5],ipv6[6],ipv6[7],nbits,
  429                             alias->Ipv6.Ip[0],alias->Ipv6.Ip[1],alias->Ipv6.Ip[2],alias->Ipv6.Ip[3],alias->Ipv6.Ip[4],
  430                             alias->Ipv6.Ip[5],alias->Ipv6.Ip[6],alias->Ipv6.Ip[7],alias->Ipv6.NBits);
  431                 return(0);
  432             }
  433         }
  434         prev_alias=alias;
  435     }
  436 
  437     // insert into the list
  438     new_alias=malloc(sizeof(*new_alias));
  439     if (!new_alias) {
  440         debuga(__FILE__,__LINE__,_("Not enough memory to store the host name aliasing directives\n"));
  441         return(-1);
  442     }
  443     new_alias->Type=ALIASTYPE_Ipv6;
  444     memcpy(new_alias->Ipv6.Ip,ipv6,8*sizeof(unsigned short int));
  445     new_alias->Ipv6.NBits=nbits;
  446     if (Replace) {
  447         char *tmp;
  448         len=ReplaceE-Replace;
  449         tmp=malloc(len+2);
  450         if (!tmp) {
  451             debuga(__FILE__,__LINE__,_("Not enough memory to store the host name aliasing directives\n"));
  452             free(new_alias);
  453             return(-1);
  454         }
  455         tmp[0]=ALIAS_PREFIX;
  456         memcpy(tmp+1,Replace,len);
  457         tmp[len+1]='\0';
  458         new_alias->Alias=StringBuffer_Store(AliasData->StringBuffer,tmp);
  459         free(tmp);
  460     } else {
  461         char tmp[5*8+5];
  462         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);
  463         new_alias->Alias=StringBuffer_Store(AliasData->StringBuffer,tmp);
  464     }
  465     if (!new_alias->Alias) {
  466         debuga(__FILE__,__LINE__,_("Not enough memory to store the IPv6 aliasing directives\n"));
  467         free(new_alias);
  468         return(-1);
  469     }
  470 
  471     new_alias->Next=NULL;
  472     if (prev_alias)
  473         prev_alias->Next=new_alias;
  474     else
  475         AliasData->First=new_alias;
  476     return(1);
  477 }
  478 
  479 #ifdef USE_PCRE
  480 /*!
  481 Store a regular expression to match the alias.
  482 
  483 \retval 1 Alias added.
  484 \retval 0 Ignore the line.
  485 \retval -1 Error.
  486 */
  487 static int Alias_StoreRegexp(struct AliasStruct *AliasData,char *buf)
  488 {
  489     char Delimiter;
  490     char *End;
  491     struct AliasItemStruct *alias;
  492     struct AliasItemStruct *new_alias;
  493     struct AliasItemStruct **prev_alias;
  494     const char *PcreError;
  495     int ErrorOffset;
  496     char *Replace;
  497     int len;
  498     char *tmp;
  499     int i;
  500     int ReOption=0;
  501 
  502     // find the pattern
  503     Delimiter=*buf++;
  504     for (End=buf ; *End && *End!=Delimiter ; End++) {
  505         if (*End=='\\') {
  506             if (End[1]=='\0') {
  507                 debuga(__FILE__,__LINE__,_("Invalid NUL character found in regular expression\n"));
  508                 return(-1);
  509             }
  510             End++; //ignore the escaped character
  511         }
  512     }
  513     if (*End!=Delimiter) {
  514         debuga(__FILE__,__LINE__,_("Unterminated regular expression\n"));
  515         return(-1);
  516     }
  517     *End++='\0';
  518 
  519     // get option: currently supported: i=case insensitive
  520     while (*End && isalpha(*End)) {
  521         if (*End=='i') {
  522             ReOption|=PCRE_CASELESS;
  523         } else {
  524             debuga(__FILE__,__LINE__,_("Invalid option character %c found after regular expression\n"),*End);
  525             return(-1);
  526         }
  527         End++;
  528     }
  529 
  530     // find the alias
  531     for (Replace=End ; *Replace==' ' || *Replace=='\t' ; Replace++);
  532     for (End=Replace ; *End && (unsigned char)*End>' ' ; End++);
  533     *End='\0';
  534 
  535     // store it
  536     new_alias=malloc(sizeof(*new_alias));
  537     if (!new_alias) {
  538         debuga(__FILE__,__LINE__,_("Not enough memory to store the host name aliasing directives\n"));
  539         return(-1);
  540     }
  541     new_alias->Type=ALIASTYPE_Pcre;
  542     new_alias->Next=NULL;
  543     new_alias->Regex.Re=pcre_compile(buf,ReOption,&PcreError,&ErrorOffset,NULL);
  544     if (new_alias->Regex.Re==NULL) {
  545         debuga(__FILE__,__LINE__,_("Failed to compile the regular expression \"%s\": %s\n"),buf,PcreError);
  546         free(new_alias);
  547         return(-1);
  548     }
  549     len=strlen(Replace);
  550     tmp=malloc(len+2);
  551     if (!tmp) {
  552         debuga(__FILE__,__LINE__,_("Not enough memory to store the host name aliasing directives\n"));
  553         pcre_free(new_alias->Regex.Re);
  554         return(-1);
  555     }
  556     tmp[0]=ALIAS_PREFIX;
  557     memcpy(tmp+1,Replace,len);
  558     tmp[len+1]='\0';
  559     new_alias->Alias=StringBuffer_Store(AliasData->StringBuffer,tmp);
  560     free(tmp);
  561     if (!new_alias->Alias) {
  562         debuga(__FILE__,__LINE__,_("Not enough memory to store the regex aliasing directives\n"));
  563         free(new_alias);
  564         return(-1);
  565     }
  566 
  567     new_alias->Regex.SubPartern=false;
  568     for (i=0 ; Replace[i] ; i++)
  569         // both the sed \1 and the perl $1 replacement operators are accepted
  570         if ((Replace[i]=='\\' || Replace[i]=='$') && isdigit(Replace[i+1])) {
  571             new_alias->Regex.SubPartern=true;
  572             break;
  573         }
  574 
  575     // chain it
  576     prev_alias=&AliasData->First;
  577     for (alias=AliasData->First ; alias ; alias=alias->Next)
  578         prev_alias=&alias->Next;
  579     *prev_alias=new_alias;
  580 
  581     return(1);
  582 }
  583 #endif
  584 
  585 /*!
  586 Store an alias in the corresponding list.
  587 
  588 \param String The string to parse and store.
  589 
  590 \retval 0 No error.
  591 \retval -1 Error in file.
  592 \retval -2 Unknown string type to store.
  593 */
  594 int Alias_Store(struct AliasStruct *AliasData,char *String)
  595 {
  596     int type;
  597     const char *name;
  598     unsigned char ipv4[4];
  599     unsigned short int ipv6[8];
  600     int nbits;
  601     const char *next;
  602     int Error=-2;
  603 
  604     if (*String=='#' || *String==';') return(0);
  605 
  606     if (strncasecmp(String,"re:",3)==0) {
  607 #ifdef USE_PCRE
  608         if (Alias_StoreRegexp(AliasData,String+3)<0)
  609             return(-1);
  610 #else
  611         debuga(__FILE__,__LINE__,_("PCRE not compiled in therefore the regular expressions are not available to alias items\n"));
  612         return(-1);
  613 #endif
  614     }
  615     else
  616     {
  617         type=extract_address_mask(String,&name,ipv4,ipv6,&nbits,&next);
  618         if (type==1) {
  619             Error=Alias_StoreName(AliasData,name,next);
  620         } else if (type==2) {
  621             Error=Alias_StoreIpv4(AliasData,ipv4,nbits,next);
  622         } else if (type==3) {
  623             Error=Alias_StoreIpv6(AliasData,ipv6,nbits,next);
  624         } else {
  625             return(-1);
  626         }
  627         if (Error<0) return(-1);
  628     }
  629     return(0);
  630 }
  631 
  632 /*!
  633   Print the list of the aliases stored in the object.
  634 
  635   \param AliasData Object created by Alias_Create() and
  636   containing the aliases stored by Alias_Store().
  637  */
  638 void Alias_PrintList(struct AliasStruct *AliasData)
  639 {
  640     struct AliasItemStruct *alias;
  641 
  642     for (alias=AliasData->First ; alias ; alias=alias->Next) {
  643         switch (alias->Type)
  644         {
  645             case ALIASTYPE_Name:
  646                 debuga(__FILE__,__LINE__,_("  %s => %s\n"),alias->Name.Mask,alias->Alias);
  647                 break;
  648             case ALIASTYPE_Ipv4:
  649                 debuga(__FILE__,__LINE__,_("  %d.%d.%d.%d/%d => %s\n"),alias->Ipv4.Ip[0],alias->Ipv4.Ip[1],alias->Ipv4.Ip[2],
  650                         alias->Ipv4.Ip[3],alias->Ipv4.NBits,alias->Alias);
  651                 break;
  652             case ALIASTYPE_Ipv6:
  653                 debuga(__FILE__,__LINE__,_("  %x:%x:%x:%x:%x:%x:%x:%x/%d => %s\n"),alias->Ipv6.Ip[0],alias->Ipv6.Ip[1],alias->Ipv6.Ip[2],
  654                         alias->Ipv6.Ip[3],alias->Ipv6.Ip[4],alias->Ipv6.Ip[5],alias->Ipv6.Ip[6],alias->Ipv6.Ip[7],
  655                         alias->Ipv6.NBits,alias->Alias);
  656                 break;
  657             case ALIASTYPE_Pcre:
  658                 debuga(__FILE__,__LINE__,_("  Re => %s\n"),alias->Alias);
  659                 break;
  660         }
  661     }
  662 }
  663 
  664 /*!
  665 Replace the name by its alias if it is in our list.
  666 
  667 \param name The name to find in the list.
  668 
  669 \return The pointer to the name or its alias.
  670 */
  671 static bool Alias_MatchName(struct AliasItemStruct *alias,const char *name,int len)
  672 {
  673     int k;
  674     const char *Searched;
  675     const char *Candidate;
  676 
  677     if (!alias->Name.Wildcards)
  678     {
  679         if (len!=alias->Name.MinLen) return(false);
  680         return(strcmp(name,alias->Name.Mask)==0);
  681     }
  682     if (len<alias->Name.MinLen) return(false);
  683     Candidate=name;
  684     Searched=alias->Name.Mask;
  685     if (Searched[0]!='*')
  686     {
  687         while (*Searched && *Candidate && *Searched!='*')
  688         {
  689             if (Searched[0]!=Candidate[0]) return(false);
  690             Searched++;
  691             Candidate++;
  692         }
  693     }
  694     if (Searched[0]=='*') Searched++;
  695     while (Searched[0] && Candidate[0])
  696     {
  697         while (Candidate[0] && Candidate[0]!=Searched[0]) Candidate++;
  698         for (k=0 ; Candidate[k] && Searched[k] && Searched[k]!='*' && Searched[k]==Candidate[k] ; k++);
  699         if (Candidate[k]=='\0')
  700         {
  701             return(Searched[k]=='\0' || (Searched[k]=='*' && Searched[k+1]=='\0'));
  702         }
  703         if (Searched[k]=='\0') return(false);
  704         if (Searched[k]=='*')
  705         {
  706             Searched+=k+1;
  707             Candidate+=k;
  708         }
  709         else
  710             Candidate++;
  711     }
  712     return(Searched[0]=='\0');
  713 }
  714 
  715 /*!
  716 Replace the IPv4 address by its alias if it is in our list.
  717 
  718 \param url The host name.
  719 \param ipv4 The address.
  720 
  721 \return The pointer to the host name or its alias.
  722 */
  723 static bool Alias_MatchIpv4(struct AliasItemStruct *alias,unsigned char *ipv4)
  724 {
  725     int len;
  726     int n,m;
  727 
  728     len=alias->Ipv4.NBits;
  729     n=len/8;
  730     m=len%8;
  731     if (n>0 && memcmp(ipv4,alias->Ipv4.Ip,n)!=0) return(false);
  732     if (m!=0 && ((ipv4[n] ^ alias->Ipv4.Ip[n]) & (0xFFU<<(8-m)))!=0) return(false);
  733     return(true);
  734 }
  735 
  736 /*!
  737 Replace the IPv6 address by its alias if it is in our list.
  738 
  739 \param url The host name.
  740 \param ipv6 The address.
  741 
  742 \return The pointer to the host name or its alias.
  743 */
  744 static bool Alias_MatchIpv6(struct AliasItemStruct *alias,unsigned short int *ipv6)
  745 {
  746     int len;
  747     int i;
  748 
  749     len=alias->Ipv6.NBits;
  750     for (i=len/16-1 ; i>=0 && ipv6[i]==alias->Ipv6.Ip[i] ; i--);
  751     if (i<0) {
  752         i=len/16;
  753         if (i>=8 || len%16==0 || ((ipv6[i] ^ alias->Ipv6.Ip[i]) & (0xFFFF<<(len-i*16)))==0) {
  754             return(true);
  755         }
  756     }
  757     return(false);
  758 }
  759 
  760 #ifdef USE_PCRE
  761 /*!
  762 Replace the host name by its alias if it is in our list.
  763 
  764 \param url_ptr A pointer to the host name to match. It is replaced
  765 by a pointer to the alias if a match is found.
  766 
  767 \return A pointer to the replacement string or NULL if the regex
  768 doesn't match.
  769 
  770 \warning The function is not thread safe as it may return a static
  771 internal buffer.
  772 */
  773 static const char *Alias_MatchRegex(struct AliasItemStruct *alias,const char *name)
  774 {
  775     int nmatches;
  776     int len;
  777     int ovector[30];//size must be a multiple of 3
  778     static char Replacement[1024];
  779     const char *str;
  780     int i;
  781     int sub;
  782     int repl_idx;
  783 
  784     len=strlen(name);
  785     nmatches=pcre_exec(alias->Regex.Re,NULL,name,len,0,0,ovector,sizeof(ovector)/sizeof(ovector[0]));
  786     if (nmatches<0) return(NULL);
  787 
  788     if (nmatches==0) nmatches=(int)(sizeof(ovector)/sizeof(ovector[0]))/3*2; //only 2/3 of the vector is used by pcre_exec
  789     if (nmatches==1 || !alias->Regex.SubPartern) { //no subpattern to replace
  790         return(alias->Alias);
  791     }
  792 
  793     repl_idx=0;
  794     str=alias->Alias;
  795     for (i=0 ; str[i] ; i++) {
  796         // both the sed \1 and the perl $1 replacement operators are accepted
  797         if ((str[i]=='\\' || str[i]=='$') && isdigit(str[i+1])) {
  798             sub=str[++i]-'0';
  799             if (sub>=1 && sub<=nmatches) {
  800                 /*
  801                  * ovector[sub] is the start position of the match.
  802                  * ovector[sub+1] is the end position of the match.
  803                  */
  804                 sub<<=1;
  805                 if (repl_idx+ovector[sub+1]-ovector[sub]>=sizeof(Replacement)-1) break;
  806                 memcpy(Replacement+repl_idx,name+ovector[sub],ovector[sub+1]-ovector[sub]);
  807                 repl_idx+=ovector[sub+1]-ovector[sub];
  808                 continue;
  809             }
  810         }
  811         if (repl_idx>=sizeof(Replacement)-1) break;
  812         Replacement[repl_idx++]=str[i];
  813     }
  814     Replacement[repl_idx]='\0';
  815     return(Replacement);
  816 }
  817 #endif
  818 
  819 const char *Alias_Replace(struct AliasStruct *AliasData,const char *Name)
  820 {
  821     struct AliasItemStruct *alias;
  822     int type;
  823     unsigned char ipv4[4];
  824     unsigned short int ipv6[8];
  825     int len;
  826     char lname[MAX_ALIAS_LEN];
  827 
  828     if (!AliasData) return(Name);
  829     for (len=0 ; len<sizeof(lname)-1 && Name[len] ; len++) lname[len]=tolower(Name[len]);
  830     lname[len]='\0';
  831 
  832     type=extract_address_mask(Name,NULL,ipv4,ipv6,NULL,NULL);
  833 
  834     for (alias=AliasData->First ; alias ; alias=alias->Next) {
  835         if (type==2) {
  836             if (alias->Type==ALIASTYPE_Ipv4 && Alias_MatchIpv4(alias,ipv4))
  837                 return(alias->Alias);
  838         }
  839         if (type==3) {
  840             if (alias->Type==ALIASTYPE_Ipv6 && Alias_MatchIpv6(alias,ipv6))
  841                 return(alias->Alias);
  842         }
  843 #ifdef USE_PCRE
  844         if (alias->Type==ALIASTYPE_Pcre) {
  845             const char *Result=Alias_MatchRegex(alias,Name);
  846             if (Result) return(Result);
  847         }
  848 #endif
  849         if (alias->Type==ALIASTYPE_Name && Alias_MatchName(alias,lname,len))
  850             return(alias->Alias);
  851     }
  852     return(Name);
  853 }