]> git.ipfire.org Git - thirdparty/sarg.git/blobdiff - ip2name.c
Rename configure.in as configure.ac
[thirdparty/sarg.git] / ip2name.c
index 066c596ff733edee3c004b34e9f3f3c901319c8e..d30f3f787d73c798a3a87b76d7f0bcbeaedda227 100644 (file)
--- a/ip2name.c
+++ b/ip2name.c
@@ -1,6 +1,6 @@
 /*
  * SARG Squid Analysis Report Generator      http://sarg.sourceforge.net
- *                                                            1998, 2010
+ *                                                            1998, 2015
  *
  * SARG donations:
  *      please look at http://sarg.sourceforge.net/donations.php
 
 #include "include/conf.h"
 #include "include/defs.h"
-#ifdef HAVE_WS2TCPIP_H
-#include <ws2tcpip.h> //define getnameinfo on windows
-#endif
+#include "include/ip2name.h"
+#include "include/dichotomic.h"
 
-void ip2name(char *ip,int ip_len)
+//! Associate a name or alias to a module.
+struct Ip2NameModules
 {
-#ifdef HAVE_GETNAMEINFO
-       struct sockaddr_storage sa;
-       char host[NI_MAXHOST];
-       int n1,n2,n3,n4,next=0;
-       int error;
+       //! The name of the module
+       const char *Name;
+       //! The structure to access the module functions.
+       struct Ip2NameProcess *Process;
+};
 
-       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;
-               sa.ss_family=AF_INET;
-       } else {
-               struct sockaddr_in6 *s6=(struct sockaddr_in6 *)&sa;
-               if (inet_pton(AF_INET6,ip,&s6->sin6_addr)!=1) return;
-               sa.ss_family=AF_INET6;
-       }
-       error=getnameinfo((struct sockaddr *)&sa,sizeof(sa),host,sizeof(host),NULL,0,0);
-       if (error==0)
-       {
-               strncpy(ip,host,ip_len-1);
-               ip[ip_len-1]='\0';
-       } else {
-               debuga(_("IP to name resolution (getnameinfo) on IP address %s failed with error %d - %s\n"),ip,error,gai_strerror(error));
+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
+};
+
+//! The chain of the configured modules to try to resolve an IP.
+static struct Ip2NameProcess *FirstModule=NULL;
+//! The list of the names found so far.
+static DichotomicObject KnownIp=NULL;
+
+/*!
+Add a new module to the list of the configured modules.
+*/
+static void ip2name_chainmodule(struct Ip2NameProcess *Module)
+{
+       struct Ip2NameProcess *Chain;
+       struct Ip2NameProcess *Last;
+
+       if (debug) debuga(__FILE__,__LINE__,_("Chaining IP resolving module \"%s\"\n"),Module->Name);
+
+       Last=NULL;
+       for (Chain=FirstModule ; Chain ; Chain=Chain->Next) {
+               if (Chain==Module) {
+                       debuga(__FILE__,__LINE__,_("Ignoring duplicate module \"%s\" to resolve an IP address\n"),Module->Name);
+                       return;
+               }
+               Last=Chain;
        }
-#else
-       struct in_addr addr;
-       struct hostent *hp;
-       char **p;
 
-#ifdef HAVE_INET_ATON
-       if (inet_aton(ip,&addr) == 0)
-               return;
-#else
-       addr.s_addr=inet_addr(ip);
-       if (addr.s_addr==-1) return;
-#endif
+       if (Last)
+               Last->Next=Module;
+       else {
+               FirstModule=Module;
+               Ip2Name=true;
+       }
+}
 
-       hp = gethostbyaddr((void *)&addr, sizeof (addr), AF_INET);
-       if (hp == NULL)
-               return;
+/*!
+Add a new module to the list of the configured modules.
 
-       for (p = hp->h_addr_list; *p != 0; p++) {
-               struct in_addr in;
+\param list The list of the modules name to chain.
+*/
+static void ip2name_buildmoduleslist(const char *list)
+{
+       const char *candidate;
+       int length;
+       int ModuleIdx;
 
-               (void) memcpy(&in.s_addr, *p, sizeof (in.s_addr));
-               strncpy(ip,hp->h_name,ip_len-1);
-               ip[ip_len-1]=0;
+       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(__FILE__,__LINE__,_("Unknown module \"%.*s\" to resolve the IP addresses\n"),length,candidate);
+                       exit(EXIT_FAILURE);
+               }
+               list=candidate+length;
        }
-#endif
-       return;
 }
 
