]> git.ipfire.org Git - thirdparty/sarg.git/blame - alias.c
Optimize away a useless strcpy.
[thirdparty/sarg.git] / alias.c
CommitLineData
c4f0ea8f
FM
1/*
2 * SARG Squid Analysis Report Generator http://sarg.sourceforge.net
110ce984 3 * 1998, 2015
c4f0ea8f
FM
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
c4f0ea8f
FM
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/*!
40A host name and the name to report.
41*/
42struct 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/*!
53An IPv4 address and the name to report.
54*/
55struct 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/*!
64An IPv6 address and the name to report.
65*/
66struct 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/*!
76A regular expression.
77*/
78struct 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.
88enum aliasitem_type
89{
90 ALIASTYPE_Name,
91 ALIASTYPE_Ipv4,
92 ALIASTYPE_Ipv6,
93 ALIASTYPE_Pcre
94};
95
96//! \brief One item to group.
97struct 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.
121struct 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 */
137AliasObject 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 */
161void 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 */
202static 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)) {
af961877 250 debuga(__FILE__,__LINE__,_("Duplicate aliasing directive for name %s\n"),Name);
c4f0ea8f
FM
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) {
af961877 259 debuga(__FILE__,__LINE__,_("Not enough memory to store the user name aliasing directives\n"));
c4f0ea8f
FM
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) {
af961877 267 debuga(__FILE__,__LINE__,_("Not enough memory to store the user name aliasing directives\n"));
c4f0ea8f
FM
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) {
af961877 275 debuga(__FILE__,__LINE__,_("Not enough memory to store the user name aliasing directives\n"));
c4f0ea8f
FM
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 */
299static 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)
af961877 327 debuga(__FILE__,__LINE__,_("Duplicate aliasing directive for IPv4 address %d.%d.%d.%d/%d\n"),
c4f0ea8f
FM
328 ipv4[0],ipv4[1],ipv4[2],ipv4[3],nbits);
329 else
af961877 330 debuga(__FILE__,__LINE__,_("IPv4 aliasing directive ignored for IPv4 address %d.%d.%d.%d/%d as it is"
c4f0ea8f
FM
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) {
af961877 344 debuga(__FILE__,__LINE__,_("Not enough memory to store the host name aliasing directives\n"));
c4f0ea8f
FM
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) {
af961877 356 debuga(__FILE__,__LINE__,_("Not enough memory to store the host name aliasing directives\n"));
c4f0ea8f
FM
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) {
af961877 371 debuga(__FILE__,__LINE__,_("Not enough memory to store the IPv4 aliasing directives\n"));
c4f0ea8f
FM
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 */
395static 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)
af961877 423 debuga(__FILE__,__LINE__,_("Duplicate aliasing directive for IPv6 address %x:%x:%x:%x:%x:%x:%x:%x/%d\n"),
c4f0ea8f
FM
424 ipv6[0],ipv6[1],ipv6[2],ipv6[3],ipv6[4],ipv6[5],ipv6[6],ipv6[7],nbits);
425 else
af961877 426 debuga(__FILE__,__LINE__,_("IPv6 aliasing directive ignored for IPv6 address %x:%x:%x:%x:%x:%x:%x:%x/%d as it is"
c4f0ea8f
FM
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) {
af961877 440 debuga(__FILE__,__LINE__,_("Not enough memory to store the host name aliasing directives\n"));
c4f0ea8f
FM
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) {
af961877 451 debuga(__FILE__,__LINE__,_("Not enough memory to store the host name aliasing directives\n"));
c4f0ea8f
FM
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) {
af961877 466 debuga(__FILE__,__LINE__,_("Not enough memory to store the IPv6 aliasing directives\n"));
c4f0ea8f
FM
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/*!
481Store a regular expression to match the alias.
482
483\retval 1 Alias added.
484\retval 0 Ignore the line.
485\retval -1 Error.
486*/
487static 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;
7abbda48 500 int ReOption=0;
c4f0ea8f
FM
501
502 // find the pattern
503 Delimiter=*buf++;
504 for (End=buf ; *End && *End!=Delimiter ; End++) {
505 if (*End=='\\') {
506 if (End[1]=='\0') {
af961877 507 debuga(__FILE__,__LINE__,_("Invalid NUL character found in regular expression\n"));
c4f0ea8f
FM
508 return(-1);
509 }
510 End++; //ignore the escaped character
511 }
512 }
513 if (*End!=Delimiter) {
af961877 514 debuga(__FILE__,__LINE__,_("Unterminated regular expression\n"));
c4f0ea8f
FM
515 return(-1);
516 }
517 *End++='\0';
518
7abbda48
FM
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
c4f0ea8f
FM
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) {
af961877 538 debuga(__FILE__,__LINE__,_("Not enough memory to store the host name aliasing directives\n"));
c4f0ea8f
FM
539 return(-1);
540 }
541 new_alias->Type=ALIASTYPE_Pcre;
542 new_alias->Next=NULL;
7abbda48 543 new_alias->Regex.Re=pcre_compile(buf,ReOption,&PcreError,&ErrorOffset,NULL);
c4f0ea8f 544 if (new_alias->Regex.Re==NULL) {
af961877 545 debuga(__FILE__,__LINE__,_("Failed to compile the regular expression \"%s\": %s\n"),buf,PcreError);
c4f0ea8f
FM
546 free(new_alias);
547 return(-1);
548 }
549 len=strlen(Replace);
550 tmp=malloc(len+2);
551 if (!tmp) {
af961877 552 debuga(__FILE__,__LINE__,_("Not enough memory to store the host name aliasing directives\n"));
c4f0ea8f
FM
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) {
af961877 562 debuga(__FILE__,__LINE__,_("Not enough memory to store the regex aliasing directives\n"));
c4f0ea8f
FM
563 free(new_alias);
564 return(-1);
565 }
566
567 new_alias->Regex.SubPartern=false;
5d6479e9 568 for (i=0 ; Replace[i] ; i++)
c4f0ea8f 569 // both the sed \1 and the perl $1 replacement operators are accepted
5d6479e9 570 if ((Replace[i]=='\\' || Replace[i]=='$') && isdigit(Replace[i+1])) {
c4f0ea8f
FM
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/*!
586Store 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*/
594int 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
af961877 611 debuga(__FILE__,__LINE__,_("PCRE not compiled in therefore the regular expressions are not available to alias items\n"));
c4f0ea8f
FM
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 */
638void 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:
af961877 646 debuga(__FILE__,__LINE__,_(" %s => %s\n"),alias->Name.Mask,alias->Alias);
c4f0ea8f
FM
647 break;
648 case ALIASTYPE_Ipv4:
af961877 649 debuga(__FILE__,__LINE__,_(" %d.%d.%d.%d/%d => %s\n"),alias->Ipv4.Ip[0],alias->Ipv4.Ip[1],alias->Ipv4.Ip[2],
c4f0ea8f
FM
650 alias->Ipv4.Ip[3],alias->Ipv4.NBits,alias->Alias);
651 break;
652 case ALIASTYPE_Ipv6:
af961877 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],
c4f0ea8f
FM
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:
af961877 658 debuga(__FILE__,__LINE__,_(" Re => %s\n"),alias->Alias);
c4f0ea8f
FM
659 break;
660 }
661 }
662}
663
664/*!
665Replace 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*/
671static 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/*!
716Replace 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*/
723static bool Alias_MatchIpv4(struct AliasItemStruct *alias,unsigned char *ipv4)
724{
725 int len;
b4af579e 726 int n,m;
c4f0ea8f
FM
727
728 len=alias->Ipv4.NBits;
b4af579e
FM
729 n=len/8;
730 m=len%8;
731 if (n>0 && memcmp(ipv4,alias->Ipv4.Ip,n)!=0) return(false);
8c44d2a0 732 if (m!=0 && ((ipv4[n] ^ alias->Ipv4.Ip[n]) & (0xFFU<<(8-m)))!=0) return(false);
b4af579e 733 return(true);
c4f0ea8f
FM
734}
735
736/*!
737Replace 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*/
744static 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/*!
762Replace 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
765by a pointer to the alias if a match is found.
766
767\return A pointer to the replacement string or NULL if the regex
768doesn't match.
769
770\warning The function is not thread safe as it may return a static
771internal buffer.
772*/
773static 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 /*
cee1addc
FM
801 * ovector[sub] is the start position of the match.
802 * ovector[sub+1] is the end position of the match.
803 */
c4f0ea8f
FM
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
819const 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}