]>
git.ipfire.org Git - thirdparty/sarg.git/blob - url.c
da66df59245004e09877f6d7b98f78cbcee9c0e5
2 * SARG Squid Analysis Report Generator http://sarg.sourceforge.net
6 * please look at http://sarg.sourceforge.net/donations.php
8 * http://sourceforge.net/projects/sarg/forums/forum/363374
9 * ---------------------------------------------------------------------
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.
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.
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.
27 #include "include/conf.h"
28 #include "include/defs.h"
31 A host name and the name to report.
35 //! The next host name in the list or NULL for the last item.
36 struct hostalias_name
*Next
;
37 //! The minimum length of a candidate host name.
39 //! The length of the constant part at the beginning of the mask.
41 //! The length of the constant part at the end of the mask.
43 //! The first part of the mask of the host name.
44 const char *HostName_Prefix
;
45 //! The second part of the mask of the host name.
46 const char *HostName_Suffix
;
47 //! The replacement name.
52 An IPv4 address and the name to report.
56 //! The next host name in the list or NULL for the last item.
57 struct hostalias_ipv4
*Next
;
60 //! The number of bits in the prefix.
62 //! The replacement name.
67 An IPv6 address and the name to report.
71 //! The next host name in the list or NULL for the last item.
72 struct hostalias_ipv6
*Next
;
75 //! The number of bits in the prefix.
77 //! The replacement name.
81 //! The first host name.
82 static struct hostalias_name
*FirstAliasName
=NULL
;
83 //! The first IPv4 address.
84 static struct hostalias_ipv4
*FirstAliasIpv4
=NULL
;
85 //! The first IPvĀ§ address.
86 static struct hostalias_ipv6
*FirstAliasIpv6
=NULL
;
89 Store a name to alias.
91 \param name The name to match including the wildcard.
92 \param next A pointer to the first character after the name.
94 \retval 1 Alias added.
95 \retval 0 Ignore the line.
98 static int Alias_StoreName(const char *name
,const char *next
)
100 const char *NameBegin
;
101 const char *NameBeginE
;
103 const char *NameEndE
;
105 const char *ReplaceE
;
108 struct hostalias_name
*alias
;
109 struct hostalias_name
*new_alias
;
110 struct hostalias_name
*prev_alias
;
114 if (*name
=='#' || *name
==';') return(0);
116 // get host name and split at the wildcard
118 for (str
=NameBegin
; str
<next
&& (unsigned char)*str
>' ' && *str
!='*' ; str
++);
120 if (NameBegin
==NameBeginE
) NameBegin
=NULL
;
121 if (str
<next
&& *str
=='*') {
123 while (str
<next
&& (unsigned char)*str
>' ') {
125 debuga(_("Host name alias \"%s*%s\" contains too many wildcards (*)\n"),NameBegin
,NameEnd
);
131 if (NameEnd
==NameEndE
) {
132 debuga(_("Host name alias \"%*s\" must not end with a wildcard\n"),(int)(next
-name
),name
);
138 while (str
<next
&& (unsigned char)*str
<=' ') str
++;
139 if (!NameBegin
&& !NameEnd
) return(0);
143 if (sep
==' ' || sep
=='\t') {
145 while (*Replace
==' ' || *Replace
=='\t') Replace
++;
146 if ((unsigned char)*Replace
<' ') {
149 for (str
=Replace
; *str
&& (unsigned char)*str
>=' ' ; str
++);
156 len
=(int)(NameBeginE
-NameBegin
);
159 debuga(_("Not enough memory to store the host name aliasing directives\n"));
162 memcpy(tmp
,NameBegin
,len
);
167 len
=(int)(NameEndE
-NameEnd
);
170 if (NameBegin
) free((void*)NameBegin
);
171 debuga(_("Not enough memory to store the host name aliasing directives\n"));
174 memcpy(tmp
,NameEnd
,len
);
181 for (alias
=FirstAliasName
; alias
; alias
=alias
->Next
) {
182 if (((NameBegin
&& alias
->HostName_Prefix
&& !strcmp(NameBegin
,alias
->HostName_Prefix
)) || (!NameBegin
&& !alias
->HostName_Prefix
)) &&
183 ((NameEnd
&& alias
->HostName_Suffix
&& !strcmp(NameEnd
,alias
->HostName_Suffix
)) || (!NameEnd
&& !alias
->HostName_Suffix
))) {
184 if (NameBegin
) free((void*)NameBegin
);
190 // insert into the list
191 new_alias
=malloc(sizeof(*new_alias
));
193 if (NameBegin
) free((void*)NameBegin
);
194 if (NameEnd
) free((void*)NameEnd
);
195 debuga(_("Not enough memory to store the host name aliasing directives\n"));
200 new_alias
->HostName_Prefix
=NameBegin
;
201 new_alias
->MinLen
+=strlen(NameBegin
);
202 new_alias
->PrefixLen
=strlen(NameBegin
);
204 new_alias
->HostName_Prefix
=NULL
;
205 new_alias
->PrefixLen
=0;
208 new_alias
->HostName_Suffix
=NameEnd
;
209 new_alias
->MinLen
+=strlen(NameEnd
)+1;
210 new_alias
->SuffixLen
=strlen(NameEnd
);
212 new_alias
->HostName_Suffix
=NULL
;
213 new_alias
->SuffixLen
=0;
216 len
=(int)(ReplaceE
-Replace
);
219 debuga(_("Not enough memory to store the host name aliasing directives\n"));
223 memcpy(tmp
+1,Replace
,len
);
225 new_alias
->Alias
=tmp
;
227 tmp
=malloc(new_alias
->MinLen
+2);
229 debuga(_("Not enough memory to store the host name aliasing directives\n"));
233 if (new_alias
->HostName_Prefix
) strcpy(tmp
+1,new_alias
->HostName_Prefix
);
234 if (new_alias
->HostName_Suffix
) {
235 tmp
[new_alias
->PrefixLen
+1]='*';
236 strcpy(tmp
+new_alias
->PrefixLen
+2,new_alias
->HostName_Suffix
);
238 new_alias
->Alias
=tmp
;
241 new_alias
->Next
=NULL
;
243 prev_alias
->Next
=new_alias
;
245 FirstAliasName
=new_alias
;
250 Store a IPv4 to alias.
252 \param ipv4 The IPv4 to match.
253 \param nbits The number of bits in the prefix
254 \param next A pointer to the first character after the address.
256 \retval 1 Alias added.
257 \retval 0 Ignore the line.
260 static int Alias_StoreIpv4(unsigned char *ipv4
,int nbits
,const char *next
)
263 const char *ReplaceE
;
265 struct hostalias_ipv4
*alias
;
266 struct hostalias_ipv4
*new_alias
;
267 struct hostalias_ipv4
*prev_alias
;
274 while (*Replace
==' ' || *Replace
=='\t') Replace
++;
275 if ((unsigned char)*Replace
<' ') {
278 for (str
=Replace
; *str
&& (unsigned char)*str
>=' ' ; str
++);
282 // store more restrictive range first
284 for (alias
=FirstAliasIpv4
; alias
; alias
=alias
->Next
) {
285 i
=(nbits
<alias
->NBits
) ? nbits
: alias
->NBits
;
286 if ((i
<8 || memcmp(ipv4
,alias
->Ip
,i
/8)==0) && ((i
%8)==0 || (ipv4
[i
/8] ^ alias
->Ip
[i
/8]) & (0xFFU
<<(8-i
%8)))==0) {
292 // insert into the list
293 new_alias
=malloc(sizeof(*new_alias
));
295 debuga(_("Not enough memory to store the host name aliasing directives\n"));
298 memcpy(new_alias
->Ip
,ipv4
,4);
299 new_alias
->NBits
=nbits
;
301 len
=(int)(ReplaceE
-Replace
);
304 debuga(_("Not enough memory to store the host name aliasing directives\n"));
308 memcpy(tmp
+1,Replace
,len
);
310 new_alias
->Alias
=tmp
;
314 debuga(_("Not enough memory to store the host name aliasing directives\n"));
317 sprintf(tmp
,"%c%d.%d.%d.%d/%d",ALIAS_PREFIX
,ipv4
[0],ipv4
[1],ipv4
[2],ipv4
[3],nbits
);
318 new_alias
->Alias
=tmp
;
322 new_alias
->Next
=prev_alias
->Next
;
323 prev_alias
->Next
=new_alias
;
325 new_alias
->Next
=NULL
;
326 FirstAliasIpv4
=new_alias
;
332 Store a IPv6 to alias.
334 \param ipv6 The IPv6 to match.
335 \param nbits The number of bits in the prefix
336 \param next A pointer to the first character after the address.
338 \retval 1 Alias added.
339 \retval 0 Ignore the line.
342 static int Alias_StoreIpv6(unsigned short *ipv6
,int nbits
,const char *next
)
345 const char *ReplaceE
;
347 struct hostalias_ipv6
*alias
;
348 struct hostalias_ipv6
*new_alias
;
349 struct hostalias_ipv6
*prev_alias
;
356 while (*Replace
==' ' || *Replace
=='\t') Replace
++;
357 if ((unsigned char)*Replace
<' ') {
360 for (str
=Replace
; *str
&& (unsigned char)*str
>=' ' ; str
++);
364 // store more restrictive range first
366 for (alias
=FirstAliasIpv6
; alias
; alias
=alias
->Next
) {
367 i
=(nbits
<alias
->NBits
) ? nbits
: alias
->NBits
;
368 if ((i
<16 || memcmp(ipv6
,alias
->Ip
,i
/16*2)==0) && ((i
%16)==0 || (ipv6
[i
/16] ^ alias
->Ip
[i
/16]) & (0xFFFFU
<<(16-i
%16)))==0) {
374 // insert into the list
375 new_alias
=malloc(sizeof(*new_alias
));
377 debuga(_("Not enough memory to store the host name aliasing directives\n"));
380 memcpy(new_alias
->Ip
,ipv6
,8*sizeof(unsigned short int));
381 new_alias
->NBits
=nbits
;
383 len
=ReplaceE
-Replace
;
386 debuga(_("Not enough memory to store the host name aliasing directives\n"));
390 memcpy(tmp
+1,Replace
,len
);
392 new_alias
->Alias
=tmp
;
396 debuga(_("Not enough memory to store the host name aliasing directives\n"));
399 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
);
400 new_alias
->Alias
=tmp
;
404 new_alias
->Next
=prev_alias
->Next
;
405 prev_alias
->Next
=new_alias
;
407 new_alias
->Next
=NULL
;
408 FirstAliasIpv6
=new_alias
;
414 Read the file containing the host names to alias in the report.
416 \param Filename The name of the file.
418 void read_hostalias(const char *Filename
)
425 unsigned char ipv4
[4];
426 unsigned short int ipv6
[8];
430 if (debug
) debuga(_("Reading host alias file \"%s\"\n"),Filename
);
431 fi
=fopen(Filename
,"rt");
433 debuga(_("Cannot read host name alias file \"%s\" - %s\n"),Filename
,strerror(errno
));
437 if ((line
=longline_create())==NULL
) {
438 debuga(_("Not enough memory to read the host name aliases\n"));
442 while ((buf
=longline_read(fi
,line
)) != NULL
) {
443 type
=extract_address_mask(buf
,&name
,ipv4
,ipv6
,&nbits
,&next
);
445 debuga(_("While reading \"%s\"\n"),Filename
);
450 Alias_StoreName(name
,next
);
451 } else if (type
==2) {
452 Alias_StoreIpv4(ipv4
,nbits
,next
);
453 } else if (type
==3) {
454 Alias_StoreIpv6(ipv6
,nbits
,next
);
458 longline_destroy(&line
);
462 struct hostalias_name
*alias1
;
463 struct hostalias_ipv4
*alias4
;
464 struct hostalias_ipv6
*alias6
;
466 debuga(_("List of host names to alias:\n"));
467 for (alias1
=FirstAliasName
; alias1
; alias1
=alias1
->Next
) {
468 if (alias1
->HostName_Prefix
&& alias1
->HostName_Suffix
)
469 debuga(_(" %s*%s => %s\n"),alias1
->HostName_Prefix
,alias1
->HostName_Suffix
,alias1
->Alias
);
470 else if (alias1
->HostName_Prefix
)
471 debuga(_(" %s => %s\n"),alias1
->HostName_Prefix
,alias1
->Alias
);
473 debuga(_(" *%s => %s\n"),alias1
->HostName_Suffix
,alias1
->Alias
);
475 for (alias4
=FirstAliasIpv4
; alias4
; alias4
=alias4
->Next
) {
476 debuga(_(" %d.%d.%d.%d/%d => %s\n"),alias4
->Ip
[0],alias4
->Ip
[1],alias4
->Ip
[2],alias4
->Ip
[3],alias4
->NBits
,alias4
->Alias
);
478 for (alias6
=FirstAliasIpv6
; alias6
; alias6
=alias6
->Next
) {
479 debuga(_(" %x:%x:%x:%x:%x:%x:%x:%x/%d => %s\n"),alias6
->Ip
[0],alias6
->Ip
[1],alias6
->Ip
[2],alias6
->Ip
[3],
480 alias6
->Ip
[4],alias6
->Ip
[5],alias6
->Ip
[6],alias6
->Ip
[7],alias6
->NBits
,alias6
->Alias
);
486 Free the memory allocated by read_hostalias().
488 void free_hostalias(void)
490 struct hostalias_name
*alias1
;
491 struct hostalias_name
*next1
;
492 struct hostalias_ipv4
*alias4
;
493 struct hostalias_ipv4
*next4
;
494 struct hostalias_ipv6
*alias6
;
495 struct hostalias_ipv6
*next6
;
497 for (alias1
=FirstAliasName
; alias1
; alias1
=next1
) {
499 if (alias1
->HostName_Prefix
) free((void *)alias1
->HostName_Prefix
);
500 if (alias1
->HostName_Suffix
) free((void *)alias1
->HostName_Suffix
);
501 free((void *)alias1
->Alias
);
505 for (alias4
=FirstAliasIpv4
; alias4
; alias4
=next4
) {
507 free((void *)alias4
->Alias
);
511 for (alias6
=FirstAliasIpv6
; alias6
; alias6
=next6
) {
513 free((void *)alias6
->Alias
);
520 Replace the host name by its alias if it is in our list.
522 \param url The host name.
524 \return The pointer to the host name or its alias.
526 const char *alias_url_name(const char *url
,const char *next
)
528 struct hostalias_name
*alias
;
532 for (alias
=FirstAliasName
; alias
; alias
=alias
->Next
) {
533 if (len
<alias
->MinLen
) continue;
534 if (alias
->HostName_Prefix
) {
535 if (alias
->HostName_Suffix
) {
536 if (strncasecmp(url
,alias
->HostName_Prefix
,alias
->PrefixLen
)==0 &&
537 strncasecmp(url
+(len
-alias
->SuffixLen
),alias
->HostName_Suffix
,len
)==0) {
538 return(alias
->Alias
);
541 if (len
==alias
->PrefixLen
&& strncasecmp(url
,alias
->HostName_Prefix
,len
)==0) {
542 return(alias
->Alias
);
545 } else if (strncasecmp(url
+(len
-alias
->SuffixLen
),alias
->HostName_Suffix
,len
)==0) {
546 return(alias
->Alias
);
553 Replace the IPv4 address by its alias if it is in our list.
555 \param url The host name.
556 \param ipv4 The address.
558 \return The pointer to the host name or its alias.
560 const char *alias_url_ipv4(const char *url
,unsigned char *ipv4
)
562 struct hostalias_ipv4
*alias
;
565 for (alias
=FirstAliasIpv4
; alias
; alias
=alias
->Next
) {
567 if ((len
<8 || memcmp(ipv4
,alias
->Ip
,len
/8)==0) && ((len
%8)==0 || (ipv4
[len
/8] ^ alias
->Ip
[len
/8]) & (0xFFU
<<(8-len
%8)))==0) {
568 return(alias
->Alias
);
575 Replace the IPv6 address by its alias if it is in our list.
577 \param url The host name.
578 \param ipv6 The address.
580 \return The pointer to the host name or its alias.
582 const char *alias_url_ipv6(const char *url
,unsigned short int *ipv6
)
584 struct hostalias_ipv6
*alias
;
588 for (alias
=FirstAliasIpv6
; alias
; alias
=alias
->Next
) {
590 for (i
=len
/16-1 ; i
>=0 && ipv6
[i
]==alias
->Ip
[i
] ; i
--);
593 if (i
>=8 || len
%16==0 || ((ipv6
[i
] ^ alias
->Ip
[i
]) & (0xFFFF<<(len
-i
*16)))==0) {
594 return(alias
->Alias
);
601 Find the beginning of the URL beyond the scheme://
603 \param url The url possibly containing a scheme.
605 \return The beginning of the url beyond the scheme.
607 const char *skip_scheme(const char *url
)
612 Skip any scheme:// at the beginning of the URL (see rfc2396 section 3.1).
613 The underscore is not part of the standard but is found in the squid logs as cache_object://.
615 for (str
=url
; *str
&& (isalnum(*str
) || *str
=='+' || *str
=='-' || *str
=='.' || *str
=='_') ; str
++);
616 if (str
[0]==':' && str
[1]=='/' && str
[2]=='/') {
618 while (*url
=='/') url
++;
624 Get the part of the URL necessary to generate the report.
626 \param url The URL as extracted from the report.
627 \param full_url \c True to keep the whole URL. If \c false,
628 the URL is truncated to only keep the host name and port number.
630 const char *process_url(char *url
,bool full_url
)
636 unsigned char ipv4
[4];
637 unsigned short int ipv6
[8];
640 start
=skip_scheme(url
);
642 for (str
=(char *)start
; *str
&& *str
!='/' && *str
!='?' ; str
++);
644 type
=extract_address_mask(start
,&address
,ipv4
,ipv6
,NULL
,&next
);
647 start
=alias_url_name(start
,next
);
648 } else if (type
==2) {
650 start
=alias_url_ipv4(start
,ipv4
);
651 } else if (type
==3) {
653 start
=alias_url_ipv6(start
,ipv6
);
660 Extract the host name from the URL.
662 \param url The url whose host name must be extracted.
663 \param hostname The buffer to store the host name.
664 \param hostsize The size of the host name buffer.
666 \note The function is stupid at this time. It just searches for the first slash
667 in the URL and truncates the URL there. It doesn't take the protocol into account
668 nor the port number nor any user or password information.
670 void url_hostname(const char *url
,char *hostname
,int hostsize
)
675 for (i
=0 ; i
<hostsize
&& url
[i
] && url
[i
]!='/' ; i
++)