From: Frédéric Marchal Date: Sat, 18 Feb 2012 08:19:45 +0000 (+0100) Subject: Make a module out of the DNS IP resolving X-Git-Tag: v2.3.3-pre1~21 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=51b166d4eaa0b9966465a9adff1f4bfb2b5c8f42;p=thirdparty%2Fsarg.git Make a module out of the DNS IP resolving The code was changed to accommodate module names in resolve_ip instead of just yes or no. The named modules are tried in sequence until one returns a positive result. Currently, only the dns module is available. --- diff --git a/CMakeLists.txt b/CMakeLists.txt index a541a3c..e17d313 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,7 +48,7 @@ SET(SARGPHPDIR "share/sarg/sarg-php" CACHE PATH "The directory to copy sarg-php 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 diff --git a/Makefile.in b/Makefile.in index 332a587..16d3ea5 100644 --- a/Makefile.in +++ b/Makefile.in @@ -32,7 +32,7 @@ INSTALL = cp 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 \ diff --git a/getconf.c b/getconf.c index c38c9ec..efa1fe6 100644 --- a/getconf.c +++ b/getconf.c @@ -456,7 +456,9 @@ static void parmtest(char *buf) 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; diff --git a/include/defs.h b/include/defs.h index 0d59741..8e3fdf3 100755 --- a/include/defs.h +++ b/include/defs.h @@ -150,6 +150,8 @@ void htmlrel(void); 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); diff --git a/include/ip2name.h b/include/ip2name.h new file mode 100644 index 0000000..42d62fe --- /dev/null +++ b/include/ip2name.h @@ -0,0 +1,29 @@ +#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 diff --git a/ip2name.c b/ip2name.c index 31502af..205574e 100644 --- a/ip2name.c +++ b/ip2name.c @@ -26,102 +26,147 @@ #include "include/conf.h" #include "include/defs.h" -#ifdef HAVE_WS2TCPIP_H -#include //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)) { + 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 ; iNext) { + 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); } /*! @@ -130,13 +175,20 @@ Convert an IP address into a name. \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) diff --git a/ip2name_dns.c b/ip2name_dns.c new file mode 100644 index 0000000..cf12969 --- /dev/null +++ b/ip2name_dns.c @@ -0,0 +1,127 @@ +/* + * 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 //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); +} + diff --git a/log.c b/log.c index a6d6c61..e2172e6 100644 --- a/log.c +++ b/log.c @@ -533,7 +533,7 @@ int main(int argc,char *argv[]) if(userip) UserIp=true; - if(dns) Ip2Name=true; + if(dns) ip2name_forcedns(); if (lastlog>=0) LastLog=lastlog; diff --git a/sarg.conf b/sarg.conf index e93441d..c3b44a1 100644 --- a/sarg.conf +++ b/sarg.conf @@ -136,9 +136,19 @@ # #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