INCLUDE_DIRECTORIES("${CMAKE_BINARY_DIR}") #Make it find this config.h before the one in src/include
INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/include")
SET(SRC util.c log.c report.c topuser.c email.c sort.c html.c
- index.c getconf.c usage.c decomp.c ip2name.c
+ index.c getconf.c usage.c decomp.c ip2name.c ip2name_dns.c
useragent.c exclude.c convlog.c totday.c repday.c datafile.c
indexonly.c splitlog.c lastlog.c topsites.c siteuser.c css.c
smartfilter.c denied.c authfail.c charset.c
INSTALL_PROGRAM = $(INSTALL)
SRCS = util.c log.c report.c topuser.c email.c sort.c html.c \
- index.c getconf.c usage.c decomp.c ip2name.c \
+ index.c getconf.c usage.c decomp.c ip2name.c ip2name_dns.c \
useragent.c exclude.c convlog.c totday.c repday.c datafile.c\
indexonly.c splitlog.c lastlog.c topsites.c siteuser.c css.c \
smartfilter.c denied.c authfail.c charset.c \
if (getparam_quoted("title",buf,Title,sizeof(Title))>0) return;
- if (getparam_bool("resolve_ip",buf,&Ip2Name)>0) return;
+ if (strncasecmp(buf,"resolve_ip",10)==0) {
+ if (ip2name_config(buf+10)>0) return;
+ }
if (getparam_bool("user_ip",buf,&UserIp)>0) return;
void index_only(const char *dirname,int debug);
// ip2name.c
+int ip2name_config(const char *param);
+void ip2name_forcedns(void);
void ip2name(char *ip,int ip_len);
void name2ip(char *name,int name_size);
--- /dev/null
+#ifndef IP2NAME_HEADER
+#define IP2NAME_HEADER
+
+//! The possible return code of ip2name subfunctions.
+enum ip2name_retcode
+{
+ //! Error encountered during the
+ INRC_Error=-1,
+ //! No match found.
+ INRC_NotFound,
+ //! A match was found.
+ INRC_Found,
+};
+
+
+//! Entry points of the ip2name modules
+struct Ip2NameProcess
+{
+ //! The real name of the module.
+ const char *Name;
+ //! The link to the next module to try if this one fails.
+ struct Ip2NameProcess *Next;
+ //! The function to configure the module.
+ int (*Configure)(const char *param);
+ //! Function to resolve an IP address into a name.
+ enum ip2name_retcode (*Resolve)(char *ip,int ip_len);
+};
+
+#endif //IP2NAME_HEADER
\ No newline at end of file
#include "include/conf.h"
#include "include/defs.h"
-#ifdef HAVE_WS2TCPIP_H
-#include <ws2tcpip.h> //define getnameinfo on windows
-#endif
+#include "include/ip2name.h"
-//! The possible return code of ip2name subfunctions.
-enum ip2name_retcode
+//! Associate a name or alias to a module.
+struct Ip2NameModules
{
- //! Error encountered during the
- INRC_Error=-1,
- //! No match found.
- INRC_NotFound,
- //! A match was found.
- INRC_Found,
+ //! The name of the module
+ const char *Name;
+ //! The structure to access the module functions.
+ struct Ip2NameProcess *Process;
};
-/*!
-Resolve the IP address using a reverse DNS entry.
+extern struct Ip2NameProcess Ip2NameDns;
-\param ip The IP address. It is replaced by the corresponding name if one
-can be found.
-\param ip_len The length of the \c ip buffer.
+//! The list of the modules available to resolve an IP address into a name.
+static const struct Ip2NameModules ModulesList[]=
+{
+ {"dns",&Ip2NameDns},
+ {"yes",&Ip2NameDns},//for historical compatibility
+ {"no",NULL},//does nothing for compatibility with previous versions
+};
-\return One of the ::ip2name_retcode value.
+//! The chain of the configured modules to try to resolve an IP.
+static struct Ip2NameProcess *FirstModule=NULL;
+
+/*!
+Add a new module to the list of the configured modules.
*/
-static enum ip2name_retcode ip2name_dns(char *ip,int ip_len)
+static void ip2name_chainmodule(struct Ip2NameProcess *Module)
{
-#ifdef HAVE_GETNAMEINFO
- struct sockaddr_storage sa;
- int sockaddr_size;
- char host[NI_MAXHOST];
- int n1,n2,n3,n4,next=0;
- int error;
-
- memset(&sa,0,sizeof(sa));
- if (sscanf(ip,"%d.%d.%d.%d%n",&n1,&n2,&n3,&n4,&next)==4 && ip[next]=='\0') {
- struct sockaddr_in *s4=(struct sockaddr_in *)&sa;
- if (inet_pton(AF_INET,ip,&s4->sin_addr)!=1) return(INRC_Error);
- sa.ss_family=AF_INET;
- sockaddr_size=sizeof(*s4);
- } else {
- struct sockaddr_in6 *s6=(struct sockaddr_in6 *)&sa;
- if (inet_pton(AF_INET6,ip,&s6->sin6_addr)!=1) return(INRC_Error);
- sa.ss_family=AF_INET6;
- sockaddr_size=sizeof(*s6);
- }
-#ifdef HAVE_SOCKADDR_SA_LEN
- sa.ss_len=sockaddr_size;
-#endif
- error=getnameinfo((struct sockaddr *)&sa,sockaddr_size,host,sizeof(host),NULL,0,NI_NAMEREQD);
- if (error==EAI_AGAIN) {
- /*
- This is a temporary failure. According to the man page we should try again but
- it doesn't say if the program should wait before trying again nor how many attempts
- before it becomes a fatal error. I could find no clues on internet so I try once and
- leave it at that. Considering the number of IP addresses to resolve and the absence
- of serious consequences should some IP fail to be resolved properly, it is best
- not waste too much time on this.
- */
- error=getnameinfo((struct sockaddr *)&sa,sizeof(sa),host,sizeof(host),NULL,0,NI_NAMEREQD);
+ struct Ip2NameProcess *Chain;
+ struct Ip2NameProcess *Last;
+
+ if (debug) debuga(_("Chaining IP resolving module \"%s\"\n"),Module->Name);
+
+ Last=NULL;
+ for (Chain=FirstModule ; Chain ; Chain=Chain->Next) {
+ if (Chain==Module) {
+ debuga(_("Ignoring duplicate module \"%s\" to resolve an IP address\n"),Module->Name);
+ return;
+ }
+ Last=Chain;
}
- if (error==EAI_NONAME)
- return(INRC_NotFound);
- if (error!=0) {
- debuga(_("IP to name resolution (getnameinfo) on IP address %s failed with error %d - %s\n"),ip,error,gai_strerror(error));
- return(INRC_Error);
+
+ if (Last)
+ Last->Next=Module;
+ else {
+ FirstModule=Module;
+ Ip2Name=true;
}
- safe_strcpy(ip,host,ip_len);
-#else //HAVE_GETNAMEINFO
- struct in_addr addr;
- struct hostent *hp;
- char **p;
- extern int h_errno;
+}
-#ifdef HAVE_INET_ATON
- if (inet_aton(ip,&addr) == 0)
- return(INRC_Error);
-#else
- addr.s_addr=inet_addr(ip);
- if (addr.s_addr==-1) return(INRC_Error);
-#endif
+/*!
+Add a new module to the list of the configured modules.
- hp = gethostbyaddr((void *)&addr, sizeof (addr), AF_INET);
- if (hp == NULL) {
- if (h_errno==HOST_NOT_FOUND)
- return(INRC_NotFound);
- return(INRC_Error);
+\param list The list of the modules name to chain.
+*/
+static void ip2name_buildmoduleslist(const char *list)
+{
+ const char *candidate;
+ int length;
+ int ModuleIdx;
+
+ while (*list) {
+ candidate=list;
+ while (*candidate && (unsigned char)*candidate<=' ') candidate++;
+ for (length=0 ; (unsigned char)candidate[length]>' ' ; length++);
+ for (ModuleIdx=0 ; ModuleIdx<sizeof(ModulesList)/sizeof(*ModulesList) ; ModuleIdx++) {
+ if (strncasecmp(candidate,ModulesList[ModuleIdx].Name,length)==0 && ModulesList[ModuleIdx].Name[length]=='\0') {
+ // module found
+ if (ModulesList[ModuleIdx].Process)
+ ip2name_chainmodule(ModulesList[ModuleIdx].Process);
+ break;
+ }
+ }
+ if (ModuleIdx>=sizeof(ModulesList)/sizeof(*ModulesList)) {
+ debuga(_("Unknown module \"%.*s\" to resolve the IP addresses\n"),length,candidate);
+ exit(EXIT_FAILURE);
+ }
+ list=candidate+length;
}
+}
- for (p = hp->h_addr_list; *p != 0; p++) {
- struct in_addr in;
+/*!
+Configure a module to resolve an IP address into a name.
- (void) memcpy(&in.s_addr, *p, sizeof (in.s_addr));
- safe_strcpy(ip,hp->h_name,ip_len);
+\param param The parameter found in the configuration file.
+It always begins after the "resolv_ip".
+
+\retval 1 Parameter processed.
+\retval 0 Parameter ignored.
+*/
+int ip2name_config(const char *param)
+{
+ // module to add to the list
+ if (*param==' ') {
+ ip2name_buildmoduleslist(param);
+ return(1);
+ }
+
+ // parameter for a module?
+ if (*param=='_') {
+ }
+
+ return(0);
+}
+
+/*!
+Require the use of the DNS to resolve the IP addresses.
+*/
+void ip2name_forcedns(void)
+{
+ struct Ip2NameProcess *DnsModule=NULL;
+ int i;
+ struct Ip2NameProcess *Chain;
+ struct Ip2NameProcess *Last;
+
+ // find the dns module
+ for (i=0 ; i<sizeof(ModulesList)/sizeof(*ModulesList) ; i++) {
+ if (strcmp("dns",ModulesList[i].Name)==0) {
+ // module found
+ DnsModule=ModulesList[i].Process;
+ break;
+ }
+ }
+ if (!DnsModule) {
+ if (debugz) debuga(_("No known module to resolve an IP address using the DNS\n"));
+ exit(EXIT_FAILURE);
+ }
+
+ // add the module to the list if it isn't there yet
+ Last=NULL;
+ for (Chain=FirstModule ; Chain && Chain!=DnsModule ; Chain=Chain->Next) {
+ Last=Chain;
+ }
+ if (debug) debuga(_("Chaining IP resolving module \"%s\"\n"),DnsModule->Name);
+ if (Last)
+ Last->Next=DnsModule;
+ else {
+ FirstModule=DnsModule;
+ Ip2Name=true;
}
-#endif
- return(INRC_Found);
}
/*!
\param ip The IP address. It is replaced by the corresponding name if one
can be found.
\param ip_len The length of the \c ip buffer.
+
+The function does nothing if no module are configured.
*/
void ip2name(char *ip,int ip_len)
{
+ struct Ip2NameProcess *Module;
enum ip2name_retcode Status;
- Status=ip2name_dns(ip,ip_len);
- if (Status==INRC_Found) return;
+ for (Module=FirstModule ; Module ; Module=Module->Next) {
+ if (Module->Resolve) {
+ Status=Module->Resolve(ip,ip_len);
+ if (Status==INRC_Found) return;
+ }
+ }
}
void name2ip(char *name,int name_size)
--- /dev/null
+/*
+ * SARG Squid Analysis Report Generator http://sarg.sourceforge.net
+ * 1998, 2012
+ *
+ * SARG donations:
+ * please look at http://sarg.sourceforge.net/donations.php
+ * Support:
+ * http://sourceforge.net/projects/sarg/forums/forum/363374
+ * ---------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+#include "include/conf.h"
+#include "include/defs.h"
+#include "include/ip2name.h"
+#ifdef HAVE_WS2TCPIP_H
+#include <ws2tcpip.h> //define getnameinfo on windows
+#endif
+
+static enum ip2name_retcode ip2name_dns(char *ip,int ip_len);
+
+//! The functions to resolve an IP address through tne dns.
+struct Ip2NameProcess Ip2NameDns=
+{
+ "dns",
+ NULL,//no next item yet
+ NULL,//no configuration
+ ip2name_dns
+};
+
+/*!
+Resolve the IP address using a reverse DNS entry.
+
+\param ip The IP address. It is replaced by the corresponding name if one
+can be found.
+\param ip_len The length of the \c ip buffer.
+
+\return One of the ::ip2name_retcode value.
+*/
+static enum ip2name_retcode ip2name_dns(char *ip,int ip_len)
+{
+#ifdef HAVE_GETNAMEINFO
+ struct sockaddr_storage sa;
+ int sockaddr_size;
+ char host[NI_MAXHOST];
+ int n1,n2,n3,n4,next=0;
+ int error;
+
+ memset(&sa,0,sizeof(sa));
+ if (sscanf(ip,"%d.%d.%d.%d%n",&n1,&n2,&n3,&n4,&next)==4 && ip[next]=='\0') {
+ struct sockaddr_in *s4=(struct sockaddr_in *)&sa;
+ if (inet_pton(AF_INET,ip,&s4->sin_addr)!=1) return(INRC_Error);
+ sa.ss_family=AF_INET;
+ sockaddr_size=sizeof(*s4);
+ } else {
+ struct sockaddr_in6 *s6=(struct sockaddr_in6 *)&sa;
+ if (inet_pton(AF_INET6,ip,&s6->sin6_addr)!=1) return(INRC_Error);
+ sa.ss_family=AF_INET6;
+ sockaddr_size=sizeof(*s6);
+ }
+#ifdef HAVE_SOCKADDR_SA_LEN
+ sa.ss_len=sockaddr_size;
+#endif
+ error=getnameinfo((struct sockaddr *)&sa,sockaddr_size,host,sizeof(host),NULL,0,NI_NAMEREQD);
+ if (error==EAI_AGAIN) {
+ /*
+ This is a temporary failure. According to the man page we should try again but
+ it doesn't say if the program should wait before trying again nor how many attempts
+ before it becomes a fatal error. I could find no clues on internet so I try once and
+ leave it at that. Considering the number of IP addresses to resolve and the absence
+ of serious consequences should some IP fail to be resolved properly, it is best
+ not waste too much time on this.
+ */
+ error=getnameinfo((struct sockaddr *)&sa,sizeof(sa),host,sizeof(host),NULL,0,NI_NAMEREQD);
+ }
+ if (error==EAI_NONAME)
+ return(INRC_NotFound);
+ if (error!=0) {
+ debuga(_("IP to name resolution (getnameinfo) on IP address %s failed with error %d - %s\n"),ip,error,gai_strerror(error));
+ return(INRC_Error);
+ }
+ safe_strcpy(ip,host,ip_len);
+#else //HAVE_GETNAMEINFO
+ struct in_addr addr;
+ struct hostent *hp;
+ char **p;
+ extern int h_errno;
+
+#ifdef HAVE_INET_ATON
+ if (inet_aton(ip,&addr) == 0)
+ return(INRC_Error);
+#else
+ addr.s_addr=inet_addr(ip);
+ if (addr.s_addr==-1) return(INRC_Error);
+#endif
+
+ hp = gethostbyaddr((void *)&addr, sizeof (addr), AF_INET);
+ if (hp == NULL) {
+ if (h_errno==HOST_NOT_FOUND)
+ return(INRC_NotFound);
+ return(INRC_Error);
+ }
+
+ for (p = hp->h_addr_list; *p != 0; p++) {
+ struct in_addr in;
+
+ (void) memcpy(&in.s_addr, *p, sizeof (in.s_addr));
+ safe_strcpy(ip,hp->h_name,ip_len);
+ }
+#endif
+ return(INRC_Found);
+}
+
if(userip) UserIp=true;
- if(dns) Ip2Name=true;
+ if(dns) ip2name_forcedns();
if (lastlog>=0) LastLog=lastlog;
#
#output_email none
-# TAG: resolve_ip yes/no
-# Convert ip address to dns name
-# sarg -n
+# TAG: resolve_ip modulelist
+# List the modules to use to convert IP addresses into names.
+# Each named module is tried in sequence until one returns a result. Therefore
+# the order of the modules is relevant.
+# The modules must be listed on one line each separated from the previous one with
+# a space.
+#
+# The possible modules are
+# dns Use the DNS.
+#
+# For compatibility with previous versions, yes is a synonymous for dns and
+# no does nothing.
+# sarg -n forces the use of the dns module.
#resolve_ip no
# TAG: user_ip yes/no