@cfg_get.<group_name>.<var_name> is documented
[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 <netdb.h>
47 #include <arpa/nameser.h>
48 #include <resolv.h>
49
50 #ifdef __OS_darwin
51 #include <arpa/nameser_compat.h>
52 #endif
53
54 #include "ip_addr.h"
55 #ifdef USE_DNS_CACHE
56 #include "dns_wrappers.h"
57 #endif
58
59 /* define RESOLVE_DBG for debugging info (very noisy) */
60 #define RESOLVE_DBG
61 /* define NAPTR_DBG for naptr related debugging info (very noisy) */
62 #define NAPTR_DBG
63
64
65 #define MAX_QUERY_SIZE 8192
66 #define ANS_SIZE       8192
67 #define DNS_HDR_SIZE     12
68 #define MAX_DNS_NAME 256
69 #define MAX_DNS_STRING 255
70
71
72 /* get_record flags */
73 #define RES_ONLY_TYPE 1   /* return only the specified type records */
74 #define RES_AR            2   /* return also the additional records */
75
76 /* query union*/
77 union dns_query{
78         HEADER hdr;
79         unsigned char buff[MAX_QUERY_SIZE];
80 };
81
82
83 /* rdata struct*/
84 struct rdata {
85         unsigned short type;
86         unsigned short class;
87         unsigned int   ttl;
88         void* rdata;
89         struct rdata* next;
90         unsigned char name_len; /* name length w/o the terminating 0 */
91         char name[1]; /* null terminated name (len=name_len+1) */
92 };
93 /* real size of the structure */
94 #define RDATA_SIZE(s) (sizeof(struct rdata)+(s).name_len) /* +1-1 */
95
96
97 /* srv rec. struct*/
98 struct srv_rdata {
99         unsigned short priority;
100         unsigned short weight;
101         unsigned short port;
102         unsigned char name_len; /* name length w/o the terminating 0 */
103         char name[1]; /* null terminated name (len=name_len+1) */
104 };
105
106
107 /* real size of the structure */
108 #define SRV_RDATA_SIZE(s) (sizeof(struct srv_rdata)+(s).name_len)
109
110 /* naptr rec. struct*/
111 struct naptr_rdata {
112         char* flags;    /* points inside str_table */
113         char* services; /* points inside str_table */
114         char* regexp;   /* points inside str_table */
115         char* repl;     /* points inside str_table, null terminated */
116         
117         unsigned short order;
118         unsigned short pref;
119         
120         unsigned char flags_len;
121         unsigned char services_len;
122         unsigned char regexp_len;
123         unsigned char repl_len; /* not currently used */
124         
125         char str_table[1]; /* contains all the strings */
126 };
127
128 /* real size of the structure */
129 #define NAPTR_RDATA_SIZE(s) (sizeof(struct naptr_rdata) \
130                                                                 + (s).flags_len \
131                                                                 + (s).services_len \
132                                                                 + (s).regexp_len \
133                                                                 + (s).repl_len + 1 - 1)
134
135
136 /* A rec. struct */
137 struct a_rdata {
138         unsigned char ip[4];
139 };
140
141 struct aaaa_rdata {
142         unsigned char ip6[16];
143 };
144
145 /* cname rec. struct*/
146 struct cname_rdata {
147         unsigned char name_len; /* name length w/o the terminating 0 */
148         char name[1]; /* null terminated name (len=name_len+1) */
149 };
150
151 /* real size of the structure */
152 #define CNAME_RDATA_SIZE(s) (sizeof(struct cname_rdata)+(s).name_len)
153
154
155 #ifdef HAVE_RESOLV_RES
156 int match_search_list(const struct __res_state* res, char* name);
157 #endif
158 struct rdata* get_record(char* name, int type, int flags);
159 void free_rdata_list(struct rdata* head);
160
161
162 extern int dns_try_ipv6;
163 extern int dns_try_naptr;
164 extern int dns_udp_pref;  /* udp transport preference (for naptr) */
165 extern int dns_tcp_pref;  /* tcp transport preference (for naptr) */
166 extern int dns_tls_pref;  /* tls transport preference (for naptr) */
167
168
169 #define rev_resolvehost(ip)\
170                                         gethostbyaddr((char*)(ip)->u.addr, (ip)->len, (ip)->af)
171
172
173
174 #define HEX2I(c) \
175         (       (((c)>='0') && ((c)<='9'))? (c)-'0' :  \
176                 (((c)>='A') && ((c)<='F'))? ((c)-'A')+10 : \
177                 (((c)>='a') && ((c)<='f'))? ((c)-'a')+10 : -1 )
178
179
180
181
182
183 /* converts a str to an ipv4 address, returns the address or 0 on error
184    Warning: the result is a pointer to a statically allocated structure */
185 static inline struct ip_addr* str2ip(str* st)
186 {
187         int i;
188         unsigned char *limit;
189         static struct ip_addr ip;
190         unsigned char* s;
191
192         s=(unsigned char*)st->s;
193
194         /*init*/
195         ip.u.addr32[0]=0;
196         i=0;
197         limit=(unsigned char*)(st->s + st->len);
198
199         for(;s<limit ;s++){
200                 if (*s=='.'){
201                                 i++;
202                                 if (i>3) goto error_dots;
203                 }else if ( (*s <= '9' ) && (*s >= '0') ){
204                                 ip.u.addr[i]=ip.u.addr[i]*10+*s-'0';
205                 }else{
206                                 //error unknown char
207                                 goto error_char;
208                 }
209         }
210         if (i<3) goto error_dots;
211         ip.af=AF_INET;
212         ip.len=4;
213         
214         return &ip;
215 error_dots:
216 #ifdef RESOLVE_DBG
217         DBG("str2ip: ERROR: too %s dots in [%.*s]\n", (i>3)?"many":"few", 
218                         st->len, st->s);
219 #endif
220         return 0;
221  error_char:
222         /*
223         DBG("str2ip: WARNING: unexpected char %c in [%.*s]\n", *s, st->len, st->s);
224         */
225         return 0;
226 }
227
228
229
230 /* returns an ip_addr struct.; on error returns 0
231  * the ip_addr struct is static, so subsequent calls will destroy its content*/
232 static inline struct ip_addr* str2ip6(str* st)
233 {
234         int i, idx1, rest;
235         int no_colons;
236         int double_colon;
237         int hex;
238         static struct ip_addr ip;
239         unsigned short* addr_start;
240         unsigned short addr_end[8];
241         unsigned short* addr;
242         unsigned char* limit;
243         unsigned char* s;
244         
245         /* init */
246         if ((st->len) && (st->s[0]=='[')){
247                 /* skip over [ ] */
248                 if (st->s[st->len-1]!=']') goto error_char;
249                 s=(unsigned char*)(st->s+1);
250                 limit=(unsigned char*)(st->s+st->len-1);
251         }else{
252                 s=(unsigned char*)st->s;
253                 limit=(unsigned char*)(st->s+st->len);
254         }
255         i=idx1=rest=0;
256         double_colon=0;
257         no_colons=0;
258         ip.af=AF_INET6;
259         ip.len=16;
260         addr_start=ip.u.addr16;
261         addr=addr_start;
262         memset(addr_start, 0 , 8*sizeof(unsigned short));
263         memset(addr_end, 0 , 8*sizeof(unsigned short));
264         for (; s<limit; s++){
265                 if (*s==':'){
266                         no_colons++;
267                         if (no_colons>7) goto error_too_many_colons;
268                         if (double_colon){
269                                 idx1=i;
270                                 i=0;
271                                 if (addr==addr_end) goto error_colons;
272                                 addr=addr_end;
273                         }else{
274                                 double_colon=1;
275                                 addr[i]=htons(addr[i]);
276                                 i++;
277                         }
278                 }else if ((hex=HEX2I(*s))>=0){
279                                 addr[i]=addr[i]*16+hex;
280                                 double_colon=0;
281                 }else{
282                         /* error, unknown char */
283                         goto error_char;
284                 }
285         }
286         if (!double_colon){ /* not ending in ':' */
287                 addr[i]=htons(addr[i]);
288                 i++; 
289         }
290         /* if address contained '::' fix it */
291         if (addr==addr_end){
292                 rest=8-i-idx1;
293                 memcpy(addr_start+idx1+rest, addr_end, i*sizeof(unsigned short));
294         }else{
295                 /* no double colons inside */
296                 if (no_colons<7) goto error_too_few_colons;
297         }
298 /*
299         DBG("str2ip6: idx1=%d, rest=%d, no_colons=%d, hex=%x\n",
300                         idx1, rest, no_colons, hex);
301         DBG("str2ip6: address %x:%x:%x:%x:%x:%x:%x:%x\n", 
302                         addr_start[0], addr_start[1], addr_start[2],
303                         addr_start[3], addr_start[4], addr_start[5],
304                         addr_start[6], addr_start[7] );
305 */
306         return &ip;
307
308 error_too_many_colons:
309 #ifdef RESOLVE_DBG
310         DBG("str2ip6: ERROR: too many colons in [%.*s]\n", st->len, st->s);
311 #endif
312         return 0;
313
314 error_too_few_colons:
315 #ifdef RESOLVE_DBG
316         DBG("str2ip6: ERROR: too few colons in [%.*s]\n", st->len, st->s);
317 #endif
318         return 0;
319
320 error_colons:
321 #ifdef RESOLVE_DBG
322         DBG("str2ip6: ERROR: too many double colons in [%.*s]\n", st->len, st->s);
323 #endif
324         return 0;
325
326 error_char:
327         /*
328         DBG("str2ip6: WARNING: unexpected char %c in  [%.*s]\n", *s, st->len,
329                         st->s);*/
330         return 0;
331 }
332
333
334
335 struct hostent* _sip_resolvehost(str* name, unsigned short* port, char* proto);
336
337
338
339 /* gethostbyname wrapper, handles ip/ipv6 automatically */
340 static inline struct hostent* _resolvehost(char* name)
341 {
342         static struct hostent* he=0;
343 #ifdef HAVE_GETIPNODEBYNAME 
344         int err;
345         static struct hostent* he2=0;
346 #endif
347 #ifndef DNS_IP_HACK
348 #ifdef USE_IPV6
349         int len;
350 #endif
351 #endif
352 #ifdef DNS_IP_HACK
353         struct ip_addr* ip;
354         str s;
355
356         s.s = (char*)name;
357         s.len = strlen(name);
358
359         /* check if it's an ip address */
360         if ( ((ip=str2ip(&s))!=0)
361 #ifdef  USE_IPV6
362                   || ((ip=str2ip6(&s))!=0)
363 #endif
364                 ){
365                 /* we are lucky, this is an ip address */
366                 return ip_addr2he(&s, ip);
367         }
368         
369 #else /* DNS_IP_HACK */
370 #ifdef USE_IPV6
371         len=0;
372         if (*name=='['){
373                 len=strlen(name);
374                 if (len && (name[len-1]==']')){
375                         name[len-1]=0; /* remove '[' */
376                         name++; /* skip '[' */
377                         goto skip_ipv4;
378                 }
379         }
380 #endif
381 #endif
382         /* ipv4 */
383         he=gethostbyname(name);
384 #ifdef USE_IPV6
385         if(he==0 && dns_try_ipv6){
386 #ifndef DNS_IP_HACK
387 skip_ipv4:
388 #endif
389                 /*try ipv6*/
390         #ifdef HAVE_GETHOSTBYNAME2
391                 he=gethostbyname2(name, AF_INET6);
392         #elif defined HAVE_GETIPNODEBYNAME
393                 /* on solaris 8 getipnodebyname has a memory leak,
394                  * after some time calls to it will fail with err=3
395                  * solution: patch your solaris 8 installation */
396                 if (he2) freehostent(he2);
397                 he=he2=getipnodebyname(name, AF_INET6, 0, &err);
398         #else
399                 #error neither gethostbyname2 or getipnodebyname present
400         #endif
401 #ifndef DNS_IP_HACK
402                 if (len) name[len-2]=']'; /* restore */
403 #endif
404         }
405 #endif
406         return he;
407 }
408
409
410
411 int resolv_init();
412
413 int sip_hostport2su(union sockaddr_union* su, str* host, unsigned short port,
414                                                 char* proto);
415
416
417
418 /* wrappers */
419 #ifdef USE_DNS_CACHE
420 #define resolvehost dns_resolvehost
421 #define sip_resolvehost dns_sip_resolvehost
422 #else
423 #define resolvehost _resolvehost
424 #define sip_resolvehost _sip_resolvehost
425 #endif
426
427
428
429 #ifdef USE_NAPTR
430 /* NAPTR helper functions */
431 typedef unsigned int naptr_bmp_t; /* type used for keeping track of tried
432                                                                          naptr records*/
433 #define MAX_NAPTR_RRS (sizeof(naptr_bmp_t)*8)
434
435 /* use before first call to naptr_sip_iterate */
436 #define naptr_iterate_init(bmp) \
437         do{ \
438                 *(bmp)=0; \
439         }while(0) \
440
441 struct rdata* naptr_sip_iterate(struct rdata* naptr_head, 
442                                                                                 naptr_bmp_t* tried,
443                                                                                 str* srv_name, char* proto);
444 /* returns sip proto if valis sip naptr record, .-1 otherwise */
445 char naptr_get_sip_proto(struct naptr_rdata* n);
446 /* returns true if new_proto is preferred over old_proto */
447 int naptr_proto_preferred(char new_proto, char old_proto);
448 /* returns true if we support the protocol */
449 int naptr_proto_supported(char proto);
450 /* choose between 2 naptr records, should take into account local
451  * preferences too
452  * returns 1 if the new record was selected, 0 otherwise */
453 int naptr_choose (struct naptr_rdata** crt, char* crt_proto,
454                                                                         struct naptr_rdata* n , char n_proto);
455
456 #endif/* USE_NAPTR */
457
458 #endif