]>
Commit | Line | Data |
---|---|---|
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 | /*! | |
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)) { | |
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 | */ | |
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) | |
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 | */ | |
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) | |
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 | /*! | |
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') { | |
af961877 | 506 | debuga(__FILE__,__LINE__,_("Invalid NUL character found in regular expression\n")); |
c4f0ea8f FM |
507 | return(-1); |
508 | } | |
509 | End++; //ignore the escaped character | |
510 | } | |
511 | } | |
512 | if (*End!=Delimiter) { | |
af961877 | 513 | debuga(__FILE__,__LINE__,_("Unterminated regular expression\n")); |
c4f0ea8f FM |
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) { | |
af961877 | 526 | debuga(__FILE__,__LINE__,_("Not enough memory to store the host name aliasing directives\n")); |
c4f0ea8f FM |
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) { | |
af961877 | 533 | debuga(__FILE__,__LINE__,_("Failed to compile the regular expression \"%s\": %s\n"),buf,PcreError); |
c4f0ea8f FM |
534 | free(new_alias); |
535 | return(-1); | |
536 | } | |
537 | len=strlen(Replace); | |
538 | tmp=malloc(len+2); | |
539 | if (!tmp) { | |
af961877 | 540 | debuga(__FILE__,__LINE__,_("Not enough memory to store the host name aliasing directives\n")); |
c4f0ea8f FM |
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) { | |
af961877 | 550 | debuga(__FILE__,__LINE__,_("Not enough memory to store the regex aliasing directives\n")); |
c4f0ea8f FM |
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 | |
af961877 | 599 | debuga(__FILE__,__LINE__,_("PCRE not compiled in therefore the regular expressions are not available to alias items\n")); |
c4f0ea8f FM |
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: | |
af961877 | 634 | debuga(__FILE__,__LINE__,_(" %s => %s\n"),alias->Name.Mask,alias->Alias); |
c4f0ea8f FM |
635 | break; |
636 | case ALIASTYPE_Ipv4: | |
af961877 | 637 | debuga(__FILE__,__LINE__,_(" %d.%d.%d.%d/%d => %s\n"),alias->Ipv4.Ip[0],alias->Ipv4.Ip[1],alias->Ipv4.Ip[2], |
c4f0ea8f FM |
638 | alias->Ipv4.Ip[3],alias->Ipv4.NBits,alias->Alias); |
639 | break; | |
640 | case ALIASTYPE_Ipv6: | |
af961877 | 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], |
c4f0ea8f FM |
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: | |
af961877 | 646 | debuga(__FILE__,__LINE__,_(" Re => %s\n"),alias->Alias); |
c4f0ea8f FM |
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; | |
b4af579e | 714 | int n,m; |
c4f0ea8f FM |
715 | |
716 | len=alias->Ipv4.NBits; | |
b4af579e FM |
717 | n=len/8; |
718 | m=len%8; | |
719 | if (n>0 && memcmp(ipv4,alias->Ipv4.Ip,n)!=0) return(false); | |
8c44d2a0 | 720 | if (m!=0 && ((ipv4[n] ^ alias->Ipv4.Ip[n]) & (0xFFU<<(8-m)))!=0) return(false); |
b4af579e | 721 | return(true); |
c4f0ea8f FM |
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 | } |