]> git.ipfire.org Git - thirdparty/sarg.git/blob - ip2name.c
Make b-tree cache functions static.
[thirdparty/sarg.git] / ip2name.c
1 /*
2 * SARG Squid Analysis Report Generator http://sarg.sourceforge.net
3 * 1998, 2015
4 *
5 * SARG donations:
6 * please look at http://sarg.sourceforge.net/donations.php
7 * Support:
8 * http://sourceforge.net/projects/sarg/forums/forum/363374
9 * ---------------------------------------------------------------------
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
24 *
25 */
26
27 #include "include/conf.h"
28 #include "include/defs.h"
29 #include "include/ip2name.h"
30 #include "include/dichotomic.h"
31
32 //! Associate a name or alias to a module.
33 struct Ip2NameModules
34 {
35 //! The name of the module
36 const char *Name;
37 //! The structure to access the module functions.
38 struct Ip2NameProcess *Process;
39 };
40
41 extern struct Ip2NameProcess Ip2NameDns;
42 extern struct Ip2NameProcess Ip2NameExec;
43
44 //! The list of the modules available to resolve an IP address into a name.
45 static const struct Ip2NameModules ModulesList[]=
46 {
47 {"dns",&Ip2NameDns},
48 {"exec",&Ip2NameExec},
49 {"yes",&Ip2NameDns},//for historical compatibility
50 {"no",NULL},//does nothing for compatibility with previous versions
51 };
52
53 //! The chain of the configured modules to try to resolve an IP.
54 static struct Ip2NameProcess *FirstModule=NULL;
55 //! The list of the names found so far.
56 static DichotomicObject KnownIp=NULL;
57
58 /*!
59 Add a new module to the list of the configured modules.
60 */
61 static void ip2name_chainmodule(struct Ip2NameProcess *Module)
62 {
63 struct Ip2NameProcess *Chain;
64 struct Ip2NameProcess *Last;
65
66 if (debug) debuga(__FILE__,__LINE__,_("Chaining IP resolving module \"%s\"\n"),Module->Name);
67
68 Last=NULL;
69 for (Chain=FirstModule ; Chain ; Chain=Chain->Next) {
70 if (Chain==Module) {
71 debuga(__FILE__,__LINE__,_("Ignoring duplicate module \"%s\" to resolve an IP address\n"),Module->Name);
72 return;
73 }
74 Last=Chain;
75 }
76
77 if (Last)
78 Last->Next=Module;
79 else {
80 FirstModule=Module;
81 Ip2Name=true;
82 }
83 }
84
85 /*!
86 Add a new module to the list of the configured modules.
87
88 \param list The list of the modules name to chain.
89 */
90 static void ip2name_buildmoduleslist(const char *list)
91 {
92 const char *candidate;
93 int length;
94 int ModuleIdx;
95
96 while (*list) {
97 candidate=list;
98 while (*candidate && (unsigned char)*candidate<=' ') candidate++;
99 for (length=0 ; (unsigned char)candidate[length]>' ' ; length++);
100 for (ModuleIdx=0 ; ModuleIdx<sizeof(ModulesList)/sizeof(*ModulesList) ; ModuleIdx++) {
101 if (strncasecmp(candidate,ModulesList[ModuleIdx].Name,length)==0 && ModulesList[ModuleIdx].Name[length]=='\0') {
102 // module found
103 if (ModulesList[ModuleIdx].Process)
104 ip2name_chainmodule(ModulesList[ModuleIdx].Process);
105 break;
106 }
107 }
108 if (ModuleIdx>=sizeof(ModulesList)/sizeof(*ModulesList)) {
109 debuga(__FILE__,__LINE__,_("Unknown module \"%.*s\" to resolve the IP addresses\n"),length,candidate);
110 exit(EXIT_FAILURE);
111 }
112 list=candidate+length;
113 }
114 }
115
116 /*!
117 Configure a module whose name is given as an argument. The parameters to configure
118 follow the module name after one or more space or tabs.
119
120 \param module The name of the module, a space and the configuration options.
121 */
122 static void ip2name_configmodule(const char *module)
123 {
124 int length;
125 unsigned int ModuleIdx;
126
127 for (length=0 ; module[length] && (unsigned char)module[length]>' ' ; length++);
128 for (ModuleIdx=0 ; ModuleIdx<sizeof(ModulesList)/sizeof(*ModulesList) ; ModuleIdx++) {
129 if (strncasecmp(module,ModulesList[ModuleIdx].Name,length)==0 && ModulesList[ModuleIdx].Name[length]=='\0') {
130 // module found
131 if (ModulesList[ModuleIdx].Process) {
132 if (!ModulesList[ModuleIdx].Process->Configure) {
133 debuga(__FILE__,__LINE__,_("No option to configure for module %s\n"),ModulesList[ModuleIdx].Name);
134 exit(EXIT_FAILURE);
135 }
136 while (module[length] && (unsigned char)module[length]<=' ') length++;
137 ModulesList[ModuleIdx].Process->Configure(ModulesList[ModuleIdx].Name,module+length);
138 }
139 break;
140 }
141 }
142 }
143
144 /*!
145 Configure a module to resolve an IP address into a name.
146
147 \param param The parameter found in the configuration file.
148 It always begins after the "resolv_ip".
149
150 \retval 1 Parameter processed.
151 \retval 0 Parameter ignored.
152 */
153 int ip2name_config(const char *param)
154 {
155 // module to add to the list
156 if (*param==' ') {
157 ip2name_buildmoduleslist(param);
158 return(1);
159 }
160
161 // parameter for a module?
162 if (*param=='_') {
163 ip2name_configmodule(param+1);
164 return(1);
165 }
166
167 return(0);
168 }
169
170 /*!
171 Require the use of the DNS to resolve the IP addresses.
172 */
173 void ip2name_forcedns(void)
174 {
175 struct Ip2NameProcess *DnsModule=NULL;
176 int i;
177 struct Ip2NameProcess *Chain;
178 struct Ip2NameProcess *Last;
179
180 // find the dns module
181 for (i=0 ; i<sizeof(ModulesList)/sizeof(*ModulesList) ; i++) {
182 if (strcmp("dns",ModulesList[i].Name)==0) {
183 // module found
184 DnsModule=ModulesList[i].Process;
185 break;
186 }
187 }
188 if (!DnsModule) {
189 debuga(__FILE__,__LINE__,_("No known module to resolve an IP address using the DNS\n"));
190 exit(EXIT_FAILURE);
191 }
192
193 // add the module to the list if it isn't there yet
194 Last=NULL;
195 for (Chain=FirstModule ; Chain && Chain!=DnsModule ; Chain=Chain->Next) {
196 Last=Chain;
197 }
198 if (debug) debuga(__FILE__,__LINE__,_("Chaining IP resolving module \"%s\"\n"),DnsModule->Name);
199 if (Last)
200 Last->Next=DnsModule;
201 else {
202 FirstModule=DnsModule;
203 Ip2Name=true;
204 }
205 }
206
207 /*!
208 Convert an IP address into a name.
209
210 \param ip The IP address. It is replaced by the corresponding name if one
211 can be found.
212 \param ip_len The length of the \c ip buffer.
213
214 The function does nothing if no module are configured.
215 */
216 void ip2name(char *ip,int ip_len)
217 {
218 struct Ip2NameProcess *Module;
219 enum ip2name_retcode Status;
220 const char *Name;
221 char OrigIp[80];
222
223 if (!KnownIp) {
224 KnownIp=Dichotomic_Create();
225 if (!KnownIp) {
226 debuga(__FILE__,__LINE__,_("Not enough memory to store the names corresponding to the IP address\n"));
227 exit(EXIT_FAILURE);
228 }
229 }
230
231 Name=Dichotomic_Search(KnownIp,ip);
232 if (Name) {
233 safe_strcpy(ip,Name,ip_len);
234 return;
235 }
236
237 safe_strcpy(OrigIp,ip,sizeof(OrigIp));
238 for (Module=FirstModule ; Module ; Module=Module->Next) {
239 if (Module->Resolve) {
240 Status=Module->Resolve(ip,ip_len);
241 if (Status==INRC_Found) break;
242 }
243 }
244 Dichotomic_Insert(KnownIp,OrigIp,ip);
245 }
246
247 /*!
248 Release the memory allocated to resolve the IP addresses
249 into names.
250 */
251 void ip2name_cleanup(void)
252 {
253 Dichotomic_Destroy(&KnownIp);
254 }
255
256 void name2ip(char *name,int name_size)
257 {
258 #ifdef HAVE_GETADDRINFO
259 int error;
260 char *port;
261 struct addrinfo *res;
262 char *addr;
263
264 addr=name;
265 if (name[0]=='[') { //IPv6 address
266 port=strchr(name,']');
267 if (port) { //confirmed IPv6 address
268 *port='\0';
269 addr++;
270 }
271 } else { //IPv4 address
272 port=strchr(name,':');
273 if (port) *port='\0';
274 }
275
276 error=getaddrinfo(addr,NULL,NULL,&res);
277 if (error) {
278 freeaddrinfo(res);
279 debuga(__FILE__,__LINE__,_("Cannot resolve host name %s: %s\n"),name,gai_strerror(error));
280 exit(EXIT_FAILURE);
281 }
282 if (res->ai_family==AF_INET) {
283 struct sockaddr_in *s4=(struct sockaddr_in *)res->ai_addr;
284 struct in_addr *sa=&s4->sin_addr;
285 if (res->ai_addrlen<sizeof(*s4)) {
286 debuga(__FILE__,__LINE__,_("Short structure returned by getaddrinfo for an IPv4 address: %d bytes instead of %d\n"),res->ai_addrlen,(int)sizeof(*s4));
287 exit(EXIT_FAILURE);
288 }
289 inet_ntop(res->ai_family,sa,name,name_size);
290 } else if (res->ai_family==AF_INET6) {
291 struct sockaddr_in6 *s6=(struct sockaddr_in6 *)res->ai_addr;
292 struct in6_addr *sa6=&s6->sin6_addr;
293 if (res->ai_addrlen<sizeof(*s6)) {
294 debuga(__FILE__,__LINE__,_("Short structure returned by getaddrinfo for an IPv6 address: %d bytes instead of %d\n"),res->ai_addrlen,(int)sizeof(*s6));
295 exit(EXIT_FAILURE);
296 }
297 inet_ntop(res->ai_family,sa6,name,name_size);
298 } else {
299 debuga(__FILE__,__LINE__,_("Invalid address type %d returned when resolving host name \"%s\"\n"),res->ai_family,name);
300 }
301 freeaddrinfo(res);
302 #else
303 struct in_addr ia;
304 struct hostent *hp;
305 char *port;
306 char n1[4];
307 char n2[4];
308 char n3[4];
309 char n4[4];
310 struct getwordstruct gwarea;
311
312 port=strchr(name,':');
313 if (port) *port='\0';
314
315 if((hp=gethostbyname(name))==NULL)
316 return;
317
318 memcpy(&ia.s_addr,hp->h_addr_list[0],sizeof(ia.s_addr));
319 ia.s_addr=ntohl(ia.s_addr);
320 getword_start(&gwarea,inet_ntoa(ia));
321 if (getword(n4,sizeof(n4),&gwarea,'.')<0 || getword(n3,sizeof(n3),&gwarea,'.')<0 ||
322 getword(n2,sizeof(n2),&gwarea,'.')<0 || getword(n1,sizeof(n1),&gwarea,0)<0) {
323 debuga(__FILE__,__LINE__,_("Invalid IPv4 address \"%s\"\n"),gwarea.beginning);
324 exit(EXIT_FAILURE);
325 }
326 snprintf(name,name_size,"%s.%s.%s.%s",n1,n2,n3,n4);
327 #endif
328
329 return;
330 }