-void name2ip(char *name)
+/*!
+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 ; ModuleIdx<sizeof(ModulesList)/sizeof(*ModulesList) ; ModuleIdx++) {
+               if (strncasecmp(module,ModulesList[ModuleIdx].Name,length)==0 && ModulesList[ModuleIdx].Name[length]=='\0') {
+                       // module found
+                       if (ModulesList[ModuleIdx].Process) {
+                               if (!ModulesList[ModuleIdx].Process->Configure) {
+                                       debuga(__FILE__,__LINE__,_("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.
+
+\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=='_') {
+               ip2name_configmodule(param+1);
+               return(1);
+       }
+
+       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>=LogLevel_Process) debuga(__FILE__,__LINE__,_("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(__FILE__,__LINE__,_("Chaining IP resolving module \"%s\"\n"),DnsModule->Name);
+       if (Last)
+               Last->Next=DnsModule;
+       else {
+               FirstModule=DnsModule;
+               Ip2Name=true;
+       }
+}
+
+/*!
+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;
+       const char *Name;
+       char OrigIp[80];
+
+       if (!KnownIp) {
+               KnownIp=Dichotomic_Create();
+               if (!KnownIp) {
+                       debuga(__FILE__,__LINE__,_("Not enough memory to store the names corresponding to the IP address\n"));
+                       exit(EXIT_FAILURE);
+               }
+       }
+
+       Name=Dichotomic_Search(KnownIp,ip);
+       if (Name) {
+               safe_strcpy(ip,Name,ip_len);
+               return;
+       }
+
+       safe_strcpy(OrigIp,ip,sizeof(OrigIp));
+       for (Module=FirstModule ; Module ; Module=Module->Next) {
+               if (Module->Resolve) {
+                       Status=Module->Resolve(ip,ip_len);
+                       if (Status==INRC_Found) break;
+               }
+       }
+       Dichotomic_Insert(KnownIp,OrigIp,ip);
+}
+
+/*!
+Release the memory allocated to resolve the IP addresses
+into names.
+*/
+void ip2name_cleanup(void)
+{
+       Dichotomic_Destroy(&KnownIp);
+}
+
+void name2ip(char *name,int name_size)
+{
+#ifdef HAVE_GETADDRINFO
+       int error;
+       char *port;
+       struct addrinfo *res;
+       char *addr;
+
+       addr=name;
+       if (name[0]=='[') { //IPv6 address
+               port=strchr(name,']');
+               if (port) { //confirmed IPv6 address
+                       *port='\0';
+                       addr++;
+               }
+       } else { //IPv4 address
+               port=strchr(name,':');
+               if (port) *port='\0';
+       }
+
+       error=getaddrinfo(addr,NULL,NULL,&res);
+       if (error) {
+               freeaddrinfo(res);
+               debuga(__FILE__,__LINE__,_("Cannot resolve host name %s: %s\n"),name,gai_strerror(error));
+               exit(EXIT_FAILURE);
+       }
+       if (res->ai_family==AF_INET) {
+               struct sockaddr_in *s4=(struct sockaddr_in *)res->ai_addr;
+               struct in_addr *sa=&s4->sin_addr;
+               if (res->ai_addrlen<sizeof(*s4)) {
+                       debuga(__FILE__,__LINE__,_("Short structure returned by getaddrinfo for an IPv4 address: %d bytes instead of %d\n"),res->ai_addrlen,(int)sizeof(*s4));
+                       exit(EXIT_FAILURE);
+               }
+               inet_ntop(res->ai_family,sa,name,name_size);
+       } else if (res->ai_family==AF_INET6) {
+               struct sockaddr_in6 *s6=(struct sockaddr_in6 *)res->ai_addr;
+               struct in6_addr *sa6=&s6->sin6_addr;
+               if (res->ai_addrlen<sizeof(*s6)) {
+                       debuga(__FILE__,__LINE__,_("Short structure returned by getaddrinfo for an IPv6 address: %d bytes instead of %d\n"),res->ai_addrlen,(int)sizeof(*s6));
+                       exit(EXIT_FAILURE);
+               }
+               inet_ntop(res->ai_family,sa6,name,name_size);
+       } else {
+               debuga(__FILE__,__LINE__,_("Invalid address type %d returned when resolving host name \"%s\"\n"),res->ai_family,name);
+       }
+       freeaddrinfo(res);
+#else
        struct in_addr ia;
        struct hostent *hp;
        char *port;
@@ -96,7 +310,7 @@ void name2ip(char *name)
        struct getwordstruct gwarea;
 
        port=strchr(name,':');
-       if (port) *port=0;
+       if (port) *port='\0';
 
        if((hp=gethostbyname(name))==NULL)
                return;
@@ -106,10 +320,11 @@ void name2ip(char *name)
        getword_start(&gwarea,inet_ntoa(ia));
        if (getword(n4,sizeof(n4),&gwarea,'.')<0 || getword(n3,sizeof(n3),&gwarea,'.')<0 ||
            getword(n2,sizeof(n2),&gwarea,'.')<0 || getword(n1,sizeof(n1),&gwarea,0)<0) {
-               printf("SARG: Maybe you have a broken record or garbage in your %s ip address.\n",gwarea.beginning);
+               debuga(__FILE__,__LINE__,_("Invalid IPv4 address \"%s\"\n"),gwarea.beginning);
                exit(EXIT_FAILURE);
        }
-       sprintf(name,"%s.%s.%s.%s",n1,n2,n3,n4);
+       snprintf(name,name_size,"%s.%s.%s.%s",n1,n2,n3,n4);
+#endif
 
        return;
 }