From: Frédéric Marchal Date: Mon, 21 May 2012 19:55:47 +0000 (+0200) Subject: IP address resolution using one external program X-Git-Tag: v2.3.3-pre1~9 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1e312c82bc22805a17cfb08ac3a3524c0627587e;p=thirdparty%2Fsarg.git IP address resolution using one external program It is now possible to resolve an IP address using an external program. Only one external program can be configured but it may do anything including attempting several strategies to resolve the IP address. The module may be chained after the standard dns module to get the name of a computer not registered with the DNS. Executing an external program is exceedingly slow so it is best to try the DNS first! --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 0000eb9..2736fe7 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,7 +52,7 @@ SET(SRC util.c log.c report.c topuser.c email.c sort.c html.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 dichotomic.c - redirector.c auth.c download.c grepday.c + redirector.c auth.c download.c grepday.c ip2name_exec.c dansguardian_log.c dansguardian_report.c realtime.c btree_cache.c usertab.c userinfo.c longline.c url.c) diff --git a/Makefile.in b/Makefile.in index 4595f81..42e7c58 100644 --- a/Makefile.in +++ b/Makefile.in @@ -36,7 +36,7 @@ SRCS = util.c log.c report.c topuser.c email.c sort.c html.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 dichotomic.c \ - redirector.c auth.c download.c grepday.c \ + redirector.c auth.c download.c grepday.c ip2name_exec.c \ dansguardian_log.c dansguardian_report.c realtime.c btree_cache.c \ usertab.c userinfo.c longline.c url.c diff --git a/include/ip2name.h b/include/ip2name.h index 42d62fe..3a894f7 100644 --- a/include/ip2name.h +++ b/include/ip2name.h @@ -4,7 +4,7 @@ //! The possible return code of ip2name subfunctions. enum ip2name_retcode { - //! Error encountered during the + //! Error encountered during the processing. INRC_Error=-1, //! No match found. INRC_NotFound, @@ -21,9 +21,9 @@ struct Ip2NameProcess //! 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); + void (*Configure)(const char *name,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 +#endif //IP2NAME_HEADER diff --git a/ip2name.c b/ip2name.c index 5e7825e..3f6b3e5 100644 --- a/ip2name.c +++ b/ip2name.c @@ -39,11 +39,13 @@ struct Ip2NameModules }; extern struct Ip2NameProcess Ip2NameDns; +extern struct Ip2NameProcess Ip2NameExec; //! The list of the modules available to resolve an IP address into a name. static const struct Ip2NameModules ModulesList[]= { {"dns",&Ip2NameDns}, + {"exec",&Ip2NameExec}, {"yes",&Ip2NameDns},//for historical compatibility {"no",NULL},//does nothing for compatibility with previous versions }; @@ -111,6 +113,34 @@ static void ip2name_buildmoduleslist(const char *list) } } +/*! +Configure a module whose name is given as an argument. The parameters to configure +follow the module name after one or more space or tabs. + +\param module The name of the module, a space and the configuration options. +*/ +static void ip2name_configmodule(const char *module) +{ + int length; + unsigned int ModuleIdx; + + for (length=0 ; module[length] && (unsigned char)module[length]>' ' ; length++); + for (ModuleIdx=0 ; ModuleIdxConfigure) { + debuga(_("No option to configure for module %s\n"),ModulesList[ModuleIdx].Name); + exit(EXIT_FAILURE); + } + while (module[length] && (unsigned char)module[length]<=' ') length++; + ModulesList[ModuleIdx].Process->Configure(ModulesList[ModuleIdx].Name,module+length); + } + break; + } + } +} + /*! Configure a module to resolve an IP address into a name. @@ -130,6 +160,8 @@ int ip2name_config(const char *param) // parameter for a module? if (*param=='_') { + ip2name_configmodule(param+1); + return(1); } return(0); diff --git a/ip2name_exec.c b/ip2name_exec.c new file mode 100644 index 0000000..306d7d9 --- /dev/null +++ b/ip2name_exec.c @@ -0,0 +1,128 @@ +/* + * 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" + +//! The buffer size to store the command. +#define CMD_BUFFER_SIZE 2048 + +static void ip2name_execconfig(const char *name,const char *param); +static enum ip2name_retcode ip2name_exec(char *ip,int ip_len); + +//! The functions to resolve an IP address using an external executable. +struct Ip2NameProcess Ip2NameExec= +{ + "dns", + NULL,//no next item yet + ip2name_execconfig, + ip2name_exec +}; + +static char ExecCmd[CMD_BUFFER_SIZE]=""; + +/*! +Configure the module to resolve an IP address using an external program. + +\param name The name of the module as invoked by the user in the configuration +file. +\param param The parameters passed to the module. +*/ +static void ip2name_execconfig(const char *name,const char *param) +{ + int len; + + len=strlen(param); + if (len>=sizeof(ExecCmd)) { + debuga(_("Command to execute to resolve the IP addresses is too long (maximum is %lu bytes)\n"),sizeof(ExecCmd)); + exit(EXIT_FAILURE); + } + strcpy(ExecCmd,param); +} + +/*! +Run an external process to get the name of a computer. + +\param ip The ip address. +\param ip_len The number of bytes in the IP address. + +\return One of the ::ip2name_retcode value. +*/ +static enum ip2name_retcode ip2name_exec(char *ip,int ip_len) +{ + char cmd[CMD_BUFFER_SIZE]; + int i; + int j; + int len; + FILE *cmd_in; + char buffer[512]; + size_t nread; + + if (ExecCmd[0]=='\0') { + debuga(_("No command to run to resolve an IP address. Please configure it in sarg.conf\n")); + exit(EXIT_FAILURE); + } + + j=0; + len=strlen(ip); + for (i=0 ; i=sizeof(cmd)) { + debuga(_("IP address %s too long for the command to run\n"),ip); + return(INRC_Error); + } + strcpy(cmd+j,ip); + j+=len; + i+=2; + } else { + if (j>=sizeof(cmd)) { + debuga(_("IP address %.*s too long for the command to run\n"),ip_len,ip); + return(INRC_Error); + } + cmd[j++]=ExecCmd[i]; + } + } + cmd[j]='\0'; + + cmd_in=popen(cmd,"r"); + if (!cmd_in) { + debuga(_("Cannot run command %s\n"),cmd); + exit(EXIT_FAILURE); + } + + nread=fread(buffer,1,sizeof(buffer),cmd_in); + + if (pclose(cmd_in)==-1) { + debuga(_("Command failed: %s\n"),cmd); + exit(EXIT_FAILURE); + } + + if (nread==0) return(INRC_NotFound); + + safe_strcpy(ip,buffer,ip_len); + return(INRC_Found); +} diff --git a/sarg.conf b/sarg.conf index a405476..f474428 100644 --- a/sarg.conf +++ b/sarg.conf @@ -145,12 +145,33 @@ # # The possible modules are # dns Use the DNS. +# exec Call an external program with the IP address as argument. # # 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: resolve_ip_exec command +# If resolve_ip selects the exec module, this is the command to run to +# resolve an IP address. The command must contain a placeholder where the +# IP address is inserted. The placeholder must be %IP in uppercases. The +# placeholder may be repeated multiple times if necessary. +# +# The command is expected to return the host name without frills on its +# standard output. If the command returns nothing, it is assumed that the +# command could not resolve the IP address and the next module in the +# chain is given a try with the same address. +# +# This option can only be used once. Therefore there is only one command +# available to resolve an IP address but the program can do anything it +# deems fit including attempting several strategies. +# +# Beware that running an external program is exceedingly slow. So you +# should try the DNS first and only call an external program if the DNS +# fails. +#resolve_ip_exec nmblookup -A %IP | sed -n -e 's/^ *\(.*\) *<00> - *B.*/\1/p' + # TAG: user_ip yes/no # Use Ip Address instead userid in reports. # sarg -p