76f39031b7e7906d49543d6bda1f0747f7258a5c
[sip-router] / resolve.h
1 /*
2  * $Id$
3  *
4  * resolver related functions
5  *
6  * Copyright (C) 2001-2003 FhG Fokus
7  *
8  * This file is part of ser, a free SIP server.
9  *
10  * ser is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version
14  *
15  * For a license to use the ser software under conditions
16  * other than those described here, or to purchase support for this
17  * software, please contact iptel.org by e-mail at the following addresses:
18  *    info@iptel.org
19  *
20  * ser is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License 
26  * along with this program; if not, write to the Free Software 
27  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
28  */
29 /* History:
30  * --------
31  *  2003-04-12  support for resolving ipv6 address references added (andrei)
32  *  2004-07-28  darwin needs nameser_compat.h (andrei)
33  *  2006-07-13  rdata structures put on diet (andrei)
34  *  2006-07-17  rdata contains now also the record name (andrei)
35  *  2006-08-18  get_record uses flags (andrei)
36  *  2006-06-16  naptr support (andrei)
37  */
38
39
40
41 #ifndef __resolve_h
42 #define __resolve_h
43
44 #include <sys/types.h>
45 #include <sys/socket.h>
46 #include <netinet/in.h>
47 #include <netdb.h>
48 #include <arpa/nameser.h>
49 #include <resolv.h>
50
51 #ifdef __OS_darwin
52 #include <arpa/nameser_compat.h>
53 #endif
54
55 #include "ip_addr.h"
56 #ifdef USE_DNS_CACHE
57 #include "dns_wrappers.h"
58 #endif
59
60 /* define RESOLVE_DBG for debugging info (very noisy) */
61 #define RESOLVE_DBG
62 /* define NAPTR_DBG for naptr related debugging info (very noisy) */
63 #define NAPTR_DBG
64
65
66 #define MAX_QUERY_SIZE 8192
67 #define ANS_SIZE       8192
68 #define DNS_HDR_SIZE     12
69 #define MAX_DNS_NAME 256
70 #define MAX_DNS_STRING 255
71
72
73 /* get_record flags */
74 #define RES_ONLY_TYPE 1   /* return only the specified type records */
75 #define RES_AR            2   /* return also the additional records */
76
77 /* query union*/
78 union dns_query{
79         HEADER hdr;
80         unsigned char buff[MAX_QUERY_SIZE];
81 };
82
83
84 /* rdata struct*/
85 struct rdata {
86         unsigned short type;
87         unsigned short class;
88         unsigned int   ttl;
89         void* rdata;
90         struct rdata* next;
91         unsigned char name_len; /* name length w/o the terminating 0 */
92         char name[1]; /* null terminated name (len=name_len+1) */
93 };
94 /* real size of the structure */
95 #define RDATA_SIZE(s) (sizeof(struct rdata)+(s).name_len) /* +1-1 */
96
97
98 /* srv rec. struct*/
99 struct srv_rdata {
100         unsigned short priority;
101         unsigned short weight;
102         unsigned short port;
103         unsigned char name_len; /* name length w/o the terminating 0 */
104         char name[1]; /* null terminated name (len=name_len+1) */
105 };
106
107
108 /* real size of the structure */
109 #define SRV_RDATA_SIZE(s) (sizeof(struct srv_rdata)+(s).name_len)
110
111 /* naptr rec. struct*/
112 struct naptr_rdata {
113         char* flags;    /* points inside str_table */
114         char* services; /* points inside str_table */
115         char* regexp;   /* points inside str_table */
116         char* repl;     /* points inside str_table, null terminated */
117         
118         unsigned short order;
119         unsigned short pref;
120         
121         unsigned char flags_len;
122         unsigned char services_len;
123         unsigned char regexp_len;
124         unsigned char repl_len; /* not currently used */
125         
126         char str_table[1]; /* contains all the strings */
127 };
128
129 /* real size of the structure */
130 #define NAPTR_RDATA_SIZE(s) (sizeof(struct naptr_rdata) \
131                                                                 + (s).flags_len \
132                                                                 + (s).services_len \
133                                                                 + (s).regexp_len \
134                                                                 + (s).repl_len + 1 - 1)
135
136
137 /* A rec. struct */
138 struct a_rdata {
139         unsigned char ip[4];
140 };
141
142 struct aaaa_rdata {
143         unsigned char ip6[16];
144 };
145
146 /* cname rec. struct*/
147 struct cname_rdata {
148         unsigned char name_len; /* name length w/o the terminating 0 */
149         char name[1]; /* null terminated name (len=name_len+1) */
150 };
151
152 /* real size of the structure */
153 #define CNAME_RDATA_SIZE(s) (sizeof(struct cname_rdata)+(s).name_len)
154
155
156 #ifdef HAVE_RESOLV_RES
157 int match_search_list(const struct __res_state* res, char* name);
158 #endif
159 struct rdata* get_record(char* name, int type, int flags);
160 void free_rdata_list(struct rdata* head);
161
162
163
164 #define rev_resolvehost(ip)\
165                                         gethostbyaddr((char*)(ip)->u.addr, (ip)->len, (ip)->af)
166
167
168
169 #define HEX2I(c) \
170         (       (((c)>='0') && ((c)<='9'))? (c)-'0' :  \
171                 (((c)>='A') && ((c)<='F'))? ((c)-'A')+10 : \
172                 (((c)>='a') && ((c)<='f'))? ((c)-'a')+10 : -1 )
173
174
175
176
177
178 /* converts a str to an ipv4 address, returns the address or 0 on error
179    Warning: the result is a pointer to a statically allocated structure */
180 static inline struct ip_addr* str2ip(str* st)
181 {
182         int i;
183         unsigned char *limit;
184         static struct ip_addr ip;
185         unsigned char* s;
186
187         s=(unsigned char*)st->s;
188
189         /*init*/
190         ip.u.addr32[0]=0;
191         i=0;
192         limit=(unsigned char*)(st->s + st->len);
193
194         for(;s<limit ;s++){
195                 if (*s=='.'){
196                                 i++;
197                                 if (i>3) goto error_dots;
198                 }else if ( (*s <= '9' ) && (*s >= '0') ){
199                                 ip.u.addr[i]=ip.u.addr[i]*10+*s-'0';
200                 }else{
201                                 //error unknown char
202                                 goto error_char;
203                 }
204         }
205         if (i<3) goto error_dots;
206         ip.af=AF_INET;
207         ip.len=4;
208         
209         return &ip;
210 error_dots:
211 #ifdef RESOLVE_DBG
212         DBG("str2ip: ERROR: too %s dots in [%.*s]\n", (i>3)?"many":"few", 
213                         st->len, st->s);
214 #endif
215         return 0;
216  error_char:
217         /*
218         DBG("str2ip: WARNING: unexpected char %c in [%.*s]\n", *s, st->len, st->s);
219         */
220         return 0;
221 }
222
223
224 #ifdef USE_IPV6
225 /* returns an ip_addr struct.; on error returns 0
226  * the ip_addr struct is static, so subsequent calls will destroy its content*/
227 static inline struct ip_addr* str2ip6(str* st)
228 {
229         int i, idx1, rest;
230         int no_colons;
231         int double_colon;
232         int hex;
233         static struct ip_addr ip;
234         unsigned short* addr_start;
235         unsigned short addr_end[8];
236         unsigned short* addr;
237         unsigned char* limit;
238         unsigned char* s;
239         
240         /* init */
241         if ((st->len) && (st->s[0]=='[')){
242                 /* skip over [ ] */
243                 if (st->s[st->len-1]!=']') goto error_char;
244                 s=(unsigned char*)(st->s+1);
245                 limit=(unsigned char*)(st->s+st->len-1);
246         }else{
247                 s=(unsigned char*)st->s;
248                 limit=(unsigned char*)(st->s+st->len);
249         }
250         i=idx1=rest=0;
251         double_colon=0;
252         no_colons=0;
253         ip.af=AF_INET6;
254         ip.len=16;
255         addr_start=ip.u.addr16;
256         addr=addr_start;
257         memset(addr_start, 0 , 8*sizeof(unsigned short));
258         memset(addr_end, 0 , 8*sizeof(unsigned short));
259         for (; s<limit; s++){
260                 if (*s==':'){
261                         no_colons++;
262                         if (no_colons>7) goto error_too_many_colons;
263                         if (double_colon){
264                                 idx1=i;
265                                 i=0;
266                                 if (addr==addr_end) goto error_colons;
267                                 addr=addr_end;
268                         }else{
269                                 double_colon=1;
270                                 addr[i]=htons(addr[i]);
271                                 i++;
272                         }
273                 }else if ((hex=HEX2I(*s))>=0){
274                                 addr[i]=addr[i]*16+hex;
275                                 double_colon=0;
276                 }else{
277                         /* error, unknown char */
278                         goto error_char;
279                 }
280         }
281         if (!double_colon){ /* not ending in ':' */
282                 addr[i]=htons(addr[i]);
283                 i++; 
284         }
285         /* if address contained '::' fix it */
286         if (addr==addr_end){
287                 rest=8-i-idx1;
288                 memcpy(addr_start+idx1+rest, addr_end, i*sizeof(unsigned short));
289         }else{
290                 /* no double colons inside */
291                 if (no_colons<7) goto error_too_few_colons;
292         }
293 /*
294         DBG("str2ip6: idx1=%d, rest=%d, no_colons=%d, hex=%x\n",
295                         idx1, rest, no_colons, hex);
296         DBG("str2ip6: address %x:%x:%x:%x:%x:%x:%x:%x\n", 
297                         addr_start[0], addr_start[1], addr_start[2],
298                         addr_start[3], addr_start[4], addr_start[5],
299                         addr_start[6], addr_start[7] );
300 */
301         return &ip;
302
303 error_too_many_colons:
304 #ifdef RESOLVE_DBG
305         DBG("str2ip6: ERROR: too many colons in [%.*s]\n", st->len, st->s);
306 #endif
307         return 0;
308
309 error_too_few_colons:
310 #ifdef RESOLVE_DBG
311         DBG("str2ip6: ERROR: too few colons in [%.*s]\n", st->len, st->s);
312 #endif
313         return 0;
314
315 error_colons:
316 #ifdef RESOLVE_DBG
317         DBG("str2ip6: ERROR: too many double colons in [%.*s]\n", st->len, st->s);
318 #endif
319         return 0;
320
321 error_char:
322         /*
323         DBG("str2ip6: WARNING: unexpected char %c in  [%.*s]\n", *s, st->len,
324                         st->s);*/
325         return 0;
326 }
327 #endif /* USE_IPV6 */
328
329
330
331 struct hostent* _sip_resolvehost(str* name, unsigned short* port, char* proto);
332
333
334
335 /* gethostbyname wrapper, handles ip/ipv6 automatically */
336 static inline struct hostent* _resolvehost(char* name)
337 {
338         static struct hostent* he=0;
339 #ifdef HAVE_GETIPNODEBYNAME 
340         int err;
341         static struct hostent* he2=0;
342 #endif
343 #ifndef DNS_IP_HACK
344 #ifdef USE_IPV6
345         int len;
346 #endif
347 #endif
348 #ifdef DNS_IP_HACK
349         struct ip_addr* ip;
350         str s;
351
352         s.s = (char*)name;
353         s.len = strlen(name);
354
355         /* check if it's an ip address */
356         if ( ((ip=str2ip(&s))!=0)
357 #ifdef  USE_IPV6
358                   || ((ip=str2ip6(&s))!=0)
359 #endif
360                 ){
361                 /* we are lucky, this is an ip address */
362                 return ip_addr2he(&s, ip);
363         }
364         
365 #else /* DNS_IP_HACK */
366 #ifdef USE_IPV6
367         len=0;
368         if (*name=='['){
369                 len=strlen(name);
370                 if (len && (name[len-1]==']')){
371                         name[len-1]=0; /* remove '[' */
372                         name++; /* skip '[' */
373                         goto skip_ipv4;
374                 }
375         }
376 #endif
377 #endif
378         /* ipv4 */
379         he=gethostbyname(name);
380 #ifdef USE_IPV6
381         if(he==0 && cfg_get(core, core_cfg, dns_try_ipv6)){
382 #ifndef DNS_IP_HACK
383 skip_ipv4:
384 #endif
385                 /*try ipv6*/
386         #ifdef HAVE_GETHOSTBYNAME2
387                 he=gethostbyname2(name, AF_INET6);
388         #elif defined HAVE_GETIPNODEBYNAME
389                 /* on solaris 8 getipnodebyname has a memory leak,
390                  * after some time calls to it will fail with err=3
391                  * solution: patch your solaris 8 installation */
392                 if (he2) freehostent(he2);
393                 he=he2=getipnodebyname(name, AF_INET6, 0, &err);
394         #else
395                 #error neither gethostbyname2 or getipnodebyname present
396         #endif
397 #ifndef DNS_IP_HACK
398                 if (len) name[len-2]=']'; /* restore */
399 #endif
400         }
401 #endif
402         return he;
403 }
404
405
406 int resolv_init();
407
408 /* callback/fixup functions executed by the configuration framework */
409 void resolv_reinit(str *name);
410 int dns_reinit_fixup(void *handle, str *name, void **val);
411 int dns_try_ipv6_fixup(void *handle, str *name, void **val);
412 void reinit_naptr_proto_prefs(str *name);
413
414 #ifdef DNS_WATCHDOG_SUPPORT
415 /* callback function that is called by the child processes
416  * when they reinitialize the resolver
417  *
418  * Note, that this callback is called by each chiled process separately!!!
419  * If the callback is registered after forking, only the child process
420  * that installs the hook will call the callback.
421  */
422 typedef void (*on_resolv_reinit)(str*);
423 int register_resolv_reinit_cb(on_resolv_reinit cb);
424 #endif
425
426
427 int sip_hostport2su(union sockaddr_union* su, str* host, unsigned short port,
428                                                 char* proto);
429
430
431
432 /* wrappers */
433 #ifdef USE_DNS_CACHE
434 #define resolvehost dns_resolvehost
435 #define sip_resolvehost dns_sip_resolvehost
436 #else
437 #define resolvehost _resolvehost
438 #define sip_resolvehost _sip_resolvehost
439 #endif
440
441
442
443 #ifdef USE_NAPTR
444 /* NAPTR helper functions */
445 typedef unsigned int naptr_bmp_t; /* type used for keeping track of tried
446                                                                          naptr records*/
447 #define MAX_NAPTR_RRS (sizeof(naptr_bmp_t)*8)
448
449 /* use before first call to naptr_sip_iterate */
450 #define naptr_iterate_init(bmp) \
451         do{ \
452                 *(bmp)=0; \
453         }while(0) \
454
455 struct rdata* naptr_sip_iterate(struct rdata* naptr_head, 
456                                                                                 naptr_bmp_t* tried,
457                                                                                 str* srv_name, char* proto);
458 /* returns sip proto if valis sip naptr record, .-1 otherwise */
459 char naptr_get_sip_proto(struct naptr_rdata* n);
460 /* returns true if new_proto is preferred over old_proto */
461 int naptr_proto_preferred(char new_proto, char old_proto);
462 /* returns true if we support the protocol */
463 int naptr_proto_supported(char proto);
464 /* choose between 2 naptr records, should take into account local
465  * preferences too
466  * returns 1 if the new record was selected, 0 otherwise */
467 int naptr_choose (struct naptr_rdata** crt, char* crt_proto,
468                                                                         struct naptr_rdata* n , char n_proto);
469
470 #endif/* USE_NAPTR */
471
472 #endif