3aa690aab82eec8da647a6c20715851be3fb9faf
[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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  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 #include "counters.h"
51 #include "dns_func.h"
52
53 #ifdef __OS_darwin
54 #include <arpa/nameser_compat.h>
55 #endif
56
57 #include "ip_addr.h"
58 #ifdef USE_DNS_CACHE
59 #include "dns_wrappers.h"
60 #endif
61
62
63 /* define RESOLVE_DBG for debugging info (very noisy) */
64 #define RESOLVE_DBG
65 /* define NAPTR_DBG for naptr related debugging info (very noisy) */
66 #define NAPTR_DBG
67
68
69 #define MAX_QUERY_SIZE 8192
70 #define ANS_SIZE       8192
71 #define DNS_HDR_SIZE     12
72 #define MAX_DNS_NAME 256
73 #define MAX_DNS_STRING 255
74
75 #ifndef T_EBL
76 /** not official yet - iEnum. */
77 #define T_EBL 65300
78 #endif
79
80 /* get_record flags */
81 #define RES_ONLY_TYPE 1   /* return only the specified type records */
82 #define RES_AR            2   /* return also the additional records */
83
84 /* counter for failed DNS requests
85 */
86 struct dns_counters_h {
87     counter_handle_t failed_dns_req;
88 };
89
90 extern struct dns_counters_h dns_cnts_h;
91 extern struct dns_func_t dns_func;
92
93 /* query union*/
94 union dns_query{
95         HEADER hdr;
96         unsigned char buff[MAX_QUERY_SIZE];
97 };
98
99
100 /* rdata struct*/
101 struct rdata {
102         unsigned short type;
103         unsigned short pclass;
104         unsigned int   ttl;
105         void* rdata;
106         struct rdata* next;
107         unsigned char name_len; /* name length w/o the terminating 0 */
108         char name[1]; /* null terminated name (len=name_len+1) */
109 };
110 /* real size of the structure */
111 #define RDATA_SIZE(s) (sizeof(struct rdata)+(s).name_len) /* +1-1 */
112
113
114 /* srv rec. struct*/
115 struct srv_rdata {
116         unsigned short priority;
117         unsigned short weight;
118         unsigned short port;
119         unsigned char name_len; /* name length w/o the terminating 0 */
120         char name[1]; /* null terminated name (len=name_len+1) */
121 };
122
123
124 /* real size of the structure */
125 #define SRV_RDATA_SIZE(s) (sizeof(struct srv_rdata)+(s).name_len)
126
127 /* naptr rec. struct*/
128 struct naptr_rdata {
129         char* flags;    /* points inside str_table */
130         char* services; /* points inside str_table */
131         char* regexp;   /* points inside str_table */
132         char* repl;     /* points inside str_table, null terminated */
133         
134         unsigned short order;
135         unsigned short pref;
136         
137         unsigned char flags_len;
138         unsigned char services_len;
139         unsigned char regexp_len;
140         unsigned char repl_len; /* not currently used */
141         
142         char str_table[1]; /* contains all the strings */
143 };
144
145 /* real size of the structure */
146 #define NAPTR_RDATA_SIZE(s) (sizeof(struct naptr_rdata) \
147                                                                 + (s).flags_len \
148                                                                 + (s).services_len \
149                                                                 + (s).regexp_len \
150                                                                 + (s).repl_len + 1 - 1)
151
152
153 /* A rec. struct */
154 struct a_rdata {
155         unsigned char ip[4];
156 };
157
158 struct aaaa_rdata {
159         unsigned char ip6[16];
160 };
161
162 /* cname rec. struct*/
163 struct cname_rdata {
164         unsigned char name_len; /* name length w/o the terminating 0 */
165         char name[1]; /* null terminated name (len=name_len+1) */
166 };
167
168 /* real size of the structure */
169 #define CNAME_RDATA_SIZE(s) (sizeof(struct cname_rdata)+(s).name_len)
170
171 /* dns character-string */
172 struct dns_cstr{
173         char* cstr; /* pointer to null term. string */
174         unsigned char cstr_len;
175 };
176
177 /* txt rec. struct */
178 struct txt_rdata {
179         unsigned short cstr_no; /* number of strings */
180         unsigned short tslen; /* total strings table len */
181         struct dns_cstr txt[1]; /* at least 1 */
182         /* all txt[*].cstr point inside a string table at the end of the struct.*/
183 };
184
185 #define TXT_RDATA_SIZE(s) \
186         (sizeof(struct txt_rdata)+((s).cstr_no-1)*sizeof(struct dns_cstr)+\
187                 (s).tslen)
188
189 /* ebl rec. struct, see
190    http://tools.ietf.org/html/draft-ietf-enum-branch-location-record-03 */
191 struct ebl_rdata {
192         char* separator; /* points inside str_table */
193         char* apex;      /* point inside str_table */
194         unsigned char separator_len; /* separator len w/o the terminating 0 */
195         unsigned char apex_len;      /* apex len w/p the terminating 0 */
196         unsigned char position;
197         char str_table[1]; /* contains the 2 strings: separator and apex */
198 };
199 #define EBL_RDATA_SIZE(s) \
200         (sizeof(struct ebl_rdata)-1+(s).separator_len+1+(s).apex_len+1)
201
202
203 struct ptr_rdata {
204         unsigned char ptrdname_len; /* name length w/o the terminating 0 */
205         char ptrdname[1]; /* null terminated name (len=name_len+1) */
206 };
207 /* real size of the structure */
208 #define PTR_RDATA_SIZE(s) (sizeof(struct ptr_rdata)-1+(s).ptrdname_len+1)
209
210
211 #ifdef HAVE_RESOLV_RES
212 int match_search_list(const struct __res_state* res, char* name);
213 #endif
214 struct rdata* get_record(char* name, int type, int flags);
215 void free_rdata_list(struct rdata* head);
216
217
218
219 #define rev_resolvehost(ip)\
220                                         gethostbyaddr((char*)(ip)->u.addr, (ip)->len, (ip)->af)
221
222
223
224 #define HEX2I(c) \
225         (       (((c)>='0') && ((c)<='9'))? (c)-'0' :  \
226                 (((c)>='A') && ((c)<='F'))? ((c)-'A')+10 : \
227                 (((c)>='a') && ((c)<='f'))? ((c)-'a')+10 : -1 )
228
229
230
231
232
233 /* converts a str to an ipv4 address, returns the address or 0 on error
234    Warning: the result is a pointer to a statically allocated structure */
235 static inline struct ip_addr* str2ip(str* st)
236 {
237         int i;
238         unsigned char *limit;
239         static struct ip_addr ip;
240         unsigned char* s;
241
242         s=(unsigned char*)st->s;
243
244         /*init*/
245         ip.u.addr32[0]=0;
246         i=0;
247         limit=(unsigned char*)(st->s + st->len);
248
249         for(;s<limit ;s++){
250                 if (*s=='.'){
251                                 i++;
252                                 if (i>3) goto error_dots;
253                 }else if ( (*s <= '9' ) && (*s >= '0') ){
254                                 ip.u.addr[i]=ip.u.addr[i]*10+*s-'0';
255                 }else{
256                                 //error unknown char
257                                 goto error_char;
258                 }
259         }
260         if (i<3) goto error_dots;
261         ip.af=AF_INET;
262         ip.len=4;
263         
264         return &ip;
265 error_dots:
266 #ifdef RESOLVE_DBG
267         DBG("str2ip: ERROR: too %s dots in [%.*s]\n", (i>3)?"many":"few", 
268                         st->len, st->s);
269 #endif
270         return 0;
271  error_char:
272         /*
273         DBG("str2ip: WARNING: unexpected char %c in [%.*s]\n", *s, st->len, st->s);
274         */
275         return 0;
276 }
277
278
279 /* returns an ip_addr struct.; on error returns 0
280  * the ip_addr struct is static, so subsequent calls will destroy its content*/
281 static inline struct ip_addr* str2ip6(str* st)
282 {
283         int i, idx1, rest;
284         int no_colons;
285         int double_colon;
286         int hex;
287         static struct ip_addr ip;
288         unsigned short* addr_start;
289         unsigned short addr_end[8];
290         unsigned short* addr;
291         unsigned char* limit;
292         unsigned char* s;
293         
294         /* init */
295         if ((st->len) && (st->s[0]=='[')){
296                 /* skip over [ ] */
297                 if (st->s[st->len-1]!=']') goto error_char;
298                 s=(unsigned char*)(st->s+1);
299                 limit=(unsigned char*)(st->s+st->len-1);
300         }else{
301                 s=(unsigned char*)st->s;
302                 limit=(unsigned char*)(st->s+st->len);
303         }
304         i=idx1=rest=0;
305         double_colon=0;
306         no_colons=0;
307         ip.af=AF_INET6;
308         ip.len=16;
309         addr_start=ip.u.addr16;
310         addr=addr_start;
311         memset(addr_start, 0 , 8*sizeof(unsigned short));
312         memset(addr_end, 0 , 8*sizeof(unsigned short));
313         for (; s<limit; s++){
314                 if (*s==':'){
315                         no_colons++;
316                         if (no_colons>7) goto error_too_many_colons;
317                         if (double_colon){
318                                 idx1=i;
319                                 i=0;
320                                 if (addr==addr_end) goto error_colons;
321                                 addr=addr_end;
322                         }else{
323                                 double_colon=1;
324                                 addr[i]=htons(addr[i]);
325                                 i++;
326                         }
327                 }else if ((hex=HEX2I(*s))>=0){
328                                 addr[i]=addr[i]*16+hex;
329                                 double_colon=0;
330                 }else{
331                         /* error, unknown char */
332                         goto error_char;
333                 }
334         }
335         if (!double_colon){ /* not ending in ':' */
336                 addr[i]=htons(addr[i]);
337                 i++; 
338         }
339         /* if address contained '::' fix it */
340         if (addr==addr_end){
341                 rest=8-i-idx1;
342                 memcpy(addr_start+idx1+rest, addr_end, i*sizeof(unsigned short));
343         }else{
344                 /* no double colons inside */
345                 if (no_colons<7) goto error_too_few_colons;
346         }
347 /*
348         DBG("str2ip6: idx1=%d, rest=%d, no_colons=%d, hex=%x\n",
349                         idx1, rest, no_colons, hex);
350         DBG("str2ip6: address %x:%x:%x:%x:%x:%x:%x:%x\n", 
351                         addr_start[0], addr_start[1], addr_start[2],
352                         addr_start[3], addr_start[4], addr_start[5],
353                         addr_start[6], addr_start[7] );
354 */
355         return &ip;
356
357 error_too_many_colons:
358 #ifdef RESOLVE_DBG
359         DBG("str2ip6: ERROR: too many colons in [%.*s]\n", st->len, st->s);
360 #endif
361         return 0;
362
363 error_too_few_colons:
364 #ifdef RESOLVE_DBG
365         DBG("str2ip6: ERROR: too few colons in [%.*s]\n", st->len, st->s);
366 #endif
367         return 0;
368
369 error_colons:
370 #ifdef RESOLVE_DBG
371         DBG("str2ip6: ERROR: too many double colons in [%.*s]\n", st->len, st->s);
372 #endif
373         return 0;
374
375 error_char:
376         /*
377         DBG("str2ip6: WARNING: unexpected char %c in  [%.*s]\n", *s, st->len,
378                         st->s);*/
379         return 0;
380 }
381
382
383
384 struct hostent* _sip_resolvehost(str* name, unsigned short* port, char* proto);
385
386
387
388 /* gethostbyname wrapper, handles ip/ipv6 automatically */
389 static inline struct hostent* _resolvehost(char* name)
390 {
391         static struct hostent* he=0;
392 #ifdef HAVE_GETIPNODEBYNAME 
393         int err;
394         static struct hostent* he2=0;
395 #endif
396 #ifndef DNS_IP_HACK
397         int len;
398 #endif
399 #ifdef DNS_IP_HACK
400         struct ip_addr* ip;
401         str s;
402
403         s.s = (char*)name;
404         s.len = strlen(name);
405
406         /* check if it's an ip address */
407         if ( ((ip=str2ip(&s))!=0)
408                   || ((ip=str2ip6(&s))!=0)
409                 ){
410                 /* we are lucky, this is an ip address */
411                 return ip_addr2he(&s, ip);
412         }
413         
414 #else /* DNS_IP_HACK */
415         len=0;
416         if (*name=='['){
417                 len=strlen(name);
418                 if (len && (name[len-1]==']')){
419                         name[len-1]=0; /* remove '[' */
420                         name++; /* skip '[' */
421                         goto skip_ipv4;
422                 }
423         }
424 #endif
425         /* ipv4 */
426         he=dns_func.sr_gethostbyname(name);
427
428         if(he==0 && cfg_get(core, core_cfg, dns_try_ipv6)){
429 #ifndef DNS_IP_HACK
430 skip_ipv4:
431 #endif
432                 /*try ipv6*/
433         #ifdef HAVE_GETHOSTBYNAME2
434                 he=dns_func.sr_gethostbyname2(name, AF_INET6);
435         #elif defined HAVE_GETIPNODEBYNAME
436                 /* on solaris 8 getipnodebyname has a memory leak,
437                  * after some time calls to it will fail with err=3
438                  * solution: patch your solaris 8 installation */
439                 if (he2) freehostent(he2);
440                 he=he2=getipnodebyname(name, AF_INET6, 0, &err);
441         #else
442                 #error neither gethostbyname2 or getipnodebyname present
443         #endif
444 #ifndef DNS_IP_HACK
445                 if (len) name[len-2]=']'; /* restore */
446 #endif
447         }
448         return he;
449 }
450
451
452 int resolv_init(void);
453
454 /* callback/fixup functions executed by the configuration framework */
455 void resolv_reinit(str *gname, str *name);
456 int dns_reinit_fixup(void *handle, str *gname, str *name, void **val);
457 int dns_try_ipv6_fixup(void *handle, str *gname, str *name, void **val);
458 void reinit_proto_prefs(str *gname, str *name);
459
460 struct dns_srv_proto {
461         char proto;
462         int proto_pref;
463 };
464 void create_srv_name(char proto, str *name, char *srv);
465 size_t create_srv_pref_list(char *proto, struct dns_srv_proto *list);
466
467 #ifdef DNS_WATCHDOG_SUPPORT
468 /* callback function that is called by the child processes
469  * when they reinitialize the resolver
470  *
471  * Note, that this callback is called by each chiled process separately!!!
472  * If the callback is registered after forking, only the child process
473  * that installs the hook will call the callback.
474  */
475 typedef void (*on_resolv_reinit)(str*);
476 int register_resolv_reinit_cb(on_resolv_reinit cb);
477 #endif
478
479
480 int sip_hostport2su(union sockaddr_union* su, str* host, unsigned short port,
481                                                 char* proto);
482
483
484
485 /* wrappers */
486 #ifdef USE_DNS_CACHE
487 #define resolvehost dns_resolvehost
488 #define sip_resolvehost dns_sip_resolvehost
489 #else
490 #define resolvehost _resolvehost
491 #define sip_resolvehost _sip_resolvehost
492 #endif
493
494
495
496 #ifdef USE_NAPTR
497 /* NAPTR helper functions */
498 typedef unsigned int naptr_bmp_t; /* type used for keeping track of tried
499                                                                          naptr records*/
500 #define MAX_NAPTR_RRS (sizeof(naptr_bmp_t)*8)
501
502 /* use before first call to naptr_sip_iterate */
503 #define naptr_iterate_init(bmp) \
504         do{ \
505                 *(bmp)=0; \
506         }while(0) \
507
508 struct rdata* naptr_sip_iterate(struct rdata* naptr_head, 
509                                                                                 naptr_bmp_t* tried,
510                                                                                 str* srv_name, char* proto);
511 /* returns sip proto if valis sip naptr record, .-1 otherwise */
512 char naptr_get_sip_proto(struct naptr_rdata* n);
513 /* returns true if new_proto is preferred over old_proto */
514 int naptr_proto_preferred(char new_proto, char old_proto);
515 /* returns true if we support the protocol */
516 int naptr_proto_supported(char proto);
517 /* choose between 2 naptr records, should take into account local
518  * preferences too
519  * returns 1 if the new record was selected, 0 otherwise */
520 int naptr_choose (struct naptr_rdata** crt, char* crt_proto,
521                                                                         struct naptr_rdata* n , char n_proto);
522
523 #endif/* USE_NAPTR */
524
525 struct hostent* no_naptr_srv_sip_resolvehost(str* name, unsigned short* port,
526                 char* proto);
527
528 #endif