]> git.ipfire.org Git - thirdparty/sarg.git/blob - alias.c
Update the man page
[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 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 }