]> git.ipfire.org Git - thirdparty/sarg.git/blob - alias.c
Rename configure.in as configure.ac
[thirdparty/sarg.git] / alias.c
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
501 // find the pattern
502 Delimiter=*buf++;
503 for (End=buf ; *End && *End!=Delimiter ; End++) {
504 if (*End=='\\') {
505 if (End[1]=='\0') {
506 debuga(__FILE__,__LINE__,_("Invalid NUL character found in regular expression\n"));
507 return(-1);
508 }
509 End++; //ignore the escaped character
510 }
511 }
512 if (*End!=Delimiter) {
513 debuga(__FILE__,__LINE__,_("Unterminated regular expression\n"));
514 return(-1);
515 }
516 *End++='\0';
517
518 // find the alias
519 for (Replace=End ; *Replace==' ' || *Replace=='\t' ; Replace++);
520 for (End=Replace ; *End && (unsigned char)*End>' ' ; End++);
521 *End='\0';
522
523 // store it
524 new_alias=malloc(sizeof(*new_alias));
525 if (!new_alias) {
526 debuga(__FILE__,__LINE__,_("Not enough memory to store the host name aliasing directives\n"));
527 return(-1);
528 }
529 new_alias->Type=ALIASTYPE_Pcre;
530 new_alias->Next=NULL;
531 new_alias->Regex.Re=pcre_compile(buf,0,&PcreError,&ErrorOffset,NULL);
532 if (new_alias->Regex.Re==NULL) {
533 debuga(__FILE__,__LINE__,_("Failed to compile the regular expression \"%s\": %s\n"),buf,PcreError);
534 free(new_alias);
535 return(-1);
536 }
537 len=strlen(Replace);
538 tmp=malloc(len+2);
539 if (!tmp) {
540 debuga(__FILE__,__LINE__,_("Not enough memory to store the host name aliasing directives\n"));
541 pcre_free(new_alias->Regex.Re);
542 return(-1);
543 }
544 tmp[0]=ALIAS_PREFIX;
545 memcpy(tmp+1,Replace,len);
546 tmp[len+1]='\0';
547 new_alias->Alias=StringBuffer_Store(AliasData->StringBuffer,tmp);
548 free(tmp);
549 if (!new_alias->Alias) {
550 debuga(__FILE__,__LINE__,_("Not enough memory to store the regex aliasing directives\n"));
551 free(new_alias);
552 return(-1);
553 }
554
555 new_alias->Regex.SubPartern=false;
556 for (i=1 ; tmp[i] ; i++)
557 // both the sed \1 and the perl $1 replacement operators are accepted
558 if ((tmp[i]=='\\' || tmp[i]=='$') && isdigit(tmp[i+1])) {
559 new_alias->Regex.SubPartern=true;
560 break;
561 }
562
563 // chain it
564 prev_alias=&AliasData->First;
565 for (alias=AliasData->First ; alias ; alias=alias->Next)
566 prev_alias=&alias->Next;
567 *prev_alias=new_alias;
568
569 return(1);
570 }
571 #endif
572
573 /*!
574 Store an alias in the corresponding list.
575
576 \param String The string to parse and store.
577
578 \retval 0 No error.
579 \retval -1 Error in file.
580 \retval -2 Unknown string type to store.
581 */
582 int Alias_Store(struct AliasStruct *AliasData,char *String)
583 {
584 int type;
585 const char *name;
586 unsigned char ipv4[4];
587 unsigned short int ipv6[8];
588 int nbits;
589 const char *next;
590 int Error=-2;
591
592 if (*String=='#' || *String==';') return(0);
593
594 if (strncasecmp(String,"re:",3)==0) {
595 #ifdef USE_PCRE
596 if (Alias_StoreRegexp(AliasData,String+3)<0)
597 return(-1);
598 #else
599 debuga(__FILE__,__LINE__,_("PCRE not compiled in therefore the regular expressions are not available to alias items\n"));
600 return(-1);
601 #endif
602 }
603 else
604 {
605 type=extract_address_mask(String,&name,ipv4,ipv6,&nbits,&next);
606 if (type==1) {
607 Error=Alias_StoreName(AliasData,name,next);
608 } else if (type==2) {
609 Error=Alias_StoreIpv4(AliasData,ipv4,nbits,next);
610 } else if (type==3) {
611 Error=Alias_StoreIpv6(AliasData,ipv6,nbits,next);
612 } else {
613 return(-1);
614 }
615 if (Error<0) return(-1);
616 }
617 return(0);
618 }
619
620 /*!
621 Print the list of the aliases stored in the object.
622
623 \param AliasData Object created by Alias_Create() and
624 containing the aliases stored by Alias_Store().
625 */
626 void Alias_PrintList(struct AliasStruct *AliasData)
627 {
628 struct AliasItemStruct *alias;
629
630 for (alias=AliasData->First ; alias ; alias=alias->Next) {
631 switch (alias->Type)
632 {
633 case ALIASTYPE_Name:
634 debuga(__FILE__,__LINE__,_(" %s => %s\n"),alias->Name.Mask,alias->Alias);
635 break;
636 case ALIASTYPE_Ipv4:
637 debuga(__FILE__,__LINE__,_(" %d.%d.%d.%d/%d => %s\n"),alias->Ipv4.Ip[0],alias->Ipv4.Ip[1],alias->Ipv4.Ip[2],
638 alias->Ipv4.Ip[3],alias->Ipv4.NBits,alias->Alias);
639 break;
640 case ALIASTYPE_Ipv6:
641 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],
642 alias->Ipv6.Ip[3],alias->Ipv6.Ip[4],alias->Ipv6.Ip[5],alias->Ipv6.Ip[6],alias->Ipv6.Ip[7],
643 alias->Ipv6.NBits,alias->Alias);
644 break;
645 case ALIASTYPE_Pcre:
646 debuga(__FILE__,__LINE__,_(" Re => %s\n"),alias->Alias);
647 break;
648 }
649 }
650 }
651
652 /*!
653 Replace the name by its alias if it is in our list.
654
655 \param name The name to find in the list.
656
657 \return The pointer to the name or its alias.
658 */
659 static bool Alias_MatchName(struct AliasItemStruct *alias,const char *name,int len)
660 {
661 int k;
662 const char *Searched;
663 const char *Candidate;
664
665 if (!alias->Name.Wildcards)
666 {
667 if (len!=alias->Name.MinLen) return(false);
668 return(strcmp(name,alias->Name.Mask)==0);
669 }
670 if (len<alias->Name.MinLen) return(false);
671 Candidate=name;
672 Searched=alias->Name.Mask;
673 if (Searched[0]!='*')
674 {
675 while (*Searched && *Candidate && *Searched!='*')
676 {
677 if (Searched[0]!=Candidate[0]) return(false);
678 Searched++;
679 Candidate++;
680 }
681 }
682 if (Searched[0]=='*') Searched++;
683 while (Searched[0] && Candidate[0])
684 {
685 while (Candidate[0] && Candidate[0]!=Searched[0]) Candidate++;
686 for (k=0 ; Candidate[k] && Searched[k] && Searched[k]!='*' && Searched[k]==Candidate[k] ; k++);
687 if (Candidate[k]=='\0')
688 {
689 return(Searched[k]=='\0' || (Searched[k]=='*' && Searched[k+1]=='\0'));
690 }
691 if (Searched[k]=='\0') return(false);
692 if (Searched[k]=='*')
693 {
694 Searched+=k+1;
695 Candidate+=k;
696 }
697 else
698 Candidate++;
699 }
700 return(Searched[0]=='\0');
701 }
702
703 /*!
704 Replace the IPv4 address by its alias if it is in our list.
705
706 \param url The host name.
707 \param ipv4 The address.
708
709 \return The pointer to the host name or its alias.
710 */
711 static bool Alias_MatchIpv4(struct AliasItemStruct *alias,unsigned char *ipv4)
712 {
713 int len;
714 int n,m;
715
716 len=alias->Ipv4.NBits;
717 n=len/8;
718 m=len%8;
719 if (n>0 && memcmp(ipv4,alias->Ipv4.Ip,n)!=0) return(false);
720 if (m!=0 && ((ipv4[n] ^ alias->Ipv4.Ip[n]) & (0xFFU<<(8-m)))!=0) return(false);
721 return(true);
722 }
723
724 /*!
725 Replace the IPv6 address by its alias if it is in our list.
726
727 \param url The host name.
728 \param ipv6 The address.
729
730 \return The pointer to the host name or its alias.
731 */
732 static bool Alias_MatchIpv6(struct AliasItemStruct *alias,unsigned short int *ipv6)
733 {
734 int len;
735 int i;
736
737 len=alias->Ipv6.NBits;
738 for (i=len/16-1 ; i>=0 && ipv6[i]==alias->Ipv6.Ip[i] ; i--);
739 if (i<0) {
740 i=len/16;
741 if (i>=8 || len%16==0 || ((ipv6[i] ^ alias->Ipv6.Ip[i]) & (0xFFFF<<(len-i*16)))==0) {
742 return(true);
743 }
744 }
745 return(false);
746 }
747
748 #ifdef USE_PCRE
749 /*!
750 Replace the host name by its alias if it is in our list.
751
752 \param url_ptr A pointer to the host name to match. It is replaced
753 by a pointer to the alias if a match is found.
754
755 \return A pointer to the replacement string or NULL if the regex
756 doesn't match.
757
758 \warning The function is not thread safe as it may return a static
759 internal buffer.
760 */
761 static const char *Alias_MatchRegex(struct AliasItemStruct *alias,const char *name)
762 {
763 int nmatches;
764 int len;
765 int ovector[30];//size must be a multiple of 3
766 static char Replacement[1024];
767 const char *str;
768 int i;
769 int sub;
770 int repl_idx;
771
772 len=strlen(name);
773 nmatches=pcre_exec(alias->Regex.Re,NULL,name,len,0,0,ovector,sizeof(ovector)/sizeof(ovector[0]));
774 if (nmatches<0) return(NULL);
775
776 if (nmatches==0) nmatches=(int)(sizeof(ovector)/sizeof(ovector[0]))/3*2; //only 2/3 of the vector is used by pcre_exec
777 if (nmatches==1 || !alias->Regex.SubPartern) { //no subpattern to replace
778 return(alias->Alias);
779 }
780
781 repl_idx=0;
782 str=alias->Alias;
783 for (i=0 ; str[i] ; i++) {
784 // both the sed \1 and the perl $1 replacement operators are accepted
785 if ((str[i]=='\\' || str[i]=='$') && isdigit(str[i+1])) {
786 sub=str[++i]-'0';
787 if (sub>=1 && sub<=nmatches) {
788 /*
789 * ovector[sub] is the start position of the match.
790 * ovector[sub+1] is the end position of the match.
791 */
792 sub<<=1;
793 if (repl_idx+ovector[sub+1]-ovector[sub]>=sizeof(Replacement)-1) break;
794 memcpy(Replacement+repl_idx,name+ovector[sub],ovector[sub+1]-ovector[sub]);
795 repl_idx+=ovector[sub+1]-ovector[sub];
796 continue;
797 }
798 }
799 if (repl_idx>=sizeof(Replacement)-1) break;
800 Replacement[repl_idx++]=str[i];
801 }
802 Replacement[repl_idx]='\0';
803 return(Replacement);
804 }
805 #endif
806
807 const char *Alias_Replace(struct AliasStruct *AliasData,const char *Name)
808 {
809 struct AliasItemStruct *alias;
810 int type;
811 unsigned char ipv4[4];
812 unsigned short int ipv6[8];
813 int len;
814 char lname[MAX_ALIAS_LEN];
815
816 if (!AliasData) return(Name);
817 for (len=0 ; len<sizeof(lname)-1 && Name[len] ; len++) lname[len]=tolower(Name[len]);
818 lname[len]='\0';
819
820 type=extract_address_mask(Name,NULL,ipv4,ipv6,NULL,NULL);
821
822 for (alias=AliasData->First ; alias ; alias=alias->Next) {
823 if (type==2) {
824 if (alias->Type==ALIASTYPE_Ipv4 && Alias_MatchIpv4(alias,ipv4))
825 return(alias->Alias);
826 }
827 if (type==3) {
828 if (alias->Type==ALIASTYPE_Ipv6 && Alias_MatchIpv6(alias,ipv6))
829 return(alias->Alias);
830 }
831 #ifdef USE_PCRE
832 if (alias->Type==ALIASTYPE_Pcre) {
833 const char *Result=Alias_MatchRegex(alias,Name);
834 if (Result) return(Result);
835 }
836 #endif
837 if (alias->Type==ALIASTYPE_Name && Alias_MatchName(alias,lname,len))
838 return(alias->Alias);
839 }
840 return(Name);
841 }