]> git.ipfire.org Git - thirdparty/sarg.git/commitdiff
Make a module out of the DNS IP resolving
authorFrédéric Marchal <fmarchal@users.sourceforge.net>
Sat, 18 Feb 2012 08:19:45 +0000 (09:19 +0100)
committerFrédéric Marchal <fmarchal@users.sourceforge.net>
Sat, 18 Feb 2012 08:19:45 +0000 (09:19 +0100)
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.

CMakeLists.txt
Makefile.in
getconf.c
include/defs.h
include/ip2name.h [new file with mode: 0644]
ip2name.c
ip2name_dns.c [new file with mode: 0644]
log.c
sarg.conf

index a541a3cfb78e65bf372bfa8cb8f05e97e6bf5093..e17d3130905027b1cbb1b4b5e28011e21532da69 100755 (executable)
@@ -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
index 332a58778a774ea7fdbfed4f3ce132efcd9a50d7..16d3ea56ad52714f01a26850347f191272ccd8e4 100644 (file)
@@ -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 \
index c38c9ec92e63ee9bb01ef81a1cf2287ce5ba6f51..efa1fe679ca6e111e7ba121dd4ee2e9eaac6bfea 100644 (file)
--- 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;
 
index 0d59741c44d7ad675b32061a3b1efc94a4ee357e..8e3fdf38b00ae1c371ba1059b53f6e1c84701e26 100755 (executable)
@@ -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 (file)
index 0000000..42d62fe
--- /dev/null
@@ -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
index 31502af4dcad58b4e021bf432884a1df07201e62..205574ee813bbdcb10ee09e9f8db49e978d5b2b7 100644 (file)
--- a/ip2name.c
+++ b/ip2name.c
 
 #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);
 }
 
 /*!
@@ -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 (file)
index 0000000..cf12969
--- /dev/null
@@ -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 <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);
+}
+
diff --git a/log.c b/log.c
index a6d6c61014836957c7b5313a282c6d746405c9b9..e2172e6d6cc77fa101333175b57fc9554b53df2a 100644 (file)
--- 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;
 
index e93441da70cef2a5e8d89d56ab60055867010fe9..c3b44a1b50bfea985cdf0e98d945c24cdd945b78 100644 (file)
--- a/sarg.conf
+++ b/sarg.conf
 #
 #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