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