"Fossies" - the Fresh Open Source Software Archive

Member "sarg-2.4.0/url.c" (30 Jan 2017, 24198 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 "url.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.3.11_vs_2.4.0.

    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 #ifdef HAVE_PCRE_H
   30 #include <pcre.h>
   31 #define USE_PCRE
   32 #endif
   33 
   34 /*!
   35 A host name and the name to report.
   36 */
   37 struct hostalias_name
   38 {
   39     //! The next host name in the list or NULL for the last item.
   40     struct hostalias_name *Next;
   41     //! The minimum length of a candidate host name.
   42     int MinLen;
   43     //! The length of the constant part at the beginning of the mask.
   44     int PrefixLen;
   45     //! The length of the constant part at the end of the mask.
   46     int SuffixLen;
   47     //! The first part of the mask of the host name.
   48     const char *HostName_Prefix;
   49     //! The second part of the mask of the host name.
   50     const char *HostName_Suffix;
   51     //! The replacement name.
   52     const char *Alias;
   53 };
   54 
   55 /*!
   56 An IPv4 address and the name to report.
   57 */
   58 struct hostalias_ipv4
   59 {
   60     //! The next host name in the list or NULL for the last item.
   61     struct hostalias_ipv4 *Next;
   62     //! The IP address.
   63     unsigned char Ip[4];
   64     //! The number of bits in the prefix.
   65     int NBits;
   66     //! The replacement name.
   67     const char *Alias;
   68 };
   69 
   70 /*!
   71 An IPv6 address and the name to report.
   72 */
   73 struct hostalias_ipv6
   74 {
   75     //! The next host name in the list or NULL for the last item.
   76     struct hostalias_ipv6 *Next;
   77     //! The IP address.
   78     unsigned short Ip[8];
   79     //! The number of bits in the prefix.
   80     int NBits;
   81     //! The replacement name.
   82     const char *Alias;
   83 };
   84 
   85 #ifdef USE_PCRE
   86 /*!
   87 A regular expression.
   88 */
   89 struct hostalias_regex
   90 {
   91     //! The next regular expression to test.
   92     struct hostalias_regex *Next;
   93     //! The regular expression to match against the host name.
   94     pcre *Re;
   95     //! The replacement name.
   96     const char *Alias;
   97     //! \c True if this regular expression contains at least one subpattern
   98     bool SubPartern;
   99 };
  100 #endif
  101 
  102 //! The first host name.
  103 static struct hostalias_name *FirstAliasName=NULL;
  104 //! The first IPv4 address.
  105 static struct hostalias_ipv4 *FirstAliasIpv4=NULL;
  106 //! The first IPvĀ§ address.
  107 static struct hostalias_ipv6 *FirstAliasIpv6=NULL;
  108 
  109 #ifdef USE_PCRE
  110 static struct hostalias_regex *FirstAliasRe=NULL;
  111 #endif
  112 
  113 /*!
  114   Store a name to alias.
  115 
  116   \param name The name to match including the wildcard.
  117   \param next A pointer to the first character after the name.
  118 
  119   \retval 1 Alias added.
  120   \retval 0 Ignore the line.
  121   \retval -1 Error.
  122  */
  123 static int Alias_StoreName(const char *name,const char *next)
  124 {
  125     const char *NameBegin;
  126     const char *NameBeginE;
  127     const char *NameEnd;
  128     const char *NameEndE;
  129     const char *Replace;
  130     const char *ReplaceE;
  131     const char *str;
  132     char sep;
  133     struct hostalias_name *alias;
  134     struct hostalias_name *new_alias;
  135     struct hostalias_name *prev_alias;
  136     char *tmp;
  137     int len;
  138 
  139     if (*name=='#' || *name==';') return(0);
  140 
  141     // get host name and split at the wildcard
  142     NameBegin=name;
  143     for (str=NameBegin ; str<next && (unsigned char)*str>' ' && *str!='*' ; str++);
  144     NameBeginE=str;
  145     if (NameBegin==NameBeginE) NameBegin=NULL;
  146     if (str<next && *str=='*') {
  147         NameEnd=++str;
  148         while (str<next && (unsigned char)*str>' ') {
  149             if (*str=='*') {
  150                 debuga(__FILE__,__LINE__,_("Host name alias \"%s*%s\" contains too many wildcards (*)\n"),NameBegin,NameEnd);
  151                 return(-1);
  152             }
  153             str++;
  154         }
  155         NameEndE=str;
  156         if (NameEnd==NameEndE) {
  157             debuga(__FILE__,__LINE__,_("Host name alias \"%*s\" must not end with a wildcard\n"),(int)(next-name),name);
  158             return(-1);
  159         }
  160     } else {
  161         NameEnd=NULL;
  162     }
  163     while (str<next && (unsigned char)*str<=' ') str++;
  164     if (!NameBegin && !NameEnd) return(0);
  165 
  166     // get the alias
  167     sep=*next;
  168     if (sep==' ' || sep=='\t') {
  169         Replace=next;
  170         while (*Replace==' ' || *Replace=='\t') Replace++;
  171         if ((unsigned char)*Replace<' ') {
  172             Replace=NULL;
  173         } else {
  174             for (str=Replace ; *str && (unsigned char)*str>=' ' ; str++);
  175             ReplaceE=str;
  176         }
  177     } else
  178         Replace=NULL;
  179 
  180     if (NameBegin) {
  181         len=(int)(NameBeginE-NameBegin);
  182         tmp=malloc(len+1);
  183         if (!tmp) {
  184             debuga(__FILE__,__LINE__,_("Not enough memory to store the host name aliasing directives\n"));
  185             return(-1);
  186         }
  187         memcpy(tmp,NameBegin,len);
  188         tmp[len]='\0';
  189         NameBegin=tmp;
  190     }
  191     if (NameEnd) {
  192         len=(int)(NameEndE-NameEnd);
  193         tmp=malloc(len+1);
  194         if (!tmp) {
  195             if (NameBegin) free((void*)NameBegin);
  196             debuga(__FILE__,__LINE__,_("Not enough memory to store the host name aliasing directives\n"));
  197             return(-1);
  198         }
  199         memcpy(tmp,NameEnd,len);
  200         tmp[len]='\0';
  201         NameEnd=tmp;
  202     }
  203 
  204     // ignore duplicates
  205     prev_alias=NULL;
  206     for (alias=FirstAliasName ; alias ; alias=alias->Next) {
  207         if (((NameBegin && alias->HostName_Prefix && !strcmp(NameBegin,alias->HostName_Prefix)) || (!NameBegin && !alias->HostName_Prefix)) &&
  208             ((NameEnd && alias->HostName_Suffix && !strcmp(NameEnd,alias->HostName_Suffix)) || (!NameEnd && !alias->HostName_Suffix))) {
  209             if (NameBegin) free((void*)NameBegin);
  210             return(0);
  211         }
  212         prev_alias=alias;
  213     }
  214 
  215     // insert into the list
  216     new_alias=malloc(sizeof(*new_alias));
  217     if (!new_alias) {
  218         if (NameBegin) free((void*)NameBegin);
  219         if (NameEnd) free((void*)NameEnd);
  220         debuga(__FILE__,__LINE__,_("Not enough memory to store the host name aliasing directives\n"));
  221         return(-1);
  222     }
  223     new_alias->MinLen=0;
  224     if (NameBegin) {
  225         new_alias->HostName_Prefix=NameBegin;
  226         new_alias->MinLen+=strlen(NameBegin);
  227         new_alias->PrefixLen=strlen(NameBegin);
  228     } else {
  229         new_alias->HostName_Prefix=NULL;
  230         new_alias->PrefixLen=0;
  231     }
  232     if (NameEnd) {
  233         new_alias->HostName_Suffix=NameEnd;
  234         new_alias->MinLen+=strlen(NameEnd)+1;
  235         new_alias->SuffixLen=strlen(NameEnd);
  236     } else {
  237         new_alias->HostName_Suffix=NULL;
  238         new_alias->SuffixLen=0;
  239     }
  240     if (Replace) {
  241         len=(int)(ReplaceE-Replace);
  242         tmp=malloc(len+2);
  243         if (!tmp) {
  244             debuga(__FILE__,__LINE__,_("Not enough memory to store the host name aliasing directives\n"));
  245             return(-1);
  246         }
  247         tmp[0]=ALIAS_PREFIX;
  248         memcpy(tmp+1,Replace,len);
  249         tmp[len+1]='\0';
  250         new_alias->Alias=tmp;
  251     } else {
  252         tmp=malloc(new_alias->MinLen+2);
  253         if (!tmp) {
  254             debuga(__FILE__,__LINE__,_("Not enough memory to store the host name aliasing directives\n"));
  255             return(-1);
  256         }
  257         tmp[0]=ALIAS_PREFIX;
  258         if (new_alias->HostName_Prefix) strcpy(tmp+1,new_alias->HostName_Prefix);
  259         if (new_alias->HostName_Suffix) {
  260             tmp[new_alias->PrefixLen+1]='*';
  261             strcpy(tmp+new_alias->PrefixLen+2,new_alias->HostName_Suffix);
  262         }
  263         new_alias->Alias=tmp;
  264     }
  265 
  266     new_alias->Next=NULL;
  267     if (prev_alias)
  268         prev_alias->Next=new_alias;
  269     else
  270         FirstAliasName=new_alias;
  271     return(1);
  272 }
  273 
  274 /*!
  275   Store a IPv4 to alias.
  276 
  277   \param ipv4 The IPv4 to match.
  278   \param nbits The number of bits in the prefix
  279   \param next A pointer to the first character after the address.
  280 
  281   \retval 1 Alias added.
  282   \retval 0 Ignore the line.
  283   \retval -1 Error.
  284  */
  285 static int Alias_StoreIpv4(unsigned char *ipv4,int nbits,const char *next)
  286 {
  287     const char *Replace;
  288     const char *ReplaceE;
  289     const char *str;
  290     struct hostalias_ipv4 *alias;
  291     struct hostalias_ipv4 *new_alias;
  292     struct hostalias_ipv4 *prev_alias;
  293     int i;
  294     char *tmp;
  295     int len;
  296 
  297     // get the alias
  298     Replace=next;
  299     while (*Replace==' ' || *Replace=='\t') Replace++;
  300     if ((unsigned char)*Replace<' ') {
  301         Replace=NULL;
  302     } else {
  303         for (str=Replace ; *str && (unsigned char)*str>=' ' ; str++);
  304         ReplaceE=str;
  305     }
  306 
  307     // store more restrictive range first
  308     prev_alias=NULL;
  309     for (alias=FirstAliasIpv4 ; alias ; alias=alias->Next) {
  310         i=(nbits<alias->NBits) ? nbits : alias->NBits;
  311         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) {
  312             break;
  313         }
  314         prev_alias=alias;
  315     }
  316 
  317     // insert into the list
  318     new_alias=malloc(sizeof(*new_alias));
  319     if (!new_alias) {
  320         debuga(__FILE__,__LINE__,_("Not enough memory to store the host name aliasing directives\n"));
  321         return(-1);
  322     }
  323     memcpy(new_alias->Ip,ipv4,4);
  324     new_alias->NBits=nbits;
  325     if (Replace) {
  326         len=(int)(ReplaceE-Replace);
  327         tmp=malloc(len+2);
  328         if (!tmp) {
  329             debuga(__FILE__,__LINE__,_("Not enough memory to store the host name aliasing directives\n"));
  330             return(-1);
  331         }
  332         tmp[0]=ALIAS_PREFIX;
  333         memcpy(tmp+1,Replace,len);
  334         tmp[len+1]='\0';
  335         new_alias->Alias=tmp;
  336     } else {
  337         tmp=malloc(5*4+1);
  338         if (!tmp) {
  339             debuga(__FILE__,__LINE__,_("Not enough memory to store the host name aliasing directives\n"));
  340             return(-1);
  341         }
  342         sprintf(tmp,"%c%d.%d.%d.%d/%d",ALIAS_PREFIX,ipv4[0],ipv4[1],ipv4[2],ipv4[3],nbits);
  343         new_alias->Alias=tmp;
  344     }
  345 
  346     if (prev_alias) {
  347         new_alias->Next=prev_alias->Next;
  348         prev_alias->Next=new_alias;
  349     } else {
  350         new_alias->Next=NULL;
  351         FirstAliasIpv4=new_alias;
  352     }
  353     return(1);
  354 }
  355 
  356 /*!
  357   Store a IPv6 to alias.
  358 
  359   \param ipv6 The IPv6 to match.
  360   \param nbits The number of bits in the prefix
  361   \param next A pointer to the first character after the address.
  362 
  363   \retval 1 Alias added.
  364   \retval 0 Ignore the line.
  365   \retval -1 Error.
  366  */
  367 static int Alias_StoreIpv6(unsigned short *ipv6,int nbits,const char *next)
  368 {
  369     const char *Replace;
  370     const char *ReplaceE;
  371     const char *str;
  372     struct hostalias_ipv6 *alias;
  373     struct hostalias_ipv6 *new_alias;
  374     struct hostalias_ipv6 *prev_alias;
  375     int i;
  376     char *tmp;
  377     int len;
  378 
  379     // get the alias
  380     Replace=next;
  381     while (*Replace==' ' || *Replace=='\t') Replace++;
  382     if ((unsigned char)*Replace<' ') {
  383         Replace=NULL;
  384     } else {
  385         for (str=Replace ; *str && (unsigned char)*str>=' ' ; str++);
  386         ReplaceE=str;
  387     }
  388 
  389     // store more restrictive range first
  390     prev_alias=NULL;
  391     for (alias=FirstAliasIpv6 ; alias ; alias=alias->Next) {
  392         i=(nbits<alias->NBits) ? nbits : alias->NBits;
  393         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) {
  394             break;
  395         }
  396         prev_alias=alias;
  397     }
  398 
  399     // insert into the list
  400     new_alias=malloc(sizeof(*new_alias));
  401     if (!new_alias) {
  402         debuga(__FILE__,__LINE__,_("Not enough memory to store the host name aliasing directives\n"));
  403         return(-1);
  404     }
  405     memcpy(new_alias->Ip,ipv6,8*sizeof(unsigned short int));
  406     new_alias->NBits=nbits;
  407     if (Replace) {
  408         len=ReplaceE-Replace;
  409         tmp=malloc(len+2);
  410         if (!tmp) {
  411             debuga(__FILE__,__LINE__,_("Not enough memory to store the host name aliasing directives\n"));
  412             return(-1);
  413         }
  414         tmp[0]=ALIAS_PREFIX;
  415         memcpy(tmp+1,Replace,len);
  416         tmp[len+1]='\0';
  417         new_alias->Alias=tmp;
  418     } else {
  419         tmp=malloc(5*8+5);
  420         if (!tmp) {
  421             debuga(__FILE__,__LINE__,_("Not enough memory to store the host name aliasing directives\n"));
  422             return(-1);
  423         }
  424         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);
  425         new_alias->Alias=tmp;
  426     }
  427 
  428     if (prev_alias) {
  429         new_alias->Next=prev_alias->Next;
  430         prev_alias->Next=new_alias;
  431     } else {
  432         new_alias->Next=NULL;
  433         FirstAliasIpv6=new_alias;
  434     }
  435     return(1);
  436 }
  437 
  438 #ifdef USE_PCRE
  439 /*!
  440 Store a regular expression to match the alias.
  441 
  442 \retval 1 Alias added.
  443 \retval 0 Ignore the line.
  444 \retval -1 Error.
  445 */
  446 static int Alias_StoreRegexp(char *buf)
  447 {
  448     char Delimiter;
  449     char *End;
  450     struct hostalias_regex *alias;
  451     struct hostalias_regex *new_alias;
  452     struct hostalias_regex **prev_alias;
  453     const char *PcreError;
  454     int ErrorOffset;
  455     char *Replace;
  456     int len;
  457     char *tmp;
  458     int i;
  459 
  460     // find the pattern
  461     Delimiter=*buf++;
  462     for (End=buf ; *End && *End!=Delimiter ; End++) {
  463         if (*End=='\\') {
  464             if (End[1]=='\0') {
  465                 debuga(__FILE__,__LINE__,_("Invalid NUL character found in regular expression\n"));
  466                 return(-1);
  467             }
  468             End++; //ignore the escaped character
  469         }
  470     }
  471     if (*End!=Delimiter) {
  472         debuga(__FILE__,__LINE__,_("Unterminated regular expression\n"));
  473         return(-1);
  474     }
  475     *End++='\0';
  476 
  477     // find the alias
  478     for (Replace=End ; *Replace==' ' || *Replace=='\t' ; Replace++);
  479     for (End=Replace ; *End && (unsigned char)*End>' ' ; End++);
  480     *End='\0';
  481 
  482     // store it
  483     new_alias=malloc(sizeof(*new_alias));
  484     if (!new_alias) {
  485         debuga(__FILE__,__LINE__,_("Not enough memory to store the host name aliasing directives\n"));
  486         return(-1);
  487     }
  488     new_alias->Next=NULL;
  489     new_alias->Re=pcre_compile(buf,0,&PcreError,&ErrorOffset,NULL);
  490     if (new_alias->Re==NULL) {
  491         debuga(__FILE__,__LINE__,_("Failed to compile the regular expression \"%s\": %s\n"),buf,PcreError);
  492         free(new_alias);
  493         return(-1);
  494     }
  495     len=strlen(Replace);
  496     tmp=malloc(len+2);
  497     if (!tmp) {
  498         debuga(__FILE__,__LINE__,_("Not enough memory to store the host name aliasing directives\n"));
  499         pcre_free(new_alias->Re);
  500         return(-1);
  501     }
  502     tmp[0]=ALIAS_PREFIX;
  503     memcpy(tmp+1,Replace,len);
  504     tmp[len+1]='\0';
  505     new_alias->Alias=tmp;
  506 
  507     new_alias->SubPartern=false;
  508     for (i=1 ; tmp[i] ; i++)
  509         // both the sed \1 and the perl $1 replacement operators are accepted
  510         if ((tmp[i]=='\\' || tmp[i]=='$') && isdigit(tmp[i+1])) {
  511             new_alias->SubPartern=true;
  512             break;
  513         }
  514 
  515     // chain it
  516     prev_alias=&FirstAliasRe;
  517     for (alias=FirstAliasRe ; alias ; alias=alias->Next)
  518         prev_alias=&alias->Next;
  519     *prev_alias=new_alias;
  520 
  521     return(1);
  522 }
  523 #endif
  524 
  525 /*!
  526 Store an alias in the corresponding list.
  527 
  528 \param buf The string to parse and store.
  529 
  530 \retval 0 No error.
  531 \retval -1 Error in file.
  532 \retval -2 Unknown string type to store.
  533 */
  534 static int Alias_Store(char *buf)
  535 {
  536     int type;
  537     const char *name;
  538     unsigned char ipv4[4];
  539     unsigned short int ipv6[8];
  540     int nbits;
  541     const char *next;
  542     int Error=-2;
  543 
  544     if (strncasecmp(buf,"re:",3)==0) {
  545 #ifdef USE_PCRE
  546         if (Alias_StoreRegexp(buf+3)<0)
  547             return(-1);
  548         return(0);
  549 #else
  550         debuga(__FILE__,__LINE__,_("PCRE not compiled in therefore the regular expressions are not available in the host alias file\n"));
  551         return(-1);
  552 #endif
  553     }
  554     type=extract_address_mask(buf,&name,ipv4,ipv6,&nbits,&next);
  555     if (type<0) {
  556         return(-1);
  557     }
  558 
  559     if (type==1) {
  560         Error=Alias_StoreName(name,next);
  561     } else if (type==2) {
  562         Error=Alias_StoreIpv4(ipv4,nbits,next);
  563     } else if (type==3) {
  564         Error=Alias_StoreIpv6(ipv6,nbits,next);
  565     }
  566     if (Error<0) return(-1);
  567     return(0);
  568 }
  569 
  570 /*!
  571 Read the file containing the host names to alias in the report.
  572 
  573 \param Filename The name of the file.
  574 */
  575 void read_hostalias(const char *Filename)
  576 {
  577     FileObject *fi;
  578     longline line;
  579     char *buf;
  580 
  581     if (debug) debuga(__FILE__,__LINE__,_("Reading host alias file \"%s\"\n"),Filename);
  582     fi=FileObject_Open(Filename);
  583     if (!fi) {
  584         debuga(__FILE__,__LINE__,_("Cannot read host name alias file \"%s\": %s\n"),Filename,FileObject_GetLastOpenError());
  585         exit(EXIT_FAILURE);
  586     }
  587 
  588     if ((line=longline_create())==NULL) {
  589         debuga(__FILE__,__LINE__,_("Not enough memory to read file \"%s\"\n"),Filename);
  590         exit(EXIT_FAILURE);
  591     }
  592 
  593     while ((buf=longline_read(fi,line)) != NULL) {
  594         if (Alias_Store(buf)<0) {
  595             debuga(__FILE__,__LINE__,_("While reading \"%s\"\n"),Filename);
  596             exit(EXIT_FAILURE);
  597         }
  598     }
  599 
  600     longline_destroy(&line);
  601     if (FileObject_Close(fi)) {
  602         debuga(__FILE__,__LINE__,_("Read error in \"%s\": %s\n"),Filename,FileObject_GetLastCloseError());
  603         exit(EXIT_FAILURE);
  604     }
  605 
  606     if (debug) {
  607         struct hostalias_name *alias1;
  608         struct hostalias_ipv4 *alias4;
  609         struct hostalias_ipv6 *alias6;
  610 
  611         debuga(__FILE__,__LINE__,_("List of host names to alias:\n"));
  612         for (alias1=FirstAliasName ; alias1 ; alias1=alias1->Next) {
  613             if (alias1->HostName_Prefix && alias1->HostName_Suffix)
  614                 debuga(__FILE__,__LINE__,_("  %s*%s => %s\n"),alias1->HostName_Prefix,alias1->HostName_Suffix,alias1->Alias);
  615             else if (alias1->HostName_Prefix)
  616                 debuga(__FILE__,__LINE__,_("  %s => %s\n"),alias1->HostName_Prefix,alias1->Alias);
  617             else
  618                 debuga(__FILE__,__LINE__,_("  *%s => %s\n"),alias1->HostName_Suffix,alias1->Alias);
  619         }
  620         for (alias4=FirstAliasIpv4 ; alias4 ; alias4=alias4->Next) {
  621             debuga(__FILE__,__LINE__,_("  %d.%d.%d.%d/%d => %s\n"),alias4->Ip[0],alias4->Ip[1],alias4->Ip[2],alias4->Ip[3],alias4->NBits,alias4->Alias);
  622         }
  623         for (alias6=FirstAliasIpv6 ; alias6 ; alias6=alias6->Next) {
  624             debuga(__FILE__,__LINE__,_("  %x:%x:%x:%x:%x:%x:%x:%x/%d => %s\n"),alias6->Ip[0],alias6->Ip[1],alias6->Ip[2],alias6->Ip[3],
  625                 alias6->Ip[4],alias6->Ip[5],alias6->Ip[6],alias6->Ip[7],alias6->NBits,alias6->Alias);
  626         }
  627     }
  628 }
  629 
  630 /*!
  631 Free the memory allocated by read_hostalias().
  632 */
  633 void free_hostalias(void)
  634 {
  635     {
  636         struct hostalias_name *alias1;
  637         struct hostalias_name *next1;
  638 
  639         for (alias1=FirstAliasName ; alias1 ; alias1=next1) {
  640             next1=alias1->Next;
  641             if (alias1->HostName_Prefix) free((void *)alias1->HostName_Prefix);
  642             if (alias1->HostName_Suffix) free((void *)alias1->HostName_Suffix);
  643             free((void *)alias1->Alias);
  644             free(alias1);
  645         }
  646         FirstAliasName=NULL;
  647     }
  648     {
  649         struct hostalias_ipv4 *alias4;
  650         struct hostalias_ipv4 *next4;
  651 
  652         for (alias4=FirstAliasIpv4 ; alias4 ; alias4=next4) {
  653             next4=alias4->Next;
  654             free((void *)alias4->Alias);
  655             free(alias4);
  656         }
  657         FirstAliasIpv4=NULL;
  658     }
  659     {
  660         struct hostalias_ipv6 *alias6;
  661         struct hostalias_ipv6 *next6;
  662 
  663         for (alias6=FirstAliasIpv6 ; alias6 ; alias6=next6) {
  664             next6=alias6->Next;
  665             free((void *)alias6->Alias);
  666             free(alias6);
  667         }
  668         FirstAliasIpv6=NULL;
  669     }
  670 #ifdef USE_PCRE
  671     {
  672         struct hostalias_regex *alias;
  673         struct hostalias_regex *next;
  674 
  675         for (alias=FirstAliasRe ; alias ; alias=next) {
  676             next=alias->Next;
  677             pcre_free(alias->Re);
  678             free((void *)alias->Alias);
  679             free(alias);
  680         }
  681         FirstAliasRe=NULL;
  682     }
  683 #endif
  684 }
  685 
  686 /*!
  687 Replace the host name by its alias if it is in our list.
  688 
  689 \param url The host name.
  690 
  691 \return The pointer to the host name or its alias.
  692 */
  693 static const char *alias_url_name(const char *url,const char *next)
  694 {
  695     struct hostalias_name *alias;
  696     int len;
  697 
  698     len=(int)(next-url);
  699     for (alias=FirstAliasName ; alias ; alias=alias->Next) {
  700         if (len<alias->MinLen) continue;
  701         if (alias->HostName_Prefix) {
  702             if (alias->HostName_Suffix) {
  703                 if (strncasecmp(url,alias->HostName_Prefix,alias->PrefixLen)==0 &&
  704                     strncasecmp(url+(len-alias->SuffixLen),alias->HostName_Suffix,len)==0) {
  705                     return(alias->Alias);
  706                 }
  707             } else {
  708                 if (len==alias->PrefixLen && strncasecmp(url,alias->HostName_Prefix,len)==0) {
  709                     return(alias->Alias);
  710                 }
  711             }
  712         } else if (strncasecmp(url+(len-alias->SuffixLen),alias->HostName_Suffix,len)==0) {
  713             return(alias->Alias);
  714         }
  715     }
  716     return(url);
  717 }
  718 
  719 /*!
  720 Replace the IPv4 address by its alias if it is in our list.
  721 
  722 \param url The host name.
  723 \param ipv4 The address.
  724 
  725 \return The pointer to the host name or its alias.
  726 */
  727 static const char *alias_url_ipv4(const char *url,unsigned char *ipv4)
  728 {
  729     struct hostalias_ipv4 *alias;
  730     int len;
  731 
  732     for (alias=FirstAliasIpv4 ; alias ; alias=alias->Next) {
  733         len=alias->NBits;
  734         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) {
  735             return(alias->Alias);
  736         }
  737     }
  738     return(url);
  739 }
  740 
  741 /*!
  742 Replace the IPv6 address by its alias if it is in our list.
  743 
  744 \param url The host name.
  745 \param ipv6 The address.
  746 
  747 \return The pointer to the host name or its alias.
  748 */
  749 static const char *alias_url_ipv6(const char *url,unsigned short int *ipv6)
  750 {
  751     struct hostalias_ipv6 *alias;
  752     int len;
  753     int i;
  754 
  755     for (alias=FirstAliasIpv6 ; alias ; alias=alias->Next) {
  756         len=alias->NBits;
  757         for (i=len/16-1 ; i>=0 && ipv6[i]==alias->Ip[i] ; i--);
  758         if (i>=0) continue;
  759         i=len/16;
  760         if (i>=8 || len%16==0 || ((ipv6[i] ^ alias->Ip[i]) & (0xFFFF<<(len-i*16)))==0) {
  761             return(alias->Alias);
  762         }
  763     }
  764     return(url);
  765 }
  766 
  767 #ifdef USE_PCRE
  768 /*!
  769 Replace the host name by its alias if it is in our list.
  770 
  771 \param url_ptr A pointer to the host name to match. It is replaced
  772 by a pointer to the alias if a match is found.
  773 
  774 \return \c True if a match is found or \c false if it failed.
  775 
  776 \warning The function is not thread safe as it may return a static
  777 internal buffer.
  778 */
  779 static bool alias_url_regex(const char **url_ptr)
  780 {
  781     struct hostalias_regex *alias;
  782     int nmatches;
  783     const char *url;
  784     int url_len;
  785     int ovector[30];//size must be a multiple of 3
  786     static char Replacement[1024];
  787     const char *str;
  788     int i;
  789     int sub;
  790     int repl_idx;
  791 
  792     url=*url_ptr;
  793     url_len=strlen(url);
  794     for (alias=FirstAliasRe ; alias ; alias=alias->Next) {
  795         nmatches=pcre_exec(alias->Re,NULL,url,url_len,0,0,ovector,sizeof(ovector)/sizeof(ovector[0]));
  796         if (nmatches>=0) {
  797             if (nmatches==0) nmatches=(int)(sizeof(ovector)/sizeof(ovector[0]))/3*2; //only 2/3 of the vector is used by pcre_exec
  798             if (nmatches==1 || !alias->SubPartern) { //no subpattern to replace
  799                 *url_ptr=alias->Alias;
  800             } else {
  801                 repl_idx=0;
  802                 str=alias->Alias;
  803                 for (i=0 ; str[i] ; i++) {
  804                     // both the sed \1 and the perl $1 replacement operators are accepted
  805                     if ((str[i]=='\\' || str[i]=='$') && isdigit(str[i+1])) {
  806                         sub=str[++i]-'0';
  807                         if (sub>=1 && sub<=nmatches) {
  808                             /*
  809                              * ovector[sub] is the start position of the match.
  810                              * ovector[sub+1] is the end position of the match.
  811                              */
  812                             sub<<=1;
  813                             if (repl_idx+ovector[sub+1]-ovector[sub]>=sizeof(Replacement)-1) break;
  814                             memcpy(Replacement+repl_idx,url+ovector[sub],ovector[sub+1]-ovector[sub]);
  815                             repl_idx+=ovector[sub+1]-ovector[sub];
  816                             continue;
  817                         }
  818                     }
  819                     if (repl_idx>=sizeof(Replacement)-1) break;
  820                     Replacement[repl_idx++]=str[i];
  821                 }
  822                 Replacement[repl_idx]='\0';
  823                 *url_ptr=Replacement;
  824             }
  825             return(true);
  826         }
  827     }
  828     return(false);
  829 }
  830 #endif
  831 
  832 /*!
  833 Find the beginning of the URL beyond the scheme://
  834 
  835 \param url The url possibly containing a scheme.
  836 
  837 \return The beginning of the url beyond the scheme.
  838 */
  839 const char *skip_scheme(const char *url)
  840 {
  841     const char *str;
  842 
  843     /*
  844     Skip any scheme:// at the beginning of the URL (see rfc2396 section 3.1).
  845     The underscore is not part of the standard but is found in the squid logs as cache_object://.
  846     */
  847     for (str=url ; *str && (isalnum(*str) || *str=='+' || *str=='-' || *str=='.' || *str=='_') ; str++);
  848     if (str[0]==':' && str[1]=='/' && str[2]=='/') {
  849         url=str+3;
  850         while (*url=='/') url++;
  851     }
  852     return(url);
  853 }
  854 
  855 /*!
  856 Get the part of the URL necessary to generate the report.
  857 
  858 \param url The URL as extracted from the report.
  859 \param full_url \c True to keep the whole URL. If \c false,
  860 the URL is truncated to only keep the host name and port number.
  861 */
  862 const char *process_url(const char *url,bool full_url)
  863 {
  864     static char short_url[1024];
  865     int i;
  866     const char *start;
  867     int type;
  868     unsigned char ipv4[4];
  869     unsigned short int ipv6[8];
  870     const char *next;
  871 
  872     start=skip_scheme(url);
  873     if (!full_url) {
  874         for (i=0 ; i<sizeof(short_url)-1 && start[i] && start[i]!='/' && start[i]!='?' ; i++)
  875             short_url[i]=start[i];
  876         short_url[i]='\0';
  877         start=short_url;
  878 #ifdef USE_PCRE
  879         if (FirstAliasRe) {
  880             if (alias_url_regex(&start)) return(start);
  881         }
  882 #endif
  883         type=extract_address_mask(start,NULL,ipv4,ipv6,NULL,&next);
  884         if (type==1) {
  885             if (FirstAliasName)
  886                 start=alias_url_name(start,next);
  887         } else if (type==2) {
  888             if (FirstAliasIpv4)
  889                 start=alias_url_ipv4(start,ipv4);
  890         } else if (type==3) {
  891             if (FirstAliasIpv6)
  892                 start=alias_url_ipv6(start,ipv6);
  893         }
  894     }
  895     return(start);
  896 }
  897 
  898 /*!
  899 Extract the host name from the URL.
  900 
  901 \param url The url whose host name must be extracted.
  902 \param hostname The buffer to store the host name.
  903 \param hostsize The size of the host name buffer.
  904 
  905 \note The function is stupid at this time. It just searches for the first slash
  906 in the URL and truncates the URL there. It doesn't take the protocol into account
  907 nor the port number nor any user or password information.
  908 */
  909 void url_hostname(const char *url,char *hostname,int hostsize)
  910 {
  911     int i;
  912 
  913     hostsize--;
  914     for (i=0 ; i<hostsize && url[i] && url[i]!='/' ; i++)
  915         hostname[i]=url[i];
  916     hostname[i]='\0';
  917 }
  918