- Spelling checked
[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  */
34
35
36
37 #ifndef __resolve_h
38 #define __resolve_h
39
40 #include <sys/types.h>
41 #include <sys/socket.h>
42 #include <netdb.h>
43 #include <arpa/nameser.h>
44
45 #ifdef __OS_darwin
46 #include <arpa/nameser_compat.h>
47 #endif
48
49 #include "ip_addr.h"
50
51
52 #define MAX_QUERY_SIZE 8192
53 #define ANS_SIZE       8192
54 #define DNS_HDR_SIZE     12
55 #define MAX_DNS_NAME 256
56 #define MAX_DNS_STRING 255
57
58
59
60 /* query union*/
61 union dns_query{
62         HEADER hdr;
63         unsigned char buff[MAX_QUERY_SIZE];
64 };
65
66
67 /* rdata struct*/
68 struct rdata {
69         unsigned short type;
70         unsigned short class;
71         unsigned int   ttl;
72         void* rdata;
73         struct rdata* next;
74 };
75
76
77 /* srv rec. struct*/
78 struct srv_rdata {
79         unsigned short priority;
80         unsigned short weight;
81         unsigned short port;
82         unsigned int name_len;
83         char name[MAX_DNS_NAME];
84 };
85
86 /* naptr rec. struct*/
87 struct naptr_rdata {
88         unsigned short order;
89         unsigned short pref;
90         unsigned int flags_len;
91         char flags[MAX_DNS_STRING];
92         unsigned int services_len;
93         char services[MAX_DNS_STRING];
94         unsigned int regexp_len;
95         char regexp[MAX_DNS_STRING];
96         unsigned int repl_len; /* not currently used */
97         char repl[MAX_DNS_NAME];
98 };
99
100
101 /* A rec. struct */
102 struct a_rdata {
103         unsigned char ip[4];
104 };
105
106 struct aaaa_rdata {
107         unsigned char ip6[16];
108 };
109
110 /* cname rec. struct*/
111 struct cname_rdata {
112         char name[MAX_DNS_NAME];
113 };
114
115
116
117 struct rdata* get_record(char* name, int type);
118 void free_rdata_list(struct rdata* head);
119
120
121
122
123 #define rev_resolvehost(ip)\
124                                         gethostbyaddr((char*)(ip)->u.addr, (ip)->len, (ip)->af);
125
126
127
128 #define HEX2I(c) \
129         (       (((c)>='0') && ((c)<='9'))? (c)-'0' :  \
130                 (((c)>='A') && ((c)<='F'))? ((c)-'A')+10 : \
131                 (((c)>='a') && ((c)<='f'))? ((c)-'a')+10 : -1 )
132
133
134
135
136
137 /* converts a str to an ipv4 address, returns the address or 0 on error
138    Warning: the result is a pointer to a statically allocated structure */
139 static inline struct ip_addr* str2ip(str* st)
140 {
141         int i;
142         unsigned char *limit;
143         static struct ip_addr ip;
144         unsigned char* s;
145
146         s=(unsigned char*)st->s;
147
148         /*init*/
149         ip.u.addr32[0]=0;
150         i=0;
151         limit=(unsigned char*)(st->s + st->len);
152
153         for(;s<limit ;s++){
154                 if (*s=='.'){
155                                 i++;
156                                 if (i>3) goto error_dots;
157                 }else if ( (*s <= '9' ) && (*s >= '0') ){
158                                 ip.u.addr[i]=ip.u.addr[i]*10+*s-'0';
159                 }else{
160                                 //error unknown char
161                                 goto error_char;
162                 }
163         }
164         if (i<3) goto error_dots;
165         ip.af=AF_INET;
166         ip.len=4;
167         
168         return &ip;
169 error_dots:
170         DBG("str2ip: ERROR: too %s dots in [%.*s]\n", (i>3)?"many":"few", 
171                         st->len, st->s);
172         return 0;
173  error_char:
174         /*
175         DBG("str2ip: WARNING: unexpected char %c in [%.*s]\n", *s, st->len, st->s);
176         */
177         return 0;
178 }
179
180
181
182 /* returns an ip_addr struct.; on error returns 0
183  * the ip_addr struct is static, so subsequent calls will destroy its content*/
184 static inline struct ip_addr* str2ip6(str* st)
185 {
186         int i, idx1, rest;
187         int no_colons;
188         int double_colon;
189         int hex;
190         static struct ip_addr ip;
191         unsigned short* addr_start;
192         unsigned short addr_end[8];
193         unsigned short* addr;
194         unsigned char* limit;
195         unsigned char* s;
196         
197         /* init */
198         if ((st->len) && (st->s[0]=='[')){
199                 /* skip over [ ] */
200                 if (st->s[st->len-1]!=']') goto error_char;
201                 s=(unsigned char*)(st->s+1);
202                 limit=(unsigned char*)(st->s+st->len-1);
203         }else{
204                 s=(unsigned char*)st->s;
205                 limit=(unsigned char*)(st->s+st->len);
206         }
207         i=idx1=rest=0;
208         double_colon=0;
209         no_colons=0;
210         ip.af=AF_INET6;
211         ip.len=16;
212         addr_start=ip.u.addr16;
213         addr=addr_start;
214         memset(addr_start, 0 , 8*sizeof(unsigned short));
215         memset(addr_end, 0 , 8*sizeof(unsigned short));
216         for (; s<limit; s++){
217                 if (*s==':'){
218                         no_colons++;
219                         if (no_colons>7) goto error_too_many_colons;
220                         if (double_colon){
221                                 idx1=i;
222                                 i=0;
223                                 if (addr==addr_end) goto error_colons;
224                                 addr=addr_end;
225                         }else{
226                                 double_colon=1;
227                                 addr[i]=htons(addr[i]);
228                                 i++;
229                         }
230                 }else if ((hex=HEX2I(*s))>=0){
231                                 addr[i]=addr[i]*16+hex;
232                                 double_colon=0;
233                 }else{
234                         /* error, unknown char */
235                         goto error_char;
236                 }
237         }
238         if (!double_colon){ /* not ending in ':' */
239                 addr[i]=htons(addr[i]);
240                 i++; 
241         }
242         /* if address contained '::' fix it */
243         if (addr==addr_end){
244                 rest=8-i-idx1;
245                 memcpy(addr_start+idx1+rest, addr_end, i*sizeof(unsigned short));
246         }else{
247                 /* no double colons inside */
248                 if (no_colons<7) goto error_too_few_colons;
249         }
250 /*
251         DBG("str2ip6: idx1=%d, rest=%d, no_colons=%d, hex=%x\n",
252                         idx1, rest, no_colons, hex);
253         DBG("str2ip6: address %x:%x:%x:%x:%x:%x:%x:%x\n", 
254                         addr_start[0], addr_start[1], addr_start[2],
255                         addr_start[3], addr_start[4], addr_start[5],
256                         addr_start[6], addr_start[7] );
257 */
258         return &ip;
259
260 error_too_many_colons:
261         DBG("str2ip6: ERROR: too many colons in [%.*s]\n", st->len, st->s);
262         return 0;
263
264 error_too_few_colons:
265         DBG("str2ip6: ERROR: too few colons in [%.*s]\n", st->len, st->s);
266         return 0;
267
268 error_colons:
269         DBG("str2ip6: ERROR: too many double colons in [%.*s]\n", st->len, st->s);
270         return 0;
271
272 error_char:
273         /*
274         DBG("str2ip6: WARNING: unexpected char %c in  [%.*s]\n", *s, st->len,
275                         st->s);*/
276         return 0;
277 }
278
279
280
281 struct hostent* sip_resolvehost(str* name, unsigned short* port, int proto);
282
283
284
285 /* gethostbyname wrappers
286  * use this, someday they will use a local cache */
287
288 static inline struct hostent* resolvehost(char* name)
289 {
290         static struct hostent* he=0;
291 #ifdef HAVE_GETIPNODEBYNAME 
292         int err;
293         static struct hostent* he2=0;
294 #endif
295 #ifndef DNS_IP_HACK
296 #ifdef USE_IPV6
297         int len;
298 #endif
299 #endif
300 #ifdef DNS_IP_HACK
301         struct ip_addr* ip;
302         str s;
303
304         s.s = (char*)name;
305         s.len = strlen(name);
306
307         /* check if it's an ip address */
308         if ( ((ip=str2ip(&s))!=0)
309 #ifdef  USE_IPV6
310                   || ((ip=str2ip6(&s))!=0)
311 #endif
312                 ){
313                 /* we are lucky, this is an ip address */
314                 return ip_addr2he(&s, ip);
315         }
316         
317 #else /* DNS_IP_HACK */
318 #ifdef USE_IPV6
319         len=0;
320         if (*name=='['){
321                 len=strlen(name);
322                 if (len && (name[len-1]==']')){
323                         name[len-1]=0; /* remove '[' */
324                         name++; /* skip '[' */
325                         goto skip_ipv4;
326                 }
327         }
328 #endif
329 #endif
330         /* ipv4 */
331         he=gethostbyname(name);
332 #ifdef USE_IPV6
333         if(he==0){
334 #ifndef DNS_IP_HACK
335 skip_ipv4:
336 #endif
337                 /*try ipv6*/
338         #ifdef HAVE_GETHOSTBYNAME2
339                 he=gethostbyname2(name, AF_INET6);
340         #elif defined HAVE_GETIPNODEBYNAME
341                 /* on solaris 8 getipnodebyname has a memory leak,
342                  * after some time calls to it will fail with err=3
343                  * solution: patch your solaris 8 installation */
344                 if (he2) freehostent(he2);
345                 he=he2=getipnodebyname(name, AF_INET6, 0, &err);
346         #else
347                 #error neither gethostbyname2 or getipnodebyname present
348         #endif
349 #ifndef DNS_IP_HACK
350                 if (len) name[len-2]=']'; /* restore */
351 #endif
352         }
353 #endif
354         return he;
355 }
356
357
358
359 #endif